mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
Merge branch kvm-arm64/vgic-v5-PPI-fixes into kvmarm-master/next
* kvm-arm64/vgic-v5-PPI-fixes: : . : Substantial cleanup of the vgic-v5 PPI support. From the original : cover letter: : : "With the GICv5 PPi support merged in, it has become obvious that a few : things could be improved, both from the correctness and maintainability : angles." : . KVM: arm64: Fix arch timer interrupts for GICv3-on-GICv5 guests irqchip/gic-v5: Immediately exec priority drop following activate Documentation: KVM: Clarify that PMU_V3_IRQ IntID requirements for GICv5 Documentation: KVM: Fix typos in VGICv5 documentation KVM: arm64: selftests: Improve error handling for GICv5 PPI selftest KVM: arm64: selftests: Cleanup unused vars in GICv5 PPI selftest KVM: arm64: selftests: Add missing GIC CDEN to no-vgic-v5 selftest KVM: arm64: vgic-v5: Atomically assign bits to PPI DVI bitmap KVM: arm64: vgic-v5: Add missing trap handing for NV triage KVM: arm64: vgic-v5: Limit support to 64 PPIs KVM: arm64: vgic: Rationalise per-CPU irq accessor KVM: arm64: vgic-v5: Drop defensive checks from vgic_v5_ppi_queue_irq_unlock() KVM: arm64: vgic: Consolidate vgic_allocate_private_irqs_locked() KVM: arm64: vgic: Constify struct irq_ops usage KVM: arm64: vgic-v5: Drop pointless ARM64_HAS_GICV5_CPUIF check KVM: arm64: vgic-v5: Remove use of __assign_bit() with a constant KVM: arm64: vgic-v5: Move PPI caps into kvm_vgic_global_state KVM: arm64: vgic-v5: Add for_each_visible_v5_ppi() iterator Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
commit
8411f1534a
|
|
@ -12,8 +12,8 @@ Only one VGIC instance may be instantiated through this API. The created VGIC
|
|||
will act as the VM interrupt controller, requiring emulated user-space devices
|
||||
to inject interrupts to the VGIC instead of directly to CPUs.
|
||||
|
||||
Creating a guest GICv5 device requires a host GICv5 host. The current VGICv5
|
||||
device only supports PPI interrupts. These can either be injected from emulated
|
||||
Creating a guest GICv5 device requires a GICv5 host. The current VGICv5 device
|
||||
only supports PPI interrupts. These can either be injected from emulated
|
||||
in-kernel devices (such as the Arch Timer, or PMU), or via the KVM_IRQ_LINE
|
||||
ioctl.
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ Groups:
|
|||
request the initialization of the VGIC, no additional parameter in
|
||||
kvm_device_attr.addr. Must be called after all VCPUs have been created.
|
||||
|
||||
KVM_DEV_ARM_VGIC_USERPSPACE_PPIs
|
||||
KVM_DEV_ARM_VGIC_USERSPACE_PPIS
|
||||
request the mask of userspace-drivable PPIs. Only a subset of the PPIs can
|
||||
be directly driven from userspace with GICv5, and the returned mask
|
||||
informs userspace of which it is allowed to drive via KVM_IRQ_LINE.
|
||||
|
|
|
|||
|
|
@ -37,8 +37,11 @@ Returns:
|
|||
A value describing the PMUv3 (Performance Monitor Unit v3) overflow interrupt
|
||||
number for this vcpu. This interrupt could be a PPI or SPI, but the interrupt
|
||||
type must be same for each vcpu. As a PPI, the interrupt number is the same for
|
||||
all vcpus, while as an SPI it must be a separate number per vcpu. For
|
||||
GICv5-based guests, the architected PPI (23) must be used.
|
||||
all vcpus, while as an SPI it must be a separate number per vcpu.
|
||||
|
||||
For GICv5-based guests, the architected PPI (23) must be used, and must be
|
||||
communicated as the full GICv5-style Interrupt ID, i.e., 0x20000017. This ioctl
|
||||
can be omitted altogether for a GICv5-based guest.
|
||||
|
||||
1.2 ATTRIBUTE: KVM_ARM_VCPU_PMU_V3_INIT
|
||||
---------------------------------------
|
||||
|
|
|
|||
|
|
@ -51,11 +51,17 @@ static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu,
|
|||
enum kvm_arch_timer_regs treg);
|
||||
static bool kvm_arch_timer_get_input_level(int vintid);
|
||||
|
||||
static struct irq_ops arch_timer_irq_ops = {
|
||||
static unsigned long kvm_arch_timer_get_irq_flags(void)
|
||||
{
|
||||
return kvm_vgic_global_state.no_hw_deactivation ? VGIC_IRQ_SW_RESAMPLE : 0;
|
||||
}
|
||||
|
||||
static const struct irq_ops arch_timer_irq_ops = {
|
||||
.get_flags = kvm_arch_timer_get_irq_flags,
|
||||
.get_input_level = kvm_arch_timer_get_input_level,
|
||||
};
|
||||
|
||||
static struct irq_ops arch_timer_irq_ops_vgic_v5 = {
|
||||
static const struct irq_ops arch_timer_irq_ops_vgic_v5 = {
|
||||
.get_input_level = kvm_arch_timer_get_input_level,
|
||||
.queue_irq_unlock = vgic_v5_ppi_queue_irq_unlock,
|
||||
.set_direct_injection = vgic_v5_set_ppi_dvi,
|
||||
|
|
@ -1276,7 +1282,12 @@ static int timer_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
|
|||
static int timer_irq_set_irqchip_state(struct irq_data *d,
|
||||
enum irqchip_irq_state which, bool val)
|
||||
{
|
||||
if (which != IRQCHIP_STATE_ACTIVE || !irqd_is_forwarded_to_vcpu(d))
|
||||
bool passthrough = which != IRQCHIP_STATE_ACTIVE ||
|
||||
!irqd_is_forwarded_to_vcpu(d) ||
|
||||
(kvm_vgic_global_state.type == VGIC_V5 &&
|
||||
vgic_is_v3(kvm_get_running_vcpu()->kvm));
|
||||
|
||||
if (passthrough)
|
||||
return irq_chip_set_parent_state(d, which, val);
|
||||
|
||||
if (val)
|
||||
|
|
@ -1289,15 +1300,7 @@ static int timer_irq_set_irqchip_state(struct irq_data *d,
|
|||
|
||||
static void timer_irq_eoi(struct irq_data *d)
|
||||
{
|
||||
/*
|
||||
* On a GICv5 host, we still need to call EOI on the parent for
|
||||
* PPIs. The host driver already handles irqs which are forwarded to
|
||||
* vcpus, and skips the GIC CDDI while still doing the GIC CDEOI. This
|
||||
* is required to emulate the EOIMode=1 on GICv5 hardware. Failure to
|
||||
* call EOI unsurprisingly results in *BAD* lock-ups.
|
||||
*/
|
||||
if (!irqd_is_forwarded_to_vcpu(d) ||
|
||||
kvm_vgic_global_state.type == VGIC_V5)
|
||||
if (!irqd_is_forwarded_to_vcpu(d))
|
||||
irq_chip_eoi_parent(d);
|
||||
}
|
||||
|
||||
|
|
@ -1380,8 +1383,6 @@ static int kvm_irq_init(struct arch_timer_kvm_info *info)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (kvm_vgic_global_state.no_hw_deactivation)
|
||||
arch_timer_irq_ops.flags |= VGIC_IRQ_SW_RESAMPLE;
|
||||
WARN_ON(irq_domain_push_irq(domain, host_vtimer_irq,
|
||||
(void *)TIMER_VTIMER));
|
||||
}
|
||||
|
|
@ -1579,8 +1580,8 @@ static bool kvm_arch_timer_get_input_level(int vintid)
|
|||
int kvm_timer_enable(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct arch_timer_cpu *timer = vcpu_timer(vcpu);
|
||||
const struct irq_ops *ops;
|
||||
struct timer_map map;
|
||||
struct irq_ops *ops;
|
||||
int ret;
|
||||
|
||||
if (timer->enabled)
|
||||
|
|
|
|||
|
|
@ -2631,6 +2631,14 @@ bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index)
|
|||
fgtreg = HFGITR2_EL2;
|
||||
break;
|
||||
|
||||
case ICH_HFGRTR_GROUP:
|
||||
fgtreg = is_read ? ICH_HFGRTR_EL2 : ICH_HFGWTR_EL2;
|
||||
break;
|
||||
|
||||
case ICH_HFGITR_GROUP:
|
||||
fgtreg = ICH_HFGITR_EL2;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Something is really wrong, bail out */
|
||||
WARN_ONCE(1, "Bad FGT group (encoding %08x, config %016llx)\n",
|
||||
|
|
|
|||
|
|
@ -30,10 +30,9 @@ void __vgic_v5_save_ppi_state(struct vgic_v5_cpu_if *cpu_if)
|
|||
{
|
||||
/*
|
||||
* The following code assumes that the bitmap storage that we have for
|
||||
* PPIs is either 64 (architected PPIs, only) or 128 bits (architected &
|
||||
* impdef PPIs).
|
||||
* PPIs is either 64 (architected PPIs, only).
|
||||
*/
|
||||
BUILD_BUG_ON(VGIC_V5_NR_PRIVATE_IRQS % 64);
|
||||
BUILD_BUG_ON(VGIC_V5_NR_PRIVATE_IRQS != 64);
|
||||
|
||||
bitmap_write(host_data_ptr(vgic_v5_ppi_state)->activer_exit,
|
||||
read_sysreg_s(SYS_ICH_PPI_ACTIVER0_EL2), 0, 64);
|
||||
|
|
@ -49,22 +48,6 @@ void __vgic_v5_save_ppi_state(struct vgic_v5_cpu_if *cpu_if)
|
|||
cpu_if->vgic_ppi_priorityr[6] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR6_EL2);
|
||||
cpu_if->vgic_ppi_priorityr[7] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR7_EL2);
|
||||
|
||||
if (VGIC_V5_NR_PRIVATE_IRQS == 128) {
|
||||
bitmap_write(host_data_ptr(vgic_v5_ppi_state)->activer_exit,
|
||||
read_sysreg_s(SYS_ICH_PPI_ACTIVER1_EL2), 64, 64);
|
||||
bitmap_write(host_data_ptr(vgic_v5_ppi_state)->pendr,
|
||||
read_sysreg_s(SYS_ICH_PPI_PENDR1_EL2), 64, 64);
|
||||
|
||||
cpu_if->vgic_ppi_priorityr[8] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR8_EL2);
|
||||
cpu_if->vgic_ppi_priorityr[9] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR9_EL2);
|
||||
cpu_if->vgic_ppi_priorityr[10] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR10_EL2);
|
||||
cpu_if->vgic_ppi_priorityr[11] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR11_EL2);
|
||||
cpu_if->vgic_ppi_priorityr[12] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR12_EL2);
|
||||
cpu_if->vgic_ppi_priorityr[13] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR13_EL2);
|
||||
cpu_if->vgic_ppi_priorityr[14] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR14_EL2);
|
||||
cpu_if->vgic_ppi_priorityr[15] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR15_EL2);
|
||||
}
|
||||
|
||||
/* Now that we are done, disable DVI */
|
||||
write_sysreg_s(0, SYS_ICH_PPI_DVIR0_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_DVIR1_EL2);
|
||||
|
|
@ -74,9 +57,6 @@ void __vgic_v5_restore_ppi_state(struct vgic_v5_cpu_if *cpu_if)
|
|||
{
|
||||
DECLARE_BITMAP(pendr, VGIC_V5_NR_PRIVATE_IRQS);
|
||||
|
||||
/* We assume 64 or 128 PPIs - see above comment */
|
||||
BUILD_BUG_ON(VGIC_V5_NR_PRIVATE_IRQS % 64);
|
||||
|
||||
/* Enable DVI so that the guest's interrupt config takes over */
|
||||
write_sysreg_s(bitmap_read(cpu_if->vgic_ppi_dvir, 0, 64),
|
||||
SYS_ICH_PPI_DVIR0_EL2);
|
||||
|
|
@ -108,50 +88,20 @@ void __vgic_v5_restore_ppi_state(struct vgic_v5_cpu_if *cpu_if)
|
|||
write_sysreg_s(cpu_if->vgic_ppi_priorityr[7],
|
||||
SYS_ICH_PPI_PRIORITYR7_EL2);
|
||||
|
||||
if (VGIC_V5_NR_PRIVATE_IRQS == 128) {
|
||||
/* Enable DVI so that the guest's interrupt config takes over */
|
||||
write_sysreg_s(bitmap_read(cpu_if->vgic_ppi_dvir, 64, 64),
|
||||
SYS_ICH_PPI_DVIR1_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_DVIR1_EL2);
|
||||
|
||||
write_sysreg_s(bitmap_read(cpu_if->vgic_ppi_activer, 64, 64),
|
||||
SYS_ICH_PPI_ACTIVER1_EL2);
|
||||
write_sysreg_s(bitmap_read(cpu_if->vgic_ppi_enabler, 64, 64),
|
||||
SYS_ICH_PPI_ENABLER1_EL2);
|
||||
write_sysreg_s(bitmap_read(pendr, 64, 64),
|
||||
SYS_ICH_PPI_PENDR1_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_ACTIVER1_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_ENABLER1_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PENDR1_EL2);
|
||||
|
||||
write_sysreg_s(cpu_if->vgic_ppi_priorityr[8],
|
||||
SYS_ICH_PPI_PRIORITYR8_EL2);
|
||||
write_sysreg_s(cpu_if->vgic_ppi_priorityr[9],
|
||||
SYS_ICH_PPI_PRIORITYR9_EL2);
|
||||
write_sysreg_s(cpu_if->vgic_ppi_priorityr[10],
|
||||
SYS_ICH_PPI_PRIORITYR10_EL2);
|
||||
write_sysreg_s(cpu_if->vgic_ppi_priorityr[11],
|
||||
SYS_ICH_PPI_PRIORITYR11_EL2);
|
||||
write_sysreg_s(cpu_if->vgic_ppi_priorityr[12],
|
||||
SYS_ICH_PPI_PRIORITYR12_EL2);
|
||||
write_sysreg_s(cpu_if->vgic_ppi_priorityr[13],
|
||||
SYS_ICH_PPI_PRIORITYR13_EL2);
|
||||
write_sysreg_s(cpu_if->vgic_ppi_priorityr[14],
|
||||
SYS_ICH_PPI_PRIORITYR14_EL2);
|
||||
write_sysreg_s(cpu_if->vgic_ppi_priorityr[15],
|
||||
SYS_ICH_PPI_PRIORITYR15_EL2);
|
||||
} else {
|
||||
write_sysreg_s(0, SYS_ICH_PPI_DVIR1_EL2);
|
||||
|
||||
write_sysreg_s(0, SYS_ICH_PPI_ACTIVER1_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_ENABLER1_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PENDR1_EL2);
|
||||
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR8_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR9_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR10_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR11_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR12_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR13_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR14_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR15_EL2);
|
||||
}
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR8_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR9_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR10_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR11_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR12_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR13_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR14_EL2);
|
||||
write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR15_EL2);
|
||||
}
|
||||
|
||||
void __vgic_v5_save_state(struct vgic_v5_cpu_if *cpu_if)
|
||||
|
|
|
|||
|
|
@ -724,6 +724,7 @@ static bool access_gicv5_ppi_enabler(struct kvm_vcpu *vcpu,
|
|||
{
|
||||
unsigned long *mask = vcpu->kvm->arch.vgic.gicv5_vm.vgic_ppi_mask;
|
||||
struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
|
||||
unsigned long reg = p->regval;
|
||||
int i;
|
||||
|
||||
/* We never expect to get here with a read! */
|
||||
|
|
@ -731,27 +732,23 @@ static bool access_gicv5_ppi_enabler(struct kvm_vcpu *vcpu,
|
|||
return undef_access(vcpu, p, r);
|
||||
|
||||
/*
|
||||
* If we're only handling architected PPIs and the guest writes to the
|
||||
* enable for the non-architected PPIs, we just return as there's
|
||||
* nothing to do at all. We don't even allocate the storage for them in
|
||||
* this case.
|
||||
* As we're only handling architected PPIs, the guest writes to the
|
||||
* enable for the non-architected PPIs just return as there's
|
||||
* nothing to do at all. We don't even allocate the storage for them.
|
||||
*/
|
||||
if (VGIC_V5_NR_PRIVATE_IRQS == 64 && p->Op2 % 2)
|
||||
if (p->Op2 % 2)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Merge the raw guest write into out bitmap at an offset of either 0 or
|
||||
* 64, then and it with our PPI mask.
|
||||
* Merge the raw guest write into out bitmap, anded with our PPI mask.
|
||||
*/
|
||||
bitmap_write(cpu_if->vgic_ppi_enabler, p->regval, 64 * (p->Op2 % 2), 64);
|
||||
bitmap_and(cpu_if->vgic_ppi_enabler, cpu_if->vgic_ppi_enabler, mask,
|
||||
VGIC_V5_NR_PRIVATE_IRQS);
|
||||
bitmap_and(cpu_if->vgic_ppi_enabler, ®, mask, VGIC_V5_NR_PRIVATE_IRQS);
|
||||
|
||||
/*
|
||||
* Sync the change in enable states to the vgic_irqs. We consider all
|
||||
* PPIs as we don't expose many to the guest.
|
||||
*/
|
||||
for_each_set_bit(i, mask, VGIC_V5_NR_PRIVATE_IRQS) {
|
||||
for_each_visible_v5_ppi(i, vcpu->kvm) {
|
||||
u32 intid = vgic_v5_make_ppi(i);
|
||||
struct vgic_irq *irq;
|
||||
|
||||
|
|
|
|||
|
|
@ -271,18 +271,12 @@ int kvm_vgic_vcpu_nv_init(struct kvm_vcpu *vcpu)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void vgic_allocate_private_irq(struct kvm_vcpu *vcpu, int i, u32 type)
|
||||
static void vgic_setup_private_irq(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
|
||||
u32 type)
|
||||
{
|
||||
struct vgic_irq *irq = &vcpu->arch.vgic_cpu.private_irqs[i];
|
||||
irq->intid = irq - &vcpu->arch.vgic_cpu.private_irqs[0];
|
||||
|
||||
INIT_LIST_HEAD(&irq->ap_list);
|
||||
raw_spin_lock_init(&irq->irq_lock);
|
||||
irq->vcpu = NULL;
|
||||
irq->target_vcpu = vcpu;
|
||||
refcount_set(&irq->refcount, 0);
|
||||
|
||||
irq->intid = i;
|
||||
if (vgic_irq_is_sgi(i)) {
|
||||
if (vgic_irq_is_sgi(irq->intid)) {
|
||||
/* SGIs */
|
||||
irq->enabled = 1;
|
||||
irq->config = VGIC_CONFIG_EDGE;
|
||||
|
|
@ -303,18 +297,11 @@ static void vgic_allocate_private_irq(struct kvm_vcpu *vcpu, int i, u32 type)
|
|||
}
|
||||
}
|
||||
|
||||
static void vgic_v5_allocate_private_irq(struct kvm_vcpu *vcpu, int i, u32 type)
|
||||
static void vgic_v5_setup_private_irq(struct kvm_vcpu *vcpu, struct vgic_irq *irq)
|
||||
{
|
||||
struct vgic_irq *irq = &vcpu->arch.vgic_cpu.private_irqs[i];
|
||||
u32 intid = vgic_v5_make_ppi(i);
|
||||
int i = irq - &vcpu->arch.vgic_cpu.private_irqs[0];
|
||||
|
||||
INIT_LIST_HEAD(&irq->ap_list);
|
||||
raw_spin_lock_init(&irq->irq_lock);
|
||||
irq->vcpu = NULL;
|
||||
irq->target_vcpu = vcpu;
|
||||
refcount_set(&irq->refcount, 0);
|
||||
|
||||
irq->intid = intid;
|
||||
irq->intid = vgic_v5_make_ppi(i);
|
||||
|
||||
/* The only Edge architected PPI is the SW_PPI */
|
||||
if (i == GICV5_ARCH_PPI_SW_PPI)
|
||||
|
|
@ -323,7 +310,7 @@ static void vgic_v5_allocate_private_irq(struct kvm_vcpu *vcpu, int i, u32 type)
|
|||
irq->config = VGIC_CONFIG_LEVEL;
|
||||
|
||||
/* Register the GICv5-specific PPI ops */
|
||||
vgic_v5_set_ppi_ops(vcpu, intid);
|
||||
vgic_v5_set_ppi_ops(vcpu, irq->intid);
|
||||
}
|
||||
|
||||
static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type)
|
||||
|
|
@ -349,15 +336,19 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type)
|
|||
if (!vgic_cpu->private_irqs)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Enable and configure all SGIs to be edge-triggered and
|
||||
* configure all PPIs as level-triggered.
|
||||
*/
|
||||
for (i = 0; i < num_private_irqs; i++) {
|
||||
struct vgic_irq *irq = &vcpu->arch.vgic_cpu.private_irqs[i];
|
||||
|
||||
INIT_LIST_HEAD(&irq->ap_list);
|
||||
raw_spin_lock_init(&irq->irq_lock);
|
||||
irq->vcpu = NULL;
|
||||
irq->target_vcpu = vcpu;
|
||||
refcount_set(&irq->refcount, 0);
|
||||
|
||||
if (vgic_is_v5(vcpu->kvm))
|
||||
vgic_v5_allocate_private_irq(vcpu, i, type);
|
||||
vgic_v5_setup_private_irq(vcpu, irq);
|
||||
else
|
||||
vgic_allocate_private_irq(vcpu, i, type);
|
||||
vgic_setup_private_irq(vcpu, irq, type);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -730,18 +730,15 @@ static int vgic_v5_get_userspace_ppis(struct kvm_device *dev,
|
|||
guard(mutex)(&dev->kvm->arch.config_lock);
|
||||
|
||||
/*
|
||||
* We either support 64 or 128 PPIs. In the former case, we need to
|
||||
* return 0s for the second 64 bits as we have no storage backing those.
|
||||
* We only support 64 PPIs, so, we need to return 0s for the
|
||||
* second 64 bits as we have no storage backing those.
|
||||
*/
|
||||
ret = put_user(bitmap_read(gicv5_vm->userspace_ppis, 0, 64), uaddr);
|
||||
if (ret)
|
||||
return ret;
|
||||
uaddr++;
|
||||
|
||||
if (VGIC_V5_NR_PRIVATE_IRQS == 128)
|
||||
ret = put_user(bitmap_read(gicv5_vm->userspace_ppis, 64, 128), uaddr);
|
||||
else
|
||||
ret = put_user(0, uaddr);
|
||||
ret = put_user(0, uaddr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include "vgic.h"
|
||||
|
||||
static struct vgic_v5_ppi_caps ppi_caps;
|
||||
#define ppi_caps kvm_vgic_global_state.vgic_v5_ppi_caps
|
||||
|
||||
/*
|
||||
* Not all PPIs are guaranteed to be implemented for GICv5. Deterermine which
|
||||
|
|
@ -18,20 +18,17 @@ static struct vgic_v5_ppi_caps ppi_caps;
|
|||
*/
|
||||
static void vgic_v5_get_implemented_ppis(void)
|
||||
{
|
||||
if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF))
|
||||
return;
|
||||
|
||||
/*
|
||||
* If we have KVM, we have EL2, which means that we have support for the
|
||||
* EL1 and EL2 Physical & Virtual timers.
|
||||
*/
|
||||
__assign_bit(GICV5_ARCH_PPI_CNTHP, ppi_caps.impl_ppi_mask, 1);
|
||||
__assign_bit(GICV5_ARCH_PPI_CNTV, ppi_caps.impl_ppi_mask, 1);
|
||||
__assign_bit(GICV5_ARCH_PPI_CNTHV, ppi_caps.impl_ppi_mask, 1);
|
||||
__assign_bit(GICV5_ARCH_PPI_CNTP, ppi_caps.impl_ppi_mask, 1);
|
||||
__set_bit(GICV5_ARCH_PPI_CNTHP, ppi_caps.impl_ppi_mask);
|
||||
__set_bit(GICV5_ARCH_PPI_CNTV, ppi_caps.impl_ppi_mask);
|
||||
__set_bit(GICV5_ARCH_PPI_CNTHV, ppi_caps.impl_ppi_mask);
|
||||
__set_bit(GICV5_ARCH_PPI_CNTP, ppi_caps.impl_ppi_mask);
|
||||
|
||||
/* The SW_PPI should be available */
|
||||
__assign_bit(GICV5_ARCH_PPI_SW_PPI, ppi_caps.impl_ppi_mask, 1);
|
||||
__set_bit(GICV5_ARCH_PPI_SW_PPI, ppi_caps.impl_ppi_mask);
|
||||
|
||||
/* The PMUIRQ is available if we have the PMU */
|
||||
__assign_bit(GICV5_ARCH_PPI_PMUIRQ, ppi_caps.impl_ppi_mask, system_supports_pmuv3());
|
||||
|
|
@ -146,9 +143,7 @@ int vgic_v5_init(struct kvm *kvm)
|
|||
/* We only allow userspace to drive the SW_PPI, if it is implemented. */
|
||||
bitmap_zero(kvm->arch.vgic.gicv5_vm.userspace_ppis,
|
||||
VGIC_V5_NR_PRIVATE_IRQS);
|
||||
__assign_bit(GICV5_ARCH_PPI_SW_PPI,
|
||||
kvm->arch.vgic.gicv5_vm.userspace_ppis,
|
||||
VGIC_V5_NR_PRIVATE_IRQS);
|
||||
__set_bit(GICV5_ARCH_PPI_SW_PPI, kvm->arch.vgic.gicv5_vm.userspace_ppis);
|
||||
bitmap_and(kvm->arch.vgic.gicv5_vm.userspace_ppis,
|
||||
kvm->arch.vgic.gicv5_vm.userspace_ppis,
|
||||
ppi_caps.impl_ppi_mask, VGIC_V5_NR_PRIVATE_IRQS);
|
||||
|
|
@ -197,7 +192,7 @@ int vgic_v5_finalize_ppi_state(struct kvm *kvm)
|
|||
/* Expose PPIs with an owner or the SW_PPI, only */
|
||||
scoped_guard(raw_spinlock_irqsave, &irq->irq_lock) {
|
||||
if (irq->owner || i == GICV5_ARCH_PPI_SW_PPI) {
|
||||
__assign_bit(i, kvm->arch.vgic.gicv5_vm.vgic_ppi_mask, 1);
|
||||
__set_bit(i, kvm->arch.vgic.gicv5_vm.vgic_ppi_mask);
|
||||
__assign_bit(i, kvm->arch.vgic.gicv5_vm.vgic_ppi_hmr,
|
||||
irq->config == VGIC_CONFIG_LEVEL);
|
||||
}
|
||||
|
|
@ -243,9 +238,9 @@ static u32 vgic_v5_get_effective_priority_mask(struct kvm_vcpu *vcpu)
|
|||
|
||||
/*
|
||||
* For GICv5, the PPIs are mostly directly managed by the hardware. We (the
|
||||
* hypervisor) handle the pending, active, enable state save/restore, but don't
|
||||
* need the PPIs to be queued on a per-VCPU AP list. Therefore, sanity check the
|
||||
* state, unlock, and return.
|
||||
* hypervisor) handle the pending, active, enable state save/restore, but
|
||||
* don't need the PPIs to be queued on a per-VCPU AP list. Therefore,
|
||||
* unlock, kick the vcpu and return.
|
||||
*/
|
||||
bool vgic_v5_ppi_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
|
||||
unsigned long flags)
|
||||
|
|
@ -255,12 +250,7 @@ bool vgic_v5_ppi_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
|
|||
|
||||
lockdep_assert_held(&irq->irq_lock);
|
||||
|
||||
if (WARN_ON_ONCE(!__irq_is_ppi(KVM_DEV_TYPE_ARM_VGIC_V5, irq->intid)))
|
||||
goto out_unlock_fail;
|
||||
|
||||
vcpu = irq->target_vcpu;
|
||||
if (WARN_ON_ONCE(!vcpu))
|
||||
goto out_unlock_fail;
|
||||
|
||||
raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
|
||||
|
||||
|
|
@ -269,11 +259,6 @@ bool vgic_v5_ppi_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
|
|||
kvm_vcpu_kick(vcpu);
|
||||
|
||||
return true;
|
||||
|
||||
out_unlock_fail:
|
||||
raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -287,10 +272,10 @@ void vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, struct vgic_irq *irq, bool dvi)
|
|||
lockdep_assert_held(&irq->irq_lock);
|
||||
|
||||
ppi = vgic_v5_get_hwirq_id(irq->intid);
|
||||
__assign_bit(ppi, cpu_if->vgic_ppi_dvir, dvi);
|
||||
assign_bit(ppi, cpu_if->vgic_ppi_dvir, dvi);
|
||||
}
|
||||
|
||||
static struct irq_ops vgic_v5_ppi_irq_ops = {
|
||||
static const struct irq_ops vgic_v5_ppi_irq_ops = {
|
||||
.queue_irq_unlock = vgic_v5_ppi_queue_irq_unlock,
|
||||
.set_direct_injection = vgic_v5_set_ppi_dvi,
|
||||
};
|
||||
|
|
@ -316,7 +301,7 @@ static void vgic_v5_sync_ppi_priorities(struct kvm_vcpu *vcpu)
|
|||
* those actually exposed to the guest by first iterating over the mask
|
||||
* of exposed PPIs.
|
||||
*/
|
||||
for_each_set_bit(i, vcpu->kvm->arch.vgic.gicv5_vm.vgic_ppi_mask, VGIC_V5_NR_PRIVATE_IRQS) {
|
||||
for_each_visible_v5_ppi(i, vcpu->kvm) {
|
||||
u32 intid = vgic_v5_make_ppi(i);
|
||||
struct vgic_irq *irq;
|
||||
int pri_idx, pri_reg, pri_bit;
|
||||
|
|
@ -358,7 +343,7 @@ bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu)
|
|||
if (!priority_mask)
|
||||
return false;
|
||||
|
||||
for_each_set_bit(i, vcpu->kvm->arch.vgic.gicv5_vm.vgic_ppi_mask, VGIC_V5_NR_PRIVATE_IRQS) {
|
||||
for_each_visible_v5_ppi(i, vcpu->kvm) {
|
||||
u32 intid = vgic_v5_make_ppi(i);
|
||||
bool has_pending = false;
|
||||
struct vgic_irq *irq;
|
||||
|
|
@ -391,8 +376,7 @@ void vgic_v5_fold_ppi_state(struct kvm_vcpu *vcpu)
|
|||
activer = host_data_ptr(vgic_v5_ppi_state)->activer_exit;
|
||||
pendr = host_data_ptr(vgic_v5_ppi_state)->pendr;
|
||||
|
||||
for_each_set_bit(i, vcpu->kvm->arch.vgic.gicv5_vm.vgic_ppi_mask,
|
||||
VGIC_V5_NR_PRIVATE_IRQS) {
|
||||
for_each_visible_v5_ppi(i, vcpu->kvm) {
|
||||
u32 intid = vgic_v5_make_ppi(i);
|
||||
struct vgic_irq *irq;
|
||||
|
||||
|
|
@ -429,8 +413,7 @@ void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu)
|
|||
* ICC_PPI_PENDRx_EL1, however.
|
||||
*/
|
||||
bitmap_zero(pendr, VGIC_V5_NR_PRIVATE_IRQS);
|
||||
for_each_set_bit(i, vcpu->kvm->arch.vgic.gicv5_vm.vgic_ppi_mask,
|
||||
VGIC_V5_NR_PRIVATE_IRQS) {
|
||||
for_each_visible_v5_ppi(i, vcpu->kvm) {
|
||||
u32 intid = vgic_v5_make_ppi(i);
|
||||
struct vgic_irq *irq;
|
||||
|
||||
|
|
|
|||
|
|
@ -106,24 +106,23 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, u32 intid)
|
|||
|
||||
struct vgic_irq *vgic_get_vcpu_irq(struct kvm_vcpu *vcpu, u32 intid)
|
||||
{
|
||||
enum kvm_device_type type;
|
||||
|
||||
if (WARN_ON(!vcpu))
|
||||
return NULL;
|
||||
|
||||
if (vgic_is_v5(vcpu->kvm)) {
|
||||
u32 int_num, hwirq_id;
|
||||
type = vcpu->kvm->arch.vgic.vgic_model;
|
||||
|
||||
if (!__irq_is_ppi(KVM_DEV_TYPE_ARM_VGIC_V5, intid))
|
||||
return NULL;
|
||||
if (__irq_is_sgi(type, intid) || __irq_is_ppi(type, intid)) {
|
||||
switch (type) {
|
||||
case KVM_DEV_TYPE_ARM_VGIC_V5:
|
||||
intid = vgic_v5_get_hwirq_id(intid);
|
||||
intid = array_index_nospec(intid, VGIC_V5_NR_PRIVATE_IRQS);
|
||||
break;
|
||||
default:
|
||||
intid = array_index_nospec(intid, VGIC_NR_PRIVATE_IRQS);
|
||||
}
|
||||
|
||||
hwirq_id = FIELD_GET(GICV5_HWIRQ_ID, intid);
|
||||
int_num = array_index_nospec(hwirq_id, VGIC_V5_NR_PRIVATE_IRQS);
|
||||
|
||||
return &vcpu->arch.vgic_cpu.private_irqs[int_num];
|
||||
}
|
||||
|
||||
/* SGIs and PPIs */
|
||||
if (intid < VGIC_NR_PRIVATE_IRQS) {
|
||||
intid = array_index_nospec(intid, VGIC_NR_PRIVATE_IRQS);
|
||||
return &vcpu->arch.vgic_cpu.private_irqs[intid];
|
||||
}
|
||||
|
||||
|
|
@ -571,7 +570,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
|
|||
}
|
||||
|
||||
void kvm_vgic_set_irq_ops(struct kvm_vcpu *vcpu, u32 vintid,
|
||||
struct irq_ops *ops)
|
||||
const struct irq_ops *ops)
|
||||
{
|
||||
struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, vintid);
|
||||
|
||||
|
|
|
|||
|
|
@ -378,6 +378,9 @@ void vgic_v5_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
|
|||
void vgic_v5_restore_state(struct kvm_vcpu *vcpu);
|
||||
void vgic_v5_save_state(struct kvm_vcpu *vcpu);
|
||||
|
||||
#define for_each_visible_v5_ppi(__i, __k) \
|
||||
for_each_set_bit(__i, (__k)->arch.vgic.gicv5_vm.vgic_ppi_mask, VGIC_V5_NR_PRIVATE_IRQS)
|
||||
|
||||
static inline int vgic_v3_max_apr_idx(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_cpu *cpu_if = &vcpu->arch.vgic_cpu;
|
||||
|
|
|
|||
|
|
@ -208,17 +208,13 @@ static void gicv5_hwirq_eoi(u32 hwirq_id, u8 hwirq_type)
|
|||
FIELD_PREP(GICV5_GIC_CDDI_TYPE_MASK, hwirq_type);
|
||||
|
||||
gic_insn(cddi, CDDI);
|
||||
|
||||
gic_insn(0, CDEOI);
|
||||
}
|
||||
|
||||
static void gicv5_ppi_irq_eoi(struct irq_data *d)
|
||||
{
|
||||
/* Skip deactivate for forwarded PPI interrupts */
|
||||
if (irqd_is_forwarded_to_vcpu(d)) {
|
||||
gic_insn(0, CDEOI);
|
||||
if (irqd_is_forwarded_to_vcpu(d))
|
||||
return;
|
||||
}
|
||||
|
||||
gicv5_hwirq_eoi(d->hwirq, GICV5_HWIRQ_TYPE_PPI);
|
||||
}
|
||||
|
|
@ -969,6 +965,13 @@ static void __exception_irq_entry gicv5_handle_irq(struct pt_regs *regs)
|
|||
*/
|
||||
isb();
|
||||
|
||||
/*
|
||||
* Ensure that we can receive the next interrupts in the event that we
|
||||
* have a long running handler or directly enter a guest by doing the
|
||||
* priority drop immediately.
|
||||
*/
|
||||
gic_insn(0, CDEOI);
|
||||
|
||||
hwirq = FIELD_GET(GICV5_HWIRQ_INTID, ia);
|
||||
|
||||
handle_irq_per_domain(hwirq);
|
||||
|
|
|
|||
|
|
@ -177,6 +177,11 @@ struct vgic_global {
|
|||
bool has_gcie_v3_compat;
|
||||
|
||||
u32 ich_vtr_el2;
|
||||
|
||||
/* GICv5 PPI capabilities */
|
||||
struct {
|
||||
DECLARE_BITMAP(impl_ppi_mask, VGIC_V5_NR_PRIVATE_IRQS);
|
||||
} vgic_v5_ppi_caps;
|
||||
};
|
||||
|
||||
extern struct vgic_global kvm_vgic_global_state;
|
||||
|
|
@ -200,7 +205,7 @@ struct vgic_irq;
|
|||
*/
|
||||
struct irq_ops {
|
||||
/* Per interrupt flags for special-cased interrupts */
|
||||
unsigned long flags;
|
||||
unsigned long (*get_flags)(void);
|
||||
|
||||
#define VGIC_IRQ_SW_RESAMPLE BIT(0) /* Clear the active state for resampling */
|
||||
|
||||
|
|
@ -266,7 +271,7 @@ struct vgic_irq {
|
|||
u8 priority;
|
||||
u8 group; /* 0 == group 0, 1 == group 1 */
|
||||
|
||||
struct irq_ops *ops;
|
||||
const struct irq_ops *ops;
|
||||
|
||||
void *owner; /* Opaque pointer to reserve an interrupt
|
||||
for in-kernel devices. */
|
||||
|
|
@ -274,7 +279,8 @@ struct vgic_irq {
|
|||
|
||||
static inline bool vgic_irq_needs_resampling(struct vgic_irq *irq)
|
||||
{
|
||||
return irq->ops && (irq->ops->flags & VGIC_IRQ_SW_RESAMPLE);
|
||||
return irq->ops && irq->ops->get_flags &&
|
||||
(irq->ops->get_flags() & VGIC_IRQ_SW_RESAMPLE);
|
||||
}
|
||||
|
||||
struct vgic_register_region;
|
||||
|
|
@ -492,11 +498,6 @@ struct vgic_v5_cpu_if {
|
|||
struct gicv5_vpe gicv5_vpe;
|
||||
};
|
||||
|
||||
/* What PPI capabilities does a GICv5 host have */
|
||||
struct vgic_v5_ppi_caps {
|
||||
DECLARE_BITMAP(impl_ppi_mask, VGIC_V5_NR_PRIVATE_IRQS);
|
||||
};
|
||||
|
||||
struct vgic_cpu {
|
||||
/* CPU vif control registers for world switch */
|
||||
union {
|
||||
|
|
@ -557,7 +558,7 @@ void kvm_vgic_init_cpu_hardware(void);
|
|||
int kvm_vgic_inject_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
|
||||
unsigned int intid, bool level, void *owner);
|
||||
void kvm_vgic_set_irq_ops(struct kvm_vcpu *vcpu, u32 vintid,
|
||||
struct irq_ops *ops);
|
||||
const struct irq_ops *ops);
|
||||
void kvm_vgic_clear_irq_ops(struct kvm_vcpu *vcpu, u32 vintid);
|
||||
int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
|
||||
u32 vintid);
|
||||
|
|
|
|||
|
|
@ -159,6 +159,7 @@ static void guest_code_gicv5(void)
|
|||
check_gicv5_gic_op(CDAFF);
|
||||
check_gicv5_gic_op(CDDI);
|
||||
check_gicv5_gic_op(CDDIS);
|
||||
check_gicv5_gic_op(CDEN);
|
||||
check_gicv5_gic_op(CDEOI);
|
||||
check_gicv5_gic_op(CDHM);
|
||||
check_gicv5_gic_op(CDPEND);
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@ struct vm_gic {
|
|||
u32 gic_dev_type;
|
||||
};
|
||||
|
||||
static u64 max_phys_size;
|
||||
|
||||
#define GUEST_CMD_IRQ_CDIA 10
|
||||
#define GUEST_CMD_IRQ_DIEOI 11
|
||||
#define GUEST_CMD_IS_AWAKE 12
|
||||
|
|
@ -131,6 +129,8 @@ static void test_vgic_v5_ppis(u32 gic_dev_type)
|
|||
|
||||
while (1) {
|
||||
ret = run_vcpu(vcpus[0]);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
switch (get_ucall(vcpus[0], &uc)) {
|
||||
case UCALL_SYNC:
|
||||
|
|
@ -146,7 +146,7 @@ static void test_vgic_v5_ppis(u32 gic_dev_type)
|
|||
irq = FIELD_PREP(KVM_ARM_IRQ_NUM_MASK, 3);
|
||||
irq |= KVM_ARM_IRQ_TYPE_PPI << KVM_ARM_IRQ_TYPE_SHIFT;
|
||||
|
||||
_kvm_irq_line(v.vm, irq, level);
|
||||
kvm_irq_line(v.vm, irq, level);
|
||||
} else if (uc.args[1] == GUEST_CMD_IS_AWAKE) {
|
||||
pr_info("Guest skipping WFI due to pending IRQ\n");
|
||||
} else if (uc.args[1] == GUEST_CMD_IRQ_CDIA) {
|
||||
|
|
@ -208,13 +208,9 @@ void run_tests(u32 gic_dev_type)
|
|||
int main(int ac, char **av)
|
||||
{
|
||||
int ret;
|
||||
int pa_bits;
|
||||
|
||||
test_disable_default_vgic();
|
||||
|
||||
pa_bits = vm_guest_mode_params[VM_MODE_DEFAULT].pa_bits;
|
||||
max_phys_size = 1ULL << pa_bits;
|
||||
|
||||
ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V5);
|
||||
if (ret) {
|
||||
pr_info("No GICv5 support; Not running GIC_v5 tests.\n");
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user