Merge d58db3f3a0 ("Merge tag 'docs-6.12' of git://git.lwn.net/linux") into android-mainline
Steps on the way to 6.12-rc1 Bug: 367265496 Change-Id: If60ec1a650903bc7f1e176954ae2cc19590f580c Signed-off-by: Matthias Maennich <maennich@google.com>
This commit is contained in:
+36
-17
@@ -20,13 +20,6 @@
|
||||
DEFINE_RAW_SPINLOCK(i8253_lock);
|
||||
EXPORT_SYMBOL(i8253_lock);
|
||||
|
||||
/*
|
||||
* Handle PIT quirk in pit_shutdown() where zeroing the counter register
|
||||
* restarts the PIT, negating the shutdown. On platforms with the quirk,
|
||||
* platform specific code can set this to false.
|
||||
*/
|
||||
bool i8253_clear_counter_on_shutdown __ro_after_init = true;
|
||||
|
||||
#ifdef CONFIG_CLKSRC_I8253
|
||||
/*
|
||||
* Since the PIT overflows every tick, its not very useful
|
||||
@@ -108,21 +101,47 @@ int __init clocksource_i8253_init(void)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CLKEVT_I8253
|
||||
void clockevent_i8253_disable(void)
|
||||
{
|
||||
raw_spin_lock(&i8253_lock);
|
||||
|
||||
/*
|
||||
* Writing the MODE register should stop the counter, according to
|
||||
* the datasheet. This appears to work on real hardware (well, on
|
||||
* modern Intel and AMD boxes; I didn't dig the Pegasos out of the
|
||||
* shed).
|
||||
*
|
||||
* However, some virtual implementations differ, and the MODE change
|
||||
* doesn't have any effect until either the counter is written (KVM
|
||||
* in-kernel PIT) or the next interrupt (QEMU). And in those cases,
|
||||
* it may not stop the *count*, only the interrupts. Although in
|
||||
* the virt case, that probably doesn't matter, as the value of the
|
||||
* counter will only be calculated on demand if the guest reads it;
|
||||
* it's the interrupts which cause steal time.
|
||||
*
|
||||
* Hyper-V apparently has a bug where even in mode 0, the IRQ keeps
|
||||
* firing repeatedly if the counter is running. But it *does* do the
|
||||
* right thing when the MODE register is written.
|
||||
*
|
||||
* So: write the MODE and then load the counter, which ensures that
|
||||
* the IRQ is stopped on those buggy virt implementations. And then
|
||||
* write the MODE again, which is the right way to stop it.
|
||||
*/
|
||||
outb_p(0x30, PIT_MODE);
|
||||
outb_p(0, PIT_CH0);
|
||||
outb_p(0, PIT_CH0);
|
||||
|
||||
outb_p(0x30, PIT_MODE);
|
||||
|
||||
raw_spin_unlock(&i8253_lock);
|
||||
}
|
||||
|
||||
static int pit_shutdown(struct clock_event_device *evt)
|
||||
{
|
||||
if (!clockevent_state_oneshot(evt) && !clockevent_state_periodic(evt))
|
||||
return 0;
|
||||
|
||||
raw_spin_lock(&i8253_lock);
|
||||
|
||||
outb_p(0x30, PIT_MODE);
|
||||
|
||||
if (i8253_clear_counter_on_shutdown) {
|
||||
outb_p(0, PIT_CH0);
|
||||
outb_p(0, PIT_CH0);
|
||||
}
|
||||
|
||||
raw_spin_unlock(&i8253_lock);
|
||||
clockevent_i8253_disable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user