forked from analogdevicesinc/linux
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
Create a new file called vgic-mmio-v3.c and describe the GICv3 distributor and redistributor registers there. This adds a special macro to deal with the split of SGI/PPI in the redistributor and SPIs in the distributor, which allows us to reuse the existing GICv2 handlers for those registers which are compatible. Also we provide a function to deal with the registration of the two separate redistributor frames per VCPU. Signed-off-by: Andre Przywara <[email protected]> Reviewed-by: Eric Auger <[email protected]> Reviewed-by: Christoffer Dall <[email protected]>
- Loading branch information
Showing
4 changed files
with
238 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
/* | ||
* VGICv3 MMIO handling functions | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#include <linux/irqchip/arm-gic-v3.h> | ||
#include <linux/kvm.h> | ||
#include <linux/kvm_host.h> | ||
#include <kvm/iodev.h> | ||
#include <kvm/arm_vgic.h> | ||
|
||
#include <asm/kvm_emulate.h> | ||
|
||
#include "vgic.h" | ||
#include "vgic-mmio.h" | ||
|
||
/* | ||
* The GICv3 per-IRQ registers are split to control PPIs and SGIs in the | ||
* redistributors, while SPIs are covered by registers in the distributor | ||
* block. Trying to set private IRQs in this block gets ignored. | ||
* We take some special care here to fix the calculation of the register | ||
* offset. | ||
*/ | ||
#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, bpi, acc) \ | ||
{ \ | ||
.reg_offset = off, \ | ||
.bits_per_irq = bpi, \ | ||
.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8, \ | ||
.access_flags = acc, \ | ||
.read = vgic_mmio_read_raz, \ | ||
.write = vgic_mmio_write_wi, \ | ||
}, { \ | ||
.reg_offset = off + (bpi * VGIC_NR_PRIVATE_IRQS) / 8, \ | ||
.bits_per_irq = bpi, \ | ||
.len = (bpi * (1024 - VGIC_NR_PRIVATE_IRQS)) / 8, \ | ||
.access_flags = acc, \ | ||
.read = rd, \ | ||
.write = wr, \ | ||
} | ||
|
||
static const struct vgic_register_region vgic_v3_dist_registers[] = { | ||
REGISTER_DESC_WITH_LENGTH(GICD_CTLR, | ||
vgic_mmio_read_raz, vgic_mmio_write_wi, 16, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR, | ||
vgic_mmio_read_rao, vgic_mmio_write_wi, 1, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER, | ||
vgic_mmio_read_enable, vgic_mmio_write_senable, 1, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER, | ||
vgic_mmio_read_enable, vgic_mmio_write_cenable, 1, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR, | ||
vgic_mmio_read_pending, vgic_mmio_write_spending, 1, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR, | ||
vgic_mmio_read_pending, vgic_mmio_write_cpending, 1, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER, | ||
vgic_mmio_read_active, vgic_mmio_write_sactive, 1, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER, | ||
vgic_mmio_read_active, vgic_mmio_write_cactive, 1, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR, | ||
vgic_mmio_read_priority, vgic_mmio_write_priority, 8, | ||
VGIC_ACCESS_32bit | VGIC_ACCESS_8bit), | ||
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR, | ||
vgic_mmio_read_raz, vgic_mmio_write_wi, 8, | ||
VGIC_ACCESS_32bit | VGIC_ACCESS_8bit), | ||
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR, | ||
vgic_mmio_read_config, vgic_mmio_write_config, 2, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR, | ||
vgic_mmio_read_raz, vgic_mmio_write_wi, 1, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER, | ||
vgic_mmio_read_raz, vgic_mmio_write_wi, 64, | ||
VGIC_ACCESS_64bit | VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_LENGTH(GICD_IDREGS, | ||
vgic_mmio_read_raz, vgic_mmio_write_wi, 48, | ||
VGIC_ACCESS_32bit), | ||
}; | ||
|
||
static const struct vgic_register_region vgic_v3_rdbase_registers[] = { | ||
REGISTER_DESC_WITH_LENGTH(GICR_CTLR, | ||
vgic_mmio_read_raz, vgic_mmio_write_wi, 4, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_LENGTH(GICR_IIDR, | ||
vgic_mmio_read_raz, vgic_mmio_write_wi, 4, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_LENGTH(GICR_TYPER, | ||
vgic_mmio_read_raz, vgic_mmio_write_wi, 8, | ||
VGIC_ACCESS_64bit | VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER, | ||
vgic_mmio_read_raz, vgic_mmio_write_wi, 8, | ||
VGIC_ACCESS_64bit | VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER, | ||
vgic_mmio_read_raz, vgic_mmio_write_wi, 8, | ||
VGIC_ACCESS_64bit | VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_LENGTH(GICR_IDREGS, | ||
vgic_mmio_read_raz, vgic_mmio_write_wi, 48, | ||
VGIC_ACCESS_32bit), | ||
}; | ||
|
||
static const struct vgic_register_region vgic_v3_sgibase_registers[] = { | ||
REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0, | ||
vgic_mmio_read_rao, vgic_mmio_write_wi, 4, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0, | ||
vgic_mmio_read_enable, vgic_mmio_write_senable, 4, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0, | ||
vgic_mmio_read_enable, vgic_mmio_write_cenable, 4, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0, | ||
vgic_mmio_read_pending, vgic_mmio_write_spending, 4, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0, | ||
vgic_mmio_read_pending, vgic_mmio_write_cpending, 4, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0, | ||
vgic_mmio_read_active, vgic_mmio_write_sactive, 4, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0, | ||
vgic_mmio_read_active, vgic_mmio_write_cactive, 4, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0, | ||
vgic_mmio_read_priority, vgic_mmio_write_priority, 32, | ||
VGIC_ACCESS_32bit | VGIC_ACCESS_8bit), | ||
REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0, | ||
vgic_mmio_read_config, vgic_mmio_write_config, 8, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0, | ||
vgic_mmio_read_raz, vgic_mmio_write_wi, 4, | ||
VGIC_ACCESS_32bit), | ||
REGISTER_DESC_WITH_LENGTH(GICR_NSACR, | ||
vgic_mmio_read_raz, vgic_mmio_write_wi, 4, | ||
VGIC_ACCESS_32bit), | ||
}; | ||
|
||
unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev) | ||
{ | ||
dev->regions = vgic_v3_dist_registers; | ||
dev->nr_regions = ARRAY_SIZE(vgic_v3_dist_registers); | ||
|
||
kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops); | ||
|
||
return SZ_64K; | ||
} | ||
|
||
int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address) | ||
{ | ||
int nr_vcpus = atomic_read(&kvm->online_vcpus); | ||
struct kvm_vcpu *vcpu; | ||
struct vgic_io_device *devices; | ||
int c, ret = 0; | ||
|
||
devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2, | ||
GFP_KERNEL); | ||
if (!devices) | ||
return -ENOMEM; | ||
|
||
kvm_for_each_vcpu(c, vcpu, kvm) { | ||
gpa_t rd_base = redist_base_address + c * SZ_64K * 2; | ||
gpa_t sgi_base = rd_base + SZ_64K; | ||
struct vgic_io_device *rd_dev = &devices[c * 2]; | ||
struct vgic_io_device *sgi_dev = &devices[c * 2 + 1]; | ||
|
||
kvm_iodevice_init(&rd_dev->dev, &kvm_io_gic_ops); | ||
rd_dev->base_addr = rd_base; | ||
rd_dev->regions = vgic_v3_rdbase_registers; | ||
rd_dev->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers); | ||
rd_dev->redist_vcpu = vcpu; | ||
|
||
mutex_lock(&kvm->slots_lock); | ||
ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, rd_base, | ||
SZ_64K, &rd_dev->dev); | ||
mutex_unlock(&kvm->slots_lock); | ||
|
||
if (ret) | ||
break; | ||
|
||
kvm_iodevice_init(&sgi_dev->dev, &kvm_io_gic_ops); | ||
sgi_dev->base_addr = sgi_base; | ||
sgi_dev->regions = vgic_v3_sgibase_registers; | ||
sgi_dev->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers); | ||
sgi_dev->redist_vcpu = vcpu; | ||
|
||
mutex_lock(&kvm->slots_lock); | ||
ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, sgi_base, | ||
SZ_64K, &sgi_dev->dev); | ||
mutex_unlock(&kvm->slots_lock); | ||
if (ret) { | ||
kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, | ||
&rd_dev->dev); | ||
break; | ||
} | ||
} | ||
|
||
if (ret) { | ||
/* The current c failed, so we start with the previous one. */ | ||
for (c--; c >= 0; c--) { | ||
kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, | ||
&devices[c * 2].dev); | ||
kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, | ||
&devices[c * 2 + 1].dev); | ||
} | ||
kfree(devices); | ||
} else { | ||
kvm->arch.vgic.redist_iodevs = devices; | ||
} | ||
|
||
return ret; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters