lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Fri, 8 May 2009 06:39:00 -0300
From:	Mauro Carvalho Chehab <mchehab@...hat.com>
To:	Borislav Petkov <borislav.petkov@....com>
Cc:	<akpm@...ux-foundation.org>, <greg@...ah.com>, <mingo@...e.hu>,
	<norsk5@...oo.com>, <tglx@...utronix.de>, <hpa@...or.com>,
	<aris@...hat.com>, edt@....ca, <linux-kernel@...r.kernel.org>,
	Doug Thompson <dougthompson@...ssion.com>,
	Borislav Petkov <borislav.petkov@....com>
Subject: Re: [PATCH 15/21] amd64_edac: add F10h-and-later methods-p3

Em Thu, 7 May 2009 15:49:37 +0200
Borislav Petkov <borislav.petkov@....com> escreveu:

> From: Doug Thompson <dougthompson@...ssion.com>
> 
> Borislav: cleanup, remove StinkyIdentifiers, simplify logic
> 
> Signed-off-by: Doug Thompson <dougthompson@...ssion.com>
> Signed-off-by: Borislav Petkov <borislav.petkov@....com>

Reviewed-by: Mauro Carvalho Chehab <mchehab@...hat.com>


> ---
>  drivers/edac/amd64_edac.c |  292 ++++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 288 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
> index 3dc04c0..a805554 100644
> --- a/drivers/edac/amd64_edac.c
> +++ b/drivers/edac/amd64_edac.c
> @@ -1554,6 +1554,10 @@ static void f10_read_dram_ctl_register(struct amd64_pvt *pvt)
>  			pvt->dram_ctl_select_high);
>  }
>  
> +/*
> + * determine channel based on the interleaving mode: F10h BKDG, 2.8.9 Memory
> + * Interleaving Modes.
> + */
>  static u32 f10_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
>  				int hi_range_sel, u32 intlv_en)
>  {
> @@ -1564,6 +1568,9 @@ static u32 f10_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
>  	else if (hi_range_sel)
>  		cs = dct_sel_high;
>  	else if (dct_interleave_enabled(pvt)) {
> +		/*
> +		 * see F2x110[DctSelIntLvAddr] - channel interleave mode
> +		 */
>  		if (dct_sel_interleave_addr(pvt) == 0)
>  			cs = sys_addr >> 6 & 1;
>  		else if ((dct_sel_interleave_addr(pvt) >> 1) & 1) {
> @@ -1601,22 +1608,25 @@ static inline u32 f10_map_intlv_en_to_shift(u32 intlv_en)
>  	return 0;
>  }
>  
> -static inline u64 f10_determine_base_addr_offset(u64 sys_addr, int hi_range_sel,
> +/*
> + * See F10h BKDG, 2.8.10.2 DctSelBaseOffset Programming
> + */
> +static inline u64 f10_get_base_addr_offset(u64 sys_addr, int hi_range_sel,
>  						 u32 dct_sel_base_addr,
>  						 u64 dct_sel_base_off,
> -						 u32 hole_en, u32 hole_off,
> +						 u32 hole_valid, u32 hole_off,
>  						 u64 dram_base)
>  {
>  	u64 chan_off;
>  
>  	if (hi_range_sel) {
>  		if ((!dct_sel_base_addr & 0xFFFF0000) &&
> -		   (hole_en & 1) && (sys_addr >= 0x100000000ULL))
> +		    hole_valid && (sys_addr >= 0x100000000ULL))
>  			chan_off = hole_off << 16;
>  		else
>  			chan_off = dct_sel_base_off;
>  	} else {
> -		if ((hole_en & 1) && (sys_addr >= 0x100000000ULL))
> +		if (hole_valid && (sys_addr >= 0x100000000ULL))
>  			chan_off = hole_off << 16;
>  		else
>  			chan_off = dram_base & 0xFFFFF8000000ULL;
> @@ -1724,4 +1734,278 @@ static int f10_lookup_addr_in_dct(u32 in_addr, u32 nid, u32 cs)
>  	return cs_found;
>  }
>  
> +/*
> + * f10_match_to_this_node
> + *
> + * For a given 'DramRange' value, check if 'SystemAddr' fall within this value
> + */
> +static int f10_match_to_this_node(struct amd64_pvt *pvt, int dram_range,
> +				  u64 sys_addr, int *nid, int *chan_sel)
> +{
> +	int node_id, cs_found = -EINVAL, high_range = 0;
> +	u32 intlv_en, intlv_sel, intlv_shift, hole_off;
> +	u32 hole_valid, tmp, dct_sel_base, channel;
> +	u64 dram_base, chan_addr;
> +
> +	/* DRAM base and limit values for this DRAM instance */
> +	dram_base = pvt->dram_base[dram_range];
> +	intlv_en = pvt->dram_IntlvEn[dram_range];
> +
> +	node_id = pvt->dram_DstNode[dram_range];
> +	intlv_sel = pvt->dram_IntlvSel[dram_range];
> +
> +	debugf1("%s(dram=%d) Base=0x%llx SystemAddr= 0x%llx Limit=0x%llx\n",
> +		__func__, dram_range, dram_base, sys_addr,
> +		pvt->dram_limit[dram_range]);
> +
> +	/*
> +	 * This assumes that one node's DHAR is the same as all the other
> +	 * nodes' DHAR.
> +	 */
> +	hole_off = (pvt->dhar & 0x0000FF80);
> +	hole_valid = (pvt->dhar & 0x1);
> +
> +	debugf1("   HoleOffset=0x%x  HoleValid=0x%x IntlvSel=0x%x\n",
> +			hole_off, hole_valid, intlv_sel);
> +
> +	if (intlv_en ||
> +	    (intlv_sel != ((sys_addr >> 12) & intlv_en)))
> +		return -EINVAL;
> +
> +	dct_sel_base = dct_sel_baseaddr(pvt);
> +
> +	/*
> +	 * check whether addresses >= DctSelBaseAddr[47:27] are to be used to
> +	 * select between DCT0 and DCT1.
> +	 */
> +	if (dct_high_range_enabled(pvt) &&
> +	   !dct_ganging_enabled(pvt) &&
> +	   ((sys_addr >> 27) >= (dct_sel_base >> 11)))
> +		high_range = 1;
> +
> +	channel = f10_determine_channel(pvt, sys_addr, high_range, intlv_en);
> +
> +	chan_addr = f10_get_base_addr_offset(sys_addr, high_range, dct_sel_base,
> +					     pvt->dram_ctl_select_high << 16,
> +					     hole_valid, hole_off, dram_base);
> +
> +	intlv_shift = f10_map_intlv_en_to_shift(intlv_en);
> +
> +	/* remove Node ID (in case of memory interleaving) */
> +	tmp = chan_addr & 0xFC0;
> +
> +	chan_addr = ((chan_addr >> intlv_shift) & 0xFFFFFFFFF000ULL) | tmp;
> +
> +	/* remove channel interleave and hash */
> +	if (dct_interleave_enabled(pvt) &&
> +	   !dct_high_range_enabled(pvt) &&
> +	   !dct_ganging_enabled(pvt)) {
> +		if (dct_sel_interleave_addr(pvt) != 1)
> +			chan_addr = (chan_addr >> 1) & 0xFFFFFFFFFFFFFFC0ULL;
> +		else {
> +			tmp = chan_addr & 0xFC0;
> +			chan_addr = ((chan_addr & 0xFFFFFFFFFFFFC000ULL) >> 1)
> +					| tmp;
> +		}
> +	}
> +
> +	debugf1("   (ChannelAddrLong=0x%llx) >> 8 becomes InputAddr=0x%x\n",
> +		chan_addr, (u32)(chan_addr >> 8));
> +
> +	cs_found = f10_lookup_addr_in_dct(chan_addr >> 8, node_id, channel);
> +
> +	if (cs_found >= 0) {
> +		*nid = node_id;
> +		*chan_sel = channel;
> +	}
> +	return cs_found;
> +}
> +
> +static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
> +				       int *node, int *chan_sel)
> +{
> +	int dram_range, cs_found = -EINVAL;
> +	u64 dram_base, dram_limit;
> +
> +	for (dram_range = 0; dram_range < DRAM_REG_COUNT; dram_range++) {
> +
> +		if (!pvt->dram_rw_en[dram_range])
> +			continue;
> +
> +		dram_base = pvt->dram_base[dram_range];
> +		dram_limit = pvt->dram_limit[dram_range];
> +
> +		if ((dram_base <= sys_addr) && (sys_addr <= dram_limit)) {
> +
> +			cs_found = f10_match_to_this_node(pvt, dram_range,
> +							  sys_addr, node,
> +							  chan_sel);
> +			if (cs_found >= 0)
> +				break;
> +		}
> +	}
> +	return cs_found;
> +}
> +
> +/*
> + * f10_map_sysaddr_to_csrow
> + *
> + *	This the F10 reference code from AMD to
> + *	map a SystemAddress to NodeID, CSROW, Channel
> + *
> + *	See the Family 10h BKDG (with bug fixes in the code from AMD)
> + *
> + *	The SystemAddress is usually an error address received from the
> + *	hardware error detector.
> + */
> +static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
> +				     struct amd64_error_info_regs *info,
> +				     u64 sys_addr)
> +{
> +	struct amd64_pvt *pvt = mci->pvt_info;
> +	u32 page, offset;
> +	unsigned short syndrome;
> +	int nid, csrow, chan = 0;
> +
> +	csrow = f10_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan);
> +
> +	if (csrow >= 0) {
> +		error_address_to_page_and_offset(sys_addr, &page, &offset);
> +
> +		syndrome = EXTRACT_HIGH_SYNDROME(info->nbsl) << 8;
> +		syndrome |= EXTRACT_LOW_SYNDROME(info->nbsh);
> +
> +		/* Is CHIPKILL ON?
> +		 * If so, then we can attempt to use the 'syndrome' to isolate
> +		 * which channel the error was on
> +		 */
> +		if (pvt->nbcfg & K8_NBCFG_CHIPKILL)
> +			chan = get_channel_from_ecc_syndrome(syndrome);
> +
> +		if (chan >= 0) {
> +			edac_mc_handle_ce(mci, page, offset, syndrome,
> +					csrow, chan, EDAC_MOD_STR);
> +		} else {
> +			/* Channel is not known,
> +			 * report all channels on this CSROW as failed.
> +			 */
> +			for (chan = 0; chan < mci->csrows[csrow].nr_channels;
> +								chan++) {
> +					edac_mc_handle_ce(mci, page, offset,
> +							syndrome,
> +							csrow, chan,
> +							EDAC_MOD_STR);
> +			}
> +		}
> +
> +	} else {
> +		edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
> +	}
> +}
> +
> +/* map_dbam_to_csrow_size
> + *
> + * Input (index) is the DBAM DIMM value (1 of 4) used as an index into a
> + * shift table (revf_quad_ddr2_shift) which starts at 128MB DIMM size.
> + *
> + * Index of 0 indicates an empty DIMM slot, as reported by Hardware on
> + * empty slots.
> + *
> + * Normalize to 128MB by subracting 27 bit shift
> + */
> +static int map_dbam_to_csrow_size(int index)
> +{
> +	int mega_bytes = 0;
> +
> +	if (index > 0 && index <= DBAM_MAX_VALUE)
> +		mega_bytes = ((128 << (revf_quad_ddr2_shift[index]-27)));
> +
> +	return mega_bytes;
> +}
> +
> +/*
> + * f10_debug_display_dimm_sizes
> + *
> + *	debug routine to display the memory sizes of a DIMM
> + *	(ganged or not) and it CSROWs as well
> + */
> +static void f10_debug_display_dimm_sizes(int ctrl,
> +					struct amd64_pvt *pvt, int ganged)
> +{
> +	int dimm;
> +	int size0;
> +	int size1;
> +	u32 dbam;
> +	u32 *dcsb;
> +
> +	debugf1("  dbam%d: 0x%8.08x  CSROW is %s\n", ctrl,
> +			ctrl ? pvt->dbam1 : pvt->dbam0,
> +			ganged ? "GANGED - dbam1 not used" : "NON-GANGED");
> +
> +	dbam = ctrl ? pvt->dbam1 : pvt->dbam0;
> +	dcsb = ctrl ? pvt->dcsb1 : pvt->dcsb0;
> +
> +	/* Dump memory sizes for DIMM and its CSROWs */
> +	for (dimm = 0; dimm < 4; dimm++) {
> +
> +		size0 = 0;
> +		if (dcsb[dimm*2] & K8_DCSB_CS_ENABLE)
> +			size0 = map_dbam_to_csrow_size(DBAM_DIMM(dimm, dbam));
> +
> +		size1 = 0;
> +		if (dcsb[dimm*2 + 1] & K8_DCSB_CS_ENABLE)
> +			size1 = map_dbam_to_csrow_size(DBAM_DIMM(dimm, dbam));
> +
> +		debugf1("     CTRL-%d DIMM-%d=%5dMB   CSROW-%d=%5dMB "
> +				"CSROW-%d=%5dMB\n",
> +				ctrl,
> +				dimm,
> +				size0 + size1,
> +				dimm * 2,
> +				size0,
> +				dimm * 2 + 1,
> +				size1);
> +	}
> +}
> +
> +/*
> + * f10_probe_valid_hardware
> + *
> + * Very early hardware probe on pci_probe thread to determine if this module can
> + * support the hardware.
> + *
> + * Return:
> + *      0 for OK
> + *      1 for error
> + */
> +static int f10_probe_valid_hardware(struct amd64_pvt *pvt)
> +{
> +	int rc = 0;
> +
> +	/*
> +	 * If we are on a DDR3 machine, we don't know yet if
> +	 * we support that properly at this time
> +	 */
> +	if ((pvt->dchr0 & F10_DCHR_Ddr3Mode) ||
> +	    (pvt->dchr1 & F10_DCHR_Ddr3Mode)) {
> +
> +		amd64_printk(KERN_WARNING,
> +			"%s() This machine is running with DDR3 memory. "
> +			"This is not currently supported. "
> +			"DCHR0=0x%x DCHR1=0x%x\n",
> +			__func__, pvt->dchr0, pvt->dchr1);
> +
> +		amd64_printk(KERN_WARNING,
> +			"   Contact '%s' module MAINTAINER to help add"
> +			" support.\n",
> +			EDAC_MOD_STR);
> +
> +		rc = 1;
> +
> +	} else {
> +		debugf0("%s() DDR2 Memory Installed\n", __func__);
> +	}
> +
> +	return rc;
> +}
>  


-- 

Cheers,
Mauro
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