[PATCH v10 00/17] KVM: arm64: GICv3 ITS emulation

Andre Przywara
2016-07-15T11:43:21Z

Hi,

this series allows those KVM guests that use an emulated GICv3 to use LPIs
as well, though in the moment this is limited to emulated PCI devices.
This is based on kvmarm/queue, which now only features the new VGIC
implementation.

Another round of fixes:
An optimization from Marc to only actually refcount LPIs. This avoids
some churn on SPIs and private IRQs which don't need to be refcounted.
Some bugs have been fixed in vgic_copy_lpi_list(), sync_pending_table(),
and the CWRITER handler.
Now we check for device IDs and collection IDs to be actually within
the range the guest once advertised, also a check was added to make sure
we don't try to propagate an unmapped collection to a struct vgic_irq.
>From now on we only support 64K sized pages for the ITS BASER tables.
Some comments have been added or improved.
The changelog below holds a more detailed list.

You can find all of this code (and the prerequisites) in the
its-emul/v10 branch of my repository [1].
This has been briefly tested on the model and on GICv3 hardware, with
lockdep debugging enabled. If you have GICv3 capable hardware, please
test it on your setup.
Also of course any review comments are very welcome!

Cheers,
Andre.

Changelog v9..v10:
- Don't actually refcount SPIs, PPIs, SGIs (only LPIs)
- add vgic-its.c to the Makefile later (avoids warnings in between)
- fix vgic_copy_lpi_list() counter overflow
- fix sync_pending_table optimization to actually work
- drop support for 4K and 16K BASER tables
- use consistent naming for BASER_CACHEABILITY_MASK definitions
- check device ID and collection IDs to fit into the tables
- extra check for indirect device tables to contain valid pointers
- check for collection being mapped before updating target_vcpu
- add and refine some comments
- fix CWRITER handling: rework masking, take lock earlier, fix comparison
- move some ITS initialization bits into vgic_its_register and rename it

Changelog v8..v9:
- MMIO dispatching now no longer holds iodev type in each register
- indirect bit is now cleared for collections
- sanitisation functions reworked (no extra masking, taking
register specific masks)
- make PROPBASER/PENDBASER updates atomic
- move vgic_its_get_lpi to vgic.c
- fix potential race in vgic_add_lpi
- add comments on puts and gets if not obviously symmetric
- simplify copy_lpi_list (no get/put anymore)
- remove vgic_put_irq_locked()
- remove update_lpi_config_filtered() wrapper
- take its_lock in vgic_its_handle_command() already
- move PENDBASER/PROPBASER RES0 masking into sanitise functions
- properly mask *BASER registers to only support 48 bits
- cache last read byte in its_sync_lpi_pending_table()

Changelog v7..v8:
- rebase on old-VGIC removal patch
- add missing vgic_put_irq()s
- check and ensure proper ITS initialisation sequence
- avoid double collection mapping
- renaming vits_ function prefixes to vgic_its_
- properly setup PENDBASER (for new VGIC now)
- change vgic_v2_probe init order to allow clean exit

Changelog v6..v7:
- use kref reference counting
- remove RCU usage from lpi_list, use spinlock instead
- copy list of LPIs before accessing guest memory
- introduce kvm_io_bus_get_dev()
- refactor parts of arm-gic-v3.h header file
- provide proper initial values for redistributor and ITS base registers
- rework sanitisation of base registers
- rework VGIC MMIO dispatching to differentiate between VGIC parts
- smaller fixes, also comments and commit messages amended

Changelog v5..v6:
- remove its_list from VGIC code
- add lpi_list and accessor functions
- introduce reference counting to struct vgic_irq
- replace its_lock spinlock with its_cmd and its_lock mutexes
- simplify guest memory accesses (due to the new mutexes)
- avoid unnecessary affinity updates
- refine base register address masking
- introduce sanity checks for PROPBASER and PENDBASER
- implement BASER<n> registers
- pass struct vgic_its directly into the MMIO handlers
- convert KVM_SIGNAL_MSI ioctl into an MMIO write
- add explicit INIT ioctl to the ITS KVM device
- adjusting comments and commit messages

Changelog v4..v5:
- adapting to final new VGIC (MMIO handlers, etc.)
- new KVM device to model an ITS, multiple instances allowed
- move redistributor data into struct vgic_cpu
- separate distributor and ITS(es)
- various bug fixes and amended comments after review comments

Changelog v3..v4:
- adapting to new VGIC (changes in IRQ injection mechanism)

Changelog v2..v3:
- adapt to 4.3-rc and Christoffer's timer rework
- adapt spin locks on handling PROPBASER/PENDBASER registers
- rework locking in ITS command handling (dropping dist where needed)
- only clear LPI pending bit if LPI could actually be queued
- simplify GICR_CTLR handling
- properly free ITTEs (including our pending bitmap)
- fix corner cases with unmapped collections
- keep retire_lr() around
- rename vgic_handle_base_register to vgic_reg64_access()
- use kcalloc instead of kmalloc
- minor fixes, renames and added comments

