diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-11 14:58:50 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-11 14:58:50 -0500 |
| commit | 709d9f09b6aee5828cb8f168f63030608176cd0e (patch) | |
| tree | feb2690c528eee4cf91885dfe4e4e7e889810c12 /drivers | |
| parent | 2183a58803c2bbd87c2d0057eed6779ec4718d4d (diff) | |
| parent | fec53af531dd040e41fe358abe00b33747af2688 (diff) | |
Merge tag 'edac/v3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac
Pull edac updates from Mauro Carvalho Chehab:
- Broadwell-DE support on sb-edac driver
- Some fixes at sb-edac driver
* tag 'edac/v3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac:
sb_edac: Fix typo computing number of banks
sb_edac: Add support for Broadwell-DE processor
sb_edac: Fix discovery of top-of-low-memory for Haswell
sb_edac: Fix erroneous bytes->gigabytes conversion
sb_edac: Fix off-by-one error in number of channels
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/edac/edac_mc_sysfs.c | 2 | ||||
| -rw-r--r-- | drivers/edac/sb_edac.c | 208 |
2 files changed, 182 insertions, 28 deletions
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index a6cd36100663..670d2829c547 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c | |||
| @@ -372,7 +372,7 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci, | |||
| 372 | { | 372 | { |
| 373 | int err, chan; | 373 | int err, chan; |
| 374 | 374 | ||
| 375 | if (csrow->nr_channels >= EDAC_NR_CHANNELS) | 375 | if (csrow->nr_channels > EDAC_NR_CHANNELS) |
| 376 | return -ENODEV; | 376 | return -ENODEV; |
| 377 | 377 | ||
| 378 | csrow->dev.type = &csrow_attr_type; | 378 | csrow->dev.type = &csrow_attr_type; |
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index e9bb1af67c8d..63aa6730e89e 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c | |||
| @@ -135,6 +135,7 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg, | |||
| 135 | 135 | ||
| 136 | #define TOLM 0x80 | 136 | #define TOLM 0x80 |
| 137 | #define TOHM 0x84 | 137 | #define TOHM 0x84 |
| 138 | #define HASWELL_TOLM 0xd0 | ||
| 138 | #define HASWELL_TOHM_0 0xd4 | 139 | #define HASWELL_TOHM_0 0xd4 |
| 139 | #define HASWELL_TOHM_1 0xd8 | 140 | #define HASWELL_TOHM_1 0xd8 |
| 140 | 141 | ||
| @@ -261,6 +262,7 @@ enum type { | |||
| 261 | SANDY_BRIDGE, | 262 | SANDY_BRIDGE, |
| 262 | IVY_BRIDGE, | 263 | IVY_BRIDGE, |
| 263 | HASWELL, | 264 | HASWELL, |
| 265 | BROADWELL, | ||
| 264 | }; | 266 | }; |
| 265 | 267 | ||
| 266 | struct sbridge_pvt; | 268 | struct sbridge_pvt; |
| @@ -445,7 +447,7 @@ static const struct pci_id_table pci_dev_descr_ibridge_table[] = { | |||
| 445 | * - each SMI channel interfaces with a scalable memory buffer | 447 | * - each SMI channel interfaces with a scalable memory buffer |
| 446 | * - each scalable memory buffer supports 4 DDR3/DDR4 channels, 3 DPC | 448 | * - each scalable memory buffer supports 4 DDR3/DDR4 channels, 3 DPC |
| 447 | */ | 449 | */ |
| 448 | #define HASWELL_DDRCRCLKCONTROLS 0xa10 | 450 | #define HASWELL_DDRCRCLKCONTROLS 0xa10 /* Ditto on Broadwell */ |
| 449 | #define HASWELL_HASYSDEFEATURE2 0x84 | 451 | #define HASWELL_HASYSDEFEATURE2 0x84 |
| 450 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC 0x2f28 | 452 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC 0x2f28 |
| 451 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0 0x2fa0 | 453 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0 0x2fa0 |
| @@ -497,12 +499,53 @@ static const struct pci_id_table pci_dev_descr_haswell_table[] = { | |||
| 497 | }; | 499 | }; |
| 498 | 500 | ||
| 499 | /* | 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 | /* | ||
| 500 | * pci_device_id table for which devices we are looking for | 542 | * pci_device_id table for which devices we are looking for |
| 501 | */ | 543 | */ |
| 502 | static const struct pci_device_id sbridge_pci_tbl[] = { | 544 | static const struct pci_device_id sbridge_pci_tbl[] = { |
| 503 | {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)}, |
| 504 | {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)}, |
| 505 | {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)}, | ||
| 506 | {0,} /* 0 terminated list. */ | 549 | {0,} /* 0 terminated list. */ |
| 507 | }; | 550 | }; |
| 508 | 551 | ||
| @@ -706,8 +749,8 @@ static u64 haswell_get_tolm(struct sbridge_pvt *pvt) | |||
| 706 | { | 749 | { |
| 707 | u32 reg; | 750 | u32 reg; |
| 708 | 751 | ||
| 709 | pci_read_config_dword(pvt->info.pci_vtd, TOLM, ®); | 752 | pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOLM, ®); |
| 710 | return (GET_BITFIELD(reg, 26, 31) << 26) | 0x1ffffff; | 753 | return (GET_BITFIELD(reg, 26, 31) << 26) | 0x3ffffff; |
| 711 | } | 754 | } |
| 712 | 755 | ||
| 713 | static u64 haswell_get_tohm(struct sbridge_pvt *pvt) | 756 | static u64 haswell_get_tohm(struct sbridge_pvt *pvt) |
| @@ -767,12 +810,22 @@ static int check_if_ecc_is_active(const u8 bus, enum type type) | |||
| 767 | struct pci_dev *pdev = NULL; | 810 | struct pci_dev *pdev = NULL; |
| 768 | u32 mcmtr, id; | 811 | u32 mcmtr, id; |
| 769 | 812 | ||
| 770 | if (type == IVY_BRIDGE) | 813 | switch (type) { |
| 814 | case IVY_BRIDGE: | ||
| 771 | id = PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA; | 815 | id = PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA; |
| 772 | else if (type == HASWELL) | 816 | break; |
| 817 | case HASWELL: | ||
| 773 | id = PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA; | 818 | id = PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA; |
| 774 | else | 819 | break; |
| 820 | case SANDY_BRIDGE: | ||
| 775 | 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 | } | ||
| 776 | 829 | ||
| 777 | pdev = get_pdev_same_bus(bus, id); | 830 | pdev = get_pdev_same_bus(bus, id); |
| 778 | if (!pdev) { | 831 | if (!pdev) { |
| @@ -800,7 +853,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
| 800 | enum edac_type mode; | 853 | enum edac_type mode; |
| 801 | enum mem_type mtype; | 854 | enum mem_type mtype; |
| 802 | 855 | ||
| 803 | if (pvt->info.type == HASWELL) | 856 | if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL) |
| 804 | pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, ®); | 857 | pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, ®); |
| 805 | else | 858 | else |
| 806 | pci_read_config_dword(pvt->pci_br0, SAD_TARGET, ®); | 859 | pci_read_config_dword(pvt->pci_br0, SAD_TARGET, ®); |
| @@ -848,7 +901,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
| 848 | else | 901 | else |
| 849 | edac_dbg(0, "Memory is unregistered\n"); | 902 | edac_dbg(0, "Memory is unregistered\n"); |
| 850 | 903 | ||
| 851 | if (mtype == MEM_DDR4 || MEM_RDDR4) | 904 | if (mtype == MEM_DDR4 || mtype == MEM_RDDR4) |
| 852 | banks = 16; | 905 | banks = 16; |
| 853 | else | 906 | else |
| 854 | banks = 8; | 907 | banks = 8; |
| @@ -909,7 +962,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci) | |||
| 909 | u32 reg; | 962 | u32 reg; |
| 910 | u64 limit, prv = 0; | 963 | u64 limit, prv = 0; |
| 911 | u64 tmp_mb; | 964 | u64 tmp_mb; |
| 912 | u32 mb, kb; | 965 | u32 gb, mb; |
| 913 | u32 rir_way; | 966 | u32 rir_way; |
| 914 | 967 | ||
| 915 | /* | 968 | /* |
| @@ -919,15 +972,17 @@ static void get_memory_layout(const struct mem_ctl_info *mci) | |||
| 919 | pvt->tolm = pvt->info.get_tolm(pvt); | 972 | pvt->tolm = pvt->info.get_tolm(pvt); |
| 920 | tmp_mb = (1 + pvt->tolm) >> 20; | 973 | tmp_mb = (1 + pvt->tolm) >> 20; |
| 921 | 974 | ||
| 922 | mb = div_u64_rem(tmp_mb, 1000, &kb); | 975 | gb = div_u64_rem(tmp_mb, 1024, &mb); |
| 923 | edac_dbg(0, "TOLM: %u.%03u GB (0x%016Lx)\n", mb, kb, (u64)pvt->tolm); | 976 | edac_dbg(0, "TOLM: %u.%03u GB (0x%016Lx)\n", |
| 977 | gb, (mb*1000)/1024, (u64)pvt->tolm); | ||
| 924 | 978 | ||
| 925 | /* Address range is already 45:25 */ | 979 | /* Address range is already 45:25 */ |
| 926 | pvt->tohm = pvt->info.get_tohm(pvt); | 980 | pvt->tohm = pvt->info.get_tohm(pvt); |
| 927 | tmp_mb = (1 + pvt->tohm) >> 20; | 981 | tmp_mb = (1 + pvt->tohm) >> 20; |
| 928 | 982 | ||
| 929 | mb = div_u64_rem(tmp_mb, 1000, &kb); | 983 | gb = div_u64_rem(tmp_mb, 1024, &mb); |
| 930 | edac_dbg(0, "TOHM: %u.%03u GB (0x%016Lx)\n", mb, kb, (u64)pvt->tohm); | 984 | edac_dbg(0, "TOHM: %u.%03u GB (0x%016Lx)\n", |
| 985 | gb, (mb*1000)/1024, (u64)pvt->tohm); | ||
| 931 | 986 | ||
| 932 | /* | 987 | /* |
| 933 | * Step 2) Get SAD range and SAD Interleave list | 988 | * Step 2) Get SAD range and SAD Interleave list |
| @@ -949,11 +1004,11 @@ static void get_memory_layout(const struct mem_ctl_info *mci) | |||
| 949 | break; | 1004 | break; |
| 950 | 1005 | ||
| 951 | tmp_mb = (limit + 1) >> 20; | 1006 | tmp_mb = (limit + 1) >> 20; |
| 952 | mb = div_u64_rem(tmp_mb, 1000, &kb); | 1007 | gb = div_u64_rem(tmp_mb, 1024, &mb); |
| 953 | edac_dbg(0, "SAD#%d %s up to %u.%03u GB (0x%016Lx) Interleave: %s reg=0x%08x\n", | 1008 | edac_dbg(0, "SAD#%d %s up to %u.%03u GB (0x%016Lx) Interleave: %s reg=0x%08x\n", |
| 954 | n_sads, | 1009 | n_sads, |
| 955 | get_dram_attr(reg), | 1010 | get_dram_attr(reg), |
| 956 | mb, kb, | 1011 | gb, (mb*1000)/1024, |
| 957 | ((u64)tmp_mb) << 20L, | 1012 | ((u64)tmp_mb) << 20L, |
| 958 | INTERLEAVE_MODE(reg) ? "8:6" : "[8:6]XOR[18:16]", | 1013 | INTERLEAVE_MODE(reg) ? "8:6" : "[8:6]XOR[18:16]", |
| 959 | reg); | 1014 | reg); |
| @@ -984,9 +1039,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci) | |||
| 984 | break; | 1039 | break; |
| 985 | tmp_mb = (limit + 1) >> 20; | 1040 | tmp_mb = (limit + 1) >> 20; |
| 986 | 1041 | ||
| 987 | mb = div_u64_rem(tmp_mb, 1000, &kb); | 1042 | gb = div_u64_rem(tmp_mb, 1024, &mb); |
| 988 | edac_dbg(0, "TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n", | 1043 | edac_dbg(0, "TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n", |
| 989 | n_tads, mb, kb, | 1044 | n_tads, gb, (mb*1000)/1024, |
| 990 | ((u64)tmp_mb) << 20L, | 1045 | ((u64)tmp_mb) << 20L, |
| 991 | (u32)TAD_SOCK(reg), | 1046 | (u32)TAD_SOCK(reg), |
| 992 | (u32)TAD_CH(reg), | 1047 | (u32)TAD_CH(reg), |
| @@ -1009,10 +1064,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci) | |||
| 1009 | tad_ch_nilv_offset[j], | 1064 | tad_ch_nilv_offset[j], |
| 1010 | ®); | 1065 | ®); |
| 1011 | tmp_mb = TAD_OFFSET(reg) >> 20; | 1066 | tmp_mb = TAD_OFFSET(reg) >> 20; |
| 1012 | mb = div_u64_rem(tmp_mb, 1000, &kb); | 1067 | gb = div_u64_rem(tmp_mb, 1024, &mb); |
| 1013 | edac_dbg(0, "TAD CH#%d, offset #%d: %u.%03u GB (0x%016Lx), reg=0x%08x\n", | 1068 | edac_dbg(0, "TAD CH#%d, offset #%d: %u.%03u GB (0x%016Lx), reg=0x%08x\n", |
| 1014 | i, j, | 1069 | i, j, |
| 1015 | mb, kb, | 1070 | gb, (mb*1000)/1024, |
| 1016 | ((u64)tmp_mb) << 20L, | 1071 | ((u64)tmp_mb) << 20L, |
| 1017 | reg); | 1072 | reg); |
| 1018 | } | 1073 | } |
| @@ -1034,10 +1089,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci) | |||
| 1034 | 1089 | ||
| 1035 | tmp_mb = pvt->info.rir_limit(reg) >> 20; | 1090 | tmp_mb = pvt->info.rir_limit(reg) >> 20; |
| 1036 | rir_way = 1 << RIR_WAY(reg); | 1091 | rir_way = 1 << RIR_WAY(reg); |
| 1037 | mb = div_u64_rem(tmp_mb, 1000, &kb); | 1092 | gb = div_u64_rem(tmp_mb, 1024, &mb); |
| 1038 | edac_dbg(0, "CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n", | 1093 | edac_dbg(0, "CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n", |
| 1039 | i, j, | 1094 | i, j, |
| 1040 | mb, kb, | 1095 | gb, (mb*1000)/1024, |
| 1041 | ((u64)tmp_mb) << 20L, | 1096 | ((u64)tmp_mb) << 20L, |
| 1042 | rir_way, | 1097 | rir_way, |
| 1043 | reg); | 1098 | reg); |
| @@ -1048,10 +1103,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci) | |||
| 1048 | ®); | 1103 | ®); |
| 1049 | tmp_mb = RIR_OFFSET(reg) << 6; | 1104 | tmp_mb = RIR_OFFSET(reg) << 6; |
| 1050 | 1105 | ||
| 1051 | mb = div_u64_rem(tmp_mb, 1000, &kb); | 1106 | gb = div_u64_rem(tmp_mb, 1024, &mb); |
| 1052 | edac_dbg(0, "CH#%d RIR#%d INTL#%d, offset %u.%03u GB (0x%016Lx), tgt: %d, reg=0x%08x\n", | 1107 | edac_dbg(0, "CH#%d RIR#%d INTL#%d, offset %u.%03u GB (0x%016Lx), tgt: %d, reg=0x%08x\n", |
| 1053 | i, j, k, | 1108 | i, j, k, |
| 1054 | mb, kb, | 1109 | gb, (mb*1000)/1024, |
| 1055 | ((u64)tmp_mb) << 20L, | 1110 | ((u64)tmp_mb) << 20L, |
| 1056 | (u32)RIR_RNK_TGT(reg), | 1111 | (u32)RIR_RNK_TGT(reg), |
| 1057 | reg); | 1112 | reg); |
| @@ -1089,7 +1144,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
| 1089 | u8 ch_way, sck_way, pkg, sad_ha = 0; | 1144 | u8 ch_way, sck_way, pkg, sad_ha = 0; |
| 1090 | u32 tad_offset; | 1145 | u32 tad_offset; |
| 1091 | u32 rir_way; | 1146 | u32 rir_way; |
| 1092 | u32 mb, kb; | 1147 | u32 mb, gb; |
| 1093 | u64 ch_addr, offset, limit = 0, prv = 0; | 1148 | u64 ch_addr, offset, limit = 0, prv = 0; |
| 1094 | 1149 | ||
| 1095 | 1150 | ||
| @@ -1179,7 +1234,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
| 1179 | *socket = sad_interleave[idx]; | 1234 | *socket = sad_interleave[idx]; |
| 1180 | 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", |
| 1181 | idx, sad_way, *socket); | 1236 | idx, sad_way, *socket); |
| 1182 | } else if (pvt->info.type == HASWELL) { | 1237 | } else if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL) { |
| 1183 | int bits, a7mode = A7MODE(dram_rule); | 1238 | int bits, a7mode = A7MODE(dram_rule); |
| 1184 | 1239 | ||
| 1185 | if (a7mode) { | 1240 | if (a7mode) { |
| @@ -1358,10 +1413,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
| 1358 | continue; | 1413 | continue; |
| 1359 | 1414 | ||
| 1360 | limit = pvt->info.rir_limit(reg); | 1415 | limit = pvt->info.rir_limit(reg); |
| 1361 | mb = div_u64_rem(limit >> 20, 1000, &kb); | 1416 | gb = div_u64_rem(limit >> 20, 1024, &mb); |
| 1362 | edac_dbg(0, "RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n", | 1417 | edac_dbg(0, "RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n", |
| 1363 | n_rir, | 1418 | n_rir, |
| 1364 | mb, kb, | 1419 | gb, (mb*1000)/1024, |
| 1365 | limit, | 1420 | limit, |
| 1366 | 1 << RIR_WAY(reg)); | 1421 | 1 << RIR_WAY(reg)); |
| 1367 | if (ch_addr <= limit) | 1422 | if (ch_addr <= limit) |
| @@ -1828,6 +1883,82 @@ enodev: | |||
| 1828 | return -ENODEV; | 1883 | return -ENODEV; |
| 1829 | } | 1884 | } |
| 1830 | 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 | |||
| 1831 | /**************************************************************************** | 1962 | /**************************************************************************** |
| 1832 | Error check routines | 1963 | Error check routines |
| 1833 | ****************************************************************************/ | 1964 | ****************************************************************************/ |
| @@ -2240,6 +2371,25 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
| 2240 | if (unlikely(rc < 0)) | 2371 | if (unlikely(rc < 0)) |
| 2241 | goto fail0; | 2372 | goto fail0; |
| 2242 | 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; | ||
| 2243 | } | 2393 | } |
| 2244 | 2394 | ||
| 2245 | /* Get dimm basic config and the memory layout */ | 2395 | /* Get dimm basic config and the memory layout */ |
| @@ -2305,6 +2455,10 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 2305 | 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); |
| 2306 | type = HASWELL; | 2456 | type = HASWELL; |
| 2307 | 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; | ||
| 2308 | } | 2462 | } |
| 2309 | if (unlikely(rc < 0)) | 2463 | if (unlikely(rc < 0)) |
| 2310 | goto fail0; | 2464 | goto fail0; |
