Commit 6410393a authored by Mikael Starvik's avatar Mikael Starvik Committed by Linus Torvalds

[PATCH] CRIS: Core kernel updates

Added profiler.
Optimized MMU refill handling.
Improved multiple interrupt handling.
Signed-off-by: default avatarMikael Starvik <starvik@axis.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 574f1884
#include <linux/config.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/arch/svinto.h>
/* Export shadow registers for the CPU I/O pins */
EXPORT_SYMBOL(genconfig_shadow);
EXPORT_SYMBOL(port_pa_data_shadow);
EXPORT_SYMBOL(port_pa_dir_shadow);
EXPORT_SYMBOL(port_pb_data_shadow);
EXPORT_SYMBOL(port_pb_dir_shadow);
EXPORT_SYMBOL(port_pb_config_shadow);
EXPORT_SYMBOL(port_g_data_shadow);
/* Cache flush functions */
EXPORT_SYMBOL(flush_etrax_cache);
EXPORT_SYMBOL(prepare_rx_descriptor);
/* $Id: entry.S,v 1.18 2004/05/11 12:28:25 starvik Exp $
/* $Id: entry.S,v 1.23 2004/10/19 13:07:37 starvik Exp $
*
* linux/arch/cris/entry.S
*
......@@ -7,6 +7,23 @@
* Authors: Bjorn Wesen (bjornw@axis.com)
*
* $Log: entry.S,v $
* Revision 1.23 2004/10/19 13:07:37 starvik
* Merge of Linux 2.6.9
*
* Revision 1.22 2004/06/21 10:29:55 starvik
* Merge of Linux 2.6.7
*
* Revision 1.21 2004/06/09 05:30:27 starvik
* Clean up multiple interrupt handling.
* Prevent interrupts from interrupting each other.
* Handle all active interrupts.
*
* Revision 1.20 2004/06/08 08:55:32 starvik
* Removed unused code
*
* Revision 1.19 2004/06/04 11:56:15 starvik
* Implemented page table lookup for refills in assembler for improved performance.
*
* Revision 1.18 2004/05/11 12:28:25 starvik
* Merge of Linux 2.6.6
*
......@@ -238,7 +255,9 @@
#include <asm/errno.h>
#include <asm/thread_info.h>
#include <asm/arch/offset.h>
#include <asm/page.h>
#include <asm/pgtable.h>
;; functions exported from this file
.globl system_call
......@@ -539,11 +558,63 @@ resume:
;; It needs to stack the CPU status and overall is different
;; from the other interrupt handlers.
mmu_bus_fault:
sbfs [$sp=$sp-16] ; push the internal CPU status
mmu_bus_fault:
;; For refills we try to do a quick page table lookup. If it is
;; a real fault we let the mm subsystem handle it.
;; the first longword in the sbfs frame was the interrupted PC
;; which fits nicely with the "IRP" slot in pt_regs normally used to
;; contain the return address. used by Oops to print kernel errors..
;; contain the return address. used by Oops to print kernel errors.
sbfs [$sp=$sp-16] ; push the internal CPU status
push $dccr
di
subq 2*4, $sp
movem $r1, [$sp]
move.d [R_MMU_CAUSE], $r1
;; ETRAX 100LX TR89 bugfix: if the second half of an unaligned
;; write causes a MMU-fault, it will not be restarted correctly.
;; This could happen if a write crosses a page-boundary and the
;; second page is not yet COW'ed or even loaded. The workaround
;; is to clear the unaligned bit in the CPU status record, so
;; that the CPU will rerun both the first and second halves of
;; the instruction. This will not have any sideeffects unless
;; the first half goes to any device or memory that can't be
;; written twice, and which is mapped through the MMU.
;;
;; We only need to do this for writes.
btstq 8, $r1 ; Write access?
bpl 1f
nop
move.d [$sp+16], $r0 ; Clear unaligned bit in csrinstr
and.d ~(1<<5), $r0
move.d $r0, [$sp+16]
1: btstq 12, $r1 ; Refill?
bpl 2f
lsrq PMD_SHIFT, $r1 ; Get PMD index into PGD (bit 24-31)
move.d [current_pgd], $r0 ; PGD for the current process
move.d [$r0+$r1.d], $r0 ; Get PMD
beq 2f
nop
and.w PAGE_MASK, $r0 ; Remove PMD flags
move.d [R_MMU_CAUSE], $r1
lsrq PAGE_SHIFT, $r1
and.d 0x7ff, $r1 ; Get PTE index into PMD (bit 13-24)
move.d [$r0+$r1.d], $r1 ; Get PTE
beq 2f
nop
;; Store in TLB
move.d $r1, [R_TLB_LO]
;; Return
movem [$sp+], $r1
pop $dccr
rbf [$sp+] ; return by popping the CPU status
2: ; PMD or PTE missing, let the mm subsystem fix it up.
movem [$sp+], $r1
pop $dccr
; Ok, not that easy, pass it on to the mm subsystem
; The MMU status record is now on the stack
push $srp ; make a stackframe similar to pt_regs
push $dccr
push $mof
......@@ -556,7 +627,7 @@ mmu_bus_fault:
move.d $sp, $r10 ; pt_regs argument to handle_mmu_bus_fault
jsr handle_mmu_bus_fault ; in arch/cris/mm/fault.c
jsr handle_mmu_bus_fault ; in arch/cris/arch-v10/mm/fault.c
;; now we need to return through the normal path, we cannot just
;; do the RBFexit since we might have killed off the running
......@@ -569,48 +640,20 @@ mmu_bus_fault:
nop
;; special handlers for breakpoint and NMI
#if 0
hwbreakpoint:
push $dccr
di
push $r10
push $r11
push $r12
push $r13
clearf b
move $brp,$r11
move.d [hw_bp_msg],$r10
jsr printk
setf b
pop $r13
pop $r12
pop $r11
pop $r10
pop $dccr
retb
nop
#else
hwbreakpoint:
push $dccr
di
#if 1
push $r10
push $r11
move.d [hw_bp_trig_ptr],$r10
move.d [$r10],$r11
cmp.d 42,$r11
beq 1f
nop
move $brp,$r11
move.d $r11,[$r10+]
move.d $r10,[hw_bp_trig_ptr]
1: pop $r11
pop $r10
#endif
pop $dccr
retb
nop
#endif
IRQ1_interrupt:
......@@ -719,29 +762,23 @@ multiple_interrupt:
push $r10 ; push orig_r10
clear.d [$sp=$sp-4] ; frametype == 0, normal frame
move.d irq_shortcuts + 8, $r1
moveq 2, $r2 ; first bit we care about is the timer0 irq
move.d [R_VECT_MASK_RD], $r0; read the irq bits that triggered the multiple irq
move.d $r0, [R_VECT_MASK_CLR] ; Block all active IRQs
1:
btst $r2, $r0 ; check for the irq given by bit r2
bmi _do_shortcut ; actually do the shortcut
nop
bpl 2f
move.d $r2, $r10 ; First argument to do_IRQ
move.d $sp, $r11 ; second argument to do_IRQ
jsr do_IRQ
2:
addq 1, $r2 ; next vector bit
addq 4, $r1 ; next vector
cmp.b 32, $r2
bne 1b ; process all irq's up to and including number 31
nop
moveq 0, $r9 ; make ret_from_intr realise we came from an ir
;; strange, we didn't get any set vector bits.. oh well, just return
ba _Rexit
nop
_do_shortcut:
test.d [$r1]
beq _Rexit
nop
jump [$r1] ; jump to the irq handlers shortcut
move.d $r0, [R_VECT_MASK_SET] ; Unblock all the IRQs
jump ret_from_intr
do_sigtrap:
;;
......@@ -1079,7 +1116,9 @@ sys_call_table:
.long sys_mq_timedreceive /* 280 */
.long sys_mq_notify
.long sys_mq_getsetattr
.long sys_ni_syscall /* reserved for kexec */
.long sys_waitid
/*
* NOTE!! This doesn't have to be exact - we just have
* to make sure we have _enough_ of the "sys_ni_syscall"
......
/* $Id: irq.c,v 1.1 2002/12/11 15:42:02 starvik Exp $
/* $Id: irq.c,v 1.2 2004/06/09 05:30:27 starvik Exp $
*
* linux/arch/cris/kernel/irq.c
*
......@@ -23,12 +23,8 @@ irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq pro
*/
void
set_int_vector(int n, irqvectptr addr, irqvectptr saddr)
set_int_vector(int n, irqvectptr addr)
{
/* remember the shortcut entry point, after the prologue */
irq_shortcuts[n] = saddr;
etrax_irv->v[n + 0x20] = (irqvectptr)addr;
}
......@@ -106,17 +102,6 @@ static void (*interrupt[NR_IRQS])(void) = {
IRQ31_interrupt
};
static void (*sinterrupt[NR_IRQS])(void) = {
NULL, NULL, sIRQ2_interrupt, sIRQ3_interrupt,
sIRQ4_interrupt, sIRQ5_interrupt, sIRQ6_interrupt, sIRQ7_interrupt,
sIRQ8_interrupt, sIRQ9_interrupt, sIRQ10_interrupt, sIRQ11_interrupt,
sIRQ12_interrupt, sIRQ13_interrupt, NULL, NULL,
sIRQ16_interrupt, sIRQ17_interrupt, sIRQ18_interrupt, sIRQ19_interrupt,
sIRQ20_interrupt, sIRQ21_interrupt, sIRQ22_interrupt, sIRQ23_interrupt,
sIRQ24_interrupt, sIRQ25_interrupt, NULL, NULL, NULL, NULL, NULL,
sIRQ31_interrupt
};
static void (*bad_interrupt[NR_IRQS])(void) = {
NULL, NULL,
NULL, bad_IRQ3_interrupt,
......@@ -137,12 +122,12 @@ static void (*bad_interrupt[NR_IRQS])(void) = {
void arch_setup_irq(int irq)
{
set_int_vector(irq, interrupt[irq], sinterrupt[irq]);
set_int_vector(irq, interrupt[irq]);
}
void arch_free_irq(int irq)
{
set_int_vector(irq, bad_interrupt[irq], 0);
set_int_vector(irq, bad_interrupt[irq]);
}
void weird_irq(void);
......@@ -187,20 +172,20 @@ init_IRQ(void)
/* set all etrax irq's to the bad handlers */
for (i = 2; i < NR_IRQS; i++)
set_int_vector(i, bad_interrupt[i], 0);
set_int_vector(i, bad_interrupt[i]);
/* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */
set_int_vector(15, multiple_interrupt, 0);
set_int_vector(15, multiple_interrupt);
/* 0 and 1 which are special breakpoint/NMI traps */
set_int_vector(0, hwbreakpoint, 0);
set_int_vector(1, IRQ1_interrupt, 0);
set_int_vector(0, hwbreakpoint);
set_int_vector(1, IRQ1_interrupt);
/* and irq 14 which is the mmu bus fault handler */
set_int_vector(14, mmu_bus_fault, 0);
set_int_vector(14, mmu_bus_fault);
/* setup the system-call trap, which is reached by BREAK 13 */
......
......@@ -18,6 +18,9 @@
*! Jul 21 1999 Bjorn Wesen eLinux port
*!
*! $Log: kgdb.c,v $
*! Revision 1.5 2004/10/07 13:59:08 starvik
*! Corrected call to set_int_vector
*!
*! Revision 1.4 2003/04/09 05:20:44 starvik
*! Merge of Linux 2.5.67
*!
......@@ -68,7 +71,7 @@
*!
*!---------------------------------------------------------------------------
*!
*! $Id: kgdb.c,v 1.4 2003/04/09 05:20:44 starvik Exp $
*! $Id: kgdb.c,v 1.5 2004/10/07 13:59:08 starvik Exp $
*!
*! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN
*!
......@@ -1557,7 +1560,7 @@ kgdb_init(void)
/* could initialize debug port as well but it's done in head.S already... */
/* breakpoint handler is now set in irq.c */
set_int_vector(8, kgdb_handle_serial, 0);
set_int_vector(8, kgdb_handle_serial);
enableDebugIRQ();
}
......
/* $Id: process.c,v 1.6 2004/05/11 12:28:25 starvik Exp $
/* $Id: process.c,v 1.9 2004/10/19 13:07:37 starvik Exp $
*
* linux/arch/cris/kernel/process.c
*
......@@ -34,6 +34,15 @@ void default_idle(void)
#endif
}
/*
* Free current thread data structures etc..
*/
void exit_thread(void)
{
/* Nothing needs to be done. */
}
/* if the watchdog is enabled, we can simply disable interrupts and go
* into an eternal loop, and the watchdog will reset the CPU after 0.1s
* if on the other hand the watchdog wasn't enabled, we just enable it and wait
......@@ -122,6 +131,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
*childregs = *regs; /* struct copy of pt_regs */
p->set_child_tid = p->clear_child_tid = NULL;
childregs->r10 = 0; /* child returns 0 after a fork/clone */
/* put the switch stack right below the pt_regs */
......@@ -212,13 +223,6 @@ asmlinkage int sys_execve(const char *fname, char **argv, char **envp,
return error;
}
/*
* These bracket the sleeping functions..
*/
#define first_sched ((unsigned long)__sched_text_start)
#define last_sched ((unsigned long)__sched_text_end)
unsigned long get_wchan(struct task_struct *p)
{
#if 0
......@@ -239,8 +243,8 @@ unsigned long get_wchan(struct task_struct *p)
if (ebp < stack_page || ebp > 8184+stack_page)
return 0;
eip = *(unsigned long *) (ebp+4);
if (eip < first_sched || eip >= last_sched)
return eip;
if (!in_sched_functions(eip))
return eip;
ebp = *(unsigned long *) ebp;
} while (count++ < 16);
#endif
......
......@@ -23,8 +23,37 @@
*/
#define DCCR_MASK 0x0000001f /* XNZVC */
extern inline long get_reg(struct task_struct *, unsigned int);
extern inline long put_reg(struct task_struct *, unsigned int, unsigned long);
/*
* Get contents of register REGNO in task TASK.
*/
inline long get_reg(struct task_struct *task, unsigned int regno)
{
/* USP is a special case, it's not in the pt_regs struct but
* in the tasks thread struct
*/
if (regno == PT_USP)
return task->thread.usp;
else if (regno < PT_MAX)
return ((unsigned long *)user_regs(task->thread_info))[regno];
else
return 0;
}
/*
* Write contents of register REGNO in task TASK.
*/
inline int put_reg(struct task_struct *task, unsigned int regno,
unsigned long data)
{
if (regno == PT_USP)
task->thread.usp = data;
else if (regno < PT_MAX)
((unsigned long *)user_regs(task->thread_info))[regno] = data;
else
return -1;
return 0;
}
/*
* Called by kernel/ptrace.c when detaching.
......@@ -50,6 +79,7 @@ sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
int ret;
unsigned long __user *datap = (unsigned long __user *)data;
lock_kernel();
ret = -EPERM;
......@@ -102,7 +132,7 @@ sys_ptrace(long request, long pid, long addr, long data)
if (copied != sizeof(tmp))
break;
ret = put_user(tmp,(unsigned long *) data);
ret = put_user(tmp,datap);
break;
}
......@@ -115,7 +145,7 @@ sys_ptrace(long request, long pid, long addr, long data)
break;
tmp = get_reg(child, addr >> 2);
ret = put_user(tmp, (unsigned long *)data);
ret = put_user(tmp, datap);
break;
}
......@@ -176,7 +206,7 @@ sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_KILL:
ret = 0;
if (child->exit_state == EXIT_ZOMBIE)
if (child->state == TASK_ZOMBIE)
break;
child->exit_code = SIGKILL;
......@@ -213,7 +243,7 @@ sys_ptrace(long request, long pid, long addr, long data)
for (i = 0; i <= PT_MAX; i++) {
tmp = get_reg(child, i);
if (put_user(tmp, (unsigned long *) data)) {
if (put_user(tmp, datap)) {
ret = -EFAULT;
goto out_tsk;
}
......@@ -231,7 +261,7 @@ sys_ptrace(long request, long pid, long addr, long data)
unsigned long tmp;
for (i = 0; i <= PT_MAX; i++) {
if (get_user(tmp, (unsigned long *) data)) {
if (get_user(tmp, datap)) {
ret = -EFAULT;
goto out_tsk;
}
......
......@@ -264,7 +264,6 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13,
{
struct rt_sigframe __user *frame = (struct rt_sigframe *)rdusp();
sigset_t set;
stack_t st;
/*
* Since we stacked the signal on a dword boundary,
......@@ -288,11 +287,8 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13,
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT)
goto badframe;
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
do_sigaltstack(&st, NULL, rdusp());
return regs->r10;
......@@ -388,9 +384,9 @@ static void setup_frame(int sig, struct k_sigaction *ka,
/* trampoline - the desired return ip is the retcode itself */
return_ip = (unsigned long)&frame->retcode;
/* This is movu.w __NR_sigreturn, r9; break 13; */
err |= __put_user(0x9c5f, (short *)(frame->retcode+0));
err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2));
err |= __put_user(0xe93d, (short *)(frame->retcode+4));
err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0));
err |= __put_user(__NR_sigreturn, (short __user*)(frame->retcode+2));
err |= __put_user(0xe93d, (short __user*)(frame->retcode+4));
}
if (err)
......@@ -448,9 +444,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* trampoline - the desired return ip is the retcode itself */
return_ip = (unsigned long)&frame->retcode;
/* This is movu.w __NR_rt_sigreturn, r9; break 13; */
err |= __put_user(0x9c5f, (short *)(frame->retcode+0));
err |= __put_user(__NR_rt_sigreturn, (short *)(frame->retcode+2));
err |= __put_user(0xe93d, (short *)(frame->retcode+4));
err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0));
err |= __put_user(__NR_rt_sigreturn, (short __user*)(frame->retcode+2));
err |= __put_user(0xe93d, (short __user*)(frame->retcode+4));
}
if (err)
......@@ -482,10 +478,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
extern inline void
handle_signal(int canrestart, unsigned long sig,
siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs * regs)
{
struct k_sigaction *ka = &current->sighand->action[sig-1];
/* Are we from a system call? */
if (canrestart) {
/* If so, check system call restarting.. */
......@@ -547,6 +542,7 @@ int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
{
siginfo_t info;
int signr;
struct k_sigaction ka;
/*
* We want the common case to go fast, which
......@@ -560,10 +556,10 @@ int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
if (!oldset)
oldset = &current->blocked;
signr = get_signal_to_deliver(&info, regs, NULL);
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
/* Whee! Actually deliver the signal. */
handle_signal(canrestart, signr, &info, oldset, regs);
handle_signal(canrestart, signr, &info, &ka, oldset, regs);
return 1;
}
......
/* $Id: time.c,v 1.3 2004/06/01 05:38:42 starvik Exp $
/* $Id: time.c,v 1.5 2004/09/29 06:12:46 starvik Exp $
*
* linux/arch/cris/arch-v10/kernel/time.c
*
......@@ -200,6 +200,8 @@ static long last_rtc_update = 0;
//static unsigned short myjiff; /* used by our debug routine print_timestamp */
extern void cris_do_profile(struct pt_regs *regs);
static inline irqreturn_t
timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
......@@ -227,10 +229,9 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* call the real timer interrupt handler */
do_timer(regs);
#ifndef CONFIG_SMP
update_process_times(user_mode(regs));
#endif
cris_do_profile(regs); /* Save profiling information */
/*
* If we have an externally synchronized Linux clock, then update
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
......
......@@ -40,23 +40,25 @@ void
handle_mmu_bus_fault(struct pt_regs *regs)
{
int cause;
#ifdef DEBUG
int select;
#ifdef DEBUG
int index;
int page_id;
int acc, inv;
#endif
int miss, we, writeac;
pgd_t* pgd = (pgd_t*)current_pgd;
pmd_t *pmd;
pte_t pte;
int miss, we, writeac;
unsigned long address;
unsigned long flags;
cause = *R_MMU_CAUSE;
address = cause & PAGE_MASK; /* get faulting address */
select = *R_TLB_SELECT;
#ifdef DEBUG
select = *R_TLB_SELECT;
page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause);
acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause);
inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause);
......@@ -66,85 +68,31 @@ handle_mmu_bus_fault(struct pt_regs *regs)
we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause);
writeac = IO_EXTRACT(R_MMU_CAUSE, wr_rd, cause);
/* ETRAX 100LX TR89 bugfix: if the second half of an unaligned
* write causes a MMU-fault, it will not be restarted correctly.
* This could happen if a write crosses a page-boundary and the
* second page is not yet COW'ed or even loaded. The workaround
* is to clear the unaligned bit in the CPU status record, so
* that the CPU will rerun both the first and second halves of
* the instruction. This will not have any sideeffects unless
* the first half goes to any device or memory that can't be
* written twice, and which is mapped through the MMU.
*
* We only need to do this for writes.
*/
if(writeac)
regs->csrinstr &= ~(1 << 5);
D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n",
regs->irp, address, miss, inv, we, acc, index, page_id));
/* for a miss, we need to reload the TLB entry */
if (miss) {
/* see if the pte exists at all
* refer through current_pgd, dont use mm->pgd
*/
pmd = (pmd_t *)(current_pgd + pgd_index(address));
if (pmd_none(*pmd)) {
do_page_fault(address, regs, 0, writeac);
return;
}
if (pmd_bad(*pmd)) {
printk("bad pgdir entry 0x%lx at 0x%p\n", *(unsigned long*)pmd, pmd);
pmd_clear(pmd);
return;
}
pte = *pte_offset_kernel(pmd, address);
if (!pte_present(pte)) {
do_page_fault(address, regs, 0, writeac);
return;
}
#ifdef DEBUG
printk(" found pte %lx pg %p ", pte_val(pte), pte_page(pte));
if (pte_val(pte) & _PAGE_SILENT_WRITE)
printk("Silent-W ");
if (pte_val(pte) & _PAGE_KERNEL)
printk("Kernel ");
if (pte_val(pte) & _PAGE_SILENT_READ)
printk("Silent-R ");
if (pte_val(pte) & _PAGE_GLOBAL)
printk("Global ");
if (pte_val(pte) & _PAGE_PRESENT)
printk("Present ");
if (pte_val(pte) & _PAGE_ACCESSED)
printk("Accessed ");
if (pte_val(pte) & _PAGE_MODIFIED)
printk("Modified ");
if (pte_val(pte) & _PAGE_READ)
printk("Readable ");
if (pte_val(pte) & _PAGE_WRITE)
printk("Writeable ");
printk("\n");
#endif
/* load up the chosen TLB entry
* this assumes the pte format is the same as the TLB_LO layout.
*
* the write to R_TLB_LO also writes the vpn and page_id fields from
* R_MMU_CAUSE, which we in this case obviously want to keep
*/
*R_TLB_LO = pte_val(pte);
return;
}
/* leave it to the MM system fault handler */
do_page_fault(address, regs, 1, we);
if (miss)
do_page_fault(address, regs, 0, writeac);
else
do_page_fault(address, regs, 1, we);
/* Reload TLB with new entry to avoid an extra miss exception.
* do_page_fault may have flushed the TLB so we have to restore
* the MMU registers.
*/
local_save_flags(flags);
local_irq_disable();
pmd = (pmd_t *)(pgd + pgd_index(address));
if (pmd_none(*pmd))
return;
pte = *pte_offset_kernel(pmd, address);
if (!pte_present(pte))
return;
*R_TLB_SELECT = select;
*R_TLB_HI = cause;
*R_TLB_LO = pte_val(pte);
local_irq_restore(flags);
}
/* Called from arch/cris/mm/fault.c to find fixup code. */
......
......@@ -65,7 +65,7 @@ void
flush_tlb_mm(struct mm_struct *mm)
{
int i;
int page_id = mm->context;
int page_id = mm->context.page_id;
unsigned long flags;
D(printk("tlb: flush mm context %d (%p)\n", page_id, mm));
......@@ -103,7 +103,7 @@ flush_tlb_page(struct vm_area_struct *vma,
unsigned long addr)
{
struct mm_struct *mm = vma->vm_mm;
int page_id = mm->context;
int page_id = mm->context.page_id;
int i;
unsigned long flags;
......@@ -147,7 +147,7 @@ flush_tlb_range(struct vm_area_struct *vma,
unsigned long end)
{
struct mm_struct *mm = vma->vm_mm;
int page_id = mm->context;
int page_id = mm->context.page_id;
int i;
unsigned long flags;
......@@ -208,6 +208,18 @@ dump_tlb_all(void)
}
#endif
/*
* Initialize the context related info for a new mm_struct
* instance.
*/
int
init_new_context(struct task_struct *tsk, struct mm_struct *mm)
{
mm->context.page_id = NO_CONTEXT;
return 0;
}
/* called in schedule() just before actually doing the switch_to */
void
......@@ -231,6 +243,6 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
D(printk("switching mmu_context to %d (%p)\n", next->context, next));
*R_MMU_CONTEXT = IO_FIELD(R_MMU_CONTEXT, page_id, next->context);
*R_MMU_CONTEXT = IO_FIELD(R_MMU_CONTEXT, page_id, next->context.page_id);
}
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