* [PATCH v3 0/2] irqchip: RISC-V PLIC cleanup and optimization @ 2022-07-01 20:24 Samuel Holland 2022-07-01 20:24 ` [PATCH v3 1/2] irqchip/sifive-plic: Make better use of the effective affinity mask Samuel Holland 2022-07-01 20:24 ` [PATCH v3 2/2] irqchip/sifive-plic: Separate the enable and mask operations Samuel Holland 0 siblings, 2 replies; 7+ messages in thread From: Samuel Holland @ 2022-07-01 20:24 UTC (permalink / raw) To: Thomas Gleixner, Marc Zyngier, Palmer Dabbelt, Paul Walmsley, Albert Ou Cc: Samuel Holland, linux-kernel, linux-riscv This series removes the spinlocks and cpumask operations from the PLIC driver's hot path. As far as I know, using the priority to mask interrupts is an intended usage and will work on all existing implementations. See [1] for more discussion. This series depends on my other series[2] making the IRQ affinity mask behavior more consistent between uniprocessor and SMP configurations. (The Allwinner D1 is a uniprocessor SoC containing a PLIC.) A further optimization is to take advantage of the fact that multiple IRQs can be claimed at once. This allows removing the mask operations for oneshot IRQs -- i.e. the combination of IRQCHIP_ONESHOT_SAFE and IRQCHIP_EOI_THREADED, which is not currently supported. I will send this as a separate series, since it makes more invasive changes to the generic IRQ code. [1]: https://lore.kernel.org/lkml/2b063917-17c8-0add-fadf-5aa42532fbbf@sholland.org/ [2]: https://lore.kernel.org/lkml/20220701200056.46555-1-samuel@sholland.org/ Changes in v3: - Rebased on top of irqchip-next - Split affinity series and PLIC series Samuel Holland (2): irqchip/sifive-plic: Make better use of the effective affinity mask irqchip/sifive-plic: Separate the enable and mask operations drivers/irqchip/Kconfig | 1 + drivers/irqchip/irq-sifive-plic.c | 64 ++++++++++++++++--------------- 2 files changed, 35 insertions(+), 30 deletions(-) -- 2.35.1 ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 1/2] irqchip/sifive-plic: Make better use of the effective affinity mask 2022-07-01 20:24 [PATCH v3 0/2] irqchip: RISC-V PLIC cleanup and optimization Samuel Holland @ 2022-07-01 20:24 ` Samuel Holland 2022-07-07 13:31 ` [irqchip: irq/irqchip-next] " irqchip-bot for Samuel Holland 2022-07-10 8:55 ` irqchip-bot for Samuel Holland 2022-07-01 20:24 ` [PATCH v3 2/2] irqchip/sifive-plic: Separate the enable and mask operations Samuel Holland 1 sibling, 2 replies; 7+ messages in thread From: Samuel Holland @ 2022-07-01 20:24 UTC (permalink / raw) To: Thomas Gleixner, Marc Zyngier, Palmer Dabbelt, Paul Walmsley, Albert Ou Cc: Samuel Holland, linux-kernel, linux-riscv The PLIC driver already updates the effective affinity mask in its .irq_set_affinity callback. Take advantage of that information to only touch bits (and take spinlocks) for the specific relevant hart contexts. First, make sure the effective affinity mask is set before IRQ startup. Then, since this mask already takes priv->lmask into account, checking that mask later is no longer needed (and handler->present is equivalent to the bit being set in priv->lmask). Finally, when (un)masking or changing affinity, only clear/set the enable bits in the specific old/new context(s). The cpumask operations in plic_irq_unmask() are not needed because they duplicate the code in plic_set_affinity(). Signed-off-by: Samuel Holland <samuel@sholland.org> --- Changes in v3: - Rebased on top of irqchip-next drivers/irqchip/Kconfig | 1 + drivers/irqchip/irq-sifive-plic.c | 27 +++++++++------------------ 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 462adac905a6..ea7b7485327c 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -531,6 +531,7 @@ config SIFIVE_PLIC bool "SiFive Platform-Level Interrupt Controller" depends on RISCV select IRQ_DOMAIN_HIERARCHY + select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP help This enables support for the PLIC chip found in SiFive (and potentially other) RISC-V systems. The PLIC controls devices diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index b3a36dca7f1b..46595e607b0e 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -114,31 +114,18 @@ static inline void plic_irq_toggle(const struct cpumask *mask, for_each_cpu(cpu, mask) { struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); - if (handler->present && - cpumask_test_cpu(cpu, &handler->priv->lmask)) - plic_toggle(handler, d->hwirq, enable); + plic_toggle(handler, d->hwirq, enable); } } static void plic_irq_unmask(struct irq_data *d) { - struct cpumask amask; - unsigned int cpu; - struct plic_priv *priv = irq_data_get_irq_chip_data(d); - - cpumask_and(&amask, &priv->lmask, cpu_online_mask); - cpu = cpumask_any_and(irq_data_get_affinity_mask(d), - &amask); - if (WARN_ON_ONCE(cpu >= nr_cpu_ids)) - return; - plic_irq_toggle(cpumask_of(cpu), d, 1); + plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 1); } static void plic_irq_mask(struct irq_data *d) { - struct plic_priv *priv = irq_data_get_irq_chip_data(d); - - plic_irq_toggle(&priv->lmask, d, 0); + plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 0); } #ifdef CONFIG_SMP @@ -159,11 +146,13 @@ static int plic_set_affinity(struct irq_data *d, if (cpu >= nr_cpu_ids) return -EINVAL; - plic_irq_toggle(&priv->lmask, d, 0); - plic_irq_toggle(cpumask_of(cpu), d, !irqd_irq_masked(d)); + plic_irq_mask(d); irq_data_update_effective_affinity(d, cpumask_of(cpu)); + if (!irqd_irq_masked(d)) + plic_irq_unmask(d); + return IRQ_SET_MASK_OK_DONE; } #endif @@ -190,6 +179,7 @@ static struct irq_chip plic_edge_chip = { .irq_set_affinity = plic_set_affinity, #endif .irq_set_type = plic_irq_set_type, + .flags = IRQCHIP_AFFINITY_PRE_STARTUP, }; static struct irq_chip plic_chip = { @@ -201,6 +191,7 @@ static struct irq_chip plic_chip = { .irq_set_affinity = plic_set_affinity, #endif .irq_set_type = plic_irq_set_type, + .flags = IRQCHIP_AFFINITY_PRE_STARTUP, }; static int plic_irq_set_type(struct irq_data *d, unsigned int type) -- 2.35.1 ^ permalink raw reply [flat|nested] 7+ messages in thread
* [irqchip: irq/irqchip-next] irqchip/sifive-plic: Make better use of the effective affinity mask 2022-07-01 20:24 ` [PATCH v3 1/2] irqchip/sifive-plic: Make better use of the effective affinity mask Samuel Holland @ 2022-07-07 13:31 ` irqchip-bot for Samuel Holland 2022-07-10 8:55 ` irqchip-bot for Samuel Holland 1 sibling, 0 replies; 7+ messages in thread From: irqchip-bot for Samuel Holland @ 2022-07-07 13:31 UTC (permalink / raw) To: linux-kernel; +Cc: Samuel Holland, Marc Zyngier, tglx The following commit has been merged into the irq/irqchip-next branch of irqchip: Commit-ID: c1eb23d42c0c5c764687a6dfd5d8b9594065dc97 Gitweb: https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms/c1eb23d42c0c5c764687a6dfd5d8b9594065dc97 Author: Samuel Holland <samuel@sholland.org> AuthorDate: Fri, 01 Jul 2022 15:24:39 -05:00 Committer: Marc Zyngier <maz@kernel.org> CommitterDate: Thu, 07 Jul 2022 14:19:48 +01:00 irqchip/sifive-plic: Make better use of the effective affinity mask The PLIC driver already updates the effective affinity mask in its .irq_set_affinity callback. Take advantage of that information to only touch bits (and take spinlocks) for the specific relevant hart contexts. First, make sure the effective affinity mask is set before IRQ startup. Then, since this mask already takes priv->lmask into account, checking that mask later is no longer needed (and handler->present is equivalent to the bit being set in priv->lmask). Finally, when (un)masking or changing affinity, only clear/set the enable bits in the specific old/new context(s). The cpumask operations in plic_irq_unmask() are not needed because they duplicate the code in plic_set_affinity(). Signed-off-by: Samuel Holland <samuel@sholland.org> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20220701202440.59059-2-samuel@sholland.org --- drivers/irqchip/Kconfig | 1 + drivers/irqchip/irq-sifive-plic.c | 27 +++++++++------------------ 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 462adac..ea7b748 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -531,6 +531,7 @@ config SIFIVE_PLIC bool "SiFive Platform-Level Interrupt Controller" depends on RISCV select IRQ_DOMAIN_HIERARCHY + select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP help This enables support for the PLIC chip found in SiFive (and potentially other) RISC-V systems. The PLIC controls devices diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index b3a36dc..46595e6 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -114,31 +114,18 @@ static inline void plic_irq_toggle(const struct cpumask *mask, for_each_cpu(cpu, mask) { struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); - if (handler->present && - cpumask_test_cpu(cpu, &handler->priv->lmask)) - plic_toggle(handler, d->hwirq, enable); + plic_toggle(handler, d->hwirq, enable); } } static void plic_irq_unmask(struct irq_data *d) { - struct cpumask amask; - unsigned int cpu; - struct plic_priv *priv = irq_data_get_irq_chip_data(d); - - cpumask_and(&amask, &priv->lmask, cpu_online_mask); - cpu = cpumask_any_and(irq_data_get_affinity_mask(d), - &amask); - if (WARN_ON_ONCE(cpu >= nr_cpu_ids)) - return; - plic_irq_toggle(cpumask_of(cpu), d, 1); + plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 1); } static void plic_irq_mask(struct irq_data *d) { - struct plic_priv *priv = irq_data_get_irq_chip_data(d); - - plic_irq_toggle(&priv->lmask, d, 0); + plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 0); } #ifdef CONFIG_SMP @@ -159,11 +146,13 @@ static int plic_set_affinity(struct irq_data *d, if (cpu >= nr_cpu_ids) return -EINVAL; - plic_irq_toggle(&priv->lmask, d, 0); - plic_irq_toggle(cpumask_of(cpu), d, !irqd_irq_masked(d)); + plic_irq_mask(d); irq_data_update_effective_affinity(d, cpumask_of(cpu)); + if (!irqd_irq_masked(d)) + plic_irq_unmask(d); + return IRQ_SET_MASK_OK_DONE; } #endif @@ -190,6 +179,7 @@ static struct irq_chip plic_edge_chip = { .irq_set_affinity = plic_set_affinity, #endif .irq_set_type = plic_irq_set_type, + .flags = IRQCHIP_AFFINITY_PRE_STARTUP, }; static struct irq_chip plic_chip = { @@ -201,6 +191,7 @@ static struct irq_chip plic_chip = { .irq_set_affinity = plic_set_affinity, #endif .irq_set_type = plic_irq_set_type, + .flags = IRQCHIP_AFFINITY_PRE_STARTUP, }; static int plic_irq_set_type(struct irq_data *d, unsigned int type) ^ permalink raw reply [flat|nested] 7+ messages in thread
* [irqchip: irq/irqchip-next] irqchip/sifive-plic: Make better use of the effective affinity mask 2022-07-01 20:24 ` [PATCH v3 1/2] irqchip/sifive-plic: Make better use of the effective affinity mask Samuel Holland 2022-07-07 13:31 ` [irqchip: irq/irqchip-next] " irqchip-bot for Samuel Holland @ 2022-07-10 8:55 ` irqchip-bot for Samuel Holland 1 sibling, 0 replies; 7+ messages in thread From: irqchip-bot for Samuel Holland @ 2022-07-10 8:55 UTC (permalink / raw) To: linux-kernel; +Cc: Samuel Holland, Marc Zyngier, tglx The following commit has been merged into the irq/irqchip-next branch of irqchip: Commit-ID: de078949218242d57f791b63fac87cdb09cb0424 Gitweb: https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms/de078949218242d57f791b63fac87cdb09cb0424 Author: Samuel Holland <samuel@sholland.org> AuthorDate: Fri, 01 Jul 2022 15:24:39 -05:00 Committer: Marc Zyngier <maz@kernel.org> CommitterDate: Sun, 10 Jul 2022 09:50:04 +01:00 irqchip/sifive-plic: Make better use of the effective affinity mask The PLIC driver already updates the effective affinity mask in its .irq_set_affinity callback. Take advantage of that information to only touch bits (and take spinlocks) for the specific relevant hart contexts. First, make sure the effective affinity mask is set before IRQ startup. Then, since this mask already takes priv->lmask into account, checking that mask later is no longer needed (and handler->present is equivalent to the bit being set in priv->lmask). Finally, when (un)masking or changing affinity, only clear/set the enable bits in the specific old/new context(s). The cpumask operations in plic_irq_unmask() are not needed because they duplicate the code in plic_set_affinity(). Signed-off-by: Samuel Holland <samuel@sholland.org> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20220701202440.59059-2-samuel@sholland.org --- drivers/irqchip/Kconfig | 1 + drivers/irqchip/irq-sifive-plic.c | 27 +++++++++------------------ 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 462adac..ea7b748 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -531,6 +531,7 @@ config SIFIVE_PLIC bool "SiFive Platform-Level Interrupt Controller" depends on RISCV select IRQ_DOMAIN_HIERARCHY + select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP help This enables support for the PLIC chip found in SiFive (and potentially other) RISC-V systems. The PLIC controls devices diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index b3a36dc..46595e6 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -114,31 +114,18 @@ static inline void plic_irq_toggle(const struct cpumask *mask, for_each_cpu(cpu, mask) { struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); - if (handler->present && - cpumask_test_cpu(cpu, &handler->priv->lmask)) - plic_toggle(handler, d->hwirq, enable); + plic_toggle(handler, d->hwirq, enable); } } static void plic_irq_unmask(struct irq_data *d) { - struct cpumask amask; - unsigned int cpu; - struct plic_priv *priv = irq_data_get_irq_chip_data(d); - - cpumask_and(&amask, &priv->lmask, cpu_online_mask); - cpu = cpumask_any_and(irq_data_get_affinity_mask(d), - &amask); - if (WARN_ON_ONCE(cpu >= nr_cpu_ids)) - return; - plic_irq_toggle(cpumask_of(cpu), d, 1); + plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 1); } static void plic_irq_mask(struct irq_data *d) { - struct plic_priv *priv = irq_data_get_irq_chip_data(d); - - plic_irq_toggle(&priv->lmask, d, 0); + plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 0); } #ifdef CONFIG_SMP @@ -159,11 +146,13 @@ static int plic_set_affinity(struct irq_data *d, if (cpu >= nr_cpu_ids) return -EINVAL; - plic_irq_toggle(&priv->lmask, d, 0); - plic_irq_toggle(cpumask_of(cpu), d, !irqd_irq_masked(d)); + plic_irq_mask(d); irq_data_update_effective_affinity(d, cpumask_of(cpu)); + if (!irqd_irq_masked(d)) + plic_irq_unmask(d); + return IRQ_SET_MASK_OK_DONE; } #endif @@ -190,6 +179,7 @@ static struct irq_chip plic_edge_chip = { .irq_set_affinity = plic_set_affinity, #endif .irq_set_type = plic_irq_set_type, + .flags = IRQCHIP_AFFINITY_PRE_STARTUP, }; static struct irq_chip plic_chip = { @@ -201,6 +191,7 @@ static struct irq_chip plic_chip = { .irq_set_affinity = plic_set_affinity, #endif .irq_set_type = plic_irq_set_type, + .flags = IRQCHIP_AFFINITY_PRE_STARTUP, }; static int plic_irq_set_type(struct irq_data *d, unsigned int type) ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 2/2] irqchip/sifive-plic: Separate the enable and mask operations 2022-07-01 20:24 [PATCH v3 0/2] irqchip: RISC-V PLIC cleanup and optimization Samuel Holland 2022-07-01 20:24 ` [PATCH v3 1/2] irqchip/sifive-plic: Make better use of the effective affinity mask Samuel Holland @ 2022-07-01 20:24 ` Samuel Holland 2022-07-07 13:31 ` [irqchip: irq/irqchip-next] " irqchip-bot for Samuel Holland 2022-07-10 8:55 ` irqchip-bot for Samuel Holland 1 sibling, 2 replies; 7+ messages in thread From: Samuel Holland @ 2022-07-01 20:24 UTC (permalink / raw) To: Thomas Gleixner, Marc Zyngier, Palmer Dabbelt, Paul Walmsley, Albert Ou Cc: Samuel Holland, linux-kernel, linux-riscv The PLIC has two per-IRQ checks before sending an IRQ to a hart context. First, it checks that the IRQ's priority is nonzero. Then, it checks that the enable bit is set for that combination of IRQ and context. Currently, the PLIC driver sets both the priority value and the enable bit in its (un)mask operations. However, modifying the enable bit is problematic for two reasons: 1) The enable bits are packed, so changes are not atomic and require taking a spinlock. 2) The following requirement from the PLIC spec, which explains the racy (un)mask operations in plic_irq_eoi(): If the completion ID does not match an interrupt source that is currently enabled for the target, the completion is silently ignored. Both of these problems are solved by using the priority value to mask IRQs. Each IRQ has a separate priority register, so writing the priority value is atomic. And since the enable bit remains set while an IRQ is masked, the EOI operation works normally. The enable bits are still used to control the IRQ's affinity. Signed-off-by: Samuel Holland <samuel@sholland.org> --- Changes in v3: - Rebased on top of irqchip-next drivers/irqchip/irq-sifive-plic.c | 55 +++++++++++++++++++------------ 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index 46595e607b0e..ba4938188570 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -108,9 +108,7 @@ static inline void plic_irq_toggle(const struct cpumask *mask, struct irq_data *d, int enable) { int cpu; - struct plic_priv *priv = irq_data_get_irq_chip_data(d); - writel(enable, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID); for_each_cpu(cpu, mask) { struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); @@ -118,16 +116,37 @@ static inline void plic_irq_toggle(const struct cpumask *mask, } } -static void plic_irq_unmask(struct irq_data *d) +static void plic_irq_enable(struct irq_data *d) { plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 1); } -static void plic_irq_mask(struct irq_data *d) +static void plic_irq_disable(struct irq_data *d) { plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 0); } +static void plic_irq_unmask(struct irq_data *d) +{ + struct plic_priv *priv = irq_data_get_irq_chip_data(d); + + writel(1, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID); +} + +static void plic_irq_mask(struct irq_data *d) +{ + struct plic_priv *priv = irq_data_get_irq_chip_data(d); + + writel(0, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID); +} + +static void plic_irq_eoi(struct irq_data *d) +{ + struct plic_handler *handler = this_cpu_ptr(&plic_handlers); + + writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM); +} + #ifdef CONFIG_SMP static int plic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) @@ -146,32 +165,21 @@ static int plic_set_affinity(struct irq_data *d, if (cpu >= nr_cpu_ids) return -EINVAL; - plic_irq_mask(d); + plic_irq_disable(d); irq_data_update_effective_affinity(d, cpumask_of(cpu)); - if (!irqd_irq_masked(d)) - plic_irq_unmask(d); + if (!irqd_irq_disabled(d)) + plic_irq_enable(d); return IRQ_SET_MASK_OK_DONE; } #endif -static void plic_irq_eoi(struct irq_data *d) -{ - struct plic_handler *handler = this_cpu_ptr(&plic_handlers); - - if (irqd_irq_masked(d)) { - plic_irq_unmask(d); - writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM); - plic_irq_mask(d); - } else { - writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM); - } -} - static struct irq_chip plic_edge_chip = { .name = "SiFive PLIC", + .irq_enable = plic_irq_enable, + .irq_disable = plic_irq_disable, .irq_ack = plic_irq_eoi, .irq_mask = plic_irq_mask, .irq_unmask = plic_irq_unmask, @@ -184,6 +192,8 @@ static struct irq_chip plic_edge_chip = { static struct irq_chip plic_chip = { .name = "SiFive PLIC", + .irq_enable = plic_irq_enable, + .irq_disable = plic_irq_disable, .irq_mask = plic_irq_mask, .irq_unmask = plic_irq_unmask, .irq_eoi = plic_irq_eoi, @@ -429,8 +439,11 @@ static int __init __plic_init(struct device_node *node, i * CONTEXT_ENABLE_SIZE; handler->priv = priv; done: - for (hwirq = 1; hwirq <= nr_irqs; hwirq++) + for (hwirq = 1; hwirq <= nr_irqs; hwirq++) { plic_toggle(handler, hwirq, 0); + writel(1, priv->regs + PRIORITY_BASE + + hwirq * PRIORITY_PER_ID); + } nr_handlers++; } -- 2.35.1 ^ permalink raw reply [flat|nested] 7+ messages in thread
* [irqchip: irq/irqchip-next] irqchip/sifive-plic: Separate the enable and mask operations 2022-07-01 20:24 ` [PATCH v3 2/2] irqchip/sifive-plic: Separate the enable and mask operations Samuel Holland @ 2022-07-07 13:31 ` irqchip-bot for Samuel Holland 2022-07-10 8:55 ` irqchip-bot for Samuel Holland 1 sibling, 0 replies; 7+ messages in thread From: irqchip-bot for Samuel Holland @ 2022-07-07 13:31 UTC (permalink / raw) To: linux-kernel; +Cc: Samuel Holland, Marc Zyngier, tglx The following commit has been merged into the irq/irqchip-next branch of irqchip: Commit-ID: b5121acddbfc5be09947b95991cae8c645eabcb5 Gitweb: https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms/b5121acddbfc5be09947b95991cae8c645eabcb5 Author: Samuel Holland <samuel@sholland.org> AuthorDate: Fri, 01 Jul 2022 15:24:40 -05:00 Committer: Marc Zyngier <maz@kernel.org> CommitterDate: Thu, 07 Jul 2022 14:19:48 +01:00 irqchip/sifive-plic: Separate the enable and mask operations The PLIC has two per-IRQ checks before sending an IRQ to a hart context. First, it checks that the IRQ's priority is nonzero. Then, it checks that the enable bit is set for that combination of IRQ and context. Currently, the PLIC driver sets both the priority value and the enable bit in its (un)mask operations. However, modifying the enable bit is problematic for two reasons: 1) The enable bits are packed, so changes are not atomic and require taking a spinlock. 2) The following requirement from the PLIC spec, which explains the racy (un)mask operations in plic_irq_eoi(): If the completion ID does not match an interrupt source that is currently enabled for the target, the completion is silently ignored. Both of these problems are solved by using the priority value to mask IRQs. Each IRQ has a separate priority register, so writing the priority value is atomic. And since the enable bit remains set while an IRQ is masked, the EOI operation works normally. The enable bits are still used to control the IRQ's affinity. Signed-off-by: Samuel Holland <samuel@sholland.org> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20220701202440.59059-3-samuel@sholland.org --- drivers/irqchip/irq-sifive-plic.c | 55 ++++++++++++++++++------------ 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index 46595e6..ba49381 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -108,9 +108,7 @@ static inline void plic_irq_toggle(const struct cpumask *mask, struct irq_data *d, int enable) { int cpu; - struct plic_priv *priv = irq_data_get_irq_chip_data(d); - writel(enable, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID); for_each_cpu(cpu, mask) { struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); @@ -118,16 +116,37 @@ static inline void plic_irq_toggle(const struct cpumask *mask, } } -static void plic_irq_unmask(struct irq_data *d) +static void plic_irq_enable(struct irq_data *d) { plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 1); } -static void plic_irq_mask(struct irq_data *d) +static void plic_irq_disable(struct irq_data *d) { plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 0); } +static void plic_irq_unmask(struct irq_data *d) +{ + struct plic_priv *priv = irq_data_get_irq_chip_data(d); + + writel(1, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID); +} + +static void plic_irq_mask(struct irq_data *d) +{ + struct plic_priv *priv = irq_data_get_irq_chip_data(d); + + writel(0, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID); +} + +static void plic_irq_eoi(struct irq_data *d) +{ + struct plic_handler *handler = this_cpu_ptr(&plic_handlers); + + writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM); +} + #ifdef CONFIG_SMP static int plic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) @@ -146,32 +165,21 @@ static int plic_set_affinity(struct irq_data *d, if (cpu >= nr_cpu_ids) return -EINVAL; - plic_irq_mask(d); + plic_irq_disable(d); irq_data_update_effective_affinity(d, cpumask_of(cpu)); - if (!irqd_irq_masked(d)) - plic_irq_unmask(d); + if (!irqd_irq_disabled(d)) + plic_irq_enable(d); return IRQ_SET_MASK_OK_DONE; } #endif -static void plic_irq_eoi(struct irq_data *d) -{ - struct plic_handler *handler = this_cpu_ptr(&plic_handlers); - - if (irqd_irq_masked(d)) { - plic_irq_unmask(d); - writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM); - plic_irq_mask(d); - } else { - writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM); - } -} - static struct irq_chip plic_edge_chip = { .name = "SiFive PLIC", + .irq_enable = plic_irq_enable, + .irq_disable = plic_irq_disable, .irq_ack = plic_irq_eoi, .irq_mask = plic_irq_mask, .irq_unmask = plic_irq_unmask, @@ -184,6 +192,8 @@ static struct irq_chip plic_edge_chip = { static struct irq_chip plic_chip = { .name = "SiFive PLIC", + .irq_enable = plic_irq_enable, + .irq_disable = plic_irq_disable, .irq_mask = plic_irq_mask, .irq_unmask = plic_irq_unmask, .irq_eoi = plic_irq_eoi, @@ -429,8 +439,11 @@ static int __init __plic_init(struct device_node *node, i * CONTEXT_ENABLE_SIZE; handler->priv = priv; done: - for (hwirq = 1; hwirq <= nr_irqs; hwirq++) + for (hwirq = 1; hwirq <= nr_irqs; hwirq++) { plic_toggle(handler, hwirq, 0); + writel(1, priv->regs + PRIORITY_BASE + + hwirq * PRIORITY_PER_ID); + } nr_handlers++; } ^ permalink raw reply [flat|nested] 7+ messages in thread
* [irqchip: irq/irqchip-next] irqchip/sifive-plic: Separate the enable and mask operations 2022-07-01 20:24 ` [PATCH v3 2/2] irqchip/sifive-plic: Separate the enable and mask operations Samuel Holland 2022-07-07 13:31 ` [irqchip: irq/irqchip-next] " irqchip-bot for Samuel Holland @ 2022-07-10 8:55 ` irqchip-bot for Samuel Holland 1 sibling, 0 replies; 7+ messages in thread From: irqchip-bot for Samuel Holland @ 2022-07-10 8:55 UTC (permalink / raw) To: linux-kernel; +Cc: Samuel Holland, Marc Zyngier, tglx The following commit has been merged into the irq/irqchip-next branch of irqchip: Commit-ID: a1706a1c5062e0908528170f853601ed53f428c8 Gitweb: https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms/a1706a1c5062e0908528170f853601ed53f428c8 Author: Samuel Holland <samuel@sholland.org> AuthorDate: Fri, 01 Jul 2022 15:24:40 -05:00 Committer: Marc Zyngier <maz@kernel.org> CommitterDate: Sun, 10 Jul 2022 09:50:04 +01:00 irqchip/sifive-plic: Separate the enable and mask operations The PLIC has two per-IRQ checks before sending an IRQ to a hart context. First, it checks that the IRQ's priority is nonzero. Then, it checks that the enable bit is set for that combination of IRQ and context. Currently, the PLIC driver sets both the priority value and the enable bit in its (un)mask operations. However, modifying the enable bit is problematic for two reasons: 1) The enable bits are packed, so changes are not atomic and require taking a spinlock. 2) The following requirement from the PLIC spec, which explains the racy (un)mask operations in plic_irq_eoi(): If the completion ID does not match an interrupt source that is currently enabled for the target, the completion is silently ignored. Both of these problems are solved by using the priority value to mask IRQs. Each IRQ has a separate priority register, so writing the priority value is atomic. And since the enable bit remains set while an IRQ is masked, the EOI operation works normally. The enable bits are still used to control the IRQ's affinity. Signed-off-by: Samuel Holland <samuel@sholland.org> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20220701202440.59059-3-samuel@sholland.org --- drivers/irqchip/irq-sifive-plic.c | 55 ++++++++++++++++++------------ 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index 46595e6..ba49381 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -108,9 +108,7 @@ static inline void plic_irq_toggle(const struct cpumask *mask, struct irq_data *d, int enable) { int cpu; - struct plic_priv *priv = irq_data_get_irq_chip_data(d); - writel(enable, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID); for_each_cpu(cpu, mask) { struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); @@ -118,16 +116,37 @@ static inline void plic_irq_toggle(const struct cpumask *mask, } } -static void plic_irq_unmask(struct irq_data *d) +static void plic_irq_enable(struct irq_data *d) { plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 1); } -static void plic_irq_mask(struct irq_data *d) +static void plic_irq_disable(struct irq_data *d) { plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 0); } +static void plic_irq_unmask(struct irq_data *d) +{ + struct plic_priv *priv = irq_data_get_irq_chip_data(d); + + writel(1, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID); +} + +static void plic_irq_mask(struct irq_data *d) +{ + struct plic_priv *priv = irq_data_get_irq_chip_data(d); + + writel(0, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID); +} + +static void plic_irq_eoi(struct irq_data *d) +{ + struct plic_handler *handler = this_cpu_ptr(&plic_handlers); + + writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM); +} + #ifdef CONFIG_SMP static int plic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) @@ -146,32 +165,21 @@ static int plic_set_affinity(struct irq_data *d, if (cpu >= nr_cpu_ids) return -EINVAL; - plic_irq_mask(d); + plic_irq_disable(d); irq_data_update_effective_affinity(d, cpumask_of(cpu)); - if (!irqd_irq_masked(d)) - plic_irq_unmask(d); + if (!irqd_irq_disabled(d)) + plic_irq_enable(d); return IRQ_SET_MASK_OK_DONE; } #endif -static void plic_irq_eoi(struct irq_data *d) -{ - struct plic_handler *handler = this_cpu_ptr(&plic_handlers); - - if (irqd_irq_masked(d)) { - plic_irq_unmask(d); - writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM); - plic_irq_mask(d); - } else { - writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM); - } -} - static struct irq_chip plic_edge_chip = { .name = "SiFive PLIC", + .irq_enable = plic_irq_enable, + .irq_disable = plic_irq_disable, .irq_ack = plic_irq_eoi, .irq_mask = plic_irq_mask, .irq_unmask = plic_irq_unmask, @@ -184,6 +192,8 @@ static struct irq_chip plic_edge_chip = { static struct irq_chip plic_chip = { .name = "SiFive PLIC", + .irq_enable = plic_irq_enable, + .irq_disable = plic_irq_disable, .irq_mask = plic_irq_mask, .irq_unmask = plic_irq_unmask, .irq_eoi = plic_irq_eoi, @@ -429,8 +439,11 @@ static int __init __plic_init(struct device_node *node, i * CONTEXT_ENABLE_SIZE; handler->priv = priv; done: - for (hwirq = 1; hwirq <= nr_irqs; hwirq++) + for (hwirq = 1; hwirq <= nr_irqs; hwirq++) { plic_toggle(handler, hwirq, 0); + writel(1, priv->regs + PRIORITY_BASE + + hwirq * PRIORITY_PER_ID); + } nr_handlers++; } ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2022-07-10 8:56 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2022-07-01 20:24 [PATCH v3 0/2] irqchip: RISC-V PLIC cleanup and optimization Samuel Holland 2022-07-01 20:24 ` [PATCH v3 1/2] irqchip/sifive-plic: Make better use of the effective affinity mask Samuel Holland 2022-07-07 13:31 ` [irqchip: irq/irqchip-next] " irqchip-bot for Samuel Holland 2022-07-10 8:55 ` irqchip-bot for Samuel Holland 2022-07-01 20:24 ` [PATCH v3 2/2] irqchip/sifive-plic: Separate the enable and mask operations Samuel Holland 2022-07-07 13:31 ` [irqchip: irq/irqchip-next] " irqchip-bot for Samuel Holland 2022-07-10 8:55 ` irqchip-bot for Samuel Holland
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®