mce.c (0a182611d149b5b747014fbb230ec35b20a45c86) mce.c (cc15ff3275694fedc33cd3d53212a43eec7aa0bc)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Machine check exception handling.
4 *
5 * Copyright 2013 IBM Corporation
6 * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
7 */
8

--- 14 unchanged lines hidden (view full) ---

23#include <asm/interrupt.h>
24#include <asm/machdep.h>
25#include <asm/mce.h>
26#include <asm/nmi.h>
27#include <asm/asm-prototypes.h>
28
29#include "setup.h"
30
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Machine check exception handling.
4 *
5 * Copyright 2013 IBM Corporation
6 * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
7 */
8

--- 14 unchanged lines hidden (view full) ---

23#include <asm/interrupt.h>
24#include <asm/machdep.h>
25#include <asm/mce.h>
26#include <asm/nmi.h>
27#include <asm/asm-prototypes.h>
28
29#include "setup.h"
30
31static void machine_check_process_queued_event(struct irq_work *work);
32static void machine_check_ue_irq_work(struct irq_work *work);
33static void machine_check_ue_event(struct machine_check_event *evt);
34static void machine_process_ue_event(struct work_struct *work);
35
31static void machine_check_ue_event(struct machine_check_event *evt);
32static void machine_process_ue_event(struct work_struct *work);
33
36static struct irq_work mce_event_process_work = {
37 .func = machine_check_process_queued_event,
38};
39
40static struct irq_work mce_ue_event_irq_work = {
41 .func = machine_check_ue_irq_work,
42};
43
44static DECLARE_WORK(mce_ue_event_work, machine_process_ue_event);
45
46static BLOCKING_NOTIFIER_HEAD(mce_notifier_list);
47
48int mce_register_notifier(struct notifier_block *nb)
49{
50 return blocking_notifier_chain_register(&mce_notifier_list, nb);
51}

--- 32 unchanged lines hidden (view full) ---

84 mce->u.link_error.link_error_type = mce_err->u.link_error_type;
85 break;
86 case MCE_ERROR_TYPE_UNKNOWN:
87 default:
88 break;
89 }
90}
91
34static DECLARE_WORK(mce_ue_event_work, machine_process_ue_event);
35
36static BLOCKING_NOTIFIER_HEAD(mce_notifier_list);
37
38int mce_register_notifier(struct notifier_block *nb)
39{
40 return blocking_notifier_chain_register(&mce_notifier_list, nb);
41}

--- 32 unchanged lines hidden (view full) ---

74 mce->u.link_error.link_error_type = mce_err->u.link_error_type;
75 break;
76 case MCE_ERROR_TYPE_UNKNOWN:
77 default:
78 break;
79 }
80}
81
82void mce_irq_work_queue(void)
83{
84 /* Raise decrementer interrupt */
85 arch_irq_work_raise();
86 set_mce_pending_irq_work();
87}
88
92/*
93 * Decode and save high level MCE information into per cpu buffer which
94 * is an array of machine_check_event structure.
95 */
96void save_mce_event(struct pt_regs *regs, long handled,
97 struct mce_error_info *mce_err,
98 uint64_t nip, uint64_t addr, uint64_t phys_addr)
99{

--- 112 unchanged lines hidden (view full) ---

212 return ret;
213}
214
215void release_mce_event(void)
216{
217 get_mce_event(NULL, true);
218}
219
89/*
90 * Decode and save high level MCE information into per cpu buffer which
91 * is an array of machine_check_event structure.
92 */
93void save_mce_event(struct pt_regs *regs, long handled,
94 struct mce_error_info *mce_err,
95 uint64_t nip, uint64_t addr, uint64_t phys_addr)
96{

--- 112 unchanged lines hidden (view full) ---

209 return ret;
210}
211
212void release_mce_event(void)
213{
214 get_mce_event(NULL, true);
215}
216
220static void machine_check_ue_irq_work(struct irq_work *work)
217static void machine_check_ue_work(void)
221{
222 schedule_work(&mce_ue_event_work);
223}
224
225/*
226 * Queue up the MCE event which then can be handled later.
227 */
228static void machine_check_ue_event(struct machine_check_event *evt)

--- 5 unchanged lines hidden (view full) ---

234 if (index >= MAX_MC_EVT) {
235 local_paca->mce_info->mce_ue_count--;
236 return;
237 }
238 memcpy(&local_paca->mce_info->mce_ue_event_queue[index],
239 evt, sizeof(*evt));
240
241 /* Queue work to process this event later. */
218{
219 schedule_work(&mce_ue_event_work);
220}
221
222/*
223 * Queue up the MCE event which then can be handled later.
224 */
225static void machine_check_ue_event(struct machine_check_event *evt)

--- 5 unchanged lines hidden (view full) ---

