Blame view

drivers/edac/amd64_edac.c 88.5 KB
2bc654187   Doug Thompson   amd64_edac: add m...
1
  #include "amd64_edac.h"
23ac4ae82   Andreas Herrmann   x86, k8: Rename k...
2
  #include <asm/amd_nb.h>
2bc654187   Doug Thompson   amd64_edac: add m...
3

d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
4
  static struct edac_pci_ctl_info *pci_ctl;
2bc654187   Doug Thompson   amd64_edac: add m...
5
6
7
8
9
10
11
12
13
14
  
  static int report_gart_errors;
  module_param(report_gart_errors, int, 0644);
  
  /*
   * 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...
15
  static struct msr __percpu *msrs;
505422517   Borislav Petkov   x86, msr: Add sup...
16

2ec591ac7   Borislav Petkov   EDAC, amd64_edac:...
17
  /* Per-node stuff */
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
18
  static struct ecc_settings **ecc_stngs;
2bc654187   Doug Thompson   amd64_edac: add m...
19
20
  
  /*
b70ef0101   Borislav Petkov   EDAC: move MCE er...
21
22
23
24
25
26
   * 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...
27
  static const struct scrubrate {
390944439   Borislav Petkov   EDAC: Fixup scrub...
28
29
30
         u32 scrubval;           /* bit pattern for scrub rate */
         u32 bandwidth;          /* bandwidth consumed (bytes/sec) */
  } scrubrates[] = {
b70ef0101   Borislav Petkov   EDAC: move MCE er...
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  	{ 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...
55
56
  int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
  			       u32 *val, const char *func)
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
57
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
  {
  	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...
84
85
86
87
88
89
90
91
92
93
94
95
96
   * 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...
97
98
99
   *
   * Depending on the family, F2 DCT reads need special handling:
   *
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
100
   * K8: has a single DCT only and no address offsets >= 0x100
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
101
102
103
104
105
   *
   * F10h: each DCT has its own set of regs
   *	DCT0 -> F2x040..
   *	DCT1 -> F2x140..
   *
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
106
   * F16h: has only 1 DCT
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
107
108
   *
   * F15h: we select which DCT we access using F1x10C[DctCfgSel]
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
109
   */
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
110
111
  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...
112
  {
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
113
114
115
116
117
  	switch (pvt->fam) {
  	case 0xf:
  		if (dct || offset >= 0x100)
  			return -EINVAL;
  		break;
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
118

7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
119
120
121
122
123
124
125
126
127
  	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...
128

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

7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
133
134
135
136
137
138
139
140
  	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...
141

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

7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
147
148
  	default:
  		break;
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
149
  	}
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
150
  	return amd64_read_pci_cfg(pvt->F2, offset, val);
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
151
  }
b70ef0101   Borislav Petkov   EDAC: move MCE er...
152
  /*
2bc654187   Doug Thompson   amd64_edac: add m...
153
154
155
156
157
158
159
160
161
162
163
164
   * 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 ...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  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...
180
  /*
8051c0af3   Yazen Ghannam   EDAC, amd64: Add ...
181
   * Scan the scrub rate mapping table for a close or matching bandwidth value to
2bc654187   Doug Thompson   amd64_edac: add m...
182
183
   * issue. If requested is too big, then use last maximum value found.
   */
da92110df   Aravind Gopalakrishnan   EDAC, amd64_edac:...
184
  static int __set_scrub_rate(struct amd64_pvt *pvt, u32 new_bw, u32 min_rate)
2bc654187   Doug Thompson   amd64_edac: add m...
185
186
187
188
189
190
191
192
193
  {
  	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...
194
195
196
  	 *
  	 * 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...
197
  	 */
168bfeef7   Andrew Morton   amd64_edac:__amd6...
198
  	for (i = 0; i < ARRAY_SIZE(scrubrates) - 1; i++) {
2bc654187   Doug Thompson   amd64_edac: add m...
199
200
201
202
  		/*
  		 * skip scrub rates which aren't recommended
  		 * (see F10 BKDG, F3x58)
  		 */
395ae783b   Borislav Petkov   amd64_edac: Add p...
203
  		if (scrubrates[i].scrubval < min_rate)
2bc654187   Doug Thompson   amd64_edac: add m...
204
205
206
207
  			continue;
  
  		if (scrubrates[i].bandwidth <= new_bw)
  			break;
2bc654187   Doug Thompson   amd64_edac: add m...
208
209
210
  	}
  
  	scrubval = scrubrates[i].scrubval;
2bc654187   Doug Thompson   amd64_edac: add m...
211

8051c0af3   Yazen Ghannam   EDAC, amd64: Add ...
212
213
214
  	if (pvt->fam == 0x17) {
  		__f17h_set_scrubval(pvt, scrubval);
  	} else if (pvt->fam == 0x15 && pvt->model == 0x60) {
da92110df   Aravind Gopalakrishnan   EDAC, amd64_edac:...
215
216
217
218
219
220
221
  		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...
222

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

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

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

8051c0af3   Yazen Ghannam   EDAC, amd64: Add ...
250
251
  	switch (pvt->fam) {
  	case 0x15:
da92110df   Aravind Gopalakrishnan   EDAC, amd64_edac:...
252
253
254
  		/* Erratum #505 */
  		if (pvt->model < 0x10)
  			f15h_select_dct(pvt, 0);
73ba85937   Borislav Petkov   amd64_edac: Add a...
255

da92110df   Aravind Gopalakrishnan   EDAC, amd64_edac:...
256
257
  		if (pvt->model == 0x60)
  			amd64_read_pci_cfg(pvt->F2, F15H_M60H_SCRCTRL, &scrubval);
8051c0af3   Yazen Ghannam   EDAC, amd64: Add ...
258
259
260
261
262
263
264
265
266
267
268
269
270
271
  		break;
  
  	case 0x17:
  		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;
  		}
  		break;
  
  	default:
da92110df   Aravind Gopalakrishnan   EDAC, amd64_edac:...
272
  		amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval);
8051c0af3   Yazen Ghannam   EDAC, amd64: Add ...
273
274
  		break;
  	}
2bc654187   Doug Thompson   amd64_edac: add m...
275
276
  
  	scrubval = scrubval & 0x001F;
926311fd7   Roel Kluin   amd64_edac: Ensur...
277
  	for (i = 0; i < ARRAY_SIZE(scrubrates); i++) {
2bc654187   Doug Thompson   amd64_edac: add m...
278
  		if (scrubrates[i].scrubval == scrubval) {
390944439   Borislav Petkov   EDAC: Fixup scrub...
279
  			retval = scrubrates[i].bandwidth;
2bc654187   Doug Thompson   amd64_edac: add m...
280
281
282
  			break;
  		}
  	}
390944439   Borislav Petkov   EDAC: Fixup scrub...
283
  	return retval;
2bc654187   Doug Thompson   amd64_edac: add m...
284
  }
6775763a2   Doug Thompson   amd64_edac: add s...
285
  /*
7f19bf755   Borislav Petkov   amd64_edac: Remov...
286
287
   * 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...
288
   */
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
289
  static bool base_limit_match(struct amd64_pvt *pvt, u64 sys_addr, u8 nid)
6775763a2   Doug Thompson   amd64_edac: add s...
290
  {
7f19bf755   Borislav Petkov   amd64_edac: Remov...
291
  	u64 addr;
6775763a2   Doug Thompson   amd64_edac: add s...
292
293
294
295
296
297
298
299
  
  	/* 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...
300
301
  	return ((addr >= get_dram_base(pvt, nid)) &&
  		(addr <= get_dram_limit(pvt, nid)));
6775763a2   Doug Thompson   amd64_edac: add s...
302
303
304
305
306
307
308
309
310
311
312
313
  }
  
  /*
   * 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...
314
  	u8 node_id;
6775763a2   Doug Thompson   amd64_edac: add s...
315
316
317
318
319
320
321
322
323
324
325
326
327
  	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...
328
  	intlv_en = dram_intlv_en(pvt, 0);
6775763a2   Doug Thompson   amd64_edac: add s...
329
330
  
  	if (intlv_en == 0) {
7f19bf755   Borislav Petkov   amd64_edac: Remov...
331
  		for (node_id = 0; node_id < DRAM_RANGES; node_id++) {
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
332
  			if (base_limit_match(pvt, sys_addr, node_id))
8edc54458   Borislav Petkov   amd64_edac: fix K...
333
  				goto found;
6775763a2   Doug Thompson   amd64_edac: add s...
334
  		}
8edc54458   Borislav Petkov   amd64_edac: fix K...
335
  		goto err_no_match;
6775763a2   Doug Thompson   amd64_edac: add s...
336
  	}
72f158fe6   Borislav Petkov   amd64_edac: fix i...
337
338
339
  	if (unlikely((intlv_en != 0x01) &&
  		     (intlv_en != 0x03) &&
  		     (intlv_en != 0x07))) {
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
340
341
  		amd64_warn("DRAM Base[IntlvEn] junk value: 0x%x, BIOS bug?
  ", intlv_en);
6775763a2   Doug Thompson   amd64_edac: add s...
342
343
344
345
346
347
  		return NULL;
  	}
  
  	bits = (((u32) sys_addr) >> 12) & intlv_en;
  
  	for (node_id = 0; ; ) {
7f19bf755   Borislav Petkov   amd64_edac: Remov...
348
  		if ((dram_intlv_sel(pvt, node_id) & intlv_en) == bits)
6775763a2   Doug Thompson   amd64_edac: add s...
349
  			break;	/* intlv_sel field matches */
7f19bf755   Borislav Petkov   amd64_edac: Remov...
350
  		if (++node_id >= DRAM_RANGES)
6775763a2   Doug Thompson   amd64_edac: add s...
351
352
353
354
  			goto err_no_match;
  	}
  
  	/* sanity test for sys_addr */
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
355
  	if (unlikely(!base_limit_match(pvt, sys_addr, node_id))) {
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
356
357
358
359
  		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...
360
361
362
363
  		return NULL;
  	}
  
  found:
b487c33e5   Borislav Petkov   amd64_edac: Fix n...
364
  	return edac_mc_find((int)node_id);
6775763a2   Doug Thompson   amd64_edac: add s...
365
366
  
  err_no_match:
956b9ba15   Joe Perches   edac: Convert deb...
367
368
369
  	edac_dbg(2, "sys_addr 0x%lx doesn't match any node
  ",
  		 (unsigned long)sys_addr);
6775763a2   Doug Thompson   amd64_edac: add s...
370
371
372
  
  	return NULL;
  }
e2ce7255e   Doug Thompson   amd64_edac: add f...
373
374
  
  /*
11c75eada   Borislav Petkov   amd64_edac: Clean...
375
376
   * 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...
377
   */
11c75eada   Borislav Petkov   amd64_edac: Clean...
378
379
  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...
380
  {
11c75eada   Borislav Petkov   amd64_edac: Clean...
381
382
  	u64 csbase, csmask, base_bits, mask_bits;
  	u8 addr_shift;
e2ce7255e   Doug Thompson   amd64_edac: add f...
383

18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
384
  	if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) {
11c75eada   Borislav Petkov   amd64_edac: Clean...
385
386
  		csbase		= pvt->csels[dct].csbases[csrow];
  		csmask		= pvt->csels[dct].csmasks[csrow];
10ef6b0df   Chen, Gong   bitops: Introduce...
387
388
  		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...
389
  		addr_shift	= 4;
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
390
391
  
  	/*
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
392
393
394
395
396
  	 * 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...
397
398
  		csbase          = pvt->csels[dct].csbases[csrow];
  		csmask          = pvt->csels[dct].csmasks[csrow >> 1];
10ef6b0df   Chen, Gong   bitops: Introduce...
399
400
  		*base  = (csbase & GENMASK_ULL(15,  5)) << 6;
  		*base |= (csbase & GENMASK_ULL(30, 19)) << 8;
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
401
402
403
  
  		*mask = ~0ULL;
  		/* poke holes for the csmask */
10ef6b0df   Chen, Gong   bitops: Introduce...
404
405
  		*mask &= ~((GENMASK_ULL(15, 5)  << 6) |
  			   (GENMASK_ULL(30, 19) << 8));
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
406

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

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

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

11c75eada   Borislav Petkov   amd64_edac: Clean...
426
427
428
429
430
  	*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...
431
  }
11c75eada   Borislav Petkov   amd64_edac: Clean...
432
433
  #define for_each_chip_select(i, dct, pvt) \
  	for (i = 0; i < pvt->csels[dct].b_cnt; i++)
614ec9d85   Borislav Petkov   amd64_edac: Revam...
434
435
  #define chip_select_base(i, dct, pvt) \
  	pvt->csels[dct].csbases[i]
11c75eada   Borislav Petkov   amd64_edac: Clean...
436
437
  #define for_each_chip_select_mask(i, dct, pvt) \
  	for (i = 0; i < pvt->csels[dct].m_cnt; i++)
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

d27f3a348   Yazen Ghannam   EDAC, amd64: Dete...
713
714
715
  		for (i = 0; i < NUM_UMCS; i++) {
  			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
  }
07ed82ef9   Yazen Ghannam   EDAC, amd64: Add ...
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
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
  static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl)
  {
  	u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases;
  	int dimm, size0, size1;
  
  	edac_printk(KERN_DEBUG, EDAC_MC, "UMC%d chip selects:
  ", ctrl);
  
  	for (dimm = 0; dimm < 4; dimm++) {
  		size0 = 0;
  
  		if (dcsb[dimm*2] & DCSB_CS_ENABLE)
  			size0 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, dimm);
  
  		size1 = 0;
  		if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE)
  			size1 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, dimm);
  
  		amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB
  ",
  				dimm * 2,     size0,
  				dimm * 2 + 1, size1);
  	}
  }
  
  static void __dump_misc_regs_df(struct amd64_pvt *pvt)
  {
  	struct amd64_umc *umc;
  	u32 i, tmp, umc_base;
  
  	for (i = 0; i < NUM_UMCS; i++) {
  		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...
856
  /* Display and decode various NB registers for debug purposes. */
07ed82ef9   Yazen Ghannam   EDAC, amd64: Add ...
857
  static void __dump_misc_regs(struct amd64_pvt *pvt)
2da11654e   Doug Thompson   amd64_edac: add h...
858
  {
956b9ba15   Joe Perches   edac: Convert deb...
859
860
  	edac_dbg(1, "F3xE8 (NB Cap): 0x%08x
  ", pvt->nbcap);
68798e176   Borislav Petkov   amd64_edac: clean...
861

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

956b9ba15   Joe Perches   edac: Convert deb...
866
867
868
869
  	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...
870

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

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

956b9ba15   Joe Perches   edac: Convert deb...
876
877
878
  	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...
879
880
  		 (pvt->fam == 0xf) ? k8_dhar_offset(pvt)
  				   : f10_dhar_offset(pvt));
2da11654e   Doug Thompson   amd64_edac: add h...
881

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

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

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

8de1d91e6   Borislav Petkov   amd64_edac: clean...
890
  	/* Only if NOT ganged does dclr1 have valid info */
68798e176   Borislav Petkov   amd64_edac: clean...
891
  	if (!dct_ganging_enabled(pvt))
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
892
  		debug_dump_dramcfg_low(pvt, pvt->dclr1, 1);
2da11654e   Doug Thompson   amd64_edac: add h...
893
  }
07ed82ef9   Yazen Ghannam   EDAC, amd64: Add ...
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
  /* 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");
  
  	amd64_info("using %s syndromes.
  ",
  			((pvt->ecc_sym_sz == 8) ? "x8" : "x4"));
  }
94be4bff2   Doug Thompson   amd64_edac: assig...
909
  /*
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
910
   * See BKDG, F2x[1,0][5C:40], F2[1,0][6C:60]
94be4bff2   Doug Thompson   amd64_edac: assig...
911
   */
11c75eada   Borislav Petkov   amd64_edac: Clean...
912
  static void prep_chip_selects(struct amd64_pvt *pvt)
94be4bff2   Doug Thompson   amd64_edac: assig...
913
  {
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
914
  	if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) {
11c75eada   Borislav Petkov   amd64_edac: Clean...
915
916
  		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...
917
  	} else if (pvt->fam == 0x15 && pvt->model == 0x30) {
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
918
919
  		pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4;
  		pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2;
9d858bb10   Borislav Petkov   amd64_edac: fix c...
920
  	} else {
11c75eada   Borislav Petkov   amd64_edac: Clean...
921
922
  		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...
923
924
925
926
  	}
  }
  
  /*
11c75eada   Borislav Petkov   amd64_edac: Clean...
927
   * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers
94be4bff2   Doug Thompson   amd64_edac: assig...
928
   */
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
929
  static void read_dct_base_mask(struct amd64_pvt *pvt)
94be4bff2   Doug Thompson   amd64_edac: assig...
930
  {
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
931
  	int base_reg0, base_reg1, mask_reg0, mask_reg1, cs;
94be4bff2   Doug Thompson   amd64_edac: assig...
932

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

b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
935
936
937
938
939
940
941
942
943
944
945
  	if (pvt->umc) {
  		base_reg0 = get_umc_base(0) + UMCCH_BASE_ADDR;
  		base_reg1 = get_umc_base(1) + UMCCH_BASE_ADDR;
  		mask_reg0 = get_umc_base(0) + UMCCH_ADDR_MASK;
  		mask_reg1 = get_umc_base(1) + UMCCH_ADDR_MASK;
  	} else {
  		base_reg0 = DCSB0;
  		base_reg1 = DCSB1;
  		mask_reg0 = DCSM0;
  		mask_reg1 = DCSM1;
  	}
11c75eada   Borislav Petkov   amd64_edac: Clean...
946
  	for_each_chip_select(cs, 0, pvt) {
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
947
948
  		int reg0   = base_reg0 + (cs * 4);
  		int reg1   = base_reg1 + (cs * 4);
11c75eada   Borislav Petkov   amd64_edac: Clean...
949
950
  		u32 *base0 = &pvt->csels[0].csbases[cs];
  		u32 *base1 = &pvt->csels[1].csbases[cs];
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
951

b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
  		if (pvt->umc) {
  			if (!amd_smn_read(pvt->mc_node_id, reg0, base0))
  				edac_dbg(0, "  DCSB0[%d]=0x%08x reg: 0x%x
  ",
  					 cs, *base0, reg0);
  
  			if (!amd_smn_read(pvt->mc_node_id, reg1, base1))
  				edac_dbg(0, "  DCSB1[%d]=0x%08x reg: 0x%x
  ",
  					 cs, *base1, reg1);
  		} else {
  			if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, base0))
  				edac_dbg(0, "  DCSB0[%d]=0x%08x reg: F2x%x
  ",
  					 cs, *base0, reg0);
  
  			if (pvt->fam == 0xf)
  				continue;
  
  			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
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
975
  								: reg0);
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
976
  		}
94be4bff2   Doug Thompson   amd64_edac: assig...
977
  	}
11c75eada   Borislav Petkov   amd64_edac: Clean...
978
  	for_each_chip_select_mask(cs, 0, pvt) {
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
979
980
  		int reg0   = mask_reg0 + (cs * 4);
  		int reg1   = mask_reg1 + (cs * 4);
11c75eada   Borislav Petkov   amd64_edac: Clean...
981
982
  		u32 *mask0 = &pvt->csels[0].csmasks[cs];
  		u32 *mask1 = &pvt->csels[1].csmasks[cs];
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
983

b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
  		if (pvt->umc) {
  			if (!amd_smn_read(pvt->mc_node_id, reg0, mask0))
  				edac_dbg(0, "    DCSM0[%d]=0x%08x reg: 0x%x
  ",
  					 cs, *mask0, reg0);
  
  			if (!amd_smn_read(pvt->mc_node_id, reg1, mask1))
  				edac_dbg(0, "    DCSM1[%d]=0x%08x reg: 0x%x
  ",
  					 cs, *mask1, reg1);
  		} else {
  			if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, mask0))
  				edac_dbg(0, "    DCSM0[%d]=0x%08x reg: F2x%x
  ",
  					 cs, *mask0, reg0);
  
  			if (pvt->fam == 0xf)
  				continue;
  
  			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
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
1007
  								: reg0);
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
1008
  		}
94be4bff2   Doug Thompson   amd64_edac: assig...
1009
1010
  	}
  }
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1011
  static void determine_memory_type(struct amd64_pvt *pvt)
94be4bff2   Doug Thompson   amd64_edac: assig...
1012
  {
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1013
  	u32 dram_ctrl, dcsm;
94be4bff2   Doug Thompson   amd64_edac: assig...
1014

a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1015
1016
1017
1018
1019
1020
1021
1022
1023
  	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...
1024
  		if (pvt->dchr0 & DDR3_MODE)
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
  			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...
1052
  		else
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1053
  			pvt->dram_type = MEM_RDDR3;
94be4bff2   Doug Thompson   amd64_edac: assig...
1054

a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1055
1056
1057
1058
  		return;
  
  	case 0x16:
  		goto ddr3;
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
1059
1060
1061
1062
1063
1064
1065
1066
  	case 0x17:
  		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
  	default:
  		WARN(1, KERN_ERR "%s: Family??? 0x%x
  ", __func__, pvt->fam);
  		pvt->dram_type = MEM_EMPTY;
  	}
  	return;
94be4bff2   Doug Thompson   amd64_edac: assig...
1073

a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1074
1075
  ddr3:
  	pvt->dram_type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3;
94be4bff2   Doug Thompson   amd64_edac: assig...
1076
  }
cb3285074   Borislav Petkov   amd64_edac: Clean...
1077
  /* Get the number of DCT channels the memory controller is using. */
ddff876d2   Doug Thompson   amd64_edac: add k...
1078
1079
  static int k8_early_channel_count(struct amd64_pvt *pvt)
  {
cb3285074   Borislav Petkov   amd64_edac: Clean...
1080
  	int flag;
ddff876d2   Doug Thompson   amd64_edac: add k...
1081

9f56da0e3   Borislav Petkov   amd64_edac: Use c...
1082
  	if (pvt->ext_model >= K8_REV_F)
ddff876d2   Doug Thompson   amd64_edac: add k...
1083
  		/* RevF (NPT) and later */
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1084
  		flag = pvt->dclr0 & WIDTH_128;
9f56da0e3   Borislav Petkov   amd64_edac: Use c...
1085
  	else
ddff876d2   Doug Thompson   amd64_edac: add k...
1086
1087
  		/* RevE and earlier */
  		flag = pvt->dclr0 & REVE_WIDTH_128;
ddff876d2   Doug Thompson   amd64_edac: add k...
1088
1089
1090
1091
1092
1093
  
  	/* not used */
  	pvt->dclr1 = 0;
  
  	return (flag) ? 2 : 1;
  }
700466249   Borislav Petkov   amd64_edac: Unify...
1094
  /* On F10h and later ErrAddr is MC4_ADDR[47:1] */
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
1095
  static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m)
ddff876d2   Doug Thompson   amd64_edac: add k...
1096
  {
2ec591ac7   Borislav Petkov   EDAC, amd64_edac:...
1097
1098
  	u16 mce_nid = amd_get_nb_id(m->extcpu);
  	struct mem_ctl_info *mci;
700466249   Borislav Petkov   amd64_edac: Unify...
1099
1100
  	u8 start_bit = 1;
  	u8 end_bit   = 47;
2ec591ac7   Borislav Petkov   EDAC, amd64_edac:...
1101
1102
1103
1104
1105
1106
1107
  	u64 addr;
  
  	mci = edac_mc_find(mce_nid);
  	if (!mci)
  		return 0;
  
  	pvt = mci->pvt_info;
700466249   Borislav Petkov   amd64_edac: Unify...
1108

a4b4bedce   Borislav Petkov   amd64_edac: Get r...
1109
  	if (pvt->fam == 0xf) {
700466249   Borislav Petkov   amd64_edac: Unify...
1110
1111
1112
  		start_bit = 3;
  		end_bit   = 39;
  	}
10ef6b0df   Chen, Gong   bitops: Introduce...
1113
  	addr = m->addr & GENMASK_ULL(end_bit, start_bit);
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1114
1115
1116
1117
  
  	/*
  	 * Erratum 637 workaround
  	 */
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
1118
  	if (pvt->fam == 0x15) {
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1119
1120
  		u64 cc6_base, tmp_addr;
  		u32 tmp;
8b84c8df3   Daniel J Blueman   x86, AMD, NB: Use...
1121
  		u8 intlv_en;
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1122

10ef6b0df   Chen, Gong   bitops: Introduce...
1123
  		if ((addr & GENMASK_ULL(47, 24)) >> 24 != 0x00fdf7)
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1124
  			return addr;
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1125
1126
1127
1128
1129
  
  		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...
1130
  		cc6_base  = (tmp & GENMASK_ULL(20, 0)) << 3;
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1131
1132
1133
1134
1135
1136
1137
1138
  
  		/* reverse and add DramIntlvEn */
  		cc6_base |= intlv_en ^ 0x7;
  
  		/* pin at [47:24] */
  		cc6_base <<= 24;
  
  		if (!intlv_en)
10ef6b0df   Chen, Gong   bitops: Introduce...
1139
  			return cc6_base | (addr & GENMASK_ULL(23, 0));
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1140
1141
1142
1143
  
  		amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_BASE, &tmp);
  
  							/* faster log2 */
10ef6b0df   Chen, Gong   bitops: Introduce...
1144
  		tmp_addr  = (addr & GENMASK_ULL(23, 12)) << __fls(intlv_en + 1);
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1145
1146
  
  		/* OR DramIntlvSel into bits [14:12] */
10ef6b0df   Chen, Gong   bitops: Introduce...
1147
  		tmp_addr |= (tmp & GENMASK_ULL(23, 21)) >> 9;
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1148
1149
  
  		/* add remaining [11:0] bits from original MC4_ADDR */
10ef6b0df   Chen, Gong   bitops: Introduce...
1150
  		tmp_addr |= addr & GENMASK_ULL(11, 0);
c1ae68309   Borislav Petkov   amd64_edac: Errat...
1151
1152
1153
1154
1155
  
  		return cc6_base | tmp_addr;
  	}
  
  	return addr;
ddff876d2   Doug Thompson   amd64_edac: add k...
1156
  }
e2c0bffea   Daniel J Blueman   amd64_edac: Fix P...
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
  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...
1172
  static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
ddff876d2   Doug Thompson   amd64_edac: add k...
1173
  {
e2c0bffea   Daniel J Blueman   amd64_edac: Fix P...
1174
  	struct amd_northbridge *nb;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1175
1176
  	struct pci_dev *f1 = NULL;
  	unsigned int pci_func;
71d2a32e8   Borislav Petkov   amd64_edac: Fix P...
1177
  	int off = range << 3;
e2c0bffea   Daniel J Blueman   amd64_edac: Fix P...
1178
  	u32 llim;
ddff876d2   Doug Thompson   amd64_edac: add k...
1179

7f19bf755   Borislav Petkov   amd64_edac: Remov...
1180
1181
  	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...
1182

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

7f19bf755   Borislav Petkov   amd64_edac: Remov...
1186
1187
  	if (!dram_rw(pvt, range))
  		return;
ddff876d2   Doug Thompson   amd64_edac: add k...
1188

7f19bf755   Borislav Petkov   amd64_edac: Remov...
1189
1190
  	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...
1191

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

e2c0bffea   Daniel J Blueman   amd64_edac: Fix P...
1196
1197
1198
  	nb = node_to_amd_nb(dram_dst_node(pvt, range));
  	if (WARN_ON(!nb))
  		return;
f08e457ce   Borislav Petkov   amd64_edac: Facto...
1199

a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1200
1201
1202
1203
1204
1205
  	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...
1206
1207
  
  	f1 = pci_get_related_function(nb->misc->vendor, pci_func, nb->misc);
e2c0bffea   Daniel J Blueman   amd64_edac: Fix P...
1208
1209
  	if (WARN_ON(!f1))
  		return;
f08e457ce   Borislav Petkov   amd64_edac: Facto...
1210

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

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

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

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

e2c0bffea   Daniel J Blueman   amd64_edac: Fix P...
1220
1221
1222
1223
  				    /* [47:40] */
  	pvt->ranges[range].lim.hi |= llim >> 13;
  
  	pci_dev_put(f1);
ddff876d2   Doug Thompson   amd64_edac: add k...
1224
  }
f192c7b16   Borislav Petkov   amd64_edac: Simpl...
1225
  static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1226
  				    struct err_info *err)
ddff876d2   Doug Thompson   amd64_edac: add k...
1227
  {
f192c7b16   Borislav Petkov   amd64_edac: Simpl...
1228
  	struct amd64_pvt *pvt = mci->pvt_info;
ddff876d2   Doug Thompson   amd64_edac: add k...
1229

33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1230
  	error_address_to_page_and_offset(sys_addr, err);
ab5a503cb   Mauro Carvalho Chehab   amd64_edac: conve...
1231
1232
1233
1234
1235
  
  	/*
  	 * 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...
1236
1237
  	err->src_mci = find_mc_by_sys_addr(mci, sys_addr);
  	if (!err->src_mci) {
ab5a503cb   Mauro Carvalho Chehab   amd64_edac: conve...
1238
1239
1240
  		amd64_mc_err(mci, "failed to map error addr 0x%lx to a node
  ",
  			     (unsigned long)sys_addr);
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1241
  		err->err_code = ERR_NODE;
ab5a503cb   Mauro Carvalho Chehab   amd64_edac: conve...
1242
1243
1244
1245
  		return;
  	}
  
  	/* Now map the sys_addr to a CSROW */
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1246
1247
1248
  	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...
1249
1250
  		return;
  	}
