--- /dev/null
+From f71f01394f742fc4558b3f9f4c7ef4c4cf3b07c8 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Sun, 8 May 2022 11:37:07 +0200
+Subject: floppy: use a statically allocated error counter
+
+From: Willy Tarreau <w@1wt.eu>
+
+commit f71f01394f742fc4558b3f9f4c7ef4c4cf3b07c8 upstream.
+
+Interrupt handler bad_flp_intr() may cause a UAF on the recently freed
+request just to increment the error count. There's no point keeping
+that one in the request anyway, and since the interrupt handler uses a
+static pointer to the error which cannot be kept in sync with the
+pending request, better make it use a static error counter that's reset
+for each new request. This reset now happens when entering
+redo_fd_request() for a new request via set_next_request().
+
+One initial concern about a single error counter was that errors on one
+floppy drive could be reported on another one, but this problem is not
+real given that the driver uses a single drive at a time, as that
+PC-compatible controllers also have this limitation by using shared
+signals. As such the error count is always for the "current" drive.
+
+Reported-by: Minh Yuan <yuanmingbuaa@gmail.com>
+Suggested-by: Linus Torvalds <torvalds@linuxfoundation.org>
+Tested-by: Denis Efremov <efremov@linux.com>
+Signed-off-by: Willy Tarreau <w@1wt.eu>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/block/floppy.c | 18 ++++++++----------
+ 1 file changed, 8 insertions(+), 10 deletions(-)
+
+--- a/drivers/block/floppy.c
++++ b/drivers/block/floppy.c
+@@ -509,8 +509,8 @@ static unsigned long fdc_busy;
+ static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
+ static DECLARE_WAIT_QUEUE_HEAD(command_done);
+
+-/* Errors during formatting are counted here. */
+-static int format_errors;
++/* errors encountered on the current (or last) request */
++static int floppy_errors;
+
+ /* Format request descriptor. */
+ static struct format_descr format_req;
+@@ -530,7 +530,6 @@ static struct format_descr format_req;
+ static char *floppy_track_buffer;
+ static int max_buffer_sectors;
+
+-static int *errors;
+ typedef void (*done_f)(int);
+ static const struct cont_t {
+ void (*interrupt)(void);
+@@ -1455,7 +1454,7 @@ static int interpret_errors(void)
+ if (drive_params[current_drive].flags & FTD_MSG)
+ DPRINT("Over/Underrun - retrying\n");
+ bad = 0;
+- } else if (*errors >= drive_params[current_drive].max_errors.reporting) {
++ } else if (floppy_errors >= drive_params[current_drive].max_errors.reporting) {
+ print_errors();
+ }
+ if (reply_buffer[ST2] & ST2_WC || reply_buffer[ST2] & ST2_BC)
+@@ -2095,7 +2094,7 @@ static void bad_flp_intr(void)
+ if (!next_valid_format(current_drive))
+ return;
+ }
+- err_count = ++(*errors);
++ err_count = ++floppy_errors;
+ INFBOUND(write_errors[current_drive].badness, err_count);
+ if (err_count > drive_params[current_drive].max_errors.abort)
+ cont->done(0);
+@@ -2241,9 +2240,8 @@ static int do_format(int drive, struct f
+ return -EINVAL;
+ }
+ format_req = *tmp_format_req;
+- format_errors = 0;
+ cont = &format_cont;
+- errors = &format_errors;
++ floppy_errors = 0;
+ ret = wait_til_done(redo_format, true);
+ if (ret == -EINTR)
+ return -EINTR;
+@@ -2761,10 +2759,11 @@ static int set_next_request(void)
+ current_req = list_first_entry_or_null(&floppy_reqs, struct request,
+ queuelist);
+ if (current_req) {
+- current_req->error_count = 0;
++ floppy_errors = 0;
+ list_del_init(¤t_req->queuelist);
++ return 1;
+ }
+- return current_req != NULL;
++ return 0;
+ }
+
+ /* Starts or continues processing request. Will automatically unlock the
+@@ -2823,7 +2822,6 @@ do_request:
+ _floppy = floppy_type + drive_params[current_drive].autodetect[drive_state[current_drive].probed_format];
+ } else
+ probing = 0;
+- errors = &(current_req->error_count);
+ tmp = make_raw_rw_request();
+ if (tmp < 2) {
+ request_done(tmp);
--- /dev/null
+From 381a3083c6747ae5cdbef9b176d57d1b966db49f Mon Sep 17 00:00:00 2001
+From: Terry Bowman <terry.bowman@amd.com>
+Date: Wed, 9 Feb 2022 11:27:16 -0600
+Subject: i2c: piix4: Add EFCH MMIO support for SMBus port select
+
+From: Terry Bowman <terry.bowman@amd.com>
+
+commit 381a3083c6747ae5cdbef9b176d57d1b966db49f upstream.
+
+AMD processors include registers capable of selecting between 2 SMBus
+ports. Port selection is made during each user access by writing to
+FCH::PM::DECODEEN[smbus0sel]. Change the driver to use MMIO during
+SMBus port selection because cd6h/cd7h port I/O is not available on
+later AMD processors.
+
+Signed-off-by: Terry Bowman <terry.bowman@amd.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Reviewed-by: Jean Delvare <jdelvare@suse.de>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Cc: Mario Limonciello <Mario.Limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/i2c/busses/i2c-piix4.c | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-piix4.c
++++ b/drivers/i2c/busses/i2c-piix4.c
+@@ -753,10 +753,19 @@ static void piix4_imc_wakeup(void)
+ release_region(KERNCZ_IMC_IDX, 2);
+ }
+
+-static int piix4_sb800_port_sel(u8 port)
++static int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg)
+ {
+ u8 smba_en_lo, val;
+
++ if (mmio_cfg->use_mmio) {
++ smba_en_lo = ioread8(mmio_cfg->addr + piix4_port_sel_sb800);
++ val = (smba_en_lo & ~piix4_port_mask_sb800) | port;
++ if (smba_en_lo != val)
++ iowrite8(val, mmio_cfg->addr + piix4_port_sel_sb800);
++
++ return (smba_en_lo & piix4_port_mask_sb800);
++ }
++
+ outb_p(piix4_port_sel_sb800, SB800_PIIX4_SMB_IDX);
+ smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1);
+
+@@ -843,12 +852,12 @@ static s32 piix4_access_sb800(struct i2c
+ }
+ }
+
+- prev_port = piix4_sb800_port_sel(adapdata->port);
++ prev_port = piix4_sb800_port_sel(adapdata->port, &adapdata->mmio_cfg);
+
+ retval = piix4_access(adap, addr, flags, read_write,
+ command, size, data);
+
+- piix4_sb800_port_sel(prev_port);
++ piix4_sb800_port_sel(prev_port, &adapdata->mmio_cfg);
+
+ /* Release the semaphore */
+ outb_p(smbslvcnt | 0x20, SMBSLVCNT);
--- /dev/null
+From 7c148722d074c29fb998578eea5de3c14b9608c9 Mon Sep 17 00:00:00 2001
+From: Terry Bowman <terry.bowman@amd.com>
+Date: Wed, 9 Feb 2022 11:27:14 -0600
+Subject: i2c: piix4: Add EFCH MMIO support to region request and release
+
+From: Terry Bowman <terry.bowman@amd.com>
+
+commit 7c148722d074c29fb998578eea5de3c14b9608c9 upstream.
+
+EFCH cd6h/cd7h port I/O may no longer be available on later AMD
+processors and it is recommended to use MMIO instead. Update the
+request and release functions to support MMIO.
+
+MMIO request/release and mmapping require details during cleanup.
+Add a MMIO configuration structure containing resource and vaddress
+details for mapping the region, accessing the region, and releasing
+the region.
+
+Signed-off-by: Terry Bowman <terry.bowman@amd.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Reviewed-by: Jean Delvare <jdelvare@suse.de>
+[wsa: rebased after fixup in previous patch]
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Cc: Mario Limonciello <Mario.Limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/i2c/busses/i2c-piix4.c | 66 ++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 58 insertions(+), 8 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-piix4.c
++++ b/drivers/i2c/busses/i2c-piix4.c
+@@ -98,6 +98,9 @@
+ #define SB800_PIIX4_PORT_IDX_MASK_KERNCZ 0x18
+ #define SB800_PIIX4_PORT_IDX_SHIFT_KERNCZ 3
+
++#define SB800_PIIX4_FCH_PM_ADDR 0xFED80300
++#define SB800_PIIX4_FCH_PM_SIZE 8
++
+ /* insmod parameters */
+
+ /* If force is set to anything different from 0, we forcibly enable the
+@@ -156,6 +159,12 @@ static const char *piix4_main_port_names
+ };
+ static const char *piix4_aux_port_name_sb800 = " port 1";
+
++struct sb800_mmio_cfg {
++ void __iomem *addr;
++ struct resource *res;
++ bool use_mmio;
++};
++
+ struct i2c_piix4_adapdata {
+ unsigned short smba;
+
+@@ -163,10 +172,40 @@ struct i2c_piix4_adapdata {
+ bool sb800_main;
+ bool notify_imc;
+ u8 port; /* Port number, shifted */
++ struct sb800_mmio_cfg mmio_cfg;
+ };
+
+-static int piix4_sb800_region_request(struct device *dev)
++static int piix4_sb800_region_request(struct device *dev,
++ struct sb800_mmio_cfg *mmio_cfg)
+ {
++ if (mmio_cfg->use_mmio) {
++ struct resource *res;
++ void __iomem *addr;
++
++ res = request_mem_region_muxed(SB800_PIIX4_FCH_PM_ADDR,
++ SB800_PIIX4_FCH_PM_SIZE,
++ "sb800_piix4_smb");
++ if (!res) {
++ dev_err(dev,
++ "SMBus base address memory region 0x%x already in use.\n",
++ SB800_PIIX4_FCH_PM_ADDR);
++ return -EBUSY;
++ }
++
++ addr = ioremap(SB800_PIIX4_FCH_PM_ADDR,
++ SB800_PIIX4_FCH_PM_SIZE);
++ if (!addr) {
++ release_resource(res);
++ dev_err(dev, "SMBus base address mapping failed.\n");
++ return -ENOMEM;
++ }
++
++ mmio_cfg->res = res;
++ mmio_cfg->addr = addr;
++
++ return 0;
++ }
++
+ if (!request_muxed_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE,
+ "sb800_piix4_smb")) {
+ dev_err(dev,
+@@ -178,8 +217,15 @@ static int piix4_sb800_region_request(st
+ return 0;
+ }
+
+-static void piix4_sb800_region_release(struct device *dev)
++static void piix4_sb800_region_release(struct device *dev,
++ struct sb800_mmio_cfg *mmio_cfg)
+ {
++ if (mmio_cfg->use_mmio) {
++ iounmap(mmio_cfg->addr);
++ release_resource(mmio_cfg->res);
++ return;
++ }
++
+ release_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE);
+ }
+
+@@ -288,11 +334,13 @@ static int piix4_setup_sb800_smba(struct
+ u8 *smb_en_status,
+ unsigned short *piix4_smba)
+ {
++ struct sb800_mmio_cfg mmio_cfg;
+ u8 smba_en_lo;
+ u8 smba_en_hi;
+ int retval;
+
+- retval = piix4_sb800_region_request(&PIIX4_dev->dev);
++ mmio_cfg.use_mmio = 0;
++ retval = piix4_sb800_region_request(&PIIX4_dev->dev, &mmio_cfg);
+ if (retval)
+ return retval;
+
+@@ -301,7 +349,7 @@ static int piix4_setup_sb800_smba(struct
+ outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX);
+ smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1);
+
+- piix4_sb800_region_release(&PIIX4_dev->dev);
++ piix4_sb800_region_release(&PIIX4_dev->dev, &mmio_cfg);
+
+ if (!smb_en) {
+ *smb_en_status = smba_en_lo & 0x10;
+@@ -328,6 +376,7 @@ static int piix4_setup_sb800(struct pci_
+ unsigned short piix4_smba;
+ u8 smb_en, smb_en_status, port_sel;
+ u8 i2ccfg, i2ccfg_offset = 0x10;
++ struct sb800_mmio_cfg mmio_cfg;
+ int retval;
+
+ /* SB800 and later SMBus does not support forcing address */
+@@ -407,7 +456,8 @@ static int piix4_setup_sb800(struct pci_
+ piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT;
+ }
+ } else {
+- retval = piix4_sb800_region_request(&PIIX4_dev->dev);
++ mmio_cfg.use_mmio = 0;
++ retval = piix4_sb800_region_request(&PIIX4_dev->dev, &mmio_cfg);
+ if (retval) {
+ release_region(piix4_smba, SMBIOSIZE);
+ return retval;
+@@ -420,7 +470,7 @@ static int piix4_setup_sb800(struct pci_
+ SB800_PIIX4_PORT_IDX;
+ piix4_port_mask_sb800 = SB800_PIIX4_PORT_IDX_MASK;
+ piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT;
+- piix4_sb800_region_release(&PIIX4_dev->dev);
++ piix4_sb800_region_release(&PIIX4_dev->dev, &mmio_cfg);
+ }
+
+ dev_info(&PIIX4_dev->dev,
+@@ -731,7 +781,7 @@ static s32 piix4_access_sb800(struct i2c
+ u8 prev_port;
+ int retval;
+
+- retval = piix4_sb800_region_request(&adap->dev);
++ retval = piix4_sb800_region_request(&adap->dev, &adapdata->mmio_cfg);
+ if (retval)
+ return retval;
+
+@@ -802,7 +852,7 @@ static s32 piix4_access_sb800(struct i2c
+ piix4_imc_wakeup();
+
+ release:
+- piix4_sb800_region_release(&adap->dev);
++ piix4_sb800_region_release(&adap->dev, &adapdata->mmio_cfg);
+ return retval;
+ }
+
--- /dev/null
+From 46967bc1ee93acd1d8953c87dc16f43de4076f93 Mon Sep 17 00:00:00 2001
+From: Terry Bowman <terry.bowman@amd.com>
+Date: Wed, 9 Feb 2022 11:27:15 -0600
+Subject: i2c: piix4: Add EFCH MMIO support to SMBus base address detect
+
+From: Terry Bowman <terry.bowman@amd.com>
+
+commit 46967bc1ee93acd1d8953c87dc16f43de4076f93 upstream.
+
+The EFCH SMBus controller's base address is determined using details in
+FCH::PM::DECODEEN[smbusasfiobase] and FCH::PM::DECODEEN[smbusasfioen].These
+register fields were accessed using cd6h/cd7h port I/O. cd6h/cd7h port I/O
+is no longer available in later AMD processors. Change base address
+detection to use MMIO instead of port I/O cd6h/cd7h.
+
+Signed-off-by: Terry Bowman <terry.bowman@amd.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Reviewed-by: Jean Delvare <jdelvare@suse.de>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Cc: Mario Limonciello <Mario.Limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/i2c/busses/i2c-piix4.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-piix4.c
++++ b/drivers/i2c/busses/i2c-piix4.c
+@@ -344,10 +344,15 @@ static int piix4_setup_sb800_smba(struct
+ if (retval)
+ return retval;
+
+- outb_p(smb_en, SB800_PIIX4_SMB_IDX);
+- smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1);
+- outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX);
+- smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1);
++ if (mmio_cfg.use_mmio) {
++ smba_en_lo = ioread8(mmio_cfg.addr);
++ smba_en_hi = ioread8(mmio_cfg.addr + 1);
++ } else {
++ outb_p(smb_en, SB800_PIIX4_SMB_IDX);
++ smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1);
++ outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX);
++ smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1);
++ }
+
+ piix4_sb800_region_release(&PIIX4_dev->dev, &mmio_cfg);
+
--- /dev/null
+From 6cf72f41808ab5db1d7718b999b3ff0166e67e45 Mon Sep 17 00:00:00 2001
+From: Terry Bowman <terry.bowman@amd.com>
+Date: Wed, 9 Feb 2022 11:27:17 -0600
+Subject: i2c: piix4: Enable EFCH MMIO for Family 17h+
+
+From: Terry Bowman <terry.bowman@amd.com>
+
+commit 6cf72f41808ab5db1d7718b999b3ff0166e67e45 upstream.
+
+Enable EFCH MMIO using check for SMBus PCI revision ID value 0x51 or
+greater. This PCI revision ID check will enable family 17h and future
+AMD processors with the same EFCH SMBus controller HW.
+
+Signed-off-by: Terry Bowman <terry.bowman@amd.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Reviewed-by: Jean Delvare <jdelvare@suse.de>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Cc: Mario Limonciello <Mario.Limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/i2c/busses/i2c-piix4.c | 17 +++++++++++++++--
+ 1 file changed, 15 insertions(+), 2 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-piix4.c
++++ b/drivers/i2c/busses/i2c-piix4.c
+@@ -229,6 +229,18 @@ static void piix4_sb800_region_release(s
+ release_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE);
+ }
+
++static bool piix4_sb800_use_mmio(struct pci_dev *PIIX4_dev)
++{
++ /*
++ * cd6h/cd7h port I/O accesses can be disabled on AMD processors
++ * w/ SMBus PCI revision ID 0x51 or greater. MMIO is supported on
++ * the same processors and is the recommended access method.
++ */
++ return (PIIX4_dev->vendor == PCI_VENDOR_ID_AMD &&
++ PIIX4_dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS &&
++ PIIX4_dev->revision >= 0x51);
++}
++
+ static int piix4_setup(struct pci_dev *PIIX4_dev,
+ const struct pci_device_id *id)
+ {
+@@ -339,7 +351,7 @@ static int piix4_setup_sb800_smba(struct
+ u8 smba_en_hi;
+ int retval;
+
+- mmio_cfg.use_mmio = 0;
++ mmio_cfg.use_mmio = piix4_sb800_use_mmio(PIIX4_dev);
+ retval = piix4_sb800_region_request(&PIIX4_dev->dev, &mmio_cfg);
+ if (retval)
+ return retval;
+@@ -461,7 +473,7 @@ static int piix4_setup_sb800(struct pci_
+ piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT;
+ }
+ } else {
+- mmio_cfg.use_mmio = 0;
++ mmio_cfg.use_mmio = piix4_sb800_use_mmio(PIIX4_dev);
+ retval = piix4_sb800_region_request(&PIIX4_dev->dev, &mmio_cfg);
+ if (retval) {
+ release_region(piix4_smba, SMBIOSIZE);
+@@ -944,6 +956,7 @@ static int piix4_add_adapter(struct pci_
+ return -ENOMEM;
+ }
+
++ adapdata->mmio_cfg.use_mmio = piix4_sb800_use_mmio(dev);
+ adapdata->smba = smba;
+ adapdata->sb800_main = sb800_main;
+ adapdata->port = port << piix4_port_shift_sb800;
--- /dev/null
+From a3325d225b00889f4b7fdb25d83033cae1048a92 Mon Sep 17 00:00:00 2001
+From: Terry Bowman <terry.bowman@amd.com>
+Date: Wed, 9 Feb 2022 11:27:11 -0600
+Subject: i2c: piix4: Move port I/O region request/release code into functions
+
+From: Terry Bowman <terry.bowman@amd.com>
+
+commit a3325d225b00889f4b7fdb25d83033cae1048a92 upstream.
+
+Move duplicated region request and release code into a function. Move is
+in preparation for following MMIO changes.
+
+Signed-off-by: Terry Bowman <terry.bowman@amd.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Reviewed-by: Jean Delvare <jdelvare@suse.de>
+[wsa: added missing curly brace]
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Cc: Mario Limonciello <Mario.Limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/i2c/busses/i2c-piix4.c | 48 ++++++++++++++++++++++++++---------------
+ 1 file changed, 31 insertions(+), 17 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-piix4.c
++++ b/drivers/i2c/busses/i2c-piix4.c
+@@ -165,6 +165,24 @@ struct i2c_piix4_adapdata {
+ u8 port; /* Port number, shifted */
+ };
+
++static int piix4_sb800_region_request(struct device *dev)
++{
++ if (!request_muxed_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE,
++ "sb800_piix4_smb")) {
++ dev_err(dev,
++ "SMBus base address index region 0x%x already in use.\n",
++ SB800_PIIX4_SMB_IDX);
++ return -EBUSY;
++ }
++
++ return 0;
++}
++
++static void piix4_sb800_region_release(struct device *dev)
++{
++ release_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE);
++}
++
+ static int piix4_setup(struct pci_dev *PIIX4_dev,
+ const struct pci_device_id *id)
+ {
+@@ -270,6 +288,7 @@ static int piix4_setup_sb800(struct pci_
+ unsigned short piix4_smba;
+ u8 smba_en_lo, smba_en_hi, smb_en, smb_en_status, port_sel;
+ u8 i2ccfg, i2ccfg_offset = 0x10;
++ int retval;
+
+ /* SB800 and later SMBus does not support forcing address */
+ if (force || force_addr) {
+@@ -291,20 +310,16 @@ static int piix4_setup_sb800(struct pci_
+ else
+ smb_en = (aux) ? 0x28 : 0x2c;
+
+- if (!request_muxed_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE,
+- "sb800_piix4_smb")) {
+- dev_err(&PIIX4_dev->dev,
+- "SMB base address index region 0x%x already in use.\n",
+- SB800_PIIX4_SMB_IDX);
+- return -EBUSY;
+- }
++ retval = piix4_sb800_region_request(&PIIX4_dev->dev);
++ if (retval)
++ return retval;
+
+ outb_p(smb_en, SB800_PIIX4_SMB_IDX);
+ smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1);
+ outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX);
+ smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1);
+
+- release_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE);
++ piix4_sb800_region_release(&PIIX4_dev->dev);
+
+ if (!smb_en) {
+ smb_en_status = smba_en_lo & 0x10;
+@@ -373,11 +388,10 @@ static int piix4_setup_sb800(struct pci_
+ piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT;
+ }
+ } else {
+- if (!request_muxed_region(SB800_PIIX4_SMB_IDX,
+- SB800_PIIX4_SMB_MAP_SIZE,
+- "sb800_piix4_smb")) {
++ retval = piix4_sb800_region_request(&PIIX4_dev->dev);
++ if (retval) {
+ release_region(piix4_smba, SMBIOSIZE);
+- return -EBUSY;
++ return retval;
+ }
+
+ outb_p(SB800_PIIX4_PORT_IDX_SEL, SB800_PIIX4_SMB_IDX);
+@@ -387,7 +401,7 @@ static int piix4_setup_sb800(struct pci_
+ SB800_PIIX4_PORT_IDX;
+ piix4_port_mask_sb800 = SB800_PIIX4_PORT_IDX_MASK;
+ piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT;
+- release_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE);
++ piix4_sb800_region_release(&PIIX4_dev->dev);
+ }
+
+ dev_info(&PIIX4_dev->dev,
+@@ -685,9 +699,9 @@ static s32 piix4_access_sb800(struct i2c
+ u8 port;
+ int retval;
+
+- if (!request_muxed_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE,
+- "sb800_piix4_smb"))
+- return -EBUSY;
++ retval = piix4_sb800_region_request(&adap->dev);
++ if (retval)
++ return retval;
+
+ /* Request the SMBUS semaphore, avoid conflicts with the IMC */
+ smbslvcnt = inb_p(SMBSLVCNT);
+@@ -762,7 +776,7 @@ static s32 piix4_access_sb800(struct i2c
+ piix4_imc_wakeup();
+
+ release:
+- release_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE);
++ piix4_sb800_region_release(&adap->dev);
+ return retval;
+ }
+
--- /dev/null
+From 0a59a24e14e9b21dcbb6b8ea41422e2fdfa437fd Mon Sep 17 00:00:00 2001
+From: Terry Bowman <terry.bowman@amd.com>
+Date: Wed, 9 Feb 2022 11:27:12 -0600
+Subject: i2c: piix4: Move SMBus controller base address detect into function
+
+From: Terry Bowman <terry.bowman@amd.com>
+
+commit 0a59a24e14e9b21dcbb6b8ea41422e2fdfa437fd upstream.
+
+Move SMBus controller base address detection into function. Refactor
+is in preparation for following MMIO changes.
+
+Signed-off-by: Terry Bowman <terry.bowman@amd.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Reviewed-by: Jean Delvare <jdelvare@suse.de>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Cc: Mario Limonciello <Mario.Limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/i2c/busses/i2c-piix4.c | 69 ++++++++++++++++++++++++++---------------
+ 1 file changed, 44 insertions(+), 25 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-piix4.c
++++ b/drivers/i2c/busses/i2c-piix4.c
+@@ -282,11 +282,51 @@ static int piix4_setup(struct pci_dev *P
+ return piix4_smba;
+ }
+
++static int piix4_setup_sb800_smba(struct pci_dev *PIIX4_dev,
++ u8 smb_en,
++ u8 aux,
++ u8 *smb_en_status,
++ unsigned short *piix4_smba)
++{
++ u8 smba_en_lo;
++ u8 smba_en_hi;
++ int retval;
++
++ retval = piix4_sb800_region_request(&PIIX4_dev->dev);
++ if (retval)
++ return retval;
++
++ outb_p(smb_en, SB800_PIIX4_SMB_IDX);
++ smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1);
++ outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX);
++ smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1);
++
++ piix4_sb800_region_release(&PIIX4_dev->dev);
++
++ if (!smb_en) {
++ *smb_en_status = smba_en_lo & 0x10;
++ *piix4_smba = smba_en_hi << 8;
++ if (aux)
++ *piix4_smba |= 0x20;
++ } else {
++ *smb_en_status = smba_en_lo & 0x01;
++ *piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0;
++ }
++
++ if (!*smb_en_status) {
++ dev_err(&PIIX4_dev->dev,
++ "SMBus Host Controller not enabled!\n");
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
+ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
+ const struct pci_device_id *id, u8 aux)
+ {
+ unsigned short piix4_smba;
+- u8 smba_en_lo, smba_en_hi, smb_en, smb_en_status, port_sel;
++ u8 smb_en, smb_en_status, port_sel;
+ u8 i2ccfg, i2ccfg_offset = 0x10;
+ int retval;
+
+@@ -310,33 +350,12 @@ static int piix4_setup_sb800(struct pci_
+ else
+ smb_en = (aux) ? 0x28 : 0x2c;
+
+- retval = piix4_sb800_region_request(&PIIX4_dev->dev);
++ retval = piix4_setup_sb800_smba(PIIX4_dev, smb_en, aux, &smb_en_status,
++ &piix4_smba);
++
+ if (retval)
+ return retval;
+
+- outb_p(smb_en, SB800_PIIX4_SMB_IDX);
+- smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1);
+- outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX);
+- smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1);
+-
+- piix4_sb800_region_release(&PIIX4_dev->dev);
+-
+- if (!smb_en) {
+- smb_en_status = smba_en_lo & 0x10;
+- piix4_smba = smba_en_hi << 8;
+- if (aux)
+- piix4_smba |= 0x20;
+- } else {
+- smb_en_status = smba_en_lo & 0x01;
+- piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0;
+- }
+-
+- if (!smb_en_status) {
+- dev_err(&PIIX4_dev->dev,
+- "SMBus Host Controller not enabled!\n");
+- return -ENODEV;
+- }
+-
+ if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
+ return -ENODEV;
+
--- /dev/null
+From fbafbd51bff52cb3a920fd98d4dae2a78dd433d0 Mon Sep 17 00:00:00 2001
+From: Terry Bowman <terry.bowman@amd.com>
+Date: Wed, 9 Feb 2022 11:27:13 -0600
+Subject: i2c: piix4: Move SMBus port selection into function
+
+From: Terry Bowman <terry.bowman@amd.com>
+
+commit fbafbd51bff52cb3a920fd98d4dae2a78dd433d0 upstream.
+
+Move port selection code into a separate function. Refactor is in
+preparation for following MMIO changes.
+
+Signed-off-by: Terry Bowman <terry.bowman@amd.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Reviewed-by: Jean Delvare <jdelvare@suse.de>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Cc: Mario Limonciello <Mario.Limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/i2c/busses/i2c-piix4.c | 27 +++++++++++++++++----------
+ 1 file changed, 17 insertions(+), 10 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-piix4.c
++++ b/drivers/i2c/busses/i2c-piix4.c
+@@ -698,6 +698,20 @@ static void piix4_imc_wakeup(void)
+ release_region(KERNCZ_IMC_IDX, 2);
+ }
+
++static int piix4_sb800_port_sel(u8 port)
++{
++ u8 smba_en_lo, val;
++
++ outb_p(piix4_port_sel_sb800, SB800_PIIX4_SMB_IDX);
++ smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1);
++
++ val = (smba_en_lo & ~piix4_port_mask_sb800) | port;
++ if (smba_en_lo != val)
++ outb_p(val, SB800_PIIX4_SMB_IDX + 1);
++
++ return (smba_en_lo & piix4_port_mask_sb800);
++}
++
+ /*
+ * Handles access to multiple SMBus ports on the SB800.
+ * The port is selected by bits 2:1 of the smb_en register (0x2c).
+@@ -714,8 +728,7 @@ static s32 piix4_access_sb800(struct i2c
+ unsigned short piix4_smba = adapdata->smba;
+ int retries = MAX_TIMEOUT;
+ int smbslvcnt;
+- u8 smba_en_lo;
+- u8 port;
++ u8 prev_port;
+ int retval;
+
+ retval = piix4_sb800_region_request(&adap->dev);
+@@ -775,18 +788,12 @@ static s32 piix4_access_sb800(struct i2c
+ }
+ }
+
+- outb_p(piix4_port_sel_sb800, SB800_PIIX4_SMB_IDX);
+- smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1);
+-
+- port = adapdata->port;
+- if ((smba_en_lo & piix4_port_mask_sb800) != port)
+- outb_p((smba_en_lo & ~piix4_port_mask_sb800) | port,
+- SB800_PIIX4_SMB_IDX + 1);
++ prev_port = piix4_sb800_port_sel(adapdata->port);
+
+ retval = piix4_access(adap, addr, flags, read_write,
+ command, size, data);
+
+- outb_p(smba_en_lo, SB800_PIIX4_SMB_IDX + 1);
++ piix4_sb800_port_sel(prev_port);
+
+ /* Release the semaphore */
+ outb_p(smbslvcnt | 0x20, SMBSLVCNT);
--- /dev/null
+From 93102cb449780f7b4eecf713451627b78373ce49 Mon Sep 17 00:00:00 2001
+From: Terry Bowman <terry.bowman@amd.com>
+Date: Wed, 9 Feb 2022 11:27:10 -0600
+Subject: i2c: piix4: Replace hardcoded memory map size with a #define
+
+From: Terry Bowman <terry.bowman@amd.com>
+
+commit 93102cb449780f7b4eecf713451627b78373ce49 upstream.
+
+Replace number constant with #define to improve readability and
+maintainability.
+
+Signed-off-by: Terry Bowman <terry.bowman@amd.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Reviewed-by: Jean Delvare <jdelvare@suse.de>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Cc: Mario Limonciello <Mario.Limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/i2c/busses/i2c-piix4.c | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-piix4.c
++++ b/drivers/i2c/busses/i2c-piix4.c
+@@ -77,6 +77,7 @@
+
+ /* SB800 constants */
+ #define SB800_PIIX4_SMB_IDX 0xcd6
++#define SB800_PIIX4_SMB_MAP_SIZE 2
+
+ #define KERNCZ_IMC_IDX 0x3e
+ #define KERNCZ_IMC_DATA 0x3f
+@@ -290,7 +291,8 @@ static int piix4_setup_sb800(struct pci_
+ else
+ smb_en = (aux) ? 0x28 : 0x2c;
+
+- if (!request_muxed_region(SB800_PIIX4_SMB_IDX, 2, "sb800_piix4_smb")) {
++ if (!request_muxed_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE,
++ "sb800_piix4_smb")) {
+ dev_err(&PIIX4_dev->dev,
+ "SMB base address index region 0x%x already in use.\n",
+ SB800_PIIX4_SMB_IDX);
+@@ -302,7 +304,7 @@ static int piix4_setup_sb800(struct pci_
+ outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX);
+ smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1);
+
+- release_region(SB800_PIIX4_SMB_IDX, 2);
++ release_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE);
+
+ if (!smb_en) {
+ smb_en_status = smba_en_lo & 0x10;
+@@ -371,7 +373,8 @@ static int piix4_setup_sb800(struct pci_
+ piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT;
+ }
+ } else {
+- if (!request_muxed_region(SB800_PIIX4_SMB_IDX, 2,
++ if (!request_muxed_region(SB800_PIIX4_SMB_IDX,
++ SB800_PIIX4_SMB_MAP_SIZE,
+ "sb800_piix4_smb")) {
+ release_region(piix4_smba, SMBIOSIZE);
+ return -EBUSY;
+@@ -384,7 +387,7 @@ static int piix4_setup_sb800(struct pci_
+ SB800_PIIX4_PORT_IDX;
+ piix4_port_mask_sb800 = SB800_PIIX4_PORT_IDX_MASK;
+ piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT;
+- release_region(SB800_PIIX4_SMB_IDX, 2);
++ release_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE);
+ }
+
+ dev_info(&PIIX4_dev->dev,
+@@ -682,7 +685,8 @@ static s32 piix4_access_sb800(struct i2c
+ u8 port;
+ int retval;
+
+- if (!request_muxed_region(SB800_PIIX4_SMB_IDX, 2, "sb800_piix4_smb"))
++ if (!request_muxed_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE,
++ "sb800_piix4_smb"))
+ return -EBUSY;
+
+ /* Request the SMBUS semaphore, avoid conflicts with the IMC */
+@@ -758,7 +762,7 @@ static s32 piix4_access_sb800(struct i2c
+ piix4_imc_wakeup();
+
+ release:
+- release_region(SB800_PIIX4_SMB_IDX, 2);
++ release_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE);
+ return retval;
+ }
+
--- /dev/null
+From e74ead135bc4459f7d40b1f8edab1333a28b54e8 Mon Sep 17 00:00:00 2001
+From: Pavel Begunkov <asml.silence@gmail.com>
+Date: Sun, 17 Oct 2021 00:07:08 +0100
+Subject: io_uring: arm poll for non-nowait files
+
+From: Pavel Begunkov <asml.silence@gmail.com>
+
+commit e74ead135bc4459f7d40b1f8edab1333a28b54e8 upstream.
+
+Don't check if we can do nowait before arming apoll, there are several
+reasons for that. First, we don't care much about files that don't
+support nowait. Second, it may be useful -- we don't want to be taking
+away extra workers from io-wq when it can go in some async. Even if it
+will go through io-wq eventually, it make difference in the numbers of
+workers actually used. And the last one, it's needed to clean nowait in
+future commits.
+
+[kernel test robot: fix unused-var]
+
+Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
+Link: https://lore.kernel.org/r/9d06f3cb2c8b686d970269a87986f154edb83043.1634425438.git.asml.silence@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/io_uring.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+--- a/fs/io_uring.c
++++ b/fs/io_uring.c
+@@ -5662,7 +5662,6 @@ static int io_arm_poll_handler(struct io
+ struct async_poll *apoll;
+ struct io_poll_table ipt;
+ __poll_t ret, mask = EPOLLONESHOT | POLLERR | POLLPRI;
+- int rw;
+
+ if (!req->file || !file_can_poll(req->file))
+ return IO_APOLL_ABORTED;
+@@ -5672,7 +5671,6 @@ static int io_arm_poll_handler(struct io
+ return IO_APOLL_ABORTED;
+
+ if (def->pollin) {
+- rw = READ;
+ mask |= POLLIN | POLLRDNORM;
+
+ /* If reading from MSG_ERRQUEUE using recvmsg, ignore POLLIN */
+@@ -5680,14 +5678,9 @@ static int io_arm_poll_handler(struct io
+ (req->sr_msg.msg_flags & MSG_ERRQUEUE))
+ mask &= ~POLLIN;
+ } else {
+- rw = WRITE;
+ mask |= POLLOUT | POLLWRNORM;
+ }
+
+- /* if we can't nonblock try, then no point in arming a poll handler */
+- if (!io_file_supports_nowait(req, rw))
+- return IO_APOLL_ABORTED;
+-
+ apoll = kmalloc(sizeof(*apoll), GFP_ATOMIC);
+ if (unlikely(!apoll))
+ return IO_APOLL_ABORTED;
--- /dev/null
+From 27c196c7b73cb70bbed3a9df46563bab60e63415 Mon Sep 17 00:00:00 2001
+From: Terry Bowman <terry.bowman@amd.com>
+Date: Wed, 9 Feb 2022 11:27:09 -0600
+Subject: kernel/resource: Introduce request_mem_region_muxed()
+
+From: Terry Bowman <terry.bowman@amd.com>
+
+commit 27c196c7b73cb70bbed3a9df46563bab60e63415 upstream.
+
+Support for requesting muxed memory region is implemented but not
+currently callable as a macro. Add the request muxed memory
+region macro.
+
+MMIO memory accesses can be synchronized using request_mem_region() which
+is already available. This call will return failure if the resource is
+busy. The 'muxed' version of this macro will handle a busy resource by
+using a wait queue to retry until the resource is available.
+
+Signed-off-by: Terry Bowman <terry.bowman@amd.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Cc: Mario Limonciello <Mario.Limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/ioport.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/include/linux/ioport.h
++++ b/include/linux/ioport.h
+@@ -262,6 +262,8 @@ resource_union(struct resource *r1, stru
+ #define request_muxed_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), IORESOURCE_MUXED)
+ #define __request_mem_region(start,n,name, excl) __request_region(&iomem_resource, (start), (n), (name), excl)
+ #define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0)
++#define request_mem_region_muxed(start, n, name) \
++ __request_region(&iomem_resource, (start), (n), (name), IORESOURCE_MUXED)
+ #define request_mem_region_exclusive(start,n,name) \
+ __request_region(&iomem_resource, (start), (n), (name), IORESOURCE_EXCLUSIVE)
+ #define rename_region(region, newname) do { (region)->name = (newname); } while (0)
--- /dev/null
+From 2839b0999c20c9f6bf353849c69370e121e2fa1a Mon Sep 17 00:00:00 2001
+From: Hyeonggon Yoo <42.hyeyoo@gmail.com>
+Date: Mon, 9 May 2022 17:34:29 -0700
+Subject: mm/kfence: reset PG_slab and memcg_data before freeing __kfence_pool
+
+From: Hyeonggon Yoo <42.hyeyoo@gmail.com>
+
+commit 2839b0999c20c9f6bf353849c69370e121e2fa1a upstream.
+
+When kfence fails to initialize kfence pool, it frees the pool. But it
+does not reset memcg_data and PG_slab flag.
+
+Below is a BUG because of this. Let's fix it by resetting memcg_data
+and PG_slab flag before free.
+
+[ 0.089149] BUG: Bad page state in process swapper/0 pfn:3d8e06
+[ 0.089149] page:ffffea46cf638180 refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x3d8e06
+[ 0.089150] memcg:ffffffff94a475d1
+[ 0.089150] flags: 0x17ffffc0000200(slab|node=0|zone=2|lastcpupid=0x1fffff)
+[ 0.089151] raw: 0017ffffc0000200 ffffea46cf638188 ffffea46cf638188 0000000000000000
+[ 0.089152] raw: 0000000000000000 0000000000000000 00000000ffffffff ffffffff94a475d1
+[ 0.089152] page dumped because: page still charged to cgroup
+[ 0.089153] Modules linked in:
+[ 0.089153] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G B W 5.18.0-rc1+ #965
+[ 0.089154] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014
+[ 0.089154] Call Trace:
+[ 0.089155] <TASK>
+[ 0.089155] dump_stack_lvl+0x49/0x5f
+[ 0.089157] dump_stack+0x10/0x12
+[ 0.089158] bad_page.cold+0x63/0x94
+[ 0.089159] check_free_page_bad+0x66/0x70
+[ 0.089160] __free_pages_ok+0x423/0x530
+[ 0.089161] __free_pages_core+0x8e/0xa0
+[ 0.089162] memblock_free_pages+0x10/0x12
+[ 0.089164] memblock_free_late+0x8f/0xb9
+[ 0.089165] kfence_init+0x68/0x92
+[ 0.089166] start_kernel+0x789/0x992
+[ 0.089167] x86_64_start_reservations+0x24/0x26
+[ 0.089168] x86_64_start_kernel+0xa9/0xaf
+[ 0.089170] secondary_startup_64_no_verify+0xd5/0xdb
+[ 0.089171] </TASK>
+
+Link: https://lkml.kernel.org/r/YnPG3pQrqfcgOlVa@hyeyoo
+Fixes: 0ce20dd84089 ("mm: add Kernel Electric-Fence infrastructure")
+Fixes: 8f0b36497303 ("mm: kfence: fix objcgs vector allocation")
+Signed-off-by: Hyeonggon Yoo <42.hyeyoo@gmail.com>
+Reviewed-by: Marco Elver <elver@google.com>
+Reviewed-by: Muchun Song <songmuchun@bytedance.com>
+Cc: Alexander Potapenko <glider@google.com>
+Cc: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+[42.hyeyoo@gmail.com: backport - use struct page]
+Signed-off-by: Hyeonggon Yoo <42.hyeyoo@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/kfence/core.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/mm/kfence/core.c
++++ b/mm/kfence/core.c
+@@ -510,6 +510,7 @@ static bool __init kfence_init_pool(void
+ unsigned long addr = (unsigned long)__kfence_pool;
+ struct page *pages;
+ int i;
++ char *p;
+
+ if (!__kfence_pool)
+ return false;
+@@ -592,6 +593,16 @@ err:
+ * fails for the first page, and therefore expect addr==__kfence_pool in
+ * most failure cases.
+ */
++ for (p = (char *)addr; p < __kfence_pool + KFENCE_POOL_SIZE; p += PAGE_SIZE) {
++ struct page *page = virt_to_page(p);
++
++ if (!PageSlab(page))
++ continue;
++#ifdef CONFIG_MEMCG
++ page->memcg_data = 0;
++#endif
++ __ClearPageSlab(page);
++ }
+ memblock_free_late(__pa(addr), KFENCE_POOL_SIZE - (addr - (unsigned long)__kfence_pool));
+ __kfence_pool = NULL;
+ return false;
usb-gadget-fix-race-when-gadget-driver-register-via-ioctl.patch
+io_uring-arm-poll-for-non-nowait-files.patch
+floppy-use-a-statically-allocated-error-counter.patch
+kernel-resource-introduce-request_mem_region_muxed.patch
+i2c-piix4-replace-hardcoded-memory-map-size-with-a-define.patch
+i2c-piix4-move-port-i-o-region-request-release-code-into-functions.patch
+i2c-piix4-move-smbus-controller-base-address-detect-into-function.patch
+i2c-piix4-move-smbus-port-selection-into-function.patch
+i2c-piix4-add-efch-mmio-support-to-region-request-and-release.patch
+i2c-piix4-add-efch-mmio-support-to-smbus-base-address-detect.patch
+i2c-piix4-add-efch-mmio-support-for-smbus-port-select.patch
+i2c-piix4-enable-efch-mmio-for-family-17h.patch
+watchdog-sp5100_tco-move-timer-initialization-into-function.patch
+watchdog-sp5100_tco-refactor-mmio-base-address-initialization.patch
+watchdog-sp5100_tco-add-initialization-using-efch-mmio.patch
+watchdog-sp5100_tco-enable-family-17h-cpus.patch
+mm-kfence-reset-pg_slab-and-memcg_data-before-freeing-__kfence_pool.patch
--- /dev/null
+From 0578fff4aae5bce3f09875f58e68e9ffbab8daf5 Mon Sep 17 00:00:00 2001
+From: Terry Bowman <terry.bowman@amd.com>
+Date: Wed, 2 Feb 2022 09:35:24 -0600
+Subject: Watchdog: sp5100_tco: Add initialization using EFCH MMIO
+
+From: Terry Bowman <terry.bowman@amd.com>
+
+commit 0578fff4aae5bce3f09875f58e68e9ffbab8daf5 upstream.
+
+cd6h/cd7h port I/O can be disabled on recent AMD hardware. Read
+accesses to disabled cd6h/cd7h port I/O will return F's and written
+data is dropped. It is recommended to replace the cd6h/cd7h
+port I/O with MMIO.
+
+Co-developed-by: Robert Richter <rrichter@amd.com>
+Signed-off-by: Robert Richter <rrichter@amd.com>
+Signed-off-by: Terry Bowman <terry.bowman@amd.com>
+Tested-by: Jean Delvare <jdelvare@suse.de>
+Reviewed-by: Jean Delvare <jdelvare@suse.de>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Link: https://lore.kernel.org/r/20220202153525.1693378-4-terry.bowman@amd.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
+Cc: Mario Limonciello <Mario.Limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/watchdog/sp5100_tco.c | 100 +++++++++++++++++++++++++++++++++++++++++-
+ drivers/watchdog/sp5100_tco.h | 5 ++
+ 2 files changed, 104 insertions(+), 1 deletion(-)
+
+--- a/drivers/watchdog/sp5100_tco.c
++++ b/drivers/watchdog/sp5100_tco.c
+@@ -48,7 +48,7 @@
+ /* internal variables */
+
+ enum tco_reg_layout {
+- sp5100, sb800, efch
++ sp5100, sb800, efch, efch_mmio
+ };
+
+ struct sp5100_tco {
+@@ -201,6 +201,8 @@ static void tco_timer_enable(struct sp51
+ ~EFCH_PM_WATCHDOG_DISABLE,
+ EFCH_PM_DECODEEN_SECOND_RES);
+ break;
++ default:
++ break;
+ }
+ }
+
+@@ -299,6 +301,99 @@ static int sp5100_tco_timer_init(struct
+ return 0;
+ }
+
++static u8 efch_read_pm_reg8(void __iomem *addr, u8 index)
++{
++ return readb(addr + index);
++}
++
++static void efch_update_pm_reg8(void __iomem *addr, u8 index, u8 reset, u8 set)
++{
++ u8 val;
++
++ val = readb(addr + index);
++ val &= reset;
++ val |= set;
++ writeb(val, addr + index);
++}
++
++static void tco_timer_enable_mmio(void __iomem *addr)
++{
++ efch_update_pm_reg8(addr, EFCH_PM_DECODEEN3,
++ ~EFCH_PM_WATCHDOG_DISABLE,
++ EFCH_PM_DECODEEN_SECOND_RES);
++}
++
++static int sp5100_tco_setupdevice_mmio(struct device *dev,
++ struct watchdog_device *wdd)
++{
++ struct sp5100_tco *tco = watchdog_get_drvdata(wdd);
++ const char *dev_name = SB800_DEVNAME;
++ u32 mmio_addr = 0, alt_mmio_addr = 0;
++ struct resource *res;
++ void __iomem *addr;
++ int ret;
++ u32 val;
++
++ res = request_mem_region_muxed(EFCH_PM_ACPI_MMIO_PM_ADDR,
++ EFCH_PM_ACPI_MMIO_PM_SIZE,
++ "sp5100_tco");
++
++ if (!res) {
++ dev_err(dev,
++ "Memory region 0x%08x already in use\n",
++ EFCH_PM_ACPI_MMIO_PM_ADDR);
++ return -EBUSY;
++ }
++
++ addr = ioremap(EFCH_PM_ACPI_MMIO_PM_ADDR, EFCH_PM_ACPI_MMIO_PM_SIZE);
++ if (!addr) {
++ dev_err(dev, "Address mapping failed\n");
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ /*
++ * EFCH_PM_DECODEEN_WDT_TMREN is dual purpose. This bitfield
++ * enables sp5100_tco register MMIO space decoding. The bitfield
++ * also starts the timer operation. Enable if not already enabled.
++ */
++ val = efch_read_pm_reg8(addr, EFCH_PM_DECODEEN);
++ if (!(val & EFCH_PM_DECODEEN_WDT_TMREN)) {
++ efch_update_pm_reg8(addr, EFCH_PM_DECODEEN, 0xff,
++ EFCH_PM_DECODEEN_WDT_TMREN);
++ }
++
++ /* Error if the timer could not be enabled */
++ val = efch_read_pm_reg8(addr, EFCH_PM_DECODEEN);
++ if (!(val & EFCH_PM_DECODEEN_WDT_TMREN)) {
++ dev_err(dev, "Failed to enable the timer\n");
++ ret = -EFAULT;
++ goto out;
++ }
++
++ mmio_addr = EFCH_PM_WDT_ADDR;
++
++ /* Determine alternate MMIO base address */
++ val = efch_read_pm_reg8(addr, EFCH_PM_ISACONTROL);
++ if (val & EFCH_PM_ISACONTROL_MMIOEN)
++ alt_mmio_addr = EFCH_PM_ACPI_MMIO_ADDR +
++ EFCH_PM_ACPI_MMIO_WDT_OFFSET;
++
++ ret = sp5100_tco_prepare_base(tco, mmio_addr, alt_mmio_addr, dev_name);
++ if (!ret) {
++ tco_timer_enable_mmio(addr);
++ ret = sp5100_tco_timer_init(tco);
++ }
++
++out:
++ if (addr)
++ iounmap(addr);
++
++ release_resource(res);
++
++ return ret;
++}
++
+ static int sp5100_tco_setupdevice(struct device *dev,
+ struct watchdog_device *wdd)
+ {
+@@ -308,6 +403,9 @@ static int sp5100_tco_setupdevice(struct
+ u32 alt_mmio_addr = 0;
+ int ret;
+
++ if (tco->tco_reg_layout == efch_mmio)
++ return sp5100_tco_setupdevice_mmio(dev, wdd);
++
+ /* Request the IO ports used by this driver */
+ if (!request_muxed_region(SP5100_IO_PM_INDEX_REG,
+ SP5100_PM_IOPORTS_SIZE, "sp5100_tco")) {
+--- a/drivers/watchdog/sp5100_tco.h
++++ b/drivers/watchdog/sp5100_tco.h
+@@ -83,4 +83,9 @@
+ #define EFCH_PM_ISACONTROL_MMIOEN BIT(1)
+
+ #define EFCH_PM_ACPI_MMIO_ADDR 0xfed80000
++#define EFCH_PM_ACPI_MMIO_PM_OFFSET 0x00000300
+ #define EFCH_PM_ACPI_MMIO_WDT_OFFSET 0x00000b00
++
++#define EFCH_PM_ACPI_MMIO_PM_ADDR (EFCH_PM_ACPI_MMIO_ADDR + \
++ EFCH_PM_ACPI_MMIO_PM_OFFSET)
++#define EFCH_PM_ACPI_MMIO_PM_SIZE 8
--- /dev/null
+From 826270373f17fd8ebd10753ca0a5fd2ceb1dc38e Mon Sep 17 00:00:00 2001
+From: Terry Bowman <terry.bowman@amd.com>
+Date: Wed, 2 Feb 2022 09:35:25 -0600
+Subject: Watchdog: sp5100_tco: Enable Family 17h+ CPUs
+
+From: Terry Bowman <terry.bowman@amd.com>
+
+commit 826270373f17fd8ebd10753ca0a5fd2ceb1dc38e upstream.
+
+The driver currently uses a CPU family match of 17h to determine
+EFCH_PM_DECODEEN_WDT_TMREN register support. This family check will not
+support future AMD CPUs and instead will require driver updates to add
+support.
+
+Remove the family 17h family check and add a check for SMBus PCI
+revision ID 0x51 or greater. The MMIO access method has been available
+since at least SMBus controllers using PCI revision 0x51. This revision
+check will support family 17h and future AMD processors including EFCH
+functionality without requiring driver changes.
+
+Co-developed-by: Robert Richter <rrichter@amd.com>
+Signed-off-by: Robert Richter <rrichter@amd.com>
+Signed-off-by: Terry Bowman <terry.bowman@amd.com>
+Tested-by: Jean Delvare <jdelvare@suse.de>
+Reviewed-by: Jean Delvare <jdelvare@suse.de>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Link: https://lore.kernel.org/r/20220202153525.1693378-5-terry.bowman@amd.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
+Cc: Mario Limonciello <Mario.Limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/watchdog/sp5100_tco.c | 16 ++++------------
+ drivers/watchdog/sp5100_tco.h | 1 +
+ 2 files changed, 5 insertions(+), 12 deletions(-)
+
+--- a/drivers/watchdog/sp5100_tco.c
++++ b/drivers/watchdog/sp5100_tco.c
+@@ -86,6 +86,10 @@ static enum tco_reg_layout tco_reg_layou
+ dev->revision < 0x40) {
+ return sp5100;
+ } else if (dev->vendor == PCI_VENDOR_ID_AMD &&
++ sp5100_tco_pci->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS &&
++ sp5100_tco_pci->revision >= AMD_ZEN_SMBUS_PCI_REV) {
++ return efch_mmio;
++ } else if (dev->vendor == PCI_VENDOR_ID_AMD &&
+ ((dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS &&
+ dev->revision >= 0x41) ||
+ (dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS &&
+@@ -451,18 +455,6 @@ static int sp5100_tco_setupdevice(struct
+ break;
+ case efch:
+ dev_name = SB800_DEVNAME;
+- /*
+- * On Family 17h devices, the EFCH_PM_DECODEEN_WDT_TMREN bit of
+- * EFCH_PM_DECODEEN not only enables the EFCH_PM_WDT_ADDR memory
+- * region, it also enables the watchdog itself.
+- */
+- if (boot_cpu_data.x86 == 0x17) {
+- val = sp5100_tco_read_pm_reg8(EFCH_PM_DECODEEN);
+- if (!(val & EFCH_PM_DECODEEN_WDT_TMREN)) {
+- sp5100_tco_update_pm_reg8(EFCH_PM_DECODEEN, 0xff,
+- EFCH_PM_DECODEEN_WDT_TMREN);
+- }
+- }
+ val = sp5100_tco_read_pm_reg8(EFCH_PM_DECODEEN);
+ if (val & EFCH_PM_DECODEEN_WDT_TMREN)
+ mmio_addr = EFCH_PM_WDT_ADDR;
+--- a/drivers/watchdog/sp5100_tco.h
++++ b/drivers/watchdog/sp5100_tco.h
+@@ -89,3 +89,4 @@
+ #define EFCH_PM_ACPI_MMIO_PM_ADDR (EFCH_PM_ACPI_MMIO_ADDR + \
+ EFCH_PM_ACPI_MMIO_PM_OFFSET)
+ #define EFCH_PM_ACPI_MMIO_PM_SIZE 8
++#define AMD_ZEN_SMBUS_PCI_REV 0x51
--- /dev/null
+From abd71a948f7aab47ca49d3e7fe6afa6c48c8aae0 Mon Sep 17 00:00:00 2001
+From: Terry Bowman <terry.bowman@amd.com>
+Date: Wed, 2 Feb 2022 09:35:22 -0600
+Subject: Watchdog: sp5100_tco: Move timer initialization into function
+
+From: Terry Bowman <terry.bowman@amd.com>
+
+commit abd71a948f7aab47ca49d3e7fe6afa6c48c8aae0 upstream.
+
+Refactor driver's timer initialization into new function. This is needed
+inorder to support adding new device layouts while using common timer
+initialization.
+
+Co-developed-by: Robert Richter <rrichter@amd.com>
+Signed-off-by: Robert Richter <rrichter@amd.com>
+Signed-off-by: Terry Bowman <terry.bowman@amd.com>
+Tested-by: Jean Delvare <jdelvare@suse.de>
+Reviewed-by: Jean Delvare <jdelvare@suse.de>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Link: https://lore.kernel.org/r/20220202153525.1693378-2-terry.bowman@amd.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
+Cc: Mario Limonciello <Mario.Limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/watchdog/sp5100_tco.c | 65 +++++++++++++++++++++++-------------------
+ 1 file changed, 36 insertions(+), 29 deletions(-)
+
+--- a/drivers/watchdog/sp5100_tco.c
++++ b/drivers/watchdog/sp5100_tco.c
+@@ -215,6 +215,41 @@ static u32 sp5100_tco_read_pm_reg32(u8 i
+ return val;
+ }
+
++static int sp5100_tco_timer_init(struct sp5100_tco *tco)
++{
++ struct watchdog_device *wdd = &tco->wdd;
++ struct device *dev = wdd->parent;
++ u32 val;
++
++ val = readl(SP5100_WDT_CONTROL(tco->tcobase));
++ if (val & SP5100_WDT_DISABLED) {
++ dev_err(dev, "Watchdog hardware is disabled\n");
++ return -ENODEV;
++ }
++
++ /*
++ * Save WatchDogFired status, because WatchDogFired flag is
++ * cleared here.
++ */
++ if (val & SP5100_WDT_FIRED)
++ wdd->bootstatus = WDIOF_CARDRESET;
++
++ /* Set watchdog action to reset the system */
++ val &= ~SP5100_WDT_ACTION_RESET;
++ writel(val, SP5100_WDT_CONTROL(tco->tcobase));
++
++ /* Set a reasonable heartbeat before we stop the timer */
++ tco_timer_set_timeout(wdd, wdd->timeout);
++
++ /*
++ * Stop the TCO before we change anything so we don't race with
++ * a zeroed timer.
++ */
++ tco_timer_stop(wdd);
++
++ return 0;
++}
++
+ static int sp5100_tco_setupdevice(struct device *dev,
+ struct watchdog_device *wdd)
+ {
+@@ -340,35 +375,7 @@ static int sp5100_tco_setupdevice(struct
+ /* Setup the watchdog timer */
+ tco_timer_enable(tco);
+
+- val = readl(SP5100_WDT_CONTROL(tco->tcobase));
+- if (val & SP5100_WDT_DISABLED) {
+- dev_err(dev, "Watchdog hardware is disabled\n");
+- ret = -ENODEV;
+- goto unreg_region;
+- }
+-
+- /*
+- * Save WatchDogFired status, because WatchDogFired flag is
+- * cleared here.
+- */
+- if (val & SP5100_WDT_FIRED)
+- wdd->bootstatus = WDIOF_CARDRESET;
+- /* Set watchdog action to reset the system */
+- val &= ~SP5100_WDT_ACTION_RESET;
+- writel(val, SP5100_WDT_CONTROL(tco->tcobase));
+-
+- /* Set a reasonable heartbeat before we stop the timer */
+- tco_timer_set_timeout(wdd, wdd->timeout);
+-
+- /*
+- * Stop the TCO before we change anything so we don't race with
+- * a zeroed timer.
+- */
+- tco_timer_stop(wdd);
+-
+- release_region(SP5100_IO_PM_INDEX_REG, SP5100_PM_IOPORTS_SIZE);
+-
+- return 0;
++ ret = sp5100_tco_timer_init(tco);
+
+ unreg_region:
+ release_region(SP5100_IO_PM_INDEX_REG, SP5100_PM_IOPORTS_SIZE);
--- /dev/null
+From 1f182aca230086d4a4469c0f9136a6ea762d6385 Mon Sep 17 00:00:00 2001
+From: Terry Bowman <terry.bowman@amd.com>
+Date: Wed, 2 Feb 2022 09:35:23 -0600
+Subject: Watchdog: sp5100_tco: Refactor MMIO base address initialization
+
+From: Terry Bowman <terry.bowman@amd.com>
+
+commit 1f182aca230086d4a4469c0f9136a6ea762d6385 upstream.
+
+Combine MMIO base address and alternate base address detection. Combine
+based on layout type. This will simplify the function by eliminating
+a switch case.
+
+Move existing request/release code into functions. This currently only
+supports port I/O request/release. The move into a separate function
+will make it ready for adding MMIO region support.
+
+Co-developed-by: Robert Richter <rrichter@amd.com>
+Signed-off-by: Robert Richter <rrichter@amd.com>
+Signed-off-by: Terry Bowman <terry.bowman@amd.com>
+Tested-by: Jean Delvare <jdelvare@suse.de>
+Reviewed-by: Jean Delvare <jdelvare@suse.de>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Link: https://lore.kernel.org/r/20220202153525.1693378-3-terry.bowman@amd.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
+Cc: Mario Limonciello <Mario.Limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/watchdog/sp5100_tco.c | 155 +++++++++++++++++++++---------------------
+ drivers/watchdog/sp5100_tco.h | 1
+ 2 files changed, 82 insertions(+), 74 deletions(-)
+
+--- a/drivers/watchdog/sp5100_tco.c
++++ b/drivers/watchdog/sp5100_tco.c
+@@ -215,6 +215,55 @@ static u32 sp5100_tco_read_pm_reg32(u8 i
+ return val;
+ }
+
++static u32 sp5100_tco_request_region(struct device *dev,
++ u32 mmio_addr,
++ const char *dev_name)
++{
++ if (!devm_request_mem_region(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE,
++ dev_name)) {
++ dev_dbg(dev, "MMIO address 0x%08x already in use\n", mmio_addr);
++ return 0;
++ }
++
++ return mmio_addr;
++}
++
++static u32 sp5100_tco_prepare_base(struct sp5100_tco *tco,
++ u32 mmio_addr,
++ u32 alt_mmio_addr,
++ const char *dev_name)
++{
++ struct device *dev = tco->wdd.parent;
++
++ dev_dbg(dev, "Got 0x%08x from SBResource_MMIO register\n", mmio_addr);
++
++ if (!mmio_addr && !alt_mmio_addr)
++ return -ENODEV;
++
++ /* Check for MMIO address and alternate MMIO address conflicts */
++ if (mmio_addr)
++ mmio_addr = sp5100_tco_request_region(dev, mmio_addr, dev_name);
++
++ if (!mmio_addr && alt_mmio_addr)
++ mmio_addr = sp5100_tco_request_region(dev, alt_mmio_addr, dev_name);
++
++ if (!mmio_addr) {
++ dev_err(dev, "Failed to reserve MMIO or alternate MMIO region\n");
++ return -EBUSY;
++ }
++
++ tco->tcobase = devm_ioremap(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE);
++ if (!tco->tcobase) {
++ dev_err(dev, "MMIO address 0x%08x failed mapping\n", mmio_addr);
++ devm_release_mem_region(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE);
++ return -ENOMEM;
++ }
++
++ dev_info(dev, "Using 0x%08x for watchdog MMIO address\n", mmio_addr);
++
++ return 0;
++}
++
+ static int sp5100_tco_timer_init(struct sp5100_tco *tco)
+ {
+ struct watchdog_device *wdd = &tco->wdd;
+@@ -256,6 +305,7 @@ static int sp5100_tco_setupdevice(struct
+ struct sp5100_tco *tco = watchdog_get_drvdata(wdd);
+ const char *dev_name;
+ u32 mmio_addr = 0, val;
++ u32 alt_mmio_addr = 0;
+ int ret;
+
+ /* Request the IO ports used by this driver */
+@@ -274,11 +324,32 @@ static int sp5100_tco_setupdevice(struct
+ dev_name = SP5100_DEVNAME;
+ mmio_addr = sp5100_tco_read_pm_reg32(SP5100_PM_WATCHDOG_BASE) &
+ 0xfffffff8;
++
++ /*
++ * Secondly, find the watchdog timer MMIO address
++ * from SBResource_MMIO register.
++ */
++
++ /* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */
++ pci_read_config_dword(sp5100_tco_pci,
++ SP5100_SB_RESOURCE_MMIO_BASE,
++ &val);
++
++ /* Verify MMIO is enabled and using bar0 */
++ if ((val & SB800_ACPI_MMIO_MASK) == SB800_ACPI_MMIO_DECODE_EN)
++ alt_mmio_addr = (val & ~0xfff) + SB800_PM_WDT_MMIO_OFFSET;
+ break;
+ case sb800:
+ dev_name = SB800_DEVNAME;
+ mmio_addr = sp5100_tco_read_pm_reg32(SB800_PM_WATCHDOG_BASE) &
+ 0xfffffff8;
++
++ /* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */
++ val = sp5100_tco_read_pm_reg32(SB800_PM_ACPI_MMIO_EN);
++
++ /* Verify MMIO is enabled and using bar0 */
++ if ((val & SB800_ACPI_MMIO_MASK) == SB800_ACPI_MMIO_DECODE_EN)
++ alt_mmio_addr = (val & ~0xfff) + SB800_PM_WDT_MMIO_OFFSET;
+ break;
+ case efch:
+ dev_name = SB800_DEVNAME;
+@@ -297,87 +368,23 @@ static int sp5100_tco_setupdevice(struct
+ val = sp5100_tco_read_pm_reg8(EFCH_PM_DECODEEN);
+ if (val & EFCH_PM_DECODEEN_WDT_TMREN)
+ mmio_addr = EFCH_PM_WDT_ADDR;
++
++ val = sp5100_tco_read_pm_reg8(EFCH_PM_ISACONTROL);
++ if (val & EFCH_PM_ISACONTROL_MMIOEN)
++ alt_mmio_addr = EFCH_PM_ACPI_MMIO_ADDR +
++ EFCH_PM_ACPI_MMIO_WDT_OFFSET;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+- /* Check MMIO address conflict */
+- if (!mmio_addr ||
+- !devm_request_mem_region(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE,
+- dev_name)) {
+- if (mmio_addr)
+- dev_dbg(dev, "MMIO address 0x%08x already in use\n",
+- mmio_addr);
+- switch (tco->tco_reg_layout) {
+- case sp5100:
+- /*
+- * Secondly, Find the watchdog timer MMIO address
+- * from SBResource_MMIO register.
+- */
+- /* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */
+- pci_read_config_dword(sp5100_tco_pci,
+- SP5100_SB_RESOURCE_MMIO_BASE,
+- &mmio_addr);
+- if ((mmio_addr & (SB800_ACPI_MMIO_DECODE_EN |
+- SB800_ACPI_MMIO_SEL)) !=
+- SB800_ACPI_MMIO_DECODE_EN) {
+- ret = -ENODEV;
+- goto unreg_region;
+- }
+- mmio_addr &= ~0xFFF;
+- mmio_addr += SB800_PM_WDT_MMIO_OFFSET;
+- break;
+- case sb800:
+- /* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */
+- mmio_addr =
+- sp5100_tco_read_pm_reg32(SB800_PM_ACPI_MMIO_EN);
+- if ((mmio_addr & (SB800_ACPI_MMIO_DECODE_EN |
+- SB800_ACPI_MMIO_SEL)) !=
+- SB800_ACPI_MMIO_DECODE_EN) {
+- ret = -ENODEV;
+- goto unreg_region;
+- }
+- mmio_addr &= ~0xFFF;
+- mmio_addr += SB800_PM_WDT_MMIO_OFFSET;
+- break;
+- case efch:
+- val = sp5100_tco_read_pm_reg8(EFCH_PM_ISACONTROL);
+- if (!(val & EFCH_PM_ISACONTROL_MMIOEN)) {
+- ret = -ENODEV;
+- goto unreg_region;
+- }
+- mmio_addr = EFCH_PM_ACPI_MMIO_ADDR +
+- EFCH_PM_ACPI_MMIO_WDT_OFFSET;
+- break;
+- }
+- dev_dbg(dev, "Got 0x%08x from SBResource_MMIO register\n",
+- mmio_addr);
+- if (!devm_request_mem_region(dev, mmio_addr,
+- SP5100_WDT_MEM_MAP_SIZE,
+- dev_name)) {
+- dev_dbg(dev, "MMIO address 0x%08x already in use\n",
+- mmio_addr);
+- ret = -EBUSY;
+- goto unreg_region;
+- }
++ ret = sp5100_tco_prepare_base(tco, mmio_addr, alt_mmio_addr, dev_name);
++ if (!ret) {
++ /* Setup the watchdog timer */
++ tco_timer_enable(tco);
++ ret = sp5100_tco_timer_init(tco);
+ }
+
+- tco->tcobase = devm_ioremap(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE);
+- if (!tco->tcobase) {
+- dev_err(dev, "failed to get tcobase address\n");
+- ret = -ENOMEM;
+- goto unreg_region;
+- }
+-
+- dev_info(dev, "Using 0x%08x for watchdog MMIO address\n", mmio_addr);
+-
+- /* Setup the watchdog timer */
+- tco_timer_enable(tco);
+-
+- ret = sp5100_tco_timer_init(tco);
+-
+-unreg_region:
+ release_region(SP5100_IO_PM_INDEX_REG, SP5100_PM_IOPORTS_SIZE);
+ return ret;
+ }
+--- a/drivers/watchdog/sp5100_tco.h
++++ b/drivers/watchdog/sp5100_tco.h
+@@ -58,6 +58,7 @@
+ #define SB800_PM_WATCHDOG_SECOND_RES GENMASK(1, 0)
+ #define SB800_ACPI_MMIO_DECODE_EN BIT(0)
+ #define SB800_ACPI_MMIO_SEL BIT(1)
++#define SB800_ACPI_MMIO_MASK GENMASK(1, 0)
+
+ #define SB800_PM_WDT_MMIO_OFFSET 0xB00
+