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 #include <linux/config.h>
9 #include <linux/init.h>
10 #include <linux/irq.h>
11 #include <linux/errno.h>
12 #include <linux/signal.h>
13 #include <linux/sched.h>
14 #include <linux/types.h>
15 #include <linux/interrupt.h>
16 #include <linux/ioport.h>
17 #include <linux/timex.h>
18 #include <linux/slab.h>
19 #include <linux/random.h>
20 #include <linux/smp_lock.h>
21 #include <linux/kernel_stat.h>
22 #include <linux/delay.h>
23
24 #include <asm/bitops.h>
25 #include <asm/bootinfo.h>
26 #include <asm/io.h>
27 #include <asm/mipsregs.h>
28 #include <asm/system.h>
29
30 #include <asm/ptrace.h>
31 #include <asm/processor.h>
32 #include <asm/pci/bridge.h>
33 #include <asm/sn/sn0/hub.h>
34 #include <asm/sn/sn0/ip27.h>
35 #include <asm/sn/addrs.h>
36 #include <asm/sn/agent.h>
37 #include <asm/sn/arch.h>
38 #include <asm/sn/intr.h>
39 #include <asm/sn/intr_public.h>
40
41
42 #undef DEBUG_IRQ
43 #ifdef DEBUG_IRQ
44 #define DBG(x...) printk(x)
45 #else
46 #define DBG(x...)
47 #endif
48
49 /* These should die */
50 unsigned char bus_to_wid[256]; /* widget id for linux pci bus */
51 unsigned char bus_to_nid[256]; /* nasid for linux pci bus */
52 unsigned char num_bridges; /* number of bridges in the system */
53
54 /*
55 * Linux has a controller-independent x86 interrupt architecture.
56 * every controller has a 'controller-template', that is used
57 * by the main code to do the right thing. Each driver-visible
58 * interrupt source is transparently wired to the apropriate
59 * controller. Thus drivers need not be aware of the
60 * interrupt-controller.
61 *
62 * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
63 * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
64 * (IO-APICs assumed to be messaging to Pentium local-APICs)
65 *
66 * the code is designed to be easily extended with new/different
67 * interrupt controllers, without having to do assembly magic.
68 */
69
70 extern asmlinkage void ip27_irq(void);
71
72 extern int irq_to_bus[], irq_to_slot[], bus_to_cpu[];
73 int intr_connect_level(int cpu, int bit);
74 int intr_disconnect_level(int cpu, int bit);
75
76 /*
77 * There is a single intpend register per node, and we want to have
78 * distinct levels for intercpu intrs for both cpus A and B on a node.
79 */
80 int node_level_to_irq[MAX_COMPACT_NODES][PERNODE_LEVELS];
81
82 /*
83 * use these macros to get the encoded nasid and widget id
84 * from the irq value
85 */
86 #define IRQ_TO_BUS(i) irq_to_bus[(i)]
87 #define IRQ_TO_CPU(i) bus_to_cpu[IRQ_TO_BUS(i)]
88 #define NASID_FROM_PCI_IRQ(i) bus_to_nid[IRQ_TO_BUS(i)]
89 #define WID_FROM_PCI_IRQ(i) bus_to_wid[IRQ_TO_BUS(i)]
90 #define SLOT_FROM_PCI_IRQ(i) irq_to_slot[i]
91
alloc_level(cpuid_t cpunum,int irq)92 static inline int alloc_level(cpuid_t cpunum, int irq)
93 {
94 cnodeid_t nodenum = CPUID_TO_COMPACT_NODEID(cpunum);
95 int j = LEAST_LEVEL + 3; /* resched & crosscall entries taken */
96
97 while (++j < PERNODE_LEVELS) {
98 if (node_level_to_irq[nodenum][j] == -1) {
99 node_level_to_irq[nodenum][j] = irq;
100 return j;
101 }
102 }
103 printk("Cpu %ld flooded with devices\n", cpunum);
104 while(1);
105 return -1;
106 }
107
find_level(cpuid_t * cpunum,int irq)108 static inline int find_level(cpuid_t *cpunum, int irq)
109 {
110 int j;
111 cnodeid_t nodenum = INVALID_CNODEID;
112
113 while (++nodenum < MAX_COMPACT_NODES) {
114 j = LEAST_LEVEL + 3; /* resched & crosscall entries taken */
115 while (++j < PERNODE_LEVELS)
116 if (node_level_to_irq[nodenum][j] == irq) {
117 *cpunum = 0; /* XXX Fixme */
118 return(j);
119 }
120 }
121 printk("Could not identify cpu/level for irq %d\n", irq);
122 while(1);
123 return(-1);
124 }
125
126 /*
127 * Find first bit set
128 */
ms1bit(unsigned long x)129 static int ms1bit(unsigned long x)
130 {
131 int b = 0, s;
132
133 s = 16; if (x >> 16 == 0) s = 0; b += s; x >>= s;
134 s = 8; if (x >> 8 == 0) s = 0; b += s; x >>= s;
135 s = 4; if (x >> 4 == 0) s = 0; b += s; x >>= s;
136 s = 2; if (x >> 2 == 0) s = 0; b += s; x >>= s;
137 s = 1; if (x >> 1 == 0) s = 0; b += s;
138
139 return b;
140 }
141
142 /*
143 * This code is unnecessarily complex, because we do SA_INTERRUPT
144 * intr enabling. Basically, once we grab the set of intrs we need
145 * to service, we must mask _all_ these interrupts; firstly, to make
146 * sure the same intr does not intr again, causing recursion that
147 * can lead to stack overflow. Secondly, we can not just mask the
148 * one intr we are do_IRQing, because the non-masked intrs in the
149 * first set might intr again, causing multiple servicings of the
150 * same intr. This effect is mostly seen for intercpu intrs.
151 * Kanoj 05.13.00
152 */
ip27_do_irq(struct pt_regs * regs)153 void ip27_do_irq(struct pt_regs *regs)
154 {
155 int irq, swlevel;
156 hubreg_t pend0, mask0;
157 cpuid_t thiscpu = smp_processor_id();
158 int pi_int_mask0 = ((cputoslice(thiscpu) == 0) ?
159 PI_INT_MASK0_A : PI_INT_MASK0_B);
160
161 /* copied from Irix intpend0() */
162 while (((pend0 = LOCAL_HUB_L(PI_INT_PEND0)) &
163 (mask0 = LOCAL_HUB_L(pi_int_mask0))) != 0) {
164 pend0 &= mask0; /* Pick intrs we should look at */
165 if (pend0) {
166 /* Prevent any of the picked intrs from recursing */
167 LOCAL_HUB_S(pi_int_mask0, mask0 & ~(pend0));
168 do {
169 swlevel = ms1bit(pend0);
170 LOCAL_HUB_CLR_INTR(swlevel);
171 /* "map" swlevel to irq */
172 irq = LEVEL_TO_IRQ(thiscpu, swlevel);
173 do_IRQ(irq, regs);
174 /* clear bit in pend0 */
175 pend0 ^= 1ULL << swlevel;
176 } while(pend0);
177 /* Now allow the set of serviced intrs again */
178 LOCAL_HUB_S(pi_int_mask0, mask0);
179 LOCAL_HUB_L(PI_INT_PEND0);
180 }
181 }
182 }
183
184
185 /* Startup one of the (PCI ...) IRQs routes over a bridge. */
startup_bridge_irq(unsigned int irq)186 static unsigned int startup_bridge_irq(unsigned int irq)
187 {
188 bridgereg_t device;
189 bridge_t *bridge;
190 int pin, swlevel;
191 cpuid_t cpu;
192 nasid_t master = NASID_FROM_PCI_IRQ(irq);
193
194 if (irq < BASE_PCI_IRQ)
195 return 0;
196
197 bridge = (bridge_t *) NODE_SWIN_BASE(master, WID_FROM_PCI_IRQ(irq));
198 pin = SLOT_FROM_PCI_IRQ(irq);
199 cpu = IRQ_TO_CPU(irq);
200
201 DBG("bridge_startup(): irq= 0x%x pin=%d\n", irq, pin);
202 /*
203 * "map" irq to a swlevel greater than 6 since the first 6 bits
204 * of INT_PEND0 are taken
205 */
206 swlevel = alloc_level(cpu, irq);
207 intr_connect_level(cpu, swlevel);
208
209 bridge->b_int_addr[pin].addr = (0x20000 | swlevel | (master << 8));
210 bridge->b_int_enable |= (1 << pin);
211 /* more stuff in int_enable reg */
212 bridge->b_int_enable |= 0x7ffffe00;
213
214 /*
215 * XXX This only works if b_int_device is initialized to 0!
216 * We program the bridge to have a 1:1 mapping between devices
217 * (slots) and intr pins.
218 */
219 device = bridge->b_int_device;
220 device |= (pin << (pin*3));
221 bridge->b_int_device = device;
222
223 bridge->b_widget.w_tflush; /* Flush */
224
225 return 0; /* Never anything pending. */
226 }
227
228 /* Shutdown one of the (PCI ...) IRQs routes over a bridge. */
shutdown_bridge_irq(unsigned int irq)229 static unsigned int shutdown_bridge_irq(unsigned int irq)
230 {
231 bridge_t *bridge;
232 int pin, swlevel;
233 cpuid_t cpu;
234
235 if (irq < BASE_PCI_IRQ)
236 return 0;
237
238 bridge = (bridge_t *) NODE_SWIN_BASE(NASID_FROM_PCI_IRQ(irq),
239 WID_FROM_PCI_IRQ(irq));
240 DBG("bridge_shutdown: irq 0x%x\n", irq);
241 pin = SLOT_FROM_PCI_IRQ(irq);
242
243 /*
244 * map irq to a swlevel greater than 6 since the first 6 bits
245 * of INT_PEND0 are taken
246 */
247 swlevel = find_level(&cpu, irq);
248 intr_disconnect_level(cpu, swlevel);
249 LEVEL_TO_IRQ(cpu, swlevel) = -1;
250
251 bridge->b_int_enable &= ~(1 << pin);
252 bridge->b_widget.w_tflush; /* Flush */
253
254 return 0; /* Never anything pending. */
255 }
256
enable_bridge_irq(unsigned int irq)257 static inline void enable_bridge_irq(unsigned int irq)
258 {
259 /* All the braindamage happens magically for us in ip27_do_irq */
260 }
261
disable_bridge_irq(unsigned int irq)262 static void disable_bridge_irq(unsigned int irq)
263 {
264 /* All the braindamage happens magically for us in ip27_do_irq */
265 }
266
mask_and_ack_bridge_irq(unsigned int irq)267 static void mask_and_ack_bridge_irq(unsigned int irq)
268 {
269 /* All the braindamage happens magically for us in ip27_do_irq */
270 }
271
end_bridge_irq(unsigned int irq)272 static void end_bridge_irq (unsigned int irq)
273 {
274 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
275 enable_bridge_irq(irq);
276 }
277
278 static struct hw_interrupt_type bridge_irq_type = {
279 "bridge",
280 startup_bridge_irq,
281 shutdown_bridge_irq,
282 enable_bridge_irq,
283 disable_bridge_irq,
284 mask_and_ack_bridge_irq,
285 end_bridge_irq
286 };
287
irq_debug(void)288 void irq_debug(void)
289 {
290 bridge_t *bridge = (bridge_t *) 0x9200000008000000;
291
292 printk("bridge->b_int_status = 0x%x\n", bridge->b_int_status);
293 printk("bridge->b_int_enable = 0x%x\n", bridge->b_int_enable);
294 printk("PI_INT_PEND0 = 0x%lx\n", LOCAL_HUB_L(PI_INT_PEND0));
295 printk("PI_INT_MASK0_A = 0x%lx\n", LOCAL_HUB_L(PI_INT_MASK0_A));
296 }
297
init_IRQ(void)298 void __init init_IRQ(void)
299 {
300 int i;
301
302 set_except_vector(0, ip27_irq);
303
304 /*
305 * Right now the bridge irq is our kitchen sink interrupt type
306 */
307 for (i = 0; i <= NR_IRQS; i++) {
308 irq_desc[i].status = IRQ_DISABLED;
309 irq_desc[i].action = 0;
310 irq_desc[i].depth = 1;
311 irq_desc[i].handler = &bridge_irq_type;
312 }
313 }
314
315 /*
316 * Get values that vary depending on which CPU and bit we're operating on.
317 */
intr_get_ptrs(cpuid_t cpu,int bit,int * new_bit,hubreg_t ** intpend_masks,int * ip)318 static hub_intmasks_t *intr_get_ptrs(cpuid_t cpu, int bit, int *new_bit,
319 hubreg_t **intpend_masks, int *ip)
320 {
321 hub_intmasks_t *hub_intmasks;
322
323 hub_intmasks = &cpu_data[cpu].p_intmasks;
324 if (bit < N_INTPEND_BITS) {
325 *intpend_masks = hub_intmasks->intpend0_masks;
326 *ip = 0;
327 *new_bit = bit;
328 } else {
329 *intpend_masks = hub_intmasks->intpend1_masks;
330 *ip = 1;
331 *new_bit = bit - N_INTPEND_BITS;
332 }
333 return hub_intmasks;
334 }
335
intr_connect_level(int cpu,int bit)336 int intr_connect_level(int cpu, int bit)
337 {
338 int ip;
339 int slice = cputoslice(cpu);
340 volatile hubreg_t *mask_reg;
341 hubreg_t *intpend_masks;
342 nasid_t nasid = COMPACT_TO_NASID_NODEID(cputocnode(cpu));
343
344 (void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks, &ip);
345
346 /* Make sure it's not already pending when we connect it. */
347 REMOTE_HUB_CLR_INTR(nasid, bit + ip * N_INTPEND_BITS);
348
349 intpend_masks[0] |= (1ULL << (u64)bit);
350
351 if (ip == 0) {
352 mask_reg = REMOTE_HUB_ADDR(nasid, PI_INT_MASK0_A +
353 PI_INT_MASK_OFFSET * slice);
354 } else {
355 mask_reg = REMOTE_HUB_ADDR(nasid, PI_INT_MASK1_A +
356 PI_INT_MASK_OFFSET * slice);
357 }
358 HUB_S(mask_reg, intpend_masks[0]);
359 return(0);
360 }
361
intr_disconnect_level(int cpu,int bit)362 int intr_disconnect_level(int cpu, int bit)
363 {
364 int ip;
365 int slice = cputoslice(cpu);
366 volatile hubreg_t *mask_reg;
367 hubreg_t *intpend_masks;
368 nasid_t nasid = COMPACT_TO_NASID_NODEID(cputocnode(cpu));
369
370 (void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks, &ip);
371 intpend_masks[0] &= ~(1ULL << (u64)bit);
372 if (ip == 0) {
373 mask_reg = REMOTE_HUB_ADDR(nasid, PI_INT_MASK0_A +
374 PI_INT_MASK_OFFSET * slice);
375 } else {
376 mask_reg = REMOTE_HUB_ADDR(nasid, PI_INT_MASK1_A +
377 PI_INT_MASK_OFFSET * slice);
378 }
379 HUB_S(mask_reg, intpend_masks[0]);
380 return(0);
381 }
382
383
handle_resched_intr(int irq,void * dev_id,struct pt_regs * regs)384 void handle_resched_intr(int irq, void *dev_id, struct pt_regs *regs)
385 {
386 /* Nothing, the return from intr will work for us */
387 }
388
389 #ifdef CONFIG_SMP
390
core_send_ipi(int destid,unsigned int action)391 void core_send_ipi(int destid, unsigned int action)
392 {
393 int irq;
394
395 #if (CPUS_PER_NODE == 2)
396 switch (action) {
397 case SMP_RESCHEDULE_YOURSELF:
398 irq = CPU_RESCHED_A_IRQ;
399 break;
400 case SMP_CALL_FUNCTION:
401 irq = CPU_CALL_A_IRQ;
402 break;
403 default:
404 panic("sendintr");
405 }
406 irq += cputoslice(destid);
407
408 /*
409 * Convert the compact hub number to the NASID to get the correct
410 * part of the address space. Then set the interrupt bit associated
411 * with the CPU we want to send the interrupt to.
412 */
413 REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cputocnode(destid)),
414 FAST_IRQ_TO_LEVEL(irq));
415 #else
416 << Bomb! Must redefine this for more than 2 CPUS. >>
417 #endif
418 }
419
420 #endif
421
422 extern void smp_call_function_interrupt(void);
423
424 void install_cpuintr(int cpu)
425 {
426 #ifdef CONFIG_SMP
427 #if (CPUS_PER_NODE == 2)
428 static int done = 0;
429
430 /*
431 * This is a hack till we have a pernode irqlist. Currently,
432 * just have the master cpu set up the handlers for the per
433 * cpu irqs.
434 */
435 if (done == 0) {
436 int j;
437
438 if (request_irq(CPU_RESCHED_A_IRQ, handle_resched_intr,
439 0, "resched", 0))
440 panic("intercpu intr unconnectible");
441 if (request_irq(CPU_RESCHED_B_IRQ, handle_resched_intr,
442 0, "resched", 0))
443 panic("intercpu intr unconnectible");
444 if (request_irq(CPU_CALL_A_IRQ, smp_call_function_interrupt,
445 0, "callfunc", 0))
446 panic("intercpu intr unconnectible");
447 if (request_irq(CPU_CALL_B_IRQ, smp_call_function_interrupt,
448 0, "callfunc", 0))
449 panic("intercpu intr unconnectible");
450
451 for (j = 0; j < PERNODE_LEVELS; j++)
452 LEVEL_TO_IRQ(0, j) = -1;
453 LEVEL_TO_IRQ(0, FAST_IRQ_TO_LEVEL(CPU_RESCHED_A_IRQ)) =
454 CPU_RESCHED_A_IRQ;
455 LEVEL_TO_IRQ(0, FAST_IRQ_TO_LEVEL(CPU_RESCHED_B_IRQ)) =
456 CPU_RESCHED_B_IRQ;
457 LEVEL_TO_IRQ(0, FAST_IRQ_TO_LEVEL(CPU_CALL_A_IRQ)) =
458 CPU_CALL_A_IRQ;
459 LEVEL_TO_IRQ(0, FAST_IRQ_TO_LEVEL(CPU_CALL_B_IRQ)) =
460 CPU_CALL_B_IRQ;
461 for (j = 1; j < MAX_COMPACT_NODES; j++)
462 memcpy(&node_level_to_irq[j][0],
463 &node_level_to_irq[0][0],
464 sizeof(node_level_to_irq[0][0])*PERNODE_LEVELS);
465
466 done = 1;
467 }
468
469 intr_connect_level(cpu, FAST_IRQ_TO_LEVEL(CPU_RESCHED_A_IRQ +
470 cputoslice(cpu)));
471 intr_connect_level(cpu, FAST_IRQ_TO_LEVEL(CPU_CALL_A_IRQ +
472 cputoslice(cpu)));
473 #else /* CPUS_PER_NODE */
474 #error Must redefine this for more than 2 CPUS.
475 #endif /* CPUS_PER_NODE */
476 #endif /* CONFIG_SMP */
477 }
478
479 void install_tlbintr(int cpu)
480 {
481 #if 0
482 int intr_bit = N_INTPEND_BITS + TLB_INTR_A + cputoslice(cpu);
483
484 intr_connect_level(cpu, intr_bit);
485 #endif
486 }
487