From: Marc Zyngier <hidden> Date: 2017-06-28 15:04:49
Yes, it's been a long time coming, but I really wasn't looking forward
to picking this up again. Anyway...
This (monster of a) series implements full support for GICv4, bringing
direct injection of MSIs to KVM on arm and arm64, assuming you have
the right hardware (which is quite unlikely).
To get an idea of the design, I'd recommend you start with patch #32,
which tries to shed some light on the approach that I've taken. And
before that, please digest some of the GICv3/GICv4 architecture
documentation[1] (less than 800 pages!). Once you feel reasonably
insane, you'll be in the right mood to read the code.
The structure of the series is fairly simple. The initial 34 patches
add some generic support for GICv4, while the rest of the code plugs
KVM into it. This series relies on Eric Auger's irq-bypass series[2],
which is a prerequisite for this work.
The stack has been *very lightly* tested on an arm64 model, with a PCI
virtio block device passed from the host to a guest (using kvmtool and
Jean-Philippe Brucker's excellent VFIO support patches[3]). As it has
never seen any HW, I expect things to be subtly broken, so go forward
and test if you can, though I'm mostly interested in people reviewing
the code at the moment.
I've pushed out a branch based on 4.12-rc6 containing the
dependencies (as well as a couple of debug patches):
git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv4-kvm
* From v1:
- The bulk of the 30-something initial patches have seen countless
bugs being fixed, and some key data structures have been subtly
tweaked (or killed altogether). They are still quite similar to
what I had in v1 though.
- The whole KVM code is brand new and as I said above, only lightly
tested.
- Collected a bunch a R-bs from Thomas and Eric (many thanks, guys).
[1] https://static.docs.arm.com/ihi0069/c/IHI0069C_gic_architecture_specification.pdf
[2] http://www.spinics.net/lists/kvm/msg151463.html
[3] http://www.spinics.net/lists/kvm/msg151823.html
Marc Zyngier (52):
genirq: Let irq_set_vcpu_affinity() iterate over hierarchy
irqchip/gic-v3: Add redistributor iterator
irqchip/gic-v3: Add VLPI/DirectLPI discovery
irqchip/gic-v3-its: Move LPI definitions around
irqchip/gic-v3-its: Add probing for VLPI properties
irqchip/gic-v3-its: Macro-ize its_send_single_command
irqchip/gic-v3-its: Implement irq_set_irqchip_state for pending state
irqchip/gic-v3-its: Split out property table allocation
irqchip/gic-v3-its: Allow use of indirect VCPU tables
irqchip/gic-v3-its: Split out pending table allocation
irqchip/gic-v3-its: Rework LPI freeing
irqchip/gic-v3-its: Generalize device table allocation
irqchip/gic-v3-its: Generalize LPI configuration
irqchip/gic-v4: Add management structure definitions
irqchip/gic-v3-its: Add GICv4 ITS command definitions
irqchip/gic-v3-its: Add VLPI configuration hook
irqchip/gic-v3-its: Add VLPI map/unmap operations
irqchip/gic-v3-its: Add VLPI configuration handling
irqchip/gic-v3-its: Add VPE domain infrastructure
irqchip/gic-v3-its: Add VPE irq domain allocation/teardown
irqchip/gic-v3-its: Add VPE irq domain [de]activation
irqchip/gic-v3-its: Add VPENDBASER/VPROPBASER accessors
irqchip/gic-v3-its: Add VPE scheduling
irqchip/gic-v3-its: Add VPE invalidation hook
irqchip/gic-v3-its: Add VPE affinity changes
irqchip/gic-v3-its: Add VPE interrupt masking
irqchip/gic-v3-its: Support VPE doorbell invalidation even when
!DirectLPI
irqchip/gic-v3-its: Set implementation defined bit to enable VLPIs
irqchip/gic-v4: Add per-VM VPE domain creation
irqchip/gic-v4: Add VPE command interface
irqchip/gic-v4: Add VLPI configuration interface
irqchip/gic-v4: Add some basic documentation
irqchip/gic-v4: Enable low-level GICv4 operations
irqchip/gic-v3: Advertise GICv4 support to KVM
KVM: arm/arm64: vgic: Move kvm_vgic_destroy call around
KVM: arm/arm64: vITS: Add MSI translation helpers
KVM: arm/arm64: GICv4: Add init and teardown of the vPE irq domain
KVM: arm/arm64: GICv4: Wire init/teardown of per-VM support
KVM: arm/arm64: GICv4: Wire mapping/unmapping of VLPIs in VFIO irq
bypass
KVM: arm/arm64: GICv4: Handle INT command applied to a VLPI
KVM: arm/arm64: GICv4: Unmap VLPI when freeing an LPI
KVM: arm/arm64: GICv4: Handle MOVI applied to a VLPI
KVM: arm/arm64: GICv4: Handle CLEAR applied to a VLPI
KVM: arm/arm64: GICv4: Handle MOVALL applied to a vPE
KVM: arm/arm64: GICv4: Propagate property updates to VLPIs
KVM: arm/arm64: GICv4: Handle INVALL applied to a vPE
KVM: arm/arm64: GICv4: Propagate VLPI properties at map time
KVM: arm/arm64: GICv4: Add doorbell interrupt handling
KVM: arm/arm64: GICv4: Hook vPE scheduling into vgic flush/sync
KVM: arm/arm64: GICv4: Enable virtual cpuif if VLPIs can be delivered
KVM: arm/arm64: GICv4: Use pending_last as a scheduling hint
KVM: arm/arm64: GICv4: Enable VLPI support
arch/arm/include/asm/arch_gicv3.h | 33 +
arch/arm/kvm/Makefile | 1 +
arch/arm64/include/asm/arch_gicv3.h | 6 +
arch/arm64/kvm/Makefile | 1 +
drivers/irqchip/Makefile | 2 +-
drivers/irqchip/irq-gic-v3-its.c | 1288 +++++++++++++++++++++++++++++---
drivers/irqchip/irq-gic-v3.c | 93 ++-
drivers/irqchip/irq-gic-v4.c | 209 ++++++
include/kvm/arm_vgic.h | 19 +
include/linux/irqchip/arm-gic-common.h | 2 +
include/linux/irqchip/arm-gic-v3.h | 84 +++
include/linux/irqchip/arm-gic-v4.h | 102 +++
kernel/irq/manage.c | 14 +-
virt/kvm/arm/arm.c | 31 +-
virt/kvm/arm/hyp/vgic-v3-sr.c | 9 +-
virt/kvm/arm/vgic/vgic-init.c | 11 +-
virt/kvm/arm/vgic/vgic-its.c | 165 ++--
virt/kvm/arm/vgic/vgic-v3.c | 6 +
virt/kvm/arm/vgic/vgic-v4.c | 210 ++++++
virt/kvm/arm/vgic/vgic.c | 7 +
virt/kvm/arm/vgic/vgic.h | 10 +
21 files changed, 2103 insertions(+), 200 deletions(-)
create mode 100644 drivers/irqchip/irq-gic-v4.c
create mode 100644 include/linux/irqchip/arm-gic-v4.h
create mode 100644 virt/kvm/arm/vgic/vgic-v4.c
--
2.11.0
From: Marc Zyngier <hidden> Date: 2017-06-28 15:05:09
When assigning an interrupt to a vcpu, it is not unlikely that
the level of the hierarchy implementing irq_set_vcpu_affinity
is not the top level (think a generic MSI domain on top of a
virtualization aware interrupt controller).
In such a case, let's iterate over the hierarchy until we find
an irqchip implementing it.
Signed-off-by: Marc Zyngier <redacted>
---
kernel/irq/manage.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:05:17
Allow the pending state of an LPI to be set or cleared via
irq_set_irqchip_state.
Reviewed-by: Thomas Gleixner <redacted>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 78 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 78 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:05:26
Move the LPI property table allocation into its own function, as
this is going to be required for those associated with VMs in
the future.
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Thomas Gleixner <redacted>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)
@@ -897,15 +897,31 @@ static void its_lpi_free(struct event_lpi_map *map)kfree(map->col_map);}+staticstructpage*its_allocate_prop_table(gfp_tgfp_flags)+{+structpage*prop_page;++prop_page=alloc_pages(gfp_flags,get_order(LPI_PROPBASE_SZ));+if(!prop_page)+returnNULL;++/* Priority 0xa0, Group-1, disabled */+memset(page_address(prop_page),+LPI_PROP_DEFAULT_PRIO|LPI_PROP_GROUP1,+LPI_PROPBASE_SZ);++/* Make sure the GIC will observe the written configuration */+gic_flush_dcache_to_poc(page_address(prop_page),LPI_PROPBASE_SZ);+returnprop_page;+}staticint__initits_alloc_lpi_tables(void){phys_addr_tpaddr;-gic_rdists->prop_page=alloc_pages(GFP_NOWAIT,-get_order(LPI_PROPBASE_SZ));+gic_rdists->prop_page=its_allocate_prop_table(GFP_NOWAIT);if(!gic_rdists->prop_page){pr_err("Failed to allocate PROPBASE\n");return-ENOMEM;
@@ -914,14 +930,6 @@ static int __init its_alloc_lpi_tables(void)paddr=page_to_phys(gic_rdists->prop_page);pr_info("GIC: using LPI property table @%pa\n",&paddr);-/* Priority 0xa0, Group-1, disabled */-memset(page_address(gic_rdists->prop_page),-LPI_PROP_DEFAULT_PRIO|LPI_PROP_GROUP1,-LPI_PROPBASE_SZ);--/* Make sure the GIC will observe the written configuration */-gic_flush_dcache_to_poc(page_address(gic_rdists->prop_page),LPI_PROPBASE_SZ);-return0;}
From: Marc Zyngier <hidden> Date: 2017-06-28 15:05:29
Add the basic GICv4 VPE (vcpu in GICv4 parlance) infrastructure
(irqchip, irq domain) that is going to be populated in the following
patches.
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:05:30
When a VPE is scheduled to run, the corresponding redistributor must
be told so, by setting VPROPBASER to the VM's property table, and
VPENDBASER to the vcpu's pending table.
When scheduled out, we preserve the IDAI and PendingLast bits. The
latter is specially important, as it tells the hypervisor that
there are pending interrupts for this vcpu.
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 73 ++++++++++++++++++++++++++++++++++++++
include/linux/irqchip/arm-gic-v3.h | 58 ++++++++++++++++++++++++++++++
2 files changed, 131 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:05:34
A long time ago, GITS_CTLR[1] used to be called GITC_CTLR.EnableVLPI.
It has been subsequently deprecated and is now an "Implementation
Defined" bit that may ot may not be set for GICv4. Brilliant.
And the current crop of the FastModel requires that bit for VLPIs
to be enabled. Oh well... Let's set it and find out what breaks.
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 7 +++++--
include/linux/irqchip/arm-gic-v3.h | 1 +
2 files changed, 6 insertions(+), 2 deletions(-)
@@ -2552,7 +2552,7 @@ static int its_force_quiescent(void __iomem *base)return0;/* Disable the generation of all interrupts to this ITS */-val&=~GITS_CTLR_ENABLE;+val&=~(GITS_CTLR_ENABLE|GITS_CTLR_ImDe);writel_relaxed(val,base+GITS_CTLR);/* Poll GITS_CTLR and wait until ITS becomes quiescent */
@@ -2818,7 +2818,10 @@ static int __init its_probe_one(struct resource *res,gits_write_cwriter(0,its->base+GITS_CWRITER);ctlr=readl_relaxed(its->base+GITS_CTLR);-writel_relaxed(ctlr|GITS_CTLR_ENABLE,its->base+GITS_CTLR);+ctlr|=GITS_CTLR_ENABLE;+if(its->is_v4)+ctlr|=GITS_CTLR_ImDe;+writel_relaxed(ctlr,its->base+GITS_CTLR);err=its_init_domain(handle,its);if(err)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:05:42
When masking/unmasking a doorbell interrupt, it is necessary
to issue an invalidation to the corresponding redistributor.
We use the DirectLPI feature by writting directly to the corresponding
redistributor.
Reviewed-by: Thomas Gleixner <redacted>
Signed-off-by: Marc Zyngier <redacted>
---
arch/arm/include/asm/arch_gicv3.h | 5 +++++
arch/arm64/include/asm/arch_gicv3.h | 1 +
drivers/irqchip/irq-gic-v3-its.c | 26 +++++++++++++++++++++++++-
3 files changed, 31 insertions(+), 1 deletion(-)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:05:52
Add the required interfaces to schedule a VPE and perform a
VINVALL command.
Reviewed-by: Thomas Gleixner <redacted>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v4.c | 25 +++++++++++++++++++++++++
include/linux/irqchip/arm-gic-v4.h | 2 ++
2 files changed, 27 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:06:02
When we don't have the DirectLPI feature, we must work around the
architecture shortcomings to be able to perform the required
invalidation.
For this, we create a fake device whose sole purpose is to
provide a way to issue a map/inv/unmap sequence (and the corresponding
sync operations). That's 6 commands and a full serialization point
to be able to do this.
You just have to hope the hypervisor won't do that too often...
Reviewed-by: Thomas Gleixner <redacted>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 66 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 63 insertions(+), 3 deletions(-)
@@ -2616,6 +2655,27 @@ static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)staticintits_init_vpe_domain(void){+structits_node*its;+u32devid;++if(gic_rdists->has_direct_lpi){+pr_info("ITS: Using DirectLPI for VPE invalidation\n");+return0;+}++/* Any ITS will do, even if not v4 */+its=list_first_entry(&its_nodes,structits_node,entry);++/* Use the last possible DevID */+devid=GENMASK(its->device_ids-1,0);+vpe_proxy_dev=its_create_device(its,devid,1);+if(!vpe_proxy_dev){+pr_err("ITS: Can't allocate GICv4 proxy device\n");+return-ENODEV;+}++pr_info("ITS: Allocated DevID %x as GICv4 proxy device\n",devid);+return0;}
From: Marc Zyngier <hidden> Date: 2017-06-28 15:06:12
The way we call kvm_vgic_destroy is a bit bizarre. We call it
*after* having freed the vcpus, which sort of defeats the point
of cleaning up things before that point.
Let's move kvm_vgic_destroy towards the beginning of kvm_arch_destroy_vm,
which seems more sensible.
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/arm.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:06:22
In order to control the GICv4 view of virtual CPUs, we rely
on an irqdomain allocated for that purpose. Let's add a couple
of helpers to that effect.
At the same time, the vgic data structures gain new fields to
track all this... erm... wonderful stuff.
Signed-off-by: Marc Zyngier <redacted>
---
arch/arm/kvm/Makefile | 1 +
arch/arm64/kvm/Makefile | 1 +
include/kvm/arm_vgic.h | 11 +++++++++
virt/kvm/arm/vgic/vgic-v4.c | 59 +++++++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.h | 3 +++
5 files changed, 75 insertions(+)
create mode 100644 virt/kvm/arm/vgic/vgic-v4.c
@@ -73,6 +75,9 @@ struct vgic_global {/* Only needed for the legacy KVM_CREATE_IRQCHIP */boolcan_emulate_gicv2;+/* Does have GICv4? */+boolhas_gicv4;+/* GIC system register CPU interface */structstatic_key_falsegicv3_cpuif;
@@ -233,6 +238,9 @@ struct vgic_dist {/* used by vgic-debug */structvgic_state_iter*iter;++/* GICv4 ITS per-VM stuff */+structits_vmits_vm;};structvgic_v2_cpu_if{
From: Marc Zyngier <hidden> Date: 2017-06-28 15:06:30
As KVM needs to know about the availability of GICv4 to enable
direct injection of interrupts, let's advertise the feature in
the gic_kvm_info structure.
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3.c | 2 ++
include/linux/irqchip/arm-gic-common.h | 2 ++
2 files changed, 4 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:06:40
Handling CLEAR is pretty easy. Just ask the ITS driver to clear
the corresponding pending bit (which will turn into a CLEAR
command on the physical side).
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic-its.c | 4 ++++
1 file changed, 4 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:06:42
When freeing an LPI (on a DISCARD command, for example), we need
to unmap the VLPI down to the physical ITS level.
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic-its.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
@@ -623,8 +623,12 @@ static void its_free_ite(struct kvm *kvm, struct its_ite *ite)list_del(&ite->ite_list);/* This put matches the get in vgic_add_lpi. */-if(ite->irq)+if(ite->irq){+if(ite->irq->hw)+its_unmap_vlpi(ite->irq->host_irq);+vgic_put_irq(kvm,ite->irq);+}kfree(ite);}
From: Marc Zyngier <hidden> Date: 2017-06-28 15:06:44
The current implementation of MOVALL doesn't allow us to call
into the core ITS code as we hold a number of spinlocks.
Let's try a method used in other parts of the code, were we copy
the intids of the candicate interrupts, and then do whatever
we need to do with them outside of the critical section.
This allows us to move the interrupts one by one, at the expense
of a bit of CPU time. Who cares? MOVALL is such a stupid command
anyway...
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic-its.c | 27 ++++++++++++++++++++-------
1 file changed, 20 insertions(+), 7 deletions(-)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:06:53
Upon updating a property, we propagate it all the way to the physical
ITS, and ask for an INV command to be executed there.
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic-its.c | 3 +++
1 file changed, 3 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:07:02
When a vPE is not running, the delivery of a VLPI results in a
doorbell interrupt to be delivered. Let's handle this interrupt
and update the pending_last flag that indicates that VLPIs are
pending.
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic-v4.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:07:11
The redistributor needs to be told which vPE is about to be run,
and tells us whether there is any pending VLPI on exit.
Let's add the scheduling calls to the vgic flush/sync functions,
allowing the VLPIs to be delivered to the guest.
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic-v4.c | 23 +++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.c | 4 ++++
virt/kvm/arm/vgic/vgic.h | 1 +
3 files changed, 28 insertions(+)
@@ -733,6 +735,8 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)/* Flush our emulation state into the GIC hardware before entering the guest. */voidkvm_vgic_flush_hwstate(structkvm_vcpu*vcpu){+WARN_ON(vgic_v4_schedule(vcpu,true));+/**Iftherearenovirtualinterruptsactiveorpendingforthis*VCPU,thenthereisnoworktodoandwecanbailoutwithout
From: Marc Zyngier <hidden> Date: 2017-06-28 15:09:00
In order for VLPIs to be delivered to the guest, we must make
sure that the cpuif is always enabled, irrespective of the
presence of virtual interrupt in the LRs.
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/hyp/vgic-v3-sr.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:09:12
All it takes is for the has_v4 flag to be set in gic_kvm_info, and
we'll enable it...
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic-v3.c | 6 ++++++
1 file changed, 6 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:09:47
When a vPE exits, the pending_last flag is set when there are
pending VLPIs stored in the pending table. Similarily, we set
this flag when a doorbell interrupt fires, as it indicates the
same condition.
Let's update kvm_vgic_vcpu_pending_irq() to account for that
flag as well, making a vcpu runnable when set.
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic.c | 3 +++
1 file changed, 3 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:10:11
Should the HW support GICv4 and an ITS being associated with this
VM, let's init the its_vm and its_vpe structures.
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic-init.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:10:12
When the VLPI gets mapped, it must inherit the configuration of
LPI configured at the vITS level. FOr that purpose, let's make
update_lpi_config globally available and call it just after
having performed the VLPI map operation.
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic-its.c | 6 ++----
virt/kvm/arm/vgic/vgic-v4.c | 2 ++
virt/kvm/arm/vgic/vgic.h | 2 ++
3 files changed, 6 insertions(+), 4 deletions(-)
@@ -118,6 +118,8 @@ int kvm_vgic_v4_set_forwarding(struct kvm *kvm, int virq,irq->hw=true;irq->host_irq=virq;+/* Force the property update and invalidate */+update_lpi_config(kvm,irq,NULL,true);out:mutex_unlock(&its->its_lock);return0;
From: Marc Zyngier <hidden> Date: 2017-06-28 15:10:14
If the guest issues an INT command targetting a VLPI, let's
call into the irq_set_irqchip_state() helper to make it pending
on the physical side.
This works just as well if userspace decides to inject an interrupt
using the normal userspace API...
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic-its.c | 4 ++++
1 file changed, 4 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:10:21
Since when updating the properties one LPI at a time, there is no
need to perform an INV each time we read one. Instead, we rely
on the final VINVALL that gets sent to the ITS to do the work.
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic-its.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:11:12
When the guest issues a MOVI, we need to tell the physical ITS
that we're now targetting a new vcpu. This is done by extracting
the current mapping, updating the target, and reapplying the
mapping. The core ITS code should do the right thing.
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic-its.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:11:26
The whole MSI injection process is fairly monolithic. An MSI write
gets turned into an injected LPI in one swift go. But this is actually
a more fine-grained process:
- First, a virtual ITS gets selected using the doorbell address
- Then the DevID/EventID pair gets translated into an LPI
- Finally the LPI is injected
Since the GICv4 code needs the first two steps in order to match
an IRQ routing entry to an LPI, let's expose them as helpers,
and refactor the existing code to use them
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic-its.c | 93 +++++++++++++++++++++++++-------------------
virt/kvm/arm/vgic/vgic.h | 4 ++
2 files changed, 57 insertions(+), 40 deletions(-)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:11:36
Do a braindump of the way things are supposed to work.
Reviewed-by: Thomas Gleixner <redacted>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v4.c | 71 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 71 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:16:34
When creating a VM, it is very convenient to have an irq domain
containing all the doorbell interrupts associated with that VM
(each interrupt representing a VPE).
Reviewed-by: Thomas Gleixner <redacted>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v4.c | 58 ++++++++++++++++++++++++++++++++++++++
include/linux/irqchip/arm-gic-v4.h | 3 ++
2 files changed, 61 insertions(+)
create mode 100644 drivers/irqchip/irq-gic-v4.c
From: Marc Zyngier <hidden> Date: 2017-06-28 15:16:56
When a guest issues a INVALL command targetting a collection, it must
be translated into a VINVALL for the VPE that has this collection.
This patch implements a hook that offers this functionallity to the
hypervisor.
Reviewed-by: Thomas Gleixner <redacted>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 4 ++++
1 file changed, 4 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:17:06
When we're about to run a vcpu, it is crucial that the redistributor
associated with the physical CPU is being told about the new residency.
This is abstracted by hijacking the irq_set_affinity method for the
doorbell interrupt associated with the VPE. It is expected that the
hypervisor will call this method before scheduling the VPE.
Reviewed-by: Thomas Gleixner <redacted>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 96 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 96 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:17:27
When a VLPI is reconfigured (enabled, disabled, change in priority),
the full configuration byte must be written, and the caches invalidated.
Also, when using the irq_mask/irq_unmask methods, it is necessary
to disable the doorbell for that particular interrupt (by mapping it
to 1023) on top of clearing the Enable bit.
Reviewed-by: Thomas Gleixner <redacted>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 73 +++++++++++++++++++++++++++++++++++++---
1 file changed, 69 insertions(+), 4 deletions(-)
@@ -852,6 +896,10 @@ static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,structits_collection*target_col;u32id=its_get_event_id(d);+/* A forwarded interrupt should use irq_set_vcpu_affinity */+if(irqd_is_forwarded_to_vcpu(d))+return-EINVAL;+/* lpi cannot be routed to a redistributor that is on a foreign node */if(its_dev->its->flags&ITS_FLAGS_WORKAROUND_CAVIUM_23144){if(its_dev->its->numa_node>=0){
@@ -1017,6 +1065,22 @@ static int its_vlpi_unmap(struct irq_data *d)returnret;}+staticintits_vlpi_prop_update(structirq_data*d,structits_cmd_info*info)+{+structits_device*its_dev=irq_data_get_irq_chip_data(d);++if(!its_dev->event_map.vm||!irqd_is_forwarded_to_vcpu(d))+return-EINVAL;++if(info->cmd_type==PROP_UPDATE_AND_INV_VLPI)+lpi_update_config(d,0xff,info->config);+else+lpi_write_config(d,0xff,info->config);+its_vlpi_set_doorbell(d,!!(info->config&LPI_PROP_ENABLED));++return0;+}+staticintits_irq_set_vcpu_affinity(structirq_data*d,void*vcpu_info){structits_device*its_dev=irq_data_get_irq_chip_data(d);
From: Marc Zyngier <hidden> Date: 2017-06-28 15:17:35
When creating a VM, the low level GICv4 code is responsible for:
- allocating each VPE a unique VPEID
- allocating a doorbell interrupt for each VPE
- allocating the pending tables for each VPE
- allocating the property table for the VM
This of course has to be reversed when the VM is brought down.
All of this is wired into the irq domain alloc/free methods.
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 169 +++++++++++++++++++++++++++++++++++++++
1 file changed, 169 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:17:45
V{PEND,PROP}BASER being 64bit registers, they need some ad-hoc
accessors on 32bit, specially given that VPENDBASER contains
a Valid bit, making the access a bit convoluted.
Reviewed-by: Thomas Gleixner <redacted>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <redacted>
---
arch/arm/include/asm/arch_gicv3.h | 28 ++++++++++++++++++++++++++++
arch/arm64/include/asm/arch_gicv3.h | 5 +++++
include/linux/irqchip/arm-gic-v3.h | 5 +++++
3 files changed, 38 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:17:54
On activation, a VPE is mapped using the VMAPP command, followed
by a VINVALL for a good measure. On deactivation, the VPE is
simply unmapped.
Reviewed-by: Thomas Gleixner <redacted>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 102 +++++++++++++++++++++++++++++++++++++++
1 file changed, 102 insertions(+)
@@ -2194,9 +2275,30 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virqreturnerr;}+staticvoidits_vpe_irq_domain_activate(structirq_domain*domain,+structirq_data*d)+{+structits_vpe*vpe=irq_data_get_irq_chip_data(d);++/* Map the VPE to the first possible CPU */+vpe->col_idx=cpumask_first(cpu_online_mask);+its_send_vmapp(vpe,true);+its_send_vinvall(vpe);+}++staticvoidits_vpe_irq_domain_deactivate(structirq_domain*domain,+structirq_data*d)+{+structits_vpe*vpe=irq_data_get_irq_chip_data(d);++its_send_vmapp(vpe,false);+}+staticconststructirq_domain_opsits_vpe_domain_ops={.alloc=its_vpe_irq_domain_alloc,.free=its_vpe_irq_domain_free,+.activate=its_vpe_irq_domain_activate,+.deactivate=its_vpe_irq_domain_deactivate,};staticintits_force_quiescent(void__iomem*base)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:18:20
In order to let a VLPI being injected into a guest, the VLPI must
be mapped using the VMAPTI command. When moved to a different vcpu,
it must be moved with the VMOVI command.
These commands are issued via the irq_set_vcpu_affinity method,
making sure we unmap the corresponding host LPI first.
The reverse is also done when the VLPI is unmapped from the guest.
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 250 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 247 insertions(+), 3 deletions(-)
@@ -780,19 +907,135 @@ static int its_irq_set_irqchip_state(struct irq_data *d,return0;}+staticintits_vlpi_map(structirq_data*d,structits_cmd_info*info)+{+structits_device*its_dev=irq_data_get_irq_chip_data(d);+u32event=its_get_event_id(d);+intret=0;++if(!info->map)+return-EINVAL;++mutex_lock(&its_dev->event_map.vlpi_lock);++if(!its_dev->event_map.vm){+structits_vlpi_map*maps;++maps=kzalloc(sizeof(*maps)*its_dev->event_map.nr_lpis,+GFP_KERNEL);+if(!maps){+ret=-ENOMEM;+gotoout;+}++its_dev->event_map.vm=info->map->vm;+its_dev->event_map.vlpi_maps=maps;+}elseif(its_dev->event_map.vm!=info->map->vm){+ret=-EINVAL;+gotoout;+}++/* Get our private copy of the mapping information */+its_dev->event_map.vlpi_maps[event]=*info->map;++if(irqd_is_forwarded_to_vcpu(d)){+/* Already mapped, move it around */+its_send_vmovi(its_dev,event);+}else{+/* Drop the physical mapping */+its_send_discard(its_dev,event);++/* and install the virtual one */+its_send_vmapti(its_dev,event);+irqd_set_forwarded_to_vcpu(d);++/* Increment the number of VLPIs */+its_dev->event_map.nr_vlpis++;+}++out:+mutex_unlock(&its_dev->event_map.vlpi_lock);+returnret;+}++staticintits_vlpi_get(structirq_data*d,structits_cmd_info*info)+{+structits_device*its_dev=irq_data_get_irq_chip_data(d);+u32event=its_get_event_id(d);+intret=0;++mutex_lock(&its_dev->event_map.vlpi_lock);++if(!its_dev->event_map.vm||+!its_dev->event_map.vlpi_maps[event].vm){+ret=-EINVAL;+gotoout;+}++/* Copy our mapping information to the incoming request */+*info->map=its_dev->event_map.vlpi_maps[event];++out:+mutex_unlock(&its_dev->event_map.vlpi_lock);+returnret;+}++staticintits_vlpi_unmap(structirq_data*d)+{+structits_device*its_dev=irq_data_get_irq_chip_data(d);+u32event=its_get_event_id(d);+intret=0;++mutex_lock(&its_dev->event_map.vlpi_lock);++if(!its_dev->event_map.vm||!irqd_is_forwarded_to_vcpu(d)){+ret=-EINVAL;+gotoout;+}++/* Drop the virtual mapping */+its_send_discard(its_dev,event);++/* and restore the physical one */+irqd_clr_forwarded_to_vcpu(d);+its_send_mapti(its_dev,d->hwirq,event);+lpi_update_config(d,0xff,(LPI_PROP_DEFAULT_PRIO|+LPI_PROP_ENABLED|+LPI_PROP_GROUP1));++/*+*Droptherefcountandmakethedeviceavailableagainif+*thiswasthelastVLPI.+*/+if(!--its_dev->event_map.nr_vlpis){+its_dev->event_map.vm=NULL;+kfree(its_dev->event_map.vlpi_maps);+}++out:+mutex_unlock(&its_dev->event_map.vlpi_lock);+returnret;+}+staticintits_irq_set_vcpu_affinity(structirq_data*d,void*vcpu_info){structits_device*its_dev=irq_data_get_irq_chip_data(d);structits_cmd_info*info=vcpu_info;/* Need a v4 ITS */-if(!its_dev->its->is_v4||!info)+if(!its_dev->its->is_v4)return-EINVAL;+/* Unmap request? */+if(!info)+returnits_vlpi_unmap(d);+switch(info->cmd_type){caseMAP_VLPI:+returnits_vlpi_map(d,info);caseGET_VLPI:+returnits_vlpi_get(d,info);casePROP_UPDATE_VLPI:casePROP_UPDATE_AND_INV_VLPI:
From: Marc Zyngier <hidden> Date: 2017-06-28 15:18:24
Add the skeleton irq_set_vcpu_affinity method that will be used
to configure VLPIs.
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
@@ -779,6 +780,28 @@ static int its_irq_set_irqchip_state(struct irq_data *d,return0;}+staticintits_irq_set_vcpu_affinity(structirq_data*d,void*vcpu_info)+{+structits_device*its_dev=irq_data_get_irq_chip_data(d);+structits_cmd_info*info=vcpu_info;++/* Need a v4 ITS */+if(!its_dev->its->is_v4||!info)+return-EINVAL;++switch(info->cmd_type){+caseMAP_VLPI:++caseGET_VLPI:++casePROP_UPDATE_VLPI:+casePROP_UPDATE_AND_INV_VLPI:++default:+return-EINVAL;+}+}+staticstructirq_chipits_irq_chip={.name="ITS",.irq_mask=its_mask_irq,
From: Marc Zyngier <hidden> Date: 2017-06-28 15:18:32
Add the new GICv4 ITS command definitions, most of them, being
defined in terms of their physical counterparts.
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Thomas Gleixner <redacted>
Signed-off-by: Marc Zyngier <redacted>
---
include/linux/irqchip/arm-gic-v3.h | 12 ++++++++++++
1 file changed, 12 insertions(+)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:19:00
We're are going to need to change a bit more than just the enable
bit in the LPI property table in the future. So let's change the
LPI configuration funtion to take a set of bits to be cleared,
and a set of bits to be set.
This way, we'll be able to use it when a guest updates an LPI
property (priority, for example).
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Thomas Gleixner <redacted>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:19:09
The VCPU tables can be quite sparse as well, and it makes sense
to use indirect tables as well if possible.
Reviewed-by: Thomas Gleixner <redacted>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:19:21
Add a bunch of GICv4-specific data structures that will get used in
subsequent patches.
Reviewed-by: Thomas Gleixner <redacted>
Signed-off-by: Marc Zyngier <redacted>
---
include/linux/irqchip/arm-gic-v4.h | 91 ++++++++++++++++++++++++++++++++++++++
1 file changed, 91 insertions(+)
create mode 100644 include/linux/irqchip/arm-gic-v4.h
From: Marc Zyngier <hidden> Date: 2017-06-28 15:19:30
As we want to use 2-level tables for VCPUs, let's hack the device
table allocator in order to make it slightly more generic. It
will get reused in subsequent patches.
Reviewed-by: Thomas Gleixner <redacted>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 26 ++++++++++++++++----------
1 file changed, 16 insertions(+), 10 deletions(-)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:19:46
Rework LPI deallocation so that it can be reused by the v4 support
code.
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Thomas Gleixner <redacted>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
@@ -873,16 +873,15 @@ static unsigned long *its_lpi_alloc_chunks(int nr_irqs, int *base, int *nr_ids)returnbitmap;}-staticvoidits_lpi_free(structevent_lpi_map*map)+staticvoidits_lpi_free_chunks(unsignedlong*bitmap,intbase,intnr_ids){-intbase=map->lpi_base;-intnr_ids=map->nr_lpis;intlpi;spin_lock(&lpi_lock);for(lpi=base;lpi<(base+nr_ids);lpi+=IRQS_PER_CHUNK){intchunk=its_lpi_to_chunk(lpi);+BUG_ON(chunk>lpi_chunks);if(test_bit(chunk,lpi_bitmap)){clear_bit(chunk,lpi_bitmap);
@@ -1665,7 +1663,10 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,/* If all interrupts have been freed, start mopping the floor */if(bitmap_empty(its_dev->event_map.lpi_map,its_dev->event_map.nr_lpis)){-its_lpi_free(&its_dev->event_map);+its_lpi_free_chunks(its_dev->event_map.lpi_map,+its_dev->event_map.lpi_base,+its_dev->event_map.nr_lpis);+kfree(its_dev->event_map.col_map);/* Unmap device/itt */its_send_mapd(its_dev,0);
From: Marc Zyngier <hidden> Date: 2017-06-28 15:20:17
Just as for the property table, let's move the pending table
allocation to a separate function.
Reviewed-by: Thomas Gleixner <redacted>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)
@@ -1199,6 +1199,24 @@ static int its_alloc_collections(struct its_node *its)return0;}+staticstructpage*its_allocate_pending_table(gfp_tgfp_flags)+{+structpage*pend_page;+/*+*Thependingpageshavetobeatleast64kBaligned,+*hencethe'max(LPI_PENDBASE_SZ,SZ_64K)'below.+*/+pend_page=alloc_pages(gfp_flags|__GFP_ZERO,+get_order(max(LPI_PENDBASE_SZ,SZ_64K)));+if(!pend_page)+returnNULL;++/* Make sure the GIC will observe the zero-ed page */+gic_flush_dcache_to_poc(page_address(pend_page),LPI_PENDBASE_SZ);++returnpend_page;+}+staticvoidits_cpu_init_lpis(void){void__iomem*rbase=gic_data_rdist_rd_base();
@@ -1209,21 +1227,14 @@ static void its_cpu_init_lpis(void)pend_page=gic_data_rdist()->pend_page;if(!pend_page){phys_addr_tpaddr;-/*-*Thependingpageshavetobeatleast64kBaligned,-*hencethe'max(LPI_PENDBASE_SZ,SZ_64K)'below.-*/-pend_page=alloc_pages(GFP_NOWAIT|__GFP_ZERO,-get_order(max(LPI_PENDBASE_SZ,SZ_64K)));++pend_page=its_allocate_pending_table(GFP_NOWAIT);if(!pend_page){pr_err("Failed to allocate PENDBASE for CPU%d\n",smp_processor_id());return;}-/* Make sure the GIC will observe the zero-ed page */-gic_flush_dcache_to_poc(page_address(pend_page),LPI_PENDBASE_SZ);-paddr=page_to_phys(pend_page);pr_info("CPU%d: using LPI pending table @%pa\n",smp_processor_id(),&paddr);
From: Marc Zyngier <hidden> Date: 2017-06-28 15:20:20
Most ITS commands do operate on a collection object, and require
a SYNC command to be performed on that collection in order to
guarantee the execution of the first command.
With GICv4 ITS, another set of commands perform similar operations
on a VPE object, and a VSYNC operations must be executed to guarantee
their execution.
Given the similarities (post a command, perform a synchronization
operation on a sync object), it makes sense to reuse the same
mechanism for both class of commands.
Let's start with turning its_send_single_command into a huge macro
that performs the bulk of the work, and a set of helpers that
make this macro usable for the GICv3 ITS commands.
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 84 ++++++++++++++++++++++------------------
1 file changed, 47 insertions(+), 37 deletions(-)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:20:23
Add the probing code for the ITS VLPI support. This includes
configuring the ITS number if not supporting the single VMOVP
command feature.
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 68 +++++++++++++++++++++++++++++++++++---
include/linux/irqchip/arm-gic-v3.h | 5 +++
2 files changed, 69 insertions(+), 4 deletions(-)
@@ -1673,13 +1682,51 @@ static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)return0;}+staticint__initits_compute_its_list_map(structresource*res,+void__iomem*its_base)+{+intits_number;+u32ctlr;++/*+*Thisisassumedtobedoneearlyenoughthatwe're+*guaranteedtobesingle-threaded,henceno+*locking.Shouldthischange,weshouldaddress+*this.+*/+its_number=find_first_zero_bit(&its_list_map,ITS_LIST_MAX);+if(its_number>=ITS_LIST_MAX){+pr_err("ITS@%pa: No ITSList entry available!\n",+&res->start);+return-EINVAL;+}++ctlr=readl_relaxed(its_base+GITS_CTLR);+ctlr&=~GITS_CTLR_ITS_NUMBER;+ctlr|=its_number<<GITS_CTLR_ITS_NUMBER_SHIFT;+writel_relaxed(ctlr,its_base+GITS_CTLR);+ctlr=readl_relaxed(its_base+GITS_CTLR);+if((ctlr&GITS_CTLR_ITS_NUMBER)!=(its_number<<GITS_CTLR_ITS_NUMBER_SHIFT)){+its_number=ctlr&GITS_CTLR_ITS_NUMBER;+its_number>>=GITS_CTLR_ITS_NUMBER_SHIFT;+}++if(test_and_set_bit(its_number,&its_list_map)){+pr_err("ITS@%pa: Duplicate ITSList entry %d\n",+&res->start,its_number);+return-EINVAL;+}++returnits_number;+}+staticint__initits_probe_one(structresource*res,structfwnode_handle*handle,intnuma_node){structits_node*its;void__iomem*its_base;-u32val;-u64baser,tmp;+u32val,ctlr;+u64baser,tmp,typer;interr;its_base=ioremap(res->start,resource_size(res));
@@ -1712,9 +1759,21 @@ static int __init its_probe_one(struct resource *res,raw_spin_lock_init(&its->lock);INIT_LIST_HEAD(&its->entry);INIT_LIST_HEAD(&its->its_device_list);+typer=gic_read_typer(its_base+GITS_TYPER);its->base=its_base;its->phys_base=res->start;-its->ite_size=((gic_read_typer(its_base+GITS_TYPER)>>4)&0xf)+1;+its->ite_size=GITS_TYPER_ITT_ENTRY_SIZE(typer);+its->is_v4=!!(typer&GITS_TYPER_VLPIS);+if(its->is_v4&&!(typer&GITS_TYPER_VMOVP)){+err=its_compute_its_list_map(res,its_base);+if(err<0)+gotoout_free_its;++pr_info("ITS@%pa: Using ITS number %d\n",&res->start,err);+}else{+pr_info("ITS@%pa: Single VMOVP capable\n",&res->start);+}+its->numa_node=numa_node;its->cmd_base=(void*)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
@@ -1761,7 +1820,8 @@ static int __init its_probe_one(struct resource *res,}gits_write_cwriter(0,its->base+GITS_CWRITER);-writel_relaxed(GITS_CTLR_ENABLE,its->base+GITS_CTLR);+ctlr=readl_relaxed(its->base+GITS_CTLR);+writel_relaxed(ctlr|GITS_CTLR_ENABLE,its->base+GITS_CTLR);err=its_init_domain(handle,its);if(err)
From: Marc Zyngier <hidden> Date: 2017-06-28 15:20:32
In order to discover the VLPI properties, we need to iterate over
the redistributor regions. As we already have code that does this,
let's factor it out and make it slightly more generic.
Reviewed-by: Thomas Gleixner <redacted>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3.c | 69 ++++++++++++++++++++++++++++++--------------
1 file changed, 47 insertions(+), 22 deletions(-)
@@ -450,15 +440,9 @@ static int gic_populate_rdist(void)do{typer=gic_read_typer(ptr+GICR_TYPER);-if((typer>>32)==aff){-u64offset=ptr-gic_data.redist_regions[i].redist_base;-gic_data_rdist_rd_base()=ptr;-gic_data_rdist()->phys_base=gic_data.redist_regions[i].phys_base+offset;-pr_info("CPU%d: found redistributor %lx region %d:%pa\n",-smp_processor_id(),mpidr,i,-&gic_data_rdist()->phys_base);+ret=fn(gic_data.redist_regions+i,ptr);+if(!ret)return0;-}if(gic_data.redist_regions[i].single_redist)break;
@@ -473,9 +457,50 @@ static int gic_populate_rdist(void)}while(!(typer&GICR_TYPER_LAST));}+returnret?-ENODEV:0;+}++staticint__gic_populate_rdist(structredist_region*region,void__iomem*ptr)+{+unsignedlongmpidr=cpu_logical_map(smp_processor_id());+u64typer;+u32aff;++/*+*Convertaffinitytoa32bitvaluethatcanbematchedto+*GICR_TYPERbits[63:32].+*/+aff=(MPIDR_AFFINITY_LEVEL(mpidr,3)<<24|+MPIDR_AFFINITY_LEVEL(mpidr,2)<<16|+MPIDR_AFFINITY_LEVEL(mpidr,1)<<8|+MPIDR_AFFINITY_LEVEL(mpidr,0));++typer=gic_read_typer(ptr+GICR_TYPER);+if((typer>>32)==aff){+u64offset=ptr-region->redist_base;+gic_data_rdist_rd_base()=ptr;+gic_data_rdist()->phys_base=region->phys_base+offset;++pr_info("CPU%d: found redistributor %lx region %d:%pa\n",+smp_processor_id(),mpidr,+(int)(region-gic_data.redist_regions),+&gic_data_rdist()->phys_base);+return0;+}++/* Try next one */+return1;+}++staticintgic_populate_rdist(void)+{+if(gic_iterate_rdists(__gic_populate_rdist)==0)+return0;+/* We couldn't even deal with ourselves... */WARN(true,"CPU%d: mpidr %lx has no re-distributor!\n",-smp_processor_id(),mpidr);+smp_processor_id(),+(unsignedlong)cpu_logical_map(smp_processor_id()));return-ENODEV;}
From: Marc Zyngier <hidden> Date: 2017-06-28 15:20:40
The various LPI definitions are in the middle of the code, and
would be better placed at the beginning, given that we're going
to use some of them much earlier.
Reviewed-by: Thomas Gleixner <redacted>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <redacted>
---
drivers/irqchip/irq-gic-v3-its.c | 27 +++++++++++++++------------
1 file changed, 15 insertions(+), 12 deletions(-)
Hi Marc,
I've verified the basic GICv4 functionality with v2 series + Eric's IRQ
bypass patches on QDF2400 platform with a minor change in vgic-init.c
successfully. Nice, I don't see any deadlock or catastrophic issues
running on QCOM hardware. You can add my tested-by, I'll provide comments
after reviewing giant v2 series.
Tested-by: Shanker Donthineni <redacted>
-----Original Message-----
From: linux-arm-kernel [mailto:linux-arm-kernel-bounces at lists.infradead.org]
On Behalf Of Marc Zyngier
Sent: Wednesday, June 28, 2017 10:03 AM
To: linux-kernel at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
kvmarm at lists.cs.columbia.edu
Cc: Mark Rutland <mark.rutland@arm.com>; Jason Cooper
[off-list ref]; Eric Auger [off-list ref]; Christoffer Dall
[off-list ref]; Thomas Gleixner [off-list ref]; Shanker
Donthineni [off-list ref]
Subject: [PATCH v2 00/52] irqchip: KVM: Add support for GICv4
Yes, it's been a long time coming, but I really wasn't looking forward to
picking this up again. Anyway...
This (monster of a) series implements full support for GICv4, bringing
direct injection of MSIs to KVM on arm and arm64, assuming you have the
right hardware (which is quite unlikely).
To get an idea of the design, I'd recommend you start with patch #32, which
tries to shed some light on the approach that I've taken. And before that,
please digest some of the GICv3/GICv4 architecture documentation[1] (less
than 800 pages!). Once you feel reasonably insane, you'll be in the right
mood to read the code.
The structure of the series is fairly simple. The initial 34 patches add
some generic support for GICv4, while the rest of the code plugs KVM into
it. This series relies on Eric Auger's irq-bypass series[2], which is a
prerequisite for this work.
The stack has been *very lightly* tested on an arm64 model, with a PCI
virtio block device passed from the host to a guest (using kvmtool and
Jean-Philippe Brucker's excellent VFIO support patches[3]). As it has never
seen any HW, I expect things to be subtly broken, so go forward and test if
you can, though I'm mostly interested in people reviewing the code at the
moment.
I've pushed out a branch based on 4.12-rc6 containing the dependencies (as
well as a couple of debug patches):
git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git
kvm-arm64/gicv4-kvm
* From v1:
- The bulk of the 30-something initial patches have seen countless
bugs being fixed, and some key data structures have been subtly
tweaked (or killed altogether). They are still quite similar to
what I had in v1 though.
- The whole KVM code is brand new and as I said above, only lightly
tested.
- Collected a bunch a R-bs from Thomas and Eric (many thanks, guys).
[1]
https://static.docs.arm.com/ihi0069/c/IHI0069C_gic_architecture_specificatio
n.pdf
[2] http://www.spinics.net/lists/kvm/msg151463.html
[3] http://www.spinics.net/lists/kvm/msg151823.html
Marc Zyngier (52):
genirq: Let irq_set_vcpu_affinity() iterate over hierarchy
irqchip/gic-v3: Add redistributor iterator
irqchip/gic-v3: Add VLPI/DirectLPI discovery
irqchip/gic-v3-its: Move LPI definitions around
irqchip/gic-v3-its: Add probing for VLPI properties
irqchip/gic-v3-its: Macro-ize its_send_single_command
irqchip/gic-v3-its: Implement irq_set_irqchip_state for pending state
irqchip/gic-v3-its: Split out property table allocation
irqchip/gic-v3-its: Allow use of indirect VCPU tables
irqchip/gic-v3-its: Split out pending table allocation
irqchip/gic-v3-its: Rework LPI freeing
irqchip/gic-v3-its: Generalize device table allocation
irqchip/gic-v3-its: Generalize LPI configuration
irqchip/gic-v4: Add management structure definitions
irqchip/gic-v3-its: Add GICv4 ITS command definitions
irqchip/gic-v3-its: Add VLPI configuration hook
irqchip/gic-v3-its: Add VLPI map/unmap operations
irqchip/gic-v3-its: Add VLPI configuration handling
irqchip/gic-v3-its: Add VPE domain infrastructure
irqchip/gic-v3-its: Add VPE irq domain allocation/teardown
irqchip/gic-v3-its: Add VPE irq domain [de]activation
irqchip/gic-v3-its: Add VPENDBASER/VPROPBASER accessors
irqchip/gic-v3-its: Add VPE scheduling
irqchip/gic-v3-its: Add VPE invalidation hook
irqchip/gic-v3-its: Add VPE affinity changes
irqchip/gic-v3-its: Add VPE interrupt masking
irqchip/gic-v3-its: Support VPE doorbell invalidation even when
!DirectLPI
irqchip/gic-v3-its: Set implementation defined bit to enable VLPIs
irqchip/gic-v4: Add per-VM VPE domain creation
irqchip/gic-v4: Add VPE command interface
irqchip/gic-v4: Add VLPI configuration interface
irqchip/gic-v4: Add some basic documentation
irqchip/gic-v4: Enable low-level GICv4 operations
irqchip/gic-v3: Advertise GICv4 support to KVM
KVM: arm/arm64: vgic: Move kvm_vgic_destroy call around
KVM: arm/arm64: vITS: Add MSI translation helpers
KVM: arm/arm64: GICv4: Add init and teardown of the vPE irq domain
KVM: arm/arm64: GICv4: Wire init/teardown of per-VM support
KVM: arm/arm64: GICv4: Wire mapping/unmapping of VLPIs in VFIO irq
bypass
KVM: arm/arm64: GICv4: Handle INT command applied to a VLPI
KVM: arm/arm64: GICv4: Unmap VLPI when freeing an LPI
KVM: arm/arm64: GICv4: Handle MOVI applied to a VLPI
KVM: arm/arm64: GICv4: Handle CLEAR applied to a VLPI
KVM: arm/arm64: GICv4: Handle MOVALL applied to a vPE
KVM: arm/arm64: GICv4: Propagate property updates to VLPIs
KVM: arm/arm64: GICv4: Handle INVALL applied to a vPE
KVM: arm/arm64: GICv4: Propagate VLPI properties at map time
KVM: arm/arm64: GICv4: Add doorbell interrupt handling
KVM: arm/arm64: GICv4: Hook vPE scheduling into vgic flush/sync
KVM: arm/arm64: GICv4: Enable virtual cpuif if VLPIs can be delivered
KVM: arm/arm64: GICv4: Use pending_last as a scheduling hint
KVM: arm/arm64: GICv4: Enable VLPI support
arch/arm/include/asm/arch_gicv3.h | 33 +
arch/arm/kvm/Makefile | 1 +
arch/arm64/include/asm/arch_gicv3.h | 6 +
arch/arm64/kvm/Makefile | 1 +
drivers/irqchip/Makefile | 2 +-
drivers/irqchip/irq-gic-v3-its.c | 1288
+++++++++++++++++++++++++++++---
drivers/irqchip/irq-gic-v3.c | 93 ++-
drivers/irqchip/irq-gic-v4.c | 209 ++++++
include/kvm/arm_vgic.h | 19 +
include/linux/irqchip/arm-gic-common.h | 2 +
include/linux/irqchip/arm-gic-v3.h | 84 +++
include/linux/irqchip/arm-gic-v4.h | 102 +++
kernel/irq/manage.c | 14 +-
virt/kvm/arm/arm.c | 31 +-
virt/kvm/arm/hyp/vgic-v3-sr.c | 9 +-
virt/kvm/arm/vgic/vgic-init.c | 11 +-
virt/kvm/arm/vgic/vgic-its.c | 165 ++--
virt/kvm/arm/vgic/vgic-v3.c | 6 +
virt/kvm/arm/vgic/vgic-v4.c | 210 ++++++
virt/kvm/arm/vgic/vgic.c | 7 +
virt/kvm/arm/vgic/vgic.h | 10 +
21 files changed, 2103 insertions(+), 200 deletions(-) create mode 100644
drivers/irqchip/irq-gic-v4.c create mode 100644
include/linux/irqchip/arm-gic-v4.h
create mode 100644 virt/kvm/arm/vgic/vgic-v4.c
--
2.11.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Thomas Gleixner <hidden> Date: 2017-07-04 21:15:56
On Wed, 28 Jun 2017, Marc Zyngier wrote:
When assigning an interrupt to a vcpu, it is not unlikely that
the level of the hierarchy implementing irq_set_vcpu_affinity
is not the top level (think a generic MSI domain on top of a
virtualization aware interrupt controller).
In such a case, let's iterate over the hierarchy until we find
an irqchip implementing it.
Signed-off-by: Marc Zyngier <redacted>
Hi Marc,
On 06/28/2017 10:03 AM, Marc Zyngier wrote:
quoted hunk
Should the HW support GICv4 and an ITS being associated with this
VM, let's init the its_vm and its_vpe structures.
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic-init.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
@@ -285,8 +285,14 @@ int vgic_init(struct kvm *kvm)if(ret)gotoout;-if(vgic_has_its(kvm))+if(vgic_has_its(kvm)){dist->msis_require_devid=true;+if(kvm_vgic_global_state.has_gicv4){+ret=vgic_v4_init(kvm);+if(ret)+gotoout;+}
This is not quite right, ITS virtual device may not be initialized at the time of
calling vgic-init(). This change breaks the existing KVM functionality with QEMU
hypervisor tool. In later patches, code assumes vgic_v4_init(kvm) was called when
vgic_has_its(kvm) returns a true value.
The right change would be move this logic to inside vgic_its_create() something like this.
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -285,14 +285,8 @@ int vgic_init(struct kvm *kvm)
if (ret)
goto out;
- if (vgic_has_its(kvm)) {
+ if (vgic_has_its(kvm))
dist->msis_require_devid = true;
- if (kvm_vgic_global_state.has_gicv4) {
- ret = vgic_v4_init(kvm);
- if (ret)
- goto out;
- }
- }
kvm_for_each_vcpu(i, vcpu, kvm)
kvm_vgic_vcpu_enable(vcpu);
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -1637,6 +1637,7 @@ static int vgic_register_its_iodev(struct kvm *kvm, struct
static int vgic_its_create(struct kvm_device *dev, u32 type)
{
struct vgic_its *its;
+ int ret;
if (type != KVM_DEV_TYPE_ARM_VGIC_ITS)
return -ENODEV;
@@ -1657,6 +1658,12 @@ static int vgic_its_create(struct kvm_device *dev, u32 ty
its->enabled = false;
its->dev = dev;
+ if (kvm_vgic_global_state.has_gicv4) {
+ ret = vgic_v4_init(dev->kvm);
+ if (ret)
+ return -ENOMEM;
+ }
+
--
Shanker Donthineni
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
From: Marc Zyngier <hidden> Date: 2017-07-10 16:34:35
On 08/07/17 12:26, Shanker Donthineni wrote:
Hi Marc,
On 06/28/2017 10:03 AM, Marc Zyngier wrote:
quoted
Should the HW support GICv4 and an ITS being associated with this
VM, let's init the its_vm and its_vpe structures.
Signed-off-by: Marc Zyngier <redacted>
---
virt/kvm/arm/vgic/vgic-init.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
@@ -285,8 +285,14 @@ int vgic_init(struct kvm *kvm)if(ret)gotoout;-if(vgic_has_its(kvm))+if(vgic_has_its(kvm)){dist->msis_require_devid=true;+if(kvm_vgic_global_state.has_gicv4){+ret=vgic_v4_init(kvm);+if(ret)+gotoout;+}
This is not quite right, ITS virtual device may not be initialized at the time of
calling vgic-init(). This change breaks the existing KVM functionality with QEMU
hypervisor tool. In later patches, code assumes vgic_v4_init(kvm) was called when
vgic_has_its(kvm) returns a true value.
The right change would be move this logic to inside vgic_its_create() something like this.
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -285,14 +285,8 @@ int vgic_init(struct kvm *kvm)
if (ret)
goto out;
- if (vgic_has_its(kvm)) {
+ if (vgic_has_its(kvm))
dist->msis_require_devid = true;
- if (kvm_vgic_global_state.has_gicv4) {
- ret = vgic_v4_init(kvm);
- if (ret)
- goto out;
- }
- }
kvm_for_each_vcpu(i, vcpu, kvm)
kvm_vgic_vcpu_enable(vcpu);
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -1637,6 +1637,7 @@ static int vgic_register_its_iodev(struct kvm *kvm, struct
static int vgic_its_create(struct kvm_device *dev, u32 type)
{
struct vgic_its *its;
+ int ret;
if (type != KVM_DEV_TYPE_ARM_VGIC_ITS)
return -ENODEV;
@@ -1657,6 +1658,12 @@ static int vgic_its_create(struct kvm_device *dev, u32 ty
its->enabled = false;
its->dev = dev;
+ if (kvm_vgic_global_state.has_gicv4) {
+ ret = vgic_v4_init(dev->kvm);
+ if (ret)
+ return -ENOMEM;
+ }
+
This approach is pretty busted if you have more than a single virtual
ITS, as you now leak memory from the VPE array and IRQ domain allocations.
Also, there is no guarantee that we've created all vcpus by the time we
create an ITS, so this approach fails as well ("create vcpu 1, create
ITS, create vcpu 2, init vgic" is a valid sequence).
I guess we need to call vgic_v4_init() on both vgic_init() and
its_create(), and only perform the GICv4 init if the vgic has already
been initialized.
Or we simply restrict the order to be vgic_init() last, and fix
userspace to respect that order. Not enabling GICv4 won't break SW. It
may even be faster.
M.
--
Jazz is not dead. It just smells funny...