mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-09 14:43:16 +00:00
Merge branch 'kvm-arm64/vlpi-save-restore' into kvmarm-master/next
Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
commit
e629003215
@ -80,7 +80,7 @@ KVM_DEV_ARM_VGIC_GRP_CTRL
|
||||
-EFAULT Invalid guest ram access
|
||||
-EBUSY One or more VCPUS are running
|
||||
-EACCES The virtual ITS is backed by a physical GICv4 ITS, and the
|
||||
state is not available
|
||||
state is not available without GICv4.1
|
||||
======= ==========================================================
|
||||
|
||||
KVM_DEV_ARM_VGIC_GRP_ITS_REGS
|
||||
|
@ -2218,10 +2218,10 @@ static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
|
||||
/*
|
||||
* If an LPI carries the HW bit, this means that this
|
||||
* interrupt is controlled by GICv4, and we do not
|
||||
* have direct access to that state. Let's simply fail
|
||||
* the save operation...
|
||||
* have direct access to that state without GICv4.1.
|
||||
* Let's simply fail the save operation...
|
||||
*/
|
||||
if (ite->irq->hw)
|
||||
if (ite->irq->hw && !kvm_vgic_global_state.has_gicv4_1)
|
||||
return -EACCES;
|
||||
|
||||
ret = vgic_its_save_ite(its, device, ite, gpa, ite_esz);
|
||||
|
@ -1,6 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/irqchip/arm-gic-v3.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kvm.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <kvm/arm_vgic.h>
|
||||
@ -356,6 +358,32 @@ retry:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The deactivation of the doorbell interrupt will trigger the
|
||||
* unmapping of the associated vPE.
|
||||
*/
|
||||
static void unmap_all_vpes(struct vgic_dist *dist)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dist->its_vm.nr_vpes; i++) {
|
||||
desc = irq_to_desc(dist->its_vm.vpes[i]->irq);
|
||||
irq_domain_deactivate_irq(irq_desc_get_irq_data(desc));
|
||||
}
|
||||
}
|
||||
|
||||
static void map_all_vpes(struct vgic_dist *dist)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dist->its_vm.nr_vpes; i++) {
|
||||
desc = irq_to_desc(dist->its_vm.vpes[i]->irq);
|
||||
irq_domain_activate_irq(irq_desc_get_irq_data(desc), false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* vgic_v3_save_pending_tables - Save the pending tables into guest RAM
|
||||
* kvm lock and all vcpu lock must be held
|
||||
@ -365,13 +393,28 @@ int vgic_v3_save_pending_tables(struct kvm *kvm)
|
||||
struct vgic_dist *dist = &kvm->arch.vgic;
|
||||
struct vgic_irq *irq;
|
||||
gpa_t last_ptr = ~(gpa_t)0;
|
||||
int ret;
|
||||
bool vlpi_avail = false;
|
||||
int ret = 0;
|
||||
u8 val;
|
||||
|
||||
if (unlikely(!vgic_initialized(kvm)))
|
||||
return -ENXIO;
|
||||
|
||||
/*
|
||||
* A preparation for getting any VLPI states.
|
||||
* The above vgic initialized check also ensures that the allocation
|
||||
* and enabling of the doorbells have already been done.
|
||||
*/
|
||||
if (kvm_vgic_global_state.has_gicv4_1) {
|
||||
unmap_all_vpes(dist);
|
||||
vlpi_avail = true;
|
||||
}
|
||||
|
||||
list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) {
|
||||
int byte_offset, bit_nr;
|
||||
struct kvm_vcpu *vcpu;
|
||||
gpa_t pendbase, ptr;
|
||||
bool is_pending;
|
||||
bool stored;
|
||||
|
||||
vcpu = irq->target_vcpu;
|
||||
@ -387,24 +430,35 @@ int vgic_v3_save_pending_tables(struct kvm *kvm)
|
||||
if (ptr != last_ptr) {
|
||||
ret = kvm_read_guest_lock(kvm, ptr, &val, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
last_ptr = ptr;
|
||||
}
|
||||
|
||||
stored = val & (1U << bit_nr);
|
||||
if (stored == irq->pending_latch)
|
||||
|
||||
is_pending = irq->pending_latch;
|
||||
|
||||
if (irq->hw && vlpi_avail)
|
||||
vgic_v4_get_vlpi_state(irq, &is_pending);
|
||||
|
||||
if (stored == is_pending)
|
||||
continue;
|
||||
|
||||
if (irq->pending_latch)
|
||||
if (is_pending)
|
||||
val |= 1 << bit_nr;
|
||||
else
|
||||
val &= ~(1 << bit_nr);
|
||||
|
||||
ret = kvm_write_guest_lock(kvm, ptr, &val, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
return 0;
|
||||
|
||||
out:
|
||||
if (vlpi_avail)
|
||||
map_all_vpes(dist);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -203,6 +203,25 @@ void vgic_v4_configure_vsgis(struct kvm *kvm)
|
||||
kvm_arm_resume_guest(kvm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called with GICv4.1 and the vPE unmapped, which
|
||||
* indicates the invalidation of any VPT caches associated
|
||||
* with the vPE, thus we can get the VLPI state by peeking
|
||||
* at the VPT.
|
||||
*/
|
||||
void vgic_v4_get_vlpi_state(struct vgic_irq *irq, bool *val)
|
||||
{
|
||||
struct its_vpe *vpe = &irq->target_vcpu->arch.vgic_cpu.vgic_v3.its_vpe;
|
||||
int mask = BIT(irq->intid % BITS_PER_BYTE);
|
||||
void *va;
|
||||
u8 *ptr;
|
||||
|
||||
va = page_address(vpe->vpt_page);
|
||||
ptr = va + irq->intid / BITS_PER_BYTE;
|
||||
|
||||
*val = !!(*ptr & mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* vgic_v4_init - Initialize the GICv4 data structures
|
||||
* @kvm: Pointer to the VM being initialized
|
||||
@ -385,6 +404,7 @@ int kvm_vgic_v4_set_forwarding(struct kvm *kvm, int virq,
|
||||
struct vgic_its *its;
|
||||
struct vgic_irq *irq;
|
||||
struct its_vlpi_map map;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
if (!vgic_supports_direct_msis(kvm))
|
||||
@ -430,6 +450,24 @@ int kvm_vgic_v4_set_forwarding(struct kvm *kvm, int virq,
|
||||
irq->host_irq = virq;
|
||||
atomic_inc(&map.vpe->vlpi_count);
|
||||
|
||||
/* Transfer pending state */
|
||||
raw_spin_lock_irqsave(&irq->irq_lock, flags);
|
||||
if (irq->pending_latch) {
|
||||
ret = irq_set_irqchip_state(irq->host_irq,
|
||||
IRQCHIP_STATE_PENDING,
|
||||
irq->pending_latch);
|
||||
WARN_RATELIMIT(ret, "IRQ %d", irq->host_irq);
|
||||
|
||||
/*
|
||||
* Clear pending_latch and communicate this state
|
||||
* change via vgic_queue_irq_unlock.
|
||||
*/
|
||||
irq->pending_latch = false;
|
||||
vgic_queue_irq_unlock(kvm, irq, flags);
|
||||
} else {
|
||||
raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&its->its_lock);
|
||||
return ret;
|
||||
|
@ -318,5 +318,6 @@ bool vgic_supports_direct_msis(struct kvm *kvm);
|
||||
int vgic_v4_init(struct kvm *kvm);
|
||||
void vgic_v4_teardown(struct kvm *kvm);
|
||||
void vgic_v4_configure_vsgis(struct kvm *kvm);
|
||||
void vgic_v4_get_vlpi_state(struct vgic_irq *irq, bool *val);
|
||||
|
||||
#endif
|
||||
|
@ -794,8 +794,13 @@ static struct its_vpe *its_build_vmapp_cmd(struct its_node *its,
|
||||
|
||||
its_encode_alloc(cmd, alloc);
|
||||
|
||||
/* We can only signal PTZ when alloc==1. Why do we have two bits? */
|
||||
its_encode_ptz(cmd, alloc);
|
||||
/*
|
||||
* GICv4.1 provides a way to get the VLPI state, which needs the vPE
|
||||
* to be unmapped first, and in this case, we may remap the vPE
|
||||
* back while the VPT is not empty. So we can't assume that the
|
||||
* VPT is empty on map. This is why we never advertise PTZ.
|
||||
*/
|
||||
its_encode_ptz(cmd, false);
|
||||
its_encode_vconf_addr(cmd, vconf_addr);
|
||||
its_encode_vmapp_default_db(cmd, desc->its_vmapp_cmd.vpe->vpe_db_lpi);
|
||||
|
||||
@ -4554,6 +4559,15 @@ static void its_vpe_irq_domain_deactivate(struct irq_domain *domain,
|
||||
|
||||
its_send_vmapp(its, vpe, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* There may be a direct read to the VPT after unmapping the
|
||||
* vPE, to guarantee the validity of this, we make the VPT
|
||||
* memory coherent with the CPU caches here.
|
||||
*/
|
||||
if (find_4_1_its() && !atomic_read(&vpe->vmapp_count))
|
||||
gic_flush_dcache_to_poc(page_address(vpe->vpt_page),
|
||||
LPI_PENDBASE_SZ);
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops its_vpe_domain_ops = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user