diff options
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/mce_amd.c | 79 | ||||
-rw-r--r-- | drivers/edac/mce_amd.h | 2 |
2 files changed, 62 insertions, 19 deletions
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c index 01853eed2019..12bae3b18e3d 100644 --- a/drivers/edac/mce_amd.c +++ b/drivers/edac/mce_amd.c | |||
@@ -75,7 +75,7 @@ static const char *f10h_nb_mce_desc[] = { | |||
75 | "ECC Error in the Probe Filter directory" | 75 | "ECC Error in the Probe Filter directory" |
76 | }; | 76 | }; |
77 | 77 | ||
78 | static bool f12h_dc_mce(u16 ec) | 78 | static bool f12h_dc_mce(u16 ec, u8 xec) |
79 | { | 79 | { |
80 | bool ret = false; | 80 | bool ret = false; |
81 | 81 | ||
@@ -93,7 +93,7 @@ static bool f12h_dc_mce(u16 ec) | |||
93 | return ret; | 93 | return ret; |
94 | } | 94 | } |
95 | 95 | ||
96 | static bool f10h_dc_mce(u16 ec) | 96 | static bool f10h_dc_mce(u16 ec, u8 xec) |
97 | { | 97 | { |
98 | u8 r4 = (ec >> 4) & 0xf; | 98 | u8 r4 = (ec >> 4) & 0xf; |
99 | u8 ll = ec & 0x3; | 99 | u8 ll = ec & 0x3; |
@@ -102,20 +102,20 @@ static bool f10h_dc_mce(u16 ec) | |||
102 | pr_cont("during data scrub.\n"); | 102 | pr_cont("during data scrub.\n"); |
103 | return true; | 103 | return true; |
104 | } | 104 | } |
105 | return f12h_dc_mce(ec); | 105 | return f12h_dc_mce(ec, xec); |
106 | } | 106 | } |
107 | 107 | ||
108 | static bool k8_dc_mce(u16 ec) | 108 | static bool k8_dc_mce(u16 ec, u8 xec) |
109 | { | 109 | { |
110 | if (BUS_ERROR(ec)) { | 110 | if (BUS_ERROR(ec)) { |
111 | pr_cont("during system linefill.\n"); | 111 | pr_cont("during system linefill.\n"); |
112 | return true; | 112 | return true; |
113 | } | 113 | } |
114 | 114 | ||
115 | return f10h_dc_mce(ec); | 115 | return f10h_dc_mce(ec, xec); |
116 | } | 116 | } |
117 | 117 | ||
118 | static bool f14h_dc_mce(u16 ec) | 118 | static bool f14h_dc_mce(u16 ec, u8 xec) |
119 | { | 119 | { |
120 | u8 r4 = (ec >> 4) & 0xf; | 120 | u8 r4 = (ec >> 4) & 0xf; |
121 | u8 ll = ec & 0x3; | 121 | u8 ll = ec & 0x3; |
@@ -170,6 +170,54 @@ static bool f14h_dc_mce(u16 ec) | |||
170 | return ret; | 170 | return ret; |
171 | } | 171 | } |
172 | 172 | ||
173 | static bool f15h_dc_mce(u16 ec, u8 xec) | ||
174 | { | ||
175 | bool ret = true; | ||
176 | |||
177 | if (MEM_ERROR(ec)) { | ||
178 | |||
179 | switch (xec) { | ||
180 | case 0x0: | ||
181 | pr_cont("Data Array access error.\n"); | ||
182 | break; | ||
183 | |||
184 | case 0x1: | ||
185 | pr_cont("UC error during a linefill from L2/NB.\n"); | ||
186 | break; | ||
187 | |||
188 | case 0x2: | ||
189 | case 0x11: | ||
190 | pr_cont("STQ access error.\n"); | ||
191 | break; | ||
192 | |||
193 | case 0x3: | ||
194 | pr_cont("SCB access error.\n"); | ||
195 | break; | ||
196 | |||
197 | case 0x10: | ||
198 | pr_cont("Tag error.\n"); | ||
199 | break; | ||
200 | |||
201 | case 0x12: | ||
202 | pr_cont("LDQ access error.\n"); | ||
203 | break; | ||
204 | |||
205 | default: | ||
206 | ret = false; | ||
207 | } | ||
208 | } else if (BUS_ERROR(ec)) { | ||
209 | |||
210 | if (!xec) | ||
211 | pr_cont("during system linefill.\n"); | ||
212 | else | ||
213 | pr_cont(" Internal %s condition.\n", | ||
214 | ((xec == 1) ? "livelock" : "deadlock")); | ||
215 | } else | ||
216 | ret = false; | ||
217 | |||
218 | return ret; | ||
219 | } | ||
220 | |||
173 | static void amd_decode_dc_mce(struct mce *m) | 221 | static void amd_decode_dc_mce(struct mce *m) |
174 | { | 222 | { |
175 | u16 ec = m->status & 0xffff; | 223 | u16 ec = m->status & 0xffff; |
@@ -183,20 +231,14 @@ static void amd_decode_dc_mce(struct mce *m) | |||
183 | 231 | ||
184 | if (tt == TT_DATA) { | 232 | if (tt == TT_DATA) { |
185 | pr_cont("%s TLB %s.\n", LL_MSG(ec), | 233 | pr_cont("%s TLB %s.\n", LL_MSG(ec), |
186 | (xec ? "multimatch" : "parity error")); | 234 | ((xec == 2) ? "locked miss" |
235 | : (xec ? "multimatch" : "parity"))); | ||
187 | return; | 236 | return; |
188 | } | 237 | } |
189 | else | 238 | } else if (fam_ops->dc_mce(ec, xec)) |
190 | goto wrong_dc_mce; | 239 | ; |
191 | } | 240 | else |
192 | 241 | pr_emerg(HW_ERR "Corrupted DC MCE info?\n"); | |
193 | if (!fam_ops->dc_mce(ec)) | ||
194 | goto wrong_dc_mce; | ||
195 | |||
196 | return; | ||
197 | |||
198 | wrong_dc_mce: | ||
199 | pr_emerg(HW_ERR "Corrupted DC MCE info?\n"); | ||
200 | } | 242 | } |
201 | 243 | ||
202 | static bool k8_ic_mce(u16 ec) | 244 | static bool k8_ic_mce(u16 ec) |
@@ -654,6 +696,7 @@ static int __init mce_amd_init(void) | |||
654 | 696 | ||
655 | case 0x15: | 697 | case 0x15: |
656 | xec_mask = 0x1f; | 698 | xec_mask = 0x1f; |
699 | fam_ops->dc_mce = f15h_dc_mce; | ||
657 | break; | 700 | break; |
658 | 701 | ||
659 | default: | 702 | default: |
diff --git a/drivers/edac/mce_amd.h b/drivers/edac/mce_amd.h index 35f6e0e3b297..c12394db9bdf 100644 --- a/drivers/edac/mce_amd.h +++ b/drivers/edac/mce_amd.h | |||
@@ -100,7 +100,7 @@ struct err_regs { | |||
100 | * per-family decoder ops | 100 | * per-family decoder ops |
101 | */ | 101 | */ |
102 | struct amd_decoder_ops { | 102 | struct amd_decoder_ops { |
103 | bool (*dc_mce)(u16); | 103 | bool (*dc_mce)(u16, u8); |
104 | bool (*ic_mce)(u16); | 104 | bool (*ic_mce)(u16); |
105 | bool (*nb_mce)(u16, u8); | 105 | bool (*nb_mce)(u16, u8); |
106 | }; | 106 | }; |