diff options
| -rw-r--r-- | arch/frv/Kconfig | 8 | ||||
| -rw-r--r-- | arch/frv/kernel/Makefile | 5 | ||||
| -rw-r--r-- | arch/frv/kernel/irq-mb93091.c | 157 | ||||
| -rw-r--r-- | arch/frv/kernel/irq-mb93093.c | 115 | ||||
| -rw-r--r-- | arch/frv/kernel/irq-mb93493.c | 167 | ||||
| -rw-r--r-- | arch/frv/kernel/irq-routing.c | 291 | ||||
| -rw-r--r-- | arch/frv/kernel/irq.c | 750 | ||||
| -rw-r--r-- | arch/frv/kernel/setup.c | 1 | ||||
| -rw-r--r-- | arch/frv/kernel/time.c | 1 | ||||
| -rw-r--r-- | arch/frv/mb93090-mb00/pci-irq.c | 1 | ||||
| -rw-r--r-- | include/asm-frv/cpu-irqs.h | 54 | ||||
| -rw-r--r-- | include/asm-frv/hardirq.h | 5 | ||||
| -rw-r--r-- | include/asm-frv/irq-routing.h | 70 | ||||
| -rw-r--r-- | include/asm-frv/irq.h | 26 | ||||
| -rw-r--r-- | include/asm-frv/mb93091-fpga-irqs.h | 6 | ||||
| -rw-r--r-- | include/asm-frv/mb93093-fpga-irqs.h | 6 | ||||
| -rw-r--r-- | include/asm-frv/mb93493-irqs.h | 6 | ||||
| -rw-r--r-- | include/asm-frv/mb93493-regs.h | 2 |
18 files changed, 450 insertions, 1221 deletions
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig index a601a17cf568..5833808fb823 100644 --- a/arch/frv/Kconfig +++ b/arch/frv/Kconfig | |||
| @@ -27,7 +27,7 @@ config GENERIC_CALIBRATE_DELAY | |||
| 27 | 27 | ||
| 28 | config GENERIC_HARDIRQS | 28 | config GENERIC_HARDIRQS |
| 29 | bool | 29 | bool |
| 30 | default n | 30 | default y |
| 31 | 31 | ||
| 32 | config GENERIC_TIME | 32 | config GENERIC_TIME |
| 33 | bool | 33 | bool |
| @@ -251,6 +251,12 @@ config MB93091_NO_MB | |||
| 251 | endchoice | 251 | endchoice |
| 252 | endif | 252 | endif |
| 253 | 253 | ||
| 254 | config FUJITSU_MB93493 | ||
| 255 | bool "MB93493 Multimedia chip" | ||
| 256 | help | ||
| 257 | Select this option if the MB93493 multimedia chip is going to be | ||
| 258 | used. | ||
| 259 | |||
| 254 | choice | 260 | choice |
| 255 | prompt "GP-Relative data support" | 261 | prompt "GP-Relative data support" |
| 256 | default GPREL_DATA_8 | 262 | default GPREL_DATA_8 |
diff --git a/arch/frv/kernel/Makefile b/arch/frv/kernel/Makefile index 5a827b349b5e..32db3499c461 100644 --- a/arch/frv/kernel/Makefile +++ b/arch/frv/kernel/Makefile | |||
| @@ -10,15 +10,14 @@ extra-y:= head.o init_task.o vmlinux.lds | |||
| 10 | obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o kernel_thread.o \ | 10 | obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o kernel_thread.o \ |
| 11 | process.o traps.o ptrace.o signal.o dma.o \ | 11 | process.o traps.o ptrace.o signal.o dma.o \ |
| 12 | sys_frv.o time.o semaphore.o setup.o frv_ksyms.o \ | 12 | sys_frv.o time.o semaphore.o setup.o frv_ksyms.o \ |
| 13 | debug-stub.o irq.o irq-routing.o sleep.o uaccess.o | 13 | debug-stub.o irq.o sleep.o uaccess.o |
| 14 | 14 | ||
| 15 | obj-$(CONFIG_GDBSTUB) += gdb-stub.o gdb-io.o | 15 | obj-$(CONFIG_GDBSTUB) += gdb-stub.o gdb-io.o |
| 16 | 16 | ||
| 17 | obj-$(CONFIG_MB93091_VDK) += irq-mb93091.o | 17 | obj-$(CONFIG_MB93091_VDK) += irq-mb93091.o |
| 18 | obj-$(CONFIG_MB93093_PDK) += irq-mb93093.o | ||
| 19 | obj-$(CONFIG_FUJITSU_MB93493) += irq-mb93493.o | ||
| 20 | obj-$(CONFIG_PM) += pm.o cmode.o | 18 | obj-$(CONFIG_PM) += pm.o cmode.o |
| 21 | obj-$(CONFIG_MB93093_PDK) += pm-mb93093.o | 19 | obj-$(CONFIG_MB93093_PDK) += pm-mb93093.o |
| 20 | obj-$(CONFIG_FUJITSU_MB93493) += irq-mb93493.o | ||
| 22 | obj-$(CONFIG_SYSCTL) += sysctl.o | 21 | obj-$(CONFIG_SYSCTL) += sysctl.o |
| 23 | obj-$(CONFIG_FUTEX) += futex.o | 22 | obj-$(CONFIG_FUTEX) += futex.o |
| 24 | obj-$(CONFIG_MODULES) += module.o | 23 | obj-$(CONFIG_MODULES) += module.o |
diff --git a/arch/frv/kernel/irq-mb93091.c b/arch/frv/kernel/irq-mb93091.c index 1381abcd5cc9..635d23437666 100644 --- a/arch/frv/kernel/irq-mb93091.c +++ b/arch/frv/kernel/irq-mb93091.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | #include <asm/delay.h> | 24 | #include <asm/delay.h> |
| 25 | #include <asm/irq.h> | 25 | #include <asm/irq.h> |
| 26 | #include <asm/irc-regs.h> | 26 | #include <asm/irc-regs.h> |
| 27 | #include <asm/irq-routing.h> | ||
| 28 | 27 | ||
| 29 | #define __reg16(ADDR) (*(volatile unsigned short *)(ADDR)) | 28 | #define __reg16(ADDR) (*(volatile unsigned short *)(ADDR)) |
| 30 | 29 | ||
| @@ -33,83 +32,129 @@ | |||
| 33 | #define __get_IFR() ({ __reg16(0xffc0000c); }) | 32 | #define __get_IFR() ({ __reg16(0xffc0000c); }) |
| 34 | #define __clr_IFR(M) do { __reg16(0xffc0000c) = ~(M); wmb(); } while(0) | 33 | #define __clr_IFR(M) do { __reg16(0xffc0000c) = ~(M); wmb(); } while(0) |
| 35 | 34 | ||
| 36 | static void frv_fpga_doirq(struct irq_source *source); | ||
| 37 | static void frv_fpga_control(struct irq_group *group, int irq, int on); | ||
| 38 | 35 | ||
| 39 | /*****************************************************************************/ | ||
| 40 | /* | 36 | /* |
| 41 | * FPGA IRQ multiplexor | 37 | * on-motherboard FPGA PIC operations |
| 42 | */ | 38 | */ |
| 43 | static struct irq_source frv_fpga[4] = { | 39 | static void frv_fpga_enable(unsigned int irq) |
| 44 | #define __FPGA(X, M) \ | 40 | { |
| 45 | [X] = { \ | 41 | uint16_t imr = __get_IMR(); |
| 46 | .muxname = "fpga."#X, \ | ||
| 47 | .irqmask = M, \ | ||
| 48 | .doirq = frv_fpga_doirq, \ | ||
| 49 | } | ||
| 50 | 42 | ||
| 51 | __FPGA(0, 0x0028), | 43 | imr &= ~(1 << (irq - IRQ_BASE_FPGA)); |
| 52 | __FPGA(1, 0x0050), | ||
| 53 | __FPGA(2, 0x1c00), | ||
| 54 | __FPGA(3, 0x6386), | ||
| 55 | }; | ||
| 56 | |||
| 57 | static struct irq_group frv_fpga_irqs = { | ||
| 58 | .first_irq = IRQ_BASE_FPGA, | ||
| 59 | .control = frv_fpga_control, | ||
| 60 | .sources = { | ||
| 61 | [ 1] = &frv_fpga[3], | ||
| 62 | [ 2] = &frv_fpga[3], | ||
| 63 | [ 3] = &frv_fpga[0], | ||
| 64 | [ 4] = &frv_fpga[1], | ||
| 65 | [ 5] = &frv_fpga[0], | ||
| 66 | [ 6] = &frv_fpga[1], | ||
| 67 | [ 7] = &frv_fpga[3], | ||
| 68 | [ 8] = &frv_fpga[3], | ||
| 69 | [ 9] = &frv_fpga[3], | ||
| 70 | [10] = &frv_fpga[2], | ||
| 71 | [11] = &frv_fpga[2], | ||
| 72 | [12] = &frv_fpga[2], | ||
| 73 | [13] = &frv_fpga[3], | ||
| 74 | [14] = &frv_fpga[3], | ||
| 75 | }, | ||
| 76 | }; | ||
| 77 | 44 | ||
| 45 | __set_IMR(imr); | ||
| 46 | } | ||
| 78 | 47 | ||
| 79 | static void frv_fpga_control(struct irq_group *group, int index, int on) | 48 | static void frv_fpga_disable(unsigned int irq) |
| 80 | { | 49 | { |
| 81 | uint16_t imr = __get_IMR(); | 50 | uint16_t imr = __get_IMR(); |
| 82 | 51 | ||
| 83 | if (on) | 52 | imr |= 1 << (irq - IRQ_BASE_FPGA); |
| 84 | imr &= ~(1 << index); | ||
| 85 | else | ||
| 86 | imr |= 1 << index; | ||
| 87 | 53 | ||
| 88 | __set_IMR(imr); | 54 | __set_IMR(imr); |
| 89 | } | 55 | } |
| 90 | 56 | ||
| 91 | static void frv_fpga_doirq(struct irq_source *source) | 57 | static void frv_fpga_ack(unsigned int irq) |
| 58 | { | ||
| 59 | __clr_IFR(1 << (irq - IRQ_BASE_FPGA)); | ||
| 60 | } | ||
| 61 | |||
| 62 | static void frv_fpga_end(unsigned int irq) | ||
| 63 | { | ||
| 64 | } | ||
| 65 | |||
| 66 | static struct irq_chip frv_fpga_pic = { | ||
| 67 | .name = "mb93091", | ||
| 68 | .enable = frv_fpga_enable, | ||
| 69 | .disable = frv_fpga_disable, | ||
| 70 | .ack = frv_fpga_ack, | ||
| 71 | .mask = frv_fpga_disable, | ||
| 72 | .unmask = frv_fpga_enable, | ||
| 73 | .end = frv_fpga_end, | ||
| 74 | }; | ||
| 75 | |||
| 76 | /* | ||
| 77 | * FPGA PIC interrupt handler | ||
| 78 | */ | ||
| 79 | static irqreturn_t fpga_interrupt(int irq, void *_mask, struct pt_regs *regs) | ||
| 92 | { | 80 | { |
| 93 | uint16_t mask, imr; | 81 | uint16_t imr, mask = (unsigned long) _mask; |
| 82 | irqreturn_t iret = 0; | ||
| 94 | 83 | ||
| 95 | imr = __get_IMR(); | 84 | imr = __get_IMR(); |
| 96 | mask = source->irqmask & ~imr & __get_IFR(); | 85 | mask = mask & ~imr & __get_IFR(); |
| 97 | if (mask) { | 86 | |
| 98 | __set_IMR(imr | mask); | 87 | /* poll all the triggered IRQs */ |
| 99 | __clr_IFR(mask); | 88 | while (mask) { |
| 100 | distribute_irqs(&frv_fpga_irqs, mask); | 89 | int irq; |
| 101 | __set_IMR(imr); | 90 | |
| 91 | asm("scan %1,gr0,%0" : "=r"(irq) : "r"(mask)); | ||
| 92 | irq = 31 - irq; | ||
| 93 | mask &= ~(1 << irq); | ||
| 94 | |||
| 95 | if (__do_IRQ(IRQ_BASE_FPGA + irq, regs)) | ||
| 96 | iret |= IRQ_HANDLED; | ||
| 102 | } | 97 | } |
| 98 | |||
| 99 | return iret; | ||
| 103 | } | 100 | } |
| 104 | 101 | ||
| 102 | /* | ||
| 103 | * define an interrupt action for each FPGA PIC output | ||
| 104 | * - use dev_id to indicate the FPGA PIC input to output mappings | ||
| 105 | */ | ||
| 106 | static struct irqaction fpga_irq[4] = { | ||
| 107 | [0] = { | ||
| 108 | .handler = fpga_interrupt, | ||
| 109 | .flags = IRQF_DISABLED | IRQF_SHARED, | ||
| 110 | .mask = CPU_MASK_NONE, | ||
| 111 | .name = "fpga.0", | ||
| 112 | .dev_id = (void *) 0x0028UL, | ||
| 113 | }, | ||
| 114 | [1] = { | ||
| 115 | .handler = fpga_interrupt, | ||
| 116 | .flags = IRQF_DISABLED | IRQF_SHARED, | ||
| 117 | .mask = CPU_MASK_NONE, | ||
| 118 | .name = "fpga.1", | ||
| 119 | .dev_id = (void *) 0x0050UL, | ||
| 120 | }, | ||
| 121 | [2] = { | ||
| 122 | .handler = fpga_interrupt, | ||
| 123 | .flags = IRQF_DISABLED | IRQF_SHARED, | ||
| 124 | .mask = CPU_MASK_NONE, | ||
| 125 | .name = "fpga.2", | ||
| 126 | .dev_id = (void *) 0x1c00UL, | ||
| 127 | }, | ||
| 128 | [3] = { | ||
| 129 | .handler = fpga_interrupt, | ||
| 130 | .flags = IRQF_DISABLED | IRQF_SHARED, | ||
| 131 | .mask = CPU_MASK_NONE, | ||
| 132 | .name = "fpga.3", | ||
| 133 | .dev_id = (void *) 0x6386UL, | ||
| 134 | } | ||
| 135 | }; | ||
| 136 | |||
| 137 | /* | ||
| 138 | * initialise the motherboard FPGA's PIC | ||
| 139 | */ | ||
| 105 | void __init fpga_init(void) | 140 | void __init fpga_init(void) |
| 106 | { | 141 | { |
| 142 | int irq; | ||
| 143 | |||
| 144 | /* all PIC inputs are all set to be low-level driven, apart from the | ||
| 145 | * NMI button (15) which is fixed at falling-edge | ||
| 146 | */ | ||
| 107 | __set_IMR(0x7ffe); | 147 | __set_IMR(0x7ffe); |
| 108 | __clr_IFR(0x0000); | 148 | __clr_IFR(0x0000); |
| 109 | 149 | ||
| 110 | frv_irq_route_external(&frv_fpga[0], IRQ_CPU_EXTERNAL0); | 150 | for (irq = IRQ_BASE_FPGA + 1; irq <= IRQ_BASE_FPGA + 14; irq++) |
| 111 | frv_irq_route_external(&frv_fpga[1], IRQ_CPU_EXTERNAL1); | 151 | set_irq_chip_and_handler(irq, &frv_fpga_pic, handle_level_irq); |
| 112 | frv_irq_route_external(&frv_fpga[2], IRQ_CPU_EXTERNAL2); | 152 | |
| 113 | frv_irq_route_external(&frv_fpga[3], IRQ_CPU_EXTERNAL3); | 153 | set_irq_chip_and_handler(IRQ_FPGA_NMI, &frv_fpga_pic, handle_edge_irq); |
| 114 | frv_irq_set_group(&frv_fpga_irqs); | 154 | |
| 155 | /* the FPGA drives the first four external IRQ inputs on the CPU PIC */ | ||
| 156 | setup_irq(IRQ_CPU_EXTERNAL0, &fpga_irq[0]); | ||
| 157 | setup_irq(IRQ_CPU_EXTERNAL1, &fpga_irq[1]); | ||
| 158 | setup_irq(IRQ_CPU_EXTERNAL2, &fpga_irq[2]); | ||
| 159 | setup_irq(IRQ_CPU_EXTERNAL3, &fpga_irq[3]); | ||
| 115 | } | 160 | } |
diff --git a/arch/frv/kernel/irq-mb93093.c b/arch/frv/kernel/irq-mb93093.c index 48b2a6420888..f60db7988e78 100644 --- a/arch/frv/kernel/irq-mb93093.c +++ b/arch/frv/kernel/irq-mb93093.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* irq-mb93093.c: MB93093 FPGA interrupt handling | 1 | /* irq-mb93093.c: MB93093 FPGA interrupt handling |
| 2 | * | 2 | * |
| 3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. |
| 4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
| @@ -24,7 +24,6 @@ | |||
| 24 | #include <asm/delay.h> | 24 | #include <asm/delay.h> |
| 25 | #include <asm/irq.h> | 25 | #include <asm/irq.h> |
| 26 | #include <asm/irc-regs.h> | 26 | #include <asm/irc-regs.h> |
| 27 | #include <asm/irq-routing.h> | ||
| 28 | 27 | ||
| 29 | #define __reg16(ADDR) (*(volatile unsigned short *)(__region_CS2 + (ADDR))) | 28 | #define __reg16(ADDR) (*(volatile unsigned short *)(__region_CS2 + (ADDR))) |
| 30 | 29 | ||
| @@ -33,66 +32,100 @@ | |||
| 33 | #define __get_IFR() ({ __reg16(0x02); }) | 32 | #define __get_IFR() ({ __reg16(0x02); }) |
| 34 | #define __clr_IFR(M) do { __reg16(0x02) = ~(M); wmb(); } while(0) | 33 | #define __clr_IFR(M) do { __reg16(0x02) = ~(M); wmb(); } while(0) |
| 35 | 34 | ||
| 36 | static void frv_fpga_doirq(struct irq_source *source); | ||
| 37 | static void frv_fpga_control(struct irq_group *group, int irq, int on); | ||
| 38 | |||
| 39 | /*****************************************************************************/ | ||
| 40 | /* | 35 | /* |
| 41 | * FPGA IRQ multiplexor | 36 | * off-CPU FPGA PIC operations |
| 42 | */ | 37 | */ |
| 43 | static struct irq_source frv_fpga[4] = { | 38 | static void frv_fpga_enable(unsigned int irq) |
| 44 | #define __FPGA(X, M) \ | 39 | { |
| 45 | [X] = { \ | 40 | uint16_t imr = __get_IMR(); |
| 46 | .muxname = "fpga."#X, \ | ||
| 47 | .irqmask = M, \ | ||
| 48 | .doirq = frv_fpga_doirq, \ | ||
| 49 | } | ||
| 50 | |||
| 51 | __FPGA(0, 0x0700), | ||
| 52 | }; | ||
| 53 | 41 | ||
| 54 | static struct irq_group frv_fpga_irqs = { | 42 | imr &= ~(1 << (irq - IRQ_BASE_FPGA)); |
| 55 | .first_irq = IRQ_BASE_FPGA, | ||
| 56 | .control = frv_fpga_control, | ||
| 57 | .sources = { | ||
| 58 | [ 8] = &frv_fpga[0], | ||
| 59 | [ 9] = &frv_fpga[0], | ||
| 60 | [10] = &frv_fpga[0], | ||
| 61 | }, | ||
| 62 | }; | ||
| 63 | 43 | ||
| 44 | __set_IMR(imr); | ||
| 45 | } | ||
| 64 | 46 | ||
| 65 | static void frv_fpga_control(struct irq_group *group, int index, int on) | 47 | static void frv_fpga_disable(unsigned int irq) |
| 66 | { | 48 | { |
| 67 | uint16_t imr = __get_IMR(); | 49 | uint16_t imr = __get_IMR(); |
| 68 | 50 | ||
| 69 | if (on) | 51 | imr |= 1 << (irq - IRQ_BASE_FPGA); |
| 70 | imr &= ~(1 << index); | ||
| 71 | else | ||
| 72 | imr |= 1 << index; | ||
| 73 | 52 | ||
| 74 | __set_IMR(imr); | 53 | __set_IMR(imr); |
| 75 | } | 54 | } |
| 76 | 55 | ||
| 77 | static void frv_fpga_doirq(struct irq_source *source) | 56 | static void frv_fpga_ack(unsigned int irq) |
| 57 | { | ||
| 58 | __clr_IFR(1 << (irq - IRQ_BASE_FPGA)); | ||
| 59 | } | ||
| 60 | |||
| 61 | static void frv_fpga_end(unsigned int irq) | ||
| 62 | { | ||
| 63 | } | ||
| 64 | |||
| 65 | static struct irq_chip frv_fpga_pic = { | ||
| 66 | .name = "mb93093", | ||
| 67 | .enable = frv_fpga_enable, | ||
| 68 | .disable = frv_fpga_disable, | ||
| 69 | .ack = frv_fpga_ack, | ||
| 70 | .mask = frv_fpga_disable, | ||
| 71 | .unmask = frv_fpga_enable, | ||
| 72 | .end = frv_fpga_end, | ||
| 73 | }; | ||
| 74 | |||
| 75 | /* | ||
| 76 | * FPGA PIC interrupt handler | ||
| 77 | */ | ||
| 78 | static irqreturn_t fpga_interrupt(int irq, void *_mask, struct pt_regs *regs) | ||
| 78 | { | 79 | { |
| 79 | uint16_t mask, imr; | 80 | uint16_t imr, mask = (unsigned long) _mask; |
| 81 | irqreturn_t iret = 0; | ||
| 80 | 82 | ||
| 81 | imr = __get_IMR(); | 83 | imr = __get_IMR(); |
| 82 | mask = source->irqmask & ~imr & __get_IFR(); | 84 | mask = mask & ~imr & __get_IFR(); |
| 83 | if (mask) { | 85 | |
| 84 | __set_IMR(imr | mask); | 86 | /* poll all the triggered IRQs */ |
| 85 | __clr_IFR(mask); | 87 | while (mask) { |
| 86 | distribute_irqs(&frv_fpga_irqs, mask); | 88 | int irq; |
| 87 | __set_IMR(imr); | 89 | |
| 90 | asm("scan %1,gr0,%0" : "=r"(irq) : "r"(mask)); | ||
| 91 | irq = 31 - irq; | ||
| 92 | mask &= ~(1 << irq); | ||
| 93 | |||
| 94 | if (__do_IRQ(IRQ_BASE_FPGA + irq, regs)) | ||
| 95 | iret |= IRQ_HANDLED; | ||
| 88 | } | 96 | } |
| 97 | |||
| 98 | return iret; | ||
| 89 | } | 99 | } |
| 90 | 100 | ||
| 101 | /* | ||
| 102 | * define an interrupt action for each FPGA PIC output | ||
| 103 | * - use dev_id to indicate the FPGA PIC input to output mappings | ||
| 104 | */ | ||
| 105 | static struct irqaction fpga_irq[1] = { | ||
| 106 | [0] = { | ||
| 107 | .handler = fpga_interrupt, | ||
| 108 | .flags = IRQF_DISABLED, | ||
| 109 | .mask = CPU_MASK_NONE, | ||
| 110 | .name = "fpga.0", | ||
| 111 | .dev_id = (void *) 0x0700UL, | ||
| 112 | } | ||
| 113 | }; | ||
| 114 | |||
| 115 | /* | ||
| 116 | * initialise the motherboard FPGA's PIC | ||
| 117 | */ | ||
| 91 | void __init fpga_init(void) | 118 | void __init fpga_init(void) |
| 92 | { | 119 | { |
| 120 | int irq; | ||
| 121 | |||
| 122 | /* all PIC inputs are all set to be edge triggered */ | ||
| 93 | __set_IMR(0x0700); | 123 | __set_IMR(0x0700); |
| 94 | __clr_IFR(0x0000); | 124 | __clr_IFR(0x0000); |
| 95 | 125 | ||
| 96 | frv_irq_route_external(&frv_fpga[0], IRQ_CPU_EXTERNAL2); | 126 | for (irq = IRQ_BASE_FPGA + 8; irq <= IRQ_BASE_FPGA + 10; irq++) |
| 97 | frv_irq_set_group(&frv_fpga_irqs); | 127 | set_irq_chip_and_handler(irq, &frv_fpga_pic, handle_edge_irq); |
| 128 | |||
| 129 | /* the FPGA drives external IRQ input #2 on the CPU PIC */ | ||
| 130 | setup_irq(IRQ_CPU_EXTERNAL2, &fpga_irq[0]); | ||
| 98 | } | 131 | } |
diff --git a/arch/frv/kernel/irq-mb93493.c b/arch/frv/kernel/irq-mb93493.c index 988d035640e1..8ad9abfc7c13 100644 --- a/arch/frv/kernel/irq-mb93493.c +++ b/arch/frv/kernel/irq-mb93493.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* irq-mb93493.c: MB93493 companion chip interrupt handler | 1 | /* irq-mb93493.c: MB93493 companion chip interrupt handler |
| 2 | * | 2 | * |
| 3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. |
| 4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
| @@ -24,84 +24,133 @@ | |||
| 24 | #include <asm/delay.h> | 24 | #include <asm/delay.h> |
| 25 | #include <asm/irq.h> | 25 | #include <asm/irq.h> |
| 26 | #include <asm/irc-regs.h> | 26 | #include <asm/irc-regs.h> |
| 27 | #include <asm/irq-routing.h> | ||
| 28 | #include <asm/mb93493-irqs.h> | 27 | #include <asm/mb93493-irqs.h> |
| 28 | #include <asm/mb93493-regs.h> | ||
| 29 | 29 | ||
| 30 | static void frv_mb93493_doirq(struct irq_source *source); | 30 | #define IRQ_ROUTE_ONE(X) (X##_ROUTE << (X - IRQ_BASE_MB93493)) |
| 31 | |||
| 32 | #define IRQ_ROUTING \ | ||
| 33 | (IRQ_ROUTE_ONE(IRQ_MB93493_VDC) | \ | ||
| 34 | IRQ_ROUTE_ONE(IRQ_MB93493_VCC) | \ | ||
| 35 | IRQ_ROUTE_ONE(IRQ_MB93493_AUDIO_OUT) | \ | ||
| 36 | IRQ_ROUTE_ONE(IRQ_MB93493_I2C_0) | \ | ||
| 37 | IRQ_ROUTE_ONE(IRQ_MB93493_I2C_1) | \ | ||
| 38 | IRQ_ROUTE_ONE(IRQ_MB93493_USB) | \ | ||
| 39 | IRQ_ROUTE_ONE(IRQ_MB93493_LOCAL_BUS) | \ | ||
| 40 | IRQ_ROUTE_ONE(IRQ_MB93493_PCMCIA) | \ | ||
| 41 | IRQ_ROUTE_ONE(IRQ_MB93493_GPIO) | \ | ||
| 42 | IRQ_ROUTE_ONE(IRQ_MB93493_AUDIO_IN)) | ||
| 31 | 43 | ||
| 32 | /*****************************************************************************/ | ||
| 33 | /* | 44 | /* |
| 34 | * MB93493 companion chip IRQ multiplexor | 45 | * daughter board PIC operations |
| 35 | */ | 46 | */ |
| 36 | static struct irq_source frv_mb93493[2] = { | 47 | static void frv_mb93493_enable(unsigned int irq) |
| 37 | [0] = { | ||
| 38 | .muxname = "mb93493.0", | ||
| 39 | .muxdata = __region_CS3 + 0x3d0, | ||
| 40 | .doirq = frv_mb93493_doirq, | ||
| 41 | .irqmask = 0x0000, | ||
| 42 | }, | ||
| 43 | [1] = { | ||
| 44 | .muxname = "mb93493.1", | ||
| 45 | .muxdata = __region_CS3 + 0x3d4, | ||
| 46 | .doirq = frv_mb93493_doirq, | ||
| 47 | .irqmask = 0x0000, | ||
| 48 | }, | ||
| 49 | }; | ||
| 50 | |||
| 51 | static void frv_mb93493_control(struct irq_group *group, int index, int on) | ||
| 52 | { | 48 | { |
| 53 | struct irq_source *source; | ||
| 54 | uint32_t iqsr; | 49 | uint32_t iqsr; |
| 50 | volatile void *piqsr; | ||
| 55 | 51 | ||
| 56 | if ((frv_mb93493[0].irqmask & (1 << index))) | 52 | if (IRQ_ROUTING & (1 << (irq - IRQ_BASE_MB93493))) |
| 57 | source = &frv_mb93493[0]; | 53 | piqsr = __addr_MB93493_IQSR(1); |
| 58 | else | 54 | else |
| 59 | source = &frv_mb93493[1]; | 55 | piqsr = __addr_MB93493_IQSR(0); |
| 60 | 56 | ||
| 61 | iqsr = readl(source->muxdata); | 57 | iqsr = readl(piqsr); |
| 62 | if (on) | 58 | iqsr |= 1 << (irq - IRQ_BASE_MB93493 + 16); |
| 63 | iqsr |= 1 << (index + 16); | 59 | writel(iqsr, piqsr); |
| 60 | } | ||
| 61 | |||
| 62 | static void frv_mb93493_disable(unsigned int irq) | ||
| 63 | { | ||
| 64 | uint32_t iqsr; | ||
| 65 | volatile void *piqsr; | ||
| 66 | |||
| 67 | if (IRQ_ROUTING & (1 << (irq - IRQ_BASE_MB93493))) | ||
| 68 | piqsr = __addr_MB93493_IQSR(1); | ||
| 64 | else | 69 | else |
| 65 | iqsr &= ~(1 << (index + 16)); | 70 | piqsr = __addr_MB93493_IQSR(0); |
| 66 | 71 | ||
| 67 | writel(iqsr, source->muxdata); | 72 | iqsr = readl(piqsr); |
| 73 | iqsr &= ~(1 << (irq - IRQ_BASE_MB93493 + 16)); | ||
| 74 | writel(iqsr, piqsr); | ||
| 68 | } | 75 | } |
| 69 | 76 | ||
| 70 | static struct irq_group frv_mb93493_irqs = { | 77 | static void frv_mb93493_ack(unsigned int irq) |
| 71 | .first_irq = IRQ_BASE_MB93493, | ||
| 72 | .control = frv_mb93493_control, | ||
| 73 | }; | ||
| 74 | |||
| 75 | static void frv_mb93493_doirq(struct irq_source *source) | ||
| 76 | { | 78 | { |
| 77 | uint32_t mask = readl(source->muxdata); | 79 | } |
| 78 | mask = mask & (mask >> 16) & 0xffff; | ||
| 79 | 80 | ||
| 80 | if (mask) | 81 | static void frv_mb93493_end(unsigned int irq) |
| 81 | distribute_irqs(&frv_mb93493_irqs, mask); | 82 | { |
| 82 | } | 83 | } |
| 83 | 84 | ||
| 84 | static void __init mb93493_irq_route(int irq, int source) | 85 | static struct irq_chip frv_mb93493_pic = { |
| 86 | .name = "mb93093", | ||
| 87 | .enable = frv_mb93493_enable, | ||
| 88 | .disable = frv_mb93493_disable, | ||
| 89 | .ack = frv_mb93493_ack, | ||
| 90 | .mask = frv_mb93493_disable, | ||
| 91 | .unmask = frv_mb93493_enable, | ||
| 92 | .end = frv_mb93493_end, | ||
| 93 | }; | ||
| 94 | |||
| 95 | /* | ||
| 96 | * MB93493 PIC interrupt handler | ||
| 97 | */ | ||
| 98 | static irqreturn_t mb93493_interrupt(int irq, void *_piqsr, struct pt_regs *regs) | ||
| 85 | { | 99 | { |
| 86 | frv_mb93493[source].irqmask |= 1 << (irq - IRQ_BASE_MB93493); | 100 | volatile void *piqsr = _piqsr; |
| 87 | frv_mb93493_irqs.sources[irq - IRQ_BASE_MB93493] = &frv_mb93493[source]; | 101 | irqreturn_t iret = 0; |
| 102 | uint32_t iqsr; | ||
| 103 | |||
| 104 | iqsr = readl(piqsr); | ||
| 105 | iqsr = iqsr & (iqsr >> 16) & 0xffff; | ||
| 106 | |||
| 107 | /* poll all the triggered IRQs */ | ||
| 108 | while (iqsr) { | ||
| 109 | int irq; | ||
| 110 | |||
| 111 | asm("scan %1,gr0,%0" : "=r"(irq) : "r"(iqsr)); | ||
| 112 | irq = 31 - irq; | ||
| 113 | iqsr &= ~(1 << irq); | ||
| 114 | |||
| 115 | if (__do_IRQ(IRQ_BASE_MB93493 + irq, regs)) | ||
| 116 | iret |= IRQ_HANDLED; | ||
| 117 | } | ||
| 118 | |||
| 119 | return iret; | ||
| 88 | } | 120 | } |
| 89 | 121 | ||
| 90 | void __init route_mb93493_irqs(void) | 122 | /* |
| 123 | * define an interrupt action for each MB93493 PIC output | ||
| 124 | * - use dev_id to indicate the MB93493 PIC input to output mappings | ||
| 125 | */ | ||
| 126 | static struct irqaction mb93493_irq[2] = { | ||
| 127 | [0] = { | ||
| 128 | .handler = mb93493_interrupt, | ||
| 129 | .flags = IRQF_DISABLED | IRQF_SHARED, | ||
| 130 | .mask = CPU_MASK_NONE, | ||
| 131 | .name = "mb93493.0", | ||
| 132 | .dev_id = (void *) __addr_MB93493_IQSR(0), | ||
| 133 | }, | ||
| 134 | [1] = { | ||
| 135 | .handler = mb93493_interrupt, | ||
| 136 | .flags = IRQF_DISABLED | IRQF_SHARED, | ||
| 137 | .mask = CPU_MASK_NONE, | ||
| 138 | .name = "mb93493.1", | ||
| 139 | .dev_id = (void *) __addr_MB93493_IQSR(1), | ||
| 140 | } | ||
| 141 | }; | ||
| 142 | |||
| 143 | /* | ||
| 144 | * initialise the motherboard MB93493's PIC | ||
| 145 | */ | ||
| 146 | void __init mb93493_init(void) | ||
| 91 | { | 147 | { |
| 92 | frv_irq_route_external(&frv_mb93493[0], IRQ_CPU_MB93493_0); | 148 | int irq; |
| 93 | frv_irq_route_external(&frv_mb93493[1], IRQ_CPU_MB93493_1); | 149 | |
| 94 | 150 | for (irq = IRQ_BASE_MB93493 + 0; irq <= IRQ_BASE_MB93493 + 10; irq++) | |
| 95 | frv_irq_set_group(&frv_mb93493_irqs); | 151 | set_irq_chip_and_handler(irq, &frv_mb93493_pic, handle_edge_irq); |
| 96 | 152 | ||
| 97 | mb93493_irq_route(IRQ_MB93493_VDC, IRQ_MB93493_VDC_ROUTE); | 153 | /* the MB93493 drives external IRQ inputs on the CPU PIC */ |
| 98 | mb93493_irq_route(IRQ_MB93493_VCC, IRQ_MB93493_VCC_ROUTE); | 154 | setup_irq(IRQ_CPU_MB93493_0, &mb93493_irq[0]); |
| 99 | mb93493_irq_route(IRQ_MB93493_AUDIO_IN, IRQ_MB93493_AUDIO_IN_ROUTE); | 155 | setup_irq(IRQ_CPU_MB93493_1, &mb93493_irq[1]); |
| 100 | mb93493_irq_route(IRQ_MB93493_I2C_0, IRQ_MB93493_I2C_0_ROUTE); | ||
| 101 | mb93493_irq_route(IRQ_MB93493_I2C_1, IRQ_MB93493_I2C_1_ROUTE); | ||
| 102 | mb93493_irq_route(IRQ_MB93493_USB, IRQ_MB93493_USB_ROUTE); | ||
| 103 | mb93493_irq_route(IRQ_MB93493_LOCAL_BUS, IRQ_MB93493_LOCAL_BUS_ROUTE); | ||
| 104 | mb93493_irq_route(IRQ_MB93493_PCMCIA, IRQ_MB93493_PCMCIA_ROUTE); | ||
| 105 | mb93493_irq_route(IRQ_MB93493_GPIO, IRQ_MB93493_GPIO_ROUTE); | ||
| 106 | mb93493_irq_route(IRQ_MB93493_AUDIO_OUT, IRQ_MB93493_AUDIO_OUT_ROUTE); | ||
| 107 | } | 156 | } |
diff --git a/arch/frv/kernel/irq-routing.c b/arch/frv/kernel/irq-routing.c deleted file mode 100644 index 53886adf47de..000000000000 --- a/arch/frv/kernel/irq-routing.c +++ /dev/null | |||
| @@ -1,291 +0,0 @@ | |||
| 1 | /* irq-routing.c: IRQ routing | ||
| 2 | * | ||
| 3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the License, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/sched.h> | ||
| 13 | #include <linux/random.h> | ||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/serial_reg.h> | ||
| 16 | #include <asm/io.h> | ||
| 17 | #include <asm/irq-routing.h> | ||
| 18 | #include <asm/irc-regs.h> | ||
| 19 | #include <asm/serial-regs.h> | ||
| 20 | #include <asm/dma.h> | ||
| 21 | |||
| 22 | struct irq_level frv_irq_levels[16] = { | ||
| 23 | [0 ... 15] = { | ||
| 24 | .lock = SPIN_LOCK_UNLOCKED, | ||
| 25 | } | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct irq_group *irq_groups[NR_IRQ_GROUPS]; | ||
| 29 | |||
| 30 | extern struct irq_group frv_cpu_irqs; | ||
| 31 | |||
| 32 | void __init frv_irq_route(struct irq_source *source, int irqlevel) | ||
| 33 | { | ||
| 34 | source->level = &frv_irq_levels[irqlevel]; | ||
| 35 | source->next = frv_irq_levels[irqlevel].sources; | ||
| 36 | frv_irq_levels[irqlevel].sources = source; | ||
| 37 | } | ||
| 38 | |||
| 39 | void __init frv_irq_route_external(struct irq_source *source, int irq) | ||
| 40 | { | ||
| 41 | int irqlevel = 0; | ||
| 42 | |||
| 43 | switch (irq) { | ||
| 44 | case IRQ_CPU_EXTERNAL0: irqlevel = IRQ_XIRQ0_LEVEL; break; | ||
| 45 | case IRQ_CPU_EXTERNAL1: irqlevel = IRQ_XIRQ1_LEVEL; break; | ||
| 46 | case IRQ_CPU_EXTERNAL2: irqlevel = IRQ_XIRQ2_LEVEL; break; | ||
| 47 | case IRQ_CPU_EXTERNAL3: irqlevel = IRQ_XIRQ3_LEVEL; break; | ||
| 48 | case IRQ_CPU_EXTERNAL4: irqlevel = IRQ_XIRQ4_LEVEL; break; | ||
| 49 | case IRQ_CPU_EXTERNAL5: irqlevel = IRQ_XIRQ5_LEVEL; break; | ||
| 50 | case IRQ_CPU_EXTERNAL6: irqlevel = IRQ_XIRQ6_LEVEL; break; | ||
| 51 | case IRQ_CPU_EXTERNAL7: irqlevel = IRQ_XIRQ7_LEVEL; break; | ||
| 52 | default: BUG(); | ||
| 53 | } | ||
| 54 | |||
| 55 | source->level = &frv_irq_levels[irqlevel]; | ||
| 56 | source->next = frv_irq_levels[irqlevel].sources; | ||
| 57 | frv_irq_levels[irqlevel].sources = source; | ||
| 58 | } | ||
| 59 | |||
| 60 | void __init frv_irq_set_group(struct irq_group *group) | ||
| 61 | { | ||
| 62 | irq_groups[group->first_irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP] = group; | ||
| 63 | } | ||
| 64 | |||
| 65 | void distribute_irqs(struct irq_group *group, unsigned long irqmask) | ||
| 66 | { | ||
| 67 | struct irqaction *action; | ||
| 68 | int irq; | ||
| 69 | |||
| 70 | while (irqmask) { | ||
| 71 | asm("scan %1,gr0,%0" : "=r"(irq) : "r"(irqmask)); | ||
| 72 | if (irq < 0 || irq > 31) | ||
| 73 | asm volatile("break"); | ||
| 74 | irq = 31 - irq; | ||
| 75 | |||
| 76 | irqmask &= ~(1 << irq); | ||
| 77 | action = group->actions[irq]; | ||
| 78 | |||
| 79 | irq += group->first_irq; | ||
| 80 | |||
| 81 | if (action) { | ||
| 82 | int status = 0; | ||
| 83 | |||
| 84 | // if (!(action->flags & IRQF_DISABLED)) | ||
| 85 | // local_irq_enable(); | ||
| 86 | |||
| 87 | do { | ||
| 88 | status |= action->flags; | ||
| 89 | action->handler(irq, action->dev_id, __frame); | ||
| 90 | action = action->next; | ||
| 91 | } while (action); | ||
| 92 | |||
| 93 | if (status & IRQF_SAMPLE_RANDOM) | ||
| 94 | add_interrupt_randomness(irq); | ||
| 95 | local_irq_disable(); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | /*****************************************************************************/ | ||
| 101 | /* | ||
| 102 | * CPU UART interrupts | ||
| 103 | */ | ||
| 104 | static void frv_cpuuart_doirq(struct irq_source *source) | ||
| 105 | { | ||
| 106 | // uint8_t iir = readb(source->muxdata + UART_IIR * 8); | ||
| 107 | // if ((iir & 0x0f) != UART_IIR_NO_INT) | ||
| 108 | distribute_irqs(&frv_cpu_irqs, source->irqmask); | ||
| 109 | } | ||
| 110 | |||
| 111 | struct irq_source frv_cpuuart[2] = { | ||
| 112 | #define __CPUUART(X, A) \ | ||
| 113 | [X] = { \ | ||
| 114 | .muxname = "uart", \ | ||
| 115 | .muxdata = (volatile void __iomem *)(unsigned long)A,\ | ||
| 116 | .irqmask = 1 << IRQ_CPU_UART##X, \ | ||
| 117 | .doirq = frv_cpuuart_doirq, \ | ||
| 118 | } | ||
| 119 | |||
| 120 | __CPUUART(0, UART0_BASE), | ||
| 121 | __CPUUART(1, UART1_BASE), | ||
| 122 | }; | ||
| 123 | |||
| 124 | /*****************************************************************************/ | ||
| 125 | /* | ||
| 126 | * CPU DMA interrupts | ||
| 127 | */ | ||
| 128 | static void frv_cpudma_doirq(struct irq_source *source) | ||
| 129 | { | ||
| 130 | uint32_t cstr = readl(source->muxdata + DMAC_CSTRx); | ||
| 131 | if (cstr & DMAC_CSTRx_INT) | ||
| 132 | distribute_irqs(&frv_cpu_irqs, source->irqmask); | ||
| 133 | } | ||
| 134 | |||
| 135 | struct irq_source frv_cpudma[8] = { | ||
| 136 | #define __CPUDMA(X, A) \ | ||
| 137 | [X] = { \ | ||
| 138 | .muxname = "dma", \ | ||
| 139 | .muxdata = (volatile void __iomem *)(unsigned long)A,\ | ||
| 140 | .irqmask = 1 << IRQ_CPU_DMA##X, \ | ||
| 141 | .doirq = frv_cpudma_doirq, \ | ||
| 142 | } | ||
| 143 | |||
| 144 | __CPUDMA(0, 0xfe000900), | ||
| 145 | __CPUDMA(1, 0xfe000980), | ||
| 146 | __CPUDMA(2, 0xfe000a00), | ||
| 147 | __CPUDMA(3, 0xfe000a80), | ||
| 148 | __CPUDMA(4, 0xfe001000), | ||
| 149 | __CPUDMA(5, 0xfe001080), | ||
| 150 | __CPUDMA(6, 0xfe001100), | ||
| 151 | __CPUDMA(7, 0xfe001180), | ||
| 152 | }; | ||
| 153 | |||
| 154 | /*****************************************************************************/ | ||
| 155 | /* | ||
| 156 | * CPU timer interrupts - can't tell whether they've generated an interrupt or not | ||
| 157 | */ | ||
| 158 | static void frv_cputimer_doirq(struct irq_source *source) | ||
| 159 | { | ||
| 160 | distribute_irqs(&frv_cpu_irqs, source->irqmask); | ||
| 161 | } | ||
| 162 | |||
| 163 | struct irq_source frv_cputimer[3] = { | ||
| 164 | #define __CPUTIMER(X) \ | ||
| 165 | [X] = { \ | ||
| 166 | .muxname = "timer", \ | ||
| 167 | .muxdata = NULL, \ | ||
| 168 | .irqmask = 1 << IRQ_CPU_TIMER##X, \ | ||
| 169 | .doirq = frv_cputimer_doirq, \ | ||
| 170 | } | ||
| 171 | |||
| 172 | __CPUTIMER(0), | ||
| 173 | __CPUTIMER(1), | ||
| 174 | __CPUTIMER(2), | ||
| 175 | }; | ||
| 176 | |||
| 177 | /*****************************************************************************/ | ||
| 178 | /* | ||
| 179 | * external CPU interrupts - can't tell directly whether they've generated an interrupt or not | ||
| 180 | */ | ||
| 181 | static void frv_cpuexternal_doirq(struct irq_source *source) | ||
| 182 | { | ||
| 183 | distribute_irqs(&frv_cpu_irqs, source->irqmask); | ||
| 184 | } | ||
| 185 | |||
| 186 | struct irq_source frv_cpuexternal[8] = { | ||
| 187 | #define __CPUEXTERNAL(X) \ | ||
| 188 | [X] = { \ | ||
| 189 | .muxname = "ext", \ | ||
| 190 | .muxdata = NULL, \ | ||
| 191 | .irqmask = 1 << IRQ_CPU_EXTERNAL##X, \ | ||
| 192 | .doirq = frv_cpuexternal_doirq, \ | ||
| 193 | } | ||
| 194 | |||
| 195 | __CPUEXTERNAL(0), | ||
| 196 | __CPUEXTERNAL(1), | ||
| 197 | __CPUEXTERNAL(2), | ||
| 198 | __CPUEXTERNAL(3), | ||
| 199 | __CPUEXTERNAL(4), | ||
| 200 | __CPUEXTERNAL(5), | ||
| 201 | __CPUEXTERNAL(6), | ||
| 202 | __CPUEXTERNAL(7), | ||
| 203 | }; | ||
| 204 | |||
| 205 | #define set_IRR(N,A,B,C,D) __set_IRR(N, (A << 28) | (B << 24) | (C << 20) | (D << 16)) | ||
| 206 | |||
| 207 | struct irq_group frv_cpu_irqs = { | ||
| 208 | .sources = { | ||
| 209 | [IRQ_CPU_UART0] = &frv_cpuuart[0], | ||
| 210 | [IRQ_CPU_UART1] = &frv_cpuuart[1], | ||
| 211 | [IRQ_CPU_TIMER0] = &frv_cputimer[0], | ||
| 212 | [IRQ_CPU_TIMER1] = &frv_cputimer[1], | ||
| 213 | [IRQ_CPU_TIMER2] = &frv_cputimer[2], | ||
| 214 | [IRQ_CPU_DMA0] = &frv_cpudma[0], | ||
| 215 | [IRQ_CPU_DMA1] = &frv_cpudma[1], | ||
| 216 | [IRQ_CPU_DMA2] = &frv_cpudma[2], | ||
| 217 | [IRQ_CPU_DMA3] = &frv_cpudma[3], | ||
| 218 | [IRQ_CPU_DMA4] = &frv_cpudma[4], | ||
| 219 | [IRQ_CPU_DMA5] = &frv_cpudma[5], | ||
| 220 | [IRQ_CPU_DMA6] = &frv_cpudma[6], | ||
| 221 | [IRQ_CPU_DMA7] = &frv_cpudma[7], | ||
| 222 | [IRQ_CPU_EXTERNAL0] = &frv_cpuexternal[0], | ||
| 223 | [IRQ_CPU_EXTERNAL1] = &frv_cpuexternal[1], | ||
| 224 | [IRQ_CPU_EXTERNAL2] = &frv_cpuexternal[2], | ||
| 225 | [IRQ_CPU_EXTERNAL3] = &frv_cpuexternal[3], | ||
| 226 | [IRQ_CPU_EXTERNAL4] = &frv_cpuexternal[4], | ||
| 227 | [IRQ_CPU_EXTERNAL5] = &frv_cpuexternal[5], | ||
| 228 | [IRQ_CPU_EXTERNAL6] = &frv_cpuexternal[6], | ||
| 229 | [IRQ_CPU_EXTERNAL7] = &frv_cpuexternal[7], | ||
| 230 | }, | ||
| 231 | }; | ||
| 232 | |||
| 233 | /*****************************************************************************/ | ||
| 234 | /* | ||
| 235 | * route the CPU's interrupt sources | ||
| 236 | */ | ||
| 237 | void __init route_cpu_irqs(void) | ||
| 238 | { | ||
| 239 | frv_irq_set_group(&frv_cpu_irqs); | ||
| 240 | |||
| 241 | __set_IITMR(0, 0x003f0000); /* DMA0-3, TIMER0-2 IRQ detect levels */ | ||
| 242 | __set_IITMR(1, 0x20000000); /* ERR0-1, UART0-1, DMA4-7 IRQ detect levels */ | ||
| 243 | |||
| 244 | /* route UART and error interrupts */ | ||
| 245 | frv_irq_route(&frv_cpuuart[0], IRQ_UART0_LEVEL); | ||
| 246 | frv_irq_route(&frv_cpuuart[1], IRQ_UART1_LEVEL); | ||
| 247 | |||
| 248 | set_IRR(6, IRQ_GDBSTUB_LEVEL, IRQ_GDBSTUB_LEVEL, IRQ_UART1_LEVEL, IRQ_UART0_LEVEL); | ||
| 249 | |||
| 250 | /* route DMA channel interrupts */ | ||
| 251 | frv_irq_route(&frv_cpudma[0], IRQ_DMA0_LEVEL); | ||
| 252 | frv_irq_route(&frv_cpudma[1], IRQ_DMA1_LEVEL); | ||
| 253 | frv_irq_route(&frv_cpudma[2], IRQ_DMA2_LEVEL); | ||
| 254 | frv_irq_route(&frv_cpudma[3], IRQ_DMA3_LEVEL); | ||
| 255 | frv_irq_route(&frv_cpudma[4], IRQ_DMA4_LEVEL); | ||
| 256 | frv_irq_route(&frv_cpudma[5], IRQ_DMA5_LEVEL); | ||
| 257 | frv_irq_route(&frv_cpudma[6], IRQ_DMA6_LEVEL); | ||
| 258 | frv_irq_route(&frv_cpudma[7], IRQ_DMA7_LEVEL); | ||
| 259 | |||
| 260 | set_IRR(4, IRQ_DMA3_LEVEL, IRQ_DMA2_LEVEL, IRQ_DMA1_LEVEL, IRQ_DMA0_LEVEL); | ||
| 261 | set_IRR(7, IRQ_DMA7_LEVEL, IRQ_DMA6_LEVEL, IRQ_DMA5_LEVEL, IRQ_DMA4_LEVEL); | ||
| 262 | |||
| 263 | /* route timer interrupts */ | ||
| 264 | frv_irq_route(&frv_cputimer[0], IRQ_TIMER0_LEVEL); | ||
| 265 | frv_irq_route(&frv_cputimer[1], IRQ_TIMER1_LEVEL); | ||
| 266 | frv_irq_route(&frv_cputimer[2], IRQ_TIMER2_LEVEL); | ||
| 267 | |||
| 268 | set_IRR(5, 0, IRQ_TIMER2_LEVEL, IRQ_TIMER1_LEVEL, IRQ_TIMER0_LEVEL); | ||
| 269 | |||
| 270 | /* route external interrupts */ | ||
| 271 | frv_irq_route(&frv_cpuexternal[0], IRQ_XIRQ0_LEVEL); | ||
| 272 | frv_irq_route(&frv_cpuexternal[1], IRQ_XIRQ1_LEVEL); | ||
| 273 | frv_irq_route(&frv_cpuexternal[2], IRQ_XIRQ2_LEVEL); | ||
| 274 | frv_irq_route(&frv_cpuexternal[3], IRQ_XIRQ3_LEVEL); | ||
| 275 | frv_irq_route(&frv_cpuexternal[4], IRQ_XIRQ4_LEVEL); | ||
| 276 | frv_irq_route(&frv_cpuexternal[5], IRQ_XIRQ5_LEVEL); | ||
| 277 | frv_irq_route(&frv_cpuexternal[6], IRQ_XIRQ6_LEVEL); | ||
| 278 | frv_irq_route(&frv_cpuexternal[7], IRQ_XIRQ7_LEVEL); | ||
| 279 | |||
| 280 | set_IRR(2, IRQ_XIRQ7_LEVEL, IRQ_XIRQ6_LEVEL, IRQ_XIRQ5_LEVEL, IRQ_XIRQ4_LEVEL); | ||
| 281 | set_IRR(3, IRQ_XIRQ3_LEVEL, IRQ_XIRQ2_LEVEL, IRQ_XIRQ1_LEVEL, IRQ_XIRQ0_LEVEL); | ||
| 282 | |||
| 283 | #if defined(CONFIG_MB93091_VDK) | ||
| 284 | __set_TM1(0x55550000); /* XIRQ7-0 all active low */ | ||
| 285 | #elif defined(CONFIG_MB93093_PDK) | ||
| 286 | __set_TM1(0x15550000); /* XIRQ7 active high, 6-0 all active low */ | ||
| 287 | #else | ||
| 288 | #error dont know external IRQ trigger levels for this setup | ||
| 289 | #endif | ||
| 290 | |||
| 291 | } /* end route_cpu_irqs() */ | ||
diff --git a/arch/frv/kernel/irq.c b/arch/frv/kernel/irq.c index 08967010be04..e1ab9f2e43fb 100644 --- a/arch/frv/kernel/irq.c +++ b/arch/frv/kernel/irq.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* irq.c: FRV IRQ handling | 1 | /* irq.c: FRV IRQ handling |
| 2 | * | 2 | * |
| 3 | * Copyright (C) 2003, 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2003, 2004, 2006 Red Hat, Inc. All Rights Reserved. |
| 4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
| @@ -9,13 +9,6 @@ | |||
| 9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | /* | ||
| 13 | * (mostly architecture independent, will move to kernel/irq.c in 2.5.) | ||
| 14 | * | ||
| 15 | * IRQs are in fact implemented a bit like signal handlers for the kernel. | ||
| 16 | * Naturally it's not a 1:1 relation, but there are similarities. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/ptrace.h> | 12 | #include <linux/ptrace.h> |
| 20 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
| 21 | #include <linux/signal.h> | 14 | #include <linux/signal.h> |
| @@ -43,19 +36,16 @@ | |||
| 43 | #include <asm/delay.h> | 36 | #include <asm/delay.h> |
| 44 | #include <asm/irq.h> | 37 | #include <asm/irq.h> |
| 45 | #include <asm/irc-regs.h> | 38 | #include <asm/irc-regs.h> |
| 46 | #include <asm/irq-routing.h> | ||
| 47 | #include <asm/gdb-stub.h> | 39 | #include <asm/gdb-stub.h> |
| 48 | 40 | ||
| 49 | extern void __init fpga_init(void); | 41 | #define set_IRR(N,A,B,C,D) __set_IRR(N, (A << 28) | (B << 24) | (C << 20) | (D << 16)) |
| 50 | extern void __init route_mb93493_irqs(void); | ||
| 51 | |||
| 52 | static void register_irq_proc (unsigned int irq); | ||
| 53 | 42 | ||
| 54 | /* | 43 | extern void __init fpga_init(void); |
| 55 | * Special irq handlers. | 44 | #ifdef CONFIG_FUJITSU_MB93493 |
| 56 | */ | 45 | extern void __init mb93493_init(void); |
| 46 | #endif | ||
| 57 | 47 | ||
| 58 | irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs) { return IRQ_HANDLED; } | 48 | #define __reg16(ADDR) (*(volatile unsigned short *)(ADDR)) |
| 59 | 49 | ||
| 60 | atomic_t irq_err_count; | 50 | atomic_t irq_err_count; |
| 61 | 51 | ||
| @@ -64,215 +54,99 @@ atomic_t irq_err_count; | |||
| 64 | */ | 54 | */ |
| 65 | int show_interrupts(struct seq_file *p, void *v) | 55 | int show_interrupts(struct seq_file *p, void *v) |
| 66 | { | 56 | { |
| 67 | struct irqaction *action; | 57 | int i = *(loff_t *) v, cpu; |
| 68 | struct irq_group *group; | 58 | struct irqaction * action; |
| 69 | unsigned long flags; | 59 | unsigned long flags; |
| 70 | int level, grp, ix, i, j; | ||
| 71 | |||
| 72 | i = *(loff_t *) v; | ||
| 73 | |||
| 74 | switch (i) { | ||
| 75 | case 0: | ||
| 76 | seq_printf(p, " "); | ||
| 77 | for_each_online_cpu(j) | ||
| 78 | seq_printf(p, "CPU%d ",j); | ||
| 79 | |||
| 80 | seq_putc(p, '\n'); | ||
| 81 | break; | ||
| 82 | 60 | ||
| 83 | case 1 ... NR_IRQ_GROUPS * NR_IRQ_ACTIONS_PER_GROUP: | 61 | if (i == 0) { |
| 84 | local_irq_save(flags); | 62 | char cpuname[12]; |
| 85 | |||
| 86 | grp = (i - 1) / NR_IRQ_ACTIONS_PER_GROUP; | ||
| 87 | group = irq_groups[grp]; | ||
| 88 | if (!group) | ||
| 89 | goto skip; | ||
| 90 | |||
| 91 | ix = (i - 1) % NR_IRQ_ACTIONS_PER_GROUP; | ||
| 92 | action = group->actions[ix]; | ||
| 93 | if (!action) | ||
| 94 | goto skip; | ||
| 95 | |||
| 96 | seq_printf(p, "%3d: ", i - 1); | ||
| 97 | |||
| 98 | #ifndef CONFIG_SMP | ||
| 99 | seq_printf(p, "%10u ", kstat_irqs(i)); | ||
| 100 | #else | ||
| 101 | for_each_online_cpu(j) | ||
| 102 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i - 1]); | ||
| 103 | #endif | ||
| 104 | |||
| 105 | level = group->sources[ix]->level - frv_irq_levels; | ||
| 106 | |||
| 107 | seq_printf(p, " %12s@%x", group->sources[ix]->muxname, level); | ||
| 108 | seq_printf(p, " %s", action->name); | ||
| 109 | |||
| 110 | for (action = action->next; action; action = action->next) | ||
| 111 | seq_printf(p, ", %s", action->name); | ||
| 112 | 63 | ||
| 64 | seq_printf(p, " "); | ||
| 65 | for_each_present_cpu(cpu) { | ||
| 66 | sprintf(cpuname, "CPU%d", cpu); | ||
| 67 | seq_printf(p, " %10s", cpuname); | ||
| 68 | } | ||
| 113 | seq_putc(p, '\n'); | 69 | seq_putc(p, '\n'); |
| 114 | skip: | 70 | } |
| 115 | local_irq_restore(flags); | ||
| 116 | break; | ||
| 117 | 71 | ||
| 118 | case NR_IRQ_GROUPS * NR_IRQ_ACTIONS_PER_GROUP + 1: | 72 | if (i < NR_IRQS) { |
| 119 | seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); | 73 | spin_lock_irqsave(&irq_desc[i].lock, flags); |
| 120 | break; | 74 | action = irq_desc[i].action; |
| 75 | if (action) { | ||
| 76 | seq_printf(p, "%3d: ", i); | ||
| 77 | for_each_present_cpu(cpu) | ||
| 78 | seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]); | ||
| 79 | seq_printf(p, " %10s", irq_desc[i].chip->name ? : "-"); | ||
| 80 | seq_printf(p, " %s", action->name); | ||
| 81 | for (action = action->next; | ||
| 82 | action; | ||
| 83 | action = action->next) | ||
| 84 | seq_printf(p, ", %s", action->name); | ||
| 85 | |||
| 86 | seq_putc(p, '\n'); | ||
| 87 | } | ||
| 121 | 88 | ||
| 122 | default: | 89 | spin_unlock_irqrestore(&irq_desc[i].lock, flags); |
| 123 | break; | 90 | } else if (i == NR_IRQS) { |
| 91 | seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count)); | ||
| 124 | } | 92 | } |
| 125 | 93 | ||
| 126 | return 0; | 94 | return 0; |
| 127 | } | 95 | } |
| 128 | 96 | ||
| 129 | |||
| 130 | /* | 97 | /* |
| 131 | * Generic enable/disable code: this just calls | 98 | * on-CPU PIC operations |
| 132 | * down into the PIC-specific version for the actual | ||
| 133 | * hardware disable after having gotten the irq | ||
| 134 | * controller lock. | ||
| 135 | */ | 99 | */ |
| 136 | 100 | static void frv_cpupic_enable(unsigned int irqlevel) | |
| 137 | /** | ||
| 138 | * disable_irq_nosync - disable an irq without waiting | ||
| 139 | * @irq: Interrupt to disable | ||
| 140 | * | ||
| 141 | * Disable the selected interrupt line. Disables and Enables are | ||
| 142 | * nested. | ||
| 143 | * Unlike disable_irq(), this function does not ensure existing | ||
| 144 | * instances of the IRQ handler have completed before returning. | ||
| 145 | * | ||
| 146 | * This function may be called from IRQ context. | ||
| 147 | */ | ||
| 148 | |||
| 149 | void disable_irq_nosync(unsigned int irq) | ||
| 150 | { | 101 | { |
| 151 | struct irq_source *source; | 102 | __clr_MASK(irqlevel); |
| 152 | struct irq_group *group; | ||
| 153 | struct irq_level *level; | ||
| 154 | unsigned long flags; | ||
| 155 | int idx = irq & (NR_IRQ_ACTIONS_PER_GROUP - 1); | ||
| 156 | |||
| 157 | group = irq_groups[irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP]; | ||
| 158 | if (!group) | ||
| 159 | BUG(); | ||
| 160 | |||
| 161 | source = group->sources[idx]; | ||
| 162 | if (!source) | ||
| 163 | BUG(); | ||
| 164 | |||
| 165 | level = source->level; | ||
| 166 | |||
| 167 | spin_lock_irqsave(&level->lock, flags); | ||
| 168 | |||
| 169 | if (group->control) { | ||
| 170 | if (!group->disable_cnt[idx]++) | ||
| 171 | group->control(group, idx, 0); | ||
| 172 | } else if (!level->disable_count++) { | ||
| 173 | __set_MASK(level - frv_irq_levels); | ||
| 174 | } | ||
| 175 | |||
| 176 | spin_unlock_irqrestore(&level->lock, flags); | ||
| 177 | } | 103 | } |
| 178 | 104 | ||
| 179 | EXPORT_SYMBOL(disable_irq_nosync); | 105 | static void frv_cpupic_disable(unsigned int irqlevel) |
| 180 | |||
| 181 | /** | ||
| 182 | * disable_irq - disable an irq and wait for completion | ||
| 183 | * @irq: Interrupt to disable | ||
| 184 | * | ||
| 185 | * Disable the selected interrupt line. Enables and Disables are | ||
| 186 | * nested. | ||
| 187 | * This function waits for any pending IRQ handlers for this interrupt | ||
| 188 | * to complete before returning. If you use this function while | ||
| 189 | * holding a resource the IRQ handler may need you will deadlock. | ||
| 190 | * | ||
| 191 | * This function may be called - with care - from IRQ context. | ||
| 192 | */ | ||
| 193 | |||
| 194 | void disable_irq(unsigned int irq) | ||
| 195 | { | 106 | { |
| 196 | disable_irq_nosync(irq); | 107 | __set_MASK(irqlevel); |
| 197 | |||
| 198 | #ifdef CONFIG_SMP | ||
| 199 | if (!local_irq_count(smp_processor_id())) { | ||
| 200 | do { | ||
| 201 | barrier(); | ||
| 202 | } while (irq_desc[irq].status & IRQ_INPROGRESS); | ||
| 203 | } | ||
| 204 | #endif | ||
| 205 | } | 108 | } |
| 206 | 109 | ||
| 207 | EXPORT_SYMBOL(disable_irq); | 110 | static void frv_cpupic_ack(unsigned int irqlevel) |
| 208 | |||
| 209 | /** | ||
| 210 | * enable_irq - enable handling of an irq | ||
| 211 | * @irq: Interrupt to enable | ||
| 212 | * | ||
| 213 | * Undoes the effect of one call to disable_irq(). If this | ||
| 214 | * matches the last disable, processing of interrupts on this | ||
| 215 | * IRQ line is re-enabled. | ||
| 216 | * | ||
| 217 | * This function may be called from IRQ context. | ||
| 218 | */ | ||
| 219 | |||
| 220 | void enable_irq(unsigned int irq) | ||
| 221 | { | 111 | { |
| 222 | struct irq_source *source; | 112 | __set_MASK(irqlevel); |
| 223 | struct irq_group *group; | 113 | __clr_RC(irqlevel); |
| 224 | struct irq_level *level; | 114 | __clr_IRL(); |
| 225 | unsigned long flags; | 115 | } |
| 226 | int idx = irq & (NR_IRQ_ACTIONS_PER_GROUP - 1); | ||
| 227 | int count; | ||
| 228 | |||
| 229 | group = irq_groups[irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP]; | ||
| 230 | if (!group) | ||
| 231 | BUG(); | ||
| 232 | |||
| 233 | source = group->sources[idx]; | ||
| 234 | if (!source) | ||
| 235 | BUG(); | ||
| 236 | |||
| 237 | level = source->level; | ||
| 238 | |||
| 239 | spin_lock_irqsave(&level->lock, flags); | ||
| 240 | |||
| 241 | if (group->control) | ||
| 242 | count = group->disable_cnt[idx]; | ||
| 243 | else | ||
| 244 | count = level->disable_count; | ||
| 245 | |||
| 246 | switch (count) { | ||
| 247 | case 1: | ||
| 248 | if (group->control) { | ||
| 249 | if (group->actions[idx]) | ||
| 250 | group->control(group, idx, 1); | ||
| 251 | } else { | ||
| 252 | if (level->usage) | ||
| 253 | __clr_MASK(level - frv_irq_levels); | ||
| 254 | } | ||
| 255 | /* fall-through */ | ||
| 256 | 116 | ||
| 257 | default: | 117 | static void frv_cpupic_mask(unsigned int irqlevel) |
| 258 | count--; | 118 | { |
| 259 | break; | 119 | __set_MASK(irqlevel); |
| 120 | } | ||
| 260 | 121 | ||
| 261 | case 0: | 122 | static void frv_cpupic_mask_ack(unsigned int irqlevel) |
| 262 | printk("enable_irq(%u) unbalanced from %p\n", irq, __builtin_return_address(0)); | 123 | { |
| 263 | } | 124 | __set_MASK(irqlevel); |
| 125 | __clr_RC(irqlevel); | ||
| 126 | __clr_IRL(); | ||
| 127 | } | ||
| 264 | 128 | ||
| 265 | if (group->control) | 129 | static void frv_cpupic_unmask(unsigned int irqlevel) |
| 266 | group->disable_cnt[idx] = count; | 130 | { |
| 267 | else | 131 | __clr_MASK(irqlevel); |
| 268 | level->disable_count = count; | 132 | } |
| 269 | 133 | ||
| 270 | spin_unlock_irqrestore(&level->lock, flags); | 134 | static void frv_cpupic_end(unsigned int irqlevel) |
| 135 | { | ||
| 136 | __clr_MASK(irqlevel); | ||
| 271 | } | 137 | } |
| 272 | 138 | ||
| 273 | EXPORT_SYMBOL(enable_irq); | 139 | static struct irq_chip frv_cpu_pic = { |
| 140 | .name = "cpu", | ||
| 141 | .enable = frv_cpupic_enable, | ||
| 142 | .disable = frv_cpupic_disable, | ||
| 143 | .ack = frv_cpupic_ack, | ||
| 144 | .mask = frv_cpupic_mask, | ||
| 145 | .mask_ack = frv_cpupic_mask_ack, | ||
| 146 | .unmask = frv_cpupic_unmask, | ||
| 147 | .end = frv_cpupic_end, | ||
| 148 | }; | ||
| 274 | 149 | ||
| 275 | /*****************************************************************************/ | ||
| 276 | /* | 150 | /* |
| 277 | * handles all normal device IRQ's | 151 | * handles all normal device IRQ's |
| 278 | * - registers are referred to by the __frame variable (GR28) | 152 | * - registers are referred to by the __frame variable (GR28) |
| @@ -281,463 +155,65 @@ EXPORT_SYMBOL(enable_irq); | |||
| 281 | */ | 155 | */ |
| 282 | asmlinkage void do_IRQ(void) | 156 | asmlinkage void do_IRQ(void) |
| 283 | { | 157 | { |
| 284 | struct irq_source *source; | ||
| 285 | int level, cpu; | ||
| 286 | |||
| 287 | irq_enter(); | 158 | irq_enter(); |
| 288 | 159 | __do_IRQ(__get_IRL(), __frame); | |
| 289 | level = (__frame->tbr >> 4) & 0xf; | ||
| 290 | cpu = smp_processor_id(); | ||
| 291 | |||
| 292 | if ((unsigned long) __frame - (unsigned long) (current + 1) < 512) | ||
| 293 | BUG(); | ||
| 294 | |||
| 295 | __set_MASK(level); | ||
| 296 | __clr_RC(level); | ||
| 297 | __clr_IRL(); | ||
| 298 | |||
| 299 | kstat_this_cpu.irqs[level]++; | ||
| 300 | |||
| 301 | for (source = frv_irq_levels[level].sources; source; source = source->next) | ||
| 302 | source->doirq(source); | ||
| 303 | |||
| 304 | __clr_MASK(level); | ||
| 305 | |||
| 306 | irq_exit(); | 160 | irq_exit(); |
| 161 | } | ||
| 307 | 162 | ||
| 308 | } /* end do_IRQ() */ | ||
| 309 | |||
| 310 | /*****************************************************************************/ | ||
| 311 | /* | 163 | /* |
| 312 | * handles all NMIs when not co-opted by the debugger | 164 | * handles all NMIs when not co-opted by the debugger |
| 313 | * - registers are referred to by the __frame variable (GR28) | 165 | * - registers are referred to by the __frame variable (GR28) |
| 314 | */ | 166 | */ |
| 315 | asmlinkage void do_NMI(void) | 167 | asmlinkage void do_NMI(void) |
| 316 | { | 168 | { |
| 317 | } /* end do_NMI() */ | ||
| 318 | |||
| 319 | /*****************************************************************************/ | ||
| 320 | /** | ||
| 321 | * request_irq - allocate an interrupt line | ||
| 322 | * @irq: Interrupt line to allocate | ||
| 323 | * @handler: Function to be called when the IRQ occurs | ||
| 324 | * @irqflags: Interrupt type flags | ||
| 325 | * @devname: An ascii name for the claiming device | ||
| 326 | * @dev_id: A cookie passed back to the handler function | ||
| 327 | * | ||
| 328 | * This call allocates interrupt resources and enables the | ||
| 329 | * interrupt line and IRQ handling. From the point this | ||
| 330 | * call is made your handler function may be invoked. Since | ||
| 331 | * your handler function must clear any interrupt the board | ||
| 332 | * raises, you must take care both to initialise your hardware | ||
| 333 | * and to set up the interrupt handler in the right order. | ||
| 334 | * | ||
| 335 | * Dev_id must be globally unique. Normally the address of the | ||
| 336 | * device data structure is used as the cookie. Since the handler | ||
| 337 | * receives this value it makes sense to use it. | ||
| 338 | * | ||
| 339 | * If your interrupt is shared you must pass a non NULL dev_id | ||
| 340 | * as this is required when freeing the interrupt. | ||
| 341 | * | ||
| 342 | * Flags: | ||
| 343 | * | ||
| 344 | * IRQF_SHARED Interrupt is shared | ||
| 345 | * | ||
| 346 | * IRQF_DISABLED Disable local interrupts while processing | ||
| 347 | * | ||
| 348 | * IRQF_SAMPLE_RANDOM The interrupt can be used for entropy | ||
| 349 | * | ||
| 350 | */ | ||
| 351 | |||
| 352 | int request_irq(unsigned int irq, | ||
| 353 | irqreturn_t (*handler)(int, void *, struct pt_regs *), | ||
| 354 | unsigned long irqflags, | ||
| 355 | const char * devname, | ||
| 356 | void *dev_id) | ||
| 357 | { | ||
| 358 | int retval; | ||
| 359 | struct irqaction *action; | ||
| 360 | |||
| 361 | #if 1 | ||
| 362 | /* | ||
| 363 | * Sanity-check: shared interrupts should REALLY pass in | ||
| 364 | * a real dev-ID, otherwise we'll have trouble later trying | ||
| 365 | * to figure out which interrupt is which (messes up the | ||
| 366 | * interrupt freeing logic etc). | ||
| 367 | */ | ||
| 368 | if (irqflags & IRQF_SHARED) { | ||
| 369 | if (!dev_id) | ||
| 370 | printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", | ||
| 371 | devname, (&irq)[-1]); | ||
| 372 | } | ||
| 373 | #endif | ||
| 374 | |||
| 375 | if ((irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP) >= NR_IRQ_GROUPS) | ||
| 376 | return -EINVAL; | ||
| 377 | if (!handler) | ||
| 378 | return -EINVAL; | ||
| 379 | |||
| 380 | action = (struct irqaction *) kmalloc(sizeof(struct irqaction), GFP_KERNEL); | ||
| 381 | if (!action) | ||
| 382 | return -ENOMEM; | ||
| 383 | |||
| 384 | action->handler = handler; | ||
| 385 | action->flags = irqflags; | ||
| 386 | action->mask = CPU_MASK_NONE; | ||
| 387 | action->name = devname; | ||
| 388 | action->next = NULL; | ||
| 389 | action->dev_id = dev_id; | ||
| 390 | |||
| 391 | retval = setup_irq(irq, action); | ||
| 392 | if (retval) | ||
| 393 | kfree(action); | ||
| 394 | return retval; | ||
| 395 | } | ||
| 396 | |||
| 397 | EXPORT_SYMBOL(request_irq); | ||
| 398 | |||
| 399 | /** | ||
| 400 | * free_irq - free an interrupt | ||
| 401 | * @irq: Interrupt line to free | ||
| 402 | * @dev_id: Device identity to free | ||
| 403 | * | ||
| 404 | * Remove an interrupt handler. The handler is removed and if the | ||
| 405 | * interrupt line is no longer in use by any driver it is disabled. | ||
| 406 | * On a shared IRQ the caller must ensure the interrupt is disabled | ||
| 407 | * on the card it drives before calling this function. The function | ||
| 408 | * does not return until any executing interrupts for this IRQ | ||
| 409 | * have completed. | ||
| 410 | * | ||
| 411 | * This function may be called from interrupt context. | ||
| 412 | * | ||
| 413 | * Bugs: Attempting to free an irq in a handler for the same irq hangs | ||
| 414 | * the machine. | ||
| 415 | */ | ||
| 416 | |||
| 417 | void free_irq(unsigned int irq, void *dev_id) | ||
| 418 | { | ||
| 419 | struct irq_source *source; | ||
| 420 | struct irq_group *group; | ||
| 421 | struct irq_level *level; | ||
| 422 | struct irqaction **p, **pp; | ||
| 423 | unsigned long flags; | ||
| 424 | |||
| 425 | if ((irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP) >= NR_IRQ_GROUPS) | ||
| 426 | return; | ||
| 427 | |||
| 428 | group = irq_groups[irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP]; | ||
| 429 | if (!group) | ||
| 430 | BUG(); | ||
| 431 | |||
| 432 | source = group->sources[irq & (NR_IRQ_ACTIONS_PER_GROUP - 1)]; | ||
| 433 | if (!source) | ||
| 434 | BUG(); | ||
| 435 | |||
| 436 | level = source->level; | ||
| 437 | p = &group->actions[irq & (NR_IRQ_ACTIONS_PER_GROUP - 1)]; | ||
| 438 | |||
| 439 | spin_lock_irqsave(&level->lock, flags); | ||
| 440 | |||
| 441 | for (pp = p; *pp; pp = &(*pp)->next) { | ||
| 442 | struct irqaction *action = *pp; | ||
| 443 | |||
| 444 | if (action->dev_id != dev_id) | ||
| 445 | continue; | ||
| 446 | |||
| 447 | /* found it - remove from the list of entries */ | ||
| 448 | *pp = action->next; | ||
| 449 | |||
| 450 | level->usage--; | ||
| 451 | |||
| 452 | if (p == pp && group->control) | ||
| 453 | group->control(group, irq & (NR_IRQ_ACTIONS_PER_GROUP - 1), 0); | ||
| 454 | |||
| 455 | if (level->usage == 0) | ||
| 456 | __set_MASK(level - frv_irq_levels); | ||
| 457 | |||
| 458 | spin_unlock_irqrestore(&level->lock,flags); | ||
| 459 | |||
| 460 | #ifdef CONFIG_SMP | ||
| 461 | /* Wait to make sure it's not being used on another CPU */ | ||
| 462 | while (desc->status & IRQ_INPROGRESS) | ||
| 463 | barrier(); | ||
| 464 | #endif | ||
| 465 | kfree(action); | ||
| 466 | return; | ||
| 467 | } | ||
| 468 | } | ||
| 469 | |||
| 470 | EXPORT_SYMBOL(free_irq); | ||
| 471 | |||
| 472 | /* | ||
| 473 | * IRQ autodetection code.. | ||
| 474 | * | ||
| 475 | * This depends on the fact that any interrupt that comes in on to an | ||
| 476 | * unassigned IRQ will cause GxICR_DETECT to be set | ||
| 477 | */ | ||
| 478 | |||
| 479 | static DECLARE_MUTEX(probe_sem); | ||
| 480 | |||
| 481 | /** | ||
| 482 | * probe_irq_on - begin an interrupt autodetect | ||
| 483 | * | ||
| 484 | * Commence probing for an interrupt. The interrupts are scanned | ||
| 485 | * and a mask of potential interrupt lines is returned. | ||
| 486 | * | ||
| 487 | */ | ||
| 488 | |||
| 489 | unsigned long probe_irq_on(void) | ||
| 490 | { | ||
| 491 | down(&probe_sem); | ||
| 492 | return 0; | ||
| 493 | } | 169 | } |
| 494 | 170 | ||
| 495 | EXPORT_SYMBOL(probe_irq_on); | ||
| 496 | |||
| 497 | /* | ||
| 498 | * Return a mask of triggered interrupts (this | ||
| 499 | * can handle only legacy ISA interrupts). | ||
| 500 | */ | ||
| 501 | |||
| 502 | /** | ||
| 503 | * probe_irq_mask - scan a bitmap of interrupt lines | ||
| 504 | * @val: mask of interrupts to consider | ||
| 505 | * | ||
| 506 | * Scan the ISA bus interrupt lines and return a bitmap of | ||
| 507 | * active interrupts. The interrupt probe logic state is then | ||
| 508 | * returned to its previous value. | ||
| 509 | * | ||
| 510 | * Note: we need to scan all the irq's even though we will | ||
| 511 | * only return ISA irq numbers - just so that we reset them | ||
| 512 | * all to a known state. | ||
| 513 | */ | ||
| 514 | unsigned int probe_irq_mask(unsigned long xmask) | ||
| 515 | { | ||
| 516 | up(&probe_sem); | ||
| 517 | return 0; | ||
| 518 | } | ||
| 519 | |||
| 520 | EXPORT_SYMBOL(probe_irq_mask); | ||
| 521 | |||
| 522 | /* | 171 | /* |
| 523 | * Return the one interrupt that triggered (this can | 172 | * initialise the interrupt system |
| 524 | * handle any interrupt source). | ||
| 525 | */ | ||
| 526 | |||
| 527 | /** | ||
| 528 | * probe_irq_off - end an interrupt autodetect | ||
| 529 | * @xmask: mask of potential interrupts (unused) | ||
| 530 | * | ||
| 531 | * Scans the unused interrupt lines and returns the line which | ||
| 532 | * appears to have triggered the interrupt. If no interrupt was | ||
| 533 | * found then zero is returned. If more than one interrupt is | ||
| 534 | * found then minus the first candidate is returned to indicate | ||
| 535 | * their is doubt. | ||
| 536 | * | ||
| 537 | * The interrupt probe logic state is returned to its previous | ||
| 538 | * value. | ||
| 539 | * | ||
| 540 | * BUGS: When used in a module (which arguably shouldnt happen) | ||
| 541 | * nothing prevents two IRQ probe callers from overlapping. The | ||
| 542 | * results of this are non-optimal. | ||
| 543 | */ | 173 | */ |
| 544 | 174 | void __init init_IRQ(void) | |
| 545 | int probe_irq_off(unsigned long xmask) | ||
| 546 | { | ||
| 547 | up(&probe_sem); | ||
| 548 | return -1; | ||
| 549 | } | ||
| 550 | |||
| 551 | EXPORT_SYMBOL(probe_irq_off); | ||
| 552 | |||
| 553 | /* this was setup_x86_irq but it seems pretty generic */ | ||
| 554 | int setup_irq(unsigned int irq, struct irqaction *new) | ||
| 555 | { | ||
| 556 | struct irq_source *source; | ||
| 557 | struct irq_group *group; | ||
| 558 | struct irq_level *level; | ||
| 559 | struct irqaction **p, **pp; | ||
| 560 | unsigned long flags; | ||
| 561 | |||
| 562 | group = irq_groups[irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP]; | ||
| 563 | if (!group) | ||
| 564 | BUG(); | ||
| 565 | |||
| 566 | source = group->sources[irq & (NR_IRQ_ACTIONS_PER_GROUP - 1)]; | ||
| 567 | if (!source) | ||
| 568 | BUG(); | ||
| 569 | |||
| 570 | level = source->level; | ||
| 571 | |||
| 572 | p = &group->actions[irq & (NR_IRQ_ACTIONS_PER_GROUP - 1)]; | ||
| 573 | |||
| 574 | /* | ||
| 575 | * Some drivers like serial.c use request_irq() heavily, | ||
| 576 | * so we have to be careful not to interfere with a | ||
| 577 | * running system. | ||
| 578 | */ | ||
| 579 | if (new->flags & IRQF_SAMPLE_RANDOM) { | ||
| 580 | /* | ||
| 581 | * This function might sleep, we want to call it first, | ||
| 582 | * outside of the atomic block. | ||
| 583 | * Yes, this might clear the entropy pool if the wrong | ||
| 584 | * driver is attempted to be loaded, without actually | ||
| 585 | * installing a new handler, but is this really a problem, | ||
| 586 | * only the sysadmin is able to do this. | ||
| 587 | */ | ||
| 588 | rand_initialize_irq(irq); | ||
| 589 | } | ||
| 590 | |||
| 591 | /* must juggle the interrupt processing stuff with interrupts disabled */ | ||
| 592 | spin_lock_irqsave(&level->lock, flags); | ||
| 593 | |||
| 594 | /* can't share interrupts unless all parties agree to */ | ||
| 595 | if (level->usage != 0 && !(level->flags & new->flags & IRQF_SHARED)) { | ||
| 596 | spin_unlock_irqrestore(&level->lock,flags); | ||
| 597 | return -EBUSY; | ||
| 598 | } | ||
| 599 | |||
| 600 | /* add new interrupt at end of irq queue */ | ||
| 601 | pp = p; | ||
| 602 | while (*pp) | ||
| 603 | pp = &(*pp)->next; | ||
| 604 | |||
| 605 | *pp = new; | ||
| 606 | |||
| 607 | level->usage++; | ||
| 608 | level->flags = new->flags; | ||
| 609 | |||
| 610 | /* turn the interrupts on */ | ||
| 611 | if (level->usage == 1) | ||
| 612 | __clr_MASK(level - frv_irq_levels); | ||
| 613 | |||
| 614 | if (p == pp && group->control) | ||
| 615 | group->control(group, irq & (NR_IRQ_ACTIONS_PER_GROUP - 1), 1); | ||
| 616 | |||
| 617 | spin_unlock_irqrestore(&level->lock, flags); | ||
| 618 | register_irq_proc(irq); | ||
| 619 | return 0; | ||
| 620 | } | ||
| 621 | |||
| 622 | static struct proc_dir_entry * root_irq_dir; | ||
| 623 | static struct proc_dir_entry * irq_dir [NR_IRQS]; | ||
| 624 | |||
| 625 | #define HEX_DIGITS 8 | ||
| 626 | |||
| 627 | static unsigned int parse_hex_value (const char __user *buffer, | ||
| 628 | unsigned long count, unsigned long *ret) | ||
| 629 | { | ||
| 630 | unsigned char hexnum [HEX_DIGITS]; | ||
| 631 | unsigned long value; | ||
| 632 | int i; | ||
| 633 | |||
| 634 | if (!count) | ||
| 635 | return -EINVAL; | ||
| 636 | if (count > HEX_DIGITS) | ||
| 637 | count = HEX_DIGITS; | ||
| 638 | if (copy_from_user(hexnum, buffer, count)) | ||
| 639 | return -EFAULT; | ||
| 640 | |||
| 641 | /* | ||
| 642 | * Parse the first 8 characters as a hex string, any non-hex char | ||
| 643 | * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same. | ||
| 644 | */ | ||
| 645 | value = 0; | ||
| 646 | |||
| 647 | for (i = 0; i < count; i++) { | ||
| 648 | unsigned int c = hexnum[i]; | ||
| 649 | |||
| 650 | switch (c) { | ||
| 651 | case '0' ... '9': c -= '0'; break; | ||
| 652 | case 'a' ... 'f': c -= 'a'-10; break; | ||
| 653 | case 'A' ... 'F': c -= 'A'-10; break; | ||
| 654 | default: | ||
| 655 | goto out; | ||
| 656 | } | ||
| 657 | value = (value << 4) | c; | ||
| 658 | } | ||
| 659 | out: | ||
| 660 | *ret = value; | ||
| 661 | return 0; | ||
| 662 | } | ||
| 663 | |||
| 664 | |||
| 665 | static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, | ||
| 666 | int count, int *eof, void *data) | ||
| 667 | { | ||
| 668 | unsigned long *mask = (unsigned long *) data; | ||
| 669 | if (count < HEX_DIGITS+1) | ||
| 670 | return -EINVAL; | ||
| 671 | return sprintf (page, "%08lx\n", *mask); | ||
| 672 | } | ||
| 673 | |||
| 674 | static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer, | ||
| 675 | unsigned long count, void *data) | ||
| 676 | { | ||
| 677 | unsigned long *mask = (unsigned long *) data, full_count = count, err; | ||
| 678 | unsigned long new_value; | ||
| 679 | |||
| 680 | show_state(); | ||
| 681 | err = parse_hex_value(buffer, count, &new_value); | ||
| 682 | if (err) | ||
| 683 | return err; | ||
| 684 | |||
| 685 | *mask = new_value; | ||
| 686 | return full_count; | ||
| 687 | } | ||
| 688 | |||
| 689 | #define MAX_NAMELEN 10 | ||
| 690 | |||
| 691 | static void register_irq_proc (unsigned int irq) | ||
| 692 | { | ||
| 693 | char name [MAX_NAMELEN]; | ||
| 694 | |||
| 695 | if (!root_irq_dir || irq_dir[irq]) | ||
| 696 | return; | ||
| 697 | |||
| 698 | memset(name, 0, MAX_NAMELEN); | ||
| 699 | sprintf(name, "%d", irq); | ||
| 700 | |||
| 701 | /* create /proc/irq/1234 */ | ||
| 702 | irq_dir[irq] = proc_mkdir(name, root_irq_dir); | ||
| 703 | } | ||
| 704 | |||
| 705 | unsigned long prof_cpu_mask = -1; | ||
| 706 | |||
| 707 | void init_irq_proc (void) | ||
| 708 | { | 175 | { |
| 709 | struct proc_dir_entry *entry; | 176 | int level; |
| 710 | int i; | ||
| 711 | 177 | ||
| 712 | /* create /proc/irq */ | 178 | for (level = 1; level <= 14; level++) |
| 713 | root_irq_dir = proc_mkdir("irq", NULL); | 179 | set_irq_chip_and_handler(level, &frv_cpu_pic, |
| 180 | handle_level_irq); | ||
| 714 | 181 | ||
| 715 | /* create /proc/irq/prof_cpu_mask */ | 182 | set_irq_handler(IRQ_CPU_TIMER0, handle_edge_irq); |
| 716 | entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); | ||
| 717 | if (!entry) | ||
| 718 | return; | ||
| 719 | 183 | ||
| 720 | entry->nlink = 1; | 184 | /* set the trigger levels for internal interrupt sources |
| 721 | entry->data = (void *)&prof_cpu_mask; | 185 | * - timers all falling-edge |
| 722 | entry->read_proc = prof_cpu_mask_read_proc; | 186 | * - ERR0 is rising-edge |
| 723 | entry->write_proc = prof_cpu_mask_write_proc; | 187 | * - all others are high-level |
| 724 | |||
| 725 | /* | ||
| 726 | * Create entries for all existing IRQs. | ||
| 727 | */ | 188 | */ |
| 728 | for (i = 0; i < NR_IRQS; i++) | 189 | __set_IITMR(0, 0x003f0000); /* DMA0-3, TIMER0-2 */ |
| 729 | register_irq_proc(i); | 190 | __set_IITMR(1, 0x20000000); /* ERR0-1, UART0-1, DMA4-7 */ |
| 730 | } | 191 | |
| 192 | /* route internal interrupts */ | ||
| 193 | set_IRR(4, IRQ_DMA3_LEVEL, IRQ_DMA2_LEVEL, IRQ_DMA1_LEVEL, | ||
| 194 | IRQ_DMA0_LEVEL); | ||
| 195 | set_IRR(5, 0, IRQ_TIMER2_LEVEL, IRQ_TIMER1_LEVEL, IRQ_TIMER0_LEVEL); | ||
| 196 | set_IRR(6, IRQ_GDBSTUB_LEVEL, IRQ_GDBSTUB_LEVEL, | ||
| 197 | IRQ_UART1_LEVEL, IRQ_UART0_LEVEL); | ||
| 198 | set_IRR(7, IRQ_DMA7_LEVEL, IRQ_DMA6_LEVEL, IRQ_DMA5_LEVEL, | ||
| 199 | IRQ_DMA4_LEVEL); | ||
| 200 | |||
| 201 | /* route external interrupts */ | ||
| 202 | set_IRR(2, IRQ_XIRQ7_LEVEL, IRQ_XIRQ6_LEVEL, IRQ_XIRQ5_LEVEL, | ||
| 203 | IRQ_XIRQ4_LEVEL); | ||
| 204 | set_IRR(3, IRQ_XIRQ3_LEVEL, IRQ_XIRQ2_LEVEL, IRQ_XIRQ1_LEVEL, | ||
| 205 | IRQ_XIRQ0_LEVEL); | ||
| 206 | |||
| 207 | #if defined(CONFIG_MB93091_VDK) | ||
| 208 | __set_TM1(0x55550000); /* XIRQ7-0 all active low */ | ||
| 209 | #elif defined(CONFIG_MB93093_PDK) | ||
| 210 | __set_TM1(0x15550000); /* XIRQ7 active high, 6-0 all active low */ | ||
| 211 | #else | ||
| 212 | #error dont know external IRQ trigger levels for this setup | ||
| 213 | #endif | ||
| 731 | 214 | ||
| 732 | /*****************************************************************************/ | ||
| 733 | /* | ||
| 734 | * initialise the interrupt system | ||
| 735 | */ | ||
| 736 | void __init init_IRQ(void) | ||
| 737 | { | ||
| 738 | route_cpu_irqs(); | ||
| 739 | fpga_init(); | 215 | fpga_init(); |
| 740 | #ifdef CONFIG_FUJITSU_MB93493 | 216 | #ifdef CONFIG_FUJITSU_MB93493 |
| 741 | route_mb93493_irqs(); | 217 | mb93493_init(); |
| 742 | #endif | 218 | #endif |
| 743 | } /* end init_IRQ() */ | 219 | } |
diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c index af08ccd4ed6e..d96a57e5f030 100644 --- a/arch/frv/kernel/setup.c +++ b/arch/frv/kernel/setup.c | |||
| @@ -43,7 +43,6 @@ | |||
| 43 | #include <asm/mb-regs.h> | 43 | #include <asm/mb-regs.h> |
| 44 | #include <asm/mb93493-regs.h> | 44 | #include <asm/mb93493-regs.h> |
| 45 | #include <asm/gdb-stub.h> | 45 | #include <asm/gdb-stub.h> |
| 46 | #include <asm/irq-routing.h> | ||
| 47 | #include <asm/io.h> | 46 | #include <asm/io.h> |
| 48 | 47 | ||
| 49 | #ifdef CONFIG_BLK_DEV_INITRD | 48 | #ifdef CONFIG_BLK_DEV_INITRD |
diff --git a/arch/frv/kernel/time.c b/arch/frv/kernel/time.c index 68a77fe3bb40..3d0284bccb94 100644 --- a/arch/frv/kernel/time.c +++ b/arch/frv/kernel/time.c | |||
| @@ -26,7 +26,6 @@ | |||
| 26 | #include <asm/timer-regs.h> | 26 | #include <asm/timer-regs.h> |
| 27 | #include <asm/mb-regs.h> | 27 | #include <asm/mb-regs.h> |
| 28 | #include <asm/mb86943a.h> | 28 | #include <asm/mb86943a.h> |
| 29 | #include <asm/irq-routing.h> | ||
| 30 | 29 | ||
| 31 | #include <linux/timex.h> | 30 | #include <linux/timex.h> |
| 32 | 31 | ||
diff --git a/arch/frv/mb93090-mb00/pci-irq.c b/arch/frv/mb93090-mb00/pci-irq.c index 2278c80bd88c..ba587523c015 100644 --- a/arch/frv/mb93090-mb00/pci-irq.c +++ b/arch/frv/mb93090-mb00/pci-irq.c | |||
| @@ -15,7 +15,6 @@ | |||
| 15 | 15 | ||
| 16 | #include <asm/io.h> | 16 | #include <asm/io.h> |
| 17 | #include <asm/smp.h> | 17 | #include <asm/smp.h> |
| 18 | #include <asm/irq-routing.h> | ||
| 19 | 18 | ||
| 20 | #include "pci-frv.h" | 19 | #include "pci-frv.h" |
| 21 | 20 | ||
diff --git a/include/asm-frv/cpu-irqs.h b/include/asm-frv/cpu-irqs.h index 5cd691e1f8c4..478f3498fcfe 100644 --- a/include/asm-frv/cpu-irqs.h +++ b/include/asm-frv/cpu-irqs.h | |||
| @@ -14,36 +14,6 @@ | |||
| 14 | 14 | ||
| 15 | #ifndef __ASSEMBLY__ | 15 | #ifndef __ASSEMBLY__ |
| 16 | 16 | ||
| 17 | #include <asm/irq-routing.h> | ||
| 18 | |||
| 19 | #define IRQ_BASE_CPU (NR_IRQ_ACTIONS_PER_GROUP * 0) | ||
| 20 | |||
| 21 | /* IRQ IDs presented to drivers */ | ||
| 22 | enum { | ||
| 23 | IRQ_CPU__UNUSED = IRQ_BASE_CPU, | ||
| 24 | IRQ_CPU_UART0, | ||
| 25 | IRQ_CPU_UART1, | ||
| 26 | IRQ_CPU_TIMER0, | ||
| 27 | IRQ_CPU_TIMER1, | ||
| 28 | IRQ_CPU_TIMER2, | ||
| 29 | IRQ_CPU_DMA0, | ||
| 30 | IRQ_CPU_DMA1, | ||
| 31 | IRQ_CPU_DMA2, | ||
| 32 | IRQ_CPU_DMA3, | ||
| 33 | IRQ_CPU_DMA4, | ||
| 34 | IRQ_CPU_DMA5, | ||
| 35 | IRQ_CPU_DMA6, | ||
| 36 | IRQ_CPU_DMA7, | ||
| 37 | IRQ_CPU_EXTERNAL0, | ||
| 38 | IRQ_CPU_EXTERNAL1, | ||
| 39 | IRQ_CPU_EXTERNAL2, | ||
| 40 | IRQ_CPU_EXTERNAL3, | ||
| 41 | IRQ_CPU_EXTERNAL4, | ||
| 42 | IRQ_CPU_EXTERNAL5, | ||
| 43 | IRQ_CPU_EXTERNAL6, | ||
| 44 | IRQ_CPU_EXTERNAL7, | ||
| 45 | }; | ||
| 46 | |||
| 47 | /* IRQ to level mappings */ | 17 | /* IRQ to level mappings */ |
| 48 | #define IRQ_GDBSTUB_LEVEL 15 | 18 | #define IRQ_GDBSTUB_LEVEL 15 |
| 49 | #define IRQ_UART_LEVEL 13 | 19 | #define IRQ_UART_LEVEL 13 |
| @@ -82,6 +52,30 @@ enum { | |||
| 82 | #define IRQ_XIRQ6_LEVEL 7 | 52 | #define IRQ_XIRQ6_LEVEL 7 |
| 83 | #define IRQ_XIRQ7_LEVEL 8 | 53 | #define IRQ_XIRQ7_LEVEL 8 |
| 84 | 54 | ||
| 55 | /* IRQ IDs presented to drivers */ | ||
| 56 | #define IRQ_CPU__UNUSED IRQ_BASE_CPU | ||
| 57 | #define IRQ_CPU_UART0 (IRQ_BASE_CPU + IRQ_UART0_LEVEL) | ||
| 58 | #define IRQ_CPU_UART1 (IRQ_BASE_CPU + IRQ_UART1_LEVEL) | ||
| 59 | #define IRQ_CPU_TIMER0 (IRQ_BASE_CPU + IRQ_TIMER0_LEVEL) | ||
| 60 | #define IRQ_CPU_TIMER1 (IRQ_BASE_CPU + IRQ_TIMER1_LEVEL) | ||
| 61 | #define IRQ_CPU_TIMER2 (IRQ_BASE_CPU + IRQ_TIMER2_LEVEL) | ||
| 62 | #define IRQ_CPU_DMA0 (IRQ_BASE_CPU + IRQ_DMA0_LEVEL) | ||
| 63 | #define IRQ_CPU_DMA1 (IRQ_BASE_CPU + IRQ_DMA1_LEVEL) | ||
| 64 | #define IRQ_CPU_DMA2 (IRQ_BASE_CPU + IRQ_DMA2_LEVEL) | ||
| 65 | #define IRQ_CPU_DMA3 (IRQ_BASE_CPU + IRQ_DMA3_LEVEL) | ||
| 66 | #define IRQ_CPU_DMA4 (IRQ_BASE_CPU + IRQ_DMA4_LEVEL) | ||
| 67 | #define IRQ_CPU_DMA5 (IRQ_BASE_CPU + IRQ_DMA5_LEVEL) | ||
| 68 | #define IRQ_CPU_DMA6 (IRQ_BASE_CPU + IRQ_DMA6_LEVEL) | ||
| 69 | #define IRQ_CPU_DMA7 (IRQ_BASE_CPU + IRQ_DMA7_LEVEL) | ||
| 70 | #define IRQ_CPU_EXTERNAL0 (IRQ_BASE_CPU + IRQ_XIRQ0_LEVEL) | ||
| 71 | #define IRQ_CPU_EXTERNAL1 (IRQ_BASE_CPU + IRQ_XIRQ1_LEVEL) | ||
| 72 | #define IRQ_CPU_EXTERNAL2 (IRQ_BASE_CPU + IRQ_XIRQ2_LEVEL) | ||
| 73 | #define IRQ_CPU_EXTERNAL3 (IRQ_BASE_CPU + IRQ_XIRQ3_LEVEL) | ||
| 74 | #define IRQ_CPU_EXTERNAL4 (IRQ_BASE_CPU + IRQ_XIRQ4_LEVEL) | ||
| 75 | #define IRQ_CPU_EXTERNAL5 (IRQ_BASE_CPU + IRQ_XIRQ5_LEVEL) | ||
| 76 | #define IRQ_CPU_EXTERNAL6 (IRQ_BASE_CPU + IRQ_XIRQ6_LEVEL) | ||
| 77 | #define IRQ_CPU_EXTERNAL7 (IRQ_BASE_CPU + IRQ_XIRQ7_LEVEL) | ||
| 78 | |||
| 85 | #endif /* !__ASSEMBLY__ */ | 79 | #endif /* !__ASSEMBLY__ */ |
| 86 | 80 | ||
| 87 | #endif /* _ASM_CPU_IRQS_H */ | 81 | #endif /* _ASM_CPU_IRQS_H */ |
diff --git a/include/asm-frv/hardirq.h b/include/asm-frv/hardirq.h index 7581b5a7559a..fc47515822a2 100644 --- a/include/asm-frv/hardirq.h +++ b/include/asm-frv/hardirq.h | |||
| @@ -26,5 +26,10 @@ typedef struct { | |||
| 26 | #error SMP not available on FR-V | 26 | #error SMP not available on FR-V |
| 27 | #endif /* CONFIG_SMP */ | 27 | #endif /* CONFIG_SMP */ |
| 28 | 28 | ||
| 29 | extern atomic_t irq_err_count; | ||
| 30 | static inline void ack_bad_irq(int irq) | ||
| 31 | { | ||
| 32 | atomic_inc(&irq_err_count); | ||
| 33 | } | ||
| 29 | 34 | ||
| 30 | #endif | 35 | #endif |
diff --git a/include/asm-frv/irq-routing.h b/include/asm-frv/irq-routing.h deleted file mode 100644 index ac3ab900a1dc..000000000000 --- a/include/asm-frv/irq-routing.h +++ /dev/null | |||
| @@ -1,70 +0,0 @@ | |||
| 1 | /* irq-routing.h: multiplexed IRQ routing | ||
| 2 | * | ||
| 3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the License, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef _ASM_IRQ_ROUTING_H | ||
| 13 | #define _ASM_IRQ_ROUTING_H | ||
| 14 | |||
| 15 | #ifndef __ASSEMBLY__ | ||
| 16 | |||
| 17 | #include <linux/spinlock.h> | ||
| 18 | #include <asm/irq.h> | ||
| 19 | |||
| 20 | struct irq_source; | ||
| 21 | struct irq_level; | ||
| 22 | |||
| 23 | /* | ||
| 24 | * IRQ action distribution sets | ||
| 25 | */ | ||
| 26 | struct irq_group { | ||
| 27 | int first_irq; /* first IRQ distributed here */ | ||
| 28 | void (*control)(struct irq_group *group, int index, int on); | ||
| 29 | |||
| 30 | struct irqaction *actions[NR_IRQ_ACTIONS_PER_GROUP]; /* IRQ action chains */ | ||
| 31 | struct irq_source *sources[NR_IRQ_ACTIONS_PER_GROUP]; /* IRQ sources */ | ||
| 32 | int disable_cnt[NR_IRQ_ACTIONS_PER_GROUP]; /* disable counts */ | ||
| 33 | }; | ||
| 34 | |||
| 35 | /* | ||
| 36 | * IRQ source manager | ||
| 37 | */ | ||
| 38 | struct irq_source { | ||
| 39 | struct irq_source *next; | ||
| 40 | struct irq_level *level; | ||
| 41 | const char *muxname; | ||
| 42 | volatile void __iomem *muxdata; | ||
| 43 | unsigned long irqmask; | ||
| 44 | |||
| 45 | void (*doirq)(struct irq_source *source); | ||
| 46 | }; | ||
| 47 | |||
| 48 | /* | ||
| 49 | * IRQ level management (per CPU IRQ priority / entry vector) | ||
| 50 | */ | ||
| 51 | struct irq_level { | ||
| 52 | int usage; | ||
| 53 | int disable_count; | ||
| 54 | unsigned long flags; /* current IRQF_DISABLED and IRQF_SHARED settings */ | ||
| 55 | spinlock_t lock; | ||
| 56 | struct irq_source *sources; | ||
| 57 | }; | ||
| 58 | |||
| 59 | extern struct irq_level frv_irq_levels[16]; | ||
| 60 | extern struct irq_group *irq_groups[NR_IRQ_GROUPS]; | ||
| 61 | |||
| 62 | extern void frv_irq_route(struct irq_source *source, int irqlevel); | ||
| 63 | extern void frv_irq_route_external(struct irq_source *source, int irq); | ||
| 64 | extern void frv_irq_set_group(struct irq_group *group); | ||
| 65 | extern void distribute_irqs(struct irq_group *group, unsigned long irqmask); | ||
| 66 | extern void route_cpu_irqs(void); | ||
| 67 | |||
| 68 | #endif /* !__ASSEMBLY__ */ | ||
| 69 | |||
| 70 | #endif /* _ASM_IRQ_ROUTING_H */ | ||
diff --git a/include/asm-frv/irq.h b/include/asm-frv/irq.h index 58b619215a50..8fefd6b827aa 100644 --- a/include/asm-frv/irq.h +++ b/include/asm-frv/irq.h | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* irq.h: FRV IRQ definitions | 1 | /* irq.h: FRV IRQ definitions |
| 2 | * | 2 | * |
| 3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. |
| 4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
| @@ -12,32 +12,22 @@ | |||
| 12 | #ifndef _ASM_IRQ_H_ | 12 | #ifndef _ASM_IRQ_H_ |
| 13 | #define _ASM_IRQ_H_ | 13 | #define _ASM_IRQ_H_ |
| 14 | 14 | ||
| 15 | |||
| 16 | /* | ||
| 17 | * the system has an on-CPU PIC and another PIC on the FPGA and other PICs on other peripherals, | ||
| 18 | * so we do some routing in irq-routing.[ch] to reduce the number of false-positives seen by | ||
| 19 | * drivers | ||
| 20 | */ | ||
| 21 | |||
| 22 | /* this number is used when no interrupt has been assigned */ | 15 | /* this number is used when no interrupt has been assigned */ |
| 23 | #define NO_IRQ (-1) | 16 | #define NO_IRQ (-1) |
| 24 | 17 | ||
| 25 | #define NR_IRQ_LOG2_ACTIONS_PER_GROUP 5 | 18 | #define NR_IRQS 48 |
| 26 | #define NR_IRQ_ACTIONS_PER_GROUP (1 << NR_IRQ_LOG2_ACTIONS_PER_GROUP) | 19 | #define IRQ_BASE_CPU (0 * 16) |
| 27 | #define NR_IRQ_GROUPS 4 | 20 | #define IRQ_BASE_FPGA (1 * 16) |
| 28 | #define NR_IRQS (NR_IRQ_ACTIONS_PER_GROUP * NR_IRQ_GROUPS) | 21 | #define IRQ_BASE_MB93493 (2 * 16) |
| 29 | 22 | ||
| 30 | /* probe returns a 32-bit IRQ mask:-/ */ | 23 | /* probe returns a 32-bit IRQ mask:-/ */ |
| 31 | #define MIN_PROBE_IRQ (NR_IRQS - 32) | 24 | #define MIN_PROBE_IRQ (NR_IRQS - 32) |
| 32 | 25 | ||
| 26 | #ifndef __ASSEMBLY__ | ||
| 33 | static inline int irq_canonicalize(int irq) | 27 | static inline int irq_canonicalize(int irq) |
| 34 | { | 28 | { |
| 35 | return irq; | 29 | return irq; |
| 36 | } | 30 | } |
| 37 | 31 | #endif | |
| 38 | extern void disable_irq_nosync(unsigned int irq); | ||
| 39 | extern void disable_irq(unsigned int irq); | ||
| 40 | extern void enable_irq(unsigned int irq); | ||
| 41 | |||
| 42 | 32 | ||
| 43 | #endif /* _ASM_IRQ_H_ */ | 33 | #endif /* _ASM_IRQ_H_ */ |
diff --git a/include/asm-frv/mb93091-fpga-irqs.h b/include/asm-frv/mb93091-fpga-irqs.h index 341bfc52a0eb..19778c5ba9d6 100644 --- a/include/asm-frv/mb93091-fpga-irqs.h +++ b/include/asm-frv/mb93091-fpga-irqs.h | |||
| @@ -12,11 +12,9 @@ | |||
| 12 | #ifndef _ASM_MB93091_FPGA_IRQS_H | 12 | #ifndef _ASM_MB93091_FPGA_IRQS_H |
| 13 | #define _ASM_MB93091_FPGA_IRQS_H | 13 | #define _ASM_MB93091_FPGA_IRQS_H |
| 14 | 14 | ||
| 15 | #ifndef __ASSEMBLY__ | 15 | #include <asm/irq.h> |
| 16 | |||
| 17 | #include <asm/irq-routing.h> | ||
| 18 | 16 | ||
| 19 | #define IRQ_BASE_FPGA (NR_IRQ_ACTIONS_PER_GROUP * 1) | 17 | #ifndef __ASSEMBLY__ |
| 20 | 18 | ||
| 21 | /* IRQ IDs presented to drivers */ | 19 | /* IRQ IDs presented to drivers */ |
| 22 | enum { | 20 | enum { |
diff --git a/include/asm-frv/mb93093-fpga-irqs.h b/include/asm-frv/mb93093-fpga-irqs.h index 1e0f11c2fcdb..590266b1a6d3 100644 --- a/include/asm-frv/mb93093-fpga-irqs.h +++ b/include/asm-frv/mb93093-fpga-irqs.h | |||
| @@ -12,11 +12,9 @@ | |||
| 12 | #ifndef _ASM_MB93093_FPGA_IRQS_H | 12 | #ifndef _ASM_MB93093_FPGA_IRQS_H |
| 13 | #define _ASM_MB93093_FPGA_IRQS_H | 13 | #define _ASM_MB93093_FPGA_IRQS_H |
| 14 | 14 | ||
| 15 | #ifndef __ASSEMBLY__ | 15 | #include <asm/irq.h> |
| 16 | |||
| 17 | #include <asm/irq-routing.h> | ||
| 18 | 16 | ||
| 19 | #define IRQ_BASE_FPGA (NR_IRQ_ACTIONS_PER_GROUP * 1) | 17 | #ifndef __ASSEMBLY__ |
| 20 | 18 | ||
| 21 | /* IRQ IDs presented to drivers */ | 19 | /* IRQ IDs presented to drivers */ |
| 22 | enum { | 20 | enum { |
diff --git a/include/asm-frv/mb93493-irqs.h b/include/asm-frv/mb93493-irqs.h index 15096e731325..82c7aeddd333 100644 --- a/include/asm-frv/mb93493-irqs.h +++ b/include/asm-frv/mb93493-irqs.h | |||
| @@ -12,11 +12,9 @@ | |||
| 12 | #ifndef _ASM_MB93493_IRQS_H | 12 | #ifndef _ASM_MB93493_IRQS_H |
| 13 | #define _ASM_MB93493_IRQS_H | 13 | #define _ASM_MB93493_IRQS_H |
| 14 | 14 | ||
| 15 | #ifndef __ASSEMBLY__ | 15 | #include <asm/irq.h> |
| 16 | |||
| 17 | #include <asm/irq-routing.h> | ||
| 18 | 16 | ||
| 19 | #define IRQ_BASE_MB93493 (NR_IRQ_ACTIONS_PER_GROUP * 2) | 17 | #ifndef __ASSEMBLY__ |
| 20 | 18 | ||
| 21 | /* IRQ IDs presented to drivers */ | 19 | /* IRQ IDs presented to drivers */ |
| 22 | enum { | 20 | enum { |
diff --git a/include/asm-frv/mb93493-regs.h b/include/asm-frv/mb93493-regs.h index c54aa9d14468..8a1f6aac8cf1 100644 --- a/include/asm-frv/mb93493-regs.h +++ b/include/asm-frv/mb93493-regs.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <asm/mb-regs.h> | 15 | #include <asm/mb-regs.h> |
| 16 | #include <asm/mb93493-irqs.h> | 16 | #include <asm/mb93493-irqs.h> |
| 17 | 17 | ||
| 18 | #define __addr_MB93493(X) ((volatile unsigned long *)(__region_CS3 + (X))) | ||
| 18 | #define __get_MB93493(X) ({ *(volatile unsigned long *)(__region_CS3 + (X)); }) | 19 | #define __get_MB93493(X) ({ *(volatile unsigned long *)(__region_CS3 + (X)); }) |
| 19 | 20 | ||
| 20 | #define __set_MB93493(X,V) \ | 21 | #define __set_MB93493(X,V) \ |
| @@ -26,6 +27,7 @@ do { \ | |||
| 26 | #define __set_MB93493_STSR(X,V) __set_MB93493(0x3c0 + (X) * 4, (V)) | 27 | #define __set_MB93493_STSR(X,V) __set_MB93493(0x3c0 + (X) * 4, (V)) |
| 27 | #define MB93493_STSR_EN | 28 | #define MB93493_STSR_EN |
| 28 | 29 | ||
| 30 | #define __addr_MB93493_IQSR(X) __addr_MB93493(0x3d0 + (X) * 4) | ||
| 29 | #define __get_MB93493_IQSR(X) __get_MB93493(0x3d0 + (X) * 4) | 31 | #define __get_MB93493_IQSR(X) __get_MB93493(0x3d0 + (X) * 4) |
| 30 | #define __set_MB93493_IQSR(X,V) __set_MB93493(0x3d0 + (X) * 4, (V)) | 32 | #define __set_MB93493_IQSR(X,V) __set_MB93493(0x3d0 + (X) * 4, (V)) |
| 31 | 33 | ||
