blob: e4fd459d807a037f30566573153edb893b29f1e3 [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
Pu Wenc4a3e942018-09-27 16:31:28 +0200214 if (pvt->fam == 0x17 || pvt->fam == 0x18) {
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500215 __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:
Pu Wenc4a3e942018-09-27 16:31:28 +0200267 case 0x18:
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500268 amd64_read_pci_cfg(pvt->F6, F17H_SCR_BASE_ADDR, &scrubval);
269 if (scrubval & BIT(0)) {
270 amd64_read_pci_cfg(pvt->F6, F17H_SCR_LIMIT_ADDR, &scrubval);
271 scrubval &= 0xF;
272 scrubval += 0x5;
273 } else {
274 scrubval = 0;
275 }
276 break;
277
278 default:
Aravind Gopalakrishnanda921102015-09-28 06:43:12 -0500279 amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval);
Yazen Ghannam8051c0a2016-11-17 17:57:42 -0500280 break;
281 }
Doug Thompson2bc65412009-05-04 20:11:14 +0200282
283 scrubval = scrubval & 0x001F;
284
Roel Kluin926311f2010-01-11 20:58:21 +0100285 for (i = 0; i < ARRAY_SIZE(scrubrates); i++) {
Doug Thompson2bc65412009-05-04 20:11:14 +0200286 if (scrubrates[i].scrubval == scrubval) {
Borislav Petkov39094442010-11-24 19:52:09 +0100287 retval = scrubrates[i].bandwidth;
Doug Thompson2bc65412009-05-04 20:11:14 +0200288 break;
289 }
290 }
Borislav Petkov39094442010-11-24 19:52:09 +0100291 return retval;
Doug Thompson2bc65412009-05-04 20:11:14 +0200292}
293
Doug Thompson67757632009-04-27 15:53:22 +0200294/*
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200295 * returns true if the SysAddr given by sys_addr matches the
296 * DRAM base/limit associated with node_id
Doug Thompson67757632009-04-27 15:53:22 +0200297 */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100298static bool base_limit_match(struct amd64_pvt *pvt, u64 sys_addr, u8 nid)
Doug Thompson67757632009-04-27 15:53:22 +0200299{
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200300 u64 addr;
Doug Thompson67757632009-04-27 15:53:22 +0200301
302 /* The K8 treats this as a 40-bit value. However, bits 63-40 will be
303 * all ones if the most significant implemented address bit is 1.
304 * Here we discard bits 63-40. See section 3.4.2 of AMD publication
305 * 24592: AMD x86-64 Architecture Programmer's Manual Volume 1
306 * Application Programming.
307 */
308 addr = sys_addr & 0x000000ffffffffffull;
309
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200310 return ((addr >= get_dram_base(pvt, nid)) &&
311 (addr <= get_dram_limit(pvt, nid)));
Doug Thompson67757632009-04-27 15:53:22 +0200312}
313
314/*
315 * Attempt to map a SysAddr to a node. On success, return a pointer to the
316 * mem_ctl_info structure for the node that the SysAddr maps to.
317 *
318 * On failure, return NULL.
319 */
320static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
321 u64 sys_addr)
322{
323 struct amd64_pvt *pvt;
Daniel J Bluemanc7e53012012-11-30 16:44:20 +0800324 u8 node_id;
Doug Thompson67757632009-04-27 15:53:22 +0200325 u32 intlv_en, bits;
326
327 /*
328 * Here we use the DRAM Base (section 3.4.4.1) and DRAM Limit (section
329 * 3.4.4.2) registers to map the SysAddr to a node ID.
330 */
331 pvt = mci->pvt_info;
332
333 /*
334 * The value of this field should be the same for all DRAM Base
335 * registers. Therefore we arbitrarily choose to read it from the
336 * register for node 0.
337 */
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200338 intlv_en = dram_intlv_en(pvt, 0);
Doug Thompson67757632009-04-27 15:53:22 +0200339
340 if (intlv_en == 0) {
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200341 for (node_id = 0; node_id < DRAM_RANGES; node_id++) {
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100342 if (base_limit_match(pvt, sys_addr, node_id))
Borislav Petkov8edc5442009-09-18 12:39:19 +0200343 goto found;
Doug Thompson67757632009-04-27 15:53:22 +0200344 }
Borislav Petkov8edc5442009-09-18 12:39:19 +0200345 goto err_no_match;
Doug Thompson67757632009-04-27 15:53:22 +0200346 }
347
Borislav Petkov72f158f2009-09-18 12:27:27 +0200348 if (unlikely((intlv_en != 0x01) &&
349 (intlv_en != 0x03) &&
350 (intlv_en != 0x07))) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200351 amd64_warn("DRAM Base[IntlvEn] junk value: 0x%x, BIOS bug?\n", intlv_en);
Doug Thompson67757632009-04-27 15:53:22 +0200352 return NULL;
353 }
354
355 bits = (((u32) sys_addr) >> 12) & intlv_en;
356
357 for (node_id = 0; ; ) {
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200358 if ((dram_intlv_sel(pvt, node_id) & intlv_en) == bits)
Doug Thompson67757632009-04-27 15:53:22 +0200359 break; /* intlv_sel field matches */
360
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200361 if (++node_id >= DRAM_RANGES)
Doug Thompson67757632009-04-27 15:53:22 +0200362 goto err_no_match;
363 }
364
365 /* sanity test for sys_addr */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100366 if (unlikely(!base_limit_match(pvt, sys_addr, node_id))) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200367 amd64_warn("%s: sys_addr 0x%llx falls outside base/limit address"
368 "range for node %d with node interleaving enabled.\n",
369 __func__, sys_addr, node_id);
Doug Thompson67757632009-04-27 15:53:22 +0200370 return NULL;
371 }
372
373found:
Borislav Petkovb487c332011-02-21 18:55:00 +0100374 return edac_mc_find((int)node_id);
Doug Thompson67757632009-04-27 15:53:22 +0200375
376err_no_match:
Joe Perches956b9ba12012-04-29 17:08:39 -0300377 edac_dbg(2, "sys_addr 0x%lx doesn't match any node\n",
378 (unsigned long)sys_addr);
Doug Thompson67757632009-04-27 15:53:22 +0200379
380 return NULL;
381}
Doug Thompsone2ce7252009-04-27 15:57:12 +0200382
383/*
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100384 * compute the CS base address of the @csrow on the DRAM controller @dct.
385 * For details see F2x[5C:40] in the processor's BKDG
Doug Thompsone2ce7252009-04-27 15:57:12 +0200386 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100387static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct,
388 u64 *base, u64 *mask)
Doug Thompsone2ce7252009-04-27 15:57:12 +0200389{
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100390 u64 csbase, csmask, base_bits, mask_bits;
391 u8 addr_shift;
392
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -0500393 if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) {
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100394 csbase = pvt->csels[dct].csbases[csrow];
395 csmask = pvt->csels[dct].csmasks[csrow];
Chen, Gong10ef6b02013-10-18 14:29:07 -0700396 base_bits = GENMASK_ULL(31, 21) | GENMASK_ULL(15, 9);
397 mask_bits = GENMASK_ULL(29, 21) | GENMASK_ULL(15, 9);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100398 addr_shift = 4;
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -0500399
400 /*
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -0500401 * F16h and F15h, models 30h and later need two addr_shift values:
402 * 8 for high and 6 for low (cf. F16h BKDG).
403 */
404 } else if (pvt->fam == 0x16 ||
405 (pvt->fam == 0x15 && pvt->model >= 0x30)) {
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -0500406 csbase = pvt->csels[dct].csbases[csrow];
407 csmask = pvt->csels[dct].csmasks[csrow >> 1];
408
Chen, Gong10ef6b02013-10-18 14:29:07 -0700409 *base = (csbase & GENMASK_ULL(15, 5)) << 6;
410 *base |= (csbase & GENMASK_ULL(30, 19)) << 8;
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -0500411
412 *mask = ~0ULL;
413 /* poke holes for the csmask */
Chen, Gong10ef6b02013-10-18 14:29:07 -0700414 *mask &= ~((GENMASK_ULL(15, 5) << 6) |
415 (GENMASK_ULL(30, 19) << 8));
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -0500416
Chen, Gong10ef6b02013-10-18 14:29:07 -0700417 *mask |= (csmask & GENMASK_ULL(15, 5)) << 6;
418 *mask |= (csmask & GENMASK_ULL(30, 19)) << 8;
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -0500419
420 return;
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100421 } else {
422 csbase = pvt->csels[dct].csbases[csrow];
423 csmask = pvt->csels[dct].csmasks[csrow >> 1];
424 addr_shift = 8;
425
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200426 if (pvt->fam == 0x15)
Chen, Gong10ef6b02013-10-18 14:29:07 -0700427 base_bits = mask_bits =
428 GENMASK_ULL(30,19) | GENMASK_ULL(13,5);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100429 else
Chen, Gong10ef6b02013-10-18 14:29:07 -0700430 base_bits = mask_bits =
431 GENMASK_ULL(28,19) | GENMASK_ULL(13,5);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100432 }
433
434 *base = (csbase & base_bits) << addr_shift;
435
436 *mask = ~0ULL;
437 /* poke holes for the csmask */
438 *mask &= ~(mask_bits << addr_shift);
439 /* OR them in */
440 *mask |= (csmask & mask_bits) << addr_shift;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200441}
442
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100443#define for_each_chip_select(i, dct, pvt) \
444 for (i = 0; i < pvt->csels[dct].b_cnt; i++)
Doug Thompsone2ce7252009-04-27 15:57:12 +0200445
Borislav Petkov614ec9d2011-01-13 18:02:22 +0100446#define chip_select_base(i, dct, pvt) \
447 pvt->csels[dct].csbases[i]
448
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100449#define for_each_chip_select_mask(i, dct, pvt) \
450 for (i = 0; i < pvt->csels[dct].m_cnt; i++)
Doug Thompsone2ce7252009-04-27 15:57:12 +0200451
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +0000452#define for_each_umc(i) \
453 for (i = 0; i < NUM_UMCS; i++)
454
Doug Thompsone2ce7252009-04-27 15:57:12 +0200455/*
456 * @input_addr is an InputAddr associated with the node given by mci. Return the
457 * csrow that input_addr maps to, or -1 on failure (no csrow claims input_addr).
458 */
459static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr)
460{
461 struct amd64_pvt *pvt;
462 int csrow;
463 u64 base, mask;
464
465 pvt = mci->pvt_info;
466
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100467 for_each_chip_select(csrow, 0, pvt) {
468 if (!csrow_enabled(csrow, 0, pvt))
Doug Thompsone2ce7252009-04-27 15:57:12 +0200469 continue;
470
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100471 get_cs_base_and_mask(pvt, csrow, 0, &base, &mask);
472
473 mask = ~mask;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200474
475 if ((input_addr & mask) == (base & mask)) {
Joe Perches956b9ba12012-04-29 17:08:39 -0300476 edac_dbg(2, "InputAddr 0x%lx matches csrow %d (node %d)\n",
477 (unsigned long)input_addr, csrow,
478 pvt->mc_node_id);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200479
480 return csrow;
481 }
482 }
Joe Perches956b9ba12012-04-29 17:08:39 -0300483 edac_dbg(2, "no matching csrow for InputAddr 0x%lx (MC node %d)\n",
484 (unsigned long)input_addr, pvt->mc_node_id);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200485
486 return -1;
487}
488
489/*
Doug Thompsone2ce7252009-04-27 15:57:12 +0200490 * Obtain info from the DRAM Hole Address Register (section 3.4.8, pub #26094)
491 * for the node represented by mci. Info is passed back in *hole_base,
492 * *hole_offset, and *hole_size. Function returns 0 if info is valid or 1 if
493 * info is invalid. Info may be invalid for either of the following reasons:
494 *
495 * - The revision of the node is not E or greater. In this case, the DRAM Hole
496 * Address Register does not exist.
497 *
498 * - The DramHoleValid bit is cleared in the DRAM Hole Address Register,
499 * indicating that its contents are not valid.
500 *
501 * The values passed back in *hole_base, *hole_offset, and *hole_size are
502 * complete 32-bit values despite the fact that the bitfields in the DHAR
503 * only represent bits 31-24 of the base and offset values.
504 */
505int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
506 u64 *hole_offset, u64 *hole_size)
507{
508 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200509
510 /* only revE and later have the DRAM Hole Address Register */
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200511 if (pvt->fam == 0xf && pvt->ext_model < K8_REV_E) {
Joe Perches956b9ba12012-04-29 17:08:39 -0300512 edac_dbg(1, " revision %d for node %d does not support DHAR\n",
513 pvt->ext_model, pvt->mc_node_id);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200514 return 1;
515 }
516
Borislav Petkovbc21fa52010-11-11 17:29:13 +0100517 /* valid for Fam10h and above */
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200518 if (pvt->fam >= 0x10 && !dhar_mem_hoist_valid(pvt)) {
Joe Perches956b9ba12012-04-29 17:08:39 -0300519 edac_dbg(1, " Dram Memory Hoisting is DISABLED on this system\n");
Doug Thompsone2ce7252009-04-27 15:57:12 +0200520 return 1;
521 }
522
Borislav Petkovc8e518d2010-12-10 19:49:19 +0100523 if (!dhar_valid(pvt)) {
Joe Perches956b9ba12012-04-29 17:08:39 -0300524 edac_dbg(1, " Dram Memory Hoisting is DISABLED on this node %d\n",
525 pvt->mc_node_id);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200526 return 1;
527 }
528
529 /* This node has Memory Hoisting */
530
531 /* +------------------+--------------------+--------------------+-----
532 * | memory | DRAM hole | relocated |
533 * | [0, (x - 1)] | [x, 0xffffffff] | addresses from |
534 * | | | DRAM hole |
535 * | | | [0x100000000, |
536 * | | | (0x100000000+ |
537 * | | | (0xffffffff-x))] |
538 * +------------------+--------------------+--------------------+-----
539 *
540 * Above is a diagram of physical memory showing the DRAM hole and the
541 * relocated addresses from the DRAM hole. As shown, the DRAM hole
542 * starts at address x (the base address) and extends through address
543 * 0xffffffff. The DRAM Hole Address Register (DHAR) relocates the
544 * addresses in the hole so that they start at 0x100000000.
545 */
546
Borislav Petkov1f316772012-08-10 12:50:50 +0200547 *hole_base = dhar_base(pvt);
548 *hole_size = (1ULL << 32) - *hole_base;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200549
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200550 *hole_offset = (pvt->fam > 0xf) ? f10_dhar_offset(pvt)
551 : k8_dhar_offset(pvt);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200552
Joe Perches956b9ba12012-04-29 17:08:39 -0300553 edac_dbg(1, " DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx\n",
554 pvt->mc_node_id, (unsigned long)*hole_base,
555 (unsigned long)*hole_offset, (unsigned long)*hole_size);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200556
557 return 0;
558}
559EXPORT_SYMBOL_GPL(amd64_get_dram_hole_info);
560
Doug Thompson93c2df52009-05-04 20:46:50 +0200561/*
562 * Return the DramAddr that the SysAddr given by @sys_addr maps to. It is
563 * assumed that sys_addr maps to the node given by mci.
564 *
565 * The first part of section 3.4.4 (p. 70) shows how the DRAM Base (section
566 * 3.4.4.1) and DRAM Limit (section 3.4.4.2) registers are used to translate a
567 * SysAddr to a DramAddr. If the DRAM Hole Address Register (DHAR) is enabled,
568 * then it is also involved in translating a SysAddr to a DramAddr. Sections
569 * 3.4.8 and 3.5.8.2 describe the DHAR and how it is used for memory hoisting.
570 * These parts of the documentation are unclear. I interpret them as follows:
571 *
572 * When node n receives a SysAddr, it processes the SysAddr as follows:
573 *
574 * 1. It extracts the DRAMBase and DRAMLimit values from the DRAM Base and DRAM
575 * Limit registers for node n. If the SysAddr is not within the range
576 * specified by the base and limit values, then node n ignores the Sysaddr
577 * (since it does not map to node n). Otherwise continue to step 2 below.
578 *
579 * 2. If the DramHoleValid bit of the DHAR for node n is clear, the DHAR is
580 * disabled so skip to step 3 below. Otherwise see if the SysAddr is within
581 * the range of relocated addresses (starting at 0x100000000) from the DRAM
582 * hole. If not, skip to step 3 below. Else get the value of the
583 * DramHoleOffset field from the DHAR. To obtain the DramAddr, subtract the
584 * offset defined by this value from the SysAddr.
585 *
586 * 3. Obtain the base address for node n from the DRAMBase field of the DRAM
587 * Base register for node n. To obtain the DramAddr, subtract the base
588 * address from the SysAddr, as shown near the start of section 3.4.4 (p.70).
589 */
590static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr)
591{
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200592 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompson93c2df52009-05-04 20:46:50 +0200593 u64 dram_base, hole_base, hole_offset, hole_size, dram_addr;
Borislav Petkov1f316772012-08-10 12:50:50 +0200594 int ret;
Doug Thompson93c2df52009-05-04 20:46:50 +0200595
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200596 dram_base = get_dram_base(pvt, pvt->mc_node_id);
Doug Thompson93c2df52009-05-04 20:46:50 +0200597
598 ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
599 &hole_size);
600 if (!ret) {
Borislav Petkov1f316772012-08-10 12:50:50 +0200601 if ((sys_addr >= (1ULL << 32)) &&
602 (sys_addr < ((1ULL << 32) + hole_size))) {
Doug Thompson93c2df52009-05-04 20:46:50 +0200603 /* use DHAR to translate SysAddr to DramAddr */
604 dram_addr = sys_addr - hole_offset;
605
Joe Perches956b9ba12012-04-29 17:08:39 -0300606 edac_dbg(2, "using DHAR to translate SysAddr 0x%lx to DramAddr 0x%lx\n",
607 (unsigned long)sys_addr,
608 (unsigned long)dram_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200609
610 return dram_addr;
611 }
612 }
613
614 /*
615 * Translate the SysAddr to a DramAddr as shown near the start of
616 * section 3.4.4 (p. 70). Although sys_addr is a 64-bit value, the k8
617 * only deals with 40-bit values. Therefore we discard bits 63-40 of
618 * sys_addr below. If bit 39 of sys_addr is 1 then the bits we
619 * discard are all 1s. Otherwise the bits we discard are all 0s. See
620 * section 3.4.2 of AMD publication 24592: AMD x86-64 Architecture
621 * Programmer's Manual Volume 1 Application Programming.
622 */
Chen, Gong10ef6b02013-10-18 14:29:07 -0700623 dram_addr = (sys_addr & GENMASK_ULL(39, 0)) - dram_base;
Doug Thompson93c2df52009-05-04 20:46:50 +0200624
Joe Perches956b9ba12012-04-29 17:08:39 -0300625 edac_dbg(2, "using DRAM Base register to translate SysAddr 0x%lx to DramAddr 0x%lx\n",
626 (unsigned long)sys_addr, (unsigned long)dram_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200627 return dram_addr;
628}
629
630/*
631 * @intlv_en is the value of the IntlvEn field from a DRAM Base register
632 * (section 3.4.4.1). Return the number of bits from a SysAddr that are used
633 * for node interleaving.
634 */
635static int num_node_interleave_bits(unsigned intlv_en)
636{
637 static const int intlv_shift_table[] = { 0, 1, 0, 2, 0, 0, 0, 3 };
638 int n;
639
640 BUG_ON(intlv_en > 7);
641 n = intlv_shift_table[intlv_en];
642 return n;
643}
644
645/* Translate the DramAddr given by @dram_addr to an InputAddr. */
646static u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr)
647{
648 struct amd64_pvt *pvt;
649 int intlv_shift;
650 u64 input_addr;
651
652 pvt = mci->pvt_info;
653
654 /*
655 * See the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E)
656 * concerning translating a DramAddr to an InputAddr.
657 */
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200658 intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0));
Chen, Gong10ef6b02013-10-18 14:29:07 -0700659 input_addr = ((dram_addr >> intlv_shift) & GENMASK_ULL(35, 12)) +
Borislav Petkovf678b8c2010-12-13 19:21:07 +0100660 (dram_addr & 0xfff);
Doug Thompson93c2df52009-05-04 20:46:50 +0200661
Joe Perches956b9ba12012-04-29 17:08:39 -0300662 edac_dbg(2, " Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n",
663 intlv_shift, (unsigned long)dram_addr,
664 (unsigned long)input_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200665
666 return input_addr;
667}
668
669/*
670 * Translate the SysAddr represented by @sys_addr to an InputAddr. It is
671 * assumed that @sys_addr maps to the node given by mci.
672 */
673static u64 sys_addr_to_input_addr(struct mem_ctl_info *mci, u64 sys_addr)
674{
675 u64 input_addr;
676
677 input_addr =
678 dram_addr_to_input_addr(mci, sys_addr_to_dram_addr(mci, sys_addr));
679
Masanari Iidac19ca6c2016-02-08 20:53:12 +0900680 edac_dbg(2, "SysAddr 0x%lx translates to InputAddr 0x%lx\n",
Joe Perches956b9ba12012-04-29 17:08:39 -0300681 (unsigned long)sys_addr, (unsigned long)input_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200682
683 return input_addr;
684}
685
Doug Thompson93c2df52009-05-04 20:46:50 +0200686/* Map the Error address to a PAGE and PAGE OFFSET. */
687static inline void error_address_to_page_and_offset(u64 error_address,
Borislav Petkov33ca0642012-08-30 18:01:36 +0200688 struct err_info *err)
Doug Thompson93c2df52009-05-04 20:46:50 +0200689{
Borislav Petkov33ca0642012-08-30 18:01:36 +0200690 err->page = (u32) (error_address >> PAGE_SHIFT);
691 err->offset = ((u32) error_address) & ~PAGE_MASK;
Doug Thompson93c2df52009-05-04 20:46:50 +0200692}
693
694/*
695 * @sys_addr is an error address (a SysAddr) extracted from the MCA NB Address
696 * Low (section 3.6.4.5) and MCA NB Address High (section 3.6.4.6) registers
697 * of a node that detected an ECC memory error. mci represents the node that
698 * the error address maps to (possibly different from the node that detected
699 * the error). Return the number of the csrow that sys_addr maps to, or -1 on
700 * error.
701 */
702static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr)
703{
704 int csrow;
705
706 csrow = input_addr_to_csrow(mci, sys_addr_to_input_addr(mci, sys_addr));
707
708 if (csrow == -1)
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200709 amd64_mc_err(mci, "Failed to translate InputAddr to csrow for "
710 "address 0x%lx\n", (unsigned long)sys_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200711 return csrow;
712}
Doug Thompsone2ce7252009-04-27 15:57:12 +0200713
Borislav Petkovbfc04ae2009-11-12 19:05:07 +0100714static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);
Doug Thompson2da11652009-04-27 16:09:09 +0200715
Doug Thompson2da11652009-04-27 16:09:09 +0200716/*
717 * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs
718 * are ECC capable.
719 */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100720static unsigned long determine_edac_cap(struct amd64_pvt *pvt)
Doug Thompson2da11652009-04-27 16:09:09 +0200721{
Dan Carpenter1f6189e2011-10-06 02:30:25 -0400722 unsigned long edac_cap = EDAC_FLAG_NONE;
Yazen Ghannamd27f3a32016-11-17 17:57:40 -0500723 u8 bit;
Doug Thompson2da11652009-04-27 16:09:09 +0200724
Yazen Ghannamd27f3a32016-11-17 17:57:40 -0500725 if (pvt->umc) {
726 u8 i, umc_en_mask = 0, dimm_ecc_en_mask = 0;
Doug Thompson2da11652009-04-27 16:09:09 +0200727
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +0000728 for_each_umc(i) {
Yazen Ghannamd27f3a32016-11-17 17:57:40 -0500729 if (!(pvt->umc[i].sdp_ctrl & UMC_SDP_INIT))
730 continue;
731
732 umc_en_mask |= BIT(i);
733
734 /* UMC Configuration bit 12 (DimmEccEn) */
735 if (pvt->umc[i].umc_cfg & BIT(12))
736 dimm_ecc_en_mask |= BIT(i);
737 }
738
739 if (umc_en_mask == dimm_ecc_en_mask)
740 edac_cap = EDAC_FLAG_SECDED;
741 } else {
742 bit = (pvt->fam > 0xf || pvt->ext_model >= K8_REV_F)
743 ? 19
744 : 17;
745
746 if (pvt->dclr0 & BIT(bit))
747 edac_cap = EDAC_FLAG_SECDED;
748 }
Doug Thompson2da11652009-04-27 16:09:09 +0200749
750 return edac_cap;
751}
752
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100753static void debug_display_dimm_sizes(struct amd64_pvt *, u8);
Doug Thompson2da11652009-04-27 16:09:09 +0200754
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100755static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan)
Borislav Petkov68798e12009-11-03 16:18:33 +0100756{
Joe Perches956b9ba12012-04-29 17:08:39 -0300757 edac_dbg(1, "F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr);
Borislav Petkov68798e12009-11-03 16:18:33 +0100758
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +0100759 if (pvt->dram_type == MEM_LRDDR3) {
760 u32 dcsm = pvt->csels[chan].csmasks[0];
761 /*
762 * It's assumed all LRDIMMs in a DCT are going to be of
763 * same 'type' until proven otherwise. So, use a cs
764 * value of '0' here to get dcsm value.
765 */
766 edac_dbg(1, " LRDIMM %dx rank multiply\n", (dcsm & 0x3));
767 }
768
769 edac_dbg(1, "All DIMMs support ECC:%s\n",
770 (dclr & BIT(19)) ? "yes" : "no");
771
Borislav Petkov68798e12009-11-03 16:18:33 +0100772
Joe Perches956b9ba12012-04-29 17:08:39 -0300773 edac_dbg(1, " PAR/ERR parity: %s\n",
774 (dclr & BIT(8)) ? "enabled" : "disabled");
Borislav Petkov68798e12009-11-03 16:18:33 +0100775
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200776 if (pvt->fam == 0x10)
Joe Perches956b9ba12012-04-29 17:08:39 -0300777 edac_dbg(1, " DCT 128bit mode width: %s\n",
778 (dclr & BIT(11)) ? "128b" : "64b");
Borislav Petkov68798e12009-11-03 16:18:33 +0100779
Joe Perches956b9ba12012-04-29 17:08:39 -0300780 edac_dbg(1, " x4 logical DIMMs present: L0: %s L1: %s L2: %s L3: %s\n",
781 (dclr & BIT(12)) ? "yes" : "no",
782 (dclr & BIT(13)) ? "yes" : "no",
783 (dclr & BIT(14)) ? "yes" : "no",
784 (dclr & BIT(15)) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100785}
786
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600787static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl)
788{
Yazen Ghannameb77e6b2017-04-27 12:11:54 -0500789 int dimm, size0, size1, cs0, cs1;
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600790
791 edac_printk(KERN_DEBUG, EDAC_MC, "UMC%d chip selects:\n", ctrl);
792
793 for (dimm = 0; dimm < 4; dimm++) {
794 size0 = 0;
Yazen Ghannameb77e6b2017-04-27 12:11:54 -0500795 cs0 = dimm * 2;
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600796
Yazen Ghannameb77e6b2017-04-27 12:11:54 -0500797 if (csrow_enabled(cs0, ctrl, pvt))
798 size0 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, cs0);
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600799
800 size1 = 0;
Yazen Ghannameb77e6b2017-04-27 12:11:54 -0500801 cs1 = dimm * 2 + 1;
802
803 if (csrow_enabled(cs1, ctrl, pvt))
804 size1 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, cs1);
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600805
806 amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
Yazen Ghannameb77e6b2017-04-27 12:11:54 -0500807 cs0, size0,
808 cs1, size1);
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600809 }
810}
811
812static void __dump_misc_regs_df(struct amd64_pvt *pvt)
813{
814 struct amd64_umc *umc;
815 u32 i, tmp, umc_base;
816
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +0000817 for_each_umc(i) {
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600818 umc_base = get_umc_base(i);
819 umc = &pvt->umc[i];
820
821 edac_dbg(1, "UMC%d DIMM cfg: 0x%x\n", i, umc->dimm_cfg);
822 edac_dbg(1, "UMC%d UMC cfg: 0x%x\n", i, umc->umc_cfg);
823 edac_dbg(1, "UMC%d SDP ctrl: 0x%x\n", i, umc->sdp_ctrl);
824 edac_dbg(1, "UMC%d ECC ctrl: 0x%x\n", i, umc->ecc_ctrl);
825
826 amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_ECC_BAD_SYMBOL, &tmp);
827 edac_dbg(1, "UMC%d ECC bad symbol: 0x%x\n", i, tmp);
828
829 amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_UMC_CAP, &tmp);
830 edac_dbg(1, "UMC%d UMC cap: 0x%x\n", i, tmp);
831 edac_dbg(1, "UMC%d UMC cap high: 0x%x\n", i, umc->umc_cap_hi);
832
833 edac_dbg(1, "UMC%d ECC capable: %s, ChipKill ECC capable: %s\n",
834 i, (umc->umc_cap_hi & BIT(30)) ? "yes" : "no",
835 (umc->umc_cap_hi & BIT(31)) ? "yes" : "no");
836 edac_dbg(1, "UMC%d All DIMMs support ECC: %s\n",
837 i, (umc->umc_cfg & BIT(12)) ? "yes" : "no");
838 edac_dbg(1, "UMC%d x4 DIMMs present: %s\n",
839 i, (umc->dimm_cfg & BIT(6)) ? "yes" : "no");
840 edac_dbg(1, "UMC%d x16 DIMMs present: %s\n",
841 i, (umc->dimm_cfg & BIT(7)) ? "yes" : "no");
842
843 if (pvt->dram_type == MEM_LRDDR4) {
844 amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_ADDR_CFG, &tmp);
845 edac_dbg(1, "UMC%d LRDIMM %dx rank multiply\n",
846 i, 1 << ((tmp >> 4) & 0x3));
847 }
848
849 debug_display_dimm_sizes_df(pvt, i);
850 }
851
852 edac_dbg(1, "F0x104 (DRAM Hole Address): 0x%08x, base: 0x%08x\n",
853 pvt->dhar, dhar_base(pvt));
854}
855
Doug Thompson2da11652009-04-27 16:09:09 +0200856/* Display and decode various NB registers for debug purposes. */
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600857static void __dump_misc_regs(struct amd64_pvt *pvt)
Doug Thompson2da11652009-04-27 16:09:09 +0200858{
Joe Perches956b9ba12012-04-29 17:08:39 -0300859 edac_dbg(1, "F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap);
Doug Thompson2da11652009-04-27 16:09:09 +0200860
Joe Perches956b9ba12012-04-29 17:08:39 -0300861 edac_dbg(1, " NB two channel DRAM capable: %s\n",
862 (pvt->nbcap & NBCAP_DCT_DUAL) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100863
Joe Perches956b9ba12012-04-29 17:08:39 -0300864 edac_dbg(1, " ECC capable: %s, ChipKill ECC capable: %s\n",
865 (pvt->nbcap & NBCAP_SECDED) ? "yes" : "no",
866 (pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100867
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100868 debug_dump_dramcfg_low(pvt, pvt->dclr0, 0);
Doug Thompson2da11652009-04-27 16:09:09 +0200869
Joe Perches956b9ba12012-04-29 17:08:39 -0300870 edac_dbg(1, "F3xB0 (Online Spare): 0x%08x\n", pvt->online_spare);
Doug Thompson2da11652009-04-27 16:09:09 +0200871
Joe Perches956b9ba12012-04-29 17:08:39 -0300872 edac_dbg(1, "F1xF0 (DRAM Hole Address): 0x%08x, base: 0x%08x, offset: 0x%08x\n",
873 pvt->dhar, dhar_base(pvt),
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200874 (pvt->fam == 0xf) ? k8_dhar_offset(pvt)
875 : f10_dhar_offset(pvt));
Doug Thompson2da11652009-04-27 16:09:09 +0200876
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100877 debug_display_dimm_sizes(pvt, 0);
Borislav Petkov4d796362011-02-03 15:59:57 +0100878
Borislav Petkov8de1d912009-10-16 13:39:30 +0200879 /* everything below this point is Fam10h and above */
Borislav Petkova4b4bed2013-08-10 13:54:48 +0200880 if (pvt->fam == 0xf)
Doug Thompson2da11652009-04-27 16:09:09 +0200881 return;
Borislav Petkov4d796362011-02-03 15:59:57 +0100882
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100883 debug_display_dimm_sizes(pvt, 1);
Doug Thompson2da11652009-04-27 16:09:09 +0200884
Borislav Petkov8de1d912009-10-16 13:39:30 +0200885 /* Only if NOT ganged does dclr1 have valid info */
Borislav Petkov68798e12009-11-03 16:18:33 +0100886 if (!dct_ganging_enabled(pvt))
Borislav Petkovd1ea71c2013-12-15 17:54:27 +0100887 debug_dump_dramcfg_low(pvt, pvt->dclr1, 1);
Doug Thompson2da11652009-04-27 16:09:09 +0200888}
889
Yazen Ghannam07ed82e2016-11-28 08:50:21 -0600890/* Display and decode various NB registers for debug purposes. */
891static void dump_misc_regs(struct amd64_pvt *pvt)
892{
893 if (pvt->umc)
894 __dump_misc_regs_df(pvt);
895 else
896 __dump_misc_regs(pvt);
897
898 edac_dbg(1, " DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no");
899
900 amd64_info("using %s syndromes.\n",
901 ((pvt->ecc_sym_sz == 8) ? "x8" : "x4"));
902}
903
Doug Thompson94be4bf2009-04-27 16:12:00 +0200904/*
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -0500905 * See BKDG, F2x[1,0][5C:40], F2[1,0][6C:60]
Doug Thompson94be4bf2009-04-27 16:12:00 +0200906 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100907static void prep_chip_selects(struct amd64_pvt *pvt)
Doug Thompson94be4bf2009-04-27 16:12:00 +0200908{
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -0500909 if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) {
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 = 8;
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +0100912 } else if (pvt->fam == 0x15 && pvt->model == 0x30) {
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -0500913 pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4;
914 pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2;
Borislav Petkov9d858bb2009-09-21 14:35:51 +0200915 } else {
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100916 pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
917 pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4;
Doug Thompson94be4bf2009-04-27 16:12:00 +0200918 }
919}
920
921/*
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100922 * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers
Doug Thompson94be4bf2009-04-27 16:12:00 +0200923 */
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200924static void read_dct_base_mask(struct amd64_pvt *pvt)
Doug Thompson94be4bf2009-04-27 16:12:00 +0200925{
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500926 int base_reg0, base_reg1, mask_reg0, mask_reg1, cs;
Doug Thompson94be4bf2009-04-27 16:12:00 +0200927
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100928 prep_chip_selects(pvt);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200929
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500930 if (pvt->umc) {
931 base_reg0 = get_umc_base(0) + UMCCH_BASE_ADDR;
932 base_reg1 = get_umc_base(1) + UMCCH_BASE_ADDR;
933 mask_reg0 = get_umc_base(0) + UMCCH_ADDR_MASK;
934 mask_reg1 = get_umc_base(1) + UMCCH_ADDR_MASK;
935 } else {
936 base_reg0 = DCSB0;
937 base_reg1 = DCSB1;
938 mask_reg0 = DCSM0;
939 mask_reg1 = DCSM1;
940 }
941
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100942 for_each_chip_select(cs, 0, pvt) {
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500943 int reg0 = base_reg0 + (cs * 4);
944 int reg1 = base_reg1 + (cs * 4);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100945 u32 *base0 = &pvt->csels[0].csbases[cs];
946 u32 *base1 = &pvt->csels[1].csbases[cs];
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200947
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500948 if (pvt->umc) {
949 if (!amd_smn_read(pvt->mc_node_id, reg0, base0))
950 edac_dbg(0, " DCSB0[%d]=0x%08x reg: 0x%x\n",
951 cs, *base0, reg0);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200952
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500953 if (!amd_smn_read(pvt->mc_node_id, reg1, base1))
954 edac_dbg(0, " DCSB1[%d]=0x%08x reg: 0x%x\n",
955 cs, *base1, reg1);
956 } else {
957 if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, base0))
958 edac_dbg(0, " DCSB0[%d]=0x%08x reg: F2x%x\n",
959 cs, *base0, reg0);
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200960
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500961 if (pvt->fam == 0xf)
962 continue;
963
964 if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, base1))
965 edac_dbg(0, " DCSB1[%d]=0x%08x reg: F2x%x\n",
966 cs, *base1, (pvt->fam == 0x10) ? reg1
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -0500967 : reg0);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500968 }
Doug Thompson94be4bf2009-04-27 16:12:00 +0200969 }
970
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100971 for_each_chip_select_mask(cs, 0, pvt) {
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500972 int reg0 = mask_reg0 + (cs * 4);
973 int reg1 = mask_reg1 + (cs * 4);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100974 u32 *mask0 = &pvt->csels[0].csmasks[cs];
975 u32 *mask1 = &pvt->csels[1].csmasks[cs];
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200976
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500977 if (pvt->umc) {
978 if (!amd_smn_read(pvt->mc_node_id, reg0, mask0))
979 edac_dbg(0, " DCSM0[%d]=0x%08x reg: 0x%x\n",
980 cs, *mask0, reg0);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200981
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500982 if (!amd_smn_read(pvt->mc_node_id, reg1, mask1))
983 edac_dbg(0, " DCSM1[%d]=0x%08x reg: 0x%x\n",
984 cs, *mask1, reg1);
985 } else {
986 if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, mask0))
987 edac_dbg(0, " DCSM0[%d]=0x%08x reg: F2x%x\n",
988 cs, *mask0, reg0);
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200989
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500990 if (pvt->fam == 0xf)
991 continue;
992
993 if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, mask1))
994 edac_dbg(0, " DCSM1[%d]=0x%08x reg: F2x%x\n",
995 cs, *mask1, (pvt->fam == 0x10) ? reg1
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -0500996 : reg0);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -0500997 }
Doug Thompson94be4bf2009-04-27 16:12:00 +0200998 }
999}
1000
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001001static void determine_memory_type(struct amd64_pvt *pvt)
Doug Thompson94be4bf2009-04-27 16:12:00 +02001002{
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001003 u32 dram_ctrl, dcsm;
Doug Thompson94be4bf2009-04-27 16:12:00 +02001004
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001005 switch (pvt->fam) {
1006 case 0xf:
1007 if (pvt->ext_model >= K8_REV_F)
1008 goto ddr3;
1009
1010 pvt->dram_type = (pvt->dclr0 & BIT(18)) ? MEM_DDR : MEM_RDDR;
1011 return;
1012
1013 case 0x10:
Borislav Petkov6b4c0bd2009-11-12 15:37:57 +01001014 if (pvt->dchr0 & DDR3_MODE)
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001015 goto ddr3;
1016
1017 pvt->dram_type = (pvt->dclr0 & BIT(16)) ? MEM_DDR2 : MEM_RDDR2;
1018 return;
1019
1020 case 0x15:
1021 if (pvt->model < 0x60)
1022 goto ddr3;
1023
1024 /*
1025 * Model 0x60h needs special handling:
1026 *
1027 * We use a Chip Select value of '0' to obtain dcsm.
1028 * Theoretically, it is possible to populate LRDIMMs of different
1029 * 'Rank' value on a DCT. But this is not the common case. So,
1030 * it's reasonable to assume all DIMMs are going to be of same
1031 * 'type' until proven otherwise.
1032 */
1033 amd64_read_dct_pci_cfg(pvt, 0, DRAM_CONTROL, &dram_ctrl);
1034 dcsm = pvt->csels[0].csmasks[0];
1035
1036 if (((dram_ctrl >> 8) & 0x7) == 0x2)
1037 pvt->dram_type = MEM_DDR4;
1038 else if (pvt->dclr0 & BIT(16))
1039 pvt->dram_type = MEM_DDR3;
1040 else if (dcsm & 0x3)
1041 pvt->dram_type = MEM_LRDDR3;
Borislav Petkov6b4c0bd2009-11-12 15:37:57 +01001042 else
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001043 pvt->dram_type = MEM_RDDR3;
1044
1045 return;
1046
1047 case 0x16:
1048 goto ddr3;
1049
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05001050 case 0x17:
Pu Wenc4a3e942018-09-27 16:31:28 +02001051 case 0x18:
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05001052 if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(5))
1053 pvt->dram_type = MEM_LRDDR4;
1054 else if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(4))
1055 pvt->dram_type = MEM_RDDR4;
1056 else
1057 pvt->dram_type = MEM_DDR4;
1058 return;
1059
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001060 default:
1061 WARN(1, KERN_ERR "%s: Family??? 0x%x\n", __func__, pvt->fam);
1062 pvt->dram_type = MEM_EMPTY;
Doug Thompson94be4bf2009-04-27 16:12:00 +02001063 }
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001064 return;
Doug Thompson94be4bf2009-04-27 16:12:00 +02001065
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001066ddr3:
1067 pvt->dram_type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3;
Doug Thompson94be4bf2009-04-27 16:12:00 +02001068}
1069
Borislav Petkovcb328502010-12-22 14:28:24 +01001070/* Get the number of DCT channels the memory controller is using. */
Doug Thompsonddff8762009-04-27 16:14:52 +02001071static int k8_early_channel_count(struct amd64_pvt *pvt)
1072{
Borislav Petkovcb328502010-12-22 14:28:24 +01001073 int flag;
Doug Thompsonddff8762009-04-27 16:14:52 +02001074
Borislav Petkov9f56da02010-10-01 19:44:53 +02001075 if (pvt->ext_model >= K8_REV_F)
Doug Thompsonddff8762009-04-27 16:14:52 +02001076 /* RevF (NPT) and later */
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001077 flag = pvt->dclr0 & WIDTH_128;
Borislav Petkov9f56da02010-10-01 19:44:53 +02001078 else
Doug Thompsonddff8762009-04-27 16:14:52 +02001079 /* RevE and earlier */
1080 flag = pvt->dclr0 & REVE_WIDTH_128;
Doug Thompsonddff8762009-04-27 16:14:52 +02001081
1082 /* not used */
1083 pvt->dclr1 = 0;
1084
1085 return (flag) ? 2 : 1;
1086}
1087
Borislav Petkov70046622011-01-10 14:37:27 +01001088/* On F10h and later ErrAddr is MC4_ADDR[47:1] */
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001089static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m)
Doug Thompsonddff8762009-04-27 16:14:52 +02001090{
Borislav Petkov2ec591a2015-02-17 10:58:34 +01001091 u16 mce_nid = amd_get_nb_id(m->extcpu);
1092 struct mem_ctl_info *mci;
Borislav Petkov70046622011-01-10 14:37:27 +01001093 u8 start_bit = 1;
1094 u8 end_bit = 47;
Borislav Petkov2ec591a2015-02-17 10:58:34 +01001095 u64 addr;
1096
1097 mci = edac_mc_find(mce_nid);
1098 if (!mci)
1099 return 0;
1100
1101 pvt = mci->pvt_info;
Borislav Petkov70046622011-01-10 14:37:27 +01001102
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001103 if (pvt->fam == 0xf) {
Borislav Petkov70046622011-01-10 14:37:27 +01001104 start_bit = 3;
1105 end_bit = 39;
1106 }
1107
Chen, Gong10ef6b02013-10-18 14:29:07 -07001108 addr = m->addr & GENMASK_ULL(end_bit, start_bit);
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001109
1110 /*
1111 * Erratum 637 workaround
1112 */
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001113 if (pvt->fam == 0x15) {
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001114 u64 cc6_base, tmp_addr;
1115 u32 tmp;
Daniel J Blueman8b84c8d2012-11-27 14:32:10 +08001116 u8 intlv_en;
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001117
Chen, Gong10ef6b02013-10-18 14:29:07 -07001118 if ((addr & GENMASK_ULL(47, 24)) >> 24 != 0x00fdf7)
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001119 return addr;
1120
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001121
1122 amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_LIM, &tmp);
1123 intlv_en = tmp >> 21 & 0x7;
1124
1125 /* add [47:27] + 3 trailing bits */
Chen, Gong10ef6b02013-10-18 14:29:07 -07001126 cc6_base = (tmp & GENMASK_ULL(20, 0)) << 3;
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001127
1128 /* reverse and add DramIntlvEn */
1129 cc6_base |= intlv_en ^ 0x7;
1130
1131 /* pin at [47:24] */
1132 cc6_base <<= 24;
1133
1134 if (!intlv_en)
Chen, Gong10ef6b02013-10-18 14:29:07 -07001135 return cc6_base | (addr & GENMASK_ULL(23, 0));
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001136
1137 amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_BASE, &tmp);
1138
1139 /* faster log2 */
Chen, Gong10ef6b02013-10-18 14:29:07 -07001140 tmp_addr = (addr & GENMASK_ULL(23, 12)) << __fls(intlv_en + 1);
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001141
1142 /* OR DramIntlvSel into bits [14:12] */
Chen, Gong10ef6b02013-10-18 14:29:07 -07001143 tmp_addr |= (tmp & GENMASK_ULL(23, 21)) >> 9;
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001144
1145 /* add remaining [11:0] bits from original MC4_ADDR */
Chen, Gong10ef6b02013-10-18 14:29:07 -07001146 tmp_addr |= addr & GENMASK_ULL(11, 0);
Borislav Petkovc1ae6832011-03-30 15:42:10 +02001147
1148 return cc6_base | tmp_addr;
1149 }
1150
1151 return addr;
Doug Thompsonddff8762009-04-27 16:14:52 +02001152}
1153
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001154static struct pci_dev *pci_get_related_function(unsigned int vendor,
1155 unsigned int device,
1156 struct pci_dev *related)
1157{
1158 struct pci_dev *dev = NULL;
1159
1160 while ((dev = pci_get_device(vendor, device, dev))) {
1161 if (pci_domain_nr(dev->bus) == pci_domain_nr(related->bus) &&
1162 (dev->bus->number == related->bus->number) &&
1163 (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
1164 break;
1165 }
1166
1167 return dev;
1168}
1169
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001170static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
Doug Thompsonddff8762009-04-27 16:14:52 +02001171{
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001172 struct amd_northbridge *nb;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001173 struct pci_dev *f1 = NULL;
1174 unsigned int pci_func;
Borislav Petkov71d2a322011-02-21 19:37:24 +01001175 int off = range << 3;
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001176 u32 llim;
Doug Thompsonddff8762009-04-27 16:14:52 +02001177
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001178 amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo);
1179 amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
Doug Thompsonddff8762009-04-27 16:14:52 +02001180
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001181 if (pvt->fam == 0xf)
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001182 return;
Doug Thompsonddff8762009-04-27 16:14:52 +02001183
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001184 if (!dram_rw(pvt, range))
1185 return;
Doug Thompsonddff8762009-04-27 16:14:52 +02001186
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001187 amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi);
1188 amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
Borislav Petkovf08e4572011-03-21 20:45:06 +01001189
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001190 /* F15h: factor in CC6 save area by reading dst node's limit reg */
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001191 if (pvt->fam != 0x15)
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001192 return;
Borislav Petkovf08e4572011-03-21 20:45:06 +01001193
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001194 nb = node_to_amd_nb(dram_dst_node(pvt, range));
1195 if (WARN_ON(!nb))
1196 return;
Borislav Petkovf08e4572011-03-21 20:45:06 +01001197
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001198 if (pvt->model == 0x60)
1199 pci_func = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1;
1200 else if (pvt->model == 0x30)
1201 pci_func = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1;
1202 else
1203 pci_func = PCI_DEVICE_ID_AMD_15H_NB_F1;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001204
1205 f1 = pci_get_related_function(nb->misc->vendor, pci_func, nb->misc);
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001206 if (WARN_ON(!f1))
1207 return;
Borislav Petkovf08e4572011-03-21 20:45:06 +01001208
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001209 amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
Borislav Petkovf08e4572011-03-21 20:45:06 +01001210
Chen, Gong10ef6b02013-10-18 14:29:07 -07001211 pvt->ranges[range].lim.lo &= GENMASK_ULL(15, 0);
Borislav Petkovf08e4572011-03-21 20:45:06 +01001212
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001213 /* {[39:27],111b} */
1214 pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
Borislav Petkovf08e4572011-03-21 20:45:06 +01001215
Chen, Gong10ef6b02013-10-18 14:29:07 -07001216 pvt->ranges[range].lim.hi &= GENMASK_ULL(7, 0);
Borislav Petkovf08e4572011-03-21 20:45:06 +01001217
Daniel J Bluemane2c0bff2012-11-30 16:44:19 +08001218 /* [47:40] */
1219 pvt->ranges[range].lim.hi |= llim >> 13;
1220
1221 pci_dev_put(f1);
Doug Thompsonddff8762009-04-27 16:14:52 +02001222}
1223
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001224static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
Borislav Petkov33ca0642012-08-30 18:01:36 +02001225 struct err_info *err)
Doug Thompsonddff8762009-04-27 16:14:52 +02001226{
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001227 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompsonddff8762009-04-27 16:14:52 +02001228
Borislav Petkov33ca0642012-08-30 18:01:36 +02001229 error_address_to_page_and_offset(sys_addr, err);
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001230
1231 /*
1232 * Find out which node the error address belongs to. This may be
1233 * different from the node that detected the error.
1234 */
Borislav Petkov33ca0642012-08-30 18:01:36 +02001235 err->src_mci = find_mc_by_sys_addr(mci, sys_addr);
1236 if (!err->src_mci) {
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001237 amd64_mc_err(mci, "failed to map error addr 0x%lx to a node\n",
1238 (unsigned long)sys_addr);
Borislav Petkov33ca0642012-08-30 18:01:36 +02001239 err->err_code = ERR_NODE;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001240 return;
1241 }
1242
1243 /* Now map the sys_addr to a CSROW */
Borislav Petkov33ca0642012-08-30 18:01:36 +02001244 err->csrow = sys_addr_to_csrow(err->src_mci, sys_addr);
1245 if (err->csrow < 0) {
1246 err->err_code = ERR_CSROW;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001247 return;
1248 }
1249
Doug Thompsonddff8762009-04-27 16:14:52 +02001250 /* CHIPKILL enabled */
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001251 if (pvt->nbcfg & NBCFG_CHIPKILL) {
Borislav Petkov33ca0642012-08-30 18:01:36 +02001252 err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome);
1253 if (err->channel < 0) {
Doug Thompsonddff8762009-04-27 16:14:52 +02001254 /*
1255 * Syndrome didn't map, so we don't know which of the
1256 * 2 DIMMs is in error. So we need to ID 'both' of them
1257 * as suspect.
1258 */
Borislav Petkov33ca0642012-08-30 18:01:36 +02001259 amd64_mc_warn(err->src_mci, "unknown syndrome 0x%04x - "
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001260 "possible error reporting race\n",
Borislav Petkov33ca0642012-08-30 18:01:36 +02001261 err->syndrome);
1262 err->err_code = ERR_CHANNEL;
Doug Thompsonddff8762009-04-27 16:14:52 +02001263 return;
1264 }
1265 } else {
1266 /*
1267 * non-chipkill ecc mode
1268 *
1269 * The k8 documentation is unclear about how to determine the
1270 * channel number when using non-chipkill memory. This method
1271 * was obtained from email communication with someone at AMD.
1272 * (Wish the email was placed in this comment - norsk)
1273 */
Borislav Petkov33ca0642012-08-30 18:01:36 +02001274 err->channel = ((sys_addr & BIT(3)) != 0);
Doug Thompsonddff8762009-04-27 16:14:52 +02001275 }
Doug Thompsonddff8762009-04-27 16:14:52 +02001276}
1277
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001278static int ddr2_cs_size(unsigned i, bool dct_width)
Doug Thompsonddff8762009-04-27 16:14:52 +02001279{
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001280 unsigned shift = 0;
Doug Thompsonddff8762009-04-27 16:14:52 +02001281
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001282 if (i <= 2)
1283 shift = i;
1284 else if (!(i & 0x1))
1285 shift = i >> 1;
Borislav Petkov1433eb92009-10-21 13:44:36 +02001286 else
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001287 shift = (i + 1) >> 1;
Doug Thompsonddff8762009-04-27 16:14:52 +02001288
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001289 return 128 << (shift + !!dct_width);
1290}
1291
1292static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001293 unsigned cs_mode, int cs_mask_nr)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001294{
1295 u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
1296
1297 if (pvt->ext_model >= K8_REV_F) {
1298 WARN_ON(cs_mode > 11);
1299 return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
1300 }
1301 else if (pvt->ext_model >= K8_REV_D) {
Borislav Petkov11b0a312011-11-09 21:28:43 +01001302 unsigned diff;
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001303 WARN_ON(cs_mode > 10);
1304
Borislav Petkov11b0a312011-11-09 21:28:43 +01001305 /*
1306 * the below calculation, besides trying to win an obfuscated C
1307 * contest, maps cs_mode values to DIMM chip select sizes. The
1308 * mappings are:
1309 *
1310 * cs_mode CS size (mb)
1311 * ======= ============
1312 * 0 32
1313 * 1 64
1314 * 2 128
1315 * 3 128
1316 * 4 256
1317 * 5 512
1318 * 6 256
1319 * 7 512
1320 * 8 1024
1321 * 9 1024
1322 * 10 2048
1323 *
1324 * Basically, it calculates a value with which to shift the
1325 * smallest CS size of 32MB.
1326 *
1327 * ddr[23]_cs_size have a similar purpose.
1328 */
1329 diff = cs_mode/3 + (unsigned)(cs_mode > 5);
1330
1331 return 32 << (cs_mode - diff);
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001332 }
1333 else {
1334 WARN_ON(cs_mode > 6);
1335 return 32 << cs_mode;
1336 }
Doug Thompsonddff8762009-04-27 16:14:52 +02001337}
1338
Doug Thompson1afd3c92009-04-27 16:16:50 +02001339/*
1340 * Get the number of DCT channels in use.
1341 *
1342 * Return:
1343 * number of Memory Channels in operation
1344 * Pass back:
1345 * contents of the DCL0_LOW register
1346 */
Borislav Petkov7d20d142011-01-07 17:58:04 +01001347static int f1x_early_channel_count(struct amd64_pvt *pvt)
Doug Thompson1afd3c92009-04-27 16:16:50 +02001348{
Borislav Petkov6ba5dcd2009-10-13 19:26:55 +02001349 int i, j, channels = 0;
Doug Thompsonddff8762009-04-27 16:14:52 +02001350
Borislav Petkov7d20d142011-01-07 17:58:04 +01001351 /* On F10h, if we are in 128 bit mode, then we are using 2 channels */
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001352 if (pvt->fam == 0x10 && (pvt->dclr0 & WIDTH_128))
Borislav Petkov7d20d142011-01-07 17:58:04 +01001353 return 2;
Doug Thompson1afd3c92009-04-27 16:16:50 +02001354
1355 /*
Borislav Petkovd16149e2009-10-16 19:55:49 +02001356 * Need to check if in unganged mode: In such, there are 2 channels,
1357 * but they are not in 128 bit mode and thus the above 'dclr0' status
1358 * bit will be OFF.
Doug Thompson1afd3c92009-04-27 16:16:50 +02001359 *
1360 * Need to check DCT0[0] and DCT1[0] to see if only one of them has
1361 * their CSEnable bit on. If so, then SINGLE DIMM case.
1362 */
Joe Perches956b9ba12012-04-29 17:08:39 -03001363 edac_dbg(0, "Data width is not 128 bits - need more decoding\n");
Doug Thompson1afd3c92009-04-27 16:16:50 +02001364
1365 /*
1366 * Check DRAM Bank Address Mapping values for each DIMM to see if there
1367 * is more than just one DIMM present in unganged mode. Need to check
1368 * both controllers since DIMMs can be placed in either one.
1369 */
Borislav Petkov525a1b22010-12-21 15:53:27 +01001370 for (i = 0; i < 2; i++) {
1371 u32 dbam = (i ? pvt->dbam1 : pvt->dbam0);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001372
Wan Wei57a30852009-08-07 17:04:49 +02001373 for (j = 0; j < 4; j++) {
1374 if (DBAM_DIMM(j, dbam) > 0) {
1375 channels++;
1376 break;
1377 }
1378 }
Doug Thompson1afd3c92009-04-27 16:16:50 +02001379 }
1380
Borislav Petkovd16149e2009-10-16 19:55:49 +02001381 if (channels > 2)
1382 channels = 2;
1383
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001384 amd64_info("MCT channel count: %d\n", channels);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001385
1386 return channels;
Doug Thompson1afd3c92009-04-27 16:16:50 +02001387}
1388
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05001389static int f17_early_channel_count(struct amd64_pvt *pvt)
1390{
1391 int i, channels = 0;
1392
1393 /* SDP Control bit 31 (SdpInit) is clear for unused UMC channels */
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +00001394 for_each_umc(i)
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05001395 channels += !!(pvt->umc[i].sdp_ctrl & UMC_SDP_INIT);
1396
1397 amd64_info("MCT channel count: %d\n", channels);
1398
1399 return channels;
1400}
1401
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001402static int ddr3_cs_size(unsigned i, bool dct_width)
Doug Thompson1afd3c92009-04-27 16:16:50 +02001403{
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001404 unsigned shift = 0;
1405 int cs_size = 0;
1406
1407 if (i == 0 || i == 3 || i == 4)
1408 cs_size = -1;
1409 else if (i <= 2)
1410 shift = i;
1411 else if (i == 12)
1412 shift = 7;
1413 else if (!(i & 0x1))
1414 shift = i >> 1;
1415 else
1416 shift = (i + 1) >> 1;
1417
1418 if (cs_size != -1)
1419 cs_size = (128 * (1 << !!dct_width)) << shift;
1420
1421 return cs_size;
1422}
1423
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001424static int ddr3_lrdimm_cs_size(unsigned i, unsigned rank_multiply)
1425{
1426 unsigned shift = 0;
1427 int cs_size = 0;
1428
1429 if (i < 4 || i == 6)
1430 cs_size = -1;
1431 else if (i == 12)
1432 shift = 7;
1433 else if (!(i & 0x1))
1434 shift = i >> 1;
1435 else
1436 shift = (i + 1) >> 1;
1437
1438 if (cs_size != -1)
1439 cs_size = rank_multiply * (128 << shift);
1440
1441 return cs_size;
1442}
1443
1444static int ddr4_cs_size(unsigned i)
1445{
1446 int cs_size = 0;
1447
1448 if (i == 0)
1449 cs_size = -1;
1450 else if (i == 1)
1451 cs_size = 1024;
1452 else
1453 /* Min cs_size = 1G */
1454 cs_size = 1024 * (1 << (i >> 1));
1455
1456 return cs_size;
1457}
1458
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001459static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001460 unsigned cs_mode, int cs_mask_nr)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001461{
1462 u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
1463
1464 WARN_ON(cs_mode > 11);
Borislav Petkov1433eb92009-10-21 13:44:36 +02001465
1466 if (pvt->dchr0 & DDR3_MODE || pvt->dchr1 & DDR3_MODE)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001467 return ddr3_cs_size(cs_mode, dclr & WIDTH_128);
Borislav Petkov1433eb92009-10-21 13:44:36 +02001468 else
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001469 return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
1470}
Borislav Petkov1433eb92009-10-21 13:44:36 +02001471
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001472/*
1473 * F15h supports only 64bit DCT interfaces
1474 */
1475static int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001476 unsigned cs_mode, int cs_mask_nr)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001477{
1478 WARN_ON(cs_mode > 12);
1479
1480 return ddr3_cs_size(cs_mode, false);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001481}
1482
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001483/* F15h M60h supports DDR4 mapping as well.. */
1484static int f15_m60h_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
1485 unsigned cs_mode, int cs_mask_nr)
1486{
1487 int cs_size;
1488 u32 dcsm = pvt->csels[dct].csmasks[cs_mask_nr];
1489
1490 WARN_ON(cs_mode > 12);
1491
1492 if (pvt->dram_type == MEM_DDR4) {
1493 if (cs_mode > 9)
1494 return -1;
1495
1496 cs_size = ddr4_cs_size(cs_mode);
1497 } else if (pvt->dram_type == MEM_LRDDR3) {
1498 unsigned rank_multiply = dcsm & 0xf;
1499
1500 if (rank_multiply == 3)
1501 rank_multiply = 4;
1502 cs_size = ddr3_lrdimm_cs_size(cs_mode, rank_multiply);
1503 } else {
1504 /* Minimum cs size is 512mb for F15hM60h*/
1505 if (cs_mode == 0x1)
1506 return -1;
1507
1508 cs_size = ddr3_cs_size(cs_mode, false);
1509 }
1510
1511 return cs_size;
1512}
1513
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05001514/*
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001515 * F16h and F15h model 30h have only limited cs_modes.
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05001516 */
1517static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01001518 unsigned cs_mode, int cs_mask_nr)
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05001519{
1520 WARN_ON(cs_mode > 12);
1521
1522 if (cs_mode == 6 || cs_mode == 8 ||
1523 cs_mode == 9 || cs_mode == 12)
1524 return -1;
1525 else
1526 return ddr3_cs_size(cs_mode, false);
1527}
1528
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05001529static int f17_base_addr_to_cs_size(struct amd64_pvt *pvt, u8 umc,
1530 unsigned int cs_mode, int csrow_nr)
1531{
1532 u32 base_addr = pvt->csels[umc].csbases[csrow_nr];
1533
1534 /* Each mask is used for every two base addresses. */
1535 u32 addr_mask = pvt->csels[umc].csmasks[csrow_nr >> 1];
1536
1537 /* Register [31:1] = Address [39:9]. Size is in kBs here. */
1538 u32 size = ((addr_mask >> 1) - (base_addr >> 1) + 1) >> 1;
1539
1540 edac_dbg(1, "BaseAddr: 0x%x, AddrMask: 0x%x\n", base_addr, addr_mask);
1541
1542 /* Return size in MBs. */
1543 return size >> 10;
1544}
1545
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001546static void read_dram_ctl_register(struct amd64_pvt *pvt)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001547{
Doug Thompson6163b5d2009-04-27 16:20:17 +02001548
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001549 if (pvt->fam == 0xf)
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001550 return;
1551
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05001552 if (!amd64_read_pci_cfg(pvt->F2, DCT_SEL_LO, &pvt->dct_sel_lo)) {
Joe Perches956b9ba12012-04-29 17:08:39 -03001553 edac_dbg(0, "F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x\n",
1554 pvt->dct_sel_lo, dct_sel_baseaddr(pvt));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001555
Joe Perches956b9ba12012-04-29 17:08:39 -03001556 edac_dbg(0, " DCTs operate in %s mode\n",
1557 (dct_ganging_enabled(pvt) ? "ganged" : "unganged"));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001558
Borislav Petkov72381bd2009-10-09 19:14:43 +02001559 if (!dct_ganging_enabled(pvt))
Joe Perches956b9ba12012-04-29 17:08:39 -03001560 edac_dbg(0, " Address range split per DCT: %s\n",
1561 (dct_high_range_enabled(pvt) ? "yes" : "no"));
Borislav Petkov72381bd2009-10-09 19:14:43 +02001562
Joe Perches956b9ba12012-04-29 17:08:39 -03001563 edac_dbg(0, " data interleave for ECC: %s, DRAM cleared since last warm reset: %s\n",
1564 (dct_data_intlv_enabled(pvt) ? "enabled" : "disabled"),
1565 (dct_memory_cleared(pvt) ? "yes" : "no"));
Borislav Petkov72381bd2009-10-09 19:14:43 +02001566
Joe Perches956b9ba12012-04-29 17:08:39 -03001567 edac_dbg(0, " channel interleave: %s, "
1568 "interleave bits selector: 0x%x\n",
1569 (dct_interleave_enabled(pvt) ? "enabled" : "disabled"),
1570 dct_sel_interleave_addr(pvt));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001571 }
1572
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05001573 amd64_read_pci_cfg(pvt->F2, DCT_SEL_HI, &pvt->dct_sel_hi);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001574}
1575
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001576/*
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001577 * Determine channel (DCT) based on the interleaving mode (see F15h M30h BKDG,
1578 * 2.10.12 Memory Interleaving Modes).
1579 */
1580static u8 f15_m30h_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
1581 u8 intlv_en, int num_dcts_intlv,
1582 u32 dct_sel)
1583{
1584 u8 channel = 0;
1585 u8 select;
1586
1587 if (!(intlv_en))
1588 return (u8)(dct_sel);
1589
1590 if (num_dcts_intlv == 2) {
1591 select = (sys_addr >> 8) & 0x3;
1592 channel = select ? 0x3 : 0;
Aravind Gopalakrishnan9d0e8d82014-01-21 15:03:36 -06001593 } else if (num_dcts_intlv == 4) {
1594 u8 intlv_addr = dct_sel_interleave_addr(pvt);
1595 switch (intlv_addr) {
1596 case 0x4:
1597 channel = (sys_addr >> 8) & 0x3;
1598 break;
1599 case 0x5:
1600 channel = (sys_addr >> 9) & 0x3;
1601 break;
1602 }
1603 }
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001604 return channel;
1605}
1606
1607/*
Borislav Petkov229a7a12010-12-09 18:57:54 +01001608 * Determine channel (DCT) based on the interleaving mode: F10h BKDG, 2.8.9 Memory
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001609 * Interleaving Modes.
1610 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001611static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
Borislav Petkov229a7a12010-12-09 18:57:54 +01001612 bool hi_range_sel, u8 intlv_en)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001613{
Borislav Petkov151fa712011-02-21 19:33:10 +01001614 u8 dct_sel_high = (pvt->dct_sel_lo >> 1) & 1;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001615
1616 if (dct_ganging_enabled(pvt))
Borislav Petkov229a7a12010-12-09 18:57:54 +01001617 return 0;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001618
Borislav Petkov229a7a12010-12-09 18:57:54 +01001619 if (hi_range_sel)
1620 return dct_sel_high;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001621
Borislav Petkov229a7a12010-12-09 18:57:54 +01001622 /*
1623 * see F2x110[DctSelIntLvAddr] - channel interleave mode
1624 */
1625 if (dct_interleave_enabled(pvt)) {
1626 u8 intlv_addr = dct_sel_interleave_addr(pvt);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001627
Borislav Petkov229a7a12010-12-09 18:57:54 +01001628 /* return DCT select function: 0=DCT0, 1=DCT1 */
1629 if (!intlv_addr)
1630 return sys_addr >> 6 & 1;
1631
1632 if (intlv_addr & 0x2) {
1633 u8 shift = intlv_addr & 0x1 ? 9 : 6;
Yazen Ghannamdc0a50a82016-08-03 10:59:15 -04001634 u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) & 1;
Borislav Petkov229a7a12010-12-09 18:57:54 +01001635
1636 return ((sys_addr >> shift) & 1) ^ temp;
1637 }
1638
Yazen Ghannamdc0a50a82016-08-03 10:59:15 -04001639 if (intlv_addr & 0x4) {
1640 u8 shift = intlv_addr & 0x1 ? 9 : 8;
1641
1642 return (sys_addr >> shift) & 1;
1643 }
1644
Borislav Petkov229a7a12010-12-09 18:57:54 +01001645 return (sys_addr >> (12 + hweight8(intlv_en))) & 1;
1646 }
1647
1648 if (dct_high_range_enabled(pvt))
1649 return ~dct_sel_high & 1;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001650
1651 return 0;
1652}
1653
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001654/* Convert the sys_addr to the normalized DCT address */
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08001655static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range,
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001656 u64 sys_addr, bool hi_rng,
1657 u32 dct_sel_base_addr)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001658{
1659 u64 chan_off;
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001660 u64 dram_base = get_dram_base(pvt, range);
1661 u64 hole_off = f10_dhar_offset(pvt);
Dan Carpenter6f3508f2016-01-20 12:54:51 +03001662 u64 dct_sel_base_off = (u64)(pvt->dct_sel_hi & 0xFFFFFC00) << 16;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001663
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001664 if (hi_rng) {
1665 /*
1666 * if
1667 * base address of high range is below 4Gb
1668 * (bits [47:27] at [31:11])
1669 * DRAM address space on this DCT is hoisted above 4Gb &&
1670 * sys_addr > 4Gb
1671 *
1672 * remove hole offset from sys_addr
1673 * else
1674 * remove high range offset from sys_addr
1675 */
1676 if ((!(dct_sel_base_addr >> 16) ||
1677 dct_sel_base_addr < dhar_base(pvt)) &&
Borislav Petkov972ea172011-02-21 19:43:02 +01001678 dhar_valid(pvt) &&
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001679 (sys_addr >= BIT_64(32)))
Borislav Petkovbc21fa52010-11-11 17:29:13 +01001680 chan_off = hole_off;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001681 else
1682 chan_off = dct_sel_base_off;
1683 } else {
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001684 /*
1685 * if
1686 * we have a valid hole &&
1687 * sys_addr > 4Gb
1688 *
1689 * remove hole
1690 * else
1691 * remove dram base to normalize to DCT address
1692 */
Borislav Petkov972ea172011-02-21 19:43:02 +01001693 if (dhar_valid(pvt) && (sys_addr >= BIT_64(32)))
Borislav Petkovbc21fa52010-11-11 17:29:13 +01001694 chan_off = hole_off;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001695 else
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001696 chan_off = dram_base;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001697 }
1698
Chen, Gong10ef6b02013-10-18 14:29:07 -07001699 return (sys_addr & GENMASK_ULL(47,6)) - (chan_off & GENMASK_ULL(47,23));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001700}
1701
Doug Thompson6163b5d2009-04-27 16:20:17 +02001702/*
1703 * checks if the csrow passed in is marked as SPARED, if so returns the new
1704 * spare row
1705 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001706static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001707{
Borislav Petkov614ec9d2011-01-13 18:02:22 +01001708 int tmp_cs;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001709
Borislav Petkov614ec9d2011-01-13 18:02:22 +01001710 if (online_spare_swap_done(pvt, dct) &&
1711 csrow == online_spare_bad_dramcs(pvt, dct)) {
1712
1713 for_each_chip_select(tmp_cs, dct, pvt) {
1714 if (chip_select_base(tmp_cs, dct, pvt) & 0x2) {
1715 csrow = tmp_cs;
1716 break;
1717 }
1718 }
Doug Thompson6163b5d2009-04-27 16:20:17 +02001719 }
1720 return csrow;
1721}
1722
1723/*
1724 * Iterate over the DRAM DCT "base" and "mask" registers looking for a
1725 * SystemAddr match on the specified 'ChannelSelect' and 'NodeID'
1726 *
1727 * Return:
1728 * -EINVAL: NOT FOUND
1729 * 0..csrow = Chip-Select Row
1730 */
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08001731static int f1x_lookup_addr_in_dct(u64 in_addr, u8 nid, u8 dct)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001732{
1733 struct mem_ctl_info *mci;
1734 struct amd64_pvt *pvt;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001735 u64 cs_base, cs_mask;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001736 int cs_found = -EINVAL;
1737 int csrow;
1738
Borislav Petkov2ec591a2015-02-17 10:58:34 +01001739 mci = edac_mc_find(nid);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001740 if (!mci)
1741 return cs_found;
1742
1743 pvt = mci->pvt_info;
1744
Joe Perches956b9ba12012-04-29 17:08:39 -03001745 edac_dbg(1, "input addr: 0x%llx, DCT: %d\n", in_addr, dct);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001746
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001747 for_each_chip_select(csrow, dct, pvt) {
1748 if (!csrow_enabled(csrow, dct, pvt))
Doug Thompson6163b5d2009-04-27 16:20:17 +02001749 continue;
1750
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001751 get_cs_base_and_mask(pvt, csrow, dct, &cs_base, &cs_mask);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001752
Joe Perches956b9ba12012-04-29 17:08:39 -03001753 edac_dbg(1, " CSROW=%d CSBase=0x%llx CSMask=0x%llx\n",
1754 csrow, cs_base, cs_mask);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001755
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001756 cs_mask = ~cs_mask;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001757
Joe Perches956b9ba12012-04-29 17:08:39 -03001758 edac_dbg(1, " (InputAddr & ~CSMask)=0x%llx (CSBase & ~CSMask)=0x%llx\n",
1759 (in_addr & cs_mask), (cs_base & cs_mask));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001760
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001761 if ((in_addr & cs_mask) == (cs_base & cs_mask)) {
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001762 if (pvt->fam == 0x15 && pvt->model >= 0x30) {
1763 cs_found = csrow;
1764 break;
1765 }
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001766 cs_found = f10_process_possible_spare(pvt, dct, csrow);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001767
Joe Perches956b9ba12012-04-29 17:08:39 -03001768 edac_dbg(1, " MATCH csrow=%d\n", cs_found);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001769 break;
1770 }
1771 }
1772 return cs_found;
1773}
1774
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001775/*
1776 * See F2x10C. Non-interleaved graphics framebuffer memory under the 16G is
1777 * swapped with a region located at the bottom of memory so that the GPU can use
1778 * the interleaved region and thus two channels.
1779 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001780static u64 f1x_swap_interleaved_region(struct amd64_pvt *pvt, u64 sys_addr)
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001781{
1782 u32 swap_reg, swap_base, swap_limit, rgn_size, tmp_addr;
1783
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001784 if (pvt->fam == 0x10) {
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001785 /* only revC3 and revE have that feature */
Borislav Petkova4b4bed2013-08-10 13:54:48 +02001786 if (pvt->model < 4 || (pvt->model < 0xa && pvt->stepping < 3))
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001787 return sys_addr;
1788 }
1789
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05001790 amd64_read_pci_cfg(pvt->F2, SWAP_INTLV_REG, &swap_reg);
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001791
1792 if (!(swap_reg & 0x1))
1793 return sys_addr;
1794
1795 swap_base = (swap_reg >> 3) & 0x7f;
1796 swap_limit = (swap_reg >> 11) & 0x7f;
1797 rgn_size = (swap_reg >> 20) & 0x7f;
1798 tmp_addr = sys_addr >> 27;
1799
1800 if (!(sys_addr >> 34) &&
1801 (((tmp_addr >= swap_base) &&
1802 (tmp_addr <= swap_limit)) ||
1803 (tmp_addr < rgn_size)))
1804 return sys_addr ^ (u64)swap_base << 27;
1805
1806 return sys_addr;
1807}
1808
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001809/* For a given @dram_range, check if @sys_addr falls within it. */
Borislav Petkove761359a2011-02-21 19:49:01 +01001810static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
Borislav Petkov33ca0642012-08-30 18:01:36 +02001811 u64 sys_addr, int *chan_sel)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001812{
Borislav Petkov229a7a12010-12-09 18:57:54 +01001813 int cs_found = -EINVAL;
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001814 u64 chan_addr;
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001815 u32 dct_sel_base;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001816 u8 channel;
Borislav Petkov229a7a12010-12-09 18:57:54 +01001817 bool high_range = false;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001818
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001819 u8 node_id = dram_dst_node(pvt, range);
Borislav Petkov229a7a12010-12-09 18:57:54 +01001820 u8 intlv_en = dram_intlv_en(pvt, range);
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001821 u32 intlv_sel = dram_intlv_sel(pvt, range);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001822
Joe Perches956b9ba12012-04-29 17:08:39 -03001823 edac_dbg(1, "(range %d) SystemAddr= 0x%llx Limit=0x%llx\n",
1824 range, sys_addr, get_dram_limit(pvt, range));
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001825
Borislav Petkov355fba62011-01-17 13:03:26 +01001826 if (dhar_valid(pvt) &&
1827 dhar_base(pvt) <= sys_addr &&
1828 sys_addr < BIT_64(32)) {
1829 amd64_warn("Huh? Address is in the MMIO hole: 0x%016llx\n",
1830 sys_addr);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001831 return -EINVAL;
Borislav Petkov355fba62011-01-17 13:03:26 +01001832 }
1833
Borislav Petkovf030ddf2011-04-08 15:05:21 +02001834 if (intlv_en && (intlv_sel != ((sys_addr >> 12) & intlv_en)))
Borislav Petkov355fba62011-01-17 13:03:26 +01001835 return -EINVAL;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001836
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001837 sys_addr = f1x_swap_interleaved_region(pvt, sys_addr);
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001838
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001839 dct_sel_base = dct_sel_baseaddr(pvt);
1840
1841 /*
1842 * check whether addresses >= DctSelBaseAddr[47:27] are to be used to
1843 * select between DCT0 and DCT1.
1844 */
1845 if (dct_high_range_enabled(pvt) &&
1846 !dct_ganging_enabled(pvt) &&
1847 ((sys_addr >> 27) >= (dct_sel_base >> 11)))
Borislav Petkov229a7a12010-12-09 18:57:54 +01001848 high_range = true;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001849
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001850 channel = f1x_determine_channel(pvt, sys_addr, high_range, intlv_en);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001851
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001852 chan_addr = f1x_get_norm_dct_addr(pvt, range, sys_addr,
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001853 high_range, dct_sel_base);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001854
Borislav Petkove2f79db2011-01-13 14:57:34 +01001855 /* Remove node interleaving, see F1x120 */
1856 if (intlv_en)
1857 chan_addr = ((chan_addr >> (12 + hweight8(intlv_en))) << 12) |
1858 (chan_addr & 0xfff);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001859
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001860 /* remove channel interleave */
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001861 if (dct_interleave_enabled(pvt) &&
1862 !dct_high_range_enabled(pvt) &&
1863 !dct_ganging_enabled(pvt)) {
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001864
1865 if (dct_sel_interleave_addr(pvt) != 1) {
1866 if (dct_sel_interleave_addr(pvt) == 0x3)
1867 /* hash 9 */
1868 chan_addr = ((chan_addr >> 10) << 9) |
1869 (chan_addr & 0x1ff);
1870 else
1871 /* A[6] or hash 6 */
1872 chan_addr = ((chan_addr >> 7) << 6) |
1873 (chan_addr & 0x3f);
1874 } else
1875 /* A[12] */
1876 chan_addr = ((chan_addr >> 13) << 12) |
1877 (chan_addr & 0xfff);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001878 }
1879
Joe Perches956b9ba12012-04-29 17:08:39 -03001880 edac_dbg(1, " Normalized DCT addr: 0x%llx\n", chan_addr);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001881
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001882 cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, channel);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001883
Borislav Petkov33ca0642012-08-30 18:01:36 +02001884 if (cs_found >= 0)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001885 *chan_sel = channel;
Borislav Petkov33ca0642012-08-30 18:01:36 +02001886
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001887 return cs_found;
1888}
1889
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001890static int f15_m30h_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
1891 u64 sys_addr, int *chan_sel)
1892{
1893 int cs_found = -EINVAL;
1894 int num_dcts_intlv = 0;
1895 u64 chan_addr, chan_offset;
1896 u64 dct_base, dct_limit;
1897 u32 dct_cont_base_reg, dct_cont_limit_reg, tmp;
1898 u8 channel, alias_channel, leg_mmio_hole, dct_sel, dct_offset_en;
1899
1900 u64 dhar_offset = f10_dhar_offset(pvt);
1901 u8 intlv_addr = dct_sel_interleave_addr(pvt);
1902 u8 node_id = dram_dst_node(pvt, range);
1903 u8 intlv_en = dram_intlv_en(pvt, range);
1904
1905 amd64_read_pci_cfg(pvt->F1, DRAM_CONT_BASE, &dct_cont_base_reg);
1906 amd64_read_pci_cfg(pvt->F1, DRAM_CONT_LIMIT, &dct_cont_limit_reg);
1907
1908 dct_offset_en = (u8) ((dct_cont_base_reg >> 3) & BIT(0));
1909 dct_sel = (u8) ((dct_cont_base_reg >> 4) & 0x7);
1910
1911 edac_dbg(1, "(range %d) SystemAddr= 0x%llx Limit=0x%llx\n",
1912 range, sys_addr, get_dram_limit(pvt, range));
1913
1914 if (!(get_dram_base(pvt, range) <= sys_addr) &&
1915 !(get_dram_limit(pvt, range) >= sys_addr))
1916 return -EINVAL;
1917
1918 if (dhar_valid(pvt) &&
1919 dhar_base(pvt) <= sys_addr &&
1920 sys_addr < BIT_64(32)) {
1921 amd64_warn("Huh? Address is in the MMIO hole: 0x%016llx\n",
1922 sys_addr);
1923 return -EINVAL;
1924 }
1925
1926 /* Verify sys_addr is within DCT Range. */
Aravind Gopalakrishnan4fc06b32013-08-24 10:47:48 -05001927 dct_base = (u64) dct_sel_baseaddr(pvt);
1928 dct_limit = (dct_cont_limit_reg >> 11) & 0x1FFF;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001929
1930 if (!(dct_cont_base_reg & BIT(0)) &&
Aravind Gopalakrishnan4fc06b32013-08-24 10:47:48 -05001931 !(dct_base <= (sys_addr >> 27) &&
1932 dct_limit >= (sys_addr >> 27)))
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001933 return -EINVAL;
1934
1935 /* Verify number of dct's that participate in channel interleaving. */
1936 num_dcts_intlv = (int) hweight8(intlv_en);
1937
1938 if (!(num_dcts_intlv % 2 == 0) || (num_dcts_intlv > 4))
1939 return -EINVAL;
1940
Yazen Ghannamdc0a50a82016-08-03 10:59:15 -04001941 if (pvt->model >= 0x60)
1942 channel = f1x_determine_channel(pvt, sys_addr, false, intlv_en);
1943 else
1944 channel = f15_m30h_determine_channel(pvt, sys_addr, intlv_en,
1945 num_dcts_intlv, dct_sel);
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001946
1947 /* Verify we stay within the MAX number of channels allowed */
Aravind Gopalakrishnan7f3f5242013-12-04 11:40:11 -06001948 if (channel > 3)
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001949 return -EINVAL;
1950
1951 leg_mmio_hole = (u8) (dct_cont_base_reg >> 1 & BIT(0));
1952
1953 /* Get normalized DCT addr */
1954 if (leg_mmio_hole && (sys_addr >= BIT_64(32)))
1955 chan_offset = dhar_offset;
1956 else
Aravind Gopalakrishnan4fc06b32013-08-24 10:47:48 -05001957 chan_offset = dct_base << 27;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001958
1959 chan_addr = sys_addr - chan_offset;
1960
1961 /* remove channel interleave */
1962 if (num_dcts_intlv == 2) {
1963 if (intlv_addr == 0x4)
1964 chan_addr = ((chan_addr >> 9) << 8) |
1965 (chan_addr & 0xff);
1966 else if (intlv_addr == 0x5)
1967 chan_addr = ((chan_addr >> 10) << 9) |
1968 (chan_addr & 0x1ff);
1969 else
1970 return -EINVAL;
1971
1972 } else if (num_dcts_intlv == 4) {
1973 if (intlv_addr == 0x4)
1974 chan_addr = ((chan_addr >> 10) << 8) |
1975 (chan_addr & 0xff);
1976 else if (intlv_addr == 0x5)
1977 chan_addr = ((chan_addr >> 11) << 9) |
1978 (chan_addr & 0x1ff);
1979 else
1980 return -EINVAL;
1981 }
1982
1983 if (dct_offset_en) {
1984 amd64_read_pci_cfg(pvt->F1,
1985 DRAM_CONT_HIGH_OFF + (int) channel * 4,
1986 &tmp);
Aravind Gopalakrishnan4fc06b32013-08-24 10:47:48 -05001987 chan_addr += (u64) ((tmp >> 11) & 0xfff) << 27;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05001988 }
1989
1990 f15h_select_dct(pvt, channel);
1991
1992 edac_dbg(1, " Normalized DCT addr: 0x%llx\n", chan_addr);
1993
1994 /*
1995 * Find Chip select:
1996 * if channel = 3, then alias it to 1. This is because, in F15 M30h,
1997 * there is support for 4 DCT's, but only 2 are currently functional.
1998 * They are DCT0 and DCT3. But we have read all registers of DCT3 into
1999 * pvt->csels[1]. So we need to use '1' here to get correct info.
2000 * Refer F15 M30h BKDG Section 2.10 and 2.10.3 for clarifications.
2001 */
2002 alias_channel = (channel == 3) ? 1 : channel;
2003
2004 cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, alias_channel);
2005
2006 if (cs_found >= 0)
2007 *chan_sel = alias_channel;
2008
2009 return cs_found;
2010}
2011
2012static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt,
2013 u64 sys_addr,
2014 int *chan_sel)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002015{
Borislav Petkove761359a2011-02-21 19:49:01 +01002016 int cs_found = -EINVAL;
2017 unsigned range;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002018
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002019 for (range = 0; range < DRAM_RANGES; range++) {
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002020 if (!dram_rw(pvt, range))
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002021 continue;
2022
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05002023 if (pvt->fam == 0x15 && pvt->model >= 0x30)
2024 cs_found = f15_m30h_match_to_this_node(pvt, range,
2025 sys_addr,
2026 chan_sel);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002027
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05002028 else if ((get_dram_base(pvt, range) <= sys_addr) &&
2029 (get_dram_limit(pvt, range) >= sys_addr)) {
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01002030 cs_found = f1x_match_to_this_node(pvt, range,
Borislav Petkov33ca0642012-08-30 18:01:36 +02002031 sys_addr, chan_sel);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002032 if (cs_found >= 0)
2033 break;
2034 }
2035 }
2036 return cs_found;
2037}
2038
2039/*
Borislav Petkovbdc30a02009-11-13 15:10:43 +01002040 * For reference see "2.8.5 Routing DRAM Requests" in F10 BKDG. This code maps
2041 * a @sys_addr to NodeID, DCT (channel) and chip select (CSROW).
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002042 *
Borislav Petkovbdc30a02009-11-13 15:10:43 +01002043 * The @sys_addr is usually an error address received from the hardware
2044 * (MCX_ADDR).
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002045 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01002046static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
Borislav Petkov33ca0642012-08-30 18:01:36 +02002047 struct err_info *err)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002048{
2049 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002050
Borislav Petkov33ca0642012-08-30 18:01:36 +02002051 error_address_to_page_and_offset(sys_addr, err);
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03002052
Borislav Petkov33ca0642012-08-30 18:01:36 +02002053 err->csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &err->channel);
2054 if (err->csrow < 0) {
2055 err->err_code = ERR_CSROW;
Borislav Petkovbdc30a02009-11-13 15:10:43 +01002056 return;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002057 }
Borislav Petkovbdc30a02009-11-13 15:10:43 +01002058
Borislav Petkovbdc30a02009-11-13 15:10:43 +01002059 /*
2060 * We need the syndromes for channel detection only when we're
2061 * ganged. Otherwise @chan should already contain the channel at
2062 * this point.
2063 */
Borislav Petkova97fa682010-12-23 14:07:18 +01002064 if (dct_ganging_enabled(pvt))
Borislav Petkov33ca0642012-08-30 18:01:36 +02002065 err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002066}
2067
2068/*
Borislav Petkov8566c4d2009-10-16 13:48:28 +02002069 * debug routine to display the memory sizes of all logical DIMMs and its
Borislav Petkovcb328502010-12-22 14:28:24 +01002070 * CSROWs
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002071 */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01002072static void debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002073{
Borislav Petkovbb89f5a2012-09-12 18:06:00 +02002074 int dimm, size0, size1;
Borislav Petkov525a1b22010-12-21 15:53:27 +01002075 u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases;
2076 u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002077
Borislav Petkova4b4bed2013-08-10 13:54:48 +02002078 if (pvt->fam == 0xf) {
Borislav Petkov8566c4d2009-10-16 13:48:28 +02002079 /* K8 families < revF not supported yet */
Borislav Petkov1433eb92009-10-21 13:44:36 +02002080 if (pvt->ext_model < K8_REV_F)
Borislav Petkov8566c4d2009-10-16 13:48:28 +02002081 return;
2082 else
2083 WARN_ON(ctrl != 0);
2084 }
2085
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05002086 if (pvt->fam == 0x10) {
2087 dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1
2088 : pvt->dbam0;
2089 dcsb = (ctrl && !dct_ganging_enabled(pvt)) ?
2090 pvt->csels[1].csbases :
2091 pvt->csels[0].csbases;
2092 } else if (ctrl) {
2093 dbam = pvt->dbam0;
2094 dcsb = pvt->csels[1].csbases;
2095 }
Joe Perches956b9ba12012-04-29 17:08:39 -03002096 edac_dbg(1, "F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n",
2097 ctrl, dbam);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002098
Borislav Petkov8566c4d2009-10-16 13:48:28 +02002099 edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl);
2100
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002101 /* Dump memory sizes for DIMM and its CSROWs */
2102 for (dimm = 0; dimm < 4; dimm++) {
2103
2104 size0 = 0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002105 if (dcsb[dimm*2] & DCSB_CS_ENABLE)
Yazen Ghannam07ed82e2016-11-28 08:50:21 -06002106 /*
2107 * For F15m60h, we need multiplier for LRDIMM cs_size
2108 * calculation. We pass dimm value to the dbam_to_cs
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002109 * mapper so we can find the multiplier from the
2110 * corresponding DCSM.
2111 */
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01002112 size0 = pvt->ops->dbam_to_cs(pvt, ctrl,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002113 DBAM_DIMM(dimm, dbam),
2114 dimm);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002115
2116 size1 = 0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002117 if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01002118 size1 = pvt->ops->dbam_to_cs(pvt, ctrl,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002119 DBAM_DIMM(dimm, dbam),
2120 dimm);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002121
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002122 amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
Borislav Petkovbb89f5a2012-09-12 18:06:00 +02002123 dimm * 2, size0,
2124 dimm * 2 + 1, size1);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02002125 }
2126}
2127
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01002128static struct amd64_family_type family_types[] = {
Doug Thompson4d376072009-04-27 16:25:05 +02002129 [K8_CPUS] = {
Borislav Petkov0092b202010-10-01 19:20:05 +02002130 .ctl_name = "K8",
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002131 .f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002132 .f2_id = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL,
Doug Thompson4d376072009-04-27 16:25:05 +02002133 .ops = {
Borislav Petkov1433eb92009-10-21 13:44:36 +02002134 .early_channel_count = k8_early_channel_count,
Borislav Petkov1433eb92009-10-21 13:44:36 +02002135 .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow,
2136 .dbam_to_cs = k8_dbam_to_chip_select,
Doug Thompson4d376072009-04-27 16:25:05 +02002137 }
2138 },
2139 [F10_CPUS] = {
Borislav Petkov0092b202010-10-01 19:20:05 +02002140 .ctl_name = "F10h",
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002141 .f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002142 .f2_id = PCI_DEVICE_ID_AMD_10H_NB_DRAM,
Doug Thompson4d376072009-04-27 16:25:05 +02002143 .ops = {
Borislav Petkov7d20d142011-01-07 17:58:04 +01002144 .early_channel_count = f1x_early_channel_count,
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01002145 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
Borislav Petkov1433eb92009-10-21 13:44:36 +02002146 .dbam_to_cs = f10_dbam_to_chip_select,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02002147 }
2148 },
2149 [F15_CPUS] = {
2150 .ctl_name = "F15h",
Borislav Petkovdf71a052011-01-19 18:15:10 +01002151 .f1_id = PCI_DEVICE_ID_AMD_15H_NB_F1,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002152 .f2_id = PCI_DEVICE_ID_AMD_15H_NB_F2,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02002153 .ops = {
Borislav Petkov7d20d142011-01-07 17:58:04 +01002154 .early_channel_count = f1x_early_channel_count,
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01002155 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01002156 .dbam_to_cs = f15_dbam_to_chip_select,
Doug Thompson4d376072009-04-27 16:25:05 +02002157 }
2158 },
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05002159 [F15_M30H_CPUS] = {
2160 .ctl_name = "F15h_M30h",
2161 .f1_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002162 .f2_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F2,
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05002163 .ops = {
2164 .early_channel_count = f1x_early_channel_count,
2165 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
2166 .dbam_to_cs = f16_dbam_to_chip_select,
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05002167 }
2168 },
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002169 [F15_M60H_CPUS] = {
2170 .ctl_name = "F15h_M60h",
2171 .f1_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002172 .f2_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F2,
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002173 .ops = {
2174 .early_channel_count = f1x_early_channel_count,
2175 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
2176 .dbam_to_cs = f15_m60h_dbam_to_chip_select,
2177 }
2178 },
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05002179 [F16_CPUS] = {
2180 .ctl_name = "F16h",
2181 .f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002182 .f2_id = PCI_DEVICE_ID_AMD_16H_NB_F2,
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05002183 .ops = {
2184 .early_channel_count = f1x_early_channel_count,
2185 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
2186 .dbam_to_cs = f16_dbam_to_chip_select,
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05002187 }
2188 },
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -06002189 [F16_M30H_CPUS] = {
2190 .ctl_name = "F16h_M30h",
2191 .f1_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F1,
Borislav Petkov3f37a362016-05-06 19:44:27 +02002192 .f2_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F2,
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -06002193 .ops = {
2194 .early_channel_count = f1x_early_channel_count,
2195 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
2196 .dbam_to_cs = f16_dbam_to_chip_select,
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -06002197 }
2198 },
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05002199 [F17_CPUS] = {
2200 .ctl_name = "F17h",
2201 .f0_id = PCI_DEVICE_ID_AMD_17H_DF_F0,
2202 .f6_id = PCI_DEVICE_ID_AMD_17H_DF_F6,
2203 .ops = {
2204 .early_channel_count = f17_early_channel_count,
2205 .dbam_to_cs = f17_base_addr_to_cs_size,
2206 }
2207 },
Michael Jin8960de42018-08-16 15:28:40 -04002208 [F17_M10H_CPUS] = {
2209 .ctl_name = "F17h_M10h",
2210 .f0_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F0,
2211 .f6_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F6,
2212 .ops = {
2213 .early_channel_count = f17_early_channel_count,
2214 .dbam_to_cs = f17_base_addr_to_cs_size,
2215 }
2216 },
Yazen Ghannam6e8462392019-02-28 15:36:09 +00002217 [F17_M30H_CPUS] = {
2218 .ctl_name = "F17h_M30h",
2219 .f0_id = PCI_DEVICE_ID_AMD_17H_M30H_DF_F0,
2220 .f6_id = PCI_DEVICE_ID_AMD_17H_M30H_DF_F6,
2221 .ops = {
2222 .early_channel_count = f17_early_channel_count,
2223 .dbam_to_cs = f17_base_addr_to_cs_size,
2224 }
2225 },
Doug Thompson4d376072009-04-27 16:25:05 +02002226};
2227
Doug Thompsonb1289d62009-04-27 16:37:05 +02002228/*
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002229 * These are tables of eigenvectors (one per line) which can be used for the
2230 * construction of the syndrome tables. The modified syndrome search algorithm
2231 * uses those to find the symbol in error and thus the DIMM.
Doug Thompsonb1289d62009-04-27 16:37:05 +02002232 *
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002233 * Algorithm courtesy of Ross LaFetra from AMD.
Doug Thompsonb1289d62009-04-27 16:37:05 +02002234 */
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08002235static const u16 x4_vectors[] = {
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002236 0x2f57, 0x1afe, 0x66cc, 0xdd88,
2237 0x11eb, 0x3396, 0x7f4c, 0xeac8,
2238 0x0001, 0x0002, 0x0004, 0x0008,
2239 0x1013, 0x3032, 0x4044, 0x8088,
2240 0x106b, 0x30d6, 0x70fc, 0xe0a8,
2241 0x4857, 0xc4fe, 0x13cc, 0x3288,
2242 0x1ac5, 0x2f4a, 0x5394, 0xa1e8,
2243 0x1f39, 0x251e, 0xbd6c, 0x6bd8,
2244 0x15c1, 0x2a42, 0x89ac, 0x4758,
2245 0x2b03, 0x1602, 0x4f0c, 0xca08,
2246 0x1f07, 0x3a0e, 0x6b04, 0xbd08,
2247 0x8ba7, 0x465e, 0x244c, 0x1cc8,
2248 0x2b87, 0x164e, 0x642c, 0xdc18,
2249 0x40b9, 0x80de, 0x1094, 0x20e8,
2250 0x27db, 0x1eb6, 0x9dac, 0x7b58,
2251 0x11c1, 0x2242, 0x84ac, 0x4c58,
2252 0x1be5, 0x2d7a, 0x5e34, 0xa718,
2253 0x4b39, 0x8d1e, 0x14b4, 0x28d8,
2254 0x4c97, 0xc87e, 0x11fc, 0x33a8,
2255 0x8e97, 0x497e, 0x2ffc, 0x1aa8,
2256 0x16b3, 0x3d62, 0x4f34, 0x8518,
2257 0x1e2f, 0x391a, 0x5cac, 0xf858,
2258 0x1d9f, 0x3b7a, 0x572c, 0xfe18,
2259 0x15f5, 0x2a5a, 0x5264, 0xa3b8,
2260 0x1dbb, 0x3b66, 0x715c, 0xe3f8,
2261 0x4397, 0xc27e, 0x17fc, 0x3ea8,
2262 0x1617, 0x3d3e, 0x6464, 0xb8b8,
2263 0x23ff, 0x12aa, 0xab6c, 0x56d8,
2264 0x2dfb, 0x1ba6, 0x913c, 0x7328,
2265 0x185d, 0x2ca6, 0x7914, 0x9e28,
2266 0x171b, 0x3e36, 0x7d7c, 0xebe8,
2267 0x4199, 0x82ee, 0x19f4, 0x2e58,
2268 0x4807, 0xc40e, 0x130c, 0x3208,
2269 0x1905, 0x2e0a, 0x5804, 0xac08,
2270 0x213f, 0x132a, 0xadfc, 0x5ba8,
2271 0x19a9, 0x2efe, 0xb5cc, 0x6f88,
Doug Thompsonb1289d62009-04-27 16:37:05 +02002272};
2273
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08002274static const u16 x8_vectors[] = {
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002275 0x0145, 0x028a, 0x2374, 0x43c8, 0xa1f0, 0x0520, 0x0a40, 0x1480,
2276 0x0211, 0x0422, 0x0844, 0x1088, 0x01b0, 0x44e0, 0x23c0, 0xed80,
2277 0x1011, 0x0116, 0x022c, 0x0458, 0x08b0, 0x8c60, 0x2740, 0x4e80,
2278 0x0411, 0x0822, 0x1044, 0x0158, 0x02b0, 0x2360, 0x46c0, 0xab80,
2279 0x0811, 0x1022, 0x012c, 0x0258, 0x04b0, 0x4660, 0x8cc0, 0x2780,
2280 0x2071, 0x40e2, 0xa0c4, 0x0108, 0x0210, 0x0420, 0x0840, 0x1080,
2281 0x4071, 0x80e2, 0x0104, 0x0208, 0x0410, 0x0820, 0x1040, 0x2080,
2282 0x8071, 0x0102, 0x0204, 0x0408, 0x0810, 0x1020, 0x2040, 0x4080,
2283 0x019d, 0x03d6, 0x136c, 0x2198, 0x50b0, 0xb2e0, 0x0740, 0x0e80,
2284 0x0189, 0x03ea, 0x072c, 0x0e58, 0x1cb0, 0x56e0, 0x37c0, 0xf580,
2285 0x01fd, 0x0376, 0x06ec, 0x0bb8, 0x1110, 0x2220, 0x4440, 0x8880,
2286 0x0163, 0x02c6, 0x1104, 0x0758, 0x0eb0, 0x2be0, 0x6140, 0xc280,
2287 0x02fd, 0x01c6, 0x0b5c, 0x1108, 0x07b0, 0x25a0, 0x8840, 0x6180,
2288 0x0801, 0x012e, 0x025c, 0x04b8, 0x1370, 0x26e0, 0x57c0, 0xb580,
2289 0x0401, 0x0802, 0x015c, 0x02b8, 0x22b0, 0x13e0, 0x7140, 0xe280,
2290 0x0201, 0x0402, 0x0804, 0x01b8, 0x11b0, 0x31a0, 0x8040, 0x7180,
2291 0x0101, 0x0202, 0x0404, 0x0808, 0x1010, 0x2020, 0x4040, 0x8080,
2292 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
2293 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
2294};
2295
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08002296static int decode_syndrome(u16 syndrome, const u16 *vectors, unsigned num_vecs,
Borislav Petkovd34a6ec2011-02-23 17:41:50 +01002297 unsigned v_dim)
Doug Thompsonb1289d62009-04-27 16:37:05 +02002298{
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002299 unsigned int i, err_sym;
Doug Thompsonb1289d62009-04-27 16:37:05 +02002300
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002301 for (err_sym = 0; err_sym < num_vecs / v_dim; err_sym++) {
2302 u16 s = syndrome;
Borislav Petkovd34a6ec2011-02-23 17:41:50 +01002303 unsigned v_idx = err_sym * v_dim;
2304 unsigned v_end = (err_sym + 1) * v_dim;
Doug Thompsonb1289d62009-04-27 16:37:05 +02002305
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002306 /* walk over all 16 bits of the syndrome */
2307 for (i = 1; i < (1U << 16); i <<= 1) {
2308
2309 /* if bit is set in that eigenvector... */
2310 if (v_idx < v_end && vectors[v_idx] & i) {
2311 u16 ev_comp = vectors[v_idx++];
2312
2313 /* ... and bit set in the modified syndrome, */
2314 if (s & i) {
2315 /* remove it. */
2316 s ^= ev_comp;
2317
2318 if (!s)
2319 return err_sym;
2320 }
2321
2322 } else if (s & i)
2323 /* can't get to zero, move to next symbol */
2324 break;
2325 }
Doug Thompsonb1289d62009-04-27 16:37:05 +02002326 }
2327
Joe Perches956b9ba12012-04-29 17:08:39 -03002328 edac_dbg(0, "syndrome(%x) not found\n", syndrome);
Doug Thompsonb1289d62009-04-27 16:37:05 +02002329 return -1;
2330}
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002331
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002332static int map_err_sym_to_channel(int err_sym, int sym_size)
2333{
2334 if (sym_size == 4)
2335 switch (err_sym) {
2336 case 0x20:
2337 case 0x21:
2338 return 0;
2339 break;
2340 case 0x22:
2341 case 0x23:
2342 return 1;
2343 break;
2344 default:
2345 return err_sym >> 4;
2346 break;
2347 }
2348 /* x8 symbols */
2349 else
2350 switch (err_sym) {
2351 /* imaginary bits not in a DIMM */
2352 case 0x10:
2353 WARN(1, KERN_ERR "Invalid error symbol: 0x%x\n",
2354 err_sym);
2355 return -1;
2356 break;
2357
2358 case 0x11:
2359 return 0;
2360 break;
2361 case 0x12:
2362 return 1;
2363 break;
2364 default:
2365 return err_sym >> 3;
2366 break;
2367 }
2368 return -1;
2369}
2370
2371static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
2372{
2373 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002374 int err_sym = -1;
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002375
Borislav Petkova3b7db02011-01-19 20:35:12 +01002376 if (pvt->ecc_sym_sz == 8)
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002377 err_sym = decode_syndrome(syndrome, x8_vectors,
2378 ARRAY_SIZE(x8_vectors),
Borislav Petkova3b7db02011-01-19 20:35:12 +01002379 pvt->ecc_sym_sz);
2380 else if (pvt->ecc_sym_sz == 4)
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002381 err_sym = decode_syndrome(syndrome, x4_vectors,
2382 ARRAY_SIZE(x4_vectors),
Borislav Petkova3b7db02011-01-19 20:35:12 +01002383 pvt->ecc_sym_sz);
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002384 else {
Borislav Petkova3b7db02011-01-19 20:35:12 +01002385 amd64_warn("Illegal syndrome type: %u\n", pvt->ecc_sym_sz);
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002386 return err_sym;
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002387 }
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002388
Borislav Petkova3b7db02011-01-19 20:35:12 +01002389 return map_err_sym_to_channel(err_sym, pvt->ecc_sym_sz);
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01002390}
2391
Yazen Ghanname70984d2016-11-17 17:57:31 -05002392static void __log_ecc_error(struct mem_ctl_info *mci, struct err_info *err,
Borislav Petkov33ca0642012-08-30 18:01:36 +02002393 u8 ecc_type)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002394{
Borislav Petkov33ca0642012-08-30 18:01:36 +02002395 enum hw_event_mc_err_type err_type;
2396 const char *string;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002397
Borislav Petkov33ca0642012-08-30 18:01:36 +02002398 if (ecc_type == 2)
2399 err_type = HW_EVENT_ERR_CORRECTED;
2400 else if (ecc_type == 1)
2401 err_type = HW_EVENT_ERR_UNCORRECTED;
Yazen Ghannamd12a9692016-11-17 17:57:32 -05002402 else if (ecc_type == 3)
2403 err_type = HW_EVENT_ERR_DEFERRED;
Borislav Petkov33ca0642012-08-30 18:01:36 +02002404 else {
2405 WARN(1, "Something is rotten in the state of Denmark.\n");
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002406 return;
2407 }
2408
Borislav Petkov33ca0642012-08-30 18:01:36 +02002409 switch (err->err_code) {
2410 case DECODE_OK:
2411 string = "";
2412 break;
2413 case ERR_NODE:
2414 string = "Failed to map error addr to a node";
2415 break;
2416 case ERR_CSROW:
2417 string = "Failed to map error addr to a csrow";
2418 break;
2419 case ERR_CHANNEL:
Yazen Ghannam713ad542016-11-28 12:59:53 -06002420 string = "Unknown syndrome - possible error reporting race";
2421 break;
2422 case ERR_SYND:
2423 string = "MCA_SYND not valid - unknown syndrome and csrow";
2424 break;
2425 case ERR_NORM_ADDR:
2426 string = "Cannot decode normalized address";
Borislav Petkov33ca0642012-08-30 18:01:36 +02002427 break;
2428 default:
2429 string = "WTF error";
2430 break;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002431 }
Borislav Petkov33ca0642012-08-30 18:01:36 +02002432
2433 edac_mc_handle_error(err_type, mci, 1,
2434 err->page, err->offset, err->syndrome,
2435 err->csrow, err->channel, -1,
2436 string, "");
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002437}
2438
Borislav Petkovdf781d02013-12-15 17:29:44 +01002439static inline void decode_bus_error(int node_id, struct mce *m)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002440{
Daniel J Blueman0c510cc2015-02-17 11:34:38 +08002441 struct mem_ctl_info *mci;
2442 struct amd64_pvt *pvt;
Borislav Petkovf192c7b2011-01-10 14:24:32 +01002443 u8 ecc_type = (m->status >> 45) & 0x3;
Borislav Petkov66fed2d2012-08-09 18:41:07 +02002444 u8 xec = XEC(m->status, 0x1f);
2445 u16 ec = EC(m->status);
Borislav Petkov33ca0642012-08-30 18:01:36 +02002446 u64 sys_addr;
2447 struct err_info err;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002448
Daniel J Blueman0c510cc2015-02-17 11:34:38 +08002449 mci = edac_mc_find(node_id);
2450 if (!mci)
2451 return;
2452
2453 pvt = mci->pvt_info;
2454
Borislav Petkov66fed2d2012-08-09 18:41:07 +02002455 /* Bail out early if this was an 'observed' error */
Borislav Petkov5980bb92011-01-07 16:26:49 +01002456 if (PP(ec) == NBSL_PP_OBS)
Borislav Petkovb70ef012009-06-25 19:32:38 +02002457 return;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002458
Borislav Petkovecaf5602009-07-23 16:32:01 +02002459 /* Do only ECC errors */
2460 if (xec && xec != F10_NBSL_EXT_ERR_ECC)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002461 return;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002462
Borislav Petkov33ca0642012-08-30 18:01:36 +02002463 memset(&err, 0, sizeof(err));
2464
Borislav Petkova4b4bed2013-08-10 13:54:48 +02002465 sys_addr = get_error_address(pvt, m);
Borislav Petkov33ca0642012-08-30 18:01:36 +02002466
Borislav Petkovecaf5602009-07-23 16:32:01 +02002467 if (ecc_type == 2)
Borislav Petkov33ca0642012-08-30 18:01:36 +02002468 err.syndrome = extract_syndrome(m->status);
2469
2470 pvt->ops->map_sysaddr_to_csrow(mci, sys_addr, &err);
2471
Yazen Ghanname70984d2016-11-17 17:57:31 -05002472 __log_ecc_error(mci, &err, ecc_type);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002473}
2474
Doug Thompson0ec449e2009-04-27 19:41:25 +02002475/*
Yazen Ghannam713ad542016-11-28 12:59:53 -06002476 * To find the UMC channel represented by this bank we need to match on its
2477 * instance_id. The instance_id of a bank is held in the lower 32 bits of its
2478 * IPID.
2479 */
2480static int find_umc_channel(struct amd64_pvt *pvt, struct mce *m)
2481{
2482 u32 umc_instance_id[] = {0x50f00, 0x150f00};
2483 u32 instance_id = m->ipid & GENMASK(31, 0);
2484 int i, channel = -1;
2485
2486 for (i = 0; i < ARRAY_SIZE(umc_instance_id); i++)
2487 if (umc_instance_id[i] == instance_id)
2488 channel = i;
2489
2490 return channel;
2491}
2492
2493static void decode_umc_error(int node_id, struct mce *m)
2494{
2495 u8 ecc_type = (m->status >> 45) & 0x3;
2496 struct mem_ctl_info *mci;
2497 struct amd64_pvt *pvt;
2498 struct err_info err;
2499 u64 sys_addr;
2500
2501 mci = edac_mc_find(node_id);
2502 if (!mci)
2503 return;
2504
2505 pvt = mci->pvt_info;
2506
2507 memset(&err, 0, sizeof(err));
2508
2509 if (m->status & MCI_STATUS_DEFERRED)
2510 ecc_type = 3;
2511
2512 err.channel = find_umc_channel(pvt, m);
2513 if (err.channel < 0) {
2514 err.err_code = ERR_CHANNEL;
2515 goto log_error;
2516 }
2517
2518 if (umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, err.channel, &sys_addr)) {
2519 err.err_code = ERR_NORM_ADDR;
2520 goto log_error;
2521 }
2522
2523 error_address_to_page_and_offset(sys_addr, &err);
2524
2525 if (!(m->status & MCI_STATUS_SYNDV)) {
2526 err.err_code = ERR_SYND;
2527 goto log_error;
2528 }
2529
2530 if (ecc_type == 2) {
2531 u8 length = (m->synd >> 18) & 0x3f;
2532
2533 if (length)
2534 err.syndrome = (m->synd >> 32) & GENMASK(length - 1, 0);
2535 else
2536 err.err_code = ERR_CHANNEL;
2537 }
2538
2539 err.csrow = m->synd & 0x7;
2540
2541log_error:
2542 __log_ecc_error(mci, &err, ecc_type);
2543}
2544
2545/*
Borislav Petkov3f37a362016-05-06 19:44:27 +02002546 * Use pvt->F3 which contains the F3 CPU PCI device to get the related
2547 * F1 (AddrMap) and F2 (Dct) devices. Return negative value on error.
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002548 * Reserve F0 and F6 on systems with a UMC.
Doug Thompson0ec449e2009-04-27 19:41:25 +02002549 */
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002550static int
2551reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 pci_id1, u16 pci_id2)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002552{
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002553 if (pvt->umc) {
2554 pvt->F0 = pci_get_related_function(pvt->F3->vendor, pci_id1, pvt->F3);
2555 if (!pvt->F0) {
Borislav Petkov5246c542016-12-01 11:35:07 +01002556 amd64_err("F0 not found, device 0x%x (broken BIOS?)\n", pci_id1);
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002557 return -ENODEV;
2558 }
2559
2560 pvt->F6 = pci_get_related_function(pvt->F3->vendor, pci_id2, pvt->F3);
2561 if (!pvt->F6) {
2562 pci_dev_put(pvt->F0);
2563 pvt->F0 = NULL;
2564
Borislav Petkov5246c542016-12-01 11:35:07 +01002565 amd64_err("F6 not found: device 0x%x (broken BIOS?)\n", pci_id2);
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002566 return -ENODEV;
2567 }
Borislav Petkov5246c542016-12-01 11:35:07 +01002568
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002569 edac_dbg(1, "F0: %s\n", pci_name(pvt->F0));
2570 edac_dbg(1, "F3: %s\n", pci_name(pvt->F3));
2571 edac_dbg(1, "F6: %s\n", pci_name(pvt->F6));
2572
2573 return 0;
2574 }
2575
Doug Thompson0ec449e2009-04-27 19:41:25 +02002576 /* Reserve the ADDRESS MAP Device */
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002577 pvt->F1 = pci_get_related_function(pvt->F3->vendor, pci_id1, pvt->F3);
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002578 if (!pvt->F1) {
Borislav Petkov5246c542016-12-01 11:35:07 +01002579 amd64_err("F1 not found: device 0x%x (broken BIOS?)\n", pci_id1);
Borislav Petkovbbd0c1f62010-10-01 19:27:58 +02002580 return -ENODEV;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002581 }
2582
Borislav Petkov3f37a362016-05-06 19:44:27 +02002583 /* Reserve the DCT Device */
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002584 pvt->F2 = pci_get_related_function(pvt->F3->vendor, pci_id2, pvt->F3);
Borislav Petkov3f37a362016-05-06 19:44:27 +02002585 if (!pvt->F2) {
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002586 pci_dev_put(pvt->F1);
2587 pvt->F1 = NULL;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002588
Borislav Petkov5246c542016-12-01 11:35:07 +01002589 amd64_err("F2 not found: device 0x%x (broken BIOS?)\n", pci_id2);
2590 return -ENODEV;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002591 }
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002592
Joe Perches956b9ba12012-04-29 17:08:39 -03002593 edac_dbg(1, "F1: %s\n", pci_name(pvt->F1));
2594 edac_dbg(1, "F2: %s\n", pci_name(pvt->F2));
2595 edac_dbg(1, "F3: %s\n", pci_name(pvt->F3));
Doug Thompson0ec449e2009-04-27 19:41:25 +02002596
2597 return 0;
2598}
2599
Borislav Petkov360b7f32010-10-15 19:25:38 +02002600static void free_mc_sibling_devs(struct amd64_pvt *pvt)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002601{
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05002602 if (pvt->umc) {
2603 pci_dev_put(pvt->F0);
2604 pci_dev_put(pvt->F6);
2605 } else {
2606 pci_dev_put(pvt->F1);
2607 pci_dev_put(pvt->F2);
2608 }
Doug Thompson0ec449e2009-04-27 19:41:25 +02002609}
2610
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002611static void determine_ecc_sym_sz(struct amd64_pvt *pvt)
2612{
2613 pvt->ecc_sym_sz = 4;
2614
2615 if (pvt->umc) {
2616 u8 i;
2617
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +00002618 for_each_umc(i) {
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002619 /* Check enabled channels only: */
2620 if ((pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) &&
2621 (pvt->umc[i].ecc_ctrl & BIT(7))) {
2622 pvt->ecc_sym_sz = 8;
2623 break;
2624 }
2625 }
2626
2627 return;
2628 }
2629
2630 if (pvt->fam >= 0x10) {
2631 u32 tmp;
2632
2633 amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
2634 /* F16h has only DCT0, so no need to read dbam1. */
2635 if (pvt->fam != 0x16)
2636 amd64_read_dct_pci_cfg(pvt, 1, DBAM0, &pvt->dbam1);
2637
2638 /* F10h, revD and later can do x8 ECC too. */
2639 if ((pvt->fam > 0x10 || pvt->model > 7) && tmp & BIT(25))
2640 pvt->ecc_sym_sz = 8;
2641 }
2642}
2643
2644/*
2645 * Retrieve the hardware registers of the memory controller.
2646 */
2647static void __read_mc_regs_df(struct amd64_pvt *pvt)
2648{
2649 u8 nid = pvt->mc_node_id;
2650 struct amd64_umc *umc;
2651 u32 i, umc_base;
2652
2653 /* Read registers from each UMC */
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +00002654 for_each_umc(i) {
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002655
2656 umc_base = get_umc_base(i);
2657 umc = &pvt->umc[i];
2658
Yazen Ghannam07ed82e2016-11-28 08:50:21 -06002659 amd_smn_read(nid, umc_base + UMCCH_DIMM_CFG, &umc->dimm_cfg);
2660 amd_smn_read(nid, umc_base + UMCCH_UMC_CFG, &umc->umc_cfg);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002661 amd_smn_read(nid, umc_base + UMCCH_SDP_CTRL, &umc->sdp_ctrl);
2662 amd_smn_read(nid, umc_base + UMCCH_ECC_CTRL, &umc->ecc_ctrl);
Yazen Ghannam07ed82e2016-11-28 08:50:21 -06002663 amd_smn_read(nid, umc_base + UMCCH_UMC_CAP_HI, &umc->umc_cap_hi);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002664 }
2665}
2666
Doug Thompson0ec449e2009-04-27 19:41:25 +02002667/*
2668 * Retrieve the hardware registers of the memory controller (this includes the
2669 * 'Address Map' and 'Misc' device regs)
2670 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02002671static void read_mc_regs(struct amd64_pvt *pvt)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002672{
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002673 unsigned int range;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002674 u64 msr_val;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002675
2676 /*
2677 * Retrieve TOP_MEM and TOP_MEM2; no masking off of reserved bits since
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002678 * those are Read-As-Zero.
Doug Thompson0ec449e2009-04-27 19:41:25 +02002679 */
Borislav Petkove97f8bb2009-10-12 15:27:45 +02002680 rdmsrl(MSR_K8_TOP_MEM1, pvt->top_mem);
Joe Perches956b9ba12012-04-29 17:08:39 -03002681 edac_dbg(0, " TOP_MEM: 0x%016llx\n", pvt->top_mem);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002682
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002683 /* Check first whether TOP_MEM2 is enabled: */
Doug Thompson0ec449e2009-04-27 19:41:25 +02002684 rdmsrl(MSR_K8_SYSCFG, msr_val);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002685 if (msr_val & BIT(21)) {
Borislav Petkove97f8bb2009-10-12 15:27:45 +02002686 rdmsrl(MSR_K8_TOP_MEM2, pvt->top_mem2);
Joe Perches956b9ba12012-04-29 17:08:39 -03002687 edac_dbg(0, " TOP_MEM2: 0x%016llx\n", pvt->top_mem2);
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002688 } else {
Joe Perches956b9ba12012-04-29 17:08:39 -03002689 edac_dbg(0, " TOP_MEM2 disabled\n");
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002690 }
2691
2692 if (pvt->umc) {
2693 __read_mc_regs_df(pvt);
2694 amd64_read_pci_cfg(pvt->F0, DF_DHAR, &pvt->dhar);
2695
2696 goto skip;
2697 }
Doug Thompson0ec449e2009-04-27 19:41:25 +02002698
Borislav Petkov5980bb92011-01-07 16:26:49 +01002699 amd64_read_pci_cfg(pvt->F3, NBCAP, &pvt->nbcap);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002700
Borislav Petkov5a5d2372011-01-17 17:52:57 +01002701 read_dram_ctl_register(pvt);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002702
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002703 for (range = 0; range < DRAM_RANGES; range++) {
2704 u8 rw;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002705
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002706 /* read settings for this DRAM range */
2707 read_dram_base_limit_regs(pvt, range);
Borislav Petkove97f8bb2009-10-12 15:27:45 +02002708
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002709 rw = dram_rw(pvt, range);
2710 if (!rw)
2711 continue;
2712
Joe Perches956b9ba12012-04-29 17:08:39 -03002713 edac_dbg(1, " DRAM range[%d], base: 0x%016llx; limit: 0x%016llx\n",
2714 range,
2715 get_dram_base(pvt, range),
2716 get_dram_limit(pvt, range));
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002717
Joe Perches956b9ba12012-04-29 17:08:39 -03002718 edac_dbg(1, " IntlvEn=%s; Range access: %s%s IntlvSel=%d DstNode=%d\n",
2719 dram_intlv_en(pvt, range) ? "Enabled" : "Disabled",
2720 (rw & 0x1) ? "R" : "-",
2721 (rw & 0x2) ? "W" : "-",
2722 dram_intlv_sel(pvt, range),
2723 dram_dst_node(pvt, range));
Doug Thompson0ec449e2009-04-27 19:41:25 +02002724 }
2725
Borislav Petkovbc21fa52010-11-11 17:29:13 +01002726 amd64_read_pci_cfg(pvt->F1, DHAR, &pvt->dhar);
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05002727 amd64_read_dct_pci_cfg(pvt, 0, DBAM0, &pvt->dbam0);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002728
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002729 amd64_read_pci_cfg(pvt->F3, F10_ONLINE_SPARE, &pvt->online_spare);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002730
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05002731 amd64_read_dct_pci_cfg(pvt, 0, DCLR0, &pvt->dclr0);
2732 amd64_read_dct_pci_cfg(pvt, 0, DCHR0, &pvt->dchr0);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002733
Borislav Petkov78da1212010-12-22 19:31:45 +01002734 if (!dct_ganging_enabled(pvt)) {
Aravind Gopalakrishnan7981a282014-09-15 11:37:38 -05002735 amd64_read_dct_pci_cfg(pvt, 1, DCLR0, &pvt->dclr1);
2736 amd64_read_dct_pci_cfg(pvt, 1, DCHR0, &pvt->dchr1);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002737 }
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002738
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002739skip:
2740 read_dct_base_mask(pvt);
2741
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002742 determine_memory_type(pvt);
2743 edac_dbg(1, " DIMM type: %s\n", edac_mem_types[pvt->dram_type]);
Borislav Petkova3b7db02011-01-19 20:35:12 +01002744
Yazen Ghannamb64ce7c2016-11-17 17:57:37 -05002745 determine_ecc_sym_sz(pvt);
Borislav Petkova3b7db02011-01-19 20:35:12 +01002746
Borislav Petkovb2b0c602010-10-08 18:32:29 +02002747 dump_misc_regs(pvt);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002748}
2749
2750/*
2751 * NOTE: CPU Revision Dependent code
2752 *
2753 * Input:
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002754 * @csrow_nr ChipSelect Row Number (0..NUM_CHIPSELECTS-1)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002755 * k8 private pointer to -->
2756 * DRAM Bank Address mapping register
2757 * node_id
2758 * DCL register where dual_channel_active is
2759 *
2760 * The DBAM register consists of 4 sets of 4 bits each definitions:
2761 *
2762 * Bits: CSROWs
2763 * 0-3 CSROWs 0 and 1
2764 * 4-7 CSROWs 2 and 3
2765 * 8-11 CSROWs 4 and 5
2766 * 12-15 CSROWs 6 and 7
2767 *
2768 * Values range from: 0 to 15
2769 * The meaning of the values depends on CPU revision and dual-channel state,
2770 * see relevant BKDG more info.
2771 *
2772 * The memory controller provides for total of only 8 CSROWs in its current
2773 * architecture. Each "pair" of CSROWs normally represents just one DIMM in
2774 * single channel or two (2) DIMMs in dual channel mode.
2775 *
2776 * The following code logic collapses the various tables for CSROW based on CPU
2777 * revision.
2778 *
2779 * Returns:
2780 * The number of PAGE_SIZE pages on the specified CSROW number it
2781 * encompasses
2782 *
2783 */
Yazen Ghannameb77e6b2017-04-27 12:11:54 -05002784static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr_orig)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002785{
Ashish Shenoyf92cae42012-02-22 17:20:38 -08002786 u32 dbam = dct ? pvt->dbam1 : pvt->dbam0;
Yazen Ghannameb77e6b2017-04-27 12:11:54 -05002787 int csrow_nr = csrow_nr_orig;
2788 u32 cs_mode, nr_pages;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002789
Yazen Ghannameb77e6b2017-04-27 12:11:54 -05002790 if (!pvt->umc)
2791 csrow_nr >>= 1;
Borislav Petkov10de6492012-09-12 19:00:38 +02002792
Yazen Ghannameb77e6b2017-04-27 12:11:54 -05002793 cs_mode = DBAM_DIMM(csrow_nr, dbam);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002794
Yazen Ghannameb77e6b2017-04-27 12:11:54 -05002795 nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode, csrow_nr);
2796 nr_pages <<= 20 - PAGE_SHIFT;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002797
Borislav Petkov10de6492012-09-12 19:00:38 +02002798 edac_dbg(0, "csrow: %d, channel: %d, DBAM idx: %d\n",
Yazen Ghannameb77e6b2017-04-27 12:11:54 -05002799 csrow_nr_orig, dct, cs_mode);
Borislav Petkov10de6492012-09-12 19:00:38 +02002800 edac_dbg(0, "nr_pages/channel: %u\n", nr_pages);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002801
2802 return nr_pages;
2803}
2804
2805/*
2806 * Initialize the array of csrow attribute instances, based on the values
2807 * from pci config hardware registers.
2808 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02002809static int init_csrows(struct mem_ctl_info *mci)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002810{
Borislav Petkov10de6492012-09-12 19:00:38 +02002811 struct amd64_pvt *pvt = mci->pvt_info;
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06002812 enum edac_type edac_mode = EDAC_NONE;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002813 struct csrow_info *csrow;
Mauro Carvalho Chehabde3910eb2012-04-24 15:05:43 -03002814 struct dimm_info *dimm;
Borislav Petkov10de6492012-09-12 19:00:38 +02002815 int i, j, empty = 1;
Mauro Carvalho Chehaba895bf82012-01-28 09:09:38 -03002816 int nr_pages = 0;
Borislav Petkov10de6492012-09-12 19:00:38 +02002817 u32 val;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002818
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06002819 if (!pvt->umc) {
2820 amd64_read_pci_cfg(pvt->F3, NBCFG, &val);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002821
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06002822 pvt->nbcfg = val;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002823
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06002824 edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
2825 pvt->mc_node_id, val,
2826 !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
2827 }
Doug Thompson0ec449e2009-04-27 19:41:25 +02002828
Borislav Petkov10de6492012-09-12 19:00:38 +02002829 /*
2830 * We iterate over DCT0 here but we look at DCT1 in parallel, if needed.
2831 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002832 for_each_chip_select(i, 0, pvt) {
Borislav Petkov10de6492012-09-12 19:00:38 +02002833 bool row_dct0 = !!csrow_enabled(i, 0, pvt);
2834 bool row_dct1 = false;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002835
Borislav Petkova4b4bed2013-08-10 13:54:48 +02002836 if (pvt->fam != 0xf)
Borislav Petkov10de6492012-09-12 19:00:38 +02002837 row_dct1 = !!csrow_enabled(i, 1, pvt);
2838
2839 if (!row_dct0 && !row_dct1)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002840 continue;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002841
Borislav Petkov10de6492012-09-12 19:00:38 +02002842 csrow = mci->csrows[i];
Doug Thompson0ec449e2009-04-27 19:41:25 +02002843 empty = 0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002844
Borislav Petkov10de6492012-09-12 19:00:38 +02002845 edac_dbg(1, "MC node: %d, csrow: %d\n",
2846 pvt->mc_node_id, i);
2847
Mauro Carvalho Chehab1eef1282013-03-11 09:07:46 -03002848 if (row_dct0) {
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01002849 nr_pages = get_csrow_nr_pages(pvt, 0, i);
Mauro Carvalho Chehab1eef1282013-03-11 09:07:46 -03002850 csrow->channels[0]->dimm->nr_pages = nr_pages;
2851 }
Borislav Petkov10de6492012-09-12 19:00:38 +02002852
2853 /* K8 has only one DCT */
Borislav Petkova4b4bed2013-08-10 13:54:48 +02002854 if (pvt->fam != 0xf && row_dct1) {
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01002855 int row_dct1_pages = get_csrow_nr_pages(pvt, 1, i);
Mauro Carvalho Chehab1eef1282013-03-11 09:07:46 -03002856
2857 csrow->channels[1]->dimm->nr_pages = row_dct1_pages;
2858 nr_pages += row_dct1_pages;
2859 }
Doug Thompson0ec449e2009-04-27 19:41:25 +02002860
Borislav Petkov10de6492012-09-12 19:00:38 +02002861 edac_dbg(1, "Total csrow%d pages: %u\n", i, nr_pages);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002862
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06002863 /* Determine DIMM ECC mode: */
2864 if (pvt->umc) {
2865 if (mci->edac_ctl_cap & EDAC_FLAG_S4ECD4ED)
2866 edac_mode = EDAC_S4ECD4ED;
2867 else if (mci->edac_ctl_cap & EDAC_FLAG_SECDED)
2868 edac_mode = EDAC_SECDED;
2869
2870 } else if (pvt->nbcfg & NBCFG_ECC_ENABLE) {
2871 edac_mode = (pvt->nbcfg & NBCFG_CHIPKILL)
2872 ? EDAC_S4ECD4ED
2873 : EDAC_SECDED;
2874 }
Mauro Carvalho Chehab084a4fc2012-01-27 18:38:08 -03002875
2876 for (j = 0; j < pvt->channel_count; j++) {
Mauro Carvalho Chehabde3910eb2012-04-24 15:05:43 -03002877 dimm = csrow->channels[j]->dimm;
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01002878 dimm->mtype = pvt->dram_type;
Mauro Carvalho Chehabde3910eb2012-04-24 15:05:43 -03002879 dimm->edac_mode = edac_mode;
Mauro Carvalho Chehab084a4fc2012-01-27 18:38:08 -03002880 }
Doug Thompson0ec449e2009-04-27 19:41:25 +02002881 }
2882
2883 return empty;
2884}
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002885
Borislav Petkov06724532009-09-16 13:05:46 +02002886/* get all cores on this DCT */
Daniel J Blueman8b84c8d2012-11-27 14:32:10 +08002887static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, u16 nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02002888{
Borislav Petkov06724532009-09-16 13:05:46 +02002889 int cpu;
Doug Thompsonf9431992009-04-27 19:46:08 +02002890
Borislav Petkov06724532009-09-16 13:05:46 +02002891 for_each_online_cpu(cpu)
2892 if (amd_get_nb_id(cpu) == nid)
2893 cpumask_set_cpu(cpu, mask);
Doug Thompsonf9431992009-04-27 19:46:08 +02002894}
2895
2896/* check MCG_CTL on all the cpus on this node */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01002897static bool nb_mce_bank_enabled_on_node(u16 nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02002898{
Rusty Russellba578cb2009-11-03 14:56:35 +10302899 cpumask_var_t mask;
Borislav Petkov50542252009-12-11 18:14:40 +01002900 int cpu, nbe;
Borislav Petkov06724532009-09-16 13:05:46 +02002901 bool ret = false;
Doug Thompsonf9431992009-04-27 19:46:08 +02002902
Rusty Russellba578cb2009-11-03 14:56:35 +10302903 if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002904 amd64_warn("%s: Error allocating mask\n", __func__);
Rusty Russellba578cb2009-11-03 14:56:35 +10302905 return false;
2906 }
Borislav Petkov06724532009-09-16 13:05:46 +02002907
Rusty Russellba578cb2009-11-03 14:56:35 +10302908 get_cpus_on_this_dct_cpumask(mask, nid);
Borislav Petkov06724532009-09-16 13:05:46 +02002909
Rusty Russellba578cb2009-11-03 14:56:35 +10302910 rdmsr_on_cpus(mask, MSR_IA32_MCG_CTL, msrs);
Borislav Petkov06724532009-09-16 13:05:46 +02002911
Rusty Russellba578cb2009-11-03 14:56:35 +10302912 for_each_cpu(cpu, mask) {
Borislav Petkov50542252009-12-11 18:14:40 +01002913 struct msr *reg = per_cpu_ptr(msrs, cpu);
Borislav Petkov5980bb92011-01-07 16:26:49 +01002914 nbe = reg->l & MSR_MCGCTL_NBE;
Borislav Petkov06724532009-09-16 13:05:46 +02002915
Joe Perches956b9ba12012-04-29 17:08:39 -03002916 edac_dbg(0, "core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n",
2917 cpu, reg->q,
2918 (nbe ? "enabled" : "disabled"));
Borislav Petkov06724532009-09-16 13:05:46 +02002919
2920 if (!nbe)
2921 goto out;
Borislav Petkov06724532009-09-16 13:05:46 +02002922 }
2923 ret = true;
2924
2925out:
Rusty Russellba578cb2009-11-03 14:56:35 +10302926 free_cpumask_var(mask);
Doug Thompsonf9431992009-04-27 19:46:08 +02002927 return ret;
2928}
2929
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08002930static int toggle_ecc_err_reporting(struct ecc_settings *s, u16 nid, bool on)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002931{
2932 cpumask_var_t cmask;
Borislav Petkov50542252009-12-11 18:14:40 +01002933 int cpu;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002934
2935 if (!zalloc_cpumask_var(&cmask, GFP_KERNEL)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002936 amd64_warn("%s: error allocating mask\n", __func__);
Pan Bian0de278842016-12-04 14:07:18 +08002937 return -ENOMEM;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002938 }
2939
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002940 get_cpus_on_this_dct_cpumask(cmask, nid);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002941
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002942 rdmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
2943
2944 for_each_cpu(cpu, cmask) {
2945
Borislav Petkov50542252009-12-11 18:14:40 +01002946 struct msr *reg = per_cpu_ptr(msrs, cpu);
2947
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002948 if (on) {
Borislav Petkov5980bb92011-01-07 16:26:49 +01002949 if (reg->l & MSR_MCGCTL_NBE)
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002950 s->flags.nb_mce_enable = 1;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002951
Borislav Petkov5980bb92011-01-07 16:26:49 +01002952 reg->l |= MSR_MCGCTL_NBE;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002953 } else {
2954 /*
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002955 * Turn off NB MCE reporting only when it was off before
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002956 */
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002957 if (!s->flags.nb_mce_enable)
Borislav Petkov5980bb92011-01-07 16:26:49 +01002958 reg->l &= ~MSR_MCGCTL_NBE;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002959 }
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002960 }
2961 wrmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
2962
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002963 free_cpumask_var(cmask);
2964
2965 return 0;
2966}
2967
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08002968static bool enable_ecc_error_reporting(struct ecc_settings *s, u16 nid,
Borislav Petkov2299ef72010-10-15 17:44:04 +02002969 struct pci_dev *F3)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002970{
Borislav Petkov2299ef72010-10-15 17:44:04 +02002971 bool ret = true;
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002972 u32 value, mask = 0x3; /* UECC/CECC enable */
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002973
Borislav Petkov2299ef72010-10-15 17:44:04 +02002974 if (toggle_ecc_err_reporting(s, nid, ON)) {
2975 amd64_warn("Error enabling ECC reporting over MCGCTL!\n");
2976 return false;
2977 }
2978
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002979 amd64_read_pci_cfg(F3, NBCTL, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002980
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002981 s->old_nbctl = value & mask;
2982 s->nbctl_valid = true;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002983
2984 value |= mask;
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002985 amd64_write_pci_cfg(F3, NBCTL, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002986
Borislav Petkova97fa682010-12-23 14:07:18 +01002987 amd64_read_pci_cfg(F3, NBCFG, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002988
Joe Perches956b9ba12012-04-29 17:08:39 -03002989 edac_dbg(0, "1: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
2990 nid, value, !!(value & NBCFG_ECC_ENABLE));
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002991
Borislav Petkova97fa682010-12-23 14:07:18 +01002992 if (!(value & NBCFG_ECC_ENABLE)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002993 amd64_warn("DRAM ECC disabled on this node, enabling...\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002994
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002995 s->flags.nb_ecc_prev = 0;
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002996
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002997 /* Attempt to turn on DRAM ECC Enable */
Borislav Petkova97fa682010-12-23 14:07:18 +01002998 value |= NBCFG_ECC_ENABLE;
2999 amd64_write_pci_cfg(F3, NBCFG, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003000
Borislav Petkova97fa682010-12-23 14:07:18 +01003001 amd64_read_pci_cfg(F3, NBCFG, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003002
Borislav Petkova97fa682010-12-23 14:07:18 +01003003 if (!(value & NBCFG_ECC_ENABLE)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02003004 amd64_warn("Hardware rejected DRAM ECC enable,"
3005 "check memory DIMM configuration.\n");
Borislav Petkov2299ef72010-10-15 17:44:04 +02003006 ret = false;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003007 } else {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02003008 amd64_info("Hardware accepted DRAM ECC Enable\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003009 }
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01003010 } else {
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003011 s->flags.nb_ecc_prev = 1;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003012 }
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01003013
Joe Perches956b9ba12012-04-29 17:08:39 -03003014 edac_dbg(0, "2: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
3015 nid, value, !!(value & NBCFG_ECC_ENABLE));
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003016
Borislav Petkov2299ef72010-10-15 17:44:04 +02003017 return ret;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003018}
3019
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08003020static void restore_ecc_error_reporting(struct ecc_settings *s, u16 nid,
Borislav Petkov360b7f32010-10-15 19:25:38 +02003021 struct pci_dev *F3)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003022{
Borislav Petkovc9f4f262010-12-22 19:48:20 +01003023 u32 value, mask = 0x3; /* UECC/CECC enable */
3024
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003025 if (!s->nbctl_valid)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003026 return;
3027
Borislav Petkovc9f4f262010-12-22 19:48:20 +01003028 amd64_read_pci_cfg(F3, NBCTL, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003029 value &= ~mask;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003030 value |= s->old_nbctl;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003031
Borislav Petkovc9f4f262010-12-22 19:48:20 +01003032 amd64_write_pci_cfg(F3, NBCTL, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003033
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003034 /* restore previous BIOS DRAM ECC "off" setting we force-enabled */
3035 if (!s->flags.nb_ecc_prev) {
Borislav Petkova97fa682010-12-23 14:07:18 +01003036 amd64_read_pci_cfg(F3, NBCFG, &value);
3037 value &= ~NBCFG_ECC_ENABLE;
3038 amd64_write_pci_cfg(F3, NBCFG, value);
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01003039 }
3040
3041 /* restore the NB Enable MCGCTL bit */
Borislav Petkov2299ef72010-10-15 17:44:04 +02003042 if (toggle_ecc_err_reporting(s, nid, OFF))
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02003043 amd64_warn("Error restoring NB MCGCTL settings!\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01003044}
3045
Doug Thompsonf9431992009-04-27 19:46:08 +02003046/*
Borislav Petkov2299ef72010-10-15 17:44:04 +02003047 * EDAC requires that the BIOS have ECC enabled before
3048 * taking over the processing of ECC errors. A command line
3049 * option allows to force-enable hardware ECC later in
3050 * enable_ecc_error_reporting().
Doug Thompsonf9431992009-04-27 19:46:08 +02003051 */
Borislav Petkovcab4d272010-02-11 17:15:57 +01003052static const char *ecc_msg =
3053 "ECC disabled in the BIOS or no ECC capability, module will not load.\n"
3054 " Either enable ECC checking or force module loading by setting "
3055 "'ecc_enable_override'.\n"
3056 " (Note that use of the override may cause unknown side effects.)\n";
Borislav Petkovbe3468e2009-08-05 15:47:22 +02003057
Daniel J Bluemanc7e53012012-11-30 16:44:20 +08003058static bool ecc_enabled(struct pci_dev *F3, u16 nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02003059{
Borislav Petkov06724532009-09-16 13:05:46 +02003060 bool nb_mce_en = false;
Yazen Ghannam196b79f2016-11-17 17:57:34 -05003061 u8 ecc_en = 0, i;
3062 u32 value;
Doug Thompsonf9431992009-04-27 19:46:08 +02003063
Yazen Ghannam196b79f2016-11-17 17:57:34 -05003064 if (boot_cpu_data.x86 >= 0x17) {
3065 u8 umc_en_mask = 0, ecc_en_mask = 0;
Doug Thompsonf9431992009-04-27 19:46:08 +02003066
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +00003067 for_each_umc(i) {
Yazen Ghannam196b79f2016-11-17 17:57:34 -05003068 u32 base = get_umc_base(i);
3069
3070 /* Only check enabled UMCs. */
3071 if (amd_smn_read(nid, base + UMCCH_SDP_CTRL, &value))
3072 continue;
3073
3074 if (!(value & UMC_SDP_INIT))
3075 continue;
3076
3077 umc_en_mask |= BIT(i);
3078
3079 if (amd_smn_read(nid, base + UMCCH_UMC_CAP_HI, &value))
3080 continue;
3081
3082 if (value & UMC_ECC_ENABLED)
3083 ecc_en_mask |= BIT(i);
3084 }
3085
3086 /* Check whether at least one UMC is enabled: */
3087 if (umc_en_mask)
3088 ecc_en = umc_en_mask == ecc_en_mask;
Yazen Ghannam11ab1ca2017-01-27 11:24:19 -06003089 else
3090 edac_dbg(0, "Node %d: No enabled UMCs.\n", nid);
Yazen Ghannam196b79f2016-11-17 17:57:34 -05003091
3092 /* Assume UMC MCA banks are enabled. */
3093 nb_mce_en = true;
3094 } else {
3095 amd64_read_pci_cfg(F3, NBCFG, &value);
3096
3097 ecc_en = !!(value & NBCFG_ECC_ENABLE);
3098
3099 nb_mce_en = nb_mce_bank_enabled_on_node(nid);
3100 if (!nb_mce_en)
Yazen Ghannam11ab1ca2017-01-27 11:24:19 -06003101 edac_dbg(0, "NB MCE bank disabled, set MSR 0x%08x[4] on node %d to enable.\n",
Yazen Ghannam196b79f2016-11-17 17:57:34 -05003102 MSR_IA32_MCG_CTL, nid);
3103 }
3104
Yazen Ghannam11ab1ca2017-01-27 11:24:19 -06003105 amd64_info("Node %d: DRAM ECC %s.\n",
3106 nid, (ecc_en ? "enabled" : "disabled"));
Doug Thompsonf9431992009-04-27 19:46:08 +02003107
Borislav Petkov2299ef72010-10-15 17:44:04 +02003108 if (!ecc_en || !nb_mce_en) {
Yazen Ghannam11ab1ca2017-01-27 11:24:19 -06003109 amd64_info("%s", ecc_msg);
Borislav Petkov2299ef72010-10-15 17:44:04 +02003110 return false;
Borislav Petkov43f5e682009-12-21 18:55:18 +01003111 }
Borislav Petkov2299ef72010-10-15 17:44:04 +02003112 return true;
Doug Thompsonf9431992009-04-27 19:46:08 +02003113}
3114
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06003115static inline void
3116f17h_determine_edac_ctl_cap(struct mem_ctl_info *mci, struct amd64_pvt *pvt)
3117{
3118 u8 i, ecc_en = 1, cpk_en = 1;
3119
Yazen Ghannam4d30d2b2019-02-28 15:36:10 +00003120 for_each_umc(i) {
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06003121 if (pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) {
3122 ecc_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_ENABLED);
3123 cpk_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_CHIPKILL_CAP);
3124 }
3125 }
3126
3127 /* Set chipkill only if ECC is enabled: */
3128 if (ecc_en) {
3129 mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
3130
3131 if (cpk_en)
3132 mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
3133 }
3134}
3135
Borislav Petkovdf71a052011-01-19 18:15:10 +01003136static void setup_mci_misc_attrs(struct mem_ctl_info *mci,
3137 struct amd64_family_type *fam)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003138{
3139 struct amd64_pvt *pvt = mci->pvt_info;
3140
3141 mci->mtype_cap = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2;
3142 mci->edac_ctl_cap = EDAC_FLAG_NONE;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003143
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06003144 if (pvt->umc) {
3145 f17h_determine_edac_ctl_cap(mci, pvt);
3146 } else {
3147 if (pvt->nbcap & NBCAP_SECDED)
3148 mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003149
Yazen Ghannam2d09d8f2016-11-29 08:51:56 -06003150 if (pvt->nbcap & NBCAP_CHIPKILL)
3151 mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
3152 }
Doug Thompson7d6034d2009-04-27 20:01:01 +02003153
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003154 mci->edac_cap = determine_edac_cap(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003155 mci->mod_name = EDAC_MOD_STR;
Borislav Petkovdf71a052011-01-19 18:15:10 +01003156 mci->ctl_name = fam->ctl_name;
Yazen Ghanname7934b72016-11-17 17:57:30 -05003157 mci->dev_name = pci_name(pvt->F3);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003158 mci->ctl_page_to_phys = NULL;
3159
Doug Thompson7d6034d2009-04-27 20:01:01 +02003160 /* memory scrubber interface */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003161 mci->set_sdram_scrub_rate = set_scrub_rate;
3162 mci->get_sdram_scrub_rate = get_scrub_rate;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003163}
3164
Borislav Petkov0092b202010-10-01 19:20:05 +02003165/*
3166 * returns a pointer to the family descriptor on success, NULL otherwise.
3167 */
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003168static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
Borislav Petkov395ae782010-10-01 18:38:19 +02003169{
Borislav Petkov0092b202010-10-01 19:20:05 +02003170 struct amd64_family_type *fam_type = NULL;
3171
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003172 pvt->ext_model = boot_cpu_data.x86_model >> 4;
Jia Zhangb3991512018-01-01 09:52:10 +08003173 pvt->stepping = boot_cpu_data.x86_stepping;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003174 pvt->model = boot_cpu_data.x86_model;
3175 pvt->fam = boot_cpu_data.x86;
3176
3177 switch (pvt->fam) {
Borislav Petkov395ae782010-10-01 18:38:19 +02003178 case 0xf:
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003179 fam_type = &family_types[K8_CPUS];
3180 pvt->ops = &family_types[K8_CPUS].ops;
Borislav Petkov395ae782010-10-01 18:38:19 +02003181 break;
Borislav Petkovdf71a052011-01-19 18:15:10 +01003182
Borislav Petkov395ae782010-10-01 18:38:19 +02003183 case 0x10:
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003184 fam_type = &family_types[F10_CPUS];
3185 pvt->ops = &family_types[F10_CPUS].ops;
Borislav Petkovdf71a052011-01-19 18:15:10 +01003186 break;
3187
3188 case 0x15:
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003189 if (pvt->model == 0x30) {
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003190 fam_type = &family_types[F15_M30H_CPUS];
3191 pvt->ops = &family_types[F15_M30H_CPUS].ops;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003192 break;
Aravind Gopalakrishnana597d2a2014-10-30 12:16:09 +01003193 } else if (pvt->model == 0x60) {
3194 fam_type = &family_types[F15_M60H_CPUS];
3195 pvt->ops = &family_types[F15_M60H_CPUS].ops;
3196 break;
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003197 }
3198
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003199 fam_type = &family_types[F15_CPUS];
3200 pvt->ops = &family_types[F15_CPUS].ops;
Borislav Petkov395ae782010-10-01 18:38:19 +02003201 break;
3202
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05003203 case 0x16:
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -06003204 if (pvt->model == 0x30) {
3205 fam_type = &family_types[F16_M30H_CPUS];
3206 pvt->ops = &family_types[F16_M30H_CPUS].ops;
3207 break;
3208 }
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003209 fam_type = &family_types[F16_CPUS];
3210 pvt->ops = &family_types[F16_CPUS].ops;
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -05003211 break;
3212
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05003213 case 0x17:
Michael Jin8960de42018-08-16 15:28:40 -04003214 if (pvt->model >= 0x10 && pvt->model <= 0x2f) {
3215 fam_type = &family_types[F17_M10H_CPUS];
3216 pvt->ops = &family_types[F17_M10H_CPUS].ops;
3217 break;
Yazen Ghannam6e8462392019-02-28 15:36:09 +00003218 } else if (pvt->model >= 0x30 && pvt->model <= 0x3f) {
3219 fam_type = &family_types[F17_M30H_CPUS];
3220 pvt->ops = &family_types[F17_M30H_CPUS].ops;
3221 break;
Michael Jin8960de42018-08-16 15:28:40 -04003222 }
Pu Wenc4a3e942018-09-27 16:31:28 +02003223 /* fall through */
3224 case 0x18:
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05003225 fam_type = &family_types[F17_CPUS];
3226 pvt->ops = &family_types[F17_CPUS].ops;
Pu Wenc4a3e942018-09-27 16:31:28 +02003227
3228 if (pvt->fam == 0x18)
3229 family_types[F17_CPUS].ctl_name = "F18h";
Yazen Ghannamf1cbbec2016-11-17 17:57:35 -05003230 break;
3231
Borislav Petkov395ae782010-10-01 18:38:19 +02003232 default:
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02003233 amd64_err("Unsupported family!\n");
Borislav Petkov0092b202010-10-01 19:20:05 +02003234 return NULL;
Borislav Petkov395ae782010-10-01 18:38:19 +02003235 }
Borislav Petkov0092b202010-10-01 19:20:05 +02003236
Borislav Petkovdf71a052011-01-19 18:15:10 +01003237 amd64_info("%s %sdetected (node %d).\n", fam_type->ctl_name,
Aravind Gopalakrishnan18b94f62013-08-09 11:54:49 -05003238 (pvt->fam == 0xf ?
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02003239 (pvt->ext_model >= K8_REV_F ? "revF or later "
3240 : "revE or earlier ")
3241 : ""), pvt->mc_node_id);
Borislav Petkov0092b202010-10-01 19:20:05 +02003242 return fam_type;
Borislav Petkov395ae782010-10-01 18:38:19 +02003243}
3244
Takashi Iwaie339f1e2015-02-04 11:48:53 +01003245static const struct attribute_group *amd64_edac_attr_groups[] = {
3246#ifdef CONFIG_EDAC_DEBUG
3247 &amd64_edac_dbg_group,
3248#endif
3249#ifdef CONFIG_EDAC_AMD64_ERROR_INJECTION
3250 &amd64_edac_inj_group,
3251#endif
3252 NULL
3253};
3254
Borislav Petkov3f37a362016-05-06 19:44:27 +02003255static int init_one_instance(unsigned int nid)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003256{
Borislav Petkov3f37a362016-05-06 19:44:27 +02003257 struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
Borislav Petkov0092b202010-10-01 19:20:05 +02003258 struct amd64_family_type *fam_type = NULL;
Borislav Petkov360b7f32010-10-15 19:25:38 +02003259 struct mem_ctl_info *mci = NULL;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03003260 struct edac_mc_layer layers[2];
Borislav Petkov3f37a362016-05-06 19:44:27 +02003261 struct amd64_pvt *pvt = NULL;
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05003262 u16 pci_id1, pci_id2;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003263 int err = 0, ret;
3264
3265 ret = -ENOMEM;
3266 pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
3267 if (!pvt)
Borislav Petkov360b7f32010-10-15 19:25:38 +02003268 goto err_ret;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003269
Borislav Petkov360b7f32010-10-15 19:25:38 +02003270 pvt->mc_node_id = nid;
Borislav Petkov3f37a362016-05-06 19:44:27 +02003271 pvt->F3 = F3;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003272
Borislav Petkov395ae782010-10-01 18:38:19 +02003273 ret = -EINVAL;
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003274 fam_type = per_family_init(pvt);
Borislav Petkov0092b202010-10-01 19:20:05 +02003275 if (!fam_type)
Borislav Petkov395ae782010-10-01 18:38:19 +02003276 goto err_free;
3277
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05003278 if (pvt->fam >= 0x17) {
3279 pvt->umc = kcalloc(NUM_UMCS, sizeof(struct amd64_umc), GFP_KERNEL);
3280 if (!pvt->umc) {
3281 ret = -ENOMEM;
3282 goto err_free;
3283 }
3284
3285 pci_id1 = fam_type->f0_id;
3286 pci_id2 = fam_type->f6_id;
3287 } else {
3288 pci_id1 = fam_type->f1_id;
3289 pci_id2 = fam_type->f2_id;
3290 }
3291
3292 err = reserve_mc_sibling_devs(pvt, pci_id1, pci_id2);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003293 if (err)
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05003294 goto err_post_init;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003295
Borislav Petkov360b7f32010-10-15 19:25:38 +02003296 read_mc_regs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003297
Doug Thompson7d6034d2009-04-27 20:01:01 +02003298 /*
3299 * We need to determine how many memory channels there are. Then use
3300 * that information for calculating the size of the dynamic instance
Borislav Petkov360b7f32010-10-15 19:25:38 +02003301 * tables in the 'mci' structure.
Doug Thompson7d6034d2009-04-27 20:01:01 +02003302 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02003303 ret = -EINVAL;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003304 pvt->channel_count = pvt->ops->early_channel_count(pvt);
3305 if (pvt->channel_count < 0)
Borislav Petkov360b7f32010-10-15 19:25:38 +02003306 goto err_siblings;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003307
3308 ret = -ENOMEM;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03003309 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
3310 layers[0].size = pvt->csels[0].b_cnt;
3311 layers[0].is_virt_csrow = true;
3312 layers[1].type = EDAC_MC_LAYER_CHANNEL;
Borislav Petkovf0a56c42013-07-23 20:01:23 +02003313
3314 /*
3315 * Always allocate two channels since we can have setups with DIMMs on
3316 * only one channel. Also, this simplifies handling later for the price
3317 * of a couple of KBs tops.
3318 */
3319 layers[1].size = 2;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03003320 layers[1].is_virt_csrow = false;
Borislav Petkovf0a56c42013-07-23 20:01:23 +02003321
Mauro Carvalho Chehabca0907b2012-05-02 14:37:00 -03003322 mci = edac_mc_alloc(nid, ARRAY_SIZE(layers), layers, 0);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003323 if (!mci)
Borislav Petkov360b7f32010-10-15 19:25:38 +02003324 goto err_siblings;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003325
3326 mci->pvt_info = pvt;
Borislav Petkov3f37a362016-05-06 19:44:27 +02003327 mci->pdev = &pvt->F3->dev;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003328
Borislav Petkovdf71a052011-01-19 18:15:10 +01003329 setup_mci_misc_attrs(mci, fam_type);
Borislav Petkov360b7f32010-10-15 19:25:38 +02003330
3331 if (init_csrows(mci))
Doug Thompson7d6034d2009-04-27 20:01:01 +02003332 mci->edac_cap = EDAC_FLAG_NONE;
3333
Doug Thompson7d6034d2009-04-27 20:01:01 +02003334 ret = -ENODEV;
Takashi Iwaie339f1e2015-02-04 11:48:53 +01003335 if (edac_mc_add_mc_with_groups(mci, amd64_edac_attr_groups)) {
Joe Perches956b9ba12012-04-29 17:08:39 -03003336 edac_dbg(1, "failed edac_mc_add_mc()\n");
Doug Thompson7d6034d2009-04-27 20:01:01 +02003337 goto err_add_mc;
3338 }
3339
Doug Thompson7d6034d2009-04-27 20:01:01 +02003340 return 0;
3341
3342err_add_mc:
3343 edac_mc_free(mci);
3344
Borislav Petkov360b7f32010-10-15 19:25:38 +02003345err_siblings:
3346 free_mc_sibling_devs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003347
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05003348err_post_init:
3349 if (pvt->fam >= 0x17)
3350 kfree(pvt->umc);
3351
Borislav Petkov360b7f32010-10-15 19:25:38 +02003352err_free:
3353 kfree(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003354
Borislav Petkov360b7f32010-10-15 19:25:38 +02003355err_ret:
Doug Thompson7d6034d2009-04-27 20:01:01 +02003356 return ret;
3357}
3358
Borislav Petkov3f37a362016-05-06 19:44:27 +02003359static int probe_one_instance(unsigned int nid)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003360{
Borislav Petkov2299ef72010-10-15 17:44:04 +02003361 struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003362 struct ecc_settings *s;
Borislav Petkov3f37a362016-05-06 19:44:27 +02003363 int ret;
Borislav Petkovb8cfa022010-10-01 19:35:38 +02003364
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003365 ret = -ENOMEM;
3366 s = kzalloc(sizeof(struct ecc_settings), GFP_KERNEL);
3367 if (!s)
Borislav Petkov2299ef72010-10-15 17:44:04 +02003368 goto err_out;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003369
3370 ecc_stngs[nid] = s;
3371
Borislav Petkov2299ef72010-10-15 17:44:04 +02003372 if (!ecc_enabled(F3, nid)) {
Yazen Ghannam4688c9b2017-01-27 11:24:22 -06003373 ret = 0;
Borislav Petkov2299ef72010-10-15 17:44:04 +02003374
3375 if (!ecc_enable_override)
3376 goto err_enable;
3377
Yazen Ghannam044e7a42016-11-22 15:40:16 -06003378 if (boot_cpu_data.x86 >= 0x17) {
3379 amd64_warn("Forcing ECC on is not recommended on newer systems. Please enable ECC in BIOS.");
3380 goto err_enable;
3381 } else
3382 amd64_warn("Forcing ECC on!\n");
Borislav Petkov2299ef72010-10-15 17:44:04 +02003383
3384 if (!enable_ecc_error_reporting(s, nid, F3))
3385 goto err_enable;
3386 }
3387
Borislav Petkov3f37a362016-05-06 19:44:27 +02003388 ret = init_one_instance(nid);
Borislav Petkov360b7f32010-10-15 19:25:38 +02003389 if (ret < 0) {
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003390 amd64_err("Error probing instance: %d\n", nid);
Yazen Ghannam044e7a42016-11-22 15:40:16 -06003391
3392 if (boot_cpu_data.x86 < 0x17)
3393 restore_ecc_error_reporting(s, nid, F3);
Yazen Ghannam2b9b2c42017-01-24 16:32:24 -06003394
3395 goto err_enable;
Borislav Petkov360b7f32010-10-15 19:25:38 +02003396 }
Doug Thompson7d6034d2009-04-27 20:01:01 +02003397
3398 return ret;
Borislav Petkov2299ef72010-10-15 17:44:04 +02003399
3400err_enable:
3401 kfree(s);
3402 ecc_stngs[nid] = NULL;
3403
3404err_out:
3405 return ret;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003406}
3407
Borislav Petkov3f37a362016-05-06 19:44:27 +02003408static void remove_one_instance(unsigned int nid)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003409{
Borislav Petkov360b7f32010-10-15 19:25:38 +02003410 struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
3411 struct ecc_settings *s = ecc_stngs[nid];
Borislav Petkov3f37a362016-05-06 19:44:27 +02003412 struct mem_ctl_info *mci;
3413 struct amd64_pvt *pvt;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003414
Borislav Petkov3f37a362016-05-06 19:44:27 +02003415 mci = find_mci_by_dev(&F3->dev);
Borislav Petkova4b4bed2013-08-10 13:54:48 +02003416 WARN_ON(!mci);
3417
Doug Thompson7d6034d2009-04-27 20:01:01 +02003418 /* Remove from EDAC CORE tracking list */
Borislav Petkov3f37a362016-05-06 19:44:27 +02003419 mci = edac_mc_del_mc(&F3->dev);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003420 if (!mci)
3421 return;
3422
3423 pvt = mci->pvt_info;
3424
Borislav Petkov360b7f32010-10-15 19:25:38 +02003425 restore_ecc_error_reporting(s, nid, F3);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003426
Borislav Petkov360b7f32010-10-15 19:25:38 +02003427 free_mc_sibling_devs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003428
Borislav Petkov360b7f32010-10-15 19:25:38 +02003429 kfree(ecc_stngs[nid]);
3430 ecc_stngs[nid] = NULL;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003431
Doug Thompson7d6034d2009-04-27 20:01:01 +02003432 /* Free the EDAC CORE resources */
Borislav Petkov8f68ed92009-12-21 15:15:59 +01003433 mci->pvt_info = NULL;
Borislav Petkov8f68ed92009-12-21 15:15:59 +01003434
3435 kfree(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003436 edac_mc_free(mci);
3437}
3438
Borislav Petkov360b7f32010-10-15 19:25:38 +02003439static void setup_pci_device(void)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003440{
3441 struct mem_ctl_info *mci;
3442 struct amd64_pvt *pvt;
3443
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003444 if (pci_ctl)
Doug Thompson7d6034d2009-04-27 20:01:01 +02003445 return;
3446
Borislav Petkov2ec591a2015-02-17 10:58:34 +01003447 mci = edac_mc_find(0);
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003448 if (!mci)
3449 return;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003450
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003451 pvt = mci->pvt_info;
Yazen Ghannam936fc3a2016-11-17 17:57:36 -05003452 if (pvt->umc)
3453 pci_ctl = edac_pci_create_generic_ctl(&pvt->F0->dev, EDAC_MOD_STR);
3454 else
3455 pci_ctl = edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR);
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003456 if (!pci_ctl) {
3457 pr_warn("%s(): Unable to create PCI control\n", __func__);
3458 pr_warn("%s(): PCI error report via EDAC not set\n", __func__);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003459 }
3460}
3461
Yazen Ghannamd6efab72016-09-15 19:07:17 -05003462static const struct x86_cpu_id amd64_cpuids[] = {
3463 { X86_VENDOR_AMD, 0xF, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
3464 { X86_VENDOR_AMD, 0x10, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
3465 { X86_VENDOR_AMD, 0x15, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
3466 { X86_VENDOR_AMD, 0x16, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
Yazen Ghannam95d3af62016-11-17 17:57:43 -05003467 { X86_VENDOR_AMD, 0x17, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
Pu Wenc4a3e942018-09-27 16:31:28 +02003468 { X86_VENDOR_HYGON, 0x18, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
Yazen Ghannamd6efab72016-09-15 19:07:17 -05003469 { }
3470};
3471MODULE_DEVICE_TABLE(x86cpu, amd64_cpuids);
3472
Doug Thompson7d6034d2009-04-27 20:01:01 +02003473static int __init amd64_edac_init(void)
3474{
Toshi Kani301375e2017-08-23 16:54:47 -06003475 const char *owner;
Borislav Petkov360b7f32010-10-15 19:25:38 +02003476 int err = -ENODEV;
Borislav Petkov3f37a362016-05-06 19:44:27 +02003477 int i;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003478
Toshi Kani301375e2017-08-23 16:54:47 -06003479 owner = edac_get_owner();
3480 if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
3481 return -EBUSY;
3482
Yazen Ghannam1bd99002017-01-27 11:24:23 -06003483 if (!x86_match_cpu(amd64_cpuids))
3484 return -ENODEV;
3485
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +02003486 if (amd_cache_northbridges() < 0)
Yazen Ghannam1bd99002017-01-27 11:24:23 -06003487 return -ENODEV;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003488
Borislav Petkov6ba92fe2016-06-16 01:13:18 +02003489 opstate_init();
3490
Borislav Petkovcc4d8862010-10-13 16:11:59 +02003491 err = -ENOMEM;
Kees Cook6396bb22018-06-12 14:03:40 -07003492 ecc_stngs = kcalloc(amd_nb_num(), sizeof(ecc_stngs[0]), GFP_KERNEL);
Borislav Petkov2ec591a2015-02-17 10:58:34 +01003493 if (!ecc_stngs)
Borislav Petkova9f0fbe2011-03-29 18:10:53 +02003494 goto err_free;
Borislav Petkovcc4d8862010-10-13 16:11:59 +02003495
Borislav Petkov50542252009-12-11 18:14:40 +01003496 msrs = msrs_alloc();
Borislav Petkov56b34b92009-12-21 18:13:01 +01003497 if (!msrs)
Borislav Petkov360b7f32010-10-15 19:25:38 +02003498 goto err_free;
Borislav Petkov50542252009-12-11 18:14:40 +01003499
Yazen Ghannam2287c632017-01-13 09:52:19 -06003500 for (i = 0; i < amd_nb_num(); i++) {
3501 err = probe_one_instance(i);
3502 if (err) {
Borislav Petkov3f37a362016-05-06 19:44:27 +02003503 /* unwind properly */
3504 while (--i >= 0)
3505 remove_one_instance(i);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003506
Borislav Petkov3f37a362016-05-06 19:44:27 +02003507 goto err_pci;
3508 }
Yazen Ghannam2287c632017-01-13 09:52:19 -06003509 }
Doug Thompson7d6034d2009-04-27 20:01:01 +02003510
Yazen Ghannam4688c9b2017-01-27 11:24:22 -06003511 if (!edac_has_mcs()) {
3512 err = -ENODEV;
3513 goto err_pci;
3514 }
3515
Yazen Ghannam234365f2017-01-24 16:32:25 -06003516 /* register stuff with EDAC MCE */
3517 if (report_gart_errors)
3518 amd_report_gart_errors(true);
3519
3520 if (boot_cpu_data.x86 >= 0x17)
3521 amd_register_ecc_decoder(decode_umc_error);
3522 else
3523 amd_register_ecc_decoder(decode_bus_error);
3524
Borislav Petkov360b7f32010-10-15 19:25:38 +02003525 setup_pci_device();
Tomasz Palaf5b10c42014-11-02 11:22:12 +01003526
3527#ifdef CONFIG_X86_32
3528 amd64_err("%s on 32-bit is unsupported. USE AT YOUR OWN RISK!\n", EDAC_MOD_STR);
3529#endif
3530
Borislav Petkovde0336b2016-04-27 12:21:21 +02003531 printk(KERN_INFO "AMD64 EDAC driver v%s\n", EDAC_AMD64_VERSION);
3532
Borislav Petkov360b7f32010-10-15 19:25:38 +02003533 return 0;
Borislav Petkov56b34b92009-12-21 18:13:01 +01003534
Borislav Petkov56b34b92009-12-21 18:13:01 +01003535err_pci:
3536 msrs_free(msrs);
3537 msrs = NULL;
Borislav Petkovcc4d8862010-10-13 16:11:59 +02003538
Borislav Petkov360b7f32010-10-15 19:25:38 +02003539err_free:
Borislav Petkov360b7f32010-10-15 19:25:38 +02003540 kfree(ecc_stngs);
3541 ecc_stngs = NULL;
3542
Doug Thompson7d6034d2009-04-27 20:01:01 +02003543 return err;
3544}
3545
3546static void __exit amd64_edac_exit(void)
3547{
Borislav Petkov3f37a362016-05-06 19:44:27 +02003548 int i;
3549
Borislav Petkovd1ea71c2013-12-15 17:54:27 +01003550 if (pci_ctl)
3551 edac_pci_release_generic_ctl(pci_ctl);
Doug Thompson7d6034d2009-04-27 20:01:01 +02003552
Yazen Ghannam234365f2017-01-24 16:32:25 -06003553 /* unregister from EDAC MCE */
3554 amd_report_gart_errors(false);
3555
3556 if (boot_cpu_data.x86 >= 0x17)
3557 amd_unregister_ecc_decoder(decode_umc_error);
3558 else
3559 amd_unregister_ecc_decoder(decode_bus_error);
3560
Borislav Petkov3f37a362016-05-06 19:44:27 +02003561 for (i = 0; i < amd_nb_num(); i++)
3562 remove_one_instance(i);
Borislav Petkov50542252009-12-11 18:14:40 +01003563
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02003564 kfree(ecc_stngs);
3565 ecc_stngs = NULL;
3566
Borislav Petkov50542252009-12-11 18:14:40 +01003567 msrs_free(msrs);
3568 msrs = NULL;
Doug Thompson7d6034d2009-04-27 20:01:01 +02003569}
3570
3571module_init(amd64_edac_init);
3572module_exit(amd64_edac_exit);
3573
3574MODULE_LICENSE("GPL");
3575MODULE_AUTHOR("SoftwareBitMaker: Doug Thompson, "
3576 "Dave Peterson, Thayne Harbaugh");
3577MODULE_DESCRIPTION("MC support for AMD64 memory controllers - "
3578 EDAC_AMD64_VERSION);
3579
3580module_param(edac_op_state, int, 0444);
3581MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");