diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-08 10:01:28 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-08 10:01:28 -0800 |
commit | 0cf975e16927fd70f34cee20d3856246c13bb4c8 (patch) | |
tree | bb955d50f28e5d98c198701798c8341d9763299a /arch/cris/arch-v32/mm/mmu.S | |
parent | 03054de1e0b90b33e9974107d84dabd2509f5898 (diff) | |
parent | bc10ac3f2fe44e65f787d6197fd5d17304bf7d83 (diff) |
Merge branch 'cris' of git://www.jni.nu/cris
* 'cris' of git://www.jni.nu/cris: (158 commits)
CRIS v32: Remove hwregs/timer_defs.h, it is now architecture specific.
CRIS v32: Change drivers/i2c.c locking.
CRIS v32: Rewrite ARTPEC-3 gpio driver to avoid volatiles and general cleanup.
CRIS: Add new timerfd syscall entries.
MAINTAINERS: Add my information for the CRIS port.
CRIS v32: Correct spelling of bandwidth in function name.
CRIS v32: Clean up nandflash.c for ARTPEC-3 and ETRAX FS.
CRIS v10: Cleanup of drivers/gpio.c
CRIS v10: drivers/net/cris/eth_v10.c rename LED defines to CRIS_LED to avoid name clash.
CRIS: Make io_pwm_set_period members unsigned in etraxgpio.h
CRIS: Move ETRAX_AXISFLASHMAP to common Kconfig file.
CRIS: Drop regs parameter from call to profile_tick in kernel/time.c
CRIS v32: Fix minor formatting issue in mach-a3/io.c
CRIS v32: Initialize GIO even if we're rambooting in kernel/head.S
CRIS v32: Remove kernel/arbiter.c, it now exists in machine dependent directory.
CRIS v32: Minor changes to avoid errors in asm-cris/arch-v32/hwregs/reg_rdwr.h
CRIS v32: arch-v32/hwregs/intr_vect_defs.h moved to machine dependent directory.
CRIS v32: Correct offset for TASK_pid in asm-cris/arch-v32/offset.h
CRIS v32: Move register map header to machine dependent directory.
CRIS v32: Let compiler know that memory is clobbered after a break op.
...
Diffstat (limited to 'arch/cris/arch-v32/mm/mmu.S')
-rw-r--r-- | arch/cris/arch-v32/mm/mmu.S | 93 |
1 files changed, 81 insertions, 12 deletions
diff --git a/arch/cris/arch-v32/mm/mmu.S b/arch/cris/arch-v32/mm/mmu.S index 27b70e5006a..2238d154bde 100644 --- a/arch/cris/arch-v32/mm/mmu.S +++ b/arch/cris/arch-v32/mm/mmu.S @@ -1,3 +1,5 @@ +; WARNING : The refill handler has been modified, see below !!! + /* * Copyright (C) 2003 Axis Communications AB * @@ -61,6 +63,14 @@ ; Note that the code is optimized to minimize stalls (makes the code harder ; to read). ; +; WARNING !!! +; Modified by Mikael Asker 060725: added a workaround for strange TLB +; behavior. If the same PTE is present in more than one set, the TLB +; doesn't recognize it and we get stuck in a loop of refill exceptions. +; The workaround detects such loops and exits them by flushing +; the TLB contents. The problem and workaround were verified +; in VCS by Mikael Starvik. +; ; Each page is 8 KB. Each PMD holds 8192/4 PTEs (each PTE is 4 bytes) so each ; PMD holds 16 MB of virtual memory. ; Bits 0-12 : Offset within a page @@ -68,6 +78,11 @@ ; Bits 24-31 : PMD offset within the PGD .macro MMU_REFILL_HANDLER handler, mmu + .data +1: .dword 0 ; refill_count + ; == 0 <=> last_refill_cause is invalid +2: .dword 0 ; last_refill_cause + .text .globl \handler \handler: subq 4, $sp @@ -76,42 +91,96 @@ subq 4, $sp move \mmu, $srs ; Select MMU support register bank move.d $acr, [$sp] - subq 4, $sp - move.d $r0, [$sp] + subq 12, $sp + move.d 1b, $acr ; Point to refill_count + movem $r2, [$sp] + + test.d [$acr] ; refill_count == 0 ? + beq 5f ; yes, last_refill_cause is invalid + move.d $acr, $r1 + + ; last_refill_cause is valid, investigate cause + addq 4, $r1 ; Point to last_refill_cause + move $s3, $r0 ; Get rw_mm_cause + move.d [$r1], $r2 ; Get last_refill_cause + cmp.d $r0, $r2 ; rw_mm_cause == last_refill_cause ? + beq 6f ; yes, increment count + moveq 1, $r2 + + ; rw_mm_cause != last_refill_cause + move.d $r2, [$acr] ; refill_count = 1 + move.d $r0, [$r1] ; last_refill_cause = rw_mm_cause + +3: ; Probably not in a loop, continue normal processing #ifdef CONFIG_SMP move $s7, $acr ; PGD #else move.d per_cpu__current_pgd, $acr ; PGD #endif ; Look up PMD in PGD - move $s3, $r0 ; rw_mm_cause lsrq 24, $r0 ; Get PMD index into PGD (bit 24-31) move.d [$acr], $acr ; PGD for the current process addi $r0.d, $acr, $acr move $s3, $r0 ; rw_mm_cause move.d [$acr], $acr ; Get PMD - beq 1f + beq 8f ; Look up PTE in PMD lsrq PAGE_SHIFT, $r0 and.w PAGE_MASK, $acr ; Remove PMD flags and.d 0x7ff, $r0 ; Get PTE index into PMD (bit 13-23) addi $r0.d, $acr, $acr move.d [$acr], $acr ; Get PTE - beq 2f - move.d [$sp+], $r0 ; Pop r0 in delayslot + beq 9f + movem [$sp], $r2 ; Restore r0-r2 in delay slot + addq 12, $sp ; Store in TLB move $acr, $s5 - ; Return +4: ; Return move.d [$sp+], $acr - move [$sp], $srs + move [$sp], $srs addq 4, $sp rete rfe -1: ; PMD missing, let the mm subsystem fix it up. - move.d [$sp+], $r0 ; Pop r0 -2: ; PTE missing, let the mm subsystem fix it up. + +5: ; last_refill_cause is invalid + moveq 1, $r2 + addq 4, $r1 ; Point to last_refill_cause + move.d $r2, [$acr] ; refill_count = 1 + move $s3, $r0 ; Get rw_mm_cause + ba 3b ; Continue normal processing + move.d $r0,[$r1] ; last_refill_cause = rw_mm_cause + +6: ; rw_mm_cause == last_refill_cause + move.d [$acr], $r2 ; Get refill_count + cmpq 4, $r2 ; refill_count > 4 ? + bhi 7f ; yes + addq 1, $r2 ; refill_count++ + ba 3b ; Continue normal processing + move.d $r2, [$acr] + +7: ; refill_count > 4, error + move.d $acr, $r0 ; Save pointer to refill_count + clear.d [$r0] ; refill_count = 0 + + ;; rewind the short stack + movem [$sp], $r2 ; Restore r0-r2 + addq 12, $sp + move.d [$sp+], $acr + move [$sp], $srs + addq 4, $sp + ;; Keep it simple (slow), save all the regs. + SAVE_ALL + jsr __flush_tlb_all + nop + ba ret_from_intr ; Return + nop + +8: ; PMD missing, let the mm subsystem fix it up. + movem [$sp], $r2 ; Restore r0-r2 +9: ; PTE missing, let the mm subsystem fix it up. + addq 12, $sp move.d [$sp+], $acr - move [$sp], $srs + move [$sp], $srs addq 4, $sp SAVE_ALL move \mmu, $srs |