From: Radu Rendec <radu@rendec.net>
To: Eliav Farber <farbere@amazon.com>,
Thomas Gleixner <tglx@kernel.org>,
Talel Shenhar <talel@amazon.com>
Cc: Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v5 9/9] irqchip/al-fic: support per-child affinity via interrupt redirection
Date: Mon, 12 Oct 2026 15:10:57 -0400 [thread overview]
Message-ID: <07adea400dbab7f1204354070c738f495d5d1646.camel@rendec.net> (raw)
In-Reply-To: <20261011050449.41903-10-farbere@amazon.com>
On Sun, 2026-10-11 at 05:04 +0000, Eliav Farber wrote:
> The FIC multiplexes up to 32 sources into one parent GIC SPI, and a
> child's handler runs in the parent's context, so a child has no affinity
> control of its own. irq_set_affinity() therefore fails with -EINVAL, and
> drivers that treat that as fatal cannot probe when their interrupt
> arrives through a FIC group. The parent routing cannot be changed on
> behalf of one child either, because several FIC groups may share one SPI
> and all of them would move with it.
>
> Use the interrupt redirection infrastructure. Dispatch children with
> generic_handle_demux_domain_irq() and set irq_set_affinity to
> irq_chip_redirect_set_affinity(), so a child whose affinity excludes the
> CPU taking the parent interrupt runs on its target CPU in IRQ work
> context. The interrupt is still taken on the parent's CPU; only the
> child's handler body moves.
>
> Redirection defers the whole flow handler, so the cause bit is cleared in
> al_fic_irq_pre_redirect(), which runs in parent context on both the
> inline and the redirected path. A level configured group is masked there
> too, because its cause bit re-latches while the input stays asserted; the
> deferred handle_level_irq() masks again and unmasks when the handler is
> done. An edge configured group is only acked, since handle_edge_irq() has
> no unconditional unmask. irq_ack is a noop because irq_pre_redirect runs
> on every dispatch and the ack must not happen twice.
>
> Signed-off-by: Eliav Farber <farbere@amazon.com>
> ---
> v5: rewritten from scratch. Thomas Gleixner rejected the
> IRQ_SET_MASK_OK_DONE approach below ("That's a horrible hack and just
> pretends to solve a problem. We have the interrupt redirection
> infrastructure to handle that correctly."). This patch instead wires
> al-fic into that infrastructure (irq_chip_redirect_set_affinity(),
> generic_handle_demux_domain_irq(), and an irq_pre_redirect callback
> that moves the ack - and, for a level configured group, the mask -
> into parent context), per Radu Rendec's confirmation of this shape on
> the v2 thread and the dw_pci driver he and Thomas pointed at as a
> reference. Tested on our hardware: with a child's affinity pinned
> away from the CPU taking the parent SPI, the handler body runs on the
> target CPU and the ack still happens on the parent's CPU, with no
> re-fire storm on a level configured group, and no change to the
> inline (non-redirected) path. This replaces every version of the
> irq_set_affinity callback below; the v2-v4 history is kept for the
> record of how the approach got here.
>
> v4: no change. The question Radu Rendec raised on this patch - whether an
> unconditional IRQ_SET_MASK_OK_DONE is the right contract, or whether
> it should fail with -EINVAL - is still open.
>
> v3: no change. The question Radu Rendec raised on this patch - whether an
> unconditional IRQ_SET_MASK_OK_DONE is the right contract, or whether
> it should fail with -EINVAL - is still under discussion on the v2
> thread and is answered there.
>
> v2: add Co-developed-by/Signed-off-by: Talel Shenhar. No code change from
> v1.
>
> drivers/irqchip/irq-al-fic.c | 46 ++++++++++++++++++++++++++++++++++--
> 1 file changed, 44 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/irqchip/irq-al-fic.c b/drivers/irqchip/irq-al-fic.c
> index 13a945a1d312..77cff6308eba 100644
> --- a/drivers/irqchip/irq-al-fic.c
> +++ b/drivers/irqchip/irq-al-fic.c
> @@ -142,7 +142,13 @@ static irqreturn_t al_fic_irq_handler(int irq, void *data)
> pending &= ~gc->mask_cache;
>
> for_each_set_bit(hwirq, &pending, NR_FIC_IRQS)
> - generic_handle_domain_irq(domain, hwirq);
> + /*
> + * Redirect a child whose affinity excludes this CPU to its
> + * target CPU via irq_work. The ack moves to
> + * al_fic_irq_pre_redirect(), because the whole flow handler is
> + * deferred when that happens.
> + */
> + generic_handle_demux_domain_irq(domain, hwirq);
>
> return pending ? IRQ_HANDLED : IRQ_NONE;
> }
> @@ -157,6 +163,32 @@ static int al_fic_irq_retrigger(struct irq_data *data)
> return 1;
> }
>
> +#ifdef CONFIG_SMP
> +/* The ack happens in al_fic_irq_pre_redirect() on both paths instead. */
> +static void al_fic_irq_noop(struct irq_data *data) { }
> +
> +/*
> + * Runs in the parent interrupt context on every dispatch, redirected or not.
> + * Clear the cause bit here: once the flow handler is deferred, the FIC keeps
> + * driving its output until the irq_work runs, and a level parent SPI re-fires.
> + *
> + * A level configured group is masked too, because its cause bit re-latches
> + * while the input stays asserted; the deferred handle_level_irq() unmasks
> + * when the handler is done. An edge configured group is only acked, since
> + * handle_edge_irq() never unmasks unconditionally and the mask would stay.
> + */
> +static void al_fic_irq_pre_redirect(struct irq_data *data)
> +{
> + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
> + struct al_fic *fic = gc->private;
> +
> + if (fic->state == AL_FIC_CONFIGURED_LEVEL)
> + irq_gc_mask_set_bit(data);
> +
> + irq_gc_ack_clr_bit(data);
> +}
> +#endif /* CONFIG_SMP */
> +
> static int al_fic_register(struct device_node *node,
> struct al_fic *fic,
> enum al_fic_id fic_id)
> @@ -195,9 +227,19 @@ static int al_fic_register(struct device_node *node,
> gc->chip_types->regs.ack = AL_FIC_CAUSE;
> gc->chip_types->chip.irq_mask = irq_gc_mask_set_bit;
> gc->chip_types->chip.irq_unmask = irq_gc_mask_clr_bit;
> - gc->chip_types->chip.irq_ack = irq_gc_ack_clr_bit;
> gc->chip_types->chip.irq_set_type = al_fic_irq_set_type;
> gc->chip_types->chip.irq_retrigger = al_fic_irq_retrigger;
> +#ifdef CONFIG_SMP
> + /*
> + * The FIC has no hardware affinity control, so give each child real
> + * affinity by redirecting its handler to the target CPU.
> + */
> + gc->chip_types->chip.irq_ack = al_fic_irq_noop;
> + gc->chip_types->chip.irq_pre_redirect = al_fic_irq_pre_redirect;
> + gc->chip_types->chip.irq_set_affinity = irq_chip_redirect_set_affinity;
> +#else
> + gc->chip_types->chip.irq_ack = irq_gc_ack_clr_bit;
> +#endif
> gc->chip_types->chip.flags = IRQCHIP_SKIP_SET_WAKE;
> gc->private = fic;
>
Reviewed-by: Radu Rendec <radu@rendec.net>
prev parent reply other threads:[~2026-10-12 19:11 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-11 5:04 [PATCH v5 0/9] irqchip/al-fic: shared parent IRQ, error/fatal outputs and affinity Eliav Farber
2026-10-11 5:04 ` [PATCH v5 1/9] irqchip/al-fic: fix argument alignment and a repeated word Eliav Farber
2026-10-11 5:04 ` [PATCH v5 2/9] irqchip/al-fic: use %pe to print init error Eliav Farber
2026-10-12 18:42 ` Radu Rendec
2026-10-11 5:04 ` [PATCH v5 3/9] irqchip/al-fic: use %pOF and raise init log level Eliav Farber
2026-10-11 5:04 ` [PATCH v5 4/9] irqchip/al-fic: keep the device_node instead of a cached name string Eliav Farber
2026-10-12 18:53 ` Radu Rendec
2026-10-11 5:04 ` [PATCH v5 5/9] irqchip/al-fic: switch to shared parent interrupt Eliav Farber
2026-10-11 5:04 ` [PATCH v5 6/9] dt-bindings: interrupt-controller: amazon,al-fic: add mask selection Eliav Farber
2026-10-11 5:04 ` [PATCH v5 7/9] irqchip/al-fic: support error and fatal outputs and FIC v2 Eliav Farber
2026-10-11 5:04 ` [PATCH v5 8/9] irqchip/al-fic: add support for FIC v3 Eliav Farber
2026-10-11 5:04 ` [PATCH v5 9/9] irqchip/al-fic: support per-child affinity via interrupt redirection Eliav Farber
2026-10-12 19:10 ` Radu Rendec [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=07adea400dbab7f1204354070c738f495d5d1646.camel@rendec.net \
--to=radu@rendec.net \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=farbere@amazon.com \
--cc=krzk+dt@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=robh@kernel.org \
--cc=talel@amazon.com \
--cc=tglx@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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®