Commit 320bcfc9 authored by Ralf Bächle's avatar Ralf Bächle Committed by Linus Torvalds

[PATCH] DEC update

An update of the code for the DECstations.  This also adds 64-bit support
for the R4000 versions of DEC's good old workstations.
parent d4da6773
......@@ -2,6 +2,10 @@
# Makefile for the DECstation family specific parts of the kernel
#
obj-y := int-handler.o setup.o irq.o time.o reset.o rtc-dec.o wbflush.o
obj-y := ecc-berr.o int-handler.o ioasic-irq.o kn02-irq.o reset.o \
rtc-dec.o setup.o time.o
obj-$(CONFIG_PROM_CONSOLE) += promcon.o
obj-$(CONFIG_CPU_HAS_WB) += wbflush.o
EXTRA_AFLAGS := $(CFLAGS)
......@@ -3,8 +3,8 @@
#
netboot: all
mipsel-linux-ld -N -G 0 -T ld.ecoff ../../boot/zImage \
built-in.o ramdisk.img -o nbImage
$(LD) -N -G 0 -T ld.ecoff ../../boot/zImage \
dec_boot.o ramdisk.img -o nbImage
obj-y := decstation.o
......
/*
* linux/arch/mips/dec/ecc-berr.c
*
* 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 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/kernel.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <asm/cpu.h>
#include <asm/processor.h>
#include <asm/system.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 = "";
dma_addr_t 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 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 "Unindentified 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 *)KSEG1ADDR(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);
}
void dec_ecc_be_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
int action = dec_ecc_be_backend(regs, 0, 1);
if (action == MIPS_BE_DISCARD)
return;
/*
* FIXME: Find 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 *)KN02_CSR_BASE;
unsigned long flags;
kn0x_erraddr = (void *)(KN02_SLOT_BASE + KN02_ERRADDR);
kn0x_chksyn = (void *)(KN02_SLOT_BASE + KN02_CHKSYN);
spin_lock_irqsave(&kn02_lock, flags);
/* Preset write-only bits of the Control Register cache. */
cached_kn02_csr = *csr | KN03_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();
spin_unlock_irqrestore(&kn02_lock, flags);
}
static inline void dec_kn03_be_init(void)
{
volatile u32 *mcr = (void *)(KN03_SLOT_BASE + IOASIC_MCR);
volatile u32 *mbcs = (void *)(KN03_SLOT_BASE + KN05_MB_CSR);
kn0x_erraddr = (void *)(KN03_SLOT_BASE + IOASIC_ERRADDR);
kn0x_chksyn = (void *)(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_data.cputype == CPU_R4400SC)
*mbcs |= KN05_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();
}
This diff is collapsed.
/*
* linux/arch/mips/dec/ioasic-irq.c
*
* DEC I/O ASIC interrupts.
*
* Copyright (c) 2002, 2003 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/spinlock.h>
#include <linux/types.h>
#include <asm/dec/ioasic.h>
#include <asm/dec/ioasic_addrs.h>
#include <asm/dec/ioasic_ints.h>
static spinlock_t ioasic_lock = SPIN_LOCK_UNLOCKED;
static int ioasic_irq_base;
static inline void unmask_ioasic_irq(unsigned int irq)
{
u32 simr;
simr = ioasic_read(IO_REG_SIMR);
simr |= (1 << (irq - ioasic_irq_base));
ioasic_write(IO_REG_SIMR, simr);
}
static inline void mask_ioasic_irq(unsigned int irq)
{
u32 simr;
simr = ioasic_read(IO_REG_SIMR);
simr &= ~(1 << (irq - ioasic_irq_base));
ioasic_write(IO_REG_SIMR, simr);
}
static inline void clear_ioasic_irq(unsigned int irq)
{
u32 sir;
sir = ~(1 << (irq - ioasic_irq_base));
ioasic_write(IO_REG_SIR, sir);
}
static inline void enable_ioasic_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&ioasic_lock, flags);
unmask_ioasic_irq(irq);
spin_unlock_irqrestore(&ioasic_lock, flags);
}
static inline void disable_ioasic_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&ioasic_lock, flags);
mask_ioasic_irq(irq);
spin_unlock_irqrestore(&ioasic_lock, flags);
}
static inline unsigned int startup_ioasic_irq(unsigned int irq)
{
enable_ioasic_irq(irq);
return 0;
}
#define shutdown_ioasic_irq disable_ioasic_irq
static inline void ack_ioasic_irq(unsigned int irq)
{
spin_lock(&ioasic_lock);
mask_ioasic_irq(irq);
spin_unlock(&ioasic_lock);
fast_iob();
}
static inline void end_ioasic_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
enable_ioasic_irq(irq);
}
static struct hw_interrupt_type ioasic_irq_type = {
.typename = "IO-ASIC",
.startup = startup_ioasic_irq,
.shutdown = shutdown_ioasic_irq,
.enable = enable_ioasic_irq,
.disable = disable_ioasic_irq,
.ack = ack_ioasic_irq,
.end = end_ioasic_irq,
};
#define startup_ioasic_dma_irq startup_ioasic_irq
#define shutdown_ioasic_dma_irq shutdown_ioasic_irq
#define enable_ioasic_dma_irq enable_ioasic_irq
#define disable_ioasic_dma_irq disable_ioasic_irq
#define ack_ioasic_dma_irq ack_ioasic_irq
static inline void end_ioasic_dma_irq(unsigned int irq)
{
clear_ioasic_irq(irq);
fast_iob();
end_ioasic_irq(irq);
}
static struct hw_interrupt_type ioasic_dma_irq_type = {
.typename = "IO-ASIC-DMA",
.startup = startup_ioasic_dma_irq,
.shutdown = shutdown_ioasic_dma_irq,
.enable = enable_ioasic_dma_irq,
.disable = disable_ioasic_dma_irq,
.ack = ack_ioasic_dma_irq,
.end = end_ioasic_dma_irq,
};
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_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0;
irq_desc[i].depth = 1;
irq_desc[i].handler = &ioasic_irq_type;
}
for (; i < base + IO_IRQ_LINES; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0;
irq_desc[i].depth = 1;
irq_desc[i].handler = &ioasic_dma_irq_type;
}
ioasic_irq_base = base;
}
/*
* Code to handle DECstation IRQs plus some generic interrupt stuff.
*
* Copyright (C) 1992 Linus Torvalds
* Copyright (C) 1994, 1995, 1996, 1997, 2000 Ralf Baechle
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/seq_file.h>
#include <asm/bitops.h>
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
#include <asm/dec/interrupts.h>
extern void dec_init_kn01(void);
extern void dec_init_kn230(void);
extern void dec_init_kn02(void);
extern void dec_init_kn02ba(void);
extern void dec_init_kn02ca(void);
extern void dec_init_kn03(void);
extern asmlinkage void decstation_handle_int(void);
unsigned long spurious_count = 0;
static inline void mask_irq(unsigned int irq_nr)
{
unsigned int dummy;
if (dec_interrupt[irq_nr].iemask) { /* This is an ASIC interrupt */
*imr &= ~dec_interrupt[irq_nr].iemask;
dummy = *imr;
dummy = *imr;
} else /* This is a cpu interrupt */
change_cp0_status(ST0_IM, read_32bit_cp0_register(CP0_STATUS) & ~dec_interrupt[irq_nr].cpu_mask);
}
static inline void unmask_irq(unsigned int irq_nr)
{
unsigned int dummy;
if (dec_interrupt[irq_nr].iemask) { /* This is an ASIC interrupt */
*imr |= dec_interrupt[irq_nr].iemask;
dummy = *imr;
dummy = *imr;
}
change_cp0_status(ST0_IM, read_32bit_cp0_register(CP0_STATUS) | dec_interrupt[irq_nr].cpu_mask);
}
void disable_irq(unsigned int irq_nr)
{
unsigned long flags;
save_and_cli(flags);
mask_irq(irq_nr);
restore_flags(flags);
}
void enable_irq(unsigned int irq_nr)
{
unsigned long flags;
save_and_cli(flags);
unmask_irq(irq_nr);
restore_flags(flags);
}
/*
* Pointers to the low-level handlers: first the general ones, then the
* fast ones, then the bad ones.
*/
extern void interrupt(void);
static struct irqaction *irq_action[32] =
{
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
int show_interrupts(struct seq_file *p, void *v)
{
int i;
struct irqaction *action;
unsigned long flags;
for (i = 0; i < 32; i++) {
local_irq_save(flags);
action = irq_action[i];
if (!action)
goto skip;
seq_printf(p, "%2d: %8d %c %s",
i, kstat_cpu(0).irqs[i],
(action->flags & SA_INTERRUPT) ? '+' : ' ',
action->name);
for (action = action->next; action; action = action->next) {
seq_printf(p, ",%s %s",
(action->flags & SA_INTERRUPT) ? " +" : "",
action->name);
}
seq_putc(p, '\n');
skip:
local_irq_restore(flags);
}
return 0;
}
/*
* do_IRQ handles IRQ's that have been installed without the
* SA_INTERRUPT flag: it uses the full signal-handling return
* and runs with other interrupts enabled. All relatively slow
* IRQ's should use this format: notably the keyboard/timer
* routines.
*/
asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
{
struct irqaction *action;
int do_random, cpu;
cpu = smp_processor_id();
irq_enter(cpu, irq);
kstat_cpu(cpu).irqs[irq]++;
mask_irq(irq);
action = *(irq + irq_action);
if (action) {
if (!(action->flags & SA_INTERRUPT))
local_irq_enable();
action = *(irq + irq_action);
do_random = 0;
do {
do_random |= action->flags;
action->handler(irq, action->dev_id, regs);
action = action->next;
} while (action);
if (do_random & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
local_irq_disable();
unmask_irq(irq);
}
irq_exit(cpu, irq);
/* unmasking and bottom half handling is done magically for us. */
}
/*
* Idea is to put all interrupts
* in a single table and differenciate them just by number.
*/
int setup_dec_irq(int irq, struct irqaction *new)
{
int shared = 0;
struct irqaction *old, **p;
unsigned long flags;
p = irq_action + irq;
if ((old = *p) != NULL) {
/* Can't share interrupts unless both agree to */
if (!(old->flags & new->flags & SA_SHIRQ))
return -EBUSY;
/* Can't share interrupts unless both are same type */
if ((old->flags ^ new->flags) & SA_INTERRUPT)
return -EBUSY;
/* add new interrupt at end of irq queue */
do {
p = &old->next;
old = *p;
} while (old);
shared = 1;
}
if (new->flags & SA_SAMPLE_RANDOM)
rand_initialize_irq(irq);
save_and_cli(flags);
*p = new;
if (!shared) {
unmask_irq(irq);
}
restore_flags(flags);
return 0;
}
int request_irq(unsigned int irq,
void (*handler) (int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id)
{
int retval;
struct irqaction *action;
if (irq >= 32)
return -EINVAL;
if (!handler)
return -EINVAL;
action = (struct irqaction *) kmalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action)
return -ENOMEM;
action->handler = handler;
action->flags = irqflags;
action->mask = 0;
action->name = devname;
action->next = NULL;
action->dev_id = dev_id;
retval = setup_dec_irq(irq, action);
if (retval)
kfree(action);
return retval;
}
void free_irq(unsigned int irq, void *dev_id)
{
struct irqaction *action, **p;
unsigned long flags;
if (irq > 39) {
printk("Trying to free IRQ%d\n", irq);
return;
}
for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
if (action->dev_id != dev_id)
continue;
/* Found it - now free it */
save_and_cli(flags);
*p = action->next;
if (!irq[irq_action])
mask_irq(irq);
restore_flags(flags);
kfree(action);
return;
}
printk("Trying to free free IRQ%d\n", irq);
}
unsigned long probe_irq_on(void)
{
/* TODO */
return 0;
}
int probe_irq_off(unsigned long irqs)
{
/* TODO */
return 0;
}
void __init init_IRQ(void)
{
switch (mips_machtype) {
case MACH_DS23100:
dec_init_kn01();
break;
case MACH_DS5100: /* DS5100 MIPSMATE */
dec_init_kn230();
break;
case MACH_DS5000_200: /* DS5000 3max */
dec_init_kn02();
break;
case MACH_DS5000_1XX: /* DS5000/100 3min */
dec_init_kn02ba();
break;
case MACH_DS5000_2X0: /* DS5000/240 3max+ */
dec_init_kn03();
break;
case MACH_DS5000_XX: /* Personal DS5000/2x */
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;
}
set_except_vector(0, decstation_handle_int);
}
/*
* linux/arch/mips/dec/kn02-irq.c
*
* DECstation 5000/200 (KN02) Control and Status Register
* interrupts.
*
* Copyright (c) 2002, 2003 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/spinlock.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;
spinlock_t kn02_lock = SPIN_LOCK_UNLOCKED;
static int kn02_irq_base;
static inline void unmask_kn02_irq(unsigned int irq)
{
volatile u32 *csr = (volatile u32 *)KN02_CSR_BASE;
cached_kn02_csr |= (1 << (irq - kn02_irq_base + 16));
*csr = cached_kn02_csr;
}
static inline void mask_kn02_irq(unsigned int irq)
{
volatile u32 *csr = (volatile u32 *)KN02_CSR_BASE;
cached_kn02_csr &= ~(1 << (irq - kn02_irq_base + 16));
*csr = cached_kn02_csr;
}
static inline void enable_kn02_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&kn02_lock, flags);
unmask_kn02_irq(irq);
spin_unlock_irqrestore(&kn02_lock, flags);
}
static inline void disable_kn02_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&kn02_lock, flags);
mask_kn02_irq(irq);
spin_unlock_irqrestore(&kn02_lock, flags);
}
static unsigned int startup_kn02_irq(unsigned int irq)
{
enable_kn02_irq(irq);
return 0;
}
#define shutdown_kn02_irq disable_kn02_irq
static void ack_kn02_irq(unsigned int irq)
{
spin_lock(&kn02_lock);
mask_kn02_irq(irq);
spin_unlock(&kn02_lock);
iob();
}
static void end_kn02_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
enable_kn02_irq(irq);
}
static struct hw_interrupt_type kn02_irq_type = {
.typename = "KN02-CSR",
.startup = startup_kn02_irq,
.shutdown = shutdown_kn02_irq,
.enable = enable_kn02_irq,
.disable = disable_kn02_irq,
.ack = ack_kn02_irq,
.end = end_kn02_irq,
};
void __init init_kn02_irqs(int base)
{
volatile u32 *csr = (volatile u32 *)KN02_CSR_BASE;
unsigned long flags;
int i;
/* Mask interrupts. */
spin_lock_irqsave(&kn02_lock, flags);
cached_kn02_csr &= ~KN03_CSR_IOINTEN;
*csr = cached_kn02_csr;
iob();
spin_unlock_irqrestore(&kn02_lock, flags);
for (i = base; i < base + KN02_IRQ_LINES; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0;
irq_desc[i].depth = 1;
irq_desc[i].handler = &kn02_irq_type;
}
kn02_irq_base = base;
}
# $Id: Makefile,v 1.1 1999/01/17 03:49:44 ralf Exp $
#
# Makefile for the DECstation prom monitor library routines
# under Linux.
#
lib-y := init.o memory.o cmdline.o identify.o locore.o
lib-y += init.o memory.o cmdline.o identify.o
EXTRA_AFLAGS := $(CFLAGS)
lib-$(CONFIG_MIPS32) += locore.o
lib-$(CONFIG_MIPS64) += call_o32.o
dep:
$(CPP) $(CPPFLAGS) -M *.c > .depend
EXTRA_AFLAGS := $(CFLAGS)
/*
* arch/mips/dec/call_o32.S
*
* O32 interface for the 64 (or N32) ABI.
*
* Copyright (C) 2002 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 <asm/asm.h>
#include <asm/regdef.h>
/* Maximum number of arguments supported. Must be even! */
#define O32_ARGC 32
/* Number of static registers we save. */
#define O32_STATC 11
/* Frame size for both of the above. */
#define O32_FRAMESZ (4 * O32_ARGC + SZREG * O32_STATC)
.text
/*
* O32 function call dispatcher, for interfacing 32-bit ROM routines.
*
* The standard 64 (N32) calling sequence is supported, with a0
* holding a function pointer, a1-a7 -- its first seven arguments
* and the stack -- remaining ones (up to O32_ARGC, including a1-a7).
* Static registers, gp and fp are preserved, v0 holds a result.
* This code relies on the called o32 function for sp and ra
* restoration and thus both this dispatcher and the current stack
* have to be placed in a KSEGx (or KUSEG) address space. Any
* pointers passed have to point to addresses within one of these
* spaces as well.
*/
NESTED(call_o32, O32_FRAMESZ, ra)
REG_SUBU sp,O32_FRAMESZ
REG_S ra,O32_FRAMESZ-1*SZREG(sp)
REG_S fp,O32_FRAMESZ-2*SZREG(sp)
REG_S gp,O32_FRAMESZ-3*SZREG(sp)
REG_S s7,O32_FRAMESZ-4*SZREG(sp)
REG_S s6,O32_FRAMESZ-5*SZREG(sp)
REG_S s5,O32_FRAMESZ-6*SZREG(sp)
REG_S s4,O32_FRAMESZ-7*SZREG(sp)
REG_S s3,O32_FRAMESZ-8*SZREG(sp)
REG_S s2,O32_FRAMESZ-9*SZREG(sp)
REG_S s1,O32_FRAMESZ-10*SZREG(sp)
REG_S s0,O32_FRAMESZ-11*SZREG(sp)
move jp,a0
sll a0,a1,zero
sll a1,a2,zero
sll a2,a3,zero
sll a3,a4,zero
sw a5,0x10(sp)
sw a6,0x14(sp)
sw a7,0x18(sp)
PTR_LA t0,O32_FRAMESZ(sp)
PTR_LA t1,0x1c(sp)
li t2,O32_ARGC-7
1:
lw t3,(t0)
REG_ADDU t0,SZREG
sw t3,(t1)
REG_SUBU t2,1
REG_ADDU t1,4
bnez t2,1b
jalr jp
REG_L s0,O32_FRAMESZ-11*SZREG(sp)
REG_L s1,O32_FRAMESZ-10*SZREG(sp)
REG_L s2,O32_FRAMESZ-9*SZREG(sp)
REG_L s3,O32_FRAMESZ-8*SZREG(sp)
REG_L s4,O32_FRAMESZ-7*SZREG(sp)
REG_L s5,O32_FRAMESZ-6*SZREG(sp)
REG_L s6,O32_FRAMESZ-5*SZREG(sp)
REG_L s7,O32_FRAMESZ-4*SZREG(sp)
REG_L gp,O32_FRAMESZ-3*SZREG(sp)
REG_L fp,O32_FRAMESZ-2*SZREG(sp)
REG_L ra,O32_FRAMESZ-1*SZREG(sp)
REG_ADDU sp,O32_FRAMESZ
jr ra
END(call_o32)
......@@ -6,32 +6,30 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/types.h>
#include <asm/bootinfo.h>
#include "prom.h"
#include <asm/dec/prom.h>
#undef PROM_DEBUG
#ifdef PROM_DEBUG
extern int (*prom_printf)(char *, ...);
#endif
char arcs_cmdline[COMMAND_LINE_SIZE];
char arcs_cmdline[CL_SIZE];
void __init prom_init_cmdline(int argc, char **argv, unsigned long magic)
void __init prom_init_cmdline(s32 argc, s32 *argv, u32 magic)
{
char *arg;
int start_arg, i;
/*
* collect args and prepare cmd_line
*/
if (magic != REX_PROM_MAGIC)
if (!prom_is_rex(magic))
start_arg = 1;
else
start_arg = 2;
for (i = start_arg; i < argc; i++) {
strcat(arcs_cmdline, argv[i]);
arg = (void *)(long)(argv[i]);
strcat(arcs_cmdline, arg);
if (i < (argc - 1))
strcat(arcs_cmdline, " ");
}
......@@ -39,6 +37,4 @@ void __init prom_init_cmdline(int argc, char **argv, unsigned long magic)
#ifdef PROM_DEBUG
prom_printf("arcs_cmdline: %s\n", &(arcs_cmdline[0]));
#endif
}
......@@ -2,32 +2,104 @@
* identify.c: machine identification code.
*
* Copyright (C) 1998 Harald Koerfgen and Paul M. Antoine
*
* $Id: identify.c,v 1.2 1999/10/09 00:00:58 ralf Exp $
* Copyright (C) 2002, 2003 Maciej W. Rozycki
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mc146818rtc.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 "dectypes.h"
#include "prom.h"
extern char *(*prom_getenv)(char *);
extern int (*prom_printf)(char *, ...);
extern int (*rex_getsysid)(void);
extern unsigned long mips_machgroup;
extern unsigned long mips_machtype;
void __init prom_identify_arch (unsigned int magic)
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
*/
static inline void prom_init_kn01(void)
{
dec_rtc_base = (void *)KN01_RTC_BASE;
dec_kn_slot_size = KN01_SLOT_SIZE;
}
static inline void prom_init_kn230(void)
{
dec_rtc_base = (void *)KN01_RTC_BASE;
dec_kn_slot_size = KN01_SLOT_SIZE;
}
static inline void prom_init_kn02(void)
{
dec_rtc_base = (void *)KN02_RTC_BASE;
dec_kn_slot_size = KN02_SLOT_SIZE;
}
static inline void prom_init_kn02xa(void)
{
ioasic_base = (void *)KN02XA_IOASIC_BASE;
dec_rtc_base = (void *)KN02XA_RTC_BASE;
dec_kn_slot_size = IOASIC_SLOT_SIZE;
}
static inline void prom_init_kn03(void)
{
unsigned char dec_cpunum, dec_firmrev, dec_etc;
int dec_systype;
unsigned long dec_sysid;
ioasic_base = (void *)KN03_IOASIC_BASE;
dec_rtc_base = (void *)KN03_RTC_BASE;
dec_kn_slot_size = IOASIC_SLOT_SIZE;
}
void __init prom_identify_arch(u32 magic)
{
unsigned char dec_cpunum, dec_firmrev, dec_etc, dec_systype;
u32 dec_sysid;
if (magic != REX_PROM_MAGIC) {
if (!prom_is_rex(magic)) {
dec_sysid = simple_strtoul(prom_getenv("systype"), (char **)0, 0);
} else {
dec_sysid = rex_getsysid();
......@@ -49,50 +121,52 @@ void __init prom_identify_arch (unsigned int magic)
* FIXME: This may not be an exhaustive list of DECStations/Servers!
* Put all model-specific initialisation calls here.
*/
prom_printf("This DECstation is a ");
switch (dec_systype) {
case DS2100_3100:
prom_printf("DS2100/3100\n");
mips_machtype = MACH_DS23100;
prom_init_kn01();
break;
case DS5100: /* DS5100 MIPSMATE */
prom_printf("DS5100\n");
mips_machtype = MACH_DS5100;
prom_init_kn230();
break;
case DS5000_200: /* DS5000 3max */
prom_printf("DS5000/200\n");
mips_machtype = MACH_DS5000_200;
prom_init_kn02();
break;
case DS5000_1XX: /* DS5000/100 3min */
prom_printf("DS5000/1xx\n");
mips_machtype = MACH_DS5000_1XX;
prom_init_kn02xa();
break;
case DS5000_2X0: /* DS5000/240 3max+ */
prom_printf("DS5000/2x0\n");
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/2x */
prom_printf("Personal DS5000/xx\n");
case DS5000_XX: /* Personal DS5000/xx maxine */
mips_machtype = MACH_DS5000_XX;
prom_init_kn02xa();
break;
case DS5800: /* DS5800 Isis */
prom_printf("DS5800\n");
mips_machtype = MACH_DS5800;
break;
case DS5400: /* DS5400 MIPSfair */
prom_printf("DS5400\n");
mips_machtype = MACH_DS5400;
break;
case DS5500: /* DS5500 MIPSfair-2 */
prom_printf("DS5500\n");
mips_machtype = MACH_DS5500;
break;
default:
prom_printf("unknown, id is %x", dec_systype);
mips_machtype = MACH_DSUNKNOWN;
break;
}
}
if (mips_machtype == MACH_DSUNKNOWN)
prom_printf("This is an %s, id is %x\n",
dec_system_strings[mips_machtype],
dec_systype);
else
prom_printf("This is a %s\n",
dec_system_strings[mips_machtype]);
}
......@@ -2,98 +2,103 @@
* init.c: PROM library initialisation code.
*
* Copyright (C) 1998 Harald Koerfgen
* Copyright (C) 2002 Maciej W. Rozycki
*/
#include <linux/init.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/types.h>
#include <asm/bootinfo.h>
#include <asm/cpu.h>
#include "prom.h"
#include <asm/processor.h>
/*
* PROM Interface (whichprom.c)
*/
typedef struct {
int pagesize;
unsigned char bitmap[0];
} memmap;
#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 (*__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 (*pmax_open)(char*, int);
int (*pmax_lseek)(int, long, int);
int (*pmax_read)(int, void *, int);
int (*pmax_close)(int);
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);
extern void prom_meminit(unsigned int);
extern void prom_identify_arch(unsigned int);
extern void prom_init_cmdline(int, char **, unsigned long);
/*
* Detect which PROM's the DECSTATION has, and set the callback vectors
* appropriately.
*/
void __init which_prom(unsigned long magic, int *prom_vec)
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 (magic == REX_PROM_MAGIC)
{
if (prom_is_rex(magic)) {
/*
* Set up prom abstraction structure with REX entry points.
*/
rex_bootinit = (int (*)(void)) *(prom_vec + REX_PROM_BOOTINIT);
rex_bootread = (int (*)(void)) *(prom_vec + REX_PROM_BOOTREAD);
rex_getbitmap = (int (*)(memmap *)) *(prom_vec + REX_PROM_GETBITMAP);
prom_getchar = (int (*)(void)) *(prom_vec + REX_PROM_GETCHAR);
prom_getenv = (char *(*)(char *)) *(prom_vec + REX_PROM_GETENV);
rex_getsysid = (int (*)(void)) *(prom_vec + REX_PROM_GETSYSID);
rex_gettcinfo = (void *(*)(void)) *(prom_vec + REX_PROM_GETTCINFO);
prom_printf = (int (*)(char *, ...)) *(prom_vec + REX_PROM_PRINTF);
rex_slot_address = (unsigned long *(*)(int)) *(prom_vec + REX_PROM_SLOTADDR);
rex_clear_cache = (void (*)(void)) * (prom_vec + REX_PROM_CLEARCACHE);
}
else
{
__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 = (int (*)(void)) PMAX_PROM_GETCHAR;
prom_getenv = (char *(*)(char *)) PMAX_PROM_GETENV;
prom_printf = (int (*)(char *, ...)) PMAX_PROM_PRINTF;
pmax_open = (int (*)(char *, int)) PMAX_PROM_OPEN;
pmax_lseek = (int (*)(int, long, int)) PMAX_PROM_LSEEK;
pmax_read = (int (*)(int, void *, int)) PMAX_PROM_READ;
pmax_close = (int (*)(int)) PMAX_PROM_CLOSE;
__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;
}
}
int __init prom_init(int argc, char **argv,
unsigned long magic, int *prom_vec)
int __init prom_init(s32 argc, s32 *argv, u32 magic, s32 *prom_vec)
{
extern void dec_machine_halt(void);
/* Determine which PROM's we have (and therefore which machine we're on!) */
/*
* Determine which PROM's we have
* (and therefore which machine we're on!)
*/
which_prom(magic, prom_vec);
if (magic == REX_PROM_MAGIC)
if (prom_is_rex(magic))
rex_clear_cache();
/* Were we compiled with the right CPU option? */
#if defined(CONFIG_CPU_R3000)
if ((mips_cpu.cputype == CPU_R4000SC) ||
(mips_cpu.cputype == CPU_R4400SC)) {
if ((current_cpu_data.cputype == CPU_R4000SC) ||
(current_cpu_data.cputype == CPU_R4400SC)) {
prom_printf("Sorry, this kernel is compiled for the wrong CPU type!\n");
prom_printf("Please recompile with \"CONFIG_CPU_R4x00 = y\"\n");
dec_machine_halt();
......@@ -101,8 +106,8 @@ int __init prom_init(int argc, char **argv,
#endif
#if defined(CONFIG_CPU_R4X00)
if ((mips_cpu.cputype == CPU_R3000) ||
(mips_cpu.cputype == CPU_R3000A)) {
if ((current_cpu_data.cputype == CPU_R3000) ||
(current_cpu_data.cputype == CPU_R3000A)) {
prom_printf("Sorry, this kernel is compiled for the wrong CPU type!\n");
prom_printf("Please recompile with \"CONFIG_CPU_R3000 = y\"\n");
dec_machine_halt();
......@@ -115,4 +120,3 @@ int __init prom_init(int argc, char **argv,
return 0;
}
......@@ -19,11 +19,11 @@ NESTED(genexcept_early, 0, sp)
mfc0 k0, CP0_STATUS
la k1, mem_err
sw k0,0(k1)
sw k0, 0(k1)
mfc0 k0, CP0_EPC
nop
addiu k0,4 # skip the causing instruction
addiu k0, 4 # skip the causing instruction
jr k0
rfe
END(genexcept_early)
......
......@@ -2,37 +2,22 @@
* memory.c: memory initialisation code.
*
* Copyright (C) 1998 Harald Koerfgen, Frieder Streffer and Paul M. Antoine
* Copyright (C) 2000 Maciej W. Rozycki
*
* $Id: memory.c,v 1.3 1999/10/09 00:00:58 ralf Exp $
* Copyright (C) 2000, 2002 Maciej W. Rozycki
*/
#include <linux/init.h>
#include <linux/config.h>
#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/page.h>
#include <asm/bootinfo.h>
#include <asm/dec/machtype.h>
#include <asm/dec/prom.h>
#include <asm/page.h>
#include <asm/sections.h>
#include "prom.h"
typedef struct {
int pagesize;
unsigned char bitmap[0];
} memmap;
extern int (*rex_getbitmap)(memmap *);
#undef PROM_DEBUG
#ifdef PROM_DEBUG
extern int (*prom_printf)(char *, ...);
#endif
volatile unsigned long mem_err = 0; /* So we know an error occurred */
......@@ -43,7 +28,7 @@ volatile unsigned long mem_err = 0; /* So we know an error occurred */
#define CHUNK_SIZE 0x400000
static void __init pmax_setup_memory_region(void)
static inline void pmax_setup_memory_region(void)
{
volatile unsigned char *memory_page, dummy;
char old_handler[0x80];
......@@ -73,14 +58,14 @@ static void __init pmax_setup_memory_region(void)
* Use the REX prom calls to get hold of the memory bitmap, and thence
* determine memory size.
*/
static void __init rex_setup_memory_region(void)
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 *) 0x80028000;
bm = (memmap *)KSEG0ADDR(0x28000);
bitmap_size = rex_getbitmap(bm);
......@@ -100,9 +85,9 @@ static void __init rex_setup_memory_region(void)
add_memory_region(mem_start, mem_size, BOOT_MEM_RAM);
}
void __init prom_meminit(unsigned int magic)
void __init prom_meminit(u32 magic)
{
if (magic != REX_PROM_MAGIC)
if (!prom_is_rex(magic))
pmax_setup_memory_region();
else
rex_setup_memory_region();
......@@ -111,14 +96,13 @@ void __init prom_meminit(unsigned int magic)
void __init prom_free_prom_memory (void)
{
unsigned long addr, end;
extern char _ftext;
/*
* Free everything below the kernel itself but leave
* the first page reserved for the exception handlers.
*/
#ifdef CONFIG_DECLANCE
#if defined(CONFIG_DECLANCE) || defined(CONFIG_DECLANCE_MODULE)
/*
* Leave 128 KB reserved for Lance memory for
* IOASIC DECstations.
......@@ -126,10 +110,10 @@ void __init prom_free_prom_memory (void)
* XXX: save this address for use in dec_lance.c?
*/
if (IOASIC)
end = __pa(&_ftext) - 0x00020000;
end = __pa(&_text) - 0x00020000;
else
#endif
end = __pa(&_ftext);
end = __pa(&_text);
addr = PAGE_SIZE;
while (addr < end) {
......
/*
* Miscellaneous definitions used to call the routines contained in the boot
* PROMs on various models of DECSTATION's.
* the rights to redistribute these changes.
*/
#ifndef __ASM_DEC_PROM_H
#define __ASM_DEC_PROM_H
/*
* PMAX/3MAX PROM entry points for DS2100/3100's and DS5000/2xx's. Many of
* these will work for MIPSen as well!
*/
#define VEC_RESET 0xBFC00000 /* Prom base address */
#define PMAX_PROM_ENTRY(x) (VEC_RESET+((x)*8)) /* Prom jump table */
#define PMAX_PROM_HALT PMAX_PROM_ENTRY(2) /* valid on MIPSen */
#define PMAX_PROM_AUTOBOOT PMAX_PROM_ENTRY(5) /* valid on MIPSen */
#define PMAX_PROM_OPEN PMAX_PROM_ENTRY(6)
#define PMAX_PROM_READ PMAX_PROM_ENTRY(7)
#define PMAX_PROM_CLOSE PMAX_PROM_ENTRY(10)
#define PMAX_PROM_LSEEK PMAX_PROM_ENTRY(11)
#define PMAX_PROM_GETCHAR PMAX_PROM_ENTRY(12)
#define PMAX_PROM_PUTCHAR PMAX_PROM_ENTRY(13) /* 12 on MIPSen */
#define PMAX_PROM_GETS PMAX_PROM_ENTRY(15)
#define PMAX_PROM_PRINTF PMAX_PROM_ENTRY(17)
#define PMAX_PROM_GETENV PMAX_PROM_ENTRY(33) /* valid on MIPSen */
/*
* Magic number indicating REX PROM available on DECSTATION. Found in
* register a2 on transfer of control to program from PROM.
*/
#define REX_PROM_MAGIC 0x30464354
/*
* 3MIN/MAXINE PROM entry points for DS5000/1xx's, DS5000/xx's, and
* DS5000/2x0.
*/
#define REX_PROM_GETBITMAP 0x84/4 /* get mem bitmap */
#define REX_PROM_GETCHAR 0x24/4 /* getch() */
#define REX_PROM_GETENV 0x64/4 /* get env. variable */
#define REX_PROM_GETSYSID 0x80/4 /* get system id */
#define REX_PROM_GETTCINFO 0xa4/4
#define REX_PROM_PRINTF 0x30/4 /* printf() */
#define REX_PROM_SLOTADDR 0x6c/4 /* slotaddr */
#define REX_PROM_BOOTINIT 0x54/4 /* open() */
#define REX_PROM_BOOTREAD 0x58/4 /* read() */
#define REX_PROM_CLEARCACHE 0x7c/4
#endif /* __ASM_DEC_PROM_H */
......@@ -12,8 +12,7 @@
#include <linux/console.h>
#include <linux/fs.h>
extern int (*prom_getchar) (void);
extern int (*prom_printf) (char *,...);
#include <asm/dec/prom.h>
static void prom_console_write(struct console *co, const char *s,
unsigned count)
......@@ -35,16 +34,10 @@ static int __init prom_console_setup(struct console *co, char *options)
return 0;
}
static kdev_t prom_console_device(struct console *c)
{
return MKDEV(TTY_MAJOR, 64 + c->index);
}
static struct console sercons =
{
.name = "ttyS",
.write = prom_console_write,
.device = prom_console_device,
.setup = prom_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
......@@ -54,8 +47,10 @@ static struct console sercons =
* Register console.
*/
long __init prom_console_init(long kmem_start, long kmem_end)
static int __init prom_console_init(void)
{
register_console(&sercons);
return kmem_start;
return 0;
}
console_initcall(prom_console_init);
/*
* $Id: $
*
* Reset a DECstation machine.
*
* Copyright (C) 199x the Anonymous
* Copyright (C) 2001, 2002, 2003 Maciej W. Rozycki
*/
void (*back_to_prom)(void) = (void (*)(void))0xBFC00000;
#include <asm/addrspace.h>
#include <asm/ptrace.h>
#define back_to_prom() (((void (*)(void))KSEG1ADDR(0x1fc00000))())
void dec_machine_restart(char *command)
{
......
......@@ -3,18 +3,22 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* RTC routines for DECstation style attached Dallas chip.
* RTC routines for DECstation style attached Dallas DS1287 chip.
*
* Copyright (C) 1998, 2001 by Ralf Baechle
* Copyright (C) 1998 by Harald Koerfgen
* Copyright (C) 2002 Maciej W. Rozycki
*/
#include <linux/mc146818rtc.h>
#include <linux/module.h>
#include <linux/types.h>
extern char *dec_rtc_base;
volatile u8 *dec_rtc_base;
static unsigned char dec_rtc_read_data(unsigned long addr)
{
return (dec_rtc_base[addr * 4]);
return dec_rtc_base[addr * 4];
}
static void dec_rtc_write_data(unsigned char data, unsigned long addr)
......@@ -27,9 +31,10 @@ static int dec_rtc_bcd_mode(void)
return 0;
}
struct rtc_ops dec_rtc_ops =
{
struct rtc_ops dec_rtc_ops = {
&dec_rtc_read_data,
&dec_rtc_write_data,
&dec_rtc_bcd_mode
};
EXPORT_SYMBOL(dec_rtc_base);
This diff is collapsed.
......@@ -2,12 +2,14 @@
* linux/arch/mips/dec/time.c
*
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
* Copyright (C) 2000 Maciej W. Rozycki
* 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/types.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/sched.h>
......@@ -45,7 +47,9 @@ extern volatile unsigned long wall_jiffies;
/* This is for machines which generate the exact clock. */
#define USECS_PER_JIFFY (1000000/HZ)
#define USECS_PER_JIFFY_FRAC ((1000000ULL << 32) / HZ & 0xffffffff)
#define USECS_PER_JIFFY_FRAC ((u32)((1000000ULL << 32) / HZ))
#define TICK_SIZE (tick_nsec / 1000)
/* Cycle counter value at the previous timer interrupt.. */
......@@ -99,7 +103,7 @@ static unsigned long do_fast_gettimeoffset(void)
}
}
/* Get last timer tick in absolute kernel time */
count = read_32bit_cp0_register(CP0_COUNT);
count = read_c0_count();
/* .. relative to previous jiffy (32 bits is enough) */
count -= timerlo;
......@@ -140,7 +144,7 @@ static unsigned long do_ioasic_gettimeoffset(void)
}
}
/* Get last timer tick in absolute kernel time */
count = ioasic_read(FCTR);
count = ioasic_read(IO_REG_FCTR);
/* .. relative to previous jiffy (32 bits is enough) */
count -= timerlo;
......@@ -192,8 +196,6 @@ static unsigned long do_ioasic_gettimeoffset(void)
* comp.protocols.time.ntp!
*/
#define TICK_SIZE tick
static unsigned long do_slow_gettimeoffset(void)
{
/*
......@@ -206,57 +208,58 @@ static unsigned long do_slow_gettimeoffset(void)
static unsigned long (*do_gettimeoffset) (void) = do_slow_gettimeoffset;
/*
* This version of gettimeofday has near microsecond resolution.
* This version of gettimeofday has microsecond resolution
* and better than microsecond precision on fast x86 machines with TSC.
*/
void do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
unsigned long seq;
unsigned long usec, sec;
do {
seq = read_seqbegin_irqsave(&xtime_lock, flags);
*tv = xtime;
tv->tv_usec += do_gettimeoffset();
/*
* xtime is atomically updated in timer_bh. jiffies - wall_jiffies
* is nonzero if the timer bottom half hasnt executed yet.
*/
if (jiffies - wall_jiffies)
tv->tv_usec += USECS_PER_JIFFY;
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
seq = read_seqbegin(&xtime_lock);
usec = do_gettimeoffset();
{
unsigned long lost = jiffies - wall_jiffies;
if (lost)
usec += lost * (1000000 / HZ);
}
sec = xtime.tv_sec;
usec += (xtime.tv_nsec / 1000);
} while (read_seqretry(&xtime_lock, seq));
if (tv->tv_usec >= 1000000) {
tv->tv_usec -= 1000000;
tv->tv_sec++;
while (usec >= 1000000) {
usec -= 1000000;
sec++;
}
tv->tv_sec = sec;
tv->tv_usec = usec;
}
void do_settimeofday(struct timeval *tv)
{
write_seqlock_irq(&xtime_lock);
/* This is revolting. We need to set the xtime.tv_usec
* correctly. However, the value in this location is
* is value at the last tick.
* Discover what correction gettimeofday
* would have done, and then undo it!
/*
* This is revolting. We need to set "xtime" correctly. However, the
* value in this location is the value at the most recent update of
* wall time. Discover what correction gettimeofday() would have
* made, and then undo it!
*/
tv->tv_usec -= do_gettimeoffset();
tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
if (tv->tv_usec < 0) {
while (tv->tv_usec < 0) {
tv->tv_usec += 1000000;
tv->tv_sec--;
}
xtime = *tv;
xtime.tv_sec = tv->tv_sec;
xtime.tv_nsec = (tv->tv_usec * 1000);
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
write_sequnlock_irq(&xtime_lock);
}
......@@ -281,7 +284,7 @@ static int set_rtc_mmss(unsigned long nowtime)
cmos_minutes = CMOS_READ(RTC_MINUTES);
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
BCD_TO_BIN(cmos_minutes);
cmos_minutes = BCD2BIN(cmos_minutes);
/*
* since we're only adjusting minutes and seconds,
......@@ -297,8 +300,8 @@ static int set_rtc_mmss(unsigned long nowtime)
if (abs(real_minutes - cmos_minutes) < 30) {
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
BIN_TO_BCD(real_seconds);
BIN_TO_BCD(real_minutes);
real_seconds = BIN2BCD(real_seconds);
real_minutes = BIN2BCD(real_minutes);
}
CMOS_WRITE(real_seconds, RTC_SECONDS);
CMOS_WRITE(real_minutes, RTC_MINUTES);
......@@ -366,8 +369,8 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if ((time_status & STA_UNSYNC) == 0
&& xtime.tv_sec > last_rtc_update + 660
&& xtime.tv_usec >= 500000 - tick / 2
&& xtime.tv_usec <= 500000 + tick / 2) {
&& (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2
&& (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
......@@ -381,7 +384,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
rigged to be safe on the 386 - basically it's a hack, so don't look
closely for now.. */
/*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */
write_sequnlock(&xtime_lock);
}
static void r4k_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
......@@ -392,7 +395,7 @@ static void r4k_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* The cycle counter is only 32 bit which is good for about
* a minute at current count rates of upto 150MHz or so.
*/
count = read_32bit_cp0_register(CP0_COUNT);
count = read_c0_count();
timerhi += (count < timerlo); /* Wrap around */
timerlo = count;
......@@ -402,7 +405,7 @@ static void r4k_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* update the timer[hi]/[lo] to make do_fast_gettimeoffset()
* quotient calc still valid. -arca
*/
write_32bit_cp0_register(CP0_COUNT, 0);
write_c0_count(0);
timerhi = timerlo = 0;
}
......@@ -417,7 +420,7 @@ static void ioasic_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* The free-running counter is 32 bit which is good for about
* 2 minutes, 50 seconds at possible count rates of upto 25MHz.
*/
count = ioasic_read(FCTR);
count = ioasic_read(IO_REG_FCTR);
timerhi += (count < timerlo); /* Wrap around */
timerlo = count;
......@@ -427,15 +430,18 @@ static void ioasic_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* update the timer[hi]/[lo] to make do_fast_gettimeoffset()
* quotient calc still valid. -arca
*/
ioasic_write(FCTR, 0);
ioasic_write(IO_REG_FCTR, 0);
timerhi = timerlo = 0;
}
timer_interrupt(irq, dev_id, regs);
}
struct irqaction irq0 = {timer_interrupt, SA_INTERRUPT, 0,
"timer", NULL, NULL};
struct irqaction irq0 = {
.handler = timer_interrupt,
.flags = SA_INTERRUPT,
.name = "timer",
};
void __init time_init(void)
{
......@@ -463,12 +469,12 @@ void __init time_init(void)
year = CMOS_READ(RTC_YEAR);
} while (sec != CMOS_READ(RTC_SECONDS));
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
BCD_TO_BIN(sec);
BCD_TO_BIN(min);
BCD_TO_BIN(hour);
BCD_TO_BIN(day);
BCD_TO_BIN(mon);
BCD_TO_BIN(year);
sec = BCD2BIN(sec);
min = BCD2BIN(min);
hour = BCD2BIN(hour);
day = BCD2BIN(day);
mon = BCD2BIN(mon);
year = BCD2BIN(year);
}
/*
* The PROM will reset the year to either '72 or '73.
......@@ -480,15 +486,15 @@ void __init time_init(void)
write_seqlock_irq(&xtime_lock);
xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
xtime.tv_usec = 0;
xtime.tv_nsec = 0;
write_sequnlock_irq(&xtime_lock);
if (mips_cpu.options & MIPS_CPU_COUNTER) {
write_32bit_cp0_register(CP0_COUNT, 0);
if (cpu_has_counter) {
write_c0_count(0);
do_gettimeoffset = do_fast_gettimeoffset;
irq0.handler = r4k_timer_interrupt;
} else if (IOASIC) {
ioasic_write(FCTR, 0);
ioasic_write(IO_REG_FCTR, 0);
do_gettimeoffset = do_ioasic_gettimeoffset;
irq0.handler = ioasic_timer_interrupt;
}
......
......@@ -11,15 +11,18 @@
* for more details.
*
* Copyright (C) 1998 Harald Koerfgen
* Copyright (C) 2002 Maciej W. Rozycki
*/
#include <asm/bootinfo.h>
#include <linux/init.h>
#include <asm/bootinfo.h>
#include <asm/system.h>
#include <asm/wbflush.h>
static void wbflush_kn01(void);
static void wbflush_kn210(void);
static void wbflush_kn02ba(void);
static void wbflush_kn03(void);
static void wbflush_mips(void);
void (*__wbflush) (void);
......@@ -27,28 +30,24 @@ 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_200: /* DS5000 3max */
__wbflush = wbflush_kn01;
break;
case MACH_DS5000_1XX: /* DS5000/100 3min */
__wbflush = wbflush_kn02ba;
break;
case MACH_DS5000_2X0: /* DS5000/240 3max+ */
__wbflush = wbflush_kn03;
break;
case MACH_DS5000_XX: /* Personal DS5000/2x */
__wbflush = wbflush_kn02ba;
case MACH_DS5000_2X0: /* DS5000/240 3max+ */
case MACH_DS5900: /* DS5900 bigmax */
default:
__wbflush = wbflush_mips;
break;
}
}
/*
* For the DS3100 and DS5000/200 the writeback buffer functions
* For the DS3100 and DS5000/200 the R2020/R3220 writeback buffer functions
* as part of Coprocessor 0.
*/
static void wbflush_kn01(void)
......@@ -78,29 +77,16 @@ static void wbflush_kn210(void)
"mtc0\t$2,$12\n\t"
"nop\n\t"
".set\tpop"
: : :"$2", "$3");
}
/*
* Looks like some magic with the System Interrupt Mask Register
* in the famous IOASIC for kmins and maxines.
*/
static void wbflush_kn02ba(void)
{
asm(".set\tpush\n\t"
".set\tnoreorder\n\t"
"lui\t$2,0xbc04\n\t"
"lw\t$3,0x120($2)\n\t"
"lw\t$3,0x120($2)\n\t"
".set\tpop"
: : :"$2", "$3");
: : : "$2", "$3");
}
/*
* The DS500/2x0 doesn't need to write back the WB.
* I/O ASIC systems use a standard writeback buffer that gets flushed
* upon an uncached read.
*/
static void wbflush_kn03(void)
static void wbflush_mips(void)
{
__fast_iob();
}
#include <linux/module.h>
......
This diff is collapsed.
This diff is collapsed.
/*
* include/asm-mips/dec/ecc.h
*
* ECC handling logic definitions common to DECstation/DECsystem
* 5000/200 (KN02), 5000/240 (KN03), 5000/260 (KN05) and
* DECsystem 5900 (KN03), 5900/260 (KN05) systems.
*
* Copyright (C) 2003 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.
*/
#ifndef __ASM_MIPS_DEC_ECC_H
#define __ASM_MIPS_DEC_ECC_H
/*
* Error Address Register bits.
* The register is r/wc -- any write clears it.
*/
#define KN0X_EAR_VALID (1<<31) /* error data valid, bus IRQ */
#define KN0X_EAR_CPU (1<<30) /* CPU/DMA transaction */
#define KN0X_EAR_WRITE (1<<29) /* write/read transaction */
#define KN0X_EAR_ECCERR (1<<28) /* ECC/timeout or overrun */
#define KN0X_EAR_RES_27 (1<<27) /* unused */
#define KN0X_EAR_ADDRESS (0x7ffffff<<0) /* address involved */
/*
* Error Syndrome Register bits.
* The register is frozen when EAR.VALID is set, otherwise it records bits
* from the last memory read. The register is r/wc -- any write clears it.
*/
#define KN0X_ESR_VLDHI (1<<31) /* error data valid hi word */
#define KN0X_ESR_CHKHI (0x7f<<24) /* check bits read from mem */
#define KN0X_ESR_SNGHI (1<<23) /* single/double bit error */
#define KN0X_ESR_SYNHI (0x7f<<16) /* syndrome from ECC logic */
#define KN0X_ESR_VLDLO (1<<15) /* error data valid lo word */
#define KN0X_ESR_CHKLO (0x7f<<8) /* check bits read from mem */
#define KN0X_ESR_SNGLO (1<<7) /* single/double bit error */
#define KN0X_ESR_SYNLO (0x7f<<0) /* syndrome from ECC logic */
#ifndef __ASSEMBLY__
struct pt_regs;
extern void dec_ecc_be_init(void);
extern int dec_ecc_be_handler(struct pt_regs *regs, int is_fixup);
extern void dec_ecc_be_interrupt(int irq, void *dev_id, struct pt_regs *regs);
#endif
#endif /* __ASM_MIPS_DEC_ECC_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment