Blame view

drivers/edac/ghes_edac.c 13.6 KB
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
1
2
3
4
5
6
  /*
   * GHES/EDAC Linux driver
   *
   * This file may be distributed under the terms of the GNU General Public
   * License version 2.
   *
37e59f876   Mauro Carvalho Chehab   [media, edac] Cha...
7
   * Copyright (c) 2013 by Mauro Carvalho Chehab
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
8
9
10
   *
   * Red Hat Inc. http://www.redhat.com
   */
d2a685661   Mauro Carvalho Chehab   ghes_edac: Improv...
11
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
12
13
  #include <acpi/ghes.h>
  #include <linux/edac.h>
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
14
  #include <linux/dmi.h>
78d88e8a3   Mauro Carvalho Chehab   edac: rename edac...
15
  #include "edac_module.h"
8ae8f50ad   Mauro Carvalho Chehab   ghes_edac: Fix RA...
16
  #include <ras/ras_event.h>
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
17

77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
18
19
20
21
22
23
  #define GHES_EDAC_REVISION " Ver: 1.0.0"
  
  struct ghes_edac_pvt {
  	struct list_head list;
  	struct ghes *ghes;
  	struct mem_ctl_info *mci;
689c9cd81   Mauro Carvalho Chehab   ghes_edac: Make i...
24
25
  
  	/* Buffers for the error handling routine */
8ae8f50ad   Mauro Carvalho Chehab   ghes_edac: Fix RA...
26
  	char detail_location[240];
689c9cd81   Mauro Carvalho Chehab   ghes_edac: Make i...
27
28
  	char other_detail[160];
  	char msg[80];
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
29
30
31
32
33
  };
  
  static LIST_HEAD(ghes_reglist);
  static DEFINE_MUTEX(ghes_edac_lock);
  static int ghes_edac_mc_num;
d2a685661   Mauro Carvalho Chehab   ghes_edac: Improv...
34

32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  /* Memory Device - Type 17 of SMBIOS spec */
  struct memdev_dmi_entry {
  	u8 type;
  	u8 length;
  	u16 handle;
  	u16 phys_mem_array_handle;
  	u16 mem_err_info_handle;
  	u16 total_width;
  	u16 data_width;
  	u16 size;
  	u8 form_factor;
  	u8 device_set;
  	u8 device_locator;
  	u8 bank_locator;
  	u8 memory_type;
  	u16 type_detail;
  	u16 speed;
  	u8 manufacturer;
  	u8 serial_number;
  	u8 asset_tag;
  	u8 part_number;
  	u8 attributes;
  	u32 extended_size;
  	u16 conf_mem_clk_speed;
  } __attribute__((__packed__));
  
  struct ghes_edac_dimm_fill {
  	struct mem_ctl_info *mci;
  	unsigned count;
  };
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  static void ghes_edac_count_dimms(const struct dmi_header *dh, void *arg)
  {
  	int *num_dimm = arg;
  
  	if (dh->type == DMI_ENTRY_MEM_DEVICE)
  		(*num_dimm)++;
  }
  
  static void ghes_edac_dmidecode(const struct dmi_header *dh, void *arg)
  {
  	struct ghes_edac_dimm_fill *dimm_fill = arg;
  	struct mem_ctl_info *mci = dimm_fill->mci;
  
  	if (dh->type == DMI_ENTRY_MEM_DEVICE) {
  		struct memdev_dmi_entry *entry = (struct memdev_dmi_entry *)dh;
  		struct dimm_info *dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms,
  						       mci->n_layers,
  						       dimm_fill->count, 0, 0);
  
  		if (entry->size == 0xffff) {
d2a685661   Mauro Carvalho Chehab   ghes_edac: Improv...
85
86
87
  			pr_info("Can't get DIMM%i size
  ",
  				dimm_fill->count);
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  			dimm->nr_pages = MiB_TO_PAGES(32);/* Unknown */
  		} else if (entry->size == 0x7fff) {
  			dimm->nr_pages = MiB_TO_PAGES(entry->extended_size);
  		} else {
  			if (entry->size & 1 << 15)
  				dimm->nr_pages = MiB_TO_PAGES((entry->size &
  							       0x7fff) << 10);
  			else
  				dimm->nr_pages = MiB_TO_PAGES(entry->size);
  		}
  
  		switch (entry->memory_type) {
  		case 0x12:
  			if (entry->type_detail & 1 << 13)
  				dimm->mtype = MEM_RDDR;
  			else
  				dimm->mtype = MEM_DDR;
  			break;
  		case 0x13:
  			if (entry->type_detail & 1 << 13)
  				dimm->mtype = MEM_RDDR2;
  			else
  				dimm->mtype = MEM_DDR2;
  			break;
  		case 0x14:
  			dimm->mtype = MEM_FB_DDR2;
  			break;
  		case 0x18:
  			if (entry->type_detail & 1 << 13)
  				dimm->mtype = MEM_RDDR3;
  			else
  				dimm->mtype = MEM_DDR3;
  			break;
  		default:
  			if (entry->type_detail & 1 << 6)
  				dimm->mtype = MEM_RMBS;
  			else if ((entry->type_detail & ((1 << 7) | (1 << 13)))
  				 == ((1 << 7) | (1 << 13)))
  				dimm->mtype = MEM_RDR;
  			else if (entry->type_detail & 1 << 7)
  				dimm->mtype = MEM_SDR;
  			else if (entry->type_detail & 1 << 9)
  				dimm->mtype = MEM_EDO;
  			else
  				dimm->mtype = MEM_UNKNOWN;
  		}
  
  		/*
  		 * Actually, we can only detect if the memory has bits for
  		 * checksum or not
  		 */
  		if (entry->total_width == entry->data_width)
  			dimm->edac_mode = EDAC_NONE;
  		else
  			dimm->edac_mode = EDAC_SECDED;
  
  		dimm->dtype = DEV_UNKNOWN;
  		dimm->grain = 128;		/* Likely, worse case */
  
  		/*
  		 * FIXME: It shouldn't be hard to also fill the DIMM labels
  		 */
  
  		if (dimm->nr_pages) {
d2a685661   Mauro Carvalho Chehab   ghes_edac: Improv...
152
153
  			edac_dbg(1, "DIMM%i: %s size = %d MB%s
  ",
58a9c251c   Aravind Gopalakrishnan   EDAC, ghes_edac: ...
154
  				dimm_fill->count, edac_mem_types[dimm->mtype],
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
155
156
  				PAGES_TO_MiB(dimm->nr_pages),
  				(dimm->edac_mode != EDAC_NONE) ? "(ECC)" : "");
d2a685661   Mauro Carvalho Chehab   ghes_edac: Improv...
157
158
  			edac_dbg(2, "\ttype %d, detail 0x%02x, width %d(total %d)
  ",
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
159
160
161
162
163
164
165
  				entry->memory_type, entry->type_detail,
  				entry->total_width, entry->data_width);
  		}
  
  		dimm_fill->count++;
  	}
  }
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
166
  void ghes_edac_report_mem_error(struct ghes *ghes, int sev,
f04c62a70   Mauro Carvalho Chehab   ghes_edac: add su...
167
  				struct cper_sec_mem_err *mem_err)
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
168
  {
f04c62a70   Mauro Carvalho Chehab   ghes_edac: add su...
169
170
171
172
  	enum hw_event_mc_err_type type;
  	struct edac_raw_error_desc *e;
  	struct mem_ctl_info *mci;
  	struct ghes_edac_pvt *pvt = NULL;
689c9cd81   Mauro Carvalho Chehab   ghes_edac: Make i...
173
  	char *p;
8ae8f50ad   Mauro Carvalho Chehab   ghes_edac: Fix RA...
174
  	u8 grain_bits;
f04c62a70   Mauro Carvalho Chehab   ghes_edac: add su...
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  
  	list_for_each_entry(pvt, &ghes_reglist, list) {
  		if (ghes == pvt->ghes)
  			break;
  	}
  	if (!pvt) {
  		pr_err("Internal error: Can't find EDAC structure
  ");
  		return;
  	}
  	mci = pvt->mci;
  	e = &mci->error_desc;
  
  	/* Cleans the error report buffer */
  	memset(e, 0, sizeof (*e));
  	e->error_count = 1;
689c9cd81   Mauro Carvalho Chehab   ghes_edac: Make i...
191
192
193
194
195
196
197
198
  	strcpy(e->label, "unknown label");
  	e->msg = pvt->msg;
  	e->other_detail = pvt->other_detail;
  	e->top_layer = -1;
  	e->mid_layer = -1;
  	e->low_layer = -1;
  	*pvt->other_detail = '\0';
  	*pvt->msg = '\0';
f04c62a70   Mauro Carvalho Chehab   ghes_edac: add su...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
  
  	switch (sev) {
  	case GHES_SEV_CORRECTED:
  		type = HW_EVENT_ERR_CORRECTED;
  		break;
  	case GHES_SEV_RECOVERABLE:
  		type = HW_EVENT_ERR_UNCORRECTED;
  		break;
  	case GHES_SEV_PANIC:
  		type = HW_EVENT_ERR_FATAL;
  		break;
  	default:
  	case GHES_SEV_NO:
  		type = HW_EVENT_ERR_INFO;
  	}
689c9cd81   Mauro Carvalho Chehab   ghes_edac: Make i...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
  	edac_dbg(1, "error validation_bits: 0x%08llx
  ",
  		 (long long)mem_err->validation_bits);
  
  	/* Error type, mapped on e->msg */
  	if (mem_err->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
  		p = pvt->msg;
  		switch (mem_err->error_type) {
  		case 0:
  			p += sprintf(p, "Unknown");
  			break;
  		case 1:
  			p += sprintf(p, "No error");
  			break;
  		case 2:
  			p += sprintf(p, "Single-bit ECC");
  			break;
  		case 3:
  			p += sprintf(p, "Multi-bit ECC");
  			break;
  		case 4:
  			p += sprintf(p, "Single-symbol ChipKill ECC");
  			break;
  		case 5:
  			p += sprintf(p, "Multi-symbol ChipKill ECC");
  			break;
  		case 6:
  			p += sprintf(p, "Master abort");
  			break;
  		case 7:
  			p += sprintf(p, "Target abort");
  			break;
  		case 8:
  			p += sprintf(p, "Parity Error");
  			break;
  		case 9:
  			p += sprintf(p, "Watchdog timeout");
  			break;
  		case 10:
  			p += sprintf(p, "Invalid address");
  			break;
  		case 11:
  			p += sprintf(p, "Mirror Broken");
  			break;
  		case 12:
  			p += sprintf(p, "Memory Sparing");
  			break;
  		case 13:
  			p += sprintf(p, "Scrub corrected error");
  			break;
  		case 14:
  			p += sprintf(p, "Scrub uncorrected error");
  			break;
  		case 15:
  			p += sprintf(p, "Physical Memory Map-out event");
  			break;
  		default:
  			p += sprintf(p, "reserved error (%d)",
  				     mem_err->error_type);
  		}
  	} else {
  		strcpy(pvt->msg, "unknown error");
  	}
  
  	/* Error address */
147de1477   Chen, Gong   ACPI, APEI, CPER:...
279
  	if (mem_err->validation_bits & CPER_MEM_VALID_PA) {
689c9cd81   Mauro Carvalho Chehab   ghes_edac: Make i...
280
281
282
283
284
  		e->page_frame_number = mem_err->physical_addr >> PAGE_SHIFT;
  		e->offset_in_page = mem_err->physical_addr & ~PAGE_MASK;
  	}
  
  	/* Error grain */
147de1477   Chen, Gong   ACPI, APEI, CPER:...
285
  	if (mem_err->validation_bits & CPER_MEM_VALID_PA_MASK)
689c9cd81   Mauro Carvalho Chehab   ghes_edac: Make i...
286
  		e->grain = ~(mem_err->physical_addr_mask & ~PAGE_MASK);
689c9cd81   Mauro Carvalho Chehab   ghes_edac: Make i...
287
288
289
290
291
292
293
294
295
  
  	/* Memory error location, mapped on e->location */
  	p = e->location;
  	if (mem_err->validation_bits & CPER_MEM_VALID_NODE)
  		p += sprintf(p, "node:%d ", mem_err->node);
  	if (mem_err->validation_bits & CPER_MEM_VALID_CARD)
  		p += sprintf(p, "card:%d ", mem_err->card);
  	if (mem_err->validation_bits & CPER_MEM_VALID_MODULE)
  		p += sprintf(p, "module:%d ", mem_err->module);
56507694d   Chen, Gong   EDAC, GHES: Updat...
296
297
  	if (mem_err->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
  		p += sprintf(p, "rank:%d ", mem_err->rank);
689c9cd81   Mauro Carvalho Chehab   ghes_edac: Make i...
298
299
300
301
302
303
304
305
  	if (mem_err->validation_bits & CPER_MEM_VALID_BANK)
  		p += sprintf(p, "bank:%d ", mem_err->bank);
  	if (mem_err->validation_bits & CPER_MEM_VALID_ROW)
  		p += sprintf(p, "row:%d ", mem_err->row);
  	if (mem_err->validation_bits & CPER_MEM_VALID_COLUMN)
  		p += sprintf(p, "col:%d ", mem_err->column);
  	if (mem_err->validation_bits & CPER_MEM_VALID_BIT_POSITION)
  		p += sprintf(p, "bit_pos:%d ", mem_err->bit_pos);
56507694d   Chen, Gong   EDAC, GHES: Updat...
306
307
308
309
310
311
312
313
314
  	if (mem_err->validation_bits & CPER_MEM_VALID_MODULE_HANDLE) {
  		const char *bank = NULL, *device = NULL;
  		dmi_memdev_name(mem_err->mem_dev_handle, &bank, &device);
  		if (bank != NULL && device != NULL)
  			p += sprintf(p, "DIMM location:%s %s ", bank, device);
  		else
  			p += sprintf(p, "DIMM DMI handle: 0x%.4x ",
  				     mem_err->mem_dev_handle);
  	}
689c9cd81   Mauro Carvalho Chehab   ghes_edac: Make i...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
  	if (p > e->location)
  		*(p - 1) = '\0';
  
  	/* All other fields are mapped on e->other_detail */
  	p = pvt->other_detail;
  	if (mem_err->validation_bits & CPER_MEM_VALID_ERROR_STATUS) {
  		u64 status = mem_err->error_status;
  
  		p += sprintf(p, "status(0x%016llx): ", (long long)status);
  		switch ((status >> 8) & 0xff) {
  		case 1:
  			p += sprintf(p, "Error detected internal to the component ");
  			break;
  		case 16:
  			p += sprintf(p, "Error detected in the bus ");
  			break;
  		case 4:
  			p += sprintf(p, "Storage error in DRAM memory ");
  			break;
  		case 5:
  			p += sprintf(p, "Storage error in TLB ");
  			break;
  		case 6:
  			p += sprintf(p, "Storage error in cache ");
  			break;
  		case 7:
  			p += sprintf(p, "Error in one or more functional units ");
  			break;
  		case 8:
  			p += sprintf(p, "component failed self test ");
  			break;
  		case 9:
  			p += sprintf(p, "Overflow or undervalue of internal queue ");
  			break;
  		case 17:
  			p += sprintf(p, "Virtual address not found on IO-TLB or IO-PDIR ");
  			break;
  		case 18:
  			p += sprintf(p, "Improper access error ");
  			break;
  		case 19:
  			p += sprintf(p, "Access to a memory address which is not mapped to any component ");
  			break;
  		case 20:
  			p += sprintf(p, "Loss of Lockstep ");
  			break;
  		case 21:
  			p += sprintf(p, "Response not associated with a request ");
  			break;
  		case 22:
  			p += sprintf(p, "Bus parity error - must also set the A, C, or D Bits ");
  			break;
  		case 23:
  			p += sprintf(p, "Detection of a PATH_ERROR ");
  			break;
  		case 25:
  			p += sprintf(p, "Bus operation timeout ");
  			break;
  		case 26:
  			p += sprintf(p, "A read was issued to data that has been poisoned ");
  			break;
  		default:
  			p += sprintf(p, "reserved ");
  			break;
  		}
  	}
  	if (mem_err->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
  		p += sprintf(p, "requestorID: 0x%016llx ",
  			     (long long)mem_err->requestor_id);
  	if (mem_err->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
  		p += sprintf(p, "responderID: 0x%016llx ",
  			     (long long)mem_err->responder_id);
  	if (mem_err->validation_bits & CPER_MEM_VALID_TARGET_ID)
  		p += sprintf(p, "targetID: 0x%016llx ",
  			     (long long)mem_err->responder_id);
  	if (p > pvt->other_detail)
  		*(p - 1) = '\0';
f04c62a70   Mauro Carvalho Chehab   ghes_edac: add su...
392

8ae8f50ad   Mauro Carvalho Chehab   ghes_edac: Fix RA...
393
394
  	/* Generate the trace event */
  	grain_bits = fls_long(e->grain);
665aa8cdc   Dan Carpenter   ghes_edac: Use sn...
395
396
  	snprintf(pvt->detail_location, sizeof(pvt->detail_location),
  		 "APEI location: %s %s", e->location, e->other_detail);
8ae8f50ad   Mauro Carvalho Chehab   ghes_edac: Fix RA...
397
398
  	trace_mc_event(type, e->msg, e->label, e->error_count,
  		       mci->mc_idx, e->top_layer, e->mid_layer, e->low_layer,
990995bad   Tan Xiaojun   EDAC: Fix PAGES_T...
399
  		       (e->page_frame_number << PAGE_SHIFT) | e->offset_in_page,
8ae8f50ad   Mauro Carvalho Chehab   ghes_edac: Fix RA...
400
401
402
  		       grain_bits, e->syndrome, pvt->detail_location);
  
  	/* Report the error via EDAC API */
f04c62a70   Mauro Carvalho Chehab   ghes_edac: add su...
403
  	edac_raw_mc_handle_error(type, mci, e);
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
404
405
406
407
408
  }
  EXPORT_SYMBOL_GPL(ghes_edac_report_mem_error);
  
  int ghes_edac_register(struct ghes *ghes, struct device *dev)
  {
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
409
410
  	bool fake = false;
  	int rc, num_dimm = 0;
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
411
412
  	struct mem_ctl_info *mci;
  	struct edac_mc_layer layers[1];
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
413
  	struct ghes_edac_pvt *pvt;
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
414
415
416
417
418
419
420
421
422
423
  	struct ghes_edac_dimm_fill dimm_fill;
  
  	/* Get the number of DIMMs */
  	dmi_walk(ghes_edac_count_dimms, &num_dimm);
  
  	/* Check if we've got a bogus BIOS */
  	if (num_dimm == 0) {
  		fake = true;
  		num_dimm = 1;
  	}
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
424
425
  
  	layers[0].type = EDAC_MC_LAYER_ALL_MEM;
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
426
  	layers[0].size = num_dimm;
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
427
428
429
430
431
432
433
434
435
436
  	layers[0].is_virt_csrow = true;
  
  	/*
  	 * We need to serialize edac_mc_alloc() and edac_mc_add_mc(),
  	 * to avoid duplicated memory controller numbers
  	 */
  	mutex_lock(&ghes_edac_lock);
  	mci = edac_mc_alloc(ghes_edac_mc_num, ARRAY_SIZE(layers), layers,
  			    sizeof(*pvt));
  	if (!mci) {
d2a685661   Mauro Carvalho Chehab   ghes_edac: Improv...
437
438
  		pr_info("Can't allocate memory for EDAC data
  ");
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
439
440
441
442
443
444
  		mutex_unlock(&ghes_edac_lock);
  		return -ENOMEM;
  	}
  
  	pvt = mci->pvt_info;
  	memset(pvt, 0, sizeof(*pvt));
f04c62a70   Mauro Carvalho Chehab   ghes_edac: add su...
445
  	list_add_tail(&pvt->list, &ghes_reglist);
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
446
447
448
449
450
451
452
453
454
455
456
  	pvt->ghes = ghes;
  	pvt->mci  = mci;
  	mci->pdev = dev;
  
  	mci->mtype_cap = MEM_FLAG_EMPTY;
  	mci->edac_ctl_cap = EDAC_FLAG_NONE;
  	mci->edac_cap = EDAC_FLAG_NONE;
  	mci->mod_name = "ghes_edac.c";
  	mci->mod_ver = GHES_EDAC_REVISION;
  	mci->ctl_name = "ghes_edac";
  	mci->dev_name = "ghes";
d2a685661   Mauro Carvalho Chehab   ghes_edac: Improv...
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
  	if (!ghes_edac_mc_num) {
  		if (!fake) {
  			pr_info("This EDAC driver relies on BIOS to enumerate memory and get error reports.
  ");
  			pr_info("Unfortunately, not all BIOSes reflect the memory layout correctly.
  ");
  			pr_info("So, the end result of using this driver varies from vendor to vendor.
  ");
  			pr_info("If you find incorrect reports, please contact your hardware vendor
  ");
  			pr_info("to correct its BIOS.
  ");
  			pr_info("This system has %d DIMM sockets.
  ",
  				num_dimm);
  		} else {
  			pr_info("This system has a very crappy BIOS: It doesn't even list the DIMMS.
  ");
  			pr_info("Its SMBIOS info is wrong. It is doubtful that the error report would
  ");
  			pr_info("work on such system. Use this driver with caution
  ");
  		}
  	}
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
481
  	if (!fake) {
5ee726db5   Mauro Carvalho Chehab   ghes_edac: Don't ...
482
483
484
485
486
487
488
489
490
491
492
493
494
  		/*
  		 * Fill DIMM info from DMI for the memory controller #0
  		 *
  		 * Keep it in blank for the other memory controllers, as
  		 * there's no reliable way to properly credit each DIMM to
  		 * the memory controller, as different BIOSes fill the
  		 * DMI bank location fields on different ways
  		 */
  		if (!ghes_edac_mc_num) {
  			dimm_fill.count = 0;
  			dimm_fill.mci = mci;
  			dmi_walk(ghes_edac_dmidecode, &dimm_fill);
  		}
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
495
496
497
  	} else {
  		struct dimm_info *dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms,
  						       mci->n_layers, 0, 0, 0);
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
498

d2a685661   Mauro Carvalho Chehab   ghes_edac: Improv...
499
  		dimm->nr_pages = 1;
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
500
501
502
503
504
  		dimm->grain = 128;
  		dimm->mtype = MEM_UNKNOWN;
  		dimm->dtype = DEV_UNKNOWN;
  		dimm->edac_mode = EDAC_SECDED;
  	}
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
505
506
507
  
  	rc = edac_mc_add_mc(mci);
  	if (rc < 0) {
d2a685661   Mauro Carvalho Chehab   ghes_edac: Improv...
508
509
  		pr_info("Can't register at EDAC core
  ");
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
510
511
512
513
514
515
516
517
518
519
520
521
522
523
  		edac_mc_free(mci);
  		mutex_unlock(&ghes_edac_lock);
  		return -ENODEV;
  	}
  
  	ghes_edac_mc_num++;
  	mutex_unlock(&ghes_edac_lock);
  	return 0;
  }
  EXPORT_SYMBOL_GPL(ghes_edac_register);
  
  void ghes_edac_unregister(struct ghes *ghes)
  {
  	struct mem_ctl_info *mci;
5dae92a71   Wei Yongjun   ghes_edac: fix to...
524
  	struct ghes_edac_pvt *pvt, *tmp;
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
525

5dae92a71   Wei Yongjun   ghes_edac: fix to...
526
  	list_for_each_entry_safe(pvt, tmp, &ghes_reglist, list) {
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
527
528
529
530
531
532
533
534
535
  		if (ghes == pvt->ghes) {
  			mci = pvt->mci;
  			edac_mc_del_mc(mci->pdev);
  			edac_mc_free(mci);
  			list_del(&pvt->list);
  		}
  	}
  }
  EXPORT_SYMBOL_GPL(ghes_edac_unregister);