Blame view

drivers/edac/amd64_edac.c 93.9 KB
09c434b8a   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
2bc654187   Doug Thompson   amd64_edac: add m...
2
  #include "amd64_edac.h"
23ac4ae82   Andreas Herrmann   x86, k8: Rename k...
3
  #include <asm/amd_nb.h>
2bc654187   Doug Thompson   amd64_edac: add m...
4

d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
5
  static struct edac_pci_ctl_info *pci_ctl;
2bc654187   Doug Thompson   amd64_edac: add m...
6

2bc654187   Doug Thompson   amd64_edac: add m...
7
8
9
10
11
12
  /*
   * Set by command line parameter. If BIOS has enabled the ECC, this override is
   * cleared to prevent re-enabling the hardware by this driver.
   */
  static int ecc_enable_override;
  module_param(ecc_enable_override, int, 0644);
a29d8b8e2   Tejun Heo   percpu: add __per...
13
  static struct msr __percpu *msrs;
505422517   Borislav Petkov   x86, msr: Add sup...
14

38ddd4d15   Yazen Ghannam   EDAC/amd64: Make ...
15
  static struct amd64_family_type *fam_type;
2ec591ac7   Borislav Petkov   EDAC, amd64_edac:...
16
  /* Per-node stuff */
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
17
  static struct ecc_settings **ecc_stngs;
2bc654187   Doug Thompson   amd64_edac: add m...
18

eae95da7f   Borislav Petkov   EDAC/amd64: Fix P...
19
20
  /* Device for the PCI component */
  static struct device *pci_ctl_dev;
2bc654187   Doug Thompson   amd64_edac: add m...
21
  /*
b70ef0101   Borislav Petkov   EDAC: move MCE er...
22
23
24
25
26
27
   * Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing
   * bandwidth to a valid bit pattern. The 'set' operation finds the 'matching-
   * or higher value'.
   *
   *FIXME: Produce a better mapping/linearisation.
   */
c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
28
  static const struct scrubrate {
390944439   Borislav Petkov   EDAC: Fixup scrub...
29
30
31
         u32 scrubval;           /* bit pattern for scrub rate */
         u32 bandwidth;          /* bandwidth consumed (bytes/sec) */
  } scrubrates[] = {
b70ef0101   Borislav Petkov   EDAC: move MCE er...
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
  	{ 0x01, 1600000000UL},
  	{ 0x02, 800000000UL},
  	{ 0x03, 400000000UL},
  	{ 0x04, 200000000UL},
  	{ 0x05, 100000000UL},
  	{ 0x06, 50000000UL},
  	{ 0x07, 25000000UL},
  	{ 0x08, 12284069UL},
  	{ 0x09, 6274509UL},
  	{ 0x0A, 3121951UL},
  	{ 0x0B, 1560975UL},
  	{ 0x0C, 781440UL},
  	{ 0x0D, 390720UL},
  	{ 0x0E, 195300UL},
  	{ 0x0F, 97650UL},
  	{ 0x10, 48854UL},
  	{ 0x11, 24427UL},
  	{ 0x12, 12213UL},
  	{ 0x13, 6101UL},
  	{ 0x14, 3051UL},
  	{ 0x15, 1523UL},
  	{ 0x16, 761UL},
  	{ 0x00, 0UL},        /* scrubbing off */
  };
66fed2d46   Borislav Petkov   amd64_edac: Impro...
56
57
  int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
  			       u32 *val, const char *func)
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  {
  	int err = 0;
  
  	err = pci_read_config_dword(pdev, offset, val);
  	if (err)
  		amd64_warn("%s: error reading F%dx%03x.
  ",
  			   func, PCI_FUNC(pdev->devfn), offset);
  
  	return err;
  }
  
  int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset,
  				u32 val, const char *func)
  {
  	int err = 0;
  
  	err = pci_write_config_dword(pdev, offset, val);
  	if (err)
  		amd64_warn("%s: error writing to F%dx%03x.
  ",
  			   func, PCI_FUNC(pdev->devfn), offset);
  
  	return err;
  }
  
  /*
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
85
86
87
88
89
90
91
92
93
94
95
96
97
   * Select DCT to which PCI cfg accesses are routed
   */
  static void f15h_select_dct(struct amd64_pvt *pvt, u8 dct)
  {
  	u32 reg = 0;
  
  	amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, &reg);
  	reg &= (pvt->model == 0x30) ? ~3 : ~1;
  	reg |= dct;
  	amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg);
  }
  
  /*
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
98
99
100
   *
   * Depending on the family, F2 DCT reads need special handling:
   *
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
101
   * K8: has a single DCT only and no address offsets >= 0x100
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
102
103
104
105
106
   *
   * F10h: each DCT has its own set of regs
   *	DCT0 -> F2x040..
   *	DCT1 -> F2x140..
   *
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
107
   * F16h: has only 1 DCT
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
108
109
   *
   * F15h: we select which DCT we access using F1x10C[DctCfgSel]
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
110
   */
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
111
112
  static inline int amd64_read_dct_pci_cfg(struct amd64_pvt *pvt, u8 dct,
  					 int offset, u32 *val)
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
113
  {
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
114
115
116
117
118
  	switch (pvt->fam) {
  	case 0xf:
  		if (dct || offset >= 0x100)
  			return -EINVAL;
  		break;
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
119

7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
120
121
122
123
124
125
126
127
128
  	case 0x10:
  		if (dct) {
  			/*
  			 * Note: If ganging is enabled, barring the regs
  			 * F2x[1,0]98 and F2x[1,0]9C; reads reads to F2x1xx
  			 * return 0. (cf. Section 2.8.1 F10h BKDG)
  			 */
  			if (dct_ganging_enabled(pvt))
  				return 0;
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
129

7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
130
131
132
  			offset += 0x100;
  		}
  		break;
73ba85937   Borislav Petkov   amd64_edac: Add a...
133

7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
134
135
136
137
138
139
140
141
  	case 0x15:
  		/*
  		 * F15h: F2x1xx addresses do not map explicitly to DCT1.
  		 * We should select which DCT we access using F1x10C[DctCfgSel]
  		 */
  		dct = (dct && pvt->model == 0x30) ? 3 : dct;
  		f15h_select_dct(pvt, dct);
  		break;
73ba85937   Borislav Petkov   amd64_edac: Add a...
142

7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
143
144
145
146
  	case 0x16:
  		if (dct)
  			return -EINVAL;
  		break;
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
147

7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
148
149
  	default:
  		break;
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
150
  	}
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
151
  	return amd64_read_pci_cfg(pvt->F2, offset, val);
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
152
  }
b70ef0101   Borislav Petkov   EDAC: move MCE er...
153
  /*
2bc654187   Doug Thompson   amd64_edac: add m...
154
155
156
157
158
159
160
161
162
163
164
165
   * Memory scrubber control interface. For K8, memory scrubbing is handled by
   * hardware and can involve L2 cache, dcache as well as the main memory. With
   * F10, this is extended to L3 cache scrubbing on CPU models sporting that
   * functionality.
   *
   * This causes the "units" for the scrubbing speed to vary from 64 byte blocks
   * (dram) over to cache lines. This is nasty, so we will use bandwidth in
   * bytes/sec for the setting.
   *
   * Currently, we only do dram scrubbing. If the scrubbing is done in software on
   * other archs, we might not have access to the caches directly.
   */
8051c0af3   Yazen Ghannam   EDAC, amd64: Add ...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
  static inline void __f17h_set_scrubval(struct amd64_pvt *pvt, u32 scrubval)
  {
  	/*
  	 * Fam17h supports scrub values between 0x5 and 0x14. Also, the values
  	 * are shifted down by 0x5, so scrubval 0x5 is written to the register
  	 * as 0x0, scrubval 0x6 as 0x1, etc.
  	 */
  	if (scrubval >= 0x5 && scrubval <= 0x14) {
  		scrubval -= 0x5;
  		pci_write_bits32(pvt->F6, F17H_SCR_LIMIT_ADDR, scrubval, 0xF);
  		pci_write_bits32(pvt->F6, F17H_SCR_BASE_ADDR, 1, 0x1);
  	} else {
  		pci_write_bits32(pvt->F6, F17H_SCR_BASE_ADDR, 0, 0x1);
  	}
  }
2bc654187   Doug Thompson   amd64_edac: add m...
181
  /*
8051c0af3   Yazen Ghannam   EDAC, amd64: Add ...
182
   * Scan the scrub rate mapping table for a close or matching bandwidth value to
2bc654187   Doug Thompson   amd64_edac: add m...
183
184
   * issue. If requested is too big, then use last maximum value found.
   */
da92110df   Aravind Gopalakrishnan   EDAC, amd64_edac:...
185
  static int __set_scrub_rate(struct amd64_pvt *pvt, u32 new_bw, u32 min_rate)
2bc654187   Doug Thompson   amd64_edac: add m...
186
187
188
189
190
191
192
193
194
  {
  	u32 scrubval;
  	int i;
  
  	/*
  	 * map the configured rate (new_bw) to a value specific to the AMD64
  	 * memory controller and apply to register. Search for the first
  	 * bandwidth entry that is greater or equal than the setting requested
  	 * and program that. If at last entry, turn off DRAM scrubbing.
168bfeef7   Andrew Morton   amd64_edac:__amd6...
195
196
197
  	 *
  	 * If no suitable bandwidth is found, turn off DRAM scrubbing entirely
  	 * by falling back to the last element in scrubrates[].
2bc654187   Doug Thompson   amd64_edac: add m...
198
  	 */
168bfeef7   Andrew Morton   amd64_edac:__amd6...
199
  	for (i = 0; i < ARRAY_SIZE(scrubrates) - 1; i++) {
2bc654187   Doug Thompson   amd64_edac: add m...
200
201
202
203
  		/*
  		 * skip scrub rates which aren't recommended
  		 * (see F10 BKDG, F3x58)
  		 */
395ae783b   Borislav Petkov   amd64_edac: Add p...
204
  		if (scrubrates[i].scrubval < min_rate)
2bc654187   Doug Thompson   amd64_edac: add m...
205
206
207
208
  			continue;
  
  		if (scrubrates[i].bandwidth <= new_bw)
  			break;
2bc654187   Doug Thompson   amd64_edac: add m...
209
210
211
  	}
  
  	scrubval = scrubrates[i].scrubval;
2bc654187   Doug Thompson   amd64_edac: add m...
212

dcd01394c   Yazen Ghannam   EDAC/amd64: Drop ...
213
  	if (pvt->umc) {
8051c0af3   Yazen Ghannam   EDAC, amd64: Add ...
214
215
  		__f17h_set_scrubval(pvt, scrubval);
  	} else if (pvt->fam == 0x15 && pvt->model == 0x60) {
da92110df   Aravind Gopalakrishnan   EDAC, amd64_edac:...
216
217
218
219
220
221
222
  		f15h_select_dct(pvt, 0);
  		pci_write_bits32(pvt->F2, F15H_M60H_SCRCTRL, scrubval, 0x001F);
  		f15h_select_dct(pvt, 1);
  		pci_write_bits32(pvt->F2, F15H_M60H_SCRCTRL, scrubval, 0x001F);
  	} else {
  		pci_write_bits32(pvt->F3, SCRCTRL, scrubval, 0x001F);
  	}
2bc654187   Doug Thompson   amd64_edac: add m...
223

390944439   Borislav Petkov   EDAC: Fixup scrub...
224
225
  	if (scrubval)
  		return scrubrates[i].bandwidth;
2bc654187   Doug Thompson   amd64_edac: add m...
226
227
  	return 0;
  }
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
228
  static int set_scrub_rate(struct mem_ctl_info *mci, u32 bw)
2bc654187   Doug Thompson   amd64_edac: add m...
229
230
  {
  	struct amd64_pvt *pvt = mci->pvt_info;
87b3e0e6e   Borislav Petkov   amd64_edac: Simpl...
231
  	u32 min_scrubrate = 0x5;
2bc654187   Doug Thompson   amd64_edac: add m...
232

a4b4bedce   Borislav Petkov   amd64_edac: Get r...
233
  	if (pvt->fam == 0xf)
87b3e0e6e   Borislav Petkov   amd64_edac: Simpl...
234
  		min_scrubrate = 0x0;
da92110df   Aravind Gopalakrishnan   EDAC, amd64_edac:...
235
236
237
238
  	if (pvt->fam == 0x15) {
  		/* Erratum #505 */
  		if (pvt->model < 0x10)
  			f15h_select_dct(pvt, 0);
73ba85937   Borislav Petkov   amd64_edac: Add a...
239

da92110df   Aravind Gopalakrishnan   EDAC, amd64_edac:...
240
241
242
243
  		if (pvt->model == 0x60)
  			min_scrubrate = 0x6;
  	}
  	return __set_scrub_rate(pvt, bw, min_scrubrate);
2bc654187   Doug Thompson   amd64_edac: add m...
244
  }
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
245
  static int get_scrub_rate(struct mem_ctl_info *mci)
2bc654187   Doug Thompson   amd64_edac: add m...
246
247
  {
  	struct amd64_pvt *pvt = mci->pvt_info;
390944439   Borislav Petkov   EDAC: Fixup scrub...
248
  	int i, retval = -EINVAL;
8051c0af3   Yazen Ghannam   EDAC, amd64: Add ...
249
  	u32 scrubval = 0;
2bc654187   Doug Thompson   amd64_edac: add m...
250

dcd01394c   Yazen Ghannam   EDAC/amd64: Drop ...
251
  	if (pvt->umc) {
8051c0af3   Yazen Ghannam   EDAC, amd64: Add ...
252
253
254
255
256
257
258
259
  		amd64_read_pci_cfg(pvt->F6, F17H_SCR_BASE_ADDR, &scrubval);
  		if (scrubval & BIT(0)) {
  			amd64_read_pci_cfg(pvt->F6, F17H_SCR_LIMIT_ADDR, &scrubval);
  			scrubval &= 0xF;
  			scrubval += 0x5;
  		} else {
  			scrubval = 0;
  		}
dcd01394c   Yazen Ghannam   EDAC/amd64: Drop ...
260
261
262
263
  	} else if (pvt->fam == 0x15) {
  		/* Erratum #505 */
  		if (pvt->model < 0x10)
  			f15h_select_dct(pvt, 0);
8051c0af3   Yazen Ghannam   EDAC, amd64: Add ...
264

dcd01394c   Yazen Ghannam   EDAC/amd64: Drop ...
265
266
  		if (pvt->model == 0x60)
  			amd64_read_pci_cfg(pvt->F2, F15H_M60H_SCRCTRL, &scrubval);
ee470bb25   Borislav Petkov   EDAC/amd64: Read ...
267
268
  		else
  			amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval);
dcd01394c   Yazen Ghannam   EDAC/amd64: Drop ...
269
  	} else {
da92110df   Aravind Gopalakrishnan   EDAC, amd64_edac:...
270
  		amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval);
8051c0af3   Yazen Ghannam   EDAC, amd64: Add ...
271
  	}
2bc654187   Doug Thompson   amd64_edac: add m...
272
273
  
  	scrubval = scrubval & 0x001F;
926311fd7   Roel Kluin   amd64_edac: Ensur...
274
  	for (i = 0; i < ARRAY_SIZE(scrubrates); i++) {
2bc654187   Doug Thompson   amd64_edac: add m...
275
  		if (scrubrates[i].scrubval == scrubval) {
390944439   Borislav Petkov   EDAC: Fixup scrub...
276
  			retval = scrubrates[i].bandwidth;
2bc654187   Doug Thompson   amd64_edac: add m...
277
278
279
  			break;
  		}
  	}
390944439   Borislav Petkov   EDAC: Fixup scrub...
280
  	return retval;
2bc654187   Doug Thompson   amd64_edac: add m...
281
  }
6775763a2   Doug Thompson   amd64_edac: add s...
282
  /*
7f19bf755   Borislav Petkov   amd64_edac: Remov...
283
284
   * returns true if the SysAddr given by sys_addr matches the
   * DRAM base/limit associated with node_id
6775763a2   Doug Thompson   amd64_edac: add s...
285
   */
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
286
  static bool base_limit_match(struct amd64_pvt *pvt, u64 sys_addr, u8 nid)
6775763a2   Doug Thompson   amd64_edac: add s...
287
  {
7f19bf755   Borislav Petkov   amd64_edac: Remov...
288
  	u64 addr;
6775763a2   Doug Thompson   amd64_edac: add s...
289
290
291
292
293
294
295
296
  
  	/* The K8 treats this as a 40-bit value.  However, bits 63-40 will be
  	 * all ones if the most significant implemented address bit is 1.
  	 * Here we discard bits 63-40.  See section 3.4.2 of AMD publication
  	 * 24592: AMD x86-64 Architecture Programmer's Manual Volume 1
  	 * Application Programming.
  	 */
  	addr = sys_addr & 0x000000ffffffffffull;
7f19bf755   Borislav Petkov   amd64_edac: Remov...
297
298
  	return ((addr >= get_dram_base(pvt, nid)) &&
  		(addr <= get_dram_limit(pvt, nid)));
6775763a2   Doug Thompson   amd64_edac: add s...
299
300
301
302
303
304
305
306
307
308
309
310
  }
  
  /*
   * Attempt to map a SysAddr to a node. On success, return a pointer to the
   * mem_ctl_info structure for the node that the SysAddr maps to.
   *
   * On failure, return NULL.
   */
  static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
  						u64 sys_addr)
  {
  	struct amd64_pvt *pvt;
c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
311
  	u8 node_id;
6775763a2   Doug Thompson   amd64_edac: add s...
312
313
314
315
316
317
318
319
320
321
322
323
324
  	u32 intlv_en, bits;
  
  	/*
  	 * Here we use the DRAM Base (section 3.4.4.1) and DRAM Limit (section
  	 * 3.4.4.2) registers to map the SysAddr to a node ID.
  	 */
  	pvt = mci->pvt_info;
  
  	/*
  	 * The value of this field should be the same for all DRAM Base
  	 * registers.  Therefore we arbitrarily choose to read it from the
  	 * register for node 0.
  	 */
7f19bf755   Borislav Petkov   amd64_edac: Remov...
325
  	intlv_en = dram_intlv_en(pvt, 0);
6775763a2   Doug Thompson   amd64_edac: add s...
326
327
  
  	if (intlv_en == 0) {
7f19bf755   Borislav Petkov   amd64_edac: Remov...
328
  		for (node_id = 0; node_id < DRAM_RANGES; node_id++) {
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
329
  			if (base_limit_match(pvt, sys_addr, node_id))
8edc54458   Borislav Petkov   amd64_edac: fix K...
330
  				goto found;
6775763a2   Doug Thompson   amd64_edac: add s...
331
  		}
8edc54458   Borislav Petkov   amd64_edac: fix K...
332
  		goto err_no_match;
6775763a2   Doug Thompson   amd64_edac: add s...
333
  	}
72f158fe6   Borislav Petkov   amd64_edac: fix i...
334
335
336
  	if (unlikely((intlv_en != 0x01) &&
  		     (intlv_en != 0x03) &&
  		     (intlv_en != 0x07))) {
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
337
338
  		amd64_warn("DRAM Base[IntlvEn] junk value: 0x%x, BIOS bug?
  ", intlv_en);
6775763a2   Doug Thompson   amd64_edac: add s...
339
340
341
342
343
344
  		return NULL;
  	}
  
  	bits = (((u32) sys_addr) >> 12) & intlv_en;
  
  	for (node_id = 0; ; ) {
7f19bf755   Borislav Petkov   amd64_edac: Remov...
345
  		if ((dram_intlv_sel(pvt, node_id) & intlv_en) == bits)
6775763a2   Doug Thompson   amd64_edac: add s...
346
  			break;	/* intlv_sel field matches */
7f19bf755   Borislav Petkov   amd64_edac: Remov...
347
  		if (++node_id >= DRAM_RANGES)
6775763a2   Doug Thompson   amd64_edac: add s...
348
349
350
351
  			goto err_no_match;
  	}
  
  	/* sanity test for sys_addr */
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
352
  	if (unlikely(!base_limit_match(pvt, sys_addr, node_id))) {
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
353
354
355
356
  		amd64_warn("%s: sys_addr 0x%llx falls outside base/limit address"
  			   "range for node %d with node interleaving enabled.
  ",
  			   __func__, sys_addr, node_id);
6775763a2   Doug Thompson   amd64_edac: add s...
357
358
359
360
  		return NULL;
  	}
  
  found:
b487c33e5   Borislav Petkov   amd64_edac: Fix n...
361
  	return edac_mc_find((int)node_id);
6775763a2   Doug Thompson   amd64_edac: add s...
362
363
  
  err_no_match:
956b9ba15   Joe Perches   edac: Convert deb...
364
365
366
  	edac_dbg(2, "sys_addr 0x%lx doesn't match any node
  ",
  		 (unsigned long)sys_addr);
6775763a2   Doug Thompson   amd64_edac: add s...
367
368
369
  
  	return NULL;
  }
e2ce7255e   Doug Thompson   amd64_edac: add f...
370
371
  
  /*
11c75eada   Borislav Petkov   amd64_edac: Clean...
372
373
   * compute the CS base address of the @csrow on the DRAM controller @dct.
   * For details see F2x[5C:40] in the processor's BKDG
e2ce7255e   Doug Thompson   amd64_edac: add f...
374
   */
11c75eada   Borislav Petkov   amd64_edac: Clean...
375
376
  static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct,
  				 u64 *base, u64 *mask)
e2ce7255e   Doug Thompson   amd64_edac: add f...
377
  {
11c75eada   Borislav Petkov   amd64_edac: Clean...
378
379
  	u64 csbase, csmask, base_bits, mask_bits;
  	u8 addr_shift;
e2ce7255e   Doug Thompson   amd64_edac: add f...
380

18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
381
  	if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) {
11c75eada   Borislav Petkov   amd64_edac: Clean...
382
383
  		csbase		= pvt->csels[dct].csbases[csrow];
  		csmask		= pvt->csels[dct].csmasks[csrow];
10ef6b0df   Chen, Gong   bitops: Introduce...
384
385
  		base_bits	= GENMASK_ULL(31, 21) | GENMASK_ULL(15, 9);
  		mask_bits	= GENMASK_ULL(29, 21) | GENMASK_ULL(15, 9);
11c75eada   Borislav Petkov   amd64_edac: Clean...
386
  		addr_shift	= 4;
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
387
388
  
  	/*
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
389
390
391
392
393
  	 * F16h and F15h, models 30h and later need two addr_shift values:
  	 * 8 for high and 6 for low (cf. F16h BKDG).
  	 */
  	} else if (pvt->fam == 0x16 ||
  		  (pvt->fam == 0x15 && pvt->model >= 0x30)) {
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
394
395
  		csbase          = pvt->csels[dct].csbases[csrow];
  		csmask          = pvt->csels[dct].csmasks[csrow >> 1];
10ef6b0df   Chen, Gong   bitops: Introduce...
396
397
  		*base  = (csbase & GENMASK_ULL(15,  5)) << 6;
  		*base |= (csbase & GENMASK_ULL(30, 19)) << 8;
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
398
399
400
  
  		*mask = ~0ULL;
  		/* poke holes for the csmask */
10ef6b0df   Chen, Gong   bitops: Introduce...
401
402
  		*mask &= ~((GENMASK_ULL(15, 5)  << 6) |
  			   (GENMASK_ULL(30, 19) << 8));
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
403

10ef6b0df   Chen, Gong   bitops: Introduce...
404
405
  		*mask |= (csmask & GENMASK_ULL(15, 5))  << 6;
  		*mask |= (csmask & GENMASK_ULL(30, 19)) << 8;
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
406
407
  
  		return;
11c75eada   Borislav Petkov   amd64_edac: Clean...
408
409
410
411
  	} else {
  		csbase		= pvt->csels[dct].csbases[csrow];
  		csmask		= pvt->csels[dct].csmasks[csrow >> 1];
  		addr_shift	= 8;
e2ce7255e   Doug Thompson   amd64_edac: add f...
412

a4b4bedce   Borislav Petkov   amd64_edac: Get r...
413
  		if (pvt->fam == 0x15)
10ef6b0df   Chen, Gong   bitops: Introduce...
414
415
  			base_bits = mask_bits =
  				GENMASK_ULL(30,19) | GENMASK_ULL(13,5);
11c75eada   Borislav Petkov   amd64_edac: Clean...
416
  		else
10ef6b0df   Chen, Gong   bitops: Introduce...
417
418
  			base_bits = mask_bits =
  				GENMASK_ULL(28,19) | GENMASK_ULL(13,5);
11c75eada   Borislav Petkov   amd64_edac: Clean...
419
  	}
e2ce7255e   Doug Thompson   amd64_edac: add f...
420

11c75eada   Borislav Petkov   amd64_edac: Clean...
421
  	*base  = (csbase & base_bits) << addr_shift;
e2ce7255e   Doug Thompson   amd64_edac: add f...
422

11c75eada   Borislav Petkov   amd64_edac: Clean...
423
424
425
426
427
  	*mask  = ~0ULL;
  	/* poke holes for the csmask */
  	*mask &= ~(mask_bits << addr_shift);
  	/* OR them in */
  	*mask |= (csmask & mask_bits) << addr_shift;
e2ce7255e   Doug Thompson   amd64_edac: add f...
428
  }
11c75eada   Borislav Petkov   amd64_edac: Clean...
429
430
  #define for_each_chip_select(i, dct, pvt) \
  	for (i = 0; i < pvt->csels[dct].b_cnt; i++)
614ec9d85   Borislav Petkov   amd64_edac: Revam...
431
432
  #define chip_select_base(i, dct, pvt) \
  	pvt->csels[dct].csbases[i]
11c75eada   Borislav Petkov   amd64_edac: Clean...
433
434
  #define for_each_chip_select_mask(i, dct, pvt) \
  	for (i = 0; i < pvt->csels[dct].m_cnt; i++)
4d30d2bc3   Yazen Ghannam   EDAC/amd64: Use a...
435
  #define for_each_umc(i) \
5e4c55276   Yazen Ghannam   EDAC/amd64: Save ...
436
  	for (i = 0; i < fam_type->max_mcs; i++)
4d30d2bc3   Yazen Ghannam   EDAC/amd64: Use a...
437

e2ce7255e   Doug Thompson   amd64_edac: add f...
438
439
440
441
442
443
444
445
446
447
448
  /*
   * @input_addr is an InputAddr associated with the node given by mci. Return the
   * csrow that input_addr maps to, or -1 on failure (no csrow claims input_addr).
   */
  static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr)
  {
  	struct amd64_pvt *pvt;
  	int csrow;
  	u64 base, mask;
  
  	pvt = mci->pvt_info;
11c75eada   Borislav Petkov   amd64_edac: Clean...
449
450
  	for_each_chip_select(csrow, 0, pvt) {
  		if (!csrow_enabled(csrow, 0, pvt))
e2ce7255e   Doug Thompson   amd64_edac: add f...
451
  			continue;
11c75eada   Borislav Petkov   amd64_edac: Clean...
452
453
454
  		get_cs_base_and_mask(pvt, csrow, 0, &base, &mask);
  
  		mask = ~mask;
e2ce7255e   Doug Thompson   amd64_edac: add f...
455
456
  
  		if ((input_addr & mask) == (base & mask)) {
956b9ba15   Joe Perches   edac: Convert deb...
457
458
459
460
  			edac_dbg(2, "InputAddr 0x%lx matches csrow %d (node %d)
  ",
  				 (unsigned long)input_addr, csrow,
  				 pvt->mc_node_id);
e2ce7255e   Doug Thompson   amd64_edac: add f...
461
462
463
464
  
  			return csrow;
  		}
  	}
956b9ba15   Joe Perches   edac: Convert deb...
465
466
467
  	edac_dbg(2, "no matching csrow for InputAddr 0x%lx (MC node %d)
  ",
  		 (unsigned long)input_addr, pvt->mc_node_id);
e2ce7255e   Doug Thompson   amd64_edac: add f...
468
469
470
471
472
  
  	return -1;
  }
  
  /*
e2ce7255e   Doug Thompson   amd64_edac: add f...
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
   * Obtain info from the DRAM Hole Address Register (section 3.4.8, pub #26094)
   * for the node represented by mci. Info is passed back in *hole_base,
   * *hole_offset, and *hole_size.  Function returns 0 if info is valid or 1 if
   * info is invalid. Info may be invalid for either of the following reasons:
   *
   * - The revision of the node is not E or greater.  In this case, the DRAM Hole
   *   Address Register does not exist.
   *
   * - The DramHoleValid bit is cleared in the DRAM Hole Address Register,
   *   indicating that its contents are not valid.
   *
   * The values passed back in *hole_base, *hole_offset, and *hole_size are
   * complete 32-bit values despite the fact that the bitfields in the DHAR
   * only represent bits 31-24 of the base and offset values.
   */
  int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
  			     u64 *hole_offset, u64 *hole_size)
  {
  	struct amd64_pvt *pvt = mci->pvt_info;
e2ce7255e   Doug Thompson   amd64_edac: add f...
492
493
  
  	/* only revE and later have the DRAM Hole Address Register */
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
494
  	if (pvt->fam == 0xf && pvt->ext_model < K8_REV_E) {
956b9ba15   Joe Perches   edac: Convert deb...
495
496
497
  		edac_dbg(1, "  revision %d for node %d does not support DHAR
  ",
  			 pvt->ext_model, pvt->mc_node_id);
e2ce7255e   Doug Thompson   amd64_edac: add f...
498
499
  		return 1;
  	}
bc21fa578   Borislav Petkov   amd64_edac: Clean...
500
  	/* valid for Fam10h and above */
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
501
  	if (pvt->fam >= 0x10 && !dhar_mem_hoist_valid(pvt)) {
956b9ba15   Joe Perches   edac: Convert deb...
502
503
  		edac_dbg(1, "  Dram Memory Hoisting is DISABLED on this system
  ");
e2ce7255e   Doug Thompson   amd64_edac: add f...
504
505
  		return 1;
  	}
c8e518d56   Borislav Petkov   amd64_edac: Sanit...
506
  	if (!dhar_valid(pvt)) {
956b9ba15   Joe Perches   edac: Convert deb...
507
508
509
  		edac_dbg(1, "  Dram Memory Hoisting is DISABLED on this node %d
  ",
  			 pvt->mc_node_id);
e2ce7255e   Doug Thompson   amd64_edac: add f...
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
  		return 1;
  	}
  
  	/* This node has Memory Hoisting */
  
  	/* +------------------+--------------------+--------------------+-----
  	 * | memory           | DRAM hole          | relocated          |
  	 * | [0, (x - 1)]     | [x, 0xffffffff]    | addresses from     |
  	 * |                  |                    | DRAM hole          |
  	 * |                  |                    | [0x100000000,      |
  	 * |                  |                    |  (0x100000000+     |
  	 * |                  |                    |   (0xffffffff-x))] |
  	 * +------------------+--------------------+--------------------+-----
  	 *
  	 * Above is a diagram of physical memory showing the DRAM hole and the
  	 * relocated addresses from the DRAM hole.  As shown, the DRAM hole
  	 * starts at address x (the base address) and extends through address
  	 * 0xffffffff.  The DRAM Hole Address Register (DHAR) relocates the
  	 * addresses in the hole so that they start at 0x100000000.
  	 */
1f31677e0   Borislav Petkov   amd64_edac: Small...
530
531
  	*hole_base = dhar_base(pvt);
  	*hole_size = (1ULL << 32) - *hole_base;
e2ce7255e   Doug Thompson   amd64_edac: add f...
532

a4b4bedce   Borislav Petkov   amd64_edac: Get r...
533
534
  	*hole_offset = (pvt->fam > 0xf) ? f10_dhar_offset(pvt)
  					: k8_dhar_offset(pvt);
e2ce7255e   Doug Thompson   amd64_edac: add f...
535

956b9ba15   Joe Perches   edac: Convert deb...
536
537
538
539
  	edac_dbg(1, "  DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx
  ",
  		 pvt->mc_node_id, (unsigned long)*hole_base,
  		 (unsigned long)*hole_offset, (unsigned long)*hole_size);
e2ce7255e   Doug Thompson   amd64_edac: add f...
540
541
542
543
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(amd64_get_dram_hole_info);
93c2df58b   Doug Thompson   amd64_edac: add D...
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
  /*
   * Return the DramAddr that the SysAddr given by @sys_addr maps to.  It is
   * assumed that sys_addr maps to the node given by mci.
   *
   * The first part of section 3.4.4 (p. 70) shows how the DRAM Base (section
   * 3.4.4.1) and DRAM Limit (section 3.4.4.2) registers are used to translate a
   * SysAddr to a DramAddr. If the DRAM Hole Address Register (DHAR) is enabled,
   * then it is also involved in translating a SysAddr to a DramAddr. Sections
   * 3.4.8 and 3.5.8.2 describe the DHAR and how it is used for memory hoisting.
   * These parts of the documentation are unclear. I interpret them as follows:
   *
   * When node n receives a SysAddr, it processes the SysAddr as follows:
   *
   * 1. It extracts the DRAMBase and DRAMLimit values from the DRAM Base and DRAM
   *    Limit registers for node n. If the SysAddr is not within the range
   *    specified by the base and limit values, then node n ignores the Sysaddr
   *    (since it does not map to node n). Otherwise continue to step 2 below.
   *
   * 2. If the DramHoleValid bit of the DHAR for node n is clear, the DHAR is
   *    disabled so skip to step 3 below. Otherwise see if the SysAddr is within
   *    the range of relocated addresses (starting at 0x100000000) from the DRAM
   *    hole. If not, skip to step 3 below. Else get the value of the
   *    DramHoleOffset field from the DHAR. To obtain the DramAddr, subtract the
   *    offset defined by this value from the SysAddr.
   *
   * 3. Obtain the base address for node n from the DRAMBase field of the DRAM
   *    Base register for node n. To obtain the DramAddr, subtract the base
   *    address from the SysAddr, as shown near the start of section 3.4.4 (p.70).
   */
  static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr)
  {
7f19bf755   Borislav Petkov   amd64_edac: Remov...
575
  	struct amd64_pvt *pvt = mci->pvt_info;
93c2df58b   Doug Thompson   amd64_edac: add D...
576
  	u64 dram_base, hole_base, hole_offset, hole_size, dram_addr;
1f31677e0   Borislav Petkov   amd64_edac: Small...
577
  	int ret;
93c2df58b   Doug Thompson   amd64_edac: add D...
578

7f19bf755   Borislav Petkov   amd64_edac: Remov...
579
  	dram_base = get_dram_base(pvt, pvt->mc_node_id);
93c2df58b   Doug Thompson   amd64_edac: add D...
580
581
582
583
  
  	ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
  				      &hole_size);
  	if (!ret) {
1f31677e0   Borislav Petkov   amd64_edac: Small...
584
585
  		if ((sys_addr >= (1ULL << 32)) &&
  		    (sys_addr < ((1ULL << 32) + hole_size))) {
93c2df58b   Doug Thompson   amd64_edac: add D...
586
587
  			/* use DHAR to translate SysAddr to DramAddr */
  			dram_addr = sys_addr - hole_offset;
956b9ba15   Joe Perches   edac: Convert deb...
588
589
590
591
  			edac_dbg(2, "using DHAR to translate SysAddr 0x%lx to DramAddr 0x%lx
  ",
  				 (unsigned long)sys_addr,
  				 (unsigned long)dram_addr);
93c2df58b   Doug Thompson   amd64_edac: add D...
592
593
594
595
596
597
598
599
600
601
602
603
604
605
  
  			return dram_addr;
  		}
  	}
  
  	/*
  	 * Translate the SysAddr to a DramAddr as shown near the start of
  	 * section 3.4.4 (p. 70).  Although sys_addr is a 64-bit value, the k8
  	 * only deals with 40-bit values.  Therefore we discard bits 63-40 of
  	 * sys_addr below.  If bit 39 of sys_addr is 1 then the bits we
  	 * discard are all 1s.  Otherwise the bits we discard are all 0s.  See
  	 * section 3.4.2 of AMD publication 24592: AMD x86-64 Architecture
  	 * Programmer's Manual Volume 1 Application Programming.
  	 */
10ef6b0df   Chen, Gong   bitops: Introduce...
606
  	dram_addr = (sys_addr & GENMASK_ULL(39, 0)) - dram_base;
93c2df58b   Doug Thompson   amd64_edac: add D...
607

956b9ba15   Joe Perches   edac: Convert deb...
608
609
610
  	edac_dbg(2, "using DRAM Base register to translate SysAddr 0x%lx to DramAddr 0x%lx
  ",
  		 (unsigned long)sys_addr, (unsigned long)dram_addr);
93c2df58b   Doug Thompson   amd64_edac: add D...
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
  	return dram_addr;
  }
  
  /*
   * @intlv_en is the value of the IntlvEn field from a DRAM Base register
   * (section 3.4.4.1).  Return the number of bits from a SysAddr that are used
   * for node interleaving.
   */
  static int num_node_interleave_bits(unsigned intlv_en)
  {
  	static const int intlv_shift_table[] = { 0, 1, 0, 2, 0, 0, 0, 3 };
  	int n;
  
  	BUG_ON(intlv_en > 7);
  	n = intlv_shift_table[intlv_en];
  	return n;
  }
  
  /* Translate the DramAddr given by @dram_addr to an InputAddr. */
  static u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr)
  {
  	struct amd64_pvt *pvt;
  	int intlv_shift;
  	u64 input_addr;
  
  	pvt = mci->pvt_info;
  
  	/*
  	 * See the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E)
  	 * concerning translating a DramAddr to an InputAddr.
  	 */
7f19bf755   Borislav Petkov   amd64_edac: Remov...
642
  	intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0));
10ef6b0df   Chen, Gong   bitops: Introduce...
643
  	input_addr = ((dram_addr >> intlv_shift) & GENMASK_ULL(35, 12)) +
f678b8ccc   Borislav Petkov   amd64_edac: Repla...
644
  		      (dram_addr & 0xfff);
93c2df58b   Doug Thompson   amd64_edac: add D...
645

956b9ba15   Joe Perches   edac: Convert deb...
646
647
648
649
  	edac_dbg(2, "  Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx
  ",
  		 intlv_shift, (unsigned long)dram_addr,
  		 (unsigned long)input_addr);
93c2df58b   Doug Thompson   amd64_edac: add D...
650
651
652
653
654
655
656
657
658
659
660
661
662
663
  
  	return input_addr;
  }
  
  /*
   * Translate the SysAddr represented by @sys_addr to an InputAddr.  It is
   * assumed that @sys_addr maps to the node given by mci.
   */
  static u64 sys_addr_to_input_addr(struct mem_ctl_info *mci, u64 sys_addr)
  {
  	u64 input_addr;
  
  	input_addr =
  	    dram_addr_to_input_addr(mci, sys_addr_to_dram_addr(mci, sys_addr));
c19ca6cb4   Masanari Iida   treewide: Fix typ...
664
665
  	edac_dbg(2, "SysAddr 0x%lx translates to InputAddr 0x%lx
  ",
956b9ba15   Joe Perches   edac: Convert deb...
666
  		 (unsigned long)sys_addr, (unsigned long)input_addr);
93c2df58b   Doug Thompson   amd64_edac: add D...
667
668
669
  
  	return input_addr;
  }
93c2df58b   Doug Thompson   amd64_edac: add D...
670
671
  /* Map the Error address to a PAGE and PAGE OFFSET. */
  static inline void error_address_to_page_and_offset(u64 error_address,
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
672
  						    struct err_info *err)
93c2df58b   Doug Thompson   amd64_edac: add D...
673
  {
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
674
675
  	err->page = (u32) (error_address >> PAGE_SHIFT);
  	err->offset = ((u32) error_address) & ~PAGE_MASK;
93c2df58b   Doug Thompson   amd64_edac: add D...
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
  }
  
  /*
   * @sys_addr is an error address (a SysAddr) extracted from the MCA NB Address
   * Low (section 3.6.4.5) and MCA NB Address High (section 3.6.4.6) registers
   * of a node that detected an ECC memory error.  mci represents the node that
   * the error address maps to (possibly different from the node that detected
   * the error).  Return the number of the csrow that sys_addr maps to, or -1 on
   * error.
   */
  static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr)
  {
  	int csrow;
  
  	csrow = input_addr_to_csrow(mci, sys_addr_to_input_addr(mci, sys_addr));
  
  	if (csrow == -1)
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
693
694
695
  		amd64_mc_err(mci, "Failed to translate InputAddr to csrow for "
  				  "address 0x%lx
  ", (unsigned long)sys_addr);
93c2df58b   Doug Thompson   amd64_edac: add D...
696
697
  	return csrow;
  }
e2ce7255e   Doug Thompson   amd64_edac: add f...
698

bfc04aec7   Borislav Petkov   amd64_edac: add a...
699
  static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);
2da11654e   Doug Thompson   amd64_edac: add h...
700

2da11654e   Doug Thompson   amd64_edac: add h...
701
702
703
704
  /*
   * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs
   * are ECC capable.
   */
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
705
  static unsigned long determine_edac_cap(struct amd64_pvt *pvt)
2da11654e   Doug Thompson   amd64_edac: add h...
706
  {
1f6189ed1   Dan Carpenter   amd64_edac: Clean...
707
  	unsigned long edac_cap = EDAC_FLAG_NONE;
d27f3a348   Yazen Ghannam   EDAC, amd64: Dete...
708
709
710
711
  	u8 bit;
  
  	if (pvt->umc) {
  		u8 i, umc_en_mask = 0, dimm_ecc_en_mask = 0;
2da11654e   Doug Thompson   amd64_edac: add h...
712

4d30d2bc3   Yazen Ghannam   EDAC/amd64: Use a...
713
  		for_each_umc(i) {
d27f3a348   Yazen Ghannam   EDAC, amd64: Dete...
714
715
  			if (!(pvt->umc[i].sdp_ctrl & UMC_SDP_INIT))
  				continue;
2da11654e   Doug Thompson   amd64_edac: add h...
716

d27f3a348   Yazen Ghannam   EDAC, amd64: Dete...
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
  			umc_en_mask |= BIT(i);
  
  			/* UMC Configuration bit 12 (DimmEccEn) */
  			if (pvt->umc[i].umc_cfg & BIT(12))
  				dimm_ecc_en_mask |= BIT(i);
  		}
  
  		if (umc_en_mask == dimm_ecc_en_mask)
  			edac_cap = EDAC_FLAG_SECDED;
  	} else {
  		bit = (pvt->fam > 0xf || pvt->ext_model >= K8_REV_F)
  			? 19
  			: 17;
  
  		if (pvt->dclr0 & BIT(bit))
  			edac_cap = EDAC_FLAG_SECDED;
  	}
2da11654e   Doug Thompson   amd64_edac: add h...
734
735
736
  
  	return edac_cap;
  }
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
737
  static void debug_display_dimm_sizes(struct amd64_pvt *, u8);
2da11654e   Doug Thompson   amd64_edac: add h...
738

d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
739
  static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan)
68798e176   Borislav Petkov   amd64_edac: clean...
740
  {
956b9ba15   Joe Perches   edac: Convert deb...
741
742
  	edac_dbg(1, "F2x%d90 (DRAM Cfg Low): 0x%08x
  ", chan, dclr);
68798e176   Borislav Petkov   amd64_edac: clean...
743

a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
744
745
746
747
748
749
750
751
752
753
754
755
756
757
  	if (pvt->dram_type == MEM_LRDDR3) {
  		u32 dcsm = pvt->csels[chan].csmasks[0];
  		/*
  		 * It's assumed all LRDIMMs in a DCT are going to be of
  		 * same 'type' until proven otherwise. So, use a cs
  		 * value of '0' here to get dcsm value.
  		 */
  		edac_dbg(1, " LRDIMM %dx rank multiply
  ", (dcsm & 0x3));
  	}
  
  	edac_dbg(1, "All DIMMs support ECC:%s
  ",
  		    (dclr & BIT(19)) ? "yes" : "no");
68798e176   Borislav Petkov   amd64_edac: clean...
758

956b9ba15   Joe Perches   edac: Convert deb...
759
760
761
  	edac_dbg(1, "  PAR/ERR parity: %s
  ",
  		 (dclr & BIT(8)) ?  "enabled" : "disabled");
68798e176   Borislav Petkov   amd64_edac: clean...
762

a4b4bedce   Borislav Petkov   amd64_edac: Get r...
763
  	if (pvt->fam == 0x10)
956b9ba15   Joe Perches   edac: Convert deb...
764
765
766
  		edac_dbg(1, "  DCT 128bit mode width: %s
  ",
  			 (dclr & BIT(11)) ?  "128b" : "64b");
68798e176   Borislav Petkov   amd64_edac: clean...
767

956b9ba15   Joe Perches   edac: Convert deb...
768
769
770
771
772
773
  	edac_dbg(1, "  x4 logical DIMMs present: L0: %s L1: %s L2: %s L3: %s
  ",
  		 (dclr & BIT(12)) ?  "yes" : "no",
  		 (dclr & BIT(13)) ?  "yes" : "no",
  		 (dclr & BIT(14)) ?  "yes" : "no",
  		 (dclr & BIT(15)) ?  "yes" : "no");
68798e176   Borislav Petkov   amd64_edac: clean...
774
  }
e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
775
776
  #define CS_EVEN_PRIMARY		BIT(0)
  #define CS_ODD_PRIMARY		BIT(1)
81f5090db   Yazen Ghannam   EDAC/amd64: Suppo...
777
778
  #define CS_EVEN_SECONDARY	BIT(2)
  #define CS_ODD_SECONDARY	BIT(3)
e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
779

81f5090db   Yazen Ghannam   EDAC/amd64: Suppo...
780
781
  #define CS_EVEN			(CS_EVEN_PRIMARY | CS_EVEN_SECONDARY)
  #define CS_ODD			(CS_ODD_PRIMARY | CS_ODD_SECONDARY)
e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
782
783
  
  static int f17_get_cs_mode(int dimm, u8 ctrl, struct amd64_pvt *pvt)
fc00c6a41   Yazen Ghannam   EDAC/amd64: Adjus...
784
  {
e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
785
  	int cs_mode = 0;
fc00c6a41   Yazen Ghannam   EDAC/amd64: Adjus...
786

e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
787
788
  	if (csrow_enabled(2 * dimm, ctrl, pvt))
  		cs_mode |= CS_EVEN_PRIMARY;
fc00c6a41   Yazen Ghannam   EDAC/amd64: Adjus...
789

e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
790
791
  	if (csrow_enabled(2 * dimm + 1, ctrl, pvt))
  		cs_mode |= CS_ODD_PRIMARY;
81f5090db   Yazen Ghannam   EDAC/amd64: Suppo...
792
793
794
  	/* Asymmetric dual-rank DIMM support. */
  	if (csrow_sec_enabled(2 * dimm + 1, ctrl, pvt))
  		cs_mode |= CS_ODD_SECONDARY;
e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
795
  	return cs_mode;
fc00c6a41   Yazen Ghannam   EDAC/amd64: Adjus...
796
  }
07ed82ef9   Yazen Ghannam   EDAC, amd64: Add ...
797
798
  static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl)
  {
e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
799
  	int dimm, size0, size1, cs0, cs1, cs_mode;
07ed82ef9   Yazen Ghannam   EDAC, amd64: Add ...
800
801
802
  
  	edac_printk(KERN_DEBUG, EDAC_MC, "UMC%d chip selects:
  ", ctrl);
d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
803
  	for (dimm = 0; dimm < 2; dimm++) {
eb77e6b80   Yazen Ghannam   EDAC, amd64: Fix ...
804
  		cs0 = dimm * 2;
eb77e6b80   Yazen Ghannam   EDAC, amd64: Fix ...
805
  		cs1 = dimm * 2 + 1;
e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
806
807
808
809
  		cs_mode = f17_get_cs_mode(dimm, ctrl, pvt);
  
  		size0 = pvt->ops->dbam_to_cs(pvt, ctrl, cs_mode, cs0);
  		size1 = pvt->ops->dbam_to_cs(pvt, ctrl, cs_mode, cs1);
07ed82ef9   Yazen Ghannam   EDAC, amd64: Add ...
810
811
812
  
  		amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB
  ",
eb77e6b80   Yazen Ghannam   EDAC, amd64: Fix ...
813
814
  				cs0,	size0,
  				cs1,	size1);
07ed82ef9   Yazen Ghannam   EDAC, amd64: Add ...
815
816
817
818
819
820
821
  	}
  }
  
  static void __dump_misc_regs_df(struct amd64_pvt *pvt)
  {
  	struct amd64_umc *umc;
  	u32 i, tmp, umc_base;
4d30d2bc3   Yazen Ghannam   EDAC/amd64: Use a...
822
  	for_each_umc(i) {
07ed82ef9   Yazen Ghannam   EDAC, amd64: Add ...
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
  		umc_base = get_umc_base(i);
  		umc = &pvt->umc[i];
  
  		edac_dbg(1, "UMC%d DIMM cfg: 0x%x
  ", i, umc->dimm_cfg);
  		edac_dbg(1, "UMC%d UMC cfg: 0x%x
  ", i, umc->umc_cfg);
  		edac_dbg(1, "UMC%d SDP ctrl: 0x%x
  ", i, umc->sdp_ctrl);
  		edac_dbg(1, "UMC%d ECC ctrl: 0x%x
  ", i, umc->ecc_ctrl);
  
  		amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_ECC_BAD_SYMBOL, &tmp);
  		edac_dbg(1, "UMC%d ECC bad symbol: 0x%x
  ", i, tmp);
  
  		amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_UMC_CAP, &tmp);
  		edac_dbg(1, "UMC%d UMC cap: 0x%x
  ", i, tmp);
  		edac_dbg(1, "UMC%d UMC cap high: 0x%x
  ", i, umc->umc_cap_hi);
  
  		edac_dbg(1, "UMC%d ECC capable: %s, ChipKill ECC capable: %s
  ",
  				i, (umc->umc_cap_hi & BIT(30)) ? "yes" : "no",
  				    (umc->umc_cap_hi & BIT(31)) ? "yes" : "no");
  		edac_dbg(1, "UMC%d All DIMMs support ECC: %s
  ",
  				i, (umc->umc_cfg & BIT(12)) ? "yes" : "no");
  		edac_dbg(1, "UMC%d x4 DIMMs present: %s
  ",
  				i, (umc->dimm_cfg & BIT(6)) ? "yes" : "no");
  		edac_dbg(1, "UMC%d x16 DIMMs present: %s
  ",
  				i, (umc->dimm_cfg & BIT(7)) ? "yes" : "no");
  
  		if (pvt->dram_type == MEM_LRDDR4) {
  			amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_ADDR_CFG, &tmp);
  			edac_dbg(1, "UMC%d LRDIMM %dx rank multiply
  ",
  					i, 1 << ((tmp >> 4) & 0x3));
  		}
  
  		debug_display_dimm_sizes_df(pvt, i);
  	}
  
  	edac_dbg(1, "F0x104 (DRAM Hole Address): 0x%08x, base: 0x%08x
  ",
  		 pvt->dhar, dhar_base(pvt));
  }
2da11654e   Doug Thompson   amd64_edac: add h...
873
  /* Display and decode various NB registers for debug purposes. */
07ed82ef9   Yazen Ghannam   EDAC, amd64: Add ...
874
  static void __dump_misc_regs(struct amd64_pvt *pvt)
2da11654e   Doug Thompson   amd64_edac: add h...
875
  {
956b9ba15   Joe Perches   edac: Convert deb...
876
877
  	edac_dbg(1, "F3xE8 (NB Cap): 0x%08x
  ", pvt->nbcap);
68798e176   Borislav Petkov   amd64_edac: clean...
878

956b9ba15   Joe Perches   edac: Convert deb...
879
880
881
  	edac_dbg(1, "  NB two channel DRAM capable: %s
  ",
  		 (pvt->nbcap & NBCAP_DCT_DUAL) ? "yes" : "no");
2da11654e   Doug Thompson   amd64_edac: add h...
882

956b9ba15   Joe Perches   edac: Convert deb...
883
884
885
886
  	edac_dbg(1, "  ECC capable: %s, ChipKill ECC capable: %s
  ",
  		 (pvt->nbcap & NBCAP_SECDED) ? "yes" : "no",
  		 (pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no");
68798e176   Borislav Petkov   amd64_edac: clean...
887

d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
888
  	debug_dump_dramcfg_low(pvt, pvt->dclr0, 0);
2da11654e   Doug Thompson   amd64_edac: add h...
889

956b9ba15   Joe Perches   edac: Convert deb...
890
891
  	edac_dbg(1, "F3xB0 (Online Spare): 0x%08x
  ", pvt->online_spare);
2da11654e   Doug Thompson   amd64_edac: add h...
892

956b9ba15   Joe Perches   edac: Convert deb...
893
894
895
  	edac_dbg(1, "F1xF0 (DRAM Hole Address): 0x%08x, base: 0x%08x, offset: 0x%08x
  ",
  		 pvt->dhar, dhar_base(pvt),
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
896
897
  		 (pvt->fam == 0xf) ? k8_dhar_offset(pvt)
  				   : f10_dhar_offset(pvt));
2da11654e   Doug Thompson   amd64_edac: add h...
898

d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
899
  	debug_display_dimm_sizes(pvt, 0);
4d7963648   Borislav Petkov   amd64_edac: Fix D...
900

8de1d91e6   Borislav Petkov   amd64_edac: clean...
901
  	/* everything below this point is Fam10h and above */
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
902
  	if (pvt->fam == 0xf)
2da11654e   Doug Thompson   amd64_edac: add h...
903
  		return;
4d7963648   Borislav Petkov   amd64_edac: Fix D...
904

d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
905
  	debug_display_dimm_sizes(pvt, 1);
2da11654e   Doug Thompson   amd64_edac: add h...
906

8de1d91e6   Borislav Petkov   amd64_edac: clean...
907
  	/* Only if NOT ganged does dclr1 have valid info */
68798e176   Borislav Petkov   amd64_edac: clean...
908
  	if (!dct_ganging_enabled(pvt))
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
909
  		debug_dump_dramcfg_low(pvt, pvt->dclr1, 1);
2da11654e   Doug Thompson   amd64_edac: add h...
910
  }
07ed82ef9   Yazen Ghannam   EDAC, amd64: Add ...
911
912
913
914
915
916
917
918
919
920
  /* Display and decode various NB registers for debug purposes. */
  static void dump_misc_regs(struct amd64_pvt *pvt)
  {
  	if (pvt->umc)
  		__dump_misc_regs_df(pvt);
  	else
  		__dump_misc_regs(pvt);
  
  	edac_dbg(1, "  DramHoleValid: %s
  ", dhar_valid(pvt) ? "yes" : "no");
7835961d3   Yazen Ghannam   EDAC/amd64: Recog...
921
922
  	amd64_info("using x%u syndromes.
  ", pvt->ecc_sym_sz);
07ed82ef9   Yazen Ghannam   EDAC, amd64: Add ...
923
  }
94be4bff2   Doug Thompson   amd64_edac: assig...
924
  /*
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
925
   * See BKDG, F2x[1,0][5C:40], F2[1,0][6C:60]
94be4bff2   Doug Thompson   amd64_edac: assig...
926
   */
11c75eada   Borislav Petkov   amd64_edac: Clean...
927
  static void prep_chip_selects(struct amd64_pvt *pvt)
94be4bff2   Doug Thompson   amd64_edac: assig...
928
  {
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
929
  	if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) {
11c75eada   Borislav Petkov   amd64_edac: Clean...
930
931
  		pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
  		pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 8;
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
932
  	} else if (pvt->fam == 0x15 && pvt->model == 0x30) {
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
933
934
  		pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4;
  		pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2;
d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
935
936
937
938
939
940
941
  	} else if (pvt->fam >= 0x17) {
  		int umc;
  
  		for_each_umc(umc) {
  			pvt->csels[umc].b_cnt = 4;
  			pvt->csels[umc].m_cnt = 2;
  		}
9d858bb10   Borislav Petkov   amd64_edac: fix c...
942
  	} else {
11c75eada   Borislav Petkov   amd64_edac: Clean...
943
944
  		pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
  		pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4;
94be4bff2   Doug Thompson   amd64_edac: assig...
945
946
  	}
  }
d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
947
948
  static void read_umc_base_mask(struct amd64_pvt *pvt)
  {
7574729e9   Yazen Ghannam   EDAC/amd64: Cache...
949
950
951
952
953
954
  	u32 umc_base_reg, umc_base_reg_sec;
  	u32 umc_mask_reg, umc_mask_reg_sec;
  	u32 base_reg, base_reg_sec;
  	u32 mask_reg, mask_reg_sec;
  	u32 *base, *base_sec;
  	u32 *mask, *mask_sec;
d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
955
956
957
958
  	int cs, umc;
  
  	for_each_umc(umc) {
  		umc_base_reg = get_umc_base(umc) + UMCCH_BASE_ADDR;
7574729e9   Yazen Ghannam   EDAC/amd64: Cache...
959
  		umc_base_reg_sec = get_umc_base(umc) + UMCCH_BASE_ADDR_SEC;
d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
960
961
962
  
  		for_each_chip_select(cs, umc, pvt) {
  			base = &pvt->csels[umc].csbases[cs];
7574729e9   Yazen Ghannam   EDAC/amd64: Cache...
963
  			base_sec = &pvt->csels[umc].csbases_sec[cs];
d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
964
965
  
  			base_reg = umc_base_reg + (cs * 4);
7574729e9   Yazen Ghannam   EDAC/amd64: Cache...
966
  			base_reg_sec = umc_base_reg_sec + (cs * 4);
d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
967
968
969
970
971
  
  			if (!amd_smn_read(pvt->mc_node_id, base_reg, base))
  				edac_dbg(0, "  DCSB%d[%d]=0x%08x reg: 0x%x
  ",
  					 umc, cs, *base, base_reg);
7574729e9   Yazen Ghannam   EDAC/amd64: Cache...
972
973
974
975
976
  
  			if (!amd_smn_read(pvt->mc_node_id, base_reg_sec, base_sec))
  				edac_dbg(0, "    DCSB_SEC%d[%d]=0x%08x reg: 0x%x
  ",
  					 umc, cs, *base_sec, base_reg_sec);
d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
977
978
979
  		}
  
  		umc_mask_reg = get_umc_base(umc) + UMCCH_ADDR_MASK;
7574729e9   Yazen Ghannam   EDAC/amd64: Cache...
980
  		umc_mask_reg_sec = get_umc_base(umc) + UMCCH_ADDR_MASK_SEC;
d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
981
982
983
  
  		for_each_chip_select_mask(cs, umc, pvt) {
  			mask = &pvt->csels[umc].csmasks[cs];
7574729e9   Yazen Ghannam   EDAC/amd64: Cache...
984
  			mask_sec = &pvt->csels[umc].csmasks_sec[cs];
d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
985
986
  
  			mask_reg = umc_mask_reg + (cs * 4);
7574729e9   Yazen Ghannam   EDAC/amd64: Cache...
987
  			mask_reg_sec = umc_mask_reg_sec + (cs * 4);
d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
988
989
990
991
992
  
  			if (!amd_smn_read(pvt->mc_node_id, mask_reg, mask))
  				edac_dbg(0, "  DCSM%d[%d]=0x%08x reg: 0x%x
  ",
  					 umc, cs, *mask, mask_reg);
7574729e9   Yazen Ghannam   EDAC/amd64: Cache...
993
994
995
996
997
  
  			if (!amd_smn_read(pvt->mc_node_id, mask_reg_sec, mask_sec))
  				edac_dbg(0, "    DCSM_SEC%d[%d]=0x%08x reg: 0x%x
  ",
  					 umc, cs, *mask_sec, mask_reg_sec);
d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
998
999
1000
  		}
  	}
  }
94be4bff2   Doug Thompson   amd64_edac: assig...
1001
  /*
11c75eada   Borislav Petkov   amd64_edac: Clean...
1002
   * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers
94be4bff2   Doug Thompson   amd64_edac: assig...
1003
   */
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
1004
  static void read_dct_base_mask(struct amd64_pvt *pvt)
94be4bff2   Doug Thompson   amd64_edac: assig...
1005
  {
d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
1006
  	int cs;
94be4bff2   Doug Thompson   amd64_edac: assig...
1007

11c75eada   Borislav Petkov   amd64_edac: Clean...
1008
  	prep_chip_selects(pvt);
94be4bff2   Doug Thompson   amd64_edac: assig...
1009

d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
1010
1011
  	if (pvt->umc)
  		return read_umc_base_mask(pvt);
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
1012

11c75eada   Borislav Petkov   amd64_edac: Clean...
1013
  	for_each_chip_select(cs, 0, pvt) {
d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
1014
1015
  		int reg0   = DCSB0 + (cs * 4);
  		int reg1   = DCSB1 + (cs * 4);
11c75eada   Borislav Petkov   amd64_edac: Clean...
1016
1017
  		u32 *base0 = &pvt->csels[0].csbases[cs];
  		u32 *base1 = &pvt->csels[1].csbases[cs];
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
1018

d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
1019
1020
1021
1022
  		if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, base0))
  			edac_dbg(0, "  DCSB0[%d]=0x%08x reg: F2x%x
  ",
  				 cs, *base0, reg0);
8de9930a4   Borislav Petkov   Revert "EDAC/amd6...
1023

d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
1024
1025
  		if (pvt->fam == 0xf)
  			continue;
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
1026

d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
1027
1028
1029
1030
1031
  		if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, base1))
  			edac_dbg(0, "  DCSB1[%d]=0x%08x reg: F2x%x
  ",
  				 cs, *base1, (pvt->fam == 0x10) ? reg1
  							: reg0);
94be4bff2   Doug Thompson   amd64_edac: assig...
1032
  	}
11c75eada   Borislav Petkov   amd64_edac: Clean...
1033
  	for_each_chip_select_mask(cs, 0, pvt) {
d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
1034
1035
  		int reg0   = DCSM0 + (cs * 4);
  		int reg1   = DCSM1 + (cs * 4);
11c75eada   Borislav Petkov   amd64_edac: Clean...
1036
1037
  		u32 *mask0 = &pvt->csels[0].csmasks[cs];
  		u32 *mask1 = &pvt->csels[1].csmasks[cs];
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
1038

d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
1039
1040
1041
1042
  		if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, mask0))
  			edac_dbg(0, "    DCSM0[%d]=0x%08x reg: F2x%x
  ",
  				 cs, *mask0, reg0);
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
1043

d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
1044
1045
  		if (pvt->fam == 0xf)
  			continue;
8de9930a4   Borislav Petkov   Revert "EDAC/amd6...
1046

d971e28e2   Yazen Ghannam   EDAC/amd64: Suppo...
1047
1048
1049
1050
1051
  		if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, mask1))
  			edac_dbg(0, "    DCSM1[%d]=0x%08x reg: F2x%x
  ",
  				 cs, *mask1, (pvt->fam == 0x10) ? reg1
  							: reg0);
94be4bff2   Doug Thompson   amd64_edac: assig...
1052
1053
  	}
  }
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1054
  static void determine_memory_type(struct amd64_pvt *pvt)
94be4bff2   Doug Thompson   amd64_edac: assig...
1055
  {
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1056
  	u32 dram_ctrl, dcsm;
94be4bff2   Doug Thompson   amd64_edac: assig...
1057

dcd01394c   Yazen Ghannam   EDAC/amd64: Drop ...
1058
1059
1060
1061
1062
1063
1064
1065
1066
  	if (pvt->umc) {
  		if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(5))
  			pvt->dram_type = MEM_LRDDR4;
  		else if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(4))
  			pvt->dram_type = MEM_RDDR4;
  		else
  			pvt->dram_type = MEM_DDR4;
  		return;
  	}
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1067
1068
1069
1070
1071
1072
1073
1074
1075
  	switch (pvt->fam) {
  	case 0xf:
  		if (pvt->ext_model >= K8_REV_F)
  			goto ddr3;
  
  		pvt->dram_type = (pvt->dclr0 & BIT(18)) ? MEM_DDR : MEM_RDDR;
  		return;
  
  	case 0x10:
6b4c0bdeb   Borislav Petkov   amd64_edac: detec...
1076
  		if (pvt->dchr0 & DDR3_MODE)
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
  			goto ddr3;
  
  		pvt->dram_type = (pvt->dclr0 & BIT(16)) ? MEM_DDR2 : MEM_RDDR2;
  		return;
  
  	case 0x15:
  		if (pvt->model < 0x60)
  			goto ddr3;
  
  		/*
  		 * Model 0x60h needs special handling:
  		 *
  		 * We use a Chip Select value of '0' to obtain dcsm.
  		 * Theoretically, it is possible to populate LRDIMMs of different
  		 * 'Rank' value on a DCT. But this is not the common case. So,
  		 * it's reasonable to assume all DIMMs are going to be of same
  		 * 'type' until proven otherwise.
  		 */
  		amd64_read_dct_pci_cfg(pvt, 0, DRAM_CONTROL, &dram_ctrl);
  		dcsm = pvt->csels[0].csmasks[0];
  
  		if (((dram_ctrl >> 8) & 0x7) == 0x2)
  			pvt->dram_type = MEM_DDR4;
  		else if (pvt->dclr0 & BIT(16))
  			pvt->dram_type = MEM_DDR3;
  		else if (dcsm & 0x3)
  			pvt->dram_type = MEM_LRDDR3;
6b4c0bdeb   Borislav Petkov   amd64_edac: detec...
1104
  		else
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1105
  			pvt->dram_type = MEM_RDDR3;
94be4bff2   Doug Thompson   amd64_edac: assig...
1106

a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
  		return;
  
  	case 0x16:
  		goto ddr3;
  
  	default:
  		WARN(1, KERN_ERR "%s: Family??? 0x%x
  ", __func__, pvt->fam);
  		pvt->dram_type = MEM_EMPTY;
  	}
  	return;
94be4bff2   Doug Thompson   amd64_edac: assig...
1118

a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1119
1120
  ddr3:
  	pvt->dram_type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3;
94be4bff2   Doug Thompson   amd64_edac: assig...
1121
  }
cb3285074   Borislav Petkov   amd64_edac: Clean...
1122
  /* Get the number of DCT channels the memory controller is using. */
ddff876d2   Doug Thompson   amd64_edac: add k...
1123
1124
  static int k8_early_channel_count(struct amd64_pvt *pvt)
  {
cb3285074   Borislav Petkov   amd64_edac: Clean...
1125
  	int flag;
ddff876d2   Doug Thompson   amd64_edac: add k...
1126

9f56da0e3   Borislav Petkov   amd64_edac: Use c...
1127
  	if (pvt->ext_model >= K8_REV_F)
ddff876d2   Doug Thompson   amd64_edac: add k...
1128
  		/* RevF (NPT) and later */
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1129
  		flag = pvt->dclr0 & WIDTH_128;
9f56da0e3   Borislav Petkov   amd64_edac: Use c...
1130
  	else
ddff876d2   Doug Thompson   amd64_edac: add k...
1131
1132
  		/* RevE and earlier */
  		flag = pvt->dclr0 & REVE_WIDTH_128;
ddff876d2   Doug Thompson   amd64_edac: add k...
1133
1134
1135
1136
1137
1138
  
  	/* not used */
  	pvt->dclr1 = 0;
  
  	return (flag) ? 2 : 1;
  }
700466249   Borislav Petkov   amd64_edac: Unify...
1139
  /* On F10h and later ErrAddr is MC4_ADDR[47:1] */
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
1140
  static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m)
ddff876d2   Doug Thompson   amd64_edac: add k...
1141
  {
2ec591ac7   Borislav Petkov   EDAC, amd64_edac:...
1142
1143
  	u16 mce_nid = amd_get_nb_id(m->extcpu);
  	struct mem_ctl_info *mci;
700466249   Borislav Petkov   amd64_edac: Unify...
1144
1145
  	u8 start_bit = 1;
  	u8 end_bit   = 47;
2ec591ac7   Borislav Petkov   EDAC, amd64_edac:...
1146
1147
1148
1149
1150
1151
1152
  	u64 addr;
  
  	mci = edac_mc_find(mce_nid);
  	if (!mci)
  		return 0;
  
  	pvt = mci->pvt_info;
700466249   Borislav Petkov   amd64_edac: Unify...
1153

a4b4bedce   Borislav Petkov   amd64_edac: Get r...
1154
  	if (pvt->fam == 0xf) {
700466249   Borislav Petkov   amd64_edac: Unify...
1155
1156
1157
  		start_bit = 3;
  		end_bit   = 39;
  	}
10ef6b0df   Chen, Gong   bitops: Introduce...
1158
  	addr = m->addr & GENMASK_ULL(end_bit, start_bit);
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1159
1160
1161
1162
  
  	/*
  	 * Erratum 637 workaround
  	 */
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
1163
  	if (pvt->fam == 0x15) {
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1164
1165
  		u64 cc6_base, tmp_addr;
  		u32 tmp;
8b84c8df3   Daniel J Blueman   x86, AMD, NB: Use...
1166
  		u8 intlv_en;
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1167

10ef6b0df   Chen, Gong   bitops: Introduce...
1168
  		if ((addr & GENMASK_ULL(47, 24)) >> 24 != 0x00fdf7)
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1169
  			return addr;
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1170
1171
1172
1173
1174
  
  		amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_LIM, &tmp);
  		intlv_en = tmp >> 21 & 0x7;
  
  		/* add [47:27] + 3 trailing bits */
10ef6b0df   Chen, Gong   bitops: Introduce...
1175
  		cc6_base  = (tmp & GENMASK_ULL(20, 0)) << 3;
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1176
1177
1178
1179
1180
1181
1182
1183
  
  		/* reverse and add DramIntlvEn */
  		cc6_base |= intlv_en ^ 0x7;
  
  		/* pin at [47:24] */
  		cc6_base <<= 24;
  
  		if (!intlv_en)
10ef6b0df   Chen, Gong   bitops: Introduce...
1184
  			return cc6_base | (addr & GENMASK_ULL(23, 0));
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1185
1186
1187
1188
  
  		amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_BASE, &tmp);
  
  							/* faster log2 */
10ef6b0df   Chen, Gong   bitops: Introduce...
1189
  		tmp_addr  = (addr & GENMASK_ULL(23, 12)) << __fls(intlv_en + 1);
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1190
1191
  
  		/* OR DramIntlvSel into bits [14:12] */
10ef6b0df   Chen, Gong   bitops: Introduce...
1192
  		tmp_addr |= (tmp & GENMASK_ULL(23, 21)) >> 9;
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1193
1194
  
  		/* add remaining [11:0] bits from original MC4_ADDR */
10ef6b0df   Chen, Gong   bitops: Introduce...
1195
  		tmp_addr |= addr & GENMASK_ULL(11, 0);
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1196
1197
1198
1199
1200
  
  		return cc6_base | tmp_addr;
  	}
  
  	return addr;
ddff876d2   Doug Thompson   amd64_edac: add k...
1201
  }
e2c0bffea   Daniel J Blueman   amd64_edac: Fix P...
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
  static struct pci_dev *pci_get_related_function(unsigned int vendor,
  						unsigned int device,
  						struct pci_dev *related)
  {
  	struct pci_dev *dev = NULL;
  
  	while ((dev = pci_get_device(vendor, device, dev))) {
  		if (pci_domain_nr(dev->bus) == pci_domain_nr(related->bus) &&
  		    (dev->bus->number == related->bus->number) &&
  		    (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
  			break;
  	}
  
  	return dev;
  }
7f19bf755   Borislav Petkov   amd64_edac: Remov...
1217
  static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
ddff876d2   Doug Thompson   amd64_edac: add k...
1218
  {
e2c0bffea   Daniel J Blueman   amd64_edac: Fix P...
1219
  	struct amd_northbridge *nb;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1220
1221
  	struct pci_dev *f1 = NULL;
  	unsigned int pci_func;
71d2a32e8   Borislav Petkov   amd64_edac: Fix P...
1222
  	int off = range << 3;
e2c0bffea   Daniel J Blueman   amd64_edac: Fix P...
1223
  	u32 llim;
ddff876d2   Doug Thompson   amd64_edac: add k...
1224

7f19bf755   Borislav Petkov   amd64_edac: Remov...
1225
1226
  	amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off,  &pvt->ranges[range].base.lo);
  	amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
ddff876d2   Doug Thompson   amd64_edac: add k...
1227

18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1228
  	if (pvt->fam == 0xf)
7f19bf755   Borislav Petkov   amd64_edac: Remov...
1229
  		return;
ddff876d2   Doug Thompson   amd64_edac: add k...
1230

7f19bf755   Borislav Petkov   amd64_edac: Remov...
1231
1232
  	if (!dram_rw(pvt, range))
  		return;
ddff876d2   Doug Thompson   amd64_edac: add k...
1233

7f19bf755   Borislav Petkov   amd64_edac: Remov...
1234
1235
  	amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off,  &pvt->ranges[range].base.hi);
  	amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
f08e457ce   Borislav Petkov   amd64_edac: Facto...
1236

e2c0bffea   Daniel J Blueman   amd64_edac: Fix P...
1237
  	/* F15h: factor in CC6 save area by reading dst node's limit reg */
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1238
  	if (pvt->fam != 0x15)
e2c0bffea   Daniel J Blueman   amd64_edac: Fix P...
1239
  		return;
f08e457ce   Borislav Petkov   amd64_edac: Facto...
1240

e2c0bffea   Daniel J Blueman   amd64_edac: Fix P...
1241
1242
1243
  	nb = node_to_amd_nb(dram_dst_node(pvt, range));
  	if (WARN_ON(!nb))
  		return;
f08e457ce   Borislav Petkov   amd64_edac: Facto...
1244

a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1245
1246
1247
1248
1249
1250
  	if (pvt->model == 0x60)
  		pci_func = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1;
  	else if (pvt->model == 0x30)
  		pci_func = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1;
  	else
  		pci_func = PCI_DEVICE_ID_AMD_15H_NB_F1;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1251
1252
  
  	f1 = pci_get_related_function(nb->misc->vendor, pci_func, nb->misc);
e2c0bffea   Daniel J Blueman   amd64_edac: Fix P...
1253
1254
  	if (WARN_ON(!f1))
  		return;
f08e457ce   Borislav Petkov   amd64_edac: Facto...
1255

e2c0bffea   Daniel J Blueman   amd64_edac: Fix P...
1256
  	amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
f08e457ce   Borislav Petkov   amd64_edac: Facto...
1257

10ef6b0df   Chen, Gong   bitops: Introduce...
1258
  	pvt->ranges[range].lim.lo &= GENMASK_ULL(15, 0);
f08e457ce   Borislav Petkov   amd64_edac: Facto...
1259

e2c0bffea   Daniel J Blueman   amd64_edac: Fix P...
1260
1261
  				    /* {[39:27],111b} */
  	pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
f08e457ce   Borislav Petkov   amd64_edac: Facto...
1262

10ef6b0df   Chen, Gong   bitops: Introduce...
1263
  	pvt->ranges[range].lim.hi &= GENMASK_ULL(7, 0);
f08e457ce   Borislav Petkov   amd64_edac: Facto...
1264

e2c0bffea   Daniel J Blueman   amd64_edac: Fix P...
1265
1266
1267
1268
  				    /* [47:40] */
  	pvt->ranges[range].lim.hi |= llim >> 13;
  
  	pci_dev_put(f1);
ddff876d2   Doug Thompson   amd64_edac: add k...
1269
  }
f192c7b16   Borislav Petkov   amd64_edac: Simpl...
1270
  static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1271
  				    struct err_info *err)
ddff876d2   Doug Thompson   amd64_edac: add k...
1272
  {
f192c7b16   Borislav Petkov   amd64_edac: Simpl...
1273
  	struct amd64_pvt *pvt = mci->pvt_info;
ddff876d2   Doug Thompson   amd64_edac: add k...
1274

33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1275
  	error_address_to_page_and_offset(sys_addr, err);
ab5a503cb   Mauro Carvalho Chehab   amd64_edac: conve...
1276
1277
1278
1279
1280
  
  	/*
  	 * Find out which node the error address belongs to. This may be
  	 * different from the node that detected the error.
  	 */
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1281
1282
  	err->src_mci = find_mc_by_sys_addr(mci, sys_addr);
  	if (!err->src_mci) {
ab5a503cb   Mauro Carvalho Chehab   amd64_edac: conve...
1283
1284
1285
  		amd64_mc_err(mci, "failed to map error addr 0x%lx to a node
  ",
  			     (unsigned long)sys_addr);
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1286
  		err->err_code = ERR_NODE;
ab5a503cb   Mauro Carvalho Chehab   amd64_edac: conve...
1287
1288
1289
1290
  		return;
  	}
  
  	/* Now map the sys_addr to a CSROW */
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1291
1292
1293
  	err->csrow = sys_addr_to_csrow(err->src_mci, sys_addr);
  	if (err->csrow < 0) {
  		err->err_code = ERR_CSROW;
ab5a503cb   Mauro Carvalho Chehab   amd64_edac: conve...
1294
1295
  		return;
  	}
ddff876d2   Doug Thompson   amd64_edac: add k...
1296
  	/* CHIPKILL enabled */
f192c7b16   Borislav Petkov   amd64_edac: Simpl...
1297
  	if (pvt->nbcfg & NBCFG_CHIPKILL) {
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1298
1299
  		err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome);
  		if (err->channel < 0) {
ddff876d2   Doug Thompson   amd64_edac: add k...
1300
1301
1302
1303
1304
  			/*
  			 * Syndrome didn't map, so we don't know which of the
  			 * 2 DIMMs is in error. So we need to ID 'both' of them
  			 * as suspect.
  			 */
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1305
  			amd64_mc_warn(err->src_mci, "unknown syndrome 0x%04x - "
ab5a503cb   Mauro Carvalho Chehab   amd64_edac: conve...
1306
1307
  				      "possible error reporting race
  ",
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1308
1309
  				      err->syndrome);
  			err->err_code = ERR_CHANNEL;
ddff876d2   Doug Thompson   amd64_edac: add k...
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
  			return;
  		}
  	} else {
  		/*
  		 * non-chipkill ecc mode
  		 *
  		 * The k8 documentation is unclear about how to determine the
  		 * channel number when using non-chipkill memory.  This method
  		 * was obtained from email communication with someone at AMD.
  		 * (Wish the email was placed in this comment - norsk)
  		 */
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1321
  		err->channel = ((sys_addr & BIT(3)) != 0);
ddff876d2   Doug Thompson   amd64_edac: add k...
1322
  	}
ddff876d2   Doug Thompson   amd64_edac: add k...
1323
  }
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1324
  static int ddr2_cs_size(unsigned i, bool dct_width)
ddff876d2   Doug Thompson   amd64_edac: add k...
1325
  {
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1326
  	unsigned shift = 0;
ddff876d2   Doug Thompson   amd64_edac: add k...
1327

41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1328
1329
1330
1331
  	if (i <= 2)
  		shift = i;
  	else if (!(i & 0x1))
  		shift = i >> 1;
1433eb990   Borislav Petkov   amd64_edac: enhan...
1332
  	else
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1333
  		shift = (i + 1) >> 1;
ddff876d2   Doug Thompson   amd64_edac: add k...
1334

41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1335
1336
1337
1338
  	return 128 << (shift + !!dct_width);
  }
  
  static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1339
  				  unsigned cs_mode, int cs_mask_nr)
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1340
1341
1342
1343
1344
1345
1346
1347
  {
  	u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
  
  	if (pvt->ext_model >= K8_REV_F) {
  		WARN_ON(cs_mode > 11);
  		return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
  	}
  	else if (pvt->ext_model >= K8_REV_D) {
11b0a3147   Borislav Petkov   amd64_edac: Fix K...
1348
  		unsigned diff;
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1349
  		WARN_ON(cs_mode > 10);
11b0a3147   Borislav Petkov   amd64_edac: Fix K...
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
  		/*
  		 * the below calculation, besides trying to win an obfuscated C
  		 * contest, maps cs_mode values to DIMM chip select sizes. The
  		 * mappings are:
  		 *
  		 * cs_mode	CS size (mb)
  		 * =======	============
  		 * 0		32
  		 * 1		64
  		 * 2		128
  		 * 3		128
  		 * 4		256
  		 * 5		512
  		 * 6		256
  		 * 7		512
  		 * 8		1024
  		 * 9		1024
  		 * 10		2048
  		 *
  		 * Basically, it calculates a value with which to shift the
  		 * smallest CS size of 32MB.
  		 *
  		 * ddr[23]_cs_size have a similar purpose.
  		 */
  		diff = cs_mode/3 + (unsigned)(cs_mode > 5);
  
  		return 32 << (cs_mode - diff);
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1377
1378
1379
1380
1381
  	}
  	else {
  		WARN_ON(cs_mode > 6);
  		return 32 << cs_mode;
  	}
ddff876d2   Doug Thompson   amd64_edac: add k...
1382
  }
1afd3c98b   Doug Thompson   amd64_edac: add F...
1383
1384
1385
1386
1387
1388
1389
1390
  /*
   * Get the number of DCT channels in use.
   *
   * Return:
   *	number of Memory Channels in operation
   * Pass back:
   *	contents of the DCL0_LOW register
   */
7d20d14da   Borislav Petkov   amd64_edac: Adjus...
1391
  static int f1x_early_channel_count(struct amd64_pvt *pvt)
1afd3c98b   Doug Thompson   amd64_edac: add F...
1392
  {
6ba5dcdc4   Borislav Petkov   amd64_edac: wrap-...
1393
  	int i, j, channels = 0;
1afd3c98b   Doug Thompson   amd64_edac: add F...
1394

7d20d14da   Borislav Petkov   amd64_edac: Adjus...
1395
  	/* On F10h, if we are in 128 bit mode, then we are using 2 channels */
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
1396
  	if (pvt->fam == 0x10 && (pvt->dclr0 & WIDTH_128))
7d20d14da   Borislav Petkov   amd64_edac: Adjus...
1397
  		return 2;
1afd3c98b   Doug Thompson   amd64_edac: add F...
1398
1399
  
  	/*
d16149e8c   Borislav Petkov   amd64_edac: clean...
1400
1401
1402
  	 * Need to check if in unganged mode: In such, there are 2 channels,
  	 * but they are not in 128 bit mode and thus the above 'dclr0' status
  	 * bit will be OFF.
1afd3c98b   Doug Thompson   amd64_edac: add F...
1403
1404
1405
1406
  	 *
  	 * Need to check DCT0[0] and DCT1[0] to see if only one of them has
  	 * their CSEnable bit on. If so, then SINGLE DIMM case.
  	 */
956b9ba15   Joe Perches   edac: Convert deb...
1407
1408
  	edac_dbg(0, "Data width is not 128 bits - need more decoding
  ");
ddff876d2   Doug Thompson   amd64_edac: add k...
1409

1afd3c98b   Doug Thompson   amd64_edac: add F...
1410
1411
1412
1413
1414
  	/*
  	 * Check DRAM Bank Address Mapping values for each DIMM to see if there
  	 * is more than just one DIMM present in unganged mode. Need to check
  	 * both controllers since DIMMs can be placed in either one.
  	 */
525a1b20a   Borislav Petkov   amd64_edac: Clean...
1415
1416
  	for (i = 0; i < 2; i++) {
  		u32 dbam = (i ? pvt->dbam1 : pvt->dbam0);
1afd3c98b   Doug Thompson   amd64_edac: add F...
1417

57a30854c   Wan Wei   amd64_edac: Rewri...
1418
1419
1420
1421
1422
1423
  		for (j = 0; j < 4; j++) {
  			if (DBAM_DIMM(j, dbam) > 0) {
  				channels++;
  				break;
  			}
  		}
1afd3c98b   Doug Thompson   amd64_edac: add F...
1424
  	}
d16149e8c   Borislav Petkov   amd64_edac: clean...
1425
1426
  	if (channels > 2)
  		channels = 2;
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
1427
1428
  	amd64_info("MCT channel count: %d
  ", channels);
1afd3c98b   Doug Thompson   amd64_edac: add F...
1429
1430
  
  	return channels;
1afd3c98b   Doug Thompson   amd64_edac: add F...
1431
  }
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
1432
1433
1434
1435
1436
  static int f17_early_channel_count(struct amd64_pvt *pvt)
  {
  	int i, channels = 0;
  
  	/* SDP Control bit 31 (SdpInit) is clear for unused UMC channels */
4d30d2bc3   Yazen Ghannam   EDAC/amd64: Use a...
1437
  	for_each_umc(i)
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
1438
1439
1440
1441
1442
1443
1444
  		channels += !!(pvt->umc[i].sdp_ctrl & UMC_SDP_INIT);
  
  	amd64_info("MCT channel count: %d
  ", channels);
  
  	return channels;
  }
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1445
  static int ddr3_cs_size(unsigned i, bool dct_width)
1afd3c98b   Doug Thompson   amd64_edac: add F...
1446
  {
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
  	unsigned shift = 0;
  	int cs_size = 0;
  
  	if (i == 0 || i == 3 || i == 4)
  		cs_size = -1;
  	else if (i <= 2)
  		shift = i;
  	else if (i == 12)
  		shift = 7;
  	else if (!(i & 0x1))
  		shift = i >> 1;
  	else
  		shift = (i + 1) >> 1;
  
  	if (cs_size != -1)
  		cs_size = (128 * (1 << !!dct_width)) << shift;
  
  	return cs_size;
  }
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
  static int ddr3_lrdimm_cs_size(unsigned i, unsigned rank_multiply)
  {
  	unsigned shift = 0;
  	int cs_size = 0;
  
  	if (i < 4 || i == 6)
  		cs_size = -1;
  	else if (i == 12)
  		shift = 7;
  	else if (!(i & 0x1))
  		shift = i >> 1;
  	else
  		shift = (i + 1) >> 1;
  
  	if (cs_size != -1)
  		cs_size = rank_multiply * (128 << shift);
  
  	return cs_size;
  }
  
  static int ddr4_cs_size(unsigned i)
  {
  	int cs_size = 0;
  
  	if (i == 0)
  		cs_size = -1;
  	else if (i == 1)
  		cs_size = 1024;
  	else
  		/* Min cs_size = 1G */
  		cs_size = 1024 * (1 << (i >> 1));
  
  	return cs_size;
  }
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1500
  static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1501
  				   unsigned cs_mode, int cs_mask_nr)
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1502
1503
1504
1505
  {
  	u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
  
  	WARN_ON(cs_mode > 11);
1433eb990   Borislav Petkov   amd64_edac: enhan...
1506
1507
  
  	if (pvt->dchr0 & DDR3_MODE || pvt->dchr1 & DDR3_MODE)
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1508
  		return ddr3_cs_size(cs_mode, dclr & WIDTH_128);
1433eb990   Borislav Petkov   amd64_edac: enhan...
1509
  	else
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1510
1511
1512
1513
1514
1515
1516
  		return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
  }
  
  /*
   * F15h supports only 64bit DCT interfaces
   */
  static int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1517
  				   unsigned cs_mode, int cs_mask_nr)
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1518
1519
  {
  	WARN_ON(cs_mode > 12);
1433eb990   Borislav Petkov   amd64_edac: enhan...
1520

41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1521
  	return ddr3_cs_size(cs_mode, false);
1afd3c98b   Doug Thompson   amd64_edac: add F...
1522
  }
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
  /* F15h M60h supports DDR4 mapping as well.. */
  static int f15_m60h_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
  					unsigned cs_mode, int cs_mask_nr)
  {
  	int cs_size;
  	u32 dcsm = pvt->csels[dct].csmasks[cs_mask_nr];
  
  	WARN_ON(cs_mode > 12);
  
  	if (pvt->dram_type == MEM_DDR4) {
  		if (cs_mode > 9)
  			return -1;
  
  		cs_size = ddr4_cs_size(cs_mode);
  	} else if (pvt->dram_type == MEM_LRDDR3) {
  		unsigned rank_multiply = dcsm & 0xf;
  
  		if (rank_multiply == 3)
  			rank_multiply = 4;
  		cs_size = ddr3_lrdimm_cs_size(cs_mode, rank_multiply);
  	} else {
  		/* Minimum cs size is 512mb for F15hM60h*/
  		if (cs_mode == 0x1)
  			return -1;
  
  		cs_size = ddr3_cs_size(cs_mode, false);
  	}
  
  	return cs_size;
  }
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
1553
  /*
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1554
   * F16h and F15h model 30h have only limited cs_modes.
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
1555
1556
   */
  static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1557
  				unsigned cs_mode, int cs_mask_nr)
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
1558
1559
1560
1561
1562
1563
1564
1565
1566
  {
  	WARN_ON(cs_mode > 12);
  
  	if (cs_mode == 6 || cs_mode == 8 ||
  	    cs_mode == 9 || cs_mode == 12)
  		return -1;
  	else
  		return ddr3_cs_size(cs_mode, false);
  }
e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
1567
  static int f17_addr_mask_to_cs_size(struct amd64_pvt *pvt, u8 umc,
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
1568
1569
  				    unsigned int cs_mode, int csrow_nr)
  {
e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
1570
1571
1572
  	u32 addr_mask_orig, addr_mask_deinterleaved;
  	u32 msb, weight, num_zero_bits;
  	int dimm, size = 0;
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
1573

e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
1574
1575
1576
  	/* No Chip Selects are enabled. */
  	if (!cs_mode)
  		return size;
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
1577

e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
1578
1579
1580
  	/* Requested size of an even CS but none are enabled. */
  	if (!(cs_mode & CS_EVEN) && !(csrow_nr & 1))
  		return size;
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
1581

e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
  	/* Requested size of an odd CS but none are enabled. */
  	if (!(cs_mode & CS_ODD) && (csrow_nr & 1))
  		return size;
  
  	/*
  	 * There is one mask per DIMM, and two Chip Selects per DIMM.
  	 *	CS0 and CS1 -> DIMM0
  	 *	CS2 and CS3 -> DIMM1
  	 */
  	dimm = csrow_nr >> 1;
81f5090db   Yazen Ghannam   EDAC/amd64: Suppo...
1592
1593
1594
1595
1596
  	/* Asymmetric dual-rank DIMM support. */
  	if ((csrow_nr & 1) && (cs_mode & CS_ODD_SECONDARY))
  		addr_mask_orig = pvt->csels[umc].csmasks_sec[dimm];
  	else
  		addr_mask_orig = pvt->csels[umc].csmasks[dimm];
e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
  
  	/*
  	 * The number of zero bits in the mask is equal to the number of bits
  	 * in a full mask minus the number of bits in the current mask.
  	 *
  	 * The MSB is the number of bits in the full mask because BIT[0] is
  	 * always 0.
  	 */
  	msb = fls(addr_mask_orig) - 1;
  	weight = hweight_long(addr_mask_orig);
  	num_zero_bits = msb - weight;
  
  	/* Take the number of zero bits off from the top of the mask. */
  	addr_mask_deinterleaved = GENMASK_ULL(msb - num_zero_bits, 1);
  
  	edac_dbg(1, "CS%d DIMM%d AddrMasks:
  ", csrow_nr, dimm);
  	edac_dbg(1, "  Original AddrMask: 0x%x
  ", addr_mask_orig);
  	edac_dbg(1, "  Deinterleaved AddrMask: 0x%x
  ", addr_mask_deinterleaved);
  
  	/* Register [31:1] = Address [39:9]. Size is in kBs here. */
  	size = (addr_mask_deinterleaved >> 2) + 1;
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
1621
1622
1623
1624
  
  	/* Return size in MBs. */
  	return size >> 10;
  }
5a5d23716   Borislav Petkov   amd64_edac: Sanit...
1625
  static void read_dram_ctl_register(struct amd64_pvt *pvt)
6163b5d4f   Doug Thompson   amd64_edac: add F...
1626
  {
6163b5d4f   Doug Thompson   amd64_edac: add F...
1627

a4b4bedce   Borislav Petkov   amd64_edac: Get r...
1628
  	if (pvt->fam == 0xf)
5a5d23716   Borislav Petkov   amd64_edac: Sanit...
1629
  		return;
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
1630
  	if (!amd64_read_pci_cfg(pvt->F2, DCT_SEL_LO, &pvt->dct_sel_lo)) {
956b9ba15   Joe Perches   edac: Convert deb...
1631
1632
1633
  		edac_dbg(0, "F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x
  ",
  			 pvt->dct_sel_lo, dct_sel_baseaddr(pvt));
72381bd55   Borislav Petkov   amd64_edac: clari...
1634

956b9ba15   Joe Perches   edac: Convert deb...
1635
1636
1637
  		edac_dbg(0, "  DCTs operate in %s mode
  ",
  			 (dct_ganging_enabled(pvt) ? "ganged" : "unganged"));
72381bd55   Borislav Petkov   amd64_edac: clari...
1638
1639
  
  		if (!dct_ganging_enabled(pvt))
956b9ba15   Joe Perches   edac: Convert deb...
1640
1641
1642
  			edac_dbg(0, "  Address range split per DCT: %s
  ",
  				 (dct_high_range_enabled(pvt) ? "yes" : "no"));
72381bd55   Borislav Petkov   amd64_edac: clari...
1643

956b9ba15   Joe Perches   edac: Convert deb...
1644
1645
1646
1647
  		edac_dbg(0, "  data interleave for ECC: %s, DRAM cleared since last warm reset: %s
  ",
  			 (dct_data_intlv_enabled(pvt) ? "enabled" : "disabled"),
  			 (dct_memory_cleared(pvt) ? "yes" : "no"));
72381bd55   Borislav Petkov   amd64_edac: clari...
1648

956b9ba15   Joe Perches   edac: Convert deb...
1649
1650
1651
1652
1653
  		edac_dbg(0, "  channel interleave: %s, "
  			 "interleave bits selector: 0x%x
  ",
  			 (dct_interleave_enabled(pvt) ? "enabled" : "disabled"),
  			 dct_sel_interleave_addr(pvt));
6163b5d4f   Doug Thompson   amd64_edac: add F...
1654
  	}
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
1655
  	amd64_read_pci_cfg(pvt->F2, DCT_SEL_HI, &pvt->dct_sel_hi);
6163b5d4f   Doug Thompson   amd64_edac: add F...
1656
  }
f71d0a050   Doug Thompson   amd64_edac: add F...
1657
  /*
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
   * Determine channel (DCT) based on the interleaving mode (see F15h M30h BKDG,
   * 2.10.12 Memory Interleaving Modes).
   */
  static u8 f15_m30h_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
  				     u8 intlv_en, int num_dcts_intlv,
  				     u32 dct_sel)
  {
  	u8 channel = 0;
  	u8 select;
  
  	if (!(intlv_en))
  		return (u8)(dct_sel);
  
  	if (num_dcts_intlv == 2) {
  		select = (sys_addr >> 8) & 0x3;
  		channel = select ? 0x3 : 0;
9d0e8d834   Aravind Gopalakrishnan   amd64_edac: Fix l...
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
  	} else if (num_dcts_intlv == 4) {
  		u8 intlv_addr = dct_sel_interleave_addr(pvt);
  		switch (intlv_addr) {
  		case 0x4:
  			channel = (sys_addr >> 8) & 0x3;
  			break;
  		case 0x5:
  			channel = (sys_addr >> 9) & 0x3;
  			break;
  		}
  	}
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1685
1686
1687
1688
  	return channel;
  }
  
  /*
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1689
   * Determine channel (DCT) based on the interleaving mode: F10h BKDG, 2.8.9 Memory
f71d0a050   Doug Thompson   amd64_edac: add F...
1690
1691
   * Interleaving Modes.
   */
b15f0fcab   Borislav Petkov   amd64_edac: Adjus...
1692
  static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1693
  				bool hi_range_sel, u8 intlv_en)
6163b5d4f   Doug Thompson   amd64_edac: add F...
1694
  {
151fa71c5   Borislav Petkov   amd64_edac: Fix D...
1695
  	u8 dct_sel_high = (pvt->dct_sel_lo >> 1) & 1;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1696
1697
  
  	if (dct_ganging_enabled(pvt))
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1698
  		return 0;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1699

229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1700
1701
  	if (hi_range_sel)
  		return dct_sel_high;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1702

229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
  	/*
  	 * see F2x110[DctSelIntLvAddr] - channel interleave mode
  	 */
  	if (dct_interleave_enabled(pvt)) {
  		u8 intlv_addr = dct_sel_interleave_addr(pvt);
  
  		/* return DCT select function: 0=DCT0, 1=DCT1 */
  		if (!intlv_addr)
  			return sys_addr >> 6 & 1;
  
  		if (intlv_addr & 0x2) {
  			u8 shift = intlv_addr & 0x1 ? 9 : 6;
dc0a50a84   Yazen Ghannam   EDAC, amd64: Fix ...
1715
  			u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) & 1;
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1716
1717
1718
  
  			return ((sys_addr >> shift) & 1) ^ temp;
  		}
dc0a50a84   Yazen Ghannam   EDAC, amd64: Fix ...
1719
1720
1721
1722
1723
  		if (intlv_addr & 0x4) {
  			u8 shift = intlv_addr & 0x1 ? 9 : 8;
  
  			return (sys_addr >> shift) & 1;
  		}
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1724
1725
1726
1727
1728
  		return (sys_addr >> (12 + hweight8(intlv_en))) & 1;
  	}
  
  	if (dct_high_range_enabled(pvt))
  		return ~dct_sel_high & 1;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1729
1730
1731
  
  	return 0;
  }
c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1732
  /* Convert the sys_addr to the normalized DCT address */
c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
1733
  static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range,
c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1734
1735
  				 u64 sys_addr, bool hi_rng,
  				 u32 dct_sel_base_addr)
6163b5d4f   Doug Thompson   amd64_edac: add F...
1736
1737
  {
  	u64 chan_off;
c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1738
1739
  	u64 dram_base		= get_dram_base(pvt, range);
  	u64 hole_off		= f10_dhar_offset(pvt);
6f3508f61   Dan Carpenter   EDAC, amd64_edac:...
1740
  	u64 dct_sel_base_off	= (u64)(pvt->dct_sel_hi & 0xFFFFFC00) << 16;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1741

c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
  	if (hi_rng) {
  		/*
  		 * if
  		 * base address of high range is below 4Gb
  		 * (bits [47:27] at [31:11])
  		 * DRAM address space on this DCT is hoisted above 4Gb	&&
  		 * sys_addr > 4Gb
  		 *
  		 *	remove hole offset from sys_addr
  		 * else
  		 *	remove high range offset from sys_addr
  		 */
  		if ((!(dct_sel_base_addr >> 16) ||
  		     dct_sel_base_addr < dhar_base(pvt)) &&
972ea17ab   Borislav Petkov   amd64_edac: Drop ...
1756
  		    dhar_valid(pvt) &&
c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1757
  		    (sys_addr >= BIT_64(32)))
bc21fa578   Borislav Petkov   amd64_edac: Clean...
1758
  			chan_off = hole_off;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1759
1760
1761
  		else
  			chan_off = dct_sel_base_off;
  	} else {
c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1762
1763
1764
1765
1766
1767
1768
1769
1770
  		/*
  		 * if
  		 * we have a valid hole		&&
  		 * sys_addr > 4Gb
  		 *
  		 *	remove hole
  		 * else
  		 *	remove dram base to normalize to DCT address
  		 */
972ea17ab   Borislav Petkov   amd64_edac: Drop ...
1771
  		if (dhar_valid(pvt) && (sys_addr >= BIT_64(32)))
bc21fa578   Borislav Petkov   amd64_edac: Clean...
1772
  			chan_off = hole_off;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1773
  		else
c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1774
  			chan_off = dram_base;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1775
  	}
10ef6b0df   Chen, Gong   bitops: Introduce...
1776
  	return (sys_addr & GENMASK_ULL(47,6)) - (chan_off & GENMASK_ULL(47,23));
6163b5d4f   Doug Thompson   amd64_edac: add F...
1777
  }
6163b5d4f   Doug Thompson   amd64_edac: add F...
1778
1779
1780
1781
  /*
   * checks if the csrow passed in is marked as SPARED, if so returns the new
   * spare row
   */
11c75eada   Borislav Petkov   amd64_edac: Clean...
1782
  static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow)
6163b5d4f   Doug Thompson   amd64_edac: add F...
1783
  {
614ec9d85   Borislav Petkov   amd64_edac: Revam...
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
  	int tmp_cs;
  
  	if (online_spare_swap_done(pvt, dct) &&
  	    csrow == online_spare_bad_dramcs(pvt, dct)) {
  
  		for_each_chip_select(tmp_cs, dct, pvt) {
  			if (chip_select_base(tmp_cs, dct, pvt) & 0x2) {
  				csrow = tmp_cs;
  				break;
  			}
  		}
6163b5d4f   Doug Thompson   amd64_edac: add F...
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
  	}
  	return csrow;
  }
  
  /*
   * Iterate over the DRAM DCT "base" and "mask" registers looking for a
   * SystemAddr match on the specified 'ChannelSelect' and 'NodeID'
   *
   * Return:
   *	-EINVAL:  NOT FOUND
   *	0..csrow = Chip-Select Row
   */
c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
1807
  static int f1x_lookup_addr_in_dct(u64 in_addr, u8 nid, u8 dct)
6163b5d4f   Doug Thompson   amd64_edac: add F...
1808
1809
1810
  {
  	struct mem_ctl_info *mci;
  	struct amd64_pvt *pvt;
11c75eada   Borislav Petkov   amd64_edac: Clean...
1811
  	u64 cs_base, cs_mask;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1812
1813
  	int cs_found = -EINVAL;
  	int csrow;
2ec591ac7   Borislav Petkov   EDAC, amd64_edac:...
1814
  	mci = edac_mc_find(nid);
6163b5d4f   Doug Thompson   amd64_edac: add F...
1815
1816
1817
1818
  	if (!mci)
  		return cs_found;
  
  	pvt = mci->pvt_info;
956b9ba15   Joe Perches   edac: Convert deb...
1819
1820
  	edac_dbg(1, "input addr: 0x%llx, DCT: %d
  ", in_addr, dct);
6163b5d4f   Doug Thompson   amd64_edac: add F...
1821

11c75eada   Borislav Petkov   amd64_edac: Clean...
1822
1823
  	for_each_chip_select(csrow, dct, pvt) {
  		if (!csrow_enabled(csrow, dct, pvt))
6163b5d4f   Doug Thompson   amd64_edac: add F...
1824
  			continue;
11c75eada   Borislav Petkov   amd64_edac: Clean...
1825
  		get_cs_base_and_mask(pvt, csrow, dct, &cs_base, &cs_mask);
6163b5d4f   Doug Thompson   amd64_edac: add F...
1826

956b9ba15   Joe Perches   edac: Convert deb...
1827
1828
1829
  		edac_dbg(1, "    CSROW=%d CSBase=0x%llx CSMask=0x%llx
  ",
  			 csrow, cs_base, cs_mask);
6163b5d4f   Doug Thompson   amd64_edac: add F...
1830

11c75eada   Borislav Petkov   amd64_edac: Clean...
1831
  		cs_mask = ~cs_mask;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1832

956b9ba15   Joe Perches   edac: Convert deb...
1833
1834
1835
  		edac_dbg(1, "    (InputAddr & ~CSMask)=0x%llx (CSBase & ~CSMask)=0x%llx
  ",
  			 (in_addr & cs_mask), (cs_base & cs_mask));
6163b5d4f   Doug Thompson   amd64_edac: add F...
1836

11c75eada   Borislav Petkov   amd64_edac: Clean...
1837
  		if ((in_addr & cs_mask) == (cs_base & cs_mask)) {
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1838
1839
1840
1841
  			if (pvt->fam == 0x15 && pvt->model >= 0x30) {
  				cs_found =  csrow;
  				break;
  			}
11c75eada   Borislav Petkov   amd64_edac: Clean...
1842
  			cs_found = f10_process_possible_spare(pvt, dct, csrow);
6163b5d4f   Doug Thompson   amd64_edac: add F...
1843

956b9ba15   Joe Perches   edac: Convert deb...
1844
1845
  			edac_dbg(1, " MATCH csrow=%d
  ", cs_found);
6163b5d4f   Doug Thompson   amd64_edac: add F...
1846
1847
1848
1849
1850
  			break;
  		}
  	}
  	return cs_found;
  }
95b0ef55c   Borislav Petkov   amd64_edac: Add s...
1851
1852
1853
1854
1855
  /*
   * See F2x10C. Non-interleaved graphics framebuffer memory under the 16G is
   * swapped with a region located at the bottom of memory so that the GPU can use
   * the interleaved region and thus two channels.
   */
b15f0fcab   Borislav Petkov   amd64_edac: Adjus...
1856
  static u64 f1x_swap_interleaved_region(struct amd64_pvt *pvt, u64 sys_addr)
95b0ef55c   Borislav Petkov   amd64_edac: Add s...
1857
1858
  {
  	u32 swap_reg, swap_base, swap_limit, rgn_size, tmp_addr;
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
1859
  	if (pvt->fam == 0x10) {
95b0ef55c   Borislav Petkov   amd64_edac: Add s...
1860
  		/* only revC3 and revE have that feature */
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
1861
  		if (pvt->model < 4 || (pvt->model < 0xa && pvt->stepping < 3))
95b0ef55c   Borislav Petkov   amd64_edac: Add s...
1862
1863
  			return sys_addr;
  	}
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
1864
  	amd64_read_pci_cfg(pvt->F2, SWAP_INTLV_REG, &swap_reg);
95b0ef55c   Borislav Petkov   amd64_edac: Add s...
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
  
  	if (!(swap_reg & 0x1))
  		return sys_addr;
  
  	swap_base	= (swap_reg >> 3) & 0x7f;
  	swap_limit	= (swap_reg >> 11) & 0x7f;
  	rgn_size	= (swap_reg >> 20) & 0x7f;
  	tmp_addr	= sys_addr >> 27;
  
  	if (!(sys_addr >> 34) &&
  	    (((tmp_addr >= swap_base) &&
  	     (tmp_addr <= swap_limit)) ||
  	     (tmp_addr < rgn_size)))
  		return sys_addr ^ (u64)swap_base << 27;
  
  	return sys_addr;
  }
f71d0a050   Doug Thompson   amd64_edac: add F...
1882
  /* For a given @dram_range, check if @sys_addr falls within it. */
e761359a2   Borislav Petkov   amd64_edac: Fix r...
1883
  static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1884
  				  u64 sys_addr, int *chan_sel)
f71d0a050   Doug Thompson   amd64_edac: add F...
1885
  {
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1886
  	int cs_found = -EINVAL;
c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1887
  	u64 chan_addr;
5d4b58e84   Borislav Petkov   amd64_edac: Fix c...
1888
  	u32 dct_sel_base;
11c75eada   Borislav Petkov   amd64_edac: Clean...
1889
  	u8 channel;
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1890
  	bool high_range = false;
f71d0a050   Doug Thompson   amd64_edac: add F...
1891

7f19bf755   Borislav Petkov   amd64_edac: Remov...
1892
  	u8 node_id    = dram_dst_node(pvt, range);
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1893
  	u8 intlv_en   = dram_intlv_en(pvt, range);
7f19bf755   Borislav Petkov   amd64_edac: Remov...
1894
  	u32 intlv_sel = dram_intlv_sel(pvt, range);
f71d0a050   Doug Thompson   amd64_edac: add F...
1895

956b9ba15   Joe Perches   edac: Convert deb...
1896
1897
1898
  	edac_dbg(1, "(range %d) SystemAddr= 0x%llx Limit=0x%llx
  ",
  		 range, sys_addr, get_dram_limit(pvt, range));
f71d0a050   Doug Thompson   amd64_edac: add F...
1899

355fba600   Borislav Petkov   amd64_edac: Beef ...
1900
1901
1902
1903
1904
1905
1906
1907
  	if (dhar_valid(pvt) &&
  	    dhar_base(pvt) <= sys_addr &&
  	    sys_addr < BIT_64(32)) {
  		amd64_warn("Huh? Address is in the MMIO hole: 0x%016llx
  ",
  			    sys_addr);
  		return -EINVAL;
  	}
f030ddfb3   Borislav Petkov   amd64_edac: Remov...
1908
  	if (intlv_en && (intlv_sel != ((sys_addr >> 12) & intlv_en)))
f71d0a050   Doug Thompson   amd64_edac: add F...
1909
  		return -EINVAL;
b15f0fcab   Borislav Petkov   amd64_edac: Adjus...
1910
  	sys_addr = f1x_swap_interleaved_region(pvt, sys_addr);
95b0ef55c   Borislav Petkov   amd64_edac: Add s...
1911

f71d0a050   Doug Thompson   amd64_edac: add F...
1912
1913
1914
1915
1916
1917
1918
1919
1920
  	dct_sel_base = dct_sel_baseaddr(pvt);
  
  	/*
  	 * check whether addresses >= DctSelBaseAddr[47:27] are to be used to
  	 * select between DCT0 and DCT1.
  	 */
  	if (dct_high_range_enabled(pvt) &&
  	   !dct_ganging_enabled(pvt) &&
  	   ((sys_addr >> 27) >= (dct_sel_base >> 11)))
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1921
  		high_range = true;
f71d0a050   Doug Thompson   amd64_edac: add F...
1922

b15f0fcab   Borislav Petkov   amd64_edac: Adjus...
1923
  	channel = f1x_determine_channel(pvt, sys_addr, high_range, intlv_en);
f71d0a050   Doug Thompson   amd64_edac: add F...
1924

b15f0fcab   Borislav Petkov   amd64_edac: Adjus...
1925
  	chan_addr = f1x_get_norm_dct_addr(pvt, range, sys_addr,
c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1926
  					  high_range, dct_sel_base);
f71d0a050   Doug Thompson   amd64_edac: add F...
1927

e2f79dbdf   Borislav Petkov   amd64_edac: Corre...
1928
1929
1930
1931
  	/* Remove node interleaving, see F1x120 */
  	if (intlv_en)
  		chan_addr = ((chan_addr >> (12 + hweight8(intlv_en))) << 12) |
  			    (chan_addr & 0xfff);
f71d0a050   Doug Thompson   amd64_edac: add F...
1932

5d4b58e84   Borislav Petkov   amd64_edac: Fix c...
1933
  	/* remove channel interleave */
f71d0a050   Doug Thompson   amd64_edac: add F...
1934
1935
1936
  	if (dct_interleave_enabled(pvt) &&
  	   !dct_high_range_enabled(pvt) &&
  	   !dct_ganging_enabled(pvt)) {
5d4b58e84   Borislav Petkov   amd64_edac: Fix c...
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
  
  		if (dct_sel_interleave_addr(pvt) != 1) {
  			if (dct_sel_interleave_addr(pvt) == 0x3)
  				/* hash 9 */
  				chan_addr = ((chan_addr >> 10) << 9) |
  					     (chan_addr & 0x1ff);
  			else
  				/* A[6] or hash 6 */
  				chan_addr = ((chan_addr >> 7) << 6) |
  					     (chan_addr & 0x3f);
  		} else
  			/* A[12] */
  			chan_addr = ((chan_addr >> 13) << 12) |
  				     (chan_addr & 0xfff);
f71d0a050   Doug Thompson   amd64_edac: add F...
1951
  	}
956b9ba15   Joe Perches   edac: Convert deb...
1952
1953
  	edac_dbg(1, "   Normalized DCT addr: 0x%llx
  ", chan_addr);
f71d0a050   Doug Thompson   amd64_edac: add F...
1954

b15f0fcab   Borislav Petkov   amd64_edac: Adjus...
1955
  	cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, channel);
f71d0a050   Doug Thompson   amd64_edac: add F...
1956

33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1957
  	if (cs_found >= 0)
f71d0a050   Doug Thompson   amd64_edac: add F...
1958
  		*chan_sel = channel;
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1959

f71d0a050   Doug Thompson   amd64_edac: add F...
1960
1961
  	return cs_found;
  }
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
  static int f15_m30h_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
  					u64 sys_addr, int *chan_sel)
  {
  	int cs_found = -EINVAL;
  	int num_dcts_intlv = 0;
  	u64 chan_addr, chan_offset;
  	u64 dct_base, dct_limit;
  	u32 dct_cont_base_reg, dct_cont_limit_reg, tmp;
  	u8 channel, alias_channel, leg_mmio_hole, dct_sel, dct_offset_en;
  
  	u64 dhar_offset		= f10_dhar_offset(pvt);
  	u8 intlv_addr		= dct_sel_interleave_addr(pvt);
  	u8 node_id		= dram_dst_node(pvt, range);
  	u8 intlv_en		= dram_intlv_en(pvt, range);
  
  	amd64_read_pci_cfg(pvt->F1, DRAM_CONT_BASE, &dct_cont_base_reg);
  	amd64_read_pci_cfg(pvt->F1, DRAM_CONT_LIMIT, &dct_cont_limit_reg);
  
  	dct_offset_en		= (u8) ((dct_cont_base_reg >> 3) & BIT(0));
  	dct_sel			= (u8) ((dct_cont_base_reg >> 4) & 0x7);
  
  	edac_dbg(1, "(range %d) SystemAddr= 0x%llx Limit=0x%llx
  ",
  		 range, sys_addr, get_dram_limit(pvt, range));
  
  	if (!(get_dram_base(pvt, range)  <= sys_addr) &&
  	    !(get_dram_limit(pvt, range) >= sys_addr))
  		return -EINVAL;
  
  	if (dhar_valid(pvt) &&
  	    dhar_base(pvt) <= sys_addr &&
  	    sys_addr < BIT_64(32)) {
  		amd64_warn("Huh? Address is in the MMIO hole: 0x%016llx
  ",
  			    sys_addr);
  		return -EINVAL;
  	}
  
  	/* Verify sys_addr is within DCT Range. */
4fc06b317   Aravind Gopalakrishnan   amd64_edac: Fix i...
2001
2002
  	dct_base = (u64) dct_sel_baseaddr(pvt);
  	dct_limit = (dct_cont_limit_reg >> 11) & 0x1FFF;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
2003
2004
  
  	if (!(dct_cont_base_reg & BIT(0)) &&
4fc06b317   Aravind Gopalakrishnan   amd64_edac: Fix i...
2005
2006
  	    !(dct_base <= (sys_addr >> 27) &&
  	      dct_limit >= (sys_addr >> 27)))
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
2007
2008
2009
2010
2011
2012
2013
  		return -EINVAL;
  
  	/* Verify number of dct's that participate in channel interleaving. */
  	num_dcts_intlv = (int) hweight8(intlv_en);
  
  	if (!(num_dcts_intlv % 2 == 0) || (num_dcts_intlv > 4))
  		return -EINVAL;
dc0a50a84   Yazen Ghannam   EDAC, amd64: Fix ...
2014
2015
2016
2017
2018
  	if (pvt->model >= 0x60)
  		channel = f1x_determine_channel(pvt, sys_addr, false, intlv_en);
  	else
  		channel = f15_m30h_determine_channel(pvt, sys_addr, intlv_en,
  						     num_dcts_intlv, dct_sel);
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
2019
2020
  
  	/* Verify we stay within the MAX number of channels allowed */
7f3f5240c   Aravind Gopalakrishnan   amd64_edac: Fix c...
2021
  	if (channel > 3)
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
2022
2023
2024
2025
2026
2027
2028
2029
  		return -EINVAL;
  
  	leg_mmio_hole = (u8) (dct_cont_base_reg >> 1 & BIT(0));
  
  	/* Get normalized DCT addr */
  	if (leg_mmio_hole && (sys_addr >= BIT_64(32)))
  		chan_offset = dhar_offset;
  	else
4fc06b317   Aravind Gopalakrishnan   amd64_edac: Fix i...
2030
  		chan_offset = dct_base << 27;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
  
  	chan_addr = sys_addr - chan_offset;
  
  	/* remove channel interleave */
  	if (num_dcts_intlv == 2) {
  		if (intlv_addr == 0x4)
  			chan_addr = ((chan_addr >> 9) << 8) |
  						(chan_addr & 0xff);
  		else if (intlv_addr == 0x5)
  			chan_addr = ((chan_addr >> 10) << 9) |
  						(chan_addr & 0x1ff);
  		else
  			return -EINVAL;
  
  	} else if (num_dcts_intlv == 4) {
  		if (intlv_addr == 0x4)
  			chan_addr = ((chan_addr >> 10) << 8) |
  							(chan_addr & 0xff);
  		else if (intlv_addr == 0x5)
  			chan_addr = ((chan_addr >> 11) << 9) |
  							(chan_addr & 0x1ff);
  		else
  			return -EINVAL;
  	}
  
  	if (dct_offset_en) {
  		amd64_read_pci_cfg(pvt->F1,
  				   DRAM_CONT_HIGH_OFF + (int) channel * 4,
  				   &tmp);
4fc06b317   Aravind Gopalakrishnan   amd64_edac: Fix i...
2060
  		chan_addr +=  (u64) ((tmp >> 11) & 0xfff) << 27;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
  	}
  
  	f15h_select_dct(pvt, channel);
  
  	edac_dbg(1, "   Normalized DCT addr: 0x%llx
  ", chan_addr);
  
  	/*
  	 * Find Chip select:
  	 * if channel = 3, then alias it to 1. This is because, in F15 M30h,
  	 * there is support for 4 DCT's, but only 2 are currently functional.
  	 * They are DCT0 and DCT3. But we have read all registers of DCT3 into
  	 * pvt->csels[1]. So we need to use '1' here to get correct info.
  	 * Refer F15 M30h BKDG Section 2.10 and 2.10.3 for clarifications.
  	 */
  	alias_channel =  (channel == 3) ? 1 : channel;
  
  	cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, alias_channel);
  
  	if (cs_found >= 0)
  		*chan_sel = alias_channel;
  
  	return cs_found;
  }
  
  static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt,
  					u64 sys_addr,
  					int *chan_sel)
f71d0a050   Doug Thompson   amd64_edac: add F...
2089
  {
e761359a2   Borislav Petkov   amd64_edac: Fix r...
2090
2091
  	int cs_found = -EINVAL;
  	unsigned range;
f71d0a050   Doug Thompson   amd64_edac: add F...
2092

7f19bf755   Borislav Petkov   amd64_edac: Remov...
2093
  	for (range = 0; range < DRAM_RANGES; range++) {
7f19bf755   Borislav Petkov   amd64_edac: Remov...
2094
  		if (!dram_rw(pvt, range))
f71d0a050   Doug Thompson   amd64_edac: add F...
2095
  			continue;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
2096
2097
2098
2099
  		if (pvt->fam == 0x15 && pvt->model >= 0x30)
  			cs_found = f15_m30h_match_to_this_node(pvt, range,
  							       sys_addr,
  							       chan_sel);
f71d0a050   Doug Thompson   amd64_edac: add F...
2100

18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
2101
2102
  		else if ((get_dram_base(pvt, range)  <= sys_addr) &&
  			 (get_dram_limit(pvt, range) >= sys_addr)) {
b15f0fcab   Borislav Petkov   amd64_edac: Adjus...
2103
  			cs_found = f1x_match_to_this_node(pvt, range,
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2104
  							  sys_addr, chan_sel);
f71d0a050   Doug Thompson   amd64_edac: add F...
2105
2106
2107
2108
2109
2110
2111
2112
  			if (cs_found >= 0)
  				break;
  		}
  	}
  	return cs_found;
  }
  
  /*
bdc30a0c8   Borislav Petkov   amd64_edac: corre...
2113
2114
   * For reference see "2.8.5 Routing DRAM Requests" in F10 BKDG. This code maps
   * a @sys_addr to NodeID, DCT (channel) and chip select (CSROW).
f71d0a050   Doug Thompson   amd64_edac: add F...
2115
   *
bdc30a0c8   Borislav Petkov   amd64_edac: corre...
2116
2117
   * The @sys_addr is usually an error address received from the hardware
   * (MCX_ADDR).
f71d0a050   Doug Thompson   amd64_edac: add F...
2118
   */
b15f0fcab   Borislav Petkov   amd64_edac: Adjus...
2119
  static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2120
  				     struct err_info *err)
f71d0a050   Doug Thompson   amd64_edac: add F...
2121
2122
  {
  	struct amd64_pvt *pvt = mci->pvt_info;
f71d0a050   Doug Thompson   amd64_edac: add F...
2123

33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2124
  	error_address_to_page_and_offset(sys_addr, err);
ab5a503cb   Mauro Carvalho Chehab   amd64_edac: conve...
2125

33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2126
2127
2128
  	err->csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &err->channel);
  	if (err->csrow < 0) {
  		err->err_code = ERR_CSROW;
bdc30a0c8   Borislav Petkov   amd64_edac: corre...
2129
2130
  		return;
  	}
bdc30a0c8   Borislav Petkov   amd64_edac: corre...
2131
2132
2133
2134
2135
  	/*
  	 * We need the syndromes for channel detection only when we're
  	 * ganged. Otherwise @chan should already contain the channel at
  	 * this point.
  	 */
a97fa68ec   Borislav Petkov   amd64_edac: Clean...
2136
  	if (dct_ganging_enabled(pvt))
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2137
  		err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome);
f71d0a050   Doug Thompson   amd64_edac: add F...
2138
2139
2140
  }
  
  /*
8566c4df1   Borislav Petkov   amd64_edac: dump ...
2141
   * debug routine to display the memory sizes of all logical DIMMs and its
cb3285074   Borislav Petkov   amd64_edac: Clean...
2142
   * CSROWs
f71d0a050   Doug Thompson   amd64_edac: add F...
2143
   */
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
2144
  static void debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
f71d0a050   Doug Thompson   amd64_edac: add F...
2145
  {
bb89f5a05   Borislav Petkov   amd64_edac: Fix K...
2146
  	int dimm, size0, size1;
525a1b20a   Borislav Petkov   amd64_edac: Clean...
2147
2148
  	u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases;
  	u32 dbam  = ctrl ? pvt->dbam1 : pvt->dbam0;
f71d0a050   Doug Thompson   amd64_edac: add F...
2149

a4b4bedce   Borislav Petkov   amd64_edac: Get r...
2150
  	if (pvt->fam == 0xf) {
8566c4df1   Borislav Petkov   amd64_edac: dump ...
2151
  		/* K8 families < revF not supported yet */
1433eb990   Borislav Petkov   amd64_edac: enhan...
2152
  	       if (pvt->ext_model < K8_REV_F)
8566c4df1   Borislav Petkov   amd64_edac: dump ...
2153
2154
2155
2156
  			return;
  	       else
  		       WARN_ON(ctrl != 0);
  	}
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
  	if (pvt->fam == 0x10) {
  		dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1
  							   : pvt->dbam0;
  		dcsb = (ctrl && !dct_ganging_enabled(pvt)) ?
  				 pvt->csels[1].csbases :
  				 pvt->csels[0].csbases;
  	} else if (ctrl) {
  		dbam = pvt->dbam0;
  		dcsb = pvt->csels[1].csbases;
  	}
956b9ba15   Joe Perches   edac: Convert deb...
2167
2168
2169
  	edac_dbg(1, "F2x%d80 (DRAM Bank Address Mapping): 0x%08x
  ",
  		 ctrl, dbam);
f71d0a050   Doug Thompson   amd64_edac: add F...
2170

8566c4df1   Borislav Petkov   amd64_edac: dump ...
2171
2172
  	edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:
  ", ctrl);
f71d0a050   Doug Thompson   amd64_edac: add F...
2173
2174
2175
2176
  	/* Dump memory sizes for DIMM and its CSROWs */
  	for (dimm = 0; dimm < 4; dimm++) {
  
  		size0 = 0;
11c75eada   Borislav Petkov   amd64_edac: Clean...
2177
  		if (dcsb[dimm*2] & DCSB_CS_ENABLE)
07ed82ef9   Yazen Ghannam   EDAC, amd64: Add ...
2178
2179
2180
  			/*
  			 * For F15m60h, we need multiplier for LRDIMM cs_size
  			 * calculation. We pass dimm value to the dbam_to_cs
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
2181
2182
2183
  			 * mapper so we can find the multiplier from the
  			 * corresponding DCSM.
  			 */
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
2184
  			size0 = pvt->ops->dbam_to_cs(pvt, ctrl,
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
2185
2186
  						     DBAM_DIMM(dimm, dbam),
  						     dimm);
f71d0a050   Doug Thompson   amd64_edac: add F...
2187
2188
  
  		size1 = 0;
11c75eada   Borislav Petkov   amd64_edac: Clean...
2189
  		if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE)
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
2190
  			size1 = pvt->ops->dbam_to_cs(pvt, ctrl,
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
2191
2192
  						     DBAM_DIMM(dimm, dbam),
  						     dimm);
f71d0a050   Doug Thompson   amd64_edac: add F...
2193

24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
2194
2195
  		amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB
  ",
bb89f5a05   Borislav Petkov   amd64_edac: Fix K...
2196
2197
  				dimm * 2,     size0,
  				dimm * 2 + 1, size1);
f71d0a050   Doug Thompson   amd64_edac: add F...
2198
2199
  	}
  }
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
2200
  static struct amd64_family_type family_types[] = {
4d37607ad   Doug Thompson   amd64_edac: add p...
2201
  	[K8_CPUS] = {
0092b20d4   Borislav Petkov   amd64_edac: Simpl...
2202
  		.ctl_name = "K8",
8d5b5d9c7   Borislav Petkov   amd64_edac: Renam...
2203
  		.f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP,
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2204
  		.f2_id = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL,
5e4c55276   Yazen Ghannam   EDAC/amd64: Save ...
2205
  		.max_mcs = 2,
4d37607ad   Doug Thompson   amd64_edac: add p...
2206
  		.ops = {
1433eb990   Borislav Petkov   amd64_edac: enhan...
2207
  			.early_channel_count	= k8_early_channel_count,
1433eb990   Borislav Petkov   amd64_edac: enhan...
2208
2209
  			.map_sysaddr_to_csrow	= k8_map_sysaddr_to_csrow,
  			.dbam_to_cs		= k8_dbam_to_chip_select,
4d37607ad   Doug Thompson   amd64_edac: add p...
2210
2211
2212
  		}
  	},
  	[F10_CPUS] = {
0092b20d4   Borislav Petkov   amd64_edac: Simpl...
2213
  		.ctl_name = "F10h",
8d5b5d9c7   Borislav Petkov   amd64_edac: Renam...
2214
  		.f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP,
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2215
  		.f2_id = PCI_DEVICE_ID_AMD_10H_NB_DRAM,
5e4c55276   Yazen Ghannam   EDAC/amd64: Save ...
2216
  		.max_mcs = 2,
4d37607ad   Doug Thompson   amd64_edac: add p...
2217
  		.ops = {
7d20d14da   Borislav Petkov   amd64_edac: Adjus...
2218
  			.early_channel_count	= f1x_early_channel_count,
b15f0fcab   Borislav Petkov   amd64_edac: Adjus...
2219
  			.map_sysaddr_to_csrow	= f1x_map_sysaddr_to_csrow,
1433eb990   Borislav Petkov   amd64_edac: enhan...
2220
  			.dbam_to_cs		= f10_dbam_to_chip_select,
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
2221
2222
2223
2224
  		}
  	},
  	[F15_CPUS] = {
  		.ctl_name = "F15h",
df71a0532   Borislav Petkov   amd64_edac: Enabl...
2225
  		.f1_id = PCI_DEVICE_ID_AMD_15H_NB_F1,
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2226
  		.f2_id = PCI_DEVICE_ID_AMD_15H_NB_F2,
5e4c55276   Yazen Ghannam   EDAC/amd64: Save ...
2227
  		.max_mcs = 2,
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
2228
  		.ops = {
7d20d14da   Borislav Petkov   amd64_edac: Adjus...
2229
  			.early_channel_count	= f1x_early_channel_count,
b15f0fcab   Borislav Petkov   amd64_edac: Adjus...
2230
  			.map_sysaddr_to_csrow	= f1x_map_sysaddr_to_csrow,
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
2231
  			.dbam_to_cs		= f15_dbam_to_chip_select,
4d37607ad   Doug Thompson   amd64_edac: add p...
2232
2233
  		}
  	},
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
2234
2235
2236
  	[F15_M30H_CPUS] = {
  		.ctl_name = "F15h_M30h",
  		.f1_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1,
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2237
  		.f2_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F2,
5e4c55276   Yazen Ghannam   EDAC/amd64: Save ...
2238
  		.max_mcs = 2,
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
2239
2240
2241
2242
  		.ops = {
  			.early_channel_count	= f1x_early_channel_count,
  			.map_sysaddr_to_csrow	= f1x_map_sysaddr_to_csrow,
  			.dbam_to_cs		= f16_dbam_to_chip_select,
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
2243
2244
  		}
  	},
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
2245
2246
2247
  	[F15_M60H_CPUS] = {
  		.ctl_name = "F15h_M60h",
  		.f1_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1,
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2248
  		.f2_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F2,
5e4c55276   Yazen Ghannam   EDAC/amd64: Save ...
2249
  		.max_mcs = 2,
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
2250
2251
2252
2253
2254
2255
  		.ops = {
  			.early_channel_count	= f1x_early_channel_count,
  			.map_sysaddr_to_csrow	= f1x_map_sysaddr_to_csrow,
  			.dbam_to_cs		= f15_m60h_dbam_to_chip_select,
  		}
  	},
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
2256
2257
2258
  	[F16_CPUS] = {
  		.ctl_name = "F16h",
  		.f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1,
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2259
  		.f2_id = PCI_DEVICE_ID_AMD_16H_NB_F2,
5e4c55276   Yazen Ghannam   EDAC/amd64: Save ...
2260
  		.max_mcs = 2,
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
2261
2262
2263
2264
  		.ops = {
  			.early_channel_count	= f1x_early_channel_count,
  			.map_sysaddr_to_csrow	= f1x_map_sysaddr_to_csrow,
  			.dbam_to_cs		= f16_dbam_to_chip_select,
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
2265
2266
  		}
  	},
85a8885bd   Aravind Gopalakrishnan   amd64_edac: Add s...
2267
2268
2269
  	[F16_M30H_CPUS] = {
  		.ctl_name = "F16h_M30h",
  		.f1_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F1,
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2270
  		.f2_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F2,
5e4c55276   Yazen Ghannam   EDAC/amd64: Save ...
2271
  		.max_mcs = 2,
85a8885bd   Aravind Gopalakrishnan   amd64_edac: Add s...
2272
2273
2274
2275
  		.ops = {
  			.early_channel_count	= f1x_early_channel_count,
  			.map_sysaddr_to_csrow	= f1x_map_sysaddr_to_csrow,
  			.dbam_to_cs		= f16_dbam_to_chip_select,
85a8885bd   Aravind Gopalakrishnan   amd64_edac: Add s...
2276
2277
  		}
  	},
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
2278
2279
2280
2281
  	[F17_CPUS] = {
  		.ctl_name = "F17h",
  		.f0_id = PCI_DEVICE_ID_AMD_17H_DF_F0,
  		.f6_id = PCI_DEVICE_ID_AMD_17H_DF_F6,
5e4c55276   Yazen Ghannam   EDAC/amd64: Save ...
2282
  		.max_mcs = 2,
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
2283
2284
  		.ops = {
  			.early_channel_count	= f17_early_channel_count,
e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
2285
  			.dbam_to_cs		= f17_addr_mask_to_cs_size,
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
2286
2287
  		}
  	},
8960de4a5   Michael Jin   EDAC, amd64: Add ...
2288
2289
2290
2291
  	[F17_M10H_CPUS] = {
  		.ctl_name = "F17h_M10h",
  		.f0_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F0,
  		.f6_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F6,
5e4c55276   Yazen Ghannam   EDAC/amd64: Save ...
2292
  		.max_mcs = 2,
8960de4a5   Michael Jin   EDAC, amd64: Add ...
2293
2294
  		.ops = {
  			.early_channel_count	= f17_early_channel_count,
e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
2295
  			.dbam_to_cs		= f17_addr_mask_to_cs_size,
8960de4a5   Michael Jin   EDAC, amd64: Add ...
2296
2297
  		}
  	},
6e846239e   Yazen Ghannam   EDAC/amd64: Add F...
2298
2299
2300
2301
  	[F17_M30H_CPUS] = {
  		.ctl_name = "F17h_M30h",
  		.f0_id = PCI_DEVICE_ID_AMD_17H_M30H_DF_F0,
  		.f6_id = PCI_DEVICE_ID_AMD_17H_M30H_DF_F6,
5e4c55276   Yazen Ghannam   EDAC/amd64: Save ...
2302
  		.max_mcs = 8,
6e846239e   Yazen Ghannam   EDAC/amd64: Add F...
2303
2304
  		.ops = {
  			.early_channel_count	= f17_early_channel_count,
e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
2305
  			.dbam_to_cs		= f17_addr_mask_to_cs_size,
6e846239e   Yazen Ghannam   EDAC/amd64: Add F...
2306
2307
  		}
  	},
b6bea24d4   Alexander Monakov   EDAC/amd64: Add A...
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
  	[F17_M60H_CPUS] = {
  		.ctl_name = "F17h_M60h",
  		.f0_id = PCI_DEVICE_ID_AMD_17H_M60H_DF_F0,
  		.f6_id = PCI_DEVICE_ID_AMD_17H_M60H_DF_F6,
  		.max_mcs = 2,
  		.ops = {
  			.early_channel_count	= f17_early_channel_count,
  			.dbam_to_cs		= f17_addr_mask_to_cs_size,
  		}
  	},
3e443eb35   Isaac Vaughn   EDAC/amd64: Add P...
2318
2319
2320
2321
  	[F17_M70H_CPUS] = {
  		.ctl_name = "F17h_M70h",
  		.f0_id = PCI_DEVICE_ID_AMD_17H_M70H_DF_F0,
  		.f6_id = PCI_DEVICE_ID_AMD_17H_M70H_DF_F6,
5e4c55276   Yazen Ghannam   EDAC/amd64: Save ...
2322
  		.max_mcs = 2,
3e443eb35   Isaac Vaughn   EDAC/amd64: Add P...
2323
2324
2325
2326
2327
  		.ops = {
  			.early_channel_count	= f17_early_channel_count,
  			.dbam_to_cs		= f17_addr_mask_to_cs_size,
  		}
  	},
2eb61c91c   Yazen Ghannam   EDAC/amd64: Add f...
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
  	[F19_CPUS] = {
  		.ctl_name = "F19h",
  		.f0_id = PCI_DEVICE_ID_AMD_19H_DF_F0,
  		.f6_id = PCI_DEVICE_ID_AMD_19H_DF_F6,
  		.max_mcs = 8,
  		.ops = {
  			.early_channel_count	= f17_early_channel_count,
  			.dbam_to_cs		= f17_addr_mask_to_cs_size,
  		}
  	},
4d37607ad   Doug Thompson   amd64_edac: add p...
2338
  };
b1289d6f9   Doug Thompson   amd64_edac: add E...
2339
  /*
bfc04aec7   Borislav Petkov   amd64_edac: add a...
2340
2341
2342
   * These are tables of eigenvectors (one per line) which can be used for the
   * construction of the syndrome tables. The modified syndrome search algorithm
   * uses those to find the symbol in error and thus the DIMM.
b1289d6f9   Doug Thompson   amd64_edac: add E...
2343
   *
bfc04aec7   Borislav Petkov   amd64_edac: add a...
2344
   * Algorithm courtesy of Ross LaFetra from AMD.
b1289d6f9   Doug Thompson   amd64_edac: add E...
2345
   */
c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
2346
  static const u16 x4_vectors[] = {
bfc04aec7   Borislav Petkov   amd64_edac: add a...
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
  	0x2f57, 0x1afe, 0x66cc, 0xdd88,
  	0x11eb, 0x3396, 0x7f4c, 0xeac8,
  	0x0001, 0x0002, 0x0004, 0x0008,
  	0x1013, 0x3032, 0x4044, 0x8088,
  	0x106b, 0x30d6, 0x70fc, 0xe0a8,
  	0x4857, 0xc4fe, 0x13cc, 0x3288,
  	0x1ac5, 0x2f4a, 0x5394, 0xa1e8,
  	0x1f39, 0x251e, 0xbd6c, 0x6bd8,
  	0x15c1, 0x2a42, 0x89ac, 0x4758,
  	0x2b03, 0x1602, 0x4f0c, 0xca08,
  	0x1f07, 0x3a0e, 0x6b04, 0xbd08,
  	0x8ba7, 0x465e, 0x244c, 0x1cc8,
  	0x2b87, 0x164e, 0x642c, 0xdc18,
  	0x40b9, 0x80de, 0x1094, 0x20e8,
  	0x27db, 0x1eb6, 0x9dac, 0x7b58,
  	0x11c1, 0x2242, 0x84ac, 0x4c58,
  	0x1be5, 0x2d7a, 0x5e34, 0xa718,
  	0x4b39, 0x8d1e, 0x14b4, 0x28d8,
  	0x4c97, 0xc87e, 0x11fc, 0x33a8,
  	0x8e97, 0x497e, 0x2ffc, 0x1aa8,
  	0x16b3, 0x3d62, 0x4f34, 0x8518,
  	0x1e2f, 0x391a, 0x5cac, 0xf858,
  	0x1d9f, 0x3b7a, 0x572c, 0xfe18,
  	0x15f5, 0x2a5a, 0x5264, 0xa3b8,
  	0x1dbb, 0x3b66, 0x715c, 0xe3f8,
  	0x4397, 0xc27e, 0x17fc, 0x3ea8,
  	0x1617, 0x3d3e, 0x6464, 0xb8b8,
  	0x23ff, 0x12aa, 0xab6c, 0x56d8,
  	0x2dfb, 0x1ba6, 0x913c, 0x7328,
  	0x185d, 0x2ca6, 0x7914, 0x9e28,
  	0x171b, 0x3e36, 0x7d7c, 0xebe8,
  	0x4199, 0x82ee, 0x19f4, 0x2e58,
  	0x4807, 0xc40e, 0x130c, 0x3208,
  	0x1905, 0x2e0a, 0x5804, 0xac08,
  	0x213f, 0x132a, 0xadfc, 0x5ba8,
  	0x19a9, 0x2efe, 0xb5cc, 0x6f88,
b1289d6f9   Doug Thompson   amd64_edac: add E...
2383
  };
c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
2384
  static const u16 x8_vectors[] = {
bfc04aec7   Borislav Petkov   amd64_edac: add a...
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
  	0x0145, 0x028a, 0x2374, 0x43c8, 0xa1f0, 0x0520, 0x0a40, 0x1480,
  	0x0211, 0x0422, 0x0844, 0x1088, 0x01b0, 0x44e0, 0x23c0, 0xed80,
  	0x1011, 0x0116, 0x022c, 0x0458, 0x08b0, 0x8c60, 0x2740, 0x4e80,
  	0x0411, 0x0822, 0x1044, 0x0158, 0x02b0, 0x2360, 0x46c0, 0xab80,
  	0x0811, 0x1022, 0x012c, 0x0258, 0x04b0, 0x4660, 0x8cc0, 0x2780,
  	0x2071, 0x40e2, 0xa0c4, 0x0108, 0x0210, 0x0420, 0x0840, 0x1080,
  	0x4071, 0x80e2, 0x0104, 0x0208, 0x0410, 0x0820, 0x1040, 0x2080,
  	0x8071, 0x0102, 0x0204, 0x0408, 0x0810, 0x1020, 0x2040, 0x4080,
  	0x019d, 0x03d6, 0x136c, 0x2198, 0x50b0, 0xb2e0, 0x0740, 0x0e80,
  	0x0189, 0x03ea, 0x072c, 0x0e58, 0x1cb0, 0x56e0, 0x37c0, 0xf580,
  	0x01fd, 0x0376, 0x06ec, 0x0bb8, 0x1110, 0x2220, 0x4440, 0x8880,
  	0x0163, 0x02c6, 0x1104, 0x0758, 0x0eb0, 0x2be0, 0x6140, 0xc280,
  	0x02fd, 0x01c6, 0x0b5c, 0x1108, 0x07b0, 0x25a0, 0x8840, 0x6180,
  	0x0801, 0x012e, 0x025c, 0x04b8, 0x1370, 0x26e0, 0x57c0, 0xb580,
  	0x0401, 0x0802, 0x015c, 0x02b8, 0x22b0, 0x13e0, 0x7140, 0xe280,
  	0x0201, 0x0402, 0x0804, 0x01b8, 0x11b0, 0x31a0, 0x8040, 0x7180,
  	0x0101, 0x0202, 0x0404, 0x0808, 0x1010, 0x2020, 0x4040, 0x8080,
  	0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
  	0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
  };
c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
2405
  static int decode_syndrome(u16 syndrome, const u16 *vectors, unsigned num_vecs,
d34a6ecd4   Borislav Petkov   amd64_edac: Fix d...
2406
  			   unsigned v_dim)
b1289d6f9   Doug Thompson   amd64_edac: add E...
2407
  {
bfc04aec7   Borislav Petkov   amd64_edac: add a...
2408
2409
2410
2411
  	unsigned int i, err_sym;
  
  	for (err_sym = 0; err_sym < num_vecs / v_dim; err_sym++) {
  		u16 s = syndrome;
d34a6ecd4   Borislav Petkov   amd64_edac: Fix d...
2412
2413
  		unsigned v_idx =  err_sym * v_dim;
  		unsigned v_end = (err_sym + 1) * v_dim;
bfc04aec7   Borislav Petkov   amd64_edac: add a...
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
  
  		/* walk over all 16 bits of the syndrome */
  		for (i = 1; i < (1U << 16); i <<= 1) {
  
  			/* if bit is set in that eigenvector... */
  			if (v_idx < v_end && vectors[v_idx] & i) {
  				u16 ev_comp = vectors[v_idx++];
  
  				/* ... and bit set in the modified syndrome, */
  				if (s & i) {
  					/* remove it. */
  					s ^= ev_comp;
4d37607ad   Doug Thompson   amd64_edac: add p...
2426

bfc04aec7   Borislav Petkov   amd64_edac: add a...
2427
2428
2429
  					if (!s)
  						return err_sym;
  				}
b1289d6f9   Doug Thompson   amd64_edac: add E...
2430

bfc04aec7   Borislav Petkov   amd64_edac: add a...
2431
2432
2433
2434
  			} else if (s & i)
  				/* can't get to zero, move to next symbol */
  				break;
  		}
b1289d6f9   Doug Thompson   amd64_edac: add E...
2435
  	}
956b9ba15   Joe Perches   edac: Convert deb...
2436
2437
  	edac_dbg(0, "syndrome(%x) not found
  ", syndrome);
b1289d6f9   Doug Thompson   amd64_edac: add E...
2438
2439
  	return -1;
  }
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2440

bfc04aec7   Borislav Petkov   amd64_edac: add a...
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
  static int map_err_sym_to_channel(int err_sym, int sym_size)
  {
  	if (sym_size == 4)
  		switch (err_sym) {
  		case 0x20:
  		case 0x21:
  			return 0;
  			break;
  		case 0x22:
  		case 0x23:
  			return 1;
  			break;
  		default:
  			return err_sym >> 4;
  			break;
  		}
  	/* x8 symbols */
  	else
  		switch (err_sym) {
  		/* imaginary bits not in a DIMM */
  		case 0x10:
  			WARN(1, KERN_ERR "Invalid error symbol: 0x%x
  ",
  					  err_sym);
  			return -1;
  			break;
  
  		case 0x11:
  			return 0;
  			break;
  		case 0x12:
  			return 1;
  			break;
  		default:
  			return err_sym >> 3;
  			break;
  		}
  	return -1;
  }
  
  static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
  {
  	struct amd64_pvt *pvt = mci->pvt_info;
ad6a32e96   Borislav Petkov   amd64_edac: Sanit...
2484
  	int err_sym = -1;
a3b7db09a   Borislav Petkov   amd64_edac: Adjus...
2485
  	if (pvt->ecc_sym_sz == 8)
ad6a32e96   Borislav Petkov   amd64_edac: Sanit...
2486
2487
  		err_sym = decode_syndrome(syndrome, x8_vectors,
  					  ARRAY_SIZE(x8_vectors),
a3b7db09a   Borislav Petkov   amd64_edac: Adjus...
2488
2489
  					  pvt->ecc_sym_sz);
  	else if (pvt->ecc_sym_sz == 4)
ad6a32e96   Borislav Petkov   amd64_edac: Sanit...
2490
2491
  		err_sym = decode_syndrome(syndrome, x4_vectors,
  					  ARRAY_SIZE(x4_vectors),
a3b7db09a   Borislav Petkov   amd64_edac: Adjus...
2492
  					  pvt->ecc_sym_sz);
ad6a32e96   Borislav Petkov   amd64_edac: Sanit...
2493
  	else {
a3b7db09a   Borislav Petkov   amd64_edac: Adjus...
2494
2495
  		amd64_warn("Illegal syndrome type: %u
  ", pvt->ecc_sym_sz);
ad6a32e96   Borislav Petkov   amd64_edac: Sanit...
2496
  		return err_sym;
bfc04aec7   Borislav Petkov   amd64_edac: add a...
2497
  	}
ad6a32e96   Borislav Petkov   amd64_edac: Sanit...
2498

a3b7db09a   Borislav Petkov   amd64_edac: Adjus...
2499
  	return map_err_sym_to_channel(err_sym, pvt->ecc_sym_sz);
bfc04aec7   Borislav Petkov   amd64_edac: add a...
2500
  }
e70984d9e   Yazen Ghannam   EDAC, amd64: Rena...
2501
  static void __log_ecc_error(struct mem_ctl_info *mci, struct err_info *err,
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2502
  			    u8 ecc_type)
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2503
  {
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2504
2505
  	enum hw_event_mc_err_type err_type;
  	const char *string;
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2506

33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2507
2508
2509
2510
  	if (ecc_type == 2)
  		err_type = HW_EVENT_ERR_CORRECTED;
  	else if (ecc_type == 1)
  		err_type = HW_EVENT_ERR_UNCORRECTED;
d12a969eb   Yazen Ghannam   EDAC, amd64: Add ...
2511
2512
  	else if (ecc_type == 3)
  		err_type = HW_EVENT_ERR_DEFERRED;
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2513
2514
2515
  	else {
  		WARN(1, "Something is rotten in the state of Denmark.
  ");
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2516
2517
  		return;
  	}
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
  	switch (err->err_code) {
  	case DECODE_OK:
  		string = "";
  		break;
  	case ERR_NODE:
  		string = "Failed to map error addr to a node";
  		break;
  	case ERR_CSROW:
  		string = "Failed to map error addr to a csrow";
  		break;
  	case ERR_CHANNEL:
713ad5467   Yazen Ghannam   EDAC, amd64: Defi...
2529
2530
2531
2532
2533
2534
2535
  		string = "Unknown syndrome - possible error reporting race";
  		break;
  	case ERR_SYND:
  		string = "MCA_SYND not valid - unknown syndrome and csrow";
  		break;
  	case ERR_NORM_ADDR:
  		string = "Cannot decode normalized address";
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2536
2537
2538
2539
  		break;
  	default:
  		string = "WTF error";
  		break;
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2540
  	}
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2541
2542
2543
2544
2545
  
  	edac_mc_handle_error(err_type, mci, 1,
  			     err->page, err->offset, err->syndrome,
  			     err->csrow, err->channel, -1,
  			     string, "");
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2546
  }
df781d038   Borislav Petkov   amd64_edac: Simpl...
2547
  static inline void decode_bus_error(int node_id, struct mce *m)
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2548
  {
0c510cc83   Daniel J Blueman   EDAC, amd64_edac:...
2549
2550
  	struct mem_ctl_info *mci;
  	struct amd64_pvt *pvt;
f192c7b16   Borislav Petkov   amd64_edac: Simpl...
2551
  	u8 ecc_type = (m->status >> 45) & 0x3;
66fed2d46   Borislav Petkov   amd64_edac: Impro...
2552
2553
  	u8 xec = XEC(m->status, 0x1f);
  	u16 ec = EC(m->status);
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2554
2555
  	u64 sys_addr;
  	struct err_info err;
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2556

0c510cc83   Daniel J Blueman   EDAC, amd64_edac:...
2557
2558
2559
2560
2561
  	mci = edac_mc_find(node_id);
  	if (!mci)
  		return;
  
  	pvt = mci->pvt_info;
66fed2d46   Borislav Petkov   amd64_edac: Impro...
2562
  	/* Bail out early if this was an 'observed' error */
5980bb9cd   Borislav Petkov   amd64_edac: Clean...
2563
  	if (PP(ec) == NBSL_PP_OBS)
b70ef0101   Borislav Petkov   EDAC: move MCE er...
2564
  		return;
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2565

ecaf5606d   Borislav Petkov   amd64_edac: clean...
2566
2567
  	/* Do only ECC errors */
  	if (xec && xec != F10_NBSL_EXT_ERR_ECC)
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2568
  		return;
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2569

33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2570
  	memset(&err, 0, sizeof(err));
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
2571
  	sys_addr = get_error_address(pvt, m);
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2572

ecaf5606d   Borislav Petkov   amd64_edac: clean...
2573
  	if (ecc_type == 2)
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2574
2575
2576
  		err.syndrome = extract_syndrome(m->status);
  
  	pvt->ops->map_sysaddr_to_csrow(mci, sys_addr, &err);
e70984d9e   Yazen Ghannam   EDAC, amd64: Rena...
2577
  	__log_ecc_error(mci, &err, ecc_type);
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2578
  }
0ec449ee9   Doug Thompson   amd64_edac: add E...
2579
  /*
713ad5467   Yazen Ghannam   EDAC, amd64: Defi...
2580
2581
2582
   * To find the UMC channel represented by this bank we need to match on its
   * instance_id. The instance_id of a bank is held in the lower 32 bits of its
   * IPID.
bdcee7747   Yazen Ghannam   EDAC/amd64: Suppo...
2583
2584
2585
2586
   *
   * Currently, we can derive the channel number by looking at the 6th nibble in
   * the instance_id. For example, instance_id=0xYXXXXX where Y is the channel
   * number.
713ad5467   Yazen Ghannam   EDAC, amd64: Defi...
2587
   */
bdcee7747   Yazen Ghannam   EDAC/amd64: Suppo...
2588
  static int find_umc_channel(struct mce *m)
713ad5467   Yazen Ghannam   EDAC, amd64: Defi...
2589
  {
bdcee7747   Yazen Ghannam   EDAC/amd64: Suppo...
2590
  	return (m->ipid & GENMASK(31, 0)) >> 20;
713ad5467   Yazen Ghannam   EDAC, amd64: Defi...
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
  }
  
  static void decode_umc_error(int node_id, struct mce *m)
  {
  	u8 ecc_type = (m->status >> 45) & 0x3;
  	struct mem_ctl_info *mci;
  	struct amd64_pvt *pvt;
  	struct err_info err;
  	u64 sys_addr;
  
  	mci = edac_mc_find(node_id);
  	if (!mci)
  		return;
  
  	pvt = mci->pvt_info;
  
  	memset(&err, 0, sizeof(err));
  
  	if (m->status & MCI_STATUS_DEFERRED)
  		ecc_type = 3;
bdcee7747   Yazen Ghannam   EDAC/amd64: Suppo...
2611
  	err.channel = find_umc_channel(m);
713ad5467   Yazen Ghannam   EDAC, amd64: Defi...
2612

713ad5467   Yazen Ghannam   EDAC, amd64: Defi...
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
  	if (!(m->status & MCI_STATUS_SYNDV)) {
  		err.err_code = ERR_SYND;
  		goto log_error;
  	}
  
  	if (ecc_type == 2) {
  		u8 length = (m->synd >> 18) & 0x3f;
  
  		if (length)
  			err.syndrome = (m->synd >> 32) & GENMASK(length - 1, 0);
  		else
  			err.err_code = ERR_CHANNEL;
  	}
  
  	err.csrow = m->synd & 0x7;
8a2eaab7d   Yazen Ghannam   EDAC/amd64: Decod...
2628
2629
2630
2631
2632
2633
  	if (umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, err.channel, &sys_addr)) {
  		err.err_code = ERR_NORM_ADDR;
  		goto log_error;
  	}
  
  	error_address_to_page_and_offset(sys_addr, &err);
713ad5467   Yazen Ghannam   EDAC, amd64: Defi...
2634
2635
2636
2637
2638
  log_error:
  	__log_ecc_error(mci, &err, ecc_type);
  }
  
  /*
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2639
2640
   * Use pvt->F3 which contains the F3 CPU PCI device to get the related
   * F1 (AddrMap) and F2 (Dct) devices. Return negative value on error.
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
2641
   * Reserve F0 and F6 on systems with a UMC.
0ec449ee9   Doug Thompson   amd64_edac: add E...
2642
   */
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
2643
2644
2645
2646
2647
2648
  static int
  reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 pci_id1, u16 pci_id2)
  {
  	if (pvt->umc) {
  		pvt->F0 = pci_get_related_function(pvt->F3->vendor, pci_id1, pvt->F3);
  		if (!pvt->F0) {
5246c5400   Borislav Petkov   EDAC, amd64: Impr...
2649
2650
  			amd64_err("F0 not found, device 0x%x (broken BIOS?)
  ", pci_id1);
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
2651
2652
2653
2654
2655
2656
2657
  			return -ENODEV;
  		}
  
  		pvt->F6 = pci_get_related_function(pvt->F3->vendor, pci_id2, pvt->F3);
  		if (!pvt->F6) {
  			pci_dev_put(pvt->F0);
  			pvt->F0 = NULL;
5246c5400   Borislav Petkov   EDAC, amd64: Impr...
2658
2659
  			amd64_err("F6 not found: device 0x%x (broken BIOS?)
  ", pci_id2);
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
2660
2661
  			return -ENODEV;
  		}
5246c5400   Borislav Petkov   EDAC, amd64: Impr...
2662

eae95da7f   Borislav Petkov   EDAC/amd64: Fix P...
2663
2664
  		if (!pci_ctl_dev)
  			pci_ctl_dev = &pvt->F0->dev;
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
2665
2666
2667
2668
2669
2670
2671
2672
2673
  		edac_dbg(1, "F0: %s
  ", pci_name(pvt->F0));
  		edac_dbg(1, "F3: %s
  ", pci_name(pvt->F3));
  		edac_dbg(1, "F6: %s
  ", pci_name(pvt->F6));
  
  		return 0;
  	}
0ec449ee9   Doug Thompson   amd64_edac: add E...
2674
  	/* Reserve the ADDRESS MAP Device */
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
2675
  	pvt->F1 = pci_get_related_function(pvt->F3->vendor, pci_id1, pvt->F3);
8d5b5d9c7   Borislav Petkov   amd64_edac: Renam...
2676
  	if (!pvt->F1) {
5246c5400   Borislav Petkov   EDAC, amd64: Impr...
2677
2678
  		amd64_err("F1 not found: device 0x%x (broken BIOS?)
  ", pci_id1);
bbd0c1f67   Borislav Petkov   amd64_edac: Clean...
2679
  		return -ENODEV;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2680
  	}
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2681
  	/* Reserve the DCT Device */
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
2682
  	pvt->F2 = pci_get_related_function(pvt->F3->vendor, pci_id2, pvt->F3);
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2683
  	if (!pvt->F2) {
8d5b5d9c7   Borislav Petkov   amd64_edac: Renam...
2684
2685
  		pci_dev_put(pvt->F1);
  		pvt->F1 = NULL;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2686

5246c5400   Borislav Petkov   EDAC, amd64: Impr...
2687
2688
2689
  		amd64_err("F2 not found: device 0x%x (broken BIOS?)
  ", pci_id2);
  		return -ENODEV;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2690
  	}
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
2691

eae95da7f   Borislav Petkov   EDAC/amd64: Fix P...
2692
2693
  	if (!pci_ctl_dev)
  		pci_ctl_dev = &pvt->F2->dev;
956b9ba15   Joe Perches   edac: Convert deb...
2694
2695
2696
2697
2698
2699
  	edac_dbg(1, "F1: %s
  ", pci_name(pvt->F1));
  	edac_dbg(1, "F2: %s
  ", pci_name(pvt->F2));
  	edac_dbg(1, "F3: %s
  ", pci_name(pvt->F3));
0ec449ee9   Doug Thompson   amd64_edac: add E...
2700
2701
2702
  
  	return 0;
  }
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
2703
  static void free_mc_sibling_devs(struct amd64_pvt *pvt)
0ec449ee9   Doug Thompson   amd64_edac: add E...
2704
  {
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
2705
2706
2707
2708
2709
2710
2711
  	if (pvt->umc) {
  		pci_dev_put(pvt->F0);
  		pci_dev_put(pvt->F6);
  	} else {
  		pci_dev_put(pvt->F1);
  		pci_dev_put(pvt->F2);
  	}
0ec449ee9   Doug Thompson   amd64_edac: add E...
2712
  }
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2713
2714
2715
2716
2717
2718
  static void determine_ecc_sym_sz(struct amd64_pvt *pvt)
  {
  	pvt->ecc_sym_sz = 4;
  
  	if (pvt->umc) {
  		u8 i;
4d30d2bc3   Yazen Ghannam   EDAC/amd64: Use a...
2719
  		for_each_umc(i) {
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2720
  			/* Check enabled channels only: */
7835961d3   Yazen Ghannam   EDAC/amd64: Recog...
2721
2722
2723
2724
2725
2726
2727
2728
  			if (pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) {
  				if (pvt->umc[i].ecc_ctrl & BIT(9)) {
  					pvt->ecc_sym_sz = 16;
  					return;
  				} else if (pvt->umc[i].ecc_ctrl & BIT(7)) {
  					pvt->ecc_sym_sz = 8;
  					return;
  				}
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2729
2730
  			}
  		}
7835961d3   Yazen Ghannam   EDAC/amd64: Recog...
2731
  	} else if (pvt->fam >= 0x10) {
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
  		u32 tmp;
  
  		amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
  		/* F16h has only DCT0, so no need to read dbam1. */
  		if (pvt->fam != 0x16)
  			amd64_read_dct_pci_cfg(pvt, 1, DBAM0, &pvt->dbam1);
  
  		/* F10h, revD and later can do x8 ECC too. */
  		if ((pvt->fam > 0x10 || pvt->model > 7) && tmp & BIT(25))
  			pvt->ecc_sym_sz = 8;
  	}
  }
  
  /*
   * Retrieve the hardware registers of the memory controller.
   */
  static void __read_mc_regs_df(struct amd64_pvt *pvt)
  {
  	u8 nid = pvt->mc_node_id;
  	struct amd64_umc *umc;
  	u32 i, umc_base;
  
  	/* Read registers from each UMC */
4d30d2bc3   Yazen Ghannam   EDAC/amd64: Use a...
2755
  	for_each_umc(i) {
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2756
2757
2758
  
  		umc_base = get_umc_base(i);
  		umc = &pvt->umc[i];
07ed82ef9   Yazen Ghannam   EDAC, amd64: Add ...
2759
2760
  		amd_smn_read(nid, umc_base + UMCCH_DIMM_CFG, &umc->dimm_cfg);
  		amd_smn_read(nid, umc_base + UMCCH_UMC_CFG, &umc->umc_cfg);
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2761
2762
  		amd_smn_read(nid, umc_base + UMCCH_SDP_CTRL, &umc->sdp_ctrl);
  		amd_smn_read(nid, umc_base + UMCCH_ECC_CTRL, &umc->ecc_ctrl);
07ed82ef9   Yazen Ghannam   EDAC, amd64: Add ...
2763
  		amd_smn_read(nid, umc_base + UMCCH_UMC_CAP_HI, &umc->umc_cap_hi);
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2764
2765
  	}
  }
0ec449ee9   Doug Thompson   amd64_edac: add E...
2766
2767
2768
2769
  /*
   * Retrieve the hardware registers of the memory controller (this includes the
   * 'Address Map' and 'Misc' device regs)
   */
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
2770
  static void read_mc_regs(struct amd64_pvt *pvt)
0ec449ee9   Doug Thompson   amd64_edac: add E...
2771
  {
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2772
  	unsigned int range;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2773
  	u64 msr_val;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2774
2775
2776
  
  	/*
  	 * Retrieve TOP_MEM and TOP_MEM2; no masking off of reserved bits since
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2777
  	 * those are Read-As-Zero.
0ec449ee9   Doug Thompson   amd64_edac: add E...
2778
  	 */
e97f8bb8c   Borislav Petkov   amd64_edac: make ...
2779
  	rdmsrl(MSR_K8_TOP_MEM1, pvt->top_mem);
956b9ba15   Joe Perches   edac: Convert deb...
2780
2781
  	edac_dbg(0, "  TOP_MEM:  0x%016llx
  ", pvt->top_mem);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2782

b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2783
  	/* Check first whether TOP_MEM2 is enabled: */
0ec449ee9   Doug Thompson   amd64_edac: add E...
2784
  	rdmsrl(MSR_K8_SYSCFG, msr_val);
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2785
  	if (msr_val & BIT(21)) {
e97f8bb8c   Borislav Petkov   amd64_edac: make ...
2786
  		rdmsrl(MSR_K8_TOP_MEM2, pvt->top_mem2);
956b9ba15   Joe Perches   edac: Convert deb...
2787
2788
  		edac_dbg(0, "  TOP_MEM2: 0x%016llx
  ", pvt->top_mem2);
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2789
  	} else {
956b9ba15   Joe Perches   edac: Convert deb...
2790
2791
  		edac_dbg(0, "  TOP_MEM2 disabled
  ");
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2792
2793
2794
2795
2796
2797
2798
2799
  	}
  
  	if (pvt->umc) {
  		__read_mc_regs_df(pvt);
  		amd64_read_pci_cfg(pvt->F0, DF_DHAR, &pvt->dhar);
  
  		goto skip;
  	}
0ec449ee9   Doug Thompson   amd64_edac: add E...
2800

5980bb9cd   Borislav Petkov   amd64_edac: Clean...
2801
  	amd64_read_pci_cfg(pvt->F3, NBCAP, &pvt->nbcap);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2802

5a5d23716   Borislav Petkov   amd64_edac: Sanit...
2803
  	read_dram_ctl_register(pvt);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2804

7f19bf755   Borislav Petkov   amd64_edac: Remov...
2805
2806
  	for (range = 0; range < DRAM_RANGES; range++) {
  		u8 rw;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2807

7f19bf755   Borislav Petkov   amd64_edac: Remov...
2808
2809
2810
2811
2812
2813
  		/* read settings for this DRAM range */
  		read_dram_base_limit_regs(pvt, range);
  
  		rw = dram_rw(pvt, range);
  		if (!rw)
  			continue;
956b9ba15   Joe Perches   edac: Convert deb...
2814
2815
2816
2817
2818
  		edac_dbg(1, "  DRAM range[%d], base: 0x%016llx; limit: 0x%016llx
  ",
  			 range,
  			 get_dram_base(pvt, range),
  			 get_dram_limit(pvt, range));
7f19bf755   Borislav Petkov   amd64_edac: Remov...
2819

956b9ba15   Joe Perches   edac: Convert deb...
2820
2821
2822
2823
2824
2825
2826
  		edac_dbg(1, "   IntlvEn=%s; Range access: %s%s IntlvSel=%d DstNode=%d
  ",
  			 dram_intlv_en(pvt, range) ? "Enabled" : "Disabled",
  			 (rw & 0x1) ? "R" : "-",
  			 (rw & 0x2) ? "W" : "-",
  			 dram_intlv_sel(pvt, range),
  			 dram_dst_node(pvt, range));
0ec449ee9   Doug Thompson   amd64_edac: add E...
2827
  	}
bc21fa578   Borislav Petkov   amd64_edac: Clean...
2828
  	amd64_read_pci_cfg(pvt->F1, DHAR, &pvt->dhar);
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
2829
  	amd64_read_dct_pci_cfg(pvt, 0, DBAM0, &pvt->dbam0);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2830

8d5b5d9c7   Borislav Petkov   amd64_edac: Renam...
2831
  	amd64_read_pci_cfg(pvt->F3, F10_ONLINE_SPARE, &pvt->online_spare);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2832

7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
2833
2834
  	amd64_read_dct_pci_cfg(pvt, 0, DCLR0, &pvt->dclr0);
  	amd64_read_dct_pci_cfg(pvt, 0, DCHR0, &pvt->dchr0);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2835

78da121e1   Borislav Petkov   amd64_edac: Clean...
2836
  	if (!dct_ganging_enabled(pvt)) {
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
2837
2838
  		amd64_read_dct_pci_cfg(pvt, 1, DCLR0, &pvt->dclr1);
  		amd64_read_dct_pci_cfg(pvt, 1, DCHR0, &pvt->dchr1);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2839
  	}
ad6a32e96   Borislav Petkov   amd64_edac: Sanit...
2840

b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2841
2842
  skip:
  	read_dct_base_mask(pvt);
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
2843
2844
2845
  	determine_memory_type(pvt);
  	edac_dbg(1, "  DIMM type: %s
  ", edac_mem_types[pvt->dram_type]);
a3b7db09a   Borislav Petkov   amd64_edac: Adjus...
2846

b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2847
  	determine_ecc_sym_sz(pvt);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2848
2849
2850
2851
2852
2853
  }
  
  /*
   * NOTE: CPU Revision Dependent code
   *
   * Input:
11c75eada   Borislav Petkov   amd64_edac: Clean...
2854
   *	@csrow_nr ChipSelect Row Number (0..NUM_CHIPSELECTS-1)
0ec449ee9   Doug Thompson   amd64_edac: add E...
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
   *	k8 private pointer to -->
   *			DRAM Bank Address mapping register
   *			node_id
   *			DCL register where dual_channel_active is
   *
   * The DBAM register consists of 4 sets of 4 bits each definitions:
   *
   * Bits:	CSROWs
   * 0-3		CSROWs 0 and 1
   * 4-7		CSROWs 2 and 3
   * 8-11		CSROWs 4 and 5
   * 12-15	CSROWs 6 and 7
   *
   * Values range from: 0 to 15
   * The meaning of the values depends on CPU revision and dual-channel state,
   * see relevant BKDG more info.
   *
   * The memory controller provides for total of only 8 CSROWs in its current
   * architecture. Each "pair" of CSROWs normally represents just one DIMM in
   * single channel or two (2) DIMMs in dual channel mode.
   *
   * The following code logic collapses the various tables for CSROW based on CPU
   * revision.
   *
   * Returns:
   *	The number of PAGE_SIZE pages on the specified CSROW number it
   *	encompasses
   *
   */
eb77e6b80   Yazen Ghannam   EDAC, amd64: Fix ...
2884
  static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr_orig)
0ec449ee9   Doug Thompson   amd64_edac: add E...
2885
  {
f92cae452   Ashish Shenoy   amd64_edac: Fix m...
2886
  	u32 dbam = dct ? pvt->dbam1 : pvt->dbam0;
eb77e6b80   Yazen Ghannam   EDAC, amd64: Fix ...
2887
2888
  	int csrow_nr = csrow_nr_orig;
  	u32 cs_mode, nr_pages;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2889

e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
2890
  	if (!pvt->umc) {
eb77e6b80   Yazen Ghannam   EDAC, amd64: Fix ...
2891
  		csrow_nr >>= 1;
e53a3b267   Yazen Ghannam   EDAC/amd64: Find ...
2892
2893
2894
2895
  		cs_mode = DBAM_DIMM(csrow_nr, dbam);
  	} else {
  		cs_mode = f17_get_cs_mode(csrow_nr >> 1, dct, pvt);
  	}
0ec449ee9   Doug Thompson   amd64_edac: add E...
2896

eb77e6b80   Yazen Ghannam   EDAC, amd64: Fix ...
2897
2898
  	nr_pages   = pvt->ops->dbam_to_cs(pvt, dct, cs_mode, csrow_nr);
  	nr_pages <<= 20 - PAGE_SHIFT;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2899

10de6497a   Borislav Petkov   amd64_edac: Fix c...
2900
2901
  	edac_dbg(0, "csrow: %d, channel: %d, DBAM idx: %d
  ",
eb77e6b80   Yazen Ghannam   EDAC, amd64: Fix ...
2902
  		    csrow_nr_orig, dct,  cs_mode);
10de6497a   Borislav Petkov   amd64_edac: Fix c...
2903
2904
  	edac_dbg(0, "nr_pages/channel: %u
  ", nr_pages);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2905
2906
2907
  
  	return nr_pages;
  }
353a1fcb8   Yazen Ghannam   EDAC/amd64: Initi...
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
  static int init_csrows_df(struct mem_ctl_info *mci)
  {
  	struct amd64_pvt *pvt = mci->pvt_info;
  	enum edac_type edac_mode = EDAC_NONE;
  	enum dev_type dev_type = DEV_UNKNOWN;
  	struct dimm_info *dimm;
  	int empty = 1;
  	u8 umc, cs;
  
  	if (mci->edac_ctl_cap & EDAC_FLAG_S16ECD16ED) {
  		edac_mode = EDAC_S16ECD16ED;
  		dev_type = DEV_X16;
  	} else if (mci->edac_ctl_cap & EDAC_FLAG_S8ECD8ED) {
  		edac_mode = EDAC_S8ECD8ED;
  		dev_type = DEV_X8;
  	} else if (mci->edac_ctl_cap & EDAC_FLAG_S4ECD4ED) {
  		edac_mode = EDAC_S4ECD4ED;
  		dev_type = DEV_X4;
  	} else if (mci->edac_ctl_cap & EDAC_FLAG_SECDED) {
  		edac_mode = EDAC_SECDED;
  	}
  
  	for_each_umc(umc) {
  		for_each_chip_select(cs, umc, pvt) {
  			if (!csrow_enabled(cs, umc, pvt))
  				continue;
  
  			empty = 0;
  			dimm = mci->csrows[cs]->channels[umc]->dimm;
  
  			edac_dbg(1, "MC node: %d, csrow: %d
  ",
  					pvt->mc_node_id, cs);
  
  			dimm->nr_pages = get_csrow_nr_pages(pvt, umc, cs);
  			dimm->mtype = pvt->dram_type;
  			dimm->edac_mode = edac_mode;
  			dimm->dtype = dev_type;
466503d6b   Yazen Ghannam   EDAC/amd64: Set g...
2946
  			dimm->grain = 64;
353a1fcb8   Yazen Ghannam   EDAC/amd64: Initi...
2947
2948
2949
2950
2951
  		}
  	}
  
  	return empty;
  }
0ec449ee9   Doug Thompson   amd64_edac: add E...
2952
2953
2954
2955
  /*
   * Initialize the array of csrow attribute instances, based on the values
   * from pci config hardware registers.
   */
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
2956
  static int init_csrows(struct mem_ctl_info *mci)
0ec449ee9   Doug Thompson   amd64_edac: add E...
2957
  {
10de6497a   Borislav Petkov   amd64_edac: Fix c...
2958
  	struct amd64_pvt *pvt = mci->pvt_info;
2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
2959
  	enum edac_type edac_mode = EDAC_NONE;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2960
  	struct csrow_info *csrow;
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
2961
  	struct dimm_info *dimm;
10de6497a   Borislav Petkov   amd64_edac: Fix c...
2962
  	int i, j, empty = 1;
a895bf8b1   Mauro Carvalho Chehab   edac: move nr_pag...
2963
  	int nr_pages = 0;
10de6497a   Borislav Petkov   amd64_edac: Fix c...
2964
  	u32 val;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2965

353a1fcb8   Yazen Ghannam   EDAC/amd64: Initi...
2966
2967
  	if (pvt->umc)
  		return init_csrows_df(mci);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2968

353a1fcb8   Yazen Ghannam   EDAC/amd64: Initi...
2969
  	amd64_read_pci_cfg(pvt->F3, NBCFG, &val);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2970

353a1fcb8   Yazen Ghannam   EDAC/amd64: Initi...
2971
2972
2973
2974
2975
2976
  	pvt->nbcfg = val;
  
  	edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]
  ",
  		 pvt->mc_node_id, val,
  		 !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
0ec449ee9   Doug Thompson   amd64_edac: add E...
2977

10de6497a   Borislav Petkov   amd64_edac: Fix c...
2978
2979
2980
  	/*
  	 * We iterate over DCT0 here but we look at DCT1 in parallel, if needed.
  	 */
11c75eada   Borislav Petkov   amd64_edac: Clean...
2981
  	for_each_chip_select(i, 0, pvt) {
10de6497a   Borislav Petkov   amd64_edac: Fix c...
2982
2983
  		bool row_dct0 = !!csrow_enabled(i, 0, pvt);
  		bool row_dct1 = false;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2984

a4b4bedce   Borislav Petkov   amd64_edac: Get r...
2985
  		if (pvt->fam != 0xf)
10de6497a   Borislav Petkov   amd64_edac: Fix c...
2986
2987
2988
  			row_dct1 = !!csrow_enabled(i, 1, pvt);
  
  		if (!row_dct0 && !row_dct1)
0ec449ee9   Doug Thompson   amd64_edac: add E...
2989
  			continue;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2990

10de6497a   Borislav Petkov   amd64_edac: Fix c...
2991
  		csrow = mci->csrows[i];
0ec449ee9   Doug Thompson   amd64_edac: add E...
2992
  		empty = 0;
10de6497a   Borislav Petkov   amd64_edac: Fix c...
2993
2994
2995
2996
  
  		edac_dbg(1, "MC node: %d, csrow: %d
  ",
  			    pvt->mc_node_id, i);
1eef12825   Mauro Carvalho Chehab   amd64_edac: Corre...
2997
  		if (row_dct0) {
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
2998
  			nr_pages = get_csrow_nr_pages(pvt, 0, i);
1eef12825   Mauro Carvalho Chehab   amd64_edac: Corre...
2999
3000
  			csrow->channels[0]->dimm->nr_pages = nr_pages;
  		}
11c75eada   Borislav Petkov   amd64_edac: Clean...
3001

10de6497a   Borislav Petkov   amd64_edac: Fix c...
3002
  		/* K8 has only one DCT */
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
3003
  		if (pvt->fam != 0xf && row_dct1) {
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3004
  			int row_dct1_pages = get_csrow_nr_pages(pvt, 1, i);
1eef12825   Mauro Carvalho Chehab   amd64_edac: Corre...
3005
3006
3007
3008
  
  			csrow->channels[1]->dimm->nr_pages = row_dct1_pages;
  			nr_pages += row_dct1_pages;
  		}
0ec449ee9   Doug Thompson   amd64_edac: add E...
3009

10de6497a   Borislav Petkov   amd64_edac: Fix c...
3010
3011
  		edac_dbg(1, "Total csrow%d pages: %u
  ", i, nr_pages);
0ec449ee9   Doug Thompson   amd64_edac: add E...
3012

2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
3013
  		/* Determine DIMM ECC mode: */
353a1fcb8   Yazen Ghannam   EDAC/amd64: Initi...
3014
  		if (pvt->nbcfg & NBCFG_ECC_ENABLE) {
2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
3015
3016
3017
3018
  			edac_mode = (pvt->nbcfg & NBCFG_CHIPKILL)
  					? EDAC_S4ECD4ED
  					: EDAC_SECDED;
  		}
084a4fcce   Mauro Carvalho Chehab   edac: move dimm p...
3019
3020
  
  		for (j = 0; j < pvt->channel_count; j++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
3021
  			dimm = csrow->channels[j]->dimm;
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
3022
  			dimm->mtype = pvt->dram_type;
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
3023
  			dimm->edac_mode = edac_mode;
466503d6b   Yazen Ghannam   EDAC/amd64: Set g...
3024
  			dimm->grain = 64;
084a4fcce   Mauro Carvalho Chehab   edac: move dimm p...
3025
  		}
0ec449ee9   Doug Thompson   amd64_edac: add E...
3026
3027
3028
3029
  	}
  
  	return empty;
  }
d27bf6fa3   Doug Thompson   amd64_edac: add e...
3030

f6d6ae965   Borislav Petkov   amd64_edac: unify...
3031
  /* get all cores on this DCT */
8b84c8df3   Daniel J Blueman   x86, AMD, NB: Use...
3032
  static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, u16 nid)
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3033
3034
3035
3036
3037
3038
3039
3040
3041
  {
  	int cpu;
  
  	for_each_online_cpu(cpu)
  		if (amd_get_nb_id(cpu) == nid)
  			cpumask_set_cpu(cpu, mask);
  }
  
  /* check MCG_CTL on all the cpus on this node */
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3042
  static bool nb_mce_bank_enabled_on_node(u16 nid)
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3043
3044
  {
  	cpumask_var_t mask;
505422517   Borislav Petkov   x86, msr: Add sup...
3045
  	int cpu, nbe;
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3046
3047
3048
  	bool ret = false;
  
  	if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
3049
3050
  		amd64_warn("%s: Error allocating mask
  ", __func__);
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3051
3052
3053
3054
  		return false;
  	}
  
  	get_cpus_on_this_dct_cpumask(mask, nid);
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3055
3056
3057
  	rdmsr_on_cpus(mask, MSR_IA32_MCG_CTL, msrs);
  
  	for_each_cpu(cpu, mask) {
505422517   Borislav Petkov   x86, msr: Add sup...
3058
  		struct msr *reg = per_cpu_ptr(msrs, cpu);
5980bb9cd   Borislav Petkov   amd64_edac: Clean...
3059
  		nbe = reg->l & MSR_MCGCTL_NBE;
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3060

956b9ba15   Joe Perches   edac: Convert deb...
3061
3062
3063
3064
  		edac_dbg(0, "core: %u, MCG_CTL: 0x%llx, NB MSR is %s
  ",
  			 cpu, reg->q,
  			 (nbe ? "enabled" : "disabled"));
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3065
3066
3067
  
  		if (!nbe)
  			goto out;
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3068
3069
3070
3071
  	}
  	ret = true;
  
  out:
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3072
3073
3074
  	free_cpumask_var(mask);
  	return ret;
  }
c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
3075
  static int toggle_ecc_err_reporting(struct ecc_settings *s, u16 nid, bool on)
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3076
3077
  {
  	cpumask_var_t cmask;
505422517   Borislav Petkov   x86, msr: Add sup...
3078
  	int cpu;
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3079
3080
  
  	if (!zalloc_cpumask_var(&cmask, GFP_KERNEL)) {
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
3081
3082
  		amd64_warn("%s: error allocating mask
  ", __func__);
0de278844   Pan Bian   EDAC, amd64: Fix ...
3083
  		return -ENOMEM;
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3084
  	}
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3085
  	get_cpus_on_this_dct_cpumask(cmask, nid);
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3086

f6d6ae965   Borislav Petkov   amd64_edac: unify...
3087
3088
3089
  	rdmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
  
  	for_each_cpu(cpu, cmask) {
505422517   Borislav Petkov   x86, msr: Add sup...
3090
  		struct msr *reg = per_cpu_ptr(msrs, cpu);
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3091
  		if (on) {
5980bb9cd   Borislav Petkov   amd64_edac: Clean...
3092
  			if (reg->l & MSR_MCGCTL_NBE)
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3093
  				s->flags.nb_mce_enable = 1;
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3094

5980bb9cd   Borislav Petkov   amd64_edac: Clean...
3095
  			reg->l |= MSR_MCGCTL_NBE;
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3096
3097
  		} else {
  			/*
d95cf4de6   Borislav Petkov   amd64_edac: Simpl...
3098
  			 * Turn off NB MCE reporting only when it was off before
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3099
  			 */
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3100
  			if (!s->flags.nb_mce_enable)
5980bb9cd   Borislav Petkov   amd64_edac: Clean...
3101
  				reg->l &= ~MSR_MCGCTL_NBE;
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3102
  		}
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3103
3104
  	}
  	wrmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
f6d6ae965   Borislav Petkov   amd64_edac: unify...
3105
3106
3107
3108
  	free_cpumask_var(cmask);
  
  	return 0;
  }
c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
3109
  static bool enable_ecc_error_reporting(struct ecc_settings *s, u16 nid,
2299ef711   Borislav Petkov   amd64_edac: Check...
3110
  				       struct pci_dev *F3)
f9431992b   Doug Thompson   amd64_edac: add E...
3111
  {
2299ef711   Borislav Petkov   amd64_edac: Check...
3112
  	bool ret = true;
c9f4f26ea   Borislav Petkov   amd64_edac: Clean...
3113
  	u32 value, mask = 0x3;		/* UECC/CECC enable */
f9431992b   Doug Thompson   amd64_edac: add E...
3114

2299ef711   Borislav Petkov   amd64_edac: Check...
3115
3116
3117
3118
3119
  	if (toggle_ecc_err_reporting(s, nid, ON)) {
  		amd64_warn("Error enabling ECC reporting over MCGCTL!
  ");
  		return false;
  	}
c9f4f26ea   Borislav Petkov   amd64_edac: Clean...
3120
  	amd64_read_pci_cfg(F3, NBCTL, &value);
f9431992b   Doug Thompson   amd64_edac: add E...
3121

ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3122
3123
  	s->old_nbctl   = value & mask;
  	s->nbctl_valid = true;
f9431992b   Doug Thompson   amd64_edac: add E...
3124
3125
  
  	value |= mask;
c9f4f26ea   Borislav Petkov   amd64_edac: Clean...
3126
  	amd64_write_pci_cfg(F3, NBCTL, value);
f9431992b   Doug Thompson   amd64_edac: add E...
3127

a97fa68ec   Borislav Petkov   amd64_edac: Clean...
3128
  	amd64_read_pci_cfg(F3, NBCFG, &value);
f9431992b   Doug Thompson   amd64_edac: add E...
3129

956b9ba15   Joe Perches   edac: Convert deb...
3130
3131
3132
  	edac_dbg(0, "1: node %d, NBCFG=0x%08x[DramEccEn: %d]
  ",
  		 nid, value, !!(value & NBCFG_ECC_ENABLE));
f9431992b   Doug Thompson   amd64_edac: add E...
3133

a97fa68ec   Borislav Petkov   amd64_edac: Clean...
3134
  	if (!(value & NBCFG_ECC_ENABLE)) {
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
3135
3136
  		amd64_warn("DRAM ECC disabled on this node, enabling...
  ");
f9431992b   Doug Thompson   amd64_edac: add E...
3137

ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3138
  		s->flags.nb_ecc_prev = 0;
d95cf4de6   Borislav Petkov   amd64_edac: Simpl...
3139

f9431992b   Doug Thompson   amd64_edac: add E...
3140
  		/* Attempt to turn on DRAM ECC Enable */
a97fa68ec   Borislav Petkov   amd64_edac: Clean...
3141
3142
  		value |= NBCFG_ECC_ENABLE;
  		amd64_write_pci_cfg(F3, NBCFG, value);
f9431992b   Doug Thompson   amd64_edac: add E...
3143

a97fa68ec   Borislav Petkov   amd64_edac: Clean...
3144
  		amd64_read_pci_cfg(F3, NBCFG, &value);
f9431992b   Doug Thompson   amd64_edac: add E...
3145

a97fa68ec   Borislav Petkov   amd64_edac: Clean...
3146
  		if (!(value & NBCFG_ECC_ENABLE)) {
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
3147
3148
3149
  			amd64_warn("Hardware rejected DRAM ECC enable,"
  				   "check memory DIMM configuration.
  ");
2299ef711   Borislav Petkov   amd64_edac: Check...
3150
  			ret = false;
f9431992b   Doug Thompson   amd64_edac: add E...
3151
  		} else {
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
3152
3153
  			amd64_info("Hardware accepted DRAM ECC Enable
  ");
f9431992b   Doug Thompson   amd64_edac: add E...
3154
  		}
d95cf4de6   Borislav Petkov   amd64_edac: Simpl...
3155
  	} else {
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3156
  		s->flags.nb_ecc_prev = 1;
f9431992b   Doug Thompson   amd64_edac: add E...
3157
  	}
d95cf4de6   Borislav Petkov   amd64_edac: Simpl...
3158

956b9ba15   Joe Perches   edac: Convert deb...
3159
3160
3161
  	edac_dbg(0, "2: node %d, NBCFG=0x%08x[DramEccEn: %d]
  ",
  		 nid, value, !!(value & NBCFG_ECC_ENABLE));
f9431992b   Doug Thompson   amd64_edac: add E...
3162

2299ef711   Borislav Petkov   amd64_edac: Check...
3163
  	return ret;
f9431992b   Doug Thompson   amd64_edac: add E...
3164
  }
c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
3165
  static void restore_ecc_error_reporting(struct ecc_settings *s, u16 nid,
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3166
  					struct pci_dev *F3)
f9431992b   Doug Thompson   amd64_edac: add E...
3167
  {
c9f4f26ea   Borislav Petkov   amd64_edac: Clean...
3168
  	u32 value, mask = 0x3;		/* UECC/CECC enable */
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3169
  	if (!s->nbctl_valid)
f9431992b   Doug Thompson   amd64_edac: add E...
3170
  		return;
c9f4f26ea   Borislav Petkov   amd64_edac: Clean...
3171
  	amd64_read_pci_cfg(F3, NBCTL, &value);
f9431992b   Doug Thompson   amd64_edac: add E...
3172
  	value &= ~mask;
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3173
  	value |= s->old_nbctl;
f9431992b   Doug Thompson   amd64_edac: add E...
3174

c9f4f26ea   Borislav Petkov   amd64_edac: Clean...
3175
  	amd64_write_pci_cfg(F3, NBCTL, value);
f9431992b   Doug Thompson   amd64_edac: add E...
3176

ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3177
3178
  	/* restore previous BIOS DRAM ECC "off" setting we force-enabled */
  	if (!s->flags.nb_ecc_prev) {
a97fa68ec   Borislav Petkov   amd64_edac: Clean...
3179
3180
3181
  		amd64_read_pci_cfg(F3, NBCFG, &value);
  		value &= ~NBCFG_ECC_ENABLE;
  		amd64_write_pci_cfg(F3, NBCFG, value);
d95cf4de6   Borislav Petkov   amd64_edac: Simpl...
3182
3183
3184
  	}
  
  	/* restore the NB Enable MCGCTL bit */
2299ef711   Borislav Petkov   amd64_edac: Check...
3185
  	if (toggle_ecc_err_reporting(s, nid, OFF))
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
3186
3187
  		amd64_warn("Error restoring NB MCGCTL settings!
  ");
f9431992b   Doug Thompson   amd64_edac: add E...
3188
  }
1c9b08bac   Yazen Ghannam   EDAC/amd64: Use c...
3189
  static bool ecc_enabled(struct amd64_pvt *pvt)
f9431992b   Doug Thompson   amd64_edac: add E...
3190
  {
1c9b08bac   Yazen Ghannam   EDAC/amd64: Use c...
3191
  	u16 nid = pvt->mc_node_id;
06724535f   Borislav Petkov   amd64_edac: check...
3192
  	bool nb_mce_en = false;
196b79fcc   Yazen Ghannam   EDAC, amd64: Exte...
3193
3194
  	u8 ecc_en = 0, i;
  	u32 value;
f9431992b   Doug Thompson   amd64_edac: add E...
3195

196b79fcc   Yazen Ghannam   EDAC, amd64: Exte...
3196
3197
  	if (boot_cpu_data.x86 >= 0x17) {
  		u8 umc_en_mask = 0, ecc_en_mask = 0;
1c9b08bac   Yazen Ghannam   EDAC/amd64: Use c...
3198
  		struct amd64_umc *umc;
f9431992b   Doug Thompson   amd64_edac: add E...
3199

4d30d2bc3   Yazen Ghannam   EDAC/amd64: Use a...
3200
  		for_each_umc(i) {
1c9b08bac   Yazen Ghannam   EDAC/amd64: Use c...
3201
  			umc = &pvt->umc[i];
196b79fcc   Yazen Ghannam   EDAC, amd64: Exte...
3202
3203
  
  			/* Only check enabled UMCs. */
1c9b08bac   Yazen Ghannam   EDAC/amd64: Use c...
3204
  			if (!(umc->sdp_ctrl & UMC_SDP_INIT))
196b79fcc   Yazen Ghannam   EDAC, amd64: Exte...
3205
3206
3207
  				continue;
  
  			umc_en_mask |= BIT(i);
1c9b08bac   Yazen Ghannam   EDAC/amd64: Use c...
3208
  			if (umc->umc_cap_hi & UMC_ECC_ENABLED)
196b79fcc   Yazen Ghannam   EDAC, amd64: Exte...
3209
3210
3211
3212
3213
3214
  				ecc_en_mask |= BIT(i);
  		}
  
  		/* Check whether at least one UMC is enabled: */
  		if (umc_en_mask)
  			ecc_en = umc_en_mask == ecc_en_mask;
11ab1cae5   Yazen Ghannam   EDAC, amd64: Rewo...
3215
3216
3217
  		else
  			edac_dbg(0, "Node %d: No enabled UMCs.
  ", nid);
196b79fcc   Yazen Ghannam   EDAC, amd64: Exte...
3218
3219
3220
3221
  
  		/* Assume UMC MCA banks are enabled. */
  		nb_mce_en = true;
  	} else {
1c9b08bac   Yazen Ghannam   EDAC/amd64: Use c...
3222
  		amd64_read_pci_cfg(pvt->F3, NBCFG, &value);
f9431992b   Doug Thompson   amd64_edac: add E...
3223

196b79fcc   Yazen Ghannam   EDAC, amd64: Exte...
3224
3225
3226
3227
  		ecc_en = !!(value & NBCFG_ECC_ENABLE);
  
  		nb_mce_en = nb_mce_bank_enabled_on_node(nid);
  		if (!nb_mce_en)
11ab1cae5   Yazen Ghannam   EDAC, amd64: Rewo...
3228
3229
  			edac_dbg(0, "NB MCE bank disabled, set MSR 0x%08x[4] on node %d to enable.
  ",
196b79fcc   Yazen Ghannam   EDAC, amd64: Exte...
3230
3231
  				     MSR_IA32_MCG_CTL, nid);
  	}
11ab1cae5   Yazen Ghannam   EDAC, amd64: Rewo...
3232
3233
3234
  	amd64_info("Node %d: DRAM ECC %s.
  ",
  		   nid, (ecc_en ? "enabled" : "disabled"));
f9431992b   Doug Thompson   amd64_edac: add E...
3235

7fdfee926   Borislav Petkov   EDAC/amd64: Get r...
3236
  	if (!ecc_en || !nb_mce_en)
2299ef711   Borislav Petkov   amd64_edac: Check...
3237
  		return false;
7fdfee926   Borislav Petkov   EDAC/amd64: Get r...
3238
3239
  	else
  		return true;
f9431992b   Doug Thompson   amd64_edac: add E...
3240
  }
2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
3241
3242
3243
  static inline void
  f17h_determine_edac_ctl_cap(struct mem_ctl_info *mci, struct amd64_pvt *pvt)
  {
f8be8e568   Yazen Ghannam   EDAC/amd64: Recog...
3244
  	u8 i, ecc_en = 1, cpk_en = 1, dev_x4 = 1, dev_x16 = 1;
2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
3245

4d30d2bc3   Yazen Ghannam   EDAC/amd64: Use a...
3246
  	for_each_umc(i) {
2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
3247
3248
3249
  		if (pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) {
  			ecc_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_ENABLED);
  			cpk_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_CHIPKILL_CAP);
f8be8e568   Yazen Ghannam   EDAC/amd64: Recog...
3250
3251
3252
  
  			dev_x4  &= !!(pvt->umc[i].dimm_cfg & BIT(6));
  			dev_x16 &= !!(pvt->umc[i].dimm_cfg & BIT(7));
2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
3253
3254
3255
3256
3257
3258
  		}
  	}
  
  	/* Set chipkill only if ECC is enabled: */
  	if (ecc_en) {
  		mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
f8be8e568   Yazen Ghannam   EDAC/amd64: Recog...
3259
3260
3261
3262
  		if (!cpk_en)
  			return;
  
  		if (dev_x4)
2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
3263
  			mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
f8be8e568   Yazen Ghannam   EDAC/amd64: Recog...
3264
3265
3266
3267
  		else if (dev_x16)
  			mci->edac_ctl_cap |= EDAC_FLAG_S16ECD16ED;
  		else
  			mci->edac_ctl_cap |= EDAC_FLAG_S8ECD8ED;
2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
3268
3269
  	}
  }
38ddd4d15   Yazen Ghannam   EDAC/amd64: Make ...
3270
  static void setup_mci_misc_attrs(struct mem_ctl_info *mci)
7d6034d32   Doug Thompson   amd64_edac: add m...
3271
3272
3273
3274
3275
  {
  	struct amd64_pvt *pvt = mci->pvt_info;
  
  	mci->mtype_cap		= MEM_FLAG_DDR2 | MEM_FLAG_RDDR2;
  	mci->edac_ctl_cap	= EDAC_FLAG_NONE;
7d6034d32   Doug Thompson   amd64_edac: add m...
3276

2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
3277
3278
3279
3280
3281
  	if (pvt->umc) {
  		f17h_determine_edac_ctl_cap(mci, pvt);
  	} else {
  		if (pvt->nbcap & NBCAP_SECDED)
  			mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
7d6034d32   Doug Thompson   amd64_edac: add m...
3282

2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
3283
3284
3285
  		if (pvt->nbcap & NBCAP_CHIPKILL)
  			mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
  	}
7d6034d32   Doug Thompson   amd64_edac: add m...
3286

d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3287
  	mci->edac_cap		= determine_edac_cap(pvt);
7d6034d32   Doug Thompson   amd64_edac: add m...
3288
  	mci->mod_name		= EDAC_MOD_STR;
38ddd4d15   Yazen Ghannam   EDAC/amd64: Make ...
3289
  	mci->ctl_name		= fam_type->ctl_name;
e7934b70d   Yazen Ghannam   EDAC, amd64: Chan...
3290
  	mci->dev_name		= pci_name(pvt->F3);
7d6034d32   Doug Thompson   amd64_edac: add m...
3291
  	mci->ctl_page_to_phys	= NULL;
7d6034d32   Doug Thompson   amd64_edac: add m...
3292
  	/* memory scrubber interface */
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3293
3294
  	mci->set_sdram_scrub_rate = set_scrub_rate;
  	mci->get_sdram_scrub_rate = get_scrub_rate;
7d6034d32   Doug Thompson   amd64_edac: add m...
3295
  }
0092b20d4   Borislav Petkov   amd64_edac: Simpl...
3296
3297
3298
  /*
   * returns a pointer to the family descriptor on success, NULL otherwise.
   */
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3299
  static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
395ae783b   Borislav Petkov   amd64_edac: Add p...
3300
  {
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
3301
  	pvt->ext_model  = boot_cpu_data.x86_model >> 4;
b399151cb   Jia Zhang   x86/cpu: Rename c...
3302
  	pvt->stepping	= boot_cpu_data.x86_stepping;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
3303
3304
3305
3306
  	pvt->model	= boot_cpu_data.x86_model;
  	pvt->fam	= boot_cpu_data.x86;
  
  	switch (pvt->fam) {
395ae783b   Borislav Petkov   amd64_edac: Add p...
3307
  	case 0xf:
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3308
3309
  		fam_type	= &family_types[K8_CPUS];
  		pvt->ops	= &family_types[K8_CPUS].ops;
395ae783b   Borislav Petkov   amd64_edac: Add p...
3310
  		break;
df71a0532   Borislav Petkov   amd64_edac: Enabl...
3311

395ae783b   Borislav Petkov   amd64_edac: Add p...
3312
  	case 0x10:
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3313
3314
  		fam_type	= &family_types[F10_CPUS];
  		pvt->ops	= &family_types[F10_CPUS].ops;
df71a0532   Borislav Petkov   amd64_edac: Enabl...
3315
3316
3317
  		break;
  
  	case 0x15:
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
3318
  		if (pvt->model == 0x30) {
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3319
3320
  			fam_type = &family_types[F15_M30H_CPUS];
  			pvt->ops = &family_types[F15_M30H_CPUS].ops;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
3321
  			break;
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
3322
3323
3324
3325
  		} else if (pvt->model == 0x60) {
  			fam_type = &family_types[F15_M60H_CPUS];
  			pvt->ops = &family_types[F15_M60H_CPUS].ops;
  			break;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
3326
  		}
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3327
3328
  		fam_type	= &family_types[F15_CPUS];
  		pvt->ops	= &family_types[F15_CPUS].ops;
395ae783b   Borislav Petkov   amd64_edac: Add p...
3329
  		break;
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
3330
  	case 0x16:
85a8885bd   Aravind Gopalakrishnan   amd64_edac: Add s...
3331
3332
3333
3334
3335
  		if (pvt->model == 0x30) {
  			fam_type = &family_types[F16_M30H_CPUS];
  			pvt->ops = &family_types[F16_M30H_CPUS].ops;
  			break;
  		}
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3336
3337
  		fam_type	= &family_types[F16_CPUS];
  		pvt->ops	= &family_types[F16_CPUS].ops;
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
3338
  		break;
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
3339
  	case 0x17:
8960de4a5   Michael Jin   EDAC, amd64: Add ...
3340
3341
3342
3343
  		if (pvt->model >= 0x10 && pvt->model <= 0x2f) {
  			fam_type = &family_types[F17_M10H_CPUS];
  			pvt->ops = &family_types[F17_M10H_CPUS].ops;
  			break;
6e846239e   Yazen Ghannam   EDAC/amd64: Add F...
3344
3345
3346
3347
  		} else if (pvt->model >= 0x30 && pvt->model <= 0x3f) {
  			fam_type = &family_types[F17_M30H_CPUS];
  			pvt->ops = &family_types[F17_M30H_CPUS].ops;
  			break;
b6bea24d4   Alexander Monakov   EDAC/amd64: Add A...
3348
3349
3350
3351
  		} else if (pvt->model >= 0x60 && pvt->model <= 0x6f) {
  			fam_type = &family_types[F17_M60H_CPUS];
  			pvt->ops = &family_types[F17_M60H_CPUS].ops;
  			break;
3e443eb35   Isaac Vaughn   EDAC/amd64: Add P...
3352
3353
3354
3355
  		} else if (pvt->model >= 0x70 && pvt->model <= 0x7f) {
  			fam_type = &family_types[F17_M70H_CPUS];
  			pvt->ops = &family_types[F17_M70H_CPUS].ops;
  			break;
8960de4a5   Michael Jin   EDAC, amd64: Add ...
3356
  		}
df561f668   Gustavo A. R. Silva   treewide: Use fal...
3357
  		fallthrough;
c4a3e9464   Pu Wen   EDAC, amd64: Add ...
3358
  	case 0x18:
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
3359
3360
  		fam_type	= &family_types[F17_CPUS];
  		pvt->ops	= &family_types[F17_CPUS].ops;
c4a3e9464   Pu Wen   EDAC, amd64: Add ...
3361
3362
3363
  
  		if (pvt->fam == 0x18)
  			family_types[F17_CPUS].ctl_name = "F18h";
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
3364
  		break;
2eb61c91c   Yazen Ghannam   EDAC/amd64: Add f...
3365
  	case 0x19:
b4210eab9   Yazen Ghannam   EDAC/amd64: Set p...
3366
3367
3368
3369
3370
3371
  		if (pvt->model >= 0x20 && pvt->model <= 0x2f) {
  			fam_type = &family_types[F17_M70H_CPUS];
  			pvt->ops = &family_types[F17_M70H_CPUS].ops;
  			fam_type->ctl_name = "F19h_M20h";
  			break;
  		}
2eb61c91c   Yazen Ghannam   EDAC/amd64: Add f...
3372
3373
3374
3375
  		fam_type	= &family_types[F19_CPUS];
  		pvt->ops	= &family_types[F19_CPUS].ops;
  		family_types[F19_CPUS].ctl_name = "F19h";
  		break;
395ae783b   Borislav Petkov   amd64_edac: Add p...
3376
  	default:
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
3377
3378
  		amd64_err("Unsupported family!
  ");
0092b20d4   Borislav Petkov   amd64_edac: Simpl...
3379
  		return NULL;
395ae783b   Borislav Petkov   amd64_edac: Add p...
3380
  	}
0092b20d4   Borislav Petkov   amd64_edac: Simpl...
3381

df71a0532   Borislav Petkov   amd64_edac: Enabl...
3382
3383
  	amd64_info("%s %sdetected (node %d).
  ", fam_type->ctl_name,
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
3384
  		     (pvt->fam == 0xf ?
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
3385
3386
3387
  				(pvt->ext_model >= K8_REV_F  ? "revF or later "
  							     : "revE or earlier ")
  				 : ""), pvt->mc_node_id);
0092b20d4   Borislav Petkov   amd64_edac: Simpl...
3388
  	return fam_type;
395ae783b   Borislav Petkov   amd64_edac: Add p...
3389
  }
e339f1ec9   Takashi Iwai   EDAC: amd64: Use ...
3390
3391
3392
3393
3394
3395
3396
3397
3398
  static const struct attribute_group *amd64_edac_attr_groups[] = {
  #ifdef CONFIG_EDAC_DEBUG
  	&amd64_edac_dbg_group,
  #endif
  #ifdef CONFIG_EDAC_AMD64_ERROR_INJECTION
  	&amd64_edac_inj_group,
  #endif
  	NULL
  };
80355a3b2   Yazen Ghannam   EDAC/amd64: Gathe...
3399
  static int hw_info_get(struct amd64_pvt *pvt)
7d6034d32   Doug Thompson   amd64_edac: add m...
3400
  {
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
3401
  	u16 pci_id1, pci_id2;
f00eb5ff2   Colin Ian King   EDAC/amd64: Remov...
3402
  	int ret;
395ae783b   Borislav Petkov   amd64_edac: Add p...
3403

936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
3404
  	if (pvt->fam >= 0x17) {
5e4c55276   Yazen Ghannam   EDAC/amd64: Save ...
3405
  		pvt->umc = kcalloc(fam_type->max_mcs, sizeof(struct amd64_umc), GFP_KERNEL);
80355a3b2   Yazen Ghannam   EDAC/amd64: Gathe...
3406
3407
  		if (!pvt->umc)
  			return -ENOMEM;
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
3408
3409
3410
3411
3412
3413
3414
  
  		pci_id1 = fam_type->f0_id;
  		pci_id2 = fam_type->f6_id;
  	} else {
  		pci_id1 = fam_type->f1_id;
  		pci_id2 = fam_type->f2_id;
  	}
80355a3b2   Yazen Ghannam   EDAC/amd64: Gathe...
3415
3416
3417
  	ret = reserve_mc_sibling_devs(pvt, pci_id1, pci_id2);
  	if (ret)
  		return ret;
7d6034d32   Doug Thompson   amd64_edac: add m...
3418

360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3419
  	read_mc_regs(pvt);
7d6034d32   Doug Thompson   amd64_edac: add m...
3420

80355a3b2   Yazen Ghannam   EDAC/amd64: Gathe...
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
  	return 0;
  }
  
  static void hw_info_put(struct amd64_pvt *pvt)
  {
  	if (pvt->F0 || pvt->F1)
  		free_mc_sibling_devs(pvt);
  
  	kfree(pvt->umc);
  }
  
  static int init_one_instance(struct amd64_pvt *pvt)
  {
  	struct mem_ctl_info *mci = NULL;
  	struct edac_mc_layer layers[2];
  	int ret = -EINVAL;
7d6034d32   Doug Thompson   amd64_edac: add m...
3437
3438
3439
  	/*
  	 * We need to determine how many memory channels there are. Then use
  	 * that information for calculating the size of the dynamic instance
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3440
  	 * tables in the 'mci' structure.
7d6034d32   Doug Thompson   amd64_edac: add m...
3441
3442
3443
  	 */
  	pvt->channel_count = pvt->ops->early_channel_count(pvt);
  	if (pvt->channel_count < 0)
80355a3b2   Yazen Ghannam   EDAC/amd64: Gathe...
3444
  		return ret;
7d6034d32   Doug Thompson   amd64_edac: add m...
3445
3446
  
  	ret = -ENOMEM;
ab5a503cb   Mauro Carvalho Chehab   amd64_edac: conve...
3447
3448
3449
3450
  	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
  	layers[0].size = pvt->csels[0].b_cnt;
  	layers[0].is_virt_csrow = true;
  	layers[1].type = EDAC_MC_LAYER_CHANNEL;
f0a56c480   Borislav Petkov   amd64_edac: Fix s...
3451
3452
3453
3454
3455
3456
  
  	/*
  	 * Always allocate two channels since we can have setups with DIMMs on
  	 * only one channel. Also, this simplifies handling later for the price
  	 * of a couple of KBs tops.
  	 */
5e4c55276   Yazen Ghannam   EDAC/amd64: Save ...
3457
  	layers[1].size = fam_type->max_mcs;
ab5a503cb   Mauro Carvalho Chehab   amd64_edac: conve...
3458
  	layers[1].is_virt_csrow = false;
f0a56c480   Borislav Petkov   amd64_edac: Fix s...
3459

80355a3b2   Yazen Ghannam   EDAC/amd64: Gathe...
3460
  	mci = edac_mc_alloc(pvt->mc_node_id, ARRAY_SIZE(layers), layers, 0);
7d6034d32   Doug Thompson   amd64_edac: add m...
3461
  	if (!mci)
80355a3b2   Yazen Ghannam   EDAC/amd64: Gathe...
3462
  		return ret;
7d6034d32   Doug Thompson   amd64_edac: add m...
3463
3464
  
  	mci->pvt_info = pvt;
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3465
  	mci->pdev = &pvt->F3->dev;
7d6034d32   Doug Thompson   amd64_edac: add m...
3466

38ddd4d15   Yazen Ghannam   EDAC/amd64: Make ...
3467
  	setup_mci_misc_attrs(mci);
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3468
3469
  
  	if (init_csrows(mci))
7d6034d32   Doug Thompson   amd64_edac: add m...
3470
  		mci->edac_cap = EDAC_FLAG_NONE;
7d6034d32   Doug Thompson   amd64_edac: add m...
3471
  	ret = -ENODEV;
e339f1ec9   Takashi Iwai   EDAC: amd64: Use ...
3472
  	if (edac_mc_add_mc_with_groups(mci, amd64_edac_attr_groups)) {
956b9ba15   Joe Perches   edac: Convert deb...
3473
3474
  		edac_dbg(1, "failed edac_mc_add_mc()
  ");
80355a3b2   Yazen Ghannam   EDAC/amd64: Gathe...
3475
3476
  		edac_mc_free(mci);
  		return ret;
7d6034d32   Doug Thompson   amd64_edac: add m...
3477
  	}
7d6034d32   Doug Thompson   amd64_edac: add m...
3478
  	return 0;
7d6034d32   Doug Thompson   amd64_edac: add m...
3479
  }
582f94b59   Yazen Ghannam   EDAC/amd64: Check...
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
  static bool instance_has_memory(struct amd64_pvt *pvt)
  {
  	bool cs_enabled = false;
  	int cs = 0, dct = 0;
  
  	for (dct = 0; dct < fam_type->max_mcs; dct++) {
  		for_each_chip_select(cs, dct, pvt)
  			cs_enabled |= csrow_enabled(cs, dct, pvt);
  	}
  
  	return cs_enabled;
  }
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3492
  static int probe_one_instance(unsigned int nid)
7d6034d32   Doug Thompson   amd64_edac: add m...
3493
  {
2299ef711   Borislav Petkov   amd64_edac: Check...
3494
  	struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
80355a3b2   Yazen Ghannam   EDAC/amd64: Gathe...
3495
  	struct amd64_pvt *pvt = NULL;
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3496
  	struct ecc_settings *s;
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3497
  	int ret;
7d6034d32   Doug Thompson   amd64_edac: add m...
3498

ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3499
3500
3501
  	ret = -ENOMEM;
  	s = kzalloc(sizeof(struct ecc_settings), GFP_KERNEL);
  	if (!s)
2299ef711   Borislav Petkov   amd64_edac: Check...
3502
  		goto err_out;
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3503
3504
  
  	ecc_stngs[nid] = s;
80355a3b2   Yazen Ghannam   EDAC/amd64: Gathe...
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
  	pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
  	if (!pvt)
  		goto err_settings;
  
  	pvt->mc_node_id	= nid;
  	pvt->F3 = F3;
  
  	fam_type = per_family_init(pvt);
  	if (!fam_type)
  		goto err_enable;
  
  	ret = hw_info_get(pvt);
  	if (ret < 0)
  		goto err_enable;
582f94b59   Yazen Ghannam   EDAC/amd64: Check...
3519
3520
3521
3522
3523
3524
  	ret = 0;
  	if (!instance_has_memory(pvt)) {
  		amd64_info("Node %d: No DIMMs detected.
  ", nid);
  		goto err_enable;
  	}
1c9b08bac   Yazen Ghannam   EDAC/amd64: Use c...
3525
  	if (!ecc_enabled(pvt)) {
582f94b59   Yazen Ghannam   EDAC/amd64: Check...
3526
  		ret = -ENODEV;
2299ef711   Borislav Petkov   amd64_edac: Check...
3527
3528
3529
  
  		if (!ecc_enable_override)
  			goto err_enable;
044e7a414   Yazen Ghannam   EDAC, amd64: Don'...
3530
3531
3532
3533
3534
3535
  		if (boot_cpu_data.x86 >= 0x17) {
  			amd64_warn("Forcing ECC on is not recommended on newer systems. Please enable ECC in BIOS.");
  			goto err_enable;
  		} else
  			amd64_warn("Forcing ECC on!
  ");
2299ef711   Borislav Petkov   amd64_edac: Check...
3536
3537
3538
3539
  
  		if (!enable_ecc_error_reporting(s, nid, F3))
  			goto err_enable;
  	}
80355a3b2   Yazen Ghannam   EDAC/amd64: Gathe...
3540
  	ret = init_one_instance(pvt);
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3541
  	if (ret < 0) {
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3542
3543
  		amd64_err("Error probing instance: %d
  ", nid);
044e7a414   Yazen Ghannam   EDAC, amd64: Don'...
3544
3545
3546
  
  		if (boot_cpu_data.x86 < 0x17)
  			restore_ecc_error_reporting(s, nid, F3);
2b9b2c465   Yazen Ghannam   EDAC, amd64: Free...
3547
3548
  
  		goto err_enable;
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3549
  	}
7d6034d32   Doug Thompson   amd64_edac: add m...
3550

582f94b59   Yazen Ghannam   EDAC/amd64: Check...
3551
  	dump_misc_regs(pvt);
7d6034d32   Doug Thompson   amd64_edac: add m...
3552
  	return ret;
2299ef711   Borislav Petkov   amd64_edac: Check...
3553
3554
  
  err_enable:
80355a3b2   Yazen Ghannam   EDAC/amd64: Gathe...
3555
3556
3557
3558
  	hw_info_put(pvt);
  	kfree(pvt);
  
  err_settings:
2299ef711   Borislav Petkov   amd64_edac: Check...
3559
3560
3561
3562
3563
  	kfree(s);
  	ecc_stngs[nid] = NULL;
  
  err_out:
  	return ret;
7d6034d32   Doug Thompson   amd64_edac: add m...
3564
  }
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3565
  static void remove_one_instance(unsigned int nid)
7d6034d32   Doug Thompson   amd64_edac: add m...
3566
  {
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3567
3568
  	struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
  	struct ecc_settings *s = ecc_stngs[nid];
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3569
3570
  	struct mem_ctl_info *mci;
  	struct amd64_pvt *pvt;
7d6034d32   Doug Thompson   amd64_edac: add m...
3571
3572
  
  	/* Remove from EDAC CORE tracking list */
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3573
  	mci = edac_mc_del_mc(&F3->dev);
7d6034d32   Doug Thompson   amd64_edac: add m...
3574
3575
3576
3577
  	if (!mci)
  		return;
  
  	pvt = mci->pvt_info;
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3578
  	restore_ecc_error_reporting(s, nid, F3);
7d6034d32   Doug Thompson   amd64_edac: add m...
3579

360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3580
3581
  	kfree(ecc_stngs[nid]);
  	ecc_stngs[nid] = NULL;
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3582

7d6034d32   Doug Thompson   amd64_edac: add m...
3583
  	/* Free the EDAC CORE resources */
8f68ed972   Borislav Petkov   amd64_edac: fix d...
3584
  	mci->pvt_info = NULL;
8f68ed972   Borislav Petkov   amd64_edac: fix d...
3585

80355a3b2   Yazen Ghannam   EDAC/amd64: Gathe...
3586
  	hw_info_put(pvt);
8f68ed972   Borislav Petkov   amd64_edac: fix d...
3587
  	kfree(pvt);
7d6034d32   Doug Thompson   amd64_edac: add m...
3588
3589
  	edac_mc_free(mci);
  }
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3590
  static void setup_pci_device(void)
7d6034d32   Doug Thompson   amd64_edac: add m...
3591
  {
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3592
  	if (pci_ctl)
7d6034d32   Doug Thompson   amd64_edac: add m...
3593
  		return;
eae95da7f   Borislav Petkov   EDAC/amd64: Fix P...
3594
  	pci_ctl = edac_pci_create_generic_ctl(pci_ctl_dev, EDAC_MOD_STR);
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3595
3596
3597
3598
3599
  	if (!pci_ctl) {
  		pr_warn("%s(): Unable to create PCI control
  ", __func__);
  		pr_warn("%s(): PCI error report via EDAC not set
  ", __func__);
7d6034d32   Doug Thompson   amd64_edac: add m...
3600
3601
  	}
  }
d6efab74f   Yazen Ghannam   EDAC, amd64: Auto...
3602
  static const struct x86_cpu_id amd64_cpuids[] = {
298426211   Thomas Gleixner   EDAC: Convert to ...
3603
3604
3605
3606
3607
3608
3609
  	X86_MATCH_VENDOR_FAM(AMD,	0x0F, NULL),
  	X86_MATCH_VENDOR_FAM(AMD,	0x10, NULL),
  	X86_MATCH_VENDOR_FAM(AMD,	0x15, NULL),
  	X86_MATCH_VENDOR_FAM(AMD,	0x16, NULL),
  	X86_MATCH_VENDOR_FAM(AMD,	0x17, NULL),
  	X86_MATCH_VENDOR_FAM(HYGON,	0x18, NULL),
  	X86_MATCH_VENDOR_FAM(AMD,	0x19, NULL),
d6efab74f   Yazen Ghannam   EDAC, amd64: Auto...
3610
3611
3612
  	{ }
  };
  MODULE_DEVICE_TABLE(x86cpu, amd64_cpuids);
7d6034d32   Doug Thompson   amd64_edac: add m...
3613
3614
  static int __init amd64_edac_init(void)
  {
301375e76   Toshi Kani   EDAC: Add owner c...
3615
  	const char *owner;
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3616
  	int err = -ENODEV;
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3617
  	int i;
7d6034d32   Doug Thompson   amd64_edac: add m...
3618

301375e76   Toshi Kani   EDAC: Add owner c...
3619
3620
3621
  	owner = edac_get_owner();
  	if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
  		return -EBUSY;
1bd9900b8   Yazen Ghannam   EDAC, amd64: Add ...
3622
3623
  	if (!x86_match_cpu(amd64_cpuids))
  		return -ENODEV;
9653a5c76   Hans Rosenfeld   x86, amd-nb: Clea...
3624
  	if (amd_cache_northbridges() < 0)
1bd9900b8   Yazen Ghannam   EDAC, amd64: Add ...
3625
  		return -ENODEV;
7d6034d32   Doug Thompson   amd64_edac: add m...
3626

6ba92fea1   Borislav Petkov   EDAC, amd64_edac:...
3627
  	opstate_init();
cc4d8860f   Borislav Petkov   amd64_edac: Alloc...
3628
  	err = -ENOMEM;
6396bb221   Kees Cook   treewide: kzalloc...
3629
  	ecc_stngs = kcalloc(amd_nb_num(), sizeof(ecc_stngs[0]), GFP_KERNEL);
2ec591ac7   Borislav Petkov   EDAC, amd64_edac:...
3630
  	if (!ecc_stngs)
a9f0fbe2b   Borislav Petkov   amd64_edac: Fix p...
3631
  		goto err_free;
cc4d8860f   Borislav Petkov   amd64_edac: Alloc...
3632

505422517   Borislav Petkov   x86, msr: Add sup...
3633
  	msrs = msrs_alloc();
56b34b91e   Borislav Petkov   amd64_edac: make ...
3634
  	if (!msrs)
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3635
  		goto err_free;
505422517   Borislav Petkov   x86, msr: Add sup...
3636

2287c6364   Yazen Ghannam   EDAC, amd64: Save...
3637
3638
3639
  	for (i = 0; i < amd_nb_num(); i++) {
  		err = probe_one_instance(i);
  		if (err) {
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3640
3641
3642
  			/* unwind properly */
  			while (--i >= 0)
  				remove_one_instance(i);
7d6034d32   Doug Thompson   amd64_edac: add m...
3643

3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3644
3645
  			goto err_pci;
  		}
2287c6364   Yazen Ghannam   EDAC, amd64: Save...
3646
  	}
7d6034d32   Doug Thompson   amd64_edac: add m...
3647

4688c9b42   Yazen Ghannam   EDAC, amd64: Don'...
3648
3649
3650
3651
  	if (!edac_has_mcs()) {
  		err = -ENODEV;
  		goto err_pci;
  	}
234365f56   Yazen Ghannam   EDAC, amd64: Move...
3652
  	/* register stuff with EDAC MCE */
234365f56   Yazen Ghannam   EDAC, amd64: Move...
3653
3654
3655
3656
  	if (boot_cpu_data.x86 >= 0x17)
  		amd_register_ecc_decoder(decode_umc_error);
  	else
  		amd_register_ecc_decoder(decode_bus_error);
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3657
  	setup_pci_device();
f5b10c45e   Tomasz Pala   amd64_edac: Build...
3658
3659
3660
3661
3662
  
  #ifdef CONFIG_X86_32
  	amd64_err("%s on 32-bit is unsupported. USE AT YOUR OWN RISK!
  ", EDAC_MOD_STR);
  #endif
de0336b30   Borislav Petkov   EDAC, amd64_edac:...
3663
3664
  	printk(KERN_INFO "AMD64 EDAC driver v%s
  ", EDAC_AMD64_VERSION);
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3665
  	return 0;
7d6034d32   Doug Thompson   amd64_edac: add m...
3666

56b34b91e   Borislav Petkov   amd64_edac: make ...
3667
  err_pci:
eae95da7f   Borislav Petkov   EDAC/amd64: Fix P...
3668
  	pci_ctl_dev = NULL;
56b34b91e   Borislav Petkov   amd64_edac: make ...
3669
3670
  	msrs_free(msrs);
  	msrs = NULL;
cc4d8860f   Borislav Petkov   amd64_edac: Alloc...
3671

360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3672
  err_free:
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3673
3674
  	kfree(ecc_stngs);
  	ecc_stngs = NULL;
7d6034d32   Doug Thompson   amd64_edac: add m...
3675
3676
3677
3678
3679
  	return err;
  }
  
  static void __exit amd64_edac_exit(void)
  {
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3680
  	int i;
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3681
3682
  	if (pci_ctl)
  		edac_pci_release_generic_ctl(pci_ctl);
7d6034d32   Doug Thompson   amd64_edac: add m...
3683

234365f56   Yazen Ghannam   EDAC, amd64: Move...
3684
  	/* unregister from EDAC MCE */
234365f56   Yazen Ghannam   EDAC, amd64: Move...
3685
3686
3687
3688
  	if (boot_cpu_data.x86 >= 0x17)
  		amd_unregister_ecc_decoder(decode_umc_error);
  	else
  		amd_unregister_ecc_decoder(decode_bus_error);
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3689
3690
  	for (i = 0; i < amd_nb_num(); i++)
  		remove_one_instance(i);
505422517   Borislav Petkov   x86, msr: Add sup...
3691

ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3692
3693
  	kfree(ecc_stngs);
  	ecc_stngs = NULL;
eae95da7f   Borislav Petkov   EDAC/amd64: Fix P...
3694
  	pci_ctl_dev = NULL;
505422517   Borislav Petkov   x86, msr: Add sup...
3695
3696
  	msrs_free(msrs);
  	msrs = NULL;
7d6034d32   Doug Thompson   amd64_edac: add m...
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
  }
  
  module_init(amd64_edac_init);
  module_exit(amd64_edac_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("SoftwareBitMaker: Doug Thompson, "
  		"Dave Peterson, Thayne Harbaugh");
  MODULE_DESCRIPTION("MC support for AMD64 memory controllers - "
  		EDAC_AMD64_VERSION);
  
  module_param(edac_op_state, int, 0444);
  MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");