aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2013-06-13 08:04:16 -0400
committerRalf Baechle <ralf@linux-mips.org>2013-06-21 12:07:00 -0400
commit8ea2b8b605d0053fc87abde56ff42b19520322f0 (patch)
tree0ef89f10705467957df48dc34606e53297d920ef /arch/mips
parent28963b1e2054f8c0ea968717ecf68c5fa2da6745 (diff)
MIPS: IP27: Fix build errors with CONFIG_PCI disabled.
LD init/built-in.o arch/mips/built-in.o: In function `startup_bridge_irq': ip27-irq.c:(.text+0x434): undefined reference to `irq_to_slot' ip27-irq.c:(.text+0x43c): undefined reference to `irq_to_slot' ip27-irq.c:(.text+0x460): undefined reference to `irq_to_bridge' ip27-irq.c:(.text+0x464): undefined reference to `irq_to_bridge' arch/mips/built-in.o: In function `shutdown_bridge_irq': ip27-irq.c:(.text+0x564): undefined reference to `irq_to_bridge' ip27-irq.c:(.text+0x56c): undefined reference to `irq_to_bridge' ip27-irq.c:(.text+0x5a0): undefined reference to `irq_to_slot' ip27-irq.c:(.text+0x5a4): undefined reference to `irq_to_slot' Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/sgi-ip27/Makefile1
-rw-r--r--arch/mips/sgi-ip27/ip27-irq-pci.c266
-rw-r--r--arch/mips/sgi-ip27/ip27-irq.c214
3 files changed, 267 insertions, 214 deletions
diff --git a/arch/mips/sgi-ip27/Makefile b/arch/mips/sgi-ip27/Makefile
index 1f29e761d691..da8f6816d346 100644
--- a/arch/mips/sgi-ip27/Makefile
+++ b/arch/mips/sgi-ip27/Makefile
@@ -7,4 +7,5 @@ obj-y := ip27-berr.o ip27-irq.o ip27-init.o ip27-klconfig.o ip27-klnuma.o \
7 ip27-xtalk.o 7 ip27-xtalk.o
8 8
9obj-$(CONFIG_EARLY_PRINTK) += ip27-console.o 9obj-$(CONFIG_EARLY_PRINTK) += ip27-console.o
10obj-$(CONFIG_PCI) += ip27-irq-pci.o
10obj-$(CONFIG_SMP) += ip27-smp.o 11obj-$(CONFIG_SMP) += ip27-smp.o
diff --git a/arch/mips/sgi-ip27/ip27-irq-pci.c b/arch/mips/sgi-ip27/ip27-irq-pci.c
new file mode 100644
index 000000000000..ec22ec5600f3
--- /dev/null
+++ b/arch/mips/sgi-ip27/ip27-irq-pci.c
@@ -0,0 +1,266 @@
1/*
2 * ip27-irq.c: Highlevel interrupt handling for IP27 architecture.
3 *
4 * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
5 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
6 * Copyright (C) 1999 - 2001 Kanoj Sarcar
7 */
8
9#undef DEBUG
10
11#include <linux/init.h>
12#include <linux/irq.h>
13#include <linux/errno.h>
14#include <linux/signal.h>
15#include <linux/sched.h>
16#include <linux/types.h>
17#include <linux/interrupt.h>
18#include <linux/ioport.h>
19#include <linux/timex.h>
20#include <linux/smp.h>
21#include <linux/random.h>
22#include <linux/kernel.h>
23#include <linux/kernel_stat.h>
24#include <linux/delay.h>
25#include <linux/bitops.h>
26
27#include <asm/bootinfo.h>
28#include <asm/io.h>
29#include <asm/mipsregs.h>
30
31#include <asm/processor.h>
32#include <asm/pci/bridge.h>
33#include <asm/sn/addrs.h>
34#include <asm/sn/agent.h>
35#include <asm/sn/arch.h>
36#include <asm/sn/hub.h>
37#include <asm/sn/intr.h>
38
39/*
40 * Linux has a controller-independent x86 interrupt architecture.
41 * every controller has a 'controller-template', that is used
42 * by the main code to do the right thing. Each driver-visible
43 * interrupt source is transparently wired to the appropriate
44 * controller. Thus drivers need not be aware of the
45 * interrupt-controller.
46 *
47 * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
48 * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
49 * (IO-APICs assumed to be messaging to Pentium local-APICs)
50 *
51 * the code is designed to be easily extended with new/different
52 * interrupt controllers, without having to do assembly magic.
53 */
54
55extern struct bridge_controller *irq_to_bridge[];
56extern int irq_to_slot[];
57
58/*
59 * use these macros to get the encoded nasid and widget id
60 * from the irq value
61 */
62#define IRQ_TO_BRIDGE(i) irq_to_bridge[(i)]
63#define SLOT_FROM_PCI_IRQ(i) irq_to_slot[i]
64
65static inline int alloc_level(int cpu, int irq)
66{
67 struct hub_data *hub = hub_data(cpu_to_node(cpu));
68 struct slice_data *si = cpu_data[cpu].data;
69 int level;
70
71 level = find_first_zero_bit(hub->irq_alloc_mask, LEVELS_PER_SLICE);
72 if (level >= LEVELS_PER_SLICE)
73 panic("Cpu %d flooded with devices", cpu);
74
75 __set_bit(level, hub->irq_alloc_mask);
76 si->level_to_irq[level] = irq;
77
78 return level;
79}
80
81static inline int find_level(cpuid_t *cpunum, int irq)
82{
83 int cpu, i;
84
85 for_each_online_cpu(cpu) {
86 struct slice_data *si = cpu_data[cpu].data;
87
88 for (i = BASE_PCI_IRQ; i < LEVELS_PER_SLICE; i++)
89 if (si->level_to_irq[i] == irq) {
90 *cpunum = cpu;
91
92 return i;
93 }
94 }
95
96 panic("Could not identify cpu/level for irq %d", irq);
97}
98
99static int intr_connect_level(int cpu, int bit)
100{
101 nasid_t nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
102 struct slice_data *si = cpu_data[cpu].data;
103
104 set_bit(bit, si->irq_enable_mask);
105
106 if (!cputoslice(cpu)) {
107 REMOTE_HUB_S(nasid, PI_INT_MASK0_A, si->irq_enable_mask[0]);
108 REMOTE_HUB_S(nasid, PI_INT_MASK1_A, si->irq_enable_mask[1]);
109 } else {
110 REMOTE_HUB_S(nasid, PI_INT_MASK0_B, si->irq_enable_mask[0]);
111 REMOTE_HUB_S(nasid, PI_INT_MASK1_B, si->irq_enable_mask[1]);
112 }
113
114 return 0;
115}
116
117static int intr_disconnect_level(int cpu, int bit)
118{
119 nasid_t nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
120 struct slice_data *si = cpu_data[cpu].data;
121
122 clear_bit(bit, si->irq_enable_mask);
123
124 if (!cputoslice(cpu)) {
125 REMOTE_HUB_S(nasid, PI_INT_MASK0_A, si->irq_enable_mask[0]);
126 REMOTE_HUB_S(nasid, PI_INT_MASK1_A, si->irq_enable_mask[1]);
127 } else {
128 REMOTE_HUB_S(nasid, PI_INT_MASK0_B, si->irq_enable_mask[0]);
129 REMOTE_HUB_S(nasid, PI_INT_MASK1_B, si->irq_enable_mask[1]);
130 }
131
132 return 0;
133}
134
135/* Startup one of the (PCI ...) IRQs routes over a bridge. */
136static unsigned int startup_bridge_irq(struct irq_data *d)
137{
138 struct bridge_controller *bc;
139 bridgereg_t device;
140 bridge_t *bridge;
141 int pin, swlevel;
142 cpuid_t cpu;
143
144 pin = SLOT_FROM_PCI_IRQ(d->irq);
145 bc = IRQ_TO_BRIDGE(d->irq);
146 bridge = bc->base;
147
148 pr_debug("bridge_startup(): irq= 0x%x pin=%d\n", d->irq, pin);
149 /*
150 * "map" irq to a swlevel greater than 6 since the first 6 bits
151 * of INT_PEND0 are taken
152 */
153 swlevel = find_level(&cpu, d->irq);
154 bridge->b_int_addr[pin].addr = (0x20000 | swlevel | (bc->nasid << 8));
155 bridge->b_int_enable |= (1 << pin);
156 bridge->b_int_enable |= 0x7ffffe00; /* more stuff in int_enable */
157
158 /*
159 * Enable sending of an interrupt clear packt to the hub on a high to
160 * low transition of the interrupt pin.
161 *
162 * IRIX sets additional bits in the address which are documented as
163 * reserved in the bridge docs.
164 */
165 bridge->b_int_mode |= (1UL << pin);
166
167 /*
168 * We assume the bridge to have a 1:1 mapping between devices
169 * (slots) and intr pins.
170 */
171 device = bridge->b_int_device;
172 device &= ~(7 << (pin*3));
173 device |= (pin << (pin*3));
174 bridge->b_int_device = device;
175
176 bridge->b_wid_tflush;
177
178 intr_connect_level(cpu, swlevel);
179
180 return 0; /* Never anything pending. */
181}
182
183/* Shutdown one of the (PCI ...) IRQs routes over a bridge. */
184static void shutdown_bridge_irq(struct irq_data *d)
185{
186 struct bridge_controller *bc = IRQ_TO_BRIDGE(d->irq);
187 bridge_t *bridge = bc->base;
188 int pin, swlevel;
189 cpuid_t cpu;
190
191 pr_debug("bridge_shutdown: irq 0x%x\n", d->irq);
192 pin = SLOT_FROM_PCI_IRQ(d->irq);
193
194 /*
195 * map irq to a swlevel greater than 6 since the first 6 bits
196 * of INT_PEND0 are taken
197 */
198 swlevel = find_level(&cpu, d->irq);
199 intr_disconnect_level(cpu, swlevel);
200
201 bridge->b_int_enable &= ~(1 << pin);
202 bridge->b_wid_tflush;
203}
204
205static inline void enable_bridge_irq(struct irq_data *d)
206{
207 cpuid_t cpu;
208 int swlevel;
209
210 swlevel = find_level(&cpu, d->irq); /* Criminal offence */
211 intr_connect_level(cpu, swlevel);
212}
213
214static inline void disable_bridge_irq(struct irq_data *d)
215{
216 cpuid_t cpu;
217 int swlevel;
218
219 swlevel = find_level(&cpu, d->irq); /* Criminal offence */
220 intr_disconnect_level(cpu, swlevel);
221}
222
223static struct irq_chip bridge_irq_type = {
224 .name = "bridge",
225 .irq_startup = startup_bridge_irq,
226 .irq_shutdown = shutdown_bridge_irq,
227 .irq_mask = disable_bridge_irq,
228 .irq_unmask = enable_bridge_irq,
229};
230
231void register_bridge_irq(unsigned int irq)
232{
233 irq_set_chip_and_handler(irq, &bridge_irq_type, handle_level_irq);
234}
235
236int request_bridge_irq(struct bridge_controller *bc)
237{
238 int irq = allocate_irqno();
239 int swlevel, cpu;
240 nasid_t nasid;
241
242 if (irq < 0)
243 return irq;
244
245 /*
246 * "map" irq to a swlevel greater than 6 since the first 6 bits
247 * of INT_PEND0 are taken
248 */
249 cpu = bc->irq_cpu;
250 swlevel = alloc_level(cpu, irq);
251 if (unlikely(swlevel < 0)) {
252 free_irqno(irq);
253
254 return -EAGAIN;
255 }
256
257 /* Make sure it's not already pending when we connect it. */
258 nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
259 REMOTE_HUB_CLR_INTR(nasid, swlevel);
260
261 intr_connect_level(cpu, swlevel);
262
263 register_bridge_irq(irq);
264
265 return irq;
266}
diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c
index 2315cfeb2687..3fbaef97a1b8 100644
--- a/arch/mips/sgi-ip27/ip27-irq.c
+++ b/arch/mips/sgi-ip27/ip27-irq.c
@@ -29,7 +29,6 @@
29#include <asm/mipsregs.h> 29#include <asm/mipsregs.h>
30 30
31#include <asm/processor.h> 31#include <asm/processor.h>
32#include <asm/pci/bridge.h>
33#include <asm/sn/addrs.h> 32#include <asm/sn/addrs.h>
34#include <asm/sn/agent.h> 33#include <asm/sn/agent.h>
35#include <asm/sn/arch.h> 34#include <asm/sn/arch.h>
@@ -54,50 +53,6 @@
54 53
55extern asmlinkage void ip27_irq(void); 54extern asmlinkage void ip27_irq(void);
56 55
57extern struct bridge_controller *irq_to_bridge[];
58extern int irq_to_slot[];
59
60/*
61 * use these macros to get the encoded nasid and widget id
62 * from the irq value
63 */
64#define IRQ_TO_BRIDGE(i) irq_to_bridge[(i)]
65#define SLOT_FROM_PCI_IRQ(i) irq_to_slot[i]
66
67static inline int alloc_level(int cpu, int irq)
68{
69 struct hub_data *hub = hub_data(cpu_to_node(cpu));
70 struct slice_data *si = cpu_data[cpu].data;
71 int level;
72
73 level = find_first_zero_bit(hub->irq_alloc_mask, LEVELS_PER_SLICE);
74 if (level >= LEVELS_PER_SLICE)
75 panic("Cpu %d flooded with devices", cpu);
76
77 __set_bit(level, hub->irq_alloc_mask);
78 si->level_to_irq[level] = irq;
79
80 return level;
81}
82
83static inline int find_level(cpuid_t *cpunum, int irq)
84{
85 int cpu, i;
86
87 for_each_online_cpu(cpu) {
88 struct slice_data *si = cpu_data[cpu].data;
89
90 for (i = BASE_PCI_IRQ; i < LEVELS_PER_SLICE; i++)
91 if (si->level_to_irq[i] == irq) {
92 *cpunum = cpu;
93
94 return i;
95 }
96 }
97
98 panic("Could not identify cpu/level for irq %d", irq);
99}
100
101/* 56/*
102 * Find first bit set 57 * Find first bit set
103 */ 58 */
@@ -204,175 +159,6 @@ static void ip27_hub_error(void)
204 panic("CPU %d got a hub error interrupt", smp_processor_id()); 159 panic("CPU %d got a hub error interrupt", smp_processor_id());
205} 160}
206 161
207static int intr_connect_level(int cpu, int bit)
208{
209 nasid_t nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
210 struct slice_data *si = cpu_data[cpu].data;
211
212 set_bit(bit, si->irq_enable_mask);
213
214 if (!cputoslice(cpu)) {
215 REMOTE_HUB_S(nasid, PI_INT_MASK0_A, si->irq_enable_mask[0]);
216 REMOTE_HUB_S(nasid, PI_INT_MASK1_A, si->irq_enable_mask[1]);
217 } else {
218 REMOTE_HUB_S(nasid, PI_INT_MASK0_B, si->irq_enable_mask[0]);
219 REMOTE_HUB_S(nasid, PI_INT_MASK1_B, si->irq_enable_mask[1]);
220 }
221
222 return 0;
223}
224
225static int intr_disconnect_level(int cpu, int bit)
226{
227 nasid_t nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
228 struct slice_data *si = cpu_data[cpu].data;
229
230 clear_bit(bit, si->irq_enable_mask);
231
232 if (!cputoslice(cpu)) {
233 REMOTE_HUB_S(nasid, PI_INT_MASK0_A, si->irq_enable_mask[0]);
234 REMOTE_HUB_S(nasid, PI_INT_MASK1_A, si->irq_enable_mask[1]);
235 } else {
236 REMOTE_HUB_S(nasid, PI_INT_MASK0_B, si->irq_enable_mask[0]);
237 REMOTE_HUB_S(nasid, PI_INT_MASK1_B, si->irq_enable_mask[1]);
238 }
239
240 return 0;
241}
242
243/* Startup one of the (PCI ...) IRQs routes over a bridge. */
244static unsigned int startup_bridge_irq(struct irq_data *d)
245{
246 struct bridge_controller *bc;
247 bridgereg_t device;
248 bridge_t *bridge;
249 int pin, swlevel;
250 cpuid_t cpu;
251
252 pin = SLOT_FROM_PCI_IRQ(d->irq);
253 bc = IRQ_TO_BRIDGE(d->irq);
254 bridge = bc->base;
255
256 pr_debug("bridge_startup(): irq= 0x%x pin=%d\n", d->irq, pin);
257 /*
258 * "map" irq to a swlevel greater than 6 since the first 6 bits
259 * of INT_PEND0 are taken
260 */
261 swlevel = find_level(&cpu, d->irq);
262 bridge->b_int_addr[pin].addr = (0x20000 | swlevel | (bc->nasid << 8));
263 bridge->b_int_enable |= (1 << pin);
264 bridge->b_int_enable |= 0x7ffffe00; /* more stuff in int_enable */
265
266 /*
267 * Enable sending of an interrupt clear packt to the hub on a high to
268 * low transition of the interrupt pin.
269 *
270 * IRIX sets additional bits in the address which are documented as
271 * reserved in the bridge docs.
272 */
273 bridge->b_int_mode |= (1UL << pin);
274
275 /*
276 * We assume the bridge to have a 1:1 mapping between devices
277 * (slots) and intr pins.
278 */
279 device = bridge->b_int_device;
280 device &= ~(7 << (pin*3));
281 device |= (pin << (pin*3));
282 bridge->b_int_device = device;
283
284 bridge->b_wid_tflush;
285
286 intr_connect_level(cpu, swlevel);
287
288 return 0; /* Never anything pending. */
289}
290
291/* Shutdown one of the (PCI ...) IRQs routes over a bridge. */
292static void shutdown_bridge_irq(struct irq_data *d)
293{
294 struct bridge_controller *bc = IRQ_TO_BRIDGE(d->irq);
295 bridge_t *bridge = bc->base;
296 int pin, swlevel;
297 cpuid_t cpu;
298
299 pr_debug("bridge_shutdown: irq 0x%x\n", d->irq);
300 pin = SLOT_FROM_PCI_IRQ(d->irq);
301
302 /*
303 * map irq to a swlevel greater than 6 since the first 6 bits
304 * of INT_PEND0 are taken
305 */
306 swlevel = find_level(&cpu, d->irq);
307 intr_disconnect_level(cpu, swlevel);
308
309 bridge->b_int_enable &= ~(1 << pin);
310 bridge->b_wid_tflush;
311}
312
313static inline void enable_bridge_irq(struct irq_data *d)
314{
315 cpuid_t cpu;
316 int swlevel;
317
318 swlevel = find_level(&cpu, d->irq); /* Criminal offence */
319 intr_connect_level(cpu, swlevel);
320}
321
322static inline void disable_bridge_irq(struct irq_data *d)
323{
324 cpuid_t cpu;
325 int swlevel;
326
327 swlevel = find_level(&cpu, d->irq); /* Criminal offence */
328 intr_disconnect_level(cpu, swlevel);
329}
330
331static struct irq_chip bridge_irq_type = {
332 .name = "bridge",
333 .irq_startup = startup_bridge_irq,
334 .irq_shutdown = shutdown_bridge_irq,
335 .irq_mask = disable_bridge_irq,
336 .irq_unmask = enable_bridge_irq,
337};
338
339void register_bridge_irq(unsigned int irq)
340{
341 irq_set_chip_and_handler(irq, &bridge_irq_type, handle_level_irq);
342}
343
344int request_bridge_irq(struct bridge_controller *bc)
345{
346 int irq = allocate_irqno();
347 int swlevel, cpu;
348 nasid_t nasid;
349
350 if (irq < 0)
351 return irq;
352
353 /*
354 * "map" irq to a swlevel greater than 6 since the first 6 bits
355 * of INT_PEND0 are taken
356 */
357 cpu = bc->irq_cpu;
358 swlevel = alloc_level(cpu, irq);
359 if (unlikely(swlevel < 0)) {
360 free_irqno(irq);
361
362 return -EAGAIN;
363 }
364
365 /* Make sure it's not already pending when we connect it. */
366 nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
367 REMOTE_HUB_CLR_INTR(nasid, swlevel);
368
369 intr_connect_level(cpu, swlevel);
370
371 register_bridge_irq(irq);
372
373 return irq;
374}
375
376asmlinkage void plat_irq_dispatch(void) 162asmlinkage void plat_irq_dispatch(void)
377{ 163{
378 unsigned long pending = read_c0_cause() & read_c0_status(); 164 unsigned long pending = read_c0_cause() & read_c0_status();