2014-10-22 12:26 GMT+04:00 John Crispin <blogic@xxxxxxxxxxx>: > 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. I would like add code as-is, and then update it to use irq_domain. But seems that everybody likes the irq_domain and this work should be done now. > look at arch/mips/ralink/irq.c > Thank you for example! > >> 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) >> -- BR, Sergey