diff options
| -rw-r--r-- | arch/tile/include/asm/thread_info.h | 9 | ||||
| -rw-r--r-- | arch/tile/kernel/intvec_32.S | 41 | ||||
| -rw-r--r-- | arch/tile/kernel/intvec_64.S | 38 | ||||
| -rw-r--r-- | arch/tile/kernel/process.c | 7 |
4 files changed, 68 insertions, 27 deletions
diff --git a/arch/tile/include/asm/thread_info.h b/arch/tile/include/asm/thread_info.h index bc4f562bd459..7594764d8a69 100644 --- a/arch/tile/include/asm/thread_info.h +++ b/arch/tile/include/asm/thread_info.h | |||
| @@ -100,9 +100,14 @@ extern void cpu_idle_on_new_stack(struct thread_info *old_ti, | |||
| 100 | 100 | ||
| 101 | #else /* __ASSEMBLY__ */ | 101 | #else /* __ASSEMBLY__ */ |
| 102 | 102 | ||
| 103 | /* how to get the thread information struct from ASM */ | 103 | /* |
| 104 | * How to get the thread information struct from assembly. | ||
| 105 | * Note that we use different macros since different architectures | ||
| 106 | * have different semantics in their "mm" instruction and we would | ||
| 107 | * like to guarantee that the macro expands to exactly one instruction. | ||
| 108 | */ | ||
| 104 | #ifdef __tilegx__ | 109 | #ifdef __tilegx__ |
| 105 | #define GET_THREAD_INFO(reg) move reg, sp; mm reg, zero, LOG2_THREAD_SIZE, 63 | 110 | #define EXTRACT_THREAD_INFO(reg) mm reg, zero, LOG2_THREAD_SIZE, 63 |
| 106 | #else | 111 | #else |
| 107 | #define GET_THREAD_INFO(reg) mm reg, sp, zero, LOG2_THREAD_SIZE, 31 | 112 | #define GET_THREAD_INFO(reg) mm reg, sp, zero, LOG2_THREAD_SIZE, 31 |
| 108 | #endif | 113 | #endif |
diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S index 5d56a1ef5ba5..6943515100f8 100644 --- a/arch/tile/kernel/intvec_32.S +++ b/arch/tile/kernel/intvec_32.S | |||
| @@ -839,6 +839,18 @@ STD_ENTRY(interrupt_return) | |||
| 839 | FEEDBACK_REENTER(interrupt_return) | 839 | FEEDBACK_REENTER(interrupt_return) |
| 840 | 840 | ||
| 841 | /* | 841 | /* |
| 842 | * Use r33 to hold whether we have already loaded the callee-saves | ||
| 843 | * into ptregs. We don't want to do it twice in this loop, since | ||
| 844 | * then we'd clobber whatever changes are made by ptrace, etc. | ||
| 845 | * Get base of stack in r32. | ||
| 846 | */ | ||
| 847 | { | ||
| 848 | GET_THREAD_INFO(r32) | ||
| 849 | movei r33, 0 | ||
| 850 | } | ||
| 851 | |||
| 852 | .Lretry_work_pending: | ||
| 853 | /* | ||
| 842 | * Disable interrupts so as to make sure we don't | 854 | * Disable interrupts so as to make sure we don't |
| 843 | * miss an interrupt that sets any of the thread flags (like | 855 | * miss an interrupt that sets any of the thread flags (like |
| 844 | * need_resched or sigpending) between sampling and the iret. | 856 | * need_resched or sigpending) between sampling and the iret. |
| @@ -848,9 +860,6 @@ STD_ENTRY(interrupt_return) | |||
| 848 | IRQ_DISABLE(r20, r21) | 860 | IRQ_DISABLE(r20, r21) |
| 849 | TRACE_IRQS_OFF /* Note: clobbers registers r0-r29 */ | 861 | TRACE_IRQS_OFF /* Note: clobbers registers r0-r29 */ |
| 850 | 862 | ||
| 851 | /* Get base of stack in r32; note r30/31 are used as arguments here. */ | ||
| 852 | GET_THREAD_INFO(r32) | ||
| 853 | |||
| 854 | 863 | ||
| 855 | /* Check to see if there is any work to do before returning to user. */ | 864 | /* Check to see if there is any work to do before returning to user. */ |
| 856 | { | 865 | { |
| @@ -866,16 +875,18 @@ STD_ENTRY(interrupt_return) | |||
| 866 | 875 | ||
| 867 | /* | 876 | /* |
| 868 | * Make sure we have all the registers saved for signal | 877 | * Make sure we have all the registers saved for signal |
| 869 | * handling or single-step. Call out to C code to figure out | 878 | * handling, notify-resume, or single-step. Call out to C |
| 870 | * exactly what we need to do for each flag bit, then if | 879 | * code to figure out exactly what we need to do for each flag bit, |
| 871 | * necessary, reload the flags and recheck. | 880 | * then if necessary, reload the flags and recheck. |
| 872 | */ | 881 | */ |
| 873 | push_extra_callee_saves r0 | ||
| 874 | { | 882 | { |
| 875 | PTREGS_PTR(r0, PTREGS_OFFSET_BASE) | 883 | PTREGS_PTR(r0, PTREGS_OFFSET_BASE) |
| 876 | jal do_work_pending | 884 | bnz r33, 1f |
| 877 | } | 885 | } |
| 878 | bnz r0, .Lresume_userspace | 886 | push_extra_callee_saves r0 |
| 887 | movei r33, 1 | ||
| 888 | 1: jal do_work_pending | ||
| 889 | bnz r0, .Lretry_work_pending | ||
| 879 | 890 | ||
| 880 | /* | 891 | /* |
| 881 | * In the NMI case we | 892 | * In the NMI case we |
| @@ -1180,10 +1191,12 @@ handle_syscall: | |||
| 1180 | add r20, r20, tp | 1191 | add r20, r20, tp |
| 1181 | lw r21, r20 | 1192 | lw r21, r20 |
| 1182 | addi r21, r21, 1 | 1193 | addi r21, r21, 1 |
| 1183 | sw r20, r21 | 1194 | { |
| 1195 | sw r20, r21 | ||
| 1196 | GET_THREAD_INFO(r31) | ||
| 1197 | } | ||
| 1184 | 1198 | ||
| 1185 | /* Trace syscalls, if requested. */ | 1199 | /* Trace syscalls, if requested. */ |
| 1186 | GET_THREAD_INFO(r31) | ||
| 1187 | addi r31, r31, THREAD_INFO_FLAGS_OFFSET | 1200 | addi r31, r31, THREAD_INFO_FLAGS_OFFSET |
| 1188 | lw r30, r31 | 1201 | lw r30, r31 |
| 1189 | andi r30, r30, _TIF_SYSCALL_TRACE | 1202 | andi r30, r30, _TIF_SYSCALL_TRACE |
| @@ -1362,7 +1375,10 @@ handle_ill: | |||
| 1362 | 3: | 1375 | 3: |
| 1363 | /* set PC and continue */ | 1376 | /* set PC and continue */ |
| 1364 | lw r26, r24 | 1377 | lw r26, r24 |
| 1365 | sw r28, r26 | 1378 | { |
| 1379 | sw r28, r26 | ||
| 1380 | GET_THREAD_INFO(r0) | ||
| 1381 | } | ||
| 1366 | 1382 | ||
| 1367 | /* | 1383 | /* |
| 1368 | * Clear TIF_SINGLESTEP to prevent recursion if we execute an ill. | 1384 | * Clear TIF_SINGLESTEP to prevent recursion if we execute an ill. |
| @@ -1370,7 +1386,6 @@ handle_ill: | |||
| 1370 | * need to clear it here and can't really impose on all other arches. | 1386 | * need to clear it here and can't really impose on all other arches. |
| 1371 | * So what's another write between friends? | 1387 | * So what's another write between friends? |
| 1372 | */ | 1388 | */ |
| 1373 | GET_THREAD_INFO(r0) | ||
| 1374 | 1389 | ||
| 1375 | addi r1, r0, THREAD_INFO_FLAGS_OFFSET | 1390 | addi r1, r0, THREAD_INFO_FLAGS_OFFSET |
| 1376 | { | 1391 | { |
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S index 49d9d6621682..30ae76e50c44 100644 --- a/arch/tile/kernel/intvec_64.S +++ b/arch/tile/kernel/intvec_64.S | |||
| @@ -647,6 +647,20 @@ STD_ENTRY(interrupt_return) | |||
| 647 | FEEDBACK_REENTER(interrupt_return) | 647 | FEEDBACK_REENTER(interrupt_return) |
| 648 | 648 | ||
| 649 | /* | 649 | /* |
| 650 | * Use r33 to hold whether we have already loaded the callee-saves | ||
| 651 | * into ptregs. We don't want to do it twice in this loop, since | ||
| 652 | * then we'd clobber whatever changes are made by ptrace, etc. | ||
| 653 | */ | ||
| 654 | { | ||
| 655 | movei r33, 0 | ||
| 656 | move r32, sp | ||
| 657 | } | ||
| 658 | |||
| 659 | /* Get base of stack in r32. */ | ||
| 660 | EXTRACT_THREAD_INFO(r32) | ||
| 661 | |||
| 662 | .Lretry_work_pending: | ||
| 663 | /* | ||
| 650 | * Disable interrupts so as to make sure we don't | 664 | * Disable interrupts so as to make sure we don't |
| 651 | * miss an interrupt that sets any of the thread flags (like | 665 | * miss an interrupt that sets any of the thread flags (like |
| 652 | * need_resched or sigpending) between sampling and the iret. | 666 | * need_resched or sigpending) between sampling and the iret. |
| @@ -656,9 +670,6 @@ STD_ENTRY(interrupt_return) | |||
| 656 | IRQ_DISABLE(r20, r21) | 670 | IRQ_DISABLE(r20, r21) |
| 657 | TRACE_IRQS_OFF /* Note: clobbers registers r0-r29 */ | 671 | TRACE_IRQS_OFF /* Note: clobbers registers r0-r29 */ |
| 658 | 672 | ||
| 659 | /* Get base of stack in r32; note r30/31 are used as arguments here. */ | ||
| 660 | GET_THREAD_INFO(r32) | ||
| 661 | |||
| 662 | 673 | ||
| 663 | /* Check to see if there is any work to do before returning to user. */ | 674 | /* Check to see if there is any work to do before returning to user. */ |
| 664 | { | 675 | { |
| @@ -674,16 +685,18 @@ STD_ENTRY(interrupt_return) | |||
| 674 | 685 | ||
| 675 | /* | 686 | /* |
| 676 | * Make sure we have all the registers saved for signal | 687 | * Make sure we have all the registers saved for signal |
| 677 | * handling or single-step. Call out to C code to figure out | 688 | * handling or notify-resume. Call out to C code to figure out |
| 678 | * exactly what we need to do for each flag bit, then if | 689 | * exactly what we need to do for each flag bit, then if |
| 679 | * necessary, reload the flags and recheck. | 690 | * necessary, reload the flags and recheck. |
| 680 | */ | 691 | */ |
| 681 | push_extra_callee_saves r0 | ||
| 682 | { | 692 | { |
| 683 | PTREGS_PTR(r0, PTREGS_OFFSET_BASE) | 693 | PTREGS_PTR(r0, PTREGS_OFFSET_BASE) |
| 684 | jal do_work_pending | 694 | bnez r33, 1f |
| 685 | } | 695 | } |
| 686 | bnez r0, .Lresume_userspace | 696 | push_extra_callee_saves r0 |
| 697 | movei r33, 1 | ||
| 698 | 1: jal do_work_pending | ||
| 699 | bnez r0, .Lretry_work_pending | ||
| 687 | 700 | ||
| 688 | /* | 701 | /* |
| 689 | * In the NMI case we | 702 | * In the NMI case we |
| @@ -968,11 +981,16 @@ handle_syscall: | |||
| 968 | shl16insli r20, r20, hw0(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET) | 981 | shl16insli r20, r20, hw0(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET) |
| 969 | add r20, r20, tp | 982 | add r20, r20, tp |
| 970 | ld4s r21, r20 | 983 | ld4s r21, r20 |
| 971 | addi r21, r21, 1 | 984 | { |
| 972 | st4 r20, r21 | 985 | addi r21, r21, 1 |
| 986 | move r31, sp | ||
| 987 | } | ||
| 988 | { | ||
| 989 | st4 r20, r21 | ||
| 990 | EXTRACT_THREAD_INFO(r31) | ||
| 991 | } | ||
| 973 | 992 | ||
| 974 | /* Trace syscalls, if requested. */ | 993 | /* Trace syscalls, if requested. */ |
| 975 | GET_THREAD_INFO(r31) | ||
| 976 | addi r31, r31, THREAD_INFO_FLAGS_OFFSET | 994 | addi r31, r31, THREAD_INFO_FLAGS_OFFSET |
| 977 | ld r30, r31 | 995 | ld r30, r31 |
| 978 | andi r30, r30, _TIF_SYSCALL_TRACE | 996 | andi r30, r30, _TIF_SYSCALL_TRACE |
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index 2d5ef617bb39..54e6c64b85cc 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c | |||
| @@ -567,6 +567,10 @@ struct task_struct *__sched _switch_to(struct task_struct *prev, | |||
| 567 | */ | 567 | */ |
| 568 | int do_work_pending(struct pt_regs *regs, u32 thread_info_flags) | 568 | int do_work_pending(struct pt_regs *regs, u32 thread_info_flags) |
| 569 | { | 569 | { |
| 570 | /* If we enter in kernel mode, do nothing and exit the caller loop. */ | ||
| 571 | if (!user_mode(regs)) | ||
| 572 | return 0; | ||
| 573 | |||
| 570 | if (thread_info_flags & _TIF_NEED_RESCHED) { | 574 | if (thread_info_flags & _TIF_NEED_RESCHED) { |
| 571 | schedule(); | 575 | schedule(); |
| 572 | return 1; | 576 | return 1; |
| @@ -589,8 +593,7 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags) | |||
| 589 | return 1; | 593 | return 1; |
| 590 | } | 594 | } |
| 591 | if (thread_info_flags & _TIF_SINGLESTEP) { | 595 | if (thread_info_flags & _TIF_SINGLESTEP) { |
| 592 | if ((regs->ex1 & SPR_EX_CONTEXT_1_1__PL_MASK) == 0) | 596 | single_step_once(regs); |
| 593 | single_step_once(regs); | ||
| 594 | return 0; | 597 | return 0; |
| 595 | } | 598 | } |
| 596 | panic("work_pending: bad flags %#x\n", thread_info_flags); | 599 | panic("work_pending: bad flags %#x\n", thread_info_flags); |
