diff options
Diffstat (limited to 'arch/mips/dec')
| -rw-r--r-- | arch/mips/dec/Makefile | 8 | ||||
| -rw-r--r-- | arch/mips/dec/Platform | 8 | ||||
| -rw-r--r-- | arch/mips/dec/boot/Makefile | 12 | ||||
| -rw-r--r-- | arch/mips/dec/boot/decstation.c | 83 | ||||
| -rw-r--r-- | arch/mips/dec/boot/ld.ecoff | 43 | ||||
| -rw-r--r-- | arch/mips/dec/ecc-berr.c | 68 | ||||
| -rw-r--r-- | arch/mips/dec/int-handler.S | 128 | ||||
| -rw-r--r-- | arch/mips/dec/ioasic-irq.c | 157 | ||||
| -rw-r--r-- | arch/mips/dec/kn01-berr.c | 200 | ||||
| -rw-r--r-- | arch/mips/dec/kn02-irq.c | 92 | ||||
| -rw-r--r-- | arch/mips/dec/kn02xa-berr.c | 139 | ||||
| -rw-r--r-- | arch/mips/dec/platform.c | 44 | ||||
| -rw-r--r-- | arch/mips/dec/prom/Makefile | 5 | ||||
| -rw-r--r-- | arch/mips/dec/prom/call_o32.S | 91 | ||||
| -rw-r--r-- | arch/mips/dec/prom/console.c | 42 | ||||
| -rw-r--r-- | arch/mips/dec/prom/dectypes.h | 2 | ||||
| -rw-r--r-- | arch/mips/dec/prom/identify.c | 37 | ||||
| -rw-r--r-- | arch/mips/dec/prom/init.c | 24 | ||||
| -rw-r--r-- | arch/mips/dec/prom/locore.S | 1 | ||||
| -rw-r--r-- | arch/mips/dec/prom/memory.c | 38 | ||||
| -rw-r--r-- | arch/mips/dec/promcon.c | 55 | ||||
| -rw-r--r-- | arch/mips/dec/reset.c | 15 | ||||
| -rw-r--r-- | arch/mips/dec/setup.c | 104 | ||||
| -rw-r--r-- | arch/mips/dec/tc.c | 95 | ||||
| -rw-r--r-- | arch/mips/dec/time.c | 181 | ||||
| -rw-r--r-- | arch/mips/dec/wbflush.c | 8 |
26 files changed, 882 insertions, 798 deletions
diff --git a/arch/mips/dec/Makefile b/arch/mips/dec/Makefile index 688757a97cb..bd74e05c90b 100644 --- a/arch/mips/dec/Makefile +++ b/arch/mips/dec/Makefile @@ -2,10 +2,8 @@ # Makefile for the DECstation family specific parts of the kernel # -obj-y := ecc-berr.o int-handler.o ioasic-irq.o kn02-irq.o reset.o \ - setup.o time.o +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_PROM_CONSOLE) += promcon.o +obj-$(CONFIG_TC) += tc.o obj-$(CONFIG_CPU_HAS_WB) += wbflush.o - -EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/dec/Platform b/arch/mips/dec/Platform new file mode 100644 index 00000000000..cf55a6f4e72 --- /dev/null +++ b/arch/mips/dec/Platform @@ -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 diff --git a/arch/mips/dec/boot/Makefile b/arch/mips/dec/boot/Makefile deleted file mode 100644 index bcea41698ef..00000000000 --- a/arch/mips/dec/boot/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# -# Makefile for the DECstation family specific parts of the kernel -# - -netboot: all - $(LD) -N -G 0 -T ld.ecoff ../../boot/zImage \ - dec_boot.o ramdisk.img -o nbImage - -obj-y := decstation.o - -clean: - rm -f nbImage diff --git a/arch/mips/dec/boot/decstation.c b/arch/mips/dec/boot/decstation.c deleted file mode 100644 index 56fd4277555..00000000000 --- a/arch/mips/dec/boot/decstation.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * arch/mips/dec/decstation.c - */ - -#define RELOC -#define INITRD -#define DEBUG_BOOT - -/* - * Magic number indicating REX PROM available on DECSTATION. - */ -#define REX_PROM_MAGIC 0x30464354 - -#define REX_PROM_CLEARCACHE 0x7c/4 -#define REX_PROM_PRINTF 0x30/4 - -#define VEC_RESET 0xBFC00000 /* Prom base address */ -#define PMAX_PROM_ENTRY(x) (VEC_RESET+((x)*8)) /* Prom jump table */ -#define PMAX_PROM_PRINTF PMAX_PROM_ENTRY(17) - -#define PARAM (k_start + 0x2000) - -#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210)) -#define INITRD_START (*(unsigned long *) (PARAM+0x218)) -#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c)) - -extern int _ftext, _end; /* begin and end of kernel image */ -extern void kernel_entry(int, char **, unsigned long, int *); - -void * memcpy(void * dest, const void *src, unsigned int count) -{ - unsigned long *tmp = (unsigned long *) dest, *s = (unsigned long *) src; - - count >>= 2; - while (count--) - *tmp++ = *s++; - - return dest; -} - -void dec_entry(int argc, char **argv, - unsigned long magic, int *prom_vec) -{ - void (*rex_clear_cache)(void); - int (*prom_printf)(char *, ...); - unsigned long k_start, len; - - /* - * The DS5100 leaves cpu with BEV enabled, clear it. - */ - asm( "lui\t$8,0x3000\n\t" - "mtc0\t$8,$12\n\t" - ".section\t.sdata\n\t" - ".section\t.sbss\n\t" - ".section\t.text" - : : : "$8"); - -#ifdef DEBUG_BOOT - if (magic == REX_PROM_MAGIC) { - prom_printf = (int (*)(char *, ...)) *(prom_vec + REX_PROM_PRINTF); - } else { - prom_printf = (int (*)(char *, ...)) PMAX_PROM_PRINTF; - } - prom_printf("Launching kernel...\n"); -#endif - - k_start = (unsigned long) (&kernel_entry) & 0xffff0000; - -#ifdef RELOC - /* - * Now copy kernel image to its destination. - */ - len = ((unsigned long) (&_end) - k_start); - memcpy((void *)k_start, &_ftext, len); -#endif - - if (magic == REX_PROM_MAGIC) { - rex_clear_cache = (void (*)(void)) * (prom_vec + REX_PROM_CLEARCACHE); - rex_clear_cache(); - } - - kernel_entry(argc, argv, magic, prom_vec); -} diff --git a/arch/mips/dec/boot/ld.ecoff b/arch/mips/dec/boot/ld.ecoff deleted file mode 100644 index aaa633dfb5f..00000000000 --- a/arch/mips/dec/boot/ld.ecoff +++ /dev/null @@ -1,43 +0,0 @@ -OUTPUT_FORMAT("ecoff-littlemips") -OUTPUT_ARCH(mips) -ENTRY(dec_entry) -SECTIONS -{ - . = 0x80200000; - - .text : - { - _ftext = .; - *(.text) - *(.fixup) - } - .rdata : - { - *(.rodata .rodata.* .rdata) - } - .data : - { - . = ALIGN(0x1000); - ramdisk.img (.data) - *(.data) - } - .sdata : - { - *(.sdata) - } - _gp = .; - .sbss : - { - *(.sbss) - *(.scommon) - } - .bss : - { - *(.dynbss) - *(.bss) - *(COMMON) - } - /DISCARD/ : { - *(.reginfo .mdebug .note) - } -} diff --git a/arch/mips/dec/ecc-berr.c b/arch/mips/dec/ecc-berr.c index 133fb7c48e6..2a66e908f6a 100644 --- a/arch/mips/dec/ecc-berr.c +++ b/arch/mips/dec/ecc-berr.c @@ -1,12 +1,10 @@ /* - * 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 + * 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 @@ -15,16 +13,18 @@ */ #include <linux/init.h> +#include <linux/interrupt.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/cpu-type.h> +#include <asm/irq_regs.h> #include <asm/processor.h> -#include <asm/system.h> +#include <asm/ptrace.h> #include <asm/traps.h> #include <asm/dec/ecc.h> @@ -57,7 +57,7 @@ static int dec_ecc_be_backend(struct pt_regs *regs, int is_fixup, int invoker) const char *kind, *agent, *cycle, *event; const char *status = "", *xbit = "", *fmt = ""; - dma_addr_t address; + unsigned long address; u16 syn = 0, sngl; int i = 0; @@ -66,7 +66,7 @@ static int dec_ecc_be_backend(struct pt_regs *regs, int is_fixup, int invoker) u32 chksyn = *kn0x_chksyn; int action = MIPS_BE_FATAL; - /* For non-ECC ack ASAP, so any subsequent errors get caught. */ + /* 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(); @@ -74,7 +74,7 @@ static int dec_ecc_be_backend(struct pt_regs *regs, int is_fixup, int invoker) if (!(erraddr & KN0X_EAR_VALID)) { /* No idea what happened. */ - printk(KERN_ALERT "Unidentified bus error %s.\n", kind); + printk(KERN_ALERT "Unidentified bus error %s\n", kind); return action; } @@ -126,7 +126,7 @@ static int dec_ecc_be_backend(struct pt_regs *regs, int is_fixup, int invoker) /* Ack now, no rewrite will happen. */ dec_ecc_be_ack(); - fmt = KERN_ALERT "%s" "invalid.\n"; + fmt = KERN_ALERT "%s" "invalid\n"; } else { sngl = syn & KN0X_ESR_SNGLO; syn &= KN0X_ESR_SYNLO; @@ -144,7 +144,8 @@ static int dec_ecc_be_backend(struct pt_regs *regs, int is_fixup, int invoker) } else if (!sngl) { status = dbestr; } else { - volatile u32 *ptr = (void *)KSEG1ADDR(address); + volatile u32 *ptr = + (void *)CKSEG1ADDR(address); *ptr = *ptr; /* Rewrite. */ iob(); @@ -160,12 +161,12 @@ static int dec_ecc_be_backend(struct pt_regs *regs, int is_fixup, int invoker) if (syn == 0x01) { fmt = KERN_ALERT "%s" "%#04x -- %s bit error " - "at check bit C%s.\n"; + "at check bit C%s\n"; xbit = "X"; } else { fmt = KERN_ALERT "%s" "%#04x -- %s bit error " - "at check bit C%s%u.\n"; + "at check bit C%s%u\n"; } i = syn >> 2; } else { @@ -175,16 +176,16 @@ static int dec_ecc_be_backend(struct pt_regs *regs, int is_fixup, int invoker) if (i < 32) fmt = KERN_ALERT "%s" "%#04x -- %s bit error " - "at data bit D%s%u.\n"; + "at data bit D%s%u\n"; else fmt = KERN_ALERT "%s" - "%#04x -- %s bit error.\n"; + "%#04x -- %s bit error\n"; } } } if (action != MIPS_BE_FIXUP) - printk(KERN_ALERT "Bus error %s: %s %s %s at %#010lx.\n", + 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) @@ -198,16 +199,18 @@ 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) +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_NONE; + return IRQ_HANDLED; /* - * FIXME: Find affected processes and kill them, otherwise we - * must die. + * 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. @@ -225,16 +228,13 @@ irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ 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); + volatile u32 *csr = (void *)CKSEG1ADDR(KN02_SLOT_BASE + KN02_CSR); - spin_lock_irqsave(&kn02_lock, flags); + 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 | KN03_CSR_LEDS; + cached_kn02_csr = *csr | KN02_CSR_LEDS; /* Set normal ECC detection and generation. */ cached_kn02_csr &= ~(KN02_CSR_DIAGCHK | KN02_CSR_DIAGGEN); @@ -242,18 +242,16 @@ static inline void dec_kn02_be_init(void) 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); + 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); - 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. @@ -263,8 +261,8 @@ static inline void dec_kn03_be_init(void) */ *mcr = (*mcr & ~(KN03_MCR_DIAGCHK | KN03_MCR_DIAGGEN)) | KN03_MCR_CORRECT; - if (current_cpu_data.cputype == CPU_R4400SC) - *mbcs |= KN05_MB_CSR_EE; + if (current_cpu_type() == CPU_R4400SC) + *mbcs |= KN4K_MB_CSR_EE; fast_iob(); } diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S index 3b379099321..41a2fa1fa12 100644 --- a/arch/mips/dec/int-handler.S +++ b/arch/mips/dec/int-handler.S @@ -1,10 +1,8 @@ /* - * arch/mips/dec/int-handler.S - * * Copyright (C) 1995, 1996, 1997 Paul M. Antoine and Harald Koerfgen - * Copyright (C) 2000, 2001, 2002, 2003 Maciej W. Rozycki + * Copyright (C) 2000, 2001, 2002, 2003, 2005 Maciej W. Rozycki * - * Written by Ralf Baechle and Andreas Busse, modified for DECStation + * Written by Ralf Baechle and Andreas Busse, modified for DECstation * support by Paul Antoine and Harald Koerfgen. * * completly rewritten: @@ -13,12 +11,12 @@ * Rewritten extensively for controller-driven IRQ support * by Maciej W. Rozycki. */ -#include <linux/config.h> + +#include <asm/addrspace.h> #include <asm/asm.h> -#include <asm/regdef.h> #include <asm/mipsregs.h> +#include <asm/regdef.h> #include <asm/stackframe.h> -#include <asm/addrspace.h> #include <asm/dec/interrupts.h> #include <asm/dec/ioasic_addrs.h> @@ -28,11 +26,14 @@ #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 /* - * decstation_handle_int: Interrupt handler for DECStations + * 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: @@ -48,84 +49,80 @@ * 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 + * 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 - * 7 FPU + * -------- ------ + * 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 + * -------- ------ + * 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 + * -------- ------ + * 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 + * -------- ------ + * 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 + * -------- ------ + * 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(decstation_handle_int, PT_SIZE, ra) - .set noat - SAVE_ALL - CLI # TEST: interrupts should be off - .set at + NESTED(plat_irq_dispatch, PT_SIZE, ra) .set noreorder /* @@ -133,7 +130,7 @@ */ mfc0 t0,CP0_CAUSE # get pending interrupts mfc0 t1,CP0_STATUS -#ifdef CONFIG_MIPS32 +#ifdef CONFIG_32BIT lw t2,cpu_fpu_mask #endif andi t0,ST0_IM # CAUSE.CE may be non-zero! @@ -141,7 +138,7 @@ beqz t0,spurious -#ifdef CONFIG_MIPS32 +#ifdef CONFIG_32BIT and t2,t0 bnez t2,fpu # handle FPU immediately #endif @@ -265,13 +262,10 @@ srlv t3,t1,t2 handle_it: - jal do_IRQ - move a1,sp - - j ret_from_irq + j dec_irq_dispatch nop -#ifdef CONFIG_MIPS32 +#ifdef CONFIG_32BIT fpu: j handle_fpe_int nop @@ -280,7 +274,7 @@ fpu: spurious: j spurious_interrupt nop - END(decstation_handle_int) + END(plat_irq_dispatch) /* * Generic unimplemented interrupt routines -- cpu_mask_nr_tbl diff --git a/arch/mips/dec/ioasic-irq.c b/arch/mips/dec/ioasic-irq.c index d5bca5d233b..e04d973ce5a 100644 --- a/arch/mips/dec/ioasic-irq.c +++ b/arch/mips/dec/ioasic-irq.c @@ -1,9 +1,7 @@ /* - * linux/arch/mips/dec/ioasic-irq.c - * * DEC I/O ASIC interrupts. * - * Copyright (c) 2002, 2003 Maciej W. Rozycki + * 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 @@ -13,124 +11,90 @@ #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 DEFINE_SPINLOCK(ioasic_lock); - static int ioasic_irq_base; - -static inline void unmask_ioasic_irq(unsigned int irq) +static void unmask_ioasic_irq(struct irq_data *d) { u32 simr; simr = ioasic_read(IO_REG_SIMR); - simr |= (1 << (irq - ioasic_irq_base)); + simr |= (1 << (d->irq - ioasic_irq_base)); ioasic_write(IO_REG_SIMR, simr); } -static inline void mask_ioasic_irq(unsigned int irq) +static void mask_ioasic_irq(struct irq_data *d) { u32 simr; simr = ioasic_read(IO_REG_SIMR); - simr &= ~(1 << (irq - ioasic_irq_base)); + simr &= ~(1 << (d->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) +static void ack_ioasic_irq(struct irq_data *d) { - spin_lock(&ioasic_lock); - mask_ioasic_irq(irq); - spin_unlock(&ioasic_lock); + mask_ioasic_irq(d); 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, +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, }; - -#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) +static void clear_ioasic_dma_irq(struct irq_data *d) { - clear_ioasic_irq(irq); + u32 sir; + + sir = ~(1 << (d->irq - ioasic_irq_base)); + ioasic_write(IO_REG_SIR, sir); 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, +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) { @@ -140,18 +104,13 @@ void __init init_ioasic_irqs(int base) 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; - } + 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; } diff --git a/arch/mips/dec/kn01-berr.c b/arch/mips/dec/kn01-berr.c new file mode 100644 index 00000000000..44d8a87a8a6 --- /dev/null +++ b/arch/mips/dec/kn01-berr.c @@ -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(); +} diff --git a/arch/mips/dec/kn02-irq.c b/arch/mips/dec/kn02-irq.c index e0bfcd1521e..37199f742c4 100644 --- a/arch/mips/dec/kn02-irq.c +++ b/arch/mips/dec/kn02-irq.c @@ -1,10 +1,8 @@ /* - * linux/arch/mips/dec/kn02-irq.c - * * DECstation 5000/200 (KN02) Control and Status Register * interrupts. * - * Copyright (c) 2002, 2003 Maciej W. Rozycki + * 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 @@ -14,7 +12,6 @@ #include <linux/init.h> #include <linux/irq.h> -#include <linux/spinlock.h> #include <linux/types.h> #include <asm/dec/kn02.h> @@ -29,99 +26,54 @@ * There is no default value -- it has to be initialized. */ u32 cached_kn02_csr; -DEFINE_SPINLOCK(kn02_lock); - static int kn02_irq_base; - -static inline void unmask_kn02_irq(unsigned int irq) +static void unmask_kn02_irq(struct irq_data *d) { - volatile u32 *csr = (volatile u32 *)KN02_CSR_BASE; + volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE + + KN02_CSR); - cached_kn02_csr |= (1 << (irq - kn02_irq_base + 16)); + cached_kn02_csr |= (1 << (d->irq - kn02_irq_base + 16)); *csr = cached_kn02_csr; } -static inline void mask_kn02_irq(unsigned int irq) +static void mask_kn02_irq(struct irq_data *d) { - volatile u32 *csr = (volatile u32 *)KN02_CSR_BASE; + volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE + + KN02_CSR); - cached_kn02_csr &= ~(1 << (irq - kn02_irq_base + 16)); + cached_kn02_csr &= ~(1 << (d->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) +static void ack_kn02_irq(struct irq_data *d) { - spin_lock(&kn02_lock); - mask_kn02_irq(irq); - spin_unlock(&kn02_lock); + mask_kn02_irq(d); 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, +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 *)KN02_CSR_BASE; - unsigned long flags; + volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE + + KN02_CSR); int i; /* Mask interrupts. */ - spin_lock_irqsave(&kn02_lock, flags); - cached_kn02_csr &= ~KN03_CSR_IOINTEN; + cached_kn02_csr &= ~KN02_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; - } + 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; } diff --git a/arch/mips/dec/kn02xa-berr.c b/arch/mips/dec/kn02xa-berr.c new file mode 100644 index 00000000000..ec606363b80 --- /dev/null +++ b/arch/mips/dec/kn02xa-berr.c @@ -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(); +} diff --git a/arch/mips/dec/platform.c b/arch/mips/dec/platform.c new file mode 100644 index 00000000000..c7ac86af847 --- /dev/null +++ b/arch/mips/dec/platform.c @@ -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); diff --git a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile index 373822ec2d8..ae73e42ac20 100644 --- a/arch/mips/dec/prom/Makefile +++ b/arch/mips/dec/prom/Makefile @@ -5,7 +5,4 @@ lib-y += init.o memory.o cmdline.o identify.o console.o -lib-$(CONFIG_MIPS32) += locore.o -lib-$(CONFIG_MIPS64) += call_o32.o - -EXTRA_AFLAGS := $(CFLAGS) +lib-$(CONFIG_32BIT) += locore.o diff --git a/arch/mips/dec/prom/call_o32.S b/arch/mips/dec/prom/call_o32.S deleted file mode 100644 index 0dd56db9b3d..00000000000 --- a/arch/mips/dec/prom/call_o32.S +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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) diff --git a/arch/mips/dec/prom/console.c b/arch/mips/dec/prom/console.c index cade16ec7e5..caa6e047caf 100644 --- a/arch/mips/dec/prom/console.c +++ b/arch/mips/dec/prom/console.c @@ -1,9 +1,7 @@ /* - * arch/mips/dec/prom/console.c - * * DECstation PROM-based early console support. * - * Copyright (C) 2004 Maciej W. Rozycki + * 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 @@ -13,43 +11,35 @@ #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) { - static char sfmt[] __initdata = "%%%us"; - char fmt[13]; - - snprintf(fmt, sizeof(fmt), sfmt, c); - prom_printf(fmt, s); + 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_PRINTBUFFER, + .flags = CON_BOOT | CON_PRINTBUFFER, .index = -1, }; -static int promcons_output __initdata = 0; - void __init register_prom_console(void) { - if (!promcons_output) { - promcons_output = 1; - register_console(&promcons); - } -} - -void __init unregister_prom_console(void) -{ - if (promcons_output) { - unregister_console(&promcons); - promcons_output = 0; - } + register_console(&promcons); } - -void disable_early_printk(void) - __attribute__((alias("unregister_prom_console"))); diff --git a/arch/mips/dec/prom/dectypes.h b/arch/mips/dec/prom/dectypes.h index 707b6f1f5a9..69ea5b9c819 100644 --- a/arch/mips/dec/prom/dectypes.h +++ b/arch/mips/dec/prom/dectypes.h @@ -1,5 +1,5 @@ #ifndef DECTYPES -#define DECTYPES +#define DECTYPES #define DS2100_3100 1 /* DS2100/3100 Pmax */ #define DS5000_200 2 /* DS5000/200 3max */ diff --git a/arch/mips/dec/prom/identify.c b/arch/mips/dec/prom/identify.c index 9380588cb15..95e26f4bb38 100644 --- a/arch/mips/dec/prom/identify.c +++ b/arch/mips/dec/prom/identify.c @@ -2,7 +2,7 @@ * identify.c: machine identification code. * * Copyright (C) 1998 Harald Koerfgen and Paul M. Antoine - * Copyright (C) 2002, 2003, 2004 Maciej W. Rozycki + * Copyright (C) 2002, 2003, 2004, 2005 Maciej W. Rozycki */ #include <linux/init.h> #include <linux/kernel.h> @@ -12,6 +12,7 @@ #include <linux/types.h> #include <asm/bootinfo.h> + #include <asm/dec/ioasic.h> #include <asm/dec/ioasic_addrs.h> #include <asm/dec/kn01.h> @@ -21,12 +22,10 @@ #include <asm/dec/kn03.h> #include <asm/dec/kn230.h> #include <asm/dec/prom.h> +#include <asm/dec/system.h> #include "dectypes.h" -extern unsigned long mips_machgroup; -extern unsigned long mips_machtype; - static const char *dec_system_strings[] = { [MACH_DSUNKNOWN] "unknown DECstation", [MACH_DS23100] "DECstation 2100/3100", @@ -68,34 +67,47 @@ EXPORT_SYMBOL(dec_rtc_base); static inline void prom_init_kn01(void) { - dec_rtc_base = (void *)KN01_RTC_BASE; + 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_rtc_base = (void *)KN01_RTC_BASE; + 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_rtc_base = (void *)KN02_RTC_BASE; + 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) { - ioasic_base = (void *)KN02XA_IOASIC_BASE; - dec_rtc_base = (void *)KN02XA_RTC_BASE; + 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) { - ioasic_base = (void *)KN03_IOASIC_BASE; - dec_rtc_base = (void *)KN03_RTC_BASE; + 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); } @@ -121,9 +133,6 @@ void __init prom_identify_arch(u32 magic) dec_firmrev = (dec_sysid & 0xff00) >> 8; dec_etc = dec_sysid & 0xff; - /* We're obviously one of the DEC machines */ - mips_machgroup = MACH_GROUP_DEC; - /* * FIXME: This may not be an exhaustive list of DECStations/Servers! * Put all model-specific initialisation calls here. diff --git a/arch/mips/dec/prom/init.c b/arch/mips/dec/prom/init.c index 60f74256e68..4e1761e0a09 100644 --- a/arch/mips/dec/prom/init.c +++ b/arch/mips/dec/prom/init.c @@ -4,14 +4,16 @@ * Copyright (C) 1998 Harald Koerfgen * Copyright (C) 2002, 2004 Maciej W. Rozycki */ -#include <linux/config.h> #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> @@ -88,14 +90,10 @@ 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"; - static char r3k_msg[] __initdata = - "Please recompile with \"CONFIG_CPU_R3000 = y\".\n"; - static char r4k_msg[] __initdata = - "Please recompile with \"CONFIG_CPU_R4x00 = y\".\n"; s32 argc = fw_arg0; - s32 argv = fw_arg1; + s32 *argv = (void *)fw_arg1; u32 magic = fw_arg2; - s32 prom_vec = fw_arg3; + s32 *prom_vec = (void *)fw_arg3; /* * Determine which PROM we have @@ -111,8 +109,10 @@ void __init prom_init(void) /* Were we compiled with the right CPU option? */ #if defined(CONFIG_CPU_R3000) - if ((current_cpu_data.cputype == CPU_R4000SC) || - (current_cpu_data.cputype == CPU_R4400SC)) { + 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(); @@ -120,8 +120,10 @@ void __init prom_init(void) #endif #if defined(CONFIG_CPU_R4X00) - if ((current_cpu_data.cputype == CPU_R3000) || - (current_cpu_data.cputype == CPU_R3000A)) { + 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(); diff --git a/arch/mips/dec/prom/locore.S b/arch/mips/dec/prom/locore.S index d9acdcefee8..f72b5741025 100644 --- a/arch/mips/dec/prom/locore.S +++ b/arch/mips/dec/prom/locore.S @@ -27,4 +27,3 @@ NESTED(genexcept_early, 0, sp) jr k0 rfe END(genexcept_early) - diff --git a/arch/mips/dec/prom/memory.c b/arch/mips/dec/prom/memory.c index e4f6f26425e..8c62316f22f 100644 --- a/arch/mips/dec/prom/memory.c +++ b/arch/mips/dec/prom/memory.c @@ -4,7 +4,6 @@ * Copyright (C) 1998 Harald Koerfgen, Frieder Streffer and Paul M. Antoine * Copyright (C) 2000, 2002 Maciej W. Rozycki */ -#include <linux/config.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/mm.h> @@ -19,7 +18,7 @@ #include <asm/sections.h> -volatile unsigned long mem_err = 0; /* So we know an error occurred */ +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 @@ -35,22 +34,22 @@ static inline void pmax_setup_memory_region(void) extern char genexcept_early; /* Install exception handler */ - memcpy(&old_handler, (void *)(KSEG0 + 0x80), 0x80); - memcpy((void *)(KSEG0 + 0x80), &genexcept_early, 0x80); + 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 *) KSEG1 + CHUNK_SIZE; - (mem_err== 0) && (memory_page < ((unsigned char *) KSEG1+0x1E000000)); - memory_page += CHUNK_SIZE) { + 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 *)(KSEG0 + 0x80), &old_handler, 0x80); + memcpy((void *)(CKSEG0 + 0x80), &old_handler, 0x80); - add_memory_region(0, (unsigned long)memory_page - KSEG1 - CHUNK_SIZE, + add_memory_region(0, (unsigned long)memory_page - CKSEG1 - CHUNK_SIZE, BOOT_MEM_RAM); } @@ -65,7 +64,7 @@ static inline void rex_setup_memory_region(void) memmap *bm; /* some free 64k */ - bm = (memmap *)KSEG0ADDR(0x28000); + bm = (memmap *)CKSEG0ADDR(0x28000); bitmap_size = rex_getbitmap(bm); @@ -93,16 +92,16 @@ void __init prom_meminit(u32 magic) rex_setup_memory_region(); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - unsigned long addr, end; + unsigned long end; /* * Free everything below the kernel itself but leave * the first page reserved for the exception handlers. */ -#if defined(CONFIG_DECLANCE) || defined(CONFIG_DECLANCE_MODULE) +#if IS_ENABLED(CONFIG_DECLANCE) /* * Leave 128 KB reserved for Lance memory for * IOASIC DECstations. @@ -115,16 +114,5 @@ unsigned long __init prom_free_prom_memory(void) #endif end = __pa(&_text); - addr = PAGE_SIZE; - while (addr < end) { - ClearPageReserved(virt_to_page(__va(addr))); - set_page_count(virt_to_page(__va(addr)), 1); - free_page((unsigned long)__va(addr)); - addr += PAGE_SIZE; - } - - printk("Freeing unused PROM memory: %ldk freed\n", - (end - PAGE_SIZE) >> 10); - - return end - PAGE_SIZE; + free_init_pages("unused PROM memory", PAGE_SIZE, end); } diff --git a/arch/mips/dec/promcon.c b/arch/mips/dec/promcon.c deleted file mode 100644 index 9f0972f5a70..00000000000 --- a/arch/mips/dec/promcon.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Wrap-around code for a console using the - * DECstation PROM io-routines. - * - * Copyright (c) 1998 Harald Koerfgen - */ - -#include <linux/tty.h> -#include <linux/ptrace.h> -#include <linux/init.h> -#include <linux/console.h> -#include <linux/fs.h> - -#include <asm/dec/prom.h> - -static void prom_console_write(struct console *co, const char *s, - unsigned count) -{ - unsigned i; - - /* - * Now, do each character - */ - for (i = 0; i < count; i++) { - if (*s == 10) - prom_printf("%c", 13); - prom_printf("%c", *s++); - } -} - -static int __init prom_console_setup(struct console *co, char *options) -{ - return 0; -} - -static struct console sercons = -{ - .name = "ttyS", - .write = prom_console_write, - .setup = prom_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -/* - * Register console. - */ - -static int __init prom_console_init(void) -{ - register_console(&sercons); - - return 0; -} -console_initcall(prom_console_init); diff --git a/arch/mips/dec/reset.c b/arch/mips/dec/reset.c index 7e4d34d0573..c15a879046e 100644 --- a/arch/mips/dec/reset.c +++ b/arch/mips/dec/reset.c @@ -8,34 +8,33 @@ #include <linux/linkage.h> #include <asm/addrspace.h> -#include <asm/ptrace.h> -typedef void ATTRIB_NORET (* noret_func_t)(void); +typedef void __noreturn (* noret_func_t)(void); -static inline void ATTRIB_NORET back_to_prom(void) +static inline void __noreturn back_to_prom(void) { - noret_func_t func = (void *) KSEG1ADDR(0x1fc00000); + noret_func_t func = (void *)CKSEG1ADDR(0x1fc00000); func(); } -void ATTRIB_NORET dec_machine_restart(char *command) +void __noreturn dec_machine_restart(char *command) { back_to_prom(); } -void ATTRIB_NORET dec_machine_halt(void) +void __noreturn dec_machine_halt(void) { back_to_prom(); } -void ATTRIB_NORET dec_machine_power_off(void) +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, struct pt_regs *regs) +irqreturn_t dec_intr_halt(int irq, void *dev_id) { dec_machine_halt(); } diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c index 6a69309baf4..41bbffd9cc0 100644 --- a/arch/mips/dec/setup.c +++ b/arch/mips/dec/setup.c @@ -1,25 +1,29 @@ /* - * Setup the interrupt stuff. + * 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 Maciej W. Rozycki + * Copyright (C) 2000, 2001, 2002, 2003, 2005 Maciej W. Rozycki */ -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/param.h> #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> @@ -38,24 +42,31 @@ #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, struct pt_regs *regs); +extern irqreturn_t dec_intr_halt(int irq, void *dev_id); -extern asmlinkage void decstation_handle_int(void); +unsigned long dec_kn_slot_base, dec_kn_slot_size; -spinlock_t ioasic_ssr_lock; +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; -unsigned long dec_kn_slot_size; + +EXPORT_SYMBOL(ioasic_base); /* * IRQ routing and priority tables. Priorites are set as follows: * - * KN01 KN230 KN02 KN02-BA KN02-CA KN03 + * KN01 KN230 KN02 KN02-BA KN02-CA KN03 * * MEMORY CPU CPU CPU ASIC CPU CPU * RTC CPU CPU CPU ASIC CPU CPU @@ -77,6 +88,9 @@ unsigned long dec_kn_slot_size; 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 } }, }; @@ -88,31 +102,43 @@ 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 = { - .flags = SA_INTERRUPT, .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. */ -void __init dec_be_init(void) +static void __init dec_be_init(void) { switch (mips_machtype) { case MACH_DS23100: /* DS2100/DS3100 Pmin/Pmax */ - busirq.flags |= SA_SHIRQ; + 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+ */ @@ -124,24 +150,19 @@ void __init dec_be_init(void) } } - -extern void dec_time_init(void); -extern void dec_timer_setup(struct irqaction *); - -static void __init decstation_setup(void) +void __init plat_mem_setup(void) { board_be_init = dec_be_init; - board_time_init = dec_time_init; - board_timer_setup = dec_timer_setup; wbflush_setup(); _machine_restart = dec_machine_restart; _machine_halt = dec_machine_halt; - _machine_power_off = dec_machine_power_off; -} + pm_power_off = dec_machine_power_off; -early_initcall(decstation_setup); + ioport_resource.start = ~0UL; + ioport_resource.end = 0UL; +} /* * Machine-specific initialisation for KN01, aka DS2100 (aka Pmin) @@ -206,7 +227,7 @@ static int_ptr kn01_cpu_mask_nr_tbl[][2] __initdata = { { .p = cpu_all_int } }, }; -void __init dec_init_kn01(void) +static void __init dec_init_kn01(void) { /* IRQ routing. */ memcpy(&dec_interrupt, &kn01_interrupt, @@ -216,7 +237,7 @@ void __init dec_init_kn01(void) memcpy(&cpu_mask_nr_tbl, &kn01_cpu_mask_nr_tbl, sizeof(kn01_cpu_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); } /* dec_init_kn01 */ @@ -281,7 +302,7 @@ static int_ptr kn230_cpu_mask_nr_tbl[][2] __initdata = { { .p = cpu_all_int } }, }; -void __init dec_init_kn230(void) +static void __init dec_init_kn230(void) { /* IRQ routing. */ memcpy(&dec_interrupt, &kn230_interrupt, @@ -291,7 +312,7 @@ void __init dec_init_kn230(void) memcpy(&cpu_mask_nr_tbl, &kn230_cpu_mask_nr_tbl, sizeof(kn230_cpu_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); } /* dec_init_kn230 */ @@ -371,7 +392,7 @@ static int_ptr kn02_asic_mask_nr_tbl[][2] __initdata = { { .p = kn02_all_int } }, }; -void __init dec_init_kn02(void) +static void __init dec_init_kn02(void) { /* IRQ routing. */ memcpy(&dec_interrupt, &kn02_interrupt, @@ -385,7 +406,7 @@ void __init dec_init_kn02(void) memcpy(&asic_mask_nr_tbl, &kn02_asic_mask_nr_tbl, sizeof(kn02_asic_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); init_kn02_irqs(KN02_IRQ_BASE); } /* dec_init_kn02 */ @@ -472,7 +493,7 @@ static int_ptr kn02ba_asic_mask_nr_tbl[][2] __initdata = { { .p = asic_all_int } }, }; -void __init dec_init_kn02ba(void) +static void __init dec_init_kn02ba(void) { /* IRQ routing. */ memcpy(&dec_interrupt, &kn02ba_interrupt, @@ -486,7 +507,7 @@ void __init dec_init_kn02ba(void) memcpy(&asic_mask_nr_tbl, &kn02ba_asic_mask_nr_tbl, sizeof(kn02ba_asic_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); init_ioasic_irqs(IO_IRQ_BASE); } /* dec_init_kn02ba */ @@ -569,7 +590,7 @@ static int_ptr kn02ca_asic_mask_nr_tbl[][2] __initdata = { { .p = asic_all_int } }, }; -void __init dec_init_kn02ca(void) +static void __init dec_init_kn02ca(void) { /* IRQ routing. */ memcpy(&dec_interrupt, &kn02ca_interrupt, @@ -583,7 +604,7 @@ void __init dec_init_kn02ca(void) memcpy(&asic_mask_nr_tbl, &kn02ca_asic_mask_nr_tbl, sizeof(kn02ca_asic_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); init_ioasic_irqs(IO_IRQ_BASE); } /* dec_init_kn02ca */ @@ -670,7 +691,7 @@ static int_ptr kn03_asic_mask_nr_tbl[][2] __initdata = { { .p = asic_all_int } }, }; -void __init dec_init_kn03(void) +static void __init dec_init_kn03(void) { /* IRQ routing. */ memcpy(&dec_interrupt, &kn03_interrupt, @@ -684,7 +705,7 @@ void __init dec_init_kn03(void) memcpy(&asic_mask_nr_tbl, &kn03_asic_mask_nr_tbl, sizeof(kn03_asic_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); init_ioasic_irqs(IO_IRQ_BASE); } /* dec_init_kn03 */ @@ -722,13 +743,16 @@ void __init arch_init_irq(void) panic("Don't know how to set this up!"); break; } - set_except_vector(0, decstation_handle_int); /* 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) @@ -745,6 +769,8 @@ void __init arch_init_irq(void) setup_irq(dec_interrupt[DEC_IRQ_HALT], &haltirq); } -EXPORT_SYMBOL(ioasic_base); -EXPORT_SYMBOL(dec_kn_slot_size); -EXPORT_SYMBOL(dec_interrupt); +asmlinkage unsigned int dec_irq_dispatch(unsigned int irq) +{ + do_IRQ(irq); + return 0; +} diff --git a/arch/mips/dec/tc.c b/arch/mips/dec/tc.c new file mode 100644 index 00000000000..732027c7983 --- /dev/null +++ b/arch/mips/dec/tc.c @@ -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; + } +} diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c index dc7091caa7a..1914e56f0d9 100644 --- a/arch/mips/dec/time.c +++ b/arch/mips/dec/time.c @@ -1,6 +1,4 @@ /* - * linux/arch/mips/dec/time.c - * * Copyright (C) 1991, 1992, 1995 Linus Torvalds * Copyright (C) 2000, 2003 Maciej W. Rozycki * @@ -9,52 +7,24 @@ * */ #include <linux/bcd.h> -#include <linux/errno.h> #include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> #include <linux/mc146818rtc.h> -#include <linux/mm.h> -#include <linux/module.h> #include <linux/param.h> -#include <linux/sched.h> -#include <linux/string.h> -#include <linux/time.h> -#include <linux/types.h> - -#include <asm/bootinfo.h> -#include <asm/cpu.h> -#include <asm/div64.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/mipsregs.h> -#include <asm/sections.h> -#include <asm/time.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/ioasic_addrs.h> #include <asm/dec/machtype.h> - -static unsigned long dec_rtc_get_time(void) +void read_persistent_clock(struct timespec *ts) { unsigned int year, mon, day, hour, min, sec, real_year; - int i; + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); - /* The Linux interpretation of the DS1287 clock register contents: - * When the Update-In-Progress (UIP) flag goes from 1 to 0, the - * RTC registers show the second which has precisely just started. - * Let's hope other operating systems interpret the RTC the same way. - */ - /* read RTC exactly on falling edge of update flag */ - for (i = 0; i < 1000000; i++) /* may take up to 1 second... */ - if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) - break; - for (i = 0; i < 1000000; i++) /* must try at least 2.228 ms */ - if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) - break; - /* Isn't this overkill? UIP above should guarantee consistency */ do { sec = CMOS_READ(RTC_SECONDS); min = CMOS_READ(RTC_MINUTES); @@ -62,39 +32,46 @@ static unsigned long dec_rtc_get_time(void) 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); + 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. - * Therefore we store the real year separately, in one - * of unused BBU RAM locations. - */ - real_year = CMOS_READ(RTC_DEC_YEAR); + year += real_year - 72 + 2000; - return mktime(year, mon, day, hour, min, sec); + ts->tv_sec = mktime(year, mon, day, hour, min, sec); + ts->tv_nsec = 0; } /* - * In order to set the CMOS clock precisely, dec_rtc_set_mmss has to + * 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. */ -static int dec_rtc_set_mmss(unsigned long nowtime) +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); @@ -105,7 +82,7 @@ static int dec_rtc_set_mmss(unsigned long nowtime) cmos_minutes = CMOS_READ(RTC_MINUTES); if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - cmos_minutes = BCD2BIN(cmos_minutes); + cmos_minutes = bcd2bin(cmos_minutes); /* * since we're only adjusting minutes and seconds, @@ -121,13 +98,13 @@ static int dec_rtc_set_mmss(unsigned long nowtime) 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); + real_seconds = bin2bcd(real_seconds); + real_minutes = bin2bcd(real_minutes); } CMOS_WRITE(real_seconds, RTC_SECONDS); CMOS_WRITE(real_minutes, RTC_MINUTES); } else { - printk(KERN_WARNING + printk_once(KERN_NOTICE "set_rtc_mmss: can't update from %d to %d\n", cmos_minutes, real_minutes); retval = -1; @@ -141,60 +118,54 @@ static int dec_rtc_set_mmss(unsigned long nowtime) */ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock(&rtc_lock); return retval; } - -static int dec_timer_state(void) -{ - return (CMOS_READ(RTC_REG_C) & RTC_PF) != 0; -} - -static void dec_timer_ack(void) -{ - CMOS_READ(RTC_REG_C); /* Ack the RTC interrupt. */ -} - -static unsigned int dec_ioasic_hpt_read(void) +void __init plat_time_init(void) { - /* - * The free-running counter is 32-bit which is good for about - * 2 minutes, 50 seconds at possible count rates of up to 25MHz. - */ - return ioasic_read(IO_REG_FCTR); -} - -static void dec_ioasic_hpt_init(unsigned int count) -{ - ioasic_write(IO_REG_FCTR, ioasic_read(IO_REG_FCTR) - count); -} - - -void __init dec_time_init(void) -{ - rtc_get_time = dec_rtc_get_time; - rtc_set_mmss = dec_rtc_set_mmss; - - mips_timer_state = dec_timer_state; - mips_timer_ack = dec_timer_ack; - - if (!cpu_has_counter && IOASIC) { - /* For pre-R4k systems we use the I/O ASIC's counter. */ - mips_hpt_read = dec_ioasic_hpt_read; - mips_hpt_init = dec_ioasic_hpt_init; + 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; + } } - /* Set up the rate of periodic DS1287 interrupts. */ - CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - LOG_2_HZ), RTC_REG_A); -} - -EXPORT_SYMBOL(do_settimeofday); - -void __init dec_timer_setup(struct irqaction *irq) -{ - setup_irq(dec_interrupt[DEC_IRQ_RTC], irq); - - /* Enable periodic DS1287 interrupts. */ - CMOS_WRITE(CMOS_READ(RTC_REG_B) | RTC_PIE, RTC_REG_B); + ds1287_clockevent_init(dec_interrupt[DEC_IRQ_RTC]); } diff --git a/arch/mips/dec/wbflush.c b/arch/mips/dec/wbflush.c index 925c0525344..56bda4a396b 100644 --- a/arch/mips/dec/wbflush.c +++ b/arch/mips/dec/wbflush.c @@ -2,9 +2,9 @@ * 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" :-) + * 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 @@ -17,8 +17,8 @@ #include <linux/init.h> #include <asm/bootinfo.h> -#include <asm/system.h> #include <asm/wbflush.h> +#include <asm/barrier.h> static void wbflush_kn01(void); static void wbflush_kn210(void); |
