diff options
Diffstat (limited to 'drivers/edac/e752x_edac.c')
| -rw-r--r-- | drivers/edac/e752x_edac.c | 114 | 
1 files changed, 78 insertions, 36 deletions
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index 41223261ede..3186512c973 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -4,7 +4,11 @@   * This file may be distributed under the terms of the   * GNU General Public License.   * - * See "enum e752x_chips" below for supported chipsets + * Implement support for the e7520, E7525, e7320 and i3100 memory controllers. + * + * Datasheets: + *	http://www.intel.in/content/www/in/en/chipsets/e7525-memory-controller-hub-datasheet.html + *	ftp://download.intel.com/design/intarch/datashts/31345803.pdf   *   * Written by Tom Zimmerman   * @@ -13,8 +17,6 @@   * 	Wang Zhenyu at intel.com   * 	Dave Jiang at mvista.com   * - * $Id: edac_e752x.c,v 1.5.2.11 2005/10/05 00:43:44 dsp_llnl Exp $ - *   */  #include <linux/module.h> @@ -187,6 +189,25 @@ enum e752x_chips {  	I3100 = 3  }; +/* + * Those chips Support single-rank and dual-rank memories only. + * + * On e752x chips, the odd rows are present only on dual-rank memories. + * Dividing the rank by two will provide the dimm# + * + * i3100 MC has a different mapping: it supports only 4 ranks. + * + * The mapping is (from 1 to n): + *	slot	   single-ranked	double-ranked + *	dimm #1 -> rank #4		NA + *	dimm #2 -> rank #3		NA + *	dimm #3 -> rank #2		Ranks 2 and 3 + *	dimm #4 -> rank $1		Ranks 1 and 4 + * + * FIXME: The current mapping for i3100 considers that it supports up to 8 + *	  ranks/chanel, but datasheet says that the MC supports only 4 ranks. + */ +  struct e752x_pvt {  	struct pci_dev *bridge_ck;  	struct pci_dev *dev_d0f0; @@ -350,8 +371,10 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,  	channel = !(error_one & 1);  	/* e752x mc reads 34:6 of the DRAM linear address */ -	edac_mc_handle_ce(mci, page, offset_in_page(sec1_add << 4), -			sec1_syndrome, row, channel, "e752x CE"); +	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, +			     page, offset_in_page(sec1_add << 4), sec1_syndrome, +			     row, channel, -1, +			     "e752x CE", "", NULL);  }  static inline void process_ce(struct mem_ctl_info *mci, u16 error_one, @@ -385,9 +408,12 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,  			edac_mc_find_csrow_by_page(mci, block_page);  		/* e752x mc reads 34:6 of the DRAM linear address */ -		edac_mc_handle_ue(mci, block_page, -				offset_in_page(error_2b << 4), -				row, "e752x UE from Read"); +		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, +					block_page, +					offset_in_page(error_2b << 4), 0, +					 row, -1, -1, +					"e752x UE from Read", "", NULL); +  	}  	if (error_one & 0x0404) {  		error_2b = scrb_add; @@ -401,9 +427,11 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,  			edac_mc_find_csrow_by_page(mci, block_page);  		/* e752x mc reads 34:6 of the DRAM linear address */ -		edac_mc_handle_ue(mci, block_page, -				offset_in_page(error_2b << 4), -				row, "e752x UE from Scruber"); +		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, +					block_page, +					offset_in_page(error_2b << 4), 0, +					row, -1, -1, +					"e752x UE from Scruber", "", NULL);  	}  } @@ -426,7 +454,9 @@ static inline void process_ue_no_info_wr(struct mem_ctl_info *mci,  		return;  	debugf3("%s()\n", __func__); -	edac_mc_handle_ue_no_info(mci, "e752x UE log memory write"); +	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, +			     -1, -1, -1, +			     "e752x UE log memory write", "", NULL);  }  static void do_process_ded_retry(struct mem_ctl_info *mci, u16 error, @@ -1044,7 +1074,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,  	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; +	u32 dra, drc, cumul_size, i, nr_pages;  	dra = 0;  	for (index = 0; index < 4; index++) { @@ -1053,7 +1083,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,  		dra |= dra_reg << (index * 8);  	}  	pci_read_config_dword(pdev, E752X_DRC, &drc); -	drc_chan = dual_channel_active(ddrcsr); +	drc_chan = dual_channel_active(ddrcsr) ? 1 : 0;  	drc_drbg = drc_chan + 1;	/* 128 in dual mode, 64 in single */  	drc_ddim = (drc >> 20) & 0x3; @@ -1078,26 +1108,33 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,  		csrow->first_page = last_cumul_size;  		csrow->last_page = cumul_size - 1; -		csrow->nr_pages = cumul_size - last_cumul_size; +		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; +		for (i = 0; i < csrow->nr_channels; i++) { +			struct dimm_info *dimm = csrow->channels[i].dimm; + +			debugf3("Initializing rank at (%i,%i)\n", index, i); +			dimm->nr_pages = nr_pages / csrow->nr_channels; +			dimm->grain = 1 << 12;	/* 4KiB - resolution of CELOG */ +			dimm->mtype = MEM_RDDR;	/* only one type supported */ +			dimm->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) { +					dimm->edac_mode = EDAC_S4ECD4ED; +					mci->edac_cap |= EDAC_FLAG_S4ECD4ED; +				} else { +					dimm->edac_mode = EDAC_SECDED; +					mci->edac_cap |= EDAC_FLAG_SECDED; +				} +			} else +				dimm->edac_mode = EDAC_NONE; +		}  	}  } @@ -1226,6 +1263,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)  	u16 pci_data;  	u8 stat8;  	struct mem_ctl_info *mci; +	struct edac_mc_layer layers[2];  	struct e752x_pvt *pvt;  	u16 ddrcsr;  	int drc_chan;		/* Number of channels 0=1chan,1=2chan */ @@ -1252,11 +1290,15 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)  	/* 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) { +	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; +	layers[0].size = E752X_NR_CSROWS; +	layers[0].is_virt_csrow = true; +	layers[1].type = EDAC_MC_LAYER_CHANNEL; +	layers[1].size = drc_chan + 1; +	layers[1].is_virt_csrow = false; +	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt)); +	if (mci == NULL)  		return -ENOMEM; -	}  	debugf3("%s(): init mci\n", __func__);  	mci->mtype_cap = MEM_FLAG_RDDR;  |