Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1614950 > unrolled thread

[PATCH 0/3 v2] Fix regression in the sp5100_tco driver

Started byZoltan Boszormenyi <zboszor@pr.hu>
First post2017-04-03 10:00 +0200
Last post2017-04-03 10:00 +0200
Articles 3 — 1 participant

Back to article view | Back to linux.kernel

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  [PATCH 0/3 v2] Fix regression in the sp5100_tco driver Zoltan Boszormenyi <zboszor@pr.hu> - 2017-04-03 10:00 +0200
    [PATCH 1/3 v2] usb: pci-quirks: Add a common mutex for the I/O port pair of SB800 Zoltan Boszormenyi <zboszor@pr.hu> - 2017-04-03 10:00 +0200
    [PATCH 3/3 v2] watchdog: sp5100_tco: Use the common mutex Zoltan Boszormenyi <zboszor@pr.hu> - 2017-04-03 10:00 +0200

#1614950 — [PATCH 0/3 v2] Fix regression in the sp5100_tco driver

FromZoltan Boszormenyi <zboszor@pr.hu>
Date2017-04-03 10:00 +0200
Subject[PATCH 0/3 v2] Fix regression in the sp5100_tco driver
Message-ID<ts545-3XB-5@gated-at.bofh.it>
Three drivers are accessing the same I/O ports (0xcd6 / 0xcd7) on
AMD SB800 based machines without synchronization or with excluding
each other out:
* the USB quirk for isochronous transfers on SB800 (no locking)
* sp5100_tco (request_region)
* i2c-piix4 (request_region)

Historically, the sp5100_tco watchdog driver used request_region()
for these I/O ports but an i2c-piix4 improvement for SB800 in
Linux 4.4-rc4 also added a request_region() call. Because of this
and the load order, this cause a regression and the watchdog function
became non-functional. The commit that caused the regression is:

commit 2fee61d22e606fc99ade9079fda15fdee83ec33e
Author: Christian Fetzer <fetzer.ch@gmail.com>
Date:   Thu Nov 19 20:13:48 2015 +0100

    i2c: piix4: Add support for multiplexed main adapter in SB800

I was informed by Guenter Roeck <linux@roeck-us.net> that the
alternative, i.e. using request_muxed_region() can fail, either
because of a resource allocation failure, which is quite possible
with long uptimes, or because there are no guarantees that an as yet
unknown driver would also use request_muxed_region() consistently.

Because of this, a solution using a common mutex was chosen to
synchronize I/O port accesses and request_region() calls are removed
from both i2c-piix4 and sp5100_tco to make the code uniform.

This patch series implements this and restores the watchdog function.

v2: Don't introduce a new header, reference sb800_mutex explicitly

Signed-off-by: Zoltan Boszormenyi <zboszor@pr.hu>

 drivers/i2c/busses/i2c-piix4.c | 43 +++++++++++++------------------------------
 drivers/usb/host/pci-quirks.c  |  5 +++++
 drivers/watchdog/sp5100_tco.c  | 31 ++++++++++++++++++-------------
 3 files changed, 36 insertions(+), 43 deletions(-)

[toc] | [next] | [standalone]


#1614951 — [PATCH 1/3 v2] usb: pci-quirks: Add a common mutex for the I/O port pair of SB800

FromZoltan Boszormenyi <zboszor@pr.hu>
Date2017-04-03 10:00 +0200
Subject[PATCH 1/3 v2] usb: pci-quirks: Add a common mutex for the I/O port pair of SB800
Message-ID<ts545-3XB-7@gated-at.bofh.it>
In reply to#1614950
This patch adds a common mutex in the USB PCI quirks code and starts
using it to synchronize access to the I/O port pair 0xcd6 / 0xcd7 on
SB800.

These I/O ports are also used by i2c-piix4 and sp5100_tco, the next
two patches port these drivers to use this common mutex.

v2: No extra header and no wrapper for mutex_lock() / mutex_unlock()

Signed-off-by: Zoltan Boszormenyi <zboszor@pr.hu>
---
 drivers/usb/host/pci-quirks.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index a9a1e4c..1ef0ada 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -279,6 +279,9 @@ bool usb_amd_prefetch_quirk(void)
 }
 EXPORT_SYMBOL_GPL(usb_amd_prefetch_quirk);
 
