diff options
author | Tony Luck <tony.luck@intel.com> | 2014-12-02 12:27:30 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2014-12-02 13:46:08 -0500 |
commit | 1f39581a9a7a3387f40f379478d8827878c57530 (patch) | |
tree | 28d68867ff842a75fe73b4cf42b2edafa7375dfb /drivers/edac/sb_edac.c | |
parent | f7cf2a22a2896d3b3595b71d7936b6d7a3316b00 (diff) |
sb_edac: Add support for Broadwell-DE processor
Broadwell-DE is the microserver version of next generation Xeon
processors. A whole bunch of new PCIe device ids, but otherwise
pretty much the same as Haswell.
Acked-by: Aristeu Rozanski <aris@redhat.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/edac/sb_edac.c')
-rw-r--r-- | drivers/edac/sb_edac.c | 163 |
1 files changed, 157 insertions, 6 deletions
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index ead0bf9a5d2d..993e8b61c4b2 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c | |||
@@ -262,6 +262,7 @@ enum type { | |||
262 | SANDY_BRIDGE, | 262 | SANDY_BRIDGE, |
263 | IVY_BRIDGE, | 263 | IVY_BRIDGE, |
264 | HASWELL, | 264 | HASWELL, |
265 | BROADWELL, | ||
265 | }; | 266 | }; |
266 | 267 | ||
267 | struct sbridge_pvt; | 268 | struct sbridge_pvt; |
@@ -446,7 +447,7 @@ static const struct pci_id_table pci_dev_descr_ibridge_table[] = { | |||
446 | * - each SMI channel interfaces with a scalable memory buffer | 447 | * - each SMI channel interfaces with a scalable memory buffer |
447 | * - each scalable memory buffer supports 4 DDR3/DDR4 channels, 3 DPC | 448 | * - each scalable memory buffer supports 4 DDR3/DDR4 channels, 3 DPC |
448 | */ | 449 | */ |
449 | #define HASWELL_DDRCRCLKCONTROLS 0xa10 | 450 | #define HASWELL_DDRCRCLKCONTROLS 0xa10 /* Ditto on Broadwell */ |
450 | #define HASWELL_HASYSDEFEATURE2 0x84 | 451 | #define HASWELL_HASYSDEFEATURE2 0x84 |
451 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC 0x2f28 | 452 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC 0x2f28 |
452 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0 0x2fa0 | 453 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0 0x2fa0 |
@@ -498,12 +499,53 @@ static const struct pci_id_table pci_dev_descr_haswell_table[] = { | |||
498 | }; | 499 | }; |
499 | 500 | ||
500 | /* | 501 | /* |
502 | * Broadwell support | ||
503 | * | ||
504 | * DE processor: | ||
505 | * - 1 IMC | ||
506 | * - 2 DDR3 channels, 2 DPC per channel | ||
507 | */ | ||
508 | #define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_VTD_MISC 0x6f28 | ||
509 | #define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0 0x6fa0 | ||
510 | #define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA 0x6fa8 | ||
511 | #define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_THERMAL 0x6f71 | ||
512 | #define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD0 0x6ffc | ||
513 | #define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD1 0x6ffd | ||
514 | #define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD0 0x6faa | ||
515 | #define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD1 0x6fab | ||
516 | #define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD2 0x6fac | ||
517 | #define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD3 0x6fad | ||
518 | #define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_DDRIO0 0x6faf | ||
519 | |||
520 | static const struct pci_id_descr pci_dev_descr_broadwell[] = { | ||
521 | /* first item must be the HA */ | ||
522 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0, 0) }, | ||
523 | |||
524 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD0, 0) }, | ||
525 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD1, 0) }, | ||
526 | |||
527 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA, 0) }, | ||
528 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_THERMAL, 0) }, | ||
529 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD0, 0) }, | ||
530 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD1, 0) }, | ||
531 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD2, 0) }, | ||
532 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD3, 0) }, | ||
533 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_DDRIO0, 1) }, | ||
534 | }; | ||
535 | |||
536 | static const struct pci_id_table pci_dev_descr_broadwell_table[] = { | ||
537 | PCI_ID_TABLE_ENTRY(pci_dev_descr_broadwell), | ||
538 | {0,} /* 0 terminated list. */ | ||
539 | }; | ||
540 | |||
541 | /* | ||
501 | * pci_device_id table for which devices we are looking for | 542 | * pci_device_id table for which devices we are looking for |
502 | */ | 543 | */ |
503 | static const struct pci_device_id sbridge_pci_tbl[] = { | 544 | static const struct pci_device_id sbridge_pci_tbl[] = { |
504 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0)}, | 545 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0)}, |
505 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)}, | 546 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)}, |
506 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0)}, | 547 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0)}, |
548 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0)}, | ||
507 | {0,} /* 0 terminated list. */ | 549 | {0,} /* 0 terminated list. */ |
508 | }; | 550 | }; |
509 | 551 | ||
@@ -768,12 +810,22 @@ static int check_if_ecc_is_active(const u8 bus, enum type type) | |||
768 | struct pci_dev *pdev = NULL; | 810 | struct pci_dev *pdev = NULL; |
769 | u32 mcmtr, id; | 811 | u32 mcmtr, id; |
770 | 812 | ||
771 | if (type == IVY_BRIDGE) | 813 | switch (type) { |
814 | case IVY_BRIDGE: | ||
772 | id = PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA; | 815 | id = PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA; |
773 | else if (type == HASWELL) | 816 | break; |
817 | case HASWELL: | ||
774 | id = PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA; | 818 | id = PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA; |
775 | else | 819 | break; |
820 | case SANDY_BRIDGE: | ||
776 | id = PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA; | 821 | id = PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA; |
822 | break; | ||
823 | case BROADWELL: | ||
824 | id = PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA; | ||
825 | break; | ||
826 | default: | ||
827 | return -ENODEV; | ||
828 | } | ||
777 | 829 | ||
778 | pdev = get_pdev_same_bus(bus, id); | 830 | pdev = get_pdev_same_bus(bus, id); |
779 | if (!pdev) { | 831 | if (!pdev) { |
@@ -801,7 +853,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
801 | enum edac_type mode; | 853 | enum edac_type mode; |
802 | enum mem_type mtype; | 854 | enum mem_type mtype; |
803 | 855 | ||
804 | if (pvt->info.type == HASWELL) | 856 | if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL) |
805 | pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, ®); | 857 | pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, ®); |
806 | else | 858 | else |
807 | pci_read_config_dword(pvt->pci_br0, SAD_TARGET, ®); | 859 | pci_read_config_dword(pvt->pci_br0, SAD_TARGET, ®); |
@@ -1182,7 +1234,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
1182 | *socket = sad_interleave[idx]; | 1234 | *socket = sad_interleave[idx]; |
1183 | edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n", | 1235 | edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n", |
1184 | idx, sad_way, *socket); | 1236 | idx, sad_way, *socket); |
1185 | } else if (pvt->info.type == HASWELL) { | 1237 | } else if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL) { |
1186 | int bits, a7mode = A7MODE(dram_rule); | 1238 | int bits, a7mode = A7MODE(dram_rule); |
1187 | 1239 | ||
1188 | if (a7mode) { | 1240 | if (a7mode) { |
@@ -1831,6 +1883,82 @@ enodev: | |||
1831 | return -ENODEV; | 1883 | return -ENODEV; |
1832 | } | 1884 | } |
1833 | 1885 | ||
1886 | static int broadwell_mci_bind_devs(struct mem_ctl_info *mci, | ||
1887 | struct sbridge_dev *sbridge_dev) | ||
1888 | { | ||
1889 | struct sbridge_pvt *pvt = mci->pvt_info; | ||
1890 | struct pci_dev *pdev; | ||
1891 | int i; | ||
1892 | |||
1893 | /* there's only one device per system; not tied to any bus */ | ||
1894 | if (pvt->info.pci_vtd == NULL) | ||
1895 | /* result will be checked later */ | ||
1896 | pvt->info.pci_vtd = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
1897 | PCI_DEVICE_ID_INTEL_BROADWELL_IMC_VTD_MISC, | ||
1898 | NULL); | ||
1899 | |||
1900 | for (i = 0; i < sbridge_dev->n_devs; i++) { | ||
1901 | pdev = sbridge_dev->pdev[i]; | ||
1902 | if (!pdev) | ||
1903 | continue; | ||
1904 | |||
1905 | switch (pdev->device) { | ||
1906 | case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD0: | ||
1907 | pvt->pci_sad0 = pdev; | ||
1908 | break; | ||
1909 | case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD1: | ||
1910 | pvt->pci_sad1 = pdev; | ||
1911 | break; | ||
1912 | case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0: | ||
1913 | pvt->pci_ha0 = pdev; | ||
1914 | break; | ||
1915 | case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA: | ||
1916 | pvt->pci_ta = pdev; | ||
1917 | break; | ||
1918 | case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_THERMAL: | ||
1919 | pvt->pci_ras = pdev; | ||
1920 | break; | ||
1921 | case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD0: | ||
1922 | pvt->pci_tad[0] = pdev; | ||
1923 | break; | ||
1924 | case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD1: | ||
1925 | pvt->pci_tad[1] = pdev; | ||
1926 | break; | ||
1927 | case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD2: | ||
1928 | pvt->pci_tad[2] = pdev; | ||
1929 | break; | ||
1930 | case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD3: | ||
1931 | pvt->pci_tad[3] = pdev; | ||
1932 | break; | ||
1933 | case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_DDRIO0: | ||
1934 | pvt->pci_ddrio = pdev; | ||
1935 | break; | ||
1936 | default: | ||
1937 | break; | ||
1938 | } | ||
1939 | |||
1940 | edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n", | ||
1941 | sbridge_dev->bus, | ||
1942 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), | ||
1943 | pdev); | ||
1944 | } | ||
1945 | |||
1946 | /* Check if everything were registered */ | ||
1947 | if (!pvt->pci_sad0 || !pvt->pci_ha0 || !pvt->pci_sad1 || | ||
1948 | !pvt->pci_ras || !pvt->pci_ta || !pvt->info.pci_vtd) | ||
1949 | goto enodev; | ||
1950 | |||
1951 | for (i = 0; i < NUM_CHANNELS; i++) { | ||
1952 | if (!pvt->pci_tad[i]) | ||
1953 | goto enodev; | ||
1954 | } | ||
1955 | return 0; | ||
1956 | |||
1957 | enodev: | ||
1958 | sbridge_printk(KERN_ERR, "Some needed devices are missing\n"); | ||
1959 | return -ENODEV; | ||
1960 | } | ||
1961 | |||
1834 | /**************************************************************************** | 1962 | /**************************************************************************** |
1835 | Error check routines | 1963 | Error check routines |
1836 | ****************************************************************************/ | 1964 | ****************************************************************************/ |
@@ -2243,6 +2371,25 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
2243 | if (unlikely(rc < 0)) | 2371 | if (unlikely(rc < 0)) |
2244 | goto fail0; | 2372 | goto fail0; |
2245 | break; | 2373 | break; |
2374 | case BROADWELL: | ||
2375 | /* rankcfgr isn't used */ | ||
2376 | pvt->info.get_tolm = haswell_get_tolm; | ||
2377 | pvt->info.get_tohm = haswell_get_tohm; | ||
2378 | pvt->info.dram_rule = ibridge_dram_rule; | ||
2379 | pvt->info.get_memory_type = haswell_get_memory_type; | ||
2380 | pvt->info.get_node_id = haswell_get_node_id; | ||
2381 | pvt->info.rir_limit = haswell_rir_limit; | ||
2382 | pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); | ||
2383 | pvt->info.interleave_list = ibridge_interleave_list; | ||
2384 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); | ||
2385 | pvt->info.interleave_pkg = ibridge_interleave_pkg; | ||
2386 | mci->ctl_name = kasprintf(GFP_KERNEL, "Broadwell Socket#%d", mci->mc_idx); | ||
2387 | |||
2388 | /* Store pci devices at mci for faster access */ | ||
2389 | rc = broadwell_mci_bind_devs(mci, sbridge_dev); | ||
2390 | if (unlikely(rc < 0)) | ||
2391 | goto fail0; | ||
2392 | break; | ||
2246 | } | 2393 | } |
2247 | 2394 | ||
2248 | /* Get dimm basic config and the memory layout */ | 2395 | /* Get dimm basic config and the memory layout */ |
@@ -2308,6 +2455,10 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
2308 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_haswell_table); | 2455 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_haswell_table); |
2309 | type = HASWELL; | 2456 | type = HASWELL; |
2310 | break; | 2457 | break; |
2458 | case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0: | ||
2459 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_broadwell_table); | ||
2460 | type = BROADWELL; | ||
2461 | break; | ||
2311 | } | 2462 | } |
2312 | if (unlikely(rc < 0)) | 2463 | if (unlikely(rc < 0)) |
2313 | goto fail0; | 2464 | goto fail0; |