diff options
author | David Howells <dhowells@redhat.com> | 2006-09-26 02:32:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-26 11:48:53 -0400 |
commit | 1bcbba306048ed86b935d57a95d887c23d52c94b (patch) | |
tree | 4c6e20b162415c79a177b72b97b6fb4d246a73b0 /arch/frv/kernel | |
parent | 8d6b5eeea5eb644232cbbbe1c927fdf051e60fa5 (diff) |
[PATCH] FRV: Use the generic IRQ stuff
Make the FRV arch use the generic IRQ code rather than having its own
routines for doing so.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/frv/kernel')
-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 |
8 files changed, 398 insertions, 1089 deletions
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 | ||