Blame view

drivers/edac/edac_mc.c 32.9 KB
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
1
2
  /*
   * edac_mc kernel module
49c0dab7e   Doug Thompson   [PATCH] Fix and e...
3
   * (C) 2005, 2006 Linux Networx (http://lnxi.com)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
4
5
6
7
8
9
10
11
12
13
   * This file may be distributed under the terms of the
   * GNU General Public License.
   *
   * Written by Thayne Harbaugh
   * Based on work by Dan Hollis <goemon at anime dot net> and others.
   *	http://www.anime.net/~goemon/linux-ecc/
   *
   * Modified by Dave Peterson and Doug Thompson
   *
   */
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
14
15
16
17
18
19
20
21
22
23
24
25
26
  #include <linux/module.h>
  #include <linux/proc_fs.h>
  #include <linux/kernel.h>
  #include <linux/types.h>
  #include <linux/smp.h>
  #include <linux/init.h>
  #include <linux/sysctl.h>
  #include <linux/highmem.h>
  #include <linux/timer.h>
  #include <linux/slab.h>
  #include <linux/jiffies.h>
  #include <linux/spinlock.h>
  #include <linux/list.h>
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
27
  #include <linux/ctype.h>
c0d121720   Dave Jiang   drivers/edac: add...
28
  #include <linux/edac.h>
53f2d0289   Mauro Carvalho Chehab   RAS: Add a tracep...
29
  #include <linux/bitops.h>
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
30
31
  #include <asm/uaccess.h>
  #include <asm/page.h>
20bcb7a81   Douglas Thompson   drivers/edac: mod...
32
  #include "edac_core.h"
7c9281d76   Douglas Thompson   drivers/edac: spl...
33
  #include "edac_module.h"
53f2d0289   Mauro Carvalho Chehab   RAS: Add a tracep...
34
  #include <ras/ras_event.h>
b01aec9b2   Borislav Petkov   EDAC: Cleanup ato...
35
36
37
38
39
  #ifdef CONFIG_EDAC_ATOMIC_SCRUB
  #include <asm/edac.h>
  #else
  #define edac_atomic_scrub(va, size) do { } while (0)
  #endif
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
40
  /* lock to memory controller's control array */
63b7df910   Matthias Kaehlcke   drivers/edac: cha...
41
  static DEFINE_MUTEX(mem_ctls_mutex);
ff6ac2a61   Robert P. J. Day   edac: use the sho...
42
  static LIST_HEAD(mc_devices);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
43

80cc7d87d   Mauro Carvalho Chehab   edac: lock module...
44
45
46
47
48
  /*
   * Used to lock EDAC MC to just one module, avoiding two drivers e. g.
   *	apei/ghes and i7core_edac to be used at the same time.
   */
  static void const *edac_mc_owner;
88d84ac97   Borislav Petkov   EDAC: Fix lockdep...
49
  static struct bus_type mc_bus[EDAC_MAX_MCS];
6e84d359b   Mauro Carvalho Chehab   edac_mc: Cleanup ...
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf,
  			         unsigned len)
  {
  	struct mem_ctl_info *mci = dimm->mci;
  	int i, n, count = 0;
  	char *p = buf;
  
  	for (i = 0; i < mci->n_layers; i++) {
  		n = snprintf(p, len, "%s %d ",
  			      edac_layer_name[mci->layers[i].type],
  			      dimm->location[i]);
  		p += n;
  		len -= n;
  		count += n;
  		if (!len)
  			break;
  	}
  
  	return count;
  }
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
70
  #ifdef CONFIG_EDAC_DEBUG
a4b4be3fd   Mauro Carvalho Chehab   edac: rename chan...
71
  static void edac_mc_dump_channel(struct rank_info *chan)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
72
  {
6e84d359b   Mauro Carvalho Chehab   edac_mc: Cleanup ...
73
74
75
76
77
78
79
80
  	edac_dbg(4, "  channel->chan_idx = %d
  ", chan->chan_idx);
  	edac_dbg(4, "    channel = %p
  ", chan);
  	edac_dbg(4, "    channel->csrow = %p
  ", chan->csrow);
  	edac_dbg(4, "    channel->dimm = %p
  ", chan->dimm);
4275be635   Mauro Carvalho Chehab   edac: Change inte...
81
  }
6e84d359b   Mauro Carvalho Chehab   edac_mc: Cleanup ...
82
  static void edac_mc_dump_dimm(struct dimm_info *dimm, int number)
4275be635   Mauro Carvalho Chehab   edac: Change inte...
83
  {
6e84d359b   Mauro Carvalho Chehab   edac_mc: Cleanup ...
84
85
86
87
88
89
  	char location[80];
  
  	edac_dimm_info_location(dimm, location, sizeof(location));
  
  	edac_dbg(4, "%s%i: %smapped as virtual row %d, chan %d
  ",
9713faecf   Mauro Carvalho Chehab   EDAC: Merge mci.m...
90
  		 dimm->mci->csbased ? "rank" : "dimm",
6e84d359b   Mauro Carvalho Chehab   edac_mc: Cleanup ...
91
92
93
94
95
96
97
98
99
100
101
  		 number, location, dimm->csrow, dimm->cschannel);
  	edac_dbg(4, "  dimm = %p
  ", dimm);
  	edac_dbg(4, "  dimm->label = '%s'
  ", dimm->label);
  	edac_dbg(4, "  dimm->nr_pages = 0x%x
  ", dimm->nr_pages);
  	edac_dbg(4, "  dimm->grain = %d
  ", dimm->grain);
  	edac_dbg(4, "  dimm->nr_pages = 0x%x
  ", dimm->nr_pages);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
102
  }
2da1c119f   Adrian Bunk   drivers/edac: cor...
103
  static void edac_mc_dump_csrow(struct csrow_info *csrow)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
104
  {
6e84d359b   Mauro Carvalho Chehab   edac_mc: Cleanup ...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  	edac_dbg(4, "csrow->csrow_idx = %d
  ", csrow->csrow_idx);
  	edac_dbg(4, "  csrow = %p
  ", csrow);
  	edac_dbg(4, "  csrow->first_page = 0x%lx
  ", csrow->first_page);
  	edac_dbg(4, "  csrow->last_page = 0x%lx
  ", csrow->last_page);
  	edac_dbg(4, "  csrow->page_mask = 0x%lx
  ", csrow->page_mask);
  	edac_dbg(4, "  csrow->nr_channels = %d
  ", csrow->nr_channels);
  	edac_dbg(4, "  csrow->channels = %p
  ", csrow->channels);
  	edac_dbg(4, "  csrow->mci = %p
  ", csrow->mci);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
121
  }
2da1c119f   Adrian Bunk   drivers/edac: cor...
122
  static void edac_mc_dump_mci(struct mem_ctl_info *mci)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
123
  {
956b9ba15   Joe Perches   edac: Convert deb...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  	edac_dbg(3, "\tmci = %p
  ", mci);
  	edac_dbg(3, "\tmci->mtype_cap = %lx
  ", mci->mtype_cap);
  	edac_dbg(3, "\tmci->edac_ctl_cap = %lx
  ", mci->edac_ctl_cap);
  	edac_dbg(3, "\tmci->edac_cap = %lx
  ", mci->edac_cap);
  	edac_dbg(4, "\tmci->edac_check = %p
  ", mci->edac_check);
  	edac_dbg(3, "\tmci->nr_csrows = %d, csrows = %p
  ",
  		 mci->nr_csrows, mci->csrows);
  	edac_dbg(3, "\tmci->nr_dimms = %d, dimms = %p
  ",
  		 mci->tot_dimms, mci->dimms);
  	edac_dbg(3, "\tdev = %p
  ", mci->pdev);
  	edac_dbg(3, "\tmod_name:ctl_name = %s:%s
  ",
  		 mci->mod_name, mci->ctl_name);
  	edac_dbg(3, "\tpvt_info = %p
  
  ", mci->pvt_info);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
148
  }
24f9a7fe3   Borislav Petkov   amd64_edac: Rewor...
149
  #endif				/* CONFIG_EDAC_DEBUG */
f4ce6eca7   Borislav Petkov   EDAC: Fix mem_typ...
150
  const char * const edac_mem_types[] = {
4cfc3a40f   Borislav Petkov   EDAC: Sync memory...
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  	[MEM_EMPTY]	= "Empty csrow",
  	[MEM_RESERVED]	= "Reserved csrow type",
  	[MEM_UNKNOWN]	= "Unknown csrow type",
  	[MEM_FPM]	= "Fast page mode RAM",
  	[MEM_EDO]	= "Extended data out RAM",
  	[MEM_BEDO]	= "Burst Extended data out RAM",
  	[MEM_SDR]	= "Single data rate SDRAM",
  	[MEM_RDR]	= "Registered single data rate SDRAM",
  	[MEM_DDR]	= "Double data rate SDRAM",
  	[MEM_RDDR]	= "Registered Double data rate SDRAM",
  	[MEM_RMBS]	= "Rambus DRAM",
  	[MEM_DDR2]	= "Unbuffered DDR2 RAM",
  	[MEM_FB_DDR2]	= "Fully buffered DDR2",
  	[MEM_RDDR2]	= "Registered DDR2 RAM",
  	[MEM_XDR]	= "Rambus XDR",
  	[MEM_DDR3]	= "Unbuffered DDR3 RAM",
  	[MEM_RDDR3]	= "Registered DDR3 RAM",
  	[MEM_LRDDR3]	= "Load-Reduced DDR3 RAM",
  	[MEM_DDR4]	= "Unbuffered DDR4 RAM",
  	[MEM_RDDR4]	= "Registered DDR4 RAM",
239642fe1   Borislav Petkov   edac: add memory ...
171
172
  };
  EXPORT_SYMBOL_GPL(edac_mem_types);
93e4fe64e   Mauro Carvalho Chehab   edac: rewrite eda...
173
174
175
176
177
178
  /**
   * edac_align_ptr - Prepares the pointer offsets for a single-shot allocation
   * @p:		pointer to a pointer with the memory offset to be used. At
   *		return, this will be incremented to point to the next offset
   * @size:	Size of the data structure to be reserved
   * @n_elems:	Number of elements that should be reserved
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
179
180
   *
   * If 'size' is a constant, the compiler will optimize this whole function
93e4fe64e   Mauro Carvalho Chehab   edac: rewrite eda...
181
182
183
184
185
186
187
188
189
   * down to either a no-op or the addition of a constant to the value of '*p'.
   *
   * The 'p' pointer is absolutely needed to keep the proper advancing
   * further in memory to the proper offsets when allocating the struct along
   * with its embedded structs, as edac_device_alloc_ctl_info() does it
   * above, for example.
   *
   * At return, the pointer 'p' will be incremented to be used on a next call
   * to this function.
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
190
   */
93e4fe64e   Mauro Carvalho Chehab   edac: rewrite eda...
191
  void *edac_align_ptr(void **p, unsigned size, int n_elems)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
192
193
  {
  	unsigned align, r;
93e4fe64e   Mauro Carvalho Chehab   edac: rewrite eda...
194
  	void *ptr = *p;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
195

93e4fe64e   Mauro Carvalho Chehab   edac: rewrite eda...
196
197
198
199
200
201
202
203
  	*p += size * n_elems;
  
  	/*
  	 * 'p' can possibly be an unaligned item X such that sizeof(X) is
  	 * 'size'.  Adjust 'p' so that its alignment is at least as
  	 * stringent as what the compiler would provide for X and return
  	 * the aligned result.
  	 * Here we assume that the alignment of a "long long" is the most
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
204
205
206
207
208
209
210
211
212
213
214
215
  	 * stringent alignment that the compiler will ever provide by default.
  	 * As far as I know, this is a reasonable assumption.
  	 */
  	if (size > sizeof(long))
  		align = sizeof(long long);
  	else if (size > sizeof(int))
  		align = sizeof(long);
  	else if (size > sizeof(short))
  		align = sizeof(int);
  	else if (size > sizeof(char))
  		align = sizeof(short);
  	else
079708b91   Douglas Thompson   drivers/edac: cor...
216
  		return (char *)ptr;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
217

8447c4d15   Chris Metcalf   edac: Do alignmen...
218
  	r = (unsigned long)p % align;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
219
220
  
  	if (r == 0)
079708b91   Douglas Thompson   drivers/edac: cor...
221
  		return (char *)ptr;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
222

93e4fe64e   Mauro Carvalho Chehab   edac: rewrite eda...
223
  	*p += align - r;
7391c6dca   Douglas Thompson   drivers/edac: mod...
224
  	return (void *)(((unsigned long)ptr) + align - r);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
225
  }
faa2ad09c   Shaun Ruffell   edac_mc: edac_mc_...
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
  static void _edac_mc_free(struct mem_ctl_info *mci)
  {
  	int i, chn, row;
  	struct csrow_info *csr;
  	const unsigned int tot_dimms = mci->tot_dimms;
  	const unsigned int tot_channels = mci->num_cschannel;
  	const unsigned int tot_csrows = mci->nr_csrows;
  
  	if (mci->dimms) {
  		for (i = 0; i < tot_dimms; i++)
  			kfree(mci->dimms[i]);
  		kfree(mci->dimms);
  	}
  	if (mci->csrows) {
  		for (row = 0; row < tot_csrows; row++) {
  			csr = mci->csrows[row];
  			if (csr) {
  				if (csr->channels) {
  					for (chn = 0; chn < tot_channels; chn++)
  						kfree(csr->channels[chn]);
  					kfree(csr->channels);
  				}
  				kfree(csr);
  			}
  		}
  		kfree(mci->csrows);
  	}
  	kfree(mci);
  }
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
255
  /**
4275be635   Mauro Carvalho Chehab   edac: Change inte...
256
257
258
259
260
261
   * edac_mc_alloc: Allocate and partially fill a struct mem_ctl_info structure
   * @mc_num:		Memory controller number
   * @n_layers:		Number of MC hierarchy layers
   * layers:		Describes each layer as seen by the Memory Controller
   * @size_pvt:		size of private storage needed
   *
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
262
263
264
265
266
267
268
   *
   * Everything is kmalloc'ed as one big chunk - more efficient.
   * Only can be used if all structures have the same lifetime - otherwise
   * you have to allocate and initialize your own structures.
   *
   * Use edac_mc_free() to free mc structures allocated by this function.
   *
4275be635   Mauro Carvalho Chehab   edac: Change inte...
269
270
271
272
273
274
   * NOTE: drivers handle multi-rank memories in different ways: in some
   * drivers, one multi-rank memory stick is mapped as one entry, while, in
   * others, a single multi-rank memory stick would be mapped into several
   * entries. Currently, this function will allocate multiple struct dimm_info
   * on such scenarios, as grouping the multiple ranks require drivers change.
   *
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
275
   * Returns:
ca0907b9e   Mauro Carvalho Chehab   edac: Remove the ...
276
277
   *	On failure: NULL
   *	On success: struct mem_ctl_info pointer
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
278
   */
ca0907b9e   Mauro Carvalho Chehab   edac: Remove the ...
279
280
281
282
  struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
  				   unsigned n_layers,
  				   struct edac_mc_layer *layers,
  				   unsigned sz_pvt)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
283
284
  {
  	struct mem_ctl_info *mci;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
285
  	struct edac_mc_layer *layer;
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
286
287
  	struct csrow_info *csr;
  	struct rank_info *chan;
a7d7d2e1a   Mauro Carvalho Chehab   edac: Create a di...
288
  	struct dimm_info *dimm;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
289
290
  	u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
  	unsigned pos[EDAC_MAX_LAYERS];
4275be635   Mauro Carvalho Chehab   edac: Change inte...
291
292
  	unsigned size, tot_dimms = 1, count = 1;
  	unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0;
5926ff502   Mauro Carvalho Chehab   edac: Initialize ...
293
  	void *pvt, *p, *ptr = NULL;
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
294
  	int i, j, row, chn, n, len, off;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
  	bool per_rank = false;
  
  	BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0);
  	/*
  	 * Calculate the total amount of dimms and csrows/cschannels while
  	 * in the old API emulation mode
  	 */
  	for (i = 0; i < n_layers; i++) {
  		tot_dimms *= layers[i].size;
  		if (layers[i].is_virt_csrow)
  			tot_csrows *= layers[i].size;
  		else
  			tot_channels *= layers[i].size;
  
  		if (layers[i].type == EDAC_MC_LAYER_CHIP_SELECT)
  			per_rank = true;
  	}
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
312
313
314
315
316
317
  
  	/* Figure out the offsets of the various items from the start of an mc
  	 * structure.  We want the alignment of each item to be at least as
  	 * stringent as what the compiler would provide if we could simply
  	 * hardcode everything into a single struct.
  	 */
93e4fe64e   Mauro Carvalho Chehab   edac: rewrite eda...
318
  	mci = edac_align_ptr(&ptr, sizeof(*mci), 1);
4275be635   Mauro Carvalho Chehab   edac: Change inte...
319
  	layer = edac_align_ptr(&ptr, sizeof(*layer), n_layers);
4275be635   Mauro Carvalho Chehab   edac: Change inte...
320
321
  	for (i = 0; i < n_layers; i++) {
  		count *= layers[i].size;
956b9ba15   Joe Perches   edac: Convert deb...
322
323
  		edac_dbg(4, "errcount layer %d size %d
  ", i, count);
4275be635   Mauro Carvalho Chehab   edac: Change inte...
324
325
326
327
  		ce_per_layer[i] = edac_align_ptr(&ptr, sizeof(u32), count);
  		ue_per_layer[i] = edac_align_ptr(&ptr, sizeof(u32), count);
  		tot_errcount += 2 * count;
  	}
956b9ba15   Joe Perches   edac: Convert deb...
328
329
  	edac_dbg(4, "allocating %d error counters
  ", tot_errcount);
93e4fe64e   Mauro Carvalho Chehab   edac: rewrite eda...
330
  	pvt = edac_align_ptr(&ptr, sz_pvt, 1);
079708b91   Douglas Thompson   drivers/edac: cor...
331
  	size = ((unsigned long)pvt) + sz_pvt;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
332

956b9ba15   Joe Perches   edac: Convert deb...
333
334
335
336
337
338
  	edac_dbg(1, "allocating %u bytes for mci data (%d %s, %d csrows/channels)
  ",
  		 size,
  		 tot_dimms,
  		 per_rank ? "ranks" : "dimms",
  		 tot_csrows * tot_channels);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
339

8096cfafb   Doug Thompson   drivers/edac: fix...
340
341
  	mci = kzalloc(size, GFP_KERNEL);
  	if (mci == NULL)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
342
343
344
345
346
  		return NULL;
  
  	/* Adjust pointers so they point within the memory we just allocated
  	 * rather than an imaginary chunk of memory located at address 0.
  	 */
4275be635   Mauro Carvalho Chehab   edac: Change inte...
347
  	layer = (struct edac_mc_layer *)(((char *)mci) + ((unsigned long)layer));
4275be635   Mauro Carvalho Chehab   edac: Change inte...
348
349
350
351
  	for (i = 0; i < n_layers; i++) {
  		mci->ce_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ce_per_layer[i]));
  		mci->ue_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ue_per_layer[i]));
  	}
079708b91   Douglas Thompson   drivers/edac: cor...
352
  	pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
353

b8f6f9755   Doug Thompson   drivers/edac: fix...
354
  	/* setup index and various internal pointers */
4275be635   Mauro Carvalho Chehab   edac: Change inte...
355
  	mci->mc_idx = mc_num;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
356
  	mci->tot_dimms = tot_dimms;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
357
  	mci->pvt_info = pvt;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
358
359
360
361
362
  	mci->n_layers = n_layers;
  	mci->layers = layer;
  	memcpy(mci->layers, layers, sizeof(*layer) * n_layers);
  	mci->nr_csrows = tot_csrows;
  	mci->num_cschannel = tot_channels;
9713faecf   Mauro Carvalho Chehab   EDAC: Merge mci.m...
363
  	mci->csbased = per_rank;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
364

a7d7d2e1a   Mauro Carvalho Chehab   edac: Create a di...
365
  	/*
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
366
  	 * Alocate and fill the csrow/channels structs
a7d7d2e1a   Mauro Carvalho Chehab   edac: Create a di...
367
  	 */
d3d09e182   Joe Perches   EDAC: Fix kcalloc...
368
  	mci->csrows = kcalloc(tot_csrows, sizeof(*mci->csrows), GFP_KERNEL);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
369
370
  	if (!mci->csrows)
  		goto error;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
371
  	for (row = 0; row < tot_csrows; row++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
372
373
374
375
  		csr = kzalloc(sizeof(**mci->csrows), GFP_KERNEL);
  		if (!csr)
  			goto error;
  		mci->csrows[row] = csr;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
376
377
378
  		csr->csrow_idx = row;
  		csr->mci = mci;
  		csr->nr_channels = tot_channels;
d3d09e182   Joe Perches   EDAC: Fix kcalloc...
379
  		csr->channels = kcalloc(tot_channels, sizeof(*csr->channels),
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
380
381
382
  					GFP_KERNEL);
  		if (!csr->channels)
  			goto error;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
383
384
  
  		for (chn = 0; chn < tot_channels; chn++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
385
386
387
388
  			chan = kzalloc(sizeof(**csr->channels), GFP_KERNEL);
  			if (!chan)
  				goto error;
  			csr->channels[chn] = chan;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
389
  			chan->chan_idx = chn;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
390
391
392
393
394
  			chan->csrow = csr;
  		}
  	}
  
  	/*
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
395
  	 * Allocate and fill the dimm structs
4275be635   Mauro Carvalho Chehab   edac: Change inte...
396
  	 */
d3d09e182   Joe Perches   EDAC: Fix kcalloc...
397
  	mci->dimms  = kcalloc(tot_dimms, sizeof(*mci->dimms), GFP_KERNEL);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
398
399
  	if (!mci->dimms)
  		goto error;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
400
401
402
  	memset(&pos, 0, sizeof(pos));
  	row = 0;
  	chn = 0;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
403
  	for (i = 0; i < tot_dimms; i++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
404
405
406
407
408
409
410
  		chan = mci->csrows[row]->channels[chn];
  		off = EDAC_DIMM_OFF(layer, n_layers, pos[0], pos[1], pos[2]);
  		if (off < 0 || off >= tot_dimms) {
  			edac_mc_printk(mci, KERN_ERR, "EDAC core bug: EDAC_DIMM_OFF is trying to do an illegal data access
  ");
  			goto error;
  		}
4275be635   Mauro Carvalho Chehab   edac: Change inte...
411

de3910eb7   Mauro Carvalho Chehab   edac: change the ...
412
  		dimm = kzalloc(sizeof(**mci->dimms), GFP_KERNEL);
08a4a1369   Dan Carpenter   edac_mc: check fo...
413
414
  		if (!dimm)
  			goto error;
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
415
  		mci->dimms[off] = dimm;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
416
  		dimm->mci = mci;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
417

5926ff502   Mauro Carvalho Chehab   edac: Initialize ...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
  		/*
  		 * Copy DIMM location and initialize it.
  		 */
  		len = sizeof(dimm->label);
  		p = dimm->label;
  		n = snprintf(p, len, "mc#%u", mc_num);
  		p += n;
  		len -= n;
  		for (j = 0; j < n_layers; j++) {
  			n = snprintf(p, len, "%s#%u",
  				     edac_layer_name[layers[j].type],
  				     pos[j]);
  			p += n;
  			len -= n;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
432
  			dimm->location[j] = pos[j];
5926ff502   Mauro Carvalho Chehab   edac: Initialize ...
433
434
435
  			if (len <= 0)
  				break;
  		}
4275be635   Mauro Carvalho Chehab   edac: Change inte...
436
437
438
439
440
441
  		/* Link it to the csrows old API data */
  		chan->dimm = dimm;
  		dimm->csrow = row;
  		dimm->cschannel = chn;
  
  		/* Increment csrow location */
24bef66e7   Mauro Carvalho Chehab   edac: Fix the dim...
442
  		if (layers[0].is_virt_csrow) {
4275be635   Mauro Carvalho Chehab   edac: Change inte...
443
  			chn++;
24bef66e7   Mauro Carvalho Chehab   edac: Fix the dim...
444
445
446
447
448
449
450
451
452
453
  			if (chn == tot_channels) {
  				chn = 0;
  				row++;
  			}
  		} else {
  			row++;
  			if (row == tot_csrows) {
  				row = 0;
  				chn++;
  			}
4275be635   Mauro Carvalho Chehab   edac: Change inte...
454
  		}
a7d7d2e1a   Mauro Carvalho Chehab   edac: Create a di...
455

4275be635   Mauro Carvalho Chehab   edac: Change inte...
456
457
458
459
460
461
  		/* Increment dimm location */
  		for (j = n_layers - 1; j >= 0; j--) {
  			pos[j]++;
  			if (pos[j] < layers[j].size)
  				break;
  			pos[j] = 0;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
462
463
  		}
  	}
81d87cb13   Dave Jiang   drivers/edac: mod...
464
  	mci->op_state = OP_ALLOC;
8096cfafb   Doug Thompson   drivers/edac: fix...
465

da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
466
  	return mci;
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
467
468
  
  error:
faa2ad09c   Shaun Ruffell   edac_mc: edac_mc_...
469
  	_edac_mc_free(mci);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
470
471
  
  	return NULL;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
472
  }
9110540f7   Dave Peterson   [PATCH] EDAC: use...
473
  EXPORT_SYMBOL_GPL(edac_mc_alloc);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
474

da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
475
  /**
8096cfafb   Doug Thompson   drivers/edac: fix...
476
477
   * edac_mc_free
   *	'Free' a previously allocated 'mci' structure
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
478
   * @mci: pointer to a struct mem_ctl_info structure
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
479
480
481
   */
  void edac_mc_free(struct mem_ctl_info *mci)
  {
956b9ba15   Joe Perches   edac: Convert deb...
482
483
  	edac_dbg(1, "
  ");
bbc560ae6   Mauro Carvalho Chehab   edac_core: Print ...
484

faa2ad09c   Shaun Ruffell   edac_mc: edac_mc_...
485
486
487
488
489
490
491
  	/* If we're not yet registered with sysfs free only what was allocated
  	 * in edac_mc_alloc().
  	 */
  	if (!device_is_registered(&mci->dev)) {
  		_edac_mc_free(mci);
  		return;
  	}
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
492
  	/* the mci instance is freed here, when the sysfs object is dropped */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
493
  	edac_unregister_sysfs(mci);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
494
  }
9110540f7   Dave Peterson   [PATCH] EDAC: use...
495
  EXPORT_SYMBOL_GPL(edac_mc_free);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
496

bce19683c   Doug Thompson   drivers/edac: fix...
497

939747bd6   Mauro Carvalho Chehab   i7core_edac: Be s...
498
  /**
bce19683c   Doug Thompson   drivers/edac: fix...
499
500
501
502
   * find_mci_by_dev
   *
   *	scan list of controllers looking for the one that manages
   *	the 'dev' device
939747bd6   Mauro Carvalho Chehab   i7core_edac: Be s...
503
   * @dev: pointer to a struct device related with the MCI
bce19683c   Doug Thompson   drivers/edac: fix...
504
   */
939747bd6   Mauro Carvalho Chehab   i7core_edac: Be s...
505
  struct mem_ctl_info *find_mci_by_dev(struct device *dev)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
506
507
508
  {
  	struct mem_ctl_info *mci;
  	struct list_head *item;
956b9ba15   Joe Perches   edac: Convert deb...
509
510
  	edac_dbg(3, "
  ");
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
511
512
513
  
  	list_for_each(item, &mc_devices) {
  		mci = list_entry(item, struct mem_ctl_info, link);
fd687502d   Mauro Carvalho Chehab   edac: Rename the ...
514
  		if (mci->pdev == dev)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
515
516
517
518
519
  			return mci;
  	}
  
  	return NULL;
  }
939747bd6   Mauro Carvalho Chehab   i7core_edac: Be s...
520
  EXPORT_SYMBOL_GPL(find_mci_by_dev);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
521

81d87cb13   Dave Jiang   drivers/edac: mod...
522
523
524
525
526
  /*
   * handler for EDAC to check if NMI type handler has asserted interrupt
   */
  static int edac_mc_assert_error_check_and_clear(void)
  {
66ee2f940   Dave Jiang   drivers/edac: mod...
527
  	int old_state;
81d87cb13   Dave Jiang   drivers/edac: mod...
528

079708b91   Douglas Thompson   drivers/edac: cor...
529
  	if (edac_op_state == EDAC_OPSTATE_POLL)
81d87cb13   Dave Jiang   drivers/edac: mod...
530
  		return 1;
66ee2f940   Dave Jiang   drivers/edac: mod...
531
532
  	old_state = edac_err_assert;
  	edac_err_assert = 0;
81d87cb13   Dave Jiang   drivers/edac: mod...
533

66ee2f940   Dave Jiang   drivers/edac: mod...
534
  	return old_state;
81d87cb13   Dave Jiang   drivers/edac: mod...
535
536
537
538
539
540
  }
  
  /*
   * edac_mc_workq_function
   *	performs the operation scheduled by a workq request
   */
81d87cb13   Dave Jiang   drivers/edac: mod...
541
542
  static void edac_mc_workq_function(struct work_struct *work_req)
  {
fbeb43847   Jean Delvare   edac: use to_dela...
543
  	struct delayed_work *d_work = to_delayed_work(work_req);
81d87cb13   Dave Jiang   drivers/edac: mod...
544
  	struct mem_ctl_info *mci = to_edac_mem_ctl_work(d_work);
81d87cb13   Dave Jiang   drivers/edac: mod...
545
546
  
  	mutex_lock(&mem_ctls_mutex);
06e912d4d   Borislav Petkov   EDAC: Cleanup/syn...
547
  	if (mci->op_state != OP_RUNNING_POLL) {
bf52fa4a2   Doug Thompson   drivers/edac: fix...
548
549
550
  		mutex_unlock(&mem_ctls_mutex);
  		return;
  	}
06e912d4d   Borislav Petkov   EDAC: Cleanup/syn...
551
  	if (edac_mc_assert_error_check_and_clear())
81d87cb13   Dave Jiang   drivers/edac: mod...
552
  		mci->edac_check(mci);
81d87cb13   Dave Jiang   drivers/edac: mod...
553
  	mutex_unlock(&mem_ctls_mutex);
06e912d4d   Borislav Petkov   EDAC: Cleanup/syn...
554
  	/* Queue ourselves again. */
c4cf3b454   Borislav Petkov   EDAC: Rework work...
555
  	edac_queue_work(&mci->work, msecs_to_jiffies(edac_mc_get_poll_msec()));
81d87cb13   Dave Jiang   drivers/edac: mod...
556
557
558
  }
  
  /*
bce19683c   Doug Thompson   drivers/edac: fix...
559
560
561
562
   * edac_mc_reset_delay_period(unsigned long value)
   *
   *	user space has updated our poll period value, need to
   *	reset our workq delays
81d87cb13   Dave Jiang   drivers/edac: mod...
563
   */
9da21b150   Borislav Petkov   EDAC: Poll timeou...
564
  void edac_mc_reset_delay_period(unsigned long value)
81d87cb13   Dave Jiang   drivers/edac: mod...
565
  {
bce19683c   Doug Thompson   drivers/edac: fix...
566
567
568
569
  	struct mem_ctl_info *mci;
  	struct list_head *item;
  
  	mutex_lock(&mem_ctls_mutex);
bce19683c   Doug Thompson   drivers/edac: fix...
570
571
  	list_for_each(item, &mc_devices) {
  		mci = list_entry(item, struct mem_ctl_info, link);
fbedcaf43   Nicholas Krause   EDAC: Fix workque...
572
573
  		if (mci->op_state == OP_RUNNING_POLL)
  			edac_mod_work(&mci->work, value);
bce19683c   Doug Thompson   drivers/edac: fix...
574
  	}
81d87cb13   Dave Jiang   drivers/edac: mod...
575
576
  	mutex_unlock(&mem_ctls_mutex);
  }
bce19683c   Doug Thompson   drivers/edac: fix...
577

2d7bbb91c   Doug Thompson   [PATCH] EDAC: mc ...
578
579
580
  /* Return 0 on success, 1 on failure.
   * Before calling this function, caller must
   * assign a unique value to mci->mc_idx.
bf52fa4a2   Doug Thompson   drivers/edac: fix...
581
582
583
584
   *
   *	locking model:
   *
   *		called with the mem_ctls_mutex lock held
2d7bbb91c   Doug Thompson   [PATCH] EDAC: mc ...
585
   */
079708b91   Douglas Thompson   drivers/edac: cor...
586
  static int add_mc_to_global_list(struct mem_ctl_info *mci)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
587
588
589
  {
  	struct list_head *item, *insert_before;
  	struct mem_ctl_info *p;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
590

2d7bbb91c   Doug Thompson   [PATCH] EDAC: mc ...
591
  	insert_before = &mc_devices;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
592

fd687502d   Mauro Carvalho Chehab   edac: Rename the ...
593
  	p = find_mci_by_dev(mci->pdev);
bf52fa4a2   Doug Thompson   drivers/edac: fix...
594
  	if (unlikely(p != NULL))
2d7bbb91c   Doug Thompson   [PATCH] EDAC: mc ...
595
  		goto fail0;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
596

2d7bbb91c   Doug Thompson   [PATCH] EDAC: mc ...
597
598
  	list_for_each(item, &mc_devices) {
  		p = list_entry(item, struct mem_ctl_info, link);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
599

2d7bbb91c   Doug Thompson   [PATCH] EDAC: mc ...
600
601
602
  		if (p->mc_idx >= mci->mc_idx) {
  			if (unlikely(p->mc_idx == mci->mc_idx))
  				goto fail1;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
603

2d7bbb91c   Doug Thompson   [PATCH] EDAC: mc ...
604
605
  			insert_before = item;
  			break;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
606
  		}
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
607
608
609
  	}
  
  	list_add_tail_rcu(&mci->link, insert_before);
c0d121720   Dave Jiang   drivers/edac: add...
610
  	atomic_inc(&edac_handlers);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
611
  	return 0;
2d7bbb91c   Doug Thompson   [PATCH] EDAC: mc ...
612

052dfb45c   Douglas Thompson   drivers/edac: cle...
613
  fail0:
2d7bbb91c   Doug Thompson   [PATCH] EDAC: mc ...
614
  	edac_printk(KERN_WARNING, EDAC_MC,
fd687502d   Mauro Carvalho Chehab   edac: Rename the ...
615
616
  		"%s (%s) %s %s already assigned %d
  ", dev_name(p->pdev),
17aa7e034   Stephen Rothwell   dev_name introduc...
617
  		edac_dev_name(mci), p->mod_name, p->ctl_name, p->mc_idx);
2d7bbb91c   Doug Thompson   [PATCH] EDAC: mc ...
618
  	return 1;
052dfb45c   Douglas Thompson   drivers/edac: cle...
619
  fail1:
2d7bbb91c   Doug Thompson   [PATCH] EDAC: mc ...
620
  	edac_printk(KERN_WARNING, EDAC_MC,
052dfb45c   Douglas Thompson   drivers/edac: cle...
621
622
623
624
  		"bug in low-level driver: attempt to assign
  "
  		"    duplicate mc_idx %d in %s()
  ", p->mc_idx, __func__);
2d7bbb91c   Doug Thompson   [PATCH] EDAC: mc ...
625
  	return 1;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
626
  }
80cc7d87d   Mauro Carvalho Chehab   edac: lock module...
627
  static int del_mc_from_global_list(struct mem_ctl_info *mci)
a1d03fcc1   Dave Peterson   [PATCH] EDAC: eda...
628
  {
80cc7d87d   Mauro Carvalho Chehab   edac: lock module...
629
  	int handlers = atomic_dec_return(&edac_handlers);
a1d03fcc1   Dave Peterson   [PATCH] EDAC: eda...
630
  	list_del_rcu(&mci->link);
e2e770987   Lai Jiangshan   edac,rcu: use syn...
631
632
633
634
635
636
  
  	/* these are for safe removal of devices from global list while
  	 * NMI handlers may be traversing list
  	 */
  	synchronize_rcu();
  	INIT_LIST_HEAD(&mci->link);
80cc7d87d   Mauro Carvalho Chehab   edac: lock module...
637
638
  
  	return handlers;
a1d03fcc1   Dave Peterson   [PATCH] EDAC: eda...
639
  }
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
640
  /**
5da0831c5   Douglas Thompson   drivers/edac: add...
641
642
643
644
645
646
647
   * edac_mc_find: Search for a mem_ctl_info structure whose index is 'idx'.
   *
   * If found, return a pointer to the structure.
   * Else return NULL.
   *
   * Caller must hold mem_ctls_mutex.
   */
079708b91   Douglas Thompson   drivers/edac: cor...
648
  struct mem_ctl_info *edac_mc_find(int idx)
5da0831c5   Douglas Thompson   drivers/edac: add...
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
  {
  	struct list_head *item;
  	struct mem_ctl_info *mci;
  
  	list_for_each(item, &mc_devices) {
  		mci = list_entry(item, struct mem_ctl_info, link);
  
  		if (mci->mc_idx >= idx) {
  			if (mci->mc_idx == idx)
  				return mci;
  
  			break;
  		}
  	}
  
  	return NULL;
  }
  EXPORT_SYMBOL(edac_mc_find);
  
  /**
4e8d230de   Takashi Iwai   EDAC: Allow to pa...
669
670
   * edac_mc_add_mc_with_groups: Insert the 'mci' structure into the mci
   *	global list and create sysfs entries associated with mci structure
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
671
   * @mci: pointer to the mci structure to be added to the list
4e8d230de   Takashi Iwai   EDAC: Allow to pa...
672
   * @groups: optional attribute groups for the driver-specific sysfs entries
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
673
674
675
676
677
678
679
   *
   * Return:
   *	0	Success
   *	!0	Failure
   */
  
  /* FIXME - should a warning be printed if no error detection? correction? */
4e8d230de   Takashi Iwai   EDAC: Allow to pa...
680
681
  int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
  			       const struct attribute_group **groups)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
682
  {
80cc7d87d   Mauro Carvalho Chehab   edac: lock module...
683
  	int ret = -EINVAL;
956b9ba15   Joe Perches   edac: Convert deb...
684
685
  	edac_dbg(0, "
  ");
b8f6f9755   Doug Thompson   drivers/edac: fix...
686

88d84ac97   Borislav Petkov   EDAC: Fix lockdep...
687
688
689
690
691
  	if (mci->mc_idx >= EDAC_MAX_MCS) {
  		pr_warn_once("Too many memory controllers: %d
  ", mci->mc_idx);
  		return -ENODEV;
  	}
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
692
693
694
  #ifdef CONFIG_EDAC_DEBUG
  	if (edac_debug_level >= 3)
  		edac_mc_dump_mci(mci);
e7ecd8910   Dave Peterson   [PATCH] EDAC: for...
695

da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
696
697
698
699
  	if (edac_debug_level >= 4) {
  		int i;
  
  		for (i = 0; i < mci->nr_csrows; i++) {
6e84d359b   Mauro Carvalho Chehab   edac_mc: Cleanup ...
700
701
  			struct csrow_info *csrow = mci->csrows[i];
  			u32 nr_pages = 0;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
702
  			int j;
e7ecd8910   Dave Peterson   [PATCH] EDAC: for...
703

6e84d359b   Mauro Carvalho Chehab   edac_mc: Cleanup ...
704
705
706
707
708
709
710
711
  			for (j = 0; j < csrow->nr_channels; j++)
  				nr_pages += csrow->channels[j]->dimm->nr_pages;
  			if (!nr_pages)
  				continue;
  			edac_mc_dump_csrow(csrow);
  			for (j = 0; j < csrow->nr_channels; j++)
  				if (csrow->channels[j]->dimm->nr_pages)
  					edac_mc_dump_channel(csrow->channels[j]);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
712
  		}
4275be635   Mauro Carvalho Chehab   edac: Change inte...
713
  		for (i = 0; i < mci->tot_dimms; i++)
6e84d359b   Mauro Carvalho Chehab   edac_mc: Cleanup ...
714
715
  			if (mci->dimms[i]->nr_pages)
  				edac_mc_dump_dimm(mci->dimms[i], i);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
716
717
  	}
  #endif
63b7df910   Matthias Kaehlcke   drivers/edac: cha...
718
  	mutex_lock(&mem_ctls_mutex);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
719

80cc7d87d   Mauro Carvalho Chehab   edac: lock module...
720
721
722
723
  	if (edac_mc_owner && edac_mc_owner != mci->mod_name) {
  		ret = -EPERM;
  		goto fail0;
  	}
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
724
  	if (add_mc_to_global_list(mci))
028a7b6d3   Dave Peterson   [PATCH] EDAC: eda...
725
  		goto fail0;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
726
727
728
  
  	/* set load time so that error rate can be tracked */
  	mci->start_time = jiffies;
88d84ac97   Borislav Petkov   EDAC: Fix lockdep...
729
  	mci->bus = &mc_bus[mci->mc_idx];
4e8d230de   Takashi Iwai   EDAC: Allow to pa...
730
  	if (edac_create_sysfs_mci_device(mci, groups)) {
9794f33dd   eric wollesen   [PATCH] EDAC: Add...
731
  		edac_mc_printk(mci, KERN_WARNING,
052dfb45c   Douglas Thompson   drivers/edac: cle...
732
733
  			"failed to create sysfs device
  ");
9794f33dd   eric wollesen   [PATCH] EDAC: Add...
734
735
  		goto fail1;
  	}
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
736

096676061   Borislav Petkov   EDAC: Balance wor...
737
  	if (mci->edac_check) {
81d87cb13   Dave Jiang   drivers/edac: mod...
738
  		mci->op_state = OP_RUNNING_POLL;
626a7a4db   Borislav Petkov   EDAC: Kill workqu...
739
740
  		INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
  		edac_queue_work(&mci->work, msecs_to_jiffies(edac_mc_get_poll_msec()));
81d87cb13   Dave Jiang   drivers/edac: mod...
741
742
743
  	} else {
  		mci->op_state = OP_RUNNING_INTERRUPT;
  	}
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
744
  	/* Report action taken */
7270a6085   Robert Richter   edac: Unify repor...
745
746
747
748
749
  	edac_mc_printk(mci, KERN_INFO,
  		"Giving out device to module %s controller %s: DEV %s (%s)
  ",
  		mci->mod_name, mci->ctl_name, mci->dev_name,
  		edac_op_state_to_string(mci->op_state));
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
750

80cc7d87d   Mauro Carvalho Chehab   edac: lock module...
751
  	edac_mc_owner = mci->mod_name;
63b7df910   Matthias Kaehlcke   drivers/edac: cha...
752
  	mutex_unlock(&mem_ctls_mutex);
028a7b6d3   Dave Peterson   [PATCH] EDAC: eda...
753
  	return 0;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
754

052dfb45c   Douglas Thompson   drivers/edac: cle...
755
  fail1:
028a7b6d3   Dave Peterson   [PATCH] EDAC: eda...
756
  	del_mc_from_global_list(mci);
052dfb45c   Douglas Thompson   drivers/edac: cle...
757
  fail0:
63b7df910   Matthias Kaehlcke   drivers/edac: cha...
758
  	mutex_unlock(&mem_ctls_mutex);
80cc7d87d   Mauro Carvalho Chehab   edac: lock module...
759
  	return ret;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
760
  }
4e8d230de   Takashi Iwai   EDAC: Allow to pa...
761
  EXPORT_SYMBOL_GPL(edac_mc_add_mc_with_groups);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
762

da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
763
  /**
472678ebd   Dave Peterson   [PATCH] EDAC: kob...
764
765
   * edac_mc_del_mc: Remove sysfs entries for specified mci structure and
   *                 remove mci structure from global list
37f04581a   Doug Thompson   [PATCH] EDAC: PCI...
766
   * @pdev: Pointer to 'struct device' representing mci structure to remove.
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
767
   *
18dbc337a   Dave Peterson   [PATCH] EDAC: pro...
768
   * Return pointer to removed mci structure, or NULL if device not found.
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
769
   */
079708b91   Douglas Thompson   drivers/edac: cor...
770
  struct mem_ctl_info *edac_mc_del_mc(struct device *dev)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
771
  {
18dbc337a   Dave Peterson   [PATCH] EDAC: pro...
772
  	struct mem_ctl_info *mci;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
773

956b9ba15   Joe Perches   edac: Convert deb...
774
775
  	edac_dbg(0, "
  ");
bf52fa4a2   Doug Thompson   drivers/edac: fix...
776

63b7df910   Matthias Kaehlcke   drivers/edac: cha...
777
  	mutex_lock(&mem_ctls_mutex);
18dbc337a   Dave Peterson   [PATCH] EDAC: pro...
778

bf52fa4a2   Doug Thompson   drivers/edac: fix...
779
780
781
  	/* find the requested mci struct in the global list */
  	mci = find_mci_by_dev(dev);
  	if (mci == NULL) {
63b7df910   Matthias Kaehlcke   drivers/edac: cha...
782
  		mutex_unlock(&mem_ctls_mutex);
18dbc337a   Dave Peterson   [PATCH] EDAC: pro...
783
784
  		return NULL;
  	}
096676061   Borislav Petkov   EDAC: Balance wor...
785
786
  	/* mark MCI offline: */
  	mci->op_state = OP_OFFLINE;
80cc7d87d   Mauro Carvalho Chehab   edac: lock module...
787
788
  	if (!del_mc_from_global_list(mci))
  		edac_mc_owner = NULL;
bf52fa4a2   Doug Thompson   drivers/edac: fix...
789

096676061   Borislav Petkov   EDAC: Balance wor...
790
  	mutex_unlock(&mem_ctls_mutex);
bb31b3122   Borislav Petkov   EDAC: Fix workque...
791

096676061   Borislav Petkov   EDAC: Balance wor...
792
  	if (mci->edac_check)
626a7a4db   Borislav Petkov   EDAC: Kill workqu...
793
  		edac_stop_work(&mci->work);
bb31b3122   Borislav Petkov   EDAC: Fix workque...
794
795
  
  	/* remove from sysfs */
bf52fa4a2   Doug Thompson   drivers/edac: fix...
796
  	edac_remove_sysfs_mci_device(mci);
537fba289   Dave Peterson   [PATCH] EDAC: pri...
797
  	edac_printk(KERN_INFO, EDAC_MC,
052dfb45c   Douglas Thompson   drivers/edac: cle...
798
799
  		"Removed device %d for %s %s: DEV %s
  ", mci->mc_idx,
17aa7e034   Stephen Rothwell   dev_name introduc...
800
  		mci->mod_name, mci->ctl_name, edac_dev_name(mci));
bf52fa4a2   Doug Thompson   drivers/edac: fix...
801

18dbc337a   Dave Peterson   [PATCH] EDAC: pro...
802
  	return mci;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
803
  }
9110540f7   Dave Peterson   [PATCH] EDAC: use...
804
  EXPORT_SYMBOL_GPL(edac_mc_del_mc);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
805

2da1c119f   Adrian Bunk   drivers/edac: cor...
806
807
  static void edac_mc_scrub_block(unsigned long page, unsigned long offset,
  				u32 size)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
808
809
810
811
  {
  	struct page *pg;
  	void *virt_addr;
  	unsigned long flags = 0;
956b9ba15   Joe Perches   edac: Convert deb...
812
813
  	edac_dbg(3, "
  ");
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
814
815
  
  	/* ECC error page was not in our memory. Ignore it. */
079708b91   Douglas Thompson   drivers/edac: cor...
816
  	if (!pfn_valid(page))
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
817
818
819
820
821
822
823
  		return;
  
  	/* Find the actual page structure then map it and fix */
  	pg = pfn_to_page(page);
  
  	if (PageHighMem(pg))
  		local_irq_save(flags);
4e5df7ca3   Cong Wang   edac: remove the ...
824
  	virt_addr = kmap_atomic(pg);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
825
826
  
  	/* Perform architecture specific atomic scrub operation */
b01aec9b2   Borislav Petkov   EDAC: Cleanup ato...
827
  	edac_atomic_scrub(virt_addr + offset, size);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
828
829
  
  	/* Unmap and complete */
4e5df7ca3   Cong Wang   edac: remove the ...
830
  	kunmap_atomic(virt_addr);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
831
832
833
834
  
  	if (PageHighMem(pg))
  		local_irq_restore(flags);
  }
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
835
  /* FIXME - should return -1 */
e7ecd8910   Dave Peterson   [PATCH] EDAC: for...
836
  int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
837
  {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
838
  	struct csrow_info **csrows = mci->csrows;
a895bf8b1   Mauro Carvalho Chehab   edac: move nr_pag...
839
  	int row, i, j, n;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
840

956b9ba15   Joe Perches   edac: Convert deb...
841
842
  	edac_dbg(1, "MC%d: 0x%lx
  ", mci->mc_idx, page);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
843
844
845
  	row = -1;
  
  	for (i = 0; i < mci->nr_csrows; i++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
846
  		struct csrow_info *csrow = csrows[i];
a895bf8b1   Mauro Carvalho Chehab   edac: move nr_pag...
847
848
  		n = 0;
  		for (j = 0; j < csrow->nr_channels; j++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
849
  			struct dimm_info *dimm = csrow->channels[j]->dimm;
a895bf8b1   Mauro Carvalho Chehab   edac: move nr_pag...
850
851
852
  			n += dimm->nr_pages;
  		}
  		if (n == 0)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
853
  			continue;
956b9ba15   Joe Perches   edac: Convert deb...
854
855
856
857
858
  		edac_dbg(3, "MC%d: first(0x%lx) page(0x%lx) last(0x%lx) mask(0x%lx)
  ",
  			 mci->mc_idx,
  			 csrow->first_page, page, csrow->last_page,
  			 csrow->page_mask);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
859
860
861
862
863
864
865
866
867
868
869
  
  		if ((page >= csrow->first_page) &&
  		    (page <= csrow->last_page) &&
  		    ((page & csrow->page_mask) ==
  		     (csrow->first_page & csrow->page_mask))) {
  			row = i;
  			break;
  		}
  	}
  
  	if (row == -1)
537fba289   Dave Peterson   [PATCH] EDAC: pri...
870
  		edac_mc_printk(mci, KERN_ERR,
052dfb45c   Douglas Thompson   drivers/edac: cle...
871
872
873
  			"could not look up page error address %lx
  ",
  			(unsigned long)page);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
874
875
876
  
  	return row;
  }
9110540f7   Dave Peterson   [PATCH] EDAC: use...
877
  EXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
878

4275be635   Mauro Carvalho Chehab   edac: Change inte...
879
880
881
882
883
  const char *edac_layer_name[] = {
  	[EDAC_MC_LAYER_BRANCH] = "branch",
  	[EDAC_MC_LAYER_CHANNEL] = "channel",
  	[EDAC_MC_LAYER_SLOT] = "slot",
  	[EDAC_MC_LAYER_CHIP_SELECT] = "csrow",
c66b5a79a   Mauro Carvalho Chehab   edac: add a new m...
884
  	[EDAC_MC_LAYER_ALL_MEM] = "memory",
4275be635   Mauro Carvalho Chehab   edac: Change inte...
885
886
887
888
  };
  EXPORT_SYMBOL_GPL(edac_layer_name);
  
  static void edac_inc_ce_error(struct mem_ctl_info *mci,
9eb07a7fb   Mauro Carvalho Chehab   edac: edac_mc_han...
889
890
891
  			      bool enable_per_layer_report,
  			      const int pos[EDAC_MAX_LAYERS],
  			      const u16 count)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
892
  {
4275be635   Mauro Carvalho Chehab   edac: Change inte...
893
  	int i, index = 0;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
894

9eb07a7fb   Mauro Carvalho Chehab   edac: edac_mc_han...
895
  	mci->ce_mc += count;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
896

4275be635   Mauro Carvalho Chehab   edac: Change inte...
897
  	if (!enable_per_layer_report) {
9eb07a7fb   Mauro Carvalho Chehab   edac: edac_mc_han...
898
  		mci->ce_noinfo_count += count;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
899
900
  		return;
  	}
e7ecd8910   Dave Peterson   [PATCH] EDAC: for...
901

4275be635   Mauro Carvalho Chehab   edac: Change inte...
902
903
904
905
  	for (i = 0; i < mci->n_layers; i++) {
  		if (pos[i] < 0)
  			break;
  		index += pos[i];
9eb07a7fb   Mauro Carvalho Chehab   edac: edac_mc_han...
906
  		mci->ce_per_layer[i][index] += count;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
907
908
909
910
911
912
913
914
  
  		if (i < mci->n_layers - 1)
  			index *= mci->layers[i + 1].size;
  	}
  }
  
  static void edac_inc_ue_error(struct mem_ctl_info *mci,
  				    bool enable_per_layer_report,
9eb07a7fb   Mauro Carvalho Chehab   edac: edac_mc_han...
915
916
  				    const int pos[EDAC_MAX_LAYERS],
  				    const u16 count)
4275be635   Mauro Carvalho Chehab   edac: Change inte...
917
918
  {
  	int i, index = 0;
9eb07a7fb   Mauro Carvalho Chehab   edac: edac_mc_han...
919
  	mci->ue_mc += count;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
920
921
  
  	if (!enable_per_layer_report) {
993f88f1c   Emmanouil Maroudas   EDAC: Increment c...
922
  		mci->ue_noinfo_count += count;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
923
924
  		return;
  	}
4275be635   Mauro Carvalho Chehab   edac: Change inte...
925
926
927
928
  	for (i = 0; i < mci->n_layers; i++) {
  		if (pos[i] < 0)
  			break;
  		index += pos[i];
9eb07a7fb   Mauro Carvalho Chehab   edac: edac_mc_han...
929
  		mci->ue_per_layer[i][index] += count;
a7d7d2e1a   Mauro Carvalho Chehab   edac: Create a di...
930

4275be635   Mauro Carvalho Chehab   edac: Change inte...
931
932
933
934
  		if (i < mci->n_layers - 1)
  			index *= mci->layers[i + 1].size;
  	}
  }
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
935

4275be635   Mauro Carvalho Chehab   edac: Change inte...
936
  static void edac_ce_error(struct mem_ctl_info *mci,
9eb07a7fb   Mauro Carvalho Chehab   edac: edac_mc_han...
937
  			  const u16 error_count,
4275be635   Mauro Carvalho Chehab   edac: Change inte...
938
939
940
941
942
943
944
945
946
  			  const int pos[EDAC_MAX_LAYERS],
  			  const char *msg,
  			  const char *location,
  			  const char *label,
  			  const char *detail,
  			  const char *other_detail,
  			  const bool enable_per_layer_report,
  			  const unsigned long page_frame_number,
  			  const unsigned long offset_in_page,
53f2d0289   Mauro Carvalho Chehab   RAS: Add a tracep...
947
  			  long grain)
4275be635   Mauro Carvalho Chehab   edac: Change inte...
948
949
  {
  	unsigned long remapped_page;
f430d5707   Borislav Petkov   EDAC: Handle empt...
950
951
952
953
  	char *msg_aux = "";
  
  	if (*msg)
  		msg_aux = " ";
4275be635   Mauro Carvalho Chehab   edac: Change inte...
954
955
956
957
  
  	if (edac_mc_get_log_ce()) {
  		if (other_detail && *other_detail)
  			edac_mc_printk(mci, KERN_WARNING,
f430d5707   Borislav Petkov   EDAC: Handle empt...
958
959
960
961
  				       "%d CE %s%son %s (%s %s - %s)
  ",
  				       error_count, msg, msg_aux, label,
  				       location, detail, other_detail);
4275be635   Mauro Carvalho Chehab   edac: Change inte...
962
963
  		else
  			edac_mc_printk(mci, KERN_WARNING,
f430d5707   Borislav Petkov   EDAC: Handle empt...
964
965
966
967
  				       "%d CE %s%son %s (%s %s)
  ",
  				       error_count, msg, msg_aux, label,
  				       location, detail);
4275be635   Mauro Carvalho Chehab   edac: Change inte...
968
  	}
9eb07a7fb   Mauro Carvalho Chehab   edac: edac_mc_han...
969
  	edac_inc_ce_error(mci, enable_per_layer_report, pos, error_count);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
970

aa2064d7d   Loc Ho   EDAC: Fix MC scru...
971
  	if (mci->scrub_mode == SCRUB_SW_SRC) {
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
972
  		/*
4275be635   Mauro Carvalho Chehab   edac: Change inte...
973
974
975
976
977
978
979
980
981
982
  			* Some memory controllers (called MCs below) can remap
  			* memory so that it is still available at a different
  			* address when PCI devices map into memory.
  			* MC's that can't do this, lose the memory where PCI
  			* devices are mapped. This mapping is MC-dependent
  			* and so we call back into the MC driver for it to
  			* map the MC page to a physical (CPU) page which can
  			* then be mapped to a virtual page - which can then
  			* be scrubbed.
  			*/
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
983
  		remapped_page = mci->ctl_page_to_phys ?
052dfb45c   Douglas Thompson   drivers/edac: cle...
984
985
  			mci->ctl_page_to_phys(mci, page_frame_number) :
  			page_frame_number;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
986

4275be635   Mauro Carvalho Chehab   edac: Change inte...
987
988
  		edac_mc_scrub_block(remapped_page,
  					offset_in_page, grain);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
989
990
  	}
  }
4275be635   Mauro Carvalho Chehab   edac: Change inte...
991
  static void edac_ue_error(struct mem_ctl_info *mci,
9eb07a7fb   Mauro Carvalho Chehab   edac: edac_mc_han...
992
  			  const u16 error_count,
4275be635   Mauro Carvalho Chehab   edac: Change inte...
993
994
995
996
997
998
999
  			  const int pos[EDAC_MAX_LAYERS],
  			  const char *msg,
  			  const char *location,
  			  const char *label,
  			  const char *detail,
  			  const char *other_detail,
  			  const bool enable_per_layer_report)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
1000
  {
f430d5707   Borislav Petkov   EDAC: Handle empt...
1001
1002
1003
1004
  	char *msg_aux = "";
  
  	if (*msg)
  		msg_aux = " ";
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1005
1006
1007
  	if (edac_mc_get_log_ue()) {
  		if (other_detail && *other_detail)
  			edac_mc_printk(mci, KERN_WARNING,
f430d5707   Borislav Petkov   EDAC: Handle empt...
1008
1009
1010
1011
  				       "%d UE %s%son %s (%s %s - %s)
  ",
  				       error_count, msg, msg_aux, label,
  				       location, detail, other_detail);
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1012
1013
  		else
  			edac_mc_printk(mci, KERN_WARNING,
f430d5707   Borislav Petkov   EDAC: Handle empt...
1014
1015
1016
1017
  				       "%d UE %s%son %s (%s %s)
  ",
  				       error_count, msg, msg_aux, label,
  				       location, detail);
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1018
  	}
e7ecd8910   Dave Peterson   [PATCH] EDAC: for...
1019

4275be635   Mauro Carvalho Chehab   edac: Change inte...
1020
1021
  	if (edac_mc_get_panic_on_ue()) {
  		if (other_detail && *other_detail)
f430d5707   Borislav Petkov   EDAC: Handle empt...
1022
1023
1024
  			panic("UE %s%son %s (%s%s - %s)
  ",
  			      msg, msg_aux, label, location, detail, other_detail);
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1025
  		else
f430d5707   Borislav Petkov   EDAC: Handle empt...
1026
1027
1028
  			panic("UE %s%son %s (%s%s)
  ",
  			      msg, msg_aux, label, location, detail);
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1029
  	}
9eb07a7fb   Mauro Carvalho Chehab   edac: edac_mc_han...
1030
  	edac_inc_ue_error(mci, enable_per_layer_report, pos, error_count);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
1031
  }
e7e248304   Mauro Carvalho Chehab   edac: add support...
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
  /**
   * edac_raw_mc_handle_error - reports a memory event to userspace without doing
   *			      anything to discover the error location
   *
   * @type:		severity of the error (CE/UE/Fatal)
   * @mci:		a struct mem_ctl_info pointer
   * @e:			error description
   *
   * This raw function is used internally by edac_mc_handle_error(). It should
   * only be called directly when the hardware error come directly from BIOS,
   * like in the case of APEI GHES driver.
   */
  void edac_raw_mc_handle_error(const enum hw_event_mc_err_type type,
  			      struct mem_ctl_info *mci,
  			      struct edac_raw_error_desc *e)
  {
  	char detail[80];
  	int pos[EDAC_MAX_LAYERS] = { e->top_layer, e->mid_layer, e->low_layer };
  
  	/* Memory type dependent details about the error */
  	if (type == HW_EVENT_ERR_CORRECTED) {
  		snprintf(detail, sizeof(detail),
  			"page:0x%lx offset:0x%lx grain:%ld syndrome:0x%lx",
  			e->page_frame_number, e->offset_in_page,
  			e->grain, e->syndrome);
  		edac_ce_error(mci, e->error_count, pos, e->msg, e->location, e->label,
  			      detail, e->other_detail, e->enable_per_layer_report,
  			      e->page_frame_number, e->offset_in_page, e->grain);
  	} else {
  		snprintf(detail, sizeof(detail),
  			"page:0x%lx offset:0x%lx grain:%ld",
  			e->page_frame_number, e->offset_in_page, e->grain);
  
  		edac_ue_error(mci, e->error_count, pos, e->msg, e->location, e->label,
  			      detail, e->other_detail, e->enable_per_layer_report);
  	}
  
  
  }
  EXPORT_SYMBOL_GPL(edac_raw_mc_handle_error);
53f2d0289   Mauro Carvalho Chehab   RAS: Add a tracep...
1072
1073
1074
1075
1076
1077
  
  /**
   * edac_mc_handle_error - reports a memory event to userspace
   *
   * @type:		severity of the error (CE/UE/Fatal)
   * @mci:		a struct mem_ctl_info pointer
9eb07a7fb   Mauro Carvalho Chehab   edac: edac_mc_han...
1078
   * @error_count:	Number of errors of the same type
53f2d0289   Mauro Carvalho Chehab   RAS: Add a tracep...
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
   * @page_frame_number:	mem page where the error occurred
   * @offset_in_page:	offset of the error inside the page
   * @syndrome:		ECC syndrome
   * @top_layer:		Memory layer[0] position
   * @mid_layer:		Memory layer[1] position
   * @low_layer:		Memory layer[2] position
   * @msg:		Message meaningful to the end users that
   *			explains the event
   * @other_detail:	Technical details about the event that
   *			may help hardware manufacturers and
   *			EDAC developers to analyse the event
53f2d0289   Mauro Carvalho Chehab   RAS: Add a tracep...
1090
   */
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1091
1092
  void edac_mc_handle_error(const enum hw_event_mc_err_type type,
  			  struct mem_ctl_info *mci,
9eb07a7fb   Mauro Carvalho Chehab   edac: edac_mc_han...
1093
  			  const u16 error_count,
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1094
1095
1096
  			  const unsigned long page_frame_number,
  			  const unsigned long offset_in_page,
  			  const unsigned long syndrome,
53f2d0289   Mauro Carvalho Chehab   RAS: Add a tracep...
1097
1098
1099
  			  const int top_layer,
  			  const int mid_layer,
  			  const int low_layer,
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1100
  			  const char *msg,
03f7eae80   Mauro Carvalho Chehab   edac: remove arch...
1101
  			  const char *other_detail)
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
1102
  {
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1103
1104
  	char *p;
  	int row = -1, chan = -1;
53f2d0289   Mauro Carvalho Chehab   RAS: Add a tracep...
1105
  	int pos[EDAC_MAX_LAYERS] = { top_layer, mid_layer, low_layer };
c7ef76455   Mauro Carvalho Chehab   edac: reduce stac...
1106
  	int i, n_labels = 0;
53f2d0289   Mauro Carvalho Chehab   RAS: Add a tracep...
1107
  	u8 grain_bits;
c7ef76455   Mauro Carvalho Chehab   edac: reduce stac...
1108
  	struct edac_raw_error_desc *e = &mci->error_desc;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
1109

956b9ba15   Joe Perches   edac: Convert deb...
1110
1111
  	edac_dbg(3, "MC%d
  ", mci->mc_idx);
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
1112

c7ef76455   Mauro Carvalho Chehab   edac: reduce stac...
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
  	/* Fills the error report buffer */
  	memset(e, 0, sizeof (*e));
  	e->error_count = error_count;
  	e->top_layer = top_layer;
  	e->mid_layer = mid_layer;
  	e->low_layer = low_layer;
  	e->page_frame_number = page_frame_number;
  	e->offset_in_page = offset_in_page;
  	e->syndrome = syndrome;
  	e->msg = msg;
  	e->other_detail = other_detail;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1124
1125
1126
1127
1128
1129
1130
1131
  	/*
  	 * Check if the event report is consistent and if the memory
  	 * location is known. If it is known, enable_per_layer_report will be
  	 * true, the DIMM(s) label info will be filled and the per-layer
  	 * error counters will be incremented.
  	 */
  	for (i = 0; i < mci->n_layers; i++) {
  		if (pos[i] >= (int)mci->layers[i].size) {
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
  
  			edac_mc_printk(mci, KERN_ERR,
  				       "INTERNAL ERROR: %s value is out of range (%d >= %d)
  ",
  				       edac_layer_name[mci->layers[i].type],
  				       pos[i], mci->layers[i].size);
  			/*
  			 * Instead of just returning it, let's use what's
  			 * known about the error. The increment routines and
  			 * the DIMM filter logic will do the right thing by
  			 * pointing the likely damaged DIMMs.
  			 */
  			pos[i] = -1;
  		}
  		if (pos[i] >= 0)
c7ef76455   Mauro Carvalho Chehab   edac: reduce stac...
1147
  			e->enable_per_layer_report = true;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
1148
  	}
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
  	/*
  	 * Get the dimm label/grain that applies to the match criteria.
  	 * As the error algorithm may not be able to point to just one memory
  	 * stick, the logic here will get all possible labels that could
  	 * pottentially be affected by the error.
  	 * On FB-DIMM memory controllers, for uncorrected errors, it is common
  	 * to have only the MC channel and the MC dimm (also called "branch")
  	 * but the channel is not known, as the memory is arranged in pairs,
  	 * where each memory belongs to a separate channel within the same
  	 * branch.
  	 */
c7ef76455   Mauro Carvalho Chehab   edac: reduce stac...
1160
  	p = e->label;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1161
  	*p = '\0';
4da1b7bfe   Borislav Petkov   EDAC: Remove usel...
1162

4275be635   Mauro Carvalho Chehab   edac: Change inte...
1163
  	for (i = 0; i < mci->tot_dimms; i++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
1164
  		struct dimm_info *dimm = mci->dimms[i];
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
1165

53f2d0289   Mauro Carvalho Chehab   RAS: Add a tracep...
1166
  		if (top_layer >= 0 && top_layer != dimm->location[0])
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1167
  			continue;
53f2d0289   Mauro Carvalho Chehab   RAS: Add a tracep...
1168
  		if (mid_layer >= 0 && mid_layer != dimm->location[1])
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1169
  			continue;
53f2d0289   Mauro Carvalho Chehab   RAS: Add a tracep...
1170
  		if (low_layer >= 0 && low_layer != dimm->location[2])
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1171
  			continue;
da9bb1d27   Alan Cox   [PATCH] EDAC: cor...
1172

4275be635   Mauro Carvalho Chehab   edac: Change inte...
1173
  		/* get the max grain, over the error match range */
c7ef76455   Mauro Carvalho Chehab   edac: reduce stac...
1174
1175
  		if (dimm->grain > e->grain)
  			e->grain = dimm->grain;
9794f33dd   eric wollesen   [PATCH] EDAC: Add...
1176

4275be635   Mauro Carvalho Chehab   edac: Change inte...
1177
1178
1179
1180
1181
1182
  		/*
  		 * If the error is memory-controller wide, there's no need to
  		 * seek for the affected DIMMs because the whole
  		 * channel/memory controller/...  may be affected.
  		 * Also, don't show errors for empty DIMM slots.
  		 */
c7ef76455   Mauro Carvalho Chehab   edac: reduce stac...
1183
1184
1185
1186
1187
1188
1189
  		if (e->enable_per_layer_report && dimm->nr_pages) {
  			if (n_labels >= EDAC_MAX_LABELS) {
  				e->enable_per_layer_report = false;
  				break;
  			}
  			n_labels++;
  			if (p != e->label) {
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
  				strcpy(p, OTHER_LABEL);
  				p += strlen(OTHER_LABEL);
  			}
  			strcpy(p, dimm->label);
  			p += strlen(p);
  			*p = '\0';
  
  			/*
  			 * get csrow/channel of the DIMM, in order to allow
  			 * incrementing the compat API counters
  			 */
956b9ba15   Joe Perches   edac: Convert deb...
1201
1202
  			edac_dbg(4, "%s csrows map: (%d,%d)
  ",
9713faecf   Mauro Carvalho Chehab   EDAC: Merge mci.m...
1203
  				 mci->csbased ? "rank" : "dimm",
956b9ba15   Joe Perches   edac: Convert deb...
1204
  				 dimm->csrow, dimm->cschannel);
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
  			if (row == -1)
  				row = dimm->csrow;
  			else if (row >= 0 && row != dimm->csrow)
  				row = -2;
  
  			if (chan == -1)
  				chan = dimm->cschannel;
  			else if (chan >= 0 && chan != dimm->cschannel)
  				chan = -2;
  		}
9794f33dd   eric wollesen   [PATCH] EDAC: Add...
1215
  	}
c7ef76455   Mauro Carvalho Chehab   edac: reduce stac...
1216
1217
  	if (!e->enable_per_layer_report) {
  		strcpy(e->label, "any memory");
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1218
  	} else {
956b9ba15   Joe Perches   edac: Convert deb...
1219
1220
  		edac_dbg(4, "csrow/channel to increment: (%d,%d)
  ", row, chan);
c7ef76455   Mauro Carvalho Chehab   edac: reduce stac...
1221
1222
  		if (p == e->label)
  			strcpy(e->label, "unknown memory");
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1223
1224
  		if (type == HW_EVENT_ERR_CORRECTED) {
  			if (row >= 0) {
9eb07a7fb   Mauro Carvalho Chehab   edac: edac_mc_han...
1225
  				mci->csrows[row]->ce_count += error_count;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1226
  				if (chan >= 0)
9eb07a7fb   Mauro Carvalho Chehab   edac: edac_mc_han...
1227
  					mci->csrows[row]->channels[chan]->ce_count += error_count;
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1228
1229
1230
  			}
  		} else
  			if (row >= 0)
9eb07a7fb   Mauro Carvalho Chehab   edac: edac_mc_han...
1231
  				mci->csrows[row]->ue_count += error_count;
9794f33dd   eric wollesen   [PATCH] EDAC: Add...
1232
  	}
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1233
  	/* Fill the RAM location data */
c7ef76455   Mauro Carvalho Chehab   edac: reduce stac...
1234
  	p = e->location;
4da1b7bfe   Borislav Petkov   EDAC: Remove usel...
1235

4275be635   Mauro Carvalho Chehab   edac: Change inte...
1236
1237
1238
  	for (i = 0; i < mci->n_layers; i++) {
  		if (pos[i] < 0)
  			continue;
9794f33dd   eric wollesen   [PATCH] EDAC: Add...
1239

4275be635   Mauro Carvalho Chehab   edac: Change inte...
1240
1241
1242
  		p += sprintf(p, "%s:%d ",
  			     edac_layer_name[mci->layers[i].type],
  			     pos[i]);
9794f33dd   eric wollesen   [PATCH] EDAC: Add...
1243
  	}
c7ef76455   Mauro Carvalho Chehab   edac: reduce stac...
1244
  	if (p > e->location)
53f2d0289   Mauro Carvalho Chehab   RAS: Add a tracep...
1245
1246
1247
  		*(p - 1) = '\0';
  
  	/* Report the error via the trace interface */
c7ef76455   Mauro Carvalho Chehab   edac: reduce stac...
1248
1249
1250
  	grain_bits = fls_long(e->grain) + 1;
  	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...
1251
  		       (e->page_frame_number << PAGE_SHIFT) | e->offset_in_page,
e7e248304   Mauro Carvalho Chehab   edac: add support...
1252
  		       grain_bits, e->syndrome, e->other_detail);
a7d7d2e1a   Mauro Carvalho Chehab   edac: Create a di...
1253

e7e248304   Mauro Carvalho Chehab   edac: add support...
1254
  	edac_raw_mc_handle_error(type, mci, e);
9794f33dd   eric wollesen   [PATCH] EDAC: Add...
1255
  }
4275be635   Mauro Carvalho Chehab   edac: Change inte...
1256
  EXPORT_SYMBOL_GPL(edac_mc_handle_error);