mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-03 17:14:14 +08:00
Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus: (47 commits)
[MAINTAINERS] The ham radio code now has website at http://www.linux-ax25.org.
[MIPS] Use __ffs() instead of ffs() for waybit calculation.
[MIPS] Fix Makefile bugs for MIPS32/MIPS64 R1 and R2.
[MIPS] Handle IDE PIO cache aliases on SMP.
[MIPS] Make mips_srs_init static.
[MIPS] MIPS boards: Set HZ to 100.
[MIPS] kgdb: Let gcc compute the array size itself.
[MIPS] FPU affinity for MT ASE.
[MIPS] MT: Improved multithreading support.
[MIPS] kpsd and other AP/SP improvements.
[MIPS] R2: Instruction hazard barrier.
[MIPS] Fix genrtc compilation.
[MIPS] R2: Implement shadow register allocation without spinlock.
[MIPS] Fix VR41xx build errors.
[MIPS] Fix tx49_blast_icache32_page_indexed.
[MIPS] Enable SCHED_NO_NO_OMIT_FRAME_POINTER for MIPS.
[MIPS] Use "R" constraint for cache_op.
[MIPS] Rewrite all the assembler interrupt handlers to C.
[MIPS] Fix the crime against humanity that mipsIRQ.S is.
[MIPS] Fixup damage done by 22a9835c35
.
...
This commit is contained in:
commit
038e5e2bf2
@ -411,6 +411,7 @@ AX.25 NETWORK LAYER
|
||||
P: Ralf Baechle
|
||||
M: ralf@linux-mips.org
|
||||
L: linux-hams@vger.kernel.org
|
||||
W: http://www.linux-ax25.org/
|
||||
S: Maintained
|
||||
|
||||
BAYCOM/HDLCDRV DRIVERS FOR AX.25
|
||||
@ -1869,6 +1870,7 @@ NETROM NETWORK LAYER
|
||||
P: Ralf Baechle
|
||||
M: ralf@linux-mips.org
|
||||
L: linux-hams@vger.kernel.org
|
||||
W: http://www.linux-ax25.org/
|
||||
S: Maintained
|
||||
|
||||
NETWORK BLOCK DEVICE
|
||||
@ -2260,6 +2262,7 @@ ROSE NETWORK LAYER
|
||||
P: Ralf Baechle
|
||||
M: ralf@linux-mips.org
|
||||
L: linux-hams@vger.kernel.org
|
||||
W: http://www.linux-ax25.org/
|
||||
S: Maintained
|
||||
|
||||
RISCOM8 DRIVER
|
||||
|
@ -816,6 +816,10 @@ config GENERIC_CALIBRATE_DELAY
|
||||
bool
|
||||
default y
|
||||
|
||||
config SCHED_NO_NO_OMIT_FRAME_POINTER
|
||||
bool
|
||||
default y
|
||||
|
||||
#
|
||||
# Select some configuration options automatically based on user selections.
|
||||
#
|
||||
@ -1443,6 +1447,10 @@ choice
|
||||
prompt "MIPS MT options"
|
||||
depends on MIPS_MT
|
||||
|
||||
config MIPS_MT_SMTC
|
||||
bool "SMTC: Use all TCs on all VPEs for SMP"
|
||||
select SMP
|
||||
|
||||
config MIPS_MT_SMP
|
||||
bool "Use 1 TC on each available VPE for SMP"
|
||||
select SMP
|
||||
@ -1456,6 +1464,11 @@ config MIPS_VPE_LOADER
|
||||
|
||||
endchoice
|
||||
|
||||
config MIPS_MT_FPAFF
|
||||
bool "Dynamic FPU affinity for FP-intensive threads"
|
||||
depends on MIPS_MT
|
||||
default y
|
||||
|
||||
config MIPS_VPE_LOADER_TOM
|
||||
bool "Load VPE program into memory hidden from linux"
|
||||
depends on MIPS_VPE_LOADER
|
||||
@ -1472,6 +1485,16 @@ config MIPS_VPE_APSP_API
|
||||
depends on MIPS_VPE_LOADER
|
||||
help
|
||||
|
||||
config MIPS_APSP_KSPD
|
||||
bool "Enable KSPD"
|
||||
depends on MIPS_VPE_APSP_API
|
||||
default y
|
||||
help
|
||||
KSPD is a kernel daemon that accepts syscall requests from the SP
|
||||
side, actions them and returns the results. It also handles the
|
||||
"exit" syscall notifying other kernel modules the SP program is
|
||||
exiting. You probably want to say yes here.
|
||||
|
||||
config SB1_PASS_1_WORKAROUNDS
|
||||
bool
|
||||
depends on CPU_SB1_PASS_1
|
||||
@ -1599,7 +1622,7 @@ source "mm/Kconfig"
|
||||
|
||||
config SMP
|
||||
bool "Multi-Processing support"
|
||||
depends on CPU_RM9000 || ((SIBYTE_BCM1x80 || SIBYTE_BCM1x55 || SIBYTE_SB1250 || QEMU) && !SIBYTE_STANDALONE) || SGI_IP27 || MIPS_MT_SMP
|
||||
depends on CPU_RM9000 || ((SIBYTE_BCM1x80 || SIBYTE_BCM1x55 || SIBYTE_SB1250 || QEMU) && !SIBYTE_STANDALONE) || SGI_IP27 || MIPS_MT_SMP || MIPS_MT_SMTC
|
||||
---help---
|
||||
This enables support for systems with more than one CPU. If you have
|
||||
a system with only one CPU, like most personal computers, say N. If
|
||||
|
@ -105,18 +105,18 @@ cflags-$(CONFIG_CPU_R4300) += -march=r4300 -Wa,--trap
|
||||
cflags-$(CONFIG_CPU_VR41XX) += -march=r4100 -Wa,--trap
|
||||
cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap
|
||||
cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap
|
||||
cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips2 -mtune=r4600) \
|
||||
cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips32 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
|
||||
-Wa,-mips32 -Wa,--trap
|
||||
cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips2 -mtune=r4600) \
|
||||
cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
|
||||
-Wa,-mips32r2 -Wa,--trap
|
||||
cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips2 -mtune=r4600) \
|
||||
cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips64 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \
|
||||
-Wa,-mips64 -Wa,--trap
|
||||
cflags-$(CONFIG_CPU_MIPS64_R2) += $(call cc-option,-march=mips64r2,-mips2 -mtune=r4600 ) \
|
||||
cflags-$(CONFIG_CPU_MIPS64_R2) += $(call cc-option,-march=mips64r2,-mips64r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \
|
||||
-Wa,-mips64r2 -Wa,--trap
|
||||
cflags-$(CONFIG_CPU_R5000) += -march=r5000 -Wa,--trap
|
||||
cflags-$(CONFIG_CPU_R5432) += $(call cc-options,-march=r5400,-march=r5000) \
|
||||
cflags-$(CONFIG_CPU_R5432) += $(call cc-option,-march=r5400,-march=r5000) \
|
||||
-Wa,--trap
|
||||
cflags-$(CONFIG_CPU_NEVADA) += $(call cc-options,-march=rm5200,-march=r5000) \
|
||||
cflags-$(CONFIG_CPU_NEVADA) += $(call cc-option,-march=rm5200,-march=r5000) \
|
||||
-Wa,--trap
|
||||
cflags-$(CONFIG_CPU_RM7000) += $(call cc-option,-march=rm7000,-march=r5000) \
|
||||
-Wa,--trap
|
||||
|
@ -6,7 +6,7 @@
|
||||
# Makefile for the Alchemy Au1000 CPU, generic files.
|
||||
#
|
||||
|
||||
obj-y += prom.o int-handler.o irq.o puts.o time.o reset.o \
|
||||
obj-y += prom.o irq.o puts.o time.o reset.o \
|
||||
au1xxx_irqmap.o clocks.o platform.o power.o setup.o \
|
||||
sleeper.o cputable.o dma.o dbdma.o gpio.o
|
||||
|
||||
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright 2001 MontaVista Software Inc.
|
||||
* Author: ppopov@mvista.com
|
||||
*
|
||||
* Interrupt dispatcher for Au1000 boards.
|
||||
*
|
||||
* 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/mipsregs.h>
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/stackframe.h>
|
||||
|
||||
.text
|
||||
.set macro
|
||||
.set noat
|
||||
.align 5
|
||||
|
||||
NESTED(au1000_IRQ, PT_SIZE, sp)
|
||||
SAVE_ALL
|
||||
CLI # Important: mark KERNEL mode !
|
||||
|
||||
mfc0 t0,CP0_CAUSE # get pending interrupts
|
||||
mfc0 t1,CP0_STATUS # get enabled interrupts
|
||||
and t0,t1 # isolate allowed ones
|
||||
|
||||
andi t0,0xff00 # isolate pending bits
|
||||
beqz t0, 3f # spurious interrupt
|
||||
|
||||
andi a0, t0, CAUSEF_IP7
|
||||
beq a0, zero, 1f
|
||||
move a0, sp
|
||||
jal mips_timer_interrupt
|
||||
j ret_from_irq
|
||||
|
||||
1:
|
||||
andi a0, t0, CAUSEF_IP2 # Interrupt Controller 0, Request 0
|
||||
beq a0, zero, 2f
|
||||
move a0,sp
|
||||
jal intc0_req0_irqdispatch
|
||||
j ret_from_irq
|
||||
2:
|
||||
andi a0, t0, CAUSEF_IP3 # Interrupt Controller 0, Request 1
|
||||
beq a0, zero, 3f
|
||||
move a0,sp
|
||||
jal intc0_req1_irqdispatch
|
||||
j ret_from_irq
|
||||
3:
|
||||
andi a0, t0, CAUSEF_IP4 # Interrupt Controller 1, Request 0
|
||||
beq a0, zero, 4f
|
||||
move a0,sp
|
||||
jal intc1_req0_irqdispatch
|
||||
j ret_from_irq
|
||||
4:
|
||||
andi a0, t0, CAUSEF_IP5 # Interrupt Controller 1, Request 1
|
||||
beq a0, zero, 5f
|
||||
move a0, sp
|
||||
jal intc1_req1_irqdispatch
|
||||
j ret_from_irq
|
||||
|
||||
5:
|
||||
move a0, sp
|
||||
j spurious_interrupt
|
||||
END(au1000_IRQ)
|
@ -66,7 +66,6 @@
|
||||
#define EXT_INTC1_REQ1 5 /* IP 5 */
|
||||
#define MIPS_TIMER_IP 7 /* IP 7 */
|
||||
|
||||
extern asmlinkage void au1000_IRQ(void);
|
||||
extern void set_debug_traps(void);
|
||||
extern irq_cpustat_t irq_stat [NR_CPUS];
|
||||
|
||||
@ -446,7 +445,6 @@ void __init arch_init_irq(void)
|
||||
extern int au1xxx_ic0_nr_irqs;
|
||||
|
||||
cp0_status = read_c0_status();
|
||||
set_except_vector(0, au1000_IRQ);
|
||||
|
||||
/* Initialize interrupt controllers to a safe state.
|
||||
*/
|
||||
@ -661,3 +659,21 @@ restore_au1xxx_intctl(void)
|
||||
au_writel(sleep_intctl_mask[0], IC0_MASKSET); au_sync();
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
|
||||
|
||||
if (pending & CAUSEF_IP7)
|
||||
mips_timer_interrupt(regs);
|
||||
else if (pending & CAUSEF_IP2)
|
||||
intc0_req0_irqdispatch(regs);
|
||||
else if (pending & CAUSEF_IP3)
|
||||
intc0_req1_irqdispatch(regs);
|
||||
else if (pending & CAUSEF_IP4)
|
||||
intc1_req0_irqdispatch(regs);
|
||||
else if (pending & CAUSEF_IP5)
|
||||
intc1_req1_irqdispatch(regs);
|
||||
else
|
||||
spurious_interrupt(regs);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Makefile for the Cobalt micro systems family specific parts of the kernel
|
||||
#
|
||||
|
||||
obj-y := irq.o int-handler.o reset.o setup.o
|
||||
obj-y := irq.o reset.o setup.o
|
||||
|
||||
obj-$(CONFIG_EARLY_PRINTK) += console.o
|
||||
|
||||
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* 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) 1995, 1996, 1997, 2003 by Ralf Baechle
|
||||
* Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
|
||||
*/
|
||||
#include <asm/asm.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/mach-cobalt/cobalt.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/stackframe.h>
|
||||
|
||||
.text
|
||||
.align 5
|
||||
NESTED(cobalt_handle_int, PT_SIZE, sp)
|
||||
SAVE_ALL
|
||||
CLI
|
||||
|
||||
PTR_LA ra, ret_from_irq
|
||||
move a0, sp
|
||||
j cobalt_irq
|
||||
|
||||
END(cobalt_handle_int)
|
@ -20,8 +20,6 @@
|
||||
|
||||
#include <asm/mach-cobalt/cobalt.h>
|
||||
|
||||
extern void cobalt_handle_int(void);
|
||||
|
||||
/*
|
||||
* We have two types of interrupts that we handle, ones that come in through
|
||||
* the CPU interrupt lines, and ones that come in on the via chip. The CPU
|
||||
@ -79,7 +77,7 @@ static inline void via_pic_irq(struct pt_regs *regs)
|
||||
do_IRQ(irq, regs);
|
||||
}
|
||||
|
||||
asmlinkage void cobalt_irq(struct pt_regs *regs)
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
unsigned pending;
|
||||
|
||||
@ -122,8 +120,6 @@ void __init arch_init_irq(void)
|
||||
*/
|
||||
GALILEO_OUTL(0, GT_INTRMASK_OFS);
|
||||
|
||||
set_except_vector(0, cobalt_handle_int);
|
||||
|
||||
init_i8259_irqs(); /* 0 ... 15 */
|
||||
mips_cpu_irq_init(COBALT_CPU_IRQ); /* 16 ... 23 */
|
||||
|
||||
|
1096
arch/mips/configs/tb0287_defconfig
Normal file
1096
arch/mips/configs/tb0287_defconfig
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,6 @@
|
||||
# under Linux.
|
||||
#
|
||||
|
||||
obj-y += setup.o irq.o int-handler.o nile4_pic.o
|
||||
obj-y += setup.o irq.o nile4_pic.o
|
||||
|
||||
EXTRA_AFLAGS := $(CFLAGS)
|
||||
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
* arch/mips/ddb5074/int-handler.S -- NEC DDB Vrc-5074 interrupt handler
|
||||
*
|
||||
* Based on arch/mips/sgi/kernel/indyIRQ.S
|
||||
*
|
||||
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
|
||||
*
|
||||
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
|
||||
* Sony Software Development Center Europe (SDCE), Brussels
|
||||
*/
|
||||
#include <asm/asm.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/stackframe.h>
|
||||
|
||||
/* A lot of complication here is taken away because:
|
||||
*
|
||||
* 1) We handle one interrupt and return, sitting in a loop and moving across
|
||||
* all the pending IRQ bits in the cause register is _NOT_ the answer, the
|
||||
* common case is one pending IRQ so optimize in that direction.
|
||||
*
|
||||
* 2) We need not check against bits in the status register IRQ mask, that
|
||||
* would make this routine slow as hell.
|
||||
*
|
||||
* 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
|
||||
* between like BSD spl() brain-damage.
|
||||
*
|
||||
* Furthermore, the IRQs on the INDY look basically (barring software IRQs
|
||||
* which we don't use at all) like:
|
||||
*
|
||||
* MIPS IRQ Source
|
||||
* -------- ------
|
||||
* 0 Software (ignored)
|
||||
* 1 Software (ignored)
|
||||
* 2 Local IRQ level zero
|
||||
* 3 Local IRQ level one
|
||||
* 4 8254 Timer zero
|
||||
* 5 8254 Timer one
|
||||
* 6 Bus Error
|
||||
* 7 R4k timer (what we use)
|
||||
*
|
||||
* We handle the IRQ according to _our_ priority which is:
|
||||
*
|
||||
* Highest ---- R4k Timer
|
||||
* Local IRQ zero
|
||||
* Local IRQ one
|
||||
* Bus Error
|
||||
* 8254 Timer zero
|
||||
* Lowest ---- 8254 Timer one
|
||||
*
|
||||
* then we just return, if multiple IRQs are pending then we will just take
|
||||
* another exception, big deal.
|
||||
*/
|
||||
|
||||
.text
|
||||
.set noreorder
|
||||
.set noat
|
||||
.align 5
|
||||
NESTED(ddbIRQ, PT_SIZE, sp)
|
||||
SAVE_ALL
|
||||
CLI
|
||||
.set at
|
||||
mfc0 s0, CP0_CAUSE # get irq mask
|
||||
|
||||
#if 1
|
||||
mfc0 t2,CP0_STATUS # get enabled interrupts
|
||||
and s0,t2 # isolate allowed ones
|
||||
#endif
|
||||
/* First we check for r4k counter/timer IRQ. */
|
||||
andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero
|
||||
beq a0, zero, 1f
|
||||
andi a0, s0, CAUSEF_IP3 # delay slot, check local level one
|
||||
|
||||
/* Wheee, local level zero interrupt. */
|
||||
jal ddb_local0_irqdispatch
|
||||
move a0, sp # delay slot
|
||||
|
||||
j ret_from_irq
|
||||
nop # delay slot
|
||||
|
||||
1:
|
||||
beq a0, zero, 1f
|
||||
andi a0, s0, CAUSEF_IP6 # delay slot, check bus error
|
||||
|
||||
/* Wheee, local level one interrupt. */
|
||||
move a0, sp
|
||||
jal ddb_local1_irqdispatch
|
||||
nop
|
||||
|
||||
j ret_from_irq
|
||||
nop
|
||||
|
||||
1:
|
||||
beq a0, zero, 1f
|
||||
nop
|
||||
|
||||
/* Wheee, an asynchronous bus error... */
|
||||
move a0, sp
|
||||
jal ddb_buserror_irq
|
||||
nop
|
||||
|
||||
j ret_from_irq
|
||||
nop
|
||||
|
||||
1:
|
||||
/* 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.
|
||||
*/
|
||||
andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5)
|
||||
beq a0, zero, 1f
|
||||
|
||||
/* Must be one of the 8254 timers... */
|
||||
move a0, sp
|
||||
jal ddb_8254timer_irq
|
||||
nop
|
||||
1:
|
||||
j ret_from_irq
|
||||
nop
|
||||
END(ddbIRQ)
|
@ -21,8 +21,6 @@
|
||||
#include <asm/ddb5xxx/ddb5074.h>
|
||||
|
||||
|
||||
extern asmlinkage void ddbIRQ(void);
|
||||
|
||||
static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
|
||||
|
||||
#define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */
|
||||
@ -90,7 +88,7 @@ static void m1543_irq_setup(void)
|
||||
|
||||
}
|
||||
|
||||
void ddb_local0_irqdispatch(struct pt_regs *regs)
|
||||
static void ddb_local0_irqdispatch(struct pt_regs *regs)
|
||||
{
|
||||
u32 mask;
|
||||
int nile4_irq;
|
||||
@ -118,29 +116,41 @@ void ddb_local0_irqdispatch(struct pt_regs *regs)
|
||||
}
|
||||
}
|
||||
|
||||
void ddb_local1_irqdispatch(void)
|
||||
static void ddb_local1_irqdispatch(void)
|
||||
{
|
||||
printk("ddb_local1_irqdispatch called\n");
|
||||
}
|
||||
|
||||
void ddb_buserror_irq(void)
|
||||
static void ddb_buserror_irq(void)
|
||||
{
|
||||
printk("ddb_buserror_irq called\n");
|
||||
}
|
||||
|
||||
void ddb_8254timer_irq(void)
|
||||
static void ddb_8254timer_irq(void)
|
||||
{
|
||||
printk("ddb_8254timer_irq called\n");
|
||||
}
|
||||
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
unsigned int pending = read_c0_cause() & read_c0_status();
|
||||
|
||||
if (pending & CAUSEF_IP2)
|
||||
ddb_local0_irqdispatch(regs);
|
||||
else if (pending & CAUSEF_IP3)
|
||||
ddb_local1_irqdispatch();
|
||||
else if (pending & CAUSEF_IP6)
|
||||
ddb_buserror_irq();
|
||||
else if (pending & (CAUSEF_IP4 | CAUSEF_IP5))
|
||||
ddb_8254timer_irq();
|
||||
}
|
||||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
/* setup cascade interrupts */
|
||||
setup_irq(NILE4_IRQ_BASE + NILE4_INT_INTE, &irq_cascade);
|
||||
setup_irq(CPU_IRQ_BASE + CPU_NILE4_CASCADE, &irq_cascade);
|
||||
|
||||
set_except_vector(0, ddbIRQ);
|
||||
|
||||
nile4_irq_setup(NILE4_IRQ_BASE);
|
||||
m1543_irq_setup();
|
||||
init_i8259_irqs();
|
||||
|
@ -3,7 +3,7 @@
|
||||
# under Linux.
|
||||
#
|
||||
|
||||
obj-y += setup.o irq.o int-handler.o nile4_pic.o vrc5476_irq.o
|
||||
obj-y += setup.o irq.o nile4_pic.o vrc5476_irq.o
|
||||
obj-$(CONFIG_KGDB) += dbg_io.o
|
||||
|
||||
EXTRA_AFLAGS := $(CFLAGS)
|
||||
|
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright 2001 MontaVista Software Inc.
|
||||
* Author: jsun@mvista.com or jsun@junsun.net
|
||||
*
|
||||
* First-level interrupt dispatcher for ddb5476
|
||||
*
|
||||
* 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/mipsregs.h>
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/stackframe.h>
|
||||
|
||||
#include <asm/ddb5xxx/ddb5476.h>
|
||||
|
||||
/*
|
||||
* first level interrupt dispatcher for ocelot board -
|
||||
* We check for the timer first, then check PCI ints A and D.
|
||||
* Then check for serial IRQ and fall through.
|
||||
*/
|
||||
.align 5
|
||||
NESTED(ddb5476_handle_int, PT_SIZE, sp)
|
||||
SAVE_ALL
|
||||
CLI
|
||||
.set at
|
||||
.set noreorder
|
||||
mfc0 t0, CP0_CAUSE
|
||||
mfc0 t2, CP0_STATUS
|
||||
|
||||
and t0, t2
|
||||
|
||||
andi t1, t0, STATUSF_IP7 /* cpu timer */
|
||||
bnez t1, ll_cpu_ip7
|
||||
andi t1, t0, STATUSF_IP2 /* vrc5476 & i8259 */
|
||||
bnez t1, ll_cpu_ip2
|
||||
andi t1, t0, STATUSF_IP3
|
||||
bnez t1, ll_cpu_ip3
|
||||
andi t1, t0, STATUSF_IP4
|
||||
bnez t1, ll_cpu_ip4
|
||||
andi t1, t0, STATUSF_IP5
|
||||
bnez t1, ll_cpu_ip5
|
||||
andi t1, t0, STATUSF_IP6
|
||||
bnez t1, ll_cpu_ip6
|
||||
andi t1, t0, STATUSF_IP0 /* software int 0 */
|
||||
bnez t1, ll_cpu_ip0
|
||||
andi t1, t0, STATUSF_IP1 /* software int 1 */
|
||||
bnez t1, ll_cpu_ip1
|
||||
nop
|
||||
|
||||
.set reorder
|
||||
|
||||
/* wrong alarm or masked ... */
|
||||
// j spurious_interrupt
|
||||
move a0, sp
|
||||
jal vrc5476_irq_dispatch
|
||||
j ret_from_irq
|
||||
nop
|
||||
|
||||
.align 5
|
||||
|
||||
ll_cpu_ip0:
|
||||
li a0, CPU_IRQ_BASE + 0
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
ll_cpu_ip1:
|
||||
li a0, CPU_IRQ_BASE + 1
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
ll_cpu_ip2: /* jump to second-level dispatching */
|
||||
move a0, sp
|
||||
jal vrc5476_irq_dispatch
|
||||
j ret_from_irq
|
||||
|
||||
ll_cpu_ip3:
|
||||
li a0, CPU_IRQ_BASE + 3
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
ll_cpu_ip4:
|
||||
li a0, CPU_IRQ_BASE + 4
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
ll_cpu_ip5:
|
||||
li a0, CPU_IRQ_BASE + 5
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
ll_cpu_ip6:
|
||||
li a0, CPU_IRQ_BASE + 6
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
ll_cpu_ip7:
|
||||
li a0, CPU_IRQ_BASE + 7
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
END(ddb5476_handle_int)
|
@ -110,11 +110,36 @@ static void nile4_irq_setup(void)
|
||||
static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
|
||||
static struct irqaction irq_error = { no_action, 0, CPU_MASK_NONE, "error", NULL, NULL };
|
||||
|
||||
extern asmlinkage void ddb5476_handle_int(void);
|
||||
extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
|
||||
extern void mips_cpu_irq_init(u32 irq_base);
|
||||
extern void vrc5476_irq_init(u32 irq_base);
|
||||
|
||||
extern void vrc5476_irq_dispatch(struct pt_regs *regs);
|
||||
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
unsigned int pending = read_c0_cause() & read_c0_status();
|
||||
|
||||
if (pending & STATUSF_IP7)
|
||||
do_IRQ(CPU_IRQ_BASE + 7, regs);
|
||||
else if (pending & STATUSF_IP2)
|
||||
vrc5476_irq_dispatch(regs);
|
||||
else if (pending & STATUSF_IP3)
|
||||
do_IRQ(CPU_IRQ_BASE + 3, regs);
|
||||
else if (pending & STATUSF_IP4)
|
||||
do_IRQ(CPU_IRQ_BASE + 4, regs);
|
||||
else if (pending & STATUSF_IP5)
|
||||
do_IRQ(CPU_IRQ_BASE + 5, regs);
|
||||
else if (pending & STATUSF_IP6)
|
||||
do_IRQ(CPU_IRQ_BASE + 6, regs);
|
||||
else if (pending & STATUSF_IP0)
|
||||
do_IRQ(CPU_IRQ_BASE, regs);
|
||||
else if (pending & STATUSF_IP1)
|
||||
do_IRQ(CPU_IRQ_BASE + 1, regs);
|
||||
|
||||
vrc5476_irq_dispatch(regs);
|
||||
}
|
||||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
/* hardware initialization */
|
||||
@ -137,7 +162,4 @@ void __init arch_init_irq(void)
|
||||
setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_LBRT, &irq_error);
|
||||
setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCIS, &irq_error);
|
||||
setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCI, &irq_error);
|
||||
|
||||
/* setup the grandpa intr vector */
|
||||
set_except_vector(0, ddb5476_handle_int);
|
||||
}
|
||||
|
@ -77,11 +77,9 @@ vrc5476_irq_init(u32 base)
|
||||
}
|
||||
|
||||
|
||||
asmlinkage void
|
||||
void
|
||||
vrc5476_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
extern void spurious_interrupt(void);
|
||||
|
||||
u32 mask;
|
||||
int nile4_irq;
|
||||
|
||||
@ -107,5 +105,5 @@ vrc5476_irq_dispatch(struct pt_regs *regs)
|
||||
return;
|
||||
}
|
||||
}
|
||||
spurious_interrupt();
|
||||
spurious_interrupt(regs);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Makefile for NEC DDB-Vrc5477 board
|
||||
#
|
||||
|
||||
obj-y += int-handler.o irq.o irq_5477.o setup.o lcd44780.o
|
||||
obj-y += irq.o irq_5477.o setup.o lcd44780.o
|
||||
|
||||
obj-$(CONFIG_RUNTIME_DEBUG) += debug.o
|
||||
obj-$(CONFIG_KGDB) += kgdb_io.o
|
||||
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright 2001 MontaVista Software Inc.
|
||||
* Author: jsun@mvista.com or jsun@junsun.net
|
||||
*
|
||||
* First-level interrupt dispatcher for ddb5477
|
||||
*
|
||||
* 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/mipsregs.h>
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/stackframe.h>
|
||||
#include <asm/ddb5xxx/ddb5477.h>
|
||||
|
||||
/*
|
||||
* first level interrupt dispatcher for ocelot board -
|
||||
* We check for the timer first, then check PCI ints A and D.
|
||||
* Then check for serial IRQ and fall through.
|
||||
*/
|
||||
.align 5
|
||||
NESTED(ddb5477_handle_int, PT_SIZE, sp)
|
||||
SAVE_ALL
|
||||
CLI
|
||||
.set at
|
||||
.set noreorder
|
||||
mfc0 t0, CP0_CAUSE
|
||||
mfc0 t2, CP0_STATUS
|
||||
|
||||
and t0, t2
|
||||
|
||||
andi t1, t0, STATUSF_IP7 /* cpu timer */
|
||||
bnez t1, ll_cputimer_irq
|
||||
andi t1, t0, (STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6 )
|
||||
bnez t1, ll_vrc5477_irq
|
||||
andi t1, t0, STATUSF_IP0 /* software int 0 */
|
||||
bnez t1, ll_cpu_ip0
|
||||
andi t1, t0, STATUSF_IP1 /* software int 1 */
|
||||
bnez t1, ll_cpu_ip1
|
||||
nop
|
||||
.set reorder
|
||||
|
||||
/* wrong alarm or masked ... */
|
||||
j spurious_interrupt
|
||||
nop
|
||||
END(ddb5477_handle_int)
|
||||
|
||||
.align 5
|
||||
|
||||
ll_vrc5477_irq:
|
||||
move a0, sp
|
||||
jal vrc5477_irq_dispatch
|
||||
j ret_from_irq
|
||||
|
||||
ll_cputimer_irq:
|
||||
li a0, CPU_IRQ_BASE + 7
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
|
||||
ll_cpu_ip0:
|
||||
li a0, CPU_IRQ_BASE + 0
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
ll_cpu_ip1:
|
||||
li a0, CPU_IRQ_BASE + 1
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
@ -75,7 +75,6 @@ set_pci_int_attr(u32 pci, u32 intn, u32 active, u32 trigger)
|
||||
|
||||
extern void vrc5477_irq_init(u32 base);
|
||||
extern void mips_cpu_irq_init(u32 base);
|
||||
extern asmlinkage void ddb5477_handle_int(void);
|
||||
extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
|
||||
static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
|
||||
|
||||
@ -135,9 +134,6 @@ void __init arch_init_irq(void)
|
||||
/* setup cascade interrupts */
|
||||
setup_irq(VRC5477_IRQ_BASE + VRC5477_I8259_CASCADE, &irq_cascade);
|
||||
setup_irq(CPU_IRQ_BASE + CPU_VRC5477_CASCADE, &irq_cascade);
|
||||
|
||||
/* hook up the first-level interrupt handler */
|
||||
set_except_vector(0, ddb5477_handle_int);
|
||||
}
|
||||
|
||||
u8 i8259_interrupt_ack(void)
|
||||
@ -159,7 +155,7 @@ u8 i8259_interrupt_ack(void)
|
||||
* the first level int-handler will jump here if it is a vrc5477 irq
|
||||
*/
|
||||
#define NUM_5477_IRQS 32
|
||||
asmlinkage void
|
||||
static void
|
||||
vrc5477_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
u32 intStatus;
|
||||
@ -197,3 +193,21 @@ vrc5477_irq_dispatch(struct pt_regs *regs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define VR5477INTS (STATUSF_IP2|STATUSF_IP3|STATUSF_IP4|STATUSF_IP5|STATUSF_IP6)
|
||||
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
unsigned int pending = read_c0_cause() & read_c0_status();
|
||||
|
||||
if (pending & STATUSF_IP7)
|
||||
do_IRQ(CPU_IRQ_BASE + 7, regs);
|
||||
else if (pending & VR5477INTS)
|
||||
vrc5477_irq_dispatch(regs);
|
||||
else if (pending & STATUSF_IP0)
|
||||
do_IRQ(CPU_IRQ_BASE, regs);
|
||||
else if (pending & STATUSF_IP1)
|
||||
do_IRQ(CPU_IRQ_BASE + 1, regs);
|
||||
else
|
||||
spurious_interrupt(regs);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* arch/mips/dec/decstation.c
|
||||
*/
|
||||
#include <asm/sections.h>
|
||||
|
||||
#define RELOC
|
||||
#define INITRD
|
||||
@ -24,7 +25,7 @@
|
||||
#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 int _ftext; /* 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)
|
||||
|
@ -36,7 +36,7 @@
|
||||
.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:
|
||||
@ -125,11 +125,7 @@
|
||||
* 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
|
||||
|
||||
/*
|
||||
@ -282,9 +278,11 @@ fpu:
|
||||
#endif
|
||||
|
||||
spurious:
|
||||
j spurious_interrupt
|
||||
jal spurious_interrupt
|
||||
nop
|
||||
END(decstation_handle_int)
|
||||
j ret_from_irq
|
||||
nop
|
||||
END(plat_irq_dispatch)
|
||||
|
||||
/*
|
||||
* Generic unimplemented interrupt routines -- cpu_mask_nr_tbl
|
||||
|
@ -48,8 +48,6 @@ 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 asmlinkage void decstation_handle_int(void);
|
||||
|
||||
unsigned long dec_kn_slot_base, dec_kn_slot_size;
|
||||
|
||||
EXPORT_SYMBOL(dec_kn_slot_base);
|
||||
@ -744,7 +742,6 @@ 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) {
|
||||
|
@ -6,4 +6,4 @@
|
||||
# Makefile for the Galileo EV96100 board.
|
||||
#
|
||||
|
||||
obj-y += init.o irq.o puts.o reset.o time.o int-handler.o setup.o
|
||||
obj-y += init.o irq.o puts.o reset.o time.o setup.o
|
||||
|
@ -1,33 +0,0 @@
|
||||
#include <asm/asm.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/stackframe.h>
|
||||
|
||||
.set noat
|
||||
.align 5
|
||||
|
||||
NESTED(ev96100IRQ, PT_SIZE, sp)
|
||||
SAVE_ALL
|
||||
CLI # Important: mark KERNEL mode !
|
||||
|
||||
mfc0 t0, CP0_CAUSE # get pending interrupts
|
||||
mfc0 t1, CP0_STATUS # get enabled interrupts
|
||||
and t0, t1 # isolate allowed ones
|
||||
|
||||
# FIX ME add R7000 extensions
|
||||
andi t0,0xff00 # isolate pending bits
|
||||
andi a0, t0, CAUSEF_IP7
|
||||
beq a0, zero, 1f
|
||||
move a0, sp
|
||||
jal mips_timer_interrupt
|
||||
j ret_from_irq
|
||||
|
||||
1: beqz t0, 3f # spurious interrupt
|
||||
|
||||
move a0, t0
|
||||
move a1, sp
|
||||
jal ev96100_cpu_irq
|
||||
j ret_from_irq
|
||||
|
||||
3: j spurious_interrupt
|
||||
END(ev96100IRQ)
|
@ -40,8 +40,6 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/irq_cpu.h>
|
||||
|
||||
extern asmlinkage void ev96100IRQ(void);
|
||||
|
||||
static inline unsigned int ffz8(unsigned int word)
|
||||
{
|
||||
unsigned long k;
|
||||
@ -54,13 +52,26 @@ static inline unsigned int ffz8(unsigned int word)
|
||||
return k;
|
||||
}
|
||||
|
||||
asmlinkage void ev96100_cpu_irq(unsigned int pendin)
|
||||
extern void mips_timer_interrupt(struct pt_regs *regs);
|
||||
|
||||
asmlinkage void ev96100_cpu_irq(unsigned int pending, struct pt_regs *regs)
|
||||
{
|
||||
do_IRQ(ffz8(pending >> 8), regs);
|
||||
}
|
||||
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
|
||||
|
||||
if (pending & CAUSEF_IP7)
|
||||
mips_timer_interrupt(regs);
|
||||
else if (pending)
|
||||
ev96100_cpu_irq(pending, regs);
|
||||
else
|
||||
spurious_interrupt(regs);
|
||||
}
|
||||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
set_except_vector(0, ev96100IRQ);
|
||||
mips_cpu_irq_init(0);
|
||||
}
|
||||
|
@ -6,6 +6,6 @@
|
||||
# Makefile for the Galileo EV64120 board.
|
||||
#
|
||||
|
||||
obj-y += int-handler.o irq.o promcon.o reset.o serialGT.o setup.o
|
||||
obj-y += irq.o promcon.o reset.o serialGT.o setup.o
|
||||
|
||||
EXTRA_AFLAGS := $(CFLAGS)
|
||||
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
* int-handler.S
|
||||
*
|
||||
* Based on the cobalt handler.
|
||||
*/
|
||||
#include <asm/asm.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/stackframe.h>
|
||||
|
||||
/*
|
||||
* galileo_handle_int -
|
||||
* We check for the timer first, then check PCI ints A and D.
|
||||
* Then check for serial IRQ and fall through.
|
||||
*/
|
||||
.align 5
|
||||
.set reorder
|
||||
.set noat
|
||||
NESTED(galileo_handle_int, PT_SIZE, sp)
|
||||
SAVE_ALL
|
||||
CLI
|
||||
.set at
|
||||
mfc0 t0,CP0_CAUSE
|
||||
mfc0 t2,CP0_STATUS
|
||||
|
||||
and t0,t2
|
||||
|
||||
andi t1,t0,STATUSF_IP4 /* int2 hardware line (timer) */
|
||||
bnez t1,ll_gt64120_irq
|
||||
andi t1,t0,STATUSF_IP2 /* int0 hardware line */
|
||||
bnez t1,ll_pci_intA
|
||||
andi t1,t0,STATUSF_IP5 /* int3 hardware line */
|
||||
bnez t1,ll_pci_intD
|
||||
andi t1,t0,STATUSF_IP6 /* int4 hardware line */
|
||||
bnez t1,ll_serial_irq
|
||||
andi t1,t0,STATUSF_IP7 /* compare int */
|
||||
bnez t1,ll_compare_irq
|
||||
nop
|
||||
|
||||
/* wrong alarm or masked ... */
|
||||
j spurious_interrupt
|
||||
nop
|
||||
END(galileo_handle_int)
|
||||
|
||||
|
||||
.align 5
|
||||
.set reorder
|
||||
ll_gt64120_irq:
|
||||
li a0,4
|
||||
move a1,sp
|
||||
jal do_IRQ
|
||||
nop
|
||||
j ret_from_irq
|
||||
nop
|
||||
|
||||
.align 5
|
||||
.set reorder
|
||||
ll_compare_irq:
|
||||
li a0,7
|
||||
move a1,sp
|
||||
jal do_IRQ
|
||||
nop
|
||||
j ret_from_irq
|
||||
nop
|
||||
|
||||
.align 5
|
||||
.set reorder
|
||||
ll_pci_intA:
|
||||
move a0,sp
|
||||
jal pci_intA
|
||||
nop
|
||||
j ret_from_irq
|
||||
nop
|
||||
|
||||
#if 0
|
||||
.align 5
|
||||
.set reorder
|
||||
ll_pci_intB:
|
||||
move a0,sp
|
||||
jal pci_intB
|
||||
nop
|
||||
j ret_from_irq
|
||||
nop
|
||||
|
||||
.align 5
|
||||
.set reorder
|
||||
ll_pci_intC:
|
||||
move a0,sp
|
||||
jal pci_intC
|
||||
nop
|
||||
j ret_from_irq
|
||||
nop
|
||||
#endif
|
||||
|
||||
.align 5
|
||||
.set reorder
|
||||
ll_pci_intD:
|
||||
move a0,sp
|
||||
jal pci_intD
|
||||
nop
|
||||
j ret_from_irq
|
||||
nop
|
||||
|
||||
.align 5
|
||||
.set reorder
|
||||
ll_serial_irq:
|
||||
li a0,6
|
||||
move a1,sp
|
||||
jal do_IRQ
|
||||
nop
|
||||
j ret_from_irq
|
||||
nop
|
@ -46,14 +46,22 @@
|
||||
#include <asm/system.h>
|
||||
#include <asm/gt64120.h>
|
||||
|
||||
asmlinkage inline void pci_intA(struct pt_regs *regs)
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
do_IRQ(GT_INTA, regs);
|
||||
}
|
||||
unsigned int pending = read_c0_status() & read_c0_cause();
|
||||
|
||||
asmlinkage inline void pci_intD(struct pt_regs *regs)
|
||||
{
|
||||
do_IRQ(GT_INTD, regs);
|
||||
if (pending & STATUSF_IP4) /* int2 hardware line (timer) */
|
||||
do_IRQ(4, regs);
|
||||
else if (pending & STATUSF_IP2) /* int0 hardware line */
|
||||
do_IRQ(GT_INTA, regs);
|
||||
else if (pending & STATUSF_IP5) /* int3 hardware line */
|
||||
do_IRQ(GT_INTD, regs);
|
||||
else if (pending & STATUSF_IP6) /* int4 hardware line */
|
||||
do_IRQ(6, regs);
|
||||
else if (pending & STATUSF_IP7) /* compare int */
|
||||
do_IRQ(7, regs);
|
||||
else
|
||||
spurious_interrupt(regs);
|
||||
}
|
||||
|
||||
static void disable_ev64120_irq(unsigned int irq_nr)
|
||||
@ -109,16 +117,11 @@ static struct hw_interrupt_type ev64120_irq_type = {
|
||||
|
||||
void gt64120_irq_setup(void)
|
||||
{
|
||||
extern asmlinkage void galileo_handle_int(void);
|
||||
|
||||
/*
|
||||
* Clear all of the interrupts while we change the able around a bit.
|
||||
*/
|
||||
clear_c0_status(ST0_IM);
|
||||
|
||||
/* Sets the exception_handler array. */
|
||||
set_except_vector(0, galileo_handle_int);
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
/*
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Makefile for Momentum's Ocelot board.
|
||||
#
|
||||
|
||||
obj-y += int-handler.o irq.o prom.o reset.o setup.o
|
||||
obj-y += irq.o prom.o reset.o setup.o
|
||||
|
||||
obj-$(CONFIG_KGDB) += dbg_io.o
|
||||
|
||||
|
@ -1,131 +0,0 @@
|
||||
/*
|
||||
* Copyright 2001 MontaVista Software Inc.
|
||||
* Author: jsun@mvista.com or jsun@junsun.net
|
||||
*
|
||||
* First-level interrupt dispatcher for ocelot board.
|
||||
*
|
||||
* 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/mipsregs.h>
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/stackframe.h>
|
||||
|
||||
/*
|
||||
* first level interrupt dispatcher for ocelot board -
|
||||
* We check for the timer first, then check PCI ints A and D.
|
||||
* Then check for serial IRQ and fall through.
|
||||
*/
|
||||
.align 5
|
||||
NESTED(ocelot_handle_int, PT_SIZE, sp)
|
||||
SAVE_ALL
|
||||
CLI
|
||||
.set at
|
||||
mfc0 t0, CP0_CAUSE
|
||||
mfc0 t2, CP0_STATUS
|
||||
|
||||
and t0, t2
|
||||
|
||||
andi t1, t0, STATUSF_IP2 /* int0 hardware line */
|
||||
bnez t1, ll_pri_enet_irq
|
||||
andi t1, t0, STATUSF_IP3 /* int1 hardware line */
|
||||
bnez t1, ll_sec_enet_irq
|
||||
andi t1, t0, STATUSF_IP4 /* int2 hardware line */
|
||||
bnez t1, ll_uart1_irq
|
||||
andi t1, t0, STATUSF_IP5 /* int3 hardware line */
|
||||
bnez t1, ll_cpci_irq
|
||||
andi t1, t0, STATUSF_IP6 /* int4 hardware line */
|
||||
bnez t1, ll_galileo_irq
|
||||
andi t1, t0, STATUSF_IP7 /* cpu timer */
|
||||
bnez t1, ll_cputimer_irq
|
||||
|
||||
/* now look at the extended interrupts */
|
||||
mfc0 t0, CP0_CAUSE
|
||||
cfc0 t1, CP0_S1_INTCONTROL
|
||||
|
||||
/* shift the mask 8 bits left to line up the bits */
|
||||
sll t2, t1, 8
|
||||
|
||||
and t0, t2
|
||||
srl t0, t0, 16
|
||||
|
||||
andi t1, t0, STATUSF_IP8 /* int6 hardware line */
|
||||
bnez t1, ll_pmc1_irq
|
||||
andi t1, t0, STATUSF_IP9 /* int7 hardware line */
|
||||
bnez t1, ll_pmc2_irq
|
||||
andi t1, t0, STATUSF_IP10 /* int8 hardware line */
|
||||
bnez t1, ll_cpci_abcd_irq
|
||||
andi t1, t0, STATUSF_IP11 /* int9 hardware line */
|
||||
bnez t1, ll_uart2_irq
|
||||
|
||||
.set reorder
|
||||
|
||||
/* wrong alarm or masked ... */
|
||||
j spurious_interrupt
|
||||
nop
|
||||
END(ocelot_handle_int)
|
||||
|
||||
.align 5
|
||||
ll_pri_enet_irq:
|
||||
li a0, 2
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
ll_sec_enet_irq:
|
||||
li a0, 3
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
ll_uart1_irq:
|
||||
li a0, 4
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
ll_cpci_irq:
|
||||
li a0, 5
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
ll_galileo_irq:
|
||||
li a0, 6
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
ll_cputimer_irq:
|
||||
li a0, 7
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
ll_pmc1_irq:
|
||||
li a0, 8
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
ll_pmc2_irq:
|
||||
li a0, 9
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
ll_cpci_abcd_irq:
|
||||
li a0, 10
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
||||
|
||||
ll_uart2_irq:
|
||||
li a0, 11
|
||||
move a1, sp
|
||||
jal do_IRQ
|
||||
j ret_from_irq
|
@ -48,7 +48,38 @@
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
extern asmlinkage void ocelot_handle_int(void);
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
unsigned int pending = read_c0_status() & read_c0_cause();
|
||||
|
||||
if (pending & STATUSF_IP2) /* int0 hardware line */
|
||||
do_IRQ(2, regs);
|
||||
else if (pending & STATUSF_IP3) /* int1 hardware line */
|
||||
do_IRQ(3, regs);
|
||||
else if (pending & STATUSF_IP4) /* int2 hardware line */
|
||||
do_IRQ(4, regs);
|
||||
else if (pending & STATUSF_IP5) /* int3 hardware line */
|
||||
do_IRQ(5, regs);
|
||||
else if (pending & STATUSF_IP6) /* int4 hardware line */
|
||||
do_IRQ(6, regs);
|
||||
else if (pending & STATUSF_IP7) /* cpu timer */
|
||||
do_IRQ(7, regs);
|
||||
else {
|
||||
/*
|
||||
* Now look at the extended interrupts
|
||||
*/
|
||||
pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
|
||||
|
||||
if (pending & STATUSF_IP8) /* int6 hardware line */
|
||||
do_IRQ(8, regs);
|
||||
else if (pending & STATUSF_IP9) /* int7 hardware line */
|
||||
do_IRQ(9, regs);
|
||||
else if (pending & STATUSF_IP10) /* int8 hardware line */
|
||||
do_IRQ(10, regs);
|
||||
else if (pending & STATUSF_IP11) /* int9 hardware line */
|
||||
do_IRQ(11, regs);
|
||||
}
|
||||
}
|
||||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
@ -59,9 +90,6 @@ void __init arch_init_irq(void)
|
||||
clear_c0_status(ST0_IM);
|
||||
local_irq_disable();
|
||||
|
||||
/* Sets the first-level interrupt dispatcher. */
|
||||
set_except_vector(0, ocelot_handle_int);
|
||||
|
||||
mips_cpu_irq_init(0);
|
||||
rm7k_cpu_irq_init(8);
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
# Makefile for the ITE 8172 (qed-4n-s01b) board, generic files.
|
||||
#
|
||||
|
||||
obj-y += it8172_setup.o irq.o int-handler.o pmon_prom.o \
|
||||
obj-y += it8172_setup.o irq.o pmon_prom.o \
|
||||
time.o lpc.o puts.o reset.o
|
||||
|
||||
obj-$(CONFIG_IT8172_CIR)+= it8172_cir.o
|
||||
|
@ -1,63 +0,0 @@
|
||||
#include <asm/asm.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/stackframe.h>
|
||||
|
||||
.text
|
||||
.set macro
|
||||
.set noat
|
||||
.align 5
|
||||
|
||||
NESTED(it8172_IRQ, PT_SIZE, sp)
|
||||
SAVE_ALL
|
||||
CLI # Important: mark KERNEL mode !
|
||||
|
||||
/* We're working with 'reorder' set at this point. */
|
||||
/*
|
||||
* Get pending interrupts
|
||||
*/
|
||||
|
||||
mfc0 t0,CP0_CAUSE # get pending interrupts
|
||||
mfc0 t1,CP0_STATUS # get enabled interrupts
|
||||
and t0,t1 # isolate allowed ones
|
||||
|
||||
andi t0,0xff00 # isolate pending bits
|
||||
beqz t0, 3f # spurious interrupt
|
||||
|
||||
andi a0, t0, CAUSEF_IP7
|
||||
beq a0, zero, 1f
|
||||
|
||||
li a0, 127 # MIPS_CPU_TIMER_IRQ = (NR_IRQS-1)
|
||||
move a1, sp
|
||||
jal ll_timer_interrupt
|
||||
j ret_from_irq
|
||||
nop
|
||||
|
||||
1:
|
||||
andi a0, t0, CAUSEF_IP2 # the only int we expect at this time
|
||||
beq a0, zero, 3f
|
||||
move a0,sp
|
||||
jal it8172_hw0_irqdispatch
|
||||
|
||||
mfc0 t0,CP0_STATUS # disable interrupts
|
||||
ori t0,1
|
||||
xori t0,1
|
||||
mtc0 t0,CP0_STATUS
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
la a1, ret_from_irq
|
||||
jr a1
|
||||
nop
|
||||
|
||||
3:
|
||||
move a0, sp
|
||||
jal mips_spurious_interrupt
|
||||
nop
|
||||
la a1, ret_from_irq
|
||||
jr a1
|
||||
nop
|
||||
|
||||
END(it8172_IRQ)
|
||||
|
@ -62,12 +62,8 @@
|
||||
|
||||
#define ALLINTS_NOTIMER (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
|
||||
|
||||
void disable_it8172_irq(unsigned int irq_nr);
|
||||
void enable_it8172_irq(unsigned int irq_nr);
|
||||
|
||||
extern void set_debug_traps(void);
|
||||
extern void mips_timer_interrupt(int irq, struct pt_regs *regs);
|
||||
extern asmlinkage void it8172_IRQ(void);
|
||||
|
||||
struct it8172_intc_regs volatile *it8172_hw0_icregs =
|
||||
(struct it8172_intc_regs volatile *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_INTC_BASE));
|
||||
@ -181,8 +177,6 @@ void __init arch_init_irq(void)
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
set_except_vector(0, it8172_IRQ);
|
||||
|
||||
/* mask all interrupts */
|
||||
it8172_hw0_icregs->lb_mask = 0xffff;
|
||||
it8172_hw0_icregs->lpc_mask = 0xffff;
|
||||
@ -282,6 +276,18 @@ void it8172_hw0_irqdispatch(struct pt_regs *regs)
|
||||
do_IRQ(irq, regs);
|
||||
}
|
||||
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
|
||||
|
||||
if (!pending)
|
||||
mips_spurious_interrupt(regs);
|
||||
else if (pending & CAUSEF_IP7)
|
||||
ll_timer_interrupt(127, regs);
|
||||
else if (pending & CAUSEF_IP2)
|
||||
it8172_hw0_irqdispatch(regs);
|
||||
}
|
||||
|
||||
void show_pending_irqs(void)
|
||||
{
|
||||
fputs("intstatus: ");
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
#include <asm/time.h>
|
||||
#include <asm/mipsregs.h>
|
||||
|
@ -34,13 +34,13 @@
|
||||
#include <asm/bootinfo.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/it8172/it8172.h>
|
||||
#include <asm/it8172/it8172_dbg.h>
|
||||
|
||||
int prom_argc;
|
||||
char **prom_argv, **prom_envp;
|
||||
|
||||
extern char _end;
|
||||
extern void __init prom_init_cmdline(void);
|
||||
extern unsigned long __init prom_get_memsize(void);
|
||||
extern void __init it8172_init_ram_resource(unsigned long memsize);
|
||||
|
@ -34,13 +34,13 @@
|
||||
#include <asm/bootinfo.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/it8172/it8172.h>
|
||||
#include <asm/it8172/it8172_dbg.h>
|
||||
|
||||
int prom_argc;
|
||||
char **prom_argv, **prom_envp;
|
||||
|
||||
extern char _end;
|
||||
extern void __init prom_init_cmdline(void);
|
||||
extern unsigned long __init prom_get_memsize(void);
|
||||
extern void __init it8172_init_ram_resource(unsigned long memsize);
|
||||
|
@ -2,6 +2,6 @@
|
||||
# Makefile for the Jazz family specific parts of the kernel
|
||||
#
|
||||
|
||||
obj-y := int-handler.o irq.o jazzdma.o reset.o setup.o
|
||||
obj-y := irq.o jazzdma.o reset.o setup.o
|
||||
|
||||
EXTRA_AFLAGS := $(CFLAGS)
|
||||
|
@ -1,282 +0,0 @@
|
||||
/*
|
||||
* 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) 1995, 1996, 1997, 1998 by Ralf Baechle and Andreas Busse
|
||||
*
|
||||
* Jazz family specific interrupt stuff
|
||||
*
|
||||
* To do: On Jazz machines we remap some non-ISA interrupts to ISA
|
||||
* interrupts. These interrupts should use their own vectors.
|
||||
* Squeeze the last cycles out of the handlers. Only a dead
|
||||
* cycle is a good cycle.
|
||||
*/
|
||||
#include <asm/asm.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/jazz.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/stackframe.h>
|
||||
|
||||
/*
|
||||
* jazz_handle_int: Interrupt handler for the ACER Pica-61 boards
|
||||
*/
|
||||
.set noreorder
|
||||
|
||||
NESTED(jazz_handle_int, PT_SIZE, ra)
|
||||
.set noat
|
||||
SAVE_ALL
|
||||
CLI
|
||||
.set at
|
||||
|
||||
/*
|
||||
* Get pending interrupts
|
||||
*/
|
||||
mfc0 t0,CP0_CAUSE # get pending interrupts
|
||||
mfc0 t1,CP0_STATUS # get enabled interrupts
|
||||
and t0,t1 # isolate allowed ones
|
||||
andi t0,0xff00 # isolate pending bits
|
||||
beqz t0,3f
|
||||
sll t0,16 # delay slot
|
||||
|
||||
/*
|
||||
* Find irq with highest priority
|
||||
* FIXME: This is slow - use binary search
|
||||
*/
|
||||
la t1,ll_vectors
|
||||
1: bltz t0,2f # found pending irq
|
||||
sll t0,1
|
||||
b 1b
|
||||
subu t1,PTRSIZE # delay slot
|
||||
|
||||
/*
|
||||
* Do the low-level stuff
|
||||
*/
|
||||
2: lw t0,(t1)
|
||||
jr t0
|
||||
nop # delay slot
|
||||
END(jazz_handle_int)
|
||||
|
||||
ll_sw0: li s1,~IE_SW0
|
||||
mfc0 t0,CP0_CAUSE
|
||||
and t0,s1
|
||||
mtc0 t0,CP0_CAUSE
|
||||
PANIC("Unimplemented sw0 handler")
|
||||
|
||||
ll_sw1: li s1,~IE_SW1
|
||||
mfc0 t0,CP0_CAUSE
|
||||
and t0,s1
|
||||
mtc0 t0,CP0_CAUSE
|
||||
PANIC("Unimplemented sw1 handler")
|
||||
|
||||
ll_local_dma: li s1,~IE_IRQ0
|
||||
PANIC("Unimplemented local_dma handler")
|
||||
|
||||
ll_local_dev: lbu t0,JAZZ_IO_IRQ_SOURCE
|
||||
#if PTRSIZE == 8 /* True 64 bit kernel */
|
||||
dsll t0,1
|
||||
#endif
|
||||
.set reorder
|
||||
LONG_L t0,local_vector(t0)
|
||||
jr t0
|
||||
.set noreorder
|
||||
|
||||
/*
|
||||
* The braindead PICA hardware gives us no way to distinguish if we really
|
||||
* received interrupt 7 from the (E)ISA bus or if we just received an
|
||||
* interrupt with no findable cause. This sometimes happens with braindead
|
||||
* cards. Oh well - for all the Jazz boxes slots are more or less just
|
||||
* whistles and bells and we're aware of the problem.
|
||||
*/
|
||||
ll_isa_irq: lw a0, JAZZ_EISA_IRQ_ACK
|
||||
|
||||
jal do_IRQ
|
||||
move a1,sp
|
||||
|
||||
j ret_from_irq
|
||||
nop
|
||||
|
||||
/*
|
||||
* Hmm... This is not just a plain PC clone so the question is
|
||||
* which devices on Jazz machines can generate an (E)ISA NMI?
|
||||
* (Writing to nonexistent memory?)
|
||||
*/
|
||||
ll_isa_nmi: li s1,~IE_IRQ3
|
||||
PANIC("Unimplemented isa_nmi handler")
|
||||
|
||||
/*
|
||||
* Timer IRQ - remapped to be more similar to an IBM compatible.
|
||||
*
|
||||
* The timer interrupt is handled specially to ensure that the jiffies
|
||||
* variable is updated at all times. Specifically, the timer interrupt is
|
||||
* just like the complete handlers except that it is invoked with interrupts
|
||||
* disabled and should never re-enable them. If other interrupts were
|
||||
* allowed to be processed while the timer interrupt is active, then the
|
||||
* other interrupts would have to avoid using the jiffies variable for delay
|
||||
* and interval timing operations to avoid hanging the system.
|
||||
*/
|
||||
ll_timer: lw zero,JAZZ_TIMER_REGISTER # timer irq cleared on read
|
||||
li s1,~IE_IRQ4
|
||||
|
||||
li a0, JAZZ_TIMER_IRQ
|
||||
jal do_IRQ
|
||||
move a1,sp
|
||||
|
||||
mfc0 t0,CP0_STATUS # disable interrupts again
|
||||
ori t0,1
|
||||
xori t0,1
|
||||
mtc0 t0,CP0_STATUS
|
||||
|
||||
j ret_from_irq
|
||||
nop
|
||||
|
||||
/*
|
||||
* CPU count/compare IRQ (unused)
|
||||
*/
|
||||
ll_count: j ret_from_irq
|
||||
mtc0 zero,CP0_COMPARE
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Call the handler for the interrupt
|
||||
* (Currently unused)
|
||||
*/
|
||||
call_real: /*
|
||||
* temporarily disable interrupt
|
||||
*/
|
||||
mfc0 t2,CP0_STATUS
|
||||
and t2,s1
|
||||
mtc0 t2,CP0_STATUS
|
||||
nor s1,zero,s1
|
||||
jal do_IRQ
|
||||
|
||||
/*
|
||||
* reenable interrupt
|
||||
*/
|
||||
mfc0 t2,CP0_STATUS
|
||||
or t2,s1
|
||||
mtc0 t2,CP0_STATUS
|
||||
j ret_from_irq
|
||||
#endif
|
||||
|
||||
.data
|
||||
PTR ll_sw0 # SW0
|
||||
PTR ll_sw1 # SW1
|
||||
PTR ll_local_dma # Local DMA
|
||||
PTR ll_local_dev # Local devices
|
||||
PTR ll_isa_irq # ISA IRQ
|
||||
PTR ll_isa_nmi # ISA NMI
|
||||
PTR ll_timer # Timer
|
||||
ll_vectors: PTR ll_count # Count/Compare IRQ
|
||||
|
||||
/*
|
||||
* Interrupt handlers for local devices.
|
||||
*/
|
||||
.text
|
||||
.set reorder
|
||||
loc_no_irq: PANIC("Unimplemented loc_no_irq handler")
|
||||
/*
|
||||
* Parallel port IRQ
|
||||
*/
|
||||
loc_parallel: li s1,~JAZZ_IE_PARALLEL
|
||||
li a0,JAZZ_PARALLEL_IRQ
|
||||
b loc_call
|
||||
|
||||
/*
|
||||
* Floppy IRQ
|
||||
*/
|
||||
loc_floppy: li s1,~JAZZ_IE_FLOPPY
|
||||
li a0,JAZZ_FLOPPY_IRQ
|
||||
b loc_call
|
||||
|
||||
/*
|
||||
* Sound IRQ
|
||||
*/
|
||||
loc_sound: PANIC("Unimplemented loc_sound handler")
|
||||
loc_video: PANIC("Unimplemented loc_video handler")
|
||||
|
||||
/*
|
||||
* Ethernet interrupt handler
|
||||
*/
|
||||
loc_ethernet: li s1,~JAZZ_IE_ETHERNET
|
||||
li a0,JAZZ_ETHERNET_IRQ
|
||||
b loc_call
|
||||
|
||||
/*
|
||||
* SCSI interrupt handler
|
||||
*/
|
||||
loc_scsi: li s1,~JAZZ_IE_SCSI
|
||||
li a0,JAZZ_SCSI_IRQ
|
||||
b loc_call
|
||||
|
||||
/*
|
||||
* Keyboard interrupt handler
|
||||
*/
|
||||
loc_keyboard: li s1,~JAZZ_IE_KEYBOARD
|
||||
li a0,JAZZ_KEYBOARD_IRQ
|
||||
b loc_call
|
||||
|
||||
/*
|
||||
* Mouse interrupt handler
|
||||
*/
|
||||
loc_mouse: li s1,~JAZZ_IE_MOUSE
|
||||
li a0,JAZZ_MOUSE_IRQ
|
||||
b loc_call
|
||||
|
||||
/*
|
||||
* Serial port 1 IRQ
|
||||
*/
|
||||
loc_serial1: li s1,~JAZZ_IE_SERIAL1
|
||||
li a0,JAZZ_SERIAL1_IRQ
|
||||
b loc_call
|
||||
|
||||
/*
|
||||
* Serial port 2 IRQ
|
||||
*/
|
||||
loc_serial2: li s1,~JAZZ_IE_SERIAL2
|
||||
li a0,JAZZ_SERIAL2_IRQ
|
||||
b loc_call
|
||||
|
||||
/*
|
||||
* Call the interrupt handler for an interrupt generated by a
|
||||
* local device.
|
||||
*/
|
||||
loc_call: /*
|
||||
* Temporarily disable interrupt source
|
||||
*/
|
||||
lhu t2,JAZZ_IO_IRQ_ENABLE
|
||||
and t2,s1
|
||||
sh t2,JAZZ_IO_IRQ_ENABLE
|
||||
|
||||
nor s1,zero,s1
|
||||
jal do_IRQ
|
||||
|
||||
/*
|
||||
* Reenable interrupt
|
||||
*/
|
||||
lhu t2,JAZZ_IO_IRQ_ENABLE
|
||||
or t2,s1
|
||||
sh t2,JAZZ_IO_IRQ_ENABLE
|
||||
|
||||
j ret_from_irq
|
||||
|
||||
/*
|
||||
* "Jump extender" to reach spurious_interrupt
|
||||
*/
|
||||
3: j spurious_interrupt
|
||||
|
||||
/*
|
||||
* Vectors for interrupts generated by local devices
|
||||
*/
|
||||
.data
|
||||
local_vector: PTR loc_no_irq
|
||||
PTR loc_parallel
|
||||
PTR loc_floppy
|
||||
PTR loc_sound
|
||||
PTR loc_video
|
||||
PTR loc_ethernet
|
||||
PTR loc_scsi
|
||||
PTR loc_keyboard
|
||||
PTR loc_mouse
|
||||
PTR loc_serial1
|
||||
PTR loc_serial2
|
@ -15,8 +15,6 @@
|
||||
#include <asm/io.h>
|
||||
#include <asm/jazz.h>
|
||||
|
||||
extern asmlinkage void jazz_handle_int(void);
|
||||
|
||||
static DEFINE_SPINLOCK(r4030_lock);
|
||||
|
||||
static void enable_r4030_irq(unsigned int irq)
|
||||
@ -90,10 +88,82 @@ void __init init_r4030_ints(void)
|
||||
*/
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
set_except_vector(0, jazz_handle_int);
|
||||
|
||||
init_i8259_irqs(); /* Integrated i8259 */
|
||||
init_r4030_ints();
|
||||
|
||||
change_c0_status(ST0_IM, IE_IRQ4 | IE_IRQ3 | IE_IRQ2 | IE_IRQ1);
|
||||
}
|
||||
|
||||
static void loc_call(unsigned int irq, struct pt_regs *regs, unsigned int mask)
|
||||
{
|
||||
r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
|
||||
r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) & mask);
|
||||
do_IRQ(irq, regs);
|
||||
r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
|
||||
r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | mask);
|
||||
}
|
||||
|
||||
static void ll_local_dev(struct pt_regs *regs)
|
||||
{
|
||||
switch (r4030_read_reg32(JAZZ_IO_IRQ_SOURCE)) {
|
||||
case 0:
|
||||
panic("Unimplemented loc_no_irq handler");
|
||||
break;
|
||||
case 4:
|
||||
loc_call(JAZZ_PARALLEL_IRQ, regs, JAZZ_IE_PARALLEL);
|
||||
break;
|
||||
case 8:
|
||||
loc_call(JAZZ_PARALLEL_IRQ, regs, JAZZ_IE_FLOPPY);
|
||||
break;
|
||||
case 12:
|
||||
panic("Unimplemented loc_sound handler");
|
||||
break;
|
||||
case 16:
|
||||
panic("Unimplemented loc_video handler");
|
||||
break;
|
||||
case 20:
|
||||
loc_call(JAZZ_ETHERNET_IRQ, regs, JAZZ_IE_ETHERNET);
|
||||
break;
|
||||
case 24:
|
||||
loc_call(JAZZ_SCSI_IRQ, regs, JAZZ_IE_SCSI);
|
||||
break;
|
||||
case 28:
|
||||
loc_call(JAZZ_KEYBOARD_IRQ, regs, JAZZ_IE_KEYBOARD);
|
||||
break;
|
||||
case 32:
|
||||
loc_call(JAZZ_MOUSE_IRQ, regs, JAZZ_IE_MOUSE);
|
||||
break;
|
||||
case 36:
|
||||
loc_call(JAZZ_SERIAL1_IRQ, regs, JAZZ_IE_SERIAL1);
|
||||
break;
|
||||
case 40:
|
||||
loc_call(JAZZ_SERIAL2_IRQ, regs, JAZZ_IE_SERIAL2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
|
||||
|
||||
if (pending & IE_IRQ5)
|
||||
write_c0_compare(0);
|
||||
else if (pending & IE_IRQ4) {
|
||||
r4030_read_reg32(JAZZ_TIMER_REGISTER);
|
||||
do_IRQ(JAZZ_TIMER_IRQ, regs);
|
||||
} else if (pending & IE_IRQ3)
|
||||
panic("Unimplemented ISA NMI handler");
|
||||
else if (pending & IE_IRQ2)
|
||||
do_IRQ(r4030_read_reg32(JAZZ_EISA_IRQ_ACK), regs);
|
||||
else if (pending & IE_IRQ1) {
|
||||
ll_local_dev(regs);
|
||||
} else if (unlikely(pending & IE_IRQ0))
|
||||
panic("Unimplemented local_dma handler");
|
||||
else if (pending & IE_SW1) {
|
||||
clear_c0_cause(IE_SW1);
|
||||
panic("Unimplemented sw1 handler");
|
||||
} else if (pending & IE_SW0) {
|
||||
clear_c0_cause(IE_SW0);
|
||||
panic("Unimplemented sw0 handler");
|
||||
}
|
||||
}
|
||||
|
@ -60,15 +60,15 @@ rtc_ds1742_get_time(void)
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
CMOS_WRITE(RTC_READ, RTC_CONTROL);
|
||||
second = BCD2BIN(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK);
|
||||
minute = BCD2BIN(CMOS_READ(RTC_MINUTES));
|
||||
hour = BCD2BIN(CMOS_READ(RTC_HOURS));
|
||||
day = BCD2BIN(CMOS_READ(RTC_DATE));
|
||||
month = BCD2BIN(CMOS_READ(RTC_MONTH));
|
||||
year = BCD2BIN(CMOS_READ(RTC_YEAR));
|
||||
century = BCD2BIN(CMOS_READ(RTC_CENTURY) & RTC_CENTURY_MASK);
|
||||
CMOS_WRITE(0, RTC_CONTROL);
|
||||
rtc_write(RTC_READ, RTC_CONTROL);
|
||||
second = BCD2BIN(rtc_read(RTC_SECONDS) & RTC_SECONDS_MASK);
|
||||
minute = BCD2BIN(rtc_read(RTC_MINUTES));
|
||||
hour = BCD2BIN(rtc_read(RTC_HOURS));
|
||||
day = BCD2BIN(rtc_read(RTC_DATE));
|
||||
month = BCD2BIN(rtc_read(RTC_MONTH));
|
||||
year = BCD2BIN(rtc_read(RTC_YEAR));
|
||||
century = BCD2BIN(rtc_read(RTC_CENTURY) & RTC_CENTURY_MASK);
|
||||
rtc_write(0, RTC_CONTROL);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
|
||||
year += century * 100;
|
||||
@ -87,16 +87,16 @@ rtc_ds1742_set_time(unsigned long t)
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
CMOS_WRITE(RTC_READ, RTC_CONTROL);
|
||||
cmos_second = (u8)(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK);
|
||||
cmos_minute = (u8)CMOS_READ(RTC_MINUTES);
|
||||
cmos_hour = (u8)CMOS_READ(RTC_HOURS);
|
||||
cmos_day = (u8)CMOS_READ(RTC_DATE);
|
||||
cmos_month = (u8)CMOS_READ(RTC_MONTH);
|
||||
cmos_year = (u8)CMOS_READ(RTC_YEAR);
|
||||
cmos_century = CMOS_READ(RTC_CENTURY) & RTC_CENTURY_MASK;
|
||||
rtc_write(RTC_READ, RTC_CONTROL);
|
||||
cmos_second = (u8)(rtc_read(RTC_SECONDS) & RTC_SECONDS_MASK);
|
||||
cmos_minute = (u8)rtc_read(RTC_MINUTES);
|
||||
cmos_hour = (u8)rtc_read(RTC_HOURS);
|
||||
cmos_day = (u8)rtc_read(RTC_DATE);
|
||||
cmos_month = (u8)rtc_read(RTC_MONTH);
|
||||
cmos_year = (u8)rtc_read(RTC_YEAR);
|
||||
cmos_century = rtc_read(RTC_CENTURY) & RTC_CENTURY_MASK;
|
||||
|
||||
CMOS_WRITE(RTC_WRITE, RTC_CONTROL);
|
||||
rtc_write(RTC_WRITE, RTC_CONTROL);
|
||||
|
||||
/* convert */
|
||||
to_tm(t, &tm);
|
||||
@ -104,18 +104,18 @@ rtc_ds1742_set_time(unsigned long t)
|
||||
/* check each field one by one */
|
||||
year = BIN2BCD(tm.tm_year - EPOCH);
|
||||
if (year != cmos_year) {
|
||||
CMOS_WRITE(year,RTC_YEAR);
|
||||
rtc_write(year,RTC_YEAR);
|
||||
}
|
||||
|
||||
month = BIN2BCD(tm.tm_mon);
|
||||
if (month != (cmos_month & 0x1f)) {
|
||||
CMOS_WRITE((month & 0x1f) | (cmos_month & ~0x1f),RTC_MONTH);
|
||||
rtc_write((month & 0x1f) | (cmos_month & ~0x1f),RTC_MONTH);
|
||||
}
|
||||
|
||||
day = BIN2BCD(tm.tm_mday);
|
||||
if (day != cmos_day) {
|
||||
|
||||
CMOS_WRITE(day, RTC_DATE);
|
||||
rtc_write(day, RTC_DATE);
|
||||
}
|
||||
|
||||
if (cmos_hour & 0x40) {
|
||||
@ -130,20 +130,20 @@ rtc_ds1742_set_time(unsigned long t)
|
||||
/* 24 hour format */
|
||||
hour = BIN2BCD(tm.tm_hour) & 0x3f;
|
||||
}
|
||||
if (hour != cmos_hour) CMOS_WRITE(hour, RTC_HOURS);
|
||||
if (hour != cmos_hour) rtc_write(hour, RTC_HOURS);
|
||||
|
||||
minute = BIN2BCD(tm.tm_min);
|
||||
if (minute != cmos_minute) {
|
||||
CMOS_WRITE(minute, RTC_MINUTES);
|
||||
rtc_write(minute, RTC_MINUTES);
|
||||
}
|
||||
|
||||
second = BIN2BCD(tm.tm_sec);
|
||||
if (second != cmos_second) {
|
||||
CMOS_WRITE(second & RTC_SECONDS_MASK,RTC_SECONDS);
|
||||
rtc_write(second & RTC_SECONDS_MASK,RTC_SECONDS);
|
||||
}
|
||||
|
||||
/* RTC_CENTURY and RTC_CONTROL share same address... */
|
||||
CMOS_WRITE(cmos_century, RTC_CONTROL);
|
||||
rtc_write(cmos_century, RTC_CONTROL);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
|
||||
return 0;
|
||||
@ -163,9 +163,9 @@ rtc_ds1742_init(unsigned long base)
|
||||
rtc_mips_set_time = rtc_ds1742_set_time;
|
||||
|
||||
/* clear oscillator stop bit */
|
||||
CMOS_WRITE(RTC_READ, RTC_CONTROL);
|
||||
cmos_second = (u8)(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK);
|
||||
CMOS_WRITE(RTC_WRITE, RTC_CONTROL);
|
||||
CMOS_WRITE(cmos_second, RTC_SECONDS); /* clear msb */
|
||||
CMOS_WRITE(0, RTC_CONTROL);
|
||||
rtc_write(RTC_READ, RTC_CONTROL);
|
||||
cmos_second = (u8)(rtc_read(RTC_SECONDS) & RTC_SECONDS_MASK);
|
||||
rtc_write(RTC_WRITE, RTC_CONTROL);
|
||||
rtc_write(cmos_second, RTC_SECONDS); /* clear msb */
|
||||
rtc_write(0, RTC_CONTROL);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Makefile for TOSHIBA JMR-TX3927 board
|
||||
#
|
||||
|
||||
obj-y += init.o int-handler.o irq.o setup.o
|
||||
obj-y += init.o irq.o setup.o
|
||||
obj-$(CONFIG_RUNTIME_DEBUG) += debug.o
|
||||
obj-$(CONFIG_KGDB) += kgdb_io.o
|
||||
|
||||
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright 2001 MontaVista Software Inc.
|
||||
* Author: MontaVista Software, Inc.
|
||||
* ahennessy@mvista.com
|
||||
*
|
||||
* Based on arch/mips/tsdb/kernel/int-handler.S
|
||||
*
|
||||
* Copyright (C) 2000-2001 Toshiba Corporation
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <asm/asm.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/stackframe.h>
|
||||
#include <asm/jmr3927/jmr3927.h>
|
||||
|
||||
/* A lot of complication here is taken away because:
|
||||
*
|
||||
* 1) We handle one interrupt and return, sitting in a loop
|
||||
* and moving across all the pending IRQ bits in the cause
|
||||
* register is _NOT_ the answer, the common case is one
|
||||
* pending IRQ so optimize in that direction.
|
||||
*
|
||||
* 2) We need not check against bits in the status register
|
||||
* IRQ mask, that would make this routine slow as hell.
|
||||
*
|
||||
* 3) Linux only thinks in terms of all IRQs on or all IRQs
|
||||
* off, nothing in between like BSD spl() brain-damage.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Flush write buffer (needed?)
|
||||
* NOTE: TX39xx performs "non-blocking load", so explicitly use the target
|
||||
* register of LBU to flush immediately.
|
||||
*/
|
||||
#define FLUSH_WB(tmp) \
|
||||
la tmp, JMR3927_IOC_REV_ADDR; \
|
||||
lbu tmp, (tmp); \
|
||||
move tmp, zero;
|
||||
|
||||
.text
|
||||
.set noreorder
|
||||
.set noat
|
||||
.align 5
|
||||
NESTED(jmr3927_IRQ, PT_SIZE, sp)
|
||||
SAVE_ALL
|
||||
CLI
|
||||
.set at
|
||||
jal jmr3927_irc_irqdispatch
|
||||
move a0, sp
|
||||
FLUSH_WB(t0)
|
||||
j ret_from_irq
|
||||
nop
|
||||
END(jmr3927_IRQ)
|
@ -77,8 +77,6 @@ static int jmr3927_gen_iack(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
extern asmlinkage void jmr3927_IRQ(void);
|
||||
|
||||
#define irc_dlevel 0
|
||||
#define irc_elevel 1
|
||||
|
||||
@ -262,7 +260,7 @@ void jmr3927_spurious(struct pt_regs *regs)
|
||||
regs->cp0_cause, regs->cp0_epc, regs->regs[31]);
|
||||
}
|
||||
|
||||
void jmr3927_irc_irqdispatch(struct pt_regs *regs)
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
int irq;
|
||||
|
||||
@ -398,8 +396,6 @@ void __init arch_init_irq(void)
|
||||
|
||||
jmr3927_irq_init(NR_ISA_IRQS);
|
||||
|
||||
set_except_vector(0, jmr3927_IRQ);
|
||||
|
||||
/* setup irq space */
|
||||
add_tb_irq_space(&jmr3927_isac_irqspace);
|
||||
add_tb_irq_space(&jmr3927_ioc_irqspace);
|
||||
|
@ -34,8 +34,11 @@ obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o
|
||||
|
||||
obj-$(CONFIG_SMP) += smp.o
|
||||
|
||||
obj-$(CONFIG_MIPS_MT_SMP) += smp_mt.o
|
||||
obj-$(CONFIG_MIPS_MT) += mips-mt.o
|
||||
obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o
|
||||
obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o
|
||||
|
||||
obj-$(CONFIG_MIPS_APSP_KSPD) += kspd.o
|
||||
obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o
|
||||
obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o
|
||||
|
||||
|
@ -69,6 +69,9 @@ void output_ptreg_defines(void)
|
||||
offset("#define PT_BVADDR ", struct pt_regs, cp0_badvaddr);
|
||||
offset("#define PT_STATUS ", struct pt_regs, cp0_status);
|
||||
offset("#define PT_CAUSE ", struct pt_regs, cp0_cause);
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
offset("#define PT_TCSTATUS ", struct pt_regs, cp0_tcstatus);
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
size("#define PT_SIZE ", struct pt_regs);
|
||||
linefeed;
|
||||
}
|
||||
|
@ -17,6 +17,9 @@
|
||||
#include <asm/isadep.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/war.h>
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
#include <asm/mipsmtregs.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PREEMPT
|
||||
.macro preempt_stop
|
||||
@ -75,6 +78,37 @@ FEXPORT(syscall_exit)
|
||||
bnez t0, syscall_exit_work
|
||||
|
||||
FEXPORT(restore_all) # restore full frame
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
/* Detect and execute deferred IPI "interrupts" */
|
||||
move a0,sp
|
||||
jal deferred_smtc_ipi
|
||||
/* Re-arm any temporarily masked interrupts not explicitly "acked" */
|
||||
mfc0 v0, CP0_TCSTATUS
|
||||
ori v1, v0, TCSTATUS_IXMT
|
||||
mtc0 v1, CP0_TCSTATUS
|
||||
andi v0, TCSTATUS_IXMT
|
||||
ehb
|
||||
mfc0 t0, CP0_TCCONTEXT
|
||||
DMT 9 # dmt t1
|
||||
jal mips_ihb
|
||||
mfc0 t2, CP0_STATUS
|
||||
andi t3, t0, 0xff00
|
||||
or t2, t2, t3
|
||||
mtc0 t2, CP0_STATUS
|
||||
ehb
|
||||
andi t1, t1, VPECONTROL_TE
|
||||
beqz t1, 1f
|
||||
EMT
|
||||
1:
|
||||
mfc0 v1, CP0_TCSTATUS
|
||||
/* We set IXMT above, XOR should cler it here */
|
||||
xori v1, v1, TCSTATUS_IXMT
|
||||
or v1, v0, v1
|
||||
mtc0 v1, CP0_TCSTATUS
|
||||
ehb
|
||||
xor t0, t0, t3
|
||||
mtc0 t0, CP0_TCCONTEXT
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
.set noat
|
||||
RESTORE_TEMP
|
||||
RESTORE_AT
|
||||
@ -120,28 +154,17 @@ syscall_exit_work:
|
||||
jal do_syscall_trace
|
||||
b resume_userspace
|
||||
|
||||
#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_MIPS_MT)
|
||||
|
||||
/*
|
||||
* Common spurious interrupt handler.
|
||||
* MIPS32R2 Instruction Hazard Barrier - must be called
|
||||
*
|
||||
* For C code use the inline version named instruction_hazard().
|
||||
*/
|
||||
LEAF(spurious_interrupt)
|
||||
/*
|
||||
* Someone tried to fool us by sending an interrupt but we
|
||||
* couldn't find a cause for it.
|
||||
*/
|
||||
PTR_LA t1, irq_err_count
|
||||
#ifdef CONFIG_SMP
|
||||
1: ll t0, (t1)
|
||||
addiu t0, 1
|
||||
sc t0, (t1)
|
||||
#if R10000_LLSC_WAR
|
||||
beqzl t0, 1b
|
||||
#else
|
||||
beqz t0, 1b
|
||||
#endif
|
||||
#else
|
||||
lw t0, (t1)
|
||||
addiu t0, 1
|
||||
sw t0, (t1)
|
||||
#endif
|
||||
j ret_from_irq
|
||||
END(spurious_interrupt)
|
||||
LEAF(mips_ihb)
|
||||
.set mips32r2
|
||||
jr.hb ra
|
||||
nop
|
||||
END(mips_ihb)
|
||||
|
||||
#endif /* CONFIG_CPU_MIPSR2 or CONFIG_MIPS_MT */
|
||||
|
@ -283,11 +283,33 @@
|
||||
*/
|
||||
|
||||
3:
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
/* Read-modify write of Status must be atomic */
|
||||
mfc0 t2, CP0_TCSTATUS
|
||||
ori t1, t2, TCSTATUS_IXMT
|
||||
mtc0 t1, CP0_TCSTATUS
|
||||
andi t2, t2, TCSTATUS_IXMT
|
||||
ehb
|
||||
DMT 9 # dmt t1
|
||||
jal mips_ihb
|
||||
nop
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
mfc0 t0, CP0_STATUS
|
||||
ori t0, 0x1f
|
||||
xori t0, 0x1f
|
||||
mtc0 t0, CP0_STATUS
|
||||
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
andi t1, t1, VPECONTROL_TE
|
||||
beqz t1, 9f
|
||||
nop
|
||||
EMT # emt
|
||||
9:
|
||||
mfc0 t1, CP0_TCSTATUS
|
||||
xori t1, t1, TCSTATUS_IXMT
|
||||
or t1, t1, t2
|
||||
mtc0 t1, CP0_TCSTATUS
|
||||
ehb
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
LONG_L v0, GDB_FR_STATUS(sp)
|
||||
LONG_L v1, GDB_FR_EPC(sp)
|
||||
mtc0 v0, CP0_STATUS
|
||||
|
@ -140,6 +140,7 @@
|
||||
#include <asm/system.h>
|
||||
#include <asm/gdb-stub.h>
|
||||
#include <asm/inst.h>
|
||||
#include <asm/smp.h>
|
||||
|
||||
/*
|
||||
* external low-level support routines
|
||||
@ -669,6 +670,64 @@ static void kgdb_wait(void *arg)
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* GDB stub needs to call kgdb_wait on all processor with interrupts
|
||||
* disabled, so it uses it's own special variant.
|
||||
*/
|
||||
static int kgdb_smp_call_kgdb_wait(void)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
struct call_data_struct data;
|
||||
int i, cpus = num_online_cpus() - 1;
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
/*
|
||||
* Can die spectacularly if this CPU isn't yet marked online
|
||||
*/
|
||||
BUG_ON(!cpu_online(cpu));
|
||||
|
||||
if (!cpus)
|
||||
return 0;
|
||||
|
||||
if (spin_is_locked(&smp_call_lock)) {
|
||||
/*
|
||||
* Some other processor is trying to make us do something
|
||||
* but we're not going to respond... give up
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We will continue here, accepting the fact that
|
||||
* the kernel may deadlock if another CPU attempts
|
||||
* to call smp_call_function now...
|
||||
*/
|
||||
|
||||
data.func = kgdb_wait;
|
||||
data.info = NULL;
|
||||
atomic_set(&data.started, 0);
|
||||
data.wait = 0;
|
||||
|
||||
spin_lock(&smp_call_lock);
|
||||
call_data = &data;
|
||||
mb();
|
||||
|
||||
/* Send a message to all other CPUs and wait for them to respond */
|
||||
for (i = 0; i < NR_CPUS; i++)
|
||||
if (cpu_online(i) && i != cpu)
|
||||
core_send_ipi(i, SMP_CALL_FUNCTION);
|
||||
|
||||
/* Wait for response */
|
||||
/* FIXME: lock-up detection, backtrace on lock-up */
|
||||
while (atomic_read(&data.started) != cpus)
|
||||
barrier();
|
||||
|
||||
call_data = NULL;
|
||||
spin_unlock(&smp_call_lock);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function does all command processing for interfacing to gdb. It
|
||||
@ -718,7 +777,7 @@ void handle_exception (struct gdb_regs *regs)
|
||||
/*
|
||||
* force other cpus to enter kgdb
|
||||
*/
|
||||
smp_call_function(kgdb_wait, NULL, 0, 0);
|
||||
kgdb_smp_call_kgdb_wait();
|
||||
|
||||
/*
|
||||
* If we're in breakpoint() increment the PC
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/asm.h>
|
||||
#include <asm/asmmacro.h>
|
||||
#include <asm/cacheops.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/fpregdef.h>
|
||||
@ -122,6 +123,20 @@ handle_vcei:
|
||||
.set pop
|
||||
END(except_vec3_r4000)
|
||||
|
||||
__FINIT
|
||||
|
||||
.align 5
|
||||
NESTED(handle_int, PT_SIZE, sp)
|
||||
SAVE_ALL
|
||||
CLI
|
||||
|
||||
PTR_LA ra, ret_from_irq
|
||||
move a0, sp
|
||||
j plat_irq_dispatch
|
||||
END(handle_int)
|
||||
|
||||
__INIT
|
||||
|
||||
/*
|
||||
* Special interrupt vector for MIPS64 ISA & embedded MIPS processors.
|
||||
* This is a dedicated interrupt exception vector which reduces the
|
||||
@ -157,6 +172,15 @@ NESTED(except_vec_vi, 0, sp)
|
||||
SAVE_AT
|
||||
.set push
|
||||
.set noreorder
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
/*
|
||||
* To keep from blindly blocking *all* interrupts
|
||||
* during service by SMTC kernel, we also want to
|
||||
* pass the IM value to be cleared.
|
||||
*/
|
||||
EXPORT(except_vec_vi_mori)
|
||||
ori a0, $0, 0
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
EXPORT(except_vec_vi_lui)
|
||||
lui v0, 0 /* Patched */
|
||||
j except_vec_vi_handler
|
||||
@ -173,6 +197,25 @@ EXPORT(except_vec_vi_end)
|
||||
NESTED(except_vec_vi_handler, 0, sp)
|
||||
SAVE_TEMP
|
||||
SAVE_STATIC
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
/*
|
||||
* SMTC has an interesting problem that interrupts are level-triggered,
|
||||
* and the CLI macro will clear EXL, potentially causing a duplicate
|
||||
* interrupt service invocation. So we need to clear the associated
|
||||
* IM bit of Status prior to doing CLI, and restore it after the
|
||||
* service routine has been invoked - we must assume that the
|
||||
* service routine will have cleared the state, and any active
|
||||
* level represents a new or otherwised unserviced event...
|
||||
*/
|
||||
mfc0 t1, CP0_STATUS
|
||||
and t0, a0, t1
|
||||
mfc0 t2, CP0_TCCONTEXT
|
||||
or t0, t0, t2
|
||||
mtc0 t0, CP0_TCCONTEXT
|
||||
xor t1, t1, t0
|
||||
mtc0 t1, CP0_STATUS
|
||||
ehb
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
CLI
|
||||
move a0, sp
|
||||
jalr v0
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/threads.h>
|
||||
|
||||
#include <asm/asm.h>
|
||||
#include <asm/asmmacro.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/mipsregs.h>
|
||||
@ -82,12 +83,33 @@
|
||||
*/
|
||||
.macro setup_c0_status set clr
|
||||
.set push
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
/*
|
||||
* For SMTC, we need to set privilege and disable interrupts only for
|
||||
* the current TC, using the TCStatus register.
|
||||
*/
|
||||
mfc0 t0, CP0_TCSTATUS
|
||||
/* Fortunately CU 0 is in the same place in both registers */
|
||||
/* Set TCU0, TMX, TKSU (for later inversion) and IXMT */
|
||||
li t1, ST0_CU0 | 0x08001c00
|
||||
or t0, t1
|
||||
/* Clear TKSU, leave IXMT */
|
||||
xori t0, 0x00001800
|
||||
mtc0 t0, CP0_TCSTATUS
|
||||
ehb
|
||||
/* We need to leave the global IE bit set, but clear EXL...*/
|
||||
mfc0 t0, CP0_STATUS
|
||||
or t0, ST0_CU0 | ST0_EXL | ST0_ERL | \set | \clr
|
||||
xor t0, ST0_EXL | ST0_ERL | \clr
|
||||
mtc0 t0, CP0_STATUS
|
||||
#else
|
||||
mfc0 t0, CP0_STATUS
|
||||
or t0, ST0_CU0|\set|0x1f|\clr
|
||||
xor t0, 0x1f|\clr
|
||||
mtc0 t0, CP0_STATUS
|
||||
.set noreorder
|
||||
sll zero,3 # ehb
|
||||
#endif
|
||||
.set pop
|
||||
.endm
|
||||
|
||||
@ -134,6 +156,24 @@ NESTED(kernel_entry, 16, sp) # kernel entry point
|
||||
|
||||
ARC64_TWIDDLE_PC
|
||||
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
/*
|
||||
* In SMTC kernel, "CLI" is thread-specific, in TCStatus.
|
||||
* We still need to enable interrupts globally in Status,
|
||||
* and clear EXL/ERL.
|
||||
*
|
||||
* TCContext is used to track interrupt levels under
|
||||
* service in SMTC kernel. Clear for boot TC before
|
||||
* allowing any interrupts.
|
||||
*/
|
||||
mtc0 zero, CP0_TCCONTEXT
|
||||
|
||||
mfc0 t0, CP0_STATUS
|
||||
ori t0, t0, 0xff1f
|
||||
xori t0, t0, 0x001e
|
||||
mtc0 t0, CP0_STATUS
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
PTR_LA t0, __bss_start # clear .bss
|
||||
LONG_S zero, (t0)
|
||||
PTR_LA t1, __bss_stop - LONGSIZE
|
||||
@ -166,8 +206,25 @@ NESTED(kernel_entry, 16, sp) # kernel entry point
|
||||
* function after setting up the stack and gp registers.
|
||||
*/
|
||||
NESTED(smp_bootstrap, 16, sp)
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
/*
|
||||
* Read-modify-writes of Status must be atomic, and this
|
||||
* is one case where CLI is invoked without EXL being
|
||||
* necessarily set. The CLI and setup_c0_status will
|
||||
* in fact be redundant for all but the first TC of
|
||||
* each VPE being booted.
|
||||
*/
|
||||
DMT 10 # dmt t2 /* t0, t1 are used by CLI and setup_c0_status() */
|
||||
jal mips_ihb
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
setup_c0_status_sec
|
||||
smp_slave_setup
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
andi t2, t2, VPECONTROL_TE
|
||||
beqz t2, 2f
|
||||
EMT # emt
|
||||
2:
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
j start_secondary
|
||||
END(smp_bootstrap)
|
||||
#endif /* CONFIG_SMP */
|
||||
|
@ -187,6 +187,10 @@ handle_real_irq:
|
||||
outb(cached_21,0x21);
|
||||
outb(0x60+irq,0x20); /* 'Specific EOI' to master */
|
||||
}
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
if (irq_hwmask[irq] & ST0_IM)
|
||||
set_c0_status(irq_hwmask[irq] & ST0_IM);
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
spin_unlock_irqrestore(&i8259A_lock, flags);
|
||||
return;
|
||||
|
||||
|
@ -76,6 +76,11 @@ static void level_mask_and_ack_msc_irq(unsigned int irq)
|
||||
mask_msc_irq(irq);
|
||||
if (!cpu_has_veic)
|
||||
MSCIC_WRITE(MSC01_IC_EOI, 0);
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
/* This actually needs to be a call into platform code */
|
||||
if (irq_hwmask[irq] & ST0_IM)
|
||||
set_c0_status(irq_hwmask[irq] & ST0_IM);
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
}
|
||||
|
||||
/*
|
||||
@ -92,6 +97,10 @@ static void edge_mask_and_ack_msc_irq(unsigned int irq)
|
||||
MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT);
|
||||
MSCIC_WRITE(MSC01_IC_SUP+irq*8, r);
|
||||
}
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
if (irq_hwmask[irq] & ST0_IM)
|
||||
set_c0_status(irq_hwmask[irq] & ST0_IM);
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -38,6 +38,15 @@ void ack_bad_irq(unsigned int irq)
|
||||
|
||||
atomic_t irq_err_count;
|
||||
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
/*
|
||||
* SMTC Kernel needs to manipulate low-level CPU interrupt mask
|
||||
* in do_IRQ. These are passed in setup_irq_smtc() and stored
|
||||
* in this table.
|
||||
*/
|
||||
unsigned long irq_hwmask[NR_IRQS];
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
#undef do_IRQ
|
||||
|
||||
/*
|
||||
@ -49,6 +58,7 @@ asmlinkage unsigned int do_IRQ(unsigned int irq, struct pt_regs *regs)
|
||||
{
|
||||
irq_enter();
|
||||
|
||||
__DO_IRQ_SMTC_HOOK();
|
||||
__do_IRQ(irq, regs);
|
||||
|
||||
irq_exit();
|
||||
@ -101,6 +111,11 @@ skip:
|
||||
return 0;
|
||||
}
|
||||
|
||||
asmlinkage void spurious_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
atomic_inc(&irq_err_count);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KGDB
|
||||
extern void breakpoint(void);
|
||||
extern void set_debug_traps(void);
|
||||
@ -124,6 +139,9 @@ void __init init_IRQ(void)
|
||||
irq_desc[i].depth = 1;
|
||||
irq_desc[i].handler = &no_irq_type;
|
||||
spin_lock_init(&irq_desc[i].lock);
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
irq_hwmask[i] = 0;
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
}
|
||||
|
||||
arch_init_irq();
|
||||
|
398
arch/mips/kernel/kspd.c
Normal file
398
arch/mips/kernel/kspd.c
Normal file
@ -0,0 +1,398 @@
|
||||
/*
|
||||
* Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include <asm/vpe.h>
|
||||
#include <asm/rtlx.h>
|
||||
#include <asm/kspd.h>
|
||||
|
||||
static struct workqueue_struct *workqueue = NULL;
|
||||
static struct work_struct work;
|
||||
|
||||
extern unsigned long cpu_khz;
|
||||
|
||||
struct mtsp_syscall {
|
||||
int cmd;
|
||||
unsigned char abi;
|
||||
unsigned char size;
|
||||
};
|
||||
|
||||
struct mtsp_syscall_ret {
|
||||
int retval;
|
||||
int errno;
|
||||
};
|
||||
|
||||
struct mtsp_syscall_generic {
|
||||
int arg0;
|
||||
int arg1;
|
||||
int arg2;
|
||||
int arg3;
|
||||
int arg4;
|
||||
int arg5;
|
||||
int arg6;
|
||||
};
|
||||
|
||||
static struct list_head kspd_notifylist;
|
||||
static int sp_stopping = 0;
|
||||
|
||||
/* these should match with those in the SDE kit */
|
||||
#define MTSP_SYSCALL_BASE 0
|
||||
#define MTSP_SYSCALL_EXIT (MTSP_SYSCALL_BASE + 0)
|
||||
#define MTSP_SYSCALL_OPEN (MTSP_SYSCALL_BASE + 1)
|
||||
#define MTSP_SYSCALL_READ (MTSP_SYSCALL_BASE + 2)
|
||||
#define MTSP_SYSCALL_WRITE (MTSP_SYSCALL_BASE + 3)
|
||||
#define MTSP_SYSCALL_CLOSE (MTSP_SYSCALL_BASE + 4)
|
||||
#define MTSP_SYSCALL_LSEEK32 (MTSP_SYSCALL_BASE + 5)
|
||||
#define MTSP_SYSCALL_ISATTY (MTSP_SYSCALL_BASE + 6)
|
||||
#define MTSP_SYSCALL_GETTIME (MTSP_SYSCALL_BASE + 7)
|
||||
#define MTSP_SYSCALL_PIPEFREQ (MTSP_SYSCALL_BASE + 8)
|
||||
#define MTSP_SYSCALL_GETTOD (MTSP_SYSCALL_BASE + 9)
|
||||
|
||||
#define MTSP_O_RDONLY 0x0000
|
||||
#define MTSP_O_WRONLY 0x0001
|
||||
#define MTSP_O_RDWR 0x0002
|
||||
#define MTSP_O_NONBLOCK 0x0004
|
||||
#define MTSP_O_APPEND 0x0008
|
||||
#define MTSP_O_SHLOCK 0x0010
|
||||
#define MTSP_O_EXLOCK 0x0020
|
||||
#define MTSP_O_ASYNC 0x0040
|
||||
#define MTSP_O_FSYNC O_SYNC
|
||||
#define MTSP_O_NOFOLLOW 0x0100
|
||||
#define MTSP_O_SYNC 0x0080
|
||||
#define MTSP_O_CREAT 0x0200
|
||||
#define MTSP_O_TRUNC 0x0400
|
||||
#define MTSP_O_EXCL 0x0800
|
||||
#define MTSP_O_BINARY 0x8000
|
||||
|
||||
#define SP_VPE 1
|
||||
|
||||
struct apsp_table {
|
||||
int sp;
|
||||
int ap;
|
||||
};
|
||||
|
||||
/* we might want to do the mode flags too */
|
||||
struct apsp_table open_flags_table[] = {
|
||||
{ MTSP_O_RDWR, O_RDWR },
|
||||
{ MTSP_O_WRONLY, O_WRONLY },
|
||||
{ MTSP_O_CREAT, O_CREAT },
|
||||
{ MTSP_O_TRUNC, O_TRUNC },
|
||||
{ MTSP_O_NONBLOCK, O_NONBLOCK },
|
||||
{ MTSP_O_APPEND, O_APPEND },
|
||||
{ MTSP_O_NOFOLLOW, O_NOFOLLOW }
|
||||
};
|
||||
|
||||
struct apsp_table syscall_command_table[] = {
|
||||
{ MTSP_SYSCALL_OPEN, __NR_open },
|
||||
{ MTSP_SYSCALL_CLOSE, __NR_close },
|
||||
{ MTSP_SYSCALL_READ, __NR_read },
|
||||
{ MTSP_SYSCALL_WRITE, __NR_write },
|
||||
{ MTSP_SYSCALL_LSEEK32, __NR_lseek }
|
||||
};
|
||||
|
||||
static int sp_syscall(int num, int arg0, int arg1, int arg2, int arg3)
|
||||
{
|
||||
register long int _num __asm__ ("$2") = num;
|
||||
register long int _arg0 __asm__ ("$4") = arg0;
|
||||
register long int _arg1 __asm__ ("$5") = arg1;
|
||||
register long int _arg2 __asm__ ("$6") = arg2;
|
||||
register long int _arg3 __asm__ ("$7") = arg3;
|
||||
|
||||
mm_segment_t old_fs;
|
||||
|
||||
old_fs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
|
||||
__asm__ __volatile__ (
|
||||
" syscall \n"
|
||||
: "=r" (_num), "=r" (_arg3)
|
||||
: "r" (_num), "r" (_arg0), "r" (_arg1), "r" (_arg2), "r" (_arg3));
|
||||
|
||||
set_fs(old_fs);
|
||||
|
||||
/* $a3 is error flag */
|
||||
if (_arg3)
|
||||
return -_num;
|
||||
|
||||
return _num;
|
||||
}
|
||||
|
||||
static int translate_syscall_command(int cmd)
|
||||
{
|
||||
int i;
|
||||
int ret = -1;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(syscall_command_table); i++) {
|
||||
if ((cmd == syscall_command_table[i].sp))
|
||||
return syscall_command_table[i].ap;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int translate_open_flags(int flags)
|
||||
{
|
||||
int i;
|
||||
unsigned int ret = 0;
|
||||
|
||||
for (i = 0; i < (sizeof(open_flags_table) / sizeof(struct apsp_table));
|
||||
i++) {
|
||||
if( (flags & open_flags_table[i].sp) ) {
|
||||
ret |= open_flags_table[i].ap;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void sp_setfsuidgid( uid_t uid, gid_t gid)
|
||||
{
|
||||
current->fsuid = uid;
|
||||
current->fsgid = gid;
|
||||
|
||||
key_fsuid_changed(current);
|
||||
key_fsgid_changed(current);
|
||||
}
|
||||
|
||||
/*
|
||||
* Expects a request to be on the sysio channel. Reads it. Decides whether
|
||||
* its a linux syscall and runs it, or whatever. Puts the return code back
|
||||
* into the request and sends the whole thing back.
|
||||
*/
|
||||
void sp_work_handle_request(void)
|
||||
{
|
||||
struct mtsp_syscall sc;
|
||||
struct mtsp_syscall_generic generic;
|
||||
struct mtsp_syscall_ret ret;
|
||||
struct kspd_notifications *n;
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
int cmd;
|
||||
|
||||
char *vcwd;
|
||||
mm_segment_t old_fs;
|
||||
int size;
|
||||
|
||||
ret.retval = -1;
|
||||
|
||||
if (!rtlx_read(RTLX_CHANNEL_SYSIO, &sc, sizeof(struct mtsp_syscall), 0)) {
|
||||
printk(KERN_ERR "Expected request but nothing to read\n");
|
||||
return;
|
||||
}
|
||||
|
||||
size = sc.size;
|
||||
|
||||
if (size) {
|
||||
if (!rtlx_read(RTLX_CHANNEL_SYSIO, &generic, size, 0)) {
|
||||
printk(KERN_ERR "Expected request but nothing to read\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Run the syscall at the priviledge of the user who loaded the
|
||||
SP program */
|
||||
|
||||
if (vpe_getuid(SP_VPE))
|
||||
sp_setfsuidgid( vpe_getuid(SP_VPE), vpe_getgid(SP_VPE));
|
||||
|
||||
switch (sc.cmd) {
|
||||
/* needs the flags argument translating from SDE kit to
|
||||
linux */
|
||||
case MTSP_SYSCALL_PIPEFREQ:
|
||||
ret.retval = cpu_khz * 1000;
|
||||
ret.errno = 0;
|
||||
break;
|
||||
|
||||
case MTSP_SYSCALL_GETTOD:
|
||||
memset(&tz, 0, sizeof(tz));
|
||||
if ((ret.retval = sp_syscall(__NR_gettimeofday, (int)&tv,
|
||||
(int)&tz, 0,0)) == 0)
|
||||
ret.retval = tv.tv_sec;
|
||||
|
||||
ret.errno = errno;
|
||||
break;
|
||||
|
||||
case MTSP_SYSCALL_EXIT:
|
||||
list_for_each_entry(n, &kspd_notifylist, list)
|
||||
n->kspd_sp_exit(SP_VPE);
|
||||
sp_stopping = 1;
|
||||
|
||||
printk(KERN_DEBUG "KSPD got exit syscall from SP exitcode %d\n",
|
||||
generic.arg0);
|
||||
break;
|
||||
|
||||
case MTSP_SYSCALL_OPEN:
|
||||
generic.arg1 = translate_open_flags(generic.arg1);
|
||||
|
||||
vcwd = vpe_getcwd(SP_VPE);
|
||||
|
||||
/* change to the cwd of the process that loaded the SP program */
|
||||
old_fs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
sys_chdir(vcwd);
|
||||
set_fs(old_fs);
|
||||
|
||||
sc.cmd = __NR_open;
|
||||
|
||||
/* fall through */
|
||||
|
||||
default:
|
||||
if ((sc.cmd >= __NR_Linux) &&
|
||||
(sc.cmd <= (__NR_Linux + __NR_Linux_syscalls)) )
|
||||
cmd = sc.cmd;
|
||||
else
|
||||
cmd = translate_syscall_command(sc.cmd);
|
||||
|
||||
if (cmd >= 0) {
|
||||
ret.retval = sp_syscall(cmd, generic.arg0, generic.arg1,
|
||||
generic.arg2, generic.arg3);
|
||||
ret.errno = errno;
|
||||
} else
|
||||
printk(KERN_WARNING
|
||||
"KSPD: Unknown SP syscall number %d\n", sc.cmd);
|
||||
break;
|
||||
} /* switch */
|
||||
|
||||
if (vpe_getuid(SP_VPE))
|
||||
sp_setfsuidgid( 0, 0);
|
||||
|
||||
if ((rtlx_write(RTLX_CHANNEL_SYSIO, &ret, sizeof(struct mtsp_syscall_ret), 0))
|
||||
< sizeof(struct mtsp_syscall_ret))
|
||||
printk("KSPD: sp_work_handle_request failed to send to SP\n");
|
||||
}
|
||||
|
||||
static void sp_cleanup(void)
|
||||
{
|
||||
struct files_struct *files = current->files;
|
||||
int i, j;
|
||||
struct fdtable *fdt;
|
||||
|
||||
j = 0;
|
||||
|
||||
/*
|
||||
* It is safe to dereference the fd table without RCU or
|
||||
* ->file_lock
|
||||
*/
|
||||
fdt = files_fdtable(files);
|
||||
for (;;) {
|
||||
unsigned long set;
|
||||
i = j * __NFDBITS;
|
||||
if (i >= fdt->max_fdset || i >= fdt->max_fds)
|
||||
break;
|
||||
set = fdt->open_fds->fds_bits[j++];
|
||||
while (set) {
|
||||
if (set & 1) {
|
||||
struct file * file = xchg(&fdt->fd[i], NULL);
|
||||
if (file)
|
||||
filp_close(file, files);
|
||||
}
|
||||
i++;
|
||||
set >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int channel_open = 0;
|
||||
|
||||
/* the work handler */
|
||||
static void sp_work(void *data)
|
||||
{
|
||||
if (!channel_open) {
|
||||
if( rtlx_open(RTLX_CHANNEL_SYSIO, 1) != 0) {
|
||||
printk("KSPD: unable to open sp channel\n");
|
||||
sp_stopping = 1;
|
||||
} else {
|
||||
channel_open++;
|
||||
printk(KERN_DEBUG "KSPD: SP channel opened\n");
|
||||
}
|
||||
} else {
|
||||
/* wait for some data, allow it to sleep */
|
||||
rtlx_read_poll(RTLX_CHANNEL_SYSIO, 1);
|
||||
|
||||
/* Check we haven't been woken because we are stopping */
|
||||
if (!sp_stopping)
|
||||
sp_work_handle_request();
|
||||
}
|
||||
|
||||
if (!sp_stopping)
|
||||
queue_work(workqueue, &work);
|
||||
else
|
||||
sp_cleanup();
|
||||
}
|
||||
|
||||
static void startwork(int vpe)
|
||||
{
|
||||
sp_stopping = channel_open = 0;
|
||||
|
||||
if (workqueue == NULL) {
|
||||
if ((workqueue = create_singlethread_workqueue("kspd")) == NULL) {
|
||||
printk(KERN_ERR "unable to start kspd\n");
|
||||
return;
|
||||
}
|
||||
|
||||
INIT_WORK(&work, sp_work, NULL);
|
||||
queue_work(workqueue, &work);
|
||||
} else
|
||||
queue_work(workqueue, &work);
|
||||
|
||||
}
|
||||
|
||||
static void stopwork(int vpe)
|
||||
{
|
||||
sp_stopping = 1;
|
||||
|
||||
printk(KERN_DEBUG "KSPD: SP stopping\n");
|
||||
}
|
||||
|
||||
void kspd_notify(struct kspd_notifications *notify)
|
||||
{
|
||||
list_add(¬ify->list, &kspd_notifylist);
|
||||
}
|
||||
|
||||
static struct vpe_notifications notify;
|
||||
static int kspd_module_init(void)
|
||||
{
|
||||
INIT_LIST_HEAD(&kspd_notifylist);
|
||||
|
||||
notify.start = startwork;
|
||||
notify.stop = stopwork;
|
||||
vpe_notify(SP_VPE, ¬ify);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kspd_module_exit(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
module_init(kspd_module_init);
|
||||
module_exit(kspd_module_exit);
|
||||
|
||||
MODULE_DESCRIPTION("MIPS KSPD");
|
||||
MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
@ -1182,6 +1182,16 @@ asmlinkage ssize_t sys32_readahead(int fd, u32 pad0, u64 a2, u64 a3,
|
||||
return sys_readahead(fd, merge_64(a2, a3), count);
|
||||
}
|
||||
|
||||
asmlinkage long sys32_sync_file_range(int fd, int __pad,
|
||||
unsigned long a2, unsigned long a3,
|
||||
unsigned long a4, unsigned long a5,
|
||||
int flags)
|
||||
{
|
||||
return sys_sync_file_range(fd,
|
||||
merge_64(a2, a3), merge_64(a4, a5),
|
||||
flags);
|
||||
}
|
||||
|
||||
/* Argument list sizes for sys_socketcall */
|
||||
#define AL(x) ((x) * sizeof(unsigned int))
|
||||
static unsigned char socketcall_nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
|
||||
|
449
arch/mips/kernel/mips-mt.c
Normal file
449
arch/mips/kernel/mips-mt.c
Normal file
@ -0,0 +1,449 @@
|
||||
/*
|
||||
* General MIPS MT support routines, usable in AP/SP, SMVP, or SMTC kernels
|
||||
* Copyright (C) 2005 Mips Technologies, Inc
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/hardirq.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/mipsmtregs.h>
|
||||
#include <asm/r4kcache.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
/*
|
||||
* CPU mask used to set process affinity for MT VPEs/TCs with FPUs
|
||||
*/
|
||||
|
||||
cpumask_t mt_fpu_cpumask;
|
||||
|
||||
#ifdef CONFIG_MIPS_MT_FPAFF
|
||||
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
unsigned long mt_fpemul_threshold = 0;
|
||||
|
||||
/*
|
||||
* Replacement functions for the sys_sched_setaffinity() and
|
||||
* sys_sched_getaffinity() system calls, so that we can integrate
|
||||
* FPU affinity with the user's requested processor affinity.
|
||||
* This code is 98% identical with the sys_sched_setaffinity()
|
||||
* and sys_sched_getaffinity() system calls, and should be
|
||||
* updated when kernel/sched.c changes.
|
||||
*/
|
||||
|
||||
/*
|
||||
* find_process_by_pid - find a process with a matching PID value.
|
||||
* used in sys_sched_set/getaffinity() in kernel/sched.c, so
|
||||
* cloned here.
|
||||
*/
|
||||
static inline task_t *find_process_by_pid(pid_t pid)
|
||||
{
|
||||
return pid ? find_task_by_pid(pid) : current;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* mipsmt_sys_sched_setaffinity - set the cpu affinity of a process
|
||||
*/
|
||||
asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
|
||||
unsigned long __user *user_mask_ptr)
|
||||
{
|
||||
cpumask_t new_mask;
|
||||
cpumask_t effective_mask;
|
||||
int retval;
|
||||
task_t *p;
|
||||
|
||||
if (len < sizeof(new_mask))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask)))
|
||||
return -EFAULT;
|
||||
|
||||
lock_cpu_hotplug();
|
||||
read_lock(&tasklist_lock);
|
||||
|
||||
p = find_process_by_pid(pid);
|
||||
if (!p) {
|
||||
read_unlock(&tasklist_lock);
|
||||
unlock_cpu_hotplug();
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
/*
|
||||
* It is not safe to call set_cpus_allowed with the
|
||||
* tasklist_lock held. We will bump the task_struct's
|
||||
* usage count and drop tasklist_lock before invoking
|
||||
* set_cpus_allowed.
|
||||
*/
|
||||
get_task_struct(p);
|
||||
|
||||
retval = -EPERM;
|
||||
if ((current->euid != p->euid) && (current->euid != p->uid) &&
|
||||
!capable(CAP_SYS_NICE)) {
|
||||
read_unlock(&tasklist_lock);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* Record new user-specified CPU set for future reference */
|
||||
p->thread.user_cpus_allowed = new_mask;
|
||||
|
||||
/* Unlock the task list */
|
||||
read_unlock(&tasklist_lock);
|
||||
|
||||
/* Compute new global allowed CPU set if necessary */
|
||||
if( (p->thread.mflags & MF_FPUBOUND)
|
||||
&& cpus_intersects(new_mask, mt_fpu_cpumask)) {
|
||||
cpus_and(effective_mask, new_mask, mt_fpu_cpumask);
|
||||
retval = set_cpus_allowed(p, effective_mask);
|
||||
} else {
|
||||
p->thread.mflags &= ~MF_FPUBOUND;
|
||||
retval = set_cpus_allowed(p, new_mask);
|
||||
}
|
||||
|
||||
|
||||
out_unlock:
|
||||
put_task_struct(p);
|
||||
unlock_cpu_hotplug();
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* mipsmt_sys_sched_getaffinity - get the cpu affinity of a process
|
||||
*/
|
||||
asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
|
||||
unsigned long __user *user_mask_ptr)
|
||||
{
|
||||
unsigned int real_len;
|
||||
cpumask_t mask;
|
||||
int retval;
|
||||
task_t *p;
|
||||
|
||||
real_len = sizeof(mask);
|
||||
if (len < real_len)
|
||||
return -EINVAL;
|
||||
|
||||
lock_cpu_hotplug();
|
||||
read_lock(&tasklist_lock);
|
||||
|
||||
retval = -ESRCH;
|
||||
p = find_process_by_pid(pid);
|
||||
if (!p)
|
||||
goto out_unlock;
|
||||
|
||||
retval = 0;
|
||||
|
||||
cpus_and(mask, p->thread.user_cpus_allowed, cpu_possible_map);
|
||||
|
||||
out_unlock:
|
||||
read_unlock(&tasklist_lock);
|
||||
unlock_cpu_hotplug();
|
||||
if (retval)
|
||||
return retval;
|
||||
if (copy_to_user(user_mask_ptr, &mask, real_len))
|
||||
return -EFAULT;
|
||||
return real_len;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MIPS_MT_FPAFF */
|
||||
|
||||
/*
|
||||
* Dump new MIPS MT state for the core. Does not leave TCs halted.
|
||||
* Takes an argument which taken to be a pre-call MVPControl value.
|
||||
*/
|
||||
|
||||
void mips_mt_regdump(unsigned long mvpctl)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long vpflags;
|
||||
unsigned long mvpconf0;
|
||||
int nvpe;
|
||||
int ntc;
|
||||
int i;
|
||||
int tc;
|
||||
unsigned long haltval;
|
||||
unsigned long tcstatval;
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
void smtc_soft_dump(void);
|
||||
#endif /* CONFIG_MIPT_MT_SMTC */
|
||||
|
||||
local_irq_save(flags);
|
||||
vpflags = dvpe();
|
||||
printk("=== MIPS MT State Dump ===\n");
|
||||
printk("-- Global State --\n");
|
||||
printk(" MVPControl Passed: %08lx\n", mvpctl);
|
||||
printk(" MVPControl Read: %08lx\n", vpflags);
|
||||
printk(" MVPConf0 : %08lx\n", (mvpconf0 = read_c0_mvpconf0()));
|
||||
nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
|
||||
ntc = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1;
|
||||
printk("-- per-VPE State --\n");
|
||||
for(i = 0; i < nvpe; i++) {
|
||||
for(tc = 0; tc < ntc; tc++) {
|
||||
settc(tc);
|
||||
if((read_tc_c0_tcbind() & TCBIND_CURVPE) == i) {
|
||||
printk(" VPE %d\n", i);
|
||||
printk(" VPEControl : %08lx\n", read_vpe_c0_vpecontrol());
|
||||
printk(" VPEConf0 : %08lx\n", read_vpe_c0_vpeconf0());
|
||||
printk(" VPE%d.Status : %08lx\n",
|
||||
i, read_vpe_c0_status());
|
||||
printk(" VPE%d.EPC : %08lx\n", i, read_vpe_c0_epc());
|
||||
printk(" VPE%d.Cause : %08lx\n", i, read_vpe_c0_cause());
|
||||
printk(" VPE%d.Config7 : %08lx\n",
|
||||
i, read_vpe_c0_config7());
|
||||
break; /* Next VPE */
|
||||
}
|
||||
}
|
||||
}
|
||||
printk("-- per-TC State --\n");
|
||||
for(tc = 0; tc < ntc; tc++) {
|
||||
settc(tc);
|
||||
if(read_tc_c0_tcbind() == read_c0_tcbind()) {
|
||||
/* Are we dumping ourself? */
|
||||
haltval = 0; /* Then we're not halted, and mustn't be */
|
||||
tcstatval = flags; /* And pre-dump TCStatus is flags */
|
||||
printk(" TC %d (current TC with VPE EPC above)\n", tc);
|
||||
} else {
|
||||
haltval = read_tc_c0_tchalt();
|
||||
write_tc_c0_tchalt(1);
|
||||
tcstatval = read_tc_c0_tcstatus();
|
||||
printk(" TC %d\n", tc);
|
||||
}
|
||||
printk(" TCStatus : %08lx\n", tcstatval);
|
||||
printk(" TCBind : %08lx\n", read_tc_c0_tcbind());
|
||||
printk(" TCRestart : %08lx\n", read_tc_c0_tcrestart());
|
||||
printk(" TCHalt : %08lx\n", haltval);
|
||||
printk(" TCContext : %08lx\n", read_tc_c0_tccontext());
|
||||
if (!haltval)
|
||||
write_tc_c0_tchalt(0);
|
||||
}
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
smtc_soft_dump();
|
||||
#endif /* CONFIG_MIPT_MT_SMTC */
|
||||
printk("===========================\n");
|
||||
evpe(vpflags);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static int mt_opt_norps = 0;
|
||||
static int mt_opt_rpsctl = -1;
|
||||
static int mt_opt_nblsu = -1;
|
||||
static int mt_opt_forceconfig7 = 0;
|
||||
static int mt_opt_config7 = -1;
|
||||
|
||||
static int __init rps_disable(char *s)
|
||||
{
|
||||
mt_opt_norps = 1;
|
||||
return 1;
|
||||
}
|
||||
__setup("norps", rps_disable);
|
||||
|
||||
static int __init rpsctl_set(char *str)
|
||||
{
|
||||
get_option(&str, &mt_opt_rpsctl);
|
||||
return 1;
|
||||
}
|
||||
__setup("rpsctl=", rpsctl_set);
|
||||
|
||||
static int __init nblsu_set(char *str)
|
||||
{
|
||||
get_option(&str, &mt_opt_nblsu);
|
||||
return 1;
|
||||
}
|
||||
__setup("nblsu=", nblsu_set);
|
||||
|
||||
static int __init config7_set(char *str)
|
||||
{
|
||||
get_option(&str, &mt_opt_config7);
|
||||
mt_opt_forceconfig7 = 1;
|
||||
return 1;
|
||||
}
|
||||
__setup("config7=", config7_set);
|
||||
|
||||
/* Experimental cache flush control parameters that should go away some day */
|
||||
int mt_protiflush = 0;
|
||||
int mt_protdflush = 0;
|
||||
int mt_n_iflushes = 1;
|
||||
int mt_n_dflushes = 1;
|
||||
|
||||
static int __init set_protiflush(char *s)
|
||||
{
|
||||
mt_protiflush = 1;
|
||||
return 1;
|
||||
}
|
||||
__setup("protiflush", set_protiflush);
|
||||
|
||||
static int __init set_protdflush(char *s)
|
||||
{
|
||||
mt_protdflush = 1;
|
||||
return 1;
|
||||
}
|
||||
__setup("protdflush", set_protdflush);
|
||||
|
||||
static int __init niflush(char *s)
|
||||
{
|
||||
get_option(&s, &mt_n_iflushes);
|
||||
return 1;
|
||||
}
|
||||
__setup("niflush=", niflush);
|
||||
|
||||
static int __init ndflush(char *s)
|
||||
{
|
||||
get_option(&s, &mt_n_dflushes);
|
||||
return 1;
|
||||
}
|
||||
__setup("ndflush=", ndflush);
|
||||
#ifdef CONFIG_MIPS_MT_FPAFF
|
||||
static int fpaff_threshold = -1;
|
||||
|
||||
static int __init fpaff_thresh(char *str)
|
||||
{
|
||||
get_option(&str, &fpaff_threshold);
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("fpaff=", fpaff_thresh);
|
||||
#endif /* CONFIG_MIPS_MT_FPAFF */
|
||||
|
||||
static unsigned int itc_base = 0;
|
||||
|
||||
static int __init set_itc_base(char *str)
|
||||
{
|
||||
get_option(&str, &itc_base);
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("itcbase=", set_itc_base);
|
||||
|
||||
void mips_mt_set_cpuoptions(void)
|
||||
{
|
||||
unsigned int oconfig7 = read_c0_config7();
|
||||
unsigned int nconfig7 = oconfig7;
|
||||
|
||||
if (mt_opt_norps) {
|
||||
printk("\"norps\" option deprectated: use \"rpsctl=\"\n");
|
||||
}
|
||||
if (mt_opt_rpsctl >= 0) {
|
||||
printk("34K return prediction stack override set to %d.\n",
|
||||
mt_opt_rpsctl);
|
||||
if (mt_opt_rpsctl)
|
||||
nconfig7 |= (1 << 2);
|
||||
else
|
||||
nconfig7 &= ~(1 << 2);
|
||||
}
|
||||
if (mt_opt_nblsu >= 0) {
|
||||
printk("34K ALU/LSU sync override set to %d.\n", mt_opt_nblsu);
|
||||
if (mt_opt_nblsu)
|
||||
nconfig7 |= (1 << 5);
|
||||
else
|
||||
nconfig7 &= ~(1 << 5);
|
||||
}
|
||||
if (mt_opt_forceconfig7) {
|
||||
printk("CP0.Config7 forced to 0x%08x.\n", mt_opt_config7);
|
||||
nconfig7 = mt_opt_config7;
|
||||
}
|
||||
if (oconfig7 != nconfig7) {
|
||||
__asm__ __volatile("sync");
|
||||
write_c0_config7(nconfig7);
|
||||
ehb ();
|
||||
printk("Config7: 0x%08x\n", read_c0_config7());
|
||||
}
|
||||
|
||||
/* Report Cache management debug options */
|
||||
if (mt_protiflush)
|
||||
printk("I-cache flushes single-threaded\n");
|
||||
if (mt_protdflush)
|
||||
printk("D-cache flushes single-threaded\n");
|
||||
if (mt_n_iflushes != 1)
|
||||
printk("I-Cache Flushes Repeated %d times\n", mt_n_iflushes);
|
||||
if (mt_n_dflushes != 1)
|
||||
printk("D-Cache Flushes Repeated %d times\n", mt_n_dflushes);
|
||||
|
||||
#ifdef CONFIG_MIPS_MT_FPAFF
|
||||
/* FPU Use Factor empirically derived from experiments on 34K */
|
||||
#define FPUSEFACTOR 333
|
||||
|
||||
if (fpaff_threshold >= 0) {
|
||||
mt_fpemul_threshold = fpaff_threshold;
|
||||
} else {
|
||||
mt_fpemul_threshold =
|
||||
(FPUSEFACTOR * (loops_per_jiffy/(500000/HZ))) / HZ;
|
||||
}
|
||||
printk("FPU Affinity set after %ld emulations\n",
|
||||
mt_fpemul_threshold);
|
||||
#endif /* CONFIG_MIPS_MT_FPAFF */
|
||||
|
||||
if (itc_base != 0) {
|
||||
/*
|
||||
* Configure ITC mapping. This code is very
|
||||
* specific to the 34K core family, which uses
|
||||
* a special mode bit ("ITC") in the ErrCtl
|
||||
* register to enable access to ITC control
|
||||
* registers via cache "tag" operations.
|
||||
*/
|
||||
unsigned long ectlval;
|
||||
unsigned long itcblkgrn;
|
||||
|
||||
/* ErrCtl register is known as "ecc" to Linux */
|
||||
ectlval = read_c0_ecc();
|
||||
write_c0_ecc(ectlval | (0x1 << 26));
|
||||
ehb();
|
||||
#define INDEX_0 (0x80000000)
|
||||
#define INDEX_8 (0x80000008)
|
||||
/* Read "cache tag" for Dcache pseudo-index 8 */
|
||||
cache_op(Index_Load_Tag_D, INDEX_8);
|
||||
ehb();
|
||||
itcblkgrn = read_c0_dtaglo();
|
||||
itcblkgrn &= 0xfffe0000;
|
||||
/* Set for 128 byte pitch of ITC cells */
|
||||
itcblkgrn |= 0x00000c00;
|
||||
/* Stage in Tag register */
|
||||
write_c0_dtaglo(itcblkgrn);
|
||||
ehb();
|
||||
/* Write out to ITU with CACHE op */
|
||||
cache_op(Index_Store_Tag_D, INDEX_8);
|
||||
/* Now set base address, and turn ITC on with 0x1 bit */
|
||||
write_c0_dtaglo((itc_base & 0xfffffc00) | 0x1 );
|
||||
ehb();
|
||||
/* Write out to ITU with CACHE op */
|
||||
cache_op(Index_Store_Tag_D, INDEX_0);
|
||||
write_c0_ecc(ectlval);
|
||||
ehb();
|
||||
printk("Mapped %ld ITC cells starting at 0x%08x\n",
|
||||
((itcblkgrn & 0x7fe00000) >> 20), itc_base);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to protect cache flushes from concurrent execution
|
||||
* depends on MP software model chosen.
|
||||
*/
|
||||
|
||||
void mt_cflush_lockdown(void)
|
||||
{
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
void smtc_cflush_lockdown(void);
|
||||
|
||||
smtc_cflush_lockdown();
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
/* FILL IN VSMP and AP/SP VERSIONS HERE */
|
||||
}
|
||||
|
||||
void mt_cflush_release(void)
|
||||
{
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
void smtc_cflush_release(void);
|
||||
|
||||
smtc_cflush_release();
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
/* FILL IN VSMP and AP/SP VERSIONS HERE */
|
||||
}
|
@ -28,21 +28,9 @@ extern long __strnlen_user_asm(const char *s);
|
||||
/*
|
||||
* String functions
|
||||
*/
|
||||
EXPORT_SYMBOL(memchr);
|
||||
EXPORT_SYMBOL(memcmp);
|
||||
EXPORT_SYMBOL(memset);
|
||||
EXPORT_SYMBOL(memcpy);
|
||||
EXPORT_SYMBOL(memmove);
|
||||
EXPORT_SYMBOL(strcat);
|
||||
EXPORT_SYMBOL(strchr);
|
||||
#ifdef CONFIG_64BIT
|
||||
EXPORT_SYMBOL(strncmp);
|
||||
#endif
|
||||
EXPORT_SYMBOL(strlen);
|
||||
EXPORT_SYMBOL(strncat);
|
||||
EXPORT_SYMBOL(strnlen);
|
||||
EXPORT_SYMBOL(strrchr);
|
||||
EXPORT_SYMBOL(strstr);
|
||||
|
||||
EXPORT_SYMBOL(kernel_thread);
|
||||
|
||||
@ -61,6 +49,3 @@ EXPORT_SYMBOL(__strnlen_user_asm);
|
||||
EXPORT_SYMBOL(csum_partial);
|
||||
|
||||
EXPORT_SYMBOL(invalid_pte_table);
|
||||
#ifdef CONFIG_GENERIC_IRQ_PROBE
|
||||
EXPORT_SYMBOL(probe_irq_mask);
|
||||
#endif
|
||||
|
@ -41,6 +41,10 @@
|
||||
#include <asm/elf.h>
|
||||
#include <asm/isadep.h>
|
||||
#include <asm/inst.h>
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
#include <asm/mipsmtregs.h>
|
||||
extern void smtc_idle_loop_hook(void);
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
/*
|
||||
* The idle thread. There's no useful work to be done, so just try to conserve
|
||||
@ -51,9 +55,13 @@ ATTRIB_NORET void cpu_idle(void)
|
||||
{
|
||||
/* endless idle loop with no priority at all */
|
||||
while (1) {
|
||||
while (!need_resched())
|
||||
while (!need_resched()) {
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
smtc_idle_loop_hook();
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
if (cpu_wait)
|
||||
(*cpu_wait)();
|
||||
}
|
||||
preempt_enable_no_resched();
|
||||
schedule();
|
||||
preempt_disable();
|
||||
@ -177,6 +185,17 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
|
||||
childregs->cp0_status &= ~(ST0_CU2|ST0_CU1);
|
||||
clear_tsk_thread_flag(p, TIF_USEDFPU);
|
||||
|
||||
#ifdef CONFIG_MIPS_MT_FPAFF
|
||||
/*
|
||||
* FPU affinity support is cleaner if we track the
|
||||
* user-visible CPU affinity from the very beginning.
|
||||
* The generic cpus_allowed mask will already have
|
||||
* been copied from the parent before copy_thread
|
||||
* is invoked.
|
||||
*/
|
||||
p->thread.user_cpus_allowed = p->cpus_allowed;
|
||||
#endif /* CONFIG_MIPS_MT_FPAFF */
|
||||
|
||||
if (clone_flags & CLONE_SETTLS)
|
||||
ti->tp_value = regs->regs[7];
|
||||
|
||||
|
@ -248,10 +248,20 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||
break;
|
||||
case FPC_EIR: { /* implementation / version register */
|
||||
unsigned int flags;
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
unsigned int irqflags;
|
||||
unsigned int mtflags;
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
if (!cpu_has_fpu)
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
/* Read-modify-write of Status must be atomic */
|
||||
local_irq_save(irqflags);
|
||||
mtflags = dmt();
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
preempt_disable();
|
||||
if (cpu_has_mipsmt) {
|
||||
unsigned int vpflags = dvpe();
|
||||
@ -266,6 +276,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||
__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
|
||||
write_c0_status(flags);
|
||||
}
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
emt(mtflags);
|
||||
local_irq_restore(irqflags);
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
preempt_enable();
|
||||
break;
|
||||
}
|
||||
|
@ -173,12 +173,22 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
|
||||
break;
|
||||
case FPC_EIR: { /* implementation / version register */
|
||||
unsigned int flags;
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
unsigned int irqflags;
|
||||
unsigned int mtflags;
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
if (!cpu_has_fpu) {
|
||||
tmp = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
/* Read-modify-write of Status must be atomic */
|
||||
local_irq_save(irqflags);
|
||||
mtflags = dmt();
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
preempt_disable();
|
||||
if (cpu_has_mipsmt) {
|
||||
unsigned int vpflags = dvpe();
|
||||
@ -193,6 +203,10 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
|
||||
__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
|
||||
write_c0_status(flags);
|
||||
}
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
emt(mtflags);
|
||||
local_irq_restore(irqflags);
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
preempt_enable();
|
||||
break;
|
||||
}
|
||||
|
@ -88,7 +88,18 @@
|
||||
|
||||
PTR_ADDIU t0, $28, _THREAD_SIZE - 32
|
||||
set_saved_sp t0, t1, t2
|
||||
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
/* Read-modify-writes of Status must be atomic on a VPE */
|
||||
mfc0 t2, CP0_TCSTATUS
|
||||
ori t1, t2, TCSTATUS_IXMT
|
||||
mtc0 t1, CP0_TCSTATUS
|
||||
andi t2, t2, TCSTATUS_IXMT
|
||||
ehb
|
||||
DMT 8 # dmt t0
|
||||
move t1,ra
|
||||
jal mips_ihb
|
||||
move ra,t1
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
mfc0 t1, CP0_STATUS /* Do we really need this? */
|
||||
li a3, 0xff01
|
||||
and t1, a3
|
||||
@ -97,6 +108,18 @@
|
||||
and a2, a3
|
||||
or a2, t1
|
||||
mtc0 a2, CP0_STATUS
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
ehb
|
||||
andi t0, t0, VPECONTROL_TE
|
||||
beqz t0, 1f
|
||||
emt
|
||||
1:
|
||||
mfc0 t1, CP0_TCSTATUS
|
||||
xori t1, t1, TCSTATUS_IXMT
|
||||
or t1, t1, t2
|
||||
mtc0 t1, CP0_TCSTATUS
|
||||
ehb
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
move v0, a0
|
||||
jr ra
|
||||
END(resume)
|
||||
@ -131,10 +154,19 @@ LEAF(_restore_fp)
|
||||
#define FPU_DEFAULT 0x00000000
|
||||
|
||||
LEAF(_init_fpu)
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
/* Rather than manipulate per-VPE Status, set per-TC bit in TCStatus */
|
||||
mfc0 t0, CP0_TCSTATUS
|
||||
/* Bit position is the same for Status, TCStatus */
|
||||
li t1, ST0_CU1
|
||||
or t0, t1
|
||||
mtc0 t0, CP0_TCSTATUS
|
||||
#else /* Normal MIPS CU1 enable */
|
||||
mfc0 t0, CP0_STATUS
|
||||
li t1, ST0_CU1
|
||||
or t0, t1
|
||||
mtc0 t0, CP0_STATUS
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
fpu_enable_hazard
|
||||
|
||||
li t1, FPU_DEFAULT
|
||||
|
@ -21,45 +21,44 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/moduleloader.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include <asm/mipsmtregs.h>
|
||||
#include <asm/bitops.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/vpe.h>
|
||||
#include <asm/rtlx.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#define RTLX_TARG_VPE 1
|
||||
|
||||
static struct rtlx_info *rtlx;
|
||||
static int major;
|
||||
static char module_name[] = "rtlx";
|
||||
static struct irqaction irq;
|
||||
static int irq_num;
|
||||
|
||||
static inline int spacefree(int read, int write, int size)
|
||||
{
|
||||
if (read == write) {
|
||||
/*
|
||||
* never fill the buffer completely, so indexes are always
|
||||
* equal if empty and only empty, or !equal if data available
|
||||
*/
|
||||
return size - 1;
|
||||
}
|
||||
|
||||
return ((read + size - write) % size) - 1;
|
||||
}
|
||||
|
||||
static struct chan_waitqueues {
|
||||
wait_queue_head_t rt_queue;
|
||||
wait_queue_head_t lx_queue;
|
||||
int in_open;
|
||||
} channel_wqs[RTLX_CHANNELS];
|
||||
|
||||
static struct irqaction irq;
|
||||
static int irq_num;
|
||||
static struct vpe_notifications notify;
|
||||
static int sp_stopping = 0;
|
||||
|
||||
extern void *vpe_get_shared(int index);
|
||||
|
||||
static void rtlx_dispatch(struct pt_regs *regs)
|
||||
@ -67,174 +66,298 @@ static void rtlx_dispatch(struct pt_regs *regs)
|
||||
do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ, regs);
|
||||
}
|
||||
|
||||
|
||||
/* Interrupt handler may be called before rtlx_init has otherwise had
|
||||
a chance to run.
|
||||
*/
|
||||
static irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < RTLX_CHANNELS; i++) {
|
||||
struct rtlx_channel *chan = &rtlx->channel[i];
|
||||
|
||||
if (chan->lx_read != chan->lx_write)
|
||||
wake_up_interruptible(&channel_wqs[i].lx_queue);
|
||||
wake_up(&channel_wqs[i].lx_queue);
|
||||
wake_up(&channel_wqs[i].rt_queue);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* call when we have the address of the shared structure from the SP side. */
|
||||
static int rtlx_init(struct rtlx_info *rtlxi)
|
||||
static __attribute_used__ void dump_rtlx(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printk("id 0x%lx state %d\n", rtlx->id, rtlx->state);
|
||||
|
||||
for (i = 0; i < RTLX_CHANNELS; i++) {
|
||||
struct rtlx_channel *chan = &rtlx->channel[i];
|
||||
|
||||
printk(" rt_state %d lx_state %d buffer_size %d\n",
|
||||
chan->rt_state, chan->lx_state, chan->buffer_size);
|
||||
|
||||
printk(" rt_read %d rt_write %d\n",
|
||||
chan->rt_read, chan->rt_write);
|
||||
|
||||
printk(" lx_read %d lx_write %d\n",
|
||||
chan->lx_read, chan->lx_write);
|
||||
|
||||
printk(" rt_buffer <%s>\n", chan->rt_buffer);
|
||||
printk(" lx_buffer <%s>\n", chan->lx_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/* call when we have the address of the shared structure from the SP side. */
|
||||
static int rtlx_init(struct rtlx_info *rtlxi)
|
||||
{
|
||||
if (rtlxi->id != RTLX_ID) {
|
||||
printk(KERN_WARNING "no valid RTLX id at 0x%p\n", rtlxi);
|
||||
printk(KERN_ERR "no valid RTLX id at 0x%p 0x%x\n", rtlxi, rtlxi->id);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* initialise the wait queues */
|
||||
for (i = 0; i < RTLX_CHANNELS; i++) {
|
||||
init_waitqueue_head(&channel_wqs[i].rt_queue);
|
||||
init_waitqueue_head(&channel_wqs[i].lx_queue);
|
||||
}
|
||||
|
||||
/* set up for interrupt handling */
|
||||
memset(&irq, 0, sizeof(struct irqaction));
|
||||
|
||||
if (cpu_has_vint)
|
||||
set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch);
|
||||
|
||||
irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ;
|
||||
irq.handler = rtlx_interrupt;
|
||||
irq.flags = SA_INTERRUPT;
|
||||
irq.name = "RTLX";
|
||||
irq.dev_id = rtlx;
|
||||
setup_irq(irq_num, &irq);
|
||||
|
||||
rtlx = rtlxi;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* only allow one open process at a time to open each channel */
|
||||
static int rtlx_open(struct inode *inode, struct file *filp)
|
||||
/* notifications */
|
||||
static void starting(int vpe)
|
||||
{
|
||||
int minor, ret;
|
||||
struct rtlx_channel *chan;
|
||||
int i;
|
||||
sp_stopping = 0;
|
||||
|
||||
/* assume only 1 device at the mo. */
|
||||
minor = MINOR(inode->i_rdev);
|
||||
/* force a reload of rtlx */
|
||||
rtlx=NULL;
|
||||
|
||||
/* wake up any sleeping rtlx_open's */
|
||||
for (i = 0; i < RTLX_CHANNELS; i++)
|
||||
wake_up_interruptible(&channel_wqs[i].lx_queue);
|
||||
}
|
||||
|
||||
static void stopping(int vpe)
|
||||
{
|
||||
int i;
|
||||
|
||||
sp_stopping = 1;
|
||||
for (i = 0; i < RTLX_CHANNELS; i++)
|
||||
wake_up_interruptible(&channel_wqs[i].lx_queue);
|
||||
}
|
||||
|
||||
|
||||
int rtlx_open(int index, int can_sleep)
|
||||
{
|
||||
int ret;
|
||||
struct rtlx_channel *chan;
|
||||
volatile struct rtlx_info **p;
|
||||
|
||||
if (index >= RTLX_CHANNELS) {
|
||||
printk(KERN_DEBUG "rtlx_open index out of range\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
if (channel_wqs[index].in_open) {
|
||||
printk(KERN_DEBUG "rtlx_open channel %d already opened\n", index);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
channel_wqs[index].in_open++;
|
||||
|
||||
if (rtlx == NULL) {
|
||||
struct rtlx_info **p;
|
||||
if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) {
|
||||
printk(KERN_ERR "vpe_get_shared is NULL. "
|
||||
"Has an SP program been loaded?\n");
|
||||
return -EFAULT;
|
||||
if (can_sleep) {
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
/* go to sleep */
|
||||
add_wait_queue(&channel_wqs[index].lx_queue, &wait);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
while ((p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) {
|
||||
schedule();
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
}
|
||||
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
|
||||
|
||||
/* back running */
|
||||
} else {
|
||||
printk( KERN_DEBUG "No SP program loaded, and device "
|
||||
"opened with O_NONBLOCK\n");
|
||||
channel_wqs[index].in_open = 0;
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
if (*p == NULL) {
|
||||
printk(KERN_ERR "vpe_shared %p %p\n", p, *p);
|
||||
return -EFAULT;
|
||||
if (can_sleep) {
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
/* go to sleep */
|
||||
add_wait_queue(&channel_wqs[index].lx_queue, &wait);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
while (*p == NULL) {
|
||||
schedule();
|
||||
|
||||
/* reset task state to interruptable otherwise
|
||||
we'll whizz round here like a very fast loopy
|
||||
thing. schedule() appears to return with state
|
||||
set to TASK_RUNNING.
|
||||
|
||||
If the loaded SP program, for whatever reason,
|
||||
doesn't set up the shared structure *p will never
|
||||
become true. So whoever connected to either /dev/rt?
|
||||
or if it was kspd, will then take up rather a lot of
|
||||
processor cycles.
|
||||
*/
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
}
|
||||
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
|
||||
|
||||
/* back running */
|
||||
}
|
||||
else {
|
||||
printk(" *vpe_get_shared is NULL. "
|
||||
"Has an SP program been loaded?\n");
|
||||
channel_wqs[index].in_open = 0;
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ret = rtlx_init(*p)) < 0)
|
||||
return ret;
|
||||
if ((unsigned int)*p < KSEG0) {
|
||||
printk(KERN_WARNING "vpe_get_shared returned an invalid pointer "
|
||||
"maybe an error code %d\n", (int)*p);
|
||||
channel_wqs[index].in_open = 0;
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
if ((ret = rtlx_init(*p)) < 0) {
|
||||
channel_wqs[index].in_open = 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
chan = &rtlx->channel[minor];
|
||||
chan = &rtlx->channel[index];
|
||||
|
||||
if (test_and_set_bit(RTLX_STATE_OPENED, &chan->lx_state))
|
||||
return -EBUSY;
|
||||
if (chan->lx_state == RTLX_STATE_OPENED) {
|
||||
channel_wqs[index].in_open = 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
chan->lx_state = RTLX_STATE_OPENED;
|
||||
channel_wqs[index].in_open = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtlx_release(struct inode *inode, struct file *filp)
|
||||
int rtlx_release(int index)
|
||||
{
|
||||
int minor = MINOR(inode->i_rdev);
|
||||
|
||||
clear_bit(RTLX_STATE_OPENED, &rtlx->channel[minor].lx_state);
|
||||
smp_mb__after_clear_bit();
|
||||
|
||||
rtlx->channel[index].lx_state = RTLX_STATE_UNUSED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int rtlx_poll(struct file *file, poll_table * wait)
|
||||
unsigned int rtlx_read_poll(int index, int can_sleep)
|
||||
{
|
||||
int minor;
|
||||
unsigned int mask = 0;
|
||||
struct rtlx_channel *chan;
|
||||
struct rtlx_channel *chan;
|
||||
|
||||
minor = MINOR(file->f_dentry->d_inode->i_rdev);
|
||||
chan = &rtlx->channel[minor];
|
||||
if (rtlx == NULL)
|
||||
return 0;
|
||||
|
||||
poll_wait(file, &channel_wqs[minor].rt_queue, wait);
|
||||
poll_wait(file, &channel_wqs[minor].lx_queue, wait);
|
||||
chan = &rtlx->channel[index];
|
||||
|
||||
/* data available to read? */
|
||||
if (chan->lx_read != chan->lx_write)
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
if (chan->lx_read == chan->lx_write) {
|
||||
if (can_sleep) {
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
/* space to write */
|
||||
if (spacefree(chan->rt_read, chan->rt_write, chan->buffer_size))
|
||||
mask |= POLLOUT | POLLWRNORM;
|
||||
/* go to sleep */
|
||||
add_wait_queue(&channel_wqs[index].lx_queue, &wait);
|
||||
|
||||
return mask;
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
while (chan->lx_read == chan->lx_write) {
|
||||
schedule();
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
if (sp_stopping) {
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
|
||||
|
||||
/* back running */
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (chan->lx_write + chan->buffer_size - chan->lx_read)
|
||||
% chan->buffer_size;
|
||||
}
|
||||
|
||||
static ssize_t rtlx_read(struct file *file, char __user * buffer, size_t count,
|
||||
loff_t * ppos)
|
||||
static inline int write_spacefree(int read, int write, int size)
|
||||
{
|
||||
unsigned long failed;
|
||||
size_t fl = 0L;
|
||||
int minor;
|
||||
struct rtlx_channel *lx;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
minor = MINOR(file->f_dentry->d_inode->i_rdev);
|
||||
lx = &rtlx->channel[minor];
|
||||
|
||||
/* data available? */
|
||||
if (lx->lx_write == lx->lx_read) {
|
||||
if (file->f_flags & O_NONBLOCK)
|
||||
return 0; /* -EAGAIN makes cat whinge */
|
||||
|
||||
/* go to sleep */
|
||||
add_wait_queue(&channel_wqs[minor].lx_queue, &wait);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
while (lx->lx_write == lx->lx_read)
|
||||
schedule();
|
||||
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&channel_wqs[minor].lx_queue, &wait);
|
||||
|
||||
/* back running */
|
||||
if (read == write) {
|
||||
/*
|
||||
* Never fill the buffer completely, so indexes are always
|
||||
* equal if empty and only empty, or !equal if data available
|
||||
*/
|
||||
return size - 1;
|
||||
}
|
||||
|
||||
return ((read + size - write) % size) - 1;
|
||||
}
|
||||
|
||||
unsigned int rtlx_write_poll(int index)
|
||||
{
|
||||
struct rtlx_channel *chan = &rtlx->channel[index];
|
||||
return write_spacefree(chan->rt_read, chan->rt_write, chan->buffer_size);
|
||||
}
|
||||
|
||||
static inline void copy_to(void *dst, void *src, size_t count, int user)
|
||||
{
|
||||
if (user)
|
||||
copy_to_user(dst, src, count);
|
||||
else
|
||||
memcpy(dst, src, count);
|
||||
}
|
||||
|
||||
static inline void copy_from(void *dst, void *src, size_t count, int user)
|
||||
{
|
||||
if (user)
|
||||
copy_from_user(dst, src, count);
|
||||
else
|
||||
memcpy(dst, src, count);
|
||||
}
|
||||
|
||||
ssize_t rtlx_read(int index, void *buff, size_t count, int user)
|
||||
{
|
||||
size_t fl = 0L;
|
||||
struct rtlx_channel *lx;
|
||||
|
||||
if (rtlx == NULL)
|
||||
return -ENOSYS;
|
||||
|
||||
lx = &rtlx->channel[index];
|
||||
|
||||
/* find out how much in total */
|
||||
count = min(count,
|
||||
(size_t)(lx->lx_write + lx->buffer_size - lx->lx_read) % lx->buffer_size);
|
||||
(size_t)(lx->lx_write + lx->buffer_size - lx->lx_read)
|
||||
% lx->buffer_size);
|
||||
|
||||
/* then how much from the read pointer onwards */
|
||||
fl = min(count, (size_t)lx->buffer_size - lx->lx_read);
|
||||
fl = min( count, (size_t)lx->buffer_size - lx->lx_read);
|
||||
|
||||
failed = copy_to_user (buffer, &lx->lx_buffer[lx->lx_read], fl);
|
||||
if (failed) {
|
||||
count = fl - failed;
|
||||
goto out;
|
||||
}
|
||||
copy_to(buff, &lx->lx_buffer[lx->lx_read], fl, user);
|
||||
|
||||
/* and if there is anything left at the beginning of the buffer */
|
||||
if (count - fl) {
|
||||
failed = copy_to_user (buffer + fl, lx->lx_buffer, count - fl);
|
||||
if (failed) {
|
||||
count -= failed;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if ( count - fl )
|
||||
copy_to (buff + fl, lx->lx_buffer, count - fl, user);
|
||||
|
||||
out:
|
||||
/* update the index */
|
||||
lx->lx_read += count;
|
||||
lx->lx_read %= lx->buffer_size;
|
||||
@ -242,20 +365,101 @@ out:
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t rtlx_write(struct file *file, const char __user * buffer,
|
||||
size_t count, loff_t * ppos)
|
||||
ssize_t rtlx_write(int index, void *buffer, size_t count, int user)
|
||||
{
|
||||
unsigned long failed;
|
||||
int minor;
|
||||
struct rtlx_channel *rt;
|
||||
size_t fl;
|
||||
|
||||
if (rtlx == NULL)
|
||||
return(-ENOSYS);
|
||||
|
||||
rt = &rtlx->channel[index];
|
||||
|
||||
/* total number of bytes to copy */
|
||||
count = min(count,
|
||||
(size_t)write_spacefree(rt->rt_read, rt->rt_write,
|
||||
rt->buffer_size));
|
||||
|
||||
/* first bit from write pointer to the end of the buffer, or count */
|
||||
fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
|
||||
|
||||
copy_from (&rt->rt_buffer[rt->rt_write], buffer, fl, user);
|
||||
|
||||
/* if there's any left copy to the beginning of the buffer */
|
||||
if( count - fl )
|
||||
copy_from (rt->rt_buffer, buffer + fl, count - fl, user);
|
||||
|
||||
rt->rt_write += count;
|
||||
rt->rt_write %= rt->buffer_size;
|
||||
|
||||
return(count);
|
||||
}
|
||||
|
||||
|
||||
static int file_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
int minor = MINOR(inode->i_rdev);
|
||||
|
||||
return rtlx_open(minor, (filp->f_flags & O_NONBLOCK) ? 0 : 1);
|
||||
}
|
||||
|
||||
static int file_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
int minor;
|
||||
minor = MINOR(inode->i_rdev);
|
||||
|
||||
return rtlx_release(minor);
|
||||
}
|
||||
|
||||
static unsigned int file_poll(struct file *file, poll_table * wait)
|
||||
{
|
||||
int minor;
|
||||
unsigned int mask = 0;
|
||||
|
||||
minor = MINOR(file->f_dentry->d_inode->i_rdev);
|
||||
|
||||
poll_wait(file, &channel_wqs[minor].rt_queue, wait);
|
||||
poll_wait(file, &channel_wqs[minor].lx_queue, wait);
|
||||
|
||||
if (rtlx == NULL)
|
||||
return 0;
|
||||
|
||||
/* data available to read? */
|
||||
if (rtlx_read_poll(minor, 0))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
/* space to write */
|
||||
if (rtlx_write_poll(minor))
|
||||
mask |= POLLOUT | POLLWRNORM;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static ssize_t file_read(struct file *file, char __user * buffer, size_t count,
|
||||
loff_t * ppos)
|
||||
{
|
||||
int minor = MINOR(file->f_dentry->d_inode->i_rdev);
|
||||
|
||||
/* data available? */
|
||||
if (!rtlx_read_poll(minor, (file->f_flags & O_NONBLOCK) ? 0 : 1)) {
|
||||
return 0; // -EAGAIN makes cat whinge
|
||||
}
|
||||
|
||||
return rtlx_read(minor, buffer, count, 1);
|
||||
}
|
||||
|
||||
static ssize_t file_write(struct file *file, const char __user * buffer,
|
||||
size_t count, loff_t * ppos)
|
||||
{
|
||||
int minor;
|
||||
struct rtlx_channel *rt;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
minor = MINOR(file->f_dentry->d_inode->i_rdev);
|
||||
rt = &rtlx->channel[minor];
|
||||
|
||||
/* any space left... */
|
||||
if (!spacefree(rt->rt_read, rt->rt_write, rt->buffer_size)) {
|
||||
if (!rtlx_write_poll(minor)) {
|
||||
|
||||
if (file->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
@ -263,61 +467,64 @@ static ssize_t rtlx_write(struct file *file, const char __user * buffer,
|
||||
add_wait_queue(&channel_wqs[minor].rt_queue, &wait);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
while (!spacefree(rt->rt_read, rt->rt_write, rt->buffer_size))
|
||||
while (!rtlx_write_poll(minor))
|
||||
schedule();
|
||||
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&channel_wqs[minor].rt_queue, &wait);
|
||||
}
|
||||
|
||||
/* total number of bytes to copy */
|
||||
count = min(count, (size_t)spacefree(rt->rt_read, rt->rt_write, rt->buffer_size) );
|
||||
|
||||
/* first bit from write pointer to the end of the buffer, or count */
|
||||
fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
|
||||
|
||||
failed = copy_from_user(&rt->rt_buffer[rt->rt_write], buffer, fl);
|
||||
if (failed) {
|
||||
count = fl - failed;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* if there's any left copy to the beginning of the buffer */
|
||||
if (count - fl) {
|
||||
failed = copy_from_user(rt->rt_buffer, buffer + fl, count - fl);
|
||||
if (failed) {
|
||||
count -= failed;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
rt->rt_write += count;
|
||||
rt->rt_write %= rt->buffer_size;
|
||||
|
||||
return count;
|
||||
return rtlx_write(minor, (void *)buffer, count, 1);
|
||||
}
|
||||
|
||||
static struct file_operations rtlx_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = rtlx_open,
|
||||
.release = rtlx_release,
|
||||
.write = rtlx_write,
|
||||
.read = rtlx_read,
|
||||
.poll = rtlx_poll
|
||||
.owner = THIS_MODULE,
|
||||
.open = file_open,
|
||||
.release = file_release,
|
||||
.write = file_write,
|
||||
.read = file_read,
|
||||
.poll = file_poll
|
||||
};
|
||||
|
||||
static struct irqaction rtlx_irq = {
|
||||
.handler = rtlx_interrupt,
|
||||
.flags = SA_INTERRUPT,
|
||||
.name = "RTLX",
|
||||
};
|
||||
|
||||
static int rtlx_irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ;
|
||||
|
||||
static char register_chrdev_failed[] __initdata =
|
||||
KERN_ERR "rtlx_module_init: unable to register device\n";
|
||||
|
||||
static int __init rtlx_module_init(void)
|
||||
static int rtlx_module_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
major = register_chrdev(0, module_name, &rtlx_fops);
|
||||
if (major < 0) {
|
||||
printk(register_chrdev_failed);
|
||||
return major;
|
||||
}
|
||||
|
||||
/* initialise the wait queues */
|
||||
for (i = 0; i < RTLX_CHANNELS; i++) {
|
||||
init_waitqueue_head(&channel_wqs[i].rt_queue);
|
||||
init_waitqueue_head(&channel_wqs[i].lx_queue);
|
||||
channel_wqs[i].in_open = 0;
|
||||
}
|
||||
|
||||
/* set up notifiers */
|
||||
notify.start = starting;
|
||||
notify.stop = stopping;
|
||||
vpe_notify(RTLX_TARG_VPE, ¬ify);
|
||||
|
||||
if (cpu_has_vint)
|
||||
set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch);
|
||||
|
||||
rtlx_irq.dev_id = rtlx;
|
||||
setup_irq(rtlx_irq_num, &rtlx_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -330,5 +537,5 @@ module_init(rtlx_module_init);
|
||||
module_exit(rtlx_module_exit);
|
||||
|
||||
MODULE_DESCRIPTION("MIPS RTLX");
|
||||
MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc.");
|
||||
MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -569,8 +569,19 @@ einval: li v0, -EINVAL
|
||||
sys sys_tkill 2
|
||||
sys sys_sendfile64 5
|
||||
sys sys_futex 6
|
||||
#ifdef CONFIG_MIPS_MT_FPAFF
|
||||
/*
|
||||
* For FPU affinity scheduling on MIPS MT processors, we need to
|
||||
* intercept sys_sched_xxxaffinity() calls until we get a proper hook
|
||||
* in kernel/sched.c. Considered only temporary we only support these
|
||||
* hooks for the 32-bit kernel - there is no MIPS64 MT processor atm.
|
||||
*/
|
||||
sys mipsmt_sys_sched_setaffinity 3
|
||||
sys mipsmt_sys_sched_getaffinity 3
|
||||
#else
|
||||
sys sys_sched_setaffinity 3
|
||||
sys sys_sched_getaffinity 3 /* 4240 */
|
||||
#endif /* CONFIG_MIPS_MT_FPAFF */
|
||||
sys sys_io_setup 2
|
||||
sys sys_io_destroy 1
|
||||
sys sys_io_getevents 5
|
||||
@ -634,6 +645,8 @@ einval: li v0, -EINVAL
|
||||
sys sys_pselect6 6
|
||||
sys sys_ppoll 5
|
||||
sys sys_unshare 1
|
||||
sys sys_splice 4
|
||||
sys sys_sync_file_range 7 /* 4305 */
|
||||
.endm
|
||||
|
||||
/* We pre-compute the number of _instruction_ bytes needed to
|
||||
|
@ -460,3 +460,5 @@ sys_call_table:
|
||||
PTR sys_pselect6 /* 5260 */
|
||||
PTR sys_ppoll
|
||||
PTR sys_unshare
|
||||
PTR sys_splice
|
||||
PTR sys_sync_file_range
|
||||
|
@ -386,3 +386,5 @@ EXPORT(sysn32_call_table)
|
||||
PTR sys_pselect6
|
||||
PTR sys_ppoll /* 6265 */
|
||||
PTR sys_unshare
|
||||
PTR sys_splice
|
||||
PTR sys_sync_file_range
|
||||
|
@ -508,4 +508,6 @@ sys_call_table:
|
||||
PTR sys_pselect6
|
||||
PTR sys_ppoll
|
||||
PTR sys_unshare
|
||||
PTR sys_splice
|
||||
PTR sys32_sync_file_range /* 4305 */
|
||||
.size sys_call_table,.-sys_call_table
|
||||
|
@ -529,7 +529,10 @@ void __init setup_arch(char **cmdline_p)
|
||||
|
||||
int __init fpu_disable(char *s)
|
||||
{
|
||||
cpu_data[0].options &= ~MIPS_CPU_FPU;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NR_CPUS; i++)
|
||||
cpu_data[i].options &= ~MIPS_CPU_FPU;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -1,8 +1,4 @@
|
||||
/*
|
||||
* Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved.
|
||||
*
|
||||
* Elizabeth Clarke (beth@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
|
||||
* published by the Free Software Foundation.
|
||||
@ -16,6 +12,10 @@
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
*
|
||||
* Copyright (C) 2004, 05, 06 MIPS Technologies, Inc.
|
||||
* Elizabeth Clarke (beth@mips.com)
|
||||
* Ralf Baechle (ralf@linux-mips.org)
|
||||
* Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
@ -24,6 +24,7 @@
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/system.h>
|
||||
@ -33,8 +34,8 @@
|
||||
#include <asm/time.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/mipsmtregs.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/mips-boards/maltaint.h>
|
||||
#include <asm/mips_mt.h>
|
||||
#include <asm/mips-boards/maltaint.h> /* This is f*cking wrong */
|
||||
|
||||
#define MIPS_CPU_IPI_RESCHED_IRQ 0
|
||||
#define MIPS_CPU_IPI_CALL_IRQ 1
|
||||
@ -66,6 +67,7 @@ void __init sanitize_tlb_entries(void)
|
||||
if (!cpu_has_mipsmt)
|
||||
return;
|
||||
|
||||
/* Enable VPC */
|
||||
set_c0_mvpcontrol(MVPCONTROL_VPC);
|
||||
|
||||
back_to_back_c0_hazard();
|
||||
@ -106,12 +108,12 @@ void __init sanitize_tlb_entries(void)
|
||||
|
||||
static void ipi_resched_dispatch (struct pt_regs *regs)
|
||||
{
|
||||
do_IRQ(MIPS_CPU_IPI_RESCHED_IRQ, regs);
|
||||
do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ, regs);
|
||||
}
|
||||
|
||||
static void ipi_call_dispatch (struct pt_regs *regs)
|
||||
{
|
||||
do_IRQ(MIPS_CPU_IPI_CALL_IRQ, regs);
|
||||
do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ, regs);
|
||||
}
|
||||
|
||||
irqreturn_t ipi_resched_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
@ -148,6 +150,11 @@ void plat_smp_setup(void)
|
||||
unsigned long val;
|
||||
int i, num;
|
||||
|
||||
#ifdef CONFIG_MIPS_MT_FPAFF
|
||||
/* If we have an FPU, enroll ourselves in the FPU-full mask */
|
||||
if (cpu_has_fpu)
|
||||
cpu_set(0, mt_fpu_cpumask);
|
||||
#endif /* CONFIG_MIPS_MT_FPAFF */
|
||||
if (!cpu_has_mipsmt)
|
||||
return;
|
||||
|
||||
@ -155,6 +162,8 @@ void plat_smp_setup(void)
|
||||
dvpe();
|
||||
dmt();
|
||||
|
||||
mips_mt_set_cpuoptions();
|
||||
|
||||
/* Put MVPE's into 'configuration state' */
|
||||
set_c0_mvpcontrol(MVPCONTROL_VPC);
|
||||
|
||||
@ -189,11 +198,13 @@ void plat_smp_setup(void)
|
||||
|
||||
if (i != 0) {
|
||||
write_vpe_c0_status((read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0);
|
||||
write_vpe_c0_cause(read_vpe_c0_cause() & ~CAUSEF_IP);
|
||||
|
||||
/* set config to be the same as vpe0, particularly kseg0 coherency alg */
|
||||
write_vpe_c0_config( read_c0_config());
|
||||
|
||||
/* make sure there are no software interrupts pending */
|
||||
write_vpe_c0_cause(read_vpe_c0_cause() & ~(C_SW1|C_SW0));
|
||||
|
||||
/* Propagate Config7 */
|
||||
write_vpe_c0_config7(read_c0_config7());
|
||||
}
|
||||
@ -233,16 +244,16 @@ void plat_smp_setup(void)
|
||||
/* We'll wait until starting the secondaries before starting MVPE */
|
||||
|
||||
printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);
|
||||
}
|
||||
|
||||
void __init plat_prepare_cpus(unsigned int max_cpus)
|
||||
{
|
||||
/* set up ipi interrupts */
|
||||
if (cpu_has_vint) {
|
||||
set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
|
||||
set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
|
||||
}
|
||||
}
|
||||
|
||||
void __init plat_prepare_cpus(unsigned int max_cpus)
|
||||
{
|
||||
cpu_ipi_resched_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
|
||||
cpu_ipi_call_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ;
|
||||
|
||||
@ -287,7 +298,8 @@ void prom_boot_secondary(int cpu, struct task_struct *idle)
|
||||
/* global pointer */
|
||||
write_tc_gpr_gp((unsigned long)gp);
|
||||
|
||||
flush_icache_range((unsigned long)gp, (unsigned long)(gp + 1));
|
||||
flush_icache_range((unsigned long)gp,
|
||||
(unsigned long)(gp + sizeof(struct thread_info)));
|
||||
|
||||
/* finally out of configuration and into chaos */
|
||||
clear_c0_mvpcontrol(MVPCONTROL_VPC);
|
||||
@ -305,6 +317,12 @@ void prom_smp_finish(void)
|
||||
{
|
||||
write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ));
|
||||
|
||||
#ifdef CONFIG_MIPS_MT_FPAFF
|
||||
/* If we have an FPU, enroll ourselves in the FPU-full mask */
|
||||
if (cpu_has_fpu)
|
||||
cpu_set(smp_processor_id(), mt_fpu_cpumask);
|
||||
#endif /* CONFIG_MIPS_MT_FPAFF */
|
||||
|
||||
local_irq_enable();
|
||||
}
|
||||
|
@ -38,6 +38,10 @@
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/smp.h>
|
||||
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
#include <asm/mipsmtregs.h>
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
cpumask_t phys_cpu_present_map; /* Bitmask of available CPUs */
|
||||
volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */
|
||||
cpumask_t cpu_online_map; /* Bitmask of currently online CPUs */
|
||||
@ -85,6 +89,10 @@ asmlinkage void start_secondary(void)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
/* Only do cpu_probe for first TC of CPU */
|
||||
if ((read_c0_tcbind() & TCBIND_CURTC) == 0)
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
cpu_probe();
|
||||
cpu_report();
|
||||
per_cpu_trap_init();
|
||||
@ -179,11 +187,13 @@ int smp_call_function (void (*func) (void *info), void *info, int retry,
|
||||
if (wait)
|
||||
while (atomic_read(&data.finished) != cpus)
|
||||
barrier();
|
||||
call_data = NULL;
|
||||
spin_unlock(&smp_call_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void smp_call_function_interrupt(void)
|
||||
{
|
||||
void (*func) (void *info) = call_data->func;
|
||||
@ -446,5 +456,3 @@ subsys_initcall(topology_init);
|
||||
|
||||
EXPORT_SYMBOL(flush_tlb_page);
|
||||
EXPORT_SYMBOL(flush_tlb_one);
|
||||
EXPORT_SYMBOL(cpu_data);
|
||||
EXPORT_SYMBOL(synchronize_irq);
|
||||
|
130
arch/mips/kernel/smtc-asm.S
Normal file
130
arch/mips/kernel/smtc-asm.S
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Assembly Language Functions for MIPS MT SMTC support
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file should be built into the kernel only if CONFIG_MIPS_MT_SMTC is set. */
|
||||
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/asmmacro.h>
|
||||
#include <asm/stackframe.h>
|
||||
#include <asm/stackframe.h>
|
||||
|
||||
/*
|
||||
* "Software Interrupt" linkage.
|
||||
*
|
||||
* This is invoked when an "Interrupt" is sent from one TC to another,
|
||||
* where the TC to be interrupted is halted, has it's Restart address
|
||||
* and Status values saved by the "remote control" thread, then modified
|
||||
* to cause execution to begin here, in kenel mode. This code then
|
||||
* disguises the TC state as that of an exception and transfers
|
||||
* control to the general exception or vectored interrupt handler.
|
||||
*/
|
||||
.set noreorder
|
||||
|
||||
/*
|
||||
The __smtc_ipi_vector would use k0 and k1 as temporaries and
|
||||
1) Set EXL (this is per-VPE, so this can't be done by proxy!)
|
||||
2) Restore the K/CU and IXMT bits to the pre "exception" state
|
||||
(EXL means no interrupts and access to the kernel map).
|
||||
3) Set EPC to be the saved value of TCRestart.
|
||||
4) Jump to the exception handler entry point passed by the sender.
|
||||
|
||||
CAN WE PROVE THAT WE WON'T DO THIS IF INTS DISABLED??
|
||||
*/
|
||||
|
||||
/*
|
||||
* Reviled and slandered vision: Set EXL and restore K/CU/IXMT
|
||||
* state of pre-halt thread, then save everything and call
|
||||
* thought some function pointer to imaginary_exception, which
|
||||
* will parse a register value or memory message queue to
|
||||
* deliver things like interprocessor interrupts. On return
|
||||
* from that function, jump to the global ret_from_irq code
|
||||
* to invoke the scheduler and return as appropriate.
|
||||
*/
|
||||
|
||||
#define PT_PADSLOT4 (PT_R0-8)
|
||||
#define PT_PADSLOT5 (PT_R0-4)
|
||||
|
||||
.text
|
||||
.align 5
|
||||
FEXPORT(__smtc_ipi_vector)
|
||||
.set noat
|
||||
/* Disable thread scheduling to make Status update atomic */
|
||||
DMT 27 # dmt k1
|
||||
ehb
|
||||
/* Set EXL */
|
||||
mfc0 k0,CP0_STATUS
|
||||
ori k0,k0,ST0_EXL
|
||||
mtc0 k0,CP0_STATUS
|
||||
ehb
|
||||
/* Thread scheduling now inhibited by EXL. Restore TE state. */
|
||||
andi k1,k1,VPECONTROL_TE
|
||||
beqz k1,1f
|
||||
emt
|
||||
1:
|
||||
/*
|
||||
* The IPI sender has put some information on the anticipated
|
||||
* kernel stack frame. If we were in user mode, this will be
|
||||
* built above the saved kernel SP. If we were already in the
|
||||
* kernel, it will be built above the current CPU SP.
|
||||
*
|
||||
* Were we in kernel mode, as indicated by CU0?
|
||||
*/
|
||||
sll k1,k0,3
|
||||
.set noreorder
|
||||
bltz k1,2f
|
||||
move k1,sp
|
||||
.set reorder
|
||||
/*
|
||||
* If previously in user mode, set CU0 and use kernel stack.
|
||||
*/
|
||||
li k1,ST0_CU0
|
||||
or k1,k1,k0
|
||||
mtc0 k1,CP0_STATUS
|
||||
ehb
|
||||
get_saved_sp
|
||||
/* Interrupting TC will have pre-set values in slots in the new frame */
|
||||
2: subu k1,k1,PT_SIZE
|
||||
/* Load TCStatus Value */
|
||||
lw k0,PT_TCSTATUS(k1)
|
||||
/* Write it to TCStatus to restore CU/KSU/IXMT state */
|
||||
mtc0 k0,$2,1
|
||||
ehb
|
||||
lw k0,PT_EPC(k1)
|
||||
mtc0 k0,CP0_EPC
|
||||
/* Save all will redundantly recompute the SP, but use it for now */
|
||||
SAVE_ALL
|
||||
CLI
|
||||
move a0,sp
|
||||
/* Function to be invoked passed stack pad slot 5 */
|
||||
lw t0,PT_PADSLOT5(sp)
|
||||
/* Argument from sender passed in stack pad slot 4 */
|
||||
lw a1,PT_PADSLOT4(sp)
|
||||
jalr t0
|
||||
nop
|
||||
j ret_from_irq
|
||||
nop
|
||||
|
||||
/*
|
||||
* Called from idle loop to provoke processing of queued IPIs
|
||||
* First IPI message in queue passed as argument.
|
||||
*/
|
||||
|
||||
LEAF(self_ipi)
|
||||
/* Before anything else, block interrupts */
|
||||
mfc0 t0,CP0_TCSTATUS
|
||||
ori t1,t0,TCSTATUS_IXMT
|
||||
mtc0 t1,CP0_TCSTATUS
|
||||
ehb
|
||||
/* We know we're in kernel mode, so prepare stack frame */
|
||||
subu t1,sp,PT_SIZE
|
||||
sw ra,PT_EPC(t1)
|
||||
sw a0,PT_PADSLOT4(t1)
|
||||
la t2,ipi_decode
|
||||
sw t2,PT_PADSLOT5(t1)
|
||||
/* Save pre-disable value of TCStatus */
|
||||
sw t0,PT_TCSTATUS(t1)
|
||||
j __smtc_ipi_vector
|
||||
nop
|
||||
END(self_ipi)
|
93
arch/mips/kernel/smtc-proc.c
Normal file
93
arch/mips/kernel/smtc-proc.c
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* /proc hooks for SMTC kernel
|
||||
* Copyright (C) 2005 Mips Technologies, Inc
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/hardirq.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
#include <asm/smtc_proc.h>
|
||||
|
||||
/*
|
||||
* /proc diagnostic and statistics hooks
|
||||
*/
|
||||
|
||||
/*
|
||||
* Statistics gathered
|
||||
*/
|
||||
unsigned long selfipis[NR_CPUS];
|
||||
|
||||
struct smtc_cpu_proc smtc_cpu_stats[NR_CPUS];
|
||||
|
||||
static struct proc_dir_entry *smtc_stats;
|
||||
|
||||
atomic_t smtc_fpu_recoveries;
|
||||
|
||||
static int proc_read_smtc(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
int totalen = 0;
|
||||
int len;
|
||||
int i;
|
||||
extern unsigned long ebase;
|
||||
|
||||
len = sprintf(page, "SMTC Status Word: 0x%08x\n", smtc_status);
|
||||
totalen += len;
|
||||
page += len;
|
||||
len = sprintf(page, "Config7: 0x%08x\n", read_c0_config7());
|
||||
totalen += len;
|
||||
page += len;
|
||||
len = sprintf(page, "EBASE: 0x%08lx\n", ebase);
|
||||
totalen += len;
|
||||
page += len;
|
||||
len = sprintf(page, "Counter Interrupts taken per CPU (TC)\n");
|
||||
totalen += len;
|
||||
page += len;
|
||||
for (i=0; i < NR_CPUS; i++) {
|
||||
len = sprintf(page, "%d: %ld\n", i, smtc_cpu_stats[i].timerints);
|
||||
totalen += len;
|
||||
page += len;
|
||||
}
|
||||
len = sprintf(page, "Self-IPIs by CPU:\n");
|
||||
totalen += len;
|
||||
page += len;
|
||||
for(i = 0; i < NR_CPUS; i++) {
|
||||
len = sprintf(page, "%d: %ld\n", i, smtc_cpu_stats[i].selfipis);
|
||||
totalen += len;
|
||||
page += len;
|
||||
}
|
||||
len = sprintf(page, "%d Recoveries of \"stolen\" FPU\n",
|
||||
atomic_read(&smtc_fpu_recoveries));
|
||||
totalen += len;
|
||||
page += len;
|
||||
|
||||
return totalen;
|
||||
}
|
||||
|
||||
void init_smtc_stats(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<NR_CPUS; i++) {
|
||||
smtc_cpu_stats[i].timerints = 0;
|
||||
smtc_cpu_stats[i].selfipis = 0;
|
||||
}
|
||||
|
||||
atomic_set(&smtc_fpu_recoveries, 0);
|
||||
|
||||
smtc_stats = create_proc_read_entry("smtc", 0444, NULL,
|
||||
proc_read_smtc, NULL);
|
||||
}
|
1322
arch/mips/kernel/smtc.c
Normal file
1322
arch/mips/kernel/smtc.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -116,8 +116,7 @@ static void c0_timer_ack(void)
|
||||
write_c0_compare(expirelo);
|
||||
|
||||
/* Check to see if we have missed any timer interrupts. */
|
||||
count = read_c0_count();
|
||||
if ((count - expirelo) < 0x7fffffff) {
|
||||
while (((count = read_c0_count()) - expirelo) < 0x7fffffff) {
|
||||
/* missed_timer_count++; */
|
||||
expirelo = count + cycles_per_jiffy;
|
||||
write_c0_compare(expirelo);
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include <asm/watch.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
extern asmlinkage void handle_int(void);
|
||||
extern asmlinkage void handle_tlbm(void);
|
||||
extern asmlinkage void handle_tlbl(void);
|
||||
extern asmlinkage void handle_tlbs(void);
|
||||
@ -279,9 +280,16 @@ static DEFINE_SPINLOCK(die_lock);
|
||||
NORET_TYPE void ATTRIB_NORET die(const char * str, struct pt_regs * regs)
|
||||
{
|
||||
static int die_counter;
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
unsigned long dvpret = dvpe();
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
console_verbose();
|
||||
spin_lock_irq(&die_lock);
|
||||
bust_spinlocks(1);
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
mips_mt_regdump(dvpret);
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
printk("%s[#%d]:\n", str, ++die_counter);
|
||||
show_registers(regs);
|
||||
spin_unlock_irq(&die_lock);
|
||||
@ -750,12 +758,43 @@ asmlinkage void do_cpu(struct pt_regs *regs)
|
||||
¤t->thread.fpu.soft);
|
||||
if (sig)
|
||||
force_sig(sig, current);
|
||||
#ifdef CONFIG_MIPS_MT_FPAFF
|
||||
else {
|
||||
/*
|
||||
* MIPS MT processors may have fewer FPU contexts
|
||||
* than CPU threads. If we've emulated more than
|
||||
* some threshold number of instructions, force
|
||||
* migration to a "CPU" that has FP support.
|
||||
*/
|
||||
if(mt_fpemul_threshold > 0
|
||||
&& ((current->thread.emulated_fp++
|
||||
> mt_fpemul_threshold))) {
|
||||
/*
|
||||
* If there's no FPU present, or if the
|
||||
* application has already restricted
|
||||
* the allowed set to exclude any CPUs
|
||||
* with FPUs, we'll skip the procedure.
|
||||
*/
|
||||
if (cpus_intersects(current->cpus_allowed,
|
||||
mt_fpu_cpumask)) {
|
||||
cpumask_t tmask;
|
||||
|
||||
cpus_and(tmask,
|
||||
current->thread.user_cpus_allowed,
|
||||
mt_fpu_cpumask);
|
||||
set_cpus_allowed(current, tmask);
|
||||
current->thread.mflags |= MF_FPUBOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_MIPS_MT_FPAFF */
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
die_if_kernel("do_cpu invoked from kernel context!", regs);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -793,6 +832,36 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
|
||||
|
||||
asmlinkage void do_mt(struct pt_regs *regs)
|
||||
{
|
||||
int subcode;
|
||||
|
||||
die_if_kernel("MIPS MT Thread exception in kernel", regs);
|
||||
|
||||
subcode = (read_vpe_c0_vpecontrol() & VPECONTROL_EXCPT)
|
||||
>> VPECONTROL_EXCPT_SHIFT;
|
||||
switch (subcode) {
|
||||
case 0:
|
||||
printk(KERN_ERR "Thread Underflow\n");
|
||||
break;
|
||||
case 1:
|
||||
printk(KERN_ERR "Thread Overflow\n");
|
||||
break;
|
||||
case 2:
|
||||
printk(KERN_ERR "Invalid YIELD Qualifier\n");
|
||||
break;
|
||||
case 3:
|
||||
printk(KERN_ERR "Gating Storage Exception\n");
|
||||
break;
|
||||
case 4:
|
||||
printk(KERN_ERR "YIELD Scheduler Exception\n");
|
||||
break;
|
||||
case 5:
|
||||
printk(KERN_ERR "Gating Storage Schedulier Exception\n");
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "*** UNKNOWN THREAD EXCEPTION %d ***\n",
|
||||
subcode);
|
||||
break;
|
||||
}
|
||||
die_if_kernel("MIPS MT Thread exception in kernel", regs);
|
||||
|
||||
force_sig(SIGILL, current);
|
||||
@ -928,7 +997,15 @@ void ejtag_exception_handler(struct pt_regs *regs)
|
||||
*/
|
||||
void nmi_exception_handler(struct pt_regs *regs)
|
||||
{
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
unsigned long dvpret = dvpe();
|
||||
bust_spinlocks(1);
|
||||
printk("NMI taken!!!!\n");
|
||||
mips_mt_regdump(dvpret);
|
||||
#else
|
||||
bust_spinlocks(1);
|
||||
printk("NMI taken!!!!\n");
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
die("NMI", regs);
|
||||
while(1) ;
|
||||
}
|
||||
@ -960,27 +1037,29 @@ void *set_except_vector(int n, void *addr)
|
||||
|
||||
#ifdef CONFIG_CPU_MIPSR2
|
||||
/*
|
||||
* Shadow register allocation
|
||||
* MIPSR2 shadow register set allocation
|
||||
* FIXME: SMP...
|
||||
*/
|
||||
|
||||
/* MIPSR2 shadow register sets */
|
||||
struct shadow_registers {
|
||||
spinlock_t sr_lock; /* */
|
||||
int sr_supported; /* Number of shadow register sets supported */
|
||||
int sr_allocated; /* Bitmap of allocated shadow registers */
|
||||
static struct shadow_registers {
|
||||
/*
|
||||
* Number of shadow register sets supported
|
||||
*/
|
||||
unsigned long sr_supported;
|
||||
/*
|
||||
* Bitmap of allocated shadow registers
|
||||
*/
|
||||
unsigned long sr_allocated;
|
||||
} shadow_registers;
|
||||
|
||||
void mips_srs_init(void)
|
||||
static void mips_srs_init(void)
|
||||
{
|
||||
#ifdef CONFIG_CPU_MIPSR2_SRS
|
||||
shadow_registers.sr_supported = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
|
||||
printk ("%d MIPSR2 register sets available\n", shadow_registers.sr_supported);
|
||||
#else
|
||||
shadow_registers.sr_supported = 1;
|
||||
printk(KERN_INFO "%d MIPSR2 register sets available\n",
|
||||
shadow_registers.sr_supported);
|
||||
#endif
|
||||
shadow_registers.sr_allocated = 1; /* Set 0 used by kernel */
|
||||
spin_lock_init(&shadow_registers.sr_lock);
|
||||
}
|
||||
|
||||
int mips_srs_max(void)
|
||||
@ -988,38 +1067,30 @@ int mips_srs_max(void)
|
||||
return shadow_registers.sr_supported;
|
||||
}
|
||||
|
||||
int mips_srs_alloc (void)
|
||||
int mips_srs_alloc(void)
|
||||
{
|
||||
struct shadow_registers *sr = &shadow_registers;
|
||||
unsigned long flags;
|
||||
int set;
|
||||
|
||||
spin_lock_irqsave(&sr->sr_lock, flags);
|
||||
again:
|
||||
set = find_first_zero_bit(&sr->sr_allocated, sr->sr_supported);
|
||||
if (set >= sr->sr_supported)
|
||||
return -1;
|
||||
|
||||
for (set = 0; set < sr->sr_supported; set++) {
|
||||
if ((sr->sr_allocated & (1 << set)) == 0) {
|
||||
sr->sr_allocated |= 1 << set;
|
||||
spin_unlock_irqrestore(&sr->sr_lock, flags);
|
||||
return set;
|
||||
}
|
||||
}
|
||||
if (test_and_set_bit(set, &sr->sr_allocated))
|
||||
goto again;
|
||||
|
||||
/* None available */
|
||||
spin_unlock_irqrestore(&sr->sr_lock, flags);
|
||||
return -1;
|
||||
return set;
|
||||
}
|
||||
|
||||
void mips_srs_free (int set)
|
||||
void mips_srs_free(int set)
|
||||
{
|
||||
struct shadow_registers *sr = &shadow_registers;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sr->sr_lock, flags);
|
||||
sr->sr_allocated &= ~(1 << set);
|
||||
spin_unlock_irqrestore(&sr->sr_lock, flags);
|
||||
clear_bit(set, &sr->sr_allocated);
|
||||
}
|
||||
|
||||
void *set_vi_srs_handler (int n, void *addr, int srs)
|
||||
static void *set_vi_srs_handler(int n, void *addr, int srs)
|
||||
{
|
||||
unsigned long handler;
|
||||
unsigned long old_handler = vi_handlers[n];
|
||||
@ -1032,8 +1103,7 @@ void *set_vi_srs_handler (int n, void *addr, int srs)
|
||||
if (addr == NULL) {
|
||||
handler = (unsigned long) do_default_vi;
|
||||
srs = 0;
|
||||
}
|
||||
else
|
||||
} else
|
||||
handler = (unsigned long) addr;
|
||||
vi_handlers[n] = (unsigned long) addr;
|
||||
|
||||
@ -1045,8 +1115,7 @@ void *set_vi_srs_handler (int n, void *addr, int srs)
|
||||
if (cpu_has_veic) {
|
||||
if (board_bind_eic_interrupt)
|
||||
board_bind_eic_interrupt (n, srs);
|
||||
}
|
||||
else if (cpu_has_vint) {
|
||||
} else if (cpu_has_vint) {
|
||||
/* SRSMap is only defined if shadow sets are implemented */
|
||||
if (mips_srs_max() > 1)
|
||||
change_c0_srsmap (0xf << n*4, srs << n*4);
|
||||
@ -1060,6 +1129,15 @@ void *set_vi_srs_handler (int n, void *addr, int srs)
|
||||
|
||||
extern char except_vec_vi, except_vec_vi_lui;
|
||||
extern char except_vec_vi_ori, except_vec_vi_end;
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
/*
|
||||
* We need to provide the SMTC vectored interrupt handler
|
||||
* not only with the address of the handler, but with the
|
||||
* Status.IM bit to be masked before going there.
|
||||
*/
|
||||
extern char except_vec_vi_mori;
|
||||
const int mori_offset = &except_vec_vi_mori - &except_vec_vi;
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
const int handler_len = &except_vec_vi_end - &except_vec_vi;
|
||||
const int lui_offset = &except_vec_vi_lui - &except_vec_vi;
|
||||
const int ori_offset = &except_vec_vi_ori - &except_vec_vi;
|
||||
@ -1073,6 +1151,12 @@ void *set_vi_srs_handler (int n, void *addr, int srs)
|
||||
}
|
||||
|
||||
memcpy (b, &except_vec_vi, handler_len);
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
if (n > 7)
|
||||
printk("Vector index %d exceeds SMTC maximum\n", n);
|
||||
w = (u32 *)(b + mori_offset);
|
||||
*w = (*w & 0xffff0000) | (0x100 << n);
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
w = (u32 *)(b + lui_offset);
|
||||
*w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff);
|
||||
w = (u32 *)(b + ori_offset);
|
||||
@ -1095,9 +1179,9 @@ void *set_vi_srs_handler (int n, void *addr, int srs)
|
||||
return (void *)old_handler;
|
||||
}
|
||||
|
||||
void *set_vi_handler (int n, void *addr)
|
||||
void *set_vi_handler(int n, void *addr)
|
||||
{
|
||||
return set_vi_srs_handler (n, addr, 0);
|
||||
return set_vi_srs_handler(n, addr, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1113,8 +1197,29 @@ extern asmlinkage int _restore_fp_context(struct sigcontext *sc);
|
||||
extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc);
|
||||
extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static int smp_save_fp_context(struct sigcontext *sc)
|
||||
{
|
||||
return cpu_has_fpu
|
||||
? _save_fp_context(sc)
|
||||
: fpu_emulator_save_context(sc);
|
||||
}
|
||||
|
||||
static int smp_restore_fp_context(struct sigcontext *sc)
|
||||
{
|
||||
return cpu_has_fpu
|
||||
? _restore_fp_context(sc)
|
||||
: fpu_emulator_restore_context(sc);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void signal_init(void)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
/* For now just do the cpu_has_fpu check when the functions are invoked */
|
||||
save_fp_context = smp_save_fp_context;
|
||||
restore_fp_context = smp_restore_fp_context;
|
||||
#else
|
||||
if (cpu_has_fpu) {
|
||||
save_fp_context = _save_fp_context;
|
||||
restore_fp_context = _restore_fp_context;
|
||||
@ -1122,6 +1227,7 @@ static inline void signal_init(void)
|
||||
save_fp_context = fpu_emulator_save_context;
|
||||
restore_fp_context = fpu_emulator_restore_context;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MIPS32_COMPAT
|
||||
@ -1158,6 +1264,20 @@ void __init per_cpu_trap_init(void)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
unsigned int status_set = ST0_CU0;
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
int secondaryTC = 0;
|
||||
int bootTC = (cpu == 0);
|
||||
|
||||
/*
|
||||
* Only do per_cpu_trap_init() for first TC of Each VPE.
|
||||
* Note that this hack assumes that the SMTC init code
|
||||
* assigns TCs consecutively and in ascending order.
|
||||
*/
|
||||
|
||||
if (((read_c0_tcbind() & TCBIND_CURTC) != 0) &&
|
||||
((read_c0_tcbind() & TCBIND_CURVPE) == cpu_data[cpu - 1].vpe_id))
|
||||
secondaryTC = 1;
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
/*
|
||||
* Disable coprocessors and select 32-bit or 64-bit addressing
|
||||
@ -1180,6 +1300,10 @@ void __init per_cpu_trap_init(void)
|
||||
write_c0_hwrena (0x0000000f); /* Allow rdhwr to all registers */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
if (!secondaryTC) {
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
/*
|
||||
* Interrupt handling.
|
||||
*/
|
||||
@ -1196,6 +1320,9 @@ void __init per_cpu_trap_init(void)
|
||||
} else
|
||||
set_c0_cause(CAUSEF_IV);
|
||||
}
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
}
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
cpu_data[cpu].asid_cache = ASID_FIRST_VERSION;
|
||||
TLBMISS_HANDLER_SETUP();
|
||||
@ -1205,8 +1332,14 @@ void __init per_cpu_trap_init(void)
|
||||
BUG_ON(current->mm);
|
||||
enter_lazy_tlb(&init_mm, current);
|
||||
|
||||
cpu_cache_init();
|
||||
tlb_init();
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
if (bootTC) {
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
cpu_cache_init();
|
||||
tlb_init();
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
}
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
}
|
||||
|
||||
/* Install CPU exception handler */
|
||||
@ -1278,7 +1411,7 @@ void __init trap_init(void)
|
||||
if (cpu_has_veic || cpu_has_vint) {
|
||||
int nvec = cpu_has_veic ? 64 : 8;
|
||||
for (i = 0; i < nvec; i++)
|
||||
set_vi_handler (i, NULL);
|
||||
set_vi_handler(i, NULL);
|
||||
}
|
||||
else if (cpu_has_divec)
|
||||
set_handler(0x200, &except_vec4, 0x8);
|
||||
@ -1297,6 +1430,7 @@ void __init trap_init(void)
|
||||
if (board_be_init)
|
||||
board_be_init();
|
||||
|
||||
set_except_vector(0, handle_int);
|
||||
set_except_vector(1, handle_tlbm);
|
||||
set_except_vector(2, handle_tlbl);
|
||||
set_except_vector(3, handle_tlbs);
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm-generic/vmlinux.lds.h>
|
||||
|
||||
#undef mips /* CPP really sucks for this job */
|
||||
#undef mips
|
||||
#define mips mips
|
||||
OUTPUT_ARCH(mips)
|
||||
ENTRY(kernel_entry)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@
|
||||
#
|
||||
|
||||
obj-y += reset.o setup.o prom.o lasat_board.o \
|
||||
at93c.o interrupt.o lasatIRQ.o
|
||||
at93c.o interrupt.o
|
||||
|
||||
obj-$(CONFIG_LASAT_SYSCTL) += sysctl.o
|
||||
obj-$(CONFIG_DS1603) += ds1603.o
|
||||
|
@ -27,14 +27,13 @@
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/lasat/lasatint.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/gdb-stub.h>
|
||||
|
||||
static volatile int *lasat_int_status = NULL;
|
||||
static volatile int *lasat_int_mask = NULL;
|
||||
static volatile int lasat_int_mask_shift;
|
||||
|
||||
extern asmlinkage void lasatIRQ(void);
|
||||
|
||||
void disable_lasat_irq(unsigned int irq_nr)
|
||||
{
|
||||
unsigned long flags;
|
||||
@ -109,11 +108,17 @@ static unsigned long get_int_status_200(void)
|
||||
return int_status;
|
||||
}
|
||||
|
||||
void lasat_hw0_irqdispatch(struct pt_regs *regs)
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long int_status;
|
||||
unsigned int cause = read_c0_cause();
|
||||
int irq;
|
||||
|
||||
if (cause & CAUSEF_IP7) { /* R4000 count / compare IRQ */
|
||||
ll_timer_interrupt(7, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
int_status = get_int_status();
|
||||
|
||||
/* if int_status == 0, then the interrupt has already been cleared */
|
||||
@ -147,9 +152,6 @@ void __init arch_init_irq(void)
|
||||
panic("arch_init_irq: mips_machtype incorrect");
|
||||
}
|
||||
|
||||
/* Now safe to set the exception vector. */
|
||||
set_except_vector(0, lasatIRQ);
|
||||
|
||||
for (i = 0; i <= LASATINT_END; i++) {
|
||||
irq_desc[i].status = IRQ_DISABLED;
|
||||
irq_desc[i].action = 0;
|
||||
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Carsten Langgaard, carstenl@mips.com
|
||||
* Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
*
|
||||
* Interrupt exception dispatch code.
|
||||
*/
|
||||
#include <asm/asm.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/stackframe.h>
|
||||
|
||||
.text
|
||||
.set noreorder
|
||||
.align 5
|
||||
NESTED(lasatIRQ, PT_SIZE, sp)
|
||||
.set noat
|
||||
SAVE_ALL
|
||||
CLI
|
||||
.set at
|
||||
.set noreorder
|
||||
|
||||
mfc0 s0, CP0_CAUSE # get irq mask
|
||||
|
||||
/* 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
|
||||
|
||||
/* Wheee, a timer interrupt. */
|
||||
li a0, 7
|
||||
jal ll_timer_interrupt
|
||||
move a1, sp
|
||||
|
||||
j ret_from_irq
|
||||
nop
|
||||
|
||||
1:
|
||||
/* Wheee, combined hardware level zero interrupt. */
|
||||
jal lasat_hw0_irqdispatch
|
||||
move a0, sp # delay slot
|
||||
|
||||
j ret_from_irq
|
||||
nop # delay slot
|
||||
|
||||
1:
|
||||
/*
|
||||
* 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
|
||||
mfc0 a1, CP0_EPC
|
||||
|
||||
j ret_from_irq
|
||||
nop
|
||||
END(lasatIRQ)
|
@ -39,8 +39,6 @@
|
||||
|
||||
static struct atlas_ictrl_regs *atlas_hw0_icregs;
|
||||
|
||||
extern asmlinkage void mipsIRQ(void);
|
||||
|
||||
#if 0
|
||||
#define DEBUG_INT(x...) printk(x)
|
||||
#else
|
||||
@ -98,7 +96,7 @@ static inline int ls1bit32(unsigned int x)
|
||||
return b;
|
||||
}
|
||||
|
||||
void atlas_hw0_irqdispatch(struct pt_regs *regs)
|
||||
static inline void atlas_hw0_irqdispatch(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long int_status;
|
||||
int irq;
|
||||
@ -116,6 +114,91 @@ void atlas_hw0_irqdispatch(struct pt_regs *regs)
|
||||
do_IRQ(irq, regs);
|
||||
}
|
||||
|
||||
static inline int clz(unsigned long x)
|
||||
{
|
||||
__asm__ (
|
||||
" .set push \n"
|
||||
" .set mips32 \n"
|
||||
" clz %0, %1 \n"
|
||||
" .set pop \n"
|
||||
: "=r" (x)
|
||||
: "r" (x));
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* Version of ffs that only looks at bits 12..15.
|
||||
*/
|
||||
static inline unsigned int irq_ffs(unsigned int pending)
|
||||
{
|
||||
#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
|
||||
return -clz(pending) + 31 - CAUSEB_IP;
|
||||
#else
|
||||
unsigned int a0 = 7;
|
||||
unsigned int t0;
|
||||
|
||||
t0 = s0 & 0xf000;
|
||||
t0 = t0 < 1;
|
||||
t0 = t0 << 2;
|
||||
a0 = a0 - t0;
|
||||
s0 = s0 << t0;
|
||||
|
||||
t0 = s0 & 0xc000;
|
||||
t0 = t0 < 1;
|
||||
t0 = t0 << 1;
|
||||
a0 = a0 - t0;
|
||||
s0 = s0 << t0;
|
||||
|
||||
t0 = s0 & 0x8000;
|
||||
t0 = t0 < 1;
|
||||
//t0 = t0 << 2;
|
||||
a0 = a0 - t0;
|
||||
//s0 = s0 << t0;
|
||||
|
||||
return a0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* IRQs on the Atlas board look basically (barring software IRQs which we
|
||||
* don't use at all and all external interrupt sources are combined together
|
||||
* on hardware interrupt 0 (MIPS IRQ 2)) like:
|
||||
*
|
||||
* MIPS IRQ Source
|
||||
* -------- ------
|
||||
* 0 Software (ignored)
|
||||
* 1 Software (ignored)
|
||||
* 2 Combined hardware interrupt (hw0)
|
||||
* 3 Hardware (ignored)
|
||||
* 4 Hardware (ignored)
|
||||
* 5 Hardware (ignored)
|
||||
* 6 Hardware (ignored)
|
||||
* 7 R4k timer (what we use)
|
||||
*
|
||||
* We handle the IRQ according to _our_ priority which is:
|
||||
*
|
||||
* Highest ---- R4k Timer
|
||||
* Lowest ---- Combined hardware interrupt
|
||||
*
|
||||
* then we just return, if multiple IRQs are pending then we will just take
|
||||
* another exception, big deal.
|
||||
*/
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
|
||||
int irq;
|
||||
|
||||
irq = irq_ffs(pending);
|
||||
|
||||
if (irq == MIPSCPU_INT_ATLAS)
|
||||
atlas_hw0_irqdispatch(regs);
|
||||
else if (irq > 0)
|
||||
do_IRQ(MIPSCPU_INT_BASE + irq, regs);
|
||||
else
|
||||
spurious_interrupt(regs);
|
||||
}
|
||||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
int i;
|
||||
@ -128,9 +211,6 @@ void __init arch_init_irq(void)
|
||||
*/
|
||||
atlas_hw0_icregs->intrsten = 0xffffffff;
|
||||
|
||||
/* Now safe to set the exception vector. */
|
||||
set_except_vector(0, mipsIRQ);
|
||||
|
||||
for (i = ATLASINT_BASE; i <= ATLASINT_END; i++) {
|
||||
irq_desc[i].status = IRQ_DISABLED;
|
||||
irq_desc[i].action = 0;
|
||||
|
@ -18,8 +18,8 @@
|
||||
# Makefile for the MIPS boards generic routines under Linux.
|
||||
#
|
||||
|
||||
obj-y := mipsIRQ.o reset.o display.o init.o memory.o \
|
||||
printf.o cmdline.o time.o
|
||||
obj-y := reset.o display.o init.o memory.o printf.o \
|
||||
cmdline.o time.o
|
||||
obj-$(CONFIG_PCI) += pci.o
|
||||
obj-$(CONFIG_KGDB) += gdb_hook.o
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include <asm/serial.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static struct serial_state rs_table[RS_TABLE_SIZE] = {
|
||||
static struct serial_state rs_table[] = {
|
||||
SERIAL_PORT_DFNS /* Defined in serial.h */
|
||||
};
|
||||
|
||||
|
@ -220,7 +220,6 @@ void __init kgdb_config (void)
|
||||
generic_putDebugChar (*s++);
|
||||
}
|
||||
|
||||
kgdb_enabled = 1;
|
||||
/* Breakpoint is invoked after interrupts are initialised */
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +22,12 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/pfn.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/sections.h>
|
||||
|
||||
#include <asm/mips-boards/prom.h>
|
||||
|
||||
@ -46,9 +48,6 @@ static char *mtypes[3] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
/* References to section boundaries */
|
||||
extern char _end;
|
||||
|
||||
struct prom_pmemblock * __init prom_getmdesc(void)
|
||||
{
|
||||
char *memsize_str;
|
||||
@ -106,10 +105,10 @@ struct prom_pmemblock * __init prom_getmdesc(void)
|
||||
|
||||
mdesc[3].type = yamon_dontuse;
|
||||
mdesc[3].base = 0x00100000;
|
||||
mdesc[3].size = CPHYSADDR(PAGE_ALIGN(&_end)) - mdesc[3].base;
|
||||
mdesc[3].size = CPHYSADDR(PFN_ALIGN((unsigned long)&_end)) - mdesc[3].base;
|
||||
|
||||
mdesc[4].type = yamon_free;
|
||||
mdesc[4].base = CPHYSADDR(PAGE_ALIGN(&_end));
|
||||
mdesc[4].base = CPHYSADDR(PFN_ALIGN(&_end));
|
||||
mdesc[4].size = memsize - mdesc[4].base;
|
||||
|
||||
return &mdesc[0];
|
||||
|
@ -1,155 +0,0 @@
|
||||
/*
|
||||
* Carsten Langgaard, carstenl@mips.com
|
||||
* Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved.
|
||||
*
|
||||
* ########################################################################
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
*
|
||||
* ########################################################################
|
||||
*
|
||||
* Interrupt exception dispatch code.
|
||||
*
|
||||
*/
|
||||
#include <linux/config.h>
|
||||
|
||||
#include <asm/asm.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#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
|
||||
* all the pending IRQ bits in the cause register is _NOT_ the answer, the
|
||||
* common case is one pending IRQ so optimize in that direction.
|
||||
*
|
||||
* 2) We need not check against bits in the status register IRQ mask, that
|
||||
* would make this routine slow as hell.
|
||||
*
|
||||
* 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
|
||||
* between like BSD spl() brain-damage.
|
||||
*
|
||||
* Furthermore, the IRQs on the MIPS board look basically (barring software
|
||||
* IRQs which we don't use at all and all external interrupt sources are
|
||||
* combined together on hardware interrupt 0 (MIPS IRQ 2)) like:
|
||||
*
|
||||
* MIPS IRQ Source
|
||||
* -------- ------
|
||||
* 0 Software (ignored)
|
||||
* 1 Software (ignored)
|
||||
* 2 Combined hardware interrupt (hw0)
|
||||
* 3 Hardware (ignored)
|
||||
* 4 Hardware (ignored)
|
||||
* 5 Hardware (ignored)
|
||||
* 6 Hardware (ignored)
|
||||
* 7 R4k timer (what we use)
|
||||
*
|
||||
* Note: On the SEAD board thing are a little bit different.
|
||||
* Here IRQ 2 (hw0) is wired to the UART0 and IRQ 3 (hw1) is wired
|
||||
* wired to UART1.
|
||||
*
|
||||
* We handle the IRQ according to _our_ priority which is:
|
||||
*
|
||||
* Highest ---- R4k Timer
|
||||
* Lowest ---- Combined hardware interrupt
|
||||
*
|
||||
* then we just return, if multiple IRQs are pending then we will just take
|
||||
* another exception, big deal.
|
||||
*/
|
||||
|
||||
.text
|
||||
.set noreorder
|
||||
.set noat
|
||||
.align 5
|
||||
NESTED(mipsIRQ, PT_SIZE, sp)
|
||||
SAVE_ALL
|
||||
CLI
|
||||
.set at
|
||||
|
||||
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
|
||||
|
||||
#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
|
||||
|
||||
and t0, s0, 0xf000
|
||||
sltiu t0, t0, 1
|
||||
sll t0, 2
|
||||
subu a0, t0
|
||||
sll s0, t0
|
||||
|
||||
and t0, s0, 0xc000
|
||||
sltiu t0, t0, 1
|
||||
sll t0, 1
|
||||
subu a0, t0
|
||||
sll s0, t0
|
||||
|
||||
and t0, s0, 0x8000
|
||||
sltiu t0, t0, 1
|
||||
# sll t0, 0
|
||||
subu a0, t0
|
||||
# sll s0, t0
|
||||
#endif
|
||||
|
||||
#ifdef CASCADE_IRQ
|
||||
li a1, CASCADE_IRQ
|
||||
bne a0, a1, 1f
|
||||
addu a0, MIPSCPU_INT_BASE
|
||||
|
||||
jal CASCADE_DISPATCH
|
||||
move a0, sp
|
||||
|
||||
j ret_from_irq
|
||||
nop
|
||||
1:
|
||||
#else
|
||||
addu a0, MIPSCPU_INT_BASE
|
||||
#endif
|
||||
|
||||
jal do_IRQ
|
||||
move a1, sp
|
||||
|
||||
j ret_from_irq
|
||||
nop
|
||||
|
||||
|
||||
spurious:
|
||||
j spurious_interrupt
|
||||
nop
|
||||
END(mipsIRQ)
|
@ -30,6 +30,7 @@
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/mipsmtregs.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/hardirq.h>
|
||||
#include <asm/irq.h>
|
||||
@ -50,16 +51,23 @@ unsigned long cpu_khz;
|
||||
static char display_string[] = " LINUX ON ATLAS ";
|
||||
#endif
|
||||
#if defined(CONFIG_MIPS_MALTA)
|
||||
#if defined(CONFIG_MIPS_MT_SMTC)
|
||||
static char display_string[] = " SMTC LINUX ON MALTA ";
|
||||
#else
|
||||
static char display_string[] = " LINUX ON MALTA ";
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
#endif
|
||||
#if defined(CONFIG_MIPS_SEAD)
|
||||
static char display_string[] = " LINUX ON SEAD ";
|
||||
#endif
|
||||
static unsigned int display_count = 0;
|
||||
static unsigned int display_count;
|
||||
#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8)
|
||||
|
||||
static unsigned int timer_tick_count=0;
|
||||
#define CPUCTR_IMASKBIT (0x100 << MIPSCPU_INT_CPUCTR)
|
||||
|
||||
static unsigned int timer_tick_count;
|
||||
static int mips_cpu_timer_irq;
|
||||
extern void smtc_timer_broadcast(int);
|
||||
|
||||
static inline void scroll_display_message(void)
|
||||
{
|
||||
@ -75,15 +83,55 @@ static void mips_timer_dispatch (struct pt_regs *regs)
|
||||
do_IRQ (mips_cpu_timer_irq, regs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Redeclare until I get around mopping the timer code insanity on MIPS.
|
||||
*/
|
||||
extern int null_perf_irq(struct pt_regs *regs);
|
||||
|
||||
extern int (*perf_irq)(struct pt_regs *regs);
|
||||
|
||||
irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
int r2 = cpu_has_mips_r2;
|
||||
int cpu = smp_processor_id();
|
||||
int r2 = cpu_has_mips_r2;
|
||||
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
/*
|
||||
* In an SMTC system, one Count/Compare set exists per VPE.
|
||||
* Which TC within a VPE gets the interrupt is essentially
|
||||
* random - we only know that it shouldn't be one with
|
||||
* IXMT set. Whichever TC gets the interrupt needs to
|
||||
* send special interprocessor interrupts to the other
|
||||
* TCs to make sure that they schedule, etc.
|
||||
*
|
||||
* That code is specific to the SMTC kernel, not to
|
||||
* the a particular platform, so it's invoked from
|
||||
* the general MIPS timer_interrupt routine.
|
||||
*/
|
||||
|
||||
/*
|
||||
* DVPE is necessary so long as cross-VPE interrupts
|
||||
* are done via read-modify-write of Cause register.
|
||||
*/
|
||||
int vpflags = dvpe();
|
||||
write_c0_compare (read_c0_count() - 1);
|
||||
clear_c0_cause(CPUCTR_IMASKBIT);
|
||||
evpe(vpflags);
|
||||
|
||||
if (cpu_data[cpu].vpe_id == 0) {
|
||||
timer_interrupt(irq, dev_id, regs);
|
||||
scroll_display_message();
|
||||
} else
|
||||
write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ));
|
||||
smtc_timer_broadcast(cpu_data[cpu].vpe_id);
|
||||
|
||||
if (cpu != 0)
|
||||
/*
|
||||
* Other CPUs should do profiling and process accounting
|
||||
*/
|
||||
local_timer_interrupt(irq, dev_id, regs);
|
||||
|
||||
#else /* CONFIG_MIPS_MT_SMTC */
|
||||
if (cpu == 0) {
|
||||
/*
|
||||
* CPU 0 handles the global timer interrupt job and process
|
||||
@ -107,12 +155,14 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
* 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));
|
||||
write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ));
|
||||
|
||||
/*
|
||||
* other CPUs should do profiling and process accounting
|
||||
* Other CPUs should do profiling and process accounting
|
||||
*/
|
||||
local_timer_interrupt (irq, dev_id, regs);
|
||||
local_timer_interrupt(irq, dev_id, regs);
|
||||
}
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
@ -126,7 +176,7 @@ static unsigned int __init estimate_cpu_frequency(void)
|
||||
unsigned int prid = read_c0_prid() & 0xffff00;
|
||||
unsigned int count;
|
||||
|
||||
#ifdef CONFIG_MIPS_SEAD
|
||||
#if defined(CONFIG_MIPS_SEAD) || defined(CONFIG_MIPS_SIM)
|
||||
/*
|
||||
* The SEAD board doesn't have a real time clock, so we can't
|
||||
* really calculate the timer frequency
|
||||
@ -211,7 +261,11 @@ void __init mips_timer_setup(struct irqaction *irq)
|
||||
|
||||
/* we are using the cpu counter for timer interrupts */
|
||||
irq->handler = mips_timer_interrupt; /* we use our own handler */
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
setup_irq_smtc(mips_cpu_timer_irq, irq, CPUCTR_IMASKBIT);
|
||||
#else
|
||||
setup_irq(mips_cpu_timer_irq, irq);
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* irq_desc(riptor) is a global resource, when the interrupt overlaps
|
||||
|
@ -20,3 +20,4 @@
|
||||
#
|
||||
|
||||
obj-y := malta_int.o malta_setup.o
|
||||
obj-$(CONFIG_SMP) += malta_smp.o
|
||||
|
@ -40,7 +40,6 @@
|
||||
#include <asm/mips-boards/msc01_pci.h>
|
||||
#include <asm/msc01_ic.h>
|
||||
|
||||
extern asmlinkage void mipsIRQ(void);
|
||||
extern void mips_timer_interrupt(void);
|
||||
|
||||
static DEFINE_SPINLOCK(mips_irq_lock);
|
||||
@ -114,13 +113,14 @@ static inline int get_int(void)
|
||||
return irq;
|
||||
}
|
||||
|
||||
void malta_hw0_irqdispatch(struct pt_regs *regs)
|
||||
static void malta_hw0_irqdispatch(struct pt_regs *regs)
|
||||
{
|
||||
int irq;
|
||||
|
||||
irq = get_int();
|
||||
if (irq < 0)
|
||||
if (irq < 0) {
|
||||
return; /* interrupt has already been cleared */
|
||||
}
|
||||
|
||||
do_IRQ(MALTA_INT_BASE+irq, regs);
|
||||
}
|
||||
@ -182,6 +182,92 @@ void corehi_irqdispatch(struct pt_regs *regs)
|
||||
die("CoreHi interrupt", regs);
|
||||
}
|
||||
|
||||
static inline int clz(unsigned long x)
|
||||
{
|
||||
__asm__ (
|
||||
" .set push \n"
|
||||
" .set mips32 \n"
|
||||
" clz %0, %1 \n"
|
||||
" .set pop \n"
|
||||
: "=r" (x)
|
||||
: "r" (x));
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* Version of ffs that only looks at bits 12..15.
|
||||
*/
|
||||
static inline unsigned int irq_ffs(unsigned int pending)
|
||||
{
|
||||
#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
|
||||
return -clz(pending) + 31 - CAUSEB_IP;
|
||||
#else
|
||||
unsigned int a0 = 7;
|
||||
unsigned int t0;
|
||||
|
||||
t0 = s0 & 0xf000;
|
||||
t0 = t0 < 1;
|
||||
t0 = t0 << 2;
|
||||
a0 = a0 - t0;
|
||||
s0 = s0 << t0;
|
||||
|
||||
t0 = s0 & 0xc000;
|
||||
t0 = t0 < 1;
|
||||
t0 = t0 << 1;
|
||||
a0 = a0 - t0;
|
||||
s0 = s0 << t0;
|
||||
|
||||
t0 = s0 & 0x8000;
|
||||
t0 = t0 < 1;
|
||||
//t0 = t0 << 2;
|
||||
a0 = a0 - t0;
|
||||
//s0 = s0 << t0;
|
||||
|
||||
return a0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* IRQs on the Malta board look basically (barring software IRQs which we
|
||||
* don't use at all and all external interrupt sources are combined together
|
||||
* on hardware interrupt 0 (MIPS IRQ 2)) like:
|
||||
*
|
||||
* MIPS IRQ Source
|
||||
* -------- ------
|
||||
* 0 Software (ignored)
|
||||
* 1 Software (ignored)
|
||||
* 2 Combined hardware interrupt (hw0)
|
||||
* 3 Hardware (ignored)
|
||||
* 4 Hardware (ignored)
|
||||
* 5 Hardware (ignored)
|
||||
* 6 Hardware (ignored)
|
||||
* 7 R4k timer (what we use)
|
||||
*
|
||||
* We handle the IRQ according to _our_ priority which is:
|
||||
*
|
||||
* Highest ---- R4k Timer
|
||||
* Lowest ---- Combined hardware interrupt
|
||||
*
|
||||
* then we just return, if multiple IRQs are pending then we will just take
|
||||
* another exception, big deal.
|
||||
*/
|
||||
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
|
||||
int irq;
|
||||
|
||||
irq = irq_ffs(pending);
|
||||
|
||||
if (irq == MIPSCPU_INT_I8259A)
|
||||
malta_hw0_irqdispatch(regs);
|
||||
else if (irq > 0)
|
||||
do_IRQ(MIPSCPU_INT_BASE + irq, regs);
|
||||
else
|
||||
spurious_interrupt(regs);
|
||||
}
|
||||
|
||||
static struct irqaction i8259irq = {
|
||||
.handler = no_action,
|
||||
.name = "XT-PIC cascade"
|
||||
@ -214,7 +300,6 @@ int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap)/sizeof(msc_irqmap_t);
|
||||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
set_except_vector(0, mipsIRQ);
|
||||
init_i8259_irqs();
|
||||
|
||||
if (!cpu_has_veic)
|
||||
@ -240,12 +325,17 @@ void __init arch_init_irq(void)
|
||||
else if (cpu_has_vint) {
|
||||
set_vi_handler (MIPSCPU_INT_I8259A, malta_hw0_irqdispatch);
|
||||
set_vi_handler (MIPSCPU_INT_COREHI, corehi_irqdispatch);
|
||||
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
setup_irq_smtc (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq,
|
||||
(0x100 << MIPSCPU_INT_I8259A));
|
||||
setup_irq_smtc (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI,
|
||||
&corehi_irqaction, (0x100 << MIPSCPU_INT_COREHI));
|
||||
#else /* Not SMTC */
|
||||
setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq);
|
||||
setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction);
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
}
|
||||
else {
|
||||
set_except_vector(0, mipsIRQ);
|
||||
setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq);
|
||||
setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction);
|
||||
}
|
||||
|
128
arch/mips/mips-boards/malta/malta_smp.c
Normal file
128
arch/mips/mips-boards/malta/malta_smp.c
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Malta Platform-specific hooks for SMP operation
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/hardirq.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/smp.h>
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
#include <asm/smtc_ipi.h>
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
/* VPE/SMP Prototype implements platform interfaces directly */
|
||||
#if !defined(CONFIG_MIPS_MT_SMP)
|
||||
|
||||
/*
|
||||
* Cause the specified action to be performed on a targeted "CPU"
|
||||
*/
|
||||
|
||||
void core_send_ipi(int cpu, unsigned int action)
|
||||
{
|
||||
/* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
smtc_send_ipi(cpu, LINUX_SMP_IPI, action);
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
}
|
||||
|
||||
/*
|
||||
* Detect available CPUs/VPEs/TCs and populate phys_cpu_present_map
|
||||
*/
|
||||
|
||||
void __init prom_build_cpu_map(void)
|
||||
{
|
||||
int nextslot;
|
||||
|
||||
/*
|
||||
* As of November, 2004, MIPSsim only simulates one core
|
||||
* at a time. However, that core may be a MIPS MT core
|
||||
* with multiple virtual processors and thread contexts.
|
||||
*/
|
||||
|
||||
if (read_c0_config3() & (1<<2)) {
|
||||
nextslot = mipsmt_build_cpu_map(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Platform "CPU" startup hook
|
||||
*/
|
||||
|
||||
void prom_boot_secondary(int cpu, struct task_struct *idle)
|
||||
{
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
smtc_boot_secondary(cpu, idle);
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
}
|
||||
|
||||
/*
|
||||
* Post-config but pre-boot cleanup entry point
|
||||
*/
|
||||
|
||||
void prom_init_secondary(void)
|
||||
{
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
void smtc_init_secondary(void);
|
||||
int myvpe;
|
||||
|
||||
/* Don't enable Malta I/O interrupts (IP2) for secondary VPEs */
|
||||
myvpe = read_c0_tcbind() & TCBIND_CURVPE;
|
||||
if (myvpe != 0) {
|
||||
/* Ideally, this should be done only once per VPE, but... */
|
||||
clear_c0_status(STATUSF_IP2);
|
||||
set_c0_status(STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP3
|
||||
| STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6
|
||||
| STATUSF_IP7);
|
||||
}
|
||||
|
||||
smtc_init_secondary();
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
}
|
||||
|
||||
/*
|
||||
* Platform SMP pre-initialization
|
||||
*
|
||||
* As noted above, we can assume a single CPU for now
|
||||
* but it may be multithreaded.
|
||||
*/
|
||||
|
||||
void plat_smp_setup(void)
|
||||
{
|
||||
if (read_c0_config3() & (1<<2))
|
||||
mipsmt_build_cpu_map(0);
|
||||
}
|
||||
|
||||
void __init plat_prepare_cpus(unsigned int max_cpus)
|
||||
{
|
||||
if (read_c0_config3() & (1<<2))
|
||||
mipsmt_prepare_cpus();
|
||||
}
|
||||
|
||||
/*
|
||||
* SMP initialization finalization entry point
|
||||
*/
|
||||
|
||||
void prom_smp_finish(void)
|
||||
{
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
smtc_smp_finish();
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
}
|
||||
|
||||
/*
|
||||
* Hook for after all CPUs are online
|
||||
*/
|
||||
|
||||
void prom_cpus_done(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MIPS32R2_MT_SMP */
|
@ -24,16 +24,94 @@
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <asm/irq_cpu.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#include <asm/mips-boards/seadint.h>
|
||||
|
||||
extern asmlinkage void mipsIRQ(void);
|
||||
static inline int clz(unsigned long x)
|
||||
{
|
||||
__asm__ (
|
||||
" .set push \n"
|
||||
" .set mips32 \n"
|
||||
" clz %0, %1 \n"
|
||||
" .set pop \n"
|
||||
: "=r" (x)
|
||||
: "r" (x));
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* Version of ffs that only looks at bits 12..15.
|
||||
*/
|
||||
static inline unsigned int irq_ffs(unsigned int pending)
|
||||
{
|
||||
#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
|
||||
return -clz(pending) + 31 - CAUSEB_IP;
|
||||
#else
|
||||
unsigned int a0 = 7;
|
||||
unsigned int t0;
|
||||
|
||||
t0 = s0 & 0xf000;
|
||||
t0 = t0 < 1;
|
||||
t0 = t0 << 2;
|
||||
a0 = a0 - t0;
|
||||
s0 = s0 << t0;
|
||||
|
||||
t0 = s0 & 0xc000;
|
||||
t0 = t0 < 1;
|
||||
t0 = t0 << 1;
|
||||
a0 = a0 - t0;
|
||||
s0 = s0 << t0;
|
||||
|
||||
t0 = s0 & 0x8000;
|
||||
t0 = t0 < 1;
|
||||
//t0 = t0 << 2;
|
||||
a0 = a0 - t0;
|
||||
//s0 = s0 << t0;
|
||||
|
||||
return a0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* IRQs on the SEAD board look basically are combined together on hardware
|
||||
* interrupt 0 (MIPS IRQ 2)) like:
|
||||
*
|
||||
* MIPS IRQ Source
|
||||
* -------- ------
|
||||
* 0 Software (ignored)
|
||||
* 1 Software (ignored)
|
||||
* 2 UART0 (hw0)
|
||||
* 3 UART1 (hw1)
|
||||
* 4 Hardware (ignored)
|
||||
* 5 Hardware (ignored)
|
||||
* 6 Hardware (ignored)
|
||||
* 7 R4k timer (what we use)
|
||||
*
|
||||
* We handle the IRQ according to _our_ priority which is:
|
||||
*
|
||||
* Highest ---- R4k Timer
|
||||
* Lowest ---- Combined hardware interrupt
|
||||
*
|
||||
* then we just return, if multiple IRQs are pending then we will just take
|
||||
* another exception, big deal.
|
||||
*/
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
|
||||
int irq;
|
||||
|
||||
irq = irq_ffs(pending);
|
||||
|
||||
if (irq >= 0)
|
||||
do_IRQ(MIPSCPU_INT_BASE + irq, regs);
|
||||
else
|
||||
spurious_interrupt(regs);
|
||||
}
|
||||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
mips_cpu_irq_init(MIPSCPU_INT_BASE);
|
||||
|
||||
/* Now safe to set the exception vector. */
|
||||
set_except_vector(0, mipsIRQ);
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Carsten Langgaard, carstenl@mips.com
|
||||
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
*
|
||||
* Kernel command line creation using the prom monitor (YAMON) argc/argv.
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
|
||||
extern int prom_argc;
|
||||
extern int *_prom_argv;
|
||||
|
||||
/*
|
||||
* YAMON (32-bit PROM) pass arguments and environment as 32-bit pointer.
|
||||
* This macro take care of sign extension.
|
||||
*/
|
||||
#define prom_argv(index) ((char *)(((int *)(int)_prom_argv)[(index)]))
|
||||
|
||||
char arcs_cmdline[CL_SIZE];
|
||||
|
||||
char * __init prom_getcmdline(void)
|
||||
{
|
||||
return &(arcs_cmdline[0]);
|
||||
}
|
||||
|
||||
|
||||
void __init prom_init_cmdline(void)
|
||||
{
|
||||
char *cp;
|
||||
int actr;
|
||||
|
||||
actr = 1; /* Always ignore argv[0] */
|
||||
|
||||
cp = &(arcs_cmdline[0]);
|
||||
while(actr < prom_argc) {
|
||||
strcpy(cp, prom_argv(actr));
|
||||
cp += strlen(prom_argv(actr));
|
||||
*cp++ = ' ';
|
||||
actr++;
|
||||
}
|
||||
if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
|
||||
--cp;
|
||||
*cp = '\0';
|
||||
}
|
@ -26,8 +26,10 @@ char * __init prom_getcmdline(void)
|
||||
return arcs_cmdline;
|
||||
}
|
||||
|
||||
|
||||
void __init prom_init_cmdline(void)
|
||||
{
|
||||
/* nothing to do */
|
||||
char *cp;
|
||||
cp = arcs_cmdline;
|
||||
/* Get boot line from environment? */
|
||||
*cp = '\0';
|
||||
}
|
||||
|
@ -25,17 +25,71 @@
|
||||
|
||||
extern void mips_cpu_irq_init(int);
|
||||
|
||||
extern asmlinkage void simIRQ(void);
|
||||
static inline int clz(unsigned long x)
|
||||
{
|
||||
__asm__ (
|
||||
" .set push \n"
|
||||
" .set mips32 \n"
|
||||
" clz %0, %1 \n"
|
||||
" .set pop \n"
|
||||
: "=r" (x)
|
||||
: "r" (x));
|
||||
|
||||
asmlinkage void sim_hw0_irqdispatch(struct pt_regs *regs)
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* Version of ffs that only looks at bits 12..15.
|
||||
*/
|
||||
static inline unsigned int irq_ffs(unsigned int pending)
|
||||
{
|
||||
#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
|
||||
return -clz(pending) + 31 - CAUSEB_IP;
|
||||
#else
|
||||
unsigned int a0 = 7;
|
||||
unsigned int t0;
|
||||
|
||||
t0 = s0 & 0xf000;
|
||||
t0 = t0 < 1;
|
||||
t0 = t0 << 2;
|
||||
a0 = a0 - t0;
|
||||
s0 = s0 << t0;
|
||||
|
||||
t0 = s0 & 0xc000;
|
||||
t0 = t0 < 1;
|
||||
t0 = t0 << 1;
|
||||
a0 = a0 - t0;
|
||||
s0 = s0 << t0;
|
||||
|
||||
t0 = s0 & 0x8000;
|
||||
t0 = t0 < 1;
|
||||
//t0 = t0 << 2;
|
||||
a0 = a0 - t0;
|
||||
//s0 = s0 << t0;
|
||||
|
||||
return a0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void sim_hw0_irqdispatch(struct pt_regs *regs)
|
||||
{
|
||||
do_IRQ(2, regs);
|
||||
}
|
||||
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
|
||||
int irq;
|
||||
|
||||
irq = irq_ffs(pending);
|
||||
|
||||
if (irq > 0)
|
||||
do_IRQ(MIPSCPU_INT_BASE + irq, regs);
|
||||
else
|
||||
spurious_interrupt(regs);
|
||||
}
|
||||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
/* Now safe to set the exception vector. */
|
||||
set_except_vector(0, simIRQ);
|
||||
|
||||
mips_cpu_irq_init(MIPSCPU_INT_BASE);
|
||||
}
|
||||
|
@ -94,6 +94,8 @@
|
||||
|
||||
|
||||
spurious:
|
||||
j spurious_interrupt
|
||||
jal spurious_interrupt
|
||||
nop
|
||||
j ret_from_irq
|
||||
nop
|
||||
END(simIRQ)
|
||||
|
@ -18,9 +18,11 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/pfn.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/sections.h>
|
||||
|
||||
#include <asm/mips-boards/prom.h>
|
||||
|
||||
@ -39,9 +41,6 @@ static char *mtypes[3] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
/* References to section boundaries */
|
||||
extern char _end;
|
||||
|
||||
struct prom_pmemblock * __init prom_getmdesc(void)
|
||||
{
|
||||
unsigned int memsize;
|
||||
@ -61,10 +60,10 @@ struct prom_pmemblock * __init prom_getmdesc(void)
|
||||
|
||||
mdesc[2].type = simmem_reserved;
|
||||
mdesc[2].base = 0x00100000;
|
||||
mdesc[2].size = CPHYSADDR(PAGE_ALIGN(&_end)) - mdesc[2].base;
|
||||
mdesc[2].size = CPHYSADDR(PFN_ALIGN(&_end)) - mdesc[2].base;
|
||||
|
||||
mdesc[3].type = simmem_free;
|
||||
mdesc[3].base = CPHYSADDR(PAGE_ALIGN(&_end));
|
||||
mdesc[3].base = CPHYSADDR(PFN_ALIGN(&_end));
|
||||
mdesc[3].size = memsize - mdesc[3].base;
|
||||
|
||||
return &mdesc[0];
|
||||
|
@ -44,8 +44,6 @@
|
||||
void core_send_ipi(int cpu, unsigned int action)
|
||||
{
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
void smtc_send_ipi(int, int, unsigned int);
|
||||
|
||||
smtc_send_ipi(cpu, LINUX_SMP_IPI, action);
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
/* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */
|
||||
@ -59,15 +57,8 @@ void core_send_ipi(int cpu, unsigned int action)
|
||||
void __init prom_build_cpu_map(void)
|
||||
{
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
extern int mipsmt_build_cpu_map(int startslot);
|
||||
int nextslot;
|
||||
|
||||
cpus_clear(phys_cpu_present_map);
|
||||
|
||||
/* Register the boot CPU */
|
||||
|
||||
smp_prepare_boot_cpu();
|
||||
|
||||
/*
|
||||
* As of November, 2004, MIPSsim only simulates one core
|
||||
* at a time. However, that core may be a MIPS MT core
|
||||
@ -87,8 +78,6 @@ void __init prom_build_cpu_map(void)
|
||||
void prom_boot_secondary(int cpu, struct task_struct *idle)
|
||||
{
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
extern void smtc_boot_secondary(int cpu, struct task_struct *t);
|
||||
|
||||
smtc_boot_secondary(cpu, idle);
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
}
|
||||
@ -113,7 +102,6 @@ void prom_init_secondary(void)
|
||||
void prom_prepare_cpus(unsigned int max_cpus)
|
||||
{
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
void mipsmt_prepare_cpus(int c);
|
||||
/*
|
||||
* As noted above, we can assume a single CPU for now
|
||||
* but it may be multithreaded.
|
||||
@ -132,8 +120,6 @@ void prom_prepare_cpus(unsigned int max_cpus)
|
||||
void prom_smp_finish(void)
|
||||
{
|
||||
#ifdef CONFIG_MIPS_MT_SMTC
|
||||
void smtc_smp_finish(void);
|
||||
|
||||
smtc_smp_finish();
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
}
|
||||
|
@ -260,6 +260,10 @@ static void r3k_flush_cache_page(struct vm_area_struct *vma, unsigned long page,
|
||||
{
|
||||
}
|
||||
|
||||
static void local_r3k_flush_data_cache_page(unsigned long addr)
|
||||
{
|
||||
}
|
||||
|
||||
static void r3k_flush_data_cache_page(unsigned long addr)
|
||||
{
|
||||
}
|
||||
@ -335,6 +339,7 @@ void __init r3k_cache_init(void)
|
||||
flush_icache_range = r3k_flush_icache_range;
|
||||
|
||||
flush_cache_sigtramp = r3k_flush_cache_sigtramp;
|
||||
local_flush_data_cache_page = local_r3k_flush_data_cache_page;
|
||||
flush_data_cache_page = r3k_flush_data_cache_page;
|
||||
|
||||
_dma_cache_wback_inv = r3k_dma_cache_wback_inv;
|
||||
|
@ -154,7 +154,8 @@ static inline void blast_icache32_r4600_v1_page_indexed(unsigned long page)
|
||||
|
||||
static inline void tx49_blast_icache32_page_indexed(unsigned long page)
|
||||
{
|
||||
unsigned long start = page;
|
||||
unsigned long indexmask = current_cpu_data.icache.waysize - 1;
|
||||
unsigned long start = INDEX_BASE + (page & indexmask);
|
||||
unsigned long end = start + PAGE_SIZE;
|
||||
unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit;
|
||||
unsigned long ws_end = current_cpu_data.icache.ways <<
|
||||
@ -749,12 +750,12 @@ static void __init probe_pcache(void)
|
||||
icache_size = 1 << (12 + ((config & CONF_IC) >> 9));
|
||||
c->icache.linesz = 16 << ((config & CONF_IB) >> 5);
|
||||
c->icache.ways = 2;
|
||||
c->icache.waybit = ffs(icache_size/2) - 1;
|
||||
c->icache.waybit = __ffs(icache_size/2);
|
||||
|
||||
dcache_size = 1 << (12 + ((config & CONF_DC) >> 6));
|
||||
c->dcache.linesz = 16 << ((config & CONF_DB) >> 4);
|
||||
c->dcache.ways = 2;
|
||||
c->dcache.waybit= ffs(dcache_size/2) - 1;
|
||||
c->dcache.waybit= __ffs(dcache_size/2);
|
||||
|
||||
c->options |= MIPS_CPU_CACHE_CDEX_P;
|
||||
break;
|
||||
@ -837,12 +838,12 @@ static void __init probe_pcache(void)
|
||||
icache_size = 1 << (10 + ((config & CONF_IC) >> 9));
|
||||
c->icache.linesz = 16 << ((config & CONF_IB) >> 5);
|
||||
c->icache.ways = 2;
|
||||
c->icache.waybit = ffs(icache_size/2) - 1;
|
||||
c->icache.waybit = __ffs(icache_size/2);
|
||||
|
||||
dcache_size = 1 << (10 + ((config & CONF_DC) >> 6));
|
||||
c->dcache.linesz = 16 << ((config & CONF_DB) >> 4);
|
||||
c->dcache.ways = 2;
|
||||
c->dcache.waybit = ffs(dcache_size/2) - 1;
|
||||
c->dcache.waybit = __ffs(dcache_size/2);
|
||||
|
||||
c->options |= MIPS_CPU_CACHE_CDEX_P;
|
||||
break;
|
||||
@ -873,12 +874,12 @@ static void __init probe_pcache(void)
|
||||
icache_size = 1 << (12 + ((config & CONF_IC) >> 9));
|
||||
c->icache.linesz = 16 << ((config & CONF_IB) >> 5);
|
||||
c->icache.ways = 4;
|
||||
c->icache.waybit = ffs(icache_size / c->icache.ways) - 1;
|
||||
c->icache.waybit = __ffs(icache_size / c->icache.ways);
|
||||
|
||||
dcache_size = 1 << (12 + ((config & CONF_DC) >> 6));
|
||||
c->dcache.linesz = 16 << ((config & CONF_DB) >> 4);
|
||||
c->dcache.ways = 4;
|
||||
c->dcache.waybit = ffs(dcache_size / c->dcache.ways) - 1;
|
||||
c->dcache.waybit = __ffs(dcache_size / c->dcache.ways);
|
||||
|
||||
#if !defined(CONFIG_SMP) || !defined(RM9000_CDEX_SMP_WAR)
|
||||
c->options |= MIPS_CPU_CACHE_CDEX_P;
|
||||
@ -906,7 +907,7 @@ static void __init probe_pcache(void)
|
||||
icache_size = c->icache.sets *
|
||||
c->icache.ways *
|
||||
c->icache.linesz;
|
||||
c->icache.waybit = ffs(icache_size/c->icache.ways) - 1;
|
||||
c->icache.waybit = __ffs(icache_size/c->icache.ways);
|
||||
|
||||
if (config & 0x8) /* VI bit */
|
||||
c->icache.flags |= MIPS_CACHE_VTAG;
|
||||
@ -926,7 +927,7 @@ static void __init probe_pcache(void)
|
||||
dcache_size = c->dcache.sets *
|
||||
c->dcache.ways *
|
||||
c->dcache.linesz;
|
||||
c->dcache.waybit = ffs(dcache_size/c->dcache.ways) - 1;
|
||||
c->dcache.waybit = __ffs(dcache_size/c->dcache.ways);
|
||||
|
||||
c->options |= MIPS_CPU_PREFETCH;
|
||||
break;
|
||||
@ -1198,6 +1199,7 @@ void __init r4k_cache_init(void)
|
||||
|
||||
flush_cache_sigtramp = r4k_flush_cache_sigtramp;
|
||||
flush_icache_all = r4k_flush_icache_all;
|
||||
local_flush_data_cache_page = local_r4k_flush_data_cache_page;
|
||||
flush_data_cache_page = r4k_flush_data_cache_page;
|
||||
flush_icache_range = r4k_flush_icache_range;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user