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 v4 6/8] irqchip/al-fic: support error and fatal outputs and FIC v2
Date: Sat, 10 Oct 2026 13:43:59 -0400 [thread overview]
Message-ID: <947e93b2fedaebccea3d99161d396f2539bd9e40.camel@rendec.net> (raw)
In-Reply-To: <20261008090058.38591-7-farbere@amazon.com>
On Thu, 2026-10-08 at 09:00 +0000, Eliav Farber wrote:
> FIC v2 hardware adds two interrupt outputs on top of the info output: an
> error output and a fatal output, each with its own mask register
> (AL_FIC_ERROR_MASK, AL_FIC_FATAL_MASK). A group drives exactly one of the
> three outputs.
>
> Read which output a group drives from the amazon,al-fic-mask devicetree
> property (info, error or fatal; absent means info) and program the
> matching mask register. Detect the hardware revision from the CONTROL
> register version field (bits 28-29). The revision is not in the
> devicetree, so requesting the error or fatal output on a v1 device - which
> has neither - is rejected at probe against the register.
>
> Name the selected output in the probe log line, in place of the "Legacy
> mode" text it replaces. A booted system then shows which output each group
> drives.
>
> The "v1" and "v2" names are this driver's labels for the CONTROL
> version field encoding (0 and 1).
>
> The driver seeds mask_cache from the value it programs rather than having
> the generic chip read the mask register back, so the error and fatal mask
> registers are never read - which also sidesteps the v2 erratum where they
> always read as 0 regardless of their contents.
>
> Reading CONTROL to get the version field turns the write that follows into
> a read-modify-write instead of a value built from CONTROL_MASK_MSI_X
> alone. Every RW bit in this register resets to 0, so the two are
> equivalent at probe time; the read-modify-write is kept anyway as the
> better practice; it costs nothing and does not depend on the reset value
> staying 0.
>
> Signed-off-by: Eliav Farber <farbere@amazon.com>
> ---
> v4: drop the gc_flags local and the revision-gated condition that cleared
> IRQ_GC_INIT_MASK_CACHE for the v2 error and fatal outputs. Patch 4 now
> seeds mask_cache unconditionally and does not ask for the flag at all,
> so there is nothing left for this patch to gate. The enum
> al_fic_version parameter on al_fic_register() goes with it, since the
> condition was its only user. The v2 read-back erratum is now stated in
> the commit message as a consequence of seeding rather than as the
> reason for a per-revision workaround.
>
> v3:
> - Initialise gc_flags to IRQ_GC_INIT_MASK_CACHE at its declaration and
> only clear it on the FIC v2 error/fatal path, dropping the else
> branch.
> - Use ~0U instead of 0xFFFFFFFF, for the mask_cache seed and for the
> three mask register writes.
> - Explain the control register read-modify-write in the commit message.
> Every writable bit in that register resets to 0, so preserving the
> other bits is equivalent to the previous plain write at probe time. It
> is better practice, not a behaviour fix.
>
> v2:
> - Fix the v2 mask_cache workaround, which was dead in v1. mask_cache is
> not seeded until the first child mapping (irq_map_generic_chip), so the
> v1 override was overwritten with 0 and the first unmask then cleared the
> whole mask register, unmasking all 32 sources. Drop
> IRQ_GC_INIT_MASK_CACHE for the error and fatal outputs and seed
> mask_cache from the value al_fic_wire_init() programmed. Commit message
> rewritten to state the real timing and consequence.
> - Read the output from the new amazon,al-fic-mask property (was per-output
> compatible in v1).
> - Label the mask in the probe log line (mask=%s).
>
> drivers/irqchip/irq-al-fic.c | 108 +++++++++++++++++++++++++++++++----
> 1 file changed, 98 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/irqchip/irq-al-fic.c b/drivers/irqchip/irq-al-fic.c
> index fda9c05a639f..d5671b9624db 100644
> --- a/drivers/irqchip/irq-al-fic.c
> +++ b/drivers/irqchip/irq-al-fic.c
> @@ -16,11 +16,14 @@
> /* FIC Registers */
> #define AL_FIC_CAUSE 0x00
> #define AL_FIC_SET_CAUSE 0x08
> -#define AL_FIC_MASK 0x10
> +#define AL_FIC_INFO_MASK 0x10
> #define AL_FIC_CONTROL 0x28
> +#define AL_FIC_ERROR_MASK 0x2c
> +#define AL_FIC_FATAL_MASK 0x34
>
> #define CONTROL_TRIGGER_RISING BIT(3)
> #define CONTROL_MASK_MSI_X BIT(5)
> +#define CONTROL_VERSION_ID GENMASK(29, 28)
>
> #define NR_FIC_IRQS 32
>
> @@ -33,6 +36,37 @@ enum al_fic_state {
> AL_FIC_CONFIGURED_RISING_EDGE,
> };
>
> +/*
> + * FIC hardware revision, as reported by the CONTROL register version field
> + * (CONTROL_VERSION_ID, bits 29-28). These are this driver's names for that
> + * field's encoding.
> + */
> +enum al_fic_version {
> + AL_FIC_VERSION_V1,
> + AL_FIC_VERSION_V2,
> +};
> +
> +enum al_fic_id {
> + AL_FIC_ID_INFO,
> + AL_FIC_ID_ERROR,
> + AL_FIC_ID_FATAL,
> + AL_FIC_ID_MAX, /* keep last */
> +};
> +
> +/* Mask register offset for each interrupt group */
> +static const unsigned int al_fic_mask_offset[AL_FIC_ID_MAX] = {
> + [AL_FIC_ID_INFO] = AL_FIC_INFO_MASK,
> + [AL_FIC_ID_ERROR] = AL_FIC_ERROR_MASK,
> + [AL_FIC_ID_FATAL] = AL_FIC_FATAL_MASK,
> +};
> +
> +/* amazon,al-fic-mask property value for each interrupt group */
> +static const char * const al_fic_mask_name[AL_FIC_ID_MAX] = {
> + [AL_FIC_ID_INFO] = "info",
> + [AL_FIC_ID_ERROR] = "error",
> + [AL_FIC_ID_FATAL] = "fatal",
> +};
> +
> struct al_fic {
> void __iomem *base;
> struct irq_domain *domain;
> @@ -123,7 +157,8 @@ static int al_fic_irq_retrigger(struct irq_data *data)
> }
>
> static int al_fic_register(struct device_node *node,
> - struct al_fic *fic)
> + struct al_fic *fic,
> + enum al_fic_id fic_id)
> {
> struct irq_chip_generic *gc;
> int ret;
> @@ -155,7 +190,7 @@ static int al_fic_register(struct device_node *node,
>
> gc = irq_get_domain_generic_chip(fic->domain, 0);
> gc->reg_base = fic->base;
> - gc->chip_types->regs.mask = AL_FIC_MASK;
> + gc->chip_types->regs.mask = al_fic_mask_offset[fic_id];
> 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;
> @@ -194,6 +229,8 @@ static int al_fic_register(struct device_node *node,
> * @node: pointer to the interrupt controller's device tree node
> * @base: mmio to fic register
> * @parent_irq: interrupt of parent
> + * @fic_id: which of the controller's outputs (info, error or fatal) this
> + * group drives
> *
> * This API will configure the fic hardware to work in wire mode.
> * In wire mode, fic hardware is generating a wire ("wired") interrupt.
> @@ -202,11 +239,13 @@ static int al_fic_register(struct device_node *node,
> */
> static struct al_fic *al_fic_wire_init(struct device_node *node,
> void __iomem *base,
> - unsigned int parent_irq)
> + unsigned int parent_irq,
> + enum al_fic_id fic_id)
> {
> struct al_fic *fic;
> + u32 version_id;
> + u32 control;
> int ret;
> - u32 control = CONTROL_MASK_MSI_X;
>
> fic = kzalloc_obj(*fic);
> if (!fic)
> @@ -216,22 +255,37 @@ static struct al_fic *al_fic_wire_init(struct device_node *node,
> fic->parent_irq = parent_irq;
> fic->node = node;
>
> + control = readl_relaxed(fic->base + AL_FIC_CONTROL);
> + version_id = FIELD_GET(CONTROL_VERSION_ID, control);
> + if (version_id == AL_FIC_VERSION_V1 && fic_id != AL_FIC_ID_INFO) {
> + pr_err("%pOF: amazon,al-fic-mask = \"%s\" not available on FIC v1\n",
> + node, al_fic_mask_name[fic_id]);
> + ret = -EINVAL;
> + goto err_free;
> + }
> +
> /* mask out all interrupts */
> - writel_relaxed(0xFFFFFFFF, fic->base + AL_FIC_MASK);
> + writel_relaxed(~0U, fic->base + AL_FIC_INFO_MASK);
> + if (version_id > AL_FIC_VERSION_V1) {
> + writel_relaxed(~0U, fic->base + AL_FIC_ERROR_MASK);
> + writel_relaxed(~0U, fic->base + AL_FIC_FATAL_MASK);
> + }
>
> /* clear any pending interrupt */
> writel_relaxed(0, fic->base + AL_FIC_CAUSE);
>
> + /* make sure the controller works in non msi_x mode */
> + control |= CONTROL_MASK_MSI_X;
> writel_relaxed(control, fic->base + AL_FIC_CONTROL);
>
> - ret = al_fic_register(node, fic);
> + ret = al_fic_register(node, fic, fic_id);
> if (ret) {
> pr_err("fail to register irqchip\n");
> goto err_free;
> }
>
> - pr_info("%pOF initialized successfully in Legacy mode (parent-irq=%u)\n",
> - node, parent_irq);
> + pr_info("%pOF initialized successfully (mask=%s parent-irq=%u)\n",
> + node, al_fic_mask_name[fic_id], parent_irq);
>
> return fic;
>
> @@ -240,11 +294,38 @@ static struct al_fic *al_fic_wire_init(struct device_node *node,
> return ERR_PTR(ret);
> }
>
> +/*
> + * Parse the amazon,al-fic-mask property into an enum al_fic_id, selecting
> + * which of the controller's outputs this group drives. The property is
> + * optional; an absent property means the info output.
> + */
> +static int al_fic_parse_mask(struct device_node *node, enum al_fic_id *fic_id)
> +{
> + const char *mask;
> + int ret;
> +
> + ret = of_property_read_string(node, "amazon,al-fic-mask", &mask);
> + if (ret == -EINVAL) {
> + *fic_id = AL_FIC_ID_INFO;
> + return 0;
> + }
> + if (ret)
> + return ret;
> +
> + ret = match_string(al_fic_mask_name, AL_FIC_ID_MAX, mask);
> + if (ret < 0)
> + return ret;
> +
> + *fic_id = ret;
> + return 0;
> +}
> +
> static int __init al_fic_init_dt(struct device_node *node,
> struct device_node *parent)
> {
> int ret;
> void __iomem *base;
> + enum al_fic_id fic_id;
> unsigned int parent_irq;
> struct al_fic *fic;
>
> @@ -253,6 +334,12 @@ static int __init al_fic_init_dt(struct device_node *node,
> return -EINVAL;
> }
>
> + ret = al_fic_parse_mask(node, &fic_id);
> + if (ret) {
> + pr_err("%pOF: invalid amazon,al-fic-mask\n", node);
> + return ret;
> + }
> +
> base = of_iomap(node, 0);
> if (!base) {
> pr_err("%pOF: fail to map memory\n", node);
> @@ -268,7 +355,8 @@ static int __init al_fic_init_dt(struct device_node *node,
>
> fic = al_fic_wire_init(node,
> base,
> - parent_irq);
> + parent_irq,
> + fic_id);
> if (IS_ERR(fic)) {
> pr_err("%pOF: fail to initialize irqchip (%lu)\n",
> node, PTR_ERR(fic));
Reviewed-by: Radu Rendec <radu@rendec.net>
next prev parent reply other threads:[~2026-10-10 17:44 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-08 9:00 [PATCH v4 0/8] irqchip/al-fic: shared parent IRQ, error/fatal outputs and affinity Eliav Farber
2026-10-08 9:00 ` [PATCH v4 1/8] irqchip/al-fic: fix argument alignment and a repeated word Eliav Farber
2026-10-08 9:00 ` [PATCH v4 2/8] irqchip/al-fic: use %pOF and raise init log level Eliav Farber
2026-10-08 9:00 ` [PATCH v4 3/8] irqchip/al-fic: keep the device_node instead of a cached name string Eliav Farber
2026-10-10 15:33 ` Radu Rendec
2026-10-10 18:28 ` Farber, Eliav
2026-10-08 9:00 ` [PATCH v4 4/8] irqchip/al-fic: switch to shared parent interrupt Eliav Farber
2026-10-10 17:19 ` Radu Rendec
2026-10-08 9:00 ` [PATCH v4 5/8] dt-bindings: interrupt-controller: amazon,al-fic: add mask selection Eliav Farber
2026-10-08 9:00 ` [PATCH v4 6/8] irqchip/al-fic: support error and fatal outputs and FIC v2 Eliav Farber
2026-10-10 17:43 ` Radu Rendec [this message]
2026-10-08 9:00 ` [PATCH v4 7/8] irqchip/al-fic: add support for FIC v3 Eliav Farber
2026-10-08 9:00 ` [PATCH v4 8/8] irqchip/al-fic: add irq_set_affinity callback Eliav Farber
2026-10-10 19:52 ` Thomas Gleixner
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=947e93b2fedaebccea3d99161d396f2539bd9e40.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®