blob: 29be39d020765d74f4ae6ad2c99838576a392824 [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
4static struct edac_pci_ctl_info *amd64_ctl_pci;
5
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 Petkov360b7f32010-10-15 19:25:38 +020018/*
19 * count successfully initialized driver instances for setup_pci_device()
20 */
21static atomic_t drv_instances = ATOMIC_INIT(0);
22
Borislav Petkovcc4d8862010-10-13 16:11:59 +020023/* Per-node driver instances */
24static struct mem_ctl_info **mcis;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +020025static struct ecc_settings **ecc_stngs;
Doug Thompson2bc65412009-05-04 20:11:14 +020026
27/*
Borislav Petkovb70ef012009-06-25 19:32:38 +020028 * Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing
29 * bandwidth to a valid bit pattern. The 'set' operation finds the 'matching-
30 * or higher value'.
31 *
32 *FIXME: Produce a better mapping/linearisation.
33 */
Borislav Petkov39094442010-11-24 19:52:09 +010034struct scrubrate {
35 u32 scrubval; /* bit pattern for scrub rate */
36 u32 bandwidth; /* bandwidth consumed (bytes/sec) */
37} scrubrates[] = {
Borislav Petkovb70ef012009-06-25 19:32:38 +020038 { 0x01, 1600000000UL},
39 { 0x02, 800000000UL},
40 { 0x03, 400000000UL},
41 { 0x04, 200000000UL},
42 { 0x05, 100000000UL},
43 { 0x06, 50000000UL},
44 { 0x07, 25000000UL},
45 { 0x08, 12284069UL},
46 { 0x09, 6274509UL},
47 { 0x0A, 3121951UL},
48 { 0x0B, 1560975UL},
49 { 0x0C, 781440UL},
50 { 0x0D, 390720UL},
51 { 0x0E, 195300UL},
52 { 0x0F, 97650UL},
53 { 0x10, 48854UL},
54 { 0x11, 24427UL},
55 { 0x12, 12213UL},
56 { 0x13, 6101UL},
57 { 0x14, 3051UL},
58 { 0x15, 1523UL},
59 { 0x16, 761UL},
60 { 0x00, 0UL}, /* scrubbing off */
61};
62
Borislav Petkov66fed2d2012-08-09 18:41:07 +020063int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
64 u32 *val, const char *func)
Borislav Petkovb2b0c602010-10-08 18:32:29 +020065{
66 int err = 0;
67
68 err = pci_read_config_dword(pdev, offset, val);
69 if (err)
70 amd64_warn("%s: error reading F%dx%03x.\n",
71 func, PCI_FUNC(pdev->devfn), offset);
72
73 return err;
74}
75
76int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset,
77 u32 val, const char *func)
78{
79 int err = 0;
80
81 err = pci_write_config_dword(pdev, offset, val);
82 if (err)
83 amd64_warn("%s: error writing to F%dx%03x.\n",
84 func, PCI_FUNC(pdev->devfn), offset);
85
86 return err;
87}
88
89/*
90 *
91 * Depending on the family, F2 DCT reads need special handling:
92 *
93 * K8: has a single DCT only
94 *
95 * F10h: each DCT has its own set of regs
96 * DCT0 -> F2x040..
97 * DCT1 -> F2x140..
98 *
99 * F15h: we select which DCT we access using F1x10C[DctCfgSel]
100 *
101 */
102static int k8_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
103 const char *func)
104{
105 if (addr >= 0x100)
106 return -EINVAL;
107
108 return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func);
109}
110
111static int f10_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
112 const char *func)
113{
114 return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func);
115}
116
Borislav Petkov73ba8592011-09-19 17:34:45 +0200117/*
118 * Select DCT to which PCI cfg accesses are routed
119 */
120static void f15h_select_dct(struct amd64_pvt *pvt, u8 dct)
121{
122 u32 reg = 0;
123
124 amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, &reg);
125 reg &= 0xfffffffe;
126 reg |= dct;
127 amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg);
128}
129
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200130static int f15_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
131 const char *func)
132{
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200133 u8 dct = 0;
134
135 if (addr >= 0x140 && addr <= 0x1a0) {
136 dct = 1;
137 addr -= 0x100;
138 }
139
Borislav Petkov73ba8592011-09-19 17:34:45 +0200140 f15h_select_dct(pvt, dct);
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200141
142 return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func);
143}
144
Borislav Petkovb70ef012009-06-25 19:32:38 +0200145/*
Doug Thompson2bc65412009-05-04 20:11:14 +0200146 * Memory scrubber control interface. For K8, memory scrubbing is handled by
147 * hardware and can involve L2 cache, dcache as well as the main memory. With
148 * F10, this is extended to L3 cache scrubbing on CPU models sporting that
149 * functionality.
150 *
151 * This causes the "units" for the scrubbing speed to vary from 64 byte blocks
152 * (dram) over to cache lines. This is nasty, so we will use bandwidth in
153 * bytes/sec for the setting.
154 *
155 * Currently, we only do dram scrubbing. If the scrubbing is done in software on
156 * other archs, we might not have access to the caches directly.
157 */
158
159/*
160 * scan the scrub rate mapping table for a close or matching bandwidth value to
161 * issue. If requested is too big, then use last maximum value found.
162 */
Borislav Petkov395ae782010-10-01 18:38:19 +0200163static int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate)
Doug Thompson2bc65412009-05-04 20:11:14 +0200164{
165 u32 scrubval;
166 int i;
167
168 /*
169 * map the configured rate (new_bw) to a value specific to the AMD64
170 * memory controller and apply to register. Search for the first
171 * bandwidth entry that is greater or equal than the setting requested
172 * and program that. If at last entry, turn off DRAM scrubbing.
Andrew Morton168bfee2012-10-23 14:09:39 -0700173 *
174 * If no suitable bandwidth is found, turn off DRAM scrubbing entirely
175 * by falling back to the last element in scrubrates[].
Doug Thompson2bc65412009-05-04 20:11:14 +0200176 */
Andrew Morton168bfee2012-10-23 14:09:39 -0700177 for (i = 0; i < ARRAY_SIZE(scrubrates) - 1; i++) {
Doug Thompson2bc65412009-05-04 20:11:14 +0200178 /*
179 * skip scrub rates which aren't recommended
180 * (see F10 BKDG, F3x58)
181 */
Borislav Petkov395ae782010-10-01 18:38:19 +0200182 if (scrubrates[i].scrubval < min_rate)
Doug Thompson2bc65412009-05-04 20:11:14 +0200183 continue;
184
185 if (scrubrates[i].bandwidth <= new_bw)
186 break;
Doug Thompson2bc65412009-05-04 20:11:14 +0200187 }
188
189 scrubval = scrubrates[i].scrubval;
Doug Thompson2bc65412009-05-04 20:11:14 +0200190
Borislav Petkov5980bb92011-01-07 16:26:49 +0100191 pci_write_bits32(ctl, SCRCTRL, scrubval, 0x001F);
Doug Thompson2bc65412009-05-04 20:11:14 +0200192
Borislav Petkov39094442010-11-24 19:52:09 +0100193 if (scrubval)
194 return scrubrates[i].bandwidth;
195
Doug Thompson2bc65412009-05-04 20:11:14 +0200196 return 0;
197}
198
Borislav Petkov395ae782010-10-01 18:38:19 +0200199static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bw)
Doug Thompson2bc65412009-05-04 20:11:14 +0200200{
201 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkov87b3e0e2011-01-19 20:02:38 +0100202 u32 min_scrubrate = 0x5;
Doug Thompson2bc65412009-05-04 20:11:14 +0200203
Borislav Petkov87b3e0e2011-01-19 20:02:38 +0100204 if (boot_cpu_data.x86 == 0xf)
205 min_scrubrate = 0x0;
206
Borislav Petkov73ba8592011-09-19 17:34:45 +0200207 /* F15h Erratum #505 */
208 if (boot_cpu_data.x86 == 0x15)
209 f15h_select_dct(pvt, 0);
210
Borislav Petkov87b3e0e2011-01-19 20:02:38 +0100211 return __amd64_set_scrub_rate(pvt->F3, bw, min_scrubrate);
Doug Thompson2bc65412009-05-04 20:11:14 +0200212}
213
Borislav Petkov39094442010-11-24 19:52:09 +0100214static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
Doug Thompson2bc65412009-05-04 20:11:14 +0200215{
216 struct amd64_pvt *pvt = mci->pvt_info;
217 u32 scrubval = 0;
Borislav Petkov39094442010-11-24 19:52:09 +0100218 int i, retval = -EINVAL;
Doug Thompson2bc65412009-05-04 20:11:14 +0200219
Borislav Petkov73ba8592011-09-19 17:34:45 +0200220 /* F15h Erratum #505 */
221 if (boot_cpu_data.x86 == 0x15)
222 f15h_select_dct(pvt, 0);
223
Borislav Petkov5980bb92011-01-07 16:26:49 +0100224 amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval);
Doug Thompson2bc65412009-05-04 20:11:14 +0200225
226 scrubval = scrubval & 0x001F;
227
Roel Kluin926311f2010-01-11 20:58:21 +0100228 for (i = 0; i < ARRAY_SIZE(scrubrates); i++) {
Doug Thompson2bc65412009-05-04 20:11:14 +0200229 if (scrubrates[i].scrubval == scrubval) {
Borislav Petkov39094442010-11-24 19:52:09 +0100230 retval = scrubrates[i].bandwidth;
Doug Thompson2bc65412009-05-04 20:11:14 +0200231 break;
232 }
233 }
Borislav Petkov39094442010-11-24 19:52:09 +0100234 return retval;
Doug Thompson2bc65412009-05-04 20:11:14 +0200235}
236
Doug Thompson67757632009-04-27 15:53:22 +0200237/*
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200238 * returns true if the SysAddr given by sys_addr matches the
239 * DRAM base/limit associated with node_id
Doug Thompson67757632009-04-27 15:53:22 +0200240 */
Borislav Petkovb487c332011-02-21 18:55:00 +0100241static bool amd64_base_limit_match(struct amd64_pvt *pvt, u64 sys_addr,
242 unsigned nid)
Doug Thompson67757632009-04-27 15:53:22 +0200243{
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200244 u64 addr;
Doug Thompson67757632009-04-27 15:53:22 +0200245
246 /* The K8 treats this as a 40-bit value. However, bits 63-40 will be
247 * all ones if the most significant implemented address bit is 1.
248 * Here we discard bits 63-40. See section 3.4.2 of AMD publication
249 * 24592: AMD x86-64 Architecture Programmer's Manual Volume 1
250 * Application Programming.
251 */
252 addr = sys_addr & 0x000000ffffffffffull;
253
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200254 return ((addr >= get_dram_base(pvt, nid)) &&
255 (addr <= get_dram_limit(pvt, nid)));
Doug Thompson67757632009-04-27 15:53:22 +0200256}
257
258/*
259 * Attempt to map a SysAddr to a node. On success, return a pointer to the
260 * mem_ctl_info structure for the node that the SysAddr maps to.
261 *
262 * On failure, return NULL.
263 */
264static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
265 u64 sys_addr)
266{
267 struct amd64_pvt *pvt;
Borislav Petkovb487c332011-02-21 18:55:00 +0100268 unsigned node_id;
Doug Thompson67757632009-04-27 15:53:22 +0200269 u32 intlv_en, bits;
270
271 /*
272 * Here we use the DRAM Base (section 3.4.4.1) and DRAM Limit (section
273 * 3.4.4.2) registers to map the SysAddr to a node ID.
274 */
275 pvt = mci->pvt_info;
276
277 /*
278 * The value of this field should be the same for all DRAM Base
279 * registers. Therefore we arbitrarily choose to read it from the
280 * register for node 0.
281 */
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200282 intlv_en = dram_intlv_en(pvt, 0);
Doug Thompson67757632009-04-27 15:53:22 +0200283
284 if (intlv_en == 0) {
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200285 for (node_id = 0; node_id < DRAM_RANGES; node_id++) {
Doug Thompson67757632009-04-27 15:53:22 +0200286 if (amd64_base_limit_match(pvt, sys_addr, node_id))
Borislav Petkov8edc5442009-09-18 12:39:19 +0200287 goto found;
Doug Thompson67757632009-04-27 15:53:22 +0200288 }
Borislav Petkov8edc5442009-09-18 12:39:19 +0200289 goto err_no_match;
Doug Thompson67757632009-04-27 15:53:22 +0200290 }
291
Borislav Petkov72f158f2009-09-18 12:27:27 +0200292 if (unlikely((intlv_en != 0x01) &&
293 (intlv_en != 0x03) &&
294 (intlv_en != 0x07))) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200295 amd64_warn("DRAM Base[IntlvEn] junk value: 0x%x, BIOS bug?\n", intlv_en);
Doug Thompson67757632009-04-27 15:53:22 +0200296 return NULL;
297 }
298
299 bits = (((u32) sys_addr) >> 12) & intlv_en;
300
301 for (node_id = 0; ; ) {
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200302 if ((dram_intlv_sel(pvt, node_id) & intlv_en) == bits)
Doug Thompson67757632009-04-27 15:53:22 +0200303 break; /* intlv_sel field matches */
304
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200305 if (++node_id >= DRAM_RANGES)
Doug Thompson67757632009-04-27 15:53:22 +0200306 goto err_no_match;
307 }
308
309 /* sanity test for sys_addr */
310 if (unlikely(!amd64_base_limit_match(pvt, sys_addr, node_id))) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200311 amd64_warn("%s: sys_addr 0x%llx falls outside base/limit address"
312 "range for node %d with node interleaving enabled.\n",
313 __func__, sys_addr, node_id);
Doug Thompson67757632009-04-27 15:53:22 +0200314 return NULL;
315 }
316
317found:
Borislav Petkovb487c332011-02-21 18:55:00 +0100318 return edac_mc_find((int)node_id);
Doug Thompson67757632009-04-27 15:53:22 +0200319
320err_no_match:
Joe Perches956b9ba2012-04-29 17:08:39 -0300321 edac_dbg(2, "sys_addr 0x%lx doesn't match any node\n",
322 (unsigned long)sys_addr);
Doug Thompson67757632009-04-27 15:53:22 +0200323
324 return NULL;
325}
Doug Thompsone2ce7252009-04-27 15:57:12 +0200326
327/*
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100328 * compute the CS base address of the @csrow on the DRAM controller @dct.
329 * For details see F2x[5C:40] in the processor's BKDG
Doug Thompsone2ce7252009-04-27 15:57:12 +0200330 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100331static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct,
332 u64 *base, u64 *mask)
Doug Thompsone2ce7252009-04-27 15:57:12 +0200333{
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100334 u64 csbase, csmask, base_bits, mask_bits;
335 u8 addr_shift;
336
337 if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) {
338 csbase = pvt->csels[dct].csbases[csrow];
339 csmask = pvt->csels[dct].csmasks[csrow];
340 base_bits = GENMASK(21, 31) | GENMASK(9, 15);
341 mask_bits = GENMASK(21, 29) | GENMASK(9, 15);
342 addr_shift = 4;
343 } else {
344 csbase = pvt->csels[dct].csbases[csrow];
345 csmask = pvt->csels[dct].csmasks[csrow >> 1];
346 addr_shift = 8;
347
348 if (boot_cpu_data.x86 == 0x15)
349 base_bits = mask_bits = GENMASK(19,30) | GENMASK(5,13);
350 else
351 base_bits = mask_bits = GENMASK(19,28) | GENMASK(5,13);
352 }
353
354 *base = (csbase & base_bits) << addr_shift;
355
356 *mask = ~0ULL;
357 /* poke holes for the csmask */
358 *mask &= ~(mask_bits << addr_shift);
359 /* OR them in */
360 *mask |= (csmask & mask_bits) << addr_shift;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200361}
362
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100363#define for_each_chip_select(i, dct, pvt) \
364 for (i = 0; i < pvt->csels[dct].b_cnt; i++)
Doug Thompsone2ce7252009-04-27 15:57:12 +0200365
Borislav Petkov614ec9d2011-01-13 18:02:22 +0100366#define chip_select_base(i, dct, pvt) \
367 pvt->csels[dct].csbases[i]
368
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100369#define for_each_chip_select_mask(i, dct, pvt) \
370 for (i = 0; i < pvt->csels[dct].m_cnt; i++)
Doug Thompsone2ce7252009-04-27 15:57:12 +0200371
372/*
373 * @input_addr is an InputAddr associated with the node given by mci. Return the
374 * csrow that input_addr maps to, or -1 on failure (no csrow claims input_addr).
375 */
376static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr)
377{
378 struct amd64_pvt *pvt;
379 int csrow;
380 u64 base, mask;
381
382 pvt = mci->pvt_info;
383
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100384 for_each_chip_select(csrow, 0, pvt) {
385 if (!csrow_enabled(csrow, 0, pvt))
Doug Thompsone2ce7252009-04-27 15:57:12 +0200386 continue;
387
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100388 get_cs_base_and_mask(pvt, csrow, 0, &base, &mask);
389
390 mask = ~mask;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200391
392 if ((input_addr & mask) == (base & mask)) {
Joe Perches956b9ba2012-04-29 17:08:39 -0300393 edac_dbg(2, "InputAddr 0x%lx matches csrow %d (node %d)\n",
394 (unsigned long)input_addr, csrow,
395 pvt->mc_node_id);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200396
397 return csrow;
398 }
399 }
Joe Perches956b9ba2012-04-29 17:08:39 -0300400 edac_dbg(2, "no matching csrow for InputAddr 0x%lx (MC node %d)\n",
401 (unsigned long)input_addr, pvt->mc_node_id);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200402
403 return -1;
404}
405
406/*
Doug Thompsone2ce7252009-04-27 15:57:12 +0200407 * Obtain info from the DRAM Hole Address Register (section 3.4.8, pub #26094)
408 * for the node represented by mci. Info is passed back in *hole_base,
409 * *hole_offset, and *hole_size. Function returns 0 if info is valid or 1 if
410 * info is invalid. Info may be invalid for either of the following reasons:
411 *
412 * - The revision of the node is not E or greater. In this case, the DRAM Hole
413 * Address Register does not exist.
414 *
415 * - The DramHoleValid bit is cleared in the DRAM Hole Address Register,
416 * indicating that its contents are not valid.
417 *
418 * The values passed back in *hole_base, *hole_offset, and *hole_size are
419 * complete 32-bit values despite the fact that the bitfields in the DHAR
420 * only represent bits 31-24 of the base and offset values.
421 */
422int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
423 u64 *hole_offset, u64 *hole_size)
424{
425 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200426
427 /* only revE and later have the DRAM Hole Address Register */
Borislav Petkov1433eb92009-10-21 13:44:36 +0200428 if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_E) {
Joe Perches956b9ba2012-04-29 17:08:39 -0300429 edac_dbg(1, " revision %d for node %d does not support DHAR\n",
430 pvt->ext_model, pvt->mc_node_id);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200431 return 1;
432 }
433
Borislav Petkovbc21fa52010-11-11 17:29:13 +0100434 /* valid for Fam10h and above */
Borislav Petkovc8e518d2010-12-10 19:49:19 +0100435 if (boot_cpu_data.x86 >= 0x10 && !dhar_mem_hoist_valid(pvt)) {
Joe Perches956b9ba2012-04-29 17:08:39 -0300436 edac_dbg(1, " Dram Memory Hoisting is DISABLED on this system\n");
Doug Thompsone2ce7252009-04-27 15:57:12 +0200437 return 1;
438 }
439
Borislav Petkovc8e518d2010-12-10 19:49:19 +0100440 if (!dhar_valid(pvt)) {
Joe Perches956b9ba2012-04-29 17:08:39 -0300441 edac_dbg(1, " Dram Memory Hoisting is DISABLED on this node %d\n",
442 pvt->mc_node_id);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200443 return 1;
444 }
445
446 /* This node has Memory Hoisting */
447
448 /* +------------------+--------------------+--------------------+-----
449 * | memory | DRAM hole | relocated |
450 * | [0, (x - 1)] | [x, 0xffffffff] | addresses from |
451 * | | | DRAM hole |
452 * | | | [0x100000000, |
453 * | | | (0x100000000+ |
454 * | | | (0xffffffff-x))] |
455 * +------------------+--------------------+--------------------+-----
456 *
457 * Above is a diagram of physical memory showing the DRAM hole and the
458 * relocated addresses from the DRAM hole. As shown, the DRAM hole
459 * starts at address x (the base address) and extends through address
460 * 0xffffffff. The DRAM Hole Address Register (DHAR) relocates the
461 * addresses in the hole so that they start at 0x100000000.
462 */
463
Borislav Petkov1f316772012-08-10 12:50:50 +0200464 *hole_base = dhar_base(pvt);
465 *hole_size = (1ULL << 32) - *hole_base;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200466
467 if (boot_cpu_data.x86 > 0xf)
Borislav Petkovbc21fa52010-11-11 17:29:13 +0100468 *hole_offset = f10_dhar_offset(pvt);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200469 else
Borislav Petkovbc21fa52010-11-11 17:29:13 +0100470 *hole_offset = k8_dhar_offset(pvt);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200471
Joe Perches956b9ba2012-04-29 17:08:39 -0300472 edac_dbg(1, " DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx\n",
473 pvt->mc_node_id, (unsigned long)*hole_base,
474 (unsigned long)*hole_offset, (unsigned long)*hole_size);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200475
476 return 0;
477}
478EXPORT_SYMBOL_GPL(amd64_get_dram_hole_info);
479
Doug Thompson93c2df52009-05-04 20:46:50 +0200480/*
481 * Return the DramAddr that the SysAddr given by @sys_addr maps to. It is
482 * assumed that sys_addr maps to the node given by mci.
483 *
484 * The first part of section 3.4.4 (p. 70) shows how the DRAM Base (section
485 * 3.4.4.1) and DRAM Limit (section 3.4.4.2) registers are used to translate a
486 * SysAddr to a DramAddr. If the DRAM Hole Address Register (DHAR) is enabled,
487 * then it is also involved in translating a SysAddr to a DramAddr. Sections
488 * 3.4.8 and 3.5.8.2 describe the DHAR and how it is used for memory hoisting.
489 * These parts of the documentation are unclear. I interpret them as follows:
490 *
491 * When node n receives a SysAddr, it processes the SysAddr as follows:
492 *
493 * 1. It extracts the DRAMBase and DRAMLimit values from the DRAM Base and DRAM
494 * Limit registers for node n. If the SysAddr is not within the range
495 * specified by the base and limit values, then node n ignores the Sysaddr
496 * (since it does not map to node n). Otherwise continue to step 2 below.
497 *
498 * 2. If the DramHoleValid bit of the DHAR for node n is clear, the DHAR is
499 * disabled so skip to step 3 below. Otherwise see if the SysAddr is within
500 * the range of relocated addresses (starting at 0x100000000) from the DRAM
501 * hole. If not, skip to step 3 below. Else get the value of the
502 * DramHoleOffset field from the DHAR. To obtain the DramAddr, subtract the
503 * offset defined by this value from the SysAddr.
504 *
505 * 3. Obtain the base address for node n from the DRAMBase field of the DRAM
506 * Base register for node n. To obtain the DramAddr, subtract the base
507 * address from the SysAddr, as shown near the start of section 3.4.4 (p.70).
508 */
509static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr)
510{
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200511 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompson93c2df52009-05-04 20:46:50 +0200512 u64 dram_base, hole_base, hole_offset, hole_size, dram_addr;
Borislav Petkov1f316772012-08-10 12:50:50 +0200513 int ret;
Doug Thompson93c2df52009-05-04 20:46:50 +0200514
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200515 dram_base = get_dram_base(pvt, pvt->mc_node_id);
Doug Thompson93c2df52009-05-04 20:46:50 +0200516
517 ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
518 &hole_size);
519 if (!ret) {
Borislav Petkov1f316772012-08-10 12:50:50 +0200520 if ((sys_addr >= (1ULL << 32)) &&
521 (sys_addr < ((1ULL << 32) + hole_size))) {
Doug Thompson93c2df52009-05-04 20:46:50 +0200522 /* use DHAR to translate SysAddr to DramAddr */
523 dram_addr = sys_addr - hole_offset;
524
Joe Perches956b9ba2012-04-29 17:08:39 -0300525 edac_dbg(2, "using DHAR to translate SysAddr 0x%lx to DramAddr 0x%lx\n",
526 (unsigned long)sys_addr,
527 (unsigned long)dram_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200528
529 return dram_addr;
530 }
531 }
532
533 /*
534 * Translate the SysAddr to a DramAddr as shown near the start of
535 * section 3.4.4 (p. 70). Although sys_addr is a 64-bit value, the k8
536 * only deals with 40-bit values. Therefore we discard bits 63-40 of
537 * sys_addr below. If bit 39 of sys_addr is 1 then the bits we
538 * discard are all 1s. Otherwise the bits we discard are all 0s. See
539 * section 3.4.2 of AMD publication 24592: AMD x86-64 Architecture
540 * Programmer's Manual Volume 1 Application Programming.
541 */
Borislav Petkovf678b8c2010-12-13 19:21:07 +0100542 dram_addr = (sys_addr & GENMASK(0, 39)) - dram_base;
Doug Thompson93c2df52009-05-04 20:46:50 +0200543
Joe Perches956b9ba2012-04-29 17:08:39 -0300544 edac_dbg(2, "using DRAM Base register to translate SysAddr 0x%lx to DramAddr 0x%lx\n",
545 (unsigned long)sys_addr, (unsigned long)dram_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200546 return dram_addr;
547}
548
549/*
550 * @intlv_en is the value of the IntlvEn field from a DRAM Base register
551 * (section 3.4.4.1). Return the number of bits from a SysAddr that are used
552 * for node interleaving.
553 */
554static int num_node_interleave_bits(unsigned intlv_en)
555{
556 static const int intlv_shift_table[] = { 0, 1, 0, 2, 0, 0, 0, 3 };
557 int n;
558
559 BUG_ON(intlv_en > 7);
560 n = intlv_shift_table[intlv_en];
561 return n;
562}
563
564/* Translate the DramAddr given by @dram_addr to an InputAddr. */
565static u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr)
566{
567 struct amd64_pvt *pvt;
568 int intlv_shift;
569 u64 input_addr;
570
571 pvt = mci->pvt_info;
572
573 /*
574 * See the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E)
575 * concerning translating a DramAddr to an InputAddr.
576 */
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200577 intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0));
Borislav Petkovf678b8c2010-12-13 19:21:07 +0100578 input_addr = ((dram_addr >> intlv_shift) & GENMASK(12, 35)) +
579 (dram_addr & 0xfff);
Doug Thompson93c2df52009-05-04 20:46:50 +0200580
Joe Perches956b9ba2012-04-29 17:08:39 -0300581 edac_dbg(2, " Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n",
582 intlv_shift, (unsigned long)dram_addr,
583 (unsigned long)input_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200584
585 return input_addr;
586}
587
588/*
589 * Translate the SysAddr represented by @sys_addr to an InputAddr. It is
590 * assumed that @sys_addr maps to the node given by mci.
591 */
592static u64 sys_addr_to_input_addr(struct mem_ctl_info *mci, u64 sys_addr)
593{
594 u64 input_addr;
595
596 input_addr =
597 dram_addr_to_input_addr(mci, sys_addr_to_dram_addr(mci, sys_addr));
598
Joe Perches956b9ba2012-04-29 17:08:39 -0300599 edac_dbg(2, "SysAdddr 0x%lx translates to InputAddr 0x%lx\n",
600 (unsigned long)sys_addr, (unsigned long)input_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200601
602 return input_addr;
603}
604
605
606/*
607 * @input_addr is an InputAddr associated with the node represented by mci.
608 * Translate @input_addr to a DramAddr and return the result.
609 */
610static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr)
611{
612 struct amd64_pvt *pvt;
Borislav Petkovb487c332011-02-21 18:55:00 +0100613 unsigned node_id, intlv_shift;
Doug Thompson93c2df52009-05-04 20:46:50 +0200614 u64 bits, dram_addr;
615 u32 intlv_sel;
616
617 /*
618 * Near the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E)
619 * shows how to translate a DramAddr to an InputAddr. Here we reverse
620 * this procedure. When translating from a DramAddr to an InputAddr, the
621 * bits used for node interleaving are discarded. Here we recover these
622 * bits from the IntlvSel field of the DRAM Limit register (section
623 * 3.4.4.2) for the node that input_addr is associated with.
624 */
625 pvt = mci->pvt_info;
626 node_id = pvt->mc_node_id;
Borislav Petkovb487c332011-02-21 18:55:00 +0100627
628 BUG_ON(node_id > 7);
Doug Thompson93c2df52009-05-04 20:46:50 +0200629
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200630 intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0));
Doug Thompson93c2df52009-05-04 20:46:50 +0200631 if (intlv_shift == 0) {
Joe Perches956b9ba2012-04-29 17:08:39 -0300632 edac_dbg(1, " InputAddr 0x%lx translates to DramAddr of same value\n",
633 (unsigned long)input_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200634
635 return input_addr;
636 }
637
Borislav Petkovf678b8c2010-12-13 19:21:07 +0100638 bits = ((input_addr & GENMASK(12, 35)) << intlv_shift) +
639 (input_addr & 0xfff);
Doug Thompson93c2df52009-05-04 20:46:50 +0200640
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200641 intlv_sel = dram_intlv_sel(pvt, node_id) & ((1 << intlv_shift) - 1);
Doug Thompson93c2df52009-05-04 20:46:50 +0200642 dram_addr = bits + (intlv_sel << 12);
643
Joe Perches956b9ba2012-04-29 17:08:39 -0300644 edac_dbg(1, "InputAddr 0x%lx translates to DramAddr 0x%lx (%d node interleave bits)\n",
645 (unsigned long)input_addr,
646 (unsigned long)dram_addr, intlv_shift);
Doug Thompson93c2df52009-05-04 20:46:50 +0200647
648 return dram_addr;
649}
650
651/*
652 * @dram_addr is a DramAddr that maps to the node represented by mci. Convert
653 * @dram_addr to a SysAddr.
654 */
655static u64 dram_addr_to_sys_addr(struct mem_ctl_info *mci, u64 dram_addr)
656{
657 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200658 u64 hole_base, hole_offset, hole_size, base, sys_addr;
Doug Thompson93c2df52009-05-04 20:46:50 +0200659 int ret = 0;
660
661 ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
662 &hole_size);
663 if (!ret) {
664 if ((dram_addr >= hole_base) &&
665 (dram_addr < (hole_base + hole_size))) {
666 sys_addr = dram_addr + hole_offset;
667
Joe Perches956b9ba2012-04-29 17:08:39 -0300668 edac_dbg(1, "using DHAR to translate DramAddr 0x%lx to SysAddr 0x%lx\n",
669 (unsigned long)dram_addr,
670 (unsigned long)sys_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200671
672 return sys_addr;
673 }
674 }
675
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200676 base = get_dram_base(pvt, pvt->mc_node_id);
Doug Thompson93c2df52009-05-04 20:46:50 +0200677 sys_addr = dram_addr + base;
678
679 /*
680 * The sys_addr we have computed up to this point is a 40-bit value
681 * because the k8 deals with 40-bit values. However, the value we are
682 * supposed to return is a full 64-bit physical address. The AMD
683 * x86-64 architecture specifies that the most significant implemented
684 * address bit through bit 63 of a physical address must be either all
685 * 0s or all 1s. Therefore we sign-extend the 40-bit sys_addr to a
686 * 64-bit value below. See section 3.4.2 of AMD publication 24592:
687 * AMD x86-64 Architecture Programmer's Manual Volume 1 Application
688 * Programming.
689 */
690 sys_addr |= ~((sys_addr & (1ull << 39)) - 1);
691
Joe Perches956b9ba2012-04-29 17:08:39 -0300692 edac_dbg(1, " Node %d, DramAddr 0x%lx to SysAddr 0x%lx\n",
693 pvt->mc_node_id, (unsigned long)dram_addr,
694 (unsigned long)sys_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200695
696 return sys_addr;
697}
698
699/*
700 * @input_addr is an InputAddr associated with the node given by mci. Translate
701 * @input_addr to a SysAddr.
702 */
703static inline u64 input_addr_to_sys_addr(struct mem_ctl_info *mci,
704 u64 input_addr)
705{
706 return dram_addr_to_sys_addr(mci,
707 input_addr_to_dram_addr(mci, input_addr));
708}
709
Doug Thompson93c2df52009-05-04 20:46:50 +0200710/* Map the Error address to a PAGE and PAGE OFFSET. */
711static inline void error_address_to_page_and_offset(u64 error_address,
Borislav Petkov33ca0642012-08-30 18:01:36 +0200712 struct err_info *err)
Doug Thompson93c2df52009-05-04 20:46:50 +0200713{
Borislav Petkov33ca0642012-08-30 18:01:36 +0200714 err->page = (u32) (error_address >> PAGE_SHIFT);
715 err->offset = ((u32) error_address) & ~PAGE_MASK;
Doug Thompson93c2df52009-05-04 20:46:50 +0200716}
717
718/*
719 * @sys_addr is an error address (a SysAddr) extracted from the MCA NB Address
720 * Low (section 3.6.4.5) and MCA NB Address High (section 3.6.4.6) registers
721 * of a node that detected an ECC memory error. mci represents the node that
722 * the error address maps to (possibly different from the node that detected
723 * the error). Return the number of the csrow that sys_addr maps to, or -1 on
724 * error.
725 */
726static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr)
727{
728 int csrow;
729
730 csrow = input_addr_to_csrow(mci, sys_addr_to_input_addr(mci, sys_addr));
731
732 if (csrow == -1)
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200733 amd64_mc_err(mci, "Failed to translate InputAddr to csrow for "
734 "address 0x%lx\n", (unsigned long)sys_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200735 return csrow;
736}
Doug Thompsone2ce7252009-04-27 15:57:12 +0200737
Borislav Petkovbfc04ae2009-11-12 19:05:07 +0100738static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);
Doug Thompson2da11652009-04-27 16:09:09 +0200739
Doug Thompson2da11652009-04-27 16:09:09 +0200740/*
741 * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs
742 * are ECC capable.
743 */
Dan Carpenter1f6189e2011-10-06 02:30:25 -0400744static unsigned long amd64_determine_edac_cap(struct amd64_pvt *pvt)
Doug Thompson2da11652009-04-27 16:09:09 +0200745{
Borislav Petkovcb328502010-12-22 14:28:24 +0100746 u8 bit;
Dan Carpenter1f6189e2011-10-06 02:30:25 -0400747 unsigned long edac_cap = EDAC_FLAG_NONE;
Doug Thompson2da11652009-04-27 16:09:09 +0200748
Borislav Petkov1433eb92009-10-21 13:44:36 +0200749 bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= K8_REV_F)
Doug Thompson2da11652009-04-27 16:09:09 +0200750 ? 19
751 : 17;
752
Borislav Petkov584fcff2009-06-10 18:29:54 +0200753 if (pvt->dclr0 & BIT(bit))
Doug Thompson2da11652009-04-27 16:09:09 +0200754 edac_cap = EDAC_FLAG_SECDED;
755
756 return edac_cap;
757}
758
Borislav Petkov8c671752011-02-23 17:25:12 +0100759static void amd64_debug_display_dimm_sizes(struct amd64_pvt *, u8);
Doug Thompson2da11652009-04-27 16:09:09 +0200760
Borislav Petkov68798e12009-11-03 16:18:33 +0100761static void amd64_dump_dramcfg_low(u32 dclr, int chan)
762{
Joe Perches956b9ba2012-04-29 17:08:39 -0300763 edac_dbg(1, "F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr);
Borislav Petkov68798e12009-11-03 16:18:33 +0100764
Joe Perches956b9ba2012-04-29 17:08:39 -0300765 edac_dbg(1, " DIMM type: %sbuffered; all DIMMs support ECC: %s\n",
766 (dclr & BIT(16)) ? "un" : "",
767 (dclr & BIT(19)) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100768
Joe Perches956b9ba2012-04-29 17:08:39 -0300769 edac_dbg(1, " PAR/ERR parity: %s\n",
770 (dclr & BIT(8)) ? "enabled" : "disabled");
Borislav Petkov68798e12009-11-03 16:18:33 +0100771
Borislav Petkovcb328502010-12-22 14:28:24 +0100772 if (boot_cpu_data.x86 == 0x10)
Joe Perches956b9ba2012-04-29 17:08:39 -0300773 edac_dbg(1, " DCT 128bit mode width: %s\n",
774 (dclr & BIT(11)) ? "128b" : "64b");
Borislav Petkov68798e12009-11-03 16:18:33 +0100775
Joe Perches956b9ba2012-04-29 17:08:39 -0300776 edac_dbg(1, " x4 logical DIMMs present: L0: %s L1: %s L2: %s L3: %s\n",
777 (dclr & BIT(12)) ? "yes" : "no",
778 (dclr & BIT(13)) ? "yes" : "no",
779 (dclr & BIT(14)) ? "yes" : "no",
780 (dclr & BIT(15)) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100781}
782
Doug Thompson2da11652009-04-27 16:09:09 +0200783/* Display and decode various NB registers for debug purposes. */
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200784static void dump_misc_regs(struct amd64_pvt *pvt)
Doug Thompson2da11652009-04-27 16:09:09 +0200785{
Joe Perches956b9ba2012-04-29 17:08:39 -0300786 edac_dbg(1, "F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap);
Doug Thompson2da11652009-04-27 16:09:09 +0200787
Joe Perches956b9ba2012-04-29 17:08:39 -0300788 edac_dbg(1, " NB two channel DRAM capable: %s\n",
789 (pvt->nbcap & NBCAP_DCT_DUAL) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100790
Joe Perches956b9ba2012-04-29 17:08:39 -0300791 edac_dbg(1, " ECC capable: %s, ChipKill ECC capable: %s\n",
792 (pvt->nbcap & NBCAP_SECDED) ? "yes" : "no",
793 (pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100794
795 amd64_dump_dramcfg_low(pvt->dclr0, 0);
Doug Thompson2da11652009-04-27 16:09:09 +0200796
Joe Perches956b9ba2012-04-29 17:08:39 -0300797 edac_dbg(1, "F3xB0 (Online Spare): 0x%08x\n", pvt->online_spare);
Doug Thompson2da11652009-04-27 16:09:09 +0200798
Joe Perches956b9ba2012-04-29 17:08:39 -0300799 edac_dbg(1, "F1xF0 (DRAM Hole Address): 0x%08x, base: 0x%08x, offset: 0x%08x\n",
800 pvt->dhar, dhar_base(pvt),
801 (boot_cpu_data.x86 == 0xf) ? k8_dhar_offset(pvt)
802 : f10_dhar_offset(pvt));
Doug Thompson2da11652009-04-27 16:09:09 +0200803
Joe Perches956b9ba2012-04-29 17:08:39 -0300804 edac_dbg(1, " DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no");
Doug Thompson2da11652009-04-27 16:09:09 +0200805
Borislav Petkov8c671752011-02-23 17:25:12 +0100806 amd64_debug_display_dimm_sizes(pvt, 0);
Borislav Petkov4d796362011-02-03 15:59:57 +0100807
Borislav Petkov8de1d912009-10-16 13:39:30 +0200808 /* everything below this point is Fam10h and above */
Borislav Petkov4d796362011-02-03 15:59:57 +0100809 if (boot_cpu_data.x86 == 0xf)
Doug Thompson2da11652009-04-27 16:09:09 +0200810 return;
Borislav Petkov4d796362011-02-03 15:59:57 +0100811
Borislav Petkov8c671752011-02-23 17:25:12 +0100812 amd64_debug_display_dimm_sizes(pvt, 1);
Doug Thompson2da11652009-04-27 16:09:09 +0200813
Borislav Petkova3b7db02011-01-19 20:35:12 +0100814 amd64_info("using %s syndromes.\n", ((pvt->ecc_sym_sz == 8) ? "x8" : "x4"));
Borislav Petkovad6a32e2010-03-09 12:46:00 +0100815
Borislav Petkov8de1d912009-10-16 13:39:30 +0200816 /* Only if NOT ganged does dclr1 have valid info */
Borislav Petkov68798e12009-11-03 16:18:33 +0100817 if (!dct_ganging_enabled(pvt))
818 amd64_dump_dramcfg_low(pvt->dclr1, 1);
Doug Thompson2da11652009-04-27 16:09:09 +0200819}
820
Doug Thompson94be4bf2009-04-27 16:12:00 +0200821/*
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100822 * see BKDG, F2x[1,0][5C:40], F2[1,0][6C:60]
Doug Thompson94be4bf2009-04-27 16:12:00 +0200823 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100824static void prep_chip_selects(struct amd64_pvt *pvt)
Doug Thompson94be4bf2009-04-27 16:12:00 +0200825{
Borislav Petkov1433eb92009-10-21 13:44:36 +0200826 if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) {
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100827 pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
828 pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 8;
Borislav Petkov9d858bb2009-09-21 14:35:51 +0200829 } else {
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100830 pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
831 pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4;
Doug Thompson94be4bf2009-04-27 16:12:00 +0200832 }
833}
834
835/*
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100836 * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers
Doug Thompson94be4bf2009-04-27 16:12:00 +0200837 */
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200838static void read_dct_base_mask(struct amd64_pvt *pvt)
Doug Thompson94be4bf2009-04-27 16:12:00 +0200839{
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100840 int cs;
Doug Thompson94be4bf2009-04-27 16:12:00 +0200841
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100842 prep_chip_selects(pvt);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200843
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100844 for_each_chip_select(cs, 0, pvt) {
Borislav Petkov71d2a322011-02-21 19:37:24 +0100845 int reg0 = DCSB0 + (cs * 4);
846 int reg1 = DCSB1 + (cs * 4);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100847 u32 *base0 = &pvt->csels[0].csbases[cs];
848 u32 *base1 = &pvt->csels[1].csbases[cs];
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200849
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100850 if (!amd64_read_dct_pci_cfg(pvt, reg0, base0))
Joe Perches956b9ba2012-04-29 17:08:39 -0300851 edac_dbg(0, " DCSB0[%d]=0x%08x reg: F2x%x\n",
852 cs, *base0, reg0);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200853
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100854 if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt))
855 continue;
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200856
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100857 if (!amd64_read_dct_pci_cfg(pvt, reg1, base1))
Joe Perches956b9ba2012-04-29 17:08:39 -0300858 edac_dbg(0, " DCSB1[%d]=0x%08x reg: F2x%x\n",
859 cs, *base1, reg1);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200860 }
861
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100862 for_each_chip_select_mask(cs, 0, pvt) {
Borislav Petkov71d2a322011-02-21 19:37:24 +0100863 int reg0 = DCSM0 + (cs * 4);
864 int reg1 = DCSM1 + (cs * 4);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100865 u32 *mask0 = &pvt->csels[0].csmasks[cs];
866 u32 *mask1 = &pvt->csels[1].csmasks[cs];
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200867
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100868 if (!amd64_read_dct_pci_cfg(pvt, reg0, mask0))
Joe Perches956b9ba2012-04-29 17:08:39 -0300869 edac_dbg(0, " DCSM0[%d]=0x%08x reg: F2x%x\n",
870 cs, *mask0, reg0);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200871
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100872 if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt))
873 continue;
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200874
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100875 if (!amd64_read_dct_pci_cfg(pvt, reg1, mask1))
Joe Perches956b9ba2012-04-29 17:08:39 -0300876 edac_dbg(0, " DCSM1[%d]=0x%08x reg: F2x%x\n",
877 cs, *mask1, reg1);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200878 }
879}
880
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200881static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt, int cs)
Doug Thompson94be4bf2009-04-27 16:12:00 +0200882{
883 enum mem_type type;
884
Borislav Petkovcb328502010-12-22 14:28:24 +0100885 /* F15h supports only DDR3 */
886 if (boot_cpu_data.x86 >= 0x15)
887 type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3;
888 else if (boot_cpu_data.x86 == 0x10 || pvt->ext_model >= K8_REV_F) {
Borislav Petkov6b4c0bd2009-11-12 15:37:57 +0100889 if (pvt->dchr0 & DDR3_MODE)
890 type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3;
891 else
892 type = (pvt->dclr0 & BIT(16)) ? MEM_DDR2 : MEM_RDDR2;
Doug Thompson94be4bf2009-04-27 16:12:00 +0200893 } else {
Doug Thompson94be4bf2009-04-27 16:12:00 +0200894 type = (pvt->dclr0 & BIT(18)) ? MEM_DDR : MEM_RDDR;
895 }
896
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200897 amd64_info("CS%d: %s\n", cs, edac_mem_types[type]);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200898
899 return type;
900}
901
Borislav Petkovcb328502010-12-22 14:28:24 +0100902/* Get the number of DCT channels the memory controller is using. */
Doug Thompsonddff8762009-04-27 16:14:52 +0200903static int k8_early_channel_count(struct amd64_pvt *pvt)
904{
Borislav Petkovcb328502010-12-22 14:28:24 +0100905 int flag;
Doug Thompsonddff8762009-04-27 16:14:52 +0200906
Borislav Petkov9f56da02010-10-01 19:44:53 +0200907 if (pvt->ext_model >= K8_REV_F)
Doug Thompsonddff8762009-04-27 16:14:52 +0200908 /* RevF (NPT) and later */
Borislav Petkov41d8bfa2011-01-18 19:16:08 +0100909 flag = pvt->dclr0 & WIDTH_128;
Borislav Petkov9f56da02010-10-01 19:44:53 +0200910 else
Doug Thompsonddff8762009-04-27 16:14:52 +0200911 /* RevE and earlier */
912 flag = pvt->dclr0 & REVE_WIDTH_128;
Doug Thompsonddff8762009-04-27 16:14:52 +0200913
914 /* not used */
915 pvt->dclr1 = 0;
916
917 return (flag) ? 2 : 1;
918}
919
Borislav Petkov70046622011-01-10 14:37:27 +0100920/* On F10h and later ErrAddr is MC4_ADDR[47:1] */
921static u64 get_error_address(struct mce *m)
Doug Thompsonddff8762009-04-27 16:14:52 +0200922{
Borislav Petkovc1ae6832011-03-30 15:42:10 +0200923 struct cpuinfo_x86 *c = &boot_cpu_data;
924 u64 addr;
Borislav Petkov70046622011-01-10 14:37:27 +0100925 u8 start_bit = 1;
926 u8 end_bit = 47;
927
Borislav Petkovc1ae6832011-03-30 15:42:10 +0200928 if (c->x86 == 0xf) {
Borislav Petkov70046622011-01-10 14:37:27 +0100929 start_bit = 3;
930 end_bit = 39;
931 }
932
Borislav Petkovc1ae6832011-03-30 15:42:10 +0200933 addr = m->addr & GENMASK(start_bit, end_bit);
934
935 /*
936 * Erratum 637 workaround
937 */
938 if (c->x86 == 0x15) {
939 struct amd64_pvt *pvt;
940 u64 cc6_base, tmp_addr;
941 u32 tmp;
Daniel J Blueman8b84c8d2012-11-27 14:32:10 +0800942 u16 mce_nid;
943 u8 intlv_en;
Borislav Petkovc1ae6832011-03-30 15:42:10 +0200944
945 if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7)
946 return addr;
947
948 mce_nid = amd_get_nb_id(m->extcpu);
949 pvt = mcis[mce_nid]->pvt_info;
950
951 amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_LIM, &tmp);
952 intlv_en = tmp >> 21 & 0x7;
953
954 /* add [47:27] + 3 trailing bits */
955 cc6_base = (tmp & GENMASK(0, 20)) << 3;
956
957 /* reverse and add DramIntlvEn */
958 cc6_base |= intlv_en ^ 0x7;
959
960 /* pin at [47:24] */
961 cc6_base <<= 24;
962
963 if (!intlv_en)
964 return cc6_base | (addr & GENMASK(0, 23));
965
966 amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_BASE, &tmp);
967
968 /* faster log2 */
969 tmp_addr = (addr & GENMASK(12, 23)) << __fls(intlv_en + 1);
970
971 /* OR DramIntlvSel into bits [14:12] */
972 tmp_addr |= (tmp & GENMASK(21, 23)) >> 9;
973
974 /* add remaining [11:0] bits from original MC4_ADDR */
975 tmp_addr |= addr & GENMASK(0, 11);
976
977 return cc6_base | tmp_addr;
978 }
979
980 return addr;
Doug Thompsonddff8762009-04-27 16:14:52 +0200981}
982
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200983static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
Doug Thompsonddff8762009-04-27 16:14:52 +0200984{
Borislav Petkovf08e4572011-03-21 20:45:06 +0100985 struct cpuinfo_x86 *c = &boot_cpu_data;
Borislav Petkov71d2a322011-02-21 19:37:24 +0100986 int off = range << 3;
Doug Thompsonddff8762009-04-27 16:14:52 +0200987
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200988 amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo);
989 amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
Doug Thompsonddff8762009-04-27 16:14:52 +0200990
Borislav Petkovf08e4572011-03-21 20:45:06 +0100991 if (c->x86 == 0xf)
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200992 return;
Doug Thompsonddff8762009-04-27 16:14:52 +0200993
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200994 if (!dram_rw(pvt, range))
995 return;
Doug Thompsonddff8762009-04-27 16:14:52 +0200996
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200997 amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi);
998 amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
Borislav Petkovf08e4572011-03-21 20:45:06 +0100999
1000 /* Factor in CC6 save area by reading dst node's limit reg */
1001 if (c->x86 == 0x15) {
1002 struct pci_dev *f1 = NULL;
1003 u8 nid = dram_dst_node(pvt, range);
1004 u32 llim;
1005
1006 f1 = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x18 + nid, 1));
1007 if (WARN_ON(!f1))
1008 return;
1009
1010 amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
1011
1012 pvt->ranges[range].lim.lo &= GENMASK(0, 15);
1013
1014 /* {[39:27],111b} */
1015 pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
1016
1017 pvt->ranges[range].lim.hi &= GENMASK(0, 7);
1018
1019 /* [47:40] */
1020 pvt->ranges[range].lim.hi |= llim >> 13;
1021
1022 pci_dev_put(f1);
1023 }
Doug Thompsonddff8762009-04-27 16:14:52 +02001024}
1025
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001026static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
Borislav Petkov33ca0642012-08-30 18:01:36 +02001027 struct err_info *err)
Doug Thompsonddff8762009-04-27 16:14:52 +02001028{
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001029 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompsonddff8762009-04-27 16:14:52 +02001030
Borislav Petkov33ca0642012-08-30 18:01:36 +02001031 error_address_to_page_and_offset(sys_addr, err);
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001032
1033 /*
1034 * Find out which node the error address belongs to. This may be
1035 * different from the node that detected the error.
1036 */
Borislav Petkov33ca0642012-08-30 18:01:36 +02001037 err->src_mci = find_mc_by_sys_addr(mci, sys_addr);
1038 if (!err->src_mci) {
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001039 amd64_mc_err(mci, "failed to map error addr 0x%lx to a node\n",
1040 (unsigned long)sys_addr);
Borislav Petkov33ca0642012-08-30 18:01:36 +02001041 err->err_code = ERR_NODE;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001042 return;
1043 }
1044
1045 /* Now map the sys_addr to a CSROW */
Borislav Petkov33ca0642012-08-30 18:01:36 +02001046 err->csrow = sys_addr_to_csrow(err->src_mci, sys_addr);
1047 if (err->csrow < 0) {
1048 err->err_code = ERR_CSROW;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001049 return;
1050 }
1051
Doug Thompsonddff8762009-04-27 16:14:52 +02001052 /* CHIPKILL enabled */
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001053 if (pvt->nbcfg & NBCFG_CHIPKILL) {
Borislav Petkov33ca0642012-08-30 18:01:36 +02001054 err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome);
1055 if (err->channel < 0) {
Doug Thompsonddff8762009-04-27 16:14:52 +02001056 /*
1057 * Syndrome didn't map, so we don't know which of the
1058 * 2 DIMMs is in error. So we need to ID 'both' of them
1059 * as suspect.
1060 */
Borislav Petkov33ca0642012-08-30 18:01:36 +02001061 amd64_mc_warn(err->src_mci, "unknown syndrome 0x%04x - "
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001062 "possible error reporting race\n",
Borislav Petkov33ca0642012-08-30 18:01:36 +02001063 err->syndrome);
1064 err->err_code = ERR_CHANNEL;
Doug Thompsonddff8762009-04-27 16:14:52 +02001065 return;
1066 }
1067 } else {
1068 /*
1069 * non-chipkill ecc mode
1070 *
1071 * The k8 documentation is unclear about how to determine the
1072 * channel number when using non-chipkill memory. This method
1073 * was obtained from email communication with someone at AMD.
1074 * (Wish the email was placed in this comment - norsk)
1075 */
Borislav Petkov33ca0642012-08-30 18:01:36 +02001076 err->channel = ((sys_addr & BIT(3)) != 0);
Doug Thompsonddff8762009-04-27 16:14:52 +02001077 }
Doug Thompsonddff8762009-04-27 16:14:52 +02001078}
1079
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001080static int ddr2_cs_size(unsigned i, bool dct_width)
Doug Thompsonddff8762009-04-27 16:14:52 +02001081{
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001082 unsigned shift = 0;
Doug Thompsonddff8762009-04-27 16:14:52 +02001083
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001084 if (i <= 2)
1085 shift = i;
1086 else if (!(i & 0x1))
1087 shift = i >> 1;
Borislav Petkov1433eb92009-10-21 13:44:36 +02001088 else
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001089 shift = (i + 1) >> 1;
Doug Thompsonddff8762009-04-27 16:14:52 +02001090
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001091 return 128 << (shift + !!dct_width);
1092}
1093
1094static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
1095 unsigned cs_mode)
1096{
1097 u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
1098
1099 if (pvt->ext_model >= K8_REV_F) {
1100 WARN_ON(cs_mode > 11);
1101 return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
1102 }
1103 else if (pvt->ext_model >= K8_REV_D) {
Borislav Petkov11b0a312011-11-09 21:28:43 +01001104 unsigned diff;
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001105 WARN_ON(cs_mode > 10);
1106
Borislav Petkov11b0a312011-11-09 21:28:43 +01001107 /*
1108 * the below calculation, besides trying to win an obfuscated C
1109 * contest, maps cs_mode values to DIMM chip select sizes. The
1110 * mappings are:
1111 *
1112 * cs_mode CS size (mb)
1113 * ======= ============
1114 * 0 32
1115 * 1 64
1116 * 2 128
1117 * 3 128
1118 * 4 256
1119 * 5 512
1120 * 6 256
1121 * 7 512
1122 * 8 1024
1123 * 9 1024
1124 * 10 2048
1125 *
1126 * Basically, it calculates a value with which to shift the
1127 * smallest CS size of 32MB.
1128 *
1129 * ddr[23]_cs_size have a similar purpose.
1130 */
1131 diff = cs_mode/3 + (unsigned)(cs_mode > 5);
1132
1133 return 32 << (cs_mode - diff);
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001134 }
1135 else {
1136 WARN_ON(cs_mode > 6);
1137 return 32 << cs_mode;
1138 }
Doug Thompsonddff8762009-04-27 16:14:52 +02001139}
1140
Doug Thompson1afd3c92009-04-27 16:16:50 +02001141/*
1142 * Get the number of DCT channels in use.
1143 *
1144 * Return:
1145 * number of Memory Channels in operation
1146 * Pass back:
1147 * contents of the DCL0_LOW register
1148 */
Borislav Petkov7d20d142011-01-07 17:58:04 +01001149static int f1x_early_channel_count(struct amd64_pvt *pvt)
Doug Thompson1afd3c92009-04-27 16:16:50 +02001150{
Borislav Petkov6ba5dcd2009-10-13 19:26:55 +02001151 int i, j, channels = 0;
Doug Thompsonddff8762009-04-27 16:14:52 +02001152
Borislav Petkov7d20d142011-01-07 17:58:04 +01001153 /* On F10h, if we are in 128 bit mode, then we are using 2 channels */
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001154 if (boot_cpu_data.x86 == 0x10 && (pvt->dclr0 & WIDTH_128))
Borislav Petkov7d20d142011-01-07 17:58:04 +01001155 return 2;
Doug Thompson1afd3c92009-04-27 16:16:50 +02001156
1157 /*
Borislav Petkovd16149e2009-10-16 19:55:49 +02001158 * Need to check if in unganged mode: In such, there are 2 channels,
1159 * but they are not in 128 bit mode and thus the above 'dclr0' status
1160 * bit will be OFF.
Doug Thompson1afd3c92009-04-27 16:16:50 +02001161 *
1162 * Need to check DCT0[0] and DCT1[0] to see if only one of them has
1163 * their CSEnable bit on. If so, then SINGLE DIMM case.
1164 */
Joe Perches956b9ba2012-04-29 17:08:39 -03001165 edac_dbg(0, "Data width is not 128 bits - need more decoding\n");
Doug Thompson1afd3c92009-04-27 16:16:50 +02001166
1167 /*
1168 * Check DRAM Bank Address Mapping values for each DIMM to see if there
1169 * is more than just one DIMM present in unganged mode. Need to check
1170 * both controllers since DIMMs can be placed in either one.
1171 */
Borislav Petkov525a1b22010-12-21 15:53:27 +01001172 for (i = 0; i < 2; i++) {
1173 u32 dbam = (i ? pvt->dbam1 : pvt->dbam0);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001174
Wan Wei57a30852009-08-07 17:04:49 +02001175 for (j = 0; j < 4; j++) {
1176 if (DBAM_DIMM(j, dbam) > 0) {
1177 channels++;
1178 break;
1179 }
1180 }
Doug Thompson1afd3c92009-04-27 16:16:50 +02001181 }
1182
Borislav Petkovd16149e2009-10-16 19:55:49 +02001183 if (channels > 2)
1184 channels = 2;
1185
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001186 amd64_info("MCT channel count: %d\n", channels);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001187
1188 return channels;
Doug Thompson1afd3c92009-04-27 16:16:50 +02001189}
1190
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001191static int ddr3_cs_size(unsigned i, bool dct_width)
Doug Thompson1afd3c92009-04-27 16:16:50 +02001192{
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001193 unsigned shift = 0;
1194 int cs_size = 0;
1195
1196 if (i == 0 || i == 3 || i == 4)
1197 cs_size = -1;
1198 else if (i <= 2)
1199 shift = i;
1200 else if (i == 12)
1201 shift = 7;
1202 else if (!(i & 0x1))
1203 shift = i >> 1;
1204 else
1205 shift = (i + 1) >> 1;
1206
1207 if (cs_size != -1)
1208 cs_size = (128 * (1 << !!dct_width)) << shift;
1209
1210 return cs_size;
1211}
1212
1213static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
1214 unsigned cs_mode)
1215{
1216 u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
1217
1218 WARN_ON(cs_mode > 11);
Borislav Petkov1433eb92009-10-21 13:44:36 +02001219
1220 if (pvt->dchr0 & DDR3_MODE || pvt->dchr1 & DDR3_MODE)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001221 return ddr3_cs_size(cs_mode, dclr & WIDTH_128);
Borislav Petkov1433eb92009-10-21 13:44:36 +02001222 else
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001223 return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
1224}
Borislav Petkov1433eb92009-10-21 13:44:36 +02001225
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001226/*
1227 * F15h supports only 64bit DCT interfaces
1228 */
1229static int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
1230 unsigned cs_mode)
1231{
1232 WARN_ON(cs_mode > 12);
1233
1234 return ddr3_cs_size(cs_mode, false);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001235}
1236
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001237static void read_dram_ctl_register(struct amd64_pvt *pvt)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001238{
Doug Thompson6163b5d2009-04-27 16:20:17 +02001239
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001240 if (boot_cpu_data.x86 == 0xf)
1241 return;
1242
Borislav Petkov78da1212010-12-22 19:31:45 +01001243 if (!amd64_read_dct_pci_cfg(pvt, DCT_SEL_LO, &pvt->dct_sel_lo)) {
Joe Perches956b9ba2012-04-29 17:08:39 -03001244 edac_dbg(0, "F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x\n",
1245 pvt->dct_sel_lo, dct_sel_baseaddr(pvt));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001246
Joe Perches956b9ba2012-04-29 17:08:39 -03001247 edac_dbg(0, " DCTs operate in %s mode\n",
1248 (dct_ganging_enabled(pvt) ? "ganged" : "unganged"));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001249
Borislav Petkov72381bd2009-10-09 19:14:43 +02001250 if (!dct_ganging_enabled(pvt))
Joe Perches956b9ba2012-04-29 17:08:39 -03001251 edac_dbg(0, " Address range split per DCT: %s\n",
1252 (dct_high_range_enabled(pvt) ? "yes" : "no"));
Borislav Petkov72381bd2009-10-09 19:14:43 +02001253
Joe Perches956b9ba2012-04-29 17:08:39 -03001254 edac_dbg(0, " data interleave for ECC: %s, DRAM cleared since last warm reset: %s\n",
1255 (dct_data_intlv_enabled(pvt) ? "enabled" : "disabled"),
1256 (dct_memory_cleared(pvt) ? "yes" : "no"));
Borislav Petkov72381bd2009-10-09 19:14:43 +02001257
Joe Perches956b9ba2012-04-29 17:08:39 -03001258 edac_dbg(0, " channel interleave: %s, "
1259 "interleave bits selector: 0x%x\n",
1260 (dct_interleave_enabled(pvt) ? "enabled" : "disabled"),
1261 dct_sel_interleave_addr(pvt));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001262 }
1263
Borislav Petkov78da1212010-12-22 19:31:45 +01001264 amd64_read_dct_pci_cfg(pvt, DCT_SEL_HI, &pvt->dct_sel_hi);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001265}
1266
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001267/*
Borislav Petkov229a7a12010-12-09 18:57:54 +01001268 * Determine channel (DCT) based on the interleaving mode: F10h BKDG, 2.8.9 Memory
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001269 * Interleaving Modes.
1270 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001271static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
Borislav Petkov229a7a12010-12-09 18:57:54 +01001272 bool hi_range_sel, u8 intlv_en)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001273{
Borislav Petkov151fa712011-02-21 19:33:10 +01001274 u8 dct_sel_high = (pvt->dct_sel_lo >> 1) & 1;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001275
1276 if (dct_ganging_enabled(pvt))
Borislav Petkov229a7a12010-12-09 18:57:54 +01001277 return 0;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001278
Borislav Petkov229a7a12010-12-09 18:57:54 +01001279 if (hi_range_sel)
1280 return dct_sel_high;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001281
Borislav Petkov229a7a12010-12-09 18:57:54 +01001282 /*
1283 * see F2x110[DctSelIntLvAddr] - channel interleave mode
1284 */
1285 if (dct_interleave_enabled(pvt)) {
1286 u8 intlv_addr = dct_sel_interleave_addr(pvt);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001287
Borislav Petkov229a7a12010-12-09 18:57:54 +01001288 /* return DCT select function: 0=DCT0, 1=DCT1 */
1289 if (!intlv_addr)
1290 return sys_addr >> 6 & 1;
1291
1292 if (intlv_addr & 0x2) {
1293 u8 shift = intlv_addr & 0x1 ? 9 : 6;
1294 u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) % 2;
1295
1296 return ((sys_addr >> shift) & 1) ^ temp;
1297 }
1298
1299 return (sys_addr >> (12 + hweight8(intlv_en))) & 1;
1300 }
1301
1302 if (dct_high_range_enabled(pvt))
1303 return ~dct_sel_high & 1;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001304
1305 return 0;
1306}
1307
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001308/* Convert the sys_addr to the normalized DCT address */
Borislav Petkove7613592011-02-21 19:49:01 +01001309static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, unsigned range,
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001310 u64 sys_addr, bool hi_rng,
1311 u32 dct_sel_base_addr)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001312{
1313 u64 chan_off;
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001314 u64 dram_base = get_dram_base(pvt, range);
1315 u64 hole_off = f10_dhar_offset(pvt);
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001316 u64 dct_sel_base_off = (pvt->dct_sel_hi & 0xFFFFFC00) << 16;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001317
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001318 if (hi_rng) {
1319 /*
1320 * if
1321 * base address of high range is below 4Gb
1322 * (bits [47:27] at [31:11])
1323 * DRAM address space on this DCT is hoisted above 4Gb &&
1324 * sys_addr > 4Gb
1325 *
1326 * remove hole offset from sys_addr
1327 * else
1328 * remove high range offset from sys_addr
1329 */
1330 if ((!(dct_sel_base_addr >> 16) ||
1331 dct_sel_base_addr < dhar_base(pvt)) &&
Borislav Petkov972ea172011-02-21 19:43:02 +01001332 dhar_valid(pvt) &&
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001333 (sys_addr >= BIT_64(32)))
Borislav Petkovbc21fa52010-11-11 17:29:13 +01001334 chan_off = hole_off;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001335 else
1336 chan_off = dct_sel_base_off;
1337 } else {
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001338 /*
1339 * if
1340 * we have a valid hole &&
1341 * sys_addr > 4Gb
1342 *
1343 * remove hole
1344 * else
1345 * remove dram base to normalize to DCT address
1346 */
Borislav Petkov972ea172011-02-21 19:43:02 +01001347 if (dhar_valid(pvt) && (sys_addr >= BIT_64(32)))
Borislav Petkovbc21fa52010-11-11 17:29:13 +01001348 chan_off = hole_off;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001349 else
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001350 chan_off = dram_base;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001351 }
1352
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001353 return (sys_addr & GENMASK(6,47)) - (chan_off & GENMASK(23,47));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001354}
1355
Doug Thompson6163b5d2009-04-27 16:20:17 +02001356/*
1357 * checks if the csrow passed in is marked as SPARED, if so returns the new
1358 * spare row
1359 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001360static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001361{
Borislav Petkov614ec9d2011-01-13 18:02:22 +01001362 int tmp_cs;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001363
Borislav Petkov614ec9d2011-01-13 18:02:22 +01001364 if (online_spare_swap_done(pvt, dct) &&
1365 csrow == online_spare_bad_dramcs(pvt, dct)) {
1366
1367 for_each_chip_select(tmp_cs, dct, pvt) {
1368 if (chip_select_base(tmp_cs, dct, pvt) & 0x2) {
1369 csrow = tmp_cs;
1370 break;
1371 }
1372 }
Doug Thompson6163b5d2009-04-27 16:20:17 +02001373 }
1374 return csrow;
1375}
1376
1377/*
1378 * Iterate over the DRAM DCT "base" and "mask" registers looking for a
1379 * SystemAddr match on the specified 'ChannelSelect' and 'NodeID'
1380 *
1381 * Return:
1382 * -EINVAL: NOT FOUND
1383 * 0..csrow = Chip-Select Row
1384 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001385static int f1x_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001386{
1387 struct mem_ctl_info *mci;
1388 struct amd64_pvt *pvt;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001389 u64 cs_base, cs_mask;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001390 int cs_found = -EINVAL;
1391 int csrow;
1392
Borislav Petkovcc4d8862010-10-13 16:11:59 +02001393 mci = mcis[nid];
Doug Thompson6163b5d2009-04-27 16:20:17 +02001394 if (!mci)
1395 return cs_found;
1396
1397 pvt = mci->pvt_info;
1398
Joe Perches956b9ba2012-04-29 17:08:39 -03001399 edac_dbg(1, "input addr: 0x%llx, DCT: %d\n", in_addr, dct);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001400
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001401 for_each_chip_select(csrow, dct, pvt) {
1402 if (!csrow_enabled(csrow, dct, pvt))
Doug Thompson6163b5d2009-04-27 16:20:17 +02001403 continue;
1404
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001405 get_cs_base_and_mask(pvt, csrow, dct, &cs_base, &cs_mask);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001406
Joe Perches956b9ba2012-04-29 17:08:39 -03001407 edac_dbg(1, " CSROW=%d CSBase=0x%llx CSMask=0x%llx\n",
1408 csrow, cs_base, cs_mask);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001409
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001410 cs_mask = ~cs_mask;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001411
Joe Perches956b9ba2012-04-29 17:08:39 -03001412 edac_dbg(1, " (InputAddr & ~CSMask)=0x%llx (CSBase & ~CSMask)=0x%llx\n",
1413 (in_addr & cs_mask), (cs_base & cs_mask));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001414
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001415 if ((in_addr & cs_mask) == (cs_base & cs_mask)) {
1416 cs_found = f10_process_possible_spare(pvt, dct, csrow);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001417
Joe Perches956b9ba2012-04-29 17:08:39 -03001418 edac_dbg(1, " MATCH csrow=%d\n", cs_found);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001419 break;
1420 }
1421 }
1422 return cs_found;
1423}
1424
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001425/*
1426 * See F2x10C. Non-interleaved graphics framebuffer memory under the 16G is
1427 * swapped with a region located at the bottom of memory so that the GPU can use
1428 * the interleaved region and thus two channels.
1429 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001430static u64 f1x_swap_interleaved_region(struct amd64_pvt *pvt, u64 sys_addr)
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001431{
1432 u32 swap_reg, swap_base, swap_limit, rgn_size, tmp_addr;
1433
1434 if (boot_cpu_data.x86 == 0x10) {
1435 /* only revC3 and revE have that feature */
1436 if (boot_cpu_data.x86_model < 4 ||
1437 (boot_cpu_data.x86_model < 0xa &&
1438 boot_cpu_data.x86_mask < 3))
1439 return sys_addr;
1440 }
1441
1442 amd64_read_dct_pci_cfg(pvt, SWAP_INTLV_REG, &swap_reg);
1443
1444 if (!(swap_reg & 0x1))
1445 return sys_addr;
1446
1447 swap_base = (swap_reg >> 3) & 0x7f;
1448 swap_limit = (swap_reg >> 11) & 0x7f;
1449 rgn_size = (swap_reg >> 20) & 0x7f;
1450 tmp_addr = sys_addr >> 27;
1451
1452 if (!(sys_addr >> 34) &&
1453 (((tmp_addr >= swap_base) &&
1454 (tmp_addr <= swap_limit)) ||
1455 (tmp_addr < rgn_size)))
1456 return sys_addr ^ (u64)swap_base << 27;
1457
1458 return sys_addr;
1459}
1460
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001461/* For a given @dram_range, check if @sys_addr falls within it. */
Borislav Petkove7613592011-02-21 19:49:01 +01001462static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
Borislav Petkov33ca0642012-08-30 18:01:36 +02001463 u64 sys_addr, int *chan_sel)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001464{
Borislav Petkov229a7a12010-12-09 18:57:54 +01001465 int cs_found = -EINVAL;
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001466 u64 chan_addr;
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001467 u32 dct_sel_base;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001468 u8 channel;
Borislav Petkov229a7a12010-12-09 18:57:54 +01001469 bool high_range = false;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001470
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001471 u8 node_id = dram_dst_node(pvt, range);
Borislav Petkov229a7a12010-12-09 18:57:54 +01001472 u8 intlv_en = dram_intlv_en(pvt, range);
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001473 u32 intlv_sel = dram_intlv_sel(pvt, range);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001474
Joe Perches956b9ba2012-04-29 17:08:39 -03001475 edac_dbg(1, "(range %d) SystemAddr= 0x%llx Limit=0x%llx\n",
1476 range, sys_addr, get_dram_limit(pvt, range));
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001477
Borislav Petkov355fba62011-01-17 13:03:26 +01001478 if (dhar_valid(pvt) &&
1479 dhar_base(pvt) <= sys_addr &&
1480 sys_addr < BIT_64(32)) {
1481 amd64_warn("Huh? Address is in the MMIO hole: 0x%016llx\n",
1482 sys_addr);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001483 return -EINVAL;
Borislav Petkov355fba62011-01-17 13:03:26 +01001484 }
1485
Borislav Petkovf030ddf2011-04-08 15:05:21 +02001486 if (intlv_en && (intlv_sel != ((sys_addr >> 12) & intlv_en)))
Borislav Petkov355fba62011-01-17 13:03:26 +01001487 return -EINVAL;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001488
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001489 sys_addr = f1x_swap_interleaved_region(pvt, sys_addr);
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001490
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001491 dct_sel_base = dct_sel_baseaddr(pvt);
1492
1493 /*
1494 * check whether addresses >= DctSelBaseAddr[47:27] are to be used to
1495 * select between DCT0 and DCT1.
1496 */
1497 if (dct_high_range_enabled(pvt) &&
1498 !dct_ganging_enabled(pvt) &&
1499 ((sys_addr >> 27) >= (dct_sel_base >> 11)))
Borislav Petkov229a7a12010-12-09 18:57:54 +01001500 high_range = true;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001501
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001502 channel = f1x_determine_channel(pvt, sys_addr, high_range, intlv_en);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001503
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001504 chan_addr = f1x_get_norm_dct_addr(pvt, range, sys_addr,
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001505 high_range, dct_sel_base);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001506
Borislav Petkove2f79db2011-01-13 14:57:34 +01001507 /* Remove node interleaving, see F1x120 */
1508 if (intlv_en)
1509 chan_addr = ((chan_addr >> (12 + hweight8(intlv_en))) << 12) |
1510 (chan_addr & 0xfff);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001511
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001512 /* remove channel interleave */
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001513 if (dct_interleave_enabled(pvt) &&
1514 !dct_high_range_enabled(pvt) &&
1515 !dct_ganging_enabled(pvt)) {
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001516
1517 if (dct_sel_interleave_addr(pvt) != 1) {
1518 if (dct_sel_interleave_addr(pvt) == 0x3)
1519 /* hash 9 */
1520 chan_addr = ((chan_addr >> 10) << 9) |
1521 (chan_addr & 0x1ff);
1522 else
1523 /* A[6] or hash 6 */
1524 chan_addr = ((chan_addr >> 7) << 6) |
1525 (chan_addr & 0x3f);
1526 } else
1527 /* A[12] */
1528 chan_addr = ((chan_addr >> 13) << 12) |
1529 (chan_addr & 0xfff);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001530 }
1531
Joe Perches956b9ba2012-04-29 17:08:39 -03001532 edac_dbg(1, " Normalized DCT addr: 0x%llx\n", chan_addr);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001533
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001534 cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, channel);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001535
Borislav Petkov33ca0642012-08-30 18:01:36 +02001536 if (cs_found >= 0)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001537 *chan_sel = channel;
Borislav Petkov33ca0642012-08-30 18:01:36 +02001538
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001539 return cs_found;
1540}
1541
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001542static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
Borislav Petkov33ca0642012-08-30 18:01:36 +02001543 int *chan_sel)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001544{
Borislav Petkove7613592011-02-21 19:49:01 +01001545 int cs_found = -EINVAL;
1546 unsigned range;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001547
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001548 for (range = 0; range < DRAM_RANGES; range++) {
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001549
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001550 if (!dram_rw(pvt, range))
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001551 continue;
1552
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001553 if ((get_dram_base(pvt, range) <= sys_addr) &&
1554 (get_dram_limit(pvt, range) >= sys_addr)) {
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001555
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001556 cs_found = f1x_match_to_this_node(pvt, range,
Borislav Petkov33ca0642012-08-30 18:01:36 +02001557 sys_addr, chan_sel);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001558 if (cs_found >= 0)
1559 break;
1560 }
1561 }
1562 return cs_found;
1563}
1564
1565/*
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001566 * For reference see "2.8.5 Routing DRAM Requests" in F10 BKDG. This code maps
1567 * a @sys_addr to NodeID, DCT (channel) and chip select (CSROW).
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001568 *
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001569 * The @sys_addr is usually an error address received from the hardware
1570 * (MCX_ADDR).
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001571 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001572static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
Borislav Petkov33ca0642012-08-30 18:01:36 +02001573 struct err_info *err)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001574{
1575 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001576
Borislav Petkov33ca0642012-08-30 18:01:36 +02001577 error_address_to_page_and_offset(sys_addr, err);
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03001578
Borislav Petkov33ca0642012-08-30 18:01:36 +02001579 err->csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &err->channel);
1580 if (err->csrow < 0) {
1581 err->err_code = ERR_CSROW;
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001582 return;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001583 }
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001584
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001585 /*
1586 * We need the syndromes for channel detection only when we're
1587 * ganged. Otherwise @chan should already contain the channel at
1588 * this point.
1589 */
Borislav Petkova97fa682010-12-23 14:07:18 +01001590 if (dct_ganging_enabled(pvt))
Borislav Petkov33ca0642012-08-30 18:01:36 +02001591 err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001592}
1593
1594/*
Borislav Petkov8566c4d2009-10-16 13:48:28 +02001595 * debug routine to display the memory sizes of all logical DIMMs and its
Borislav Petkovcb328502010-12-22 14:28:24 +01001596 * CSROWs
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001597 */
Borislav Petkov8c671752011-02-23 17:25:12 +01001598static void amd64_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001599{
Borislav Petkovbb89f5a2012-09-12 18:06:00 +02001600 int dimm, size0, size1;
Borislav Petkov525a1b22010-12-21 15:53:27 +01001601 u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases;
1602 u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001603
Borislav Petkov8566c4d2009-10-16 13:48:28 +02001604 if (boot_cpu_data.x86 == 0xf) {
1605 /* K8 families < revF not supported yet */
Borislav Petkov1433eb92009-10-21 13:44:36 +02001606 if (pvt->ext_model < K8_REV_F)
Borislav Petkov8566c4d2009-10-16 13:48:28 +02001607 return;
1608 else
1609 WARN_ON(ctrl != 0);
1610 }
1611
Borislav Petkov4d796362011-02-03 15:59:57 +01001612 dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1 : pvt->dbam0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001613 dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->csels[1].csbases
1614 : pvt->csels[0].csbases;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001615
Joe Perches956b9ba2012-04-29 17:08:39 -03001616 edac_dbg(1, "F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n",
1617 ctrl, dbam);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001618
Borislav Petkov8566c4d2009-10-16 13:48:28 +02001619 edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl);
1620
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001621 /* Dump memory sizes for DIMM and its CSROWs */
1622 for (dimm = 0; dimm < 4; dimm++) {
1623
1624 size0 = 0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001625 if (dcsb[dimm*2] & DCSB_CS_ENABLE)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001626 size0 = pvt->ops->dbam_to_cs(pvt, ctrl,
1627 DBAM_DIMM(dimm, dbam));
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001628
1629 size1 = 0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001630 if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001631 size1 = pvt->ops->dbam_to_cs(pvt, ctrl,
1632 DBAM_DIMM(dimm, dbam));
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001633
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001634 amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
Borislav Petkovbb89f5a2012-09-12 18:06:00 +02001635 dimm * 2, size0,
1636 dimm * 2 + 1, size1);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001637 }
1638}
1639
Doug Thompson4d376072009-04-27 16:25:05 +02001640static struct amd64_family_type amd64_family_types[] = {
1641 [K8_CPUS] = {
Borislav Petkov0092b202010-10-01 19:20:05 +02001642 .ctl_name = "K8",
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001643 .f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP,
1644 .f3_id = PCI_DEVICE_ID_AMD_K8_NB_MISC,
Doug Thompson4d376072009-04-27 16:25:05 +02001645 .ops = {
Borislav Petkov1433eb92009-10-21 13:44:36 +02001646 .early_channel_count = k8_early_channel_count,
Borislav Petkov1433eb92009-10-21 13:44:36 +02001647 .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow,
1648 .dbam_to_cs = k8_dbam_to_chip_select,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02001649 .read_dct_pci_cfg = k8_read_dct_pci_cfg,
Doug Thompson4d376072009-04-27 16:25:05 +02001650 }
1651 },
1652 [F10_CPUS] = {
Borislav Petkov0092b202010-10-01 19:20:05 +02001653 .ctl_name = "F10h",
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001654 .f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP,
1655 .f3_id = PCI_DEVICE_ID_AMD_10H_NB_MISC,
Doug Thompson4d376072009-04-27 16:25:05 +02001656 .ops = {
Borislav Petkov7d20d142011-01-07 17:58:04 +01001657 .early_channel_count = f1x_early_channel_count,
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001658 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
Borislav Petkov1433eb92009-10-21 13:44:36 +02001659 .dbam_to_cs = f10_dbam_to_chip_select,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02001660 .read_dct_pci_cfg = f10_read_dct_pci_cfg,
1661 }
1662 },
1663 [F15_CPUS] = {
1664 .ctl_name = "F15h",
Borislav Petkovdf71a052011-01-19 18:15:10 +01001665 .f1_id = PCI_DEVICE_ID_AMD_15H_NB_F1,
1666 .f3_id = PCI_DEVICE_ID_AMD_15H_NB_F3,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02001667 .ops = {
Borislav Petkov7d20d142011-01-07 17:58:04 +01001668 .early_channel_count = f1x_early_channel_count,
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001669 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001670 .dbam_to_cs = f15_dbam_to_chip_select,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02001671 .read_dct_pci_cfg = f15_read_dct_pci_cfg,
Doug Thompson4d376072009-04-27 16:25:05 +02001672 }
1673 },
Doug Thompson4d376072009-04-27 16:25:05 +02001674};
1675
1676static struct pci_dev *pci_get_related_function(unsigned int vendor,
1677 unsigned int device,
1678 struct pci_dev *related)
1679{
1680 struct pci_dev *dev = NULL;
1681
1682 dev = pci_get_device(vendor, device, dev);
1683 while (dev) {
1684 if ((dev->bus->number == related->bus->number) &&
1685 (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
1686 break;
1687 dev = pci_get_device(vendor, device, dev);
1688 }
1689
1690 return dev;
1691}
1692
Doug Thompsonb1289d62009-04-27 16:37:05 +02001693/*
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001694 * These are tables of eigenvectors (one per line) which can be used for the
1695 * construction of the syndrome tables. The modified syndrome search algorithm
1696 * uses those to find the symbol in error and thus the DIMM.
Doug Thompsonb1289d62009-04-27 16:37:05 +02001697 *
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001698 * Algorithm courtesy of Ross LaFetra from AMD.
Doug Thompsonb1289d62009-04-27 16:37:05 +02001699 */
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001700static u16 x4_vectors[] = {
1701 0x2f57, 0x1afe, 0x66cc, 0xdd88,
1702 0x11eb, 0x3396, 0x7f4c, 0xeac8,
1703 0x0001, 0x0002, 0x0004, 0x0008,
1704 0x1013, 0x3032, 0x4044, 0x8088,
1705 0x106b, 0x30d6, 0x70fc, 0xe0a8,
1706 0x4857, 0xc4fe, 0x13cc, 0x3288,
1707 0x1ac5, 0x2f4a, 0x5394, 0xa1e8,
1708 0x1f39, 0x251e, 0xbd6c, 0x6bd8,
1709 0x15c1, 0x2a42, 0x89ac, 0x4758,
1710 0x2b03, 0x1602, 0x4f0c, 0xca08,
1711 0x1f07, 0x3a0e, 0x6b04, 0xbd08,
1712 0x8ba7, 0x465e, 0x244c, 0x1cc8,
1713 0x2b87, 0x164e, 0x642c, 0xdc18,
1714 0x40b9, 0x80de, 0x1094, 0x20e8,
1715 0x27db, 0x1eb6, 0x9dac, 0x7b58,
1716 0x11c1, 0x2242, 0x84ac, 0x4c58,
1717 0x1be5, 0x2d7a, 0x5e34, 0xa718,
1718 0x4b39, 0x8d1e, 0x14b4, 0x28d8,
1719 0x4c97, 0xc87e, 0x11fc, 0x33a8,
1720 0x8e97, 0x497e, 0x2ffc, 0x1aa8,
1721 0x16b3, 0x3d62, 0x4f34, 0x8518,
1722 0x1e2f, 0x391a, 0x5cac, 0xf858,
1723 0x1d9f, 0x3b7a, 0x572c, 0xfe18,
1724 0x15f5, 0x2a5a, 0x5264, 0xa3b8,
1725 0x1dbb, 0x3b66, 0x715c, 0xe3f8,
1726 0x4397, 0xc27e, 0x17fc, 0x3ea8,
1727 0x1617, 0x3d3e, 0x6464, 0xb8b8,
1728 0x23ff, 0x12aa, 0xab6c, 0x56d8,
1729 0x2dfb, 0x1ba6, 0x913c, 0x7328,
1730 0x185d, 0x2ca6, 0x7914, 0x9e28,
1731 0x171b, 0x3e36, 0x7d7c, 0xebe8,
1732 0x4199, 0x82ee, 0x19f4, 0x2e58,
1733 0x4807, 0xc40e, 0x130c, 0x3208,
1734 0x1905, 0x2e0a, 0x5804, 0xac08,
1735 0x213f, 0x132a, 0xadfc, 0x5ba8,
1736 0x19a9, 0x2efe, 0xb5cc, 0x6f88,
Doug Thompsonb1289d62009-04-27 16:37:05 +02001737};
1738
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001739static u16 x8_vectors[] = {
1740 0x0145, 0x028a, 0x2374, 0x43c8, 0xa1f0, 0x0520, 0x0a40, 0x1480,
1741 0x0211, 0x0422, 0x0844, 0x1088, 0x01b0, 0x44e0, 0x23c0, 0xed80,
1742 0x1011, 0x0116, 0x022c, 0x0458, 0x08b0, 0x8c60, 0x2740, 0x4e80,
1743 0x0411, 0x0822, 0x1044, 0x0158, 0x02b0, 0x2360, 0x46c0, 0xab80,
1744 0x0811, 0x1022, 0x012c, 0x0258, 0x04b0, 0x4660, 0x8cc0, 0x2780,
1745 0x2071, 0x40e2, 0xa0c4, 0x0108, 0x0210, 0x0420, 0x0840, 0x1080,
1746 0x4071, 0x80e2, 0x0104, 0x0208, 0x0410, 0x0820, 0x1040, 0x2080,
1747 0x8071, 0x0102, 0x0204, 0x0408, 0x0810, 0x1020, 0x2040, 0x4080,
1748 0x019d, 0x03d6, 0x136c, 0x2198, 0x50b0, 0xb2e0, 0x0740, 0x0e80,
1749 0x0189, 0x03ea, 0x072c, 0x0e58, 0x1cb0, 0x56e0, 0x37c0, 0xf580,
1750 0x01fd, 0x0376, 0x06ec, 0x0bb8, 0x1110, 0x2220, 0x4440, 0x8880,
1751 0x0163, 0x02c6, 0x1104, 0x0758, 0x0eb0, 0x2be0, 0x6140, 0xc280,
1752 0x02fd, 0x01c6, 0x0b5c, 0x1108, 0x07b0, 0x25a0, 0x8840, 0x6180,
1753 0x0801, 0x012e, 0x025c, 0x04b8, 0x1370, 0x26e0, 0x57c0, 0xb580,
1754 0x0401, 0x0802, 0x015c, 0x02b8, 0x22b0, 0x13e0, 0x7140, 0xe280,
1755 0x0201, 0x0402, 0x0804, 0x01b8, 0x11b0, 0x31a0, 0x8040, 0x7180,
1756 0x0101, 0x0202, 0x0404, 0x0808, 0x1010, 0x2020, 0x4040, 0x8080,
1757 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
1758 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
1759};
1760
Borislav Petkovd34a6ec2011-02-23 17:41:50 +01001761static int decode_syndrome(u16 syndrome, u16 *vectors, unsigned num_vecs,
1762 unsigned v_dim)
Doug Thompsonb1289d62009-04-27 16:37:05 +02001763{
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001764 unsigned int i, err_sym;
Doug Thompsonb1289d62009-04-27 16:37:05 +02001765
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001766 for (err_sym = 0; err_sym < num_vecs / v_dim; err_sym++) {
1767 u16 s = syndrome;
Borislav Petkovd34a6ec2011-02-23 17:41:50 +01001768 unsigned v_idx = err_sym * v_dim;
1769 unsigned v_end = (err_sym + 1) * v_dim;
Doug Thompsonb1289d62009-04-27 16:37:05 +02001770
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001771 /* walk over all 16 bits of the syndrome */
1772 for (i = 1; i < (1U << 16); i <<= 1) {
1773
1774 /* if bit is set in that eigenvector... */
1775 if (v_idx < v_end && vectors[v_idx] & i) {
1776 u16 ev_comp = vectors[v_idx++];
1777
1778 /* ... and bit set in the modified syndrome, */
1779 if (s & i) {
1780 /* remove it. */
1781 s ^= ev_comp;
1782
1783 if (!s)
1784 return err_sym;
1785 }
1786
1787 } else if (s & i)
1788 /* can't get to zero, move to next symbol */
1789 break;
1790 }
Doug Thompsonb1289d62009-04-27 16:37:05 +02001791 }
1792
Joe Perches956b9ba2012-04-29 17:08:39 -03001793 edac_dbg(0, "syndrome(%x) not found\n", syndrome);
Doug Thompsonb1289d62009-04-27 16:37:05 +02001794 return -1;
1795}
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001796
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001797static int map_err_sym_to_channel(int err_sym, int sym_size)
1798{
1799 if (sym_size == 4)
1800 switch (err_sym) {
1801 case 0x20:
1802 case 0x21:
1803 return 0;
1804 break;
1805 case 0x22:
1806 case 0x23:
1807 return 1;
1808 break;
1809 default:
1810 return err_sym >> 4;
1811 break;
1812 }
1813 /* x8 symbols */
1814 else
1815 switch (err_sym) {
1816 /* imaginary bits not in a DIMM */
1817 case 0x10:
1818 WARN(1, KERN_ERR "Invalid error symbol: 0x%x\n",
1819 err_sym);
1820 return -1;
1821 break;
1822
1823 case 0x11:
1824 return 0;
1825 break;
1826 case 0x12:
1827 return 1;
1828 break;
1829 default:
1830 return err_sym >> 3;
1831 break;
1832 }
1833 return -1;
1834}
1835
1836static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
1837{
1838 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001839 int err_sym = -1;
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001840
Borislav Petkova3b7db02011-01-19 20:35:12 +01001841 if (pvt->ecc_sym_sz == 8)
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001842 err_sym = decode_syndrome(syndrome, x8_vectors,
1843 ARRAY_SIZE(x8_vectors),
Borislav Petkova3b7db02011-01-19 20:35:12 +01001844 pvt->ecc_sym_sz);
1845 else if (pvt->ecc_sym_sz == 4)
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001846 err_sym = decode_syndrome(syndrome, x4_vectors,
1847 ARRAY_SIZE(x4_vectors),
Borislav Petkova3b7db02011-01-19 20:35:12 +01001848 pvt->ecc_sym_sz);
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001849 else {
Borislav Petkova3b7db02011-01-19 20:35:12 +01001850 amd64_warn("Illegal syndrome type: %u\n", pvt->ecc_sym_sz);
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001851 return err_sym;
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001852 }
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001853
Borislav Petkova3b7db02011-01-19 20:35:12 +01001854 return map_err_sym_to_channel(err_sym, pvt->ecc_sym_sz);
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001855}
1856
Borislav Petkov33ca0642012-08-30 18:01:36 +02001857static void __log_bus_error(struct mem_ctl_info *mci, struct err_info *err,
1858 u8 ecc_type)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001859{
Borislav Petkov33ca0642012-08-30 18:01:36 +02001860 enum hw_event_mc_err_type err_type;
1861 const char *string;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001862
Borislav Petkov33ca0642012-08-30 18:01:36 +02001863 if (ecc_type == 2)
1864 err_type = HW_EVENT_ERR_CORRECTED;
1865 else if (ecc_type == 1)
1866 err_type = HW_EVENT_ERR_UNCORRECTED;
1867 else {
1868 WARN(1, "Something is rotten in the state of Denmark.\n");
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001869 return;
1870 }
1871
Borislav Petkov33ca0642012-08-30 18:01:36 +02001872 switch (err->err_code) {
1873 case DECODE_OK:
1874 string = "";
1875 break;
1876 case ERR_NODE:
1877 string = "Failed to map error addr to a node";
1878 break;
1879 case ERR_CSROW:
1880 string = "Failed to map error addr to a csrow";
1881 break;
1882 case ERR_CHANNEL:
1883 string = "unknown syndrome - possible error reporting race";
1884 break;
1885 default:
1886 string = "WTF error";
1887 break;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001888 }
Borislav Petkov33ca0642012-08-30 18:01:36 +02001889
1890 edac_mc_handle_error(err_type, mci, 1,
1891 err->page, err->offset, err->syndrome,
1892 err->csrow, err->channel, -1,
1893 string, "");
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001894}
1895
Borislav Petkov549d0422009-07-24 13:51:42 +02001896static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001897 struct mce *m)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001898{
Borislav Petkov33ca0642012-08-30 18:01:36 +02001899 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001900 u8 ecc_type = (m->status >> 45) & 0x3;
Borislav Petkov66fed2d2012-08-09 18:41:07 +02001901 u8 xec = XEC(m->status, 0x1f);
1902 u16 ec = EC(m->status);
Borislav Petkov33ca0642012-08-30 18:01:36 +02001903 u64 sys_addr;
1904 struct err_info err;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001905
Borislav Petkov66fed2d2012-08-09 18:41:07 +02001906 /* Bail out early if this was an 'observed' error */
Borislav Petkov5980bb92011-01-07 16:26:49 +01001907 if (PP(ec) == NBSL_PP_OBS)
Borislav Petkovb70ef012009-06-25 19:32:38 +02001908 return;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001909
Borislav Petkovecaf5602009-07-23 16:32:01 +02001910 /* Do only ECC errors */
1911 if (xec && xec != F10_NBSL_EXT_ERR_ECC)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001912 return;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001913
Borislav Petkov33ca0642012-08-30 18:01:36 +02001914 memset(&err, 0, sizeof(err));
1915
1916 sys_addr = get_error_address(m);
1917
Borislav Petkovecaf5602009-07-23 16:32:01 +02001918 if (ecc_type == 2)
Borislav Petkov33ca0642012-08-30 18:01:36 +02001919 err.syndrome = extract_syndrome(m->status);
1920
1921 pvt->ops->map_sysaddr_to_csrow(mci, sys_addr, &err);
1922
1923 __log_bus_error(mci, &err, ecc_type);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001924}
1925
Borislav Petkovb0b07a22011-08-24 18:44:22 +02001926void amd64_decode_bus_error(int node_id, struct mce *m)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001927{
Borislav Petkovb0b07a22011-08-24 18:44:22 +02001928 __amd64_decode_bus_error(mcis[node_id], m);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001929}
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001930
Doug Thompson0ec449e2009-04-27 19:41:25 +02001931/*
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001932 * Use pvt->F2 which contains the F2 CPU PCI device to get the related
Borislav Petkovbbd0c1f2010-10-01 19:27:58 +02001933 * F1 (AddrMap) and F3 (Misc) devices. Return negative value on error.
Doug Thompson0ec449e2009-04-27 19:41:25 +02001934 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02001935static int reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 f1_id, u16 f3_id)
Doug Thompson0ec449e2009-04-27 19:41:25 +02001936{
Doug Thompson0ec449e2009-04-27 19:41:25 +02001937 /* Reserve the ADDRESS MAP Device */
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001938 pvt->F1 = pci_get_related_function(pvt->F2->vendor, f1_id, pvt->F2);
1939 if (!pvt->F1) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001940 amd64_err("error address map device not found: "
1941 "vendor %x device 0x%x (broken BIOS?)\n",
1942 PCI_VENDOR_ID_AMD, f1_id);
Borislav Petkovbbd0c1f2010-10-01 19:27:58 +02001943 return -ENODEV;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001944 }
1945
1946 /* Reserve the MISC Device */
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001947 pvt->F3 = pci_get_related_function(pvt->F2->vendor, f3_id, pvt->F2);
1948 if (!pvt->F3) {
1949 pci_dev_put(pvt->F1);
1950 pvt->F1 = NULL;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001951
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001952 amd64_err("error F3 device not found: "
1953 "vendor %x device 0x%x (broken BIOS?)\n",
1954 PCI_VENDOR_ID_AMD, f3_id);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001955
Borislav Petkovbbd0c1f2010-10-01 19:27:58 +02001956 return -ENODEV;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001957 }
Joe Perches956b9ba2012-04-29 17:08:39 -03001958 edac_dbg(1, "F1: %s\n", pci_name(pvt->F1));
1959 edac_dbg(1, "F2: %s\n", pci_name(pvt->F2));
1960 edac_dbg(1, "F3: %s\n", pci_name(pvt->F3));
Doug Thompson0ec449e2009-04-27 19:41:25 +02001961
1962 return 0;
1963}
1964
Borislav Petkov360b7f32010-10-15 19:25:38 +02001965static void free_mc_sibling_devs(struct amd64_pvt *pvt)
Doug Thompson0ec449e2009-04-27 19:41:25 +02001966{
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001967 pci_dev_put(pvt->F1);
1968 pci_dev_put(pvt->F3);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001969}
1970
1971/*
1972 * Retrieve the hardware registers of the memory controller (this includes the
1973 * 'Address Map' and 'Misc' device regs)
1974 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02001975static void read_mc_regs(struct amd64_pvt *pvt)
Doug Thompson0ec449e2009-04-27 19:41:25 +02001976{
Borislav Petkova3b7db02011-01-19 20:35:12 +01001977 struct cpuinfo_x86 *c = &boot_cpu_data;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001978 u64 msr_val;
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001979 u32 tmp;
Borislav Petkove7613592011-02-21 19:49:01 +01001980 unsigned range;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001981
1982 /*
1983 * Retrieve TOP_MEM and TOP_MEM2; no masking off of reserved bits since
1984 * those are Read-As-Zero
1985 */
Borislav Petkove97f8bb2009-10-12 15:27:45 +02001986 rdmsrl(MSR_K8_TOP_MEM1, pvt->top_mem);
Joe Perches956b9ba2012-04-29 17:08:39 -03001987 edac_dbg(0, " TOP_MEM: 0x%016llx\n", pvt->top_mem);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001988
1989 /* check first whether TOP_MEM2 is enabled */
1990 rdmsrl(MSR_K8_SYSCFG, msr_val);
1991 if (msr_val & (1U << 21)) {
Borislav Petkove97f8bb2009-10-12 15:27:45 +02001992 rdmsrl(MSR_K8_TOP_MEM2, pvt->top_mem2);
Joe Perches956b9ba2012-04-29 17:08:39 -03001993 edac_dbg(0, " TOP_MEM2: 0x%016llx\n", pvt->top_mem2);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001994 } else
Joe Perches956b9ba2012-04-29 17:08:39 -03001995 edac_dbg(0, " TOP_MEM2 disabled\n");
Doug Thompson0ec449e2009-04-27 19:41:25 +02001996
Borislav Petkov5980bb92011-01-07 16:26:49 +01001997 amd64_read_pci_cfg(pvt->F3, NBCAP, &pvt->nbcap);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001998
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001999 read_dram_ctl_register(pvt);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002000
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002001 for (range = 0; range < DRAM_RANGES; range++) {
2002 u8 rw;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002003
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002004 /* read settings for this DRAM range */
2005 read_dram_base_limit_regs(pvt, range);
Borislav Petkove97f8bb2009-10-12 15:27:45 +02002006
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002007 rw = dram_rw(pvt, range);
2008 if (!rw)
2009 continue;
2010
Joe Perches956b9ba2012-04-29 17:08:39 -03002011 edac_dbg(1, " DRAM range[%d], base: 0x%016llx; limit: 0x%016llx\n",
2012 range,
2013 get_dram_base(pvt, range),
2014 get_dram_limit(pvt, range));
Borislav Petkov7f19bf72010-10-21 18:52:53 +02002015
Joe Perches956b9ba2012-04-29 17:08:39 -03002016 edac_dbg(1, " IntlvEn=%s; Range access: %s%s IntlvSel=%d DstNode=%d\n",
2017 dram_intlv_en(pvt, range) ? "Enabled" : "Disabled",
2018 (rw & 0x1) ? "R" : "-",
2019 (rw & 0x2) ? "W" : "-",
2020 dram_intlv_sel(pvt, range),
2021 dram_dst_node(pvt, range));
Doug Thompson0ec449e2009-04-27 19:41:25 +02002022 }
2023
Borislav Petkovb2b0c602010-10-08 18:32:29 +02002024 read_dct_base_mask(pvt);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002025
Borislav Petkovbc21fa52010-11-11 17:29:13 +01002026 amd64_read_pci_cfg(pvt->F1, DHAR, &pvt->dhar);
Borislav Petkov525a1b22010-12-21 15:53:27 +01002027 amd64_read_dct_pci_cfg(pvt, DBAM0, &pvt->dbam0);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002028
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002029 amd64_read_pci_cfg(pvt->F3, F10_ONLINE_SPARE, &pvt->online_spare);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002030
Borislav Petkovcb328502010-12-22 14:28:24 +01002031 amd64_read_dct_pci_cfg(pvt, DCLR0, &pvt->dclr0);
2032 amd64_read_dct_pci_cfg(pvt, DCHR0, &pvt->dchr0);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002033
Borislav Petkov78da1212010-12-22 19:31:45 +01002034 if (!dct_ganging_enabled(pvt)) {
Borislav Petkovcb328502010-12-22 14:28:24 +01002035 amd64_read_dct_pci_cfg(pvt, DCLR1, &pvt->dclr1);
2036 amd64_read_dct_pci_cfg(pvt, DCHR1, &pvt->dchr1);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002037 }
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002038
Borislav Petkova3b7db02011-01-19 20:35:12 +01002039 pvt->ecc_sym_sz = 4;
2040
2041 if (c->x86 >= 0x10) {
Borislav Petkovb2b0c602010-10-08 18:32:29 +02002042 amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
Borislav Petkov525a1b22010-12-21 15:53:27 +01002043 amd64_read_dct_pci_cfg(pvt, DBAM1, &pvt->dbam1);
Borislav Petkova3b7db02011-01-19 20:35:12 +01002044
2045 /* F10h, revD and later can do x8 ECC too */
2046 if ((c->x86 > 0x10 || c->x86_model > 7) && tmp & BIT(25))
2047 pvt->ecc_sym_sz = 8;
Borislav Petkov525a1b22010-12-21 15:53:27 +01002048 }
Borislav Petkovb2b0c602010-10-08 18:32:29 +02002049 dump_misc_regs(pvt);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002050}
2051
2052/*
2053 * NOTE: CPU Revision Dependent code
2054 *
2055 * Input:
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002056 * @csrow_nr ChipSelect Row Number (0..NUM_CHIPSELECTS-1)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002057 * k8 private pointer to -->
2058 * DRAM Bank Address mapping register
2059 * node_id
2060 * DCL register where dual_channel_active is
2061 *
2062 * The DBAM register consists of 4 sets of 4 bits each definitions:
2063 *
2064 * Bits: CSROWs
2065 * 0-3 CSROWs 0 and 1
2066 * 4-7 CSROWs 2 and 3
2067 * 8-11 CSROWs 4 and 5
2068 * 12-15 CSROWs 6 and 7
2069 *
2070 * Values range from: 0 to 15
2071 * The meaning of the values depends on CPU revision and dual-channel state,
2072 * see relevant BKDG more info.
2073 *
2074 * The memory controller provides for total of only 8 CSROWs in its current
2075 * architecture. Each "pair" of CSROWs normally represents just one DIMM in
2076 * single channel or two (2) DIMMs in dual channel mode.
2077 *
2078 * The following code logic collapses the various tables for CSROW based on CPU
2079 * revision.
2080 *
2081 * Returns:
2082 * The number of PAGE_SIZE pages on the specified CSROW number it
2083 * encompasses
2084 *
2085 */
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01002086static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002087{
Borislav Petkov1433eb92009-10-21 13:44:36 +02002088 u32 cs_mode, nr_pages;
Ashish Shenoyf92cae42012-02-22 17:20:38 -08002089 u32 dbam = dct ? pvt->dbam1 : pvt->dbam0;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002090
Borislav Petkov10de6492012-09-12 19:00:38 +02002091
Doug Thompson0ec449e2009-04-27 19:41:25 +02002092 /*
2093 * The math on this doesn't look right on the surface because x/2*4 can
2094 * be simplified to x*2 but this expression makes use of the fact that
2095 * it is integral math where 1/2=0. This intermediate value becomes the
2096 * number of bits to shift the DBAM register to extract the proper CSROW
2097 * field.
2098 */
Borislav Petkov0a5dfc32012-09-12 18:16:01 +02002099 cs_mode = DBAM_DIMM(csrow_nr / 2, dbam);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002100
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01002101 nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002102
Borislav Petkov10de6492012-09-12 19:00:38 +02002103 edac_dbg(0, "csrow: %d, channel: %d, DBAM idx: %d\n",
2104 csrow_nr, dct, cs_mode);
2105 edac_dbg(0, "nr_pages/channel: %u\n", nr_pages);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002106
2107 return nr_pages;
2108}
2109
2110/*
2111 * Initialize the array of csrow attribute instances, based on the values
2112 * from pci config hardware registers.
2113 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02002114static int init_csrows(struct mem_ctl_info *mci)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002115{
Borislav Petkov10de6492012-09-12 19:00:38 +02002116 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002117 struct csrow_info *csrow;
Mauro Carvalho Chehabde3910eb2012-04-24 15:05:43 -03002118 struct dimm_info *dimm;
Mauro Carvalho Chehab084a4fc2012-01-27 18:38:08 -03002119 enum edac_type edac_mode;
Borislav Petkov10de6492012-09-12 19:00:38 +02002120 enum mem_type mtype;
2121 int i, j, empty = 1;
Mauro Carvalho Chehaba895bf82012-01-28 09:09:38 -03002122 int nr_pages = 0;
Borislav Petkov10de6492012-09-12 19:00:38 +02002123 u32 val;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002124
Borislav Petkova97fa682010-12-23 14:07:18 +01002125 amd64_read_pci_cfg(pvt->F3, NBCFG, &val);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002126
Borislav Petkov2299ef72010-10-15 17:44:04 +02002127 pvt->nbcfg = val;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002128
Joe Perches956b9ba2012-04-29 17:08:39 -03002129 edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
2130 pvt->mc_node_id, val,
2131 !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
Doug Thompson0ec449e2009-04-27 19:41:25 +02002132
Borislav Petkov10de6492012-09-12 19:00:38 +02002133 /*
2134 * We iterate over DCT0 here but we look at DCT1 in parallel, if needed.
2135 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002136 for_each_chip_select(i, 0, pvt) {
Borislav Petkov10de6492012-09-12 19:00:38 +02002137 bool row_dct0 = !!csrow_enabled(i, 0, pvt);
2138 bool row_dct1 = false;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002139
Borislav Petkov10de6492012-09-12 19:00:38 +02002140 if (boot_cpu_data.x86 != 0xf)
2141 row_dct1 = !!csrow_enabled(i, 1, pvt);
2142
2143 if (!row_dct0 && !row_dct1)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002144 continue;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002145
Borislav Petkov10de6492012-09-12 19:00:38 +02002146 csrow = mci->csrows[i];
Doug Thompson0ec449e2009-04-27 19:41:25 +02002147 empty = 0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002148
Borislav Petkov10de6492012-09-12 19:00:38 +02002149 edac_dbg(1, "MC node: %d, csrow: %d\n",
2150 pvt->mc_node_id, i);
2151
2152 if (row_dct0)
2153 nr_pages = amd64_csrow_nr_pages(pvt, 0, i);
2154
2155 /* K8 has only one DCT */
2156 if (boot_cpu_data.x86 != 0xf && row_dct1)
2157 nr_pages += amd64_csrow_nr_pages(pvt, 1, i);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002158
Mauro Carvalho Chehab084a4fc2012-01-27 18:38:08 -03002159 mtype = amd64_determine_memory_type(pvt, i);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002160
Borislav Petkov10de6492012-09-12 19:00:38 +02002161 edac_dbg(1, "Total csrow%d pages: %u\n", i, nr_pages);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002162
2163 /*
2164 * determine whether CHIPKILL or JUST ECC or NO ECC is operating
2165 */
Borislav Petkova97fa682010-12-23 14:07:18 +01002166 if (pvt->nbcfg & NBCFG_ECC_ENABLE)
Mauro Carvalho Chehab084a4fc2012-01-27 18:38:08 -03002167 edac_mode = (pvt->nbcfg & NBCFG_CHIPKILL) ?
2168 EDAC_S4ECD4ED : EDAC_SECDED;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002169 else
Mauro Carvalho Chehab084a4fc2012-01-27 18:38:08 -03002170 edac_mode = EDAC_NONE;
2171
2172 for (j = 0; j < pvt->channel_count; j++) {
Mauro Carvalho Chehabde3910eb2012-04-24 15:05:43 -03002173 dimm = csrow->channels[j]->dimm;
2174 dimm->mtype = mtype;
2175 dimm->edac_mode = edac_mode;
2176 dimm->nr_pages = nr_pages;
Mauro Carvalho Chehab084a4fc2012-01-27 18:38:08 -03002177 }
Borislav Petkov16a528ee2012-09-13 18:53:58 +02002178 csrow->nr_pages = nr_pages;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002179 }
2180
2181 return empty;
2182}
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002183
Borislav Petkov06724532009-09-16 13:05:46 +02002184/* get all cores on this DCT */
Daniel J Blueman8b84c8d2012-11-27 14:32:10 +08002185static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, u16 nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02002186{
Borislav Petkov06724532009-09-16 13:05:46 +02002187 int cpu;
Doug Thompsonf9431992009-04-27 19:46:08 +02002188
Borislav Petkov06724532009-09-16 13:05:46 +02002189 for_each_online_cpu(cpu)
2190 if (amd_get_nb_id(cpu) == nid)
2191 cpumask_set_cpu(cpu, mask);
Doug Thompsonf9431992009-04-27 19:46:08 +02002192}
2193
2194/* check MCG_CTL on all the cpus on this node */
Borislav Petkovb487c332011-02-21 18:55:00 +01002195static bool amd64_nb_mce_bank_enabled_on_node(unsigned nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02002196{
Rusty Russellba578cb2009-11-03 14:56:35 +10302197 cpumask_var_t mask;
Borislav Petkov50542252009-12-11 18:14:40 +01002198 int cpu, nbe;
Borislav Petkov06724532009-09-16 13:05:46 +02002199 bool ret = false;
Doug Thompsonf9431992009-04-27 19:46:08 +02002200
Rusty Russellba578cb2009-11-03 14:56:35 +10302201 if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002202 amd64_warn("%s: Error allocating mask\n", __func__);
Rusty Russellba578cb2009-11-03 14:56:35 +10302203 return false;
2204 }
Borislav Petkov06724532009-09-16 13:05:46 +02002205
Rusty Russellba578cb2009-11-03 14:56:35 +10302206 get_cpus_on_this_dct_cpumask(mask, nid);
Borislav Petkov06724532009-09-16 13:05:46 +02002207
Rusty Russellba578cb2009-11-03 14:56:35 +10302208 rdmsr_on_cpus(mask, MSR_IA32_MCG_CTL, msrs);
Borislav Petkov06724532009-09-16 13:05:46 +02002209
Rusty Russellba578cb2009-11-03 14:56:35 +10302210 for_each_cpu(cpu, mask) {
Borislav Petkov50542252009-12-11 18:14:40 +01002211 struct msr *reg = per_cpu_ptr(msrs, cpu);
Borislav Petkov5980bb92011-01-07 16:26:49 +01002212 nbe = reg->l & MSR_MCGCTL_NBE;
Borislav Petkov06724532009-09-16 13:05:46 +02002213
Joe Perches956b9ba2012-04-29 17:08:39 -03002214 edac_dbg(0, "core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n",
2215 cpu, reg->q,
2216 (nbe ? "enabled" : "disabled"));
Borislav Petkov06724532009-09-16 13:05:46 +02002217
2218 if (!nbe)
2219 goto out;
Borislav Petkov06724532009-09-16 13:05:46 +02002220 }
2221 ret = true;
2222
2223out:
Rusty Russellba578cb2009-11-03 14:56:35 +10302224 free_cpumask_var(mask);
Doug Thompsonf9431992009-04-27 19:46:08 +02002225 return ret;
2226}
2227
Borislav Petkov2299ef72010-10-15 17:44:04 +02002228static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002229{
2230 cpumask_var_t cmask;
Borislav Petkov50542252009-12-11 18:14:40 +01002231 int cpu;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002232
2233 if (!zalloc_cpumask_var(&cmask, GFP_KERNEL)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002234 amd64_warn("%s: error allocating mask\n", __func__);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002235 return false;
2236 }
2237
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002238 get_cpus_on_this_dct_cpumask(cmask, nid);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002239
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002240 rdmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
2241
2242 for_each_cpu(cpu, cmask) {
2243
Borislav Petkov50542252009-12-11 18:14:40 +01002244 struct msr *reg = per_cpu_ptr(msrs, cpu);
2245
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002246 if (on) {
Borislav Petkov5980bb92011-01-07 16:26:49 +01002247 if (reg->l & MSR_MCGCTL_NBE)
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002248 s->flags.nb_mce_enable = 1;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002249
Borislav Petkov5980bb92011-01-07 16:26:49 +01002250 reg->l |= MSR_MCGCTL_NBE;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002251 } else {
2252 /*
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002253 * Turn off NB MCE reporting only when it was off before
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002254 */
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002255 if (!s->flags.nb_mce_enable)
Borislav Petkov5980bb92011-01-07 16:26:49 +01002256 reg->l &= ~MSR_MCGCTL_NBE;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002257 }
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002258 }
2259 wrmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
2260
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002261 free_cpumask_var(cmask);
2262
2263 return 0;
2264}
2265
Borislav Petkov2299ef72010-10-15 17:44:04 +02002266static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
2267 struct pci_dev *F3)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002268{
Borislav Petkov2299ef72010-10-15 17:44:04 +02002269 bool ret = true;
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002270 u32 value, mask = 0x3; /* UECC/CECC enable */
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002271
Borislav Petkov2299ef72010-10-15 17:44:04 +02002272 if (toggle_ecc_err_reporting(s, nid, ON)) {
2273 amd64_warn("Error enabling ECC reporting over MCGCTL!\n");
2274 return false;
2275 }
2276
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002277 amd64_read_pci_cfg(F3, NBCTL, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002278
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002279 s->old_nbctl = value & mask;
2280 s->nbctl_valid = true;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002281
2282 value |= mask;
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002283 amd64_write_pci_cfg(F3, NBCTL, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002284
Borislav Petkova97fa682010-12-23 14:07:18 +01002285 amd64_read_pci_cfg(F3, NBCFG, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002286
Joe Perches956b9ba2012-04-29 17:08:39 -03002287 edac_dbg(0, "1: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
2288 nid, value, !!(value & NBCFG_ECC_ENABLE));
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002289
Borislav Petkova97fa682010-12-23 14:07:18 +01002290 if (!(value & NBCFG_ECC_ENABLE)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002291 amd64_warn("DRAM ECC disabled on this node, enabling...\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002292
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002293 s->flags.nb_ecc_prev = 0;
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002294
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002295 /* Attempt to turn on DRAM ECC Enable */
Borislav Petkova97fa682010-12-23 14:07:18 +01002296 value |= NBCFG_ECC_ENABLE;
2297 amd64_write_pci_cfg(F3, NBCFG, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002298
Borislav Petkova97fa682010-12-23 14:07:18 +01002299 amd64_read_pci_cfg(F3, NBCFG, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002300
Borislav Petkova97fa682010-12-23 14:07:18 +01002301 if (!(value & NBCFG_ECC_ENABLE)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002302 amd64_warn("Hardware rejected DRAM ECC enable,"
2303 "check memory DIMM configuration.\n");
Borislav Petkov2299ef72010-10-15 17:44:04 +02002304 ret = false;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002305 } else {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002306 amd64_info("Hardware accepted DRAM ECC Enable\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002307 }
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002308 } else {
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002309 s->flags.nb_ecc_prev = 1;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002310 }
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002311
Joe Perches956b9ba2012-04-29 17:08:39 -03002312 edac_dbg(0, "2: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
2313 nid, value, !!(value & NBCFG_ECC_ENABLE));
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002314
Borislav Petkov2299ef72010-10-15 17:44:04 +02002315 return ret;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002316}
2317
Borislav Petkov360b7f32010-10-15 19:25:38 +02002318static void restore_ecc_error_reporting(struct ecc_settings *s, u8 nid,
2319 struct pci_dev *F3)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002320{
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002321 u32 value, mask = 0x3; /* UECC/CECC enable */
2322
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002323
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002324 if (!s->nbctl_valid)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002325 return;
2326
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002327 amd64_read_pci_cfg(F3, NBCTL, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002328 value &= ~mask;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002329 value |= s->old_nbctl;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002330
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002331 amd64_write_pci_cfg(F3, NBCTL, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002332
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002333 /* restore previous BIOS DRAM ECC "off" setting we force-enabled */
2334 if (!s->flags.nb_ecc_prev) {
Borislav Petkova97fa682010-12-23 14:07:18 +01002335 amd64_read_pci_cfg(F3, NBCFG, &value);
2336 value &= ~NBCFG_ECC_ENABLE;
2337 amd64_write_pci_cfg(F3, NBCFG, value);
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002338 }
2339
2340 /* restore the NB Enable MCGCTL bit */
Borislav Petkov2299ef72010-10-15 17:44:04 +02002341 if (toggle_ecc_err_reporting(s, nid, OFF))
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002342 amd64_warn("Error restoring NB MCGCTL settings!\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002343}
2344
Doug Thompsonf9431992009-04-27 19:46:08 +02002345/*
Borislav Petkov2299ef72010-10-15 17:44:04 +02002346 * EDAC requires that the BIOS have ECC enabled before
2347 * taking over the processing of ECC errors. A command line
2348 * option allows to force-enable hardware ECC later in
2349 * enable_ecc_error_reporting().
Doug Thompsonf9431992009-04-27 19:46:08 +02002350 */
Borislav Petkovcab4d272010-02-11 17:15:57 +01002351static const char *ecc_msg =
2352 "ECC disabled in the BIOS or no ECC capability, module will not load.\n"
2353 " Either enable ECC checking or force module loading by setting "
2354 "'ecc_enable_override'.\n"
2355 " (Note that use of the override may cause unknown side effects.)\n";
Borislav Petkovbe3468e2009-08-05 15:47:22 +02002356
Borislav Petkov2299ef72010-10-15 17:44:04 +02002357static bool ecc_enabled(struct pci_dev *F3, u8 nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02002358{
2359 u32 value;
Borislav Petkov2299ef72010-10-15 17:44:04 +02002360 u8 ecc_en = 0;
Borislav Petkov06724532009-09-16 13:05:46 +02002361 bool nb_mce_en = false;
Doug Thompsonf9431992009-04-27 19:46:08 +02002362
Borislav Petkova97fa682010-12-23 14:07:18 +01002363 amd64_read_pci_cfg(F3, NBCFG, &value);
Doug Thompsonf9431992009-04-27 19:46:08 +02002364
Borislav Petkova97fa682010-12-23 14:07:18 +01002365 ecc_en = !!(value & NBCFG_ECC_ENABLE);
Borislav Petkov2299ef72010-10-15 17:44:04 +02002366 amd64_info("DRAM ECC %s.\n", (ecc_en ? "enabled" : "disabled"));
Doug Thompsonf9431992009-04-27 19:46:08 +02002367
Borislav Petkov2299ef72010-10-15 17:44:04 +02002368 nb_mce_en = amd64_nb_mce_bank_enabled_on_node(nid);
Borislav Petkov06724532009-09-16 13:05:46 +02002369 if (!nb_mce_en)
Borislav Petkov2299ef72010-10-15 17:44:04 +02002370 amd64_notice("NB MCE bank disabled, set MSR "
2371 "0x%08x[4] on node %d to enable.\n",
2372 MSR_IA32_MCG_CTL, nid);
Doug Thompsonf9431992009-04-27 19:46:08 +02002373
Borislav Petkov2299ef72010-10-15 17:44:04 +02002374 if (!ecc_en || !nb_mce_en) {
2375 amd64_notice("%s", ecc_msg);
2376 return false;
Borislav Petkov43f5e682009-12-21 18:55:18 +01002377 }
Borislav Petkov2299ef72010-10-15 17:44:04 +02002378 return true;
Doug Thompsonf9431992009-04-27 19:46:08 +02002379}
2380
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -03002381static int set_mc_sysfs_attrs(struct mem_ctl_info *mci)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002382{
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -03002383 int rc;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002384
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -03002385 rc = amd64_create_sysfs_dbg_files(mci);
2386 if (rc < 0)
2387 return rc;
2388
2389 if (boot_cpu_data.x86 >= 0x10) {
2390 rc = amd64_create_sysfs_inject_files(mci);
2391 if (rc < 0)
2392 return rc;
2393 }
2394
2395 return 0;
2396}
2397
2398static void del_mc_sysfs_attrs(struct mem_ctl_info *mci)
2399{
2400 amd64_remove_sysfs_dbg_files(mci);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002401
Borislav Petkova135cef2010-11-26 19:24:44 +01002402 if (boot_cpu_data.x86 >= 0x10)
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -03002403 amd64_remove_sysfs_inject_files(mci);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002404}
2405
Borislav Petkovdf71a052011-01-19 18:15:10 +01002406static void setup_mci_misc_attrs(struct mem_ctl_info *mci,
2407 struct amd64_family_type *fam)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002408{
2409 struct amd64_pvt *pvt = mci->pvt_info;
2410
2411 mci->mtype_cap = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2;
2412 mci->edac_ctl_cap = EDAC_FLAG_NONE;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002413
Borislav Petkov5980bb92011-01-07 16:26:49 +01002414 if (pvt->nbcap & NBCAP_SECDED)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002415 mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
2416
Borislav Petkov5980bb92011-01-07 16:26:49 +01002417 if (pvt->nbcap & NBCAP_CHIPKILL)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002418 mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
2419
2420 mci->edac_cap = amd64_determine_edac_cap(pvt);
2421 mci->mod_name = EDAC_MOD_STR;
2422 mci->mod_ver = EDAC_AMD64_VERSION;
Borislav Petkovdf71a052011-01-19 18:15:10 +01002423 mci->ctl_name = fam->ctl_name;
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002424 mci->dev_name = pci_name(pvt->F2);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002425 mci->ctl_page_to_phys = NULL;
2426
Doug Thompson7d6034d2009-04-27 20:01:01 +02002427 /* memory scrubber interface */
2428 mci->set_sdram_scrub_rate = amd64_set_scrub_rate;
2429 mci->get_sdram_scrub_rate = amd64_get_scrub_rate;
2430}
2431
Borislav Petkov0092b202010-10-01 19:20:05 +02002432/*
2433 * returns a pointer to the family descriptor on success, NULL otherwise.
2434 */
2435static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)
Borislav Petkov395ae782010-10-01 18:38:19 +02002436{
Borislav Petkov0092b202010-10-01 19:20:05 +02002437 u8 fam = boot_cpu_data.x86;
2438 struct amd64_family_type *fam_type = NULL;
2439
2440 switch (fam) {
Borislav Petkov395ae782010-10-01 18:38:19 +02002441 case 0xf:
Borislav Petkov0092b202010-10-01 19:20:05 +02002442 fam_type = &amd64_family_types[K8_CPUS];
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002443 pvt->ops = &amd64_family_types[K8_CPUS].ops;
Borislav Petkov395ae782010-10-01 18:38:19 +02002444 break;
Borislav Petkovdf71a052011-01-19 18:15:10 +01002445
Borislav Petkov395ae782010-10-01 18:38:19 +02002446 case 0x10:
Borislav Petkov0092b202010-10-01 19:20:05 +02002447 fam_type = &amd64_family_types[F10_CPUS];
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002448 pvt->ops = &amd64_family_types[F10_CPUS].ops;
Borislav Petkovdf71a052011-01-19 18:15:10 +01002449 break;
2450
2451 case 0x15:
2452 fam_type = &amd64_family_types[F15_CPUS];
2453 pvt->ops = &amd64_family_types[F15_CPUS].ops;
Borislav Petkov395ae782010-10-01 18:38:19 +02002454 break;
2455
2456 default:
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002457 amd64_err("Unsupported family!\n");
Borislav Petkov0092b202010-10-01 19:20:05 +02002458 return NULL;
Borislav Petkov395ae782010-10-01 18:38:19 +02002459 }
Borislav Petkov0092b202010-10-01 19:20:05 +02002460
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002461 pvt->ext_model = boot_cpu_data.x86_model >> 4;
2462
Borislav Petkovdf71a052011-01-19 18:15:10 +01002463 amd64_info("%s %sdetected (node %d).\n", fam_type->ctl_name,
Borislav Petkov0092b202010-10-01 19:20:05 +02002464 (fam == 0xf ?
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002465 (pvt->ext_model >= K8_REV_F ? "revF or later "
2466 : "revE or earlier ")
2467 : ""), pvt->mc_node_id);
Borislav Petkov0092b202010-10-01 19:20:05 +02002468 return fam_type;
Borislav Petkov395ae782010-10-01 18:38:19 +02002469}
2470
Borislav Petkov2299ef72010-10-15 17:44:04 +02002471static int amd64_init_one_instance(struct pci_dev *F2)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002472{
2473 struct amd64_pvt *pvt = NULL;
Borislav Petkov0092b202010-10-01 19:20:05 +02002474 struct amd64_family_type *fam_type = NULL;
Borislav Petkov360b7f32010-10-15 19:25:38 +02002475 struct mem_ctl_info *mci = NULL;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03002476 struct edac_mc_layer layers[2];
Doug Thompson7d6034d2009-04-27 20:01:01 +02002477 int err = 0, ret;
Daniel J Blueman772c3ff2012-11-27 14:32:09 +08002478 u16 nid = amd_get_node_id(F2);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002479
2480 ret = -ENOMEM;
2481 pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
2482 if (!pvt)
Borislav Petkov360b7f32010-10-15 19:25:38 +02002483 goto err_ret;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002484
Borislav Petkov360b7f32010-10-15 19:25:38 +02002485 pvt->mc_node_id = nid;
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002486 pvt->F2 = F2;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002487
Borislav Petkov395ae782010-10-01 18:38:19 +02002488 ret = -EINVAL;
Borislav Petkov0092b202010-10-01 19:20:05 +02002489 fam_type = amd64_per_family_init(pvt);
2490 if (!fam_type)
Borislav Petkov395ae782010-10-01 18:38:19 +02002491 goto err_free;
2492
Doug Thompson7d6034d2009-04-27 20:01:01 +02002493 ret = -ENODEV;
Borislav Petkov360b7f32010-10-15 19:25:38 +02002494 err = reserve_mc_sibling_devs(pvt, fam_type->f1_id, fam_type->f3_id);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002495 if (err)
2496 goto err_free;
2497
Borislav Petkov360b7f32010-10-15 19:25:38 +02002498 read_mc_regs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002499
Doug Thompson7d6034d2009-04-27 20:01:01 +02002500 /*
2501 * We need to determine how many memory channels there are. Then use
2502 * that information for calculating the size of the dynamic instance
Borislav Petkov360b7f32010-10-15 19:25:38 +02002503 * tables in the 'mci' structure.
Doug Thompson7d6034d2009-04-27 20:01:01 +02002504 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02002505 ret = -EINVAL;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002506 pvt->channel_count = pvt->ops->early_channel_count(pvt);
2507 if (pvt->channel_count < 0)
Borislav Petkov360b7f32010-10-15 19:25:38 +02002508 goto err_siblings;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002509
2510 ret = -ENOMEM;
Mauro Carvalho Chehabab5a5032012-04-16 15:03:50 -03002511 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
2512 layers[0].size = pvt->csels[0].b_cnt;
2513 layers[0].is_virt_csrow = true;
2514 layers[1].type = EDAC_MC_LAYER_CHANNEL;
2515 layers[1].size = pvt->channel_count;
2516 layers[1].is_virt_csrow = false;
Mauro Carvalho Chehabca0907b2012-05-02 14:37:00 -03002517 mci = edac_mc_alloc(nid, ARRAY_SIZE(layers), layers, 0);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002518 if (!mci)
Borislav Petkov360b7f32010-10-15 19:25:38 +02002519 goto err_siblings;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002520
2521 mci->pvt_info = pvt;
Mauro Carvalho Chehabfd687502012-03-16 07:44:18 -03002522 mci->pdev = &pvt->F2->dev;
Borislav Petkov11652762012-09-13 17:19:40 +02002523 mci->csbased = 1;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002524
Borislav Petkovdf71a052011-01-19 18:15:10 +01002525 setup_mci_misc_attrs(mci, fam_type);
Borislav Petkov360b7f32010-10-15 19:25:38 +02002526
2527 if (init_csrows(mci))
Doug Thompson7d6034d2009-04-27 20:01:01 +02002528 mci->edac_cap = EDAC_FLAG_NONE;
2529
Doug Thompson7d6034d2009-04-27 20:01:01 +02002530 ret = -ENODEV;
2531 if (edac_mc_add_mc(mci)) {
Joe Perches956b9ba2012-04-29 17:08:39 -03002532 edac_dbg(1, "failed edac_mc_add_mc()\n");
Doug Thompson7d6034d2009-04-27 20:01:01 +02002533 goto err_add_mc;
2534 }
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -03002535 if (set_mc_sysfs_attrs(mci)) {
Joe Perches956b9ba2012-04-29 17:08:39 -03002536 edac_dbg(1, "failed edac_mc_add_mc()\n");
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -03002537 goto err_add_sysfs;
2538 }
Doug Thompson7d6034d2009-04-27 20:01:01 +02002539
Borislav Petkov549d0422009-07-24 13:51:42 +02002540 /* register stuff with EDAC MCE */
2541 if (report_gart_errors)
2542 amd_report_gart_errors(true);
2543
2544 amd_register_ecc_decoder(amd64_decode_bus_error);
2545
Borislav Petkov360b7f32010-10-15 19:25:38 +02002546 mcis[nid] = mci;
2547
2548 atomic_inc(&drv_instances);
2549
Doug Thompson7d6034d2009-04-27 20:01:01 +02002550 return 0;
2551
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -03002552err_add_sysfs:
2553 edac_mc_del_mc(mci->pdev);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002554err_add_mc:
2555 edac_mc_free(mci);
2556
Borislav Petkov360b7f32010-10-15 19:25:38 +02002557err_siblings:
2558 free_mc_sibling_devs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002559
Borislav Petkov360b7f32010-10-15 19:25:38 +02002560err_free:
2561 kfree(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002562
Borislav Petkov360b7f32010-10-15 19:25:38 +02002563err_ret:
Doug Thompson7d6034d2009-04-27 20:01:01 +02002564 return ret;
2565}
2566
Greg Kroah-Hartman9b3c6e82012-12-21 13:23:51 -08002567static int amd64_probe_one_instance(struct pci_dev *pdev,
2568 const struct pci_device_id *mc_type)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002569{
Daniel J Blueman772c3ff2012-11-27 14:32:09 +08002570 u16 nid = amd_get_node_id(pdev);
Borislav Petkov2299ef72010-10-15 17:44:04 +02002571 struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002572 struct ecc_settings *s;
Borislav Petkov2299ef72010-10-15 17:44:04 +02002573 int ret = 0;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002574
Doug Thompson7d6034d2009-04-27 20:01:01 +02002575 ret = pci_enable_device(pdev);
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002576 if (ret < 0) {
Joe Perches956b9ba2012-04-29 17:08:39 -03002577 edac_dbg(0, "ret=%d\n", ret);
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002578 return -EIO;
2579 }
2580
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002581 ret = -ENOMEM;
2582 s = kzalloc(sizeof(struct ecc_settings), GFP_KERNEL);
2583 if (!s)
Borislav Petkov2299ef72010-10-15 17:44:04 +02002584 goto err_out;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002585
2586 ecc_stngs[nid] = s;
2587
Borislav Petkov2299ef72010-10-15 17:44:04 +02002588 if (!ecc_enabled(F3, nid)) {
2589 ret = -ENODEV;
2590
2591 if (!ecc_enable_override)
2592 goto err_enable;
2593
2594 amd64_warn("Forcing ECC on!\n");
2595
2596 if (!enable_ecc_error_reporting(s, nid, F3))
2597 goto err_enable;
2598 }
2599
2600 ret = amd64_init_one_instance(pdev);
Borislav Petkov360b7f32010-10-15 19:25:38 +02002601 if (ret < 0) {
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002602 amd64_err("Error probing instance: %d\n", nid);
Borislav Petkov360b7f32010-10-15 19:25:38 +02002603 restore_ecc_error_reporting(s, nid, F3);
2604 }
Doug Thompson7d6034d2009-04-27 20:01:01 +02002605
2606 return ret;
Borislav Petkov2299ef72010-10-15 17:44:04 +02002607
2608err_enable:
2609 kfree(s);
2610 ecc_stngs[nid] = NULL;
2611
2612err_out:
2613 return ret;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002614}
2615
Greg Kroah-Hartman9b3c6e82012-12-21 13:23:51 -08002616static void amd64_remove_one_instance(struct pci_dev *pdev)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002617{
2618 struct mem_ctl_info *mci;
2619 struct amd64_pvt *pvt;
Daniel J Blueman772c3ff2012-11-27 14:32:09 +08002620 u16 nid = amd_get_node_id(pdev);
Borislav Petkov360b7f32010-10-15 19:25:38 +02002621 struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
2622 struct ecc_settings *s = ecc_stngs[nid];
Doug Thompson7d6034d2009-04-27 20:01:01 +02002623
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -03002624 mci = find_mci_by_dev(&pdev->dev);
2625 del_mc_sysfs_attrs(mci);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002626 /* Remove from EDAC CORE tracking list */
2627 mci = edac_mc_del_mc(&pdev->dev);
2628 if (!mci)
2629 return;
2630
2631 pvt = mci->pvt_info;
2632
Borislav Petkov360b7f32010-10-15 19:25:38 +02002633 restore_ecc_error_reporting(s, nid, F3);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002634
Borislav Petkov360b7f32010-10-15 19:25:38 +02002635 free_mc_sibling_devs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002636
Borislav Petkov549d0422009-07-24 13:51:42 +02002637 /* unregister from EDAC MCE */
2638 amd_report_gart_errors(false);
2639 amd_unregister_ecc_decoder(amd64_decode_bus_error);
2640
Borislav Petkov360b7f32010-10-15 19:25:38 +02002641 kfree(ecc_stngs[nid]);
2642 ecc_stngs[nid] = NULL;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002643
Doug Thompson7d6034d2009-04-27 20:01:01 +02002644 /* Free the EDAC CORE resources */
Borislav Petkov8f68ed92009-12-21 15:15:59 +01002645 mci->pvt_info = NULL;
Borislav Petkov360b7f32010-10-15 19:25:38 +02002646 mcis[nid] = NULL;
Borislav Petkov8f68ed92009-12-21 15:15:59 +01002647
2648 kfree(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002649 edac_mc_free(mci);
2650}
2651
2652/*
2653 * This table is part of the interface for loading drivers for PCI devices. The
2654 * PCI core identifies what devices are on a system during boot, and then
2655 * inquiry this table to see if this driver is for a given device found.
2656 */
Lionel Debroux36c46f32012-02-27 07:41:47 +01002657static DEFINE_PCI_DEVICE_TABLE(amd64_pci_table) = {
Doug Thompson7d6034d2009-04-27 20:01:01 +02002658 {
2659 .vendor = PCI_VENDOR_ID_AMD,
2660 .device = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL,
2661 .subvendor = PCI_ANY_ID,
2662 .subdevice = PCI_ANY_ID,
2663 .class = 0,
2664 .class_mask = 0,
Doug Thompson7d6034d2009-04-27 20:01:01 +02002665 },
2666 {
2667 .vendor = PCI_VENDOR_ID_AMD,
2668 .device = PCI_DEVICE_ID_AMD_10H_NB_DRAM,
2669 .subvendor = PCI_ANY_ID,
2670 .subdevice = PCI_ANY_ID,
2671 .class = 0,
2672 .class_mask = 0,
Doug Thompson7d6034d2009-04-27 20:01:01 +02002673 },
Borislav Petkovdf71a052011-01-19 18:15:10 +01002674 {
2675 .vendor = PCI_VENDOR_ID_AMD,
2676 .device = PCI_DEVICE_ID_AMD_15H_NB_F2,
2677 .subvendor = PCI_ANY_ID,
2678 .subdevice = PCI_ANY_ID,
2679 .class = 0,
2680 .class_mask = 0,
2681 },
2682
Doug Thompson7d6034d2009-04-27 20:01:01 +02002683 {0, }
2684};
2685MODULE_DEVICE_TABLE(pci, amd64_pci_table);
2686
2687static struct pci_driver amd64_pci_driver = {
2688 .name = EDAC_MOD_STR,
Borislav Petkov2299ef72010-10-15 17:44:04 +02002689 .probe = amd64_probe_one_instance,
Greg Kroah-Hartman9b3c6e82012-12-21 13:23:51 -08002690 .remove = amd64_remove_one_instance,
Doug Thompson7d6034d2009-04-27 20:01:01 +02002691 .id_table = amd64_pci_table,
2692};
2693
Borislav Petkov360b7f32010-10-15 19:25:38 +02002694static void setup_pci_device(void)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002695{
2696 struct mem_ctl_info *mci;
2697 struct amd64_pvt *pvt;
2698
2699 if (amd64_ctl_pci)
2700 return;
2701
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002702 mci = mcis[0];
Doug Thompson7d6034d2009-04-27 20:01:01 +02002703 if (mci) {
2704
2705 pvt = mci->pvt_info;
2706 amd64_ctl_pci =
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002707 edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002708
2709 if (!amd64_ctl_pci) {
2710 pr_warning("%s(): Unable to create PCI control\n",
2711 __func__);
2712
2713 pr_warning("%s(): PCI error report via EDAC not set\n",
2714 __func__);
2715 }
2716 }
2717}
2718
2719static int __init amd64_edac_init(void)
2720{
Borislav Petkov360b7f32010-10-15 19:25:38 +02002721 int err = -ENODEV;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002722
Borislav Petkovdf71a052011-01-19 18:15:10 +01002723 printk(KERN_INFO "AMD64 EDAC driver v%s\n", EDAC_AMD64_VERSION);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002724
2725 opstate_init();
2726
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +02002727 if (amd_cache_northbridges() < 0)
Borislav Petkov56b34b91e2009-12-21 18:13:01 +01002728 goto err_ret;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002729
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002730 err = -ENOMEM;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002731 mcis = kzalloc(amd_nb_num() * sizeof(mcis[0]), GFP_KERNEL);
2732 ecc_stngs = kzalloc(amd_nb_num() * sizeof(ecc_stngs[0]), GFP_KERNEL);
Borislav Petkov360b7f32010-10-15 19:25:38 +02002733 if (!(mcis && ecc_stngs))
Borislav Petkova9f0fbe2011-03-29 18:10:53 +02002734 goto err_free;
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002735
Borislav Petkov50542252009-12-11 18:14:40 +01002736 msrs = msrs_alloc();
Borislav Petkov56b34b91e2009-12-21 18:13:01 +01002737 if (!msrs)
Borislav Petkov360b7f32010-10-15 19:25:38 +02002738 goto err_free;
Borislav Petkov50542252009-12-11 18:14:40 +01002739
Doug Thompson7d6034d2009-04-27 20:01:01 +02002740 err = pci_register_driver(&amd64_pci_driver);
2741 if (err)
Borislav Petkov56b34b91e2009-12-21 18:13:01 +01002742 goto err_pci;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002743
Borislav Petkov56b34b91e2009-12-21 18:13:01 +01002744 err = -ENODEV;
Borislav Petkov360b7f32010-10-15 19:25:38 +02002745 if (!atomic_read(&drv_instances))
2746 goto err_no_instances;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002747
Borislav Petkov360b7f32010-10-15 19:25:38 +02002748 setup_pci_device();
2749 return 0;
Borislav Petkov56b34b91e2009-12-21 18:13:01 +01002750
Borislav Petkov360b7f32010-10-15 19:25:38 +02002751err_no_instances:
Doug Thompson7d6034d2009-04-27 20:01:01 +02002752 pci_unregister_driver(&amd64_pci_driver);
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002753
Borislav Petkov56b34b91e2009-12-21 18:13:01 +01002754err_pci:
2755 msrs_free(msrs);
2756 msrs = NULL;
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002757
Borislav Petkov360b7f32010-10-15 19:25:38 +02002758err_free:
2759 kfree(mcis);
2760 mcis = NULL;
2761
2762 kfree(ecc_stngs);
2763 ecc_stngs = NULL;
2764
Borislav Petkov56b34b91e2009-12-21 18:13:01 +01002765err_ret:
Doug Thompson7d6034d2009-04-27 20:01:01 +02002766 return err;
2767}
2768
2769static void __exit amd64_edac_exit(void)
2770{
2771 if (amd64_ctl_pci)
2772 edac_pci_release_generic_ctl(amd64_ctl_pci);
2773
2774 pci_unregister_driver(&amd64_pci_driver);
Borislav Petkov50542252009-12-11 18:14:40 +01002775
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002776 kfree(ecc_stngs);
2777 ecc_stngs = NULL;
2778
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002779 kfree(mcis);
2780 mcis = NULL;
2781
Borislav Petkov50542252009-12-11 18:14:40 +01002782 msrs_free(msrs);
2783 msrs = NULL;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002784}
2785
2786module_init(amd64_edac_init);
2787module_exit(amd64_edac_exit);
2788
2789MODULE_LICENSE("GPL");
2790MODULE_AUTHOR("SoftwareBitMaker: Doug Thompson, "
2791 "Dave Peterson, Thayne Harbaugh");
2792MODULE_DESCRIPTION("MC support for AMD64 memory controllers - "
2793 EDAC_AMD64_VERSION);
2794
2795module_param(edac_op_state, int, 0444);
2796MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");