blob: 1b8fa7a905eb6aefee7b55393937931466998a3d [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 if (intlv_shift == 0) {
625 debugf1(" InputAddr 0x%lx translates to DramAddr of "
626 "same value\n", (unsigned long)input_addr);
627
628 return input_addr;
629 }
630
Borislav Petkovf678b8c2010-12-13 19:21:07 +0100631 bits = ((input_addr & GENMASK(12, 35)) << intlv_shift) +
632 (input_addr & 0xfff);
Doug Thompson93c2df52009-05-04 20:46:50 +0200633
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200634 intlv_sel = dram_intlv_sel(pvt, node_id) & ((1 << intlv_shift) - 1);
Doug Thompson93c2df52009-05-04 20:46:50 +0200635 dram_addr = bits + (intlv_sel << 12);
636
637 debugf1("InputAddr 0x%lx translates to DramAddr 0x%lx "
638 "(%d node interleave bits)\n", (unsigned long)input_addr,
639 (unsigned long)dram_addr, intlv_shift);
640
641 return dram_addr;
642}
643
644/*
645 * @dram_addr is a DramAddr that maps to the node represented by mci. Convert
646 * @dram_addr to a SysAddr.
647 */
648static u64 dram_addr_to_sys_addr(struct mem_ctl_info *mci, u64 dram_addr)
649{
650 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200651 u64 hole_base, hole_offset, hole_size, base, sys_addr;
Doug Thompson93c2df52009-05-04 20:46:50 +0200652 int ret = 0;
653
654 ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
655 &hole_size);
656 if (!ret) {
657 if ((dram_addr >= hole_base) &&
658 (dram_addr < (hole_base + hole_size))) {
659 sys_addr = dram_addr + hole_offset;
660
661 debugf1("using DHAR to translate DramAddr 0x%lx to "
662 "SysAddr 0x%lx\n", (unsigned long)dram_addr,
663 (unsigned long)sys_addr);
664
665 return sys_addr;
666 }
667 }
668
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200669 base = get_dram_base(pvt, pvt->mc_node_id);
Doug Thompson93c2df52009-05-04 20:46:50 +0200670 sys_addr = dram_addr + base;
671
672 /*
673 * The sys_addr we have computed up to this point is a 40-bit value
674 * because the k8 deals with 40-bit values. However, the value we are
675 * supposed to return is a full 64-bit physical address. The AMD
676 * x86-64 architecture specifies that the most significant implemented
677 * address bit through bit 63 of a physical address must be either all
678 * 0s or all 1s. Therefore we sign-extend the 40-bit sys_addr to a
679 * 64-bit value below. See section 3.4.2 of AMD publication 24592:
680 * AMD x86-64 Architecture Programmer's Manual Volume 1 Application
681 * Programming.
682 */
683 sys_addr |= ~((sys_addr & (1ull << 39)) - 1);
684
685 debugf1(" Node %d, DramAddr 0x%lx to SysAddr 0x%lx\n",
686 pvt->mc_node_id, (unsigned long)dram_addr,
687 (unsigned long)sys_addr);
688
689 return sys_addr;
690}
691
692/*
693 * @input_addr is an InputAddr associated with the node given by mci. Translate
694 * @input_addr to a SysAddr.
695 */
696static inline u64 input_addr_to_sys_addr(struct mem_ctl_info *mci,
697 u64 input_addr)
698{
699 return dram_addr_to_sys_addr(mci,
700 input_addr_to_dram_addr(mci, input_addr));
701}
702
703/*
704 * Find the minimum and maximum InputAddr values that map to the given @csrow.
705 * Pass back these values in *input_addr_min and *input_addr_max.
706 */
707static void find_csrow_limits(struct mem_ctl_info *mci, int csrow,
708 u64 *input_addr_min, u64 *input_addr_max)
709{
710 struct amd64_pvt *pvt;
711 u64 base, mask;
712
713 pvt = mci->pvt_info;
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100714 BUG_ON((csrow < 0) || (csrow >= pvt->csels[0].b_cnt));
Doug Thompson93c2df52009-05-04 20:46:50 +0200715
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100716 get_cs_base_and_mask(pvt, csrow, 0, &base, &mask);
Doug Thompson93c2df52009-05-04 20:46:50 +0200717
718 *input_addr_min = base & ~mask;
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100719 *input_addr_max = base | mask;
Doug Thompson93c2df52009-05-04 20:46:50 +0200720}
721
Doug Thompson93c2df52009-05-04 20:46:50 +0200722/* Map the Error address to a PAGE and PAGE OFFSET. */
723static inline void error_address_to_page_and_offset(u64 error_address,
724 u32 *page, u32 *offset)
725{
726 *page = (u32) (error_address >> PAGE_SHIFT);
727 *offset = ((u32) error_address) & ~PAGE_MASK;
728}
729
730/*
731 * @sys_addr is an error address (a SysAddr) extracted from the MCA NB Address
732 * Low (section 3.6.4.5) and MCA NB Address High (section 3.6.4.6) registers
733 * of a node that detected an ECC memory error. mci represents the node that
734 * the error address maps to (possibly different from the node that detected
735 * the error). Return the number of the csrow that sys_addr maps to, or -1 on
736 * error.
737 */
738static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr)
739{
740 int csrow;
741
742 csrow = input_addr_to_csrow(mci, sys_addr_to_input_addr(mci, sys_addr));
743
744 if (csrow == -1)
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200745 amd64_mc_err(mci, "Failed to translate InputAddr to csrow for "
746 "address 0x%lx\n", (unsigned long)sys_addr);
Doug Thompson93c2df52009-05-04 20:46:50 +0200747 return csrow;
748}
Doug Thompsone2ce7252009-04-27 15:57:12 +0200749
Borislav Petkovbfc04ae2009-11-12 19:05:07 +0100750static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);
Doug Thompson2da11652009-04-27 16:09:09 +0200751
Doug Thompson2da11652009-04-27 16:09:09 +0200752/*
753 * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs
754 * are ECC capable.
755 */
756static enum edac_type amd64_determine_edac_cap(struct amd64_pvt *pvt)
757{
Borislav Petkovcb328502010-12-22 14:28:24 +0100758 u8 bit;
Borislav Petkov584fcff2009-06-10 18:29:54 +0200759 enum dev_type edac_cap = EDAC_FLAG_NONE;
Doug Thompson2da11652009-04-27 16:09:09 +0200760
Borislav Petkov1433eb92009-10-21 13:44:36 +0200761 bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= K8_REV_F)
Doug Thompson2da11652009-04-27 16:09:09 +0200762 ? 19
763 : 17;
764
Borislav Petkov584fcff2009-06-10 18:29:54 +0200765 if (pvt->dclr0 & BIT(bit))
Doug Thompson2da11652009-04-27 16:09:09 +0200766 edac_cap = EDAC_FLAG_SECDED;
767
768 return edac_cap;
769}
770
771
Borislav Petkov8566c4d2009-10-16 13:48:28 +0200772static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt);
Doug Thompson2da11652009-04-27 16:09:09 +0200773
Borislav Petkov68798e12009-11-03 16:18:33 +0100774static void amd64_dump_dramcfg_low(u32 dclr, int chan)
775{
776 debugf1("F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr);
777
778 debugf1(" DIMM type: %sbuffered; all DIMMs support ECC: %s\n",
779 (dclr & BIT(16)) ? "un" : "",
780 (dclr & BIT(19)) ? "yes" : "no");
781
782 debugf1(" PAR/ERR parity: %s\n",
783 (dclr & BIT(8)) ? "enabled" : "disabled");
784
Borislav Petkovcb328502010-12-22 14:28:24 +0100785 if (boot_cpu_data.x86 == 0x10)
786 debugf1(" DCT 128bit mode width: %s\n",
787 (dclr & BIT(11)) ? "128b" : "64b");
Borislav Petkov68798e12009-11-03 16:18:33 +0100788
789 debugf1(" x4 logical DIMMs present: L0: %s L1: %s L2: %s L3: %s\n",
790 (dclr & BIT(12)) ? "yes" : "no",
791 (dclr & BIT(13)) ? "yes" : "no",
792 (dclr & BIT(14)) ? "yes" : "no",
793 (dclr & BIT(15)) ? "yes" : "no");
794}
795
Doug Thompson2da11652009-04-27 16:09:09 +0200796/* Display and decode various NB registers for debug purposes. */
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200797static void dump_misc_regs(struct amd64_pvt *pvt)
Doug Thompson2da11652009-04-27 16:09:09 +0200798{
Borislav Petkov68798e12009-11-03 16:18:33 +0100799 debugf1("F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap);
Doug Thompson2da11652009-04-27 16:09:09 +0200800
Borislav Petkov68798e12009-11-03 16:18:33 +0100801 debugf1(" NB two channel DRAM capable: %s\n",
Borislav Petkov5980bb92011-01-07 16:26:49 +0100802 (pvt->nbcap & NBCAP_DCT_DUAL) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100803
804 debugf1(" ECC capable: %s, ChipKill ECC capable: %s\n",
Borislav Petkov5980bb92011-01-07 16:26:49 +0100805 (pvt->nbcap & NBCAP_SECDED) ? "yes" : "no",
806 (pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no");
Borislav Petkov68798e12009-11-03 16:18:33 +0100807
808 amd64_dump_dramcfg_low(pvt->dclr0, 0);
Doug Thompson2da11652009-04-27 16:09:09 +0200809
Borislav Petkov8de1d912009-10-16 13:39:30 +0200810 debugf1("F3xB0 (Online Spare): 0x%08x\n", pvt->online_spare);
Doug Thompson2da11652009-04-27 16:09:09 +0200811
Borislav Petkov8de1d912009-10-16 13:39:30 +0200812 debugf1("F1xF0 (DRAM Hole Address): 0x%08x, base: 0x%08x, "
813 "offset: 0x%08x\n",
Borislav Petkovbc21fa52010-11-11 17:29:13 +0100814 pvt->dhar, dhar_base(pvt),
815 (boot_cpu_data.x86 == 0xf) ? k8_dhar_offset(pvt)
816 : f10_dhar_offset(pvt));
Doug Thompson2da11652009-04-27 16:09:09 +0200817
Borislav Petkovc8e518d2010-12-10 19:49:19 +0100818 debugf1(" DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no");
Doug Thompson2da11652009-04-27 16:09:09 +0200819
Borislav Petkov4d796362011-02-03 15:59:57 +0100820 amd64_debug_display_dimm_sizes(0, pvt);
821
Borislav Petkov8de1d912009-10-16 13:39:30 +0200822 /* everything below this point is Fam10h and above */
Borislav Petkov4d796362011-02-03 15:59:57 +0100823 if (boot_cpu_data.x86 == 0xf)
Doug Thompson2da11652009-04-27 16:09:09 +0200824 return;
Borislav Petkov4d796362011-02-03 15:59:57 +0100825
826 amd64_debug_display_dimm_sizes(1, pvt);
Doug Thompson2da11652009-04-27 16:09:09 +0200827
Borislav Petkova3b7db02011-01-19 20:35:12 +0100828 amd64_info("using %s syndromes.\n", ((pvt->ecc_sym_sz == 8) ? "x8" : "x4"));
Borislav Petkovad6a32e2010-03-09 12:46:00 +0100829
Borislav Petkov8de1d912009-10-16 13:39:30 +0200830 /* Only if NOT ganged does dclr1 have valid info */
Borislav Petkov68798e12009-11-03 16:18:33 +0100831 if (!dct_ganging_enabled(pvt))
832 amd64_dump_dramcfg_low(pvt->dclr1, 1);
Doug Thompson2da11652009-04-27 16:09:09 +0200833}
834
Doug Thompson94be4bf2009-04-27 16:12:00 +0200835/*
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100836 * see BKDG, F2x[1,0][5C:40], F2[1,0][6C:60]
Doug Thompson94be4bf2009-04-27 16:12:00 +0200837 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100838static void prep_chip_selects(struct amd64_pvt *pvt)
Doug Thompson94be4bf2009-04-27 16:12:00 +0200839{
Borislav Petkov1433eb92009-10-21 13:44:36 +0200840 if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) {
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100841 pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
842 pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 8;
Borislav Petkov9d858bb2009-09-21 14:35:51 +0200843 } else {
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100844 pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
845 pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4;
Doug Thompson94be4bf2009-04-27 16:12:00 +0200846 }
847}
848
849/*
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100850 * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers
Doug Thompson94be4bf2009-04-27 16:12:00 +0200851 */
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200852static void read_dct_base_mask(struct amd64_pvt *pvt)
Doug Thompson94be4bf2009-04-27 16:12:00 +0200853{
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100854 int cs;
Doug Thompson94be4bf2009-04-27 16:12:00 +0200855
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100856 prep_chip_selects(pvt);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200857
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100858 for_each_chip_select(cs, 0, pvt) {
Borislav Petkov71d2a322011-02-21 19:37:24 +0100859 int reg0 = DCSB0 + (cs * 4);
860 int reg1 = DCSB1 + (cs * 4);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100861 u32 *base0 = &pvt->csels[0].csbases[cs];
862 u32 *base1 = &pvt->csels[1].csbases[cs];
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200863
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100864 if (!amd64_read_dct_pci_cfg(pvt, reg0, base0))
Doug Thompson94be4bf2009-04-27 16:12:00 +0200865 debugf0(" DCSB0[%d]=0x%08x reg: F2x%x\n",
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100866 cs, *base0, reg0);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200867
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100868 if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt))
869 continue;
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200870
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100871 if (!amd64_read_dct_pci_cfg(pvt, reg1, base1))
872 debugf0(" DCSB1[%d]=0x%08x reg: F2x%x\n",
873 cs, *base1, reg1);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200874 }
875
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100876 for_each_chip_select_mask(cs, 0, pvt) {
Borislav Petkov71d2a322011-02-21 19:37:24 +0100877 int reg0 = DCSM0 + (cs * 4);
878 int reg1 = DCSM1 + (cs * 4);
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100879 u32 *mask0 = &pvt->csels[0].csmasks[cs];
880 u32 *mask1 = &pvt->csels[1].csmasks[cs];
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200881
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100882 if (!amd64_read_dct_pci_cfg(pvt, reg0, mask0))
Doug Thompson94be4bf2009-04-27 16:12:00 +0200883 debugf0(" DCSM0[%d]=0x%08x reg: F2x%x\n",
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100884 cs, *mask0, reg0);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200885
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100886 if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt))
887 continue;
Borislav Petkovb2b0c602010-10-08 18:32:29 +0200888
Borislav Petkov11c75ea2010-11-29 19:49:02 +0100889 if (!amd64_read_dct_pci_cfg(pvt, reg1, mask1))
890 debugf0(" DCSM1[%d]=0x%08x reg: F2x%x\n",
891 cs, *mask1, reg1);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200892 }
893}
894
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200895static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt, int cs)
Doug Thompson94be4bf2009-04-27 16:12:00 +0200896{
897 enum mem_type type;
898
Borislav Petkovcb328502010-12-22 14:28:24 +0100899 /* F15h supports only DDR3 */
900 if (boot_cpu_data.x86 >= 0x15)
901 type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3;
902 else if (boot_cpu_data.x86 == 0x10 || pvt->ext_model >= K8_REV_F) {
Borislav Petkov6b4c0bd2009-11-12 15:37:57 +0100903 if (pvt->dchr0 & DDR3_MODE)
904 type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3;
905 else
906 type = (pvt->dclr0 & BIT(16)) ? MEM_DDR2 : MEM_RDDR2;
Doug Thompson94be4bf2009-04-27 16:12:00 +0200907 } else {
Doug Thompson94be4bf2009-04-27 16:12:00 +0200908 type = (pvt->dclr0 & BIT(18)) ? MEM_DDR : MEM_RDDR;
909 }
910
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200911 amd64_info("CS%d: %s\n", cs, edac_mem_types[type]);
Doug Thompson94be4bf2009-04-27 16:12:00 +0200912
913 return type;
914}
915
Borislav Petkovcb328502010-12-22 14:28:24 +0100916/* Get the number of DCT channels the memory controller is using. */
Doug Thompsonddff8762009-04-27 16:14:52 +0200917static int k8_early_channel_count(struct amd64_pvt *pvt)
918{
Borislav Petkovcb328502010-12-22 14:28:24 +0100919 int flag;
Doug Thompsonddff8762009-04-27 16:14:52 +0200920
Borislav Petkov9f56da02010-10-01 19:44:53 +0200921 if (pvt->ext_model >= K8_REV_F)
Doug Thompsonddff8762009-04-27 16:14:52 +0200922 /* RevF (NPT) and later */
Borislav Petkov41d8bfa2011-01-18 19:16:08 +0100923 flag = pvt->dclr0 & WIDTH_128;
Borislav Petkov9f56da02010-10-01 19:44:53 +0200924 else
Doug Thompsonddff8762009-04-27 16:14:52 +0200925 /* RevE and earlier */
926 flag = pvt->dclr0 & REVE_WIDTH_128;
Doug Thompsonddff8762009-04-27 16:14:52 +0200927
928 /* not used */
929 pvt->dclr1 = 0;
930
931 return (flag) ? 2 : 1;
932}
933
Borislav Petkov70046622011-01-10 14:37:27 +0100934/* On F10h and later ErrAddr is MC4_ADDR[47:1] */
935static u64 get_error_address(struct mce *m)
Doug Thompsonddff8762009-04-27 16:14:52 +0200936{
Borislav Petkov70046622011-01-10 14:37:27 +0100937 u8 start_bit = 1;
938 u8 end_bit = 47;
939
940 if (boot_cpu_data.x86 == 0xf) {
941 start_bit = 3;
942 end_bit = 39;
943 }
944
945 return m->addr & GENMASK(start_bit, end_bit);
Doug Thompsonddff8762009-04-27 16:14:52 +0200946}
947
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200948static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
Doug Thompsonddff8762009-04-27 16:14:52 +0200949{
Borislav Petkov71d2a322011-02-21 19:37:24 +0100950 int off = range << 3;
Doug Thompsonddff8762009-04-27 16:14:52 +0200951
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200952 amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo);
953 amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
Doug Thompsonddff8762009-04-27 16:14:52 +0200954
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200955 if (boot_cpu_data.x86 == 0xf)
956 return;
Doug Thompsonddff8762009-04-27 16:14:52 +0200957
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200958 if (!dram_rw(pvt, range))
959 return;
Doug Thompsonddff8762009-04-27 16:14:52 +0200960
Borislav Petkov7f19bf72010-10-21 18:52:53 +0200961 amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi);
962 amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
Doug Thompsonddff8762009-04-27 16:14:52 +0200963}
964
Borislav Petkovf192c7b2011-01-10 14:24:32 +0100965static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
966 u16 syndrome)
Doug Thompsonddff8762009-04-27 16:14:52 +0200967{
968 struct mem_ctl_info *src_mci;
Borislav Petkovf192c7b2011-01-10 14:24:32 +0100969 struct amd64_pvt *pvt = mci->pvt_info;
Doug Thompsonddff8762009-04-27 16:14:52 +0200970 int channel, csrow;
971 u32 page, offset;
Doug Thompsonddff8762009-04-27 16:14:52 +0200972
973 /* CHIPKILL enabled */
Borislav Petkovf192c7b2011-01-10 14:24:32 +0100974 if (pvt->nbcfg & NBCFG_CHIPKILL) {
Borislav Petkovbfc04ae2009-11-12 19:05:07 +0100975 channel = get_channel_from_ecc_syndrome(mci, syndrome);
Doug Thompsonddff8762009-04-27 16:14:52 +0200976 if (channel < 0) {
977 /*
978 * Syndrome didn't map, so we don't know which of the
979 * 2 DIMMs is in error. So we need to ID 'both' of them
980 * as suspect.
981 */
Borislav Petkov24f9a7f2010-10-07 18:29:15 +0200982 amd64_mc_warn(mci, "unknown syndrome 0x%04x - possible "
983 "error reporting race\n", syndrome);
Doug Thompsonddff8762009-04-27 16:14:52 +0200984 edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
985 return;
986 }
987 } else {
988 /*
989 * non-chipkill ecc mode
990 *
991 * The k8 documentation is unclear about how to determine the
992 * channel number when using non-chipkill memory. This method
993 * was obtained from email communication with someone at AMD.
994 * (Wish the email was placed in this comment - norsk)
995 */
Borislav Petkov44e9e2e2009-10-26 15:00:19 +0100996 channel = ((sys_addr & BIT(3)) != 0);
Doug Thompsonddff8762009-04-27 16:14:52 +0200997 }
998
999 /*
1000 * Find out which node the error address belongs to. This may be
1001 * different from the node that detected the error.
1002 */
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001003 src_mci = find_mc_by_sys_addr(mci, sys_addr);
Keith Mannthey2cff18c2009-09-18 14:35:23 +02001004 if (!src_mci) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001005 amd64_mc_err(mci, "failed to map error addr 0x%lx to a node\n",
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001006 (unsigned long)sys_addr);
Doug Thompsonddff8762009-04-27 16:14:52 +02001007 edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
1008 return;
1009 }
1010
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001011 /* Now map the sys_addr to a CSROW */
1012 csrow = sys_addr_to_csrow(src_mci, sys_addr);
Doug Thompsonddff8762009-04-27 16:14:52 +02001013 if (csrow < 0) {
1014 edac_mc_handle_ce_no_info(src_mci, EDAC_MOD_STR);
1015 } else {
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001016 error_address_to_page_and_offset(sys_addr, &page, &offset);
Doug Thompsonddff8762009-04-27 16:14:52 +02001017
1018 edac_mc_handle_ce(src_mci, page, offset, syndrome, csrow,
1019 channel, EDAC_MOD_STR);
1020 }
1021}
1022
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001023static int ddr2_cs_size(unsigned i, bool dct_width)
Doug Thompsonddff8762009-04-27 16:14:52 +02001024{
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001025 unsigned shift = 0;
Doug Thompsonddff8762009-04-27 16:14:52 +02001026
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001027 if (i <= 2)
1028 shift = i;
1029 else if (!(i & 0x1))
1030 shift = i >> 1;
Borislav Petkov1433eb92009-10-21 13:44:36 +02001031 else
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001032 shift = (i + 1) >> 1;
Doug Thompsonddff8762009-04-27 16:14:52 +02001033
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001034 return 128 << (shift + !!dct_width);
1035}
1036
1037static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
1038 unsigned cs_mode)
1039{
1040 u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
1041
1042 if (pvt->ext_model >= K8_REV_F) {
1043 WARN_ON(cs_mode > 11);
1044 return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
1045 }
1046 else if (pvt->ext_model >= K8_REV_D) {
1047 WARN_ON(cs_mode > 10);
1048
1049 if (cs_mode == 3 || cs_mode == 8)
1050 return 32 << (cs_mode - 1);
1051 else
1052 return 32 << cs_mode;
1053 }
1054 else {
1055 WARN_ON(cs_mode > 6);
1056 return 32 << cs_mode;
1057 }
Doug Thompsonddff8762009-04-27 16:14:52 +02001058}
1059
Doug Thompson1afd3c92009-04-27 16:16:50 +02001060/*
1061 * Get the number of DCT channels in use.
1062 *
1063 * Return:
1064 * number of Memory Channels in operation
1065 * Pass back:
1066 * contents of the DCL0_LOW register
1067 */
Borislav Petkov7d20d142011-01-07 17:58:04 +01001068static int f1x_early_channel_count(struct amd64_pvt *pvt)
Doug Thompson1afd3c92009-04-27 16:16:50 +02001069{
Borislav Petkov6ba5dcd2009-10-13 19:26:55 +02001070 int i, j, channels = 0;
Doug Thompsonddff8762009-04-27 16:14:52 +02001071
Borislav Petkov7d20d142011-01-07 17:58:04 +01001072 /* On F10h, if we are in 128 bit mode, then we are using 2 channels */
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001073 if (boot_cpu_data.x86 == 0x10 && (pvt->dclr0 & WIDTH_128))
Borislav Petkov7d20d142011-01-07 17:58:04 +01001074 return 2;
Doug Thompson1afd3c92009-04-27 16:16:50 +02001075
1076 /*
Borislav Petkovd16149e2009-10-16 19:55:49 +02001077 * Need to check if in unganged mode: In such, there are 2 channels,
1078 * but they are not in 128 bit mode and thus the above 'dclr0' status
1079 * bit will be OFF.
Doug Thompson1afd3c92009-04-27 16:16:50 +02001080 *
1081 * Need to check DCT0[0] and DCT1[0] to see if only one of them has
1082 * their CSEnable bit on. If so, then SINGLE DIMM case.
1083 */
Borislav Petkovd16149e2009-10-16 19:55:49 +02001084 debugf0("Data width is not 128 bits - need more decoding\n");
Doug Thompson1afd3c92009-04-27 16:16:50 +02001085
1086 /*
1087 * Check DRAM Bank Address Mapping values for each DIMM to see if there
1088 * is more than just one DIMM present in unganged mode. Need to check
1089 * both controllers since DIMMs can be placed in either one.
1090 */
Borislav Petkov525a1b22010-12-21 15:53:27 +01001091 for (i = 0; i < 2; i++) {
1092 u32 dbam = (i ? pvt->dbam1 : pvt->dbam0);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001093
Wan Wei57a30852009-08-07 17:04:49 +02001094 for (j = 0; j < 4; j++) {
1095 if (DBAM_DIMM(j, dbam) > 0) {
1096 channels++;
1097 break;
1098 }
1099 }
Doug Thompson1afd3c92009-04-27 16:16:50 +02001100 }
1101
Borislav Petkovd16149e2009-10-16 19:55:49 +02001102 if (channels > 2)
1103 channels = 2;
1104
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001105 amd64_info("MCT channel count: %d\n", channels);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001106
1107 return channels;
Doug Thompson1afd3c92009-04-27 16:16:50 +02001108}
1109
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001110static int ddr3_cs_size(unsigned i, bool dct_width)
Doug Thompson1afd3c92009-04-27 16:16:50 +02001111{
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001112 unsigned shift = 0;
1113 int cs_size = 0;
1114
1115 if (i == 0 || i == 3 || i == 4)
1116 cs_size = -1;
1117 else if (i <= 2)
1118 shift = i;
1119 else if (i == 12)
1120 shift = 7;
1121 else if (!(i & 0x1))
1122 shift = i >> 1;
1123 else
1124 shift = (i + 1) >> 1;
1125
1126 if (cs_size != -1)
1127 cs_size = (128 * (1 << !!dct_width)) << shift;
1128
1129 return cs_size;
1130}
1131
1132static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
1133 unsigned cs_mode)
1134{
1135 u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
1136
1137 WARN_ON(cs_mode > 11);
Borislav Petkov1433eb92009-10-21 13:44:36 +02001138
1139 if (pvt->dchr0 & DDR3_MODE || pvt->dchr1 & DDR3_MODE)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001140 return ddr3_cs_size(cs_mode, dclr & WIDTH_128);
Borislav Petkov1433eb92009-10-21 13:44:36 +02001141 else
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001142 return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
1143}
Borislav Petkov1433eb92009-10-21 13:44:36 +02001144
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001145/*
1146 * F15h supports only 64bit DCT interfaces
1147 */
1148static int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
1149 unsigned cs_mode)
1150{
1151 WARN_ON(cs_mode > 12);
1152
1153 return ddr3_cs_size(cs_mode, false);
Doug Thompson1afd3c92009-04-27 16:16:50 +02001154}
1155
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001156static void read_dram_ctl_register(struct amd64_pvt *pvt)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001157{
Doug Thompson6163b5d2009-04-27 16:20:17 +02001158
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001159 if (boot_cpu_data.x86 == 0xf)
1160 return;
1161
Borislav Petkov78da1212010-12-22 19:31:45 +01001162 if (!amd64_read_dct_pci_cfg(pvt, DCT_SEL_LO, &pvt->dct_sel_lo)) {
1163 debugf0("F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x\n",
1164 pvt->dct_sel_lo, dct_sel_baseaddr(pvt));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001165
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001166 debugf0(" DCTs operate in %s mode.\n",
1167 (dct_ganging_enabled(pvt) ? "ganged" : "unganged"));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001168
Borislav Petkov72381bd2009-10-09 19:14:43 +02001169 if (!dct_ganging_enabled(pvt))
1170 debugf0(" Address range split per DCT: %s\n",
1171 (dct_high_range_enabled(pvt) ? "yes" : "no"));
1172
Borislav Petkov78da1212010-12-22 19:31:45 +01001173 debugf0(" data interleave for ECC: %s, "
Borislav Petkov72381bd2009-10-09 19:14:43 +02001174 "DRAM cleared since last warm reset: %s\n",
1175 (dct_data_intlv_enabled(pvt) ? "enabled" : "disabled"),
1176 (dct_memory_cleared(pvt) ? "yes" : "no"));
1177
Borislav Petkov78da1212010-12-22 19:31:45 +01001178 debugf0(" channel interleave: %s, "
1179 "interleave bits selector: 0x%x\n",
Borislav Petkov72381bd2009-10-09 19:14:43 +02001180 (dct_interleave_enabled(pvt) ? "enabled" : "disabled"),
Doug Thompson6163b5d2009-04-27 16:20:17 +02001181 dct_sel_interleave_addr(pvt));
1182 }
1183
Borislav Petkov78da1212010-12-22 19:31:45 +01001184 amd64_read_dct_pci_cfg(pvt, DCT_SEL_HI, &pvt->dct_sel_hi);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001185}
1186
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001187/*
Borislav Petkov229a7a12010-12-09 18:57:54 +01001188 * Determine channel (DCT) based on the interleaving mode: F10h BKDG, 2.8.9 Memory
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001189 * Interleaving Modes.
1190 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001191static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
Borislav Petkov229a7a12010-12-09 18:57:54 +01001192 bool hi_range_sel, u8 intlv_en)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001193{
Borislav Petkov151fa712011-02-21 19:33:10 +01001194 u8 dct_sel_high = (pvt->dct_sel_lo >> 1) & 1;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001195
1196 if (dct_ganging_enabled(pvt))
Borislav Petkov229a7a12010-12-09 18:57:54 +01001197 return 0;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001198
Borislav Petkov229a7a12010-12-09 18:57:54 +01001199 if (hi_range_sel)
1200 return dct_sel_high;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001201
Borislav Petkov229a7a12010-12-09 18:57:54 +01001202 /*
1203 * see F2x110[DctSelIntLvAddr] - channel interleave mode
1204 */
1205 if (dct_interleave_enabled(pvt)) {
1206 u8 intlv_addr = dct_sel_interleave_addr(pvt);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001207
Borislav Petkov229a7a12010-12-09 18:57:54 +01001208 /* return DCT select function: 0=DCT0, 1=DCT1 */
1209 if (!intlv_addr)
1210 return sys_addr >> 6 & 1;
1211
1212 if (intlv_addr & 0x2) {
1213 u8 shift = intlv_addr & 0x1 ? 9 : 6;
1214 u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) % 2;
1215
1216 return ((sys_addr >> shift) & 1) ^ temp;
1217 }
1218
1219 return (sys_addr >> (12 + hweight8(intlv_en))) & 1;
1220 }
1221
1222 if (dct_high_range_enabled(pvt))
1223 return ~dct_sel_high & 1;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001224
1225 return 0;
1226}
1227
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001228/* Convert the sys_addr to the normalized DCT address */
Borislav Petkove761359a2011-02-21 19:49:01 +01001229static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, unsigned range,
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001230 u64 sys_addr, bool hi_rng,
1231 u32 dct_sel_base_addr)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001232{
1233 u64 chan_off;
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001234 u64 dram_base = get_dram_base(pvt, range);
1235 u64 hole_off = f10_dhar_offset(pvt);
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001236 u64 dct_sel_base_off = (pvt->dct_sel_hi & 0xFFFFFC00) << 16;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001237
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001238 if (hi_rng) {
1239 /*
1240 * if
1241 * base address of high range is below 4Gb
1242 * (bits [47:27] at [31:11])
1243 * DRAM address space on this DCT is hoisted above 4Gb &&
1244 * sys_addr > 4Gb
1245 *
1246 * remove hole offset from sys_addr
1247 * else
1248 * remove high range offset from sys_addr
1249 */
1250 if ((!(dct_sel_base_addr >> 16) ||
1251 dct_sel_base_addr < dhar_base(pvt)) &&
Borislav Petkov972ea172011-02-21 19:43:02 +01001252 dhar_valid(pvt) &&
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001253 (sys_addr >= BIT_64(32)))
Borislav Petkovbc21fa52010-11-11 17:29:13 +01001254 chan_off = hole_off;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001255 else
1256 chan_off = dct_sel_base_off;
1257 } else {
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001258 /*
1259 * if
1260 * we have a valid hole &&
1261 * sys_addr > 4Gb
1262 *
1263 * remove hole
1264 * else
1265 * remove dram base to normalize to DCT address
1266 */
Borislav Petkov972ea172011-02-21 19:43:02 +01001267 if (dhar_valid(pvt) && (sys_addr >= BIT_64(32)))
Borislav Petkovbc21fa52010-11-11 17:29:13 +01001268 chan_off = hole_off;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001269 else
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001270 chan_off = dram_base;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001271 }
1272
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001273 return (sys_addr & GENMASK(6,47)) - (chan_off & GENMASK(23,47));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001274}
1275
Doug Thompson6163b5d2009-04-27 16:20:17 +02001276/*
1277 * checks if the csrow passed in is marked as SPARED, if so returns the new
1278 * spare row
1279 */
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001280static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001281{
Borislav Petkov614ec9d2011-01-13 18:02:22 +01001282 int tmp_cs;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001283
Borislav Petkov614ec9d2011-01-13 18:02:22 +01001284 if (online_spare_swap_done(pvt, dct) &&
1285 csrow == online_spare_bad_dramcs(pvt, dct)) {
1286
1287 for_each_chip_select(tmp_cs, dct, pvt) {
1288 if (chip_select_base(tmp_cs, dct, pvt) & 0x2) {
1289 csrow = tmp_cs;
1290 break;
1291 }
1292 }
Doug Thompson6163b5d2009-04-27 16:20:17 +02001293 }
1294 return csrow;
1295}
1296
1297/*
1298 * Iterate over the DRAM DCT "base" and "mask" registers looking for a
1299 * SystemAddr match on the specified 'ChannelSelect' and 'NodeID'
1300 *
1301 * Return:
1302 * -EINVAL: NOT FOUND
1303 * 0..csrow = Chip-Select Row
1304 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001305static int f1x_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)
Doug Thompson6163b5d2009-04-27 16:20:17 +02001306{
1307 struct mem_ctl_info *mci;
1308 struct amd64_pvt *pvt;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001309 u64 cs_base, cs_mask;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001310 int cs_found = -EINVAL;
1311 int csrow;
1312
Borislav Petkovcc4d8862010-10-13 16:11:59 +02001313 mci = mcis[nid];
Doug Thompson6163b5d2009-04-27 16:20:17 +02001314 if (!mci)
1315 return cs_found;
1316
1317 pvt = mci->pvt_info;
1318
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001319 debugf1("input addr: 0x%llx, DCT: %d\n", in_addr, dct);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001320
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001321 for_each_chip_select(csrow, dct, pvt) {
1322 if (!csrow_enabled(csrow, dct, pvt))
Doug Thompson6163b5d2009-04-27 16:20:17 +02001323 continue;
1324
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001325 get_cs_base_and_mask(pvt, csrow, dct, &cs_base, &cs_mask);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001326
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001327 debugf1(" CSROW=%d CSBase=0x%llx CSMask=0x%llx\n",
1328 csrow, cs_base, cs_mask);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001329
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001330 cs_mask = ~cs_mask;
Doug Thompson6163b5d2009-04-27 16:20:17 +02001331
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001332 debugf1(" (InputAddr & ~CSMask)=0x%llx "
1333 "(CSBase & ~CSMask)=0x%llx\n",
1334 (in_addr & cs_mask), (cs_base & cs_mask));
Doug Thompson6163b5d2009-04-27 16:20:17 +02001335
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001336 if ((in_addr & cs_mask) == (cs_base & cs_mask)) {
1337 cs_found = f10_process_possible_spare(pvt, dct, csrow);
Doug Thompson6163b5d2009-04-27 16:20:17 +02001338
1339 debugf1(" MATCH csrow=%d\n", cs_found);
1340 break;
1341 }
1342 }
1343 return cs_found;
1344}
1345
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001346/*
1347 * See F2x10C. Non-interleaved graphics framebuffer memory under the 16G is
1348 * swapped with a region located at the bottom of memory so that the GPU can use
1349 * the interleaved region and thus two channels.
1350 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001351static u64 f1x_swap_interleaved_region(struct amd64_pvt *pvt, u64 sys_addr)
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001352{
1353 u32 swap_reg, swap_base, swap_limit, rgn_size, tmp_addr;
1354
1355 if (boot_cpu_data.x86 == 0x10) {
1356 /* only revC3 and revE have that feature */
1357 if (boot_cpu_data.x86_model < 4 ||
1358 (boot_cpu_data.x86_model < 0xa &&
1359 boot_cpu_data.x86_mask < 3))
1360 return sys_addr;
1361 }
1362
1363 amd64_read_dct_pci_cfg(pvt, SWAP_INTLV_REG, &swap_reg);
1364
1365 if (!(swap_reg & 0x1))
1366 return sys_addr;
1367
1368 swap_base = (swap_reg >> 3) & 0x7f;
1369 swap_limit = (swap_reg >> 11) & 0x7f;
1370 rgn_size = (swap_reg >> 20) & 0x7f;
1371 tmp_addr = sys_addr >> 27;
1372
1373 if (!(sys_addr >> 34) &&
1374 (((tmp_addr >= swap_base) &&
1375 (tmp_addr <= swap_limit)) ||
1376 (tmp_addr < rgn_size)))
1377 return sys_addr ^ (u64)swap_base << 27;
1378
1379 return sys_addr;
1380}
1381
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001382/* For a given @dram_range, check if @sys_addr falls within it. */
Borislav Petkove761359a2011-02-21 19:49:01 +01001383static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001384 u64 sys_addr, int *nid, int *chan_sel)
1385{
Borislav Petkov229a7a12010-12-09 18:57:54 +01001386 int cs_found = -EINVAL;
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001387 u64 chan_addr;
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001388 u32 dct_sel_base;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001389 u8 channel;
Borislav Petkov229a7a12010-12-09 18:57:54 +01001390 bool high_range = false;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001391
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001392 u8 node_id = dram_dst_node(pvt, range);
Borislav Petkov229a7a12010-12-09 18:57:54 +01001393 u8 intlv_en = dram_intlv_en(pvt, range);
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001394 u32 intlv_sel = dram_intlv_sel(pvt, range);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001395
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001396 debugf1("(range %d) SystemAddr= 0x%llx Limit=0x%llx\n",
1397 range, sys_addr, get_dram_limit(pvt, range));
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001398
Borislav Petkov355fba62011-01-17 13:03:26 +01001399 if (dhar_valid(pvt) &&
1400 dhar_base(pvt) <= sys_addr &&
1401 sys_addr < BIT_64(32)) {
1402 amd64_warn("Huh? Address is in the MMIO hole: 0x%016llx\n",
1403 sys_addr);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001404 return -EINVAL;
Borislav Petkov355fba62011-01-17 13:03:26 +01001405 }
1406
1407 if (intlv_en &&
1408 (intlv_sel != ((sys_addr >> 12) & intlv_en))) {
1409 amd64_warn("Botched intlv bits, en: 0x%x, sel: 0x%x\n",
1410 intlv_en, intlv_sel);
1411 return -EINVAL;
1412 }
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001413
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001414 sys_addr = f1x_swap_interleaved_region(pvt, sys_addr);
Borislav Petkov95b0ef52011-01-11 22:08:07 +01001415
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001416 dct_sel_base = dct_sel_baseaddr(pvt);
1417
1418 /*
1419 * check whether addresses >= DctSelBaseAddr[47:27] are to be used to
1420 * select between DCT0 and DCT1.
1421 */
1422 if (dct_high_range_enabled(pvt) &&
1423 !dct_ganging_enabled(pvt) &&
1424 ((sys_addr >> 27) >= (dct_sel_base >> 11)))
Borislav Petkov229a7a12010-12-09 18:57:54 +01001425 high_range = true;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001426
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001427 channel = f1x_determine_channel(pvt, sys_addr, high_range, intlv_en);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001428
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001429 chan_addr = f1x_get_norm_dct_addr(pvt, range, sys_addr,
Borislav Petkovc8e518d2010-12-10 19:49:19 +01001430 high_range, dct_sel_base);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001431
Borislav Petkove2f79db2011-01-13 14:57:34 +01001432 /* Remove node interleaving, see F1x120 */
1433 if (intlv_en)
1434 chan_addr = ((chan_addr >> (12 + hweight8(intlv_en))) << 12) |
1435 (chan_addr & 0xfff);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001436
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001437 /* remove channel interleave */
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001438 if (dct_interleave_enabled(pvt) &&
1439 !dct_high_range_enabled(pvt) &&
1440 !dct_ganging_enabled(pvt)) {
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001441
1442 if (dct_sel_interleave_addr(pvt) != 1) {
1443 if (dct_sel_interleave_addr(pvt) == 0x3)
1444 /* hash 9 */
1445 chan_addr = ((chan_addr >> 10) << 9) |
1446 (chan_addr & 0x1ff);
1447 else
1448 /* A[6] or hash 6 */
1449 chan_addr = ((chan_addr >> 7) << 6) |
1450 (chan_addr & 0x3f);
1451 } else
1452 /* A[12] */
1453 chan_addr = ((chan_addr >> 13) << 12) |
1454 (chan_addr & 0xfff);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001455 }
1456
Borislav Petkov5d4b58e2011-01-13 16:01:13 +01001457 debugf1(" Normalized DCT addr: 0x%llx\n", chan_addr);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001458
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001459 cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, channel);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001460
1461 if (cs_found >= 0) {
1462 *nid = node_id;
1463 *chan_sel = channel;
1464 }
1465 return cs_found;
1466}
1467
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001468static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001469 int *node, int *chan_sel)
1470{
Borislav Petkove761359a2011-02-21 19:49:01 +01001471 int cs_found = -EINVAL;
1472 unsigned range;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001473
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001474 for (range = 0; range < DRAM_RANGES; range++) {
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001475
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001476 if (!dram_rw(pvt, range))
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001477 continue;
1478
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001479 if ((get_dram_base(pvt, range) <= sys_addr) &&
1480 (get_dram_limit(pvt, range) >= sys_addr)) {
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001481
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001482 cs_found = f1x_match_to_this_node(pvt, range,
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001483 sys_addr, node,
1484 chan_sel);
1485 if (cs_found >= 0)
1486 break;
1487 }
1488 }
1489 return cs_found;
1490}
1491
1492/*
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001493 * For reference see "2.8.5 Routing DRAM Requests" in F10 BKDG. This code maps
1494 * a @sys_addr to NodeID, DCT (channel) and chip select (CSROW).
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001495 *
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001496 * The @sys_addr is usually an error address received from the hardware
1497 * (MCX_ADDR).
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001498 */
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001499static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001500 u16 syndrome)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001501{
1502 struct amd64_pvt *pvt = mci->pvt_info;
1503 u32 page, offset;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001504 int nid, csrow, chan = 0;
1505
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001506 csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001507
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001508 if (csrow < 0) {
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001509 edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001510 return;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001511 }
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001512
1513 error_address_to_page_and_offset(sys_addr, &page, &offset);
1514
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001515 /*
1516 * We need the syndromes for channel detection only when we're
1517 * ganged. Otherwise @chan should already contain the channel at
1518 * this point.
1519 */
Borislav Petkova97fa682010-12-23 14:07:18 +01001520 if (dct_ganging_enabled(pvt))
Borislav Petkovbdc30a02009-11-13 15:10:43 +01001521 chan = get_channel_from_ecc_syndrome(mci, syndrome);
1522
1523 if (chan >= 0)
1524 edac_mc_handle_ce(mci, page, offset, syndrome, csrow, chan,
1525 EDAC_MOD_STR);
1526 else
1527 /*
1528 * Channel unknown, report all channels on this CSROW as failed.
1529 */
1530 for (chan = 0; chan < mci->csrows[csrow].nr_channels; chan++)
1531 edac_mc_handle_ce(mci, page, offset, syndrome,
1532 csrow, chan, EDAC_MOD_STR);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001533}
1534
1535/*
Borislav Petkov8566c4d2009-10-16 13:48:28 +02001536 * debug routine to display the memory sizes of all logical DIMMs and its
Borislav Petkovcb328502010-12-22 14:28:24 +01001537 * CSROWs
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001538 */
Borislav Petkov8566c4d2009-10-16 13:48:28 +02001539static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001540{
Borislav Petkov603adaf2009-12-21 14:52:53 +01001541 int dimm, size0, size1, factor = 0;
Borislav Petkov525a1b22010-12-21 15:53:27 +01001542 u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases;
1543 u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001544
Borislav Petkov8566c4d2009-10-16 13:48:28 +02001545 if (boot_cpu_data.x86 == 0xf) {
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001546 if (pvt->dclr0 & WIDTH_128)
Borislav Petkov603adaf2009-12-21 14:52:53 +01001547 factor = 1;
1548
Borislav Petkov8566c4d2009-10-16 13:48:28 +02001549 /* K8 families < revF not supported yet */
Borislav Petkov1433eb92009-10-21 13:44:36 +02001550 if (pvt->ext_model < K8_REV_F)
Borislav Petkov8566c4d2009-10-16 13:48:28 +02001551 return;
1552 else
1553 WARN_ON(ctrl != 0);
1554 }
1555
Borislav Petkov4d796362011-02-03 15:59:57 +01001556 dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1 : pvt->dbam0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001557 dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->csels[1].csbases
1558 : pvt->csels[0].csbases;
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001559
Borislav Petkov4d796362011-02-03 15:59:57 +01001560 debugf1("F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", ctrl, dbam);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001561
Borislav Petkov8566c4d2009-10-16 13:48:28 +02001562 edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl);
1563
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001564 /* Dump memory sizes for DIMM and its CSROWs */
1565 for (dimm = 0; dimm < 4; dimm++) {
1566
1567 size0 = 0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001568 if (dcsb[dimm*2] & DCSB_CS_ENABLE)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001569 size0 = pvt->ops->dbam_to_cs(pvt, ctrl,
1570 DBAM_DIMM(dimm, dbam));
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001571
1572 size1 = 0;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01001573 if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE)
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001574 size1 = pvt->ops->dbam_to_cs(pvt, ctrl,
1575 DBAM_DIMM(dimm, dbam));
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001576
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001577 amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
1578 dimm * 2, size0 << factor,
1579 dimm * 2 + 1, size1 << factor);
Doug Thompsonf71d0a02009-04-27 16:22:43 +02001580 }
1581}
1582
Doug Thompson4d376072009-04-27 16:25:05 +02001583static struct amd64_family_type amd64_family_types[] = {
1584 [K8_CPUS] = {
Borislav Petkov0092b202010-10-01 19:20:05 +02001585 .ctl_name = "K8",
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001586 .f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP,
1587 .f3_id = PCI_DEVICE_ID_AMD_K8_NB_MISC,
Doug Thompson4d376072009-04-27 16:25:05 +02001588 .ops = {
Borislav Petkov1433eb92009-10-21 13:44:36 +02001589 .early_channel_count = k8_early_channel_count,
Borislav Petkov1433eb92009-10-21 13:44:36 +02001590 .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow,
1591 .dbam_to_cs = k8_dbam_to_chip_select,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02001592 .read_dct_pci_cfg = k8_read_dct_pci_cfg,
Doug Thompson4d376072009-04-27 16:25:05 +02001593 }
1594 },
1595 [F10_CPUS] = {
Borislav Petkov0092b202010-10-01 19:20:05 +02001596 .ctl_name = "F10h",
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001597 .f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP,
1598 .f3_id = PCI_DEVICE_ID_AMD_10H_NB_MISC,
Doug Thompson4d376072009-04-27 16:25:05 +02001599 .ops = {
Borislav Petkov7d20d142011-01-07 17:58:04 +01001600 .early_channel_count = f1x_early_channel_count,
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001601 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
Borislav Petkov1433eb92009-10-21 13:44:36 +02001602 .dbam_to_cs = f10_dbam_to_chip_select,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02001603 .read_dct_pci_cfg = f10_read_dct_pci_cfg,
1604 }
1605 },
1606 [F15_CPUS] = {
1607 .ctl_name = "F15h",
Borislav Petkovdf71a052011-01-19 18:15:10 +01001608 .f1_id = PCI_DEVICE_ID_AMD_15H_NB_F1,
1609 .f3_id = PCI_DEVICE_ID_AMD_15H_NB_F3,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02001610 .ops = {
Borislav Petkov7d20d142011-01-07 17:58:04 +01001611 .early_channel_count = f1x_early_channel_count,
Borislav Petkovb15f0fc2011-01-17 15:59:58 +01001612 .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01001613 .dbam_to_cs = f15_dbam_to_chip_select,
Borislav Petkovb2b0c602010-10-08 18:32:29 +02001614 .read_dct_pci_cfg = f15_read_dct_pci_cfg,
Doug Thompson4d376072009-04-27 16:25:05 +02001615 }
1616 },
Doug Thompson4d376072009-04-27 16:25:05 +02001617};
1618
1619static struct pci_dev *pci_get_related_function(unsigned int vendor,
1620 unsigned int device,
1621 struct pci_dev *related)
1622{
1623 struct pci_dev *dev = NULL;
1624
1625 dev = pci_get_device(vendor, device, dev);
1626 while (dev) {
1627 if ((dev->bus->number == related->bus->number) &&
1628 (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
1629 break;
1630 dev = pci_get_device(vendor, device, dev);
1631 }
1632
1633 return dev;
1634}
1635
Doug Thompsonb1289d62009-04-27 16:37:05 +02001636/*
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001637 * These are tables of eigenvectors (one per line) which can be used for the
1638 * construction of the syndrome tables. The modified syndrome search algorithm
1639 * uses those to find the symbol in error and thus the DIMM.
Doug Thompsonb1289d62009-04-27 16:37:05 +02001640 *
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001641 * Algorithm courtesy of Ross LaFetra from AMD.
Doug Thompsonb1289d62009-04-27 16:37:05 +02001642 */
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001643static u16 x4_vectors[] = {
1644 0x2f57, 0x1afe, 0x66cc, 0xdd88,
1645 0x11eb, 0x3396, 0x7f4c, 0xeac8,
1646 0x0001, 0x0002, 0x0004, 0x0008,
1647 0x1013, 0x3032, 0x4044, 0x8088,
1648 0x106b, 0x30d6, 0x70fc, 0xe0a8,
1649 0x4857, 0xc4fe, 0x13cc, 0x3288,
1650 0x1ac5, 0x2f4a, 0x5394, 0xa1e8,
1651 0x1f39, 0x251e, 0xbd6c, 0x6bd8,
1652 0x15c1, 0x2a42, 0x89ac, 0x4758,
1653 0x2b03, 0x1602, 0x4f0c, 0xca08,
1654 0x1f07, 0x3a0e, 0x6b04, 0xbd08,
1655 0x8ba7, 0x465e, 0x244c, 0x1cc8,
1656 0x2b87, 0x164e, 0x642c, 0xdc18,
1657 0x40b9, 0x80de, 0x1094, 0x20e8,
1658 0x27db, 0x1eb6, 0x9dac, 0x7b58,
1659 0x11c1, 0x2242, 0x84ac, 0x4c58,
1660 0x1be5, 0x2d7a, 0x5e34, 0xa718,
1661 0x4b39, 0x8d1e, 0x14b4, 0x28d8,
1662 0x4c97, 0xc87e, 0x11fc, 0x33a8,
1663 0x8e97, 0x497e, 0x2ffc, 0x1aa8,
1664 0x16b3, 0x3d62, 0x4f34, 0x8518,
1665 0x1e2f, 0x391a, 0x5cac, 0xf858,
1666 0x1d9f, 0x3b7a, 0x572c, 0xfe18,
1667 0x15f5, 0x2a5a, 0x5264, 0xa3b8,
1668 0x1dbb, 0x3b66, 0x715c, 0xe3f8,
1669 0x4397, 0xc27e, 0x17fc, 0x3ea8,
1670 0x1617, 0x3d3e, 0x6464, 0xb8b8,
1671 0x23ff, 0x12aa, 0xab6c, 0x56d8,
1672 0x2dfb, 0x1ba6, 0x913c, 0x7328,
1673 0x185d, 0x2ca6, 0x7914, 0x9e28,
1674 0x171b, 0x3e36, 0x7d7c, 0xebe8,
1675 0x4199, 0x82ee, 0x19f4, 0x2e58,
1676 0x4807, 0xc40e, 0x130c, 0x3208,
1677 0x1905, 0x2e0a, 0x5804, 0xac08,
1678 0x213f, 0x132a, 0xadfc, 0x5ba8,
1679 0x19a9, 0x2efe, 0xb5cc, 0x6f88,
Doug Thompsonb1289d62009-04-27 16:37:05 +02001680};
1681
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001682static u16 x8_vectors[] = {
1683 0x0145, 0x028a, 0x2374, 0x43c8, 0xa1f0, 0x0520, 0x0a40, 0x1480,
1684 0x0211, 0x0422, 0x0844, 0x1088, 0x01b0, 0x44e0, 0x23c0, 0xed80,
1685 0x1011, 0x0116, 0x022c, 0x0458, 0x08b0, 0x8c60, 0x2740, 0x4e80,
1686 0x0411, 0x0822, 0x1044, 0x0158, 0x02b0, 0x2360, 0x46c0, 0xab80,
1687 0x0811, 0x1022, 0x012c, 0x0258, 0x04b0, 0x4660, 0x8cc0, 0x2780,
1688 0x2071, 0x40e2, 0xa0c4, 0x0108, 0x0210, 0x0420, 0x0840, 0x1080,
1689 0x4071, 0x80e2, 0x0104, 0x0208, 0x0410, 0x0820, 0x1040, 0x2080,
1690 0x8071, 0x0102, 0x0204, 0x0408, 0x0810, 0x1020, 0x2040, 0x4080,
1691 0x019d, 0x03d6, 0x136c, 0x2198, 0x50b0, 0xb2e0, 0x0740, 0x0e80,
1692 0x0189, 0x03ea, 0x072c, 0x0e58, 0x1cb0, 0x56e0, 0x37c0, 0xf580,
1693 0x01fd, 0x0376, 0x06ec, 0x0bb8, 0x1110, 0x2220, 0x4440, 0x8880,
1694 0x0163, 0x02c6, 0x1104, 0x0758, 0x0eb0, 0x2be0, 0x6140, 0xc280,
1695 0x02fd, 0x01c6, 0x0b5c, 0x1108, 0x07b0, 0x25a0, 0x8840, 0x6180,
1696 0x0801, 0x012e, 0x025c, 0x04b8, 0x1370, 0x26e0, 0x57c0, 0xb580,
1697 0x0401, 0x0802, 0x015c, 0x02b8, 0x22b0, 0x13e0, 0x7140, 0xe280,
1698 0x0201, 0x0402, 0x0804, 0x01b8, 0x11b0, 0x31a0, 0x8040, 0x7180,
1699 0x0101, 0x0202, 0x0404, 0x0808, 0x1010, 0x2020, 0x4040, 0x8080,
1700 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
1701 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
1702};
1703
1704static int decode_syndrome(u16 syndrome, u16 *vectors, int num_vecs,
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001705 int v_dim)
Doug Thompsonb1289d62009-04-27 16:37:05 +02001706{
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001707 unsigned int i, err_sym;
Doug Thompsonb1289d62009-04-27 16:37:05 +02001708
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001709 for (err_sym = 0; err_sym < num_vecs / v_dim; err_sym++) {
1710 u16 s = syndrome;
1711 int v_idx = err_sym * v_dim;
1712 int v_end = (err_sym + 1) * v_dim;
Doug Thompsonb1289d62009-04-27 16:37:05 +02001713
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001714 /* walk over all 16 bits of the syndrome */
1715 for (i = 1; i < (1U << 16); i <<= 1) {
1716
1717 /* if bit is set in that eigenvector... */
1718 if (v_idx < v_end && vectors[v_idx] & i) {
1719 u16 ev_comp = vectors[v_idx++];
1720
1721 /* ... and bit set in the modified syndrome, */
1722 if (s & i) {
1723 /* remove it. */
1724 s ^= ev_comp;
1725
1726 if (!s)
1727 return err_sym;
1728 }
1729
1730 } else if (s & i)
1731 /* can't get to zero, move to next symbol */
1732 break;
1733 }
Doug Thompsonb1289d62009-04-27 16:37:05 +02001734 }
1735
1736 debugf0("syndrome(%x) not found\n", syndrome);
1737 return -1;
1738}
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001739
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001740static int map_err_sym_to_channel(int err_sym, int sym_size)
1741{
1742 if (sym_size == 4)
1743 switch (err_sym) {
1744 case 0x20:
1745 case 0x21:
1746 return 0;
1747 break;
1748 case 0x22:
1749 case 0x23:
1750 return 1;
1751 break;
1752 default:
1753 return err_sym >> 4;
1754 break;
1755 }
1756 /* x8 symbols */
1757 else
1758 switch (err_sym) {
1759 /* imaginary bits not in a DIMM */
1760 case 0x10:
1761 WARN(1, KERN_ERR "Invalid error symbol: 0x%x\n",
1762 err_sym);
1763 return -1;
1764 break;
1765
1766 case 0x11:
1767 return 0;
1768 break;
1769 case 0x12:
1770 return 1;
1771 break;
1772 default:
1773 return err_sym >> 3;
1774 break;
1775 }
1776 return -1;
1777}
1778
1779static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
1780{
1781 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001782 int err_sym = -1;
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001783
Borislav Petkova3b7db02011-01-19 20:35:12 +01001784 if (pvt->ecc_sym_sz == 8)
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001785 err_sym = decode_syndrome(syndrome, x8_vectors,
1786 ARRAY_SIZE(x8_vectors),
Borislav Petkova3b7db02011-01-19 20:35:12 +01001787 pvt->ecc_sym_sz);
1788 else if (pvt->ecc_sym_sz == 4)
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001789 err_sym = decode_syndrome(syndrome, x4_vectors,
1790 ARRAY_SIZE(x4_vectors),
Borislav Petkova3b7db02011-01-19 20:35:12 +01001791 pvt->ecc_sym_sz);
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001792 else {
Borislav Petkova3b7db02011-01-19 20:35:12 +01001793 amd64_warn("Illegal syndrome type: %u\n", pvt->ecc_sym_sz);
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001794 return err_sym;
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001795 }
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001796
Borislav Petkova3b7db02011-01-19 20:35:12 +01001797 return map_err_sym_to_channel(err_sym, pvt->ecc_sym_sz);
Borislav Petkovbfc04ae2009-11-12 19:05:07 +01001798}
1799
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001800/*
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001801 * Handle any Correctable Errors (CEs) that have occurred. Check for valid ERROR
1802 * ADDRESS and process.
1803 */
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001804static void amd64_handle_ce(struct mem_ctl_info *mci, struct mce *m)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001805{
1806 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001807 u64 sys_addr;
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001808 u16 syndrome;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001809
1810 /* Ensure that the Error Address is VALID */
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001811 if (!(m->status & MCI_STATUS_ADDRV)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001812 amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001813 edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
1814 return;
1815 }
1816
Borislav Petkov70046622011-01-10 14:37:27 +01001817 sys_addr = get_error_address(m);
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001818 syndrome = extract_syndrome(m->status);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001819
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001820 amd64_mc_err(mci, "CE ERROR_ADDRESS= 0x%llx\n", sys_addr);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001821
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001822 pvt->ops->map_sysaddr_to_csrow(mci, sys_addr, syndrome);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001823}
1824
1825/* Handle any Un-correctable Errors (UEs) */
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001826static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001827{
Borislav Petkov1f6bcee2009-11-13 14:02:57 +01001828 struct mem_ctl_info *log_mci, *src_mci = NULL;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001829 int csrow;
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001830 u64 sys_addr;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001831 u32 page, offset;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001832
1833 log_mci = mci;
1834
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001835 if (!(m->status & MCI_STATUS_ADDRV)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001836 amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001837 edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
1838 return;
1839 }
1840
Borislav Petkov70046622011-01-10 14:37:27 +01001841 sys_addr = get_error_address(m);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001842
1843 /*
1844 * Find out which node the error address belongs to. This may be
1845 * different from the node that detected the error.
1846 */
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001847 src_mci = find_mc_by_sys_addr(mci, sys_addr);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001848 if (!src_mci) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001849 amd64_mc_err(mci, "ERROR ADDRESS (0x%lx) NOT mapped to a MC\n",
1850 (unsigned long)sys_addr);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001851 edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
1852 return;
1853 }
1854
1855 log_mci = src_mci;
1856
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001857 csrow = sys_addr_to_csrow(log_mci, sys_addr);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001858 if (csrow < 0) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001859 amd64_mc_err(mci, "ERROR_ADDRESS (0x%lx) NOT mapped to CS\n",
1860 (unsigned long)sys_addr);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001861 edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
1862 } else {
Borislav Petkov44e9e2e2009-10-26 15:00:19 +01001863 error_address_to_page_and_offset(sys_addr, &page, &offset);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001864 edac_mc_handle_ue(log_mci, page, offset, csrow, EDAC_MOD_STR);
1865 }
1866}
1867
Borislav Petkov549d0422009-07-24 13:51:42 +02001868static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001869 struct mce *m)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001870{
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001871 u16 ec = EC(m->status);
1872 u8 xec = XEC(m->status, 0x1f);
1873 u8 ecc_type = (m->status >> 45) & 0x3;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001874
Borislav Petkovb70ef012009-06-25 19:32:38 +02001875 /* Bail early out if this was an 'observed' error */
Borislav Petkov5980bb92011-01-07 16:26:49 +01001876 if (PP(ec) == NBSL_PP_OBS)
Borislav Petkovb70ef012009-06-25 19:32:38 +02001877 return;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001878
Borislav Petkovecaf5602009-07-23 16:32:01 +02001879 /* Do only ECC errors */
1880 if (xec && xec != F10_NBSL_EXT_ERR_ECC)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001881 return;
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001882
Borislav Petkovecaf5602009-07-23 16:32:01 +02001883 if (ecc_type == 2)
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001884 amd64_handle_ce(mci, m);
Borislav Petkovecaf5602009-07-23 16:32:01 +02001885 else if (ecc_type == 1)
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001886 amd64_handle_ue(mci, m);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001887}
1888
Borislav Petkov7cfd4a82010-09-01 14:45:20 +02001889void amd64_decode_bus_error(int node_id, struct mce *m, u32 nbcfg)
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001890{
Borislav Petkovcc4d8862010-10-13 16:11:59 +02001891 struct mem_ctl_info *mci = mcis[node_id];
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001892
Borislav Petkovf192c7b2011-01-10 14:24:32 +01001893 __amd64_decode_bus_error(mci, m);
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001894}
Doug Thompsond27bf6f2009-05-06 17:55:27 +02001895
Doug Thompson0ec449e2009-04-27 19:41:25 +02001896/*
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001897 * Use pvt->F2 which contains the F2 CPU PCI device to get the related
Borislav Petkovbbd0c1f62010-10-01 19:27:58 +02001898 * F1 (AddrMap) and F3 (Misc) devices. Return negative value on error.
Doug Thompson0ec449e2009-04-27 19:41:25 +02001899 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02001900static int reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 f1_id, u16 f3_id)
Doug Thompson0ec449e2009-04-27 19:41:25 +02001901{
Doug Thompson0ec449e2009-04-27 19:41:25 +02001902 /* Reserve the ADDRESS MAP Device */
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001903 pvt->F1 = pci_get_related_function(pvt->F2->vendor, f1_id, pvt->F2);
1904 if (!pvt->F1) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001905 amd64_err("error address map device not found: "
1906 "vendor %x device 0x%x (broken BIOS?)\n",
1907 PCI_VENDOR_ID_AMD, f1_id);
Borislav Petkovbbd0c1f62010-10-01 19:27:58 +02001908 return -ENODEV;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001909 }
1910
1911 /* Reserve the MISC Device */
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001912 pvt->F3 = pci_get_related_function(pvt->F2->vendor, f3_id, pvt->F2);
1913 if (!pvt->F3) {
1914 pci_dev_put(pvt->F1);
1915 pvt->F1 = NULL;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001916
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02001917 amd64_err("error F3 device not found: "
1918 "vendor %x device 0x%x (broken BIOS?)\n",
1919 PCI_VENDOR_ID_AMD, f3_id);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001920
Borislav Petkovbbd0c1f62010-10-01 19:27:58 +02001921 return -ENODEV;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001922 }
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001923 debugf1("F1: %s\n", pci_name(pvt->F1));
1924 debugf1("F2: %s\n", pci_name(pvt->F2));
1925 debugf1("F3: %s\n", pci_name(pvt->F3));
Doug Thompson0ec449e2009-04-27 19:41:25 +02001926
1927 return 0;
1928}
1929
Borislav Petkov360b7f32010-10-15 19:25:38 +02001930static void free_mc_sibling_devs(struct amd64_pvt *pvt)
Doug Thompson0ec449e2009-04-27 19:41:25 +02001931{
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001932 pci_dev_put(pvt->F1);
1933 pci_dev_put(pvt->F3);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001934}
1935
1936/*
1937 * Retrieve the hardware registers of the memory controller (this includes the
1938 * 'Address Map' and 'Misc' device regs)
1939 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02001940static void read_mc_regs(struct amd64_pvt *pvt)
Doug Thompson0ec449e2009-04-27 19:41:25 +02001941{
Borislav Petkova3b7db02011-01-19 20:35:12 +01001942 struct cpuinfo_x86 *c = &boot_cpu_data;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001943 u64 msr_val;
Borislav Petkovad6a32e2010-03-09 12:46:00 +01001944 u32 tmp;
Borislav Petkove761359a2011-02-21 19:49:01 +01001945 unsigned range;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001946
1947 /*
1948 * Retrieve TOP_MEM and TOP_MEM2; no masking off of reserved bits since
1949 * those are Read-As-Zero
1950 */
Borislav Petkove97f8bb2009-10-12 15:27:45 +02001951 rdmsrl(MSR_K8_TOP_MEM1, pvt->top_mem);
1952 debugf0(" TOP_MEM: 0x%016llx\n", pvt->top_mem);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001953
1954 /* check first whether TOP_MEM2 is enabled */
1955 rdmsrl(MSR_K8_SYSCFG, msr_val);
1956 if (msr_val & (1U << 21)) {
Borislav Petkove97f8bb2009-10-12 15:27:45 +02001957 rdmsrl(MSR_K8_TOP_MEM2, pvt->top_mem2);
1958 debugf0(" TOP_MEM2: 0x%016llx\n", pvt->top_mem2);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001959 } else
1960 debugf0(" TOP_MEM2 disabled.\n");
1961
Borislav Petkov5980bb92011-01-07 16:26:49 +01001962 amd64_read_pci_cfg(pvt->F3, NBCAP, &pvt->nbcap);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001963
Borislav Petkov5a5d2372011-01-17 17:52:57 +01001964 read_dram_ctl_register(pvt);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001965
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001966 for (range = 0; range < DRAM_RANGES; range++) {
1967 u8 rw;
Doug Thompson0ec449e2009-04-27 19:41:25 +02001968
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001969 /* read settings for this DRAM range */
1970 read_dram_base_limit_regs(pvt, range);
Borislav Petkove97f8bb2009-10-12 15:27:45 +02001971
Borislav Petkov7f19bf72010-10-21 18:52:53 +02001972 rw = dram_rw(pvt, range);
1973 if (!rw)
1974 continue;
1975
1976 debugf1(" DRAM range[%d], base: 0x%016llx; limit: 0x%016llx\n",
1977 range,
1978 get_dram_base(pvt, range),
1979 get_dram_limit(pvt, range));
1980
1981 debugf1(" IntlvEn=%s; Range access: %s%s IntlvSel=%d DstNode=%d\n",
1982 dram_intlv_en(pvt, range) ? "Enabled" : "Disabled",
1983 (rw & 0x1) ? "R" : "-",
1984 (rw & 0x2) ? "W" : "-",
1985 dram_intlv_sel(pvt, range),
1986 dram_dst_node(pvt, range));
Doug Thompson0ec449e2009-04-27 19:41:25 +02001987 }
1988
Borislav Petkovb2b0c602010-10-08 18:32:29 +02001989 read_dct_base_mask(pvt);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001990
Borislav Petkovbc21fa52010-11-11 17:29:13 +01001991 amd64_read_pci_cfg(pvt->F1, DHAR, &pvt->dhar);
Borislav Petkov525a1b22010-12-21 15:53:27 +01001992 amd64_read_dct_pci_cfg(pvt, DBAM0, &pvt->dbam0);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001993
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02001994 amd64_read_pci_cfg(pvt->F3, F10_ONLINE_SPARE, &pvt->online_spare);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001995
Borislav Petkovcb328502010-12-22 14:28:24 +01001996 amd64_read_dct_pci_cfg(pvt, DCLR0, &pvt->dclr0);
1997 amd64_read_dct_pci_cfg(pvt, DCHR0, &pvt->dchr0);
Doug Thompson0ec449e2009-04-27 19:41:25 +02001998
Borislav Petkov78da1212010-12-22 19:31:45 +01001999 if (!dct_ganging_enabled(pvt)) {
Borislav Petkovcb328502010-12-22 14:28:24 +01002000 amd64_read_dct_pci_cfg(pvt, DCLR1, &pvt->dclr1);
2001 amd64_read_dct_pci_cfg(pvt, DCHR1, &pvt->dchr1);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002002 }
Borislav Petkovad6a32e2010-03-09 12:46:00 +01002003
Borislav Petkova3b7db02011-01-19 20:35:12 +01002004 pvt->ecc_sym_sz = 4;
2005
2006 if (c->x86 >= 0x10) {
Borislav Petkovb2b0c602010-10-08 18:32:29 +02002007 amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
Borislav Petkov525a1b22010-12-21 15:53:27 +01002008 amd64_read_dct_pci_cfg(pvt, DBAM1, &pvt->dbam1);
Borislav Petkova3b7db02011-01-19 20:35:12 +01002009
2010 /* F10h, revD and later can do x8 ECC too */
2011 if ((c->x86 > 0x10 || c->x86_model > 7) && tmp & BIT(25))
2012 pvt->ecc_sym_sz = 8;
Borislav Petkov525a1b22010-12-21 15:53:27 +01002013 }
Borislav Petkovb2b0c602010-10-08 18:32:29 +02002014 dump_misc_regs(pvt);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002015}
2016
2017/*
2018 * NOTE: CPU Revision Dependent code
2019 *
2020 * Input:
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002021 * @csrow_nr ChipSelect Row Number (0..NUM_CHIPSELECTS-1)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002022 * k8 private pointer to -->
2023 * DRAM Bank Address mapping register
2024 * node_id
2025 * DCL register where dual_channel_active is
2026 *
2027 * The DBAM register consists of 4 sets of 4 bits each definitions:
2028 *
2029 * Bits: CSROWs
2030 * 0-3 CSROWs 0 and 1
2031 * 4-7 CSROWs 2 and 3
2032 * 8-11 CSROWs 4 and 5
2033 * 12-15 CSROWs 6 and 7
2034 *
2035 * Values range from: 0 to 15
2036 * The meaning of the values depends on CPU revision and dual-channel state,
2037 * see relevant BKDG more info.
2038 *
2039 * The memory controller provides for total of only 8 CSROWs in its current
2040 * architecture. Each "pair" of CSROWs normally represents just one DIMM in
2041 * single channel or two (2) DIMMs in dual channel mode.
2042 *
2043 * The following code logic collapses the various tables for CSROW based on CPU
2044 * revision.
2045 *
2046 * Returns:
2047 * The number of PAGE_SIZE pages on the specified CSROW number it
2048 * encompasses
2049 *
2050 */
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01002051static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002052{
Borislav Petkov1433eb92009-10-21 13:44:36 +02002053 u32 cs_mode, nr_pages;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002054
2055 /*
2056 * The math on this doesn't look right on the surface because x/2*4 can
2057 * be simplified to x*2 but this expression makes use of the fact that
2058 * it is integral math where 1/2=0. This intermediate value becomes the
2059 * number of bits to shift the DBAM register to extract the proper CSROW
2060 * field.
2061 */
Borislav Petkov1433eb92009-10-21 13:44:36 +02002062 cs_mode = (pvt->dbam0 >> ((csrow_nr / 2) * 4)) & 0xF;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002063
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01002064 nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002065
2066 /*
2067 * If dual channel then double the memory size of single channel.
2068 * Channel count is 1 or 2
2069 */
2070 nr_pages <<= (pvt->channel_count - 1);
2071
Borislav Petkov1433eb92009-10-21 13:44:36 +02002072 debugf0(" (csrow=%d) DBAM map index= %d\n", csrow_nr, cs_mode);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002073 debugf0(" nr_pages= %u channel-count = %d\n",
2074 nr_pages, pvt->channel_count);
2075
2076 return nr_pages;
2077}
2078
2079/*
2080 * Initialize the array of csrow attribute instances, based on the values
2081 * from pci config hardware registers.
2082 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02002083static int init_csrows(struct mem_ctl_info *mci)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002084{
2085 struct csrow_info *csrow;
Borislav Petkov2299ef72010-10-15 17:44:04 +02002086 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002087 u64 input_addr_min, input_addr_max, sys_addr, base, mask;
Borislav Petkov2299ef72010-10-15 17:44:04 +02002088 u32 val;
Borislav Petkov6ba5dcd2009-10-13 19:26:55 +02002089 int i, empty = 1;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002090
Borislav Petkova97fa682010-12-23 14:07:18 +01002091 amd64_read_pci_cfg(pvt->F3, NBCFG, &val);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002092
Borislav Petkov2299ef72010-10-15 17:44:04 +02002093 pvt->nbcfg = val;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002094
Borislav Petkov2299ef72010-10-15 17:44:04 +02002095 debugf0("node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
2096 pvt->mc_node_id, val,
Borislav Petkova97fa682010-12-23 14:07:18 +01002097 !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
Doug Thompson0ec449e2009-04-27 19:41:25 +02002098
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002099 for_each_chip_select(i, 0, pvt) {
Doug Thompson0ec449e2009-04-27 19:41:25 +02002100 csrow = &mci->csrows[i];
2101
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002102 if (!csrow_enabled(i, 0, pvt)) {
Doug Thompson0ec449e2009-04-27 19:41:25 +02002103 debugf1("----CSROW %d EMPTY for node %d\n", i,
2104 pvt->mc_node_id);
2105 continue;
2106 }
2107
2108 debugf1("----CSROW %d VALID for MC node %d\n",
2109 i, pvt->mc_node_id);
2110
2111 empty = 0;
Borislav Petkov41d8bfa2011-01-18 19:16:08 +01002112 csrow->nr_pages = amd64_csrow_nr_pages(pvt, 0, i);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002113 find_csrow_limits(mci, i, &input_addr_min, &input_addr_max);
2114 sys_addr = input_addr_to_sys_addr(mci, input_addr_min);
2115 csrow->first_page = (u32) (sys_addr >> PAGE_SHIFT);
2116 sys_addr = input_addr_to_sys_addr(mci, input_addr_max);
2117 csrow->last_page = (u32) (sys_addr >> PAGE_SHIFT);
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002118
2119 get_cs_base_and_mask(pvt, i, 0, &base, &mask);
2120 csrow->page_mask = ~mask;
Doug Thompson0ec449e2009-04-27 19:41:25 +02002121 /* 8 bytes of resolution */
2122
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002123 csrow->mtype = amd64_determine_memory_type(pvt, i);
Doug Thompson0ec449e2009-04-27 19:41:25 +02002124
2125 debugf1(" for MC node %d csrow %d:\n", pvt->mc_node_id, i);
2126 debugf1(" input_addr_min: 0x%lx input_addr_max: 0x%lx\n",
2127 (unsigned long)input_addr_min,
2128 (unsigned long)input_addr_max);
2129 debugf1(" sys_addr: 0x%lx page_mask: 0x%lx\n",
2130 (unsigned long)sys_addr, csrow->page_mask);
2131 debugf1(" nr_pages: %u first_page: 0x%lx "
2132 "last_page: 0x%lx\n",
2133 (unsigned)csrow->nr_pages,
2134 csrow->first_page, csrow->last_page);
2135
2136 /*
2137 * determine whether CHIPKILL or JUST ECC or NO ECC is operating
2138 */
Borislav Petkova97fa682010-12-23 14:07:18 +01002139 if (pvt->nbcfg & NBCFG_ECC_ENABLE)
Doug Thompson0ec449e2009-04-27 19:41:25 +02002140 csrow->edac_mode =
Borislav Petkova97fa682010-12-23 14:07:18 +01002141 (pvt->nbcfg & NBCFG_CHIPKILL) ?
Doug Thompson0ec449e2009-04-27 19:41:25 +02002142 EDAC_S4ECD4ED : EDAC_SECDED;
2143 else
2144 csrow->edac_mode = EDAC_NONE;
2145 }
2146
2147 return empty;
2148}
Doug Thompsond27bf6f2009-05-06 17:55:27 +02002149
Borislav Petkov06724532009-09-16 13:05:46 +02002150/* get all cores on this DCT */
Borislav Petkovb487c332011-02-21 18:55:00 +01002151static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, unsigned nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02002152{
Borislav Petkov06724532009-09-16 13:05:46 +02002153 int cpu;
Doug Thompsonf9431992009-04-27 19:46:08 +02002154
Borislav Petkov06724532009-09-16 13:05:46 +02002155 for_each_online_cpu(cpu)
2156 if (amd_get_nb_id(cpu) == nid)
2157 cpumask_set_cpu(cpu, mask);
Doug Thompsonf9431992009-04-27 19:46:08 +02002158}
2159
2160/* check MCG_CTL on all the cpus on this node */
Borislav Petkovb487c332011-02-21 18:55:00 +01002161static bool amd64_nb_mce_bank_enabled_on_node(unsigned nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02002162{
Rusty Russellba578cb2009-11-03 14:56:35 +10302163 cpumask_var_t mask;
Borislav Petkov50542252009-12-11 18:14:40 +01002164 int cpu, nbe;
Borislav Petkov06724532009-09-16 13:05:46 +02002165 bool ret = false;
Doug Thompsonf9431992009-04-27 19:46:08 +02002166
Rusty Russellba578cb2009-11-03 14:56:35 +10302167 if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002168 amd64_warn("%s: Error allocating mask\n", __func__);
Rusty Russellba578cb2009-11-03 14:56:35 +10302169 return false;
2170 }
Borislav Petkov06724532009-09-16 13:05:46 +02002171
Rusty Russellba578cb2009-11-03 14:56:35 +10302172 get_cpus_on_this_dct_cpumask(mask, nid);
Borislav Petkov06724532009-09-16 13:05:46 +02002173
Rusty Russellba578cb2009-11-03 14:56:35 +10302174 rdmsr_on_cpus(mask, MSR_IA32_MCG_CTL, msrs);
Borislav Petkov06724532009-09-16 13:05:46 +02002175
Rusty Russellba578cb2009-11-03 14:56:35 +10302176 for_each_cpu(cpu, mask) {
Borislav Petkov50542252009-12-11 18:14:40 +01002177 struct msr *reg = per_cpu_ptr(msrs, cpu);
Borislav Petkov5980bb92011-01-07 16:26:49 +01002178 nbe = reg->l & MSR_MCGCTL_NBE;
Borislav Petkov06724532009-09-16 13:05:46 +02002179
2180 debugf0("core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n",
Borislav Petkov50542252009-12-11 18:14:40 +01002181 cpu, reg->q,
Borislav Petkov06724532009-09-16 13:05:46 +02002182 (nbe ? "enabled" : "disabled"));
2183
2184 if (!nbe)
2185 goto out;
Borislav Petkov06724532009-09-16 13:05:46 +02002186 }
2187 ret = true;
2188
2189out:
Rusty Russellba578cb2009-11-03 14:56:35 +10302190 free_cpumask_var(mask);
Doug Thompsonf9431992009-04-27 19:46:08 +02002191 return ret;
2192}
2193
Borislav Petkov2299ef72010-10-15 17:44:04 +02002194static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002195{
2196 cpumask_var_t cmask;
Borislav Petkov50542252009-12-11 18:14:40 +01002197 int cpu;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002198
2199 if (!zalloc_cpumask_var(&cmask, GFP_KERNEL)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002200 amd64_warn("%s: error allocating mask\n", __func__);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002201 return false;
2202 }
2203
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002204 get_cpus_on_this_dct_cpumask(cmask, nid);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002205
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002206 rdmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
2207
2208 for_each_cpu(cpu, cmask) {
2209
Borislav Petkov50542252009-12-11 18:14:40 +01002210 struct msr *reg = per_cpu_ptr(msrs, cpu);
2211
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002212 if (on) {
Borislav Petkov5980bb92011-01-07 16:26:49 +01002213 if (reg->l & MSR_MCGCTL_NBE)
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002214 s->flags.nb_mce_enable = 1;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002215
Borislav Petkov5980bb92011-01-07 16:26:49 +01002216 reg->l |= MSR_MCGCTL_NBE;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002217 } else {
2218 /*
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002219 * Turn off NB MCE reporting only when it was off before
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002220 */
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002221 if (!s->flags.nb_mce_enable)
Borislav Petkov5980bb92011-01-07 16:26:49 +01002222 reg->l &= ~MSR_MCGCTL_NBE;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002223 }
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002224 }
2225 wrmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
2226
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002227 free_cpumask_var(cmask);
2228
2229 return 0;
2230}
2231
Borislav Petkov2299ef72010-10-15 17:44:04 +02002232static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
2233 struct pci_dev *F3)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002234{
Borislav Petkov2299ef72010-10-15 17:44:04 +02002235 bool ret = true;
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002236 u32 value, mask = 0x3; /* UECC/CECC enable */
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002237
Borislav Petkov2299ef72010-10-15 17:44:04 +02002238 if (toggle_ecc_err_reporting(s, nid, ON)) {
2239 amd64_warn("Error enabling ECC reporting over MCGCTL!\n");
2240 return false;
2241 }
2242
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002243 amd64_read_pci_cfg(F3, NBCTL, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002244
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002245 s->old_nbctl = value & mask;
2246 s->nbctl_valid = true;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002247
2248 value |= mask;
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002249 amd64_write_pci_cfg(F3, NBCTL, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002250
Borislav Petkova97fa682010-12-23 14:07:18 +01002251 amd64_read_pci_cfg(F3, NBCFG, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002252
Borislav Petkova97fa682010-12-23 14:07:18 +01002253 debugf0("1: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
2254 nid, value, !!(value & NBCFG_ECC_ENABLE));
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002255
Borislav Petkova97fa682010-12-23 14:07:18 +01002256 if (!(value & NBCFG_ECC_ENABLE)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002257 amd64_warn("DRAM ECC disabled on this node, enabling...\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002258
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002259 s->flags.nb_ecc_prev = 0;
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002260
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002261 /* Attempt to turn on DRAM ECC Enable */
Borislav Petkova97fa682010-12-23 14:07:18 +01002262 value |= NBCFG_ECC_ENABLE;
2263 amd64_write_pci_cfg(F3, NBCFG, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002264
Borislav Petkova97fa682010-12-23 14:07:18 +01002265 amd64_read_pci_cfg(F3, NBCFG, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002266
Borislav Petkova97fa682010-12-23 14:07:18 +01002267 if (!(value & NBCFG_ECC_ENABLE)) {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002268 amd64_warn("Hardware rejected DRAM ECC enable,"
2269 "check memory DIMM configuration.\n");
Borislav Petkov2299ef72010-10-15 17:44:04 +02002270 ret = false;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002271 } else {
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002272 amd64_info("Hardware accepted DRAM ECC Enable\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002273 }
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002274 } else {
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002275 s->flags.nb_ecc_prev = 1;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002276 }
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002277
Borislav Petkova97fa682010-12-23 14:07:18 +01002278 debugf0("2: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
2279 nid, value, !!(value & NBCFG_ECC_ENABLE));
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002280
Borislav Petkov2299ef72010-10-15 17:44:04 +02002281 return ret;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002282}
2283
Borislav Petkov360b7f32010-10-15 19:25:38 +02002284static void restore_ecc_error_reporting(struct ecc_settings *s, u8 nid,
2285 struct pci_dev *F3)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002286{
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002287 u32 value, mask = 0x3; /* UECC/CECC enable */
2288
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002289
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002290 if (!s->nbctl_valid)
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002291 return;
2292
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002293 amd64_read_pci_cfg(F3, NBCTL, &value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002294 value &= ~mask;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002295 value |= s->old_nbctl;
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002296
Borislav Petkovc9f4f262010-12-22 19:48:20 +01002297 amd64_write_pci_cfg(F3, NBCTL, value);
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002298
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002299 /* restore previous BIOS DRAM ECC "off" setting we force-enabled */
2300 if (!s->flags.nb_ecc_prev) {
Borislav Petkova97fa682010-12-23 14:07:18 +01002301 amd64_read_pci_cfg(F3, NBCFG, &value);
2302 value &= ~NBCFG_ECC_ENABLE;
2303 amd64_write_pci_cfg(F3, NBCFG, value);
Borislav Petkovd95cf4d2010-02-24 14:49:47 +01002304 }
2305
2306 /* restore the NB Enable MCGCTL bit */
Borislav Petkov2299ef72010-10-15 17:44:04 +02002307 if (toggle_ecc_err_reporting(s, nid, OFF))
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002308 amd64_warn("Error restoring NB MCGCTL settings!\n");
Borislav Petkovf6d6ae92009-11-03 15:29:26 +01002309}
2310
Doug Thompsonf9431992009-04-27 19:46:08 +02002311/*
Borislav Petkov2299ef72010-10-15 17:44:04 +02002312 * EDAC requires that the BIOS have ECC enabled before
2313 * taking over the processing of ECC errors. A command line
2314 * option allows to force-enable hardware ECC later in
2315 * enable_ecc_error_reporting().
Doug Thompsonf9431992009-04-27 19:46:08 +02002316 */
Borislav Petkovcab4d272010-02-11 17:15:57 +01002317static const char *ecc_msg =
2318 "ECC disabled in the BIOS or no ECC capability, module will not load.\n"
2319 " Either enable ECC checking or force module loading by setting "
2320 "'ecc_enable_override'.\n"
2321 " (Note that use of the override may cause unknown side effects.)\n";
Borislav Petkovbe3468e2009-08-05 15:47:22 +02002322
Borislav Petkov2299ef72010-10-15 17:44:04 +02002323static bool ecc_enabled(struct pci_dev *F3, u8 nid)
Doug Thompsonf9431992009-04-27 19:46:08 +02002324{
2325 u32 value;
Borislav Petkov2299ef72010-10-15 17:44:04 +02002326 u8 ecc_en = 0;
Borislav Petkov06724532009-09-16 13:05:46 +02002327 bool nb_mce_en = false;
Doug Thompsonf9431992009-04-27 19:46:08 +02002328
Borislav Petkova97fa682010-12-23 14:07:18 +01002329 amd64_read_pci_cfg(F3, NBCFG, &value);
Doug Thompsonf9431992009-04-27 19:46:08 +02002330
Borislav Petkova97fa682010-12-23 14:07:18 +01002331 ecc_en = !!(value & NBCFG_ECC_ENABLE);
Borislav Petkov2299ef72010-10-15 17:44:04 +02002332 amd64_info("DRAM ECC %s.\n", (ecc_en ? "enabled" : "disabled"));
Doug Thompsonf9431992009-04-27 19:46:08 +02002333
Borislav Petkov2299ef72010-10-15 17:44:04 +02002334 nb_mce_en = amd64_nb_mce_bank_enabled_on_node(nid);
Borislav Petkov06724532009-09-16 13:05:46 +02002335 if (!nb_mce_en)
Borislav Petkov2299ef72010-10-15 17:44:04 +02002336 amd64_notice("NB MCE bank disabled, set MSR "
2337 "0x%08x[4] on node %d to enable.\n",
2338 MSR_IA32_MCG_CTL, nid);
Doug Thompsonf9431992009-04-27 19:46:08 +02002339
Borislav Petkov2299ef72010-10-15 17:44:04 +02002340 if (!ecc_en || !nb_mce_en) {
2341 amd64_notice("%s", ecc_msg);
2342 return false;
Borislav Petkov43f5e682009-12-21 18:55:18 +01002343 }
Borislav Petkov2299ef72010-10-15 17:44:04 +02002344 return true;
Doug Thompsonf9431992009-04-27 19:46:08 +02002345}
2346
Doug Thompson7d6034d2009-04-27 20:01:01 +02002347struct mcidev_sysfs_attribute sysfs_attrs[ARRAY_SIZE(amd64_dbg_attrs) +
2348 ARRAY_SIZE(amd64_inj_attrs) +
2349 1];
2350
2351struct mcidev_sysfs_attribute terminator = { .attr = { .name = NULL } };
2352
Borislav Petkov360b7f32010-10-15 19:25:38 +02002353static void set_mc_sysfs_attrs(struct mem_ctl_info *mci)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002354{
2355 unsigned int i = 0, j = 0;
2356
2357 for (; i < ARRAY_SIZE(amd64_dbg_attrs); i++)
2358 sysfs_attrs[i] = amd64_dbg_attrs[i];
2359
Borislav Petkova135cef2010-11-26 19:24:44 +01002360 if (boot_cpu_data.x86 >= 0x10)
2361 for (j = 0; j < ARRAY_SIZE(amd64_inj_attrs); j++, i++)
2362 sysfs_attrs[i] = amd64_inj_attrs[j];
Doug Thompson7d6034d2009-04-27 20:01:01 +02002363
2364 sysfs_attrs[i] = terminator;
2365
2366 mci->mc_driver_sysfs_attributes = sysfs_attrs;
2367}
2368
Borislav Petkovdf71a052011-01-19 18:15:10 +01002369static void setup_mci_misc_attrs(struct mem_ctl_info *mci,
2370 struct amd64_family_type *fam)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002371{
2372 struct amd64_pvt *pvt = mci->pvt_info;
2373
2374 mci->mtype_cap = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2;
2375 mci->edac_ctl_cap = EDAC_FLAG_NONE;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002376
Borislav Petkov5980bb92011-01-07 16:26:49 +01002377 if (pvt->nbcap & NBCAP_SECDED)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002378 mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
2379
Borislav Petkov5980bb92011-01-07 16:26:49 +01002380 if (pvt->nbcap & NBCAP_CHIPKILL)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002381 mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
2382
2383 mci->edac_cap = amd64_determine_edac_cap(pvt);
2384 mci->mod_name = EDAC_MOD_STR;
2385 mci->mod_ver = EDAC_AMD64_VERSION;
Borislav Petkovdf71a052011-01-19 18:15:10 +01002386 mci->ctl_name = fam->ctl_name;
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002387 mci->dev_name = pci_name(pvt->F2);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002388 mci->ctl_page_to_phys = NULL;
2389
Doug Thompson7d6034d2009-04-27 20:01:01 +02002390 /* memory scrubber interface */
2391 mci->set_sdram_scrub_rate = amd64_set_scrub_rate;
2392 mci->get_sdram_scrub_rate = amd64_get_scrub_rate;
2393}
2394
Borislav Petkov0092b202010-10-01 19:20:05 +02002395/*
2396 * returns a pointer to the family descriptor on success, NULL otherwise.
2397 */
2398static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)
Borislav Petkov395ae782010-10-01 18:38:19 +02002399{
Borislav Petkov0092b202010-10-01 19:20:05 +02002400 u8 fam = boot_cpu_data.x86;
2401 struct amd64_family_type *fam_type = NULL;
2402
2403 switch (fam) {
Borislav Petkov395ae782010-10-01 18:38:19 +02002404 case 0xf:
Borislav Petkov0092b202010-10-01 19:20:05 +02002405 fam_type = &amd64_family_types[K8_CPUS];
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002406 pvt->ops = &amd64_family_types[K8_CPUS].ops;
Borislav Petkov395ae782010-10-01 18:38:19 +02002407 break;
Borislav Petkovdf71a052011-01-19 18:15:10 +01002408
Borislav Petkov395ae782010-10-01 18:38:19 +02002409 case 0x10:
Borislav Petkov0092b202010-10-01 19:20:05 +02002410 fam_type = &amd64_family_types[F10_CPUS];
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002411 pvt->ops = &amd64_family_types[F10_CPUS].ops;
Borislav Petkovdf71a052011-01-19 18:15:10 +01002412 break;
2413
2414 case 0x15:
2415 fam_type = &amd64_family_types[F15_CPUS];
2416 pvt->ops = &amd64_family_types[F15_CPUS].ops;
Borislav Petkov395ae782010-10-01 18:38:19 +02002417 break;
2418
2419 default:
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002420 amd64_err("Unsupported family!\n");
Borislav Petkov0092b202010-10-01 19:20:05 +02002421 return NULL;
Borislav Petkov395ae782010-10-01 18:38:19 +02002422 }
Borislav Petkov0092b202010-10-01 19:20:05 +02002423
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002424 pvt->ext_model = boot_cpu_data.x86_model >> 4;
2425
Borislav Petkovdf71a052011-01-19 18:15:10 +01002426 amd64_info("%s %sdetected (node %d).\n", fam_type->ctl_name,
Borislav Petkov0092b202010-10-01 19:20:05 +02002427 (fam == 0xf ?
Borislav Petkov24f9a7f2010-10-07 18:29:15 +02002428 (pvt->ext_model >= K8_REV_F ? "revF or later "
2429 : "revE or earlier ")
2430 : ""), pvt->mc_node_id);
Borislav Petkov0092b202010-10-01 19:20:05 +02002431 return fam_type;
Borislav Petkov395ae782010-10-01 18:38:19 +02002432}
2433
Borislav Petkov2299ef72010-10-15 17:44:04 +02002434static int amd64_init_one_instance(struct pci_dev *F2)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002435{
2436 struct amd64_pvt *pvt = NULL;
Borislav Petkov0092b202010-10-01 19:20:05 +02002437 struct amd64_family_type *fam_type = NULL;
Borislav Petkov360b7f32010-10-15 19:25:38 +02002438 struct mem_ctl_info *mci = NULL;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002439 int err = 0, ret;
Borislav Petkov360b7f32010-10-15 19:25:38 +02002440 u8 nid = get_node_id(F2);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002441
2442 ret = -ENOMEM;
2443 pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
2444 if (!pvt)
Borislav Petkov360b7f32010-10-15 19:25:38 +02002445 goto err_ret;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002446
Borislav Petkov360b7f32010-10-15 19:25:38 +02002447 pvt->mc_node_id = nid;
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002448 pvt->F2 = F2;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002449
Borislav Petkov395ae782010-10-01 18:38:19 +02002450 ret = -EINVAL;
Borislav Petkov0092b202010-10-01 19:20:05 +02002451 fam_type = amd64_per_family_init(pvt);
2452 if (!fam_type)
Borislav Petkov395ae782010-10-01 18:38:19 +02002453 goto err_free;
2454
Doug Thompson7d6034d2009-04-27 20:01:01 +02002455 ret = -ENODEV;
Borislav Petkov360b7f32010-10-15 19:25:38 +02002456 err = reserve_mc_sibling_devs(pvt, fam_type->f1_id, fam_type->f3_id);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002457 if (err)
2458 goto err_free;
2459
Borislav Petkov360b7f32010-10-15 19:25:38 +02002460 read_mc_regs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002461
Doug Thompson7d6034d2009-04-27 20:01:01 +02002462 /*
2463 * We need to determine how many memory channels there are. Then use
2464 * that information for calculating the size of the dynamic instance
Borislav Petkov360b7f32010-10-15 19:25:38 +02002465 * tables in the 'mci' structure.
Doug Thompson7d6034d2009-04-27 20:01:01 +02002466 */
Borislav Petkov360b7f32010-10-15 19:25:38 +02002467 ret = -EINVAL;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002468 pvt->channel_count = pvt->ops->early_channel_count(pvt);
2469 if (pvt->channel_count < 0)
Borislav Petkov360b7f32010-10-15 19:25:38 +02002470 goto err_siblings;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002471
2472 ret = -ENOMEM;
Borislav Petkov11c75ea2010-11-29 19:49:02 +01002473 mci = edac_mc_alloc(0, pvt->csels[0].b_cnt, pvt->channel_count, nid);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002474 if (!mci)
Borislav Petkov360b7f32010-10-15 19:25:38 +02002475 goto err_siblings;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002476
2477 mci->pvt_info = pvt;
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002478 mci->dev = &pvt->F2->dev;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002479
Borislav Petkovdf71a052011-01-19 18:15:10 +01002480 setup_mci_misc_attrs(mci, fam_type);
Borislav Petkov360b7f32010-10-15 19:25:38 +02002481
2482 if (init_csrows(mci))
Doug Thompson7d6034d2009-04-27 20:01:01 +02002483 mci->edac_cap = EDAC_FLAG_NONE;
2484
Borislav Petkov360b7f32010-10-15 19:25:38 +02002485 set_mc_sysfs_attrs(mci);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002486
2487 ret = -ENODEV;
2488 if (edac_mc_add_mc(mci)) {
2489 debugf1("failed edac_mc_add_mc()\n");
2490 goto err_add_mc;
2491 }
2492
Borislav Petkov549d0422009-07-24 13:51:42 +02002493 /* register stuff with EDAC MCE */
2494 if (report_gart_errors)
2495 amd_report_gart_errors(true);
2496
2497 amd_register_ecc_decoder(amd64_decode_bus_error);
2498
Borislav Petkov360b7f32010-10-15 19:25:38 +02002499 mcis[nid] = mci;
2500
2501 atomic_inc(&drv_instances);
2502
Doug Thompson7d6034d2009-04-27 20:01:01 +02002503 return 0;
2504
2505err_add_mc:
2506 edac_mc_free(mci);
2507
Borislav Petkov360b7f32010-10-15 19:25:38 +02002508err_siblings:
2509 free_mc_sibling_devs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002510
Borislav Petkov360b7f32010-10-15 19:25:38 +02002511err_free:
2512 kfree(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002513
Borislav Petkov360b7f32010-10-15 19:25:38 +02002514err_ret:
Doug Thompson7d6034d2009-04-27 20:01:01 +02002515 return ret;
2516}
2517
Borislav Petkov2299ef72010-10-15 17:44:04 +02002518static int __devinit amd64_probe_one_instance(struct pci_dev *pdev,
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002519 const struct pci_device_id *mc_type)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002520{
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002521 u8 nid = get_node_id(pdev);
Borislav Petkov2299ef72010-10-15 17:44:04 +02002522 struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002523 struct ecc_settings *s;
Borislav Petkov2299ef72010-10-15 17:44:04 +02002524 int ret = 0;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002525
Doug Thompson7d6034d2009-04-27 20:01:01 +02002526 ret = pci_enable_device(pdev);
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002527 if (ret < 0) {
Doug Thompson7d6034d2009-04-27 20:01:01 +02002528 debugf0("ret=%d\n", ret);
Borislav Petkovb8cfa022010-10-01 19:35:38 +02002529 return -EIO;
2530 }
2531
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002532 ret = -ENOMEM;
2533 s = kzalloc(sizeof(struct ecc_settings), GFP_KERNEL);
2534 if (!s)
Borislav Petkov2299ef72010-10-15 17:44:04 +02002535 goto err_out;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002536
2537 ecc_stngs[nid] = s;
2538
Borislav Petkov2299ef72010-10-15 17:44:04 +02002539 if (!ecc_enabled(F3, nid)) {
2540 ret = -ENODEV;
2541
2542 if (!ecc_enable_override)
2543 goto err_enable;
2544
2545 amd64_warn("Forcing ECC on!\n");
2546
2547 if (!enable_ecc_error_reporting(s, nid, F3))
2548 goto err_enable;
2549 }
2550
2551 ret = amd64_init_one_instance(pdev);
Borislav Petkov360b7f32010-10-15 19:25:38 +02002552 if (ret < 0) {
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002553 amd64_err("Error probing instance: %d\n", nid);
Borislav Petkov360b7f32010-10-15 19:25:38 +02002554 restore_ecc_error_reporting(s, nid, F3);
2555 }
Doug Thompson7d6034d2009-04-27 20:01:01 +02002556
2557 return ret;
Borislav Petkov2299ef72010-10-15 17:44:04 +02002558
2559err_enable:
2560 kfree(s);
2561 ecc_stngs[nid] = NULL;
2562
2563err_out:
2564 return ret;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002565}
2566
2567static void __devexit amd64_remove_one_instance(struct pci_dev *pdev)
2568{
2569 struct mem_ctl_info *mci;
2570 struct amd64_pvt *pvt;
Borislav Petkov360b7f32010-10-15 19:25:38 +02002571 u8 nid = get_node_id(pdev);
2572 struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
2573 struct ecc_settings *s = ecc_stngs[nid];
Doug Thompson7d6034d2009-04-27 20:01:01 +02002574
2575 /* Remove from EDAC CORE tracking list */
2576 mci = edac_mc_del_mc(&pdev->dev);
2577 if (!mci)
2578 return;
2579
2580 pvt = mci->pvt_info;
2581
Borislav Petkov360b7f32010-10-15 19:25:38 +02002582 restore_ecc_error_reporting(s, nid, F3);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002583
Borislav Petkov360b7f32010-10-15 19:25:38 +02002584 free_mc_sibling_devs(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002585
Borislav Petkov549d0422009-07-24 13:51:42 +02002586 /* unregister from EDAC MCE */
2587 amd_report_gart_errors(false);
2588 amd_unregister_ecc_decoder(amd64_decode_bus_error);
2589
Borislav Petkov360b7f32010-10-15 19:25:38 +02002590 kfree(ecc_stngs[nid]);
2591 ecc_stngs[nid] = NULL;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002592
Doug Thompson7d6034d2009-04-27 20:01:01 +02002593 /* Free the EDAC CORE resources */
Borislav Petkov8f68ed92009-12-21 15:15:59 +01002594 mci->pvt_info = NULL;
Borislav Petkov360b7f32010-10-15 19:25:38 +02002595 mcis[nid] = NULL;
Borislav Petkov8f68ed92009-12-21 15:15:59 +01002596
2597 kfree(pvt);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002598 edac_mc_free(mci);
2599}
2600
2601/*
2602 * This table is part of the interface for loading drivers for PCI devices. The
2603 * PCI core identifies what devices are on a system during boot, and then
2604 * inquiry this table to see if this driver is for a given device found.
2605 */
2606static const struct pci_device_id amd64_pci_table[] __devinitdata = {
2607 {
2608 .vendor = PCI_VENDOR_ID_AMD,
2609 .device = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL,
2610 .subvendor = PCI_ANY_ID,
2611 .subdevice = PCI_ANY_ID,
2612 .class = 0,
2613 .class_mask = 0,
Doug Thompson7d6034d2009-04-27 20:01:01 +02002614 },
2615 {
2616 .vendor = PCI_VENDOR_ID_AMD,
2617 .device = PCI_DEVICE_ID_AMD_10H_NB_DRAM,
2618 .subvendor = PCI_ANY_ID,
2619 .subdevice = PCI_ANY_ID,
2620 .class = 0,
2621 .class_mask = 0,
Doug Thompson7d6034d2009-04-27 20:01:01 +02002622 },
Borislav Petkovdf71a052011-01-19 18:15:10 +01002623 {
2624 .vendor = PCI_VENDOR_ID_AMD,
2625 .device = PCI_DEVICE_ID_AMD_15H_NB_F2,
2626 .subvendor = PCI_ANY_ID,
2627 .subdevice = PCI_ANY_ID,
2628 .class = 0,
2629 .class_mask = 0,
2630 },
2631
Doug Thompson7d6034d2009-04-27 20:01:01 +02002632 {0, }
2633};
2634MODULE_DEVICE_TABLE(pci, amd64_pci_table);
2635
2636static struct pci_driver amd64_pci_driver = {
2637 .name = EDAC_MOD_STR,
Borislav Petkov2299ef72010-10-15 17:44:04 +02002638 .probe = amd64_probe_one_instance,
Doug Thompson7d6034d2009-04-27 20:01:01 +02002639 .remove = __devexit_p(amd64_remove_one_instance),
2640 .id_table = amd64_pci_table,
2641};
2642
Borislav Petkov360b7f32010-10-15 19:25:38 +02002643static void setup_pci_device(void)
Doug Thompson7d6034d2009-04-27 20:01:01 +02002644{
2645 struct mem_ctl_info *mci;
2646 struct amd64_pvt *pvt;
2647
2648 if (amd64_ctl_pci)
2649 return;
2650
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002651 mci = mcis[0];
Doug Thompson7d6034d2009-04-27 20:01:01 +02002652 if (mci) {
2653
2654 pvt = mci->pvt_info;
2655 amd64_ctl_pci =
Borislav Petkov8d5b5d92010-10-01 20:11:07 +02002656 edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002657
2658 if (!amd64_ctl_pci) {
2659 pr_warning("%s(): Unable to create PCI control\n",
2660 __func__);
2661
2662 pr_warning("%s(): PCI error report via EDAC not set\n",
2663 __func__);
2664 }
2665 }
2666}
2667
2668static int __init amd64_edac_init(void)
2669{
Borislav Petkov360b7f32010-10-15 19:25:38 +02002670 int err = -ENODEV;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002671
Borislav Petkovdf71a052011-01-19 18:15:10 +01002672 printk(KERN_INFO "AMD64 EDAC driver v%s\n", EDAC_AMD64_VERSION);
Doug Thompson7d6034d2009-04-27 20:01:01 +02002673
2674 opstate_init();
2675
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +02002676 if (amd_cache_northbridges() < 0)
Borislav Petkov56b34b92009-12-21 18:13:01 +01002677 goto err_ret;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002678
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002679 err = -ENOMEM;
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002680 mcis = kzalloc(amd_nb_num() * sizeof(mcis[0]), GFP_KERNEL);
2681 ecc_stngs = kzalloc(amd_nb_num() * sizeof(ecc_stngs[0]), GFP_KERNEL);
Borislav Petkov360b7f32010-10-15 19:25:38 +02002682 if (!(mcis && ecc_stngs))
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002683 goto err_ret;
2684
Borislav Petkov50542252009-12-11 18:14:40 +01002685 msrs = msrs_alloc();
Borislav Petkov56b34b92009-12-21 18:13:01 +01002686 if (!msrs)
Borislav Petkov360b7f32010-10-15 19:25:38 +02002687 goto err_free;
Borislav Petkov50542252009-12-11 18:14:40 +01002688
Doug Thompson7d6034d2009-04-27 20:01:01 +02002689 err = pci_register_driver(&amd64_pci_driver);
2690 if (err)
Borislav Petkov56b34b92009-12-21 18:13:01 +01002691 goto err_pci;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002692
Borislav Petkov56b34b92009-12-21 18:13:01 +01002693 err = -ENODEV;
Borislav Petkov360b7f32010-10-15 19:25:38 +02002694 if (!atomic_read(&drv_instances))
2695 goto err_no_instances;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002696
Borislav Petkov360b7f32010-10-15 19:25:38 +02002697 setup_pci_device();
2698 return 0;
Borislav Petkov56b34b92009-12-21 18:13:01 +01002699
Borislav Petkov360b7f32010-10-15 19:25:38 +02002700err_no_instances:
Doug Thompson7d6034d2009-04-27 20:01:01 +02002701 pci_unregister_driver(&amd64_pci_driver);
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002702
Borislav Petkov56b34b92009-12-21 18:13:01 +01002703err_pci:
2704 msrs_free(msrs);
2705 msrs = NULL;
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002706
Borislav Petkov360b7f32010-10-15 19:25:38 +02002707err_free:
2708 kfree(mcis);
2709 mcis = NULL;
2710
2711 kfree(ecc_stngs);
2712 ecc_stngs = NULL;
2713
Borislav Petkov56b34b92009-12-21 18:13:01 +01002714err_ret:
Doug Thompson7d6034d2009-04-27 20:01:01 +02002715 return err;
2716}
2717
2718static void __exit amd64_edac_exit(void)
2719{
2720 if (amd64_ctl_pci)
2721 edac_pci_release_generic_ctl(amd64_ctl_pci);
2722
2723 pci_unregister_driver(&amd64_pci_driver);
Borislav Petkov50542252009-12-11 18:14:40 +01002724
Borislav Petkovae7bb7c2010-10-14 16:01:30 +02002725 kfree(ecc_stngs);
2726 ecc_stngs = NULL;
2727
Borislav Petkovcc4d8862010-10-13 16:11:59 +02002728 kfree(mcis);
2729 mcis = NULL;
2730
Borislav Petkov50542252009-12-11 18:14:40 +01002731 msrs_free(msrs);
2732 msrs = NULL;
Doug Thompson7d6034d2009-04-27 20:01:01 +02002733}
2734
2735module_init(amd64_edac_init);
2736module_exit(amd64_edac_exit);
2737
2738MODULE_LICENSE("GPL");
2739MODULE_AUTHOR("SoftwareBitMaker: Doug Thompson, "
2740 "Dave Peterson, Thayne Harbaugh");
2741MODULE_DESCRIPTION("MC support for AMD64 memory controllers - "
2742 EDAC_AMD64_VERSION);
2743
2744module_param(edac_op_state, int, 0444);
2745MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");