| .. | .. |
|---|
| 43 | 43 | int edac_op_state = EDAC_OPSTATE_INVAL; |
|---|
| 44 | 44 | EXPORT_SYMBOL_GPL(edac_op_state); |
|---|
| 45 | 45 | |
|---|
| 46 | | -static int edac_report = EDAC_REPORTING_ENABLED; |
|---|
| 47 | | - |
|---|
| 48 | 46 | /* lock to memory controller's control array */ |
|---|
| 49 | 47 | static DEFINE_MUTEX(mem_ctls_mutex); |
|---|
| 50 | 48 | static LIST_HEAD(mc_devices); |
|---|
| .. | .. |
|---|
| 55 | 53 | */ |
|---|
| 56 | 54 | static const char *edac_mc_owner; |
|---|
| 57 | 55 | |
|---|
| 58 | | -static struct bus_type mc_bus[EDAC_MAX_MCS]; |
|---|
| 59 | | - |
|---|
| 60 | | -int edac_get_report_status(void) |
|---|
| 56 | +static struct mem_ctl_info *error_desc_to_mci(struct edac_raw_error_desc *e) |
|---|
| 61 | 57 | { |
|---|
| 62 | | - return edac_report; |
|---|
| 63 | | -} |
|---|
| 64 | | -EXPORT_SYMBOL_GPL(edac_get_report_status); |
|---|
| 65 | | - |
|---|
| 66 | | -void edac_set_report_status(int new) |
|---|
| 67 | | -{ |
|---|
| 68 | | - if (new == EDAC_REPORTING_ENABLED || |
|---|
| 69 | | - new == EDAC_REPORTING_DISABLED || |
|---|
| 70 | | - new == EDAC_REPORTING_FORCE) |
|---|
| 71 | | - edac_report = new; |
|---|
| 72 | | -} |
|---|
| 73 | | -EXPORT_SYMBOL_GPL(edac_set_report_status); |
|---|
| 74 | | - |
|---|
| 75 | | -static int edac_report_set(const char *str, const struct kernel_param *kp) |
|---|
| 76 | | -{ |
|---|
| 77 | | - if (!str) |
|---|
| 78 | | - return -EINVAL; |
|---|
| 79 | | - |
|---|
| 80 | | - if (!strncmp(str, "on", 2)) |
|---|
| 81 | | - edac_report = EDAC_REPORTING_ENABLED; |
|---|
| 82 | | - else if (!strncmp(str, "off", 3)) |
|---|
| 83 | | - edac_report = EDAC_REPORTING_DISABLED; |
|---|
| 84 | | - else if (!strncmp(str, "force", 5)) |
|---|
| 85 | | - edac_report = EDAC_REPORTING_FORCE; |
|---|
| 86 | | - |
|---|
| 87 | | - return 0; |
|---|
| 58 | + return container_of(e, struct mem_ctl_info, error_desc); |
|---|
| 88 | 59 | } |
|---|
| 89 | 60 | |
|---|
| 90 | | -static int edac_report_get(char *buffer, const struct kernel_param *kp) |
|---|
| 91 | | -{ |
|---|
| 92 | | - int ret = 0; |
|---|
| 93 | | - |
|---|
| 94 | | - switch (edac_report) { |
|---|
| 95 | | - case EDAC_REPORTING_ENABLED: |
|---|
| 96 | | - ret = sprintf(buffer, "on"); |
|---|
| 97 | | - break; |
|---|
| 98 | | - case EDAC_REPORTING_DISABLED: |
|---|
| 99 | | - ret = sprintf(buffer, "off"); |
|---|
| 100 | | - break; |
|---|
| 101 | | - case EDAC_REPORTING_FORCE: |
|---|
| 102 | | - ret = sprintf(buffer, "force"); |
|---|
| 103 | | - break; |
|---|
| 104 | | - default: |
|---|
| 105 | | - ret = -EINVAL; |
|---|
| 106 | | - break; |
|---|
| 107 | | - } |
|---|
| 108 | | - |
|---|
| 109 | | - return ret; |
|---|
| 110 | | -} |
|---|
| 111 | | - |
|---|
| 112 | | -static const struct kernel_param_ops edac_report_ops = { |
|---|
| 113 | | - .set = edac_report_set, |
|---|
| 114 | | - .get = edac_report_get, |
|---|
| 115 | | -}; |
|---|
| 116 | | - |
|---|
| 117 | | -module_param_cb(edac_report, &edac_report_ops, &edac_report, 0644); |
|---|
| 118 | | - |
|---|
| 119 | | -unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf, |
|---|
| 120 | | - unsigned len) |
|---|
| 61 | +unsigned int edac_dimm_info_location(struct dimm_info *dimm, char *buf, |
|---|
| 62 | + unsigned int len) |
|---|
| 121 | 63 | { |
|---|
| 122 | 64 | struct mem_ctl_info *mci = dimm->mci; |
|---|
| 123 | 65 | int i, n, count = 0; |
|---|
| .. | .. |
|---|
| 147 | 89 | edac_dbg(4, " channel->dimm = %p\n", chan->dimm); |
|---|
| 148 | 90 | } |
|---|
| 149 | 91 | |
|---|
| 150 | | -static void edac_mc_dump_dimm(struct dimm_info *dimm, int number) |
|---|
| 92 | +static void edac_mc_dump_dimm(struct dimm_info *dimm) |
|---|
| 151 | 93 | { |
|---|
| 152 | 94 | char location[80]; |
|---|
| 95 | + |
|---|
| 96 | + if (!dimm->nr_pages) |
|---|
| 97 | + return; |
|---|
| 153 | 98 | |
|---|
| 154 | 99 | edac_dimm_info_location(dimm, location, sizeof(location)); |
|---|
| 155 | 100 | |
|---|
| 156 | 101 | edac_dbg(4, "%s%i: %smapped as virtual row %d, chan %d\n", |
|---|
| 157 | 102 | dimm->mci->csbased ? "rank" : "dimm", |
|---|
| 158 | | - number, location, dimm->csrow, dimm->cschannel); |
|---|
| 103 | + dimm->idx, location, dimm->csrow, dimm->cschannel); |
|---|
| 159 | 104 | edac_dbg(4, " dimm = %p\n", dimm); |
|---|
| 160 | 105 | edac_dbg(4, " dimm->label = '%s'\n", dimm->label); |
|---|
| 161 | 106 | edac_dbg(4, " dimm->nr_pages = 0x%x\n", dimm->nr_pages); |
|---|
| .. | .. |
|---|
| 238 | 183 | * At return, the pointer 'p' will be incremented to be used on a next call |
|---|
| 239 | 184 | * to this function. |
|---|
| 240 | 185 | */ |
|---|
| 241 | | -void *edac_align_ptr(void **p, unsigned size, int n_elems) |
|---|
| 186 | +void *edac_align_ptr(void **p, unsigned int size, int n_elems) |
|---|
| 242 | 187 | { |
|---|
| 243 | | - unsigned align, r; |
|---|
| 188 | + unsigned int align, r; |
|---|
| 244 | 189 | void *ptr = *p; |
|---|
| 245 | 190 | |
|---|
| 246 | 191 | *p += size * n_elems; |
|---|
| .. | .. |
|---|
| 277 | 222 | |
|---|
| 278 | 223 | static void _edac_mc_free(struct mem_ctl_info *mci) |
|---|
| 279 | 224 | { |
|---|
| 280 | | - int i, chn, row; |
|---|
| 225 | + put_device(&mci->dev); |
|---|
| 226 | +} |
|---|
| 227 | + |
|---|
| 228 | +static void mci_release(struct device *dev) |
|---|
| 229 | +{ |
|---|
| 230 | + struct mem_ctl_info *mci = container_of(dev, struct mem_ctl_info, dev); |
|---|
| 281 | 231 | struct csrow_info *csr; |
|---|
| 282 | | - const unsigned int tot_dimms = mci->tot_dimms; |
|---|
| 283 | | - const unsigned int tot_channels = mci->num_cschannel; |
|---|
| 284 | | - const unsigned int tot_csrows = mci->nr_csrows; |
|---|
| 232 | + int i, chn, row; |
|---|
| 285 | 233 | |
|---|
| 286 | 234 | if (mci->dimms) { |
|---|
| 287 | | - for (i = 0; i < tot_dimms; i++) |
|---|
| 235 | + for (i = 0; i < mci->tot_dimms; i++) |
|---|
| 288 | 236 | kfree(mci->dimms[i]); |
|---|
| 289 | 237 | kfree(mci->dimms); |
|---|
| 290 | 238 | } |
|---|
| 239 | + |
|---|
| 291 | 240 | if (mci->csrows) { |
|---|
| 292 | | - for (row = 0; row < tot_csrows; row++) { |
|---|
| 241 | + for (row = 0; row < mci->nr_csrows; row++) { |
|---|
| 293 | 242 | csr = mci->csrows[row]; |
|---|
| 294 | | - if (csr) { |
|---|
| 295 | | - if (csr->channels) { |
|---|
| 296 | | - for (chn = 0; chn < tot_channels; chn++) |
|---|
| 297 | | - kfree(csr->channels[chn]); |
|---|
| 298 | | - kfree(csr->channels); |
|---|
| 299 | | - } |
|---|
| 300 | | - kfree(csr); |
|---|
| 243 | + if (!csr) |
|---|
| 244 | + continue; |
|---|
| 245 | + |
|---|
| 246 | + if (csr->channels) { |
|---|
| 247 | + for (chn = 0; chn < mci->num_cschannel; chn++) |
|---|
| 248 | + kfree(csr->channels[chn]); |
|---|
| 249 | + kfree(csr->channels); |
|---|
| 301 | 250 | } |
|---|
| 251 | + kfree(csr); |
|---|
| 302 | 252 | } |
|---|
| 303 | 253 | kfree(mci->csrows); |
|---|
| 304 | 254 | } |
|---|
| 305 | 255 | kfree(mci); |
|---|
| 306 | 256 | } |
|---|
| 307 | 257 | |
|---|
| 308 | | -struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, |
|---|
| 309 | | - unsigned n_layers, |
|---|
| 258 | +static int edac_mc_alloc_csrows(struct mem_ctl_info *mci) |
|---|
| 259 | +{ |
|---|
| 260 | + unsigned int tot_channels = mci->num_cschannel; |
|---|
| 261 | + unsigned int tot_csrows = mci->nr_csrows; |
|---|
| 262 | + unsigned int row, chn; |
|---|
| 263 | + |
|---|
| 264 | + /* |
|---|
| 265 | + * Alocate and fill the csrow/channels structs |
|---|
| 266 | + */ |
|---|
| 267 | + mci->csrows = kcalloc(tot_csrows, sizeof(*mci->csrows), GFP_KERNEL); |
|---|
| 268 | + if (!mci->csrows) |
|---|
| 269 | + return -ENOMEM; |
|---|
| 270 | + |
|---|
| 271 | + for (row = 0; row < tot_csrows; row++) { |
|---|
| 272 | + struct csrow_info *csr; |
|---|
| 273 | + |
|---|
| 274 | + csr = kzalloc(sizeof(**mci->csrows), GFP_KERNEL); |
|---|
| 275 | + if (!csr) |
|---|
| 276 | + return -ENOMEM; |
|---|
| 277 | + |
|---|
| 278 | + mci->csrows[row] = csr; |
|---|
| 279 | + csr->csrow_idx = row; |
|---|
| 280 | + csr->mci = mci; |
|---|
| 281 | + csr->nr_channels = tot_channels; |
|---|
| 282 | + csr->channels = kcalloc(tot_channels, sizeof(*csr->channels), |
|---|
| 283 | + GFP_KERNEL); |
|---|
| 284 | + if (!csr->channels) |
|---|
| 285 | + return -ENOMEM; |
|---|
| 286 | + |
|---|
| 287 | + for (chn = 0; chn < tot_channels; chn++) { |
|---|
| 288 | + struct rank_info *chan; |
|---|
| 289 | + |
|---|
| 290 | + chan = kzalloc(sizeof(**csr->channels), GFP_KERNEL); |
|---|
| 291 | + if (!chan) |
|---|
| 292 | + return -ENOMEM; |
|---|
| 293 | + |
|---|
| 294 | + csr->channels[chn] = chan; |
|---|
| 295 | + chan->chan_idx = chn; |
|---|
| 296 | + chan->csrow = csr; |
|---|
| 297 | + } |
|---|
| 298 | + } |
|---|
| 299 | + |
|---|
| 300 | + return 0; |
|---|
| 301 | +} |
|---|
| 302 | + |
|---|
| 303 | +static int edac_mc_alloc_dimms(struct mem_ctl_info *mci) |
|---|
| 304 | +{ |
|---|
| 305 | + unsigned int pos[EDAC_MAX_LAYERS]; |
|---|
| 306 | + unsigned int row, chn, idx; |
|---|
| 307 | + int layer; |
|---|
| 308 | + void *p; |
|---|
| 309 | + |
|---|
| 310 | + /* |
|---|
| 311 | + * Allocate and fill the dimm structs |
|---|
| 312 | + */ |
|---|
| 313 | + mci->dimms = kcalloc(mci->tot_dimms, sizeof(*mci->dimms), GFP_KERNEL); |
|---|
| 314 | + if (!mci->dimms) |
|---|
| 315 | + return -ENOMEM; |
|---|
| 316 | + |
|---|
| 317 | + memset(&pos, 0, sizeof(pos)); |
|---|
| 318 | + row = 0; |
|---|
| 319 | + chn = 0; |
|---|
| 320 | + for (idx = 0; idx < mci->tot_dimms; idx++) { |
|---|
| 321 | + struct dimm_info *dimm; |
|---|
| 322 | + struct rank_info *chan; |
|---|
| 323 | + int n, len; |
|---|
| 324 | + |
|---|
| 325 | + chan = mci->csrows[row]->channels[chn]; |
|---|
| 326 | + |
|---|
| 327 | + dimm = kzalloc(sizeof(**mci->dimms), GFP_KERNEL); |
|---|
| 328 | + if (!dimm) |
|---|
| 329 | + return -ENOMEM; |
|---|
| 330 | + mci->dimms[idx] = dimm; |
|---|
| 331 | + dimm->mci = mci; |
|---|
| 332 | + dimm->idx = idx; |
|---|
| 333 | + |
|---|
| 334 | + /* |
|---|
| 335 | + * Copy DIMM location and initialize it. |
|---|
| 336 | + */ |
|---|
| 337 | + len = sizeof(dimm->label); |
|---|
| 338 | + p = dimm->label; |
|---|
| 339 | + n = snprintf(p, len, "mc#%u", mci->mc_idx); |
|---|
| 340 | + p += n; |
|---|
| 341 | + len -= n; |
|---|
| 342 | + for (layer = 0; layer < mci->n_layers; layer++) { |
|---|
| 343 | + n = snprintf(p, len, "%s#%u", |
|---|
| 344 | + edac_layer_name[mci->layers[layer].type], |
|---|
| 345 | + pos[layer]); |
|---|
| 346 | + p += n; |
|---|
| 347 | + len -= n; |
|---|
| 348 | + dimm->location[layer] = pos[layer]; |
|---|
| 349 | + |
|---|
| 350 | + if (len <= 0) |
|---|
| 351 | + break; |
|---|
| 352 | + } |
|---|
| 353 | + |
|---|
| 354 | + /* Link it to the csrows old API data */ |
|---|
| 355 | + chan->dimm = dimm; |
|---|
| 356 | + dimm->csrow = row; |
|---|
| 357 | + dimm->cschannel = chn; |
|---|
| 358 | + |
|---|
| 359 | + /* Increment csrow location */ |
|---|
| 360 | + if (mci->layers[0].is_virt_csrow) { |
|---|
| 361 | + chn++; |
|---|
| 362 | + if (chn == mci->num_cschannel) { |
|---|
| 363 | + chn = 0; |
|---|
| 364 | + row++; |
|---|
| 365 | + } |
|---|
| 366 | + } else { |
|---|
| 367 | + row++; |
|---|
| 368 | + if (row == mci->nr_csrows) { |
|---|
| 369 | + row = 0; |
|---|
| 370 | + chn++; |
|---|
| 371 | + } |
|---|
| 372 | + } |
|---|
| 373 | + |
|---|
| 374 | + /* Increment dimm location */ |
|---|
| 375 | + for (layer = mci->n_layers - 1; layer >= 0; layer--) { |
|---|
| 376 | + pos[layer]++; |
|---|
| 377 | + if (pos[layer] < mci->layers[layer].size) |
|---|
| 378 | + break; |
|---|
| 379 | + pos[layer] = 0; |
|---|
| 380 | + } |
|---|
| 381 | + } |
|---|
| 382 | + |
|---|
| 383 | + return 0; |
|---|
| 384 | +} |
|---|
| 385 | + |
|---|
| 386 | +struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num, |
|---|
| 387 | + unsigned int n_layers, |
|---|
| 310 | 388 | struct edac_mc_layer *layers, |
|---|
| 311 | | - unsigned sz_pvt) |
|---|
| 389 | + unsigned int sz_pvt) |
|---|
| 312 | 390 | { |
|---|
| 313 | 391 | struct mem_ctl_info *mci; |
|---|
| 314 | 392 | struct edac_mc_layer *layer; |
|---|
| 315 | | - struct csrow_info *csr; |
|---|
| 316 | | - struct rank_info *chan; |
|---|
| 317 | | - struct dimm_info *dimm; |
|---|
| 318 | | - u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS]; |
|---|
| 319 | | - unsigned pos[EDAC_MAX_LAYERS]; |
|---|
| 320 | | - unsigned size, tot_dimms = 1, count = 1; |
|---|
| 321 | | - unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0; |
|---|
| 322 | | - void *pvt, *p, *ptr = NULL; |
|---|
| 323 | | - int i, j, row, chn, n, len, off; |
|---|
| 393 | + unsigned int idx, size, tot_dimms = 1; |
|---|
| 394 | + unsigned int tot_csrows = 1, tot_channels = 1; |
|---|
| 395 | + void *pvt, *ptr = NULL; |
|---|
| 324 | 396 | bool per_rank = false; |
|---|
| 325 | 397 | |
|---|
| 326 | | - BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0); |
|---|
| 398 | + if (WARN_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0)) |
|---|
| 399 | + return NULL; |
|---|
| 400 | + |
|---|
| 327 | 401 | /* |
|---|
| 328 | 402 | * Calculate the total amount of dimms and csrows/cschannels while |
|---|
| 329 | 403 | * in the old API emulation mode |
|---|
| 330 | 404 | */ |
|---|
| 331 | | - for (i = 0; i < n_layers; i++) { |
|---|
| 332 | | - tot_dimms *= layers[i].size; |
|---|
| 333 | | - if (layers[i].is_virt_csrow) |
|---|
| 334 | | - tot_csrows *= layers[i].size; |
|---|
| 335 | | - else |
|---|
| 336 | | - tot_channels *= layers[i].size; |
|---|
| 405 | + for (idx = 0; idx < n_layers; idx++) { |
|---|
| 406 | + tot_dimms *= layers[idx].size; |
|---|
| 337 | 407 | |
|---|
| 338 | | - if (layers[i].type == EDAC_MC_LAYER_CHIP_SELECT) |
|---|
| 408 | + if (layers[idx].is_virt_csrow) |
|---|
| 409 | + tot_csrows *= layers[idx].size; |
|---|
| 410 | + else |
|---|
| 411 | + tot_channels *= layers[idx].size; |
|---|
| 412 | + |
|---|
| 413 | + if (layers[idx].type == EDAC_MC_LAYER_CHIP_SELECT) |
|---|
| 339 | 414 | per_rank = true; |
|---|
| 340 | 415 | } |
|---|
| 341 | 416 | |
|---|
| .. | .. |
|---|
| 344 | 419 | * stringent as what the compiler would provide if we could simply |
|---|
| 345 | 420 | * hardcode everything into a single struct. |
|---|
| 346 | 421 | */ |
|---|
| 347 | | - mci = edac_align_ptr(&ptr, sizeof(*mci), 1); |
|---|
| 348 | | - layer = edac_align_ptr(&ptr, sizeof(*layer), n_layers); |
|---|
| 349 | | - for (i = 0; i < n_layers; i++) { |
|---|
| 350 | | - count *= layers[i].size; |
|---|
| 351 | | - edac_dbg(4, "errcount layer %d size %d\n", i, count); |
|---|
| 352 | | - ce_per_layer[i] = edac_align_ptr(&ptr, sizeof(u32), count); |
|---|
| 353 | | - ue_per_layer[i] = edac_align_ptr(&ptr, sizeof(u32), count); |
|---|
| 354 | | - tot_errcount += 2 * count; |
|---|
| 355 | | - } |
|---|
| 356 | | - |
|---|
| 357 | | - edac_dbg(4, "allocating %d error counters\n", tot_errcount); |
|---|
| 358 | | - pvt = edac_align_ptr(&ptr, sz_pvt, 1); |
|---|
| 359 | | - size = ((unsigned long)pvt) + sz_pvt; |
|---|
| 422 | + mci = edac_align_ptr(&ptr, sizeof(*mci), 1); |
|---|
| 423 | + layer = edac_align_ptr(&ptr, sizeof(*layer), n_layers); |
|---|
| 424 | + pvt = edac_align_ptr(&ptr, sz_pvt, 1); |
|---|
| 425 | + size = ((unsigned long)pvt) + sz_pvt; |
|---|
| 360 | 426 | |
|---|
| 361 | 427 | edac_dbg(1, "allocating %u bytes for mci data (%d %s, %d csrows/channels)\n", |
|---|
| 362 | 428 | size, |
|---|
| .. | .. |
|---|
| 368 | 434 | if (mci == NULL) |
|---|
| 369 | 435 | return NULL; |
|---|
| 370 | 436 | |
|---|
| 437 | + mci->dev.release = mci_release; |
|---|
| 438 | + device_initialize(&mci->dev); |
|---|
| 439 | + |
|---|
| 371 | 440 | /* Adjust pointers so they point within the memory we just allocated |
|---|
| 372 | 441 | * rather than an imaginary chunk of memory located at address 0. |
|---|
| 373 | 442 | */ |
|---|
| 374 | 443 | layer = (struct edac_mc_layer *)(((char *)mci) + ((unsigned long)layer)); |
|---|
| 375 | | - for (i = 0; i < n_layers; i++) { |
|---|
| 376 | | - mci->ce_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ce_per_layer[i])); |
|---|
| 377 | | - mci->ue_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ue_per_layer[i])); |
|---|
| 378 | | - } |
|---|
| 379 | 444 | pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL; |
|---|
| 380 | 445 | |
|---|
| 381 | 446 | /* setup index and various internal pointers */ |
|---|
| .. | .. |
|---|
| 389 | 454 | mci->num_cschannel = tot_channels; |
|---|
| 390 | 455 | mci->csbased = per_rank; |
|---|
| 391 | 456 | |
|---|
| 392 | | - /* |
|---|
| 393 | | - * Alocate and fill the csrow/channels structs |
|---|
| 394 | | - */ |
|---|
| 395 | | - mci->csrows = kcalloc(tot_csrows, sizeof(*mci->csrows), GFP_KERNEL); |
|---|
| 396 | | - if (!mci->csrows) |
|---|
| 397 | | - goto error; |
|---|
| 398 | | - for (row = 0; row < tot_csrows; row++) { |
|---|
| 399 | | - csr = kzalloc(sizeof(**mci->csrows), GFP_KERNEL); |
|---|
| 400 | | - if (!csr) |
|---|
| 401 | | - goto error; |
|---|
| 402 | | - mci->csrows[row] = csr; |
|---|
| 403 | | - csr->csrow_idx = row; |
|---|
| 404 | | - csr->mci = mci; |
|---|
| 405 | | - csr->nr_channels = tot_channels; |
|---|
| 406 | | - csr->channels = kcalloc(tot_channels, sizeof(*csr->channels), |
|---|
| 407 | | - GFP_KERNEL); |
|---|
| 408 | | - if (!csr->channels) |
|---|
| 409 | | - goto error; |
|---|
| 410 | | - |
|---|
| 411 | | - for (chn = 0; chn < tot_channels; chn++) { |
|---|
| 412 | | - chan = kzalloc(sizeof(**csr->channels), GFP_KERNEL); |
|---|
| 413 | | - if (!chan) |
|---|
| 414 | | - goto error; |
|---|
| 415 | | - csr->channels[chn] = chan; |
|---|
| 416 | | - chan->chan_idx = chn; |
|---|
| 417 | | - chan->csrow = csr; |
|---|
| 418 | | - } |
|---|
| 419 | | - } |
|---|
| 420 | | - |
|---|
| 421 | | - /* |
|---|
| 422 | | - * Allocate and fill the dimm structs |
|---|
| 423 | | - */ |
|---|
| 424 | | - mci->dimms = kcalloc(tot_dimms, sizeof(*mci->dimms), GFP_KERNEL); |
|---|
| 425 | | - if (!mci->dimms) |
|---|
| 457 | + if (edac_mc_alloc_csrows(mci)) |
|---|
| 426 | 458 | goto error; |
|---|
| 427 | 459 | |
|---|
| 428 | | - memset(&pos, 0, sizeof(pos)); |
|---|
| 429 | | - row = 0; |
|---|
| 430 | | - chn = 0; |
|---|
| 431 | | - for (i = 0; i < tot_dimms; i++) { |
|---|
| 432 | | - chan = mci->csrows[row]->channels[chn]; |
|---|
| 433 | | - off = EDAC_DIMM_OFF(layer, n_layers, pos[0], pos[1], pos[2]); |
|---|
| 434 | | - if (off < 0 || off >= tot_dimms) { |
|---|
| 435 | | - edac_mc_printk(mci, KERN_ERR, "EDAC core bug: EDAC_DIMM_OFF is trying to do an illegal data access\n"); |
|---|
| 436 | | - goto error; |
|---|
| 437 | | - } |
|---|
| 438 | | - |
|---|
| 439 | | - dimm = kzalloc(sizeof(**mci->dimms), GFP_KERNEL); |
|---|
| 440 | | - if (!dimm) |
|---|
| 441 | | - goto error; |
|---|
| 442 | | - mci->dimms[off] = dimm; |
|---|
| 443 | | - dimm->mci = mci; |
|---|
| 444 | | - |
|---|
| 445 | | - /* |
|---|
| 446 | | - * Copy DIMM location and initialize it. |
|---|
| 447 | | - */ |
|---|
| 448 | | - len = sizeof(dimm->label); |
|---|
| 449 | | - p = dimm->label; |
|---|
| 450 | | - n = snprintf(p, len, "mc#%u", mc_num); |
|---|
| 451 | | - p += n; |
|---|
| 452 | | - len -= n; |
|---|
| 453 | | - for (j = 0; j < n_layers; j++) { |
|---|
| 454 | | - n = snprintf(p, len, "%s#%u", |
|---|
| 455 | | - edac_layer_name[layers[j].type], |
|---|
| 456 | | - pos[j]); |
|---|
| 457 | | - p += n; |
|---|
| 458 | | - len -= n; |
|---|
| 459 | | - dimm->location[j] = pos[j]; |
|---|
| 460 | | - |
|---|
| 461 | | - if (len <= 0) |
|---|
| 462 | | - break; |
|---|
| 463 | | - } |
|---|
| 464 | | - |
|---|
| 465 | | - /* Link it to the csrows old API data */ |
|---|
| 466 | | - chan->dimm = dimm; |
|---|
| 467 | | - dimm->csrow = row; |
|---|
| 468 | | - dimm->cschannel = chn; |
|---|
| 469 | | - |
|---|
| 470 | | - /* Increment csrow location */ |
|---|
| 471 | | - if (layers[0].is_virt_csrow) { |
|---|
| 472 | | - chn++; |
|---|
| 473 | | - if (chn == tot_channels) { |
|---|
| 474 | | - chn = 0; |
|---|
| 475 | | - row++; |
|---|
| 476 | | - } |
|---|
| 477 | | - } else { |
|---|
| 478 | | - row++; |
|---|
| 479 | | - if (row == tot_csrows) { |
|---|
| 480 | | - row = 0; |
|---|
| 481 | | - chn++; |
|---|
| 482 | | - } |
|---|
| 483 | | - } |
|---|
| 484 | | - |
|---|
| 485 | | - /* Increment dimm location */ |
|---|
| 486 | | - for (j = n_layers - 1; j >= 0; j--) { |
|---|
| 487 | | - pos[j]++; |
|---|
| 488 | | - if (pos[j] < layers[j].size) |
|---|
| 489 | | - break; |
|---|
| 490 | | - pos[j] = 0; |
|---|
| 491 | | - } |
|---|
| 492 | | - } |
|---|
| 460 | + if (edac_mc_alloc_dimms(mci)) |
|---|
| 461 | + goto error; |
|---|
| 493 | 462 | |
|---|
| 494 | 463 | mci->op_state = OP_ALLOC; |
|---|
| 495 | 464 | |
|---|
| .. | .. |
|---|
| 506 | 475 | { |
|---|
| 507 | 476 | edac_dbg(1, "\n"); |
|---|
| 508 | 477 | |
|---|
| 509 | | - /* If we're not yet registered with sysfs free only what was allocated |
|---|
| 510 | | - * in edac_mc_alloc(). |
|---|
| 511 | | - */ |
|---|
| 512 | | - if (!device_is_registered(&mci->dev)) { |
|---|
| 513 | | - _edac_mc_free(mci); |
|---|
| 514 | | - return; |
|---|
| 515 | | - } |
|---|
| 516 | | - |
|---|
| 517 | | - /* the mci instance is freed here, when the sysfs object is dropped */ |
|---|
| 518 | | - edac_unregister_sysfs(mci); |
|---|
| 478 | + _edac_mc_free(mci); |
|---|
| 519 | 479 | } |
|---|
| 520 | 480 | EXPORT_SYMBOL_GPL(edac_mc_free); |
|---|
| 521 | 481 | |
|---|
| .. | .. |
|---|
| 712 | 672 | int ret = -EINVAL; |
|---|
| 713 | 673 | edac_dbg(0, "\n"); |
|---|
| 714 | 674 | |
|---|
| 715 | | - if (mci->mc_idx >= EDAC_MAX_MCS) { |
|---|
| 716 | | - pr_warn_once("Too many memory controllers: %d\n", mci->mc_idx); |
|---|
| 717 | | - return -ENODEV; |
|---|
| 718 | | - } |
|---|
| 719 | | - |
|---|
| 720 | 675 | #ifdef CONFIG_EDAC_DEBUG |
|---|
| 721 | 676 | if (edac_debug_level >= 3) |
|---|
| 722 | 677 | edac_mc_dump_mci(mci); |
|---|
| 723 | 678 | |
|---|
| 724 | 679 | if (edac_debug_level >= 4) { |
|---|
| 680 | + struct dimm_info *dimm; |
|---|
| 725 | 681 | int i; |
|---|
| 726 | 682 | |
|---|
| 727 | 683 | for (i = 0; i < mci->nr_csrows; i++) { |
|---|
| .. | .. |
|---|
| 738 | 694 | if (csrow->channels[j]->dimm->nr_pages) |
|---|
| 739 | 695 | edac_mc_dump_channel(csrow->channels[j]); |
|---|
| 740 | 696 | } |
|---|
| 741 | | - for (i = 0; i < mci->tot_dimms; i++) |
|---|
| 742 | | - if (mci->dimms[i]->nr_pages) |
|---|
| 743 | | - edac_mc_dump_dimm(mci->dimms[i], i); |
|---|
| 697 | + |
|---|
| 698 | + mci_for_each_dimm(mci, dimm) |
|---|
| 699 | + edac_mc_dump_dimm(dimm); |
|---|
| 744 | 700 | } |
|---|
| 745 | 701 | #endif |
|---|
| 746 | 702 | mutex_lock(&mem_ctls_mutex); |
|---|
| .. | .. |
|---|
| 756 | 712 | /* set load time so that error rate can be tracked */ |
|---|
| 757 | 713 | mci->start_time = jiffies; |
|---|
| 758 | 714 | |
|---|
| 759 | | - mci->bus = &mc_bus[mci->mc_idx]; |
|---|
| 715 | + mci->bus = edac_get_sysfs_subsys(); |
|---|
| 760 | 716 | |
|---|
| 761 | 717 | if (edac_create_sysfs_mci_device(mci, groups)) { |
|---|
| 762 | 718 | edac_mc_printk(mci, KERN_WARNING, |
|---|
| .. | .. |
|---|
| 913 | 869 | }; |
|---|
| 914 | 870 | EXPORT_SYMBOL_GPL(edac_layer_name); |
|---|
| 915 | 871 | |
|---|
| 916 | | -static void edac_inc_ce_error(struct mem_ctl_info *mci, |
|---|
| 917 | | - bool enable_per_layer_report, |
|---|
| 918 | | - const int pos[EDAC_MAX_LAYERS], |
|---|
| 919 | | - const u16 count) |
|---|
| 872 | +static void edac_inc_ce_error(struct edac_raw_error_desc *e) |
|---|
| 920 | 873 | { |
|---|
| 921 | | - int i, index = 0; |
|---|
| 874 | + int pos[EDAC_MAX_LAYERS] = { e->top_layer, e->mid_layer, e->low_layer }; |
|---|
| 875 | + struct mem_ctl_info *mci = error_desc_to_mci(e); |
|---|
| 876 | + struct dimm_info *dimm = edac_get_dimm(mci, pos[0], pos[1], pos[2]); |
|---|
| 922 | 877 | |
|---|
| 923 | | - mci->ce_mc += count; |
|---|
| 878 | + mci->ce_mc += e->error_count; |
|---|
| 924 | 879 | |
|---|
| 925 | | - if (!enable_per_layer_report) { |
|---|
| 926 | | - mci->ce_noinfo_count += count; |
|---|
| 927 | | - return; |
|---|
| 928 | | - } |
|---|
| 929 | | - |
|---|
| 930 | | - for (i = 0; i < mci->n_layers; i++) { |
|---|
| 931 | | - if (pos[i] < 0) |
|---|
| 932 | | - break; |
|---|
| 933 | | - index += pos[i]; |
|---|
| 934 | | - mci->ce_per_layer[i][index] += count; |
|---|
| 935 | | - |
|---|
| 936 | | - if (i < mci->n_layers - 1) |
|---|
| 937 | | - index *= mci->layers[i + 1].size; |
|---|
| 938 | | - } |
|---|
| 880 | + if (dimm) |
|---|
| 881 | + dimm->ce_count += e->error_count; |
|---|
| 882 | + else |
|---|
| 883 | + mci->ce_noinfo_count += e->error_count; |
|---|
| 939 | 884 | } |
|---|
| 940 | 885 | |
|---|
| 941 | | -static void edac_inc_ue_error(struct mem_ctl_info *mci, |
|---|
| 942 | | - bool enable_per_layer_report, |
|---|
| 943 | | - const int pos[EDAC_MAX_LAYERS], |
|---|
| 944 | | - const u16 count) |
|---|
| 886 | +static void edac_inc_ue_error(struct edac_raw_error_desc *e) |
|---|
| 945 | 887 | { |
|---|
| 946 | | - int i, index = 0; |
|---|
| 888 | + int pos[EDAC_MAX_LAYERS] = { e->top_layer, e->mid_layer, e->low_layer }; |
|---|
| 889 | + struct mem_ctl_info *mci = error_desc_to_mci(e); |
|---|
| 890 | + struct dimm_info *dimm = edac_get_dimm(mci, pos[0], pos[1], pos[2]); |
|---|
| 947 | 891 | |
|---|
| 948 | | - mci->ue_mc += count; |
|---|
| 892 | + mci->ue_mc += e->error_count; |
|---|
| 949 | 893 | |
|---|
| 950 | | - if (!enable_per_layer_report) { |
|---|
| 951 | | - mci->ue_noinfo_count += count; |
|---|
| 952 | | - return; |
|---|
| 953 | | - } |
|---|
| 954 | | - |
|---|
| 955 | | - for (i = 0; i < mci->n_layers; i++) { |
|---|
| 956 | | - if (pos[i] < 0) |
|---|
| 957 | | - break; |
|---|
| 958 | | - index += pos[i]; |
|---|
| 959 | | - mci->ue_per_layer[i][index] += count; |
|---|
| 960 | | - |
|---|
| 961 | | - if (i < mci->n_layers - 1) |
|---|
| 962 | | - index *= mci->layers[i + 1].size; |
|---|
| 963 | | - } |
|---|
| 894 | + if (dimm) |
|---|
| 895 | + dimm->ue_count += e->error_count; |
|---|
| 896 | + else |
|---|
| 897 | + mci->ue_noinfo_count += e->error_count; |
|---|
| 964 | 898 | } |
|---|
| 965 | 899 | |
|---|
| 966 | | -static void edac_ce_error(struct mem_ctl_info *mci, |
|---|
| 967 | | - const u16 error_count, |
|---|
| 968 | | - const int pos[EDAC_MAX_LAYERS], |
|---|
| 969 | | - const char *msg, |
|---|
| 970 | | - const char *location, |
|---|
| 971 | | - const char *label, |
|---|
| 972 | | - const char *detail, |
|---|
| 973 | | - const char *other_detail, |
|---|
| 974 | | - const bool enable_per_layer_report, |
|---|
| 975 | | - const unsigned long page_frame_number, |
|---|
| 976 | | - const unsigned long offset_in_page, |
|---|
| 977 | | - long grain) |
|---|
| 900 | +static void edac_ce_error(struct edac_raw_error_desc *e) |
|---|
| 978 | 901 | { |
|---|
| 902 | + struct mem_ctl_info *mci = error_desc_to_mci(e); |
|---|
| 979 | 903 | unsigned long remapped_page; |
|---|
| 980 | | - char *msg_aux = ""; |
|---|
| 981 | | - |
|---|
| 982 | | - if (*msg) |
|---|
| 983 | | - msg_aux = " "; |
|---|
| 984 | 904 | |
|---|
| 985 | 905 | if (edac_mc_get_log_ce()) { |
|---|
| 986 | | - if (other_detail && *other_detail) |
|---|
| 987 | | - edac_mc_printk(mci, KERN_WARNING, |
|---|
| 988 | | - "%d CE %s%son %s (%s %s - %s)\n", |
|---|
| 989 | | - error_count, msg, msg_aux, label, |
|---|
| 990 | | - location, detail, other_detail); |
|---|
| 991 | | - else |
|---|
| 992 | | - edac_mc_printk(mci, KERN_WARNING, |
|---|
| 993 | | - "%d CE %s%son %s (%s %s)\n", |
|---|
| 994 | | - error_count, msg, msg_aux, label, |
|---|
| 995 | | - location, detail); |
|---|
| 906 | + edac_mc_printk(mci, KERN_WARNING, |
|---|
| 907 | + "%d CE %s%son %s (%s page:0x%lx offset:0x%lx grain:%ld syndrome:0x%lx%s%s)\n", |
|---|
| 908 | + e->error_count, e->msg, |
|---|
| 909 | + *e->msg ? " " : "", |
|---|
| 910 | + e->label, e->location, e->page_frame_number, e->offset_in_page, |
|---|
| 911 | + e->grain, e->syndrome, |
|---|
| 912 | + *e->other_detail ? " - " : "", |
|---|
| 913 | + e->other_detail); |
|---|
| 996 | 914 | } |
|---|
| 997 | | - edac_inc_ce_error(mci, enable_per_layer_report, pos, error_count); |
|---|
| 915 | + |
|---|
| 916 | + edac_inc_ce_error(e); |
|---|
| 998 | 917 | |
|---|
| 999 | 918 | if (mci->scrub_mode == SCRUB_SW_SRC) { |
|---|
| 1000 | 919 | /* |
|---|
| .. | .. |
|---|
| 1009 | 928 | * be scrubbed. |
|---|
| 1010 | 929 | */ |
|---|
| 1011 | 930 | remapped_page = mci->ctl_page_to_phys ? |
|---|
| 1012 | | - mci->ctl_page_to_phys(mci, page_frame_number) : |
|---|
| 1013 | | - page_frame_number; |
|---|
| 931 | + mci->ctl_page_to_phys(mci, e->page_frame_number) : |
|---|
| 932 | + e->page_frame_number; |
|---|
| 1014 | 933 | |
|---|
| 1015 | | - edac_mc_scrub_block(remapped_page, |
|---|
| 1016 | | - offset_in_page, grain); |
|---|
| 934 | + edac_mc_scrub_block(remapped_page, e->offset_in_page, e->grain); |
|---|
| 1017 | 935 | } |
|---|
| 1018 | 936 | } |
|---|
| 1019 | 937 | |
|---|
| 1020 | | -static void edac_ue_error(struct mem_ctl_info *mci, |
|---|
| 1021 | | - const u16 error_count, |
|---|
| 1022 | | - const int pos[EDAC_MAX_LAYERS], |
|---|
| 1023 | | - const char *msg, |
|---|
| 1024 | | - const char *location, |
|---|
| 1025 | | - const char *label, |
|---|
| 1026 | | - const char *detail, |
|---|
| 1027 | | - const char *other_detail, |
|---|
| 1028 | | - const bool enable_per_layer_report) |
|---|
| 938 | +static void edac_ue_error(struct edac_raw_error_desc *e) |
|---|
| 1029 | 939 | { |
|---|
| 1030 | | - char *msg_aux = ""; |
|---|
| 1031 | | - |
|---|
| 1032 | | - if (*msg) |
|---|
| 1033 | | - msg_aux = " "; |
|---|
| 940 | + struct mem_ctl_info *mci = error_desc_to_mci(e); |
|---|
| 1034 | 941 | |
|---|
| 1035 | 942 | if (edac_mc_get_log_ue()) { |
|---|
| 1036 | | - if (other_detail && *other_detail) |
|---|
| 1037 | | - edac_mc_printk(mci, KERN_WARNING, |
|---|
| 1038 | | - "%d UE %s%son %s (%s %s - %s)\n", |
|---|
| 1039 | | - error_count, msg, msg_aux, label, |
|---|
| 1040 | | - location, detail, other_detail); |
|---|
| 1041 | | - else |
|---|
| 1042 | | - edac_mc_printk(mci, KERN_WARNING, |
|---|
| 1043 | | - "%d UE %s%son %s (%s %s)\n", |
|---|
| 1044 | | - error_count, msg, msg_aux, label, |
|---|
| 1045 | | - location, detail); |
|---|
| 943 | + edac_mc_printk(mci, KERN_WARNING, |
|---|
| 944 | + "%d UE %s%son %s (%s page:0x%lx offset:0x%lx grain:%ld%s%s)\n", |
|---|
| 945 | + e->error_count, e->msg, |
|---|
| 946 | + *e->msg ? " " : "", |
|---|
| 947 | + e->label, e->location, e->page_frame_number, e->offset_in_page, |
|---|
| 948 | + e->grain, |
|---|
| 949 | + *e->other_detail ? " - " : "", |
|---|
| 950 | + e->other_detail); |
|---|
| 1046 | 951 | } |
|---|
| 952 | + |
|---|
| 953 | + edac_inc_ue_error(e); |
|---|
| 1047 | 954 | |
|---|
| 1048 | 955 | if (edac_mc_get_panic_on_ue()) { |
|---|
| 1049 | | - if (other_detail && *other_detail) |
|---|
| 1050 | | - panic("UE %s%son %s (%s%s - %s)\n", |
|---|
| 1051 | | - msg, msg_aux, label, location, detail, other_detail); |
|---|
| 1052 | | - else |
|---|
| 1053 | | - panic("UE %s%son %s (%s%s)\n", |
|---|
| 1054 | | - msg, msg_aux, label, location, detail); |
|---|
| 956 | + panic("UE %s%son %s (%s page:0x%lx offset:0x%lx grain:%ld%s%s)\n", |
|---|
| 957 | + e->msg, |
|---|
| 958 | + *e->msg ? " " : "", |
|---|
| 959 | + e->label, e->location, e->page_frame_number, e->offset_in_page, |
|---|
| 960 | + e->grain, |
|---|
| 961 | + *e->other_detail ? " - " : "", |
|---|
| 962 | + e->other_detail); |
|---|
| 1055 | 963 | } |
|---|
| 1056 | | - |
|---|
| 1057 | | - edac_inc_ue_error(mci, enable_per_layer_report, pos, error_count); |
|---|
| 1058 | 964 | } |
|---|
| 1059 | 965 | |
|---|
| 1060 | | -void edac_raw_mc_handle_error(const enum hw_event_mc_err_type type, |
|---|
| 1061 | | - struct mem_ctl_info *mci, |
|---|
| 1062 | | - struct edac_raw_error_desc *e) |
|---|
| 966 | +static void edac_inc_csrow(struct edac_raw_error_desc *e, int row, int chan) |
|---|
| 1063 | 967 | { |
|---|
| 1064 | | - char detail[80]; |
|---|
| 1065 | | - int pos[EDAC_MAX_LAYERS] = { e->top_layer, e->mid_layer, e->low_layer }; |
|---|
| 968 | + struct mem_ctl_info *mci = error_desc_to_mci(e); |
|---|
| 969 | + enum hw_event_mc_err_type type = e->type; |
|---|
| 970 | + u16 count = e->error_count; |
|---|
| 1066 | 971 | |
|---|
| 1067 | | - /* Memory type dependent details about the error */ |
|---|
| 972 | + if (row < 0) |
|---|
| 973 | + return; |
|---|
| 974 | + |
|---|
| 975 | + edac_dbg(4, "csrow/channel to increment: (%d,%d)\n", row, chan); |
|---|
| 976 | + |
|---|
| 1068 | 977 | if (type == HW_EVENT_ERR_CORRECTED) { |
|---|
| 1069 | | - snprintf(detail, sizeof(detail), |
|---|
| 1070 | | - "page:0x%lx offset:0x%lx grain:%ld syndrome:0x%lx", |
|---|
| 1071 | | - e->page_frame_number, e->offset_in_page, |
|---|
| 1072 | | - e->grain, e->syndrome); |
|---|
| 1073 | | - edac_ce_error(mci, e->error_count, pos, e->msg, e->location, e->label, |
|---|
| 1074 | | - detail, e->other_detail, e->enable_per_layer_report, |
|---|
| 1075 | | - e->page_frame_number, e->offset_in_page, e->grain); |
|---|
| 978 | + mci->csrows[row]->ce_count += count; |
|---|
| 979 | + if (chan >= 0) |
|---|
| 980 | + mci->csrows[row]->channels[chan]->ce_count += count; |
|---|
| 1076 | 981 | } else { |
|---|
| 1077 | | - snprintf(detail, sizeof(detail), |
|---|
| 1078 | | - "page:0x%lx offset:0x%lx grain:%ld", |
|---|
| 1079 | | - e->page_frame_number, e->offset_in_page, e->grain); |
|---|
| 1080 | | - |
|---|
| 1081 | | - edac_ue_error(mci, e->error_count, pos, e->msg, e->location, e->label, |
|---|
| 1082 | | - detail, e->other_detail, e->enable_per_layer_report); |
|---|
| 982 | + mci->csrows[row]->ue_count += count; |
|---|
| 1083 | 983 | } |
|---|
| 984 | +} |
|---|
| 1084 | 985 | |
|---|
| 986 | +void edac_raw_mc_handle_error(struct edac_raw_error_desc *e) |
|---|
| 987 | +{ |
|---|
| 988 | + struct mem_ctl_info *mci = error_desc_to_mci(e); |
|---|
| 989 | + u8 grain_bits; |
|---|
| 1085 | 990 | |
|---|
| 991 | + /* Sanity-check driver-supplied grain value. */ |
|---|
| 992 | + if (WARN_ON_ONCE(!e->grain)) |
|---|
| 993 | + e->grain = 1; |
|---|
| 994 | + |
|---|
| 995 | + grain_bits = fls_long(e->grain - 1); |
|---|
| 996 | + |
|---|
| 997 | + /* Report the error via the trace interface */ |
|---|
| 998 | + if (IS_ENABLED(CONFIG_RAS)) |
|---|
| 999 | + trace_mc_event(e->type, e->msg, e->label, e->error_count, |
|---|
| 1000 | + mci->mc_idx, e->top_layer, e->mid_layer, |
|---|
| 1001 | + e->low_layer, |
|---|
| 1002 | + (e->page_frame_number << PAGE_SHIFT) | e->offset_in_page, |
|---|
| 1003 | + grain_bits, e->syndrome, e->other_detail); |
|---|
| 1004 | + |
|---|
| 1005 | + if (e->type == HW_EVENT_ERR_CORRECTED) |
|---|
| 1006 | + edac_ce_error(e); |
|---|
| 1007 | + else |
|---|
| 1008 | + edac_ue_error(e); |
|---|
| 1086 | 1009 | } |
|---|
| 1087 | 1010 | EXPORT_SYMBOL_GPL(edac_raw_mc_handle_error); |
|---|
| 1088 | 1011 | |
|---|
| .. | .. |
|---|
| 1098 | 1021 | const char *msg, |
|---|
| 1099 | 1022 | const char *other_detail) |
|---|
| 1100 | 1023 | { |
|---|
| 1024 | + struct dimm_info *dimm; |
|---|
| 1101 | 1025 | char *p; |
|---|
| 1102 | 1026 | int row = -1, chan = -1; |
|---|
| 1103 | 1027 | int pos[EDAC_MAX_LAYERS] = { top_layer, mid_layer, low_layer }; |
|---|
| 1104 | 1028 | int i, n_labels = 0; |
|---|
| 1105 | | - u8 grain_bits; |
|---|
| 1106 | 1029 | struct edac_raw_error_desc *e = &mci->error_desc; |
|---|
| 1030 | + bool any_memory = true; |
|---|
| 1107 | 1031 | |
|---|
| 1108 | 1032 | edac_dbg(3, "MC%d\n", mci->mc_idx); |
|---|
| 1109 | 1033 | |
|---|
| 1110 | 1034 | /* Fills the error report buffer */ |
|---|
| 1111 | 1035 | memset(e, 0, sizeof (*e)); |
|---|
| 1112 | 1036 | e->error_count = error_count; |
|---|
| 1037 | + e->type = type; |
|---|
| 1113 | 1038 | e->top_layer = top_layer; |
|---|
| 1114 | 1039 | e->mid_layer = mid_layer; |
|---|
| 1115 | 1040 | e->low_layer = low_layer; |
|---|
| 1116 | 1041 | e->page_frame_number = page_frame_number; |
|---|
| 1117 | 1042 | e->offset_in_page = offset_in_page; |
|---|
| 1118 | 1043 | e->syndrome = syndrome; |
|---|
| 1119 | | - e->msg = msg; |
|---|
| 1120 | | - e->other_detail = other_detail; |
|---|
| 1044 | + /* need valid strings here for both: */ |
|---|
| 1045 | + e->msg = msg ?: ""; |
|---|
| 1046 | + e->other_detail = other_detail ?: ""; |
|---|
| 1121 | 1047 | |
|---|
| 1122 | 1048 | /* |
|---|
| 1123 | | - * Check if the event report is consistent and if the memory |
|---|
| 1124 | | - * location is known. If it is known, enable_per_layer_report will be |
|---|
| 1125 | | - * true, the DIMM(s) label info will be filled and the per-layer |
|---|
| 1049 | + * Check if the event report is consistent and if the memory location is |
|---|
| 1050 | + * known. If it is, the DIMM(s) label info will be filled and the DIMM's |
|---|
| 1126 | 1051 | * error counters will be incremented. |
|---|
| 1127 | 1052 | */ |
|---|
| 1128 | 1053 | for (i = 0; i < mci->n_layers; i++) { |
|---|
| .. | .. |
|---|
| 1141 | 1066 | pos[i] = -1; |
|---|
| 1142 | 1067 | } |
|---|
| 1143 | 1068 | if (pos[i] >= 0) |
|---|
| 1144 | | - e->enable_per_layer_report = true; |
|---|
| 1069 | + any_memory = false; |
|---|
| 1145 | 1070 | } |
|---|
| 1146 | 1071 | |
|---|
| 1147 | 1072 | /* |
|---|
| .. | .. |
|---|
| 1158 | 1083 | p = e->label; |
|---|
| 1159 | 1084 | *p = '\0'; |
|---|
| 1160 | 1085 | |
|---|
| 1161 | | - for (i = 0; i < mci->tot_dimms; i++) { |
|---|
| 1162 | | - struct dimm_info *dimm = mci->dimms[i]; |
|---|
| 1163 | | - |
|---|
| 1086 | + mci_for_each_dimm(mci, dimm) { |
|---|
| 1164 | 1087 | if (top_layer >= 0 && top_layer != dimm->location[0]) |
|---|
| 1165 | 1088 | continue; |
|---|
| 1166 | 1089 | if (mid_layer >= 0 && mid_layer != dimm->location[1]) |
|---|
| .. | .. |
|---|
| 1174 | 1097 | |
|---|
| 1175 | 1098 | /* |
|---|
| 1176 | 1099 | * If the error is memory-controller wide, there's no need to |
|---|
| 1177 | | - * seek for the affected DIMMs because the whole |
|---|
| 1178 | | - * channel/memory controller/... may be affected. |
|---|
| 1179 | | - * Also, don't show errors for empty DIMM slots. |
|---|
| 1100 | + * seek for the affected DIMMs because the whole channel/memory |
|---|
| 1101 | + * controller/... may be affected. Also, don't show errors for |
|---|
| 1102 | + * empty DIMM slots. |
|---|
| 1180 | 1103 | */ |
|---|
| 1181 | | - if (e->enable_per_layer_report && dimm->nr_pages) { |
|---|
| 1182 | | - if (n_labels >= EDAC_MAX_LABELS) { |
|---|
| 1183 | | - e->enable_per_layer_report = false; |
|---|
| 1184 | | - break; |
|---|
| 1185 | | - } |
|---|
| 1186 | | - n_labels++; |
|---|
| 1104 | + if (!dimm->nr_pages) |
|---|
| 1105 | + continue; |
|---|
| 1106 | + |
|---|
| 1107 | + n_labels++; |
|---|
| 1108 | + if (n_labels > EDAC_MAX_LABELS) { |
|---|
| 1109 | + p = e->label; |
|---|
| 1110 | + *p = '\0'; |
|---|
| 1111 | + } else { |
|---|
| 1187 | 1112 | if (p != e->label) { |
|---|
| 1188 | 1113 | strcpy(p, OTHER_LABEL); |
|---|
| 1189 | 1114 | p += strlen(OTHER_LABEL); |
|---|
| 1190 | 1115 | } |
|---|
| 1191 | 1116 | strcpy(p, dimm->label); |
|---|
| 1192 | 1117 | p += strlen(p); |
|---|
| 1193 | | - *p = '\0'; |
|---|
| 1194 | | - |
|---|
| 1195 | | - /* |
|---|
| 1196 | | - * get csrow/channel of the DIMM, in order to allow |
|---|
| 1197 | | - * incrementing the compat API counters |
|---|
| 1198 | | - */ |
|---|
| 1199 | | - edac_dbg(4, "%s csrows map: (%d,%d)\n", |
|---|
| 1200 | | - mci->csbased ? "rank" : "dimm", |
|---|
| 1201 | | - dimm->csrow, dimm->cschannel); |
|---|
| 1202 | | - if (row == -1) |
|---|
| 1203 | | - row = dimm->csrow; |
|---|
| 1204 | | - else if (row >= 0 && row != dimm->csrow) |
|---|
| 1205 | | - row = -2; |
|---|
| 1206 | | - |
|---|
| 1207 | | - if (chan == -1) |
|---|
| 1208 | | - chan = dimm->cschannel; |
|---|
| 1209 | | - else if (chan >= 0 && chan != dimm->cschannel) |
|---|
| 1210 | | - chan = -2; |
|---|
| 1211 | 1118 | } |
|---|
| 1119 | + |
|---|
| 1120 | + /* |
|---|
| 1121 | + * get csrow/channel of the DIMM, in order to allow |
|---|
| 1122 | + * incrementing the compat API counters |
|---|
| 1123 | + */ |
|---|
| 1124 | + edac_dbg(4, "%s csrows map: (%d,%d)\n", |
|---|
| 1125 | + mci->csbased ? "rank" : "dimm", |
|---|
| 1126 | + dimm->csrow, dimm->cschannel); |
|---|
| 1127 | + if (row == -1) |
|---|
| 1128 | + row = dimm->csrow; |
|---|
| 1129 | + else if (row >= 0 && row != dimm->csrow) |
|---|
| 1130 | + row = -2; |
|---|
| 1131 | + |
|---|
| 1132 | + if (chan == -1) |
|---|
| 1133 | + chan = dimm->cschannel; |
|---|
| 1134 | + else if (chan >= 0 && chan != dimm->cschannel) |
|---|
| 1135 | + chan = -2; |
|---|
| 1212 | 1136 | } |
|---|
| 1213 | 1137 | |
|---|
| 1214 | | - if (!e->enable_per_layer_report) { |
|---|
| 1138 | + if (any_memory) |
|---|
| 1215 | 1139 | strcpy(e->label, "any memory"); |
|---|
| 1216 | | - } else { |
|---|
| 1217 | | - edac_dbg(4, "csrow/channel to increment: (%d,%d)\n", row, chan); |
|---|
| 1218 | | - if (p == e->label) |
|---|
| 1219 | | - strcpy(e->label, "unknown memory"); |
|---|
| 1220 | | - if (type == HW_EVENT_ERR_CORRECTED) { |
|---|
| 1221 | | - if (row >= 0) { |
|---|
| 1222 | | - mci->csrows[row]->ce_count += error_count; |
|---|
| 1223 | | - if (chan >= 0) |
|---|
| 1224 | | - mci->csrows[row]->channels[chan]->ce_count += error_count; |
|---|
| 1225 | | - } |
|---|
| 1226 | | - } else |
|---|
| 1227 | | - if (row >= 0) |
|---|
| 1228 | | - mci->csrows[row]->ue_count += error_count; |
|---|
| 1229 | | - } |
|---|
| 1140 | + else if (!*e->label) |
|---|
| 1141 | + strcpy(e->label, "unknown memory"); |
|---|
| 1142 | + |
|---|
| 1143 | + edac_inc_csrow(e, row, chan); |
|---|
| 1230 | 1144 | |
|---|
| 1231 | 1145 | /* Fill the RAM location data */ |
|---|
| 1232 | 1146 | p = e->location; |
|---|
| .. | .. |
|---|
| 1242 | 1156 | if (p > e->location) |
|---|
| 1243 | 1157 | *(p - 1) = '\0'; |
|---|
| 1244 | 1158 | |
|---|
| 1245 | | - /* Sanity-check driver-supplied grain value. */ |
|---|
| 1246 | | - if (WARN_ON_ONCE(!e->grain)) |
|---|
| 1247 | | - e->grain = 1; |
|---|
| 1248 | | - |
|---|
| 1249 | | - grain_bits = fls_long(e->grain - 1); |
|---|
| 1250 | | - |
|---|
| 1251 | | - /* Report the error via the trace interface */ |
|---|
| 1252 | | - if (IS_ENABLED(CONFIG_RAS)) |
|---|
| 1253 | | - trace_mc_event(type, e->msg, e->label, e->error_count, |
|---|
| 1254 | | - mci->mc_idx, e->top_layer, e->mid_layer, |
|---|
| 1255 | | - e->low_layer, |
|---|
| 1256 | | - (e->page_frame_number << PAGE_SHIFT) | e->offset_in_page, |
|---|
| 1257 | | - grain_bits, e->syndrome, e->other_detail); |
|---|
| 1258 | | - |
|---|
| 1259 | | - edac_raw_mc_handle_error(type, mci, e); |
|---|
| 1159 | + edac_raw_mc_handle_error(e); |
|---|
| 1260 | 1160 | } |
|---|
| 1261 | 1161 | EXPORT_SYMBOL_GPL(edac_mc_handle_error); |
|---|