diff options
Diffstat (limited to 'drivers/edac/edac_mc.c')
-rw-r--r-- | drivers/edac/edac_mc.c | 107 |
1 files changed, 70 insertions, 37 deletions
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 4a6fdc03740e..db2ba31ba2b1 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
@@ -210,15 +210,15 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
210 | { | 210 | { |
211 | struct mem_ctl_info *mci; | 211 | struct mem_ctl_info *mci; |
212 | struct edac_mc_layer *layer; | 212 | struct edac_mc_layer *layer; |
213 | struct csrow_info *csi, *csr; | 213 | struct csrow_info *csr; |
214 | struct rank_info *chi, *chp, *chan; | 214 | struct rank_info *chan; |
215 | struct dimm_info *dimm; | 215 | struct dimm_info *dimm; |
216 | u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS]; | 216 | u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS]; |
217 | unsigned pos[EDAC_MAX_LAYERS]; | 217 | unsigned pos[EDAC_MAX_LAYERS]; |
218 | unsigned size, tot_dimms = 1, count = 1; | 218 | unsigned size, tot_dimms = 1, count = 1; |
219 | unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0; | 219 | unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0; |
220 | void *pvt, *p, *ptr = NULL; | 220 | void *pvt, *p, *ptr = NULL; |
221 | int i, j, row, chn, n, len; | 221 | int i, j, row, chn, n, len, off; |
222 | bool per_rank = false; | 222 | bool per_rank = false; |
223 | 223 | ||
224 | BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0); | 224 | BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0); |
@@ -244,9 +244,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
244 | */ | 244 | */ |
245 | mci = edac_align_ptr(&ptr, sizeof(*mci), 1); | 245 | mci = edac_align_ptr(&ptr, sizeof(*mci), 1); |
246 | layer = edac_align_ptr(&ptr, sizeof(*layer), n_layers); | 246 | layer = edac_align_ptr(&ptr, sizeof(*layer), n_layers); |
247 | csi = edac_align_ptr(&ptr, sizeof(*csi), tot_csrows); | ||
248 | chi = edac_align_ptr(&ptr, sizeof(*chi), tot_csrows * tot_channels); | ||
249 | dimm = edac_align_ptr(&ptr, sizeof(*dimm), tot_dimms); | ||
250 | for (i = 0; i < n_layers; i++) { | 247 | for (i = 0; i < n_layers; i++) { |
251 | count *= layers[i].size; | 248 | count *= layers[i].size; |
252 | debugf4("%s: errcount layer %d size %d\n", __func__, i, count); | 249 | debugf4("%s: errcount layer %d size %d\n", __func__, i, count); |
@@ -264,6 +261,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
264 | tot_dimms, | 261 | tot_dimms, |
265 | per_rank ? "ranks" : "dimms", | 262 | per_rank ? "ranks" : "dimms", |
266 | tot_csrows * tot_channels); | 263 | tot_csrows * tot_channels); |
264 | |||
267 | mci = kzalloc(size, GFP_KERNEL); | 265 | mci = kzalloc(size, GFP_KERNEL); |
268 | if (mci == NULL) | 266 | if (mci == NULL) |
269 | return NULL; | 267 | return NULL; |
@@ -272,9 +270,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
272 | * rather than an imaginary chunk of memory located at address 0. | 270 | * rather than an imaginary chunk of memory located at address 0. |
273 | */ | 271 | */ |
274 | layer = (struct edac_mc_layer *)(((char *)mci) + ((unsigned long)layer)); | 272 | layer = (struct edac_mc_layer *)(((char *)mci) + ((unsigned long)layer)); |
275 | csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi)); | ||
276 | chi = (struct rank_info *)(((char *)mci) + ((unsigned long)chi)); | ||
277 | dimm = (struct dimm_info *)(((char *)mci) + ((unsigned long)dimm)); | ||
278 | for (i = 0; i < n_layers; i++) { | 273 | for (i = 0; i < n_layers; i++) { |
279 | mci->ce_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ce_per_layer[i])); | 274 | mci->ce_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ce_per_layer[i])); |
280 | mci->ue_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ue_per_layer[i])); | 275 | mci->ue_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ue_per_layer[i])); |
@@ -283,8 +278,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
283 | 278 | ||
284 | /* setup index and various internal pointers */ | 279 | /* setup index and various internal pointers */ |
285 | mci->mc_idx = mc_num; | 280 | mci->mc_idx = mc_num; |
286 | mci->csrows = csi; | ||
287 | mci->dimms = dimm; | ||
288 | mci->tot_dimms = tot_dimms; | 281 | mci->tot_dimms = tot_dimms; |
289 | mci->pvt_info = pvt; | 282 | mci->pvt_info = pvt; |
290 | mci->n_layers = n_layers; | 283 | mci->n_layers = n_layers; |
@@ -295,39 +288,60 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
295 | mci->mem_is_per_rank = per_rank; | 288 | mci->mem_is_per_rank = per_rank; |
296 | 289 | ||
297 | /* | 290 | /* |
298 | * Fill the csrow struct | 291 | * Alocate and fill the csrow/channels structs |
299 | */ | 292 | */ |
293 | mci->csrows = kcalloc(sizeof(*mci->csrows), tot_csrows, GFP_KERNEL); | ||
294 | if (!mci->csrows) | ||
295 | goto error; | ||
300 | for (row = 0; row < tot_csrows; row++) { | 296 | for (row = 0; row < tot_csrows; row++) { |
301 | csr = &csi[row]; | 297 | csr = kzalloc(sizeof(**mci->csrows), GFP_KERNEL); |
298 | if (!csr) | ||
299 | goto error; | ||
300 | mci->csrows[row] = csr; | ||
302 | csr->csrow_idx = row; | 301 | csr->csrow_idx = row; |
303 | csr->mci = mci; | 302 | csr->mci = mci; |
304 | csr->nr_channels = tot_channels; | 303 | csr->nr_channels = tot_channels; |
305 | chp = &chi[row * tot_channels]; | 304 | csr->channels = kcalloc(sizeof(*csr->channels), tot_channels, |
306 | csr->channels = chp; | 305 | GFP_KERNEL); |
306 | if (!csr->channels) | ||
307 | goto error; | ||
307 | 308 | ||
308 | for (chn = 0; chn < tot_channels; chn++) { | 309 | for (chn = 0; chn < tot_channels; chn++) { |
309 | chan = &chp[chn]; | 310 | chan = kzalloc(sizeof(**csr->channels), GFP_KERNEL); |
311 | if (!chan) | ||
312 | goto error; | ||
313 | csr->channels[chn] = chan; | ||
310 | chan->chan_idx = chn; | 314 | chan->chan_idx = chn; |
311 | chan->csrow = csr; | 315 | chan->csrow = csr; |
312 | } | 316 | } |
313 | } | 317 | } |
314 | 318 | ||
315 | /* | 319 | /* |
316 | * Fill the dimm struct | 320 | * Allocate and fill the dimm structs |
317 | */ | 321 | */ |
322 | mci->dimms = kcalloc(sizeof(*mci->dimms), tot_dimms, GFP_KERNEL); | ||
323 | if (!mci->dimms) | ||
324 | goto error; | ||
325 | |||
318 | memset(&pos, 0, sizeof(pos)); | 326 | memset(&pos, 0, sizeof(pos)); |
319 | row = 0; | 327 | row = 0; |
320 | chn = 0; | 328 | chn = 0; |
321 | debugf4("%s: initializing %d %s\n", __func__, tot_dimms, | 329 | debugf4("%s: initializing %d %s\n", __func__, tot_dimms, |
322 | per_rank ? "ranks" : "dimms"); | 330 | per_rank ? "ranks" : "dimms"); |
323 | for (i = 0; i < tot_dimms; i++) { | 331 | for (i = 0; i < tot_dimms; i++) { |
324 | chan = &csi[row].channels[chn]; | 332 | chan = mci->csrows[row]->channels[chn]; |
325 | dimm = EDAC_DIMM_PTR(layer, mci->dimms, n_layers, | 333 | off = EDAC_DIMM_OFF(layer, n_layers, pos[0], pos[1], pos[2]); |
326 | pos[0], pos[1], pos[2]); | 334 | if (off < 0 || off >= tot_dimms) { |
335 | edac_mc_printk(mci, KERN_ERR, "EDAC core bug: EDAC_DIMM_OFF is trying to do an illegal data access\n"); | ||
336 | goto error; | ||
337 | } | ||
338 | |||
339 | dimm = kzalloc(sizeof(**mci->dimms), GFP_KERNEL); | ||
340 | mci->dimms[off] = dimm; | ||
327 | dimm->mci = mci; | 341 | dimm->mci = mci; |
328 | 342 | ||
329 | debugf2("%s: %d: %s%zd (%d:%d:%d): row %d, chan %d\n", __func__, | 343 | debugf2("%s: %d: %s%i (%d:%d:%d): row %d, chan %d\n", __func__, |
330 | i, per_rank ? "rank" : "dimm", (dimm - mci->dimms), | 344 | i, per_rank ? "rank" : "dimm", off, |
331 | pos[0], pos[1], pos[2], row, chn); | 345 | pos[0], pos[1], pos[2], row, chn); |
332 | 346 | ||
333 | /* | 347 | /* |
@@ -381,6 +395,28 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
381 | */ | 395 | */ |
382 | 396 | ||
383 | return mci; | 397 | return mci; |
398 | |||
399 | error: | ||
400 | if (mci->dimms) { | ||
401 | for (i = 0; i < tot_dimms; i++) | ||
402 | kfree(mci->dimms[i]); | ||
403 | kfree(mci->dimms); | ||
404 | } | ||
405 | if (mci->csrows) { | ||
406 | for (chn = 0; chn < tot_channels; chn++) { | ||
407 | csr = mci->csrows[chn]; | ||
408 | if (csr) { | ||
409 | for (chn = 0; chn < tot_channels; chn++) | ||
410 | kfree(csr->channels[chn]); | ||
411 | kfree(csr); | ||
412 | } | ||
413 | kfree(mci->csrows[i]); | ||
414 | } | ||
415 | kfree(mci->csrows); | ||
416 | } | ||
417 | kfree(mci); | ||
418 | |||
419 | return NULL; | ||
384 | } | 420 | } |
385 | EXPORT_SYMBOL_GPL(edac_mc_alloc); | 421 | EXPORT_SYMBOL_GPL(edac_mc_alloc); |
386 | 422 | ||
@@ -393,10 +429,8 @@ void edac_mc_free(struct mem_ctl_info *mci) | |||
393 | { | 429 | { |
394 | debugf1("%s()\n", __func__); | 430 | debugf1("%s()\n", __func__); |
395 | 431 | ||
432 | /* the mci instance is freed here, when the sysfs object is dropped */ | ||
396 | edac_unregister_sysfs(mci); | 433 | edac_unregister_sysfs(mci); |
397 | |||
398 | /* free the mci instance memory here */ | ||
399 | kfree(mci); | ||
400 | } | 434 | } |
401 | EXPORT_SYMBOL_GPL(edac_mc_free); | 435 | EXPORT_SYMBOL_GPL(edac_mc_free); |
402 | 436 | ||
@@ -668,13 +702,12 @@ int edac_mc_add_mc(struct mem_ctl_info *mci) | |||
668 | for (i = 0; i < mci->nr_csrows; i++) { | 702 | for (i = 0; i < mci->nr_csrows; i++) { |
669 | int j; | 703 | int j; |
670 | 704 | ||
671 | edac_mc_dump_csrow(&mci->csrows[i]); | 705 | edac_mc_dump_csrow(mci->csrows[i]); |
672 | for (j = 0; j < mci->csrows[i].nr_channels; j++) | 706 | for (j = 0; j < mci->csrows[i]->nr_channels; j++) |
673 | edac_mc_dump_channel(&mci->csrows[i]. | 707 | edac_mc_dump_channel(mci->csrows[i]->channels[j]); |
674 | channels[j]); | ||
675 | } | 708 | } |
676 | for (i = 0; i < mci->tot_dimms; i++) | 709 | for (i = 0; i < mci->tot_dimms; i++) |
677 | edac_mc_dump_dimm(&mci->dimms[i]); | 710 | edac_mc_dump_dimm(mci->dimms[i]); |
678 | } | 711 | } |
679 | #endif | 712 | #endif |
680 | mutex_lock(&mem_ctls_mutex); | 713 | mutex_lock(&mem_ctls_mutex); |
@@ -793,17 +826,17 @@ static void edac_mc_scrub_block(unsigned long page, unsigned long offset, | |||
793 | /* FIXME - should return -1 */ | 826 | /* FIXME - should return -1 */ |
794 | int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page) | 827 | int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page) |
795 | { | 828 | { |
796 | struct csrow_info *csrows = mci->csrows; | 829 | struct csrow_info **csrows = mci->csrows; |
797 | int row, i, j, n; | 830 | int row, i, j, n; |
798 | 831 | ||
799 | debugf1("MC%d: %s(): 0x%lx\n", mci->mc_idx, __func__, page); | 832 | debugf1("MC%d: %s(): 0x%lx\n", mci->mc_idx, __func__, page); |
800 | row = -1; | 833 | row = -1; |
801 | 834 | ||
802 | for (i = 0; i < mci->nr_csrows; i++) { | 835 | for (i = 0; i < mci->nr_csrows; i++) { |
803 | struct csrow_info *csrow = &csrows[i]; | 836 | struct csrow_info *csrow = csrows[i]; |
804 | n = 0; | 837 | n = 0; |
805 | for (j = 0; j < csrow->nr_channels; j++) { | 838 | for (j = 0; j < csrow->nr_channels; j++) { |
806 | struct dimm_info *dimm = csrow->channels[j].dimm; | 839 | struct dimm_info *dimm = csrow->channels[j]->dimm; |
807 | n += dimm->nr_pages; | 840 | n += dimm->nr_pages; |
808 | } | 841 | } |
809 | if (n == 0) | 842 | if (n == 0) |
@@ -1062,7 +1095,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, | |||
1062 | p = label; | 1095 | p = label; |
1063 | *p = '\0'; | 1096 | *p = '\0'; |
1064 | for (i = 0; i < mci->tot_dimms; i++) { | 1097 | for (i = 0; i < mci->tot_dimms; i++) { |
1065 | struct dimm_info *dimm = &mci->dimms[i]; | 1098 | struct dimm_info *dimm = mci->dimms[i]; |
1066 | 1099 | ||
1067 | if (top_layer >= 0 && top_layer != dimm->location[0]) | 1100 | if (top_layer >= 0 && top_layer != dimm->location[0]) |
1068 | continue; | 1101 | continue; |
@@ -1120,13 +1153,13 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, | |||
1120 | strcpy(label, "unknown memory"); | 1153 | strcpy(label, "unknown memory"); |
1121 | if (type == HW_EVENT_ERR_CORRECTED) { | 1154 | if (type == HW_EVENT_ERR_CORRECTED) { |
1122 | if (row >= 0) { | 1155 | if (row >= 0) { |
1123 | mci->csrows[row].ce_count++; | 1156 | mci->csrows[row]->ce_count++; |
1124 | if (chan >= 0) | 1157 | if (chan >= 0) |
1125 | mci->csrows[row].channels[chan].ce_count++; | 1158 | mci->csrows[row]->channels[chan]->ce_count++; |
1126 | } | 1159 | } |
1127 | } else | 1160 | } else |
1128 | if (row >= 0) | 1161 | if (row >= 0) |
1129 | mci->csrows[row].ue_count++; | 1162 | mci->csrows[row]->ue_count++; |
1130 | } | 1163 | } |
1131 | 1164 | ||
1132 | /* Fill the RAM location data */ | 1165 | /* Fill the RAM location data */ |