[PATCH v3 2/4] Watchdog: sp5100_tco: Refactor MMIO base address initialization
From: Terry Bowman
Date: Tue Jan 18 2022 - 15:23:12 EST
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@xxxxxxx>
Signed-off-by: Robert Richter <rrichter@xxxxxxx>
Signed-off-by: Terry Bowman <terry.bowman@xxxxxxx>
To: Guenter Roeck <linux@xxxxxxxxxxxx>
To: linux-watchdog@xxxxxxxxxxxxxxx
To: Jean Delvare <jdelvare@xxxxxxxx>
To: linux-i2c@xxxxxxxxxxxxxxx
To: Wolfram Sang <wsa@xxxxxxxxxx>
To: Andy Shevchenko <andy.shevchenko@xxxxxxxxx>
To: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
Cc: linux-kernel@xxxxxxxxxxxxxxx
Cc: Wim Van Sebroeck <wim@xxxxxxxxxxxxxxxxxx>
Cc: Robert Richter <rrichter@xxxxxxx>
Cc: Thomas Lendacky <thomas.lendacky@xxxxxxx>
---
drivers/watchdog/sp5100_tco.c | 168 +++++++++++++++++++---------------
1 file changed, 95 insertions(+), 73 deletions(-)
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
index ecc273b9b17f..64ecebd93403 100644
--- a/drivers/watchdog/sp5100_tco.c
+++ b/drivers/watchdog/sp5100_tco.c
@@ -223,6 +223,66 @@ static u32 sp5100_tco_read_pm_reg32(u8 index)
return val;
}
+static int __sp5100_tco_prepare_base(struct sp5100_tco *tco,
+ u32 mmio_addr,
+ const char *dev_name)
+{
+ struct device *dev = tco->wdd.parent;
+ int ret = 0;
+
+ if (!mmio_addr)
+ return -ENOMEM;
+
+ 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 -EBUSY;
+ }
+
+ tco->tcobase = devm_ioremap(dev, mmio_addr,
+ SP5100_WDT_MEM_MAP_SIZE);
+ if (!tco->tcobase) {
+ dev_dbg(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 ret;
+}
+
+static int 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;
+ int ret = 0;
+
+ dev_dbg(dev, "Got 0x%08x from SBResource_MMIO register\n",
+ mmio_addr);
+
+ /* Check MMIO address conflict */
+ ret = __sp5100_tco_prepare_base(tco, mmio_addr, dev_name);
+
+ /* Check alternate MMIO address conflict */
+ if (ret)
+ ret = __sp5100_tco_prepare_base(tco, alt_mmio_addr,
+ dev_name);
+
+ if (ret)
+ dev_err(dev, "Failed to reserve-map MMIO (%X) and alternate MMIO (%X) regions. ret=%X",
+ mmio_addr, alt_mmio_addr, ret);
+
+ return ret;
+}
+
static int sp5100_tco_timer_init(struct sp5100_tco *tco)
{
struct watchdog_device *wdd = &tco->wdd;
@@ -264,6 +324,7 @@ static int sp5100_tco_setupdevice(struct device *dev,
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 */
@@ -282,11 +343,35 @@ static int sp5100_tco_setupdevice(struct device *dev,
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,
+ &alt_mmio_addr);
+ if (alt_mmio_addr & ((SB800_ACPI_MMIO_DECODE_EN |
+ SB800_ACPI_MMIO_SEL) !=
+ SB800_ACPI_MMIO_DECODE_EN)) {
+ alt_mmio_addr &= ~0xFFF;
+ alt_mmio_addr += 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) */
+ alt_mmio_addr =
+ sp5100_tco_read_pm_reg32(SB800_PM_ACPI_MMIO_EN);
+ if (!(alt_mmio_addr & (((SB800_ACPI_MMIO_DECODE_EN |
+ SB800_ACPI_MMIO_SEL)) !=
+ SB800_ACPI_MMIO_DECODE_EN))) {
+ alt_mmio_addr &= ~0xFFF;
+ alt_mmio_addr += SB800_PM_WDT_MMIO_OFFSET;
+ }
break;
case efch:
dev_name = SB800_DEVNAME;
@@ -305,87 +390,24 @@ static int sp5100_tco_setupdevice(struct device *dev,
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);
- 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;
+ ret = sp5100_tco_timer_init(tco);
}
- 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;
}
--
2.30.2