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