blob: 9a7cf3c8df06e2ea6ae00f3091366a054e317008 [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
21/*
Borislav Petkovb70ef012009-06-25 19:32:38 +020022 * Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing
23 * bandwidth to a valid bit pattern. The 'set' operation finds the 'matching-
24 * or higher value'.
25 *
26 *FIXME: Produce a better mapping/linearisation.
27 */
Daniel J Bluemanc7e53012012-11-30 16:44:20 +080028static const struct scrubrate {
Borislav Petkov39094442010-11-24 19:52:09 +010029 u32 scrubval; /* bit pattern for scrub rate */
30 u32 bandwidth; /* bandwidth consumed (bytes/sec) */
31} scrubrates[] = {
Borislav Petkovb70ef012009-06-25 19:32:38 +020032 { 0x01, 1600000000UL},
33 { 0x02, 800000000UL},
34 { 0x03, 400000000UL},
35 { 0x04, 200000000UL},
36 { 0x05, 100000000UL},
37 { 0x06, 50000000UL},
38 { 0x07, 25000000UL},
39 { 0x08, 12284069UL},
40 { 0x09, 6274509UL},
41 { 0x0A, 3121951UL},
42 { 0x0B, 1560975UL},
43 { 0x0C, 781440UL},
44 { 0x0D, 390720UL},
45 { 0x0E, 195300UL},
46 { 0x0F, 97650UL},
47 { 0x10, 48854UL},
48 { 0x11, 24427UL},
49 { 0x12, 12213UL},
50 { 0x13, 6101UL},
51 { 0x14, 3051UL},
52 { 0x15, 1523UL},
53 { 0x16, 761UL},
54 { 0x00, 0UL}, /* scrubbing off */
55};
56
Borislav Petkov66fed2d2012-08-09 18:41:07 +020057int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
58 u32 *val, const char *func)
Borislav Petkovb2b0c602010-10-08 18:32:29 +020059{
60 int err = 0;
61
62 err = pci_read_config_dword(pdev, offset, val);
63 if (err)
64 amd64_warn("%s: error reading F%dx%03x.\n",
65 func, PCI_FUNC(pdev->devfn), offset);
66
67 return err;
68}
69
70int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset,
71 u32 val, const char *func)
72{
73 int err = 0;
74
75 err = pci_write_config_dword(pdev, offset, val);
76 if (err)
77 amd64_warn("%s: error writing to F%dx%03x.\n",
78 func, PCI_FUNC(pdev->devfn), offset);
79
80 return err;
81}
82
83/*
Borislav Petkov73ba8592011-09-19 17:34:45 +020084 * Select DCT to which PCI cfg accesses are routed
85 */
86static void f15h_select_dct(struct amd64_pvt *pvt, u8 dct)
87{
88 u32 reg = 0;
89
90 amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, &reg);
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -050091 reg &= (pvt->model == 0x30) ? ~3 : ~1;
Borislav Petkov73ba8592011-09-19 17:34:45 +020092 reg |= dct;
93 amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg);
94}
95
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -050096/*
97 *
98 * Depending on the family, F2 DCT reads need special handling:
99 *
100 * K8: has a single DCT only and no address offsets >= 0x100
101 *
102 * F10h: each DCT has its own set of regs
103 * DCT0 -> F2x040..
104 * DCT1 -> F2x140..
105 *
106 * F16h: has only 1 DCT
107 *
108 * F15h: we select which DCT we access using F1x10C[DctCfgSel]
109 */
110static inline int amd64_read_dct_pci_cfg(struct amd64_pvt *pvt, u8 dct,
111 int offset, u32 *val)
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200112{
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -0500113 switch (pvt->fam) {
114 case 0xf:
115 if (dct || offset >= 0x100)
116 return -EINVAL;
117 break;
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200118
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -0500119 case 0x10:
120 if (dct) {
121 /*
122 * Note: If ganging is enabled, barring the regs
123 * F2x[1,0]98 and F2x[1,0]9C; reads reads to F2x1xx
124 * return 0. (cf. Section 2.8.1 F10h BKDG)
125 */
126 if (dct_ganging_enabled(pvt))
127 return 0;
128
129 offset += 0x100;
130 }
131 break;
132
133 case 0x15:
134 /*
135 * F15h: F2x1xx addresses do not map explicitly to DCT1.
136 * We should select which DCT we access using F1x10C[DctCfgSel]
137 */
138 dct = (dct && pvt->model == 0x30) ? 3 : dct;
139 f15h_select_dct(pvt, dct);
140 break;
141
142 case 0x16:
143 if (dct)
144 return -EINVAL;
145 break;
146
147 default:
148 break;
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200149 }
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -0500150 return amd64_read_pci_cfg(pvt->F2, offset, val);
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200151}
152
Borislav Petkovb70ef012009-06-25 19:32:38 +0200153/*
Doug Thompson2bc65412009-05-04 20:11:14 +0200154 * Memory scrubber control interface. For K8, memory scrubbing is handled by
155 * hardware and can involve L2 cache, dcache as well as the main memory. With
156 * F10, this is extended to L3 cache scrubbing on CPU models sporting that
157 * functionality.
158 *
159 * This causes the "units" for the scrubbing speed to vary from 64 byte blocks
160 * (dram) over to cache lines. This is nasty, so we will use bandwidth in
161 * bytes/sec for the setting.
162 *
163 * Currently, we only do dram scrubbing. If the scrubbing is done in software on
164 * other archs, we might not have access to the caches directly.
165 */
166
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500167static inline void __f17h_set_scrubval(struct amd64_pvt *pvt, u32 scrubval)
168{
169 /*
170 * Fam17h supports scrub values between 0x5 and 0x14. Also, the values
171 * are shifted down by 0x5, so scrubval 0x5 is written to the register
172 * as 0x0, scrubval 0x6 as 0x1, etc.
173 */
174 if (scrubval >= 0x5 && scrubval <= 0x14) {
175 scrubval -= 0x5;
176 pci_write_bits32(pvt->F6, F17H_SCR_LIMIT_ADDR, scrubval, 0xF);
177 pci_write_bits32(pvt->F6, F17H_SCR_BASE_ADDR, 1, 0x1);
178 } else {
179 pci_write_bits32(pvt->F6, F17H_SCR_BASE_ADDR, 0, 0x1);
180 }
181}
Doug Thompson2bc65412009-05-04 20:11:14 +0200182/*
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500183 * Scan the scrub rate mapping table for a close or matching bandwidth value to
Doug Thompson2bc65412009-05-04 20:11:14 +0200184 * issue. If requested is too big, then use last maximum value found.
185 */
Aravind Gopalakrishnanda921102015-09-28 06:43:12 -0500186static int __set_scrub_rate(struct amd64_pvt *pvt, u32 new_bw, u32 min_rate)
Doug Thompson2bc65412009-05-04 20:11:14 +0200187{
188 u32 scrubval;
189 int i;
190
191 /*
192 * map the configured rate (new_bw) to a value specific to the AMD64
193 * memory controller and apply to register. Search for the first
194 * bandwidth entry that is greater or equal than the setting requested
195 * and program that. If at last entry, turn off DRAM scrubbing.
Andrew Morton168bfee2012-10-23 14:09:39 -0700196 *
197 * If no suitable bandwidth is found, turn off DRAM scrubbing entirely
198 * by falling back to the last element in scrubrates[].
Doug Thompson2bc65412009-05-04 20:11:14 +0200199 */
Andrew Morton168bfee2012-10-23 14:09:39 -0700200 for (i = 0; i < ARRAY_SIZE(scrubrates) - 1; i++) {
Doug Thompson2bc65412009-05-04 20:11:14 +0200201 /*
202 * skip scrub rates which aren't recommended
203 * (see F10 BKDG, F3x58)
204 */
Borislav Petkov395ae782010-10-01 18:38:19 +0200205 if (scrubrates[i].scrubval < min_rate)
Doug Thompson2bc65412009-05-04 20:11:14 +0200206 continue;
207
208 if (scrubrates[i].bandwidth <= new_bw)
209 break;
Doug Thompson2bc65412009-05-04 20:11:14 +0200210 }
211
212 scrubval = scrubrates[i].scrubval;
Doug Thompson2bc65412009-05-04 20:11:14 +0200213
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500214 if (pvt->fam == 0x17) {
215 __f17h_set_scrubval(pvt, scrubval);
216 } else if (pvt->fam == 0x15 && pvt->model == 0x60) {
Aravind Gopalakrishnanda921102015-09-28 06:43:12 -0500217 f15h_select_dct(pvt, 0);
218 pci_write_bits32(pvt->F2, F15H_M60H_SCRCTRL, scrubval, 0x001F);
219 f15h_select_dct(pvt, 1);
220 pci_write_bits32(pvt->F2, F15H_M60H_SCRCTRL, scrubval, 0x001F);
221 } else {
222 pci_write_bits32(pvt->F3, SCRCTRL, scrubval, 0x001F);
223 }
Doug Thompson2bc65412009-05-04 20:11:14 +0200224
Borislav Petkov39094442010-11-24 19:52:09 +0100225 if (scrubval)
226 return scrubrates[i].bandwidth;
227
Doug Thompson2bc65412009-05-04 20:11:14 +0200228 return 0;
229}
230
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100231static int set_scrub_rate(struct mem_ctl_info *mci, u32 bw)
Doug Thompson2bc65412009-05-04 20:11:14 +0200232{
233 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkov87b3e0e2011-01-19 20:02:38 +0100234 u32 min_scrubrate = 0x5;
Doug Thompson2bc65412009-05-04 20:11:14 +0200235
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200236 if (pvt->fam == 0xf)
Borislav Petkov87b3e0e2011-01-19 20:02:38 +0100237 min_scrubrate = 0x0;
238
Aravind Gopalakrishnanda921102015-09-28 06:43:12 -0500239 if (pvt->fam == 0x15) {
240 /* Erratum #505 */
241 if (pvt->model < 0x10)
242 f15h_select_dct(pvt, 0);
Borislav Petkov73ba8592011-09-19 17:34:45 +0200243
Aravind Gopalakrishnanda921102015-09-28 06:43:12 -0500244 if (pvt->model == 0x60)
245 min_scrubrate = 0x6;
246 }
247 return __set_scrub_rate(pvt, bw, min_scrubrate);
Doug Thompson2bc65412009-05-04 20:11:14 +0200248}
249
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100250static int get_scrub_rate(struct mem_ctl_info *mci)
Doug Thompson2bc65412009-05-04 20:11:14 +0200251{
252 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkov39094442010-11-24 19:52:09 +0100253 int i, retval = -EINVAL;
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500254 u32 scrubval = 0;
Doug Thompson2bc65412009-05-04 20:11:14 +0200255
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500256 switch (pvt->fam) {
257 case 0x15:
Aravind Gopalakrishnanda921102015-09-28 06:43:12 -0500258 /* Erratum #505 */
259 if (pvt->model < 0x10)
260 f15h_select_dct(pvt, 0);
Borislav Petkov73ba8592011-09-19 17:34:45 +0200261
Aravind Gopalakrishnanda921102015-09-28 06:43:12 -0500262 if (pvt->model == 0x60)
263 amd64_read_pci_cfg(pvt->F2, F15H_M60H_SCRCTRL, &scrubval);
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500264 break;
265
266 case 0x17:
267 amd64_read_pci_cfg(pvt->F6, F17H_SCR_BASE_ADDR, &scrubval);
268 if (scrubval & BIT(0)) {
269 amd64_read_pci_cfg(pvt->F6, F17H_SCR_LIMIT_ADDR, &scrubval);
270 scrubval &= 0xF;
271 scrubval += 0x5;
272 } else {
273 scrubval = 0;
274 }
275 break;
276
277 default:
Aravind Gopalakrishnanda921102015-09-28 06:43:12 -0500278 amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval);
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500279 break;
280 }
Doug Thompson2bc65412009-05-04 20:11:14 +0200281
282 scrubval = scrubval & 0x001F;
283
Roel Kluin926311f2010-01-11 20:58:21 +0100284 for (i = 0; i < ARRAY_SIZE(scrubrates); i++) {
Doug Thompson2bc65412009-05-04 20:11:14 +0200285 if (scrubrates[i].scrubval == scrubval) {
Borislav Petkov39094442010-11-24 19:52:09 +0100286 retval = scrubrates[i].bandwidth;
Doug Thompson2bc65412009-05-04 20:11:14 +0200287 break;
288 }
289 }
Borislav Petkov39094442010-11-24 19:52:09 +0100290 return retval;
Doug Thompson2bc65412009-05-04 20:11:14 +0200291}
292
Doug Thompson67757632009-04-27 15:53:22 +0200293/*
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200294 * returns true if the SysAddr given by sys_addr matches the
295 * DRAM base/limit associated with node_id
Doug Thompson67757632009-04-27 15:53:22 +0200296 */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100297static bool base_limit_match(struct amd64_pvt *pvt, u64 sys_addr, u8 nid)
Doug Thompson67757632009-04-27 15:53:22 +0200298{
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200299 u64 addr;
Doug Thompson67757632009-04-27 15:53:22 +0200300
301 /* The K8 treats this as a 40-bit value. However, bits 63-40 will be
302 * all ones if the most significant implemented address bit is 1.
303 * Here we discard bits 63-40. See section 3.4.2 of AMD publication
304 * 24592: AMD x86-64 Architecture Programmer's Manual Volume 1
305 * Application Programming.
306 */
307 addr = sys_addr & 0x000000ffffffffffull;
308
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200309 return ((addr >= get_dram_base(pvt, nid)) &&
310 (addr <= get_dram_limit(pvt, nid)));
Doug Thompson67757632009-04-27 15:53:22 +0200311}
312
313/*
314 * Attempt to map a SysAddr to a node. On success, return a pointer to the
315 * mem_ctl_info structure for the node that the SysAddr maps to.
316 *
317 * On failure, return NULL.
318 */
319static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
320 u64 sys_addr)
321{
322 struct amd64_pvt *pvt;
Daniel J Bluemanc7e53012012-11-30 16:44:20 +0800323 u8 node_id;
Doug Thompson67757632009-04-27 15:53:22 +0200324 u32 intlv_en, bits;
325
326 /*
327 * Here we use the DRAM Base (section 3.4.4.1) and DRAM Limit (section
328 * 3.4.4.2) registers to map the SysAddr to a node ID.
329 */
330 pvt = mci->pvt_info;
331
332 /*
333 * The value of this field should be the same for all DRAM Base
334 * registers. Therefore we arbitrarily choose to read it from the
335 * register for node 0.
336 */
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200337 intlv_en = dram_intlv_en(pvt, 0);
Doug Thompson67757632009-04-27 15:53:22 +0200338
339 if (intlv_en == 0) {
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200340 for (node_id = 0; node_id < DRAM_RANGES; node_id++) {
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100341 if (base_limit_match(pvt, sys_addr, node_id))
Borislav Petkov8edc5442009-09-18 12:39:19 +0200342 goto found;
Doug Thompson67757632009-04-27 15:53:22 +0200343 }
Borislav Petkov8edc5442009-09-18 12:39:19 +0200344 goto err_no_match;
Doug Thompson67757632009-04-27 15:53:22 +0200345 }
346
Borislav Petkov72f158f2009-09-18 12:27:27 +0200347 if (unlikely((intlv_en != 0x01) &&
348 (intlv_en != 0x03) &&
349 (intlv_en != 0x07))) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200350 amd64_warn("DRAM Base[IntlvEn] junk value: 0x%x, BIOS bug?\n", intlv_en);
Doug Thompson67757632009-04-27 15:53:22 +0200351 return NULL;
352 }
353
354 bits = (((u32) sys_addr) >> 12) & intlv_en;
355
356 for (node_id = 0; ; ) {
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200357 if ((dram_intlv_sel(pvt, node_id) & intlv_en) == bits)
Doug Thompson67757632009-04-27 15:53:22 +0200358 break; /* intlv_sel field matches */
359
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200360 if (++node_id >= DRAM_RANGES)
Doug Thompson67757632009-04-27 15:53:22 +0200361 goto err_no_match;
362 }
363
364 /* sanity test for sys_addr */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100365 if (unlikely(!base_limit_match(pvt, sys_addr, node_id))) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200366 amd64_warn("%s: sys_addr 0x%llx falls outside base/limit address"
367 "range for node %d with node interleaving enabled.\n",
368 __func__, sys_addr, node_id);
Doug Thompson67757632009-04-27 15:53:22 +0200369 return NULL;
370 }
371
372found:
Borislav Petkovb487c332011-02-21 18:55:00 +0100373 return edac_mc_find((int)node_id);
Doug Thompson67757632009-04-27 15:53:22 +0200374
375err_no_match:
Joe Perches956b9ba2012-04-29 17:08:39 -0300376 edac_dbg(2, "sys_addr 0x%lx doesn't match any node\n",
377 (unsigned long)sys_addr);
Doug Thompson67757632009-04-27 15:53:22 +0200378
379 return NULL;
380}
Doug Thompsone2ce7252009-04-27 15:57:12 +0200381
382/*
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100383 * compute the CS base address of the @csrow on the DRAM controller @dct.
384 * For details see F2x[5C:40] in the processor's BKDG
Doug Thompsone2ce7252009-04-27 15:57:12 +0200385 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100386static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct,
387 u64 *base, u64 *mask)
Doug Thompsone2ce7252009-04-27 15:57:12 +0200388{
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100389 u64 csbase, csmask, base_bits, mask_bits;
390 u8 addr_shift;
391
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -0500392 if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) {
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100393 csbase = pvt->csels[dct].csbases[csrow];
394 csmask = pvt->csels[dct].csmasks[csrow];
Chen, Gong10ef6b02013-10-18 14:29:07 -0700395 base_bits = GENMASK_ULL(31, 21) | GENMASK_ULL(15, 9);
396 mask_bits = GENMASK_ULL(29, 21) | GENMASK_ULL(15, 9);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100397 addr_shift = 4;
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -0500398
399 /*
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -0500400 * F16h and F15h, models 30h and later need two addr_shift values:
401 * 8 for high and 6 for low (cf. F16h BKDG).
402 */
403 } else if (pvt->fam == 0x16 ||
404 (pvt->fam == 0x15 && pvt->model >= 0x30)) {
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -0500405 csbase = pvt->csels[dct].csbases[csrow];
406 csmask = pvt->csels[dct].csmasks[csrow >> 1];
407
Chen, Gong10ef6b02013-10-18 14:29:07 -0700408 *base = (csbase & GENMASK_ULL(15, 5)) << 6;
409 *base |= (csbase & GENMASK_ULL(30, 19)) << 8;
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -0500410
411 *mask = ~0ULL;
412 /* poke holes for the csmask */
Chen, Gong10ef6b02013-10-18 14:29:07 -0700413 *mask &= ~((GENMASK_ULL(15, 5) << 6) |
414 (GENMASK_ULL(30, 19) << 8));
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -0500415
Chen, Gong10ef6b02013-10-18 14:29:07 -0700416 *mask |= (csmask & GENMASK_ULL(15, 5)) << 6;
417 *mask |= (csmask & GENMASK_ULL(30, 19)) << 8;
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -0500418
419 return;
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100420 } else {
421 csbase = pvt->csels[dct].csbases[csrow];
422 csmask = pvt->csels[dct].csmasks[csrow >> 1];
423 addr_shift = 8;
424
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200425 if (pvt->fam == 0x15)
Chen, Gong10ef6b02013-10-18 14:29:07 -0700426 base_bits = mask_bits =
427 GENMASK_ULL(30,19) | GENMASK_ULL(13,5);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100428 else
Chen, Gong10ef6b02013-10-18 14:29:07 -0700429 base_bits = mask_bits =
430 GENMASK_ULL(28,19) | GENMASK_ULL(13,5);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100431 }
432
433 *base = (csbase & base_bits) << addr_shift;
434
435 *mask = ~0ULL;
436 /* poke holes for the csmask */
437 *mask &= ~(mask_bits << addr_shift);
438 /* OR them in */
439 *mask |= (csmask & mask_bits) << addr_shift;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200440}
441
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100442#define for_each_chip_select(i, dct, pvt) \
443 for (i = 0; i < pvt->csels[dct].b_cnt; i++)
Doug Thompsone2ce7252009-04-27 15:57:12 +0200444
Borislav Petkov614ec9d2011-01-13 18:02:22 +0100445#define chip_select_base(i, dct, pvt) \
446 pvt->csels[dct].csbases[i]
447
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100448#define for_each_chip_select_mask(i, dct, pvt) \
449 for (i = 0; i < pvt->csels[dct].m_cnt; i++)
Doug Thompsone2ce7252009-04-27 15:57:12 +0200450
451/*
452 * @input_addr is an InputAddr associated with the node given by mci. Return the
453 * csrow that input_addr maps to, or -1 on failure (no csrow claims input_addr).
454 */
455static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr)
456{
457 struct amd64_pvt *pvt;
458 int csrow;
459 u64 base, mask;
460
461 pvt = mci->pvt_info;
462
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100463 for_each_chip_select(csrow, 0, pvt) {
464 if (!csrow_enabled(csrow, 0, pvt))
Doug Thompsone2ce7252009-04-27 15:57:12 +0200465 continue;
466
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100467 get_cs_base_and_mask(pvt, csrow, 0, &base, &mask);
468
469 mask = ~mask;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200470
471 if ((input_addr & mask) == (base & mask)) {
Joe Perches956b9ba2012-04-29 17:08:39 -0300472 edac_dbg(2, "InputAddr 0x%lx matches csrow %d (node %d)\n",
473 (unsigned long)input_addr, csrow,
474 pvt->mc_node_id);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200475
476 return csrow;
477 }
478 }
Joe Perches956b9ba2012-04-29 17:08:39 -0300479 edac_dbg(2, "no matching csrow for InputAddr 0x%lx (MC node %d)\n",
480 (unsigned long)input_addr, pvt->mc_node_id);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200481
482 return -1;
483}
484
485/*
Doug Thompsone2ce7252009-04-27 15:57:12 +0200486 * Obtain info from the DRAM Hole Address Register (section 3.4.8, pub #26094)
487 * for the node represented by mci. Info is passed back in *hole_base,
488 * *hole_offset, and *hole_size. Function returns 0 if info is valid or 1 if
489 * info is invalid. Info may be invalid for either of the following reasons:
490 *
491 * - The revision of the node is not E or greater. In this case, the DRAM Hole
492 * Address Register does not exist.
493 *
494 * - The DramHoleValid bit is cleared in the DRAM Hole Address Register,
495 * indicating that its contents are not valid.
496 *
497 * The values passed back in *hole_base, *hole_offset, and *hole_size are
498 * complete 32-bit values despite the fact that the bitfields in the DHAR
499 * only represent bits 31-24 of the base and offset values.
500 */
501int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
502 u64 *hole_offset, u64 *hole_size)
503{
504 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200505
506 /* only revE and later have the DRAM Hole Address Register */
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200507 if (pvt->fam == 0xf && pvt->ext_model < K8_REV_E) {
Joe Perches956b9ba2012-04-29 17:08:39 -0300508 edac_dbg(1, " revision %d for node %d does not support DHAR\n",
509 pvt->ext_model, pvt->mc_node_id);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200510 return 1;
511 }
512
Borislav Petkovbc21fa52010-11-11 17:29:13 +0100513 /* valid for Fam10h and above */
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200514 if (pvt->fam >= 0x10 && !dhar_mem_hoist_valid(pvt)) {
Joe Perches956b9ba2012-04-29 17:08:39 -0300515 edac_dbg(1, " Dram Memory Hoisting is DISABLED on this system\n");
Doug Thompsone2ce7252009-04-27 15:57:12 +0200516 return 1;
517 }
518
Borislav Petkovc8e518d2010-12-10 19:49:19 +0100519 if (!dhar_valid(pvt)) {
Joe Perches956b9ba2012-04-29 17:08:39 -0300520 edac_dbg(1, " Dram Memory Hoisting is DISABLED on this node %d\n",
521 pvt->mc_node_id);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200522 return 1;
523 }
524
525 /* This node has Memory Hoisting */
526
527 /* +------------------+--------------------+--------------------+-----
528 * | memory | DRAM hole | relocated |
529 * | [0, (x - 1)] | [x, 0xffffffff] | addresses from |
530 * | | | DRAM hole |
531 * | | | [0x100000000, |
532 * | | | (0x100000000+ |
533 * | | | (0xffffffff-x))] |
534 * +------------------+--------------------+--------------------+-----
535 *
536 * Above is a diagram of physical memory showing the DRAM hole and the
537 * relocated addresses from the DRAM hole. As shown, the DRAM hole
538 * starts at address x (the base address) and extends through address
539 * 0xffffffff. The DRAM Hole Address Register (DHAR) relocates the
540 * addresses in the hole so that they start at 0x100000000.
541 */
542
Borislav Petkov1f316772012-08-10 12:50:50 +0200543 *hole_base = dhar_base(pvt);
544 *hole_size = (1ULL << 32) - *hole_base;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200545
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200546 *hole_offset = (pvt->fam > 0xf) ? f10_dhar_offset(pvt)
547 : k8_dhar_offset(pvt);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200548
Joe Perches956b9ba2012-04-29 17:08:39 -0300549 edac_dbg(1, " DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx\n",
550 pvt->mc_node_id, (unsigned long)*hole_base,
551 (unsigned long)*hole_offset, (unsigned long)*hole_size);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200552
553 return 0;
554}
555EXPORT_SYMBOL_GPL(amd64_get_dram_hole_info);
556
Doug Thompson93c2df52009-05-04 20:46:50 +0200557/*
558 * Return the DramAddr that the SysAddr given by @sys_addr maps to. It is
559 * assumed that sys_addr maps to the node given by mci.
560 *
561 * The first part of section 3.4.4 (p. 70) shows how the DRAM Base (section
562 * 3.4.4.1) and DRAM Limit (section 3.4.4.2) registers are used to translate a
563 * SysAddr to a DramAddr. If the DRAM Hole Address Register (DHAR) is enabled,
564 * then it is also involved in translating a SysAddr to a DramAddr. Sections
565 * 3.4.8 and 3.5.8.2 describe the DHAR and how it is used for memory hoisting.
566 * These parts of the documentation are unclear. I interpret them as follows:
567 *
568 * When node n receives a SysAddr, it processes the SysAddr as follows:
569 *
570 * 1. It extracts the DRAMBase and DRAMLimit values from the DRAM Base and DRAM
571 * Limit registers for node n. If the SysAddr is not within the range
572 * specified by the base and limit values, then node n ignores the Sysaddr
573 * (since it does not map to node n). Otherwise continue to step 2 below.
574 *
575 * 2. If the DramHoleValid bit of the DHAR for node n is clear, the DHAR is
576 * disabled so skip to step 3 below. Otherwise see if the SysAddr is within
577 * the range of relocated addresses (starting at 0x100000000) from the DRAM
578 * hole. If not, skip to step 3 below. Else get the value of the
579 * DramHoleOffset field from the DHAR. To obtain the DramAddr, subtract the
580 * offset defined by this value from the SysAddr.
581 *
582 * 3. Obtain the base address for node n from the DRAMBase field of the DRAM
583 * Base register for node n. To obtain the DramAddr, subtract the base
584 * address from the SysAddr, as shown near the start of section 3.4.4 (p.70).
585 */
586static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr)
587{
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200588 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompson93c2df52009-05-04 20:46:50 +0200589 u64 dram_base, hole_base, hole_offset, hole_size, dram_addr;
Borislav Petkov1f316772012-08-10 12:50:50 +0200590 int ret;
Doug Thompson93c2df52009-05-04 20:46:50 +0200591
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200592 dram_base = get_dram_base(pvt, pvt->mc_node_id);
Doug Thompson93c2df52009-05-04 20:46:50 +0200593
594 ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
595 &hole_size);
596 if (!ret) {
Borislav Petkov1f316772012-08-10 12:50:50 +0200597 if ((sys_addr >= (1ULL << 32)) &&
598 (sys_addr < ((1ULL << 32) + hole_size))) {
Doug Thompson93c2df52009-05-04 20:46:50 +0200599 /* use DHAR to translate SysAddr to DramAddr */
600 dram_addr = sys_addr - hole_offset;
601
Joe Perches956b9ba2012-04-29 17:08:39 -0300602 edac_dbg(2, "using DHAR to translate SysAddr 0x%lx to DramAddr 0x%lx\n",
603 (unsigned long)sys_addr,
604 (unsigned long)dram_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200605
606 return dram_addr;
607 }
608 }
609
610 /*
611 * Translate the SysAddr to a DramAddr as shown near the start of
612 * section 3.4.4 (p. 70). Although sys_addr is a 64-bit value, the k8
613 * only deals with 40-bit values. Therefore we discard bits 63-40 of
614 * sys_addr below. If bit 39 of sys_addr is 1 then the bits we
615 * discard are all 1s. Otherwise the bits we discard are all 0s. See
616 * section 3.4.2 of AMD publication 24592: AMD x86-64 Architecture
617 * Programmer's Manual Volume 1 Application Programming.
618 */
Chen, Gong10ef6b02013-10-18 14:29:07 -0700619 dram_addr = (sys_addr & GENMASK_ULL(39, 0)) - dram_base;
Doug Thompson93c2df52009-05-04 20:46:50 +0200620
Joe Perches956b9ba2012-04-29 17:08:39 -0300621 edac_dbg(2, "using DRAM Base register to translate SysAddr 0x%lx to DramAddr 0x%lx\n",
622 (unsigned long)sys_addr, (unsigned long)dram_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200623 return dram_addr;
624}
625
626/*
627 * @intlv_en is the value of the IntlvEn field from a DRAM Base register
628 * (section 3.4.4.1). Return the number of bits from a SysAddr that are used
629 * for node interleaving.
630 */
631static int num_node_interleave_bits(unsigned intlv_en)
632{
633 static const int intlv_shift_table[] = { 0, 1, 0, 2, 0, 0, 0, 3 };
634 int n;
635
636 BUG_ON(intlv_en > 7);
637 n = intlv_shift_table[intlv_en];
638 return n;
639}
640
641/* Translate the DramAddr given by @dram_addr to an InputAddr. */
642static u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr)
643{
644 struct amd64_pvt *pvt;
645 int intlv_shift;
646 u64 input_addr;
647
648 pvt = mci->pvt_info;
649
650 /*
651 * See the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E)
652 * concerning translating a DramAddr to an InputAddr.
653 */
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200654 intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0));
Chen, Gong10ef6b02013-10-18 14:29:07 -0700655 input_addr = ((dram_addr >> intlv_shift) & GENMASK_ULL(35, 12)) +
Borislav Petkovf678b8c2010-12-13 19:21:07 +0100656 (dram_addr & 0xfff);
Doug Thompson93c2df52009-05-04 20:46:50 +0200657
Joe Perches956b9ba2012-04-29 17:08:39 -0300658 edac_dbg(2, " Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n",
659 intlv_shift, (unsigned long)dram_addr,
660 (unsigned long)input_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200661
662 return input_addr;
663}
664
665/*
666 * Translate the SysAddr represented by @sys_addr to an InputAddr. It is
667 * assumed that @sys_addr maps to the node given by mci.
668 */
669static u64 sys_addr_to_input_addr(struct mem_ctl_info *mci, u64 sys_addr)
670{
671 u64 input_addr;
672
673 input_addr =
674 dram_addr_to_input_addr(mci, sys_addr_to_dram_addr(mci, sys_addr));
675
Masanari Iidac19ca6c2016-02-08 20:53:12 +0900676 edac_dbg(2, "SysAddr 0x%lx translates to InputAddr 0x%lx\n",
Joe Perches956b9ba2012-04-29 17:08:39 -0300677 (unsigned long)sys_addr, (unsigned long)input_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200678
679 return input_addr;
680}
681
Doug Thompson93c2df52009-05-04 20:46:50 +0200682/* Map the Error address to a PAGE and PAGE OFFSET. */
683static inline void error_address_to_page_and_offset(u64 error_address,
Borislav Petkov33ca0642012-08-30 18:01:36 +0200684 struct err_info *err)
Doug Thompson93c2df52009-05-04 20:46:50 +0200685{
Borislav Petkov33ca0642012-08-30 18:01:36 +0200686 err->page = (u32) (error_address >> PAGE_SHIFT);
687 err->offset = ((u32) error_address) & ~PAGE_MASK;
Doug Thompson93c2df52009-05-04 20:46:50 +0200688}
689
690/*
691 * @sys_addr is an error address (a SysAddr) extracted from the MCA NB Address
692 * Low (section 3.6.4.5) and MCA NB Address High (section 3.6.4.6) registers
693 * of a node that detected an ECC memory error. mci represents the node that
694 * the error address maps to (possibly different from the node that detected
695 * the error). Return the number of the csrow that sys_addr maps to, or -1 on
696 * error.
697 */
698static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr)
699{
700 int csrow;
701
702 csrow = input_addr_to_csrow(mci, sys_addr_to_input_addr(mci, sys_addr));
703
704 if (csrow == -1)
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200705 amd64_mc_err(mci, "Failed to translate InputAddr to csrow for "
706 "address 0x%lx\n", (unsigned long)sys_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200707 return csrow;
708}
Doug Thompsone2ce7252009-04-27 15:57:12 +0200709
Borislav Petkovbfc04ae2009-11-12 19:05:07 +0100710static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);
Doug Thompson2da11652009-04-27 16:09:09 +0200711
Doug Thompson2da11652009-04-27 16:09:09 +0200712/*
713 * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs
714 * are ECC capable.
715 */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100716static unsigned long determine_edac_cap(struct amd64_pvt *pvt)
Doug Thompson2da11652009-04-27 16:09:09 +0200717{
Dan Carpenter1f6189e2011-10-06 02:30:25 -0400718 unsigned long edac_cap = EDAC_FLAG_NONE;
Yazen Ghannamd27f3a32016-11-17 17:57:40 -0500719 u8 bit;
Doug Thompson2da11652009-04-27 16:09:09 +0200720
Yazen Ghannamd27f3a32016-11-17 17:57:40 -0500721 if (pvt->umc) {
722 u8 i, umc_en_mask = 0, dimm_ecc_en_mask = 0;
Doug Thompson2da11652009-04-27 16:09:09 +0200723
Yazen Ghannamd27f3a32016-11-17 17:57:40 -0500724 for (i = 0; i < NUM_UMCS; i++) {
725 if (!(pvt->umc[i].sdp_ctrl & UMC_SDP_INIT))
726 continue;
727
728 umc_en_mask |= BIT(i);
729
730 /* UMC Configuration bit 12 (DimmEccEn) */
731 if (pvt->umc[i].umc_cfg & BIT(12))
732 dimm_ecc_en_mask |= BIT(i);
733 }
734
735 if (umc_en_mask == dimm_ecc_en_mask)
736 edac_cap = EDAC_FLAG_SECDED;
737 } else {
738 bit = (pvt->fam > 0xf || pvt->ext_model >= K8_REV_F)
739 ? 19
740 : 17;
741
742 if (pvt->dclr0 & BIT(bit))
743 edac_cap = EDAC_FLAG_SECDED;
744 }
Doug Thompson2da11652009-04-27 16:09:09 +0200745
746 return edac_cap;
747}
748
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100749static void debug_display_dimm_sizes(struct amd64_pvt *, u8);
Doug Thompson2da11652009-04-27 16:09:09 +0200750
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100751static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan)
Borislav Petkov68798e12009-11-03 16:18:33 +0100752{
Joe Perches956b9ba2012-04-29 17:08:39 -0300753 edac_dbg(1, "F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr);
Borislav Petkov68798e12009-11-03 16:18:33 +0100754
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +0100755 if (pvt->dram_type == MEM_LRDDR3) {
756 u32 dcsm = pvt->csels[chan].csmasks[0];
757 /*
758 * It's assumed all LRDIMMs in a DCT are going to be of
759 * same 'type' until proven otherwise. So, use a cs
760 * value of '0' here to get dcsm value.
761 */
762 edac_dbg(1, " LRDIMM %dx rank multiply\n", (dcsm & 0x3));
763 }
764
765 edac_dbg(1, "All DIMMs support ECC:%s\n",
766 (dclr & BIT(19)) ? "yes" : "no");
767
Borislav Petkov68798e12009-11-03 16:18:33 +0100768
Joe Perches956b9ba2012-04-29 17:08:39 -0300769 edac_dbg(1, " PAR/ERR parity: %s\n",
770 (dclr & BIT(8)) ? "enabled" : "disabled");
Borislav Petkov68798e12009-11-03 16:18:33 +0100771
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200772 if (pvt->fam == 0x10)
Joe Perches956b9ba2012-04-29 17:08:39 -0300773 edac_dbg(1, " DCT 128bit mode width: %s\n",
774 (dclr & BIT(11)) ? "128b" : "64b");
Borislav Petkov68798e12009-11-03 16:18:33 +0100775
Joe Perches956b9ba2012-04-29 17:08:39 -0300776 edac_dbg(1, " x4 logical DIMMs present: L0: %s L1: %s L2: %s L3: %s\n",
777 (dclr & BIT(12)) ? "yes" : "no",
778 (dclr & BIT(13)) ? "yes" : "no",
779 (dclr & BIT(14)) ? "yes" : "no",
780 (dclr & BIT(15)) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100781}
782
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600783static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl)
784{
785 u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases;
786 int dimm, size0, size1;
787
788 edac_printk(KERN_DEBUG, EDAC_MC, "UMC%d chip selects:\n", ctrl);
789
790 for (dimm = 0; dimm < 4; dimm++) {
791 size0 = 0;
792
793 if (dcsb[dimm*2] & DCSB_CS_ENABLE)
794 size0 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, dimm);
795
796 size1 = 0;
797 if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE)
798 size1 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, dimm);
799
800 amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
801 dimm * 2, size0,
802 dimm * 2 + 1, size1);
803 }
804}
805
806static void __dump_misc_regs_df(struct amd64_pvt *pvt)
807{
808 struct amd64_umc *umc;
809 u32 i, tmp, umc_base;
810
811 for (i = 0; i < NUM_UMCS; i++) {
812 umc_base = get_umc_base(i);
813 umc = &pvt->umc[i];
814
815 edac_dbg(1, "UMC%d DIMM cfg: 0x%x\n", i, umc->dimm_cfg);
816 edac_dbg(1, "UMC%d UMC cfg: 0x%x\n", i, umc->umc_cfg);
817 edac_dbg(1, "UMC%d SDP ctrl: 0x%x\n", i, umc->sdp_ctrl);
818 edac_dbg(1, "UMC%d ECC ctrl: 0x%x\n", i, umc->ecc_ctrl);
819
820 amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_ECC_BAD_SYMBOL, &tmp);
821 edac_dbg(1, "UMC%d ECC bad symbol: 0x%x\n", i, tmp);
822
823 amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_UMC_CAP, &tmp);
824 edac_dbg(1, "UMC%d UMC cap: 0x%x\n", i, tmp);
825 edac_dbg(1, "UMC%d UMC cap high: 0x%x\n", i, umc->umc_cap_hi);
826
827 edac_dbg(1, "UMC%d ECC capable: %s, ChipKill ECC capable: %s\n",
828 i, (umc->umc_cap_hi & BIT(30)) ? "yes" : "no",
829 (umc->umc_cap_hi & BIT(31)) ? "yes" : "no");
830 edac_dbg(1, "UMC%d All DIMMs support ECC: %s\n",
831 i, (umc->umc_cfg & BIT(12)) ? "yes" : "no");
832 edac_dbg(1, "UMC%d x4 DIMMs present: %s\n",
833 i, (umc->dimm_cfg & BIT(6)) ? "yes" : "no");
834 edac_dbg(1, "UMC%d x16 DIMMs present: %s\n",
835 i, (umc->dimm_cfg & BIT(7)) ? "yes" : "no");
836
837 if (pvt->dram_type == MEM_LRDDR4) {
838 amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_ADDR_CFG, &tmp);
839 edac_dbg(1, "UMC%d LRDIMM %dx rank multiply\n",
840 i, 1 << ((tmp >> 4) & 0x3));
841 }
842
843 debug_display_dimm_sizes_df(pvt, i);
844 }
845
846 edac_dbg(1, "F0x104 (DRAM Hole Address): 0x%08x, base: 0x%08x\n",
847 pvt->dhar, dhar_base(pvt));
848}
849
Doug Thompson2da11652009-04-27 16:09:09 +0200850/* Display and decode various NB registers for debug purposes. */
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600851static void __dump_misc_regs(struct amd64_pvt *pvt)
Doug Thompson2da11652009-04-27 16:09:09 +0200852{
Joe Perches956b9ba2012-04-29 17:08:39 -0300853 edac_dbg(1, "F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap);
Doug Thompson2da11652009-04-27 16:09:09 +0200854
Joe Perches956b9ba2012-04-29 17:08:39 -0300855 edac_dbg(1, " NB two channel DRAM capable: %s\n",
856 (pvt->nbcap & NBCAP_DCT_DUAL) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100857
Joe Perches956b9ba2012-04-29 17:08:39 -0300858 edac_dbg(1, " ECC capable: %s, ChipKill ECC capable: %s\n",
859 (pvt->nbcap & NBCAP_SECDED) ? "yes" : "no",
860 (pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100861
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100862 debug_dump_dramcfg_low(pvt, pvt->dclr0, 0);
Doug Thompson2da11652009-04-27 16:09:09 +0200863
Joe Perches956b9ba2012-04-29 17:08:39 -0300864 edac_dbg(1, "F3xB0 (Online Spare): 0x%08x\n", pvt->online_spare);
Doug Thompson2da11652009-04-27 16:09:09 +0200865
Joe Perches956b9ba2012-04-29 17:08:39 -0300866 edac_dbg(1, "F1xF0 (DRAM Hole Address): 0x%08x, base: 0x%08x, offset: 0x%08x\n",
867 pvt->dhar, dhar_base(pvt),
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200868 (pvt->fam == 0xf) ? k8_dhar_offset(pvt)
869 : f10_dhar_offset(pvt));
Doug Thompson2da11652009-04-27 16:09:09 +0200870
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100871 debug_display_dimm_sizes(pvt, 0);
Borislav Petkov4d796362011-02-03 15:59:57 +0100872
Borislav Petkov8de1d912009-10-16 13:39:30 +0200873 /* everything below this point is Fam10h and above */
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200874 if (pvt->fam == 0xf)
Doug Thompson2da11652009-04-27 16:09:09 +0200875 return;
Borislav Petkov4d796362011-02-03 15:59:57 +0100876
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100877 debug_display_dimm_sizes(pvt, 1);
Doug Thompson2da11652009-04-27 16:09:09 +0200878
Borislav Petkov8de1d912009-10-16 13:39:30 +0200879 /* Only if NOT ganged does dclr1 have valid info */
Borislav Petkov68798e12009-11-03 16:18:33 +0100880 if (!dct_ganging_enabled(pvt))
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100881 debug_dump_dramcfg_low(pvt, pvt->dclr1, 1);
Doug Thompson2da11652009-04-27 16:09:09 +0200882}
883
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600884/* Display and decode various NB registers for debug purposes. */
885static void dump_misc_regs(struct amd64_pvt *pvt)
886{
887 if (pvt->umc)
888 __dump_misc_regs_df(pvt);
889 else
890 __dump_misc_regs(pvt);
891
892 edac_dbg(1, " DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no");
893
894 amd64_info("using %s syndromes.\n",
895 ((pvt->ecc_sym_sz == 8) ? "x8" : "x4"));
896}
897
Doug Thompson94be4bf2009-04-27 16:12:00 +0200898/*
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -0500899 * See BKDG, F2x[1,0][5C:40], F2[1,0][6C:60]
Doug Thompson94be4bf2009-04-27 16:12:00 +0200900 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100901static void prep_chip_selects(struct amd64_pvt *pvt)
Doug Thompson94be4bf2009-04-27 16:12:00 +0200902{
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -0500903 if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) {
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100904 pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
905 pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 8;
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +0100906 } else if (pvt->fam == 0x15 && pvt->model == 0x30) {
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -0500907 pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4;
908 pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2;
Borislav Petkov9d858bb2009-09-21 14:35:51 +0200909 } else {
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100910 pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
911 pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4;
Doug Thompson94be4bf2009-04-27 16:12:00 +0200912 }
913}
914
915/*
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100916 * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers
Doug Thompson94be4bf2009-04-27 16:12:00 +0200917 */
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200918static void read_dct_base_mask(struct amd64_pvt *pvt)
Doug Thompson94be4bf2009-04-27 16:12:00 +0200919{
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500920 int base_reg0, base_reg1, mask_reg0, mask_reg1, cs;
Doug Thompson94be4bf2009-04-27 16:12:00 +0200921
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100922 prep_chip_selects(pvt);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200923
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500924 if (pvt->umc) {
925 base_reg0 = get_umc_base(0) + UMCCH_BASE_ADDR;
926 base_reg1 = get_umc_base(1) + UMCCH_BASE_ADDR;
927 mask_reg0 = get_umc_base(0) + UMCCH_ADDR_MASK;
928 mask_reg1 = get_umc_base(1) + UMCCH_ADDR_MASK;
929 } else {
930 base_reg0 = DCSB0;
931 base_reg1 = DCSB1;
932 mask_reg0 = DCSM0;
933 mask_reg1 = DCSM1;
934 }
935
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100936 for_each_chip_select(cs, 0, pvt) {
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500937 int reg0 = base_reg0 + (cs * 4);
938 int reg1 = base_reg1 + (cs * 4);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100939 u32 *base0 = &pvt->csels[0].csbases[cs];
940 u32 *base1 = &pvt->csels[1].csbases[cs];
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200941
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500942 if (pvt->umc) {
943 if (!amd_smn_read(pvt->mc_node_id, reg0, base0))
944 edac_dbg(0, " DCSB0[%d]=0x%08x reg: 0x%x\n",
945 cs, *base0, reg0);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200946
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500947 if (!amd_smn_read(pvt->mc_node_id, reg1, base1))
948 edac_dbg(0, " DCSB1[%d]=0x%08x reg: 0x%x\n",
949 cs, *base1, reg1);
950 } else {
951 if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, base0))
952 edac_dbg(0, " DCSB0[%d]=0x%08x reg: F2x%x\n",
953 cs, *base0, reg0);
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200954
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500955 if (pvt->fam == 0xf)
956 continue;
957
958 if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, base1))
959 edac_dbg(0, " DCSB1[%d]=0x%08x reg: F2x%x\n",
960 cs, *base1, (pvt->fam == 0x10) ? reg1
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -0500961 : reg0);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500962 }
Doug Thompson94be4bf2009-04-27 16:12:00 +0200963 }
964
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100965 for_each_chip_select_mask(cs, 0, pvt) {
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500966 int reg0 = mask_reg0 + (cs * 4);
967 int reg1 = mask_reg1 + (cs * 4);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100968 u32 *mask0 = &pvt->csels[0].csmasks[cs];
969 u32 *mask1 = &pvt->csels[1].csmasks[cs];
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200970
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500971 if (pvt->umc) {
972 if (!amd_smn_read(pvt->mc_node_id, reg0, mask0))
973 edac_dbg(0, " DCSM0[%d]=0x%08x reg: 0x%x\n",
974 cs, *mask0, reg0);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200975
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500976 if (!amd_smn_read(pvt->mc_node_id, reg1, mask1))
977 edac_dbg(0, " DCSM1[%d]=0x%08x reg: 0x%x\n",
978 cs, *mask1, reg1);
979 } else {
980 if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, mask0))
981 edac_dbg(0, " DCSM0[%d]=0x%08x reg: F2x%x\n",
982 cs, *mask0, reg0);
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200983
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500984 if (pvt->fam == 0xf)
985 continue;
986
987 if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, mask1))
988 edac_dbg(0, " DCSM1[%d]=0x%08x reg: F2x%x\n",
989 cs, *mask1, (pvt->fam == 0x10) ? reg1
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -0500990 : reg0);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500991 }
Doug Thompson94be4bf2009-04-27 16:12:00 +0200992 }
993}
994
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +0100995static void determine_memory_type(struct amd64_pvt *pvt)
Doug Thompson94be4bf2009-04-27 16:12:00 +0200996{
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +0100997 u32 dram_ctrl, dcsm;
Doug Thompson94be4bf2009-04-27 16:12:00 +0200998
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +0100999 switch (pvt->fam) {
1000 case 0xf:
1001 if (pvt->ext_model >= K8_REV_F)
1002 goto ddr3;
1003
1004 pvt->dram_type = (pvt->dclr0 & BIT(18)) ? MEM_DDR : MEM_RDDR;
1005 return;
1006
1007 case 0x10:
Borislav Petkov6b4c0bd2009-11-12 15:37:57 +01001008 if (pvt->dchr0 & DDR3_MODE)
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001009 goto ddr3;
1010
1011 pvt->dram_type = (pvt->dclr0 & BIT(16)) ? MEM_DDR2 : MEM_RDDR2;
1012 return;
1013
1014 case 0x15:
1015 if (pvt->model < 0x60)
1016 goto ddr3;
1017
1018 /*
1019 * Model 0x60h needs special handling:
1020 *
1021 * We use a Chip Select value of '0' to obtain dcsm.
1022 * Theoretically, it is possible to populate LRDIMMs of different
1023 * 'Rank' value on a DCT. But this is not the common case. So,
1024 * it's reasonable to assume all DIMMs are going to be of same
1025 * 'type' until proven otherwise.
1026 */
1027 amd64_read_dct_pci_cfg(pvt, 0, DRAM_CONTROL, &dram_ctrl);
1028 dcsm = pvt->csels[0].csmasks[0];
1029
1030 if (((dram_ctrl >> 8) & 0x7) == 0x2)
1031 pvt->dram_type = MEM_DDR4;
1032 else if (pvt->dclr0 & BIT(16))
1033 pvt->dram_type = MEM_DDR3;
1034 else if (dcsm & 0x3)
1035 pvt->dram_type = MEM_LRDDR3;
Borislav Petkov6b4c0bd2009-11-12 15:37:57 +01001036 else
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001037 pvt->dram_type = MEM_RDDR3;
1038
1039 return;
1040
1041 case 0x16:
1042 goto ddr3;
1043
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05001044 case 0x17:
1045 if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(5))
1046 pvt->dram_type = MEM_LRDDR4;
1047 else if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(4))
1048 pvt->dram_type = MEM_RDDR4;
1049 else
1050 pvt->dram_type = MEM_DDR4;
1051 return;
1052
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001053 default:
1054 WARN(1, KERN_ERR "%s: Family??? 0x%x\n", __func__, pvt->fam);
1055 pvt->dram_type = MEM_EMPTY;
Doug Thompson94be4bf2009-04-27 16:12:00 +02001056 }
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001057 return;
Doug Thompson94be4bf2009-04-27 16:12:00 +02001058
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001059ddr3:
1060 pvt->dram_type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3;
Doug Thompson94be4bf2009-04-27 16:12:00 +02001061}
1062
Borislav Petkovcb328502010-12-22 14:28:24 +01001063/* Get the number of DCT channels the memory controller is using. */
Doug Thompsonddff8762009-04-27 16:14:52 +02001064static int k8_early_channel_count(struct amd64_pvt *pvt)
1065{
Borislav Petkovcb328502010-12-22 14:28:24 +01001066 int flag;
Doug Thompsonddff8762009-04-27 16:14:52 +02001067
Borislav Petkov9f56da02010-10-01 19:44:53 +02001068 if (pvt->ext_model >= K8_REV_F)
Doug Thompsonddff8762009-04-27 16:14:52 +02001069 /* RevF (NPT) and later */
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001070 flag = pvt->dclr0 & WIDTH_128;
Borislav Petkov9f56da02010-10-01 19:44:53 +02001071 else
Doug Thompsonddff8762009-04-27 16:14:52 +02001072 /* RevE and earlier */
1073 flag = pvt->dclr0 & REVE_WIDTH_128;
Doug Thompsonddff8762009-04-27 16:14:52 +02001074
1075 /* not used */
1076 pvt->dclr1 = 0;
1077
1078 return (flag) ? 2 : 1;
1079}
1080
Borislav Petkov70046622011-01-10 14:37:27 +01001081/* On F10h and later ErrAddr is MC4_ADDR[47:1] */
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001082static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m)
Doug Thompsonddff8762009-04-27 16:14:52 +02001083{
Borislav Petkov2ec591a2015-02-17 10:58:34 +01001084 u16 mce_nid = amd_get_nb_id(m->extcpu);
1085 struct mem_ctl_info *mci;
Borislav Petkov70046622011-01-10 14:37:27 +01001086 u8 start_bit = 1;
1087 u8 end_bit = 47;
Borislav Petkov2ec591a2015-02-17 10:58:34 +01001088 u64 addr;
1089
1090 mci = edac_mc_find(mce_nid);
1091 if (!mci)
1092 return 0;
1093
1094 pvt = mci->pvt_info;
Borislav Petkov70046622011-01-10 14:37:27 +01001095
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001096 if (pvt->fam == 0xf) {
Borislav Petkov70046622011-01-10 14:37:27 +01001097 start_bit = 3;
1098 end_bit = 39;
1099 }
1100
Chen, Gong10ef6b02013-10-18 14:29:07 -07001101 addr = m->addr & GENMASK_ULL(end_bit, start_bit);
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001102
1103 /*
1104 * Erratum 637 workaround
1105 */
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001106 if (pvt->fam == 0x15) {
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001107 u64 cc6_base, tmp_addr;
1108 u32 tmp;
Daniel J Blueman8b84c8d2012-11-27 14:32:10 +08001109 u8 intlv_en;
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001110
Chen, Gong10ef6b02013-10-18 14:29:07 -07001111 if ((addr & GENMASK_ULL(47, 24)) >> 24 != 0x00fdf7)
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001112 return addr;
1113
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001114
1115 amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_LIM, &tmp);
1116 intlv_en = tmp >> 21 & 0x7;
1117
1118 /* add [47:27] + 3 trailing bits */
Chen, Gong10ef6b02013-10-18 14:29:07 -07001119 cc6_base = (tmp & GENMASK_ULL(20, 0)) << 3;
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001120
1121 /* reverse and add DramIntlvEn */
1122 cc6_base |= intlv_en ^ 0x7;
1123
1124 /* pin at [47:24] */
1125 cc6_base <<= 24;
1126
1127 if (!intlv_en)
Chen, Gong10ef6b02013-10-18 14:29:07 -07001128 return cc6_base | (addr & GENMASK_ULL(23, 0));
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001129
1130 amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_BASE, &tmp);
1131
1132 /* faster log2 */
Chen, Gong10ef6b02013-10-18 14:29:07 -07001133 tmp_addr = (addr & GENMASK_ULL(23, 12)) << __fls(intlv_en + 1);
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001134
1135 /* OR DramIntlvSel into bits [14:12] */
Chen, Gong10ef6b02013-10-18 14:29:07 -07001136 tmp_addr |= (tmp & GENMASK_ULL(23, 21)) >> 9;
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001137
1138 /* add remaining [11:0] bits from original MC4_ADDR */
Chen, Gong10ef6b02013-10-18 14:29:07 -07001139 tmp_addr |= addr & GENMASK_ULL(11, 0);
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001140
1141 return cc6_base | tmp_addr;
1142 }
1143
1144 return addr;
Doug Thompsonddff8762009-04-27 16:14:52 +02001145}
1146
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001147static struct pci_dev *pci_get_related_function(unsigned int vendor,
1148 unsigned int device,
1149 struct pci_dev *related)
1150{
1151 struct pci_dev *dev = NULL;
1152
1153 while ((dev = pci_get_device(vendor, device, dev))) {
1154 if (pci_domain_nr(dev->bus) == pci_domain_nr(related->bus) &&
1155 (dev->bus->number == related->bus->number) &&
1156 (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
1157 break;
1158 }
1159
1160 return dev;
1161}
1162
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001163static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
Doug Thompsonddff8762009-04-27 16:14:52 +02001164{
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001165 struct amd_northbridge *nb;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001166 struct pci_dev *f1 = NULL;
1167 unsigned int pci_func;
Borislav Petkov71d2a322011-02-21 19:37:24 +01001168 int off = range << 3;
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001169 u32 llim;
Doug Thompsonddff8762009-04-27 16:14:52 +02001170
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001171 amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo);
1172 amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
Doug Thompsonddff8762009-04-27 16:14:52 +02001173
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001174 if (pvt->fam == 0xf)
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001175 return;
Doug Thompsonddff8762009-04-27 16:14:52 +02001176
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001177 if (!dram_rw(pvt, range))
1178 return;
Doug Thompsonddff8762009-04-27 16:14:52 +02001179
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001180 amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi);
1181 amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
Borislav Petkovf08e4572011-03-21 20:45:06 +01001182
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001183 /* F15h: factor in CC6 save area by reading dst node's limit reg */
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001184 if (pvt->fam != 0x15)
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001185 return;
Borislav Petkovf08e4572011-03-21 20:45:06 +01001186
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001187 nb = node_to_amd_nb(dram_dst_node(pvt, range));
1188 if (WARN_ON(!nb))
1189 return;
Borislav Petkovf08e4572011-03-21 20:45:06 +01001190
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001191 if (pvt->model == 0x60)
1192 pci_func = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1;
1193 else if (pvt->model == 0x30)
1194 pci_func = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1;
1195 else
1196 pci_func = PCI_DEVICE_ID_AMD_15H_NB_F1;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001197
1198 f1 = pci_get_related_function(nb->misc->vendor, pci_func, nb->misc);
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001199 if (WARN_ON(!f1))
1200 return;
Borislav Petkovf08e4572011-03-21 20:45:06 +01001201
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001202 amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
Borislav Petkovf08e4572011-03-21 20:45:06 +01001203
Chen, Gong10ef6b02013-10-18 14:29:07 -07001204 pvt->ranges[range].lim.lo &= GENMASK_ULL(15, 0);
Borislav Petkovf08e4572011-03-21 20:45:06 +01001205
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001206 /* {[39:27],111b} */
1207 pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
Borislav Petkovf08e4572011-03-21 20:45:06 +01001208
Chen, Gong10ef6b02013-10-18 14:29:07 -07001209 pvt->ranges[range].lim.hi &= GENMASK_ULL(7, 0);
Borislav Petkovf08e4572011-03-21 20:45:06 +01001210
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001211 /* [47:40] */
1212 pvt->ranges[range].lim.hi |= llim >> 13;
1213
1214 pci_dev_put(f1);
Doug Thompsonddff8762009-04-27 16:14:52 +02001215}
1216
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001217static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
Borislav Petkov33ca0642012-08-30 18:01:36 +02001218 struct err_info *err)
Doug Thompsonddff8762009-04-27 16:14:52 +02001219{
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001220 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompsonddff8762009-04-27 16:14:52 +02001221
Borislav Petkov33ca0642012-08-30 18:01:36 +02001222 error_address_to_page_and_offset(sys_addr, err);
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001223
1224 /*
1225 * Find out which node the error address belongs to. This may be
1226 * different from the node that detected the error.
1227 */
Borislav Petkov33ca0642012-08-30 18:01:36 +02001228 err->src_mci = find_mc_by_sys_addr(mci, sys_addr);
1229 if (!err->src_mci) {
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001230 amd64_mc_err(mci, "failed to map error addr 0x%lx to a node\n",
1231 (unsigned long)sys_addr);
Borislav Petkov33ca0642012-08-30 18:01:36 +02001232 err->err_code = ERR_NODE;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001233 return;
1234 }
1235
1236 /* Now map the sys_addr to a CSROW */
Borislav Petkov33ca0642012-08-30 18:01:36 +02001237 err->csrow = sys_addr_to_csrow(err->src_mci, sys_addr);
1238 if (err->csrow < 0) {
1239 err->err_code = ERR_CSROW;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001240 return;
1241 }
1242
Doug Thompsonddff8762009-04-27 16:14:52 +02001243 /* CHIPKILL enabled */
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001244 if (pvt->nbcfg & NBCFG_CHIPKILL) {
Borislav Petkov33ca0642012-08-30 18:01:36 +02001245 err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome);
1246 if (err->channel < 0) {
Doug Thompsonddff8762009-04-27 16:14:52 +02001247 /*
1248 * Syndrome didn't map, so we don't know which of the
1249 * 2 DIMMs is in error. So we need to ID 'both' of them
1250 * as suspect.
1251 */
Borislav Petkov33ca0642012-08-30 18:01:36 +02001252 amd64_mc_warn(err->src_mci, "unknown syndrome 0x%04x - "
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001253 "possible error reporting race\n",
Borislav Petkov33ca0642012-08-30 18:01:36 +02001254 err->syndrome);
1255 err->err_code = ERR_CHANNEL;
Doug Thompsonddff8762009-04-27 16:14:52 +02001256 return;
1257 }
1258 } else {
1259 /*
1260 * non-chipkill ecc mode
1261 *
1262 * The k8 documentation is unclear about how to determine the
1263 * channel number when using non-chipkill memory. This method
1264 * was obtained from email communication with someone at AMD.
1265 * (Wish the email was placed in this comment - norsk)
1266 */
Borislav Petkov33ca0642012-08-30 18:01:36 +02001267 err->channel = ((sys_addr & BIT(3)) != 0);
Doug Thompsonddff8762009-04-27 16:14:52 +02001268 }
Doug Thompsonddff8762009-04-27 16:14:52 +02001269}
1270
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001271static int ddr2_cs_size(unsigned i, bool dct_width)
Doug Thompsonddff8762009-04-27 16:14:52 +02001272{
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001273 unsigned shift = 0;
Doug Thompsonddff8762009-04-27 16:14:52 +02001274
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001275 if (i <= 2)
1276 shift = i;
1277 else if (!(i & 0x1))
1278 shift = i >> 1;
Borislav Petkov1433eb92009-10-21 13:44:36 +02001279 else
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001280 shift = (i + 1) >> 1;
Doug Thompsonddff8762009-04-27 16:14:52 +02001281
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001282 return 128 << (shift + !!dct_width);
1283}
1284
1285static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001286 unsigned cs_mode, int cs_mask_nr)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001287{
1288 u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
1289
1290 if (pvt->ext_model >= K8_REV_F) {
1291 WARN_ON(cs_mode > 11);
1292 return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
1293 }
1294 else if (pvt->ext_model >= K8_REV_D) {
Borislav Petkov11b0a312011-11-09 21:28:43 +01001295 unsigned diff;
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001296 WARN_ON(cs_mode > 10);
1297
Borislav Petkov11b0a312011-11-09 21:28:43 +01001298 /*
1299 * the below calculation, besides trying to win an obfuscated C
1300 * contest, maps cs_mode values to DIMM chip select sizes. The
1301 * mappings are:
1302 *
1303 * cs_mode CS size (mb)
1304 * ======= ============
1305 * 0 32
1306 * 1 64
1307 * 2 128
1308 * 3 128
1309 * 4 256
1310 * 5 512
1311 * 6 256
1312 * 7 512
1313 * 8 1024
1314 * 9 1024
1315 * 10 2048
1316 *
1317 * Basically, it calculates a value with which to shift the
1318 * smallest CS size of 32MB.
1319 *
1320 * ddr[23]_cs_size have a similar purpose.
1321 */
1322 diff = cs_mode/3 + (unsigned)(cs_mode > 5);
1323
1324 return 32 << (cs_mode - diff);
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001325 }
1326 else {
1327 WARN_ON(cs_mode > 6);
1328 return 32 << cs_mode;
1329 }
Doug Thompsonddff8762009-04-27 16:14:52 +02001330}
1331
Doug Thompson1afd3c92009-04-27 16:16:50 +02001332/*
1333 * Get the number of DCT channels in use.
1334 *
1335 * Return:
1336 * number of Memory Channels in operation
1337 * Pass back:
1338 * contents of the DCL0_LOW register
1339 */
Borislav Petkov7d20d142011-01-07 17:58:04 +01001340static int f1x_early_channel_count(struct amd64_pvt *pvt)
Doug Thompson1afd3c92009-04-27 16:16:50 +02001341{
Borislav Petkov6ba5dcd2009-10-13 19:26:55 +02001342 int i, j, channels = 0;
Doug Thompsonddff8762009-04-27 16:14:52 +02001343
Borislav Petkov7d20d142011-01-07 17:58:04 +01001344 /* On F10h, if we are in 128 bit mode, then we are using 2 channels */
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001345 if (pvt->fam == 0x10 && (pvt->dclr0 & WIDTH_128))
Borislav Petkov7d20d142011-01-07 17:58:04 +01001346 return 2;
Doug Thompson1afd3c92009-04-27 16:16:50 +02001347
1348 /*
Borislav Petkovd16149e2009-10-16 19:55:49 +02001349 * Need to check if in unganged mode: In such, there are 2 channels,
1350 * but they are not in 128 bit mode and thus the above 'dclr0' status
1351 * bit will be OFF.
Doug Thompson1afd3c92009-04-27 16:16:50 +02001352 *
1353 * Need to check DCT0[0] and DCT1[0] to see if only one of them has
1354 * their CSEnable bit on. If so, then SINGLE DIMM case.
1355 */
Joe Perches956b9ba2012-04-29 17:08:39 -03001356 edac_dbg(0, "Data width is not 128 bits - need more decoding\n");
Doug Thompson1afd3c92009-04-27 16:16:50 +02001357
1358 /*
1359 * Check DRAM Bank Address Mapping values for each DIMM to see if there
1360 * is more than just one DIMM present in unganged mode. Need to check
1361 * both controllers since DIMMs can be placed in either one.
1362 */
Borislav Petkov525a1b22010-12-21 15:53:27 +01001363 for (i = 0; i < 2; i++) {
1364 u32 dbam = (i ? pvt->dbam1 : pvt->dbam0);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001365
Wan Wei57a30852009-08-07 17:04:49 +02001366 for (j = 0; j < 4; j++) {
1367 if (DBAM_DIMM(j, dbam) > 0) {
1368 channels++;
1369 break;
1370 }
1371 }
Doug Thompson1afd3c92009-04-27 16:16:50 +02001372 }
1373
Borislav Petkovd16149e2009-10-16 19:55:49 +02001374 if (channels > 2)
1375 channels = 2;
1376
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001377 amd64_info("MCT channel count: %d\n", channels);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001378
1379 return channels;
Doug Thompson1afd3c92009-04-27 16:16:50 +02001380}
1381
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05001382static int f17_early_channel_count(struct amd64_pvt *pvt)
1383{
1384 int i, channels = 0;
1385
1386 /* SDP Control bit 31 (SdpInit) is clear for unused UMC channels */
1387 for (i = 0; i < NUM_UMCS; i++)
1388 channels += !!(pvt->umc[i].sdp_ctrl & UMC_SDP_INIT);
1389
1390 amd64_info("MCT channel count: %d\n", channels);
1391
1392 return channels;
1393}
1394
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001395static int ddr3_cs_size(unsigned i, bool dct_width)
Doug Thompson1afd3c92009-04-27 16:16:50 +02001396{
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001397 unsigned shift = 0;
1398 int cs_size = 0;
1399
1400 if (i == 0 || i == 3 || i == 4)
1401 cs_size = -1;
1402 else if (i <= 2)
1403 shift = i;
1404 else if (i == 12)
1405 shift = 7;
1406 else if (!(i & 0x1))
1407 shift = i >> 1;
1408 else
1409 shift = (i + 1) >> 1;
1410
1411 if (cs_size != -1)
1412 cs_size = (128 * (1 << !!dct_width)) << shift;
1413
1414 return cs_size;
1415}
1416
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001417static int ddr3_lrdimm_cs_size(unsigned i, unsigned rank_multiply)
1418{
1419 unsigned shift = 0;
1420 int cs_size = 0;
1421
1422 if (i < 4 || i == 6)
1423 cs_size = -1;
1424 else if (i == 12)
1425 shift = 7;
1426 else if (!(i & 0x1))
1427 shift = i >> 1;
1428 else
1429 shift = (i + 1) >> 1;
1430
1431 if (cs_size != -1)
1432 cs_size = rank_multiply * (128 << shift);
1433
1434 return cs_size;
1435}
1436
1437static int ddr4_cs_size(unsigned i)
1438{
1439 int cs_size = 0;
1440
1441 if (i == 0)
1442 cs_size = -1;
1443 else if (i == 1)
1444 cs_size = 1024;
1445 else
1446 /* Min cs_size = 1G */
1447 cs_size = 1024 * (1 << (i >> 1));
1448
1449 return cs_size;
1450}
1451
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001452static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001453 unsigned cs_mode, int cs_mask_nr)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001454{
1455 u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
1456
1457 WARN_ON(cs_mode > 11);
Borislav Petkov1433eb92009-10-21 13:44:36 +02001458
1459 if (pvt->dchr0 & DDR3_MODE || pvt->dchr1 & DDR3_MODE)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001460 return ddr3_cs_size(cs_mode, dclr & WIDTH_128);
Borislav Petkov1433eb92009-10-21 13:44:36 +02001461 else
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001462 return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
1463}
Borislav Petkov1433eb92009-10-21 13:44:36 +02001464
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001465/*
1466 * F15h supports only 64bit DCT interfaces
1467 */
1468static int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001469 unsigned cs_mode, int cs_mask_nr)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001470{
1471 WARN_ON(cs_mode > 12);
1472
1473 return ddr3_cs_size(cs_mode, false);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001474}
1475
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001476/* F15h M60h supports DDR4 mapping as well.. */
1477static int f15_m60h_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
1478 unsigned cs_mode, int cs_mask_nr)
1479{
1480 int cs_size;
1481 u32 dcsm = pvt->csels[dct].csmasks[cs_mask_nr];
1482
1483 WARN_ON(cs_mode > 12);
1484
1485 if (pvt->dram_type == MEM_DDR4) {
1486 if (cs_mode > 9)
1487 return -1;
1488
1489 cs_size = ddr4_cs_size(cs_mode);
1490 } else if (pvt->dram_type == MEM_LRDDR3) {
1491 unsigned rank_multiply = dcsm & 0xf;
1492
1493 if (rank_multiply == 3)
1494 rank_multiply = 4;
1495 cs_size = ddr3_lrdimm_cs_size(cs_mode, rank_multiply);
1496 } else {
1497 /* Minimum cs size is 512mb for F15hM60h*/
1498 if (cs_mode == 0x1)
1499 return -1;
1500
1501 cs_size = ddr3_cs_size(cs_mode, false);
1502 }
1503
1504 return cs_size;
1505}
1506
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05001507/*
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001508 * F16h and F15h model 30h have only limited cs_modes.
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05001509 */
1510static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001511 unsigned cs_mode, int cs_mask_nr)
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05001512{
1513 WARN_ON(cs_mode > 12);
1514
1515 if (cs_mode == 6 || cs_mode == 8 ||
1516 cs_mode == 9 || cs_mode == 12)
1517 return -1;
1518 else
1519 return ddr3_cs_size(cs_mode, false);
1520}
1521
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05001522static int f17_base_addr_to_cs_size(struct amd64_pvt *pvt, u8 umc,
1523 unsigned int cs_mode, int csrow_nr)
1524{
1525 u32 base_addr = pvt->csels[umc].csbases[csrow_nr];
1526
1527 /* Each mask is used for every two base addresses. */
1528 u32 addr_mask = pvt->csels[umc].csmasks[csrow_nr >> 1];
1529
1530 /* Register [31:1] = Address [39:9]. Size is in kBs here. */
1531 u32 size = ((addr_mask >> 1) - (base_addr >> 1) + 1) >> 1;
1532
1533 edac_dbg(1, "BaseAddr: 0x%x, AddrMask: 0x%x\n", base_addr, addr_mask);
1534
1535 /* Return size in MBs. */
1536 return size >> 10;
1537}
1538
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001539static void read_dram_ctl_register(struct amd64_pvt *pvt)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001540{
Doug Thompson6163b5d2009-04-27 16:20:17 +02001541
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001542 if (pvt->fam == 0xf)
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001543 return;
1544
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05001545 if (!amd64_read_pci_cfg(pvt->F2, DCT_SEL_LO, &pvt->dct_sel_lo)) {
Joe Perches956b9ba2012-04-29 17:08:39 -03001546 edac_dbg(0, "F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x\n",
1547 pvt->dct_sel_lo, dct_sel_baseaddr(pvt));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001548
Joe Perches956b9ba2012-04-29 17:08:39 -03001549 edac_dbg(0, " DCTs operate in %s mode\n",
1550 (dct_ganging_enabled(pvt) ? "ganged" : "unganged"));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001551
Borislav Petkov72381bd2009-10-09 19:14:43 +02001552 if (!dct_ganging_enabled(pvt))
Joe Perches956b9ba2012-04-29 17:08:39 -03001553 edac_dbg(0, " Address range split per DCT: %s\n",
1554 (dct_high_range_enabled(pvt) ? "yes" : "no"));
Borislav Petkov72381bd2009-10-09 19:14:43 +02001555
Joe Perches956b9ba2012-04-29 17:08:39 -03001556 edac_dbg(0, " data interleave for ECC: %s, DRAM cleared since last warm reset: %s\n",
1557 (dct_data_intlv_enabled(pvt) ? "enabled" : "disabled"),
1558 (dct_memory_cleared(pvt) ? "yes" : "no"));
Borislav Petkov72381bd2009-10-09 19:14:43 +02001559
Joe Perches956b9ba2012-04-29 17:08:39 -03001560 edac_dbg(0, " channel interleave: %s, "
1561 "interleave bits selector: 0x%x\n",
1562 (dct_interleave_enabled(pvt) ? "enabled" : "disabled"),
1563 dct_sel_interleave_addr(pvt));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001564 }
1565
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05001566 amd64_read_pci_cfg(pvt->F2, DCT_SEL_HI, &pvt->dct_sel_hi);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001567}
1568
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001569/*
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001570 * Determine channel (DCT) based on the interleaving mode (see F15h M30h BKDG,
1571 * 2.10.12 Memory Interleaving Modes).
1572 */
1573static u8 f15_m30h_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
1574 u8 intlv_en, int num_dcts_intlv,
1575 u32 dct_sel)
1576{
1577 u8 channel = 0;
1578 u8 select;
1579
1580 if (!(intlv_en))
1581 return (u8)(dct_sel);
1582
1583 if (num_dcts_intlv == 2) {
1584 select = (sys_addr >> 8) & 0x3;
1585 channel = select ? 0x3 : 0;
Aravind Gopalakrishnan9d0e8d82014-01-21 15:03:36 -06001586 } else if (num_dcts_intlv == 4) {
1587 u8 intlv_addr = dct_sel_interleave_addr(pvt);
1588 switch (intlv_addr) {
1589 case 0x4:
1590 channel = (sys_addr >> 8) & 0x3;
1591 break;
1592 case 0x5:
1593 channel = (sys_addr >> 9) & 0x3;
1594 break;
1595 }
1596 }
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001597 return channel;
1598}
1599
1600/*
Borislav Petkov229a7a12010-12-09 18:57:54 +01001601 * Determine channel (DCT) based on the interleaving mode: F10h BKDG, 2.8.9 Memory
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001602 * Interleaving Modes.
1603 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001604static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
Borislav Petkov229a7a12010-12-09 18:57:54 +01001605 bool hi_range_sel, u8 intlv_en)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001606{
Borislav Petkov151fa712011-02-21 19:33:10 +01001607 u8 dct_sel_high = (pvt->dct_sel_lo >> 1) & 1;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001608
1609 if (dct_ganging_enabled(pvt))
Borislav Petkov229a7a12010-12-09 18:57:54 +01001610 return 0;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001611
Borislav Petkov229a7a12010-12-09 18:57:54 +01001612 if (hi_range_sel)
1613 return dct_sel_high;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001614
Borislav Petkov229a7a12010-12-09 18:57:54 +01001615 /*
1616 * see F2x110[DctSelIntLvAddr] - channel interleave mode
1617 */
1618 if (dct_interleave_enabled(pvt)) {
1619 u8 intlv_addr = dct_sel_interleave_addr(pvt);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001620
Borislav Petkov229a7a12010-12-09 18:57:54 +01001621 /* return DCT select function: 0=DCT0, 1=DCT1 */
1622 if (!intlv_addr)
1623 return sys_addr >> 6 & 1;
1624
1625 if (intlv_addr & 0x2) {
1626 u8 shift = intlv_addr & 0x1 ? 9 : 6;
Yazen Ghannamdc0a50a82016-08-03 10:59:15 -04001627 u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) & 1;
Borislav Petkov229a7a12010-12-09 18:57:54 +01001628
1629 return ((sys_addr >> shift) & 1) ^ temp;
1630 }
1631
Yazen Ghannamdc0a50a82016-08-03 10:59:15 -04001632 if (intlv_addr & 0x4) {
1633 u8 shift = intlv_addr & 0x1 ? 9 : 8;
1634
1635 return (sys_addr >> shift) & 1;
1636 }
1637
Borislav Petkov229a7a12010-12-09 18:57:54 +01001638 return (sys_addr >> (12 + hweight8(intlv_en))) & 1;
1639 }
1640
1641 if (dct_high_range_enabled(pvt))
1642 return ~dct_sel_high & 1;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001643
1644 return 0;
1645}
1646
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001647/* Convert the sys_addr to the normalized DCT address */
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08001648static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range,
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001649 u64 sys_addr, bool hi_rng,
1650 u32 dct_sel_base_addr)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001651{
1652 u64 chan_off;
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001653 u64 dram_base = get_dram_base(pvt, range);
1654 u64 hole_off = f10_dhar_offset(pvt);
Dan Carpenter6f3508f2016-01-20 12:54:51 +03001655 u64 dct_sel_base_off = (u64)(pvt->dct_sel_hi & 0xFFFFFC00) << 16;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001656
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001657 if (hi_rng) {
1658 /*
1659 * if
1660 * base address of high range is below 4Gb
1661 * (bits [47:27] at [31:11])
1662 * DRAM address space on this DCT is hoisted above 4Gb &&
1663 * sys_addr > 4Gb
1664 *
1665 * remove hole offset from sys_addr
1666 * else
1667 * remove high range offset from sys_addr
1668 */
1669 if ((!(dct_sel_base_addr >> 16) ||
1670 dct_sel_base_addr < dhar_base(pvt)) &&
Borislav Petkov972ea172011-02-21 19:43:02 +01001671 dhar_valid(pvt) &&
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001672 (sys_addr >= BIT_64(32)))
Borislav Petkovbc21fa52010-11-11 17:29:13 +01001673 chan_off = hole_off;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001674 else
1675 chan_off = dct_sel_base_off;
1676 } else {
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001677 /*
1678 * if
1679 * we have a valid hole &&
1680 * sys_addr > 4Gb
1681 *
1682 * remove hole
1683 * else
1684 * remove dram base to normalize to DCT address
1685 */
Borislav Petkov972ea172011-02-21 19:43:02 +01001686 if (dhar_valid(pvt) && (sys_addr >= BIT_64(32)))
Borislav Petkovbc21fa52010-11-11 17:29:13 +01001687 chan_off = hole_off;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001688 else
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001689 chan_off = dram_base;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001690 }
1691
Chen, Gong10ef6b02013-10-18 14:29:07 -07001692 return (sys_addr & GENMASK_ULL(47,6)) - (chan_off & GENMASK_ULL(47,23));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001693}
1694
Doug Thompson6163b5d2009-04-27 16:20:17 +02001695/*
1696 * checks if the csrow passed in is marked as SPARED, if so returns the new
1697 * spare row
1698 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001699static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001700{
Borislav Petkov614ec9d2011-01-13 18:02:22 +01001701 int tmp_cs;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001702
Borislav Petkov614ec9d2011-01-13 18:02:22 +01001703 if (online_spare_swap_done(pvt, dct) &&
1704 csrow == online_spare_bad_dramcs(pvt, dct)) {
1705
1706 for_each_chip_select(tmp_cs, dct, pvt) {
1707 if (chip_select_base(tmp_cs, dct, pvt) & 0x2) {
1708 csrow = tmp_cs;
1709 break;
1710 }
1711 }
Doug Thompson6163b5d2009-04-27 16:20:17 +02001712 }
1713 return csrow;
1714}
1715
1716/*
1717 * Iterate over the DRAM DCT "base" and "mask" registers looking for a
1718 * SystemAddr match on the specified 'ChannelSelect' and 'NodeID'
1719 *
1720 * Return:
1721 * -EINVAL: NOT FOUND
1722 * 0..csrow = Chip-Select Row
1723 */
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08001724static int f1x_lookup_addr_in_dct(u64 in_addr, u8 nid, u8 dct)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001725{
1726 struct mem_ctl_info *mci;
1727 struct amd64_pvt *pvt;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001728 u64 cs_base, cs_mask;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001729 int cs_found = -EINVAL;
1730 int csrow;
1731
Borislav Petkov2ec591a2015-02-17 10:58:34 +01001732 mci = edac_mc_find(nid);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001733 if (!mci)
1734 return cs_found;
1735
1736 pvt = mci->pvt_info;
1737
Joe Perches956b9ba2012-04-29 17:08:39 -03001738 edac_dbg(1, "input addr: 0x%llx, DCT: %d\n", in_addr, dct);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001739
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001740 for_each_chip_select(csrow, dct, pvt) {
1741 if (!csrow_enabled(csrow, dct, pvt))
Doug Thompson6163b5d2009-04-27 16:20:17 +02001742 continue;
1743
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001744 get_cs_base_and_mask(pvt, csrow, dct, &cs_base, &cs_mask);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001745
Joe Perches956b9ba2012-04-29 17:08:39 -03001746 edac_dbg(1, " CSROW=%d CSBase=0x%llx CSMask=0x%llx\n",
1747 csrow, cs_base, cs_mask);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001748
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001749 cs_mask = ~cs_mask;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001750
Joe Perches956b9ba2012-04-29 17:08:39 -03001751 edac_dbg(1, " (InputAddr & ~CSMask)=0x%llx (CSBase & ~CSMask)=0x%llx\n",
1752 (in_addr & cs_mask), (cs_base & cs_mask));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001753
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001754 if ((in_addr & cs_mask) == (cs_base & cs_mask)) {
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001755 if (pvt->fam == 0x15 && pvt->model >= 0x30) {
1756 cs_found = csrow;
1757 break;
1758 }
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001759 cs_found = f10_process_possible_spare(pvt, dct, csrow);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001760
Joe Perches956b9ba2012-04-29 17:08:39 -03001761 edac_dbg(1, " MATCH csrow=%d\n", cs_found);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001762 break;
1763 }
1764 }
1765 return cs_found;
1766}
1767
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001768/*
1769 * See F2x10C. Non-interleaved graphics framebuffer memory under the 16G is
1770 * swapped with a region located at the bottom of memory so that the GPU can use
1771 * the interleaved region and thus two channels.
1772 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001773static u64 f1x_swap_interleaved_region(struct amd64_pvt *pvt, u64 sys_addr)
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001774{
1775 u32 swap_reg, swap_base, swap_limit, rgn_size, tmp_addr;
1776
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001777 if (pvt->fam == 0x10) {
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001778 /* only revC3 and revE have that feature */
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001779 if (pvt->model < 4 || (pvt->model < 0xa && pvt->stepping < 3))
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001780 return sys_addr;
1781 }
1782
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05001783 amd64_read_pci_cfg(pvt->F2, SWAP_INTLV_REG, &swap_reg);
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001784
1785 if (!(swap_reg & 0x1))
1786 return sys_addr;
1787
1788 swap_base = (swap_reg >> 3) & 0x7f;
1789 swap_limit = (swap_reg >> 11) & 0x7f;
1790 rgn_size = (swap_reg >> 20) & 0x7f;
1791 tmp_addr = sys_addr >> 27;
1792
1793 if (!(sys_addr >> 34) &&
1794 (((tmp_addr >= swap_base) &&
1795 (tmp_addr <= swap_limit)) ||
1796 (tmp_addr < rgn_size)))
1797 return sys_addr ^ (u64)swap_base << 27;
1798
1799 return sys_addr;
1800}
1801
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001802/* For a given @dram_range, check if @sys_addr falls within it. */
Borislav Petkove761359a2011-02-21 19:49:01 +01001803static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
Borislav Petkov33ca0642012-08-30 18:01:36 +02001804 u64 sys_addr, int *chan_sel)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001805{
Borislav Petkov229a7a12010-12-09 18:57:54 +01001806 int cs_found = -EINVAL;
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001807 u64 chan_addr;
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001808 u32 dct_sel_base;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001809 u8 channel;
Borislav Petkov229a7a12010-12-09 18:57:54 +01001810 bool high_range = false;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001811
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001812 u8 node_id = dram_dst_node(pvt, range);
Borislav Petkov229a7a12010-12-09 18:57:54 +01001813 u8 intlv_en = dram_intlv_en(pvt, range);
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001814 u32 intlv_sel = dram_intlv_sel(pvt, range);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001815
Joe Perches956b9ba2012-04-29 17:08:39 -03001816 edac_dbg(1, "(range %d) SystemAddr= 0x%llx Limit=0x%llx\n",
1817 range, sys_addr, get_dram_limit(pvt, range));
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001818
Borislav Petkov355fba62011-01-17 13:03:26 +01001819 if (dhar_valid(pvt) &&
1820 dhar_base(pvt) <= sys_addr &&
1821 sys_addr < BIT_64(32)) {
1822 amd64_warn("Huh? Address is in the MMIO hole: 0x%016llx\n",
1823 sys_addr);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001824 return -EINVAL;
Borislav Petkov355fba62011-01-17 13:03:26 +01001825 }
1826
Borislav Petkovf030ddf2011-04-08 15:05:21 +02001827 if (intlv_en && (intlv_sel != ((sys_addr >> 12) & intlv_en)))
Borislav Petkov355fba62011-01-17 13:03:26 +01001828 return -EINVAL;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001829
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001830 sys_addr = f1x_swap_interleaved_region(pvt, sys_addr);
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001831
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001832 dct_sel_base = dct_sel_baseaddr(pvt);
1833
1834 /*
1835 * check whether addresses >= DctSelBaseAddr[47:27] are to be used to
1836 * select between DCT0 and DCT1.
1837 */
1838 if (dct_high_range_enabled(pvt) &&
1839 !dct_ganging_enabled(pvt) &&
1840 ((sys_addr >> 27) >= (dct_sel_base >> 11)))
Borislav Petkov229a7a12010-12-09 18:57:54 +01001841 high_range = true;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001842
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001843 channel = f1x_determine_channel(pvt, sys_addr, high_range, intlv_en);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001844
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001845 chan_addr = f1x_get_norm_dct_addr(pvt, range, sys_addr,
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001846 high_range, dct_sel_base);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001847
Borislav Petkove2f79db2011-01-13 14:57:34 +01001848 /* Remove node interleaving, see F1x120 */
1849 if (intlv_en)
1850 chan_addr = ((chan_addr >> (12 + hweight8(intlv_en))) << 12) |
1851 (chan_addr & 0xfff);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001852
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001853 /* remove channel interleave */
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001854 if (dct_interleave_enabled(pvt) &&
1855 !dct_high_range_enabled(pvt) &&
1856 !dct_ganging_enabled(pvt)) {
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001857
1858 if (dct_sel_interleave_addr(pvt) != 1) {
1859 if (dct_sel_interleave_addr(pvt) == 0x3)
1860 /* hash 9 */
1861 chan_addr = ((chan_addr >> 10) << 9) |
1862 (chan_addr & 0x1ff);
1863 else
1864 /* A[6] or hash 6 */
1865 chan_addr = ((chan_addr >> 7) << 6) |
1866 (chan_addr & 0x3f);
1867 } else
1868 /* A[12] */
1869 chan_addr = ((chan_addr >> 13) << 12) |
1870 (chan_addr & 0xfff);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001871 }
1872
Joe Perches956b9ba2012-04-29 17:08:39 -03001873 edac_dbg(1, " Normalized DCT addr: 0x%llx\n", chan_addr);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001874
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001875 cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, channel);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001876
Borislav Petkov33ca0642012-08-30 18:01:36 +02001877 if (cs_found >= 0)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001878 *chan_sel = channel;
Borislav Petkov33ca0642012-08-30 18:01:36 +02001879
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001880 return cs_found;
1881}
1882
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001883static int f15_m30h_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
1884 u64 sys_addr, int *chan_sel)
1885{
1886 int cs_found = -EINVAL;
1887 int num_dcts_intlv = 0;
1888 u64 chan_addr, chan_offset;
1889 u64 dct_base, dct_limit;
1890 u32 dct_cont_base_reg, dct_cont_limit_reg, tmp;
1891 u8 channel, alias_channel, leg_mmio_hole, dct_sel, dct_offset_en;
1892
1893 u64 dhar_offset = f10_dhar_offset(pvt);
1894 u8 intlv_addr = dct_sel_interleave_addr(pvt);
1895 u8 node_id = dram_dst_node(pvt, range);
1896 u8 intlv_en = dram_intlv_en(pvt, range);
1897
1898 amd64_read_pci_cfg(pvt->F1, DRAM_CONT_BASE, &dct_cont_base_reg);
1899 amd64_read_pci_cfg(pvt->F1, DRAM_CONT_LIMIT, &dct_cont_limit_reg);
1900
1901 dct_offset_en = (u8) ((dct_cont_base_reg >> 3) & BIT(0));
1902 dct_sel = (u8) ((dct_cont_base_reg >> 4) & 0x7);
1903
1904 edac_dbg(1, "(range %d) SystemAddr= 0x%llx Limit=0x%llx\n",
1905 range, sys_addr, get_dram_limit(pvt, range));
1906
1907 if (!(get_dram_base(pvt, range) <= sys_addr) &&
1908 !(get_dram_limit(pvt, range) >= sys_addr))
1909 return -EINVAL;
1910
1911 if (dhar_valid(pvt) &&
1912 dhar_base(pvt) <= sys_addr &&
1913 sys_addr < BIT_64(32)) {
1914 amd64_warn("Huh? Address is in the MMIO hole: 0x%016llx\n",
1915 sys_addr);
1916 return -EINVAL;
1917 }
1918
1919 /* Verify sys_addr is within DCT Range. */
Aravind Gopalakrishnan4fc06b32013-08-24 10:47:48 -05001920 dct_base = (u64) dct_sel_baseaddr(pvt);
1921 dct_limit = (dct_cont_limit_reg >> 11) & 0x1FFF;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001922
1923 if (!(dct_cont_base_reg & BIT(0)) &&
Aravind Gopalakrishnan4fc06b32013-08-24 10:47:48 -05001924 !(dct_base <= (sys_addr >> 27) &&
1925 dct_limit >= (sys_addr >> 27)))
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001926 return -EINVAL;
1927
1928 /* Verify number of dct's that participate in channel interleaving. */
1929 num_dcts_intlv = (int) hweight8(intlv_en);
1930
1931 if (!(num_dcts_intlv % 2 == 0) || (num_dcts_intlv > 4))
1932 return -EINVAL;
1933
Yazen Ghannamdc0a50a82016-08-03 10:59:15 -04001934 if (pvt->model >= 0x60)
1935 channel = f1x_determine_channel(pvt, sys_addr, false, intlv_en);
1936 else
1937 channel = f15_m30h_determine_channel(pvt, sys_addr, intlv_en,
1938 num_dcts_intlv, dct_sel);
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001939
1940 /* Verify we stay within the MAX number of channels allowed */
Aravind Gopalakrishnan7f3f5242013-12-04 11:40:11 -06001941 if (channel > 3)
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001942 return -EINVAL;
1943
1944 leg_mmio_hole = (u8) (dct_cont_base_reg >> 1 & BIT(0));
1945
1946 /* Get normalized DCT addr */
1947 if (leg_mmio_hole && (sys_addr >= BIT_64(32)))
1948 chan_offset = dhar_offset;
1949 else
Aravind Gopalakrishnan4fc06b32013-08-24 10:47:48 -05001950 chan_offset = dct_base << 27;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001951
1952 chan_addr = sys_addr - chan_offset;
1953
1954 /* remove channel interleave */
1955 if (num_dcts_intlv == 2) {
1956 if (intlv_addr == 0x4)
1957 chan_addr = ((chan_addr >> 9) << 8) |
1958 (chan_addr & 0xff);
1959 else if (intlv_addr == 0x5)
1960 chan_addr = ((chan_addr >> 10) << 9) |
1961 (chan_addr & 0x1ff);
1962 else
1963 return -EINVAL;
1964
1965 } else if (num_dcts_intlv == 4) {
1966 if (intlv_addr == 0x4)
1967 chan_addr = ((chan_addr >> 10) << 8) |
1968 (chan_addr & 0xff);
1969 else if (intlv_addr == 0x5)
1970 chan_addr = ((chan_addr >> 11) << 9) |
1971 (chan_addr & 0x1ff);
1972 else
1973 return -EINVAL;
1974 }
1975
1976 if (dct_offset_en) {
1977 amd64_read_pci_cfg(pvt->F1,
1978 DRAM_CONT_HIGH_OFF + (int) channel * 4,
1979 &tmp);
Aravind Gopalakrishnan4fc06b32013-08-24 10:47:48 -05001980 chan_addr += (u64) ((tmp >> 11) & 0xfff) << 27;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001981 }
1982
1983 f15h_select_dct(pvt, channel);
1984
1985 edac_dbg(1, " Normalized DCT addr: 0x%llx\n", chan_addr);
1986
1987 /*
1988 * Find Chip select:
1989 * if channel = 3, then alias it to 1. This is because, in F15 M30h,
1990 * there is support for 4 DCT's, but only 2 are currently functional.
1991 * They are DCT0 and DCT3. But we have read all registers of DCT3 into
1992 * pvt->csels[1]. So we need to use '1' here to get correct info.
1993 * Refer F15 M30h BKDG Section 2.10 and 2.10.3 for clarifications.
1994 */
1995 alias_channel = (channel == 3) ? 1 : channel;
1996
1997 cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, alias_channel);
1998
1999 if (cs_found >= 0)
2000 *chan_sel = alias_channel;
2001
2002 return cs_found;
2003}
2004
2005static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt,
2006 u64 sys_addr,
2007 int *chan_sel)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002008{
Borislav Petkove761359a2011-02-21 19:49:01 +01002009 int cs_found = -EINVAL;
2010 unsigned range;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002011
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002012 for (range = 0; range < DRAM_RANGES; range++) {
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002013 if (!dram_rw(pvt, range))
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002014 continue;
2015
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05002016 if (pvt->fam == 0x15 && pvt->model >= 0x30)
2017 cs_found = f15_m30h_match_to_this_node(pvt, range,
2018 sys_addr,
2019 chan_sel);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002020
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05002021 else if ((get_dram_base(pvt, range) <= sys_addr) &&
2022 (get_dram_limit(pvt, range) >= sys_addr)) {
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01002023 cs_found = f1x_match_to_this_node(pvt, range,
Borislav Petkov33ca0642012-08-30 18:01:36 +02002024 sys_addr, chan_sel);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002025 if (cs_found >= 0)
2026 break;
2027 }
2028 }
2029 return cs_found;
2030}
2031
2032/*
Borislav Petkovbdc30a02009-11-13 15:10:43 +01002033 * For reference see "2.8.5 Routing DRAM Requests" in F10 BKDG. This code maps
2034 * a @sys_addr to NodeID, DCT (channel) and chip select (CSROW).
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002035 *
Borislav Petkovbdc30a02009-11-13 15:10:43 +01002036 * The @sys_addr is usually an error address received from the hardware
2037 * (MCX_ADDR).
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002038 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01002039static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
Borislav Petkov33ca0642012-08-30 18:01:36 +02002040 struct err_info *err)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002041{
2042 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002043
Borislav Petkov33ca0642012-08-30 18:01:36 +02002044 error_address_to_page_and_offset(sys_addr, err);
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03002045
Borislav Petkov33ca0642012-08-30 18:01:36 +02002046 err->csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &err->channel);
2047 if (err->csrow < 0) {
2048 err->err_code = ERR_CSROW;
Borislav Petkovbdc30a02009-11-13 15:10:43 +01002049 return;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002050 }
Borislav Petkovbdc30a02009-11-13 15:10:43 +01002051
Borislav Petkovbdc30a02009-11-13 15:10:43 +01002052 /*
2053 * We need the syndromes for channel detection only when we're
2054 * ganged. Otherwise @chan should already contain the channel at
2055 * this point.
2056 */
Borislav Petkova97fa682010-12-23 14:07:18 +01002057 if (dct_ganging_enabled(pvt))
Borislav Petkov33ca0642012-08-30 18:01:36 +02002058 err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002059}
2060
2061/*
Borislav Petkov8566c4d2009-10-16 13:48:28 +02002062 * debug routine to display the memory sizes of all logical DIMMs and its
Borislav Petkovcb328502010-12-22 14:28:24 +01002063 * CSROWs
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002064 */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01002065static void debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002066{
Borislav Petkovbb89f5a2012-09-12 18:06:00 +02002067 int dimm, size0, size1;
Borislav Petkov525a1b22010-12-21 15:53:27 +01002068 u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases;
2069 u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002070
Borislav Petkova4b4bed2013-08-10 13:54:48 +02002071 if (pvt->fam == 0xf) {
Borislav Petkov8566c4d2009-10-16 13:48:28 +02002072 /* K8 families < revF not supported yet */
Borislav Petkov1433eb92009-10-21 13:44:36 +02002073 if (pvt->ext_model < K8_REV_F)
Borislav Petkov8566c4d2009-10-16 13:48:28 +02002074 return;
2075 else
2076 WARN_ON(ctrl != 0);
2077 }
2078
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05002079 if (pvt->fam == 0x10) {
2080 dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1
2081 : pvt->dbam0;
2082 dcsb = (ctrl && !dct_ganging_enabled(pvt)) ?
2083 pvt->csels[1].csbases :
2084 pvt->csels[0].csbases;
2085 } else if (ctrl) {
2086 dbam = pvt->dbam0;
2087 dcsb = pvt->csels[1].csbases;
2088 }
Joe Perches956b9ba2012-04-29 17:08:39 -03002089 edac_dbg(1, "F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n",
2090 ctrl, dbam);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002091
Borislav Petkov8566c4d2009-10-16 13:48:28 +02002092 edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl);
2093
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002094 /* Dump memory sizes for DIMM and its CSROWs */
2095 for (dimm = 0; dimm < 4; dimm++) {
2096
2097 size0 = 0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002098 if (dcsb[dimm*2] & DCSB_CS_ENABLE)
Yazen Ghannam07ed82e2016-11-28 08:50:21 -06002099 /*
2100 * For F15m60h, we need multiplier for LRDIMM cs_size
2101 * calculation. We pass dimm value to the dbam_to_cs
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002102 * mapper so we can find the multiplier from the
2103 * corresponding DCSM.
2104 */
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01002105 size0 = pvt->ops->dbam_to_cs(pvt, ctrl,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002106 DBAM_DIMM(dimm, dbam),
2107 dimm);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002108
2109 size1 = 0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002110 if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01002111 size1 = pvt->ops->dbam_to_cs(pvt, ctrl,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002112 DBAM_DIMM(dimm, dbam),
2113 dimm);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002114
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002115 amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
Borislav Petkovbb89f5a2012-09-12 18:06:00 +02002116 dimm * 2, size0,
2117 dimm * 2 + 1, size1);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002118 }
2119}
2120
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01002121static struct amd64_family_type family_types[] = {
Doug Thompson4d376072009-04-27 16:25:05 +02002122 [K8_CPUS] = {
Borislav Petkov0092b202010-10-01 19:20:05 +02002123 .ctl_name = "K8",
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002124 .f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002125 .f2_id = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL,
Doug Thompson4d376072009-04-27 16:25:05 +02002126 .ops = {
Borislav Petkov1433eb92009-10-21 13:44:36 +02002127 .early_channel_count = k8_early_channel_count,
Borislav Petkov1433eb92009-10-21 13:44:36 +02002128 .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow,
2129 .dbam_to_cs = k8_dbam_to_chip_select,
Doug Thompson4d376072009-04-27 16:25:05 +02002130 }
2131 },
2132 [F10_CPUS] = {
Borislav Petkov0092b202010-10-01 19:20:05 +02002133 .ctl_name = "F10h",
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002134 .f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002135 .f2_id = PCI_DEVICE_ID_AMD_10H_NB_DRAM,
Doug Thompson4d376072009-04-27 16:25:05 +02002136 .ops = {
Borislav Petkov7d20d142011-01-07 17:58:04 +01002137 .early_channel_count = f1x_early_channel_count,
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01002138 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
Borislav Petkov1433eb92009-10-21 13:44:36 +02002139 .dbam_to_cs = f10_dbam_to_chip_select,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02002140 }
2141 },
2142 [F15_CPUS] = {
2143 .ctl_name = "F15h",
Borislav Petkovdf71a052011-01-19 18:15:10 +01002144 .f1_id = PCI_DEVICE_ID_AMD_15H_NB_F1,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002145 .f2_id = PCI_DEVICE_ID_AMD_15H_NB_F2,
Borislav Petkovb2b0c602010-10-08 18:32:29 +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 Petkov41d8bfa2011-01-18 19:16:08 +01002149 .dbam_to_cs = f15_dbam_to_chip_select,
Doug Thompson4d376072009-04-27 16:25:05 +02002150 }
2151 },
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05002152 [F15_M30H_CPUS] = {
2153 .ctl_name = "F15h_M30h",
2154 .f1_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002155 .f2_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F2,
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05002156 .ops = {
2157 .early_channel_count = f1x_early_channel_count,
2158 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
2159 .dbam_to_cs = f16_dbam_to_chip_select,
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05002160 }
2161 },
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002162 [F15_M60H_CPUS] = {
2163 .ctl_name = "F15h_M60h",
2164 .f1_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002165 .f2_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F2,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002166 .ops = {
2167 .early_channel_count = f1x_early_channel_count,
2168 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
2169 .dbam_to_cs = f15_m60h_dbam_to_chip_select,
2170 }
2171 },
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05002172 [F16_CPUS] = {
2173 .ctl_name = "F16h",
2174 .f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002175 .f2_id = PCI_DEVICE_ID_AMD_16H_NB_F2,
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05002176 .ops = {
2177 .early_channel_count = f1x_early_channel_count,
2178 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
2179 .dbam_to_cs = f16_dbam_to_chip_select,
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05002180 }
2181 },
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -06002182 [F16_M30H_CPUS] = {
2183 .ctl_name = "F16h_M30h",
2184 .f1_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F1,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002185 .f2_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F2,
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -06002186 .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 Gopalakrishnan85a88852014-02-20 10:28:46 -06002190 }
2191 },
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05002192 [F17_CPUS] = {
2193 .ctl_name = "F17h",
2194 .f0_id = PCI_DEVICE_ID_AMD_17H_DF_F0,
2195 .f6_id = PCI_DEVICE_ID_AMD_17H_DF_F6,
2196 .ops = {
2197 .early_channel_count = f17_early_channel_count,
2198 .dbam_to_cs = f17_base_addr_to_cs_size,
2199 }
2200 },
Doug Thompson4d376072009-04-27 16:25:05 +02002201};
2202
Doug Thompsonb1289d62009-04-27 16:37:05 +02002203/*
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002204 * These are tables of eigenvectors (one per line) which can be used for the
2205 * construction of the syndrome tables. The modified syndrome search algorithm
2206 * uses those to find the symbol in error and thus the DIMM.
Doug Thompsonb1289d62009-04-27 16:37:05 +02002207 *
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002208 * Algorithm courtesy of Ross LaFetra from AMD.
Doug Thompsonb1289d62009-04-27 16:37:05 +02002209 */
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08002210static const u16 x4_vectors[] = {
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002211 0x2f57, 0x1afe, 0x66cc, 0xdd88,
2212 0x11eb, 0x3396, 0x7f4c, 0xeac8,
2213 0x0001, 0x0002, 0x0004, 0x0008,
2214 0x1013, 0x3032, 0x4044, 0x8088,
2215 0x106b, 0x30d6, 0x70fc, 0xe0a8,
2216 0x4857, 0xc4fe, 0x13cc, 0x3288,
2217 0x1ac5, 0x2f4a, 0x5394, 0xa1e8,
2218 0x1f39, 0x251e, 0xbd6c, 0x6bd8,
2219 0x15c1, 0x2a42, 0x89ac, 0x4758,
2220 0x2b03, 0x1602, 0x4f0c, 0xca08,
2221 0x1f07, 0x3a0e, 0x6b04, 0xbd08,
2222 0x8ba7, 0x465e, 0x244c, 0x1cc8,
2223 0x2b87, 0x164e, 0x642c, 0xdc18,
2224 0x40b9, 0x80de, 0x1094, 0x20e8,
2225 0x27db, 0x1eb6, 0x9dac, 0x7b58,
2226 0x11c1, 0x2242, 0x84ac, 0x4c58,
2227 0x1be5, 0x2d7a, 0x5e34, 0xa718,
2228 0x4b39, 0x8d1e, 0x14b4, 0x28d8,
2229 0x4c97, 0xc87e, 0x11fc, 0x33a8,
2230 0x8e97, 0x497e, 0x2ffc, 0x1aa8,
2231 0x16b3, 0x3d62, 0x4f34, 0x8518,
2232 0x1e2f, 0x391a, 0x5cac, 0xf858,
2233 0x1d9f, 0x3b7a, 0x572c, 0xfe18,
2234 0x15f5, 0x2a5a, 0x5264, 0xa3b8,
2235 0x1dbb, 0x3b66, 0x715c, 0xe3f8,
2236 0x4397, 0xc27e, 0x17fc, 0x3ea8,
2237 0x1617, 0x3d3e, 0x6464, 0xb8b8,
2238 0x23ff, 0x12aa, 0xab6c, 0x56d8,
2239 0x2dfb, 0x1ba6, 0x913c, 0x7328,
2240 0x185d, 0x2ca6, 0x7914, 0x9e28,
2241 0x171b, 0x3e36, 0x7d7c, 0xebe8,
2242 0x4199, 0x82ee, 0x19f4, 0x2e58,
2243 0x4807, 0xc40e, 0x130c, 0x3208,
2244 0x1905, 0x2e0a, 0x5804, 0xac08,
2245 0x213f, 0x132a, 0xadfc, 0x5ba8,
2246 0x19a9, 0x2efe, 0xb5cc, 0x6f88,
Doug Thompsonb1289d62009-04-27 16:37:05 +02002247};
2248
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08002249static const u16 x8_vectors[] = {
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002250 0x0145, 0x028a, 0x2374, 0x43c8, 0xa1f0, 0x0520, 0x0a40, 0x1480,
2251 0x0211, 0x0422, 0x0844, 0x1088, 0x01b0, 0x44e0, 0x23c0, 0xed80,
2252 0x1011, 0x0116, 0x022c, 0x0458, 0x08b0, 0x8c60, 0x2740, 0x4e80,
2253 0x0411, 0x0822, 0x1044, 0x0158, 0x02b0, 0x2360, 0x46c0, 0xab80,
2254 0x0811, 0x1022, 0x012c, 0x0258, 0x04b0, 0x4660, 0x8cc0, 0x2780,
2255 0x2071, 0x40e2, 0xa0c4, 0x0108, 0x0210, 0x0420, 0x0840, 0x1080,
2256 0x4071, 0x80e2, 0x0104, 0x0208, 0x0410, 0x0820, 0x1040, 0x2080,
2257 0x8071, 0x0102, 0x0204, 0x0408, 0x0810, 0x1020, 0x2040, 0x4080,
2258 0x019d, 0x03d6, 0x136c, 0x2198, 0x50b0, 0xb2e0, 0x0740, 0x0e80,
2259 0x0189, 0x03ea, 0x072c, 0x0e58, 0x1cb0, 0x56e0, 0x37c0, 0xf580,
2260 0x01fd, 0x0376, 0x06ec, 0x0bb8, 0x1110, 0x2220, 0x4440, 0x8880,
2261 0x0163, 0x02c6, 0x1104, 0x0758, 0x0eb0, 0x2be0, 0x6140, 0xc280,
2262 0x02fd, 0x01c6, 0x0b5c, 0x1108, 0x07b0, 0x25a0, 0x8840, 0x6180,
2263 0x0801, 0x012e, 0x025c, 0x04b8, 0x1370, 0x26e0, 0x57c0, 0xb580,
2264 0x0401, 0x0802, 0x015c, 0x02b8, 0x22b0, 0x13e0, 0x7140, 0xe280,
2265 0x0201, 0x0402, 0x0804, 0x01b8, 0x11b0, 0x31a0, 0x8040, 0x7180,
2266 0x0101, 0x0202, 0x0404, 0x0808, 0x1010, 0x2020, 0x4040, 0x8080,
2267 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
2268 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
2269};
2270
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08002271static int decode_syndrome(u16 syndrome, const u16 *vectors, unsigned num_vecs,
Borislav Petkovd34a6ec2011-02-23 17:41:50 +01002272 unsigned v_dim)
Doug Thompsonb1289d62009-04-27 16:37:05 +02002273{
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002274 unsigned int i, err_sym;
Doug Thompsonb1289d62009-04-27 16:37:05 +02002275
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002276 for (err_sym = 0; err_sym < num_vecs / v_dim; err_sym++) {
2277 u16 s = syndrome;
Borislav Petkovd34a6ec2011-02-23 17:41:50 +01002278 unsigned v_idx = err_sym * v_dim;
2279 unsigned v_end = (err_sym + 1) * v_dim;
Doug Thompsonb1289d62009-04-27 16:37:05 +02002280
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002281 /* walk over all 16 bits of the syndrome */
2282 for (i = 1; i < (1U << 16); i <<= 1) {
2283
2284 /* if bit is set in that eigenvector... */
2285 if (v_idx < v_end && vectors[v_idx] & i) {
2286 u16 ev_comp = vectors[v_idx++];
2287
2288 /* ... and bit set in the modified syndrome, */
2289 if (s & i) {
2290 /* remove it. */
2291 s ^= ev_comp;
2292
2293 if (!s)
2294 return err_sym;
2295 }
2296
2297 } else if (s & i)
2298 /* can't get to zero, move to next symbol */
2299 break;
2300 }
Doug Thompsonb1289d62009-04-27 16:37:05 +02002301 }
2302
Joe Perches956b9ba2012-04-29 17:08:39 -03002303 edac_dbg(0, "syndrome(%x) not found\n", syndrome);
Doug Thompsonb1289d62009-04-27 16:37:05 +02002304 return -1;
2305}
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002306
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002307static int map_err_sym_to_channel(int err_sym, int sym_size)
2308{
2309 if (sym_size == 4)
2310 switch (err_sym) {
2311 case 0x20:
2312 case 0x21:
2313 return 0;
2314 break;
2315 case 0x22:
2316 case 0x23:
2317 return 1;
2318 break;
2319 default:
2320 return err_sym >> 4;
2321 break;
2322 }
2323 /* x8 symbols */
2324 else
2325 switch (err_sym) {
2326 /* imaginary bits not in a DIMM */
2327 case 0x10:
2328 WARN(1, KERN_ERR "Invalid error symbol: 0x%x\n",
2329 err_sym);
2330 return -1;
2331 break;
2332
2333 case 0x11:
2334 return 0;
2335 break;
2336 case 0x12:
2337 return 1;
2338 break;
2339 default:
2340 return err_sym >> 3;
2341 break;
2342 }
2343 return -1;
2344}
2345
2346static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
2347{
2348 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002349 int err_sym = -1;
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002350
Borislav Petkova3b7db02011-01-19 20:35:12 +01002351 if (pvt->ecc_sym_sz == 8)
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002352 err_sym = decode_syndrome(syndrome, x8_vectors,
2353 ARRAY_SIZE(x8_vectors),
Borislav Petkova3b7db02011-01-19 20:35:12 +01002354 pvt->ecc_sym_sz);
2355 else if (pvt->ecc_sym_sz == 4)
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002356 err_sym = decode_syndrome(syndrome, x4_vectors,
2357 ARRAY_SIZE(x4_vectors),
Borislav Petkova3b7db02011-01-19 20:35:12 +01002358 pvt->ecc_sym_sz);
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002359 else {
Borislav Petkova3b7db02011-01-19 20:35:12 +01002360 amd64_warn("Illegal syndrome type: %u\n", pvt->ecc_sym_sz);
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002361 return err_sym;
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002362 }
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002363
Borislav Petkova3b7db02011-01-19 20:35:12 +01002364 return map_err_sym_to_channel(err_sym, pvt->ecc_sym_sz);
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002365}
2366
Yazen Ghanname70984d2016-11-17 17:57:31 -05002367static void __log_ecc_error(struct mem_ctl_info *mci, struct err_info *err,
Borislav Petkov33ca0642012-08-30 18:01:36 +02002368 u8 ecc_type)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002369{
Borislav Petkov33ca0642012-08-30 18:01:36 +02002370 enum hw_event_mc_err_type err_type;
2371 const char *string;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002372
Borislav Petkov33ca0642012-08-30 18:01:36 +02002373 if (ecc_type == 2)
2374 err_type = HW_EVENT_ERR_CORRECTED;
2375 else if (ecc_type == 1)
2376 err_type = HW_EVENT_ERR_UNCORRECTED;
Yazen Ghannamd12a9692016-11-17 17:57:32 -05002377 else if (ecc_type == 3)
2378 err_type = HW_EVENT_ERR_DEFERRED;
Borislav Petkov33ca0642012-08-30 18:01:36 +02002379 else {
2380 WARN(1, "Something is rotten in the state of Denmark.\n");
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002381 return;
2382 }
2383
Borislav Petkov33ca0642012-08-30 18:01:36 +02002384 switch (err->err_code) {
2385 case DECODE_OK:
2386 string = "";
2387 break;
2388 case ERR_NODE:
2389 string = "Failed to map error addr to a node";
2390 break;
2391 case ERR_CSROW:
2392 string = "Failed to map error addr to a csrow";
2393 break;
2394 case ERR_CHANNEL:
Yazen Ghannam713ad542016-11-28 12:59:53 -06002395 string = "Unknown syndrome - possible error reporting race";
2396 break;
2397 case ERR_SYND:
2398 string = "MCA_SYND not valid - unknown syndrome and csrow";
2399 break;
2400 case ERR_NORM_ADDR:
2401 string = "Cannot decode normalized address";
Borislav Petkov33ca0642012-08-30 18:01:36 +02002402 break;
2403 default:
2404 string = "WTF error";
2405 break;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002406 }
Borislav Petkov33ca0642012-08-30 18:01:36 +02002407
2408 edac_mc_handle_error(err_type, mci, 1,
2409 err->page, err->offset, err->syndrome,
2410 err->csrow, err->channel, -1,
2411 string, "");
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002412}
2413
Borislav Petkovdf781d02013-12-15 17:29:44 +01002414static inline void decode_bus_error(int node_id, struct mce *m)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002415{
Daniel J Blueman0c510cc2015-02-17 11:34:38 +08002416 struct mem_ctl_info *mci;
2417 struct amd64_pvt *pvt;
Borislav Petkovf192c7b2011-01-10 14:24:32 +01002418 u8 ecc_type = (m->status >> 45) & 0x3;
Borislav Petkov66fed2d2012-08-09 18:41:07 +02002419 u8 xec = XEC(m->status, 0x1f);
2420 u16 ec = EC(m->status);
Borislav Petkov33ca0642012-08-30 18:01:36 +02002421 u64 sys_addr;
2422 struct err_info err;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002423
Daniel J Blueman0c510cc2015-02-17 11:34:38 +08002424 mci = edac_mc_find(node_id);
2425 if (!mci)
2426 return;
2427
2428 pvt = mci->pvt_info;
2429
Borislav Petkov66fed2d2012-08-09 18:41:07 +02002430 /* Bail out early if this was an 'observed' error */
Borislav Petkov5980bb92011-01-07 16:26:49 +01002431 if (PP(ec) == NBSL_PP_OBS)
Borislav Petkovb70ef012009-06-25 19:32:38 +02002432 return;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002433
Borislav Petkovecaf5602009-07-23 16:32:01 +02002434 /* Do only ECC errors */
2435 if (xec && xec != F10_NBSL_EXT_ERR_ECC)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002436 return;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002437
Borislav Petkov33ca0642012-08-30 18:01:36 +02002438 memset(&err, 0, sizeof(err));
2439
Borislav Petkova4b4bed2013-08-10 13:54:48 +02002440 sys_addr = get_error_address(pvt, m);
Borislav Petkov33ca0642012-08-30 18:01:36 +02002441
Borislav Petkovecaf5602009-07-23 16:32:01 +02002442 if (ecc_type == 2)
Borislav Petkov33ca0642012-08-30 18:01:36 +02002443 err.syndrome = extract_syndrome(m->status);
2444
2445 pvt->ops->map_sysaddr_to_csrow(mci, sys_addr, &err);
2446
Yazen Ghanname70984d2016-11-17 17:57:31 -05002447 __log_ecc_error(mci, &err, ecc_type);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002448}
2449
Doug Thompson0ec449e2009-04-27 19:41:25 +02002450/*
Yazen Ghannam713ad542016-11-28 12:59:53 -06002451 * To find the UMC channel represented by this bank we need to match on its
2452 * instance_id. The instance_id of a bank is held in the lower 32 bits of its
2453 * IPID.
2454 */
2455static int find_umc_channel(struct amd64_pvt *pvt, struct mce *m)
2456{
2457 u32 umc_instance_id[] = {0x50f00, 0x150f00};
2458 u32 instance_id = m->ipid & GENMASK(31, 0);
2459 int i, channel = -1;
2460
2461 for (i = 0; i < ARRAY_SIZE(umc_instance_id); i++)
2462 if (umc_instance_id[i] == instance_id)
2463 channel = i;
2464
2465 return channel;
2466}
2467
2468static void decode_umc_error(int node_id, struct mce *m)
2469{
2470 u8 ecc_type = (m->status >> 45) & 0x3;
2471 struct mem_ctl_info *mci;
2472 struct amd64_pvt *pvt;
2473 struct err_info err;
2474 u64 sys_addr;
2475
2476 mci = edac_mc_find(node_id);
2477 if (!mci)
2478 return;
2479
2480 pvt = mci->pvt_info;
2481
2482 memset(&err, 0, sizeof(err));
2483
2484 if (m->status & MCI_STATUS_DEFERRED)
2485 ecc_type = 3;
2486
2487 err.channel = find_umc_channel(pvt, m);
2488 if (err.channel < 0) {
2489 err.err_code = ERR_CHANNEL;
2490 goto log_error;
2491 }
2492
2493 if (umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, err.channel, &sys_addr)) {
2494 err.err_code = ERR_NORM_ADDR;
2495 goto log_error;
2496 }
2497
2498 error_address_to_page_and_offset(sys_addr, &err);
2499
2500 if (!(m->status & MCI_STATUS_SYNDV)) {
2501 err.err_code = ERR_SYND;
2502 goto log_error;
2503 }
2504
2505 if (ecc_type == 2) {
2506 u8 length = (m->synd >> 18) & 0x3f;
2507
2508 if (length)
2509 err.syndrome = (m->synd >> 32) & GENMASK(length - 1, 0);
2510 else
2511 err.err_code = ERR_CHANNEL;
2512 }
2513
2514 err.csrow = m->synd & 0x7;
2515
2516log_error:
2517 __log_ecc_error(mci, &err, ecc_type);
2518}
2519
2520/*
Borislav Petkov3f37a362016-05-06 19:44:27 +02002521 * Use pvt->F3 which contains the F3 CPU PCI device to get the related
2522 * F1 (AddrMap) and F2 (Dct) devices. Return negative value on error.
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002523 * Reserve F0 and F6 on systems with a UMC.
Doug Thompson0ec449e2009-04-27 19:41:25 +02002524 */
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002525static int
2526reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 pci_id1, u16 pci_id2)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002527{
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002528 if (pvt->umc) {
2529 pvt->F0 = pci_get_related_function(pvt->F3->vendor, pci_id1, pvt->F3);
2530 if (!pvt->F0) {
Borislav Petkov5246c542016-12-01 11:35:07 +01002531 amd64_err("F0 not found, device 0x%x (broken BIOS?)\n", pci_id1);
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002532 return -ENODEV;
2533 }
2534
2535 pvt->F6 = pci_get_related_function(pvt->F3->vendor, pci_id2, pvt->F3);
2536 if (!pvt->F6) {
2537 pci_dev_put(pvt->F0);
2538 pvt->F0 = NULL;
2539
Borislav Petkov5246c542016-12-01 11:35:07 +01002540 amd64_err("F6 not found: device 0x%x (broken BIOS?)\n", pci_id2);
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002541 return -ENODEV;
2542 }
Borislav Petkov5246c542016-12-01 11:35:07 +01002543
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002544 edac_dbg(1, "F0: %s\n", pci_name(pvt->F0));
2545 edac_dbg(1, "F3: %s\n", pci_name(pvt->F3));
2546 edac_dbg(1, "F6: %s\n", pci_name(pvt->F6));
2547
2548 return 0;
2549 }
2550
Doug Thompson0ec449e2009-04-27 19:41:25 +02002551 /* Reserve the ADDRESS MAP Device */
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002552 pvt->F1 = pci_get_related_function(pvt->F3->vendor, pci_id1, pvt->F3);
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002553 if (!pvt->F1) {
Borislav Petkov5246c542016-12-01 11:35:07 +01002554 amd64_err("F1 not found: device 0x%x (broken BIOS?)\n", pci_id1);
Borislav Petkovbbd0c1f2010-10-01 19:27:58 +02002555 return -ENODEV;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002556 }
2557
Borislav Petkov3f37a362016-05-06 19:44:27 +02002558 /* Reserve the DCT Device */
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002559 pvt->F2 = pci_get_related_function(pvt->F3->vendor, pci_id2, pvt->F3);
Borislav Petkov3f37a362016-05-06 19:44:27 +02002560 if (!pvt->F2) {
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002561 pci_dev_put(pvt->F1);
2562 pvt->F1 = NULL;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002563
Borislav Petkov5246c542016-12-01 11:35:07 +01002564 amd64_err("F2 not found: device 0x%x (broken BIOS?)\n", pci_id2);
2565 return -ENODEV;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002566 }
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002567
Joe Perches956b9ba2012-04-29 17:08:39 -03002568 edac_dbg(1, "F1: %s\n", pci_name(pvt->F1));
2569 edac_dbg(1, "F2: %s\n", pci_name(pvt->F2));
2570 edac_dbg(1, "F3: %s\n", pci_name(pvt->F3));
Doug Thompson0ec449e2009-04-27 19:41:25 +02002571
2572 return 0;
2573}
2574
Borislav Petkov360b7f32010-10-15 19:25:38 +02002575static void free_mc_sibling_devs(struct amd64_pvt *pvt)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002576{
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002577 if (pvt->umc) {
2578 pci_dev_put(pvt->F0);
2579 pci_dev_put(pvt->F6);
2580 } else {
2581 pci_dev_put(pvt->F1);
2582 pci_dev_put(pvt->F2);
2583 }
Doug Thompson0ec449e2009-04-27 19:41:25 +02002584}
2585
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002586static void determine_ecc_sym_sz(struct amd64_pvt *pvt)
2587{
2588 pvt->ecc_sym_sz = 4;
2589
2590 if (pvt->umc) {
2591 u8 i;
2592
2593 for (i = 0; i < NUM_UMCS; i++) {
2594 /* Check enabled channels only: */
2595 if ((pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) &&
2596 (pvt->umc[i].ecc_ctrl & BIT(7))) {
2597 pvt->ecc_sym_sz = 8;
2598 break;
2599 }
2600 }
2601
2602 return;
2603 }
2604
2605 if (pvt->fam >= 0x10) {
2606 u32 tmp;
2607
2608 amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
2609 /* F16h has only DCT0, so no need to read dbam1. */
2610 if (pvt->fam != 0x16)
2611 amd64_read_dct_pci_cfg(pvt, 1, DBAM0, &pvt->dbam1);
2612
2613 /* F10h, revD and later can do x8 ECC too. */
2614 if ((pvt->fam > 0x10 || pvt->model > 7) && tmp & BIT(25))
2615 pvt->ecc_sym_sz = 8;
2616 }
2617}
2618
2619/*
2620 * Retrieve the hardware registers of the memory controller.
2621 */
2622static void __read_mc_regs_df(struct amd64_pvt *pvt)
2623{
2624 u8 nid = pvt->mc_node_id;
2625 struct amd64_umc *umc;
2626 u32 i, umc_base;
2627
2628 /* Read registers from each UMC */
2629 for (i = 0; i < NUM_UMCS; i++) {
2630
2631 umc_base = get_umc_base(i);
2632 umc = &pvt->umc[i];
2633
Yazen Ghannam07ed82e2016-11-28 08:50:21 -06002634 amd_smn_read(nid, umc_base + UMCCH_DIMM_CFG, &umc->dimm_cfg);
2635 amd_smn_read(nid, umc_base + UMCCH_UMC_CFG, &umc->umc_cfg);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002636 amd_smn_read(nid, umc_base + UMCCH_SDP_CTRL, &umc->sdp_ctrl);
2637 amd_smn_read(nid, umc_base + UMCCH_ECC_CTRL, &umc->ecc_ctrl);
Yazen Ghannam07ed82e2016-11-28 08:50:21 -06002638 amd_smn_read(nid, umc_base + UMCCH_UMC_CAP_HI, &umc->umc_cap_hi);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002639 }
2640}
2641
Doug Thompson0ec449e2009-04-27 19:41:25 +02002642/*
2643 * Retrieve the hardware registers of the memory controller (this includes the
2644 * 'Address Map' and 'Misc' device regs)
2645 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02002646static void read_mc_regs(struct amd64_pvt *pvt)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002647{
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002648 unsigned int range;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002649 u64 msr_val;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002650
2651 /*
2652 * Retrieve TOP_MEM and TOP_MEM2; no masking off of reserved bits since
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002653 * those are Read-As-Zero.
Doug Thompson0ec449e2009-04-27 19:41:25 +02002654 */
Borislav Petkove97f8bb2009-10-12 15:27:45 +02002655 rdmsrl(MSR_K8_TOP_MEM1, pvt->top_mem);
Joe Perches956b9ba2012-04-29 17:08:39 -03002656 edac_dbg(0, " TOP_MEM: 0x%016llx\n", pvt->top_mem);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002657
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002658 /* Check first whether TOP_MEM2 is enabled: */
Doug Thompson0ec449e2009-04-27 19:41:25 +02002659 rdmsrl(MSR_K8_SYSCFG, msr_val);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002660 if (msr_val & BIT(21)) {
Borislav Petkove97f8bb2009-10-12 15:27:45 +02002661 rdmsrl(MSR_K8_TOP_MEM2, pvt->top_mem2);
Joe Perches956b9ba2012-04-29 17:08:39 -03002662 edac_dbg(0, " TOP_MEM2: 0x%016llx\n", pvt->top_mem2);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002663 } else {
Joe Perches956b9ba2012-04-29 17:08:39 -03002664 edac_dbg(0, " TOP_MEM2 disabled\n");
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002665 }
2666
2667 if (pvt->umc) {
2668 __read_mc_regs_df(pvt);
2669 amd64_read_pci_cfg(pvt->F0, DF_DHAR, &pvt->dhar);
2670
2671 goto skip;
2672 }
Doug Thompson0ec449e2009-04-27 19:41:25 +02002673
Borislav Petkov5980bb92011-01-07 16:26:49 +01002674 amd64_read_pci_cfg(pvt->F3, NBCAP, &pvt->nbcap);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002675
Borislav Petkov5a5d2372011-01-17 17:52:57 +01002676 read_dram_ctl_register(pvt);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002677
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002678 for (range = 0; range < DRAM_RANGES; range++) {
2679 u8 rw;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002680
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002681 /* read settings for this DRAM range */
2682 read_dram_base_limit_regs(pvt, range);
Borislav Petkove97f8bb2009-10-12 15:27:45 +02002683
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002684 rw = dram_rw(pvt, range);
2685 if (!rw)
2686 continue;
2687
Joe Perches956b9ba2012-04-29 17:08:39 -03002688 edac_dbg(1, " DRAM range[%d], base: 0x%016llx; limit: 0x%016llx\n",
2689 range,
2690 get_dram_base(pvt, range),
2691 get_dram_limit(pvt, range));
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002692
Joe Perches956b9ba2012-04-29 17:08:39 -03002693 edac_dbg(1, " IntlvEn=%s; Range access: %s%s IntlvSel=%d DstNode=%d\n",
2694 dram_intlv_en(pvt, range) ? "Enabled" : "Disabled",
2695 (rw & 0x1) ? "R" : "-",
2696 (rw & 0x2) ? "W" : "-",
2697 dram_intlv_sel(pvt, range),
2698 dram_dst_node(pvt, range));
Doug Thompson0ec449e2009-04-27 19:41:25 +02002699 }
2700
Borislav Petkovbc21fa52010-11-11 17:29:13 +01002701 amd64_read_pci_cfg(pvt->F1, DHAR, &pvt->dhar);
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05002702 amd64_read_dct_pci_cfg(pvt, 0, DBAM0, &pvt->dbam0);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002703
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002704 amd64_read_pci_cfg(pvt->F3, F10_ONLINE_SPARE, &pvt->online_spare);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002705
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05002706 amd64_read_dct_pci_cfg(pvt, 0, DCLR0, &pvt->dclr0);
2707 amd64_read_dct_pci_cfg(pvt, 0, DCHR0, &pvt->dchr0);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002708
Borislav Petkov78da1212010-12-22 19:31:45 +01002709 if (!dct_ganging_enabled(pvt)) {
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05002710 amd64_read_dct_pci_cfg(pvt, 1, DCLR0, &pvt->dclr1);
2711 amd64_read_dct_pci_cfg(pvt, 1, DCHR0, &pvt->dchr1);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002712 }
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002713
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002714skip:
2715 read_dct_base_mask(pvt);
2716
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002717 determine_memory_type(pvt);
2718 edac_dbg(1, " DIMM type: %s\n", edac_mem_types[pvt->dram_type]);
Borislav Petkova3b7db02011-01-19 20:35:12 +01002719
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002720 determine_ecc_sym_sz(pvt);
Borislav Petkova3b7db02011-01-19 20:35:12 +01002721
Borislav Petkovb2b0c602010-10-08 18:32:29 +02002722 dump_misc_regs(pvt);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002723}
2724
2725/*
2726 * NOTE: CPU Revision Dependent code
2727 *
2728 * Input:
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002729 * @csrow_nr ChipSelect Row Number (0..NUM_CHIPSELECTS-1)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002730 * k8 private pointer to -->
2731 * DRAM Bank Address mapping register
2732 * node_id
2733 * DCL register where dual_channel_active is
2734 *
2735 * The DBAM register consists of 4 sets of 4 bits each definitions:
2736 *
2737 * Bits: CSROWs
2738 * 0-3 CSROWs 0 and 1
2739 * 4-7 CSROWs 2 and 3
2740 * 8-11 CSROWs 4 and 5
2741 * 12-15 CSROWs 6 and 7
2742 *
2743 * Values range from: 0 to 15
2744 * The meaning of the values depends on CPU revision and dual-channel state,
2745 * see relevant BKDG more info.
2746 *
2747 * The memory controller provides for total of only 8 CSROWs in its current
2748 * architecture. Each "pair" of CSROWs normally represents just one DIMM in
2749 * single channel or two (2) DIMMs in dual channel mode.
2750 *
2751 * The following code logic collapses the various tables for CSROW based on CPU
2752 * revision.
2753 *
2754 * Returns:
2755 * The number of PAGE_SIZE pages on the specified CSROW number it
2756 * encompasses
2757 *
2758 */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01002759static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002760{
Borislav Petkov1433eb92009-10-21 13:44:36 +02002761 u32 cs_mode, nr_pages;
Ashish Shenoyf92cae42012-02-22 17:20:38 -08002762 u32 dbam = dct ? pvt->dbam1 : pvt->dbam0;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002763
Borislav Petkov10de6492012-09-12 19:00:38 +02002764
Doug Thompson0ec449e2009-04-27 19:41:25 +02002765 /*
2766 * The math on this doesn't look right on the surface because x/2*4 can
2767 * be simplified to x*2 but this expression makes use of the fact that
2768 * it is integral math where 1/2=0. This intermediate value becomes the
2769 * number of bits to shift the DBAM register to extract the proper CSROW
2770 * field.
2771 */
Borislav Petkov0a5dfc32012-09-12 18:16:01 +02002772 cs_mode = DBAM_DIMM(csrow_nr / 2, dbam);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002773
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002774 nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode, (csrow_nr / 2))
2775 << (20 - PAGE_SHIFT);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002776
Borislav Petkov10de6492012-09-12 19:00:38 +02002777 edac_dbg(0, "csrow: %d, channel: %d, DBAM idx: %d\n",
2778 csrow_nr, dct, cs_mode);
2779 edac_dbg(0, "nr_pages/channel: %u\n", nr_pages);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002780
2781 return nr_pages;
2782}
2783
2784/*
2785 * Initialize the array of csrow attribute instances, based on the values
2786 * from pci config hardware registers.
2787 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02002788static int init_csrows(struct mem_ctl_info *mci)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002789{
Borislav Petkov10de6492012-09-12 19:00:38 +02002790 struct amd64_pvt *pvt = mci->pvt_info;
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06002791 enum edac_type edac_mode = EDAC_NONE;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002792 struct csrow_info *csrow;
Mauro Carvalho Chehabde3910eb2012-04-24 15:05:43 -03002793 struct dimm_info *dimm;
Borislav Petkov10de6492012-09-12 19:00:38 +02002794 int i, j, empty = 1;
Mauro Carvalho Chehaba895bf82012-01-28 09:09:38 -03002795 int nr_pages = 0;
Borislav Petkov10de6492012-09-12 19:00:38 +02002796 u32 val;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002797
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06002798 if (!pvt->umc) {
2799 amd64_read_pci_cfg(pvt->F3, NBCFG, &val);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002800
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06002801 pvt->nbcfg = val;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002802
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06002803 edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
2804 pvt->mc_node_id, val,
2805 !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
2806 }
Doug Thompson0ec449e2009-04-27 19:41:25 +02002807
Borislav Petkov10de6492012-09-12 19:00:38 +02002808 /*
2809 * We iterate over DCT0 here but we look at DCT1 in parallel, if needed.
2810 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002811 for_each_chip_select(i, 0, pvt) {
Borislav Petkov10de6492012-09-12 19:00:38 +02002812 bool row_dct0 = !!csrow_enabled(i, 0, pvt);
2813 bool row_dct1 = false;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002814
Borislav Petkova4b4bed2013-08-10 13:54:48 +02002815 if (pvt->fam != 0xf)
Borislav Petkov10de6492012-09-12 19:00:38 +02002816 row_dct1 = !!csrow_enabled(i, 1, pvt);
2817
2818 if (!row_dct0 && !row_dct1)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002819 continue;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002820
Borislav Petkov10de6492012-09-12 19:00:38 +02002821 csrow = mci->csrows[i];
Doug Thompson0ec449e2009-04-27 19:41:25 +02002822 empty = 0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002823
Borislav Petkov10de6492012-09-12 19:00:38 +02002824 edac_dbg(1, "MC node: %d, csrow: %d\n",
2825 pvt->mc_node_id, i);
2826
Mauro Carvalho Chehab1eef1282013-03-11 09:07:46 -03002827 if (row_dct0) {
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01002828 nr_pages = get_csrow_nr_pages(pvt, 0, i);
Mauro Carvalho Chehab1eef1282013-03-11 09:07:46 -03002829 csrow->channels[0]->dimm->nr_pages = nr_pages;
2830 }
Borislav Petkov10de6492012-09-12 19:00:38 +02002831
2832 /* K8 has only one DCT */
Borislav Petkova4b4bed2013-08-10 13:54:48 +02002833 if (pvt->fam != 0xf && row_dct1) {
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01002834 int row_dct1_pages = get_csrow_nr_pages(pvt, 1, i);
Mauro Carvalho Chehab1eef1282013-03-11 09:07:46 -03002835
2836 csrow->channels[1]->dimm->nr_pages = row_dct1_pages;
2837 nr_pages += row_dct1_pages;
2838 }
Doug Thompson0ec449e2009-04-27 19:41:25 +02002839
Borislav Petkov10de6492012-09-12 19:00:38 +02002840 edac_dbg(1, "Total csrow%d pages: %u\n", i, nr_pages);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002841
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06002842 /* Determine DIMM ECC mode: */
2843 if (pvt->umc) {
2844 if (mci->edac_ctl_cap & EDAC_FLAG_S4ECD4ED)
2845 edac_mode = EDAC_S4ECD4ED;
2846 else if (mci->edac_ctl_cap & EDAC_FLAG_SECDED)
2847 edac_mode = EDAC_SECDED;
2848
2849 } else if (pvt->nbcfg & NBCFG_ECC_ENABLE) {
2850 edac_mode = (pvt->nbcfg & NBCFG_CHIPKILL)
2851 ? EDAC_S4ECD4ED
2852 : EDAC_SECDED;
2853 }
Mauro Carvalho Chehab084a4fc2012-01-27 18:38:08 -03002854
2855 for (j = 0; j < pvt->channel_count; j++) {
Mauro Carvalho Chehabde3910eb2012-04-24 15:05:43 -03002856 dimm = csrow->channels[j]->dimm;
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002857 dimm->mtype = pvt->dram_type;
Mauro Carvalho Chehabde3910eb2012-04-24 15:05:43 -03002858 dimm->edac_mode = edac_mode;
Mauro Carvalho Chehab084a4fc2012-01-27 18:38:08 -03002859 }
Doug Thompson0ec449e2009-04-27 19:41:25 +02002860 }
2861
2862 return empty;
2863}
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002864
Borislav Petkov06724532009-09-16 13:05:46 +02002865/* get all cores on this DCT */
Daniel J Blueman8b84c8d2012-11-27 14:32:10 +08002866static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, u16 nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02002867{
Borislav Petkov06724532009-09-16 13:05:46 +02002868 int cpu;
Doug Thompsonf9431992009-04-27 19:46:08 +02002869
Borislav Petkov06724532009-09-16 13:05:46 +02002870 for_each_online_cpu(cpu)
2871 if (amd_get_nb_id(cpu) == nid)
2872 cpumask_set_cpu(cpu, mask);
Doug Thompsonf9431992009-04-27 19:46:08 +02002873}
2874
2875/* check MCG_CTL on all the cpus on this node */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01002876static bool nb_mce_bank_enabled_on_node(u16 nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02002877{
Rusty Russellba578cb2009-11-03 14:56:35 +10302878 cpumask_var_t mask;
Borislav Petkov50542252009-12-11 18:14:40 +01002879 int cpu, nbe;
Borislav Petkov06724532009-09-16 13:05:46 +02002880 bool ret = false;
Doug Thompsonf9431992009-04-27 19:46:08 +02002881
Rusty Russellba578cb2009-11-03 14:56:35 +10302882 if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002883 amd64_warn("%s: Error allocating mask\n", __func__);
Rusty Russellba578cb2009-11-03 14:56:35 +10302884 return false;
2885 }
Borislav Petkov06724532009-09-16 13:05:46 +02002886
Rusty Russellba578cb2009-11-03 14:56:35 +10302887 get_cpus_on_this_dct_cpumask(mask, nid);
Borislav Petkov06724532009-09-16 13:05:46 +02002888
Rusty Russellba578cb2009-11-03 14:56:35 +10302889 rdmsr_on_cpus(mask, MSR_IA32_MCG_CTL, msrs);
Borislav Petkov06724532009-09-16 13:05:46 +02002890
Rusty Russellba578cb2009-11-03 14:56:35 +10302891 for_each_cpu(cpu, mask) {
Borislav Petkov50542252009-12-11 18:14:40 +01002892 struct msr *reg = per_cpu_ptr(msrs, cpu);
Borislav Petkov5980bb92011-01-07 16:26:49 +01002893 nbe = reg->l & MSR_MCGCTL_NBE;
Borislav Petkov06724532009-09-16 13:05:46 +02002894
Joe Perches956b9ba2012-04-29 17:08:39 -03002895 edac_dbg(0, "core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n",
2896 cpu, reg->q,
2897 (nbe ? "enabled" : "disabled"));
Borislav Petkov06724532009-09-16 13:05:46 +02002898
2899 if (!nbe)
2900 goto out;
Borislav Petkov06724532009-09-16 13:05:46 +02002901 }
2902 ret = true;
2903
2904out:
Rusty Russellba578cb2009-11-03 14:56:35 +10302905 free_cpumask_var(mask);
Doug Thompsonf9431992009-04-27 19:46:08 +02002906 return ret;
2907}
2908
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08002909static int toggle_ecc_err_reporting(struct ecc_settings *s, u16 nid, bool on)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002910{
2911 cpumask_var_t cmask;
Borislav Petkov50542252009-12-11 18:14:40 +01002912 int cpu;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002913
2914 if (!zalloc_cpumask_var(&cmask, GFP_KERNEL)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002915 amd64_warn("%s: error allocating mask\n", __func__);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002916 return false;
2917 }
2918
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002919 get_cpus_on_this_dct_cpumask(cmask, nid);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002920
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002921 rdmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
2922
2923 for_each_cpu(cpu, cmask) {
2924
Borislav Petkov50542252009-12-11 18:14:40 +01002925 struct msr *reg = per_cpu_ptr(msrs, cpu);
2926
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002927 if (on) {
Borislav Petkov5980bb92011-01-07 16:26:49 +01002928 if (reg->l & MSR_MCGCTL_NBE)
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002929 s->flags.nb_mce_enable = 1;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002930
Borislav Petkov5980bb92011-01-07 16:26:49 +01002931 reg->l |= MSR_MCGCTL_NBE;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002932 } else {
2933 /*
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002934 * Turn off NB MCE reporting only when it was off before
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002935 */
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002936 if (!s->flags.nb_mce_enable)
Borislav Petkov5980bb92011-01-07 16:26:49 +01002937 reg->l &= ~MSR_MCGCTL_NBE;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002938 }
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002939 }
2940 wrmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
2941
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002942 free_cpumask_var(cmask);
2943
2944 return 0;
2945}
2946
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08002947static bool enable_ecc_error_reporting(struct ecc_settings *s, u16 nid,
Borislav Petkov2299ef72010-10-15 17:44:04 +02002948 struct pci_dev *F3)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002949{
Borislav Petkov2299ef72010-10-15 17:44:04 +02002950 bool ret = true;
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002951 u32 value, mask = 0x3; /* UECC/CECC enable */
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002952
Borislav Petkov2299ef72010-10-15 17:44:04 +02002953 if (toggle_ecc_err_reporting(s, nid, ON)) {
2954 amd64_warn("Error enabling ECC reporting over MCGCTL!\n");
2955 return false;
2956 }
2957
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002958 amd64_read_pci_cfg(F3, NBCTL, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002959
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002960 s->old_nbctl = value & mask;
2961 s->nbctl_valid = true;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002962
2963 value |= mask;
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002964 amd64_write_pci_cfg(F3, NBCTL, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002965
Borislav Petkova97fa682010-12-23 14:07:18 +01002966 amd64_read_pci_cfg(F3, NBCFG, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002967
Joe Perches956b9ba2012-04-29 17:08:39 -03002968 edac_dbg(0, "1: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
2969 nid, value, !!(value & NBCFG_ECC_ENABLE));
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002970
Borislav Petkova97fa682010-12-23 14:07:18 +01002971 if (!(value & NBCFG_ECC_ENABLE)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002972 amd64_warn("DRAM ECC disabled on this node, enabling...\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002973
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002974 s->flags.nb_ecc_prev = 0;
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002975
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002976 /* Attempt to turn on DRAM ECC Enable */
Borislav Petkova97fa682010-12-23 14:07:18 +01002977 value |= NBCFG_ECC_ENABLE;
2978 amd64_write_pci_cfg(F3, NBCFG, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002979
Borislav Petkova97fa682010-12-23 14:07:18 +01002980 amd64_read_pci_cfg(F3, NBCFG, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002981
Borislav Petkova97fa682010-12-23 14:07:18 +01002982 if (!(value & NBCFG_ECC_ENABLE)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002983 amd64_warn("Hardware rejected DRAM ECC enable,"
2984 "check memory DIMM configuration.\n");
Borislav Petkov2299ef72010-10-15 17:44:04 +02002985 ret = false;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002986 } else {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002987 amd64_info("Hardware accepted DRAM ECC Enable\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002988 }
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002989 } else {
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002990 s->flags.nb_ecc_prev = 1;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002991 }
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002992
Joe Perches956b9ba2012-04-29 17:08:39 -03002993 edac_dbg(0, "2: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
2994 nid, value, !!(value & NBCFG_ECC_ENABLE));
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002995
Borislav Petkov2299ef72010-10-15 17:44:04 +02002996 return ret;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002997}
2998
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08002999static void restore_ecc_error_reporting(struct ecc_settings *s, u16 nid,
Borislav Petkov360b7f32010-10-15 19:25:38 +02003000 struct pci_dev *F3)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003001{
Borislav Petkovc9f4f262010-12-22 19:48:20 +01003002 u32 value, mask = 0x3; /* UECC/CECC enable */
3003
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003004 if (!s->nbctl_valid)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003005 return;
3006
Borislav Petkovc9f4f262010-12-22 19:48:20 +01003007 amd64_read_pci_cfg(F3, NBCTL, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003008 value &= ~mask;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003009 value |= s->old_nbctl;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003010
Borislav Petkovc9f4f262010-12-22 19:48:20 +01003011 amd64_write_pci_cfg(F3, NBCTL, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003012
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003013 /* restore previous BIOS DRAM ECC "off" setting we force-enabled */
3014 if (!s->flags.nb_ecc_prev) {
Borislav Petkova97fa682010-12-23 14:07:18 +01003015 amd64_read_pci_cfg(F3, NBCFG, &value);
3016 value &= ~NBCFG_ECC_ENABLE;
3017 amd64_write_pci_cfg(F3, NBCFG, value);
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01003018 }
3019
3020 /* restore the NB Enable MCGCTL bit */
Borislav Petkov2299ef72010-10-15 17:44:04 +02003021 if (toggle_ecc_err_reporting(s, nid, OFF))
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02003022 amd64_warn("Error restoring NB MCGCTL settings!\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003023}
3024
Doug Thompsonf9431992009-04-27 19:46:08 +02003025/*
Borislav Petkov2299ef72010-10-15 17:44:04 +02003026 * EDAC requires that the BIOS have ECC enabled before
3027 * taking over the processing of ECC errors. A command line
3028 * option allows to force-enable hardware ECC later in
3029 * enable_ecc_error_reporting().
Doug Thompsonf9431992009-04-27 19:46:08 +02003030 */
Borislav Petkovcab4d272010-02-11 17:15:57 +01003031static const char *ecc_msg =
3032 "ECC disabled in the BIOS or no ECC capability, module will not load.\n"
3033 " Either enable ECC checking or force module loading by setting "
3034 "'ecc_enable_override'.\n"
3035 " (Note that use of the override may cause unknown side effects.)\n";
Borislav Petkovbe3468e2009-08-05 15:47:22 +02003036
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08003037static bool ecc_enabled(struct pci_dev *F3, u16 nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02003038{
Borislav Petkov06724532009-09-16 13:05:46 +02003039 bool nb_mce_en = false;
Yazen Ghannam196b79f2016-11-17 17:57:34 -05003040 u8 ecc_en = 0, i;
3041 u32 value;
Doug Thompsonf9431992009-04-27 19:46:08 +02003042
Yazen Ghannam196b79f2016-11-17 17:57:34 -05003043 if (boot_cpu_data.x86 >= 0x17) {
3044 u8 umc_en_mask = 0, ecc_en_mask = 0;
Doug Thompsonf9431992009-04-27 19:46:08 +02003045
Yazen Ghannam196b79f2016-11-17 17:57:34 -05003046 for (i = 0; i < NUM_UMCS; i++) {
3047 u32 base = get_umc_base(i);
3048
3049 /* Only check enabled UMCs. */
3050 if (amd_smn_read(nid, base + UMCCH_SDP_CTRL, &value))
3051 continue;
3052
3053 if (!(value & UMC_SDP_INIT))
3054 continue;
3055
3056 umc_en_mask |= BIT(i);
3057
3058 if (amd_smn_read(nid, base + UMCCH_UMC_CAP_HI, &value))
3059 continue;
3060
3061 if (value & UMC_ECC_ENABLED)
3062 ecc_en_mask |= BIT(i);
3063 }
3064
3065 /* Check whether at least one UMC is enabled: */
3066 if (umc_en_mask)
3067 ecc_en = umc_en_mask == ecc_en_mask;
3068
3069 /* Assume UMC MCA banks are enabled. */
3070 nb_mce_en = true;
3071 } else {
3072 amd64_read_pci_cfg(F3, NBCFG, &value);
3073
3074 ecc_en = !!(value & NBCFG_ECC_ENABLE);
3075
3076 nb_mce_en = nb_mce_bank_enabled_on_node(nid);
3077 if (!nb_mce_en)
3078 amd64_notice("NB MCE bank disabled, set MSR 0x%08x[4] on node %d to enable.\n",
3079 MSR_IA32_MCG_CTL, nid);
3080 }
3081
Borislav Petkov2299ef72010-10-15 17:44:04 +02003082 amd64_info("DRAM ECC %s.\n", (ecc_en ? "enabled" : "disabled"));
Doug Thompsonf9431992009-04-27 19:46:08 +02003083
Borislav Petkov2299ef72010-10-15 17:44:04 +02003084 if (!ecc_en || !nb_mce_en) {
3085 amd64_notice("%s", ecc_msg);
3086 return false;
Borislav Petkov43f5e682009-12-21 18:55:18 +01003087 }
Borislav Petkov2299ef72010-10-15 17:44:04 +02003088 return true;
Doug Thompsonf9431992009-04-27 19:46:08 +02003089}
3090
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06003091static inline void
3092f17h_determine_edac_ctl_cap(struct mem_ctl_info *mci, struct amd64_pvt *pvt)
3093{
3094 u8 i, ecc_en = 1, cpk_en = 1;
3095
3096 for (i = 0; i < NUM_UMCS; i++) {
3097 if (pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) {
3098 ecc_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_ENABLED);
3099 cpk_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_CHIPKILL_CAP);
3100 }
3101 }
3102
3103 /* Set chipkill only if ECC is enabled: */
3104 if (ecc_en) {
3105 mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
3106
3107 if (cpk_en)
3108 mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
3109 }
3110}
3111
Borislav Petkovdf71a052011-01-19 18:15:10 +01003112static void setup_mci_misc_attrs(struct mem_ctl_info *mci,
3113 struct amd64_family_type *fam)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003114{
3115 struct amd64_pvt *pvt = mci->pvt_info;
3116
3117 mci->mtype_cap = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2;
3118 mci->edac_ctl_cap = EDAC_FLAG_NONE;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003119
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06003120 if (pvt->umc) {
3121 f17h_determine_edac_ctl_cap(mci, pvt);
3122 } else {
3123 if (pvt->nbcap & NBCAP_SECDED)
3124 mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003125
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06003126 if (pvt->nbcap & NBCAP_CHIPKILL)
3127 mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
3128 }
Doug Thompson7d6034d2009-04-27 20:01:01 +02003129
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003130 mci->edac_cap = determine_edac_cap(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003131 mci->mod_name = EDAC_MOD_STR;
3132 mci->mod_ver = EDAC_AMD64_VERSION;
Borislav Petkovdf71a052011-01-19 18:15:10 +01003133 mci->ctl_name = fam->ctl_name;
Yazen Ghanname7934b72016-11-17 17:57:30 -05003134 mci->dev_name = pci_name(pvt->F3);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003135 mci->ctl_page_to_phys = NULL;
3136
Doug Thompson7d6034d2009-04-27 20:01:01 +02003137 /* memory scrubber interface */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003138 mci->set_sdram_scrub_rate = set_scrub_rate;
3139 mci->get_sdram_scrub_rate = get_scrub_rate;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003140}
3141
Borislav Petkov0092b202010-10-01 19:20:05 +02003142/*
3143 * returns a pointer to the family descriptor on success, NULL otherwise.
3144 */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003145static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
Borislav Petkov395ae782010-10-01 18:38:19 +02003146{
Borislav Petkov0092b202010-10-01 19:20:05 +02003147 struct amd64_family_type *fam_type = NULL;
3148
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003149 pvt->ext_model = boot_cpu_data.x86_model >> 4;
Borislav Petkova4b4bed2013-08-10 13:54:48 +02003150 pvt->stepping = boot_cpu_data.x86_mask;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003151 pvt->model = boot_cpu_data.x86_model;
3152 pvt->fam = boot_cpu_data.x86;
3153
3154 switch (pvt->fam) {
Borislav Petkov395ae782010-10-01 18:38:19 +02003155 case 0xf:
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003156 fam_type = &family_types[K8_CPUS];
3157 pvt->ops = &family_types[K8_CPUS].ops;
Borislav Petkov395ae782010-10-01 18:38:19 +02003158 break;
Borislav Petkovdf71a052011-01-19 18:15:10 +01003159
Borislav Petkov395ae782010-10-01 18:38:19 +02003160 case 0x10:
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003161 fam_type = &family_types[F10_CPUS];
3162 pvt->ops = &family_types[F10_CPUS].ops;
Borislav Petkovdf71a052011-01-19 18:15:10 +01003163 break;
3164
3165 case 0x15:
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003166 if (pvt->model == 0x30) {
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003167 fam_type = &family_types[F15_M30H_CPUS];
3168 pvt->ops = &family_types[F15_M30H_CPUS].ops;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003169 break;
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01003170 } else if (pvt->model == 0x60) {
3171 fam_type = &family_types[F15_M60H_CPUS];
3172 pvt->ops = &family_types[F15_M60H_CPUS].ops;
3173 break;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003174 }
3175
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003176 fam_type = &family_types[F15_CPUS];
3177 pvt->ops = &family_types[F15_CPUS].ops;
Borislav Petkov395ae782010-10-01 18:38:19 +02003178 break;
3179
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05003180 case 0x16:
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -06003181 if (pvt->model == 0x30) {
3182 fam_type = &family_types[F16_M30H_CPUS];
3183 pvt->ops = &family_types[F16_M30H_CPUS].ops;
3184 break;
3185 }
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003186 fam_type = &family_types[F16_CPUS];
3187 pvt->ops = &family_types[F16_CPUS].ops;
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05003188 break;
3189
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05003190 case 0x17:
3191 fam_type = &family_types[F17_CPUS];
3192 pvt->ops = &family_types[F17_CPUS].ops;
3193 break;
3194
Borislav Petkov395ae782010-10-01 18:38:19 +02003195 default:
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02003196 amd64_err("Unsupported family!\n");
Borislav Petkov0092b202010-10-01 19:20:05 +02003197 return NULL;
Borislav Petkov395ae782010-10-01 18:38:19 +02003198 }
Borislav Petkov0092b202010-10-01 19:20:05 +02003199
Borislav Petkovdf71a052011-01-19 18:15:10 +01003200 amd64_info("%s %sdetected (node %d).\n", fam_type->ctl_name,
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003201 (pvt->fam == 0xf ?
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02003202 (pvt->ext_model >= K8_REV_F ? "revF or later "
3203 : "revE or earlier ")
3204 : ""), pvt->mc_node_id);
Borislav Petkov0092b202010-10-01 19:20:05 +02003205 return fam_type;
Borislav Petkov395ae782010-10-01 18:38:19 +02003206}
3207
Takashi Iwaie339f1e2015-02-04 11:48:53 +01003208static const struct attribute_group *amd64_edac_attr_groups[] = {
3209#ifdef CONFIG_EDAC_DEBUG
3210 &amd64_edac_dbg_group,
3211#endif
3212#ifdef CONFIG_EDAC_AMD64_ERROR_INJECTION
3213 &amd64_edac_inj_group,
3214#endif
3215 NULL
3216};
3217
Borislav Petkov3f37a362016-05-06 19:44:27 +02003218static int init_one_instance(unsigned int nid)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003219{
Borislav Petkov3f37a362016-05-06 19:44:27 +02003220 struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
Borislav Petkov0092b202010-10-01 19:20:05 +02003221 struct amd64_family_type *fam_type = NULL;
Borislav Petkov360b7f32010-10-15 19:25:38 +02003222 struct mem_ctl_info *mci = NULL;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03003223 struct edac_mc_layer layers[2];
Borislav Petkov3f37a362016-05-06 19:44:27 +02003224 struct amd64_pvt *pvt = NULL;
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05003225 u16 pci_id1, pci_id2;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003226 int err = 0, ret;
3227
3228 ret = -ENOMEM;
3229 pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
3230 if (!pvt)
Borislav Petkov360b7f32010-10-15 19:25:38 +02003231 goto err_ret;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003232
Borislav Petkov360b7f32010-10-15 19:25:38 +02003233 pvt->mc_node_id = nid;
Borislav Petkov3f37a362016-05-06 19:44:27 +02003234 pvt->F3 = F3;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003235
Borislav Petkov395ae782010-10-01 18:38:19 +02003236 ret = -EINVAL;
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003237 fam_type = per_family_init(pvt);
Borislav Petkov0092b202010-10-01 19:20:05 +02003238 if (!fam_type)
Borislav Petkov395ae782010-10-01 18:38:19 +02003239 goto err_free;
3240
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05003241 if (pvt->fam >= 0x17) {
3242 pvt->umc = kcalloc(NUM_UMCS, sizeof(struct amd64_umc), GFP_KERNEL);
3243 if (!pvt->umc) {
3244 ret = -ENOMEM;
3245 goto err_free;
3246 }
3247
3248 pci_id1 = fam_type->f0_id;
3249 pci_id2 = fam_type->f6_id;
3250 } else {
3251 pci_id1 = fam_type->f1_id;
3252 pci_id2 = fam_type->f2_id;
3253 }
3254
3255 err = reserve_mc_sibling_devs(pvt, pci_id1, pci_id2);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003256 if (err)
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05003257 goto err_post_init;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003258
Borislav Petkov360b7f32010-10-15 19:25:38 +02003259 read_mc_regs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003260
Doug Thompson7d6034d2009-04-27 20:01:01 +02003261 /*
3262 * We need to determine how many memory channels there are. Then use
3263 * that information for calculating the size of the dynamic instance
Borislav Petkov360b7f32010-10-15 19:25:38 +02003264 * tables in the 'mci' structure.
Doug Thompson7d6034d2009-04-27 20:01:01 +02003265 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02003266 ret = -EINVAL;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003267 pvt->channel_count = pvt->ops->early_channel_count(pvt);
3268 if (pvt->channel_count < 0)
Borislav Petkov360b7f32010-10-15 19:25:38 +02003269 goto err_siblings;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003270
3271 ret = -ENOMEM;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03003272 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
3273 layers[0].size = pvt->csels[0].b_cnt;
3274 layers[0].is_virt_csrow = true;
3275 layers[1].type = EDAC_MC_LAYER_CHANNEL;
Borislav Petkovf0a56c42013-07-23 20:01:23 +02003276
3277 /*
3278 * Always allocate two channels since we can have setups with DIMMs on
3279 * only one channel. Also, this simplifies handling later for the price
3280 * of a couple of KBs tops.
3281 */
3282 layers[1].size = 2;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03003283 layers[1].is_virt_csrow = false;
Borislav Petkovf0a56c42013-07-23 20:01:23 +02003284
Mauro Carvalho Chehabca0907b2012-05-02 14:37:00 -03003285 mci = edac_mc_alloc(nid, ARRAY_SIZE(layers), layers, 0);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003286 if (!mci)
Borislav Petkov360b7f32010-10-15 19:25:38 +02003287 goto err_siblings;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003288
3289 mci->pvt_info = pvt;
Borislav Petkov3f37a362016-05-06 19:44:27 +02003290 mci->pdev = &pvt->F3->dev;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003291
Borislav Petkovdf71a052011-01-19 18:15:10 +01003292 setup_mci_misc_attrs(mci, fam_type);
Borislav Petkov360b7f32010-10-15 19:25:38 +02003293
3294 if (init_csrows(mci))
Doug Thompson7d6034d2009-04-27 20:01:01 +02003295 mci->edac_cap = EDAC_FLAG_NONE;
3296
Doug Thompson7d6034d2009-04-27 20:01:01 +02003297 ret = -ENODEV;
Takashi Iwaie339f1e2015-02-04 11:48:53 +01003298 if (edac_mc_add_mc_with_groups(mci, amd64_edac_attr_groups)) {
Joe Perches956b9ba2012-04-29 17:08:39 -03003299 edac_dbg(1, "failed edac_mc_add_mc()\n");
Doug Thompson7d6034d2009-04-27 20:01:01 +02003300 goto err_add_mc;
3301 }
3302
Borislav Petkov549d0422009-07-24 13:51:42 +02003303 /* register stuff with EDAC MCE */
3304 if (report_gart_errors)
3305 amd_report_gart_errors(true);
3306
Yazen Ghannam713ad542016-11-28 12:59:53 -06003307 if (pvt->umc)
3308 amd_register_ecc_decoder(decode_umc_error);
3309 else
3310 amd_register_ecc_decoder(decode_bus_error);
Borislav Petkov549d0422009-07-24 13:51:42 +02003311
Doug Thompson7d6034d2009-04-27 20:01:01 +02003312 return 0;
3313
3314err_add_mc:
3315 edac_mc_free(mci);
3316
Borislav Petkov360b7f32010-10-15 19:25:38 +02003317err_siblings:
3318 free_mc_sibling_devs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003319
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05003320err_post_init:
3321 if (pvt->fam >= 0x17)
3322 kfree(pvt->umc);
3323
Borislav Petkov360b7f32010-10-15 19:25:38 +02003324err_free:
3325 kfree(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003326
Borislav Petkov360b7f32010-10-15 19:25:38 +02003327err_ret:
Doug Thompson7d6034d2009-04-27 20:01:01 +02003328 return ret;
3329}
3330
Borislav Petkov3f37a362016-05-06 19:44:27 +02003331static int probe_one_instance(unsigned int nid)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003332{
Borislav Petkov2299ef72010-10-15 17:44:04 +02003333 struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003334 struct ecc_settings *s;
Borislav Petkov3f37a362016-05-06 19:44:27 +02003335 int ret;
Borislav Petkovb8cfa022010-10-01 19:35:38 +02003336
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003337 ret = -ENOMEM;
3338 s = kzalloc(sizeof(struct ecc_settings), GFP_KERNEL);
3339 if (!s)
Borislav Petkov2299ef72010-10-15 17:44:04 +02003340 goto err_out;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003341
3342 ecc_stngs[nid] = s;
3343
Borislav Petkov2299ef72010-10-15 17:44:04 +02003344 if (!ecc_enabled(F3, nid)) {
3345 ret = -ENODEV;
3346
3347 if (!ecc_enable_override)
3348 goto err_enable;
3349
Yazen Ghannam044e7a42016-11-22 15:40:16 -06003350 if (boot_cpu_data.x86 >= 0x17) {
3351 amd64_warn("Forcing ECC on is not recommended on newer systems. Please enable ECC in BIOS.");
3352 goto err_enable;
3353 } else
3354 amd64_warn("Forcing ECC on!\n");
Borislav Petkov2299ef72010-10-15 17:44:04 +02003355
3356 if (!enable_ecc_error_reporting(s, nid, F3))
3357 goto err_enable;
3358 }
3359
Borislav Petkov3f37a362016-05-06 19:44:27 +02003360 ret = init_one_instance(nid);
Borislav Petkov360b7f32010-10-15 19:25:38 +02003361 if (ret < 0) {
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003362 amd64_err("Error probing instance: %d\n", nid);
Yazen Ghannam044e7a42016-11-22 15:40:16 -06003363
3364 if (boot_cpu_data.x86 < 0x17)
3365 restore_ecc_error_reporting(s, nid, F3);
Borislav Petkov360b7f32010-10-15 19:25:38 +02003366 }
Doug Thompson7d6034d2009-04-27 20:01:01 +02003367
3368 return ret;
Borislav Petkov2299ef72010-10-15 17:44:04 +02003369
3370err_enable:
3371 kfree(s);
3372 ecc_stngs[nid] = NULL;
3373
3374err_out:
3375 return ret;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003376}
3377
Borislav Petkov3f37a362016-05-06 19:44:27 +02003378static void remove_one_instance(unsigned int nid)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003379{
Borislav Petkov360b7f32010-10-15 19:25:38 +02003380 struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
3381 struct ecc_settings *s = ecc_stngs[nid];
Borislav Petkov3f37a362016-05-06 19:44:27 +02003382 struct mem_ctl_info *mci;
3383 struct amd64_pvt *pvt;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003384
Borislav Petkov3f37a362016-05-06 19:44:27 +02003385 mci = find_mci_by_dev(&F3->dev);
Borislav Petkova4b4bed2013-08-10 13:54:48 +02003386 WARN_ON(!mci);
3387
Doug Thompson7d6034d2009-04-27 20:01:01 +02003388 /* Remove from EDAC CORE tracking list */
Borislav Petkov3f37a362016-05-06 19:44:27 +02003389 mci = edac_mc_del_mc(&F3->dev);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003390 if (!mci)
3391 return;
3392
3393 pvt = mci->pvt_info;
3394
Borislav Petkov360b7f32010-10-15 19:25:38 +02003395 restore_ecc_error_reporting(s, nid, F3);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003396
Borislav Petkov360b7f32010-10-15 19:25:38 +02003397 free_mc_sibling_devs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003398
Borislav Petkov549d0422009-07-24 13:51:42 +02003399 /* unregister from EDAC MCE */
3400 amd_report_gart_errors(false);
Yazen Ghannam713ad542016-11-28 12:59:53 -06003401
3402 if (pvt->umc)
3403 amd_unregister_ecc_decoder(decode_umc_error);
3404 else
3405 amd_unregister_ecc_decoder(decode_bus_error);
Borislav Petkov549d0422009-07-24 13:51:42 +02003406
Borislav Petkov360b7f32010-10-15 19:25:38 +02003407 kfree(ecc_stngs[nid]);
3408 ecc_stngs[nid] = NULL;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003409
Doug Thompson7d6034d2009-04-27 20:01:01 +02003410 /* Free the EDAC CORE resources */
Borislav Petkov8f68ed92009-12-21 15:15:59 +01003411 mci->pvt_info = NULL;
Borislav Petkov8f68ed92009-12-21 15:15:59 +01003412
3413 kfree(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003414 edac_mc_free(mci);
3415}
3416
Borislav Petkov360b7f32010-10-15 19:25:38 +02003417static void setup_pci_device(void)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003418{
3419 struct mem_ctl_info *mci;
3420 struct amd64_pvt *pvt;
3421
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003422 if (pci_ctl)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003423 return;
3424
Borislav Petkov2ec591a2015-02-17 10:58:34 +01003425 mci = edac_mc_find(0);
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003426 if (!mci)
3427 return;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003428
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003429 pvt = mci->pvt_info;
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05003430 if (pvt->umc)
3431 pci_ctl = edac_pci_create_generic_ctl(&pvt->F0->dev, EDAC_MOD_STR);
3432 else
3433 pci_ctl = edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR);
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003434 if (!pci_ctl) {
3435 pr_warn("%s(): Unable to create PCI control\n", __func__);
3436 pr_warn("%s(): PCI error report via EDAC not set\n", __func__);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003437 }
3438}
3439
Yazen Ghannamd6efab72016-09-15 19:07:17 -05003440static const struct x86_cpu_id amd64_cpuids[] = {
3441 { X86_VENDOR_AMD, 0xF, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
3442 { X86_VENDOR_AMD, 0x10, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
3443 { X86_VENDOR_AMD, 0x15, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
3444 { X86_VENDOR_AMD, 0x16, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
Yazen Ghannam95d3af62016-11-17 17:57:43 -05003445 { X86_VENDOR_AMD, 0x17, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
Yazen Ghannamd6efab72016-09-15 19:07:17 -05003446 { }
3447};
3448MODULE_DEVICE_TABLE(x86cpu, amd64_cpuids);
3449
Doug Thompson7d6034d2009-04-27 20:01:01 +02003450static int __init amd64_edac_init(void)
3451{
Borislav Petkov360b7f32010-10-15 19:25:38 +02003452 int err = -ENODEV;
Borislav Petkov3f37a362016-05-06 19:44:27 +02003453 int i;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003454
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +02003455 if (amd_cache_northbridges() < 0)
Borislav Petkov56b34b92009-12-21 18:13:01 +01003456 goto err_ret;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003457
Borislav Petkov6ba92fe2016-06-16 01:13:18 +02003458 opstate_init();
3459
Borislav Petkovcc4d8862010-10-13 16:11:59 +02003460 err = -ENOMEM;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003461 ecc_stngs = kzalloc(amd_nb_num() * sizeof(ecc_stngs[0]), GFP_KERNEL);
Borislav Petkov2ec591a2015-02-17 10:58:34 +01003462 if (!ecc_stngs)
Borislav Petkova9f0fbe2011-03-29 18:10:53 +02003463 goto err_free;
Borislav Petkovcc4d8862010-10-13 16:11:59 +02003464
Borislav Petkov50542252009-12-11 18:14:40 +01003465 msrs = msrs_alloc();
Borislav Petkov56b34b92009-12-21 18:13:01 +01003466 if (!msrs)
Borislav Petkov360b7f32010-10-15 19:25:38 +02003467 goto err_free;
Borislav Petkov50542252009-12-11 18:14:40 +01003468
Borislav Petkov3f37a362016-05-06 19:44:27 +02003469 for (i = 0; i < amd_nb_num(); i++)
3470 if (probe_one_instance(i)) {
3471 /* unwind properly */
3472 while (--i >= 0)
3473 remove_one_instance(i);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003474
Borislav Petkov3f37a362016-05-06 19:44:27 +02003475 goto err_pci;
3476 }
Doug Thompson7d6034d2009-04-27 20:01:01 +02003477
Borislav Petkov360b7f32010-10-15 19:25:38 +02003478 setup_pci_device();
Tomasz Palaf5b10c42014-11-02 11:22:12 +01003479
3480#ifdef CONFIG_X86_32
3481 amd64_err("%s on 32-bit is unsupported. USE AT YOUR OWN RISK!\n", EDAC_MOD_STR);
3482#endif
3483
Borislav Petkovde0336b2016-04-27 12:21:21 +02003484 printk(KERN_INFO "AMD64 EDAC driver v%s\n", EDAC_AMD64_VERSION);
3485
Borislav Petkov360b7f32010-10-15 19:25:38 +02003486 return 0;
Borislav Petkov56b34b92009-12-21 18:13:01 +01003487
Borislav Petkov56b34b92009-12-21 18:13:01 +01003488err_pci:
3489 msrs_free(msrs);
3490 msrs = NULL;
Borislav Petkovcc4d8862010-10-13 16:11:59 +02003491
Borislav Petkov360b7f32010-10-15 19:25:38 +02003492err_free:
Borislav Petkov360b7f32010-10-15 19:25:38 +02003493 kfree(ecc_stngs);
3494 ecc_stngs = NULL;
3495
Borislav Petkov56b34b92009-12-21 18:13:01 +01003496err_ret:
Doug Thompson7d6034d2009-04-27 20:01:01 +02003497 return err;
3498}
3499
3500static void __exit amd64_edac_exit(void)
3501{
Borislav Petkov3f37a362016-05-06 19:44:27 +02003502 int i;
3503
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003504 if (pci_ctl)
3505 edac_pci_release_generic_ctl(pci_ctl);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003506
Borislav Petkov3f37a362016-05-06 19:44:27 +02003507 for (i = 0; i < amd_nb_num(); i++)
3508 remove_one_instance(i);
Borislav Petkov50542252009-12-11 18:14:40 +01003509
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003510 kfree(ecc_stngs);
3511 ecc_stngs = NULL;
3512
Borislav Petkov50542252009-12-11 18:14:40 +01003513 msrs_free(msrs);
3514 msrs = NULL;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003515}
3516
3517module_init(amd64_edac_init);
3518module_exit(amd64_edac_exit);
3519
3520MODULE_LICENSE("GPL");
3521MODULE_AUTHOR("SoftwareBitMaker: Doug Thompson, "
3522 "Dave Peterson, Thayne Harbaugh");
3523MODULE_DESCRIPTION("MC support for AMD64 memory controllers - "
3524 EDAC_AMD64_VERSION);
3525
3526module_param(edac_op_state, int, 0444);
3527MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");