diff options
author | Thomas Bogendoerfer <tsbogend@alpha.franken.de> | 2007-12-02 07:00:32 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2008-01-29 05:14:58 -0500 |
commit | e2defae5a9b4f8d1acb058be212ef89c8763dc5b (patch) | |
tree | 3a0e72b5df8ee181e6c30fb6d1cba636c460a9fd /arch/mips | |
parent | 81149be11327cbad006f82318f46e0b68a7b14ad (diff) |
[MIPS] IP28 support
Add support for SGI IP28 machines (Indigo 2 with R10k CPUs)
This work is mainly based on Peter Fuersts work.
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/Kconfig | 67 | ||||
-rw-r--r-- | arch/mips/Makefile | 14 | ||||
-rw-r--r-- | arch/mips/sgi-ip22/Makefile | 8 | ||||
-rw-r--r-- | arch/mips/sgi-ip22/ip22-mc.c | 4 | ||||
-rw-r--r-- | arch/mips/sgi-ip22/ip28-berr.c | 502 |
5 files changed, 589 insertions, 6 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 00d6940d4ed7..01740ef77824 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
@@ -127,6 +127,7 @@ config MACH_JAZZ | |||
127 | select ARCH_MAY_HAVE_PC_FDC | 127 | select ARCH_MAY_HAVE_PC_FDC |
128 | select CEVT_R4K | 128 | select CEVT_R4K |
129 | select CSRC_R4K | 129 | select CSRC_R4K |
130 | select DEFAULT_SGI_PARTITION if CPU_BIG_ENDIAN | ||
130 | select GENERIC_ISA_DMA | 131 | select GENERIC_ISA_DMA |
131 | select IRQ_CPU | 132 | select IRQ_CPU |
132 | select I8253 | 133 | select I8253 |
@@ -401,6 +402,7 @@ config SGI_IP22 | |||
401 | select BOOT_ELF32 | 402 | select BOOT_ELF32 |
402 | select CEVT_R4K | 403 | select CEVT_R4K |
403 | select CSRC_R4K | 404 | select CSRC_R4K |
405 | select DEFAULT_SGI_PARTITION | ||
404 | select DMA_NONCOHERENT | 406 | select DMA_NONCOHERENT |
405 | select HW_HAS_EISA | 407 | select HW_HAS_EISA |
406 | select I8253 | 408 | select I8253 |
@@ -408,6 +410,12 @@ config SGI_IP22 | |||
408 | select IP22_CPU_SCACHE | 410 | select IP22_CPU_SCACHE |
409 | select IRQ_CPU | 411 | select IRQ_CPU |
410 | select GENERIC_ISA_DMA_SUPPORT_BROKEN | 412 | select GENERIC_ISA_DMA_SUPPORT_BROKEN |
413 | select SGI_HAS_DS1286 | ||
414 | select SGI_HAS_I8042 | ||
415 | select SGI_HAS_INDYDOG | ||
416 | select SGI_HAS_SEEQ | ||
417 | select SGI_HAS_WD93 | ||
418 | select SGI_HAS_ZILOG | ||
411 | select SWAP_IO_SPACE | 419 | select SWAP_IO_SPACE |
412 | select SYS_HAS_CPU_R4X00 | 420 | select SYS_HAS_CPU_R4X00 |
413 | select SYS_HAS_CPU_R5000 | 421 | select SYS_HAS_CPU_R5000 |
@@ -425,6 +433,7 @@ config SGI_IP27 | |||
425 | select ARC | 433 | select ARC |
426 | select ARC64 | 434 | select ARC64 |
427 | select BOOT_ELF64 | 435 | select BOOT_ELF64 |
436 | select DEFAULT_SGI_PARTITION | ||
428 | select DMA_IP27 | 437 | select DMA_IP27 |
429 | select SYS_HAS_EARLY_PRINTK | 438 | select SYS_HAS_EARLY_PRINTK |
430 | select HW_HAS_PCI | 439 | select HW_HAS_PCI |
@@ -441,6 +450,36 @@ config SGI_IP27 | |||
441 | workstations. To compile a Linux kernel that runs on these, say Y | 450 | workstations. To compile a Linux kernel that runs on these, say Y |
442 | here. | 451 | here. |
443 | 452 | ||
453 | config SGI_IP28 | ||
454 | bool "SGI IP28 (Indigo2 R10k) (EXPERIMENTAL)" | ||
455 | depends on EXPERIMENTAL | ||
456 | select ARC | ||
457 | select ARC64 | ||
458 | select BOOT_ELF64 | ||
459 | select CEVT_R4K | ||
460 | select CSRC_R4K | ||
461 | select DEFAULT_SGI_PARTITION | ||
462 | select DMA_NONCOHERENT | ||
463 | select GENERIC_ISA_DMA_SUPPORT_BROKEN | ||
464 | select IRQ_CPU | ||
465 | select HW_HAS_EISA | ||
466 | select I8253 | ||
467 | select I8259 | ||
468 | select SGI_HAS_DS1286 | ||
469 | select SGI_HAS_I8042 | ||
470 | select SGI_HAS_INDYDOG | ||
471 | select SGI_HAS_SEEQ | ||
472 | select SGI_HAS_WD93 | ||
473 | select SGI_HAS_ZILOG | ||
474 | select SWAP_IO_SPACE | ||
475 | select SYS_HAS_CPU_R10000 | ||
476 | select SYS_HAS_EARLY_PRINTK | ||
477 | select SYS_SUPPORTS_64BIT_KERNEL | ||
478 | select SYS_SUPPORTS_BIG_ENDIAN | ||
479 | help | ||
480 | This is the SGI Indigo2 with R10000 processor. To compile a Linux | ||
481 | kernel that runs on these, say Y here. | ||
482 | |||
444 | config SGI_IP32 | 483 | config SGI_IP32 |
445 | bool "SGI IP32 (O2)" | 484 | bool "SGI IP32 (O2)" |
446 | select ARC | 485 | select ARC |
@@ -567,6 +606,7 @@ config SNI_RM | |||
567 | select BOOT_ELF32 | 606 | select BOOT_ELF32 |
568 | select CEVT_R4K | 607 | select CEVT_R4K |
569 | select CSRC_R4K | 608 | select CSRC_R4K |
609 | select DEFAULT_SGI_PARTITION if CPU_BIG_ENDIAN | ||
570 | select DMA_NONCOHERENT | 610 | select DMA_NONCOHERENT |
571 | select GENERIC_ISA_DMA | 611 | select GENERIC_ISA_DMA |
572 | select HW_HAS_EISA | 612 | select HW_HAS_EISA |
@@ -939,6 +979,27 @@ config EMMA2RH | |||
939 | config SERIAL_RM9000 | 979 | config SERIAL_RM9000 |
940 | bool | 980 | bool |
941 | 981 | ||
982 | config SGI_HAS_DS1286 | ||
983 | bool | ||
984 | |||
985 | config SGI_HAS_INDYDOG | ||
986 | bool | ||
987 | |||
988 | config SGI_HAS_SEEQ | ||
989 | bool | ||
990 | |||
991 | config SGI_HAS_WD93 | ||
992 | bool | ||
993 | |||
994 | config SGI_HAS_ZILOG | ||
995 | bool | ||
996 | |||
997 | config SGI_HAS_I8042 | ||
998 | bool | ||
999 | |||
1000 | config DEFAULT_SGI_PARTITION | ||
1001 | bool | ||
1002 | |||
942 | config ARC32 | 1003 | config ARC32 |
943 | bool | 1004 | bool |
944 | 1005 | ||
@@ -948,7 +1009,7 @@ config BOOT_ELF32 | |||
948 | config MIPS_L1_CACHE_SHIFT | 1009 | config MIPS_L1_CACHE_SHIFT |
949 | int | 1010 | int |
950 | default "4" if MACH_DECSTATION | 1011 | default "4" if MACH_DECSTATION |
951 | default "7" if SGI_IP27 || SNI_RM | 1012 | default "7" if SGI_IP27 || SGI_IP28 || SNI_RM |
952 | default "4" if PMC_MSP4200_EVAL | 1013 | default "4" if PMC_MSP4200_EVAL |
953 | default "5" | 1014 | default "5" |
954 | 1015 | ||
@@ -957,7 +1018,7 @@ config HAVE_STD_PC_SERIAL_PORT | |||
957 | 1018 | ||
958 | config ARC_CONSOLE | 1019 | config ARC_CONSOLE |
959 | bool "ARC console support" | 1020 | bool "ARC console support" |
960 | depends on SGI_IP22 || (SNI_RM && CPU_LITTLE_ENDIAN) | 1021 | depends on SGI_IP22 || SGI_IP28 || (SNI_RM && CPU_LITTLE_ENDIAN) |
961 | 1022 | ||
962 | config ARC_MEMORY | 1023 | config ARC_MEMORY |
963 | bool | 1024 | bool |
@@ -966,7 +1027,7 @@ config ARC_MEMORY | |||
966 | 1027 | ||
967 | config ARC_PROMLIB | 1028 | config ARC_PROMLIB |
968 | bool | 1029 | bool |
969 | depends on MACH_JAZZ || SNI_RM || SGI_IP22 || SGI_IP32 | 1030 | depends on MACH_JAZZ || SNI_RM || SGI_IP22 || SGI_IP28 || SGI_IP32 |
970 | default y | 1031 | default y |
971 | 1032 | ||
972 | config ARC64 | 1033 | config ARC64 |
diff --git a/arch/mips/Makefile b/arch/mips/Makefile index a49127af33c8..dd668f3a8394 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile | |||
@@ -479,6 +479,20 @@ endif | |||
479 | endif | 479 | endif |
480 | 480 | ||
481 | # | 481 | # |
482 | # SGI IP28 (Indigo2 R10k) | ||
483 | # | ||
484 | # Set the load address to >= 0xa800000020080000 if you want to leave space for | ||
485 | # symmon, 0xa800000020004000 for production kernels ? Note that the value must | ||
486 | # be 16kb aligned or the handling of the current variable will break. | ||
487 | # Simplified: what IP22 does at 128MB+ in ksegN, IP28 does at 512MB+ in xkphys | ||
488 | # | ||
489 | #core-$(CONFIG_SGI_IP28) += arch/mips/sgi-ip22/ arch/mips/arc/arc_con.o | ||
490 | core-$(CONFIG_SGI_IP28) += arch/mips/sgi-ip22/ | ||
491 | cflags-$(CONFIG_SGI_IP28) += -mr10k-cache-barrier=1 -Iinclude/asm-mips/mach-ip28 | ||
492 | #cflags-$(CONFIG_SGI_IP28) += -Iinclude/asm-mips/mach-ip28 | ||
493 | load-$(CONFIG_SGI_IP28) += 0xa800000020004000 | ||
494 | |||
495 | # | ||
482 | # SGI-IP32 (O2) | 496 | # SGI-IP32 (O2) |
483 | # | 497 | # |
484 | # Set the load address to >= 80069000 if you want to leave space for symmon, | 498 | # Set the load address to >= 80069000 if you want to leave space for symmon, |
diff --git a/arch/mips/sgi-ip22/Makefile b/arch/mips/sgi-ip22/Makefile index e3acb51b70b5..ef1564e40c8d 100644 --- a/arch/mips/sgi-ip22/Makefile +++ b/arch/mips/sgi-ip22/Makefile | |||
@@ -3,9 +3,11 @@ | |||
3 | # under Linux. | 3 | # under Linux. |
4 | # | 4 | # |
5 | 5 | ||
6 | obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-berr.o \ | 6 | obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-time.o ip22-nvram.o \ |
7 | ip22-time.o ip22-nvram.o ip22-platform.o ip22-reset.o ip22-setup.o | 7 | ip22-platform.o ip22-reset.o ip22-setup.o |
8 | 8 | ||
9 | obj-$(CONFIG_SGI_IP22) += ip22-berr.o | ||
10 | obj-$(CONFIG_SGI_IP28) += ip28-berr.o | ||
9 | obj-$(CONFIG_EISA) += ip22-eisa.o | 11 | obj-$(CONFIG_EISA) += ip22-eisa.o |
10 | 12 | ||
11 | EXTRA_CFLAGS += -Werror | 13 | # EXTRA_CFLAGS += -Werror |
diff --git a/arch/mips/sgi-ip22/ip22-mc.c b/arch/mips/sgi-ip22/ip22-mc.c index 01a805dcc67c..3f35d6367bec 100644 --- a/arch/mips/sgi-ip22/ip22-mc.c +++ b/arch/mips/sgi-ip22/ip22-mc.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) | 4 | * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) |
5 | * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes | 5 | * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes |
6 | * Copyright (C) 2003 Ladislav Michl (ladis@linux-mips.org) | 6 | * Copyright (C) 2003 Ladislav Michl (ladis@linux-mips.org) |
7 | * Copyright (C) 2004 Peter Fuerst (pf@net.alphadv.de) - IP28 | ||
7 | */ | 8 | */ |
8 | 9 | ||
9 | #include <linux/init.h> | 10 | #include <linux/init.h> |
@@ -137,9 +138,12 @@ void __init sgimc_init(void) | |||
137 | /* Step 2: Enable all parity checking in cpu control register | 138 | /* Step 2: Enable all parity checking in cpu control register |
138 | * zero. | 139 | * zero. |
139 | */ | 140 | */ |
141 | /* don't touch parity settings for IP28 */ | ||
142 | #ifndef CONFIG_SGI_IP28 | ||
140 | tmp = sgimc->cpuctrl0; | 143 | tmp = sgimc->cpuctrl0; |
141 | tmp |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM | | 144 | tmp |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM | |
142 | SGIMC_CCTRL0_R4KNOCHKPARR); | 145 | SGIMC_CCTRL0_R4KNOCHKPARR); |
146 | #endif | ||
143 | sgimc->cpuctrl0 = tmp; | 147 | sgimc->cpuctrl0 = tmp; |
144 | 148 | ||
145 | /* Step 3: Setup the MC write buffer depth, this is controlled | 149 | /* Step 3: Setup the MC write buffer depth, this is controlled |
diff --git a/arch/mips/sgi-ip22/ip28-berr.c b/arch/mips/sgi-ip22/ip28-berr.c new file mode 100644 index 000000000000..30e12e2ec4b5 --- /dev/null +++ b/arch/mips/sgi-ip22/ip28-berr.c | |||
@@ -0,0 +1,502 @@ | |||
1 | /* | ||
2 | * ip28-berr.c: Bus error handling. | ||
3 | * | ||
4 | * Copyright (C) 2002, 2003 Ladislav Michl (ladis@linux-mips.org) | ||
5 | * Copyright (C) 2005 Peter Fuerst (pf@net.alphadv.de) - IP28 | ||
6 | */ | ||
7 | |||
8 | #include <linux/init.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/sched.h> | ||
11 | #include <linux/seq_file.h> | ||
12 | |||
13 | #include <asm/addrspace.h> | ||
14 | #include <asm/system.h> | ||
15 | #include <asm/traps.h> | ||
16 | #include <asm/branch.h> | ||
17 | #include <asm/irq_regs.h> | ||
18 | #include <asm/sgi/mc.h> | ||
19 | #include <asm/sgi/hpc3.h> | ||
20 | #include <asm/sgi/ioc.h> | ||
21 | #include <asm/sgi/ip22.h> | ||
22 | #include <asm/r4kcache.h> | ||
23 | #include <asm/uaccess.h> | ||
24 | #include <asm/bootinfo.h> | ||
25 | |||
26 | static unsigned int count_be_is_fixup; | ||
27 | static unsigned int count_be_handler; | ||
28 | static unsigned int count_be_interrupt; | ||
29 | static int debug_be_interrupt; | ||
30 | |||
31 | static unsigned int cpu_err_stat; /* Status reg for CPU */ | ||
32 | static unsigned int gio_err_stat; /* Status reg for GIO */ | ||
33 | static unsigned int cpu_err_addr; /* Error address reg for CPU */ | ||
34 | static unsigned int gio_err_addr; /* Error address reg for GIO */ | ||
35 | static unsigned int extio_stat; | ||
36 | static unsigned int hpc3_berr_stat; /* Bus error interrupt status */ | ||
37 | |||
38 | struct hpc3_stat { | ||
39 | unsigned long addr; | ||
40 | unsigned int ctrl; | ||
41 | unsigned int cbp; | ||
42 | unsigned int ndptr; | ||
43 | }; | ||
44 | |||
45 | static struct { | ||
46 | struct hpc3_stat pbdma[8]; | ||
47 | struct hpc3_stat scsi[2]; | ||
48 | struct hpc3_stat ethrx, ethtx; | ||
49 | } hpc3; | ||
50 | |||
51 | static struct { | ||
52 | unsigned long err_addr; | ||
53 | struct { | ||
54 | u32 lo; | ||
55 | u32 hi; | ||
56 | } tags[1][2], tagd[4][2], tagi[4][2]; /* Way 0/1 */ | ||
57 | } cache_tags; | ||
58 | |||
59 | static inline void save_cache_tags(unsigned busaddr) | ||
60 | { | ||
61 | unsigned long addr = CAC_BASE | busaddr; | ||
62 | int i; | ||
63 | cache_tags.err_addr = addr; | ||
64 | |||
65 | /* | ||
66 | * Starting with a bus-address, save secondary cache (indexed by | ||
67 | * PA[23..18:7..6]) tags first. | ||
68 | */ | ||
69 | addr &= ~1L; | ||
70 | #define tag cache_tags.tags[0] | ||
71 | cache_op(Index_Load_Tag_S, addr); | ||
72 | tag[0].lo = read_c0_taglo(); /* PA[35:18], VA[13:12] */ | ||
73 | tag[0].hi = read_c0_taghi(); /* PA[39:36] */ | ||
74 | cache_op(Index_Load_Tag_S, addr | 1L); | ||
75 | tag[1].lo = read_c0_taglo(); /* PA[35:18], VA[13:12] */ | ||
76 | tag[1].hi = read_c0_taghi(); /* PA[39:36] */ | ||
77 | #undef tag | ||
78 | |||
79 | /* | ||
80 | * Save all primary data cache (indexed by VA[13:5]) tags which | ||
81 | * might fit to this bus-address, knowing that VA[11:0] == PA[11:0]. | ||
82 | * Saving all tags and evaluating them later is easier and safer | ||
83 | * than relying on VA[13:12] from the secondary cache tags to pick | ||
84 | * matching primary tags here already. | ||
85 | */ | ||
86 | addr &= (0xffL << 56) | ((1 << 12) - 1); | ||
87 | #define tag cache_tags.tagd[i] | ||
88 | for (i = 0; i < 4; ++i, addr += (1 << 12)) { | ||
89 | cache_op(Index_Load_Tag_D, addr); | ||
90 | tag[0].lo = read_c0_taglo(); /* PA[35:12] */ | ||
91 | tag[0].hi = read_c0_taghi(); /* PA[39:36] */ | ||
92 | cache_op(Index_Load_Tag_D, addr | 1L); | ||
93 | tag[1].lo = read_c0_taglo(); /* PA[35:12] */ | ||
94 | tag[1].hi = read_c0_taghi(); /* PA[39:36] */ | ||
95 | } | ||
96 | #undef tag | ||
97 | |||
98 | /* | ||
99 | * Save primary instruction cache (indexed by VA[13:6]) tags | ||
100 | * the same way. | ||
101 | */ | ||
102 | addr &= (0xffL << 56) | ((1 << 12) - 1); | ||
103 | #define tag cache_tags.tagi[i] | ||
104 | for (i = 0; i < 4; ++i, addr += (1 << 12)) { | ||
105 | cache_op(Index_Load_Tag_I, addr); | ||
106 | tag[0].lo = read_c0_taglo(); /* PA[35:12] */ | ||
107 | tag[0].hi = read_c0_taghi(); /* PA[39:36] */ | ||
108 | cache_op(Index_Load_Tag_I, addr | 1L); | ||
109 | tag[1].lo = read_c0_taglo(); /* PA[35:12] */ | ||
110 | tag[1].hi = read_c0_taghi(); /* PA[39:36] */ | ||
111 | } | ||
112 | #undef tag | ||
113 | } | ||
114 | |||
115 | #define GIO_ERRMASK 0xff00 | ||
116 | #define CPU_ERRMASK 0x3f00 | ||
117 | |||
118 | static void save_and_clear_buserr(void) | ||
119 | { | ||
120 | int i; | ||
121 | |||
122 | /* save status registers */ | ||
123 | cpu_err_addr = sgimc->cerr; | ||
124 | cpu_err_stat = sgimc->cstat; | ||
125 | gio_err_addr = sgimc->gerr; | ||
126 | gio_err_stat = sgimc->gstat; | ||
127 | extio_stat = sgioc->extio; | ||
128 | hpc3_berr_stat = hpc3c0->bestat; | ||
129 | |||
130 | hpc3.scsi[0].addr = (unsigned long)&hpc3c0->scsi_chan0; | ||
131 | hpc3.scsi[0].ctrl = hpc3c0->scsi_chan0.ctrl; /* HPC3_SCTRL_ACTIVE ? */ | ||
132 | hpc3.scsi[0].cbp = hpc3c0->scsi_chan0.cbptr; | ||
133 | hpc3.scsi[0].ndptr = hpc3c0->scsi_chan0.ndptr; | ||
134 | |||
135 | hpc3.scsi[1].addr = (unsigned long)&hpc3c0->scsi_chan1; | ||
136 | hpc3.scsi[1].ctrl = hpc3c0->scsi_chan1.ctrl; /* HPC3_SCTRL_ACTIVE ? */ | ||
137 | hpc3.scsi[1].cbp = hpc3c0->scsi_chan1.cbptr; | ||
138 | hpc3.scsi[1].ndptr = hpc3c0->scsi_chan1.ndptr; | ||
139 | |||
140 | hpc3.ethrx.addr = (unsigned long)&hpc3c0->ethregs.rx_cbptr; | ||
141 | hpc3.ethrx.ctrl = hpc3c0->ethregs.rx_ctrl; /* HPC3_ERXCTRL_ACTIVE ? */ | ||
142 | hpc3.ethrx.cbp = hpc3c0->ethregs.rx_cbptr; | ||
143 | hpc3.ethrx.ndptr = hpc3c0->ethregs.rx_ndptr; | ||
144 | |||
145 | hpc3.ethtx.addr = (unsigned long)&hpc3c0->ethregs.tx_cbptr; | ||
146 | hpc3.ethtx.ctrl = hpc3c0->ethregs.tx_ctrl; /* HPC3_ETXCTRL_ACTIVE ? */ | ||
147 | hpc3.ethtx.cbp = hpc3c0->ethregs.tx_cbptr; | ||
148 | hpc3.ethtx.ndptr = hpc3c0->ethregs.tx_ndptr; | ||
149 | |||
150 | for (i = 0; i < 8; ++i) { | ||
151 | /* HPC3_PDMACTRL_ISACT ? */ | ||
152 | hpc3.pbdma[i].addr = (unsigned long)&hpc3c0->pbdma[i]; | ||
153 | hpc3.pbdma[i].ctrl = hpc3c0->pbdma[i].pbdma_ctrl; | ||
154 | hpc3.pbdma[i].cbp = hpc3c0->pbdma[i].pbdma_bptr; | ||
155 | hpc3.pbdma[i].ndptr = hpc3c0->pbdma[i].pbdma_dptr; | ||
156 | } | ||
157 | i = 0; | ||
158 | if (gio_err_stat & CPU_ERRMASK) | ||
159 | i = gio_err_addr; | ||
160 | if (cpu_err_stat & CPU_ERRMASK) | ||
161 | i = cpu_err_addr; | ||
162 | save_cache_tags(i); | ||
163 | |||
164 | sgimc->cstat = sgimc->gstat = 0; | ||
165 | } | ||
166 | |||
167 | static void print_cache_tags(void) | ||
168 | { | ||
169 | u32 scb, scw; | ||
170 | int i; | ||
171 | |||
172 | printk(KERN_ERR "Cache tags @ %08x:\n", (unsigned)cache_tags.err_addr); | ||
173 | |||
174 | /* PA[31:12] shifted to PTag0 (PA[35:12]) format */ | ||
175 | scw = (cache_tags.err_addr >> 4) & 0x0fffff00; | ||
176 | |||
177 | scb = cache_tags.err_addr & ((1 << 12) - 1) & ~((1 << 5) - 1); | ||
178 | for (i = 0; i < 4; ++i) { /* for each possible VA[13:12] value */ | ||
179 | if ((cache_tags.tagd[i][0].lo & 0x0fffff00) != scw && | ||
180 | (cache_tags.tagd[i][1].lo & 0x0fffff00) != scw) | ||
181 | continue; | ||
182 | printk(KERN_ERR | ||
183 | "D: 0: %08x %08x, 1: %08x %08x (VA[13:5] %04x)\n", | ||
184 | cache_tags.tagd[i][0].hi, cache_tags.tagd[i][0].lo, | ||
185 | cache_tags.tagd[i][1].hi, cache_tags.tagd[i][1].lo, | ||
186 | scb | (1 << 12)*i); | ||
187 | } | ||
188 | scb = cache_tags.err_addr & ((1 << 12) - 1) & ~((1 << 6) - 1); | ||
189 | for (i = 0; i < 4; ++i) { /* for each possible VA[13:12] value */ | ||
190 | if ((cache_tags.tagi[i][0].lo & 0x0fffff00) != scw && | ||
191 | (cache_tags.tagi[i][1].lo & 0x0fffff00) != scw) | ||
192 | continue; | ||
193 | printk(KERN_ERR | ||
194 | "I: 0: %08x %08x, 1: %08x %08x (VA[13:6] %04x)\n", | ||
195 | cache_tags.tagi[i][0].hi, cache_tags.tagi[i][0].lo, | ||
196 | cache_tags.tagi[i][1].hi, cache_tags.tagi[i][1].lo, | ||
197 | scb | (1 << 12)*i); | ||
198 | } | ||
199 | i = read_c0_config(); | ||
200 | scb = i & (1 << 13) ? 7:6; /* scblksize = 2^[7..6] */ | ||
201 | scw = ((i >> 16) & 7) + 19 - 1; /* scwaysize = 2^[24..19] / 2 */ | ||
202 | |||
203 | i = ((1 << scw) - 1) & ~((1 << scb) - 1); | ||
204 | printk(KERN_ERR "S: 0: %08x %08x, 1: %08x %08x (PA[%u:%u] %05x)\n", | ||
205 | cache_tags.tags[0][0].hi, cache_tags.tags[0][0].lo, | ||
206 | cache_tags.tags[0][1].hi, cache_tags.tags[0][1].lo, | ||
207 | scw-1, scb, i & (unsigned)cache_tags.err_addr); | ||
208 | } | ||
209 | |||
210 | static inline const char *cause_excode_text(int cause) | ||
211 | { | ||
212 | static const char *txt[32] = | ||
213 | { "Interrupt", | ||
214 | "TLB modification", | ||
215 | "TLB (load or instruction fetch)", | ||
216 | "TLB (store)", | ||
217 | "Address error (load or instruction fetch)", | ||
218 | "Address error (store)", | ||
219 | "Bus error (instruction fetch)", | ||
220 | "Bus error (data: load or store)", | ||
221 | "Syscall", | ||
222 | "Breakpoint", | ||
223 | "Reserved instruction", | ||
224 | "Coprocessor unusable", | ||
225 | "Arithmetic Overflow", | ||
226 | "Trap", | ||
227 | "14", | ||
228 | "Floating-Point", | ||
229 | "16", "17", "18", "19", "20", "21", "22", | ||
230 | "Watch Hi/Lo", | ||
231 | "24", "25", "26", "27", "28", "29", "30", "31", | ||
232 | }; | ||
233 | return txt[(cause & 0x7c) >> 2]; | ||
234 | } | ||
235 | |||
236 | static void print_buserr(const struct pt_regs *regs) | ||
237 | { | ||
238 | const int field = 2 * sizeof(unsigned long); | ||
239 | int error = 0; | ||
240 | |||
241 | if (extio_stat & EXTIO_MC_BUSERR) { | ||
242 | printk(KERN_ERR "MC Bus Error\n"); | ||
243 | error |= 1; | ||
244 | } | ||
245 | if (extio_stat & EXTIO_HPC3_BUSERR) { | ||
246 | printk(KERN_ERR "HPC3 Bus Error 0x%x:<id=0x%x,%s,lane=0x%x>\n", | ||
247 | hpc3_berr_stat, | ||
248 | (hpc3_berr_stat & HPC3_BESTAT_PIDMASK) >> | ||
249 | HPC3_BESTAT_PIDSHIFT, | ||
250 | (hpc3_berr_stat & HPC3_BESTAT_CTYPE) ? "PIO" : "DMA", | ||
251 | hpc3_berr_stat & HPC3_BESTAT_BLMASK); | ||
252 | error |= 2; | ||
253 | } | ||
254 | if (extio_stat & EXTIO_EISA_BUSERR) { | ||
255 | printk(KERN_ERR "EISA Bus Error\n"); | ||
256 | error |= 4; | ||
257 | } | ||
258 | if (cpu_err_stat & CPU_ERRMASK) { | ||
259 | printk(KERN_ERR "CPU error 0x%x<%s%s%s%s%s%s> @ 0x%08x\n", | ||
260 | cpu_err_stat, | ||
261 | cpu_err_stat & SGIMC_CSTAT_RD ? "RD " : "", | ||
262 | cpu_err_stat & SGIMC_CSTAT_PAR ? "PAR " : "", | ||
263 | cpu_err_stat & SGIMC_CSTAT_ADDR ? "ADDR " : "", | ||
264 | cpu_err_stat & SGIMC_CSTAT_SYSAD_PAR ? "SYSAD " : "", | ||
265 | cpu_err_stat & SGIMC_CSTAT_SYSCMD_PAR ? "SYSCMD " : "", | ||
266 | cpu_err_stat & SGIMC_CSTAT_BAD_DATA ? "BAD_DATA " : "", | ||
267 | cpu_err_addr); | ||
268 | error |= 8; | ||
269 | } | ||
270 | if (gio_err_stat & GIO_ERRMASK) { | ||
271 | printk(KERN_ERR "GIO error 0x%x:<%s%s%s%s%s%s%s%s> @ 0x%08x\n", | ||
272 | gio_err_stat, | ||
273 | gio_err_stat & SGIMC_GSTAT_RD ? "RD " : "", | ||
274 | gio_err_stat & SGIMC_GSTAT_WR ? "WR " : "", | ||
275 | gio_err_stat & SGIMC_GSTAT_TIME ? "TIME " : "", | ||
276 | gio_err_stat & SGIMC_GSTAT_PROM ? "PROM " : "", | ||
277 | gio_err_stat & SGIMC_GSTAT_ADDR ? "ADDR " : "", | ||
278 | gio_err_stat & SGIMC_GSTAT_BC ? "BC " : "", | ||
279 | gio_err_stat & SGIMC_GSTAT_PIO_RD ? "PIO_RD " : "", | ||
280 | gio_err_stat & SGIMC_GSTAT_PIO_WR ? "PIO_WR " : "", | ||
281 | gio_err_addr); | ||
282 | error |= 16; | ||
283 | } | ||
284 | if (!error) | ||
285 | printk(KERN_ERR "MC: Hmm, didn't find any error condition.\n"); | ||
286 | else { | ||
287 | printk(KERN_ERR "CP0: config %08x, " | ||
288 | "MC: cpuctrl0/1: %08x/%05x, giopar: %04x\n" | ||
289 | "MC: cpu/gio_memacc: %08x/%05x, memcfg0/1: %08x/%08x\n", | ||
290 | read_c0_config(), | ||
291 | sgimc->cpuctrl0, sgimc->cpuctrl0, sgimc->giopar, | ||
292 | sgimc->cmacc, sgimc->gmacc, | ||
293 | sgimc->mconfig0, sgimc->mconfig1); | ||
294 | print_cache_tags(); | ||
295 | } | ||
296 | printk(KERN_ALERT "%s, epc == %0*lx, ra == %0*lx\n", | ||
297 | cause_excode_text(regs->cp0_cause), | ||
298 | field, regs->cp0_epc, field, regs->regs[31]); | ||
299 | } | ||
300 | |||
301 | /* | ||
302 | * Check, whether MC's (virtual) DMA address caused the bus error. | ||
303 | * See "Virtual DMA Specification", Draft 1.5, Feb 13 1992, SGI | ||
304 | */ | ||
305 | |||
306 | static int addr_is_ram(unsigned long addr, unsigned sz) | ||
307 | { | ||
308 | int i; | ||
309 | |||
310 | for (i = 0; i < boot_mem_map.nr_map; i++) { | ||
311 | unsigned long a = boot_mem_map.map[i].addr; | ||
312 | if (a <= addr && addr+sz <= a+boot_mem_map.map[i].size) | ||
313 | return 1; | ||
314 | } | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int check_microtlb(u32 hi, u32 lo, unsigned long vaddr) | ||
319 | { | ||
320 | /* This is likely rather similar to correct code ;-) */ | ||
321 | |||
322 | vaddr &= 0x7fffffff; /* Doc. states that top bit is ignored */ | ||
323 | |||
324 | /* If tlb-entry is valid and VPN-high (bits [30:21] ?) matches... */ | ||
325 | if ((lo & 2) && (vaddr >> 21) == ((hi<<1) >> 22)) { | ||
326 | u32 ctl = sgimc->dma_ctrl; | ||
327 | if (ctl & 1) { | ||
328 | unsigned int pgsz = (ctl & 2) ? 14:12; /* 16k:4k */ | ||
329 | /* PTEIndex is VPN-low (bits [22:14]/[20:12] ?) */ | ||
330 | unsigned long pte = (lo >> 6) << 12; /* PTEBase */ | ||
331 | pte += 8*((vaddr >> pgsz) & 0x1ff); | ||
332 | if (addr_is_ram(pte, 8)) { | ||
333 | /* | ||
334 | * Note: Since DMA hardware does look up | ||
335 | * translation on its own, this PTE *must* | ||
336 | * match the TLB/EntryLo-register format ! | ||
337 | */ | ||
338 | unsigned long a = *(unsigned long *) | ||
339 | PHYS_TO_XKSEG_UNCACHED(pte); | ||
340 | a = (a & 0x3f) << 6; /* PFN */ | ||
341 | a += vaddr & ((1 << pgsz) - 1); | ||
342 | return (cpu_err_addr == a); | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int check_vdma_memaddr(void) | ||
350 | { | ||
351 | if (cpu_err_stat & CPU_ERRMASK) { | ||
352 | u32 a = sgimc->maddronly; | ||
353 | |||
354 | if (!(sgimc->dma_ctrl & 0x100)) /* Xlate-bit clear ? */ | ||
355 | return (cpu_err_addr == a); | ||
356 | |||
357 | if (check_microtlb(sgimc->dtlb_hi0, sgimc->dtlb_lo0, a) || | ||
358 | check_microtlb(sgimc->dtlb_hi1, sgimc->dtlb_lo1, a) || | ||
359 | check_microtlb(sgimc->dtlb_hi2, sgimc->dtlb_lo2, a) || | ||
360 | check_microtlb(sgimc->dtlb_hi3, sgimc->dtlb_lo3, a)) | ||
361 | return 1; | ||
362 | } | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int check_vdma_gioaddr(void) | ||
367 | { | ||
368 | if (gio_err_stat & GIO_ERRMASK) { | ||
369 | u32 a = sgimc->gio_dma_trans; | ||
370 | a = (sgimc->gmaddronly & ~a) | (sgimc->gio_dma_sbits & a); | ||
371 | return (gio_err_addr == a); | ||
372 | } | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | /* | ||
377 | * MC sends an interrupt whenever bus or parity errors occur. In addition, | ||
378 | * if the error happened during a CPU read, it also asserts the bus error | ||
379 | * pin on the R4K. Code in bus error handler save the MC bus error registers | ||
380 | * and then clear the interrupt when this happens. | ||
381 | */ | ||
382 | |||
383 | static int ip28_be_interrupt(const struct pt_regs *regs) | ||
384 | { | ||
385 | int i; | ||
386 | |||
387 | save_and_clear_buserr(); | ||
388 | /* | ||
389 | * Try to find out, whether we got here by a mispredicted speculative | ||
390 | * load/store operation. If so, it's not fatal, we can go on. | ||
391 | */ | ||
392 | /* Any cause other than "Interrupt" (ExcCode 0) is fatal. */ | ||
393 | if (regs->cp0_cause & CAUSEF_EXCCODE) | ||
394 | goto mips_be_fatal; | ||
395 | |||
396 | /* Any cause other than "Bus error interrupt" (IP6) is weird. */ | ||
397 | if ((regs->cp0_cause & CAUSEF_IP6) != CAUSEF_IP6) | ||
398 | goto mips_be_fatal; | ||
399 | |||
400 | if (extio_stat & (EXTIO_HPC3_BUSERR | EXTIO_EISA_BUSERR)) | ||
401 | goto mips_be_fatal; | ||
402 | |||
403 | /* Any state other than "Memory bus error" is fatal. */ | ||
404 | if (cpu_err_stat & CPU_ERRMASK & ~SGIMC_CSTAT_ADDR) | ||
405 | goto mips_be_fatal; | ||
406 | |||
407 | /* GIO errors other than timeouts are fatal */ | ||
408 | if (gio_err_stat & GIO_ERRMASK & ~SGIMC_GSTAT_TIME) | ||
409 | goto mips_be_fatal; | ||
410 | |||
411 | /* | ||
412 | * Now we have an asynchronous bus error, speculatively or DMA caused. | ||
413 | * Need to search all DMA descriptors for the error address. | ||
414 | */ | ||
415 | for (i = 0; i < sizeof(hpc3)/sizeof(struct hpc3_stat); ++i) { | ||
416 | struct hpc3_stat *hp = (struct hpc3_stat *)&hpc3 + i; | ||
417 | if ((cpu_err_stat & CPU_ERRMASK) && | ||
418 | (cpu_err_addr == hp->ndptr || cpu_err_addr == hp->cbp)) | ||
419 | break; | ||
420 | if ((gio_err_stat & GIO_ERRMASK) && | ||
421 | (gio_err_addr == hp->ndptr || gio_err_addr == hp->cbp)) | ||
422 | break; | ||
423 | } | ||
424 | if (i < sizeof(hpc3)/sizeof(struct hpc3_stat)) { | ||
425 | struct hpc3_stat *hp = (struct hpc3_stat *)&hpc3 + i; | ||
426 | printk(KERN_ERR "at DMA addresses: HPC3 @ %08lx:" | ||
427 | " ctl %08x, ndp %08x, cbp %08x\n", | ||
428 | CPHYSADDR(hp->addr), hp->ctrl, hp->ndptr, hp->cbp); | ||
429 | goto mips_be_fatal; | ||
430 | } | ||
431 | /* Check MC's virtual DMA stuff. */ | ||
432 | if (check_vdma_memaddr()) { | ||
433 | printk(KERN_ERR "at GIO DMA: mem address 0x%08x.\n", | ||
434 | sgimc->maddronly); | ||
435 | goto mips_be_fatal; | ||
436 | } | ||
437 | if (check_vdma_gioaddr()) { | ||
438 | printk(KERN_ERR "at GIO DMA: gio address 0x%08x.\n", | ||
439 | sgimc->gmaddronly); | ||
440 | goto mips_be_fatal; | ||
441 | } | ||
442 | /* A speculative bus error... */ | ||
443 | if (debug_be_interrupt) { | ||
444 | print_buserr(regs); | ||
445 | printk(KERN_ERR "discarded!\n"); | ||
446 | } | ||
447 | return MIPS_BE_DISCARD; | ||
448 | |||
449 | mips_be_fatal: | ||
450 | print_buserr(regs); | ||
451 | return MIPS_BE_FATAL; | ||
452 | } | ||
453 | |||
454 | void ip22_be_interrupt(int irq) | ||
455 | { | ||
456 | const struct pt_regs *regs = get_irq_regs(); | ||
457 | |||
458 | count_be_interrupt++; | ||
459 | |||
460 | if (ip28_be_interrupt(regs) != MIPS_BE_DISCARD) { | ||
461 | /* Assume it would be too dangerous to continue ... */ | ||
462 | die_if_kernel("Oops", regs); | ||
463 | force_sig(SIGBUS, current); | ||
464 | } else if (debug_be_interrupt) | ||
465 | show_regs((struct pt_regs *)regs); | ||
466 | } | ||
467 | |||
468 | static int ip28_be_handler(struct pt_regs *regs, int is_fixup) | ||
469 | { | ||
470 | /* | ||
471 | * We arrive here only in the unusual case of do_be() invocation, | ||
472 | * i.e. by a bus error exception without a bus error interrupt. | ||
473 | */ | ||
474 | if (is_fixup) { | ||
475 | count_be_is_fixup++; | ||
476 | save_and_clear_buserr(); | ||
477 | return MIPS_BE_FIXUP; | ||
478 | } | ||
479 | count_be_handler++; | ||
480 | return ip28_be_interrupt(regs); | ||
481 | } | ||
482 | |||
483 | void __init ip22_be_init(void) | ||
484 | { | ||
485 | board_be_handler = ip28_be_handler; | ||
486 | } | ||
487 | |||
488 | int ip28_show_be_info(struct seq_file *m) | ||
489 | { | ||
490 | seq_printf(m, "IP28 be fixups\t\t: %u\n", count_be_is_fixup); | ||
491 | seq_printf(m, "IP28 be interrupts\t: %u\n", count_be_interrupt); | ||
492 | seq_printf(m, "IP28 be handler\t\t: %u\n", count_be_handler); | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static int __init debug_be_setup(char *str) | ||
498 | { | ||
499 | debug_be_interrupt++; | ||
500 | return 1; | ||
501 | } | ||
502 | __setup("ip28_debug_be", debug_be_setup); | ||