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

📄 mca_drv.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * File:	mca_drv.c * Purpose:	Generic MCA handling layer * * Copyright (C) 2004 FUJITSU LIMITED * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com) * Copyright (C) 2005 Silicon Graphics, Inc * Copyright (C) 2005 Keith Owens <kaos@sgi.com> * Copyright (C) 2006 Russ Anderson <rja@sgi.com> */#include <linux/types.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/irq.h>#include <linux/kallsyms.h>#include <linux/bootmem.h>#include <linux/acpi.h>#include <linux/timer.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/smp.h>#include <linux/workqueue.h>#include <linux/mm.h>#include <asm/delay.h>#include <asm/machvec.h>#include <asm/page.h>#include <asm/ptrace.h>#include <asm/system.h>#include <asm/sal.h>#include <asm/mca.h>#include <asm/irq.h>#include <asm/hw_irq.h>#include "mca_drv.h"/* max size of SAL error record (default) */static int sal_rec_max = 10000;/* from mca_drv_asm.S */extern void *mca_handler_bhhook(void);static DEFINE_SPINLOCK(mca_bh_lock);typedef enum {	MCA_IS_LOCAL  = 0,	MCA_IS_GLOBAL = 1} mca_type_t;#define MAX_PAGE_ISOLATE 1024static struct page *page_isolate[MAX_PAGE_ISOLATE];static int num_page_isolate = 0;typedef enum {	ISOLATE_NG,	ISOLATE_OK,	ISOLATE_NONE} isolate_status_t;typedef enum {	MCA_NOT_RECOVERED = 0,	MCA_RECOVERED	  = 1} recovery_status_t;/* *  This pool keeps pointers to the section part of SAL error record */static struct {	slidx_list_t *buffer; /* section pointer list pool */	int	     cur_idx; /* Current index of section pointer list pool */	int	     max_idx; /* Maximum index of section pointer list pool */} slidx_pool;static intfatal_mca(const char *fmt, ...){	va_list args;	char buf[256];	va_start(args, fmt);	vsnprintf(buf, sizeof(buf), fmt, args);	va_end(args);	ia64_mca_printk(KERN_ALERT "MCA: %s\n", buf);	return MCA_NOT_RECOVERED;}static intmca_recovered(const char *fmt, ...){	va_list args;	char buf[256];	va_start(args, fmt);	vsnprintf(buf, sizeof(buf), fmt, args);	va_end(args);	ia64_mca_printk(KERN_INFO "MCA: %s\n", buf);	return MCA_RECOVERED;}/** * mca_page_isolate - isolate a poisoned page in order not to use it later * @paddr:	poisoned memory location * * Return value: *	one of isolate_status_t, ISOLATE_OK/NG/NONE. */static isolate_status_tmca_page_isolate(unsigned long paddr){	int i;	struct page *p;	/* whether physical address is valid or not */	if (!ia64_phys_addr_valid(paddr))		return ISOLATE_NONE;	if (!pfn_valid(paddr >> PAGE_SHIFT))		return ISOLATE_NONE;	/* convert physical address to physical page number */	p = pfn_to_page(paddr>>PAGE_SHIFT);	/* check whether a page number have been already registered or not */	for (i = 0; i < num_page_isolate; i++)		if (page_isolate[i] == p)			return ISOLATE_OK; /* already listed */	/* limitation check */	if (num_page_isolate == MAX_PAGE_ISOLATE)		return ISOLATE_NG;	/* kick pages having attribute 'SLAB' or 'Reserved' */	if (PageSlab(p) || PageReserved(p))		return ISOLATE_NG;	/* add attribute 'Reserved' and register the page */	get_page(p);	SetPageReserved(p);	page_isolate[num_page_isolate++] = p;	return ISOLATE_OK;}/** * mca_hanlder_bh - Kill the process which occurred memory read error * @paddr:	poisoned address received from MCA Handler */voidmca_handler_bh(unsigned long paddr, void *iip, unsigned long ipsr){	ia64_mlogbuf_dump();	printk(KERN_ERR "OS_MCA: process [cpu %d, pid: %d, uid: %d, "		"iip: %p, psr: 0x%lx,paddr: 0x%lx](%s) encounters MCA.\n",		raw_smp_processor_id(), current->pid, current->uid,		iip, ipsr, paddr, current->comm);	spin_lock(&mca_bh_lock);	switch (mca_page_isolate(paddr)) {	case ISOLATE_OK:		printk(KERN_DEBUG "Page isolation: ( %lx ) success.\n", paddr);		break;	case ISOLATE_NG:		printk(KERN_CRIT "Page isolation: ( %lx ) failure.\n", paddr);		break;	default:		break;	}	spin_unlock(&mca_bh_lock);	/* This process is about to be killed itself */	do_exit(SIGKILL);}/** * mca_make_peidx - Make index of processor error section * @slpi:	pointer to record of processor error section * @peidx:	pointer to index of processor error section */static voidmca_make_peidx(sal_log_processor_info_t *slpi, peidx_table_t *peidx){	/*	 * calculate the start address of	 *   "struct cpuid_info" and "sal_processor_static_info_t".	 */	u64 total_check_num = slpi->valid.num_cache_check				+ slpi->valid.num_tlb_check				+ slpi->valid.num_bus_check				+ slpi->valid.num_reg_file_check				+ slpi->valid.num_ms_check;	u64 head_size =	sizeof(sal_log_mod_error_info_t) * total_check_num			+ sizeof(sal_log_processor_info_t);	u64 mid_size  = slpi->valid.cpuid_info * sizeof(struct sal_cpuid_info);	peidx_head(peidx)   = slpi;	peidx_mid(peidx)    = (struct sal_cpuid_info *)		(slpi->valid.cpuid_info ? ((char*)slpi + head_size) : NULL);	peidx_bottom(peidx) = (sal_processor_static_info_t *)		(slpi->valid.psi_static_struct ?			((char*)slpi + head_size + mid_size) : NULL);}/** * mca_make_slidx -  Make index of SAL error record * @buffer:	pointer to SAL error record * @slidx:	pointer to index of SAL error record * * Return value: *	1 if record has platform error / 0 if not */#define LOG_INDEX_ADD_SECT_PTR(sect, ptr) \	{slidx_list_t *hl = &slidx_pool.buffer[slidx_pool.cur_idx]; \	hl->hdr = ptr; \	list_add(&hl->list, &(sect)); \	slidx_pool.cur_idx = (slidx_pool.cur_idx + 1)%slidx_pool.max_idx; }static intmca_make_slidx(void *buffer, slidx_table_t *slidx){	int platform_err = 0;	int record_len = ((sal_log_record_header_t*)buffer)->len;	u32 ercd_pos;	int sects;	sal_log_section_hdr_t *sp;	/*	 * Initialize index referring current record	 */	INIT_LIST_HEAD(&(slidx->proc_err));	INIT_LIST_HEAD(&(slidx->mem_dev_err));	INIT_LIST_HEAD(&(slidx->sel_dev_err));	INIT_LIST_HEAD(&(slidx->pci_bus_err));	INIT_LIST_HEAD(&(slidx->smbios_dev_err));	INIT_LIST_HEAD(&(slidx->pci_comp_err));	INIT_LIST_HEAD(&(slidx->plat_specific_err));	INIT_LIST_HEAD(&(slidx->host_ctlr_err));	INIT_LIST_HEAD(&(slidx->plat_bus_err));	INIT_LIST_HEAD(&(slidx->unsupported));	/*	 * Extract a Record Header	 */	slidx->header = buffer;	/*	 * Extract each section records	 * (arranged from "int ia64_log_platform_info_print()")	 */	for (ercd_pos = sizeof(sal_log_record_header_t), sects = 0;		ercd_pos < record_len; ercd_pos += sp->len, sects++) {		sp = (sal_log_section_hdr_t *)((char*)buffer + ercd_pos);		if (!efi_guidcmp(sp->guid, SAL_PROC_DEV_ERR_SECT_GUID)) {			LOG_INDEX_ADD_SECT_PTR(slidx->proc_err, sp);		} else if (!efi_guidcmp(sp->guid,				SAL_PLAT_MEM_DEV_ERR_SECT_GUID)) {			platform_err = 1;			LOG_INDEX_ADD_SECT_PTR(slidx->mem_dev_err, sp);		} else if (!efi_guidcmp(sp->guid,				SAL_PLAT_SEL_DEV_ERR_SECT_GUID)) {			platform_err = 1;			LOG_INDEX_ADD_SECT_PTR(slidx->sel_dev_err, sp);		} else if (!efi_guidcmp(sp->guid,				SAL_PLAT_PCI_BUS_ERR_SECT_GUID)) {			platform_err = 1;			LOG_INDEX_ADD_SECT_PTR(slidx->pci_bus_err, sp);		} else if (!efi_guidcmp(sp->guid,				SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID)) {			platform_err = 1;			LOG_INDEX_ADD_SECT_PTR(slidx->smbios_dev_err, sp);		} else if (!efi_guidcmp(sp->guid,				SAL_PLAT_PCI_COMP_ERR_SECT_GUID)) {			platform_err = 1;			LOG_INDEX_ADD_SECT_PTR(slidx->pci_comp_err, sp);		} else if (!efi_guidcmp(sp->guid,				SAL_PLAT_SPECIFIC_ERR_SECT_GUID)) {			platform_err = 1;			LOG_INDEX_ADD_SECT_PTR(slidx->plat_specific_err, sp);		} else if (!efi_guidcmp(sp->guid,				SAL_PLAT_HOST_CTLR_ERR_SECT_GUID)) {			platform_err = 1;			LOG_INDEX_ADD_SECT_PTR(slidx->host_ctlr_err, sp);		} else if (!efi_guidcmp(sp->guid,				SAL_PLAT_BUS_ERR_SECT_GUID)) {			platform_err = 1;			LOG_INDEX_ADD_SECT_PTR(slidx->plat_bus_err, sp);		} else {			LOG_INDEX_ADD_SECT_PTR(slidx->unsupported, sp);		}	}	slidx->n_sections = sects;	return platform_err;}/** * init_record_index_pools - Initialize pool of lists for SAL record index * * Return value: *	0 on Success / -ENOMEM on Failure */static intinit_record_index_pools(void){	int i;	int rec_max_size;  /* Maximum size of SAL error records */	int sect_min_size; /* Minimum size of SAL error sections */	/* minimum size table of each section */	static int sal_log_sect_min_sizes[] = {		sizeof(sal_log_processor_info_t)		+ sizeof(sal_processor_static_info_t),		sizeof(sal_log_mem_dev_err_info_t),		sizeof(sal_log_sel_dev_err_info_t),		sizeof(sal_log_pci_bus_err_info_t),		sizeof(sal_log_smbios_dev_err_info_t),		sizeof(sal_log_pci_comp_err_info_t),		sizeof(sal_log_plat_specific_err_info_t),		sizeof(sal_log_host_ctlr_err_info_t),		sizeof(sal_log_plat_bus_err_info_t),	};	/*	 * MCA handler cannot allocate new memory on flight,	 * so we preallocate enough memory to handle a SAL record.	 *	 * Initialize a handling set of slidx_pool:	 *   1. Pick up the max size of SAL error records	 *   2. Pick up the min size of SAL error sections	 *   3. Allocate the pool as enough to 2 SAL records	 *     (now we can estimate the maxinum of section in a record.)	 */	/* - 1 - */	rec_max_size = sal_rec_max;	/* - 2 - */	sect_min_size = sal_log_sect_min_sizes[0];	for (i = 1; i < sizeof sal_log_sect_min_sizes/sizeof(size_t); i++)		if (sect_min_size > sal_log_sect_min_sizes[i])			sect_min_size = sal_log_sect_min_sizes[i];	/* - 3 - */	slidx_pool.max_idx = (rec_max_size/sect_min_size) * 2 + 1;	slidx_pool.buffer = (slidx_list_t *)		kmalloc(slidx_pool.max_idx * sizeof(slidx_list_t), GFP_KERNEL);	return slidx_pool.buffer ? 0 : -ENOMEM;}/***************************************************************************** * Recovery functions                                                        * *****************************************************************************//** * is_mca_global - Check whether this MCA is global or not * @peidx:	pointer of index of processor error section * @pbci:	pointer to pal_bus_check_info_t * @sos:	pointer to hand off struct between SAL and OS * * Return value: *	MCA_IS_LOCAL / MCA_IS_GLOBAL */static mca_type_tis_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci,	      struct ia64_sal_os_state *sos){	pal_processor_state_info_t *psp =		(pal_processor_state_info_t*)peidx_psp(peidx);	/*	 * PAL can request a rendezvous, if the MCA has a global scope.	 * If "rz_always" flag is set, SAL requests MCA rendezvous	 * in spite of global MCA.	 * Therefore it is local MCA when rendezvous has not been requested.	 * Failed to rendezvous, the system must be down.	 */	switch (sos->rv_rc) {		case -1: /* SAL rendezvous unsuccessful */			return MCA_IS_GLOBAL;		case  0: /* SAL rendezvous not required */			return MCA_IS_LOCAL;		case  1: /* SAL rendezvous successful int */		case  2: /* SAL rendezvous successful int with init */		default:			break;	}	/*	 * If One or more Cache/TLB/Reg_File/Uarch_Check is here,

⌨️ 快捷键说明

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