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 + -
显示快捷键?