aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/dec
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/dec')
-rw-r--r--arch/mips/dec/Makefile11
-rw-r--r--arch/mips/dec/boot/Makefile12
-rw-r--r--arch/mips/dec/boot/decstation.c83
-rw-r--r--arch/mips/dec/boot/ld.ecoff43
-rw-r--r--arch/mips/dec/ecc-berr.c280
-rw-r--r--arch/mips/dec/int-handler.S297
-rw-r--r--arch/mips/dec/ioasic-irq.c157
-rw-r--r--arch/mips/dec/kn02-irq.c127
-rw-r--r--arch/mips/dec/prom/Makefile11
-rw-r--r--arch/mips/dec/prom/call_o32.S91
-rw-r--r--arch/mips/dec/prom/cmdline.c39
-rw-r--r--arch/mips/dec/prom/console.c55
-rw-r--r--arch/mips/dec/prom/dectypes.h14
-rw-r--r--arch/mips/dec/prom/identify.c177
-rw-r--r--arch/mips/dec/prom/init.c134
-rw-r--r--arch/mips/dec/prom/locore.S30
-rw-r--r--arch/mips/dec/prom/memory.c130
-rw-r--r--arch/mips/dec/promcon.c55
-rw-r--r--arch/mips/dec/reset.c41
-rw-r--r--arch/mips/dec/setup.c750
-rw-r--r--arch/mips/dec/time.c200
-rw-r--r--arch/mips/dec/wbflush.c94
22 files changed, 2831 insertions, 0 deletions
diff --git a/arch/mips/dec/Makefile b/arch/mips/dec/Makefile
new file mode 100644
index 000000000000..688757a97cb8
--- /dev/null
+++ b/arch/mips/dec/Makefile
@@ -0,0 +1,11 @@
1#
2# Makefile for the DECstation family specific parts of the kernel
3#
4
5obj-y := ecc-berr.o int-handler.o ioasic-irq.o kn02-irq.o reset.o \
6 setup.o time.o
7
8obj-$(CONFIG_PROM_CONSOLE) += promcon.o
9obj-$(CONFIG_CPU_HAS_WB) += wbflush.o
10
11EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/dec/boot/Makefile b/arch/mips/dec/boot/Makefile
new file mode 100644
index 000000000000..bcea41698ef5
--- /dev/null
+++ b/arch/mips/dec/boot/Makefile
@@ -0,0 +1,12 @@
1#
2# Makefile for the DECstation family specific parts of the kernel
3#
4
5netboot: all
6 $(LD) -N -G 0 -T ld.ecoff ../../boot/zImage \
7 dec_boot.o ramdisk.img -o nbImage
8
9obj-y := decstation.o
10
11clean:
12 rm -f nbImage
diff --git a/arch/mips/dec/boot/decstation.c b/arch/mips/dec/boot/decstation.c
new file mode 100644
index 000000000000..56fd4277555e
--- /dev/null
+++ b/arch/mips/dec/boot/decstation.c
@@ -0,0 +1,83 @@
1/*
2 * arch/mips/dec/decstation.c
3 */
4
5#define RELOC
6#define INITRD
7#define DEBUG_BOOT
8
9/*
10 * Magic number indicating REX PROM available on DECSTATION.
11 */
12#define REX_PROM_MAGIC 0x30464354
13
14#define REX_PROM_CLEARCACHE 0x7c/4
15#define REX_PROM_PRINTF 0x30/4
16
17#define VEC_RESET 0xBFC00000 /* Prom base address */
18#define PMAX_PROM_ENTRY(x) (VEC_RESET+((x)*8)) /* Prom jump table */
19#define PMAX_PROM_PRINTF PMAX_PROM_ENTRY(17)
20
21#define PARAM (k_start + 0x2000)
22
23#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
24#define INITRD_START (*(unsigned long *) (PARAM+0x218))
25#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
26
27extern int _ftext, _end; /* begin and end of kernel image */
28extern void kernel_entry(int, char **, unsigned long, int *);
29
30void * memcpy(void * dest, const void *src, unsigned int count)
31{
32 unsigned long *tmp = (unsigned long *) dest, *s = (unsigned long *) src;
33
34 count >>= 2;
35 while (count--)
36 *tmp++ = *s++;
37
38 return dest;
39}
40
41void dec_entry(int argc, char **argv,
42 unsigned long magic, int *prom_vec)
43{
44 void (*rex_clear_cache)(void);
45 int (*prom_printf)(char *, ...);
46 unsigned long k_start, len;
47
48 /*
49 * The DS5100 leaves cpu with BEV enabled, clear it.
50 */
51 asm( "lui\t$8,0x3000\n\t"
52 "mtc0\t$8,$12\n\t"
53 ".section\t.sdata\n\t"
54 ".section\t.sbss\n\t"
55 ".section\t.text"
56 : : : "$8");
57
58#ifdef DEBUG_BOOT
59 if (magic == REX_PROM_MAGIC) {
60 prom_printf = (int (*)(char *, ...)) *(prom_vec + REX_PROM_PRINTF);
61 } else {
62 prom_printf = (int (*)(char *, ...)) PMAX_PROM_PRINTF;
63 }
64 prom_printf("Launching kernel...\n");
65#endif
66
67 k_start = (unsigned long) (&kernel_entry) & 0xffff0000;
68
69#ifdef RELOC
70 /*
71 * Now copy kernel image to its destination.
72 */
73 len = ((unsigned long) (&_end) - k_start);
74 memcpy((void *)k_start, &_ftext, len);
75#endif
76
77 if (magic == REX_PROM_MAGIC) {
78 rex_clear_cache = (void (*)(void)) * (prom_vec + REX_PROM_CLEARCACHE);
79 rex_clear_cache();
80 }
81
82 kernel_entry(argc, argv, magic, prom_vec);
83}
diff --git a/arch/mips/dec/boot/ld.ecoff b/arch/mips/dec/boot/ld.ecoff
new file mode 100644
index 000000000000..aaa633dfb5f7
--- /dev/null
+++ b/arch/mips/dec/boot/ld.ecoff
@@ -0,0 +1,43 @@
1OUTPUT_FORMAT("ecoff-littlemips")
2OUTPUT_ARCH(mips)
3ENTRY(dec_entry)
4SECTIONS
5{
6 . = 0x80200000;
7
8 .text :
9 {
10 _ftext = .;
11 *(.text)
12 *(.fixup)
13 }
14 .rdata :
15 {
16 *(.rodata .rodata.* .rdata)
17 }
18 .data :
19 {
20 . = ALIGN(0x1000);
21 ramdisk.img (.data)
22 *(.data)
23 }
24 .sdata :
25 {
26 *(.sdata)
27 }
28 _gp = .;
29 .sbss :
30 {
31 *(.sbss)
32 *(.scommon)
33 }
34 .bss :
35 {
36 *(.dynbss)
37 *(.bss)
38 *(COMMON)
39 }
40 /DISCARD/ : {
41 *(.reginfo .mdebug .note)
42 }
43}
diff --git a/arch/mips/dec/ecc-berr.c b/arch/mips/dec/ecc-berr.c
new file mode 100644
index 000000000000..133fb7c48e6c
--- /dev/null
+++ b/arch/mips/dec/ecc-berr.c
@@ -0,0 +1,280 @@
1/*
2 * linux/arch/mips/dec/ecc-berr.c
3 *
4 * Bus error event handling code for systems equipped with ECC
5 * handling logic, i.e. DECstation/DECsystem 5000/200 (KN02),
6 * 5000/240 (KN03), 5000/260 (KN05) and DECsystem 5900 (KN03),
7 * 5900/260 (KN05) systems.
8 *
9 * Copyright (c) 2003 Maciej W. Rozycki
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version
14 * 2 of the License, or (at your option) any later version.
15 */
16
17#include <linux/init.h>
18#include <linux/kernel.h>
19#include <linux/sched.h>
20#include <linux/spinlock.h>
21#include <linux/types.h>
22
23#include <asm/addrspace.h>
24#include <asm/bootinfo.h>
25#include <asm/cpu.h>
26#include <asm/processor.h>
27#include <asm/system.h>
28#include <asm/traps.h>
29
30#include <asm/dec/ecc.h>
31#include <asm/dec/kn02.h>
32#include <asm/dec/kn03.h>
33#include <asm/dec/kn05.h>
34
35static volatile u32 *kn0x_erraddr;
36static volatile u32 *kn0x_chksyn;
37
38static inline void dec_ecc_be_ack(void)
39{
40 *kn0x_erraddr = 0; /* any write clears the IRQ */
41 iob();
42}
43
44static int dec_ecc_be_backend(struct pt_regs *regs, int is_fixup, int invoker)
45{
46 static const char excstr[] = "exception";
47 static const char intstr[] = "interrupt";
48 static const char cpustr[] = "CPU";
49 static const char dmastr[] = "DMA";
50 static const char readstr[] = "read";
51 static const char mreadstr[] = "memory read";
52 static const char writestr[] = "write";
53 static const char mwritstr[] = "partial memory write";
54 static const char timestr[] = "timeout";
55 static const char overstr[] = "overrun";
56 static const char eccstr[] = "ECC error";
57
58 const char *kind, *agent, *cycle, *event;
59 const char *status = "", *xbit = "", *fmt = "";
60 dma_addr_t address;
61 u16 syn = 0, sngl;
62
63 int i = 0;
64
65 u32 erraddr = *kn0x_erraddr;
66 u32 chksyn = *kn0x_chksyn;
67 int action = MIPS_BE_FATAL;
68
69 /* For non-ECC ack ASAP, so any subsequent errors get caught. */
70 if ((erraddr & (KN0X_EAR_VALID | KN0X_EAR_ECCERR)) == KN0X_EAR_VALID)
71 dec_ecc_be_ack();
72
73 kind = invoker ? intstr : excstr;
74
75 if (!(erraddr & KN0X_EAR_VALID)) {
76 /* No idea what happened. */
77 printk(KERN_ALERT "Unidentified bus error %s.\n", kind);
78 return action;
79 }
80
81 agent = (erraddr & KN0X_EAR_CPU) ? cpustr : dmastr;
82
83 if (erraddr & KN0X_EAR_ECCERR) {
84 /* An ECC error on a CPU or DMA transaction. */
85 cycle = (erraddr & KN0X_EAR_WRITE) ? mwritstr : mreadstr;
86 event = eccstr;
87 } else {
88 /* A CPU timeout or a DMA overrun. */
89 cycle = (erraddr & KN0X_EAR_WRITE) ? writestr : readstr;
90 event = (erraddr & KN0X_EAR_CPU) ? timestr : overstr;
91 }
92
93 address = erraddr & KN0X_EAR_ADDRESS;
94 /* For ECC errors on reads adjust for MT pipelining. */
95 if ((erraddr & (KN0X_EAR_WRITE | KN0X_EAR_ECCERR)) == KN0X_EAR_ECCERR)
96 address = (address & ~0xfffLL) | ((address - 5) & 0xfffLL);
97 address <<= 2;
98
99 /* Only CPU errors are fixable. */
100 if (erraddr & KN0X_EAR_CPU && is_fixup)
101 action = MIPS_BE_FIXUP;
102
103 if (erraddr & KN0X_EAR_ECCERR) {
104 static const u8 data_sbit[32] = {
105 0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d,
106 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34,
107 0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c,
108 0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75,
109 };
110 static const u8 data_mbit[25] = {
111 0x07, 0x0d, 0x1f,
112 0x2f, 0x32, 0x37, 0x38, 0x3b, 0x3d, 0x3e,
113 0x43, 0x45, 0x46, 0x49, 0x4c, 0x51, 0x5e,
114 0x61, 0x6e, 0x73, 0x76, 0x79, 0x7a, 0x7c, 0x7f,
115 };
116 static const char sbestr[] = "corrected single";
117 static const char dbestr[] = "uncorrectable double";
118 static const char mbestr[] = "uncorrectable multiple";
119
120 if (!(address & 0x4))
121 syn = chksyn; /* Low bank. */
122 else
123 syn = chksyn >> 16; /* High bank. */
124
125 if (!(syn & KN0X_ESR_VLDLO)) {
126 /* Ack now, no rewrite will happen. */
127 dec_ecc_be_ack();
128
129 fmt = KERN_ALERT "%s" "invalid.\n";
130 } else {
131 sngl = syn & KN0X_ESR_SNGLO;
132 syn &= KN0X_ESR_SYNLO;
133
134 /*
135 * Multibit errors may be tagged incorrectly;
136 * check the syndrome explicitly.
137 */
138 for (i = 0; i < 25; i++)
139 if (syn == data_mbit[i])
140 break;
141
142 if (i < 25) {
143 status = mbestr;
144 } else if (!sngl) {
145 status = dbestr;
146 } else {
147 volatile u32 *ptr = (void *)KSEG1ADDR(address);
148
149 *ptr = *ptr; /* Rewrite. */
150 iob();
151
152 status = sbestr;
153 action = MIPS_BE_DISCARD;
154 }
155
156 /* Ack now, now we've rewritten (or not). */
157 dec_ecc_be_ack();
158
159 if (syn && syn == (syn & -syn)) {
160 if (syn == 0x01) {
161 fmt = KERN_ALERT "%s"
162 "%#04x -- %s bit error "
163 "at check bit C%s.\n";
164 xbit = "X";
165 } else {
166 fmt = KERN_ALERT "%s"
167 "%#04x -- %s bit error "
168 "at check bit C%s%u.\n";
169 }
170 i = syn >> 2;
171 } else {
172 for (i = 0; i < 32; i++)
173 if (syn == data_sbit[i])
174 break;
175 if (i < 32)
176 fmt = KERN_ALERT "%s"
177 "%#04x -- %s bit error "
178 "at data bit D%s%u.\n";
179 else
180 fmt = KERN_ALERT "%s"
181 "%#04x -- %s bit error.\n";
182 }
183 }
184 }
185
186 if (action != MIPS_BE_FIXUP)
187 printk(KERN_ALERT "Bus error %s: %s %s %s at %#010lx.\n",
188 kind, agent, cycle, event, address);
189
190 if (action != MIPS_BE_FIXUP && erraddr & KN0X_EAR_ECCERR)
191 printk(fmt, " ECC syndrome ", syn, status, xbit, i);
192
193 return action;
194}
195
196int dec_ecc_be_handler(struct pt_regs *regs, int is_fixup)
197{
198 return dec_ecc_be_backend(regs, is_fixup, 0);
199}
200
201irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id, struct pt_regs *regs)
202{
203 int action = dec_ecc_be_backend(regs, 0, 1);
204
205 if (action == MIPS_BE_DISCARD)
206 return IRQ_NONE;
207
208 /*
209 * FIXME: Find affected processes and kill them, otherwise we
210 * must die.
211 *
212 * The interrupt is asynchronously delivered thus EPC and RA
213 * may be irrelevant, but are printed for a reference.
214 */
215 printk(KERN_ALERT "Fatal bus interrupt, epc == %08lx, ra == %08lx\n",
216 regs->cp0_epc, regs->regs[31]);
217 die("Unrecoverable bus error", regs);
218}
219
220
221/*
222 * Initialization differs a bit between KN02 and KN03/KN05, so we
223 * need two variants. Once set up, all systems can be handled the
224 * same way.
225 */
226static inline void dec_kn02_be_init(void)
227{
228 volatile u32 *csr = (void *)KN02_CSR_BASE;
229 unsigned long flags;
230
231 kn0x_erraddr = (void *)(KN02_SLOT_BASE + KN02_ERRADDR);
232 kn0x_chksyn = (void *)(KN02_SLOT_BASE + KN02_CHKSYN);
233
234 spin_lock_irqsave(&kn02_lock, flags);
235
236 /* Preset write-only bits of the Control Register cache. */
237 cached_kn02_csr = *csr | KN03_CSR_LEDS;
238
239 /* Set normal ECC detection and generation. */
240 cached_kn02_csr &= ~(KN02_CSR_DIAGCHK | KN02_CSR_DIAGGEN);
241 /* Enable ECC correction. */
242 cached_kn02_csr |= KN02_CSR_CORRECT;
243 *csr = cached_kn02_csr;
244 iob();
245
246 spin_unlock_irqrestore(&kn02_lock, flags);
247}
248
249static inline void dec_kn03_be_init(void)
250{
251 volatile u32 *mcr = (void *)(KN03_SLOT_BASE + IOASIC_MCR);
252 volatile u32 *mbcs = (void *)(KN03_SLOT_BASE + KN05_MB_CSR);
253
254 kn0x_erraddr = (void *)(KN03_SLOT_BASE + IOASIC_ERRADDR);
255 kn0x_chksyn = (void *)(KN03_SLOT_BASE + IOASIC_CHKSYN);
256
257 /*
258 * Set normal ECC detection and generation, enable ECC correction.
259 * For KN05 we also need to make sure EE (?) is enabled in the MB.
260 * Otherwise DBE/IBE exceptions would be masked but bus error
261 * interrupts would still arrive, resulting in an inevitable crash
262 * if get_dbe() triggers one.
263 */
264 *mcr = (*mcr & ~(KN03_MCR_DIAGCHK | KN03_MCR_DIAGGEN)) |
265 KN03_MCR_CORRECT;
266 if (current_cpu_data.cputype == CPU_R4400SC)
267 *mbcs |= KN05_MB_CSR_EE;
268 fast_iob();
269}
270
271void __init dec_ecc_be_init(void)
272{
273 if (mips_machtype == MACH_DS5000_200)
274 dec_kn02_be_init();
275 else
276 dec_kn03_be_init();
277
278 /* Clear any leftover errors from the firmware. */
279 dec_ecc_be_ack();
280}
diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S
new file mode 100644
index 000000000000..3b3790993219
--- /dev/null
+++ b/arch/mips/dec/int-handler.S
@@ -0,0 +1,297 @@
1/*
2 * arch/mips/dec/int-handler.S
3 *
4 * Copyright (C) 1995, 1996, 1997 Paul M. Antoine and Harald Koerfgen
5 * Copyright (C) 2000, 2001, 2002, 2003 Maciej W. Rozycki
6 *
7 * Written by Ralf Baechle and Andreas Busse, modified for DECStation
8 * support by Paul Antoine and Harald Koerfgen.
9 *
10 * completly rewritten:
11 * Copyright (C) 1998 Harald Koerfgen
12 *
13 * Rewritten extensively for controller-driven IRQ support
14 * by Maciej W. Rozycki.
15 */
16#include <linux/config.h>
17#include <asm/asm.h>
18#include <asm/regdef.h>
19#include <asm/mipsregs.h>
20#include <asm/stackframe.h>
21#include <asm/addrspace.h>
22
23#include <asm/dec/interrupts.h>
24#include <asm/dec/ioasic_addrs.h>
25#include <asm/dec/ioasic_ints.h>
26#include <asm/dec/kn01.h>
27#include <asm/dec/kn02.h>
28#include <asm/dec/kn02xa.h>
29#include <asm/dec/kn03.h>
30
31
32 .text
33 .set noreorder
34/*
35 * decstation_handle_int: Interrupt handler for DECStations
36 *
37 * We follow the model in the Indy interrupt code by David Miller, where he
38 * says: a lot of complication here is taken away because:
39 *
40 * 1) We handle one interrupt and return, sitting in a loop
41 * and moving across all the pending IRQ bits in the cause
42 * register is _NOT_ the answer, the common case is one
43 * pending IRQ so optimize in that direction.
44 *
45 * 2) We need not check against bits in the status register
46 * IRQ mask, that would make this routine slow as hell.
47 *
48 * 3) Linux only thinks in terms of all IRQs on or all IRQs
49 * off, nothing in between like BSD spl() brain-damage.
50 *
51 * Furthermore, the IRQs on the DECStations look basically (barring
52 * software IRQs which we don't use at all) like...
53 *
54 * DS2100/3100's, aka kn01, aka Pmax:
55 *
56 * MIPS IRQ Source
57 * -------- ------
58 * 0 Software (ignored)
59 * 1 Software (ignored)
60 * 2 SCSI
61 * 3 Lance Ethernet
62 * 4 DZ11 serial
63 * 5 RTC
64 * 6 Memory Controller
65 * 7 FPU
66 *
67 * DS5000/200, aka kn02, aka 3max:
68 *
69 * MIPS IRQ Source
70 * -------- ------
71 * 0 Software (ignored)
72 * 1 Software (ignored)
73 * 2 TurboChannel
74 * 3 RTC
75 * 4 Reserved
76 * 5 Memory Controller
77 * 6 Reserved
78 * 7 FPU
79 *
80 * DS5000/1xx's, aka kn02ba, aka 3min:
81 *
82 * MIPS IRQ Source
83 * -------- ------
84 * 0 Software (ignored)
85 * 1 Software (ignored)
86 * 2 TurboChannel Slot 0
87 * 3 TurboChannel Slot 1
88 * 4 TurboChannel Slot 2
89 * 5 TurboChannel Slot 3 (ASIC)
90 * 6 Halt button
91 * 7 FPU/R4k timer
92 *
93 * DS5000/2x's, aka kn02ca, aka maxine:
94 *
95 * MIPS IRQ Source
96 * -------- ------
97 * 0 Software (ignored)
98 * 1 Software (ignored)
99 * 2 Periodic Interrupt (100usec)
100 * 3 RTC
101 * 4 I/O write timeout
102 * 5 TurboChannel (ASIC)
103 * 6 Halt Keycode from Access.Bus keyboard (CTRL-ALT-ENTER)
104 * 7 FPU/R4k timer
105 *
106 * DS5000/2xx's, aka kn03, aka 3maxplus:
107 *
108 * MIPS IRQ Source
109 * -------- ------
110 * 0 Software (ignored)
111 * 1 Software (ignored)
112 * 2 System Board (ASIC)
113 * 3 RTC
114 * 4 Reserved
115 * 5 Memory
116 * 6 Halt Button
117 * 7 FPU/R4k timer
118 *
119 * We handle the IRQ according to _our_ priority (see setup.c),
120 * then we just return. If multiple IRQs are pending then we will
121 * just take another exception, big deal.
122 */
123 .align 5
124 NESTED(decstation_handle_int, PT_SIZE, ra)
125 .set noat
126 SAVE_ALL
127 CLI # TEST: interrupts should be off
128 .set at
129 .set noreorder
130
131 /*
132 * Get pending Interrupts
133 */
134 mfc0 t0,CP0_CAUSE # get pending interrupts
135 mfc0 t1,CP0_STATUS
136#ifdef CONFIG_MIPS32
137 lw t2,cpu_fpu_mask
138#endif
139 andi t0,ST0_IM # CAUSE.CE may be non-zero!
140 and t0,t1 # isolate allowed ones
141
142 beqz t0,spurious
143
144#ifdef CONFIG_MIPS32
145 and t2,t0
146 bnez t2,fpu # handle FPU immediately
147#endif
148
149 /*
150 * Find irq with highest priority
151 */
152 PTR_LA t1,cpu_mask_nr_tbl
1531: lw t2,(t1)
154 nop
155 and t2,t0
156 beqz t2,1b
157 addu t1,2*PTRSIZE # delay slot
158
159 /*
160 * Do the low-level stuff
161 */
162 lw a0,(-PTRSIZE)(t1)
163 nop
164 bgez a0,handle_it # irq_nr >= 0?
165 # irq_nr < 0: it is an address
166 nop
167 jr a0
168 # a trick to save a branch:
169 lui t2,(KN03_IOASIC_BASE>>16)&0xffff
170 # upper part of IOASIC Address
171
172/*
173 * Handle "IRQ Controller" Interrupts
174 * Masked Interrupts are still visible and have to be masked "by hand".
175 */
176 FEXPORT(kn02_io_int) # 3max
177 lui t0,(KN02_CSR_BASE>>16)&0xffff
178 # get interrupt status and mask
179 lw t0,(t0)
180 nop
181 andi t1,t0,KN02_IRQ_ALL
182 b 1f
183 srl t0,16 # shift interrupt mask
184
185 FEXPORT(kn02xa_io_int) # 3min/maxine
186 lui t2,(KN02XA_IOASIC_BASE>>16)&0xffff
187 # upper part of IOASIC Address
188
189 FEXPORT(kn03_io_int) # 3max+ (t2 loaded earlier)
190 lw t0,IO_REG_SIR(t2) # get status: IOASIC sir
191 lw t1,IO_REG_SIMR(t2) # get mask: IOASIC simr
192 nop
193
1941: and t0,t1 # mask out allowed ones
195
196 beqz t0,spurious
197
198 /*
199 * Find irq with highest priority
200 */
201 PTR_LA t1,asic_mask_nr_tbl
2022: lw t2,(t1)
203 nop
204 and t2,t0
205 beq zero,t2,2b
206 addu t1,2*PTRSIZE # delay slot
207
208 /*
209 * Do the low-level stuff
210 */
211 lw a0,%lo(-PTRSIZE)(t1)
212 nop
213 bgez a0,handle_it # irq_nr >= 0?
214 # irq_nr < 0: it is an address
215 nop
216 jr a0
217 nop # delay slot
218
219/*
220 * Dispatch low-priority interrupts. We reconsider all status
221 * bits again, which looks like a lose, but it makes the code
222 * simple and O(log n), so it gets compensated.
223 */
224 FEXPORT(cpu_all_int) # HALT, timers, software junk
225 li a0,DEC_CPU_IRQ_BASE
226 srl t0,CAUSEB_IP
227 li t1,CAUSEF_IP>>CAUSEB_IP # mask
228 b 1f
229 li t2,4 # nr of bits / 2
230
231 FEXPORT(kn02_all_int) # impossible ?
232 li a0,KN02_IRQ_BASE
233 li t1,KN02_IRQ_ALL # mask
234 b 1f
235 li t2,4 # nr of bits / 2
236
237 FEXPORT(asic_all_int) # various I/O ASIC junk
238 li a0,IO_IRQ_BASE
239 li t1,IO_IRQ_ALL # mask
240 b 1f
241 li t2,8 # nr of bits / 2
242
243/*
244 * Dispatch DMA interrupts -- O(log n).
245 */
246 FEXPORT(asic_dma_int) # I/O ASIC DMA events
247 li a0,IO_IRQ_BASE+IO_INR_DMA
248 srl t0,IO_INR_DMA
249 li t1,IO_IRQ_DMA>>IO_INR_DMA # mask
250 li t2,8 # nr of bits / 2
251
252 /*
253 * Find irq with highest priority.
254 * Highest irq number takes precedence.
255 */
2561: srlv t3,t1,t2
2572: xor t1,t3
258 and t3,t0,t1
259 beqz t3,3f
260 nop
261 move t0,t3
262 addu a0,t2
2633: srl t2,1
264 bnez t2,2b
265 srlv t3,t1,t2
266
267handle_it:
268 jal do_IRQ
269 move a1,sp
270
271 j ret_from_irq
272 nop
273
274#ifdef CONFIG_MIPS32
275fpu:
276 j handle_fpe_int
277 nop
278#endif
279
280spurious:
281 j spurious_interrupt
282 nop
283 END(decstation_handle_int)
284
285/*
286 * Generic unimplemented interrupt routines -- cpu_mask_nr_tbl
287 * and asic_mask_nr_tbl are initialized to point all interrupts here.
288 * The tables are then filled in by machine-specific initialisation
289 * in dec_setup().
290 */
291 FEXPORT(dec_intr_unimplemented)
292 move a1,t0 # cheats way of printing an arg!
293 PANIC("Unimplemented cpu interrupt! CP0_CAUSE: 0x%08x");
294
295 FEXPORT(asic_intr_unimplemented)
296 move a1,t0 # cheats way of printing an arg!
297 PANIC("Unimplemented asic interrupt! ASIC ISR: 0x%08x");
diff --git a/arch/mips/dec/ioasic-irq.c b/arch/mips/dec/ioasic-irq.c
new file mode 100644
index 000000000000..d5bca5d233b6
--- /dev/null
+++ b/arch/mips/dec/ioasic-irq.c
@@ -0,0 +1,157 @@
1/*
2 * linux/arch/mips/dec/ioasic-irq.c
3 *
4 * DEC I/O ASIC interrupts.
5 *
6 * Copyright (c) 2002, 2003 Maciej W. Rozycki
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13
14#include <linux/init.h>
15#include <linux/irq.h>
16#include <linux/spinlock.h>
17#include <linux/types.h>
18
19#include <asm/dec/ioasic.h>
20#include <asm/dec/ioasic_addrs.h>
21#include <asm/dec/ioasic_ints.h>
22
23
24static DEFINE_SPINLOCK(ioasic_lock);
25
26static int ioasic_irq_base;
27
28
29static inline void unmask_ioasic_irq(unsigned int irq)
30{
31 u32 simr;
32
33 simr = ioasic_read(IO_REG_SIMR);
34 simr |= (1 << (irq - ioasic_irq_base));
35 ioasic_write(IO_REG_SIMR, simr);
36}
37
38static inline void mask_ioasic_irq(unsigned int irq)
39{
40 u32 simr;
41
42 simr = ioasic_read(IO_REG_SIMR);
43 simr &= ~(1 << (irq - ioasic_irq_base));
44 ioasic_write(IO_REG_SIMR, simr);
45}
46
47static inline void clear_ioasic_irq(unsigned int irq)
48{
49 u32 sir;
50
51 sir = ~(1 << (irq - ioasic_irq_base));
52 ioasic_write(IO_REG_SIR, sir);
53}
54
55static inline void enable_ioasic_irq(unsigned int irq)
56{
57 unsigned long flags;
58
59 spin_lock_irqsave(&ioasic_lock, flags);
60 unmask_ioasic_irq(irq);
61 spin_unlock_irqrestore(&ioasic_lock, flags);
62}
63
64static inline void disable_ioasic_irq(unsigned int irq)
65{
66 unsigned long flags;
67
68 spin_lock_irqsave(&ioasic_lock, flags);
69 mask_ioasic_irq(irq);
70 spin_unlock_irqrestore(&ioasic_lock, flags);
71}
72
73
74static inline unsigned int startup_ioasic_irq(unsigned int irq)
75{
76 enable_ioasic_irq(irq);
77 return 0;
78}
79
80#define shutdown_ioasic_irq disable_ioasic_irq
81
82static inline void ack_ioasic_irq(unsigned int irq)
83{
84 spin_lock(&ioasic_lock);
85 mask_ioasic_irq(irq);
86 spin_unlock(&ioasic_lock);
87 fast_iob();
88}
89
90static inline void end_ioasic_irq(unsigned int irq)
91{
92 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
93 enable_ioasic_irq(irq);
94}
95
96static struct hw_interrupt_type ioasic_irq_type = {
97 .typename = "IO-ASIC",
98 .startup = startup_ioasic_irq,
99 .shutdown = shutdown_ioasic_irq,
100 .enable = enable_ioasic_irq,
101 .disable = disable_ioasic_irq,
102 .ack = ack_ioasic_irq,
103 .end = end_ioasic_irq,
104};
105
106
107#define startup_ioasic_dma_irq startup_ioasic_irq
108
109#define shutdown_ioasic_dma_irq shutdown_ioasic_irq
110
111#define enable_ioasic_dma_irq enable_ioasic_irq
112
113#define disable_ioasic_dma_irq disable_ioasic_irq
114
115#define ack_ioasic_dma_irq ack_ioasic_irq
116
117static inline void end_ioasic_dma_irq(unsigned int irq)
118{
119 clear_ioasic_irq(irq);
120 fast_iob();
121 end_ioasic_irq(irq);
122}
123
124static struct hw_interrupt_type ioasic_dma_irq_type = {
125 .typename = "IO-ASIC-DMA",
126 .startup = startup_ioasic_dma_irq,
127 .shutdown = shutdown_ioasic_dma_irq,
128 .enable = enable_ioasic_dma_irq,
129 .disable = disable_ioasic_dma_irq,
130 .ack = ack_ioasic_dma_irq,
131 .end = end_ioasic_dma_irq,
132};
133
134
135void __init init_ioasic_irqs(int base)
136{
137 int i;
138
139 /* Mask interrupts. */
140 ioasic_write(IO_REG_SIMR, 0);
141 fast_iob();
142
143 for (i = base; i < base + IO_INR_DMA; i++) {
144 irq_desc[i].status = IRQ_DISABLED;
145 irq_desc[i].action = 0;
146 irq_desc[i].depth = 1;
147 irq_desc[i].handler = &ioasic_irq_type;
148 }
149 for (; i < base + IO_IRQ_LINES; i++) {
150 irq_desc[i].status = IRQ_DISABLED;
151 irq_desc[i].action = 0;
152 irq_desc[i].depth = 1;
153 irq_desc[i].handler = &ioasic_dma_irq_type;
154 }
155
156 ioasic_irq_base = base;
157}
diff --git a/arch/mips/dec/kn02-irq.c b/arch/mips/dec/kn02-irq.c
new file mode 100644
index 000000000000..e0bfcd1521e2
--- /dev/null
+++ b/arch/mips/dec/kn02-irq.c
@@ -0,0 +1,127 @@
1/*
2 * linux/arch/mips/dec/kn02-irq.c
3 *
4 * DECstation 5000/200 (KN02) Control and Status Register
5 * interrupts.
6 *
7 * Copyright (c) 2002, 2003 Maciej W. Rozycki
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 */
14
15#include <linux/init.h>
16#include <linux/irq.h>
17#include <linux/spinlock.h>
18#include <linux/types.h>
19
20#include <asm/dec/kn02.h>
21
22
23/*
24 * Bits 7:0 of the Control Register are write-only -- the
25 * corresponding bits of the Status Register have a different
26 * meaning. Hence we use a cache. It speeds up things a bit
27 * as well.
28 *
29 * There is no default value -- it has to be initialized.
30 */
31u32 cached_kn02_csr;
32DEFINE_SPINLOCK(kn02_lock);
33
34
35static int kn02_irq_base;
36
37
38static inline void unmask_kn02_irq(unsigned int irq)
39{
40 volatile u32 *csr = (volatile u32 *)KN02_CSR_BASE;
41
42 cached_kn02_csr |= (1 << (irq - kn02_irq_base + 16));
43 *csr = cached_kn02_csr;
44}
45
46static inline void mask_kn02_irq(unsigned int irq)
47{
48 volatile u32 *csr = (volatile u32 *)KN02_CSR_BASE;
49
50 cached_kn02_csr &= ~(1 << (irq - kn02_irq_base + 16));
51 *csr = cached_kn02_csr;
52}
53
54static inline void enable_kn02_irq(unsigned int irq)
55{
56 unsigned long flags;
57
58 spin_lock_irqsave(&kn02_lock, flags);
59 unmask_kn02_irq(irq);
60 spin_unlock_irqrestore(&kn02_lock, flags);
61}
62
63static inline void disable_kn02_irq(unsigned int irq)
64{
65 unsigned long flags;
66
67 spin_lock_irqsave(&kn02_lock, flags);
68 mask_kn02_irq(irq);
69 spin_unlock_irqrestore(&kn02_lock, flags);
70}
71
72
73static unsigned int startup_kn02_irq(unsigned int irq)
74{
75 enable_kn02_irq(irq);
76 return 0;
77}
78
79#define shutdown_kn02_irq disable_kn02_irq
80
81static void ack_kn02_irq(unsigned int irq)
82{
83 spin_lock(&kn02_lock);
84 mask_kn02_irq(irq);
85 spin_unlock(&kn02_lock);
86 iob();
87}
88
89static void end_kn02_irq(unsigned int irq)
90{
91 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
92 enable_kn02_irq(irq);
93}
94
95static struct hw_interrupt_type kn02_irq_type = {
96 .typename = "KN02-CSR",
97 .startup = startup_kn02_irq,
98 .shutdown = shutdown_kn02_irq,
99 .enable = enable_kn02_irq,
100 .disable = disable_kn02_irq,
101 .ack = ack_kn02_irq,
102 .end = end_kn02_irq,
103};
104
105
106void __init init_kn02_irqs(int base)
107{
108 volatile u32 *csr = (volatile u32 *)KN02_CSR_BASE;
109 unsigned long flags;
110 int i;
111
112 /* Mask interrupts. */
113 spin_lock_irqsave(&kn02_lock, flags);
114 cached_kn02_csr &= ~KN03_CSR_IOINTEN;
115 *csr = cached_kn02_csr;
116 iob();
117 spin_unlock_irqrestore(&kn02_lock, flags);
118
119 for (i = base; i < base + KN02_IRQ_LINES; i++) {
120 irq_desc[i].status = IRQ_DISABLED;
121 irq_desc[i].action = 0;
122 irq_desc[i].depth = 1;
123 irq_desc[i].handler = &kn02_irq_type;
124 }
125
126 kn02_irq_base = base;
127}
diff --git a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile
new file mode 100644
index 000000000000..373822ec2d8c
--- /dev/null
+++ b/arch/mips/dec/prom/Makefile
@@ -0,0 +1,11 @@
1#
2# Makefile for the DECstation prom monitor library routines
3# under Linux.
4#
5
6lib-y += init.o memory.o cmdline.o identify.o console.o
7
8lib-$(CONFIG_MIPS32) += locore.o
9lib-$(CONFIG_MIPS64) += call_o32.o
10
11EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/dec/prom/call_o32.S b/arch/mips/dec/prom/call_o32.S
new file mode 100644
index 000000000000..0dd56db9b3d0
--- /dev/null
+++ b/arch/mips/dec/prom/call_o32.S
@@ -0,0 +1,91 @@
1/*
2 * arch/mips/dec/call_o32.S
3 *
4 * O32 interface for the 64 (or N32) ABI.
5 *
6 * Copyright (C) 2002 Maciej W. Rozycki
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13
14#include <asm/asm.h>
15#include <asm/regdef.h>
16
17/* Maximum number of arguments supported. Must be even! */
18#define O32_ARGC 32
19/* Number of static registers we save. */
20#define O32_STATC 11
21/* Frame size for both of the above. */
22#define O32_FRAMESZ (4 * O32_ARGC + SZREG * O32_STATC)
23
24 .text
25
26/*
27 * O32 function call dispatcher, for interfacing 32-bit ROM routines.
28 *
29 * The standard 64 (N32) calling sequence is supported, with a0
30 * holding a function pointer, a1-a7 -- its first seven arguments
31 * and the stack -- remaining ones (up to O32_ARGC, including a1-a7).
32 * Static registers, gp and fp are preserved, v0 holds a result.
33 * This code relies on the called o32 function for sp and ra
34 * restoration and thus both this dispatcher and the current stack
35 * have to be placed in a KSEGx (or KUSEG) address space. Any
36 * pointers passed have to point to addresses within one of these
37 * spaces as well.
38 */
39NESTED(call_o32, O32_FRAMESZ, ra)
40 REG_SUBU sp,O32_FRAMESZ
41
42 REG_S ra,O32_FRAMESZ-1*SZREG(sp)
43 REG_S fp,O32_FRAMESZ-2*SZREG(sp)
44 REG_S gp,O32_FRAMESZ-3*SZREG(sp)
45 REG_S s7,O32_FRAMESZ-4*SZREG(sp)
46 REG_S s6,O32_FRAMESZ-5*SZREG(sp)
47 REG_S s5,O32_FRAMESZ-6*SZREG(sp)
48 REG_S s4,O32_FRAMESZ-7*SZREG(sp)
49 REG_S s3,O32_FRAMESZ-8*SZREG(sp)
50 REG_S s2,O32_FRAMESZ-9*SZREG(sp)
51 REG_S s1,O32_FRAMESZ-10*SZREG(sp)
52 REG_S s0,O32_FRAMESZ-11*SZREG(sp)
53
54 move jp,a0
55
56 sll a0,a1,zero
57 sll a1,a2,zero
58 sll a2,a3,zero
59 sll a3,a4,zero
60 sw a5,0x10(sp)
61 sw a6,0x14(sp)
62 sw a7,0x18(sp)
63
64 PTR_LA t0,O32_FRAMESZ(sp)
65 PTR_LA t1,0x1c(sp)
66 li t2,O32_ARGC-7
671:
68 lw t3,(t0)
69 REG_ADDU t0,SZREG
70 sw t3,(t1)
71 REG_SUBU t2,1
72 REG_ADDU t1,4
73 bnez t2,1b
74
75 jalr jp
76
77 REG_L s0,O32_FRAMESZ-11*SZREG(sp)
78 REG_L s1,O32_FRAMESZ-10*SZREG(sp)
79 REG_L s2,O32_FRAMESZ-9*SZREG(sp)
80 REG_L s3,O32_FRAMESZ-8*SZREG(sp)
81 REG_L s4,O32_FRAMESZ-7*SZREG(sp)
82 REG_L s5,O32_FRAMESZ-6*SZREG(sp)
83 REG_L s6,O32_FRAMESZ-5*SZREG(sp)
84 REG_L s7,O32_FRAMESZ-4*SZREG(sp)
85 REG_L gp,O32_FRAMESZ-3*SZREG(sp)
86 REG_L fp,O32_FRAMESZ-2*SZREG(sp)
87 REG_L ra,O32_FRAMESZ-1*SZREG(sp)
88
89 REG_ADDU sp,O32_FRAMESZ
90 jr ra
91END(call_o32)
diff --git a/arch/mips/dec/prom/cmdline.c b/arch/mips/dec/prom/cmdline.c
new file mode 100644
index 000000000000..c3490bebbc5d
--- /dev/null
+++ b/arch/mips/dec/prom/cmdline.c
@@ -0,0 +1,39 @@
1/*
2 * cmdline.c: read the command line passed to us by the PROM.
3 *
4 * Copyright (C) 1998 Harald Koerfgen
5 * Copyright (C) 2002, 2004 Maciej W. Rozycki
6 */
7#include <linux/init.h>
8#include <linux/kernel.h>
9#include <linux/string.h>
10#include <linux/types.h>
11
12#include <asm/bootinfo.h>
13#include <asm/dec/prom.h>
14
15#undef PROM_DEBUG
16
17void __init prom_init_cmdline(s32 argc, s32 *argv, u32 magic)
18{
19 char *arg;
20 int start_arg, i;
21
22 /*
23 * collect args and prepare cmd_line
24 */
25 if (!prom_is_rex(magic))
26 start_arg = 1;
27 else
28 start_arg = 2;
29 for (i = start_arg; i < argc; i++) {
30 arg = (void *)(long)(argv[i]);
31 strcat(arcs_cmdline, arg);
32 if (i < (argc - 1))
33 strcat(arcs_cmdline, " ");
34 }
35
36#ifdef PROM_DEBUG
37 printk("arcs_cmdline: %s\n", &(arcs_cmdline[0]));
38#endif
39}
diff --git a/arch/mips/dec/prom/console.c b/arch/mips/dec/prom/console.c
new file mode 100644
index 000000000000..cade16ec7e5a
--- /dev/null
+++ b/arch/mips/dec/prom/console.c
@@ -0,0 +1,55 @@
1/*
2 * arch/mips/dec/prom/console.c
3 *
4 * DECstation PROM-based early console support.
5 *
6 * Copyright (C) 2004 Maciej W. Rozycki
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13#include <linux/console.h>
14#include <linux/init.h>
15#include <linux/kernel.h>
16
17#include <asm/dec/prom.h>
18
19static void __init prom_console_write(struct console *con, const char *s,
20 unsigned int c)
21{
22 static char sfmt[] __initdata = "%%%us";
23 char fmt[13];
24
25 snprintf(fmt, sizeof(fmt), sfmt, c);
26 prom_printf(fmt, s);
27}
28
29static struct console promcons __initdata = {
30 .name = "prom",
31 .write = prom_console_write,
32 .flags = CON_PRINTBUFFER,
33 .index = -1,
34};
35
36static int promcons_output __initdata = 0;
37
38void __init register_prom_console(void)
39{
40 if (!promcons_output) {
41 promcons_output = 1;
42 register_console(&promcons);
43 }
44}
45
46void __init unregister_prom_console(void)
47{
48 if (promcons_output) {
49 unregister_console(&promcons);
50 promcons_output = 0;
51 }
52}
53
54void disable_early_printk(void)
55 __attribute__((alias("unregister_prom_console")));
diff --git a/arch/mips/dec/prom/dectypes.h b/arch/mips/dec/prom/dectypes.h
new file mode 100644
index 000000000000..707b6f1f5a9d
--- /dev/null
+++ b/arch/mips/dec/prom/dectypes.h
@@ -0,0 +1,14 @@
1#ifndef DECTYPES
2#define DECTYPES
3
4#define DS2100_3100 1 /* DS2100/3100 Pmax */
5#define DS5000_200 2 /* DS5000/200 3max */
6#define DS5000_1XX 3 /* DS5000/1xx kmin */
7#define DS5000_2X0 4 /* DS5000/2x0 3max+ */
8#define DS5800 5 /* DS5800 Isis */
9#define DS5400 6 /* DS5400 MIPSfair */
10#define DS5000_XX 7 /* DS5000/xx maxine */
11#define DS5500 11 /* DS5500 MIPSfair-2 */
12#define DS5100 12 /* DS5100 MIPSmate */
13
14#endif
diff --git a/arch/mips/dec/prom/identify.c b/arch/mips/dec/prom/identify.c
new file mode 100644
index 000000000000..9380588cb15c
--- /dev/null
+++ b/arch/mips/dec/prom/identify.c
@@ -0,0 +1,177 @@
1/*
2 * identify.c: machine identification code.
3 *
4 * Copyright (C) 1998 Harald Koerfgen and Paul M. Antoine
5 * Copyright (C) 2002, 2003, 2004 Maciej W. Rozycki
6 */
7#include <linux/init.h>
8#include <linux/kernel.h>
9#include <linux/mc146818rtc.h>
10#include <linux/module.h>
11#include <linux/string.h>
12#include <linux/types.h>
13
14#include <asm/bootinfo.h>
15#include <asm/dec/ioasic.h>
16#include <asm/dec/ioasic_addrs.h>
17#include <asm/dec/kn01.h>
18#include <asm/dec/kn02.h>
19#include <asm/dec/kn02ba.h>
20#include <asm/dec/kn02ca.h>
21#include <asm/dec/kn03.h>
22#include <asm/dec/kn230.h>
23#include <asm/dec/prom.h>
24
25#include "dectypes.h"
26
27extern unsigned long mips_machgroup;
28extern unsigned long mips_machtype;
29
30static const char *dec_system_strings[] = {
31 [MACH_DSUNKNOWN] "unknown DECstation",
32 [MACH_DS23100] "DECstation 2100/3100",
33 [MACH_DS5100] "DECsystem 5100",
34 [MACH_DS5000_200] "DECstation 5000/200",
35 [MACH_DS5000_1XX] "DECstation 5000/1xx",
36 [MACH_DS5000_XX] "Personal DECstation 5000/xx",
37 [MACH_DS5000_2X0] "DECstation 5000/2x0",
38 [MACH_DS5400] "DECsystem 5400",
39 [MACH_DS5500] "DECsystem 5500",
40 [MACH_DS5800] "DECsystem 5800",
41 [MACH_DS5900] "DECsystem 5900",
42};
43
44const char *get_system_type(void)
45{
46#define STR_BUF_LEN 64
47 static char system[STR_BUF_LEN];
48 static int called = 0;
49
50 if (called == 0) {
51 called = 1;
52 snprintf(system, STR_BUF_LEN, "Digital %s",
53 dec_system_strings[mips_machtype]);
54 }
55
56 return system;
57}
58
59
60/*
61 * Setup essential system-specific memory addresses. We need them
62 * early. Semantically the functions belong to prom/init.c, but they
63 * are compact enough we want them inlined. --macro
64 */
65volatile u8 *dec_rtc_base;
66
67EXPORT_SYMBOL(dec_rtc_base);
68
69static inline void prom_init_kn01(void)
70{
71 dec_rtc_base = (void *)KN01_RTC_BASE;
72 dec_kn_slot_size = KN01_SLOT_SIZE;
73}
74
75static inline void prom_init_kn230(void)
76{
77 dec_rtc_base = (void *)KN01_RTC_BASE;
78 dec_kn_slot_size = KN01_SLOT_SIZE;
79}
80
81static inline void prom_init_kn02(void)
82{
83 dec_rtc_base = (void *)KN02_RTC_BASE;
84 dec_kn_slot_size = KN02_SLOT_SIZE;
85}
86
87static inline void prom_init_kn02xa(void)
88{
89 ioasic_base = (void *)KN02XA_IOASIC_BASE;
90 dec_rtc_base = (void *)KN02XA_RTC_BASE;
91 dec_kn_slot_size = IOASIC_SLOT_SIZE;
92}
93
94static inline void prom_init_kn03(void)
95{
96 ioasic_base = (void *)KN03_IOASIC_BASE;
97 dec_rtc_base = (void *)KN03_RTC_BASE;
98 dec_kn_slot_size = IOASIC_SLOT_SIZE;
99}
100
101
102void __init prom_identify_arch(u32 magic)
103{
104 unsigned char dec_cpunum, dec_firmrev, dec_etc, dec_systype;
105 u32 dec_sysid;
106
107 if (!prom_is_rex(magic)) {
108 dec_sysid = simple_strtoul(prom_getenv("systype"),
109 (char **)0, 0);
110 } else {
111 dec_sysid = rex_getsysid();
112 if (dec_sysid == 0) {
113 printk("Zero sysid returned from PROM! "
114 "Assuming a PMAX-like machine.\n");
115 dec_sysid = 1;
116 }
117 }
118
119 dec_cpunum = (dec_sysid & 0xff000000) >> 24;
120 dec_systype = (dec_sysid & 0xff0000) >> 16;
121 dec_firmrev = (dec_sysid & 0xff00) >> 8;
122 dec_etc = dec_sysid & 0xff;
123
124 /* We're obviously one of the DEC machines */
125 mips_machgroup = MACH_GROUP_DEC;
126
127 /*
128 * FIXME: This may not be an exhaustive list of DECStations/Servers!
129 * Put all model-specific initialisation calls here.
130 */
131 switch (dec_systype) {
132 case DS2100_3100:
133 mips_machtype = MACH_DS23100;
134 prom_init_kn01();
135 break;
136 case DS5100: /* DS5100 MIPSMATE */
137 mips_machtype = MACH_DS5100;
138 prom_init_kn230();
139 break;
140 case DS5000_200: /* DS5000 3max */
141 mips_machtype = MACH_DS5000_200;
142 prom_init_kn02();
143 break;
144 case DS5000_1XX: /* DS5000/100 3min */
145 mips_machtype = MACH_DS5000_1XX;
146 prom_init_kn02xa();
147 break;
148 case DS5000_2X0: /* DS5000/240 3max+ or DS5900 bigmax */
149 mips_machtype = MACH_DS5000_2X0;
150 prom_init_kn03();
151 if (!(ioasic_read(IO_REG_SIR) & KN03_IO_INR_3MAXP))
152 mips_machtype = MACH_DS5900;
153 break;
154 case DS5000_XX: /* Personal DS5000/xx maxine */
155 mips_machtype = MACH_DS5000_XX;
156 prom_init_kn02xa();
157 break;
158 case DS5800: /* DS5800 Isis */
159 mips_machtype = MACH_DS5800;
160 break;
161 case DS5400: /* DS5400 MIPSfair */
162 mips_machtype = MACH_DS5400;
163 break;
164 case DS5500: /* DS5500 MIPSfair-2 */
165 mips_machtype = MACH_DS5500;
166 break;
167 default:
168 mips_machtype = MACH_DSUNKNOWN;
169 break;
170 }
171
172 if (mips_machtype == MACH_DSUNKNOWN)
173 printk("This is an %s, id is %x\n",
174 dec_system_strings[mips_machtype], dec_systype);
175 else
176 printk("This is a %s\n", dec_system_strings[mips_machtype]);
177}
diff --git a/arch/mips/dec/prom/init.c b/arch/mips/dec/prom/init.c
new file mode 100644
index 000000000000..60f74256e689
--- /dev/null
+++ b/arch/mips/dec/prom/init.c
@@ -0,0 +1,134 @@
1/*
2 * init.c: PROM library initialisation code.
3 *
4 * Copyright (C) 1998 Harald Koerfgen
5 * Copyright (C) 2002, 2004 Maciej W. Rozycki
6 */
7#include <linux/config.h>
8#include <linux/init.h>
9#include <linux/smp.h>
10#include <linux/string.h>
11#include <linux/types.h>
12
13#include <asm/bootinfo.h>
14#include <asm/cpu.h>
15#include <asm/processor.h>
16
17#include <asm/dec/prom.h>
18
19
20int (*__rex_bootinit)(void);
21int (*__rex_bootread)(void);
22int (*__rex_getbitmap)(memmap *);
23unsigned long *(*__rex_slot_address)(int);
24void *(*__rex_gettcinfo)(void);
25int (*__rex_getsysid)(void);
26void (*__rex_clear_cache)(void);
27
28int (*__prom_getchar)(void);
29char *(*__prom_getenv)(char *);
30int (*__prom_printf)(char *, ...);
31
32int (*__pmax_open)(char*, int);
33int (*__pmax_lseek)(int, long, int);
34int (*__pmax_read)(int, void *, int);
35int (*__pmax_close)(int);
36
37
38/*
39 * Detect which PROM the DECSTATION has, and set the callback vectors
40 * appropriately.
41 */
42void __init which_prom(s32 magic, s32 *prom_vec)
43{
44 /*
45 * No sign of the REX PROM's magic number means we assume a non-REX
46 * machine (i.e. we're on a DS2100/3100, DS5100 or DS5000/2xx)
47 */
48 if (prom_is_rex(magic)) {
49 /*
50 * Set up prom abstraction structure with REX entry points.
51 */
52 __rex_bootinit =
53 (void *)(long)*(prom_vec + REX_PROM_BOOTINIT);
54 __rex_bootread =
55 (void *)(long)*(prom_vec + REX_PROM_BOOTREAD);
56 __rex_getbitmap =
57 (void *)(long)*(prom_vec + REX_PROM_GETBITMAP);
58 __prom_getchar =
59 (void *)(long)*(prom_vec + REX_PROM_GETCHAR);
60 __prom_getenv =
61 (void *)(long)*(prom_vec + REX_PROM_GETENV);
62 __rex_getsysid =
63 (void *)(long)*(prom_vec + REX_PROM_GETSYSID);
64 __rex_gettcinfo =
65 (void *)(long)*(prom_vec + REX_PROM_GETTCINFO);
66 __prom_printf =
67 (void *)(long)*(prom_vec + REX_PROM_PRINTF);
68 __rex_slot_address =
69 (void *)(long)*(prom_vec + REX_PROM_SLOTADDR);
70 __rex_clear_cache =
71 (void *)(long)*(prom_vec + REX_PROM_CLEARCACHE);
72 } else {
73 /*
74 * Set up prom abstraction structure with non-REX entry points.
75 */
76 __prom_getchar = (void *)PMAX_PROM_GETCHAR;
77 __prom_getenv = (void *)PMAX_PROM_GETENV;
78 __prom_printf = (void *)PMAX_PROM_PRINTF;
79 __pmax_open = (void *)PMAX_PROM_OPEN;
80 __pmax_lseek = (void *)PMAX_PROM_LSEEK;
81 __pmax_read = (void *)PMAX_PROM_READ;
82 __pmax_close = (void *)PMAX_PROM_CLOSE;
83 }
84}
85
86void __init prom_init(void)
87{
88 extern void dec_machine_halt(void);
89 static char cpu_msg[] __initdata =
90 "Sorry, this kernel is compiled for a wrong CPU type!\n";
91 static char r3k_msg[] __initdata =
92 "Please recompile with \"CONFIG_CPU_R3000 = y\".\n";
93 static char r4k_msg[] __initdata =
94 "Please recompile with \"CONFIG_CPU_R4x00 = y\".\n";
95 s32 argc = fw_arg0;
96 s32 argv = fw_arg1;
97 u32 magic = fw_arg2;
98 s32 prom_vec = fw_arg3;
99
100 /*
101 * Determine which PROM we have
102 * (and therefore which machine we're on!)
103 */
104 which_prom(magic, prom_vec);
105
106 if (prom_is_rex(magic))
107 rex_clear_cache();
108
109 /* Register the early console. */
110 register_prom_console();
111
112 /* Were we compiled with the right CPU option? */
113#if defined(CONFIG_CPU_R3000)
114 if ((current_cpu_data.cputype == CPU_R4000SC) ||
115 (current_cpu_data.cputype == CPU_R4400SC)) {
116 printk(cpu_msg);
117 printk(r4k_msg);
118 dec_machine_halt();
119 }
120#endif
121
122#if defined(CONFIG_CPU_R4X00)
123 if ((current_cpu_data.cputype == CPU_R3000) ||
124 (current_cpu_data.cputype == CPU_R3000A)) {
125 printk(cpu_msg);
126 printk(r3k_msg);
127 dec_machine_halt();
128 }
129#endif
130
131 prom_meminit(magic);
132 prom_identify_arch(magic);
133 prom_init_cmdline(argc, argv, magic);
134}
diff --git a/arch/mips/dec/prom/locore.S b/arch/mips/dec/prom/locore.S
new file mode 100644
index 000000000000..d9acdcefee81
--- /dev/null
+++ b/arch/mips/dec/prom/locore.S
@@ -0,0 +1,30 @@
1/*
2 * locore.S
3 */
4#include <asm/asm.h>
5#include <asm/regdef.h>
6#include <asm/mipsregs.h>
7
8 .text
9
10/*
11 * Simple general exception handling routine. This one is used for the
12 * Memory sizing routine for pmax machines. HK
13 */
14
15NESTED(genexcept_early, 0, sp)
16 .set noat
17 .set noreorder
18
19 mfc0 k0, CP0_STATUS
20 la k1, mem_err
21
22 sw k0, 0(k1)
23
24 mfc0 k0, CP0_EPC
25 nop
26 addiu k0, 4 # skip the causing instruction
27 jr k0
28 rfe
29END(genexcept_early)
30
diff --git a/arch/mips/dec/prom/memory.c b/arch/mips/dec/prom/memory.c
new file mode 100644
index 000000000000..e4f6f26425ea
--- /dev/null
+++ b/arch/mips/dec/prom/memory.c
@@ -0,0 +1,130 @@
1/*
2 * memory.c: memory initialisation code.
3 *
4 * Copyright (C) 1998 Harald Koerfgen, Frieder Streffer and Paul M. Antoine
5 * Copyright (C) 2000, 2002 Maciej W. Rozycki
6 */
7#include <linux/config.h>
8#include <linux/init.h>
9#include <linux/kernel.h>
10#include <linux/mm.h>
11#include <linux/bootmem.h>
12#include <linux/types.h>
13
14#include <asm/addrspace.h>
15#include <asm/bootinfo.h>
16#include <asm/dec/machtype.h>
17#include <asm/dec/prom.h>
18#include <asm/page.h>
19#include <asm/sections.h>
20
21
22volatile unsigned long mem_err = 0; /* So we know an error occurred */
23
24/*
25 * Probe memory in 4MB chunks, waiting for an error to tell us we've fallen
26 * off the end of real memory. Only suitable for the 2100/3100's (PMAX).
27 */
28
29#define CHUNK_SIZE 0x400000
30
31static inline void pmax_setup_memory_region(void)
32{
33 volatile unsigned char *memory_page, dummy;
34 char old_handler[0x80];
35 extern char genexcept_early;
36
37 /* Install exception handler */
38 memcpy(&old_handler, (void *)(KSEG0 + 0x80), 0x80);
39 memcpy((void *)(KSEG0 + 0x80), &genexcept_early, 0x80);
40
41 /* read unmapped and uncached (KSEG1)
42 * DECstations have at least 4MB RAM
43 * Assume less than 480MB of RAM, as this is max for 5000/2xx
44 * FIXME this should be replaced by the first free page!
45 */
46 for (memory_page = (unsigned char *) KSEG1 + CHUNK_SIZE;
47 (mem_err== 0) && (memory_page < ((unsigned char *) KSEG1+0x1E000000));
48 memory_page += CHUNK_SIZE) {
49 dummy = *memory_page;
50 }
51 memcpy((void *)(KSEG0 + 0x80), &old_handler, 0x80);
52
53 add_memory_region(0, (unsigned long)memory_page - KSEG1 - CHUNK_SIZE,
54 BOOT_MEM_RAM);
55}
56
57/*
58 * Use the REX prom calls to get hold of the memory bitmap, and thence
59 * determine memory size.
60 */
61static inline void rex_setup_memory_region(void)
62{
63 int i, bitmap_size;
64 unsigned long mem_start = 0, mem_size = 0;
65 memmap *bm;
66
67 /* some free 64k */
68 bm = (memmap *)KSEG0ADDR(0x28000);
69
70 bitmap_size = rex_getbitmap(bm);
71
72 for (i = 0; i < bitmap_size; i++) {
73 /* FIXME: very simplistically only add full sets of pages */
74 if (bm->bitmap[i] == 0xff)
75 mem_size += (8 * bm->pagesize);
76 else if (!mem_size)
77 mem_start += (8 * bm->pagesize);
78 else {
79 add_memory_region(mem_start, mem_size, BOOT_MEM_RAM);
80 mem_start += mem_size + (8 * bm->pagesize);
81 mem_size = 0;
82 }
83 }
84 if (mem_size)
85 add_memory_region(mem_start, mem_size, BOOT_MEM_RAM);
86}
87
88void __init prom_meminit(u32 magic)
89{
90 if (!prom_is_rex(magic))
91 pmax_setup_memory_region();
92 else
93 rex_setup_memory_region();
94}
95
96unsigned long __init prom_free_prom_memory(void)
97{
98 unsigned long addr, end;
99
100 /*
101 * Free everything below the kernel itself but leave
102 * the first page reserved for the exception handlers.
103 */
104
105#if defined(CONFIG_DECLANCE) || defined(CONFIG_DECLANCE_MODULE)
106 /*
107 * Leave 128 KB reserved for Lance memory for
108 * IOASIC DECstations.
109 *
110 * XXX: save this address for use in dec_lance.c?
111 */
112 if (IOASIC)
113 end = __pa(&_text) - 0x00020000;
114 else
115#endif
116 end = __pa(&_text);
117
118 addr = PAGE_SIZE;
119 while (addr < end) {
120 ClearPageReserved(virt_to_page(__va(addr)));
121 set_page_count(virt_to_page(__va(addr)), 1);
122 free_page((unsigned long)__va(addr));
123 addr += PAGE_SIZE;
124 }
125
126 printk("Freeing unused PROM memory: %ldk freed\n",
127 (end - PAGE_SIZE) >> 10);
128
129 return end - PAGE_SIZE;
130}
diff --git a/arch/mips/dec/promcon.c b/arch/mips/dec/promcon.c
new file mode 100644
index 000000000000..9f0972f5a702
--- /dev/null
+++ b/arch/mips/dec/promcon.c
@@ -0,0 +1,55 @@
1/*
2 * Wrap-around code for a console using the
3 * DECstation PROM io-routines.
4 *
5 * Copyright (c) 1998 Harald Koerfgen
6 */
7
8#include <linux/tty.h>
9#include <linux/ptrace.h>
10#include <linux/init.h>
11#include <linux/console.h>
12#include <linux/fs.h>
13
14#include <asm/dec/prom.h>
15
16static void prom_console_write(struct console *co, const char *s,
17 unsigned count)
18{
19 unsigned i;
20
21 /*
22 * Now, do each character
23 */
24 for (i = 0; i < count; i++) {
25 if (*s == 10)
26 prom_printf("%c", 13);
27 prom_printf("%c", *s++);
28 }
29}
30
31static int __init prom_console_setup(struct console *co, char *options)
32{
33 return 0;
34}
35
36static struct console sercons =
37{
38 .name = "ttyS",
39 .write = prom_console_write,
40 .setup = prom_console_setup,
41 .flags = CON_PRINTBUFFER,
42 .index = -1,
43};
44
45/*
46 * Register console.
47 */
48
49static int __init prom_console_init(void)
50{
51 register_console(&sercons);
52
53 return 0;
54}
55console_initcall(prom_console_init);
diff --git a/arch/mips/dec/reset.c b/arch/mips/dec/reset.c
new file mode 100644
index 000000000000..7e4d34d0573d
--- /dev/null
+++ b/arch/mips/dec/reset.c
@@ -0,0 +1,41 @@
1/*
2 * Reset a DECstation machine.
3 *
4 * Copyright (C) 199x the Anonymous
5 * Copyright (C) 2001, 2002, 2003 Maciej W. Rozycki
6 */
7#include <linux/interrupt.h>
8#include <linux/linkage.h>
9
10#include <asm/addrspace.h>
11#include <asm/ptrace.h>
12
13typedef void ATTRIB_NORET (* noret_func_t)(void);
14
15static inline void ATTRIB_NORET back_to_prom(void)
16{
17 noret_func_t func = (void *) KSEG1ADDR(0x1fc00000);
18
19 func();
20}
21
22void ATTRIB_NORET dec_machine_restart(char *command)
23{
24 back_to_prom();
25}
26
27void ATTRIB_NORET dec_machine_halt(void)
28{
29 back_to_prom();
30}
31
32void ATTRIB_NORET dec_machine_power_off(void)
33{
34 /* DECstations don't have a software power switch */
35 back_to_prom();
36}
37
38irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs)
39{
40 dec_machine_halt();
41}
diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c
new file mode 100644
index 000000000000..6a69309baf40
--- /dev/null
+++ b/arch/mips/dec/setup.c
@@ -0,0 +1,750 @@
1/*
2 * Setup the interrupt stuff.
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
6 * for more details.
7 *
8 * Copyright (C) 1998 Harald Koerfgen
9 * Copyright (C) 2000, 2001, 2002, 2003 Maciej W. Rozycki
10 */
11#include <linux/sched.h>
12#include <linux/interrupt.h>
13#include <linux/param.h>
14#include <linux/console.h>
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/spinlock.h>
18#include <linux/types.h>
19
20#include <asm/bootinfo.h>
21#include <asm/cpu.h>
22#include <asm/cpu-features.h>
23#include <asm/irq.h>
24#include <asm/irq_cpu.h>
25#include <asm/mipsregs.h>
26#include <asm/reboot.h>
27#include <asm/time.h>
28#include <asm/traps.h>
29#include <asm/wbflush.h>
30
31#include <asm/dec/interrupts.h>
32#include <asm/dec/ioasic.h>
33#include <asm/dec/ioasic_addrs.h>
34#include <asm/dec/ioasic_ints.h>
35#include <asm/dec/kn01.h>
36#include <asm/dec/kn02.h>
37#include <asm/dec/kn02ba.h>
38#include <asm/dec/kn02ca.h>
39#include <asm/dec/kn03.h>
40#include <asm/dec/kn230.h>
41
42
43extern void dec_machine_restart(char *command);
44extern void dec_machine_halt(void);
45extern void dec_machine_power_off(void);
46extern irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs);
47
48extern asmlinkage void decstation_handle_int(void);
49
50spinlock_t ioasic_ssr_lock;
51
52volatile u32 *ioasic_base;
53unsigned long dec_kn_slot_size;
54
55/*
56 * IRQ routing and priority tables. Priorites are set as follows:
57 *
58 * KN01 KN230 KN02 KN02-BA KN02-CA KN03
59 *
60 * MEMORY CPU CPU CPU ASIC CPU CPU
61 * RTC CPU CPU CPU ASIC CPU CPU
62 * DMA - - - ASIC ASIC ASIC
63 * SERIAL0 CPU CPU CSR ASIC ASIC ASIC
64 * SERIAL1 - - - ASIC - ASIC
65 * SCSI CPU CPU CSR ASIC ASIC ASIC
66 * ETHERNET CPU * CSR ASIC ASIC ASIC
67 * other - - - ASIC - -
68 * TC2 - - CSR CPU ASIC ASIC
69 * TC1 - - CSR CPU ASIC ASIC
70 * TC0 - - CSR CPU ASIC ASIC
71 * other - CPU - CPU ASIC ASIC
72 * other - - - - CPU CPU
73 *
74 * * -- shared with SCSI
75 */
76
77int dec_interrupt[DEC_NR_INTS] = {
78 [0 ... DEC_NR_INTS - 1] = -1
79};
80int_ptr cpu_mask_nr_tbl[DEC_MAX_CPU_INTS][2] = {
81 { { .i = ~0 }, { .p = dec_intr_unimplemented } },
82};
83int_ptr asic_mask_nr_tbl[DEC_MAX_ASIC_INTS][2] = {
84 { { .i = ~0 }, { .p = asic_intr_unimplemented } },
85};
86int cpu_fpu_mask = DEC_CPU_IRQ_MASK(DEC_CPU_INR_FPU);
87
88static struct irqaction ioirq = {
89 .handler = no_action,
90 .name = "cascade",
91};
92static struct irqaction fpuirq = {
93 .handler = no_action,
94 .name = "fpu",
95};
96
97static struct irqaction busirq = {
98 .flags = SA_INTERRUPT,
99 .name = "bus error",
100};
101
102static struct irqaction haltirq = {
103 .handler = dec_intr_halt,
104 .name = "halt",
105};
106
107
108/*
109 * Bus error (DBE/IBE exceptions and bus interrupts) handling setup.
110 */
111void __init dec_be_init(void)
112{
113 switch (mips_machtype) {
114 case MACH_DS23100: /* DS2100/DS3100 Pmin/Pmax */
115 busirq.flags |= SA_SHIRQ;
116 break;
117 case MACH_DS5000_200: /* DS5000/200 3max */
118 case MACH_DS5000_2X0: /* DS5000/240 3max+ */
119 case MACH_DS5900: /* DS5900 bigmax */
120 board_be_handler = dec_ecc_be_handler;
121 busirq.handler = dec_ecc_be_interrupt;
122 dec_ecc_be_init();
123 break;
124 }
125}
126
127
128extern void dec_time_init(void);
129extern void dec_timer_setup(struct irqaction *);
130
131static void __init decstation_setup(void)
132{
133 board_be_init = dec_be_init;
134 board_time_init = dec_time_init;
135 board_timer_setup = dec_timer_setup;
136
137 wbflush_setup();
138
139 _machine_restart = dec_machine_restart;
140 _machine_halt = dec_machine_halt;
141 _machine_power_off = dec_machine_power_off;
142}
143
144early_initcall(decstation_setup);
145
146/*
147 * Machine-specific initialisation for KN01, aka DS2100 (aka Pmin)
148 * or DS3100 (aka Pmax).
149 */
150static int kn01_interrupt[DEC_NR_INTS] __initdata = {
151 [DEC_IRQ_CASCADE] = -1,
152 [DEC_IRQ_AB_RECV] = -1,
153 [DEC_IRQ_AB_XMIT] = -1,
154 [DEC_IRQ_DZ11] = DEC_CPU_IRQ_NR(KN01_CPU_INR_DZ11),
155 [DEC_IRQ_ASC] = -1,
156 [DEC_IRQ_FLOPPY] = -1,
157 [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU),
158 [DEC_IRQ_HALT] = -1,
159 [DEC_IRQ_ISDN] = -1,
160 [DEC_IRQ_LANCE] = DEC_CPU_IRQ_NR(KN01_CPU_INR_LANCE),
161 [DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN01_CPU_INR_BUS),
162 [DEC_IRQ_PSU] = -1,
163 [DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN01_CPU_INR_RTC),
164 [DEC_IRQ_SCC0] = -1,
165 [DEC_IRQ_SCC1] = -1,
166 [DEC_IRQ_SII] = DEC_CPU_IRQ_NR(KN01_CPU_INR_SII),
167 [DEC_IRQ_TC0] = -1,
168 [DEC_IRQ_TC1] = -1,
169 [DEC_IRQ_TC2] = -1,
170 [DEC_IRQ_TIMER] = -1,
171 [DEC_IRQ_VIDEO] = DEC_CPU_IRQ_NR(KN01_CPU_INR_VIDEO),
172 [DEC_IRQ_ASC_MERR] = -1,
173 [DEC_IRQ_ASC_ERR] = -1,
174 [DEC_IRQ_ASC_DMA] = -1,
175 [DEC_IRQ_FLOPPY_ERR] = -1,
176 [DEC_IRQ_ISDN_ERR] = -1,
177 [DEC_IRQ_ISDN_RXDMA] = -1,
178 [DEC_IRQ_ISDN_TXDMA] = -1,
179 [DEC_IRQ_LANCE_MERR] = -1,
180 [DEC_IRQ_SCC0A_RXERR] = -1,
181 [DEC_IRQ_SCC0A_RXDMA] = -1,
182 [DEC_IRQ_SCC0A_TXERR] = -1,
183 [DEC_IRQ_SCC0A_TXDMA] = -1,
184 [DEC_IRQ_AB_RXERR] = -1,
185 [DEC_IRQ_AB_RXDMA] = -1,
186 [DEC_IRQ_AB_TXERR] = -1,
187 [DEC_IRQ_AB_TXDMA] = -1,
188 [DEC_IRQ_SCC1A_RXERR] = -1,
189 [DEC_IRQ_SCC1A_RXDMA] = -1,
190 [DEC_IRQ_SCC1A_TXERR] = -1,
191 [DEC_IRQ_SCC1A_TXDMA] = -1,
192};
193
194static int_ptr kn01_cpu_mask_nr_tbl[][2] __initdata = {
195 { { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_BUS) },
196 { .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_BUS) } },
197 { { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_RTC) },
198 { .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_RTC) } },
199 { { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_DZ11) },
200 { .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_DZ11) } },
201 { { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_SII) },
202 { .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_SII) } },
203 { { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_LANCE) },
204 { .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_LANCE) } },
205 { { .i = DEC_CPU_IRQ_ALL },
206 { .p = cpu_all_int } },
207};
208
209void __init dec_init_kn01(void)
210{
211 /* IRQ routing. */
212 memcpy(&dec_interrupt, &kn01_interrupt,
213 sizeof(kn01_interrupt));
214
215 /* CPU IRQ priorities. */
216 memcpy(&cpu_mask_nr_tbl, &kn01_cpu_mask_nr_tbl,
217 sizeof(kn01_cpu_mask_nr_tbl));
218
219 mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
220
221} /* dec_init_kn01 */
222
223
224/*
225 * Machine-specific initialisation for KN230, aka DS5100, aka MIPSmate.
226 */
227static int kn230_interrupt[DEC_NR_INTS] __initdata = {
228 [DEC_IRQ_CASCADE] = -1,
229 [DEC_IRQ_AB_RECV] = -1,
230 [DEC_IRQ_AB_XMIT] = -1,
231 [DEC_IRQ_DZ11] = DEC_CPU_IRQ_NR(KN230_CPU_INR_DZ11),
232 [DEC_IRQ_ASC] = -1,
233 [DEC_IRQ_FLOPPY] = -1,
234 [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU),
235 [DEC_IRQ_HALT] = DEC_CPU_IRQ_NR(KN230_CPU_INR_HALT),
236 [DEC_IRQ_ISDN] = -1,
237 [DEC_IRQ_LANCE] = DEC_CPU_IRQ_NR(KN230_CPU_INR_LANCE),
238 [DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN230_CPU_INR_BUS),
239 [DEC_IRQ_PSU] = -1,
240 [DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN230_CPU_INR_RTC),
241 [DEC_IRQ_SCC0] = -1,
242 [DEC_IRQ_SCC1] = -1,
243 [DEC_IRQ_SII] = DEC_CPU_IRQ_NR(KN230_CPU_INR_SII),
244 [DEC_IRQ_TC0] = -1,
245 [DEC_IRQ_TC1] = -1,
246 [DEC_IRQ_TC2] = -1,
247 [DEC_IRQ_TIMER] = -1,
248 [DEC_IRQ_VIDEO] = -1,
249 [DEC_IRQ_ASC_MERR] = -1,
250 [DEC_IRQ_ASC_ERR] = -1,
251 [DEC_IRQ_ASC_DMA] = -1,
252 [DEC_IRQ_FLOPPY_ERR] = -1,
253 [DEC_IRQ_ISDN_ERR] = -1,
254 [DEC_IRQ_ISDN_RXDMA] = -1,
255 [DEC_IRQ_ISDN_TXDMA] = -1,
256 [DEC_IRQ_LANCE_MERR] = -1,
257 [DEC_IRQ_SCC0A_RXERR] = -1,
258 [DEC_IRQ_SCC0A_RXDMA] = -1,
259 [DEC_IRQ_SCC0A_TXERR] = -1,
260 [DEC_IRQ_SCC0A_TXDMA] = -1,
261 [DEC_IRQ_AB_RXERR] = -1,
262 [DEC_IRQ_AB_RXDMA] = -1,
263 [DEC_IRQ_AB_TXERR] = -1,
264 [DEC_IRQ_AB_TXDMA] = -1,
265 [DEC_IRQ_SCC1A_RXERR] = -1,
266 [DEC_IRQ_SCC1A_RXDMA] = -1,
267 [DEC_IRQ_SCC1A_TXERR] = -1,
268 [DEC_IRQ_SCC1A_TXDMA] = -1,
269};
270
271static int_ptr kn230_cpu_mask_nr_tbl[][2] __initdata = {
272 { { .i = DEC_CPU_IRQ_MASK(KN230_CPU_INR_BUS) },
273 { .i = DEC_CPU_IRQ_NR(KN230_CPU_INR_BUS) } },
274 { { .i = DEC_CPU_IRQ_MASK(KN230_CPU_INR_RTC) },
275 { .i = DEC_CPU_IRQ_NR(KN230_CPU_INR_RTC) } },
276 { { .i = DEC_CPU_IRQ_MASK(KN230_CPU_INR_DZ11) },
277 { .i = DEC_CPU_IRQ_NR(KN230_CPU_INR_DZ11) } },
278 { { .i = DEC_CPU_IRQ_MASK(KN230_CPU_INR_SII) },
279 { .i = DEC_CPU_IRQ_NR(KN230_CPU_INR_SII) } },
280 { { .i = DEC_CPU_IRQ_ALL },
281 { .p = cpu_all_int } },
282};
283
284void __init dec_init_kn230(void)
285{
286 /* IRQ routing. */
287 memcpy(&dec_interrupt, &kn230_interrupt,
288 sizeof(kn230_interrupt));
289
290 /* CPU IRQ priorities. */
291 memcpy(&cpu_mask_nr_tbl, &kn230_cpu_mask_nr_tbl,
292 sizeof(kn230_cpu_mask_nr_tbl));
293
294 mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
295
296} /* dec_init_kn230 */
297
298
299/*
300 * Machine-specific initialisation for KN02, aka DS5000/200, aka 3max.
301 */
302static int kn02_interrupt[DEC_NR_INTS] __initdata = {
303 [DEC_IRQ_CASCADE] = DEC_CPU_IRQ_NR(KN02_CPU_INR_CASCADE),
304 [DEC_IRQ_AB_RECV] = -1,
305 [DEC_IRQ_AB_XMIT] = -1,
306 [DEC_IRQ_DZ11] = KN02_IRQ_NR(KN02_CSR_INR_DZ11),
307 [DEC_IRQ_ASC] = KN02_IRQ_NR(KN02_CSR_INR_ASC),
308 [DEC_IRQ_FLOPPY] = -1,
309 [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU),
310 [DEC_IRQ_HALT] = -1,
311 [DEC_IRQ_ISDN] = -1,
312 [DEC_IRQ_LANCE] = KN02_IRQ_NR(KN02_CSR_INR_LANCE),
313 [DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN02_CPU_INR_BUS),
314 [DEC_IRQ_PSU] = -1,
315 [DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN02_CPU_INR_RTC),
316 [DEC_IRQ_SCC0] = -1,
317 [DEC_IRQ_SCC1] = -1,
318 [DEC_IRQ_SII] = -1,
319 [DEC_IRQ_TC0] = KN02_IRQ_NR(KN02_CSR_INR_TC0),
320 [DEC_IRQ_TC1] = KN02_IRQ_NR(KN02_CSR_INR_TC1),
321 [DEC_IRQ_TC2] = KN02_IRQ_NR(KN02_CSR_INR_TC2),
322 [DEC_IRQ_TIMER] = -1,
323 [DEC_IRQ_VIDEO] = -1,
324 [DEC_IRQ_ASC_MERR] = -1,
325 [DEC_IRQ_ASC_ERR] = -1,
326 [DEC_IRQ_ASC_DMA] = -1,
327 [DEC_IRQ_FLOPPY_ERR] = -1,
328 [DEC_IRQ_ISDN_ERR] = -1,
329 [DEC_IRQ_ISDN_RXDMA] = -1,
330 [DEC_IRQ_ISDN_TXDMA] = -1,
331 [DEC_IRQ_LANCE_MERR] = -1,
332 [DEC_IRQ_SCC0A_RXERR] = -1,
333 [DEC_IRQ_SCC0A_RXDMA] = -1,
334 [DEC_IRQ_SCC0A_TXERR] = -1,
335 [DEC_IRQ_SCC0A_TXDMA] = -1,
336 [DEC_IRQ_AB_RXERR] = -1,
337 [DEC_IRQ_AB_RXDMA] = -1,
338 [DEC_IRQ_AB_TXERR] = -1,
339 [DEC_IRQ_AB_TXDMA] = -1,
340 [DEC_IRQ_SCC1A_RXERR] = -1,
341 [DEC_IRQ_SCC1A_RXDMA] = -1,
342 [DEC_IRQ_SCC1A_TXERR] = -1,
343 [DEC_IRQ_SCC1A_TXDMA] = -1,
344};
345
346static int_ptr kn02_cpu_mask_nr_tbl[][2] __initdata = {
347 { { .i = DEC_CPU_IRQ_MASK(KN02_CPU_INR_BUS) },
348 { .i = DEC_CPU_IRQ_NR(KN02_CPU_INR_BUS) } },
349 { { .i = DEC_CPU_IRQ_MASK(KN02_CPU_INR_RTC) },
350 { .i = DEC_CPU_IRQ_NR(KN02_CPU_INR_RTC) } },
351 { { .i = DEC_CPU_IRQ_MASK(KN02_CPU_INR_CASCADE) },
352 { .p = kn02_io_int } },
353 { { .i = DEC_CPU_IRQ_ALL },
354 { .p = cpu_all_int } },
355};
356
357static int_ptr kn02_asic_mask_nr_tbl[][2] __initdata = {
358 { { .i = KN02_IRQ_MASK(KN02_CSR_INR_DZ11) },
359 { .i = KN02_IRQ_NR(KN02_CSR_INR_DZ11) } },
360 { { .i = KN02_IRQ_MASK(KN02_CSR_INR_ASC) },
361 { .i = KN02_IRQ_NR(KN02_CSR_INR_ASC) } },
362 { { .i = KN02_IRQ_MASK(KN02_CSR_INR_LANCE) },
363 { .i = KN02_IRQ_NR(KN02_CSR_INR_LANCE) } },
364 { { .i = KN02_IRQ_MASK(KN02_CSR_INR_TC2) },
365 { .i = KN02_IRQ_NR(KN02_CSR_INR_TC2) } },
366 { { .i = KN02_IRQ_MASK(KN02_CSR_INR_TC1) },
367 { .i = KN02_IRQ_NR(KN02_CSR_INR_TC1) } },
368 { { .i = KN02_IRQ_MASK(KN02_CSR_INR_TC0) },
369 { .i = KN02_IRQ_NR(KN02_CSR_INR_TC0) } },
370 { { .i = KN02_IRQ_ALL },
371 { .p = kn02_all_int } },
372};
373
374void __init dec_init_kn02(void)
375{
376 /* IRQ routing. */
377 memcpy(&dec_interrupt, &kn02_interrupt,
378 sizeof(kn02_interrupt));
379
380 /* CPU IRQ priorities. */
381 memcpy(&cpu_mask_nr_tbl, &kn02_cpu_mask_nr_tbl,
382 sizeof(kn02_cpu_mask_nr_tbl));
383
384 /* KN02 CSR IRQ priorities. */
385 memcpy(&asic_mask_nr_tbl, &kn02_asic_mask_nr_tbl,
386 sizeof(kn02_asic_mask_nr_tbl));
387
388 mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
389 init_kn02_irqs(KN02_IRQ_BASE);
390
391} /* dec_init_kn02 */
392
393
394/*
395 * Machine-specific initialisation for KN02-BA, aka DS5000/1xx
396 * (xx = 20, 25, 33), aka 3min. Also applies to KN04(-BA), aka
397 * DS5000/150, aka 4min.
398 */
399static int kn02ba_interrupt[DEC_NR_INTS] __initdata = {
400 [DEC_IRQ_CASCADE] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_CASCADE),
401 [DEC_IRQ_AB_RECV] = -1,
402 [DEC_IRQ_AB_XMIT] = -1,
403 [DEC_IRQ_DZ11] = -1,
404 [DEC_IRQ_ASC] = IO_IRQ_NR(KN02BA_IO_INR_ASC),
405 [DEC_IRQ_FLOPPY] = -1,
406 [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU),
407 [DEC_IRQ_HALT] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_HALT),
408 [DEC_IRQ_ISDN] = -1,
409 [DEC_IRQ_LANCE] = IO_IRQ_NR(KN02BA_IO_INR_LANCE),
410 [DEC_IRQ_BUS] = IO_IRQ_NR(KN02BA_IO_INR_BUS),
411 [DEC_IRQ_PSU] = IO_IRQ_NR(KN02BA_IO_INR_PSU),
412 [DEC_IRQ_RTC] = IO_IRQ_NR(KN02BA_IO_INR_RTC),
413 [DEC_IRQ_SCC0] = IO_IRQ_NR(KN02BA_IO_INR_SCC0),
414 [DEC_IRQ_SCC1] = IO_IRQ_NR(KN02BA_IO_INR_SCC1),
415 [DEC_IRQ_SII] = -1,
416 [DEC_IRQ_TC0] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC0),
417 [DEC_IRQ_TC1] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC1),
418 [DEC_IRQ_TC2] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC2),
419 [DEC_IRQ_TIMER] = -1,
420 [DEC_IRQ_VIDEO] = -1,
421 [DEC_IRQ_ASC_MERR] = IO_IRQ_NR(IO_INR_ASC_MERR),
422 [DEC_IRQ_ASC_ERR] = IO_IRQ_NR(IO_INR_ASC_ERR),
423 [DEC_IRQ_ASC_DMA] = IO_IRQ_NR(IO_INR_ASC_DMA),
424 [DEC_IRQ_FLOPPY_ERR] = -1,
425 [DEC_IRQ_ISDN_ERR] = -1,
426 [DEC_IRQ_ISDN_RXDMA] = -1,
427 [DEC_IRQ_ISDN_TXDMA] = -1,
428 [DEC_IRQ_LANCE_MERR] = IO_IRQ_NR(IO_INR_LANCE_MERR),
429 [DEC_IRQ_SCC0A_RXERR] = IO_IRQ_NR(IO_INR_SCC0A_RXERR),
430 [DEC_IRQ_SCC0A_RXDMA] = IO_IRQ_NR(IO_INR_SCC0A_RXDMA),
431 [DEC_IRQ_SCC0A_TXERR] = IO_IRQ_NR(IO_INR_SCC0A_TXERR),
432 [DEC_IRQ_SCC0A_TXDMA] = IO_IRQ_NR(IO_INR_SCC0A_TXDMA),
433 [DEC_IRQ_AB_RXERR] = -1,
434 [DEC_IRQ_AB_RXDMA] = -1,
435 [DEC_IRQ_AB_TXERR] = -1,
436 [DEC_IRQ_AB_TXDMA] = -1,
437 [DEC_IRQ_SCC1A_RXERR] = IO_IRQ_NR(IO_INR_SCC1A_RXERR),
438 [DEC_IRQ_SCC1A_RXDMA] = IO_IRQ_NR(IO_INR_SCC1A_RXDMA),
439 [DEC_IRQ_SCC1A_TXERR] = IO_IRQ_NR(IO_INR_SCC1A_TXERR),
440 [DEC_IRQ_SCC1A_TXDMA] = IO_IRQ_NR(IO_INR_SCC1A_TXDMA),
441};
442
443static int_ptr kn02ba_cpu_mask_nr_tbl[][2] __initdata = {
444 { { .i = DEC_CPU_IRQ_MASK(KN02BA_CPU_INR_CASCADE) },
445 { .p = kn02xa_io_int } },
446 { { .i = DEC_CPU_IRQ_MASK(KN02BA_CPU_INR_TC2) },
447 { .i = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC2) } },
448 { { .i = DEC_CPU_IRQ_MASK(KN02BA_CPU_INR_TC1) },
449 { .i = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC1) } },
450 { { .i = DEC_CPU_IRQ_MASK(KN02BA_CPU_INR_TC0) },
451 { .i = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC0) } },
452 { { .i = DEC_CPU_IRQ_ALL },
453 { .p = cpu_all_int } },
454};
455
456static int_ptr kn02ba_asic_mask_nr_tbl[][2] __initdata = {
457 { { .i = IO_IRQ_MASK(KN02BA_IO_INR_BUS) },
458 { .i = IO_IRQ_NR(KN02BA_IO_INR_BUS) } },
459 { { .i = IO_IRQ_MASK(KN02BA_IO_INR_RTC) },
460 { .i = IO_IRQ_NR(KN02BA_IO_INR_RTC) } },
461 { { .i = IO_IRQ_DMA },
462 { .p = asic_dma_int } },
463 { { .i = IO_IRQ_MASK(KN02BA_IO_INR_SCC0) },
464 { .i = IO_IRQ_NR(KN02BA_IO_INR_SCC0) } },
465 { { .i = IO_IRQ_MASK(KN02BA_IO_INR_SCC1) },
466 { .i = IO_IRQ_NR(KN02BA_IO_INR_SCC1) } },
467 { { .i = IO_IRQ_MASK(KN02BA_IO_INR_ASC) },
468 { .i = IO_IRQ_NR(KN02BA_IO_INR_ASC) } },
469 { { .i = IO_IRQ_MASK(KN02BA_IO_INR_LANCE) },
470 { .i = IO_IRQ_NR(KN02BA_IO_INR_LANCE) } },
471 { { .i = IO_IRQ_ALL },
472 { .p = asic_all_int } },
473};
474
475void __init dec_init_kn02ba(void)
476{
477 /* IRQ routing. */
478 memcpy(&dec_interrupt, &kn02ba_interrupt,
479 sizeof(kn02ba_interrupt));
480
481 /* CPU IRQ priorities. */
482 memcpy(&cpu_mask_nr_tbl, &kn02ba_cpu_mask_nr_tbl,
483 sizeof(kn02ba_cpu_mask_nr_tbl));
484
485 /* I/O ASIC IRQ priorities. */
486 memcpy(&asic_mask_nr_tbl, &kn02ba_asic_mask_nr_tbl,
487 sizeof(kn02ba_asic_mask_nr_tbl));
488
489 mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
490 init_ioasic_irqs(IO_IRQ_BASE);
491
492} /* dec_init_kn02ba */
493
494
495/*
496 * Machine-specific initialisation for KN02-CA, aka DS5000/xx,
497 * (xx = 20, 25, 33), aka MAXine. Also applies to KN04(-CA), aka
498 * DS5000/50, aka 4MAXine.
499 */
500static int kn02ca_interrupt[DEC_NR_INTS] __initdata = {
501 [DEC_IRQ_CASCADE] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_CASCADE),
502 [DEC_IRQ_AB_RECV] = IO_IRQ_NR(KN02CA_IO_INR_AB_RECV),
503 [DEC_IRQ_AB_XMIT] = IO_IRQ_NR(KN02CA_IO_INR_AB_XMIT),
504 [DEC_IRQ_DZ11] = -1,
505 [DEC_IRQ_ASC] = IO_IRQ_NR(KN02CA_IO_INR_ASC),
506 [DEC_IRQ_FLOPPY] = IO_IRQ_NR(KN02CA_IO_INR_FLOPPY),
507 [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU),
508 [DEC_IRQ_HALT] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_HALT),
509 [DEC_IRQ_ISDN] = IO_IRQ_NR(KN02CA_IO_INR_ISDN),
510 [DEC_IRQ_LANCE] = IO_IRQ_NR(KN02CA_IO_INR_LANCE),
511 [DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_BUS),
512 [DEC_IRQ_PSU] = -1,
513 [DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_RTC),
514 [DEC_IRQ_SCC0] = IO_IRQ_NR(KN02CA_IO_INR_SCC0),
515 [DEC_IRQ_SCC1] = -1,
516 [DEC_IRQ_SII] = -1,
517 [DEC_IRQ_TC0] = IO_IRQ_NR(KN02CA_IO_INR_TC0),
518 [DEC_IRQ_TC1] = IO_IRQ_NR(KN02CA_IO_INR_TC1),
519 [DEC_IRQ_TC2] = -1,
520 [DEC_IRQ_TIMER] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_TIMER),
521 [DEC_IRQ_VIDEO] = IO_IRQ_NR(KN02CA_IO_INR_VIDEO),
522 [DEC_IRQ_ASC_MERR] = IO_IRQ_NR(IO_INR_ASC_MERR),
523 [DEC_IRQ_ASC_ERR] = IO_IRQ_NR(IO_INR_ASC_ERR),
524 [DEC_IRQ_ASC_DMA] = IO_IRQ_NR(IO_INR_ASC_DMA),
525 [DEC_IRQ_FLOPPY_ERR] = IO_IRQ_NR(IO_INR_FLOPPY_ERR),
526 [DEC_IRQ_ISDN_ERR] = IO_IRQ_NR(IO_INR_ISDN_ERR),
527 [DEC_IRQ_ISDN_RXDMA] = IO_IRQ_NR(IO_INR_ISDN_RXDMA),
528 [DEC_IRQ_ISDN_TXDMA] = IO_IRQ_NR(IO_INR_ISDN_TXDMA),
529 [DEC_IRQ_LANCE_MERR] = IO_IRQ_NR(IO_INR_LANCE_MERR),
530 [DEC_IRQ_SCC0A_RXERR] = IO_IRQ_NR(IO_INR_SCC0A_RXERR),
531 [DEC_IRQ_SCC0A_RXDMA] = IO_IRQ_NR(IO_INR_SCC0A_RXDMA),
532 [DEC_IRQ_SCC0A_TXERR] = IO_IRQ_NR(IO_INR_SCC0A_TXERR),
533 [DEC_IRQ_SCC0A_TXDMA] = IO_IRQ_NR(IO_INR_SCC0A_TXDMA),
534 [DEC_IRQ_AB_RXERR] = IO_IRQ_NR(IO_INR_AB_RXERR),
535 [DEC_IRQ_AB_RXDMA] = IO_IRQ_NR(IO_INR_AB_RXDMA),
536 [DEC_IRQ_AB_TXERR] = IO_IRQ_NR(IO_INR_AB_TXERR),
537 [DEC_IRQ_AB_TXDMA] = IO_IRQ_NR(IO_INR_AB_TXDMA),
538 [DEC_IRQ_SCC1A_RXERR] = -1,
539 [DEC_IRQ_SCC1A_RXDMA] = -1,
540 [DEC_IRQ_SCC1A_TXERR] = -1,
541 [DEC_IRQ_SCC1A_TXDMA] = -1,
542};
543
544static int_ptr kn02ca_cpu_mask_nr_tbl[][2] __initdata = {
545 { { .i = DEC_CPU_IRQ_MASK(KN02CA_CPU_INR_BUS) },
546 { .i = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_BUS) } },
547 { { .i = DEC_CPU_IRQ_MASK(KN02CA_CPU_INR_RTC) },
548 { .i = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_RTC) } },
549 { { .i = DEC_CPU_IRQ_MASK(KN02CA_CPU_INR_CASCADE) },
550 { .p = kn02xa_io_int } },
551 { { .i = DEC_CPU_IRQ_ALL },
552 { .p = cpu_all_int } },
553};
554
555static int_ptr kn02ca_asic_mask_nr_tbl[][2] __initdata = {
556 { { .i = IO_IRQ_DMA },
557 { .p = asic_dma_int } },
558 { { .i = IO_IRQ_MASK(KN02CA_IO_INR_SCC0) },
559 { .i = IO_IRQ_NR(KN02CA_IO_INR_SCC0) } },
560 { { .i = IO_IRQ_MASK(KN02CA_IO_INR_ASC) },
561 { .i = IO_IRQ_NR(KN02CA_IO_INR_ASC) } },
562 { { .i = IO_IRQ_MASK(KN02CA_IO_INR_LANCE) },
563 { .i = IO_IRQ_NR(KN02CA_IO_INR_LANCE) } },
564 { { .i = IO_IRQ_MASK(KN02CA_IO_INR_TC1) },
565 { .i = IO_IRQ_NR(KN02CA_IO_INR_TC1) } },
566 { { .i = IO_IRQ_MASK(KN02CA_IO_INR_TC0) },
567 { .i = IO_IRQ_NR(KN02CA_IO_INR_TC0) } },
568 { { .i = IO_IRQ_ALL },
569 { .p = asic_all_int } },
570};
571
572void __init dec_init_kn02ca(void)
573{
574 /* IRQ routing. */
575 memcpy(&dec_interrupt, &kn02ca_interrupt,
576 sizeof(kn02ca_interrupt));
577
578 /* CPU IRQ priorities. */
579 memcpy(&cpu_mask_nr_tbl, &kn02ca_cpu_mask_nr_tbl,
580 sizeof(kn02ca_cpu_mask_nr_tbl));
581
582 /* I/O ASIC IRQ priorities. */
583 memcpy(&asic_mask_nr_tbl, &kn02ca_asic_mask_nr_tbl,
584 sizeof(kn02ca_asic_mask_nr_tbl));
585
586 mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
587 init_ioasic_irqs(IO_IRQ_BASE);
588
589} /* dec_init_kn02ca */
590
591
592/*
593 * Machine-specific initialisation for KN03, aka DS5000/240,
594 * aka 3max+ and DS5900, aka BIGmax. Also applies to KN05, aka
595 * DS5000/260, aka 4max+ and DS5900/260.
596 */
597static int kn03_interrupt[DEC_NR_INTS] __initdata = {
598 [DEC_IRQ_CASCADE] = DEC_CPU_IRQ_NR(KN03_CPU_INR_CASCADE),
599 [DEC_IRQ_AB_RECV] = -1,
600 [DEC_IRQ_AB_XMIT] = -1,
601 [DEC_IRQ_DZ11] = -1,
602 [DEC_IRQ_ASC] = IO_IRQ_NR(KN03_IO_INR_ASC),
603 [DEC_IRQ_FLOPPY] = -1,
604 [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU),
605 [DEC_IRQ_HALT] = DEC_CPU_IRQ_NR(KN03_CPU_INR_HALT),
606 [DEC_IRQ_ISDN] = -1,
607 [DEC_IRQ_LANCE] = IO_IRQ_NR(KN03_IO_INR_LANCE),
608 [DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN03_CPU_INR_BUS),
609 [DEC_IRQ_PSU] = IO_IRQ_NR(KN03_IO_INR_PSU),
610 [DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN03_CPU_INR_RTC),
611 [DEC_IRQ_SCC0] = IO_IRQ_NR(KN03_IO_INR_SCC0),
612 [DEC_IRQ_SCC1] = IO_IRQ_NR(KN03_IO_INR_SCC1),
613 [DEC_IRQ_SII] = -1,
614 [DEC_IRQ_TC0] = IO_IRQ_NR(KN03_IO_INR_TC0),
615 [DEC_IRQ_TC1] = IO_IRQ_NR(KN03_IO_INR_TC1),
616 [DEC_IRQ_TC2] = IO_IRQ_NR(KN03_IO_INR_TC2),
617 [DEC_IRQ_TIMER] = -1,
618 [DEC_IRQ_VIDEO] = -1,
619 [DEC_IRQ_ASC_MERR] = IO_IRQ_NR(IO_INR_ASC_MERR),
620 [DEC_IRQ_ASC_ERR] = IO_IRQ_NR(IO_INR_ASC_ERR),
621 [DEC_IRQ_ASC_DMA] = IO_IRQ_NR(IO_INR_ASC_DMA),
622 [DEC_IRQ_FLOPPY_ERR] = -1,
623 [DEC_IRQ_ISDN_ERR] = -1,
624 [DEC_IRQ_ISDN_RXDMA] = -1,
625 [DEC_IRQ_ISDN_TXDMA] = -1,
626 [DEC_IRQ_LANCE_MERR] = IO_IRQ_NR(IO_INR_LANCE_MERR),
627 [DEC_IRQ_SCC0A_RXERR] = IO_IRQ_NR(IO_INR_SCC0A_RXERR),
628 [DEC_IRQ_SCC0A_RXDMA] = IO_IRQ_NR(IO_INR_SCC0A_RXDMA),
629 [DEC_IRQ_SCC0A_TXERR] = IO_IRQ_NR(IO_INR_SCC0A_TXERR),
630 [DEC_IRQ_SCC0A_TXDMA] = IO_IRQ_NR(IO_INR_SCC0A_TXDMA),
631 [DEC_IRQ_AB_RXERR] = -1,
632 [DEC_IRQ_AB_RXDMA] = -1,
633 [DEC_IRQ_AB_TXERR] = -1,
634 [DEC_IRQ_AB_TXDMA] = -1,
635 [DEC_IRQ_SCC1A_RXERR] = IO_IRQ_NR(IO_INR_SCC1A_RXERR),
636 [DEC_IRQ_SCC1A_RXDMA] = IO_IRQ_NR(IO_INR_SCC1A_RXDMA),
637 [DEC_IRQ_SCC1A_TXERR] = IO_IRQ_NR(IO_INR_SCC1A_TXERR),
638 [DEC_IRQ_SCC1A_TXDMA] = IO_IRQ_NR(IO_INR_SCC1A_TXDMA),
639};
640
641static int_ptr kn03_cpu_mask_nr_tbl[][2] __initdata = {
642 { { .i = DEC_CPU_IRQ_MASK(KN03_CPU_INR_BUS) },
643 { .i = DEC_CPU_IRQ_NR(KN03_CPU_INR_BUS) } },
644 { { .i = DEC_CPU_IRQ_MASK(KN03_CPU_INR_RTC) },
645 { .i = DEC_CPU_IRQ_NR(KN03_CPU_INR_RTC) } },
646 { { .i = DEC_CPU_IRQ_MASK(KN03_CPU_INR_CASCADE) },
647 { .p = kn03_io_int } },
648 { { .i = DEC_CPU_IRQ_ALL },
649 { .p = cpu_all_int } },
650};
651
652static int_ptr kn03_asic_mask_nr_tbl[][2] __initdata = {
653 { { .i = IO_IRQ_DMA },
654 { .p = asic_dma_int } },
655 { { .i = IO_IRQ_MASK(KN03_IO_INR_SCC0) },
656 { .i = IO_IRQ_NR(KN03_IO_INR_SCC0) } },
657 { { .i = IO_IRQ_MASK(KN03_IO_INR_SCC1) },
658 { .i = IO_IRQ_NR(KN03_IO_INR_SCC1) } },
659 { { .i = IO_IRQ_MASK(KN03_IO_INR_ASC) },
660 { .i = IO_IRQ_NR(KN03_IO_INR_ASC) } },
661 { { .i = IO_IRQ_MASK(KN03_IO_INR_LANCE) },
662 { .i = IO_IRQ_NR(KN03_IO_INR_LANCE) } },
663 { { .i = IO_IRQ_MASK(KN03_IO_INR_TC2) },
664 { .i = IO_IRQ_NR(KN03_IO_INR_TC2) } },
665 { { .i = IO_IRQ_MASK(KN03_IO_INR_TC1) },
666 { .i = IO_IRQ_NR(KN03_IO_INR_TC1) } },
667 { { .i = IO_IRQ_MASK(KN03_IO_INR_TC0) },
668 { .i = IO_IRQ_NR(KN03_IO_INR_TC0) } },
669 { { .i = IO_IRQ_ALL },
670 { .p = asic_all_int } },
671};
672
673void __init dec_init_kn03(void)
674{
675 /* IRQ routing. */
676 memcpy(&dec_interrupt, &kn03_interrupt,
677 sizeof(kn03_interrupt));
678
679 /* CPU IRQ priorities. */
680 memcpy(&cpu_mask_nr_tbl, &kn03_cpu_mask_nr_tbl,
681 sizeof(kn03_cpu_mask_nr_tbl));
682
683 /* I/O ASIC IRQ priorities. */
684 memcpy(&asic_mask_nr_tbl, &kn03_asic_mask_nr_tbl,
685 sizeof(kn03_asic_mask_nr_tbl));
686
687 mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
688 init_ioasic_irqs(IO_IRQ_BASE);
689
690} /* dec_init_kn03 */
691
692
693void __init arch_init_irq(void)
694{
695 switch (mips_machtype) {
696 case MACH_DS23100: /* DS2100/DS3100 Pmin/Pmax */
697 dec_init_kn01();
698 break;
699 case MACH_DS5100: /* DS5100 MIPSmate */
700 dec_init_kn230();
701 break;
702 case MACH_DS5000_200: /* DS5000/200 3max */
703 dec_init_kn02();
704 break;
705 case MACH_DS5000_1XX: /* DS5000/1xx 3min */
706 dec_init_kn02ba();
707 break;
708 case MACH_DS5000_2X0: /* DS5000/240 3max+ */
709 case MACH_DS5900: /* DS5900 bigmax */
710 dec_init_kn03();
711 break;
712 case MACH_DS5000_XX: /* Personal DS5000/xx */
713 dec_init_kn02ca();
714 break;
715 case MACH_DS5800: /* DS5800 Isis */
716 panic("Don't know how to set this up!");
717 break;
718 case MACH_DS5400: /* DS5400 MIPSfair */
719 panic("Don't know how to set this up!");
720 break;
721 case MACH_DS5500: /* DS5500 MIPSfair-2 */
722 panic("Don't know how to set this up!");
723 break;
724 }
725 set_except_vector(0, decstation_handle_int);
726
727 /* Free the FPU interrupt if the exception is present. */
728 if (!cpu_has_nofpuex) {
729 cpu_fpu_mask = 0;
730 dec_interrupt[DEC_IRQ_FPU] = -1;
731 }
732
733 /* Register board interrupts: FPU and cascade. */
734 if (dec_interrupt[DEC_IRQ_FPU] >= 0)
735 setup_irq(dec_interrupt[DEC_IRQ_FPU], &fpuirq);
736 if (dec_interrupt[DEC_IRQ_CASCADE] >= 0)
737 setup_irq(dec_interrupt[DEC_IRQ_CASCADE], &ioirq);
738
739 /* Register the bus error interrupt. */
740 if (dec_interrupt[DEC_IRQ_BUS] >= 0 && busirq.handler)
741 setup_irq(dec_interrupt[DEC_IRQ_BUS], &busirq);
742
743 /* Register the HALT interrupt. */
744 if (dec_interrupt[DEC_IRQ_HALT] >= 0)
745 setup_irq(dec_interrupt[DEC_IRQ_HALT], &haltirq);
746}
747
748EXPORT_SYMBOL(ioasic_base);
749EXPORT_SYMBOL(dec_kn_slot_size);
750EXPORT_SYMBOL(dec_interrupt);
diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c
new file mode 100644
index 000000000000..dc7091caa7aa
--- /dev/null
+++ b/arch/mips/dec/time.c
@@ -0,0 +1,200 @@
1/*
2 * linux/arch/mips/dec/time.c
3 *
4 * Copyright (C) 1991, 1992, 1995 Linus Torvalds
5 * Copyright (C) 2000, 2003 Maciej W. Rozycki
6 *
7 * This file contains the time handling details for PC-style clocks as
8 * found in some MIPS systems.
9 *
10 */
11#include <linux/bcd.h>
12#include <linux/errno.h>
13#include <linux/init.h>
14#include <linux/interrupt.h>
15#include <linux/kernel.h>
16#include <linux/mc146818rtc.h>
17#include <linux/mm.h>
18#include <linux/module.h>
19#include <linux/param.h>
20#include <linux/sched.h>
21#include <linux/string.h>
22#include <linux/time.h>
23#include <linux/types.h>
24
25#include <asm/bootinfo.h>
26#include <asm/cpu.h>
27#include <asm/div64.h>
28#include <asm/io.h>
29#include <asm/irq.h>
30#include <asm/mipsregs.h>
31#include <asm/sections.h>
32#include <asm/time.h>
33
34#include <asm/dec/interrupts.h>
35#include <asm/dec/ioasic.h>
36#include <asm/dec/ioasic_addrs.h>
37#include <asm/dec/machtype.h>
38
39
40static unsigned long dec_rtc_get_time(void)
41{
42 unsigned int year, mon, day, hour, min, sec, real_year;
43 int i;
44
45 /* The Linux interpretation of the DS1287 clock register contents:
46 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
47 * RTC registers show the second which has precisely just started.
48 * Let's hope other operating systems interpret the RTC the same way.
49 */
50 /* read RTC exactly on falling edge of update flag */
51 for (i = 0; i < 1000000; i++) /* may take up to 1 second... */
52 if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
53 break;
54 for (i = 0; i < 1000000; i++) /* must try at least 2.228 ms */
55 if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
56 break;
57 /* Isn't this overkill? UIP above should guarantee consistency */
58 do {
59 sec = CMOS_READ(RTC_SECONDS);
60 min = CMOS_READ(RTC_MINUTES);
61 hour = CMOS_READ(RTC_HOURS);
62 day = CMOS_READ(RTC_DAY_OF_MONTH);
63 mon = CMOS_READ(RTC_MONTH);
64 year = CMOS_READ(RTC_YEAR);
65 } while (sec != CMOS_READ(RTC_SECONDS));
66 if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
67 sec = BCD2BIN(sec);
68 min = BCD2BIN(min);
69 hour = BCD2BIN(hour);
70 day = BCD2BIN(day);
71 mon = BCD2BIN(mon);
72 year = BCD2BIN(year);
73 }
74 /*
75 * The PROM will reset the year to either '72 or '73.
76 * Therefore we store the real year separately, in one
77 * of unused BBU RAM locations.
78 */
79 real_year = CMOS_READ(RTC_DEC_YEAR);
80 year += real_year - 72 + 2000;
81
82 return mktime(year, mon, day, hour, min, sec);
83}
84
85/*
86 * In order to set the CMOS clock precisely, dec_rtc_set_mmss has to
87 * be called 500 ms after the second nowtime has started, because when
88 * nowtime is written into the registers of the CMOS clock, it will
89 * jump to the next second precisely 500 ms later. Check the Dallas
90 * DS1287 data sheet for details.
91 */
92static int dec_rtc_set_mmss(unsigned long nowtime)
93{
94 int retval = 0;
95 int real_seconds, real_minutes, cmos_minutes;
96 unsigned char save_control, save_freq_select;
97
98 /* tell the clock it's being set */
99 save_control = CMOS_READ(RTC_CONTROL);
100 CMOS_WRITE((save_control | RTC_SET), RTC_CONTROL);
101
102 /* stop and reset prescaler */
103 save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
104 CMOS_WRITE((save_freq_select | RTC_DIV_RESET2), RTC_FREQ_SELECT);
105
106 cmos_minutes = CMOS_READ(RTC_MINUTES);
107 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
108 cmos_minutes = BCD2BIN(cmos_minutes);
109
110 /*
111 * since we're only adjusting minutes and seconds,
112 * don't interfere with hour overflow. This avoids
113 * messing with unknown time zones but requires your
114 * RTC not to be off by more than 15 minutes
115 */
116 real_seconds = nowtime % 60;
117 real_minutes = nowtime / 60;
118 if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
119 real_minutes += 30; /* correct for half hour time zone */
120 real_minutes %= 60;
121
122 if (abs(real_minutes - cmos_minutes) < 30) {
123 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
124 real_seconds = BIN2BCD(real_seconds);
125 real_minutes = BIN2BCD(real_minutes);
126 }
127 CMOS_WRITE(real_seconds, RTC_SECONDS);
128 CMOS_WRITE(real_minutes, RTC_MINUTES);
129 } else {
130 printk(KERN_WARNING
131 "set_rtc_mmss: can't update from %d to %d\n",
132 cmos_minutes, real_minutes);
133 retval = -1;
134 }
135
136 /* The following flags have to be released exactly in this order,
137 * otherwise the DS1287 will not reset the oscillator and will not
138 * update precisely 500 ms later. You won't find this mentioned
139 * in the Dallas Semiconductor data sheets, but who believes data
140 * sheets anyway ... -- Markus Kuhn
141 */
142 CMOS_WRITE(save_control, RTC_CONTROL);
143 CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
144
145 return retval;
146}
147
148
149static int dec_timer_state(void)
150{
151 return (CMOS_READ(RTC_REG_C) & RTC_PF) != 0;
152}
153
154static void dec_timer_ack(void)
155{
156 CMOS_READ(RTC_REG_C); /* Ack the RTC interrupt. */
157}
158
159static unsigned int dec_ioasic_hpt_read(void)
160{
161 /*
162 * The free-running counter is 32-bit which is good for about
163 * 2 minutes, 50 seconds at possible count rates of up to 25MHz.
164 */
165 return ioasic_read(IO_REG_FCTR);
166}
167
168static void dec_ioasic_hpt_init(unsigned int count)
169{
170 ioasic_write(IO_REG_FCTR, ioasic_read(IO_REG_FCTR) - count);
171}
172
173
174void __init dec_time_init(void)
175{
176 rtc_get_time = dec_rtc_get_time;
177 rtc_set_mmss = dec_rtc_set_mmss;
178
179 mips_timer_state = dec_timer_state;
180 mips_timer_ack = dec_timer_ack;
181
182 if (!cpu_has_counter && IOASIC) {
183 /* For pre-R4k systems we use the I/O ASIC's counter. */
184 mips_hpt_read = dec_ioasic_hpt_read;
185 mips_hpt_init = dec_ioasic_hpt_init;
186 }
187
188 /* Set up the rate of periodic DS1287 interrupts. */
189 CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - LOG_2_HZ), RTC_REG_A);
190}
191
192EXPORT_SYMBOL(do_settimeofday);
193
194void __init dec_timer_setup(struct irqaction *irq)
195{
196 setup_irq(dec_interrupt[DEC_IRQ_RTC], irq);
197
198 /* Enable periodic DS1287 interrupts. */
199 CMOS_WRITE(CMOS_READ(RTC_REG_B) | RTC_PIE, RTC_REG_B);
200}
diff --git a/arch/mips/dec/wbflush.c b/arch/mips/dec/wbflush.c
new file mode 100644
index 000000000000..925c0525344b
--- /dev/null
+++ b/arch/mips/dec/wbflush.c
@@ -0,0 +1,94 @@
1/*
2 * Setup the right wbflush routine for the different DECstations.
3 *
4 * Created with information from:
5 * DECstation 3100 Desktop Workstation Functional Specification
6 * DECstation 5000/200 KN02 System Module Functional Specification
7 * mipsel-linux-objdump --disassemble vmunix | grep "wbflush" :-)
8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file "COPYING" in the main directory of this archive
11 * for more details.
12 *
13 * Copyright (C) 1998 Harald Koerfgen
14 * Copyright (C) 2002 Maciej W. Rozycki
15 */
16
17#include <linux/init.h>
18
19#include <asm/bootinfo.h>
20#include <asm/system.h>
21#include <asm/wbflush.h>
22
23static void wbflush_kn01(void);
24static void wbflush_kn210(void);
25static void wbflush_mips(void);
26
27void (*__wbflush) (void);
28
29void __init wbflush_setup(void)
30{
31 switch (mips_machtype) {
32 case MACH_DS23100:
33 case MACH_DS5000_200: /* DS5000 3max */
34 __wbflush = wbflush_kn01;
35 break;
36 case MACH_DS5100: /* DS5100 MIPSMATE */
37 __wbflush = wbflush_kn210;
38 break;
39 case MACH_DS5000_1XX: /* DS5000/100 3min */
40 case MACH_DS5000_XX: /* Personal DS5000/2x */
41 case MACH_DS5000_2X0: /* DS5000/240 3max+ */
42 case MACH_DS5900: /* DS5900 bigmax */
43 default:
44 __wbflush = wbflush_mips;
45 break;
46 }
47}
48
49/*
50 * For the DS3100 and DS5000/200 the R2020/R3220 writeback buffer functions
51 * as part of Coprocessor 0.
52 */
53static void wbflush_kn01(void)
54{
55 asm(".set\tpush\n\t"
56 ".set\tnoreorder\n\t"
57 "1:\tbc0f\t1b\n\t"
58 "nop\n\t"
59 ".set\tpop");
60}
61
62/*
63 * For the DS5100 the writeback buffer seems to be a part of Coprocessor 3.
64 * But CP3 has to enabled first.
65 */
66static void wbflush_kn210(void)
67{
68 asm(".set\tpush\n\t"
69 ".set\tnoreorder\n\t"
70 "mfc0\t$2,$12\n\t"
71 "lui\t$3,0x8000\n\t"
72 "or\t$3,$2,$3\n\t"
73 "mtc0\t$3,$12\n\t"
74 "nop\n"
75 "1:\tbc3f\t1b\n\t"
76 "nop\n\t"
77 "mtc0\t$2,$12\n\t"
78 "nop\n\t"
79 ".set\tpop"
80 : : : "$2", "$3");
81}
82
83/*
84 * I/O ASIC systems use a standard writeback buffer that gets flushed
85 * upon an uncached read.
86 */
87static void wbflush_mips(void)
88{
89 __fast_iob();
90}
91
92#include <linux/module.h>
93
94EXPORT_SYMBOL(__wbflush);