diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-11 19:21:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-11 19:21:12 -0400 |
commit | d9b44fe30fb8637b23f804eab2e7afbce129d714 (patch) | |
tree | fdf3a50bf173c4914f542be9c6ef483856af33e4 | |
parent | 9ebd051a7d5aa7b0ce813c3c2e5b9c851e7774b9 (diff) | |
parent | 12f0721c5a70408e86257c5c99605cf743cd44c6 (diff) |
Merge tag 'edac/v4.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac
Pull edac updates from Mauro Carvalho Chehab:
"Two EDAC fixes for Intel systems (Haswell and Ivy Bridge)"
* tag 'edac/v4.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac:
sb_edac: correctly fetch DIMM width on Ivy Bridge and Haswell
sb_edac: look harder for DDRIO on Haswell systems
-rw-r--r-- | drivers/edac/sb_edac.c | 72 |
1 files changed, 60 insertions, 12 deletions
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index ca7831168298..cf1268ddef0c 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c | |||
@@ -280,6 +280,7 @@ struct sbridge_info { | |||
280 | u8 max_interleave; | 280 | u8 max_interleave; |
281 | u8 (*get_node_id)(struct sbridge_pvt *pvt); | 281 | u8 (*get_node_id)(struct sbridge_pvt *pvt); |
282 | enum mem_type (*get_memory_type)(struct sbridge_pvt *pvt); | 282 | enum mem_type (*get_memory_type)(struct sbridge_pvt *pvt); |
283 | enum dev_type (*get_width)(struct sbridge_pvt *pvt, u32 mtr); | ||
283 | struct pci_dev *pci_vtd; | 284 | struct pci_dev *pci_vtd; |
284 | }; | 285 | }; |
285 | 286 | ||
@@ -471,6 +472,9 @@ static const struct pci_id_table pci_dev_descr_ibridge_table[] = { | |||
471 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2 0x2f6c | 472 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2 0x2f6c |
472 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3 0x2f6d | 473 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3 0x2f6d |
473 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0 0x2fbd | 474 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0 0x2fbd |
475 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO1 0x2fbf | ||
476 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO2 0x2fb9 | ||
477 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO3 0x2fbb | ||
474 | static const struct pci_id_descr pci_dev_descr_haswell[] = { | 478 | static const struct pci_id_descr pci_dev_descr_haswell[] = { |
475 | /* first item must be the HA */ | 479 | /* first item must be the HA */ |
476 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0, 0) }, | 480 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0, 0) }, |
@@ -488,6 +492,9 @@ static const struct pci_id_descr pci_dev_descr_haswell[] = { | |||
488 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3, 1) }, | 492 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3, 1) }, |
489 | 493 | ||
490 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0, 1) }, | 494 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0, 1) }, |
495 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO1, 1) }, | ||
496 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO2, 1) }, | ||
497 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO3, 1) }, | ||
491 | 498 | ||
492 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA, 1) }, | 499 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA, 1) }, |
493 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_THERMAL, 1) }, | 500 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_THERMAL, 1) }, |
@@ -762,6 +769,49 @@ out: | |||
762 | return mtype; | 769 | return mtype; |
763 | } | 770 | } |
764 | 771 | ||
772 | static enum dev_type sbridge_get_width(struct sbridge_pvt *pvt, u32 mtr) | ||
773 | { | ||
774 | /* there's no way to figure out */ | ||
775 | return DEV_UNKNOWN; | ||
776 | } | ||
777 | |||
778 | static enum dev_type __ibridge_get_width(u32 mtr) | ||
779 | { | ||
780 | enum dev_type type; | ||
781 | |||
782 | switch (mtr) { | ||
783 | case 3: | ||
784 | type = DEV_UNKNOWN; | ||
785 | break; | ||
786 | case 2: | ||
787 | type = DEV_X16; | ||
788 | break; | ||
789 | case 1: | ||
790 | type = DEV_X8; | ||
791 | break; | ||
792 | case 0: | ||
793 | type = DEV_X4; | ||
794 | break; | ||
795 | } | ||
796 | |||
797 | return type; | ||
798 | } | ||
799 | |||
800 | static enum dev_type ibridge_get_width(struct sbridge_pvt *pvt, u32 mtr) | ||
801 | { | ||
802 | /* | ||
803 | * ddr3_width on the documentation but also valid for DDR4 on | ||
804 | * Haswell | ||
805 | */ | ||
806 | return __ibridge_get_width(GET_BITFIELD(mtr, 7, 8)); | ||
807 | } | ||
808 | |||
809 | static enum dev_type broadwell_get_width(struct sbridge_pvt *pvt, u32 mtr) | ||
810 | { | ||
811 | /* ddr3_width on the documentation but also valid for DDR4 */ | ||
812 | return __ibridge_get_width(GET_BITFIELD(mtr, 8, 9)); | ||
813 | } | ||
814 | |||
765 | static u8 get_node_id(struct sbridge_pvt *pvt) | 815 | static u8 get_node_id(struct sbridge_pvt *pvt) |
766 | { | 816 | { |
767 | u32 reg; | 817 | u32 reg; |
@@ -966,17 +1016,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
966 | 1016 | ||
967 | dimm->nr_pages = npages; | 1017 | dimm->nr_pages = npages; |
968 | dimm->grain = 32; | 1018 | dimm->grain = 32; |
969 | switch (banks) { | 1019 | dimm->dtype = pvt->info.get_width(pvt, mtr); |
970 | case 16: | ||
971 | dimm->dtype = DEV_X16; | ||
972 | break; | ||
973 | case 8: | ||
974 | dimm->dtype = DEV_X8; | ||
975 | break; | ||
976 | case 4: | ||
977 | dimm->dtype = DEV_X4; | ||
978 | break; | ||
979 | } | ||
980 | dimm->mtype = mtype; | 1020 | dimm->mtype = mtype; |
981 | dimm->edac_mode = mode; | 1021 | dimm->edac_mode = mode; |
982 | snprintf(dimm->label, sizeof(dimm->label), | 1022 | snprintf(dimm->label, sizeof(dimm->label), |
@@ -1869,7 +1909,11 @@ static int haswell_mci_bind_devs(struct mem_ctl_info *mci, | |||
1869 | } | 1909 | } |
1870 | break; | 1910 | break; |
1871 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0: | 1911 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0: |
1872 | pvt->pci_ddrio = pdev; | 1912 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO1: |
1913 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO2: | ||
1914 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO3: | ||
1915 | if (!pvt->pci_ddrio) | ||
1916 | pvt->pci_ddrio = pdev; | ||
1873 | break; | 1917 | break; |
1874 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1: | 1918 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1: |
1875 | pvt->pci_ha1 = pdev; | 1919 | pvt->pci_ha1 = pdev; |
@@ -2361,6 +2405,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
2361 | pvt->info.interleave_list = ibridge_interleave_list; | 2405 | pvt->info.interleave_list = ibridge_interleave_list; |
2362 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); | 2406 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); |
2363 | pvt->info.interleave_pkg = ibridge_interleave_pkg; | 2407 | pvt->info.interleave_pkg = ibridge_interleave_pkg; |
2408 | pvt->info.get_width = ibridge_get_width; | ||
2364 | mci->ctl_name = kasprintf(GFP_KERNEL, "Ivy Bridge Socket#%d", mci->mc_idx); | 2409 | mci->ctl_name = kasprintf(GFP_KERNEL, "Ivy Bridge Socket#%d", mci->mc_idx); |
2365 | 2410 | ||
2366 | /* Store pci devices at mci for faster access */ | 2411 | /* Store pci devices at mci for faster access */ |
@@ -2380,6 +2425,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
2380 | pvt->info.interleave_list = sbridge_interleave_list; | 2425 | pvt->info.interleave_list = sbridge_interleave_list; |
2381 | pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list); | 2426 | pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list); |
2382 | pvt->info.interleave_pkg = sbridge_interleave_pkg; | 2427 | pvt->info.interleave_pkg = sbridge_interleave_pkg; |
2428 | pvt->info.get_width = sbridge_get_width; | ||
2383 | mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge Socket#%d", mci->mc_idx); | 2429 | mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge Socket#%d", mci->mc_idx); |
2384 | 2430 | ||
2385 | /* Store pci devices at mci for faster access */ | 2431 | /* Store pci devices at mci for faster access */ |
@@ -2399,6 +2445,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
2399 | pvt->info.interleave_list = ibridge_interleave_list; | 2445 | pvt->info.interleave_list = ibridge_interleave_list; |
2400 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); | 2446 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); |
2401 | pvt->info.interleave_pkg = ibridge_interleave_pkg; | 2447 | pvt->info.interleave_pkg = ibridge_interleave_pkg; |
2448 | pvt->info.get_width = ibridge_get_width; | ||
2402 | mci->ctl_name = kasprintf(GFP_KERNEL, "Haswell Socket#%d", mci->mc_idx); | 2449 | mci->ctl_name = kasprintf(GFP_KERNEL, "Haswell Socket#%d", mci->mc_idx); |
2403 | 2450 | ||
2404 | /* Store pci devices at mci for faster access */ | 2451 | /* Store pci devices at mci for faster access */ |
@@ -2418,6 +2465,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
2418 | pvt->info.interleave_list = ibridge_interleave_list; | 2465 | pvt->info.interleave_list = ibridge_interleave_list; |
2419 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); | 2466 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); |
2420 | pvt->info.interleave_pkg = ibridge_interleave_pkg; | 2467 | pvt->info.interleave_pkg = ibridge_interleave_pkg; |
2468 | pvt->info.get_width = broadwell_get_width; | ||
2421 | mci->ctl_name = kasprintf(GFP_KERNEL, "Broadwell Socket#%d", mci->mc_idx); | 2469 | mci->ctl_name = kasprintf(GFP_KERNEL, "Broadwell Socket#%d", mci->mc_idx); |
2422 | 2470 | ||
2423 | /* Store pci devices at mci for faster access */ | 2471 | /* Store pci devices at mci for faster access */ |