mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 13:14:07 +08:00
powerpc/time: add API for KVM to re-arm the host timer/decrementer
Rather than have KVM look up the host timer and fiddle with the irq-work internal details, have the powerpc/time.c code provide a function for KVM to re-arm the Linux timer code when exiting a guest. This is implementation has an improvement over existing code of marking a decrementer interrupt as soft-pending if a timer has expired, rather than setting DEC to a -ve value, which tended to cause host timers to take two interrupts (first hdec to exit the guest, then the immediate dec). Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20211123095231.1036501-8-npiggin@gmail.com
This commit is contained in:
parent
34bf08a207
commit
25aa145856
@ -99,18 +99,6 @@ extern void div128_by_32(u64 dividend_high, u64 dividend_low,
|
|||||||
extern void secondary_cpu_time_init(void);
|
extern void secondary_cpu_time_init(void);
|
||||||
extern void __init time_init(void);
|
extern void __init time_init(void);
|
||||||
|
|
||||||
#ifdef CONFIG_PPC64
|
|
||||||
static inline unsigned long test_irq_work_pending(void)
|
|
||||||
{
|
|
||||||
unsigned long x;
|
|
||||||
|
|
||||||
asm volatile("lbz %0,%1(13)"
|
|
||||||
: "=r" (x)
|
|
||||||
: "i" (offsetof(struct paca_struct, irq_work_pending)));
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DECLARE_PER_CPU(u64, decrementers_next_tb);
|
DECLARE_PER_CPU(u64, decrementers_next_tb);
|
||||||
|
|
||||||
static inline u64 timer_get_next_tb(void)
|
static inline u64 timer_get_next_tb(void)
|
||||||
@ -118,6 +106,10 @@ static inline u64 timer_get_next_tb(void)
|
|||||||
return __this_cpu_read(decrementers_next_tb);
|
return __this_cpu_read(decrementers_next_tb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
|
||||||
|
void timer_rearm_host_dec(u64 now);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Convert timebase ticks to nanoseconds */
|
/* Convert timebase ticks to nanoseconds */
|
||||||
unsigned long long tb_to_ns(unsigned long long tb_ticks);
|
unsigned long long tb_to_ns(unsigned long long tb_ticks);
|
||||||
|
|
||||||
|
@ -498,6 +498,16 @@ EXPORT_SYMBOL(profile_pc);
|
|||||||
* 64-bit uses a byte in the PACA, 32-bit uses a per-cpu variable...
|
* 64-bit uses a byte in the PACA, 32-bit uses a per-cpu variable...
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_PPC64
|
#ifdef CONFIG_PPC64
|
||||||
|
static inline unsigned long test_irq_work_pending(void)
|
||||||
|
{
|
||||||
|
unsigned long x;
|
||||||
|
|
||||||
|
asm volatile("lbz %0,%1(13)"
|
||||||
|
: "=r" (x)
|
||||||
|
: "i" (offsetof(struct paca_struct, irq_work_pending)));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void set_irq_work_pending_flag(void)
|
static inline void set_irq_work_pending_flag(void)
|
||||||
{
|
{
|
||||||
asm volatile("stb %0,%1(13)" : :
|
asm volatile("stb %0,%1(13)" : :
|
||||||
@ -541,13 +551,44 @@ void arch_irq_work_raise(void)
|
|||||||
preempt_enable();
|
preempt_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_dec_or_work(u64 val)
|
||||||
|
{
|
||||||
|
set_dec(val);
|
||||||
|
/* We may have raced with new irq work */
|
||||||
|
if (unlikely(test_irq_work_pending()))
|
||||||
|
set_dec(1);
|
||||||
|
}
|
||||||
|
|
||||||
#else /* CONFIG_IRQ_WORK */
|
#else /* CONFIG_IRQ_WORK */
|
||||||
|
|
||||||
#define test_irq_work_pending() 0
|
#define test_irq_work_pending() 0
|
||||||
#define clear_irq_work_pending()
|
#define clear_irq_work_pending()
|
||||||
|
|
||||||
|
static void set_dec_or_work(u64 val)
|
||||||
|
{
|
||||||
|
set_dec(val);
|
||||||
|
}
|
||||||
#endif /* CONFIG_IRQ_WORK */
|
#endif /* CONFIG_IRQ_WORK */
|
||||||
|
|
||||||
|
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
|
||||||
|
void timer_rearm_host_dec(u64 now)
|
||||||
|
{
|
||||||
|
u64 *next_tb = this_cpu_ptr(&decrementers_next_tb);
|
||||||
|
|
||||||
|
WARN_ON_ONCE(!arch_irqs_disabled());
|
||||||
|
WARN_ON_ONCE(mfmsr() & MSR_EE);
|
||||||
|
|
||||||
|
if (now >= *next_tb) {
|
||||||
|
local_paca->irq_happened |= PACA_IRQ_DEC;
|
||||||
|
} else {
|
||||||
|
now = *next_tb - now;
|
||||||
|
if (now <= decrementer_max)
|
||||||
|
set_dec_or_work(now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(timer_rearm_host_dec);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* timer_interrupt - gets called when the decrementer overflows,
|
* timer_interrupt - gets called when the decrementer overflows,
|
||||||
* with interrupts disabled.
|
* with interrupts disabled.
|
||||||
@ -608,10 +649,7 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(timer_interrupt)
|
|||||||
} else {
|
} else {
|
||||||
now = *next_tb - now;
|
now = *next_tb - now;
|
||||||
if (now <= decrementer_max)
|
if (now <= decrementer_max)
|
||||||
set_dec(now);
|
set_dec_or_work(now);
|
||||||
/* We may have raced with new irq work */
|
|
||||||
if (test_irq_work_pending())
|
|
||||||
set_dec(1);
|
|
||||||
__this_cpu_inc(irq_stat.timer_irqs_others);
|
__this_cpu_inc(irq_stat.timer_irqs_others);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -845,11 +883,7 @@ static int decrementer_set_next_event(unsigned long evt,
|
|||||||
struct clock_event_device *dev)
|
struct clock_event_device *dev)
|
||||||
{
|
{
|
||||||
__this_cpu_write(decrementers_next_tb, get_tb() + evt);
|
__this_cpu_write(decrementers_next_tb, get_tb() + evt);
|
||||||
set_dec(evt);
|
set_dec_or_work(evt);
|
||||||
|
|
||||||
/* We may have raced with new irq work */
|
|
||||||
if (test_irq_work_pending())
|
|
||||||
set_dec(1);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -4062,11 +4062,8 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,
|
|||||||
vc->entry_exit_map = 0x101;
|
vc->entry_exit_map = 0x101;
|
||||||
vc->in_guest = 0;
|
vc->in_guest = 0;
|
||||||
|
|
||||||
next_timer = timer_get_next_tb();
|
timer_rearm_host_dec(tb);
|
||||||
set_dec(next_timer - tb);
|
|
||||||
/* We may have raced with new irq work */
|
|
||||||
if (test_irq_work_pending())
|
|
||||||
set_dec(1);
|
|
||||||
mtspr(SPRN_SPRG_VDSO_WRITE, local_paca->sprg_vdso);
|
mtspr(SPRN_SPRG_VDSO_WRITE, local_paca->sprg_vdso);
|
||||||
|
|
||||||
kvmhv_load_host_pmu();
|
kvmhv_load_host_pmu();
|
||||||
|
Loading…
Reference in New Issue
Block a user