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) 2001, 2003 Keith M Wesolowski
78c2ecf20Sopenharmony_ci * Copyright (C) 2005 Ilya A. Volynets <ilya@total-knowledge.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#include <linux/types.h>
108c2ecf20Sopenharmony_ci#include <linux/init.h>
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <linux/export.h>
148c2ecf20Sopenharmony_ci#include <asm/bootinfo.h>
158c2ecf20Sopenharmony_ci#include <asm/io.h>
168c2ecf20Sopenharmony_ci#include <asm/mipsregs.h>
178c2ecf20Sopenharmony_ci#include <asm/page.h>
188c2ecf20Sopenharmony_ci#include <asm/ip32/crime.h>
198c2ecf20Sopenharmony_ci#include <asm/ip32/mace.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistruct sgi_crime __iomem *crime;
228c2ecf20Sopenharmony_cistruct sgi_mace __iomem *mace;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mace);
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_civoid __init crime_init(void)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	unsigned int id, rev;
298c2ecf20Sopenharmony_ci	const int field = 2 * sizeof(unsigned long);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	set_io_port_base((unsigned long) ioremap(MACEPCI_LOW_IO, 0x2000000));
328c2ecf20Sopenharmony_ci	crime = ioremap(CRIME_BASE, sizeof(struct sgi_crime));
338c2ecf20Sopenharmony_ci	mace = ioremap(MACE_BASE, sizeof(struct sgi_mace));
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	id = crime->id;
368c2ecf20Sopenharmony_ci	rev = id & CRIME_ID_REV;
378c2ecf20Sopenharmony_ci	id = (id & CRIME_ID_IDBITS) >> 4;
388c2ecf20Sopenharmony_ci	printk(KERN_INFO "CRIME id %1x rev %d at 0x%0*lx\n",
398c2ecf20Sopenharmony_ci	       id, rev, field, (unsigned long) CRIME_BASE);
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ciirqreturn_t crime_memerr_intr(unsigned int irq, void *dev_id)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	unsigned long stat, addr;
458c2ecf20Sopenharmony_ci	int fatal = 0;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	stat = crime->mem_error_stat & CRIME_MEM_ERROR_STAT_MASK;
488c2ecf20Sopenharmony_ci	addr = crime->mem_error_addr & CRIME_MEM_ERROR_ADDR_MASK;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	printk("CRIME memory error at 0x%08lx ST 0x%08lx<", addr, stat);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_INV)
538c2ecf20Sopenharmony_ci		printk("INV,");
548c2ecf20Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_ECC) {
558c2ecf20Sopenharmony_ci		unsigned long ecc_syn =
568c2ecf20Sopenharmony_ci			crime->mem_ecc_syn & CRIME_MEM_ERROR_ECC_SYN_MASK;
578c2ecf20Sopenharmony_ci		unsigned long ecc_gen =
588c2ecf20Sopenharmony_ci			crime->mem_ecc_chk & CRIME_MEM_ERROR_ECC_CHK_MASK;
598c2ecf20Sopenharmony_ci		printk("ECC,SYN=0x%08lx,GEN=0x%08lx,", ecc_syn, ecc_gen);
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_MULTIPLE) {
628c2ecf20Sopenharmony_ci		fatal = 1;
638c2ecf20Sopenharmony_ci		printk("MULTIPLE,");
648c2ecf20Sopenharmony_ci	}
658c2ecf20Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_HARD_ERR) {
668c2ecf20Sopenharmony_ci		fatal = 1;
678c2ecf20Sopenharmony_ci		printk("HARD,");
688c2ecf20Sopenharmony_ci	}
698c2ecf20Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_SOFT_ERR)
708c2ecf20Sopenharmony_ci		printk("SOFT,");
718c2ecf20Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_CPU_ACCESS)
728c2ecf20Sopenharmony_ci		printk("CPU,");
738c2ecf20Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_VICE_ACCESS)
748c2ecf20Sopenharmony_ci		printk("VICE,");
758c2ecf20Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_GBE_ACCESS)
768c2ecf20Sopenharmony_ci		printk("GBE,");
778c2ecf20Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_RE_ACCESS)
788c2ecf20Sopenharmony_ci		printk("RE,REID=0x%02lx,", (stat & CRIME_MEM_ERROR_RE_ID)>>8);
798c2ecf20Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_MACE_ACCESS)
808c2ecf20Sopenharmony_ci		printk("MACE,MACEID=0x%02lx,", stat & CRIME_MEM_ERROR_MACE_ID);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	crime->mem_error_stat = 0;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	if (fatal) {
858c2ecf20Sopenharmony_ci		printk("FATAL>\n");
868c2ecf20Sopenharmony_ci		panic("Fatal memory error.");
878c2ecf20Sopenharmony_ci	} else
888c2ecf20Sopenharmony_ci		printk("NONFATAL>\n");
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ciirqreturn_t crime_cpuerr_intr(unsigned int irq, void *dev_id)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	unsigned long stat = crime->cpu_error_stat & CRIME_CPU_ERROR_MASK;
968c2ecf20Sopenharmony_ci	unsigned long addr = crime->cpu_error_addr & CRIME_CPU_ERROR_ADDR_MASK;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	addr <<= 2;
998c2ecf20Sopenharmony_ci	printk("CRIME CPU error at 0x%09lx status 0x%08lx\n", addr, stat);
1008c2ecf20Sopenharmony_ci	crime->cpu_error_stat = 0;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1038c2ecf20Sopenharmony_ci}
104