162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/kernel.h>
662306a36Sopenharmony_ci#include <linux/printk.h>
762306a36Sopenharmony_ci#include <linux/ptrace.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <asm/reg.h>
1062306a36Sopenharmony_ci#include <asm/cacheflush.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ciint machine_check_440A(struct pt_regs *regs)
1362306a36Sopenharmony_ci{
1462306a36Sopenharmony_ci	unsigned long reason = regs->esr;
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci	printk("Machine check in kernel mode.\n");
1762306a36Sopenharmony_ci	if (reason & ESR_IMCP){
1862306a36Sopenharmony_ci		printk("Instruction Synchronous Machine Check exception\n");
1962306a36Sopenharmony_ci		mtspr(SPRN_ESR, reason & ~ESR_IMCP);
2062306a36Sopenharmony_ci	}
2162306a36Sopenharmony_ci	else {
2262306a36Sopenharmony_ci		u32 mcsr = mfspr(SPRN_MCSR);
2362306a36Sopenharmony_ci		if (mcsr & MCSR_IB)
2462306a36Sopenharmony_ci			printk("Instruction Read PLB Error\n");
2562306a36Sopenharmony_ci		if (mcsr & MCSR_DRB)
2662306a36Sopenharmony_ci			printk("Data Read PLB Error\n");
2762306a36Sopenharmony_ci		if (mcsr & MCSR_DWB)
2862306a36Sopenharmony_ci			printk("Data Write PLB Error\n");
2962306a36Sopenharmony_ci		if (mcsr & MCSR_TLBP)
3062306a36Sopenharmony_ci			printk("TLB Parity Error\n");
3162306a36Sopenharmony_ci		if (mcsr & MCSR_ICP){
3262306a36Sopenharmony_ci			flush_instruction_cache();
3362306a36Sopenharmony_ci			printk("I-Cache Parity Error\n");
3462306a36Sopenharmony_ci		}
3562306a36Sopenharmony_ci		if (mcsr & MCSR_DCSP)
3662306a36Sopenharmony_ci			printk("D-Cache Search Parity Error\n");
3762306a36Sopenharmony_ci		if (mcsr & MCSR_DCFP)
3862306a36Sopenharmony_ci			printk("D-Cache Flush Parity Error\n");
3962306a36Sopenharmony_ci		if (mcsr & MCSR_IMPE)
4062306a36Sopenharmony_ci			printk("Machine Check exception is imprecise\n");
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci		/* Clear MCSR */
4362306a36Sopenharmony_ci		mtspr(SPRN_MCSR, mcsr);
4462306a36Sopenharmony_ci	}
4562306a36Sopenharmony_ci	return 0;
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#ifdef CONFIG_PPC_47x
4962306a36Sopenharmony_ciint machine_check_47x(struct pt_regs *regs)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	unsigned long reason = regs->esr;
5262306a36Sopenharmony_ci	u32 mcsr;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	printk(KERN_ERR "Machine check in kernel mode.\n");
5562306a36Sopenharmony_ci	if (reason & ESR_IMCP) {
5662306a36Sopenharmony_ci		printk(KERN_ERR "Instruction Synchronous Machine Check exception\n");
5762306a36Sopenharmony_ci		mtspr(SPRN_ESR, reason & ~ESR_IMCP);
5862306a36Sopenharmony_ci		return 0;
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci	mcsr = mfspr(SPRN_MCSR);
6162306a36Sopenharmony_ci	if (mcsr & MCSR_IB)
6262306a36Sopenharmony_ci		printk(KERN_ERR "Instruction Read PLB Error\n");
6362306a36Sopenharmony_ci	if (mcsr & MCSR_DRB)
6462306a36Sopenharmony_ci		printk(KERN_ERR "Data Read PLB Error\n");
6562306a36Sopenharmony_ci	if (mcsr & MCSR_DWB)
6662306a36Sopenharmony_ci		printk(KERN_ERR "Data Write PLB Error\n");
6762306a36Sopenharmony_ci	if (mcsr & MCSR_TLBP)
6862306a36Sopenharmony_ci		printk(KERN_ERR "TLB Parity Error\n");
6962306a36Sopenharmony_ci	if (mcsr & MCSR_ICP) {
7062306a36Sopenharmony_ci		flush_instruction_cache();
7162306a36Sopenharmony_ci		printk(KERN_ERR "I-Cache Parity Error\n");
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci	if (mcsr & MCSR_DCSP)
7462306a36Sopenharmony_ci		printk(KERN_ERR "D-Cache Search Parity Error\n");
7562306a36Sopenharmony_ci	if (mcsr & PPC47x_MCSR_GPR)
7662306a36Sopenharmony_ci		printk(KERN_ERR "GPR Parity Error\n");
7762306a36Sopenharmony_ci	if (mcsr & PPC47x_MCSR_FPR)
7862306a36Sopenharmony_ci		printk(KERN_ERR "FPR Parity Error\n");
7962306a36Sopenharmony_ci	if (mcsr & PPC47x_MCSR_IPR)
8062306a36Sopenharmony_ci		printk(KERN_ERR "Machine Check exception is imprecise\n");
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	/* Clear MCSR */
8362306a36Sopenharmony_ci	mtspr(SPRN_MCSR, mcsr);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	return 0;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci#endif /* CONFIG_PPC_47x */
88