ml_SN_intr.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:32k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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