blob: 81dca957fce06e9a5bff92888368585a135a19c4 [file] [log] [blame]
Doug Thompson2bc65412009-05-04 20:11:14 +02001#include "amd64_edac.h"
Andreas Herrmann23ac4ae2010-09-17 18:03:43 +02002#include <asm/amd_nb.h>
Doug Thompson2bc65412009-05-04 20:11:14 +02003
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01004static struct edac_pci_ctl_info *pci_ctl;
Doug Thompson2bc65412009-05-04 20:11:14 +02005
6static int report_gart_errors;
7module_param(report_gart_errors, int, 0644);
8
9/*
10 * Set by command line parameter. If BIOS has enabled the ECC, this override is
11 * cleared to prevent re-enabling the hardware by this driver.
12 */
13static int ecc_enable_override;
14module_param(ecc_enable_override, int, 0644);
15
Tejun Heoa29d8b82010-02-02 14:39:15 +090016static struct msr __percpu *msrs;
Borislav Petkov50542252009-12-11 18:14:40 +010017
Borislav Petkov2ec591a2015-02-17 10:58:34 +010018/* Per-node stuff */
Borislav Petkovae7bb7c2010-10-14 16:01:30 +020019static struct ecc_settings **ecc_stngs;
Doug Thompson2bc65412009-05-04 20:11:14 +020020
Yazen Ghannambdcee772019-02-28 15:36:10 +000021/* Number of Unified Memory Controllers */
22static u8 num_umcs;
23
Doug Thompson2bc65412009-05-04 20:11:14 +020024/*
Borislav Petkovb70ef012009-06-25 19:32:38 +020025 * Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing
26 * bandwidth to a valid bit pattern. The 'set' operation finds the 'matching-
27 * or higher value'.
28 *
29 *FIXME: Produce a better mapping/linearisation.
30 */
Daniel J Bluemanc7e53012012-11-30 16:44:20 +080031static const struct scrubrate {
Borislav Petkov39094442010-11-24 19:52:09 +010032 u32 scrubval; /* bit pattern for scrub rate */
33 u32 bandwidth; /* bandwidth consumed (bytes/sec) */
34} scrubrates[] = {
Borislav Petkovb70ef012009-06-25 19:32:38 +020035 { 0x01, 1600000000UL},
36 { 0x02, 800000000UL},
37 { 0x03, 400000000UL},
38 { 0x04, 200000000UL},
39 { 0x05, 100000000UL},
40 { 0x06, 50000000UL},
41 { 0x07, 25000000UL},
42 { 0x08, 12284069UL},
43 { 0x09, 6274509UL},
44 { 0x0A, 3121951UL},
45 { 0x0B, 1560975UL},
46 { 0x0C, 781440UL},
47 { 0x0D, 390720UL},
48 { 0x0E, 195300UL},
49 { 0x0F, 97650UL},
50 { 0x10, 48854UL},
51 { 0x11, 24427UL},
52 { 0x12, 12213UL},
53 { 0x13, 6101UL},
54 { 0x14, 3051UL},
55 { 0x15, 1523UL},
56 { 0x16, 761UL},
57 { 0x00, 0UL}, /* scrubbing off */
58};
59
Borislav Petkov66fed2d2012-08-09 18:41:07 +020060int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
61 u32 *val, const char *func)
Borislav Petkovb2b0c602010-10-08 18:32:29 +020062{
63 int err = 0;
64
65 err = pci_read_config_dword(pdev, offset, val);
66 if (err)
67 amd64_warn("%s: error reading F%dx%03x.\n",
68 func, PCI_FUNC(pdev->devfn), offset);
69
70 return err;
71}
72
73int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset,
74 u32 val, const char *func)
75{
76 int err = 0;
77
78 err = pci_write_config_dword(pdev, offset, val);
79 if (err)
80 amd64_warn("%s: error writing to F%dx%03x.\n",
81 func, PCI_FUNC(pdev->devfn), offset);
82
83 return err;
84}
85
86/*
Borislav Petkov73ba8592011-09-19 17:34:45 +020087 * Select DCT to which PCI cfg accesses are routed
88 */
89static void f15h_select_dct(struct amd64_pvt *pvt, u8 dct)
90{
91 u32 reg = 0;
92
93 amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, &reg);
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -050094 reg &= (pvt->model == 0x30) ? ~3 : ~1;
Borislav Petkov73ba8592011-09-19 17:34:45 +020095 reg |= dct;
96 amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg);
97}
98
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -050099/*
100 *
101 * Depending on the family, F2 DCT reads need special handling:
102 *
103 * K8: has a single DCT only and no address offsets >= 0x100
104 *
105 * F10h: each DCT has its own set of regs
106 * DCT0 -> F2x040..
107 * DCT1 -> F2x140..
108 *
109 * F16h: has only 1 DCT
110 *
111 * F15h: we select which DCT we access using F1x10C[DctCfgSel]
112 */
113static inline int amd64_read_dct_pci_cfg(struct amd64_pvt *pvt, u8 dct,
114 int offset, u32 *val)
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200115{
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -0500116 switch (pvt->fam) {
117 case 0xf:
118 if (dct || offset >= 0x100)
119 return -EINVAL;
120 break;
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200121
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -0500122 case 0x10:
123 if (dct) {
124 /*
125 * Note: If ganging is enabled, barring the regs
126 * F2x[1,0]98 and F2x[1,0]9C; reads reads to F2x1xx
127 * return 0. (cf. Section 2.8.1 F10h BKDG)
128 */
129 if (dct_ganging_enabled(pvt))
130 return 0;
131
132 offset += 0x100;
133 }
134 break;
135
136 case 0x15:
137 /*
138 * F15h: F2x1xx addresses do not map explicitly to DCT1.
139 * We should select which DCT we access using F1x10C[DctCfgSel]
140 */
141 dct = (dct && pvt->model == 0x30) ? 3 : dct;
142 f15h_select_dct(pvt, dct);
143 break;
144
145 case 0x16:
146 if (dct)
147 return -EINVAL;
148 break;
149
150 default:
151 break;
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200152 }
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -0500153 return amd64_read_pci_cfg(pvt->F2, offset, val);
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200154}
155
Borislav Petkovb70ef012009-06-25 19:32:38 +0200156/*
Doug Thompson2bc65412009-05-04 20:11:14 +0200157 * Memory scrubber control interface. For K8, memory scrubbing is handled by
158 * hardware and can involve L2 cache, dcache as well as the main memory. With
159 * F10, this is extended to L3 cache scrubbing on CPU models sporting that
160 * functionality.
161 *
162 * This causes the "units" for the scrubbing speed to vary from 64 byte blocks
163 * (dram) over to cache lines. This is nasty, so we will use bandwidth in
164 * bytes/sec for the setting.
165 *
166 * Currently, we only do dram scrubbing. If the scrubbing is done in software on
167 * other archs, we might not have access to the caches directly.
168 */
169
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500170static inline void __f17h_set_scrubval(struct amd64_pvt *pvt, u32 scrubval)
171{
172 /*
173 * Fam17h supports scrub values between 0x5 and 0x14. Also, the values
174 * are shifted down by 0x5, so scrubval 0x5 is written to the register
175 * as 0x0, scrubval 0x6 as 0x1, etc.
176 */
177 if (scrubval >= 0x5 && scrubval <= 0x14) {
178 scrubval -= 0x5;
179 pci_write_bits32(pvt->F6, F17H_SCR_LIMIT_ADDR, scrubval, 0xF);
180 pci_write_bits32(pvt->F6, F17H_SCR_BASE_ADDR, 1, 0x1);
181 } else {
182 pci_write_bits32(pvt->F6, F17H_SCR_BASE_ADDR, 0, 0x1);
183 }
184}
Doug Thompson2bc65412009-05-04 20:11:14 +0200185/*
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500186 * Scan the scrub rate mapping table for a close or matching bandwidth value to
Doug Thompson2bc65412009-05-04 20:11:14 +0200187 * issue. If requested is too big, then use last maximum value found.
188 */
Aravind Gopalakrishnanda921102015-09-28 06:43:12 -0500189static int __set_scrub_rate(struct amd64_pvt *pvt, u32 new_bw, u32 min_rate)
Doug Thompson2bc65412009-05-04 20:11:14 +0200190{
191 u32 scrubval;
192 int i;
193
194 /*
195 * map the configured rate (new_bw) to a value specific to the AMD64
196 * memory controller and apply to register. Search for the first
197 * bandwidth entry that is greater or equal than the setting requested
198 * and program that. If at last entry, turn off DRAM scrubbing.
Andrew Morton168bfee2012-10-23 14:09:39 -0700199 *
200 * If no suitable bandwidth is found, turn off DRAM scrubbing entirely
201 * by falling back to the last element in scrubrates[].
Doug Thompson2bc65412009-05-04 20:11:14 +0200202 */
Andrew Morton168bfee2012-10-23 14:09:39 -0700203 for (i = 0; i < ARRAY_SIZE(scrubrates) - 1; i++) {
Doug Thompson2bc65412009-05-04 20:11:14 +0200204 /*
205 * skip scrub rates which aren't recommended
206 * (see F10 BKDG, F3x58)
207 */
Borislav Petkov395ae782010-10-01 18:38:19 +0200208 if (scrubrates[i].scrubval < min_rate)
Doug Thompson2bc65412009-05-04 20:11:14 +0200209 continue;
210
211 if (scrubrates[i].bandwidth <= new_bw)
212 break;
Doug Thompson2bc65412009-05-04 20:11:14 +0200213 }
214
215 scrubval = scrubrates[i].scrubval;
Doug Thompson2bc65412009-05-04 20:11:14 +0200216
Pu Wenc4a3e942018-09-27 16:31:28 +0200217 if (pvt->fam == 0x17 || pvt->fam == 0x18) {
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500218 __f17h_set_scrubval(pvt, scrubval);
219 } else if (pvt->fam == 0x15 && pvt->model == 0x60) {
Aravind Gopalakrishnanda921102015-09-28 06:43:12 -0500220 f15h_select_dct(pvt, 0);
221 pci_write_bits32(pvt->F2, F15H_M60H_SCRCTRL, scrubval, 0x001F);
222 f15h_select_dct(pvt, 1);
223 pci_write_bits32(pvt->F2, F15H_M60H_SCRCTRL, scrubval, 0x001F);
224 } else {
225 pci_write_bits32(pvt->F3, SCRCTRL, scrubval, 0x001F);
226 }
Doug Thompson2bc65412009-05-04 20:11:14 +0200227
Borislav Petkov39094442010-11-24 19:52:09 +0100228 if (scrubval)
229 return scrubrates[i].bandwidth;
230
Doug Thompson2bc65412009-05-04 20:11:14 +0200231 return 0;
232}
233
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100234static int set_scrub_rate(struct mem_ctl_info *mci, u32 bw)
Doug Thompson2bc65412009-05-04 20:11:14 +0200235{
236 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkov87b3e0e2011-01-19 20:02:38 +0100237 u32 min_scrubrate = 0x5;
Doug Thompson2bc65412009-05-04 20:11:14 +0200238
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200239 if (pvt->fam == 0xf)
Borislav Petkov87b3e0e2011-01-19 20:02:38 +0100240 min_scrubrate = 0x0;
241
Aravind Gopalakrishnanda921102015-09-28 06:43:12 -0500242 if (pvt->fam == 0x15) {
243 /* Erratum #505 */
244 if (pvt->model < 0x10)
245 f15h_select_dct(pvt, 0);
Borislav Petkov73ba8592011-09-19 17:34:45 +0200246
Aravind Gopalakrishnanda921102015-09-28 06:43:12 -0500247 if (pvt->model == 0x60)
248 min_scrubrate = 0x6;
249 }
250 return __set_scrub_rate(pvt, bw, min_scrubrate);
Doug Thompson2bc65412009-05-04 20:11:14 +0200251}
252
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100253static int get_scrub_rate(struct mem_ctl_info *mci)
Doug Thompson2bc65412009-05-04 20:11:14 +0200254{
255 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkov39094442010-11-24 19:52:09 +0100256 int i, retval = -EINVAL;
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500257 u32 scrubval = 0;
Doug Thompson2bc65412009-05-04 20:11:14 +0200258
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500259 switch (pvt->fam) {
260 case 0x15:
Aravind Gopalakrishnanda921102015-09-28 06:43:12 -0500261 /* Erratum #505 */
262 if (pvt->model < 0x10)
263 f15h_select_dct(pvt, 0);
Borislav Petkov73ba8592011-09-19 17:34:45 +0200264
Aravind Gopalakrishnanda921102015-09-28 06:43:12 -0500265 if (pvt->model == 0x60)
266 amd64_read_pci_cfg(pvt->F2, F15H_M60H_SCRCTRL, &scrubval);
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500267 break;
268
269 case 0x17:
Pu Wenc4a3e942018-09-27 16:31:28 +0200270 case 0x18:
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500271 amd64_read_pci_cfg(pvt->F6, F17H_SCR_BASE_ADDR, &scrubval);
272 if (scrubval & BIT(0)) {
273 amd64_read_pci_cfg(pvt->F6, F17H_SCR_LIMIT_ADDR, &scrubval);
274 scrubval &= 0xF;
275 scrubval += 0x5;
276 } else {
277 scrubval = 0;
278 }
279 break;
280
281 default:
Aravind Gopalakrishnanda921102015-09-28 06:43:12 -0500282 amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval);
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500283 break;
284 }
Doug Thompson2bc65412009-05-04 20:11:14 +0200285
286 scrubval = scrubval & 0x001F;
287
Roel Kluin926311f2010-01-11 20:58:21 +0100288 for (i = 0; i < ARRAY_SIZE(scrubrates); i++) {
Doug Thompson2bc65412009-05-04 20:11:14 +0200289 if (scrubrates[i].scrubval == scrubval) {
Borislav Petkov39094442010-11-24 19:52:09 +0100290 retval = scrubrates[i].bandwidth;
Doug Thompson2bc65412009-05-04 20:11:14 +0200291 break;
292 }
293 }
Borislav Petkov39094442010-11-24 19:52:09 +0100294 return retval;
Doug Thompson2bc65412009-05-04 20:11:14 +0200295}
296
Doug Thompson67757632009-04-27 15:53:22 +0200297/*
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200298 * returns true if the SysAddr given by sys_addr matches the
299 * DRAM base/limit associated with node_id
Doug Thompson67757632009-04-27 15:53:22 +0200300 */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100301static bool base_limit_match(struct amd64_pvt *pvt, u64 sys_addr, u8 nid)
Doug Thompson67757632009-04-27 15:53:22 +0200302{
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200303 u64 addr;
Doug Thompson67757632009-04-27 15:53:22 +0200304
305 /* The K8 treats this as a 40-bit value. However, bits 63-40 will be
306 * all ones if the most significant implemented address bit is 1.
307 * Here we discard bits 63-40. See section 3.4.2 of AMD publication
308 * 24592: AMD x86-64 Architecture Programmer's Manual Volume 1
309 * Application Programming.
310 */
311 addr = sys_addr & 0x000000ffffffffffull;
312
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200313 return ((addr >= get_dram_base(pvt, nid)) &&
314 (addr <= get_dram_limit(pvt, nid)));
Doug Thompson67757632009-04-27 15:53:22 +0200315}
316
317/*
318 * Attempt to map a SysAddr to a node. On success, return a pointer to the
319 * mem_ctl_info structure for the node that the SysAddr maps to.
320 *
321 * On failure, return NULL.
322 */
323static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
324 u64 sys_addr)
325{
326 struct amd64_pvt *pvt;
Daniel J Bluemanc7e53012012-11-30 16:44:20 +0800327 u8 node_id;
Doug Thompson67757632009-04-27 15:53:22 +0200328 u32 intlv_en, bits;
329
330 /*
331 * Here we use the DRAM Base (section 3.4.4.1) and DRAM Limit (section
332 * 3.4.4.2) registers to map the SysAddr to a node ID.
333 */
334 pvt = mci->pvt_info;
335
336 /*
337 * The value of this field should be the same for all DRAM Base
338 * registers. Therefore we arbitrarily choose to read it from the
339 * register for node 0.
340 */
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200341 intlv_en = dram_intlv_en(pvt, 0);
Doug Thompson67757632009-04-27 15:53:22 +0200342
343 if (intlv_en == 0) {
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200344 for (node_id = 0; node_id < DRAM_RANGES; node_id++) {
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100345 if (base_limit_match(pvt, sys_addr, node_id))
Borislav Petkov8edc5442009-09-18 12:39:19 +0200346 goto found;
Doug Thompson67757632009-04-27 15:53:22 +0200347 }
Borislav Petkov8edc5442009-09-18 12:39:19 +0200348 goto err_no_match;
Doug Thompson67757632009-04-27 15:53:22 +0200349 }
350
Borislav Petkov72f158f2009-09-18 12:27:27 +0200351 if (unlikely((intlv_en != 0x01) &&
352 (intlv_en != 0x03) &&
353 (intlv_en != 0x07))) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200354 amd64_warn("DRAM Base[IntlvEn] junk value: 0x%x, BIOS bug?\n", intlv_en);
Doug Thompson67757632009-04-27 15:53:22 +0200355 return NULL;
356 }
357
358 bits = (((u32) sys_addr) >> 12) & intlv_en;
359
360 for (node_id = 0; ; ) {
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200361 if ((dram_intlv_sel(pvt, node_id) & intlv_en) == bits)
Doug Thompson67757632009-04-27 15:53:22 +0200362 break; /* intlv_sel field matches */
363
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200364 if (++node_id >= DRAM_RANGES)
Doug Thompson67757632009-04-27 15:53:22 +0200365 goto err_no_match;
366 }
367
368 /* sanity test for sys_addr */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100369 if (unlikely(!base_limit_match(pvt, sys_addr, node_id))) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200370 amd64_warn("%s: sys_addr 0x%llx falls outside base/limit address"
371 "range for node %d with node interleaving enabled.\n",
372 __func__, sys_addr, node_id);
Doug Thompson67757632009-04-27 15:53:22 +0200373 return NULL;
374 }
375
376found:
Borislav Petkovb487c332011-02-21 18:55:00 +0100377 return edac_mc_find((int)node_id);
Doug Thompson67757632009-04-27 15:53:22 +0200378
379err_no_match:
Joe Perches956b9ba2012-04-29 17:08:39 -0300380 edac_dbg(2, "sys_addr 0x%lx doesn't match any node\n",
381 (unsigned long)sys_addr);
Doug Thompson67757632009-04-27 15:53:22 +0200382
383 return NULL;
384}
Doug Thompsone2ce7252009-04-27 15:57:12 +0200385
386/*
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100387 * compute the CS base address of the @csrow on the DRAM controller @dct.
388 * For details see F2x[5C:40] in the processor's BKDG
Doug Thompsone2ce7252009-04-27 15:57:12 +0200389 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100390static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct,
391 u64 *base, u64 *mask)
Doug Thompsone2ce7252009-04-27 15:57:12 +0200392{
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100393 u64 csbase, csmask, base_bits, mask_bits;
394 u8 addr_shift;
395
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -0500396 if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) {
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100397 csbase = pvt->csels[dct].csbases[csrow];
398 csmask = pvt->csels[dct].csmasks[csrow];
Chen, Gong10ef6b02013-10-18 14:29:07 -0700399 base_bits = GENMASK_ULL(31, 21) | GENMASK_ULL(15, 9);
400 mask_bits = GENMASK_ULL(29, 21) | GENMASK_ULL(15, 9);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100401 addr_shift = 4;
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -0500402
403 /*
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -0500404 * F16h and F15h, models 30h and later need two addr_shift values:
405 * 8 for high and 6 for low (cf. F16h BKDG).
406 */
407 } else if (pvt->fam == 0x16 ||
408 (pvt->fam == 0x15 && pvt->model >= 0x30)) {
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -0500409 csbase = pvt->csels[dct].csbases[csrow];
410 csmask = pvt->csels[dct].csmasks[csrow >> 1];
411
Chen, Gong10ef6b02013-10-18 14:29:07 -0700412 *base = (csbase & GENMASK_ULL(15, 5)) << 6;
413 *base |= (csbase & GENMASK_ULL(30, 19)) << 8;
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -0500414
415 *mask = ~0ULL;
416 /* poke holes for the csmask */
Chen, Gong10ef6b02013-10-18 14:29:07 -0700417 *mask &= ~((GENMASK_ULL(15, 5) << 6) |
418 (GENMASK_ULL(30, 19) << 8));
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -0500419
Chen, Gong10ef6b02013-10-18 14:29:07 -0700420 *mask |= (csmask & GENMASK_ULL(15, 5)) << 6;
421 *mask |= (csmask & GENMASK_ULL(30, 19)) << 8;
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -0500422
423 return;
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100424 } else {
425 csbase = pvt->csels[dct].csbases[csrow];
426 csmask = pvt->csels[dct].csmasks[csrow >> 1];
427 addr_shift = 8;
428
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200429 if (pvt->fam == 0x15)
Chen, Gong10ef6b02013-10-18 14:29:07 -0700430 base_bits = mask_bits =
431 GENMASK_ULL(30,19) | GENMASK_ULL(13,5);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100432 else
Chen, Gong10ef6b02013-10-18 14:29:07 -0700433 base_bits = mask_bits =
434 GENMASK_ULL(28,19) | GENMASK_ULL(13,5);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100435 }
436
437 *base = (csbase & base_bits) << addr_shift;
438
439 *mask = ~0ULL;
440 /* poke holes for the csmask */
441 *mask &= ~(mask_bits << addr_shift);
442 /* OR them in */
443 *mask |= (csmask & mask_bits) << addr_shift;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200444}
445
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100446#define for_each_chip_select(i, dct, pvt) \
447 for (i = 0; i < pvt->csels[dct].b_cnt; i++)
Doug Thompsone2ce7252009-04-27 15:57:12 +0200448
Borislav Petkov614ec9d2011-01-13 18:02:22 +0100449#define chip_select_base(i, dct, pvt) \
450 pvt->csels[dct].csbases[i]
451
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100452#define for_each_chip_select_mask(i, dct, pvt) \
453 for (i = 0; i < pvt->csels[dct].m_cnt; i++)
Doug Thompsone2ce7252009-04-27 15:57:12 +0200454
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +0000455#define for_each_umc(i) \
Yazen Ghannambdcee772019-02-28 15:36:10 +0000456 for (i = 0; i < num_umcs; i++)
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +0000457
Doug Thompsone2ce7252009-04-27 15:57:12 +0200458/*
459 * @input_addr is an InputAddr associated with the node given by mci. Return the
460 * csrow that input_addr maps to, or -1 on failure (no csrow claims input_addr).
461 */
462static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr)
463{
464 struct amd64_pvt *pvt;
465 int csrow;
466 u64 base, mask;
467
468 pvt = mci->pvt_info;
469
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100470 for_each_chip_select(csrow, 0, pvt) {
471 if (!csrow_enabled(csrow, 0, pvt))
Doug Thompsone2ce7252009-04-27 15:57:12 +0200472 continue;
473
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100474 get_cs_base_and_mask(pvt, csrow, 0, &base, &mask);
475
476 mask = ~mask;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200477
478 if ((input_addr & mask) == (base & mask)) {
Joe Perches956b9ba2012-04-29 17:08:39 -0300479 edac_dbg(2, "InputAddr 0x%lx matches csrow %d (node %d)\n",
480 (unsigned long)input_addr, csrow,
481 pvt->mc_node_id);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200482
483 return csrow;
484 }
485 }
Joe Perches956b9ba2012-04-29 17:08:39 -0300486 edac_dbg(2, "no matching csrow for InputAddr 0x%lx (MC node %d)\n",
487 (unsigned long)input_addr, pvt->mc_node_id);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200488
489 return -1;
490}
491
492/*
Doug Thompsone2ce7252009-04-27 15:57:12 +0200493 * Obtain info from the DRAM Hole Address Register (section 3.4.8, pub #26094)
494 * for the node represented by mci. Info is passed back in *hole_base,
495 * *hole_offset, and *hole_size. Function returns 0 if info is valid or 1 if
496 * info is invalid. Info may be invalid for either of the following reasons:
497 *
498 * - The revision of the node is not E or greater. In this case, the DRAM Hole
499 * Address Register does not exist.
500 *
501 * - The DramHoleValid bit is cleared in the DRAM Hole Address Register,
502 * indicating that its contents are not valid.
503 *
504 * The values passed back in *hole_base, *hole_offset, and *hole_size are
505 * complete 32-bit values despite the fact that the bitfields in the DHAR
506 * only represent bits 31-24 of the base and offset values.
507 */
508int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
509 u64 *hole_offset, u64 *hole_size)
510{
511 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200512
513 /* only revE and later have the DRAM Hole Address Register */
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200514 if (pvt->fam == 0xf && pvt->ext_model < K8_REV_E) {
Joe Perches956b9ba2012-04-29 17:08:39 -0300515 edac_dbg(1, " revision %d for node %d does not support DHAR\n",
516 pvt->ext_model, pvt->mc_node_id);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200517 return 1;
518 }
519
Borislav Petkovbc21fa52010-11-11 17:29:13 +0100520 /* valid for Fam10h and above */
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200521 if (pvt->fam >= 0x10 && !dhar_mem_hoist_valid(pvt)) {
Joe Perches956b9ba2012-04-29 17:08:39 -0300522 edac_dbg(1, " Dram Memory Hoisting is DISABLED on this system\n");
Doug Thompsone2ce7252009-04-27 15:57:12 +0200523 return 1;
524 }
525
Borislav Petkovc8e518d2010-12-10 19:49:19 +0100526 if (!dhar_valid(pvt)) {
Joe Perches956b9ba2012-04-29 17:08:39 -0300527 edac_dbg(1, " Dram Memory Hoisting is DISABLED on this node %d\n",
528 pvt->mc_node_id);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200529 return 1;
530 }
531
532 /* This node has Memory Hoisting */
533
534 /* +------------------+--------------------+--------------------+-----
535 * | memory | DRAM hole | relocated |
536 * | [0, (x - 1)] | [x, 0xffffffff] | addresses from |
537 * | | | DRAM hole |
538 * | | | [0x100000000, |
539 * | | | (0x100000000+ |
540 * | | | (0xffffffff-x))] |
541 * +------------------+--------------------+--------------------+-----
542 *
543 * Above is a diagram of physical memory showing the DRAM hole and the
544 * relocated addresses from the DRAM hole. As shown, the DRAM hole
545 * starts at address x (the base address) and extends through address
546 * 0xffffffff. The DRAM Hole Address Register (DHAR) relocates the
547 * addresses in the hole so that they start at 0x100000000.
548 */
549
Borislav Petkov1f316772012-08-10 12:50:50 +0200550 *hole_base = dhar_base(pvt);
551 *hole_size = (1ULL << 32) - *hole_base;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200552
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200553 *hole_offset = (pvt->fam > 0xf) ? f10_dhar_offset(pvt)
554 : k8_dhar_offset(pvt);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200555
Joe Perches956b9ba2012-04-29 17:08:39 -0300556 edac_dbg(1, " DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx\n",
557 pvt->mc_node_id, (unsigned long)*hole_base,
558 (unsigned long)*hole_offset, (unsigned long)*hole_size);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200559
560 return 0;
561}
562EXPORT_SYMBOL_GPL(amd64_get_dram_hole_info);
563
Doug Thompson93c2df52009-05-04 20:46:50 +0200564/*
565 * Return the DramAddr that the SysAddr given by @sys_addr maps to. It is
566 * assumed that sys_addr maps to the node given by mci.
567 *
568 * The first part of section 3.4.4 (p. 70) shows how the DRAM Base (section
569 * 3.4.4.1) and DRAM Limit (section 3.4.4.2) registers are used to translate a
570 * SysAddr to a DramAddr. If the DRAM Hole Address Register (DHAR) is enabled,
571 * then it is also involved in translating a SysAddr to a DramAddr. Sections
572 * 3.4.8 and 3.5.8.2 describe the DHAR and how it is used for memory hoisting.
573 * These parts of the documentation are unclear. I interpret them as follows:
574 *
575 * When node n receives a SysAddr, it processes the SysAddr as follows:
576 *
577 * 1. It extracts the DRAMBase and DRAMLimit values from the DRAM Base and DRAM
578 * Limit registers for node n. If the SysAddr is not within the range
579 * specified by the base and limit values, then node n ignores the Sysaddr
580 * (since it does not map to node n). Otherwise continue to step 2 below.
581 *
582 * 2. If the DramHoleValid bit of the DHAR for node n is clear, the DHAR is
583 * disabled so skip to step 3 below. Otherwise see if the SysAddr is within
584 * the range of relocated addresses (starting at 0x100000000) from the DRAM
585 * hole. If not, skip to step 3 below. Else get the value of the
586 * DramHoleOffset field from the DHAR. To obtain the DramAddr, subtract the
587 * offset defined by this value from the SysAddr.
588 *
589 * 3. Obtain the base address for node n from the DRAMBase field of the DRAM
590 * Base register for node n. To obtain the DramAddr, subtract the base
591 * address from the SysAddr, as shown near the start of section 3.4.4 (p.70).
592 */
593static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr)
594{
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200595 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompson93c2df52009-05-04 20:46:50 +0200596 u64 dram_base, hole_base, hole_offset, hole_size, dram_addr;
Borislav Petkov1f316772012-08-10 12:50:50 +0200597 int ret;
Doug Thompson93c2df52009-05-04 20:46:50 +0200598
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200599 dram_base = get_dram_base(pvt, pvt->mc_node_id);
Doug Thompson93c2df52009-05-04 20:46:50 +0200600
601 ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
602 &hole_size);
603 if (!ret) {
Borislav Petkov1f316772012-08-10 12:50:50 +0200604 if ((sys_addr >= (1ULL << 32)) &&
605 (sys_addr < ((1ULL << 32) + hole_size))) {
Doug Thompson93c2df52009-05-04 20:46:50 +0200606 /* use DHAR to translate SysAddr to DramAddr */
607 dram_addr = sys_addr - hole_offset;
608
Joe Perches956b9ba2012-04-29 17:08:39 -0300609 edac_dbg(2, "using DHAR to translate SysAddr 0x%lx to DramAddr 0x%lx\n",
610 (unsigned long)sys_addr,
611 (unsigned long)dram_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200612
613 return dram_addr;
614 }
615 }
616
617 /*
618 * Translate the SysAddr to a DramAddr as shown near the start of
619 * section 3.4.4 (p. 70). Although sys_addr is a 64-bit value, the k8
620 * only deals with 40-bit values. Therefore we discard bits 63-40 of
621 * sys_addr below. If bit 39 of sys_addr is 1 then the bits we
622 * discard are all 1s. Otherwise the bits we discard are all 0s. See
623 * section 3.4.2 of AMD publication 24592: AMD x86-64 Architecture
624 * Programmer's Manual Volume 1 Application Programming.
625 */
Chen, Gong10ef6b02013-10-18 14:29:07 -0700626 dram_addr = (sys_addr & GENMASK_ULL(39, 0)) - dram_base;
Doug Thompson93c2df52009-05-04 20:46:50 +0200627
Joe Perches956b9ba2012-04-29 17:08:39 -0300628 edac_dbg(2, "using DRAM Base register to translate SysAddr 0x%lx to DramAddr 0x%lx\n",
629 (unsigned long)sys_addr, (unsigned long)dram_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200630 return dram_addr;
631}
632
633/*
634 * @intlv_en is the value of the IntlvEn field from a DRAM Base register
635 * (section 3.4.4.1). Return the number of bits from a SysAddr that are used
636 * for node interleaving.
637 */
638static int num_node_interleave_bits(unsigned intlv_en)
639{
640 static const int intlv_shift_table[] = { 0, 1, 0, 2, 0, 0, 0, 3 };
641 int n;
642
643 BUG_ON(intlv_en > 7);
644 n = intlv_shift_table[intlv_en];
645 return n;
646}
647
648/* Translate the DramAddr given by @dram_addr to an InputAddr. */
649static u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr)
650{
651 struct amd64_pvt *pvt;
652 int intlv_shift;
653 u64 input_addr;
654
655 pvt = mci->pvt_info;
656
657 /*
658 * See the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E)
659 * concerning translating a DramAddr to an InputAddr.
660 */
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200661 intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0));
Chen, Gong10ef6b02013-10-18 14:29:07 -0700662 input_addr = ((dram_addr >> intlv_shift) & GENMASK_ULL(35, 12)) +
Borislav Petkovf678b8c2010-12-13 19:21:07 +0100663 (dram_addr & 0xfff);
Doug Thompson93c2df52009-05-04 20:46:50 +0200664
Joe Perches956b9ba2012-04-29 17:08:39 -0300665 edac_dbg(2, " Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n",
666 intlv_shift, (unsigned long)dram_addr,
667 (unsigned long)input_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200668
669 return input_addr;
670}
671
672/*
673 * Translate the SysAddr represented by @sys_addr to an InputAddr. It is
674 * assumed that @sys_addr maps to the node given by mci.
675 */
676static u64 sys_addr_to_input_addr(struct mem_ctl_info *mci, u64 sys_addr)
677{
678 u64 input_addr;
679
680 input_addr =
681 dram_addr_to_input_addr(mci, sys_addr_to_dram_addr(mci, sys_addr));
682
Masanari Iidac19ca6c2016-02-08 20:53:12 +0900683 edac_dbg(2, "SysAddr 0x%lx translates to InputAddr 0x%lx\n",
Joe Perches956b9ba2012-04-29 17:08:39 -0300684 (unsigned long)sys_addr, (unsigned long)input_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200685
686 return input_addr;
687}
688
Doug Thompson93c2df52009-05-04 20:46:50 +0200689/* Map the Error address to a PAGE and PAGE OFFSET. */
690static inline void error_address_to_page_and_offset(u64 error_address,
Borislav Petkov33ca0642012-08-30 18:01:36 +0200691 struct err_info *err)
Doug Thompson93c2df52009-05-04 20:46:50 +0200692{
Borislav Petkov33ca0642012-08-30 18:01:36 +0200693 err->page = (u32) (error_address >> PAGE_SHIFT);
694 err->offset = ((u32) error_address) & ~PAGE_MASK;
Doug Thompson93c2df52009-05-04 20:46:50 +0200695}
696
697/*
698 * @sys_addr is an error address (a SysAddr) extracted from the MCA NB Address
699 * Low (section 3.6.4.5) and MCA NB Address High (section 3.6.4.6) registers
700 * of a node that detected an ECC memory error. mci represents the node that
701 * the error address maps to (possibly different from the node that detected
702 * the error). Return the number of the csrow that sys_addr maps to, or -1 on
703 * error.
704 */
705static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr)
706{
707 int csrow;
708
709 csrow = input_addr_to_csrow(mci, sys_addr_to_input_addr(mci, sys_addr));
710
711 if (csrow == -1)
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200712 amd64_mc_err(mci, "Failed to translate InputAddr to csrow for "
713 "address 0x%lx\n", (unsigned long)sys_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200714 return csrow;
715}
Doug Thompsone2ce7252009-04-27 15:57:12 +0200716
Borislav Petkovbfc04ae2009-11-12 19:05:07 +0100717static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);
Doug Thompson2da11652009-04-27 16:09:09 +0200718
Doug Thompson2da11652009-04-27 16:09:09 +0200719/*
720 * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs
721 * are ECC capable.
722 */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100723static unsigned long determine_edac_cap(struct amd64_pvt *pvt)
Doug Thompson2da11652009-04-27 16:09:09 +0200724{
Dan Carpenter1f6189e2011-10-06 02:30:25 -0400725 unsigned long edac_cap = EDAC_FLAG_NONE;
Yazen Ghannamd27f3a32016-11-17 17:57:40 -0500726 u8 bit;
Doug Thompson2da11652009-04-27 16:09:09 +0200727
Yazen Ghannamd27f3a32016-11-17 17:57:40 -0500728 if (pvt->umc) {
729 u8 i, umc_en_mask = 0, dimm_ecc_en_mask = 0;
Doug Thompson2da11652009-04-27 16:09:09 +0200730
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +0000731 for_each_umc(i) {
Yazen Ghannamd27f3a32016-11-17 17:57:40 -0500732 if (!(pvt->umc[i].sdp_ctrl & UMC_SDP_INIT))
733 continue;
734
735 umc_en_mask |= BIT(i);
736
737 /* UMC Configuration bit 12 (DimmEccEn) */
738 if (pvt->umc[i].umc_cfg & BIT(12))
739 dimm_ecc_en_mask |= BIT(i);
740 }
741
742 if (umc_en_mask == dimm_ecc_en_mask)
743 edac_cap = EDAC_FLAG_SECDED;
744 } else {
745 bit = (pvt->fam > 0xf || pvt->ext_model >= K8_REV_F)
746 ? 19
747 : 17;
748
749 if (pvt->dclr0 & BIT(bit))
750 edac_cap = EDAC_FLAG_SECDED;
751 }
Doug Thompson2da11652009-04-27 16:09:09 +0200752
753 return edac_cap;
754}
755
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100756static void debug_display_dimm_sizes(struct amd64_pvt *, u8);
Doug Thompson2da11652009-04-27 16:09:09 +0200757
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100758static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan)
Borislav Petkov68798e12009-11-03 16:18:33 +0100759{
Joe Perches956b9ba2012-04-29 17:08:39 -0300760 edac_dbg(1, "F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr);
Borislav Petkov68798e12009-11-03 16:18:33 +0100761
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +0100762 if (pvt->dram_type == MEM_LRDDR3) {
763 u32 dcsm = pvt->csels[chan].csmasks[0];
764 /*
765 * It's assumed all LRDIMMs in a DCT are going to be of
766 * same 'type' until proven otherwise. So, use a cs
767 * value of '0' here to get dcsm value.
768 */
769 edac_dbg(1, " LRDIMM %dx rank multiply\n", (dcsm & 0x3));
770 }
771
772 edac_dbg(1, "All DIMMs support ECC:%s\n",
773 (dclr & BIT(19)) ? "yes" : "no");
774
Borislav Petkov68798e12009-11-03 16:18:33 +0100775
Joe Perches956b9ba2012-04-29 17:08:39 -0300776 edac_dbg(1, " PAR/ERR parity: %s\n",
777 (dclr & BIT(8)) ? "enabled" : "disabled");
Borislav Petkov68798e12009-11-03 16:18:33 +0100778
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200779 if (pvt->fam == 0x10)
Joe Perches956b9ba2012-04-29 17:08:39 -0300780 edac_dbg(1, " DCT 128bit mode width: %s\n",
781 (dclr & BIT(11)) ? "128b" : "64b");
Borislav Petkov68798e12009-11-03 16:18:33 +0100782
Joe Perches956b9ba2012-04-29 17:08:39 -0300783 edac_dbg(1, " x4 logical DIMMs present: L0: %s L1: %s L2: %s L3: %s\n",
784 (dclr & BIT(12)) ? "yes" : "no",
785 (dclr & BIT(13)) ? "yes" : "no",
786 (dclr & BIT(14)) ? "yes" : "no",
787 (dclr & BIT(15)) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100788}
789
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600790static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl)
791{
Yazen Ghannameb77e6b2017-04-27 12:11:54 -0500792 int dimm, size0, size1, cs0, cs1;
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600793
794 edac_printk(KERN_DEBUG, EDAC_MC, "UMC%d chip selects:\n", ctrl);
795
796 for (dimm = 0; dimm < 4; dimm++) {
797 size0 = 0;
Yazen Ghannameb77e6b2017-04-27 12:11:54 -0500798 cs0 = dimm * 2;
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600799
Yazen Ghannameb77e6b2017-04-27 12:11:54 -0500800 if (csrow_enabled(cs0, ctrl, pvt))
801 size0 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, cs0);
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600802
803 size1 = 0;
Yazen Ghannameb77e6b2017-04-27 12:11:54 -0500804 cs1 = dimm * 2 + 1;
805
806 if (csrow_enabled(cs1, ctrl, pvt))
807 size1 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, cs1);
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600808
809 amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
Yazen Ghannameb77e6b2017-04-27 12:11:54 -0500810 cs0, size0,
811 cs1, size1);
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600812 }
813}
814
815static void __dump_misc_regs_df(struct amd64_pvt *pvt)
816{
817 struct amd64_umc *umc;
818 u32 i, tmp, umc_base;
819
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +0000820 for_each_umc(i) {
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600821 umc_base = get_umc_base(i);
822 umc = &pvt->umc[i];
823
824 edac_dbg(1, "UMC%d DIMM cfg: 0x%x\n", i, umc->dimm_cfg);
825 edac_dbg(1, "UMC%d UMC cfg: 0x%x\n", i, umc->umc_cfg);
826 edac_dbg(1, "UMC%d SDP ctrl: 0x%x\n", i, umc->sdp_ctrl);
827 edac_dbg(1, "UMC%d ECC ctrl: 0x%x\n", i, umc->ecc_ctrl);
828
829 amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_ECC_BAD_SYMBOL, &tmp);
830 edac_dbg(1, "UMC%d ECC bad symbol: 0x%x\n", i, tmp);
831
832 amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_UMC_CAP, &tmp);
833 edac_dbg(1, "UMC%d UMC cap: 0x%x\n", i, tmp);
834 edac_dbg(1, "UMC%d UMC cap high: 0x%x\n", i, umc->umc_cap_hi);
835
836 edac_dbg(1, "UMC%d ECC capable: %s, ChipKill ECC capable: %s\n",
837 i, (umc->umc_cap_hi & BIT(30)) ? "yes" : "no",
838 (umc->umc_cap_hi & BIT(31)) ? "yes" : "no");
839 edac_dbg(1, "UMC%d All DIMMs support ECC: %s\n",
840 i, (umc->umc_cfg & BIT(12)) ? "yes" : "no");
841 edac_dbg(1, "UMC%d x4 DIMMs present: %s\n",
842 i, (umc->dimm_cfg & BIT(6)) ? "yes" : "no");
843 edac_dbg(1, "UMC%d x16 DIMMs present: %s\n",
844 i, (umc->dimm_cfg & BIT(7)) ? "yes" : "no");
845
846 if (pvt->dram_type == MEM_LRDDR4) {
847 amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_ADDR_CFG, &tmp);
848 edac_dbg(1, "UMC%d LRDIMM %dx rank multiply\n",
849 i, 1 << ((tmp >> 4) & 0x3));
850 }
851
852 debug_display_dimm_sizes_df(pvt, i);
853 }
854
855 edac_dbg(1, "F0x104 (DRAM Hole Address): 0x%08x, base: 0x%08x\n",
856 pvt->dhar, dhar_base(pvt));
857}
858
Doug Thompson2da11652009-04-27 16:09:09 +0200859/* Display and decode various NB registers for debug purposes. */
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600860static void __dump_misc_regs(struct amd64_pvt *pvt)
Doug Thompson2da11652009-04-27 16:09:09 +0200861{
Joe Perches956b9ba2012-04-29 17:08:39 -0300862 edac_dbg(1, "F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap);
Doug Thompson2da11652009-04-27 16:09:09 +0200863
Joe Perches956b9ba2012-04-29 17:08:39 -0300864 edac_dbg(1, " NB two channel DRAM capable: %s\n",
865 (pvt->nbcap & NBCAP_DCT_DUAL) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100866
Joe Perches956b9ba2012-04-29 17:08:39 -0300867 edac_dbg(1, " ECC capable: %s, ChipKill ECC capable: %s\n",
868 (pvt->nbcap & NBCAP_SECDED) ? "yes" : "no",
869 (pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100870
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100871 debug_dump_dramcfg_low(pvt, pvt->dclr0, 0);
Doug Thompson2da11652009-04-27 16:09:09 +0200872
Joe Perches956b9ba2012-04-29 17:08:39 -0300873 edac_dbg(1, "F3xB0 (Online Spare): 0x%08x\n", pvt->online_spare);
Doug Thompson2da11652009-04-27 16:09:09 +0200874
Joe Perches956b9ba2012-04-29 17:08:39 -0300875 edac_dbg(1, "F1xF0 (DRAM Hole Address): 0x%08x, base: 0x%08x, offset: 0x%08x\n",
876 pvt->dhar, dhar_base(pvt),
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200877 (pvt->fam == 0xf) ? k8_dhar_offset(pvt)
878 : f10_dhar_offset(pvt));
Doug Thompson2da11652009-04-27 16:09:09 +0200879
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100880 debug_display_dimm_sizes(pvt, 0);
Borislav Petkov4d796362011-02-03 15:59:57 +0100881
Borislav Petkov8de1d912009-10-16 13:39:30 +0200882 /* everything below this point is Fam10h and above */
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200883 if (pvt->fam == 0xf)
Doug Thompson2da11652009-04-27 16:09:09 +0200884 return;
Borislav Petkov4d796362011-02-03 15:59:57 +0100885
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100886 debug_display_dimm_sizes(pvt, 1);
Doug Thompson2da11652009-04-27 16:09:09 +0200887
Borislav Petkov8de1d912009-10-16 13:39:30 +0200888 /* Only if NOT ganged does dclr1 have valid info */
Borislav Petkov68798e12009-11-03 16:18:33 +0100889 if (!dct_ganging_enabled(pvt))
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100890 debug_dump_dramcfg_low(pvt, pvt->dclr1, 1);
Doug Thompson2da11652009-04-27 16:09:09 +0200891}
892
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600893/* Display and decode various NB registers for debug purposes. */
894static void dump_misc_regs(struct amd64_pvt *pvt)
895{
896 if (pvt->umc)
897 __dump_misc_regs_df(pvt);
898 else
899 __dump_misc_regs(pvt);
900
901 edac_dbg(1, " DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no");
902
903 amd64_info("using %s syndromes.\n",
904 ((pvt->ecc_sym_sz == 8) ? "x8" : "x4"));
905}
906
Doug Thompson94be4bf2009-04-27 16:12:00 +0200907/*
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -0500908 * See BKDG, F2x[1,0][5C:40], F2[1,0][6C:60]
Doug Thompson94be4bf2009-04-27 16:12:00 +0200909 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100910static void prep_chip_selects(struct amd64_pvt *pvt)
Doug Thompson94be4bf2009-04-27 16:12:00 +0200911{
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -0500912 if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) {
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100913 pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
914 pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 8;
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +0100915 } else if (pvt->fam == 0x15 && pvt->model == 0x30) {
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -0500916 pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4;
917 pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2;
Borislav Petkov9d858bb2009-09-21 14:35:51 +0200918 } else {
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100919 pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
920 pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4;
Doug Thompson94be4bf2009-04-27 16:12:00 +0200921 }
922}
923
924/*
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100925 * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers
Doug Thompson94be4bf2009-04-27 16:12:00 +0200926 */
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200927static void read_dct_base_mask(struct amd64_pvt *pvt)
Doug Thompson94be4bf2009-04-27 16:12:00 +0200928{
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500929 int base_reg0, base_reg1, mask_reg0, mask_reg1, cs;
Doug Thompson94be4bf2009-04-27 16:12:00 +0200930
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100931 prep_chip_selects(pvt);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200932
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500933 if (pvt->umc) {
934 base_reg0 = get_umc_base(0) + UMCCH_BASE_ADDR;
935 base_reg1 = get_umc_base(1) + UMCCH_BASE_ADDR;
936 mask_reg0 = get_umc_base(0) + UMCCH_ADDR_MASK;
937 mask_reg1 = get_umc_base(1) + UMCCH_ADDR_MASK;
938 } else {
939 base_reg0 = DCSB0;
940 base_reg1 = DCSB1;
941 mask_reg0 = DCSM0;
942 mask_reg1 = DCSM1;
943 }
944
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100945 for_each_chip_select(cs, 0, pvt) {
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500946 int reg0 = base_reg0 + (cs * 4);
947 int reg1 = base_reg1 + (cs * 4);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100948 u32 *base0 = &pvt->csels[0].csbases[cs];
949 u32 *base1 = &pvt->csels[1].csbases[cs];
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200950
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500951 if (pvt->umc) {
952 if (!amd_smn_read(pvt->mc_node_id, reg0, base0))
953 edac_dbg(0, " DCSB0[%d]=0x%08x reg: 0x%x\n",
954 cs, *base0, reg0);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200955
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500956 if (!amd_smn_read(pvt->mc_node_id, reg1, base1))
957 edac_dbg(0, " DCSB1[%d]=0x%08x reg: 0x%x\n",
958 cs, *base1, reg1);
959 } else {
960 if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, base0))
961 edac_dbg(0, " DCSB0[%d]=0x%08x reg: F2x%x\n",
962 cs, *base0, reg0);
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200963
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500964 if (pvt->fam == 0xf)
965 continue;
966
967 if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, base1))
968 edac_dbg(0, " DCSB1[%d]=0x%08x reg: F2x%x\n",
969 cs, *base1, (pvt->fam == 0x10) ? reg1
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -0500970 : reg0);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500971 }
Doug Thompson94be4bf2009-04-27 16:12:00 +0200972 }
973
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100974 for_each_chip_select_mask(cs, 0, pvt) {
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500975 int reg0 = mask_reg0 + (cs * 4);
976 int reg1 = mask_reg1 + (cs * 4);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100977 u32 *mask0 = &pvt->csels[0].csmasks[cs];
978 u32 *mask1 = &pvt->csels[1].csmasks[cs];
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200979
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500980 if (pvt->umc) {
981 if (!amd_smn_read(pvt->mc_node_id, reg0, mask0))
982 edac_dbg(0, " DCSM0[%d]=0x%08x reg: 0x%x\n",
983 cs, *mask0, reg0);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200984
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500985 if (!amd_smn_read(pvt->mc_node_id, reg1, mask1))
986 edac_dbg(0, " DCSM1[%d]=0x%08x reg: 0x%x\n",
987 cs, *mask1, reg1);
988 } else {
989 if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, mask0))
990 edac_dbg(0, " DCSM0[%d]=0x%08x reg: F2x%x\n",
991 cs, *mask0, reg0);
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200992
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500993 if (pvt->fam == 0xf)
994 continue;
995
996 if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, mask1))
997 edac_dbg(0, " DCSM1[%d]=0x%08x reg: F2x%x\n",
998 cs, *mask1, (pvt->fam == 0x10) ? reg1
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -0500999 : reg0);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05001000 }
Doug Thompson94be4bf2009-04-27 16:12:00 +02001001 }
1002}
1003
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001004static void determine_memory_type(struct amd64_pvt *pvt)
Doug Thompson94be4bf2009-04-27 16:12:00 +02001005{
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001006 u32 dram_ctrl, dcsm;
Doug Thompson94be4bf2009-04-27 16:12:00 +02001007
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001008 switch (pvt->fam) {
1009 case 0xf:
1010 if (pvt->ext_model >= K8_REV_F)
1011 goto ddr3;
1012
1013 pvt->dram_type = (pvt->dclr0 & BIT(18)) ? MEM_DDR : MEM_RDDR;
1014 return;
1015
1016 case 0x10:
Borislav Petkov6b4c0bd2009-11-12 15:37:57 +01001017 if (pvt->dchr0 & DDR3_MODE)
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001018 goto ddr3;
1019
1020 pvt->dram_type = (pvt->dclr0 & BIT(16)) ? MEM_DDR2 : MEM_RDDR2;
1021 return;
1022
1023 case 0x15:
1024 if (pvt->model < 0x60)
1025 goto ddr3;
1026
1027 /*
1028 * Model 0x60h needs special handling:
1029 *
1030 * We use a Chip Select value of '0' to obtain dcsm.
1031 * Theoretically, it is possible to populate LRDIMMs of different
1032 * 'Rank' value on a DCT. But this is not the common case. So,
1033 * it's reasonable to assume all DIMMs are going to be of same
1034 * 'type' until proven otherwise.
1035 */
1036 amd64_read_dct_pci_cfg(pvt, 0, DRAM_CONTROL, &dram_ctrl);
1037 dcsm = pvt->csels[0].csmasks[0];
1038
1039 if (((dram_ctrl >> 8) & 0x7) == 0x2)
1040 pvt->dram_type = MEM_DDR4;
1041 else if (pvt->dclr0 & BIT(16))
1042 pvt->dram_type = MEM_DDR3;
1043 else if (dcsm & 0x3)
1044 pvt->dram_type = MEM_LRDDR3;
Borislav Petkov6b4c0bd2009-11-12 15:37:57 +01001045 else
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001046 pvt->dram_type = MEM_RDDR3;
1047
1048 return;
1049
1050 case 0x16:
1051 goto ddr3;
1052
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05001053 case 0x17:
Pu Wenc4a3e942018-09-27 16:31:28 +02001054 case 0x18:
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05001055 if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(5))
1056 pvt->dram_type = MEM_LRDDR4;
1057 else if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(4))
1058 pvt->dram_type = MEM_RDDR4;
1059 else
1060 pvt->dram_type = MEM_DDR4;
1061 return;
1062
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001063 default:
1064 WARN(1, KERN_ERR "%s: Family??? 0x%x\n", __func__, pvt->fam);
1065 pvt->dram_type = MEM_EMPTY;
Doug Thompson94be4bf2009-04-27 16:12:00 +02001066 }
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001067 return;
Doug Thompson94be4bf2009-04-27 16:12:00 +02001068
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001069ddr3:
1070 pvt->dram_type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3;
Doug Thompson94be4bf2009-04-27 16:12:00 +02001071}
1072
Borislav Petkovcb328502010-12-22 14:28:24 +01001073/* Get the number of DCT channels the memory controller is using. */
Doug Thompsonddff8762009-04-27 16:14:52 +02001074static int k8_early_channel_count(struct amd64_pvt *pvt)
1075{
Borislav Petkovcb328502010-12-22 14:28:24 +01001076 int flag;
Doug Thompsonddff8762009-04-27 16:14:52 +02001077
Borislav Petkov9f56da02010-10-01 19:44:53 +02001078 if (pvt->ext_model >= K8_REV_F)
Doug Thompsonddff8762009-04-27 16:14:52 +02001079 /* RevF (NPT) and later */
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001080 flag = pvt->dclr0 & WIDTH_128;
Borislav Petkov9f56da02010-10-01 19:44:53 +02001081 else
Doug Thompsonddff8762009-04-27 16:14:52 +02001082 /* RevE and earlier */
1083 flag = pvt->dclr0 & REVE_WIDTH_128;
Doug Thompsonddff8762009-04-27 16:14:52 +02001084
1085 /* not used */
1086 pvt->dclr1 = 0;
1087
1088 return (flag) ? 2 : 1;
1089}
1090
Borislav Petkov70046622011-01-10 14:37:27 +01001091/* On F10h and later ErrAddr is MC4_ADDR[47:1] */
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001092static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m)
Doug Thompsonddff8762009-04-27 16:14:52 +02001093{
Borislav Petkov2ec591a2015-02-17 10:58:34 +01001094 u16 mce_nid = amd_get_nb_id(m->extcpu);
1095 struct mem_ctl_info *mci;
Borislav Petkov70046622011-01-10 14:37:27 +01001096 u8 start_bit = 1;
1097 u8 end_bit = 47;
Borislav Petkov2ec591a2015-02-17 10:58:34 +01001098 u64 addr;
1099
1100 mci = edac_mc_find(mce_nid);
1101 if (!mci)
1102 return 0;
1103
1104 pvt = mci->pvt_info;
Borislav Petkov70046622011-01-10 14:37:27 +01001105
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001106 if (pvt->fam == 0xf) {
Borislav Petkov70046622011-01-10 14:37:27 +01001107 start_bit = 3;
1108 end_bit = 39;
1109 }
1110
Chen, Gong10ef6b02013-10-18 14:29:07 -07001111 addr = m->addr & GENMASK_ULL(end_bit, start_bit);
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001112
1113 /*
1114 * Erratum 637 workaround
1115 */
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001116 if (pvt->fam == 0x15) {
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001117 u64 cc6_base, tmp_addr;
1118 u32 tmp;
Daniel J Blueman8b84c8d2012-11-27 14:32:10 +08001119 u8 intlv_en;
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001120
Chen, Gong10ef6b02013-10-18 14:29:07 -07001121 if ((addr & GENMASK_ULL(47, 24)) >> 24 != 0x00fdf7)
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001122 return addr;
1123
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001124
1125 amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_LIM, &tmp);
1126 intlv_en = tmp >> 21 & 0x7;
1127
1128 /* add [47:27] + 3 trailing bits */
Chen, Gong10ef6b02013-10-18 14:29:07 -07001129 cc6_base = (tmp & GENMASK_ULL(20, 0)) << 3;
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001130
1131 /* reverse and add DramIntlvEn */
1132 cc6_base |= intlv_en ^ 0x7;
1133
1134 /* pin at [47:24] */
1135 cc6_base <<= 24;
1136
1137 if (!intlv_en)
Chen, Gong10ef6b02013-10-18 14:29:07 -07001138 return cc6_base | (addr & GENMASK_ULL(23, 0));
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001139
1140 amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_BASE, &tmp);
1141
1142 /* faster log2 */
Chen, Gong10ef6b02013-10-18 14:29:07 -07001143 tmp_addr = (addr & GENMASK_ULL(23, 12)) << __fls(intlv_en + 1);
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001144
1145 /* OR DramIntlvSel into bits [14:12] */
Chen, Gong10ef6b02013-10-18 14:29:07 -07001146 tmp_addr |= (tmp & GENMASK_ULL(23, 21)) >> 9;
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001147
1148 /* add remaining [11:0] bits from original MC4_ADDR */
Chen, Gong10ef6b02013-10-18 14:29:07 -07001149 tmp_addr |= addr & GENMASK_ULL(11, 0);
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001150
1151 return cc6_base | tmp_addr;
1152 }
1153
1154 return addr;
Doug Thompsonddff8762009-04-27 16:14:52 +02001155}
1156
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001157static struct pci_dev *pci_get_related_function(unsigned int vendor,
1158 unsigned int device,
1159 struct pci_dev *related)
1160{
1161 struct pci_dev *dev = NULL;
1162
1163 while ((dev = pci_get_device(vendor, device, dev))) {
1164 if (pci_domain_nr(dev->bus) == pci_domain_nr(related->bus) &&
1165 (dev->bus->number == related->bus->number) &&
1166 (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
1167 break;
1168 }
1169
1170 return dev;
1171}
1172
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001173static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
Doug Thompsonddff8762009-04-27 16:14:52 +02001174{
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001175 struct amd_northbridge *nb;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001176 struct pci_dev *f1 = NULL;
1177 unsigned int pci_func;
Borislav Petkov71d2a322011-02-21 19:37:24 +01001178 int off = range << 3;
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001179 u32 llim;
Doug Thompsonddff8762009-04-27 16:14:52 +02001180
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001181 amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo);
1182 amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
Doug Thompsonddff8762009-04-27 16:14:52 +02001183
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001184 if (pvt->fam == 0xf)
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001185 return;
Doug Thompsonddff8762009-04-27 16:14:52 +02001186
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001187 if (!dram_rw(pvt, range))
1188 return;
Doug Thompsonddff8762009-04-27 16:14:52 +02001189
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001190 amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi);
1191 amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
Borislav Petkovf08e4572011-03-21 20:45:06 +01001192
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001193 /* F15h: factor in CC6 save area by reading dst node's limit reg */
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001194 if (pvt->fam != 0x15)
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001195 return;
Borislav Petkovf08e4572011-03-21 20:45:06 +01001196
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001197 nb = node_to_amd_nb(dram_dst_node(pvt, range));
1198 if (WARN_ON(!nb))
1199 return;
Borislav Petkovf08e4572011-03-21 20:45:06 +01001200
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001201 if (pvt->model == 0x60)
1202 pci_func = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1;
1203 else if (pvt->model == 0x30)
1204 pci_func = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1;
1205 else
1206 pci_func = PCI_DEVICE_ID_AMD_15H_NB_F1;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001207
1208 f1 = pci_get_related_function(nb->misc->vendor, pci_func, nb->misc);
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001209 if (WARN_ON(!f1))
1210 return;
Borislav Petkovf08e4572011-03-21 20:45:06 +01001211
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001212 amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
Borislav Petkovf08e4572011-03-21 20:45:06 +01001213
Chen, Gong10ef6b02013-10-18 14:29:07 -07001214 pvt->ranges[range].lim.lo &= GENMASK_ULL(15, 0);
Borislav Petkovf08e4572011-03-21 20:45:06 +01001215
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001216 /* {[39:27],111b} */
1217 pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
Borislav Petkovf08e4572011-03-21 20:45:06 +01001218
Chen, Gong10ef6b02013-10-18 14:29:07 -07001219 pvt->ranges[range].lim.hi &= GENMASK_ULL(7, 0);
Borislav Petkovf08e4572011-03-21 20:45:06 +01001220
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001221 /* [47:40] */
1222 pvt->ranges[range].lim.hi |= llim >> 13;
1223
1224 pci_dev_put(f1);
Doug Thompsonddff8762009-04-27 16:14:52 +02001225}
1226
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001227static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
Borislav Petkov33ca0642012-08-30 18:01:36 +02001228 struct err_info *err)
Doug Thompsonddff8762009-04-27 16:14:52 +02001229{
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001230 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompsonddff8762009-04-27 16:14:52 +02001231
Borislav Petkov33ca0642012-08-30 18:01:36 +02001232 error_address_to_page_and_offset(sys_addr, err);
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001233
1234 /*
1235 * Find out which node the error address belongs to. This may be
1236 * different from the node that detected the error.
1237 */
Borislav Petkov33ca0642012-08-30 18:01:36 +02001238 err->src_mci = find_mc_by_sys_addr(mci, sys_addr);
1239 if (!err->src_mci) {
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001240 amd64_mc_err(mci, "failed to map error addr 0x%lx to a node\n",
1241 (unsigned long)sys_addr);
Borislav Petkov33ca0642012-08-30 18:01:36 +02001242 err->err_code = ERR_NODE;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001243 return;
1244 }
1245
1246 /* Now map the sys_addr to a CSROW */
Borislav Petkov33ca0642012-08-30 18:01:36 +02001247 err->csrow = sys_addr_to_csrow(err->src_mci, sys_addr);
1248 if (err->csrow < 0) {
1249 err->err_code = ERR_CSROW;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001250 return;
1251 }
1252
Doug Thompsonddff8762009-04-27 16:14:52 +02001253 /* CHIPKILL enabled */
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001254 if (pvt->nbcfg & NBCFG_CHIPKILL) {
Borislav Petkov33ca0642012-08-30 18:01:36 +02001255 err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome);
1256 if (err->channel < 0) {
Doug Thompsonddff8762009-04-27 16:14:52 +02001257 /*
1258 * Syndrome didn't map, so we don't know which of the
1259 * 2 DIMMs is in error. So we need to ID 'both' of them
1260 * as suspect.
1261 */
Borislav Petkov33ca0642012-08-30 18:01:36 +02001262 amd64_mc_warn(err->src_mci, "unknown syndrome 0x%04x - "
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001263 "possible error reporting race\n",
Borislav Petkov33ca0642012-08-30 18:01:36 +02001264 err->syndrome);
1265 err->err_code = ERR_CHANNEL;
Doug Thompsonddff8762009-04-27 16:14:52 +02001266 return;
1267 }
1268 } else {
1269 /*
1270 * non-chipkill ecc mode
1271 *
1272 * The k8 documentation is unclear about how to determine the
1273 * channel number when using non-chipkill memory. This method
1274 * was obtained from email communication with someone at AMD.
1275 * (Wish the email was placed in this comment - norsk)
1276 */
Borislav Petkov33ca0642012-08-30 18:01:36 +02001277 err->channel = ((sys_addr & BIT(3)) != 0);
Doug Thompsonddff8762009-04-27 16:14:52 +02001278 }
Doug Thompsonddff8762009-04-27 16:14:52 +02001279}
1280
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001281static int ddr2_cs_size(unsigned i, bool dct_width)
Doug Thompsonddff8762009-04-27 16:14:52 +02001282{
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001283 unsigned shift = 0;
Doug Thompsonddff8762009-04-27 16:14:52 +02001284
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001285 if (i <= 2)
1286 shift = i;
1287 else if (!(i & 0x1))
1288 shift = i >> 1;
Borislav Petkov1433eb92009-10-21 13:44:36 +02001289 else
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001290 shift = (i + 1) >> 1;
Doug Thompsonddff8762009-04-27 16:14:52 +02001291
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001292 return 128 << (shift + !!dct_width);
1293}
1294
1295static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001296 unsigned cs_mode, int cs_mask_nr)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001297{
1298 u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
1299
1300 if (pvt->ext_model >= K8_REV_F) {
1301 WARN_ON(cs_mode > 11);
1302 return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
1303 }
1304 else if (pvt->ext_model >= K8_REV_D) {
Borislav Petkov11b0a312011-11-09 21:28:43 +01001305 unsigned diff;
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001306 WARN_ON(cs_mode > 10);
1307
Borislav Petkov11b0a312011-11-09 21:28:43 +01001308 /*
1309 * the below calculation, besides trying to win an obfuscated C
1310 * contest, maps cs_mode values to DIMM chip select sizes. The
1311 * mappings are:
1312 *
1313 * cs_mode CS size (mb)
1314 * ======= ============
1315 * 0 32
1316 * 1 64
1317 * 2 128
1318 * 3 128
1319 * 4 256
1320 * 5 512
1321 * 6 256
1322 * 7 512
1323 * 8 1024
1324 * 9 1024
1325 * 10 2048
1326 *
1327 * Basically, it calculates a value with which to shift the
1328 * smallest CS size of 32MB.
1329 *
1330 * ddr[23]_cs_size have a similar purpose.
1331 */
1332 diff = cs_mode/3 + (unsigned)(cs_mode > 5);
1333
1334 return 32 << (cs_mode - diff);
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001335 }
1336 else {
1337 WARN_ON(cs_mode > 6);
1338 return 32 << cs_mode;
1339 }
Doug Thompsonddff8762009-04-27 16:14:52 +02001340}
1341
Doug Thompson1afd3c92009-04-27 16:16:50 +02001342/*
1343 * Get the number of DCT channels in use.
1344 *
1345 * Return:
1346 * number of Memory Channels in operation
1347 * Pass back:
1348 * contents of the DCL0_LOW register
1349 */
Borislav Petkov7d20d142011-01-07 17:58:04 +01001350static int f1x_early_channel_count(struct amd64_pvt *pvt)
Doug Thompson1afd3c92009-04-27 16:16:50 +02001351{
Borislav Petkov6ba5dcd2009-10-13 19:26:55 +02001352 int i, j, channels = 0;
Doug Thompsonddff8762009-04-27 16:14:52 +02001353
Borislav Petkov7d20d142011-01-07 17:58:04 +01001354 /* On F10h, if we are in 128 bit mode, then we are using 2 channels */
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001355 if (pvt->fam == 0x10 && (pvt->dclr0 & WIDTH_128))
Borislav Petkov7d20d142011-01-07 17:58:04 +01001356 return 2;
Doug Thompson1afd3c92009-04-27 16:16:50 +02001357
1358 /*
Borislav Petkovd16149e2009-10-16 19:55:49 +02001359 * Need to check if in unganged mode: In such, there are 2 channels,
1360 * but they are not in 128 bit mode and thus the above 'dclr0' status
1361 * bit will be OFF.
Doug Thompson1afd3c92009-04-27 16:16:50 +02001362 *
1363 * Need to check DCT0[0] and DCT1[0] to see if only one of them has
1364 * their CSEnable bit on. If so, then SINGLE DIMM case.
1365 */
Joe Perches956b9ba2012-04-29 17:08:39 -03001366 edac_dbg(0, "Data width is not 128 bits - need more decoding\n");
Doug Thompson1afd3c92009-04-27 16:16:50 +02001367
1368 /*
1369 * Check DRAM Bank Address Mapping values for each DIMM to see if there
1370 * is more than just one DIMM present in unganged mode. Need to check
1371 * both controllers since DIMMs can be placed in either one.
1372 */
Borislav Petkov525a1b22010-12-21 15:53:27 +01001373 for (i = 0; i < 2; i++) {
1374 u32 dbam = (i ? pvt->dbam1 : pvt->dbam0);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001375
Wan Wei57a30852009-08-07 17:04:49 +02001376 for (j = 0; j < 4; j++) {
1377 if (DBAM_DIMM(j, dbam) > 0) {
1378 channels++;
1379 break;
1380 }
1381 }
Doug Thompson1afd3c92009-04-27 16:16:50 +02001382 }
1383
Borislav Petkovd16149e2009-10-16 19:55:49 +02001384 if (channels > 2)
1385 channels = 2;
1386
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001387 amd64_info("MCT channel count: %d\n", channels);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001388
1389 return channels;
Doug Thompson1afd3c92009-04-27 16:16:50 +02001390}
1391
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05001392static int f17_early_channel_count(struct amd64_pvt *pvt)
1393{
1394 int i, channels = 0;
1395
1396 /* SDP Control bit 31 (SdpInit) is clear for unused UMC channels */
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +00001397 for_each_umc(i)
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05001398 channels += !!(pvt->umc[i].sdp_ctrl & UMC_SDP_INIT);
1399
1400 amd64_info("MCT channel count: %d\n", channels);
1401
1402 return channels;
1403}
1404
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001405static int ddr3_cs_size(unsigned i, bool dct_width)
Doug Thompson1afd3c92009-04-27 16:16:50 +02001406{
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001407 unsigned shift = 0;
1408 int cs_size = 0;
1409
1410 if (i == 0 || i == 3 || i == 4)
1411 cs_size = -1;
1412 else if (i <= 2)
1413 shift = i;
1414 else if (i == 12)
1415 shift = 7;
1416 else if (!(i & 0x1))
1417 shift = i >> 1;
1418 else
1419 shift = (i + 1) >> 1;
1420
1421 if (cs_size != -1)
1422 cs_size = (128 * (1 << !!dct_width)) << shift;
1423
1424 return cs_size;
1425}
1426
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001427static int ddr3_lrdimm_cs_size(unsigned i, unsigned rank_multiply)
1428{
1429 unsigned shift = 0;
1430 int cs_size = 0;
1431
1432 if (i < 4 || i == 6)
1433 cs_size = -1;
1434 else if (i == 12)
1435 shift = 7;
1436 else if (!(i & 0x1))
1437 shift = i >> 1;
1438 else
1439 shift = (i + 1) >> 1;
1440
1441 if (cs_size != -1)
1442 cs_size = rank_multiply * (128 << shift);
1443
1444 return cs_size;
1445}
1446
1447static int ddr4_cs_size(unsigned i)
1448{
1449 int cs_size = 0;
1450
1451 if (i == 0)
1452 cs_size = -1;
1453 else if (i == 1)
1454 cs_size = 1024;
1455 else
1456 /* Min cs_size = 1G */
1457 cs_size = 1024 * (1 << (i >> 1));
1458
1459 return cs_size;
1460}
1461
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001462static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001463 unsigned cs_mode, int cs_mask_nr)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001464{
1465 u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
1466
1467 WARN_ON(cs_mode > 11);
Borislav Petkov1433eb92009-10-21 13:44:36 +02001468
1469 if (pvt->dchr0 & DDR3_MODE || pvt->dchr1 & DDR3_MODE)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001470 return ddr3_cs_size(cs_mode, dclr & WIDTH_128);
Borislav Petkov1433eb92009-10-21 13:44:36 +02001471 else
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001472 return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
1473}
Borislav Petkov1433eb92009-10-21 13:44:36 +02001474
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001475/*
1476 * F15h supports only 64bit DCT interfaces
1477 */
1478static int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001479 unsigned cs_mode, int cs_mask_nr)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001480{
1481 WARN_ON(cs_mode > 12);
1482
1483 return ddr3_cs_size(cs_mode, false);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001484}
1485
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001486/* F15h M60h supports DDR4 mapping as well.. */
1487static int f15_m60h_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
1488 unsigned cs_mode, int cs_mask_nr)
1489{
1490 int cs_size;
1491 u32 dcsm = pvt->csels[dct].csmasks[cs_mask_nr];
1492
1493 WARN_ON(cs_mode > 12);
1494
1495 if (pvt->dram_type == MEM_DDR4) {
1496 if (cs_mode > 9)
1497 return -1;
1498
1499 cs_size = ddr4_cs_size(cs_mode);
1500 } else if (pvt->dram_type == MEM_LRDDR3) {
1501 unsigned rank_multiply = dcsm & 0xf;
1502
1503 if (rank_multiply == 3)
1504 rank_multiply = 4;
1505 cs_size = ddr3_lrdimm_cs_size(cs_mode, rank_multiply);
1506 } else {
1507 /* Minimum cs size is 512mb for F15hM60h*/
1508 if (cs_mode == 0x1)
1509 return -1;
1510
1511 cs_size = ddr3_cs_size(cs_mode, false);
1512 }
1513
1514 return cs_size;
1515}
1516
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05001517/*
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001518 * F16h and F15h model 30h have only limited cs_modes.
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05001519 */
1520static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001521 unsigned cs_mode, int cs_mask_nr)
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05001522{
1523 WARN_ON(cs_mode > 12);
1524
1525 if (cs_mode == 6 || cs_mode == 8 ||
1526 cs_mode == 9 || cs_mode == 12)
1527 return -1;
1528 else
1529 return ddr3_cs_size(cs_mode, false);
1530}
1531
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05001532static int f17_base_addr_to_cs_size(struct amd64_pvt *pvt, u8 umc,
1533 unsigned int cs_mode, int csrow_nr)
1534{
1535 u32 base_addr = pvt->csels[umc].csbases[csrow_nr];
1536
1537 /* Each mask is used for every two base addresses. */
1538 u32 addr_mask = pvt->csels[umc].csmasks[csrow_nr >> 1];
1539
1540 /* Register [31:1] = Address [39:9]. Size is in kBs here. */
1541 u32 size = ((addr_mask >> 1) - (base_addr >> 1) + 1) >> 1;
1542
1543 edac_dbg(1, "BaseAddr: 0x%x, AddrMask: 0x%x\n", base_addr, addr_mask);
1544
1545 /* Return size in MBs. */
1546 return size >> 10;
1547}
1548
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001549static void read_dram_ctl_register(struct amd64_pvt *pvt)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001550{
Doug Thompson6163b5d2009-04-27 16:20:17 +02001551
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001552 if (pvt->fam == 0xf)
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001553 return;
1554
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05001555 if (!amd64_read_pci_cfg(pvt->F2, DCT_SEL_LO, &pvt->dct_sel_lo)) {
Joe Perches956b9ba2012-04-29 17:08:39 -03001556 edac_dbg(0, "F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x\n",
1557 pvt->dct_sel_lo, dct_sel_baseaddr(pvt));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001558
Joe Perches956b9ba2012-04-29 17:08:39 -03001559 edac_dbg(0, " DCTs operate in %s mode\n",
1560 (dct_ganging_enabled(pvt) ? "ganged" : "unganged"));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001561
Borislav Petkov72381bd2009-10-09 19:14:43 +02001562 if (!dct_ganging_enabled(pvt))
Joe Perches956b9ba2012-04-29 17:08:39 -03001563 edac_dbg(0, " Address range split per DCT: %s\n",
1564 (dct_high_range_enabled(pvt) ? "yes" : "no"));
Borislav Petkov72381bd2009-10-09 19:14:43 +02001565
Joe Perches956b9ba2012-04-29 17:08:39 -03001566 edac_dbg(0, " data interleave for ECC: %s, DRAM cleared since last warm reset: %s\n",
1567 (dct_data_intlv_enabled(pvt) ? "enabled" : "disabled"),
1568 (dct_memory_cleared(pvt) ? "yes" : "no"));
Borislav Petkov72381bd2009-10-09 19:14:43 +02001569
Joe Perches956b9ba2012-04-29 17:08:39 -03001570 edac_dbg(0, " channel interleave: %s, "
1571 "interleave bits selector: 0x%x\n",
1572 (dct_interleave_enabled(pvt) ? "enabled" : "disabled"),
1573 dct_sel_interleave_addr(pvt));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001574 }
1575
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05001576 amd64_read_pci_cfg(pvt->F2, DCT_SEL_HI, &pvt->dct_sel_hi);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001577}
1578
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001579/*
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001580 * Determine channel (DCT) based on the interleaving mode (see F15h M30h BKDG,
1581 * 2.10.12 Memory Interleaving Modes).
1582 */
1583static u8 f15_m30h_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
1584 u8 intlv_en, int num_dcts_intlv,
1585 u32 dct_sel)
1586{
1587 u8 channel = 0;
1588 u8 select;
1589
1590 if (!(intlv_en))
1591 return (u8)(dct_sel);
1592
1593 if (num_dcts_intlv == 2) {
1594 select = (sys_addr >> 8) & 0x3;
1595 channel = select ? 0x3 : 0;
Aravind Gopalakrishnan9d0e8d82014-01-21 15:03:36 -06001596 } else if (num_dcts_intlv == 4) {
1597 u8 intlv_addr = dct_sel_interleave_addr(pvt);
1598 switch (intlv_addr) {
1599 case 0x4:
1600 channel = (sys_addr >> 8) & 0x3;
1601 break;
1602 case 0x5:
1603 channel = (sys_addr >> 9) & 0x3;
1604 break;
1605 }
1606 }
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001607 return channel;
1608}
1609
1610/*
Borislav Petkov229a7a12010-12-09 18:57:54 +01001611 * Determine channel (DCT) based on the interleaving mode: F10h BKDG, 2.8.9 Memory
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001612 * Interleaving Modes.
1613 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001614static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
Borislav Petkov229a7a12010-12-09 18:57:54 +01001615 bool hi_range_sel, u8 intlv_en)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001616{
Borislav Petkov151fa712011-02-21 19:33:10 +01001617 u8 dct_sel_high = (pvt->dct_sel_lo >> 1) & 1;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001618
1619 if (dct_ganging_enabled(pvt))
Borislav Petkov229a7a12010-12-09 18:57:54 +01001620 return 0;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001621
Borislav Petkov229a7a12010-12-09 18:57:54 +01001622 if (hi_range_sel)
1623 return dct_sel_high;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001624
Borislav Petkov229a7a12010-12-09 18:57:54 +01001625 /*
1626 * see F2x110[DctSelIntLvAddr] - channel interleave mode
1627 */
1628 if (dct_interleave_enabled(pvt)) {
1629 u8 intlv_addr = dct_sel_interleave_addr(pvt);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001630
Borislav Petkov229a7a12010-12-09 18:57:54 +01001631 /* return DCT select function: 0=DCT0, 1=DCT1 */
1632 if (!intlv_addr)
1633 return sys_addr >> 6 & 1;
1634
1635 if (intlv_addr & 0x2) {
1636 u8 shift = intlv_addr & 0x1 ? 9 : 6;
Yazen Ghannamdc0a50a82016-08-03 10:59:15 -04001637 u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) & 1;
Borislav Petkov229a7a12010-12-09 18:57:54 +01001638
1639 return ((sys_addr >> shift) & 1) ^ temp;
1640 }
1641
Yazen Ghannamdc0a50a82016-08-03 10:59:15 -04001642 if (intlv_addr & 0x4) {
1643 u8 shift = intlv_addr & 0x1 ? 9 : 8;
1644
1645 return (sys_addr >> shift) & 1;
1646 }
1647
Borislav Petkov229a7a12010-12-09 18:57:54 +01001648 return (sys_addr >> (12 + hweight8(intlv_en))) & 1;
1649 }
1650
1651 if (dct_high_range_enabled(pvt))
1652 return ~dct_sel_high & 1;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001653
1654 return 0;
1655}
1656
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001657/* Convert the sys_addr to the normalized DCT address */
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08001658static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range,
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001659 u64 sys_addr, bool hi_rng,
1660 u32 dct_sel_base_addr)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001661{
1662 u64 chan_off;
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001663 u64 dram_base = get_dram_base(pvt, range);
1664 u64 hole_off = f10_dhar_offset(pvt);
Dan Carpenter6f3508f2016-01-20 12:54:51 +03001665 u64 dct_sel_base_off = (u64)(pvt->dct_sel_hi & 0xFFFFFC00) << 16;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001666
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001667 if (hi_rng) {
1668 /*
1669 * if
1670 * base address of high range is below 4Gb
1671 * (bits [47:27] at [31:11])
1672 * DRAM address space on this DCT is hoisted above 4Gb &&
1673 * sys_addr > 4Gb
1674 *
1675 * remove hole offset from sys_addr
1676 * else
1677 * remove high range offset from sys_addr
1678 */
1679 if ((!(dct_sel_base_addr >> 16) ||
1680 dct_sel_base_addr < dhar_base(pvt)) &&
Borislav Petkov972ea172011-02-21 19:43:02 +01001681 dhar_valid(pvt) &&
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001682 (sys_addr >= BIT_64(32)))
Borislav Petkovbc21fa52010-11-11 17:29:13 +01001683 chan_off = hole_off;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001684 else
1685 chan_off = dct_sel_base_off;
1686 } else {
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001687 /*
1688 * if
1689 * we have a valid hole &&
1690 * sys_addr > 4Gb
1691 *
1692 * remove hole
1693 * else
1694 * remove dram base to normalize to DCT address
1695 */
Borislav Petkov972ea172011-02-21 19:43:02 +01001696 if (dhar_valid(pvt) && (sys_addr >= BIT_64(32)))
Borislav Petkovbc21fa52010-11-11 17:29:13 +01001697 chan_off = hole_off;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001698 else
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001699 chan_off = dram_base;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001700 }
1701
Chen, Gong10ef6b02013-10-18 14:29:07 -07001702 return (sys_addr & GENMASK_ULL(47,6)) - (chan_off & GENMASK_ULL(47,23));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001703}
1704
Doug Thompson6163b5d2009-04-27 16:20:17 +02001705/*
1706 * checks if the csrow passed in is marked as SPARED, if so returns the new
1707 * spare row
1708 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001709static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001710{
Borislav Petkov614ec9d2011-01-13 18:02:22 +01001711 int tmp_cs;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001712
Borislav Petkov614ec9d2011-01-13 18:02:22 +01001713 if (online_spare_swap_done(pvt, dct) &&
1714 csrow == online_spare_bad_dramcs(pvt, dct)) {
1715
1716 for_each_chip_select(tmp_cs, dct, pvt) {
1717 if (chip_select_base(tmp_cs, dct, pvt) & 0x2) {
1718 csrow = tmp_cs;
1719 break;
1720 }
1721 }
Doug Thompson6163b5d2009-04-27 16:20:17 +02001722 }
1723 return csrow;
1724}
1725
1726/*
1727 * Iterate over the DRAM DCT "base" and "mask" registers looking for a
1728 * SystemAddr match on the specified 'ChannelSelect' and 'NodeID'
1729 *
1730 * Return:
1731 * -EINVAL: NOT FOUND
1732 * 0..csrow = Chip-Select Row
1733 */
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08001734static int f1x_lookup_addr_in_dct(u64 in_addr, u8 nid, u8 dct)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001735{
1736 struct mem_ctl_info *mci;
1737 struct amd64_pvt *pvt;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001738 u64 cs_base, cs_mask;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001739 int cs_found = -EINVAL;
1740 int csrow;
1741
Borislav Petkov2ec591a2015-02-17 10:58:34 +01001742 mci = edac_mc_find(nid);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001743 if (!mci)
1744 return cs_found;
1745
1746 pvt = mci->pvt_info;
1747
Joe Perches956b9ba2012-04-29 17:08:39 -03001748 edac_dbg(1, "input addr: 0x%llx, DCT: %d\n", in_addr, dct);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001749
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001750 for_each_chip_select(csrow, dct, pvt) {
1751 if (!csrow_enabled(csrow, dct, pvt))
Doug Thompson6163b5d2009-04-27 16:20:17 +02001752 continue;
1753
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001754 get_cs_base_and_mask(pvt, csrow, dct, &cs_base, &cs_mask);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001755
Joe Perches956b9ba2012-04-29 17:08:39 -03001756 edac_dbg(1, " CSROW=%d CSBase=0x%llx CSMask=0x%llx\n",
1757 csrow, cs_base, cs_mask);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001758
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001759 cs_mask = ~cs_mask;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001760
Joe Perches956b9ba2012-04-29 17:08:39 -03001761 edac_dbg(1, " (InputAddr & ~CSMask)=0x%llx (CSBase & ~CSMask)=0x%llx\n",
1762 (in_addr & cs_mask), (cs_base & cs_mask));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001763
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001764 if ((in_addr & cs_mask) == (cs_base & cs_mask)) {
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001765 if (pvt->fam == 0x15 && pvt->model >= 0x30) {
1766 cs_found = csrow;
1767 break;
1768 }
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001769 cs_found = f10_process_possible_spare(pvt, dct, csrow);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001770
Joe Perches956b9ba2012-04-29 17:08:39 -03001771 edac_dbg(1, " MATCH csrow=%d\n", cs_found);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001772 break;
1773 }
1774 }
1775 return cs_found;
1776}
1777
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001778/*
1779 * See F2x10C. Non-interleaved graphics framebuffer memory under the 16G is
1780 * swapped with a region located at the bottom of memory so that the GPU can use
1781 * the interleaved region and thus two channels.
1782 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001783static u64 f1x_swap_interleaved_region(struct amd64_pvt *pvt, u64 sys_addr)
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001784{
1785 u32 swap_reg, swap_base, swap_limit, rgn_size, tmp_addr;
1786
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001787 if (pvt->fam == 0x10) {
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001788 /* only revC3 and revE have that feature */
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001789 if (pvt->model < 4 || (pvt->model < 0xa && pvt->stepping < 3))
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001790 return sys_addr;
1791 }
1792
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05001793 amd64_read_pci_cfg(pvt->F2, SWAP_INTLV_REG, &swap_reg);
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001794
1795 if (!(swap_reg & 0x1))
1796 return sys_addr;
1797
1798 swap_base = (swap_reg >> 3) & 0x7f;
1799 swap_limit = (swap_reg >> 11) & 0x7f;
1800 rgn_size = (swap_reg >> 20) & 0x7f;
1801 tmp_addr = sys_addr >> 27;
1802
1803 if (!(sys_addr >> 34) &&
1804 (((tmp_addr >= swap_base) &&
1805 (tmp_addr <= swap_limit)) ||
1806 (tmp_addr < rgn_size)))
1807 return sys_addr ^ (u64)swap_base << 27;
1808
1809 return sys_addr;
1810}
1811
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001812/* For a given @dram_range, check if @sys_addr falls within it. */
Borislav Petkove761359a2011-02-21 19:49:01 +01001813static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
Borislav Petkov33ca0642012-08-30 18:01:36 +02001814 u64 sys_addr, int *chan_sel)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001815{
Borislav Petkov229a7a12010-12-09 18:57:54 +01001816 int cs_found = -EINVAL;
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001817 u64 chan_addr;
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001818 u32 dct_sel_base;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001819 u8 channel;
Borislav Petkov229a7a12010-12-09 18:57:54 +01001820 bool high_range = false;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001821
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001822 u8 node_id = dram_dst_node(pvt, range);
Borislav Petkov229a7a12010-12-09 18:57:54 +01001823 u8 intlv_en = dram_intlv_en(pvt, range);
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001824 u32 intlv_sel = dram_intlv_sel(pvt, range);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001825
Joe Perches956b9ba2012-04-29 17:08:39 -03001826 edac_dbg(1, "(range %d) SystemAddr= 0x%llx Limit=0x%llx\n",
1827 range, sys_addr, get_dram_limit(pvt, range));
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001828
Borislav Petkov355fba62011-01-17 13:03:26 +01001829 if (dhar_valid(pvt) &&
1830 dhar_base(pvt) <= sys_addr &&
1831 sys_addr < BIT_64(32)) {
1832 amd64_warn("Huh? Address is in the MMIO hole: 0x%016llx\n",
1833 sys_addr);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001834 return -EINVAL;
Borislav Petkov355fba62011-01-17 13:03:26 +01001835 }
1836
Borislav Petkovf030ddf2011-04-08 15:05:21 +02001837 if (intlv_en && (intlv_sel != ((sys_addr >> 12) & intlv_en)))
Borislav Petkov355fba62011-01-17 13:03:26 +01001838 return -EINVAL;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001839
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001840 sys_addr = f1x_swap_interleaved_region(pvt, sys_addr);
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001841
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001842 dct_sel_base = dct_sel_baseaddr(pvt);
1843
1844 /*
1845 * check whether addresses >= DctSelBaseAddr[47:27] are to be used to
1846 * select between DCT0 and DCT1.
1847 */
1848 if (dct_high_range_enabled(pvt) &&
1849 !dct_ganging_enabled(pvt) &&
1850 ((sys_addr >> 27) >= (dct_sel_base >> 11)))
Borislav Petkov229a7a12010-12-09 18:57:54 +01001851 high_range = true;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001852
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001853 channel = f1x_determine_channel(pvt, sys_addr, high_range, intlv_en);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001854
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001855 chan_addr = f1x_get_norm_dct_addr(pvt, range, sys_addr,
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001856 high_range, dct_sel_base);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001857
Borislav Petkove2f79db2011-01-13 14:57:34 +01001858 /* Remove node interleaving, see F1x120 */
1859 if (intlv_en)
1860 chan_addr = ((chan_addr >> (12 + hweight8(intlv_en))) << 12) |
1861 (chan_addr & 0xfff);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001862
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001863 /* remove channel interleave */
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001864 if (dct_interleave_enabled(pvt) &&
1865 !dct_high_range_enabled(pvt) &&
1866 !dct_ganging_enabled(pvt)) {
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001867
1868 if (dct_sel_interleave_addr(pvt) != 1) {
1869 if (dct_sel_interleave_addr(pvt) == 0x3)
1870 /* hash 9 */
1871 chan_addr = ((chan_addr >> 10) << 9) |
1872 (chan_addr & 0x1ff);
1873 else
1874 /* A[6] or hash 6 */
1875 chan_addr = ((chan_addr >> 7) << 6) |
1876 (chan_addr & 0x3f);
1877 } else
1878 /* A[12] */
1879 chan_addr = ((chan_addr >> 13) << 12) |
1880 (chan_addr & 0xfff);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001881 }
1882
Joe Perches956b9ba2012-04-29 17:08:39 -03001883 edac_dbg(1, " Normalized DCT addr: 0x%llx\n", chan_addr);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001884
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001885 cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, channel);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001886
Borislav Petkov33ca0642012-08-30 18:01:36 +02001887 if (cs_found >= 0)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001888 *chan_sel = channel;
Borislav Petkov33ca0642012-08-30 18:01:36 +02001889
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001890 return cs_found;
1891}
1892
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001893static int f15_m30h_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
1894 u64 sys_addr, int *chan_sel)
1895{
1896 int cs_found = -EINVAL;
1897 int num_dcts_intlv = 0;
1898 u64 chan_addr, chan_offset;
1899 u64 dct_base, dct_limit;
1900 u32 dct_cont_base_reg, dct_cont_limit_reg, tmp;
1901 u8 channel, alias_channel, leg_mmio_hole, dct_sel, dct_offset_en;
1902
1903 u64 dhar_offset = f10_dhar_offset(pvt);
1904 u8 intlv_addr = dct_sel_interleave_addr(pvt);
1905 u8 node_id = dram_dst_node(pvt, range);
1906 u8 intlv_en = dram_intlv_en(pvt, range);
1907
1908 amd64_read_pci_cfg(pvt->F1, DRAM_CONT_BASE, &dct_cont_base_reg);
1909 amd64_read_pci_cfg(pvt->F1, DRAM_CONT_LIMIT, &dct_cont_limit_reg);
1910
1911 dct_offset_en = (u8) ((dct_cont_base_reg >> 3) & BIT(0));
1912 dct_sel = (u8) ((dct_cont_base_reg >> 4) & 0x7);
1913
1914 edac_dbg(1, "(range %d) SystemAddr= 0x%llx Limit=0x%llx\n",
1915 range, sys_addr, get_dram_limit(pvt, range));
1916
1917 if (!(get_dram_base(pvt, range) <= sys_addr) &&
1918 !(get_dram_limit(pvt, range) >= sys_addr))
1919 return -EINVAL;
1920
1921 if (dhar_valid(pvt) &&
1922 dhar_base(pvt) <= sys_addr &&
1923 sys_addr < BIT_64(32)) {
1924 amd64_warn("Huh? Address is in the MMIO hole: 0x%016llx\n",
1925 sys_addr);
1926 return -EINVAL;
1927 }
1928
1929 /* Verify sys_addr is within DCT Range. */
Aravind Gopalakrishnan4fc06b32013-08-24 10:47:48 -05001930 dct_base = (u64) dct_sel_baseaddr(pvt);
1931 dct_limit = (dct_cont_limit_reg >> 11) & 0x1FFF;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001932
1933 if (!(dct_cont_base_reg & BIT(0)) &&
Aravind Gopalakrishnan4fc06b32013-08-24 10:47:48 -05001934 !(dct_base <= (sys_addr >> 27) &&
1935 dct_limit >= (sys_addr >> 27)))
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001936 return -EINVAL;
1937
1938 /* Verify number of dct's that participate in channel interleaving. */
1939 num_dcts_intlv = (int) hweight8(intlv_en);
1940
1941 if (!(num_dcts_intlv % 2 == 0) || (num_dcts_intlv > 4))
1942 return -EINVAL;
1943
Yazen Ghannamdc0a50a82016-08-03 10:59:15 -04001944 if (pvt->model >= 0x60)
1945 channel = f1x_determine_channel(pvt, sys_addr, false, intlv_en);
1946 else
1947 channel = f15_m30h_determine_channel(pvt, sys_addr, intlv_en,
1948 num_dcts_intlv, dct_sel);
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001949
1950 /* Verify we stay within the MAX number of channels allowed */
Aravind Gopalakrishnan7f3f5242013-12-04 11:40:11 -06001951 if (channel > 3)
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001952 return -EINVAL;
1953
1954 leg_mmio_hole = (u8) (dct_cont_base_reg >> 1 & BIT(0));
1955
1956 /* Get normalized DCT addr */
1957 if (leg_mmio_hole && (sys_addr >= BIT_64(32)))
1958 chan_offset = dhar_offset;
1959 else
Aravind Gopalakrishnan4fc06b32013-08-24 10:47:48 -05001960 chan_offset = dct_base << 27;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001961
1962 chan_addr = sys_addr - chan_offset;
1963
1964 /* remove channel interleave */
1965 if (num_dcts_intlv == 2) {
1966 if (intlv_addr == 0x4)
1967 chan_addr = ((chan_addr >> 9) << 8) |
1968 (chan_addr & 0xff);
1969 else if (intlv_addr == 0x5)
1970 chan_addr = ((chan_addr >> 10) << 9) |
1971 (chan_addr & 0x1ff);
1972 else
1973 return -EINVAL;
1974
1975 } else if (num_dcts_intlv == 4) {
1976 if (intlv_addr == 0x4)
1977 chan_addr = ((chan_addr >> 10) << 8) |
1978 (chan_addr & 0xff);
1979 else if (intlv_addr == 0x5)
1980 chan_addr = ((chan_addr >> 11) << 9) |
1981 (chan_addr & 0x1ff);
1982 else
1983 return -EINVAL;
1984 }
1985
1986 if (dct_offset_en) {
1987 amd64_read_pci_cfg(pvt->F1,
1988 DRAM_CONT_HIGH_OFF + (int) channel * 4,
1989 &tmp);
Aravind Gopalakrishnan4fc06b32013-08-24 10:47:48 -05001990 chan_addr += (u64) ((tmp >> 11) & 0xfff) << 27;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001991 }
1992
1993 f15h_select_dct(pvt, channel);
1994
1995 edac_dbg(1, " Normalized DCT addr: 0x%llx\n", chan_addr);
1996
1997 /*
1998 * Find Chip select:
1999 * if channel = 3, then alias it to 1. This is because, in F15 M30h,
2000 * there is support for 4 DCT's, but only 2 are currently functional.
2001 * They are DCT0 and DCT3. But we have read all registers of DCT3 into
2002 * pvt->csels[1]. So we need to use '1' here to get correct info.
2003 * Refer F15 M30h BKDG Section 2.10 and 2.10.3 for clarifications.
2004 */
2005 alias_channel = (channel == 3) ? 1 : channel;
2006
2007 cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, alias_channel);
2008
2009 if (cs_found >= 0)
2010 *chan_sel = alias_channel;
2011
2012 return cs_found;
2013}
2014
2015static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt,
2016 u64 sys_addr,
2017 int *chan_sel)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002018{
Borislav Petkove761359a2011-02-21 19:49:01 +01002019 int cs_found = -EINVAL;
2020 unsigned range;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002021
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002022 for (range = 0; range < DRAM_RANGES; range++) {
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002023 if (!dram_rw(pvt, range))
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002024 continue;
2025
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05002026 if (pvt->fam == 0x15 && pvt->model >= 0x30)
2027 cs_found = f15_m30h_match_to_this_node(pvt, range,
2028 sys_addr,
2029 chan_sel);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002030
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05002031 else if ((get_dram_base(pvt, range) <= sys_addr) &&
2032 (get_dram_limit(pvt, range) >= sys_addr)) {
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01002033 cs_found = f1x_match_to_this_node(pvt, range,
Borislav Petkov33ca0642012-08-30 18:01:36 +02002034 sys_addr, chan_sel);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002035 if (cs_found >= 0)
2036 break;
2037 }
2038 }
2039 return cs_found;
2040}
2041
2042/*
Borislav Petkovbdc30a02009-11-13 15:10:43 +01002043 * For reference see "2.8.5 Routing DRAM Requests" in F10 BKDG. This code maps
2044 * a @sys_addr to NodeID, DCT (channel) and chip select (CSROW).
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002045 *
Borislav Petkovbdc30a02009-11-13 15:10:43 +01002046 * The @sys_addr is usually an error address received from the hardware
2047 * (MCX_ADDR).
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002048 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01002049static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
Borislav Petkov33ca0642012-08-30 18:01:36 +02002050 struct err_info *err)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002051{
2052 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002053
Borislav Petkov33ca0642012-08-30 18:01:36 +02002054 error_address_to_page_and_offset(sys_addr, err);
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03002055
Borislav Petkov33ca0642012-08-30 18:01:36 +02002056 err->csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &err->channel);
2057 if (err->csrow < 0) {
2058 err->err_code = ERR_CSROW;
Borislav Petkovbdc30a02009-11-13 15:10:43 +01002059 return;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002060 }
Borislav Petkovbdc30a02009-11-13 15:10:43 +01002061
Borislav Petkovbdc30a02009-11-13 15:10:43 +01002062 /*
2063 * We need the syndromes for channel detection only when we're
2064 * ganged. Otherwise @chan should already contain the channel at
2065 * this point.
2066 */
Borislav Petkova97fa682010-12-23 14:07:18 +01002067 if (dct_ganging_enabled(pvt))
Borislav Petkov33ca0642012-08-30 18:01:36 +02002068 err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002069}
2070
2071/*
Borislav Petkov8566c4d2009-10-16 13:48:28 +02002072 * debug routine to display the memory sizes of all logical DIMMs and its
Borislav Petkovcb328502010-12-22 14:28:24 +01002073 * CSROWs
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002074 */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01002075static void debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002076{
Borislav Petkovbb89f5a2012-09-12 18:06:00 +02002077 int dimm, size0, size1;
Borislav Petkov525a1b22010-12-21 15:53:27 +01002078 u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases;
2079 u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002080
Borislav Petkova4b4bed2013-08-10 13:54:48 +02002081 if (pvt->fam == 0xf) {
Borislav Petkov8566c4d2009-10-16 13:48:28 +02002082 /* K8 families < revF not supported yet */
Borislav Petkov1433eb92009-10-21 13:44:36 +02002083 if (pvt->ext_model < K8_REV_F)
Borislav Petkov8566c4d2009-10-16 13:48:28 +02002084 return;
2085 else
2086 WARN_ON(ctrl != 0);
2087 }
2088
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05002089 if (pvt->fam == 0x10) {
2090 dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1
2091 : pvt->dbam0;
2092 dcsb = (ctrl && !dct_ganging_enabled(pvt)) ?
2093 pvt->csels[1].csbases :
2094 pvt->csels[0].csbases;
2095 } else if (ctrl) {
2096 dbam = pvt->dbam0;
2097 dcsb = pvt->csels[1].csbases;
2098 }
Joe Perches956b9ba2012-04-29 17:08:39 -03002099 edac_dbg(1, "F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n",
2100 ctrl, dbam);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002101
Borislav Petkov8566c4d2009-10-16 13:48:28 +02002102 edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl);
2103
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002104 /* Dump memory sizes for DIMM and its CSROWs */
2105 for (dimm = 0; dimm < 4; dimm++) {
2106
2107 size0 = 0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002108 if (dcsb[dimm*2] & DCSB_CS_ENABLE)
Yazen Ghannam07ed82e2016-11-28 08:50:21 -06002109 /*
2110 * For F15m60h, we need multiplier for LRDIMM cs_size
2111 * calculation. We pass dimm value to the dbam_to_cs
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002112 * mapper so we can find the multiplier from the
2113 * corresponding DCSM.
2114 */
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01002115 size0 = pvt->ops->dbam_to_cs(pvt, ctrl,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002116 DBAM_DIMM(dimm, dbam),
2117 dimm);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002118
2119 size1 = 0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002120 if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01002121 size1 = pvt->ops->dbam_to_cs(pvt, ctrl,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002122 DBAM_DIMM(dimm, dbam),
2123 dimm);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002124
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002125 amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
Borislav Petkovbb89f5a2012-09-12 18:06:00 +02002126 dimm * 2, size0,
2127 dimm * 2 + 1, size1);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002128 }
2129}
2130
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01002131static struct amd64_family_type family_types[] = {
Doug Thompson4d376072009-04-27 16:25:05 +02002132 [K8_CPUS] = {
Borislav Petkov0092b202010-10-01 19:20:05 +02002133 .ctl_name = "K8",
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002134 .f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002135 .f2_id = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL,
Doug Thompson4d376072009-04-27 16:25:05 +02002136 .ops = {
Borislav Petkov1433eb92009-10-21 13:44:36 +02002137 .early_channel_count = k8_early_channel_count,
Borislav Petkov1433eb92009-10-21 13:44:36 +02002138 .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow,
2139 .dbam_to_cs = k8_dbam_to_chip_select,
Doug Thompson4d376072009-04-27 16:25:05 +02002140 }
2141 },
2142 [F10_CPUS] = {
Borislav Petkov0092b202010-10-01 19:20:05 +02002143 .ctl_name = "F10h",
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002144 .f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002145 .f2_id = PCI_DEVICE_ID_AMD_10H_NB_DRAM,
Doug Thompson4d376072009-04-27 16:25:05 +02002146 .ops = {
Borislav Petkov7d20d142011-01-07 17:58:04 +01002147 .early_channel_count = f1x_early_channel_count,
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01002148 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
Borislav Petkov1433eb92009-10-21 13:44:36 +02002149 .dbam_to_cs = f10_dbam_to_chip_select,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02002150 }
2151 },
2152 [F15_CPUS] = {
2153 .ctl_name = "F15h",
Borislav Petkovdf71a052011-01-19 18:15:10 +01002154 .f1_id = PCI_DEVICE_ID_AMD_15H_NB_F1,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002155 .f2_id = PCI_DEVICE_ID_AMD_15H_NB_F2,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02002156 .ops = {
Borislav Petkov7d20d142011-01-07 17:58:04 +01002157 .early_channel_count = f1x_early_channel_count,
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01002158 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01002159 .dbam_to_cs = f15_dbam_to_chip_select,
Doug Thompson4d376072009-04-27 16:25:05 +02002160 }
2161 },
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05002162 [F15_M30H_CPUS] = {
2163 .ctl_name = "F15h_M30h",
2164 .f1_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002165 .f2_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F2,
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05002166 .ops = {
2167 .early_channel_count = f1x_early_channel_count,
2168 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
2169 .dbam_to_cs = f16_dbam_to_chip_select,
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05002170 }
2171 },
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002172 [F15_M60H_CPUS] = {
2173 .ctl_name = "F15h_M60h",
2174 .f1_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002175 .f2_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F2,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002176 .ops = {
2177 .early_channel_count = f1x_early_channel_count,
2178 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
2179 .dbam_to_cs = f15_m60h_dbam_to_chip_select,
2180 }
2181 },
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05002182 [F16_CPUS] = {
2183 .ctl_name = "F16h",
2184 .f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002185 .f2_id = PCI_DEVICE_ID_AMD_16H_NB_F2,
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05002186 .ops = {
2187 .early_channel_count = f1x_early_channel_count,
2188 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
2189 .dbam_to_cs = f16_dbam_to_chip_select,
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05002190 }
2191 },
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -06002192 [F16_M30H_CPUS] = {
2193 .ctl_name = "F16h_M30h",
2194 .f1_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F1,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002195 .f2_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F2,
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -06002196 .ops = {
2197 .early_channel_count = f1x_early_channel_count,
2198 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
2199 .dbam_to_cs = f16_dbam_to_chip_select,
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -06002200 }
2201 },
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05002202 [F17_CPUS] = {
2203 .ctl_name = "F17h",
2204 .f0_id = PCI_DEVICE_ID_AMD_17H_DF_F0,
2205 .f6_id = PCI_DEVICE_ID_AMD_17H_DF_F6,
2206 .ops = {
2207 .early_channel_count = f17_early_channel_count,
2208 .dbam_to_cs = f17_base_addr_to_cs_size,
2209 }
2210 },
Michael Jin8960de42018-08-16 15:28:40 -04002211 [F17_M10H_CPUS] = {
2212 .ctl_name = "F17h_M10h",
2213 .f0_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F0,
2214 .f6_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F6,
2215 .ops = {
2216 .early_channel_count = f17_early_channel_count,
2217 .dbam_to_cs = f17_base_addr_to_cs_size,
2218 }
2219 },
Yazen Ghannam6e8462392019-02-28 15:36:09 +00002220 [F17_M30H_CPUS] = {
2221 .ctl_name = "F17h_M30h",
2222 .f0_id = PCI_DEVICE_ID_AMD_17H_M30H_DF_F0,
2223 .f6_id = PCI_DEVICE_ID_AMD_17H_M30H_DF_F6,
2224 .ops = {
2225 .early_channel_count = f17_early_channel_count,
2226 .dbam_to_cs = f17_base_addr_to_cs_size,
2227 }
2228 },
Doug Thompson4d376072009-04-27 16:25:05 +02002229};
2230
Doug Thompsonb1289d62009-04-27 16:37:05 +02002231/*
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002232 * These are tables of eigenvectors (one per line) which can be used for the
2233 * construction of the syndrome tables. The modified syndrome search algorithm
2234 * uses those to find the symbol in error and thus the DIMM.
Doug Thompsonb1289d62009-04-27 16:37:05 +02002235 *
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002236 * Algorithm courtesy of Ross LaFetra from AMD.
Doug Thompsonb1289d62009-04-27 16:37:05 +02002237 */
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08002238static const u16 x4_vectors[] = {
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002239 0x2f57, 0x1afe, 0x66cc, 0xdd88,
2240 0x11eb, 0x3396, 0x7f4c, 0xeac8,
2241 0x0001, 0x0002, 0x0004, 0x0008,
2242 0x1013, 0x3032, 0x4044, 0x8088,
2243 0x106b, 0x30d6, 0x70fc, 0xe0a8,
2244 0x4857, 0xc4fe, 0x13cc, 0x3288,
2245 0x1ac5, 0x2f4a, 0x5394, 0xa1e8,
2246 0x1f39, 0x251e, 0xbd6c, 0x6bd8,
2247 0x15c1, 0x2a42, 0x89ac, 0x4758,
2248 0x2b03, 0x1602, 0x4f0c, 0xca08,
2249 0x1f07, 0x3a0e, 0x6b04, 0xbd08,
2250 0x8ba7, 0x465e, 0x244c, 0x1cc8,
2251 0x2b87, 0x164e, 0x642c, 0xdc18,
2252 0x40b9, 0x80de, 0x1094, 0x20e8,
2253 0x27db, 0x1eb6, 0x9dac, 0x7b58,
2254 0x11c1, 0x2242, 0x84ac, 0x4c58,
2255 0x1be5, 0x2d7a, 0x5e34, 0xa718,
2256 0x4b39, 0x8d1e, 0x14b4, 0x28d8,
2257 0x4c97, 0xc87e, 0x11fc, 0x33a8,
2258 0x8e97, 0x497e, 0x2ffc, 0x1aa8,
2259 0x16b3, 0x3d62, 0x4f34, 0x8518,
2260 0x1e2f, 0x391a, 0x5cac, 0xf858,
2261 0x1d9f, 0x3b7a, 0x572c, 0xfe18,
2262 0x15f5, 0x2a5a, 0x5264, 0xa3b8,
2263 0x1dbb, 0x3b66, 0x715c, 0xe3f8,
2264 0x4397, 0xc27e, 0x17fc, 0x3ea8,
2265 0x1617, 0x3d3e, 0x6464, 0xb8b8,
2266 0x23ff, 0x12aa, 0xab6c, 0x56d8,
2267 0x2dfb, 0x1ba6, 0x913c, 0x7328,
2268 0x185d, 0x2ca6, 0x7914, 0x9e28,
2269 0x171b, 0x3e36, 0x7d7c, 0xebe8,
2270 0x4199, 0x82ee, 0x19f4, 0x2e58,
2271 0x4807, 0xc40e, 0x130c, 0x3208,
2272 0x1905, 0x2e0a, 0x5804, 0xac08,
2273 0x213f, 0x132a, 0xadfc, 0x5ba8,
2274 0x19a9, 0x2efe, 0xb5cc, 0x6f88,
Doug Thompsonb1289d62009-04-27 16:37:05 +02002275};
2276
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08002277static const u16 x8_vectors[] = {
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002278 0x0145, 0x028a, 0x2374, 0x43c8, 0xa1f0, 0x0520, 0x0a40, 0x1480,
2279 0x0211, 0x0422, 0x0844, 0x1088, 0x01b0, 0x44e0, 0x23c0, 0xed80,
2280 0x1011, 0x0116, 0x022c, 0x0458, 0x08b0, 0x8c60, 0x2740, 0x4e80,
2281 0x0411, 0x0822, 0x1044, 0x0158, 0x02b0, 0x2360, 0x46c0, 0xab80,
2282 0x0811, 0x1022, 0x012c, 0x0258, 0x04b0, 0x4660, 0x8cc0, 0x2780,
2283 0x2071, 0x40e2, 0xa0c4, 0x0108, 0x0210, 0x0420, 0x0840, 0x1080,
2284 0x4071, 0x80e2, 0x0104, 0x0208, 0x0410, 0x0820, 0x1040, 0x2080,
2285 0x8071, 0x0102, 0x0204, 0x0408, 0x0810, 0x1020, 0x2040, 0x4080,
2286 0x019d, 0x03d6, 0x136c, 0x2198, 0x50b0, 0xb2e0, 0x0740, 0x0e80,
2287 0x0189, 0x03ea, 0x072c, 0x0e58, 0x1cb0, 0x56e0, 0x37c0, 0xf580,
2288 0x01fd, 0x0376, 0x06ec, 0x0bb8, 0x1110, 0x2220, 0x4440, 0x8880,
2289 0x0163, 0x02c6, 0x1104, 0x0758, 0x0eb0, 0x2be0, 0x6140, 0xc280,
2290 0x02fd, 0x01c6, 0x0b5c, 0x1108, 0x07b0, 0x25a0, 0x8840, 0x6180,
2291 0x0801, 0x012e, 0x025c, 0x04b8, 0x1370, 0x26e0, 0x57c0, 0xb580,
2292 0x0401, 0x0802, 0x015c, 0x02b8, 0x22b0, 0x13e0, 0x7140, 0xe280,
2293 0x0201, 0x0402, 0x0804, 0x01b8, 0x11b0, 0x31a0, 0x8040, 0x7180,
2294 0x0101, 0x0202, 0x0404, 0x0808, 0x1010, 0x2020, 0x4040, 0x8080,
2295 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
2296 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
2297};
2298
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08002299static int decode_syndrome(u16 syndrome, const u16 *vectors, unsigned num_vecs,
Borislav Petkovd34a6ec2011-02-23 17:41:50 +01002300 unsigned v_dim)
Doug Thompsonb1289d62009-04-27 16:37:05 +02002301{
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002302 unsigned int i, err_sym;
Doug Thompsonb1289d62009-04-27 16:37:05 +02002303
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002304 for (err_sym = 0; err_sym < num_vecs / v_dim; err_sym++) {
2305 u16 s = syndrome;
Borislav Petkovd34a6ec2011-02-23 17:41:50 +01002306 unsigned v_idx = err_sym * v_dim;
2307 unsigned v_end = (err_sym + 1) * v_dim;
Doug Thompsonb1289d62009-04-27 16:37:05 +02002308
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002309 /* walk over all 16 bits of the syndrome */
2310 for (i = 1; i < (1U << 16); i <<= 1) {
2311
2312 /* if bit is set in that eigenvector... */
2313 if (v_idx < v_end && vectors[v_idx] & i) {
2314 u16 ev_comp = vectors[v_idx++];
2315
2316 /* ... and bit set in the modified syndrome, */
2317 if (s & i) {
2318 /* remove it. */
2319 s ^= ev_comp;
2320
2321 if (!s)
2322 return err_sym;
2323 }
2324
2325 } else if (s & i)
2326 /* can't get to zero, move to next symbol */
2327 break;
2328 }
Doug Thompsonb1289d62009-04-27 16:37:05 +02002329 }
2330
Joe Perches956b9ba2012-04-29 17:08:39 -03002331 edac_dbg(0, "syndrome(%x) not found\n", syndrome);
Doug Thompsonb1289d62009-04-27 16:37:05 +02002332 return -1;
2333}
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002334
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002335static int map_err_sym_to_channel(int err_sym, int sym_size)
2336{
2337 if (sym_size == 4)
2338 switch (err_sym) {
2339 case 0x20:
2340 case 0x21:
2341 return 0;
2342 break;
2343 case 0x22:
2344 case 0x23:
2345 return 1;
2346 break;
2347 default:
2348 return err_sym >> 4;
2349 break;
2350 }
2351 /* x8 symbols */
2352 else
2353 switch (err_sym) {
2354 /* imaginary bits not in a DIMM */
2355 case 0x10:
2356 WARN(1, KERN_ERR "Invalid error symbol: 0x%x\n",
2357 err_sym);
2358 return -1;
2359 break;
2360
2361 case 0x11:
2362 return 0;
2363 break;
2364 case 0x12:
2365 return 1;
2366 break;
2367 default:
2368 return err_sym >> 3;
2369 break;
2370 }
2371 return -1;
2372}
2373
2374static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
2375{
2376 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002377 int err_sym = -1;
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002378
Borislav Petkova3b7db02011-01-19 20:35:12 +01002379 if (pvt->ecc_sym_sz == 8)
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002380 err_sym = decode_syndrome(syndrome, x8_vectors,
2381 ARRAY_SIZE(x8_vectors),
Borislav Petkova3b7db02011-01-19 20:35:12 +01002382 pvt->ecc_sym_sz);
2383 else if (pvt->ecc_sym_sz == 4)
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002384 err_sym = decode_syndrome(syndrome, x4_vectors,
2385 ARRAY_SIZE(x4_vectors),
Borislav Petkova3b7db02011-01-19 20:35:12 +01002386 pvt->ecc_sym_sz);
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002387 else {
Borislav Petkova3b7db02011-01-19 20:35:12 +01002388 amd64_warn("Illegal syndrome type: %u\n", pvt->ecc_sym_sz);
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002389 return err_sym;
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002390 }
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002391
Borislav Petkova3b7db02011-01-19 20:35:12 +01002392 return map_err_sym_to_channel(err_sym, pvt->ecc_sym_sz);
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002393}
2394
Yazen Ghanname70984d2016-11-17 17:57:31 -05002395static void __log_ecc_error(struct mem_ctl_info *mci, struct err_info *err,
Borislav Petkov33ca0642012-08-30 18:01:36 +02002396 u8 ecc_type)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002397{
Borislav Petkov33ca0642012-08-30 18:01:36 +02002398 enum hw_event_mc_err_type err_type;
2399 const char *string;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002400
Borislav Petkov33ca0642012-08-30 18:01:36 +02002401 if (ecc_type == 2)
2402 err_type = HW_EVENT_ERR_CORRECTED;
2403 else if (ecc_type == 1)
2404 err_type = HW_EVENT_ERR_UNCORRECTED;
Yazen Ghannamd12a9692016-11-17 17:57:32 -05002405 else if (ecc_type == 3)
2406 err_type = HW_EVENT_ERR_DEFERRED;
Borislav Petkov33ca0642012-08-30 18:01:36 +02002407 else {
2408 WARN(1, "Something is rotten in the state of Denmark.\n");
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002409 return;
2410 }
2411
Borislav Petkov33ca0642012-08-30 18:01:36 +02002412 switch (err->err_code) {
2413 case DECODE_OK:
2414 string = "";
2415 break;
2416 case ERR_NODE:
2417 string = "Failed to map error addr to a node";
2418 break;
2419 case ERR_CSROW:
2420 string = "Failed to map error addr to a csrow";
2421 break;
2422 case ERR_CHANNEL:
Yazen Ghannam713ad542016-11-28 12:59:53 -06002423 string = "Unknown syndrome - possible error reporting race";
2424 break;
2425 case ERR_SYND:
2426 string = "MCA_SYND not valid - unknown syndrome and csrow";
2427 break;
2428 case ERR_NORM_ADDR:
2429 string = "Cannot decode normalized address";
Borislav Petkov33ca0642012-08-30 18:01:36 +02002430 break;
2431 default:
2432 string = "WTF error";
2433 break;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002434 }
Borislav Petkov33ca0642012-08-30 18:01:36 +02002435
2436 edac_mc_handle_error(err_type, mci, 1,
2437 err->page, err->offset, err->syndrome,
2438 err->csrow, err->channel, -1,
2439 string, "");
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002440}
2441
Borislav Petkovdf781d02013-12-15 17:29:44 +01002442static inline void decode_bus_error(int node_id, struct mce *m)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002443{
Daniel J Blueman0c510cc2015-02-17 11:34:38 +08002444 struct mem_ctl_info *mci;
2445 struct amd64_pvt *pvt;
Borislav Petkovf192c7b2011-01-10 14:24:32 +01002446 u8 ecc_type = (m->status >> 45) & 0x3;
Borislav Petkov66fed2d2012-08-09 18:41:07 +02002447 u8 xec = XEC(m->status, 0x1f);
2448 u16 ec = EC(m->status);
Borislav Petkov33ca0642012-08-30 18:01:36 +02002449 u64 sys_addr;
2450 struct err_info err;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002451
Daniel J Blueman0c510cc2015-02-17 11:34:38 +08002452 mci = edac_mc_find(node_id);
2453 if (!mci)
2454 return;
2455
2456 pvt = mci->pvt_info;
2457
Borislav Petkov66fed2d2012-08-09 18:41:07 +02002458 /* Bail out early if this was an 'observed' error */
Borislav Petkov5980bb92011-01-07 16:26:49 +01002459 if (PP(ec) == NBSL_PP_OBS)
Borislav Petkovb70ef012009-06-25 19:32:38 +02002460 return;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002461
Borislav Petkovecaf5602009-07-23 16:32:01 +02002462 /* Do only ECC errors */
2463 if (xec && xec != F10_NBSL_EXT_ERR_ECC)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002464 return;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002465
Borislav Petkov33ca0642012-08-30 18:01:36 +02002466 memset(&err, 0, sizeof(err));
2467
Borislav Petkova4b4bed2013-08-10 13:54:48 +02002468 sys_addr = get_error_address(pvt, m);
Borislav Petkov33ca0642012-08-30 18:01:36 +02002469
Borislav Petkovecaf5602009-07-23 16:32:01 +02002470 if (ecc_type == 2)
Borislav Petkov33ca0642012-08-30 18:01:36 +02002471 err.syndrome = extract_syndrome(m->status);
2472
2473 pvt->ops->map_sysaddr_to_csrow(mci, sys_addr, &err);
2474
Yazen Ghanname70984d2016-11-17 17:57:31 -05002475 __log_ecc_error(mci, &err, ecc_type);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002476}
2477
Doug Thompson0ec449e2009-04-27 19:41:25 +02002478/*
Yazen Ghannam713ad542016-11-28 12:59:53 -06002479 * To find the UMC channel represented by this bank we need to match on its
2480 * instance_id. The instance_id of a bank is held in the lower 32 bits of its
2481 * IPID.
Yazen Ghannambdcee772019-02-28 15:36:10 +00002482 *
2483 * Currently, we can derive the channel number by looking at the 6th nibble in
2484 * the instance_id. For example, instance_id=0xYXXXXX where Y is the channel
2485 * number.
Yazen Ghannam713ad542016-11-28 12:59:53 -06002486 */
Yazen Ghannambdcee772019-02-28 15:36:10 +00002487static int find_umc_channel(struct mce *m)
Yazen Ghannam713ad542016-11-28 12:59:53 -06002488{
Yazen Ghannambdcee772019-02-28 15:36:10 +00002489 return (m->ipid & GENMASK(31, 0)) >> 20;
Yazen Ghannam713ad542016-11-28 12:59:53 -06002490}
2491
2492static void decode_umc_error(int node_id, struct mce *m)
2493{
2494 u8 ecc_type = (m->status >> 45) & 0x3;
2495 struct mem_ctl_info *mci;
2496 struct amd64_pvt *pvt;
2497 struct err_info err;
2498 u64 sys_addr;
2499
2500 mci = edac_mc_find(node_id);
2501 if (!mci)
2502 return;
2503
2504 pvt = mci->pvt_info;
2505
2506 memset(&err, 0, sizeof(err));
2507
2508 if (m->status & MCI_STATUS_DEFERRED)
2509 ecc_type = 3;
2510
Yazen Ghannambdcee772019-02-28 15:36:10 +00002511 err.channel = find_umc_channel(m);
Yazen Ghannam713ad542016-11-28 12:59:53 -06002512
2513 if (umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, err.channel, &sys_addr)) {
2514 err.err_code = ERR_NORM_ADDR;
2515 goto log_error;
2516 }
2517
2518 error_address_to_page_and_offset(sys_addr, &err);
2519
2520 if (!(m->status & MCI_STATUS_SYNDV)) {
2521 err.err_code = ERR_SYND;
2522 goto log_error;
2523 }
2524
2525 if (ecc_type == 2) {
2526 u8 length = (m->synd >> 18) & 0x3f;
2527
2528 if (length)
2529 err.syndrome = (m->synd >> 32) & GENMASK(length - 1, 0);
2530 else
2531 err.err_code = ERR_CHANNEL;
2532 }
2533
2534 err.csrow = m->synd & 0x7;
2535
2536log_error:
2537 __log_ecc_error(mci, &err, ecc_type);
2538}
2539
2540/*
Borislav Petkov3f37a362016-05-06 19:44:27 +02002541 * Use pvt->F3 which contains the F3 CPU PCI device to get the related
2542 * F1 (AddrMap) and F2 (Dct) devices. Return negative value on error.
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002543 * Reserve F0 and F6 on systems with a UMC.
Doug Thompson0ec449e2009-04-27 19:41:25 +02002544 */
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002545static int
2546reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 pci_id1, u16 pci_id2)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002547{
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002548 if (pvt->umc) {
2549 pvt->F0 = pci_get_related_function(pvt->F3->vendor, pci_id1, pvt->F3);
2550 if (!pvt->F0) {
Borislav Petkov5246c542016-12-01 11:35:07 +01002551 amd64_err("F0 not found, device 0x%x (broken BIOS?)\n", pci_id1);
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002552 return -ENODEV;
2553 }
2554
2555 pvt->F6 = pci_get_related_function(pvt->F3->vendor, pci_id2, pvt->F3);
2556 if (!pvt->F6) {
2557 pci_dev_put(pvt->F0);
2558 pvt->F0 = NULL;
2559
Borislav Petkov5246c542016-12-01 11:35:07 +01002560 amd64_err("F6 not found: device 0x%x (broken BIOS?)\n", pci_id2);
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002561 return -ENODEV;
2562 }
Borislav Petkov5246c542016-12-01 11:35:07 +01002563
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002564 edac_dbg(1, "F0: %s\n", pci_name(pvt->F0));
2565 edac_dbg(1, "F3: %s\n", pci_name(pvt->F3));
2566 edac_dbg(1, "F6: %s\n", pci_name(pvt->F6));
2567
2568 return 0;
2569 }
2570
Doug Thompson0ec449e2009-04-27 19:41:25 +02002571 /* Reserve the ADDRESS MAP Device */
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002572 pvt->F1 = pci_get_related_function(pvt->F3->vendor, pci_id1, pvt->F3);
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002573 if (!pvt->F1) {
Borislav Petkov5246c542016-12-01 11:35:07 +01002574 amd64_err("F1 not found: device 0x%x (broken BIOS?)\n", pci_id1);
Borislav Petkovbbd0c1f2010-10-01 19:27:58 +02002575 return -ENODEV;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002576 }
2577
Borislav Petkov3f37a362016-05-06 19:44:27 +02002578 /* Reserve the DCT Device */
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002579 pvt->F2 = pci_get_related_function(pvt->F3->vendor, pci_id2, pvt->F3);
Borislav Petkov3f37a362016-05-06 19:44:27 +02002580 if (!pvt->F2) {
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002581 pci_dev_put(pvt->F1);
2582 pvt->F1 = NULL;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002583
Borislav Petkov5246c542016-12-01 11:35:07 +01002584 amd64_err("F2 not found: device 0x%x (broken BIOS?)\n", pci_id2);
2585 return -ENODEV;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002586 }
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002587
Joe Perches956b9ba2012-04-29 17:08:39 -03002588 edac_dbg(1, "F1: %s\n", pci_name(pvt->F1));
2589 edac_dbg(1, "F2: %s\n", pci_name(pvt->F2));
2590 edac_dbg(1, "F3: %s\n", pci_name(pvt->F3));
Doug Thompson0ec449e2009-04-27 19:41:25 +02002591
2592 return 0;
2593}
2594
Borislav Petkov360b7f32010-10-15 19:25:38 +02002595static void free_mc_sibling_devs(struct amd64_pvt *pvt)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002596{
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002597 if (pvt->umc) {
2598 pci_dev_put(pvt->F0);
2599 pci_dev_put(pvt->F6);
2600 } else {
2601 pci_dev_put(pvt->F1);
2602 pci_dev_put(pvt->F2);
2603 }
Doug Thompson0ec449e2009-04-27 19:41:25 +02002604}
2605
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002606static void determine_ecc_sym_sz(struct amd64_pvt *pvt)
2607{
2608 pvt->ecc_sym_sz = 4;
2609
2610 if (pvt->umc) {
2611 u8 i;
2612
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +00002613 for_each_umc(i) {
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002614 /* Check enabled channels only: */
2615 if ((pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) &&
2616 (pvt->umc[i].ecc_ctrl & BIT(7))) {
2617 pvt->ecc_sym_sz = 8;
2618 break;
2619 }
2620 }
2621
2622 return;
2623 }
2624
2625 if (pvt->fam >= 0x10) {
2626 u32 tmp;
2627
2628 amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
2629 /* F16h has only DCT0, so no need to read dbam1. */
2630 if (pvt->fam != 0x16)
2631 amd64_read_dct_pci_cfg(pvt, 1, DBAM0, &pvt->dbam1);
2632
2633 /* F10h, revD and later can do x8 ECC too. */
2634 if ((pvt->fam > 0x10 || pvt->model > 7) && tmp & BIT(25))
2635 pvt->ecc_sym_sz = 8;
2636 }
2637}
2638
2639/*
2640 * Retrieve the hardware registers of the memory controller.
2641 */
2642static void __read_mc_regs_df(struct amd64_pvt *pvt)
2643{
2644 u8 nid = pvt->mc_node_id;
2645 struct amd64_umc *umc;
2646 u32 i, umc_base;
2647
2648 /* Read registers from each UMC */
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +00002649 for_each_umc(i) {
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002650
2651 umc_base = get_umc_base(i);
2652 umc = &pvt->umc[i];
2653
Yazen Ghannam07ed82e2016-11-28 08:50:21 -06002654 amd_smn_read(nid, umc_base + UMCCH_DIMM_CFG, &umc->dimm_cfg);
2655 amd_smn_read(nid, umc_base + UMCCH_UMC_CFG, &umc->umc_cfg);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002656 amd_smn_read(nid, umc_base + UMCCH_SDP_CTRL, &umc->sdp_ctrl);
2657 amd_smn_read(nid, umc_base + UMCCH_ECC_CTRL, &umc->ecc_ctrl);
Yazen Ghannam07ed82e2016-11-28 08:50:21 -06002658 amd_smn_read(nid, umc_base + UMCCH_UMC_CAP_HI, &umc->umc_cap_hi);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002659 }
2660}
2661
Doug Thompson0ec449e2009-04-27 19:41:25 +02002662/*
2663 * Retrieve the hardware registers of the memory controller (this includes the
2664 * 'Address Map' and 'Misc' device regs)
2665 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02002666static void read_mc_regs(struct amd64_pvt *pvt)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002667{
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002668 unsigned int range;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002669 u64 msr_val;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002670
2671 /*
2672 * Retrieve TOP_MEM and TOP_MEM2; no masking off of reserved bits since
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002673 * those are Read-As-Zero.
Doug Thompson0ec449e2009-04-27 19:41:25 +02002674 */
Borislav Petkove97f8bb2009-10-12 15:27:45 +02002675 rdmsrl(MSR_K8_TOP_MEM1, pvt->top_mem);
Joe Perches956b9ba2012-04-29 17:08:39 -03002676 edac_dbg(0, " TOP_MEM: 0x%016llx\n", pvt->top_mem);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002677
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002678 /* Check first whether TOP_MEM2 is enabled: */
Doug Thompson0ec449e2009-04-27 19:41:25 +02002679 rdmsrl(MSR_K8_SYSCFG, msr_val);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002680 if (msr_val & BIT(21)) {
Borislav Petkove97f8bb2009-10-12 15:27:45 +02002681 rdmsrl(MSR_K8_TOP_MEM2, pvt->top_mem2);
Joe Perches956b9ba2012-04-29 17:08:39 -03002682 edac_dbg(0, " TOP_MEM2: 0x%016llx\n", pvt->top_mem2);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002683 } else {
Joe Perches956b9ba2012-04-29 17:08:39 -03002684 edac_dbg(0, " TOP_MEM2 disabled\n");
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002685 }
2686
2687 if (pvt->umc) {
2688 __read_mc_regs_df(pvt);
2689 amd64_read_pci_cfg(pvt->F0, DF_DHAR, &pvt->dhar);
2690
2691 goto skip;
2692 }
Doug Thompson0ec449e2009-04-27 19:41:25 +02002693
Borislav Petkov5980bb92011-01-07 16:26:49 +01002694 amd64_read_pci_cfg(pvt->F3, NBCAP, &pvt->nbcap);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002695
Borislav Petkov5a5d2372011-01-17 17:52:57 +01002696 read_dram_ctl_register(pvt);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002697
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002698 for (range = 0; range < DRAM_RANGES; range++) {
2699 u8 rw;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002700
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002701 /* read settings for this DRAM range */
2702 read_dram_base_limit_regs(pvt, range);
Borislav Petkove97f8bb2009-10-12 15:27:45 +02002703
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002704 rw = dram_rw(pvt, range);
2705 if (!rw)
2706 continue;
2707
Joe Perches956b9ba2012-04-29 17:08:39 -03002708 edac_dbg(1, " DRAM range[%d], base: 0x%016llx; limit: 0x%016llx\n",
2709 range,
2710 get_dram_base(pvt, range),
2711 get_dram_limit(pvt, range));
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002712
Joe Perches956b9ba2012-04-29 17:08:39 -03002713 edac_dbg(1, " IntlvEn=%s; Range access: %s%s IntlvSel=%d DstNode=%d\n",
2714 dram_intlv_en(pvt, range) ? "Enabled" : "Disabled",
2715 (rw & 0x1) ? "R" : "-",
2716 (rw & 0x2) ? "W" : "-",
2717 dram_intlv_sel(pvt, range),
2718 dram_dst_node(pvt, range));
Doug Thompson0ec449e2009-04-27 19:41:25 +02002719 }
2720
Borislav Petkovbc21fa52010-11-11 17:29:13 +01002721 amd64_read_pci_cfg(pvt->F1, DHAR, &pvt->dhar);
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05002722 amd64_read_dct_pci_cfg(pvt, 0, DBAM0, &pvt->dbam0);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002723
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002724 amd64_read_pci_cfg(pvt->F3, F10_ONLINE_SPARE, &pvt->online_spare);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002725
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05002726 amd64_read_dct_pci_cfg(pvt, 0, DCLR0, &pvt->dclr0);
2727 amd64_read_dct_pci_cfg(pvt, 0, DCHR0, &pvt->dchr0);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002728
Borislav Petkov78da1212010-12-22 19:31:45 +01002729 if (!dct_ganging_enabled(pvt)) {
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05002730 amd64_read_dct_pci_cfg(pvt, 1, DCLR0, &pvt->dclr1);
2731 amd64_read_dct_pci_cfg(pvt, 1, DCHR0, &pvt->dchr1);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002732 }
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002733
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002734skip:
2735 read_dct_base_mask(pvt);
2736
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002737 determine_memory_type(pvt);
2738 edac_dbg(1, " DIMM type: %s\n", edac_mem_types[pvt->dram_type]);
Borislav Petkova3b7db02011-01-19 20:35:12 +01002739
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002740 determine_ecc_sym_sz(pvt);
Borislav Petkova3b7db02011-01-19 20:35:12 +01002741
Borislav Petkovb2b0c602010-10-08 18:32:29 +02002742 dump_misc_regs(pvt);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002743}
2744
2745/*
2746 * NOTE: CPU Revision Dependent code
2747 *
2748 * Input:
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002749 * @csrow_nr ChipSelect Row Number (0..NUM_CHIPSELECTS-1)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002750 * k8 private pointer to -->
2751 * DRAM Bank Address mapping register
2752 * node_id
2753 * DCL register where dual_channel_active is
2754 *
2755 * The DBAM register consists of 4 sets of 4 bits each definitions:
2756 *
2757 * Bits: CSROWs
2758 * 0-3 CSROWs 0 and 1
2759 * 4-7 CSROWs 2 and 3
2760 * 8-11 CSROWs 4 and 5
2761 * 12-15 CSROWs 6 and 7
2762 *
2763 * Values range from: 0 to 15
2764 * The meaning of the values depends on CPU revision and dual-channel state,
2765 * see relevant BKDG more info.
2766 *
2767 * The memory controller provides for total of only 8 CSROWs in its current
2768 * architecture. Each "pair" of CSROWs normally represents just one DIMM in
2769 * single channel or two (2) DIMMs in dual channel mode.
2770 *
2771 * The following code logic collapses the various tables for CSROW based on CPU
2772 * revision.
2773 *
2774 * Returns:
2775 * The number of PAGE_SIZE pages on the specified CSROW number it
2776 * encompasses
2777 *
2778 */
Yazen Ghannameb77e6b2017-04-27 12:11:54 -05002779static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr_orig)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002780{
Ashish Shenoyf92cae42012-02-22 17:20:38 -08002781 u32 dbam = dct ? pvt->dbam1 : pvt->dbam0;
Yazen Ghannameb77e6b2017-04-27 12:11:54 -05002782 int csrow_nr = csrow_nr_orig;
2783 u32 cs_mode, nr_pages;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002784
Yazen Ghannameb77e6b2017-04-27 12:11:54 -05002785 if (!pvt->umc)
2786 csrow_nr >>= 1;
Borislav Petkov10de6492012-09-12 19:00:38 +02002787
Yazen Ghannameb77e6b2017-04-27 12:11:54 -05002788 cs_mode = DBAM_DIMM(csrow_nr, dbam);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002789
Yazen Ghannameb77e6b2017-04-27 12:11:54 -05002790 nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode, csrow_nr);
2791 nr_pages <<= 20 - PAGE_SHIFT;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002792
Borislav Petkov10de6492012-09-12 19:00:38 +02002793 edac_dbg(0, "csrow: %d, channel: %d, DBAM idx: %d\n",
Yazen Ghannameb77e6b2017-04-27 12:11:54 -05002794 csrow_nr_orig, dct, cs_mode);
Borislav Petkov10de6492012-09-12 19:00:38 +02002795 edac_dbg(0, "nr_pages/channel: %u\n", nr_pages);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002796
2797 return nr_pages;
2798}
2799
2800/*
2801 * Initialize the array of csrow attribute instances, based on the values
2802 * from pci config hardware registers.
2803 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02002804static int init_csrows(struct mem_ctl_info *mci)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002805{
Borislav Petkov10de6492012-09-12 19:00:38 +02002806 struct amd64_pvt *pvt = mci->pvt_info;
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06002807 enum edac_type edac_mode = EDAC_NONE;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002808 struct csrow_info *csrow;
Mauro Carvalho Chehabde3910eb2012-04-24 15:05:43 -03002809 struct dimm_info *dimm;
Borislav Petkov10de6492012-09-12 19:00:38 +02002810 int i, j, empty = 1;
Mauro Carvalho Chehaba895bf82012-01-28 09:09:38 -03002811 int nr_pages = 0;
Borislav Petkov10de6492012-09-12 19:00:38 +02002812 u32 val;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002813
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06002814 if (!pvt->umc) {
2815 amd64_read_pci_cfg(pvt->F3, NBCFG, &val);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002816
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06002817 pvt->nbcfg = val;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002818
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06002819 edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
2820 pvt->mc_node_id, val,
2821 !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
2822 }
Doug Thompson0ec449e2009-04-27 19:41:25 +02002823
Borislav Petkov10de6492012-09-12 19:00:38 +02002824 /*
2825 * We iterate over DCT0 here but we look at DCT1 in parallel, if needed.
2826 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002827 for_each_chip_select(i, 0, pvt) {
Borislav Petkov10de6492012-09-12 19:00:38 +02002828 bool row_dct0 = !!csrow_enabled(i, 0, pvt);
2829 bool row_dct1 = false;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002830
Borislav Petkova4b4bed2013-08-10 13:54:48 +02002831 if (pvt->fam != 0xf)
Borislav Petkov10de6492012-09-12 19:00:38 +02002832 row_dct1 = !!csrow_enabled(i, 1, pvt);
2833
2834 if (!row_dct0 && !row_dct1)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002835 continue;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002836
Borislav Petkov10de6492012-09-12 19:00:38 +02002837 csrow = mci->csrows[i];
Doug Thompson0ec449e2009-04-27 19:41:25 +02002838 empty = 0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002839
Borislav Petkov10de6492012-09-12 19:00:38 +02002840 edac_dbg(1, "MC node: %d, csrow: %d\n",
2841 pvt->mc_node_id, i);
2842
Mauro Carvalho Chehab1eef1282013-03-11 09:07:46 -03002843 if (row_dct0) {
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01002844 nr_pages = get_csrow_nr_pages(pvt, 0, i);
Mauro Carvalho Chehab1eef1282013-03-11 09:07:46 -03002845 csrow->channels[0]->dimm->nr_pages = nr_pages;
2846 }
Borislav Petkov10de6492012-09-12 19:00:38 +02002847
2848 /* K8 has only one DCT */
Borislav Petkova4b4bed2013-08-10 13:54:48 +02002849 if (pvt->fam != 0xf && row_dct1) {
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01002850 int row_dct1_pages = get_csrow_nr_pages(pvt, 1, i);
Mauro Carvalho Chehab1eef1282013-03-11 09:07:46 -03002851
2852 csrow->channels[1]->dimm->nr_pages = row_dct1_pages;
2853 nr_pages += row_dct1_pages;
2854 }
Doug Thompson0ec449e2009-04-27 19:41:25 +02002855
Borislav Petkov10de6492012-09-12 19:00:38 +02002856 edac_dbg(1, "Total csrow%d pages: %u\n", i, nr_pages);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002857
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06002858 /* Determine DIMM ECC mode: */
2859 if (pvt->umc) {
2860 if (mci->edac_ctl_cap & EDAC_FLAG_S4ECD4ED)
2861 edac_mode = EDAC_S4ECD4ED;
2862 else if (mci->edac_ctl_cap & EDAC_FLAG_SECDED)
2863 edac_mode = EDAC_SECDED;
2864
2865 } else if (pvt->nbcfg & NBCFG_ECC_ENABLE) {
2866 edac_mode = (pvt->nbcfg & NBCFG_CHIPKILL)
2867 ? EDAC_S4ECD4ED
2868 : EDAC_SECDED;
2869 }
Mauro Carvalho Chehab084a4fc2012-01-27 18:38:08 -03002870
2871 for (j = 0; j < pvt->channel_count; j++) {
Mauro Carvalho Chehabde3910eb2012-04-24 15:05:43 -03002872 dimm = csrow->channels[j]->dimm;
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002873 dimm->mtype = pvt->dram_type;
Mauro Carvalho Chehabde3910eb2012-04-24 15:05:43 -03002874 dimm->edac_mode = edac_mode;
Mauro Carvalho Chehab084a4fc2012-01-27 18:38:08 -03002875 }
Doug Thompson0ec449e2009-04-27 19:41:25 +02002876 }
2877
2878 return empty;
2879}
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002880
Borislav Petkov06724532009-09-16 13:05:46 +02002881/* get all cores on this DCT */
Daniel J Blueman8b84c8d2012-11-27 14:32:10 +08002882static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, u16 nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02002883{
Borislav Petkov06724532009-09-16 13:05:46 +02002884 int cpu;
Doug Thompsonf9431992009-04-27 19:46:08 +02002885
Borislav Petkov06724532009-09-16 13:05:46 +02002886 for_each_online_cpu(cpu)
2887 if (amd_get_nb_id(cpu) == nid)
2888 cpumask_set_cpu(cpu, mask);
Doug Thompsonf9431992009-04-27 19:46:08 +02002889}
2890
2891/* check MCG_CTL on all the cpus on this node */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01002892static bool nb_mce_bank_enabled_on_node(u16 nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02002893{
Rusty Russellba578cb2009-11-03 14:56:35 +10302894 cpumask_var_t mask;
Borislav Petkov50542252009-12-11 18:14:40 +01002895 int cpu, nbe;
Borislav Petkov06724532009-09-16 13:05:46 +02002896 bool ret = false;
Doug Thompsonf9431992009-04-27 19:46:08 +02002897
Rusty Russellba578cb2009-11-03 14:56:35 +10302898 if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002899 amd64_warn("%s: Error allocating mask\n", __func__);
Rusty Russellba578cb2009-11-03 14:56:35 +10302900 return false;
2901 }
Borislav Petkov06724532009-09-16 13:05:46 +02002902
Rusty Russellba578cb2009-11-03 14:56:35 +10302903 get_cpus_on_this_dct_cpumask(mask, nid);
Borislav Petkov06724532009-09-16 13:05:46 +02002904
Rusty Russellba578cb2009-11-03 14:56:35 +10302905 rdmsr_on_cpus(mask, MSR_IA32_MCG_CTL, msrs);
Borislav Petkov06724532009-09-16 13:05:46 +02002906
Rusty Russellba578cb2009-11-03 14:56:35 +10302907 for_each_cpu(cpu, mask) {
Borislav Petkov50542252009-12-11 18:14:40 +01002908 struct msr *reg = per_cpu_ptr(msrs, cpu);
Borislav Petkov5980bb92011-01-07 16:26:49 +01002909 nbe = reg->l & MSR_MCGCTL_NBE;
Borislav Petkov06724532009-09-16 13:05:46 +02002910
Joe Perches956b9ba2012-04-29 17:08:39 -03002911 edac_dbg(0, "core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n",
2912 cpu, reg->q,
2913 (nbe ? "enabled" : "disabled"));
Borislav Petkov06724532009-09-16 13:05:46 +02002914
2915 if (!nbe)
2916 goto out;
Borislav Petkov06724532009-09-16 13:05:46 +02002917 }
2918 ret = true;
2919
2920out:
Rusty Russellba578cb2009-11-03 14:56:35 +10302921 free_cpumask_var(mask);
Doug Thompsonf9431992009-04-27 19:46:08 +02002922 return ret;
2923}
2924
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08002925static int toggle_ecc_err_reporting(struct ecc_settings *s, u16 nid, bool on)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002926{
2927 cpumask_var_t cmask;
Borislav Petkov50542252009-12-11 18:14:40 +01002928 int cpu;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002929
2930 if (!zalloc_cpumask_var(&cmask, GFP_KERNEL)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002931 amd64_warn("%s: error allocating mask\n", __func__);
Pan Bian0de27882016-12-04 14:07:18 +08002932 return -ENOMEM;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002933 }
2934
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002935 get_cpus_on_this_dct_cpumask(cmask, nid);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002936
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002937 rdmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
2938
2939 for_each_cpu(cpu, cmask) {
2940
Borislav Petkov50542252009-12-11 18:14:40 +01002941 struct msr *reg = per_cpu_ptr(msrs, cpu);
2942
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002943 if (on) {
Borislav Petkov5980bb92011-01-07 16:26:49 +01002944 if (reg->l & MSR_MCGCTL_NBE)
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002945 s->flags.nb_mce_enable = 1;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002946
Borislav Petkov5980bb92011-01-07 16:26:49 +01002947 reg->l |= MSR_MCGCTL_NBE;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002948 } else {
2949 /*
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002950 * Turn off NB MCE reporting only when it was off before
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002951 */
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002952 if (!s->flags.nb_mce_enable)
Borislav Petkov5980bb92011-01-07 16:26:49 +01002953 reg->l &= ~MSR_MCGCTL_NBE;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002954 }
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002955 }
2956 wrmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
2957
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002958 free_cpumask_var(cmask);
2959
2960 return 0;
2961}
2962
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08002963static bool enable_ecc_error_reporting(struct ecc_settings *s, u16 nid,
Borislav Petkov2299ef72010-10-15 17:44:04 +02002964 struct pci_dev *F3)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002965{
Borislav Petkov2299ef72010-10-15 17:44:04 +02002966 bool ret = true;
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002967 u32 value, mask = 0x3; /* UECC/CECC enable */
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002968
Borislav Petkov2299ef72010-10-15 17:44:04 +02002969 if (toggle_ecc_err_reporting(s, nid, ON)) {
2970 amd64_warn("Error enabling ECC reporting over MCGCTL!\n");
2971 return false;
2972 }
2973
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002974 amd64_read_pci_cfg(F3, NBCTL, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002975
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002976 s->old_nbctl = value & mask;
2977 s->nbctl_valid = true;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002978
2979 value |= mask;
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002980 amd64_write_pci_cfg(F3, NBCTL, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002981
Borislav Petkova97fa682010-12-23 14:07:18 +01002982 amd64_read_pci_cfg(F3, NBCFG, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002983
Joe Perches956b9ba2012-04-29 17:08:39 -03002984 edac_dbg(0, "1: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
2985 nid, value, !!(value & NBCFG_ECC_ENABLE));
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002986
Borislav Petkova97fa682010-12-23 14:07:18 +01002987 if (!(value & NBCFG_ECC_ENABLE)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002988 amd64_warn("DRAM ECC disabled on this node, enabling...\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002989
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002990 s->flags.nb_ecc_prev = 0;
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002991
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002992 /* Attempt to turn on DRAM ECC Enable */
Borislav Petkova97fa682010-12-23 14:07:18 +01002993 value |= NBCFG_ECC_ENABLE;
2994 amd64_write_pci_cfg(F3, NBCFG, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002995
Borislav Petkova97fa682010-12-23 14:07:18 +01002996 amd64_read_pci_cfg(F3, NBCFG, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002997
Borislav Petkova97fa682010-12-23 14:07:18 +01002998 if (!(value & NBCFG_ECC_ENABLE)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002999 amd64_warn("Hardware rejected DRAM ECC enable,"
3000 "check memory DIMM configuration.\n");
Borislav Petkov2299ef72010-10-15 17:44:04 +02003001 ret = false;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003002 } else {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02003003 amd64_info("Hardware accepted DRAM ECC Enable\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003004 }
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01003005 } else {
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003006 s->flags.nb_ecc_prev = 1;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003007 }
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01003008
Joe Perches956b9ba2012-04-29 17:08:39 -03003009 edac_dbg(0, "2: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
3010 nid, value, !!(value & NBCFG_ECC_ENABLE));
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003011
Borislav Petkov2299ef72010-10-15 17:44:04 +02003012 return ret;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003013}
3014
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08003015static void restore_ecc_error_reporting(struct ecc_settings *s, u16 nid,
Borislav Petkov360b7f32010-10-15 19:25:38 +02003016 struct pci_dev *F3)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003017{
Borislav Petkovc9f4f262010-12-22 19:48:20 +01003018 u32 value, mask = 0x3; /* UECC/CECC enable */
3019
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003020 if (!s->nbctl_valid)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003021 return;
3022
Borislav Petkovc9f4f262010-12-22 19:48:20 +01003023 amd64_read_pci_cfg(F3, NBCTL, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003024 value &= ~mask;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003025 value |= s->old_nbctl;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003026
Borislav Petkovc9f4f262010-12-22 19:48:20 +01003027 amd64_write_pci_cfg(F3, NBCTL, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003028
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003029 /* restore previous BIOS DRAM ECC "off" setting we force-enabled */
3030 if (!s->flags.nb_ecc_prev) {
Borislav Petkova97fa682010-12-23 14:07:18 +01003031 amd64_read_pci_cfg(F3, NBCFG, &value);
3032 value &= ~NBCFG_ECC_ENABLE;
3033 amd64_write_pci_cfg(F3, NBCFG, value);
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01003034 }
3035
3036 /* restore the NB Enable MCGCTL bit */
Borislav Petkov2299ef72010-10-15 17:44:04 +02003037 if (toggle_ecc_err_reporting(s, nid, OFF))
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02003038 amd64_warn("Error restoring NB MCGCTL settings!\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003039}
3040
Doug Thompsonf9431992009-04-27 19:46:08 +02003041/*
Borislav Petkov2299ef72010-10-15 17:44:04 +02003042 * EDAC requires that the BIOS have ECC enabled before
3043 * taking over the processing of ECC errors. A command line
3044 * option allows to force-enable hardware ECC later in
3045 * enable_ecc_error_reporting().
Doug Thompsonf9431992009-04-27 19:46:08 +02003046 */
Borislav Petkovcab4d272010-02-11 17:15:57 +01003047static const char *ecc_msg =
3048 "ECC disabled in the BIOS or no ECC capability, module will not load.\n"
3049 " Either enable ECC checking or force module loading by setting "
3050 "'ecc_enable_override'.\n"
3051 " (Note that use of the override may cause unknown side effects.)\n";
Borislav Petkovbe3468e2009-08-05 15:47:22 +02003052
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08003053static bool ecc_enabled(struct pci_dev *F3, u16 nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02003054{
Borislav Petkov06724532009-09-16 13:05:46 +02003055 bool nb_mce_en = false;
Yazen Ghannam196b79f2016-11-17 17:57:34 -05003056 u8 ecc_en = 0, i;
3057 u32 value;
Doug Thompsonf9431992009-04-27 19:46:08 +02003058
Yazen Ghannam196b79f2016-11-17 17:57:34 -05003059 if (boot_cpu_data.x86 >= 0x17) {
3060 u8 umc_en_mask = 0, ecc_en_mask = 0;
Doug Thompsonf9431992009-04-27 19:46:08 +02003061
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +00003062 for_each_umc(i) {
Yazen Ghannam196b79f2016-11-17 17:57:34 -05003063 u32 base = get_umc_base(i);
3064
3065 /* Only check enabled UMCs. */
3066 if (amd_smn_read(nid, base + UMCCH_SDP_CTRL, &value))
3067 continue;
3068
3069 if (!(value & UMC_SDP_INIT))
3070 continue;
3071
3072 umc_en_mask |= BIT(i);
3073
3074 if (amd_smn_read(nid, base + UMCCH_UMC_CAP_HI, &value))
3075 continue;
3076
3077 if (value & UMC_ECC_ENABLED)
3078 ecc_en_mask |= BIT(i);
3079 }
3080
3081 /* Check whether at least one UMC is enabled: */
3082 if (umc_en_mask)
3083 ecc_en = umc_en_mask == ecc_en_mask;
Yazen Ghannam11ab1ca2017-01-27 11:24:19 -06003084 else
3085 edac_dbg(0, "Node %d: No enabled UMCs.\n", nid);
Yazen Ghannam196b79f2016-11-17 17:57:34 -05003086
3087 /* Assume UMC MCA banks are enabled. */
3088 nb_mce_en = true;
3089 } else {
3090 amd64_read_pci_cfg(F3, NBCFG, &value);
3091
3092 ecc_en = !!(value & NBCFG_ECC_ENABLE);
3093
3094 nb_mce_en = nb_mce_bank_enabled_on_node(nid);
3095 if (!nb_mce_en)
Yazen Ghannam11ab1ca2017-01-27 11:24:19 -06003096 edac_dbg(0, "NB MCE bank disabled, set MSR 0x%08x[4] on node %d to enable.\n",
Yazen Ghannam196b79f2016-11-17 17:57:34 -05003097 MSR_IA32_MCG_CTL, nid);
3098 }
3099
Yazen Ghannam11ab1ca2017-01-27 11:24:19 -06003100 amd64_info("Node %d: DRAM ECC %s.\n",
3101 nid, (ecc_en ? "enabled" : "disabled"));
Doug Thompsonf9431992009-04-27 19:46:08 +02003102
Borislav Petkov2299ef72010-10-15 17:44:04 +02003103 if (!ecc_en || !nb_mce_en) {
Yazen Ghannam11ab1ca2017-01-27 11:24:19 -06003104 amd64_info("%s", ecc_msg);
Borislav Petkov2299ef72010-10-15 17:44:04 +02003105 return false;
Borislav Petkov43f5e682009-12-21 18:55:18 +01003106 }
Borislav Petkov2299ef72010-10-15 17:44:04 +02003107 return true;
Doug Thompsonf9431992009-04-27 19:46:08 +02003108}
3109
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06003110static inline void
3111f17h_determine_edac_ctl_cap(struct mem_ctl_info *mci, struct amd64_pvt *pvt)
3112{
3113 u8 i, ecc_en = 1, cpk_en = 1;
3114
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +00003115 for_each_umc(i) {
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06003116 if (pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) {
3117 ecc_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_ENABLED);
3118 cpk_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_CHIPKILL_CAP);
3119 }
3120 }
3121
3122 /* Set chipkill only if ECC is enabled: */
3123 if (ecc_en) {
3124 mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
3125
3126 if (cpk_en)
3127 mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
3128 }
3129}
3130
Borislav Petkovdf71a052011-01-19 18:15:10 +01003131static void setup_mci_misc_attrs(struct mem_ctl_info *mci,
3132 struct amd64_family_type *fam)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003133{
3134 struct amd64_pvt *pvt = mci->pvt_info;
3135
3136 mci->mtype_cap = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2;
3137 mci->edac_ctl_cap = EDAC_FLAG_NONE;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003138
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06003139 if (pvt->umc) {
3140 f17h_determine_edac_ctl_cap(mci, pvt);
3141 } else {
3142 if (pvt->nbcap & NBCAP_SECDED)
3143 mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003144
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06003145 if (pvt->nbcap & NBCAP_CHIPKILL)
3146 mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
3147 }
Doug Thompson7d6034d2009-04-27 20:01:01 +02003148
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003149 mci->edac_cap = determine_edac_cap(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003150 mci->mod_name = EDAC_MOD_STR;
Borislav Petkovdf71a052011-01-19 18:15:10 +01003151 mci->ctl_name = fam->ctl_name;
Yazen Ghanname7934b72016-11-17 17:57:30 -05003152 mci->dev_name = pci_name(pvt->F3);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003153 mci->ctl_page_to_phys = NULL;
3154
Doug Thompson7d6034d2009-04-27 20:01:01 +02003155 /* memory scrubber interface */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003156 mci->set_sdram_scrub_rate = set_scrub_rate;
3157 mci->get_sdram_scrub_rate = get_scrub_rate;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003158}
3159
Borislav Petkov0092b202010-10-01 19:20:05 +02003160/*
3161 * returns a pointer to the family descriptor on success, NULL otherwise.
3162 */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003163static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
Borislav Petkov395ae782010-10-01 18:38:19 +02003164{
Borislav Petkov0092b202010-10-01 19:20:05 +02003165 struct amd64_family_type *fam_type = NULL;
3166
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003167 pvt->ext_model = boot_cpu_data.x86_model >> 4;
Jia Zhangb3991512018-01-01 09:52:10 +08003168 pvt->stepping = boot_cpu_data.x86_stepping;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003169 pvt->model = boot_cpu_data.x86_model;
3170 pvt->fam = boot_cpu_data.x86;
3171
3172 switch (pvt->fam) {
Borislav Petkov395ae782010-10-01 18:38:19 +02003173 case 0xf:
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003174 fam_type = &family_types[K8_CPUS];
3175 pvt->ops = &family_types[K8_CPUS].ops;
Borislav Petkov395ae782010-10-01 18:38:19 +02003176 break;
Borislav Petkovdf71a052011-01-19 18:15:10 +01003177
Borislav Petkov395ae782010-10-01 18:38:19 +02003178 case 0x10:
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003179 fam_type = &family_types[F10_CPUS];
3180 pvt->ops = &family_types[F10_CPUS].ops;
Borislav Petkovdf71a052011-01-19 18:15:10 +01003181 break;
3182
3183 case 0x15:
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003184 if (pvt->model == 0x30) {
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003185 fam_type = &family_types[F15_M30H_CPUS];
3186 pvt->ops = &family_types[F15_M30H_CPUS].ops;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003187 break;
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01003188 } else if (pvt->model == 0x60) {
3189 fam_type = &family_types[F15_M60H_CPUS];
3190 pvt->ops = &family_types[F15_M60H_CPUS].ops;
3191 break;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003192 }
3193
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003194 fam_type = &family_types[F15_CPUS];
3195 pvt->ops = &family_types[F15_CPUS].ops;
Borislav Petkov395ae782010-10-01 18:38:19 +02003196 break;
3197
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05003198 case 0x16:
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -06003199 if (pvt->model == 0x30) {
3200 fam_type = &family_types[F16_M30H_CPUS];
3201 pvt->ops = &family_types[F16_M30H_CPUS].ops;
3202 break;
3203 }
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003204 fam_type = &family_types[F16_CPUS];
3205 pvt->ops = &family_types[F16_CPUS].ops;
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05003206 break;
3207
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05003208 case 0x17:
Michael Jin8960de42018-08-16 15:28:40 -04003209 if (pvt->model >= 0x10 && pvt->model <= 0x2f) {
3210 fam_type = &family_types[F17_M10H_CPUS];
3211 pvt->ops = &family_types[F17_M10H_CPUS].ops;
3212 break;
Yazen Ghannam6e8462392019-02-28 15:36:09 +00003213 } else if (pvt->model >= 0x30 && pvt->model <= 0x3f) {
3214 fam_type = &family_types[F17_M30H_CPUS];
3215 pvt->ops = &family_types[F17_M30H_CPUS].ops;
3216 break;
Michael Jin8960de42018-08-16 15:28:40 -04003217 }
Pu Wenc4a3e942018-09-27 16:31:28 +02003218 /* fall through */
3219 case 0x18:
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05003220 fam_type = &family_types[F17_CPUS];
3221 pvt->ops = &family_types[F17_CPUS].ops;
Pu Wenc4a3e942018-09-27 16:31:28 +02003222
3223 if (pvt->fam == 0x18)
3224 family_types[F17_CPUS].ctl_name = "F18h";
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05003225 break;
3226
Borislav Petkov395ae782010-10-01 18:38:19 +02003227 default:
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02003228 amd64_err("Unsupported family!\n");
Borislav Petkov0092b202010-10-01 19:20:05 +02003229 return NULL;
Borislav Petkov395ae782010-10-01 18:38:19 +02003230 }
Borislav Petkov0092b202010-10-01 19:20:05 +02003231
Borislav Petkovdf71a052011-01-19 18:15:10 +01003232 amd64_info("%s %sdetected (node %d).\n", fam_type->ctl_name,
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003233 (pvt->fam == 0xf ?
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02003234 (pvt->ext_model >= K8_REV_F ? "revF or later "
3235 : "revE or earlier ")
3236 : ""), pvt->mc_node_id);
Borislav Petkov0092b202010-10-01 19:20:05 +02003237 return fam_type;
Borislav Petkov395ae782010-10-01 18:38:19 +02003238}
3239
Takashi Iwaie339f1e2015-02-04 11:48:53 +01003240static const struct attribute_group *amd64_edac_attr_groups[] = {
3241#ifdef CONFIG_EDAC_DEBUG
3242 &amd64_edac_dbg_group,
3243#endif
3244#ifdef CONFIG_EDAC_AMD64_ERROR_INJECTION
3245 &amd64_edac_inj_group,
3246#endif
3247 NULL
3248};
3249
Yazen Ghannambdcee772019-02-28 15:36:10 +00003250/* Set the number of Unified Memory Controllers in the system. */
3251static void compute_num_umcs(void)
3252{
3253 u8 model = boot_cpu_data.x86_model;
3254
3255 if (boot_cpu_data.x86 < 0x17)
3256 return;
3257
3258 if (model >= 0x30 && model <= 0x3f)
3259 num_umcs = 8;
3260 else
3261 num_umcs = 2;
3262
3263 edac_dbg(1, "Number of UMCs: %x", num_umcs);
3264}
3265
Borislav Petkov3f37a362016-05-06 19:44:27 +02003266static int init_one_instance(unsigned int nid)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003267{
Borislav Petkov3f37a362016-05-06 19:44:27 +02003268 struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
Borislav Petkov0092b202010-10-01 19:20:05 +02003269 struct amd64_family_type *fam_type = NULL;
Borislav Petkov360b7f32010-10-15 19:25:38 +02003270 struct mem_ctl_info *mci = NULL;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03003271 struct edac_mc_layer layers[2];
Borislav Petkov3f37a362016-05-06 19:44:27 +02003272 struct amd64_pvt *pvt = NULL;
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05003273 u16 pci_id1, pci_id2;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003274 int err = 0, ret;
3275
3276 ret = -ENOMEM;
3277 pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
3278 if (!pvt)
Borislav Petkov360b7f32010-10-15 19:25:38 +02003279 goto err_ret;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003280
Borislav Petkov360b7f32010-10-15 19:25:38 +02003281 pvt->mc_node_id = nid;
Borislav Petkov3f37a362016-05-06 19:44:27 +02003282 pvt->F3 = F3;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003283
Borislav Petkov395ae782010-10-01 18:38:19 +02003284 ret = -EINVAL;
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003285 fam_type = per_family_init(pvt);
Borislav Petkov0092b202010-10-01 19:20:05 +02003286 if (!fam_type)
Borislav Petkov395ae782010-10-01 18:38:19 +02003287 goto err_free;
3288
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05003289 if (pvt->fam >= 0x17) {
Yazen Ghannambdcee772019-02-28 15:36:10 +00003290 pvt->umc = kcalloc(num_umcs, sizeof(struct amd64_umc), GFP_KERNEL);
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05003291 if (!pvt->umc) {
3292 ret = -ENOMEM;
3293 goto err_free;
3294 }
3295
3296 pci_id1 = fam_type->f0_id;
3297 pci_id2 = fam_type->f6_id;
3298 } else {
3299 pci_id1 = fam_type->f1_id;
3300 pci_id2 = fam_type->f2_id;
3301 }
3302
3303 err = reserve_mc_sibling_devs(pvt, pci_id1, pci_id2);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003304 if (err)
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05003305 goto err_post_init;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003306
Borislav Petkov360b7f32010-10-15 19:25:38 +02003307 read_mc_regs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003308
Doug Thompson7d6034d2009-04-27 20:01:01 +02003309 /*
3310 * We need to determine how many memory channels there are. Then use
3311 * that information for calculating the size of the dynamic instance
Borislav Petkov360b7f32010-10-15 19:25:38 +02003312 * tables in the 'mci' structure.
Doug Thompson7d6034d2009-04-27 20:01:01 +02003313 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02003314 ret = -EINVAL;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003315 pvt->channel_count = pvt->ops->early_channel_count(pvt);
3316 if (pvt->channel_count < 0)
Borislav Petkov360b7f32010-10-15 19:25:38 +02003317 goto err_siblings;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003318
3319 ret = -ENOMEM;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03003320 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
3321 layers[0].size = pvt->csels[0].b_cnt;
3322 layers[0].is_virt_csrow = true;
3323 layers[1].type = EDAC_MC_LAYER_CHANNEL;
Borislav Petkovf0a56c42013-07-23 20:01:23 +02003324
3325 /*
3326 * Always allocate two channels since we can have setups with DIMMs on
3327 * only one channel. Also, this simplifies handling later for the price
3328 * of a couple of KBs tops.
3329 */
3330 layers[1].size = 2;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03003331 layers[1].is_virt_csrow = false;
Borislav Petkovf0a56c42013-07-23 20:01:23 +02003332
Mauro Carvalho Chehabca0907b2012-05-02 14:37:00 -03003333 mci = edac_mc_alloc(nid, ARRAY_SIZE(layers), layers, 0);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003334 if (!mci)
Borislav Petkov360b7f32010-10-15 19:25:38 +02003335 goto err_siblings;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003336
3337 mci->pvt_info = pvt;
Borislav Petkov3f37a362016-05-06 19:44:27 +02003338 mci->pdev = &pvt->F3->dev;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003339
Borislav Petkovdf71a052011-01-19 18:15:10 +01003340 setup_mci_misc_attrs(mci, fam_type);
Borislav Petkov360b7f32010-10-15 19:25:38 +02003341
3342 if (init_csrows(mci))
Doug Thompson7d6034d2009-04-27 20:01:01 +02003343 mci->edac_cap = EDAC_FLAG_NONE;
3344
Doug Thompson7d6034d2009-04-27 20:01:01 +02003345 ret = -ENODEV;
Takashi Iwaie339f1e2015-02-04 11:48:53 +01003346 if (edac_mc_add_mc_with_groups(mci, amd64_edac_attr_groups)) {
Joe Perches956b9ba2012-04-29 17:08:39 -03003347 edac_dbg(1, "failed edac_mc_add_mc()\n");
Doug Thompson7d6034d2009-04-27 20:01:01 +02003348 goto err_add_mc;
3349 }
3350
Doug Thompson7d6034d2009-04-27 20:01:01 +02003351 return 0;
3352
3353err_add_mc:
3354 edac_mc_free(mci);
3355
Borislav Petkov360b7f32010-10-15 19:25:38 +02003356err_siblings:
3357 free_mc_sibling_devs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003358
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05003359err_post_init:
3360 if (pvt->fam >= 0x17)
3361 kfree(pvt->umc);
3362
Borislav Petkov360b7f32010-10-15 19:25:38 +02003363err_free:
3364 kfree(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003365
Borislav Petkov360b7f32010-10-15 19:25:38 +02003366err_ret:
Doug Thompson7d6034d2009-04-27 20:01:01 +02003367 return ret;
3368}
3369
Borislav Petkov3f37a362016-05-06 19:44:27 +02003370static int probe_one_instance(unsigned int nid)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003371{
Borislav Petkov2299ef72010-10-15 17:44:04 +02003372 struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003373 struct ecc_settings *s;
Borislav Petkov3f37a362016-05-06 19:44:27 +02003374 int ret;
Borislav Petkovb8cfa022010-10-01 19:35:38 +02003375
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003376 ret = -ENOMEM;
3377 s = kzalloc(sizeof(struct ecc_settings), GFP_KERNEL);
3378 if (!s)
Borislav Petkov2299ef72010-10-15 17:44:04 +02003379 goto err_out;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003380
3381 ecc_stngs[nid] = s;
3382
Borislav Petkov2299ef72010-10-15 17:44:04 +02003383 if (!ecc_enabled(F3, nid)) {
Yazen Ghannam4688c9b2017-01-27 11:24:22 -06003384 ret = 0;
Borislav Petkov2299ef72010-10-15 17:44:04 +02003385
3386 if (!ecc_enable_override)
3387 goto err_enable;
3388
Yazen Ghannam044e7a42016-11-22 15:40:16 -06003389 if (boot_cpu_data.x86 >= 0x17) {
3390 amd64_warn("Forcing ECC on is not recommended on newer systems. Please enable ECC in BIOS.");
3391 goto err_enable;
3392 } else
3393 amd64_warn("Forcing ECC on!\n");
Borislav Petkov2299ef72010-10-15 17:44:04 +02003394
3395 if (!enable_ecc_error_reporting(s, nid, F3))
3396 goto err_enable;
3397 }
3398
Borislav Petkov3f37a362016-05-06 19:44:27 +02003399 ret = init_one_instance(nid);
Borislav Petkov360b7f32010-10-15 19:25:38 +02003400 if (ret < 0) {
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003401 amd64_err("Error probing instance: %d\n", nid);
Yazen Ghannam044e7a42016-11-22 15:40:16 -06003402
3403 if (boot_cpu_data.x86 < 0x17)
3404 restore_ecc_error_reporting(s, nid, F3);
Yazen Ghannam2b9b2c42017-01-24 16:32:24 -06003405
3406 goto err_enable;
Borislav Petkov360b7f32010-10-15 19:25:38 +02003407 }
Doug Thompson7d6034d2009-04-27 20:01:01 +02003408
3409 return ret;
Borislav Petkov2299ef72010-10-15 17:44:04 +02003410
3411err_enable:
3412 kfree(s);
3413 ecc_stngs[nid] = NULL;
3414
3415err_out:
3416 return ret;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003417}
3418
Borislav Petkov3f37a362016-05-06 19:44:27 +02003419static void remove_one_instance(unsigned int nid)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003420{
Borislav Petkov360b7f32010-10-15 19:25:38 +02003421 struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
3422 struct ecc_settings *s = ecc_stngs[nid];
Borislav Petkov3f37a362016-05-06 19:44:27 +02003423 struct mem_ctl_info *mci;
3424 struct amd64_pvt *pvt;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003425
Borislav Petkov3f37a362016-05-06 19:44:27 +02003426 mci = find_mci_by_dev(&F3->dev);
Borislav Petkova4b4bed2013-08-10 13:54:48 +02003427 WARN_ON(!mci);
3428
Doug Thompson7d6034d2009-04-27 20:01:01 +02003429 /* Remove from EDAC CORE tracking list */
Borislav Petkov3f37a362016-05-06 19:44:27 +02003430 mci = edac_mc_del_mc(&F3->dev);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003431 if (!mci)
3432 return;
3433
3434 pvt = mci->pvt_info;
3435
Borislav Petkov360b7f32010-10-15 19:25:38 +02003436 restore_ecc_error_reporting(s, nid, F3);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003437
Borislav Petkov360b7f32010-10-15 19:25:38 +02003438 free_mc_sibling_devs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003439
Borislav Petkov360b7f32010-10-15 19:25:38 +02003440 kfree(ecc_stngs[nid]);
3441 ecc_stngs[nid] = NULL;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003442
Doug Thompson7d6034d2009-04-27 20:01:01 +02003443 /* Free the EDAC CORE resources */
Borislav Petkov8f68ed92009-12-21 15:15:59 +01003444 mci->pvt_info = NULL;
Borislav Petkov8f68ed92009-12-21 15:15:59 +01003445
3446 kfree(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003447 edac_mc_free(mci);
3448}
3449
Borislav Petkov360b7f32010-10-15 19:25:38 +02003450static void setup_pci_device(void)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003451{
3452 struct mem_ctl_info *mci;
3453 struct amd64_pvt *pvt;
3454
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003455 if (pci_ctl)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003456 return;
3457
Borislav Petkov2ec591a2015-02-17 10:58:34 +01003458 mci = edac_mc_find(0);
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003459 if (!mci)
3460 return;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003461
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003462 pvt = mci->pvt_info;
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05003463 if (pvt->umc)
3464 pci_ctl = edac_pci_create_generic_ctl(&pvt->F0->dev, EDAC_MOD_STR);
3465 else
3466 pci_ctl = edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR);
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003467 if (!pci_ctl) {
3468 pr_warn("%s(): Unable to create PCI control\n", __func__);
3469 pr_warn("%s(): PCI error report via EDAC not set\n", __func__);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003470 }
3471}
3472
Yazen Ghannamd6efab72016-09-15 19:07:17 -05003473static const struct x86_cpu_id amd64_cpuids[] = {
3474 { X86_VENDOR_AMD, 0xF, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
3475 { X86_VENDOR_AMD, 0x10, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
3476 { X86_VENDOR_AMD, 0x15, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
3477 { X86_VENDOR_AMD, 0x16, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
Yazen Ghannam95d3af62016-11-17 17:57:43 -05003478 { X86_VENDOR_AMD, 0x17, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
Pu Wenc4a3e942018-09-27 16:31:28 +02003479 { X86_VENDOR_HYGON, 0x18, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
Yazen Ghannamd6efab72016-09-15 19:07:17 -05003480 { }
3481};
3482MODULE_DEVICE_TABLE(x86cpu, amd64_cpuids);
3483
Doug Thompson7d6034d2009-04-27 20:01:01 +02003484static int __init amd64_edac_init(void)
3485{
Toshi Kani301375e2017-08-23 16:54:47 -06003486 const char *owner;
Borislav Petkov360b7f32010-10-15 19:25:38 +02003487 int err = -ENODEV;
Borislav Petkov3f37a362016-05-06 19:44:27 +02003488 int i;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003489
Toshi Kani301375e2017-08-23 16:54:47 -06003490 owner = edac_get_owner();
3491 if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
3492 return -EBUSY;
3493
Yazen Ghannam1bd99002017-01-27 11:24:23 -06003494 if (!x86_match_cpu(amd64_cpuids))
3495 return -ENODEV;
3496
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +02003497 if (amd_cache_northbridges() < 0)
Yazen Ghannam1bd99002017-01-27 11:24:23 -06003498 return -ENODEV;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003499
Borislav Petkov6ba92fe2016-06-16 01:13:18 +02003500 opstate_init();
3501
Borislav Petkovcc4d8862010-10-13 16:11:59 +02003502 err = -ENOMEM;
Kees Cook6396bb22018-06-12 14:03:40 -07003503 ecc_stngs = kcalloc(amd_nb_num(), sizeof(ecc_stngs[0]), GFP_KERNEL);
Borislav Petkov2ec591a2015-02-17 10:58:34 +01003504 if (!ecc_stngs)
Borislav Petkova9f0fbe2011-03-29 18:10:53 +02003505 goto err_free;
Borislav Petkovcc4d8862010-10-13 16:11:59 +02003506
Borislav Petkov50542252009-12-11 18:14:40 +01003507 msrs = msrs_alloc();
Borislav Petkov56b34b92009-12-21 18:13:01 +01003508 if (!msrs)
Borislav Petkov360b7f32010-10-15 19:25:38 +02003509 goto err_free;
Borislav Petkov50542252009-12-11 18:14:40 +01003510
Yazen Ghannambdcee772019-02-28 15:36:10 +00003511 compute_num_umcs();
3512
Yazen Ghannam2287c632017-01-13 09:52:19 -06003513 for (i = 0; i < amd_nb_num(); i++) {
3514 err = probe_one_instance(i);
3515 if (err) {
Borislav Petkov3f37a362016-05-06 19:44:27 +02003516 /* unwind properly */
3517 while (--i >= 0)
3518 remove_one_instance(i);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003519
Borislav Petkov3f37a362016-05-06 19:44:27 +02003520 goto err_pci;
3521 }
Yazen Ghannam2287c632017-01-13 09:52:19 -06003522 }
Doug Thompson7d6034d2009-04-27 20:01:01 +02003523
Yazen Ghannam4688c9b2017-01-27 11:24:22 -06003524 if (!edac_has_mcs()) {
3525 err = -ENODEV;
3526 goto err_pci;
3527 }
3528
Yazen Ghannam234365f2017-01-24 16:32:25 -06003529 /* register stuff with EDAC MCE */
3530 if (report_gart_errors)
3531 amd_report_gart_errors(true);
3532
3533 if (boot_cpu_data.x86 >= 0x17)
3534 amd_register_ecc_decoder(decode_umc_error);
3535 else
3536 amd_register_ecc_decoder(decode_bus_error);
3537
Borislav Petkov360b7f32010-10-15 19:25:38 +02003538 setup_pci_device();
Tomasz Palaf5b10c42014-11-02 11:22:12 +01003539
3540#ifdef CONFIG_X86_32
3541 amd64_err("%s on 32-bit is unsupported. USE AT YOUR OWN RISK!\n", EDAC_MOD_STR);
3542#endif
3543
Borislav Petkovde0336b2016-04-27 12:21:21 +02003544 printk(KERN_INFO "AMD64 EDAC driver v%s\n", EDAC_AMD64_VERSION);
3545
Borislav Petkov360b7f32010-10-15 19:25:38 +02003546 return 0;
Borislav Petkov56b34b92009-12-21 18:13:01 +01003547
Borislav Petkov56b34b92009-12-21 18:13:01 +01003548err_pci:
3549 msrs_free(msrs);
3550 msrs = NULL;
Borislav Petkovcc4d8862010-10-13 16:11:59 +02003551
Borislav Petkov360b7f32010-10-15 19:25:38 +02003552err_free:
Borislav Petkov360b7f32010-10-15 19:25:38 +02003553 kfree(ecc_stngs);
3554 ecc_stngs = NULL;
3555
Doug Thompson7d6034d2009-04-27 20:01:01 +02003556 return err;
3557}
3558
3559static void __exit amd64_edac_exit(void)
3560{
Borislav Petkov3f37a362016-05-06 19:44:27 +02003561 int i;
3562
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003563 if (pci_ctl)
3564 edac_pci_release_generic_ctl(pci_ctl);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003565
Yazen Ghannam234365f2017-01-24 16:32:25 -06003566 /* unregister from EDAC MCE */
3567 amd_report_gart_errors(false);
3568
3569 if (boot_cpu_data.x86 >= 0x17)
3570 amd_unregister_ecc_decoder(decode_umc_error);
3571 else
3572 amd_unregister_ecc_decoder(decode_bus_error);
3573
Borislav Petkov3f37a362016-05-06 19:44:27 +02003574 for (i = 0; i < amd_nb_num(); i++)
3575 remove_one_instance(i);
Borislav Petkov50542252009-12-11 18:14:40 +01003576
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003577 kfree(ecc_stngs);
3578 ecc_stngs = NULL;
3579
Borislav Petkov50542252009-12-11 18:14:40 +01003580 msrs_free(msrs);
3581 msrs = NULL;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003582}
3583
3584module_init(amd64_edac_init);
3585module_exit(amd64_edac_exit);
3586
3587MODULE_LICENSE("GPL");
3588MODULE_AUTHOR("SoftwareBitMaker: Doug Thompson, "
3589 "Dave Peterson, Thayne Harbaugh");
3590MODULE_DESCRIPTION("MC support for AMD64 memory controllers - "
3591 EDAC_AMD64_VERSION);
3592
3593module_param(edac_op_state, int, 0444);
3594MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");