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 <[email protected]>
---
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
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 <[email protected]>
AuthorDate: Fri, 01 Jul 2022 15:24:39 -05:00
Committer: Marc Zyngier <[email protected]>
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 <[email protected]>
Signed-off-by: Marc Zyngier <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
---
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)
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 <[email protected]>
AuthorDate: Fri, 01 Jul 2022 15:24:39 -05:00
Committer: Marc Zyngier <[email protected]>
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 <[email protected]>
Signed-off-by: Marc Zyngier <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
---
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)