Commit 3633c730 authored by Hidetoshi Seto's avatar Hidetoshi Seto Committed by Tony Luck

[IA64] fix interrupt masking for pending works on kernel leave

[Bug-fix for "[BUG?][2.6.25-mm1] sleeping during IRQ disabled"]

This patch does:
 - enable interrupts before calling schedule() as same as others, ex. x86
 - enable interrupts during ia64_do_signal() and ia64_sync_krbs()
 - do_notify_resume_user() is still called with interrupts disabled, since
   we can take short path of fsys_mode if-statement quickly.
 - pfm_handle_work() is also called with interrupts disabled, since
   it can deal interrupt mask within itself.
 - fix/add some comments/notes
Reported-by: default avatarKOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: default avatarHidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
parent f13ae30e
...@@ -1156,6 +1156,9 @@ skip_rbs_switch: ...@@ -1156,6 +1156,9 @@ skip_rbs_switch:
* r31 = current->thread_info->flags * r31 = current->thread_info->flags
* On exit: * On exit:
* p6 = TRUE if work-pending-check needs to be redone * p6 = TRUE if work-pending-check needs to be redone
*
* Interrupts are disabled on entry, reenabled depend on work, and
* disabled on exit.
*/ */
.work_pending_syscall: .work_pending_syscall:
add r2=-8,r2 add r2=-8,r2
...@@ -1170,8 +1173,8 @@ skip_rbs_switch: ...@@ -1170,8 +1173,8 @@ skip_rbs_switch:
(pKStk) dep r21=-1,r0,PREEMPT_ACTIVE_BIT,1 (pKStk) dep r21=-1,r0,PREEMPT_ACTIVE_BIT,1
;; ;;
(pKStk) st4 [r20]=r21 (pKStk) st4 [r20]=r21
ssm psr.i // enable interrupts
#endif #endif
ssm psr.i // enable interrupts
br.call.spnt.many rp=schedule br.call.spnt.many rp=schedule
.ret9: cmp.eq p6,p0=r0,r0 // p6 <- 1 .ret9: cmp.eq p6,p0=r0,r0 // p6 <- 1
rsm psr.i // disable interrupts rsm psr.i // disable interrupts
...@@ -1234,9 +1237,12 @@ GLOBAL_ENTRY(ia64_invoke_schedule_tail) ...@@ -1234,9 +1237,12 @@ GLOBAL_ENTRY(ia64_invoke_schedule_tail)
END(ia64_invoke_schedule_tail) END(ia64_invoke_schedule_tail)
/* /*
* Setup stack and call do_notify_resume_user(). Note that pSys and pNonSys need to * Setup stack and call do_notify_resume_user(), keeping interrupts
* be set up by the caller. We declare 8 input registers so the system call * disabled.
* args get preserved, in case we need to restart a system call. *
* Note that pSys and pNonSys need to be set up by the caller.
* We declare 8 input registers so the system call args get preserved,
* in case we need to restart a system call.
*/ */
ENTRY(notify_resume_user) ENTRY(notify_resume_user)
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
......
...@@ -167,11 +167,18 @@ void tsk_clear_notify_resume(struct task_struct *tsk) ...@@ -167,11 +167,18 @@ void tsk_clear_notify_resume(struct task_struct *tsk)
clear_ti_thread_flag(task_thread_info(tsk), TIF_NOTIFY_RESUME); clear_ti_thread_flag(task_thread_info(tsk), TIF_NOTIFY_RESUME);
} }
/*
* do_notify_resume_user():
* Called from notify_resume_user at entry.S, with interrupts disabled.
*/
void void
do_notify_resume_user (sigset_t *unused, struct sigscratch *scr, long in_syscall) do_notify_resume_user(sigset_t *unused, struct sigscratch *scr, long in_syscall)
{ {
if (fsys_mode(current, &scr->pt)) { if (fsys_mode(current, &scr->pt)) {
/* defer signal-handling etc. until we return to privilege-level 0. */ /*
* defer signal-handling etc. until we return to
* privilege-level 0.
*/
if (!ia64_psr(&scr->pt)->lp) if (!ia64_psr(&scr->pt)->lp)
ia64_psr(&scr->pt)->lp = 1; ia64_psr(&scr->pt)->lp = 1;
return; return;
...@@ -179,16 +186,26 @@ do_notify_resume_user (sigset_t *unused, struct sigscratch *scr, long in_syscall ...@@ -179,16 +186,26 @@ do_notify_resume_user (sigset_t *unused, struct sigscratch *scr, long in_syscall
#ifdef CONFIG_PERFMON #ifdef CONFIG_PERFMON
if (current->thread.pfm_needs_checking) if (current->thread.pfm_needs_checking)
/*
* Note: pfm_handle_work() allow us to call it with interrupts
* disabled, and may enable interrupts within the function.
*/
pfm_handle_work(); pfm_handle_work();
#endif #endif
/* deal with pending signal delivery */ /* deal with pending signal delivery */
if (test_thread_flag(TIF_SIGPENDING)) if (test_thread_flag(TIF_SIGPENDING)) {
local_irq_enable(); /* force interrupt enable */
ia64_do_signal(scr, in_syscall); ia64_do_signal(scr, in_syscall);
}
/* copy user rbs to kernel rbs */ /* copy user rbs to kernel rbs */
if (unlikely(test_thread_flag(TIF_RESTORE_RSE))) if (unlikely(test_thread_flag(TIF_RESTORE_RSE))) {
local_irq_enable(); /* force interrupt enable */
ia64_sync_krbs(); ia64_sync_krbs();
}
local_irq_disable(); /* force interrupt disable */
} }
static int pal_halt = 1; static int pal_halt = 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment