aboutsummaryrefslogtreecommitdiffstats
path: root/arch/frv
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-09-26 02:32:04 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-26 11:48:53 -0400
commit1bcbba306048ed86b935d57a95d887c23d52c94b (patch)
tree4c6e20b162415c79a177b72b97b6fb4d246a73b0 /arch/frv
parent8d6b5eeea5eb644232cbbbe1c927fdf051e60fa5 (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')
-rw-r--r--arch/frv/Kconfig8
-rw-r--r--arch/frv/kernel/Makefile5
-rw-r--r--arch/frv/kernel/irq-mb93091.c157
-rw-r--r--arch/frv/kernel/irq-mb93093.c115
-rw-r--r--arch/frv/kernel/irq-mb93493.c167
-rw-r--r--arch/frv/kernel/irq-routing.c291
-rw-r--r--arch/frv/kernel/irq.c750
-rw-r--r--arch/frv/kernel/setup.c1
-rw-r--r--arch/frv/kernel/time.c1
-rw-r--r--arch/frv/mb93090-mb00/pci-irq.c1
10 files changed, 405 insertions, 1091 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
28config GENERIC_HARDIRQS 28config GENERIC_HARDIRQS
29 bool 29 bool
30 default n 30 default y
31 31
32config GENERIC_TIME 32config GENERIC_TIME
33 bool 33 bool
@@ -251,6 +251,12 @@ config MB93091_NO_MB
251endchoice 251endchoice
252endif 252endif
253 253
254config 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
254choice 260choice
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
10obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o kernel_thread.o \ 10obj-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
15obj-$(CONFIG_GDBSTUB) += gdb-stub.o gdb-io.o 15obj-$(CONFIG_GDBSTUB) += gdb-stub.o gdb-io.o
16 16
17obj-$(CONFIG_MB93091_VDK) += irq-mb93091.o 17obj-$(CONFIG_MB93091_VDK) += irq-mb93091.o
18obj-$(CONFIG_MB93093_PDK) += irq-mb93093.o
19obj-$(CONFIG_FUJITSU_MB93493) += irq-mb93493.o
20obj-$(CONFIG_PM) += pm.o cmode.o 18obj-$(CONFIG_PM) += pm.o cmode.o
21obj-$(CONFIG_MB93093_PDK) += pm-mb93093.o 19obj-$(CONFIG_MB93093_PDK) += pm-mb93093.o
20obj-$(CONFIG_FUJITSU_MB93493) += irq-mb93493.o
22obj-$(CONFIG_SYSCTL) += sysctl.o 21obj-$(CONFIG_SYSCTL) += sysctl.o
23obj-$(CONFIG_FUTEX) += futex.o 22obj-$(CONFIG_FUTEX) += futex.o
24obj-$(CONFIG_MODULES) += module.o 23obj-$(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
36static void frv_fpga_doirq(struct irq_source *source);
37static 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 */
43static struct irq_source frv_fpga[4] = { 39static 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
57static 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
79static void frv_fpga_control(struct irq_group *group, int index, int on) 48static 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
91static void frv_fpga_doirq(struct irq_source *source) 57static void frv_fpga_ack(unsigned int irq)
58{
59 __clr_IFR(1 << (irq - IRQ_BASE_FPGA));
60}
61
62static void frv_fpga_end(unsigned int irq)
63{
64}
65
66static 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 */
79static 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 */
106static 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 */
105void __init fpga_init(void) 140void __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
36static void frv_fpga_doirq(struct irq_source *source);
37static 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 */
43static struct irq_source frv_fpga[4] = { 38static 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
54static 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
65static void frv_fpga_control(struct irq_group *group, int index, int on) 47static 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
77static void frv_fpga_doirq(struct irq_source *source) 56static void frv_fpga_ack(unsigned int irq)
57{
58 __clr_IFR(1 << (irq - IRQ_BASE_FPGA));
59}
60
61static void frv_fpga_end(unsigned int irq)
62{
63}
64
65static 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 */
78static 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 */
105static 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 */
91void __init fpga_init(void) 118void __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
30static 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 */
36static struct irq_source frv_mb93493[2] = { 47static 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
51static 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
62static 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
70static struct irq_group frv_mb93493_irqs = { 77static void frv_mb93493_ack(unsigned int irq)
71 .first_irq = IRQ_BASE_MB93493,
72 .control = frv_mb93493_control,
73};
74
75static 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) 81static void frv_mb93493_end(unsigned int irq)
81 distribute_irqs(&frv_mb93493_irqs, mask); 82{
82} 83}
83 84
84static void __init mb93493_irq_route(int irq, int source) 85static 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 */
98static 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
90void __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 */
126static 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 */
146void __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
22struct irq_level frv_irq_levels[16] = {
23 [0 ... 15] = {
24 .lock = SPIN_LOCK_UNLOCKED,
25 }
26};
27
28struct irq_group *irq_groups[NR_IRQ_GROUPS];
29
30extern struct irq_group frv_cpu_irqs;
31
32void __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
39void __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
60void __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
65void 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 */
104static 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
111struct 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 */
128static 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
135struct 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 */
158static void frv_cputimer_doirq(struct irq_source *source)
159{
160 distribute_irqs(&frv_cpu_irqs, source->irqmask);
161}
162
163struct 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 */
181static void frv_cpuexternal_doirq(struct irq_source *source)
182{
183 distribute_irqs(&frv_cpu_irqs, source->irqmask);
184}
185
186struct 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
207struct 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 */
237void __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
49extern 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))
50extern void __init route_mb93493_irqs(void);
51
52static void register_irq_proc (unsigned int irq);
53 42
54/* 43extern void __init fpga_init(void);
55 * Special irq handlers. 44#ifdef CONFIG_FUJITSU_MB93493
56 */ 45extern void __init mb93493_init(void);
46#endif
57 47
58irqreturn_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
60atomic_t irq_err_count; 50atomic_t irq_err_count;
61 51
@@ -64,215 +54,99 @@ atomic_t irq_err_count;
64 */ 54 */
65int show_interrupts(struct seq_file *p, void *v) 55int 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');
114skip: 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 100static 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
149void 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
179EXPORT_SYMBOL(disable_irq_nosync); 105static 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
194void 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
207EXPORT_SYMBOL(disable_irq); 110static 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
220void 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: 117static void frv_cpupic_mask(unsigned int irqlevel)
258 count--; 118{
259 break; 119 __set_MASK(irqlevel);
120}
260 121
261 case 0: 122static 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) 129static 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); 134static void frv_cpupic_end(unsigned int irqlevel)
135{
136 __clr_MASK(irqlevel);
271} 137}
272 138
273EXPORT_SYMBOL(enable_irq); 139static 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 */
282asmlinkage void do_IRQ(void) 156asmlinkage 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 */
315asmlinkage void do_NMI(void) 167asmlinkage 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
352int 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
397EXPORT_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
417void 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
470EXPORT_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
479static 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
489unsigned long probe_irq_on(void)
490{
491 down(&probe_sem);
492 return 0;
493} 169}
494 170
495EXPORT_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 */
514unsigned int probe_irq_mask(unsigned long xmask)
515{
516 up(&probe_sem);
517 return 0;
518}
519
520EXPORT_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 174void __init init_IRQ(void)
545int probe_irq_off(unsigned long xmask)
546{
547 up(&probe_sem);
548 return -1;
549}
550
551EXPORT_SYMBOL(probe_irq_off);
552
553/* this was setup_x86_irq but it seems pretty generic */
554int 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
622static struct proc_dir_entry * root_irq_dir;
623static struct proc_dir_entry * irq_dir [NR_IRQS];
624
625#define HEX_DIGITS 8
626
627static 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 }
659out:
660 *ret = value;
661 return 0;
662}
663
664
665static 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
674static 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
691static 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
705unsigned long prof_cpu_mask = -1;
706
707void 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 */
736void __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