linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Thomas Gleixner <tglx@linutronix.de>
To: LKML <linux-kernel@vger.kernel.org>
Cc: Feng Tang <feng.tang@intel.com>, Matthew Garrett <mjg@redhat.com>,
	Alan Cox <alan@linux.intel.com>, Alek Du <alek.du@intel.com>
Subject: [patch 3/3] platform-drivers: x86: pmic: Use irq_chip buslock mechanism
Date: Sat, 05 Feb 2011 10:46:32 -0000	[thread overview]
Message-ID: <20110205104221.336710296@linutronix.de> (raw)
In-Reply-To: 20110205104025.559237313@linutronix.de

[-- Attachment #1: platform-drivers-x86-pmic-use-buslock.patch --]
[-- Type: text/plain, Size: 4348 bytes --]

The set_type function of the pmic irq chip is a horrible hack. It
schedules work because it cannot access the scu chip from the set_type
function. That breaks the assumption, that the type is set after
set_type has returned.

irq_chips provide buslock functions to avoid the above. Convert the
driver to use the proper model.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Feng Tang <feng.tang@intel.com>
Cc: Matthew Garrett <mjg@redhat.com>
Cc: Alan Cox <alan@linux.intel.com>
Cc: Alek Du <alek.du@intel.com>
---
 drivers/platform/x86/intel_pmic_gpio.c |   80 +++++++++++++--------------------
 1 file changed, 32 insertions(+), 48 deletions(-)

Index: linux-2.6/drivers/platform/x86/intel_pmic_gpio.c
===================================================================
--- linux-2.6.orig/drivers/platform/x86/intel_pmic_gpio.c
+++ linux-2.6/drivers/platform/x86/intel_pmic_gpio.c
@@ -60,23 +60,18 @@ enum pmic_gpio_register {
 #define GPOSW_DOU 0x08
 #define GPOSW_RDRV 0x30
 
+#define GPIO_UPDATE_TYPE	0x80000000
 
 #define NUM_GPIO 24
 
-struct pmic_gpio_irq {
-	spinlock_t lock;
-	u32 trigger[NUM_GPIO];
-	u32 dirty;
-	struct work_struct work;
-};
-
-
 struct pmic_gpio {
+	struct mutex		buslock;
 	struct gpio_chip	chip;
-	struct pmic_gpio_irq	irqtypes;
 	void			*gpiointr;
 	int			irq;
 	unsigned		irq_base;
+	unsigned int		update_type;
+	u32			trigger_type;
 };
 
 static void pmic_program_irqtype(int gpio, int type)
@@ -92,37 +87,6 @@ static void pmic_program_irqtype(int gpi
 		intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10);
 };
 
-static void pmic_irqtype_work(struct work_struct *work)
-{
-	struct pmic_gpio_irq *t =
-		container_of(work, struct pmic_gpio_irq, work);
-	unsigned long flags;
-	int i;
-	u16 type;
-
-	spin_lock_irqsave(&t->lock, flags);
-	/* As we drop the lock, we may need multiple scans if we race the
-	   pmic_irq_type function */
-	while (t->dirty) {
-		/*
-		 *	For each pin that has the dirty bit set send an IPC
-		 *	message to configure the hardware via the PMIC
-		 */
-		for (i = 0; i < NUM_GPIO; i++) {
-			if (!(t->dirty & (1 << i)))
-				continue;
-			t->dirty &= ~(1 << i);
-			/* We can't trust the array entry or dirty
-			   once the lock is dropped */
-			type = t->trigger[i];
-			spin_unlock_irqrestore(&t->lock, flags);
-			pmic_program_irqtype(i, type);
-			spin_lock_irqsave(&t->lock, flags);
-		}
-	}
-	spin_unlock_irqrestore(&t->lock, flags);
-}
-
 static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
 	if (offset > 8) {
@@ -190,20 +154,21 @@ static void pmic_gpio_set(struct gpio_ch
 			1 << (offset - 16));
 }
 
+/*
+ * This is called from genirq with pg->buslock locked and
+ * irq_desc->lock held. We can not access the scu bus here, so we
+ * store the change and update in the bus_sync_unlock() function below
+ */
 static int pmic_irq_type(struct irq_data *data, unsigned type)
 {
 	struct pmic_gpio *pg = irq_data_get_irq_chip_data(data);
 	u32 gpio = data->irq - pg->irq_base;
-	unsigned long flags;
 
 	if (gpio >= pg->chip.ngpio)
 		return -EINVAL;
 
-	spin_lock_irqsave(&pg->irqtypes.lock, flags);
-	pg->irqtypes.trigger[gpio] = type;
-	pg->irqtypes.dirty |=  (1 << gpio);
-	spin_unlock_irqrestore(&pg->irqtypes.lock, flags);
-	schedule_work(&pg->irqtypes.work);
+	pg->trigger_type = type;
+	pg->update_type = gpio | GPIO_UPDATE_TYPE;
 	return 0;
 }
 
@@ -214,6 +179,26 @@ static int pmic_gpio_to_irq(struct gpio_
 	return pg->irq_base + offset;
 }
 
+static void pmic_bus_lock(struct irq_data *data)
+{
+	struct pmic_gpio *pg = irq_data_get_irq_chip_data(data);
+
+	mutex_lock(&pg->buslock);
+}
+
+static void pmic_bus_sync_unlock(struct irq_data *data)
+{
+	struct pmic_gpio *pg = irq_data_get_irq_chip_data(data);
+
+	if (pg->update_type) {
+		unsigned int gpio = pg->update_type & ~GPIO_UPDATE_TYPE;
+
+		pmic_program_irqtype(gpio, pg->trigger_type);
+		pg->update_type = 0;
+	}
+	mutex_unlock(&pg->buslock);
+}
+
 /* the gpiointr register is read-clear, so just do nothing. */
 static void pmic_irq_unmask(struct irq_data *data) { }
 
@@ -287,8 +272,7 @@ static int __devinit platform_pmic_gpio_
 	pg->chip.can_sleep = 1;
 	pg->chip.dev = dev;
 
-	INIT_WORK(&pg->irqtypes.work, pmic_irqtype_work);
-	spin_lock_init(&pg->irqtypes.lock);
+	mutex_init(&pg->buslock);
 
 	pg->chip.dev = dev;
 	retval = gpiochip_add(&pg->chip);



  parent reply	other threads:[~2011-02-05 10:46 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-02-05 10:46 [patch 0/3] platform-drivers: x86: Cleanup pmic gpio interrupt Thomas Gleixner
2011-02-05 10:46 ` [patch 1/3] platform-drivers: x86: pmic: Fix up bogus irq hackery Thomas Gleixner
2011-02-05 10:46 ` [patch 2/3] platform-drivers: x86: Convert pmic to new irq_chip functions Thomas Gleixner
2011-02-05 10:46 ` Thomas Gleixner [this message]
2011-02-07 20:17 ` [patch 0/3] platform-drivers: x86: Cleanup pmic gpio interrupt Matthew Garrett
2011-02-07 20:41   ` Thomas Gleixner
2011-02-10 23:55     ` Andrew Morton

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=20110205104221.336710296@linutronix.de \
    --to=tglx@linutronix.de \
    --cc=alan@linux.intel.com \
    --cc=alek.du@intel.com \
    --cc=feng.tang@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mjg@redhat.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).