From 53f2d02898755d1b24bde1975e202815d29fdb81 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Feb 2012 08:10:34 -0300 Subject: RAS: Add a tracepoint for reporting memory controller events Add a new tracepoint-based hardware events report method for reporting Memory Controller events. Part of the description bellow is shamelessly copied from Tony Luck's notes about the Hardware Error BoF during LPC 2010 [1]. Tony, thanks for your notes and discussions to generate the h/w error reporting requirements. [1] http://lwn.net/Articles/416669/ We have several subsystems & methods for reporting hardware errors: 1) EDAC ("Error Detection and Correction"). In its original form this consisted of a platform specific driver that read topology information and error counts from chipset registers and reported the results via a sysfs interface. 2) mcelog - x86 specific decoding of machine check bank registers reporting in binary form via /dev/mcelog. Recent additions make use of the APEI extensions that were documented in version 4.0a of the ACPI specification to acquire more information about errors without having to rely reading chipset registers directly. A user level programs decodes into somewhat human readable format. 3) drivers/edac/mce_amd.c - this driver hooks into the mcelog path and decodes errors reported via machine check bank registers in AMD processors to the console log using printk(); Each of these mechanisms has a band of followers ... and none of them appear to meet all the needs of all users. As part of a RAS subsystem, let's encapsulate the memory error hardware events into a trace facility. The tracepoint printk will be displayed like: mc_event: [quant] (Corrected|Uncorrected|Fatal) error:[error msg] on [label] ([location] [edac_mc detail] [driver_detail] Where: [quant] is the quantity of errors [error msg] is the driver-specific error message (e. g. "memory read", "bus error", ...); [location] is the location in terms of memory controller and branch/channel/slot, channel/slot or csrow/channel; [label] is the memory stick label; [edac_mc detail] describes the address location of the error and the syndrome; [driver detail] is driver-specifig error message details, when needed/provided (e. g. "area:DMA", ...) For example: mc_event: 1 Corrected error:memory read on memory stick DIMM_1A (mc:0 location:0:0:0 page:0x586b6e offset:0xa66 grain:32 syndrome:0x0 area:DMA) Of course, any userspace tools meant to handle errors should not parse the above data. They should, instead, use the binary fields provided by the tracepoint, mapping them directly into their Management Information Base. NOTE: The original patch was providing an additional mechanism for MCA-based trace events that also contained MCA error register data. However, as no agreement was reached so far for the MCA-based trace events, for now, let's add events only for memory errors. A latter patch is planned to change the tracepoint, for those types of event. Cc: Aristeu Rozanski Cc: Doug Thompson Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Ingo Molnar Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_core.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/edac/edac_core.h') diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index f06ce9ab692c..740c7e22c023 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -463,12 +463,12 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, const unsigned long page_frame_number, const unsigned long offset_in_page, const unsigned long syndrome, - const int layer0, - const int layer1, - const int layer2, + const int top_layer, + const int mid_layer, + const int low_layer, const char *msg, const char *other_detail, - const void *mcelog); + const void *arch_log); /* * edac_device APIs -- cgit From 7e881856eee8b889b76cd1d8e04ce2fc79b72099 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 28 Apr 2012 16:41:46 -0300 Subject: edac: Use more normal debugging macro style Convert macros to a simpler style and enforce appropriate format checking when not CONFIG_EDAC_DEBUG. Use fmt and __VA_ARGS__, neaten macros. Move some string arrays to the debugfx uses and remove the now unnecessary CONFIG_EDAC_DEBUG variable block definitions. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_core.h | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers/edac/edac_core.h') diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 740c7e22c023..410738bf30fd 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -71,29 +71,30 @@ extern const char *edac_mem_types[]; #ifdef CONFIG_EDAC_DEBUG extern int edac_debug_level; -#define edac_debug_printk(level, fmt, arg...) \ - do { \ - if (level <= edac_debug_level) \ - edac_printk(KERN_DEBUG, EDAC_DEBUG, \ - "%s: " fmt, __func__, ##arg); \ - } while (0) - -#define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ ) -#define debugf1( ... ) edac_debug_printk(1, __VA_ARGS__ ) -#define debugf2( ... ) edac_debug_printk(2, __VA_ARGS__ ) -#define debugf3( ... ) edac_debug_printk(3, __VA_ARGS__ ) -#define debugf4( ... ) edac_debug_printk(4, __VA_ARGS__ ) +#define edac_debug_printk(level, fmt, ...) \ +do { \ + if (level <= edac_debug_level) \ + edac_printk(KERN_DEBUG, EDAC_DEBUG, \ + "%s: " fmt, __func__, ##__VA_ARGS__); \ +} while (0) #else /* !CONFIG_EDAC_DEBUG */ -#define debugf0( ... ) -#define debugf1( ... ) -#define debugf2( ... ) -#define debugf3( ... ) -#define debugf4( ... ) +#define edac_debug_printk(level, fmt, ...) \ +do { \ + if (0) \ + edac_printk(KERN_DEBUG, EDAC_DEBUG, \ + "%s: " fmt, __func__, ##__VA_ARGS__); \ +} while (0) #endif /* !CONFIG_EDAC_DEBUG */ +#define debugf0(fmt, ...) edac_debug_printk(0, fmt, ##__VA_ARGS__) +#define debugf1(fmt, ...) edac_debug_printk(1, fmt, ##__VA_ARGS__) +#define debugf2(fmt, ...) edac_debug_printk(2, fmt, ##__VA_ARGS__) +#define debugf3(fmt, ...) edac_debug_printk(3, fmt, ##__VA_ARGS__) +#define debugf4(fmt, ...) edac_debug_printk(4, fmt, ##__VA_ARGS__) + #define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \ PCI_DEVICE_ID_ ## vend ## _ ## dev -- cgit From 956b9ba156dbfdb9cede2b2927ddf8be2233b3a7 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 29 Apr 2012 17:08:39 -0300 Subject: edac: Convert debugfX to edac_dbg(X, Use a more common debugging style. Remove __FILE__ uses, add missing newlines, coalesce formats and align arguments. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_core.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/edac/edac_core.h') diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 410738bf30fd..ee25f5483f9b 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -71,7 +71,7 @@ extern const char *edac_mem_types[]; #ifdef CONFIG_EDAC_DEBUG extern int edac_debug_level; -#define edac_debug_printk(level, fmt, ...) \ +#define edac_dbg(level, fmt, ...) \ do { \ if (level <= edac_debug_level) \ edac_printk(KERN_DEBUG, EDAC_DEBUG, \ @@ -80,7 +80,7 @@ do { \ #else /* !CONFIG_EDAC_DEBUG */ -#define edac_debug_printk(level, fmt, ...) \ +#define edac_dbg(level, fmt, ...) \ do { \ if (0) \ edac_printk(KERN_DEBUG, EDAC_DEBUG, \ @@ -89,12 +89,6 @@ do { \ #endif /* !CONFIG_EDAC_DEBUG */ -#define debugf0(fmt, ...) edac_debug_printk(0, fmt, ##__VA_ARGS__) -#define debugf1(fmt, ...) edac_debug_printk(1, fmt, ##__VA_ARGS__) -#define debugf2(fmt, ...) edac_debug_printk(2, fmt, ##__VA_ARGS__) -#define debugf3(fmt, ...) edac_debug_printk(3, fmt, ##__VA_ARGS__) -#define debugf4(fmt, ...) edac_debug_printk(4, fmt, ##__VA_ARGS__) - #define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \ PCI_DEVICE_ID_ ## vend ## _ ## dev -- cgit From 03f7eae80f4b913929be84e0c883ee98196fd6ff Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 4 Jun 2012 11:29:25 -0300 Subject: edac: remove arch-specific parameter for the error handler Remove the arch-dependent parameter, as it were not used, as the MCE tracepoint weren't implemented. It probably doesn't make sense to have an MCE-specific tracepoint, as this will cost more bytes at the tracepoint, and tracepoint is not free. The changes at the EDAC drivers were done by this small perl script: $file .=$_ while (<>); $file =~ s/(edac_mc_handle_error)\s*\(([^\;]+)\,([^\,\)]+)\s*\)/$1($2)/g; print $file; Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_core.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/edac/edac_core.h') diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index ee25f5483f9b..500ba6698986 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -462,8 +462,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, const int mid_layer, const int low_layer, const char *msg, - const char *other_detail, - const void *arch_log); + const char *other_detail); /* * edac_device APIs -- cgit From 9eb07a7fb8a90ee39fa9d5489afc0330cfcfbea7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 4 Jun 2012 13:27:43 -0300 Subject: edac: edac_mc_handle_error(): add an error_count parameter In order to avoid loosing error events, it is desirable to group error events together and generate a single trace for several identical errors. The trace API already allows reporting multiple errors. Change the handle_error function to also allow that. The changes at the drivers were made by this small script: $file .=$_ while (<>); $file =~ s/(edac_mc_handle_error)\s*\(([^\,]+)\,([^\,]+)\,/$1($2,$3, 1,/g; print $file; Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_core.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/edac/edac_core.h') diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 500ba6698986..3843222e5b9f 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -455,6 +455,7 @@ extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page); void edac_mc_handle_error(const enum hw_event_mc_err_type type, struct mem_ctl_info *mci, + const u16 error_count, const unsigned long page_frame_number, const unsigned long offset_in_page, const unsigned long syndrome, -- cgit