diff options
Diffstat (limited to 'arch/mips/mips-boards/generic')
-rw-r--r-- | arch/mips/mips-boards/generic/init.c | 91 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/memory.c | 29 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/mipsIRQ.S | 110 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/pci.c | 167 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/time.c | 88 |
5 files changed, 345 insertions, 140 deletions
diff --git a/arch/mips/mips-boards/generic/init.c b/arch/mips/mips-boards/generic/init.c index 311155d1d3e..eab5a705e98 100644 --- a/arch/mips/mips-boards/generic/init.c +++ b/arch/mips/mips-boards/generic/init.c @@ -1,6 +1,8 @@ /* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 1999, 2000, 2004, 2005 MIPS Technologies, Inc. + * All rights reserved. + * Authors: Carsten Langgaard <carstenl@mips.com> + * Maciej W. Rozycki <macro@mips.com> * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as @@ -22,18 +24,19 @@ #include <linux/string.h> #include <linux/kernel.h> -#include <asm/io.h> #include <asm/bootinfo.h> +#include <asm/gt64120.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/cacheflush.h> +#include <asm/traps.h> + #include <asm/mips-boards/prom.h> #include <asm/mips-boards/generic.h> -#ifdef CONFIG_MIPS_GT64120 -#include <asm/gt64120.h> -#endif -#include <asm/mips-boards/msc01_pci.h> #include <asm/mips-boards/bonito64.h> -#ifdef CONFIG_MIPS_MALTA +#include <asm/mips-boards/msc01_pci.h> + #include <asm/mips-boards/malta.h> -#endif #ifdef CONFIG_KGDB extern int rs_kgdb_hook(int, int); @@ -223,8 +226,34 @@ void __init kgdb_config (void) } #endif +void __init mips_nmi_setup (void) +{ + void *base; + extern char except_vec_nmi; + + base = cpu_has_veic ? + (void *)(CAC_BASE + 0xa80) : + (void *)(CAC_BASE + 0x380); + memcpy(base, &except_vec_nmi, 0x80); + flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); +} + +void __init mips_ejtag_setup (void) +{ + void *base; + extern char except_vec_ejtag_debug; + + base = cpu_has_veic ? + (void *)(CAC_BASE + 0xa00) : + (void *)(CAC_BASE + 0x300); + memcpy(base, &except_vec_ejtag_debug, 0x80); + flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); +} + void __init prom_init(void) { + u32 start, map, mask, data; + prom_argc = fw_arg0; _prom_argv = (int *) fw_arg1; _prom_envp = (int *) fw_arg2; @@ -266,12 +295,15 @@ void __init prom_init(void) #else GT_WRITE(GT_PCI0_CMD_OFS, 0); #endif + /* Fix up PCI I/O mapping if necessary (for Atlas). */ + start = GT_READ(GT_PCI0IOLD_OFS); + map = GT_READ(GT_PCI0IOREMAP_OFS); + if ((start & map) != 0) { + map &= ~start; + GT_WRITE(GT_PCI0IOREMAP_OFS, map); + } -#ifdef CONFIG_MIPS_MALTA set_io_port_base(MALTA_GT_PORT_BASE); -#else - set_io_port_base((unsigned long)ioremap(0, 0x20000000)); -#endif break; case MIPS_REVISION_CORID_CORE_EMUL_BON: @@ -300,18 +332,21 @@ void __init prom_init(void) BONITO_BONGENCFG_BYTESWAP; #endif -#ifdef CONFIG_MIPS_MALTA set_io_port_base(MALTA_BONITO_PORT_BASE); -#else - set_io_port_base((unsigned long)ioremap(0, 0x20000000)); -#endif break; case MIPS_REVISION_CORID_CORE_MSC: case MIPS_REVISION_CORID_CORE_FPGA2: + case MIPS_REVISION_CORID_CORE_FPGA3: case MIPS_REVISION_CORID_CORE_EMUL_MSC: _pcictrl_msc = (unsigned long)ioremap(MIPS_MSC01_PCI_REG_BASE, 0x2000); + mb(); + MSC_READ(MSC01_PCI_CFG, data); + MSC_WRITE(MSC01_PCI_CFG, data & ~MSC01_PCI_CFG_EN_BIT); + wmb(); + + /* Fix up lane swapping. */ #ifdef CONFIG_CPU_LITTLE_ENDIAN MSC_WRITE(MSC01_PCI_SWAP, MSC01_PCI_SWAP_NOSWAP); #else @@ -320,12 +355,23 @@ void __init prom_init(void) MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_MEM_SHF | MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_BAR0_SHF); #endif + /* Fix up target memory mapping. */ + MSC_READ(MSC01_PCI_BAR0, mask); + MSC_WRITE(MSC01_PCI_P2SCMSKL, mask & MSC01_PCI_BAR0_SIZE_MSK); + + /* Don't handle target retries indefinitely. */ + if ((data & MSC01_PCI_CFG_MAXRTRY_MSK) == + MSC01_PCI_CFG_MAXRTRY_MSK) + data = (data & ~(MSC01_PCI_CFG_MAXRTRY_MSK << + MSC01_PCI_CFG_MAXRTRY_SHF)) | + ((MSC01_PCI_CFG_MAXRTRY_MSK - 1) << + MSC01_PCI_CFG_MAXRTRY_SHF); + + wmb(); + MSC_WRITE(MSC01_PCI_CFG, data); + mb(); -#ifdef CONFIG_MIPS_MALTA set_io_port_base(MALTA_MSC_PORT_BASE); -#else - set_io_port_base((unsigned long)ioremap(0, 0x20000000)); -#endif break; default: @@ -334,6 +380,9 @@ void __init prom_init(void) while(1); /* We die here... */ } #endif + board_nmi_handler_setup = mips_nmi_setup; + board_ejtag_handler_setup = mips_ejtag_setup; + prom_printf("\nLINUX started...\n"); prom_init_cmdline(); prom_meminit(); diff --git a/arch/mips/mips-boards/generic/memory.c b/arch/mips/mips-boards/generic/memory.c index 5ae2b43e4c2..2c8afd77a20 100644 --- a/arch/mips/mips-boards/generic/memory.c +++ b/arch/mips/mips-boards/generic/memory.c @@ -22,6 +22,7 @@ #include <linux/init.h> #include <linux/mm.h> #include <linux/bootmem.h> +#include <linux/string.h> #include <asm/bootinfo.h> #include <asm/page.h> @@ -55,18 +56,30 @@ struct prom_pmemblock * __init prom_getmdesc(void) { char *memsize_str; unsigned int memsize; + char cmdline[CL_SIZE], *ptr; - memsize_str = prom_getenv("memsize"); - if (!memsize_str) { - prom_printf("memsize not set in boot prom, set to default (32Mb)\n"); - memsize = 0x02000000; - } else { + /* Check the command line first for a memsize directive */ + strcpy(cmdline, arcs_cmdline); + ptr = strstr(cmdline, "memsize="); + if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' ')) + ptr = strstr(ptr, " memsize="); + + if (ptr) { + memsize = memparse(ptr + 8, &ptr); + } + else { + /* otherwise look in the environment */ + memsize_str = prom_getenv("memsize"); + if (!memsize_str) { + prom_printf("memsize not set in boot prom, set to default (32Mb)\n"); + memsize = 0x02000000; + } else { #ifdef DEBUG - prom_printf("prom_memsize = %s\n", memsize_str); + prom_printf("prom_memsize = %s\n", memsize_str); #endif - memsize = simple_strtol(memsize_str, NULL, 0); + memsize = simple_strtol(memsize_str, NULL, 0); + } } - memset(mdesc, 0, sizeof(mdesc)); mdesc[0].type = yamon_dontuse; diff --git a/arch/mips/mips-boards/generic/mipsIRQ.S b/arch/mips/mips-boards/generic/mipsIRQ.S index 131f49bccb2..a397ecb872d 100644 --- a/arch/mips/mips-boards/generic/mipsIRQ.S +++ b/arch/mips/mips-boards/generic/mipsIRQ.S @@ -29,6 +29,20 @@ #include <asm/regdef.h> #include <asm/stackframe.h> +#ifdef CONFIG_MIPS_ATLAS +#include <asm/mips-boards/atlasint.h> +#define CASCADE_IRQ MIPSCPU_INT_ATLAS +#define CASCADE_DISPATCH atlas_hw0_irqdispatch +#endif +#ifdef CONFIG_MIPS_MALTA +#include <asm/mips-boards/maltaint.h> +#define CASCADE_IRQ MIPSCPU_INT_I8259A +#define CASCADE_DISPATCH malta_hw0_irqdispatch +#endif +#ifdef CONFIG_MIPS_SEAD +#include <asm/mips-boards/seadint.h> +#endif + /* A lot of complication here is taken away because: * * 1) We handle one interrupt and return, sitting in a loop and moving across @@ -80,74 +94,62 @@ mfc0 s0, CP0_CAUSE # get irq bits mfc0 s1, CP0_STATUS # get irq mask + andi s0, ST0_IM # CAUSE.CE may be non-zero! and s0, s1 - /* First we check for r4k counter/timer IRQ. */ - andi a0, s0, CAUSEF_IP7 - beq a0, zero, 1f - andi a0, s0, CAUSEF_IP2 # delay slot, check hw0 interrupt +#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) + .set mips32 + clz a0, s0 + .set mips0 + negu a0 + addu a0, 31-CAUSEB_IP + bltz a0, spurious +#else + beqz s0, spurious + li a0, 7 - /* Wheee, a timer interrupt. */ - move a0, sp - jal mips_timer_interrupt - nop + and t0, s0, 0xf000 + sltiu t0, t0, 1 + sll t0, 2 + subu a0, t0 + sll s0, t0 - j ret_from_irq - nop + and t0, s0, 0xc000 + sltiu t0, t0, 1 + sll t0, 1 + subu a0, t0 + sll s0, t0 -1: -#if defined(CONFIG_MIPS_SEAD) - beq a0, zero, 1f - andi a0, s0, CAUSEF_IP3 # delay slot, check hw1 interrupt -#else - beq a0, zero, 1f # delay slot, check hw3 interrupt - andi a0, s0, CAUSEF_IP5 + and t0, s0, 0x8000 + sltiu t0, t0, 1 + # sll t0, 0 + subu a0, t0 + # sll s0, t0 #endif - /* Wheee, combined hardware level zero interrupt. */ -#if defined(CONFIG_MIPS_ATLAS) - jal atlas_hw0_irqdispatch -#elif defined(CONFIG_MIPS_MALTA) - jal malta_hw0_irqdispatch -#elif defined(CONFIG_MIPS_SEAD) - jal sead_hw0_irqdispatch -#else -#error "MIPS board not supported\n" -#endif - move a0, sp # delay slot +#ifdef CASCADE_IRQ + li a1, CASCADE_IRQ + bne a0, a1, 1f + addu a0, MIPSCPU_INT_BASE - j ret_from_irq - nop # delay slot + jal CASCADE_DISPATCH + move a0, sp -1: -#if defined(CONFIG_MIPS_SEAD) - beq a0, zero, 1f - andi a0, s0, CAUSEF_IP5 # delay slot, check hw3 interrupt - jal sead_hw1_irqdispatch - move a0, sp # delay slot - j ret_from_irq - nop # delay slot -1: -#endif -#if defined(CONFIG_MIPS_MALTA) - beq a0, zero, 1f # check hw3 (coreHI) interrupt - nop - jal corehi_irqdispatch - move a0, sp j ret_from_irq nop 1: +#else + addu a0, MIPSCPU_INT_BASE #endif - /* - * Here by mistake? This is possible, what can happen is that by the - * time we take the exception the IRQ pin goes low, so just leave if - * this is the case. - */ - move a1,s0 - PRINT("Got interrupt: c0_cause = %08x\n") - mfc0 a1, CP0_EPC - PRINT("c0_epc = %08x\n") + + jal do_IRQ + move a1, sp j ret_from_irq nop + + +spurious: + j spurious_interrupt + nop END(mipsIRQ) diff --git a/arch/mips/mips-boards/generic/pci.c b/arch/mips/mips-boards/generic/pci.c index 92c34bda02a..1f6f9df74ab 100644 --- a/arch/mips/mips-boards/generic/pci.c +++ b/arch/mips/mips-boards/generic/pci.c @@ -1,6 +1,8 @@ /* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 1999, 2000, 2004, 2005 MIPS Technologies, Inc. + * All rights reserved. + * Authors: Carsten Langgaard <carstenl@mips.com> + * Maciej W. Rozycki <macro@mips.com> * * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) * @@ -19,65 +21,46 @@ * * MIPS boards specific PCI support. */ -#include <linux/config.h> #include <linux/types.h> #include <linux/pci.h> #include <linux/kernel.h> #include <linux/init.h> -#include <asm/mips-boards/generic.h> #include <asm/gt64120.h> + +#include <asm/mips-boards/generic.h> #include <asm/mips-boards/bonito64.h> #include <asm/mips-boards/msc01_pci.h> -#ifdef CONFIG_MIPS_MALTA -#include <asm/mips-boards/malta.h> -#endif static struct resource bonito64_mem_resource = { .name = "Bonito PCI MEM", - .start = 0x10000000UL, - .end = 0x1bffffffUL, .flags = IORESOURCE_MEM, }; static struct resource bonito64_io_resource = { - .name = "Bonito IO MEM", - .start = 0x00002000UL, /* avoid conflicts with YAMON allocated I/O addresses */ + .name = "Bonito PCI I/O", + .start = 0x00000000UL, .end = 0x000fffffUL, .flags = IORESOURCE_IO, }; static struct resource gt64120_mem_resource = { - .name = "GT64120 PCI MEM", - .start = 0x10000000UL, - .end = 0x1bdfffffUL, + .name = "GT-64120 PCI MEM", .flags = IORESOURCE_MEM, }; static struct resource gt64120_io_resource = { - .name = "GT64120 IO MEM", -#ifdef CONFIG_MIPS_ATLAS - .start = 0x18000000UL, - .end = 0x181fffffUL, -#endif -#ifdef CONFIG_MIPS_MALTA - .start = 0x00002000UL, - .end = 0x001fffffUL, -#endif + .name = "GT-64120 PCI I/O", .flags = IORESOURCE_IO, }; static struct resource msc_mem_resource = { .name = "MSC PCI MEM", - .start = 0x10000000UL, - .end = 0x1fffffffUL, .flags = IORESOURCE_MEM, }; static struct resource msc_io_resource = { - .name = "MSC IO MEM", - .start = 0x00002000UL, - .end = 0x007fffffUL, + .name = "MSC PCI I/O", .flags = IORESOURCE_IO, }; @@ -89,7 +72,6 @@ static struct pci_controller bonito64_controller = { .pci_ops = &bonito64_pci_ops, .io_resource = &bonito64_io_resource, .mem_resource = &bonito64_mem_resource, - .mem_offset = 0x10000000UL, .io_offset = 0x00000000UL, }; @@ -97,21 +79,18 @@ static struct pci_controller gt64120_controller = { .pci_ops = >64120_pci_ops, .io_resource = >64120_io_resource, .mem_resource = >64120_mem_resource, - .mem_offset = 0x00000000UL, - .io_offset = 0x00000000UL, }; -static struct pci_controller msc_controller = { +static struct pci_controller msc_controller = { .pci_ops = &msc_pci_ops, .io_resource = &msc_io_resource, .mem_resource = &msc_mem_resource, - .mem_offset = 0x10000000UL, - .io_offset = 0x00000000UL, }; -static int __init pcibios_init(void) +void __init mips_pcibios_init(void) { struct pci_controller *controller; + unsigned long start, end, map, start1, end1, map1, map2, map3, mask; switch (mips_revision_corid) { case MIPS_REVISION_CORID_QED_RM5261: @@ -130,34 +109,140 @@ static int __init pcibios_init(void) (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 dev */ (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0*/ ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4*/ - GT_PCI0_CFGADDR_CONFIGEN_BIT ); + GT_PCI0_CFGADDR_CONFIGEN_BIT); /* Perform the write */ GT_WRITE(GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE)); + /* Set up resource ranges from the controller's registers. */ + start = GT_READ(GT_PCI0M0LD_OFS); + end = GT_READ(GT_PCI0M0HD_OFS); + map = GT_READ(GT_PCI0M0REMAP_OFS); + end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK); + start1 = GT_READ(GT_PCI0M1LD_OFS); + end1 = GT_READ(GT_PCI0M1HD_OFS); + map1 = GT_READ(GT_PCI0M1REMAP_OFS); + end1 = (end1 & GT_PCI_HD_MSK) | (start1 & ~GT_PCI_HD_MSK); + /* Cannot support multiple windows, use the wider. */ + if (end1 - start1 > end - start) { + start = start1; + end = end1; + map = map1; + } + mask = ~(start ^ end); + /* We don't support remapping with a discontiguous mask. */ + BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) && + mask != ~((mask & -mask) - 1)); + gt64120_mem_resource.start = start; + gt64120_mem_resource.end = end; + gt64120_controller.mem_offset = (start & mask) - (map & mask); + /* Addresses are 36-bit, so do shifts in the destinations. */ + gt64120_mem_resource.start <<= GT_PCI_DCRM_SHF; + gt64120_mem_resource.end <<= GT_PCI_DCRM_SHF; + gt64120_mem_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1; + gt64120_controller.mem_offset <<= GT_PCI_DCRM_SHF; + + start = GT_READ(GT_PCI0IOLD_OFS); + end = GT_READ(GT_PCI0IOHD_OFS); + map = GT_READ(GT_PCI0IOREMAP_OFS); + end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK); + mask = ~(start ^ end); + /* We don't support remapping with a discontiguous mask. */ + BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) && + mask != ~((mask & -mask) - 1)); + gt64120_io_resource.start = map & mask; + gt64120_io_resource.end = (map & mask) | ~mask; + gt64120_controller.io_offset = 0; + /* Addresses are 36-bit, so do shifts in the destinations. */ + gt64120_io_resource.start <<= GT_PCI_DCRM_SHF; + gt64120_io_resource.end <<= GT_PCI_DCRM_SHF; + gt64120_io_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1; + controller = >64120_controller; break; case MIPS_REVISION_CORID_BONITO64: case MIPS_REVISION_CORID_CORE_20K: case MIPS_REVISION_CORID_CORE_EMUL_BON: + /* Set up resource ranges from the controller's registers. */ + map = BONITO_PCIMAP; + map1 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO0) >> + BONITO_PCIMAP_PCIMAP_LO0_SHIFT; + map2 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO1) >> + BONITO_PCIMAP_PCIMAP_LO1_SHIFT; + map3 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO2) >> + BONITO_PCIMAP_PCIMAP_LO2_SHIFT; + /* Combine as many adjacent windows as possible. */ + map = map1; + start = BONITO_PCILO0_BASE; + end = 1; + if (map3 == map2 + 1) { + map = map2; + start = BONITO_PCILO1_BASE; + end++; + } + if (map2 == map1 + 1) { + map = map1; + start = BONITO_PCILO0_BASE; + end++; + } + bonito64_mem_resource.start = start; + bonito64_mem_resource.end = start + + BONITO_PCIMAP_WINBASE(end) - 1; + bonito64_controller.mem_offset = start - + BONITO_PCIMAP_WINBASE(map); + controller = &bonito64_controller; break; case MIPS_REVISION_CORID_CORE_MSC: case MIPS_REVISION_CORID_CORE_FPGA2: + case MIPS_REVISION_CORID_CORE_FPGA3: case MIPS_REVISION_CORID_CORE_EMUL_MSC: + /* Set up resource ranges from the controller's registers. */ + MSC_READ(MSC01_PCI_SC2PMBASL, start); + MSC_READ(MSC01_PCI_SC2PMMSKL, mask); + MSC_READ(MSC01_PCI_SC2PMMAPL, map); + msc_mem_resource.start = start & mask; + msc_mem_resource.end = (start & mask) | ~mask; + msc_controller.mem_offset = (start & mask) - (map & mask); + + MSC_READ(MSC01_PCI_SC2PIOBASL, start); + MSC_READ(MSC01_PCI_SC2PIOMSKL, mask); + MSC_READ(MSC01_PCI_SC2PIOMAPL, map); + msc_io_resource.start = map & mask; + msc_io_resource.end = (map & mask) | ~mask; + msc_controller.io_offset = 0; + ioport_resource.end = ~mask; + + /* If ranges overlap I/O takes precedence. */ + start = start & mask; + end = start | ~mask; + if ((start >= msc_mem_resource.start && + start <= msc_mem_resource.end) || + (end >= msc_mem_resource.start && + end <= msc_mem_resource.end)) { + /* Use the larger space. */ + start = max(start, msc_mem_resource.start); + end = min(end, msc_mem_resource.end); + if (start - msc_mem_resource.start >= + msc_mem_resource.end - end) + msc_mem_resource.end = start - 1; + else + msc_mem_resource.start = end + 1; + } + controller = &msc_controller; break; default: - return 1; + return; } + if (controller->io_resource->start < 0x00001000UL) /* FIXME */ + controller->io_resource->start = 0x00001000UL; + + iomem_resource.end &= 0xfffffffffULL; /* 64 GB */ ioport_resource.end = controller->io_resource->end; register_pci_controller (controller); - - return 0; } - -early_initcall(pcibios_init); diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index 16315444dd5..72a12d931cb 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -31,22 +31,21 @@ #include <asm/mipsregs.h> #include <asm/ptrace.h> +#include <asm/hardirq.h> +#include <asm/irq.h> #include <asm/div64.h> #include <asm/cpu.h> #include <asm/time.h> #include <asm/mc146818-time.h> +#include <asm/msc01_ic.h> #include <asm/mips-boards/generic.h> #include <asm/mips-boards/prom.h> +#include <asm/mips-boards/maltaint.h> +#include <asm/mc146818-time.h> unsigned long cpu_khz; -#if defined(CONFIG_MIPS_SEAD) -#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ5) -#else -#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) -#endif - #if defined(CONFIG_MIPS_ATLAS) static char display_string[] = " LINUX ON ATLAS "; #endif @@ -59,20 +58,61 @@ static char display_string[] = " LINUX ON SEAD "; static unsigned int display_count = 0; #define MAX_DISPLAY_COUNT (sizeof(display_string) - 8) -#define MIPS_CPU_TIMER_IRQ (NR_IRQS-1) - static unsigned int timer_tick_count=0; +static int mips_cpu_timer_irq; -void mips_timer_interrupt(struct pt_regs *regs) +static inline void scroll_display_message(void) { if ((timer_tick_count++ % HZ) == 0) { mips_display_message(&display_string[display_count++]); if (display_count == MAX_DISPLAY_COUNT) - display_count = 0; + display_count = 0; + } +} + +static void mips_timer_dispatch (struct pt_regs *regs) +{ + do_IRQ (mips_cpu_timer_irq, regs); +} +irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ +#ifdef CONFIG_SMP + int cpu = smp_processor_id(); + + if (cpu == 0) { + /* + * CPU 0 handles the global timer interrupt job and process accounting + * resets count/compare registers to trigger next timer int. + */ + (void) timer_interrupt(irq, dev_id, regs); + scroll_display_message(); + } + else { + /* Everyone else needs to reset the timer int here as + ll_local_timer_interrupt doesn't */ + /* + * FIXME: need to cope with counter underflow. + * More support needs to be added to kernel/time for + * counter/timer interrupts on multiple CPU's + */ + write_c0_compare (read_c0_count() + (mips_hpt_frequency/HZ)); + /* + * other CPUs should do profiling and process accounting + */ + local_timer_interrupt (irq, dev_id, regs); } - ll_timer_interrupt(MIPS_CPU_TIMER_IRQ, regs); + return IRQ_HANDLED; +#else + irqreturn_t r; + + r = timer_interrupt(irq, dev_id, regs); + + scroll_display_message(); + + return r; +#endif } /* @@ -140,10 +180,8 @@ void __init mips_time_init(void) local_irq_save(flags); -#if defined(CONFIG_MIPS_ATLAS) || defined(CONFIG_MIPS_MALTA) /* Set Data mode - binary. */ CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); -#endif est_freq = estimate_cpu_frequency (); @@ -157,11 +195,29 @@ void __init mips_time_init(void) void __init mips_timer_setup(struct irqaction *irq) { + if (cpu_has_veic) { + set_vi_handler (MSC01E_INT_CPUCTR, mips_timer_dispatch); + mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR; + } + else { + if (cpu_has_vint) + set_vi_handler (MIPSCPU_INT_CPUCTR, mips_timer_dispatch); + mips_cpu_timer_irq = MIPSCPU_INT_BASE + MIPSCPU_INT_CPUCTR; + } + + /* we are using the cpu counter for timer interrupts */ - irq->handler = no_action; /* we use our own handler */ - setup_irq(MIPS_CPU_TIMER_IRQ, irq); + irq->handler = mips_timer_interrupt; /* we use our own handler */ + setup_irq(mips_cpu_timer_irq, irq); + +#ifdef CONFIG_SMP + /* irq_desc(riptor) is a global resource, when the interrupt overlaps + on seperate cpu's the first one tries to handle the second interrupt. + The effect is that the int remains disabled on the second cpu. + Mark the interrupt with IRQ_PER_CPU to avoid any confusion */ + irq_desc[mips_cpu_timer_irq].status |= IRQ_PER_CPU; +#endif /* to generate the first timer interrupt */ write_c0_compare (read_c0_count() + mips_hpt_frequency/HZ); - set_c0_status(ALLINTS); } |