ddff876d2   Doug Thompson   amd64_edac: add k...
1251
  	/* CHIPKILL enabled */
f192c7b16   Borislav Petkov   amd64_edac: Simpl...
1252
  	if (pvt->nbcfg & NBCFG_CHIPKILL) {
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1253
1254
  		err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome);
  		if (err->channel < 0) {
ddff876d2   Doug Thompson   amd64_edac: add k...
1255
1256
1257
1258
1259
  			/*
  			 * 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...
1260
  			amd64_mc_warn(err->src_mci, "unknown syndrome 0x%04x - "
ab5a503cb   Mauro Carvalho Chehab   amd64_edac: conve...
1261
1262
  				      "possible error reporting race
  ",
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1263
1264
  				      err->syndrome);
  			err->err_code = ERR_CHANNEL;
ddff876d2   Doug Thompson   amd64_edac: add k...
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
  			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...
1276
  		err->channel = ((sys_addr & BIT(3)) != 0);
ddff876d2   Doug Thompson   amd64_edac: add k...
1277
  	}
ddff876d2   Doug Thompson   amd64_edac: add k...
1278
  }
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1279
  static int ddr2_cs_size(unsigned i, bool dct_width)
ddff876d2   Doug Thompson   amd64_edac: add k...
1280
  {
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1281
  	unsigned shift = 0;
ddff876d2   Doug Thompson   amd64_edac: add k...
1282

41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1283
1284
1285
1286
  	if (i <= 2)
  		shift = i;
  	else if (!(i & 0x1))
  		shift = i >> 1;
1433eb990   Borislav Petkov   amd64_edac: enhan...
1287
  	else
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1288
  		shift = (i + 1) >> 1;
ddff876d2   Doug Thompson   amd64_edac: add k...
1289

41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1290
1291
1292
1293
  	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...
1294
  				  unsigned cs_mode, int cs_mask_nr)
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1295
1296
1297
1298
1299
1300
1301
1302
  {
  	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...
1303
  		unsigned diff;
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1304
  		WARN_ON(cs_mode > 10);
11b0a3147   Borislav Petkov   amd64_edac: Fix K...
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
  		/*
  		 * 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...
1332
1333
1334
1335
1336
  	}
  	else {
  		WARN_ON(cs_mode > 6);
  		return 32 << cs_mode;
  	}
ddff876d2   Doug Thompson   amd64_edac: add k...
1337
  }
1afd3c98b   Doug Thompson   amd64_edac: add F...
1338
1339
1340
1341
1342
1343
1344
1345
  /*
   * 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...
1346
  static int f1x_early_channel_count(struct amd64_pvt *pvt)
1afd3c98b   Doug Thompson   amd64_edac: add F...
1347
  {
6ba5dcdc4   Borislav Petkov   amd64_edac: wrap-...
1348
  	int i, j, channels = 0;
1afd3c98b   Doug Thompson   amd64_edac: add F...
1349

7d20d14da   Borislav Petkov   amd64_edac: Adjus...
1350
  	/* On F10h, if we are in 128 bit mode, then we are using 2 channels */
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
1351
  	if (pvt->fam == 0x10 && (pvt->dclr0 & WIDTH_128))
7d20d14da   Borislav Petkov   amd64_edac: Adjus...
1352
  		return 2;
1afd3c98b   Doug Thompson   amd64_edac: add F...
1353
1354
  
  	/*
d16149e8c   Borislav Petkov   amd64_edac: clean...
1355
1356
1357
  	 * 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...
1358
1359
1360
1361
  	 *
  	 * 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...
1362
1363
  	edac_dbg(0, "Data width is not 128 bits - need more decoding
  ");
ddff876d2   Doug Thompson   amd64_edac: add k...
1364

1afd3c98b   Doug Thompson   amd64_edac: add F...
1365
1366
1367
1368
1369
  	/*
  	 * 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...
1370
1371
  	for (i = 0; i < 2; i++) {
  		u32 dbam = (i ? pvt->dbam1 : pvt->dbam0);
1afd3c98b   Doug Thompson   amd64_edac: add F...
1372

57a30854c   Wan Wei   amd64_edac: Rewri...
1373
1374
1375
1376
1377
1378
  		for (j = 0; j < 4; j++) {
  			if (DBAM_DIMM(j, dbam) > 0) {
  				channels++;
  				break;
  			}
  		}
1afd3c98b   Doug Thompson   amd64_edac: add F...
1379
  	}
d16149e8c   Borislav Petkov   amd64_edac: clean...
1380
1381
  	if (channels > 2)
  		channels = 2;
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
1382
1383
  	amd64_info("MCT channel count: %d
  ", channels);
1afd3c98b   Doug Thompson   amd64_edac: add F...
1384
1385
  
  	return channels;
1afd3c98b   Doug Thompson   amd64_edac: add F...
1386
  }
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
  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 */
  	for (i = 0; i < NUM_UMCS; i++)
  		channels += !!(pvt->umc[i].sdp_ctrl & UMC_SDP_INIT);
  
  	amd64_info("MCT channel count: %d
  ", channels);
  
  	return channels;
  }
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1400
  static int ddr3_cs_size(unsigned i, bool dct_width)
1afd3c98b   Doug Thompson   amd64_edac: add F...
1401
  {
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
  	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...
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
  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...
1455
  static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1456
  				   unsigned cs_mode, int cs_mask_nr)
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1457
1458
1459
1460
  {
  	u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
  
  	WARN_ON(cs_mode > 11);
1433eb990   Borislav Petkov   amd64_edac: enhan...
1461
1462
  
  	if (pvt->dchr0 & DDR3_MODE || pvt->dchr1 & DDR3_MODE)
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1463
  		return ddr3_cs_size(cs_mode, dclr & WIDTH_128);
1433eb990   Borislav Petkov   amd64_edac: enhan...
1464
  	else
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1465
1466
1467
1468
1469
1470
1471
  		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...
1472
  				   unsigned cs_mode, int cs_mask_nr)
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1473
1474
  {
  	WARN_ON(cs_mode > 12);
1433eb990   Borislav Petkov   amd64_edac: enhan...
1475

41d8bfaba   Borislav Petkov   amd64_edac: Impro...
1476
  	return ddr3_cs_size(cs_mode, false);
1afd3c98b   Doug Thompson   amd64_edac: add F...
1477
  }
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
  /* 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...
1508
  /*
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1509
   * F16h and F15h model 30h have only limited cs_modes.
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
1510
1511
   */
  static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
1512
  				unsigned cs_mode, int cs_mask_nr)
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
1513
1514
1515
1516
1517
1518
1519
1520
1521
  {
  	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);
  }
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
  static int f17_base_addr_to_cs_size(struct amd64_pvt *pvt, u8 umc,
  				    unsigned int cs_mode, int csrow_nr)
  {
  	u32 base_addr = pvt->csels[umc].csbases[csrow_nr];
  
  	/*  Each mask is used for every two base addresses. */
  	u32 addr_mask = pvt->csels[umc].csmasks[csrow_nr >> 1];
  
  	/*  Register [31:1] = Address [39:9]. Size is in kBs here. */
  	u32 size = ((addr_mask >> 1) - (base_addr >> 1) + 1) >> 1;
  
  	edac_dbg(1, "BaseAddr: 0x%x, AddrMask: 0x%x
  ", base_addr, addr_mask);
  
  	/* Return size in MBs. */
  	return size >> 10;
  }
5a5d23716   Borislav Petkov   amd64_edac: Sanit...
1539
  static void read_dram_ctl_register(struct amd64_pvt *pvt)
6163b5d4f   Doug Thompson   amd64_edac: add F...
1540
  {
6163b5d4f   Doug Thompson   amd64_edac: add F...
1541

a4b4bedce   Borislav Petkov   amd64_edac: Get r...
1542
  	if (pvt->fam == 0xf)
5a5d23716   Borislav Petkov   amd64_edac: Sanit...
1543
  		return;
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
1544
  	if (!amd64_read_pci_cfg(pvt->F2, DCT_SEL_LO, &pvt->dct_sel_lo)) {
956b9ba15   Joe Perches   edac: Convert deb...
1545
1546
1547
  		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...
1548

956b9ba15   Joe Perches   edac: Convert deb...
1549
1550
1551
  		edac_dbg(0, "  DCTs operate in %s mode
  ",
  			 (dct_ganging_enabled(pvt) ? "ganged" : "unganged"));
72381bd55   Borislav Petkov   amd64_edac: clari...
1552
1553
  
  		if (!dct_ganging_enabled(pvt))
956b9ba15   Joe Perches   edac: Convert deb...
1554
1555
1556
  			edac_dbg(0, "  Address range split per DCT: %s
  ",
  				 (dct_high_range_enabled(pvt) ? "yes" : "no"));
72381bd55   Borislav Petkov   amd64_edac: clari...
1557

956b9ba15   Joe Perches   edac: Convert deb...
1558
1559
1560
1561
  		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...
1562

956b9ba15   Joe Perches   edac: Convert deb...
1563
1564
1565
1566
1567
  		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...
1568
  	}
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
1569
  	amd64_read_pci_cfg(pvt->F2, DCT_SEL_HI, &pvt->dct_sel_hi);
6163b5d4f   Doug Thompson   amd64_edac: add F...
1570
  }
f71d0a050   Doug Thompson   amd64_edac: add F...
1571
  /*
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
   * 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...
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
  	} 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...
1599
1600
1601
1602
  	return channel;
  }
  
  /*
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1603
   * Determine channel (DCT) based on the interleaving mode: F10h BKDG, 2.8.9 Memory
f71d0a050   Doug Thompson   amd64_edac: add F...
1604
1605
   * Interleaving Modes.
   */
b15f0fcab   Borislav Petkov   amd64_edac: Adjus...
1606
  static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1607
  				bool hi_range_sel, u8 intlv_en)
6163b5d4f   Doug Thompson   amd64_edac: add F...
1608
  {
151fa71c5   Borislav Petkov   amd64_edac: Fix D...
1609
  	u8 dct_sel_high = (pvt->dct_sel_lo >> 1) & 1;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1610
1611
  
  	if (dct_ganging_enabled(pvt))
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1612
  		return 0;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1613

229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1614
1615
  	if (hi_range_sel)
  		return dct_sel_high;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1616

229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
  	/*
  	 * 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 ...
1629
  			u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) & 1;
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1630
1631
1632
  
  			return ((sys_addr >> shift) & 1) ^ temp;
  		}
dc0a50a84   Yazen Ghannam   EDAC, amd64: Fix ...
1633
1634
1635
1636
1637
  		if (intlv_addr & 0x4) {
  			u8 shift = intlv_addr & 0x1 ? 9 : 8;
  
  			return (sys_addr >> shift) & 1;
  		}
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1638
1639
1640
1641
1642
  		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...
1643
1644
1645
  
  	return 0;
  }
c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1646
  /* Convert the sys_addr to the normalized DCT address */
c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
1647
  static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range,
c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1648
1649
  				 u64 sys_addr, bool hi_rng,
  				 u32 dct_sel_base_addr)
6163b5d4f   Doug Thompson   amd64_edac: add F...
1650
1651
  {
  	u64 chan_off;
c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1652
1653
  	u64 dram_base		= get_dram_base(pvt, range);
  	u64 hole_off		= f10_dhar_offset(pvt);
6f3508f61   Dan Carpenter   EDAC, amd64_edac:...
1654
  	u64 dct_sel_base_off	= (u64)(pvt->dct_sel_hi & 0xFFFFFC00) << 16;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1655

c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
  	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 ...
1670
  		    dhar_valid(pvt) &&
c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1671
  		    (sys_addr >= BIT_64(32)))
bc21fa578   Borislav Petkov   amd64_edac: Clean...
1672
  			chan_off = hole_off;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1673
1674
1675
  		else
  			chan_off = dct_sel_base_off;
  	} else {
c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1676
1677
1678
1679
1680
1681
1682
1683
1684
  		/*
  		 * 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 ...
1685
  		if (dhar_valid(pvt) && (sys_addr >= BIT_64(32)))
bc21fa578   Borislav Petkov   amd64_edac: Clean...
1686
  			chan_off = hole_off;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1687
  		else
c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1688
  			chan_off = dram_base;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1689
  	}
10ef6b0df   Chen, Gong   bitops: Introduce...
1690
  	return (sys_addr & GENMASK_ULL(47,6)) - (chan_off & GENMASK_ULL(47,23));
6163b5d4f   Doug Thompson   amd64_edac: add F...
1691
  }
6163b5d4f   Doug Thompson   amd64_edac: add F...
1692
1693
1694
1695
  /*
   * checks if the csrow passed in is marked as SPARED, if so returns the new
   * spare row
   */
11c75eada   Borislav Petkov   amd64_edac: Clean...
1696
  static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow)
6163b5d4f   Doug Thompson   amd64_edac: add F...
1697
  {
614ec9d85   Borislav Petkov   amd64_edac: Revam...
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
  	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...
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
  	}
  	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...
1721
  static int f1x_lookup_addr_in_dct(u64 in_addr, u8 nid, u8 dct)
6163b5d4f   Doug Thompson   amd64_edac: add F...
1722
1723
1724
  {
  	struct mem_ctl_info *mci;
  	struct amd64_pvt *pvt;
11c75eada   Borislav Petkov   amd64_edac: Clean...
1725
  	u64 cs_base, cs_mask;
6163b5d4f   Doug Thompson   amd64_edac: add F...
1726
1727
  	int cs_found = -EINVAL;
  	int csrow;
2ec591ac7   Borislav Petkov   EDAC, amd64_edac:...
1728
  	mci = edac_mc_find(nid);
6163b5d4f   Doug Thompson   amd64_edac: add F...
1729
1730
1731
1732
  	if (!mci)
  		return cs_found;
  
  	pvt = mci->pvt_info;
956b9ba15   Joe Perches   edac: Convert deb...
1733
1734
  	edac_dbg(1, "input addr: 0x%llx, DCT: %d
  ", in_addr, dct);
6163b5d4f   Doug Thompson   amd64_edac: add F...
1735

11c75eada   Borislav Petkov   amd64_edac: Clean...
1736
1737
  	for_each_chip_select(csrow, dct, pvt) {
  		if (!csrow_enabled(csrow, dct, pvt))
6163b5d4f   Doug Thompson   amd64_edac: add F...
1738
  			continue;
11c75eada   Borislav Petkov   amd64_edac: Clean...
1739
  		get_cs_base_and_mask(pvt, csrow, dct, &cs_base, &cs_mask);
6163b5d4f   Doug Thompson   amd64_edac: add F...
1740

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

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

956b9ba15   Joe Perches   edac: Convert deb...
1747
1748
1749
  		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...
1750

11c75eada   Borislav Petkov   amd64_edac: Clean...
1751
  		if ((in_addr & cs_mask) == (cs_base & cs_mask)) {
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1752
1753
1754
1755
  			if (pvt->fam == 0x15 && pvt->model >= 0x30) {
  				cs_found =  csrow;
  				break;
  			}
11c75eada   Borislav Petkov   amd64_edac: Clean...
1756
  			cs_found = f10_process_possible_spare(pvt, dct, csrow);
6163b5d4f   Doug Thompson   amd64_edac: add F...
1757

956b9ba15   Joe Perches   edac: Convert deb...
1758
1759
  			edac_dbg(1, " MATCH csrow=%d
  ", cs_found);
6163b5d4f   Doug Thompson   amd64_edac: add F...
1760
1761
1762
1763
1764
  			break;
  		}
  	}
  	return cs_found;
  }
95b0ef55c   Borislav Petkov   amd64_edac: Add s...
1765
1766
1767
1768
1769
  /*
   * 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...
1770
  static u64 f1x_swap_interleaved_region(struct amd64_pvt *pvt, u64 sys_addr)
95b0ef55c   Borislav Petkov   amd64_edac: Add s...
1771
1772
  {
  	u32 swap_reg, swap_base, swap_limit, rgn_size, tmp_addr;
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
1773
  	if (pvt->fam == 0x10) {
95b0ef55c   Borislav Petkov   amd64_edac: Add s...
1774
  		/* only revC3 and revE have that feature */
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
1775
  		if (pvt->model < 4 || (pvt->model < 0xa && pvt->stepping < 3))
95b0ef55c   Borislav Petkov   amd64_edac: Add s...
1776
1777
  			return sys_addr;
  	}
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
1778
  	amd64_read_pci_cfg(pvt->F2, SWAP_INTLV_REG, &swap_reg);
95b0ef55c   Borislav Petkov   amd64_edac: Add s...
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
  
  	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...
1796
  /* For a given @dram_range, check if @sys_addr falls within it. */
e761359a2   Borislav Petkov   amd64_edac: Fix r...
1797
  static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
1798
  				  u64 sys_addr, int *chan_sel)
f71d0a050   Doug Thompson   amd64_edac: add F...
1799
  {
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1800
  	int cs_found = -EINVAL;
c8e518d56   Borislav Petkov   amd64_edac: Sanit...
1801
  	u64 chan_addr;
5d4b58e84   Borislav Petkov   amd64_edac: Fix c...
1802
  	u32 dct_sel_base;
11c75eada   Borislav Petkov   amd64_edac: Clean...
1803
  	u8 channel;
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1804
  	bool high_range = false;
f71d0a050   Doug Thompson   amd64_edac: add F...
1805

7f19bf755   Borislav Petkov   amd64_edac: Remov...
1806
  	u8 node_id    = dram_dst_node(pvt, range);
229a7a11a   Borislav Petkov   amd64_edac: Sanit...
1807
  	u8 intlv_en   = dram_intlv_en(pvt, range);
7f19bf755   Borislav Petkov   amd64_edac: Remov...
1808
  	u32 intlv_sel = dram_intlv_sel(pvt, range);
f71d0a050   Doug Thompson   amd64_edac: add F...
1809

956b9ba15   Joe Perches   edac: Convert deb...
1810
1811
1812
  	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...
1813

355fba600   Borislav Petkov   amd64_edac: Beef ...
1814
1815
1816
1817
1818
1819
1820
1821
  	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...
1822
  	if (intlv_en && (intlv_sel != ((sys_addr >> 12) & intlv_en)))
f71d0a050   Doug Thompson   amd64_edac: add F...
1823
  		return -EINVAL;
b15f0fcab   Borislav Petkov   amd64_edac: Adjus...
1824
  	sys_addr = f1x_swap_interleaved_region(pvt, sys_addr);
95b0ef55c   Borislav Petkov   amd64_edac: Add s...
1825

f71d0a050   Doug Thompson   amd64_edac: add F...
1826
1827
1828
1829
1830
1831
1832
1833
1834
  	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...
1835
  		high_range = true;
f71d0a050   Doug Thompson   amd64_edac: add F...
1836

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

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

e2f79dbdf   Borislav Petkov   amd64_edac: Corre...
1842
1843
1844
1845
  	/* 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...
1846

5d4b58e84   Borislav Petkov   amd64_edac: Fix c...
1847
  	/* remove channel interleave */
f71d0a050   Doug Thompson   amd64_edac: add F...
1848
1849
1850
  	if (dct_interleave_enabled(pvt) &&
  	   !dct_high_range_enabled(pvt) &&
  	   !dct_ganging_enabled(pvt)) {
5d4b58e84   Borislav Petkov   amd64_edac: Fix c...
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
  
  		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...
1865
  	}
956b9ba15   Joe Perches   edac: Convert deb...
1866
1867
  	edac_dbg(1, "   Normalized DCT addr: 0x%llx
  ", chan_addr);
f71d0a050   Doug Thompson   amd64_edac: add F...
1868

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

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

f71d0a050   Doug Thompson   amd64_edac: add F...
1874
1875
  	return cs_found;
  }
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
  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...
1915
1916
  	dct_base = (u64) dct_sel_baseaddr(pvt);
  	dct_limit = (dct_cont_limit_reg >> 11) & 0x1FFF;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1917
1918
  
  	if (!(dct_cont_base_reg & BIT(0)) &&
4fc06b317   Aravind Gopalakrishnan   amd64_edac: Fix i...
1919
1920
  	    !(dct_base <= (sys_addr >> 27) &&
  	      dct_limit >= (sys_addr >> 27)))
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1921
1922
1923
1924
1925
1926
1927
  		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 ...
1928
1929
1930
1931
1932
  	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...
1933
1934
  
  	/* Verify we stay within the MAX number of channels allowed */
7f3f5240c   Aravind Gopalakrishnan   amd64_edac: Fix c...
1935
  	if (channel > 3)
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1936
1937
1938
1939
1940
1941
1942
1943
  		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...
1944
  		chan_offset = dct_base << 27;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
  
  	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...
1974
  		chan_addr +=  (u64) ((tmp >> 11) & 0xfff) << 27;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
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
2001
2002
  	}
  
  	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...
2003
  {
e761359a2   Borislav Petkov   amd64_edac: Fix r...
2004
2005
  	int cs_found = -EINVAL;
  	unsigned range;
f71d0a050   Doug Thompson   amd64_edac: add F...
2006

7f19bf755   Borislav Petkov   amd64_edac: Remov...
2007
  	for (range = 0; range < DRAM_RANGES; range++) {
7f19bf755   Borislav Petkov   amd64_edac: Remov...
2008
  		if (!dram_rw(pvt, range))
f71d0a050   Doug Thompson   amd64_edac: add F...
2009
  			continue;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
2010
2011
2012
2013
  		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...
2014

18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
2015
2016
  		else if ((get_dram_base(pvt, range)  <= sys_addr) &&
  			 (get_dram_limit(pvt, range) >= sys_addr)) {
b15f0fcab   Borislav Petkov   amd64_edac: Adjus...
2017
  			cs_found = f1x_match_to_this_node(pvt, range,
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2018
  							  sys_addr, chan_sel);
f71d0a050   Doug Thompson   amd64_edac: add F...
2019
2020
2021
2022
2023
2024
2025
2026
  			if (cs_found >= 0)
  				break;
  		}
  	}
  	return cs_found;
  }
  
  /*
bdc30a0c8   Borislav Petkov   amd64_edac: corre...
2027
2028
   * 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...
2029
   *
bdc30a0c8   Borislav Petkov   amd64_edac: corre...
2030
2031
   * The @sys_addr is usually an error address received from the hardware
   * (MCX_ADDR).
f71d0a050   Doug Thompson   amd64_edac: add F...
2032
   */
b15f0fcab   Borislav Petkov   amd64_edac: Adjus...
2033
  static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2034
  				     struct err_info *err)
f71d0a050   Doug Thompson   amd64_edac: add F...
2035
2036
  {
  	struct amd64_pvt *pvt = mci->pvt_info;
f71d0a050   Doug Thompson   amd64_edac: add F...
2037

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

33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2040
2041
2042
  	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...
2043
2044
  		return;
  	}
bdc30a0c8   Borislav Petkov   amd64_edac: corre...
2045
2046
2047
2048
2049
  	/*
  	 * 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...
2050
  	if (dct_ganging_enabled(pvt))
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2051
  		err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome);
f71d0a050   Doug Thompson   amd64_edac: add F...
2052
2053
2054
  }
  
  /*
8566c4df1   Borislav Petkov   amd64_edac: dump ...
2055
   * debug routine to display the memory sizes of all logical DIMMs and its
cb3285074   Borislav Petkov   amd64_edac: Clean...
2056
   * CSROWs
f71d0a050   Doug Thompson   amd64_edac: add F...
2057
   */
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
2058
  static void debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
f71d0a050   Doug Thompson   amd64_edac: add F...
2059
  {
bb89f5a05   Borislav Petkov   amd64_edac: Fix K...
2060
  	int dimm, size0, size1;
525a1b20a   Borislav Petkov   amd64_edac: Clean...
2061
2062
  	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...
2063

a4b4bedce   Borislav Petkov   amd64_edac: Get r...
2064
  	if (pvt->fam == 0xf) {
8566c4df1   Borislav Petkov   amd64_edac: dump ...
2065
  		/* K8 families < revF not supported yet */
1433eb990   Borislav Petkov   amd64_edac: enhan...
2066
  	       if (pvt->ext_model < K8_REV_F)
8566c4df1   Borislav Petkov   amd64_edac: dump ...
2067
2068
2069
2070
  			return;
  	       else
  		       WARN_ON(ctrl != 0);
  	}
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
  	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...
2081
2082
2083
  	edac_dbg(1, "F2x%d80 (DRAM Bank Address Mapping): 0x%08x
  ",
  		 ctrl, dbam);
f71d0a050   Doug Thompson   amd64_edac: add F...
2084

8566c4df1   Borislav Petkov   amd64_edac: dump ...
2085
2086
  	edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:
  ", ctrl);
f71d0a050   Doug Thompson   amd64_edac: add F...
2087
2088
2089
2090
  	/* Dump memory sizes for DIMM and its CSROWs */
  	for (dimm = 0; dimm < 4; dimm++) {
  
  		size0 = 0;
11c75eada   Borislav Petkov   amd64_edac: Clean...
2091
  		if (dcsb[dimm*2] & DCSB_CS_ENABLE)
07ed82ef9   Yazen Ghannam   EDAC, amd64: Add ...
2092
2093
2094
  			/*
  			 * 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...
2095
2096
2097
  			 * mapper so we can find the multiplier from the
  			 * corresponding DCSM.
  			 */
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
2098
  			size0 = pvt->ops->dbam_to_cs(pvt, ctrl,
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
2099
2100
  						     DBAM_DIMM(dimm, dbam),
  						     dimm);
f71d0a050   Doug Thompson   amd64_edac: add F...
2101
2102
  
  		size1 = 0;
11c75eada   Borislav Petkov   amd64_edac: Clean...
2103
  		if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE)
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
2104
  			size1 = pvt->ops->dbam_to_cs(pvt, ctrl,
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
2105
2106
  						     DBAM_DIMM(dimm, dbam),
  						     dimm);
f71d0a050   Doug Thompson   amd64_edac: add F...
2107

24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
2108
2109
  		amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB
  ",
bb89f5a05   Borislav Petkov   amd64_edac: Fix K...
2110
2111
  				dimm * 2,     size0,
  				dimm * 2 + 1, size1);
f71d0a050   Doug Thompson   amd64_edac: add F...
2112
2113
  	}
  }
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
2114
  static struct amd64_family_type family_types[] = {
4d37607ad   Doug Thompson   amd64_edac: add p...
2115
  	[K8_CPUS] = {
0092b20d4   Borislav Petkov   amd64_edac: Simpl...
2116
  		.ctl_name = "K8",
8d5b5d9c7   Borislav Petkov   amd64_edac: Renam...
2117
  		.f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP,
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2118
  		.f2_id = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL,
4d37607ad   Doug Thompson   amd64_edac: add p...
2119
  		.ops = {
1433eb990   Borislav Petkov   amd64_edac: enhan...
2120
  			.early_channel_count	= k8_early_channel_count,
1433eb990   Borislav Petkov   amd64_edac: enhan...
2121
2122
  			.map_sysaddr_to_csrow	= k8_map_sysaddr_to_csrow,
  			.dbam_to_cs		= k8_dbam_to_chip_select,
4d37607ad   Doug Thompson   amd64_edac: add p...
2123
2124
2125
  		}
  	},
  	[F10_CPUS] = {
0092b20d4   Borislav Petkov   amd64_edac: Simpl...
2126
  		.ctl_name = "F10h",
8d5b5d9c7   Borislav Petkov   amd64_edac: Renam...
2127
  		.f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP,
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2128
  		.f2_id = PCI_DEVICE_ID_AMD_10H_NB_DRAM,
4d37607ad   Doug Thompson   amd64_edac: add p...
2129
  		.ops = {
7d20d14da   Borislav Petkov   amd64_edac: Adjus...
2130
  			.early_channel_count	= f1x_early_channel_count,
b15f0fcab   Borislav Petkov   amd64_edac: Adjus...
2131
  			.map_sysaddr_to_csrow	= f1x_map_sysaddr_to_csrow,
1433eb990   Borislav Petkov   amd64_edac: enhan...
2132
  			.dbam_to_cs		= f10_dbam_to_chip_select,
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
2133
2134
2135
2136
  		}
  	},
  	[F15_CPUS] = {
  		.ctl_name = "F15h",
df71a0532   Borislav Petkov   amd64_edac: Enabl...
2137
  		.f1_id = PCI_DEVICE_ID_AMD_15H_NB_F1,
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2138
  		.f2_id = PCI_DEVICE_ID_AMD_15H_NB_F2,
b2b0c6054   Borislav Petkov   amd64_edac: Add s...
2139
  		.ops = {
7d20d14da   Borislav Petkov   amd64_edac: Adjus...
2140
  			.early_channel_count	= f1x_early_channel_count,
b15f0fcab   Borislav Petkov   amd64_edac: Adjus...
2141
  			.map_sysaddr_to_csrow	= f1x_map_sysaddr_to_csrow,
41d8bfaba   Borislav Petkov   amd64_edac: Impro...
2142
  			.dbam_to_cs		= f15_dbam_to_chip_select,
4d37607ad   Doug Thompson   amd64_edac: add p...
2143
2144
  		}
  	},
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
2145
2146
2147
  	[F15_M30H_CPUS] = {
  		.ctl_name = "F15h_M30h",
  		.f1_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1,
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2148
  		.f2_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F2,
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
2149
2150
2151
2152
  		.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...
2153
2154
  		}
  	},
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
2155
2156
2157
  	[F15_M60H_CPUS] = {
  		.ctl_name = "F15h_M60h",
  		.f1_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1,
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2158
  		.f2_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F2,
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
2159
2160
2161
2162
2163
2164
  		.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...
2165
2166
2167
  	[F16_CPUS] = {
  		.ctl_name = "F16h",
  		.f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1,
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2168
  		.f2_id = PCI_DEVICE_ID_AMD_16H_NB_F2,
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
2169
2170
2171
2172
  		.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...
2173
2174
  		}
  	},
85a8885bd   Aravind Gopalakrishnan   amd64_edac: Add s...
2175
2176
2177
  	[F16_M30H_CPUS] = {
  		.ctl_name = "F16h_M30h",
  		.f1_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F1,
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2178
  		.f2_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F2,
85a8885bd   Aravind Gopalakrishnan   amd64_edac: Add s...
2179
2180
2181
2182
  		.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...
2183
2184
  		}
  	},
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
2185
2186
2187
2188
2189
2190
2191
2192
2193
  	[F17_CPUS] = {
  		.ctl_name = "F17h",
  		.f0_id = PCI_DEVICE_ID_AMD_17H_DF_F0,
  		.f6_id = PCI_DEVICE_ID_AMD_17H_DF_F6,
  		.ops = {
  			.early_channel_count	= f17_early_channel_count,
  			.dbam_to_cs		= f17_base_addr_to_cs_size,
  		}
  	},
4d37607ad   Doug Thompson   amd64_edac: add p...
2194
  };
b1289d6f9   Doug Thompson   amd64_edac: add E...
2195
  /*
bfc04aec7   Borislav Petkov   amd64_edac: add a...
2196
2197
2198
   * 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...
2199
   *
bfc04aec7   Borislav Petkov   amd64_edac: add a...
2200
   * Algorithm courtesy of Ross LaFetra from AMD.
b1289d6f9   Doug Thompson   amd64_edac: add E...
2201
   */
c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
2202
  static const u16 x4_vectors[] = {
bfc04aec7   Borislav Petkov   amd64_edac: add a...
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
  	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...
2239
  };
c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
2240
  static const u16 x8_vectors[] = {
bfc04aec7   Borislav Petkov   amd64_edac: add a...
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
  	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...
2261
  static int decode_syndrome(u16 syndrome, const u16 *vectors, unsigned num_vecs,
d34a6ecd4   Borislav Petkov   amd64_edac: Fix d...
2262
  			   unsigned v_dim)
b1289d6f9   Doug Thompson   amd64_edac: add E...
2263
  {
bfc04aec7   Borislav Petkov   amd64_edac: add a...
2264
2265
2266
2267
  	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...
2268
2269
  		unsigned v_idx =  err_sym * v_dim;
  		unsigned v_end = (err_sym + 1) * v_dim;
bfc04aec7   Borislav Petkov   amd64_edac: add a...
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
  
  		/* 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...
2282

bfc04aec7   Borislav Petkov   amd64_edac: add a...
2283
2284
2285
  					if (!s)
  						return err_sym;
  				}
b1289d6f9   Doug Thompson   amd64_edac: add E...
2286

bfc04aec7   Borislav Petkov   amd64_edac: add a...
2287
2288
2289
2290
  			} else if (s & i)
  				/* can't get to zero, move to next symbol */
  				break;
  		}
b1289d6f9   Doug Thompson   amd64_edac: add E...
2291
  	}
956b9ba15   Joe Perches   edac: Convert deb...
2292
2293
  	edac_dbg(0, "syndrome(%x) not found
  ", syndrome);
b1289d6f9   Doug Thompson   amd64_edac: add E...
2294
2295
  	return -1;
  }
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2296

bfc04aec7   Borislav Petkov   amd64_edac: add a...
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
  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...
2340
  	int err_sym = -1;
a3b7db09a   Borislav Petkov   amd64_edac: Adjus...
2341
  	if (pvt->ecc_sym_sz == 8)
ad6a32e96   Borislav Petkov   amd64_edac: Sanit...
2342
2343
  		err_sym = decode_syndrome(syndrome, x8_vectors,
  					  ARRAY_SIZE(x8_vectors),
a3b7db09a   Borislav Petkov   amd64_edac: Adjus...
2344
2345
  					  pvt->ecc_sym_sz);
  	else if (pvt->ecc_sym_sz == 4)
ad6a32e96   Borislav Petkov   amd64_edac: Sanit...
2346
2347
  		err_sym = decode_syndrome(syndrome, x4_vectors,
  					  ARRAY_SIZE(x4_vectors),
a3b7db09a   Borislav Petkov   amd64_edac: Adjus...
2348
  					  pvt->ecc_sym_sz);
ad6a32e96   Borislav Petkov   amd64_edac: Sanit...
2349
  	else {
a3b7db09a   Borislav Petkov   amd64_edac: Adjus...
2350
2351
  		amd64_warn("Illegal syndrome type: %u
  ", pvt->ecc_sym_sz);
ad6a32e96   Borislav Petkov   amd64_edac: Sanit...
2352
  		return err_sym;
bfc04aec7   Borislav Petkov   amd64_edac: add a...
2353
  	}
ad6a32e96   Borislav Petkov   amd64_edac: Sanit...
2354

a3b7db09a   Borislav Petkov   amd64_edac: Adjus...
2355
  	return map_err_sym_to_channel(err_sym, pvt->ecc_sym_sz);
bfc04aec7   Borislav Petkov   amd64_edac: add a...
2356
  }
e70984d9e   Yazen Ghannam   EDAC, amd64: Rena...
2357
  static void __log_ecc_error(struct mem_ctl_info *mci, struct err_info *err,
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2358
  			    u8 ecc_type)
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2359
  {
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2360
2361
  	enum hw_event_mc_err_type err_type;
  	const char *string;
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2362

33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2363
2364
2365
2366
  	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 ...
2367
2368
  	else if (ecc_type == 3)
  		err_type = HW_EVENT_ERR_DEFERRED;
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2369
2370
2371
  	else {
  		WARN(1, "Something is rotten in the state of Denmark.
  ");
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2372
2373
  		return;
  	}
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
  	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...
2385
2386
2387
2388
2389
2390
2391
  		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...
2392
2393
2394
2395
  		break;
  	default:
  		string = "WTF error";
  		break;
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2396
  	}
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2397
2398
2399
2400
2401
  
  	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...
2402
  }
df781d038   Borislav Petkov   amd64_edac: Simpl...
2403
  static inline void decode_bus_error(int node_id, struct mce *m)
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2404
  {
0c510cc83   Daniel J Blueman   EDAC, amd64_edac:...
2405
2406
  	struct mem_ctl_info *mci;
  	struct amd64_pvt *pvt;
f192c7b16   Borislav Petkov   amd64_edac: Simpl...
2407
  	u8 ecc_type = (m->status >> 45) & 0x3;
66fed2d46   Borislav Petkov   amd64_edac: Impro...
2408
2409
  	u8 xec = XEC(m->status, 0x1f);
  	u16 ec = EC(m->status);
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2410
2411
  	u64 sys_addr;
  	struct err_info err;
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2412

0c510cc83   Daniel J Blueman   EDAC, amd64_edac:...
2413
2414
2415
2416
2417
  	mci = edac_mc_find(node_id);
  	if (!mci)
  		return;
  
  	pvt = mci->pvt_info;
66fed2d46   Borislav Petkov   amd64_edac: Impro...
2418
  	/* Bail out early if this was an 'observed' error */
5980bb9cd   Borislav Petkov   amd64_edac: Clean...
2419
  	if (PP(ec) == NBSL_PP_OBS)
b70ef0101   Borislav Petkov   EDAC: move MCE er...
2420
  		return;
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2421

ecaf5606d   Borislav Petkov   amd64_edac: clean...
2422
2423
  	/* Do only ECC errors */
  	if (xec && xec != F10_NBSL_EXT_ERR_ECC)
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2424
  		return;
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2425

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

ecaf5606d   Borislav Petkov   amd64_edac: clean...
2429
  	if (ecc_type == 2)
33ca0643c   Borislav Petkov   amd64_edac: Reorg...
2430
2431
2432
  		err.syndrome = extract_syndrome(m->status);
  
  	pvt->ops->map_sysaddr_to_csrow(mci, sys_addr, &err);
e70984d9e   Yazen Ghannam   EDAC, amd64: Rena...
2433
  	__log_ecc_error(mci, &err, ecc_type);
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2434
  }
0ec449ee9   Doug Thompson   amd64_edac: add E...
2435
  /*
713ad5467   Yazen Ghannam   EDAC, amd64: Defi...
2436
2437
2438
2439
2440
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
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
   * 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.
   */
  static int find_umc_channel(struct amd64_pvt *pvt, struct mce *m)
  {
  	u32 umc_instance_id[] = {0x50f00, 0x150f00};
  	u32 instance_id = m->ipid & GENMASK(31, 0);
  	int i, channel = -1;
  
  	for (i = 0; i < ARRAY_SIZE(umc_instance_id); i++)
  		if (umc_instance_id[i] == instance_id)
  			channel = i;
  
  	return channel;
  }
  
  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;
  
  	err.channel = find_umc_channel(pvt, m);
  	if (err.channel < 0) {
  		err.err_code = ERR_CHANNEL;
  		goto log_error;
  	}
  
  	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);
  
  	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;
  
  log_error:
  	__log_ecc_error(mci, &err, ecc_type);
  }
  
  /*
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2506
2507
   * 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...
2508
   * Reserve F0 and F6 on systems with a UMC.
0ec449ee9   Doug Thompson   amd64_edac: add E...
2509
   */
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
2510
2511
2512
2513
2514
2515
  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...
2516
2517
  			amd64_err("F0 not found, device 0x%x (broken BIOS?)
  ", pci_id1);
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
2518
2519
2520
2521
2522
2523
2524
  			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...
2525
2526
  			amd64_err("F6 not found: device 0x%x (broken BIOS?)
  ", pci_id2);
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
2527
2528
  			return -ENODEV;
  		}
5246c5400   Borislav Petkov   EDAC, amd64: Impr...
2529

936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
2530
2531
2532
2533
2534
2535
2536
2537
2538
  		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...
2539
  	/* Reserve the ADDRESS MAP Device */
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
2540
  	pvt->F1 = pci_get_related_function(pvt->F3->vendor, pci_id1, pvt->F3);
8d5b5d9c7   Borislav Petkov   amd64_edac: Renam...
2541
  	if (!pvt->F1) {
5246c5400   Borislav Petkov   EDAC, amd64: Impr...
2542
2543
  		amd64_err("F1 not found: device 0x%x (broken BIOS?)
  ", pci_id1);
bbd0c1f67   Borislav Petkov   amd64_edac: Clean...
2544
  		return -ENODEV;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2545
  	}
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2546
  	/* Reserve the DCT Device */
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
2547
  	pvt->F2 = pci_get_related_function(pvt->F3->vendor, pci_id2, pvt->F3);
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
2548
  	if (!pvt->F2) {
8d5b5d9c7   Borislav Petkov   amd64_edac: Renam...
2549
2550
  		pci_dev_put(pvt->F1);
  		pvt->F1 = NULL;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2551

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

956b9ba15   Joe Perches   edac: Convert deb...
2557
2558
2559
2560
2561
2562
  	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...
2563
2564
2565
  
  	return 0;
  }
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
2566
  static void free_mc_sibling_devs(struct amd64_pvt *pvt)
0ec449ee9   Doug Thompson   amd64_edac: add E...
2567
  {
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
2568
2569
2570
2571
2572
2573
2574
  	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...
2575
  }
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
  static void determine_ecc_sym_sz(struct amd64_pvt *pvt)
  {
  	pvt->ecc_sym_sz = 4;
  
  	if (pvt->umc) {
  		u8 i;
  
  		for (i = 0; i < NUM_UMCS; i++) {
  			/* Check enabled channels only: */
  			if ((pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) &&
  			    (pvt->umc[i].ecc_ctrl & BIT(7))) {
  				pvt->ecc_sym_sz = 8;
  				break;
  			}
  		}
  
  		return;
  	}
  
  	if (pvt->fam >= 0x10) {
  		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 */
  	for (i = 0; i < NUM_UMCS; i++) {
  
  		umc_base = get_umc_base(i);
  		umc = &pvt->umc[i];
07ed82ef9   Yazen Ghannam   EDAC, amd64: Add ...
2623
2624
  		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...
2625
2626
  		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 ...
2627
  		amd_smn_read(nid, umc_base + UMCCH_UMC_CAP_HI, &umc->umc_cap_hi);
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2628
2629
  	}
  }
0ec449ee9   Doug Thompson   amd64_edac: add E...
2630
2631
2632
2633
  /*
   * Retrieve the hardware registers of the memory controller (this includes the
   * 'Address Map' and 'Misc' device regs)
   */
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
2634
  static void read_mc_regs(struct amd64_pvt *pvt)
0ec449ee9   Doug Thompson   amd64_edac: add E...
2635
  {
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2636
  	unsigned int range;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2637
  	u64 msr_val;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2638
2639
2640
  
  	/*
  	 * Retrieve TOP_MEM and TOP_MEM2; no masking off of reserved bits since
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2641
  	 * those are Read-As-Zero.
0ec449ee9   Doug Thompson   amd64_edac: add E...
2642
  	 */
e97f8bb8c   Borislav Petkov   amd64_edac: make ...
2643
  	rdmsrl(MSR_K8_TOP_MEM1, pvt->top_mem);
956b9ba15   Joe Perches   edac: Convert deb...
2644
2645
  	edac_dbg(0, "  TOP_MEM:  0x%016llx
  ", pvt->top_mem);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2646

b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2647
  	/* Check first whether TOP_MEM2 is enabled: */
0ec449ee9   Doug Thompson   amd64_edac: add E...
2648
  	rdmsrl(MSR_K8_SYSCFG, msr_val);
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2649
  	if (msr_val & BIT(21)) {
e97f8bb8c   Borislav Petkov   amd64_edac: make ...
2650
  		rdmsrl(MSR_K8_TOP_MEM2, pvt->top_mem2);
956b9ba15   Joe Perches   edac: Convert deb...
2651
2652
  		edac_dbg(0, "  TOP_MEM2: 0x%016llx
  ", pvt->top_mem2);
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2653
  	} else {
956b9ba15   Joe Perches   edac: Convert deb...
2654
2655
  		edac_dbg(0, "  TOP_MEM2 disabled
  ");
b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2656
2657
2658
2659
2660
2661
2662
2663
  	}
  
  	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...
2664

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

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

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

7f19bf755   Borislav Petkov   amd64_edac: Remov...
2672
2673
2674
2675
2676
2677
  		/* 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...
2678
2679
2680
2681
2682
  		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...
2683

956b9ba15   Joe Perches   edac: Convert deb...
2684
2685
2686
2687
2688
2689
2690
  		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...
2691
  	}
bc21fa578   Borislav Petkov   amd64_edac: Clean...
2692
  	amd64_read_pci_cfg(pvt->F1, DHAR, &pvt->dhar);
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
2693
  	amd64_read_dct_pci_cfg(pvt, 0, DBAM0, &pvt->dbam0);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2694

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

7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
2697
2698
  	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...
2699

78da121e1   Borislav Petkov   amd64_edac: Clean...
2700
  	if (!dct_ganging_enabled(pvt)) {
7981a28f1   Aravind Gopalakrishnan   amd64_edac: Modif...
2701
2702
  		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...
2703
  	}
ad6a32e96   Borislav Petkov   amd64_edac: Sanit...
2704

b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2705
2706
  skip:
  	read_dct_base_mask(pvt);
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
2707
2708
2709
  	determine_memory_type(pvt);
  	edac_dbg(1, "  DIMM type: %s
  ", edac_mem_types[pvt->dram_type]);
a3b7db09a   Borislav Petkov   amd64_edac: Adjus...
2710

b64ce7cd7   Yazen Ghannam   EDAC, amd64: Read...
2711
  	determine_ecc_sym_sz(pvt);
ad6a32e96   Borislav Petkov   amd64_edac: Sanit...
2712

b2b0c6054   Borislav Petkov   amd64_edac: Add s...
2713
  	dump_misc_regs(pvt);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2714
2715
2716
2717
2718
2719
  }
  
  /*
   * NOTE: CPU Revision Dependent code
   *
   * Input:
11c75eada   Borislav Petkov   amd64_edac: Clean...
2720
   *	@csrow_nr ChipSelect Row Number (0..NUM_CHIPSELECTS-1)
0ec449ee9   Doug Thompson   amd64_edac: add E...
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
   *	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
   *
   */
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
2750
  static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
0ec449ee9   Doug Thompson   amd64_edac: add E...
2751
  {
1433eb990   Borislav Petkov   amd64_edac: enhan...
2752
  	u32 cs_mode, nr_pages;
f92cae452   Ashish Shenoy   amd64_edac: Fix m...
2753
  	u32 dbam = dct ? pvt->dbam1 : pvt->dbam0;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2754

10de6497a   Borislav Petkov   amd64_edac: Fix c...
2755

0ec449ee9   Doug Thompson   amd64_edac: add E...
2756
2757
2758
2759
2760
2761
2762
  	/*
  	 * The math on this doesn't look right on the surface because x/2*4 can
  	 * be simplified to x*2 but this expression makes use of the fact that
  	 * it is integral math where 1/2=0. This intermediate value becomes the
  	 * number of bits to shift the DBAM register to extract the proper CSROW
  	 * field.
  	 */
0a5dfc314   Borislav Petkov   amd64_edac: Use D...
2763
  	cs_mode = DBAM_DIMM(csrow_nr / 2, dbam);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2764

a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
2765
2766
  	nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode, (csrow_nr / 2))
  							   << (20 - PAGE_SHIFT);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2767

10de6497a   Borislav Petkov   amd64_edac: Fix c...
2768
2769
2770
2771
2772
  	edac_dbg(0, "csrow: %d, channel: %d, DBAM idx: %d
  ",
  		    csrow_nr, dct,  cs_mode);
  	edac_dbg(0, "nr_pages/channel: %u
  ", nr_pages);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2773
2774
2775
2776
2777
2778
2779
2780
  
  	return nr_pages;
  }
  
  /*
   * Initialize the array of csrow attribute instances, based on the values
   * from pci config hardware registers.
   */
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
2781
  static int init_csrows(struct mem_ctl_info *mci)
0ec449ee9   Doug Thompson   amd64_edac: add E...
2782
  {
10de6497a   Borislav Petkov   amd64_edac: Fix c...
2783
  	struct amd64_pvt *pvt = mci->pvt_info;
2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
2784
  	enum edac_type edac_mode = EDAC_NONE;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2785
  	struct csrow_info *csrow;
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
2786
  	struct dimm_info *dimm;
10de6497a   Borislav Petkov   amd64_edac: Fix c...
2787
  	int i, j, empty = 1;
a895bf8b1   Mauro Carvalho Chehab   edac: move nr_pag...
2788
  	int nr_pages = 0;
10de6497a   Borislav Petkov   amd64_edac: Fix c...
2789
  	u32 val;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2790

2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
2791
2792
  	if (!pvt->umc) {
  		amd64_read_pci_cfg(pvt->F3, NBCFG, &val);
0ec449ee9   Doug Thompson   amd64_edac: add E...
2793

2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
2794
  		pvt->nbcfg = val;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2795

2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
2796
2797
2798
2799
2800
  		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...
2801

10de6497a   Borislav Petkov   amd64_edac: Fix c...
2802
2803
2804
  	/*
  	 * We iterate over DCT0 here but we look at DCT1 in parallel, if needed.
  	 */
11c75eada   Borislav Petkov   amd64_edac: Clean...
2805
  	for_each_chip_select(i, 0, pvt) {
10de6497a   Borislav Petkov   amd64_edac: Fix c...
2806
2807
  		bool row_dct0 = !!csrow_enabled(i, 0, pvt);
  		bool row_dct1 = false;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2808

a4b4bedce   Borislav Petkov   amd64_edac: Get r...
2809
  		if (pvt->fam != 0xf)
10de6497a   Borislav Petkov   amd64_edac: Fix c...
2810
2811
2812
  			row_dct1 = !!csrow_enabled(i, 1, pvt);
  
  		if (!row_dct0 && !row_dct1)
0ec449ee9   Doug Thompson   amd64_edac: add E...
2813
  			continue;
0ec449ee9   Doug Thompson   amd64_edac: add E...
2814

10de6497a   Borislav Petkov   amd64_edac: Fix c...
2815
  		csrow = mci->csrows[i];
0ec449ee9   Doug Thompson   amd64_edac: add E...
2816
  		empty = 0;
10de6497a   Borislav Petkov   amd64_edac: Fix c...
2817
2818
2819
2820
  
  		edac_dbg(1, "MC node: %d, csrow: %d
  ",
  			    pvt->mc_node_id, i);
1eef12825   Mauro Carvalho Chehab   amd64_edac: Corre...
2821
  		if (row_dct0) {
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
2822
  			nr_pages = get_csrow_nr_pages(pvt, 0, i);
1eef12825   Mauro Carvalho Chehab   amd64_edac: Corre...
2823
2824
  			csrow->channels[0]->dimm->nr_pages = nr_pages;
  		}
11c75eada   Borislav Petkov   amd64_edac: Clean...
2825

10de6497a   Borislav Petkov   amd64_edac: Fix c...
2826
  		/* K8 has only one DCT */
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
2827
  		if (pvt->fam != 0xf && row_dct1) {
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
2828
  			int row_dct1_pages = get_csrow_nr_pages(pvt, 1, i);
1eef12825   Mauro Carvalho Chehab   amd64_edac: Corre...
2829
2830
2831
2832
  
  			csrow->channels[1]->dimm->nr_pages = row_dct1_pages;
  			nr_pages += row_dct1_pages;
  		}
0ec449ee9   Doug Thompson   amd64_edac: add E...
2833

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

2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
  		/* Determine DIMM ECC mode: */
  		if (pvt->umc) {
  			if (mci->edac_ctl_cap & EDAC_FLAG_S4ECD4ED)
  				edac_mode = EDAC_S4ECD4ED;
  			else if (mci->edac_ctl_cap & EDAC_FLAG_SECDED)
  				edac_mode = EDAC_SECDED;
  
  		} else if (pvt->nbcfg & NBCFG_ECC_ENABLE) {
  			edac_mode = (pvt->nbcfg & NBCFG_CHIPKILL)
  					? EDAC_S4ECD4ED
  					: EDAC_SECDED;
  		}
084a4fcce   Mauro Carvalho Chehab   edac: move dimm p...
2849
2850
  
  		for (j = 0; j < pvt->channel_count; j++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
2851
  			dimm = csrow->channels[j]->dimm;
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
2852
  			dimm->mtype = pvt->dram_type;
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
2853
  			dimm->edac_mode = edac_mode;
084a4fcce   Mauro Carvalho Chehab   edac: move dimm p...
2854
  		}
0ec449ee9   Doug Thompson   amd64_edac: add E...
2855
2856
2857
2858
  	}
  
  	return empty;
  }
d27bf6fa3   Doug Thompson   amd64_edac: add e...
2859

f6d6ae965   Borislav Petkov   amd64_edac: unify...
2860
  /* get all cores on this DCT */
8b84c8df3   Daniel J Blueman   x86, AMD, NB: Use...
2861
  static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, u16 nid)
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2862
2863
2864
2865
2866
2867
2868
2869
2870
  {
  	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...
2871
  static bool nb_mce_bank_enabled_on_node(u16 nid)
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2872
2873
  {
  	cpumask_var_t mask;
505422517   Borislav Petkov   x86, msr: Add sup...
2874
  	int cpu, nbe;
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2875
2876
2877
  	bool ret = false;
  
  	if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
2878
2879
  		amd64_warn("%s: Error allocating mask
  ", __func__);
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2880
2881
2882
2883
  		return false;
  	}
  
  	get_cpus_on_this_dct_cpumask(mask, nid);
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2884
2885
2886
  	rdmsr_on_cpus(mask, MSR_IA32_MCG_CTL, msrs);
  
  	for_each_cpu(cpu, mask) {
505422517   Borislav Petkov   x86, msr: Add sup...
2887
  		struct msr *reg = per_cpu_ptr(msrs, cpu);
5980bb9cd   Borislav Petkov   amd64_edac: Clean...
2888
  		nbe = reg->l & MSR_MCGCTL_NBE;
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2889

956b9ba15   Joe Perches   edac: Convert deb...
2890
2891
2892
2893
  		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...
2894
2895
2896
  
  		if (!nbe)
  			goto out;
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2897
2898
2899
2900
  	}
  	ret = true;
  
  out:
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2901
2902
2903
  	free_cpumask_var(mask);
  	return ret;
  }
c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
2904
  static int toggle_ecc_err_reporting(struct ecc_settings *s, u16 nid, bool on)
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2905
2906
  {
  	cpumask_var_t cmask;
505422517   Borislav Petkov   x86, msr: Add sup...
2907
  	int cpu;
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2908
2909
  
  	if (!zalloc_cpumask_var(&cmask, GFP_KERNEL)) {
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
2910
2911
  		amd64_warn("%s: error allocating mask
  ", __func__);
0de278844   Pan Bian   EDAC, amd64: Fix ...
2912
  		return -ENOMEM;
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2913
  	}
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
2914
  	get_cpus_on_this_dct_cpumask(cmask, nid);
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2915

f6d6ae965   Borislav Petkov   amd64_edac: unify...
2916
2917
2918
  	rdmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
  
  	for_each_cpu(cpu, cmask) {
505422517   Borislav Petkov   x86, msr: Add sup...
2919
  		struct msr *reg = per_cpu_ptr(msrs, cpu);
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2920
  		if (on) {
5980bb9cd   Borislav Petkov   amd64_edac: Clean...
2921
  			if (reg->l & MSR_MCGCTL_NBE)
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
2922
  				s->flags.nb_mce_enable = 1;
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2923

5980bb9cd   Borislav Petkov   amd64_edac: Clean...
2924
  			reg->l |= MSR_MCGCTL_NBE;
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2925
2926
  		} else {
  			/*
d95cf4de6   Borislav Petkov   amd64_edac: Simpl...
2927
  			 * Turn off NB MCE reporting only when it was off before
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2928
  			 */
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
2929
  			if (!s->flags.nb_mce_enable)
5980bb9cd   Borislav Petkov   amd64_edac: Clean...
2930
  				reg->l &= ~MSR_MCGCTL_NBE;
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2931
  		}
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2932
2933
  	}
  	wrmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
f6d6ae965   Borislav Petkov   amd64_edac: unify...
2934
2935
2936
2937
  	free_cpumask_var(cmask);
  
  	return 0;
  }
c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
2938
  static bool enable_ecc_error_reporting(struct ecc_settings *s, u16 nid,
2299ef711   Borislav Petkov   amd64_edac: Check...
2939
  				       struct pci_dev *F3)
f9431992b   Doug Thompson   amd64_edac: add E...
2940
  {
2299ef711   Borislav Petkov   amd64_edac: Check...
2941
  	bool ret = true;
c9f4f26ea   Borislav Petkov   amd64_edac: Clean...
2942
  	u32 value, mask = 0x3;		/* UECC/CECC enable */
f9431992b   Doug Thompson   amd64_edac: add E...
2943

2299ef711   Borislav Petkov   amd64_edac: Check...
2944
2945
2946
2947
2948
  	if (toggle_ecc_err_reporting(s, nid, ON)) {
  		amd64_warn("Error enabling ECC reporting over MCGCTL!
  ");
  		return false;
  	}
c9f4f26ea   Borislav Petkov   amd64_edac: Clean...
2949
  	amd64_read_pci_cfg(F3, NBCTL, &value);
f9431992b   Doug Thompson   amd64_edac: add E...
2950

ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
2951
2952
  	s->old_nbctl   = value & mask;
  	s->nbctl_valid = true;
f9431992b   Doug Thompson   amd64_edac: add E...
2953
2954
  
  	value |= mask;
c9f4f26ea   Borislav Petkov   amd64_edac: Clean...
2955
  	amd64_write_pci_cfg(F3, NBCTL, value);
f9431992b   Doug Thompson   amd64_edac: add E...
2956

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

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

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

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

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

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

a97fa68ec   Borislav Petkov   amd64_edac: Clean...
2975
  		if (!(value & NBCFG_ECC_ENABLE)) {
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
2976
2977
2978
  			amd64_warn("Hardware rejected DRAM ECC enable,"
  				   "check memory DIMM configuration.
  ");
2299ef711   Borislav Petkov   amd64_edac: Check...
2979
  			ret = false;
f9431992b   Doug Thompson   amd64_edac: add E...
2980
  		} else {
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
2981
2982
  			amd64_info("Hardware accepted DRAM ECC Enable
  ");
f9431992b   Doug Thompson   amd64_edac: add E...
2983
  		}
d95cf4de6   Borislav Petkov   amd64_edac: Simpl...
2984
  	} else {
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
2985
  		s->flags.nb_ecc_prev = 1;
f9431992b   Doug Thompson   amd64_edac: add E...
2986
  	}
d95cf4de6   Borislav Petkov   amd64_edac: Simpl...
2987

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

2299ef711   Borislav Petkov   amd64_edac: Check...
2992
  	return ret;
f9431992b   Doug Thompson   amd64_edac: add E...
2993
  }
c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
2994
  static void restore_ecc_error_reporting(struct ecc_settings *s, u16 nid,
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
2995
  					struct pci_dev *F3)
f9431992b   Doug Thompson   amd64_edac: add E...
2996
  {
c9f4f26ea   Borislav Petkov   amd64_edac: Clean...
2997
  	u32 value, mask = 0x3;		/* UECC/CECC enable */
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
2998
  	if (!s->nbctl_valid)
f9431992b   Doug Thompson   amd64_edac: add E...
2999
  		return;
c9f4f26ea   Borislav Petkov   amd64_edac: Clean...
3000
  	amd64_read_pci_cfg(F3, NBCTL, &value);
f9431992b   Doug Thompson   amd64_edac: add E...
3001
  	value &= ~mask;
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3002
  	value |= s->old_nbctl;
f9431992b   Doug Thompson   amd64_edac: add E...
3003

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

ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3006
3007
  	/* restore previous BIOS DRAM ECC "off" setting we force-enabled */
  	if (!s->flags.nb_ecc_prev) {
a97fa68ec   Borislav Petkov   amd64_edac: Clean...
3008
3009
3010
  		amd64_read_pci_cfg(F3, NBCFG, &value);
  		value &= ~NBCFG_ECC_ENABLE;
  		amd64_write_pci_cfg(F3, NBCFG, value);
d95cf4de6   Borislav Petkov   amd64_edac: Simpl...
3011
3012
3013
  	}
  
  	/* restore the NB Enable MCGCTL bit */
2299ef711   Borislav Petkov   amd64_edac: Check...
3014
  	if (toggle_ecc_err_reporting(s, nid, OFF))
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
3015
3016
  		amd64_warn("Error restoring NB MCGCTL settings!
  ");
f9431992b   Doug Thompson   amd64_edac: add E...
3017
3018
3019
  }
  
  /*
2299ef711   Borislav Petkov   amd64_edac: Check...
3020
3021
3022
3023
   * EDAC requires that the BIOS have ECC enabled before
   * taking over the processing of ECC errors. A command line
   * option allows to force-enable hardware ECC later in
   * enable_ecc_error_reporting().
f9431992b   Doug Thompson   amd64_edac: add E...
3024
   */
cab4d2776   Borislav Petkov   amd64_edac: Do no...
3025
3026
3027
3028
3029
3030
3031
3032
  static const char *ecc_msg =
  	"ECC disabled in the BIOS or no ECC capability, module will not load.
  "
  	" Either enable ECC checking or force module loading by setting "
  	"'ecc_enable_override'.
  "
  	" (Note that use of the override may cause unknown side effects.)
  ";
be3468e8f   Borislav Petkov   amd64_edac: clean...
3033

c7e5301a1   Daniel J Blueman   amd64_edac: Fix t...
3034
  static bool ecc_enabled(struct pci_dev *F3, u16 nid)
f9431992b   Doug Thompson   amd64_edac: add E...
3035
  {
06724535f   Borislav Petkov   amd64_edac: check...
3036
  	bool nb_mce_en = false;
196b79fcc   Yazen Ghannam   EDAC, amd64: Exte...
3037
3038
  	u8 ecc_en = 0, i;
  	u32 value;
f9431992b   Doug Thompson   amd64_edac: add E...
3039

196b79fcc   Yazen Ghannam   EDAC, amd64: Exte...
3040
3041
  	if (boot_cpu_data.x86 >= 0x17) {
  		u8 umc_en_mask = 0, ecc_en_mask = 0;
f9431992b   Doug Thompson   amd64_edac: add E...
3042

196b79fcc   Yazen Ghannam   EDAC, amd64: Exte...
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
  		for (i = 0; i < NUM_UMCS; i++) {
  			u32 base = get_umc_base(i);
  
  			/* Only check enabled UMCs. */
  			if (amd_smn_read(nid, base + UMCCH_SDP_CTRL, &value))
  				continue;
  
  			if (!(value & UMC_SDP_INIT))
  				continue;
  
  			umc_en_mask |= BIT(i);
  
  			if (amd_smn_read(nid, base + UMCCH_UMC_CAP_HI, &value))
  				continue;
  
  			if (value & UMC_ECC_ENABLED)
  				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...
3065
3066
3067
  		else
  			edac_dbg(0, "Node %d: No enabled UMCs.
  ", nid);
196b79fcc   Yazen Ghannam   EDAC, amd64: Exte...
3068
3069
3070
3071
3072
  
  		/* Assume UMC MCA banks are enabled. */
  		nb_mce_en = true;
  	} else {
  		amd64_read_pci_cfg(F3, NBCFG, &value);
f9431992b   Doug Thompson   amd64_edac: add E...
3073

196b79fcc   Yazen Ghannam   EDAC, amd64: Exte...
3074
3075
3076
3077
  		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...
3078
3079
  			edac_dbg(0, "NB MCE bank disabled, set MSR 0x%08x[4] on node %d to enable.
  ",
196b79fcc   Yazen Ghannam   EDAC, amd64: Exte...
3080
3081
  				     MSR_IA32_MCG_CTL, nid);
  	}
11ab1cae5   Yazen Ghannam   EDAC, amd64: Rewo...
3082
3083
3084
  	amd64_info("Node %d: DRAM ECC %s.
  ",
  		   nid, (ecc_en ? "enabled" : "disabled"));
f9431992b   Doug Thompson   amd64_edac: add E...
3085

2299ef711   Borislav Petkov   amd64_edac: Check...
3086
  	if (!ecc_en || !nb_mce_en) {
11ab1cae5   Yazen Ghannam   EDAC, amd64: Rewo...
3087
  		amd64_info("%s", ecc_msg);
2299ef711   Borislav Petkov   amd64_edac: Check...
3088
3089
3090
  		return false;
  	}
  	return true;
f9431992b   Doug Thompson   amd64_edac: add E...
3091
  }
2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
  static inline void
  f17h_determine_edac_ctl_cap(struct mem_ctl_info *mci, struct amd64_pvt *pvt)
  {
  	u8 i, ecc_en = 1, cpk_en = 1;
  
  	for (i = 0; i < NUM_UMCS; i++) {
  		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);
  		}
  	}
  
  	/* Set chipkill only if ECC is enabled: */
  	if (ecc_en) {
  		mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
  
  		if (cpk_en)
  			mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
  	}
  }
df71a0532   Borislav Petkov   amd64_edac: Enabl...
3112
3113
  static void setup_mci_misc_attrs(struct mem_ctl_info *mci,
  				 struct amd64_family_type *fam)
7d6034d32   Doug Thompson   amd64_edac: add m...
3114
3115
3116
3117
3118
  {
  	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...
3119

2d09d8f30   Yazen Ghannam   EDAC, amd64: Dete...
3120
3121
3122
3123
3124
  	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...
3125

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

d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3130
  	mci->edac_cap		= determine_edac_cap(pvt);
7d6034d32   Doug Thompson   amd64_edac: add m...
3131
3132
  	mci->mod_name		= EDAC_MOD_STR;
  	mci->mod_ver		= EDAC_AMD64_VERSION;
df71a0532   Borislav Petkov   amd64_edac: Enabl...
3133
  	mci->ctl_name		= fam->ctl_name;
e7934b70d   Yazen Ghannam   EDAC, amd64: Chan...
3134
  	mci->dev_name		= pci_name(pvt->F3);
7d6034d32   Doug Thompson   amd64_edac: add m...
3135
  	mci->ctl_page_to_phys	= NULL;
7d6034d32   Doug Thompson   amd64_edac: add m...
3136
  	/* memory scrubber interface */
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3137
3138
  	mci->set_sdram_scrub_rate = set_scrub_rate;
  	mci->get_sdram_scrub_rate = get_scrub_rate;
7d6034d32   Doug Thompson   amd64_edac: add m...
3139
  }
0092b20d4   Borislav Petkov   amd64_edac: Simpl...
3140
3141
3142
  /*
   * returns a pointer to the family descriptor on success, NULL otherwise.
   */
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3143
  static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
395ae783b   Borislav Petkov   amd64_edac: Add p...
3144
  {
0092b20d4   Borislav Petkov   amd64_edac: Simpl...
3145
  	struct amd64_family_type *fam_type = NULL;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
3146
  	pvt->ext_model  = boot_cpu_data.x86_model >> 4;
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
3147
  	pvt->stepping	= boot_cpu_data.x86_mask;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
3148
3149
3150
3151
  	pvt->model	= boot_cpu_data.x86_model;
  	pvt->fam	= boot_cpu_data.x86;
  
  	switch (pvt->fam) {
395ae783b   Borislav Petkov   amd64_edac: Add p...
3152
  	case 0xf:
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3153
3154
  		fam_type	= &family_types[K8_CPUS];
  		pvt->ops	= &family_types[K8_CPUS].ops;
395ae783b   Borislav Petkov   amd64_edac: Add p...
3155
  		break;
df71a0532   Borislav Petkov   amd64_edac: Enabl...
3156

395ae783b   Borislav Petkov   amd64_edac: Add p...
3157
  	case 0x10:
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3158
3159
  		fam_type	= &family_types[F10_CPUS];
  		pvt->ops	= &family_types[F10_CPUS].ops;
df71a0532   Borislav Petkov   amd64_edac: Enabl...
3160
3161
3162
  		break;
  
  	case 0x15:
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
3163
  		if (pvt->model == 0x30) {
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3164
3165
  			fam_type = &family_types[F15_M30H_CPUS];
  			pvt->ops = &family_types[F15_M30H_CPUS].ops;
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
3166
  			break;
a597d2a5d   Aravind Gopalakrishnan   amd64_edac: Add F...
3167
3168
3169
3170
  		} 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...
3171
  		}
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3172
3173
  		fam_type	= &family_types[F15_CPUS];
  		pvt->ops	= &family_types[F15_CPUS].ops;
395ae783b   Borislav Petkov   amd64_edac: Add p...
3174
  		break;
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
3175
  	case 0x16:
85a8885bd   Aravind Gopalakrishnan   amd64_edac: Add s...
3176
3177
3178
3179
3180
  		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...
3181
3182
  		fam_type	= &family_types[F16_CPUS];
  		pvt->ops	= &family_types[F16_CPUS].ops;
94c1acf2c   Aravind Gopalakrishnan   amd64_edac: Add F...
3183
  		break;
f1cbbec9f   Yazen Ghannam   EDAC, amd64: Add ...
3184
3185
3186
3187
  	case 0x17:
  		fam_type	= &family_types[F17_CPUS];
  		pvt->ops	= &family_types[F17_CPUS].ops;
  		break;
395ae783b   Borislav Petkov   amd64_edac: Add p...
3188
  	default:
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
3189
3190
  		amd64_err("Unsupported family!
  ");
0092b20d4   Borislav Petkov   amd64_edac: Simpl...
3191
  		return NULL;
395ae783b   Borislav Petkov   amd64_edac: Add p...
3192
  	}
0092b20d4   Borislav Petkov   amd64_edac: Simpl...
3193

df71a0532   Borislav Petkov   amd64_edac: Enabl...
3194
3195
  	amd64_info("%s %sdetected (node %d).
  ", fam_type->ctl_name,
18b94f66f   Aravind Gopalakrishnan   amd64_edac: Add E...
3196
  		     (pvt->fam == 0xf ?
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
3197
3198
3199
  				(pvt->ext_model >= K8_REV_F  ? "revF or later "
  							     : "revE or earlier ")
  				 : ""), pvt->mc_node_id);
0092b20d4   Borislav Petkov   amd64_edac: Simpl...
3200
  	return fam_type;
395ae783b   Borislav Petkov   amd64_edac: Add p...
3201
  }
e339f1ec9   Takashi Iwai   EDAC: amd64: Use ...
3202
3203
3204
3205
3206
3207
3208
3209
3210
  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
  };
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3211
  static int init_one_instance(unsigned int nid)
7d6034d32   Doug Thompson   amd64_edac: add m...
3212
  {
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3213
  	struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
0092b20d4   Borislav Petkov   amd64_edac: Simpl...
3214
  	struct amd64_family_type *fam_type = NULL;
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3215
  	struct mem_ctl_info *mci = NULL;
ab5a503cb   Mauro Carvalho Chehab   amd64_edac: conve...
3216
  	struct edac_mc_layer layers[2];
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3217
  	struct amd64_pvt *pvt = NULL;
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
3218
  	u16 pci_id1, pci_id2;
7d6034d32   Doug Thompson   amd64_edac: add m...
3219
3220
3221
3222
3223
  	int err = 0, ret;
  
  	ret = -ENOMEM;
  	pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
  	if (!pvt)
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3224
  		goto err_ret;
7d6034d32   Doug Thompson   amd64_edac: add m...
3225

360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3226
  	pvt->mc_node_id	= nid;
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3227
  	pvt->F3 = F3;
7d6034d32   Doug Thompson   amd64_edac: add m...
3228

395ae783b   Borislav Petkov   amd64_edac: Add p...
3229
  	ret = -EINVAL;
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3230
  	fam_type = per_family_init(pvt);
0092b20d4   Borislav Petkov   amd64_edac: Simpl...
3231
  	if (!fam_type)
395ae783b   Borislav Petkov   amd64_edac: Add p...
3232
  		goto err_free;
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
  	if (pvt->fam >= 0x17) {
  		pvt->umc = kcalloc(NUM_UMCS, sizeof(struct amd64_umc), GFP_KERNEL);
  		if (!pvt->umc) {
  			ret = -ENOMEM;
  			goto err_free;
  		}
  
  		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;
  	}
  
  	err = reserve_mc_sibling_devs(pvt, pci_id1, pci_id2);
7d6034d32   Doug Thompson   amd64_edac: add m...
3248
  	if (err)
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
3249
  		goto err_post_init;
7d6034d32   Doug Thompson   amd64_edac: add m...
3250

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

7d6034d32   Doug Thompson   amd64_edac: add m...
3253
3254
3255
  	/*
  	 * 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...
3256
  	 * tables in the 'mci' structure.
7d6034d32   Doug Thompson   amd64_edac: add m...
3257
  	 */
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3258
  	ret = -EINVAL;
7d6034d32   Doug Thompson   amd64_edac: add m...
3259
3260
  	pvt->channel_count = pvt->ops->early_channel_count(pvt);
  	if (pvt->channel_count < 0)
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3261
  		goto err_siblings;
7d6034d32   Doug Thompson   amd64_edac: add m...
3262
3263
  
  	ret = -ENOMEM;
ab5a503cb   Mauro Carvalho Chehab   amd64_edac: conve...
3264
3265
3266
3267
  	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...
3268
3269
3270
3271
3272
3273
3274
  
  	/*
  	 * 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.
  	 */
  	layers[1].size = 2;
ab5a503cb   Mauro Carvalho Chehab   amd64_edac: conve...
3275
  	layers[1].is_virt_csrow = false;
f0a56c480   Borislav Petkov   amd64_edac: Fix s...
3276

ca0907b9e   Mauro Carvalho Chehab   edac: Remove the ...
3277
  	mci = edac_mc_alloc(nid, ARRAY_SIZE(layers), layers, 0);
7d6034d32   Doug Thompson   amd64_edac: add m...
3278
  	if (!mci)
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3279
  		goto err_siblings;
7d6034d32   Doug Thompson   amd64_edac: add m...
3280
3281
  
  	mci->pvt_info = pvt;
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3282
  	mci->pdev = &pvt->F3->dev;
7d6034d32   Doug Thompson   amd64_edac: add m...
3283

df71a0532   Borislav Petkov   amd64_edac: Enabl...
3284
  	setup_mci_misc_attrs(mci, fam_type);
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3285
3286
  
  	if (init_csrows(mci))
7d6034d32   Doug Thompson   amd64_edac: add m...
3287
  		mci->edac_cap = EDAC_FLAG_NONE;
7d6034d32   Doug Thompson   amd64_edac: add m...
3288
  	ret = -ENODEV;
e339f1ec9   Takashi Iwai   EDAC: amd64: Use ...
3289
  	if (edac_mc_add_mc_with_groups(mci, amd64_edac_attr_groups)) {
956b9ba15   Joe Perches   edac: Convert deb...
3290
3291
  		edac_dbg(1, "failed edac_mc_add_mc()
  ");
7d6034d32   Doug Thompson   amd64_edac: add m...
3292
3293
  		goto err_add_mc;
  	}
7d6034d32   Doug Thompson   amd64_edac: add m...
3294
3295
3296
3297
  	return 0;
  
  err_add_mc:
  	edac_mc_free(mci);
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3298
3299
  err_siblings:
  	free_mc_sibling_devs(pvt);
7d6034d32   Doug Thompson   amd64_edac: add m...
3300

936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
3301
3302
3303
  err_post_init:
  	if (pvt->fam >= 0x17)
  		kfree(pvt->umc);
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3304
3305
  err_free:
  	kfree(pvt);
7d6034d32   Doug Thompson   amd64_edac: add m...
3306

360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3307
  err_ret:
7d6034d32   Doug Thompson   amd64_edac: add m...
3308
3309
  	return ret;
  }
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3310
  static int probe_one_instance(unsigned int nid)
7d6034d32   Doug Thompson   amd64_edac: add m...
3311
  {
2299ef711   Borislav Petkov   amd64_edac: Check...
3312
  	struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3313
  	struct ecc_settings *s;
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3314
  	int ret;
7d6034d32   Doug Thompson   amd64_edac: add m...
3315

ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3316
3317
3318
  	ret = -ENOMEM;
  	s = kzalloc(sizeof(struct ecc_settings), GFP_KERNEL);
  	if (!s)
2299ef711   Borislav Petkov   amd64_edac: Check...
3319
  		goto err_out;
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3320
3321
  
  	ecc_stngs[nid] = s;
2299ef711   Borislav Petkov   amd64_edac: Check...
3322
  	if (!ecc_enabled(F3, nid)) {
4688c9b42   Yazen Ghannam   EDAC, amd64: Don'...
3323
  		ret = 0;
2299ef711   Borislav Petkov   amd64_edac: Check...
3324
3325
3326
  
  		if (!ecc_enable_override)
  			goto err_enable;
044e7a414   Yazen Ghannam   EDAC, amd64: Don'...
3327
3328
3329
3330
3331
3332
  		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...
3333
3334
3335
3336
  
  		if (!enable_ecc_error_reporting(s, nid, F3))
  			goto err_enable;
  	}
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3337
  	ret = init_one_instance(nid);
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3338
  	if (ret < 0) {
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3339
3340
  		amd64_err("Error probing instance: %d
  ", nid);
044e7a414   Yazen Ghannam   EDAC, amd64: Don'...
3341
3342
3343
  
  		if (boot_cpu_data.x86 < 0x17)
  			restore_ecc_error_reporting(s, nid, F3);
2b9b2c465   Yazen Ghannam   EDAC, amd64: Free...
3344
3345
  
  		goto err_enable;
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3346
  	}
7d6034d32   Doug Thompson   amd64_edac: add m...
3347
3348
  
  	return ret;
2299ef711   Borislav Petkov   amd64_edac: Check...
3349
3350
3351
3352
3353
3354
3355
  
  err_enable:
  	kfree(s);
  	ecc_stngs[nid] = NULL;
  
  err_out:
  	return ret;
7d6034d32   Doug Thompson   amd64_edac: add m...
3356
  }
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3357
  static void remove_one_instance(unsigned int nid)
7d6034d32   Doug Thompson   amd64_edac: add m...
3358
  {
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3359
3360
  	struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
  	struct ecc_settings *s = ecc_stngs[nid];
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3361
3362
  	struct mem_ctl_info *mci;
  	struct amd64_pvt *pvt;
7d6034d32   Doug Thompson   amd64_edac: add m...
3363

3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3364
  	mci = find_mci_by_dev(&F3->dev);
a4b4bedce   Borislav Petkov   amd64_edac: Get r...
3365
  	WARN_ON(!mci);
7d6034d32   Doug Thompson   amd64_edac: add m...
3366
  	/* Remove from EDAC CORE tracking list */
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3367
  	mci = edac_mc_del_mc(&F3->dev);
7d6034d32   Doug Thompson   amd64_edac: add m...
3368
3369
3370
3371
  	if (!mci)
  		return;
  
  	pvt = mci->pvt_info;
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3372
  	restore_ecc_error_reporting(s, nid, F3);
7d6034d32   Doug Thompson   amd64_edac: add m...
3373

360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3374
  	free_mc_sibling_devs(pvt);
7d6034d32   Doug Thompson   amd64_edac: add m...
3375

360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3376
3377
  	kfree(ecc_stngs[nid]);
  	ecc_stngs[nid] = NULL;
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3378

7d6034d32   Doug Thompson   amd64_edac: add m...
3379
  	/* Free the EDAC CORE resources */
8f68ed972   Borislav Petkov   amd64_edac: fix d...
3380
  	mci->pvt_info = NULL;
8f68ed972   Borislav Petkov   amd64_edac: fix d...
3381
3382
  
  	kfree(pvt);
7d6034d32   Doug Thompson   amd64_edac: add m...
3383
3384
  	edac_mc_free(mci);
  }
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3385
  static void setup_pci_device(void)
7d6034d32   Doug Thompson   amd64_edac: add m...
3386
3387
3388
  {
  	struct mem_ctl_info *mci;
  	struct amd64_pvt *pvt;
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3389
  	if (pci_ctl)
7d6034d32   Doug Thompson   amd64_edac: add m...
3390
  		return;
2ec591ac7   Borislav Petkov   EDAC, amd64_edac:...
3391
  	mci = edac_mc_find(0);
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3392
3393
  	if (!mci)
  		return;
7d6034d32   Doug Thompson   amd64_edac: add m...
3394

d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3395
  	pvt = mci->pvt_info;
936fc3afa   Yazen Ghannam   EDAC, amd64: Rese...
3396
3397
3398
3399
  	if (pvt->umc)
  		pci_ctl = edac_pci_create_generic_ctl(&pvt->F0->dev, EDAC_MOD_STR);
  	else
  		pci_ctl = edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR);
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3400
3401
3402
3403
3404
  	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...
3405
3406
  	}
  }
d6efab74f   Yazen Ghannam   EDAC, amd64: Auto...
3407
3408
3409
3410
3411
  static const struct x86_cpu_id amd64_cpuids[] = {
  	{ X86_VENDOR_AMD, 0xF,	X86_MODEL_ANY,	X86_FEATURE_ANY, 0 },
  	{ X86_VENDOR_AMD, 0x10, X86_MODEL_ANY,	X86_FEATURE_ANY, 0 },
  	{ X86_VENDOR_AMD, 0x15, X86_MODEL_ANY,	X86_FEATURE_ANY, 0 },
  	{ X86_VENDOR_AMD, 0x16, X86_MODEL_ANY,	X86_FEATURE_ANY, 0 },
95d3af6bd   Yazen Ghannam   EDAC, amd64: Auto...
3412
  	{ X86_VENDOR_AMD, 0x17, X86_MODEL_ANY,	X86_FEATURE_ANY, 0 },
d6efab74f   Yazen Ghannam   EDAC, amd64: Auto...
3413
3414
3415
  	{ }
  };
  MODULE_DEVICE_TABLE(x86cpu, amd64_cpuids);
7d6034d32   Doug Thompson   amd64_edac: add m...
3416
3417
  static int __init amd64_edac_init(void)
  {
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3418
  	int err = -ENODEV;
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3419
  	int i;
7d6034d32   Doug Thompson   amd64_edac: add m...
3420

1bd9900b8   Yazen Ghannam   EDAC, amd64: Add ...
3421
3422
  	if (!x86_match_cpu(amd64_cpuids))
  		return -ENODEV;
9653a5c76   Hans Rosenfeld   x86, amd-nb: Clea...
3423
  	if (amd_cache_northbridges() < 0)
1bd9900b8   Yazen Ghannam   EDAC, amd64: Add ...
3424
  		return -ENODEV;
7d6034d32   Doug Thompson   amd64_edac: add m...
3425

6ba92fea1   Borislav Petkov   EDAC, amd64_edac:...
3426
  	opstate_init();
cc4d8860f   Borislav Petkov   amd64_edac: Alloc...
3427
  	err = -ENOMEM;
ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3428
  	ecc_stngs = kzalloc(amd_nb_num() * sizeof(ecc_stngs[0]), GFP_KERNEL);
2ec591ac7   Borislav Petkov   EDAC, amd64_edac:...
3429
  	if (!ecc_stngs)
a9f0fbe2b   Borislav Petkov   amd64_edac: Fix p...
3430
  		goto err_free;
cc4d8860f   Borislav Petkov   amd64_edac: Alloc...
3431

505422517   Borislav Petkov   x86, msr: Add sup...
3432
  	msrs = msrs_alloc();
56b34b91e   Borislav Petkov   amd64_edac: make ...
3433
  	if (!msrs)
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3434
  		goto err_free;
505422517   Borislav Petkov   x86, msr: Add sup...
3435

2287c6364   Yazen Ghannam   EDAC, amd64: Save...
3436
3437
3438
  	for (i = 0; i < amd_nb_num(); i++) {
  		err = probe_one_instance(i);
  		if (err) {
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3439
3440
3441
  			/* unwind properly */
  			while (--i >= 0)
  				remove_one_instance(i);
7d6034d32   Doug Thompson   amd64_edac: add m...
3442

3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3443
3444
  			goto err_pci;
  		}
2287c6364   Yazen Ghannam   EDAC, amd64: Save...
3445
  	}
7d6034d32   Doug Thompson   amd64_edac: add m...
3446

4688c9b42   Yazen Ghannam   EDAC, amd64: Don'...
3447
3448
3449
3450
  	if (!edac_has_mcs()) {
  		err = -ENODEV;
  		goto err_pci;
  	}
234365f56   Yazen Ghannam   EDAC, amd64: Move...
3451
3452
3453
3454
3455
3456
3457
3458
  	/* register stuff with EDAC MCE */
  	if (report_gart_errors)
  		amd_report_gart_errors(true);
  
  	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...
3459
  	setup_pci_device();
f5b10c45e   Tomasz Pala   amd64_edac: Build...
3460
3461
3462
3463
3464
  
  #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:...
3465
3466
  	printk(KERN_INFO "AMD64 EDAC driver v%s
  ", EDAC_AMD64_VERSION);
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3467
  	return 0;
7d6034d32   Doug Thompson   amd64_edac: add m...
3468

56b34b91e   Borislav Petkov   amd64_edac: make ...
3469
3470
3471
  err_pci:
  	msrs_free(msrs);
  	msrs = NULL;
cc4d8860f   Borislav Petkov   amd64_edac: Alloc...
3472

360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3473
  err_free:
360b7f3c6   Borislav Petkov   amd64_edac: Remov...
3474
3475
  	kfree(ecc_stngs);
  	ecc_stngs = NULL;
7d6034d32   Doug Thompson   amd64_edac: add m...
3476
3477
3478
3479
3480
  	return err;
  }
  
  static void __exit amd64_edac_exit(void)
  {
3f37a36b6   Borislav Petkov   EDAC, amd64_edac:...
3481
  	int i;
d1ea71cdc   Borislav Petkov   amd64_edac: Remov...
3482
3483
  	if (pci_ctl)
  		edac_pci_release_generic_ctl(pci_ctl);
7d6034d32   Doug Thompson   amd64_edac: add m...
3484

234365f56   Yazen Ghannam   EDAC, amd64: Move...
3485
3486
3487
3488
3489
3490
3491
  	/* unregister from EDAC MCE */
  	amd_report_gart_errors(false);
  
  	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:...
3492
3493
  	for (i = 0; i < amd_nb_num(); i++)
  		remove_one_instance(i);
505422517   Borislav Petkov   x86, msr: Add sup...
3494

ae7bb7c67   Borislav Petkov   amd64_edac: Carve...
3495
3496
  	kfree(ecc_stngs);
  	ecc_stngs = NULL;
505422517   Borislav Petkov   x86, msr: Add sup...
3497
3498
  	msrs_free(msrs);
  	msrs = NULL;
7d6034d32   Doug Thompson   amd64_edac: add m...
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
  }
  
  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");