Skip to content

Commit db0f032

Browse files
Fabien Dessennelinusw
authored andcommitted
pinctrl: stm32: check for IRQ MUX validity during alloc()
Considering the following irq_domain_ops call chain: - .alloc() is called when a clients calls platform_get_irq() or gpiod_to_irq() - .activate() is called next, when the clients calls request_threaded_irq() Check for the IRQ MUX conflict during the first stage (alloc instead of activate). This avoids to provide the client with an IRQ that can't be used. Signed-off-by: Fabien Dessenne <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Linus Walleij <[email protected]>
1 parent fa99e70 commit db0f032

File tree

1 file changed

+40
-39
lines changed

1 file changed

+40
-39
lines changed

drivers/pinctrl/stm32/pinctrl-stm32.c

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -414,67 +414,54 @@ static int stm32_gpio_domain_activate(struct irq_domain *d,
414414
{
415415
struct stm32_gpio_bank *bank = d->host_data;
416416
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
417-
unsigned long flags;
418417
int ret = 0;
419418

420-
/*
421-
* gpio irq mux is shared between several banks, a lock has to be done
422-
* to avoid overriding.
423-
*/
424-
spin_lock_irqsave(&pctl->irqmux_lock, flags);
425-
426419
if (pctl->hwlock) {
427420
ret = hwspin_lock_timeout_in_atomic(pctl->hwlock,
428421
HWSPNLCK_TIMEOUT);
429422
if (ret) {
430423
dev_err(pctl->dev, "Can't get hwspinlock\n");
431-
goto unlock;
424+
return ret;
432425
}
433426
}
434427

435-
if (pctl->irqmux_map & BIT(irq_data->hwirq)) {
436-
dev_err(pctl->dev, "irq line %ld already requested.\n",
437-
irq_data->hwirq);
438-
ret = -EBUSY;
439-
if (pctl->hwlock)
440-
hwspin_unlock_in_atomic(pctl->hwlock);
441-
goto unlock;
442-
} else {
443-
pctl->irqmux_map |= BIT(irq_data->hwirq);
444-
}
445-
446428
regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_ioport_nr);
447429

448430
if (pctl->hwlock)
449431
hwspin_unlock_in_atomic(pctl->hwlock);
450432

451-
unlock:
452-
spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
453433
return ret;
454434
}
455435

456-
static void stm32_gpio_domain_deactivate(struct irq_domain *d,
457-
struct irq_data *irq_data)
458-
{
459-
struct stm32_gpio_bank *bank = d->host_data;
460-
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
461-
unsigned long flags;
462-
463-
spin_lock_irqsave(&pctl->irqmux_lock, flags);
464-
pctl->irqmux_map &= ~BIT(irq_data->hwirq);
465-
spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
466-
}
467-
468436
static int stm32_gpio_domain_alloc(struct irq_domain *d,
469437
unsigned int virq,
470438
unsigned int nr_irqs, void *data)
471439
{
472440
struct stm32_gpio_bank *bank = d->host_data;
473441
struct irq_fwspec *fwspec = data;
474442
struct irq_fwspec parent_fwspec;
475-
irq_hw_number_t hwirq;
443+
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
444+
irq_hw_number_t hwirq = fwspec->param[0];
445+
unsigned long flags;
446+
int ret = 0;
447+
448+
/*
449+
* Check first that the IRQ MUX of that line is free.
450+
* gpio irq mux is shared between several banks, protect with a lock
451+
*/
452+
spin_lock_irqsave(&pctl->irqmux_lock, flags);
453+
454+
if (pctl->irqmux_map & BIT(hwirq)) {
455+
dev_err(pctl->dev, "irq line %ld already requested.\n", hwirq);
456+
ret = -EBUSY;
457+
} else {
458+
pctl->irqmux_map |= BIT(hwirq);
459+
}
460+
461+
spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
462+
if (ret)
463+
return ret;
476464

477-
hwirq = fwspec->param[0];
478465
parent_fwspec.fwnode = d->parent->fwnode;
479466
parent_fwspec.param_count = 2;
480467
parent_fwspec.param[0] = fwspec->param[0];
@@ -486,12 +473,26 @@ static int stm32_gpio_domain_alloc(struct irq_domain *d,
486473
return irq_domain_alloc_irqs_parent(d, virq, nr_irqs, &parent_fwspec);
487474
}
488475

476+
static void stm32_gpio_domain_free(struct irq_domain *d, unsigned int virq,
477+
unsigned int nr_irqs)
478+
{
479+
struct stm32_gpio_bank *bank = d->host_data;
480+
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
481+
struct irq_data *irq_data = irq_domain_get_irq_data(d, virq);
482+
unsigned long flags, hwirq = irq_data->hwirq;
483+
484+
irq_domain_free_irqs_common(d, virq, nr_irqs);
485+
486+
spin_lock_irqsave(&pctl->irqmux_lock, flags);
487+
pctl->irqmux_map &= ~BIT(hwirq);
488+
spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
489+
}
490+
489491
static const struct irq_domain_ops stm32_gpio_domain_ops = {
490-
.translate = stm32_gpio_domain_translate,
491-
.alloc = stm32_gpio_domain_alloc,
492-
.free = irq_domain_free_irqs_common,
492+
.translate = stm32_gpio_domain_translate,
493+
.alloc = stm32_gpio_domain_alloc,
494+
.free = stm32_gpio_domain_free,
493495
.activate = stm32_gpio_domain_activate,
494-
.deactivate = stm32_gpio_domain_deactivate,
495496
};
496497

497498
/* Pinctrl functions */

0 commit comments

Comments
 (0)