linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] regmap: Add hardware spinlock support
@ 2017-10-31  6:35 Baolin Wang
  2017-10-31  6:35 ` [PATCH 2/2] mfd: syscon: " Baolin Wang
  2017-10-31 10:38 ` [PATCH 1/2] regmap: " Mark Brown
  0 siblings, 2 replies; 7+ messages in thread
From: Baolin Wang @ 2017-10-31  6:35 UTC (permalink / raw)
  To: broonie, gregkh, lee.jones, arnd; +Cc: linux-kernel, baolin.wang

On some platforms, when reading or writing some special registers through
regmap, we should acquire one hardware spinlock to synchronize between
the multiple subsystems. Thus this patch adds the hardware spinlock
support for regmap.

Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
 drivers/base/regmap/internal.h |    3 +
 drivers/base/regmap/regmap.c   |  118 ++++++++++++++++++++++++++++++++++------
 include/linux/regmap.h         |    9 +++
 3 files changed, 114 insertions(+), 16 deletions(-)

diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 2a4435d..bb8b663 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -157,6 +157,9 @@ struct regmap {
 
 	struct rb_root range_tree;
 	void *selector_work_buf;	/* Scratch buffer used for selector */
+
+	struct hwspinlock *hwlock;
+	unsigned int hwlock_timeout;
 };
 
 struct regcache_ops {
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index b9a779a..615e8d0 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -413,6 +413,71 @@ static unsigned int regmap_parse_64_native(const void *buf)
 }
 #endif
 
+static void regmap_lock_hwlock(void *__map)
+{
+	struct regmap *map = __map;
+	int ret;
+
+	if (map->hwlock_timeout)
+		ret = hwspin_lock_timeout(map->hwlock, map->hwlock_timeout);
+	else
+		ret = hwspin_trylock(map->hwlock);
+
+	if (ret)
+		dev_err(map->dev, "Failed to get hwlock %d\n", ret);
+}
+
+static void regmap_lock_hwlock_irq(void *__map)
+{
+	struct regmap *map = __map;
+	int ret;
+
+	if (map->hwlock_timeout)
+		ret = hwspin_lock_timeout_irq(map->hwlock, map->hwlock_timeout);
+	else
+		ret = hwspin_trylock_irq(map->hwlock);
+
+	if (ret)
+		dev_err(map->dev, "Failed to get hwlock %d\n", ret);
+}
+
+static void regmap_lock_hwlock_irqsave(void *__map)
+{
+	struct regmap *map = __map;
+	int ret;
+
+	if (map->hwlock_timeout)
+		ret = hwspin_lock_timeout_irqsave(map->hwlock,
+						  map->hwlock_timeout,
+						  &map->spinlock_flags);
+	else
+		ret = hwspin_trylock_irqsave(map->hwlock, &map->spinlock_flags);
+
+	if (ret)
+		dev_err(map->dev, "Failed to get hwlock %d\n", ret);
+}
+
+static void regmap_unlock_hwlock(void *__map)
+{
+	struct regmap *map = __map;
+
+	hwspin_unlock(map->hwlock);
+}
+
+static void regmap_unlock_hwlock_irq(void *__map)
+{
+	struct regmap *map = __map;
+
+	hwspin_unlock_irq(map->hwlock);
+}
+
+static void regmap_unlock_hwlock_irqrestore(void *__map)
+{
+	struct regmap *map = __map;
+
+	hwspin_unlock_irqrestore(map->hwlock, &map->spinlock_flags);
+}
+
 static void regmap_lock_mutex(void *__map)
 {
 	struct regmap *map = __map;
@@ -627,6 +692,25 @@ struct regmap *__regmap_init(struct device *dev,
 		map->lock = config->lock;
 		map->unlock = config->unlock;
 		map->lock_arg = config->lock_arg;
+	} else if (config->hwlock_id) {
+		map->hwlock = hwspin_lock_request_specific(config->hwlock_id);
+		if (!map->hwlock) {
+			ret = -ENXIO;
+			goto err_map;
+		}
+
+		map->hwlock_timeout = config->hwlock_timeout;
+		if (config->hwlock_mode == HWLOCK_IRQSTATE) {
+			map->lock = regmap_lock_hwlock_irqsave;
+			map->unlock = regmap_unlock_hwlock_irqrestore;
+		} else if (config->hwlock_mode == HWLOCK_IRQ) {
+			map->lock = regmap_lock_hwlock_irq;
+			map->unlock = regmap_unlock_hwlock_irq;
+		} else {
+			map->lock = regmap_lock_hwlock;
+			map->unlock = regmap_unlock_hwlock;
+		}
+		map->lock_arg = map;
 	} else {
 		if ((bus && bus->fast_io) ||
 		    config->fast_io) {
@@ -729,7 +813,7 @@ struct regmap *__regmap_init(struct device *dev,
 			map->format.format_write = regmap_format_2_6_write;
 			break;
 		default:
-			goto err_map;
+			goto err_hwlock;
 		}
 		break;
 
@@ -739,7 +823,7 @@ struct regmap *__regmap_init(struct device *dev,
 			map->format.format_write = regmap_format_4_12_write;
 			break;
 		default:
-			goto err_map;
+			goto err_hwlock;
 		}
 		break;
 
@@ -749,7 +833,7 @@ struct regmap *__regmap_init(struct device *dev,
 			map->format.format_write = regmap_format_7_9_write;
 			break;
 		default:
-			goto err_map;
+			goto err_hwlock;
 		}
 		break;
 
@@ -759,7 +843,7 @@ struct regmap *__regmap_init(struct device *dev,
 			map->format.format_write = regmap_format_10_14_write;
 			break;
 		default:
-			goto err_map;
+			goto err_hwlock;
 		}
 		break;
 
@@ -779,13 +863,13 @@ struct regmap *__regmap_init(struct device *dev,
 			map->format.format_reg = regmap_format_16_native;
 			break;
 		default:
-			goto err_map;
+			goto err_hwlock;
 		}
 		break;
 
 	case 24:
 		if (reg_endian != REGMAP_ENDIAN_BIG)
-			goto err_map;
+			goto err_hwlock;
 		map->format.format_reg = regmap_format_24;
 		break;
 
@@ -801,7 +885,7 @@ struct regmap *__regmap_init(struct device *dev,
 			map->format.format_reg = regmap_format_32_native;
 			break;
 		default:
-			goto err_map;
+			goto err_hwlock;
 		}
 		break;
 
@@ -818,13 +902,13 @@ struct regmap *__regmap_init(struct device *dev,
 			map->format.format_reg = regmap_format_64_native;
 			break;
 		default:
-			goto err_map;
+			goto err_hwlock;
 		}
 		break;
 #endif
 
 	default:
-		goto err_map;
+		goto err_hwlock;
 	}
 
 	if (val_endian == REGMAP_ENDIAN_NATIVE)
@@ -853,12 +937,12 @@ struct regmap *__regmap_init(struct device *dev,
 			map->format.parse_val = regmap_parse_16_native;
 			break;
 		default:
-			goto err_map;
+			goto err_hwlock;
 		}
 		break;
 	case 24:
 		if (val_endian != REGMAP_ENDIAN_BIG)
-			goto err_map;
+			goto err_hwlock;
 		map->format.format_val = regmap_format_24;
 		map->format.parse_val = regmap_parse_24;
 		break;
@@ -879,7 +963,7 @@ struct regmap *__regmap_init(struct device *dev,
 			map->format.parse_val = regmap_parse_32_native;
 			break;
 		default:
-			goto err_map;
+			goto err_hwlock;
 		}
 		break;
 #ifdef CONFIG_64BIT
@@ -900,7 +984,7 @@ struct regmap *__regmap_init(struct device *dev,
 			map->format.parse_val = regmap_parse_64_native;
 			break;
 		default:
-			goto err_map;
+			goto err_hwlock;
 		}
 		break;
 #endif
@@ -909,18 +993,18 @@ struct regmap *__regmap_init(struct device *dev,
 	if (map->format.format_write) {
 		if ((reg_endian != REGMAP_ENDIAN_BIG) ||
 		    (val_endian != REGMAP_ENDIAN_BIG))
-			goto err_map;
+			goto err_hwlock;
 		map->use_single_write = true;
 	}
 
 	if (!map->format.format_write &&
 	    !(map->format.format_reg && map->format.format_val))
-		goto err_map;
+		goto err_hwlock;
 
 	map->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL);
 	if (map->work_buf == NULL) {
 		ret = -ENOMEM;
-		goto err_map;
+		goto err_hwlock;
 	}
 
 	if (map->format.format_write) {
@@ -1041,6 +1125,8 @@ struct regmap *__regmap_init(struct device *dev,
 err_range:
 	regmap_range_exit(map);
 	kfree(map->work_buf);
+err_hwlock:
+	hwspin_lock_free(map->hwlock);
 err_map:
 	kfree(map);
 err:
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 978abfb..fe958e2 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -19,6 +19,7 @@
 #include <linux/err.h>
 #include <linux/bug.h>
 #include <linux/lockdep.h>
+#include <linux/hwspinlock.h>
 
 struct module;
 struct device;
@@ -273,6 +274,10 @@ struct regmap_access_table {
  *
  * @ranges: Array of configuration entries for virtual address ranges.
  * @num_ranges: Number of range configuration entries.
+ * @hwlock_id: Specify the hardware spinlock id.
+ * @hwlock_mode: The hardware spinlock mode, should be HWLOCK_IRQSTATE,
+ *		 HWLOCK_IRQ or 0.
+ * @hwlock_timeout: Timeout value in msecs.
  */
 struct regmap_config {
 	const char *name;
@@ -317,6 +322,10 @@ struct regmap_config {
 
 	const struct regmap_range_cfg *ranges;
 	unsigned int num_ranges;
+
+	unsigned int hwlock_id;
+	unsigned int hwlock_mode;
+	unsigned int hwlock_timeout;
 };
 
 /**
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] mfd: syscon: Add hardware spinlock support
  2017-10-31  6:35 [PATCH 1/2] regmap: Add hardware spinlock support Baolin Wang
@ 2017-10-31  6:35 ` Baolin Wang
  2017-10-31 10:38 ` [PATCH 1/2] regmap: " Mark Brown
  1 sibling, 0 replies; 7+ messages in thread
From: Baolin Wang @ 2017-10-31  6:35 UTC (permalink / raw)
  To: broonie, gregkh, lee.jones, arnd; +Cc: linux-kernel, baolin.wang

Some system control registers need hardware spinlock to synchronize
between the multiple subsystems, so we should add hardware spinlock
support for syscon.

Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
 drivers/mfd/syscon.c |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index b93fe4c..adc1c9c 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -25,6 +25,8 @@
 #include <linux/mfd/syscon.h>
 #include <linux/slab.h>
 
+#define SYSCON_HWSPINLOCK_TIMEOUT	(~0U)
+
 static struct platform_driver syscon_driver;
 
 static DEFINE_SPINLOCK(syscon_list_slock);
@@ -87,6 +89,13 @@ static struct syscon *of_syscon_register(struct device_node *np)
 	if (ret)
 		reg_io_width = 4;
 
+	ret = of_hwspin_lock_get_id(np, 0);
+	if (ret > 0) {
+		syscon_config.hwlock_id = ret;
+		syscon_config.hwlock_mode = HWLOCK_IRQSTATE;
+		syscon_config.hwlock_timeout = SYSCON_HWSPINLOCK_TIMEOUT;
+	}
+
 	syscon_config.reg_stride = reg_io_width;
 	syscon_config.val_bits = reg_io_width * 8;
 	syscon_config.max_register = resource_size(&res) - reg_io_width;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] regmap: Add hardware spinlock support
  2017-10-31  6:35 [PATCH 1/2] regmap: Add hardware spinlock support Baolin Wang
  2017-10-31  6:35 ` [PATCH 2/2] mfd: syscon: " Baolin Wang
@ 2017-10-31 10:38 ` Mark Brown
  2017-10-31 11:31   ` Baolin Wang
  1 sibling, 1 reply; 7+ messages in thread
From: Mark Brown @ 2017-10-31 10:38 UTC (permalink / raw)
  To: Baolin Wang; +Cc: gregkh, lee.jones, arnd, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1523 bytes --]

On Tue, Oct 31, 2017 at 02:35:55PM +0800, Baolin Wang wrote:

This looks mostly good, a few small things:

> +static void regmap_lock_hwlock(void *__map)
> +{
> +	struct regmap *map = __map;
> +	int ret;
> +
> +	if (map->hwlock_timeout)
> +		ret = hwspin_lock_timeout(map->hwlock, map->hwlock_timeout);
> +	else
> +		ret = hwspin_trylock(map->hwlock);
> +
> +	if (ret)
> +		dev_err(map->dev, "Failed to get hwlock %d\n", ret);
> +}

Given that we have no error handling path on the locks should we be
supporting timeout mode at all?  Otherwise we should probably add a
set of error handling paths whenever we take the lock...

> +		if (config->hwlock_mode == HWLOCK_IRQSTATE) {
> +			map->lock = regmap_lock_hwlock_irqsave;
> +			map->unlock = regmap_unlock_hwlock_irqrestore;
> +		} else if (config->hwlock_mode == HWLOCK_IRQ) {
> +			map->lock = regmap_lock_hwlock_irq;
> +			map->unlock = regmap_unlock_hwlock_irq;
> +		} else {
> +			map->lock = regmap_lock_hwlock;
> +			map->unlock = regmap_unlock_hwlock;
> +		}

This should be a switch statement.

> --- a/include/linux/regmap.h
> +++ b/include/linux/regmap.h
> @@ -19,6 +19,7 @@
>  #include <linux/err.h>
>  #include <linux/bug.h>
>  #include <linux/lockdep.h>
> +#include <linux/hwspinlock.h>

We don't actually use hwspinlock.h in the header (the config options are
all just unsigned ints) so this could be moved to regmap.c with a
forward declaration of the struct in internal.h.  That way we don't
force a rebuild of every regmap user when hwspinlock changes.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] regmap: Add hardware spinlock support
  2017-10-31 10:38 ` [PATCH 1/2] regmap: " Mark Brown
@ 2017-10-31 11:31   ` Baolin Wang
  2017-10-31 11:37     ` Mark Brown
  0 siblings, 1 reply; 7+ messages in thread
From: Baolin Wang @ 2017-10-31 11:31 UTC (permalink / raw)
  To: Mark Brown; +Cc: Greg KH, Lee Jones, Arnd Bergmann, LKML

Hi Mark,

On 31 October 2017 at 18:38, Mark Brown <broonie@kernel.org> wrote:
> On Tue, Oct 31, 2017 at 02:35:55PM +0800, Baolin Wang wrote:
>
> This looks mostly good, a few small things:
>
>> +static void regmap_lock_hwlock(void *__map)
>> +{
>> +     struct regmap *map = __map;
>> +     int ret;
>> +
>> +     if (map->hwlock_timeout)
>> +             ret = hwspin_lock_timeout(map->hwlock, map->hwlock_timeout);
>> +     else
>> +             ret = hwspin_trylock(map->hwlock);
>> +
>> +     if (ret)
>> +             dev_err(map->dev, "Failed to get hwlock %d\n", ret);
>> +}
>
> Given that we have no error handling path on the locks should we be
> supporting timeout mode at all?  Otherwise we should probably add a
> set of error handling paths whenever we take the lock...

It will be more helpful to use the timeout to try more times to get
the hwlock, and we usually do not use hwspin_trylock_xxx(), so we can
remove hwspin_trylock_xxx() support and set timeout as MAX value as
default to avoid adding 'hwlock_timeout' config,
is this OK for you?

>
>> +             if (config->hwlock_mode == HWLOCK_IRQSTATE) {
>> +                     map->lock = regmap_lock_hwlock_irqsave;
>> +                     map->unlock = regmap_unlock_hwlock_irqrestore;
>> +             } else if (config->hwlock_mode == HWLOCK_IRQ) {
>> +                     map->lock = regmap_lock_hwlock_irq;
>> +                     map->unlock = regmap_unlock_hwlock_irq;
>> +             } else {
>> +                     map->lock = regmap_lock_hwlock;
>> +                     map->unlock = regmap_unlock_hwlock;
>> +             }
>
> This should be a switch statement.

Yes, will fix in next version.

>
>> --- a/include/linux/regmap.h
>> +++ b/include/linux/regmap.h
>> @@ -19,6 +19,7 @@
>>  #include <linux/err.h>
>>  #include <linux/bug.h>
>>  #include <linux/lockdep.h>
>> +#include <linux/hwspinlock.h>
>
> We don't actually use hwspinlock.h in the header (the config options are
> all just unsigned ints) so this could be moved to regmap.c with a
> forward declaration of the struct in internal.h.  That way we don't
> force a rebuild of every regmap user when hwspinlock changes.

You are right. I will more the hwspinlock.h to regmap.c file. Very
appreciated for your comments.

-- 
Baolin.wang
Best Regards

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] regmap: Add hardware spinlock support
  2017-10-31 11:31   ` Baolin Wang
@ 2017-10-31 11:37     ` Mark Brown
  2017-10-31 11:47       ` Baolin Wang
  0 siblings, 1 reply; 7+ messages in thread
From: Mark Brown @ 2017-10-31 11:37 UTC (permalink / raw)
  To: Baolin Wang; +Cc: Greg KH, Lee Jones, Arnd Bergmann, LKML

[-- Attachment #1: Type: text/plain, Size: 898 bytes --]

On Tue, Oct 31, 2017 at 07:31:57PM +0800, Baolin Wang wrote:
> On 31 October 2017 at 18:38, Mark Brown <broonie@kernel.org> wrote:

> > Given that we have no error handling path on the locks should we be
> > supporting timeout mode at all?  Otherwise we should probably add a
> > set of error handling paths whenever we take the lock...

> It will be more helpful to use the timeout to try more times to get
> the hwlock, and we usually do not use hwspin_trylock_xxx(), so we can
> remove hwspin_trylock_xxx() support and set timeout as MAX value as
> default to avoid adding 'hwlock_timeout' config,
> is this OK for you?

I *think* so - but let's see the code.  It might make sense to do two
patches, one with the base hwspinlock support then another adding the
timeout functionality.  That way if there's any problem we can still
merge the non-timeout code and there's less to review next time.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] regmap: Add hardware spinlock support
  2017-10-31 11:37     ` Mark Brown
@ 2017-10-31 11:47       ` Baolin Wang
  2017-10-31 19:43         ` Mark Brown
  0 siblings, 1 reply; 7+ messages in thread
From: Baolin Wang @ 2017-10-31 11:47 UTC (permalink / raw)
  To: Mark Brown; +Cc: Greg KH, Lee Jones, Arnd Bergmann, LKML

On 31 October 2017 at 19:37, Mark Brown <broonie@kernel.org> wrote:
> On Tue, Oct 31, 2017 at 07:31:57PM +0800, Baolin Wang wrote:
>> On 31 October 2017 at 18:38, Mark Brown <broonie@kernel.org> wrote:
>
>> > Given that we have no error handling path on the locks should we be
>> > supporting timeout mode at all?  Otherwise we should probably add a
>> > set of error handling paths whenever we take the lock...
>
>> It will be more helpful to use the timeout to try more times to get
>> the hwlock, and we usually do not use hwspin_trylock_xxx(), so we can
>> remove hwspin_trylock_xxx() support and set timeout as MAX value as
>> default to avoid adding 'hwlock_timeout' config,
>> is this OK for you?
>
> I *think* so - but let's see the code.  It might make sense to do two
> patches, one with the base hwspinlock support then another adding the
> timeout functionality.  That way if there's any problem we can still
> merge the non-timeout code and there's less to review next time.

What I mean is we only introduce the timeout functions, since we do
not want to get the hwlocks failed to avoid error handling path:

static void regmap_lock_hwlock(void *__map)
{
    struct regmap *map = __map;

    hwspin_lock_timeout(map->hwlock, ~0U);
}

static void regmap_lock_hwlock_irq(void *__map)
{
    struct regmap *map = __map;

    hwspin_lock_timeout_irq(map->hwlock, ~0U);
}

static void regmap_lock_hwlock_irqsave(void *__map)
{
    struct regmap *map = __map;

    hwspin_lock_timeout_irqsave(map->hwlock, ~0U, &map->spinlock_flags);
}

-- 
Baolin.wang
Best Regards

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] regmap: Add hardware spinlock support
  2017-10-31 11:47       ` Baolin Wang
@ 2017-10-31 19:43         ` Mark Brown
  0 siblings, 0 replies; 7+ messages in thread
From: Mark Brown @ 2017-10-31 19:43 UTC (permalink / raw)
  To: Baolin Wang; +Cc: Greg KH, Lee Jones, Arnd Bergmann, LKML

[-- Attachment #1: Type: text/plain, Size: 204 bytes --]

On Tue, Oct 31, 2017 at 07:47:57PM +0800, Baolin Wang wrote:

> What I mean is we only introduce the timeout functions, since we do
> not want to get the hwlocks failed to avoid error handling path:

OK.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2017-10-31 19:43 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-31  6:35 [PATCH 1/2] regmap: Add hardware spinlock support Baolin Wang
2017-10-31  6:35 ` [PATCH 2/2] mfd: syscon: " Baolin Wang
2017-10-31 10:38 ` [PATCH 1/2] regmap: " Mark Brown
2017-10-31 11:31   ` Baolin Wang
2017-10-31 11:37     ` Mark Brown
2017-10-31 11:47       ` Baolin Wang
2017-10-31 19:43         ` Mark Brown

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).