All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vincent Pelletier <plr.vincent@gmail.com>
To: linux-gpio@vger.kernel.org
Cc: Simon Guinot <simon.guinot@sequanux.org>
Subject: [1/4] gpio: gpio-f7188x: Use mutex for access serialisation.
Date: Thu, 20 Aug 2015 20:03:26 +0200	[thread overview]
Message-ID: <7d1a2156ddabe0b72964e88734adba307a472067.1440093298.git.plr.vincent@gmail.com> (raw)
In-Reply-To: <1440093809-18234-1-git-send-email-plr.vincent@gmail.com>

For some (unclear to me) reason, superio_enter/superio_exit, although
calling request_muxed_region/release_region (respectively), are not
sufficient on an multi-processor system to guarantee serialised access,
leading to the following errors:
[ 1210.586990] Trying to free nonexistent resource <000000000000002e-000000000000002f>
[ 1211.227414] Trying to free nonexistent resource <000000000000002e-000000000000002f>
[ 1211.867890] Trying to free nonexistent resource <000000000000002e-000000000000002f>
[ 1212.508299] Trying to free nonexistent resource <000000000000002e-000000000000002f>
[ 1213.148734] Trying to free nonexistent resource <000000000000002e-000000000000002f>
[ 1213.789172] Trying to free nonexistent resource <000000000000002e-000000000000002f>
[ 1214.429607] Trying to free nonexistent resource <000000000000002e-000000000000002f>

Disabling all but one core make the error disappear, and re-enabling it
make it reappear.

Loaded modules for this SuperIO chip on this system are:
  8250_fintek (not actively used)
  fintek_cir (not actively used)
  f71882fg (polled every 2 seconds from userland)
  gpio_f7188x

Loaded modules using GPIO functionality:
  gpio_keys_polled (20ms polling period)
  leds_gpio (usb-host and 500ms timer triggers)

This change replaces frequent superio_enter/superio_exit and accesses via the
common GPIO IO region (0x2e..0x2f or 0x4e..0x4f) with mutex locking and
accesses via GPIO-dedicated IO region (pre-configured on chip).

Code inspired from hwmon/f71882fg .

Signed-off-by: Vincent Pelletier <plr.vincent@gmail.com>
---
 drivers/gpio/gpio-f7188x.c | 126 ++++++++++++++++++++++++++++-----------------
 1 file changed, 80 insertions(+), 46 deletions(-)

diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c
index dbda843..2915f8d 100644
--- a/drivers/gpio/gpio-f7188x.c
+++ b/drivers/gpio/gpio-f7188x.c
@@ -16,6 +16,8 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/mutex.h>
+#include <linux/acpi.h>
 
 #define DRVNAME "gpio-f7188x"
 
@@ -26,11 +28,17 @@
 #define SIO_DEVID		0x20	/* Device ID (2 bytes) */
 #define SIO_DEVREV		0x22	/* Device revision */
 #define SIO_MANID		0x23	/* Fintek ID (2 bytes) */
+#define SIO_ENABLE		0x30	/* Logical device enable */
+#define SIO_ADDR		0x60	/* Logical device address (2 bytes) */
 
 #define SIO_LD_GPIO		0x06	/* GPIO logical device */
 #define SIO_UNLOCK_KEY		0x87	/* Key to enable Super-I/O */
 #define SIO_LOCK_KEY		0xAA	/* Key to disable Super-I/O */
 
+#define REGION_LENGTH		8
+#define ADDR_REG_OFFSET		5
+#define DATA_REG_OFFSET		6
+
 #define SIO_FINTEK_ID		0x1934	/* Manufacturer ID */
 #define SIO_F71869_ID		0x0814	/* F71869 chipset ID */
 #define SIO_F71869A_ID		0x1007	/* F71869A chipset ID */
@@ -47,8 +55,9 @@ static const char * const f7188x_names[] = {
 };
 
 struct f7188x_sio {
-	int addr;
+	u16 addr;
 	enum chips type;
+	struct mutex lock;
 };
 
 struct f7188x_gpio_bank {
@@ -118,6 +127,22 @@ static inline void superio_exit(int base)
 	release_region(base, 2);
 }
 
+static u8 f7188x_read8(struct f7188x_sio *data, u8 reg)
+{
+	u8 val;
+
+	outb(reg, data->addr + ADDR_REG_OFFSET);
+	val = inb(data->addr + DATA_REG_OFFSET);
+
+	return val;
+}
+
+static void f7188x_write8(struct f7188x_sio *data, u8 reg, u8 val)
+{
+	outb(reg, data->addr + ADDR_REG_OFFSET);
+	outb(val, data->addr + DATA_REG_OFFSET);
+}
+
 /*
  * GPIO chip.
  */
@@ -192,47 +217,35 @@ static struct f7188x_gpio_bank f71889_gpio_bank[] = {
 
 static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
-	int err;
 	struct f7188x_gpio_bank *bank =
 		container_of(chip, struct f7188x_gpio_bank, chip);
 	struct f7188x_sio *sio = bank->data->sio;
 	u8 dir;
 
-	err = superio_enter(sio->addr);
-	if (err)
-		return err;
-	superio_select(sio->addr, SIO_LD_GPIO);
-
-	dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
+	mutex_lock(&sio->lock);
+	dir = f7188x_read8(sio, gpio_dir(bank->regbase));
 	dir &= ~(1 << offset);
-	superio_outb(sio->addr, gpio_dir(bank->regbase), dir);
-
-	superio_exit(sio->addr);
+	f7188x_write8(sio, gpio_dir(bank->regbase), dir);
+	mutex_unlock(&sio->lock);
 
 	return 0;
 }
 
 static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	int err;
 	struct f7188x_gpio_bank *bank =
 		container_of(chip, struct f7188x_gpio_bank, chip);
 	struct f7188x_sio *sio = bank->data->sio;
 	u8 dir, data;
 
-	err = superio_enter(sio->addr);
-	if (err)
-		return err;
-	superio_select(sio->addr, SIO_LD_GPIO);
-
-	dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
+	mutex_lock(&sio->lock);
+	dir = f7188x_read8(sio, gpio_dir(bank->regbase));
 	dir = !!(dir & (1 << offset));
 	if (dir)
-		data = superio_inb(sio->addr, gpio_data_out(bank->regbase));
+		data = f7188x_read8(sio, gpio_data_out(bank->regbase));
 	else
-		data = superio_inb(sio->addr, gpio_data_in(bank->regbase));
-
-	superio_exit(sio->addr);
+		data = f7188x_read8(sio, gpio_data_in(bank->regbase));
+	mutex_unlock(&sio->lock);
 
 	return !!(data & 1 << offset);
 }
@@ -240,54 +253,42 @@ static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset)
 static int f7188x_gpio_direction_out(struct gpio_chip *chip,
 				     unsigned offset, int value)
 {
-	int err;
 	struct f7188x_gpio_bank *bank =
 		container_of(chip, struct f7188x_gpio_bank, chip);
 	struct f7188x_sio *sio = bank->data->sio;
 	u8 dir, data_out;
 
-	err = superio_enter(sio->addr);
-	if (err)
-		return err;
-	superio_select(sio->addr, SIO_LD_GPIO);
-
-	data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase));
+	mutex_lock(&sio->lock);
+	data_out = f7188x_read8(sio, gpio_data_out(bank->regbase));
 	if (value)
 		data_out |= (1 << offset);
 	else
 		data_out &= ~(1 << offset);
-	superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out);
+	f7188x_write8(sio, gpio_data_out(bank->regbase), data_out);
 
-	dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
+	dir = f7188x_read8(sio, gpio_dir(bank->regbase));
 	dir |= (1 << offset);
-	superio_outb(sio->addr, gpio_dir(bank->regbase), dir);
-
-	superio_exit(sio->addr);
+	f7188x_write8(sio, gpio_dir(bank->regbase), dir);
+	mutex_unlock(&sio->lock);
 
 	return 0;
 }
 
 static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	int err;
 	struct f7188x_gpio_bank *bank =
 		container_of(chip, struct f7188x_gpio_bank, chip);
 	struct f7188x_sio *sio = bank->data->sio;
 	u8 data_out;
 
-	err = superio_enter(sio->addr);
-	if (err)
-		return;
-	superio_select(sio->addr, SIO_LD_GPIO);
-
-	data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase));
+	mutex_lock(&sio->lock);
+	data_out = f7188x_read8(sio, gpio_data_out(bank->regbase));
 	if (value)
 		data_out |= (1 << offset);
 	else
 		data_out &= ~(1 << offset);
