📄 ml_sn_intr.c
字号:
/* Try to reserve an interrupt bit on the hub * corresponding to the canidate cnode. If we * are successful then we got a cpu which can * act as an interrupt target for the io device. * Otherwise we need to continue the search * further. */ *resp_bit = do_intr_reserve_level(cpuid, req_bit, intr_resflags, II_RESERVE, owner_dev, intr_name); if (*resp_bit >= 0) /* The interrupt target specified was fine */ return(cpuid); } return(CPU_NONE);}/* * intr_heuristic(dev_t dev,device_desc_t dev_desc, * int req_bit,int intr_resflags,dev_t owner_dev, * char *intr_name,int *resp_bit) * * Choose an interrupt destination for an interrupt. * dev is the device for which the interrupt is being set up * dev_desc is a description of hardware and policy that could * help determine where this interrupt should go * req_bit is the interrupt bit requested * (can be INTRCONNECT_ANY_BIT in which the first available * interrupt bit is used) * intr_resflags indicates whether we want to (un)reserve bit * owner_dev is the owner device * intr_name is the readable interrupt name * resp_bit indicates whether we succeeded in getting the required * action { (un)reservation} done * negative value indicates failure * *//* ARGSUSED */cpuid_tintr_heuristic(devfs_handle_t dev, device_desc_t dev_desc, int req_bit, int intr_resflags, devfs_handle_t owner_dev, char *intr_name, int *resp_bit){ cpuid_t cpuid; /* possible intr targ*/ cnodeid_t candidate; /* possible canidate */ int which_subnode = SUBNODE_ANY;/* SN1 + pcibr Addressing Limitation */ { devfs_handle_t pconn_vhdl; pcibr_soft_t pcibr_soft; /* * This combination of SN1 and Bridge hardware has an odd "limitation". * Due to the choice of addresses for PI0 and PI1 registers on SN1 * and historical limitations in Bridge, Bridge is unable to * send interrupts to both PI0 CPUs and PI1 CPUs -- we have * to choose one set or the other. That choice is implicitly * made when Bridge first attaches its error interrupt. After * that point, all subsequent interrupts are restricted to the * same PI number (though it's possible to send interrupts to * the same PI number on a different node). * * Since neither SN1 nor Bridge designers are willing to admit a * bug, we can't really call this a "workaround". It's a permanent * solution for an SN1-specific and Bridge-specific hardware * limitation that won't ever be lifted. */ if ((hwgraph_edge_get(dev, EDGE_LBL_PCI, &pconn_vhdl) == GRAPH_SUCCESS) && ((pcibr_soft = pcibr_soft_get(pconn_vhdl)) != NULL)) { /* * We "know" that the error interrupt is the first * interrupt set up by pcibr_attach. Send all interrupts * on this bridge to the same subnode number. */ if (pcibr_soft->bsi_err_intr) { which_subnode = cpuid_to_subnode(((hub_intr_t) pcibr_soft->bsi_err_intr)->i_cpuid); } } } /* Check if we can find a valid interrupt target candidate on * the master node for the device. */ cpuid = intr_bit_reserve_test(CPU_NONE, which_subnode, master_node_get(dev), req_bit, intr_resflags, owner_dev, intr_name, resp_bit); if (cpuid != CPU_NONE) { if (cpu_on_subnode(cpuid, which_subnode)) return(cpuid); /* got a valid interrupt target */ else intr_unreserve_level(cpuid, *resp_bit); } printk(KERN_WARNING "Cannot target interrupts to closest node(%d): (0x%lx)\n", master_node_get(dev),(unsigned long)owner_dev); /* Fall through into the default algorithm * (exhaustive-search-for-the-nearest-possible-interrupt-target) * for finding the interrupt target */ { /* * Do a stupid round-robin assignment of the node. * (Should do a "nearest neighbor" but not for SN1. */ static cnodeid_t last_node = -1; if (last_node >= numnodes) last_node = 0; for (candidate = last_node + 1; candidate != last_node; candidate++) { if (candidate == numnodes) candidate = 0; cpuid = intr_bit_reserve_test(CPU_NONE, which_subnode, candidate, req_bit, intr_resflags, owner_dev, intr_name, resp_bit); if (cpuid != CPU_NONE) { if (cpu_on_subnode(cpuid, which_subnode)) { last_node = candidate; return(cpuid); /* got a valid interrupt target */ } else intr_unreserve_level(cpuid, *resp_bit); } } last_node = candidate; } printk(KERN_WARNING "Cannot target interrupts to any close node: %ld (0x%lx)\n", (long)owner_dev, (unsigned long)owner_dev); /* In the worst case try to allocate interrupt bits on the * master processor's node. We may get here during error interrupt * allocation phase when the topology matrix is not yet setup * and hence cannot do an exhaustive search. */ ASSERT(cpu_allows_intr(master_procid)); cpuid = intr_bit_reserve_test(master_procid, which_subnode, CNODEID_NONE, req_bit, intr_resflags, owner_dev, intr_name, resp_bit); if (cpuid != CPU_NONE) { if (cpu_on_subnode(cpuid, which_subnode)) return(cpuid); else intr_unreserve_level(cpuid, *resp_bit); } printk(KERN_WARNING "Cannot target interrupts: (0x%lx)\n", (unsigned long)owner_dev); return(CPU_NONE); /* Should never get here */}struct hardwired_intr_s { signed char level; int flags; char *name;} const hardwired_intr[] = { { INT_PEND0_BASELVL + RESERVED_INTR, 0, "Reserved" }, { INT_PEND0_BASELVL + GFX_INTR_A, 0, "Gfx A" }, { INT_PEND0_BASELVL + GFX_INTR_B, 0, "Gfx B" }, { INT_PEND0_BASELVL + PG_MIG_INTR, II_THREADED, "Migration" }, { INT_PEND0_BASELVL + UART_INTR, II_THREADED, "Bedrock/L1" }, { INT_PEND0_BASELVL + CC_PEND_A, 0, "Crosscall A" }, { INT_PEND0_BASELVL + CC_PEND_B, 0, "Crosscall B" }, { INT_PEND1_BASELVL + CLK_ERR_INTR, II_ERRORINT, "Clock Error" }, { INT_PEND1_BASELVL + COR_ERR_INTR_A, II_ERRORINT, "Correctable Error A" }, { INT_PEND1_BASELVL + COR_ERR_INTR_B, II_ERRORINT, "Correctable Error B" }, { INT_PEND1_BASELVL + MD_COR_ERR_INTR, II_ERRORINT, "MD Correct. Error" }, { INT_PEND1_BASELVL + NI_ERROR_INTR, II_ERRORINT, "NI Error" }, { INT_PEND1_BASELVL + NI_BRDCAST_ERR_A, II_ERRORINT, "Remote NI Error"}, { INT_PEND1_BASELVL + NI_BRDCAST_ERR_B, II_ERRORINT, "Remote NI Error"}, { INT_PEND1_BASELVL + MSC_PANIC_INTR, II_ERRORINT, "MSC Panic" }, { INT_PEND1_BASELVL + LLP_PFAIL_INTR_A, II_ERRORINT, "LLP Pfail WAR" }, { INT_PEND1_BASELVL + LLP_PFAIL_INTR_B, II_ERRORINT, "LLP Pfail WAR" }, { INT_PEND1_BASELVL + NACK_INT_A, 0, "CPU A Nack count == NACK_CMP" }, { INT_PEND1_BASELVL + NACK_INT_B, 0, "CPU B Nack count == NACK_CMP" }, { INT_PEND1_BASELVL + LB_ERROR, 0, "Local Block Error" }, { INT_PEND1_BASELVL + XB_ERROR, 0, "Local XBar Error" }, { -1, 0, (char *)NULL},};/* * Reserve all of the hardwired interrupt levels so they're not used as * general purpose bits later. */voidintr_reserve_hardwired(cnodeid_t cnode){ cpuid_t cpu; int level; int i; char subnode_done[NUM_SUBNODES]; // cpu = cnodetocpu(cnode); for (cpu = 0; cpu < smp_num_cpus; cpu++) { if (cpuid_to_cnodeid(cpu) == cnode) { break; } } if (cpu == smp_num_cpus) cpu = CPU_NONE; if (cpu == CPU_NONE) { printk("Node %d has no CPUs", cnode); return; } for (i=0; i<NUM_SUBNODES; i++) subnode_done[i] = 0; for (; cpu<smp_num_cpus && cpu_enabled(cpu) && cpuid_to_cnodeid(cpu) == cnode; cpu++) { int which_subnode = cpuid_to_subnode(cpu); if (subnode_done[which_subnode]) continue; subnode_done[which_subnode] = 1; for (i = 0; hardwired_intr[i].level != -1; i++) { level = hardwired_intr[i].level; if (level != intr_reserve_level(cpu, level, hardwired_intr[i].flags, (devfs_handle_t) NULL, hardwired_intr[i].name)) panic("intr_reserve_hardwired: Can't reserve level %d, cpu %ld.", level, cpu); } }}/* * Check and clear interrupts. *//*ARGSUSED*/static voidintr_clear_bits(nasid_t nasid, volatile hubreg_t *pend, int base_level, char *name){ volatile hubreg_t bits; int i; /* Check pending interrupts */ if ((bits = HUB_L(pend)) != 0) { for (i = 0; i < N_INTPEND_BITS; i++) { if (bits & (1 << i)) {#ifdef INTRDEBUG printk(KERN_WARNING "Nasid %d interrupt bit %d set in %s", nasid, i, name);#endif LOCAL_HUB_CLR_INTR(base_level + i); } } }}/* * Clear out our interrupt registers. */voidintr_clear_all(nasid_t nasid){ int sn; for(sn=0; sn<NUM_SUBNODES; sn++) { REMOTE_HUB_PI_S(nasid, sn, PI_INT_MASK0_A, 0); REMOTE_HUB_PI_S(nasid, sn, PI_INT_MASK0_B, 0); REMOTE_HUB_PI_S(nasid, sn, PI_INT_MASK1_A, 0); REMOTE_HUB_PI_S(nasid, sn, PI_INT_MASK1_B, 0); intr_clear_bits(nasid, REMOTE_HUB_PI_ADDR(nasid, sn, PI_INT_PEND0), INT_PEND0_BASELVL, "INT_PEND0"); intr_clear_bits(nasid, REMOTE_HUB_PI_ADDR(nasid, sn, PI_INT_PEND1), INT_PEND1_BASELVL, "INT_PEND1"); }}/* * Dump information about a particular interrupt vector. */static voiddump_vector(intr_info_t *info, intr_vector_t *vector, int bit, hubreg_t ip, hubreg_t ima, hubreg_t imb, void (*pf)(char *, ...)){ hubreg_t value = 1LL << bit; pf(" Bit %02d: %s: func 0x%x arg 0x%x prefunc 0x%x\n", bit, info->ii_name, vector->iv_func, vector->iv_arg, vector->iv_prefunc); pf(" vertex 0x%x %s%s", info->ii_owner_dev, ((info->ii_flags) & II_RESERVE) ? "R" : "U", ((info->ii_flags) & II_INUSE) ? "C" : "-"); pf("%s%s%s%s", ip & value ? "P" : "-", ima & value ? "A" : "-", imb & value ? "B" : "-", ((info->ii_flags) & II_ERRORINT) ? "E" : "-"); pf("\n");}/* * Dump information about interrupt vector assignment. */voidintr_dumpvec(cnodeid_t cnode, void (*pf)(char *, ...)){ nodepda_t *npda; int ip, sn, bit; intr_vecblk_t *dispatch; hubreg_t ipr, ima, imb; nasid_t nasid; if ((cnode < 0) || (cnode >= numnodes)) { pf("intr_dumpvec: cnodeid out of range: %d\n", cnode); return ; } nasid = COMPACT_TO_NASID_NODEID(cnode); if (nasid == INVALID_NASID) { pf("intr_dumpvec: Bad cnodeid: %d\n", cnode); return ; } npda = NODEPDA(cnode); for (sn = 0; sn < NUM_SUBNODES; sn++) { for (ip = 0; ip < 2; ip++) { dispatch = ip ? &(SNPDA(npda,sn)->intr_dispatch1) : &(SNPDA(npda,sn)->intr_dispatch0); ipr = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_PEND1 : PI_INT_PEND0); ima = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_MASK1_A : PI_INT_MASK0_A); imb = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_MASK1_B : PI_INT_MASK0_B); pf("Node %d INT_PEND%d:\n", cnode, ip); if (dispatch->ithreads_enabled) pf(" Ithreads enabled\n"); else pf(" Ithreads disabled\n"); pf(" vector_count = %d, vector_state = %d\n", dispatch->vector_count, dispatch->vector_state); pf(" CPU A count %d, CPU B count %d\n", dispatch->cpu_count[0], dispatch->cpu_count[1]); pf(" &vector_lock = 0x%x\n", &(dispatch->vector_lock)); for (bit = 0; bit < N_INTPEND_BITS; bit++) { if ((dispatch->info[bit].ii_flags & II_RESERVE) || (ipr & (1L << bit))) { dump_vector(&(dispatch->info[bit]), &(dispatch->vectors[bit]), bit, ipr, ima, imb, pf); } } pf("\n"); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -