blob: 8d9def57232b1ab8057bbe7492cb925dcfbd5ab9 [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 Petkovb2b0c602010-10-08 18:32:29 +020063static int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
64 u32 *val, const char *func)
65{
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
117static int f15_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
118 const char *func)
119{
120 u32 reg = 0;
121 u8 dct = 0;
122
123 if (addr >= 0x140 && addr <= 0x1a0) {
124 dct = 1;
125 addr -= 0x100;
126 }
127
128 amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, &reg);
129 reg &= 0xfffffffe;
130 reg |= dct;
131 amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg);
132
133 return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func);
134}
135
Borislav Petkovb70ef012009-06-25 19:32:38 +0200136/*
Doug Thompson2bc65412009-05-04 20:11:14 +0200137 * Memory scrubber control interface. For K8, memory scrubbing is handled by
138 * hardware and can involve L2 cache, dcache as well as the main memory. With
139 * F10, this is extended to L3 cache scrubbing on CPU models sporting that
140 * functionality.
141 *
142 * This causes the "units" for the scrubbing speed to vary from 64 byte blocks
143 * (dram) over to cache lines. This is nasty, so we will use bandwidth in
144 * bytes/sec for the setting.
145 *
146 * Currently, we only do dram scrubbing. If the scrubbing is done in software on
147 * other archs, we might not have access to the caches directly.
148 */
149
150/*
151 * scan the scrub rate mapping table for a close or matching bandwidth value to
152 * issue. If requested is too big, then use last maximum value found.
153 */
Borislav Petkov395ae782010-10-01 18:38:19 +0200154static int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate)
Doug Thompson2bc65412009-05-04 20:11:14 +0200155{
156 u32 scrubval;
157 int i;
158
159 /*
160 * map the configured rate (new_bw) to a value specific to the AMD64
161 * memory controller and apply to register. Search for the first
162 * bandwidth entry that is greater or equal than the setting requested
163 * and program that. If at last entry, turn off DRAM scrubbing.
164 */
165 for (i = 0; i < ARRAY_SIZE(scrubrates); i++) {
166 /*
167 * skip scrub rates which aren't recommended
168 * (see F10 BKDG, F3x58)
169 */
Borislav Petkov395ae782010-10-01 18:38:19 +0200170 if (scrubrates[i].scrubval < min_rate)
Doug Thompson2bc65412009-05-04 20:11:14 +0200171 continue;
172
173 if (scrubrates[i].bandwidth <= new_bw)
174 break;
175
176 /*
177 * if no suitable bandwidth found, turn off DRAM scrubbing
178 * entirely by falling back to the last element in the
179 * scrubrates array.
180 */
181 }
182
183 scrubval = scrubrates[i].scrubval;
Doug Thompson2bc65412009-05-04 20:11:14 +0200184
Borislav Petkov5980bb92011-01-07 16:26:49 +0100185 pci_write_bits32(ctl, SCRCTRL, scrubval, 0x001F);
Doug Thompson2bc65412009-05-04 20:11:14 +0200186
Borislav Petkov39094442010-11-24 19:52:09 +0100187 if (scrubval)
188 return scrubrates[i].bandwidth;
189
Doug Thompson2bc65412009-05-04 20:11:14 +0200190 return 0;
191}
192
Borislav Petkov395ae782010-10-01 18:38:19 +0200193static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bw)
Doug Thompson2bc65412009-05-04 20:11:14 +0200194{
195 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkov87b3e0e2011-01-19 20:02:38 +0100196 u32 min_scrubrate = 0x5;
Doug Thompson2bc65412009-05-04 20:11:14 +0200197
Borislav Petkov87b3e0e2011-01-19 20:02:38 +0100198 if (boot_cpu_data.x86 == 0xf)
199 min_scrubrate = 0x0;
200
201 return __amd64_set_scrub_rate(pvt->F3, bw, min_scrubrate);
Doug Thompson2bc65412009-05-04 20:11:14 +0200202}
203
Borislav Petkov39094442010-11-24 19:52:09 +0100204static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
Doug Thompson2bc65412009-05-04 20:11:14 +0200205{
206 struct amd64_pvt *pvt = mci->pvt_info;
207 u32 scrubval = 0;
Borislav Petkov39094442010-11-24 19:52:09 +0100208 int i, retval = -EINVAL;
Doug Thompson2bc65412009-05-04 20:11:14 +0200209
Borislav Petkov5980bb92011-01-07 16:26:49 +0100210 amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval);
Doug Thompson2bc65412009-05-04 20:11:14 +0200211
212 scrubval = scrubval & 0x001F;
213
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200214 amd64_debug("pci-read, sdram scrub control value: %d\n", scrubval);
Doug Thompson2bc65412009-05-04 20:11:14 +0200215
Roel Kluin926311f2010-01-11 20:58:21 +0100216 for (i = 0; i < ARRAY_SIZE(scrubrates); i++) {
Doug Thompson2bc65412009-05-04 20:11:14 +0200217 if (scrubrates[i].scrubval == scrubval) {
Borislav Petkov39094442010-11-24 19:52:09 +0100218 retval = scrubrates[i].bandwidth;
Doug Thompson2bc65412009-05-04 20:11:14 +0200219 break;
220 }
221 }
Borislav Petkov39094442010-11-24 19:52:09 +0100222 return retval;
Doug Thompson2bc65412009-05-04 20:11:14 +0200223}
224
Doug Thompson67757632009-04-27 15:53:22 +0200225/*
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200226 * returns true if the SysAddr given by sys_addr matches the
227 * DRAM base/limit associated with node_id
Doug Thompson67757632009-04-27 15:53:22 +0200228 */
Borislav Petkovb487c332011-02-21 18:55:00 +0100229static bool amd64_base_limit_match(struct amd64_pvt *pvt, u64 sys_addr,
230 unsigned nid)
Doug Thompson67757632009-04-27 15:53:22 +0200231{
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200232 u64 addr;
Doug Thompson67757632009-04-27 15:53:22 +0200233
234 /* The K8 treats this as a 40-bit value. However, bits 63-40 will be
235 * all ones if the most significant implemented address bit is 1.
236 * Here we discard bits 63-40. See section 3.4.2 of AMD publication
237 * 24592: AMD x86-64 Architecture Programmer's Manual Volume 1
238 * Application Programming.
239 */
240 addr = sys_addr & 0x000000ffffffffffull;
241
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200242 return ((addr >= get_dram_base(pvt, nid)) &&
243 (addr <= get_dram_limit(pvt, nid)));
Doug Thompson67757632009-04-27 15:53:22 +0200244}
245
246/*
247 * Attempt to map a SysAddr to a node. On success, return a pointer to the
248 * mem_ctl_info structure for the node that the SysAddr maps to.
249 *
250 * On failure, return NULL.
251 */
252static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
253 u64 sys_addr)
254{
255 struct amd64_pvt *pvt;
Borislav Petkovb487c332011-02-21 18:55:00 +0100256 unsigned node_id;
Doug Thompson67757632009-04-27 15:53:22 +0200257 u32 intlv_en, bits;
258
259 /*
260 * Here we use the DRAM Base (section 3.4.4.1) and DRAM Limit (section
261 * 3.4.4.2) registers to map the SysAddr to a node ID.
262 */
263 pvt = mci->pvt_info;
264
265 /*
266 * The value of this field should be the same for all DRAM Base
267 * registers. Therefore we arbitrarily choose to read it from the
268 * register for node 0.
269 */
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200270 intlv_en = dram_intlv_en(pvt, 0);
Doug Thompson67757632009-04-27 15:53:22 +0200271
272 if (intlv_en == 0) {
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200273 for (node_id = 0; node_id < DRAM_RANGES; node_id++) {
Doug Thompson67757632009-04-27 15:53:22 +0200274 if (amd64_base_limit_match(pvt, sys_addr, node_id))
Borislav Petkov8edc5442009-09-18 12:39:19 +0200275 goto found;
Doug Thompson67757632009-04-27 15:53:22 +0200276 }
Borislav Petkov8edc5442009-09-18 12:39:19 +0200277 goto err_no_match;
Doug Thompson67757632009-04-27 15:53:22 +0200278 }
279
Borislav Petkov72f158f2009-09-18 12:27:27 +0200280 if (unlikely((intlv_en != 0x01) &&
281 (intlv_en != 0x03) &&
282 (intlv_en != 0x07))) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200283 amd64_warn("DRAM Base[IntlvEn] junk value: 0x%x, BIOS bug?\n", intlv_en);
Doug Thompson67757632009-04-27 15:53:22 +0200284 return NULL;
285 }
286
287 bits = (((u32) sys_addr) >> 12) & intlv_en;
288
289 for (node_id = 0; ; ) {
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200290 if ((dram_intlv_sel(pvt, node_id) & intlv_en) == bits)
Doug Thompson67757632009-04-27 15:53:22 +0200291 break; /* intlv_sel field matches */
292
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200293 if (++node_id >= DRAM_RANGES)
Doug Thompson67757632009-04-27 15:53:22 +0200294 goto err_no_match;
295 }
296
297 /* sanity test for sys_addr */
298 if (unlikely(!amd64_base_limit_match(pvt, sys_addr, node_id))) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200299 amd64_warn("%s: sys_addr 0x%llx falls outside base/limit address"
300 "range for node %d with node interleaving enabled.\n",
301 __func__, sys_addr, node_id);
Doug Thompson67757632009-04-27 15:53:22 +0200302 return NULL;
303 }
304
305found:
Borislav Petkovb487c332011-02-21 18:55:00 +0100306 return edac_mc_find((int)node_id);
Doug Thompson67757632009-04-27 15:53:22 +0200307
308err_no_match:
309 debugf2("sys_addr 0x%lx doesn't match any node\n",
310 (unsigned long)sys_addr);
311
312 return NULL;
313}
Doug Thompsone2ce7252009-04-27 15:57:12 +0200314
315/*
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100316 * compute the CS base address of the @csrow on the DRAM controller @dct.
317 * For details see F2x[5C:40] in the processor's BKDG
Doug Thompsone2ce7252009-04-27 15:57:12 +0200318 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100319static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct,
320 u64 *base, u64 *mask)
Doug Thompsone2ce7252009-04-27 15:57:12 +0200321{
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100322 u64 csbase, csmask, base_bits, mask_bits;
323 u8 addr_shift;
324
325 if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) {
326 csbase = pvt->csels[dct].csbases[csrow];
327 csmask = pvt->csels[dct].csmasks[csrow];
328 base_bits = GENMASK(21, 31) | GENMASK(9, 15);
329 mask_bits = GENMASK(21, 29) | GENMASK(9, 15);
330 addr_shift = 4;
331 } else {
332 csbase = pvt->csels[dct].csbases[csrow];
333 csmask = pvt->csels[dct].csmasks[csrow >> 1];
334 addr_shift = 8;
335
336 if (boot_cpu_data.x86 == 0x15)
337 base_bits = mask_bits = GENMASK(19,30) | GENMASK(5,13);
338 else
339 base_bits = mask_bits = GENMASK(19,28) | GENMASK(5,13);
340 }
341
342 *base = (csbase & base_bits) << addr_shift;
343
344 *mask = ~0ULL;
345 /* poke holes for the csmask */
346 *mask &= ~(mask_bits << addr_shift);
347 /* OR them in */
348 *mask |= (csmask & mask_bits) << addr_shift;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200349}
350
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100351#define for_each_chip_select(i, dct, pvt) \
352 for (i = 0; i < pvt->csels[dct].b_cnt; i++)
Doug Thompsone2ce7252009-04-27 15:57:12 +0200353
Borislav Petkov614ec9d2011-01-13 18:02:22 +0100354#define chip_select_base(i, dct, pvt) \
355 pvt->csels[dct].csbases[i]
356
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100357#define for_each_chip_select_mask(i, dct, pvt) \
358 for (i = 0; i < pvt->csels[dct].m_cnt; i++)
Doug Thompsone2ce7252009-04-27 15:57:12 +0200359
360/*
361 * @input_addr is an InputAddr associated with the node given by mci. Return the
362 * csrow that input_addr maps to, or -1 on failure (no csrow claims input_addr).
363 */
364static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr)
365{
366 struct amd64_pvt *pvt;
367 int csrow;
368 u64 base, mask;
369
370 pvt = mci->pvt_info;
371
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100372 for_each_chip_select(csrow, 0, pvt) {
373 if (!csrow_enabled(csrow, 0, pvt))
Doug Thompsone2ce7252009-04-27 15:57:12 +0200374 continue;
375
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100376 get_cs_base_and_mask(pvt, csrow, 0, &base, &mask);
377
378 mask = ~mask;
Doug Thompsone2ce7252009-04-27 15:57:12 +0200379
380 if ((input_addr & mask) == (base & mask)) {
381 debugf2("InputAddr 0x%lx matches csrow %d (node %d)\n",
382 (unsigned long)input_addr, csrow,
383 pvt->mc_node_id);
384
385 return csrow;
386 }
387 }
Doug Thompsone2ce7252009-04-27 15:57:12 +0200388 debugf2("no matching csrow for InputAddr 0x%lx (MC node %d)\n",
389 (unsigned long)input_addr, pvt->mc_node_id);
390
391 return -1;
392}
393
394/*
Doug Thompsone2ce7252009-04-27 15:57:12 +0200395 * Obtain info from the DRAM Hole Address Register (section 3.4.8, pub #26094)
396 * for the node represented by mci. Info is passed back in *hole_base,
397 * *hole_offset, and *hole_size. Function returns 0 if info is valid or 1 if
398 * info is invalid. Info may be invalid for either of the following reasons:
399 *
400 * - The revision of the node is not E or greater. In this case, the DRAM Hole
401 * Address Register does not exist.
402 *
403 * - The DramHoleValid bit is cleared in the DRAM Hole Address Register,
404 * indicating that its contents are not valid.
405 *
406 * The values passed back in *hole_base, *hole_offset, and *hole_size are
407 * complete 32-bit values despite the fact that the bitfields in the DHAR
408 * only represent bits 31-24 of the base and offset values.
409 */
410int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
411 u64 *hole_offset, u64 *hole_size)
412{
413 struct amd64_pvt *pvt = mci->pvt_info;
414 u64 base;
415
416 /* only revE and later have the DRAM Hole Address Register */
Borislav Petkov1433eb92009-10-21 13:44:36 +0200417 if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_E) {
Doug Thompsone2ce7252009-04-27 15:57:12 +0200418 debugf1(" revision %d for node %d does not support DHAR\n",
419 pvt->ext_model, pvt->mc_node_id);
420 return 1;
421 }
422
Borislav Petkovbc21fa52010-11-11 17:29:13 +0100423 /* valid for Fam10h and above */
Borislav Petkovc8e518d2010-12-10 19:49:19 +0100424 if (boot_cpu_data.x86 >= 0x10 && !dhar_mem_hoist_valid(pvt)) {
Doug Thompsone2ce7252009-04-27 15:57:12 +0200425 debugf1(" Dram Memory Hoisting is DISABLED on this system\n");
426 return 1;
427 }
428
Borislav Petkovc8e518d2010-12-10 19:49:19 +0100429 if (!dhar_valid(pvt)) {
Doug Thompsone2ce7252009-04-27 15:57:12 +0200430 debugf1(" Dram Memory Hoisting is DISABLED on this node %d\n",
431 pvt->mc_node_id);
432 return 1;
433 }
434
435 /* This node has Memory Hoisting */
436
437 /* +------------------+--------------------+--------------------+-----
438 * | memory | DRAM hole | relocated |
439 * | [0, (x - 1)] | [x, 0xffffffff] | addresses from |
440 * | | | DRAM hole |
441 * | | | [0x100000000, |
442 * | | | (0x100000000+ |
443 * | | | (0xffffffff-x))] |
444 * +------------------+--------------------+--------------------+-----
445 *
446 * Above is a diagram of physical memory showing the DRAM hole and the
447 * relocated addresses from the DRAM hole. As shown, the DRAM hole
448 * starts at address x (the base address) and extends through address
449 * 0xffffffff. The DRAM Hole Address Register (DHAR) relocates the
450 * addresses in the hole so that they start at 0x100000000.
451 */
452
Borislav Petkovbc21fa52010-11-11 17:29:13 +0100453 base = dhar_base(pvt);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200454
455 *hole_base = base;
456 *hole_size = (0x1ull << 32) - base;
457
458 if (boot_cpu_data.x86 > 0xf)
Borislav Petkovbc21fa52010-11-11 17:29:13 +0100459 *hole_offset = f10_dhar_offset(pvt);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200460 else
Borislav Petkovbc21fa52010-11-11 17:29:13 +0100461 *hole_offset = k8_dhar_offset(pvt);
Doug Thompsone2ce7252009-04-27 15:57:12 +0200462
463 debugf1(" DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx\n",
464 pvt->mc_node_id, (unsigned long)*hole_base,
465 (unsigned long)*hole_offset, (unsigned long)*hole_size);
466
467 return 0;
468}
469EXPORT_SYMBOL_GPL(amd64_get_dram_hole_info);
470
Doug Thompson93c2df52009-05-04 20:46:50 +0200471/*
472 * Return the DramAddr that the SysAddr given by @sys_addr maps to. It is
473 * assumed that sys_addr maps to the node given by mci.
474 *
475 * The first part of section 3.4.4 (p. 70) shows how the DRAM Base (section
476 * 3.4.4.1) and DRAM Limit (section 3.4.4.2) registers are used to translate a
477 * SysAddr to a DramAddr. If the DRAM Hole Address Register (DHAR) is enabled,
478 * then it is also involved in translating a SysAddr to a DramAddr. Sections
479 * 3.4.8 and 3.5.8.2 describe the DHAR and how it is used for memory hoisting.
480 * These parts of the documentation are unclear. I interpret them as follows:
481 *
482 * When node n receives a SysAddr, it processes the SysAddr as follows:
483 *
484 * 1. It extracts the DRAMBase and DRAMLimit values from the DRAM Base and DRAM
485 * Limit registers for node n. If the SysAddr is not within the range
486 * specified by the base and limit values, then node n ignores the Sysaddr
487 * (since it does not map to node n). Otherwise continue to step 2 below.
488 *
489 * 2. If the DramHoleValid bit of the DHAR for node n is clear, the DHAR is
490 * disabled so skip to step 3 below. Otherwise see if the SysAddr is within
491 * the range of relocated addresses (starting at 0x100000000) from the DRAM
492 * hole. If not, skip to step 3 below. Else get the value of the
493 * DramHoleOffset field from the DHAR. To obtain the DramAddr, subtract the
494 * offset defined by this value from the SysAddr.
495 *
496 * 3. Obtain the base address for node n from the DRAMBase field of the DRAM
497 * Base register for node n. To obtain the DramAddr, subtract the base
498 * address from the SysAddr, as shown near the start of section 3.4.4 (p.70).
499 */
500static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr)
501{
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200502 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompson93c2df52009-05-04 20:46:50 +0200503 u64 dram_base, hole_base, hole_offset, hole_size, dram_addr;
504 int ret = 0;
505
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200506 dram_base = get_dram_base(pvt, pvt->mc_node_id);
Doug Thompson93c2df52009-05-04 20:46:50 +0200507
508 ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
509 &hole_size);
510 if (!ret) {
511 if ((sys_addr >= (1ull << 32)) &&
512 (sys_addr < ((1ull << 32) + hole_size))) {
513 /* use DHAR to translate SysAddr to DramAddr */
514 dram_addr = sys_addr - hole_offset;
515
516 debugf2("using DHAR to translate SysAddr 0x%lx to "
517 "DramAddr 0x%lx\n",
518 (unsigned long)sys_addr,
519 (unsigned long)dram_addr);
520
521 return dram_addr;
522 }
523 }
524
525 /*
526 * Translate the SysAddr to a DramAddr as shown near the start of
527 * section 3.4.4 (p. 70). Although sys_addr is a 64-bit value, the k8
528 * only deals with 40-bit values. Therefore we discard bits 63-40 of
529 * sys_addr below. If bit 39 of sys_addr is 1 then the bits we
530 * discard are all 1s. Otherwise the bits we discard are all 0s. See
531 * section 3.4.2 of AMD publication 24592: AMD x86-64 Architecture
532 * Programmer's Manual Volume 1 Application Programming.
533 */
Borislav Petkovf678b8c2010-12-13 19:21:07 +0100534 dram_addr = (sys_addr & GENMASK(0, 39)) - dram_base;
Doug Thompson93c2df52009-05-04 20:46:50 +0200535
536 debugf2("using DRAM Base register to translate SysAddr 0x%lx to "
537 "DramAddr 0x%lx\n", (unsigned long)sys_addr,
538 (unsigned long)dram_addr);
539 return dram_addr;
540}
541
542/*
543 * @intlv_en is the value of the IntlvEn field from a DRAM Base register
544 * (section 3.4.4.1). Return the number of bits from a SysAddr that are used
545 * for node interleaving.
546 */
547static int num_node_interleave_bits(unsigned intlv_en)
548{
549 static const int intlv_shift_table[] = { 0, 1, 0, 2, 0, 0, 0, 3 };
550 int n;
551
552 BUG_ON(intlv_en > 7);
553 n = intlv_shift_table[intlv_en];
554 return n;
555}
556
557/* Translate the DramAddr given by @dram_addr to an InputAddr. */
558static u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr)
559{
560 struct amd64_pvt *pvt;
561 int intlv_shift;
562 u64 input_addr;
563
564 pvt = mci->pvt_info;
565
566 /*
567 * See the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E)
568 * concerning translating a DramAddr to an InputAddr.
569 */
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200570 intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0));
Borislav Petkovf678b8c2010-12-13 19:21:07 +0100571 input_addr = ((dram_addr >> intlv_shift) & GENMASK(12, 35)) +
572 (dram_addr & 0xfff);
Doug Thompson93c2df52009-05-04 20:46:50 +0200573
574 debugf2(" Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n",
575 intlv_shift, (unsigned long)dram_addr,
576 (unsigned long)input_addr);
577
578 return input_addr;
579}
580
581/*
582 * Translate the SysAddr represented by @sys_addr to an InputAddr. It is
583 * assumed that @sys_addr maps to the node given by mci.
584 */
585static u64 sys_addr_to_input_addr(struct mem_ctl_info *mci, u64 sys_addr)
586{
587 u64 input_addr;
588
589 input_addr =
590 dram_addr_to_input_addr(mci, sys_addr_to_dram_addr(mci, sys_addr));
591
592 debugf2("SysAdddr 0x%lx translates to InputAddr 0x%lx\n",
593 (unsigned long)sys_addr, (unsigned long)input_addr);
594
595 return input_addr;
596}
597
598
599/*
600 * @input_addr is an InputAddr associated with the node represented by mci.
601 * Translate @input_addr to a DramAddr and return the result.
602 */
603static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr)
604{
605 struct amd64_pvt *pvt;
Borislav Petkovb487c332011-02-21 18:55:00 +0100606 unsigned node_id, intlv_shift;
Doug Thompson93c2df52009-05-04 20:46:50 +0200607 u64 bits, dram_addr;
608 u32 intlv_sel;
609
610 /*
611 * Near the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E)
612 * shows how to translate a DramAddr to an InputAddr. Here we reverse
613 * this procedure. When translating from a DramAddr to an InputAddr, the
614 * bits used for node interleaving are discarded. Here we recover these
615 * bits from the IntlvSel field of the DRAM Limit register (section
616 * 3.4.4.2) for the node that input_addr is associated with.
617 */
618 pvt = mci->pvt_info;
619 node_id = pvt->mc_node_id;
Borislav Petkovb487c332011-02-21 18:55:00 +0100620
621 BUG_ON(node_id > 7);
Doug Thompson93c2df52009-05-04 20:46:50 +0200622
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200623 intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0));
Doug Thompson93c2df52009-05-04 20:46:50 +0200624
625 if (intlv_shift == 0) {
626 debugf1(" InputAddr 0x%lx translates to DramAddr of "
627 "same value\n", (unsigned long)input_addr);
628
629 return input_addr;
630 }
631
Borislav Petkovf678b8c2010-12-13 19:21:07 +0100632 bits = ((input_addr & GENMASK(12, 35)) << intlv_shift) +
633 (input_addr & 0xfff);
Doug Thompson93c2df52009-05-04 20:46:50 +0200634
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200635 intlv_sel = dram_intlv_sel(pvt, node_id) & ((1 << intlv_shift) - 1);
Doug Thompson93c2df52009-05-04 20:46:50 +0200636 dram_addr = bits + (intlv_sel << 12);
637
638 debugf1("InputAddr 0x%lx translates to DramAddr 0x%lx "
639 "(%d node interleave bits)\n", (unsigned long)input_addr,
640 (unsigned long)dram_addr, intlv_shift);
641
642 return dram_addr;
643}
644
645/*
646 * @dram_addr is a DramAddr that maps to the node represented by mci. Convert
647 * @dram_addr to a SysAddr.
648 */
649static u64 dram_addr_to_sys_addr(struct mem_ctl_info *mci, u64 dram_addr)
650{
651 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200652 u64 hole_base, hole_offset, hole_size, base, sys_addr;
Doug Thompson93c2df52009-05-04 20:46:50 +0200653 int ret = 0;
654
655 ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
656 &hole_size);
657 if (!ret) {
658 if ((dram_addr >= hole_base) &&
659 (dram_addr < (hole_base + hole_size))) {
660 sys_addr = dram_addr + hole_offset;
661
662 debugf1("using DHAR to translate DramAddr 0x%lx to "
663 "SysAddr 0x%lx\n", (unsigned long)dram_addr,
664 (unsigned long)sys_addr);
665
666 return sys_addr;
667 }
668 }
669
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200670 base = get_dram_base(pvt, pvt->mc_node_id);
Doug Thompson93c2df52009-05-04 20:46:50 +0200671 sys_addr = dram_addr + base;
672
673 /*
674 * The sys_addr we have computed up to this point is a 40-bit value
675 * because the k8 deals with 40-bit values. However, the value we are
676 * supposed to return is a full 64-bit physical address. The AMD
677 * x86-64 architecture specifies that the most significant implemented
678 * address bit through bit 63 of a physical address must be either all
679 * 0s or all 1s. Therefore we sign-extend the 40-bit sys_addr to a
680 * 64-bit value below. See section 3.4.2 of AMD publication 24592:
681 * AMD x86-64 Architecture Programmer's Manual Volume 1 Application
682 * Programming.
683 */
684 sys_addr |= ~((sys_addr & (1ull << 39)) - 1);
685
686 debugf1(" Node %d, DramAddr 0x%lx to SysAddr 0x%lx\n",
687 pvt->mc_node_id, (unsigned long)dram_addr,
688 (unsigned long)sys_addr);
689
690 return sys_addr;
691}
692
693/*
694 * @input_addr is an InputAddr associated with the node given by mci. Translate
695 * @input_addr to a SysAddr.
696 */
697static inline u64 input_addr_to_sys_addr(struct mem_ctl_info *mci,
698 u64 input_addr)
699{
700 return dram_addr_to_sys_addr(mci,
701 input_addr_to_dram_addr(mci, input_addr));
702}
703
704/*
705 * Find the minimum and maximum InputAddr values that map to the given @csrow.
706 * Pass back these values in *input_addr_min and *input_addr_max.
707 */
708static void find_csrow_limits(struct mem_ctl_info *mci, int csrow,
709 u64 *input_addr_min, u64 *input_addr_max)
710{
711 struct amd64_pvt *pvt;
712 u64 base, mask;
713
714 pvt = mci->pvt_info;
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100715 BUG_ON((csrow < 0) || (csrow >= pvt->csels[0].b_cnt));
Doug Thompson93c2df52009-05-04 20:46:50 +0200716
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100717 get_cs_base_and_mask(pvt, csrow, 0, &base, &mask);
Doug Thompson93c2df52009-05-04 20:46:50 +0200718
719 *input_addr_min = base & ~mask;
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100720 *input_addr_max = base | mask;
Doug Thompson93c2df52009-05-04 20:46:50 +0200721}
722
Doug Thompson93c2df52009-05-04 20:46:50 +0200723/* Map the Error address to a PAGE and PAGE OFFSET. */
724static inline void error_address_to_page_and_offset(u64 error_address,
725 u32 *page, u32 *offset)
726{
727 *page = (u32) (error_address >> PAGE_SHIFT);
728 *offset = ((u32) error_address) & ~PAGE_MASK;
729}
730
731/*
732 * @sys_addr is an error address (a SysAddr) extracted from the MCA NB Address
733 * Low (section 3.6.4.5) and MCA NB Address High (section 3.6.4.6) registers
734 * of a node that detected an ECC memory error. mci represents the node that
735 * the error address maps to (possibly different from the node that detected
736 * the error). Return the number of the csrow that sys_addr maps to, or -1 on
737 * error.
738 */
739static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr)
740{
741 int csrow;
742
743 csrow = input_addr_to_csrow(mci, sys_addr_to_input_addr(mci, sys_addr));
744
745 if (csrow == -1)
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200746 amd64_mc_err(mci, "Failed to translate InputAddr to csrow for "
747 "address 0x%lx\n", (unsigned long)sys_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200748 return csrow;
749}
Doug Thompsone2ce7252009-04-27 15:57:12 +0200750
Borislav Petkovbfc04ae2009-11-12 19:05:07 +0100751static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);
Doug Thompson2da11652009-04-27 16:09:09 +0200752
Doug Thompson2da11652009-04-27 16:09:09 +0200753/*
754 * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs
755 * are ECC capable.
756 */
757static enum edac_type amd64_determine_edac_cap(struct amd64_pvt *pvt)
758{
Borislav Petkovcb328502010-12-22 14:28:24 +0100759 u8 bit;
Borislav Petkov584fcff2009-06-10 18:29:54 +0200760 enum dev_type edac_cap = EDAC_FLAG_NONE;
Doug Thompson2da11652009-04-27 16:09:09 +0200761
Borislav Petkov1433eb92009-10-21 13:44:36 +0200762 bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= K8_REV_F)
Doug Thompson2da11652009-04-27 16:09:09 +0200763 ? 19
764 : 17;
765
Borislav Petkov584fcff2009-06-10 18:29:54 +0200766 if (pvt->dclr0 & BIT(bit))
Doug Thompson2da11652009-04-27 16:09:09 +0200767 edac_cap = EDAC_FLAG_SECDED;
768
769 return edac_cap;
770}
771
772
Borislav Petkov8566c4d2009-10-16 13:48:28 +0200773static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt);
Doug Thompson2da11652009-04-27 16:09:09 +0200774
Borislav Petkov68798e12009-11-03 16:18:33 +0100775static void amd64_dump_dramcfg_low(u32 dclr, int chan)
776{
777 debugf1("F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr);
778
779 debugf1(" DIMM type: %sbuffered; all DIMMs support ECC: %s\n",
780 (dclr & BIT(16)) ? "un" : "",
781 (dclr & BIT(19)) ? "yes" : "no");
782
783 debugf1(" PAR/ERR parity: %s\n",
784 (dclr & BIT(8)) ? "enabled" : "disabled");
785
Borislav Petkovcb328502010-12-22 14:28:24 +0100786 if (boot_cpu_data.x86 == 0x10)
787 debugf1(" DCT 128bit mode width: %s\n",
788 (dclr & BIT(11)) ? "128b" : "64b");
Borislav Petkov68798e12009-11-03 16:18:33 +0100789
790 debugf1(" x4 logical DIMMs present: L0: %s L1: %s L2: %s L3: %s\n",
791 (dclr & BIT(12)) ? "yes" : "no",
792 (dclr & BIT(13)) ? "yes" : "no",
793 (dclr & BIT(14)) ? "yes" : "no",
794 (dclr & BIT(15)) ? "yes" : "no");
795}
796
Doug Thompson2da11652009-04-27 16:09:09 +0200797/* Display and decode various NB registers for debug purposes. */
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200798static void dump_misc_regs(struct amd64_pvt *pvt)
Doug Thompson2da11652009-04-27 16:09:09 +0200799{
Borislav Petkov68798e12009-11-03 16:18:33 +0100800 debugf1("F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap);
Doug Thompson2da11652009-04-27 16:09:09 +0200801
Borislav Petkov68798e12009-11-03 16:18:33 +0100802 debugf1(" NB two channel DRAM capable: %s\n",
Borislav Petkov5980bb92011-01-07 16:26:49 +0100803 (pvt->nbcap & NBCAP_DCT_DUAL) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100804
805 debugf1(" ECC capable: %s, ChipKill ECC capable: %s\n",
Borislav Petkov5980bb92011-01-07 16:26:49 +0100806 (pvt->nbcap & NBCAP_SECDED) ? "yes" : "no",
807 (pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100808
809 amd64_dump_dramcfg_low(pvt->dclr0, 0);
Doug Thompson2da11652009-04-27 16:09:09 +0200810
Borislav Petkov8de1d912009-10-16 13:39:30 +0200811 debugf1("F3xB0 (Online Spare): 0x%08x\n", pvt->online_spare);
Doug Thompson2da11652009-04-27 16:09:09 +0200812
Borislav Petkov8de1d912009-10-16 13:39:30 +0200813 debugf1("F1xF0 (DRAM Hole Address): 0x%08x, base: 0x%08x, "
814 "offset: 0x%08x\n",
Borislav Petkovbc21fa52010-11-11 17:29:13 +0100815 pvt->dhar, dhar_base(pvt),
816 (boot_cpu_data.x86 == 0xf) ? k8_dhar_offset(pvt)
817 : f10_dhar_offset(pvt));
Doug Thompson2da11652009-04-27 16:09:09 +0200818
Borislav Petkovc8e518d2010-12-10 19:49:19 +0100819 debugf1(" DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no");
Doug Thompson2da11652009-04-27 16:09:09 +0200820
Borislav Petkov4d796362011-02-03 15:59:57 +0100821 amd64_debug_display_dimm_sizes(0, pvt);
822
Borislav Petkov8de1d912009-10-16 13:39:30 +0200823 /* everything below this point is Fam10h and above */
Borislav Petkov4d796362011-02-03 15:59:57 +0100824 if (boot_cpu_data.x86 == 0xf)
Doug Thompson2da11652009-04-27 16:09:09 +0200825 return;
Borislav Petkov4d796362011-02-03 15:59:57 +0100826
827 amd64_debug_display_dimm_sizes(1, pvt);
Doug Thompson2da11652009-04-27 16:09:09 +0200828
Borislav Petkova3b7db02011-01-19 20:35:12 +0100829 amd64_info("using %s syndromes.\n", ((pvt->ecc_sym_sz == 8) ? "x8" : "x4"));
Borislav Petkovad6a32e2010-03-09 12:46:00 +0100830
Borislav Petkov8de1d912009-10-16 13:39:30 +0200831 /* Only if NOT ganged does dclr1 have valid info */
Borislav Petkov68798e12009-11-03 16:18:33 +0100832 if (!dct_ganging_enabled(pvt))
833 amd64_dump_dramcfg_low(pvt->dclr1, 1);
Doug Thompson2da11652009-04-27 16:09:09 +0200834}
835
Doug Thompson94be4bf2009-04-27 16:12:00 +0200836/*
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100837 * see BKDG, F2x[1,0][5C:40], F2[1,0][6C:60]
Doug Thompson94be4bf2009-04-27 16:12:00 +0200838 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100839static void prep_chip_selects(struct amd64_pvt *pvt)
Doug Thompson94be4bf2009-04-27 16:12:00 +0200840{
Borislav Petkov1433eb92009-10-21 13:44:36 +0200841 if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) {
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100842 pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
843 pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 8;
Borislav Petkov9d858bb2009-09-21 14:35:51 +0200844 } else {
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100845 pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
846 pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4;
Doug Thompson94be4bf2009-04-27 16:12:00 +0200847 }
848}
849
850/*
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100851 * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers
Doug Thompson94be4bf2009-04-27 16:12:00 +0200852 */
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200853static void read_dct_base_mask(struct amd64_pvt *pvt)
Doug Thompson94be4bf2009-04-27 16:12:00 +0200854{
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100855 int cs;
Doug Thompson94be4bf2009-04-27 16:12:00 +0200856
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100857 prep_chip_selects(pvt);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200858
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100859 for_each_chip_select(cs, 0, pvt) {
860 u32 reg0 = DCSB0 + (cs * 4);
861 u32 reg1 = DCSB1 + (cs * 4);
862 u32 *base0 = &pvt->csels[0].csbases[cs];
863 u32 *base1 = &pvt->csels[1].csbases[cs];
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200864
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100865 if (!amd64_read_dct_pci_cfg(pvt, reg0, base0))
Doug Thompson94be4bf2009-04-27 16:12:00 +0200866 debugf0(" DCSB0[%d]=0x%08x reg: F2x%x\n",
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100867 cs, *base0, reg0);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200868
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100869 if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt))
870 continue;
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200871
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100872 if (!amd64_read_dct_pci_cfg(pvt, reg1, base1))
873 debugf0(" DCSB1[%d]=0x%08x reg: F2x%x\n",
874 cs, *base1, reg1);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200875 }
876
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100877 for_each_chip_select_mask(cs, 0, pvt) {
878 u32 reg0 = DCSM0 + (cs * 4);
879 u32 reg1 = DCSM1 + (cs * 4);
880 u32 *mask0 = &pvt->csels[0].csmasks[cs];
881 u32 *mask1 = &pvt->csels[1].csmasks[cs];
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200882
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100883 if (!amd64_read_dct_pci_cfg(pvt, reg0, mask0))
Doug Thompson94be4bf2009-04-27 16:12:00 +0200884 debugf0(" DCSM0[%d]=0x%08x reg: F2x%x\n",
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100885 cs, *mask0, reg0);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200886
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100887 if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt))
888 continue;
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200889
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100890 if (!amd64_read_dct_pci_cfg(pvt, reg1, mask1))
891 debugf0(" DCSM1[%d]=0x%08x reg: F2x%x\n",
892 cs, *mask1, reg1);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200893 }
894}
895
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200896static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt, int cs)
Doug Thompson94be4bf2009-04-27 16:12:00 +0200897{
898 enum mem_type type;
899
Borislav Petkovcb328502010-12-22 14:28:24 +0100900 /* F15h supports only DDR3 */
901 if (boot_cpu_data.x86 >= 0x15)
902 type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3;
903 else if (boot_cpu_data.x86 == 0x10 || pvt->ext_model >= K8_REV_F) {
Borislav Petkov6b4c0bd2009-11-12 15:37:57 +0100904 if (pvt->dchr0 & DDR3_MODE)
905 type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3;
906 else
907 type = (pvt->dclr0 & BIT(16)) ? MEM_DDR2 : MEM_RDDR2;
Doug Thompson94be4bf2009-04-27 16:12:00 +0200908 } else {
Doug Thompson94be4bf2009-04-27 16:12:00 +0200909 type = (pvt->dclr0 & BIT(18)) ? MEM_DDR : MEM_RDDR;
910 }
911
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200912 amd64_info("CS%d: %s\n", cs, edac_mem_types[type]);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200913
914 return type;
915}
916
Borislav Petkovcb328502010-12-22 14:28:24 +0100917/* Get the number of DCT channels the memory controller is using. */
Doug Thompsonddff8762009-04-27 16:14:52 +0200918static int k8_early_channel_count(struct amd64_pvt *pvt)
919{
Borislav Petkovcb328502010-12-22 14:28:24 +0100920 int flag;
Doug Thompsonddff8762009-04-27 16:14:52 +0200921
Borislav Petkov9f56da02010-10-01 19:44:53 +0200922 if (pvt->ext_model >= K8_REV_F)
Doug Thompsonddff8762009-04-27 16:14:52 +0200923 /* RevF (NPT) and later */
Borislav Petkov41d8bfa2011-01-18 19:16:08 +0100924 flag = pvt->dclr0 & WIDTH_128;
Borislav Petkov9f56da02010-10-01 19:44:53 +0200925 else
Doug Thompsonddff8762009-04-27 16:14:52 +0200926 /* RevE and earlier */
927 flag = pvt->dclr0 & REVE_WIDTH_128;
Doug Thompsonddff8762009-04-27 16:14:52 +0200928
929 /* not used */
930 pvt->dclr1 = 0;
931
932 return (flag) ? 2 : 1;
933}
934
Borislav Petkov70046622011-01-10 14:37:27 +0100935/* On F10h and later ErrAddr is MC4_ADDR[47:1] */
936static u64 get_error_address(struct mce *m)
Doug Thompsonddff8762009-04-27 16:14:52 +0200937{
Borislav Petkov70046622011-01-10 14:37:27 +0100938 u8 start_bit = 1;
939 u8 end_bit = 47;
940
941 if (boot_cpu_data.x86 == 0xf) {
942 start_bit = 3;
943 end_bit = 39;
944 }
945
946 return m->addr & GENMASK(start_bit, end_bit);
Doug Thompsonddff8762009-04-27 16:14:52 +0200947}
948
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200949static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
Doug Thompsonddff8762009-04-27 16:14:52 +0200950{
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200951 u32 off = range << 3;
Doug Thompsonddff8762009-04-27 16:14:52 +0200952
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200953 amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo);
954 amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
Doug Thompsonddff8762009-04-27 16:14:52 +0200955
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200956 if (boot_cpu_data.x86 == 0xf)
957 return;
Doug Thompsonddff8762009-04-27 16:14:52 +0200958
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200959 if (!dram_rw(pvt, range))
960 return;
Doug Thompsonddff8762009-04-27 16:14:52 +0200961
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200962 amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi);
963 amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
Doug Thompsonddff8762009-04-27 16:14:52 +0200964}
965
Borislav Petkovf192c7b2011-01-10 14:24:32 +0100966static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
967 u16 syndrome)
Doug Thompsonddff8762009-04-27 16:14:52 +0200968{
969 struct mem_ctl_info *src_mci;
Borislav Petkovf192c7b2011-01-10 14:24:32 +0100970 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompsonddff8762009-04-27 16:14:52 +0200971 int channel, csrow;
972 u32 page, offset;
Doug Thompsonddff8762009-04-27 16:14:52 +0200973
974 /* CHIPKILL enabled */
Borislav Petkovf192c7b2011-01-10 14:24:32 +0100975 if (pvt->nbcfg & NBCFG_CHIPKILL) {
Borislav Petkovbfc04ae2009-11-12 19:05:07 +0100976 channel = get_channel_from_ecc_syndrome(mci, syndrome);
Doug Thompsonddff8762009-04-27 16:14:52 +0200977 if (channel < 0) {
978 /*
979 * Syndrome didn't map, so we don't know which of the
980 * 2 DIMMs is in error. So we need to ID 'both' of them
981 * as suspect.
982 */
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200983 amd64_mc_warn(mci, "unknown syndrome 0x%04x - possible "
984 "error reporting race\n", syndrome);
Doug Thompsonddff8762009-04-27 16:14:52 +0200985 edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
986 return;
987 }
988 } else {
989 /*
990 * non-chipkill ecc mode
991 *
992 * The k8 documentation is unclear about how to determine the
993 * channel number when using non-chipkill memory. This method
994 * was obtained from email communication with someone at AMD.
995 * (Wish the email was placed in this comment - norsk)
996 */
Borislav Petkov44e9e2e2009-10-26 15:00:19 +0100997 channel = ((sys_addr & BIT(3)) != 0);
Doug Thompsonddff8762009-04-27 16:14:52 +0200998 }
999
1000 /*
1001 * Find out which node the error address belongs to. This may be
1002 * different from the node that detected the error.
1003 */
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001004 src_mci = find_mc_by_sys_addr(mci, sys_addr);
Keith Mannthey2cff18c2009-09-18 14:35:23 +02001005 if (!src_mci) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001006 amd64_mc_err(mci, "failed to map error addr 0x%lx to a node\n",
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001007 (unsigned long)sys_addr);
Doug Thompsonddff8762009-04-27 16:14:52 +02001008 edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
1009 return;
1010 }
1011
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001012 /* Now map the sys_addr to a CSROW */
1013 csrow = sys_addr_to_csrow(src_mci, sys_addr);
Doug Thompsonddff8762009-04-27 16:14:52 +02001014 if (csrow < 0) {
1015 edac_mc_handle_ce_no_info(src_mci, EDAC_MOD_STR);
1016 } else {
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001017 error_address_to_page_and_offset(sys_addr, &page, &offset);
Doug Thompsonddff8762009-04-27 16:14:52 +02001018
1019 edac_mc_handle_ce(src_mci, page, offset, syndrome, csrow,
1020 channel, EDAC_MOD_STR);
1021 }
1022}
1023
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001024static int ddr2_cs_size(unsigned i, bool dct_width)
Doug Thompsonddff8762009-04-27 16:14:52 +02001025{
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001026 unsigned shift = 0;
Doug Thompsonddff8762009-04-27 16:14:52 +02001027
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001028 if (i <= 2)
1029 shift = i;
1030 else if (!(i & 0x1))
1031 shift = i >> 1;
Borislav Petkov1433eb92009-10-21 13:44:36 +02001032 else
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001033 shift = (i + 1) >> 1;
Doug Thompsonddff8762009-04-27 16:14:52 +02001034
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001035 return 128 << (shift + !!dct_width);
1036}
1037
1038static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
1039 unsigned cs_mode)
1040{
1041 u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
1042
1043 if (pvt->ext_model >= K8_REV_F) {
1044 WARN_ON(cs_mode > 11);
1045 return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
1046 }
1047 else if (pvt->ext_model >= K8_REV_D) {
1048 WARN_ON(cs_mode > 10);
1049
1050 if (cs_mode == 3 || cs_mode == 8)
1051 return 32 << (cs_mode - 1);
1052 else
1053 return 32 << cs_mode;
1054 }
1055 else {
1056 WARN_ON(cs_mode > 6);
1057 return 32 << cs_mode;
1058 }
Doug Thompsonddff8762009-04-27 16:14:52 +02001059}
1060
Doug Thompson1afd3c92009-04-27 16:16:50 +02001061/*
1062 * Get the number of DCT channels in use.
1063 *
1064 * Return:
1065 * number of Memory Channels in operation
1066 * Pass back:
1067 * contents of the DCL0_LOW register
1068 */
Borislav Petkov7d20d142011-01-07 17:58:04 +01001069static int f1x_early_channel_count(struct amd64_pvt *pvt)
Doug Thompson1afd3c92009-04-27 16:16:50 +02001070{
Borislav Petkov6ba5dcd2009-10-13 19:26:55 +02001071 int i, j, channels = 0;
Doug Thompsonddff8762009-04-27 16:14:52 +02001072
Borislav Petkov7d20d142011-01-07 17:58:04 +01001073 /* On F10h, if we are in 128 bit mode, then we are using 2 channels */
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001074 if (boot_cpu_data.x86 == 0x10 && (pvt->dclr0 & WIDTH_128))
Borislav Petkov7d20d142011-01-07 17:58:04 +01001075 return 2;
Doug Thompson1afd3c92009-04-27 16:16:50 +02001076
1077 /*
Borislav Petkovd16149e2009-10-16 19:55:49 +02001078 * Need to check if in unganged mode: In such, there are 2 channels,
1079 * but they are not in 128 bit mode and thus the above 'dclr0' status
1080 * bit will be OFF.
Doug Thompson1afd3c92009-04-27 16:16:50 +02001081 *
1082 * Need to check DCT0[0] and DCT1[0] to see if only one of them has
1083 * their CSEnable bit on. If so, then SINGLE DIMM case.
1084 */
Borislav Petkovd16149e2009-10-16 19:55:49 +02001085 debugf0("Data width is not 128 bits - need more decoding\n");
Doug Thompson1afd3c92009-04-27 16:16:50 +02001086
1087 /*
1088 * Check DRAM Bank Address Mapping values for each DIMM to see if there
1089 * is more than just one DIMM present in unganged mode. Need to check
1090 * both controllers since DIMMs can be placed in either one.
1091 */
Borislav Petkov525a1b22010-12-21 15:53:27 +01001092 for (i = 0; i < 2; i++) {
1093 u32 dbam = (i ? pvt->dbam1 : pvt->dbam0);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001094
Wan Wei57a30852009-08-07 17:04:49 +02001095 for (j = 0; j < 4; j++) {
1096 if (DBAM_DIMM(j, dbam) > 0) {
1097 channels++;
1098 break;
1099 }
1100 }
Doug Thompson1afd3c92009-04-27 16:16:50 +02001101 }
1102
Borislav Petkovd16149e2009-10-16 19:55:49 +02001103 if (channels > 2)
1104 channels = 2;
1105
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001106 amd64_info("MCT channel count: %d\n", channels);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001107
1108 return channels;
Doug Thompson1afd3c92009-04-27 16:16:50 +02001109}
1110
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001111static int ddr3_cs_size(unsigned i, bool dct_width)
Doug Thompson1afd3c92009-04-27 16:16:50 +02001112{
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001113 unsigned shift = 0;
1114 int cs_size = 0;
1115
1116 if (i == 0 || i == 3 || i == 4)
1117 cs_size = -1;
1118 else if (i <= 2)
1119 shift = i;
1120 else if (i == 12)
1121 shift = 7;
1122 else if (!(i & 0x1))
1123 shift = i >> 1;
1124 else
1125 shift = (i + 1) >> 1;
1126
1127 if (cs_size != -1)
1128 cs_size = (128 * (1 << !!dct_width)) << shift;
1129
1130 return cs_size;
1131}
1132
1133static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
1134 unsigned cs_mode)
1135{
1136 u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
1137
1138 WARN_ON(cs_mode > 11);
Borislav Petkov1433eb92009-10-21 13:44:36 +02001139
1140 if (pvt->dchr0 & DDR3_MODE || pvt->dchr1 & DDR3_MODE)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001141 return ddr3_cs_size(cs_mode, dclr & WIDTH_128);
Borislav Petkov1433eb92009-10-21 13:44:36 +02001142 else
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001143 return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
1144}
Borislav Petkov1433eb92009-10-21 13:44:36 +02001145
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001146/*
1147 * F15h supports only 64bit DCT interfaces
1148 */
1149static int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
1150 unsigned cs_mode)
1151{
1152 WARN_ON(cs_mode > 12);
1153
1154 return ddr3_cs_size(cs_mode, false);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001155}
1156
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001157static void read_dram_ctl_register(struct amd64_pvt *pvt)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001158{
Doug Thompson6163b5d2009-04-27 16:20:17 +02001159
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001160 if (boot_cpu_data.x86 == 0xf)
1161 return;
1162
Borislav Petkov78da1212010-12-22 19:31:45 +01001163 if (!amd64_read_dct_pci_cfg(pvt, DCT_SEL_LO, &pvt->dct_sel_lo)) {
1164 debugf0("F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x\n",
1165 pvt->dct_sel_lo, dct_sel_baseaddr(pvt));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001166
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001167 debugf0(" DCTs operate in %s mode.\n",
1168 (dct_ganging_enabled(pvt) ? "ganged" : "unganged"));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001169
Borislav Petkov72381bd2009-10-09 19:14:43 +02001170 if (!dct_ganging_enabled(pvt))
1171 debugf0(" Address range split per DCT: %s\n",
1172 (dct_high_range_enabled(pvt) ? "yes" : "no"));
1173
Borislav Petkov78da1212010-12-22 19:31:45 +01001174 debugf0(" data interleave for ECC: %s, "
Borislav Petkov72381bd2009-10-09 19:14:43 +02001175 "DRAM cleared since last warm reset: %s\n",
1176 (dct_data_intlv_enabled(pvt) ? "enabled" : "disabled"),
1177 (dct_memory_cleared(pvt) ? "yes" : "no"));
1178
Borislav Petkov78da1212010-12-22 19:31:45 +01001179 debugf0(" channel interleave: %s, "
1180 "interleave bits selector: 0x%x\n",
Borislav Petkov72381bd2009-10-09 19:14:43 +02001181 (dct_interleave_enabled(pvt) ? "enabled" : "disabled"),
Doug Thompson6163b5d2009-04-27 16:20:17 +02001182 dct_sel_interleave_addr(pvt));
1183 }
1184
Borislav Petkov78da1212010-12-22 19:31:45 +01001185 amd64_read_dct_pci_cfg(pvt, DCT_SEL_HI, &pvt->dct_sel_hi);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001186}
1187
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001188/*
Borislav Petkov229a7a12010-12-09 18:57:54 +01001189 * Determine channel (DCT) based on the interleaving mode: F10h BKDG, 2.8.9 Memory
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001190 * Interleaving Modes.
1191 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001192static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
Borislav Petkov229a7a12010-12-09 18:57:54 +01001193 bool hi_range_sel, u8 intlv_en)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001194{
Borislav Petkov78da1212010-12-22 19:31:45 +01001195 u32 dct_sel_high = (pvt->dct_sel_lo >> 1) & 1;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001196
1197 if (dct_ganging_enabled(pvt))
Borislav Petkov229a7a12010-12-09 18:57:54 +01001198 return 0;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001199
Borislav Petkov229a7a12010-12-09 18:57:54 +01001200 if (hi_range_sel)
1201 return dct_sel_high;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001202
Borislav Petkov229a7a12010-12-09 18:57:54 +01001203 /*
1204 * see F2x110[DctSelIntLvAddr] - channel interleave mode
1205 */
1206 if (dct_interleave_enabled(pvt)) {
1207 u8 intlv_addr = dct_sel_interleave_addr(pvt);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001208
Borislav Petkov229a7a12010-12-09 18:57:54 +01001209 /* return DCT select function: 0=DCT0, 1=DCT1 */
1210 if (!intlv_addr)
1211 return sys_addr >> 6 & 1;
1212
1213 if (intlv_addr & 0x2) {
1214 u8 shift = intlv_addr & 0x1 ? 9 : 6;
1215 u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) % 2;
1216
1217 return ((sys_addr >> shift) & 1) ^ temp;
1218 }
1219
1220 return (sys_addr >> (12 + hweight8(intlv_en))) & 1;
1221 }
1222
1223 if (dct_high_range_enabled(pvt))
1224 return ~dct_sel_high & 1;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001225
1226 return 0;
1227}
1228
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001229/* Convert the sys_addr to the normalized DCT address */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001230static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, int range,
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001231 u64 sys_addr, bool hi_rng,
1232 u32 dct_sel_base_addr)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001233{
1234 u64 chan_off;
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001235 u64 dram_base = get_dram_base(pvt, range);
1236 u64 hole_off = f10_dhar_offset(pvt);
1237 u32 hole_valid = dhar_valid(pvt);
1238 u64 dct_sel_base_off = (pvt->dct_sel_hi & 0xFFFFFC00) << 16;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001239
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001240 if (hi_rng) {
1241 /*
1242 * if
1243 * base address of high range is below 4Gb
1244 * (bits [47:27] at [31:11])
1245 * DRAM address space on this DCT is hoisted above 4Gb &&
1246 * sys_addr > 4Gb
1247 *
1248 * remove hole offset from sys_addr
1249 * else
1250 * remove high range offset from sys_addr
1251 */
1252 if ((!(dct_sel_base_addr >> 16) ||
1253 dct_sel_base_addr < dhar_base(pvt)) &&
1254 hole_valid &&
1255 (sys_addr >= BIT_64(32)))
Borislav Petkovbc21fa52010-11-11 17:29:13 +01001256 chan_off = hole_off;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001257 else
1258 chan_off = dct_sel_base_off;
1259 } else {
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001260 /*
1261 * if
1262 * we have a valid hole &&
1263 * sys_addr > 4Gb
1264 *
1265 * remove hole
1266 * else
1267 * remove dram base to normalize to DCT address
1268 */
1269 if (hole_valid && (sys_addr >= BIT_64(32)))
Borislav Petkovbc21fa52010-11-11 17:29:13 +01001270 chan_off = hole_off;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001271 else
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001272 chan_off = dram_base;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001273 }
1274
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001275 return (sys_addr & GENMASK(6,47)) - (chan_off & GENMASK(23,47));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001276}
1277
Doug Thompson6163b5d2009-04-27 16:20:17 +02001278/*
1279 * checks if the csrow passed in is marked as SPARED, if so returns the new
1280 * spare row
1281 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001282static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001283{
Borislav Petkov614ec9d2011-01-13 18:02:22 +01001284 int tmp_cs;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001285
Borislav Petkov614ec9d2011-01-13 18:02:22 +01001286 if (online_spare_swap_done(pvt, dct) &&
1287 csrow == online_spare_bad_dramcs(pvt, dct)) {
1288
1289 for_each_chip_select(tmp_cs, dct, pvt) {
1290 if (chip_select_base(tmp_cs, dct, pvt) & 0x2) {
1291 csrow = tmp_cs;
1292 break;
1293 }
1294 }
Doug Thompson6163b5d2009-04-27 16:20:17 +02001295 }
1296 return csrow;
1297}
1298
1299/*
1300 * Iterate over the DRAM DCT "base" and "mask" registers looking for a
1301 * SystemAddr match on the specified 'ChannelSelect' and 'NodeID'
1302 *
1303 * Return:
1304 * -EINVAL: NOT FOUND
1305 * 0..csrow = Chip-Select Row
1306 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001307static int f1x_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001308{
1309 struct mem_ctl_info *mci;
1310 struct amd64_pvt *pvt;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001311 u64 cs_base, cs_mask;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001312 int cs_found = -EINVAL;
1313 int csrow;
1314
Borislav Petkovcc4d8862010-10-13 16:11:59 +02001315 mci = mcis[nid];
Doug Thompson6163b5d2009-04-27 16:20:17 +02001316 if (!mci)
1317 return cs_found;
1318
1319 pvt = mci->pvt_info;
1320
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001321 debugf1("input addr: 0x%llx, DCT: %d\n", in_addr, dct);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001322
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001323 for_each_chip_select(csrow, dct, pvt) {
1324 if (!csrow_enabled(csrow, dct, pvt))
Doug Thompson6163b5d2009-04-27 16:20:17 +02001325 continue;
1326
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001327 get_cs_base_and_mask(pvt, csrow, dct, &cs_base, &cs_mask);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001328
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001329 debugf1(" CSROW=%d CSBase=0x%llx CSMask=0x%llx\n",
1330 csrow, cs_base, cs_mask);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001331
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001332 cs_mask = ~cs_mask;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001333
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001334 debugf1(" (InputAddr & ~CSMask)=0x%llx "
1335 "(CSBase & ~CSMask)=0x%llx\n",
1336 (in_addr & cs_mask), (cs_base & cs_mask));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001337
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001338 if ((in_addr & cs_mask) == (cs_base & cs_mask)) {
1339 cs_found = f10_process_possible_spare(pvt, dct, csrow);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001340
1341 debugf1(" MATCH csrow=%d\n", cs_found);
1342 break;
1343 }
1344 }
1345 return cs_found;
1346}
1347
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001348/*
1349 * See F2x10C. Non-interleaved graphics framebuffer memory under the 16G is
1350 * swapped with a region located at the bottom of memory so that the GPU can use
1351 * the interleaved region and thus two channels.
1352 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001353static u64 f1x_swap_interleaved_region(struct amd64_pvt *pvt, u64 sys_addr)
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001354{
1355 u32 swap_reg, swap_base, swap_limit, rgn_size, tmp_addr;
1356
1357 if (boot_cpu_data.x86 == 0x10) {
1358 /* only revC3 and revE have that feature */
1359 if (boot_cpu_data.x86_model < 4 ||
1360 (boot_cpu_data.x86_model < 0xa &&
1361 boot_cpu_data.x86_mask < 3))
1362 return sys_addr;
1363 }
1364
1365 amd64_read_dct_pci_cfg(pvt, SWAP_INTLV_REG, &swap_reg);
1366
1367 if (!(swap_reg & 0x1))
1368 return sys_addr;
1369
1370 swap_base = (swap_reg >> 3) & 0x7f;
1371 swap_limit = (swap_reg >> 11) & 0x7f;
1372 rgn_size = (swap_reg >> 20) & 0x7f;
1373 tmp_addr = sys_addr >> 27;
1374
1375 if (!(sys_addr >> 34) &&
1376 (((tmp_addr >= swap_base) &&
1377 (tmp_addr <= swap_limit)) ||
1378 (tmp_addr < rgn_size)))
1379 return sys_addr ^ (u64)swap_base << 27;
1380
1381 return sys_addr;
1382}
1383
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001384/* For a given @dram_range, check if @sys_addr falls within it. */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001385static int f1x_match_to_this_node(struct amd64_pvt *pvt, int range,
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001386 u64 sys_addr, int *nid, int *chan_sel)
1387{
Borislav Petkov229a7a12010-12-09 18:57:54 +01001388 int cs_found = -EINVAL;
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001389 u64 chan_addr;
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001390 u32 dct_sel_base;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001391 u8 channel;
Borislav Petkov229a7a12010-12-09 18:57:54 +01001392 bool high_range = false;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001393
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001394 u8 node_id = dram_dst_node(pvt, range);
Borislav Petkov229a7a12010-12-09 18:57:54 +01001395 u8 intlv_en = dram_intlv_en(pvt, range);
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001396 u32 intlv_sel = dram_intlv_sel(pvt, range);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001397
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001398 debugf1("(range %d) SystemAddr= 0x%llx Limit=0x%llx\n",
1399 range, sys_addr, get_dram_limit(pvt, range));
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001400
Borislav Petkov355fba62011-01-17 13:03:26 +01001401 if (dhar_valid(pvt) &&
1402 dhar_base(pvt) <= sys_addr &&
1403 sys_addr < BIT_64(32)) {
1404 amd64_warn("Huh? Address is in the MMIO hole: 0x%016llx\n",
1405 sys_addr);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001406 return -EINVAL;
Borislav Petkov355fba62011-01-17 13:03:26 +01001407 }
1408
1409 if (intlv_en &&
1410 (intlv_sel != ((sys_addr >> 12) & intlv_en))) {
1411 amd64_warn("Botched intlv bits, en: 0x%x, sel: 0x%x\n",
1412 intlv_en, intlv_sel);
1413 return -EINVAL;
1414 }
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001415
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001416 sys_addr = f1x_swap_interleaved_region(pvt, sys_addr);
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001417
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001418 dct_sel_base = dct_sel_baseaddr(pvt);
1419
1420 /*
1421 * check whether addresses >= DctSelBaseAddr[47:27] are to be used to
1422 * select between DCT0 and DCT1.
1423 */
1424 if (dct_high_range_enabled(pvt) &&
1425 !dct_ganging_enabled(pvt) &&
1426 ((sys_addr >> 27) >= (dct_sel_base >> 11)))
Borislav Petkov229a7a12010-12-09 18:57:54 +01001427 high_range = true;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001428
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001429 channel = f1x_determine_channel(pvt, sys_addr, high_range, intlv_en);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001430
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001431 chan_addr = f1x_get_norm_dct_addr(pvt, range, sys_addr,
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001432 high_range, dct_sel_base);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001433
Borislav Petkove2f79db2011-01-13 14:57:34 +01001434 /* Remove node interleaving, see F1x120 */
1435 if (intlv_en)
1436 chan_addr = ((chan_addr >> (12 + hweight8(intlv_en))) << 12) |
1437 (chan_addr & 0xfff);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001438
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001439 /* remove channel interleave */
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001440 if (dct_interleave_enabled(pvt) &&
1441 !dct_high_range_enabled(pvt) &&
1442 !dct_ganging_enabled(pvt)) {
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001443
1444 if (dct_sel_interleave_addr(pvt) != 1) {
1445 if (dct_sel_interleave_addr(pvt) == 0x3)
1446 /* hash 9 */
1447 chan_addr = ((chan_addr >> 10) << 9) |
1448 (chan_addr & 0x1ff);
1449 else
1450 /* A[6] or hash 6 */
1451 chan_addr = ((chan_addr >> 7) << 6) |
1452 (chan_addr & 0x3f);
1453 } else
1454 /* A[12] */
1455 chan_addr = ((chan_addr >> 13) << 12) |
1456 (chan_addr & 0xfff);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001457 }
1458
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001459 debugf1(" Normalized DCT addr: 0x%llx\n", chan_addr);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001460
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001461 cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, channel);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001462
1463 if (cs_found >= 0) {
1464 *nid = node_id;
1465 *chan_sel = channel;
1466 }
1467 return cs_found;
1468}
1469
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001470static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001471 int *node, int *chan_sel)
1472{
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001473 int range, cs_found = -EINVAL;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001474
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001475 for (range = 0; range < DRAM_RANGES; range++) {
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001476
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001477 if (!dram_rw(pvt, range))
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001478 continue;
1479
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001480 if ((get_dram_base(pvt, range) <= sys_addr) &&
1481 (get_dram_limit(pvt, range) >= sys_addr)) {
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001482
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001483 cs_found = f1x_match_to_this_node(pvt, range,
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001484 sys_addr, node,
1485 chan_sel);
1486 if (cs_found >= 0)
1487 break;
1488 }
1489 }
1490 return cs_found;
1491}
1492
1493/*
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001494 * For reference see "2.8.5 Routing DRAM Requests" in F10 BKDG. This code maps
1495 * a @sys_addr to NodeID, DCT (channel) and chip select (CSROW).
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001496 *
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001497 * The @sys_addr is usually an error address received from the hardware
1498 * (MCX_ADDR).
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001499 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001500static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001501 u16 syndrome)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001502{
1503 struct amd64_pvt *pvt = mci->pvt_info;
1504 u32 page, offset;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001505 int nid, csrow, chan = 0;
1506
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001507 csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001508
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001509 if (csrow < 0) {
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001510 edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001511 return;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001512 }
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001513
1514 error_address_to_page_and_offset(sys_addr, &page, &offset);
1515
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001516 /*
1517 * We need the syndromes for channel detection only when we're
1518 * ganged. Otherwise @chan should already contain the channel at
1519 * this point.
1520 */
Borislav Petkova97fa682010-12-23 14:07:18 +01001521 if (dct_ganging_enabled(pvt))
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001522 chan = get_channel_from_ecc_syndrome(mci, syndrome);
1523
1524 if (chan >= 0)
1525 edac_mc_handle_ce(mci, page, offset, syndrome, csrow, chan,
1526 EDAC_MOD_STR);
1527 else
1528 /*
1529 * Channel unknown, report all channels on this CSROW as failed.
1530 */
1531 for (chan = 0; chan < mci->csrows[csrow].nr_channels; chan++)
1532 edac_mc_handle_ce(mci, page, offset, syndrome,
1533 csrow, chan, EDAC_MOD_STR);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001534}
1535
1536/*
Borislav Petkov8566c4d2009-10-16 13:48:28 +02001537 * debug routine to display the memory sizes of all logical DIMMs and its
Borislav Petkovcb328502010-12-22 14:28:24 +01001538 * CSROWs
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001539 */
Borislav Petkov8566c4d2009-10-16 13:48:28 +02001540static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001541{
Borislav Petkov603adaf2009-12-21 14:52:53 +01001542 int dimm, size0, size1, factor = 0;
Borislav Petkov525a1b22010-12-21 15:53:27 +01001543 u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases;
1544 u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001545
Borislav Petkov8566c4d2009-10-16 13:48:28 +02001546 if (boot_cpu_data.x86 == 0xf) {
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001547 if (pvt->dclr0 & WIDTH_128)
Borislav Petkov603adaf2009-12-21 14:52:53 +01001548 factor = 1;
1549
Borislav Petkov8566c4d2009-10-16 13:48:28 +02001550 /* K8 families < revF not supported yet */
Borislav Petkov1433eb92009-10-21 13:44:36 +02001551 if (pvt->ext_model < K8_REV_F)
Borislav Petkov8566c4d2009-10-16 13:48:28 +02001552 return;
1553 else
1554 WARN_ON(ctrl != 0);
1555 }
1556
Borislav Petkov4d796362011-02-03 15:59:57 +01001557 dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1 : pvt->dbam0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001558 dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->csels[1].csbases
1559 : pvt->csels[0].csbases;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001560
Borislav Petkov4d796362011-02-03 15:59:57 +01001561 debugf1("F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", ctrl, dbam);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001562
Borislav Petkov8566c4d2009-10-16 13:48:28 +02001563 edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl);
1564
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001565 /* Dump memory sizes for DIMM and its CSROWs */
1566 for (dimm = 0; dimm < 4; dimm++) {
1567
1568 size0 = 0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001569 if (dcsb[dimm*2] & DCSB_CS_ENABLE)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001570 size0 = pvt->ops->dbam_to_cs(pvt, ctrl,
1571 DBAM_DIMM(dimm, dbam));
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001572
1573 size1 = 0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001574 if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001575 size1 = pvt->ops->dbam_to_cs(pvt, ctrl,
1576 DBAM_DIMM(dimm, dbam));
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001577
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001578 amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
1579 dimm * 2, size0 << factor,
1580 dimm * 2 + 1, size1 << factor);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001581 }
1582}
1583
Doug Thompson4d376072009-04-27 16:25:05 +02001584static struct amd64_family_type amd64_family_types[] = {
1585 [K8_CPUS] = {
Borislav Petkov0092b202010-10-01 19:20:05 +02001586 .ctl_name = "K8",
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001587 .f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP,
1588 .f3_id = PCI_DEVICE_ID_AMD_K8_NB_MISC,
Doug Thompson4d376072009-04-27 16:25:05 +02001589 .ops = {
Borislav Petkov1433eb92009-10-21 13:44:36 +02001590 .early_channel_count = k8_early_channel_count,
Borislav Petkov1433eb92009-10-21 13:44:36 +02001591 .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow,
1592 .dbam_to_cs = k8_dbam_to_chip_select,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02001593 .read_dct_pci_cfg = k8_read_dct_pci_cfg,
Doug Thompson4d376072009-04-27 16:25:05 +02001594 }
1595 },
1596 [F10_CPUS] = {
Borislav Petkov0092b202010-10-01 19:20:05 +02001597 .ctl_name = "F10h",
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001598 .f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP,
1599 .f3_id = PCI_DEVICE_ID_AMD_10H_NB_MISC,
Doug Thompson4d376072009-04-27 16:25:05 +02001600 .ops = {
Borislav Petkov7d20d142011-01-07 17:58:04 +01001601 .early_channel_count = f1x_early_channel_count,
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001602 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
Borislav Petkov1433eb92009-10-21 13:44:36 +02001603 .dbam_to_cs = f10_dbam_to_chip_select,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02001604 .read_dct_pci_cfg = f10_read_dct_pci_cfg,
1605 }
1606 },
1607 [F15_CPUS] = {
1608 .ctl_name = "F15h",
Borislav Petkovdf71a052011-01-19 18:15:10 +01001609 .f1_id = PCI_DEVICE_ID_AMD_15H_NB_F1,
1610 .f3_id = PCI_DEVICE_ID_AMD_15H_NB_F3,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02001611 .ops = {
Borislav Petkov7d20d142011-01-07 17:58:04 +01001612 .early_channel_count = f1x_early_channel_count,
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001613 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001614 .dbam_to_cs = f15_dbam_to_chip_select,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02001615 .read_dct_pci_cfg = f15_read_dct_pci_cfg,
Doug Thompson4d376072009-04-27 16:25:05 +02001616 }
1617 },
Doug Thompson4d376072009-04-27 16:25:05 +02001618};
1619
1620static struct pci_dev *pci_get_related_function(unsigned int vendor,
1621 unsigned int device,
1622 struct pci_dev *related)
1623{
1624 struct pci_dev *dev = NULL;
1625
1626 dev = pci_get_device(vendor, device, dev);
1627 while (dev) {
1628 if ((dev->bus->number == related->bus->number) &&
1629 (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
1630 break;
1631 dev = pci_get_device(vendor, device, dev);
1632 }
1633
1634 return dev;
1635}
1636
Doug Thompsonb1289d62009-04-27 16:37:05 +02001637/*
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001638 * These are tables of eigenvectors (one per line) which can be used for the
1639 * construction of the syndrome tables. The modified syndrome search algorithm
1640 * uses those to find the symbol in error and thus the DIMM.
Doug Thompsonb1289d62009-04-27 16:37:05 +02001641 *
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001642 * Algorithm courtesy of Ross LaFetra from AMD.
Doug Thompsonb1289d62009-04-27 16:37:05 +02001643 */
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001644static u16 x4_vectors[] = {
1645 0x2f57, 0x1afe, 0x66cc, 0xdd88,
1646 0x11eb, 0x3396, 0x7f4c, 0xeac8,
1647 0x0001, 0x0002, 0x0004, 0x0008,
1648 0x1013, 0x3032, 0x4044, 0x8088,
1649 0x106b, 0x30d6, 0x70fc, 0xe0a8,
1650 0x4857, 0xc4fe, 0x13cc, 0x3288,
1651 0x1ac5, 0x2f4a, 0x5394, 0xa1e8,
1652 0x1f39, 0x251e, 0xbd6c, 0x6bd8,
1653 0x15c1, 0x2a42, 0x89ac, 0x4758,
1654 0x2b03, 0x1602, 0x4f0c, 0xca08,
1655 0x1f07, 0x3a0e, 0x6b04, 0xbd08,
1656 0x8ba7, 0x465e, 0x244c, 0x1cc8,
1657 0x2b87, 0x164e, 0x642c, 0xdc18,
1658 0x40b9, 0x80de, 0x1094, 0x20e8,
1659 0x27db, 0x1eb6, 0x9dac, 0x7b58,
1660 0x11c1, 0x2242, 0x84ac, 0x4c58,
1661 0x1be5, 0x2d7a, 0x5e34, 0xa718,
1662 0x4b39, 0x8d1e, 0x14b4, 0x28d8,
1663 0x4c97, 0xc87e, 0x11fc, 0x33a8,
1664 0x8e97, 0x497e, 0x2ffc, 0x1aa8,
1665 0x16b3, 0x3d62, 0x4f34, 0x8518,
1666 0x1e2f, 0x391a, 0x5cac, 0xf858,
1667 0x1d9f, 0x3b7a, 0x572c, 0xfe18,
1668 0x15f5, 0x2a5a, 0x5264, 0xa3b8,
1669 0x1dbb, 0x3b66, 0x715c, 0xe3f8,
1670 0x4397, 0xc27e, 0x17fc, 0x3ea8,
1671 0x1617, 0x3d3e, 0x6464, 0xb8b8,
1672 0x23ff, 0x12aa, 0xab6c, 0x56d8,
1673 0x2dfb, 0x1ba6, 0x913c, 0x7328,
1674 0x185d, 0x2ca6, 0x7914, 0x9e28,
1675 0x171b, 0x3e36, 0x7d7c, 0xebe8,
1676 0x4199, 0x82ee, 0x19f4, 0x2e58,
1677 0x4807, 0xc40e, 0x130c, 0x3208,
1678 0x1905, 0x2e0a, 0x5804, 0xac08,
1679 0x213f, 0x132a, 0xadfc, 0x5ba8,
1680 0x19a9, 0x2efe, 0xb5cc, 0x6f88,
Doug Thompsonb1289d62009-04-27 16:37:05 +02001681};
1682
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001683static u16 x8_vectors[] = {
1684 0x0145, 0x028a, 0x2374, 0x43c8, 0xa1f0, 0x0520, 0x0a40, 0x1480,
1685 0x0211, 0x0422, 0x0844, 0x1088, 0x01b0, 0x44e0, 0x23c0, 0xed80,
1686 0x1011, 0x0116, 0x022c, 0x0458, 0x08b0, 0x8c60, 0x2740, 0x4e80,
1687 0x0411, 0x0822, 0x1044, 0x0158, 0x02b0, 0x2360, 0x46c0, 0xab80,
1688 0x0811, 0x1022, 0x012c, 0x0258, 0x04b0, 0x4660, 0x8cc0, 0x2780,
1689 0x2071, 0x40e2, 0xa0c4, 0x0108, 0x0210, 0x0420, 0x0840, 0x1080,
1690 0x4071, 0x80e2, 0x0104, 0x0208, 0x0410, 0x0820, 0x1040, 0x2080,
1691 0x8071, 0x0102, 0x0204, 0x0408, 0x0810, 0x1020, 0x2040, 0x4080,
1692 0x019d, 0x03d6, 0x136c, 0x2198, 0x50b0, 0xb2e0, 0x0740, 0x0e80,
1693 0x0189, 0x03ea, 0x072c, 0x0e58, 0x1cb0, 0x56e0, 0x37c0, 0xf580,
1694 0x01fd, 0x0376, 0x06ec, 0x0bb8, 0x1110, 0x2220, 0x4440, 0x8880,
1695 0x0163, 0x02c6, 0x1104, 0x0758, 0x0eb0, 0x2be0, 0x6140, 0xc280,
1696 0x02fd, 0x01c6, 0x0b5c, 0x1108, 0x07b0, 0x25a0, 0x8840, 0x6180,
1697 0x0801, 0x012e, 0x025c, 0x04b8, 0x1370, 0x26e0, 0x57c0, 0xb580,
1698 0x0401, 0x0802, 0x015c, 0x02b8, 0x22b0, 0x13e0, 0x7140, 0xe280,
1699 0x0201, 0x0402, 0x0804, 0x01b8, 0x11b0, 0x31a0, 0x8040, 0x7180,
1700 0x0101, 0x0202, 0x0404, 0x0808, 0x1010, 0x2020, 0x4040, 0x8080,
1701 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
1702 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
1703};
1704
1705static int decode_syndrome(u16 syndrome, u16 *vectors, int num_vecs,
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001706 int v_dim)
Doug Thompsonb1289d62009-04-27 16:37:05 +02001707{
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001708 unsigned int i, err_sym;
Doug Thompsonb1289d62009-04-27 16:37:05 +02001709
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001710 for (err_sym = 0; err_sym < num_vecs / v_dim; err_sym++) {
1711 u16 s = syndrome;
1712 int v_idx = err_sym * v_dim;
1713 int v_end = (err_sym + 1) * v_dim;
Doug Thompsonb1289d62009-04-27 16:37:05 +02001714
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001715 /* walk over all 16 bits of the syndrome */
1716 for (i = 1; i < (1U << 16); i <<= 1) {
1717
1718 /* if bit is set in that eigenvector... */
1719 if (v_idx < v_end && vectors[v_idx] & i) {
1720 u16 ev_comp = vectors[v_idx++];
1721
1722 /* ... and bit set in the modified syndrome, */
1723 if (s & i) {
1724 /* remove it. */
1725 s ^= ev_comp;
1726
1727 if (!s)
1728 return err_sym;
1729 }
1730
1731 } else if (s & i)
1732 /* can't get to zero, move to next symbol */
1733 break;
1734 }
Doug Thompsonb1289d62009-04-27 16:37:05 +02001735 }
1736
1737 debugf0("syndrome(%x) not found\n", syndrome);
1738 return -1;
1739}
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001740
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001741static int map_err_sym_to_channel(int err_sym, int sym_size)
1742{
1743 if (sym_size == 4)
1744 switch (err_sym) {
1745 case 0x20:
1746 case 0x21:
1747 return 0;
1748 break;
1749 case 0x22:
1750 case 0x23:
1751 return 1;
1752 break;
1753 default:
1754 return err_sym >> 4;
1755 break;
1756 }
1757 /* x8 symbols */
1758 else
1759 switch (err_sym) {
1760 /* imaginary bits not in a DIMM */
1761 case 0x10:
1762 WARN(1, KERN_ERR "Invalid error symbol: 0x%x\n",
1763 err_sym);
1764 return -1;
1765 break;
1766
1767 case 0x11:
1768 return 0;
1769 break;
1770 case 0x12:
1771 return 1;
1772 break;
1773 default:
1774 return err_sym >> 3;
1775 break;
1776 }
1777 return -1;
1778}
1779
1780static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
1781{
1782 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001783 int err_sym = -1;
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001784
Borislav Petkova3b7db02011-01-19 20:35:12 +01001785 if (pvt->ecc_sym_sz == 8)
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001786 err_sym = decode_syndrome(syndrome, x8_vectors,
1787 ARRAY_SIZE(x8_vectors),
Borislav Petkova3b7db02011-01-19 20:35:12 +01001788 pvt->ecc_sym_sz);
1789 else if (pvt->ecc_sym_sz == 4)
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001790 err_sym = decode_syndrome(syndrome, x4_vectors,
1791 ARRAY_SIZE(x4_vectors),
Borislav Petkova3b7db02011-01-19 20:35:12 +01001792 pvt->ecc_sym_sz);
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001793 else {
Borislav Petkova3b7db02011-01-19 20:35:12 +01001794 amd64_warn("Illegal syndrome type: %u\n", pvt->ecc_sym_sz);
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001795 return err_sym;
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001796 }
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001797
Borislav Petkova3b7db02011-01-19 20:35:12 +01001798 return map_err_sym_to_channel(err_sym, pvt->ecc_sym_sz);
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001799}
1800
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001801/*
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001802 * Handle any Correctable Errors (CEs) that have occurred. Check for valid ERROR
1803 * ADDRESS and process.
1804 */
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001805static void amd64_handle_ce(struct mem_ctl_info *mci, struct mce *m)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001806{
1807 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001808 u64 sys_addr;
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001809 u16 syndrome;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001810
1811 /* Ensure that the Error Address is VALID */
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001812 if (!(m->status & MCI_STATUS_ADDRV)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001813 amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001814 edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
1815 return;
1816 }
1817
Borislav Petkov70046622011-01-10 14:37:27 +01001818 sys_addr = get_error_address(m);
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001819 syndrome = extract_syndrome(m->status);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001820
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001821 amd64_mc_err(mci, "CE ERROR_ADDRESS= 0x%llx\n", sys_addr);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001822
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001823 pvt->ops->map_sysaddr_to_csrow(mci, sys_addr, syndrome);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001824}
1825
1826/* Handle any Un-correctable Errors (UEs) */
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001827static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001828{
Borislav Petkov1f6bcee2009-11-13 14:02:57 +01001829 struct mem_ctl_info *log_mci, *src_mci = NULL;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001830 int csrow;
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001831 u64 sys_addr;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001832 u32 page, offset;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001833
1834 log_mci = mci;
1835
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001836 if (!(m->status & MCI_STATUS_ADDRV)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001837 amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001838 edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
1839 return;
1840 }
1841
Borislav Petkov70046622011-01-10 14:37:27 +01001842 sys_addr = get_error_address(m);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001843
1844 /*
1845 * Find out which node the error address belongs to. This may be
1846 * different from the node that detected the error.
1847 */
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001848 src_mci = find_mc_by_sys_addr(mci, sys_addr);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001849 if (!src_mci) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001850 amd64_mc_err(mci, "ERROR ADDRESS (0x%lx) NOT mapped to a MC\n",
1851 (unsigned long)sys_addr);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001852 edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
1853 return;
1854 }
1855
1856 log_mci = src_mci;
1857
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001858 csrow = sys_addr_to_csrow(log_mci, sys_addr);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001859 if (csrow < 0) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001860 amd64_mc_err(mci, "ERROR_ADDRESS (0x%lx) NOT mapped to CS\n",
1861 (unsigned long)sys_addr);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001862 edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
1863 } else {
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001864 error_address_to_page_and_offset(sys_addr, &page, &offset);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001865 edac_mc_handle_ue(log_mci, page, offset, csrow, EDAC_MOD_STR);
1866 }
1867}
1868
Borislav Petkov549d0422009-07-24 13:51:42 +02001869static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001870 struct mce *m)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001871{
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001872 u16 ec = EC(m->status);
1873 u8 xec = XEC(m->status, 0x1f);
1874 u8 ecc_type = (m->status >> 45) & 0x3;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001875
Borislav Petkovb70ef012009-06-25 19:32:38 +02001876 /* Bail early out if this was an 'observed' error */
Borislav Petkov5980bb92011-01-07 16:26:49 +01001877 if (PP(ec) == NBSL_PP_OBS)
Borislav Petkovb70ef012009-06-25 19:32:38 +02001878 return;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001879
Borislav Petkovecaf5602009-07-23 16:32:01 +02001880 /* Do only ECC errors */
1881 if (xec && xec != F10_NBSL_EXT_ERR_ECC)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001882 return;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001883
Borislav Petkovecaf5602009-07-23 16:32:01 +02001884 if (ecc_type == 2)
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001885 amd64_handle_ce(mci, m);
Borislav Petkovecaf5602009-07-23 16:32:01 +02001886 else if (ecc_type == 1)
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001887 amd64_handle_ue(mci, m);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001888}
1889
Borislav Petkov7cfd4a82010-09-01 14:45:20 +02001890void amd64_decode_bus_error(int node_id, struct mce *m, u32 nbcfg)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001891{
Borislav Petkovcc4d8862010-10-13 16:11:59 +02001892 struct mem_ctl_info *mci = mcis[node_id];
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001893
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001894 __amd64_decode_bus_error(mci, m);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001895}
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001896
Doug Thompson0ec449e2009-04-27 19:41:25 +02001897/*
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001898 * Use pvt->F2 which contains the F2 CPU PCI device to get the related
Borislav Petkovbbd0c1f2010-10-01 19:27:58 +02001899 * F1 (AddrMap) and F3 (Misc) devices. Return negative value on error.
Doug Thompson0ec449e2009-04-27 19:41:25 +02001900 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02001901static int reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 f1_id, u16 f3_id)
Doug Thompson0ec449e2009-04-27 19:41:25 +02001902{
Doug Thompson0ec449e2009-04-27 19:41:25 +02001903 /* Reserve the ADDRESS MAP Device */
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001904 pvt->F1 = pci_get_related_function(pvt->F2->vendor, f1_id, pvt->F2);
1905 if (!pvt->F1) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001906 amd64_err("error address map device not found: "
1907 "vendor %x device 0x%x (broken BIOS?)\n",
1908 PCI_VENDOR_ID_AMD, f1_id);
Borislav Petkovbbd0c1f2010-10-01 19:27:58 +02001909 return -ENODEV;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001910 }
1911
1912 /* Reserve the MISC Device */
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001913 pvt->F3 = pci_get_related_function(pvt->F2->vendor, f3_id, pvt->F2);
1914 if (!pvt->F3) {
1915 pci_dev_put(pvt->F1);
1916 pvt->F1 = NULL;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001917
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001918 amd64_err("error F3 device not found: "
1919 "vendor %x device 0x%x (broken BIOS?)\n",
1920 PCI_VENDOR_ID_AMD, f3_id);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001921
Borislav Petkovbbd0c1f2010-10-01 19:27:58 +02001922 return -ENODEV;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001923 }
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001924 debugf1("F1: %s\n", pci_name(pvt->F1));
1925 debugf1("F2: %s\n", pci_name(pvt->F2));
1926 debugf1("F3: %s\n", pci_name(pvt->F3));
Doug Thompson0ec449e2009-04-27 19:41:25 +02001927
1928 return 0;
1929}
1930
Borislav Petkov360b7f32010-10-15 19:25:38 +02001931static void free_mc_sibling_devs(struct amd64_pvt *pvt)
Doug Thompson0ec449e2009-04-27 19:41:25 +02001932{
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001933 pci_dev_put(pvt->F1);
1934 pci_dev_put(pvt->F3);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001935}
1936
1937/*
1938 * Retrieve the hardware registers of the memory controller (this includes the
1939 * 'Address Map' and 'Misc' device regs)
1940 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02001941static void read_mc_regs(struct amd64_pvt *pvt)
Doug Thompson0ec449e2009-04-27 19:41:25 +02001942{
Borislav Petkova3b7db02011-01-19 20:35:12 +01001943 struct cpuinfo_x86 *c = &boot_cpu_data;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001944 u64 msr_val;
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001945 u32 tmp;
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001946 int range;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001947
1948 /*
1949 * Retrieve TOP_MEM and TOP_MEM2; no masking off of reserved bits since
1950 * those are Read-As-Zero
1951 */
Borislav Petkove97f8bb2009-10-12 15:27:45 +02001952 rdmsrl(MSR_K8_TOP_MEM1, pvt->top_mem);
1953 debugf0(" TOP_MEM: 0x%016llx\n", pvt->top_mem);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001954
1955 /* check first whether TOP_MEM2 is enabled */
1956 rdmsrl(MSR_K8_SYSCFG, msr_val);
1957 if (msr_val & (1U << 21)) {
Borislav Petkove97f8bb2009-10-12 15:27:45 +02001958 rdmsrl(MSR_K8_TOP_MEM2, pvt->top_mem2);
1959 debugf0(" TOP_MEM2: 0x%016llx\n", pvt->top_mem2);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001960 } else
1961 debugf0(" TOP_MEM2 disabled.\n");
1962
Borislav Petkov5980bb92011-01-07 16:26:49 +01001963 amd64_read_pci_cfg(pvt->F3, NBCAP, &pvt->nbcap);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001964
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001965 read_dram_ctl_register(pvt);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001966
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001967 for (range = 0; range < DRAM_RANGES; range++) {
1968 u8 rw;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001969
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001970 /* read settings for this DRAM range */
1971 read_dram_base_limit_regs(pvt, range);
Borislav Petkove97f8bb2009-10-12 15:27:45 +02001972
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001973 rw = dram_rw(pvt, range);
1974 if (!rw)
1975 continue;
1976
1977 debugf1(" DRAM range[%d], base: 0x%016llx; limit: 0x%016llx\n",
1978 range,
1979 get_dram_base(pvt, range),
1980 get_dram_limit(pvt, range));
1981
1982 debugf1(" IntlvEn=%s; Range access: %s%s IntlvSel=%d DstNode=%d\n",
1983 dram_intlv_en(pvt, range) ? "Enabled" : "Disabled",
1984 (rw & 0x1) ? "R" : "-",
1985 (rw & 0x2) ? "W" : "-",
1986 dram_intlv_sel(pvt, range),
1987 dram_dst_node(pvt, range));
Doug Thompson0ec449e2009-04-27 19:41:25 +02001988 }
1989
Borislav Petkovb2b0c602010-10-08 18:32:29 +02001990 read_dct_base_mask(pvt);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001991
Borislav Petkovbc21fa52010-11-11 17:29:13 +01001992 amd64_read_pci_cfg(pvt->F1, DHAR, &pvt->dhar);
Borislav Petkov525a1b22010-12-21 15:53:27 +01001993 amd64_read_dct_pci_cfg(pvt, DBAM0, &pvt->dbam0);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001994
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001995 amd64_read_pci_cfg(pvt->F3, F10_ONLINE_SPARE, &pvt->online_spare);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001996
Borislav Petkovcb328502010-12-22 14:28:24 +01001997 amd64_read_dct_pci_cfg(pvt, DCLR0, &pvt->dclr0);
1998 amd64_read_dct_pci_cfg(pvt, DCHR0, &pvt->dchr0);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001999
Borislav Petkov78da1212010-12-22 19:31:45 +01002000 if (!dct_ganging_enabled(pvt)) {
Borislav Petkovcb328502010-12-22 14:28:24 +01002001 amd64_read_dct_pci_cfg(pvt, DCLR1, &pvt->dclr1);
2002 amd64_read_dct_pci_cfg(pvt, DCHR1, &pvt->dchr1);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002003 }
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002004
Borislav Petkova3b7db02011-01-19 20:35:12 +01002005 pvt->ecc_sym_sz = 4;
2006
2007 if (c->x86 >= 0x10) {
Borislav Petkovb2b0c602010-10-08 18:32:29 +02002008 amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
Borislav Petkov525a1b22010-12-21 15:53:27 +01002009 amd64_read_dct_pci_cfg(pvt, DBAM1, &pvt->dbam1);
Borislav Petkova3b7db02011-01-19 20:35:12 +01002010
2011 /* F10h, revD and later can do x8 ECC too */
2012 if ((c->x86 > 0x10 || c->x86_model > 7) && tmp & BIT(25))
2013 pvt->ecc_sym_sz = 8;
Borislav Petkov525a1b22010-12-21 15:53:27 +01002014 }
Borislav Petkovb2b0c602010-10-08 18:32:29 +02002015 dump_misc_regs(pvt);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002016}
2017
2018/*
2019 * NOTE: CPU Revision Dependent code
2020 *
2021 * Input:
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002022 * @csrow_nr ChipSelect Row Number (0..NUM_CHIPSELECTS-1)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002023 * k8 private pointer to -->
2024 * DRAM Bank Address mapping register
2025 * node_id
2026 * DCL register where dual_channel_active is
2027 *
2028 * The DBAM register consists of 4 sets of 4 bits each definitions:
2029 *
2030 * Bits: CSROWs
2031 * 0-3 CSROWs 0 and 1
2032 * 4-7 CSROWs 2 and 3
2033 * 8-11 CSROWs 4 and 5
2034 * 12-15 CSROWs 6 and 7
2035 *
2036 * Values range from: 0 to 15
2037 * The meaning of the values depends on CPU revision and dual-channel state,
2038 * see relevant BKDG more info.
2039 *
2040 * The memory controller provides for total of only 8 CSROWs in its current
2041 * architecture. Each "pair" of CSROWs normally represents just one DIMM in
2042 * single channel or two (2) DIMMs in dual channel mode.
2043 *
2044 * The following code logic collapses the various tables for CSROW based on CPU
2045 * revision.
2046 *
2047 * Returns:
2048 * The number of PAGE_SIZE pages on the specified CSROW number it
2049 * encompasses
2050 *
2051 */
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01002052static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002053{
Borislav Petkov1433eb92009-10-21 13:44:36 +02002054 u32 cs_mode, nr_pages;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002055
2056 /*
2057 * The math on this doesn't look right on the surface because x/2*4 can
2058 * be simplified to x*2 but this expression makes use of the fact that
2059 * it is integral math where 1/2=0. This intermediate value becomes the
2060 * number of bits to shift the DBAM register to extract the proper CSROW
2061 * field.
2062 */
Borislav Petkov1433eb92009-10-21 13:44:36 +02002063 cs_mode = (pvt->dbam0 >> ((csrow_nr / 2) * 4)) & 0xF;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002064
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01002065 nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002066
2067 /*
2068 * If dual channel then double the memory size of single channel.
2069 * Channel count is 1 or 2
2070 */
2071 nr_pages <<= (pvt->channel_count - 1);
2072
Borislav Petkov1433eb92009-10-21 13:44:36 +02002073 debugf0(" (csrow=%d) DBAM map index= %d\n", csrow_nr, cs_mode);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002074 debugf0(" nr_pages= %u channel-count = %d\n",
2075 nr_pages, pvt->channel_count);
2076
2077 return nr_pages;
2078}
2079
2080/*
2081 * Initialize the array of csrow attribute instances, based on the values
2082 * from pci config hardware registers.
2083 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02002084static int init_csrows(struct mem_ctl_info *mci)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002085{
2086 struct csrow_info *csrow;
Borislav Petkov2299ef72010-10-15 17:44:04 +02002087 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002088 u64 input_addr_min, input_addr_max, sys_addr, base, mask;
Borislav Petkov2299ef72010-10-15 17:44:04 +02002089 u32 val;
Borislav Petkov6ba5dcd2009-10-13 19:26:55 +02002090 int i, empty = 1;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002091
Borislav Petkova97fa682010-12-23 14:07:18 +01002092 amd64_read_pci_cfg(pvt->F3, NBCFG, &val);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002093
Borislav Petkov2299ef72010-10-15 17:44:04 +02002094 pvt->nbcfg = val;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002095
Borislav Petkov2299ef72010-10-15 17:44:04 +02002096 debugf0("node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
2097 pvt->mc_node_id, val,
Borislav Petkova97fa682010-12-23 14:07:18 +01002098 !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
Doug Thompson0ec449e2009-04-27 19:41:25 +02002099
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002100 for_each_chip_select(i, 0, pvt) {
Doug Thompson0ec449e2009-04-27 19:41:25 +02002101 csrow = &mci->csrows[i];
2102
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002103 if (!csrow_enabled(i, 0, pvt)) {
Doug Thompson0ec449e2009-04-27 19:41:25 +02002104 debugf1("----CSROW %d EMPTY for node %d\n", i,
2105 pvt->mc_node_id);
2106 continue;
2107 }
2108
2109 debugf1("----CSROW %d VALID for MC node %d\n",
2110 i, pvt->mc_node_id);
2111
2112 empty = 0;
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01002113 csrow->nr_pages = amd64_csrow_nr_pages(pvt, 0, i);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002114 find_csrow_limits(mci, i, &input_addr_min, &input_addr_max);
2115 sys_addr = input_addr_to_sys_addr(mci, input_addr_min);
2116 csrow->first_page = (u32) (sys_addr >> PAGE_SHIFT);
2117 sys_addr = input_addr_to_sys_addr(mci, input_addr_max);
2118 csrow->last_page = (u32) (sys_addr >> PAGE_SHIFT);
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002119
2120 get_cs_base_and_mask(pvt, i, 0, &base, &mask);
2121 csrow->page_mask = ~mask;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002122 /* 8 bytes of resolution */
2123
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002124 csrow->mtype = amd64_determine_memory_type(pvt, i);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002125
2126 debugf1(" for MC node %d csrow %d:\n", pvt->mc_node_id, i);
2127 debugf1(" input_addr_min: 0x%lx input_addr_max: 0x%lx\n",
2128 (unsigned long)input_addr_min,
2129 (unsigned long)input_addr_max);
2130 debugf1(" sys_addr: 0x%lx page_mask: 0x%lx\n",
2131 (unsigned long)sys_addr, csrow->page_mask);
2132 debugf1(" nr_pages: %u first_page: 0x%lx "
2133 "last_page: 0x%lx\n",
2134 (unsigned)csrow->nr_pages,
2135 csrow->first_page, csrow->last_page);
2136
2137 /*
2138 * determine whether CHIPKILL or JUST ECC or NO ECC is operating
2139 */
Borislav Petkova97fa682010-12-23 14:07:18 +01002140 if (pvt->nbcfg & NBCFG_ECC_ENABLE)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002141 csrow->edac_mode =
Borislav Petkova97fa682010-12-23 14:07:18 +01002142 (pvt->nbcfg & NBCFG_CHIPKILL) ?
Doug Thompson0ec449e2009-04-27 19:41:25 +02002143 EDAC_S4ECD4ED : EDAC_SECDED;
2144 else
2145 csrow->edac_mode = EDAC_NONE;
2146 }
2147
2148 return empty;
2149}
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002150
Borislav Petkov06724532009-09-16 13:05:46 +02002151/* get all cores on this DCT */
Borislav Petkovb487c332011-02-21 18:55:00 +01002152static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, unsigned nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02002153{
Borislav Petkov06724532009-09-16 13:05:46 +02002154 int cpu;
Doug Thompsonf9431992009-04-27 19:46:08 +02002155
Borislav Petkov06724532009-09-16 13:05:46 +02002156 for_each_online_cpu(cpu)
2157 if (amd_get_nb_id(cpu) == nid)
2158 cpumask_set_cpu(cpu, mask);
Doug Thompsonf9431992009-04-27 19:46:08 +02002159}
2160
2161/* check MCG_CTL on all the cpus on this node */
Borislav Petkovb487c332011-02-21 18:55:00 +01002162static bool amd64_nb_mce_bank_enabled_on_node(unsigned nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02002163{
Rusty Russellba578cb2009-11-03 14:56:35 +10302164 cpumask_var_t mask;
Borislav Petkov50542252009-12-11 18:14:40 +01002165 int cpu, nbe;
Borislav Petkov06724532009-09-16 13:05:46 +02002166 bool ret = false;
Doug Thompsonf9431992009-04-27 19:46:08 +02002167
Rusty Russellba578cb2009-11-03 14:56:35 +10302168 if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002169 amd64_warn("%s: Error allocating mask\n", __func__);
Rusty Russellba578cb2009-11-03 14:56:35 +10302170 return false;
2171 }
Borislav Petkov06724532009-09-16 13:05:46 +02002172
Rusty Russellba578cb2009-11-03 14:56:35 +10302173 get_cpus_on_this_dct_cpumask(mask, nid);
Borislav Petkov06724532009-09-16 13:05:46 +02002174
Rusty Russellba578cb2009-11-03 14:56:35 +10302175 rdmsr_on_cpus(mask, MSR_IA32_MCG_CTL, msrs);
Borislav Petkov06724532009-09-16 13:05:46 +02002176
Rusty Russellba578cb2009-11-03 14:56:35 +10302177 for_each_cpu(cpu, mask) {
Borislav Petkov50542252009-12-11 18:14:40 +01002178 struct msr *reg = per_cpu_ptr(msrs, cpu);
Borislav Petkov5980bb92011-01-07 16:26:49 +01002179 nbe = reg->l & MSR_MCGCTL_NBE;
Borislav Petkov06724532009-09-16 13:05:46 +02002180
2181 debugf0("core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n",
Borislav Petkov50542252009-12-11 18:14:40 +01002182 cpu, reg->q,
Borislav Petkov06724532009-09-16 13:05:46 +02002183 (nbe ? "enabled" : "disabled"));
2184
2185 if (!nbe)
2186 goto out;
Borislav Petkov06724532009-09-16 13:05:46 +02002187 }
2188 ret = true;
2189
2190out:
Rusty Russellba578cb2009-11-03 14:56:35 +10302191 free_cpumask_var(mask);
Doug Thompsonf9431992009-04-27 19:46:08 +02002192 return ret;
2193}
2194
Borislav Petkov2299ef72010-10-15 17:44:04 +02002195static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002196{
2197 cpumask_var_t cmask;
Borislav Petkov50542252009-12-11 18:14:40 +01002198 int cpu;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002199
2200 if (!zalloc_cpumask_var(&cmask, GFP_KERNEL)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002201 amd64_warn("%s: error allocating mask\n", __func__);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002202 return false;
2203 }
2204
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002205 get_cpus_on_this_dct_cpumask(cmask, nid);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002206
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002207 rdmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
2208
2209 for_each_cpu(cpu, cmask) {
2210
Borislav Petkov50542252009-12-11 18:14:40 +01002211 struct msr *reg = per_cpu_ptr(msrs, cpu);
2212
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002213 if (on) {
Borislav Petkov5980bb92011-01-07 16:26:49 +01002214 if (reg->l & MSR_MCGCTL_NBE)
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002215 s->flags.nb_mce_enable = 1;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002216
Borislav Petkov5980bb92011-01-07 16:26:49 +01002217 reg->l |= MSR_MCGCTL_NBE;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002218 } else {
2219 /*
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002220 * Turn off NB MCE reporting only when it was off before
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002221 */
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002222 if (!s->flags.nb_mce_enable)
Borislav Petkov5980bb92011-01-07 16:26:49 +01002223 reg->l &= ~MSR_MCGCTL_NBE;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002224 }
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002225 }
2226 wrmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
2227
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002228 free_cpumask_var(cmask);
2229
2230 return 0;
2231}
2232
Borislav Petkov2299ef72010-10-15 17:44:04 +02002233static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
2234 struct pci_dev *F3)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002235{
Borislav Petkov2299ef72010-10-15 17:44:04 +02002236 bool ret = true;
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002237 u32 value, mask = 0x3; /* UECC/CECC enable */
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002238
Borislav Petkov2299ef72010-10-15 17:44:04 +02002239 if (toggle_ecc_err_reporting(s, nid, ON)) {
2240 amd64_warn("Error enabling ECC reporting over MCGCTL!\n");
2241 return false;
2242 }
2243
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002244 amd64_read_pci_cfg(F3, NBCTL, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002245
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002246 s->old_nbctl = value & mask;
2247 s->nbctl_valid = true;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002248
2249 value |= mask;
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002250 amd64_write_pci_cfg(F3, NBCTL, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002251
Borislav Petkova97fa682010-12-23 14:07:18 +01002252 amd64_read_pci_cfg(F3, NBCFG, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002253
Borislav Petkova97fa682010-12-23 14:07:18 +01002254 debugf0("1: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
2255 nid, value, !!(value & NBCFG_ECC_ENABLE));
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002256
Borislav Petkova97fa682010-12-23 14:07:18 +01002257 if (!(value & NBCFG_ECC_ENABLE)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002258 amd64_warn("DRAM ECC disabled on this node, enabling...\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002259
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002260 s->flags.nb_ecc_prev = 0;
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002261
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002262 /* Attempt to turn on DRAM ECC Enable */
Borislav Petkova97fa682010-12-23 14:07:18 +01002263 value |= NBCFG_ECC_ENABLE;
2264 amd64_write_pci_cfg(F3, NBCFG, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002265
Borislav Petkova97fa682010-12-23 14:07:18 +01002266 amd64_read_pci_cfg(F3, NBCFG, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002267
Borislav Petkova97fa682010-12-23 14:07:18 +01002268 if (!(value & NBCFG_ECC_ENABLE)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002269 amd64_warn("Hardware rejected DRAM ECC enable,"
2270 "check memory DIMM configuration.\n");
Borislav Petkov2299ef72010-10-15 17:44:04 +02002271 ret = false;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002272 } else {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002273 amd64_info("Hardware accepted DRAM ECC Enable\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002274 }
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002275 } else {
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002276 s->flags.nb_ecc_prev = 1;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002277 }
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002278
Borislav Petkova97fa682010-12-23 14:07:18 +01002279 debugf0("2: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
2280 nid, value, !!(value & NBCFG_ECC_ENABLE));
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002281
Borislav Petkov2299ef72010-10-15 17:44:04 +02002282 return ret;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002283}
2284
Borislav Petkov360b7f32010-10-15 19:25:38 +02002285static void restore_ecc_error_reporting(struct ecc_settings *s, u8 nid,
2286 struct pci_dev *F3)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002287{
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002288 u32 value, mask = 0x3; /* UECC/CECC enable */
2289
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002290
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002291 if (!s->nbctl_valid)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002292 return;
2293
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002294 amd64_read_pci_cfg(F3, NBCTL, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002295 value &= ~mask;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002296 value |= s->old_nbctl;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002297
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002298 amd64_write_pci_cfg(F3, NBCTL, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002299
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002300 /* restore previous BIOS DRAM ECC "off" setting we force-enabled */
2301 if (!s->flags.nb_ecc_prev) {
Borislav Petkova97fa682010-12-23 14:07:18 +01002302 amd64_read_pci_cfg(F3, NBCFG, &value);
2303 value &= ~NBCFG_ECC_ENABLE;
2304 amd64_write_pci_cfg(F3, NBCFG, value);
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002305 }
2306
2307 /* restore the NB Enable MCGCTL bit */
Borislav Petkov2299ef72010-10-15 17:44:04 +02002308 if (toggle_ecc_err_reporting(s, nid, OFF))
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002309 amd64_warn("Error restoring NB MCGCTL settings!\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002310}
2311
Doug Thompsonf9431992009-04-27 19:46:08 +02002312/*
Borislav Petkov2299ef72010-10-15 17:44:04 +02002313 * EDAC requires that the BIOS have ECC enabled before
2314 * taking over the processing of ECC errors. A command line
2315 * option allows to force-enable hardware ECC later in
2316 * enable_ecc_error_reporting().
Doug Thompsonf9431992009-04-27 19:46:08 +02002317 */
Borislav Petkovcab4d272010-02-11 17:15:57 +01002318static const char *ecc_msg =
2319 "ECC disabled in the BIOS or no ECC capability, module will not load.\n"
2320 " Either enable ECC checking or force module loading by setting "
2321 "'ecc_enable_override'.\n"
2322 " (Note that use of the override may cause unknown side effects.)\n";
Borislav Petkovbe3468e2009-08-05 15:47:22 +02002323
Borislav Petkov2299ef72010-10-15 17:44:04 +02002324static bool ecc_enabled(struct pci_dev *F3, u8 nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02002325{
2326 u32 value;
Borislav Petkov2299ef72010-10-15 17:44:04 +02002327 u8 ecc_en = 0;
Borislav Petkov06724532009-09-16 13:05:46 +02002328 bool nb_mce_en = false;
Doug Thompsonf9431992009-04-27 19:46:08 +02002329
Borislav Petkova97fa682010-12-23 14:07:18 +01002330 amd64_read_pci_cfg(F3, NBCFG, &value);
Doug Thompsonf9431992009-04-27 19:46:08 +02002331
Borislav Petkova97fa682010-12-23 14:07:18 +01002332 ecc_en = !!(value & NBCFG_ECC_ENABLE);
Borislav Petkov2299ef72010-10-15 17:44:04 +02002333 amd64_info("DRAM ECC %s.\n", (ecc_en ? "enabled" : "disabled"));
Doug Thompsonf9431992009-04-27 19:46:08 +02002334
Borislav Petkov2299ef72010-10-15 17:44:04 +02002335 nb_mce_en = amd64_nb_mce_bank_enabled_on_node(nid);
Borislav Petkov06724532009-09-16 13:05:46 +02002336 if (!nb_mce_en)
Borislav Petkov2299ef72010-10-15 17:44:04 +02002337 amd64_notice("NB MCE bank disabled, set MSR "
2338 "0x%08x[4] on node %d to enable.\n",
2339 MSR_IA32_MCG_CTL, nid);
Doug Thompsonf9431992009-04-27 19:46:08 +02002340
Borislav Petkov2299ef72010-10-15 17:44:04 +02002341 if (!ecc_en || !nb_mce_en) {
2342 amd64_notice("%s", ecc_msg);
2343 return false;
Borislav Petkov43f5e682009-12-21 18:55:18 +01002344 }
Borislav Petkov2299ef72010-10-15 17:44:04 +02002345 return true;
Doug Thompsonf9431992009-04-27 19:46:08 +02002346}
2347
Doug Thompson7d6034d2009-04-27 20:01:01 +02002348struct mcidev_sysfs_attribute sysfs_attrs[ARRAY_SIZE(amd64_dbg_attrs) +
2349 ARRAY_SIZE(amd64_inj_attrs) +
2350 1];
2351
2352struct mcidev_sysfs_attribute terminator = { .attr = { .name = NULL } };
2353
Borislav Petkov360b7f32010-10-15 19:25:38 +02002354static void set_mc_sysfs_attrs(struct mem_ctl_info *mci)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002355{
2356 unsigned int i = 0, j = 0;
2357
2358 for (; i < ARRAY_SIZE(amd64_dbg_attrs); i++)
2359 sysfs_attrs[i] = amd64_dbg_attrs[i];
2360
Borislav Petkova135cef2010-11-26 19:24:44 +01002361 if (boot_cpu_data.x86 >= 0x10)
2362 for (j = 0; j < ARRAY_SIZE(amd64_inj_attrs); j++, i++)
2363 sysfs_attrs[i] = amd64_inj_attrs[j];
Doug Thompson7d6034d2009-04-27 20:01:01 +02002364
2365 sysfs_attrs[i] = terminator;
2366
2367 mci->mc_driver_sysfs_attributes = sysfs_attrs;
2368}
2369
Borislav Petkovdf71a052011-01-19 18:15:10 +01002370static void setup_mci_misc_attrs(struct mem_ctl_info *mci,
2371 struct amd64_family_type *fam)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002372{
2373 struct amd64_pvt *pvt = mci->pvt_info;
2374
2375 mci->mtype_cap = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2;
2376 mci->edac_ctl_cap = EDAC_FLAG_NONE;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002377
Borislav Petkov5980bb92011-01-07 16:26:49 +01002378 if (pvt->nbcap & NBCAP_SECDED)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002379 mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
2380
Borislav Petkov5980bb92011-01-07 16:26:49 +01002381 if (pvt->nbcap & NBCAP_CHIPKILL)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002382 mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
2383
2384 mci->edac_cap = amd64_determine_edac_cap(pvt);
2385 mci->mod_name = EDAC_MOD_STR;
2386 mci->mod_ver = EDAC_AMD64_VERSION;
Borislav Petkovdf71a052011-01-19 18:15:10 +01002387 mci->ctl_name = fam->ctl_name;
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002388 mci->dev_name = pci_name(pvt->F2);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002389 mci->ctl_page_to_phys = NULL;
2390
Doug Thompson7d6034d2009-04-27 20:01:01 +02002391 /* memory scrubber interface */
2392 mci->set_sdram_scrub_rate = amd64_set_scrub_rate;
2393 mci->get_sdram_scrub_rate = amd64_get_scrub_rate;
2394}
2395
Borislav Petkov0092b202010-10-01 19:20:05 +02002396/*
2397 * returns a pointer to the family descriptor on success, NULL otherwise.
2398 */
2399static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)
Borislav Petkov395ae782010-10-01 18:38:19 +02002400{
Borislav Petkov0092b202010-10-01 19:20:05 +02002401 u8 fam = boot_cpu_data.x86;
2402 struct amd64_family_type *fam_type = NULL;
2403
2404 switch (fam) {
Borislav Petkov395ae782010-10-01 18:38:19 +02002405 case 0xf:
Borislav Petkov0092b202010-10-01 19:20:05 +02002406 fam_type = &amd64_family_types[K8_CPUS];
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002407 pvt->ops = &amd64_family_types[K8_CPUS].ops;
Borislav Petkov395ae782010-10-01 18:38:19 +02002408 break;
Borislav Petkovdf71a052011-01-19 18:15:10 +01002409
Borislav Petkov395ae782010-10-01 18:38:19 +02002410 case 0x10:
Borislav Petkov0092b202010-10-01 19:20:05 +02002411 fam_type = &amd64_family_types[F10_CPUS];
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002412 pvt->ops = &amd64_family_types[F10_CPUS].ops;
Borislav Petkovdf71a052011-01-19 18:15:10 +01002413 break;
2414
2415 case 0x15:
2416 fam_type = &amd64_family_types[F15_CPUS];
2417 pvt->ops = &amd64_family_types[F15_CPUS].ops;
Borislav Petkov395ae782010-10-01 18:38:19 +02002418 break;
2419
2420 default:
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002421 amd64_err("Unsupported family!\n");
Borislav Petkov0092b202010-10-01 19:20:05 +02002422 return NULL;
Borislav Petkov395ae782010-10-01 18:38:19 +02002423 }
Borislav Petkov0092b202010-10-01 19:20:05 +02002424
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002425 pvt->ext_model = boot_cpu_data.x86_model >> 4;
2426
Borislav Petkovdf71a052011-01-19 18:15:10 +01002427 amd64_info("%s %sdetected (node %d).\n", fam_type->ctl_name,
Borislav Petkov0092b202010-10-01 19:20:05 +02002428 (fam == 0xf ?
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002429 (pvt->ext_model >= K8_REV_F ? "revF or later "
2430 : "revE or earlier ")
2431 : ""), pvt->mc_node_id);
Borislav Petkov0092b202010-10-01 19:20:05 +02002432 return fam_type;
Borislav Petkov395ae782010-10-01 18:38:19 +02002433}
2434
Borislav Petkov2299ef72010-10-15 17:44:04 +02002435static int amd64_init_one_instance(struct pci_dev *F2)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002436{
2437 struct amd64_pvt *pvt = NULL;
Borislav Petkov0092b202010-10-01 19:20:05 +02002438 struct amd64_family_type *fam_type = NULL;
Borislav Petkov360b7f32010-10-15 19:25:38 +02002439 struct mem_ctl_info *mci = NULL;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002440 int err = 0, ret;
Borislav Petkov360b7f32010-10-15 19:25:38 +02002441 u8 nid = get_node_id(F2);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002442
2443 ret = -ENOMEM;
2444 pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
2445 if (!pvt)
Borislav Petkov360b7f32010-10-15 19:25:38 +02002446 goto err_ret;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002447
Borislav Petkov360b7f32010-10-15 19:25:38 +02002448 pvt->mc_node_id = nid;
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002449 pvt->F2 = F2;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002450
Borislav Petkov395ae782010-10-01 18:38:19 +02002451 ret = -EINVAL;
Borislav Petkov0092b202010-10-01 19:20:05 +02002452 fam_type = amd64_per_family_init(pvt);
2453 if (!fam_type)
Borislav Petkov395ae782010-10-01 18:38:19 +02002454 goto err_free;
2455
Doug Thompson7d6034d2009-04-27 20:01:01 +02002456 ret = -ENODEV;
Borislav Petkov360b7f32010-10-15 19:25:38 +02002457 err = reserve_mc_sibling_devs(pvt, fam_type->f1_id, fam_type->f3_id);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002458 if (err)
2459 goto err_free;
2460
Borislav Petkov360b7f32010-10-15 19:25:38 +02002461 read_mc_regs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002462
Doug Thompson7d6034d2009-04-27 20:01:01 +02002463 /*
2464 * We need to determine how many memory channels there are. Then use
2465 * that information for calculating the size of the dynamic instance
Borislav Petkov360b7f32010-10-15 19:25:38 +02002466 * tables in the 'mci' structure.
Doug Thompson7d6034d2009-04-27 20:01:01 +02002467 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02002468 ret = -EINVAL;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002469 pvt->channel_count = pvt->ops->early_channel_count(pvt);
2470 if (pvt->channel_count < 0)
Borislav Petkov360b7f32010-10-15 19:25:38 +02002471 goto err_siblings;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002472
2473 ret = -ENOMEM;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002474 mci = edac_mc_alloc(0, pvt->csels[0].b_cnt, pvt->channel_count, nid);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002475 if (!mci)
Borislav Petkov360b7f32010-10-15 19:25:38 +02002476 goto err_siblings;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002477
2478 mci->pvt_info = pvt;
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002479 mci->dev = &pvt->F2->dev;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002480
Borislav Petkovdf71a052011-01-19 18:15:10 +01002481 setup_mci_misc_attrs(mci, fam_type);
Borislav Petkov360b7f32010-10-15 19:25:38 +02002482
2483 if (init_csrows(mci))
Doug Thompson7d6034d2009-04-27 20:01:01 +02002484 mci->edac_cap = EDAC_FLAG_NONE;
2485
Borislav Petkov360b7f32010-10-15 19:25:38 +02002486 set_mc_sysfs_attrs(mci);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002487
2488 ret = -ENODEV;
2489 if (edac_mc_add_mc(mci)) {
2490 debugf1("failed edac_mc_add_mc()\n");
2491 goto err_add_mc;
2492 }
2493
Borislav Petkov549d0422009-07-24 13:51:42 +02002494 /* register stuff with EDAC MCE */
2495 if (report_gart_errors)
2496 amd_report_gart_errors(true);
2497
2498 amd_register_ecc_decoder(amd64_decode_bus_error);
2499
Borislav Petkov360b7f32010-10-15 19:25:38 +02002500 mcis[nid] = mci;
2501
2502 atomic_inc(&drv_instances);
2503
Doug Thompson7d6034d2009-04-27 20:01:01 +02002504 return 0;
2505
2506err_add_mc:
2507 edac_mc_free(mci);
2508
Borislav Petkov360b7f32010-10-15 19:25:38 +02002509err_siblings:
2510 free_mc_sibling_devs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002511
Borislav Petkov360b7f32010-10-15 19:25:38 +02002512err_free:
2513 kfree(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002514
Borislav Petkov360b7f32010-10-15 19:25:38 +02002515err_ret:
Doug Thompson7d6034d2009-04-27 20:01:01 +02002516 return ret;
2517}
2518
Borislav Petkov2299ef72010-10-15 17:44:04 +02002519static int __devinit amd64_probe_one_instance(struct pci_dev *pdev,
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002520 const struct pci_device_id *mc_type)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002521{
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002522 u8 nid = get_node_id(pdev);
Borislav Petkov2299ef72010-10-15 17:44:04 +02002523 struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002524 struct ecc_settings *s;
Borislav Petkov2299ef72010-10-15 17:44:04 +02002525 int ret = 0;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002526
Doug Thompson7d6034d2009-04-27 20:01:01 +02002527 ret = pci_enable_device(pdev);
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002528 if (ret < 0) {
Doug Thompson7d6034d2009-04-27 20:01:01 +02002529 debugf0("ret=%d\n", ret);
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002530 return -EIO;
2531 }
2532
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002533 ret = -ENOMEM;
2534 s = kzalloc(sizeof(struct ecc_settings), GFP_KERNEL);
2535 if (!s)
Borislav Petkov2299ef72010-10-15 17:44:04 +02002536 goto err_out;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002537
2538 ecc_stngs[nid] = s;
2539
Borislav Petkov2299ef72010-10-15 17:44:04 +02002540 if (!ecc_enabled(F3, nid)) {
2541 ret = -ENODEV;
2542
2543 if (!ecc_enable_override)
2544 goto err_enable;
2545
2546 amd64_warn("Forcing ECC on!\n");
2547
2548 if (!enable_ecc_error_reporting(s, nid, F3))
2549 goto err_enable;
2550 }
2551
2552 ret = amd64_init_one_instance(pdev);
Borislav Petkov360b7f32010-10-15 19:25:38 +02002553 if (ret < 0) {
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002554 amd64_err("Error probing instance: %d\n", nid);
Borislav Petkov360b7f32010-10-15 19:25:38 +02002555 restore_ecc_error_reporting(s, nid, F3);
2556 }
Doug Thompson7d6034d2009-04-27 20:01:01 +02002557
2558 return ret;
Borislav Petkov2299ef72010-10-15 17:44:04 +02002559
2560err_enable:
2561 kfree(s);
2562 ecc_stngs[nid] = NULL;
2563
2564err_out:
2565 return ret;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002566}
2567
2568static void __devexit amd64_remove_one_instance(struct pci_dev *pdev)
2569{
2570 struct mem_ctl_info *mci;
2571 struct amd64_pvt *pvt;
Borislav Petkov360b7f32010-10-15 19:25:38 +02002572 u8 nid = get_node_id(pdev);
2573 struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
2574 struct ecc_settings *s = ecc_stngs[nid];
Doug Thompson7d6034d2009-04-27 20:01:01 +02002575
2576 /* Remove from EDAC CORE tracking list */
2577 mci = edac_mc_del_mc(&pdev->dev);
2578 if (!mci)
2579 return;
2580
2581 pvt = mci->pvt_info;
2582
Borislav Petkov360b7f32010-10-15 19:25:38 +02002583 restore_ecc_error_reporting(s, nid, F3);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002584
Borislav Petkov360b7f32010-10-15 19:25:38 +02002585 free_mc_sibling_devs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002586
Borislav Petkov549d0422009-07-24 13:51:42 +02002587 /* unregister from EDAC MCE */
2588 amd_report_gart_errors(false);
2589 amd_unregister_ecc_decoder(amd64_decode_bus_error);
2590
Borislav Petkov360b7f32010-10-15 19:25:38 +02002591 kfree(ecc_stngs[nid]);
2592 ecc_stngs[nid] = NULL;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002593
Doug Thompson7d6034d2009-04-27 20:01:01 +02002594 /* Free the EDAC CORE resources */
Borislav Petkov8f68ed92009-12-21 15:15:59 +01002595 mci->pvt_info = NULL;
Borislav Petkov360b7f32010-10-15 19:25:38 +02002596 mcis[nid] = NULL;
Borislav Petkov8f68ed92009-12-21 15:15:59 +01002597
2598 kfree(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002599 edac_mc_free(mci);
2600}
2601
2602/*
2603 * This table is part of the interface for loading drivers for PCI devices. The
2604 * PCI core identifies what devices are on a system during boot, and then
2605 * inquiry this table to see if this driver is for a given device found.
2606 */
2607static const struct pci_device_id amd64_pci_table[] __devinitdata = {
2608 {
2609 .vendor = PCI_VENDOR_ID_AMD,
2610 .device = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL,
2611 .subvendor = PCI_ANY_ID,
2612 .subdevice = PCI_ANY_ID,
2613 .class = 0,
2614 .class_mask = 0,
Doug Thompson7d6034d2009-04-27 20:01:01 +02002615 },
2616 {
2617 .vendor = PCI_VENDOR_ID_AMD,
2618 .device = PCI_DEVICE_ID_AMD_10H_NB_DRAM,
2619 .subvendor = PCI_ANY_ID,
2620 .subdevice = PCI_ANY_ID,
2621 .class = 0,
2622 .class_mask = 0,
Doug Thompson7d6034d2009-04-27 20:01:01 +02002623 },
Borislav Petkovdf71a052011-01-19 18:15:10 +01002624 {
2625 .vendor = PCI_VENDOR_ID_AMD,
2626 .device = PCI_DEVICE_ID_AMD_15H_NB_F2,
2627 .subvendor = PCI_ANY_ID,
2628 .subdevice = PCI_ANY_ID,
2629 .class = 0,
2630 .class_mask = 0,
2631 },
2632
Doug Thompson7d6034d2009-04-27 20:01:01 +02002633 {0, }
2634};
2635MODULE_DEVICE_TABLE(pci, amd64_pci_table);
2636
2637static struct pci_driver amd64_pci_driver = {
2638 .name = EDAC_MOD_STR,
Borislav Petkov2299ef72010-10-15 17:44:04 +02002639 .probe = amd64_probe_one_instance,
Doug Thompson7d6034d2009-04-27 20:01:01 +02002640 .remove = __devexit_p(amd64_remove_one_instance),
2641 .id_table = amd64_pci_table,
2642};
2643
Borislav Petkov360b7f32010-10-15 19:25:38 +02002644static void setup_pci_device(void)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002645{
2646 struct mem_ctl_info *mci;
2647 struct amd64_pvt *pvt;
2648
2649 if (amd64_ctl_pci)
2650 return;
2651
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002652 mci = mcis[0];
Doug Thompson7d6034d2009-04-27 20:01:01 +02002653 if (mci) {
2654
2655 pvt = mci->pvt_info;
2656 amd64_ctl_pci =
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002657 edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002658
2659 if (!amd64_ctl_pci) {
2660 pr_warning("%s(): Unable to create PCI control\n",
2661 __func__);
2662
2663 pr_warning("%s(): PCI error report via EDAC not set\n",
2664 __func__);
2665 }
2666 }
2667}
2668
2669static int __init amd64_edac_init(void)
2670{
Borislav Petkov360b7f32010-10-15 19:25:38 +02002671 int err = -ENODEV;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002672
Borislav Petkovdf71a052011-01-19 18:15:10 +01002673 printk(KERN_INFO "AMD64 EDAC driver v%s\n", EDAC_AMD64_VERSION);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002674
2675 opstate_init();
2676
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +02002677 if (amd_cache_northbridges() < 0)
Borislav Petkov56b34b92009-12-21 18:13:01 +01002678 goto err_ret;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002679
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002680 err = -ENOMEM;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002681 mcis = kzalloc(amd_nb_num() * sizeof(mcis[0]), GFP_KERNEL);
2682 ecc_stngs = kzalloc(amd_nb_num() * sizeof(ecc_stngs[0]), GFP_KERNEL);
Borislav Petkov360b7f32010-10-15 19:25:38 +02002683 if (!(mcis && ecc_stngs))
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002684 goto err_ret;
2685
Borislav Petkov50542252009-12-11 18:14:40 +01002686 msrs = msrs_alloc();
Borislav Petkov56b34b92009-12-21 18:13:01 +01002687 if (!msrs)
Borislav Petkov360b7f32010-10-15 19:25:38 +02002688 goto err_free;
Borislav Petkov50542252009-12-11 18:14:40 +01002689
Doug Thompson7d6034d2009-04-27 20:01:01 +02002690 err = pci_register_driver(&amd64_pci_driver);
2691 if (err)
Borislav Petkov56b34b92009-12-21 18:13:01 +01002692 goto err_pci;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002693
Borislav Petkov56b34b92009-12-21 18:13:01 +01002694 err = -ENODEV;
Borislav Petkov360b7f32010-10-15 19:25:38 +02002695 if (!atomic_read(&drv_instances))
2696 goto err_no_instances;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002697
Borislav Petkov360b7f32010-10-15 19:25:38 +02002698 setup_pci_device();
2699 return 0;
Borislav Petkov56b34b92009-12-21 18:13:01 +01002700
Borislav Petkov360b7f32010-10-15 19:25:38 +02002701err_no_instances:
Doug Thompson7d6034d2009-04-27 20:01:01 +02002702 pci_unregister_driver(&amd64_pci_driver);
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002703
Borislav Petkov56b34b92009-12-21 18:13:01 +01002704err_pci:
2705 msrs_free(msrs);
2706 msrs = NULL;
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002707
Borislav Petkov360b7f32010-10-15 19:25:38 +02002708err_free:
2709 kfree(mcis);
2710 mcis = NULL;
2711
2712 kfree(ecc_stngs);
2713 ecc_stngs = NULL;
2714
Borislav Petkov56b34b92009-12-21 18:13:01 +01002715err_ret:
Doug Thompson7d6034d2009-04-27 20:01:01 +02002716 return err;
2717}
2718
2719static void __exit amd64_edac_exit(void)
2720{
2721 if (amd64_ctl_pci)
2722 edac_pci_release_generic_ctl(amd64_ctl_pci);
2723
2724 pci_unregister_driver(&amd64_pci_driver);
Borislav Petkov50542252009-12-11 18:14:40 +01002725
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002726 kfree(ecc_stngs);
2727 ecc_stngs = NULL;
2728
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002729 kfree(mcis);
2730 mcis = NULL;
2731
Borislav Petkov50542252009-12-11 18:14:40 +01002732 msrs_free(msrs);
2733 msrs = NULL;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002734}
2735
2736module_init(amd64_edac_init);
2737module_exit(amd64_edac_exit);
2738
2739MODULE_LICENSE("GPL");
2740MODULE_AUTHOR("SoftwareBitMaker: Doug Thompson, "
2741 "Dave Peterson, Thayne Harbaugh");
2742MODULE_DESCRIPTION("MC support for AMD64 memory controllers - "
2743 EDAC_AMD64_VERSION);
2744
2745module_param(edac_op_state, int, 0444);
2746MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");