Re: [PATCH 2/2] irqchip: Add Xilinx Versal NET SMMU CSR interrupt controller driver
From: Tushar Nimkar
Date: Mon Aug 24 2026 - 05:29:00 EST
Hi Thomas,
thanks for reviewing.
On 8/20/2026 1:03 AM, Thomas Gleixner wrote:
Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.sure.
On Mon, Aug 17 2026 at 16:22, Tushar Nimkar wrote:
+/**Please make the member descriptions tabular aligned
+ * struct xilinx_smmu_csr - SMMU CSR interrupt controller context
+ * @base: MMIO base address of the CSR registers
+ * @domain: IRQ domain for the child interrupts
+ * @parent_irq: parent (GIC) IRQ this block is chained to
+ * @lock: protects the SMMU_CSR_IER/IDR/ISR read and writes
@base: MMIO ...
@domain: Interrupt domain
And yes, use interrupt and not IRQ. This is not twitter.
+static void xilinx_smmu_csr_irq_mask(struct irq_data *d)guard(raw_spinlock)(&crs->lock);
+{
+ struct xilinx_smmu_csr *csr = irq_data_get_irq_chip_data(d);
+ u32 mask = xilinx_smmu_csr_hwirq_mask(d->hwirq);
+
+ if (!mask)
+ return;
+
+ raw_spin_lock(&csr->lock);
okay
okay
+ writel(mask, csr->base + SMMU_CSR_IDR);Ditto
+ raw_spin_unlock(&csr->lock);
+}
+
+static void xilinx_smmu_csr_irq_unmask(struct irq_data *d)
+{
+ struct xilinx_smmu_csr *csr = irq_data_get_irq_chip_data(d);
+ u32 mask = xilinx_smmu_csr_hwirq_mask(d->hwirq);
+
+ if (!mask)
+ return;
+
+ raw_spin_lock(&csr->lock);
okay+ writel(mask, csr->base + SMMU_CSR_IER);Ditto.
+ raw_spin_unlock(&csr->lock);
+}
+
+static void xilinx_smmu_csr_irq_ack(struct irq_data *d)
+{
+ struct xilinx_smmu_csr *csr = irq_data_get_irq_chip_data(d);
+ u32 mask = xilinx_smmu_csr_hwirq_mask(d->hwirq);
+
+ if (!mask)
+ return;
+
+ raw_spin_lock(&csr->lock);
will remove seems not needed.
+ writel(mask, csr->base + SMMU_CSR_ISR);scoped_guard() if you can explain what the lock is actually protecting
+ raw_spin_unlock(&csr->lock);
+}
+
+static struct irq_chip xilinx_smmu_csr_chip = {
+ .name = "xlnx-smmu-csr",
+ .irq_mask = xilinx_smmu_csr_irq_mask,
+ .irq_unmask = xilinx_smmu_csr_irq_unmask,
+ .irq_ack = xilinx_smmu_csr_irq_ack,
+};
+
+static void xilinx_smmu_csr_irq_handler(struct irq_desc *desc)
+{
+ struct xilinx_smmu_csr *csr = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ u32 status, pending;
+
+ chained_irq_enter(chip, desc);
+ raw_spin_lock(&csr->lock);
here ...
I agree! Locking part will be removed.+ status = readl(csr->base + SMMU_CSR_ISR);... and here. There is _ONE_ chained demultiplex handler per chip, so where
+ raw_spin_unlock(&csr->lock);
+
+ /* Only service sources we support; SMMU_CSR_ISR latches raw status */
+ pending = status & SMMU_INTR_ALL;
+
+ while (pending) {
+ irq_hw_number_t hwirq = __ffs(pending);
+ int ret;
+
+ ret = generic_handle_domain_irq(csr->domain, hwirq);
+ if (ret) {
+ raw_spin_lock(&csr->lock);
+ writel(BIT(hwirq), csr->base + SMMU_CSR_ISR);
+ raw_spin_unlock(&csr->lock);
is the concurrency vs. the read and write from/to SMMU_CSR_ISR?
The irq_ack() callback of the demultiplexed interrupts cannot happen
concurrently because that happens in the context of the demultiplexed
handler invoked by generic_handle_domain_irq(). No?
Not that I care about the performance of your code, but I care about
code clarity. If there is a reason for this magic lock voodoo here, then
please explain it in a comment.
Also this write here wants a comment. Why is the pending bit written
back in the failure case? I assume to acknowlegde the interrupt. How are
the interrupts which are handled acknowledged?
The original intention was to handle cases where an interrupt source is asserted but the ARM SMMUv3 driver has not registered a corresponding handler yet. In that case generic_handle_domain_irq() returns an error and the interrupt remains pending, which can lead to an interrupt storm.
The write-back was added to clear the pending status in that failure path.
However, with the current implementation we only process interrupt sources covered by SMMU_INTR_ALL:
...
/* Only service sources we support; SMMU_CSR_ISR latches raw status */
pending = status & SMMU_INTR_ALL;
...
and those are expected to have registered handlers. Therefore the failure case should not be reachable today. Given that, I agree the extra locking/acknowledgement logic is not justified and can be removed for clarity.
We could always reintroduce it if support for additional interrupt sources is added in the future.
Shall we mask still ?
Also if this happens, then this code should make sure to mask this
interrupt line because if something left it unmasked it will come back
forever.
okay+ pr_err_ratelimited("xilinx-smmu-csr: Failed to handle domain IRQ %lu: %d\n",No line break required. You have 100 characters. Please fix that up all over the place.
+ hwirq, ret);
+ }
+
+ pending &= ~BIT(hwirq);
+ }
+static int __init xilinx_smmu_csr_init(struct device_node *node,
+ struct device_node *parent)
okay+{devm_kzalloc()
+ struct xilinx_smmu_csr *csr;
+ int ret;
+
+ if (WARN_ON_ONCE(!parent))
+ return -EINVAL;
+
+ if (irq_find_matching_fwnode(of_fwnode_handle(node),
+ DOMAIN_BUS_ANY))
+ return -ENODEV;
+
+ csr = kzalloc(sizeof(*csr), GFP_KERNEL);
okay
+ if (!csr)devm_of_iomap()
+ return -ENOMEM;
+
+ raw_spin_lock_init(&csr->lock);
+
+ csr->base = of_iomap(node, 0);
okay sure, let me re-base.
+ if (!csr->base) {devm_irq_domain_instantiate() or use this one:
+ ret = -ENOMEM;
+ goto free;
+ }
+
+ /* Start from a known state: all sources disabled, latches cleared. */
+ writel(SMMU_INTR_ALL, csr->base + SMMU_CSR_IDR);
+ writel(SMMU_INTR_ALL, csr->base + SMMU_CSR_ISR);
+
+ csr->domain = irq_domain_create_linear(of_fwnode_handle(node), SMMU_CSR_IRQ_NR,
+ &xilinx_smmu_csr_domain_ops,
+ csr);
https://lore.kernel.org/lkml/20260819090543.585131-2-Zhipeng.wang_1@xxxxxxxxxxx/
It's not merged into tip yet, but it will be.
did not get you here,
+ if (!csr->domain) {with that all these 'ret = -ERROR; goto foo;' go away.
+ pr_err("%pOF: failed to create irq domain\n", node);
+ ret = -ENOMEM;
+ goto unmap;
Thanks,
tglx
Thanks,
Tushar