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