Merge with rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[linux-2.6] / arch / mips / kernel / entry.S
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle
7  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8  * Copyright (C) 2001 MIPS Technologies, Inc.
9  */
10 #include <linux/config.h>
11
12 #include <asm/asm.h>
13 #include <asm/asmmacro.h>
14 #include <asm/regdef.h>
15 #include <asm/mipsregs.h>
16 #include <asm/stackframe.h>
17 #include <asm/isadep.h>
18 #include <asm/thread_info.h>
19 #include <asm/war.h>
20
21 #ifdef CONFIG_PREEMPT
22         .macro  preempt_stop
23         .endm
24 #else
25         .macro  preempt_stop
26         local_irq_disable
27         .endm
28 #define resume_kernel   restore_all
29 #endif
30
31         .text
32         .align  5
33 FEXPORT(ret_from_exception)
34         preempt_stop
35 FEXPORT(ret_from_irq)
36         LONG_L  t0, PT_STATUS(sp)               # returning to kernel mode?
37         andi    t0, t0, KU_USER
38         beqz    t0, resume_kernel
39
40 resume_userspace:
41         local_irq_disable               # make sure we dont miss an
42                                         # interrupt setting need_resched
43                                         # between sampling and return
44         LONG_L  a2, TI_FLAGS($28)       # current->work
45         andi    t0, a2, _TIF_WORK_MASK  # (ignoring syscall_trace)
46         bnez    t0, work_pending
47         j       restore_all
48
49 #ifdef CONFIG_PREEMPT
50 resume_kernel:
51         local_irq_disable
52         lw      t0, TI_PRE_COUNT($28)
53         bnez    t0, restore_all
54 need_resched:
55         LONG_L  t0, TI_FLAGS($28)
56         andi    t1, t0, _TIF_NEED_RESCHED
57         beqz    t1, restore_all
58         LONG_L  t0, PT_STATUS(sp)               # Interrupts off?
59         andi    t0, 1
60         beqz    t0, restore_all
61         jal     preempt_schedule_irq
62         b       need_resched
63 #endif
64
65 FEXPORT(ret_from_fork)
66         jal     schedule_tail           # a0 = task_t *prev
67
68 FEXPORT(syscall_exit)
69         local_irq_disable               # make sure need_resched and
70                                         # signals dont change between
71                                         # sampling and return
72         LONG_L  a2, TI_FLAGS($28)       # current->work
73         li      t0, _TIF_ALLWORK_MASK
74         and     t0, a2, t0
75         bnez    t0, syscall_exit_work
76
77 FEXPORT(restore_all)                    # restore full frame
78         .set    noat
79         RESTORE_TEMP
80         RESTORE_AT
81         RESTORE_STATIC
82 FEXPORT(restore_partial)                # restore partial frame
83         RESTORE_SOME
84         RESTORE_SP_AND_RET
85         .set    at
86
87 work_pending:
88         andi    t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS
89         beqz    t0, work_notifysig
90 work_resched:
91         jal     schedule
92
93         local_irq_disable               # make sure need_resched and
94                                         # signals dont change between
95                                         # sampling and return
96         LONG_L  a2, TI_FLAGS($28)
97         andi    t0, a2, _TIF_WORK_MASK  # is there any work to be done
98                                         # other than syscall tracing?
99         beqz    t0, restore_all
100         andi    t0, a2, _TIF_NEED_RESCHED
101         bnez    t0, work_resched
102
103 work_notifysig:                         # deal with pending signals and
104                                         # notify-resume requests
105         move    a0, sp
106         li      a1, 0
107         jal     do_notify_resume        # a2 already loaded
108         j       resume_userspace
109
110 FEXPORT(syscall_exit_work_partial)
111         SAVE_STATIC
112 syscall_exit_work:
113         li      t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
114         and     t0, a2                  # a2 is preloaded with TI_FLAGS
115         beqz    t0, work_pending        # trace bit set?
116         local_irq_enable                # could let do_syscall_trace()
117                                         # call schedule() instead
118         move    a0, sp
119         li      a1, 1
120         jal     do_syscall_trace
121         b       resume_userspace
122
123 /*
124  * Common spurious interrupt handler.
125  */
126 LEAF(spurious_interrupt)
127         /*
128          * Someone tried to fool us by sending an interrupt but we
129          * couldn't find a cause for it.
130          */
131         PTR_LA  t1, irq_err_count
132 #ifdef CONFIG_SMP
133 1:      ll      t0, (t1)
134         addiu   t0, 1
135         sc      t0, (t1)
136 #if R10000_LLSC_WAR
137         beqzl   t0, 1b
138 #else
139         beqz    t0, 1b
140 #endif
141 #else
142         lw      t0, (t1)
143         addiu   t0, 1
144         sw      t0, (t1)
145 #endif
146         j       ret_from_irq
147         END(spurious_interrupt)