Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / cris / arch-v10 / kernel / entry.S
index ddd947d..c808005 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.18 2004/05/11 12:28:25 starvik Exp $
+/* $Id: entry.S,v 1.28 2005/06/20 05:06:30 starvik Exp $
  *
  *  linux/arch/cris/entry.S
  *
@@ -7,6 +7,39 @@
  *  Authors:   Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: entry.S,v $
+ *  Revision 1.28  2005/06/20 05:06:30  starvik
+ *  Remove unnecessary diff to kernel.org tree
+ *
+ *  Revision 1.27  2005/03/04 08:16:16  starvik
+ *  Merge of Linux 2.6.11.
+ *
+ *  Revision 1.26  2005/01/11 13:49:47  starvik
+ *  Added NMI handler.
+ *
+ *  Revision 1.25  2004/12/27 11:18:32  starvik
+ *  Merge of Linux 2.6.10 (not functional yet).
+ *
+ *  Revision 1.24  2004/12/22 10:41:23  starvik
+ *  Updates to make v10 compile with the latest SMP aware generic code (even
+ *  though v10 will never have SMP).
+ *
+ *  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
  *
 #include <asm/arch/sv_addr_ag.h>
 #include <asm/errno.h>
 #include <asm/thread_info.h>
-#include <asm/arch/offset.h>
-               
+#include <asm/asm-offsets.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
        ;; functions exported from this file
        
        .globl system_call
 #ifdef CONFIG_PREEMPT  
        ; Check if preemptive kernel scheduling should be done
 _resume_kernel:
+       di
        ; Load current task struct
        movs.w  -8192, $r0      ;  THREAD_SIZE = 8192
        and.d   $sp, $r0
@@ -272,12 +308,7 @@ _need_resched:
        bpl     _Rexit
        nop
        ; Ok, lets's do some preemptive kernel scheduling
-       move.d  PREEMPT_ACTIVE, $r10
-       move.d  $r10, [$r0+TI_preempt_count] ; Mark as active
-       ei
-       jsr     schedule
-       clear.d [$r0+TI_preempt_count] ;  Mark as inactive
-       di
+       jsr     preempt_schedule_irq
        ; Load new task struct
        movs.w  -8192, $r0      ;  THREAD_SIZE = 8192
        and.d   $sp, $r0
@@ -539,11 +570,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    24, $r1     ; Get PGD index (bit 24-31)
+       move.d  [per_cpu__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 PGD (bit 13-23)
+       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 +639,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,55 +652,22 @@ 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:
-
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
-;; If we receive a watchdog interrupt while it is not expected, then set
-;; up a canonical frame and dump register contents before dying.
-
        ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!
        move    $brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame
        push    $srp
@@ -629,9 +679,16 @@ IRQ1_interrupt:
        push    $r10            ; push orig_r10
        clear.d [$sp=$sp-4]     ; frametype == 0, normal frame
 
-;; We don't check that we actually were bit by the watchdog as opposed to
-;; an external NMI, since there is currently no handler for external NMI.
-
+       move.d  [R_IRQ_MASK0_RD], $r1 ; External NMI or watchdog?
+       and.d   0x80000000, $r1
+       beq     wdog
+       move.d  $sp, $r10
+       jsr     handle_nmi
+       setf m                  ; Enable NMI again
+       retb                    ; Return from NMI
+       nop
+wdog:
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
 ;; Check if we're waiting for reset to happen, as signalled by
 ;; hard_reset_now setting cause_of_death to a magic value.  If so, just
 ;; get stuck until reset happens.
@@ -719,29 +776,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
-       
-       ;; strange, we didn't get any set vector bits.. oh well, just return
+       moveq   0, $r9  ; make ret_from_intr realise we came from an ir
        
-       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 +1130,13 @@ 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
+       .long sys_ni_syscall            /* 285 */ /* available */
+       .long sys_add_key
+       .long sys_request_key
+       .long sys_keyctl
+
         /*
          * NOTE!! This doesn't have to be exact - we just have
          * to make sure we have _enough_ of the "sys_ni_syscall"