linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/3] Make STM32 interrupt controller use hwspinlock
@ 2018-12-17 14:22 Benjamin Gaignard
  2018-12-17 14:22 ` [PATCH v3 1/3] dt-bindings: interrupt-controller: stm32: Document hwlock properties Benjamin Gaignard
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Benjamin Gaignard @ 2018-12-17 14:22 UTC (permalink / raw)
  To: tglx, jason, marc.zyngier, robh+dt, mark.rutland, alexandre.torgue
  Cc: linux-kernel, devicetree, linux-arm-kernel, linux-stm32,
	Benjamin Gaignard

This series allow to protect STM32 interrupt controller configuration registers
with a hwspinlock to avoid conflicting accesses between processors. 

version 3:
- with bindings patch

version 2:
- rework hwspinlock locking sequence in stm32 irqchip to take care of the
  cases where hwspinlock node is disabled or not yet probed

Benjamin Gaignard (3):
  dt-bindings: interrupt-controller: stm32: Document hwlock properties
  irqchip: stm32: protect configuration registers with hwspinlock
  ARM: dts: stm32: Add hwlock for irqchip on stm32mp157

 .../interrupt-controller/st,stm32-exti.txt         |   4 +
 arch/arm/boot/dts/stm32mp157c.dtsi                 |   1 +
 drivers/irqchip/irq-stm32-exti.c                   | 116 ++++++++++++++++++---
 3 files changed, 105 insertions(+), 16 deletions(-)

-- 
2.15.0


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

* [PATCH v3 1/3] dt-bindings: interrupt-controller: stm32: Document hwlock properties
  2018-12-17 14:22 [PATCH v3 0/3] Make STM32 interrupt controller use hwspinlock Benjamin Gaignard
@ 2018-12-17 14:22 ` Benjamin Gaignard
  2018-12-18 15:06   ` Rob Herring
  2018-12-17 14:22 ` [PATCH v3 2/3] irqchip: stm32: protect configuration registers with hwspinlock Benjamin Gaignard
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 7+ messages in thread
From: Benjamin Gaignard @ 2018-12-17 14:22 UTC (permalink / raw)
  To: tglx, jason, marc.zyngier, robh+dt, mark.rutland, alexandre.torgue
  Cc: linux-kernel, devicetree, linux-arm-kernel, linux-stm32,
	Benjamin Gaignard

Add hwlocks as optional property

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 .../devicetree/bindings/interrupt-controller/st,stm32-exti.txt        | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt
index 6a36bf66d932..cd01b2292ec6 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt
@@ -14,6 +14,10 @@ Required properties:
   (only needed for exti controller with multiple exti under
   same parent interrupt: st,stm32-exti and st,stm32h7-exti)
 
+Optional properties:
+
+- hwlocks: reference to a phandle of a hardware spinlock provider node.
+
 Example:
 
 exti: interrupt-controller@40013c00 {
-- 
2.15.0


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

* [PATCH v3 2/3] irqchip: stm32: protect configuration registers with hwspinlock
  2018-12-17 14:22 [PATCH v3 0/3] Make STM32 interrupt controller use hwspinlock Benjamin Gaignard
  2018-12-17 14:22 ` [PATCH v3 1/3] dt-bindings: interrupt-controller: stm32: Document hwlock properties Benjamin Gaignard
@ 2018-12-17 14:22 ` Benjamin Gaignard
  2018-12-17 14:22 ` [PATCH v3 3/3] ARM: dts: stm32: Add hwlock for irqchip on stm32mp157 Benjamin Gaignard
  2018-12-18 15:39 ` [PATCH v3 0/3] Make STM32 interrupt controller use hwspinlock Marc Zyngier
  3 siblings, 0 replies; 7+ messages in thread
From: Benjamin Gaignard @ 2018-12-17 14:22 UTC (permalink / raw)
  To: tglx, jason, marc.zyngier, robh+dt, mark.rutland, alexandre.torgue
  Cc: linux-kernel, devicetree, linux-arm-kernel, linux-stm32,
	Benjamin Gaignard, Fabien Dessenne

If a hwspinlock is defined in device tree use it to protect
configuration registers.

Do not request for hwspinlock during the exti driver init since the
hwspinlock driver is not probed yet at that stage and the exti driver
does not support deferred probe.
Instead of this, postpone the hwspinlock request at the first time the
hwspinlock is actually needed.

Use the hwspin_trylock_raw() API which is the most appropriated here
Indeed:
- hwspin_lock_() calls are under spin_lock protection (chip_data->rlock
  or gc->lock).
- the _timeout() API relies on jiffies count which won't work if IRQs
  are disabled which is the case here (a large part of the IRQ setup is
  done atomically (see irq/manage.c))
As a consequence implement the retry/timeout lock from here. And since
all of this is done atomically, reduce the timeout delay to 1 ms.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
Signed-off-by: Fabien Dessenne <fabien.dessenne@st.com>
---
 drivers/irqchip/irq-stm32-exti.c | 116 +++++++++++++++++++++++++++++++++------
 1 file changed, 100 insertions(+), 16 deletions(-)

diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
index 0a2088e12d96..95933745433f 100644
--- a/drivers/irqchip/irq-stm32-exti.c
+++ b/drivers/irqchip/irq-stm32-exti.c
@@ -6,6 +6,8 @@
  */
 
 #include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/hwspinlock.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irq.h>
@@ -20,6 +22,9 @@
 
 #define IRQS_PER_BANK 32
 
+#define HWSPNLCK_TIMEOUT	1000 /* usec */
+#define HWSPNLCK_RETRY_DELAY	100  /* usec */
+
 struct stm32_exti_bank {
 	u32 imr_ofst;
 	u32 emr_ofst;
@@ -32,6 +37,12 @@ struct stm32_exti_bank {
 
 #define UNDEF_REG ~0
 
+enum stm32_exti_hwspinlock {
+	HWSPINLOCK_UNKNOWN,
+	HWSPINLOCK_NONE,
+	HWSPINLOCK_READY,
+};
+
 struct stm32_desc_irq {
 	u32 exti;
 	u32 irq_parent;
@@ -58,6 +69,9 @@ struct stm32_exti_host_data {
 	void __iomem *base;
 	struct stm32_exti_chip_data *chips_data;
 	const struct stm32_exti_drv_data *drv_data;
+	struct device_node *node;
+	enum stm32_exti_hwspinlock hwlock_state;
+	struct hwspinlock *hwlock;
 };
 
 static struct stm32_exti_host_data *stm32_host_data;
@@ -269,6 +283,64 @@ static int stm32_exti_set_type(struct irq_data *d,
 	return 0;
 }
 
+static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data)
+{
+	struct stm32_exti_host_data *host_data = chip_data->host_data;
+	struct hwspinlock *hwlock;
+	int id, ret = 0, timeout = 0;
+
+	/* first time, check for hwspinlock availability */
+	if (unlikely(host_data->hwlock_state == HWSPINLOCK_UNKNOWN)) {
+		id = of_hwspin_lock_get_id(host_data->node, 0);
+		if (id >= 0) {
+			hwlock = hwspin_lock_request_specific(id);
+			if (hwlock) {
+				/* found valid hwspinlock */
+				host_data->hwlock_state = HWSPINLOCK_READY;
+				host_data->hwlock = hwlock;
+				pr_debug("%s hwspinlock = %d\n", __func__, id);
+			} else {
+				host_data->hwlock_state = HWSPINLOCK_NONE;
+			}
+		} else if (id != -EPROBE_DEFER) {
+			host_data->hwlock_state = HWSPINLOCK_NONE;
+		} else {
+			/* hwspinlock driver shall be ready at that stage */
+			ret = -EPROBE_DEFER;
+		}
+	}
+
+	if (likely(host_data->hwlock_state == HWSPINLOCK_READY)) {
+		/*
+		 * Use the x_raw API since we are under spin_lock protection.
+		 * Do not use the x_timeout API because we are under irq_disable
+		 * mode (see __setup_irq())
+		 */
+		do {
+			ret = hwspin_trylock_raw(host_data->hwlock);
+			if (!ret)
+				return 0;
+
+			udelay(HWSPNLCK_RETRY_DELAY);
+			timeout += HWSPNLCK_RETRY_DELAY;
+		} while (timeout < HWSPNLCK_TIMEOUT);
+
+		if (ret == -EBUSY)
+			ret = -ETIMEDOUT;
+	}
+
+	if (ret)
+		pr_err("%s can't get hwspinlock (%d)\n", __func__, ret);
+
+	return ret;
+}
+
+static void stm32_exti_hwspin_unlock(struct stm32_exti_chip_data *chip_data)
+{
+	if (likely(chip_data->host_data->hwlock_state == HWSPINLOCK_READY))
+		hwspin_unlock_raw(chip_data->host_data->hwlock);
+}
+
 static int stm32_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
@@ -279,21 +351,26 @@ static int stm32_irq_set_type(struct irq_data *d, unsigned int type)
 
 	irq_gc_lock(gc);
 
+	err = stm32_exti_hwspin_lock(chip_data);
+	if (err)
+		goto unlock;
+
 	rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst);
 	ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst);
 
 	err = stm32_exti_set_type(d, type, &rtsr, &ftsr);
-	if (err) {
-		irq_gc_unlock(gc);
-		return err;
-	}
+	if (err)
+		goto unspinlock;
 
 	irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst);
 	irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst);
 
+unspinlock:
+	stm32_exti_hwspin_unlock(chip_data);
+unlock:
 	irq_gc_unlock(gc);
 
-	return 0;
+	return err;
 }
 
 static void stm32_chip_suspend(struct stm32_exti_chip_data *chip_data,
@@ -460,20 +537,27 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type)
 	int err;
 
 	raw_spin_lock(&chip_data->rlock);
+
+	err = stm32_exti_hwspin_lock(chip_data);
+	if (err)
+		goto unlock;
+
 	rtsr = readl_relaxed(base + stm32_bank->rtsr_ofst);
 	ftsr = readl_relaxed(base + stm32_bank->ftsr_ofst);
 
 	err = stm32_exti_set_type(d, type, &rtsr, &ftsr);
-	if (err) {
-		raw_spin_unlock(&chip_data->rlock);
-		return err;
-	}
+	if (err)
+		goto unspinlock;
 
 	writel_relaxed(rtsr, base + stm32_bank->rtsr_ofst);
 	writel_relaxed(ftsr, base + stm32_bank->ftsr_ofst);
+
+unspinlock:
+	stm32_exti_hwspin_unlock(chip_data);
+unlock:
 	raw_spin_unlock(&chip_data->rlock);
 
-	return 0;
+	return err;
 }
 
 static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on)
@@ -599,6 +683,8 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd,
 		return NULL;
 
 	host_data->drv_data = dd;
+	host_data->node = node;
+	host_data->hwlock_state = HWSPINLOCK_UNKNOWN;
 	host_data->chips_data = kcalloc(dd->bank_nr,
 					sizeof(struct stm32_exti_chip_data),
 					GFP_KERNEL);
@@ -625,8 +711,7 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd,
 
 static struct
 stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
-					   u32 bank_idx,
-					   struct device_node *node)
+					   u32 bank_idx)
 {
 	const struct stm32_exti_bank *stm32_bank;
 	struct stm32_exti_chip_data *chip_data;
@@ -656,8 +741,7 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
 	if (stm32_bank->fpr_ofst != UNDEF_REG)
 		writel_relaxed(~0UL, base + stm32_bank->fpr_ofst);
 
-	pr_info("%s: bank%d, External IRQs available:%#x\n",
-		node->full_name, bank_idx, irqs_mask);
+	pr_info("%pOF: bank%d\n", h_data->node, bank_idx);
 
 	return chip_data;
 }
@@ -697,7 +781,7 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
 		struct stm32_exti_chip_data *chip_data;
 
 		stm32_bank = drv_data->exti_banks[i];
-		chip_data = stm32_exti_chip_init(host_data, i, node);
+		chip_data = stm32_exti_chip_init(host_data, i);
 
 		gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK);
 
@@ -760,7 +844,7 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data,
 		return -ENOMEM;
 
 	for (i = 0; i < drv_data->bank_nr; i++)
-		stm32_exti_chip_init(host_data, i, node);
+		stm32_exti_chip_init(host_data, i);
 
 	domain = irq_domain_add_hierarchy(parent_domain, 0,
 					  drv_data->bank_nr * IRQS_PER_BANK,
-- 
2.15.0


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

* [PATCH v3 3/3] ARM: dts: stm32: Add hwlock for irqchip on stm32mp157
  2018-12-17 14:22 [PATCH v3 0/3] Make STM32 interrupt controller use hwspinlock Benjamin Gaignard
  2018-12-17 14:22 ` [PATCH v3 1/3] dt-bindings: interrupt-controller: stm32: Document hwlock properties Benjamin Gaignard
  2018-12-17 14:22 ` [PATCH v3 2/3] irqchip: stm32: protect configuration registers with hwspinlock Benjamin Gaignard
@ 2018-12-17 14:22 ` Benjamin Gaignard
  2018-12-18 15:39 ` [PATCH v3 0/3] Make STM32 interrupt controller use hwspinlock Marc Zyngier
  3 siblings, 0 replies; 7+ messages in thread
From: Benjamin Gaignard @ 2018-12-17 14:22 UTC (permalink / raw)
  To: tglx, jason, marc.zyngier, robh+dt, mark.rutland, alexandre.torgue
  Cc: linux-kernel, devicetree, linux-arm-kernel, linux-stm32,
	Benjamin Gaignard

Define a hwspinlock to be used by irq controller

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 arch/arm/boot/dts/stm32mp157c.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi
index 8bf1c17f8cef..452d252a4856 100644
--- a/arch/arm/boot/dts/stm32mp157c.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -815,6 +815,7 @@
 			interrupt-controller;
 			#interrupt-cells = <2>;
 			reg = <0x5000d000 0x400>;
+			hwlocks = <&hsem 1>;
 		};
 
 		syscfg: syscon@50020000 {
-- 
2.15.0


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

* Re: [PATCH v3 1/3] dt-bindings: interrupt-controller: stm32: Document hwlock properties
  2018-12-17 14:22 ` [PATCH v3 1/3] dt-bindings: interrupt-controller: stm32: Document hwlock properties Benjamin Gaignard
@ 2018-12-18 15:06   ` Rob Herring
  0 siblings, 0 replies; 7+ messages in thread
From: Rob Herring @ 2018-12-18 15:06 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: tglx, jason, marc.zyngier, robh+dt, mark.rutland,
	alexandre.torgue, linux-kernel, devicetree, linux-arm-kernel,
	linux-stm32, Benjamin Gaignard

On Mon, 17 Dec 2018 15:22:13 +0100, Benjamin Gaignard wrote:
> Add hwlocks as optional property
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> ---
>  .../devicetree/bindings/interrupt-controller/st,stm32-exti.txt        | 4 ++++
>  1 file changed, 4 insertions(+)
> 

Reviewed-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH v3 0/3] Make STM32 interrupt controller use hwspinlock
  2018-12-17 14:22 [PATCH v3 0/3] Make STM32 interrupt controller use hwspinlock Benjamin Gaignard
                   ` (2 preceding siblings ...)
  2018-12-17 14:22 ` [PATCH v3 3/3] ARM: dts: stm32: Add hwlock for irqchip on stm32mp157 Benjamin Gaignard
@ 2018-12-18 15:39 ` Marc Zyngier
  2018-12-19 15:00   ` Alexandre Torgue
  3 siblings, 1 reply; 7+ messages in thread
From: Marc Zyngier @ 2018-12-18 15:39 UTC (permalink / raw)
  To: Benjamin Gaignard, tglx, jason, robh+dt, mark.rutland, alexandre.torgue
  Cc: linux-kernel, devicetree, linux-arm-kernel, linux-stm32

On 17/12/2018 14:22, Benjamin Gaignard wrote:
> This series allow to protect STM32 interrupt controller configuration registers
> with a hwspinlock to avoid conflicting accesses between processors. 
> 
> version 3:
> - with bindings patch
> 
> version 2:
> - rework hwspinlock locking sequence in stm32 irqchip to take care of the
>   cases where hwspinlock node is disabled or not yet probed
> 
> Benjamin Gaignard (3):
>   dt-bindings: interrupt-controller: stm32: Document hwlock properties
>   irqchip: stm32: protect configuration registers with hwspinlock
>   ARM: dts: stm32: Add hwlock for irqchip on stm32mp157
> 
>  .../interrupt-controller/st,stm32-exti.txt         |   4 +
>  arch/arm/boot/dts/stm32mp157c.dtsi                 |   1 +
>  drivers/irqchip/irq-stm32-exti.c                   | 116 ++++++++++++++++++---
>  3 files changed, 105 insertions(+), 16 deletions(-)
> 

I've taken the first two patches. Please route the DTS patch to the
appropriate tree.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 0/3] Make STM32 interrupt controller use hwspinlock
  2018-12-18 15:39 ` [PATCH v3 0/3] Make STM32 interrupt controller use hwspinlock Marc Zyngier
@ 2018-12-19 15:00   ` Alexandre Torgue
  0 siblings, 0 replies; 7+ messages in thread
From: Alexandre Torgue @ 2018-12-19 15:00 UTC (permalink / raw)
  To: Marc Zyngier, Benjamin Gaignard, tglx, jason, robh+dt, mark.rutland
  Cc: linux-kernel, devicetree, linux-arm-kernel, linux-stm32

Hi Marc,

On 12/18/18 4:39 PM, Marc Zyngier wrote:
> On 17/12/2018 14:22, Benjamin Gaignard wrote:
>> This series allow to protect STM32 interrupt controller configuration registers
>> with a hwspinlock to avoid conflicting accesses between processors.
>>
>> version 3:
>> - with bindings patch
>>
>> version 2:
>> - rework hwspinlock locking sequence in stm32 irqchip to take care of the
>>    cases where hwspinlock node is disabled or not yet probed
>>
>> Benjamin Gaignard (3):
>>    dt-bindings: interrupt-controller: stm32: Document hwlock properties
>>    irqchip: stm32: protect configuration registers with hwspinlock
>>    ARM: dts: stm32: Add hwlock for irqchip on stm32mp157
>>
>>   .../interrupt-controller/st,stm32-exti.txt         |   4 +
>>   arch/arm/boot/dts/stm32mp157c.dtsi                 |   1 +
>>   drivers/irqchip/irq-stm32-exti.c                   | 116 ++++++++++++++++++---
>>   3 files changed, 105 insertions(+), 16 deletions(-)
>>
> 
> I've taken the first two patches. Please route the DTS patch to the
> appropriate tree.
> 

I'll take DTS patch in stm32-next branch.

Regards
Alex

> Thanks,
> 
> 	M.
> 

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

end of thread, other threads:[~2018-12-19 15:01 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-17 14:22 [PATCH v3 0/3] Make STM32 interrupt controller use hwspinlock Benjamin Gaignard
2018-12-17 14:22 ` [PATCH v3 1/3] dt-bindings: interrupt-controller: stm32: Document hwlock properties Benjamin Gaignard
2018-12-18 15:06   ` Rob Herring
2018-12-17 14:22 ` [PATCH v3 2/3] irqchip: stm32: protect configuration registers with hwspinlock Benjamin Gaignard
2018-12-17 14:22 ` [PATCH v3 3/3] ARM: dts: stm32: Add hwlock for irqchip on stm32mp157 Benjamin Gaignard
2018-12-18 15:39 ` [PATCH v3 0/3] Make STM32 interrupt controller use hwspinlock Marc Zyngier
2018-12-19 15:00   ` Alexandre Torgue

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