+DEFINE_MUTEX(sb800_mutex);
+EXPORT_SYMBOL_GPL(sb800_mutex);
+
 /*
  * The hardware normally enables the A-link power management feature, which
  * lets the system lower the power consumption in idle states.
@@ -314,11 +317,13 @@ static void usb_amd_quirk_pll(int disable)
 	if (amd_chipset.sb_type.gen == AMD_CHIPSET_SB800 ||
 			amd_chipset.sb_type.gen == AMD_CHIPSET_HUDSON2 ||
 			amd_chipset.sb_type.gen == AMD_CHIPSET_BOLTON) {
+		mutex_lock(&sb800_mutex);
 		outb_p(AB_REG_BAR_LOW, 0xcd6);
 		addr_low = inb_p(0xcd7);
 		outb_p(AB_REG_BAR_HIGH, 0xcd6);
 		addr_high = inb_p(0xcd7);
 		addr = addr_high << 8 | addr_low;
+		mutex_unlock(&sb800_mutex);
 
 		outl_p(0x30, AB_INDX(addr));
 		outl_p(0x40, AB_DATA(addr));
-- 
2.9.3

[toc] | [prev] | [next] | [standalone]


#1614952 — [PATCH 3/3 v2] watchdog: sp5100_tco: Use the common mutex

FromZoltan Boszormenyi <zboszor@pr.hu>
Date2017-04-03 10:00 +0200
Subject[PATCH 3/3 v2] watchdog: sp5100_tco: Use the common mutex
Message-ID<ts546-3XB-19@gated-at.bofh.it>
In reply to#1614950
Use the common mutex from usb/host/pci-quirks.c to synchronize
accesses to the SB800 I/O port pair (0xcd6 / 0xcd7) with the
PCI quirk for isochronous USB transfers and with the i2c-piix4
driver.

At the same time, remove the request_region() call to reserve
these I/O ports, similarly to i2c-piix4 so the code is now uniform
across the three individual drivers.

v2: Explicit extern reference for sb800_mutex

Signed-off-by: Zoltan Boszormenyi <zboszor@pr.hu>
---
 drivers/watchdog/sp5100_tco.c | 31 ++++++++++++++++++-------------
 1 file changed, 18 insertions(+), 13 deletions(-)

diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
index 028618c..4dca9e89 100644
--- a/drivers/watchdog/sp5100_tco.c
+++ b/drivers/watchdog/sp5100_tco.c
@@ -36,9 +36,16 @@
 #include <linux/platform_device.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
+#include <linux/mutex.h>
 
 #include "sp5100_tco.h"
 
+/*
+ * sb800_mutex in drivers/usb/host/pci-quirks.c protects
+ * parallel access to the I/O port pair 0xCD6 / 0xCD7.
+ */
+extern struct mutex sb800_mutex;
+
 /* Module and version information */
 #define TCO_VERSION "0.05"
 #define TCO_MODULE_NAME "SP5100 TCO timer"
@@ -48,7 +55,6 @@
 static u32 tcobase_phys;
 static u32 tco_wdt_fired;
 static void __iomem *tcobase;
-static unsigned int pm_iobase;
 static DEFINE_SPINLOCK(tco_lock);	/* Guards the hardware */
 static unsigned long timer_alive;
 static char tco_expect_close;
@@ -138,6 +144,8 @@ static void tco_timer_enable(void)
 
 	if (!tco_has_sp5100_reg_layout(sp5100_tco_pci)) {
 		/* For SB800 or later */
+		mutex_lock(&sb800_mutex);
+
 		/* Set the Watchdog timer resolution to 1 sec */
 		outb(SB800_PM_WATCHDOG_CONFIG, SB800_IO_PM_INDEX_REG);
 		val = inb(SB800_IO_PM_DATA_REG);
@@ -150,6 +158,8 @@ static void tco_timer_enable(void)
 		val |= SB800_PCI_WATCHDOG_DECODE_EN;
 		val &= ~SB800_PM_WATCHDOG_DISABLE;
 		outb(val, SB800_IO_PM_DATA_REG);
+
+		mutex_unlock(&sb800_mutex);
 	} else {
 		/* For SP5100 or SB7x0 */
 		/* Enable watchdog decode bit */
@@ -164,11 +174,13 @@ static void tco_timer_enable(void)
 				       val);
 
 		/* Enable Watchdog timer and set the resolution to 1 sec */