Changelog v1..v2
- fix issues when using non-ITS GICv3 emulation
- streamline frame address initialization (new patch 05/15)
- preallocate buffer memory for reading from guest's memory
- move locking into the actual command handlers
- preallocate memory for new structures if needed
- use non-atomic __set_bit() and __clear_bit() when under the lock
- add INT command handler to allow LPI injection from the guest
- rewrite CWRITER handler to align with new locking scheme
- remove unneeded CONFIG_HAVE_KVM_MSI #ifdefs
- check memory table size against our LPI limit (65536 interrupts)
- observe initial gap of 1024 interrupts in pending table
- use term "configuration table" to be in line with the spec
- clarify and extend documentation on API extensions
- introduce new KVM_CAP_MSI_DEVID capability to advertise device ID requirement
- update, fix and add many comments
- minor style changes as requested by reviewers

---------------

The GICv3 ITS (Interrupt Translation Service) is a part of the
ARM GICv3 interrupt controller [3] used for implementing MSIs.
It specifies a new kind of interrupts (LPIs), which are mapped to
establish a connection between a device, its MSI payload value and
the target processor the IRQ is eventually delivered to.
In order to allow using MSIs in an ARM64 KVM guest, we emulate this
ITS widget in the kernel.
The ITS works by reading commands written by software (from the guest
in our case) into a (guest allocated) memory region and establishing
the mapping between a device, the MSI payload and the target CPU.
We parse these commands and update our internal data structures to
reflect those changes. On an MSI injection we iterate those
structures to learn the LPI number we have to inject.
For the time being we use simple lists to hold the data, this is
good enough for the small number of entries each of the components
currently have. Should this become a performance bottleneck in the
future, those can be extended to arrays or trees if needed.

Most of the code lives in a separate source file (vgic-its.c), though
there are some changes necessary in the existing VGIC files.

For the time being this series gives us the ability to use emulated
PCI devices that can use MSIs in the guest. Those have to be
triggered by letting the userland device emulation simulate the MSI
write with the KVM_SIGNAL_MSI ioctl. This will be translated into
the proper LPI by the ITS emulation and injected into the guest in
the usual way (just with a higher IRQ number).

This series is based on kvmarm/queue and can be found at the
its-emul/v10 branch of this repository [1].
For this to be used you need a GICv3 host machine (a fast model would
do), though it does not rely on any host ITS bits (neither in hardware
or software).

To test this you can use the kvmtool patches available in the "its-v6"
branch here [2].
Start a guest with: "$ lkvm run --irqchip=gicv3-its --force-pci"
and see the ITS being used for instance by the virtio devices.

[1]: git://linux-arm.org/linux-ap.git
http://www.linux-arm.org/git?p=linux-ap.git;a=log;h=refs/heads/its-emul/v10
[2]: git://linux-arm.org/kvmtool.git
http://www.linux-arm.org/git?p=kvmtool.git;a=log;h=refs/heads/its-v6
[3]: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0069b/index.html

Andre Przywara (17):
KVM: arm/arm64: move redistributor kvm_io_devices
KVM: arm/arm64: check return value for kvm_register_vgic_device
KVM: extend struct kvm_msi to hold a 32-bit device ID
KVM: arm/arm64: extend arch CAP checks to allow per-VM capabilities
KVM: kvm_io_bus: add kvm_io_bus_get_dev() call
KVM: arm/arm64: VGIC: add refcounting for IRQs
irqchip: refactor and add GICv3 definitions
KVM: arm64: handle ITS related GICv3 redistributor registers
KVM: arm64: introduce ITS emulation file with MMIO framework
KVM: arm64: introduce new KVM ITS device
KVM: arm64: implement basic ITS register handlers
KVM: arm64: connect LPIs to the VGIC emulation
KVM: arm64: read initial LPI pending table
KVM: arm64: allow updates of LPI configuration table
KVM: arm64: implement ITS command queue command handlers
KVM: arm64: implement MSI injection in ITS emulation
KVM: arm64: enable ITS emulation as a virtual MSI controller

Documentation/virtual/kvm/api.txt | 14 +-
Documentation/virtual/kvm/devices/arm-vgic.txt | 25 +-
arch/arm/include/asm/kvm_host.h | 2 +-
arch/arm/kvm/arm.c | 3 +-
arch/arm64/include/asm/kvm_host.h | 2 +-
arch/arm64/include/uapi/asm/kvm.h | 2 +
arch/arm64/kvm/Kconfig | 1 +
arch/arm64/kvm/Makefile | 1 +
arch/arm64/kvm/reset.c | 8 +-
include/kvm/arm_vgic.h | 74 +-
include/linux/irqchip/arm-gic-v3.h | 180 ++-
include/linux/kvm_host.h | 2 +
include/uapi/linux/kvm.h | 7 +-
virt/kvm/arm/vgic/vgic-init.c | 9 +-
virt/kvm/arm/vgic/vgic-its.c | 1484 ++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-kvm-device.c | 22 +-
virt/kvm/arm/vgic/vgic-mmio-v2.c | 8 +
virt/kvm/arm/vgic/vgic-mmio-v3.c | 247 +++-
virt/kvm/arm/vgic/vgic-mmio.c | 62 +-
virt/kvm/arm/vgic/vgic-mmio.h | 31 +-
virt/kvm/arm/vgic/vgic-v2.c | 12 +-
virt/kvm/arm/vgic/vgic-v3.c | 29 +-
virt/kvm/arm/vgic/vgic.c | 127 +-
virt/kvm/arm/vgic/vgic.h | 30 +-
virt/kvm/kvm_main.c | 24 +
25 files changed, 2265 insertions(+), 141 deletions(-)
create mode 100644 virt/kvm/arm/vgic/vgic-its.c

--
2.9.0