bluesmoke.c
来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 654 行 · 第 1/2 页
C
654 行
(u32) (status >> 36) & 0x7); break; } decode_k8_generic_errcode(cpunum, status);}static void decode_k8_mc(unsigned int banknum, unsigned int cpunum, u64 status){ switch(banknum) { case 0: decode_k8_dc_mc(cpunum, status); break; case 1: decode_k8_ic_mc(cpunum, status); break; case 2: decode_k8_bu_mc(cpunum, status); break; case 3: decode_k8_ls_mc(cpunum, status); break; case 4: decode_k8_nb_mc(cpunum, status); break; }}static void k8_poll_machine_check(void){ int cpunum = safe_smp_processor_id(); int banknum; u64 address, status, ctl; struct notifier_mc_err mc_err; for(banknum=0; banknum<banks; banknum++) { if ((1UL<<banknum) & ignored_banks) continue; rdmsrl(MSR_IA32_MC0_STATUS+banknum*4, status); if(status&(1UL<<63)) { mc_err.cpunum = cpunum; mc_err.banknum = banknum; mc_err.mci_status = status; rdmsrl(MSR_IA32_MC0_ADDR+banknum*4, address); mc_err.mci_addr = address; /* Can't write anything but zeros to status, or K8 will GPF */ wrmsrl(MSR_IA32_MC0_STATUS+banknum*4, 0UL); printk(KERN_ERR "CPU%d %s polled machine check error status: %016Lx", cpunum, k8bank[banknum], status); if(status&(1UL<<58)) { printk(" at address %016Lx", address); } printk("\n"); rdmsrl(MSR_IA32_MC0_CTL+banknum*4, ctl); mc_err.mci_ctl = ctl; notifier_call_chain(&mc_notifier_list, X86_VENDOR_AMD, &mc_err); decode_k8_mc(banknum, cpunum, status); } }}static void k8_machine_check(struct pt_regs * regs, long error_code){ int norecover=1; u64 addr, status, ctl, mcgst; int banknum; unsigned int cpunum = safe_smp_processor_id(); struct notifier_mc_err mc_err; rdmsrl(MSR_IA32_MCG_STATUS, mcgst); if(mcgst&(1UL<<0)) { /* Recoverable ? */ norecover=0; } /* Make sure unrecoverable MCEs reach the console */ if(norecover) oops_in_progress++; printk(KERN_EMERG "CPU %d: Machine Check Exception: %016Lx\n", cpunum, mcgst); if (regs && (mcgst & (1UL<<1))) { printk(KERN_EMERG "CPU%d: RIP <%02lx>:%016lx RSP %016lx %s\n", cpunum, regs->cs, regs->rip, regs->rsp, (mcgst & 1) ? "" : "!INEXACT!"); } for(banknum=0; banknum<banks; banknum++) { if ((1UL<<banknum) & ignored_banks) continue; rdmsrl(MSR_IA32_MC0_STATUS+banknum*4, status); if(status&(1UL<<63)) { memset(&mc_err, 0x00, sizeof(mc_err)); mc_err.cpunum = cpunum; mc_err.banknum = banknum; mc_err.mci_status = status; if(status&(1UL<<61)) { norecover|=1; /* uncorrectable */ } if(status &(1UL<<57)) { norecover|=2; /* processor context corrupt */ } printk(KERN_EMERG "CPU%d %s error status: %016Lx", cpunum, k8bank[banknum], status); if(status&(1UL<<58)) { rdmsrl(MSR_IA32_MC0_ADDR+banknum*4, addr); mc_err.mci_addr = addr; printk(" at address %016Lx", addr); } else if ((banknum==4) && (((status>>16)&0x0f)==7)) { /* NB watchdog, address reg has details but validity bit is not set */ rdmsrl(MSR_IA32_MC0_ADDR+banknum*4, addr); mc_err.mci_addr = addr; printk(" error details %016Lx", addr); } printk("\n"); rdmsrl(MSR_IA32_MC0_CTL+banknum*4, ctl); mc_err.mci_ctl = ctl; /* Clear it */ /* Can't write anything but zeros to status, or K8 will GPF */ wrmsrl(MSR_IA32_MC0_STATUS+banknum*4, 0UL); /* Serialize */ wmb(); notifier_call_chain(&mc_notifier_list, X86_VENDOR_AMD, &mc_err); } } if(norecover&2) { panic("CPU context corrupt"); } if(norecover&1) { panic("Unable to continue"); } printk(KERN_EMERG "Attempting to continue.\n"); mcgst&=~(1UL<<2); wrmsrl(MSR_IA32_MCG_STATUS,mcgst);}static struct timer_list mcheck_timer;int mcheck_interval = 60*HZ;#ifndef CONFIG_SMP static void mcheck_timer_handler(unsigned long data){ k8_poll_machine_check(); mcheck_timer.expires = jiffies + mcheck_interval; add_timer(&mcheck_timer);}#else/* SMP needs a process context trampoline because smp_call_function cannot be called from interrupt context. */static void mcheck_timer_other(void *data){ k8_poll_machine_check();} static void mcheck_timer_dist(void *data){ smp_call_function(mcheck_timer_other,0,0,0); k8_poll_machine_check(); mcheck_timer.expires = jiffies + mcheck_interval; add_timer(&mcheck_timer);} static void mcheck_timer_handler(unsigned long data){ static struct tq_struct mcheck_task = { routine: mcheck_timer_dist }; schedule_task(&mcheck_task); } #endif static int nok8 __initdata; static void __init k8_mcheck_init(struct cpuinfo_x86 *c){ u64 cap; int i; if (!test_bit(X86_FEATURE_MCE, &c->x86_capability) || !test_bit(X86_FEATURE_MCA, &c->x86_capability)) return; rdmsrl(MSR_IA32_MCG_CAP, cap); banks = cap&0xff; for (i = 0; i < banks; i++) { u64 val = ((1UL<<i) & disabled_banks) ? 0 : ~0UL; wrmsrl(MSR_IA32_MC0_STATUS+4*i,0UL); wrmsrl(MSR_IA32_MC0_ADDR+4*i,0UL); wrmsrl(MSR_IA32_MC0_CTL+4*i, val); } /* set up the vector first, before enabling MCG_CTL */ machine_check_vector = k8_machine_check; set_in_cr4(X86_CR4_MCE); if (cap & (1<<8)) { wrmsrl(MSR_IA32_MCG_CTL, 0xffffffffffffffffULL); } if (mcheck_interval && (smp_processor_id() == 0)) { init_timer(&mcheck_timer); mcheck_timer.function = (void (*)(unsigned long))mcheck_timer_handler; mcheck_timer.expires = jiffies + mcheck_interval; add_timer(&mcheck_timer); } printk(KERN_INFO "Machine Check Reporting enabled for CPU#%d\n", smp_processor_id()); } /* * Set up machine check reporting for Intel processors */static void __init generic_mcheck_init(struct cpuinfo_x86 *c){ u32 l, h; int i; static int done; /* * Check for MCE support */ if( !test_bit(X86_FEATURE_MCE, &c->x86_capability) ) return; /* * Check for PPro style MCA */ if( !test_bit(X86_FEATURE_MCA, &c->x86_capability) ) return; /* Ok machine check is available */ machine_check_vector = generic_machine_check; wmb(); if(done==0) printk(KERN_INFO "Intel machine check architecture supported.\n"); rdmsr(MSR_IA32_MCG_CAP, l, h); if(l&(1<<8)) wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff); banks = l&0xff; for(i=0;i<banks;i++) { u32 val = ((1UL<<i) & disabled_banks) ? 0 : ~0; wrmsr(MSR_IA32_MC0_CTL+4*i, val, val); wrmsr(MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0); } set_in_cr4(X86_CR4_MCE); printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id()); done=1;}/* * This has to be run for each processor */void __init mcheck_init(struct cpuinfo_x86 *c){ if (test_and_set_bit(smp_processor_id(), &mce_cpus)) return; if(mce_disabled==1) return; switch(c->x86_vendor) { case X86_VENDOR_AMD: if (c->x86 == 15 && !nok8) { k8_mcheck_init(c); } else { generic_mcheck_init(c); } break; /* FALL THROUGH */ default: case X86_VENDOR_INTEL: generic_mcheck_init(c); break; }}static int __init mcheck_disable(char *str){ mce_disabled = 1; return 0;}/* mce=off disable machine check mce=nok8 disable k8 specific features mce=disable<NUMBER> disable bank NUMBER mce=enable<NUMBER> enable bank number mce=NUMBER mcheck timer interval number seconds. Can be also comma separated in a single mce= */static int __init mcheck_enable(char *str){ char *p; while ((p = strsep(&str,",")) != NULL) { if (isdigit(*p)) mcheck_interval = simple_strtol(p,NULL,0) * HZ; else if (!strcmp(p,"off")) mce_disabled = 1; else if (!strncmp(p,"enable",6)) disabled_banks &= ~(1UL << simple_strtol(p+6,NULL,0)); else if (!strncmp(p,"disable",7)) disabled_banks |= 1UL << simple_strtol(p+7,NULL,0); else if (!strcmp(p,"nok8")) nok8 = 1; } return 0;}__setup("nomce", mcheck_disable);__setup("mce=", mcheck_enable);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?