Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

KVM: arm64: GICv2: Handle deactivation via GICV_DIR traps

Add the plumbing of GICv2 interrupt deactivation via GICV_DIR.
This requires adding a new device so that we can easily decode
the DIR address.

The deactivation itself is very similar to the GICv3 version.

Tested-by: Fuad Tabba <tabba@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Tested-by: Mark Brown <broonie@kernel.org>
Link: https://msgid.link/20251120172540.2267180-39-maz@kernel.org
Signed-off-by: Oliver Upton <oupton@kernel.org>

authored by

Marc Zyngier and committed by
Oliver Upton
255de897 281c6c06

+112
+24
arch/arm64/kvm/vgic/vgic-mmio-v2.c
··· 359 359 vgic_set_vmcr(vcpu, &vmcr); 360 360 } 361 361 362 + static void vgic_mmio_write_dir(struct kvm_vcpu *vcpu, 363 + gpa_t addr, unsigned int len, 364 + unsigned long val) 365 + { 366 + if (kvm_vgic_global_state.type == VGIC_V2) 367 + vgic_v2_deactivate(vcpu, val); 368 + else 369 + vgic_v3_deactivate(vcpu, val); 370 + } 371 + 362 372 static unsigned long vgic_mmio_read_apr(struct kvm_vcpu *vcpu, 363 373 gpa_t addr, unsigned int len) 364 374 { ··· 492 482 REGISTER_DESC_WITH_LENGTH(GIC_CPU_IDENT, 493 483 vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4, 494 484 VGIC_ACCESS_32bit), 485 + REGISTER_DESC_WITH_LENGTH_UACCESS(GIC_CPU_DEACTIVATE, 486 + vgic_mmio_read_raz, vgic_mmio_write_dir, 487 + vgic_mmio_read_raz, vgic_mmio_uaccess_write_wi, 488 + 4, VGIC_ACCESS_32bit), 495 489 }; 496 490 497 491 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev) ··· 506 492 kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops); 507 493 508 494 return SZ_4K; 495 + } 496 + 497 + unsigned int vgic_v2_init_cpuif_iodev(struct vgic_io_device *dev) 498 + { 499 + dev->regions = vgic_v2_cpu_registers; 500 + dev->nr_regions = ARRAY_SIZE(vgic_v2_cpu_registers); 501 + 502 + kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops); 503 + 504 + return KVM_VGIC_V2_CPU_SIZE; 509 505 } 510 506 511 507 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
+1
arch/arm64/kvm/vgic/vgic-mmio.h
··· 213 213 const u32 val); 214 214 215 215 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev); 216 + unsigned int vgic_v2_init_cpuif_iodev(struct vgic_io_device *dev); 216 217 217 218 unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev); 218 219
+85
arch/arm64/kvm/vgic/vgic-v2.c
··· 9 9 #include <kvm/arm_vgic.h> 10 10 #include <asm/kvm_mmu.h> 11 11 12 + #include "vgic-mmio.h" 12 13 #include "vgic.h" 13 14 14 15 static inline void vgic_v2_write_lr(int lr, u32 val) ··· 146 145 } 147 146 148 147 cpuif->used_lrs = 0; 148 + } 149 + 150 + void vgic_v2_deactivate(struct kvm_vcpu *vcpu, u32 val) 151 + { 152 + struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; 153 + struct vgic_v2_cpu_if *cpuif = &vgic_cpu->vgic_v2; 154 + struct kvm_vcpu *target_vcpu = NULL; 155 + bool mmio = false; 156 + struct vgic_irq *irq; 157 + unsigned long flags; 158 + u64 lr = 0; 159 + u8 cpuid; 160 + 161 + /* Snapshot CPUID, and remove it from the INTID */ 162 + cpuid = FIELD_GET(GENMASK_ULL(12, 10), val); 163 + val &= ~GENMASK_ULL(12, 10); 164 + 165 + /* We only deal with DIR when EOIMode==1 */ 166 + if (!(cpuif->vgic_vmcr & GICH_VMCR_EOI_MODE_MASK)) 167 + return; 168 + 169 + /* Make sure we're in the same context as LR handling */ 170 + local_irq_save(flags); 171 + 172 + irq = vgic_get_vcpu_irq(vcpu, val); 173 + if (WARN_ON_ONCE(!irq)) 174 + goto out; 175 + 176 + /* See the corresponding v3 code for the rationale */ 177 + scoped_guard(raw_spinlock, &irq->irq_lock) { 178 + target_vcpu = irq->vcpu; 179 + 180 + /* Not on any ap_list? */ 181 + if (!target_vcpu) 182 + goto put; 183 + 184 + /* 185 + * Urgh. We're deactivating something that we cannot 186 + * observe yet... Big hammer time. 187 + */ 188 + if (irq->on_lr) { 189 + mmio = true; 190 + goto put; 191 + } 192 + 193 + /* SGI: check that the cpuid matches */ 194 + if (val < VGIC_NR_SGIS && irq->active_source != cpuid) { 195 + target_vcpu = NULL; 196 + goto put; 197 + } 198 + 199 + /* (with a Dalek voice) DEACTIVATE!!!! */ 200 + lr = vgic_v2_compute_lr(vcpu, irq) & ~GICH_LR_ACTIVE_BIT; 201 + } 202 + 203 + if (lr & GICH_LR_HW) 204 + writel_relaxed(FIELD_GET(GICH_LR_PHYSID_CPUID, lr), 205 + kvm_vgic_global_state.gicc_base + GIC_CPU_DEACTIVATE); 206 + 207 + vgic_v2_fold_lr(vcpu, lr); 208 + 209 + put: 210 + vgic_put_irq(vcpu->kvm, irq); 211 + 212 + out: 213 + local_irq_restore(flags); 214 + 215 + if (mmio) 216 + vgic_mmio_write_cactive(vcpu, (val / 32) * 4, 4, BIT(val % 32)); 217 + 218 + /* Force the ap_list to be pruned */ 219 + if (target_vcpu) 220 + kvm_make_request(KVM_REQ_VGIC_PROCESS_UPDATE, target_vcpu); 149 221 } 150 222 151 223 static u32 vgic_v2_compute_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq) ··· 420 346 int vgic_v2_map_resources(struct kvm *kvm) 421 347 { 422 348 struct vgic_dist *dist = &kvm->arch.vgic; 349 + unsigned int len; 423 350 int ret = 0; 424 351 425 352 if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) || ··· 443 368 kvm_err("Unable to initialize VGIC dynamic data structures\n"); 444 369 return ret; 445 370 } 371 + 372 + len = vgic_v2_init_cpuif_iodev(&dist->cpuif_iodev); 373 + dist->cpuif_iodev.base_addr = dist->vgic_cpu_base; 374 + dist->cpuif_iodev.iodev_type = IODEV_CPUIF; 375 + dist->cpuif_iodev.redist_vcpu = NULL; 376 + 377 + ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, dist->vgic_cpu_base, 378 + len, &dist->cpuif_iodev.dev); 379 + if (ret) 380 + return ret; 446 381 447 382 if (!static_branch_unlikely(&vgic_v2_cpuif_trap)) { 448 383 ret = kvm_phys_addr_ioremap(kvm, dist->vgic_cpu_base,
+1
arch/arm64/kvm/vgic/vgic.h
··· 277 277 278 278 void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu); 279 279 void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr); 280 + void vgic_v2_deactivate(struct kvm_vcpu *vcpu, u32 val); 280 281 void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr); 281 282 void vgic_v2_configure_hcr(struct kvm_vcpu *vcpu, struct ap_list_summary *als); 282 283 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
+1
include/kvm/arm_vgic.h
··· 287 287 struct vgic_irq *spis; 288 288 289 289 struct vgic_io_device dist_iodev; 290 + struct vgic_io_device cpuif_iodev; 290 291 291 292 bool has_its; 292 293 bool table_write_in_progress;