Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck...
[linux-drm-fsl-dcu.git] / arch / m32r / kernel / entry.S
1 /*
2  *  linux/arch/m32r/kernel/entry.S
3  *
4  *  Copyright (c) 2001, 2002  Hirokazu Takata, Hitoshi Yamamoto, H. Kondo
5  *  Copyright (c) 2003  Hitoshi Yamamoto
6  *  Copyright (c) 2004  Hirokazu Takata <takata at linux-m32r.org>
7  *
8  *  Taken from i386 version.
9  *    Copyright (C) 1991, 1992  Linus Torvalds
10  */
11
12 /*
13  * entry.S contains the system-call and fault low-level handling routines.
14  * This also contains the timer-interrupt handler, as well as all interrupts
15  * and faults that can result in a task-switch.
16  *
17  * NOTE: This code handles signal-recognition, which happens every time
18  * after a timer-interrupt and after each system call.
19  *
20  * Stack layout in 'ret_from_system_call':
21  *      ptrace needs to have all regs on the stack.
22  *      if the order here is changed, it needs to be
23  *      updated in fork.c:copy_thread, signal.c:do_signal,
24  *      ptrace.c and ptrace.h
25  *
26  * M32R/M32Rx/M32R2
27  *       @(sp)      - r4
28  *       @(0x04,sp) - r5
29  *       @(0x08,sp) - r6
30  *       @(0x0c,sp) - *pt_regs
31  *       @(0x10,sp) - r0
32  *       @(0x14,sp) - r1
33  *       @(0x18,sp) - r2
34  *       @(0x1c,sp) - r3
35  *       @(0x20,sp) - r7
36  *       @(0x24,sp) - r8
37  *       @(0x28,sp) - r9
38  *       @(0x2c,sp) - r10
39  *       @(0x30,sp) - r11
40  *       @(0x34,sp) - r12
41  *       @(0x38,sp) - syscall_nr
42  *       @(0x3c,sp) - acc0h
43  *       @(0x40,sp) - acc0l
44  *       @(0x44,sp) - acc1h             ; ISA_DSP_LEVEL2 only
45  *       @(0x48,sp) - acc1l             ; ISA_DSP_LEVEL2 only
46  *       @(0x4c,sp) - psw
47  *       @(0x50,sp) - bpc
48  *       @(0x54,sp) - bbpsw
49  *       @(0x58,sp) - bbpc
50  *       @(0x5c,sp) - spu (cr3)
51  *       @(0x60,sp) - fp (r13)
52  *       @(0x64,sp) - lr (r14)
53  *       @(0x68,sp) - spi (cr2)
54  *       @(0x6c,sp) - orig_r0
55  */
56
57 #include <linux/linkage.h>
58 #include <asm/irq.h>
59 #include <asm/unistd.h>
60 #include <asm/assembler.h>
61 #include <asm/thread_info.h>
62 #include <asm/errno.h>
63 #include <asm/segment.h>
64 #include <asm/smp.h>
65 #include <asm/page.h>
66 #include <asm/m32r.h>
67 #include <asm/mmu_context.h>
68
69 #if !defined(CONFIG_MMU)
70 #define sys_madvise             sys_ni_syscall
71 #define sys_readahead           sys_ni_syscall
72 #define sys_mprotect            sys_ni_syscall
73 #define sys_msync               sys_ni_syscall
74 #define sys_mlock               sys_ni_syscall
75 #define sys_munlock             sys_ni_syscall
76 #define sys_mlockall            sys_ni_syscall
77 #define sys_munlockall          sys_ni_syscall
78 #define sys_mremap              sys_ni_syscall
79 #define sys_mincore             sys_ni_syscall
80 #define sys_remap_file_pages    sys_ni_syscall
81 #endif /* CONFIG_MMU */
82
83 #define R4(reg)                 @reg
84 #define R5(reg)                 @(0x04,reg)
85 #define R6(reg)                 @(0x08,reg)
86 #define PTREGS(reg)             @(0x0C,reg)
87 #define R0(reg)                 @(0x10,reg)
88 #define R1(reg)                 @(0x14,reg)
89 #define R2(reg)                 @(0x18,reg)
90 #define R3(reg)                 @(0x1C,reg)
91 #define R7(reg)                 @(0x20,reg)
92 #define R8(reg)                 @(0x24,reg)
93 #define R9(reg)                 @(0x28,reg)
94 #define R10(reg)                @(0x2C,reg)
95 #define R11(reg)                @(0x30,reg)
96 #define R12(reg)                @(0x34,reg)
97 #define SYSCALL_NR(reg)         @(0x38,reg)
98 #define ACC0H(reg)              @(0x3C,reg)
99 #define ACC0L(reg)              @(0x40,reg)
100 #define ACC1H(reg)              @(0x44,reg)
101 #define ACC1L(reg)              @(0x48,reg)
102 #define PSW(reg)                @(0x4C,reg)
103 #define BPC(reg)                @(0x50,reg)
104 #define BBPSW(reg)              @(0x54,reg)
105 #define BBPC(reg)               @(0x58,reg)
106 #define SPU(reg)                @(0x5C,reg)
107 #define FP(reg)                 @(0x60,reg)  /* FP = R13 */
108 #define LR(reg)                 @(0x64,reg)
109 #define SP(reg)                 @(0x68,reg)
110 #define ORIG_R0(reg)            @(0x6C,reg)
111
112 #define nr_syscalls ((syscall_table_size)/4)
113
114 #ifdef CONFIG_PREEMPT
115 #define preempt_stop(x)         DISABLE_INTERRUPTS(x)
116 #else
117 #define preempt_stop(x)
118 #define resume_kernel           restore_all
119 #endif
120
121 /* how to get the thread information struct from ASM */
122 #define GET_THREAD_INFO(reg)    GET_THREAD_INFO reg
123         .macro GET_THREAD_INFO reg
124         ldi     \reg, #-THREAD_SIZE
125         and     \reg, sp
126         .endm
127
128 ENTRY(ret_from_kernel_thread)
129         pop     r0
130         bl      schedule_tail
131         GET_THREAD_INFO(r8)
132         ld      r0, R0(r8)
133         ld      r1, R1(r8)
134         jl      r1
135         bra     syscall_exit
136
137 ENTRY(ret_from_fork)
138         pop     r0
139         bl      schedule_tail
140         GET_THREAD_INFO(r8)
141         bra     syscall_exit
142
143 /*
144  * Return to user mode is not as complex as all this looks,
145  * but we want the default path for a system call return to
146  * go as quickly as possible which is why some of this is
147  * less clear than it otherwise should be.
148  */
149
150         ; userspace resumption stub bypassing syscall exit tracing
151         ALIGN
152 ret_from_exception:
153         preempt_stop(r4)
154 ret_from_intr:
155         ld      r4, PSW(sp)
156 #ifdef CONFIG_ISA_M32R2
157         and3    r4, r4, #0x8800         ; check BSM and BPM bits
158 #else
159         and3    r4, r4, #0x8000         ; check BSM bit
160 #endif
161         beqz    r4, resume_kernel
162 resume_userspace:
163         DISABLE_INTERRUPTS(r4)          ; make sure we don't miss an interrupt
164                                         ; setting need_resched or sigpending
165                                         ; between sampling and the iret
166         GET_THREAD_INFO(r8)
167         ld      r9, @(TI_FLAGS, r8)
168         and3    r4, r9, #_TIF_WORK_MASK ; is there any work to be done on
169                                         ; int/exception return?
170         bnez    r4, work_pending
171         bra     restore_all
172
173 #ifdef CONFIG_PREEMPT
174 ENTRY(resume_kernel)
175         GET_THREAD_INFO(r8)
176         ld      r9, @(TI_PRE_COUNT, r8) ; non-zero preempt_count ?
177         bnez    r9, restore_all
178 need_resched:
179         ld      r9, @(TI_FLAGS, r8)     ; need_resched set ?
180         and3    r4, r9, #_TIF_NEED_RESCHED
181         beqz    r4, restore_all
182         ld      r4, PSW(sp)             ; interrupts off (exception path) ?
183         and3    r4, r4, #0x4000
184         beqz    r4, restore_all
185         bl      preempt_schedule_irq
186         bra     need_resched
187 #endif
188
189         ; system call handler stub
190 ENTRY(system_call)
191         SWITCH_TO_KERNEL_STACK
192         SAVE_ALL
193         ENABLE_INTERRUPTS(r4)           ; Enable interrupt
194         st      sp, PTREGS(sp)          ; implicit pt_regs parameter
195         cmpui   r7, #NR_syscalls
196         bnc     syscall_badsys
197         st      r7, SYSCALL_NR(sp)      ; syscall_nr
198                                         ; system call tracing in operation
199         GET_THREAD_INFO(r8)
200         ld      r9, @(TI_FLAGS, r8)
201         and3    r4, r9, #_TIF_SYSCALL_TRACE
202         bnez    r4, syscall_trace_entry
203 syscall_call:
204         slli    r7, #2                  ; table jump for the system call
205         LDIMM   (r4, sys_call_table)
206         add     r7, r4
207         ld      r7, @r7
208         jl      r7                      ; execute system call
209         st      r0, R0(sp)              ; save the return value
210 syscall_exit:
211         DISABLE_INTERRUPTS(r4)          ; make sure we don't miss an interrupt
212                                         ; setting need_resched or sigpending
213                                         ; between sampling and the iret
214         ld      r9, @(TI_FLAGS, r8)
215         and3    r4, r9, #_TIF_ALLWORK_MASK      ; current->work
216         bnez    r4, syscall_exit_work
217 restore_all:
218         RESTORE_ALL
219
220         # perform work that needs to be done immediately before resumption
221         # r9 : flags
222         ALIGN
223 work_pending:
224         and3    r4, r9, #_TIF_NEED_RESCHED
225         beqz    r4, work_notifysig
226 work_resched:
227         bl      schedule
228         DISABLE_INTERRUPTS(r4)          ; make sure we don't miss an interrupt
229                                         ; setting need_resched or sigpending
230                                         ; between sampling and the iret
231         ld      r9, @(TI_FLAGS, r8)
232         and3    r4, r9, #_TIF_WORK_MASK ; is there any work to be done other
233                                         ; than syscall tracing?
234         beqz    r4, restore_all
235         and3    r4, r4, #_TIF_NEED_RESCHED
236         bnez    r4, work_resched
237
238 work_notifysig:                         ; deal with pending signals and
239                                         ; notify-resume requests
240         mv      r0, sp                  ; arg1 : struct pt_regs *regs
241         mv      r1, r9                  ; arg2 : __u32 thread_info_flags
242         bl      do_notify_resume
243         bra     resume_userspace
244
245         ; perform syscall exit tracing
246         ALIGN
247 syscall_trace_entry:
248         ldi     r4, #-ENOSYS
249         st      r4, R0(sp)
250         bl      do_syscall_trace
251         ld      r0, ORIG_R0(sp)
252         ld      r1, R1(sp)
253         ld      r2, R2(sp)
254         ld      r3, R3(sp)
255         ld      r4, R4(sp)
256         ld      r5, R5(sp)
257         ld      r6, R6(sp)
258         ld      r7, SYSCALL_NR(sp)
259         cmpui   r7, #NR_syscalls
260         bc      syscall_call
261         bra     syscall_exit
262
263         ; perform syscall exit tracing
264         ALIGN
265 syscall_exit_work:
266         ld      r9, @(TI_FLAGS, r8)
267         and3    r4, r9, #_TIF_SYSCALL_TRACE
268         beqz    r4, work_pending
269         ENABLE_INTERRUPTS(r4)           ; could let do_syscall_trace() call
270                                         ; schedule() instead
271         bl      do_syscall_trace
272         bra     resume_userspace
273
274         ALIGN
275 syscall_fault:
276         SAVE_ALL
277         GET_THREAD_INFO(r8)
278         ldi     r4, #-EFAULT
279         st      r4, R0(sp)
280         bra     resume_userspace
281
282         ALIGN
283 syscall_badsys:
284         ldi     r4, #-ENOSYS
285         st      r4, R0(sp)
286         bra     resume_userspace
287
288         .global eit_vector
289
290         .equ ei_vec_table, eit_vector + 0x0200
291
292 /*
293  * EI handler routine
294  */
295 ENTRY(ei_handler)
296 #if defined(CONFIG_CHIP_M32700)
297         ; WORKAROUND: force to clear SM bit and use the kernel stack (SPI).
298         SWITCH_TO_KERNEL_STACK
299 #endif
300         SAVE_ALL
301         mv      r1, sp                  ; arg1(regs)
302         ; get ICU status
303         seth    r0, #shigh(M32R_ICU_ISTS_ADDR)
304         ld      r0, @(low(M32R_ICU_ISTS_ADDR),r0)
305         push    r0
306 #if defined(CONFIG_SMP)
307         /*
308          * If IRQ == 0      --> Nothing to do,  Not write IMASK
309          * If IRQ == IPI    --> Do IPI handler, Not write IMASK
310          * If IRQ != 0, IPI --> Do do_IRQ(),    Write IMASK
311          */
312         slli    r0, #4
313         srli    r0, #24                 ; r0(irq_num<<2)
314         ;; IRQ exist check
315 #if defined(CONFIG_CHIP_M32700)
316         /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */
317         bnez    r0, 0f
318         ld24    r14, #0x00070000
319         seth    r0, #shigh(M32R_ICU_IMASK_ADDR)
320         st      r14, @(low(M32R_ICU_IMASK_ADDR),r0)
321         bra     1f
322         .fillinsn
323 0:
324 #endif /* CONFIG_CHIP_M32700 */
325         beqz    r0, 1f                  ; if (!irq_num) goto exit
326         ;; IPI check
327         cmpi    r0, #(M32R_IRQ_IPI0<<2) ; ISN < IPI0 check
328         bc      2f
329         cmpi    r0, #((M32R_IRQ_IPI7+1)<<2)     ; ISN > IPI7 check
330         bnc     2f
331         LDIMM   (r2, ei_vec_table)
332         add     r2, r0
333         ld      r2, @r2
334         beqz    r2, 1f                  ; if (no IPI handler) goto exit
335         mv      r0, r1                  ; arg0(regs)
336         jl      r2
337         .fillinsn
338 1:
339         addi    sp, #4
340         bra     restore_all
341         .fillinsn
342 2:
343         srli    r0, #2
344 #else /* not CONFIG_SMP */
345         srli    r0, #22                 ; r0(irq)
346 #endif /* not CONFIG_SMP */
347
348 #if defined(CONFIG_PLAT_HAS_INT1ICU)
349         add3    r2, r0, #-(M32R_IRQ_INT1)       ; INT1# interrupt
350         bnez    r2, 3f
351         seth    r0, #shigh(M32R_INT1ICU_ISTS)
352         lduh    r0, @(low(M32R_INT1ICU_ISTS),r0)        ; bit10-6 : ISN
353         slli    r0, #21
354         srli    r0, #27                         ; ISN
355         addi    r0, #(M32R_INT1ICU_IRQ_BASE)
356         bra     check_end
357         .fillinsn
358 3:
359 #endif /* CONFIG_PLAT_HAS_INT1ICU */
360 #if defined(CONFIG_PLAT_HAS_INT0ICU)
361         add3    r2, r0, #-(M32R_IRQ_INT0)       ; INT0# interrupt
362         bnez    r2, 4f
363         seth    r0, #shigh(M32R_INT0ICU_ISTS)
364         lduh    r0, @(low(M32R_INT0ICU_ISTS),r0)        ; bit10-6 : ISN
365         slli    r0, #21
366         srli    r0, #27                         ; ISN
367         add3    r0, r0, #(M32R_INT0ICU_IRQ_BASE)
368         bra     check_end
369         .fillinsn
370 4:
371 #endif /* CONFIG_PLAT_HAS_INT0ICU */
372 #if defined(CONFIG_PLAT_HAS_INT2ICU)
373         add3    r2, r0, #-(M32R_IRQ_INT2)       ; INT2# interrupt
374         bnez    r2, 5f
375         seth    r0, #shigh(M32R_INT2ICU_ISTS)
376         lduh    r0, @(low(M32R_INT2ICU_ISTS),r0)        ; bit10-6 : ISN
377         slli    r0, #21
378         srli    r0, #27                         ; ISN
379         add3    r0, r0, #(M32R_INT2ICU_IRQ_BASE)
380         ; bra   check_end
381         .fillinsn
382 5:
383 #endif /* CONFIG_PLAT_HAS_INT2ICU */
384
385 check_end:
386         bl      do_IRQ
387         pop     r14
388         seth    r0, #shigh(M32R_ICU_IMASK_ADDR)
389         st      r14, @(low(M32R_ICU_IMASK_ADDR),r0)
390         bra  ret_from_intr
391
392 /*
393  * Default EIT handler
394  */
395         ALIGN
396 int_msg:
397         .asciz  "Unknown interrupt\n"
398         .byte   0
399
400 ENTRY(default_eit_handler)
401         push    r0
402         mvfc    r0, psw
403         push    r1
404         push    r2
405         push    r3
406         push    r0
407         LDIMM   (r0, __KERNEL_DS)
408         mv      r0, r1
409         mv      r0, r2
410         LDIMM   (r0, int_msg)
411         bl      printk
412         pop     r0
413         pop     r3
414         pop     r2
415         pop     r1
416         mvtc    r0, psw
417         pop     r0
418 infinit:
419         bra     infinit
420
421 #ifdef CONFIG_MMU
422 /*
423  * Access Exception handler
424  */
425 ENTRY(ace_handler)
426         SWITCH_TO_KERNEL_STACK
427         SAVE_ALL
428
429         seth    r2, #shigh(MMU_REG_BASE)        /* Check status register */
430         ld      r4, @(low(MESTS_offset),r2)
431         st      r4, @(low(MESTS_offset),r2)
432         srl3    r1, r4, #4
433 #ifdef CONFIG_CHIP_M32700
434         and3    r1, r1, #0x0000ffff
435         ; WORKAROUND: ignore TME bit for the M32700(TS1).
436 #endif /* CONFIG_CHIP_M32700 */
437         beqz    r1, inst
438 oprand:
439         ld      r2, @(low(MDEVA_offset),r2)     ; set address
440         srli    r1, #1
441         bra     1f
442 inst:
443         and3    r1, r4, #2
444         srli    r1, #1
445         or3     r1, r1, #8
446         mvfc    r2, bpc                         ; set address
447         .fillinsn
448 1:
449         mvfc    r3, psw
450         mv      r0, sp
451         and3    r3, r3, 0x800
452         srli    r3, #9
453         or      r1, r3
454         /*
455          * do_page_fault():
456          *    r0 : struct pt_regs *regs
457          *    r1 : unsigned long error-code
458          *    r2 : unsigned long address
459          * error-code:
460          *    +------+------+------+------+
461          *    | bit3 | bit2 | bit1 | bit0 |
462          *    +------+------+------+------+
463          *    bit 3 == 0:means data,          1:means instruction
464          *    bit 2 == 0:means kernel,        1:means user-mode
465          *    bit 1 == 0:means read,          1:means write
466          *    bit 0 == 0:means no page found  1:means protection fault
467          *
468          */
469         bl      do_page_fault
470         bra     ret_from_intr
471 #endif  /* CONFIG_MMU */
472
473
474 ENTRY(alignment_check)
475         /* void alignment_check(int error_code) */
476         SWITCH_TO_KERNEL_STACK
477         SAVE_ALL
478         ldi     r1, #0x30                       ; error_code
479         mv      r0, sp                          ; pt_regs
480         bl      do_alignment_check
481 error_code:
482         bra     ret_from_exception
483
484 ENTRY(rie_handler)
485         /* void rie_handler(int error_code) */
486         SWITCH_TO_KERNEL_STACK
487         SAVE_ALL
488         ldi     r1, #0x20                       ; error_code
489         mv      r0, sp                          ; pt_regs
490         bl      do_rie_handler
491         bra     error_code
492
493 ENTRY(pie_handler)
494         /* void pie_handler(int error_code) */
495         SWITCH_TO_KERNEL_STACK
496         SAVE_ALL
497         ldi     r1, #0                          ; error_code ; FIXME
498         mv      r0, sp                          ; pt_regs
499         bl      do_pie_handler
500         bra     error_code
501
502 ENTRY(debug_trap)
503         /* void debug_trap(void) */
504         .global withdraw_debug_trap
505         SWITCH_TO_KERNEL_STACK
506         SAVE_ALL
507         mv      r0, sp                          ; pt_regs
508         bl      withdraw_debug_trap
509         ldi     r1, #0                          ; error_code
510         mv      r0, sp                          ; pt_regs
511         bl      do_debug_trap
512         bra     error_code
513
514 ENTRY(ill_trap)
515         /* void ill_trap(void) */
516         SWITCH_TO_KERNEL_STACK
517         SAVE_ALL
518         ldi     r1, #0                          ; error_code ; FIXME
519         mv      r0, sp                          ; pt_regs
520         bl      do_ill_trap
521         bra     error_code
522
523 ENTRY(cache_flushing_handler)
524         /* void _flush_cache_all(void); */
525         .global _flush_cache_all
526         SWITCH_TO_KERNEL_STACK
527         push    r0
528         push    r1
529         push    r2
530         push    r3
531         push    r4
532         push    r5
533         push    r6
534         push    r7
535         push    lr
536         bl      _flush_cache_all
537         pop     lr
538         pop     r7
539         pop     r6
540         pop     r5
541         pop     r4
542         pop     r3
543         pop     r2
544         pop     r1
545         pop     r0
546         rte
547
548         .section .rodata,"a"
549 #include "syscall_table.S"
550
551 syscall_table_size=(.-sys_call_table)