[PATCH 1/1] regmap: add fast_io_disable_irq property for regmap_config

From: ååæ
Date: Mon Jul 06 2015 - 23:33:19 EST



(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 <zhouxuewen@xxxxxxxxxx>
---
Â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 <zhouxuewen@xxxxxxxxxx>
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 <zhouxuewen@xxxxxxxxxx>
---
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