diff options
Diffstat (limited to 'drivers/edac')
34 files changed, 1208 insertions, 547 deletions
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 3c9e4e98c65..f8bf00010d4 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -1,7 +1,7 @@  #include "amd64_edac.h"  #include <asm/amd_nb.h> -static struct edac_pci_ctl_info *amd64_ctl_pci; +static struct edac_pci_ctl_info *pci_ctl;  static int report_gart_errors;  module_param(report_gart_errors, int, 0644); @@ -162,7 +162,7 @@ static int f15_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,   * scan the scrub rate mapping table for a close or matching bandwidth value to   * issue. If requested is too big, then use last maximum value found.   */ -static int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate) +static int __set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate)  {  	u32 scrubval;  	int i; @@ -198,7 +198,7 @@ static int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate)  	return 0;  } -static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bw) +static int set_scrub_rate(struct mem_ctl_info *mci, u32 bw)  {  	struct amd64_pvt *pvt = mci->pvt_info;  	u32 min_scrubrate = 0x5; @@ -210,10 +210,10 @@ static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bw)  	if (pvt->fam == 0x15 && pvt->model < 0x10)  		f15h_select_dct(pvt, 0); -	return __amd64_set_scrub_rate(pvt->F3, bw, min_scrubrate); +	return __set_scrub_rate(pvt->F3, bw, min_scrubrate);  } -static int amd64_get_scrub_rate(struct mem_ctl_info *mci) +static int get_scrub_rate(struct mem_ctl_info *mci)  {  	struct amd64_pvt *pvt = mci->pvt_info;  	u32 scrubval = 0; @@ -240,8 +240,7 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci)   * returns true if the SysAddr given by sys_addr matches the   * DRAM base/limit associated with node_id   */ -static bool amd64_base_limit_match(struct amd64_pvt *pvt, u64 sys_addr, -				   u8 nid) +static bool base_limit_match(struct amd64_pvt *pvt, u64 sys_addr, u8 nid)  {  	u64 addr; @@ -285,7 +284,7 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,  	if (intlv_en == 0) {  		for (node_id = 0; node_id < DRAM_RANGES; node_id++) { -			if (amd64_base_limit_match(pvt, sys_addr, node_id)) +			if (base_limit_match(pvt, sys_addr, node_id))  				goto found;  		}  		goto err_no_match; @@ -309,7 +308,7 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,  	}  	/* sanity test for sys_addr */ -	if (unlikely(!amd64_base_limit_match(pvt, sys_addr, node_id))) { +	if (unlikely(!base_limit_match(pvt, sys_addr, node_id))) {  		amd64_warn("%s: sys_addr 0x%llx falls outside base/limit address"  			   "range for node %d with node interleaving enabled.\n",  			   __func__, sys_addr, node_id); @@ -339,8 +338,8 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct,  	if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) {  		csbase		= pvt->csels[dct].csbases[csrow];  		csmask		= pvt->csels[dct].csmasks[csrow]; -		base_bits	= GENMASK(21, 31) | GENMASK(9, 15); -		mask_bits	= GENMASK(21, 29) | GENMASK(9, 15); +		base_bits	= GENMASK_ULL(31, 21) | GENMASK_ULL(15, 9); +		mask_bits	= GENMASK_ULL(29, 21) | GENMASK_ULL(15, 9);  		addr_shift	= 4;  	/* @@ -352,16 +351,16 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct,  		csbase          = pvt->csels[dct].csbases[csrow];  		csmask          = pvt->csels[dct].csmasks[csrow >> 1]; -		*base  = (csbase & GENMASK(5,  15)) << 6; -		*base |= (csbase & GENMASK(19, 30)) << 8; +		*base  = (csbase & GENMASK_ULL(15,  5)) << 6; +		*base |= (csbase & GENMASK_ULL(30, 19)) << 8;  		*mask = ~0ULL;  		/* poke holes for the csmask */ -		*mask &= ~((GENMASK(5, 15)  << 6) | -			   (GENMASK(19, 30) << 8)); +		*mask &= ~((GENMASK_ULL(15, 5)  << 6) | +			   (GENMASK_ULL(30, 19) << 8)); -		*mask |= (csmask & GENMASK(5, 15))  << 6; -		*mask |= (csmask & GENMASK(19, 30)) << 8; +		*mask |= (csmask & GENMASK_ULL(15, 5))  << 6; +		*mask |= (csmask & GENMASK_ULL(30, 19)) << 8;  		return;  	} else { @@ -370,9 +369,11 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct,  		addr_shift	= 8;  		if (pvt->fam == 0x15) -			base_bits = mask_bits = GENMASK(19,30) | GENMASK(5,13); +			base_bits = mask_bits = +				GENMASK_ULL(30,19) | GENMASK_ULL(13,5);  		else -			base_bits = mask_bits = GENMASK(19,28) | GENMASK(5,13); +			base_bits = mask_bits = +				GENMASK_ULL(28,19) | GENMASK_ULL(13,5);  	}  	*base  = (csbase & base_bits) << addr_shift; @@ -561,7 +562,7 @@ static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr)  	 * section 3.4.2 of AMD publication 24592: AMD x86-64 Architecture  	 * Programmer's Manual Volume 1 Application Programming.  	 */ -	dram_addr = (sys_addr & GENMASK(0, 39)) - dram_base; +	dram_addr = (sys_addr & GENMASK_ULL(39, 0)) - dram_base;  	edac_dbg(2, "using DRAM Base register to translate SysAddr 0x%lx to DramAddr 0x%lx\n",  		 (unsigned long)sys_addr, (unsigned long)dram_addr); @@ -597,7 +598,7 @@ static u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr)  	 * concerning translating a DramAddr to an InputAddr.  	 */  	intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0)); -	input_addr = ((dram_addr >> intlv_shift) & GENMASK(12, 35)) + +	input_addr = ((dram_addr >> intlv_shift) & GENMASK_ULL(35, 12)) +  		      (dram_addr & 0xfff);  	edac_dbg(2, "  Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n", @@ -658,7 +659,7 @@ static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);   * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs   * are ECC capable.   */ -static unsigned long amd64_determine_edac_cap(struct amd64_pvt *pvt) +static unsigned long determine_edac_cap(struct amd64_pvt *pvt)  {  	u8 bit;  	unsigned long edac_cap = EDAC_FLAG_NONE; @@ -673,9 +674,9 @@ static unsigned long amd64_determine_edac_cap(struct amd64_pvt *pvt)  	return edac_cap;  } -static void amd64_debug_display_dimm_sizes(struct amd64_pvt *, u8); +static void debug_display_dimm_sizes(struct amd64_pvt *, u8); -static void amd64_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan) +static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan)  {  	edac_dbg(1, "F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr); @@ -709,7 +710,7 @@ static void dump_misc_regs(struct amd64_pvt *pvt)  		 (pvt->nbcap & NBCAP_SECDED) ? "yes" : "no",  		 (pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no"); -	amd64_dump_dramcfg_low(pvt, pvt->dclr0, 0); +	debug_dump_dramcfg_low(pvt, pvt->dclr0, 0);  	edac_dbg(1, "F3xB0 (Online Spare): 0x%08x\n", pvt->online_spare); @@ -720,19 +721,19 @@ static void dump_misc_regs(struct amd64_pvt *pvt)  	edac_dbg(1, "  DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no"); -	amd64_debug_display_dimm_sizes(pvt, 0); +	debug_display_dimm_sizes(pvt, 0);  	/* everything below this point is Fam10h and above */  	if (pvt->fam == 0xf)  		return; -	amd64_debug_display_dimm_sizes(pvt, 1); +	debug_display_dimm_sizes(pvt, 1);  	amd64_info("using %s syndromes.\n", ((pvt->ecc_sym_sz == 8) ? "x8" : "x4"));  	/* Only if NOT ganged does dclr1 have valid info */  	if (!dct_ganging_enabled(pvt)) -		amd64_dump_dramcfg_low(pvt, pvt->dclr1, 1); +		debug_dump_dramcfg_low(pvt, pvt->dclr1, 1);  }  /* @@ -798,7 +799,7 @@ static void read_dct_base_mask(struct amd64_pvt *pvt)  	}  } -static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt, int cs) +static enum mem_type determine_memory_type(struct amd64_pvt *pvt, int cs)  {  	enum mem_type type; @@ -849,7 +850,7 @@ static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m)  		end_bit   = 39;  	} -	addr = m->addr & GENMASK(start_bit, end_bit); +	addr = m->addr & GENMASK_ULL(end_bit, start_bit);  	/*  	 * Erratum 637 workaround @@ -861,7 +862,7 @@ static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m)  		u16 mce_nid;  		u8 intlv_en; -		if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7) +		if ((addr & GENMASK_ULL(47, 24)) >> 24 != 0x00fdf7)  			return addr;  		mce_nid	= amd_get_nb_id(m->extcpu); @@ -871,7 +872,7 @@ static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m)  		intlv_en = tmp >> 21 & 0x7;  		/* add [47:27] + 3 trailing bits */ -		cc6_base  = (tmp & GENMASK(0, 20)) << 3; +		cc6_base  = (tmp & GENMASK_ULL(20, 0)) << 3;  		/* reverse and add DramIntlvEn */  		cc6_base |= intlv_en ^ 0x7; @@ -880,18 +881,18 @@ static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m)  		cc6_base <<= 24;  		if (!intlv_en) -			return cc6_base | (addr & GENMASK(0, 23)); +			return cc6_base | (addr & GENMASK_ULL(23, 0));  		amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_BASE, &tmp);  							/* faster log2 */ -		tmp_addr  = (addr & GENMASK(12, 23)) << __fls(intlv_en + 1); +		tmp_addr  = (addr & GENMASK_ULL(23, 12)) << __fls(intlv_en + 1);  		/* OR DramIntlvSel into bits [14:12] */ -		tmp_addr |= (tmp & GENMASK(21, 23)) >> 9; +		tmp_addr |= (tmp & GENMASK_ULL(23, 21)) >> 9;  		/* add remaining [11:0] bits from original MC4_ADDR */ -		tmp_addr |= addr & GENMASK(0, 11); +		tmp_addr |= addr & GENMASK_ULL(11, 0);  		return cc6_base | tmp_addr;  	} @@ -952,12 +953,12 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)  	amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim); -	pvt->ranges[range].lim.lo &= GENMASK(0, 15); +	pvt->ranges[range].lim.lo &= GENMASK_ULL(15, 0);  				    /* {[39:27],111b} */  	pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16; -	pvt->ranges[range].lim.hi &= GENMASK(0, 7); +	pvt->ranges[range].lim.hi &= GENMASK_ULL(7, 0);  				    /* [47:40] */  	pvt->ranges[range].lim.hi |= llim >> 13; @@ -1238,9 +1239,17 @@ static u8 f15_m30h_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,  	if (num_dcts_intlv == 2) {  		select = (sys_addr >> 8) & 0x3;  		channel = select ? 0x3 : 0; -	} else if (num_dcts_intlv == 4) -		channel = (sys_addr >> 8) & 0x7; - +	} else if (num_dcts_intlv == 4) { +		u8 intlv_addr = dct_sel_interleave_addr(pvt); +		switch (intlv_addr) { +		case 0x4: +			channel = (sys_addr >> 8) & 0x3; +			break; +		case 0x5: +			channel = (sys_addr >> 9) & 0x3; +			break; +		} +	}  	return channel;  } @@ -1330,7 +1339,7 @@ static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range,  			chan_off = dram_base;  	} -	return (sys_addr & GENMASK(6,47)) - (chan_off & GENMASK(23,47)); +	return (sys_addr & GENMASK_ULL(47,6)) - (chan_off & GENMASK_ULL(47,23));  }  /* @@ -1576,7 +1585,7 @@ static int f15_m30h_match_to_this_node(struct amd64_pvt *pvt, unsigned range,  					     num_dcts_intlv, dct_sel);  	/* Verify we stay within the MAX number of channels allowed */ -	if (channel > 4 || channel < 0) +	if (channel > 3)  		return -EINVAL;  	leg_mmio_hole = (u8) (dct_cont_base_reg >> 1 & BIT(0)); @@ -1700,7 +1709,7 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,   * debug routine to display the memory sizes of all logical DIMMs and its   * CSROWs   */ -static void amd64_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl) +static void debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)  {  	int dimm, size0, size1;  	u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases; @@ -1742,7 +1751,7 @@ static void amd64_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)  	}  } -static struct amd64_family_type amd64_family_types[] = { +static struct amd64_family_type family_types[] = {  	[K8_CPUS] = {  		.ctl_name = "K8",  		.f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP, @@ -1798,6 +1807,17 @@ static struct amd64_family_type amd64_family_types[] = {  			.read_dct_pci_cfg	= f10_read_dct_pci_cfg,  		}  	}, +	[F16_M30H_CPUS] = { +		.ctl_name = "F16h_M30h", +		.f1_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F1, +		.f3_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F3, +		.ops = { +			.early_channel_count	= f1x_early_channel_count, +			.map_sysaddr_to_csrow	= f1x_map_sysaddr_to_csrow, +			.dbam_to_cs		= f16_dbam_to_chip_select, +			.read_dct_pci_cfg	= f10_read_dct_pci_cfg, +		} +	},  };  /* @@ -2003,9 +2023,9 @@ static void __log_bus_error(struct mem_ctl_info *mci, struct err_info *err,  			     string, "");  } -static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci, -					    struct mce *m) +static inline void decode_bus_error(int node_id, struct mce *m)  { +	struct mem_ctl_info *mci = mcis[node_id];  	struct amd64_pvt *pvt = mci->pvt_info;  	u8 ecc_type = (m->status >> 45) & 0x3;  	u8 xec = XEC(m->status, 0x1f); @@ -2033,11 +2053,6 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,  	__log_bus_error(mci, &err, ecc_type);  } -void amd64_decode_bus_error(int node_id, struct mce *m) -{ -	__amd64_decode_bus_error(mcis[node_id], m); -} -  /*   * Use pvt->F2 which contains the F2 CPU PCI device to get the related   * F1 (AddrMap) and F3 (Misc) devices. Return negative value on error. @@ -2194,7 +2209,7 @@ static void read_mc_regs(struct amd64_pvt *pvt)   *	encompasses   *   */ -static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr) +static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)  {  	u32 cs_mode, nr_pages;  	u32 dbam = dct ? pvt->dbam1 : pvt->dbam0; @@ -2261,19 +2276,19 @@ static int init_csrows(struct mem_ctl_info *mci)  			    pvt->mc_node_id, i);  		if (row_dct0) { -			nr_pages = amd64_csrow_nr_pages(pvt, 0, i); +			nr_pages = get_csrow_nr_pages(pvt, 0, i);  			csrow->channels[0]->dimm->nr_pages = nr_pages;  		}  		/* K8 has only one DCT */  		if (pvt->fam != 0xf && row_dct1) { -			int row_dct1_pages = amd64_csrow_nr_pages(pvt, 1, i); +			int row_dct1_pages = get_csrow_nr_pages(pvt, 1, i);  			csrow->channels[1]->dimm->nr_pages = row_dct1_pages;  			nr_pages += row_dct1_pages;  		} -		mtype = amd64_determine_memory_type(pvt, i); +		mtype = determine_memory_type(pvt, i);  		edac_dbg(1, "Total csrow%d pages: %u\n", i, nr_pages); @@ -2307,7 +2322,7 @@ static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, u16 nid)  }  /* check MCG_CTL on all the cpus on this node */ -static bool amd64_nb_mce_bank_enabled_on_node(u16 nid) +static bool nb_mce_bank_enabled_on_node(u16 nid)  {  	cpumask_var_t mask;  	int cpu, nbe; @@ -2480,7 +2495,7 @@ static bool ecc_enabled(struct pci_dev *F3, u16 nid)  	ecc_en = !!(value & NBCFG_ECC_ENABLE);  	amd64_info("DRAM ECC %s.\n", (ecc_en ? "enabled" : "disabled")); -	nb_mce_en = amd64_nb_mce_bank_enabled_on_node(nid); +	nb_mce_en = nb_mce_bank_enabled_on_node(nid);  	if (!nb_mce_en)  		amd64_notice("NB MCE bank disabled, set MSR "  			     "0x%08x[4] on node %d to enable.\n", @@ -2535,7 +2550,7 @@ static void setup_mci_misc_attrs(struct mem_ctl_info *mci,  	if (pvt->nbcap & NBCAP_CHIPKILL)  		mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED; -	mci->edac_cap		= amd64_determine_edac_cap(pvt); +	mci->edac_cap		= determine_edac_cap(pvt);  	mci->mod_name		= EDAC_MOD_STR;  	mci->mod_ver		= EDAC_AMD64_VERSION;  	mci->ctl_name		= fam->ctl_name; @@ -2543,14 +2558,14 @@ static void setup_mci_misc_attrs(struct mem_ctl_info *mci,  	mci->ctl_page_to_phys	= NULL;  	/* memory scrubber interface */ -	mci->set_sdram_scrub_rate = amd64_set_scrub_rate; -	mci->get_sdram_scrub_rate = amd64_get_scrub_rate; +	mci->set_sdram_scrub_rate = set_scrub_rate; +	mci->get_sdram_scrub_rate = get_scrub_rate;  }  /*   * returns a pointer to the family descriptor on success, NULL otherwise.   */ -static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt) +static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)  {  	struct amd64_family_type *fam_type = NULL; @@ -2561,29 +2576,34 @@ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)  	switch (pvt->fam) {  	case 0xf: -		fam_type		= &amd64_family_types[K8_CPUS]; -		pvt->ops		= &amd64_family_types[K8_CPUS].ops; +		fam_type	= &family_types[K8_CPUS]; +		pvt->ops	= &family_types[K8_CPUS].ops;  		break;  	case 0x10: -		fam_type		= &amd64_family_types[F10_CPUS]; -		pvt->ops		= &amd64_family_types[F10_CPUS].ops; +		fam_type	= &family_types[F10_CPUS]; +		pvt->ops	= &family_types[F10_CPUS].ops;  		break;  	case 0x15:  		if (pvt->model == 0x30) { -			fam_type	= &amd64_family_types[F15_M30H_CPUS]; -			pvt->ops	= &amd64_family_types[F15_M30H_CPUS].ops; +			fam_type = &family_types[F15_M30H_CPUS]; +			pvt->ops = &family_types[F15_M30H_CPUS].ops;  			break;  		} -		fam_type		= &amd64_family_types[F15_CPUS]; -		pvt->ops		= &amd64_family_types[F15_CPUS].ops; +		fam_type	= &family_types[F15_CPUS]; +		pvt->ops	= &family_types[F15_CPUS].ops;  		break;  	case 0x16: -		fam_type		= &amd64_family_types[F16_CPUS]; -		pvt->ops		= &amd64_family_types[F16_CPUS].ops; +		if (pvt->model == 0x30) { +			fam_type = &family_types[F16_M30H_CPUS]; +			pvt->ops = &family_types[F16_M30H_CPUS].ops; +			break; +		} +		fam_type	= &family_types[F16_CPUS]; +		pvt->ops	= &family_types[F16_CPUS].ops;  		break;  	default: @@ -2599,7 +2619,7 @@ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)  	return fam_type;  } -static int amd64_init_one_instance(struct pci_dev *F2) +static int init_one_instance(struct pci_dev *F2)  {  	struct amd64_pvt *pvt = NULL;  	struct amd64_family_type *fam_type = NULL; @@ -2617,7 +2637,7 @@ static int amd64_init_one_instance(struct pci_dev *F2)  	pvt->F2 = F2;  	ret = -EINVAL; -	fam_type = amd64_per_family_init(pvt); +	fam_type = per_family_init(pvt);  	if (!fam_type)  		goto err_free; @@ -2678,7 +2698,7 @@ static int amd64_init_one_instance(struct pci_dev *F2)  	if (report_gart_errors)  		amd_report_gart_errors(true); -	amd_register_ecc_decoder(amd64_decode_bus_error); +	amd_register_ecc_decoder(decode_bus_error);  	mcis[nid] = mci; @@ -2701,8 +2721,8 @@ err_ret:  	return ret;  } -static int amd64_probe_one_instance(struct pci_dev *pdev, -				    const struct pci_device_id *mc_type) +static int probe_one_instance(struct pci_dev *pdev, +			      const struct pci_device_id *mc_type)  {  	u16 nid = amd_get_node_id(pdev);  	struct pci_dev *F3 = node_to_amd_nb(nid)->misc; @@ -2734,7 +2754,7 @@ static int amd64_probe_one_instance(struct pci_dev *pdev,  			goto err_enable;  	} -	ret = amd64_init_one_instance(pdev); +	ret = init_one_instance(pdev);  	if (ret < 0) {  		amd64_err("Error probing instance: %d\n", nid);  		restore_ecc_error_reporting(s, nid, F3); @@ -2750,7 +2770,7 @@ err_out:  	return ret;  } -static void amd64_remove_one_instance(struct pci_dev *pdev) +static void remove_one_instance(struct pci_dev *pdev)  {  	struct mem_ctl_info *mci;  	struct amd64_pvt *pvt; @@ -2775,7 +2795,7 @@ static void amd64_remove_one_instance(struct pci_dev *pdev)  	/* unregister from EDAC MCE */  	amd_report_gart_errors(false); -	amd_unregister_ecc_decoder(amd64_decode_bus_error); +	amd_unregister_ecc_decoder(decode_bus_error);  	kfree(ecc_stngs[nid]);  	ecc_stngs[nid] = NULL; @@ -2793,7 +2813,7 @@ static void amd64_remove_one_instance(struct pci_dev *pdev)   * PCI core identifies what devices are on a system during boot, and then   * inquiry this table to see if this driver is for a given device found.   */ -static DEFINE_PCI_DEVICE_TABLE(amd64_pci_table) = { +static const struct pci_device_id amd64_pci_table[] = {  	{  		.vendor		= PCI_VENDOR_ID_AMD,  		.device		= PCI_DEVICE_ID_AMD_K8_NB_MEMCTL, @@ -2834,6 +2854,14 @@ static DEFINE_PCI_DEVICE_TABLE(amd64_pci_table) = {  		.class		= 0,  		.class_mask	= 0,  	}, +	{ +		.vendor		= PCI_VENDOR_ID_AMD, +		.device		= PCI_DEVICE_ID_AMD_16H_M30H_NB_F2, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID, +		.class		= 0, +		.class_mask	= 0, +	},  	{0, }  }; @@ -2841,8 +2869,8 @@ MODULE_DEVICE_TABLE(pci, amd64_pci_table);  static struct pci_driver amd64_pci_driver = {  	.name		= EDAC_MOD_STR, -	.probe		= amd64_probe_one_instance, -	.remove		= amd64_remove_one_instance, +	.probe		= probe_one_instance, +	.remove		= remove_one_instance,  	.id_table	= amd64_pci_table,  }; @@ -2851,23 +2879,18 @@ static void setup_pci_device(void)  	struct mem_ctl_info *mci;  	struct amd64_pvt *pvt; -	if (amd64_ctl_pci) +	if (pci_ctl)  		return;  	mci = mcis[0]; -	if (mci) { - -		pvt = mci->pvt_info; -		amd64_ctl_pci = -			edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR); - -		if (!amd64_ctl_pci) { -			pr_warning("%s(): Unable to create PCI control\n", -				   __func__); +	if (!mci) +		return; -			pr_warning("%s(): PCI error report via EDAC not set\n", -				   __func__); -			} +	pvt = mci->pvt_info; +	pci_ctl = edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR); +	if (!pci_ctl) { +		pr_warn("%s(): Unable to create PCI control\n", __func__); +		pr_warn("%s(): PCI error report via EDAC not set\n", __func__);  	}  } @@ -2923,8 +2946,8 @@ err_ret:  static void __exit amd64_edac_exit(void)  { -	if (amd64_ctl_pci) -		edac_pci_release_generic_ctl(amd64_ctl_pci); +	if (pci_ctl) +		edac_pci_release_generic_ctl(pci_ctl);  	pci_unregister_driver(&amd64_pci_driver); diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index d2443cfa069..d903e0c2114 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -160,14 +160,6 @@  #define OFF false  /* - * Create a contiguous bitmask starting at bit position @lo and ending at - * position @hi. For example - * - * GENMASK(21, 39) gives us the 64bit vector 0x000000ffffe00000. - */ -#define GENMASK(lo, hi)			(((1ULL << ((hi) - (lo) + 1)) - 1) << (lo)) - -/*   * PCI-defined configuration space registers   */  #define PCI_DEVICE_ID_AMD_15H_M30H_NB_F1 0x141b @@ -176,6 +168,8 @@  #define PCI_DEVICE_ID_AMD_15H_NB_F2	0x1602  #define PCI_DEVICE_ID_AMD_16H_NB_F1	0x1531  #define PCI_DEVICE_ID_AMD_16H_NB_F2	0x1532 +#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F1 0x1581 +#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F2 0x1582  /*   * Function 1 - Address Map @@ -308,6 +302,7 @@ enum amd_families {  	F15_CPUS,  	F15_M30H_CPUS,  	F16_CPUS, +	F16_M30H_CPUS,  	NUM_FAMILIES,  }; diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c index 96e3ee3460a..3a501b530e1 100644 --- a/drivers/edac/amd76x_edac.c +++ b/drivers/edac/amd76x_edac.c @@ -333,7 +333,7 @@ static void amd76x_remove_one(struct pci_dev *pdev)  	edac_mc_free(mci);  } -static DEFINE_PCI_DEVICE_TABLE(amd76x_pci_tbl) = { +static const struct pci_device_id amd76x_pci_tbl[] = {  	{  	 PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0,  	 AMD762}, diff --git a/drivers/edac/amd8111_edac.c b/drivers/edac/amd8111_edac.c index ddd890052ce..2b63f7c2d6d 100644 --- a/drivers/edac/amd8111_edac.c +++ b/drivers/edac/amd8111_edac.c @@ -350,6 +350,7 @@ static int amd8111_dev_probe(struct pci_dev *dev,  				const struct pci_device_id *id)  {  	struct amd8111_dev_info *dev_info = &amd8111_devices[id->driver_data]; +	int ret = -ENODEV;  	dev_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,  					dev_info->err_dev, NULL); @@ -359,16 +360,15 @@ static int amd8111_dev_probe(struct pci_dev *dev,  			"vendor %x, device %x, name %s\n",  			PCI_VENDOR_ID_AMD, dev_info->err_dev,  			dev_info->ctl_name); -		return -ENODEV; +		goto err;  	}  	if (pci_enable_device(dev_info->dev)) { -		pci_dev_put(dev_info->dev);  		printk(KERN_ERR "failed to enable:"  			"vendor %x, device %x, name %s\n",  			PCI_VENDOR_ID_AMD, dev_info->err_dev,  			dev_info->ctl_name); -		return -ENODEV; +		goto err_dev_put;  	}  	/* @@ -381,8 +381,10 @@ static int amd8111_dev_probe(struct pci_dev *dev,  		edac_device_alloc_ctl_info(0, dev_info->ctl_name, 1,  					   NULL, 0, 0,  					   NULL, 0, dev_info->edac_idx); -	if (!dev_info->edac_dev) -		return -ENOMEM; +	if (!dev_info->edac_dev) { +		ret = -ENOMEM; +		goto err_dev_put; +	}  	dev_info->edac_dev->pvt_info = dev_info;  	dev_info->edac_dev->dev = &dev_info->dev->dev; @@ -399,8 +401,7 @@ static int amd8111_dev_probe(struct pci_dev *dev,  	if (edac_device_add_device(dev_info->edac_dev) > 0) {  		printk(KERN_ERR "failed to add edac_dev for %s\n",  			dev_info->ctl_name); -		edac_device_free_ctl_info(dev_info->edac_dev); -		return -ENODEV; +		goto err_edac_free_ctl;  	}  	printk(KERN_INFO "added one edac_dev on AMD8111 " @@ -409,6 +410,13 @@ static int amd8111_dev_probe(struct pci_dev *dev,  		dev_info->ctl_name);  	return 0; + +err_edac_free_ctl: +	edac_device_free_ctl_info(dev_info->edac_dev); +err_dev_put: +	pci_dev_put(dev_info->dev); +err: +	return ret;  }  static void amd8111_dev_remove(struct pci_dev *dev) @@ -437,6 +445,7 @@ static int amd8111_pci_probe(struct pci_dev *dev,  				const struct pci_device_id *id)  {  	struct amd8111_pci_info *pci_info = &amd8111_pcis[id->driver_data]; +	int ret = -ENODEV;  	pci_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,  					pci_info->err_dev, NULL); @@ -446,16 +455,15 @@ static int amd8111_pci_probe(struct pci_dev *dev,  			"vendor %x, device %x, name %s\n",  			PCI_VENDOR_ID_AMD, pci_info->err_dev,  			pci_info->ctl_name); -		return -ENODEV; +		goto err;  	}  	if (pci_enable_device(pci_info->dev)) { -		pci_dev_put(pci_info->dev);  		printk(KERN_ERR "failed to enable:"  			"vendor %x, device %x, name %s\n",  			PCI_VENDOR_ID_AMD, pci_info->err_dev,  			pci_info->ctl_name); -		return -ENODEV; +		goto err_dev_put;  	}  	/* @@ -465,8 +473,10 @@ static int amd8111_pci_probe(struct pci_dev *dev,  	*/  	pci_info->edac_idx = edac_pci_alloc_index();  	pci_info->edac_dev = edac_pci_alloc_ctl_info(0, pci_info->ctl_name); -	if (!pci_info->edac_dev) -		return -ENOMEM; +	if (!pci_info->edac_dev) { +		ret = -ENOMEM; +		goto err_dev_put; +	}  	pci_info->edac_dev->pvt_info = pci_info;  	pci_info->edac_dev->dev = &pci_info->dev->dev; @@ -483,8 +493,7 @@ static int amd8111_pci_probe(struct pci_dev *dev,  	if (edac_pci_add_device(pci_info->edac_dev, pci_info->edac_idx) > 0) {  		printk(KERN_ERR "failed to add edac_pci for %s\n",  			pci_info->ctl_name); -		edac_pci_free_ctl_info(pci_info->edac_dev); -		return -ENODEV; +		goto err_edac_free_ctl;  	}  	printk(KERN_INFO "added one edac_pci on AMD8111 " @@ -493,6 +502,13 @@ static int amd8111_pci_probe(struct pci_dev *dev,  		pci_info->ctl_name);  	return 0; + +err_edac_free_ctl: +	edac_pci_free_ctl_info(pci_info->edac_dev); +err_dev_put: +	pci_dev_put(pci_info->dev); +err: +	return ret;  }  static void amd8111_pci_remove(struct pci_dev *dev) diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c index c2eaf334b90..374b57fc596 100644 --- a/drivers/edac/cell_edac.c +++ b/drivers/edac/cell_edac.c @@ -15,6 +15,7 @@  #include <linux/platform_device.h>  #include <linux/stop_machine.h>  #include <linux/io.h> +#include <linux/of_address.h>  #include <asm/machdep.h>  #include <asm/cell-regs.h> @@ -162,6 +163,7 @@ static void cell_edac_init_csrows(struct mem_ctl_info *mci)  			csrow->first_page, nr_pages);  		break;  	} +	of_node_put(np);  }  static int cell_edac_probe(struct platform_device *pdev) diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index 644fec54681..b2d71388172 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -209,7 +209,6 @@ enum e752x_chips {   */  struct e752x_pvt { -	struct pci_dev *bridge_ck;  	struct pci_dev *dev_d0f0;  	struct pci_dev *dev_d0f1;  	u32 tolm; @@ -891,7 +890,7 @@ static void e752x_get_error_info(struct mem_ctl_info *mci,  					info->buf_ferr);  		if (info->dram_ferr) -			pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR, +			pci_write_bits16(pvt->dev_d0f1, E752X_DRAM_FERR,  					 info->dram_ferr, info->dram_ferr);  		pci_write_config_dword(dev, E752X_FERR_GLOBAL, @@ -936,7 +935,7 @@ static void e752x_get_error_info(struct mem_ctl_info *mci,  					info->buf_nerr);  		if (info->dram_nerr) -			pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR, +			pci_write_bits16(pvt->dev_d0f1, E752X_DRAM_NERR,  					 info->dram_nerr, info->dram_nerr);  		pci_write_config_dword(dev, E752X_NERR_GLOBAL, @@ -1177,36 +1176,33 @@ static void e752x_init_mem_map_table(struct pci_dev *pdev,  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); +	pvt->dev_d0f1 = pci_get_device(PCI_VENDOR_ID_INTEL, +				pvt->dev_info->err_dev, NULL); -	if (pvt->bridge_ck == NULL) -		pvt->bridge_ck = pci_scan_single_device(pdev->bus, +	if (pvt->dev_d0f1 == NULL) { +		pvt->dev_d0f1 = pci_scan_single_device(pdev->bus,  							PCI_DEVFN(0, 1)); +		pci_dev_get(pvt->dev_d0f1); +	} -	if (pvt->bridge_ck == NULL) { +	if (pvt->dev_d0f1 == 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, +	pvt->dev_d0f0 = pci_get_device(PCI_VENDOR_ID_INTEL,  				e752x_devs[dev_idx].ctl_dev,  				NULL); -	if (dev == NULL) +	if (pvt->dev_d0f0 == 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); +	pci_dev_put(pvt->dev_d0f1);  	return 1;  } @@ -1383,7 +1379,6 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)  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; @@ -1417,11 +1412,10 @@ static void e752x_remove_one(struct pci_dev *pdev)  	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 DEFINE_PCI_DEVICE_TABLE(e752x_pci_tbl) = { +static const struct pci_device_id e752x_pci_tbl[] = {  	{  	 PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,  	 E7520}, diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c index 1c4056a5038..3cda79bc8b0 100644 --- a/drivers/edac/e7xxx_edac.c +++ b/drivers/edac/e7xxx_edac.c @@ -555,7 +555,7 @@ static void e7xxx_remove_one(struct pci_dev *pdev)  	edac_mc_free(mci);  } -static DEFINE_PCI_DEVICE_TABLE(e7xxx_pci_tbl) = { +static const struct pci_device_id e7xxx_pci_tbl[] = {  	{  	 PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,  	 E7205}, diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index 211021dfec7..592af5f0cf3 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -437,6 +437,9 @@ void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)  {  	int status; +	if (!edac_dev->edac_check) +		return; +  	status = cancel_delayed_work(&edac_dev->work);  	if (status == 0) {  		/* workq instance might be running, wait for it */ @@ -530,12 +533,9 @@ int edac_device_add_device(struct edac_device_ctl_info *edac_dev)  	/* Report action taken */  	edac_device_printk(edac_dev, KERN_INFO, -				"Giving out device to module '%s' controller " -				"'%s': DEV '%s' (%s)\n", -				edac_dev->mod_name, -				edac_dev->ctl_name, -				edac_dev_name(edac_dev), -				edac_op_state_to_string(edac_dev->op_state)); +		"Giving out device to module %s controller %s: DEV %s (%s)\n", +		edac_dev->mod_name, edac_dev->ctl_name, edac_dev->dev_name, +		edac_op_state_to_string(edac_dev->op_state));  	mutex_unlock(&device_ctls_mutex);  	return 0; diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 89e109022d7..2c694b5297c 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -559,7 +559,8 @@ static void edac_mc_workq_function(struct work_struct *work_req)   *   *		called with the mem_ctls_mutex held   */ -static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec) +static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec, +				bool init)  {  	edac_dbg(0, "\n"); @@ -567,7 +568,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)  	if (mci->op_state != OP_RUNNING_POLL)  		return; -	INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function); +	if (init) +		INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function); +  	mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));  } @@ -601,7 +604,7 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci)   *	user space has updated our poll period value, need to   *	reset our workq delays   */ -void edac_mc_reset_delay_period(int value) +void edac_mc_reset_delay_period(unsigned long value)  {  	struct mem_ctl_info *mci;  	struct list_head *item; @@ -611,7 +614,7 @@ void edac_mc_reset_delay_period(int value)  	list_for_each(item, &mc_devices) {  		mci = list_entry(item, struct mem_ctl_info, link); -		edac_mc_workq_setup(mci, (unsigned long) value); +		edac_mc_workq_setup(mci, value, false);  	}  	mutex_unlock(&mem_ctls_mutex); @@ -782,14 +785,16 @@ int edac_mc_add_mc(struct mem_ctl_info *mci)  		/* This instance is NOW RUNNING */  		mci->op_state = OP_RUNNING_POLL; -		edac_mc_workq_setup(mci, edac_mc_get_poll_msec()); +		edac_mc_workq_setup(mci, edac_mc_get_poll_msec(), true);  	} else {  		mci->op_state = OP_RUNNING_INTERRUPT;  	}  	/* Report action taken */ -	edac_mc_printk(mci, KERN_INFO, "Giving out device to '%s' '%s':" -		" DEV %s\n", mci->mod_name, mci->ctl_name, edac_dev_name(mci)); +	edac_mc_printk(mci, KERN_INFO, +		"Giving out device to module %s controller %s: DEV %s (%s)\n", +		mci->mod_name, mci->ctl_name, mci->dev_name, +		edac_op_state_to_string(mci->op_state));  	edac_mc_owner = mci->mod_name; @@ -1013,7 +1018,7 @@ static void edac_ce_error(struct mem_ctl_info *mci,  	}  	edac_inc_ce_error(mci, enable_per_layer_report, pos, error_count); -	if (mci->scrub_mode & SCRUB_SW_SRC) { +	if (mci->scrub_mode == SCRUB_SW_SRC) {  		/*  			* Some memory controllers (called MCs below) can remap  			* memory so that it is still available at a different diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 9f7e0e60951..01fae8289cf 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -7,7 +7,7 @@   *   * Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com   * - * (c) 2012-2013 - Mauro Carvalho Chehab <mchehab@redhat.com> + * (c) 2012-2013 - Mauro Carvalho Chehab   *	The entire API were re-written, and ported to use struct device   *   */ @@ -52,18 +52,20 @@ int edac_mc_get_poll_msec(void)  static int edac_set_poll_msec(const char *val, struct kernel_param *kp)  { -	long l; +	unsigned long l;  	int ret;  	if (!val)  		return -EINVAL; -	ret = kstrtol(val, 0, &l); +	ret = kstrtoul(val, 0, &l);  	if (ret)  		return ret; -	if ((int)l != l) + +	if (l < 1000)  		return -EINVAL; -	*((int *)kp->arg) = l; + +	*((unsigned long *)kp->arg) = l;  	/* notify edac_mc engine to reset the poll period */  	edac_mc_reset_delay_period(l); @@ -914,7 +916,7 @@ void __exit edac_debugfs_exit(void)  	debugfs_remove(edac_debugfs);  } -int edac_create_debug_nodes(struct mem_ctl_info *mci) +static int edac_create_debug_nodes(struct mem_ctl_info *mci)  {  	struct dentry *d, *parent;  	char name[80]; diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index 3d139c6e7fe..f2118bfcf8d 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h @@ -52,7 +52,7 @@ extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,  extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev);  extern void edac_device_reset_delay_period(struct edac_device_ctl_info  					   *edac_dev, unsigned long value); -extern void edac_mc_reset_delay_period(int value); +extern void edac_mc_reset_delay_period(unsigned long value);  extern void *edac_align_ptr(void **p, unsigned size, int n_elems); diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c index dd370f92ace..2cf44b4db80 100644 --- a/drivers/edac/edac_pci.c +++ b/drivers/edac/edac_pci.c @@ -358,11 +358,9 @@ int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)  	}  	edac_pci_printk(pci, KERN_INFO, -			"Giving out device to module '%s' controller '%s':" -			" DEV '%s' (%s)\n", -			pci->mod_name, -			pci->ctl_name, -			edac_dev_name(pci), edac_op_state_to_string(pci->op_state)); +		"Giving out device to module %s controller %s: DEV %s (%s)\n", +		pci->mod_name, pci->ctl_name, pci->dev_name, +		edac_op_state_to_string(pci->op_state));  	mutex_unlock(&edac_pci_ctls_mutex);  	return 0; diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c index 351945fa2ec..9d9e18aefaa 100644 --- a/drivers/edac/edac_stub.c +++ b/drivers/edac/edac_stub.c @@ -29,6 +29,25 @@ EXPORT_SYMBOL_GPL(edac_err_assert);  static atomic_t edac_subsys_valid = ATOMIC_INIT(0); +int edac_report_status = EDAC_REPORTING_ENABLED; +EXPORT_SYMBOL_GPL(edac_report_status); + +static int __init edac_report_setup(char *str) +{ +	if (!str) +		return -EINVAL; + +	if (!strncmp(str, "on", 2)) +		set_edac_report_status(EDAC_REPORTING_ENABLED); +	else if (!strncmp(str, "off", 3)) +		set_edac_report_status(EDAC_REPORTING_DISABLED); +	else if (!strncmp(str, "force", 5)) +		set_edac_report_status(EDAC_REPORTING_FORCE); + +	return 0; +} +__setup("edac_report=", edac_report_setup); +  /*   * called to determine if there is an EDAC driver interested in   * knowing an event (such as NMI) occurred diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c index bb534670ec0..8399b4e16fe 100644 --- a/drivers/edac/ghes_edac.c +++ b/drivers/edac/ghes_edac.c @@ -4,7 +4,7 @@   * This file may be distributed under the terms of the GNU General Public   * License version 2.   * - * Copyright (c) 2013 by Mauro Carvalho Chehab <mchehab@redhat.com> + * Copyright (c) 2013 by Mauro Carvalho Chehab   *   * Red Hat Inc. http://www.redhat.com   */ @@ -297,15 +297,14 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev,  	}  	/* Error address */ -	if (mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) { +	if (mem_err->validation_bits & CPER_MEM_VALID_PA) {  		e->page_frame_number = mem_err->physical_addr >> PAGE_SHIFT;  		e->offset_in_page = mem_err->physical_addr & ~PAGE_MASK;  	}  	/* Error grain */ -	if (mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS_MASK) { +	if (mem_err->validation_bits & CPER_MEM_VALID_PA_MASK)  		e->grain = ~(mem_err->physical_addr_mask & ~PAGE_MASK); -	}  	/* Memory error location, mapped on e->location */  	p = e->location; @@ -315,6 +314,8 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev,  		p += sprintf(p, "card:%d ", mem_err->card);  	if (mem_err->validation_bits & CPER_MEM_VALID_MODULE)  		p += sprintf(p, "module:%d ", mem_err->module); +	if (mem_err->validation_bits & CPER_MEM_VALID_RANK_NUMBER) +		p += sprintf(p, "rank:%d ", mem_err->rank);  	if (mem_err->validation_bits & CPER_MEM_VALID_BANK)  		p += sprintf(p, "bank:%d ", mem_err->bank);  	if (mem_err->validation_bits & CPER_MEM_VALID_ROW) @@ -323,6 +324,15 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev,  		p += sprintf(p, "col:%d ", mem_err->column);  	if (mem_err->validation_bits & CPER_MEM_VALID_BIT_POSITION)  		p += sprintf(p, "bit_pos:%d ", mem_err->bit_pos); +	if (mem_err->validation_bits & CPER_MEM_VALID_MODULE_HANDLE) { +		const char *bank = NULL, *device = NULL; +		dmi_memdev_name(mem_err->mem_dev_handle, &bank, &device); +		if (bank != NULL && device != NULL) +			p += sprintf(p, "DIMM location:%s %s ", bank, device); +		else +			p += sprintf(p, "DIMM DMI handle: 0x%.4x ", +				     mem_err->mem_dev_handle); +	}  	if (p > e->location)  		*(p - 1) = '\0'; diff --git a/drivers/edac/highbank_l2_edac.c b/drivers/edac/highbank_l2_edac.c index c2bd8c6a434..2f193668ebc 100644 --- a/drivers/edac/highbank_l2_edac.c +++ b/drivers/edac/highbank_l2_edac.c @@ -50,8 +50,15 @@ static irqreturn_t highbank_l2_err_handler(int irq, void *dev_id)  	return IRQ_HANDLED;  } +static const struct of_device_id hb_l2_err_of_match[] = { +	{ .compatible = "calxeda,hb-sregs-l2-ecc", }, +	{}, +}; +MODULE_DEVICE_TABLE(of, hb_l2_err_of_match); +  static int highbank_l2_err_probe(struct platform_device *pdev)  { +	const struct of_device_id *id;  	struct edac_device_ctl_info *dci;  	struct hb_l2_drvdata *drvdata;  	struct resource *r; @@ -90,28 +97,32 @@ static int highbank_l2_err_probe(struct platform_device *pdev)  		goto err;  	} +	id = of_match_device(hb_l2_err_of_match, &pdev->dev); +	dci->mod_name = pdev->dev.driver->name; +	dci->ctl_name = id ? id->compatible : "unknown"; +	dci->dev_name = dev_name(&pdev->dev); + +	if (edac_device_add_device(dci)) +		goto err; +  	drvdata->db_irq = platform_get_irq(pdev, 0);  	res = devm_request_irq(&pdev->dev, drvdata->db_irq,  			       highbank_l2_err_handler,  			       0, dev_name(&pdev->dev), dci);  	if (res < 0) -		goto err; +		goto err2;  	drvdata->sb_irq = platform_get_irq(pdev, 1);  	res = devm_request_irq(&pdev->dev, drvdata->sb_irq,  			       highbank_l2_err_handler,  			       0, dev_name(&pdev->dev), dci);  	if (res < 0) -		goto err; - -	dci->mod_name = dev_name(&pdev->dev); -	dci->dev_name = dev_name(&pdev->dev); - -	if (edac_device_add_device(dci)) -		goto err; +		goto err2;  	devres_close_group(&pdev->dev, NULL);  	return 0; +err2: +	edac_device_del_device(&pdev->dev);  err:  	devres_release_group(&pdev->dev, NULL);  	edac_device_free_ctl_info(dci); @@ -127,12 +138,6 @@ static int highbank_l2_err_remove(struct platform_device *pdev)  	return 0;  } -static const struct of_device_id hb_l2_err_of_match[] = { -	{ .compatible = "calxeda,hb-sregs-l2-ecc", }, -	{}, -}; -MODULE_DEVICE_TABLE(of, hb_l2_err_of_match); -  static struct platform_driver highbank_l2_edac_driver = {  	.probe = highbank_l2_err_probe,  	.remove = highbank_l2_err_remove, diff --git a/drivers/edac/highbank_mc_edac.c b/drivers/edac/highbank_mc_edac.c index 4695dd2d71f..f784de1dc79 100644 --- a/drivers/edac/highbank_mc_edac.c +++ b/drivers/edac/highbank_mc_edac.c @@ -26,31 +26,40 @@  #include "edac_module.h"  /* DDR Ctrlr Error Registers */ -#define HB_DDR_ECC_OPT			0x128 -#define HB_DDR_ECC_U_ERR_ADDR		0x130 -#define HB_DDR_ECC_U_ERR_STAT		0x134 -#define HB_DDR_ECC_U_ERR_DATAL		0x138 -#define HB_DDR_ECC_U_ERR_DATAH		0x13c -#define HB_DDR_ECC_C_ERR_ADDR		0x140 -#define HB_DDR_ECC_C_ERR_STAT		0x144 -#define HB_DDR_ECC_C_ERR_DATAL		0x148 -#define HB_DDR_ECC_C_ERR_DATAH		0x14c -#define HB_DDR_ECC_INT_STATUS		0x180 -#define HB_DDR_ECC_INT_ACK		0x184 -#define HB_DDR_ECC_U_ERR_ID		0x424 -#define HB_DDR_ECC_C_ERR_ID		0x428 -#define HB_DDR_ECC_INT_STAT_CE		0x8 -#define HB_DDR_ECC_INT_STAT_DOUBLE_CE	0x10 -#define HB_DDR_ECC_INT_STAT_UE		0x20 -#define HB_DDR_ECC_INT_STAT_DOUBLE_UE	0x40 +#define HB_DDR_ECC_ERR_BASE		0x128 +#define MW_DDR_ECC_ERR_BASE		0x1b4 + +#define HB_DDR_ECC_OPT			0x00 +#define HB_DDR_ECC_U_ERR_ADDR		0x08 +#define HB_DDR_ECC_U_ERR_STAT		0x0c +#define HB_DDR_ECC_U_ERR_DATAL		0x10 +#define HB_DDR_ECC_U_ERR_DATAH		0x14 +#define HB_DDR_ECC_C_ERR_ADDR		0x18 +#define HB_DDR_ECC_C_ERR_STAT		0x1c +#define HB_DDR_ECC_C_ERR_DATAL		0x20 +#define HB_DDR_ECC_C_ERR_DATAH		0x24  #define HB_DDR_ECC_OPT_MODE_MASK	0x3  #define HB_DDR_ECC_OPT_FWC		0x100  #define HB_DDR_ECC_OPT_XOR_SHIFT	16 +/* DDR Ctrlr Interrupt Registers */ + +#define HB_DDR_ECC_INT_BASE		0x180 +#define MW_DDR_ECC_INT_BASE		0x218 + +#define HB_DDR_ECC_INT_STATUS		0x00 +#define HB_DDR_ECC_INT_ACK		0x04 + +#define HB_DDR_ECC_INT_STAT_CE		0x8 +#define HB_DDR_ECC_INT_STAT_DOUBLE_CE	0x10 +#define HB_DDR_ECC_INT_STAT_UE		0x20 +#define HB_DDR_ECC_INT_STAT_DOUBLE_UE	0x40 +  struct hb_mc_drvdata { -	void __iomem *mc_vbase; +	void __iomem *mc_err_base; +	void __iomem *mc_int_base;  };  static irqreturn_t highbank_mc_err_handler(int irq, void *dev_id) @@ -60,10 +69,10 @@ static irqreturn_t highbank_mc_err_handler(int irq, void *dev_id)  	u32 status, err_addr;  	/* Read the interrupt status register */ -	status = readl(drvdata->mc_vbase + HB_DDR_ECC_INT_STATUS); +	status = readl(drvdata->mc_int_base + HB_DDR_ECC_INT_STATUS);  	if (status & HB_DDR_ECC_INT_STAT_UE) { -		err_addr = readl(drvdata->mc_vbase + HB_DDR_ECC_U_ERR_ADDR); +		err_addr = readl(drvdata->mc_err_base + HB_DDR_ECC_U_ERR_ADDR);  		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,  				     err_addr >> PAGE_SHIFT,  				     err_addr & ~PAGE_MASK, 0, @@ -71,9 +80,9 @@ static irqreturn_t highbank_mc_err_handler(int irq, void *dev_id)  				     mci->ctl_name, "");  	}  	if (status & HB_DDR_ECC_INT_STAT_CE) { -		u32 syndrome = readl(drvdata->mc_vbase + HB_DDR_ECC_C_ERR_STAT); +		u32 syndrome = readl(drvdata->mc_err_base + HB_DDR_ECC_C_ERR_STAT);  		syndrome = (syndrome >> 8) & 0xff; -		err_addr = readl(drvdata->mc_vbase + HB_DDR_ECC_C_ERR_ADDR); +		err_addr = readl(drvdata->mc_err_base + HB_DDR_ECC_C_ERR_ADDR);  		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,  				     err_addr >> PAGE_SHIFT,  				     err_addr & ~PAGE_MASK, syndrome, @@ -82,66 +91,79 @@ static irqreturn_t highbank_mc_err_handler(int irq, void *dev_id)  	}  	/* clear the error, clears the interrupt */ -	writel(status, drvdata->mc_vbase + HB_DDR_ECC_INT_ACK); +	writel(status, drvdata->mc_int_base + HB_DDR_ECC_INT_ACK);  	return IRQ_HANDLED;  } -#ifdef CONFIG_EDAC_DEBUG -static ssize_t highbank_mc_err_inject_write(struct file *file, -				      const char __user *data, -				      size_t count, loff_t *ppos) +static void highbank_mc_err_inject(struct mem_ctl_info *mci, u8 synd)  { -	struct mem_ctl_info *mci = file->private_data;  	struct hb_mc_drvdata *pdata = mci->pvt_info; -	char buf[32]; -	size_t buf_size;  	u32 reg; + +	reg = readl(pdata->mc_err_base + HB_DDR_ECC_OPT); +	reg &= HB_DDR_ECC_OPT_MODE_MASK; +	reg |= (synd << HB_DDR_ECC_OPT_XOR_SHIFT) | HB_DDR_ECC_OPT_FWC; +	writel(reg, pdata->mc_err_base + HB_DDR_ECC_OPT); +} + +#define to_mci(k) container_of(k, struct mem_ctl_info, dev) + +static ssize_t highbank_mc_inject_ctrl(struct device *dev, +	struct device_attribute *attr, const char *buf, size_t count) +{ +	struct mem_ctl_info *mci = to_mci(dev);  	u8 synd; -	buf_size = min(count, (sizeof(buf)-1)); -	if (copy_from_user(buf, data, buf_size)) -		return -EFAULT; -	buf[buf_size] = 0; +	if (kstrtou8(buf, 16, &synd)) +		return -EINVAL; -	if (!kstrtou8(buf, 16, &synd)) { -		reg = readl(pdata->mc_vbase + HB_DDR_ECC_OPT); -		reg &= HB_DDR_ECC_OPT_MODE_MASK; -		reg |= (synd << HB_DDR_ECC_OPT_XOR_SHIFT) | HB_DDR_ECC_OPT_FWC; -		writel(reg, pdata->mc_vbase + HB_DDR_ECC_OPT); -	} +	highbank_mc_err_inject(mci, synd);  	return count;  } -static const struct file_operations highbank_mc_debug_inject_fops = { -	.open = simple_open, -	.write = highbank_mc_err_inject_write, -	.llseek = generic_file_llseek, +static DEVICE_ATTR(inject_ctrl, S_IWUSR, NULL, highbank_mc_inject_ctrl); + +struct hb_mc_settings { +	int	err_offset; +	int	int_offset;  }; -static void highbank_mc_create_debugfs_nodes(struct mem_ctl_info *mci) -{ -	if (mci->debugfs) -		debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs, mci, -				    &highbank_mc_debug_inject_fops); -; -} -#else -static void highbank_mc_create_debugfs_nodes(struct mem_ctl_info *mci) -{} -#endif +static struct hb_mc_settings hb_settings = { +	.err_offset = HB_DDR_ECC_ERR_BASE, +	.int_offset = HB_DDR_ECC_INT_BASE, +}; + +static struct hb_mc_settings mw_settings = { +	.err_offset = MW_DDR_ECC_ERR_BASE, +	.int_offset = MW_DDR_ECC_INT_BASE, +}; + +static struct of_device_id hb_ddr_ctrl_of_match[] = { +	{ .compatible = "calxeda,hb-ddr-ctrl",		.data = &hb_settings }, +	{ .compatible = "calxeda,ecx-2000-ddr-ctrl",	.data = &mw_settings }, +	{}, +}; +MODULE_DEVICE_TABLE(of, hb_ddr_ctrl_of_match);  static int highbank_mc_probe(struct platform_device *pdev)  { +	const struct of_device_id *id; +	const struct hb_mc_settings *settings;  	struct edac_mc_layer layers[2];  	struct mem_ctl_info *mci;  	struct hb_mc_drvdata *drvdata;  	struct dimm_info *dimm;  	struct resource *r; +	void __iomem *base;  	u32 control;  	int irq;  	int res = 0; +	id = of_match_device(hb_ddr_ctrl_of_match, &pdev->dev); +	if (!id) +		return -ENODEV; +  	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;  	layers[0].size = 1;  	layers[0].is_virt_csrow = true; @@ -174,35 +196,31 @@ static int highbank_mc_probe(struct platform_device *pdev)  		goto err;  	} -	drvdata->mc_vbase = devm_ioremap(&pdev->dev, -					  r->start, resource_size(r)); -	if (!drvdata->mc_vbase) { +	base = devm_ioremap(&pdev->dev, r->start, resource_size(r)); +	if (!base) {  		dev_err(&pdev->dev, "Unable to map regs\n");  		res = -ENOMEM;  		goto err;  	} -	control = readl(drvdata->mc_vbase + HB_DDR_ECC_OPT) & 0x3; +	settings = id->data; +	drvdata->mc_err_base = base + settings->err_offset; +	drvdata->mc_int_base = base + settings->int_offset; + +	control = readl(drvdata->mc_err_base + HB_DDR_ECC_OPT) & 0x3;  	if (!control || (control == 0x2)) {  		dev_err(&pdev->dev, "No ECC present, or ECC disabled\n");  		res = -ENODEV;  		goto err;  	} -	irq = platform_get_irq(pdev, 0); -	res = devm_request_irq(&pdev->dev, irq, highbank_mc_err_handler, -			       0, dev_name(&pdev->dev), mci); -	if (res < 0) { -		dev_err(&pdev->dev, "Unable to request irq %d\n", irq); -		goto err; -	} -  	mci->mtype_cap = MEM_FLAG_DDR3;  	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;  	mci->edac_cap = EDAC_FLAG_SECDED; -	mci->mod_name = dev_name(&pdev->dev); +	mci->mod_name = pdev->dev.driver->name;  	mci->mod_ver = "1"; -	mci->ctl_name = dev_name(&pdev->dev); +	mci->ctl_name = id->compatible; +	mci->dev_name = dev_name(&pdev->dev);  	mci->scrub_mode = SCRUB_SW_SRC;  	/* Only a single 4GB DIMM is supported */ @@ -217,10 +235,20 @@ static int highbank_mc_probe(struct platform_device *pdev)  	if (res < 0)  		goto err; -	highbank_mc_create_debugfs_nodes(mci); +	irq = platform_get_irq(pdev, 0); +	res = devm_request_irq(&pdev->dev, irq, highbank_mc_err_handler, +			       0, dev_name(&pdev->dev), mci); +	if (res < 0) { +		dev_err(&pdev->dev, "Unable to request irq %d\n", irq); +		goto err2; +	} + +	device_create_file(&mci->dev, &dev_attr_inject_ctrl);  	devres_close_group(&pdev->dev, NULL);  	return 0; +err2: +	edac_mc_del_mc(&pdev->dev);  err:  	devres_release_group(&pdev->dev, NULL);  	edac_mc_free(mci); @@ -231,17 +259,12 @@ static int highbank_mc_remove(struct platform_device *pdev)  {  	struct mem_ctl_info *mci = platform_get_drvdata(pdev); +	device_remove_file(&mci->dev, &dev_attr_inject_ctrl);  	edac_mc_del_mc(&pdev->dev);  	edac_mc_free(mci);  	return 0;  } -static const struct of_device_id hb_ddr_ctrl_of_match[] = { -	{ .compatible = "calxeda,hb-ddr-ctrl", }, -	{}, -}; -MODULE_DEVICE_TABLE(of, hb_ddr_ctrl_of_match); -  static struct platform_driver highbank_mc_edac_driver = {  	.probe = highbank_mc_probe,  	.remove = highbank_mc_remove, diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c index 694efcbf19c..cd28b968e5c 100644 --- a/drivers/edac/i3000_edac.c +++ b/drivers/edac/i3000_edac.c @@ -487,7 +487,7 @@ static void i3000_remove_one(struct pci_dev *pdev)  	edac_mc_free(mci);  } -static DEFINE_PCI_DEVICE_TABLE(i3000_pci_tbl) = { +static const struct pci_device_id i3000_pci_tbl[] = {  	{  	 PCI_VEND_DEV(INTEL, 3000_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,  	 I3000}, diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c index be10a74b16e..022a70273ad 100644 --- a/drivers/edac/i3200_edac.c +++ b/drivers/edac/i3200_edac.c @@ -464,9 +464,11 @@ static void i3200_remove_one(struct pci_dev *pdev)  	iounmap(priv->window);  	edac_mc_free(mci); + +	pci_disable_device(pdev);  } -static DEFINE_PCI_DEVICE_TABLE(i3200_pci_tbl) = { +static const struct pci_device_id i3200_pci_tbl[] = {  	{  		PCI_VEND_DEV(INTEL, 3200_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,  		I3200}, diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c index 63b2194e8c2..72e07e3cf71 100644 --- a/drivers/edac/i5000_edac.c +++ b/drivers/edac/i5000_edac.c @@ -1530,7 +1530,7 @@ static void i5000_remove_one(struct pci_dev *pdev)   *   *	The "E500P" device is the first device supported.   */ -static DEFINE_PCI_DEVICE_TABLE(i5000_pci_tbl) = { +static const struct pci_device_id i5000_pci_tbl[] = {  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I5000_DEV16),  	 .driver_data = I5000P}, diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c index 157b934e8ce..6247d186177 100644 --- a/drivers/edac/i5100_edac.c +++ b/drivers/edac/i5100_edac.c @@ -869,16 +869,13 @@ static void i5100_init_csrows(struct mem_ctl_info *mci)  			       chan, rank, 0);  		dimm->nr_pages = npages; -		if (npages) { -			dimm->grain = 32; -			dimm->dtype = (priv->mtr[chan][rank].width == 4) ? -					DEV_X4 : DEV_X8; -			dimm->mtype = MEM_RDDR2; -			dimm->edac_mode = EDAC_SECDED; -			snprintf(dimm->label, sizeof(dimm->label), -				"DIMM%u", -				i5100_rank_to_slot(mci, chan, rank)); -		} +		dimm->grain = 32; +		dimm->dtype = (priv->mtr[chan][rank].width == 4) ? +				DEV_X4 : DEV_X8; +		dimm->mtype = MEM_RDDR2; +		dimm->edac_mode = EDAC_SECDED; +		snprintf(dimm->label, sizeof(dimm->label), "DIMM%u", +			 i5100_rank_to_slot(mci, chan, rank));  		edac_dbg(2, "dimm channel %d, rank %d, size %ld\n",  			 chan, rank, (long)PAGES_TO_MiB(npages)); @@ -1213,7 +1210,7 @@ static void i5100_remove_one(struct pci_dev *pdev)  	edac_mc_free(mci);  } -static DEFINE_PCI_DEVICE_TABLE(i5100_pci_tbl) = { +static const struct pci_device_id i5100_pci_tbl[] = {  	/* Device 16, Function 0, Channel 0 Memory Map, Error Flag/Mask, ... */  	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5100_16) },  	{ 0, } diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c index 0a05bbceb08..6ef6ad1ba16 100644 --- a/drivers/edac/i5400_edac.c +++ b/drivers/edac/i5400_edac.c @@ -6,7 +6,7 @@   *   * Copyright (c) 2008 by:   *	 Ben Woodard <woodard@redhat.com> - *	 Mauro Carvalho Chehab <mchehab@redhat.com> + *	 Mauro Carvalho Chehab   *   * Red Hat Inc. http://www.redhat.com   * @@ -1408,6 +1408,8 @@ static void i5400_remove_one(struct pci_dev *pdev)  	/* retrieve references to resources, and free those resources */  	i5400_put_devices(mci); +	pci_disable_device(pdev); +  	edac_mc_free(mci);  } @@ -1416,7 +1418,7 @@ static void i5400_remove_one(struct pci_dev *pdev)   *   *	The "E500P" device is the first device supported.   */ -static DEFINE_PCI_DEVICE_TABLE(i5400_pci_tbl) = { +static const struct pci_device_id i5400_pci_tbl[] = {  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_ERR)},  	{0,}			/* 0 terminated list. */  }; @@ -1467,7 +1469,7 @@ module_exit(i5400_exit);  MODULE_LICENSE("GPL");  MODULE_AUTHOR("Ben Woodard <woodard@redhat.com>"); -MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); +MODULE_AUTHOR("Mauro Carvalho Chehab");  MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");  MODULE_DESCRIPTION("MC Driver for Intel I5400 memory controllers - "  		   I5400_REVISION); diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c index 9004c64b169..dcac982fdc7 100644 --- a/drivers/edac/i7300_edac.c +++ b/drivers/edac/i7300_edac.c @@ -5,7 +5,7 @@   * GNU General Public License version 2 only.   *   * Copyright (c) 2010 by: - *	 Mauro Carvalho Chehab <mchehab@redhat.com> + *	 Mauro Carvalho Chehab   *   * Red Hat Inc. http://www.redhat.com   * @@ -943,33 +943,35 @@ static int i7300_get_devices(struct mem_ctl_info *mci)  	/* Attempt to 'get' the MCH register we want */  	pdev = NULL; -	while (!pvt->pci_dev_16_1_fsb_addr_map || -	       !pvt->pci_dev_16_2_fsb_err_regs) { -		pdev = pci_get_device(PCI_VENDOR_ID_INTEL, -				      PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, pdev); -		if (!pdev) { -			/* End of list, leave */ -			i7300_printk(KERN_ERR, -				"'system address,Process Bus' " -				"device not found:" -				"vendor 0x%x device 0x%x ERR funcs " -				"(broken BIOS?)\n", -				PCI_VENDOR_ID_INTEL, -				PCI_DEVICE_ID_INTEL_I7300_MCH_ERR); -			goto error; -		} - +	while ((pdev = pci_get_device(PCI_VENDOR_ID_INTEL, +				      PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, +				      pdev))) {  		/* Store device 16 funcs 1 and 2 */  		switch (PCI_FUNC(pdev->devfn)) {  		case 1: -			pvt->pci_dev_16_1_fsb_addr_map = pdev; +			if (!pvt->pci_dev_16_1_fsb_addr_map) +				pvt->pci_dev_16_1_fsb_addr_map = +							pci_dev_get(pdev);  			break;  		case 2: -			pvt->pci_dev_16_2_fsb_err_regs = pdev; +			if (!pvt->pci_dev_16_2_fsb_err_regs) +				pvt->pci_dev_16_2_fsb_err_regs = +							pci_dev_get(pdev);  			break;  		}  	} +	if (!pvt->pci_dev_16_1_fsb_addr_map || +	    !pvt->pci_dev_16_2_fsb_err_regs) { +		/* At least one device was not found */ +		i7300_printk(KERN_ERR, +			"'system address,Process Bus' device not found:" +			"vendor 0x%x device 0x%x ERR funcs (broken BIOS?)\n", +			PCI_VENDOR_ID_INTEL, +			PCI_DEVICE_ID_INTEL_I7300_MCH_ERR); +		goto error; +	} +  	edac_dbg(1, "System Address, processor bus- PCI Bus ID: %s  %x:%x\n",  		 pci_name(pvt->pci_dev_16_0_fsb_ctlr),  		 pvt->pci_dev_16_0_fsb_ctlr->vendor, @@ -1160,7 +1162,7 @@ static void i7300_remove_one(struct pci_dev *pdev)   *   * Has only 8086:360c PCI ID   */ -static DEFINE_PCI_DEVICE_TABLE(i7300_pci_tbl) = { +static const struct pci_device_id i7300_pci_tbl[] = {  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_ERR)},  	{0,}			/* 0 terminated list. */  }; @@ -1207,7 +1209,7 @@ module_init(i7300_init);  module_exit(i7300_exit);  MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); +MODULE_AUTHOR("Mauro Carvalho Chehab");  MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");  MODULE_DESCRIPTION("MC Driver for Intel I7300 memory controllers - "  		   I7300_REVISION); diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 80a963d64e5..9cd0b301f81 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -9,7 +9,7 @@   * GNU General Public License version 2 only.   *   * Copyright (c) 2009-2010 by: - *	 Mauro Carvalho Chehab <mchehab@redhat.com> + *	 Mauro Carvalho Chehab   *   * Red Hat Inc. http://www.redhat.com   * @@ -394,7 +394,7 @@ static const struct pci_id_table pci_dev_table[] = {  /*   *	pci_device_id	table for which devices we are looking for   */ -static DEFINE_PCI_DEVICE_TABLE(i7core_pci_tbl) = { +static const struct pci_device_id i7core_pci_tbl[] = {  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)},  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0)},  	{0,}			/* 0 terminated list. */ @@ -1334,14 +1334,19 @@ static int i7core_get_onedevice(struct pci_dev **prev,  	 * is at addr 8086:2c40, instead of 8086:2c41. So, we need  	 * to probe for the alternate address in case of failure  	 */ -	if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) +	if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) { +		pci_dev_get(*prev);	/* pci_get_device will put it */  		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,  				      PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev); +	} -	if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev) +	if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && +	    !pdev) { +		pci_dev_get(*prev);	/* pci_get_device will put it */  		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,  				      PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT,  				      *prev); +	}  	if (!pdev) {  		if (*prev) { @@ -1703,7 +1708,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,  				    const struct mce *m)  {  	struct i7core_pvt *pvt = mci->pvt_info; -	char *type, *optype, *err; +	char *optype, *err;  	enum hw_event_mc_err_type tp_event;  	unsigned long error = m->status & 0x1ff0000l;  	bool uncorrected_error = m->mcgstatus & 1ll << 61; @@ -1716,15 +1721,11 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,  	u32 errnum = find_first_bit(&error, 32);  	if (uncorrected_error) { -		if (ripv) { -			type = "FATAL"; +		if (ripv)  			tp_event = HW_EVENT_ERR_FATAL; -		} else { -			type = "NON_FATAL"; +		else  			tp_event = HW_EVENT_ERR_UNCORRECTED; -		}  	} else { -		type = "CORRECTED";  		tp_event = HW_EVENT_ERR_CORRECTED;  	} @@ -2456,7 +2457,7 @@ module_init(i7core_init);  module_exit(i7core_exit);  MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); +MODULE_AUTHOR("Mauro Carvalho Chehab");  MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");  MODULE_DESCRIPTION("MC Driver for Intel i7 Core memory controllers - "  		   I7CORE_REVISION); diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c index 57fdb77903b..d730e276d1a 100644 --- a/drivers/edac/i82443bxgx_edac.c +++ b/drivers/edac/i82443bxgx_edac.c @@ -386,7 +386,7 @@ static void i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)  EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_remove_one); -static DEFINE_PCI_DEVICE_TABLE(i82443bxgx_pci_tbl) = { +static const struct pci_device_id i82443bxgx_pci_tbl[] = {  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0)},  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2)},  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0)}, diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c index 3e3e431c830..3382f6344e4 100644 --- a/drivers/edac/i82860_edac.c +++ b/drivers/edac/i82860_edac.c @@ -288,7 +288,7 @@ static void i82860_remove_one(struct pci_dev *pdev)  	edac_mc_free(mci);  } -static DEFINE_PCI_DEVICE_TABLE(i82860_pci_tbl) = { +static const struct pci_device_id i82860_pci_tbl[] = {  	{  	 PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,  	 I82860}, diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c index 2f8535fc451..64b68320249 100644 --- a/drivers/edac/i82875p_edac.c +++ b/drivers/edac/i82875p_edac.c @@ -275,7 +275,6 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev,  {  	struct pci_dev *dev;  	void __iomem *window; -	int err;  	*ovrfl_pdev = NULL;  	*ovrfl_window = NULL; @@ -293,13 +292,8 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev,  		if (dev == NULL)  			return 1; -		err = pci_bus_add_device(dev); -		if (err) { -			i82875p_printk(KERN_ERR, -				"%s(): pci_bus_add_device() Failed\n", -				__func__); -		}  		pci_bus_assign_resources(dev->bus); +		pci_bus_add_device(dev);  	}  	*ovrfl_pdev = dev; @@ -406,8 +400,6 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)  	edac_dbg(0, "\n"); -	ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL); -  	if (i82875p_setup_overfl_dev(pdev, &ovrfl_pdev, &ovrfl_window))  		return -ENODEV;  	drc = readl(ovrfl_window + I82875P_DRC); @@ -527,7 +519,7 @@ static void i82875p_remove_one(struct pci_dev *pdev)  	edac_mc_free(mci);  } -static DEFINE_PCI_DEVICE_TABLE(i82875p_pci_tbl) = { +static const struct pci_device_id i82875p_pci_tbl[] = {  	{  	 PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,  	 I82875P}, diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c index 0c8d4b0eaa3..10b10521f62 100644 --- a/drivers/edac/i82975x_edac.c +++ b/drivers/edac/i82975x_edac.c @@ -628,7 +628,7 @@ static void i82975x_remove_one(struct pci_dev *pdev)  	edac_mc_free(mci);  } -static DEFINE_PCI_DEVICE_TABLE(i82975x_pci_tbl) = { +static const struct pci_device_id i82975x_pci_tbl[] = {  	{  		PCI_VEND_DEV(INTEL, 82975_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,  		I82975X diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c index 30f7309446a..5f43620d580 100644 --- a/drivers/edac/mce_amd.c +++ b/drivers/edac/mce_amd.c @@ -6,7 +6,6 @@  static struct amd_decoder_ops *fam_ops;  static u8 xec_mask	 = 0xf; -static u8 nb_err_cpumask = 0xf;  static bool report_gart_errors;  static void (*nb_bus_decoder)(int node_id, struct mce *m); @@ -741,6 +740,36 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)  	if (amd_filter_mce(m))  		return NOTIFY_STOP; +	pr_emerg(HW_ERR "%s\n", decode_error_status(m)); + +	pr_emerg(HW_ERR "CPU:%d (%x:%x:%x) MC%d_STATUS[%s|%s|%s|%s|%s", +		m->extcpu, +		c->x86, c->x86_model, c->x86_mask, +		m->bank, +		((m->status & MCI_STATUS_OVER)	? "Over"  : "-"), +		((m->status & MCI_STATUS_UC)	? "UE"	  : "CE"), +		((m->status & MCI_STATUS_MISCV)	? "MiscV" : "-"), +		((m->status & MCI_STATUS_PCC)	? "PCC"	  : "-"), +		((m->status & MCI_STATUS_ADDRV)	? "AddrV" : "-")); + +	if (c->x86 == 0x15 || c->x86 == 0x16) +		pr_cont("|%s|%s", +			((m->status & MCI_STATUS_DEFERRED) ? "Deferred" : "-"), +			((m->status & MCI_STATUS_POISON)   ? "Poison"   : "-")); + +	/* do the two bits[14:13] together */ +	ecc = (m->status >> 45) & 0x3; +	if (ecc) +		pr_cont("|%sECC", ((ecc == 2) ? "C" : "U")); + +	pr_cont("]: 0x%016llx\n", m->status); + +	if (m->status & MCI_STATUS_ADDRV) +		pr_emerg(HW_ERR "MC%d_ADDR: 0x%016llx\n", m->bank, m->addr); + +	if (!fam_ops) +		goto err_code; +  	switch (m->bank) {  	case 0:  		decode_mc0_mce(m); @@ -774,33 +803,7 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)  		break;  	} -	pr_emerg(HW_ERR "Error Status: %s\n", decode_error_status(m)); - -	pr_emerg(HW_ERR "CPU:%d (%x:%x:%x) MC%d_STATUS[%s|%s|%s|%s|%s", -		m->extcpu, -		c->x86, c->x86_model, c->x86_mask, -		m->bank, -		((m->status & MCI_STATUS_OVER)	? "Over"  : "-"), -		((m->status & MCI_STATUS_UC)	? "UE"	  : "CE"), -		((m->status & MCI_STATUS_MISCV)	? "MiscV" : "-"), -		((m->status & MCI_STATUS_PCC)	? "PCC"	  : "-"), -		((m->status & MCI_STATUS_ADDRV)	? "AddrV" : "-")); - -	if (c->x86 == 0x15 || c->x86 == 0x16) -		pr_cont("|%s|%s", -			((m->status & MCI_STATUS_DEFERRED) ? "Deferred" : "-"), -			((m->status & MCI_STATUS_POISON)   ? "Poison"   : "-")); - -	/* do the two bits[14:13] together */ -	ecc = (m->status >> 45) & 0x3; -	if (ecc) -		pr_cont("|%sECC", ((ecc == 2) ? "C" : "U")); - -	pr_cont("]: 0x%016llx\n", m->status); - -	if (m->status & MCI_STATUS_ADDRV) -		pr_emerg(HW_ERR "MC%d_ADDR: 0x%016llx\n", m->bank, m->addr); - + err_code:  	amd_decode_err_code(m->status & 0xffff);  	return NOTIFY_STOP; @@ -816,10 +819,7 @@ static int __init mce_amd_init(void)  	struct cpuinfo_x86 *c = &boot_cpu_data;  	if (c->x86_vendor != X86_VENDOR_AMD) -		return 0; - -	if (c->x86 < 0xf || c->x86 > 0x16) -		return 0; +		return -ENODEV;  	fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL);  	if (!fam_ops) @@ -851,7 +851,6 @@ static int __init mce_amd_init(void)  		break;  	case 0x14: -		nb_err_cpumask  = 0x3;  		fam_ops->mc0_mce = cat_mc0_mce;  		fam_ops->mc1_mce = cat_mc1_mce;  		fam_ops->mc2_mce = k8_mc2_mce; @@ -874,7 +873,7 @@ static int __init mce_amd_init(void)  	default:  		printk(KERN_WARNING "Huh? What family is it: 0x%x?!\n", c->x86);  		kfree(fam_ops); -		return -EINVAL; +		fam_ops = NULL;  	}  	pr_info("MCE: In-kernel MCE decoding enabled.\n"); diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 3eb32f62d72..f4aec2e6ef5 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -1,6 +1,8 @@  /*   * Freescale MPC85xx Memory Controller kenel module   * + * Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc. + *   * Author: Dave Jiang <djiang@mvista.com>   *   * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under @@ -196,6 +198,42 @@ static void mpc85xx_pci_check(struct edac_pci_ctl_info *pci)  		edac_pci_handle_npe(pci, pci->ctl_name);  } +static void mpc85xx_pcie_check(struct edac_pci_ctl_info *pci) +{ +	struct mpc85xx_pci_pdata *pdata = pci->pvt_info; +	u32 err_detect; + +	err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR); + +	pr_err("PCIe error(s) detected\n"); +	pr_err("PCIe ERR_DR register: 0x%08x\n", err_detect); +	pr_err("PCIe ERR_CAP_STAT register: 0x%08x\n", +			in_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR)); +	pr_err("PCIe ERR_CAP_R0 register: 0x%08x\n", +			in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R0)); +	pr_err("PCIe ERR_CAP_R1 register: 0x%08x\n", +			in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R1)); +	pr_err("PCIe ERR_CAP_R2 register: 0x%08x\n", +			in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R2)); +	pr_err("PCIe ERR_CAP_R3 register: 0x%08x\n", +			in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R3)); + +	/* clear error bits */ +	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect); +} + +static int mpc85xx_pcie_find_capability(struct device_node *np) +{ +	struct pci_controller *hose; + +	if (!np) +		return -EINVAL; + +	hose = pci_find_hose_for_OF_device(np); + +	return early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP); +} +  static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)  {  	struct edac_pci_ctl_info *pci = dev_id; @@ -207,7 +245,10 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)  	if (!err_detect)  		return IRQ_NONE; -	mpc85xx_pci_check(pci); +	if (pdata->is_pcie) +		mpc85xx_pcie_check(pci); +	else +		mpc85xx_pci_check(pci);  	return IRQ_HANDLED;  } @@ -239,14 +280,22 @@ int mpc85xx_pci_err_probe(struct platform_device *op)  	pdata = pci->pvt_info;  	pdata->name = "mpc85xx_pci_err";  	pdata->irq = NO_IRQ; + +	if (mpc85xx_pcie_find_capability(op->dev.of_node) > 0) +		pdata->is_pcie = true; +  	dev_set_drvdata(&op->dev, pci);  	pci->dev = &op->dev;  	pci->mod_name = EDAC_MOD_STR;  	pci->ctl_name = pdata->name;  	pci->dev_name = dev_name(&op->dev); -	if (edac_op_state == EDAC_OPSTATE_POLL) -		pci->edac_check = mpc85xx_pci_check; +	if (edac_op_state == EDAC_OPSTATE_POLL) { +		if (pdata->is_pcie) +			pci->edac_check = mpc85xx_pcie_check; +		else +			pci->edac_check = mpc85xx_pci_check; +	}  	pdata->edac_idx = edac_pci_idx++; @@ -275,16 +324,26 @@ int mpc85xx_pci_err_probe(struct platform_device *op)  		goto err;  	} -	orig_pci_err_cap_dr = -	    in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR); +	if (pdata->is_pcie) { +		orig_pci_err_cap_dr = +		    in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR); +		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR, ~0); +		orig_pci_err_en = +		    in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN); +		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, 0); +	} else { +		orig_pci_err_cap_dr = +		    in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR); -	/* PCI master abort is expected during config cycles */ -	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, 0x40); +		/* PCI master abort is expected during config cycles */ +		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, 0x40); -	orig_pci_err_en = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN); +		orig_pci_err_en = +		    in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN); -	/* disable master abort reporting */ -	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0x40); +		/* disable master abort reporting */ +		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0x40); +	}  	/* clear error bits */  	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0); @@ -297,7 +356,8 @@ int mpc85xx_pci_err_probe(struct platform_device *op)  	if (edac_op_state == EDAC_OPSTATE_INT) {  		pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);  		res = devm_request_irq(&op->dev, pdata->irq, -				       mpc85xx_pci_isr, IRQF_DISABLED, +				       mpc85xx_pci_isr, +				       IRQF_SHARED,  				       "[EDAC] PCI err", pci);  		if (res < 0) {  			printk(KERN_ERR @@ -312,6 +372,22 @@ int mpc85xx_pci_err_probe(struct platform_device *op)  		       pdata->irq);  	} +	if (pdata->is_pcie) { +		/* +		 * Enable all PCIe error interrupt & error detect except invalid +		 * PEX_CONFIG_ADDR/PEX_CONFIG_DATA access interrupt generation +		 * enable bit and invalid PEX_CONFIG_ADDR/PEX_CONFIG_DATA access +		 * detection enable bit. Because PCIe bus code to initialize and +		 * configure these PCIe devices on booting will use some invalid +		 * PEX_CONFIG_ADDR/PEX_CONFIG_DATA, edac driver prints the much +		 * notice information. So disable this detect to fix ugly print. +		 */ +		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0 +			 & ~PEX_ERR_ICCAIE_EN_BIT); +		out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR, 0 +			 | PEX_ERR_ICCAD_DISR_BIT); +	} +  	devres_remove_group(&op->dev, mpc85xx_pci_err_probe);  	edac_dbg(3, "success\n");  	printk(KERN_INFO EDAC_MOD_STR " PCI err registered\n"); @@ -327,28 +403,6 @@ err:  }  EXPORT_SYMBOL(mpc85xx_pci_err_probe); -static int mpc85xx_pci_err_remove(struct platform_device *op) -{ -	struct edac_pci_ctl_info *pci = dev_get_drvdata(&op->dev); -	struct mpc85xx_pci_pdata *pdata = pci->pvt_info; - -	edac_dbg(0, "\n"); - -	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, -		 orig_pci_err_cap_dr); - -	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, orig_pci_err_en); - -	edac_pci_del_device(pci->dev); - -	if (edac_op_state == EDAC_OPSTATE_INT) -		irq_dispose_mapping(pdata->irq); - -	edac_pci_free_ctl_info(pci); - -	return 0; -} -  #endif				/* CONFIG_PCI */  /**************************** L2 Err device ***************************/ @@ -579,7 +633,7 @@ static int mpc85xx_l2_err_probe(struct platform_device *op)  	if (edac_op_state == EDAC_OPSTATE_INT) {  		pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);  		res = devm_request_irq(&op->dev, pdata->irq, -				       mpc85xx_l2_isr, IRQF_DISABLED, +				       mpc85xx_l2_isr, 0,  				       "[EDAC] L2 err", edac_dev);  		if (res < 0) {  			printk(KERN_ERR @@ -1079,7 +1133,7 @@ static int mpc85xx_mc_err_probe(struct platform_device *op)  		pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);  		res = devm_request_irq(&op->dev, pdata->irq,  				       mpc85xx_mc_isr, -					IRQF_DISABLED | IRQF_SHARED, +				       IRQF_SHARED,  				       "[EDAC] MC err", mci);  		if (res < 0) {  			printk(KERN_ERR "%s: Unable to request irq %d for " diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h index 932016f2cf0..8c625643622 100644 --- a/drivers/edac/mpc85xx_edac.h +++ b/drivers/edac/mpc85xx_edac.h @@ -134,13 +134,19 @@  #define MPC85XX_PCI_ERR_DR		0x0000  #define MPC85XX_PCI_ERR_CAP_DR		0x0004  #define MPC85XX_PCI_ERR_EN		0x0008 +#define   PEX_ERR_ICCAIE_EN_BIT		0x00020000  #define MPC85XX_PCI_ERR_ATTRIB		0x000c  #define MPC85XX_PCI_ERR_ADDR		0x0010 +#define   PEX_ERR_ICCAD_DISR_BIT	0x00020000  #define MPC85XX_PCI_ERR_EXT_ADDR	0x0014  #define MPC85XX_PCI_ERR_DL		0x0018  #define MPC85XX_PCI_ERR_DH		0x001c  #define MPC85XX_PCI_GAS_TIMR		0x0020  #define MPC85XX_PCI_PCIX_TIMR		0x0024 +#define MPC85XX_PCIE_ERR_CAP_R0		0x0028 +#define MPC85XX_PCIE_ERR_CAP_R1		0x002c +#define MPC85XX_PCIE_ERR_CAP_R2		0x0030 +#define MPC85XX_PCIE_ERR_CAP_R3		0x0034  struct mpc85xx_mc_pdata {  	char *name; @@ -158,6 +164,7 @@ struct mpc85xx_l2_pdata {  struct mpc85xx_pci_pdata {  	char *name; +	bool is_pcie;  	int edac_idx;  	void __iomem *pci_vbase;  	int irq; diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c index 93412d6b3af..4bd10f94f06 100644 --- a/drivers/edac/octeon_edac-lmc.c +++ b/drivers/edac/octeon_edac-lmc.c @@ -5,12 +5,16 @@   *   * Copyright (C) 2009 Wind River Systems,   *   written by Ralf Baechle <ralf@linux-mips.org> + * + * Copyright (c) 2013 by Cisco Systems, Inc. + * All rights reserved.   */  #include <linux/module.h>  #include <linux/init.h>  #include <linux/slab.h>  #include <linux/io.h>  #include <linux/edac.h> +#include <linux/ctype.h>  #include <asm/octeon/octeon.h>  #include <asm/octeon/cvmx-lmcx-defs.h> @@ -20,6 +24,18 @@  #define OCTEON_MAX_MC 4 +#define to_mci(k) container_of(k, struct mem_ctl_info, dev) + +struct octeon_lmc_pvt { +	unsigned long inject; +	unsigned long error_type; +	unsigned long dimm; +	unsigned long rank; +	unsigned long bank; +	unsigned long row; +	unsigned long col; +}; +  static void octeon_lmc_edac_poll(struct mem_ctl_info *mci)  {  	union cvmx_lmcx_mem_cfg0 cfg0; @@ -55,14 +71,31 @@ static void octeon_lmc_edac_poll(struct mem_ctl_info *mci)  static void octeon_lmc_edac_poll_o2(struct mem_ctl_info *mci)  { +	struct octeon_lmc_pvt *pvt = mci->pvt_info;  	union cvmx_lmcx_int int_reg;  	bool do_clear = false;  	char msg[64]; -	int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx)); +	if (!pvt->inject) +		int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx)); +	else { +		if (pvt->error_type == 1) +			int_reg.s.sec_err = 1; +		if (pvt->error_type == 2) +			int_reg.s.ded_err = 1; +	} +  	if (int_reg.s.sec_err || int_reg.s.ded_err) {  		union cvmx_lmcx_fadr fadr; -		fadr.u64 = cvmx_read_csr(CVMX_LMCX_FADR(mci->mc_idx)); +		if (likely(!pvt->inject)) +			fadr.u64 = cvmx_read_csr(CVMX_LMCX_FADR(mci->mc_idx)); +		else { +			fadr.cn61xx.fdimm = pvt->dimm; +			fadr.cn61xx.fbunk = pvt->rank; +			fadr.cn61xx.fbank = pvt->bank; +			fadr.cn61xx.frow = pvt->row; +			fadr.cn61xx.fcol = pvt->col; +		}  		snprintf(msg, sizeof(msg),  			 "DIMM %d rank %d bank %d row %d col %d",  			 fadr.cn61xx.fdimm, fadr.cn61xx.fbunk, @@ -82,8 +115,128 @@ static void octeon_lmc_edac_poll_o2(struct mem_ctl_info *mci)  		int_reg.s.ded_err = -1;	/* Done, re-arm */  		do_clear = true;  	} -	if (do_clear) -		cvmx_write_csr(CVMX_LMCX_INT(mci->mc_idx), int_reg.u64); + +	if (do_clear) { +		if (likely(!pvt->inject)) +			cvmx_write_csr(CVMX_LMCX_INT(mci->mc_idx), int_reg.u64); +		else +			pvt->inject = 0; +	} +} + +/************************ MC SYSFS parts ***********************************/ + +/* Only a couple naming differences per template, so very similar */ +#define TEMPLATE_SHOW(reg)						\ +static ssize_t octeon_mc_inject_##reg##_show(struct device *dev,	\ +			       struct device_attribute *attr,		\ +			       char *data)				\ +{									\ +	struct mem_ctl_info *mci = to_mci(dev);				\ +	struct octeon_lmc_pvt *pvt = mci->pvt_info;			\ +	return sprintf(data, "%016llu\n", (u64)pvt->reg);		\ +} + +#define TEMPLATE_STORE(reg)						\ +static ssize_t octeon_mc_inject_##reg##_store(struct device *dev,	\ +			       struct device_attribute *attr,		\ +			       const char *data, size_t count)		\ +{									\ +	struct mem_ctl_info *mci = to_mci(dev);				\ +	struct octeon_lmc_pvt *pvt = mci->pvt_info;			\ +	if (isdigit(*data)) {						\ +		if (!kstrtoul(data, 0, &pvt->reg))			\ +			return count;					\ +	}								\ +	return 0;							\ +} + +TEMPLATE_SHOW(inject); +TEMPLATE_STORE(inject); +TEMPLATE_SHOW(dimm); +TEMPLATE_STORE(dimm); +TEMPLATE_SHOW(bank); +TEMPLATE_STORE(bank); +TEMPLATE_SHOW(rank); +TEMPLATE_STORE(rank); +TEMPLATE_SHOW(row); +TEMPLATE_STORE(row); +TEMPLATE_SHOW(col); +TEMPLATE_STORE(col); + +static ssize_t octeon_mc_inject_error_type_store(struct device *dev, +					  struct device_attribute *attr, +					  const char *data, +					  size_t count) +{ +	struct mem_ctl_info *mci = to_mci(dev); +	struct octeon_lmc_pvt *pvt = mci->pvt_info; + +	if (!strncmp(data, "single", 6)) +		pvt->error_type = 1; +	else if (!strncmp(data, "double", 6)) +		pvt->error_type = 2; + +	return count; +} + +static ssize_t octeon_mc_inject_error_type_show(struct device *dev, +					 struct device_attribute *attr, +					 char *data) +{ +	struct mem_ctl_info *mci = to_mci(dev); +	struct octeon_lmc_pvt *pvt = mci->pvt_info; +	if (pvt->error_type == 1) +		return sprintf(data, "single"); +	else if (pvt->error_type == 2) +		return sprintf(data, "double"); + +	return 0; +} + +static DEVICE_ATTR(inject, S_IRUGO | S_IWUSR, +		   octeon_mc_inject_inject_show, octeon_mc_inject_inject_store); +static DEVICE_ATTR(error_type, S_IRUGO | S_IWUSR, +		   octeon_mc_inject_error_type_show, octeon_mc_inject_error_type_store); +static DEVICE_ATTR(dimm, S_IRUGO | S_IWUSR, +		   octeon_mc_inject_dimm_show, octeon_mc_inject_dimm_store); +static DEVICE_ATTR(rank, S_IRUGO | S_IWUSR, +		   octeon_mc_inject_rank_show, octeon_mc_inject_rank_store); +static DEVICE_ATTR(bank, S_IRUGO | S_IWUSR, +		   octeon_mc_inject_bank_show, octeon_mc_inject_bank_store); +static DEVICE_ATTR(row, S_IRUGO | S_IWUSR, +		   octeon_mc_inject_row_show, octeon_mc_inject_row_store); +static DEVICE_ATTR(col, S_IRUGO | S_IWUSR, +		   octeon_mc_inject_col_show, octeon_mc_inject_col_store); + + +static int octeon_set_mc_sysfs_attributes(struct mem_ctl_info *mci) +{ +	int rc; + +	rc = device_create_file(&mci->dev, &dev_attr_inject); +	if (rc < 0) +		return rc; +	rc = device_create_file(&mci->dev, &dev_attr_error_type); +	if (rc < 0) +		return rc; +	rc = device_create_file(&mci->dev, &dev_attr_dimm); +	if (rc < 0) +		return rc; +	rc = device_create_file(&mci->dev, &dev_attr_rank); +	if (rc < 0) +		return rc; +	rc = device_create_file(&mci->dev, &dev_attr_bank); +	if (rc < 0) +		return rc; +	rc = device_create_file(&mci->dev, &dev_attr_row); +	if (rc < 0) +		return rc; +	rc = device_create_file(&mci->dev, &dev_attr_col); +	if (rc < 0) +		return rc; + +	return 0;  }  static int octeon_lmc_edac_probe(struct platform_device *pdev) @@ -92,6 +245,8 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev)  	struct edac_mc_layer layers[1];  	int mc = pdev->id; +	opstate_init(); +  	layers[0].type = EDAC_MC_LAYER_CHANNEL;  	layers[0].size = 1;  	layers[0].is_virt_csrow = false; @@ -105,7 +260,7 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev)  			return 0;  		} -		mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, 0); +		mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, sizeof(struct octeon_lmc_pvt));  		if (!mci)  			return -ENXIO; @@ -122,6 +277,12 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev)  			return -ENXIO;  		} +		if (octeon_set_mc_sysfs_attributes(mci)) { +			dev_err(&pdev->dev, "octeon_set_mc_sysfs_attributes() failed\n"); +			return -ENXIO; +		} + +  		cfg0.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(mc));  		cfg0.s.intr_ded_ena = 0;	/* We poll */  		cfg0.s.intr_sec_ena = 0; @@ -137,7 +298,7 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev)  			return 0;  		} -		mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, 0); +		mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, sizeof(struct octeon_lmc_pvt));  		if (!mci)  			return -ENXIO; @@ -154,6 +315,12 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev)  			return -ENXIO;  		} +		if (octeon_set_mc_sysfs_attributes(mci)) { +			dev_err(&pdev->dev, "octeon_set_mc_sysfs_attributes() failed\n"); +			return -ENXIO; +		} + +  		en.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(mc));  		en.s.intr_ded_ena = 0;	/* We poll */  		en.s.intr_sec_ena = 0; diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c index 2fd6a549090..8f936bc7a01 100644 --- a/drivers/edac/r82600_edac.c +++ b/drivers/edac/r82600_edac.c @@ -383,7 +383,7 @@ static void r82600_remove_one(struct pci_dev *pdev)  	edac_mc_free(mci);  } -static DEFINE_PCI_DEVICE_TABLE(r82600_pci_tbl) = { +static const struct pci_device_id r82600_pci_tbl[] = {  	{  	 PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)  	 }, diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index e04462b6075..deea0dc9999 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -7,7 +7,7 @@   * GNU General Public License version 2 only.   *   * Copyright (c) 2011 by: - *	 Mauro Carvalho Chehab <mchehab@redhat.com> + *	 Mauro Carvalho Chehab   */  #include <linux/module.h> @@ -34,7 +34,7 @@ static int probed;  /*   * Alter this version for the module when modifications are made   */ -#define SBRIDGE_REVISION    " Ver: 1.0.0 " +#define SBRIDGE_REVISION    " Ver: 1.1.0 "  #define EDAC_MOD_STR      "sbridge_edac"  /* @@ -50,7 +50,7 @@ static int probed;   * Get a bit field at register value <v>, from bit <lo> to bit <hi>   */  #define GET_BITFIELD(v, lo, hi)	\ -	(((v) & ((1ULL << ((hi) - (lo) + 1)) - 1) << (lo)) >> (lo)) +	(((v) & GENMASK_ULL(hi, lo)) >> (lo))  /*   * sbridge Memory Controller Registers @@ -83,11 +83,17 @@ static int probed;  #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR3	0x3c77	/* 16.7 */  /* Devices 12 Function 6, Offsets 0x80 to 0xcc */ -static const u32 dram_rule[] = { +static const u32 sbridge_dram_rule[] = {  	0x80, 0x88, 0x90, 0x98, 0xa0,  	0xa8, 0xb0, 0xb8, 0xc0, 0xc8,  }; -#define MAX_SAD		ARRAY_SIZE(dram_rule) + +static const u32 ibridge_dram_rule[] = { +	0x60, 0x68, 0x70, 0x78, 0x80, +	0x88, 0x90, 0x98, 0xa0,	0xa8, +	0xb0, 0xb8, 0xc0, 0xc8, 0xd0, +	0xd8, 0xe0, 0xe8, 0xf0, 0xf8, +};  #define SAD_LIMIT(reg)		((GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff)  #define DRAM_ATTR(reg)		GET_BITFIELD(reg, 2,  3) @@ -108,43 +114,50 @@ static char *get_dram_attr(u32 reg)  	}  } -static const u32 interleave_list[] = { +static const u32 sbridge_interleave_list[] = {  	0x84, 0x8c, 0x94, 0x9c, 0xa4,  	0xac, 0xb4, 0xbc, 0xc4, 0xcc,  }; -#define MAX_INTERLEAVE	ARRAY_SIZE(interleave_list) - -#define SAD_PKG0(reg)		GET_BITFIELD(reg, 0, 2) -#define SAD_PKG1(reg)		GET_BITFIELD(reg, 3, 5) -#define SAD_PKG2(reg)		GET_BITFIELD(reg, 8, 10) -#define SAD_PKG3(reg)		GET_BITFIELD(reg, 11, 13) -#define SAD_PKG4(reg)		GET_BITFIELD(reg, 16, 18) -#define SAD_PKG5(reg)		GET_BITFIELD(reg, 19, 21) -#define SAD_PKG6(reg)		GET_BITFIELD(reg, 24, 26) -#define SAD_PKG7(reg)		GET_BITFIELD(reg, 27, 29) - -static inline int sad_pkg(u32 reg, int interleave) + +static const u32 ibridge_interleave_list[] = { +	0x64, 0x6c, 0x74, 0x7c, 0x84, +	0x8c, 0x94, 0x9c, 0xa4, 0xac, +	0xb4, 0xbc, 0xc4, 0xcc, 0xd4, +	0xdc, 0xe4, 0xec, 0xf4, 0xfc, +}; + +struct interleave_pkg { +	unsigned char start; +	unsigned char end; +}; + +static const struct interleave_pkg sbridge_interleave_pkg[] = { +	{ 0, 2 }, +	{ 3, 5 }, +	{ 8, 10 }, +	{ 11, 13 }, +	{ 16, 18 }, +	{ 19, 21 }, +	{ 24, 26 }, +	{ 27, 29 }, +}; + +static const struct interleave_pkg ibridge_interleave_pkg[] = { +	{ 0, 3 }, +	{ 4, 7 }, +	{ 8, 11 }, +	{ 12, 15 }, +	{ 16, 19 }, +	{ 20, 23 }, +	{ 24, 27 }, +	{ 28, 31 }, +}; + +static inline int sad_pkg(const struct interleave_pkg *table, u32 reg, +			  int interleave)  { -	switch (interleave) { -	case 0: -		return SAD_PKG0(reg); -	case 1: -		return SAD_PKG1(reg); -	case 2: -		return SAD_PKG2(reg); -	case 3: -		return SAD_PKG3(reg); -	case 4: -		return SAD_PKG4(reg); -	case 5: -		return SAD_PKG5(reg); -	case 6: -		return SAD_PKG6(reg); -	case 7: -		return SAD_PKG7(reg); -	default: -		return -EINVAL; -	} +	return GET_BITFIELD(reg, table[interleave].start, +			    table[interleave].end);  }  /* Devices 12 Function 7 */ @@ -262,7 +275,9 @@ static const u32 correrrthrsld[] = {  /* Device 17, function 0 */ -#define RANK_CFG_A		0x0328 +#define SB_RANK_CFG_A		0x0328 + +#define IB_RANK_CFG_A		0x0320  #define IS_RDIMM_ENABLED(reg)		GET_BITFIELD(reg, 11, 11) @@ -273,8 +288,23 @@ static const u32 correrrthrsld[] = {  #define NUM_CHANNELS	4  #define MAX_DIMMS	3		/* Max DIMMS per channel */ +enum type { +	SANDY_BRIDGE, +	IVY_BRIDGE, +}; + +struct sbridge_pvt;  struct sbridge_info { -	u32	mcmtr; +	enum type	type; +	u32		mcmtr; +	u32		rankcfgr; +	u64		(*get_tolm)(struct sbridge_pvt *pvt); +	u64		(*get_tohm)(struct sbridge_pvt *pvt); +	const u32	*dram_rule; +	const u32	*interleave_list; +	const struct interleave_pkg *interleave_pkg; +	u8		max_sad; +	u8		max_interleave;  };  struct sbridge_channel { @@ -305,8 +335,9 @@ struct sbridge_dev {  struct sbridge_pvt {  	struct pci_dev		*pci_ta, *pci_ddrio, *pci_ras; -	struct pci_dev		*pci_sad0, *pci_sad1, *pci_ha0; -	struct pci_dev		*pci_br; +	struct pci_dev		*pci_sad0, *pci_sad1; +	struct pci_dev		*pci_ha0, *pci_ha1; +	struct pci_dev		*pci_br0, *pci_br1;  	struct pci_dev		*pci_tad[NUM_CHANNELS];  	struct sbridge_dev	*sbridge_dev; @@ -364,11 +395,75 @@ static const struct pci_id_table pci_dev_descr_sbridge_table[] = {  	{0,}			/* 0 terminated list. */  }; +/* This changes depending if 1HA or 2HA: + * 1HA: + *	0x0eb8 (17.0) is DDRIO0 + * 2HA: + *	0x0ebc (17.4) is DDRIO0 + */ +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0	0x0eb8 +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0	0x0ebc + +/* pci ids */ +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0		0x0ea0 +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA		0x0ea8 +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS		0x0e71 +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0	0x0eaa +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1	0x0eab +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2	0x0eac +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3	0x0ead +#define PCI_DEVICE_ID_INTEL_IBRIDGE_SAD			0x0ec8 +#define PCI_DEVICE_ID_INTEL_IBRIDGE_BR0			0x0ec9 +#define PCI_DEVICE_ID_INTEL_IBRIDGE_BR1			0x0eca +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1		0x0e60 +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA		0x0e68 +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS		0x0e79 +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0	0x0e6a +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1	0x0e6b + +static const struct pci_id_descr pci_dev_descr_ibridge[] = { +		/* Processor Home Agent */ +	{ PCI_DESCR(14, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0, 0)	}, + +		/* Memory controller */ +	{ PCI_DESCR(15, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA, 0)	}, +	{ PCI_DESCR(15, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS, 0)	}, +	{ PCI_DESCR(15, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0, 0)	}, +	{ PCI_DESCR(15, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1, 0)	}, +	{ PCI_DESCR(15, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2, 0)	}, +	{ PCI_DESCR(15, 5, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3, 0)	}, + +		/* System Address Decoder */ +	{ PCI_DESCR(22, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_SAD, 0)		}, + +		/* Broadcast Registers */ +	{ PCI_DESCR(22, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_BR0, 1)		}, +	{ PCI_DESCR(22, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_BR1, 0)		}, + +		/* Optional, mode 2HA */ +	{ PCI_DESCR(28, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, 1)	}, +#if 0 +	{ PCI_DESCR(29, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA, 1)	}, +	{ PCI_DESCR(29, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS, 1)	}, +#endif +	{ PCI_DESCR(29, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0, 1)	}, +	{ PCI_DESCR(29, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1, 1)	}, + +	{ PCI_DESCR(17, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0, 1) }, +	{ PCI_DESCR(17, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0, 1) }, +}; + +static const struct pci_id_table pci_dev_descr_ibridge_table[] = { +	PCI_ID_TABLE_ENTRY(pci_dev_descr_ibridge), +	{0,}			/* 0 terminated list. */ +}; +  /*   *	pci_device_id	table for which devices we are looking for   */ -static DEFINE_PCI_DEVICE_TABLE(sbridge_pci_tbl) = { +static const struct pci_device_id sbridge_pci_tbl[] = {  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)}, +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)},  	{0,}			/* 0 terminated list. */  }; @@ -458,6 +553,52 @@ static void free_sbridge_dev(struct sbridge_dev *sbridge_dev)  	kfree(sbridge_dev);  } +static u64 sbridge_get_tolm(struct sbridge_pvt *pvt) +{ +	u32 reg; + +	/* Address range is 32:28 */ +	pci_read_config_dword(pvt->pci_sad1, TOLM, ®); +	return GET_TOLM(reg); +} + +static u64 sbridge_get_tohm(struct sbridge_pvt *pvt) +{ +	u32 reg; + +	pci_read_config_dword(pvt->pci_sad1, TOHM, ®); +	return GET_TOHM(reg); +} + +static u64 ibridge_get_tolm(struct sbridge_pvt *pvt) +{ +	u32 reg; + +	pci_read_config_dword(pvt->pci_br1, TOLM, ®); + +	return GET_TOLM(reg); +} + +static u64 ibridge_get_tohm(struct sbridge_pvt *pvt) +{ +	u32 reg; + +	pci_read_config_dword(pvt->pci_br1, TOHM, ®); + +	return GET_TOHM(reg); +} + +static inline u8 sad_pkg_socket(u8 pkg) +{ +	/* on Ivy Bridge, nodeID is SASS, where A is HA and S is node id */ +	return (pkg >> 3) | (pkg & 0x3); +} + +static inline u8 sad_pkg_ha(u8 pkg) +{ +	return (pkg >> 2) & 0x1; +} +  /****************************************************************************  			Memory check routines   ****************************************************************************/ @@ -520,10 +661,10 @@ static int get_dimm_config(struct mem_ctl_info *mci)  	enum edac_type mode;  	enum mem_type mtype; -	pci_read_config_dword(pvt->pci_br, SAD_TARGET, ®); +	pci_read_config_dword(pvt->pci_br0, SAD_TARGET, ®);  	pvt->sbridge_dev->source_id = SOURCE_ID(reg); -	pci_read_config_dword(pvt->pci_br, SAD_CONTROL, ®); +	pci_read_config_dword(pvt->pci_br0, SAD_CONTROL, ®);  	pvt->sbridge_dev->node_id = NODE_ID(reg);  	edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n",  		 pvt->sbridge_dev->mc, @@ -558,7 +699,8 @@ static int get_dimm_config(struct mem_ctl_info *mci)  	}  	if (pvt->pci_ddrio) { -		pci_read_config_dword(pvt->pci_ddrio, RANK_CFG_A, ®); +		pci_read_config_dword(pvt->pci_ddrio, pvt->info.rankcfgr, +				      ®);  		if (IS_RDIMM_ENABLED(reg)) {  			/* FIXME: Can also be LRDIMM */  			edac_dbg(0, "Memory is registered\n"); @@ -629,19 +771,14 @@ static void get_memory_layout(const struct mem_ctl_info *mci)  	 * Step 1) Get TOLM/TOHM ranges  	 */ -	/* Address range is 32:28 */ -	pci_read_config_dword(pvt->pci_sad1, TOLM, -			      ®); -	pvt->tolm = GET_TOLM(reg); +	pvt->tolm = pvt->info.get_tolm(pvt);  	tmp_mb = (1 + pvt->tolm) >> 20;  	mb = div_u64_rem(tmp_mb, 1000, &kb);  	edac_dbg(0, "TOLM: %u.%03u GB (0x%016Lx)\n", mb, kb, (u64)pvt->tolm);  	/* Address range is already 45:25 */ -	pci_read_config_dword(pvt->pci_sad1, TOHM, -			      ®); -	pvt->tohm = GET_TOHM(reg); +	pvt->tohm = pvt->info.get_tohm(pvt);  	tmp_mb = (1 + pvt->tohm) >> 20;  	mb = div_u64_rem(tmp_mb, 1000, &kb); @@ -654,9 +791,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci)  	 * algorithm bellow.  	 */  	prv = 0; -	for (n_sads = 0; n_sads < MAX_SAD; n_sads++) { +	for (n_sads = 0; n_sads < pvt->info.max_sad; n_sads++) {  		/* SAD_LIMIT Address range is 45:26 */ -		pci_read_config_dword(pvt->pci_sad0, dram_rule[n_sads], +		pci_read_config_dword(pvt->pci_sad0, pvt->info.dram_rule[n_sads],  				      ®);  		limit = SAD_LIMIT(reg); @@ -677,15 +814,16 @@ static void get_memory_layout(const struct mem_ctl_info *mci)  			 reg);  		prv = limit; -		pci_read_config_dword(pvt->pci_sad0, interleave_list[n_sads], +		pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],  				      ®); -		sad_interl = sad_pkg(reg, 0); +		sad_interl = sad_pkg(pvt->info.interleave_pkg, reg, 0);  		for (j = 0; j < 8; j++) { -			if (j > 0 && sad_interl == sad_pkg(reg, j)) +			u32 pkg = sad_pkg(pvt->info.interleave_pkg, reg, j); +			if (j > 0 && sad_interl == pkg)  				break;  			edac_dbg(0, "SAD#%d, interleave #%d: %d\n", -				 n_sads, j, sad_pkg(reg, j)); +				 n_sads, j, pkg);  		}  	} @@ -777,7 +915,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)  	}  } -struct mem_ctl_info *get_mci_for_node_id(u8 node_id) +static struct mem_ctl_info *get_mci_for_node_id(u8 node_id)  {  	struct sbridge_dev *sbridge_dev; @@ -797,16 +935,17 @@ static int get_memory_error_data(struct mem_ctl_info *mci,  {  	struct mem_ctl_info	*new_mci;  	struct sbridge_pvt *pvt = mci->pvt_info; +	struct pci_dev		*pci_ha;  	int 			n_rir, n_sads, n_tads, sad_way, sck_xch;  	int			sad_interl, idx, base_ch;  	int			interleave_mode; -	unsigned		sad_interleave[MAX_INTERLEAVE]; +	unsigned		sad_interleave[pvt->info.max_interleave];  	u32			reg; -	u8			ch_way,sck_way; +	u8			ch_way, sck_way, pkg, sad_ha = 0;  	u32			tad_offset;  	u32			rir_way;  	u32			mb, kb; -	u64			ch_addr, offset, limit, prv = 0; +	u64			ch_addr, offset, limit = 0, prv = 0;  	/* @@ -828,8 +967,8 @@ static int get_memory_error_data(struct mem_ctl_info *mci,  	/*  	 * Step 1) Get socket  	 */ -	for (n_sads = 0; n_sads < MAX_SAD; n_sads++) { -		pci_read_config_dword(pvt->pci_sad0, dram_rule[n_sads], +	for (n_sads = 0; n_sads < pvt->info.max_sad; n_sads++) { +		pci_read_config_dword(pvt->pci_sad0, pvt->info.dram_rule[n_sads],  				      ®);  		if (!DRAM_RULE_ENABLE(reg)) @@ -844,53 +983,65 @@ static int get_memory_error_data(struct mem_ctl_info *mci,  			break;  		prv = limit;  	} -	if (n_sads == MAX_SAD) { +	if (n_sads == pvt->info.max_sad) {  		sprintf(msg, "Can't discover the memory socket");  		return -EINVAL;  	}  	*area_type = get_dram_attr(reg);  	interleave_mode = INTERLEAVE_MODE(reg); -	pci_read_config_dword(pvt->pci_sad0, interleave_list[n_sads], +	pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],  			      ®); -	sad_interl = sad_pkg(reg, 0); -	for (sad_way = 0; sad_way < 8; sad_way++) { -		if (sad_way > 0 && sad_interl == sad_pkg(reg, sad_way)) + +	if (pvt->info.type == SANDY_BRIDGE) { +		sad_interl = sad_pkg(pvt->info.interleave_pkg, reg, 0); +		for (sad_way = 0; sad_way < 8; sad_way++) { +			u32 pkg = sad_pkg(pvt->info.interleave_pkg, reg, sad_way); +			if (sad_way > 0 && sad_interl == pkg) +				break; +			sad_interleave[sad_way] = pkg; +			edac_dbg(0, "SAD interleave #%d: %d\n", +				 sad_way, sad_interleave[sad_way]); +		} +		edac_dbg(0, "mc#%d: Error detected on SAD#%d: address 0x%016Lx < 0x%016Lx, Interleave [%d:6]%s\n", +			 pvt->sbridge_dev->mc, +			 n_sads, +			 addr, +			 limit, +			 sad_way + 7, +			 !interleave_mode ? "" : "XOR[18:16]"); +		if (interleave_mode) +			idx = ((addr >> 6) ^ (addr >> 16)) & 7; +		else +			idx = (addr >> 6) & 7; +		switch (sad_way) { +		case 1: +			idx = 0;  			break; -		sad_interleave[sad_way] = sad_pkg(reg, sad_way); -		edac_dbg(0, "SAD interleave #%d: %d\n", -			 sad_way, sad_interleave[sad_way]); -	} -	edac_dbg(0, "mc#%d: Error detected on SAD#%d: address 0x%016Lx < 0x%016Lx, Interleave [%d:6]%s\n", -		 pvt->sbridge_dev->mc, -		 n_sads, -		 addr, -		 limit, -		 sad_way + 7, -		 interleave_mode ? "" : "XOR[18:16]"); -	if (interleave_mode) -		idx = ((addr >> 6) ^ (addr >> 16)) & 7; -	else +		case 2: +			idx = idx & 1; +			break; +		case 4: +			idx = idx & 3; +			break; +		case 8: +			break; +		default: +			sprintf(msg, "Can't discover socket interleave"); +			return -EINVAL; +		} +		*socket = sad_interleave[idx]; +		edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n", +			 idx, sad_way, *socket); +	} else { +		/* Ivy Bridge's SAD mode doesn't support XOR interleave mode */  		idx = (addr >> 6) & 7; -	switch (sad_way) { -	case 1: -		idx = 0; -		break; -	case 2: -		idx = idx & 1; -		break; -	case 4: -		idx = idx & 3; -		break; -	case 8: -		break; -	default: -		sprintf(msg, "Can't discover socket interleave"); -		return -EINVAL; +		pkg = sad_pkg(pvt->info.interleave_pkg, reg, idx); +		*socket = sad_pkg_socket(pkg); +		sad_ha = sad_pkg_ha(pkg); +		edac_dbg(0, "SAD interleave package: %d = CPU socket %d, HA %d\n", +			 idx, *socket, sad_ha);  	} -	*socket = sad_interleave[idx]; -	edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n", -		 idx, sad_way, *socket);  	/*  	 * Move to the proper node structure, in order to access the @@ -909,9 +1060,16 @@ static int get_memory_error_data(struct mem_ctl_info *mci,  	 * Step 2) Get memory channel  	 */  	prv = 0; +	if (pvt->info.type == SANDY_BRIDGE) +		pci_ha = pvt->pci_ha0; +	else { +		if (sad_ha) +			pci_ha = pvt->pci_ha1; +		else +			pci_ha = pvt->pci_ha0; +	}  	for (n_tads = 0; n_tads < MAX_TAD; n_tads++) { -		pci_read_config_dword(pvt->pci_ha0, tad_dram_rule[n_tads], -				      ®); +		pci_read_config_dword(pci_ha, tad_dram_rule[n_tads], ®);  		limit = TAD_LIMIT(reg);  		if (limit <= prv) {  			sprintf(msg, "Can't discover the memory channel"); @@ -921,14 +1079,13 @@ static int get_memory_error_data(struct mem_ctl_info *mci,  			break;  		prv = limit;  	} +	if (n_tads == MAX_TAD) { +		sprintf(msg, "Can't discover the memory channel"); +		return -EINVAL; +	} +  	ch_way = TAD_CH(reg) + 1;  	sck_way = TAD_SOCK(reg) + 1; -	/* -	 * FIXME: Is it right to always use channel 0 for offsets? -	 */ -	pci_read_config_dword(pvt->pci_tad[0], -				tad_ch_nilv_offset[n_tads], -				&tad_offset);  	if (ch_way == 3)  		idx = addr >> 6; @@ -958,6 +1115,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci,  	}  	*channel_mask = 1 << base_ch; +	pci_read_config_dword(pvt->pci_tad[base_ch], +				tad_ch_nilv_offset[n_tads], +				&tad_offset); +  	if (pvt->is_mirrored) {  		*channel_mask |= 1 << ((base_ch + 2) % 4);  		switch(ch_way) { @@ -1091,12 +1252,6 @@ static void sbridge_put_all_devices(void)  	}  } -/* - *	sbridge_get_all_devices	Find and perform 'get' operation on the MCH's - *			device/functions we want to reference for this driver - * - *			Need to 'get' device 16 func 1 and func 2 - */  static int sbridge_get_onedevice(struct pci_dev **prev,  				 u8 *num_mc,  				 const struct pci_id_table *table, @@ -1108,7 +1263,7 @@ static int sbridge_get_onedevice(struct pci_dev **prev,  	struct pci_dev *pdev = NULL;  	u8 bus = 0; -	sbridge_printk(KERN_INFO, +	sbridge_printk(KERN_DEBUG,  		"Seeking for: dev %02x.%d PCI ID %04x:%04x\n",  		dev_descr->dev, dev_descr->func,  		PCI_VENDOR_ID_INTEL, dev_descr->dev_id); @@ -1198,11 +1353,21 @@ static int sbridge_get_onedevice(struct pci_dev **prev,  	return 0;  } -static int sbridge_get_all_devices(u8 *num_mc) +/* + * sbridge_get_all_devices - Find and perform 'get' operation on the MCH's + *			     device/functions we want to reference for this driver. + *			     Need to 'get' device 16 func 1 and func 2. + * @num_mc: pointer to the memory controllers count, to be incremented in case + * 	    of success. + * @table: model specific table + * + * returns 0 in case of success or error code + */ +static int sbridge_get_all_devices(u8 *num_mc, +				   const struct pci_id_table *table)  {  	int i, rc;  	struct pci_dev *pdev = NULL; -	const struct pci_id_table *table = pci_dev_descr_sbridge_table;  	while (table && table->descr) {  		for (i = 0; i < table->n_devs; i++) { @@ -1226,8 +1391,8 @@ static int sbridge_get_all_devices(u8 *num_mc)  	return 0;  } -static int mci_bind_devs(struct mem_ctl_info *mci, -			 struct sbridge_dev *sbridge_dev) +static int sbridge_mci_bind_devs(struct mem_ctl_info *mci, +				 struct sbridge_dev *sbridge_dev)  {  	struct sbridge_pvt *pvt = mci->pvt_info;  	struct pci_dev *pdev; @@ -1255,7 +1420,7 @@ static int mci_bind_devs(struct mem_ctl_info *mci,  		case 13:  			switch (func) {  			case 6: -				pvt->pci_br = pdev; +				pvt->pci_br0 = pdev;  				break;  			default:  				goto error; @@ -1329,6 +1494,131 @@ error:  	return -EINVAL;  } +static int ibridge_mci_bind_devs(struct mem_ctl_info *mci, +				 struct sbridge_dev *sbridge_dev) +{ +	struct sbridge_pvt *pvt = mci->pvt_info; +	struct pci_dev *pdev, *tmp; +	int i, func, slot; +	bool mode_2ha = false; + +	tmp = pci_get_device(PCI_VENDOR_ID_INTEL, +			     PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, NULL); +	if (tmp) { +		mode_2ha = true; +		pci_dev_put(tmp); +	} + +	for (i = 0; i < sbridge_dev->n_devs; i++) { +		pdev = sbridge_dev->pdev[i]; +		if (!pdev) +			continue; +		slot = PCI_SLOT(pdev->devfn); +		func = PCI_FUNC(pdev->devfn); + +		switch (slot) { +		case 14: +			if (func == 0) { +				pvt->pci_ha0 = pdev; +				break; +			} +			goto error; +		case 15: +			switch (func) { +			case 0: +				pvt->pci_ta = pdev; +				break; +			case 1: +				pvt->pci_ras = pdev; +				break; +			case 4: +			case 5: +				/* if we have 2 HAs active, channels 2 and 3 +				 * are in other device */ +				if (mode_2ha) +					break; +				/* fall through */ +			case 2: +			case 3: +				pvt->pci_tad[func - 2] = pdev; +				break; +			default: +				goto error; +			} +			break; +		case 17: +			if (func == 4) { +				pvt->pci_ddrio = pdev; +				break; +			} else if (func == 0) { +				if (!mode_2ha) +					pvt->pci_ddrio = pdev; +				break; +			} +			goto error; +		case 22: +			switch (func) { +			case 0: +				pvt->pci_sad0 = pdev; +				break; +			case 1: +				pvt->pci_br0 = pdev; +				break; +			case 2: +				pvt->pci_br1 = pdev; +				break; +			default: +				goto error; +			} +			break; +		case 28: +			if (func == 0) { +				pvt->pci_ha1 = pdev; +				break; +			} +			goto error; +		case 29: +			/* we shouldn't have this device if we have just one +			 * HA present */ +			WARN_ON(!mode_2ha); +			if (func == 2 || func == 3) { +				pvt->pci_tad[func] = pdev; +				break; +			} +			goto error; +		default: +			goto error; +		} + +		edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n", +			 sbridge_dev->bus, +			 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), +			 pdev); +	} + +	/* Check if everything were registered */ +	if (!pvt->pci_sad0 || !pvt->pci_ha0 || !pvt->pci_br0 || +	    !pvt->pci_br1 || !pvt->pci_tad || !pvt->pci_ras  || +	    !pvt->pci_ta) +		goto enodev; + +	for (i = 0; i < NUM_CHANNELS; i++) { +		if (!pvt->pci_tad[i]) +			goto enodev; +	} +	return 0; + +enodev: +	sbridge_printk(KERN_ERR, "Some needed devices are missing\n"); +	return -ENODEV; + +error: +	sbridge_printk(KERN_ERR, +		       "Device %d, function %d is out of the expected range\n", +		       slot, func); +	return -EINVAL; +} +  /****************************************************************************  			Error check routines   ****************************************************************************/ @@ -1349,7 +1639,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,  	bool ripv = GET_BITFIELD(m->mcgstatus, 0, 0);  	bool overflow = GET_BITFIELD(m->status, 62, 62);  	bool uncorrected_error = GET_BITFIELD(m->status, 61, 61); -	bool recoverable = GET_BITFIELD(m->status, 56, 56); +	bool recoverable;  	u32 core_err_cnt = GET_BITFIELD(m->status, 38, 52);  	u32 mscod = GET_BITFIELD(m->status, 16, 31);  	u32 errcode = GET_BITFIELD(m->status, 0, 15); @@ -1360,6 +1650,11 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,  	int rc, dimm;  	char *area_type = NULL; +	if (pvt->info.type == IVY_BRIDGE) +		recoverable = true; +	else +		recoverable = GET_BITFIELD(m->status, 56, 56); +  	if (uncorrected_error) {  		if (ripv) {  			type = "FATAL"; @@ -1409,6 +1704,10 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,  		}  	} +	/* Only decode errors with an valid address (ADDRV) */ +	if (!GET_BITFIELD(m->status, 58, 58)) +		return; +  	rc = get_memory_error_data(mci, m->addr, &socket,  				   &channel_mask, &rank, &area_type, msg);  	if (rc < 0) @@ -1529,6 +1828,10 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val,  	struct mce *mce = (struct mce *)data;  	struct mem_ctl_info *mci;  	struct sbridge_pvt *pvt; +	char *type; + +	if (get_edac_report_status() == EDAC_REPORTING_DISABLED) +		return NOTIFY_DONE;  	mci = get_mci_for_node_id(mce->socketid);  	if (!mci) @@ -1544,17 +1847,23 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val,  	if ((mce->status & 0xefff) >> 7 != 1)  		return NOTIFY_DONE; -	printk("sbridge: HANDLING MCE MEMORY ERROR\n"); +	if (mce->mcgstatus & MCG_STATUS_MCIP) +		type = "Exception"; +	else +		type = "Event"; + +	sbridge_mc_printk(mci, KERN_DEBUG, "HANDLING MCE MEMORY ERROR\n"); -	printk("CPU %d: Machine Check Exception: %Lx Bank %d: %016Lx\n", -	       mce->extcpu, mce->mcgstatus, mce->bank, mce->status); -	printk("TSC %llx ", mce->tsc); -	printk("ADDR %llx ", mce->addr); -	printk("MISC %llx ", mce->misc); +	sbridge_mc_printk(mci, KERN_DEBUG, "CPU %d: Machine Check %s: %Lx " +			  "Bank %d: %016Lx\n", mce->extcpu, type, +			  mce->mcgstatus, mce->bank, mce->status); +	sbridge_mc_printk(mci, KERN_DEBUG, "TSC %llx ", mce->tsc); +	sbridge_mc_printk(mci, KERN_DEBUG, "ADDR %llx ", mce->addr); +	sbridge_mc_printk(mci, KERN_DEBUG, "MISC %llx ", mce->misc); -	printk("PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n", -		mce->cpuvendor, mce->cpuid, mce->time, -		mce->socketid, mce->apicid); +	sbridge_mc_printk(mci, KERN_DEBUG, "PROCESSOR %u:%x TIME %llu SOCKET " +			  "%u APIC %x\n", mce->cpuvendor, mce->cpuid, +			  mce->time, mce->socketid, mce->apicid);  	/* Only handle if it is the right mc controller */  	if (cpu_data(mce->cpu).phys_proc_id != pvt->sbridge_dev->mc) @@ -1614,11 +1923,12 @@ static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev)  	sbridge_dev->mci = NULL;  } -static int sbridge_register_mci(struct sbridge_dev *sbridge_dev) +static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)  {  	struct mem_ctl_info *mci;  	struct edac_mc_layer layers[2];  	struct sbridge_pvt *pvt; +	struct pci_dev *pdev = sbridge_dev->pdev[0];  	int rc;  	/* Check the number of active and not disabled channels */ @@ -1640,7 +1950,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)  		return -ENOMEM;  	edac_dbg(0, "MC: mci = %p, dev = %p\n", -		 mci, &sbridge_dev->pdev[0]->dev); +		 mci, &pdev->dev);  	pvt = mci->pvt_info;  	memset(pvt, 0, sizeof(*pvt)); @@ -1654,24 +1964,52 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)  	mci->edac_cap = EDAC_FLAG_NONE;  	mci->mod_name = "sbridge_edac.c";  	mci->mod_ver = SBRIDGE_REVISION; -	mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge Socket#%d", mci->mc_idx); -	mci->dev_name = pci_name(sbridge_dev->pdev[0]); +	mci->dev_name = pci_name(pdev);  	mci->ctl_page_to_phys = NULL;  	/* Set the function pointer to an actual operation function */  	mci->edac_check = sbridge_check_error; -	/* Store pci devices at mci for faster access */ -	rc = mci_bind_devs(mci, sbridge_dev); -	if (unlikely(rc < 0)) -		goto fail0; +	pvt->info.type = type; +	if (type == IVY_BRIDGE) { +		pvt->info.rankcfgr = IB_RANK_CFG_A; +		pvt->info.get_tolm = ibridge_get_tolm; +		pvt->info.get_tohm = ibridge_get_tohm; +		pvt->info.dram_rule = ibridge_dram_rule; +		pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); +		pvt->info.interleave_list = ibridge_interleave_list; +		pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); +		pvt->info.interleave_pkg = ibridge_interleave_pkg; +		mci->ctl_name = kasprintf(GFP_KERNEL, "Ivy Bridge Socket#%d", mci->mc_idx); + +		/* Store pci devices at mci for faster access */ +		rc = ibridge_mci_bind_devs(mci, sbridge_dev); +		if (unlikely(rc < 0)) +			goto fail0; +	} else { +		pvt->info.rankcfgr = SB_RANK_CFG_A; +		pvt->info.get_tolm = sbridge_get_tolm; +		pvt->info.get_tohm = sbridge_get_tohm; +		pvt->info.dram_rule = sbridge_dram_rule; +		pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule); +		pvt->info.interleave_list = sbridge_interleave_list; +		pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list); +		pvt->info.interleave_pkg = sbridge_interleave_pkg; +		mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge Socket#%d", mci->mc_idx); + +		/* Store pci devices at mci for faster access */ +		rc = sbridge_mci_bind_devs(mci, sbridge_dev); +		if (unlikely(rc < 0)) +			goto fail0; +	} +  	/* Get dimm basic config and the memory layout */  	get_dimm_config(mci);  	get_memory_layout(mci);  	/* record ptr to the generic device */ -	mci->pdev = &sbridge_dev->pdev[0]->dev; +	mci->pdev = &pdev->dev;  	/* add this new MC control structure to EDAC's list of MCs */  	if (unlikely(edac_mc_add_mc(mci))) { @@ -1702,6 +2040,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	int rc;  	u8 mc, num_mc = 0;  	struct sbridge_dev *sbridge_dev; +	enum type type;  	/* get the pci devices we want to reserve for our use */  	mutex_lock(&sbridge_edac_lock); @@ -1715,7 +2054,13 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	}  	probed++; -	rc = sbridge_get_all_devices(&num_mc); +	if (pdev->device == PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA) { +		rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table); +		type = IVY_BRIDGE; +	} else { +		rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table); +		type = SANDY_BRIDGE; +	}  	if (unlikely(rc < 0))  		goto fail0;  	mc = 0; @@ -1724,7 +2069,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)  		edac_dbg(0, "Registering MC#%d (%d of %d)\n",  			 mc, mc + 1, num_mc);  		sbridge_dev->mc = mc++; -		rc = sbridge_register_mci(sbridge_dev); +		rc = sbridge_register_mci(sbridge_dev, type);  		if (unlikely(rc < 0))  			goto fail1;  	} @@ -1807,9 +2152,10 @@ static int __init sbridge_init(void)  	opstate_init();  	pci_rc = pci_register_driver(&sbridge_driver); -  	if (pci_rc >= 0) {  		mce_register_decode_chain(&sbridge_mce_dec); +		if (get_edac_report_status() == EDAC_REPORTING_DISABLED) +			sbridge_printk(KERN_WARNING, "Loading driver, error reporting disabled.\n");  		return 0;  	} @@ -1837,7 +2183,7 @@ module_param(edac_op_state, int, 0444);  MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");  MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); +MODULE_AUTHOR("Mauro Carvalho Chehab");  MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); -MODULE_DESCRIPTION("MC Driver for Intel Sandy Bridge memory controllers - " +MODULE_DESCRIPTION("MC Driver for Intel Sandy Bridge and Ivy Bridge memory controllers - "  		   SBRIDGE_REVISION); diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c index 1a4df82376b..4891b450830 100644 --- a/drivers/edac/x38_edac.c +++ b/drivers/edac/x38_edac.c @@ -448,7 +448,7 @@ static void x38_remove_one(struct pci_dev *pdev)  	edac_mc_free(mci);  } -static DEFINE_PCI_DEVICE_TABLE(x38_pci_tbl) = { +static const struct pci_device_id x38_pci_tbl[] = {  	{  	 PCI_VEND_DEV(INTEL, X38_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,  	 X38},  | 
