Messages in this thread | | | Date | Wed, 30 Oct 2013 15:25:40 -0200 | From | Mauro Carvalho Chehab <> | Subject | Re: [PATCH 12/12] sb_edac: add support for Ivy Bridge |
| |
Em Wed, 30 Oct 2013 12:27:06 -0400 Aristeu Rozanski <arozansk@redhat.com> escreveu:
> Since Ivy Bridge memory controller is very similar to Sandy Bridge, it's > wiser to modify sb_edac to support both instead of creating another > driver.
Nice patch! Yeah, it is a way better to reuse the existing driver than to create another one.
Provided that you fix the minor issue with the PCI IDs, for patches 1 and 12:
Reviewed-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > Signed-off-by: Aristeu Rozanski <arozansk@redhat.com> > --- > drivers/edac/sb_edac.c | 447 ++++++++++++++++++++++++++++++++++++++++-------- > 1 files changed, 377 insertions(+), 70 deletions(-) > > diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c > index 3c2f52b..09bf76f 100644 > --- a/drivers/edac/sb_edac.c > +++ b/drivers/edac/sb_edac.c > @@ -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" > > /* > @@ -71,6 +71,14 @@ static const u32 sbridge_dram_rule[] = { > 0xa8, 0xb0, 0xb8, 0xc0, 0xc8, > }; > > +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) > #define INTERLEAVE_MODE(reg) GET_BITFIELD(reg, 1, 1) > @@ -95,6 +103,13 @@ static const u32 sbridge_interleave_list[] = { > 0xac, 0xb4, 0xbc, 0xc4, 0xcc, > }; > > +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; > @@ -111,6 +126,17 @@ static const struct interleave_pkg sbridge_interleave_pkg[] = { > { 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) > { > @@ -235,6 +261,8 @@ static const u32 correrrthrsld[] = { > > #define SB_RANK_CFG_A 0x0328 > > +#define IB_RANK_CFG_A 0x0320 > + > #define IS_RDIMM_ENABLED(reg) GET_BITFIELD(reg, 11, 11) > > /* > @@ -244,8 +272,14 @@ 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 { > + enum type type; > u32 mcmtr; > u32 rankcfgr; > u64 (*get_tolm)(struct sbridge_pvt *pvt); > @@ -285,8 +319,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_br0; > + 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; > @@ -344,11 +379,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
As mentioned on patch 1, please either keep all PCI IDs here, or move them all to pci_ids.h.
> + > +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) = { > {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. */ > }; > > @@ -455,6 +554,35 @@ static u64 sbridge_get_tohm(struct sbridge_pvt *pvt) > 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 > ****************************************************************************/ > @@ -517,8 +645,6 @@ static int get_dimm_config(struct mem_ctl_info *mci) > enum edac_type mode; > enum mem_type mtype; > > - pvt->info.rankcfgr = SB_RANK_CFG_A; > - > pci_read_config_dword(pvt->pci_br0, SAD_TARGET, ®); > pvt->sbridge_dev->source_id = SOURCE_ID(reg); > > @@ -793,12 +919,13 @@ 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[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; > @@ -849,45 +976,56 @@ static int get_memory_error_data(struct mem_ctl_info *mci, > > pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads], > ®); > - 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) > + > + 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] = 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 > + 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 > @@ -906,9 +1044,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"); > @@ -918,14 +1063,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; > @@ -955,6 +1099,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) { > @@ -1330,6 +1478,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 > ****************************************************************************/ > @@ -1350,7 +1623,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); > @@ -1361,6 +1634,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"; > @@ -1619,11 +1897,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 */ > @@ -1645,7 +1924,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)); > @@ -1659,31 +1938,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; > - 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; > > /* Set the function pointer to an actual operation function */ > mci->edac_check = sbridge_check_error; > > - /* Store pci devices at mci for faster access */ > - rc = sbridge_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))) { > @@ -1714,6 +2014,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); > @@ -1727,7 +2028,13 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) > } > probed++; > > - rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table); > + 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; > @@ -1736,7 +2043,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; > } > @@ -1851,5 +2158,5 @@ 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("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);
| |