Blame view

drivers/edac/ghes_edac.c 14 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>
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
15
  #include "edac_core.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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  /* 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;
  };
  
  char *memory_type[] = {
  	[MEM_EMPTY] = "EMPTY",
  	[MEM_RESERVED] = "RESERVED",
  	[MEM_UNKNOWN] = "UNKNOWN",
  	[MEM_FPM] = "FPM",
  	[MEM_EDO] = "EDO",
  	[MEM_BEDO] = "BEDO",
  	[MEM_SDR] = "SDR",
  	[MEM_RDR] = "RDR",
  	[MEM_DDR] = "DDR",
  	[MEM_RDDR] = "RDDR",
  	[MEM_RMBS] = "RMBS",
  	[MEM_DDR2] = "DDR2",
  	[MEM_FB_DDR2] = "FB_DDR2",
  	[MEM_RDDR2] = "RDDR2",
  	[MEM_XDR] = "XDR",
  	[MEM_DDR3] = "DDR3",
  	[MEM_RDDR3] = "RDDR3",
  };
  
  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...
106
107
108
  			pr_info("Can't get DIMM%i size
  ",
  				dimm_fill->count);
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  			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...
173
174
  			edac_dbg(1, "DIMM%i: %s size = %d MB%s
  ",
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
175
176
177
  				dimm_fill->count, memory_type[dimm->mtype],
  				PAGES_TO_MiB(dimm->nr_pages),
  				(dimm->edac_mode != EDAC_NONE) ? "(ECC)" : "");
d2a685661   Mauro Carvalho Chehab   ghes_edac: Improv...
178
179
  			edac_dbg(2, "\ttype %d, detail 0x%02x, width %d(total %d)
  ",
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
180
181
182
183
184
185
186
  				entry->memory_type, entry->type_detail,
  				entry->total_width, entry->data_width);
  		}
  
  		dimm_fill->count++;
  	}
  }
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
187
  void ghes_edac_report_mem_error(struct ghes *ghes, int sev,
f04c62a70   Mauro Carvalho Chehab   ghes_edac: add su...
188
  				struct cper_sec_mem_err *mem_err)
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
189
  {
f04c62a70   Mauro Carvalho Chehab   ghes_edac: add su...
190
191
192
193
  	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...
194
  	char *p;
8ae8f50ad   Mauro Carvalho Chehab   ghes_edac: Fix RA...
195
  	u8 grain_bits;
f04c62a70   Mauro Carvalho Chehab   ghes_edac: add su...
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
  
  	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...
212
213
214
215
216
217
218
219
  	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...
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
  
  	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...
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
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
  	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:...
300
  	if (mem_err->validation_bits & CPER_MEM_VALID_PA) {
689c9cd81   Mauro Carvalho Chehab   ghes_edac: Make i...
301
302
303
304
305
  		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:...
306
  	if (mem_err->validation_bits & CPER_MEM_VALID_PA_MASK)
689c9cd81   Mauro Carvalho Chehab   ghes_edac: Make i...
307
  		e->grain = ~(mem_err->physical_addr_mask & ~PAGE_MASK);
689c9cd81   Mauro Carvalho Chehab   ghes_edac: Make i...
308
309
310
311
312
313
314
315
316
  
  	/* 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...
317
318
  	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...
319
320
321
322
323
324
325
326
  	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...
327
328
329
330
331
332
333
334
335
  	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...
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
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
  	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...
413

8ae8f50ad   Mauro Carvalho Chehab   ghes_edac: Fix RA...
414
415
  	/* Generate the trace event */
  	grain_bits = fls_long(e->grain);
665aa8cdc   Dan Carpenter   ghes_edac: Use sn...
416
417
  	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...
418
419
420
421
422
423
  	trace_mc_event(type, e->msg, e->label, e->error_count,
  		       mci->mc_idx, e->top_layer, e->mid_layer, e->low_layer,
  		       PAGES_TO_MiB(e->page_frame_number) | e->offset_in_page,
  		       grain_bits, e->syndrome, pvt->detail_location);
  
  	/* Report the error via EDAC API */
f04c62a70   Mauro Carvalho Chehab   ghes_edac: add su...
424
  	edac_raw_mc_handle_error(type, mci, e);
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
425
426
427
428
429
  }
  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...
430
431
  	bool fake = false;
  	int rc, num_dimm = 0;
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
432
433
  	struct mem_ctl_info *mci;
  	struct edac_mc_layer layers[1];
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
434
  	struct ghes_edac_pvt *pvt;
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
435
436
437
438
439
440
441
442
443
444
  	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...
445
446
  
  	layers[0].type = EDAC_MC_LAYER_ALL_MEM;
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
447
  	layers[0].size = num_dimm;
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
448
449
450
451
452
453
454
455
456
457
  	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...
458
459
  		pr_info("Can't allocate memory for EDAC data
  ");
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
460
461
462
463
464
465
  		mutex_unlock(&ghes_edac_lock);
  		return -ENOMEM;
  	}
  
  	pvt = mci->pvt_info;
  	memset(pvt, 0, sizeof(*pvt));
f04c62a70   Mauro Carvalho Chehab   ghes_edac: add su...
466
  	list_add_tail(&pvt->list, &ghes_reglist);
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
467
468
469
470
471
472
473
474
475
476
477
  	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...
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
  	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...
502
  	if (!fake) {
5ee726db5   Mauro Carvalho Chehab   ghes_edac: Don't ...
503
504
505
506
507
508
509
510
511
512
513
514
515
  		/*
  		 * 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...
516
517
518
  	} 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...
519

d2a685661   Mauro Carvalho Chehab   ghes_edac: Improv...
520
  		dimm->nr_pages = 1;
32fa1f53c   Mauro Carvalho Chehab   ghes_edac: do a b...
521
522
523
524
525
  		dimm->grain = 128;
  		dimm->mtype = MEM_UNKNOWN;
  		dimm->dtype = DEV_UNKNOWN;
  		dimm->edac_mode = EDAC_SECDED;
  	}
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
526
527
528
  
  	rc = edac_mc_add_mc(mci);
  	if (rc < 0) {
d2a685661   Mauro Carvalho Chehab   ghes_edac: Improv...
529
530
  		pr_info("Can't register at EDAC core
  ");
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
531
532
533
534
535
536
537
538
539
540
541
542
543
544
  		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...
545
  	struct ghes_edac_pvt *pvt, *tmp;
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
546

5dae92a71   Wei Yongjun   ghes_edac: fix to...
547
  	list_for_each_entry_safe(pvt, tmp, &ghes_reglist, list) {
77c5f5d2f   Mauro Carvalho Chehab   ghes_edac: Regist...
548
549
550
551
552
553
554
555
556
  		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);