mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 00:22:00 +02:00
KVM/riscv fixes for 6.16, take #2
- Disable vstimecmp before exiting to user-space - Move HGEI[E|P] CSR access to IMSIC virtualization -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEZdn75s5e6LHDQ+f/rUjsVaLHLAcFAmhyLB4ACgkQrUjsVaLH LAeZuBAAkp0SjGtXw9AewYtmVu2FOCYBtLyaEjrILsMuLxpY/VHCM3CfbbjdRnQ8 i0EyPG51SgWHP6TS1FCN+vFly5p10f6eOkApgWj1CZXrzfFslbV1gDaL8xBGpEQD lASVjXmfEboZHFATxYXImoWsKDOAxxcX2+30T9/EojsXUe6GcslCDWUUlXkaWCmm 7Wv5TawUQ1yhg35q3iaNpkXC+P8v4aDY3qTeJv/A8GwvFz6WnXzJDT9XXnLQl4oF SA2NHHm3p6te3RL6wrJ7OuF9/HduSgH+UfI31XgL4SWC7lbZEET9GOOkUGvBseex ktI/kdNgYssdzR2OeXZih2r3SbzxtRDNeTbBlZLx1OKwrrplCqg73I6zn1qAVsxI UYST2zDI+EdfmfKC7WUsBJlNPBhupY019K8EOE11Kp/z11omZ3NsG4ZA4ijE56WW 9q4q6wrN/3Nru+6bPg8dxkAKqVZ8k1aBWkWzLwaC0qiYCXls8q2ZGo5DsKvAcNhb uz6QZ7ir/I+9clRyCBvcKyO8cY4MVa+PwdG9PjS1YPxMVpmltrCc3mybIUtmBl0a IZJmektkW2O6O8ajpeMuwfnfxO/DHGeDmcydLcJJ7w7+WzUN7unGm2rDEW4+AWNx p1DC3uBf2GTigvbYV9S13w1OJBU+doaYvNUrIPYWLZgWJHi8QVc= =B0C/ -----END PGP SIGNATURE----- Merge tag 'kvm-riscv-fixes-6.16-2' of https://github.com/kvm-riscv/linux into HEAD KVM/riscv fixes for 6.16, take #2 - Disable vstimecmp before exiting to user-space - Move HGEI[E|P] CSR access to IMSIC virtualization
This commit is contained in:
commit
709ea4a866
|
|
@ -87,6 +87,9 @@ DECLARE_STATIC_KEY_FALSE(kvm_riscv_aia_available);
|
|||
|
||||
extern struct kvm_device_ops kvm_riscv_aia_device_ops;
|
||||
|
||||
bool kvm_riscv_vcpu_aia_imsic_has_interrupt(struct kvm_vcpu *vcpu);
|
||||
void kvm_riscv_vcpu_aia_imsic_load(struct kvm_vcpu *vcpu, int cpu);
|
||||
void kvm_riscv_vcpu_aia_imsic_put(struct kvm_vcpu *vcpu);
|
||||
void kvm_riscv_vcpu_aia_imsic_release(struct kvm_vcpu *vcpu);
|
||||
int kvm_riscv_vcpu_aia_imsic_update(struct kvm_vcpu *vcpu);
|
||||
|
||||
|
|
@ -161,7 +164,6 @@ void kvm_riscv_aia_destroy_vm(struct kvm *kvm);
|
|||
int kvm_riscv_aia_alloc_hgei(int cpu, struct kvm_vcpu *owner,
|
||||
void __iomem **hgei_va, phys_addr_t *hgei_pa);
|
||||
void kvm_riscv_aia_free_hgei(int cpu, int hgei);
|
||||
void kvm_riscv_aia_wakeon_hgei(struct kvm_vcpu *owner, bool enable);
|
||||
|
||||
void kvm_riscv_aia_enable(void);
|
||||
void kvm_riscv_aia_disable(void);
|
||||
|
|
|
|||
|
|
@ -306,6 +306,9 @@ static inline bool kvm_arch_pmi_in_guest(struct kvm_vcpu *vcpu)
|
|||
return IS_ENABLED(CONFIG_GUEST_PERF_EVENTS) && !!vcpu;
|
||||
}
|
||||
|
||||
static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {}
|
||||
static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {}
|
||||
|
||||
#define KVM_RISCV_GSTAGE_TLB_MIN_ORDER 12
|
||||
|
||||
void kvm_riscv_local_hfence_gvma_vmid_gpa(unsigned long vmid,
|
||||
|
|
|
|||
|
|
@ -30,28 +30,6 @@ unsigned int kvm_riscv_aia_nr_hgei;
|
|||
unsigned int kvm_riscv_aia_max_ids;
|
||||
DEFINE_STATIC_KEY_FALSE(kvm_riscv_aia_available);
|
||||
|
||||
static int aia_find_hgei(struct kvm_vcpu *owner)
|
||||
{
|
||||
int i, hgei;
|
||||
unsigned long flags;
|
||||
struct aia_hgei_control *hgctrl = get_cpu_ptr(&aia_hgei);
|
||||
|
||||
raw_spin_lock_irqsave(&hgctrl->lock, flags);
|
||||
|
||||
hgei = -1;
|
||||
for (i = 1; i <= kvm_riscv_aia_nr_hgei; i++) {
|
||||
if (hgctrl->owners[i] == owner) {
|
||||
hgei = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
raw_spin_unlock_irqrestore(&hgctrl->lock, flags);
|
||||
|
||||
put_cpu_ptr(&aia_hgei);
|
||||
return hgei;
|
||||
}
|
||||
|
||||
static inline unsigned long aia_hvictl_value(bool ext_irq_pending)
|
||||
{
|
||||
unsigned long hvictl;
|
||||
|
|
@ -95,7 +73,6 @@ void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu)
|
|||
|
||||
bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
|
||||
{
|
||||
int hgei;
|
||||
unsigned long seip;
|
||||
|
||||
if (!kvm_riscv_aia_available())
|
||||
|
|
@ -114,11 +91,7 @@ bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
|
|||
if (!kvm_riscv_aia_initialized(vcpu->kvm) || !seip)
|
||||
return false;
|
||||
|
||||
hgei = aia_find_hgei(vcpu);
|
||||
if (hgei > 0)
|
||||
return !!(ncsr_read(CSR_HGEIP) & BIT(hgei));
|
||||
|
||||
return false;
|
||||
return kvm_riscv_vcpu_aia_imsic_has_interrupt(vcpu);
|
||||
}
|
||||
|
||||
void kvm_riscv_vcpu_aia_update_hvip(struct kvm_vcpu *vcpu)
|
||||
|
|
@ -164,6 +137,9 @@ void kvm_riscv_vcpu_aia_load(struct kvm_vcpu *vcpu, int cpu)
|
|||
csr_write(CSR_HVIPRIO2H, csr->hviprio2h);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (kvm_riscv_aia_initialized(vcpu->kvm))
|
||||
kvm_riscv_vcpu_aia_imsic_load(vcpu, cpu);
|
||||
}
|
||||
|
||||
void kvm_riscv_vcpu_aia_put(struct kvm_vcpu *vcpu)
|
||||
|
|
@ -174,6 +150,9 @@ void kvm_riscv_vcpu_aia_put(struct kvm_vcpu *vcpu)
|
|||
if (!kvm_riscv_aia_available())
|
||||
return;
|
||||
|
||||
if (kvm_riscv_aia_initialized(vcpu->kvm))
|
||||
kvm_riscv_vcpu_aia_imsic_put(vcpu);
|
||||
|
||||
if (kvm_riscv_nacl_available()) {
|
||||
nsh = nacl_shmem();
|
||||
csr->vsiselect = nacl_csr_read(nsh, CSR_VSISELECT);
|
||||
|
|
@ -472,22 +451,6 @@ void kvm_riscv_aia_free_hgei(int cpu, int hgei)
|
|||
raw_spin_unlock_irqrestore(&hgctrl->lock, flags);
|
||||
}
|
||||
|
||||
void kvm_riscv_aia_wakeon_hgei(struct kvm_vcpu *owner, bool enable)
|
||||
{
|
||||
int hgei;
|
||||
|
||||
if (!kvm_riscv_aia_available())
|
||||
return;
|
||||
|
||||
hgei = aia_find_hgei(owner);
|
||||
if (hgei > 0) {
|
||||
if (enable)
|
||||
csr_set(CSR_HGEIE, BIT(hgei));
|
||||
else
|
||||
csr_clear(CSR_HGEIE, BIT(hgei));
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t hgei_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
int i;
|
||||
|
|
|
|||
|
|
@ -676,6 +676,48 @@ static void imsic_swfile_update(struct kvm_vcpu *vcpu,
|
|||
imsic_swfile_extirq_update(vcpu);
|
||||
}
|
||||
|
||||
bool kvm_riscv_vcpu_aia_imsic_has_interrupt(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct imsic *imsic = vcpu->arch.aia_context.imsic_state;
|
||||
unsigned long flags;
|
||||
bool ret = false;
|
||||
|
||||
/*
|
||||
* The IMSIC SW-file directly injects interrupt via hvip so
|
||||
* only check for interrupt when IMSIC VS-file is being used.
|
||||
*/
|
||||
|
||||
read_lock_irqsave(&imsic->vsfile_lock, flags);
|
||||
if (imsic->vsfile_cpu > -1)
|
||||
ret = !!(csr_read(CSR_HGEIP) & BIT(imsic->vsfile_hgei));
|
||||
read_unlock_irqrestore(&imsic->vsfile_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void kvm_riscv_vcpu_aia_imsic_load(struct kvm_vcpu *vcpu, int cpu)
|
||||
{
|
||||
/*
|
||||
* No need to explicitly clear HGEIE CSR bits because the
|
||||
* hgei interrupt handler (aka hgei_interrupt()) will always
|
||||
* clear it for us.
|
||||
*/
|
||||
}
|
||||
|
||||
void kvm_riscv_vcpu_aia_imsic_put(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct imsic *imsic = vcpu->arch.aia_context.imsic_state;
|
||||
unsigned long flags;
|
||||
|
||||
if (!kvm_vcpu_is_blocking(vcpu))
|
||||
return;
|
||||
|
||||
read_lock_irqsave(&imsic->vsfile_lock, flags);
|
||||
if (imsic->vsfile_cpu > -1)
|
||||
csr_set(CSR_HGEIE, BIT(imsic->vsfile_hgei));
|
||||
read_unlock_irqrestore(&imsic->vsfile_lock, flags);
|
||||
}
|
||||
|
||||
void kvm_riscv_vcpu_aia_imsic_release(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
|
@ -781,6 +823,9 @@ int kvm_riscv_vcpu_aia_imsic_update(struct kvm_vcpu *vcpu)
|
|||
* producers to the new IMSIC VS-file.
|
||||
*/
|
||||
|
||||
/* Ensure HGEIE CSR bit is zero before using the new IMSIC VS-file */
|
||||
csr_clear(CSR_HGEIE, BIT(new_vsfile_hgei));
|
||||
|
||||
/* Zero-out new IMSIC VS-file */
|
||||
imsic_vsfile_local_clear(new_vsfile_hgei, imsic->nr_hw_eix);
|
||||
|
||||
|
|
|
|||
|
|
@ -207,16 +207,6 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
|
|||
return kvm_riscv_vcpu_timer_pending(vcpu);
|
||||
}
|
||||
|
||||
void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
kvm_riscv_aia_wakeon_hgei(vcpu, true);
|
||||
}
|
||||
|
||||
void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
kvm_riscv_aia_wakeon_hgei(vcpu, false);
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return (kvm_riscv_vcpu_has_interrupts(vcpu, -1UL) &&
|
||||
|
|
|
|||
|
|
@ -345,8 +345,24 @@ void kvm_riscv_vcpu_timer_save(struct kvm_vcpu *vcpu)
|
|||
/*
|
||||
* The vstimecmp CSRs are saved by kvm_riscv_vcpu_timer_sync()
|
||||
* upon every VM exit so no need to save here.
|
||||
*
|
||||
* If VS-timer expires when no VCPU running on a host CPU then
|
||||
* WFI executed by such host CPU will be effective NOP resulting
|
||||
* in no power savings. This is because as-per RISC-V Privileged
|
||||
* specificaiton: "WFI is also required to resume execution for
|
||||
* locally enabled interrupts pending at any privilege level,
|
||||
* regardless of the global interrupt enable at each privilege
|
||||
* level."
|
||||
*
|
||||
* To address the above issue, vstimecmp CSR must be set to -1UL
|
||||
* over here when VCPU is scheduled-out or exits to user space.
|
||||
*/
|
||||
|
||||
csr_write(CSR_VSTIMECMP, -1UL);
|
||||
#if defined(CONFIG_32BIT)
|
||||
csr_write(CSR_VSTIMECMPH, -1UL);
|
||||
#endif
|
||||
|
||||
/* timer should be enabled for the remaining operations */
|
||||
if (unlikely(!t->init_done))
|
||||
return;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user