From mboxrd@z Thu Jan 1 00:00:00 1970 From: nicolas.ferre@atmel.com (Nicolas Ferre) Date: Mon, 25 Jun 2012 10:36:52 +0200 Subject: [PATCH v3 7/7] ARM: at91: add AIC5 support In-Reply-To: <1340467956-12422-1-git-send-email-ludovic.desroches@atmel.com> References: <1340467539-12294-1-git-send-email-ludovic.desroches@atmel.com> <1340467956-12422-1-git-send-email-ludovic.desroches@atmel.com> Message-ID: <4FE82324.4010609@atmel.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org On 06/23/2012 06:12 PM, ludovic.desroches at atmel.com : > From: Ludovic Desroches > > The number of lines of AIC5 has increased from 32 to 128. Due to this > increase, a source select register has been introduced for the interrupt > line selection. Moreover, register mapping has been changed. For that reasons, > we need some dedicated callbacks for AIC5. > Power management is also concerned by these changes. On suspend, we can't get > the whole interrupt mask register as before, we have to read this register 128 > times. To reduce this overhead, a snapshot of the whole IMR is maintained. > > Signed-off-by: Ludovic Desroches Acked-by: Nicolas Ferre > --- > arch/arm/mach-at91/generic.h | 2 + > arch/arm/mach-at91/include/mach/at91_aic.h | 26 ++ > arch/arm/mach-at91/irq.c | 343 +++++++++++++++++++++++----- > 3 files changed, 314 insertions(+), 57 deletions(-) > > diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h > index 0a60bf8..f496506 100644 > --- a/arch/arm/mach-at91/generic.h > +++ b/arch/arm/mach-at91/generic.h > @@ -29,6 +29,8 @@ extern void __init at91x40_init_interrupts(unsigned int priority[]); > extern void __init at91_aic_init(unsigned int priority[]); > extern int __init at91_aic_of_init(struct device_node *node, > struct device_node *parent); > +extern int __init at91_aic5_of_init(struct device_node *node, > + struct device_node *parent); > > > /* Timer */ > diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h > index fd42a85..eaea661 100644 > --- a/arch/arm/mach-at91/include/mach/at91_aic.h > +++ b/arch/arm/mach-at91/include/mach/at91_aic.h > @@ -30,11 +30,16 @@ extern void __iomem *at91_aic_base; > > /* Number of irq lines managed by AIC */ > #define NR_AIC_IRQS 32 > +#define NR_AIC5_IRQS 128 > + > +#define AT91_AIC5_SSR 0x0 /* Source Select Register [AIC5] */ > +#define AT91_AIC5_INTSEL_MSK (0x7f << 0) /* Interrupt Line Selection Mask */ > > #define AT91_AIC_IRQ_MIN_PRIORITY 0 > #define AT91_AIC_IRQ_MAX_PRIORITY 7 > > #define AT91_AIC_SMR(n) ((n) * 4) /* Source Mode Registers 0-31 */ > +#define AT91_AIC5_SMR 0x4 /* Source Mode Register [AIC5] */ > #define AT91_AIC_PRIOR (7 << 0) /* Priority Level */ > #define AT91_AIC_SRCTYPE (3 << 5) /* Interrupt Source Type */ > #define AT91_AIC_SRCTYPE_LOW (0 << 5) > @@ -43,31 +48,52 @@ extern void __iomem *at91_aic_base; > #define AT91_AIC_SRCTYPE_RISING (3 << 5) > > #define AT91_AIC_SVR(n) (0x80 + ((n) * 4)) /* Source Vector Registers 0-31 */ > +#define AT91_AIC5_SVR 0x8 /* Source Vector Register [AIC5] */ > #define AT91_AIC_IVR 0x100 /* Interrupt Vector Register */ > +#define AT91_AIC5_IVR 0x10 /* Interrupt Vector Register [AIC5] */ > #define AT91_AIC_FVR 0x104 /* Fast Interrupt Vector Register */ > +#define AT91_AIC5_FVR 0x14 /* Fast Interrupt Vector Register [AIC5] */ > #define AT91_AIC_ISR 0x108 /* Interrupt Status Register */ > +#define AT91_AIC5_ISR 0x18 /* Interrupt Status Register [AIC5] */ > #define AT91_AIC_IRQID (0x1f << 0) /* Current Interrupt Identifier */ > > #define AT91_AIC_IPR 0x10c /* Interrupt Pending Register */ > +#define AT91_AIC5_IPR0 0x20 /* Interrupt Pending Register 0 [AIC5] */ > +#define AT91_AIC5_IPR1 0x24 /* Interrupt Pending Register 1 [AIC5] */ > +#define AT91_AIC5_IPR2 0x28 /* Interrupt Pending Register 2 [AIC5] */ > +#define AT91_AIC5_IPR3 0x2c /* Interrupt Pending Register 3 [AIC5] */ > #define AT91_AIC_IMR 0x110 /* Interrupt Mask Register */ > +#define AT91_AIC5_IMR 0x30 /* Interrupt Mask Register [AIC5] */ > #define AT91_AIC_CISR 0x114 /* Core Interrupt Status Register */ > +#define AT91_AIC5_CISR 0x34 /* Core Interrupt Status Register [AIC5] */ > #define AT91_AIC_NFIQ (1 << 0) /* nFIQ Status */ > #define AT91_AIC_NIRQ (1 << 1) /* nIRQ Status */ > > #define AT91_AIC_IECR 0x120 /* Interrupt Enable Command Register */ > +#define AT91_AIC5_IECR 0x40 /* Interrupt Enable Command Register [AIC5] */ > #define AT91_AIC_IDCR 0x124 /* Interrupt Disable Command Register */ > +#define AT91_AIC5_IDCR 0x44 /* Interrupt Disable Command Register [AIC5] */ > #define AT91_AIC_ICCR 0x128 /* Interrupt Clear Command Register */ > +#define AT91_AIC5_ICCR 0x48 /* Interrupt Clear Command Register [AIC5] */ > #define AT91_AIC_ISCR 0x12c /* Interrupt Set Command Register */ > +#define AT91_AIC5_ISCR 0x4c /* Interrupt Set Command Register [AIC5] */ > #define AT91_AIC_EOICR 0x130 /* End of Interrupt Command Register */ > +#define AT91_AIC5_EOICR 0x38 /* End of Interrupt Command Register [AIC5] */ > #define AT91_AIC_SPU 0x134 /* Spurious Interrupt Vector Register */ > +#define AT91_AIC5_SPU 0x3c /* Spurious Interrupt Vector Register [AIC5] */ > #define AT91_AIC_DCR 0x138 /* Debug Control Register */ > +#define AT91_AIC5_DCR 0x6c /* Debug Control Register [AIC5] */ > #define AT91_AIC_DCR_PROT (1 << 0) /* Protection Mode */ > #define AT91_AIC_DCR_GMSK (1 << 1) /* General Mask */ > > #define AT91_AIC_FFER 0x140 /* Fast Forcing Enable Register [SAM9 only] */ > +#define AT91_AIC5_FFER 0x50 /* Fast Forcing Enable Register [AIC5] */ > #define AT91_AIC_FFDR 0x144 /* Fast Forcing Disable Register [SAM9 only] */ > +#define AT91_AIC5_FFDR 0x54 /* Fast Forcing Disable Register [AIC5] */ > #define AT91_AIC_FFSR 0x148 /* Fast Forcing Status Register [SAM9 only] */ > +#define AT91_AIC5_FFSR 0x58 /* Fast Forcing Status Register [AIC5] */ > > void at91_aic_handle_irq(struct pt_regs *regs); > +void at91_aic5_handle_irq(struct pt_regs *regs); > > #endif > diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c > index 89679a7..de0f677 100644 > --- a/arch/arm/mach-at91/irq.c > +++ b/arch/arm/mach-at91/irq.c > @@ -23,6 +23,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -46,9 +47,116 @@ > void __iomem *at91_aic_base; > static struct irq_domain *at91_aic_domain; > static struct device_node *at91_aic_np; > +static unsigned int n_irqs = NR_AIC_IRQS; > +static unsigned long at91_aic_caps = 0; > static unsigned int *at91_aic_irq_priorities; > > -asmlinkage void __exception_irq_entry at91_aic_handle_irq(struct pt_regs *regs) > +/* AIC5 introduces a Source Select Register */ > +#define AT91_AIC_CAP_AIC5 (1 << 0) > +#define has_aic5() (at91_aic_caps & AT91_AIC_CAP_AIC5) > + > +#ifdef CONFIG_PM > + > +static unsigned long *wakeups; > +static unsigned long *backups; > + > +#define set_backup(bit) set_bit(bit, backups) > +#define clear_backup(bit) clear_bit(bit, backups) > + > +static int at91_aic_pm_init(void) > +{ > + backups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL); > + if (!backups) > + return -ENOMEM; > + > + wakeups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL); > + if (!wakeups) { > + kfree(backups); > + return -ENOMEM; > + } > + > + return 0; > +} > + > +static int at91_aic_set_wake(struct irq_data *d, unsigned value) > +{ > + if (unlikely(d->hwirq >= n_irqs)) > + return -EINVAL; > + > + if (value) > + set_bit(d->hwirq, wakeups); > + else > + clear_bit(d->hwirq, wakeups); > + > + return 0; > +} > + > +void at91_irq_suspend(void) > +{ > + int i = 0, bit; > + > + if (has_aic5()) { > + /* disable enabled irqs */ > + while ((bit = find_next_bit(backups, n_irqs, i)) < n_irqs) { > + at91_aic_write(AT91_AIC5_SSR, > + bit & AT91_AIC5_INTSEL_MSK); > + at91_aic_write(AT91_AIC5_IDCR, 1); > + i = bit; > + } > + /* enable wakeup irqs */ > + i = 0; > + while ((bit = find_next_bit(wakeups, n_irqs, i)) < n_irqs) { > + at91_aic_write(AT91_AIC5_SSR, > + bit & AT91_AIC5_INTSEL_MSK); > + at91_aic_write(AT91_AIC5_IECR, 1); > + i = bit; > + } > + } else { > + at91_aic_write(AT91_AIC_IDCR, *backups); > + at91_aic_write(AT91_AIC_IECR, *wakeups); > + } > +} > + > +void at91_irq_resume(void) > +{ > + int i = 0, bit; > + > + if (has_aic5()) { > + /* disable wakeup irqs */ > + while ((bit = find_next_bit(wakeups, n_irqs, i)) < n_irqs) { > + at91_aic_write(AT91_AIC5_SSR, > + bit & AT91_AIC5_INTSEL_MSK); > + at91_aic_write(AT91_AIC5_IDCR, 1); > + i = bit; > + } > + /* enable irqs disabled for suspend */ > + i = 0; > + while ((bit = find_next_bit(backups, n_irqs, i)) < n_irqs) { > + at91_aic_write(AT91_AIC5_SSR, > + bit & AT91_AIC5_INTSEL_MSK); > + at91_aic_write(AT91_AIC5_IECR, 1); > + i = bit; > + } > + } else { > + at91_aic_write(AT91_AIC_IDCR, *wakeups); > + at91_aic_write(AT91_AIC_IECR, *backups); > + } > +} > + > +#else > +static inline int at91_aic_pm_init(void) > +{ > + return 0; > +} > + > +#define set_backup(bit) > +#define clear_backup(bit) > +#define at91_aic_set_wake NULL > + > +#endif /* CONFIG_PM */ > + > +asmlinkage void __exception_irq_entry > +at91_aic_handle_irq(struct pt_regs *regs) > { > u32 irqnr; > u32 irqstat; > @@ -66,16 +174,53 @@ asmlinkage void __exception_irq_entry at91_aic_handle_irq(struct pt_regs *regs) > handle_IRQ(irqnr, regs); > } > > +asmlinkage void __exception_irq_entry > +at91_aic5_handle_irq(struct pt_regs *regs) > +{ > + u32 irqnr; > + u32 irqstat; > + > + irqnr = at91_aic_read(AT91_AIC5_IVR); > + irqstat = at91_aic_read(AT91_AIC5_ISR); > + > + if (!irqstat) > + at91_aic_write(AT91_AIC5_EOICR, 0); > + else > + handle_IRQ(irqnr, regs); > +} > + > static void at91_aic_mask_irq(struct irq_data *d) > { > /* Disable interrupt on AIC */ > at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq); > + /* Update ISR cache */ > + clear_backup(d->hwirq); > +} > + > +static void __maybe_unused at91_aic5_mask_irq(struct irq_data *d) > +{ > + /* Disable interrupt on AIC5 */ > + at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK); > + at91_aic_write(AT91_AIC5_IDCR, 1); > + /* Update ISR cache */ > + clear_backup(d->hwirq); > } > > static void at91_aic_unmask_irq(struct irq_data *d) > { > /* Enable interrupt on AIC */ > at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq); > + /* Update ISR cache */ > + set_backup(d->hwirq); > +} > + > +static void __maybe_unused at91_aic5_unmask_irq(struct irq_data *d) > +{ > + /* Enable interrupt on AIC5 */ > + at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK); > + at91_aic_write(AT91_AIC5_IECR, 1); > + /* Update ISR cache */ > + set_backup(d->hwirq); > } > > static void at91_aic_eoi(struct irq_data *d) > @@ -87,13 +232,18 @@ static void at91_aic_eoi(struct irq_data *d) > at91_aic_write(AT91_AIC_EOICR, 0); > } > > -unsigned int at91_extern_irq; > +static void __maybe_unused at91_aic5_eoi(struct irq_data *d) > +{ > + at91_aic_write(AT91_AIC5_EOICR, 0); > +} > > -#define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq) > +unsigned long *at91_extern_irq; > > -static int at91_aic_set_type(struct irq_data *d, unsigned type) > +#define is_extern_irq(hwirq) test_bit(hwirq, at91_extern_irq) > + > +static int at91_aic_compute_srctype(struct irq_data *d, unsigned type) > { > - unsigned int smr, srctype; > + int srctype; > > switch (type) { > case IRQ_TYPE_LEVEL_HIGH: > @@ -106,58 +256,44 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type) > if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */ > srctype = AT91_AIC_SRCTYPE_LOW; > else > - return -EINVAL; > + srctype = -EINVAL; > break; > case IRQ_TYPE_EDGE_FALLING: > if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */ > srctype = AT91_AIC_SRCTYPE_FALLING; > else > - return -EINVAL; > + srctype = -EINVAL; > break; > default: > - return -EINVAL; > + srctype = -EINVAL; > } > > - smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) & ~AT91_AIC_SRCTYPE; > - at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype); > - return 0; > + return srctype; > } > > -#ifdef CONFIG_PM > - > -static u32 wakeups; > -static u32 backups; > - > -static int at91_aic_set_wake(struct irq_data *d, unsigned value) > +static int at91_aic_set_type(struct irq_data *d, unsigned type) > { > - if (unlikely(d->hwirq >= NR_AIC_IRQS)) > - return -EINVAL; > - > - if (value) > - wakeups |= (1 << d->hwirq); > - else > - wakeups &= ~(1 << d->hwirq); > + unsigned int smr; > + int srctype; > + > + srctype = at91_aic_compute_srctype(d, type); > + if (srctype < 0) > + return srctype; > + > + if (has_aic5()) { > + at91_aic_write(AT91_AIC5_SSR, > + d->hwirq & AT91_AIC5_INTSEL_MSK); > + smr = at91_aic_read(AT91_AIC5_SMR) & ~AT91_AIC_SRCTYPE; > + at91_aic_write(AT91_AIC5_SMR, smr | srctype); > + } else { > + smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) > + & ~AT91_AIC_SRCTYPE; > + at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype); > + } > > return 0; > } > > -void at91_irq_suspend(void) > -{ > - backups = at91_aic_read(AT91_AIC_IMR); > - at91_aic_write(AT91_AIC_IDCR, backups); > - at91_aic_write(AT91_AIC_IECR, wakeups); > -} > - > -void at91_irq_resume(void) > -{ > - at91_aic_write(AT91_AIC_IDCR, wakeups); > - at91_aic_write(AT91_AIC_IECR, backups); > -} > - > -#else > -#define at91_aic_set_wake NULL > -#endif > - > static struct irq_chip at91_aic_chip = { > .name = "AIC", > .irq_mask = at91_aic_mask_irq, > @@ -193,6 +329,35 @@ static void __init at91_aic_hw_init(unsigned int spu_vector) > at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF); > } > > +static void __init __maybe_unused at91_aic5_hw_init(unsigned int spu_vector) > +{ > + int i; > + > + /* > + * Perform 8 End Of Interrupt Command to make sure AIC > + * will not Lock out nIRQ > + */ > + for (i = 0; i < 8; i++) > + at91_aic_write(AT91_AIC5_EOICR, 0); > + > + /* > + * Spurious Interrupt ID in Spurious Vector Register. > + * When there is no current interrupt, the IRQ Vector Register > + * reads the value stored in AIC_SPU > + */ > + at91_aic_write(AT91_AIC5_SPU, spu_vector); > + > + /* No debugging in AIC: Debug (Protect) Control Register */ > + at91_aic_write(AT91_AIC5_DCR, 0); > + > + /* Disable and clear all interrupts initially */ > + for (i = 0; i < n_irqs; i++) { > + at91_aic_write(AT91_AIC5_SSR, i & AT91_AIC5_INTSEL_MSK); > + at91_aic_write(AT91_AIC5_IDCR, 1); > + at91_aic_write(AT91_AIC5_ICCR, 1); > + } > +} > + > #if defined(CONFIG_OF) > static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq, > irq_hw_number_t hw) > @@ -210,13 +375,31 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq, > return 0; > } > > +static int at91_aic5_irq_map(struct irq_domain *h, unsigned int virq, > + irq_hw_number_t hw) > +{ > + at91_aic_write(AT91_AIC5_SSR, hw & AT91_AIC5_INTSEL_MSK); > + > + /* Put virq number in Source Vector Register */ > + at91_aic_write(AT91_AIC5_SVR, virq); > + > + /* Active Low interrupt, with priority */ > + at91_aic_write(AT91_AIC5_SMR, > + AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities[hw]); > + > + irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq); > + set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); > + > + return 0; > +} > + > static int at91_aic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, > const u32 *intspec, unsigned int intsize, > irq_hw_number_t *out_hwirq, unsigned int *out_type) > { > if (WARN_ON(intsize < 3)) > return -EINVAL; > - if (WARN_ON(intspec[0] >= NR_AIC_IRQS)) > + if (WARN_ON(intspec[0] >= n_irqs)) > return -EINVAL; > if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY) > | (intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY))) > @@ -234,14 +417,24 @@ static struct irq_domain_ops at91_aic_irq_ops = { > .xlate = at91_aic_irq_domain_xlate, > }; > > -int __init at91_aic_of_init(struct device_node *node, > - struct device_node *parent) > +int __init at91_aic_of_common_init(struct device_node *node, > + struct device_node *parent) > { > struct property *prop; > const __be32 *p; > u32 val; > > - at91_aic_irq_priorities = kzalloc(NR_AIC_IRQS > + at91_extern_irq = kzalloc(BITS_TO_LONGS(n_irqs) > + * sizeof(*at91_extern_irq), GFP_KERNEL); > + if (!at91_extern_irq) > + return -ENOMEM; > + > + if (at91_aic_pm_init()) { > + kfree(at91_extern_irq); > + return -ENOMEM; > + } > + > + at91_aic_irq_priorities = kzalloc(n_irqs > * sizeof(*at91_aic_irq_priorities), > GFP_KERNEL); > if (!at91_aic_irq_priorities) > @@ -250,22 +443,56 @@ int __init at91_aic_of_init(struct device_node *node, > at91_aic_base = of_iomap(node, 0); > at91_aic_np = node; > > - at91_aic_domain = irq_domain_add_linear(at91_aic_np, NR_AIC_IRQS, > + at91_aic_domain = irq_domain_add_linear(at91_aic_np, n_irqs, > &at91_aic_irq_ops, NULL); > if (!at91_aic_domain) > panic("Unable to add AIC irq domain (DT)\n"); > > - at91_extern_irq = 0; > of_property_for_each_u32(node, "atmel,external-irqs", prop, p, val) { > - if (val > 31) > - pr_warn("AIC: external irq %d > 31 skip it\n", val); > + if (val >= n_irqs) > + pr_warn("AIC: external irq %d >= %d skip it\n", > + val, n_irqs); > else > - at91_extern_irq |= (1 << val); > + set_bit(val, at91_extern_irq); > } > > irq_set_default_host(at91_aic_domain); > > - at91_aic_hw_init(NR_AIC_IRQS); > + return 0; > +} > + > +int __init at91_aic_of_init(struct device_node *node, > + struct device_node *parent) > +{ > + int err; > + > + err = at91_aic_of_common_init(node, parent); > + if (err) > + return err; > + > + at91_aic_hw_init(n_irqs); > + > + return 0; > +} > + > +int __init at91_aic5_of_init(struct device_node *node, > + struct device_node *parent) > +{ > + int err; > + > + at91_aic_caps |= AT91_AIC_CAP_AIC5; > + n_irqs = NR_AIC5_IRQS; > + at91_aic_chip.irq_ack = at91_aic5_mask_irq; > + at91_aic_chip.irq_mask = at91_aic5_mask_irq; > + at91_aic_chip.irq_unmask = at91_aic5_unmask_irq; > + at91_aic_chip.irq_eoi = at91_aic5_eoi; > + at91_aic_irq_ops.map = at91_aic5_irq_map; > + > + err = at91_aic_of_common_init(node, parent); > + if (err) > + return err; > + > + at91_aic5_hw_init(n_irqs); > > return 0; > } > @@ -274,22 +501,25 @@ int __init at91_aic_of_init(struct device_node *node, > /* > * Initialize the AIC interrupt controller. > */ > -void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS]) > +void __init at91_aic_init(unsigned int *priority) > { > unsigned int i; > int irq_base; > > + if (at91_aic_pm_init()) > + panic("Unable to allocate bit maps\n"); > + > at91_aic_base = ioremap(AT91_AIC, 512); > if (!at91_aic_base) > panic("Unable to ioremap AIC registers\n"); > > /* Add irq domain for AIC */ > - irq_base = irq_alloc_descs(-1, 0, NR_AIC_IRQS, 0); > + irq_base = irq_alloc_descs(-1, 0, n_irqs, 0); > if (irq_base < 0) { > WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n"); > irq_base = 0; > } > - at91_aic_domain = irq_domain_add_legacy(at91_aic_np, NR_AIC_IRQS, > + at91_aic_domain = irq_domain_add_legacy(at91_aic_np, n_irqs, > irq_base, 0, > &irq_domain_simple_ops, NULL); > > @@ -302,15 +532,14 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS]) > * The IVR is used by macro get_irqnr_and_base to read and verify. > * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred. > */ > - for (i = 0; i < NR_AIC_IRQS; i++) { > + for (i = 0; i < n_irqs; i++) { > /* Put hardware irq number in Source Vector Register: */ > at91_aic_write(AT91_AIC_SVR(i), NR_IRQS_LEGACY + i); > /* Active Low interrupt, with the specified priority */ > at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]); > - > irq_set_chip_and_handler(NR_IRQS_LEGACY + i, &at91_aic_chip, handle_fasteoi_irq); > set_irq_flags(i, IRQF_VALID | IRQF_PROBE); > } > > - at91_aic_hw_init(NR_AIC_IRQS); > + at91_aic_hw_init(n_irqs); > } > -- Nicolas Ferre