Add a custom implementation of cpu_lock_delay() for x86.

Avoid using DELAY() since it can try to use spin locks on CPUs without
a P-state invariant TSC.  For cpu_lock_delay(), always use the TSC if
it exists (even if it is not P-state invariant) to delay for a
microsecond.  If the TSC does not exist, read from I/O port 0x84 to
delay instead.

PR:		228768
Reported by:	Roger Hammerstein <cheeky.m@live.com>
Reviewed by:	kib
MFC after:	3 days
Differential Revision:	https://reviews.freebsd.org/D17851
This commit is contained in:
John Baldwin 2018-11-05 22:54:03 +00:00
parent c35530f464
commit 7f7f6f85a1
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=340170
3 changed files with 21 additions and 2 deletions

View File

@ -50,7 +50,6 @@
#define cpu_getstack(td) ((td)->td_frame->tf_rsp)
#define cpu_setstack(td, ap) ((td)->td_frame->tf_rsp = (ap))
#define cpu_spinwait() ia32_pause()
#define cpu_lock_delay() DELAY(1)
#define TRAPF_USERMODE(framep) \
(ISPL((framep)->tf_cs) == SEL_UPL)
@ -78,6 +77,7 @@ extern char etext[];
extern void (*vmm_resume_p)(void);
void cpu_halt(void);
void cpu_lock_delay(void);
void cpu_reset(void);
void fork_trampoline(void);
void swi_vm(void *);

View File

@ -50,7 +50,6 @@
#define cpu_getstack(td) ((td)->td_frame->tf_esp)
#define cpu_setstack(td, ap) ((td)->td_frame->tf_esp = (ap))
#define cpu_spinwait() ia32_pause()
#define cpu_lock_delay() DELAY(1)
#define TRAPF_USERMODE(framep) \
((ISPL((framep)->tf_cs) == SEL_UPL) || ((framep)->tf_eflags & PSL_VM))
@ -73,6 +72,7 @@ extern char btext[];
extern char etext[];
void cpu_halt(void);
void cpu_lock_delay(void);
void cpu_reset(void);
void fork_trampoline(void);
void swi_vm(void *);

View File

@ -122,3 +122,22 @@ DELAY(int n)
init_ops.early_delay(n);
TSEXIT();
}
void
cpu_lock_delay(void)
{
/*
* Use TSC to wait for a usec if present, otherwise fall back
* to reading from port 0x84. We can't call into timecounters
* for this delay since timecounters might use spin locks.
*
* Note that unlike delay_tc(), this uses the TSC even if it
* is not P-state invariant. For this function it is ok to
* wait even a few usecs.
*/
if (tsc_freq != 0)
delay_tsc(1);
else
inb(0x84);
}