18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
38c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
48c2ecf20Sopenharmony_ci * for more details.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 1994, 1995, 1996, 1999, 2000 by Ralf Baechle
78c2ecf20Sopenharmony_ci * Copyright (C) 1999, 2000 by Silicon Graphics
88c2ecf20Sopenharmony_ci * Copyright (C) 2002  Maciej W. Rozycki
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci#include <linux/init.h>
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/signal.h>	/* for SIGBUS */
138c2ecf20Sopenharmony_ci#include <linux/sched.h>	/* schow_regs(), force_sig() */
148c2ecf20Sopenharmony_ci#include <linux/sched/debug.h>
158c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <asm/ptrace.h>
188c2ecf20Sopenharmony_ci#include <asm/sn/addrs.h>
198c2ecf20Sopenharmony_ci#include <asm/sn/agent.h>
208c2ecf20Sopenharmony_ci#include <asm/sn/arch.h>
218c2ecf20Sopenharmony_ci#include <asm/tlbdebug.h>
228c2ecf20Sopenharmony_ci#include <asm/traps.h>
238c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic void dump_hub_information(unsigned long errst0, unsigned long errst1)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	static char *err_type[2][8] = {
288c2ecf20Sopenharmony_ci		{ NULL, "Uncached Partial Read PRERR", "DERR", "Read Timeout",
298c2ecf20Sopenharmony_ci		  NULL, NULL, NULL, NULL },
308c2ecf20Sopenharmony_ci		{ "WERR", "Uncached Partial Write", "PWERR", "Write Timeout",
318c2ecf20Sopenharmony_ci		  NULL, NULL, NULL, NULL }
328c2ecf20Sopenharmony_ci	};
338c2ecf20Sopenharmony_ci	union pi_err_stat0 st0;
348c2ecf20Sopenharmony_ci	union pi_err_stat1 st1;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	st0.pi_stat0_word = errst0;
378c2ecf20Sopenharmony_ci	st1.pi_stat1_word = errst1;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	if (!st0.pi_stat0_fmt.s0_valid) {
408c2ecf20Sopenharmony_ci		pr_info("Hub does not contain valid error information\n");
418c2ecf20Sopenharmony_ci		return;
428c2ecf20Sopenharmony_ci	}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	pr_info("Hub has valid error information:\n");
458c2ecf20Sopenharmony_ci	if (st0.pi_stat0_fmt.s0_ovr_run)
468c2ecf20Sopenharmony_ci		pr_info("Overrun is set. Error stack may contain additional "
478c2ecf20Sopenharmony_ci		       "information.\n");
488c2ecf20Sopenharmony_ci	pr_info("Hub error address is %08lx\n",
498c2ecf20Sopenharmony_ci		(unsigned long)st0.pi_stat0_fmt.s0_addr);
508c2ecf20Sopenharmony_ci	pr_info("Incoming message command 0x%lx\n",
518c2ecf20Sopenharmony_ci		(unsigned long)st0.pi_stat0_fmt.s0_cmd);
528c2ecf20Sopenharmony_ci	pr_info("Supplemental field of incoming message is 0x%lx\n",
538c2ecf20Sopenharmony_ci		(unsigned long)st0.pi_stat0_fmt.s0_supl);
548c2ecf20Sopenharmony_ci	pr_info("T5 Rn (for RRB only) is 0x%lx\n",
558c2ecf20Sopenharmony_ci		(unsigned long)st0.pi_stat0_fmt.s0_t5_req);
568c2ecf20Sopenharmony_ci	pr_info("Error type is %s\n", err_type[st1.pi_stat1_fmt.s1_rw_rb]
578c2ecf20Sopenharmony_ci	       [st0.pi_stat0_fmt.s0_err_type] ? : "invalid");
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ciint ip27_be_handler(struct pt_regs *regs, int is_fixup)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	unsigned long errst0, errst1;
638c2ecf20Sopenharmony_ci	int data = regs->cp0_cause & 4;
648c2ecf20Sopenharmony_ci	int cpu = LOCAL_HUB_L(PI_CPU_NUM);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	if (is_fixup)
678c2ecf20Sopenharmony_ci		return MIPS_BE_FIXUP;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	printk("Slice %c got %cbe at 0x%lx\n", 'A' + cpu, data ? 'd' : 'i',
708c2ecf20Sopenharmony_ci	       regs->cp0_epc);
718c2ecf20Sopenharmony_ci	printk("Hub information:\n");
728c2ecf20Sopenharmony_ci	printk("ERR_INT_PEND = 0x%06llx\n", LOCAL_HUB_L(PI_ERR_INT_PEND));
738c2ecf20Sopenharmony_ci	errst0 = LOCAL_HUB_L(cpu ? PI_ERR_STATUS0_B : PI_ERR_STATUS0_A);
748c2ecf20Sopenharmony_ci	errst1 = LOCAL_HUB_L(cpu ? PI_ERR_STATUS1_B : PI_ERR_STATUS1_A);
758c2ecf20Sopenharmony_ci	dump_hub_information(errst0, errst1);
768c2ecf20Sopenharmony_ci	show_regs(regs);
778c2ecf20Sopenharmony_ci	dump_tlb_all();
788c2ecf20Sopenharmony_ci	while(1);
798c2ecf20Sopenharmony_ci	force_sig(SIGBUS);
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_civoid __init ip27_be_init(void)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	/* XXX Initialize all the Hub & Bridge error handling here.  */
858c2ecf20Sopenharmony_ci	int cpu = LOCAL_HUB_L(PI_CPU_NUM);
868c2ecf20Sopenharmony_ci	int cpuoff = cpu << 8;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	board_be_handler = ip27_be_handler;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	LOCAL_HUB_S(PI_ERR_INT_PEND,
918c2ecf20Sopenharmony_ci		    cpu ? PI_ERR_CLEAR_ALL_B : PI_ERR_CLEAR_ALL_A);
928c2ecf20Sopenharmony_ci	LOCAL_HUB_S(PI_ERR_INT_MASK_A + cpuoff, 0);
938c2ecf20Sopenharmony_ci	LOCAL_HUB_S(PI_ERR_STACK_ADDR_A + cpuoff, 0);
948c2ecf20Sopenharmony_ci	LOCAL_HUB_S(PI_ERR_STACK_SIZE, 0);	/* Disable error stack */
958c2ecf20Sopenharmony_ci	LOCAL_HUB_S(PI_SYSAD_ERRCHK_EN, PI_SYSAD_CHECK_ALL);
968c2ecf20Sopenharmony_ci}
97