⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ecc-berr.c

📁 底层驱动开发
💻 C
字号:
/* *	linux/arch/mips/dec/ecc-berr.c * *	Bus error event handling code for systems equipped with ECC *	handling logic, i.e. DECstation/DECsystem 5000/200 (KN02), *	5000/240 (KN03), 5000/260 (KN05) and DECsystem 5900 (KN03), *	5900/260 (KN05) systems. * *	Copyright (c) 2003  Maciej W. Rozycki * *	This program is free software; you can redistribute it and/or *	modify it under the terms of the GNU General Public License *	as published by the Free Software Foundation; either version *	2 of the License, or (at your option) any later version. */#include <linux/init.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/spinlock.h>#include <linux/types.h>#include <asm/addrspace.h>#include <asm/bootinfo.h>#include <asm/cpu.h>#include <asm/processor.h>#include <asm/system.h>#include <asm/traps.h>#include <asm/dec/ecc.h>#include <asm/dec/kn02.h>#include <asm/dec/kn03.h>#include <asm/dec/kn05.h>static volatile u32 *kn0x_erraddr;static volatile u32 *kn0x_chksyn;static inline void dec_ecc_be_ack(void){	*kn0x_erraddr = 0;			/* any write clears the IRQ */	iob();}static int dec_ecc_be_backend(struct pt_regs *regs, int is_fixup, int invoker){	static const char excstr[] = "exception";	static const char intstr[] = "interrupt";	static const char cpustr[] = "CPU";	static const char dmastr[] = "DMA";	static const char readstr[] = "read";	static const char mreadstr[] = "memory read";	static const char writestr[] = "write";	static const char mwritstr[] = "partial memory write";	static const char timestr[] = "timeout";	static const char overstr[] = "overrun";	static const char eccstr[] = "ECC error";	const char *kind, *agent, *cycle, *event;	const char *status = "", *xbit = "", *fmt = "";	dma_addr_t address;	u16 syn = 0, sngl;	int i = 0;	u32 erraddr = *kn0x_erraddr;	u32 chksyn = *kn0x_chksyn;	int action = MIPS_BE_FATAL;	/* For non-ECC ack ASAP, so any subsequent errors get caught. */	if ((erraddr & (KN0X_EAR_VALID | KN0X_EAR_ECCERR)) == KN0X_EAR_VALID)		dec_ecc_be_ack();	kind = invoker ? intstr : excstr;	if (!(erraddr & KN0X_EAR_VALID)) {		/* No idea what happened. */		printk(KERN_ALERT "Unidentified bus error %s.\n", kind);		return action;	}	agent = (erraddr & KN0X_EAR_CPU) ? cpustr : dmastr;	if (erraddr & KN0X_EAR_ECCERR) {		/* An ECC error on a CPU or DMA transaction. */		cycle = (erraddr & KN0X_EAR_WRITE) ? mwritstr : mreadstr;		event = eccstr;	} else {		/* A CPU timeout or a DMA overrun. */		cycle = (erraddr & KN0X_EAR_WRITE) ? writestr : readstr;		event = (erraddr & KN0X_EAR_CPU) ? timestr : overstr;	}	address = erraddr & KN0X_EAR_ADDRESS;	/* For ECC errors on reads adjust for MT pipelining. */	if ((erraddr & (KN0X_EAR_WRITE | KN0X_EAR_ECCERR)) == KN0X_EAR_ECCERR)		address = (address & ~0xfffLL) | ((address - 5) & 0xfffLL);	address <<= 2;	/* Only CPU errors are fixable. */	if (erraddr & KN0X_EAR_CPU && is_fixup)		action = MIPS_BE_FIXUP;	if (erraddr & KN0X_EAR_ECCERR) {		static const u8 data_sbit[32] = {			0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d,			0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34,			0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c,			0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75,		};		static const u8 data_mbit[25] = {			0x07, 0x0d, 0x1f,			0x2f, 0x32, 0x37, 0x38, 0x3b, 0x3d, 0x3e,			0x43, 0x45, 0x46, 0x49, 0x4c, 0x51, 0x5e,			0x61, 0x6e, 0x73, 0x76, 0x79, 0x7a, 0x7c, 0x7f,		};		static const char sbestr[] = "corrected single";		static const char dbestr[] = "uncorrectable double";		static const char mbestr[] = "uncorrectable multiple";		if (!(address & 0x4))			syn = chksyn;			/* Low bank. */		else			syn = chksyn >> 16;		/* High bank. */		if (!(syn & KN0X_ESR_VLDLO)) {			/* Ack now, no rewrite will happen. */			dec_ecc_be_ack();			fmt = KERN_ALERT "%s" "invalid.\n";		} else {			sngl = syn & KN0X_ESR_SNGLO;			syn &= KN0X_ESR_SYNLO;			/*			 * Multibit errors may be tagged incorrectly;			 * check the syndrome explicitly.			 */			for (i = 0; i < 25; i++)				if (syn == data_mbit[i])					break;			if (i < 25) {				status = mbestr;			} else if (!sngl) {				status = dbestr;			} else {				volatile u32 *ptr = (void *)KSEG1ADDR(address);				*ptr = *ptr;		/* Rewrite. */				iob();				status = sbestr;				action = MIPS_BE_DISCARD;			}			/* Ack now, now we've rewritten (or not). */			dec_ecc_be_ack();			if (syn && syn == (syn & -syn)) {				if (syn == 0x01) {					fmt = KERN_ALERT "%s"					      "%#04x -- %s bit error "					      "at check bit C%s.\n";					xbit = "X";				} else {					fmt = KERN_ALERT "%s"					      "%#04x -- %s bit error "					      "at check bit C%s%u.\n";				}				i = syn >> 2;			} else {				for (i = 0; i < 32; i++)					if (syn == data_sbit[i])						break;				if (i < 32)					fmt = KERN_ALERT "%s"					      "%#04x -- %s bit error "					      "at data bit D%s%u.\n";				else					fmt = KERN_ALERT "%s"					      "%#04x -- %s bit error.\n";			}		}	}	if (action != MIPS_BE_FIXUP)		printk(KERN_ALERT "Bus error %s: %s %s %s at %#010lx.\n",			kind, agent, cycle, event, address);	if (action != MIPS_BE_FIXUP && erraddr & KN0X_EAR_ECCERR)		printk(fmt, "  ECC syndrome ", syn, status, xbit, i);	return action;}int dec_ecc_be_handler(struct pt_regs *regs, int is_fixup){	return dec_ecc_be_backend(regs, is_fixup, 0);}irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id, struct pt_regs *regs){	int action = dec_ecc_be_backend(regs, 0, 1);	if (action == MIPS_BE_DISCARD)		return IRQ_NONE;	/*	 * FIXME: Find affected processes and kill them, otherwise we	 * must die.	 *	 * The interrupt is asynchronously delivered thus EPC and RA	 * may be irrelevant, but are printed for a reference.	 */	printk(KERN_ALERT "Fatal bus interrupt, epc == %08lx, ra == %08lx\n",	       regs->cp0_epc, regs->regs[31]);	die("Unrecoverable bus error", regs);}/* * Initialization differs a bit between KN02 and KN03/KN05, so we * need two variants.  Once set up, all systems can be handled the * same way. */static inline void dec_kn02_be_init(void){	volatile u32 *csr = (void *)KN02_CSR_BASE;	unsigned long flags;	kn0x_erraddr = (void *)(KN02_SLOT_BASE + KN02_ERRADDR);	kn0x_chksyn = (void *)(KN02_SLOT_BASE + KN02_CHKSYN);	spin_lock_irqsave(&kn02_lock, flags);	/* Preset write-only bits of the Control Register cache. */	cached_kn02_csr = *csr | KN03_CSR_LEDS;	/* Set normal ECC detection and generation. */	cached_kn02_csr &= ~(KN02_CSR_DIAGCHK | KN02_CSR_DIAGGEN);	/* Enable ECC correction. */	cached_kn02_csr |= KN02_CSR_CORRECT;	*csr = cached_kn02_csr;	iob();	spin_unlock_irqrestore(&kn02_lock, flags);}static inline void dec_kn03_be_init(void){	volatile u32 *mcr = (void *)(KN03_SLOT_BASE + IOASIC_MCR);	volatile u32 *mbcs = (void *)(KN03_SLOT_BASE + KN05_MB_CSR);	kn0x_erraddr = (void *)(KN03_SLOT_BASE + IOASIC_ERRADDR);	kn0x_chksyn = (void *)(KN03_SLOT_BASE + IOASIC_CHKSYN);	/*	 * Set normal ECC detection and generation, enable ECC correction.	 * For KN05 we also need to make sure EE (?) is enabled in the MB.	 * Otherwise DBE/IBE exceptions would be masked but bus error	 * interrupts would still arrive, resulting in an inevitable crash	 * if get_dbe() triggers one.	 */	*mcr = (*mcr & ~(KN03_MCR_DIAGCHK | KN03_MCR_DIAGGEN)) |	       KN03_MCR_CORRECT;	if (current_cpu_data.cputype == CPU_R4400SC)		*mbcs |= KN05_MB_CSR_EE;	fast_iob();}void __init dec_ecc_be_init(void){	if (mips_machtype == MACH_DS5000_200)		dec_kn02_be_init();	else		dec_kn03_be_init();	/* Clear any leftover errors from the firmware. */	dec_ecc_be_ack();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -