diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-30 12:53:50 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-30 12:53:50 -0400 |
| commit | 8da8533dfb0929c5ea5d9fdf60ea6d3ffa02127d (patch) | |
| tree | 1f9fe13e150dae31cf48ac3a88d5003040c2ec98 /include | |
| parent | f50f118c4974f7c2208a54f96452165ffb880471 (diff) | |
| parent | c2078e4c9120e7b38b1a02cd9fc6dd4f792110bf (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac
Pull EDAC patches from Mauro Carvalho Chehab:
- the second part of the EDAC rework:
- Add the sysfs nodes that exports the real memory layout, instead
of the fake one (needed to properly represent Intel memory
controllers since 2002)
- convert EDAC MC to use "struct device" instead of creating the
sysfs nodes via the kobj API
- adds a tracepoint to represent memory errors
- some cleanup patches
- some fixes at i5000, i5400 and EDAC core
- a new EDAC driver for Caldera.
* git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac: (33 commits)
edac i5000, i5400: fix pointer math in i5000_get_mc_regs()
edac: allow specifying the error count with fake_inject
edac: add support for Calxeda highbank L2 cache ecc
edac: add support for Calxeda highbank memory controller
edac: create top-level debugfs directory
sb_edac: properly handle error count
i7core_edac: properly handle error count
edac: edac_mc_handle_error(): add an error_count parameter
edac: remove arch-specific parameter for the error handler
amd64_edac: Don't pass driver name as an error parameter
edac_mc: check for allocation failure in edac_mc_alloc()
edac: Increase version to 3.0.0
edac_mc: Cleanup per-dimm_info debug messages
edac: Convert debugfX to edac_dbg(X,
edac: Use more normal debugging macro style
edac: Don't add __func__ or __FILE__ for debugf[0-9] msgs
Edac: Add ABI Documentation for the new device nodes
edac: move documentation ABI to ABI/testing/sysfs-devices-edac
i7core_edac: change the mem allocation scheme to make Documentation/kobject.txt happy
edac: change the mem allocation scheme to make Documentation/kobject.txt happy
...
Diffstat (limited to 'include')
| -rw-r--r-- | include/linux/edac.h | 208 | ||||
| -rw-r--r-- | include/ras/ras_event.h | 102 |
2 files changed, 235 insertions, 75 deletions
diff --git a/include/linux/edac.h b/include/linux/edac.h index 91ba3bae42ee..bab9f8473dc1 100644 --- a/include/linux/edac.h +++ b/include/linux/edac.h | |||
| @@ -13,9 +13,11 @@ | |||
| 13 | #define _LINUX_EDAC_H_ | 13 | #define _LINUX_EDAC_H_ |
| 14 | 14 | ||
| 15 | #include <linux/atomic.h> | 15 | #include <linux/atomic.h> |
| 16 | #include <linux/device.h> | ||
| 16 | #include <linux/kobject.h> | 17 | #include <linux/kobject.h> |
| 17 | #include <linux/completion.h> | 18 | #include <linux/completion.h> |
| 18 | #include <linux/workqueue.h> | 19 | #include <linux/workqueue.h> |
| 20 | #include <linux/debugfs.h> | ||
| 19 | 21 | ||
| 20 | struct device; | 22 | struct device; |
| 21 | 23 | ||
| @@ -49,7 +51,19 @@ static inline void opstate_init(void) | |||
| 49 | #define EDAC_MC_LABEL_LEN 31 | 51 | #define EDAC_MC_LABEL_LEN 31 |
| 50 | #define MC_PROC_NAME_MAX_LEN 7 | 52 | #define MC_PROC_NAME_MAX_LEN 7 |
| 51 | 53 | ||
| 52 | /* memory devices */ | 54 | /** |
| 55 | * enum dev_type - describe the type of memory DRAM chips used at the stick | ||
| 56 | * @DEV_UNKNOWN: Can't be determined, or MC doesn't support detect it | ||
| 57 | * @DEV_X1: 1 bit for data | ||
| 58 | * @DEV_X2: 2 bits for data | ||
| 59 | * @DEV_X4: 4 bits for data | ||
| 60 | * @DEV_X8: 8 bits for data | ||
| 61 | * @DEV_X16: 16 bits for data | ||
| 62 | * @DEV_X32: 32 bits for data | ||
| 63 | * @DEV_X64: 64 bits for data | ||
| 64 | * | ||
| 65 | * Typical values are x4 and x8. | ||
| 66 | */ | ||
| 53 | enum dev_type { | 67 | enum dev_type { |
| 54 | DEV_UNKNOWN = 0, | 68 | DEV_UNKNOWN = 0, |
| 55 | DEV_X1, | 69 | DEV_X1, |
| @@ -167,18 +181,30 @@ enum mem_type { | |||
| 167 | #define MEM_FLAG_DDR3 BIT(MEM_DDR3) | 181 | #define MEM_FLAG_DDR3 BIT(MEM_DDR3) |
| 168 | #define MEM_FLAG_RDDR3 BIT(MEM_RDDR3) | 182 | #define MEM_FLAG_RDDR3 BIT(MEM_RDDR3) |
| 169 | 183 | ||
| 170 | /* chipset Error Detection and Correction capabilities and mode */ | 184 | /** |
| 185 | * enum edac-type - Error Detection and Correction capabilities and mode | ||
| 186 | * @EDAC_UNKNOWN: Unknown if ECC is available | ||
| 187 | * @EDAC_NONE: Doesn't support ECC | ||
| 188 | * @EDAC_RESERVED: Reserved ECC type | ||
| 189 | * @EDAC_PARITY: Detects parity errors | ||
| 190 | * @EDAC_EC: Error Checking - no correction | ||
| 191 | * @EDAC_SECDED: Single bit error correction, Double detection | ||
| 192 | * @EDAC_S2ECD2ED: Chipkill x2 devices - do these exist? | ||
| 193 | * @EDAC_S4ECD4ED: Chipkill x4 devices | ||
| 194 | * @EDAC_S8ECD8ED: Chipkill x8 devices | ||
| 195 | * @EDAC_S16ECD16ED: Chipkill x16 devices | ||
| 196 | */ | ||
| 171 | enum edac_type { | 197 | enum edac_type { |
| 172 | EDAC_UNKNOWN = 0, /* Unknown if ECC is available */ | 198 | EDAC_UNKNOWN = 0, |
| 173 | EDAC_NONE, /* Doesn't support ECC */ | 199 | EDAC_NONE, |
| 174 | EDAC_RESERVED, /* Reserved ECC type */ | 200 | EDAC_RESERVED, |
| 175 | EDAC_PARITY, /* Detects parity errors */ | 201 | EDAC_PARITY, |
| 176 | EDAC_EC, /* Error Checking - no correction */ | 202 | EDAC_EC, |
| 177 | EDAC_SECDED, /* Single bit error correction, Double detection */ | 203 | EDAC_SECDED, |
| 178 | EDAC_S2ECD2ED, /* Chipkill x2 devices - do these exist? */ | 204 | EDAC_S2ECD2ED, |
| 179 | EDAC_S4ECD4ED, /* Chipkill x4 devices */ | 205 | EDAC_S4ECD4ED, |
| 180 | EDAC_S8ECD8ED, /* Chipkill x8 devices */ | 206 | EDAC_S8ECD8ED, |
| 181 | EDAC_S16ECD16ED, /* Chipkill x16 devices */ | 207 | EDAC_S16ECD16ED, |
| 182 | }; | 208 | }; |
| 183 | 209 | ||
| 184 | #define EDAC_FLAG_UNKNOWN BIT(EDAC_UNKNOWN) | 210 | #define EDAC_FLAG_UNKNOWN BIT(EDAC_UNKNOWN) |
| @@ -191,18 +217,30 @@ enum edac_type { | |||
| 191 | #define EDAC_FLAG_S8ECD8ED BIT(EDAC_S8ECD8ED) | 217 | #define EDAC_FLAG_S8ECD8ED BIT(EDAC_S8ECD8ED) |
| 192 | #define EDAC_FLAG_S16ECD16ED BIT(EDAC_S16ECD16ED) | 218 | #define EDAC_FLAG_S16ECD16ED BIT(EDAC_S16ECD16ED) |
| 193 | 219 | ||
| 194 | /* scrubbing capabilities */ | 220 | /** |
| 221 | * enum scrub_type - scrubbing capabilities | ||
| 222 | * @SCRUB_UNKNOWN Unknown if scrubber is available | ||
| 223 | * @SCRUB_NONE: No scrubber | ||
| 224 | * @SCRUB_SW_PROG: SW progressive (sequential) scrubbing | ||
| 225 | * @SCRUB_SW_SRC: Software scrub only errors | ||
| 226 | * @SCRUB_SW_PROG_SRC: Progressive software scrub from an error | ||
| 227 | * @SCRUB_SW_TUNABLE: Software scrub frequency is tunable | ||
| 228 | * @SCRUB_HW_PROG: HW progressive (sequential) scrubbing | ||
| 229 | * @SCRUB_HW_SRC: Hardware scrub only errors | ||
| 230 | * @SCRUB_HW_PROG_SRC: Progressive hardware scrub from an error | ||
| 231 | * SCRUB_HW_TUNABLE: Hardware scrub frequency is tunable | ||
| 232 | */ | ||
| 195 | enum scrub_type { | 233 | enum scrub_type { |
| 196 | SCRUB_UNKNOWN = 0, /* Unknown if scrubber is available */ | 234 | SCRUB_UNKNOWN = 0, |
| 197 | SCRUB_NONE, /* No scrubber */ | 235 | SCRUB_NONE, |
| 198 | SCRUB_SW_PROG, /* SW progressive (sequential) scrubbing */ | 236 | SCRUB_SW_PROG, |
| 199 | SCRUB_SW_SRC, /* Software scrub only errors */ | 237 | SCRUB_SW_SRC, |
| 200 | SCRUB_SW_PROG_SRC, /* Progressive software scrub from an error */ | 238 | SCRUB_SW_PROG_SRC, |
| 201 | SCRUB_SW_TUNABLE, /* Software scrub frequency is tunable */ | 239 | SCRUB_SW_TUNABLE, |
| 202 | SCRUB_HW_PROG, /* HW progressive (sequential) scrubbing */ | 240 | SCRUB_HW_PROG, |
| 203 | SCRUB_HW_SRC, /* Hardware scrub only errors */ | 241 | SCRUB_HW_SRC, |
| 204 | SCRUB_HW_PROG_SRC, /* Progressive hardware scrub from an error */ | 242 | SCRUB_HW_PROG_SRC, |
| 205 | SCRUB_HW_TUNABLE /* Hardware scrub frequency is tunable */ | 243 | SCRUB_HW_TUNABLE |
| 206 | }; | 244 | }; |
| 207 | 245 | ||
| 208 | #define SCRUB_FLAG_SW_PROG BIT(SCRUB_SW_PROG) | 246 | #define SCRUB_FLAG_SW_PROG BIT(SCRUB_SW_PROG) |
| @@ -374,23 +412,21 @@ struct edac_mc_layer { | |||
| 374 | #define EDAC_MAX_LAYERS 3 | 412 | #define EDAC_MAX_LAYERS 3 |
| 375 | 413 | ||
| 376 | /** | 414 | /** |
| 377 | * EDAC_DIMM_PTR - Macro responsible to find a pointer inside a pointer array | 415 | * EDAC_DIMM_OFF - Macro responsible to get a pointer offset inside a pointer array |
| 378 | * for the element given by [layer0,layer1,layer2] position | 416 | * for the element given by [layer0,layer1,layer2] position |
| 379 | * | 417 | * |
| 380 | * @layers: a struct edac_mc_layer array, describing how many elements | 418 | * @layers: a struct edac_mc_layer array, describing how many elements |
| 381 | * were allocated for each layer | 419 | * were allocated for each layer |
| 382 | * @var: name of the var where we want to get the pointer | ||
| 383 | * (like mci->dimms) | ||
| 384 | * @n_layers: Number of layers at the @layers array | 420 | * @n_layers: Number of layers at the @layers array |
| 385 | * @layer0: layer0 position | 421 | * @layer0: layer0 position |
| 386 | * @layer1: layer1 position. Unused if n_layers < 2 | 422 | * @layer1: layer1 position. Unused if n_layers < 2 |
| 387 | * @layer2: layer2 position. Unused if n_layers < 3 | 423 | * @layer2: layer2 position. Unused if n_layers < 3 |
| 388 | * | 424 | * |
| 389 | * For 1 layer, this macro returns &var[layer0] | 425 | * For 1 layer, this macro returns &var[layer0] - &var |
| 390 | * For 2 layers, this macro is similar to allocate a bi-dimensional array | 426 | * For 2 layers, this macro is similar to allocate a bi-dimensional array |
| 391 | * and to return "&var[layer0][layer1]" | 427 | * and to return "&var[layer0][layer1] - &var" |
| 392 | * For 3 layers, this macro is similar to allocate a tri-dimensional array | 428 | * For 3 layers, this macro is similar to allocate a tri-dimensional array |
| 393 | * and to return "&var[layer0][layer1][layer2]" | 429 | * and to return "&var[layer0][layer1][layer2] - &var" |
| 394 | * | 430 | * |
| 395 | * A loop could be used here to make it more generic, but, as we only have | 431 | * A loop could be used here to make it more generic, but, as we only have |
| 396 | * 3 layers, this is a little faster. | 432 | * 3 layers, this is a little faster. |
| @@ -398,23 +434,52 @@ struct edac_mc_layer { | |||
| 398 | * a NULL is returned, causing an OOPS during the memory allocation routine, | 434 | * a NULL is returned, causing an OOPS during the memory allocation routine, |
| 399 | * with would point to the developer that he's doing something wrong. | 435 | * with would point to the developer that he's doing something wrong. |
| 400 | */ | 436 | */ |
| 401 | #define EDAC_DIMM_PTR(layers, var, nlayers, layer0, layer1, layer2) ({ \ | 437 | #define EDAC_DIMM_OFF(layers, nlayers, layer0, layer1, layer2) ({ \ |
| 402 | typeof(var) __p; \ | 438 | int __i; \ |
| 403 | if ((nlayers) == 1) \ | 439 | if ((nlayers) == 1) \ |
| 404 | __p = &var[layer0]; \ | 440 | __i = layer0; \ |
| 405 | else if ((nlayers) == 2) \ | 441 | else if ((nlayers) == 2) \ |
| 406 | __p = &var[(layer1) + ((layers[1]).size * (layer0))]; \ | 442 | __i = (layer1) + ((layers[1]).size * (layer0)); \ |
| 407 | else if ((nlayers) == 3) \ | 443 | else if ((nlayers) == 3) \ |
| 408 | __p = &var[(layer2) + ((layers[2]).size * ((layer1) + \ | 444 | __i = (layer2) + ((layers[2]).size * ((layer1) + \ |
| 409 | ((layers[1]).size * (layer0))))]; \ | 445 | ((layers[1]).size * (layer0)))); \ |
| 410 | else \ | 446 | else \ |
| 447 | __i = -EINVAL; \ | ||
| 448 | __i; \ | ||
| 449 | }) | ||
| 450 | |||
| 451 | /** | ||
| 452 | * EDAC_DIMM_PTR - Macro responsible to get a pointer inside a pointer array | ||
| 453 | * for the element given by [layer0,layer1,layer2] position | ||
| 454 | * | ||
| 455 | * @layers: a struct edac_mc_layer array, describing how many elements | ||
| 456 | * were allocated for each layer | ||
| 457 | * @var: name of the var where we want to get the pointer | ||
| 458 | * (like mci->dimms) | ||
| 459 | * @n_layers: Number of layers at the @layers array | ||
| 460 | * @layer0: layer0 position | ||
| 461 | * @layer1: layer1 position. Unused if n_layers < 2 | ||
| 462 | * @layer2: layer2 position. Unused if n_layers < 3 | ||
| 463 | * | ||
| 464 | * For 1 layer, this macro returns &var[layer0] | ||
| 465 | * For 2 layers, this macro is similar to allocate a bi-dimensional array | ||
| 466 | * and to return "&var[layer0][layer1]" | ||
| 467 | * For 3 layers, this macro is similar to allocate a tri-dimensional array | ||
| 468 | * and to return "&var[layer0][layer1][layer2]" | ||
| 469 | */ | ||
| 470 | #define EDAC_DIMM_PTR(layers, var, nlayers, layer0, layer1, layer2) ({ \ | ||
| 471 | typeof(*var) __p; \ | ||
| 472 | int ___i = EDAC_DIMM_OFF(layers, nlayers, layer0, layer1, layer2); \ | ||
| 473 | if (___i < 0) \ | ||
| 411 | __p = NULL; \ | 474 | __p = NULL; \ |
| 475 | else \ | ||
| 476 | __p = (var)[___i]; \ | ||
| 412 | __p; \ | 477 | __p; \ |
| 413 | }) | 478 | }) |
| 414 | 479 | ||
| 415 | |||
| 416 | /* FIXME: add the proper per-location error counts */ | ||
| 417 | struct dimm_info { | 480 | struct dimm_info { |
| 481 | struct device dev; | ||
| 482 | |||
| 418 | char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */ | 483 | char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */ |
| 419 | 484 | ||
| 420 | /* Memory location data */ | 485 | /* Memory location data */ |
| @@ -456,6 +521,8 @@ struct rank_info { | |||
| 456 | }; | 521 | }; |
| 457 | 522 | ||
| 458 | struct csrow_info { | 523 | struct csrow_info { |
| 524 | struct device dev; | ||
| 525 | |||
| 459 | /* Used only by edac_mc_find_csrow_by_page() */ | 526 | /* Used only by edac_mc_find_csrow_by_page() */ |
| 460 | unsigned long first_page; /* first page number in csrow */ | 527 | unsigned long first_page; /* first page number in csrow */ |
| 461 | unsigned long last_page; /* last page number in csrow */ | 528 | unsigned long last_page; /* last page number in csrow */ |
| @@ -469,44 +536,26 @@ struct csrow_info { | |||
| 469 | 536 | ||
| 470 | struct mem_ctl_info *mci; /* the parent */ | 537 | struct mem_ctl_info *mci; /* the parent */ |
| 471 | 538 | ||
| 472 | struct kobject kobj; /* sysfs kobject for this csrow */ | ||
| 473 | |||
| 474 | /* channel information for this csrow */ | 539 | /* channel information for this csrow */ |
| 475 | u32 nr_channels; | 540 | u32 nr_channels; |
| 476 | struct rank_info *channels; | 541 | struct rank_info **channels; |
| 477 | }; | 542 | }; |
| 478 | 543 | ||
| 479 | struct mcidev_sysfs_group { | 544 | /* |
| 480 | const char *name; /* group name */ | 545 | * struct errcount_attribute - used to store the several error counts |
| 481 | const struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */ | ||
| 482 | }; | ||
| 483 | |||
| 484 | struct mcidev_sysfs_group_kobj { | ||
| 485 | struct list_head list; /* list for all instances within a mc */ | ||
| 486 | |||
| 487 | struct kobject kobj; /* kobj for the group */ | ||
| 488 | |||
| 489 | const struct mcidev_sysfs_group *grp; /* group description table */ | ||
| 490 | struct mem_ctl_info *mci; /* the parent */ | ||
| 491 | }; | ||
| 492 | |||
| 493 | /* mcidev_sysfs_attribute structure | ||
| 494 | * used for driver sysfs attributes and in mem_ctl_info | ||
| 495 | * sysfs top level entries | ||
| 496 | */ | 546 | */ |
| 497 | struct mcidev_sysfs_attribute { | 547 | struct errcount_attribute_data { |
| 498 | /* It should use either attr or grp */ | 548 | int n_layers; |
| 499 | struct attribute attr; | 549 | int pos[EDAC_MAX_LAYERS]; |
| 500 | const struct mcidev_sysfs_group *grp; /* Points to a group of attributes */ | 550 | int layer0, layer1, layer2; |
| 501 | |||
| 502 | /* Ops for show/store values at the attribute - not used on group */ | ||
| 503 | ssize_t (*show)(struct mem_ctl_info *,char *); | ||
| 504 | ssize_t (*store)(struct mem_ctl_info *, const char *,size_t); | ||
| 505 | }; | 551 | }; |
| 506 | 552 | ||
| 507 | /* MEMORY controller information structure | 553 | /* MEMORY controller information structure |
| 508 | */ | 554 | */ |
| 509 | struct mem_ctl_info { | 555 | struct mem_ctl_info { |
| 556 | struct device dev; | ||
| 557 | struct bus_type bus; | ||
| 558 | |||
| 510 | struct list_head link; /* for global list of mem_ctl_info structs */ | 559 | struct list_head link; /* for global list of mem_ctl_info structs */ |
| 511 | 560 | ||
| 512 | struct module *owner; /* Module owner of this control struct */ | 561 | struct module *owner; /* Module owner of this control struct */ |
| @@ -548,10 +597,18 @@ struct mem_ctl_info { | |||
| 548 | unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci, | 597 | unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci, |
| 549 | unsigned long page); | 598 | unsigned long page); |
| 550 | int mc_idx; | 599 | int mc_idx; |
| 551 | struct csrow_info *csrows; | 600 | struct csrow_info **csrows; |
| 552 | unsigned nr_csrows, num_cschannel; | 601 | unsigned nr_csrows, num_cschannel; |
| 553 | 602 | ||
| 554 | /* Memory Controller hierarchy */ | 603 | /* |
| 604 | * Memory Controller hierarchy | ||
| 605 | * | ||
| 606 | * There are basically two types of memory controller: the ones that | ||
| 607 | * sees memory sticks ("dimms"), and the ones that sees memory ranks. | ||
| 608 | * All old memory controllers enumerate memories per rank, but most | ||
| 609 | * of the recent drivers enumerate memories per DIMM, instead. | ||
| 610 | * When the memory controller is per rank, mem_is_per_rank is true. | ||
| 611 | */ | ||
| 555 | unsigned n_layers; | 612 | unsigned n_layers; |
| 556 | struct edac_mc_layer *layers; | 613 | struct edac_mc_layer *layers; |
| 557 | bool mem_is_per_rank; | 614 | bool mem_is_per_rank; |
| @@ -560,14 +617,14 @@ struct mem_ctl_info { | |||
| 560 | * DIMM info. Will eventually remove the entire csrows_info some day | 617 | * DIMM info. Will eventually remove the entire csrows_info some day |
| 561 | */ | 618 | */ |
| 562 | unsigned tot_dimms; | 619 | unsigned tot_dimms; |
| 563 | struct dimm_info *dimms; | 620 | struct dimm_info **dimms; |
| 564 | 621 | ||
| 565 | /* | 622 | /* |
| 566 | * FIXME - what about controllers on other busses? - IDs must be | 623 | * FIXME - what about controllers on other busses? - IDs must be |
| 567 | * unique. dev pointer should be sufficiently unique, but | 624 | * unique. dev pointer should be sufficiently unique, but |
| 568 | * BUS:SLOT.FUNC numbers may not be unique. | 625 | * BUS:SLOT.FUNC numbers may not be unique. |
| 569 | */ | 626 | */ |
| 570 | struct device *dev; | 627 | struct device *pdev; |
| 571 | const char *mod_name; | 628 | const char *mod_name; |
| 572 | const char *mod_ver; | 629 | const char *mod_ver; |
| 573 | const char *ctl_name; | 630 | const char *ctl_name; |
| @@ -586,12 +643,6 @@ struct mem_ctl_info { | |||
| 586 | 643 | ||
| 587 | struct completion complete; | 644 | struct completion complete; |
| 588 | 645 | ||
| 589 | /* edac sysfs device control */ | ||
| 590 | struct kobject edac_mci_kobj; | ||
| 591 | |||
| 592 | /* list for all grp instances within a mc */ | ||
| 593 | struct list_head grp_kobj_list; | ||
| 594 | |||
| 595 | /* Additional top controller level attributes, but specified | 646 | /* Additional top controller level attributes, but specified |
| 596 | * by the low level driver. | 647 | * by the low level driver. |
| 597 | * | 648 | * |
| @@ -609,6 +660,13 @@ struct mem_ctl_info { | |||
| 609 | 660 | ||
| 610 | /* the internal state of this controller instance */ | 661 | /* the internal state of this controller instance */ |
| 611 | int op_state; | 662 | int op_state; |
| 663 | |||
| 664 | #ifdef CONFIG_EDAC_DEBUG | ||
| 665 | struct dentry *debugfs; | ||
| 666 | u8 fake_inject_layer[EDAC_MAX_LAYERS]; | ||
| 667 | u32 fake_inject_ue; | ||
| 668 | u16 fake_inject_count; | ||
| 669 | #endif | ||
| 612 | }; | 670 | }; |
| 613 | 671 | ||
| 614 | #endif | 672 | #endif |
diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h new file mode 100644 index 000000000000..260470e72483 --- /dev/null +++ b/include/ras/ras_event.h | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | #undef TRACE_SYSTEM | ||
| 2 | #define TRACE_SYSTEM ras | ||
| 3 | #define TRACE_INCLUDE_FILE ras_event | ||
| 4 | |||
| 5 | #if !defined(_TRACE_HW_EVENT_MC_H) || defined(TRACE_HEADER_MULTI_READ) | ||
| 6 | #define _TRACE_HW_EVENT_MC_H | ||
| 7 | |||
| 8 | #include <linux/tracepoint.h> | ||
| 9 | #include <linux/edac.h> | ||
| 10 | #include <linux/ktime.h> | ||
| 11 | |||
| 12 | /* | ||
| 13 | * Hardware Events Report | ||
| 14 | * | ||
| 15 | * Those events are generated when hardware detected a corrected or | ||
| 16 | * uncorrected event, and are meant to replace the current API to report | ||
| 17 | * errors defined on both EDAC and MCE subsystems. | ||
| 18 | * | ||
| 19 | * FIXME: Add events for handling memory errors originated from the | ||
| 20 | * MCE subsystem. | ||
| 21 | */ | ||
| 22 | |||
| 23 | /* | ||
| 24 | * Hardware-independent Memory Controller specific events | ||
| 25 | */ | ||
| 26 | |||
| 27 | /* | ||
| 28 | * Default error mechanisms for Memory Controller errors (CE and UE) | ||
| 29 | */ | ||
| 30 | TRACE_EVENT(mc_event, | ||
| 31 | |||
| 32 | TP_PROTO(const unsigned int err_type, | ||
| 33 | const char *error_msg, | ||
| 34 | const char *label, | ||
| 35 | const int error_count, | ||
| 36 | const u8 mc_index, | ||
| 37 | const s8 top_layer, | ||
| 38 | const s8 mid_layer, | ||
| 39 | const s8 low_layer, | ||
| 40 | unsigned long address, | ||
| 41 | const u8 grain_bits, | ||
| 42 | unsigned long syndrome, | ||
| 43 | const char *driver_detail), | ||
| 44 | |||
| 45 | TP_ARGS(err_type, error_msg, label, error_count, mc_index, | ||
| 46 | top_layer, mid_layer, low_layer, address, grain_bits, | ||
| 47 | syndrome, driver_detail), | ||
| 48 | |||
| 49 | TP_STRUCT__entry( | ||
| 50 | __field( unsigned int, error_type ) | ||
| 51 | __string( msg, error_msg ) | ||
| 52 | __string( label, label ) | ||
| 53 | __field( u16, error_count ) | ||
| 54 | __field( u8, mc_index ) | ||
| 55 | __field( s8, top_layer ) | ||
| 56 | __field( s8, middle_layer ) | ||
| 57 | __field( s8, lower_layer ) | ||
| 58 | __field( long, address ) | ||
| 59 | __field( u8, grain_bits ) | ||
| 60 | __field( long, syndrome ) | ||
| 61 | __string( driver_detail, driver_detail ) | ||
| 62 | ), | ||
| 63 | |||
| 64 | TP_fast_assign( | ||
| 65 | __entry->error_type = err_type; | ||
| 66 | __assign_str(msg, error_msg); | ||
| 67 | __assign_str(label, label); | ||
| 68 | __entry->error_count = error_count; | ||
| 69 | __entry->mc_index = mc_index; | ||
| 70 | __entry->top_layer = top_layer; | ||
| 71 | __entry->middle_layer = mid_layer; | ||
| 72 | __entry->lower_layer = low_layer; | ||
| 73 | __entry->address = address; | ||
| 74 | __entry->grain_bits = grain_bits; | ||
| 75 | __entry->syndrome = syndrome; | ||
| 76 | __assign_str(driver_detail, driver_detail); | ||
| 77 | ), | ||
| 78 | |||
| 79 | TP_printk("%d %s error%s:%s%s on %s (mc:%d location:%d:%d:%d address:0x%08lx grain:%d syndrome:0x%08lx%s%s)", | ||
| 80 | __entry->error_count, | ||
| 81 | (__entry->error_type == HW_EVENT_ERR_CORRECTED) ? "Corrected" : | ||
| 82 | ((__entry->error_type == HW_EVENT_ERR_FATAL) ? | ||
| 83 | "Fatal" : "Uncorrected"), | ||
| 84 | __entry->error_count > 1 ? "s" : "", | ||
| 85 | ((char *)__get_str(msg))[0] ? " " : "", | ||
| 86 | __get_str(msg), | ||
| 87 | __get_str(label), | ||
| 88 | __entry->mc_index, | ||
| 89 | __entry->top_layer, | ||
| 90 | __entry->middle_layer, | ||
| 91 | __entry->lower_layer, | ||
| 92 | __entry->address, | ||
| 93 | 1 << __entry->grain_bits, | ||
| 94 | __entry->syndrome, | ||
| 95 | ((char *)__get_str(driver_detail))[0] ? " " : "", | ||
| 96 | __get_str(driver_detail)) | ||
| 97 | ); | ||
| 98 | |||
| 99 | #endif /* _TRACE_HW_EVENT_MC_H */ | ||
| 100 | |||
| 101 | /* This part must be outside protection */ | ||
| 102 | #include <trace/define_trace.h> | ||
