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

[PATCH] mips: generic MIPS updates

Update the generic MIPS code.  Highlights are oprofile for MIPS, initially for
the PMC-Sierra RM9000.  We're also taking a significantly more aggressive
approach to the TLB exception handlers which now are runtime generated and
provide an upto 20% speedup on certain micro benchmarks.

From: Yoichi Yuasa <yuasa@hh.iij4u.or.jp>

This patch had fixed restore_sigcontext about MIPS.
Signed-off-by: default avatarYoichi Yuasa <yuasa@hh.iij4u.or.jp>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 9ec0d34b
......@@ -673,6 +673,8 @@ libs-$(CONFIG_MIPS64) += arch/mips/lib-64/
core-y += arch/mips/kernel/ arch/mips/mm/ arch/mips/math-emu/
drivers-$(CONFIG_OPROFILE) += arch/mips/oprofile/
ifdef CONFIG_LASAT
rom.bin rom.sw: vmlinux
$(call descend,arch/mips/lasat/image,$@)
......@@ -744,36 +746,16 @@ define filechk_gen-asm-offset.h
echo "#endif /* _ASM_OFFSET_H */" )
endef
define filechk_gen-asm-reg.h
(set -e; \
echo "#ifndef _ASM_REG_H"; \
echo "#define _ASM_REG_H"; \
echo "/*"; \
echo " * DO NOT MODIFY."; \
echo " *"; \
echo " * This file was generated by arch/$(ARCH)/Makefile"; \
echo " *"; \
echo " */"; \
echo ""; \
sed -ne "/^@@@/s///p"; \
echo "#endif /* _ASM_REG_H */" )
endef
prepare: include/asm-$(ARCH)/offset.h \
include/asm-$(ARCH)/reg.h
prepare: include/asm-$(ARCH)/offset.h
arch/$(ARCH)/kernel/offset.s: include/asm include/linux/version.h \
include/config/MARKER
include/asm-$(ARCH)/offset.h: arch/$(ARCH)/kernel/offset.s
$(call filechk,gen-asm-offset.h)
include/asm-$(ARCH)/reg.h: arch/$(ARCH)/kernel/reg.s
$(call filechk,gen-asm-reg.h)
CLEAN_FILES += include/asm-$(ARCH)/offset.h.tmp \
include/asm-$(ARCH)/offset.h \
include/asm-$(ARCH)/reg.h.tmp \
include/asm-$(ARCH)/reg.h \
vmlinux.32 \
vmlinux.64 \
vmlinux.ecoff
......@@ -8,6 +8,9 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \
ptrace.o reset.o semaphore.o setup.o signal.o syscall.o \
time.o traps.o unaligned.o
binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \
irix5sys.o sysirix.o
ifdef CONFIG_MODULES
obj-y += mips_ksyms.o module.o
obj-$(CONFIG_MIPS32) += module-elf32.o
......@@ -35,15 +38,16 @@ obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_NO_ISA) += dma-no-isa.o
obj-$(CONFIG_I8259) += i8259.o
obj-$(CONFIG_IRQ_CPU) += irq_cpu.o
obj-$(CONFIG_IRQ_CPU_RM7K) += irq-rm7000.o
obj-$(CONFIG_IRQ_CPU_RM9K) += irq-rm9000.o
obj-$(CONFIG_IRQ_MV64340) += irq-mv6434x.o
obj-$(CONFIG_MIPS32) += scall32-o32.o
obj-$(CONFIG_MIPS64) += scall64-64.o
obj-$(CONFIG_BINFMT_IRIX) += irixelf.o irixioctl.o irixsig.o sysirix.o \
irixinv.o
obj-$(CONFIG_BINFMT_IRIX) += binfmt_irix.o
obj-$(CONFIG_MIPS32_COMPAT) += ioctl32.o linux32.o signal32.o
obj-$(CONFIG_MIPS32_N32) += binfmt_elfn32.o scall64-n32.o signal_n32.o
obj-$(CONFIG_MIPS32_O32) += binfmt_elfo32.o scall64-o32.o ptrace32.o
......
/*
* Copyright (C) 2003 Ralf Baechle
*
* 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.
*
* Handler for RM9000 extended interrupts. These are a non-standard
* feature so we handle them separately from standard interrupts.
*/
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/irq_cpu.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
static int irq_base;
static inline void unmask_rm9k_irq(unsigned int irq)
{
set_c0_intcontrol(0x1000 << (irq - irq_base));
}
static inline void mask_rm9k_irq(unsigned int irq)
{
clear_c0_intcontrol(0x1000 << (irq - irq_base));
}
static inline void rm9k_cpu_irq_enable(unsigned int irq)
{
unsigned long flags;
local_irq_save(flags);
unmask_rm9k_irq(irq);
local_irq_restore(flags);
}
static void rm9k_cpu_irq_disable(unsigned int irq)
{
unsigned long flags;
local_irq_save(flags);
mask_rm9k_irq(irq);
local_irq_restore(flags);
}
static unsigned int rm9k_cpu_irq_startup(unsigned int irq)
{
rm9k_cpu_irq_enable(irq);
return 0;
}
#define rm9k_cpu_irq_shutdown rm9k_cpu_irq_disable
/*
* Performance counter interrupts are global on all processors.
*/
static void local_rm9k_perfcounter_irq_startup(void *args)
{
unsigned int irq = (unsigned int) args;
rm9k_cpu_irq_enable(irq);
}
static unsigned int rm9k_perfcounter_irq_startup(unsigned int irq)
{
on_each_cpu(local_rm9k_perfcounter_irq_startup, (void *) irq, 0, 1);
return 0;
}
static void local_rm9k_perfcounter_irq_shutdown(void *args)
{
unsigned int irq = (unsigned int) args;
unsigned long flags;
local_irq_save(flags);
mask_rm9k_irq(irq);
local_irq_restore(flags);
}
static void rm9k_perfcounter_irq_shutdown(unsigned int irq)
{
on_each_cpu(local_rm9k_perfcounter_irq_shutdown, (void *) irq, 0, 1);
}
/*
* While we ack the interrupt interrupts are disabled and thus we don't need
* to deal with concurrency issues. Same for rm9k_cpu_irq_end.
*/
static void rm9k_cpu_irq_ack(unsigned int irq)
{
mask_rm9k_irq(irq);
}
static void rm9k_cpu_irq_end(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
unmask_rm9k_irq(irq);
}
static hw_irq_controller rm9k_irq_controller = {
"RM9000",
rm9k_cpu_irq_startup,
rm9k_cpu_irq_shutdown,
rm9k_cpu_irq_enable,
rm9k_cpu_irq_disable,
rm9k_cpu_irq_ack,
rm9k_cpu_irq_end,
};
static hw_irq_controller rm9k_perfcounter_irq = {
"RM9000",
rm9k_perfcounter_irq_startup,
rm9k_perfcounter_irq_shutdown,
rm9k_cpu_irq_enable,
rm9k_cpu_irq_disable,
rm9k_cpu_irq_ack,
rm9k_cpu_irq_end,
};
unsigned int rm9000_perfcount_irq;
EXPORT_SYMBOL(rm9000_perfcount_irq);
void __init rm9k_cpu_irq_init(int base)
{
int i;
clear_c0_intcontrol(0x0000f000); /* Mask all */
for (i = base; i < base + 4; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = NULL;
irq_desc[i].depth = 1;
irq_desc[i].handler = &rm9k_irq_controller;
}
rm9000_perfcount_irq = base + 1;
irq_desc[rm9000_perfcount_irq].handler = &rm9k_perfcounter_irq;
irq_base = base;
}
......@@ -125,7 +125,7 @@ void __init init_IRQ(void)
irq_desc[i].action = NULL;
irq_desc[i].depth = 1;
irq_desc[i].handler = &no_irq_type;
irq_desc[i].lock = SPIN_LOCK_UNLOCKED;
spin_lock_init(&irq_desc[i].lock);
}
arch_init_irq();
......
......@@ -99,7 +99,7 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf)
}
asmlinkage unsigned long
sys32_mmap2(unsigned long addr, size_t len, unsigned long prot,
sys32_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
unsigned long flags, unsigned long fd, unsigned long pgoff)
{
struct file * file = NULL;
......
......@@ -5,9 +5,11 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1996, 97, 98, 99, 2000, 01, 03 by Ralf Baechle
* Copyright (C) 1996, 97, 98, 99, 2000, 01, 03, 04, 05 by Ralf Baechle
* Copyright (C) 1999, 2000, 01 Silicon Graphics, Inc.
*/
#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <asm/checksum.h>
#include <asm/pgtable.h>
......@@ -60,3 +62,6 @@ 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
......@@ -2,7 +2,7 @@
#include <linux/spinlock.h>
static LIST_HEAD(dbe_list);
static spinlock_t dbe_lock = SPIN_LOCK_UNLOCKED;
static DEFINE_SPINLOCK(dbe_lock);
/* Given an address, look for it in the module exception tables. */
const struct exception_table_entry *search_module_dbetables(unsigned long addr)
......
......@@ -113,19 +113,15 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
*childregs = *regs;
childregs->regs[7] = 0; /* Clear error flag */
#ifdef CONFIG_BINFMT_IRIX
#if defined(CONFIG_BINFMT_IRIX)
if (current->personality != PER_LINUX) {
/* Under IRIX things are a little different. */
childregs->regs[2] = 0;
childregs->regs[3] = 1;
regs->regs[2] = p->pid;
regs->regs[3] = 0;
} else
}
#endif
{
childregs->regs[2] = 0; /* Child gets zero as return value */
regs->regs[2] = p->pid;
}
if (childregs->cp0_status & ST0_CU0) {
childregs->regs[28] = (unsigned long) ti;
......@@ -153,6 +149,36 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
{
memcpy(r, &current->thread.fpu, sizeof(current->thread.fpu));
return 1;
}
void dump_regs(elf_greg_t *gp, struct pt_regs *regs)
{
int i;
for (i = 0; i < EF_R0; i++)
gp[i] = 0;
gp[EF_R0] = 0;
for (i = 1; i <= 31; i++)
gp[EF_R0 + i] = regs->regs[i];
gp[EF_R26] = 0;
gp[EF_R27] = 0;
gp[EF_LO] = regs->lo;
gp[EF_HI] = regs->hi;
gp[EF_CP0_EPC] = regs->cp0_epc;
gp[EF_CP0_BADVADDR] = regs->cp0_badvaddr;
gp[EF_CP0_STATUS] = regs->cp0_status;
gp[EF_CP0_CAUSE] = regs->cp0_cause;
#ifdef EF_UNUSED0
gp[EF_UNUSED0] = 0;
#endif
}
int dump_task_fpu (struct task_struct *t, elf_fpregset_t *fpr)
{
memcpy(fpr, &t->thread.fpu, sizeof(current->thread.fpu));
return 1;
}
......@@ -263,7 +289,6 @@ arch_initcall(frame_info_init);
*/
unsigned long thread_saved_pc(struct task_struct *tsk)
{
extern void ret_from_fork(void);
struct thread_struct *t = &tsk->thread;
/* New born processes are a special case */
......
/*
* offset.c: Calculate pt_regs and task_struct indices.
*
* Copyright (C) 1996 David S. Miller
* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 Ralf Baechle
*/
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
#define text(t) __asm__("\n@@@" t)
#define _offset(type, member) ((unsigned long) &(((type *)NULL)->member))
#define index(string, ptr, member) \
__asm__("\n@@@" string "%0" : : "i" (_offset(ptr, member)/sizeof(long)))
#define size(string, size) \
__asm__("\n@@@" string "%0" : : "i" (sizeof(size)))
#define linefeed text("")
void output_ptreg_defines(void)
{
text("/* MIPS pt_regs indices. */");
index("#define EF_R0 ", struct pt_regs, regs[0]);
index("#define EF_R1 ", struct pt_regs, regs[1]);
index("#define EF_R2 ", struct pt_regs, regs[2]);
index("#define EF_R3 ", struct pt_regs, regs[3]);
index("#define EF_R4 ", struct pt_regs, regs[4]);
index("#define EF_R5 ", struct pt_regs, regs[5]);
index("#define EF_R6 ", struct pt_regs, regs[6]);
index("#define EF_R7 ", struct pt_regs, regs[7]);
index("#define EF_R8 ", struct pt_regs, regs[8]);
index("#define EF_R9 ", struct pt_regs, regs[9]);
index("#define EF_R10 ", struct pt_regs, regs[10]);
index("#define EF_R11 ", struct pt_regs, regs[11]);
index("#define EF_R12 ", struct pt_regs, regs[12]);
index("#define EF_R13 ", struct pt_regs, regs[13]);
index("#define EF_R14 ", struct pt_regs, regs[14]);
index("#define EF_R15 ", struct pt_regs, regs[15]);
index("#define EF_R16 ", struct pt_regs, regs[16]);
index("#define EF_R17 ", struct pt_regs, regs[17]);
index("#define EF_R18 ", struct pt_regs, regs[18]);
index("#define EF_R19 ", struct pt_regs, regs[19]);
index("#define EF_R20 ", struct pt_regs, regs[20]);
index("#define EF_R21 ", struct pt_regs, regs[21]);
index("#define EF_R22 ", struct pt_regs, regs[22]);
index("#define EF_R23 ", struct pt_regs, regs[23]);
index("#define EF_R24 ", struct pt_regs, regs[24]);
index("#define EF_R25 ", struct pt_regs, regs[25]);
index("#define EF_R26 ", struct pt_regs, regs[26]);
index("#define EF_R27 ", struct pt_regs, regs[27]);
index("#define EF_R28 ", struct pt_regs, regs[28]);
index("#define EF_R29 ", struct pt_regs, regs[29]);
index("#define EF_R30 ", struct pt_regs, regs[30]);
index("#define EF_R31 ", struct pt_regs, regs[31]);
linefeed;
index("#define EF_LO ", struct pt_regs, lo);
index("#define EF_HI ", struct pt_regs, hi);
linefeed;
index("#define EF_EPC ", struct pt_regs, cp0_epc);
index("#define EF_BVADDR ", struct pt_regs, cp0_badvaddr);
index("#define EF_STATUS ", struct pt_regs, cp0_status);
index("#define EF_CAUSE ", struct pt_regs, cp0_cause);
linefeed;
size("#define EF_SIZE ", struct pt_regs);
linefeed;
}
......@@ -5,6 +5,7 @@
*
* Copyright (C) 1995, 96, 97, 98, 99, 2000, 01, 02 by Ralf Baechle
* Copyright (C) 2001 MIPS Technologies, Inc.
* Copyright (C) 2004 Thiemo Seufer
*/
#include <linux/config.h>
#include <linux/errno.h>
......@@ -32,26 +33,30 @@ NESTED(handle_sys, PT_SIZE, sp)
lw t1, PT_EPC(sp) # skip syscall on return
#if defined(CONFIG_BINFMT_IRIX)
sltiu t0, v0, MAX_SYSCALL_NO + 1 # check syscall number
#else
subu v0, v0, __NR_O32_Linux # check syscall number
sltiu t0, v0, __NR_O32_Linux_syscalls + 1
#endif
addiu t1, 4 # skip to next instruction
sw t1, PT_EPC(sp)
beqz t0, illegal_syscall
/* XXX Put both in one cacheline, should save a bit. */
sll t0, v0, 2
lw t2, sys_call_table(t0) # syscall routine
lbu t3, sys_narg_table(v0) # number of arguments
beqz t2, illegal_syscall;
sll t0, v0, 3
la t1, sys_call_table
addu t1, t0
lw t2, (t1) # syscall routine
lw t3, 4(t1) # >= 0 if we need stack arguments
beqz t2, illegal_syscall
subu t0, t3, 5 # 5 or more arguments?
sw a3, PT_R26(sp) # save a3 for syscall restarting
bgez t0, stackargs
bgez t3, stackargs
stack_done:
sw a3, PT_R26(sp) # save for syscall restart
LONG_L t0, TI_FLAGS($28) # syscall tracing enabled?
lw t0, TI_FLAGS($28) # syscall tracing enabled?
li t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
and t0, t1, t0
and t0, t1
bnez t0, syscall_trace_entry # -> yes
jalr t2 # Do The Real Thing (TM)
......@@ -70,9 +75,9 @@ o32_syscall_exit:
local_irq_disable # make sure need_resched and
# signals dont change between
# sampling and return
LONG_L a2, TI_FLAGS($28) # current->work
lw a2, TI_FLAGS($28) # current->work
li t0, _TIF_ALLWORK_MASK
and t0, a2, t0
and t0, a2
bnez t0, o32_syscall_exit_work
j restore_partial
......@@ -116,49 +121,48 @@ syscall_trace_entry:
*/
stackargs:
lw t0, PT_R29(sp) # get old user stack pointer
subu t3, 4
sll t1, t3, 2 # stack valid?
addu t1, t0 # end address
or t0, t1
bltz t0, bad_stack # -> sp is bad
lw t0, PT_R29(sp) # get old user stack pointer
PTR_LA t1, 4f # copy 1 to 3 arguments
sll t3, t3, 4
subu t1, t3
jr t1
/* Ok, copy the args from the luser stack to the kernel stack */
/*
* I know Ralf doesn't like nops but this avoids code
* duplication for R3000 targets (and this is the
* only place where ".set reorder" doesn't help).
* Harald.
* We intentionally keep the kernel stack a little below the top of
* userspace so we don't have to do a slower byte accurate check here.
*/
lw t5, TI_ADDR_LIMIT($28)
addu t4, t0, 32
and t5, t4
bltz t5, bad_stack # -> sp is bad
/* Ok, copy the args from the luser stack to the kernel stack.
* t3 is the precomputed number of instruction bytes needed to
* load or store arguments 6-8.
*/
la t1, 5f # load up to 3 arguments
subu t1, t3
1: lw t5, 16(t0) # argument #5 from usp
.set push
.set noreorder
.set nomacro
1: lw t1, 24(t0) # argument #7 from usp
nop
sw t1, 24(sp)
nop
2: lw t1, 20(t0) # argument #5 from usp
nop
sw t1, 20(sp)
nop
3: lw t1, 16(t0) # argument #5 from usp
nop
sw t1, 16(sp)
jr t1
addiu t1, 6f - 5f
2: lw t8, 28(t0) # argument #8 from usp
3: lw t7, 24(t0) # argument #7 from usp
4: lw t6, 20(t0) # argument #6 from usp
5: jr t1
sw t5, 16(sp) # argument #5 to ksp
sw t8, 28(sp) # argument #8 to ksp
sw t7, 24(sp) # argument #7 to ksp
sw t6, 20(sp) # argument #6 to ksp
6: j stack_done # go back
nop
4: .set pop
j stack_done # go back
.set pop
.section __ex_table,"a"
PTR 1b,bad_stack
PTR 2b,bad_stack
PTR 3b,bad_stack
PTR 4b,bad_stack
.previous
/*
......@@ -177,7 +181,7 @@ bad_stack:
* The system call does not exist in this kernel
*/
illegal_syscall:
li v0, ENOSYS # error
li v0, -ENOSYS # error
sw v0, PT_R2(sp)
li t0, 1 # set error flag
sw t0, PT_R7(sp)
......@@ -238,12 +242,12 @@ illegal_syscall:
sw v0, PT_R2(sp) # result
/* Success, so skip usual error handling garbage. */
LONG_L a2, TI_FLAGS($28) # syscall tracing enabled?
lw a2, TI_FLAGS($28) # syscall tracing enabled?
li t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
and t0, a2, t0
bnez t0, 1f
b o32_syscall_exit
j o32_syscall_exit
1: SAVE_STATIC
move a0, sp
......@@ -269,69 +273,49 @@ bad_alignment:
END(sys_sysmips)
LEAF(sys_syscall)
lw t0, PT_R29(sp) # user sp
sltu v0, a0, __NR_O32_Linux + __NR_O32_Linux_syscalls + 1
beqz v0, enosys
sll v0, a0, 2
la v1, sys_syscall
lw t2, sys_call_table(v0) # function pointer
lbu t4, sys_narg_table(a0) # number of arguments
li v0, -EINVAL
beq t2, v1, out # do not recurse
#if defined(CONFIG_BINFMT_IRIX)
sltiu v0, a0, MAX_SYSCALL_NO + 1 # check syscall number
#else
subu t0, a0, __NR_O32_Linux # check syscall number
sltiu v0, t0, __NR_O32_Linux_syscalls + 1
#endif
sll t1, t0, 3
beqz v0, einval
beqz t2, enosys # null function pointer?
lw t2, sys_call_table(t1) # syscall routine
andi v0, t0, 0x3 # unaligned stack pointer?
bnez v0, sigsegv
#if defined(CONFIG_BINFMT_IRIX)
li v1, 4000 # nr of sys_syscall
#else
li v1, 4000 - __NR_O32_Linux # index of sys_syscall
#endif
beq t0, v1, einval # do not recurse
addu v0, t0, 16 # v0 = usp + 16
addu t1, v0, 12 # 3 32-bit arguments
lw v1, TI_ADDR_LIMIT($28)
or v0, v0, t1
and v1, v1, v0
bltz v1, efault
/* Some syscalls like execve get their arguments from struct pt_regs
and claim zero arguments in the syscall table. Thus we have to
assume the worst case and shuffle around all potential arguments.
If you want performance, don't use indirect syscalls. */
move a0, a1 # shift argument registers
move a1, a2
move a2, a3
1: lw a3, 16(t0)
2: lw t3, 20(t0)
3: lw t4, 24(t0)
.section __ex_table, "a"
.word 1b, efault
.word 2b, efault
.word 3b, efault
.previous
sw t3, 16(sp) # put into new stackframe
sw t4, 20(sp)
bnez t4, 1f # zero arguments?
addu a0, sp, 32 # then pass sp in a0
1:
sw t3, 16(sp)
sw v1, 20(sp)
lw a3, 16(sp)
lw t4, 20(sp)
lw t5, 24(sp)
lw t6, 28(sp)
sw t4, 16(sp)
sw t5, 20(sp)
sw t6, 24(sp)
sw a0, PT_R4(sp) # .. and push back a0 - a3, some
sw a1, PT_R5(sp) # syscalls expect them there
sw a2, PT_R6(sp)
sw a3, PT_R7(sp)
sw a3, PT_R26(sp) # update a3 for syscall restarting
jr t2
/* Unreached */
enosys: li v0, -ENOSYS
b out
sigsegv:
li a0, _SIGSEGV
move a1, $28
jal force_sig
/* Fall through */
efault: li v0, -EFAULT
out: jr ra
einval: li v0, -EINVAL
jr ra
END(sys_syscall)
.macro fifty ptr, nargs, from=1, to=50
......@@ -349,12 +333,14 @@ out: jr ra
.endm
.macro syscalltable
#if defined(CONFIG_BINFMT_IRIX)
mille sys_ni_syscall 0 /* 0 - 999 SVR4 flavour */
#include "irix5sys.h" /* 1000 - 1999 32-bit IRIX */
mille sys_ni_syscall 0 /* 1000 - 1999 32-bit IRIX */
mille sys_ni_syscall 0 /* 2000 - 2999 BSD43 flavour */
mille sys_ni_syscall 0 /* 3000 - 3999 POSIX flavour */
#endif
sys sys_syscall 0 /* 4000 */
sys sys_syscall 8 /* 4000 */
sys sys_exit 1
sys sys_fork 0
sys sys_read 3
......@@ -405,7 +391,7 @@ out: jr ra
sys sys_ni_syscall 0 /* was signal(2) */
sys sys_geteuid 0
sys sys_getegid 0 /* 4050 */
sys sys_acct 0
sys sys_acct 1
sys sys_umount 2
sys sys_ni_syscall 0
sys sys_ioctl 3
......@@ -485,7 +471,7 @@ out: jr ra
sys sys_init_module 5
sys sys_delete_module 1
sys sys_ni_syscall 0 /* 4130 was get_kernel_syms */
sys sys_quotactl 0
sys sys_quotactl 4
sys sys_getpgid 1
sys sys_fchdir 1
sys sys_bdflush 2
......@@ -506,7 +492,7 @@ out: jr ra
sys sys_sysmips 4
sys sys_ni_syscall 0 /* 4150 */
sys sys_getsid 1
sys sys_fdatasync 0
sys sys_fdatasync 1
sys sys_sysctl 1
sys sys_mlock 2
sys sys_munlock 2 /* 4155 */
......@@ -640,19 +626,16 @@ out: jr ra
.endm
/* We pre-compute the number of _instruction_ bytes needed to
load or store the arguments 6-8. Negative values are ignored. */
.macro sys function, nargs
PTR \function
LONG (\nargs << 2) - (5 << 2)
.endm
.align 3
sys_call_table:
.type sys_call_table,@object
EXPORT(sys_call_table)
syscalltable
.size sys_call_table, . - sys_call_table
.macro sys function, nargs
.byte \nargs
.endm
sys_narg_table:
syscalltable
.size sys_narg_table, . - sys_narg_table
......@@ -53,8 +53,10 @@ NESTED(handle_sys64, PT_SIZE, sp)
sd a3, PT_R26(sp) # save a3 for syscall restarting
LONG_L t0, TI_FLAGS($28)
bltz t0, syscall_trace_entry # syscall tracing enabled?
li t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
LONG_L t0, TI_FLAGS($28) # syscall tracing enabled?
and t0, t1, t0
bnez t0, syscall_trace_entry
jalr t2 # Do The Real Thing (TM)
......@@ -112,7 +114,7 @@ syscall_trace_entry:
illegal_syscall:
/* This also isn't a 64-bit syscall, throw an error. */
li v0, ENOSYS # error
li v0, -ENOSYS # error
sd v0, PT_R2(sp)
li t0, 1 # set error flag
sd t0, PT_R7(sp)
......@@ -173,8 +175,8 @@ illegal_syscall:
sd v0, PT_R2(sp) # result
/* Success, so skip usual error handling garbage. */
LONG_L a2, TI_FLAGS($28) # syscall tracing enabled?
li t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
LONG_L a2, TI_FLAGS($28) # syscall tracing enabled?
and t0, a2, t0
bnez t0, 1f
......
......@@ -6,6 +6,7 @@
* Copyright (C) 1995 - 2000, 2001 by Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
* Copyright (C) 2001 MIPS Technologies, Inc.
* Copyright (C) 2004 Thiemo Seufer
*
* Hairy, the userspace application uses a different argument passing
* convention than the kernel, so we have to translate things from o32
......@@ -43,6 +44,8 @@ NESTED(handle_sys, PT_SIZE, sp)
RESTORE_ALL
#endif
/* We don't want to stumble over broken sign extensions from
userland. O32 does never use the upper half. */
sll a0, a0, 0
sll a1, a1, 0
sll a2, a2, 0
......@@ -68,11 +71,13 @@ NESTED(handle_sys, PT_SIZE, sp)
1: lw a4, 16(t0) # argument #5 from usp
2: lw a5, 20(t0) # argument #6 from usp
3: lw a6, 24(t0) # argument #7 from usp
4: lw a7, 28(t0) # argument #8 from usp (for indirect syscalls)
.section __ex_table,"a"
PTR 1b, bad_stack
PTR 2b, bad_stack
PTR 3b, bad_stack
PTR 4b, bad_stack
.previous
li t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
......@@ -91,7 +96,7 @@ NESTED(handle_sys, PT_SIZE, sp)
sd v0, PT_R0(sp) # flag for syscall restarting
1: sd v0, PT_R2(sp) # result
FEXPORT(o32_syscall_exit)
o32_syscall_exit:
local_irq_disable # make need_resched and
# signals dont change between
# sampling and return
......@@ -109,12 +114,12 @@ o32_syscall_exit_work:
trace_a_syscall:
SAVE_STATIC
sd a4, PT_R8(sp)
sd a4, PT_R8(sp) # Save argument registers
sd a5, PT_R9(sp)
sd a6, PT_R10(sp)
sd a7, PT_R11(sp)
sd a7, PT_R11(sp) # For indirect syscalls
move s0, t2
move s0, t2 # Save syscall pointer
move a0, sp
li a1, 0
jal do_syscall_trace
......@@ -125,7 +130,8 @@ trace_a_syscall:
ld a3, PT_R7(sp)
ld a4, PT_R8(sp)
ld a5, PT_R9(sp)
ld a6, PT_R10(sp) # For indirect syscalls
ld a6, PT_R10(sp)
ld a7, PT_R11(sp) # For indirect syscalls
jalr s0
li t0, -EMAXERRNO - 1 # error?
......@@ -162,40 +168,17 @@ not_o32_scall:
#else
j handle_sys64
#endif
illegal_syscall:
/* This also isn't a 64-bit syscall, throw an error. */
li v0, ENOSYS # error
sd v0, PT_R2(sp)
li t0, 1 # set error flag
sd t0, PT_R7(sp)
j o32_syscall_exit
END(handle_sys)
LEAF(sys32_syscall)
ld t0, PT_R29(sp) # user sp
sltu v0, a0, __NR_O32_Linux + __NR_O32_Linux_syscalls + 1
beqz v0, enosys
beqz v0, einval
dsll v0, a0, 3
dla v1, sys32_syscall
ld t2, (sys_call_table - (__NR_O32_Linux * 8))(v0)
li v0, -EINVAL
beq t2, v1, out # do not recurse
beqz t2, enosys # null function pointer?
andi v0, t0, 0x3 # unaligned stack pointer?
bnez v0, sigsegv
daddiu v0, t0, 16 # v0 = usp + 16
daddu t1, v0, 12 # 3 32-bit arguments
ld v1, TI_ADDR_LIMIT($28)
or v0, v0, t1
and v1, v1, v0
bnez v1, efault
li v1, 4000 # indirect syscall number
beq a0, v1, einval # do not recurse
move a0, a1 # shift argument registers
move a1, a2
......@@ -203,25 +186,21 @@ LEAF(sys32_syscall)
move a3, a4
move a4, a5
move a5, a6
move a6, a7
sd a0, PT_R4(sp) # ... and push back a0 - a3, some
sd a1, PT_R5(sp) # syscalls expect them there
sd a2, PT_R6(sp)
sd a3, PT_R7(sp)
sd a3, PT_R26(sp) # update a3 for syscall restarting
jr t2
/* Unreached */
enosys: li v0, -ENOSYS
b out
sigsegv:
li a0, _SIGSEGV
move a1, $28
jal force_sig
/* Fall through */
efault: li v0, -EFAULT
out: jr ra
einval: li v0, -EINVAL
jr ra
END(sys32_syscall)
.align 3
.type sys_call_table,@object;
.type sys_call_table,@object
sys_call_table:
PTR sys32_syscall /* 4000 */
PTR sys_exit
......
......@@ -15,7 +15,6 @@
* indicate that some process(es) are waiting for the semaphore.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
......@@ -64,7 +63,7 @@ static inline int __sem_update_count(struct semaphore *sem, int incr)
: "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
: "r" (incr), "m" (sem->count));
} else {
static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED;
static DEFINE_SPINLOCK(semaphore_lock);
unsigned long flags;
spin_lock_irqsave(&semaphore_lock, flags);
......
......@@ -281,12 +281,12 @@ static inline void bootmem_init(void)
initrd_reserve_bootmem = 1;
} else {
unsigned long tmp;
unsigned long *initrd_header;
u32 *initrd_header;
tmp = ((reserved_end + PAGE_SIZE-1) & PAGE_MASK) - 8;
tmp = ((reserved_end + PAGE_SIZE-1) & PAGE_MASK) - sizeof(u32) * 2;
if (tmp < reserved_end)
tmp += PAGE_SIZE;
initrd_header = (unsigned long *)tmp;
initrd_header = (u32 *)tmp;
if (initrd_header[0] == 0x494E5244) {
initrd_start = (unsigned long)&initrd_header[2];
initrd_end = initrd_start + initrd_header[1];
......@@ -425,8 +425,10 @@ static inline void bootmem_init(void)
if (CPHYSADDR(initrd_end) > PFN_PHYS(max_low_pfn)) {
printk("initrd extends beyond end of memory "
"(0x%0*Lx > 0x%0*Lx)\ndisabling initrd\n",
sizeof(long) * 2, CPHYSADDR(initrd_end),
sizeof(long) * 2, PFN_PHYS(max_low_pfn));
sizeof(long) * 2,
(unsigned long long)CPHYSADDR(initrd_end),
sizeof(long) * 2,
(unsigned long long)PFN_PHYS(max_low_pfn));
initrd_start = initrd_end = 0;
initrd_reserve_bootmem = 0;
}
......@@ -441,10 +443,21 @@ static inline void resource_init(void)
{
int i;
#if defined(CONFIG_MIPS64) && !defined(CONFIG_BUILD_ELF64)
/*
* The 64bit code in 32bit object format trick can't represent
* 64bit wide relocations for linker script symbols.
*/
code_resource.start = CPHYSADDR(&_text);
code_resource.end = CPHYSADDR(&_etext) - 1;
data_resource.start = CPHYSADDR(&_etext);
data_resource.end = CPHYSADDR(&_edata) - 1;
#else
code_resource.start = virt_to_phys(&_text);
code_resource.end = virt_to_phys(&_etext) - 1;
data_resource.start = virt_to_phys(&_etext);
data_resource.end = virt_to_phys(&_edata) - 1;
#endif
/*
* Request address space for all standard RAM.
......
/*
* 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) 1991, 1992 Linus Torvalds
* Copyright (C) 1994 - 2000 Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*/
static inline int
setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
{
int err = 0;
err |= __put_user(regs->cp0_epc, &sc->sc_pc);
err |= __put_user(regs->cp0_status, &sc->sc_status);
#define save_gp_reg(i) do { \
err |= __put_user(regs->regs[i], &sc->sc_regs[i]); \
} while(0)
__put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
save_gp_reg(31);
#undef save_gp_reg
err |= __put_user(regs->hi, &sc->sc_mdhi);
err |= __put_user(regs->lo, &sc->sc_mdlo);
err |= __put_user(regs->cp0_cause, &sc->sc_cause);
err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr);
err |= __put_user(!!used_math(), &sc->sc_used_math);
if (!used_math())
goto out;
/*
* Save FPU state to signal context. Signal handler will "inherit"
* current FPU state.
*/
preempt_disable();
if (!is_fpu_owner()) {
own_fpu();
restore_fp(current);
}
err |= save_fp_context(sc);
preempt_enable();
out:
return err;
}
static inline int
restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
{
int err = 0;
unsigned int used_math;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
err |= __get_user(regs->cp0_epc, &sc->sc_pc);
err |= __get_user(regs->hi, &sc->sc_mdhi);
err |= __get_user(regs->lo, &sc->sc_mdlo);
#define restore_gp_reg(i) do { \
err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \
} while(0)
restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
restore_gp_reg(31);
#undef restore_gp_reg
err |= __get_user(used_math, &sc->sc_used_math);
conditional_used_math(used_math);
preempt_disable();
if (used_math()) {
/* restore fpu context if we have used it before */
own_fpu();
err |= restore_fp_context(sc);
} else {
/* signal handler may have used FPU. Give it up. */
lose_fpu();
}
preempt_enable();
return err;
}
/*
* Determine which stack to use..
*/
static inline void *
get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
{
unsigned long sp, almask;
/* Default to using normal stack */
sp = regs->regs[29];
/*
* FPU emulator may have it's own trampoline active just
* above the user stack, 16-bytes before the next lowest
* 16 byte boundary. Try to avoid trashing it.
*/
sp -= 32;
/* This is the X/Open sanctioned signal stack switching. */
if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
sp = current->sas_ss_sp + current->sas_ss_size;
if (PLAT_TRAMPOLINE_STUFF_LINE)
almask = ~(PLAT_TRAMPOLINE_STUFF_LINE - 1);
else
almask = ALMASK;
return (void *)((sp - frame_size) & almask);
}
......@@ -28,12 +28,15 @@
#include <asm/sim.h>
#include <asm/uaccess.h>
#include <asm/ucontext.h>
#include <asm/cpu-features.h>
#include "signal-common.h"
#define DEBUG_SIG 0
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
extern asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
static int do_signal(sigset_t *oldset, struct pt_regs *regs);
/*
* Atomically swap in the new signal mask, and wait for a signal.
......@@ -151,53 +154,6 @@ asmlinkage int sys_sigaltstack(nabi_no_regargs struct pt_regs regs)
return do_sigaltstack(uss, uoss, usp);
}
asmlinkage int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
{
int err = 0;
unsigned int used_math;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
err |= __get_user(regs->cp0_epc, &sc->sc_pc);
err |= __get_user(regs->hi, &sc->sc_mdhi);
err |= __get_user(regs->lo, &sc->sc_mdlo);
#define restore_gp_reg(i) do { \
err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \
} while(0)
restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
restore_gp_reg(31);
#undef restore_gp_reg
err |= __get_user(used_math, &sc->sc_used_math);
conditional_used_math(used_math);
preempt_disable();
if (used_math()) {
/* restore fpu context if we have used it before */
own_fpu();
err |= restore_fp_context(sc);
} else {
/* signal handler may have used FPU. Give it up. */
lose_fpu();
}
preempt_enable();
return err;
}
#if PLAT_TRAMPOLINE_STUFF_LINE
#define __tramp __attribute__((aligned(PLAT_TRAMPOLINE_STUFF_LINE)))
#else
......@@ -221,7 +177,9 @@ struct rt_sigframe {
};
#ifdef CONFIG_TRAD_SIGNALS
asmlinkage void sys_sigreturn(struct pt_regs regs)
save_static_function(sys_sigreturn);
__attribute_used__ noinline static void
_sys_sigreturn(nabi_no_regargs struct pt_regs regs)
{
struct sigframe *frame;
sigset_t blocked;
......@@ -258,7 +216,9 @@ asmlinkage void sys_sigreturn(struct pt_regs regs)
}
#endif
asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
save_static_function(sys_rt_sigreturn);
__attribute_used__ noinline static void
_sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
{
struct rt_sigframe *frame;
sigset_t set;
......@@ -299,85 +259,6 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
force_sig(SIGSEGV, current);
}
inline int setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
{
int err = 0;
err |= __put_user(regs->cp0_epc, &sc->sc_pc);
err |= __put_user(regs->cp0_status, &sc->sc_status);
#define save_gp_reg(i) do { \
err |= __put_user(regs->regs[i], &sc->sc_regs[i]); \
} while(0)
__put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
save_gp_reg(31);
#undef save_gp_reg
err |= __put_user(regs->hi, &sc->sc_mdhi);
err |= __put_user(regs->lo, &sc->sc_mdlo);
err |= __put_user(regs->cp0_cause, &sc->sc_cause);
err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr);
err |= __put_user(!!used_math(), &sc->sc_used_math);
if (!used_math())
goto out;
/*
* Save FPU state to signal context. Signal handler will "inherit"
* current FPU state.
*/
preempt_disable();
if (!is_fpu_owner()) {
own_fpu();
restore_fp(current);
}
err |= save_fp_context(sc);
preempt_enable();
out:
return err;
}
/*
* Determine which stack to use..
*/
static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
size_t frame_size)
{
unsigned long sp, almask;
/* Default to using normal stack */
sp = regs->regs[29];
/*
* FPU emulator may have it's own trampoline active just
* above the user stack, 16-bytes before the next lowest
* 16 byte boundary. Try to avoid trashing it.
*/
sp -= 32;
/* This is the X/Open sanctioned signal stack switching. */
if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
sp = current->sas_ss_sp + current->sas_ss_size;
if (PLAT_TRAMPOLINE_STUFF_LINE)
almask = ~(PLAT_TRAMPOLINE_STUFF_LINE - 1);
else
almask = ALMASK;
return (void *)((sp - frame_size) & ~(PLAT_TRAMPOLINE_STUFF_LINE - 1));
}
#ifdef CONFIG_TRAD_SIGNALS
static void inline setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
int signr, sigset_t *set)
......@@ -396,8 +277,7 @@ static void inline setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
* syscall
*/
if (PLAT_TRAMPOLINE_STUFF_LINE)
__builtin_memset(frame->sf_code, '0',
PLAT_TRAMPOLINE_STUFF_LINE);
__clear_user(frame->sf_code, PLAT_TRAMPOLINE_STUFF_LINE);
err |= __put_user(0x24020000 + __NR_sigreturn, frame->sf_code + 0);
err |= __put_user(0x0000000c , frame->sf_code + 1);
flush_cache_sigtramp((unsigned long) frame->sf_code);
......@@ -453,8 +333,7 @@ static void inline setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
* syscall
*/
if (PLAT_TRAMPOLINE_STUFF_LINE)
__builtin_memset(frame->rs_code, '0',
PLAT_TRAMPOLINE_STUFF_LINE);
__clear_user(frame->rs_code, PLAT_TRAMPOLINE_STUFF_LINE);
err |= __put_user(0x24020000 + __NR_rt_sigreturn, frame->rs_code + 0);
err |= __put_user(0x0000000c , frame->rs_code + 1);
flush_cache_sigtramp((unsigned long) frame->rs_code);
......@@ -558,7 +437,7 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info,
extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
extern int do_irix_signal(sigset_t *oldset, struct pt_regs *regs);
asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
static int do_signal(sigset_t *oldset, struct pt_regs *regs)
{
struct k_sigaction ka;
siginfo_t info;
......@@ -612,8 +491,6 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
return 0;
}
extern int do_irix_signal(sigset_t *oldset, struct pt_regs *regs);
/*
* notification of userspace execution resumption
* - triggered by current->work.notify_resume
......
......@@ -37,7 +37,7 @@ typedef union sigval32 {
s32 sival_ptr;
} sigval_t32;
typedef struct compat_siginfo{
typedef struct compat_siginfo {
int si_signo;
int si_code;
int si_errno;
......@@ -106,7 +106,7 @@ typedef struct compat_siginfo{
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
extern asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs);
extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
/* 32-bit compatibility types */
......@@ -192,6 +192,7 @@ static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t *ubuf)
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
save_static_function(sys32_sigsuspend);
__attribute_used__ noinline static int
_sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
......@@ -333,8 +334,7 @@ asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
return ret;
}
static asmlinkage int restore_sigcontext32(struct pt_regs *regs,
struct sigcontext32 *sc)
static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 *sc)
{
int err = 0;
__u32 used_math;
......@@ -391,7 +391,7 @@ struct sigframe {
struct rt_sigframe32 {
u32 rs_ass[4]; /* argument save space for o32 */
u32 rs_code[2]; /* signal trampoline */
struct compat_siginfo_t rs_info;
compat_siginfo_t rs_info;
struct ucontext32 rs_uc;
};
......@@ -442,7 +442,9 @@ int copy_siginfo_to_user32(compat_siginfo_t *to, siginfo_t *from)
return err;
}
asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
save_static_function(sys32_sigreturn);
__attribute_used__ noinline static void
_sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
{
struct sigframe *frame;
sigset_t blocked;
......@@ -478,7 +480,9 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
force_sig(SIGSEGV, current);
}
asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
save_static_function(sys32_rt_sigreturn);
__attribute_used__ noinline static void
_sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
{
struct rt_sigframe32 *frame;
sigset_t set;
......@@ -761,7 +765,7 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info,
}
}
asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs)
int do_signal32(sigset_t *oldset, struct pt_regs *regs)
{
struct k_sigaction ka;
siginfo_t info;
......
......@@ -35,9 +35,12 @@
#include <asm/ucontext.h>
#include <asm/system.h>
#include <asm/fpu.h>
#include <asm/cpu-features.h>
#include "signal-common.h"
/*
* Including <asm/unistd.h would give use the 64-bit syscall numbers ...
* Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
*/
#define __NR_N32_rt_sigreturn 6211
#define __NR_N32_restart_syscall 6214
......@@ -59,17 +62,22 @@ struct ucontextn32 {
sigset_t uc_sigmask; /* mask last for extensibility */
};
#if PLAT_TRAMPOLINE_STUFF_LINE
#define __tramp __attribute__((aligned(PLAT_TRAMPOLINE_STUFF_LINE)))
#else
#define __tramp
#endif
struct rt_sigframe_n32 {
u32 rs_ass[4]; /* argument save space for o32 */
u32 rs_code[2]; /* signal trampoline */
struct siginfo rs_info;
u32 rs_code[2] __tramp; /* signal trampoline */
struct siginfo rs_info __tramp;
struct ucontextn32 rs_uc;
};
extern asmlinkage int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc);
extern int inline setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc);
asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
save_static_function(sysn32_rt_sigreturn);
__attribute_used__ noinline static void
_sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
{
struct rt_sigframe_n32 *frame;
sigset_t set;
......@@ -118,31 +126,6 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
force_sig(SIGSEGV, current);
}
/*
* Determine which stack to use..
*/
static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
size_t frame_size)
{
unsigned long sp;
/* Default to using normal stack */
sp = regs->regs[29];
/*
* FPU emulator may have it's own trampoline active just
* above the user stack, 16-bytes before the next lowest
* 16 byte boundary. Try to avoid trashing it.
*/
sp -= 32;
/* This is the X/Open sanctioned signal stack switching. */
if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
sp = current->sas_ss_sp + current->sas_ss_size;
return (void *)((sp - frame_size) & ALMASK);
}
void setup_rt_frame_n32(struct k_sigaction * ka,
struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info)
{
......@@ -160,6 +143,8 @@ void setup_rt_frame_n32(struct k_sigaction * ka,
* li v0, __NR_rt_sigreturn
* syscall
*/
if (PLAT_TRAMPOLINE_STUFF_LINE)
__clear_user(frame->rs_code, PLAT_TRAMPOLINE_STUFF_LINE);
err |= __put_user(0x24020000 + __NR_N32_rt_sigreturn, frame->rs_code + 0);
err |= __put_user(0x0000000c , frame->rs_code + 1);
flush_cache_sigtramp((unsigned long) frame->rs_code);
......
......@@ -18,7 +18,6 @@
* Copyright (C) 2000, 2001 Silicon Graphics, Inc.
* Copyright (C) 2000, 2001, 2003 Broadcom Corporation
*/
#include <linux/config.h>
#include <linux/cache.h>
#include <linux/delay.h>
#include <linux/init.h>
......@@ -94,6 +93,7 @@ static void smp_tune_scheduling (void)
}
extern void __init calibrate_delay(void);
extern ATTRIB_NORET void cpu_idle(void);
/*
* First C code run on the secondary CPUs after being started up by
......@@ -123,7 +123,7 @@ asmlinkage void start_secondary(void)
cpu_idle();
}
spinlock_t smp_call_lock = SPIN_LOCK_UNLOCKED;
DEFINE_SPINLOCK(smp_call_lock);
struct call_data_struct *call_data;
......
......@@ -3,10 +3,11 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1995, 1996, 1997, 2000, 2001 by Ralf Baechle
* Copyright (C) 1995, 1996, 1997, 2000, 2001, 05 by Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
* Copyright (C) 2001 MIPS Technologies, Inc.
*/
#include <linux/a.out.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <linux/mm.h>
......@@ -66,11 +67,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
int do_color_align;
unsigned long task_size;
#ifdef CONFIG_MIPS32
task_size = TASK_SIZE;
#else
task_size = (current->thread.mflags & MF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE;
#endif
task_size = STACK_TOP;
if (flags & MAP_FIXED) {
/*
......@@ -116,7 +113,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
}
/* common code for old and new mmaps */
static inline long
static inline unsigned long
do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
unsigned long flags, unsigned long fd, unsigned long pgoff)
{
......@@ -140,7 +137,8 @@ do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
return error;
}
asmlinkage unsigned long old_mmap(unsigned long addr, size_t len, int prot,
asmlinkage unsigned long
old_mmap(unsigned long addr, unsigned long len, int prot,
int flags, int fd, off_t offset)
{
unsigned long result;
......@@ -155,7 +153,7 @@ asmlinkage unsigned long old_mmap(unsigned long addr, size_t len, int prot,
return result;
}
asmlinkage long
asmlinkage unsigned long
sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
unsigned long flags, unsigned long fd, unsigned long pgoff)
{
......
......@@ -11,7 +11,6 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
......@@ -53,7 +52,7 @@ EXPORT_SYMBOL(jiffies_64);
*/
extern volatile unsigned long wall_jiffies;
spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
DEFINE_SPINLOCK(rtc_lock);
/*
* By default we provide the null RTC ops
......
......@@ -38,12 +38,9 @@
#include <asm/watch.h>
#include <asm/types.h>
extern asmlinkage void handle_mod(void);
extern asmlinkage void handle_tlbm(void);
extern asmlinkage void handle_tlbl(void);
extern asmlinkage void handle_tlbs(void);
extern asmlinkage void __xtlb_mod(void);
extern asmlinkage void __xtlb_tlbl(void);
extern asmlinkage void __xtlb_tlbs(void);
extern asmlinkage void handle_adel(void);
extern asmlinkage void handle_ades(void);
extern asmlinkage void handle_ibe(void);
......@@ -82,7 +79,12 @@ void show_stack(struct task_struct *task, unsigned long *sp)
long stackdata;
int i;
sp = sp ? sp : (unsigned long *) &sp;
if (!sp) {
if (task && task != current)
sp = (unsigned long *) task->thread.reg29;
else
sp = (unsigned long *) &sp;
}
printk("Stack :");
i = 0;
......@@ -110,8 +112,12 @@ void show_trace(struct task_struct *task, unsigned long *stack)
const int field = 2 * sizeof(unsigned long);
unsigned long addr;
if (!stack)
stack = (unsigned long*)&stack;
if (!stack) {
if (task && task != current)
stack = (unsigned long *) task->thread.reg29;
else
stack = (unsigned long *) &stack;
}
printk("Call Trace:");
#ifdef CONFIG_KALLSYMS
......@@ -244,7 +250,7 @@ void show_registers(struct pt_regs *regs)
printk("\n");
}
static spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
static DEFINE_SPINLOCK(die_lock);
NORET_TYPE void __die(const char * str, struct pt_regs * regs,
const char * file, const char * func, unsigned long line)
......@@ -1001,16 +1007,10 @@ void __init trap_init(void)
if (board_be_init)
board_be_init();
#ifdef CONFIG_MIPS32
set_except_vector(1, handle_mod);
set_except_vector(1, handle_tlbm);
set_except_vector(2, handle_tlbl);
set_except_vector(3, handle_tlbs);
#endif
#ifdef CONFIG_MIPS64
set_except_vector(1, __xtlb_mod);
set_except_vector(2, __xtlb_tlbl);
set_except_vector(3, __xtlb_tlbs);
#endif
set_except_vector(4, handle_adel);
set_except_vector(5, handle_ades);
......@@ -1047,7 +1047,7 @@ void __init trap_init(void)
* unaligned ldc1/sdc1 exception. The handlers have not been
* written yet. Well, anyway there is no R6000 machine on the
* current list of targets for Linux/MIPS.
* (Duh, crap, there is someone with a tripple R6k machine)
* (Duh, crap, there is someone with a triple R6k machine)
*/
//set_except_vector(14, handle_mc);
//set_except_vector(15, handle_ndc);
......
......@@ -156,6 +156,7 @@ SECTIONS
*(.options)
*(.pdr)
*(.reginfo)
*(.mdebug*)
}
/* This is the MIPS specific mdebug section. */
......
......@@ -148,16 +148,16 @@ void dump_list_process(struct task_struct *t, void *address)
printk("tasks->mm.pgd == %08lx\n", (unsigned long) t->mm->pgd);
page_dir = pgd_offset(t->mm, 0);
printk("page_dir == %08lx\n", (unsigned long) page_dir);
printk("page_dir == %016lx\n", (unsigned long) page_dir);
pgd = pgd_offset(t->mm, addr);
printk("pgd == %08lx, ", (unsigned long) pgd);
printk("pgd == %016lx\n", (unsigned long) pgd);
pmd = pmd_offset(pgd, addr);
printk("pmd == %08lx, ", (unsigned long) pmd);
printk("pmd == %016lx\n", (unsigned long) pmd);
pte = pte_offset(pmd, addr);
printk("pte == %08lx, ", (unsigned long) pte);
printk("pte == %016lx\n", (unsigned long) pte);
page = *pte;
printk("page == %08lx\n", pte_val(page));
......
......@@ -2,7 +2,7 @@
* cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator
*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -8,7 +8,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*
* MIPS floating point support
*
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* This program is free software; you can distribute it and/or modify it
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -4,7 +4,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -4,7 +4,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -4,7 +4,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
......
......@@ -3,7 +3,7 @@
#
obj-y += cache.o extable.o fault.o init.o pgtable.o \
tlbex.o
tlbex.o tlbex-fault.o
obj-$(CONFIG_MIPS32) += ioremap.o pgtable-32.o
obj-$(CONFIG_MIPS64) += pgtable-64.o
......@@ -27,40 +27,6 @@ obj-$(CONFIG_CPU_TX39XX) += c-tx39.o pg-r4k.o tlb-r3k.o
obj-$(CONFIG_CPU_TX49XX) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
obj-$(CONFIG_CPU_VR41XX) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
#
# TLB exception handling code differs between 32-bit and 64-bit kernels.
#
ifdef CONFIG_MIPS32
obj-$(CONFIG_CPU_R3000) += tlbex32-r3k.o
obj-$(CONFIG_CPU_TX49XX) += tlbex32-r4k.o
obj-$(CONFIG_CPU_R4300) += tlbex32-r4k.o
obj-$(CONFIG_CPU_R4X00) += tlbex32-r4k.o
obj-$(CONFIG_CPU_VR41XX) += tlbex32-r4k.o
obj-$(CONFIG_CPU_R5000) += tlbex32-r4k.o
obj-$(CONFIG_CPU_NEVADA) += tlbex32-r4k.o
obj-$(CONFIG_CPU_R5432) += tlbex32-r4k.o
obj-$(CONFIG_CPU_RM7000) += tlbex32-r4k.o
obj-$(CONFIG_CPU_RM9000) += tlbex32-r4k.o
obj-$(CONFIG_CPU_R10000) += tlbex32-r4k.o
obj-$(CONFIG_CPU_MIPS32) += tlbex32-mips32.o
obj-$(CONFIG_CPU_MIPS64) += tlbex32-r4k.o
obj-$(CONFIG_CPU_SB1) += tlbex32-r4k.o
obj-$(CONFIG_CPU_TX39XX) += tlbex32-r3k.o
endif
ifdef CONFIG_MIPS64
obj-$(CONFIG_CPU_R4300) += tlb64-glue-r4k.o
obj-$(CONFIG_CPU_R4X00) += tlb64-glue-r4k.o
obj-$(CONFIG_CPU_R5000) += tlb64-glue-r4k.o
obj-$(CONFIG_CPU_NEVADA) += tlb64-glue-r4k.o
obj-$(CONFIG_CPU_R5432) += tlb64-glue-r4k.o
obj-$(CONFIG_CPU_RM7000) += tlb64-glue-r4k.o
obj-$(CONFIG_CPU_RM9000) += tlb64-glue-r4k.o
obj-$(CONFIG_CPU_R10000) += tlb64-glue-r4k.o
obj-$(CONFIG_CPU_SB1) += tlb64-glue-sb1.o
obj-$(CONFIG_CPU_MIPS64) += tlb64-glue-r4k.o
endif
obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o
obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o
obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o
......@@ -68,8 +34,11 @@ obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o
#
# Choose one DMA coherency model
#
ifndef CONFIG_OWN_DMA
obj-$(CONFIG_DMA_COHERENT) += dma-coherent.o
obj-$(CONFIG_DMA_NONCOHERENT) += dma-noncoherent.o
endif
obj-$(CONFIG_DMA_IP27) += dma-ip27.o
obj-$(CONFIG_DMA_IP32) += dma-ip32.o
EXTRA_AFLAGS := $(CFLAGS)
......@@ -238,6 +238,22 @@ static inline void r4k_blast_scache_page_setup(void)
r4k_blast_scache_page = blast_scache128_page;
}
static void (* r4k_blast_scache_page_indexed)(unsigned long addr);
static inline void r4k_blast_scache_page_indexed_setup(void)
{
unsigned long sc_lsize = cpu_scache_line_size();
if (sc_lsize == 16)
r4k_blast_scache_page_indexed = blast_scache16_page_indexed;
else if (sc_lsize == 32)
r4k_blast_scache_page_indexed = blast_scache32_page_indexed;
else if (sc_lsize == 64)
r4k_blast_scache_page_indexed = blast_scache64_page_indexed;
else if (sc_lsize == 128)
r4k_blast_scache_page_indexed = blast_scache128_page_indexed;
}
static void (* r4k_blast_scache)(void);
static inline void r4k_blast_scache_setup(void)
......@@ -318,9 +334,6 @@ static inline void local_r4k_flush_cache_mm(void * args)
{
struct mm_struct *mm = args;
if (!cpu_has_dc_aliases)
return;
if (!cpu_context(smp_processor_id(), mm))
return;
......@@ -340,6 +353,9 @@ static inline void local_r4k_flush_cache_mm(void * args)
static void r4k_flush_cache_mm(struct mm_struct *mm)
{
if (!cpu_has_dc_aliases)
return;
on_each_cpu(local_r4k_flush_cache_mm, mm, 1, 1);
}
......@@ -359,13 +375,6 @@ static inline void local_r4k_flush_cache_page(void *args)
pmd_t *pmdp;
pte_t *ptep;
/*
* If ownes no valid ASID yet, cannot possibly have gotten
* this page into the cache.
*/
if (cpu_context(smp_processor_id(), mm) == 0)
return;
page &= PAGE_MASK;
pgdp = pgd_offset(mm, page);
pmdp = pmd_offset(pgdp, page);
......@@ -385,8 +394,11 @@ static inline void local_r4k_flush_cache_page(void *args)
* in that case, which doesn't overly flush the cache too much.
*/
if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) {
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc))
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
r4k_blast_dcache_page(page);
if (exec && !cpu_icache_snoops_remote_store)
r4k_blast_scache_page(page);
}
if (exec)
r4k_blast_icache_page(page);
......@@ -398,8 +410,11 @@ static inline void local_r4k_flush_cache_page(void *args)
* to work correctly.
*/
page = INDEX_BASE + (page & (dcache_size - 1));
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc))
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
r4k_blast_dcache_page_indexed(page);
if (exec && !cpu_icache_snoops_remote_store)
r4k_blast_scache_page_indexed(page);
}
if (exec) {
if (cpu_has_vtag_icache) {
int cpu = smp_processor_id();
......@@ -416,6 +431,13 @@ static void r4k_flush_cache_page(struct vm_area_struct *vma,
{
struct flush_cache_page_args args;
/*
* If ownes no valid ASID yet, cannot possibly have gotten
* this page into the cache.
*/
if (cpu_context(smp_processor_id(), vma->vm_mm) == 0)
return;
args.vma = vma;
args.page = page;
......@@ -442,14 +464,15 @@ static inline void local_r4k_flush_icache_range(void *args)
struct flush_icache_range_args *fir_args = args;
unsigned long dc_lsize = current_cpu_data.dcache.linesz;
unsigned long ic_lsize = current_cpu_data.icache.linesz;
unsigned long sc_lsize = current_cpu_data.scache.linesz;
unsigned long start = fir_args->start;
unsigned long end = fir_args->end;
unsigned long addr, aend;
if (!cpu_has_ic_fills_f_dc) {
if (end - start > dcache_size)
if (end - start > dcache_size) {
r4k_blast_dcache();
else {
} else {
addr = start & ~(dc_lsize - 1);
aend = (end - 1) & ~(dc_lsize - 1);
......@@ -461,6 +484,23 @@ static inline void local_r4k_flush_icache_range(void *args)
addr += dc_lsize;
}
}
if (!cpu_icache_snoops_remote_store) {
if (end - start > scache_size) {
r4k_blast_scache();
} else {
addr = start & ~(sc_lsize - 1);
aend = (end - 1) & ~(sc_lsize - 1);
while (1) {
/* Hit_Writeback_Inv_D */
protected_writeback_scache_line(addr);
if (addr == aend)
break;
addr += sc_lsize;
}
}
}
}
if (end - start > icache_size)
......@@ -527,6 +567,8 @@ static inline void local_r4k_flush_icache_page(void *args)
if (!cpu_has_ic_fills_f_dc) {
unsigned long addr = (unsigned long) page_address(page);
r4k_blast_dcache_page(addr);
if (!cpu_icache_snoops_remote_store)
r4k_blast_scache_page(addr);
ClearPageDcacheDirty(page);
}
......@@ -669,10 +711,13 @@ static void local_r4k_flush_cache_sigtramp(void * arg)
{
unsigned long ic_lsize = current_cpu_data.icache.linesz;
unsigned long dc_lsize = current_cpu_data.dcache.linesz;
unsigned long sc_lsize = current_cpu_data.scache.linesz;
unsigned long addr = (unsigned long) arg;
R4600_HIT_CACHEOP_WAR_IMPL;
protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
if (!cpu_icache_snoops_remote_store)
protected_writeback_scache_line(addr & ~(sc_lsize - 1));
protected_flush_icache_line(addr & ~(ic_lsize - 1));
if (MIPS4K_ICACHE_REFILL_WAR) {
__asm__ __volatile__ (
......@@ -739,8 +784,8 @@ static inline void rm7k_erratum31(void)
}
}
static char *way_string[] = { NULL, "direct mapped", "2-way", "3-way", "4-way",
"5-way", "6-way", "7-way", "8-way"
static char *way_string[] __initdata = { NULL, "direct mapped", "2-way",
"3-way", "4-way", "5-way", "6-way", "7-way", "8-way"
};
static void __init probe_pcache(void)
......@@ -1178,6 +1223,7 @@ void __init ld_mmu_r4xx0(void)
r4k_blast_icache_page_indexed_setup();
r4k_blast_icache_setup();
r4k_blast_scache_page_setup();
r4k_blast_scache_page_indexed_setup();
r4k_blast_scache_setup();
/*
......
......@@ -503,7 +503,7 @@ void ld_mmu_sb1(void)
/* Special cache error handler for SB1 */
memcpy((void *)(CAC_BASE + 0x100), &except_vec2_sb1, 0x80);
memcpy((void *)(UNCAC_BASE + 0x100), &except_vec2_sb1, 0x80);
memcpy((void *)KSEG1ADDR(&handle_vec2_sb1), &handle_vec2_sb1, 0x80);
memcpy((void *)CKSEG1ADDR(&handle_vec2_sb1), &handle_vec2_sb1, 0x80);
probe_cache_sizes();
......
......@@ -45,10 +45,17 @@ EXPORT_SYMBOL(_dma_cache_inv);
#endif /* CONFIG_DMA_NONCOHERENT */
asmlinkage int sys_cacheflush(void *addr, int bytes, int cache)
/*
* We could optimize the case where the cache argument is not BCACHE but
* that seems very atypical use ...
*/
asmlinkage int sys_cacheflush(unsigned long addr, unsigned long int bytes,
unsigned int cache)
{
/* This should flush more selectivly ... */
__flush_cache_all();
if (verify_area(VERIFY_WRITE, (void *) addr, bytes))
return -EFAULT;
flush_icache_range(addr, addr + bytes);
return 0;
}
......
......@@ -251,14 +251,14 @@ static const uint8_t parity[256] = {
/* Masks to select bits for Hamming parity, mask_72_64[i] for bit[i] */
static const uint64_t mask_72_64[8] = {
0x0738C808099264FFL,
0x38C808099264FF07L,
0xC808099264FF0738L,
0x08099264FF0738C8L,
0x099264FF0738C808L,
0x9264FF0738C80809L,
0x64FF0738C8080992L,
0xFF0738C808099264L
0x0738C808099264FFULL,
0x38C808099264FF07ULL,
0xC808099264FF0738ULL,
0x08099264FF0738C8ULL,
0x099264FF0738C808ULL,
0x9264FF0738C80809ULL,
0x64FF0738C8080992ULL,
0xFF0738C808099264ULL
};
/* Calculate the parity on a range of bits */
......@@ -330,9 +330,9 @@ static uint32_t extract_ic(unsigned short addr, int data)
((lru >> 4) & 0x3),
((lru >> 6) & 0x3));
}
va = (taglo & 0xC0000FFFFFFFE000) | addr;
va = (taglo & 0xC0000FFFFFFFE000ULL) | addr;
if ((taglo & (1 << 31)) && (((taglo >> 62) & 0x3) == 3))
va |= 0x3FFFF00000000000;
va |= 0x3FFFF00000000000ULL;
valid = ((taghi >> 29) & 1);
if (valid) {
tlo_tmp = taglo & 0xfff3ff;
......@@ -473,7 +473,7 @@ static uint32_t extract_dc(unsigned short addr, int data)
: "r" ((way << 13) | addr));
taglo = ((unsigned long long)taglohi << 32) | taglolo;
pa = (taglo & 0xFFFFFFE000) | addr;
pa = (taglo & 0xFFFFFFE000ULL) | addr;
if (way == 0) {
lru = (taghi >> 14) & 0xff;
prom_printf("[Bank %d Set 0x%02x] LRU > %d %d %d %d > MRU\n",
......
......@@ -15,7 +15,6 @@
* 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/config.h>
#include <linux/init.h>
#include <asm/asm.h>
......
/*
* 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) 2000 Ani Joshi <ajoshi@unixbox.com>
* Copyright (C) 2000, 2001 Ralf Baechle <ralf@gnu.org>
* Copyright (C) 2005 Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com>
* swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
* IP32 changes by Ilya.
*/
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/dma-mapping.h>
#include <asm/cache.h>
#include <asm/io.h>
#include <asm/ip32/crime.h>
/*
* Warning on the terminology - Linux calls an uncached area coherent;
* MIPS terminology calls memory areas with hardware maintained coherency
* coherent.
*/
/*
* Few notes.
* 1. CPU sees memory as two chunks: 0-256M@0x0, and the rest @0x40000000+256M
* 2. PCI sees memory as one big chunk @0x0 (or we could use 0x40000000 for native-endian)
* 3. All other devices see memory as one big chunk at 0x40000000
* 4. Non-PCI devices will pass NULL as struct device*
* Thus we translate differently, depending on device.
*/
#define RAM_OFFSET_MASK 0x3fffffff
void *dma_alloc_noncoherent(struct device *dev, size_t size,
dma_addr_t * dma_handle, int gfp)
{
void *ret;
/* ignore region specifiers */
gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
gfp |= GFP_DMA;
ret = (void *) __get_free_pages(gfp, get_order(size));
if (ret != NULL) {
unsigned long addr = virt_to_phys(ret)&RAM_OFFSET_MASK;
memset(ret, 0, size);
if(dev==NULL)
addr+= CRIME_HI_MEM_BASE;
*dma_handle = addr;
}
return ret;
}
EXPORT_SYMBOL(dma_alloc_noncoherent);
void *dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t * dma_handle, int gfp)
{
void *ret;
ret = dma_alloc_noncoherent(dev, size, dma_handle, gfp);
if (ret) {
dma_cache_wback_inv((unsigned long) ret, size);
ret = UNCAC_ADDR(ret);
}
return ret;
}
EXPORT_SYMBOL(dma_alloc_coherent);
void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
dma_addr_t dma_handle)
{
free_pages((unsigned long) vaddr, get_order(size));
}
EXPORT_SYMBOL(dma_free_noncoherent);
void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
dma_addr_t dma_handle)
{
unsigned long addr = (unsigned long) vaddr;
addr = CAC_ADDR(addr);
free_pages(addr, get_order(size));
}
EXPORT_SYMBOL(dma_free_coherent);
static inline void __dma_sync(unsigned long addr, size_t size,
enum dma_data_direction direction)
{
switch (direction) {
case DMA_TO_DEVICE:
dma_cache_wback(addr, size);
break;
case DMA_FROM_DEVICE:
dma_cache_inv(addr, size);
break;
case DMA_BIDIRECTIONAL:
dma_cache_wback_inv(addr, size);
break;
default:
BUG();
}
}
dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
enum dma_data_direction direction)
{
unsigned long addr = (unsigned long) ptr;
switch (direction) {
case DMA_TO_DEVICE:
dma_cache_wback(addr, size);
break;
case DMA_FROM_DEVICE:
dma_cache_inv(addr, size);
break;
case DMA_BIDIRECTIONAL:
dma_cache_wback_inv(addr, size);
break;
default:
BUG();
}
addr = virt_to_phys(ptr)&RAM_OFFSET_MASK;;
if(dev == NULL)
addr+=CRIME_HI_MEM_BASE;
return (dma_addr_t)addr;
}
EXPORT_SYMBOL(dma_map_single);
void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
enum dma_data_direction direction)
{
switch (direction) {
case DMA_TO_DEVICE:
break;
case DMA_FROM_DEVICE:
break;
case DMA_BIDIRECTIONAL:
break;
default:
BUG();
}
}
EXPORT_SYMBOL(dma_unmap_single);
int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction direction)
{
int i;
BUG_ON(direction == DMA_NONE);
for (i = 0; i < nents; i++, sg++) {
unsigned long addr;
addr = (unsigned long) page_address(sg->page)+sg->offset;
if (addr)
__dma_sync(addr, sg->length, direction);
addr = __pa(addr)&RAM_OFFSET_MASK;;
if(dev == NULL)
addr += CRIME_HI_MEM_BASE;
sg->dma_address = (dma_addr_t)addr;
}
return nents;
}
EXPORT_SYMBOL(dma_map_sg);
dma_addr_t dma_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size, enum dma_data_direction direction)
{
unsigned long addr;
BUG_ON(direction == DMA_NONE);
addr = (unsigned long) page_address(page) + offset;
dma_cache_wback_inv(addr, size);
addr = __pa(addr)&RAM_OFFSET_MASK;;
if(dev == NULL)
addr += CRIME_HI_MEM_BASE;
return (dma_addr_t)addr;
}
EXPORT_SYMBOL(dma_map_page);
void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
enum dma_data_direction direction)
{
BUG_ON(direction == DMA_NONE);
if (direction != DMA_TO_DEVICE) {
unsigned long addr;
dma_address&=RAM_OFFSET_MASK;
addr = dma_address + PAGE_OFFSET;
if(dma_address>=256*1024*1024)
addr+=CRIME_HI_MEM_BASE;
dma_cache_wback_inv(addr, size);
}
}
EXPORT_SYMBOL(dma_unmap_page);
void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
enum dma_data_direction direction)
{
unsigned long addr;
int i;
BUG_ON(direction == DMA_NONE);
if (direction == DMA_TO_DEVICE)
return;
for (i = 0; i < nhwentries; i++, sg++) {
addr = (unsigned long) page_address(sg->page);
if (!addr)
continue;
dma_cache_wback_inv(addr + sg->offset, sg->length);
}
}
EXPORT_SYMBOL(dma_unmap_sg);
void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
size_t size, enum dma_data_direction direction)
{
unsigned long addr;
BUG_ON(direction == DMA_NONE);
dma_handle&=RAM_OFFSET_MASK;
addr = dma_handle + PAGE_OFFSET;
if(dma_handle>=256*1024*1024)
addr+=CRIME_HI_MEM_BASE;
__dma_sync(addr, size, direction);
}
EXPORT_SYMBOL(dma_sync_single_for_cpu);
void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
size_t size, enum dma_data_direction direction)
{
unsigned long addr;
BUG_ON(direction == DMA_NONE);
dma_handle&=RAM_OFFSET_MASK;
addr = dma_handle + PAGE_OFFSET;
if(dma_handle>=256*1024*1024)
addr+=CRIME_HI_MEM_BASE;
__dma_sync(addr, size, direction);
}
EXPORT_SYMBOL(dma_sync_single_for_device);
void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
unsigned long offset, size_t size, enum dma_data_direction direction)
{
unsigned long addr;
BUG_ON(direction == DMA_NONE);
dma_handle&=RAM_OFFSET_MASK;
addr = dma_handle + offset + PAGE_OFFSET;
if(dma_handle>=256*1024*1024)
addr+=CRIME_HI_MEM_BASE;
__dma_sync(addr, size, direction);
}
EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
unsigned long offset, size_t size, enum dma_data_direction direction)
{
unsigned long addr;
BUG_ON(direction == DMA_NONE);
dma_handle&=RAM_OFFSET_MASK;
addr = dma_handle + offset + PAGE_OFFSET;
if(dma_handle>=256*1024*1024)
addr+=CRIME_HI_MEM_BASE;
__dma_sync(addr, size, direction);
}
EXPORT_SYMBOL(dma_sync_single_range_for_device);
void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
enum dma_data_direction direction)
{
int i;
BUG_ON(direction == DMA_NONE);
/* Make sure that gcc doesn't leave the empty loop body. */
for (i = 0; i < nelems; i++, sg++)
__dma_sync((unsigned long)page_address(sg->page),
sg->length, direction);
}
EXPORT_SYMBOL(dma_sync_sg_for_cpu);
void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
enum dma_data_direction direction)
{
int i;
BUG_ON(direction == DMA_NONE);
/* Make sure that gcc doesn't leave the empty loop body. */
for (i = 0; i < nelems; i++, sg++)
__dma_sync((unsigned long)page_address(sg->page),
sg->length, direction);
}
EXPORT_SYMBOL(dma_sync_sg_for_device);
int dma_mapping_error(dma_addr_t dma_addr)
{
return 0;
}
EXPORT_SYMBOL(dma_mapping_error);
int dma_supported(struct device *dev, u64 mask)
{
/*
* we fall back to GFP_DMA when the mask isn't all 1s,
* so we can't guarantee allocations that must be
* within a tighter range than GFP_DMA..
*/
if (mask < 0x00ffffff)
return 0;
return 1;
}
EXPORT_SYMBOL(dma_supported);
int dma_is_consistent(dma_addr_t dma_addr)
{
return 1;
}
EXPORT_SYMBOL(dma_is_consistent);
void dma_cache_sync(void *vaddr, size_t size, enum dma_data_direction direction)
{
if (direction == DMA_NONE)
return;
dma_cache_wback_inv((unsigned long)vaddr, size);
}
EXPORT_SYMBOL(dma_cache_sync);
......@@ -61,7 +61,7 @@ unsigned long setup_zero_pages(void)
else
order = 0;
empty_zero_page = __get_free_pages(GFP_KERNEL, order);
empty_zero_page = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
if (!empty_zero_page)
panic("Oh boy, that early out of memory?");
......@@ -74,7 +74,6 @@ unsigned long setup_zero_pages(void)
size = PAGE_SIZE << order;
zero_page_mask = (size - 1) & PAGE_MASK;
memset((void *)empty_zero_page, 0, size);
return 1UL << order;
}
......
......@@ -3,9 +3,8 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org)
* Copyright (C) 2003, 04, 05 Ralf Baechle (ralf@linux-mips.org)
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
......@@ -57,12 +56,6 @@ void copy_page(void *to, void *from) __attribute__((alias("copy_page_array")));
EXPORT_SYMBOL(copy_page);
/*
* An address fits into a single register so it's safe to use 64-bit registers
* if we have 64-bit adresses.
*/
#define cpu_has_64bit_registers cpu_has_64bit_addresses
/*
* This is suboptimal for 32-bit kernels; we assume that R10000 is only used
* with 64-bit kernels. The prefetch offsets have been experimentally tuned
......@@ -145,7 +138,7 @@ static inline void __build_load_reg(int reg)
union mips_instruction mi;
unsigned int width;
if (cpu_has_64bit_registers) {
if (cpu_has_64bit_gp_regs) {
mi.i_format.opcode = ld_op;
width = 8;
} else {
......@@ -266,7 +259,7 @@ static inline void build_addiu_a2_a0(unsigned long offset)
BUG_ON(offset > 0x7fff);
mi.i_format.opcode = cpu_has_64bit_addresses ? daddiu_op : addiu_op;
mi.i_format.opcode = cpu_has_64bit_gp_regs ? daddiu_op : addiu_op;
mi.i_format.rs = 4; /* $a0 */
mi.i_format.rt = 6; /* $a2 */
mi.i_format.simmediate = offset;
......@@ -280,7 +273,7 @@ static inline void build_addiu_a1(unsigned long offset)
BUG_ON(offset > 0x7fff);
mi.i_format.opcode = cpu_has_64bit_addresses ? daddiu_op : addiu_op;
mi.i_format.opcode = cpu_has_64bit_gp_regs ? daddiu_op : addiu_op;
mi.i_format.rs = 5; /* $a1 */
mi.i_format.rt = 5; /* $a1 */
mi.i_format.simmediate = offset;
......@@ -296,7 +289,7 @@ static inline void build_addiu_a0(unsigned long offset)
BUG_ON(offset > 0x7fff);
mi.i_format.opcode = cpu_has_64bit_addresses ? daddiu_op : addiu_op;
mi.i_format.opcode = cpu_has_64bit_gp_regs ? daddiu_op : addiu_op;
mi.i_format.rs = 4; /* $a0 */
mi.i_format.rt = 4; /* $a0 */
mi.i_format.simmediate = offset;
......
......@@ -2,6 +2,7 @@
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
* Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org)
* Copyright (C) 2000 SiByte, Inc.
* Copyright (C) 2005 Thiemo Seufer
*
* Written by Justin Carlson of SiByte, Inc.
* and Kip Walker of Broadcom Corp.
......@@ -39,11 +40,7 @@
#define SB1_PREF_STORE_STREAMED_HINT "5"
#endif
#ifdef CONFIG_SIBYTE_DMA_PAGEOPS
static inline void clear_page_cpu(void *page)
#else
void clear_page(void *page)
#endif
{
unsigned char *addr = (unsigned char *) page;
unsigned char *end = addr + PAGE_SIZE;
......@@ -57,90 +54,143 @@ void clear_page(void *page)
* since we know we're on an SB1, we force the assembler to take
* 64-bit operands to speed things up
*/
do {
__asm__ __volatile__(
" .set push \n"
" .set mips4 \n"
" .set noreorder \n"
#ifdef CONFIG_CPU_HAS_PREFETCH
" pref " SB1_PREF_STORE_STREAMED_HINT ", 0(%0) \n" /* Prefetch the first 4 lines */
" pref " SB1_PREF_STORE_STREAMED_HINT ", 32(%0) \n"
" pref " SB1_PREF_STORE_STREAMED_HINT ", 64(%0) \n"
" pref " SB1_PREF_STORE_STREAMED_HINT ", 96(%0) \n"
" daddiu %0, %0, 128 \n"
" pref " SB1_PREF_STORE_STREAMED_HINT ", -128(%0) \n" /* Prefetch the first 4 lines */
" pref " SB1_PREF_STORE_STREAMED_HINT ", -96(%0) \n"
" pref " SB1_PREF_STORE_STREAMED_HINT ", -64(%0) \n"
" pref " SB1_PREF_STORE_STREAMED_HINT ", -32(%0) \n"
"1: sd $0, -128(%0) \n" /* Throw out a cacheline of 0's */
" sd $0, -120(%0) \n"
" sd $0, -112(%0) \n"
" sd $0, -104(%0) \n"
" daddiu %0, %0, 32 \n"
" bnel %0, %1, 1b \n"
" pref " SB1_PREF_STORE_STREAMED_HINT ", -32(%0) \n"
" daddiu %0, %0, -128 \n"
#endif
"1: sd $0, 0(%0) \n" /* Throw out a cacheline of 0's */
" sd $0, 8(%0) \n"
" sd $0, 0(%0) \n" /* Throw out a cacheline of 0's */
"1: sd $0, 8(%0) \n"
" sd $0, 16(%0) \n"
" sd $0, 24(%0) \n"
#ifdef CONFIG_CPU_HAS_PREFETCH
" pref " SB1_PREF_STORE_STREAMED_HINT ",128(%0) \n" /* Prefetch 4 lines ahead */
#endif
" .set mips0 \n"
:
: "r" (addr)
" daddiu %0, %0, 32 \n"
" bnel %0, %1, 1b \n"
" sd $0, 0(%0) \n"
" .set pop \n"
: "+r" (addr)
: "r" (end)
: "memory");
addr += 32;
} while (addr != end);
}
#ifdef CONFIG_SIBYTE_DMA_PAGEOPS
static inline void copy_page_cpu(void *to, void *from)
#else
void copy_page(void *to, void *from)
#endif
{
unsigned char *src = from;
unsigned char *dst = to;
unsigned char *src = (unsigned char *)from;
unsigned char *dst = (unsigned char *)to;
unsigned char *end = src + PAGE_SIZE;
/*
* This should be optimized in assembly...can't use ld/sd, though,
* because the top 32 bits could be nuked if we took an interrupt
* during the routine. And this is not a good place to be cli()'ing
*
* The pref's used here are using "streaming" hints, which cause the
* copied data to be kicked out of the cache sooner. A page copy often
* ends up copying a lot more data than is commonly used, so this seems
* to make sense in terms of reducing cache pollution, but I've no real
* performance data to back this up
*/
do {
__asm__ __volatile__(
" .set push \n"
" .set mips4 \n"
" .set noreorder \n"
#ifdef CONFIG_CPU_HAS_PREFETCH
" pref " SB1_PREF_LOAD_STREAMED_HINT ", 0(%0)\n" /* Prefetch the first 3 lines */
" pref " SB1_PREF_STORE_STREAMED_HINT ", 0(%1)\n"
" pref " SB1_PREF_LOAD_STREAMED_HINT ", 32(%0)\n"
" pref " SB1_PREF_STORE_STREAMED_HINT ", 32(%1)\n"
" pref " SB1_PREF_LOAD_STREAMED_HINT ", 64(%0)\n"
" pref " SB1_PREF_STORE_STREAMED_HINT ", 64(%1)\n"
#endif
"1: lw $2, 0(%0) \n" /* Block copy a cacheline */
" lw $3, 4(%0) \n"
" lw $4, 8(%0) \n"
" lw $5, 12(%0) \n"
" lw $6, 16(%0) \n"
" lw $7, 20(%0) \n"
" lw $8, 24(%0) \n"
" lw $9, 28(%0) \n"
#ifdef CONFIG_CPU_HAS_PREFETCH
" pref " SB1_PREF_LOAD_STREAMED_HINT ", 96(%0) \n" /* Prefetch ahead */
" pref " SB1_PREF_STORE_STREAMED_HINT ", 96(%1) \n"
" daddiu %0, %0, 128 \n"
" daddiu %1, %1, 128 \n"
" pref " SB1_PREF_LOAD_STREAMED_HINT ", -128(%0)\n" /* Prefetch the first 4 lines */
" pref " SB1_PREF_STORE_STREAMED_HINT ", -128(%1)\n"
" pref " SB1_PREF_LOAD_STREAMED_HINT ", -96(%0)\n"
" pref " SB1_PREF_STORE_STREAMED_HINT ", -96(%1)\n"
" pref " SB1_PREF_LOAD_STREAMED_HINT ", -64(%0)\n"
" pref " SB1_PREF_STORE_STREAMED_HINT ", -64(%1)\n"
" pref " SB1_PREF_LOAD_STREAMED_HINT ", -32(%0)\n"
"1: pref " SB1_PREF_STORE_STREAMED_HINT ", -32(%1)\n"
# ifdef CONFIG_MIPS64
" ld $8, -128(%0) \n" /* Block copy a cacheline */
" ld $9, -120(%0) \n"
" ld $10, -112(%0) \n"
" ld $11, -104(%0) \n"
" sd $8, -128(%1) \n"
" sd $9, -120(%1) \n"
" sd $10, -112(%1) \n"
" sd $11, -104(%1) \n"
# else
" lw $2, -128(%0) \n" /* Block copy a cacheline */
" lw $3, -124(%0) \n"
" lw $6, -120(%0) \n"
" lw $7, -116(%0) \n"
" lw $8, -112(%0) \n"
" lw $9, -108(%0) \n"
" lw $10, -104(%0) \n"
" lw $11, -100(%0) \n"
" sw $2, -128(%1) \n"
" sw $3, -124(%1) \n"
" sw $6, -120(%1) \n"
" sw $7, -116(%1) \n"
" sw $8, -112(%1) \n"
" sw $9, -108(%1) \n"
" sw $10, -104(%1) \n"
" sw $11, -100(%1) \n"
# endif
" daddiu %0, %0, 32 \n"
" daddiu %1, %1, 32 \n"
" bnel %0, %2, 1b \n"
" pref " SB1_PREF_LOAD_STREAMED_HINT ", -32(%0)\n"
" daddiu %0, %0, -128 \n"
" daddiu %1, %1, -128 \n"
#endif
#ifdef CONFIG_MIPS64
" ld $8, 0(%0) \n" /* Block copy a cacheline */
"1: ld $9, 8(%0) \n"
" ld $10, 16(%0) \n"
" ld $11, 24(%0) \n"
" sd $8, 0(%1) \n"
" sd $9, 8(%1) \n"
" sd $10, 16(%1) \n"
" sd $11, 24(%1) \n"
#else
" lw $2, 0(%0) \n" /* Block copy a cacheline */
"1: lw $3, 4(%0) \n"
" lw $6, 8(%0) \n"
" lw $7, 12(%0) \n"
" lw $8, 16(%0) \n"
" lw $9, 20(%0) \n"
" lw $10, 24(%0) \n"
" lw $11, 28(%0) \n"
" sw $2, 0(%1) \n"
" sw $3, 4(%1) \n"
" sw $4, 8(%1) \n"
" sw $5, 12(%1) \n"
" sw $6, 16(%1) \n"
" sw $7, 20(%1) \n"
" sw $8, 24(%1) \n"
" sw $9, 28(%1) \n"
" .set mips0 \n"
:
: "r" (src), "r" (dst)
: "$2","$3","$4","$5","$6","$7","$8","$9","memory");
src += 32;
dst += 32;
} while (src != end);
" sw $6, 8(%1) \n"
" sw $7, 12(%1) \n"
" sw $8, 16(%1) \n"
" sw $9, 20(%1) \n"
" sw $10, 24(%1) \n"
" sw $11, 28(%1) \n"
#endif
" daddiu %0, %0, 32 \n"
" daddiu %1, %1, 32 \n"
" bnel %0, %2, 1b \n"
#ifdef CONFIG_MIPS64
" ld $8, 0(%0) \n"
#else
" lw $2, 0(%0) \n"
#endif
" .set pop \n"
: "+r" (src), "+r" (dst)
: "r" (end)
#ifdef CONFIG_MIPS64
: "$8","$9","$10","$11","memory");
#else
: "$2","$3","$6","$7","$8","$9","$10","$11","memory");
#endif
}
......@@ -151,10 +201,10 @@ void copy_page(void *to, void *from)
* particular CPU.
*/
typedef struct dmadscr_s {
uint64_t dscr_a;
uint64_t dscr_b;
uint64_t pad_a;
uint64_t pad_b;
u64 dscr_a;
u64 dscr_b;
u64 pad_a;
u64 pad_b;
} dmadscr_t;
static dmadscr_t page_descr[NR_CPUS] __attribute__((aligned(SMP_CACHE_BYTES)));
......@@ -162,14 +212,14 @@ static dmadscr_t page_descr[NR_CPUS] __attribute__((aligned(SMP_CACHE_BYTES)));
void sb1_dma_init(void)
{
int cpu = smp_processor_id();
uint64_t base_val = PHYSADDR(&page_descr[cpu]) | V_DM_DSCR_BASE_RINGSZ(1);
__raw_writeq(base_val,
IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
__raw_writeq(base_val | M_DM_DSCR_BASE_RESET,
IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
__raw_writeq(base_val | M_DM_DSCR_BASE_ENABL,
IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
u64 base_val = CPHYSADDR(&page_descr[cpu]) | V_DM_DSCR_BASE_RINGSZ(1);
bus_writeq(base_val,
(void *)IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
bus_writeq(base_val | M_DM_DSCR_BASE_RESET,
(void *)IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
bus_writeq(base_val | M_DM_DSCR_BASE_ENABL,
(void *)IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
}
void clear_page(void *page)
......@@ -177,46 +227,61 @@ void clear_page(void *page)
int cpu = smp_processor_id();
/* if the page is above Kseg0, use old way */
if (KSEGX(page) != CAC_BASE)
if ((long)KSEGX(page) != (long)CKSEG0)
return clear_page_cpu(page);
page_descr[cpu].dscr_a = PHYSADDR(page) | M_DM_DSCRA_ZERO_MEM | M_DM_DSCRA_L2C_DEST | M_DM_DSCRA_INTERRUPT;
page_descr[cpu].dscr_a = CPHYSADDR(page) | M_DM_DSCRA_ZERO_MEM | M_DM_DSCRA_L2C_DEST | M_DM_DSCRA_INTERRUPT;
page_descr[cpu].dscr_b = V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE);
__raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT)));
bus_writeq(1, (void *)IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT)));
/*
* Don't really want to do it this way, but there's no
* reliable way to delay completion detection.
*/
while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG)) & M_DM_DSCR_BASE_INTERRUPT)))
while (!(bus_readq((void *)(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG)) &
M_DM_DSCR_BASE_INTERRUPT))))
;
__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
bus_readq((void *)IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
}
void copy_page(void *to, void *from)
{
unsigned long from_phys = PHYSADDR(from);
unsigned long to_phys = PHYSADDR(to);
unsigned long from_phys = CPHYSADDR(from);
unsigned long to_phys = CPHYSADDR(to);
int cpu = smp_processor_id();
/* if either page is above Kseg0, use old way */
if ((KSEGX(to) != CAC_BASE) || (KSEGX(from) != CAC_BASE))
if ((long)KSEGX(to) != (long)CKSEG0
|| (long)KSEGX(from) != (long)CKSEG0)
return copy_page_cpu(to, from);
page_descr[cpu].dscr_a = PHYSADDR(to_phys) | M_DM_DSCRA_L2C_DEST | M_DM_DSCRA_INTERRUPT;
page_descr[cpu].dscr_b = PHYSADDR(from_phys) | V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE);
__raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT)));
page_descr[cpu].dscr_a = CPHYSADDR(to_phys) | M_DM_DSCRA_L2C_DEST | M_DM_DSCRA_INTERRUPT;
page_descr[cpu].dscr_b = CPHYSADDR(from_phys) | V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE);
bus_writeq(1, (void *)IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT)));
/*
* Don't really want to do it this way, but there's no
* reliable way to delay completion detection.
*/
while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG)) & M_DM_DSCR_BASE_INTERRUPT)))
while (!(bus_readq((void *)(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG)) &
M_DM_DSCR_BASE_INTERRUPT))))
;
__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
bus_readq((void *)IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
}
#endif
#else /* !CONFIG_SIBYTE_DMA_PAGEOPS */
void clear_page(void *page)
{
return clear_page_cpu(page);
}
void copy_page(void *to, void *from)
{
return copy_page_cpu(to, from);
}
#endif /* !CONFIG_SIBYTE_DMA_PAGEOPS */
EXPORT_SYMBOL(clear_page);
EXPORT_SYMBOL(copy_page);
......@@ -71,8 +71,8 @@ void __init pagetable_init(void)
/* Initialize the entire pgd. */
pgd_init((unsigned long)swapper_pg_dir);
pgd_init((unsigned long)swapper_pg_dir +
sizeof(pgd_t ) * USER_PTRS_PER_PGD);
pgd_init((unsigned long)swapper_pg_dir
+ sizeof(pgd_t) * USER_PTRS_PER_PGD);
#ifdef CONFIG_HIGHMEM
pgd_base = swapper_pg_dir;
......
......@@ -55,5 +55,4 @@ void __init pagetable_init(void)
/* Initialize the entire pgd. */
pgd_init((unsigned long)swapper_pg_dir);
pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table);
memset((void *)invalid_pte_table, 0, sizeof(pte_t) * PTRS_PER_PTE);
}
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/swap.h>
......
......@@ -96,13 +96,13 @@ static void rm7k_sc_inv(unsigned long addr, unsigned long size)
}
/*
* This function is executed in the uncached segment KSEG1.
* This function is executed in the uncached segment CKSEG1.
* It must not touch the stack, because the stack pointer still points
* into KSEG0.
* into CKSEG0.
*
* Three options:
* - Write it in assembly and guarantee that we don't use the stack.
* - Disable caching for KSEG0 before calling it.
* - Disable caching for CKSEG0 before calling it.
* - Pray that GCC doesn't randomly start using the stack.
*
* This being Linux, we obviously take the least sane of those options -
......
......@@ -7,7 +7,6 @@
* Copyright (C) 1999 Silicon Graphics, Inc.
* Copyright (C) 2000 Kanoj Sarcar (kanoj@sgi.com)
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
......
......@@ -17,7 +17,6 @@
* 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/config.h>
#include <linux/init.h>
#include <asm/mmu_context.h>
#include <asm/bootinfo.h>
......@@ -25,7 +24,7 @@
extern void build_tlb_refill_handler(void);
#define UNIQUE_ENTRYHI(idx) (KSEG0 + ((idx) << (PAGE_SHIFT + 1)))
#define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1)))
/* Dump the current entry* and pagemask registers */
static inline void dump_cur_tlb_regs(void)
......
/*
* 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) 1999 Ralf Baechle
* Copyright (C) 1999 Silicon Graphics, Inc.
*/
#include <linux/init.h>
#include <asm/mipsregs.h>
#include <asm/page.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#include <asm/war.h>
.macro __BUILD_cli
CLI
.endm
.macro __BUILD_sti
STI
.endm
.macro __BUILD_kmode
KMODE
.endm
.macro tlb_handler name interruptible writebit
NESTED(__\name, PT_SIZE, sp)
SAVE_ALL
dmfc0 a2, CP0_BADVADDR
__BUILD_\interruptible
li a1, \writebit
sd a2, PT_BVADDR(sp)
move a0, sp
jal do_page_fault
j ret_from_exception
END(__\name)
.endm
.macro tlb_handler_m3 name interruptible writebit
NESTED(__\name, PT_SIZE, sp)
dmfc0 k0, CP0_BADVADDR
dmfc0 k1, CP0_ENTRYHI
xor k0, k1
dsrl k0, k0, PAGE_SHIFT + 1
bnez k0, 1f
SAVE_ALL
dmfc0 a2, CP0_BADVADDR
__BUILD_\interruptible
li a1, \writebit
sd a2, PT_BVADDR(sp)
move a0, sp
jal do_page_fault
1:
j ret_from_exception
END(__\name)
.endm
tlb_handler xtlb_mod kmode 1
#if BCM1250_M3_WAR
tlb_handler_m3 xtlb_tlbl kmode 0
#else
tlb_handler xtlb_tlbl kmode 0
#endif
tlb_handler xtlb_tlbs kmode 1
......@@ -6,36 +6,23 @@
* Copyright (C) 1999 Ralf Baechle
* Copyright (C) 1999 Silicon Graphics, Inc.
*/
#include <linux/init.h>
#include <asm/mipsregs.h>
#include <asm/page.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
.macro __BUILD_cli
CLI
.endm
.macro __BUILD_sti
STI
.endm
.macro __BUILD_kmode
KMODE
.endm
.macro tlb_handler name interruptible writebit
NESTED(__\name, PT_SIZE, sp)
.macro tlb_do_page_fault, write
NESTED(tlb_do_page_fault_\write, PT_SIZE, sp)
SAVE_ALL
dmfc0 a2, CP0_BADVADDR
__BUILD_\interruptible
li a1, \writebit
sd a2, PT_BVADDR(sp)
MFC0 a2, CP0_BADVADDR
KMODE
move a0, sp
REG_S a2, PT_BVADDR(sp)
li a1, \write
jal do_page_fault
j ret_from_exception
END(__\name)
END(tlb_do_page_fault_\write)
.endm
tlb_handler xtlb_mod kmode 1
tlb_handler xtlb_tlbl kmode 0
tlb_handler xtlb_tlbs kmode 1
tlb_do_page_fault 0
tlb_do_page_fault 1
......@@ -5,7 +5,7 @@
*
* Synthesize TLB refill handlers at runtime.
*
* Copyright (C) 2004 by Thiemo Seufer
* Copyright (C) 2004,2005 by Thiemo Seufer
*/
#include <stdarg.h>
......@@ -19,11 +19,11 @@
#include <asm/pgtable.h>
#include <asm/cacheflush.h>
#include <asm/cacheflush.h>
#include <asm/mmu_context.h>
#include <asm/inst.h>
#include <asm/elf.h>
#include <asm/smp.h>
#include <asm/war.h>
/* #define DEBUG_TLB */
......@@ -44,6 +44,11 @@ static __init int __attribute__((unused)) bcm1250_m3_war(void)
return BCM1250_M3_WAR;
}
static __init int __attribute__((unused)) r10000_llsc_war(void)
{
return R10000_LLSC_WAR;
}
/*
* A little micro-assembler, intended for TLB refill handler
* synthesizing. It is intentionally kept simple, does only support
......@@ -84,13 +89,14 @@ enum fields
enum opcode {
insn_invalid,
insn_addu, insn_addiu, insn_and, insn_andi, insn_beq,
insn_bgez, insn_bgezl, insn_bltz, insn_bltzl, insn_bne,
insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0,
insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
insn_bne, insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0,
insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32,
insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, insn_ld,
insn_lui, insn_lw, insn_mfc0, insn_mtc0, insn_ori, insn_rfe,
insn_sd, insn_sll, insn_sra, insn_srl, insn_subu, insn_sw,
insn_tlbp, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori
insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, insn_mtc0,
insn_ori, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll,
insn_sra, insn_srl, insn_subu, insn_sw, insn_tlbp, insn_tlbwi,
insn_tlbwr, insn_xor, insn_xori
};
struct insn {
......@@ -114,6 +120,7 @@ static __initdata struct insn insn_table[] = {
{ insn_and, M(spec_op,0,0,0,0,and_op), RS | RT | RD },
{ insn_andi, M(andi_op,0,0,0,0,0), RS | RT | UIMM },
{ insn_beq, M(beq_op,0,0,0,0,0), RS | RT | BIMM },
{ insn_beql, M(beql_op,0,0,0,0,0), RS | RT | BIMM },
{ insn_bgez, M(bcond_op,0,bgez_op,0,0,0), RS | BIMM },
{ insn_bgezl, M(bcond_op,0,bgezl_op,0,0,0), RS | BIMM },
{ insn_bltz, M(bcond_op,0,bltz_op,0,0,0), RS | BIMM },
......@@ -134,12 +141,16 @@ static __initdata struct insn insn_table[] = {
{ insn_jal, M(jal_op,0,0,0,0,0), JIMM },
{ insn_jr, M(spec_op,0,0,0,0,jr_op), RS },
{ insn_ld, M(ld_op,0,0,0,0,0), RS | RT | SIMM },
{ insn_ll, M(ll_op,0,0,0,0,0), RS | RT | SIMM },
{ insn_lld, M(lld_op,0,0,0,0,0), RS | RT | SIMM },
{ insn_lui, M(lui_op,0,0,0,0,0), RT | SIMM },
{ insn_lw, M(lw_op,0,0,0,0,0), RS | RT | SIMM },
{ insn_mfc0, M(cop0_op,mfc_op,0,0,0,0), RT | RD },
{ insn_mtc0, M(cop0_op,mtc_op,0,0,0,0), RT | RD },
{ insn_ori, M(ori_op,0,0,0,0,0), RS | RT | UIMM },
{ insn_rfe, M(cop0_op,cop_op,0,0,0,rfe_op), 0 },
{ insn_sc, M(sc_op,0,0,0,0,0), RS | RT | SIMM },
{ insn_scd, M(scd_op,0,0,0,0,0), RS | RT | SIMM },
{ insn_sd, M(sd_op,0,0,0,0,0), RS | RT | SIMM },
{ insn_sll, M(spec_op,0,0,0,0,sll_op), RT | RD | RE },
{ insn_sra, M(spec_op,0,0,0,0,sra_op), RT | RD | RE },
......@@ -341,6 +352,7 @@ I_u3u1u2(_addu);
I_u2u1u3(_andi);
I_u3u1u2(_and);
I_u1u2s3(_beq);
I_u1u2s3(_beql);
I_u1s2(_bgez);
I_u1s2(_bgezl);
I_u1s2(_bltz);
......@@ -361,12 +373,16 @@ I_u1(_j);
I_u1(_jal);
I_u1(_jr);
I_u2s3u1(_ld);
I_u2s3u1(_ll);
I_u2s3u1(_lld);
I_u1s2(_lui);
I_u2s3u1(_lw);
I_u1u2(_mfc0);
I_u1u2(_mtc0);
I_u2u1u3(_ori);
I_0(_rfe);
I_u2s3u1(_sc);
I_u2s3u1(_scd);
I_u2s3u1(_sd);
I_u2u1u3(_sll);
I_u2u1u3(_sra);
......@@ -389,8 +405,14 @@ enum label_id {
label_leave,
label_vmalloc,
label_vmalloc_done,
label_tlbwr_hazard,
label_split
label_tlbw_hazard,
label_split,
label_nopage_tlbl,
label_nopage_tlbs,
label_nopage_tlbm,
label_smp_pgtable_change,
label_r3000_write_probe_fail,
label_r3000_write_probe_ok
};
struct label {
......@@ -416,8 +438,14 @@ L_LA(_second_part)
L_LA(_leave)
L_LA(_vmalloc)
L_LA(_vmalloc_done)
L_LA(_tlbwr_hazard)
L_LA(_tlbw_hazard)
L_LA(_split)
L_LA(_nopage_tlbl)
L_LA(_nopage_tlbs)
L_LA(_nopage_tlbm)
L_LA(_smp_pgtable_change)
L_LA(_r3000_write_probe_fail)
L_LA(_r3000_write_probe_ok)
/* convenience macros for instructions */
#ifdef CONFIG_MIPS64
......@@ -431,6 +459,8 @@ L_LA(_split)
# define i_ADDIU(buf, rs, rt, val) i_daddiu(buf, rs, rt, val)
# define i_ADDU(buf, rs, rt, rd) i_daddu(buf, rs, rt, rd)
# define i_SUBU(buf, rs, rt, rd) i_dsubu(buf, rs, rt, rd)
# define i_LL(buf, rs, rt, off) i_lld(buf, rs, rt, off)
# define i_SC(buf, rs, rt, off) i_scd(buf, rs, rt, off)
#else
# define i_LW(buf, rs, rt, off) i_lw(buf, rs, rt, off)
# define i_SW(buf, rs, rt, off) i_sw(buf, rs, rt, off)
......@@ -442,28 +472,33 @@ L_LA(_split)
# define i_ADDIU(buf, rs, rt, val) i_addiu(buf, rs, rt, val)
# define i_ADDU(buf, rs, rt, rd) i_addu(buf, rs, rt, rd)
# define i_SUBU(buf, rs, rt, rd) i_subu(buf, rs, rt, rd)
# define i_LL(buf, rs, rt, off) i_ll(buf, rs, rt, off)
# define i_SC(buf, rs, rt, off) i_sc(buf, rs, rt, off)
#endif
#define i_b(buf, off) i_beq(buf, 0, 0, off)
#define i_beqz(buf, rs, off) i_beq(buf, rs, 0, off)
#define i_beqzl(buf, rs, off) i_beql(buf, rs, 0, off)
#define i_bnez(buf, rs, off) i_bne(buf, rs, 0, off)
#define i_bnezl(buf, rs, off) i_bnel(buf, rs, 0, off)
#define i_move(buf, a, b) i_ADDU(buf, a, 0, b)
#define i_nop(buf) i_sll(buf, 0, 0, 0)
#define i_ssnop(buf) i_sll(buf, 0, 0, 1)
#define i_ehb(buf) i_sll(buf, 0, 0, 3)
#if CONFIG_MIPS64
static __init int in_compat_space_p(long addr)
#ifdef CONFIG_MIPS64
static __init int __attribute__((unused)) in_compat_space_p(long addr)
{
/* Is this address in 32bit compat space? */
return (((addr) & 0xffffffff00000000) == 0xffffffff00000000);
}
static __init int rel_highest(long val)
static __init int __attribute__((unused)) rel_highest(long val)
{
return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
}
static __init int rel_higher(long val)
static __init int __attribute__((unused)) rel_higher(long val)
{
return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
}
......@@ -550,22 +585,33 @@ static __init void resolve_relocs(struct reloc *rel, struct label *lab)
__resolve_relocs(rel, l);
}
static __init void copy_handler(struct reloc *rel, struct label *lab,
u32 *first, u32 *end, u32* target)
static __init void move_relocs(struct reloc *rel, u32 *first, u32 *end,
long off)
{
long off = (long)(target - first);
memcpy(target, first, (end - first) * sizeof(u32));
for (; rel->lab != label_invalid; rel++)
if (rel->addr >= first && rel->addr < end)
rel->addr += off;
}
static __init void move_labels(struct label *lab, u32 *first, u32 *end,
long off)
{
for (; lab->lab != label_invalid; lab++)
if (lab->addr >= first && lab->addr < end)
lab->addr += off;
}
static __init void copy_handler(struct reloc *rel, struct label *lab,
u32 *first, u32 *end, u32 *target)
{
long off = (long)(target - first);
memcpy(target, first, (end - first) * sizeof(u32));
move_relocs(rel, first, end, off);
move_labels(lab, first, end, off);
}
static __init int __attribute__((unused)) insn_has_bdelay(struct reloc *rel,
u32 *addr)
{
......@@ -594,6 +640,20 @@ static void __attribute__((unused)) il_b(u32 **p, struct reloc **r,
i_b(p, 0);
}
static void il_beqz(u32 **p, struct reloc **r, unsigned int reg,
enum label_id l)
{
r_mips_pc16(r, *p, l);
i_beqz(p, reg, 0);
}
static void __attribute__((unused))
il_beqzl(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)
{
r_mips_pc16(r, *p, l);
i_beqzl(p, reg, 0);
}
static void il_bnez(u32 **p, struct reloc **r, unsigned int reg,
enum label_id l)
{
......@@ -608,7 +668,7 @@ static void il_bgezl(u32 **p, struct reloc **r, unsigned int reg,
i_bgezl(p, reg, 0);
}
/* The only registers allowed in TLB handlers. */
/* The only general purpose registers allowed in TLB handlers. */
#define K0 26
#define K1 27
......@@ -642,7 +702,6 @@ static __initdata u32 tlb_handler[128];
static __initdata struct label labels[128];
static __initdata struct reloc relocs[128];
#ifdef CONFIG_MIPS32
/*
* The R3000 TLB handler is simple.
*/
......@@ -676,10 +735,11 @@ static void __init build_r3000_tlb_refill_handler(void)
panic("TLB refill handler space exceeded");
printk("Synthesized TLB handler (%u instructions).\n",
p - tlb_handler);
(unsigned int)(p - tlb_handler));
#ifdef DEBUG_TLB
{
int i;
for (i = 0; i < (p - tlb_handler); i++)
printk("%08x\n", tlb_handler[i]);
}
......@@ -688,7 +748,6 @@ static void __init build_r3000_tlb_refill_handler(void)
memcpy((void *)CAC_BASE, tlb_handler, 0x80);
flush_icache_range(CAC_BASE, CAC_BASE + 0x80);
}
#endif /* CONFIG_MIPS32 */
/*
* The R4000 TLB handler is much more complicated. We have two
......@@ -738,12 +797,22 @@ static __init void __attribute__((unused)) build_tlb_probe_entry(u32 **p)
}
/*
* Write random TLB entry, and care about the hazards from the
* preceeding mtc0 and for the following eret.
* Write random or indexed TLB entry, and care about the hazards from
* the preceeding mtc0 and for the following eret.
*/
static __init void build_tlb_write_random_entry(u32 **p, struct label **l,
struct reloc **r)
enum tlb_write_entry { tlb_random, tlb_indexed };
static __init void build_tlb_write_entry(u32 **p, struct label **l,
struct reloc **r,
enum tlb_write_entry wmode)
{
void(*tlbw)(u32 **) = NULL;
switch (wmode) {
case tlb_random: tlbw = i_tlbwr; break;
case tlb_indexed: tlbw = i_tlbwi; break;
}
switch (current_cpu_data.cputype) {
case CPU_R4000PC:
case CPU_R4000SC:
......@@ -753,11 +822,11 @@ static __init void build_tlb_write_random_entry(u32 **p, struct label **l,
case CPU_R4400MC:
/*
* This branch uses up a mtc0 hazard nop slot and saves
* two nops after the tlbwr.
* two nops after the tlbw instruction.
*/
il_bgezl(p, r, 0, label_tlbwr_hazard);
i_tlbwr(p);
l_tlbwr_hazard(l, *p);
il_bgezl(p, r, 0, label_tlbw_hazard);
tlbw(p);
l_tlbw_hazard(l, *p);
i_nop(p);
break;
......@@ -766,12 +835,13 @@ static __init void build_tlb_write_random_entry(u32 **p, struct label **l,
case CPU_R5000:
case CPU_R5000A:
case CPU_5KC:
case CPU_TX49XX:
case CPU_AU1000:
case CPU_AU1100:
case CPU_AU1500:
case CPU_AU1550:
i_nop(p);
i_tlbwr(p);
tlbw(p);
break;
case CPU_R10000:
......@@ -781,24 +851,32 @@ static __init void build_tlb_write_random_entry(u32 **p, struct label **l,
case CPU_4KSC:
case CPU_20KC:
case CPU_25KF:
i_tlbwr(p);
tlbw(p);
break;
case CPU_NEVADA:
i_nop(p); /* QED specifies 2 nops hazard */
/*
* This branch uses up a mtc0 hazard nop slot and saves
* a nop after the tlbwr.
* a nop after the tlbw instruction.
*/
il_bgezl(p, r, 0, label_tlbwr_hazard);
i_tlbwr(p);
l_tlbwr_hazard(l, *p);
il_bgezl(p, r, 0, label_tlbw_hazard);
tlbw(p);
l_tlbw_hazard(l, *p);
break;
case CPU_RM7000:
i_nop(p);
i_nop(p);
i_nop(p);
i_nop(p);
tlbw(p);
break;
case CPU_4KEC:
case CPU_24K:
i_ehb(p);
i_tlbwr(p);
tlbw(p);
break;
case CPU_RM9000:
......@@ -812,13 +890,32 @@ static __init void build_tlb_write_random_entry(u32 **p, struct label **l,
i_ssnop(p);
i_ssnop(p);
i_ssnop(p);
i_tlbwr(p);
tlbw(p);
i_ssnop(p);
i_ssnop(p);
i_ssnop(p);
i_ssnop(p);
break;
case CPU_VR4111:
case CPU_VR4121:
case CPU_VR4122:
case CPU_VR4181:
case CPU_VR4181A:
i_nop(p);
i_nop(p);
tlbw(p);
i_nop(p);
i_nop(p);
break;
case CPU_VR4131:
case CPU_VR4133:
i_nop(p);
i_nop(p);
tlbw(p);
break;
default:
panic("No TLB refill handler yet (CPU type: %d)",
current_cpu_data.cputype);
......@@ -826,7 +923,7 @@ static __init void build_tlb_write_random_entry(u32 **p, struct label **l,
}
}
#if CONFIG_MIPS64
#ifdef CONFIG_MIPS64
/*
* TMP and PTR are scratch.
* TMP will be clobbered, PTR will hold the pmd entry.
......@@ -844,7 +941,7 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
il_bltz(p, r, tmp, label_vmalloc);
/* No i_nop needed here, since the next insn doesn't touch TMP. */
# ifdef CONFIG_SMP
#ifdef CONFIG_SMP
/*
* 64 bit SMP has the lower part of &pgd_current[smp_processor_id()]
* stored in CONTEXT.
......@@ -852,7 +949,17 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
if (in_compat_space_p(pgdc)) {
i_dmfc0(p, ptr, C0_CONTEXT);
i_dsra(p, ptr, ptr, 23);
i_ld(p, ptr, 0, ptr);
} else {
#ifdef CONFIG_BUILD_ELF64
i_dmfc0(p, ptr, C0_CONTEXT);
i_dsrl(p, ptr, ptr, 23);
i_dsll(p, ptr, ptr, 3);
i_LA_mostly(p, tmp, pgdc);
i_daddu(p, ptr, ptr, tmp);
i_dmfc0(p, tmp, C0_BADVADDR);
i_ld(p, ptr, rel_lo(pgdc), ptr);
#else
i_dmfc0(p, ptr, C0_CONTEXT);
i_lui(p, tmp, rel_highest(pgdc));
i_dsll(p, ptr, ptr, 9);
......@@ -860,12 +967,13 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
i_dsrl32(p, ptr, ptr, 0);
i_and(p, ptr, ptr, tmp);
i_dmfc0(p, tmp, C0_BADVADDR);
}
i_ld(p, ptr, 0, ptr);
# else
#endif
}
#else
i_LA_mostly(p, ptr, pgdc);
i_ld(p, ptr, rel_lo(pgdc), ptr);
# endif
#endif
l_vmalloc_done(l, *p);
i_dsrl(p, tmp, tmp, PGDIR_SHIFT-3); /* get pgd offset in bytes */
......@@ -902,13 +1010,14 @@ build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
}
}
#else /* CONFIG_MIPS32 */
#else /* !CONFIG_MIPS64 */
/*
* TMP and PTR are scratch.
* TMP will be clobbered, PTR will hold the pgd entry.
*/
static __init void build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
static __init void __attribute__((unused))
build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
{
long pgdc = (long)pgd_current;
......@@ -928,17 +1037,13 @@ static __init void build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
i_sll(p, tmp, tmp, PGD_T_LOG2);
i_addu(p, ptr, ptr, tmp); /* add in pgd offset */
}
#endif /* CONFIG_MIPS32 */
#endif /* !CONFIG_MIPS64 */
static __init void build_adjust_context(u32 **p, unsigned int ctx)
{
unsigned int shift = 0;
unsigned int mask = 0xff0;
#if !defined(CONFIG_MIPS64) && !defined(CONFIG_64BIT_PHYS_ADDR)
shift++;
mask |= 0x008;
#endif
unsigned int shift = 4 - (PTE_T_LOG2 + 1);
unsigned int mask = (PTRS_PER_PTE / 2 - 1) << (PTE_T_LOG2 + 1);
switch (current_cpu_data.cputype) {
case CPU_VR41XX:
......@@ -994,7 +1099,7 @@ static __init void build_update_entries(u32 **p, unsigned int tmp,
* Kernel is a special case. Only a few CPUs use it.
*/
#ifdef CONFIG_64BIT_PHYS_ADDR
if (cpu_has_64bit_gp_regs) {
if (cpu_has_64bits) {
i_ld(p, tmp, 0, ptep); /* get even pte */
i_ld(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
i_dsrl(p, tmp, tmp, 6); /* convert to entrylo0 */
......@@ -1049,20 +1154,20 @@ static void __init build_r4000_tlb_refill_handler(void)
i_MFC0(&p, K0, C0_BADVADDR);
i_MFC0(&p, K1, C0_ENTRYHI);
i_xor(&p, K0, K0, K1);
i_SRL(&p, K0, K0, PAGE_SHIFT+1);
i_SRL(&p, K0, K0, PAGE_SHIFT + 1);
il_bnez(&p, &r, K0, label_leave);
/* No need for i_nop */
}
#ifdef CONFIG_MIPS64
build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd ptr in K1 */
build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */
#else
build_get_pgde32(&p, K0, K1); /* get pgd ptr in K1 */
build_get_pgde32(&p, K0, K1); /* get pgd in K1 */
#endif
build_get_ptep(&p, K0, K1);
build_update_entries(&p, K0, K1);
build_tlb_write_random_entry(&p, &l, &r);
build_tlb_write_entry(&p, &l, &r, tlb_random);
l_leave(&l, p);
i_eret(&p); /* return from trap */
......@@ -1121,6 +1226,7 @@ static void __init build_r4000_tlb_refill_handler(void)
i_nop(&f);
else {
copy_handler(relocs, labels, split, split + 1, f);
move_labels(labels, f, f + 1, -1);
f++;
split++;
}
......@@ -1132,7 +1238,8 @@ static void __init build_r4000_tlb_refill_handler(void)
#endif /* CONFIG_MIPS64 */
resolve_relocs(relocs, labels);
printk("Synthesized TLB handler (%u instructions).\n", final_len);
printk("Synthesized TLB refill handler (%u instructions).\n",
final_len);
#ifdef DEBUG_TLB
{
......@@ -1147,10 +1254,530 @@ static void __init build_r4000_tlb_refill_handler(void)
flush_icache_range(CAC_BASE, CAC_BASE + 0x100);
}
/*
* TLB load/store/modify handlers.
*
* Only the fastpath gets synthesized at runtime, the slowpath for
* do_page_fault remains normal asm.
*/
extern void tlb_do_page_fault_0(void);
extern void tlb_do_page_fault_1(void);
#define __tlb_handler_align \
__attribute__((__aligned__(1 << CONFIG_MIPS_L1_CACHE_SHIFT)))
/*
* 128 instructions for the fastpath handler is generous and should
* never be exceeded.
*/
#define FASTPATH_SIZE 128
u32 __tlb_handler_align handle_tlbl[FASTPATH_SIZE];
u32 __tlb_handler_align handle_tlbs[FASTPATH_SIZE];
u32 __tlb_handler_align handle_tlbm[FASTPATH_SIZE];
static void __init
iPTE_LW(u32 **p, struct label **l, unsigned int pte, int offset,
unsigned int ptr)
{
#ifdef CONFIG_SMP
# ifdef CONFIG_64BIT_PHYS_ADDR
if (cpu_has_64bits)
i_lld(p, pte, offset, ptr);
else
# endif
i_LL(p, pte, offset, ptr);
#else
# ifdef CONFIG_64BIT_PHYS_ADDR
if (cpu_has_64bits)
i_ld(p, pte, offset, ptr);
else
# endif
i_LW(p, pte, offset, ptr);
#endif
}
static void __init
iPTE_SW(u32 **p, struct reloc **r, unsigned int pte, int offset,
unsigned int ptr)
{
#ifdef CONFIG_SMP
# ifdef CONFIG_64BIT_PHYS_ADDR
if (cpu_has_64bits)
i_scd(p, pte, offset, ptr);
else
# endif
i_SC(p, pte, offset, ptr);
if (r10000_llsc_war())
il_beqzl(p, r, pte, label_smp_pgtable_change);
else
il_beqz(p, r, pte, label_smp_pgtable_change);
# ifdef CONFIG_64BIT_PHYS_ADDR
if (!cpu_has_64bits) {
/* no i_nop needed */
i_ll(p, pte, sizeof(pte_t) / 2, ptr);
i_ori(p, pte, pte, _PAGE_VALID);
i_sc(p, pte, sizeof(pte_t) / 2, ptr);
il_beqz(p, r, pte, label_smp_pgtable_change);
/* no i_nop needed */
i_lw(p, pte, 0, ptr);
} else
i_nop(p);
# else
i_nop(p);
# endif
#else
# ifdef CONFIG_64BIT_PHYS_ADDR
if (cpu_has_64bits)
i_sd(p, pte, offset, ptr);
else
# endif
i_SW(p, pte, offset, ptr);
# ifdef CONFIG_64BIT_PHYS_ADDR
if (!cpu_has_64bits) {
i_lw(p, pte, sizeof(pte_t) / 2, ptr);
i_ori(p, pte, pte, _PAGE_VALID);
i_sw(p, pte, sizeof(pte_t) / 2, ptr);
i_lw(p, pte, 0, ptr);
}
# endif
#endif
}
/*
* Check if PTE is present, if not then jump to LABEL. PTR points to
* the page table where this PTE is located, PTE will be re-loaded
* with it's original value.
*/
static void __init
build_pte_present(u32 **p, struct label **l, struct reloc **r,
unsigned int pte, unsigned int ptr, enum label_id lid)
{
i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
il_bnez(p, r, pte, lid);
iPTE_LW(p, l, pte, 0, ptr);
}
/* Make PTE valid, store result in PTR. */
static void __init
build_make_valid(u32 **p, struct reloc **r, unsigned int pte,
unsigned int ptr)
{
i_ori(p, pte, pte, _PAGE_VALID | _PAGE_ACCESSED);
iPTE_SW(p, r, pte, 0, ptr);
}
/*
* Check if PTE can be written to, if not branch to LABEL. Regardless
* restore PTE with value from PTR when done.
*/
static void __init
build_pte_writable(u32 **p, struct label **l, struct reloc **r,
unsigned int pte, unsigned int ptr, enum label_id lid)
{
i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
il_bnez(p, r, pte, lid);
iPTE_LW(p, l, pte, 0, ptr);
}
/* Make PTE writable, update software status bits as well, then store
* at PTR.
*/
static void __init
build_make_write(u32 **p, struct reloc **r, unsigned int pte,
unsigned int ptr)
{
i_ori(p, pte, pte,
_PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID | _PAGE_DIRTY);
iPTE_SW(p, r, pte, 0, ptr);
}
/*
* Check if PTE can be modified, if not branch to LABEL. Regardless
* restore PTE with value from PTR when done.
*/
static void __init
build_pte_modifiable(u32 **p, struct label **l, struct reloc **r,
unsigned int pte, unsigned int ptr, enum label_id lid)
{
i_andi(p, pte, pte, _PAGE_WRITE);
il_beqz(p, r, pte, lid);
iPTE_LW(p, l, pte, 0, ptr);
}
/*
* R3000 style TLB load/store/modify handlers.
*/
/* This places the pte in the page table at PTR into ENTRYLO0. */
static void __init
build_r3000_pte_reload(u32 **p, unsigned int ptr)
{
i_lw(p, ptr, 0, ptr);
i_nop(p); /* load delay */
i_mtc0(p, ptr, C0_ENTRYLO0);
i_nop(p); /* cp0 delay */
}
/*
* The index register may have the probe fail bit set,
* because we would trap on access kseg2, i.e. without refill.
*/
static void __init
build_r3000_tlb_write(u32 **p, struct label **l, struct reloc **r,
unsigned int tmp)
{
i_mfc0(p, tmp, C0_INDEX);
i_nop(p); /* cp0 delay */
il_bltz(p, r, tmp, label_r3000_write_probe_fail);
i_nop(p); /* branch delay */
i_tlbwi(p);
il_b(p, r, label_r3000_write_probe_ok);
i_nop(p); /* branch delay */
l_r3000_write_probe_fail(l, *p);
i_tlbwr(p);
l_r3000_write_probe_ok(l, *p);
}
static void __init
build_r3000_tlbchange_handler_head(u32 **p, unsigned int pte,
unsigned int ptr)
{
long pgdc = (long)pgd_current;
i_mfc0(p, pte, C0_BADVADDR);
i_lui(p, ptr, rel_hi(pgdc)); /* cp0 delay */
i_lw(p, ptr, rel_lo(pgdc), ptr);
i_srl(p, pte, pte, 22); /* load delay */
i_sll(p, pte, pte, 2);
i_addu(p, ptr, ptr, pte);
i_mfc0(p, pte, C0_CONTEXT);
i_lw(p, ptr, 0, ptr); /* cp0 delay */
i_andi(p, pte, pte, 0xffc); /* load delay */
i_addu(p, ptr, ptr, pte);
i_lw(p, pte, 0, ptr);
i_nop(p); /* load delay */
i_tlbp(p);
}
static void __init
build_r3000_tlbchange_handler_tail(u32 **p, unsigned int tmp)
{
i_mfc0(p, tmp, C0_EPC);
i_nop(p); /* cp0 delay */
i_jr(p, tmp);
i_rfe(p); /* branch delay */
}
static void __init build_r3000_tlb_load_handler(void)
{
u32 *p = handle_tlbl;
struct label *l = labels;
struct reloc *r = relocs;
memset(handle_tlbl, 0, sizeof(handle_tlbl));
memset(labels, 0, sizeof(labels));
memset(relocs, 0, sizeof(relocs));
build_r3000_tlbchange_handler_head(&p, K0, K1);
build_pte_present(&p, &l, &r, K0, K1, label_nopage_tlbl);
build_make_valid(&p, &r, K0, K1);
build_r3000_pte_reload(&p, K1);
build_r3000_tlb_write(&p, &l, &r, K0);
build_r3000_tlbchange_handler_tail(&p, K0);
l_nopage_tlbl(&l, p);
i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
i_nop(&p);
if ((p - handle_tlbl) > FASTPATH_SIZE)
panic("TLB load handler fastpath space exceeded");
resolve_relocs(relocs, labels);
printk("Synthesized TLB load handler fastpath (%u instructions).\n",
(unsigned int)(p - handle_tlbl));
#ifdef DEBUG_TLB
{
int i;
for (i = 0; i < FASTPATH_SIZE; i++)
printk("%08x\n", handle_tlbl[i]);
}
#endif
flush_icache_range((unsigned long)handle_tlbl,
(unsigned long)handle_tlbl + FASTPATH_SIZE * sizeof(u32));
}
static void __init build_r3000_tlb_store_handler(void)
{
u32 *p = handle_tlbs;
struct label *l = labels;
struct reloc *r = relocs;
memset(handle_tlbs, 0, sizeof(handle_tlbs));
memset(labels, 0, sizeof(labels));
memset(relocs, 0, sizeof(relocs));
build_r3000_tlbchange_handler_head(&p, K0, K1);
build_pte_writable(&p, &l, &r, K0, K1, label_nopage_tlbs);
build_make_write(&p, &r, K0, K1);
build_r3000_pte_reload(&p, K1);
build_r3000_tlb_write(&p, &l, &r, K0);
build_r3000_tlbchange_handler_tail(&p, K0);
l_nopage_tlbs(&l, p);
i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
i_nop(&p);
if ((p - handle_tlbs) > FASTPATH_SIZE)
panic("TLB store handler fastpath space exceeded");
resolve_relocs(relocs, labels);
printk("Synthesized TLB store handler fastpath (%u instructions).\n",
(unsigned int)(p - handle_tlbs));
#ifdef DEBUG_TLB
{
int i;
for (i = 0; i < FASTPATH_SIZE; i++)
printk("%08x\n", handle_tlbs[i]);
}
#endif
flush_icache_range((unsigned long)handle_tlbs,
(unsigned long)handle_tlbs + FASTPATH_SIZE * sizeof(u32));
}
static void __init build_r3000_tlb_modify_handler(void)
{
u32 *p = handle_tlbm;
struct label *l = labels;
struct reloc *r = relocs;
memset(handle_tlbm, 0, sizeof(handle_tlbm));
memset(labels, 0, sizeof(labels));
memset(relocs, 0, sizeof(relocs));
build_r3000_tlbchange_handler_head(&p, K0, K1);
build_pte_modifiable(&p, &l, &r, K0, K1, label_nopage_tlbm);
build_make_write(&p, &r, K0, K1);
build_r3000_pte_reload(&p, K1);
i_tlbwi(&p);
build_r3000_tlbchange_handler_tail(&p, K0);
l_nopage_tlbm(&l, p);
i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
i_nop(&p);
if ((p - handle_tlbm) > FASTPATH_SIZE)
panic("TLB modify handler fastpath space exceeded");
resolve_relocs(relocs, labels);
printk("Synthesized TLB modify handler fastpath (%u instructions).\n",
(unsigned int)(p - handle_tlbm));
#ifdef DEBUG_TLB
{
int i;
for (i = 0; i < FASTPATH_SIZE; i++)
printk("%08x\n", handle_tlbm[i]);
}
#endif
flush_icache_range((unsigned long)handle_tlbm,
(unsigned long)handle_tlbm + FASTPATH_SIZE * sizeof(u32));
}
/*
* R4000 style TLB load/store/modify handlers.
*/
static void __init
build_r4000_tlbchange_handler_head(u32 **p, struct label **l,
struct reloc **r, unsigned int pte,
unsigned int ptr)
{
#ifdef CONFIG_MIPS64
build_get_pmde64(p, l, r, pte, ptr); /* get pmd in ptr */
#else
build_get_pgde32(p, pte, ptr); /* get pgd in ptr */
#endif
i_MFC0(p, pte, C0_BADVADDR);
i_LW(p, ptr, 0, ptr);
i_SRL(p, pte, pte, PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2);
i_andi(p, pte, pte, (PTRS_PER_PTE - 1) << PTE_T_LOG2);
i_ADDU(p, ptr, ptr, pte);
#ifdef CONFIG_SMP
l_smp_pgtable_change(l, *p);
# endif
iPTE_LW(p, l, pte, 0, ptr); /* get even pte */
build_tlb_probe_entry(p);
}
static void __init
build_r4000_tlbchange_handler_tail(u32 **p, struct label **l,
struct reloc **r, unsigned int tmp,
unsigned int ptr)
{
i_ori(p, ptr, ptr, sizeof(pte_t));
i_xori(p, ptr, ptr, sizeof(pte_t));
build_update_entries(p, tmp, ptr);
build_tlb_write_entry(p, l, r, tlb_indexed);
l_leave(l, *p);
i_eret(p); /* return from trap */
#ifdef CONFIG_MIPS64
build_get_pgd_vmalloc64(p, l, r, tmp, ptr);
#endif
}
static void __init build_r4000_tlb_load_handler(void)
{
u32 *p = handle_tlbl;
struct label *l = labels;
struct reloc *r = relocs;
memset(handle_tlbl, 0, sizeof(handle_tlbl));
memset(labels, 0, sizeof(labels));
memset(relocs, 0, sizeof(relocs));
if (bcm1250_m3_war()) {
i_MFC0(&p, K0, C0_BADVADDR);
i_MFC0(&p, K1, C0_ENTRYHI);
i_xor(&p, K0, K0, K1);
i_SRL(&p, K0, K0, PAGE_SHIFT + 1);
il_bnez(&p, &r, K0, label_leave);
/* No need for i_nop */
}
build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
build_pte_present(&p, &l, &r, K0, K1, label_nopage_tlbl);
build_make_valid(&p, &r, K0, K1);
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
l_nopage_tlbl(&l, p);
i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
i_nop(&p);
if ((p - handle_tlbl) > FASTPATH_SIZE)
panic("TLB load handler fastpath space exceeded");
resolve_relocs(relocs, labels);
printk("Synthesized TLB load handler fastpath (%u instructions).\n",
(unsigned int)(p - handle_tlbl));
#ifdef DEBUG_TLB
{
int i;
for (i = 0; i < FASTPATH_SIZE; i++)
printk("%08x\n", handle_tlbl[i]);
}
#endif
flush_icache_range((unsigned long)handle_tlbl,
(unsigned long)handle_tlbl + FASTPATH_SIZE * sizeof(u32));
}
static void __init build_r4000_tlb_store_handler(void)
{
u32 *p = handle_tlbs;
struct label *l = labels;
struct reloc *r = relocs;
memset(handle_tlbs, 0, sizeof(handle_tlbs));
memset(labels, 0, sizeof(labels));
memset(relocs, 0, sizeof(relocs));
build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
build_pte_writable(&p, &l, &r, K0, K1, label_nopage_tlbs);
build_make_write(&p, &r, K0, K1);
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
l_nopage_tlbs(&l, p);
i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
i_nop(&p);
if ((p - handle_tlbs) > FASTPATH_SIZE)
panic("TLB store handler fastpath space exceeded");
resolve_relocs(relocs, labels);
printk("Synthesized TLB store handler fastpath (%u instructions).\n",
(unsigned int)(p - handle_tlbs));
#ifdef DEBUG_TLB
{
int i;
for (i = 0; i < FASTPATH_SIZE; i++)
printk("%08x\n", handle_tlbs[i]);
}
#endif
flush_icache_range((unsigned long)handle_tlbs,
(unsigned long)handle_tlbs + FASTPATH_SIZE * sizeof(u32));
}
static void __init build_r4000_tlb_modify_handler(void)
{
u32 *p = handle_tlbm;
struct label *l = labels;
struct reloc *r = relocs;
memset(handle_tlbm, 0, sizeof(handle_tlbm));
memset(labels, 0, sizeof(labels));
memset(relocs, 0, sizeof(relocs));
build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
build_pte_modifiable(&p, &l, &r, K0, K1, label_nopage_tlbm);
/* Present and writable bits set, set accessed and dirty bits. */
build_make_write(&p, &r, K0, K1);
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
l_nopage_tlbm(&l, p);
i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
i_nop(&p);
if ((p - handle_tlbm) > FASTPATH_SIZE)
panic("TLB modify handler fastpath space exceeded");
resolve_relocs(relocs, labels);
printk("Synthesized TLB modify handler fastpath (%u instructions).\n",
(unsigned int)(p - handle_tlbm));
#ifdef DEBUG_TLB
{
int i;
for (i = 0; i < FASTPATH_SIZE; i++)
printk("%08x\n", handle_tlbm[i]);
}
#endif
flush_icache_range((unsigned long)handle_tlbm,
(unsigned long)handle_tlbm + FASTPATH_SIZE * sizeof(u32));
}
void __init build_tlb_refill_handler(void)
{
/*
* The refill handler is generated per-CPU, multi-node systems
* may have local storage for it. The other handlers are only
* needed once.
*/
static int run_once = 0;
switch (current_cpu_data.cputype) {
#ifdef CONFIG_MIPS32
case CPU_R2000:
case CPU_R3000:
case CPU_R3000A:
......@@ -1159,13 +1786,18 @@ void __init build_tlb_refill_handler(void)
case CPU_TX3922:
case CPU_TX3927:
build_r3000_tlb_refill_handler();
if (!run_once) {
build_r3000_tlb_load_handler();
build_r3000_tlb_store_handler();
build_r3000_tlb_modify_handler();
run_once++;
}
break;
case CPU_R6000:
case CPU_R6000A:
panic("No R6000 TLB refill handler yet");
break;
#endif
case CPU_R8000:
panic("No R8000 TLB refill handler yet");
......@@ -1173,5 +1805,11 @@ void __init build_tlb_refill_handler(void)
default:
build_r4000_tlb_refill_handler();
if (!run_once) {
build_r4000_tlb_load_handler();
build_r4000_tlb_store_handler();
build_r4000_tlb_modify_handler();
run_once++;
}
}
}
/*
* TLB exception handling code for MIPS32 CPUs.
*
* Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
*
* Multi-cpu abstraction and reworking:
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
*
* Pete Popov, ppopov@pacbell.net
* Added 36 bit phys address support.
* Copyright (C) 2002 MontaVista Software, Inc.
*/
#include <linux/init.h>
#include <asm/asm.h>
#include <asm/cachectl.h>
#include <asm/fpregdef.h>
#include <asm/mipsregs.h>
#include <asm/page.h>
#include <asm/pgtable-bits.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#define TLB_OPTIMIZE /* If you are paranoid, disable this. */
#ifdef CONFIG_64BIT_PHYS_ADDR
/* We really only support 36 bit physical addresses on MIPS32 */
#define PTE_L lw
#define PTE_S sw
#define PTE_SRL srl
#define P_MTC0 mtc0
#define PTE_HALF 4 /* pte_high contains pre-shifted, ready to go entry */
#define PTE_SIZE 8
#define PTEP_INDX_MSK 0xff0
#define PTE_INDX_MSK 0xff8
#define PTE_INDX_SHIFT 9
#define CONVERT_PTE(pte)
#define PTE_MAKEWRITE_HIGH(pte, ptr) \
lw pte, PTE_HALF(ptr); \
ori pte, (_PAGE_VALID | _PAGE_DIRTY); \
sw pte, PTE_HALF(ptr); \
lw pte, 0(ptr);
#define PTE_MAKEVALID_HIGH(pte, ptr) \
lw pte, PTE_HALF(ptr); \
ori pte, pte, _PAGE_VALID; \
sw pte, PTE_HALF(ptr); \
lw pte, 0(ptr);
#else
#define PTE_L lw
#define PTE_S sw
#define PTE_SRL srl
#define P_MTC0 mtc0
#define PTE_HALF 0
#define PTE_SIZE 4
#define PTEP_INDX_MSK 0xff8
#define PTE_INDX_MSK 0xffc
#define PTE_INDX_SHIFT 10
#define CONVERT_PTE(pte) srl pte, pte, 6
#define PTE_MAKEWRITE_HIGH(pte, ptr)
#define PTE_MAKEVALID_HIGH(pte, ptr)
#endif /* CONFIG_64BIT_PHYS_ADDR */
#ifdef CONFIG_64BIT_PHYS_ADDR
#define GET_PTE_OFF(reg)
#else
#define GET_PTE_OFF(reg) srl reg, reg, 1
#endif
/*
* ABUSE of CPP macros 101.
*
* After this macro runs, the pte faulted on is
* in register PTE, a ptr into the table in which
* the pte belongs is in PTR.
*/
#ifdef CONFIG_SMP
#define GET_PGD(scratch, ptr) \
mfc0 ptr, CP0_CONTEXT; \
la scratch, pgd_current;\
srl ptr, 23; \
sll ptr, 2; \
addu ptr, scratch, ptr; \
lw ptr, (ptr);
#else
#define GET_PGD(scratch, ptr) \
lw ptr, pgd_current;
#endif
#define LOAD_PTE(pte, ptr) \
GET_PGD(pte, ptr) \
mfc0 pte, CP0_BADVADDR; \
srl pte, pte, _PGDIR_SHIFT; \
sll pte, pte, 2; \
addu ptr, ptr, pte; \
mfc0 pte, CP0_BADVADDR; \
lw ptr, (ptr); \
srl pte, pte, PTE_INDX_SHIFT; \
and pte, pte, PTE_INDX_MSK; \
addu ptr, ptr, pte; \
PTE_L pte, (ptr);
/* This places the even/odd pte pair in the page
* table at PTR into ENTRYLO0 and ENTRYLO1 using
* TMP as a scratch register.
*/
#define PTE_RELOAD(ptr, tmp) \
ori ptr, ptr, PTE_SIZE; \
xori ptr, ptr, PTE_SIZE; \
PTE_L tmp, (PTE_HALF+PTE_SIZE)(ptr); \
CONVERT_PTE(tmp); \
P_MTC0 tmp, CP0_ENTRYLO1; \
PTE_L ptr, PTE_HALF(ptr); \
CONVERT_PTE(ptr); \
P_MTC0 ptr, CP0_ENTRYLO0;
#define DO_FAULT(write) \
.set noat; \
SAVE_ALL; \
mfc0 a2, CP0_BADVADDR; \
KMODE; \
.set at; \
move a0, sp; \
jal do_page_fault; \
li a1, write; \
j ret_from_exception; \
nop; \
.set noat;
/* Check is PTE is present, if not then jump to LABEL.
* PTR points to the page table where this PTE is located,
* when the macro is done executing PTE will be restored
* with it's original value.
*/
#define PTE_PRESENT(pte, ptr, label) \
andi pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
xori pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
bnez pte, label; \
PTE_L pte, (ptr);
/* Make PTE valid, store result in PTR. */
#define PTE_MAKEVALID(pte, ptr) \
ori pte, pte, (_PAGE_VALID | _PAGE_ACCESSED); \
PTE_S pte, (ptr);
/* Check if PTE can be written to, if not branch to LABEL.
* Regardless restore PTE with value from PTR when done.
*/
#define PTE_WRITABLE(pte, ptr, label) \
andi pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
xori pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
bnez pte, label; \
PTE_L pte, (ptr);
/* Make PTE writable, update software status bits as well,
* then store at PTR.
*/
#define PTE_MAKEWRITE(pte, ptr) \
ori pte, pte, (_PAGE_ACCESSED | _PAGE_MODIFIED | \
_PAGE_VALID | _PAGE_DIRTY); \
PTE_S pte, (ptr);
.set noreorder
.align 5
NESTED(handle_tlbl, PT_SIZE, sp)
.set noat
invalid_tlbl:
#ifdef TLB_OPTIMIZE
/* Test present bit in entry. */
LOAD_PTE(k0, k1)
tlbp
PTE_PRESENT(k0, k1, nopage_tlbl)
PTE_MAKEVALID_HIGH(k0, k1)
PTE_MAKEVALID(k0, k1)
PTE_RELOAD(k1, k0)
nop
b 1f
tlbwi
1:
nop
.set mips3
eret
.set mips0
#endif
nopage_tlbl:
DO_FAULT(0)
END(handle_tlbl)
.align 5
NESTED(handle_tlbs, PT_SIZE, sp)
.set noat
#ifdef TLB_OPTIMIZE
.set mips3
li k0,0
LOAD_PTE(k0, k1)
tlbp # find faulting entry
PTE_WRITABLE(k0, k1, nopage_tlbs)
PTE_MAKEWRITE(k0, k1)
PTE_MAKEWRITE_HIGH(k0, k1)
PTE_RELOAD(k1, k0)
nop
b 1f
tlbwi
1:
nop
.set mips3
eret
.set mips0
#endif
nopage_tlbs:
DO_FAULT(1)
END(handle_tlbs)
.align 5
NESTED(handle_mod, PT_SIZE, sp)
.set noat
#ifdef TLB_OPTIMIZE
.set mips3
LOAD_PTE(k0, k1)
tlbp # find faulting entry
andi k0, k0, _PAGE_WRITE
beqz k0, nowrite_mod
PTE_L k0, (k1)
/* Present and writable bits set, set accessed and dirty bits. */
PTE_MAKEWRITE(k0, k1)
PTE_MAKEWRITE_HIGH(k0, k1)
/* Now reload the entry into the tlb. */
PTE_RELOAD(k1, k0)
nop
b 1f
tlbwi
1:
nop
.set mips3
eret
.set mips0
#endif
nowrite_mod:
DO_FAULT(1)
END(handle_mod)
/*
* TLB exception handling code for R2000/R3000.
*
* Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
*
* Multi-CPU abstraction reworking:
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
* Further modifications to make this work:
* Copyright (c) 1998 Harald Koerfgen
* Copyright (c) 1998, 1999 Gleb Raiko & Vladimir Roganov
* Copyright (c) 2001 Ralf Baechle
* Copyright (c) 2001 MIPS Technologies, Inc.
*/
#include <linux/init.h>
#include <asm/asm.h>
#include <asm/cachectl.h>
#include <asm/fpregdef.h>
#include <asm/mipsregs.h>
#include <asm/page.h>
#include <asm/pgtable-bits.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#define TLB_OPTIMIZE /* If you are paranoid, disable this. */
/* ABUSE of CPP macros 101. */
/* After this macro runs, the pte faulted on is
* in register PTE, a ptr into the table in which
* the pte belongs is in PTR.
*/
#define LOAD_PTE(pte, ptr) \
mfc0 pte, CP0_BADVADDR; \
lw ptr, pgd_current; \
srl pte, pte, 22; \
sll pte, pte, 2; \
addu ptr, ptr, pte; \
mfc0 pte, CP0_CONTEXT; \
lw ptr, (ptr); \
andi pte, pte, 0xffc; \
addu ptr, ptr, pte; \
lw pte, (ptr); \
nop;
/* This places the even/odd pte pair in the page
* table at PTR into ENTRYLO0 and ENTRYLO1 using
* TMP as a scratch register.
*/
#define PTE_RELOAD(ptr) \
lw ptr, (ptr) ; \
nop ; \
mtc0 ptr, CP0_ENTRYLO0; \
nop;
#define DO_FAULT(write) \
.set noat; \
.set macro; \
SAVE_ALL; \
mfc0 a2, CP0_BADVADDR; \
KMODE; \
.set at; \
move a0, sp; \
jal do_page_fault; \
li a1, write; \
j ret_from_exception; \
nop; \
.set noat; \
.set nomacro;
/* Check is PTE is present, if not then jump to LABEL.
* PTR points to the page table where this PTE is located,
* when the macro is done executing PTE will be restored
* with it's original value.
*/
#define PTE_PRESENT(pte, ptr, label) \
andi pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
xori pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
bnez pte, label; \
.set push; \
.set reorder; \
lw pte, (ptr); \
.set pop;
/* Make PTE valid, store result in PTR. */
#define PTE_MAKEVALID(pte, ptr) \
ori pte, pte, (_PAGE_VALID | _PAGE_ACCESSED); \
sw pte, (ptr);
/* Check if PTE can be written to, if not branch to LABEL.
* Regardless restore PTE with value from PTR when done.
*/
#define PTE_WRITABLE(pte, ptr, label) \
andi pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
xori pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
bnez pte, label; \
.set push; \
.set reorder; \
lw pte, (ptr); \
.set pop;
/* Make PTE writable, update software status bits as well,
* then store at PTR.
*/
#define PTE_MAKEWRITE(pte, ptr) \
ori pte, pte, (_PAGE_ACCESSED | _PAGE_MODIFIED | \
_PAGE_VALID | _PAGE_DIRTY); \
sw pte, (ptr);
/*
* The index register may have the probe fail bit set,
* because we would trap on access kseg2, i.e. without refill.
*/
#define TLB_WRITE(reg) \
mfc0 reg, CP0_INDEX; \
nop; \
bltz reg, 1f; \
nop; \
tlbwi; \
j 2f; \
nop; \
1: tlbwr; \
2:
#define RET(reg) \
mfc0 reg, CP0_EPC; \
nop; \
jr reg; \
rfe
.set noreorder
.align 5
NESTED(handle_tlbl, PT_SIZE, sp)
.set noat
#ifdef TLB_OPTIMIZE
/* Test present bit in entry. */
LOAD_PTE(k0, k1)
tlbp
PTE_PRESENT(k0, k1, nopage_tlbl)
PTE_MAKEVALID(k0, k1)
PTE_RELOAD(k1)
TLB_WRITE(k0)
RET(k0)
nopage_tlbl:
#endif
DO_FAULT(0)
END(handle_tlbl)
NESTED(handle_tlbs, PT_SIZE, sp)
.set noat
#ifdef TLB_OPTIMIZE
LOAD_PTE(k0, k1)
tlbp # find faulting entry
PTE_WRITABLE(k0, k1, nopage_tlbs)
PTE_MAKEWRITE(k0, k1)
PTE_RELOAD(k1)
TLB_WRITE(k0)
RET(k0)
nopage_tlbs:
#endif
DO_FAULT(1)
END(handle_tlbs)
.align 5
NESTED(handle_mod, PT_SIZE, sp)
.set noat
#ifdef TLB_OPTIMIZE
LOAD_PTE(k0, k1)
tlbp # find faulting entry
andi k0, k0, _PAGE_WRITE
beqz k0, nowrite_mod
.set push
.set reorder
lw k0, (k1)
.set pop
/* Present and writable bits set, set accessed and dirty bits. */
PTE_MAKEWRITE(k0, k1)
/* Now reload the entry into the tlb. */
PTE_RELOAD(k1)
tlbwi
RET(k0)
#endif
nowrite_mod:
DO_FAULT(1)
END(handle_mod)
/*
* TLB exception handling code for r4k.
*
* Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
*
* Multi-cpu abstraction and reworking:
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
*/
#include <linux/init.h>
#include <linux/config.h>
#include <asm/asm.h>
#include <asm/offset.h>
#include <asm/cachectl.h>
#include <asm/fpregdef.h>
#include <asm/mipsregs.h>
#include <asm/page.h>
#include <asm/pgtable-bits.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#include <asm/war.h>
#define TLB_OPTIMIZE /* If you are paranoid, disable this. */
#ifdef CONFIG_64BIT_PHYS_ADDR
#define PTE_L ld
#define PTE_S sd
#define PTE_SRL dsrl
#define P_MTC0 dmtc0
#define PTE_SIZE 8
#define PTEP_INDX_MSK 0xff0
#define PTE_INDX_MSK 0xff8
#define PTE_INDX_SHIFT 9
#else
#define PTE_L lw
#define PTE_S sw
#define PTE_SRL srl
#define P_MTC0 mtc0
#define PTE_SIZE 4
#define PTEP_INDX_MSK 0xff8
#define PTE_INDX_MSK 0xffc
#define PTE_INDX_SHIFT 10
#endif
/*
* ABUSE of CPP macros 101.
*
* After this macro runs, the pte faulted on is
* in register PTE, a ptr into the table in which
* the pte belongs is in PTR.
*/
#ifdef CONFIG_SMP
#define GET_PGD(scratch, ptr) \
mfc0 ptr, CP0_CONTEXT; \
la scratch, pgd_current;\
srl ptr, 23; \
sll ptr, 2; \
addu ptr, scratch, ptr; \
lw ptr, (ptr);
#else
#define GET_PGD(scratch, ptr) \
lw ptr, pgd_current;
#endif
#define LOAD_PTE(pte, ptr) \
GET_PGD(pte, ptr) \
mfc0 pte, CP0_BADVADDR; \
srl pte, pte, _PGDIR_SHIFT; \
sll pte, pte, 2; \
addu ptr, ptr, pte; \
mfc0 pte, CP0_BADVADDR; \
lw ptr, (ptr); \
srl pte, pte, PTE_INDX_SHIFT; \
and pte, pte, PTE_INDX_MSK; \
addu ptr, ptr, pte; \
PTE_L pte, (ptr);
/* This places the even/odd pte pair in the page
* table at PTR into ENTRYLO0 and ENTRYLO1 using
* TMP as a scratch register.
*/
#define PTE_RELOAD(ptr, tmp) \
ori ptr, ptr, PTE_SIZE; \
xori ptr, ptr, PTE_SIZE; \
PTE_L tmp, PTE_SIZE(ptr); \
PTE_L ptr, 0(ptr); \
PTE_SRL tmp, tmp, 6; \
P_MTC0 tmp, CP0_ENTRYLO1; \
PTE_SRL ptr, ptr, 6; \
P_MTC0 ptr, CP0_ENTRYLO0;
#define DO_FAULT(write) \
.set noat; \
SAVE_ALL; \
mfc0 a2, CP0_BADVADDR; \
KMODE; \
.set at; \
move a0, sp; \
jal do_page_fault; \
li a1, write; \
j ret_from_exception; \
nop; \
.set noat;
/* Check is PTE is present, if not then jump to LABEL.
* PTR points to the page table where this PTE is located,
* when the macro is done executing PTE will be restored
* with it's original value.
*/
#define PTE_PRESENT(pte, ptr, label) \
andi pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
xori pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
bnez pte, label; \
PTE_L pte, (ptr);
/* Make PTE valid, store result in PTR. */
#define PTE_MAKEVALID(pte, ptr) \
ori pte, pte, (_PAGE_VALID | _PAGE_ACCESSED); \
PTE_S pte, (ptr);
/* Check if PTE can be written to, if not branch to LABEL.
* Regardless restore PTE with value from PTR when done.
*/
#define PTE_WRITABLE(pte, ptr, label) \
andi pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
xori pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
bnez pte, label; \
PTE_L pte, (ptr);
/* Make PTE writable, update software status bits as well,
* then store at PTR.
*/
#define PTE_MAKEWRITE(pte, ptr) \
ori pte, pte, (_PAGE_ACCESSED | _PAGE_MODIFIED | \
_PAGE_VALID | _PAGE_DIRTY); \
PTE_S pte, (ptr);
.set noreorder
/*
* From the IDT errata for the QED RM5230 (Nevada), processor revision 1.0:
* 2. A timing hazard exists for the TLBP instruction.
*
* stalling_instruction
* TLBP
*
* The JTLB is being read for the TLBP throughout the stall generated by the
* previous instruction. This is not really correct as the stalling instruction
* can modify the address used to access the JTLB. The failure symptom is that
* the TLBP instruction will use an address created for the stalling instruction
* and not the address held in C0_ENHI and thus report the wrong results.
*
* The software work-around is to not allow the instruction preceding the TLBP
* to stall - make it an NOP or some other instruction guaranteed not to stall.
*
* Errata 2 will not be fixed. This errata is also on the R5000.
*
* As if we MIPS hackers wouldn't know how to nop pipelines happy ...
*/
#define R5K_HAZARD nop
/*
* Note for many R4k variants tlb probes cannot be executed out
* of the instruction cache else you get bogus results.
*/
.align 5
NESTED(handle_tlbl, PT_SIZE, sp)
.set noat
#if BCM1250_M3_WAR
mfc0 k0, CP0_BADVADDR
mfc0 k1, CP0_ENTRYHI
xor k0, k1
srl k0, k0, PAGE_SHIFT+1
beqz k0, 1f
nop
.set mips3
eret
.set mips0
1:
#endif
invalid_tlbl:
#ifdef TLB_OPTIMIZE
.set mips3
/* Test present bit in entry. */
LOAD_PTE(k0, k1)
R5K_HAZARD
tlbp
PTE_PRESENT(k0, k1, nopage_tlbl)
PTE_MAKEVALID(k0, k1)
PTE_RELOAD(k1, k0)
mtc0_tlbw_hazard
tlbwi
nop
tlbw_eret_hazard
.set mips3
eret
.set mips0
#endif
nopage_tlbl:
DO_FAULT(0)
END(handle_tlbl)
.align 5
NESTED(handle_tlbs, PT_SIZE, sp)
.set noat
#ifdef TLB_OPTIMIZE
.set mips3
li k0,0
LOAD_PTE(k0, k1)
R5K_HAZARD
tlbp # find faulting entry
PTE_WRITABLE(k0, k1, nopage_tlbs)
PTE_MAKEWRITE(k0, k1)
PTE_RELOAD(k1, k0)
mtc0_tlbw_hazard
tlbwi
nop
tlbw_eret_hazard
.set mips3
eret
.set mips0
#endif
nopage_tlbs:
DO_FAULT(1)
END(handle_tlbs)
.align 5
NESTED(handle_mod, PT_SIZE, sp)
.set noat
#ifdef TLB_OPTIMIZE
.set mips3
LOAD_PTE(k0, k1)
R5K_HAZARD
tlbp # find faulting entry
andi k0, k0, _PAGE_WRITE
beqz k0, nowrite_mod
PTE_L k0, (k1)
/* Present and writable bits set, set accessed and dirty bits. */
PTE_MAKEWRITE(k0, k1)
/* Now reload the entry into the tlb. */
PTE_RELOAD(k1, k0)
mtc0_tlbw_hazard
tlbwi
nop
tlbw_eret_hazard
.set mips3
eret
.set mips0
#endif
nowrite_mod:
DO_FAULT(1)
END(handle_mod)
menu "Profiling support"
depends on EXPERIMENTAL
config PROFILING
bool "Profiling support (EXPERIMENTAL)"
help
Say Y here to enable the extended profiling support mechanisms used
by profilers such as OProfile.
config OPROFILE
tristate "OProfile system profiling (EXPERIMENTAL)"
depends on PROFILING
help
OProfile is a profiling system capable of profiling the
whole system, include the kernel, kernel modules, libraries,
and applications.
If unsure, say N.
endmenu
EXTRA_CFLAGS := -Werror
obj-$(CONFIG_OPROFILE) += oprofile.o
DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
oprof.o cpu_buffer.o buffer_sync.o \
event_buffer.o oprofile_files.o \
oprofilefs.o oprofile_stats.o \
timer_int.o )
oprofile-y := $(DRIVER_OBJS) common.o
oprofile-$(CONFIG_CPU_MIPS32) += op_model_mipsxx.o
oprofile-$(CONFIG_CPU_MIPS64) += op_model_mipsxx.o
oprofile-$(CONFIG_CPU_RM9000) += op_model_rm9000.o
/*
* 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) 2004 by Ralf Baechle
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/oprofile.h>
#include <linux/smp.h>
#include <asm/cpu-info.h>
#include "op_impl.h"
extern struct op_mips_model op_model_mipsxx __attribute__((weak));
extern struct op_mips_model op_model_rm9000 __attribute__((weak));
static struct op_mips_model *model;
static struct op_counter_config ctr[20];
static int op_mips_setup(void)
{
/* Pre-compute the values to stuff in the hardware registers. */
model->reg_setup(ctr);
/* Configure the registers on all cpus. */
on_each_cpu(model->cpu_setup, 0, 0, 1);
return 0;
}
static int op_mips_create_files(struct super_block * sb, struct dentry * root)
{
int i;
for (i = 0; i < model->num_counters; ++i) {
struct dentry *dir;
char buf[3];
snprintf(buf, sizeof buf, "%d", i);
dir = oprofilefs_mkdir(sb, root, buf);
oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
/* Dummies. */
oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
oprofilefs_create_ulong(sb, dir, "exl", &ctr[i].exl);
oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
}
return 0;
}
static int op_mips_start(void)
{
on_each_cpu(model->cpu_start, NULL, 0, 1);
return 0;
}
static void op_mips_stop(void)
{
/* Disable performance monitoring for all counters. */
on_each_cpu(model->cpu_stop, NULL, 0, 1);
}
void __init oprofile_arch_init(struct oprofile_operations *ops)
{
struct op_mips_model *lmodel = NULL;
switch (current_cpu_data.cputype) {
case CPU_24K:
lmodel = &op_model_mipsxx;
break;
case CPU_RM9000:
lmodel = &op_model_rm9000;
break;
};
if (!lmodel)
return;
if (lmodel->init())
return;
model = lmodel;
ops->create_files = op_mips_create_files;
ops->setup = op_mips_setup;
ops->start = op_mips_start;
ops->stop = op_mips_stop;
ops->cpu_type = lmodel->cpu_type;
printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
lmodel->cpu_type);
}
void oprofile_arch_exit(void)
{
model->exit();
}
/**
* @file arch/alpha/oprofile/op_impl.h
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author Richard Henderson <rth@twiddle.net>
*/
#ifndef OP_IMPL_H
#define OP_IMPL_H 1
/* Per-counter configuration as set via oprofilefs. */
struct op_counter_config {
unsigned long enabled;
unsigned long event;
unsigned long count;
/* Dummies because I am too lazy to hack the userspace tools. */
unsigned long kernel;
unsigned long user;
unsigned long exl;
unsigned long unit_mask;
};
/* Per-architecture configury and hooks. */
struct op_mips_model {
void (*reg_setup) (struct op_counter_config *);
void (*cpu_setup) (void * dummy);
int (*init)(void);
void (*exit)(void);
void (*cpu_start)(void *args);
void (*cpu_stop)(void *args);
char *cpu_type;
unsigned char num_counters;
};
#endif
/*
* 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) 2004 by Ralf Baechle
*/
#include <linux/oprofile.h>
#include <linux/interrupt.h>
#include <linux/smp.h>
#include "op_impl.h"
#define RM9K_COUNTER1_EVENT(event) ((event) << 0)
#define RM9K_COUNTER1_SUPERVISOR (1ULL << 7)
#define RM9K_COUNTER1_KERNEL (1ULL << 8)
#define RM9K_COUNTER1_USER (1ULL << 9)
#define RM9K_COUNTER1_ENABLE (1ULL << 10)
#define RM9K_COUNTER1_OVERFLOW (1ULL << 15)
#define RM9K_COUNTER2_EVENT(event) ((event) << 16)
#define RM9K_COUNTER2_SUPERVISOR (1ULL << 23)
#define RM9K_COUNTER2_KERNEL (1ULL << 24)
#define RM9K_COUNTER2_USER (1ULL << 25)
#define RM9K_COUNTER2_ENABLE (1ULL << 26)
#define RM9K_COUNTER2_OVERFLOW (1ULL << 31)
extern unsigned int rm9000_perfcount_irq;
static struct rm9k_register_config {
unsigned int control;
unsigned int reset_counter1;
unsigned int reset_counter2;
} reg;
/* Compute all of the registers in preparation for enabling profiling. */
static void rm9000_reg_setup(struct op_counter_config *ctr)
{
unsigned int control = 0;
/* Compute the performance counter control word. */
/* For now count kernel and user mode */
if (ctr[0].enabled)
control |= RM9K_COUNTER1_EVENT(ctr[0].event) |
RM9K_COUNTER1_KERNEL |
RM9K_COUNTER1_USER |
RM9K_COUNTER1_ENABLE;
if (ctr[1].enabled)
control |= RM9K_COUNTER2_EVENT(ctr[1].event) |
RM9K_COUNTER2_KERNEL |
RM9K_COUNTER2_USER |
RM9K_COUNTER2_ENABLE;
reg.control = control;
reg.reset_counter1 = 0x80000000 - ctr[0].count;
reg.reset_counter2 = 0x80000000 - ctr[1].count;
}
/* Program all of the registers in preparation for enabling profiling. */
static void rm9000_cpu_setup (void *args)
{
uint64_t perfcount;
perfcount = ((uint64_t) reg.reset_counter2 << 32) | reg.reset_counter1;
write_c0_perfcount(perfcount);
}
static void rm9000_cpu_start(void *args)
{
/* Start all counters on current CPU */
write_c0_perfcontrol(reg.control);
}
static void rm9000_cpu_stop(void *args)
{
/* Stop all counters on current CPU */
write_c0_perfcontrol(0);
}
static irqreturn_t rm9000_perfcount_handler(int irq, void * dev_id,
struct pt_regs *regs)
{
unsigned int control = read_c0_perfcontrol();
uint32_t counter1, counter2;
uint64_t counters;
/*
* RM9000 combines two 32-bit performance counters into a single
* 64-bit coprocessor zero register. To avoid a race updating the
* registers we need to stop the counters while we're messing with
* them ...
*/
write_c0_perfcontrol(0);
counters = read_c0_perfcount();
counter1 = counters;
counter2 = counters >> 32;
if (control & RM9K_COUNTER1_OVERFLOW) {
oprofile_add_sample(regs, 0);
counter1 = reg.reset_counter1;
}
if (control & RM9K_COUNTER2_OVERFLOW) {
oprofile_add_sample(regs, 1);
counter2 = reg.reset_counter2;
}
counters = ((uint64_t)counter2 << 32) | counter1;
write_c0_perfcount(counters);
write_c0_perfcontrol(reg.control);
return IRQ_HANDLED;
}
static int rm9000_init(void)
{
return request_irq(rm9000_perfcount_irq, rm9000_perfcount_handler,
0, "Perfcounter", NULL);
}
static void rm9000_exit(void)
{
free_irq(rm9000_perfcount_irq, NULL);
}
struct op_mips_model op_model_rm9000 = {
.reg_setup = rm9000_reg_setup,
.cpu_setup = rm9000_cpu_setup,
.init = rm9000_init,
.exit = rm9000_exit,
.cpu_start = rm9000_cpu_start,
.cpu_stop = rm9000_cpu_stop,
.cpu_type = "mips/rm9000",
.num_counters = 2
};
......@@ -59,7 +59,7 @@ pcibios_align_resource(void *data, struct resource *res,
if (res->flags & IORESOURCE_IO) {
/* Make sure we start at our min on all hoses */
if (start - hose->io_resource->start < PCIBIOS_MIN_IO)
if (start < PCIBIOS_MIN_IO + hose->io_resource->start)
start = PCIBIOS_MIN_IO + hose->io_resource->start;
/*
......@@ -69,7 +69,7 @@ pcibios_align_resource(void *data, struct resource *res,
start = (start + 0x3ff) & ~0x3ff;
} else if (res->flags & IORESOURCE_MEM) {
/* Make sure we start at our min on all hoses */
if (start - hose->mem_resource->start < PCIBIOS_MIN_MEM)
if (start < PCIBIOS_MIN_MEM + hose->mem_resource->start)
start = PCIBIOS_MIN_MEM + hose->mem_resource->start;
}
......@@ -294,6 +294,8 @@ pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pcibios_resource_to_bus);
EXPORT_SYMBOL(PCIBIOS_MIN_IO);
EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
#endif
char *pcibios_setup(char *str)
......
......@@ -126,6 +126,7 @@
|| defined (CONFIG_CPU_R4X00) \
|| defined (CONFIG_CPU_R5000) \
|| defined (CONFIG_CPU_NEVADA) \
|| defined (CONFIG_CPU_TX49XX) \
|| defined (CONFIG_CPU_MIPS64)
#define KUSIZE 0x0000010000000000 /* 2^^40 */
#define KUSIZE_64 0x0000010000000000 /* 2^^40 */
......
......@@ -92,7 +92,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
__bi_flags;
a += nr >> SZLONG_LOG;
mask = 1 << (nr & SZLONG_MASK);
mask = 1UL << (nr & SZLONG_MASK);
__bi_local_irq_save(flags);
*a |= mask;
__bi_local_irq_restore(flags);
......@@ -152,7 +152,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
__bi_flags;
a += nr >> SZLONG_LOG;
mask = 1 << (nr & SZLONG_MASK);
mask = 1UL << (nr & SZLONG_MASK);
__bi_local_irq_save(flags);
*a &= ~mask;
__bi_local_irq_restore(flags);
......@@ -214,7 +214,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
__bi_flags;
a += nr >> SZLONG_LOG;
mask = 1 << (nr & SZLONG_MASK);
mask = 1UL << (nr & SZLONG_MASK);
__bi_local_irq_save(flags);
*a ^= mask;
__bi_local_irq_restore(flags);
......@@ -293,7 +293,7 @@ static inline int test_and_set_bit(unsigned long nr,
__bi_flags;
a += nr >> SZLONG_LOG;
mask = 1 << (nr & SZLONG_MASK);
mask = 1UL << (nr & SZLONG_MASK);
__bi_local_irq_save(flags);
retval = (mask & *a) != 0;
*a |= mask;
......@@ -320,7 +320,7 @@ static inline int __test_and_set_bit(unsigned long nr,
int retval;
a += nr >> SZLONG_LOG;
mask = 1 << (nr & SZLONG_MASK);
mask = 1UL << (nr & SZLONG_MASK);
retval = (mask & *a) != 0;
*a |= mask;
......@@ -385,7 +385,7 @@ static inline int test_and_clear_bit(unsigned long nr,
__bi_flags;
a += nr >> SZLONG_LOG;
mask = 1 << (nr & SZLONG_MASK);
mask = 1UL << (nr & SZLONG_MASK);
__bi_local_irq_save(flags);
retval = (mask & *a) != 0;
*a &= ~mask;
......@@ -474,7 +474,7 @@ static inline int test_and_change_bit(unsigned long nr,
__bi_flags;
a += nr >> SZLONG_LOG;
mask = 1 << (nr & SZLONG_MASK);
mask = 1UL << (nr & SZLONG_MASK);
__bi_local_irq_save(flags);
retval = (mask & *a) != 0;
*a ^= mask;
......
......@@ -195,6 +195,7 @@
#define MACH_CASIO_E55 5 /* CASIO CASSIOPEIA E-10/15/55/65 */
#define MACH_TANBAC_TB0226 6 /* TANBAC TB0226 (Mbase) */
#define MACH_TANBAC_TB0229 7 /* TANBAC TB0229 (VR4131DIMM) */
#define MACH_NEC_CMBVR4133 8 /* CMB VR4133 Board */
#define MACH_GROUP_HP_LJ 20 /* Hewlett Packard LaserJet */
#define MACH_HP_LASERJET 1
......
......@@ -27,7 +27,7 @@
#define BRK_STACKOVERFLOW 9 /* For Ada stackchecking */
#define BRK_NORLD 10 /* No rld found - not used by Linux/MIPS */
#define _BRK_THREADBP 11 /* For threads, user bp (used by debuggers) */
#define BRK_MULOVF 1023 /* Multiply overflow */
#define BRK_BUG 512 /* Used by BUG() */
#define BRK_MULOVF 1023 /* Multiply overflow */
#endif /* __ASM_BREAK_H */
......@@ -3,11 +3,13 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2003 Ralf Baechle
* Copyright (C) 2003, 2004 Ralf Baechle
*/
#ifndef __ASM_CPU_FEATURES_H
#define __ASM_CPU_FEATURES_H
#include <linux/config.h>
#include <asm/cpu.h>
#include <asm/cpu-info.h>
#include <cpu-feature-overrides.h>
......@@ -74,6 +76,25 @@
#define cpu_has_ic_fills_f_dc (cpu_data[0].icache.flags & MIPS_CACHE_IC_F_DC)
#endif
/*
* I-Cache snoops remote store. This only matters on SMP. Some multiprocessors
* such as the R10000 have I-Caches that snoop local stores; the embedded ones
* don't. For maintaining I-cache coherency this means we need to flush the
* D-cache all the way back to whever the I-cache does refills from, so the
* I-cache has a chance to see the new data at all. Then we have to flush the
* I-cache also.
* Note we may have been rescheduled and may no longer be running on the CPU
* that did the store so we can't optimize this into only doing the flush on
* the local CPU.
*/
#ifndef cpu_icache_snoops_remote_store
#ifdef CONFIG_SMP
#define cpu_icache_snoops_remote_store (cpu_data[0].icache.flags & MIPS_IC_SNOOPS_REMOTE)
#else
#define cpu_icache_snoops_remote_store 1
#endif
#endif
/*
* Certain CPUs may throw bizarre exceptions if not the whole cacheline
* contains valid instructions. For these we ensure proper alignment of
......
......@@ -37,6 +37,7 @@ struct cache_desc {
#define MIPS_CACHE_VTAG 0x00000002 /* Virtually tagged cache */
#define MIPS_CACHE_ALIASES 0x00000004 /* Cache could have aliases */
#define MIPS_CACHE_IC_F_DC 0x00000008 /* Ic can refill from D-cache */
#define MIPS_IC_SNOOPS_REMOTE 0x00000010 /* Ic snoops remote stores */
struct cpuinfo_mips {
unsigned long udelay_val;
......
......@@ -29,9 +29,9 @@
#include <linux/kernel.h>
#define db_assert(x) if (!(x)) { \
panic("assertion failed at %s:%d: %s\n", __FILE__, __LINE__, #x); }
panic("assertion failed at %s:%d: %s", __FILE__, __LINE__, #x); }
#define db_warn(x) if (!(x)) { \
printk(KERN_WARNING "warning at %s:%d: %s\n", __FILE__, __LINE__, #x); }
printk(KERN_WARNING "warning at %s:%d: %s", __FILE__, __LINE__, #x); }
#define db_verify(x, y) db_assert(x y)
#define db_verify_warn(x, y) db_warn(x y)
#define db_run(x) do { x; } while (0)
......
......@@ -23,7 +23,8 @@
#define EF_MIPS_ABI_O64 0x00002000 /* O32 extended for 64 bit. */
#define PT_MIPS_REGINFO 0x70000000
#define PT_MIPS_OPTIONS 0x70000001
#define PT_MIPS_RTPROC 0x70000001
#define PT_MIPS_OPTIONS 0x70000002
/* Flags in the e_flags field of the header */
#define EF_MIPS_NOREORDER 0x00000001
......@@ -40,9 +41,10 @@
#define DT_MIPS_ICHECKSUM 0x70000003
#define DT_MIPS_IVERSION 0x70000004
#define DT_MIPS_FLAGS 0x70000005
#define RHF_NONE 0
#define RHF_HARDWAY 1
#define RHF_NOTPOT 2
#define RHF_NONE 0x00000000
#define RHF_HARDWAY 0x00000001
#define RHF_NOTPOT 0x00000002
#define RHF_SGI_ONLY 0x00000010
#define DT_MIPS_BASE_ADDRESS 0x70000006
#define DT_MIPS_CONFLICT 0x70000008
#define DT_MIPS_LIBLIST 0x70000009
......@@ -222,18 +224,22 @@ do { current->thread.mflags &= ~MF_ABI_MASK; \
#endif /* CONFIG_MIPS64 */
extern void dump_regs(elf_greg_t *, struct pt_regs *regs);
extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *);
#define ELF_CORE_COPY_REGS(elf_regs, regs) \
dump_regs((elf_greg_t *)&(elf_regs), regs);
#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) \
dump_task_fpu(tsk, elf_fpregs)
#endif /* __KERNEL__ */
/* This one accepts IRIX binaries. */
#define irix_elf_check_arch(hdr) ((hdr)->e_machine == EM_MIPS)
#define irix_elf_check_arch(hdr) ((hdr)->e_flags & RHF_SGI_ONLY)
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE PAGE_SIZE
#define ELF_CORE_COPY_REGS(_dest,_regs) \
memcpy((char *) &_dest, (char *) _regs, \
sizeof(struct pt_regs));
/* This yields a mask that user programs can use to figure out what
instruction set this cpu supports. This could be done in userspace,
but it's not easy, and we've already done it here. */
......
/*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
* Copyright (C) 2000, 2004, 2005 MIPS Technologies, Inc.
* All rights reserved.
* Authors: Carsten Langgaard <carstenl@mips.com>
* Maciej W. Rozycki <macro@mips.com>
* Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
*
* 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
......@@ -18,7 +21,6 @@
#ifndef _ASM_GT64120_H
#define _ASM_GT64120_H
#include <linux/config.h>
#include <asm/addrspace.h>
#include <asm/byteorder.h>
......@@ -27,11 +29,12 @@
/*
* Register offset addresses
*/
/* CPU Configuration. */
#define GT_CPU_OFS 0x000
/*
* Interrupt Registers
*/
#define GT_MULTI_OFS 0x120
/* CPU Address Decode. */
#define GT_SCS10LD_OFS 0x008
#define GT_SCS10HD_OFS 0x010
#define GT_SCS32LD_OFS 0x018
......@@ -45,6 +48,7 @@
#define GT_PCI0M0LD_OFS 0x058
#define GT_PCI0M0HD_OFS 0x060
#define GT_ISD_OFS 0x068
#define GT_PCI0M1LD_OFS 0x080
#define GT_PCI0M1HD_OFS 0x088
#define GT_PCI1IOLD_OFS 0x090
......@@ -53,10 +57,14 @@
#define GT_PCI1M0HD_OFS 0x0a8
#define GT_PCI1M1LD_OFS 0x0b0
#define GT_PCI1M1HD_OFS 0x0b8
#define GT_PCI1M1LD_OFS 0x0b0
#define GT_PCI1M1HD_OFS 0x0b8
#define GT_SCS10AR_OFS 0x0d0
#define GT_SCS32AR_OFS 0x0d8
#define GT_CS20R_OFS 0x0e0
#define GT_CS3BOOTR_OFS 0x0e8
/*
* GT64120A only
*/
#define GT_PCI0IOREMAP_OFS 0x0f0
#define GT_PCI0M0REMAP_OFS 0x0f8
#define GT_PCI0M1REMAP_OFS 0x100
......@@ -64,6 +72,19 @@
#define GT_PCI1M0REMAP_OFS 0x110
#define GT_PCI1M1REMAP_OFS 0x118
/* CPU Error Report. */
#define GT_CPUERR_ADDRLO_OFS 0x070
#define GT_CPUERR_ADDRHI_OFS 0x078
#define GT_CPUERR_DATALO_OFS 0x128 /* GT-64120A only */
#define GT_CPUERR_DATAHI_OFS 0x130 /* GT-64120A only */
#define GT_CPUERR_PARITY_OFS 0x138 /* GT-64120A only */
/* CPU Sync Barrier. */
#define GT_PCI0SYNC_OFS 0x0c0
#define GT_PCI1SYNC_OFS 0x0c8
/* SDRAM and Device Address Decode. */
#define GT_SCS0LD_OFS 0x400
#define GT_SCS0HD_OFS 0x404
#define GT_SCS1LD_OFS 0x408
......@@ -83,37 +104,138 @@
#define GT_BOOTLD_OFS 0x440
#define GT_BOOTHD_OFS 0x444
#define GT_SDRAM_B0_OFS 0x44c
#define GT_ADERR_OFS 0x470
/* SDRAM Configuration. */
#define GT_SDRAM_CFG_OFS 0x448
#define GT_SDRAM_B2_OFS 0x454
#define GT_SDRAM_OPMODE_OFS 0x474
#define GT_SDRAM_BM_OFS 0x478
#define GT_SDRAM_ADDRDECODE_OFS 0x47c
#define GT_PCI0_CMD_OFS 0xc00 /* GT64120A only */
/* SDRAM Parameters. */
#define GT_SDRAM_B0_OFS 0x44c
#define GT_SDRAM_B1_OFS 0x450
#define GT_SDRAM_B2_OFS 0x454
#define GT_SDRAM_B3_OFS 0x458
/* Device Parameters. */
#define GT_DEV_B0_OFS 0x45c
#define GT_DEV_B1_OFS 0x460
#define GT_DEV_B2_OFS 0x464
#define GT_DEV_B3_OFS 0x468
#define GT_DEV_BOOT_OFS 0x46c
/* ECC. */
#define GT_ECC_ERRDATALO 0x480 /* GT-64120A only */
#define GT_ECC_ERRDATAHI 0x484 /* GT-64120A only */
#define GT_ECC_MEM 0x488 /* GT-64120A only */
#define GT_ECC_CALC 0x48c /* GT-64120A only */
#define GT_ECC_ERRADDR 0x490 /* GT-64120A only */
/* DMA Record. */
#define GT_DMA0_CNT_OFS 0x800
#define GT_DMA1_CNT_OFS 0x804
#define GT_DMA2_CNT_OFS 0x808
#define GT_DMA3_CNT_OFS 0x80c
#define GT_DMA0_SA_OFS 0x810
#define GT_DMA1_SA_OFS 0x814
#define GT_DMA2_SA_OFS 0x818
#define GT_DMA3_SA_OFS 0x81c
#define GT_DMA0_DA_OFS 0x820
#define GT_DMA1_DA_OFS 0x824
#define GT_DMA2_DA_OFS 0x828
#define GT_DMA3_DA_OFS 0x82c
#define GT_DMA0_NEXT_OFS 0x830
#define GT_DMA1_NEXT_OFS 0x834
#define GT_DMA2_NEXT_OFS 0x838
#define GT_DMA3_NEXT_OFS 0x83c
#define GT_DMA0_CUR_OFS 0x870
#define GT_DMA1_CUR_OFS 0x874
#define GT_DMA2_CUR_OFS 0x878
#define GT_DMA3_CUR_OFS 0x87c
/* DMA Channel Control. */
#define GT_DMA0_CTRL_OFS 0x840
#define GT_DMA1_CTRL_OFS 0x844
#define GT_DMA2_CTRL_OFS 0x848
#define GT_DMA3_CTRL_OFS 0x84c
/* DMA Arbiter. */
#define GT_DMA_ARB_OFS 0x860
/* Timer/Counter. */
#define GT_TC0_OFS 0x850
#define GT_TC1_OFS 0x854
#define GT_TC2_OFS 0x858
#define GT_TC3_OFS 0x85c
#define GT_TC_CONTROL_OFS 0x864
/* PCI Internal. */
#define GT_PCI0_CMD_OFS 0xc00
#define GT_PCI0_TOR_OFS 0xc04
#define GT_PCI0_BS_SCS10_OFS 0xc08
#define GT_PCI0_BS_SCS32_OFS 0xc0c
#define GT_INTRCAUSE_OFS 0xc18
#define GT_INTRMASK_OFS 0xc1c /* GT64120A only */
#define GT_PCI0_BS_CS20_OFS 0xc10
#define GT_PCI0_BS_CS3BT_OFS 0xc14
#define GT_PCI1_IACK_OFS 0xc30
#define GT_PCI0_IACK_OFS 0xc34
#define GT_PCI0_BARE_OFS 0xc3c
#define GT_HINTRCAUSE_OFS 0xc98 /* GT64120A only */
#define GT_HINTRMASK_OFS 0xc9c /* GT64120A only */
#define GT_PCI1_CFGADDR_OFS 0xcf0 /* GT64120A only */
#define GT_PCI1_CFGDATA_OFS 0xcf4 /* GT64120A only */
#define GT_PCI0_PREFMBR_OFS 0xc40
#define GT_PCI0_SCS10_BAR_OFS 0xc48
#define GT_PCI0_SCS32_BAR_OFS 0xc4c
#define GT_PCI0_CS20_BAR_OFS 0xc50
#define GT_PCI0_CS3BT_BAR_OFS 0xc54
#define GT_PCI0_SSCS10_BAR_OFS 0xc58
#define GT_PCI0_SSCS32_BAR_OFS 0xc5c
#define GT_PCI0_SCS3BT_BAR_OFS 0xc64
#define GT_PCI1_CMD_OFS 0xc80
#define GT_PCI1_TOR_OFS 0xc84
#define GT_PCI1_BS_SCS10_OFS 0xc88
#define GT_PCI1_BS_SCS32_OFS 0xc8c
#define GT_PCI1_BS_CS20_OFS 0xc90
#define GT_PCI1_BS_CS3BT_OFS 0xc94
#define GT_PCI1_BARE_OFS 0xcbc
#define GT_PCI1_PREFMBR_OFS 0xcc0
#define GT_PCI1_SCS10_BAR_OFS 0xcc8
#define GT_PCI1_SCS32_BAR_OFS 0xccc
#define GT_PCI1_CS20_BAR_OFS 0xcd0
#define GT_PCI1_CS3BT_BAR_OFS 0xcd4
#define GT_PCI1_SSCS10_BAR_OFS 0xcd8
#define GT_PCI1_SSCS32_BAR_OFS 0xcdc
#define GT_PCI1_SCS3BT_BAR_OFS 0xce4
#define GT_PCI1_CFGADDR_OFS 0xcf0
#define GT_PCI1_CFGDATA_OFS 0xcf4
#define GT_PCI0_CFGADDR_OFS 0xcf8
#define GT_PCI0_CFGDATA_OFS 0xcfc
/* Interrupts. */
#define GT_INTRCAUSE_OFS 0xc18
#define GT_INTRMASK_OFS 0xc1c
#define GT_PCI0_ICMASK_OFS 0xc24
#define GT_PCI0_SERR0MASK_OFS 0xc28
#define GT_CPU_INTSEL_OFS 0xc70
#define GT_PCI0_INTSEL_OFS 0xc74
#define GT_HINTRCAUSE_OFS 0xc98
#define GT_HINTRMASK_OFS 0xc9c
#define GT_PCI0_HICMASK_OFS 0xca4
#define GT_PCI1_SERR1MASK_OFS 0xca8
/*
* Timer/Counter. GT64120A only.
*/
#define GT_TC0_OFS 0x850
#define GT_TC1_OFS 0x854
#define GT_TC2_OFS 0x858
#define GT_TC3_OFS 0x85C
#define GT_TC_CONTROL_OFS 0x864
/*
* I2O Support Registers
......@@ -177,6 +299,15 @@
#define GT_CPU_WR_DDDD 1
#define GT_PCI_DCRM_SHF 21
#define GT_PCI_LD_SHF 0
#define GT_PCI_LD_MSK (MSK(15) << GT_PCI_LD_SHF)
#define GT_PCI_HD_SHF 0
#define GT_PCI_HD_MSK (MSK(7) << GT_PCI_HD_SHF)
#define GT_PCI_REMAP_SHF 0
#define GT_PCI_REMAP_MSK (MSK(11) << GT_PCI_REMAP_SHF)
#define GT_CFGADDR_CFGEN_SHF 31
#define GT_CFGADDR_CFGEN_MSK (MSK(1) << GT_CFGADDR_CFGEN_SHF)
#define GT_CFGADDR_CFGEN_BIT GT_CFGADDR_CFGEN_MSK
......
......@@ -3,14 +3,13 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1997, 1998, 1999, 2000, 2001 by Ralf Baechle
* Copyright (C) 1997, 98, 99, 2000, 01, 05 Ralf Baechle (ralf@linux-mips.org)
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
* Copyright (C) 2001 MIPS Technologies, Inc.
*/
#ifndef _ASM_HARDIRQ_H
#define _ASM_HARDIRQ_H
#include <linux/config.h>
#include <linux/threads.h>
#include <linux/irq.h>
......
......@@ -16,6 +16,10 @@
sll $0, $0, 1
.endm
.macro _ehb
sll $0, $0, 3
.endm
/*
* RM9000 hazards. When the JTLB is updated by tlbwi or tlbwr, a subsequent
* use of the JTLB for instructions should not occur for 4 cpu cycles and use
......@@ -23,17 +27,19 @@
*/
#ifdef CONFIG_CPU_RM9000
#define mtc0_tlbw_hazard \
.set push; \
.set mips32; \
_ssnop; _ssnop; _ssnop; _ssnop; \
.macro mtc0_tlbw_hazard
.set push
.set mips32
_ssnop; _ssnop; _ssnop; _ssnop
.set pop
.endm
#define tlbw_eret_hazard \
.set push; \
.set mips32; \
_ssnop; _ssnop; _ssnop; _ssnop; \
.macro tlbw_eret_hazard
.set push
.set mips32
_ssnop; _ssnop; _ssnop; _ssnop
.set pop
.endm
#else
......@@ -43,9 +49,12 @@
* hazard so this is nice trick to have an optimal code for a range of
* processors.
*/
#define mtc0_tlbw_hazard \
.macro mtc0_tlbw_hazard
b . + 8
#define tlbw_eret_hazard
.endm
.macro tlbw_eret_hazard
.endm
#endif
/*
......@@ -58,31 +67,51 @@
/*
* Use a macro for ehb unless explicit support for MIPSR2 is enabled
*/
.macro ehb
sll $0, $0, 3
.endm
#define irq_enable_hazard \
ehb # irq_enable_hazard
#define irq_enable_hazard
_ehb
#define irq_disable_hazard \
ehb # irq_disable_hazard
#define irq_disable_hazard
_ehb
#else
#elif defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_RM9000)
/*
* R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer.
*/
#define irq_enable_hazard
#define irq_disable_hazard
#else
/*
* Classic MIPS needs 1 - 3 nops or ssnops
*/
#define irq_enable_hazard
#define irq_disable_hazard \
_ssnop; _ssnop; _ssnop
#endif
#else /* __ASSEMBLY__ */
__asm__(
" .macro _ssnop \n\t"
" sll $0, $2, 1 \n\t"
" .endm \n\t"
" \n\t"
" .macro _ehb \n\t"
" sll $0, $0, 3 \n\t"
" .endm \n\t");
#ifdef CONFIG_CPU_RM9000
/*
* RM9000 hazards. When the JTLB is updated by tlbwi or tlbwr, a subsequent
* use of the JTLB for instructions should not occur for 4 cpu cycles and use
* for data translations should not occur for 3 cpu cycles.
*/
#ifdef CONFIG_CPU_RM9000
#define mtc0_tlbw_hazard() \
__asm__ __volatile__( \
......@@ -125,27 +154,23 @@
* Use a macro for ehb unless explicit support for MIPSR2 is enabled
*/
__asm__(
" .macro ehb \n\t"
" sll $0, $0, 3 \n\t"
" .endm \n\t"
" \n\t"
" .macro\tirq_enable_hazard \n\t"
" ehb \n\t"
" _ehb \n\t"
" .endm \n\t"
" \n\t"
" .macro\tirq_disable_hazard \n\t"
" ehb \n\t"
" _ehb \n\t"
" .endm");
#define irq_enable_hazard() \
__asm__ __volatile__( \
"ehb\t\t\t\t# irq_enable_hazard")
"_ehb\t\t\t\t# irq_enable_hazard")
#define irq_disable_hazard() \
__asm__ __volatile__( \
"ehb\t\t\t\t# irq_disable_hazard")
"_ehb\t\t\t\t# irq_disable_hazard")
#elif defined(CONFIG_CPU_R10000)
#elif defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_RM9000)
/*
* R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer.
......@@ -170,10 +195,6 @@ __asm__(
*/
__asm__(
" .macro _ssnop \n\t"
" sll $0, $2, 1 \n\t"
" .endm \n\t"
" \n\t"
" # \n\t"
" # There is a hazard but we do not care \n\t"
" # \n\t"
......
......@@ -6,21 +6,26 @@
* Copyright (C) 1994, 1995 Waldorf GmbH
* Copyright (C) 1994 - 2000 Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
* Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved.
* Author: Maciej W. Rozycki <macro@mips.com>
*/
#ifndef _ASM_IO_H
#define _ASM_IO_H
#include <linux/config.h>
#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <asm/addrspace.h>
#include <asm/bug.h>
#include <asm/byteorder.h>
#include <asm/cpu.h>
#include <asm/cpu-features.h>
#include <asm/page.h>
#include <asm/pgtable-bits.h>
#include <asm/processor.h>
#include <asm/byteorder.h>
#include <mangle-port.h>
/*
......@@ -29,34 +34,54 @@
#undef CONF_SLOWDOWN_IO
/*
* Sane hardware offers swapping of I/O space accesses in hardware; less
* sane hardware forces software to fiddle with this ...
* Raw operations are never swapped in software. Otoh values that raw
* operations are working on may or may not have been swapped by the bus
* hardware. An example use would be for flash memory that's used for
* execute in place.
*/
#if defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)
# define __raw_ioswabb(x) (x)
# define __raw_ioswabw(x) (x)
# define __raw_ioswabl(x) (x)
# define __raw_ioswabq(x) (x)
#define __ioswab8(x) (x)
/*
* Sane hardware offers swapping of PCI/ISA I/O space accesses in hardware;
* less sane hardware forces software to fiddle with this...
*/
#if defined(CONFIG_SWAP_IO_SPACE)
#ifdef CONFIG_SGI_IP22
# define ioswabb(x) (x)
# ifdef CONFIG_SGI_IP22
/*
* IP22 seems braindead enough to swap 16bits values in hardware, but
* not 32bits. Go figure... Can't tell without documentation.
*/
#define __ioswab16(x) (x)
#else
#define __ioswab16(x) swab16(x)
#endif
#define __ioswab32(x) swab32(x)
#define __ioswab64(x) swab64(x)
# define ioswabw(x) (x)
# else
# define ioswabw(x) le16_to_cpu(x)
# endif
# define ioswabl(x) le32_to_cpu(x)
# define ioswabq(x) le64_to_cpu(x)
#else
#define __ioswab8(x) (x)
#define __ioswab16(x) (x)
#define __ioswab32(x) (x)
#define __ioswab64(x) (x)
# define ioswabb(x) (x)
# define ioswabw(x) (x)
# define ioswabl(x) (x)
# define ioswabq(x) (x)
#endif
/*
* Native bus accesses never swapped.
*/
#define bus_ioswabb(x) (x)
#define bus_ioswabw(x) (x)
#define bus_ioswabl(x) (x)
#define bus_ioswabq(x) (x)
#define __bus_ioswabq bus_ioswabq
#define IO_SPACE_LIMIT 0xffff
/*
......@@ -239,114 +264,214 @@ static inline void * __ioremap_mode(phys_t offset, unsigned long size,
static inline void iounmap(volatile void __iomem *addr)
{
if (cpu_has_64bits)
if (cpu_has_64bit_addresses)
return;
__iounmap(addr);
}
#define __raw_readb(addr) \
(*(volatile unsigned char *) __swizzle_addr_b((unsigned long)(addr)))
#define __raw_readw(addr) \
(*(volatile unsigned short *) __swizzle_addr_w((unsigned long)(addr)))
#define __raw_readl(addr) \
(*(volatile unsigned int *) __swizzle_addr_l((unsigned long)(addr)))
#ifdef CONFIG_MIPS32
#define ____raw_readq(addr) \
({ \
u64 __res; \
#define __BUILD_MEMORY_SINGLE(pfx, bwlq, type, irq) \
\
static inline void pfx##write##bwlq(type val, \
volatile void __iomem *mem) \
{ \
volatile type *__mem; \
type __val; \
\
__mem = (void *)__swizzle_addr_##bwlq((unsigned long)(mem)); \
\
__val = pfx##ioswab##bwlq(val); \
\
__asm__ __volatile__ ( \
" .set mips3 # ____raw_readq \n" \
" ld %L0, (%1) \n" \
" dsra32 %M0, %L0, 0 \n" \
" sll %L0, %L0, 0 \n" \
" .set mips0 \n" \
: "=r" (__res) \
: "r" (__swizzle_addr_q((unsigned long)(addr)))); \
__res; \
})
#define __raw_readq(addr) \
({ \
if (sizeof(type) != sizeof(u64) || sizeof(u64) == sizeof(long)) \
*__mem = __val; \
else if (cpu_has_64bits) { \
unsigned long __flags; \
u64 __res; \
type __tmp; \
\
if (irq) \
local_irq_save(__flags); \
__res = ____raw_readq(addr); \
__asm__ __volatile__( \
".set mips3" "\t\t# __writeq""\n\t" \
"dsll32 %L0, %L0, 0" "\n\t" \
"dsrl32 %L0, %L0, 0" "\n\t" \
"dsll32 %M0, %M0, 0" "\n\t" \
"or %L0, %L0, %M0" "\n\t" \
"sd %L0, %2" "\n\t" \
".set mips0" "\n" \
: "=r" (__tmp) \
: "0" (__val), "m" (*__mem)); \
if (irq) \
local_irq_restore(__flags); \
__res; \
})
#endif
#ifdef CONFIG_MIPS64
#define ____raw_readq(addr) \
(*(volatile unsigned long *)__swizzle_addr_q((unsigned long)(addr)))
#define __raw_readq(addr) ____raw_readq(addr)
#endif
#define readb(addr) __ioswab8(__raw_readb(addr))
#define readw(addr) __ioswab16(__raw_readw(addr))
#define readl(addr) __ioswab32(__raw_readl(addr))
#define readq(addr) __ioswab64(__raw_readq(addr))
#define readb_relaxed(addr) readb(addr)
#define readw_relaxed(addr) readw(addr)
#define readl_relaxed(addr) readl(addr)
#define readq_relaxed(addr) readq(addr)
#define __raw_writeb(b,addr) \
do { \
((*(volatile unsigned char *)__swizzle_addr_b((unsigned long)(addr))) = (b)); \
} while (0)
#define __raw_writew(w,addr) \
do { \
((*(volatile unsigned short *)__swizzle_addr_w((unsigned long)(addr))) = (w)); \
} while (0)
#define __raw_writel(l,addr) \
do { \
((*(volatile unsigned int *)__swizzle_addr_l((unsigned long)(addr))) = (l)); \
} while (0)
#ifdef CONFIG_MIPS32
#define ____raw_writeq(val,addr) \
do { \
u64 __tmp; \
} else \
BUG(); \
} \
\
__asm__ __volatile__ ( \
" .set mips3 \n" \
" dsll32 %L0, %L0, 0 # ____raw_writeq\n" \
" dsrl32 %L0, %L0, 0 \n" \
" dsll32 %M0, %M0, 0 \n" \
" or %L0, %L0, %M0 \n" \
" sd %L0, (%2) \n" \
" .set mips0 \n" \
: "=r" (__tmp) \
: "0" ((unsigned long long)val), \
"r" (__swizzle_addr_q((unsigned long)(addr)))); \
} while (0)
#define __raw_writeq(val,addr) \
do { \
static inline type pfx##read##bwlq(volatile void __iomem *mem) \
{ \
volatile type *__mem; \
type __val; \
\
__mem = (void *)__swizzle_addr_##bwlq((unsigned long)(mem)); \
\
if (sizeof(type) != sizeof(u64) || sizeof(u64) == sizeof(long)) \
__val = *__mem; \
else if (cpu_has_64bits) { \
unsigned long __flags; \
\
local_irq_save(__flags); \
____raw_writeq(val, addr); \
__asm__ __volatile__( \
".set mips3" "\t\t# __readq" "\n\t" \
"ld %L0, %1" "\n\t" \
"dsra32 %M0, %L0, 0" "\n\t" \
"sll %L0, %L0, 0" "\n\t" \
".set mips0" "\n" \
: "=r" (__val) \
: "m" (*__mem)); \
local_irq_restore(__flags); \
} while (0)
#endif
#ifdef CONFIG_MIPS64
#define ____raw_writeq(q,addr) \
do { \
*(volatile unsigned long *)__swizzle_addr_q((unsigned long)(addr)) = (q); \
} while (0)
} else { \
__val = 0; \
BUG(); \
} \
\
return pfx##ioswab##bwlq(__val); \
}
#define __raw_writeq(q,addr) ____raw_writeq(q, addr)
#endif
#define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, p, slow) \
\
static inline void pfx##out##bwlq##p(type val, unsigned long port) \
{ \
volatile type *__addr; \
type __val; \
\
port = __swizzle_addr_##bwlq(port); \
__addr = (void *)(mips_io_port_base + port); \
\
__val = pfx##ioswab##bwlq(val); \
\
if (sizeof(type) != sizeof(u64)) { \
*__addr = __val; \
slow; \
} else \
BUILD_BUG(); \
} \
\
static inline type pfx##in##bwlq##p(unsigned long port) \
{ \
volatile type *__addr; \
type __val; \
\
port = __swizzle_addr_##bwlq(port); \
__addr = (void *)(mips_io_port_base + port); \
\
if (sizeof(type) != sizeof(u64)) { \
__val = *__addr; \
slow; \
} else { \
__val = 0; \
BUILD_BUG(); \
} \
\
return pfx##ioswab##bwlq(__val); \
}
#define __BUILD_MEMORY_PFX(bus, bwlq, type) \
\
__BUILD_MEMORY_SINGLE(bus, bwlq, type, 1)
#define __BUILD_IOPORT_PFX(bus, bwlq, type) \
\
__BUILD_IOPORT_SINGLE(bus, bwlq, type, ,) \
__BUILD_IOPORT_SINGLE(bus, bwlq, type, _p, SLOW_DOWN_IO)
#define BUILDIO(bwlq, type) \
\
__BUILD_MEMORY_PFX(, bwlq, type) \
__BUILD_MEMORY_PFX(__raw_, bwlq, type) \
__BUILD_MEMORY_PFX(bus_, bwlq, type) \
__BUILD_IOPORT_PFX(, bwlq, type) \
__BUILD_IOPORT_PFX(__raw_, bwlq, type)
#define __BUILDIO(bwlq, type) \
\
__BUILD_MEMORY_SINGLE(__bus_, bwlq, type, 0)
BUILDIO(b, u8)
BUILDIO(w, u16)
BUILDIO(l, u32)
BUILDIO(q, u64)
__BUILDIO(q, u64)
#define readb_relaxed readb
#define readw_relaxed readw
#define readl_relaxed readl
#define readq_relaxed readq
/*
* Some code tests for these symbols
*/
#define readq readq
#define writeq writeq
#define __BUILD_MEMORY_STRING(bwlq, type) \
\
static inline void writes##bwlq(volatile void __iomem *mem, void *addr, \
unsigned int count) \
{ \
volatile type *__addr = addr; \
\
while (count--) { \
__raw_write##bwlq(*__addr, mem); \
__addr++; \
} \
} \
\
static inline void reads##bwlq(volatile void __iomem *mem, void *addr, \
unsigned int count) \
{ \
volatile type *__addr = addr; \
\
while (count--) { \
*__addr = __raw_read##bwlq(mem); \
__addr++; \
} \
}
#define __BUILD_IOPORT_STRING(bwlq, type) \
\
static inline void outs##bwlq(unsigned long port, void *addr, \
unsigned int count) \
{ \
volatile type *__addr = addr; \
\
while (count--) { \
__raw_out##bwlq(*__addr, port); \
__addr++; \
} \
} \
\
static inline void ins##bwlq(unsigned long port, void *addr, \
unsigned int count) \
{ \
volatile type *__addr = addr; \
\
while (count--) { \
*__addr = __raw_in##bwlq(port); \
__addr++; \
} \
}
#define BUILDSTRING(bwlq, type) \
\
__BUILD_MEMORY_STRING(bwlq, type) \
__BUILD_IOPORT_STRING(bwlq, type)
BUILDSTRING(b, u8)
BUILDSTRING(w, u16)
BUILDSTRING(l, u32)
BUILDSTRING(q, u64)
#define writeb(b,addr) __raw_writeb(__ioswab8(b),(addr))
#define writew(w,addr) __raw_writew(__ioswab16(w),(addr))
#define writel(l,addr) __raw_writel(__ioswab32(l),(addr))
#define writeq(q,addr) __raw_writeq(__ioswab64(q),(addr))
/* Depends on MIPS II instruction set */
#define mmiowb() asm volatile ("sync" ::: "memory")
......@@ -394,7 +519,7 @@ do { \
* address should have been obtained by ioremap.
* Returns 1 on a match.
*/
static inline int check_signature(unsigned long io_addr,
static inline int check_signature(char __iomem *io_addr,
const unsigned char *signature, int length)
{
int retval = 0;
......@@ -410,177 +535,6 @@ static inline int check_signature(unsigned long io_addr,
return retval;
}
static inline void __outb(unsigned char val, unsigned long port)
{
port = __swizzle_addr_b(port);
*(volatile u8 *)(mips_io_port_base + port) = __ioswab8(val);
}
static inline void __outw(unsigned short val, unsigned long port)
{
port = __swizzle_addr_w(port);
*(volatile u16 *)(mips_io_port_base + port) = __ioswab16(val);
}
static inline void __outl(unsigned int val, unsigned long port)
{
port = __swizzle_addr_l(port);
*(volatile u32 *)(mips_io_port_base + port) = __ioswab32(val);
}
static inline void __outb_p(unsigned char val, unsigned long port)
{
port = __swizzle_addr_b(port);
*(volatile u8 *)(mips_io_port_base + port) = __ioswab8(val);
SLOW_DOWN_IO;
}
static inline void __outw_p(unsigned short val, unsigned long port)
{
port = __swizzle_addr_w(port);
*(volatile u16 *)(mips_io_port_base + port) = __ioswab16(val);
SLOW_DOWN_IO;
}
static inline void __outl_p(unsigned int val, unsigned long port)
{
port = __swizzle_addr_l(port);
*(volatile u32 *)(mips_io_port_base + port) = __ioswab32(val);
SLOW_DOWN_IO;
}
#define outb(val, port) __outb(val, port)
#define outw(val, port) __outw(val, port)
#define outl(val, port) __outl(val, port)
#define outb_p(val, port) __outb_p(val, port)
#define outw_p(val, port) __outw_p(val, port)
#define outl_p(val, port) __outl_p(val, port)
static inline unsigned char __inb(unsigned long port)
{
port = __swizzle_addr_b(port);
return __ioswab8(*(volatile u8 *)(mips_io_port_base + port));
}
static inline unsigned short __inw(unsigned long port)
{
port = __swizzle_addr_w(port);
return __ioswab16(*(volatile u16 *)(mips_io_port_base + port));
}
static inline unsigned int __inl(unsigned long port)
{
port = __swizzle_addr_l(port);
return __ioswab32(*(volatile u32 *)(mips_io_port_base + port));
}
static inline unsigned char __inb_p(unsigned long port)
{
u8 __val;
port = __swizzle_addr_b(port);
__val = *(volatile u8 *)(mips_io_port_base + port);
SLOW_DOWN_IO;
return __ioswab8(__val);
}
static inline unsigned short __inw_p(unsigned long port)
{
u16 __val;
port = __swizzle_addr_w(port);
__val = *(volatile u16 *)(mips_io_port_base + port);
SLOW_DOWN_IO;
return __ioswab16(__val);
}
static inline unsigned int __inl_p(unsigned long port)
{
u32 __val;
port = __swizzle_addr_l(port);
__val = *(volatile u32 *)(mips_io_port_base + port);
SLOW_DOWN_IO;
return __ioswab32(__val);
}
#define inb(port) __inb(port)
#define inw(port) __inw(port)
#define inl(port) __inl(port)
#define inb_p(port) __inb_p(port)
#define inw_p(port) __inw_p(port)
#define inl_p(port) __inl_p(port)
static inline void __outsb(unsigned long port, void *addr, unsigned int count)
{
while (count--) {
outb(*(u8 *)addr, port);
addr++;
}
}
static inline void __insb(unsigned long port, void *addr, unsigned int count)
{
while (count--) {
*(u8 *)addr = inb(port);
addr++;
}
}
static inline void __outsw(unsigned long port, void *addr, unsigned int count)
{
while (count--) {
outw(*(u16 *)addr, port);
addr += 2;
}
}
static inline void __insw(unsigned long port, void *addr, unsigned int count)
{
while (count--) {
*(u16 *)addr = inw(port);
addr += 2;
}
}
static inline void __outsl(unsigned long port, void *addr, unsigned int count)
{
while (count--) {
outl(*(u32 *)addr, port);
addr += 4;
}
}
static inline void __insl(unsigned long port, void *addr, unsigned int count)
{
while (count--) {
*(u32 *)addr = inl(port);
addr += 4;
}
}
#define outsb(port, addr, count) __outsb(port, addr, count)
#define insb(port, addr, count) __insb(port, addr, count)
#define outsw(port, addr, count) __outsw(port, addr, count)
#define insw(port, addr, count) __insw(port, addr, count)
#define outsl(port, addr, count) __outsl(port, addr, count)
#define insl(port, addr, count) __insl(port, addr, count)
/*
* The caches on some architectures aren't dma-coherent and have need to
* handle this in software. There are three types of operations that
......
......@@ -15,5 +15,6 @@
extern void mips_cpu_irq_init(int irq_base);
extern void rm7k_cpu_irq_init(int irq_base);
extern void rm9k_cpu_irq_init(int irq_base);
#endif /* _ASM_IRQ_CPU_H */
/*
* Registers for the SGS-Thomson M48T37 Timekeeper RAM chip
*/
#ifndef _ASM_M48T37_H
#define _ASM_M48T37_H
#include <linux/spinlock.h>
extern spinlock_t rtc_lock;
struct m48t37_rtc {
volatile u8 pad[0x7ff0]; /* NVRAM */
volatile u8 flags;
volatile u8 century;
volatile u8 alarm_sec;
volatile u8 alarm_min;
volatile u8 alarm_hour;
volatile u8 alarm_data;
volatile u8 interrupts;
volatile u8 watchdog;
volatile u8 control;
volatile u8 sec;
volatile u8 min;
volatile u8 hour;
volatile u8 day;
volatile u8 date;
volatile u8 month;
volatile u8 year;
};
#define M48T37_RTC_SET 0x80
#define M48T37_RTC_STOPPED 0x80
#define M48T37_RTC_READ 0x40
#endif /* _ASM_M48T37_H */
......@@ -16,6 +16,8 @@
#ifdef __KERNEL__
#include <linux/config.h>
#include <linux/pci.h>
#include <linux/stddef.h>
#ifndef MAX_HWIFS
# ifdef CONFIG_BLK_DEV_IDEPCI
......@@ -27,32 +29,68 @@
#define IDE_ARCH_OBSOLETE_DEFAULTS
static __inline__ int ide_probe_legacy(void)
{
#ifdef CONFIG_PCI
struct pci_dev *dev;
if ((dev = pci_get_class(PCI_CLASS_BRIDGE_EISA << 8, NULL)) != NULL ||
(dev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL)) != NULL) {
pci_dev_put(dev);
return 1;
}
return 0;
#elif defined(CONFIG_EISA) || defined(CONFIG_ISA)
return 1;
#else
return 0;
#endif
}
static __inline__ int ide_default_irq(unsigned long base)
{
if (ide_probe_legacy())
switch (base) {
case 0x1f0: return 14;
case 0x170: return 15;
case 0x1e8: return 11;
case 0x168: return 10;
case 0x1e0: return 8;
case 0x160: return 12;
case 0x1f0:
return 14;
case 0x170:
return 15;
case 0x1e8:
return 11;
case 0x168:
return 10;
case 0x1e0:
return 8;
case 0x160:
return 12;
default:
return 0;
}
else
return 0;
}
static __inline__ unsigned long ide_default_io_base(int index)
{
if (ide_probe_legacy())
switch (index) {
case 0: return 0x1f0;
case 1: return 0x170;
case 2: return 0x1e8;
case 3: return 0x168;
case 4: return 0x1e0;
case 5: return 0x160;
case 0:
return 0x1f0;
case 1:
return 0x170;
case 2:
return 0x1e8;
case 3:
return 0x168;
case 4:
return 0x1e0;
case 5:
return 0x160;
default:
return 0;
}
else
return 0;
}
#define IDE_ARCH_OBSOLETE_INIT
......@@ -64,7 +102,17 @@ static __inline__ unsigned long ide_default_io_base(int index)
#define ide_init_default_irq(base) ide_default_irq(base)
#endif
#include <asm-generic/ide_iops.h>
/* MIPS port and memory-mapped I/O string operations. */
#define __ide_insw insw
#define __ide_insl insl
#define __ide_outsw outsw
#define __ide_outsl outsl
#define __ide_mm_insw readsw
#define __ide_mm_insl readsl
#define __ide_mm_outsw writesw
#define __ide_mm_outsl writesl
#endif /* __KERNEL__ */
......
......@@ -533,31 +533,50 @@
#ifndef __ASSEMBLY__
/*
* Functions to access the r10k performance counter and control registers
* Functions to access the R10000 performance counters. These are basically
* mfc0 and mtc0 instructions from and to coprocessor register with a 5-bit
* performance counter number encoded into bits 1 ... 5 of the instruction.
* Only performance counters 0 to 1 actually exist, so for a non-R10000 aware
* disassembler these will look like an access to sel 0 or 1.
*/
#define read_r10k_perf_cntr(counter) \
({ unsigned int __res; \
({ \
unsigned int __res; \
__asm__ __volatile__( \
"mfpc\t%0, "STR(counter) \
: "=r" (__res)); \
__res;})
"mfpc\t%0, %1" \
: "=r" (__res) \
: "i" (counter)); \
\
__res; \
})
#define write_r10k_perf_cntr(counter,val) \
do { \
__asm__ __volatile__( \
"mtpc\t%0, "STR(counter) \
: : "r" (val));
"mtpc\t%0, %1" \
: \
: "r" (val), "i" (counter)); \
} while (0)
#define read_r10k_perf_cntl(counter) \
({ unsigned int __res; \
#define read_r10k_perf_event(counter) \
({ \
unsigned int __res; \
__asm__ __volatile__( \
"mfps\t%0, "STR(counter) \
: "=r" (__res)); \
__res;})
"mfps\t%0, %1" \
: "=r" (__res) \
: "i" (counter)); \
\
__res; \
})
#define write_r10k_perf_cntl(counter,val) \
do { \
__asm__ __volatile__( \
"mtps\t%0, "STR(counter) \
: : "r" (val));
"mtps\t%0, %1" \
: \
: "r" (val), "i" (counter)); \
} while (0)
/*
* Macros to access the system control coprocessor
......@@ -579,8 +598,10 @@
})
#define __read_64bit_c0_register(source, sel) \
({ unsigned long __res; \
if (sel == 0) \
({ unsigned long long __res; \
if (sizeof(unsigned long) == 4) \
__res = __read_64bit_c0_split(source, sel); \
else if (sel == 0) \
__asm__ __volatile__( \
".set\tmips3\n\t" \
"dmfc0\t%0, " #source "\n\t" \
......@@ -611,7 +632,9 @@ do { \
#define __write_64bit_c0_register(register, sel, value) \
do { \
if (sel == 0) \
if (sizeof(unsigned long) == 4) \
__write_64bit_c0_split(register, sel, value); \
else if (sel == 0) \
__asm__ __volatile__( \
".set\tmips3\n\t" \
"dmtc0\t%z0, " #register "\n\t" \
......@@ -627,8 +650,8 @@ do { \
#define __read_ulong_c0_register(reg, sel) \
((sizeof(unsigned long) == 4) ? \
__read_32bit_c0_register(reg, sel) : \
__read_64bit_c0_register(reg, sel))
(unsigned long) __read_32bit_c0_register(reg, sel) : \
(unsigned long) __read_64bit_c0_register(reg, sel))
#define __write_ulong_c0_register(reg, sel, val) \
do { \
......@@ -822,6 +845,10 @@ do { \
#define read_c0_framemask() __read_32bit_c0_register($21, 0)
#define write_c0_framemask(val) __write_32bit_c0_register($21, 0, val)
/* RM9000 PerfControl performance counter control register */
#define read_c0_perfcontrol() __read_32bit_c0_register($22, 0)
#define write_c0_perfcontrol(val) __write_32bit_c0_register($22, 0, val)
#define read_c0_diag() __read_32bit_c0_register($22, 0)
#define write_c0_diag(val) __write_32bit_c0_register($22, 0, val)
......@@ -846,6 +873,30 @@ do { \
#define read_c0_depc() __read_ulong_c0_register($24, 0)
#define write_c0_depc(val) __write_ulong_c0_register($24, 0, val)
/*
* MIPS32 / MIPS64 performance counters
*/
#define read_c0_perfctrl0() __read_32bit_c0_register($25, 0)
#define write_c0_perfctrl0(val) __write_32bit_c0_register($25, 0, val)
#define read_c0_perfcntr0() __read_32bit_c0_register($25, 1)
#define write_c0_perfcntr0(val) __write_32bit_c0_register($25, 1, val)
#define read_c0_perfctrl1() __read_32bit_c0_register($25, 2)
#define write_c0_perfctrl1(val) __write_32bit_c0_register($25, 2, val)
#define read_c0_perfcntr1() __read_32bit_c0_register($25, 3)
#define write_c0_perfcntr1(val) __write_32bit_c0_register($25, 3, val)
#define read_c0_perfctrl2() __read_32bit_c0_register($25, 4)
#define write_c0_perfctrl2(val) __write_32bit_c0_register($25, 4, val)
#define read_c0_perfcntr2() __read_32bit_c0_register($25, 5)
#define write_c0_perfcntr2(val) __write_32bit_c0_register($25, 5, val)
#define read_c0_perfctrl3() __read_32bit_c0_register($25, 6)
#define write_c0_perfctrl3(val) __write_32bit_c0_register($25, 6, val)
#define read_c0_perfcntr3() __read_32bit_c0_register($25, 7)
#define write_c0_perfcntr3(val) __write_32bit_c0_register($25, 7, val)
/* RM9000 PerfCount performance counter register */
#define read_c0_perfcount() __read_64bit_c0_register($25, 0)
#define write_c0_perfcount(val) __write_64bit_c0_register($25, 0, val)
#define read_c0_ecc() __read_32bit_c0_register($26, 0)
#define write_c0_ecc(val) __write_32bit_c0_register($26, 0, val)
......
......@@ -19,26 +19,30 @@
#include <asm/tlbflush.h>
/*
* For the fast tlb miss handlers, we currently keep a per cpu array
* of pointers to the current pgd for each processor. Also, the proc.
* id is stuffed into the context register. This should be changed to
* use the processor id via current->processor, where current is stored
* in watchhi/lo. The context register should be used to contiguously
* map the page tables.
* For the fast tlb miss handlers, we keep a per cpu array of pointers
* to the current pgd for each processor. Also, the proc. id is stuffed
* into the context register.
*/
extern unsigned long pgd_current[];
#define TLBMISS_HANDLER_SETUP_PGD(pgd) \
pgd_current[smp_processor_id()] = (unsigned long)(pgd)
#ifdef CONFIG_MIPS32
#define TLBMISS_HANDLER_SETUP() \
write_c0_context((unsigned long) smp_processor_id() << 23); \
TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
#endif
#ifdef CONFIG_MIPS64
#if defined(CONFIG_MIPS64) && !defined(CONFIG_BUILD_ELF64)
#define TLBMISS_HANDLER_SETUP() \
write_c0_context((unsigned long) &pgd_current[smp_processor_id()] << 23); \
TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
#endif
extern unsigned long pgd_current[];
#if defined(CONFIG_MIPS64) && defined(CONFIG_BUILD_ELF64)
#define TLBMISS_HANDLER_SETUP() \
write_c0_context((unsigned long) smp_processor_id() << 23); \
TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
#endif
#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
......@@ -150,7 +154,7 @@ static inline void
activate_mm(struct mm_struct *prev, struct mm_struct *next)
{
unsigned long flags;
int cpu = smp_processor_id();
unsigned int cpu = smp_processor_id();
local_irq_save(flags);
......
......@@ -98,7 +98,7 @@ extern int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
extern void load_pgd(unsigned long pg_dir);
extern pmd_t invalid_pte_table[PAGE_SIZE/sizeof(pmd_t)];
extern pte_t invalid_pte_table[PAGE_SIZE/sizeof(pte_t)];
/*
* Empty pgd/pmd entries point to the invalid_pte_table.
......
......@@ -4,22 +4,43 @@
* for more details.
*
* Copyright (C) 2004 by Ralf Baechle
*
* The cpustart method is a PMC-Sierra's function to start the secondary CPU.
* Stock PMON 2000 has the smpfork, semlock and semunlock methods instead.
*/
#ifndef _ASM_PMON_H
#define _ASM_PMON_H
struct callvectors {
int (*open) (char*, int, int); /* 0 */
int (*close) (int); /* 4 */
int (*read) (int, void*, int); /* 8 */
int (*write) (int, void*, int); /* 12 */
off_t (*lseek) (int, off_t, int); /* 16 */
int (*printf) (const char*, ...); /* 20 */
void (*cacheflush) (void); /* 24 */
char* (*gets) (char*); /* 28 */
int (*cpustart) (int, void *, int, int); /* 32 */
int (*open) (char*, int, int);
int (*close) (int);
int (*read) (int, void*, int);
int (*write) (int, void*, int);
off_t (*lseek) (int, off_t, int);
int (*printf) (const char*, ...);
void (*cacheflush) (void);
char* (*gets) (char*);
union {
int (*smpfork) (unsigned long cp, char *sp);
int (*cpustart) (long, long, long, long);
} _s;
int (*semlock) (int sem);
void (*semunlock) (int sem);
};
extern struct callvectors *debug_vectors;
#define pmon_open(name, flags, mode) debug_vectors->open(name, flage, mode)
#define pmon_close(fd) debug_vectors->close(fd)
#define pmon_read(fd, buf, count) debug_vectors->read(fd, buf, count)
#define pmon_write(fd, buf, count) debug_vectors->write(fd, buf, count)
#define pmon_lseek(fd, off, whence) debug_vectors->lseek(fd, off, whence)
#define pmon_printf(fmt...) debug_vectors->printf(fmt)
#define pmon_cacheflush() debug_vectors->cacheflush()
#define pmon_gets(s) debug_vectors->gets(s)
#define pmon_cpustart(n, f, sp, gp) debug_vectors->_s.cpustart(n, f, sp, gp)
#define pmon_smpfork(cp, sp) debug_vectors->_s.smpfork(cp, sp)
#define pmon_semlock(sem) debug_vectors->semlock(sem)
#define pmon_semunlock(sem) debug_vectors->semunlock(sem)
#endif /* _ASM_PMON_H */
......@@ -8,6 +8,8 @@
#ifndef __ASM_PREFETCH_H
#define __ASM_PREFETCH_H
#include <linux/config.h>
/*
* R5000 and RM5200 implements pref and prefx instructions but they're nops, so
* rather than wasting time we pretend these processors don't support
......@@ -41,4 +43,46 @@
#define Pref_WriteBackInvalidate 25
#define Pref_PrepareForStore 30
#ifdef __ASSEMBLY__
.macro __pref hint addr
#ifdef CONFIG_CPU_HAS_PREFETCH
pref \hint, \addr
#endif
.endm
.macro pref_load addr
__pref Pref_Load, \addr
.endm
.macro pref_store addr
__pref Pref_Store, \addr
.endm
.macro pref_load_streamed addr
__pref Pref_LoadStreamed, \addr
.endm
.macro pref_store_streamed addr
__pref Pref_StoreStreamed, \addr
.endm
.macro pref_load_retained addr
__pref Pref_LoadRetained, \addr
.endm
.macro pref_store_retained addr
__pref Pref_StoreRetained, \addr
.endm
.macro pref_wback_inv addr
__pref Pref_WriteBackInvalidate, \addr
.endm
.macro pref_prepare_for_store addr
__pref Pref_PrepareForStore, \addr
.endm
#endif
#endif /* __ASM_PREFETCH_H */
......@@ -66,11 +66,6 @@ extern unsigned int vced_count, vcei_count;
PAGE_ALIGN(TASK_SIZE32 / 3) : PAGE_ALIGN(TASK_SIZE / 3))
#endif
/*
* Size of io_bitmap in longwords.
*/
#define IO_BITMAP_SIZE 2048
#define NUM_FPU_REGS 32
typedef __u64 fpureg_t;
......
......@@ -117,6 +117,21 @@ static inline void protected_writeback_dcache_line(unsigned long addr)
: "i" (Hit_Writeback_Inv_D), "r" (addr));
}
static inline void protected_writeback_scache_line(unsigned long addr)
{
__asm__ __volatile__(
".set noreorder\n\t"
".set mips3\n"
"1:\tcache %0,(%1)\n"
"2:\t.set mips0\n\t"
".set reorder\n\t"
".section\t__ex_table,\"a\"\n\t"
STR(PTR)"\t1b,2b\n\t"
".previous"
:
: "i" (Hit_Writeback_Inv_SD), "r" (addr));
}
/*
* This one is RM7000-specific
*/
......
/*
* Various register offset definitions for debuggers, core file
* examiners and whatnot.
*
* 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, 1999 Ralf Baechle
* Copyright (C) 1995, 1999 Silicon Graphics
*/
#ifndef __ASM_MIPS_REG_H
#define __ASM_MIPS_REG_H
#include <linux/config.h>
#if defined(CONFIG_MIPS32) || defined(WANT_COMPAT_REG_H)
#define EF_R0 6
#define EF_R1 7
#define EF_R2 8
#define EF_R3 9
#define EF_R4 10
#define EF_R5 11
#define EF_R6 12
#define EF_R7 13
#define EF_R8 14
#define EF_R9 15
#define EF_R10 16
#define EF_R11 17
#define EF_R12 18
#define EF_R13 19
#define EF_R14 20
#define EF_R15 21
#define EF_R16 22
#define EF_R17 23
#define EF_R18 24
#define EF_R19 25
#define EF_R20 26
#define EF_R21 27
#define EF_R22 28
#define EF_R23 29
#define EF_R24 30
#define EF_R25 31
/*
* k0/k1 unsaved
*/
#define EF_R26 32
#define EF_R27 33
#define EF_R28 34
#define EF_R29 35
#define EF_R30 36
#define EF_R31 37
/*
* Saved special registers
*/
#define EF_LO 38
#define EF_HI 39
#define EF_CP0_EPC 40
#define EF_CP0_BADVADDR 41
#define EF_CP0_STATUS 42
#define EF_CP0_CAUSE 43
#define EF_UNUSED0 44
#define EF_SIZE 180
#endif
#if CONFIG_MIPS64
#define EF_R0 0
#define EF_R1 1
#define EF_R2 2
#define EF_R3 3
#define EF_R4 4
#define EF_R5 5
#define EF_R6 6
#define EF_R7 7
#define EF_R8 8
#define EF_R9 9
#define EF_R10 10
#define EF_R11 11
#define EF_R12 12
#define EF_R13 13
#define EF_R14 14
#define EF_R15 15
#define EF_R16 16
#define EF_R17 17
#define EF_R18 18
#define EF_R19 19
#define EF_R20 20
#define EF_R21 21
#define EF_R22 22
#define EF_R23 23
#define EF_R24 24
#define EF_R25 25
/*
* k0/k1 unsaved
*/
#define EF_R26 26
#define EF_R27 27
#define EF_R28 28
#define EF_R29 29
#define EF_R30 30
#define EF_R31 31
/*
* Saved special registers
*/
#define EF_LO 32
#define EF_HI 33
#define EF_CP0_EPC 34
#define EF_CP0_BADVADDR 35
#define EF_CP0_STATUS 36
#define EF_CP0_CAUSE 37
#define EF_SIZE 304 /* size in bytes */
#endif /* CONFIG_MIPS64 */
#endif /* __ASM_MIPS_REG_H */
......@@ -41,8 +41,6 @@ struct sigcontext {
#if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
#include <linux/types.h>
/*
* Keep this struct definition in sync with the sigcontext fragment
* in arch/mips/tools/offset.c
......@@ -66,6 +64,9 @@ struct sigcontext {
};
#ifdef __KERNEL__
#include <linux/posix_types.h>
struct sigcontext32 {
__u32 sc_regmask; /* Unused */
__u32 sc_status;
......
......@@ -9,6 +9,7 @@
#ifndef _ASM_SPINLOCK_H
#define _ASM_SPINLOCK_H
#include <linux/config.h>
#include <asm/war.h>
/*
......
......@@ -64,7 +64,7 @@
addu k1, k0
LONG_L k1, %lo(kernelsp)(k1)
#endif
#ifdef CONFIG_MIPS64
#if defined(CONFIG_MIPS64) && !defined(CONFIG_BUILD_ELF64)
MFC0 k1, CP0_CONTEXT
dsra k1, 23
lui k0, %hi(pgd_current)
......@@ -73,6 +73,12 @@
lui k0, %hi(kernelsp)
daddu k1, k0
LONG_L k1, %lo(kernelsp)(k1)
#endif
#if defined(CONFIG_MIPS64) && defined(CONFIG_BUILD_ELF64)
MFC0 k1, CP0_CONTEXT
dsrl k1, 23
dsll k1, k1, 3
LONG_L k1, kernelsp(k1)
#endif
.endm
......@@ -83,12 +89,17 @@
sll \temp, 2
LONG_S \stackp, kernelsp(\temp)
#endif
#ifdef CONFIG_MIPS64
#if defined(CONFIG_MIPS64) && !defined(CONFIG_BUILD_ELF64)
lw \temp, TI_CPU(gp)
dsll \temp, 3
lui \temp2, %hi(kernelsp)
daddu \temp, \temp2
LONG_S \stackp, %lo(kernelsp)(\temp)
#endif
#if defined(CONFIG_MIPS64) && defined(CONFIG_BUILD_ELF64)
lw \temp, TI_CPU(gp)
dsll \temp, 3
LONG_S \stackp, kernelsp(\temp)
#endif
.endm
#else
......@@ -104,6 +115,7 @@
.macro SAVE_SOME
.set push
.set noat
.set reorder
mfc0 k0, CP0_STATUS
sll k0, 3 /* extract cu0 bit */
......@@ -278,16 +290,16 @@
.macro RESTORE_ALL
RESTORE_TEMP
RESTORE_AT
RESTORE_STATIC
RESTORE_AT
RESTORE_SOME
RESTORE_SP
.endm
.macro RESTORE_ALL_AND_RET
RESTORE_TEMP
RESTORE_AT
RESTORE_STATIC
RESTORE_AT
RESTORE_SOME
RESTORE_SP_AND_RET
.endm
......
......@@ -18,6 +18,8 @@
*/
#ifdef CONFIG_MIPS32
#ifndef IN_STRING_C
#define __HAVE_ARCH_STRCPY
static __inline__ char *strcpy(char *__dest, __const__ char *__src)
{
......@@ -96,6 +98,8 @@ static __inline__ int strcmp(__const__ char *__cs, __const__ char *__ct)
return __res;
}
#endif /* !defined(IN_STRING_C) */
#define __HAVE_ARCH_STRNCMP
static __inline__ int
strncmp(__const__ char *__cs, __const__ char *__ct, size_t __count)
......
......@@ -150,7 +150,7 @@ static inline int verify_area(int type, const void * addr, unsigned long size)
* Returns zero on success, or -EFAULT on error.
*/
#define put_user(x,ptr) \
__put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
__put_user_check((x),(ptr),sizeof(*(ptr)))
/*
* get_user: - Get a simple variable from user space.
......@@ -170,7 +170,7 @@ static inline int verify_area(int type, const void * addr, unsigned long size)
* On error, the variable @x is set to zero.
*/
#define get_user(x,ptr) \
__get_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
__get_user_check((x),(ptr),sizeof(*(ptr)))
/*
* __put_user: - Write a simple value into user space, with less checking.
......@@ -192,7 +192,7 @@ static inline int verify_area(int type, const void * addr, unsigned long size)
* Returns zero on success, or -EFAULT on error.
*/
#define __put_user(x,ptr) \
__put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
__put_user_nocheck((x),(ptr),sizeof(*(ptr)))
/*
* __get_user: - Get a simple variable from user space, with less checking.
......@@ -215,7 +215,7 @@ static inline int verify_area(int type, const void * addr, unsigned long size)
* On error, the variable @x is set to zero.
*/
#define __get_user(x,ptr) \
__get_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
__get_user_nocheck((x),(ptr),sizeof(*(ptr)))
struct __large_struct { unsigned long buf[100]; };
#define __m(x) (*(struct __large_struct *)(x))
......@@ -232,9 +232,10 @@ struct __large_struct { unsigned long buf[100]; };
#define __get_user_nocheck(x,ptr,size) \
({ \
long __gu_err = 0; \
__typeof(*(ptr)) __gu_val = 0; \
long __gu_addr; \
long __gu_err = 0; \
\
might_sleep(); \
__gu_addr = (long) (ptr); \
switch (size) { \
......@@ -251,10 +252,11 @@ struct __large_struct { unsigned long buf[100]; };
#define __get_user_check(x,ptr,size) \
({ \
__typeof__(*(ptr)) __gu_val = 0; \
long __gu_addr = (long) (ptr); \
long __gu_addr; \
long __gu_err; \
\
might_sleep(); \
__gu_addr = (long) (ptr); \
__gu_err = verify_area(VERIFY_READ, (void *) __gu_addr, size); \
\
if (likely(!__gu_err)) { \
......@@ -324,9 +326,10 @@ extern void __get_user_unknown(void);
#define __put_user_nocheck(x,ptr,size) \
({ \
long __pu_err = 0; \
__typeof__(*(ptr)) __pu_val; \
long __pu_addr; \
long __pu_err = 0; \
\
might_sleep(); \
__pu_val = (x); \
__pu_addr = (long) (ptr); \
......@@ -342,11 +345,13 @@ extern void __get_user_unknown(void);
#define __put_user_check(x,ptr,size) \
({ \
__typeof__(*(ptr)) __pu_val = (x); \
long __pu_addr = (long) (ptr); \
__typeof__(*(ptr)) __pu_val; \
long __pu_addr; \
long __pu_err; \
\
might_sleep(); \
__pu_val = (x); \
__pu_addr = (long) (ptr); \
__pu_err = verify_area(VERIFY_WRITE, (void *) __pu_addr, size); \
\
if (likely(!__pu_err)) { \
......
......@@ -1100,6 +1100,9 @@ type name (atype a,btype b,ctype c,dtype d,etype e,ftype f) \
#endif /* (_MIPS_SIM == _MIPS_SIM_NABI32) || (_MIPS_SIM == _MIPS_SIM_ABI64) */
#ifdef __KERNEL__
#include <linux/config.h>
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
#define __ARCH_WANT_SYS_ALARM
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment