162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
362306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
462306a36Sopenharmony_ci * for more details.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2001, 2003 Keith M Wesolowski
762306a36Sopenharmony_ci * Copyright (C) 2005 Ilya A. Volynets <ilya@total-knowledge.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#include <linux/types.h>
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <linux/export.h>
1462306a36Sopenharmony_ci#include <asm/bootinfo.h>
1562306a36Sopenharmony_ci#include <asm/io.h>
1662306a36Sopenharmony_ci#include <asm/mipsregs.h>
1762306a36Sopenharmony_ci#include <asm/page.h>
1862306a36Sopenharmony_ci#include <asm/ip32/crime.h>
1962306a36Sopenharmony_ci#include <asm/ip32/mace.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistruct sgi_crime __iomem *crime;
2262306a36Sopenharmony_cistruct sgi_mace __iomem *mace;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mace);
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_civoid __init crime_init(void)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	unsigned int id, rev;
2962306a36Sopenharmony_ci	const int field = 2 * sizeof(unsigned long);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	set_io_port_base((unsigned long) ioremap(MACEPCI_LOW_IO, 0x2000000));
3262306a36Sopenharmony_ci	crime = ioremap(CRIME_BASE, sizeof(struct sgi_crime));
3362306a36Sopenharmony_ci	mace = ioremap(MACE_BASE, sizeof(struct sgi_mace));
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	id = crime->id;
3662306a36Sopenharmony_ci	rev = id & CRIME_ID_REV;
3762306a36Sopenharmony_ci	id = (id & CRIME_ID_IDBITS) >> 4;
3862306a36Sopenharmony_ci	printk(KERN_INFO "CRIME id %1x rev %d at 0x%0*lx\n",
3962306a36Sopenharmony_ci	       id, rev, field, (unsigned long) CRIME_BASE);
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ciirqreturn_t crime_memerr_intr(unsigned int irq, void *dev_id)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	unsigned long stat, addr;
4562306a36Sopenharmony_ci	int fatal = 0;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	stat = crime->mem_error_stat & CRIME_MEM_ERROR_STAT_MASK;
4862306a36Sopenharmony_ci	addr = crime->mem_error_addr & CRIME_MEM_ERROR_ADDR_MASK;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	printk("CRIME memory error at 0x%08lx ST 0x%08lx<", addr, stat);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_INV)
5362306a36Sopenharmony_ci		printk("INV,");
5462306a36Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_ECC) {
5562306a36Sopenharmony_ci		unsigned long ecc_syn =
5662306a36Sopenharmony_ci			crime->mem_ecc_syn & CRIME_MEM_ERROR_ECC_SYN_MASK;
5762306a36Sopenharmony_ci		unsigned long ecc_gen =
5862306a36Sopenharmony_ci			crime->mem_ecc_chk & CRIME_MEM_ERROR_ECC_CHK_MASK;
5962306a36Sopenharmony_ci		printk("ECC,SYN=0x%08lx,GEN=0x%08lx,", ecc_syn, ecc_gen);
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_MULTIPLE) {
6262306a36Sopenharmony_ci		fatal = 1;
6362306a36Sopenharmony_ci		printk("MULTIPLE,");
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_HARD_ERR) {
6662306a36Sopenharmony_ci		fatal = 1;
6762306a36Sopenharmony_ci		printk("HARD,");
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_SOFT_ERR)
7062306a36Sopenharmony_ci		printk("SOFT,");
7162306a36Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_CPU_ACCESS)
7262306a36Sopenharmony_ci		printk("CPU,");
7362306a36Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_VICE_ACCESS)
7462306a36Sopenharmony_ci		printk("VICE,");
7562306a36Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_GBE_ACCESS)
7662306a36Sopenharmony_ci		printk("GBE,");
7762306a36Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_RE_ACCESS)
7862306a36Sopenharmony_ci		printk("RE,REID=0x%02lx,", (stat & CRIME_MEM_ERROR_RE_ID)>>8);
7962306a36Sopenharmony_ci	if (stat & CRIME_MEM_ERROR_MACE_ACCESS)
8062306a36Sopenharmony_ci		printk("MACE,MACEID=0x%02lx,", stat & CRIME_MEM_ERROR_MACE_ID);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	crime->mem_error_stat = 0;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if (fatal) {
8562306a36Sopenharmony_ci		printk("FATAL>\n");
8662306a36Sopenharmony_ci		panic("Fatal memory error.");
8762306a36Sopenharmony_ci	} else
8862306a36Sopenharmony_ci		printk("NONFATAL>\n");
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return IRQ_HANDLED;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ciirqreturn_t crime_cpuerr_intr(unsigned int irq, void *dev_id)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	unsigned long stat = crime->cpu_error_stat & CRIME_CPU_ERROR_MASK;
9662306a36Sopenharmony_ci	unsigned long addr = crime->cpu_error_addr & CRIME_CPU_ERROR_ADDR_MASK;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	addr <<= 2;
9962306a36Sopenharmony_ci	printk("CRIME CPU error at 0x%09lx status 0x%08lx\n", addr, stat);
10062306a36Sopenharmony_ci	crime->cpu_error_stat = 0;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	return IRQ_HANDLED;
10362306a36Sopenharmony_ci}
104