diff options
author | H. Peter Anvin <hpa@zytor.com> | 2014-07-14 12:26:47 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2014-07-14 12:27:25 -0400 |
commit | cbd4ebcba16c31abc341e1810e6e0fb4c35117b3 (patch) | |
tree | 49a3b54c709d11efbee631a85cca5fb550515005 | |
parent | 27c934158c5be0bebfb2970da521b9d9efc0058b (diff) | |
parent | 7c76bb5f7a3d052339b873374333dd0dcc35ce28 (diff) |
Merge tag 'please-pull-extlog-trace' into x86/ras
Report extended error information ("extlog") using
a trace/event. Provide a mechanism for a smart
daemon collecting this information to tell the kernel
to skip logging corrected errors to the console.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r-- | drivers/Kconfig | 2 | ||||
-rw-r--r-- | drivers/Makefile | 1 | ||||
-rw-r--r-- | drivers/acpi/Kconfig | 4 | ||||
-rw-r--r-- | drivers/acpi/acpi_extlog.c | 46 | ||||
-rw-r--r-- | drivers/edac/Kconfig | 1 | ||||
-rw-r--r-- | drivers/edac/edac_mc.c | 3 | ||||
-rw-r--r-- | drivers/firmware/efi/cper.c | 192 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/Kconfig | 1 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_errprint.c | 4 | ||||
-rw-r--r-- | drivers/ras/Kconfig | 2 | ||||
-rw-r--r-- | drivers/ras/Makefile | 1 | ||||
-rw-r--r-- | drivers/ras/debugfs.c | 56 | ||||
-rw-r--r-- | drivers/ras/ras.c | 29 | ||||
-rw-r--r-- | include/linux/cper.h | 32 | ||||
-rw-r--r-- | include/linux/ras.h | 14 | ||||
-rw-r--r-- | include/ras/ras_event.h | 128 | ||||
-rw-r--r-- | include/trace/events/ras.h | 77 | ||||
-rw-r--r-- | include/trace/ftrace.h | 33 | ||||
-rw-r--r-- | include/trace/syscall.h | 15 | ||||
-rw-r--r-- | kernel/fork.c | 2 | ||||
-rw-r--r-- | kernel/tracepoint.c | 26 | ||||
-rw-r--r-- | samples/trace_events/trace-events-sample.h | 3 |
22 files changed, 506 insertions, 166 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 0e87a34b6472..4e6e66c3c8d6 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig | |||
@@ -176,4 +176,6 @@ source "drivers/powercap/Kconfig" | |||
176 | 176 | ||
177 | source "drivers/mcb/Kconfig" | 177 | source "drivers/mcb/Kconfig" |
178 | 178 | ||
179 | source "drivers/ras/Kconfig" | ||
180 | |||
179 | endmenu | 181 | endmenu |
diff --git a/drivers/Makefile b/drivers/Makefile index f98b50d8251d..65c32b1cea3d 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
@@ -158,3 +158,4 @@ obj-$(CONFIG_NTB) += ntb/ | |||
158 | obj-$(CONFIG_FMC) += fmc/ | 158 | obj-$(CONFIG_FMC) += fmc/ |
159 | obj-$(CONFIG_POWERCAP) += powercap/ | 159 | obj-$(CONFIG_POWERCAP) += powercap/ |
160 | obj-$(CONFIG_MCB) += mcb/ | 160 | obj-$(CONFIG_MCB) += mcb/ |
161 | obj-$(CONFIG_RAS) += ras/ | ||
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index a34a22841002..206942b8d105 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
@@ -370,6 +370,7 @@ config ACPI_EXTLOG | |||
370 | tristate "Extended Error Log support" | 370 | tristate "Extended Error Log support" |
371 | depends on X86_MCE && X86_LOCAL_APIC | 371 | depends on X86_MCE && X86_LOCAL_APIC |
372 | select UEFI_CPER | 372 | select UEFI_CPER |
373 | select RAS | ||
373 | default n | 374 | default n |
374 | help | 375 | help |
375 | Certain usages such as Predictive Failure Analysis (PFA) require | 376 | Certain usages such as Predictive Failure Analysis (PFA) require |
@@ -384,6 +385,7 @@ config ACPI_EXTLOG | |||
384 | 385 | ||
385 | Enhanced MCA Logging allows firmware to provide additional error | 386 | Enhanced MCA Logging allows firmware to provide additional error |
386 | information to system software, synchronous with MCE or CMCI. This | 387 | information to system software, synchronous with MCE or CMCI. This |
387 | driver adds support for that functionality. | 388 | driver adds support for that functionality with corresponding |
389 | tracepoint which carries that information to userspace. | ||
388 | 390 | ||
389 | endif # ACPI | 391 | endif # ACPI |
diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index 185334114d71..0ad6f389d922 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c | |||
@@ -12,10 +12,12 @@ | |||
12 | #include <linux/cper.h> | 12 | #include <linux/cper.h> |
13 | #include <linux/ratelimit.h> | 13 | #include <linux/ratelimit.h> |
14 | #include <linux/edac.h> | 14 | #include <linux/edac.h> |
15 | #include <linux/ras.h> | ||
15 | #include <asm/cpu.h> | 16 | #include <asm/cpu.h> |
16 | #include <asm/mce.h> | 17 | #include <asm/mce.h> |
17 | 18 | ||
18 | #include "apei/apei-internal.h" | 19 | #include "apei/apei-internal.h" |
20 | #include <ras/ras_event.h> | ||
19 | 21 | ||
20 | #define EXT_ELOG_ENTRY_MASK GENMASK_ULL(51, 0) /* elog entry address mask */ | 22 | #define EXT_ELOG_ENTRY_MASK GENMASK_ULL(51, 0) /* elog entry address mask */ |
21 | 23 | ||
@@ -137,8 +139,12 @@ static int extlog_print(struct notifier_block *nb, unsigned long val, | |||
137 | struct mce *mce = (struct mce *)data; | 139 | struct mce *mce = (struct mce *)data; |
138 | int bank = mce->bank; | 140 | int bank = mce->bank; |
139 | int cpu = mce->extcpu; | 141 | int cpu = mce->extcpu; |
140 | struct acpi_generic_status *estatus; | 142 | struct acpi_generic_status *estatus, *tmp; |
141 | int rc; | 143 | struct acpi_generic_data *gdata; |
144 | const uuid_le *fru_id = &NULL_UUID_LE; | ||
145 | char *fru_text = ""; | ||
146 | uuid_le *sec_type; | ||
147 | static u32 err_seq; | ||
142 | 148 | ||
143 | estatus = extlog_elog_entry_check(cpu, bank); | 149 | estatus = extlog_elog_entry_check(cpu, bank); |
144 | if (estatus == NULL) | 150 | if (estatus == NULL) |
@@ -148,8 +154,29 @@ static int extlog_print(struct notifier_block *nb, unsigned long val, | |||
148 | /* clear record status to enable BIOS to update it again */ | 154 | /* clear record status to enable BIOS to update it again */ |
149 | estatus->block_status = 0; | 155 | estatus->block_status = 0; |
150 | 156 | ||
151 | rc = print_extlog_rcd(NULL, (struct acpi_generic_status *)elog_buf, cpu); | 157 | tmp = (struct acpi_generic_status *)elog_buf; |
158 | |||
159 | if (!ras_userspace_consumers()) { | ||
160 | print_extlog_rcd(NULL, tmp, cpu); | ||
161 | goto out; | ||
162 | } | ||
163 | |||
164 | /* log event via trace */ | ||
165 | err_seq++; | ||
166 | gdata = (struct acpi_generic_data *)(tmp + 1); | ||
167 | if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID) | ||
168 | fru_id = (uuid_le *)gdata->fru_id; | ||
169 | if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT) | ||
170 | fru_text = gdata->fru_text; | ||
171 | sec_type = (uuid_le *)gdata->section_type; | ||
172 | if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) { | ||
173 | struct cper_sec_mem_err *mem = (void *)(gdata + 1); | ||
174 | if (gdata->error_data_length >= sizeof(*mem)) | ||
175 | trace_extlog_mem_event(mem, err_seq, fru_id, fru_text, | ||
176 | (u8)gdata->error_severity); | ||
177 | } | ||
152 | 178 | ||
179 | out: | ||
153 | return NOTIFY_STOP; | 180 | return NOTIFY_STOP; |
154 | } | 181 | } |
155 | 182 | ||
@@ -196,19 +223,16 @@ static int __init extlog_init(void) | |||
196 | u64 cap; | 223 | u64 cap; |
197 | int rc; | 224 | int rc; |
198 | 225 | ||
226 | rdmsrl(MSR_IA32_MCG_CAP, cap); | ||
227 | |||
228 | if (!(cap & MCG_ELOG_P) || !extlog_get_l1addr()) | ||
229 | return -ENODEV; | ||
230 | |||
199 | if (get_edac_report_status() == EDAC_REPORTING_FORCE) { | 231 | if (get_edac_report_status() == EDAC_REPORTING_FORCE) { |
200 | pr_warn("Not loading eMCA, error reporting force-enabled through EDAC.\n"); | 232 | pr_warn("Not loading eMCA, error reporting force-enabled through EDAC.\n"); |
201 | return -EPERM; | 233 | return -EPERM; |
202 | } | 234 | } |
203 | 235 | ||
204 | rc = -ENODEV; | ||
205 | rdmsrl(MSR_IA32_MCG_CAP, cap); | ||
206 | if (!(cap & MCG_ELOG_P)) | ||
207 | return rc; | ||
208 | |||
209 | if (!extlog_get_l1addr()) | ||
210 | return rc; | ||
211 | |||
212 | rc = -EINVAL; | 236 | rc = -EINVAL; |
213 | /* get L1 header to fetch necessary information */ | 237 | /* get L1 header to fetch necessary information */ |
214 | l1_hdr_size = sizeof(struct extlog_l1_head); | 238 | l1_hdr_size = sizeof(struct extlog_l1_head); |
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 878f09005fad..d3c0465ba456 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig | |||
@@ -72,6 +72,7 @@ config EDAC_MCE_INJ | |||
72 | 72 | ||
73 | config EDAC_MM_EDAC | 73 | config EDAC_MM_EDAC |
74 | tristate "Main Memory EDAC (Error Detection And Correction) reporting" | 74 | tristate "Main Memory EDAC (Error Detection And Correction) reporting" |
75 | select RAS | ||
75 | help | 76 | help |
76 | Some systems are able to detect and correct errors in main | 77 | Some systems are able to detect and correct errors in main |
77 | memory. EDAC can report statistics on memory error | 78 | memory. EDAC can report statistics on memory error |
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 2c694b5297cc..9f134823fa75 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
@@ -33,9 +33,6 @@ | |||
33 | #include <asm/edac.h> | 33 | #include <asm/edac.h> |
34 | #include "edac_core.h" | 34 | #include "edac_core.h" |
35 | #include "edac_module.h" | 35 | #include "edac_module.h" |
36 | |||
37 | #define CREATE_TRACE_POINTS | ||
38 | #define TRACE_INCLUDE_PATH ../../include/ras | ||
39 | #include <ras/ras_event.h> | 36 | #include <ras/ras_event.h> |
40 | 37 | ||
41 | /* lock to memory controller's control array */ | 38 | /* lock to memory controller's control array */ |
diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index 1491dd4f08f9..437e6fd47311 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c | |||
@@ -34,6 +34,9 @@ | |||
34 | #include <linux/aer.h> | 34 | #include <linux/aer.h> |
35 | 35 | ||
36 | #define INDENT_SP " " | 36 | #define INDENT_SP " " |
37 | |||
38 | static char rcd_decode_str[CPER_REC_LEN]; | ||
39 | |||
37 | /* | 40 | /* |
38 | * CPER record ID need to be unique even after reboot, because record | 41 | * CPER record ID need to be unique even after reboot, because record |
39 | * ID is used as index for ERST storage, while CPER records from | 42 | * ID is used as index for ERST storage, while CPER records from |
@@ -50,18 +53,19 @@ u64 cper_next_record_id(void) | |||
50 | } | 53 | } |
51 | EXPORT_SYMBOL_GPL(cper_next_record_id); | 54 | EXPORT_SYMBOL_GPL(cper_next_record_id); |
52 | 55 | ||
53 | static const char *cper_severity_strs[] = { | 56 | static const char * const severity_strs[] = { |
54 | "recoverable", | 57 | "recoverable", |
55 | "fatal", | 58 | "fatal", |
56 | "corrected", | 59 | "corrected", |
57 | "info", | 60 | "info", |
58 | }; | 61 | }; |
59 | 62 | ||
60 | static const char *cper_severity_str(unsigned int severity) | 63 | const char *cper_severity_str(unsigned int severity) |
61 | { | 64 | { |
62 | return severity < ARRAY_SIZE(cper_severity_strs) ? | 65 | return severity < ARRAY_SIZE(severity_strs) ? |
63 | cper_severity_strs[severity] : "unknown"; | 66 | severity_strs[severity] : "unknown"; |
64 | } | 67 | } |
68 | EXPORT_SYMBOL_GPL(cper_severity_str); | ||
65 | 69 | ||
66 | /* | 70 | /* |
67 | * cper_print_bits - print strings for set bits | 71 | * cper_print_bits - print strings for set bits |
@@ -100,32 +104,32 @@ void cper_print_bits(const char *pfx, unsigned int bits, | |||
100 | printk("%s\n", buf); | 104 | printk("%s\n", buf); |
101 | } | 105 | } |
102 | 106 | ||
103 | static const char * const cper_proc_type_strs[] = { | 107 | static const char * const proc_type_strs[] = { |
104 | "IA32/X64", | 108 | "IA32/X64", |
105 | "IA64", | 109 | "IA64", |
106 | }; | 110 | }; |
107 | 111 | ||
108 | static const char * const cper_proc_isa_strs[] = { | 112 | static const char * const proc_isa_strs[] = { |
109 | "IA32", | 113 | "IA32", |
110 | "IA64", | 114 | "IA64", |
111 | "X64", | 115 | "X64", |
112 | }; | 116 | }; |
113 | 117 | ||
114 | static const char * const cper_proc_error_type_strs[] = { | 118 | static const char * const proc_error_type_strs[] = { |
115 | "cache error", | 119 | "cache error", |
116 | "TLB error", | 120 | "TLB error", |
117 | "bus error", | 121 | "bus error", |
118 | "micro-architectural error", | 122 | "micro-architectural error", |
119 | }; | 123 | }; |
120 | 124 | ||
121 | static const char * const cper_proc_op_strs[] = { | 125 | static const char * const proc_op_strs[] = { |
122 | "unknown or generic", | 126 | "unknown or generic", |
123 | "data read", | 127 | "data read", |
124 | "data write", | 128 | "data write", |
125 | "instruction execution", | 129 | "instruction execution", |
126 | }; | 130 | }; |
127 | 131 | ||
128 | static const char * const cper_proc_flag_strs[] = { | 132 | static const char * const proc_flag_strs[] = { |
129 | "restartable", | 133 | "restartable", |
130 | "precise IP", | 134 | "precise IP", |
131 | "overflow", | 135 | "overflow", |
@@ -137,26 +141,26 @@ static void cper_print_proc_generic(const char *pfx, | |||
137 | { | 141 | { |
138 | if (proc->validation_bits & CPER_PROC_VALID_TYPE) | 142 | if (proc->validation_bits & CPER_PROC_VALID_TYPE) |
139 | printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type, | 143 | printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type, |
140 | proc->proc_type < ARRAY_SIZE(cper_proc_type_strs) ? | 144 | proc->proc_type < ARRAY_SIZE(proc_type_strs) ? |
141 | cper_proc_type_strs[proc->proc_type] : "unknown"); | 145 | proc_type_strs[proc->proc_type] : "unknown"); |
142 | if (proc->validation_bits & CPER_PROC_VALID_ISA) | 146 | if (proc->validation_bits & CPER_PROC_VALID_ISA) |
143 | printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa, | 147 | printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa, |
144 | proc->proc_isa < ARRAY_SIZE(cper_proc_isa_strs) ? | 148 | proc->proc_isa < ARRAY_SIZE(proc_isa_strs) ? |
145 | cper_proc_isa_strs[proc->proc_isa] : "unknown"); | 149 | proc_isa_strs[proc->proc_isa] : "unknown"); |
146 | if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) { | 150 | if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) { |
147 | printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type); | 151 | printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type); |
148 | cper_print_bits(pfx, proc->proc_error_type, | 152 | cper_print_bits(pfx, proc->proc_error_type, |
149 | cper_proc_error_type_strs, | 153 | proc_error_type_strs, |
150 | ARRAY_SIZE(cper_proc_error_type_strs)); | 154 | ARRAY_SIZE(proc_error_type_strs)); |
151 | } | 155 | } |
152 | if (proc->validation_bits & CPER_PROC_VALID_OPERATION) | 156 | if (proc->validation_bits & CPER_PROC_VALID_OPERATION) |
153 | printk("%s""operation: %d, %s\n", pfx, proc->operation, | 157 | printk("%s""operation: %d, %s\n", pfx, proc->operation, |
154 | proc->operation < ARRAY_SIZE(cper_proc_op_strs) ? | 158 | proc->operation < ARRAY_SIZE(proc_op_strs) ? |
155 | cper_proc_op_strs[proc->operation] : "unknown"); | 159 | proc_op_strs[proc->operation] : "unknown"); |
156 | if (proc->validation_bits & CPER_PROC_VALID_FLAGS) { | 160 | if (proc->validation_bits & CPER_PROC_VALID_FLAGS) { |
157 | printk("%s""flags: 0x%02x\n", pfx, proc->flags); | 161 | printk("%s""flags: 0x%02x\n", pfx, proc->flags); |
158 | cper_print_bits(pfx, proc->flags, cper_proc_flag_strs, | 162 | cper_print_bits(pfx, proc->flags, proc_flag_strs, |
159 | ARRAY_SIZE(cper_proc_flag_strs)); | 163 | ARRAY_SIZE(proc_flag_strs)); |
160 | } | 164 | } |
161 | if (proc->validation_bits & CPER_PROC_VALID_LEVEL) | 165 | if (proc->validation_bits & CPER_PROC_VALID_LEVEL) |
162 | printk("%s""level: %d\n", pfx, proc->level); | 166 | printk("%s""level: %d\n", pfx, proc->level); |
@@ -177,7 +181,7 @@ static void cper_print_proc_generic(const char *pfx, | |||
177 | printk("%s""IP: 0x%016llx\n", pfx, proc->ip); | 181 | printk("%s""IP: 0x%016llx\n", pfx, proc->ip); |
178 | } | 182 | } |
179 | 183 | ||
180 | static const char *cper_mem_err_type_strs[] = { | 184 | static const char * const mem_err_type_strs[] = { |
181 | "unknown", | 185 | "unknown", |
182 | "no error", | 186 | "no error", |
183 | "single-bit ECC", | 187 | "single-bit ECC", |
@@ -196,58 +200,136 @@ static const char *cper_mem_err_type_strs[] = { | |||
196 | "physical memory map-out event", | 200 | "physical memory map-out event", |
197 | }; | 201 | }; |
198 | 202 | ||
199 | static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem) | 203 | const char *cper_mem_err_type_str(unsigned int etype) |
200 | { | 204 | { |
201 | if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS) | 205 | return etype < ARRAY_SIZE(mem_err_type_strs) ? |
202 | printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status); | 206 | mem_err_type_strs[etype] : "unknown"; |
203 | if (mem->validation_bits & CPER_MEM_VALID_PA) | 207 | } |
204 | printk("%s""physical_address: 0x%016llx\n", | 208 | EXPORT_SYMBOL_GPL(cper_mem_err_type_str); |
205 | pfx, mem->physical_addr); | 209 | |
206 | if (mem->validation_bits & CPER_MEM_VALID_PA_MASK) | 210 | static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg) |
207 | printk("%s""physical_address_mask: 0x%016llx\n", | 211 | { |
208 | pfx, mem->physical_addr_mask); | 212 | u32 len, n; |
213 | |||
214 | if (!msg) | ||
215 | return 0; | ||
216 | |||
217 | n = 0; | ||
218 | len = CPER_REC_LEN - 1; | ||
209 | if (mem->validation_bits & CPER_MEM_VALID_NODE) | 219 | if (mem->validation_bits & CPER_MEM_VALID_NODE) |
210 | pr_debug("node: %d\n", mem->node); | 220 | n += scnprintf(msg + n, len - n, "node: %d ", mem->node); |
211 | if (mem->validation_bits & CPER_MEM_VALID_CARD) | 221 | if (mem->validation_bits & CPER_MEM_VALID_CARD) |
212 | pr_debug("card: %d\n", mem->card); | 222 | n += scnprintf(msg + n, len - n, "card: %d ", mem->card); |
213 | if (mem->validation_bits & CPER_MEM_VALID_MODULE) | 223 | if (mem->validation_bits & CPER_MEM_VALID_MODULE) |
214 | pr_debug("module: %d\n", mem->module); | 224 | n += scnprintf(msg + n, len - n, "module: %d ", mem->module); |
215 | if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER) | 225 | if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER) |
216 | pr_debug("rank: %d\n", mem->rank); | 226 | n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank); |
217 | if (mem->validation_bits & CPER_MEM_VALID_BANK) | 227 | if (mem->validation_bits & CPER_MEM_VALID_BANK) |
218 | pr_debug("bank: %d\n", mem->bank); | 228 | n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank); |
219 | if (mem->validation_bits & CPER_MEM_VALID_DEVICE) | 229 | if (mem->validation_bits & CPER_MEM_VALID_DEVICE) |
220 | pr_debug("device: %d\n", mem->device); | 230 | n += scnprintf(msg + n, len - n, "device: %d ", mem->device); |
221 | if (mem->validation_bits & CPER_MEM_VALID_ROW) | 231 | if (mem->validation_bits & CPER_MEM_VALID_ROW) |
222 | pr_debug("row: %d\n", mem->row); | 232 | n += scnprintf(msg + n, len - n, "row: %d ", mem->row); |
223 | if (mem->validation_bits & CPER_MEM_VALID_COLUMN) | 233 | if (mem->validation_bits & CPER_MEM_VALID_COLUMN) |
224 | pr_debug("column: %d\n", mem->column); | 234 | n += scnprintf(msg + n, len - n, "column: %d ", mem->column); |
225 | if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION) | 235 | if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION) |
226 | pr_debug("bit_position: %d\n", mem->bit_pos); | 236 | n += scnprintf(msg + n, len - n, "bit_position: %d ", |
237 | mem->bit_pos); | ||
227 | if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID) | 238 | if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID) |
228 | pr_debug("requestor_id: 0x%016llx\n", mem->requestor_id); | 239 | n += scnprintf(msg + n, len - n, "requestor_id: 0x%016llx ", |
240 | mem->requestor_id); | ||
229 | if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID) | 241 | if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID) |
230 | pr_debug("responder_id: 0x%016llx\n", mem->responder_id); | 242 | n += scnprintf(msg + n, len - n, "responder_id: 0x%016llx ", |
243 | mem->responder_id); | ||
231 | if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID) | 244 | if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID) |
232 | pr_debug("target_id: 0x%016llx\n", mem->target_id); | 245 | scnprintf(msg + n, len - n, "target_id: 0x%016llx ", |
246 | mem->target_id); | ||
247 | |||
248 | msg[n] = '\0'; | ||
249 | return n; | ||
250 | } | ||
251 | |||
252 | static int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg) | ||
253 | { | ||
254 | u32 len, n; | ||
255 | const char *bank = NULL, *device = NULL; | ||
256 | |||
257 | if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE)) | ||
258 | return 0; | ||
259 | |||
260 | n = 0; | ||
261 | len = CPER_REC_LEN - 1; | ||
262 | dmi_memdev_name(mem->mem_dev_handle, &bank, &device); | ||
263 | if (bank && device) | ||
264 | n = snprintf(msg, len, "DIMM location: %s %s ", bank, device); | ||
265 | else | ||
266 | n = snprintf(msg, len, | ||
267 | "DIMM location: not present. DMI handle: 0x%.4x ", | ||
268 | mem->mem_dev_handle); | ||
269 | |||
270 | msg[n] = '\0'; | ||
271 | return n; | ||
272 | } | ||
273 | |||
274 | void cper_mem_err_pack(const struct cper_sec_mem_err *mem, | ||
275 | struct cper_mem_err_compact *cmem) | ||
276 | { | ||
277 | cmem->validation_bits = mem->validation_bits; | ||
278 | cmem->node = mem->node; | ||
279 | cmem->card = mem->card; | ||
280 | cmem->module = mem->module; | ||
281 | cmem->bank = mem->bank; | ||
282 | cmem->device = mem->device; | ||
283 | cmem->row = mem->row; | ||
284 | cmem->column = mem->column; | ||
285 | cmem->bit_pos = mem->bit_pos; | ||
286 | cmem->requestor_id = mem->requestor_id; | ||
287 | cmem->responder_id = mem->responder_id; | ||
288 | cmem->target_id = mem->target_id; | ||
289 | cmem->rank = mem->rank; | ||
290 | cmem->mem_array_handle = mem->mem_array_handle; | ||
291 | cmem->mem_dev_handle = mem->mem_dev_handle; | ||
292 | } | ||
293 | |||
294 | const char *cper_mem_err_unpack(struct trace_seq *p, | ||
295 | struct cper_mem_err_compact *cmem) | ||
296 | { | ||
297 | const char *ret = p->buffer + p->len; | ||
298 | |||
299 | if (cper_mem_err_location(cmem, rcd_decode_str)) | ||
300 | trace_seq_printf(p, "%s", rcd_decode_str); | ||
301 | if (cper_dimm_err_location(cmem, rcd_decode_str)) | ||
302 | trace_seq_printf(p, "%s", rcd_decode_str); | ||
303 | trace_seq_putc(p, '\0'); | ||
304 | |||
305 | return ret; | ||
306 | } | ||
307 | |||
308 | static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem) | ||
309 | { | ||
310 | struct cper_mem_err_compact cmem; | ||
311 | |||
312 | if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS) | ||
313 | printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status); | ||
314 | if (mem->validation_bits & CPER_MEM_VALID_PA) | ||
315 | printk("%s""physical_address: 0x%016llx\n", | ||
316 | pfx, mem->physical_addr); | ||
317 | if (mem->validation_bits & CPER_MEM_VALID_PA_MASK) | ||
318 | printk("%s""physical_address_mask: 0x%016llx\n", | ||
319 | pfx, mem->physical_addr_mask); | ||
320 | cper_mem_err_pack(mem, &cmem); | ||
321 | if (cper_mem_err_location(&cmem, rcd_decode_str)) | ||
322 | printk("%s%s\n", pfx, rcd_decode_str); | ||
233 | if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) { | 323 | if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) { |
234 | u8 etype = mem->error_type; | 324 | u8 etype = mem->error_type; |
235 | printk("%s""error_type: %d, %s\n", pfx, etype, | 325 | printk("%s""error_type: %d, %s\n", pfx, etype, |
236 | etype < ARRAY_SIZE(cper_mem_err_type_strs) ? | 326 | cper_mem_err_type_str(etype)); |
237 | cper_mem_err_type_strs[etype] : "unknown"); | ||
238 | } | ||
239 | if (mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE) { | ||
240 | const char *bank = NULL, *device = NULL; | ||
241 | dmi_memdev_name(mem->mem_dev_handle, &bank, &device); | ||
242 | if (bank != NULL && device != NULL) | ||
243 | printk("%s""DIMM location: %s %s", pfx, bank, device); | ||
244 | else | ||
245 | printk("%s""DIMM DMI handle: 0x%.4x", | ||
246 | pfx, mem->mem_dev_handle); | ||
247 | } | 327 | } |
328 | if (cper_dimm_err_location(&cmem, rcd_decode_str)) | ||
329 | printk("%s%s\n", pfx, rcd_decode_str); | ||
248 | } | 330 | } |
249 | 331 | ||
250 | static const char *cper_pcie_port_type_strs[] = { | 332 | static const char * const pcie_port_type_strs[] = { |
251 | "PCIe end point", | 333 | "PCIe end point", |
252 | "legacy PCI end point", | 334 | "legacy PCI end point", |
253 | "unknown", | 335 | "unknown", |
@@ -266,8 +348,8 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, | |||
266 | { | 348 | { |
267 | if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) | 349 | if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) |
268 | printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, | 350 | printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, |
269 | pcie->port_type < ARRAY_SIZE(cper_pcie_port_type_strs) ? | 351 | pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ? |
270 | cper_pcie_port_type_strs[pcie->port_type] : "unknown"); | 352 | pcie_port_type_strs[pcie->port_type] : "unknown"); |
271 | if (pcie->validation_bits & CPER_PCIE_VALID_VERSION) | 353 | if (pcie->validation_bits & CPER_PCIE_VALID_VERSION) |
272 | printk("%s""version: %d.%d\n", pfx, | 354 | printk("%s""version: %d.%d\n", pfx, |
273 | pcie->version.major, pcie->version.minor); | 355 | pcie->version.major, pcie->version.minor); |
diff --git a/drivers/pci/pcie/aer/Kconfig b/drivers/pci/pcie/aer/Kconfig index 50e94e02378a..389440228c1d 100644 --- a/drivers/pci/pcie/aer/Kconfig +++ b/drivers/pci/pcie/aer/Kconfig | |||
@@ -5,6 +5,7 @@ | |||
5 | config PCIEAER | 5 | config PCIEAER |
6 | boolean "Root Port Advanced Error Reporting support" | 6 | boolean "Root Port Advanced Error Reporting support" |
7 | depends on PCIEPORTBUS | 7 | depends on PCIEPORTBUS |
8 | select RAS | ||
8 | default y | 9 | default y |
9 | help | 10 | help |
10 | This enables PCI Express Root Port Advanced Error Reporting | 11 | This enables PCI Express Root Port Advanced Error Reporting |
diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c index 36ed31b52198..35d06e177917 100644 --- a/drivers/pci/pcie/aer/aerdrv_errprint.c +++ b/drivers/pci/pcie/aer/aerdrv_errprint.c | |||
@@ -22,9 +22,7 @@ | |||
22 | #include <linux/cper.h> | 22 | #include <linux/cper.h> |
23 | 23 | ||
24 | #include "aerdrv.h" | 24 | #include "aerdrv.h" |
25 | 25 | #include <ras/ras_event.h> | |
26 | #define CREATE_TRACE_POINTS | ||
27 | #include <trace/events/ras.h> | ||
28 | 26 | ||
29 | #define AER_AGENT_RECEIVER 0 | 27 | #define AER_AGENT_RECEIVER 0 |
30 | #define AER_AGENT_REQUESTER 1 | 28 | #define AER_AGENT_REQUESTER 1 |
diff --git a/drivers/ras/Kconfig b/drivers/ras/Kconfig new file mode 100644 index 000000000000..f9da613052c2 --- /dev/null +++ b/drivers/ras/Kconfig | |||
@@ -0,0 +1,2 @@ | |||
1 | config RAS | ||
2 | bool | ||
diff --git a/drivers/ras/Makefile b/drivers/ras/Makefile new file mode 100644 index 000000000000..d7f73341ced3 --- /dev/null +++ b/drivers/ras/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_RAS) += ras.o debugfs.o | |||
diff --git a/drivers/ras/debugfs.c b/drivers/ras/debugfs.c new file mode 100644 index 000000000000..0322acf67ea5 --- /dev/null +++ b/drivers/ras/debugfs.c | |||
@@ -0,0 +1,56 @@ | |||
1 | #include <linux/debugfs.h> | ||
2 | |||
3 | static struct dentry *ras_debugfs_dir; | ||
4 | |||
5 | static atomic_t trace_count = ATOMIC_INIT(0); | ||
6 | |||
7 | int ras_userspace_consumers(void) | ||
8 | { | ||
9 | return atomic_read(&trace_count); | ||
10 | } | ||
11 | EXPORT_SYMBOL_GPL(ras_userspace_consumers); | ||
12 | |||
13 | static int trace_show(struct seq_file *m, void *v) | ||
14 | { | ||
15 | return atomic_read(&trace_count); | ||
16 | } | ||
17 | |||
18 | static int trace_open(struct inode *inode, struct file *file) | ||
19 | { | ||
20 | atomic_inc(&trace_count); | ||
21 | return single_open(file, trace_show, NULL); | ||
22 | } | ||
23 | |||
24 | static int trace_release(struct inode *inode, struct file *file) | ||
25 | { | ||
26 | atomic_dec(&trace_count); | ||
27 | return single_release(inode, file); | ||
28 | } | ||
29 | |||
30 | static const struct file_operations trace_fops = { | ||
31 | .open = trace_open, | ||
32 | .read = seq_read, | ||
33 | .llseek = seq_lseek, | ||
34 | .release = trace_release, | ||
35 | }; | ||
36 | |||
37 | int __init ras_add_daemon_trace(void) | ||
38 | { | ||
39 | struct dentry *fentry; | ||
40 | |||
41 | if (!ras_debugfs_dir) | ||
42 | return -ENOENT; | ||
43 | |||
44 | fentry = debugfs_create_file("daemon_active", S_IRUSR, ras_debugfs_dir, | ||
45 | NULL, &trace_fops); | ||
46 | if (!fentry) | ||
47 | return -ENODEV; | ||
48 | |||
49 | return 0; | ||
50 | |||
51 | } | ||
52 | |||
53 | void __init ras_debugfs_init(void) | ||
54 | { | ||
55 | ras_debugfs_dir = debugfs_create_dir("ras", NULL); | ||
56 | } | ||
diff --git a/drivers/ras/ras.c b/drivers/ras/ras.c new file mode 100644 index 000000000000..b67dd362b7b6 --- /dev/null +++ b/drivers/ras/ras.c | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Intel Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Chen, Gong <gong.chen@linux.intel.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/init.h> | ||
9 | #include <linux/ras.h> | ||
10 | |||
11 | #define CREATE_TRACE_POINTS | ||
12 | #define TRACE_INCLUDE_PATH ../../include/ras | ||
13 | #include <ras/ras_event.h> | ||
14 | |||
15 | static int __init ras_init(void) | ||
16 | { | ||
17 | int rc = 0; | ||
18 | |||
19 | ras_debugfs_init(); | ||
20 | rc = ras_add_daemon_trace(); | ||
21 | |||
22 | return rc; | ||
23 | } | ||
24 | subsys_initcall(ras_init); | ||
25 | |||
26 | #if defined(CONFIG_ACPI_EXTLOG) || defined(CONFIG_ACPI_EXTLOG_MODULE) | ||
27 | EXPORT_TRACEPOINT_SYMBOL_GPL(extlog_mem_event); | ||
28 | #endif | ||
29 | EXPORT_TRACEPOINT_SYMBOL_GPL(mc_event); | ||
diff --git a/include/linux/cper.h b/include/linux/cper.h index 2fc0ec3d89cc..76abba4b238e 100644 --- a/include/linux/cper.h +++ b/include/linux/cper.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #define LINUX_CPER_H | 22 | #define LINUX_CPER_H |
23 | 23 | ||
24 | #include <linux/uuid.h> | 24 | #include <linux/uuid.h> |
25 | #include <linux/trace_seq.h> | ||
25 | 26 | ||
26 | /* CPER record signature and the size */ | 27 | /* CPER record signature and the size */ |
27 | #define CPER_SIG_RECORD "CPER" | 28 | #define CPER_SIG_RECORD "CPER" |
@@ -36,6 +37,13 @@ | |||
36 | #define CPER_RECORD_REV 0x0100 | 37 | #define CPER_RECORD_REV 0x0100 |
37 | 38 | ||
38 | /* | 39 | /* |
40 | * CPER record length contains the CPER fields which are relevant for further | ||
41 | * handling of a memory error in userspace (we don't carry all the fields | ||
42 | * defined in the UEFI spec because some of them don't make any sense.) | ||
43 | * Currently, a length of 256 should be more than enough. | ||
44 | */ | ||
45 | #define CPER_REC_LEN 256 | ||
46 | /* | ||
39 | * Severity difinition for error_severity in struct cper_record_header | 47 | * Severity difinition for error_severity in struct cper_record_header |
40 | * and section_severity in struct cper_section_descriptor | 48 | * and section_severity in struct cper_section_descriptor |
41 | */ | 49 | */ |
@@ -356,6 +364,24 @@ struct cper_sec_mem_err { | |||
356 | __u16 mem_dev_handle; /* module handle in UEFI 2.4 */ | 364 | __u16 mem_dev_handle; /* module handle in UEFI 2.4 */ |
357 | }; | 365 | }; |
358 | 366 | ||
367 | struct cper_mem_err_compact { | ||
368 | __u64 validation_bits; | ||
369 | __u16 node; | ||
370 | __u16 card; | ||
371 | __u16 module; | ||
372 | __u16 bank; | ||
373 | __u16 device; | ||
374 | __u16 row; | ||
375 | __u16 column; | ||
376 | __u16 bit_pos; | ||
377 | __u64 requestor_id; | ||
378 | __u64 responder_id; | ||
379 | __u64 target_id; | ||
380 | __u16 rank; | ||
381 | __u16 mem_array_handle; | ||
382 | __u16 mem_dev_handle; | ||
383 | }; | ||
384 | |||
359 | struct cper_sec_pcie { | 385 | struct cper_sec_pcie { |
360 | __u64 validation_bits; | 386 | __u64 validation_bits; |
361 | __u32 port_type; | 387 | __u32 port_type; |
@@ -395,7 +421,13 @@ struct cper_sec_pcie { | |||
395 | #pragma pack() | 421 | #pragma pack() |
396 | 422 | ||
397 | u64 cper_next_record_id(void); | 423 | u64 cper_next_record_id(void); |
424 | const char *cper_severity_str(unsigned int); | ||
425 | const char *cper_mem_err_type_str(unsigned int); | ||
398 | void cper_print_bits(const char *prefix, unsigned int bits, | 426 | void cper_print_bits(const char *prefix, unsigned int bits, |
399 | const char * const strs[], unsigned int strs_size); | 427 | const char * const strs[], unsigned int strs_size); |
428 | void cper_mem_err_pack(const struct cper_sec_mem_err *, | ||
429 | struct cper_mem_err_compact *); | ||
430 | const char *cper_mem_err_unpack(struct trace_seq *, | ||
431 | struct cper_mem_err_compact *); | ||
400 | 432 | ||
401 | #endif | 433 | #endif |
diff --git a/include/linux/ras.h b/include/linux/ras.h new file mode 100644 index 000000000000..2aceeafd6fe5 --- /dev/null +++ b/include/linux/ras.h | |||
@@ -0,0 +1,14 @@ | |||
1 | #ifndef __RAS_H__ | ||
2 | #define __RAS_H__ | ||
3 | |||
4 | #ifdef CONFIG_DEBUG_FS | ||
5 | int ras_userspace_consumers(void); | ||
6 | void ras_debugfs_init(void); | ||
7 | int ras_add_daemon_trace(void); | ||
8 | #else | ||
9 | static inline int ras_userspace_consumers(void) { return 0; } | ||
10 | static inline void ras_debugfs_init(void) { return; } | ||
11 | static inline int ras_add_daemon_trace(void) { return 0; } | ||
12 | #endif | ||
13 | |||
14 | #endif | ||
diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h index 21cdb0b7b0fb..47da53c27ffa 100644 --- a/include/ras/ras_event.h +++ b/include/ras/ras_event.h | |||
@@ -8,6 +8,71 @@ | |||
8 | #include <linux/tracepoint.h> | 8 | #include <linux/tracepoint.h> |
9 | #include <linux/edac.h> | 9 | #include <linux/edac.h> |
10 | #include <linux/ktime.h> | 10 | #include <linux/ktime.h> |
11 | #include <linux/aer.h> | ||
12 | #include <linux/cper.h> | ||
13 | |||
14 | /* | ||
15 | * MCE Extended Error Log trace event | ||
16 | * | ||
17 | * These events are generated when hardware detects a corrected or | ||
18 | * uncorrected event. | ||
19 | */ | ||
20 | |||
21 | /* memory trace event */ | ||
22 | |||
23 | #if defined(CONFIG_ACPI_EXTLOG) || defined(CONFIG_ACPI_EXTLOG_MODULE) | ||
24 | TRACE_EVENT(extlog_mem_event, | ||
25 | TP_PROTO(struct cper_sec_mem_err *mem, | ||
26 | u32 err_seq, | ||
27 | const uuid_le *fru_id, | ||
28 | const char *fru_text, | ||
29 | u8 sev), | ||
30 | |||
31 | TP_ARGS(mem, err_seq, fru_id, fru_text, sev), | ||
32 | |||
33 | TP_STRUCT__entry( | ||
34 | __field(u32, err_seq) | ||
35 | __field(u8, etype) | ||
36 | __field(u8, sev) | ||
37 | __field(u64, pa) | ||
38 | __field(u8, pa_mask_lsb) | ||
39 | __field_struct(uuid_le, fru_id) | ||
40 | __string(fru_text, fru_text) | ||
41 | __field_struct(struct cper_mem_err_compact, data) | ||
42 | ), | ||
43 | |||
44 | TP_fast_assign( | ||
45 | __entry->err_seq = err_seq; | ||
46 | if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) | ||
47 | __entry->etype = mem->error_type; | ||
48 | else | ||
49 | __entry->etype = ~0; | ||
50 | __entry->sev = sev; | ||
51 | if (mem->validation_bits & CPER_MEM_VALID_PA) | ||
52 | __entry->pa = mem->physical_addr; | ||
53 | else | ||
54 | __entry->pa = ~0ull; | ||
55 | |||
56 | if (mem->validation_bits & CPER_MEM_VALID_PA_MASK) | ||
57 | __entry->pa_mask_lsb = (u8)__ffs64(mem->physical_addr_mask); | ||
58 | else | ||
59 | __entry->pa_mask_lsb = ~0; | ||
60 | __entry->fru_id = *fru_id; | ||
61 | __assign_str(fru_text, fru_text); | ||
62 | cper_mem_err_pack(mem, &__entry->data); | ||
63 | ), | ||
64 | |||
65 | TP_printk("{%d} %s error: %s physical addr: %016llx (mask lsb: %x) %sFRU: %pUl %.20s", | ||
66 | __entry->err_seq, | ||
67 | cper_severity_str(__entry->sev), | ||
68 | cper_mem_err_type_str(__entry->etype), | ||
69 | __entry->pa, | ||
70 | __entry->pa_mask_lsb, | ||
71 | cper_mem_err_unpack(p, &__entry->data), | ||
72 | &__entry->fru_id, | ||
73 | __get_str(fru_text)) | ||
74 | ); | ||
75 | #endif | ||
11 | 76 | ||
12 | /* | 77 | /* |
13 | * Hardware Events Report | 78 | * Hardware Events Report |
@@ -94,6 +159,69 @@ TRACE_EVENT(mc_event, | |||
94 | __get_str(driver_detail)) | 159 | __get_str(driver_detail)) |
95 | ); | 160 | ); |
96 | 161 | ||
162 | /* | ||
163 | * PCIe AER Trace event | ||
164 | * | ||
165 | * These events are generated when hardware detects a corrected or | ||
166 | * uncorrected event on a PCIe device. The event report has | ||
167 | * the following structure: | ||
168 | * | ||
169 | * char * dev_name - The name of the slot where the device resides | ||
170 | * ([domain:]bus:device.function). | ||
171 | * u32 status - Either the correctable or uncorrectable register | ||
172 | * indicating what error or errors have been seen | ||
173 | * u8 severity - error severity 0:NONFATAL 1:FATAL 2:CORRECTED | ||
174 | */ | ||
175 | |||
176 | #define aer_correctable_errors \ | ||
177 | {BIT(0), "Receiver Error"}, \ | ||
178 | {BIT(6), "Bad TLP"}, \ | ||
179 | {BIT(7), "Bad DLLP"}, \ | ||
180 | {BIT(8), "RELAY_NUM Rollover"}, \ | ||
181 | {BIT(12), "Replay Timer Timeout"}, \ | ||
182 | {BIT(13), "Advisory Non-Fatal"} | ||
183 | |||
184 | #define aer_uncorrectable_errors \ | ||
185 | {BIT(4), "Data Link Protocol"}, \ | ||
186 | {BIT(12), "Poisoned TLP"}, \ | ||
187 | {BIT(13), "Flow Control Protocol"}, \ | ||
188 | {BIT(14), "Completion Timeout"}, \ | ||
189 | {BIT(15), "Completer Abort"}, \ | ||
190 | {BIT(16), "Unexpected Completion"}, \ | ||
191 | {BIT(17), "Receiver Overflow"}, \ | ||
192 | {BIT(18), "Malformed TLP"}, \ | ||
193 | {BIT(19), "ECRC"}, \ | ||
194 | {BIT(20), "Unsupported Request"} | ||
195 | |||
196 | TRACE_EVENT(aer_event, | ||
197 | TP_PROTO(const char *dev_name, | ||
198 | const u32 status, | ||
199 | const u8 severity), | ||
200 | |||
201 | TP_ARGS(dev_name, status, severity), | ||
202 | |||
203 | TP_STRUCT__entry( | ||
204 | __string( dev_name, dev_name ) | ||
205 | __field( u32, status ) | ||
206 | __field( u8, severity ) | ||
207 | ), | ||
208 | |||
209 | TP_fast_assign( | ||
210 | __assign_str(dev_name, dev_name); | ||
211 | __entry->status = status; | ||
212 | __entry->severity = severity; | ||
213 | ), | ||
214 | |||
215 | TP_printk("%s PCIe Bus Error: severity=%s, %s\n", | ||
216 | __get_str(dev_name), | ||
217 | __entry->severity == AER_CORRECTABLE ? "Corrected" : | ||
218 | __entry->severity == AER_FATAL ? | ||
219 | "Fatal" : "Uncorrected, non-fatal", | ||
220 | __entry->severity == AER_CORRECTABLE ? | ||
221 | __print_flags(__entry->status, "|", aer_correctable_errors) : | ||
222 | __print_flags(__entry->status, "|", aer_uncorrectable_errors)) | ||
223 | ); | ||
224 | |||
97 | #endif /* _TRACE_HW_EVENT_MC_H */ | 225 | #endif /* _TRACE_HW_EVENT_MC_H */ |
98 | 226 | ||
99 | /* This part must be outside protection */ | 227 | /* This part must be outside protection */ |
diff --git a/include/trace/events/ras.h b/include/trace/events/ras.h deleted file mode 100644 index 1c875ad1ee5f..000000000000 --- a/include/trace/events/ras.h +++ /dev/null | |||
@@ -1,77 +0,0 @@ | |||
1 | #undef TRACE_SYSTEM | ||
2 | #define TRACE_SYSTEM ras | ||
3 | |||
4 | #if !defined(_TRACE_AER_H) || defined(TRACE_HEADER_MULTI_READ) | ||
5 | #define _TRACE_AER_H | ||
6 | |||
7 | #include <linux/tracepoint.h> | ||
8 | #include <linux/aer.h> | ||
9 | |||
10 | |||
11 | /* | ||
12 | * PCIe AER Trace event | ||
13 | * | ||
14 | * These events are generated when hardware detects a corrected or | ||
15 | * uncorrected event on a PCIe device. The event report has | ||
16 | * the following structure: | ||
17 | * | ||
18 | * char * dev_name - The name of the slot where the device resides | ||
19 | * ([domain:]bus:device.function). | ||
20 | * u32 status - Either the correctable or uncorrectable register | ||
21 | * indicating what error or errors have been seen | ||
22 | * u8 severity - error severity 0:NONFATAL 1:FATAL 2:CORRECTED | ||
23 | */ | ||
24 | |||
25 | #define aer_correctable_errors \ | ||
26 | {BIT(0), "Receiver Error"}, \ | ||
27 | {BIT(6), "Bad TLP"}, \ | ||
28 | {BIT(7), "Bad DLLP"}, \ | ||
29 | {BIT(8), "RELAY_NUM Rollover"}, \ | ||
30 | {BIT(12), "Replay Timer Timeout"}, \ | ||
31 | {BIT(13), "Advisory Non-Fatal"} | ||
32 | |||
33 | #define aer_uncorrectable_errors \ | ||
34 | {BIT(4), "Data Link Protocol"}, \ | ||
35 | {BIT(12), "Poisoned TLP"}, \ | ||
36 | {BIT(13), "Flow Control Protocol"}, \ | ||
37 | {BIT(14), "Completion Timeout"}, \ | ||
38 | {BIT(15), "Completer Abort"}, \ | ||
39 | {BIT(16), "Unexpected Completion"}, \ | ||
40 | {BIT(17), "Receiver Overflow"}, \ | ||
41 | {BIT(18), "Malformed TLP"}, \ | ||
42 | {BIT(19), "ECRC"}, \ | ||
43 | {BIT(20), "Unsupported Request"} | ||
44 | |||
45 | TRACE_EVENT(aer_event, | ||
46 | TP_PROTO(const char *dev_name, | ||
47 | const u32 status, | ||
48 | const u8 severity), | ||
49 | |||
50 | TP_ARGS(dev_name, status, severity), | ||
51 | |||
52 | TP_STRUCT__entry( | ||
53 | __string( dev_name, dev_name ) | ||
54 | __field( u32, status ) | ||
55 | __field( u8, severity ) | ||
56 | ), | ||
57 | |||
58 | TP_fast_assign( | ||
59 | __assign_str(dev_name, dev_name); | ||
60 | __entry->status = status; | ||
61 | __entry->severity = severity; | ||
62 | ), | ||
63 | |||
64 | TP_printk("%s PCIe Bus Error: severity=%s, %s\n", | ||
65 | __get_str(dev_name), | ||
66 | __entry->severity == AER_CORRECTABLE ? "Corrected" : | ||
67 | __entry->severity == AER_FATAL ? | ||
68 | "Fatal" : "Uncorrected, non-fatal", | ||
69 | __entry->severity == AER_CORRECTABLE ? | ||
70 | __print_flags(__entry->status, "|", aer_correctable_errors) : | ||
71 | __print_flags(__entry->status, "|", aer_uncorrectable_errors)) | ||
72 | ); | ||
73 | |||
74 | #endif /* _TRACE_AER_H */ | ||
75 | |||
76 | /* This part must be outside protection */ | ||
77 | #include <trace/define_trace.h> | ||
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 0fd06fef9fac..26b4f2e13275 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
@@ -44,6 +44,12 @@ | |||
44 | #undef __field_ext | 44 | #undef __field_ext |
45 | #define __field_ext(type, item, filter_type) type item; | 45 | #define __field_ext(type, item, filter_type) type item; |
46 | 46 | ||
47 | #undef __field_struct | ||
48 | #define __field_struct(type, item) type item; | ||
49 | |||
50 | #undef __field_struct_ext | ||
51 | #define __field_struct_ext(type, item, filter_type) type item; | ||
52 | |||
47 | #undef __array | 53 | #undef __array |
48 | #define __array(type, item, len) type item[len]; | 54 | #define __array(type, item, len) type item[len]; |
49 | 55 | ||
@@ -122,6 +128,12 @@ | |||
122 | #undef __field_ext | 128 | #undef __field_ext |
123 | #define __field_ext(type, item, filter_type) | 129 | #define __field_ext(type, item, filter_type) |
124 | 130 | ||
131 | #undef __field_struct | ||
132 | #define __field_struct(type, item) | ||
133 | |||
134 | #undef __field_struct_ext | ||
135 | #define __field_struct_ext(type, item, filter_type) | ||
136 | |||
125 | #undef __array | 137 | #undef __array |
126 | #define __array(type, item, len) | 138 | #define __array(type, item, len) |
127 | 139 | ||
@@ -315,9 +327,21 @@ static struct trace_event_functions ftrace_event_type_funcs_##call = { \ | |||
315 | if (ret) \ | 327 | if (ret) \ |
316 | return ret; | 328 | return ret; |
317 | 329 | ||
330 | #undef __field_struct_ext | ||
331 | #define __field_struct_ext(type, item, filter_type) \ | ||
332 | ret = trace_define_field(event_call, #type, #item, \ | ||
333 | offsetof(typeof(field), item), \ | ||
334 | sizeof(field.item), \ | ||
335 | 0, filter_type); \ | ||
336 | if (ret) \ | ||
337 | return ret; | ||
338 | |||
318 | #undef __field | 339 | #undef __field |
319 | #define __field(type, item) __field_ext(type, item, FILTER_OTHER) | 340 | #define __field(type, item) __field_ext(type, item, FILTER_OTHER) |
320 | 341 | ||
342 | #undef __field_struct | ||
343 | #define __field_struct(type, item) __field_struct_ext(type, item, FILTER_OTHER) | ||
344 | |||
321 | #undef __array | 345 | #undef __array |
322 | #define __array(type, item, len) \ | 346 | #define __array(type, item, len) \ |
323 | do { \ | 347 | do { \ |
@@ -379,6 +403,12 @@ ftrace_define_fields_##call(struct ftrace_event_call *event_call) \ | |||
379 | #undef __field_ext | 403 | #undef __field_ext |
380 | #define __field_ext(type, item, filter_type) | 404 | #define __field_ext(type, item, filter_type) |
381 | 405 | ||
406 | #undef __field_struct | ||
407 | #define __field_struct(type, item) | ||
408 | |||
409 | #undef __field_struct_ext | ||
410 | #define __field_struct_ext(type, item, filter_type) | ||
411 | |||
382 | #undef __array | 412 | #undef __array |
383 | #define __array(type, item, len) | 413 | #define __array(type, item, len) |
384 | 414 | ||
@@ -550,6 +580,9 @@ static inline notrace int ftrace_get_offsets_##call( \ | |||
550 | #undef __field | 580 | #undef __field |
551 | #define __field(type, item) | 581 | #define __field(type, item) |
552 | 582 | ||
583 | #undef __field_struct | ||
584 | #define __field_struct(type, item) | ||
585 | |||
553 | #undef __array | 586 | #undef __array |
554 | #define __array(type, item, len) | 587 | #define __array(type, item, len) |
555 | 588 | ||
diff --git a/include/trace/syscall.h b/include/trace/syscall.h index fed853f3d7aa..9674145e2f6a 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/tracepoint.h> | 4 | #include <linux/tracepoint.h> |
5 | #include <linux/unistd.h> | 5 | #include <linux/unistd.h> |
6 | #include <linux/ftrace_event.h> | 6 | #include <linux/ftrace_event.h> |
7 | #include <linux/thread_info.h> | ||
7 | 8 | ||
8 | #include <asm/ptrace.h> | 9 | #include <asm/ptrace.h> |
9 | 10 | ||
@@ -32,4 +33,18 @@ struct syscall_metadata { | |||
32 | struct ftrace_event_call *exit_event; | 33 | struct ftrace_event_call *exit_event; |
33 | }; | 34 | }; |
34 | 35 | ||
36 | #if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_HAVE_SYSCALL_TRACEPOINTS) | ||
37 | static inline void syscall_tracepoint_update(struct task_struct *p) | ||
38 | { | ||
39 | if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) | ||
40 | set_tsk_thread_flag(p, TIF_SYSCALL_TRACEPOINT); | ||
41 | else | ||
42 | clear_tsk_thread_flag(p, TIF_SYSCALL_TRACEPOINT); | ||
43 | } | ||
44 | #else | ||
45 | static inline void syscall_tracepoint_update(struct task_struct *p) | ||
46 | { | ||
47 | } | ||
48 | #endif | ||
49 | |||
35 | #endif /* _TRACE_SYSCALL_H */ | 50 | #endif /* _TRACE_SYSCALL_H */ |
diff --git a/kernel/fork.c b/kernel/fork.c index d2799d1fc952..6a13c46cd87d 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1487,7 +1487,9 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1487 | 1487 | ||
1488 | total_forks++; | 1488 | total_forks++; |
1489 | spin_unlock(¤t->sighand->siglock); | 1489 | spin_unlock(¤t->sighand->siglock); |
1490 | syscall_tracepoint_update(p); | ||
1490 | write_unlock_irq(&tasklist_lock); | 1491 | write_unlock_irq(&tasklist_lock); |
1492 | |||
1491 | proc_fork_connector(p); | 1493 | proc_fork_connector(p); |
1492 | cgroup_post_fork(p); | 1494 | cgroup_post_fork(p); |
1493 | if (clone_flags & CLONE_THREAD) | 1495 | if (clone_flags & CLONE_THREAD) |
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index 33cbd8c203f8..3490407dc7b7 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c | |||
@@ -492,33 +492,29 @@ static int sys_tracepoint_refcount; | |||
492 | 492 | ||
493 | void syscall_regfunc(void) | 493 | void syscall_regfunc(void) |
494 | { | 494 | { |
495 | unsigned long flags; | 495 | struct task_struct *p, *t; |
496 | struct task_struct *g, *t; | ||
497 | 496 | ||
498 | if (!sys_tracepoint_refcount) { | 497 | if (!sys_tracepoint_refcount) { |
499 | read_lock_irqsave(&tasklist_lock, flags); | 498 | read_lock(&tasklist_lock); |
500 | do_each_thread(g, t) { | 499 | for_each_process_thread(p, t) { |
501 | /* Skip kernel threads. */ | 500 | set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); |
502 | if (t->mm) | 501 | } |
503 | set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); | 502 | read_unlock(&tasklist_lock); |
504 | } while_each_thread(g, t); | ||
505 | read_unlock_irqrestore(&tasklist_lock, flags); | ||
506 | } | 503 | } |
507 | sys_tracepoint_refcount++; | 504 | sys_tracepoint_refcount++; |
508 | } | 505 | } |
509 | 506 | ||
510 | void syscall_unregfunc(void) | 507 | void syscall_unregfunc(void) |
511 | { | 508 | { |
512 | unsigned long flags; | 509 | struct task_struct *p, *t; |
513 | struct task_struct *g, *t; | ||
514 | 510 | ||
515 | sys_tracepoint_refcount--; | 511 | sys_tracepoint_refcount--; |
516 | if (!sys_tracepoint_refcount) { | 512 | if (!sys_tracepoint_refcount) { |
517 | read_lock_irqsave(&tasklist_lock, flags); | 513 | read_lock(&tasklist_lock); |
518 | do_each_thread(g, t) { | 514 | for_each_process_thread(p, t) { |
519 | clear_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); | 515 | clear_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); |
520 | } while_each_thread(g, t); | 516 | } |
521 | read_unlock_irqrestore(&tasklist_lock, flags); | 517 | read_unlock(&tasklist_lock); |
522 | } | 518 | } |
523 | } | 519 | } |
524 | #endif | 520 | #endif |
diff --git a/samples/trace_events/trace-events-sample.h b/samples/trace_events/trace-events-sample.h index 6af373236d73..4b0113f73ee9 100644 --- a/samples/trace_events/trace-events-sample.h +++ b/samples/trace_events/trace-events-sample.h | |||
@@ -56,7 +56,8 @@ | |||
56 | * struct: This defines the way the data will be stored in the ring buffer. | 56 | * struct: This defines the way the data will be stored in the ring buffer. |
57 | * There are currently two types of elements. __field and __array. | 57 | * There are currently two types of elements. __field and __array. |
58 | * a __field is broken up into (type, name). Where type can be any | 58 | * a __field is broken up into (type, name). Where type can be any |
59 | * type but an array. | 59 | * primitive type (integer, long or pointer). __field_struct() can |
60 | * be any static complex data value (struct, union, but not an array). | ||
60 | * For an array. there are three fields. (type, name, size). The | 61 | * For an array. there are three fields. (type, name, size). The |
61 | * type of elements in the array, the name of the field and the size | 62 | * type of elements in the array, the name of the field and the size |
62 | * of the array. | 63 | * of the array. |