1/* $Id: ml_SN_intr.c,v 1.1.1.1 2008/10/15 03:26:03 james26_jang Exp $
2 *
3 * This file is subject to the terms and conditions of the GNU General Public
4 * License.  See the file "COPYING" in the main directory of this archive
5 * for more details.
6 *
7 * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
8 */
9
10/*
11 * intr.c-
12 *	This file contains all of the routines necessary to set up and
13 *	handle interrupts on an IP27 board.
14 */
15
16#ident  "$Revision: 1.1.1.1 $"
17
18#include <linux/types.h>
19#include <linux/config.h>
20#include <linux/slab.h>
21#include <asm/smp.h>
22#include <asm/sn/sgi.h>
23#include <asm/sn/io.h>
24#include <asm/sn/iograph.h>
25#include <asm/sn/invent.h>
26#include <asm/sn/hcl.h>
27#include <asm/sn/labelcl.h>
28#include <asm/sn/sn_private.h>
29#include <asm/sn/klconfig.h>
30#include <asm/sn/sn_cpuid.h>
31#include <asm/sn/pci/pciio.h>
32#include <asm/sn/pci/pcibr.h>
33#include <asm/sn/xtalk/xtalk.h>
34#include <asm/sn/pci/pcibr_private.h>
35#include <asm/sn/intr.h>
36
37
38#if DEBUG_INTR_TSTAMP_DEBUG
39#include <sys/debug.h>
40#include <sys/idbg.h>
41#include <sys/inst.h>
42void do_splx_log(int, int);
43void spldebug_log_event(int);
44#endif
45
46#ifdef CONFIG_SMP
47extern unsigned long cpu_online_map;
48#endif
49#define cpu_allows_intr(cpu)	(1)
50// If I understand what's going on with this, 32 should work.
51// physmem_maxradius seems to be the maximum number of router
52// hops to get from one end of the system to the other.  With
53// a maximally configured machine, with the dumbest possible
54// topology, we would make 32 router hops.  For what we're using
55// it for, the dumbest possible should suffice.
56#define physmem_maxradius()	32
57
58#define SUBNODE_ANY (-1)
59
60extern int	nmied;
61extern int	hub_intr_wakeup_cnt;
62extern synergy_da_t	*Synergy_da_indr[];
63extern cpuid_t         master_procid;
64
65extern cnodeid_t master_node_get(devfs_handle_t vhdl);
66
67extern void snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs);
68
69
70#define INTR_LOCK(vecblk) \
71     (s = mutex_spinlock(&(vecblk)->vector_lock))
72#define INTR_UNLOCK(vecblk) \
73      mutex_spinunlock(&(vecblk)->vector_lock, s)
74
75/*
76 * REACT/Pro
77 */
78
79
80
81/*
82 * Find first bit set
83 * Used outside this file also
84 */
85int ms1bit(unsigned long x)
86{
87    int			b;
88
89    if (x >> 32)	b  = 32, x >>= 32;
90    else		b  =  0;
91    if (x >> 16)	b += 16, x >>= 16;
92    if (x >>  8)	b +=  8, x >>=  8;
93    if (x >>  4)	b +=  4, x >>=  4;
94    if (x >>  2)	b +=  2, x >>=  2;
95
96    return b + (int) (x >> 1);
97}
98
99/* ARGSUSED */
100void
101intr_stray(void *lvl)
102{
103    printk(KERN_WARNING  "Stray Interrupt - level %ld to cpu %d", (long)lvl, smp_processor_id());
104}
105
106#if defined(DEBUG)
107
108/* Infrastructure  to gather the device - target cpu mapping info */
109#define MAX_DEVICES	1000	/* Reasonable large number . Need not be
110				 * the exact maximum # devices possible.
111				 */
112#define MAX_NAME	100
113typedef struct {
114	dev_t		dev;	/* device */
115	cpuid_t		cpuid;	/* target cpu */
116	cnodeid_t	cnodeid;/* node on which the target cpu is present */
117	int		bit;	/* intr bit reserved */
118	char		intr_name[MAX_NAME]; /* name of the interrupt */
119} intr_dev_targ_map_t;
120
121intr_dev_targ_map_t 	intr_dev_targ_map[MAX_DEVICES];
122uint64_t		intr_dev_targ_map_size;
123spinlock_t		intr_dev_targ_map_lock;
124
125/* Print out the device - target cpu mapping.
126 * This routine is used only in the idbg command
127 * "intrmap"
128 */
129void
130intr_dev_targ_map_print(cnodeid_t cnodeid)
131{
132	int  i,j,size = 0;
133	int  print_flag = 0,verbose = 0;
134	char node_name[10];
135
136	if (cnodeid != CNODEID_NONE) {
137		nodepda_t 	*npda;
138
139		npda = NODEPDA(cnodeid);
140		for (j=0; j<NUM_SUBNODES; j++) {
141			qprintf("\n SUBNODE %d\n INT_PEND0: ", j);
142			for(i = 0 ; i < N_INTPEND_BITS ; i++)
143				qprintf("%d",SNPDA(npda,j)->intr_dispatch0.info[i].ii_flags);
144			qprintf("\n INT_PEND1: ");
145			for(i = 0 ; i < N_INTPEND_BITS ; i++)
146				qprintf("%d",SNPDA(npda,j)->intr_dispatch1.info[i].ii_flags);
147		}
148		verbose = 1;
149	}
150	qprintf("\n Device - Target Map [Interrupts: %s Node%s]\n\n",
151		(verbose ? "All" : "Non-hardwired"),
152		(cnodeid == CNODEID_NONE) ? "s: All" : node_name);
153
154	qprintf("Device\tCpu\tCnode\tIntr_bit\tIntr_name\n");
155	for (i = 0 ; i < intr_dev_targ_map_size ; i++) {
156
157		print_flag = 0;
158		if (verbose) {
159			if (cnodeid != CNODEID_NONE) {
160				if (cnodeid == intr_dev_targ_map[i].cnodeid)
161					print_flag = 1;
162			} else {
163				print_flag = 1;
164			}
165		} else {
166			if (intr_dev_targ_map[i].dev != 0) {
167				if (cnodeid != CNODEID_NONE) {
168					if (cnodeid ==
169					    intr_dev_targ_map[i].cnodeid)
170						print_flag = 1;
171				} else {
172					print_flag = 1;
173				}
174			}
175		}
176		if (print_flag) {
177			size++;
178			qprintf("%d\t%d\t%d\t%d\t%s\n",
179				intr_dev_targ_map[i].dev,
180				intr_dev_targ_map[i].cpuid,
181				intr_dev_targ_map[i].cnodeid,
182				intr_dev_targ_map[i].bit,
183				intr_dev_targ_map[i].intr_name);
184		}
185
186	}
187	qprintf("\nTotal : %d\n",size);
188}
189#endif /* DEBUG */
190
191/*
192 * The spinlocks have already been initialized.  Now initialize the interrupt
193 * vectors.  One processor on each hub does the work.
194 */
195void
196intr_init_vecblk(nodepda_t *npda, cnodeid_t node, int sn)
197{
198    int			i, ip=0;
199    intr_vecblk_t	*vecblk;
200    subnode_pda_t	*snpda;
201
202
203    snpda = SNPDA(npda,sn);
204    do {
205	if (ip == 0) {
206	    vecblk = &snpda->intr_dispatch0;
207	} else {
208	    vecblk = &snpda->intr_dispatch1;
209	}
210
211	/* Initialize this vector. */
212	for (i = 0; i < N_INTPEND_BITS; i++) {
213		vecblk->vectors[i].iv_func = intr_stray;
214		vecblk->vectors[i].iv_prefunc = NULL;
215		vecblk->vectors[i].iv_arg = (void *)(__psint_t)(ip * N_INTPEND_BITS + i);
216
217		vecblk->info[i].ii_owner_dev = 0;
218		strcpy(vecblk->info[i].ii_name, "Unused");
219		vecblk->info[i].ii_flags = 0;	/* No flags */
220		vecblk->vectors[i].iv_mustruncpu = -1; /* No CPU yet. */
221
222	    }
223
224	mutex_spinlock_init(&vecblk->vector_lock);
225
226	vecblk->vector_count = 0;
227	for (i = 0; i < CPUS_PER_SUBNODE; i++)
228		vecblk->cpu_count[i] = 0;
229
230	vecblk->vector_state = VECTOR_UNINITED;
231
232    } while (++ip < 2);
233
234}
235
236
237/*
238 * do_intr_reserve_level(cpuid_t cpu, int bit, int resflags, int reserve,
239 *					devfs_handle_t owner_dev, char *name)
240 *	Internal work routine to reserve or unreserve an interrupt level.
241 *		cpu is the CPU to which the interrupt will be sent.
242 *		bit is the level bit to reserve.  -1 means any level
243 *		resflags should include II_ERRORINT if this is an
244 *			error interrupt, II_THREADED if the interrupt handler
245 *			will be threaded, or 0 otherwise.
246 *		reserve should be set to II_RESERVE or II_UNRESERVE
247 *			to get or clear a reservation.
248 *		owner_dev is the device that "owns" this interrupt, if supplied
249 *		name is a human-readable name for this interrupt, if supplied
250 *	intr_reserve_level returns the bit reserved or -1 to indicate an error
251 */
252static int
253do_intr_reserve_level(cpuid_t cpu, int bit, int resflags, int reserve,
254					devfs_handle_t owner_dev, char *name)
255{
256    intr_vecblk_t	*vecblk;
257    hub_intmasks_t 	*hub_intmasks;
258    unsigned long s;
259    int rv = 0;
260    int ip;
261    synergy_da_t	*sda;
262    int		which_synergy;
263    cnodeid_t	cnode;
264
265    ASSERT(bit < N_INTPEND_BITS * 2);
266
267    cnode = cpuid_to_cnodeid(cpu);
268    which_synergy = cpuid_to_synergy(cpu);
269    sda = Synergy_da_indr[(cnode * 2) + which_synergy];
270    hub_intmasks = &sda->s_intmasks;
271    // hub_intmasks = &pdaindr[cpu].pda->p_intmasks;
272
273    // if (pdaindr[cpu].pda == NULL) return -1;
274    if ((bit < N_INTPEND_BITS) && !(resflags & II_ERRORINT)) {
275	vecblk = hub_intmasks->dispatch0;
276	ip = 0;
277    } else {
278	ASSERT((bit >= N_INTPEND_BITS) || (bit == -1));
279	bit -= N_INTPEND_BITS;	/* Get position relative to INT_PEND1 reg. */
280	vecblk = hub_intmasks->dispatch1;
281	ip = 1;
282    }
283
284    INTR_LOCK(vecblk);
285
286    if (bit <= -1) {
287	bit = 0;
288	ASSERT(reserve == II_RESERVE);
289	/* Choose any available level */
290	for (; bit < N_INTPEND_BITS; bit++) {
291	    if (!(vecblk->info[bit].ii_flags & II_RESERVE)) {
292		rv = bit;
293		break;
294	    }
295	}
296
297	/* Return -1 if all interrupt levels int this register are taken. */
298	if (bit == N_INTPEND_BITS)
299	    rv = -1;
300
301    } else {
302	/* Reserve a particular level if it's available. */
303	if ((vecblk->info[bit].ii_flags & II_RESERVE) == reserve) {
304	    /* Can't (un)reserve a level that's already (un)reserved. */
305	    rv = -1;
306	} else {
307	    rv = bit;
308	}
309    }
310
311    /* Reserve the level and bump the count. */
312    if (rv != -1) {
313	if (reserve) {
314	    int maxlen = sizeof(vecblk->info[bit].ii_name) - 1;
315	    int namelen;
316	    vecblk->info[bit].ii_flags |= (II_RESERVE | resflags);
317	    vecblk->info[bit].ii_owner_dev = owner_dev;
318	    /* Copy in the name. */
319	    namelen = name ? strlen(name) : 0;
320	    strncpy(vecblk->info[bit].ii_name, name, min(namelen, maxlen));
321	    vecblk->info[bit].ii_name[maxlen] = '\0';
322	    vecblk->vector_count++;
323	} else {
324	    vecblk->info[bit].ii_flags = 0;	/* Clear all the flags */
325	    vecblk->info[bit].ii_owner_dev = 0;
326	    /* Clear the name. */
327	    vecblk->info[bit].ii_name[0] = '\0';
328	    vecblk->vector_count--;
329	}
330    }
331
332    INTR_UNLOCK(vecblk);
333
334#if defined(DEBUG)
335    if (rv >= 0) {
336	    int namelen = name ? strlen(name) : 0;
337	    /* Gather this device - target cpu mapping information
338	     * in a table which can be used later by the idbg "intrmap"
339	     * command
340	     */
341	    s = mutex_spinlock(&intr_dev_targ_map_lock);
342	    if (intr_dev_targ_map_size < MAX_DEVICES) {
343		    intr_dev_targ_map_t	*p;
344
345		    p 		= &intr_dev_targ_map[intr_dev_targ_map_size];
346		    p->dev  	= owner_dev;
347		    p->cpuid 	= cpu;
348		    p->cnodeid 	= cpuid_to_cnodeid(cpu);
349		    p->bit 	= ip * N_INTPEND_BITS + rv;
350		    strncpy(p->intr_name,
351			    name,
352			    min(MAX_NAME,namelen));
353		    intr_dev_targ_map_size++;
354	    }
355	    mutex_spinunlock(&intr_dev_targ_map_lock,s);
356    }
357#endif /* DEBUG */
358
359    return (((rv == -1) ? rv : (ip * N_INTPEND_BITS) + rv)) ;
360}
361
362
363/*
364 * WARNING:  This routine should only be called from within ml/SN.
365 *	Reserve an interrupt level.
366 */
367int
368intr_reserve_level(cpuid_t cpu, int bit, int resflags, devfs_handle_t owner_dev, char *name)
369{
370	return(do_intr_reserve_level(cpu, bit, resflags, II_RESERVE, owner_dev, name));
371}
372
373
374/*
375 * WARNING:  This routine should only be called from within ml/SN.
376 *	Unreserve an interrupt level.
377 */
378void
379intr_unreserve_level(cpuid_t cpu, int bit)
380{
381	(void)do_intr_reserve_level(cpu, bit, 0, II_UNRESERVE, 0, NULL);
382}
383
384/*
385 * Get values that vary depending on which CPU and bit we're operating on
386 */
387static hub_intmasks_t *
388intr_get_ptrs(cpuid_t cpu, int bit,
389	      int *new_bit,		/* Bit relative to the register */
390	      hubreg_t **intpend_masks, /* Masks for this register */
391	      intr_vecblk_t **vecblk,	/* Vecblock for this interrupt */
392	      int *ip)			/* Which intpend register */
393{
394	hub_intmasks_t *hub_intmasks;
395	synergy_da_t	*sda;
396	int		which_synergy;
397	cnodeid_t	cnode;
398
399	ASSERT(bit < N_INTPEND_BITS * 2);
400
401	cnode = cpuid_to_cnodeid(cpu);
402	which_synergy = cpuid_to_synergy(cpu);
403	sda = Synergy_da_indr[(cnode * 2) + which_synergy];
404	hub_intmasks = &sda->s_intmasks;
405
406	// hub_intmasks = &pdaindr[cpu].pda->p_intmasks;
407
408	if (bit < N_INTPEND_BITS) {
409		*intpend_masks = hub_intmasks->intpend0_masks;
410		*vecblk = hub_intmasks->dispatch0;
411		*ip = 0;
412		*new_bit = bit;
413	} else {
414		*intpend_masks = hub_intmasks->intpend1_masks;
415		*vecblk = hub_intmasks->dispatch1;
416		*ip = 1;
417		*new_bit = bit - N_INTPEND_BITS;
418	}
419
420	return hub_intmasks;
421}
422
423
424/*
425 * intr_connect_level(cpuid_t cpu, int bit, ilvl_t intr_swlevel,
426 *		intr_func_t intr_func, void *intr_arg);
427 *	This is the lowest-level interface to the interrupt code.  It shouldn't
428 *	be called from outside the ml/SN directory.
429 *	intr_connect_level hooks up an interrupt to a particular bit in
430 *	the INT_PEND0/1 masks.  Returns 0 on success.
431 *		cpu is the CPU to which the interrupt will be sent.
432 *		bit is the level bit to connect to
433 *		intr_swlevel tells which software level to use
434 *		intr_func is the interrupt handler
435 *		intr_arg is an arbitrary argument interpreted by the handler
436 *		intr_prefunc is a prologue function, to be called
437 *			with interrupts disabled, to disable
438 *			the interrupt at source.  It is called
439 *			with the same argument.  Should be NULL for
440 *			typical interrupts, which can be masked
441 *			by the infrastructure at the level bit.
442 *	intr_connect_level returns 0 on success or nonzero on an error
443 */
444/* ARGSUSED */
445int
446intr_connect_level(cpuid_t cpu, int bit, ilvl_t intr_swlevel, intr_func_t intr_prefunc)
447{
448    intr_vecblk_t	*vecblk;
449    hubreg_t		*intpend_masks;
450    int rv = 0;
451    int ip;
452    unsigned long s;
453
454    ASSERT(bit < N_INTPEND_BITS * 2);
455
456    (void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks,
457				 &vecblk, &ip);
458
459    INTR_LOCK(vecblk);
460
461    if ((vecblk->info[bit].ii_flags & II_INUSE) ||
462	(!(vecblk->info[bit].ii_flags & II_RESERVE))) {
463	/* Can't assign to a level that's in use or isn't reserved. */
464	rv = -1;
465    } else {
466	/* Stuff parameters into vector and info */
467	vecblk->vectors[bit].iv_prefunc = intr_prefunc;
468	vecblk->info[bit].ii_flags |= II_INUSE;
469    }
470
471    /* Now stuff the masks if everything's okay. */
472    if (!rv) {
473	int lslice;
474	volatile hubreg_t *mask_reg;
475	// nasid_t nasid = COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu));
476	nasid_t nasid = cpuid_to_nasid(cpu);
477	int	subnode = cpuid_to_subnode(cpu);
478
479	/* Make sure it's not already pending when we connect it. */
480	REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit + ip * N_INTPEND_BITS);
481
482	if (bit >= GFX_INTR_A && bit <= CC_PEND_B) {
483		intpend_masks[0] |= (1ULL << (uint64_t)bit);
484	}
485
486	lslice = cpuid_to_localslice(cpu);
487	vecblk->cpu_count[lslice]++;
488#if SN1
489	/*
490	 * On SN1, there are 8 interrupt mask registers per node:
491	 * 	PI_0 MASK_0 A
492	 * 	PI_0 MASK_1 A
493	 * 	PI_0 MASK_0 B
494	 * 	PI_0 MASK_1 B
495	 * 	PI_1 MASK_0 A
496	 * 	PI_1 MASK_1 A
497	 * 	PI_1 MASK_0 B
498	 * 	PI_1 MASK_1 B
499	 */
500#endif
501	if (ip == 0) {
502		mask_reg = REMOTE_HUB_PI_ADDR(nasid, subnode,
503		        PI_INT_MASK0_A + PI_INT_MASK_OFFSET * lslice);
504	} else {
505		mask_reg = REMOTE_HUB_PI_ADDR(nasid, subnode,
506			PI_INT_MASK1_A + PI_INT_MASK_OFFSET * lslice);
507	}
508
509	HUB_S(mask_reg, intpend_masks[0]);
510    }
511
512    INTR_UNLOCK(vecblk);
513
514    return rv;
515}
516
517
518/*
519 * intr_disconnect_level(cpuid_t cpu, int bit)
520 *
521 *	This is the lowest-level interface to the interrupt code.  It should
522 *	not be called from outside the ml/SN directory.
523 *	intr_disconnect_level removes a particular bit from an interrupt in
524 * 	the INT_PEND0/1 masks.  Returns 0 on success or nonzero on failure.
525 */
526int
527intr_disconnect_level(cpuid_t cpu, int bit)
528{
529    intr_vecblk_t	*vecblk;
530    hubreg_t		*intpend_masks;
531    unsigned long s;
532    int rv = 0;
533    int ip;
534
535    (void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks,
536				 &vecblk, &ip);
537
538    INTR_LOCK(vecblk);
539
540    if ((vecblk->info[bit].ii_flags & (II_RESERVE | II_INUSE)) !=
541	((II_RESERVE | II_INUSE))) {
542	/* Can't remove a level that's not in use or isn't reserved. */
543	rv = -1;
544    } else {
545	/* Stuff parameters into vector and info */
546	vecblk->vectors[bit].iv_func = (intr_func_t)NULL;
547	vecblk->vectors[bit].iv_prefunc = (intr_func_t)NULL;
548	vecblk->vectors[bit].iv_arg = 0;
549	vecblk->info[bit].ii_flags &= ~II_INUSE;
550#ifdef BASE_ITHRTEAD
551	vecblk->vectors[bit].iv_mustruncpu = -1; /* No mustrun CPU any more. */
552#endif
553    }
554
555    /* Now clear the masks if everything's okay. */
556    if (!rv) {
557	int lslice;
558	volatile hubreg_t *mask_reg;
559
560	intpend_masks[0] &= ~(1ULL << (uint64_t)bit);
561	lslice = cpuid_to_localslice(cpu);
562	vecblk->cpu_count[lslice]--;
563	mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)),
564				   cpuid_to_subnode(cpu),
565				   ip == 0 ? PI_INT_MASK0_A : PI_INT_MASK1_A);
566	mask_reg = (volatile hubreg_t *)((__psunsigned_t)mask_reg +
567					(PI_INT_MASK_OFFSET * lslice));
568	*mask_reg = intpend_masks[0];
569    }
570
571    INTR_UNLOCK(vecblk);
572
573    return rv;
574}
575
576/*
577 * Actually block or unblock an interrupt
578 */
579void
580do_intr_block_bit(cpuid_t cpu, int bit, int block)
581{
582	intr_vecblk_t *vecblk;
583	int ip;
584	unsigned long s;
585	hubreg_t *intpend_masks;
586	volatile hubreg_t mask_value;
587	volatile hubreg_t *mask_reg;
588
589	intr_get_ptrs(cpu, bit, &bit, &intpend_masks, &vecblk, &ip);
590
591	INTR_LOCK(vecblk);
592
593	if (block)
594		/* Block */
595		intpend_masks[0] &= ~(1ULL << (uint64_t)bit);
596	else
597		/* Unblock */
598		intpend_masks[0] |= (1ULL << (uint64_t)bit);
599
600	if (ip == 0) {
601		mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)),
602		        cpuid_to_subnode(cpu), PI_INT_MASK0_A);
603	} else {
604		mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)),
605			cpuid_to_subnode(cpu), PI_INT_MASK1_A);
606	}
607
608	HUB_S(mask_reg, intpend_masks[0]);
609
610	/*
611	 * Wait for it to take effect.  (One read should suffice.)
612	 * This is only necessary when blocking an interrupt
613	 */
614	if (block)
615		while ((mask_value = HUB_L(mask_reg)) != intpend_masks[0])
616			;
617
618	INTR_UNLOCK(vecblk);
619}
620
621
622/*
623 * Block a particular interrupt (cpu/bit pair).
624 */
625/* ARGSUSED */
626void
627intr_block_bit(cpuid_t cpu, int bit)
628{
629	do_intr_block_bit(cpu, bit, 1);
630}
631
632
633/*
634 * Unblock a particular interrupt (cpu/bit pair).
635 */
636/* ARGSUSED */
637void
638intr_unblock_bit(cpuid_t cpu, int bit)
639{
640	do_intr_block_bit(cpu, bit, 0);
641}
642
643
644/* verifies that the specified CPUID is on the specified SUBNODE (if any) */
645#define cpu_on_subnode(cpuid, which_subnode) \
646	   (((which_subnode) == SUBNODE_ANY) || (cpuid_to_subnode(cpuid) == (which_subnode)))
647
648
649/*
650 * Choose one of the CPUs on a specified node or subnode to receive
651 * interrupts. Don't pick a cpu which has been specified as a NOINTR cpu.
652 *
653 * Among all acceptable CPUs, the CPU that has the fewest total number
654 * of interrupts targetted towards it is chosen.  Note that we never
655 * consider how frequent each of these interrupts might occur, so a rare
656 * hardware error interrupt is weighted equally with a disk interrupt.
657 */
658static cpuid_t
659do_intr_cpu_choose(cnodeid_t cnode, int which_subnode)
660{
661	cpuid_t 	cpu, best_cpu = CPU_NONE;
662	int		slice, min_count=1000;
663
664	min_count = 1000;
665	for (slice=0; slice < CPUS_PER_NODE; slice++) {
666		intr_vecblk_t 	*vecblk0, *vecblk1;
667		int total_intrs_to_slice;
668		subnode_pda_t *snpda;
669		int local_cpu_num;
670
671		cpu = cnode_slice_to_cpuid(cnode, slice);
672		if (cpu == CPU_NONE)
673			continue;
674
675		/* If this cpu isn't enabled for interrupts, skip it */
676		if (!cpu_enabled(cpu) || !cpu_allows_intr(cpu))
677			continue;
678
679		/* If this isn't the right subnode, skip it */
680		if (!cpu_on_subnode(cpu, which_subnode))
681			continue;
682
683		/* OK, this one's a potential CPU for interrupts */
684		snpda = SUBNODEPDA(cnode,SUBNODE(slice));
685		vecblk0 = &snpda->intr_dispatch0;
686		vecblk1 = &snpda->intr_dispatch1;
687		local_cpu_num = LOCALCPU(slice);
688		total_intrs_to_slice = vecblk0->cpu_count[local_cpu_num] +
689		              vecblk1->cpu_count[local_cpu_num];
690
691		if (min_count > total_intrs_to_slice) {
692			min_count = total_intrs_to_slice;
693			best_cpu = cpu;
694		}
695	}
696	return best_cpu;
697}
698
699/*
700 * Choose an appropriate interrupt target CPU on a specified node.
701 * If which_subnode is SUBNODE_ANY, then subnode is not considered.
702 * Otherwise, the chosen CPU must be on the specified subnode.
703 */
704static cpuid_t
705intr_cpu_choose_from_node(cnodeid_t cnode, int which_subnode)
706{
707	return(do_intr_cpu_choose(cnode, which_subnode));
708}
709
710
711/* Make it easy to identify subnode vertices in the hwgraph */
712void
713mark_subnodevertex_as_subnode(devfs_handle_t vhdl, int which_subnode)
714{
715	graph_error_t rv;
716
717	ASSERT(0 <= which_subnode);
718	ASSERT(which_subnode < NUM_SUBNODES);
719
720	rv = hwgraph_info_add_LBL(vhdl, INFO_LBL_CPUBUS, (arbitrary_info_t)which_subnode);
721	ASSERT_ALWAYS(rv == GRAPH_SUCCESS);
722
723	rv = hwgraph_info_export_LBL(vhdl, INFO_LBL_CPUBUS, sizeof(arbitrary_info_t));
724	ASSERT_ALWAYS(rv == GRAPH_SUCCESS);
725}
726
727
728/*
729 * Given a device descriptor, extract interrupt target information and
730 * choose an appropriate CPU.  Return CPU_NONE if we can't make sense
731 * out of the target information.
732 * TBD: Should this be considered platform-independent code?
733 */
734
735
736/*
737 * intr_bit_reserve_test(cpuid,which_subnode,cnode,req_bit,intr_resflags,
738 *		owner_dev,intr_name,*resp_bit)
739 *	Either cpuid is not CPU_NONE or cnodeid not CNODE_NONE but
740 * 	not both.
741 * 1. 	If cpuid is specified, this routine tests if this cpu can be a valid
742 * 	interrupt target candidate.
743 * 2. 	If cnodeid is specified, this routine tests if there is a cpu on
744 *	this node which can be a valid interrupt target candidate.
745 * 3.	If a valid interrupt target cpu candidate is found then an attempt at
746 * 	reserving an interrupt bit on the corresponding cnode is made.
747 *
748 * If steps 1 & 2 both fail or step 3 fails then we are not able to get a valid
749 * interrupt target cpu then routine returns CPU_NONE (failure)
750 * Otherwise routine returns cpuid of interrupt target (success)
751 */
752static cpuid_t
753intr_bit_reserve_test(cpuid_t 		cpuid,
754		      int		favor_subnode,
755		      cnodeid_t 	cnodeid,
756		      int		req_bit,
757		      int 		intr_resflags,
758		      devfs_handle_t 	owner_dev,
759		      char		*intr_name,
760		      int		*resp_bit)
761{
762
763	ASSERT((cpuid==CPU_NONE) || (cnodeid==CNODEID_NONE));
764
765	if (cnodeid != CNODEID_NONE) {
766		/* Try to choose a interrupt cpu candidate */
767		cpuid = intr_cpu_choose_from_node(cnodeid, favor_subnode);
768	}
769
770	if (cpuid != CPU_NONE) {
771		/* Try to reserve an interrupt bit on the hub
772		 * corresponding to the canidate cnode. If we
773		 * are successful then we got a cpu which can
774		 * act as an interrupt target for the io device.
775		 * Otherwise we need to continue the search
776		 * further.
777		 */
778		*resp_bit = do_intr_reserve_level(cpuid,
779						  req_bit,
780						  intr_resflags,
781						  II_RESERVE,
782						  owner_dev,
783						  intr_name);
784
785		if (*resp_bit >= 0)
786			/* The interrupt target  specified was fine */
787			return(cpuid);
788	}
789	return(CPU_NONE);
790}
791/*
792 * intr_heuristic(dev_t dev,device_desc_t dev_desc,
793 *		  int req_bit,int intr_resflags,dev_t owner_dev,
794 *		  char *intr_name,int *resp_bit)
795 *
796 * Choose an interrupt destination for an interrupt.
797 *	dev is the device for which the interrupt is being set up
798 *	dev_desc is a description of hardware and policy that could
799 *		help determine where this interrupt should go
800 *	req_bit is the interrupt bit requested
801 *		(can be INTRCONNECT_ANY_BIT in which the first available
802 * 		 interrupt bit is used)
803 *	intr_resflags indicates whether we want to (un)reserve bit
804 *	owner_dev is the owner device
805 *	intr_name is the readable interrupt name
806 * 	resp_bit indicates whether we succeeded in getting the required
807 *		 action  { (un)reservation} done
808 *		 negative value indicates failure
809 *
810 */
811/* ARGSUSED */
812cpuid_t
813intr_heuristic(devfs_handle_t 		dev,
814	       device_desc_t 	dev_desc,
815	       int		req_bit,
816	       int 		intr_resflags,
817	       devfs_handle_t 		owner_dev,
818	       char		*intr_name,
819	       int		*resp_bit)
820{
821	cpuid_t		cpuid;				/* possible intr targ*/
822	cnodeid_t 	candidate;			/* possible canidate */
823	int		which_subnode = SUBNODE_ANY;
824
825/* SN1 + pcibr Addressing Limitation */
826	{
827	devfs_handle_t pconn_vhdl;
828	pcibr_soft_t pcibr_soft;
829
830        if ((hwgraph_edge_get(dev, EDGE_LBL_PCI, &pconn_vhdl) == GRAPH_SUCCESS) &&
831	   ((pcibr_soft = pcibr_soft_get(pconn_vhdl)) != NULL)) {
832		/*
833		 * We "know" that the error interrupt is the first
834		 * interrupt set up by pcibr_attach.  Send all interrupts
835		 * on this bridge to the same subnode number.
836		 */
837		if (pcibr_soft->bsi_err_intr) {
838			which_subnode = cpuid_to_subnode(((hub_intr_t) pcibr_soft->bsi_err_intr)->i_cpuid);
839		}
840	}
841	}
842
843	/* Check if we can find a valid interrupt target candidate on
844	 * the master node for the device.
845	 */
846	cpuid = intr_bit_reserve_test(CPU_NONE,
847				      which_subnode,
848				      master_node_get(dev),
849				      req_bit,
850				      intr_resflags,
851				      owner_dev,
852				      intr_name,
853				      resp_bit);
854
855	if (cpuid != CPU_NONE) {
856		if (cpu_on_subnode(cpuid, which_subnode))
857			return(cpuid);	/* got a valid interrupt target */
858		else
859			intr_unreserve_level(cpuid, *resp_bit);
860	}
861
862	printk(KERN_WARNING  "Cannot target interrupts to closest node(%d): (0x%lx)\n",
863		master_node_get(dev),(unsigned long)owner_dev);
864
865	/* Fall through into the default algorithm
866	 * (exhaustive-search-for-the-nearest-possible-interrupt-target)
867	 * for finding the interrupt target
868	 */
869
870	{
871	/*
872	 * Do a stupid round-robin assignment of the node.
873	 *  (Should do a "nearest neighbor" but not for SN1.
874	 */
875		static cnodeid_t last_node = -1;
876
877		if (last_node >= numnodes) last_node = 0;
878		for (candidate = last_node + 1; candidate != last_node; candidate++) {
879			if (candidate == numnodes) candidate = 0;
880			cpuid = intr_bit_reserve_test(CPU_NONE,
881					      which_subnode,
882					      candidate,
883					      req_bit,
884					      intr_resflags,
885					      owner_dev,
886					      intr_name,
887					      resp_bit);
888
889			if (cpuid != CPU_NONE) {
890				if (cpu_on_subnode(cpuid, which_subnode)) {
891					last_node = candidate;
892					return(cpuid);	/* got a valid interrupt target */
893				}
894				else
895					intr_unreserve_level(cpuid, *resp_bit);
896			}
897		}
898		last_node = candidate;
899	}
900
901	printk(KERN_WARNING  "Cannot target interrupts to any close node: %ld (0x%lx)\n",
902		(long)owner_dev, (unsigned long)owner_dev);
903
904	/* In the worst case try to allocate interrupt bits on the
905	 * master processor's node. We may get here during error interrupt
906	 * allocation phase when the topology matrix is not yet setup
907	 * and hence cannot do an exhaustive search.
908	 */
909	ASSERT(cpu_allows_intr(master_procid));
910	cpuid = intr_bit_reserve_test(master_procid,
911				      which_subnode,
912				      CNODEID_NONE,
913				      req_bit,
914				      intr_resflags,
915				      owner_dev,
916				      intr_name,
917				      resp_bit);
918
919	if (cpuid != CPU_NONE) {
920		if (cpu_on_subnode(cpuid, which_subnode))
921			return(cpuid);
922		else
923			intr_unreserve_level(cpuid, *resp_bit);
924	}
925
926	printk(KERN_WARNING  "Cannot target interrupts: (0x%lx)\n",
927		(unsigned long)owner_dev);
928
929	return(CPU_NONE);	/* Should never get here */
930}
931
932struct hardwired_intr_s {
933	signed char level;
934	int flags;
935	char *name;
936} const hardwired_intr[] = {
937	{ INT_PEND0_BASELVL + RESERVED_INTR,	0,	"Reserved" },
938	{ INT_PEND0_BASELVL + GFX_INTR_A,	0, 	"Gfx A" },
939	{ INT_PEND0_BASELVL + GFX_INTR_B,	0, 	"Gfx B" },
940	{ INT_PEND0_BASELVL + PG_MIG_INTR,	II_THREADED, "Migration" },
941	{ INT_PEND0_BASELVL + UART_INTR,	II_THREADED, "Bedrock/L1" },
942	{ INT_PEND0_BASELVL + CC_PEND_A,	0,	"Crosscall A" },
943	{ INT_PEND0_BASELVL + CC_PEND_B,	0,	"Crosscall B" },
944	{ INT_PEND1_BASELVL + CLK_ERR_INTR,	II_ERRORINT, "Clock Error" },
945	{ INT_PEND1_BASELVL + COR_ERR_INTR_A,	II_ERRORINT, "Correctable Error A" },
946	{ INT_PEND1_BASELVL + COR_ERR_INTR_B,	II_ERRORINT, "Correctable Error B" },
947	{ INT_PEND1_BASELVL + MD_COR_ERR_INTR,	II_ERRORINT, "MD Correct. Error" },
948	{ INT_PEND1_BASELVL + NI_ERROR_INTR,	II_ERRORINT, "NI Error" },
949	{ INT_PEND1_BASELVL + NI_BRDCAST_ERR_A,	II_ERRORINT, "Remote NI Error"},
950	{ INT_PEND1_BASELVL + NI_BRDCAST_ERR_B,	II_ERRORINT, "Remote NI Error"},
951	{ INT_PEND1_BASELVL + MSC_PANIC_INTR,	II_ERRORINT, "MSC Panic" },
952	{ INT_PEND1_BASELVL + LLP_PFAIL_INTR_A,	II_ERRORINT, "LLP Pfail WAR" },
953	{ INT_PEND1_BASELVL + LLP_PFAIL_INTR_B,	II_ERRORINT, "LLP Pfail WAR" },
954	{ INT_PEND1_BASELVL + NACK_INT_A,	0, "CPU A Nack count == NACK_CMP" },
955	{ INT_PEND1_BASELVL + NACK_INT_B,	0, "CPU B Nack count == NACK_CMP" },
956	{ INT_PEND1_BASELVL + LB_ERROR,		0, "Local Block Error" },
957	{ INT_PEND1_BASELVL + XB_ERROR,		0, "Local XBar Error" },
958	{ -1, 0, (char *)NULL},
959};
960
961/*
962 * Reserve all of the hardwired interrupt levels so they're not used as
963 * general purpose bits later.
964 */
965void
966intr_reserve_hardwired(cnodeid_t cnode)
967{
968	cpuid_t cpu;
969	int level;
970	int i;
971	char subnode_done[NUM_SUBNODES];
972
973	// cpu = cnodetocpu(cnode);
974	for (cpu = 0; cpu < smp_num_cpus; cpu++) {
975		if (cpuid_to_cnodeid(cpu) == cnode) {
976			break;
977		}
978	}
979	if (cpu == smp_num_cpus) cpu = CPU_NONE;
980	if (cpu == CPU_NONE) {
981		printk("Node %d has no CPUs", cnode);
982		return;
983	}
984
985	for (i=0; i<NUM_SUBNODES; i++)
986		subnode_done[i] = 0;
987
988	for (; cpu<smp_num_cpus && cpu_enabled(cpu) && cpuid_to_cnodeid(cpu) == cnode; cpu++) {
989		int which_subnode = cpuid_to_subnode(cpu);
990		if (subnode_done[which_subnode])
991			continue;
992		subnode_done[which_subnode] = 1;
993
994		for (i = 0; hardwired_intr[i].level != -1; i++) {
995			level = hardwired_intr[i].level;
996
997			if (level != intr_reserve_level(cpu, level,
998						hardwired_intr[i].flags,
999						(devfs_handle_t) NULL,
1000						hardwired_intr[i].name))
1001				panic("intr_reserve_hardwired: Can't reserve level %d, cpu %ld.", level, cpu);
1002		}
1003	}
1004}
1005
1006
1007/*
1008 * Check and clear interrupts.
1009 */
1010/*ARGSUSED*/
1011static void
1012intr_clear_bits(nasid_t nasid, volatile hubreg_t *pend, int base_level,
1013		char *name)
1014{
1015	volatile hubreg_t bits;
1016	int i;
1017
1018	/* Check pending interrupts */
1019	if ((bits = HUB_L(pend)) != 0) {
1020		for (i = 0; i < N_INTPEND_BITS; i++) {
1021			if (bits & (1 << i)) {
1022#ifdef INTRDEBUG
1023				printk(KERN_WARNING  "Nasid %d interrupt bit %d set in %s",
1024					nasid, i, name);
1025#endif
1026				LOCAL_HUB_CLR_INTR(base_level + i);
1027			}
1028		}
1029	}
1030}
1031
1032/*
1033 * Clear out our interrupt registers.
1034 */
1035void
1036intr_clear_all(nasid_t nasid)
1037{
1038	int	sn;
1039
1040	for(sn=0; sn<NUM_SUBNODES; sn++) {
1041		REMOTE_HUB_PI_S(nasid, sn, PI_INT_MASK0_A, 0);
1042		REMOTE_HUB_PI_S(nasid, sn, PI_INT_MASK0_B, 0);
1043		REMOTE_HUB_PI_S(nasid, sn, PI_INT_MASK1_A, 0);
1044		REMOTE_HUB_PI_S(nasid, sn, PI_INT_MASK1_B, 0);
1045
1046		intr_clear_bits(nasid, REMOTE_HUB_PI_ADDR(nasid, sn, PI_INT_PEND0),
1047				INT_PEND0_BASELVL, "INT_PEND0");
1048		intr_clear_bits(nasid, REMOTE_HUB_PI_ADDR(nasid, sn, PI_INT_PEND1),
1049				INT_PEND1_BASELVL, "INT_PEND1");
1050	}
1051}
1052
1053/*
1054 * Dump information about a particular interrupt vector.
1055 */
1056static void
1057dump_vector(intr_info_t *info, intr_vector_t *vector, int bit, hubreg_t ip,
1058		hubreg_t ima, hubreg_t imb, void (*pf)(char *, ...))
1059{
1060	hubreg_t value = 1LL << bit;
1061
1062	pf("  Bit %02d: %s: func 0x%x arg 0x%x prefunc 0x%x\n",
1063		bit, info->ii_name,
1064		vector->iv_func, vector->iv_arg, vector->iv_prefunc);
1065	pf("   vertex 0x%x %s%s",
1066		info->ii_owner_dev,
1067		((info->ii_flags) & II_RESERVE) ? "R" : "U",
1068		((info->ii_flags) & II_INUSE) ? "C" : "-");
1069	pf("%s%s%s%s",
1070		ip & value ? "P" : "-",
1071		ima & value ? "A" : "-",
1072		imb & value ? "B" : "-",
1073		((info->ii_flags) & II_ERRORINT) ? "E" : "-");
1074	pf("\n");
1075}
1076
1077
1078/*
1079 * Dump information about interrupt vector assignment.
1080 */
1081void
1082intr_dumpvec(cnodeid_t cnode, void (*pf)(char *, ...))
1083{
1084	nodepda_t *npda;
1085	int ip, sn, bit;
1086	intr_vecblk_t *dispatch;
1087	hubreg_t ipr, ima, imb;
1088	nasid_t nasid;
1089
1090	if ((cnode < 0) || (cnode >= numnodes)) {
1091		pf("intr_dumpvec: cnodeid out of range: %d\n", cnode);
1092		return ;
1093	}
1094
1095	nasid = COMPACT_TO_NASID_NODEID(cnode);
1096
1097	if (nasid == INVALID_NASID) {
1098		pf("intr_dumpvec: Bad cnodeid: %d\n", cnode);
1099		return ;
1100	}
1101
1102
1103	npda = NODEPDA(cnode);
1104
1105	for (sn = 0; sn < NUM_SUBNODES; sn++) {
1106		for (ip = 0; ip < 2; ip++) {
1107			dispatch = ip ? &(SNPDA(npda,sn)->intr_dispatch1) : &(SNPDA(npda,sn)->intr_dispatch0);
1108			ipr = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_PEND1 : PI_INT_PEND0);
1109			ima = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_MASK1_A : PI_INT_MASK0_A);
1110			imb = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_MASK1_B : PI_INT_MASK0_B);
1111
1112			pf("Node %d INT_PEND%d:\n", cnode, ip);
1113
1114			if (dispatch->ithreads_enabled)
1115				pf(" Ithreads enabled\n");
1116			else
1117				pf(" Ithreads disabled\n");
1118			pf(" vector_count = %d, vector_state = %d\n",
1119				dispatch->vector_count,
1120				dispatch->vector_state);
1121			pf(" CPU A count %d, CPU B count %d\n",
1122 		   	dispatch->cpu_count[0],
1123 		   	dispatch->cpu_count[1]);
1124			pf(" &vector_lock = 0x%x\n",
1125				&(dispatch->vector_lock));
1126			for (bit = 0; bit < N_INTPEND_BITS; bit++) {
1127				if ((dispatch->info[bit].ii_flags & II_RESERVE) ||
1128			    	(ipr & (1L << bit))) {
1129					dump_vector(&(dispatch->info[bit]),
1130					    	&(dispatch->vectors[bit]),
1131					    	bit, ipr, ima, imb, pf);
1132				}
1133			}
1134			pf("\n");
1135		}
1136	}
1137}
1138
1139