169c75fb4SMaciej W. Rozycki /* 269c75fb4SMaciej W. Rozycki * linux/arch/mips/dec/kn02xa-berr.c 369c75fb4SMaciej W. Rozycki * 469c75fb4SMaciej W. Rozycki * Bus error event handling code for 5000-series systems equipped 569c75fb4SMaciej W. Rozycki * with parity error detection logic, i.e. DECstation/DECsystem 669c75fb4SMaciej W. Rozycki * 5000/120, /125, /133 (KN02-BA), 5000/150 (KN04-BA) and Personal 769c75fb4SMaciej W. Rozycki * DECstation/DECsystem 5000/20, /25, /33 (KN02-CA), 5000/50 869c75fb4SMaciej W. Rozycki * (KN04-CA) systems. 969c75fb4SMaciej W. Rozycki * 1069c75fb4SMaciej W. Rozycki * Copyright (c) 2005 Maciej W. Rozycki 1169c75fb4SMaciej W. Rozycki * 1269c75fb4SMaciej W. Rozycki * This program is free software; you can redistribute it and/or 1369c75fb4SMaciej W. Rozycki * modify it under the terms of the GNU General Public License 1469c75fb4SMaciej W. Rozycki * as published by the Free Software Foundation; either version 1569c75fb4SMaciej W. Rozycki * 2 of the License, or (at your option) any later version. 1669c75fb4SMaciej W. Rozycki */ 1769c75fb4SMaciej W. Rozycki 1869c75fb4SMaciej W. Rozycki #include <linux/init.h> 1969c75fb4SMaciej W. Rozycki #include <linux/interrupt.h> 2069c75fb4SMaciej W. Rozycki #include <linux/kernel.h> 2169c75fb4SMaciej W. Rozycki #include <linux/types.h> 2269c75fb4SMaciej W. Rozycki 2369c75fb4SMaciej W. Rozycki #include <asm/system.h> 2469c75fb4SMaciej W. Rozycki #include <asm/traps.h> 2569c75fb4SMaciej W. Rozycki 2669c75fb4SMaciej W. Rozycki #include <asm/dec/kn02ca.h> 2769c75fb4SMaciej W. Rozycki #include <asm/dec/kn02xa.h> 2869c75fb4SMaciej W. Rozycki #include <asm/dec/kn05.h> 2969c75fb4SMaciej W. Rozycki 3069c75fb4SMaciej W. Rozycki static inline void dec_kn02xa_be_ack(void) 3169c75fb4SMaciej W. Rozycki { 3269c75fb4SMaciej W. Rozycki volatile u32 *mer = (void *)KN02XA_MER; 3369c75fb4SMaciej W. Rozycki volatile u32 *mem_intr = (void *)KN02XA_MEM_INTR; 3469c75fb4SMaciej W. Rozycki 3569c75fb4SMaciej W. Rozycki *mer = KN02CA_MER_INTR; /* Clear errors; keep the ARC IRQ. */ 3669c75fb4SMaciej W. Rozycki *mem_intr = 0; /* Any write clears the bus IRQ. */ 3769c75fb4SMaciej W. Rozycki iob(); 3869c75fb4SMaciej W. Rozycki } 3969c75fb4SMaciej W. Rozycki 4069c75fb4SMaciej W. Rozycki static int dec_kn02xa_be_backend(struct pt_regs *regs, int is_fixup, 4169c75fb4SMaciej W. Rozycki int invoker) 4269c75fb4SMaciej W. Rozycki { 4369c75fb4SMaciej W. Rozycki volatile u32 *kn02xa_mer = (void *)KN02XA_MER; 4469c75fb4SMaciej W. Rozycki volatile u32 *kn02xa_ear = (void *)KN02XA_EAR; 4569c75fb4SMaciej W. Rozycki 4669c75fb4SMaciej W. Rozycki static const char excstr[] = "exception"; 4769c75fb4SMaciej W. Rozycki static const char intstr[] = "interrupt"; 4869c75fb4SMaciej W. Rozycki static const char cpustr[] = "CPU"; 4969c75fb4SMaciej W. Rozycki static const char mreadstr[] = "memory read"; 5069c75fb4SMaciej W. Rozycki static const char readstr[] = "read"; 5169c75fb4SMaciej W. Rozycki static const char writestr[] = "write"; 5269c75fb4SMaciej W. Rozycki static const char timestr[] = "timeout"; 5369c75fb4SMaciej W. Rozycki static const char paritystr[] = "parity error"; 5469c75fb4SMaciej W. Rozycki static const char lanestat[][4] = { " OK", "BAD" }; 5569c75fb4SMaciej W. Rozycki 5669c75fb4SMaciej W. Rozycki const char *kind, *agent, *cycle, *event; 5769c75fb4SMaciej W. Rozycki unsigned long address; 5869c75fb4SMaciej W. Rozycki 5969c75fb4SMaciej W. Rozycki u32 mer = *kn02xa_mer; 6069c75fb4SMaciej W. Rozycki u32 ear = *kn02xa_ear; 6169c75fb4SMaciej W. Rozycki int action = MIPS_BE_FATAL; 6269c75fb4SMaciej W. Rozycki 6369c75fb4SMaciej W. Rozycki /* Ack ASAP, so that any subsequent errors get caught. */ 6469c75fb4SMaciej W. Rozycki dec_kn02xa_be_ack(); 6569c75fb4SMaciej W. Rozycki 6669c75fb4SMaciej W. Rozycki kind = invoker ? intstr : excstr; 6769c75fb4SMaciej W. Rozycki 6869c75fb4SMaciej W. Rozycki /* No DMA errors? */ 6969c75fb4SMaciej W. Rozycki agent = cpustr; 7069c75fb4SMaciej W. Rozycki 7169c75fb4SMaciej W. Rozycki address = ear & KN02XA_EAR_ADDRESS; 7269c75fb4SMaciej W. Rozycki 7369c75fb4SMaciej W. Rozycki /* Low 256MB is decoded as memory, high -- as TC. */ 7469c75fb4SMaciej W. Rozycki if (address < 0x10000000) { 7569c75fb4SMaciej W. Rozycki cycle = mreadstr; 7669c75fb4SMaciej W. Rozycki event = paritystr; 7769c75fb4SMaciej W. Rozycki } else { 7869c75fb4SMaciej W. Rozycki cycle = invoker ? writestr : readstr; 7969c75fb4SMaciej W. Rozycki event = timestr; 8069c75fb4SMaciej W. Rozycki } 8169c75fb4SMaciej W. Rozycki 8269c75fb4SMaciej W. Rozycki if (is_fixup) 8369c75fb4SMaciej W. Rozycki action = MIPS_BE_FIXUP; 8469c75fb4SMaciej W. Rozycki 8569c75fb4SMaciej W. Rozycki if (action != MIPS_BE_FIXUP) 8669c75fb4SMaciej W. Rozycki printk(KERN_ALERT "Bus error %s: %s %s %s at %#010lx\n", 8769c75fb4SMaciej W. Rozycki kind, agent, cycle, event, address); 8869c75fb4SMaciej W. Rozycki 8969c75fb4SMaciej W. Rozycki if (action != MIPS_BE_FIXUP && address < 0x10000000) 9069c75fb4SMaciej W. Rozycki printk(KERN_ALERT " Byte lane status %#3x -- " 9169c75fb4SMaciej W. Rozycki "#3: %s, #2: %s, #1: %s, #0: %s\n", 9269c75fb4SMaciej W. Rozycki (mer & KN02XA_MER_BYTERR) >> 8, 9369c75fb4SMaciej W. Rozycki lanestat[(mer & KN02XA_MER_BYTERR_3) != 0], 9469c75fb4SMaciej W. Rozycki lanestat[(mer & KN02XA_MER_BYTERR_2) != 0], 9569c75fb4SMaciej W. Rozycki lanestat[(mer & KN02XA_MER_BYTERR_1) != 0], 9669c75fb4SMaciej W. Rozycki lanestat[(mer & KN02XA_MER_BYTERR_0) != 0]); 9769c75fb4SMaciej W. Rozycki 9869c75fb4SMaciej W. Rozycki return action; 9969c75fb4SMaciej W. Rozycki } 10069c75fb4SMaciej W. Rozycki 10169c75fb4SMaciej W. Rozycki int dec_kn02xa_be_handler(struct pt_regs *regs, int is_fixup) 10269c75fb4SMaciej W. Rozycki { 10369c75fb4SMaciej W. Rozycki return dec_kn02xa_be_backend(regs, is_fixup, 0); 10469c75fb4SMaciej W. Rozycki } 10569c75fb4SMaciej W. Rozycki 10669c75fb4SMaciej W. Rozycki irqreturn_t dec_kn02xa_be_interrupt(int irq, void *dev_id, 10769c75fb4SMaciej W. Rozycki struct pt_regs *regs) 10869c75fb4SMaciej W. Rozycki { 10969c75fb4SMaciej W. Rozycki int action = dec_kn02xa_be_backend(regs, 0, 1); 11069c75fb4SMaciej W. Rozycki 11169c75fb4SMaciej W. Rozycki if (action == MIPS_BE_DISCARD) 11269c75fb4SMaciej W. Rozycki return IRQ_HANDLED; 11369c75fb4SMaciej W. Rozycki 11469c75fb4SMaciej W. Rozycki /* 11569c75fb4SMaciej W. Rozycki * FIXME: Find the affected processes and kill them, otherwise 11669c75fb4SMaciej W. Rozycki * we must die. 11769c75fb4SMaciej W. Rozycki * 11869c75fb4SMaciej W. Rozycki * The interrupt is asynchronously delivered thus EPC and RA 11969c75fb4SMaciej W. Rozycki * may be irrelevant, but are printed for a reference. 12069c75fb4SMaciej W. Rozycki */ 12169c75fb4SMaciej W. Rozycki printk(KERN_ALERT "Fatal bus interrupt, epc == %08lx, ra == %08lx\n", 12269c75fb4SMaciej W. Rozycki regs->cp0_epc, regs->regs[31]); 12369c75fb4SMaciej W. Rozycki die("Unrecoverable bus error", regs); 12469c75fb4SMaciej W. Rozycki } 12569c75fb4SMaciej W. Rozycki 12669c75fb4SMaciej W. Rozycki 12769c75fb4SMaciej W. Rozycki void __init dec_kn02xa_be_init(void) 12869c75fb4SMaciej W. Rozycki { 12969c75fb4SMaciej W. Rozycki volatile u32 *mbcs = (void *)(KN4K_SLOT_BASE + KN4K_MB_CSR); 13069c75fb4SMaciej W. Rozycki 13169c75fb4SMaciej W. Rozycki /* For KN04 we need to make sure EE (?) is enabled in the MB. */ 13269c75fb4SMaciej W. Rozycki if (current_cpu_data.cputype == CPU_R4000SC) 13369c75fb4SMaciej W. Rozycki *mbcs |= KN4K_MB_CSR_EE; 13469c75fb4SMaciej W. Rozycki fast_iob(); 13569c75fb4SMaciej W. Rozycki 13669c75fb4SMaciej W. Rozycki /* Clear any leftover errors from the firmware. */ 13769c75fb4SMaciej W. Rozycki dec_kn02xa_be_ack(); 13869c75fb4SMaciej W. Rozycki } 139