Commit 4413dfbe authored by Stéphane Eranian's avatar Stéphane Eranian Committed by Tony Luck

[IA64] entry.S: perfmon psr.pp fix

Problem:
	There exists a case where we stop monitoring, i.e. clear
	psr.pp/dcr.pp, via IPI. This is when the stop is triggered
	by a close(), either explicit in the application or implicit
	via exit_files(). The IPI is necessary because at the time the
	thread (controlling the context) issues a close() it may not run
	on the CPU the context is bound to. Yet the call must succeed,
	hence we need to propagate the call to the right CPU.
	But what is the problem then?
	Under IPI, we invoke a perfmon routine which clear the kernel
	(live) kernel psr.pp bit and also dcr.pp. Then we return from
	the function and execute the kernel exit path which restores
	the interrupted state. Unfortunately, this restores the kernel
	psr from ipsr which now contains a stale value. Therefore
	monitoring in the kernel will be active even though we stopped it.
	You cannot modify the "global" psr in an interrupt routine because
	it will be systematically restored on the way back.
	
Solution:
	We need to patch ipsr.pp in the kernel exit path to reflect the
	kernel value of the kernel psr.pp bit. This must be done only when
	returning to kernel. 

	The proposed patch does patch ipsr.pp such that it is identical
	to psr.pp. The patch is subtle because the exit path does not have
	a lot of free registers and also because we need to schedule for
	a psr read. I had to shuffle  things around a little bit.

	The patch is important because there will be another situation where
	this problem can occur once we incorporate the support for event set
	and multiplexing. In this configuration, you may be in the middle of
	the idle loop and on a timer interrupt, you may stop monitoring.
	Slightly different condition, yet same problem with ipsr.pp vs. psr.pp.


Changelog:
	- update kernel exit path when returning to kernel to copy
	psr.pp to ipsr.pp. This is necesary to ensure that if psr.pp
	was modified during the kernel entry, the change is propagated
	the the psr.pp of the of the interrupted thread. Psr.pp can
	be modified as a consequence of an IPI under certain conditions,
	such as when a system-wide context is closed from a remote CPU.

Special thanks to David for reworking the patch to fit
into the enhanced exit path.
signed-off-by: default avatarstephane eranian <eranian@hpl.hp.com>
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
parent 94579094
......@@ -743,7 +743,7 @@ ENTRY(ia64_leave_syscall)
mov r22=r0 // clear r22
;;
ld8 r26=[r2],PT(B0)-PT(AR_PFS) // M0|1 load ar.pfs
nop.m 0
(pKStk) mov r22=psr // M2 read PSR now that interrupts are disabled
mov f10=f0 // clear f10
;;
ld8 r21=[r2],PT(AR_RNAT)-PT(B0) // load b0
......@@ -895,12 +895,16 @@ GLOBAL_ENTRY(ia64_leave_kernel)
srlz.i // ensure interruption collection is off
mov ar.ccv=r15
;;
ldf.fill f11=[r2]
bsw.0 // switch back to bank 0 (no stop bit required beforehand...)
;;
ldf.fill f11=[r2]
(pUStk) mov r18=IA64_KR(CURRENT) // Itanium 2: 12 cycle read latency
(pUStk) mov r18=IA64_KR(CURRENT)// M2 (12 cycle read latency)
adds r16=PT(CR_IPSR)+16,r12
adds r17=PT(CR_IIP)+16,r12
(pKStk) mov r22=psr // M2 read PSR now that interrupts are disabled
nop.i 0
nop.i 0
;;
ld8 r29=[r16],16 // load cr.ipsr
ld8 r28=[r17],16 // load cr.iip
......@@ -1045,11 +1049,11 @@ rse_clear_invalid:
;;
skip_rbs_switch:
mov ar.unat=r25 // M2
nop.i 0 // I0
(pKStk) extr.u r22=r22,21,1 // I0 extract current value of psr.pp from r22
(pLvSys)mov r19=r0 // A clear r19 for leave_syscall, no-op otherwise
;;
(pUStk) mov ar.bspstore=r23 // M2
nop.i 0 // I0
(pKStk) dep r29=r22,r29,21,1 // I0 update ipsr.pp with psr.pp
(pLvSys)mov r16=r0 // A clear r16 for leave_syscall, no-op otherwise
;;
mov cr.ipsr=r29 // M2
......
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