few comments inline .... On 22/10/2014 01:03, Sergey Ryazanov wrote: > Add interrupts initialization and handling routines, also add AHB bus > error interrupt handlers for both SoCs families. > > Signed-off-by: Sergey Ryazanov <ryazanov.s.a@xxxxxxxxx> > --- > > Changes since RFC: > - add all interrupts > - use dynamic IRQ numbers allocation > > Changes since v1: > - rename MIPS machine ar231x -> ath25 > > arch/mips/ath25/ar2315.c | 108 +++++++++++++++++++++++++ > arch/mips/ath25/ar2315.h | 2 + > arch/mips/ath25/ar5312.c | 103 +++++++++++++++++++++++ > arch/mips/ath25/ar5312.h | 2 + > arch/mips/ath25/board.c | 10 +++ > arch/mips/ath25/devices.h | 2 + > arch/mips/include/asm/mach-ath25/ar2315_regs.h | 23 ++++++ > arch/mips/include/asm/mach-ath25/ar5312_regs.h | 23 ++++++ > arch/mips/include/asm/mach-ath25/ath25.h | 2 + > 9 files changed, 275 insertions(+) > > diff --git a/arch/mips/ath25/ar2315.c b/arch/mips/ath25/ar2315.c > index 4eee362..e1a338b 100644 > --- a/arch/mips/ath25/ar2315.c > +++ b/arch/mips/ath25/ar2315.c > @@ -27,6 +27,114 @@ > #include "devices.h" > #include "ar2315.h" > > +static unsigned ar2315_misc_irq_base; > + > +static irqreturn_t ar2315_ahb_err_handler(int cpl, void *dev_id) > +{ > + ath25_write_reg(AR2315_AHB_ERR0, AR2315_AHB_ERROR_DET); > + ath25_read_reg(AR2315_AHB_ERR1); > + > + pr_emerg("AHB fatal error\n"); > + machine_restart("AHB error"); /* Catastrophic failure */ > + > + return IRQ_HANDLED; > +} > + > +static struct irqaction ar2315_ahb_err_interrupt = { > + .handler = ar2315_ahb_err_handler, > + .name = "ar2315-ahb-error", > +}; > + > +static void ar2315_misc_irq_handler(unsigned irq, struct irq_desc *desc) > +{ > + u32 pending = ath25_read_reg(AR2315_ISR) & ath25_read_reg(AR2315_IMR); > + unsigned base = ar2315_misc_irq_base; > + > + if (pending & AR2315_ISR_SPI) > + generic_handle_irq(base + AR2315_MISC_IRQ_SPI); > + else if (pending & AR2315_ISR_TIMER) > + generic_handle_irq(base + AR2315_MISC_IRQ_TIMER); > + else if (pending & AR2315_ISR_AHB) > + generic_handle_irq(base + AR2315_MISC_IRQ_AHB); > + else if (pending & AR2315_ISR_GPIO) { > + ath25_write_reg(AR2315_ISR, AR2315_ISR_GPIO); > + generic_handle_irq(base + AR2315_MISC_IRQ_GPIO); > + } else if (pending & AR2315_ISR_UART0) > + generic_handle_irq(base + AR2315_MISC_IRQ_UART0); > + else if (pending & AR2315_ISR_WD) { > + ath25_write_reg(AR2315_ISR, AR2315_ISR_WD); > + generic_handle_irq(base + AR2315_MISC_IRQ_WATCHDOG); > + } else > + spurious_interrupt(); > +} > + > +static void ar2315_misc_irq_unmask(struct irq_data *d) > +{ > + u32 imr = ath25_read_reg(AR2315_IMR); > + > + imr |= 1 << (d->irq - ar2315_misc_irq_base); > + ath25_write_reg(AR2315_IMR, imr); > +} > + > +static void ar2315_misc_irq_mask(struct irq_data *d) > +{ > + u32 imr = ath25_read_reg(AR2315_IMR); > + > + imr &= ~(1 << (d->irq - ar2315_misc_irq_base)); > + ath25_write_reg(AR2315_IMR, imr); > +} > + > +static struct irq_chip ar2315_misc_irq_chip = { > + .name = "ar2315-misc", > + .irq_unmask = ar2315_misc_irq_unmask, > + .irq_mask = ar2315_misc_irq_mask, > +}; > + > +/* > + * Called when an interrupt is received, this function > + * determines exactly which interrupt it was, and it > + * invokes the appropriate handler. > + * > + * Implicitly, we also define interrupt priority by > + * choosing which to dispatch first. > + */ > +static void ar2315_irq_dispatch(void) > +{ > + u32 pending = read_c0_status() & read_c0_cause(); > + > + if (pending & CAUSEF_IP3) > + do_IRQ(AR2315_IRQ_WLAN0); > + else if (pending & CAUSEF_IP2) > + do_IRQ(AR2315_IRQ_MISC); > + else if (pending & CAUSEF_IP7) > + do_IRQ(ATH25_IRQ_CPU_CLOCK); > + else > + spurious_interrupt(); > +} > + > +void __init ar2315_arch_init_irq(void) > +{ > + unsigned i; > + int res; > + > + ath25_irq_dispatch = ar2315_irq_dispatch; > + > + res = irq_alloc_descs(-1, 0, AR2315_MISC_IRQ_COUNT, 0); > + if (res < 0) > + pr_emerg("Failed to allocate misc IRQ numbers\n"); > + ar2315_misc_irq_base = res; > + > + for (i = 0; i < AR2315_MISC_IRQ_COUNT; i++) { > + unsigned irq = ar2315_misc_irq_base + i; > + > + irq_set_chip_and_handler(irq, &ar2315_misc_irq_chip, > + handle_level_irq); > + } > + setup_irq(ar2315_misc_irq_base + AR2315_MISC_IRQ_AHB, > + &ar2315_ahb_err_interrupt); > + irq_set_chained_handler(AR2315_IRQ_MISC, ar2315_misc_irq_handler); > +} > + you should use irq_doamin here with a xlate function. this is just a 3 liner. look at arch/mips/ralink/irq.c > static void ar2315_restart(char *command) > { > void (*mips_reset_vec)(void) = (void *)0xbfc00000; > diff --git a/arch/mips/ath25/ar2315.h b/arch/mips/ath25/ar2315.h > index 98d32b2..2a57858 100644 > --- a/arch/mips/ath25/ar2315.h > +++ b/arch/mips/ath25/ar2315.h > @@ -3,12 +3,14 @@ > > #ifdef CONFIG_SOC_AR2315 > > +void ar2315_arch_init_irq(void); > void ar2315_plat_time_init(void); > void ar2315_plat_mem_setup(void); > void ar2315_prom_init(void); > > #else > > +static inline void ar2315_arch_init_irq(void) {} > static inline void ar2315_plat_time_init(void) {} > static inline void ar2315_plat_mem_setup(void) {} > static inline void ar2315_prom_init(void) {} > diff --git a/arch/mips/ath25/ar5312.c b/arch/mips/ath25/ar5312.c > index 80d7ed7..e9c7f71 100644 > --- a/arch/mips/ath25/ar5312.c > +++ b/arch/mips/ath25/ar5312.c > @@ -27,6 +27,109 @@ > #include "devices.h" > #include "ar5312.h" > > +static unsigned ar5312_misc_irq_base; > + > +static irqreturn_t ar5312_ahb_err_handler(int cpl, void *dev_id) > +{ > + u32 proc1 = ath25_read_reg(AR5312_PROC1); > + u32 proc_addr = ath25_read_reg(AR5312_PROCADDR); /* clears error */ > + u32 dma1 = ath25_read_reg(AR5312_DMA1); > + u32 dma_addr = ath25_read_reg(AR5312_DMAADDR); /* clears error */ > + > + pr_emerg("AHB interrupt: PROCADDR=0x%8.8x PROC1=0x%8.8x DMAADDR=0x%8.8x DMA1=0x%8.8x\n", > + proc_addr, proc1, dma_addr, dma1); > + > + machine_restart("AHB error"); /* Catastrophic failure */ > + return IRQ_HANDLED; > +} > + > +static struct irqaction ar5312_ahb_err_interrupt = { > + .handler = ar5312_ahb_err_handler, > + .name = "ar5312-ahb-error", > +}; > + > +static void ar5312_misc_irq_handler(unsigned irq, struct irq_desc *desc) > +{ > + u32 pending = ath25_read_reg(AR5312_ISR) & ath25_read_reg(AR5312_IMR); > + unsigned base = ar5312_misc_irq_base; > + > + if (pending & AR5312_ISR_TIMER) { > + generic_handle_irq(base + AR5312_MISC_IRQ_TIMER); > + (void)ath25_read_reg(AR5312_TIMER); > + } else if (pending & AR5312_ISR_AHBPROC) > + generic_handle_irq(base + AR5312_MISC_IRQ_AHB_PROC); > + else if (pending & AR5312_ISR_UART0) > + generic_handle_irq(base + AR5312_MISC_IRQ_UART0); > + else if (pending & AR5312_ISR_WD) > + generic_handle_irq(base + AR5312_MISC_IRQ_WATCHDOG); > + else > + spurious_interrupt(); > +} > + > +/* Enable the specified AR5312_MISC_IRQ interrupt */ > +static void ar5312_misc_irq_unmask(struct irq_data *d) > +{ > + u32 imr = ath25_read_reg(AR5312_IMR); > + > + imr |= 1 << (d->irq - ar5312_misc_irq_base); > + ath25_write_reg(AR5312_IMR, imr); > +} > + > +/* Disable the specified AR5312_MISC_IRQ interrupt */ > +static void ar5312_misc_irq_mask(struct irq_data *d) > +{ > + u32 imr = ath25_read_reg(AR5312_IMR); > + > + imr &= ~(1 << (d->irq - ar5312_misc_irq_base)); > + ath25_write_reg(AR5312_IMR, imr); > + ath25_read_reg(AR5312_IMR); /* flush write buffer */ > +} > + > +static struct irq_chip ar5312_misc_irq_chip = { > + .name = "ar5312-misc", > + .irq_unmask = ar5312_misc_irq_unmask, > + .irq_mask = ar5312_misc_irq_mask, > +}; > + > +static void ar5312_irq_dispatch(void) > +{ > + u32 pending = read_c0_status() & read_c0_cause(); > + > + if (pending & CAUSEF_IP2) > + do_IRQ(AR5312_IRQ_WLAN0); > + else if (pending & CAUSEF_IP5) > + do_IRQ(AR5312_IRQ_WLAN1); > + else if (pending & CAUSEF_IP6) > + do_IRQ(AR5312_IRQ_MISC); > + else if (pending & CAUSEF_IP7) > + do_IRQ(ATH25_IRQ_CPU_CLOCK); > + else > + spurious_interrupt(); > +} > + > +void __init ar5312_arch_init_irq(void) > +{ > + unsigned i; > + int res; > + > + ath25_irq_dispatch = ar5312_irq_dispatch; > + > + res = irq_alloc_descs(-1, 0, AR5312_MISC_IRQ_COUNT, 0); > + if (res < 0) > + pr_emerg("Failed to allocate misc IRQ numbers\n"); > + ar5312_misc_irq_base = res; > + > + for (i = 0; i < AR5312_MISC_IRQ_COUNT; i++) { > + unsigned irq = ar5312_misc_irq_base + i; > + > + irq_set_chip_and_handler(irq, &ar5312_misc_irq_chip, > + handle_level_irq); > + } > + setup_irq(ar5312_misc_irq_base + AR5312_MISC_IRQ_AHB_PROC, > + &ar5312_ahb_err_interrupt); > + irq_set_chained_handler(AR5312_IRQ_MISC, ar5312_misc_irq_handler); > +} same here, irq_domain is the current best practice > + > static void ar5312_restart(char *command) > { > /* reset the system */ > diff --git a/arch/mips/ath25/ar5312.h b/arch/mips/ath25/ar5312.h > index 339b28e..b60ad38 100644 > --- a/arch/mips/ath25/ar5312.h > +++ b/arch/mips/ath25/ar5312.h > @@ -3,12 +3,14 @@ > > #ifdef CONFIG_SOC_AR5312 > > +void ar5312_arch_init_irq(void); > void ar5312_plat_time_init(void); > void ar5312_plat_mem_setup(void); > void ar5312_prom_init(void); > > #else > > +static inline void ar5312_arch_init_irq(void) {} > static inline void ar5312_plat_time_init(void) {} > static inline void ar5312_plat_mem_setup(void) {} > static inline void ar5312_prom_init(void) {} > diff --git a/arch/mips/ath25/board.c b/arch/mips/ath25/board.c > index a6b8c26..68447d3 100644 > --- a/arch/mips/ath25/board.c > +++ b/arch/mips/ath25/board.c > @@ -16,9 +16,12 @@ > #include <asm/bootinfo.h> > #include <asm/time.h> > > +#include "devices.h" > #include "ar5312.h" > #include "ar2315.h" > > +void (*ath25_irq_dispatch)(void); > + > static void ath25_halt(void) > { > local_irq_disable(); > @@ -42,6 +45,7 @@ void __init plat_mem_setup(void) > > asmlinkage void plat_irq_dispatch(void) > { > + ath25_irq_dispatch(); > } > > void __init plat_time_init(void) > @@ -61,5 +65,11 @@ void __init arch_init_irq(void) > { > clear_c0_status(ST0_IM); > mips_cpu_irq_init(); > + > + /* Initialize interrupt controllers */ > + if (is_ar5312()) > + ar5312_arch_init_irq(); > + else > + ar2315_arch_init_irq(); > } > > diff --git a/arch/mips/ath25/devices.h b/arch/mips/ath25/devices.h > index edda636..bbf2988 100644 > --- a/arch/mips/ath25/devices.h > +++ b/arch/mips/ath25/devices.h > @@ -3,6 +3,8 @@ > > #include <linux/cpu.h> > > +extern void (*ath25_irq_dispatch)(void); > + > static inline bool is_ar2315(void) > { > return (current_cpu_data.cputype == CPU_4KEC); > diff --git a/arch/mips/include/asm/mach-ath25/ar2315_regs.h b/arch/mips/include/asm/mach-ath25/ar2315_regs.h > index ff9a4a8..e680abc 100644 > --- a/arch/mips/include/asm/mach-ath25/ar2315_regs.h > +++ b/arch/mips/include/asm/mach-ath25/ar2315_regs.h > @@ -15,6 +15,29 @@ > #define __ASM_MACH_ATH25_AR2315_REGS_H > > /* > + * IRQs > + */ > +#define AR2315_IRQ_MISC (MIPS_CPU_IRQ_BASE + 2) /* C0_CAUSE: 0x0400 */ > +#define AR2315_IRQ_WLAN0 (MIPS_CPU_IRQ_BASE + 3) /* C0_CAUSE: 0x0800 */ > +#define AR2315_IRQ_ENET0 (MIPS_CPU_IRQ_BASE + 4) /* C0_CAUSE: 0x1000 */ > +#define AR2315_IRQ_LCBUS_PCI (MIPS_CPU_IRQ_BASE + 5) /* C0_CAUSE: 0x2000 */ > +#define AR2315_IRQ_WLAN0_POLL (MIPS_CPU_IRQ_BASE + 6) /* C0_CAUSE: 0x4000 */ > + > +/* > + * Miscellaneous interrupts, which share IP2. > + */ > +#define AR2315_MISC_IRQ_UART0 0 > +#define AR2315_MISC_IRQ_I2C_RSVD 1 > +#define AR2315_MISC_IRQ_SPI 2 > +#define AR2315_MISC_IRQ_AHB 3 > +#define AR2315_MISC_IRQ_APB 4 > +#define AR2315_MISC_IRQ_TIMER 5 > +#define AR2315_MISC_IRQ_GPIO 6 > +#define AR2315_MISC_IRQ_WATCHDOG 7 > +#define AR2315_MISC_IRQ_IR_RSVD 8 > +#define AR2315_MISC_IRQ_COUNT 9 > + > +/* > * Address map > */ > #define AR2315_SPI_READ 0x08000000 /* SPI flash */ > diff --git a/arch/mips/include/asm/mach-ath25/ar5312_regs.h b/arch/mips/include/asm/mach-ath25/ar5312_regs.h > index 76856d8..afcd0b2 100644 > --- a/arch/mips/include/asm/mach-ath25/ar5312_regs.h > +++ b/arch/mips/include/asm/mach-ath25/ar5312_regs.h > @@ -12,6 +12,29 @@ > #define __ASM_MACH_ATH25_AR5312_REGS_H > > /* > + * IRQs > + */ > +#define AR5312_IRQ_WLAN0 (MIPS_CPU_IRQ_BASE + 2) /* C0_CAUSE: 0x0400 */ > +#define AR5312_IRQ_ENET0 (MIPS_CPU_IRQ_BASE + 3) /* C0_CAUSE: 0x0800 */ > +#define AR5312_IRQ_ENET1 (MIPS_CPU_IRQ_BASE + 4) /* C0_CAUSE: 0x1000 */ > +#define AR5312_IRQ_WLAN1 (MIPS_CPU_IRQ_BASE + 5) /* C0_CAUSE: 0x2000 */ > +#define AR5312_IRQ_MISC (MIPS_CPU_IRQ_BASE + 6) /* C0_CAUSE: 0x4000 */ > + > +/* > + * Miscellaneous interrupts, which share IP6. > + */ > +#define AR5312_MISC_IRQ_TIMER 0 > +#define AR5312_MISC_IRQ_AHB_PROC 1 > +#define AR5312_MISC_IRQ_AHB_DMA 2 > +#define AR5312_MISC_IRQ_GPIO 3 > +#define AR5312_MISC_IRQ_UART0 4 > +#define AR5312_MISC_IRQ_UART0_DMA 5 > +#define AR5312_MISC_IRQ_WATCHDOG 6 > +#define AR5312_MISC_IRQ_LOCAL 7 > +#define AR5312_MISC_IRQ_SPI 8 > +#define AR5312_MISC_IRQ_COUNT 9 > + > +/* > * Address Map > * > * The AR5312 supports 2 enet MACS, even though many reference boards only > diff --git a/arch/mips/include/asm/mach-ath25/ath25.h b/arch/mips/include/asm/mach-ath25/ath25.h > index bd66ce7..caf0794 100644 > --- a/arch/mips/include/asm/mach-ath25/ath25.h > +++ b/arch/mips/include/asm/mach-ath25/ath25.h > @@ -3,6 +3,8 @@ > > #include <linux/io.h> > > +#define ATH25_IRQ_CPU_CLOCK (MIPS_CPU_IRQ_BASE + 7) /* C0_CAUSE: 0x8000 */ > + > #define ATH25_REG_MS(_val, _field) (((_val) & _field##_M) >> _field##_S) > > static inline u32 ath25_read_reg(u32 reg) >