diff mbox

[v3,32/55] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework

Message ID 1462531568-9799-33-git-send-email-andre.przywara@arm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Andre Przywara May 6, 2016, 10:45 a.m. UTC
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 <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
Changelog RFC..v1:
- adapt to new MMIO registration approach:
  register one device for the distributor and two for each VCPU
- implement special handling for private interrupts
- remove empty stub functions
- make IGROUPR return RAO

Changelog v1 .. v2:
- adapt to new framework, introduce vgic-mmio-v3.c
- remove userland register access functions (for now)
- precompute .len when describing a VGIC register
- add missed pointer incrementation on registering redist regions
- replace _nyi stub functions with raz/wi versions

Changelog v2 .. v3:
- replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
- add prototype and stub code for vgic_register_redist_iodevs
- rename register struct variables _rdbase_ and _sgibase_

 virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
 virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
 virt/kvm/arm/vgic/vgic.h         |   7 ++
 4 files changed, 205 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c

Comments

Marc Zyngier May 9, 2016, 5:18 p.m. UTC | #1
On 06/05/16 11:45, Andre Przywara wrote:
> 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 <andre.przywara@arm.com>
> Reviewed-by: Eric Auger <eric.auger@linaro.org>
> ---
> Changelog RFC..v1:
> - adapt to new MMIO registration approach:
>   register one device for the distributor and two for each VCPU
> - implement special handling for private interrupts
> - remove empty stub functions
> - make IGROUPR return RAO
> 
> Changelog v1 .. v2:
> - adapt to new framework, introduce vgic-mmio-v3.c
> - remove userland register access functions (for now)
> - precompute .len when describing a VGIC register
> - add missed pointer incrementation on registering redist regions
> - replace _nyi stub functions with raz/wi versions
> 
> Changelog v2 .. v3:
> - replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
> - add prototype and stub code for vgic_register_redist_iodevs
> - rename register struct variables _rdbase_ and _sgibase_
> 
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
>  virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
>  virt/kvm/arm/vgic/vgic.h         |   7 ++
>  4 files changed, 205 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> new file mode 100644
> index 0000000..06c7ec5
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -0,0 +1,191 @@
> +/*
> + * 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, read_ops, write_ops, bpi) \
> +	{								\
> +		.reg_offset = off,					\
> +		.bits_per_irq = bpi,					\
> +		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
> +		.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,	\
> +		.read = read_ops,					\
> +		.write = write_ops,					\
> +	}
> +
> +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),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
> +	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +};
> +
> +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),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +};
> +
> +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),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +};
> +
> +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, *device;
> +	int c, ret = 0;
> +
> +	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
> +			  GFP_KERNEL);
> +	if (!devices)
> +		return -ENOMEM;
> +
> +	device = devices;
> +	kvm_for_each_vcpu(c, vcpu, kvm) {
> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> +		device->base_addr = redist_base_address;
> +		device->regions = vgic_v3_rdbase_registers;
> +		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
> +		device->redist_vcpu = vcpu;
> +
> +		mutex_lock(&kvm->slots_lock);
> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> +					      redist_base_address,
> +					      SZ_64K, &device->dev);
> +		mutex_unlock(&kvm->slots_lock);
> +
> +		if (ret)
> +			break;
> +
> +		device++;
> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> +		device->base_addr = redist_base_address + SZ_64K;
> +		device->regions = vgic_v3_sgibase_registers;
> +		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
> +		device->redist_vcpu = vcpu;
> +
> +		mutex_lock(&kvm->slots_lock);
> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> +					      redist_base_address + SZ_64K,
> +					      SZ_64K, &device->dev);
> +		mutex_unlock(&kvm->slots_lock);
> +		if (ret) {
> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> +						  &devices[c * 2].dev);
> +			break;
> +		}
> +		device++;
> +		redist_base_address += 2 * SZ_64K;
> +	}

What I fail to see here is what prevents the redistributor range from
overlapping with the distributor (or any other device). The kvm IO bus
is happy with overlapping addresses, but I'm not sure at all that this
is safe.

Care to shed some light on it?

Thanks,

	M.
Chalamarla, Tirumalesh May 9, 2016, 5:51 p.m. UTC | #2
DQoNCg0KDQoNCk9uIDUvOS8xNiwgMTA6MTggQU0sICJrdm1hcm0tYm91bmNlc0BsaXN0cy5jcy5j
b2x1bWJpYS5lZHUgb24gYmVoYWxmIG9mIE1hcmMgWnluZ2llciIgPGt2bWFybS1ib3VuY2VzQGxp
c3RzLmNzLmNvbHVtYmlhLmVkdSBvbiBiZWhhbGYgb2YgbWFyYy56eW5naWVyQGFybS5jb20+IHdy
b3RlOg0KDQo+T24gMDYvMDUvMTYgMTE6NDUsIEFuZHJlIFByenl3YXJhIHdyb3RlOg0KPj4gQ3Jl
YXRlIGEgbmV3IGZpbGUgY2FsbGVkIHZnaWMtbW1pby12My5jIGFuZCBkZXNjcmliZSB0aGUgR0lD
djMNCj4+IGRpc3RyaWJ1dG9yIGFuZCByZWRpc3RyaWJ1dG9yIHJlZ2lzdGVycyB0aGVyZS4NCj4+
IFRoaXMgYWRkcyBhIHNwZWNpYWwgbWFjcm8gdG8gZGVhbCB3aXRoIHRoZSBzcGxpdCBvZiBTR0kv
UFBJIGluIHRoZQ0KPj4gcmVkaXN0cmlidXRvciBhbmQgU1BJcyBpbiB0aGUgZGlzdHJpYnV0b3Is
IHdoaWNoIGFsbG93cyB1cyB0byByZXVzZQ0KPj4gdGhlIGV4aXN0aW5nIEdJQ3YyIGhhbmRsZXJz
IGZvciB0aG9zZSByZWdpc3RlcnMgd2hpY2ggYXJlIGNvbXBhdGlibGUuDQo+PiBBbHNvIHdlIHBy
b3ZpZGUgYSBmdW5jdGlvbiB0byBkZWFsIHdpdGggdGhlIHJlZ2lzdHJhdGlvbiBvZiB0aGUgdHdv
DQo+PiBzZXBhcmF0ZSByZWRpc3RyaWJ1dG9yIGZyYW1lcyBwZXIgVkNQVS4NCj4+IA0KPj4gU2ln
bmVkLW9mZi1ieTogQW5kcmUgUHJ6eXdhcmEgPGFuZHJlLnByenl3YXJhQGFybS5jb20+DQo+PiBS
ZXZpZXdlZC1ieTogRXJpYyBBdWdlciA8ZXJpYy5hdWdlckBsaW5hcm8ub3JnPg0KPj4gLS0tDQo+
PiBDaGFuZ2Vsb2cgUkZDLi52MToNCj4+IC0gYWRhcHQgdG8gbmV3IE1NSU8gcmVnaXN0cmF0aW9u
IGFwcHJvYWNoOg0KPj4gICByZWdpc3RlciBvbmUgZGV2aWNlIGZvciB0aGUgZGlzdHJpYnV0b3Ig
YW5kIHR3byBmb3IgZWFjaCBWQ1BVDQo+PiAtIGltcGxlbWVudCBzcGVjaWFsIGhhbmRsaW5nIGZv
ciBwcml2YXRlIGludGVycnVwdHMNCj4+IC0gcmVtb3ZlIGVtcHR5IHN0dWIgZnVuY3Rpb25zDQo+
PiAtIG1ha2UgSUdST1VQUiByZXR1cm4gUkFPDQo+PiANCj4+IENoYW5nZWxvZyB2MSAuLiB2MjoN
Cj4+IC0gYWRhcHQgdG8gbmV3IGZyYW1ld29yaywgaW50cm9kdWNlIHZnaWMtbW1pby12My5jDQo+
PiAtIHJlbW92ZSB1c2VybGFuZCByZWdpc3RlciBhY2Nlc3MgZnVuY3Rpb25zIChmb3Igbm93KQ0K
Pj4gLSBwcmVjb21wdXRlIC5sZW4gd2hlbiBkZXNjcmliaW5nIGEgVkdJQyByZWdpc3Rlcg0KPj4g
LSBhZGQgbWlzc2VkIHBvaW50ZXIgaW5jcmVtZW50YXRpb24gb24gcmVnaXN0ZXJpbmcgcmVkaXN0
IHJlZ2lvbnMNCj4+IC0gcmVwbGFjZSBfbnlpIHN0dWIgZnVuY3Rpb25zIHdpdGggcmF6L3dpIHZl
cnNpb25zDQo+PiANCj4+IENoYW5nZWxvZyB2MiAuLiB2MzoNCj4+IC0gcmVwbGFjZSBpbmNsdXNp
b24gb2Yga3ZtL3ZnaWMvdmdpYy5oIHdpdGgga3ZtL2FybV92Z2ljLmgNCj4+IC0gYWRkIHByb3Rv
dHlwZSBhbmQgc3R1YiBjb2RlIGZvciB2Z2ljX3JlZ2lzdGVyX3JlZGlzdF9pb2RldnMNCj4+IC0g
cmVuYW1lIHJlZ2lzdGVyIHN0cnVjdCB2YXJpYWJsZXMgX3JkYmFzZV8gYW5kIF9zZ2liYXNlXw0K
Pj4gDQo+PiAgdmlydC9rdm0vYXJtL3ZnaWMvdmdpYy1tbWlvLXYzLmMgfCAxOTEgKysrKysrKysr
KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrDQo+PiAgdmlydC9rdm0vYXJtL3ZnaWMvdmdp
Yy1tbWlvLmMgICAgfCAgIDUgKw0KPj4gIHZpcnQva3ZtL2FybS92Z2ljL3ZnaWMtbW1pby5oICAg
IHwgICAyICsNCj4+ICB2aXJ0L2t2bS9hcm0vdmdpYy92Z2ljLmggICAgICAgICB8ICAgNyArKw0K
Pj4gIDQgZmlsZXMgY2hhbmdlZCwgMjA1IGluc2VydGlvbnMoKykNCj4+ICBjcmVhdGUgbW9kZSAx
MDA2NDQgdmlydC9rdm0vYXJtL3ZnaWMvdmdpYy1tbWlvLXYzLmMNCj4+IA0KPj4gZGlmZiAtLWdp
dCBhL3ZpcnQva3ZtL2FybS92Z2ljL3ZnaWMtbW1pby12My5jIGIvdmlydC9rdm0vYXJtL3ZnaWMv
dmdpYy1tbWlvLXYzLmMNCj4+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0DQo+PiBpbmRleCAwMDAwMDAw
Li4wNmM3ZWM1DQo+PiAtLS0gL2Rldi9udWxsDQo+PiArKysgYi92aXJ0L2t2bS9hcm0vdmdpYy92
Z2ljLW1taW8tdjMuYw0KPj4gQEAgLTAsMCArMSwxOTEgQEANCj4+ICsvKg0KPj4gKyAqIFZHSUN2
MyBNTUlPIGhhbmRsaW5nIGZ1bmN0aW9ucw0KPj4gKyAqDQo+PiArICogVGhpcyBwcm9ncmFtIGlz
IGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkNCj4+
ICsgKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNl
IHZlcnNpb24gMiBhcw0KPj4gKyAqIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3Vu
ZGF0aW9uLg0KPj4gKyAqDQo+PiArICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRo
ZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsDQo+PiArICogYnV0IFdJVEhPVVQgQU5ZIFdB
UlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YNCj4+ICsgKiBNRVJD
SEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhl
DQo+PiArICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4NCj4+
ICsgKi8NCj4+ICsNCj4+ICsjaW5jbHVkZSA8bGludXgvaXJxY2hpcC9hcm0tZ2ljLXYzLmg+DQo+
PiArI2luY2x1ZGUgPGxpbnV4L2t2bS5oPg0KPj4gKyNpbmNsdWRlIDxsaW51eC9rdm1faG9zdC5o
Pg0KPj4gKyNpbmNsdWRlIDxrdm0vaW9kZXYuaD4NCj4+ICsjaW5jbHVkZSA8a3ZtL2FybV92Z2lj
Lmg+DQo+PiArDQo+PiArI2luY2x1ZGUgPGFzbS9rdm1fZW11bGF0ZS5oPg0KPj4gKw0KPj4gKyNp
bmNsdWRlICJ2Z2ljLmgiDQo+PiArI2luY2x1ZGUgInZnaWMtbW1pby5oIg0KPj4gKw0KPj4gKy8q
DQo+PiArICogVGhlIEdJQ3YzIHBlci1JUlEgcmVnaXN0ZXJzIGFyZSBzcGxpdCB0byBjb250cm9s
IFBQSXMgYW5kIFNHSXMgaW4gdGhlDQo+PiArICogcmVkaXN0cmlidXRvcnMsIHdoaWxlIFNQSXMg
YXJlIGNvdmVyZWQgYnkgcmVnaXN0ZXJzIGluIHRoZSBkaXN0cmlidXRvcg0KPj4gKyAqIGJsb2Nr
LiBUcnlpbmcgdG8gc2V0IHByaXZhdGUgSVJRcyBpbiB0aGlzIGJsb2NrIGdldHMgaWdub3JlZC4N
Cj4+ICsgKiBXZSB0YWtlIHNvbWUgc3BlY2lhbCBjYXJlIGhlcmUgdG8gZml4IHRoZSBjYWxjdWxh
dGlvbiBvZiB0aGUgcmVnaXN0ZXINCj4+ICsgKiBvZmZzZXQuDQo+PiArICovDQo+PiArI2RlZmlu
ZSBSRUdJU1RFUl9ERVNDX1dJVEhfQklUU19QRVJfSVJRX1NIQVJFRChvZmYsIHJlYWRfb3BzLCB3
cml0ZV9vcHMsIGJwaSkgXA0KPj4gKwl7CQkJCQkJCQlcDQo+PiArCQkucmVnX29mZnNldCA9IG9m
ZiwJCQkJCVwNCj4+ICsJCS5iaXRzX3Blcl9pcnEgPSBicGksCQkJCQlcDQo+PiArCQkubGVuID0g
KGJwaSAqIFZHSUNfTlJfUFJJVkFURV9JUlFTKSAvIDgsCQlcDQo+PiArCQkucmVhZCA9IHZnaWNf
bW1pb19yZWFkX3JheiwJCQkJXA0KPj4gKwkJLndyaXRlID0gdmdpY19tbWlvX3dyaXRlX3dpLAkJ
CQlcDQo+PiArCX0sIHsJCQkJCQkJCVwNCj4+ICsJCS5yZWdfb2Zmc2V0ID0gb2ZmICsgKGJwaSAq
IFZHSUNfTlJfUFJJVkFURV9JUlFTKSAvIDgsCVwNCj4+ICsJCS5iaXRzX3Blcl9pcnEgPSBicGks
CQkJCQlcDQo+PiArCQkubGVuID0gKGJwaSAqICgxMDI0IC0gVkdJQ19OUl9QUklWQVRFX0lSUVMp
KSAvIDgsCVwNCj4+ICsJCS5yZWFkID0gcmVhZF9vcHMsCQkJCQlcDQo+PiArCQkud3JpdGUgPSB3
cml0ZV9vcHMsCQkJCQlcDQo+PiArCX0NCj4+ICsNCj4+ICtzdGF0aWMgY29uc3Qgc3RydWN0IHZn
aWNfcmVnaXN0ZXJfcmVnaW9uIHZnaWNfdjNfZGlzdF9yZWdpc3RlcnNbXSA9IHsNCj4+ICsJUkVH
SVNURVJfREVTQ19XSVRIX0xFTkdUSChHSUNEX0NUTFIsDQo+PiArCQl2Z2ljX21taW9fcmVhZF9y
YXosIHZnaWNfbW1pb193cml0ZV93aSwgMTYpLA0KPj4gKwlSRUdJU1RFUl9ERVNDX1dJVEhfQklU
U19QRVJfSVJRX1NIQVJFRChHSUNEX0lHUk9VUFIsDQo+PiArCQl2Z2ljX21taW9fcmVhZF9yYW8s
IHZnaWNfbW1pb193cml0ZV93aSwgMSksDQo+PiArCVJFR0lTVEVSX0RFU0NfV0lUSF9CSVRTX1BF
Ul9JUlFfU0hBUkVEKEdJQ0RfSVNFTkFCTEVSLA0KPj4gKwkJdmdpY19tbWlvX3JlYWRfZW5hYmxl
LCB2Z2ljX21taW9fd3JpdGVfc2VuYWJsZSwgMSksDQo+PiArCVJFR0lTVEVSX0RFU0NfV0lUSF9C
SVRTX1BFUl9JUlFfU0hBUkVEKEdJQ0RfSUNFTkFCTEVSLA0KPj4gKwkJdmdpY19tbWlvX3JlYWRf
ZW5hYmxlLCB2Z2ljX21taW9fd3JpdGVfY2VuYWJsZSwgMSksDQo+PiArCVJFR0lTVEVSX0RFU0Nf
V0lUSF9CSVRTX1BFUl9JUlFfU0hBUkVEKEdJQ0RfSVNQRU5EUiwNCj4+ICsJCXZnaWNfbW1pb19y
ZWFkX3BlbmRpbmcsIHZnaWNfbW1pb193cml0ZV9zcGVuZGluZywgMSksDQo+PiArCVJFR0lTVEVS
X0RFU0NfV0lUSF9CSVRTX1BFUl9JUlFfU0hBUkVEKEdJQ0RfSUNQRU5EUiwNCj4+ICsJCXZnaWNf
bW1pb19yZWFkX3BlbmRpbmcsIHZnaWNfbW1pb193cml0ZV9jcGVuZGluZywgMSksDQo+PiArCVJF
R0lTVEVSX0RFU0NfV0lUSF9CSVRTX1BFUl9JUlFfU0hBUkVEKEdJQ0RfSVNBQ1RJVkVSLA0KPj4g
KwkJdmdpY19tbWlvX3JlYWRfYWN0aXZlLCB2Z2ljX21taW9fd3JpdGVfc2FjdGl2ZSwgMSksDQo+
PiArCVJFR0lTVEVSX0RFU0NfV0lUSF9CSVRTX1BFUl9JUlFfU0hBUkVEKEdJQ0RfSUNBQ1RJVkVS
LA0KPj4gKwkJdmdpY19tbWlvX3JlYWRfYWN0aXZlLCB2Z2ljX21taW9fd3JpdGVfY2FjdGl2ZSwg
MSksDQo+PiArCVJFR0lTVEVSX0RFU0NfV0lUSF9CSVRTX1BFUl9JUlFfU0hBUkVEKEdJQ0RfSVBS
SU9SSVRZUiwNCj4+ICsJCXZnaWNfbW1pb19yZWFkX3ByaW9yaXR5LCB2Z2ljX21taW9fd3JpdGVf
cHJpb3JpdHksIDgpLA0KPj4gKwlSRUdJU1RFUl9ERVNDX1dJVEhfQklUU19QRVJfSVJRX1NIQVJF
RChHSUNEX0lUQVJHRVRTUiwNCj4+ICsJCXZnaWNfbW1pb19yZWFkX3JheiwgdmdpY19tbWlvX3dy
aXRlX3dpLCA4KSwNCj4+ICsJUkVHSVNURVJfREVTQ19XSVRIX0JJVFNfUEVSX0lSUV9TSEFSRUQo
R0lDRF9JQ0ZHUiwNCj4+ICsJCXZnaWNfbW1pb19yZWFkX2NvbmZpZywgdmdpY19tbWlvX3dyaXRl
X2NvbmZpZywgMiksDQo+PiArCVJFR0lTVEVSX0RFU0NfV0lUSF9CSVRTX1BFUl9JUlFfU0hBUkVE
KEdJQ0RfSUdSUE1PRFIsDQo+PiArCQl2Z2ljX21taW9fcmVhZF9yYXosIHZnaWNfbW1pb193cml0
ZV93aSwgMSksDQo+PiArCVJFR0lTVEVSX0RFU0NfV0lUSF9CSVRTX1BFUl9JUlFfU0hBUkVEKEdJ
Q0RfSVJPVVRFUiwNCj4+ICsJCXZnaWNfbW1pb19yZWFkX3JheiwgdmdpY19tbWlvX3dyaXRlX3dp
LCA2NCksDQo+PiArCVJFR0lTVEVSX0RFU0NfV0lUSF9MRU5HVEgoR0lDRF9JRFJFR1MsDQo+PiAr
CQl2Z2ljX21taW9fcmVhZF9yYXosIHZnaWNfbW1pb193cml0ZV93aSwgNDgpLA0KPj4gK307DQo+
PiArDQo+PiArc3RhdGljIGNvbnN0IHN0cnVjdCB2Z2ljX3JlZ2lzdGVyX3JlZ2lvbiB2Z2ljX3Yz
X3JkYmFzZV9yZWdpc3RlcnNbXSA9IHsNCj4+ICsJUkVHSVNURVJfREVTQ19XSVRIX0xFTkdUSChH
SUNSX0NUTFIsDQo+PiArCQl2Z2ljX21taW9fcmVhZF9yYXosIHZnaWNfbW1pb193cml0ZV93aSwg
NCksDQo+PiArCVJFR0lTVEVSX0RFU0NfV0lUSF9MRU5HVEgoR0lDUl9JSURSLA0KPj4gKwkJdmdp
Y19tbWlvX3JlYWRfcmF6LCB2Z2ljX21taW9fd3JpdGVfd2ksIDQpLA0KPj4gKwlSRUdJU1RFUl9E
RVNDX1dJVEhfTEVOR1RIKEdJQ1JfVFlQRVIsDQo+PiArCQl2Z2ljX21taW9fcmVhZF9yYXosIHZn
aWNfbW1pb193cml0ZV93aSwgOCksDQo+PiArCVJFR0lTVEVSX0RFU0NfV0lUSF9MRU5HVEgoR0lD
Ul9QUk9QQkFTRVIsDQo+PiArCQl2Z2ljX21taW9fcmVhZF9yYXosIHZnaWNfbW1pb193cml0ZV93
aSwgOCksDQo+PiArCVJFR0lTVEVSX0RFU0NfV0lUSF9MRU5HVEgoR0lDUl9QRU5EQkFTRVIsDQo+
PiArCQl2Z2ljX21taW9fcmVhZF9yYXosIHZnaWNfbW1pb193cml0ZV93aSwgOCksDQo+PiArCVJF
R0lTVEVSX0RFU0NfV0lUSF9MRU5HVEgoR0lDUl9JRFJFR1MsDQo+PiArCQl2Z2ljX21taW9fcmVh
ZF9yYXosIHZnaWNfbW1pb193cml0ZV93aSwgNDgpLA0KPj4gK307DQo+PiArDQo+PiArc3RhdGlj
IGNvbnN0IHN0cnVjdCB2Z2ljX3JlZ2lzdGVyX3JlZ2lvbiB2Z2ljX3YzX3NnaWJhc2VfcmVnaXN0
ZXJzW10gPSB7DQo+PiArCVJFR0lTVEVSX0RFU0NfV0lUSF9MRU5HVEgoR0lDUl9JR1JPVVBSMCwN
Cj4+ICsJCXZnaWNfbW1pb19yZWFkX3JhbywgdmdpY19tbWlvX3dyaXRlX3dpLCA0KSwNCj4+ICsJ
UkVHSVNURVJfREVTQ19XSVRIX0xFTkdUSChHSUNSX0lTRU5BQkxFUjAsDQo+PiArCQl2Z2ljX21t
aW9fcmVhZF9lbmFibGUsIHZnaWNfbW1pb193cml0ZV9zZW5hYmxlLCA0KSwNCj4+ICsJUkVHSVNU
RVJfREVTQ19XSVRIX0xFTkdUSChHSUNSX0lDRU5BQkxFUjAsDQo+PiArCQl2Z2ljX21taW9fcmVh
ZF9lbmFibGUsIHZnaWNfbW1pb193cml0ZV9jZW5hYmxlLCA0KSwNCj4+ICsJUkVHSVNURVJfREVT
Q19XSVRIX0xFTkdUSChHSUNSX0lTUEVORFIwLA0KPj4gKwkJdmdpY19tbWlvX3JlYWRfcGVuZGlu
ZywgdmdpY19tbWlvX3dyaXRlX3NwZW5kaW5nLCA0KSwNCj4+ICsJUkVHSVNURVJfREVTQ19XSVRI
X0xFTkdUSChHSUNSX0lDUEVORFIwLA0KPj4gKwkJdmdpY19tbWlvX3JlYWRfcGVuZGluZywgdmdp
Y19tbWlvX3dyaXRlX2NwZW5kaW5nLCA0KSwNCj4+ICsJUkVHSVNURVJfREVTQ19XSVRIX0xFTkdU
SChHSUNSX0lTQUNUSVZFUjAsDQo+PiArCQl2Z2ljX21taW9fcmVhZF9hY3RpdmUsIHZnaWNfbW1p
b193cml0ZV9zYWN0aXZlLCA0KSwNCj4+ICsJUkVHSVNURVJfREVTQ19XSVRIX0xFTkdUSChHSUNS
X0lDQUNUSVZFUjAsDQo+PiArCQl2Z2ljX21taW9fcmVhZF9hY3RpdmUsIHZnaWNfbW1pb193cml0
ZV9jYWN0aXZlLCA0KSwNCj4+ICsJUkVHSVNURVJfREVTQ19XSVRIX0xFTkdUSChHSUNSX0lQUklP
UklUWVIwLA0KPj4gKwkJdmdpY19tbWlvX3JlYWRfcHJpb3JpdHksIHZnaWNfbW1pb193cml0ZV9w
cmlvcml0eSwgMzIpLA0KPj4gKwlSRUdJU1RFUl9ERVNDX1dJVEhfTEVOR1RIKEdJQ1JfSUNGR1Iw
LA0KPj4gKwkJdmdpY19tbWlvX3JlYWRfY29uZmlnLCB2Z2ljX21taW9fd3JpdGVfY29uZmlnLCA4
KSwNCj4+ICsJUkVHSVNURVJfREVTQ19XSVRIX0xFTkdUSChHSUNSX0lHUlBNT0RSMCwNCj4+ICsJ
CXZnaWNfbW1pb19yZWFkX3JheiwgdmdpY19tbWlvX3dyaXRlX3dpLCA0KSwNCj4+ICsJUkVHSVNU
RVJfREVTQ19XSVRIX0xFTkdUSChHSUNSX05TQUNSLA0KPj4gKwkJdmdpY19tbWlvX3JlYWRfcmF6
LCB2Z2ljX21taW9fd3JpdGVfd2ksIDQpLA0KPj4gK307DQo+PiArDQo+PiArdW5zaWduZWQgaW50
IHZnaWNfdjNfaW5pdF9kaXN0X2lvZGV2KHN0cnVjdCB2Z2ljX2lvX2RldmljZSAqZGV2KQ0KPj4g
K3sNCj4+ICsJZGV2LT5yZWdpb25zID0gdmdpY192M19kaXN0X3JlZ2lzdGVyczsNCj4+ICsJZGV2
LT5ucl9yZWdpb25zID0gQVJSQVlfU0laRSh2Z2ljX3YzX2Rpc3RfcmVnaXN0ZXJzKTsNCj4+ICsN
Cj4+ICsJa3ZtX2lvZGV2aWNlX2luaXQoJmRldi0+ZGV2LCAma3ZtX2lvX2dpY19vcHMpOw0KPj4g
Kw0KPj4gKwlyZXR1cm4gU1pfNjRLOw0KPj4gK30NCj4+ICsNCj4+ICtpbnQgdmdpY19yZWdpc3Rl
cl9yZWRpc3RfaW9kZXZzKHN0cnVjdCBrdm0gKmt2bSwgZ3BhX3QgcmVkaXN0X2Jhc2VfYWRkcmVz
cykNCj4+ICt7DQo+PiArCWludCBucl92Y3B1cyA9IGF0b21pY19yZWFkKCZrdm0tPm9ubGluZV92
Y3B1cyk7DQo+PiArCXN0cnVjdCBrdm1fdmNwdSAqdmNwdTsNCj4+ICsJc3RydWN0IHZnaWNfaW9f
ZGV2aWNlICpkZXZpY2VzLCAqZGV2aWNlOw0KPj4gKwlpbnQgYywgcmV0ID0gMDsNCj4+ICsNCj4+
ICsJZGV2aWNlcyA9IGttYWxsb2Moc2l6ZW9mKHN0cnVjdCB2Z2ljX2lvX2RldmljZSkgKiBucl92
Y3B1cyAqIDIsDQo+PiArCQkJICBHRlBfS0VSTkVMKTsNCj4+ICsJaWYgKCFkZXZpY2VzKQ0KPj4g
KwkJcmV0dXJuIC1FTk9NRU07DQo+PiArDQo+PiArCWRldmljZSA9IGRldmljZXM7DQo+PiArCWt2
bV9mb3JfZWFjaF92Y3B1KGMsIHZjcHUsIGt2bSkgew0KPj4gKwkJa3ZtX2lvZGV2aWNlX2luaXQo
JmRldmljZS0+ZGV2LCAma3ZtX2lvX2dpY19vcHMpOw0KPj4gKwkJZGV2aWNlLT5iYXNlX2FkZHIg
PSByZWRpc3RfYmFzZV9hZGRyZXNzOw0KPj4gKwkJZGV2aWNlLT5yZWdpb25zID0gdmdpY192M19y
ZGJhc2VfcmVnaXN0ZXJzOw0KPj4gKwkJZGV2aWNlLT5ucl9yZWdpb25zID0gQVJSQVlfU0laRSh2
Z2ljX3YzX3JkYmFzZV9yZWdpc3RlcnMpOw0KPj4gKwkJZGV2aWNlLT5yZWRpc3RfdmNwdSA9IHZj
cHU7DQo+PiArDQo+PiArCQltdXRleF9sb2NrKCZrdm0tPnNsb3RzX2xvY2spOw0KPj4gKwkJcmV0
ID0ga3ZtX2lvX2J1c19yZWdpc3Rlcl9kZXYoa3ZtLCBLVk1fTU1JT19CVVMsDQo+PiArCQkJCQkg
ICAgICByZWRpc3RfYmFzZV9hZGRyZXNzLA0KPj4gKwkJCQkJICAgICAgU1pfNjRLLCAmZGV2aWNl
LT5kZXYpOw0KPj4gKwkJbXV0ZXhfdW5sb2NrKCZrdm0tPnNsb3RzX2xvY2spOw0KPj4gKw0KPj4g
KwkJaWYgKHJldCkNCj4+ICsJCQlicmVhazsNCj4+ICsNCj4+ICsJCWRldmljZSsrOw0KPj4gKwkJ
a3ZtX2lvZGV2aWNlX2luaXQoJmRldmljZS0+ZGV2LCAma3ZtX2lvX2dpY19vcHMpOw0KPj4gKwkJ
ZGV2aWNlLT5iYXNlX2FkZHIgPSByZWRpc3RfYmFzZV9hZGRyZXNzICsgU1pfNjRLOw0KPj4gKwkJ
ZGV2aWNlLT5yZWdpb25zID0gdmdpY192M19zZ2liYXNlX3JlZ2lzdGVyczsNCj4+ICsJCWRldmlj
ZS0+bnJfcmVnaW9ucyA9IEFSUkFZX1NJWkUodmdpY192M19zZ2liYXNlX3JlZ2lzdGVycyk7DQo+
PiArCQlkZXZpY2UtPnJlZGlzdF92Y3B1ID0gdmNwdTsNCj4+ICsNCj4+ICsJCW11dGV4X2xvY2so
Jmt2bS0+c2xvdHNfbG9jayk7DQo+PiArCQlyZXQgPSBrdm1faW9fYnVzX3JlZ2lzdGVyX2Rldihr
dm0sIEtWTV9NTUlPX0JVUywNCj4+ICsJCQkJCSAgICAgIHJlZGlzdF9iYXNlX2FkZHJlc3MgKyBT
Wl82NEssDQo+PiArCQkJCQkgICAgICBTWl82NEssICZkZXZpY2UtPmRldik7DQo+PiArCQltdXRl
eF91bmxvY2soJmt2bS0+c2xvdHNfbG9jayk7DQo+PiArCQlpZiAocmV0KSB7DQo+PiArCQkJa3Zt
X2lvX2J1c191bnJlZ2lzdGVyX2Rldihrdm0sIEtWTV9NTUlPX0JVUywNCj4+ICsJCQkJCQkgICZk
ZXZpY2VzW2MgKiAyXS5kZXYpOw0KPj4gKwkJCWJyZWFrOw0KPj4gKwkJfQ0KPj4gKwkJZGV2aWNl
Kys7DQo+PiArCQlyZWRpc3RfYmFzZV9hZGRyZXNzICs9IDIgKiBTWl82NEs7DQo+PiArCX0NCj4N
Cj5XaGF0IEkgZmFpbCB0byBzZWUgaGVyZSBpcyB3aGF0IHByZXZlbnRzIHRoZSByZWRpc3RyaWJ1
dG9yIHJhbmdlIGZyb20NCj5vdmVybGFwcGluZyB3aXRoIHRoZSBkaXN0cmlidXRvciAob3IgYW55
IG90aGVyIGRldmljZSkuIFRoZSBrdm0gSU8gYnVzDQo+aXMgaGFwcHkgd2l0aCBvdmVybGFwcGlu
ZyBhZGRyZXNzZXMsIGJ1dCBJJ20gbm90IHN1cmUgYXQgYWxsIHRoYXQgdGhpcw0KPmlzIHNhZmUu
DQo+DQo+Q2FyZSB0byBzaGVkIHNvbWUgbGlnaHQgb24gaXQ/DQoNCkFkZGVkIHRoZSBzYW1lIHF1
ZXN0aW9uIG9uIHdyb25nIHBhdGNoIGxhc3Qgd2VlaywgdGhhbmtzIE1hcmMuIA0KPg0KPlRoYW5r
cywNCj4NCj4JTS4NCj4tLSANCj5KYXp6IGlzIG5vdCBkZWFkLiBJdCBqdXN0IHNtZWxscyBmdW5u
eS4uLg0KPl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQo+
a3ZtYXJtIG1haWxpbmcgbGlzdA0KPmt2bWFybUBsaXN0cy5jcy5jb2x1bWJpYS5lZHUNCj5odHRw
czovL2xpc3RzLmNzLmNvbHVtYmlhLmVkdS9tYWlsbWFuL2xpc3RpbmZvL2t2bWFybQ0K
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Christoffer Dall May 12, 2016, 10:26 a.m. UTC | #3
On Fri, May 06, 2016 at 11:45:45AM +0100, Andre Przywara wrote:
> 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 <andre.przywara@arm.com>
> Reviewed-by: Eric Auger <eric.auger@linaro.org>
> ---
> Changelog RFC..v1:
> - adapt to new MMIO registration approach:
>   register one device for the distributor and two for each VCPU
> - implement special handling for private interrupts
> - remove empty stub functions
> - make IGROUPR return RAO
> 
> Changelog v1 .. v2:
> - adapt to new framework, introduce vgic-mmio-v3.c
> - remove userland register access functions (for now)
> - precompute .len when describing a VGIC register
> - add missed pointer incrementation on registering redist regions
> - replace _nyi stub functions with raz/wi versions
> 
> Changelog v2 .. v3:
> - replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
> - add prototype and stub code for vgic_register_redist_iodevs
> - rename register struct variables _rdbase_ and _sgibase_
> 
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
>  virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
>  virt/kvm/arm/vgic/vgic.h         |   7 ++
>  4 files changed, 205 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> new file mode 100644
> index 0000000..06c7ec5
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -0,0 +1,191 @@
> +/*
> + * 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, read_ops, write_ops, bpi) \
> +	{								\
> +		.reg_offset = off,					\
> +		.bits_per_irq = bpi,					\
> +		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
> +		.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,	\
> +		.read = read_ops,					\
> +		.write = write_ops,					\
> +	}
> +
> +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),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
> +	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +};
> +
> +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),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +};
> +
> +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),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +};
> +
> +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, *device;
> +	int c, ret = 0;
> +
> +	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
> +			  GFP_KERNEL);
> +	if (!devices)
> +		return -ENOMEM;
> +
> +	device = devices;
> +	kvm_for_each_vcpu(c, vcpu, kvm) {
> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> +		device->base_addr = redist_base_address;
> +		device->regions = vgic_v3_rdbase_registers;
> +		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
> +		device->redist_vcpu = vcpu;
> +
> +		mutex_lock(&kvm->slots_lock);
> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> +					      redist_base_address,
> +					      SZ_64K, &device->dev);
> +		mutex_unlock(&kvm->slots_lock);
> +
> +		if (ret)
> +			break;
> +
> +		device++;
> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> +		device->base_addr = redist_base_address + SZ_64K;
> +		device->regions = vgic_v3_sgibase_registers;
> +		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
> +		device->redist_vcpu = vcpu;
> +
> +		mutex_lock(&kvm->slots_lock);
> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> +					      redist_base_address + SZ_64K,
> +					      SZ_64K, &device->dev);
> +		mutex_unlock(&kvm->slots_lock);
> +		if (ret) {
> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> +						  &devices[c * 2].dev);
> +			break;
> +		}
> +		device++;
> +		redist_base_address += 2 * SZ_64K;

while I think this whole thing is actually correct, I think it could
have been much more clear by, in the beginning of the loop doing:

	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];
	struct vgic_io_device *sgi_dev = &devices[c + 1];

and then referring directly to these variables.

> +	}
> +
> +	if (ret) {
> +		for (c--; c >= 0; c--) {

holy dark mother of all that's evil; I think this is correct.

> +			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);

do we really need this though?  Can't we just rely on KVM to tear down
thew whole bus infrastructure as we're returning an error anyway?

(have you looked at what the unregister_dev function does, it's full of
kmallocs and other fun stuff).


Thanks,
-Christoffer

> +		}
> +		kfree(devices);
> +	} else {
> +		kvm->arch.vgic.redist_iodevs = devices;
> +	}
> +
> +	return ret;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index 19fed56..d1b88d2 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -502,6 +502,11 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>  	case VGIC_V2:
>  		len = vgic_v2_init_dist_iodev(io_device);
>  		break;
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +	case VGIC_V3:
> +		len = vgic_v3_init_dist_iodev(io_device);
> +		break;
> +#endif
>  	default:
>  		BUG_ON(1);
>  	}
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
> index 884eb71..3585ac6 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -123,4 +123,6 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>  
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
> +
>  #endif
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index cf62015..39a8a65 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -40,6 +40,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
>  void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
>  #else
>  static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
>  {
> @@ -61,6 +62,12 @@ static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>  {
>  }
> +
> +static inline int vgic_register_redist_iodevs(struct kvm *kvm,
> +					      gpa_t dist_base_address)
> +{
> +	return -ENODEV;
> +}
>  #endif
>  
>  #endif
> -- 
> 2.7.3
> 


--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Andre Przywara May 12, 2016, 10:52 a.m. UTC | #4
Hi,

On 12/05/16 11:26, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:45AM +0100, Andre Przywara wrote:
>> 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 <andre.przywara@arm.com>
>> Reviewed-by: Eric Auger <eric.auger@linaro.org>
>> ---
>> Changelog RFC..v1:
>> - adapt to new MMIO registration approach:
>>   register one device for the distributor and two for each VCPU
>> - implement special handling for private interrupts
>> - remove empty stub functions
>> - make IGROUPR return RAO
>>
>> Changelog v1 .. v2:
>> - adapt to new framework, introduce vgic-mmio-v3.c
>> - remove userland register access functions (for now)
>> - precompute .len when describing a VGIC register
>> - add missed pointer incrementation on registering redist regions
>> - replace _nyi stub functions with raz/wi versions
>>
>> Changelog v2 .. v3:
>> - replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
>> - add prototype and stub code for vgic_register_redist_iodevs
>> - rename register struct variables _rdbase_ and _sgibase_
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
>>  virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
>>  virt/kvm/arm/vgic/vgic.h         |   7 ++
>>  4 files changed, 205 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> new file mode 100644
>> index 0000000..06c7ec5
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -0,0 +1,191 @@
>> +/*
>> + * 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, read_ops, write_ops, bpi) \
>> +	{								\
>> +		.reg_offset = off,					\
>> +		.bits_per_irq = bpi,					\
>> +		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
>> +		.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,	\
>> +		.read = read_ops,					\
>> +		.write = write_ops,					\
>> +	}
>> +
>> +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),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
>> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
>> +	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>> +};
>> +
>> +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),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>> +};
>> +
>> +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),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
>> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +};
>> +
>> +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, *device;
>> +	int c, ret = 0;
>> +
>> +	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
>> +			  GFP_KERNEL);
>> +	if (!devices)
>> +		return -ENOMEM;
>> +
>> +	device = devices;
>> +	kvm_for_each_vcpu(c, vcpu, kvm) {
>> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>> +		device->base_addr = redist_base_address;
>> +		device->regions = vgic_v3_rdbase_registers;
>> +		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
>> +		device->redist_vcpu = vcpu;
>> +
>> +		mutex_lock(&kvm->slots_lock);
>> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> +					      redist_base_address,
>> +					      SZ_64K, &device->dev);
>> +		mutex_unlock(&kvm->slots_lock);
>> +
>> +		if (ret)
>> +			break;
>> +
>> +		device++;
>> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>> +		device->base_addr = redist_base_address + SZ_64K;
>> +		device->regions = vgic_v3_sgibase_registers;
>> +		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
>> +		device->redist_vcpu = vcpu;
>> +
>> +		mutex_lock(&kvm->slots_lock);
>> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> +					      redist_base_address + SZ_64K,
>> +					      SZ_64K, &device->dev);
>> +		mutex_unlock(&kvm->slots_lock);
>> +		if (ret) {
>> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> +						  &devices[c * 2].dev);
>> +			break;
>> +		}
>> +		device++;
>> +		redist_base_address += 2 * SZ_64K;
> 
> while I think this whole thing is actually correct, I think it could
> have been much more clear by, in the beginning of the loop doing:
> 
> 	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];
> 	struct vgic_io_device *sgi_dev = &devices[c + 1];
> 
> and then referring directly to these variables.

Yeah, looks useful, not sure we want to change it last minute though.

>> +	}
>> +
>> +	if (ret) {
>> +		for (c--; c >= 0; c--) {
> 
> holy dark mother of all that's evil; I think this is correct.
> 
>> +			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);
> 
> do we really need this though?  Can't we just rely on KVM to tear down
> thew whole bus infrastructure as we're returning an error anyway?

I haven't checked if this is really necessary, but this missing teardown
was mentioned multiple times in previous reviews, so I just did it.
We can remove it once we have proven that it's pointless later.

> (have you looked at what the unregister_dev function does, it's full of
> kmallocs and other fun stuff).

TBH, this whole kvm_io_bus framework is really weird (I think
registering a new region copies every thing it had before) and designed
for the x86 use case. But it shouldn't be this series which fixes this.

Cheers,
Andre.

> 
> Thanks,
> -Christoffer
> 
>> +		}
>> +		kfree(devices);
>> +	} else {
>> +		kvm->arch.vgic.redist_iodevs = devices;
>> +	}
>> +
>> +	return ret;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index 19fed56..d1b88d2 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -502,6 +502,11 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>>  	case VGIC_V2:
>>  		len = vgic_v2_init_dist_iodev(io_device);
>>  		break;
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +	case VGIC_V3:
>> +		len = vgic_v3_init_dist_iodev(io_device);
>> +		break;
>> +#endif
>>  	default:
>>  		BUG_ON(1);
>>  	}
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
>> index 884eb71..3585ac6 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.h
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
>> @@ -123,4 +123,6 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>>  
>>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>>  
>> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
>> +
>>  #endif
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index cf62015..39a8a65 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -40,6 +40,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
>>  void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>>  void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
>>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
>> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
>>  #else
>>  static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
>>  {
>> @@ -61,6 +62,12 @@ static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
>>  static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>>  {
>>  }
>> +
>> +static inline int vgic_register_redist_iodevs(struct kvm *kvm,
>> +					      gpa_t dist_base_address)
>> +{
>> +	return -ENODEV;
>> +}
>>  #endif
>>  
>>  #endif
>> -- 
>> 2.7.3
>>
> 
> 
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Marc Zyngier May 12, 2016, 10:58 a.m. UTC | #5
On 12/05/16 11:52, Andre Przywara wrote:
> Hi,
> 
> On 12/05/16 11:26, Christoffer Dall wrote:
>> On Fri, May 06, 2016 at 11:45:45AM +0100, Andre Przywara wrote:
>>> 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 <andre.przywara@arm.com>
>>> Reviewed-by: Eric Auger <eric.auger@linaro.org>
>>> ---
>>> Changelog RFC..v1:
>>> - adapt to new MMIO registration approach:
>>>   register one device for the distributor and two for each VCPU
>>> - implement special handling for private interrupts
>>> - remove empty stub functions
>>> - make IGROUPR return RAO
>>>
>>> Changelog v1 .. v2:
>>> - adapt to new framework, introduce vgic-mmio-v3.c
>>> - remove userland register access functions (for now)
>>> - precompute .len when describing a VGIC register
>>> - add missed pointer incrementation on registering redist regions
>>> - replace _nyi stub functions with raz/wi versions
>>>
>>> Changelog v2 .. v3:
>>> - replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
>>> - add prototype and stub code for vgic_register_redist_iodevs
>>> - rename register struct variables _rdbase_ and _sgibase_
>>>
>>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
>>>  virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
>>>  virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
>>>  virt/kvm/arm/vgic/vgic.h         |   7 ++
>>>  4 files changed, 205 insertions(+)
>>>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> new file mode 100644
>>> index 0000000..06c7ec5
>>> --- /dev/null
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> @@ -0,0 +1,191 @@
>>> +/*
>>> + * 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, read_ops, write_ops, bpi) \
>>> +	{								\
>>> +		.reg_offset = off,					\
>>> +		.bits_per_irq = bpi,					\
>>> +		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
>>> +		.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,	\
>>> +		.read = read_ops,					\
>>> +		.write = write_ops,					\
>>> +	}
>>> +
>>> +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),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
>>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
>>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
>>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
>>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
>>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
>>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
>>> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
>>> +	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>>> +};
>>> +
>>> +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),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>>> +};
>>> +
>>> +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),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
>>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
>>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
>>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
>>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
>>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
>>> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>>> +};
>>> +
>>> +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, *device;
>>> +	int c, ret = 0;
>>> +
>>> +	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
>>> +			  GFP_KERNEL);
>>> +	if (!devices)
>>> +		return -ENOMEM;
>>> +
>>> +	device = devices;
>>> +	kvm_for_each_vcpu(c, vcpu, kvm) {
>>> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>>> +		device->base_addr = redist_base_address;
>>> +		device->regions = vgic_v3_rdbase_registers;
>>> +		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
>>> +		device->redist_vcpu = vcpu;
>>> +
>>> +		mutex_lock(&kvm->slots_lock);
>>> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>>> +					      redist_base_address,
>>> +					      SZ_64K, &device->dev);
>>> +		mutex_unlock(&kvm->slots_lock);
>>> +
>>> +		if (ret)
>>> +			break;
>>> +
>>> +		device++;
>>> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>>> +		device->base_addr = redist_base_address + SZ_64K;
>>> +		device->regions = vgic_v3_sgibase_registers;
>>> +		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
>>> +		device->redist_vcpu = vcpu;
>>> +
>>> +		mutex_lock(&kvm->slots_lock);
>>> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>>> +					      redist_base_address + SZ_64K,
>>> +					      SZ_64K, &device->dev);
>>> +		mutex_unlock(&kvm->slots_lock);
>>> +		if (ret) {
>>> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>>> +						  &devices[c * 2].dev);
>>> +			break;
>>> +		}
>>> +		device++;
>>> +		redist_base_address += 2 * SZ_64K;
>>
>> while I think this whole thing is actually correct, I think it could
>> have been much more clear by, in the beginning of the loop doing:
>>
>> 	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];
>> 	struct vgic_io_device *sgi_dev = &devices[c + 1];
>>
>> and then referring directly to these variables.
> 
> Yeah, looks useful, not sure we want to change it last minute though.

Why not? We're changing much more fundamental things already. I'd rather
have something that I can easily read and convince myself that it does
the right thing rather than merge something that I'm suspicious of.

In other words, we fix it.

Thanks,

	M.
diff mbox

Patch

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
new file mode 100644
index 0000000..06c7ec5
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -0,0 +1,191 @@ 
+/*
+ * 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, read_ops, write_ops, bpi) \
+	{								\
+		.reg_offset = off,					\
+		.bits_per_irq = bpi,					\
+		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
+		.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,	\
+		.read = read_ops,					\
+		.write = write_ops,					\
+	}
+
+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),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
+		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
+		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
+		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
+		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
+		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
+		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
+		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
+		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
+		vgic_mmio_read_config, vgic_mmio_write_config, 2),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
+	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
+};
+
+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),
+	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
+};
+
+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),
+	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
+		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
+		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
+		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
+		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
+		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
+		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
+		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
+		vgic_mmio_read_config, vgic_mmio_write_config, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+};
+
+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, *device;
+	int c, ret = 0;
+
+	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
+			  GFP_KERNEL);
+	if (!devices)
+		return -ENOMEM;
+
+	device = devices;
+	kvm_for_each_vcpu(c, vcpu, kvm) {
+		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
+		device->base_addr = redist_base_address;
+		device->regions = vgic_v3_rdbase_registers;
+		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
+		device->redist_vcpu = vcpu;
+
+		mutex_lock(&kvm->slots_lock);
+		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
+					      redist_base_address,
+					      SZ_64K, &device->dev);
+		mutex_unlock(&kvm->slots_lock);
+
+		if (ret)
+			break;
+
+		device++;
+		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
+		device->base_addr = redist_base_address + SZ_64K;
+		device->regions = vgic_v3_sgibase_registers;
+		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
+		device->redist_vcpu = vcpu;
+
+		mutex_lock(&kvm->slots_lock);
+		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
+					      redist_base_address + SZ_64K,
+					      SZ_64K, &device->dev);
+		mutex_unlock(&kvm->slots_lock);
+		if (ret) {
+			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
+						  &devices[c * 2].dev);
+			break;
+		}
+		device++;
+		redist_base_address += 2 * SZ_64K;
+	}
+
+	if (ret) {
+		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;
+}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 19fed56..d1b88d2 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -502,6 +502,11 @@  int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 	case VGIC_V2:
 		len = vgic_v2_init_dist_iodev(io_device);
 		break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	case VGIC_V3:
+		len = vgic_v3_init_dist_iodev(io_device);
+		break;
+#endif
 	default:
 		BUG_ON(1);
 	}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 884eb71..3585ac6 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -123,4 +123,6 @@  void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
 
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
+unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
+
 #endif
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index cf62015..39a8a65 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -40,6 +40,7 @@  void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
+int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 #else
 static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
 {
@@ -61,6 +62,12 @@  static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
 static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
 {
 }
+
+static inline int vgic_register_redist_iodevs(struct kvm *kvm,
+					      gpa_t dist_base_address)
+{
+	return -ENODEV;
+}
 #endif
 
 #endif