Skip to content

Commit fb94109

Browse files
benjamingaignardMarc Zyngier
authored andcommitted
irqchip/stm32: protect configuration registers with hwspinlock
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> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
1 parent 897898a commit fb94109

File tree

1 file changed

+100
-16
lines changed

1 file changed

+100
-16
lines changed

drivers/irqchip/irq-stm32-exti.c

Lines changed: 100 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
*/
77

88
#include <linux/bitops.h>
9+
#include <linux/delay.h>
10+
#include <linux/hwspinlock.h>
911
#include <linux/interrupt.h>
1012
#include <linux/io.h>
1113
#include <linux/irq.h>
@@ -20,6 +22,9 @@
2022

2123
#define IRQS_PER_BANK 32
2224

25+
#define HWSPNLCK_TIMEOUT 1000 /* usec */
26+
#define HWSPNLCK_RETRY_DELAY 100 /* usec */
27+
2328
struct stm32_exti_bank {
2429
u32 imr_ofst;
2530
u32 emr_ofst;
@@ -32,6 +37,12 @@ struct stm32_exti_bank {
3237

3338
#define UNDEF_REG ~0
3439

40+
enum stm32_exti_hwspinlock {
41+
HWSPINLOCK_UNKNOWN,
42+
HWSPINLOCK_NONE,
43+
HWSPINLOCK_READY,
44+
};
45+
3546
struct stm32_desc_irq {
3647
u32 exti;
3748
u32 irq_parent;
@@ -58,6 +69,9 @@ struct stm32_exti_host_data {
5869
void __iomem *base;
5970
struct stm32_exti_chip_data *chips_data;
6071
const struct stm32_exti_drv_data *drv_data;
72+
struct device_node *node;
73+
enum stm32_exti_hwspinlock hwlock_state;
74+
struct hwspinlock *hwlock;
6175
};
6276

6377
static struct stm32_exti_host_data *stm32_host_data;
@@ -269,6 +283,64 @@ static int stm32_exti_set_type(struct irq_data *d,
269283
return 0;
270284
}
271285

286+
static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data)
287+
{
288+
struct stm32_exti_host_data *host_data = chip_data->host_data;
289+
struct hwspinlock *hwlock;
290+
int id, ret = 0, timeout = 0;
291+
292+
/* first time, check for hwspinlock availability */
293+
if (unlikely(host_data->hwlock_state == HWSPINLOCK_UNKNOWN)) {
294+
id = of_hwspin_lock_get_id(host_data->node, 0);
295+
if (id >= 0) {
296+
hwlock = hwspin_lock_request_specific(id);
297+
if (hwlock) {
298+
/* found valid hwspinlock */
299+
host_data->hwlock_state = HWSPINLOCK_READY;
300+
host_data->hwlock = hwlock;
301+
pr_debug("%s hwspinlock = %d\n", __func__, id);
302+
} else {
303+
host_data->hwlock_state = HWSPINLOCK_NONE;
304+
}
305+
} else if (id != -EPROBE_DEFER) {
306+
host_data->hwlock_state = HWSPINLOCK_NONE;
307+
} else {
308+
/* hwspinlock driver shall be ready at that stage */
309+
ret = -EPROBE_DEFER;
310+
}
311+
}
312+
313+
if (likely(host_data->hwlock_state == HWSPINLOCK_READY)) {
314+
/*
315+
* Use the x_raw API since we are under spin_lock protection.
316+
* Do not use the x_timeout API because we are under irq_disable
317+
* mode (see __setup_irq())
318+
*/
319+
do {
320+
ret = hwspin_trylock_raw(host_data->hwlock);
321+
if (!ret)
322+
return 0;
323+
324+
udelay(HWSPNLCK_RETRY_DELAY);
325+
timeout += HWSPNLCK_RETRY_DELAY;
326+
} while (timeout < HWSPNLCK_TIMEOUT);
327+
328+
if (ret == -EBUSY)
329+
ret = -ETIMEDOUT;
330+
}
331+
332+
if (ret)
333+
pr_err("%s can't get hwspinlock (%d)\n", __func__, ret);
334+
335+
return ret;
336+
}
337+
338+
static void stm32_exti_hwspin_unlock(struct stm32_exti_chip_data *chip_data)
339+
{
340+
if (likely(chip_data->host_data->hwlock_state == HWSPINLOCK_READY))
341+
hwspin_unlock_raw(chip_data->host_data->hwlock);
342+
}
343+
272344
static int stm32_irq_set_type(struct irq_data *d, unsigned int type)
273345
{
274346
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)
279351

280352
irq_gc_lock(gc);
281353

354+
err = stm32_exti_hwspin_lock(chip_data);
355+
if (err)
356+
goto unlock;
357+
282358
rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst);
283359
ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst);
284360

285361
err = stm32_exti_set_type(d, type, &rtsr, &ftsr);
286-
if (err) {
287-
irq_gc_unlock(gc);
288-
return err;
289-
}
362+
if (err)
363+
goto unspinlock;
290364

291365
irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst);
292366
irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst);
293367

368+
unspinlock:
369+
stm32_exti_hwspin_unlock(chip_data);
370+
unlock:
294371
irq_gc_unlock(gc);
295372

296-
return 0;
373+
return err;
297374
}
298375

299376
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)
460537
int err;
461538

462539
raw_spin_lock(&chip_data->rlock);
540+
541+
err = stm32_exti_hwspin_lock(chip_data);
542+
if (err)
543+
goto unlock;
544+
463545
rtsr = readl_relaxed(base + stm32_bank->rtsr_ofst);
464546
ftsr = readl_relaxed(base + stm32_bank->ftsr_ofst);
465547

466548
err = stm32_exti_set_type(d, type, &rtsr, &ftsr);
467-
if (err) {
468-
raw_spin_unlock(&chip_data->rlock);
469-
return err;
470-
}
549+
if (err)
550+
goto unspinlock;
471551

472552
writel_relaxed(rtsr, base + stm32_bank->rtsr_ofst);
473553
writel_relaxed(ftsr, base + stm32_bank->ftsr_ofst);
554+
555+
unspinlock:
556+
stm32_exti_hwspin_unlock(chip_data);
557+
unlock:
474558
raw_spin_unlock(&chip_data->rlock);
475559

476-
return 0;
560+
return err;
477561
}
478562

479563
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,
599683
return NULL;
600684

601685
host_data->drv_data = dd;
686+
host_data->node = node;
687+
host_data->hwlock_state = HWSPINLOCK_UNKNOWN;
602688
host_data->chips_data = kcalloc(dd->bank_nr,
603689
sizeof(struct stm32_exti_chip_data),
604690
GFP_KERNEL);
@@ -625,8 +711,7 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd,
625711

626712
static struct
627713
stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
628-
u32 bank_idx,
629-
struct device_node *node)
714+
u32 bank_idx)
630715
{
631716
const struct stm32_exti_bank *stm32_bank;
632717
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,
656741
if (stm32_bank->fpr_ofst != UNDEF_REG)
657742
writel_relaxed(~0UL, base + stm32_bank->fpr_ofst);
658743

659-
pr_info("%s: bank%d, External IRQs available:%#x\n",
660-
node->full_name, bank_idx, irqs_mask);
744+
pr_info("%pOF: bank%d\n", h_data->node, bank_idx);
661745

662746
return chip_data;
663747
}
@@ -697,7 +781,7 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
697781
struct stm32_exti_chip_data *chip_data;
698782

699783
stm32_bank = drv_data->exti_banks[i];
700-
chip_data = stm32_exti_chip_init(host_data, i, node);
784+
chip_data = stm32_exti_chip_init(host_data, i);
701785

702786
gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK);
703787

@@ -760,7 +844,7 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data,
760844
return -ENOMEM;
761845

762846
for (i = 0; i < drv_data->bank_nr; i++)
763-
stm32_exti_chip_init(host_data, i, node);
847+
stm32_exti_chip_init(host_data, i);
764848

765849
domain = irq_domain_add_hierarchy(parent_domain, 0,
766850
drv_data->bank_nr * IRQS_PER_BANK,

0 commit comments

Comments
 (0)