mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-09 01:28:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
9
arch/mips/dec/Makefile
Normal file
9
arch/mips/dec/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# Makefile for the DECstation family specific parts of the kernel
|
||||
#
|
||||
|
||||
obj-y := ecc-berr.o int-handler.o ioasic-irq.o kn01-berr.o \
|
||||
kn02-irq.o kn02xa-berr.o platform.o reset.o setup.o time.o
|
||||
|
||||
obj-$(CONFIG_TC) += tc.o
|
||||
obj-$(CONFIG_CPU_HAS_WB) += wbflush.o
|
8
arch/mips/dec/Platform
Normal file
8
arch/mips/dec/Platform
Normal file
|
@ -0,0 +1,8 @@
|
|||
#
|
||||
# DECstation family
|
||||
#
|
||||
platform-$(CONFIG_MACH_DECSTATION) += dec/
|
||||
cflags-$(CONFIG_MACH_DECSTATION) += \
|
||||
-I$(srctree)/arch/mips/include/asm/mach-dec
|
||||
libs-$(CONFIG_MACH_DECSTATION) += arch/mips/dec/prom/
|
||||
load-$(CONFIG_MACH_DECSTATION) += 0xffffffff80040000
|
278
arch/mips/dec/ecc-berr.c
Normal file
278
arch/mips/dec/ecc-berr.c
Normal file
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* Bus error event handling code for systems equipped with ECC
|
||||
* handling logic, i.e. DECstation/DECsystem 5000/200 (KN02),
|
||||
* 5000/240 (KN03), 5000/260 (KN05) and DECsystem 5900 (KN03),
|
||||
* 5900/260 (KN05) systems.
|
||||
*
|
||||
* Copyright (c) 2003, 2005 Maciej W. Rozycki
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/cpu-type.h>
|
||||
#include <asm/irq_regs.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/traps.h>
|
||||
|
||||
#include <asm/dec/ecc.h>
|
||||
#include <asm/dec/kn02.h>
|
||||
#include <asm/dec/kn03.h>
|
||||
#include <asm/dec/kn05.h>
|
||||
|
||||
static volatile u32 *kn0x_erraddr;
|
||||
static volatile u32 *kn0x_chksyn;
|
||||
|
||||
static inline void dec_ecc_be_ack(void)
|
||||
{
|
||||
*kn0x_erraddr = 0; /* any write clears the IRQ */
|
||||
iob();
|
||||
}
|
||||
|
||||
static int dec_ecc_be_backend(struct pt_regs *regs, int is_fixup, int invoker)
|
||||
{
|
||||
static const char excstr[] = "exception";
|
||||
static const char intstr[] = "interrupt";
|
||||
static const char cpustr[] = "CPU";
|
||||
static const char dmastr[] = "DMA";
|
||||
static const char readstr[] = "read";
|
||||
static const char mreadstr[] = "memory read";
|
||||
static const char writestr[] = "write";
|
||||
static const char mwritstr[] = "partial memory write";
|
||||
static const char timestr[] = "timeout";
|
||||
static const char overstr[] = "overrun";
|
||||
static const char eccstr[] = "ECC error";
|
||||
|
||||
const char *kind, *agent, *cycle, *event;
|
||||
const char *status = "", *xbit = "", *fmt = "";
|
||||
unsigned long address;
|
||||
u16 syn = 0, sngl;
|
||||
|
||||
int i = 0;
|
||||
|
||||
u32 erraddr = *kn0x_erraddr;
|
||||
u32 chksyn = *kn0x_chksyn;
|
||||
int action = MIPS_BE_FATAL;
|
||||
|
||||
/* For non-ECC ack ASAP, so that any subsequent errors get caught. */
|
||||
if ((erraddr & (KN0X_EAR_VALID | KN0X_EAR_ECCERR)) == KN0X_EAR_VALID)
|
||||
dec_ecc_be_ack();
|
||||
|
||||
kind = invoker ? intstr : excstr;
|
||||
|
||||
if (!(erraddr & KN0X_EAR_VALID)) {
|
||||
/* No idea what happened. */
|
||||
printk(KERN_ALERT "Unidentified bus error %s\n", kind);
|
||||
return action;
|
||||
}
|
||||
|
||||
agent = (erraddr & KN0X_EAR_CPU) ? cpustr : dmastr;
|
||||
|
||||
if (erraddr & KN0X_EAR_ECCERR) {
|
||||
/* An ECC error on a CPU or DMA transaction. */
|
||||
cycle = (erraddr & KN0X_EAR_WRITE) ? mwritstr : mreadstr;
|
||||
event = eccstr;
|
||||
} else {
|
||||
/* A CPU timeout or a DMA overrun. */
|
||||
cycle = (erraddr & KN0X_EAR_WRITE) ? writestr : readstr;
|
||||
event = (erraddr & KN0X_EAR_CPU) ? timestr : overstr;
|
||||
}
|
||||
|
||||
address = erraddr & KN0X_EAR_ADDRESS;
|
||||
/* For ECC errors on reads adjust for MT pipelining. */
|
||||
if ((erraddr & (KN0X_EAR_WRITE | KN0X_EAR_ECCERR)) == KN0X_EAR_ECCERR)
|
||||
address = (address & ~0xfffLL) | ((address - 5) & 0xfffLL);
|
||||
address <<= 2;
|
||||
|
||||
/* Only CPU errors are fixable. */
|
||||
if (erraddr & KN0X_EAR_CPU && is_fixup)
|
||||
action = MIPS_BE_FIXUP;
|
||||
|
||||
if (erraddr & KN0X_EAR_ECCERR) {
|
||||
static const u8 data_sbit[32] = {
|
||||
0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d,
|
||||
0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34,
|
||||
0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c,
|
||||
0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75,
|
||||
};
|
||||
static const u8 data_mbit[25] = {
|
||||
0x07, 0x0d, 0x1f,
|
||||
0x2f, 0x32, 0x37, 0x38, 0x3b, 0x3d, 0x3e,
|
||||
0x43, 0x45, 0x46, 0x49, 0x4c, 0x51, 0x5e,
|
||||
0x61, 0x6e, 0x73, 0x76, 0x79, 0x7a, 0x7c, 0x7f,
|
||||
};
|
||||
static const char sbestr[] = "corrected single";
|
||||
static const char dbestr[] = "uncorrectable double";
|
||||
static const char mbestr[] = "uncorrectable multiple";
|
||||
|
||||
if (!(address & 0x4))
|
||||
syn = chksyn; /* Low bank. */
|
||||
else
|
||||
syn = chksyn >> 16; /* High bank. */
|
||||
|
||||
if (!(syn & KN0X_ESR_VLDLO)) {
|
||||
/* Ack now, no rewrite will happen. */
|
||||
dec_ecc_be_ack();
|
||||
|
||||
fmt = KERN_ALERT "%s" "invalid\n";
|
||||
} else {
|
||||
sngl = syn & KN0X_ESR_SNGLO;
|
||||
syn &= KN0X_ESR_SYNLO;
|
||||
|
||||
/*
|
||||
* Multibit errors may be tagged incorrectly;
|
||||
* check the syndrome explicitly.
|
||||
*/
|
||||
for (i = 0; i < 25; i++)
|
||||
if (syn == data_mbit[i])
|
||||
break;
|
||||
|
||||
if (i < 25) {
|
||||
status = mbestr;
|
||||
} else if (!sngl) {
|
||||
status = dbestr;
|
||||
} else {
|
||||
volatile u32 *ptr =
|
||||
(void *)CKSEG1ADDR(address);
|
||||
|
||||
*ptr = *ptr; /* Rewrite. */
|
||||
iob();
|
||||
|
||||
status = sbestr;
|
||||
action = MIPS_BE_DISCARD;
|
||||
}
|
||||
|
||||
/* Ack now, now we've rewritten (or not). */
|
||||
dec_ecc_be_ack();
|
||||
|
||||
if (syn && syn == (syn & -syn)) {
|
||||
if (syn == 0x01) {
|
||||
fmt = KERN_ALERT "%s"
|
||||
"%#04x -- %s bit error "
|
||||
"at check bit C%s\n";
|
||||
xbit = "X";
|
||||
} else {
|
||||
fmt = KERN_ALERT "%s"
|
||||
"%#04x -- %s bit error "
|
||||
"at check bit C%s%u\n";
|
||||
}
|
||||
i = syn >> 2;
|
||||
} else {
|
||||
for (i = 0; i < 32; i++)
|
||||
if (syn == data_sbit[i])
|
||||
break;
|
||||
if (i < 32)
|
||||
fmt = KERN_ALERT "%s"
|
||||
"%#04x -- %s bit error "
|
||||
"at data bit D%s%u\n";
|
||||
else
|
||||
fmt = KERN_ALERT "%s"
|
||||
"%#04x -- %s bit error\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (action != MIPS_BE_FIXUP)
|
||||
printk(KERN_ALERT "Bus error %s: %s %s %s at %#010lx\n",
|
||||
kind, agent, cycle, event, address);
|
||||
|
||||
if (action != MIPS_BE_FIXUP && erraddr & KN0X_EAR_ECCERR)
|
||||
printk(fmt, " ECC syndrome ", syn, status, xbit, i);
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
int dec_ecc_be_handler(struct pt_regs *regs, int is_fixup)
|
||||
{
|
||||
return dec_ecc_be_backend(regs, is_fixup, 0);
|
||||
}
|
||||
|
||||
irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct pt_regs *regs = get_irq_regs();
|
||||
|
||||
int action = dec_ecc_be_backend(regs, 0, 1);
|
||||
|
||||
if (action == MIPS_BE_DISCARD)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/*
|
||||
* FIXME: Find the affected processes and kill them, otherwise
|
||||
* we must die.
|
||||
*
|
||||
* The interrupt is asynchronously delivered thus EPC and RA
|
||||
* may be irrelevant, but are printed for a reference.
|
||||
*/
|
||||
printk(KERN_ALERT "Fatal bus interrupt, epc == %08lx, ra == %08lx\n",
|
||||
regs->cp0_epc, regs->regs[31]);
|
||||
die("Unrecoverable bus error", regs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialization differs a bit between KN02 and KN03/KN05, so we
|
||||
* need two variants. Once set up, all systems can be handled the
|
||||
* same way.
|
||||
*/
|
||||
static inline void dec_kn02_be_init(void)
|
||||
{
|
||||
volatile u32 *csr = (void *)CKSEG1ADDR(KN02_SLOT_BASE + KN02_CSR);
|
||||
|
||||
kn0x_erraddr = (void *)CKSEG1ADDR(KN02_SLOT_BASE + KN02_ERRADDR);
|
||||
kn0x_chksyn = (void *)CKSEG1ADDR(KN02_SLOT_BASE + KN02_CHKSYN);
|
||||
|
||||
/* Preset write-only bits of the Control Register cache. */
|
||||
cached_kn02_csr = *csr | KN02_CSR_LEDS;
|
||||
|
||||
/* Set normal ECC detection and generation. */
|
||||
cached_kn02_csr &= ~(KN02_CSR_DIAGCHK | KN02_CSR_DIAGGEN);
|
||||
/* Enable ECC correction. */
|
||||
cached_kn02_csr |= KN02_CSR_CORRECT;
|
||||
*csr = cached_kn02_csr;
|
||||
iob();
|
||||
}
|
||||
|
||||
static inline void dec_kn03_be_init(void)
|
||||
{
|
||||
volatile u32 *mcr = (void *)CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_MCR);
|
||||
volatile u32 *mbcs = (void *)CKSEG1ADDR(KN4K_SLOT_BASE + KN4K_MB_CSR);
|
||||
|
||||
kn0x_erraddr = (void *)CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_ERRADDR);
|
||||
kn0x_chksyn = (void *)CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_CHKSYN);
|
||||
|
||||
/*
|
||||
* Set normal ECC detection and generation, enable ECC correction.
|
||||
* For KN05 we also need to make sure EE (?) is enabled in the MB.
|
||||
* Otherwise DBE/IBE exceptions would be masked but bus error
|
||||
* interrupts would still arrive, resulting in an inevitable crash
|
||||
* if get_dbe() triggers one.
|
||||
*/
|
||||
*mcr = (*mcr & ~(KN03_MCR_DIAGCHK | KN03_MCR_DIAGGEN)) |
|
||||
KN03_MCR_CORRECT;
|
||||
if (current_cpu_type() == CPU_R4400SC)
|
||||
*mbcs |= KN4K_MB_CSR_EE;
|
||||
fast_iob();
|
||||
}
|
||||
|
||||
void __init dec_ecc_be_init(void)
|
||||
{
|
||||
if (mips_machtype == MACH_DS5000_200)
|
||||
dec_kn02_be_init();
|
||||
else
|
||||
dec_kn03_be_init();
|
||||
|
||||
/* Clear any leftover errors from the firmware. */
|
||||
dec_ecc_be_ack();
|
||||
}
|
291
arch/mips/dec/int-handler.S
Normal file
291
arch/mips/dec/int-handler.S
Normal file
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* Copyright (C) 1995, 1996, 1997 Paul M. Antoine and Harald Koerfgen
|
||||
* Copyright (C) 2000, 2001, 2002, 2003, 2005 Maciej W. Rozycki
|
||||
*
|
||||
* Written by Ralf Baechle and Andreas Busse, modified for DECstation
|
||||
* support by Paul Antoine and Harald Koerfgen.
|
||||
*
|
||||
* completly rewritten:
|
||||
* Copyright (C) 1998 Harald Koerfgen
|
||||
*
|
||||
* Rewritten extensively for controller-driven IRQ support
|
||||
* by Maciej W. Rozycki.
|
||||
*/
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/stackframe.h>
|
||||
|
||||
#include <asm/dec/interrupts.h>
|
||||
#include <asm/dec/ioasic_addrs.h>
|
||||
#include <asm/dec/ioasic_ints.h>
|
||||
#include <asm/dec/kn01.h>
|
||||
#include <asm/dec/kn02.h>
|
||||
#include <asm/dec/kn02xa.h>
|
||||
#include <asm/dec/kn03.h>
|
||||
|
||||
#define KN02_CSR_BASE CKSEG1ADDR(KN02_SLOT_BASE + KN02_CSR)
|
||||
#define KN02XA_IOASIC_BASE CKSEG1ADDR(KN02XA_SLOT_BASE + IOASIC_IOCTL)
|
||||
#define KN03_IOASIC_BASE CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_IOCTL)
|
||||
|
||||
.text
|
||||
.set noreorder
|
||||
/*
|
||||
* plat_irq_dispatch: Interrupt handler for DECstations
|
||||
*
|
||||
* We follow the model in the Indy interrupt code by David Miller, where he
|
||||
* says: a lot of complication here is taken away because:
|
||||
*
|
||||
* 1) We handle one interrupt and return, sitting in a loop
|
||||
* and moving across all the pending IRQ bits in the cause
|
||||
* register is _NOT_ the answer, the common case is one
|
||||
* pending IRQ so optimize in that direction.
|
||||
*
|
||||
* 2) We need not check against bits in the status register
|
||||
* IRQ mask, that would make this routine slow as hell.
|
||||
*
|
||||
* 3) Linux only thinks in terms of all IRQs on or all IRQs
|
||||
* off, nothing in between like BSD spl() brain-damage.
|
||||
*
|
||||
* Furthermore, the IRQs on the DECstations look basically (barring
|
||||
* software IRQs which we don't use at all) like...
|
||||
*
|
||||
* DS2100/3100's, aka kn01, aka Pmax:
|
||||
*
|
||||
* MIPS IRQ Source
|
||||
* -------- ------
|
||||
* 0 Software (ignored)
|
||||
* 1 Software (ignored)
|
||||
* 2 SCSI
|
||||
* 3 Lance Ethernet
|
||||
* 4 DZ11 serial
|
||||
* 5 RTC
|
||||
* 6 Memory Controller & Video
|
||||
* 7 FPU
|
||||
*
|
||||
* DS5000/200, aka kn02, aka 3max:
|
||||
*
|
||||
* MIPS IRQ Source
|
||||
* -------- ------
|
||||
* 0 Software (ignored)
|
||||
* 1 Software (ignored)
|
||||
* 2 TurboChannel
|
||||
* 3 RTC
|
||||
* 4 Reserved
|
||||
* 5 Memory Controller
|
||||
* 6 Reserved
|
||||
* 7 FPU
|
||||
*
|
||||
* DS5000/1xx's, aka kn02ba, aka 3min:
|
||||
*
|
||||
* MIPS IRQ Source
|
||||
* -------- ------
|
||||
* 0 Software (ignored)
|
||||
* 1 Software (ignored)
|
||||
* 2 TurboChannel Slot 0
|
||||
* 3 TurboChannel Slot 1
|
||||
* 4 TurboChannel Slot 2
|
||||
* 5 TurboChannel Slot 3 (ASIC)
|
||||
* 6 Halt button
|
||||
* 7 FPU/R4k timer
|
||||
*
|
||||
* DS5000/2x's, aka kn02ca, aka maxine:
|
||||
*
|
||||
* MIPS IRQ Source
|
||||
* -------- ------
|
||||
* 0 Software (ignored)
|
||||
* 1 Software (ignored)
|
||||
* 2 Periodic Interrupt (100usec)
|
||||
* 3 RTC
|
||||
* 4 I/O write timeout
|
||||
* 5 TurboChannel (ASIC)
|
||||
* 6 Halt Keycode from Access.Bus keyboard (CTRL-ALT-ENTER)
|
||||
* 7 FPU/R4k timer
|
||||
*
|
||||
* DS5000/2xx's, aka kn03, aka 3maxplus:
|
||||
*
|
||||
* MIPS IRQ Source
|
||||
* -------- ------
|
||||
* 0 Software (ignored)
|
||||
* 1 Software (ignored)
|
||||
* 2 System Board (ASIC)
|
||||
* 3 RTC
|
||||
* 4 Reserved
|
||||
* 5 Memory
|
||||
* 6 Halt Button
|
||||
* 7 FPU/R4k timer
|
||||
*
|
||||
* We handle the IRQ according to _our_ priority (see setup.c),
|
||||
* then we just return. If multiple IRQs are pending then we will
|
||||
* just take another exception, big deal.
|
||||
*/
|
||||
.align 5
|
||||
NESTED(plat_irq_dispatch, PT_SIZE, ra)
|
||||
.set noreorder
|
||||
|
||||
/*
|
||||
* Get pending Interrupts
|
||||
*/
|
||||
mfc0 t0,CP0_CAUSE # get pending interrupts
|
||||
mfc0 t1,CP0_STATUS
|
||||
#ifdef CONFIG_32BIT
|
||||
lw t2,cpu_fpu_mask
|
||||
#endif
|
||||
andi t0,ST0_IM # CAUSE.CE may be non-zero!
|
||||
and t0,t1 # isolate allowed ones
|
||||
|
||||
beqz t0,spurious
|
||||
|
||||
#ifdef CONFIG_32BIT
|
||||
and t2,t0
|
||||
bnez t2,fpu # handle FPU immediately
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Find irq with highest priority
|
||||
*/
|
||||
PTR_LA t1,cpu_mask_nr_tbl
|
||||
1: lw t2,(t1)
|
||||
nop
|
||||
and t2,t0
|
||||
beqz t2,1b
|
||||
addu t1,2*PTRSIZE # delay slot
|
||||
|
||||
/*
|
||||
* Do the low-level stuff
|
||||
*/
|
||||
lw a0,(-PTRSIZE)(t1)
|
||||
nop
|
||||
bgez a0,handle_it # irq_nr >= 0?
|
||||
# irq_nr < 0: it is an address
|
||||
nop
|
||||
jr a0
|
||||
# a trick to save a branch:
|
||||
lui t2,(KN03_IOASIC_BASE>>16)&0xffff
|
||||
# upper part of IOASIC Address
|
||||
|
||||
/*
|
||||
* Handle "IRQ Controller" Interrupts
|
||||
* Masked Interrupts are still visible and have to be masked "by hand".
|
||||
*/
|
||||
FEXPORT(kn02_io_int) # 3max
|
||||
lui t0,(KN02_CSR_BASE>>16)&0xffff
|
||||
# get interrupt status and mask
|
||||
lw t0,(t0)
|
||||
nop
|
||||
andi t1,t0,KN02_IRQ_ALL
|
||||
b 1f
|
||||
srl t0,16 # shift interrupt mask
|
||||
|
||||
FEXPORT(kn02xa_io_int) # 3min/maxine
|
||||
lui t2,(KN02XA_IOASIC_BASE>>16)&0xffff
|
||||
# upper part of IOASIC Address
|
||||
|
||||
FEXPORT(kn03_io_int) # 3max+ (t2 loaded earlier)
|
||||
lw t0,IO_REG_SIR(t2) # get status: IOASIC sir
|
||||
lw t1,IO_REG_SIMR(t2) # get mask: IOASIC simr
|
||||
nop
|
||||
|
||||
1: and t0,t1 # mask out allowed ones
|
||||
|
||||
beqz t0,spurious
|
||||
|
||||
/*
|
||||
* Find irq with highest priority
|
||||
*/
|
||||
PTR_LA t1,asic_mask_nr_tbl
|
||||
2: lw t2,(t1)
|
||||
nop
|
||||
and t2,t0
|
||||
beq zero,t2,2b
|
||||
addu t1,2*PTRSIZE # delay slot
|
||||
|
||||
/*
|
||||
* Do the low-level stuff
|
||||
*/
|
||||
lw a0,%lo(-PTRSIZE)(t1)
|
||||
nop
|
||||
bgez a0,handle_it # irq_nr >= 0?
|
||||
# irq_nr < 0: it is an address
|
||||
nop
|
||||
jr a0
|
||||
nop # delay slot
|
||||
|
||||
/*
|
||||
* Dispatch low-priority interrupts. We reconsider all status
|
||||
* bits again, which looks like a lose, but it makes the code
|
||||
* simple and O(log n), so it gets compensated.
|
||||
*/
|
||||
FEXPORT(cpu_all_int) # HALT, timers, software junk
|
||||
li a0,DEC_CPU_IRQ_BASE
|
||||
srl t0,CAUSEB_IP
|
||||
li t1,CAUSEF_IP>>CAUSEB_IP # mask
|
||||
b 1f
|
||||
li t2,4 # nr of bits / 2
|
||||
|
||||
FEXPORT(kn02_all_int) # impossible ?
|
||||
li a0,KN02_IRQ_BASE
|
||||
li t1,KN02_IRQ_ALL # mask
|
||||
b 1f
|
||||
li t2,4 # nr of bits / 2
|
||||
|
||||
FEXPORT(asic_all_int) # various I/O ASIC junk
|
||||
li a0,IO_IRQ_BASE
|
||||
li t1,IO_IRQ_ALL # mask
|
||||
b 1f
|
||||
li t2,8 # nr of bits / 2
|
||||
|
||||
/*
|
||||
* Dispatch DMA interrupts -- O(log n).
|
||||
*/
|
||||
FEXPORT(asic_dma_int) # I/O ASIC DMA events
|
||||
li a0,IO_IRQ_BASE+IO_INR_DMA
|
||||
srl t0,IO_INR_DMA
|
||||
li t1,IO_IRQ_DMA>>IO_INR_DMA # mask
|
||||
li t2,8 # nr of bits / 2
|
||||
|
||||
/*
|
||||
* Find irq with highest priority.
|
||||
* Highest irq number takes precedence.
|
||||
*/
|
||||
1: srlv t3,t1,t2
|
||||
2: xor t1,t3
|
||||
and t3,t0,t1
|
||||
beqz t3,3f
|
||||
nop
|
||||
move t0,t3
|
||||
addu a0,t2
|
||||
3: srl t2,1
|
||||
bnez t2,2b
|
||||
srlv t3,t1,t2
|
||||
|
||||
handle_it:
|
||||
j dec_irq_dispatch
|
||||
nop
|
||||
|
||||
#ifdef CONFIG_32BIT
|
||||
fpu:
|
||||
j handle_fpe_int
|
||||
nop
|
||||
#endif
|
||||
|
||||
spurious:
|
||||
j spurious_interrupt
|
||||
nop
|
||||
END(plat_irq_dispatch)
|
||||
|
||||
/*
|
||||
* Generic unimplemented interrupt routines -- cpu_mask_nr_tbl
|
||||
* and asic_mask_nr_tbl are initialized to point all interrupts here.
|
||||
* The tables are then filled in by machine-specific initialisation
|
||||
* in dec_setup().
|
||||
*/
|
||||
FEXPORT(dec_intr_unimplemented)
|
||||
move a1,t0 # cheats way of printing an arg!
|
||||
PANIC("Unimplemented cpu interrupt! CP0_CAUSE: 0x%08x");
|
||||
|
||||
FEXPORT(asic_intr_unimplemented)
|
||||
move a1,t0 # cheats way of printing an arg!
|
||||
PANIC("Unimplemented asic interrupt! ASIC ISR: 0x%08x");
|
116
arch/mips/dec/ioasic-irq.c
Normal file
116
arch/mips/dec/ioasic-irq.c
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* DEC I/O ASIC interrupts.
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2013 Maciej W. Rozycki
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/dec/ioasic.h>
|
||||
#include <asm/dec/ioasic_addrs.h>
|
||||
#include <asm/dec/ioasic_ints.h>
|
||||
|
||||
static int ioasic_irq_base;
|
||||
|
||||
static void unmask_ioasic_irq(struct irq_data *d)
|
||||
{
|
||||
u32 simr;
|
||||
|
||||
simr = ioasic_read(IO_REG_SIMR);
|
||||
simr |= (1 << (d->irq - ioasic_irq_base));
|
||||
ioasic_write(IO_REG_SIMR, simr);
|
||||
}
|
||||
|
||||
static void mask_ioasic_irq(struct irq_data *d)
|
||||
{
|
||||
u32 simr;
|
||||
|
||||
simr = ioasic_read(IO_REG_SIMR);
|
||||
simr &= ~(1 << (d->irq - ioasic_irq_base));
|
||||
ioasic_write(IO_REG_SIMR, simr);
|
||||
}
|
||||
|
||||
static void ack_ioasic_irq(struct irq_data *d)
|
||||
{
|
||||
mask_ioasic_irq(d);
|
||||
fast_iob();
|
||||
}
|
||||
|
||||
static struct irq_chip ioasic_irq_type = {
|
||||
.name = "IO-ASIC",
|
||||
.irq_ack = ack_ioasic_irq,
|
||||
.irq_mask = mask_ioasic_irq,
|
||||
.irq_mask_ack = ack_ioasic_irq,
|
||||
.irq_unmask = unmask_ioasic_irq,
|
||||
};
|
||||
|
||||
static void clear_ioasic_dma_irq(struct irq_data *d)
|
||||
{
|
||||
u32 sir;
|
||||
|
||||
sir = ~(1 << (d->irq - ioasic_irq_base));
|
||||
ioasic_write(IO_REG_SIR, sir);
|
||||
fast_iob();
|
||||
}
|
||||
|
||||
static struct irq_chip ioasic_dma_irq_type = {
|
||||
.name = "IO-ASIC-DMA",
|
||||
.irq_ack = clear_ioasic_dma_irq,
|
||||
.irq_mask = mask_ioasic_irq,
|
||||
.irq_unmask = unmask_ioasic_irq,
|
||||
.irq_eoi = clear_ioasic_dma_irq,
|
||||
};
|
||||
|
||||
/*
|
||||
* I/O ASIC implements two kinds of DMA interrupts, informational and
|
||||
* error interrupts.
|
||||
*
|
||||
* The formers do not stop DMA and should be cleared as soon as possible
|
||||
* so that if they retrigger before the handler has completed, usually as
|
||||
* a side effect of actions taken by the handler, then they are reissued.
|
||||
* These use the `handle_edge_irq' handler that clears the request right
|
||||
* away.
|
||||
*
|
||||
* The latters stop DMA and do not resume it until the interrupt has been
|
||||
* cleared. This cannot be done until after a corrective action has been
|
||||
* taken and this also means they will not retrigger. Therefore they use
|
||||
* the `handle_fasteoi_irq' handler that only clears the request on the
|
||||
* way out. Because MIPS processor interrupt inputs, one of which the I/O
|
||||
* ASIC is cascaded to, are level-triggered it is recommended that error
|
||||
* DMA interrupt action handlers are registered with the IRQF_ONESHOT flag
|
||||
* set so that they are run with the interrupt line masked.
|
||||
*
|
||||
* This mask has `1' bits in the positions of informational interrupts.
|
||||
*/
|
||||
#define IO_IRQ_DMA_INFO \
|
||||
(IO_IRQ_MASK(IO_INR_SCC0A_RXDMA) | \
|
||||
IO_IRQ_MASK(IO_INR_SCC1A_RXDMA) | \
|
||||
IO_IRQ_MASK(IO_INR_ISDN_TXDMA) | \
|
||||
IO_IRQ_MASK(IO_INR_ISDN_RXDMA) | \
|
||||
IO_IRQ_MASK(IO_INR_ASC_DMA))
|
||||
|
||||
void __init init_ioasic_irqs(int base)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Mask interrupts. */
|
||||
ioasic_write(IO_REG_SIMR, 0);
|
||||
fast_iob();
|
||||
|
||||
for (i = base; i < base + IO_INR_DMA; i++)
|
||||
irq_set_chip_and_handler(i, &ioasic_irq_type,
|
||||
handle_level_irq);
|
||||
for (; i < base + IO_IRQ_LINES; i++)
|
||||
irq_set_chip_and_handler(i, &ioasic_dma_irq_type,
|
||||
1 << (i - base) & IO_IRQ_DMA_INFO ?
|
||||
handle_edge_irq : handle_fasteoi_irq);
|
||||
|
||||
ioasic_irq_base = base;
|
||||
}
|
200
arch/mips/dec/kn01-berr.c
Normal file
200
arch/mips/dec/kn01-berr.c
Normal file
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Bus error event handling code for DECstation/DECsystem 3100
|
||||
* and 2100 (KN01) systems equipped with parity error detection
|
||||
* logic.
|
||||
*
|
||||
* Copyright (c) 2005 Maciej W. Rozycki
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/inst.h>
|
||||
#include <asm/irq_regs.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <asm/dec/kn01.h>
|
||||
|
||||
|
||||
/* CP0 hazard avoidance. */
|
||||
#define BARRIER \
|
||||
__asm__ __volatile__( \
|
||||
".set push\n\t" \
|
||||
".set noreorder\n\t" \
|
||||
"nop\n\t" \
|
||||
".set pop\n\t")
|
||||
|
||||
/*
|
||||
* Bits 7:0 of the Control Register are write-only -- the
|
||||
* corresponding bits of the Status Register have a different
|
||||
* meaning. Hence we use a cache. It speeds up things a bit
|
||||
* as well.
|
||||
*
|
||||
* There is no default value -- it has to be initialized.
|
||||
*/
|
||||
u16 cached_kn01_csr;
|
||||
static DEFINE_RAW_SPINLOCK(kn01_lock);
|
||||
|
||||
|
||||
static inline void dec_kn01_be_ack(void)
|
||||
{
|
||||
volatile u16 *csr = (void *)CKSEG1ADDR(KN01_SLOT_BASE + KN01_CSR);
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&kn01_lock, flags);
|
||||
|
||||
*csr = cached_kn01_csr | KN01_CSR_MEMERR; /* Clear bus IRQ. */
|
||||
iob();
|
||||
|
||||
raw_spin_unlock_irqrestore(&kn01_lock, flags);
|
||||
}
|
||||
|
||||
static int dec_kn01_be_backend(struct pt_regs *regs, int is_fixup, int invoker)
|
||||
{
|
||||
volatile u32 *kn01_erraddr = (void *)CKSEG1ADDR(KN01_SLOT_BASE +
|
||||
KN01_ERRADDR);
|
||||
|
||||
static const char excstr[] = "exception";
|
||||
static const char intstr[] = "interrupt";
|
||||
static const char cpustr[] = "CPU";
|
||||
static const char mreadstr[] = "memory read";
|
||||
static const char readstr[] = "read";
|
||||
static const char writestr[] = "write";
|
||||
static const char timestr[] = "timeout";
|
||||
static const char paritystr[] = "parity error";
|
||||
|
||||
int data = regs->cp0_cause & 4;
|
||||
unsigned int __user *pc = (unsigned int __user *)regs->cp0_epc +
|
||||
((regs->cp0_cause & CAUSEF_BD) != 0);
|
||||
union mips_instruction insn;
|
||||
unsigned long entrylo, offset;
|
||||
long asid, entryhi, vaddr;
|
||||
|
||||
const char *kind, *agent, *cycle, *event;
|
||||
unsigned long address;
|
||||
|
||||
u32 erraddr = *kn01_erraddr;
|
||||
int action = MIPS_BE_FATAL;
|
||||
|
||||
/* Ack ASAP, so that any subsequent errors get caught. */
|
||||
dec_kn01_be_ack();
|
||||
|
||||
kind = invoker ? intstr : excstr;
|
||||
|
||||
agent = cpustr;
|
||||
|
||||
if (invoker)
|
||||
address = erraddr;
|
||||
else {
|
||||
/* Bloody hardware doesn't record the address for reads... */
|
||||
if (data) {
|
||||
/* This never faults. */
|
||||
__get_user(insn.word, pc);
|
||||
vaddr = regs->regs[insn.i_format.rs] +
|
||||
insn.i_format.simmediate;
|
||||
} else
|
||||
vaddr = (long)pc;
|
||||
if (KSEGX(vaddr) == CKSEG0 || KSEGX(vaddr) == CKSEG1)
|
||||
address = CPHYSADDR(vaddr);
|
||||
else {
|
||||
/* Peek at what physical address the CPU used. */
|
||||
asid = read_c0_entryhi();
|
||||
entryhi = asid & (PAGE_SIZE - 1);
|
||||
entryhi |= vaddr & ~(PAGE_SIZE - 1);
|
||||
write_c0_entryhi(entryhi);
|
||||
BARRIER;
|
||||
tlb_probe();
|
||||
/* No need to check for presence. */
|
||||
tlb_read();
|
||||
entrylo = read_c0_entrylo0();
|
||||
write_c0_entryhi(asid);
|
||||
offset = vaddr & (PAGE_SIZE - 1);
|
||||
address = (entrylo & ~(PAGE_SIZE - 1)) | offset;
|
||||
}
|
||||
}
|
||||
|
||||
/* Treat low 256MB as memory, high -- as I/O. */
|
||||
if (address < 0x10000000) {
|
||||
cycle = mreadstr;
|
||||
event = paritystr;
|
||||
} else {
|
||||
cycle = invoker ? writestr : readstr;
|
||||
event = timestr;
|
||||
}
|
||||
|
||||
if (is_fixup)
|
||||
action = MIPS_BE_FIXUP;
|
||||
|
||||
if (action != MIPS_BE_FIXUP)
|
||||
printk(KERN_ALERT "Bus error %s: %s %s %s at %#010lx\n",
|
||||
kind, agent, cycle, event, address);
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
int dec_kn01_be_handler(struct pt_regs *regs, int is_fixup)
|
||||
{
|
||||
return dec_kn01_be_backend(regs, is_fixup, 0);
|
||||
}
|
||||
|
||||
irqreturn_t dec_kn01_be_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
volatile u16 *csr = (void *)CKSEG1ADDR(KN01_SLOT_BASE + KN01_CSR);
|
||||
struct pt_regs *regs = get_irq_regs();
|
||||
int action;
|
||||
|
||||
if (!(*csr & KN01_CSR_MEMERR))
|
||||
return IRQ_NONE; /* Must have been video. */
|
||||
|
||||
action = dec_kn01_be_backend(regs, 0, 1);
|
||||
|
||||
if (action == MIPS_BE_DISCARD)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/*
|
||||
* FIXME: Find the affected processes and kill them, otherwise
|
||||
* we must die.
|
||||
*
|
||||
* The interrupt is asynchronously delivered thus EPC and RA
|
||||
* may be irrelevant, but are printed for a reference.
|
||||
*/
|
||||
printk(KERN_ALERT "Fatal bus interrupt, epc == %08lx, ra == %08lx\n",
|
||||
regs->cp0_epc, regs->regs[31]);
|
||||
die("Unrecoverable bus error", regs);
|
||||
}
|
||||
|
||||
|
||||
void __init dec_kn01_be_init(void)
|
||||
{
|
||||
volatile u16 *csr = (void *)CKSEG1ADDR(KN01_SLOT_BASE + KN01_CSR);
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&kn01_lock, flags);
|
||||
|
||||
/* Preset write-only bits of the Control Register cache. */
|
||||
cached_kn01_csr = *csr;
|
||||
cached_kn01_csr &= KN01_CSR_STATUS | KN01_CSR_PARDIS | KN01_CSR_TXDIS;
|
||||
cached_kn01_csr |= KN01_CSR_LEDS;
|
||||
|
||||
/* Enable parity error detection. */
|
||||
cached_kn01_csr &= ~KN01_CSR_PARDIS;
|
||||
*csr = cached_kn01_csr;
|
||||
iob();
|
||||
|
||||
raw_spin_unlock_irqrestore(&kn01_lock, flags);
|
||||
|
||||
/* Clear any leftover errors from the firmware. */
|
||||
dec_kn01_be_ack();
|
||||
}
|
79
arch/mips/dec/kn02-irq.c
Normal file
79
arch/mips/dec/kn02-irq.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* DECstation 5000/200 (KN02) Control and Status Register
|
||||
* interrupts.
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2005 Maciej W. Rozycki
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/dec/kn02.h>
|
||||
|
||||
|
||||
/*
|
||||
* Bits 7:0 of the Control Register are write-only -- the
|
||||
* corresponding bits of the Status Register have a different
|
||||
* meaning. Hence we use a cache. It speeds up things a bit
|
||||
* as well.
|
||||
*
|
||||
* There is no default value -- it has to be initialized.
|
||||
*/
|
||||
u32 cached_kn02_csr;
|
||||
|
||||
static int kn02_irq_base;
|
||||
|
||||
static void unmask_kn02_irq(struct irq_data *d)
|
||||
{
|
||||
volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE +
|
||||
KN02_CSR);
|
||||
|
||||
cached_kn02_csr |= (1 << (d->irq - kn02_irq_base + 16));
|
||||
*csr = cached_kn02_csr;
|
||||
}
|
||||
|
||||
static void mask_kn02_irq(struct irq_data *d)
|
||||
{
|
||||
volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE +
|
||||
KN02_CSR);
|
||||
|
||||
cached_kn02_csr &= ~(1 << (d->irq - kn02_irq_base + 16));
|
||||
*csr = cached_kn02_csr;
|
||||
}
|
||||
|
||||
static void ack_kn02_irq(struct irq_data *d)
|
||||
{
|
||||
mask_kn02_irq(d);
|
||||
iob();
|
||||
}
|
||||
|
||||
static struct irq_chip kn02_irq_type = {
|
||||
.name = "KN02-CSR",
|
||||
.irq_ack = ack_kn02_irq,
|
||||
.irq_mask = mask_kn02_irq,
|
||||
.irq_mask_ack = ack_kn02_irq,
|
||||
.irq_unmask = unmask_kn02_irq,
|
||||
};
|
||||
|
||||
void __init init_kn02_irqs(int base)
|
||||
{
|
||||
volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE +
|
||||
KN02_CSR);
|
||||
int i;
|
||||
|
||||
/* Mask interrupts. */
|
||||
cached_kn02_csr &= ~KN02_CSR_IOINTEN;
|
||||
*csr = cached_kn02_csr;
|
||||
iob();
|
||||
|
||||
for (i = base; i < base + KN02_IRQ_LINES; i++)
|
||||
irq_set_chip_and_handler(i, &kn02_irq_type, handle_level_irq);
|
||||
|
||||
kn02_irq_base = base;
|
||||
}
|
139
arch/mips/dec/kn02xa-berr.c
Normal file
139
arch/mips/dec/kn02xa-berr.c
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Bus error event handling code for 5000-series systems equipped
|
||||
* with parity error detection logic, i.e. DECstation/DECsystem
|
||||
* 5000/120, /125, /133 (KN02-BA), 5000/150 (KN04-BA) and Personal
|
||||
* DECstation/DECsystem 5000/20, /25, /33 (KN02-CA), 5000/50
|
||||
* (KN04-CA) systems.
|
||||
*
|
||||
* Copyright (c) 2005 Maciej W. Rozycki
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/cpu-type.h>
|
||||
#include <asm/irq_regs.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/traps.h>
|
||||
|
||||
#include <asm/dec/kn02ca.h>
|
||||
#include <asm/dec/kn02xa.h>
|
||||
#include <asm/dec/kn05.h>
|
||||
|
||||
static inline void dec_kn02xa_be_ack(void)
|
||||
{
|
||||
volatile u32 *mer = (void *)CKSEG1ADDR(KN02XA_MER);
|
||||
volatile u32 *mem_intr = (void *)CKSEG1ADDR(KN02XA_MEM_INTR);
|
||||
|
||||
*mer = KN02CA_MER_INTR; /* Clear errors; keep the ARC IRQ. */
|
||||
*mem_intr = 0; /* Any write clears the bus IRQ. */
|
||||
iob();
|
||||
}
|
||||
|
||||
static int dec_kn02xa_be_backend(struct pt_regs *regs, int is_fixup,
|
||||
int invoker)
|
||||
{
|
||||
volatile u32 *kn02xa_mer = (void *)CKSEG1ADDR(KN02XA_MER);
|
||||
volatile u32 *kn02xa_ear = (void *)CKSEG1ADDR(KN02XA_EAR);
|
||||
|
||||
static const char excstr[] = "exception";
|
||||
static const char intstr[] = "interrupt";
|
||||
static const char cpustr[] = "CPU";
|
||||
static const char mreadstr[] = "memory read";
|
||||
static const char readstr[] = "read";
|
||||
static const char writestr[] = "write";
|
||||
static const char timestr[] = "timeout";
|
||||
static const char paritystr[] = "parity error";
|
||||
static const char lanestat[][4] = { " OK", "BAD" };
|
||||
|
||||
const char *kind, *agent, *cycle, *event;
|
||||
unsigned long address;
|
||||
|
||||
u32 mer = *kn02xa_mer;
|
||||
u32 ear = *kn02xa_ear;
|
||||
int action = MIPS_BE_FATAL;
|
||||
|
||||
/* Ack ASAP, so that any subsequent errors get caught. */
|
||||
dec_kn02xa_be_ack();
|
||||
|
||||
kind = invoker ? intstr : excstr;
|
||||
|
||||
/* No DMA errors? */
|
||||
agent = cpustr;
|
||||
|
||||
address = ear & KN02XA_EAR_ADDRESS;
|
||||
|
||||
/* Low 256MB is decoded as memory, high -- as TC. */
|
||||
if (address < 0x10000000) {
|
||||
cycle = mreadstr;
|
||||
event = paritystr;
|
||||
} else {
|
||||
cycle = invoker ? writestr : readstr;
|
||||
event = timestr;
|
||||
}
|
||||
|
||||
if (is_fixup)
|
||||
action = MIPS_BE_FIXUP;
|
||||
|
||||
if (action != MIPS_BE_FIXUP)
|
||||
printk(KERN_ALERT "Bus error %s: %s %s %s at %#010lx\n",
|
||||
kind, agent, cycle, event, address);
|
||||
|
||||
if (action != MIPS_BE_FIXUP && address < 0x10000000)
|
||||
printk(KERN_ALERT " Byte lane status %#3x -- "
|
||||
"#3: %s, #2: %s, #1: %s, #0: %s\n",
|
||||
(mer & KN02XA_MER_BYTERR) >> 8,
|
||||
lanestat[(mer & KN02XA_MER_BYTERR_3) != 0],
|
||||
lanestat[(mer & KN02XA_MER_BYTERR_2) != 0],
|
||||
lanestat[(mer & KN02XA_MER_BYTERR_1) != 0],
|
||||
lanestat[(mer & KN02XA_MER_BYTERR_0) != 0]);
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
int dec_kn02xa_be_handler(struct pt_regs *regs, int is_fixup)
|
||||
{
|
||||
return dec_kn02xa_be_backend(regs, is_fixup, 0);
|
||||
}
|
||||
|
||||
irqreturn_t dec_kn02xa_be_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct pt_regs *regs = get_irq_regs();
|
||||
int action = dec_kn02xa_be_backend(regs, 0, 1);
|
||||
|
||||
if (action == MIPS_BE_DISCARD)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/*
|
||||
* FIXME: Find the affected processes and kill them, otherwise
|
||||
* we must die.
|
||||
*
|
||||
* The interrupt is asynchronously delivered thus EPC and RA
|
||||
* may be irrelevant, but are printed for a reference.
|
||||
*/
|
||||
printk(KERN_ALERT "Fatal bus interrupt, epc == %08lx, ra == %08lx\n",
|
||||
regs->cp0_epc, regs->regs[31]);
|
||||
die("Unrecoverable bus error", regs);
|
||||
}
|
||||
|
||||
|
||||
void __init dec_kn02xa_be_init(void)
|
||||
{
|
||||
volatile u32 *mbcs = (void *)CKSEG1ADDR(KN4K_SLOT_BASE + KN4K_MB_CSR);
|
||||
|
||||
/* For KN04 we need to make sure EE (?) is enabled in the MB. */
|
||||
if (current_cpu_type() == CPU_R4000SC)
|
||||
*mbcs |= KN4K_MB_CSR_EE;
|
||||
fast_iob();
|
||||
|
||||
/* Clear any leftover errors from the firmware. */
|
||||
dec_kn02xa_be_ack();
|
||||
}
|
44
arch/mips/dec/platform.c
Normal file
44
arch/mips/dec/platform.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* DEC platform devices.
|
||||
*
|
||||
* Copyright (c) 2014 Maciej W. Rozycki
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
static struct resource dec_rtc_resources[] = {
|
||||
{
|
||||
.name = "rtc",
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct cmos_rtc_board_info dec_rtc_info = {
|
||||
.flags = CMOS_RTC_FLAGS_NOFREQ,
|
||||
.address_space = 64,
|
||||
};
|
||||
|
||||
static struct platform_device dec_rtc_device = {
|
||||
.name = "rtc_cmos",
|
||||
.id = PLATFORM_DEVID_NONE,
|
||||
.dev.platform_data = &dec_rtc_info,
|
||||
.resource = dec_rtc_resources,
|
||||
.num_resources = ARRAY_SIZE(dec_rtc_resources),
|
||||
};
|
||||
|
||||
static int __init dec_add_devices(void)
|
||||
{
|
||||
dec_rtc_resources[0].start = RTC_PORT(0);
|
||||
dec_rtc_resources[0].end = RTC_PORT(0) + dec_kn_slot_size - 1;
|
||||
return platform_device_register(&dec_rtc_device);
|
||||
}
|
||||
|
||||
device_initcall(dec_add_devices);
|
8
arch/mips/dec/prom/Makefile
Normal file
8
arch/mips/dec/prom/Makefile
Normal file
|
@ -0,0 +1,8 @@
|
|||
#
|
||||
# Makefile for the DECstation prom monitor library routines
|
||||
# under Linux.
|
||||
#
|
||||
|
||||
lib-y += init.o memory.o cmdline.o identify.o console.o
|
||||
|
||||
lib-$(CONFIG_32BIT) += locore.o
|
39
arch/mips/dec/prom/cmdline.c
Normal file
39
arch/mips/dec/prom/cmdline.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* cmdline.c: read the command line passed to us by the PROM.
|
||||
*
|
||||
* Copyright (C) 1998 Harald Koerfgen
|
||||
* Copyright (C) 2002, 2004 Maciej W. Rozycki
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/dec/prom.h>
|
||||
|
||||
#undef PROM_DEBUG
|
||||
|
||||
void __init prom_init_cmdline(s32 argc, s32 *argv, u32 magic)
|
||||
{
|
||||
char *arg;
|
||||
int start_arg, i;
|
||||
|
||||
/*
|
||||
* collect args and prepare cmd_line
|
||||
*/
|
||||
if (!prom_is_rex(magic))
|
||||
start_arg = 1;
|
||||
else
|
||||
start_arg = 2;
|
||||
for (i = start_arg; i < argc; i++) {
|
||||
arg = (void *)(long)(argv[i]);
|
||||
strcat(arcs_cmdline, arg);
|
||||
if (i < (argc - 1))
|
||||
strcat(arcs_cmdline, " ");
|
||||
}
|
||||
|
||||
#ifdef PROM_DEBUG
|
||||
printk("arcs_cmdline: %s\n", &(arcs_cmdline[0]));
|
||||
#endif
|
||||
}
|
45
arch/mips/dec/prom/console.c
Normal file
45
arch/mips/dec/prom/console.c
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* DECstation PROM-based early console support.
|
||||
*
|
||||
* Copyright (C) 2004, 2007 Maciej W. Rozycki
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
#include <linux/console.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <asm/dec/prom.h>
|
||||
|
||||
static void __init prom_console_write(struct console *con, const char *s,
|
||||
unsigned int c)
|
||||
{
|
||||
char buf[81];
|
||||
unsigned int chunk = sizeof(buf) - 1;
|
||||
|
||||
while (c > 0) {
|
||||
if (chunk > c)
|
||||
chunk = c;
|
||||
memcpy(buf, s, chunk);
|
||||
buf[chunk] = '\0';
|
||||
prom_printf("%s", buf);
|
||||
s += chunk;
|
||||
c -= chunk;
|
||||
}
|
||||
}
|
||||
|
||||
static struct console promcons __initdata = {
|
||||
.name = "prom",
|
||||
.write = prom_console_write,
|
||||
.flags = CON_BOOT | CON_PRINTBUFFER,
|
||||
.index = -1,
|
||||
};
|
||||
|
||||
void __init register_prom_console(void)
|
||||
{
|
||||
register_console(&promcons);
|
||||
}
|
14
arch/mips/dec/prom/dectypes.h
Normal file
14
arch/mips/dec/prom/dectypes.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef DECTYPES
|
||||
#define DECTYPES
|
||||
|
||||
#define DS2100_3100 1 /* DS2100/3100 Pmax */
|
||||
#define DS5000_200 2 /* DS5000/200 3max */
|
||||
#define DS5000_1XX 3 /* DS5000/1xx kmin */
|
||||
#define DS5000_2X0 4 /* DS5000/2x0 3max+ */
|
||||
#define DS5800 5 /* DS5800 Isis */
|
||||
#define DS5400 6 /* DS5400 MIPSfair */
|
||||
#define DS5000_XX 7 /* DS5000/xx maxine */
|
||||
#define DS5500 11 /* DS5500 MIPSfair-2 */
|
||||
#define DS5100 12 /* DS5100 MIPSmate */
|
||||
|
||||
#endif
|
186
arch/mips/dec/prom/identify.c
Normal file
186
arch/mips/dec/prom/identify.c
Normal file
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* identify.c: machine identification code.
|
||||
*
|
||||
* Copyright (C) 1998 Harald Koerfgen and Paul M. Antoine
|
||||
* Copyright (C) 2002, 2003, 2004, 2005 Maciej W. Rozycki
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
|
||||
#include <asm/dec/ioasic.h>
|
||||
#include <asm/dec/ioasic_addrs.h>
|
||||
#include <asm/dec/kn01.h>
|
||||
#include <asm/dec/kn02.h>
|
||||
#include <asm/dec/kn02ba.h>
|
||||
#include <asm/dec/kn02ca.h>
|
||||
#include <asm/dec/kn03.h>
|
||||
#include <asm/dec/kn230.h>
|
||||
#include <asm/dec/prom.h>
|
||||
#include <asm/dec/system.h>
|
||||
|
||||
#include "dectypes.h"
|
||||
|
||||
static const char *dec_system_strings[] = {
|
||||
[MACH_DSUNKNOWN] "unknown DECstation",
|
||||
[MACH_DS23100] "DECstation 2100/3100",
|
||||
[MACH_DS5100] "DECsystem 5100",
|
||||
[MACH_DS5000_200] "DECstation 5000/200",
|
||||
[MACH_DS5000_1XX] "DECstation 5000/1xx",
|
||||
[MACH_DS5000_XX] "Personal DECstation 5000/xx",
|
||||
[MACH_DS5000_2X0] "DECstation 5000/2x0",
|
||||
[MACH_DS5400] "DECsystem 5400",
|
||||
[MACH_DS5500] "DECsystem 5500",
|
||||
[MACH_DS5800] "DECsystem 5800",
|
||||
[MACH_DS5900] "DECsystem 5900",
|
||||
};
|
||||
|
||||
const char *get_system_type(void)
|
||||
{
|
||||
#define STR_BUF_LEN 64
|
||||
static char system[STR_BUF_LEN];
|
||||
static int called = 0;
|
||||
|
||||
if (called == 0) {
|
||||
called = 1;
|
||||
snprintf(system, STR_BUF_LEN, "Digital %s",
|
||||
dec_system_strings[mips_machtype]);
|
||||
}
|
||||
|
||||
return system;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Setup essential system-specific memory addresses. We need them
|
||||
* early. Semantically the functions belong to prom/init.c, but they
|
||||
* are compact enough we want them inlined. --macro
|
||||
*/
|
||||
volatile u8 *dec_rtc_base;
|
||||
|
||||
EXPORT_SYMBOL(dec_rtc_base);
|
||||
|
||||
static inline void prom_init_kn01(void)
|
||||
{
|
||||
dec_kn_slot_base = KN01_SLOT_BASE;
|
||||
dec_kn_slot_size = KN01_SLOT_SIZE;
|
||||
|
||||
dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + KN01_RTC);
|
||||
}
|
||||
|
||||
static inline void prom_init_kn230(void)
|
||||
{
|
||||
dec_kn_slot_base = KN01_SLOT_BASE;
|
||||
dec_kn_slot_size = KN01_SLOT_SIZE;
|
||||
|
||||
dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + KN01_RTC);
|
||||
}
|
||||
|
||||
static inline void prom_init_kn02(void)
|
||||
{
|
||||
dec_kn_slot_base = KN02_SLOT_BASE;
|
||||
dec_kn_slot_size = KN02_SLOT_SIZE;
|
||||
dec_tc_bus = 1;
|
||||
|
||||
dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + KN02_RTC);
|
||||
}
|
||||
|
||||
static inline void prom_init_kn02xa(void)
|
||||
{
|
||||
dec_kn_slot_base = KN02XA_SLOT_BASE;
|
||||
dec_kn_slot_size = IOASIC_SLOT_SIZE;
|
||||
dec_tc_bus = 1;
|
||||
|
||||
ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL);
|
||||
dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY);
|
||||
}
|
||||
|
||||
static inline void prom_init_kn03(void)
|
||||
{
|
||||
dec_kn_slot_base = KN03_SLOT_BASE;
|
||||
dec_kn_slot_size = IOASIC_SLOT_SIZE;
|
||||
dec_tc_bus = 1;
|
||||
|
||||
ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL);
|
||||
dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY);
|
||||
}
|
||||
|
||||
|
||||
void __init prom_identify_arch(u32 magic)
|
||||
{
|
||||
unsigned char dec_cpunum, dec_firmrev, dec_etc, dec_systype;
|
||||
u32 dec_sysid;
|
||||
|
||||
if (!prom_is_rex(magic)) {
|
||||
dec_sysid = simple_strtoul(prom_getenv("systype"),
|
||||
(char **)0, 0);
|
||||
} else {
|
||||
dec_sysid = rex_getsysid();
|
||||
if (dec_sysid == 0) {
|
||||
printk("Zero sysid returned from PROM! "
|
||||
"Assuming a PMAX-like machine.\n");
|
||||
dec_sysid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
dec_cpunum = (dec_sysid & 0xff000000) >> 24;
|
||||
dec_systype = (dec_sysid & 0xff0000) >> 16;
|
||||
dec_firmrev = (dec_sysid & 0xff00) >> 8;
|
||||
dec_etc = dec_sysid & 0xff;
|
||||
|
||||
/*
|
||||
* FIXME: This may not be an exhaustive list of DECStations/Servers!
|
||||
* Put all model-specific initialisation calls here.
|
||||
*/
|
||||
switch (dec_systype) {
|
||||
case DS2100_3100:
|
||||
mips_machtype = MACH_DS23100;
|
||||
prom_init_kn01();
|
||||
break;
|
||||
case DS5100: /* DS5100 MIPSMATE */
|
||||
mips_machtype = MACH_DS5100;
|
||||
prom_init_kn230();
|
||||
break;
|
||||
case DS5000_200: /* DS5000 3max */
|
||||
mips_machtype = MACH_DS5000_200;
|
||||
prom_init_kn02();
|
||||
break;
|
||||
case DS5000_1XX: /* DS5000/100 3min */
|
||||
mips_machtype = MACH_DS5000_1XX;
|
||||
prom_init_kn02xa();
|
||||
break;
|
||||
case DS5000_2X0: /* DS5000/240 3max+ or DS5900 bigmax */
|
||||
mips_machtype = MACH_DS5000_2X0;
|
||||
prom_init_kn03();
|
||||
if (!(ioasic_read(IO_REG_SIR) & KN03_IO_INR_3MAXP))
|
||||
mips_machtype = MACH_DS5900;
|
||||
break;
|
||||
case DS5000_XX: /* Personal DS5000/xx maxine */
|
||||
mips_machtype = MACH_DS5000_XX;
|
||||
prom_init_kn02xa();
|
||||
break;
|
||||
case DS5800: /* DS5800 Isis */
|
||||
mips_machtype = MACH_DS5800;
|
||||
break;
|
||||
case DS5400: /* DS5400 MIPSfair */
|
||||
mips_machtype = MACH_DS5400;
|
||||
break;
|
||||
case DS5500: /* DS5500 MIPSfair-2 */
|
||||
mips_machtype = MACH_DS5500;
|
||||
break;
|
||||
default:
|
||||
mips_machtype = MACH_DSUNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mips_machtype == MACH_DSUNKNOWN)
|
||||
printk("This is an %s, id is %x\n",
|
||||
dec_system_strings[mips_machtype], dec_systype);
|
||||
else
|
||||
printk("This is a %s\n", dec_system_strings[mips_machtype]);
|
||||
}
|
136
arch/mips/dec/prom/init.c
Normal file
136
arch/mips/dec/prom/init.c
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* init.c: PROM library initialisation code.
|
||||
*
|
||||
* Copyright (C) 1998 Harald Koerfgen
|
||||
* Copyright (C) 2002, 2004 Maciej W. Rozycki
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/cpu-type.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#include <asm/dec/prom.h>
|
||||
|
||||
|
||||
int (*__rex_bootinit)(void);
|
||||
int (*__rex_bootread)(void);
|
||||
int (*__rex_getbitmap)(memmap *);
|
||||
unsigned long *(*__rex_slot_address)(int);
|
||||
void *(*__rex_gettcinfo)(void);
|
||||
int (*__rex_getsysid)(void);
|
||||
void (*__rex_clear_cache)(void);
|
||||
|
||||
int (*__prom_getchar)(void);
|
||||
char *(*__prom_getenv)(char *);
|
||||
int (*__prom_printf)(char *, ...);
|
||||
|
||||
int (*__pmax_open)(char*, int);
|
||||
int (*__pmax_lseek)(int, long, int);
|
||||
int (*__pmax_read)(int, void *, int);
|
||||
int (*__pmax_close)(int);
|
||||
|
||||
|
||||
/*
|
||||
* Detect which PROM the DECSTATION has, and set the callback vectors
|
||||
* appropriately.
|
||||
*/
|
||||
void __init which_prom(s32 magic, s32 *prom_vec)
|
||||
{
|
||||
/*
|
||||
* No sign of the REX PROM's magic number means we assume a non-REX
|
||||
* machine (i.e. we're on a DS2100/3100, DS5100 or DS5000/2xx)
|
||||
*/
|
||||
if (prom_is_rex(magic)) {
|
||||
/*
|
||||
* Set up prom abstraction structure with REX entry points.
|
||||
*/
|
||||
__rex_bootinit =
|
||||
(void *)(long)*(prom_vec + REX_PROM_BOOTINIT);
|
||||
__rex_bootread =
|
||||
(void *)(long)*(prom_vec + REX_PROM_BOOTREAD);
|
||||
__rex_getbitmap =
|
||||
(void *)(long)*(prom_vec + REX_PROM_GETBITMAP);
|
||||
__prom_getchar =
|
||||
(void *)(long)*(prom_vec + REX_PROM_GETCHAR);
|
||||
__prom_getenv =
|
||||
(void *)(long)*(prom_vec + REX_PROM_GETENV);
|
||||
__rex_getsysid =
|
||||
(void *)(long)*(prom_vec + REX_PROM_GETSYSID);
|
||||
__rex_gettcinfo =
|
||||
(void *)(long)*(prom_vec + REX_PROM_GETTCINFO);
|
||||
__prom_printf =
|
||||
(void *)(long)*(prom_vec + REX_PROM_PRINTF);
|
||||
__rex_slot_address =
|
||||
(void *)(long)*(prom_vec + REX_PROM_SLOTADDR);
|
||||
__rex_clear_cache =
|
||||
(void *)(long)*(prom_vec + REX_PROM_CLEARCACHE);
|
||||
} else {
|
||||
/*
|
||||
* Set up prom abstraction structure with non-REX entry points.
|
||||
*/
|
||||
__prom_getchar = (void *)PMAX_PROM_GETCHAR;
|
||||
__prom_getenv = (void *)PMAX_PROM_GETENV;
|
||||
__prom_printf = (void *)PMAX_PROM_PRINTF;
|
||||
__pmax_open = (void *)PMAX_PROM_OPEN;
|
||||
__pmax_lseek = (void *)PMAX_PROM_LSEEK;
|
||||
__pmax_read = (void *)PMAX_PROM_READ;
|
||||
__pmax_close = (void *)PMAX_PROM_CLOSE;
|
||||
}
|
||||
}
|
||||
|
||||
void __init prom_init(void)
|
||||
{
|
||||
extern void dec_machine_halt(void);
|
||||
static char cpu_msg[] __initdata =
|
||||
"Sorry, this kernel is compiled for a wrong CPU type!\n";
|
||||
s32 argc = fw_arg0;
|
||||
s32 *argv = (void *)fw_arg1;
|
||||
u32 magic = fw_arg2;
|
||||
s32 *prom_vec = (void *)fw_arg3;
|
||||
|
||||
/*
|
||||
* Determine which PROM we have
|
||||
* (and therefore which machine we're on!)
|
||||
*/
|
||||
which_prom(magic, prom_vec);
|
||||
|
||||
if (prom_is_rex(magic))
|
||||
rex_clear_cache();
|
||||
|
||||
/* Register the early console. */
|
||||
register_prom_console();
|
||||
|
||||
/* Were we compiled with the right CPU option? */
|
||||
#if defined(CONFIG_CPU_R3000)
|
||||
if ((current_cpu_type() == CPU_R4000SC) ||
|
||||
(current_cpu_type() == CPU_R4400SC)) {
|
||||
static char r4k_msg[] __initdata =
|
||||
"Please recompile with \"CONFIG_CPU_R4x00 = y\".\n";
|
||||
printk(cpu_msg);
|
||||
printk(r4k_msg);
|
||||
dec_machine_halt();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CPU_R4X00)
|
||||
if ((current_cpu_type() == CPU_R3000) ||
|
||||
(current_cpu_type() == CPU_R3000A)) {
|
||||
static char r3k_msg[] __initdata =
|
||||
"Please recompile with \"CONFIG_CPU_R3000 = y\".\n";
|
||||
printk(cpu_msg);
|
||||
printk(r3k_msg);
|
||||
dec_machine_halt();
|
||||
}
|
||||
#endif
|
||||
|
||||
prom_meminit(magic);
|
||||
prom_identify_arch(magic);
|
||||
prom_init_cmdline(argc, argv, magic);
|
||||
}
|
29
arch/mips/dec/prom/locore.S
Normal file
29
arch/mips/dec/prom/locore.S
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* locore.S
|
||||
*/
|
||||
#include <asm/asm.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/mipsregs.h>
|
||||
|
||||
.text
|
||||
|
||||
/*
|
||||
* Simple general exception handling routine. This one is used for the
|
||||
* Memory sizing routine for pmax machines. HK
|
||||
*/
|
||||
|
||||
NESTED(genexcept_early, 0, sp)
|
||||
.set noat
|
||||
.set noreorder
|
||||
|
||||
mfc0 k0, CP0_STATUS
|
||||
la k1, mem_err
|
||||
|
||||
sw k0, 0(k1)
|
||||
|
||||
mfc0 k0, CP0_EPC
|
||||
nop
|
||||
addiu k0, 4 # skip the causing instruction
|
||||
jr k0
|
||||
rfe
|
||||
END(genexcept_early)
|
118
arch/mips/dec/prom/memory.c
Normal file
118
arch/mips/dec/prom/memory.c
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* memory.c: memory initialisation code.
|
||||
*
|
||||
* Copyright (C) 1998 Harald Koerfgen, Frieder Streffer and Paul M. Antoine
|
||||
* Copyright (C) 2000, 2002 Maciej W. Rozycki
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/dec/machtype.h>
|
||||
#include <asm/dec/prom.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/sections.h>
|
||||
|
||||
|
||||
volatile unsigned long mem_err; /* So we know an error occurred */
|
||||
|
||||
/*
|
||||
* Probe memory in 4MB chunks, waiting for an error to tell us we've fallen
|
||||
* off the end of real memory. Only suitable for the 2100/3100's (PMAX).
|
||||
*/
|
||||
|
||||
#define CHUNK_SIZE 0x400000
|
||||
|
||||
static inline void pmax_setup_memory_region(void)
|
||||
{
|
||||
volatile unsigned char *memory_page, dummy;
|
||||
char old_handler[0x80];
|
||||
extern char genexcept_early;
|
||||
|
||||
/* Install exception handler */
|
||||
memcpy(&old_handler, (void *)(CKSEG0 + 0x80), 0x80);
|
||||
memcpy((void *)(CKSEG0 + 0x80), &genexcept_early, 0x80);
|
||||
|
||||
/* read unmapped and uncached (KSEG1)
|
||||
* DECstations have at least 4MB RAM
|
||||
* Assume less than 480MB of RAM, as this is max for 5000/2xx
|
||||
* FIXME this should be replaced by the first free page!
|
||||
*/
|
||||
for (memory_page = (unsigned char *)CKSEG1 + CHUNK_SIZE;
|
||||
mem_err == 0 && memory_page < (unsigned char *)CKSEG1 + 0x1e00000;
|
||||
memory_page += CHUNK_SIZE) {
|
||||
dummy = *memory_page;
|
||||
}
|
||||
memcpy((void *)(CKSEG0 + 0x80), &old_handler, 0x80);
|
||||
|
||||
add_memory_region(0, (unsigned long)memory_page - CKSEG1 - CHUNK_SIZE,
|
||||
BOOT_MEM_RAM);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the REX prom calls to get hold of the memory bitmap, and thence
|
||||
* determine memory size.
|
||||
*/
|
||||
static inline void rex_setup_memory_region(void)
|
||||
{
|
||||
int i, bitmap_size;
|
||||
unsigned long mem_start = 0, mem_size = 0;
|
||||
memmap *bm;
|
||||
|
||||
/* some free 64k */
|
||||
bm = (memmap *)CKSEG0ADDR(0x28000);
|
||||
|
||||
bitmap_size = rex_getbitmap(bm);
|
||||
|
||||
for (i = 0; i < bitmap_size; i++) {
|
||||
/* FIXME: very simplistically only add full sets of pages */
|
||||
if (bm->bitmap[i] == 0xff)
|
||||
mem_size += (8 * bm->pagesize);
|
||||
else if (!mem_size)
|
||||
mem_start += (8 * bm->pagesize);
|
||||
else {
|
||||
add_memory_region(mem_start, mem_size, BOOT_MEM_RAM);
|
||||
mem_start += mem_size + (8 * bm->pagesize);
|
||||
mem_size = 0;
|
||||
}
|
||||
}
|
||||
if (mem_size)
|
||||
add_memory_region(mem_start, mem_size, BOOT_MEM_RAM);
|
||||
}
|
||||
|
||||
void __init prom_meminit(u32 magic)
|
||||
{
|
||||
if (!prom_is_rex(magic))
|
||||
pmax_setup_memory_region();
|
||||
else
|
||||
rex_setup_memory_region();
|
||||
}
|
||||
|
||||
void __init prom_free_prom_memory(void)
|
||||
{
|
||||
unsigned long end;
|
||||
|
||||
/*
|
||||
* Free everything below the kernel itself but leave
|
||||
* the first page reserved for the exception handlers.
|
||||
*/
|
||||
|
||||
#if IS_ENABLED(CONFIG_DECLANCE)
|
||||
/*
|
||||
* Leave 128 KB reserved for Lance memory for
|
||||
* IOASIC DECstations.
|
||||
*
|
||||
* XXX: save this address for use in dec_lance.c?
|
||||
*/
|
||||
if (IOASIC)
|
||||
end = __pa(&_text) - 0x00020000;
|
||||
else
|
||||
#endif
|
||||
end = __pa(&_text);
|
||||
|
||||
free_init_pages("unused PROM memory", PAGE_SIZE, end);
|
||||
}
|
40
arch/mips/dec/reset.c
Normal file
40
arch/mips/dec/reset.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Reset a DECstation machine.
|
||||
*
|
||||
* Copyright (C) 199x the Anonymous
|
||||
* Copyright (C) 2001, 2002, 2003 Maciej W. Rozycki
|
||||
*/
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
|
||||
typedef void __noreturn (* noret_func_t)(void);
|
||||
|
||||
static inline void __noreturn back_to_prom(void)
|
||||
{
|
||||
noret_func_t func = (void *)CKSEG1ADDR(0x1fc00000);
|
||||
|
||||
func();
|
||||
}
|
||||
|
||||
void __noreturn dec_machine_restart(char *command)
|
||||
{
|
||||
back_to_prom();
|
||||
}
|
||||
|
||||
void __noreturn dec_machine_halt(void)
|
||||
{
|
||||
back_to_prom();
|
||||
}
|
||||
|
||||
void __noreturn dec_machine_power_off(void)
|
||||
{
|
||||
/* DECstations don't have a software power switch */
|
||||
back_to_prom();
|
||||
}
|
||||
|
||||
irqreturn_t dec_intr_halt(int irq, void *dev_id)
|
||||
{
|
||||
dec_machine_halt();
|
||||
}
|
776
arch/mips/dec/setup.c
Normal file
776
arch/mips/dec/setup.c
Normal file
|
@ -0,0 +1,776 @@
|
|||
/*
|
||||
* System-specific setup, especially interrupts.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 1998 Harald Koerfgen
|
||||
* Copyright (C) 2000, 2001, 2002, 2003, 2005 Maciej W. Rozycki
|
||||
*/
|
||||
#include <linux/console.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/cpu-features.h>
|
||||
#include <asm/cpu-type.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/irq_cpu.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/wbflush.h>
|
||||
|
||||
#include <asm/dec/interrupts.h>
|
||||
#include <asm/dec/ioasic.h>
|
||||
#include <asm/dec/ioasic_addrs.h>
|
||||
#include <asm/dec/ioasic_ints.h>
|
||||
#include <asm/dec/kn01.h>
|
||||
#include <asm/dec/kn02.h>
|
||||
#include <asm/dec/kn02ba.h>
|
||||
#include <asm/dec/kn02ca.h>
|
||||
#include <asm/dec/kn03.h>
|
||||
#include <asm/dec/kn230.h>
|
||||
#include <asm/dec/system.h>
|
||||
|
||||
|
||||
extern void dec_machine_restart(char *command);
|
||||
extern void dec_machine_halt(void);
|
||||
extern void dec_machine_power_off(void);
|
||||
extern irqreturn_t dec_intr_halt(int irq, void *dev_id);
|
||||
|
||||
unsigned long dec_kn_slot_base, dec_kn_slot_size;
|
||||
|
||||
EXPORT_SYMBOL(dec_kn_slot_base);
|
||||
EXPORT_SYMBOL(dec_kn_slot_size);
|
||||
|
||||
int dec_tc_bus;
|
||||
|
||||
DEFINE_SPINLOCK(ioasic_ssr_lock);
|
||||
|
||||
volatile u32 *ioasic_base;
|
||||
|
||||
EXPORT_SYMBOL(ioasic_base);
|
||||
|
||||
/*
|
||||
* IRQ routing and priority tables. Priorites are set as follows:
|
||||
*
|
||||
* KN01 KN230 KN02 KN02-BA KN02-CA KN03
|
||||
*
|
||||
* MEMORY CPU CPU CPU ASIC CPU CPU
|
||||
* RTC CPU CPU CPU ASIC CPU CPU
|
||||
* DMA - - - ASIC ASIC ASIC
|
||||
* SERIAL0 CPU CPU CSR ASIC ASIC ASIC
|
||||
* SERIAL1 - - - ASIC - ASIC
|
||||
* SCSI CPU CPU CSR ASIC ASIC ASIC
|
||||
* ETHERNET CPU * CSR ASIC ASIC ASIC
|
||||
* other - - - ASIC - -
|
||||
* TC2 - - CSR CPU ASIC ASIC
|
||||
* TC1 - - CSR CPU ASIC ASIC
|
||||
* TC0 - - CSR CPU ASIC ASIC
|
||||
* other - CPU - CPU ASIC ASIC
|
||||
* other - - - - CPU CPU
|
||||
*
|
||||
* * -- shared with SCSI
|
||||
*/
|
||||
|
||||
int dec_interrupt[DEC_NR_INTS] = {
|
||||
[0 ... DEC_NR_INTS - 1] = -1
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL(dec_interrupt);
|
||||
|
||||
int_ptr cpu_mask_nr_tbl[DEC_MAX_CPU_INTS][2] = {
|
||||
{ { .i = ~0 }, { .p = dec_intr_unimplemented } },
|
||||
};
|
||||
int_ptr asic_mask_nr_tbl[DEC_MAX_ASIC_INTS][2] = {
|
||||
{ { .i = ~0 }, { .p = asic_intr_unimplemented } },
|
||||
};
|
||||
int cpu_fpu_mask = DEC_CPU_IRQ_MASK(DEC_CPU_INR_FPU);
|
||||
|
||||
static struct irqaction ioirq = {
|
||||
.handler = no_action,
|
||||
.name = "cascade",
|
||||
.flags = IRQF_NO_THREAD,
|
||||
};
|
||||
static struct irqaction fpuirq = {
|
||||
.handler = no_action,
|
||||
.name = "fpu",
|
||||
.flags = IRQF_NO_THREAD,
|
||||
};
|
||||
|
||||
static struct irqaction busirq = {
|
||||
.name = "bus error",
|
||||
.flags = IRQF_NO_THREAD,
|
||||
};
|
||||
|
||||
static struct irqaction haltirq = {
|
||||
.handler = dec_intr_halt,
|
||||
.name = "halt",
|
||||
.flags = IRQF_NO_THREAD,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Bus error (DBE/IBE exceptions and bus interrupts) handling setup.
|
||||
*/
|
||||
static void __init dec_be_init(void)
|
||||
{
|
||||
switch (mips_machtype) {
|
||||
case MACH_DS23100: /* DS2100/DS3100 Pmin/Pmax */
|
||||
board_be_handler = dec_kn01_be_handler;
|
||||
busirq.handler = dec_kn01_be_interrupt;
|
||||
busirq.flags |= IRQF_SHARED;
|
||||
dec_kn01_be_init();
|
||||
break;
|
||||
case MACH_DS5000_1XX: /* DS5000/1xx 3min */
|
||||
case MACH_DS5000_XX: /* DS5000/xx Maxine */
|
||||
board_be_handler = dec_kn02xa_be_handler;
|
||||
busirq.handler = dec_kn02xa_be_interrupt;
|
||||
dec_kn02xa_be_init();
|
||||
break;
|
||||
case MACH_DS5000_200: /* DS5000/200 3max */
|
||||
case MACH_DS5000_2X0: /* DS5000/240 3max+ */
|
||||
case MACH_DS5900: /* DS5900 bigmax */
|
||||
board_be_handler = dec_ecc_be_handler;
|
||||
busirq.handler = dec_ecc_be_interrupt;
|
||||
dec_ecc_be_init();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void __init plat_mem_setup(void)
|
||||
{
|
||||
board_be_init = dec_be_init;
|
||||
|
||||
wbflush_setup();
|
||||
|
||||
_machine_restart = dec_machine_restart;
|
||||
_machine_halt = dec_machine_halt;
|
||||
pm_power_off = dec_machine_power_off;
|
||||
|
||||
ioport_resource.start = ~0UL;
|
||||
ioport_resource.end = 0UL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Machine-specific initialisation for KN01, aka DS2100 (aka Pmin)
|
||||
* or DS3100 (aka Pmax).
|
||||
*/
|
||||
static int kn01_interrupt[DEC_NR_INTS] __initdata = {
|
||||
[DEC_IRQ_CASCADE] = -1,
|
||||
[DEC_IRQ_AB_RECV] = -1,
|
||||
[DEC_IRQ_AB_XMIT] = -1,
|
||||
[DEC_IRQ_DZ11] = DEC_CPU_IRQ_NR(KN01_CPU_INR_DZ11),
|
||||
[DEC_IRQ_ASC] = -1,
|
||||
[DEC_IRQ_FLOPPY] = -1,
|
||||
[DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU),
|
||||
[DEC_IRQ_HALT] = -1,
|
||||
[DEC_IRQ_ISDN] = -1,
|
||||
[DEC_IRQ_LANCE] = DEC_CPU_IRQ_NR(KN01_CPU_INR_LANCE),
|
||||
[DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN01_CPU_INR_BUS),
|
||||
[DEC_IRQ_PSU] = -1,
|
||||
[DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN01_CPU_INR_RTC),
|
||||
[DEC_IRQ_SCC0] = -1,
|
||||
[DEC_IRQ_SCC1] = -1,
|
||||
[DEC_IRQ_SII] = DEC_CPU_IRQ_NR(KN01_CPU_INR_SII),
|
||||
[DEC_IRQ_TC0] = -1,
|
||||
[DEC_IRQ_TC1] = -1,
|
||||
[DEC_IRQ_TC2] = -1,
|
||||
[DEC_IRQ_TIMER] = -1,
|
||||
[DEC_IRQ_VIDEO] = DEC_CPU_IRQ_NR(KN01_CPU_INR_VIDEO),
|
||||
[DEC_IRQ_ASC_MERR] = -1,
|
||||
[DEC_IRQ_ASC_ERR] = -1,
|
||||
[DEC_IRQ_ASC_DMA] = -1,
|
||||
[DEC_IRQ_FLOPPY_ERR] = -1,
|
||||
[DEC_IRQ_ISDN_ERR] = -1,
|
||||
[DEC_IRQ_ISDN_RXDMA] = -1,
|
||||
[DEC_IRQ_ISDN_TXDMA] = -1,
|
||||
[DEC_IRQ_LANCE_MERR] = -1,
|
||||
[DEC_IRQ_SCC0A_RXERR] = -1,
|
||||
[DEC_IRQ_SCC0A_RXDMA] = -1,
|
||||
[DEC_IRQ_SCC0A_TXERR] = -1,
|
||||
[DEC_IRQ_SCC0A_TXDMA] = -1,
|
||||
[DEC_IRQ_AB_RXERR] = -1,
|
||||
[DEC_IRQ_AB_RXDMA] = -1,
|
||||
[DEC_IRQ_AB_TXERR] = -1,
|
||||
[DEC_IRQ_AB_TXDMA] = -1,
|
||||
[DEC_IRQ_SCC1A_RXERR] = -1,
|
||||
[DEC_IRQ_SCC1A_RXDMA] = -1,
|
||||
[DEC_IRQ_SCC1A_TXERR] = -1,
|
||||
[DEC_IRQ_SCC1A_TXDMA] = -1,
|
||||
};
|
||||
|
||||
static int_ptr kn01_cpu_mask_nr_tbl[][2] __initdata = {
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_BUS) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_BUS) } },
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_RTC) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_RTC) } },
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_DZ11) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_DZ11) } },
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_SII) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_SII) } },
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_LANCE) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_LANCE) } },
|
||||
{ { .i = DEC_CPU_IRQ_ALL },
|
||||
{ .p = cpu_all_int } },
|
||||
};
|
||||
|
||||
static void __init dec_init_kn01(void)
|
||||
{
|
||||
/* IRQ routing. */
|
||||
memcpy(&dec_interrupt, &kn01_interrupt,
|
||||
sizeof(kn01_interrupt));
|
||||
|
||||
/* CPU IRQ priorities. */
|
||||
memcpy(&cpu_mask_nr_tbl, &kn01_cpu_mask_nr_tbl,
|
||||
sizeof(kn01_cpu_mask_nr_tbl));
|
||||
|
||||
mips_cpu_irq_init();
|
||||
|
||||
} /* dec_init_kn01 */
|
||||
|
||||
|
||||
/*
|
||||
* Machine-specific initialisation for KN230, aka DS5100, aka MIPSmate.
|
||||
*/
|
||||
static int kn230_interrupt[DEC_NR_INTS] __initdata = {
|
||||
[DEC_IRQ_CASCADE] = -1,
|
||||
[DEC_IRQ_AB_RECV] = -1,
|
||||
[DEC_IRQ_AB_XMIT] = -1,
|
||||
[DEC_IRQ_DZ11] = DEC_CPU_IRQ_NR(KN230_CPU_INR_DZ11),
|
||||
[DEC_IRQ_ASC] = -1,
|
||||
[DEC_IRQ_FLOPPY] = -1,
|
||||
[DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU),
|
||||
[DEC_IRQ_HALT] = DEC_CPU_IRQ_NR(KN230_CPU_INR_HALT),
|
||||
[DEC_IRQ_ISDN] = -1,
|
||||
[DEC_IRQ_LANCE] = DEC_CPU_IRQ_NR(KN230_CPU_INR_LANCE),
|
||||
[DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN230_CPU_INR_BUS),
|
||||
[DEC_IRQ_PSU] = -1,
|
||||
[DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN230_CPU_INR_RTC),
|
||||
[DEC_IRQ_SCC0] = -1,
|
||||
[DEC_IRQ_SCC1] = -1,
|
||||
[DEC_IRQ_SII] = DEC_CPU_IRQ_NR(KN230_CPU_INR_SII),
|
||||
[DEC_IRQ_TC0] = -1,
|
||||
[DEC_IRQ_TC1] = -1,
|
||||
[DEC_IRQ_TC2] = -1,
|
||||
[DEC_IRQ_TIMER] = -1,
|
||||
[DEC_IRQ_VIDEO] = -1,
|
||||
[DEC_IRQ_ASC_MERR] = -1,
|
||||
[DEC_IRQ_ASC_ERR] = -1,
|
||||
[DEC_IRQ_ASC_DMA] = -1,
|
||||
[DEC_IRQ_FLOPPY_ERR] = -1,
|
||||
[DEC_IRQ_ISDN_ERR] = -1,
|
||||
[DEC_IRQ_ISDN_RXDMA] = -1,
|
||||
[DEC_IRQ_ISDN_TXDMA] = -1,
|
||||
[DEC_IRQ_LANCE_MERR] = -1,
|
||||
[DEC_IRQ_SCC0A_RXERR] = -1,
|
||||
[DEC_IRQ_SCC0A_RXDMA] = -1,
|
||||
[DEC_IRQ_SCC0A_TXERR] = -1,
|
||||
[DEC_IRQ_SCC0A_TXDMA] = -1,
|
||||
[DEC_IRQ_AB_RXERR] = -1,
|
||||
[DEC_IRQ_AB_RXDMA] = -1,
|
||||
[DEC_IRQ_AB_TXERR] = -1,
|
||||
[DEC_IRQ_AB_TXDMA] = -1,
|
||||
[DEC_IRQ_SCC1A_RXERR] = -1,
|
||||
[DEC_IRQ_SCC1A_RXDMA] = -1,
|
||||
[DEC_IRQ_SCC1A_TXERR] = -1,
|
||||
[DEC_IRQ_SCC1A_TXDMA] = -1,
|
||||
};
|
||||
|
||||
static int_ptr kn230_cpu_mask_nr_tbl[][2] __initdata = {
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN230_CPU_INR_BUS) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN230_CPU_INR_BUS) } },
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN230_CPU_INR_RTC) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN230_CPU_INR_RTC) } },
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN230_CPU_INR_DZ11) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN230_CPU_INR_DZ11) } },
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN230_CPU_INR_SII) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN230_CPU_INR_SII) } },
|
||||
{ { .i = DEC_CPU_IRQ_ALL },
|
||||
{ .p = cpu_all_int } },
|
||||
};
|
||||
|
||||
static void __init dec_init_kn230(void)
|
||||
{
|
||||
/* IRQ routing. */
|
||||
memcpy(&dec_interrupt, &kn230_interrupt,
|
||||
sizeof(kn230_interrupt));
|
||||
|
||||
/* CPU IRQ priorities. */
|
||||
memcpy(&cpu_mask_nr_tbl, &kn230_cpu_mask_nr_tbl,
|
||||
sizeof(kn230_cpu_mask_nr_tbl));
|
||||
|
||||
mips_cpu_irq_init();
|
||||
|
||||
} /* dec_init_kn230 */
|
||||
|
||||
|
||||
/*
|
||||
* Machine-specific initialisation for KN02, aka DS5000/200, aka 3max.
|
||||
*/
|
||||
static int kn02_interrupt[DEC_NR_INTS] __initdata = {
|
||||
[DEC_IRQ_CASCADE] = DEC_CPU_IRQ_NR(KN02_CPU_INR_CASCADE),
|
||||
[DEC_IRQ_AB_RECV] = -1,
|
||||
[DEC_IRQ_AB_XMIT] = -1,
|
||||
[DEC_IRQ_DZ11] = KN02_IRQ_NR(KN02_CSR_INR_DZ11),
|
||||
[DEC_IRQ_ASC] = KN02_IRQ_NR(KN02_CSR_INR_ASC),
|
||||
[DEC_IRQ_FLOPPY] = -1,
|
||||
[DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU),
|
||||
[DEC_IRQ_HALT] = -1,
|
||||
[DEC_IRQ_ISDN] = -1,
|
||||
[DEC_IRQ_LANCE] = KN02_IRQ_NR(KN02_CSR_INR_LANCE),
|
||||
[DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN02_CPU_INR_BUS),
|
||||
[DEC_IRQ_PSU] = -1,
|
||||
[DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN02_CPU_INR_RTC),
|
||||
[DEC_IRQ_SCC0] = -1,
|
||||
[DEC_IRQ_SCC1] = -1,
|
||||
[DEC_IRQ_SII] = -1,
|
||||
[DEC_IRQ_TC0] = KN02_IRQ_NR(KN02_CSR_INR_TC0),
|
||||
[DEC_IRQ_TC1] = KN02_IRQ_NR(KN02_CSR_INR_TC1),
|
||||
[DEC_IRQ_TC2] = KN02_IRQ_NR(KN02_CSR_INR_TC2),
|
||||
[DEC_IRQ_TIMER] = -1,
|
||||
[DEC_IRQ_VIDEO] = -1,
|
||||
[DEC_IRQ_ASC_MERR] = -1,
|
||||
[DEC_IRQ_ASC_ERR] = -1,
|
||||
[DEC_IRQ_ASC_DMA] = -1,
|
||||
[DEC_IRQ_FLOPPY_ERR] = -1,
|
||||
[DEC_IRQ_ISDN_ERR] = -1,
|
||||
[DEC_IRQ_ISDN_RXDMA] = -1,
|
||||
[DEC_IRQ_ISDN_TXDMA] = -1,
|
||||
[DEC_IRQ_LANCE_MERR] = -1,
|
||||
[DEC_IRQ_SCC0A_RXERR] = -1,
|
||||
[DEC_IRQ_SCC0A_RXDMA] = -1,
|
||||
[DEC_IRQ_SCC0A_TXERR] = -1,
|
||||
[DEC_IRQ_SCC0A_TXDMA] = -1,
|
||||
[DEC_IRQ_AB_RXERR] = -1,
|
||||
[DEC_IRQ_AB_RXDMA] = -1,
|
||||
[DEC_IRQ_AB_TXERR] = -1,
|
||||
[DEC_IRQ_AB_TXDMA] = -1,
|
||||
[DEC_IRQ_SCC1A_RXERR] = -1,
|
||||
[DEC_IRQ_SCC1A_RXDMA] = -1,
|
||||
[DEC_IRQ_SCC1A_TXERR] = -1,
|
||||
[DEC_IRQ_SCC1A_TXDMA] = -1,
|
||||
};
|
||||
|
||||
static int_ptr kn02_cpu_mask_nr_tbl[][2] __initdata = {
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN02_CPU_INR_BUS) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN02_CPU_INR_BUS) } },
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN02_CPU_INR_RTC) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN02_CPU_INR_RTC) } },
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN02_CPU_INR_CASCADE) },
|
||||
{ .p = kn02_io_int } },
|
||||
{ { .i = DEC_CPU_IRQ_ALL },
|
||||
{ .p = cpu_all_int } },
|
||||
};
|
||||
|
||||
static int_ptr kn02_asic_mask_nr_tbl[][2] __initdata = {
|
||||
{ { .i = KN02_IRQ_MASK(KN02_CSR_INR_DZ11) },
|
||||
{ .i = KN02_IRQ_NR(KN02_CSR_INR_DZ11) } },
|
||||
{ { .i = KN02_IRQ_MASK(KN02_CSR_INR_ASC) },
|
||||
{ .i = KN02_IRQ_NR(KN02_CSR_INR_ASC) } },
|
||||
{ { .i = KN02_IRQ_MASK(KN02_CSR_INR_LANCE) },
|
||||
{ .i = KN02_IRQ_NR(KN02_CSR_INR_LANCE) } },
|
||||
{ { .i = KN02_IRQ_MASK(KN02_CSR_INR_TC2) },
|
||||
{ .i = KN02_IRQ_NR(KN02_CSR_INR_TC2) } },
|
||||
{ { .i = KN02_IRQ_MASK(KN02_CSR_INR_TC1) },
|
||||
{ .i = KN02_IRQ_NR(KN02_CSR_INR_TC1) } },
|
||||
{ { .i = KN02_IRQ_MASK(KN02_CSR_INR_TC0) },
|
||||
{ .i = KN02_IRQ_NR(KN02_CSR_INR_TC0) } },
|
||||
{ { .i = KN02_IRQ_ALL },
|
||||
{ .p = kn02_all_int } },
|
||||
};
|
||||
|
||||
static void __init dec_init_kn02(void)
|
||||
{
|
||||
/* IRQ routing. */
|
||||
memcpy(&dec_interrupt, &kn02_interrupt,
|
||||
sizeof(kn02_interrupt));
|
||||
|
||||
/* CPU IRQ priorities. */
|
||||
memcpy(&cpu_mask_nr_tbl, &kn02_cpu_mask_nr_tbl,
|
||||
sizeof(kn02_cpu_mask_nr_tbl));
|
||||
|
||||
/* KN02 CSR IRQ priorities. */
|
||||
memcpy(&asic_mask_nr_tbl, &kn02_asic_mask_nr_tbl,
|
||||
sizeof(kn02_asic_mask_nr_tbl));
|
||||
|
||||
mips_cpu_irq_init();
|
||||
init_kn02_irqs(KN02_IRQ_BASE);
|
||||
|
||||
} /* dec_init_kn02 */
|
||||
|
||||
|
||||
/*
|
||||
* Machine-specific initialisation for KN02-BA, aka DS5000/1xx
|
||||
* (xx = 20, 25, 33), aka 3min. Also applies to KN04(-BA), aka
|
||||
* DS5000/150, aka 4min.
|
||||
*/
|
||||
static int kn02ba_interrupt[DEC_NR_INTS] __initdata = {
|
||||
[DEC_IRQ_CASCADE] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_CASCADE),
|
||||
[DEC_IRQ_AB_RECV] = -1,
|
||||
[DEC_IRQ_AB_XMIT] = -1,
|
||||
[DEC_IRQ_DZ11] = -1,
|
||||
[DEC_IRQ_ASC] = IO_IRQ_NR(KN02BA_IO_INR_ASC),
|
||||
[DEC_IRQ_FLOPPY] = -1,
|
||||
[DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU),
|
||||
[DEC_IRQ_HALT] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_HALT),
|
||||
[DEC_IRQ_ISDN] = -1,
|
||||
[DEC_IRQ_LANCE] = IO_IRQ_NR(KN02BA_IO_INR_LANCE),
|
||||
[DEC_IRQ_BUS] = IO_IRQ_NR(KN02BA_IO_INR_BUS),
|
||||
[DEC_IRQ_PSU] = IO_IRQ_NR(KN02BA_IO_INR_PSU),
|
||||
[DEC_IRQ_RTC] = IO_IRQ_NR(KN02BA_IO_INR_RTC),
|
||||
[DEC_IRQ_SCC0] = IO_IRQ_NR(KN02BA_IO_INR_SCC0),
|
||||
[DEC_IRQ_SCC1] = IO_IRQ_NR(KN02BA_IO_INR_SCC1),
|
||||
[DEC_IRQ_SII] = -1,
|
||||
[DEC_IRQ_TC0] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC0),
|
||||
[DEC_IRQ_TC1] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC1),
|
||||
[DEC_IRQ_TC2] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC2),
|
||||
[DEC_IRQ_TIMER] = -1,
|
||||
[DEC_IRQ_VIDEO] = -1,
|
||||
[DEC_IRQ_ASC_MERR] = IO_IRQ_NR(IO_INR_ASC_MERR),
|
||||
[DEC_IRQ_ASC_ERR] = IO_IRQ_NR(IO_INR_ASC_ERR),
|
||||
[DEC_IRQ_ASC_DMA] = IO_IRQ_NR(IO_INR_ASC_DMA),
|
||||
[DEC_IRQ_FLOPPY_ERR] = -1,
|
||||
[DEC_IRQ_ISDN_ERR] = -1,
|
||||
[DEC_IRQ_ISDN_RXDMA] = -1,
|
||||
[DEC_IRQ_ISDN_TXDMA] = -1,
|
||||
[DEC_IRQ_LANCE_MERR] = IO_IRQ_NR(IO_INR_LANCE_MERR),
|
||||
[DEC_IRQ_SCC0A_RXERR] = IO_IRQ_NR(IO_INR_SCC0A_RXERR),
|
||||
[DEC_IRQ_SCC0A_RXDMA] = IO_IRQ_NR(IO_INR_SCC0A_RXDMA),
|
||||
[DEC_IRQ_SCC0A_TXERR] = IO_IRQ_NR(IO_INR_SCC0A_TXERR),
|
||||
[DEC_IRQ_SCC0A_TXDMA] = IO_IRQ_NR(IO_INR_SCC0A_TXDMA),
|
||||
[DEC_IRQ_AB_RXERR] = -1,
|
||||
[DEC_IRQ_AB_RXDMA] = -1,
|
||||
[DEC_IRQ_AB_TXERR] = -1,
|
||||
[DEC_IRQ_AB_TXDMA] = -1,
|
||||
[DEC_IRQ_SCC1A_RXERR] = IO_IRQ_NR(IO_INR_SCC1A_RXERR),
|
||||
[DEC_IRQ_SCC1A_RXDMA] = IO_IRQ_NR(IO_INR_SCC1A_RXDMA),
|
||||
[DEC_IRQ_SCC1A_TXERR] = IO_IRQ_NR(IO_INR_SCC1A_TXERR),
|
||||
[DEC_IRQ_SCC1A_TXDMA] = IO_IRQ_NR(IO_INR_SCC1A_TXDMA),
|
||||
};
|
||||
|
||||
static int_ptr kn02ba_cpu_mask_nr_tbl[][2] __initdata = {
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN02BA_CPU_INR_CASCADE) },
|
||||
{ .p = kn02xa_io_int } },
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN02BA_CPU_INR_TC2) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC2) } },
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN02BA_CPU_INR_TC1) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC1) } },
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN02BA_CPU_INR_TC0) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC0) } },
|
||||
{ { .i = DEC_CPU_IRQ_ALL },
|
||||
{ .p = cpu_all_int } },
|
||||
};
|
||||
|
||||
static int_ptr kn02ba_asic_mask_nr_tbl[][2] __initdata = {
|
||||
{ { .i = IO_IRQ_MASK(KN02BA_IO_INR_BUS) },
|
||||
{ .i = IO_IRQ_NR(KN02BA_IO_INR_BUS) } },
|
||||
{ { .i = IO_IRQ_MASK(KN02BA_IO_INR_RTC) },
|
||||
{ .i = IO_IRQ_NR(KN02BA_IO_INR_RTC) } },
|
||||
{ { .i = IO_IRQ_DMA },
|
||||
{ .p = asic_dma_int } },
|
||||
{ { .i = IO_IRQ_MASK(KN02BA_IO_INR_SCC0) },
|
||||
{ .i = IO_IRQ_NR(KN02BA_IO_INR_SCC0) } },
|
||||
{ { .i = IO_IRQ_MASK(KN02BA_IO_INR_SCC1) },
|
||||
{ .i = IO_IRQ_NR(KN02BA_IO_INR_SCC1) } },
|
||||
{ { .i = IO_IRQ_MASK(KN02BA_IO_INR_ASC) },
|
||||
{ .i = IO_IRQ_NR(KN02BA_IO_INR_ASC) } },
|
||||
{ { .i = IO_IRQ_MASK(KN02BA_IO_INR_LANCE) },
|
||||
{ .i = IO_IRQ_NR(KN02BA_IO_INR_LANCE) } },
|
||||
{ { .i = IO_IRQ_ALL },
|
||||
{ .p = asic_all_int } },
|
||||
};
|
||||
|
||||
static void __init dec_init_kn02ba(void)
|
||||
{
|
||||
/* IRQ routing. */
|
||||
memcpy(&dec_interrupt, &kn02ba_interrupt,
|
||||
sizeof(kn02ba_interrupt));
|
||||
|
||||
/* CPU IRQ priorities. */
|
||||
memcpy(&cpu_mask_nr_tbl, &kn02ba_cpu_mask_nr_tbl,
|
||||
sizeof(kn02ba_cpu_mask_nr_tbl));
|
||||
|
||||
/* I/O ASIC IRQ priorities. */
|
||||
memcpy(&asic_mask_nr_tbl, &kn02ba_asic_mask_nr_tbl,
|
||||
sizeof(kn02ba_asic_mask_nr_tbl));
|
||||
|
||||
mips_cpu_irq_init();
|
||||
init_ioasic_irqs(IO_IRQ_BASE);
|
||||
|
||||
} /* dec_init_kn02ba */
|
||||
|
||||
|
||||
/*
|
||||
* Machine-specific initialisation for KN02-CA, aka DS5000/xx,
|
||||
* (xx = 20, 25, 33), aka MAXine. Also applies to KN04(-CA), aka
|
||||
* DS5000/50, aka 4MAXine.
|
||||
*/
|
||||
static int kn02ca_interrupt[DEC_NR_INTS] __initdata = {
|
||||
[DEC_IRQ_CASCADE] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_CASCADE),
|
||||
[DEC_IRQ_AB_RECV] = IO_IRQ_NR(KN02CA_IO_INR_AB_RECV),
|
||||
[DEC_IRQ_AB_XMIT] = IO_IRQ_NR(KN02CA_IO_INR_AB_XMIT),
|
||||
[DEC_IRQ_DZ11] = -1,
|
||||
[DEC_IRQ_ASC] = IO_IRQ_NR(KN02CA_IO_INR_ASC),
|
||||
[DEC_IRQ_FLOPPY] = IO_IRQ_NR(KN02CA_IO_INR_FLOPPY),
|
||||
[DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU),
|
||||
[DEC_IRQ_HALT] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_HALT),
|
||||
[DEC_IRQ_ISDN] = IO_IRQ_NR(KN02CA_IO_INR_ISDN),
|
||||
[DEC_IRQ_LANCE] = IO_IRQ_NR(KN02CA_IO_INR_LANCE),
|
||||
[DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_BUS),
|
||||
[DEC_IRQ_PSU] = -1,
|
||||
[DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_RTC),
|
||||
[DEC_IRQ_SCC0] = IO_IRQ_NR(KN02CA_IO_INR_SCC0),
|
||||
[DEC_IRQ_SCC1] = -1,
|
||||
[DEC_IRQ_SII] = -1,
|
||||
[DEC_IRQ_TC0] = IO_IRQ_NR(KN02CA_IO_INR_TC0),
|
||||
[DEC_IRQ_TC1] = IO_IRQ_NR(KN02CA_IO_INR_TC1),
|
||||
[DEC_IRQ_TC2] = -1,
|
||||
[DEC_IRQ_TIMER] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_TIMER),
|
||||
[DEC_IRQ_VIDEO] = IO_IRQ_NR(KN02CA_IO_INR_VIDEO),
|
||||
[DEC_IRQ_ASC_MERR] = IO_IRQ_NR(IO_INR_ASC_MERR),
|
||||
[DEC_IRQ_ASC_ERR] = IO_IRQ_NR(IO_INR_ASC_ERR),
|
||||
[DEC_IRQ_ASC_DMA] = IO_IRQ_NR(IO_INR_ASC_DMA),
|
||||
[DEC_IRQ_FLOPPY_ERR] = IO_IRQ_NR(IO_INR_FLOPPY_ERR),
|
||||
[DEC_IRQ_ISDN_ERR] = IO_IRQ_NR(IO_INR_ISDN_ERR),
|
||||
[DEC_IRQ_ISDN_RXDMA] = IO_IRQ_NR(IO_INR_ISDN_RXDMA),
|
||||
[DEC_IRQ_ISDN_TXDMA] = IO_IRQ_NR(IO_INR_ISDN_TXDMA),
|
||||
[DEC_IRQ_LANCE_MERR] = IO_IRQ_NR(IO_INR_LANCE_MERR),
|
||||
[DEC_IRQ_SCC0A_RXERR] = IO_IRQ_NR(IO_INR_SCC0A_RXERR),
|
||||
[DEC_IRQ_SCC0A_RXDMA] = IO_IRQ_NR(IO_INR_SCC0A_RXDMA),
|
||||
[DEC_IRQ_SCC0A_TXERR] = IO_IRQ_NR(IO_INR_SCC0A_TXERR),
|
||||
[DEC_IRQ_SCC0A_TXDMA] = IO_IRQ_NR(IO_INR_SCC0A_TXDMA),
|
||||
[DEC_IRQ_AB_RXERR] = IO_IRQ_NR(IO_INR_AB_RXERR),
|
||||
[DEC_IRQ_AB_RXDMA] = IO_IRQ_NR(IO_INR_AB_RXDMA),
|
||||
[DEC_IRQ_AB_TXERR] = IO_IRQ_NR(IO_INR_AB_TXERR),
|
||||
[DEC_IRQ_AB_TXDMA] = IO_IRQ_NR(IO_INR_AB_TXDMA),
|
||||
[DEC_IRQ_SCC1A_RXERR] = -1,
|
||||
[DEC_IRQ_SCC1A_RXDMA] = -1,
|
||||
[DEC_IRQ_SCC1A_TXERR] = -1,
|
||||
[DEC_IRQ_SCC1A_TXDMA] = -1,
|
||||
};
|
||||
|
||||
static int_ptr kn02ca_cpu_mask_nr_tbl[][2] __initdata = {
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN02CA_CPU_INR_BUS) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_BUS) } },
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN02CA_CPU_INR_RTC) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_RTC) } },
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN02CA_CPU_INR_CASCADE) },
|
||||
{ .p = kn02xa_io_int } },
|
||||
{ { .i = DEC_CPU_IRQ_ALL },
|
||||
{ .p = cpu_all_int } },
|
||||
};
|
||||
|
||||
static int_ptr kn02ca_asic_mask_nr_tbl[][2] __initdata = {
|
||||
{ { .i = IO_IRQ_DMA },
|
||||
{ .p = asic_dma_int } },
|
||||
{ { .i = IO_IRQ_MASK(KN02CA_IO_INR_SCC0) },
|
||||
{ .i = IO_IRQ_NR(KN02CA_IO_INR_SCC0) } },
|
||||
{ { .i = IO_IRQ_MASK(KN02CA_IO_INR_ASC) },
|
||||
{ .i = IO_IRQ_NR(KN02CA_IO_INR_ASC) } },
|
||||
{ { .i = IO_IRQ_MASK(KN02CA_IO_INR_LANCE) },
|
||||
{ .i = IO_IRQ_NR(KN02CA_IO_INR_LANCE) } },
|
||||
{ { .i = IO_IRQ_MASK(KN02CA_IO_INR_TC1) },
|
||||
{ .i = IO_IRQ_NR(KN02CA_IO_INR_TC1) } },
|
||||
{ { .i = IO_IRQ_MASK(KN02CA_IO_INR_TC0) },
|
||||
{ .i = IO_IRQ_NR(KN02CA_IO_INR_TC0) } },
|
||||
{ { .i = IO_IRQ_ALL },
|
||||
{ .p = asic_all_int } },
|
||||
};
|
||||
|
||||
static void __init dec_init_kn02ca(void)
|
||||
{
|
||||
/* IRQ routing. */
|
||||
memcpy(&dec_interrupt, &kn02ca_interrupt,
|
||||
sizeof(kn02ca_interrupt));
|
||||
|
||||
/* CPU IRQ priorities. */
|
||||
memcpy(&cpu_mask_nr_tbl, &kn02ca_cpu_mask_nr_tbl,
|
||||
sizeof(kn02ca_cpu_mask_nr_tbl));
|
||||
|
||||
/* I/O ASIC IRQ priorities. */
|
||||
memcpy(&asic_mask_nr_tbl, &kn02ca_asic_mask_nr_tbl,
|
||||
sizeof(kn02ca_asic_mask_nr_tbl));
|
||||
|
||||
mips_cpu_irq_init();
|
||||
init_ioasic_irqs(IO_IRQ_BASE);
|
||||
|
||||
} /* dec_init_kn02ca */
|
||||
|
||||
|
||||
/*
|
||||
* Machine-specific initialisation for KN03, aka DS5000/240,
|
||||
* aka 3max+ and DS5900, aka BIGmax. Also applies to KN05, aka
|
||||
* DS5000/260, aka 4max+ and DS5900/260.
|
||||
*/
|
||||
static int kn03_interrupt[DEC_NR_INTS] __initdata = {
|
||||
[DEC_IRQ_CASCADE] = DEC_CPU_IRQ_NR(KN03_CPU_INR_CASCADE),
|
||||
[DEC_IRQ_AB_RECV] = -1,
|
||||
[DEC_IRQ_AB_XMIT] = -1,
|
||||
[DEC_IRQ_DZ11] = -1,
|
||||
[DEC_IRQ_ASC] = IO_IRQ_NR(KN03_IO_INR_ASC),
|
||||
[DEC_IRQ_FLOPPY] = -1,
|
||||
[DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU),
|
||||
[DEC_IRQ_HALT] = DEC_CPU_IRQ_NR(KN03_CPU_INR_HALT),
|
||||
[DEC_IRQ_ISDN] = -1,
|
||||
[DEC_IRQ_LANCE] = IO_IRQ_NR(KN03_IO_INR_LANCE),
|
||||
[DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN03_CPU_INR_BUS),
|
||||
[DEC_IRQ_PSU] = IO_IRQ_NR(KN03_IO_INR_PSU),
|
||||
[DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN03_CPU_INR_RTC),
|
||||
[DEC_IRQ_SCC0] = IO_IRQ_NR(KN03_IO_INR_SCC0),
|
||||
[DEC_IRQ_SCC1] = IO_IRQ_NR(KN03_IO_INR_SCC1),
|
||||
[DEC_IRQ_SII] = -1,
|
||||
[DEC_IRQ_TC0] = IO_IRQ_NR(KN03_IO_INR_TC0),
|
||||
[DEC_IRQ_TC1] = IO_IRQ_NR(KN03_IO_INR_TC1),
|
||||
[DEC_IRQ_TC2] = IO_IRQ_NR(KN03_IO_INR_TC2),
|
||||
[DEC_IRQ_TIMER] = -1,
|
||||
[DEC_IRQ_VIDEO] = -1,
|
||||
[DEC_IRQ_ASC_MERR] = IO_IRQ_NR(IO_INR_ASC_MERR),
|
||||
[DEC_IRQ_ASC_ERR] = IO_IRQ_NR(IO_INR_ASC_ERR),
|
||||
[DEC_IRQ_ASC_DMA] = IO_IRQ_NR(IO_INR_ASC_DMA),
|
||||
[DEC_IRQ_FLOPPY_ERR] = -1,
|
||||
[DEC_IRQ_ISDN_ERR] = -1,
|
||||
[DEC_IRQ_ISDN_RXDMA] = -1,
|
||||
[DEC_IRQ_ISDN_TXDMA] = -1,
|
||||
[DEC_IRQ_LANCE_MERR] = IO_IRQ_NR(IO_INR_LANCE_MERR),
|
||||
[DEC_IRQ_SCC0A_RXERR] = IO_IRQ_NR(IO_INR_SCC0A_RXERR),
|
||||
[DEC_IRQ_SCC0A_RXDMA] = IO_IRQ_NR(IO_INR_SCC0A_RXDMA),
|
||||
[DEC_IRQ_SCC0A_TXERR] = IO_IRQ_NR(IO_INR_SCC0A_TXERR),
|
||||
[DEC_IRQ_SCC0A_TXDMA] = IO_IRQ_NR(IO_INR_SCC0A_TXDMA),
|
||||
[DEC_IRQ_AB_RXERR] = -1,
|
||||
[DEC_IRQ_AB_RXDMA] = -1,
|
||||
[DEC_IRQ_AB_TXERR] = -1,
|
||||
[DEC_IRQ_AB_TXDMA] = -1,
|
||||
[DEC_IRQ_SCC1A_RXERR] = IO_IRQ_NR(IO_INR_SCC1A_RXERR),
|
||||
[DEC_IRQ_SCC1A_RXDMA] = IO_IRQ_NR(IO_INR_SCC1A_RXDMA),
|
||||
[DEC_IRQ_SCC1A_TXERR] = IO_IRQ_NR(IO_INR_SCC1A_TXERR),
|
||||
[DEC_IRQ_SCC1A_TXDMA] = IO_IRQ_NR(IO_INR_SCC1A_TXDMA),
|
||||
};
|
||||
|
||||
static int_ptr kn03_cpu_mask_nr_tbl[][2] __initdata = {
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN03_CPU_INR_BUS) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN03_CPU_INR_BUS) } },
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN03_CPU_INR_RTC) },
|
||||
{ .i = DEC_CPU_IRQ_NR(KN03_CPU_INR_RTC) } },
|
||||
{ { .i = DEC_CPU_IRQ_MASK(KN03_CPU_INR_CASCADE) },
|
||||
{ .p = kn03_io_int } },
|
||||
{ { .i = DEC_CPU_IRQ_ALL },
|
||||
{ .p = cpu_all_int } },
|
||||
};
|
||||
|
||||
static int_ptr kn03_asic_mask_nr_tbl[][2] __initdata = {
|
||||
{ { .i = IO_IRQ_DMA },
|
||||
{ .p = asic_dma_int } },
|
||||
{ { .i = IO_IRQ_MASK(KN03_IO_INR_SCC0) },
|
||||
{ .i = IO_IRQ_NR(KN03_IO_INR_SCC0) } },
|
||||
{ { .i = IO_IRQ_MASK(KN03_IO_INR_SCC1) },
|
||||
{ .i = IO_IRQ_NR(KN03_IO_INR_SCC1) } },
|
||||
{ { .i = IO_IRQ_MASK(KN03_IO_INR_ASC) },
|
||||
{ .i = IO_IRQ_NR(KN03_IO_INR_ASC) } },
|
||||
{ { .i = IO_IRQ_MASK(KN03_IO_INR_LANCE) },
|
||||
{ .i = IO_IRQ_NR(KN03_IO_INR_LANCE) } },
|
||||
{ { .i = IO_IRQ_MASK(KN03_IO_INR_TC2) },
|
||||
{ .i = IO_IRQ_NR(KN03_IO_INR_TC2) } },
|
||||
{ { .i = IO_IRQ_MASK(KN03_IO_INR_TC1) },
|
||||
{ .i = IO_IRQ_NR(KN03_IO_INR_TC1) } },
|
||||
{ { .i = IO_IRQ_MASK(KN03_IO_INR_TC0) },
|
||||
{ .i = IO_IRQ_NR(KN03_IO_INR_TC0) } },
|
||||
{ { .i = IO_IRQ_ALL },
|
||||
{ .p = asic_all_int } },
|
||||
};
|
||||
|
||||
static void __init dec_init_kn03(void)
|
||||
{
|
||||
/* IRQ routing. */
|
||||
memcpy(&dec_interrupt, &kn03_interrupt,
|
||||
sizeof(kn03_interrupt));
|
||||
|
||||
/* CPU IRQ priorities. */
|
||||
memcpy(&cpu_mask_nr_tbl, &kn03_cpu_mask_nr_tbl,
|
||||
sizeof(kn03_cpu_mask_nr_tbl));
|
||||
|
||||
/* I/O ASIC IRQ priorities. */
|
||||
memcpy(&asic_mask_nr_tbl, &kn03_asic_mask_nr_tbl,
|
||||
sizeof(kn03_asic_mask_nr_tbl));
|
||||
|
||||
mips_cpu_irq_init();
|
||||
init_ioasic_irqs(IO_IRQ_BASE);
|
||||
|
||||
} /* dec_init_kn03 */
|
||||
|
||||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
switch (mips_machtype) {
|
||||
case MACH_DS23100: /* DS2100/DS3100 Pmin/Pmax */
|
||||
dec_init_kn01();
|
||||
break;
|
||||
case MACH_DS5100: /* DS5100 MIPSmate */
|
||||
dec_init_kn230();
|
||||
break;
|
||||
case MACH_DS5000_200: /* DS5000/200 3max */
|
||||
dec_init_kn02();
|
||||
break;
|
||||
case MACH_DS5000_1XX: /* DS5000/1xx 3min */
|
||||
dec_init_kn02ba();
|
||||
break;
|
||||
case MACH_DS5000_2X0: /* DS5000/240 3max+ */
|
||||
case MACH_DS5900: /* DS5900 bigmax */
|
||||
dec_init_kn03();
|
||||
break;
|
||||
case MACH_DS5000_XX: /* Personal DS5000/xx */
|
||||
dec_init_kn02ca();
|
||||
break;
|
||||
case MACH_DS5800: /* DS5800 Isis */
|
||||
panic("Don't know how to set this up!");
|
||||
break;
|
||||
case MACH_DS5400: /* DS5400 MIPSfair */
|
||||
panic("Don't know how to set this up!");
|
||||
break;
|
||||
case MACH_DS5500: /* DS5500 MIPSfair-2 */
|
||||
panic("Don't know how to set this up!");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Free the FPU interrupt if the exception is present. */
|
||||
if (!cpu_has_nofpuex) {
|
||||
cpu_fpu_mask = 0;
|
||||
dec_interrupt[DEC_IRQ_FPU] = -1;
|
||||
}
|
||||
/* Free the halt interrupt unused on R4k systems. */
|
||||
if (current_cpu_type() == CPU_R4000SC ||
|
||||
current_cpu_type() == CPU_R4400SC)
|
||||
dec_interrupt[DEC_IRQ_HALT] = -1;
|
||||
|
||||
/* Register board interrupts: FPU and cascade. */
|
||||
if (dec_interrupt[DEC_IRQ_FPU] >= 0)
|
||||
setup_irq(dec_interrupt[DEC_IRQ_FPU], &fpuirq);
|
||||
if (dec_interrupt[DEC_IRQ_CASCADE] >= 0)
|
||||
setup_irq(dec_interrupt[DEC_IRQ_CASCADE], &ioirq);
|
||||
|
||||
/* Register the bus error interrupt. */
|
||||
if (dec_interrupt[DEC_IRQ_BUS] >= 0 && busirq.handler)
|
||||
setup_irq(dec_interrupt[DEC_IRQ_BUS], &busirq);
|
||||
|
||||
/* Register the HALT interrupt. */
|
||||
if (dec_interrupt[DEC_IRQ_HALT] >= 0)
|
||||
setup_irq(dec_interrupt[DEC_IRQ_HALT], &haltirq);
|
||||
}
|
||||
|
||||
asmlinkage unsigned int dec_irq_dispatch(unsigned int irq)
|
||||
{
|
||||
do_IRQ(irq);
|
||||
return 0;
|
||||
}
|
95
arch/mips/dec/tc.c
Normal file
95
arch/mips/dec/tc.c
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* TURBOchannel architecture calls.
|
||||
*
|
||||
* Copyright (c) Harald Koerfgen, 1998
|
||||
* Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki
|
||||
* Copyright (c) 2005 James Simmons
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU
|
||||
* General Public License. See the file "COPYING" in the main
|
||||
* directory of this archive for more details.
|
||||
*/
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/tc.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/paccess.h>
|
||||
|
||||
#include <asm/dec/interrupts.h>
|
||||
#include <asm/dec/prom.h>
|
||||
#include <asm/dec/system.h>
|
||||
|
||||
/*
|
||||
* Protected read byte from TURBOchannel slot space.
|
||||
*/
|
||||
int tc_preadb(u8 *valp, void __iomem *addr)
|
||||
{
|
||||
return get_dbe(*valp, (u8 *)addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get TURBOchannel bus information as specified by the spec, plus
|
||||
* the slot space base address and the number of slots.
|
||||
*/
|
||||
int __init tc_bus_get_info(struct tc_bus *tbus)
|
||||
{
|
||||
if (!dec_tc_bus)
|
||||
return -ENXIO;
|
||||
|
||||
memcpy(&tbus->info, rex_gettcinfo(), sizeof(tbus->info));
|
||||
tbus->slot_base = CPHYSADDR((long)rex_slot_address(0));
|
||||
|
||||
switch (mips_machtype) {
|
||||
case MACH_DS5000_200:
|
||||
tbus->num_tcslots = 7;
|
||||
break;
|
||||
case MACH_DS5000_2X0:
|
||||
case MACH_DS5900:
|
||||
tbus->ext_slot_base = 0x20000000;
|
||||
tbus->ext_slot_size = 0x20000000;
|
||||
/* fall through */
|
||||
case MACH_DS5000_1XX:
|
||||
tbus->num_tcslots = 3;
|
||||
break;
|
||||
case MACH_DS5000_XX:
|
||||
tbus->num_tcslots = 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the IRQ for the specified slot.
|
||||
*/
|
||||
void __init tc_device_get_irq(struct tc_dev *tdev)
|
||||
{
|
||||
switch (tdev->slot) {
|
||||
case 0:
|
||||
tdev->interrupt = dec_interrupt[DEC_IRQ_TC0];
|
||||
break;
|
||||
case 1:
|
||||
tdev->interrupt = dec_interrupt[DEC_IRQ_TC1];
|
||||
break;
|
||||
case 2:
|
||||
tdev->interrupt = dec_interrupt[DEC_IRQ_TC2];
|
||||
break;
|
||||
/*
|
||||
* Yuck! DS5000/200 onboard devices
|
||||
*/
|
||||
case 5:
|
||||
tdev->interrupt = dec_interrupt[DEC_IRQ_TC5];
|
||||
break;
|
||||
case 6:
|
||||
tdev->interrupt = dec_interrupt[DEC_IRQ_TC6];
|
||||
break;
|
||||
default:
|
||||
tdev->interrupt = -1;
|
||||
break;
|
||||
}
|
||||
}
|
171
arch/mips/dec/time.c
Normal file
171
arch/mips/dec/time.c
Normal file
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
|
||||
* Copyright (C) 2000, 2003 Maciej W. Rozycki
|
||||
*
|
||||
* This file contains the time handling details for PC-style clocks as
|
||||
* found in some MIPS systems.
|
||||
*
|
||||
*/
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
#include <linux/param.h>
|
||||
|
||||
#include <asm/cpu-features.h>
|
||||
#include <asm/ds1287.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/dec/interrupts.h>
|
||||
#include <asm/dec/ioasic.h>
|
||||
#include <asm/dec/machtype.h>
|
||||
|
||||
void read_persistent_clock(struct timespec *ts)
|
||||
{
|
||||
unsigned int year, mon, day, hour, min, sec, real_year;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
|
||||
do {
|
||||
sec = CMOS_READ(RTC_SECONDS);
|
||||
min = CMOS_READ(RTC_MINUTES);
|
||||
hour = CMOS_READ(RTC_HOURS);
|
||||
day = CMOS_READ(RTC_DAY_OF_MONTH);
|
||||
mon = CMOS_READ(RTC_MONTH);
|
||||
year = CMOS_READ(RTC_YEAR);
|
||||
/*
|
||||
* The PROM will reset the year to either '72 or '73.
|
||||
* Therefore we store the real year separately, in one
|
||||
* of unused BBU RAM locations.
|
||||
*/
|
||||
real_year = CMOS_READ(RTC_DEC_YEAR);
|
||||
} while (sec != CMOS_READ(RTC_SECONDS));
|
||||
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
|
||||
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
|
||||
sec = bcd2bin(sec);
|
||||
min = bcd2bin(min);
|
||||
hour = bcd2bin(hour);
|
||||
day = bcd2bin(day);
|
||||
mon = bcd2bin(mon);
|
||||
year = bcd2bin(year);
|
||||
}
|
||||
|
||||
year += real_year - 72 + 2000;
|
||||
|
||||
ts->tv_sec = mktime(year, mon, day, hour, min, sec);
|
||||
ts->tv_nsec = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* In order to set the CMOS clock precisely, rtc_mips_set_mmss has to
|
||||
* be called 500 ms after the second nowtime has started, because when
|
||||
* nowtime is written into the registers of the CMOS clock, it will
|
||||
* jump to the next second precisely 500 ms later. Check the Dallas
|
||||
* DS1287 data sheet for details.
|
||||
*/
|
||||
int rtc_mips_set_mmss(unsigned long nowtime)
|
||||
{
|
||||
int retval = 0;
|
||||
int real_seconds, real_minutes, cmos_minutes;
|
||||
unsigned char save_control, save_freq_select;
|
||||
|
||||
/* irq are locally disabled here */
|
||||
spin_lock(&rtc_lock);
|
||||
/* tell the clock it's being set */
|
||||
save_control = CMOS_READ(RTC_CONTROL);
|
||||
CMOS_WRITE((save_control | RTC_SET), RTC_CONTROL);
|
||||
|
||||
/* stop and reset prescaler */
|
||||
save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
|
||||
CMOS_WRITE((save_freq_select | RTC_DIV_RESET2), RTC_FREQ_SELECT);
|
||||
|
||||
cmos_minutes = CMOS_READ(RTC_MINUTES);
|
||||
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
|
||||
cmos_minutes = bcd2bin(cmos_minutes);
|
||||
|
||||
/*
|
||||
* since we're only adjusting minutes and seconds,
|
||||
* don't interfere with hour overflow. This avoids
|
||||
* messing with unknown time zones but requires your
|
||||
* RTC not to be off by more than 15 minutes
|
||||
*/
|
||||
real_seconds = nowtime % 60;
|
||||
real_minutes = nowtime / 60;
|
||||
if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
|
||||
real_minutes += 30; /* correct for half hour time zone */
|
||||
real_minutes %= 60;
|
||||
|
||||
if (abs(real_minutes - cmos_minutes) < 30) {
|
||||
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
|
||||
real_seconds = bin2bcd(real_seconds);
|
||||
real_minutes = bin2bcd(real_minutes);
|
||||
}
|
||||
CMOS_WRITE(real_seconds, RTC_SECONDS);
|
||||
CMOS_WRITE(real_minutes, RTC_MINUTES);
|
||||
} else {
|
||||
printk_once(KERN_NOTICE
|
||||
"set_rtc_mmss: can't update from %d to %d\n",
|
||||
cmos_minutes, real_minutes);
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
/* The following flags have to be released exactly in this order,
|
||||
* otherwise the DS1287 will not reset the oscillator and will not
|
||||
* update precisely 500 ms later. You won't find this mentioned
|
||||
* in the Dallas Semiconductor data sheets, but who believes data
|
||||
* sheets anyway ... -- Markus Kuhn
|
||||
*/
|
||||
CMOS_WRITE(save_control, RTC_CONTROL);
|
||||
CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
|
||||
spin_unlock(&rtc_lock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void __init plat_time_init(void)
|
||||
{
|
||||
int ioasic_clock = 0;
|
||||
u32 start, end;
|
||||
int i = HZ / 8;
|
||||
|
||||
/* Set up the rate of periodic DS1287 interrupts. */
|
||||
ds1287_set_base_clock(HZ);
|
||||
|
||||
/* On some I/O ASIC systems we have the I/O ASIC's counter. */
|
||||
if (IOASIC)
|
||||
ioasic_clock = dec_ioasic_clocksource_init() == 0;
|
||||
if (cpu_has_counter) {
|
||||
ds1287_timer_state();
|
||||
while (!ds1287_timer_state())
|
||||
;
|
||||
|
||||
start = read_c0_count();
|
||||
|
||||
while (i--)
|
||||
while (!ds1287_timer_state())
|
||||
;
|
||||
|
||||
end = read_c0_count();
|
||||
|
||||
mips_hpt_frequency = (end - start) * 8;
|
||||
printk(KERN_INFO "MIPS counter frequency %dHz\n",
|
||||
mips_hpt_frequency);
|
||||
|
||||
/*
|
||||
* All R4k DECstations suffer from the CP0 Count erratum,
|
||||
* so we can't use the timer as a clock source, and a clock
|
||||
* event both at a time. An accurate wall clock is more
|
||||
* important than a high-precision interval timer so only
|
||||
* use the timer as a clock source, and not a clock event
|
||||
* if there's no I/O ASIC counter available to serve as a
|
||||
* clock source.
|
||||
*/
|
||||
if (!ioasic_clock) {
|
||||
init_r4k_clocksource();
|
||||
mips_hpt_frequency = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ds1287_clockevent_init(dec_interrupt[DEC_IRQ_RTC]);
|
||||
}
|
94
arch/mips/dec/wbflush.c
Normal file
94
arch/mips/dec/wbflush.c
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Setup the right wbflush routine for the different DECstations.
|
||||
*
|
||||
* Created with information from:
|
||||
* DECstation 3100 Desktop Workstation Functional Specification
|
||||
* DECstation 5000/200 KN02 System Module Functional Specification
|
||||
* mipsel-linux-objdump --disassemble vmunix | grep "wbflush" :-)
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 1998 Harald Koerfgen
|
||||
* Copyright (C) 2002 Maciej W. Rozycki
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/wbflush.h>
|
||||
#include <asm/barrier.h>
|
||||
|
||||
static void wbflush_kn01(void);
|
||||
static void wbflush_kn210(void);
|
||||
static void wbflush_mips(void);
|
||||
|
||||
void (*__wbflush) (void);
|
||||
|
||||
void __init wbflush_setup(void)
|
||||
{
|
||||
switch (mips_machtype) {
|
||||
case MACH_DS23100:
|
||||
case MACH_DS5000_200: /* DS5000 3max */
|
||||
__wbflush = wbflush_kn01;
|
||||
break;
|
||||
case MACH_DS5100: /* DS5100 MIPSMATE */
|
||||
__wbflush = wbflush_kn210;
|
||||
break;
|
||||
case MACH_DS5000_1XX: /* DS5000/100 3min */
|
||||
case MACH_DS5000_XX: /* Personal DS5000/2x */
|
||||
case MACH_DS5000_2X0: /* DS5000/240 3max+ */
|
||||
case MACH_DS5900: /* DS5900 bigmax */
|
||||
default:
|
||||
__wbflush = wbflush_mips;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For the DS3100 and DS5000/200 the R2020/R3220 writeback buffer functions
|
||||
* as part of Coprocessor 0.
|
||||
*/
|
||||
static void wbflush_kn01(void)
|
||||
{
|
||||
asm(".set\tpush\n\t"
|
||||
".set\tnoreorder\n\t"
|
||||
"1:\tbc0f\t1b\n\t"
|
||||
"nop\n\t"
|
||||
".set\tpop");
|
||||
}
|
||||
|
||||
/*
|
||||
* For the DS5100 the writeback buffer seems to be a part of Coprocessor 3.
|
||||
* But CP3 has to enabled first.
|
||||
*/
|
||||
static void wbflush_kn210(void)
|
||||
{
|
||||
asm(".set\tpush\n\t"
|
||||
".set\tnoreorder\n\t"
|
||||
"mfc0\t$2,$12\n\t"
|
||||
"lui\t$3,0x8000\n\t"
|
||||
"or\t$3,$2,$3\n\t"
|
||||
"mtc0\t$3,$12\n\t"
|
||||
"nop\n"
|
||||
"1:\tbc3f\t1b\n\t"
|
||||
"nop\n\t"
|
||||
"mtc0\t$2,$12\n\t"
|
||||
"nop\n\t"
|
||||
".set\tpop"
|
||||
: : : "$2", "$3");
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O ASIC systems use a standard writeback buffer that gets flushed
|
||||
* upon an uncached read.
|
||||
*/
|
||||
static void wbflush_mips(void)
|
||||
{
|
||||
__fast_iob();
|
||||
}
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
EXPORT_SYMBOL(__wbflush);
|
Loading…
Add table
Add a link
Reference in a new issue