📄 ml_sn_intr.c
字号:
} /* XXX - This will have to change to deal with various SN errors. */ panic( "exception on IDLE stack " "ep:0x%x epc:0x%x cause:0x%w32x sp:0x%x badvaddr:0x%x", ep, epc, cause, sp, getbadvaddr()); /* NOTREACHED */}/* * earlynofault - handle very early global faults - usually just while * sizing memory * Returns: 1 if should do nofault * 0 if not *//* ARGSUSED */intearlynofault(eframe_t *ep, uint code){ switch(code) { case EXC_DBE: return(1); default: return(0); }}/* ARGSUSED */static voidcpuintr(void *arg1, void *arg2){#if RTE static int rte_intrdebug = 1;#endif /* * Frame Scheduler */ LOG_TSTAMP_EVENT(RTMON_INTR, TSTAMP_EV_CPUINTR, NULL, NULL, NULL, NULL); /* * Hardware clears the IO interrupts, but we need to clear software- * generated interrupts. */ LOCAL_HUB_CLR_INTR(CPU_ACTION_A + cputolocalslice(cpuid()));#if 0 /* XXX - Handle error interrupts. */ if (error_intr_reason) error_intr();#endif /* 0 */ /* * If we're headed for panicspin and it is due to a NMI, save the * eframe in the NMI area */ if (private.p_va_panicspin && nmied) { caddr_t nmi_save_area; nmi_save_area = (caddr_t) (TO_UNCAC(TO_NODE( cputonasid(cpuid()), IP27_NMI_EFRAME_OFFSET)) + cputoslice(cpuid()) * IP27_NMI_EFRAME_SIZE); bcopy((caddr_t) arg2, nmi_save_area, sizeof(eframe_t)); } doacvec();#if RTE if (private.p_flags & PDAF_ISOLATED && !rte_intrdebug) goto end_cpuintr;#endif doactions();#if RTEend_cpuintr:#endif LOG_TSTAMP_EVENT(RTMON_INTR, TSTAMP_EV_INTREXIT, TSTAMP_EV_CPUINTR, NULL, NULL, NULL);}voidinstall_cpuintr(cpuid_t cpu){ int intr_bit = CPU_ACTION_A + cputolocalslice(cpu); if (intr_connect_level(cpu, intr_bit, INTPEND0_MAXMASK, (intr_func_t) cpuintr, NULL, NULL)) panic("install_cpuintr: Can't connect interrupt.");}#endif /* BRINGUP */#ifdef DEBUG_INTR_TSTAMP/* We allocate an array, but only use element number 64. This guarantees that * the entry is in a cacheline by itself. */#define DINTR_CNTIDX 32#define DINTR_TSTAMP1 48#define DINTR_TSTAMP2 64volatile long long dintr_tstamp_cnt[128];int dintr_debug_output=0;extern void idbg_tstamp_debug(void);#ifdef SPLDEBUGextern void idbg_splx_log(int);#endif#if DEBUG_INTR_TSTAMP_DEBUGint dintr_enter_symmon=1000; /* 1000 microseconds is 1 millisecond */#endif#ifndef BRINGUP/* ARGSUSED */static voidcpulatintr(void *arg){ /* * Hardware only clears IO interrupts so we have to clear our level * here. */ LOCAL_HUB_CLR_INTR(CPU_INTRLAT_A + cputolocalslice(cpuid()));#if DEBUG_INTR_TSTAMP_DEBUG dintr_tstamp_cnt[DINTR_TSTAMP2] = GET_LOCAL_RTC; if ((dintr_tstamp_cnt[DINTR_TSTAMP2] - dintr_tstamp_cnt[DINTR_TSTAMP1]) > dintr_enter_symmon) {#ifdef SPLDEBUG extern int spldebug_log_off; spldebug_log_off = 1;#endif /* SPLDEBUG */ debug("ring");#ifdef SPLDEBUG spldebug_log_off = 0;#endif /* SPLDEBUG */ }#endif dintr_tstamp_cnt[DINTR_CNTIDX]++; return;}static int install_cpulat_first=0;voidinstall_cpulatintr(cpuid_t cpu){ int intr_bit; devfs_handle_t cpuv = cpuid_to_vertex(cpu); intr_bit = CPU_INTRLAT_A + cputolocalslice(cpu); if (intr_bit != intr_reserve_level(cpu, intr_bit, II_THREADED, cpuv, "intrlat")) panic( "install_cpulatintr: Can't reserve interrupt."); if (intr_connect_level(cpu, intr_bit, INTPEND0_MAXMASK, cpulatintr, NULL, NULL)) panic( "install_cpulatintr: Can't connect interrupt."); if (!install_cpulat_first) { install_cpulat_first++; idbg_addfunc("tstamp_debug", (void (*)())idbg_tstamp_debug);#if defined(SPLDEBUG) || defined(SPLDEBUG_CPU_EVENTS) idbg_addfunc("splx_log", (void (*)())idbg_splx_log);#endif /* SPLDEBUG || SPLDEBUG_CPU_EVENTS */ }}#endif /* BRINGUP */#endif /* DEBUG_INTR_TSTAMP */#ifndef BRINGUP/* ARGSUSED */static voiddbgintr(void *arg){ /* * Hardware only clears IO interrupts so we have to clear our level * here. */ LOCAL_HUB_CLR_INTR(N_INTPEND_BITS + DEBUG_INTR_A + cputolocalslice(cpuid())); debug("zing"); return;}voidinstall_dbgintr(cpuid_t cpu){ int intr_bit; devfs_handle_t cpuv = cpuid_to_vertex(cpu); intr_bit = N_INTPEND_BITS + DEBUG_INTR_A + cputolocalslice(cpu); if (intr_bit != intr_reserve_level(cpu, intr_bit, 1, cpuv, "DEBUG")) panic("install_dbgintr: Can't reserve interrupt. " " intr_bit %d" ,intr_bit); if (intr_connect_level(cpu, intr_bit, INTPEND1_MAXMASK, dbgintr, NULL, NULL)) panic("install_dbgintr: Can't connect interrupt.");#ifdef DEBUG_INTR_TSTAMP /* Set up my interrupt latency test interrupt */ install_cpulatintr(cpu);#endif}/* ARGSUSED */static voidtlbintr(void *arg){ extern void tlbflush_rand(void); /* * Hardware only clears IO interrupts so we have to clear our level * here. */ LOCAL_HUB_CLR_INTR(N_INTPEND_BITS + TLB_INTR_A + cputolocalslice(cpuid())); tlbflush_rand(); return;}voidinstall_tlbintr(cpuid_t cpu){ int intr_bit; devfs_handle_t cpuv = cpuid_to_vertex(cpu); intr_bit = N_INTPEND_BITS + TLB_INTR_A + cputolocalslice(cpu); if (intr_bit != intr_reserve_level(cpu, intr_bit, 1, cpuv, "DEBUG")) panic("install_tlbintr: Can't reserve interrupt. " " intr_bit %d" ,intr_bit); if (intr_connect_level(cpu, intr_bit, INTPEND1_MAXMASK, tlbintr, NULL, NULL)) panic("install_tlbintr: Can't connect interrupt.");}/* * Send an interrupt to all nodes. Don't panic if we get an error. * Returns 1 if any exceptions occurred. */intprotected_broadcast(hubreg_t intrbit){ nodepda_t *npdap = private.p_nodepda; int byte, bit, sn; int error = 0; extern int _wbadaddr_val(volatile void *, int, volatile int *); /* Send rather than clear an interrupt. */ intrbit |= 0x100; for (byte = 0; byte < NASID_MASK_BYTES; byte++) { for (bit = 0; bit < 8; bit++) { if (npdap->nasid_mask[byte] & (1 << bit)) { nasid_t nasid = byte * 8 + bit; for (sn=0; sn<NUM_SUBNODES; sn++) { error += _wbadaddr_val(REMOTE_HUB_PI_ADDR(nasid, sn, PI_INT_PEND_MOD), sizeof(hubreg_t), (volatile int *)&intrbit); } } } } return error;}/* * Poll the interrupt register to see if another cpu has asked us * to drop into the debugger (without lowering spl). */voidchkdebug(void){ if (LOCAL_HUB_L(PI_INT_PEND1) & (1L << (DEBUG_INTR_A + cputolocalslice(cpuid())))) dbgintr((void *)NULL);}/* * Install special graphics interrupt. */voidinstall_gfxintr(cpuid_t cpu, ilvl_t swlevel, intr_func_t intr_func, void *intr_arg){ int intr_bit = GFX_INTR_A + cputolocalslice(cpu); if (intr_connect_level(cpu, intr_bit, swlevel, intr_func, intr_arg, NULL)) panic("install_gfxintr: Can't connect interrupt.");}/* * Install page migration interrupt handler. */voidhub_migrintr_init(cnodeid_t cnode){ cpuid_t cpu = cnodetocpu(cnode); int intr_bit = INT_PEND0_BASELVL + PG_MIG_INTR; if (numnodes == 1){ /* * No migration with just one node.. */ return; } if (cpu != -1) { if (intr_connect_level(cpu, intr_bit, 0, (intr_func_t) migr_intr_handler, 0, (intr_func_t) migr_intr_prologue_handler)) panic( "hub_migrintr_init: Can't connect interrupt."); }}/* * Cause all CPUs to stop by sending them each a DEBUG interrupt. * Parameter is actually a (cpumask_t *). */voiddebug_stop_all_cpus(void *stoplist){ int cpu; ulong level; for (cpu=0; cpu<maxcpus; cpu++) { if (cpu == cpuid()) continue; if (!cpu_enabled(cpu)) continue; /* "-1" is the old style parameter OR could be the new style * if no-one is currently stopped. We only stop the * requested cpus, the others are already stopped (probably * at a breakpoint). */ if (((cpumask_t *)stoplist != (cpumask_t *)-1LL) && (!CPUMASK_TSTB(*(cpumask_t*)stoplist, cpu))) continue; /* * CPU lslice A gets level DEBUG_INTR_A * CPU lslice B gets level DEBUG_INTR_B */ level = DEBUG_INTR_A + LOCALCPU(get_cpu_slice(cpu)); /* * Convert the compact hub number to the NASID to get the * correct part of the address space. Then set the interrupt * bit associated with the CPU we want to send the interrupt * to. */ REMOTE_CPU_SEND_INTR(cpu, N_INTPEND_BITS + level); }}#endif /* BRINGUP */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.", level); } }}/* * 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 PRINT_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 + -