[PATCH v2] irqchip: loongson-liointc: add hierarchy irq support

From: Yinbo Zhu
Date: Thu Dec 08 2022 - 23:09:12 EST


When the irq of hierarchical interrupt chip was routed to liointc
that asked liointc driver to support hierarchy irq and this patch
was to add such support.

Signed-off-by: Yinbo Zhu <zhuyinbo@xxxxxxxxxxx>
---
Change in v2:
1. Keep consistent approach for irq handle of dts and acpi.
2. Use a domain to cover all case.
3. Fixup the commit log.

drivers/irqchip/Kconfig | 1 +
drivers/irqchip/irq-loongson-liointc.c | 53 +++++++++++++++++---------
2 files changed, 37 insertions(+), 17 deletions(-)

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index d07568a2c539..97f589d681c6 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -593,6 +593,7 @@ config LOONGSON_LIOINTC
default y
select IRQ_DOMAIN
select GENERIC_IRQ_CHIP
+ select IRQ_DOMAIN_HIERARCHY
help
Support for the Loongson Local I/O Interrupt Controller.

diff --git a/drivers/irqchip/irq-loongson-liointc.c b/drivers/irqchip/irq-loongson-liointc.c
index 85b754f7f4e6..e5670cc6123a 100644
--- a/drivers/irqchip/irq-loongson-liointc.c
+++ b/drivers/irqchip/irq-loongson-liointc.c
@@ -160,26 +160,48 @@ static u32 parent_int_map[LIOINTC_NUM_PARENT];
static const char *const parent_names[] = {"int0", "int1", "int2", "int3"};
static const char *const core_reg_names[] = {"isr0", "isr1", "isr2", "isr3"};

-static int liointc_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
- const u32 *intspec, unsigned int intsize,
- unsigned long *out_hwirq, unsigned int *out_type)
+static int liointc_irq_domain_translate(struct irq_domain *d,
+ struct irq_fwspec *fwspec, unsigned long *out_hwirq,
+ unsigned int *out_type)
{
- if (WARN_ON(intsize < 1))
+ if (WARN_ON(fwspec->param_count < 1))
return -EINVAL;
- *out_hwirq = intspec[0] - GSI_MIN_CPU_IRQ;

- if (intsize > 1)
- *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
+ if (!acpi_disabled)
+ *out_hwirq = fwspec->param[0] - GSI_MIN_CPU_IRQ;
+ else
+ *out_hwirq = fwspec->param[0];
+
+ if (fwspec->param_count > 1)
+ *out_type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
else
*out_type = IRQ_TYPE_NONE;

return 0;
}

-static const struct irq_domain_ops acpi_irq_gc_ops = {
- .map = irq_map_generic_chip,
- .unmap = irq_unmap_generic_chip,
- .xlate = liointc_domain_xlate,
+static int liointc_irq_domain_alloc(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs, void *arg)
+{
+ int i, ret;
+ irq_hw_number_t hwirq;
+ unsigned int type = IRQ_TYPE_NONE;
+ struct irq_fwspec *fwspec = arg;
+
+ ret = liointc_irq_domain_translate(domain, fwspec, &hwirq, &type);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < nr_irqs; i++)
+ irq_map_generic_chip(domain, virq + i, hwirq + i);
+
+ return 0;
+}
+
+static const struct irq_domain_ops irq_gc_ops = {
+ .translate = liointc_irq_domain_translate,
+ .alloc = liointc_irq_domain_alloc,
+ .free = irq_domain_free_irqs_top,
};

static int liointc_init(phys_addr_t addr, unsigned long size, int revision,
@@ -222,12 +244,9 @@ static int liointc_init(phys_addr_t addr, unsigned long size, int revision,
}

/* Setup IRQ domain */
- if (!acpi_disabled)
- domain = irq_domain_create_linear(domain_handle, LIOINTC_CHIP_IRQ,
- &acpi_irq_gc_ops, priv);
- else
- domain = irq_domain_create_linear(domain_handle, LIOINTC_CHIP_IRQ,
- &irq_generic_chip_ops, priv);
+ domain = irq_domain_create_linear(domain_handle, LIOINTC_CHIP_IRQ,
+ &irq_gc_ops, priv);
+
if (!domain) {
pr_err("loongson-liointc: cannot add IRQ domain\n");
goto out_iounmap;
--
2.20.1