(please ignore the last email which contain HTML format and was rejected, sorry 
for the inconvenience caused)

This patch aims to fix an issue when using the regmap function in different 
drivers.

I describe the issue here:

We want to use the the same regmap handler to access the same hardware module 
using syscon interface in different drivers.

Some driver will read the register in interrupt handler to get  the hardware 
information while other drivers will access some other registers by regmap at 
the same time, so there will be a synchronization issue because the 
spin_lock/spin_unlock is used in regmap_read/regmap_write. a dead lock maybe 
happen on the current CPU.

This patch adds a property named fast_io_disable_irq and when this property is 
set to true the spin_lock_irqsave/spin_lockirqrestore lock function will be 
used in regmap_read/regmap_write to disable the local IRQ when accessing the 
register to  avoid the lock issue.

Change-Id: I07424191f3ab65d3f89bfee81fe2b4422cf84e74
Signed-off-by: Xuewen Zhou <zhouxue...@xiaomi.com>
---
 drivers/base/regmap/internal.h |  1 +
 drivers/base/regmap/regmap.c   | 18 +++++++++++++++++-
 include/linux/regmap.h         |  1 +
 3 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 5a22bd3..6a66e6b 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -54,6 +54,7 @@ struct regmap {
  regmap_lock lock;
  regmap_unlock unlock;
  void *lock_arg; /* This is passed to lock/unlock functions */
+ unsigned long flags;
 
  struct device *dev; /* Device we do I/O on */
  void *work_buf;     /* Scratch buffer used to format I/O */
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 58cfb32..b9b188e 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -297,6 +297,18 @@ static void regmap_unlock_spinlock(void *__map)
  spin_unlock(&map->spinlock);
 }
 
+static void regmap_lock_spinlock_irqsave(void *__map)
+{
+ struct regmap *map = __map;
+ spin_lock_irqsave(&map->spinlock, map->flags);
+}
+
+static void regmap_unlock_spinlock_irqrestore(void *__map)
+{
+ struct regmap *map = __map;
+ spin_unlock_irqrestore(&map->spinlock, map->flags);
+}
+
 static void dev_get_regmap_release(struct device *dev, void *res)
 {
  /*
@@ -403,7 +415,11 @@ struct regmap *regmap_init(struct device *dev,
  map->unlock = config->unlock;
  map->lock_arg = config->lock_arg;
  } else {
- if ((bus && bus->fast_io) ||
+ if (config->fast_io_disable_irq) {
+ spin_lock_init(&map->spinlock);
+ map->lock = regmap_lock_spinlock_irqsave;
+ map->unlock = regmap_unlock_spinlock_irqrestore;
+ } else if ((bus && bus->fast_io) ||
     config->fast_io) {
  spin_lock_init(&map->spinlock);
  map->lock = regmap_lock_spinlock;
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index bf77dfd..ca3c637 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -193,6 +193,7 @@ struct regmap_config {
  int (*reg_write)(void *context, unsigned int reg, unsigned int val);
 
  bool fast_io;
+ bool fast_io_disable_irq;
 
  unsigned int max_register;
  const struct regmap_access_table *wr_table;
-- ​


Best regards,
Xuewen Zhou      
From fcac70930f1a8e48795585234335aef92797e296 Mon Sep 17 00:00:00 2001
From: Xuewen Zhou <zhouxue...@xiaomi.com>
Date: Thu, 2 Jul 2015 15:50:36 +0800
Subject: [PATCH] regmap: add fast_io_disable_irq property for regmap_config

different drivers can share the same regmap handler to access the same
hardware module registers by syscon or other mechanism.
there will be a synchronization issue if one of the driver access the
register in interrupt handler because the spin_lock maybe has been hold
by other regsiter access using the same regmap handler and it will cause
a dead lock.

when fast_io_disable_irq is set to true, the regmap_read/reagmap_write
will use spin_lock_irqsave/spin_lockirqrestore to do the syncrhonization
to avoid the lock issue.

Change-Id: I07424191f3ab65d3f89bfee81fe2b4422cf84e74
Signed-off-by: Xuewen Zhou <zhouxue...@xiaomi.com>
---
 drivers/base/regmap/internal.h |  1 +
 drivers/base/regmap/regmap.c   | 18 +++++++++++++++++-
 include/linux/regmap.h         |  1 +
 3 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 5a22bd3..6a66e6b 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -54,6 +54,7 @@ struct regmap {
 	regmap_lock lock;
 	regmap_unlock unlock;
 	void *lock_arg; /* This is passed to lock/unlock functions */
+	unsigned long flags;
 
 	struct device *dev; /* Device we do I/O on */
 	void *work_buf;     /* Scratch buffer used to format I/O */
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 58cfb32..b9b188e 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -297,6 +297,18 @@ static void regmap_unlock_spinlock(void *__map)
 	spin_unlock(&map->spinlock);
 }
 
+static void regmap_lock_spinlock_irqsave(void *__map)
+{
+	struct regmap *map = __map;
+	spin_lock_irqsave(&map->spinlock, map->flags);
+}
+
+static void regmap_unlock_spinlock_irqrestore(void *__map)
+{
+	struct regmap *map = __map;
+	spin_unlock_irqrestore(&map->spinlock, map->flags);
+}
+
 static void dev_get_regmap_release(struct device *dev, void *res)
 {
 	/*
@@ -403,7 +415,11 @@ struct regmap *regmap_init(struct device *dev,
 		map->unlock = config->unlock;
 		map->lock_arg = config->lock_arg;
 	} else {
-		if ((bus && bus->fast_io) ||
+		if (config->fast_io_disable_irq) {
+			spin_lock_init(&map->spinlock);
+			map->lock = regmap_lock_spinlock_irqsave;
+			map->unlock = regmap_unlock_spinlock_irqrestore;
+		} else if ((bus && bus->fast_io) ||
 		    config->fast_io) {
 			spin_lock_init(&map->spinlock);
 			map->lock = regmap_lock_spinlock;
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index bf77dfd..ca3c637 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -193,6 +193,7 @@ struct regmap_config {
 	int (*reg_write)(void *context, unsigned int reg, unsigned int val);
 
 	bool fast_io;
+	bool fast_io_disable_irq;
 
 	unsigned int max_register;
 	const struct regmap_access_table *wr_table;
-- 
1.9.1

Reply via email to