Adding init function for GIC irq allocation info structure.
Signed-off-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com --- drivers/irqchip/irq-gic.c | 67 +++++++++++++++++++++++++++++++++++++++-- include/linux/irqchip/arm-gic.h | 11 +++++++ 2 files changed, 75 insertions(+), 3 deletions(-)
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4dd8826..2249c66 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -855,10 +855,13 @@ static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, int i, ret; irq_hw_number_t hwirq; unsigned int type = IRQ_TYPE_NONE; - struct of_phandle_args *irq_data = arg; + struct gic_irq_alloc_info *info = arg; + u32 intspec[3];
- ret = gic_irq_domain_xlate(domain, irq_data->np, irq_data->args, - irq_data->args_count, &hwirq, &type); + intspec[0] = info->gic_int_type; + intspec[1] = info->hwirq; + intspec[2] = info->irq_type; + ret = gic_irq_domain_xlate(domain, info->ref, intspec, 3, &hwirq, &type); if (ret) return ret;
@@ -868,10 +871,68 @@ static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, return 0; }
+static int gic_init_irq_alloc_info(uint32_t *data, int nr, void *ref, + void **info) +{ + struct gic_irq_alloc_info *alloc_info; + unsigned int gic_int_type; + unsigned int hwirq; + unsigned int irq_type; + + if (nr != 3) + return -EINVAL; + + gic_int_type = data[0]; + hwirq = data[1]; + irq_type = data[2]; + + alloc_info = kzalloc(sizeof(struct gic_irq_alloc_info), GFP_KERNEL); + if (!alloc_info) + return -ENOMEM; + + if ((irq_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_HIGH && + (irq_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_EDGE_RISING) + return -EINVAL; + + alloc_info->irq_type = irq_type; + alloc_info->ref = ref; + + /* + * ACPI have no bindings to indicate SPI or PPI, so we + * use different mappings from DT in ACPI. + * + * For FDT + * PPI interrupt: in the range [0, 15]; + * SPI interrupt: in the range [0, 987]; + * + * For ACPI, GSI should be unique so using + * the hwirq directly for the mapping: + * PPI interrupt: in the range [16, 31]; + * SPI interrupt: in the range [32, 1019]; + */ + + if (gic_int_type != GIC_INT_TYPE_NONE) { + alloc_info->gic_int_type = gic_int_type; + alloc_info->hwirq = hwirq; + } else { + if (hwirq < 32) { + alloc_info->gic_int_type = GIC_INT_TYPE_PPI; + alloc_info->hwirq = hwirq - 16; + } else { + alloc_info->gic_int_type = GIC_INT_TYPE_SPI; + alloc_info->hwirq = hwirq - 32; + } + } + + *info = alloc_info; + return 0; +} + static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = { .xlate = gic_irq_domain_xlate, .alloc = gic_irq_domain_alloc, .free = irq_domain_free_irqs_top, + .init_alloc_info = gic_init_irq_alloc_info, };
static const struct irq_domain_ops gic_irq_domain_ops = { diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 9de976b..4d6d6eb 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -89,12 +89,23 @@ #define GICH_MISR_EOI (1 << 0) #define GICH_MISR_U (1 << 1)
+#define GIC_INT_TYPE_SPI 0 +#define GIC_INT_TYPE_PPI 1 +#define GIC_INT_TYPE_NONE ~0U + #ifndef __ASSEMBLY__
#include <linux/irqdomain.h>
struct device_node;
+struct gic_irq_alloc_info { + void *ref; + unsigned int irq_type; + unsigned int gic_int_type; + unsigned int hwirq; +}; + void gic_set_irqchip_flags(unsigned long flags); void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *, u32 offset, struct device_node *);