231 if (index >= MAX_MC_EVT) {
232 local_paca->mce_info->mce_ue_count--;
233 return;
234 }
235 memcpy(&local_paca->mce_info->mce_ue_event_queue[index],
236 evt, sizeof(*evt));
237
238 /* Queue work to process this event later. */
242 irq_work_queue(&mce_ue_event_irq_work);
239 mce_irq_work_queue();
243}
244
245/*
246 * Queue up the MCE event which then can be handled later.
247 */
248void machine_check_queue_event(void)
249{
250 int index;
251 struct machine_check_event evt;
240}
241
242/*
243 * Queue up the MCE event which then can be handled later.
244 */
245void machine_check_queue_event(void)
246{
247 int index;
248 struct machine_check_event evt;
252 unsigned long msr;
253
254 if (!get_mce_event(&evt, MCE_EVENT_RELEASE))
255 return;
256
257 index = local_paca->mce_info->mce_queue_count++;
258 /* If queue is full, just return for now. */
259 if (index >= MAX_MC_EVT) {
260 local_paca->mce_info->mce_queue_count--;
261 return;
262 }
263 memcpy(&local_paca->mce_info->mce_event_queue[index],
264 &evt, sizeof(evt));
265
249
250 if (!get_mce_event(&evt, MCE_EVENT_RELEASE))
251 return;
252
253 index = local_paca->mce_info->mce_queue_count++;
254 /* If queue is full, just return for now. */
255 if (index >= MAX_MC_EVT) {
256 local_paca->mce_info->mce_queue_count--;
257 return;
258 }
259 memcpy(&local_paca->mce_info->mce_event_queue[index],
260 &evt, sizeof(evt));
261
266 /*
267 * Queue irq work to process this event later. Before
268 * queuing the work enable translation for non radix LPAR,
269 * as irq_work_queue may try to access memory outside RMO
270 * region.
271 */
272 if (!radix_enabled() && firmware_has_feature(FW_FEATURE_LPAR)) {
273 msr = mfmsr();
274 mtmsr(msr | MSR_IR | MSR_DR);
275 irq_work_queue(&mce_event_process_work);
276 mtmsr(msr);
277 } else {
278 irq_work_queue(&mce_event_process_work);
279 }
262 mce_irq_work_queue();
280}
281
282void mce_common_process_ue(struct pt_regs *regs,
283 struct mce_error_info *mce_err)
284{
285 const struct exception_table_entry *entry;
286
287 entry = search_kernel_exception_table(regs->nip);

--- 45 unchanged lines hidden (view full) ---

333#endif
334 local_paca->mce_info->mce_ue_count--;
335 }
336}
337/*
338 * process pending MCE event from the mce event queue. This function will be
339 * called during syscall exit.
340 */
263}
264
265void mce_common_process_ue(struct pt_regs *regs,
266 struct mce_error_info *mce_err)
267{
268 const struct exception_table_entry *entry;
269
270 entry = search_kernel_exception_table(regs->nip);

--- 45 unchanged lines hidden (view full) ---

316#endif
317 local_paca->mce_info->mce_ue_count--;
318 }
319}
320/*
321 * process pending MCE event from the mce event queue. This function will be
322 * called during syscall exit.
323 */
341static void machine_check_process_queued_event(struct irq_work *work)
324static void machine_check_process_queued_event(void)
342{
343 int index;
344 struct machine_check_event *evt;
345
346 add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
347
348 /*
349 * For now just print it to console.

--- 8 unchanged lines hidden (view full) ---

358 local_paca->mce_info->mce_queue_count--;
359 continue;
360 }
361 machine_check_print_event_info(evt, false, false);
362 local_paca->mce_info->mce_queue_count--;
363 }
364}
365
325{
326 int index;
327 struct machine_check_event *evt;
328
329 add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
330
331 /*
332 * For now just print it to console.

--- 8 unchanged lines hidden (view full) ---

341 local_paca->mce_info->mce_queue_count--;
342 continue;
343 }
344 machine_check_print_event_info(evt, false, false);
345 local_paca->mce_info->mce_queue_count--;
346 }
347}
348
349void set_mce_pending_irq_work(void)
350{
351 local_paca->mce_pending_irq_work = 1;
352}
353
354void clear_mce_pending_irq_work(void)
355{
356 local_paca->mce_pending_irq_work = 0;
357}
358
359void mce_run_irq_context_handlers(void)
360{
361 if (unlikely(local_paca->mce_pending_irq_work)) {
362 if (ppc_md.machine_check_log_err)
363 ppc_md.machine_check_log_err();
364 machine_check_process_queued_event();
365 machine_check_ue_work();
366 clear_mce_pending_irq_work();
367 }
368}
369
366void machine_check_print_event_info(struct machine_check_event *evt,
367 bool user_mode, bool in_guest)
368{
369 const char *level, *sevstr, *subtype, *err_type, *initiator;
370 uint64_t ea = 0, pa = 0;
371 int n = 0;
372 char dar_str[50];
373 char pa_str[50];

--- 391 unchanged lines hidden ---
370void machine_check_print_event_info(struct machine_check_event *evt,
371 bool user_mode, bool in_guest)
372{
373 const char *level, *sevstr, *subtype, *err_type, *initiator;
374 uint64_t ea = 0, pa = 0;
375 int n = 0;
376 char dar_str[50];
377 char pa_str[50];

--- 391 unchanged lines hidden ---