* [PATCH v2 1/4] genirq: Walk the irq_data hierarchy when resending an interrupt
2020-09-03 18:32 [PATCH v2 0/4] irqchip/gic: Generalize use of HW-based retriggering Marc Zyngier
@ 2020-09-03 18:32 ` Marc Zyngier
2020-09-04 19:28 ` Valentin Schneider
2020-09-03 18:32 ` [PATCH v2 2/4] irqchip/gic-v2, v3: Implement irq_chip->irq_retrigger() Marc Zyngier
` (2 subsequent siblings)
3 siblings, 1 reply; 8+ messages in thread
From: Marc Zyngier @ 2020-09-03 18:32 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel
Cc: Jason Cooper, Thomas Gleixner, Valentin Schneider, kernel-team
On resending an interrupt, we only check the topmost irqchip for
a irq_retrigger callback. However, this callback could be implemented
at a lower level. Use irq_chip_retrigger_hierarchy() in this case.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
kernel/irq/resend.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c
index c48ce19a257f..8ccd32a0cc80 100644
--- a/kernel/irq/resend.c
+++ b/kernel/irq/resend.c
@@ -86,6 +86,18 @@ static int irq_sw_resend(struct irq_desc *desc)
}
#endif
+static int try_retrigger(struct irq_desc *desc)
+{
+ if (desc->irq_data.chip->irq_retrigger)
+ return desc->irq_data.chip->irq_retrigger(&desc->irq_data);
+
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+ return irq_chip_retrigger_hierarchy(&desc->irq_data);
+#else
+ return 0;
+#endif
+}
+
/*
* IRQ resend
*
@@ -113,8 +125,7 @@ int check_irq_resend(struct irq_desc *desc, bool inject)
desc->istate &= ~IRQS_PENDING;
- if (!desc->irq_data.chip->irq_retrigger ||
- !desc->irq_data.chip->irq_retrigger(&desc->irq_data))
+ if (!try_retrigger(desc))
err = irq_sw_resend(desc);
/* If the retrigger was successfull, mark it with the REPLAY bit */
--
2.28.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v2 1/4] genirq: Walk the irq_data hierarchy when resending an interrupt
2020-09-03 18:32 ` [PATCH v2 1/4] genirq: Walk the irq_data hierarchy when resending an interrupt Marc Zyngier
@ 2020-09-04 19:28 ` Valentin Schneider
2020-09-05 9:26 ` Marc Zyngier
0 siblings, 1 reply; 8+ messages in thread
From: Valentin Schneider @ 2020-09-04 19:28 UTC (permalink / raw)
To: Marc Zyngier
Cc: linux-kernel, linux-arm-kernel, Jason Cooper, Thomas Gleixner,
kernel-team
Hi Marc,
On 03/09/20 19:32, Marc Zyngier wrote:
> On resending an interrupt, we only check the topmost irqchip for
> a irq_retrigger callback. However, this callback could be implemented
> at a lower level. Use irq_chip_retrigger_hierarchy() in this case.
>
Rookie wording question here; re-reading this I'm questioning which way is
up.
From an irq_data hierarchy PoV, the topmost chip (i.e. last ->parent)
should be the root irqchip. However, the irq_desc we get from irq_to_desc()
ought to hold the irq_data for the lowermost irqchip in that irq_data
hierarchy.
Is it that here by "topmost" you instead mean topmost of the irqchip stack
on top of the root (IOW furthest away from the root)?
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> ---
> kernel/irq/resend.c | 15 +++++++++++++--
> 1 file changed, 13 insertions(+), 2 deletions(-)
>
> diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c
> index c48ce19a257f..8ccd32a0cc80 100644
> --- a/kernel/irq/resend.c
> +++ b/kernel/irq/resend.c
> @@ -86,6 +86,18 @@ static int irq_sw_resend(struct irq_desc *desc)
> }
> #endif
>
> +static int try_retrigger(struct irq_desc *desc)
> +{
> + if (desc->irq_data.chip->irq_retrigger)
> + return desc->irq_data.chip->irq_retrigger(&desc->irq_data);
> +
> +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
> + return irq_chip_retrigger_hierarchy(&desc->irq_data);
> +#else
> + return 0;
> +#endif
> +}
> +
> /*
> * IRQ resend
> *
> @@ -113,8 +125,7 @@ int check_irq_resend(struct irq_desc *desc, bool inject)
>
> desc->istate &= ~IRQS_PENDING;
>
> - if (!desc->irq_data.chip->irq_retrigger ||
> - !desc->irq_data.chip->irq_retrigger(&desc->irq_data))
> + if (!try_retrigger(desc))
> err = irq_sw_resend(desc);
>
> /* If the retrigger was successfull, mark it with the REPLAY bit */
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 1/4] genirq: Walk the irq_data hierarchy when resending an interrupt
2020-09-04 19:28 ` Valentin Schneider
@ 2020-09-05 9:26 ` Marc Zyngier
2020-09-05 12:58 ` Valentin Schneider
0 siblings, 1 reply; 8+ messages in thread
From: Marc Zyngier @ 2020-09-05 9:26 UTC (permalink / raw)
To: Valentin Schneider
Cc: linux-kernel, linux-arm-kernel, Jason Cooper, Thomas Gleixner,
kernel-team
Hi Valentin,
On Fri, 04 Sep 2020 20:28:38 +0100,
Valentin Schneider <valentin.schneider@arm.com> wrote:
>
>
> Hi Marc,
>
> On 03/09/20 19:32, Marc Zyngier wrote:
> > On resending an interrupt, we only check the topmost irqchip for
> > a irq_retrigger callback. However, this callback could be implemented
> > at a lower level. Use irq_chip_retrigger_hierarchy() in this case.
> >
>
> Rookie wording question here; re-reading this I'm questioning which way is
> up.
>
> From an irq_data hierarchy PoV, the topmost chip (i.e. last ->parent)
> should be the root irqchip. However, the irq_desc we get from irq_to_desc()
> ought to hold the irq_data for the lowermost irqchip in that irq_data
> hierarchy.
>
> Is it that here by "topmost" you instead mean topmost of the irqchip stack
> on top of the root (IOW furthest away from the root)?
That's indeed what I mean, but I agree that the terminology is
confusing, and often used inconsistently (by me included).
<random>
Maybe considering the irqchip stack along a vertical axis is the wrong
thing to do, and that looking at it as a volume would be marginally
better?
How about innermost (close to the CPU) vs outermost (close to the
device)?
</random>
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 1/4] genirq: Walk the irq_data hierarchy when resending an interrupt
2020-09-05 9:26 ` Marc Zyngier
@ 2020-09-05 12:58 ` Valentin Schneider
0 siblings, 0 replies; 8+ messages in thread
From: Valentin Schneider @ 2020-09-05 12:58 UTC (permalink / raw)
To: Marc Zyngier
Cc: linux-kernel, linux-arm-kernel, Jason Cooper, Thomas Gleixner,
kernel-team
On 05/09/20 10:26, Marc Zyngier wrote:
> <random>
> Maybe considering the irqchip stack along a vertical axis is the wrong
> thing to do, and that looking at it as a volume would be marginally
> better?
>
> How about innermost (close to the CPU) vs outermost (close to the
> device)?
> </random>
>
I guess this is fairly subjective, but the inner/outer thing does click
with me.
I think the "issue" with the top / bottom wording is that existing data
structures (domain / irq_data hierarchy) bias my interpretation of it, but
it's upside down from the irq_chip stack representation. That's not the
case of inner / outer where all I can think of is the actual chip layout
(i.e. as an image of the distance from the CPUs).
Anyway, that's enough psychoanalysis from me, the patches look fine - I
also reran my quick rtcwake test on GICv2 (tests the WAKEUP_ARMED
path). Feel free to add
Reviewed-by: Valentin Schneider <valentin.schneider@arm.com>
to 1/4 & 3/4.
> Thanks,
>
> M.
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 2/4] irqchip/gic-v2, v3: Implement irq_chip->irq_retrigger()
2020-09-03 18:32 [PATCH v2 0/4] irqchip/gic: Generalize use of HW-based retriggering Marc Zyngier
2020-09-03 18:32 ` [PATCH v2 1/4] genirq: Walk the irq_data hierarchy when resending an interrupt Marc Zyngier
@ 2020-09-03 18:32 ` Marc Zyngier
2020-09-03 18:32 ` [PATCH v2 3/4] irqchip/git-v3-its: Implement irq_retrigger callback for device-triggered LPIs Marc Zyngier
2020-09-03 18:32 ` [PATCH v2 4/4] irqchip/gic-v2, v3: Prevent SW resends entirely Marc Zyngier
3 siblings, 0 replies; 8+ messages in thread
From: Marc Zyngier @ 2020-09-03 18:32 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel
Cc: Jason Cooper, Thomas Gleixner, Valentin Schneider, kernel-team
From: Valentin Schneider <valentin.schneider@arm.com>
While digging around IRQCHIP_EOI_IF_HANDLED and irq/resend.c, it has come
to my attention that the IRQ resend situation seems a bit precarious for
the GIC(s).
When marking an IRQ with IRQS_PENDING, handle_fasteoi_irq() will bail out
and issue an irq_eoi(). Should the IRQ in question be re-enabled,
check_irq_resend() will trigger a SW resend, which will go through the flow
handler again and issue *another* irq_eoi() on the *same* IRQ
activation. This is something the GIC spec clearly describes as a bad idea:
any EOI must match a previous ACK.
Implement irq_chip.irq_retrigger() for the GIC chips by setting the GIC
pending bit of the relevant IRQ. After being called by check_irq_resend(),
this will eventually trigger a *new* interrupt which we will handle as usual.
Signed-off-by: Valentin Schneider <valentin.schneider@arm.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20200730170321.31228-2-valentin.schneider@arm.com
---
drivers/irqchip/irq-gic-v3.c | 7 +++++++
drivers/irqchip/irq-gic.c | 6 ++++++
2 files changed, 13 insertions(+)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 324f280ff606..b507bc7c5cda 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -1207,6 +1207,11 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
#define gic_smp_init() do { } while(0)
#endif
+static int gic_retrigger(struct irq_data *data)
+{
+ return !gic_irq_set_irqchip_state(data, IRQCHIP_STATE_PENDING, true);
+}
+
#ifdef CONFIG_CPU_PM
static int gic_cpu_pm_notifier(struct notifier_block *self,
unsigned long cmd, void *v)
@@ -1242,6 +1247,7 @@ static struct irq_chip gic_chip = {
.irq_eoi = gic_eoi_irq,
.irq_set_type = gic_set_type,
.irq_set_affinity = gic_set_affinity,
+ .irq_retrigger = gic_retrigger,
.irq_get_irqchip_state = gic_irq_get_irqchip_state,
.irq_set_irqchip_state = gic_irq_set_irqchip_state,
.irq_nmi_setup = gic_irq_nmi_setup,
@@ -1258,6 +1264,7 @@ static struct irq_chip gic_eoimode1_chip = {
.irq_eoi = gic_eoimode1_eoi_irq,
.irq_set_type = gic_set_type,
.irq_set_affinity = gic_set_affinity,
+ .irq_retrigger = gic_retrigger,
.irq_get_irqchip_state = gic_irq_get_irqchip_state,
.irq_set_irqchip_state = gic_irq_set_irqchip_state,
.irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity,
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index a27ba2cc1dce..e92ee2b6d7a5 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -347,6 +347,11 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
}
#endif
+static int gic_retrigger(struct irq_data *data)
+{
+ return !gic_irq_set_irqchip_state(data, IRQCHIP_STATE_PENDING, true);
+}
+
static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{
u32 irqstat, irqnr;
@@ -417,6 +422,7 @@ static const struct irq_chip gic_chip = {
.irq_unmask = gic_unmask_irq,
.irq_eoi = gic_eoi_irq,
.irq_set_type = gic_set_type,
+ .irq_retrigger = gic_retrigger,
.irq_get_irqchip_state = gic_irq_get_irqchip_state,
.irq_set_irqchip_state = gic_irq_set_irqchip_state,
.flags = IRQCHIP_SET_TYPE_MASKED |
--
2.28.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 3/4] irqchip/git-v3-its: Implement irq_retrigger callback for device-triggered LPIs
2020-09-03 18:32 [PATCH v2 0/4] irqchip/gic: Generalize use of HW-based retriggering Marc Zyngier
2020-09-03 18:32 ` [PATCH v2 1/4] genirq: Walk the irq_data hierarchy when resending an interrupt Marc Zyngier
2020-09-03 18:32 ` [PATCH v2 2/4] irqchip/gic-v2, v3: Implement irq_chip->irq_retrigger() Marc Zyngier
@ 2020-09-03 18:32 ` Marc Zyngier
2020-09-03 18:32 ` [PATCH v2 4/4] irqchip/gic-v2, v3: Prevent SW resends entirely Marc Zyngier
3 siblings, 0 replies; 8+ messages in thread
From: Marc Zyngier @ 2020-09-03 18:32 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel
Cc: Jason Cooper, Thomas Gleixner, Valentin Schneider, kernel-team
It is pretty easy to provide a retrigger callback for the ITS,
as it we already have the required support in terms of
irq_set_irqchip_state().
Note that this only works for device-generated LPIs, and not
the GICv4 doorbells, which should never have to be retriggered
anyway.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
drivers/irqchip/irq-gic-v3-its.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 95f097448f97..2808545a963e 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1720,6 +1720,11 @@ static int its_irq_set_irqchip_state(struct irq_data *d,
return 0;
}
+static int its_irq_retrigger(struct irq_data *d)
+{
+ return !its_irq_set_irqchip_state(d, IRQCHIP_STATE_PENDING, true);
+}
+
/*
* Two favourable cases:
*
@@ -1971,6 +1976,7 @@ static struct irq_chip its_irq_chip = {
.irq_set_affinity = its_set_affinity,
.irq_compose_msi_msg = its_irq_compose_msi_msg,
.irq_set_irqchip_state = its_irq_set_irqchip_state,
+ .irq_retrigger = its_irq_retrigger,
.irq_set_vcpu_affinity = its_irq_set_vcpu_affinity,
};
--
2.28.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 4/4] irqchip/gic-v2, v3: Prevent SW resends entirely
2020-09-03 18:32 [PATCH v2 0/4] irqchip/gic: Generalize use of HW-based retriggering Marc Zyngier
` (2 preceding siblings ...)
2020-09-03 18:32 ` [PATCH v2 3/4] irqchip/git-v3-its: Implement irq_retrigger callback for device-triggered LPIs Marc Zyngier
@ 2020-09-03 18:32 ` Marc Zyngier
3 siblings, 0 replies; 8+ messages in thread
From: Marc Zyngier @ 2020-09-03 18:32 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel
Cc: Jason Cooper, Thomas Gleixner, Valentin Schneider, kernel-team
From: Valentin Schneider <valentin.schneider@arm.com>
The GIC irqchips can now use a HW resend when a retrigger is invoked by
check_irq_resend(). However, should the HW resend fail, check_irq_resend()
will still attempt to trigger a SW resend, which is still a bad idea for
the GICs.
Prevent this from happening by setting IRQD_HANDLE_ENFORCE_IRQCTX on all
GIC IRQs. Technically per-cpu IRQs do not need this, as their flow handlers
never set IRQS_PENDING, but this aligns all IRQs wrt context enforcement:
this also forces all GIC IRQ handling to happen in IRQ context (as defined
by in_irq()).
Signed-off-by: Valentin Schneider <valentin.schneider@arm.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20200730170321.31228-3-valentin.schneider@arm.com
---
drivers/irqchip/irq-gic-v3.c | 5 ++++-
drivers/irqchip/irq-gic.c | 6 +++++-
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index b507bc7c5cda..4e9387aafed8 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -1279,6 +1279,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
struct irq_chip *chip = &gic_chip;
+ struct irq_data *irqd = irq_desc_get_irq_data(irq_to_desc(irq));
if (static_branch_likely(&supports_deactivate_key))
chip = &gic_eoimode1_chip;
@@ -1296,7 +1297,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_domain_set_info(d, irq, hw, chip, d->host_data,
handle_fasteoi_irq, NULL, NULL);
irq_set_probe(irq);
- irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq)));
+ irqd_set_single_target(irqd);
break;
case LPI_RANGE:
@@ -1310,6 +1311,8 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
return -EPERM;
}
+ /* Prevents SW retriggers which mess up the ACK/EOI ordering */
+ irqd_set_handle_enforce_irqctx(irqd);
return 0;
}
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index e92ee2b6d7a5..b59bcef69bf3 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -975,6 +975,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
struct gic_chip_data *gic = d->host_data;
+ struct irq_data *irqd = irq_desc_get_irq_data(irq_to_desc(irq));
if (hw < 32) {
irq_set_percpu_devid(irq);
@@ -984,8 +985,11 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data,
handle_fasteoi_irq, NULL, NULL);
irq_set_probe(irq);
- irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq)));
+ irqd_set_single_target(irqd);
}
+
+ /* Prevents SW retriggers which mess up the ACK/EOI ordering */
+ irqd_set_handle_enforce_irqctx(irqd);
return 0;
}
--
2.28.0
^ permalink raw reply related [flat|nested] 8+ messages in thread