-	superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out);
-
-	superio_exit(sio->addr);
+	f7188x_write8(sio, gpio_data_out(bank->regbase), data_out);
+	mutex_unlock(&sio->lock);
 }
 
 /*
@@ -326,6 +327,7 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 	data->sio = sio;
+	mutex_init(&sio->lock);
 
 	platform_set_drvdata(pdev, data);
 
@@ -372,6 +374,7 @@ static int f7188x_gpio_remove(struct platform_device *pdev)
 static int __init f7188x_find(int addr, struct f7188x_sio *sio)
 {
 	int err;
+	u16 logical_device_address;
 	u16 devid;
 
 	err = superio_enter(addr);
@@ -403,12 +406,25 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio)
 		pr_info(DRVNAME ": Unsupported Fintek device 0x%04x\n", devid);
 		goto err;
 	}
-	sio->addr = addr;
+	superio_select(addr, SIO_LD_GPIO);
+
+	if (!(superio_inb(addr, SIO_ENABLE) & 0x01)) {
+		pr_warn("Device not activated\n");
+		goto err;
+	}
+
+	logical_device_address = superio_inw(addr, SIO_ADDR);
+	if (logical_device_address == 0) {
+		pr_warn("Base address not set\n");
+		goto err;
+	}
+	logical_device_address &= ~(REGION_LENGTH - 1);	/* Ignore 3 LSB */
+	sio->addr = logical_device_address;
 	err = 0;
 
 	pr_info(DRVNAME ": Found %s at %#x, revision %d\n",
 		f7188x_names[sio->type],
-		(unsigned int) addr,
+		(unsigned int) logical_device_address,
 		(int) superio_inb(addr, SIO_DEVREV));
 
 err:
@@ -421,12 +437,28 @@ static struct platform_device *f7188x_gpio_pdev;
 static int __init
 f7188x_gpio_device_add(const struct f7188x_sio *sio)
 {
+	struct resource res = {
+		.start	= sio->addr,
+		.end	= sio->addr + REGION_LENGTH - 1,
+		.flags	= IORESOURCE_IO,
+	};
 	int err;
 
 	f7188x_gpio_pdev = platform_device_alloc(DRVNAME, -1);
 	if (!f7188x_gpio_pdev)
 		return -ENOMEM;
 
+	res.name = f7188x_gpio_pdev->name;
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto err;
+
+	err = platform_device_add_resources(f7188x_gpio_pdev, &res, 1);
+	if (err) {
+		pr_err("Device resource addition failed\n");
+		goto err;
+	}
+
 	err = platform_device_add_data(f7188x_gpio_pdev,
 				       sio, sizeof(*sio));
 	if (err) {
@@ -467,6 +499,8 @@ static int __init f7188x_gpio_init(void)
 	int err;
 	struct f7188x_sio sio;
 
+	memset(&sio, 0, sizeof(sio));
+
 	if (f7188x_find(0x2e, &sio) &&
 	    f7188x_find(0x4e, &sio))
 		return -ENODEV;
-- 
2.5.0


  reply	other threads:[~2015-08-20 18:03 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-08-20 18:03 gpio-f7188x: Fix concurrent GPIO accesses (and minor improvements) Vincent Pelletier
2015-08-20 18:03 ` Vincent Pelletier [this message]
2015-08-20 18:03   ` [2/4] gpio: gpio-f7188x: GPIO bank 0 bit 0 is not available on f71869a Vincent Pelletier
2015-08-20 18:03   ` [3/4] gpio: gpio-f7188x: "get" should retrieve sensed level when available Vincent Pelletier
2015-08-20 18:03   ` [4/4] gpio: gpio-f7188x: Implement get_direction Vincent Pelletier
2015-08-21 17:52   ` [1/4] gpio: gpio-f7188x: Use mutex for access serialisation Simon Guinot
2015-08-21 20:48     ` Vincent Pelletier
2015-08-22 17:04       ` Vincent Pelletier
2015-09-03 18:05       ` Vincent Pelletier
2015-09-04  7:39         ` Simon Guinot
2015-09-09 22:01         ` Simon Guinot
2015-09-09 22:15           ` [PATCH] kernel/resource.c: fix muxed resource handling in __request_region() Simon Guinot
2016-02-19 21:10             ` Vincent Pelletier
2016-02-19 23:25               ` Jesse Barnes
2016-02-20 17:11                 ` Linus Torvalds
2016-02-20 22:15                   ` Jesse Barnes
2016-02-20 22:15                     ` Jesse Barnes
2016-02-22 13:49                     ` Alan Cox
2016-02-22 20:46                       ` Jesse Barnes
2016-02-23 16:19                         ` Simon Guinot
2016-02-23 17:19                           ` Jesse Barnes
2016-02-23 21:38                             ` One Thousand Gnomes
2016-02-24 14:25                             ` [PATCH] kernel/resource.c: ensure parent is not freed " Simon Guinot
2016-02-23  8:00                       ` [PATCH] kernel/resource.c: fix muxed resource handling " Vincent Pelletier
2015-09-12 13:26           ` [1/4] gpio: gpio-f7188x: Use mutex for access serialisation Vincent Pelletier
2015-09-04 13:48       ` Vincent Donnefort
2015-09-05  7:43         ` Vincent Pelletier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7d1a2156ddabe0b72964e88734adba307a472067.1440093298.git.plr.vincent@gmail.com \
    --to=plr.vincent@gmail.com \
    --cc=linux-gpio@vger.kernel.org \
    --cc=simon.guinot@sequanux.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.