Commit | Line | Data |
---|---|---|
6c2b374d ZY |
1 | /* |
2 | * drivers/pci/pcie/aer/aerdrv_errprint.c | |
3 | * | |
4 | * This file is subject to the terms and conditions of the GNU General Public | |
5 | * License. See the file "COPYING" in the main directory of this archive | |
6 | * for more details. | |
7 | * | |
8 | * Format error messages and print them to console. | |
9 | * | |
10 | * Copyright (C) 2006 Intel Corp. | |
11 | * Tom Long Nguyen (tom.l.nguyen@intel.com) | |
12 | * Zhang Yanmin (yanmin.zhang@intel.com) | |
13 | * | |
14 | */ | |
15 | ||
16 | #include <linux/module.h> | |
17 | #include <linux/pci.h> | |
18 | #include <linux/kernel.h> | |
19 | #include <linux/errno.h> | |
20 | #include <linux/pm.h> | |
21 | #include <linux/suspend.h> | |
c413d768 | 22 | #include <linux/cper.h> |
6c2b374d ZY |
23 | |
24 | #include "aerdrv.h" | |
25 | ||
26 | #define AER_AGENT_RECEIVER 0 | |
27 | #define AER_AGENT_REQUESTER 1 | |
28 | #define AER_AGENT_COMPLETER 2 | |
29 | #define AER_AGENT_TRANSMITTER 3 | |
30 | ||
f1585756 HS |
31 | #define AER_AGENT_REQUESTER_MASK(t) ((t == AER_CORRECTABLE) ? \ |
32 | 0 : (PCI_ERR_UNC_COMP_TIME|PCI_ERR_UNC_UNSUP)) | |
33 | #define AER_AGENT_COMPLETER_MASK(t) ((t == AER_CORRECTABLE) ? \ | |
34 | 0 : PCI_ERR_UNC_COMP_ABORT) | |
35 | #define AER_AGENT_TRANSMITTER_MASK(t) ((t == AER_CORRECTABLE) ? \ | |
36 | (PCI_ERR_COR_REP_ROLL|PCI_ERR_COR_REP_TIMER) : 0) | |
6c2b374d ZY |
37 | |
38 | #define AER_GET_AGENT(t, e) \ | |
f1585756 HS |
39 | ((e & AER_AGENT_COMPLETER_MASK(t)) ? AER_AGENT_COMPLETER : \ |
40 | (e & AER_AGENT_REQUESTER_MASK(t)) ? AER_AGENT_REQUESTER : \ | |
41 | (e & AER_AGENT_TRANSMITTER_MASK(t)) ? AER_AGENT_TRANSMITTER : \ | |
6c2b374d ZY |
42 | AER_AGENT_RECEIVER) |
43 | ||
6c2b374d ZY |
44 | #define AER_PHYSICAL_LAYER_ERROR 0 |
45 | #define AER_DATA_LINK_LAYER_ERROR 1 | |
46 | #define AER_TRANSACTION_LAYER_ERROR 2 | |
47 | ||
f1585756 HS |
48 | #define AER_PHYSICAL_LAYER_ERROR_MASK(t) ((t == AER_CORRECTABLE) ? \ |
49 | PCI_ERR_COR_RCVR : 0) | |
50 | #define AER_DATA_LINK_LAYER_ERROR_MASK(t) ((t == AER_CORRECTABLE) ? \ | |
51 | (PCI_ERR_COR_BAD_TLP| \ | |
52 | PCI_ERR_COR_BAD_DLLP| \ | |
53 | PCI_ERR_COR_REP_ROLL| \ | |
54 | PCI_ERR_COR_REP_TIMER) : PCI_ERR_UNC_DLP) | |
55 | ||
56 | #define AER_GET_LAYER_ERROR(t, e) \ | |
57 | ((e & AER_PHYSICAL_LAYER_ERROR_MASK(t)) ? AER_PHYSICAL_LAYER_ERROR : \ | |
58 | (e & AER_DATA_LINK_LAYER_ERROR_MASK(t)) ? AER_DATA_LINK_LAYER_ERROR : \ | |
59 | AER_TRANSACTION_LAYER_ERROR) | |
6c2b374d ZY |
60 | |
61 | /* | |
62 | * AER error strings | |
63 | */ | |
b64a4414 | 64 | static const char *aer_error_severity_string[] = { |
6c2b374d ZY |
65 | "Uncorrected (Non-Fatal)", |
66 | "Uncorrected (Fatal)", | |
67 | "Corrected" | |
68 | }; | |
69 | ||
b64a4414 | 70 | static const char *aer_error_layer[] = { |
6c2b374d ZY |
71 | "Physical Layer", |
72 | "Data Link Layer", | |
73 | "Transaction Layer" | |
74 | }; | |
b64a4414 HY |
75 | |
76 | static const char *aer_correctable_error_string[] = { | |
77 | "Receiver Error", /* Bit Position 0 */ | |
6c2b374d ZY |
78 | NULL, |
79 | NULL, | |
80 | NULL, | |
81 | NULL, | |
82 | NULL, | |
b64a4414 HY |
83 | "Bad TLP", /* Bit Position 6 */ |
84 | "Bad DLLP", /* Bit Position 7 */ | |
85 | "RELAY_NUM Rollover", /* Bit Position 8 */ | |
6c2b374d ZY |
86 | NULL, |
87 | NULL, | |
88 | NULL, | |
b64a4414 HY |
89 | "Replay Timer Timeout", /* Bit Position 12 */ |
90 | "Advisory Non-Fatal", /* Bit Position 13 */ | |
6c2b374d ZY |
91 | }; |
92 | ||
b64a4414 | 93 | static const char *aer_uncorrectable_error_string[] = { |
6c2b374d ZY |
94 | NULL, |
95 | NULL, | |
96 | NULL, | |
97 | NULL, | |
b64a4414 | 98 | "Data Link Protocol", /* Bit Position 4 */ |
6c2b374d ZY |
99 | NULL, |
100 | NULL, | |
101 | NULL, | |
102 | NULL, | |
103 | NULL, | |
104 | NULL, | |
105 | NULL, | |
b64a4414 HY |
106 | "Poisoned TLP", /* Bit Position 12 */ |
107 | "Flow Control Protocol", /* Bit Position 13 */ | |
108 | "Completion Timeout", /* Bit Position 14 */ | |
109 | "Completer Abort", /* Bit Position 15 */ | |
110 | "Unexpected Completion", /* Bit Position 16 */ | |
111 | "Receiver Overflow", /* Bit Position 17 */ | |
112 | "Malformed TLP", /* Bit Position 18 */ | |
113 | "ECRC", /* Bit Position 19 */ | |
114 | "Unsupported Request", /* Bit Position 20 */ | |
6c2b374d ZY |
115 | }; |
116 | ||
b64a4414 | 117 | static const char *aer_agent_string[] = { |
6c2b374d ZY |
118 | "Receiver ID", |
119 | "Requester ID", | |
120 | "Completer ID", | |
121 | "Transmitter ID" | |
122 | }; | |
123 | ||
b64a4414 HY |
124 | static void __aer_print_error(const char *prefix, |
125 | struct aer_err_info *info) | |
6c2b374d | 126 | { |
0d90c3ac | 127 | int i, status; |
b64a4414 | 128 | const char *errmsg = NULL; |
6c2b374d | 129 | |
0d90c3ac HS |
130 | status = (info->status & ~info->mask); |
131 | ||
6c2b374d | 132 | for (i = 0; i < 32; i++) { |
0d90c3ac | 133 | if (!(status & (1 << i))) |
6c2b374d ZY |
134 | continue; |
135 | ||
24dbb7be | 136 | if (info->severity == AER_CORRECTABLE) |
b64a4414 HY |
137 | errmsg = i < ARRAY_SIZE(aer_correctable_error_string) ? |
138 | aer_correctable_error_string[i] : NULL; | |
6c2b374d | 139 | else |
b64a4414 HY |
140 | errmsg = i < ARRAY_SIZE(aer_uncorrectable_error_string) ? |
141 | aer_uncorrectable_error_string[i] : NULL; | |
6c2b374d | 142 | |
24dbb7be | 143 | if (errmsg) |
b64a4414 | 144 | printk("%s"" [%2d] %-22s%s\n", prefix, i, errmsg, |
79e4b89b | 145 | info->first_error == i ? " (First)" : ""); |
24dbb7be | 146 | else |
b64a4414 | 147 | printk("%s"" [%2d] Unknown Error Bit%s\n", prefix, i, |
79e4b89b | 148 | info->first_error == i ? " (First)" : ""); |
6c2b374d | 149 | } |
6c2b374d ZY |
150 | } |
151 | ||
6c2b374d ZY |
152 | void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) |
153 | { | |
0d465f23 | 154 | int id = ((dev->bus->number << 8) | dev->devfn); |
b64a4414 HY |
155 | char prefix[44]; |
156 | ||
157 | snprintf(prefix, sizeof(prefix), "%s%s %s: ", | |
158 | (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR, | |
159 | dev_driver_string(&dev->dev), dev_name(&dev->dev)); | |
6c2b374d | 160 | |
c9a91883 | 161 | if (info->status == 0) { |
b64a4414 HY |
162 | printk("%s""PCIe Bus Error: severity=%s, type=Unaccessible, " |
163 | "id=%04x(Unregistered Agent ID)\n", prefix, | |
79e4b89b | 164 | aer_error_severity_string[info->severity], id); |
6c2b374d | 165 | } else { |
79e4b89b | 166 | int layer, agent; |
6c2b374d | 167 | |
79e4b89b | 168 | layer = AER_GET_LAYER_ERROR(info->severity, info->status); |
6c2b374d | 169 | agent = AER_GET_AGENT(info->severity, info->status); |
6c2b374d | 170 | |
b64a4414 HY |
171 | printk("%s""PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n", |
172 | prefix, aer_error_severity_string[info->severity], | |
79e4b89b HS |
173 | aer_error_layer[layer], id, aer_agent_string[agent]); |
174 | ||
b64a4414 HY |
175 | printk("%s"" device [%04x:%04x] error status/mask=%08x/%08x\n", |
176 | prefix, dev->vendor, dev->device, | |
177 | info->status, info->mask); | |
79e4b89b | 178 | |
b64a4414 | 179 | __aer_print_error(prefix, info); |
6c2b374d | 180 | |
273024de | 181 | if (info->tlp_header_valid) { |
6c2b374d | 182 | unsigned char *tlp = (unsigned char *) &info->tlp; |
b64a4414 | 183 | printk("%s"" TLP Header:" |
79e4b89b | 184 | " %02x%02x%02x%02x %02x%02x%02x%02x" |
6c2b374d | 185 | " %02x%02x%02x%02x %02x%02x%02x%02x\n", |
b64a4414 | 186 | prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, |
6c2b374d ZY |
187 | *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), |
188 | *(tlp + 11), *(tlp + 10), *(tlp + 9), | |
189 | *(tlp + 8), *(tlp + 15), *(tlp + 14), | |
190 | *(tlp + 13), *(tlp + 12)); | |
191 | } | |
192 | } | |
0d465f23 HS |
193 | |
194 | if (info->id && info->error_dev_num > 1 && info->id == id) | |
b64a4414 HY |
195 | printk("%s"" Error of this Agent(%04x) is reported first\n", |
196 | prefix, id); | |
79e4b89b HS |
197 | } |
198 | ||
199 | void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) | |
200 | { | |
201 | dev_info(&dev->dev, "AER: %s%s error received: id=%04x\n", | |
202 | info->multi_error_valid ? "Multiple " : "", | |
203 | aer_error_severity_string[info->severity], info->id); | |
6c2b374d | 204 | } |
c413d768 HY |
205 | |
206 | #ifdef CONFIG_ACPI_APEI_PCIEAER | |
0918472c | 207 | int cper_severity_to_aer(int cper_severity) |
c413d768 HY |
208 | { |
209 | switch (cper_severity) { | |
210 | case CPER_SEV_RECOVERABLE: | |
211 | return AER_NONFATAL; | |
212 | case CPER_SEV_FATAL: | |
213 | return AER_FATAL; | |
214 | default: | |
215 | return AER_CORRECTABLE; | |
216 | } | |
217 | } | |
0918472c | 218 | EXPORT_SYMBOL_GPL(cper_severity_to_aer); |
c413d768 HY |
219 | |
220 | void cper_print_aer(const char *prefix, int cper_severity, | |
221 | struct aer_capability_regs *aer) | |
222 | { | |
223 | int aer_severity, layer, agent, status_strs_size, tlp_header_valid = 0; | |
224 | u32 status, mask; | |
225 | const char **status_strs; | |
226 | ||
227 | aer_severity = cper_severity_to_aer(cper_severity); | |
228 | if (aer_severity == AER_CORRECTABLE) { | |
229 | status = aer->cor_status; | |
230 | mask = aer->cor_mask; | |
231 | status_strs = aer_correctable_error_string; | |
232 | status_strs_size = ARRAY_SIZE(aer_correctable_error_string); | |
233 | } else { | |
234 | status = aer->uncor_status; | |
235 | mask = aer->uncor_mask; | |
236 | status_strs = aer_uncorrectable_error_string; | |
237 | status_strs_size = ARRAY_SIZE(aer_uncorrectable_error_string); | |
238 | tlp_header_valid = status & AER_LOG_TLP_MASKS; | |
239 | } | |
240 | layer = AER_GET_LAYER_ERROR(aer_severity, status); | |
241 | agent = AER_GET_AGENT(aer_severity, status); | |
242 | printk("%s""aer_status: 0x%08x, aer_mask: 0x%08x\n", | |
243 | prefix, status, mask); | |
244 | cper_print_bits(prefix, status, status_strs, status_strs_size); | |
245 | printk("%s""aer_layer=%s, aer_agent=%s\n", prefix, | |
246 | aer_error_layer[layer], aer_agent_string[agent]); | |
247 | if (aer_severity != AER_CORRECTABLE) | |
248 | printk("%s""aer_uncor_severity: 0x%08x\n", | |
249 | prefix, aer->uncor_severity); | |
250 | if (tlp_header_valid) { | |
251 | const unsigned char *tlp; | |
252 | tlp = (const unsigned char *)&aer->header_log; | |
253 | printk("%s""aer_tlp_header:" | |
254 | " %02x%02x%02x%02x %02x%02x%02x%02x" | |
255 | " %02x%02x%02x%02x %02x%02x%02x%02x\n", | |
256 | prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, | |
257 | *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), | |
258 | *(tlp + 11), *(tlp + 10), *(tlp + 9), | |
259 | *(tlp + 8), *(tlp + 15), *(tlp + 14), | |
260 | *(tlp + 13), *(tlp + 12)); | |
261 | } | |
262 | } | |
263 | #endif |