+		mutex_lock(&sb800_mutex);
 		outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG);
 		val = inb(SP5100_IO_PM_DATA_REG);
 		val |= SP5100_PM_WATCHDOG_SECOND_RES;
 		val &= ~SP5100_PM_WATCHDOG_DISABLE;
 		outb(val, SP5100_IO_PM_DATA_REG);
+		mutex_unlock(&sb800_mutex);
 	}
 }
 
@@ -361,16 +373,10 @@ static unsigned char sp5100_tco_setupdevice(void)
 		base_addr = SB800_PM_WATCHDOG_BASE;
 	}
 
-	/* Request the IO ports used by this driver */
-	pm_iobase = SP5100_IO_PM_INDEX_REG;
-	if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, dev_name)) {
-		pr_err("I/O address 0x%04x already in use\n", pm_iobase);
-		goto exit;
-	}
-
 	/*
 	 * First, Find the watchdog timer MMIO address from indirect I/O.
 	 */
+	mutex_lock(&sb800_mutex);
 	outb(base_addr+3, index_reg);
 	val = inb(data_reg);
 	outb(base_addr+2, index_reg);
@@ -380,6 +386,7 @@ static unsigned char sp5100_tco_setupdevice(void)
 	outb(base_addr+0, index_reg);
 	/* Low three bits of BASE are reserved */
 	val = val << 8 | (inb(data_reg) & 0xf8);
+	mutex_unlock(&sb800_mutex);
 
 	pr_debug("Got 0x%04x from indirect I/O\n", val);
 
@@ -400,6 +407,7 @@ static unsigned char sp5100_tco_setupdevice(void)
 				      SP5100_SB_RESOURCE_MMIO_BASE, &val);
 	} else {
 		/* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */
+		mutex_lock(&sb800_mutex);
 		outb(SB800_PM_ACPI_MMIO_EN+3, SB800_IO_PM_INDEX_REG);
 		val = inb(SB800_IO_PM_DATA_REG);
 		outb(SB800_PM_ACPI_MMIO_EN+2, SB800_IO_PM_INDEX_REG);
@@ -408,6 +416,7 @@ static unsigned char sp5100_tco_setupdevice(void)
 		val = val << 8 | inb(SB800_IO_PM_DATA_REG);
 		outb(SB800_PM_ACPI_MMIO_EN+0, SB800_IO_PM_INDEX_REG);
 		val = val << 8 | inb(SB800_IO_PM_DATA_REG);
+		mutex_unlock(&sb800_mutex);
 	}
 
 	/* The SBResource_MMIO is enabled and mapped memory space? */
@@ -429,7 +438,7 @@ static unsigned char sp5100_tco_setupdevice(void)
 		pr_debug("SBResource_MMIO is disabled(0x%04x)\n", val);
 
 	pr_notice("failed to find MMIO address, giving up.\n");
-	goto  unreg_region;
+	goto  exit;
 
 setup_wdt:
 	tcobase_phys = val;
@@ -469,8 +478,6 @@ static unsigned char sp5100_tco_setupdevice(void)
 
 unreg_mem_region:
 	release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
-unreg_region:
-	release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
 exit:
 	return 0;
 }
@@ -517,7 +524,6 @@ static int sp5100_tco_init(struct platform_device *dev)
 exit:
 	iounmap(tcobase);
 	release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
-	release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
 	return ret;
 }
 
@@ -531,7 +537,6 @@ static void sp5100_tco_cleanup(void)
 	misc_deregister(&sp5100_tco_miscdev);
 	iounmap(tcobase);
 	release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
-	release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
 }
 
 static int sp5100_tco_remove(struct platform_device *dev)
-- 
2.9.3

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web