e752x_edac.c

来自「linux 内核源代码」· C语言 代码 · 共 1,153 行 · 第 1/3 页

C
1,153
字号
	return (((ddrcsr >> 12) & 3) == 3);}/* Remap csrow index numbers if map_type is "reverse" */static inline int remap_csrow_index(struct mem_ctl_info *mci, int index){	struct e752x_pvt *pvt = mci->pvt_info;	if (!pvt->map_type)		return (7 - index);	return (index);}static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,			u16 ddrcsr){	struct csrow_info *csrow;	unsigned long last_cumul_size;	int index, mem_dev, drc_chan;	int drc_drbg;		/* DRB granularity 0=64mb, 1=128mb */	int drc_ddim;		/* DRAM Data Integrity Mode 0=none, 2=edac */	u8 value;	u32 dra, drc, cumul_size;	dra = 0;	for (index = 0; index < 4; index++) {		u8 dra_reg;		pci_read_config_byte(pdev, E752X_DRA + index, &dra_reg);		dra |= dra_reg << (index * 8);	}	pci_read_config_dword(pdev, E752X_DRC, &drc);	drc_chan = dual_channel_active(ddrcsr);	drc_drbg = drc_chan + 1;	/* 128 in dual mode, 64 in single */	drc_ddim = (drc >> 20) & 0x3;	/* The dram row boundary (DRB) reg values are boundary address for	 * each DRAM row with a granularity of 64 or 128MB (single/dual	 * channel operation).  DRB regs are cumulative; therefore DRB7 will	 * contain the total memory contained in all eight rows.	 */	for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {		/* mem_dev 0=x8, 1=x4 */		mem_dev = (dra >> (index * 4 + 2)) & 0x3;		csrow = &mci->csrows[remap_csrow_index(mci, index)];		mem_dev = (mem_dev == 2);		pci_read_config_byte(pdev, E752X_DRB + index, &value);		/* convert a 128 or 64 MiB DRB to a page size. */		cumul_size = value << (25 + drc_drbg - PAGE_SHIFT);		debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,			cumul_size);		if (cumul_size == last_cumul_size)			continue;	/* not populated */		csrow->first_page = last_cumul_size;		csrow->last_page = cumul_size - 1;		csrow->nr_pages = cumul_size - last_cumul_size;		last_cumul_size = cumul_size;		csrow->grain = 1 << 12;	/* 4KiB - resolution of CELOG */		csrow->mtype = MEM_RDDR;	/* only one type supported */		csrow->dtype = mem_dev ? DEV_X4 : DEV_X8;		/*		 * if single channel or x8 devices then SECDED		 * if dual channel and x4 then S4ECD4ED		 */		if (drc_ddim) {			if (drc_chan && mem_dev) {				csrow->edac_mode = EDAC_S4ECD4ED;				mci->edac_cap |= EDAC_FLAG_S4ECD4ED;			} else {				csrow->edac_mode = EDAC_SECDED;				mci->edac_cap |= EDAC_FLAG_SECDED;			}		} else			csrow->edac_mode = EDAC_NONE;	}}static void e752x_init_mem_map_table(struct pci_dev *pdev,				struct e752x_pvt *pvt){	int index;	u8 value, last, row;	last = 0;	row = 0;	for (index = 0; index < 8; index += 2) {		pci_read_config_byte(pdev, E752X_DRB + index, &value);		/* test if there is a dimm in this slot */		if (value == last) {			/* no dimm in the slot, so flag it as empty */			pvt->map[index] = 0xff;			pvt->map[index + 1] = 0xff;		} else {	/* there is a dimm in the slot */			pvt->map[index] = row;			row++;			last = value;			/* test the next value to see if the dimm is double			 * sided			 */			pci_read_config_byte(pdev, E752X_DRB + index + 1,					&value);			/* the dimm is single sided, so flag as empty */			/* this is a double sided dimm to save the next row #*/			pvt->map[index + 1] = (value == last) ? 0xff :	row;			row++;			last = value;		}	}}/* Return 0 on success or 1 on failure. */static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,			struct e752x_pvt *pvt){	struct pci_dev *dev;	pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,					pvt->dev_info->err_dev, pvt->bridge_ck);	if (pvt->bridge_ck == NULL)		pvt->bridge_ck = pci_scan_single_device(pdev->bus,							PCI_DEVFN(0, 1));	if (pvt->bridge_ck == NULL) {		e752x_printk(KERN_ERR, "error reporting device not found:"			"vendor %x device 0x%x (broken BIOS?)\n",			PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);		return 1;	}	dev = pci_get_device(PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].ctl_dev,			NULL);	if (dev == NULL)		goto fail;	pvt->dev_d0f0 = dev;	pvt->dev_d0f1 = pci_dev_get(pvt->bridge_ck);	return 0;fail:	pci_dev_put(pvt->bridge_ck);	return 1;}static void e752x_init_error_reporting_regs(struct e752x_pvt *pvt){	struct pci_dev *dev;	dev = pvt->dev_d0f1;	/* Turn off error disable & SMI in case the BIOS turned it on */	pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00);	pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00);	pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x00);	pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00);	pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00);	pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00);	pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00);	pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00);}static int e752x_probe1(struct pci_dev *pdev, int dev_idx){	u16 pci_data;	u8 stat8;	struct mem_ctl_info *mci;	struct e752x_pvt *pvt;	u16 ddrcsr;	int drc_chan;		/* Number of channels 0=1chan,1=2chan */	struct e752x_error_info discard;	debugf0("%s(): mci\n", __func__);	debugf0("Starting Probe1\n");	/* make sure error reporting method is sane */	switch (edac_op_state) {	case EDAC_OPSTATE_POLL:	case EDAC_OPSTATE_NMI:		break;	default:		edac_op_state = EDAC_OPSTATE_POLL;		break;	}	/* check to see if device 0 function 1 is enabled; if it isn't, we	 * assume the BIOS has reserved it for a reason and is expecting	 * exclusive access, we take care not to violate that assumption and	 * fail the probe. */	pci_read_config_byte(pdev, E752X_DEVPRES1, &stat8);	if (!force_function_unhide && !(stat8 & (1 << 5))) {		printk(KERN_INFO "Contact your BIOS vendor to see if the "			"E752x error registers can be safely un-hidden\n");		return -ENODEV;	}	stat8 |= (1 << 5);	pci_write_config_byte(pdev, E752X_DEVPRES1, stat8);	pci_read_config_word(pdev, E752X_DDRCSR, &ddrcsr);	/* FIXME: should check >>12 or 0xf, true for all? */	/* Dual channel = 1, Single channel = 0 */	drc_chan = dual_channel_active(ddrcsr);	mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1, 0);	if (mci == NULL) {		return -ENOMEM;	}	debugf3("%s(): init mci\n", __func__);	mci->mtype_cap = MEM_FLAG_RDDR;	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED |		EDAC_FLAG_S4ECD4ED;	/* FIXME - what if different memory types are in different csrows? */	mci->mod_name = EDAC_MOD_STR;	mci->mod_ver = E752X_REVISION;	mci->dev = &pdev->dev;	debugf3("%s(): init pvt\n", __func__);	pvt = (struct e752x_pvt *)mci->pvt_info;	pvt->dev_info = &e752x_devs[dev_idx];	pvt->mc_symmetric = ((ddrcsr & 0x10) != 0);	if (e752x_get_devs(pdev, dev_idx, pvt)) {		edac_mc_free(mci);		return -ENODEV;	}	debugf3("%s(): more mci init\n", __func__);	mci->ctl_name = pvt->dev_info->ctl_name;	mci->dev_name = pci_name(pdev);	mci->edac_check = e752x_check;	mci->ctl_page_to_phys = ctl_page_to_phys;	/* set the map type.  1 = normal, 0 = reversed	 * Must be set before e752x_init_csrows in case csrow mapping	 * is reversed.	 */	pci_read_config_byte(pdev, E752X_DRM, &stat8);	pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f));	e752x_init_csrows(mci, pdev, ddrcsr);	e752x_init_mem_map_table(pdev, pvt);	mci->edac_cap |= EDAC_FLAG_NONE;	debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);	/* load the top of low memory, remap base, and remap limit vars */	pci_read_config_word(pdev, E752X_TOLM, &pci_data);	pvt->tolm = ((u32) pci_data) << 4;	pci_read_config_word(pdev, E752X_REMAPBASE, &pci_data);	pvt->remapbase = ((u32) pci_data) << 14;	pci_read_config_word(pdev, E752X_REMAPLIMIT, &pci_data);	pvt->remaplimit = ((u32) pci_data) << 14;	e752x_printk(KERN_INFO,			"tolm = %x, remapbase = %x, remaplimit = %x\n",			pvt->tolm, pvt->remapbase, pvt->remaplimit);	/* Here we assume that we will never see multiple instances of this	 * type of memory controller.  The ID is therefore hardcoded to 0.	 */	if (edac_mc_add_mc(mci)) {		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);		goto fail;	}	e752x_init_error_reporting_regs(pvt);	e752x_get_error_info(mci, &discard);	/* clear other MCH errors */	/* allocating generic PCI control info */	e752x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);	if (!e752x_pci) {		printk(KERN_WARNING			"%s(): Unable to create PCI control\n", __func__);		printk(KERN_WARNING			"%s(): PCI error report via EDAC not setup\n",			__func__);	}	/* get this far and it's successful */	debugf3("%s(): success\n", __func__);	return 0;fail:	pci_dev_put(pvt->dev_d0f0);	pci_dev_put(pvt->dev_d0f1);	pci_dev_put(pvt->bridge_ck);	edac_mc_free(mci);	return -ENODEV;}/* returns count (>= 0), or negative on error */static int __devinit e752x_init_one(struct pci_dev *pdev,				const struct pci_device_id *ent){	debugf0("%s()\n", __func__);	/* wake up and enable device */	if (pci_enable_device(pdev) < 0)		return -EIO;	return e752x_probe1(pdev, ent->driver_data);}static void __devexit e752x_remove_one(struct pci_dev *pdev){	struct mem_ctl_info *mci;	struct e752x_pvt *pvt;	debugf0("%s()\n", __func__);	if (e752x_pci)		edac_pci_release_generic_ctl(e752x_pci);	if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)		return;	pvt = (struct e752x_pvt *)mci->pvt_info;	pci_dev_put(pvt->dev_d0f0);	pci_dev_put(pvt->dev_d0f1);	pci_dev_put(pvt->bridge_ck);	edac_mc_free(mci);}static const struct pci_device_id e752x_pci_tbl[] __devinitdata = {	{	 PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,	 E7520},	{	 PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,	 E7525},	{	 PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,	 E7320},	{	 0,	 }			/* 0 terminated list. */};MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);static struct pci_driver e752x_driver = {	.name = EDAC_MOD_STR,	.probe = e752x_init_one,	.remove = __devexit_p(e752x_remove_one),	.id_table = e752x_pci_tbl,};static int __init e752x_init(void){	int pci_rc;	debugf3("%s()\n", __func__);	pci_rc = pci_register_driver(&e752x_driver);	return (pci_rc < 0) ? pci_rc : 0;}static void __exit e752x_exit(void){	debugf3("%s()\n", __func__);	pci_unregister_driver(&e752x_driver);}module_init(e752x_init);module_exit(e752x_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n");MODULE_DESCRIPTION("MC support for Intel e752x memory controllers");module_param(force_function_unhide, int, 0444);MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:"		 " 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access");module_param(edac_op_state, int, 0444);MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");

⌨️ 快捷键说明

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