All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v9 0/9] Handle forwarded level-triggered interrupts
@ 2017-12-20 11:35 ` Christoffer Dall
  0 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:35 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Marc Zyngier, Andre Przywara, Eric Auger, Christoffer Dall

This series is an alternative approach to Eric Auger's direct EOI setup
patches [1] in terms of the KVM VGIC support.

The idea is to maintain existing semantics for the VGIC for mapped
level-triggered IRQs and also support the timer using mapped IRQs with
the same VGIC support as VFIO interrupts.

Based on v4.15-rc3.

Also available at:
git://git.kernel.org/pub/scm/linux/kernel/git/cdall/linux.git level-mapped-v9

Changes since v8:
 - Addd kvm_timer_update_irq(vcpu, false, vtimer) call in
   unmask_vtimer_irq_user in patch 7 to fix userspace irqchip support
   with these patches.
 - Delete outdated documentation instead of erroneously attempting to
   update it.
 - Fixed weirdo commit message in patch 3
 - Attempted alternate approach in patch 8

Changes since v7:
 - Cleanup stale commentary
 - Updated documentation (patch 9/9 is new in this version)
 - Added Eric's reviewed-by tags

Changes since v6:
 - Removed double semi-colon
 - Changed another confusing conditional in patch 6
 - Fixed typos in commit message and comments

Changes since v5:
 - Rebased on v4.15-rc1
 - Changed comment on preemption code as suggested by Andre
 - Fixed white space and confusing conditionals as suggested by Drew

Changes since v4:
 - Rebased on the timer optimization series merged in the v4.15 merge
   window, which caused a fair amount of modifications to patch 3.
 - Added a static key to disable the sync operations when no VMs are
   using userspace irqchips to further optimize the performance
 - Fixed extra semicolon in vgic-mmio.c
 - Added commentary as requested during review
 - Dropped what was patch 4, because it was merged as part of GICv4
   support.
 - Factored out the VGIC input level function change as separate patch
   (helps bisect and debugging), before providing a function for the
   timer.

Changes since v3:
 - Added a number of patches and moved patches around a bit.
 - Check for uaccesses in the mmio handler functions
 - Fixed bugs in the mmio handler functions

Changes since v2:
 - Removed patch 5 from v2 and integrating the changes in what's now
   patch 5 to make it easier to reuse code when adding VFIO integration.
 - Changed the virtual distributor MMIO handling to use the
   pending_latch and more closely match the semantics of SPENDR and
   CPENDR for both level and edge mapped interrupts.

Changes since v1:
 - Added necessary changes to the timer (Patch 1)
 - Added handling of guest MMIO accesses to the virtual distributor
   (Patch 4)
 - Addressed Marc's comments from the initial RFC (mostly renames)

Thanks,
-Christoffer

[1]: https://lists.cs.columbia.edu/pipermail/kvmarm/2017-June/026072.html

Christoffer Dall (9):
  KVM: arm/arm64: Remove redundant preemptible checks
  KVM: arm/arm64: Factor out functionality to get vgic mmio
    requester_vcpu
  KVM: arm/arm64: Don't cache the timer IRQ level
  KVM: arm/arm64: vgic: Support level-triggered mapped interrupts
  KVM: arm/arm64: Support a vgic interrupt line level sample function
  KVM: arm/arm64: Support VGIC dist pend/active changes for mapped IRQs
  KVM: arm/arm64: Provide a get_input_level for the arch timer
  KVM: arm/arm64: Avoid work when userspace iqchips are not used
  KVM: arm/arm64: Delete outdated forwarded irq documentation

 Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt | 187 ---------------------
 arch/arm/include/asm/kvm_host.h                    |   2 +
 arch/arm64/include/asm/kvm_host.h                  |   2 +
 include/kvm/arm_arch_timer.h                       |   2 +
 include/kvm/arm_vgic.h                             |  13 +-
 virt/kvm/arm/arch_timer.c                          | 111 ++++++------
 virt/kvm/arm/arm.c                                 |  61 ++++---
 virt/kvm/arm/vgic/vgic-mmio.c                      | 115 ++++++++++---
 virt/kvm/arm/vgic/vgic-v2.c                        |  29 ++++
 virt/kvm/arm/vgic/vgic-v3.c                        |  29 ++++
 virt/kvm/arm/vgic/vgic.c                           |  41 ++++-
 virt/kvm/arm/vgic/vgic.h                           |   8 +
 12 files changed, 313 insertions(+), 287 deletions(-)
 delete mode 100644 Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt

-- 
2.14.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v9 0/9] Handle forwarded level-triggered interrupts
@ 2017-12-20 11:35 ` Christoffer Dall
  0 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

This series is an alternative approach to Eric Auger's direct EOI setup
patches [1] in terms of the KVM VGIC support.

The idea is to maintain existing semantics for the VGIC for mapped
level-triggered IRQs and also support the timer using mapped IRQs with
the same VGIC support as VFIO interrupts.

Based on v4.15-rc3.

Also available at:
git://git.kernel.org/pub/scm/linux/kernel/git/cdall/linux.git level-mapped-v9

Changes since v8:
 - Addd kvm_timer_update_irq(vcpu, false, vtimer) call in
   unmask_vtimer_irq_user in patch 7 to fix userspace irqchip support
   with these patches.
 - Delete outdated documentation instead of erroneously attempting to
   update it.
 - Fixed weirdo commit message in patch 3
 - Attempted alternate approach in patch 8

Changes since v7:
 - Cleanup stale commentary
 - Updated documentation (patch 9/9 is new in this version)
 - Added Eric's reviewed-by tags

Changes since v6:
 - Removed double semi-colon
 - Changed another confusing conditional in patch 6
 - Fixed typos in commit message and comments

Changes since v5:
 - Rebased on v4.15-rc1
 - Changed comment on preemption code as suggested by Andre
 - Fixed white space and confusing conditionals as suggested by Drew

Changes since v4:
 - Rebased on the timer optimization series merged in the v4.15 merge
   window, which caused a fair amount of modifications to patch 3.
 - Added a static key to disable the sync operations when no VMs are
   using userspace irqchips to further optimize the performance
 - Fixed extra semicolon in vgic-mmio.c
 - Added commentary as requested during review
 - Dropped what was patch 4, because it was merged as part of GICv4
   support.
 - Factored out the VGIC input level function change as separate patch
   (helps bisect and debugging), before providing a function for the
   timer.

Changes since v3:
 - Added a number of patches and moved patches around a bit.
 - Check for uaccesses in the mmio handler functions
 - Fixed bugs in the mmio handler functions

Changes since v2:
 - Removed patch 5 from v2 and integrating the changes in what's now
   patch 5 to make it easier to reuse code when adding VFIO integration.
 - Changed the virtual distributor MMIO handling to use the
   pending_latch and more closely match the semantics of SPENDR and
   CPENDR for both level and edge mapped interrupts.

Changes since v1:
 - Added necessary changes to the timer (Patch 1)
 - Added handling of guest MMIO accesses to the virtual distributor
   (Patch 4)
 - Addressed Marc's comments from the initial RFC (mostly renames)

Thanks,
-Christoffer

[1]: https://lists.cs.columbia.edu/pipermail/kvmarm/2017-June/026072.html

Christoffer Dall (9):
  KVM: arm/arm64: Remove redundant preemptible checks
  KVM: arm/arm64: Factor out functionality to get vgic mmio
    requester_vcpu
  KVM: arm/arm64: Don't cache the timer IRQ level
  KVM: arm/arm64: vgic: Support level-triggered mapped interrupts
  KVM: arm/arm64: Support a vgic interrupt line level sample function
  KVM: arm/arm64: Support VGIC dist pend/active changes for mapped IRQs
  KVM: arm/arm64: Provide a get_input_level for the arch timer
  KVM: arm/arm64: Avoid work when userspace iqchips are not used
  KVM: arm/arm64: Delete outdated forwarded irq documentation

 Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt | 187 ---------------------
 arch/arm/include/asm/kvm_host.h                    |   2 +
 arch/arm64/include/asm/kvm_host.h                  |   2 +
 include/kvm/arm_arch_timer.h                       |   2 +
 include/kvm/arm_vgic.h                             |  13 +-
 virt/kvm/arm/arch_timer.c                          | 111 ++++++------
 virt/kvm/arm/arm.c                                 |  61 ++++---
 virt/kvm/arm/vgic/vgic-mmio.c                      | 115 ++++++++++---
 virt/kvm/arm/vgic/vgic-v2.c                        |  29 ++++
 virt/kvm/arm/vgic/vgic-v3.c                        |  29 ++++
 virt/kvm/arm/vgic/vgic.c                           |  41 ++++-
 virt/kvm/arm/vgic/vgic.h                           |   8 +
 12 files changed, 313 insertions(+), 287 deletions(-)
 delete mode 100644 Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt

-- 
2.14.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v9 1/9] KVM: arm/arm64: Remove redundant preemptible checks
  2017-12-20 11:35 ` Christoffer Dall
@ 2017-12-20 11:35   ` Christoffer Dall
  -1 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:35 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Andre Przywara, kvm

The __this_cpu_read() and __this_cpu_write() functions already implement
checks for the required preemption levels when using
CONFIG_DEBUG_PREEMPT which gives you nice error messages and such.
Therefore there is no need to explicitly check this using a BUG_ON() in
the code (which we don't do for other uses of per cpu variables either).

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 virt/kvm/arm/arm.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 6b60c98a6e22..3610e132df8b 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -71,7 +71,6 @@ static DEFINE_PER_CPU(unsigned char, kvm_arm_hardware_enabled);
 
 static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
 {
-	BUG_ON(preemptible());
 	__this_cpu_write(kvm_arm_running_vcpu, vcpu);
 }
 
@@ -81,7 +80,6 @@ static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
  */
 struct kvm_vcpu *kvm_arm_get_running_vcpu(void)
 {
-	BUG_ON(preemptible());
 	return __this_cpu_read(kvm_arm_running_vcpu);
 }
 
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 1/9] KVM: arm/arm64: Remove redundant preemptible checks
@ 2017-12-20 11:35   ` Christoffer Dall
  0 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

The __this_cpu_read() and __this_cpu_write() functions already implement
checks for the required preemption levels when using
CONFIG_DEBUG_PREEMPT which gives you nice error messages and such.
Therefore there is no need to explicitly check this using a BUG_ON() in
the code (which we don't do for other uses of per cpu variables either).

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 virt/kvm/arm/arm.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 6b60c98a6e22..3610e132df8b 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -71,7 +71,6 @@ static DEFINE_PER_CPU(unsigned char, kvm_arm_hardware_enabled);
 
 static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
 {
-	BUG_ON(preemptible());
 	__this_cpu_write(kvm_arm_running_vcpu, vcpu);
 }
 
@@ -81,7 +80,6 @@ static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
  */
 struct kvm_vcpu *kvm_arm_get_running_vcpu(void)
 {
-	BUG_ON(preemptible());
 	return __this_cpu_read(kvm_arm_running_vcpu);
 }
 
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 2/9] KVM: arm/arm64: Factor out functionality to get vgic mmio requester_vcpu
  2017-12-20 11:35 ` Christoffer Dall
@ 2017-12-20 11:35   ` Christoffer Dall
  -1 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:35 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Andre Przywara, kvm

We are about to distinguish between userspace accesses and mmio traps
for a number of the mmio handlers.  When the requester vcpu is NULL, it
means we are handling a userspace access.

Factor out the functionality to get the request vcpu into its own
function, mostly so we have a common place to document the semantics of
the return value.

Also take the chance to move the functionality outside of holding a
spinlock and instead explicitly disable and enable preemption.  This
supports PREEMPT_RT kernels as well.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 virt/kvm/arm/vgic/vgic-mmio.c | 44 +++++++++++++++++++++++++++----------------
 1 file changed, 28 insertions(+), 16 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index deb51ee16a3d..fdad95f62fa3 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -122,6 +122,27 @@ unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
 	return value;
 }
 
+/*
+ * This function will return the VCPU that performed the MMIO access and
+ * trapped from within the VM, and will return NULL if this is a userspace
+ * access.
+ *
+ * We can disable preemption locally around accessing the per-CPU variable,
+ * and use the resolved vcpu pointer after enabling preemption again, because
+ * even if the current thread is migrated to another CPU, reading the per-CPU
+ * value later will give us the same value as we update the per-CPU variable
+ * in the preempt notifier handlers.
+ */
+static struct kvm_vcpu *vgic_get_mmio_requester_vcpu(void)
+{
+	struct kvm_vcpu *vcpu;
+
+	preempt_disable();
+	vcpu = kvm_arm_get_running_vcpu();
+	preempt_enable();
+	return vcpu;
+}
+
 void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
 			      gpa_t addr, unsigned int len,
 			      unsigned long val)
@@ -184,24 +205,10 @@ unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
 static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
 				    bool new_active_state)
 {
-	struct kvm_vcpu *requester_vcpu;
 	unsigned long flags;
-	spin_lock_irqsave(&irq->irq_lock, flags);
+	struct kvm_vcpu *requester_vcpu = vgic_get_mmio_requester_vcpu();
 
-	/*
-	 * The vcpu parameter here can mean multiple things depending on how
-	 * this function is called; when handling a trap from the kernel it
-	 * depends on the GIC version, and these functions are also called as
-	 * part of save/restore from userspace.
-	 *
-	 * Therefore, we have to figure out the requester in a reliable way.
-	 *
-	 * When accessing VGIC state from user space, the requester_vcpu is
-	 * NULL, which is fine, because we guarantee that no VCPUs are running
-	 * when accessing VGIC state from user space so irq->vcpu->cpu is
-	 * always -1.
-	 */
-	requester_vcpu = kvm_arm_get_running_vcpu();
+	spin_lock_irqsave(&irq->irq_lock, flags);
 
 	/*
 	 * If this virtual IRQ was written into a list register, we
@@ -213,6 +220,11 @@ static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
 	 * vgic_change_active_prepare)  and still has to sync back this IRQ,
 	 * so we release and re-acquire the spin_lock to let the other thread
 	 * sync back the IRQ.
+	 *
+	 * When accessing VGIC state from user space, requester_vcpu is
+	 * NULL, which is fine, because we guarantee that no VCPUs are running
+	 * when accessing VGIC state from user space so irq->vcpu->cpu is
+	 * always -1.
 	 */
 	while (irq->vcpu && /* IRQ may have state in an LR somewhere */
 	       irq->vcpu != requester_vcpu && /* Current thread is not the VCPU thread */
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 2/9] KVM: arm/arm64: Factor out functionality to get vgic mmio requester_vcpu
@ 2017-12-20 11:35   ` Christoffer Dall
  0 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

We are about to distinguish between userspace accesses and mmio traps
for a number of the mmio handlers.  When the requester vcpu is NULL, it
means we are handling a userspace access.

Factor out the functionality to get the request vcpu into its own
function, mostly so we have a common place to document the semantics of
the return value.

Also take the chance to move the functionality outside of holding a
spinlock and instead explicitly disable and enable preemption.  This
supports PREEMPT_RT kernels as well.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 virt/kvm/arm/vgic/vgic-mmio.c | 44 +++++++++++++++++++++++++++----------------
 1 file changed, 28 insertions(+), 16 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index deb51ee16a3d..fdad95f62fa3 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -122,6 +122,27 @@ unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
 	return value;
 }
 
+/*
+ * This function will return the VCPU that performed the MMIO access and
+ * trapped from within the VM, and will return NULL if this is a userspace
+ * access.
+ *
+ * We can disable preemption locally around accessing the per-CPU variable,
+ * and use the resolved vcpu pointer after enabling preemption again, because
+ * even if the current thread is migrated to another CPU, reading the per-CPU
+ * value later will give us the same value as we update the per-CPU variable
+ * in the preempt notifier handlers.
+ */
+static struct kvm_vcpu *vgic_get_mmio_requester_vcpu(void)
+{
+	struct kvm_vcpu *vcpu;
+
+	preempt_disable();
+	vcpu = kvm_arm_get_running_vcpu();
+	preempt_enable();
+	return vcpu;
+}
+
 void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
 			      gpa_t addr, unsigned int len,
 			      unsigned long val)
@@ -184,24 +205,10 @@ unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
 static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
 				    bool new_active_state)
 {
-	struct kvm_vcpu *requester_vcpu;
 	unsigned long flags;
-	spin_lock_irqsave(&irq->irq_lock, flags);
+	struct kvm_vcpu *requester_vcpu = vgic_get_mmio_requester_vcpu();
 
-	/*
-	 * The vcpu parameter here can mean multiple things depending on how
-	 * this function is called; when handling a trap from the kernel it
-	 * depends on the GIC version, and these functions are also called as
-	 * part of save/restore from userspace.
-	 *
-	 * Therefore, we have to figure out the requester in a reliable way.
-	 *
-	 * When accessing VGIC state from user space, the requester_vcpu is
-	 * NULL, which is fine, because we guarantee that no VCPUs are running
-	 * when accessing VGIC state from user space so irq->vcpu->cpu is
-	 * always -1.
-	 */
-	requester_vcpu = kvm_arm_get_running_vcpu();
+	spin_lock_irqsave(&irq->irq_lock, flags);
 
 	/*
 	 * If this virtual IRQ was written into a list register, we
@@ -213,6 +220,11 @@ static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
 	 * vgic_change_active_prepare)  and still has to sync back this IRQ,
 	 * so we release and re-acquire the spin_lock to let the other thread
 	 * sync back the IRQ.
+	 *
+	 * When accessing VGIC state from user space, requester_vcpu is
+	 * NULL, which is fine, because we guarantee that no VCPUs are running
+	 * when accessing VGIC state from user space so irq->vcpu->cpu is
+	 * always -1.
 	 */
 	while (irq->vcpu && /* IRQ may have state in an LR somewhere */
 	       irq->vcpu != requester_vcpu && /* Current thread is not the VCPU thread */
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 3/9] KVM: arm/arm64: Don't cache the timer IRQ level
  2017-12-20 11:35 ` Christoffer Dall
@ 2017-12-20 11:36   ` Christoffer Dall
  -1 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:36 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Andre Przywara, kvm

The timer logic was designed after a strict idea of modeling an
interrupt line level in software, meaning that only transitions in the
level need to be reported to the VGIC.  This works well for the timer,
because the arch timer code is in complete control of the device and can
track the transitions of the line.

However, as we are about to support using the HW bit in the VGIC not
just for the timer, but also for VFIO which cannot track transitions of
the interrupt line, we have to decide on an interface between the GIC
and other subsystems for level triggered mapped interrupts, which both
the timer and VFIO can use.

VFIO only sees an asserting transition of the physical interrupt line,
and tells the VGIC when that happens.  That means that part of the
interrupt flow is offloaded to the hardware.

To use the same interface for VFIO devices and the timer, we therefore
have to change the timer (we cannot change VFIO because it doesn't know
the details of the device it is assigning to a VM).

Luckily, changing the timer is simple, we just need to stop 'caching'
the line level, but instead let the VGIC know the state of the timer
every time there is a potential change in the line level, and when the
line level should be asserted from the timer ISR.  The VGIC can ignore
extra notifications using its validate mechanism.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 virt/kvm/arm/arch_timer.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index f9555b1e7f15..9376fe03bf2e 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -99,11 +99,9 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
 	}
 	vtimer = vcpu_vtimer(vcpu);
 
-	if (!vtimer->irq.level) {
-		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
-		if (kvm_timer_irq_can_fire(vtimer))
-			kvm_timer_update_irq(vcpu, true, vtimer);
-	}
+	vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
+	if (kvm_timer_irq_can_fire(vtimer))
+		kvm_timer_update_irq(vcpu, true, vtimer);
 
 	if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
 		kvm_vtimer_update_mask_user(vcpu);
@@ -324,12 +322,20 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
+	bool level;
 
 	if (unlikely(!timer->enabled))
 		return;
 
-	if (kvm_timer_should_fire(vtimer) != vtimer->irq.level)
-		kvm_timer_update_irq(vcpu, !vtimer->irq.level, vtimer);
+	/*
+	 * The vtimer virtual interrupt is a 'mapped' interrupt, meaning part
+	 * of its lifecycle is offloaded to the hardware, and we therefore may
+	 * not have lowered the irq.level value before having to signal a new
+	 * interrupt, but have to signal an interrupt every time the level is
+	 * asserted.
+	 */
+	level = kvm_timer_should_fire(vtimer);
+	kvm_timer_update_irq(vcpu, level, vtimer);
 
 	if (kvm_timer_should_fire(ptimer) != ptimer->irq.level)
 		kvm_timer_update_irq(vcpu, !ptimer->irq.level, ptimer);
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 3/9] KVM: arm/arm64: Don't cache the timer IRQ level
@ 2017-12-20 11:36   ` Christoffer Dall
  0 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

The timer logic was designed after a strict idea of modeling an
interrupt line level in software, meaning that only transitions in the
level need to be reported to the VGIC.  This works well for the timer,
because the arch timer code is in complete control of the device and can
track the transitions of the line.

However, as we are about to support using the HW bit in the VGIC not
just for the timer, but also for VFIO which cannot track transitions of
the interrupt line, we have to decide on an interface between the GIC
and other subsystems for level triggered mapped interrupts, which both
the timer and VFIO can use.

VFIO only sees an asserting transition of the physical interrupt line,
and tells the VGIC when that happens.  That means that part of the
interrupt flow is offloaded to the hardware.

To use the same interface for VFIO devices and the timer, we therefore
have to change the timer (we cannot change VFIO because it doesn't know
the details of the device it is assigning to a VM).

Luckily, changing the timer is simple, we just need to stop 'caching'
the line level, but instead let the VGIC know the state of the timer
every time there is a potential change in the line level, and when the
line level should be asserted from the timer ISR.  The VGIC can ignore
extra notifications using its validate mechanism.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 virt/kvm/arm/arch_timer.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index f9555b1e7f15..9376fe03bf2e 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -99,11 +99,9 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
 	}
 	vtimer = vcpu_vtimer(vcpu);
 
-	if (!vtimer->irq.level) {
-		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
-		if (kvm_timer_irq_can_fire(vtimer))
-			kvm_timer_update_irq(vcpu, true, vtimer);
-	}
+	vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
+	if (kvm_timer_irq_can_fire(vtimer))
+		kvm_timer_update_irq(vcpu, true, vtimer);
 
 	if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
 		kvm_vtimer_update_mask_user(vcpu);
@@ -324,12 +322,20 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
+	bool level;
 
 	if (unlikely(!timer->enabled))
 		return;
 
-	if (kvm_timer_should_fire(vtimer) != vtimer->irq.level)
-		kvm_timer_update_irq(vcpu, !vtimer->irq.level, vtimer);
+	/*
+	 * The vtimer virtual interrupt is a 'mapped' interrupt, meaning part
+	 * of its lifecycle is offloaded to the hardware, and we therefore may
+	 * not have lowered the irq.level value before having to signal a new
+	 * interrupt, but have to signal an interrupt every time the level is
+	 * asserted.
+	 */
+	level = kvm_timer_should_fire(vtimer);
+	kvm_timer_update_irq(vcpu, level, vtimer);
 
 	if (kvm_timer_should_fire(ptimer) != ptimer->irq.level)
 		kvm_timer_update_irq(vcpu, !ptimer->irq.level, ptimer);
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 4/9] KVM: arm/arm64: vgic: Support level-triggered mapped interrupts
  2017-12-20 11:35 ` Christoffer Dall
@ 2017-12-20 11:36   ` Christoffer Dall
  -1 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:36 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Andre Przywara, kvm

Level-triggered mapped IRQs are special because we only observe rising
edges as input to the VGIC, and we don't set the EOI flag and therefore
are not told when the level goes down, so that we can re-queue a new
interrupt when the level goes up.

One way to solve this problem is to side-step the logic of the VGIC and
special case the validation in the injection path, but it has the
unfortunate drawback of having to peak into the physical GIC state
whenever we want to know if the interrupt is pending on the virtual
distributor.

Instead, we can maintain the current semantics of a level triggered
interrupt by sort of treating it as an edge-triggered interrupt,
following from the fact that we only observe an asserting edge.  This
requires us to be a bit careful when populating the LRs and when folding
the state back in though:

 * We lower the line level when populating the LR, so that when
   subsequently observing an asserting edge, the VGIC will do the right
   thing.

 * If the guest never acked the interrupt while running (for example if
   it had masked interrupts at the CPU level while running), we have
   to preserve the pending state of the LR and move it back to the
   line_level field of the struct irq when folding LR state.

   If the guest never acked the interrupt while running, but changed the
   device state and lowered the line (again with interrupts masked) then
   we need to observe this change in the line_level.

   Both of the above situations are solved by sampling the physical line
   and set the line level when folding the LR back.

 * Finally, if the guest never acked the interrupt while running and
   sampling the line reveals that the device state has changed and the
   line has been lowered, we must clear the physical active state, since
   we will otherwise never be told when the interrupt becomes asserted
   again.

This has the added benefit of making the timer optimization patches
(https://lists.cs.columbia.edu/pipermail/kvmarm/2017-July/026343.html) a
bit simpler, because the timer code doesn't have to clear the active
state on the sync anymore.  It also potentially improves the performance
of the timer implementation because the GIC knows the state or the LR
and only needs to clear the
active state when the pending bit in the LR is still set, where the
timer has to always clear it when returning from running the guest with
an injected timer interrupt.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 virt/kvm/arm/vgic/vgic-v2.c | 29 +++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c | 29 +++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c    | 23 +++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h    |  7 +++++++
 4 files changed, 88 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 80897102da26..c32d7b93ffd1 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -105,6 +105,26 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
 				irq->pending_latch = false;
 		}
 
+		/*
+		 * Level-triggered mapped IRQs are special because we only
+		 * observe rising edges as input to the VGIC.
+		 *
+		 * If the guest never acked the interrupt we have to sample
+		 * the physical line and set the line level, because the
+		 * device state could have changed or we simply need to
+		 * process the still pending interrupt later.
+		 *
+		 * If this causes us to lower the level, we have to also clear
+		 * the physical active state, since we will otherwise never be
+		 * told when the interrupt becomes asserted again.
+		 */
+		if (vgic_irq_is_mapped_level(irq) && (val & GICH_LR_PENDING_BIT)) {
+			irq->line_level = vgic_get_phys_line_level(irq);
+
+			if (!irq->line_level)
+				vgic_irq_set_phys_active(irq, false);
+		}
+
 		spin_unlock_irqrestore(&irq->irq_lock, flags);
 		vgic_put_irq(vcpu->kvm, irq);
 	}
@@ -162,6 +182,15 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
 			val |= GICH_LR_EOI;
 	}
 
+	/*
+	 * Level-triggered mapped IRQs are special because we only observe
+	 * rising edges as input to the VGIC.  We therefore lower the line
+	 * level here, so that we can take new virtual IRQs.  See
+	 * vgic_v2_fold_lr_state for more info.
+	 */
+	if (vgic_irq_is_mapped_level(irq) && (val & GICH_LR_PENDING_BIT))
+		irq->line_level = false;
+
 	/* The GICv2 LR only holds five bits of priority. */
 	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
 
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index f47e8481fa45..6b329414e57a 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -96,6 +96,26 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
 				irq->pending_latch = false;
 		}
 
+		/*
+		 * Level-triggered mapped IRQs are special because we only
+		 * observe rising edges as input to the VGIC.
+		 *
+		 * If the guest never acked the interrupt we have to sample
+		 * the physical line and set the line level, because the
+		 * device state could have changed or we simply need to
+		 * process the still pending interrupt later.
+		 *
+		 * If this causes us to lower the level, we have to also clear
+		 * the physical active state, since we will otherwise never be
+		 * told when the interrupt becomes asserted again.
+		 */
+		if (vgic_irq_is_mapped_level(irq) && (val & ICH_LR_PENDING_BIT)) {
+			irq->line_level = vgic_get_phys_line_level(irq);
+
+			if (!irq->line_level)
+				vgic_irq_set_phys_active(irq, false);
+		}
+
 		spin_unlock_irqrestore(&irq->irq_lock, flags);
 		vgic_put_irq(vcpu->kvm, irq);
 	}
@@ -145,6 +165,15 @@ void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
 			val |= ICH_LR_EOI;
 	}
 
+	/*
+	 * Level-triggered mapped IRQs are special because we only observe
+	 * rising edges as input to the VGIC.  We therefore lower the line
+	 * level here, so that we can take new virtual IRQs.  See
+	 * vgic_v3_fold_lr_state for more info.
+	 */
+	if (vgic_irq_is_mapped_level(irq) && (val & ICH_LR_PENDING_BIT))
+		irq->line_level = false;
+
 	/*
 	 * We currently only support Group1 interrupts, which is a
 	 * known defect. This needs to be addressed at some point.
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index ecb8e25f5fe5..4318e9edd075 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -144,6 +144,29 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
 	kfree(irq);
 }
 
+/* Get the input level of a mapped IRQ directly from the physical GIC */
+bool vgic_get_phys_line_level(struct vgic_irq *irq)
+{
+	bool line_level;
+
+	BUG_ON(!irq->hw);
+
+	WARN_ON(irq_get_irqchip_state(irq->host_irq,
+				      IRQCHIP_STATE_PENDING,
+				      &line_level));
+	return line_level;
+}
+
+/* Set/Clear the physical active state */
+void vgic_irq_set_phys_active(struct vgic_irq *irq, bool active)
+{
+
+	BUG_ON(!irq->hw);
+	WARN_ON(irq_set_irqchip_state(irq->host_irq,
+				      IRQCHIP_STATE_ACTIVE,
+				      active));
+}
+
 /**
  * kvm_vgic_target_oracle - compute the target vcpu for an irq
  *
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index efbcf8f96f9c..d0787983a357 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -104,6 +104,11 @@ static inline bool irq_is_pending(struct vgic_irq *irq)
 		return irq->pending_latch || irq->line_level;
 }
 
+static inline bool vgic_irq_is_mapped_level(struct vgic_irq *irq)
+{
+	return irq->config == VGIC_CONFIG_LEVEL && irq->hw;
+}
+
 /*
  * This struct provides an intermediate representation of the fields contained
  * in the GICH_VMCR and ICH_VMCR registers, such that code exporting the GIC
@@ -140,6 +145,8 @@ vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq);
+bool vgic_get_phys_line_level(struct vgic_irq *irq);
+void vgic_irq_set_phys_active(struct vgic_irq *irq, bool active);
 bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
 			   unsigned long flags);
 void vgic_kick_vcpus(struct kvm *kvm);
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 4/9] KVM: arm/arm64: vgic: Support level-triggered mapped interrupts
@ 2017-12-20 11:36   ` Christoffer Dall
  0 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

Level-triggered mapped IRQs are special because we only observe rising
edges as input to the VGIC, and we don't set the EOI flag and therefore
are not told when the level goes down, so that we can re-queue a new
interrupt when the level goes up.

One way to solve this problem is to side-step the logic of the VGIC and
special case the validation in the injection path, but it has the
unfortunate drawback of having to peak into the physical GIC state
whenever we want to know if the interrupt is pending on the virtual
distributor.

Instead, we can maintain the current semantics of a level triggered
interrupt by sort of treating it as an edge-triggered interrupt,
following from the fact that we only observe an asserting edge.  This
requires us to be a bit careful when populating the LRs and when folding
the state back in though:

 * We lower the line level when populating the LR, so that when
   subsequently observing an asserting edge, the VGIC will do the right
   thing.

 * If the guest never acked the interrupt while running (for example if
   it had masked interrupts at the CPU level while running), we have
   to preserve the pending state of the LR and move it back to the
   line_level field of the struct irq when folding LR state.

   If the guest never acked the interrupt while running, but changed the
   device state and lowered the line (again with interrupts masked) then
   we need to observe this change in the line_level.

   Both of the above situations are solved by sampling the physical line
   and set the line level when folding the LR back.

 * Finally, if the guest never acked the interrupt while running and
   sampling the line reveals that the device state has changed and the
   line has been lowered, we must clear the physical active state, since
   we will otherwise never be told when the interrupt becomes asserted
   again.

This has the added benefit of making the timer optimization patches
(https://lists.cs.columbia.edu/pipermail/kvmarm/2017-July/026343.html) a
bit simpler, because the timer code doesn't have to clear the active
state on the sync anymore.  It also potentially improves the performance
of the timer implementation because the GIC knows the state or the LR
and only needs to clear the
active state when the pending bit in the LR is still set, where the
timer has to always clear it when returning from running the guest with
an injected timer interrupt.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 virt/kvm/arm/vgic/vgic-v2.c | 29 +++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c | 29 +++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c    | 23 +++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h    |  7 +++++++
 4 files changed, 88 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 80897102da26..c32d7b93ffd1 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -105,6 +105,26 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
 				irq->pending_latch = false;
 		}
 
+		/*
+		 * Level-triggered mapped IRQs are special because we only
+		 * observe rising edges as input to the VGIC.
+		 *
+		 * If the guest never acked the interrupt we have to sample
+		 * the physical line and set the line level, because the
+		 * device state could have changed or we simply need to
+		 * process the still pending interrupt later.
+		 *
+		 * If this causes us to lower the level, we have to also clear
+		 * the physical active state, since we will otherwise never be
+		 * told when the interrupt becomes asserted again.
+		 */
+		if (vgic_irq_is_mapped_level(irq) && (val & GICH_LR_PENDING_BIT)) {
+			irq->line_level = vgic_get_phys_line_level(irq);
+
+			if (!irq->line_level)
+				vgic_irq_set_phys_active(irq, false);
+		}
+
 		spin_unlock_irqrestore(&irq->irq_lock, flags);
 		vgic_put_irq(vcpu->kvm, irq);
 	}
@@ -162,6 +182,15 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
 			val |= GICH_LR_EOI;
 	}
 
+	/*
+	 * Level-triggered mapped IRQs are special because we only observe
+	 * rising edges as input to the VGIC.  We therefore lower the line
+	 * level here, so that we can take new virtual IRQs.  See
+	 * vgic_v2_fold_lr_state for more info.
+	 */
+	if (vgic_irq_is_mapped_level(irq) && (val & GICH_LR_PENDING_BIT))
+		irq->line_level = false;
+
 	/* The GICv2 LR only holds five bits of priority. */
 	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
 
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index f47e8481fa45..6b329414e57a 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -96,6 +96,26 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
 				irq->pending_latch = false;
 		}
 
+		/*
+		 * Level-triggered mapped IRQs are special because we only
+		 * observe rising edges as input to the VGIC.
+		 *
+		 * If the guest never acked the interrupt we have to sample
+		 * the physical line and set the line level, because the
+		 * device state could have changed or we simply need to
+		 * process the still pending interrupt later.
+		 *
+		 * If this causes us to lower the level, we have to also clear
+		 * the physical active state, since we will otherwise never be
+		 * told when the interrupt becomes asserted again.
+		 */
+		if (vgic_irq_is_mapped_level(irq) && (val & ICH_LR_PENDING_BIT)) {
+			irq->line_level = vgic_get_phys_line_level(irq);
+
+			if (!irq->line_level)
+				vgic_irq_set_phys_active(irq, false);
+		}
+
 		spin_unlock_irqrestore(&irq->irq_lock, flags);
 		vgic_put_irq(vcpu->kvm, irq);
 	}
@@ -145,6 +165,15 @@ void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
 			val |= ICH_LR_EOI;
 	}
 
+	/*
+	 * Level-triggered mapped IRQs are special because we only observe
+	 * rising edges as input to the VGIC.  We therefore lower the line
+	 * level here, so that we can take new virtual IRQs.  See
+	 * vgic_v3_fold_lr_state for more info.
+	 */
+	if (vgic_irq_is_mapped_level(irq) && (val & ICH_LR_PENDING_BIT))
+		irq->line_level = false;
+
 	/*
 	 * We currently only support Group1 interrupts, which is a
 	 * known defect. This needs to be addressed at some point.
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index ecb8e25f5fe5..4318e9edd075 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -144,6 +144,29 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
 	kfree(irq);
 }
 
+/* Get the input level of a mapped IRQ directly from the physical GIC */
+bool vgic_get_phys_line_level(struct vgic_irq *irq)
+{
+	bool line_level;
+
+	BUG_ON(!irq->hw);
+
+	WARN_ON(irq_get_irqchip_state(irq->host_irq,
+				      IRQCHIP_STATE_PENDING,
+				      &line_level));
+	return line_level;
+}
+
+/* Set/Clear the physical active state */
+void vgic_irq_set_phys_active(struct vgic_irq *irq, bool active)
+{
+
+	BUG_ON(!irq->hw);
+	WARN_ON(irq_set_irqchip_state(irq->host_irq,
+				      IRQCHIP_STATE_ACTIVE,
+				      active));
+}
+
 /**
  * kvm_vgic_target_oracle - compute the target vcpu for an irq
  *
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index efbcf8f96f9c..d0787983a357 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -104,6 +104,11 @@ static inline bool irq_is_pending(struct vgic_irq *irq)
 		return irq->pending_latch || irq->line_level;
 }
 
+static inline bool vgic_irq_is_mapped_level(struct vgic_irq *irq)
+{
+	return irq->config == VGIC_CONFIG_LEVEL && irq->hw;
+}
+
 /*
  * This struct provides an intermediate representation of the fields contained
  * in the GICH_VMCR and ICH_VMCR registers, such that code exporting the GIC
@@ -140,6 +145,8 @@ vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq);
+bool vgic_get_phys_line_level(struct vgic_irq *irq);
+void vgic_irq_set_phys_active(struct vgic_irq *irq, bool active);
 bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
 			   unsigned long flags);
 void vgic_kick_vcpus(struct kvm *kvm);
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 5/9] KVM: arm/arm64: Support a vgic interrupt line level sample function
  2017-12-20 11:35 ` Christoffer Dall
@ 2017-12-20 11:36   ` Christoffer Dall
  -1 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:36 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Andre Przywara, kvm

The GIC sometimes need to sample the physical line of a mapped
interrupt.  As we know this to be notoriously slow, provide a callback
function for devices (such as the timer) which can do this much faster
than talking to the distributor, for example by comparing a few
in-memory values.  Fall back to the good old method of poking the
physical GIC if no callback is provided.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 include/kvm/arm_vgic.h    | 13 ++++++++++++-
 virt/kvm/arm/arch_timer.c |  3 ++-
 virt/kvm/arm/vgic/vgic.c  | 13 +++++++++----
 3 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 8c896540a72c..cdbd142ca7f2 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -130,6 +130,17 @@ struct vgic_irq {
 	u8 priority;
 	enum vgic_irq_config config;	/* Level or edge */
 
+	/*
+	 * Callback function pointer to in-kernel devices that can tell us the
+	 * state of the input level of mapped level-triggered IRQ faster than
+	 * peaking into the physical GIC.
+	 *
+	 * Always called in non-preemptible section and the functions can use
+	 * kvm_arm_get_running_vcpu() to get the vcpu pointer for private
+	 * IRQs.
+	 */
+	bool (*get_input_level)(int vintid);
+
 	void *owner;			/* Opaque pointer to reserve an interrupt
 					   for in-kernel devices. */
 };
@@ -331,7 +342,7 @@ void kvm_vgic_init_cpu_hardware(void);
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level, void *owner);
 int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
-			  u32 vintid);
+			  u32 vintid, bool (*get_input_level)(int vindid));
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int vintid);
 bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int vintid);
 
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 9376fe03bf2e..fb0533ed903d 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -834,7 +834,8 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	}
 
-	ret = kvm_vgic_map_phys_irq(vcpu, host_vtimer_irq, vtimer->irq.irq);
+	ret = kvm_vgic_map_phys_irq(vcpu, host_vtimer_irq, vtimer->irq.irq,
+				    NULL);
 	if (ret)
 		return ret;
 
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 4318e9edd075..d57b3bf8eb36 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -144,13 +144,15 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
 	kfree(irq);
 }
 
-/* Get the input level of a mapped IRQ directly from the physical GIC */
 bool vgic_get_phys_line_level(struct vgic_irq *irq)
 {
 	bool line_level;
 
 	BUG_ON(!irq->hw);
 
+	if (irq->get_input_level)
+		return irq->get_input_level(irq->intid);
+
 	WARN_ON(irq_get_irqchip_state(irq->host_irq,
 				      IRQCHIP_STATE_PENDING,
 				      &line_level));
@@ -436,7 +438,8 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 
 /* @irq->irq_lock must be held */
 static int kvm_vgic_map_irq(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
-			    unsigned int host_irq)
+			    unsigned int host_irq,
+			    bool (*get_input_level)(int vindid))
 {
 	struct irq_desc *desc;
 	struct irq_data *data;
@@ -456,6 +459,7 @@ static int kvm_vgic_map_irq(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
 	irq->hw = true;
 	irq->host_irq = host_irq;
 	irq->hwintid = data->hwirq;
+	irq->get_input_level = get_input_level;
 	return 0;
 }
 
@@ -464,10 +468,11 @@ static inline void kvm_vgic_unmap_irq(struct vgic_irq *irq)
 {
 	irq->hw = false;
 	irq->hwintid = 0;
+	irq->get_input_level = NULL;
 }
 
 int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
-			  u32 vintid)
+			  u32 vintid, bool (*get_input_level)(int vindid))
 {
 	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, vintid);
 	unsigned long flags;
@@ -476,7 +481,7 @@ int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
 	BUG_ON(!irq);
 
 	spin_lock_irqsave(&irq->irq_lock, flags);
-	ret = kvm_vgic_map_irq(vcpu, irq, host_irq);
+	ret = kvm_vgic_map_irq(vcpu, irq, host_irq, get_input_level);
 	spin_unlock_irqrestore(&irq->irq_lock, flags);
 	vgic_put_irq(vcpu->kvm, irq);
 
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 5/9] KVM: arm/arm64: Support a vgic interrupt line level sample function
@ 2017-12-20 11:36   ` Christoffer Dall
  0 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

The GIC sometimes need to sample the physical line of a mapped
interrupt.  As we know this to be notoriously slow, provide a callback
function for devices (such as the timer) which can do this much faster
than talking to the distributor, for example by comparing a few
in-memory values.  Fall back to the good old method of poking the
physical GIC if no callback is provided.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 include/kvm/arm_vgic.h    | 13 ++++++++++++-
 virt/kvm/arm/arch_timer.c |  3 ++-
 virt/kvm/arm/vgic/vgic.c  | 13 +++++++++----
 3 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 8c896540a72c..cdbd142ca7f2 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -130,6 +130,17 @@ struct vgic_irq {
 	u8 priority;
 	enum vgic_irq_config config;	/* Level or edge */
 
+	/*
+	 * Callback function pointer to in-kernel devices that can tell us the
+	 * state of the input level of mapped level-triggered IRQ faster than
+	 * peaking into the physical GIC.
+	 *
+	 * Always called in non-preemptible section and the functions can use
+	 * kvm_arm_get_running_vcpu() to get the vcpu pointer for private
+	 * IRQs.
+	 */
+	bool (*get_input_level)(int vintid);
+
 	void *owner;			/* Opaque pointer to reserve an interrupt
 					   for in-kernel devices. */
 };
@@ -331,7 +342,7 @@ void kvm_vgic_init_cpu_hardware(void);
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level, void *owner);
 int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
-			  u32 vintid);
+			  u32 vintid, bool (*get_input_level)(int vindid));
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int vintid);
 bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int vintid);
 
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 9376fe03bf2e..fb0533ed903d 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -834,7 +834,8 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	}
 
-	ret = kvm_vgic_map_phys_irq(vcpu, host_vtimer_irq, vtimer->irq.irq);
+	ret = kvm_vgic_map_phys_irq(vcpu, host_vtimer_irq, vtimer->irq.irq,
+				    NULL);
 	if (ret)
 		return ret;
 
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 4318e9edd075..d57b3bf8eb36 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -144,13 +144,15 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
 	kfree(irq);
 }
 
-/* Get the input level of a mapped IRQ directly from the physical GIC */
 bool vgic_get_phys_line_level(struct vgic_irq *irq)
 {
 	bool line_level;
 
 	BUG_ON(!irq->hw);
 
+	if (irq->get_input_level)
+		return irq->get_input_level(irq->intid);
+
 	WARN_ON(irq_get_irqchip_state(irq->host_irq,
 				      IRQCHIP_STATE_PENDING,
 				      &line_level));
@@ -436,7 +438,8 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 
 /* @irq->irq_lock must be held */
 static int kvm_vgic_map_irq(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
-			    unsigned int host_irq)
+			    unsigned int host_irq,
+			    bool (*get_input_level)(int vindid))
 {
 	struct irq_desc *desc;
 	struct irq_data *data;
@@ -456,6 +459,7 @@ static int kvm_vgic_map_irq(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
 	irq->hw = true;
 	irq->host_irq = host_irq;
 	irq->hwintid = data->hwirq;
+	irq->get_input_level = get_input_level;
 	return 0;
 }
 
@@ -464,10 +468,11 @@ static inline void kvm_vgic_unmap_irq(struct vgic_irq *irq)
 {
 	irq->hw = false;
 	irq->hwintid = 0;
+	irq->get_input_level = NULL;
 }
 
 int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
-			  u32 vintid)
+			  u32 vintid, bool (*get_input_level)(int vindid))
 {
 	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, vintid);
 	unsigned long flags;
@@ -476,7 +481,7 @@ int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
 	BUG_ON(!irq);
 
 	spin_lock_irqsave(&irq->irq_lock, flags);
-	ret = kvm_vgic_map_irq(vcpu, irq, host_irq);
+	ret = kvm_vgic_map_irq(vcpu, irq, host_irq, get_input_level);
 	spin_unlock_irqrestore(&irq->irq_lock, flags);
 	vgic_put_irq(vcpu->kvm, irq);
 
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 6/9] KVM: arm/arm64: Support VGIC dist pend/active changes for mapped IRQs
  2017-12-20 11:35 ` Christoffer Dall
@ 2017-12-20 11:36   ` Christoffer Dall
  -1 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:36 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Andre Przywara, kvm

For mapped IRQs (with the HW bit set in the LR) we have to follow some
rules of the architecture.  One of these rules is that VM must not be
allowed to deactivate a virtual interrupt with the HW bit set unless the
physical interrupt is also active.

This works fine when injecting mapped interrupts, because we leave it up
to the injector to either set EOImode==1 or manually set the active
state of the physical interrupt.

However, the guest can set virtual interrupt to be pending or active by
writing to the virtual distributor, which could lead to deactivating a
virtual interrupt with the HW bit set without the physical interrupt
being active.

We could set the physical interrupt to active whenever we are about to
enter the VM with a HW interrupt either pending or active, but that
would be really slow, especially on GICv2.  So we take the long way
around and do the hard work when needed, which is expected to be
extremely rare.

When the VM sets the pending state for a HW interrupt on the virtual
distributor we set the active state on the physical distributor, because
the virtual interrupt can become active and then the guest can
deactivate it.

When the VM clears the pending state we also clear it on the physical
side, because the injector might otherwise raise the interrupt.  We also
clear the physical active state when the virtual interrupt is not
active, since otherwise a SPEND/CPEND sequence from the guest would
prevent signaling of future interrupts.

Changing the state of mapped interrupts from userspace is not supported,
and it's expected that userspace unmaps devices from VFIO before
attempting to set the interrupt state, because the interrupt state is
driven by hardware.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 virt/kvm/arm/vgic/vgic-mmio.c | 71 +++++++++++++++++++++++++++++++++++++++----
 virt/kvm/arm/vgic/vgic.c      |  7 +++++
 virt/kvm/arm/vgic/vgic.h      |  1 +
 3 files changed, 73 insertions(+), 6 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index fdad95f62fa3..83d82bd7dc4e 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -16,6 +16,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <kvm/iodev.h>
+#include <kvm/arm_arch_timer.h>
 #include <kvm/arm_vgic.h>
 
 #include "vgic.h"
@@ -143,10 +144,22 @@ static struct kvm_vcpu *vgic_get_mmio_requester_vcpu(void)
 	return vcpu;
 }
 
+/* Must be called with irq->irq_lock held */
+static void vgic_hw_irq_spending(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
+				 bool is_uaccess)
+{
+	if (is_uaccess)
+		return;
+
+	irq->pending_latch = true;
+	vgic_irq_set_phys_active(irq, true);
+}
+
 void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
 			      gpa_t addr, unsigned int len,
 			      unsigned long val)
 {
+	bool is_uaccess = !vgic_get_mmio_requester_vcpu();
 	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
 	int i;
 	unsigned long flags;
@@ -155,17 +168,45 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
 		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
 
 		spin_lock_irqsave(&irq->irq_lock, flags);
-		irq->pending_latch = true;
-
+		if (irq->hw)
+			vgic_hw_irq_spending(vcpu, irq, is_uaccess);
+		else
+			irq->pending_latch = true;
 		vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
 		vgic_put_irq(vcpu->kvm, irq);
 	}
 }
 
+/* Must be called with irq->irq_lock held */
+static void vgic_hw_irq_cpending(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
+				 bool is_uaccess)
+{
+	if (is_uaccess)
+		return;
+
+	irq->pending_latch = false;
+
+	/*
+	 * We don't want the guest to effectively mask the physical
+	 * interrupt by doing a write to SPENDR followed by a write to
+	 * CPENDR for HW interrupts, so we clear the active state on
+	 * the physical side if the virtual interrupt is not active.
+	 * This may lead to taking an additional interrupt on the
+	 * host, but that should not be a problem as the worst that
+	 * can happen is an additional vgic injection.  We also clear
+	 * the pending state to maintain proper semantics for edge HW
+	 * interrupts.
+	 */
+	vgic_irq_set_phys_pending(irq, false);
+	if (!irq->active)
+		vgic_irq_set_phys_active(irq, false);
+}
+
 void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
 			      gpa_t addr, unsigned int len,
 			      unsigned long val)
 {
+	bool is_uaccess = !vgic_get_mmio_requester_vcpu();
 	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
 	int i;
 	unsigned long flags;
@@ -175,7 +216,10 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
 
 		spin_lock_irqsave(&irq->irq_lock, flags);
 
-		irq->pending_latch = false;
+		if (irq->hw)
+			vgic_hw_irq_cpending(vcpu, irq, is_uaccess);
+		else
+			irq->pending_latch = false;
 
 		spin_unlock_irqrestore(&irq->irq_lock, flags);
 		vgic_put_irq(vcpu->kvm, irq);
@@ -202,8 +246,19 @@ unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
 	return value;
 }
 
+/* Must be called with irq->irq_lock held */
+static void vgic_hw_irq_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
+				      bool active, bool is_uaccess)
+{
+	if (is_uaccess)
+		return;
+
+	irq->active = active;
+	vgic_irq_set_phys_active(irq, active);
+}
+
 static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
-				    bool new_active_state)
+				    bool active)
 {
 	unsigned long flags;
 	struct kvm_vcpu *requester_vcpu = vgic_get_mmio_requester_vcpu();
@@ -231,8 +286,12 @@ static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
 	       irq->vcpu->cpu != -1) /* VCPU thread is running */
 		cond_resched_lock(&irq->irq_lock);
 
-	irq->active = new_active_state;
-	if (new_active_state)
+	if (irq->hw)
+		vgic_hw_irq_change_active(vcpu, irq, active, !requester_vcpu);
+	else
+		irq->active = active;
+
+	if (irq->active)
 		vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
 	else
 		spin_unlock_irqrestore(&irq->irq_lock, flags);
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index d57b3bf8eb36..c7c5ef190afa 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -144,6 +144,13 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
 	kfree(irq);
 }
 
+void vgic_irq_set_phys_pending(struct vgic_irq *irq, bool pending)
+{
+	WARN_ON(irq_set_irqchip_state(irq->host_irq,
+				      IRQCHIP_STATE_PENDING,
+				      pending));
+}
+
 bool vgic_get_phys_line_level(struct vgic_irq *irq)
 {
 	bool line_level;
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index d0787983a357..12c37b89f7a3 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -146,6 +146,7 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq);
 bool vgic_get_phys_line_level(struct vgic_irq *irq);
+void vgic_irq_set_phys_pending(struct vgic_irq *irq, bool pending);
 void vgic_irq_set_phys_active(struct vgic_irq *irq, bool active);
 bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
 			   unsigned long flags);
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 6/9] KVM: arm/arm64: Support VGIC dist pend/active changes for mapped IRQs
@ 2017-12-20 11:36   ` Christoffer Dall
  0 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

For mapped IRQs (with the HW bit set in the LR) we have to follow some
rules of the architecture.  One of these rules is that VM must not be
allowed to deactivate a virtual interrupt with the HW bit set unless the
physical interrupt is also active.

This works fine when injecting mapped interrupts, because we leave it up
to the injector to either set EOImode==1 or manually set the active
state of the physical interrupt.

However, the guest can set virtual interrupt to be pending or active by
writing to the virtual distributor, which could lead to deactivating a
virtual interrupt with the HW bit set without the physical interrupt
being active.

We could set the physical interrupt to active whenever we are about to
enter the VM with a HW interrupt either pending or active, but that
would be really slow, especially on GICv2.  So we take the long way
around and do the hard work when needed, which is expected to be
extremely rare.

When the VM sets the pending state for a HW interrupt on the virtual
distributor we set the active state on the physical distributor, because
the virtual interrupt can become active and then the guest can
deactivate it.

When the VM clears the pending state we also clear it on the physical
side, because the injector might otherwise raise the interrupt.  We also
clear the physical active state when the virtual interrupt is not
active, since otherwise a SPEND/CPEND sequence from the guest would
prevent signaling of future interrupts.

Changing the state of mapped interrupts from userspace is not supported,
and it's expected that userspace unmaps devices from VFIO before
attempting to set the interrupt state, because the interrupt state is
driven by hardware.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 virt/kvm/arm/vgic/vgic-mmio.c | 71 +++++++++++++++++++++++++++++++++++++++----
 virt/kvm/arm/vgic/vgic.c      |  7 +++++
 virt/kvm/arm/vgic/vgic.h      |  1 +
 3 files changed, 73 insertions(+), 6 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index fdad95f62fa3..83d82bd7dc4e 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -16,6 +16,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <kvm/iodev.h>
+#include <kvm/arm_arch_timer.h>
 #include <kvm/arm_vgic.h>
 
 #include "vgic.h"
@@ -143,10 +144,22 @@ static struct kvm_vcpu *vgic_get_mmio_requester_vcpu(void)
 	return vcpu;
 }
 
+/* Must be called with irq->irq_lock held */
+static void vgic_hw_irq_spending(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
+				 bool is_uaccess)
+{
+	if (is_uaccess)
+		return;
+
+	irq->pending_latch = true;
+	vgic_irq_set_phys_active(irq, true);
+}
+
 void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
 			      gpa_t addr, unsigned int len,
 			      unsigned long val)
 {
+	bool is_uaccess = !vgic_get_mmio_requester_vcpu();
 	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
 	int i;
 	unsigned long flags;
@@ -155,17 +168,45 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
 		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
 
 		spin_lock_irqsave(&irq->irq_lock, flags);
-		irq->pending_latch = true;
-
+		if (irq->hw)
+			vgic_hw_irq_spending(vcpu, irq, is_uaccess);
+		else
+			irq->pending_latch = true;
 		vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
 		vgic_put_irq(vcpu->kvm, irq);
 	}
 }
 
+/* Must be called with irq->irq_lock held */
+static void vgic_hw_irq_cpending(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
+				 bool is_uaccess)
+{
+	if (is_uaccess)
+		return;
+
+	irq->pending_latch = false;
+
+	/*
+	 * We don't want the guest to effectively mask the physical
+	 * interrupt by doing a write to SPENDR followed by a write to
+	 * CPENDR for HW interrupts, so we clear the active state on
+	 * the physical side if the virtual interrupt is not active.
+	 * This may lead to taking an additional interrupt on the
+	 * host, but that should not be a problem as the worst that
+	 * can happen is an additional vgic injection.  We also clear
+	 * the pending state to maintain proper semantics for edge HW
+	 * interrupts.
+	 */
+	vgic_irq_set_phys_pending(irq, false);
+	if (!irq->active)
+		vgic_irq_set_phys_active(irq, false);
+}
+
 void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
 			      gpa_t addr, unsigned int len,
 			      unsigned long val)
 {
+	bool is_uaccess = !vgic_get_mmio_requester_vcpu();
 	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
 	int i;
 	unsigned long flags;
@@ -175,7 +216,10 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
 
 		spin_lock_irqsave(&irq->irq_lock, flags);
 
-		irq->pending_latch = false;
+		if (irq->hw)
+			vgic_hw_irq_cpending(vcpu, irq, is_uaccess);
+		else
+			irq->pending_latch = false;
 
 		spin_unlock_irqrestore(&irq->irq_lock, flags);
 		vgic_put_irq(vcpu->kvm, irq);
@@ -202,8 +246,19 @@ unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
 	return value;
 }
 
+/* Must be called with irq->irq_lock held */
+static void vgic_hw_irq_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
+				      bool active, bool is_uaccess)
+{
+	if (is_uaccess)
+		return;
+
+	irq->active = active;
+	vgic_irq_set_phys_active(irq, active);
+}
+
 static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
-				    bool new_active_state)
+				    bool active)
 {
 	unsigned long flags;
 	struct kvm_vcpu *requester_vcpu = vgic_get_mmio_requester_vcpu();
@@ -231,8 +286,12 @@ static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
 	       irq->vcpu->cpu != -1) /* VCPU thread is running */
 		cond_resched_lock(&irq->irq_lock);
 
-	irq->active = new_active_state;
-	if (new_active_state)
+	if (irq->hw)
+		vgic_hw_irq_change_active(vcpu, irq, active, !requester_vcpu);
+	else
+		irq->active = active;
+
+	if (irq->active)
 		vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
 	else
 		spin_unlock_irqrestore(&irq->irq_lock, flags);
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index d57b3bf8eb36..c7c5ef190afa 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -144,6 +144,13 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
 	kfree(irq);
 }
 
+void vgic_irq_set_phys_pending(struct vgic_irq *irq, bool pending)
+{
+	WARN_ON(irq_set_irqchip_state(irq->host_irq,
+				      IRQCHIP_STATE_PENDING,
+				      pending));
+}
+
 bool vgic_get_phys_line_level(struct vgic_irq *irq)
 {
 	bool line_level;
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index d0787983a357..12c37b89f7a3 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -146,6 +146,7 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq);
 bool vgic_get_phys_line_level(struct vgic_irq *irq);
+void vgic_irq_set_phys_pending(struct vgic_irq *irq, bool pending);
 void vgic_irq_set_phys_active(struct vgic_irq *irq, bool active);
 bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
 			   unsigned long flags);
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 7/9] KVM: arm/arm64: Provide a get_input_level for the arch timer
  2017-12-20 11:35 ` Christoffer Dall
@ 2017-12-20 11:36   ` Christoffer Dall
  -1 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:36 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Andre Przywara, kvm

The VGIC can now support the life-cycle of mapped level-triggered
interrupts, and we no longer have to read back the timer state on every
exit from the VM if we had an asserted timer interrupt signal, because
the VGIC already knows if we hit the unlikely case where the guest
disables the timer without ACKing the virtual timer interrupt.

This means we rework a bit of the code to factor out the functionality
to snapshot the timer state from vtimer_save_state(), and we can reuse
this functionality in the sync path when we have an irqchip in
userspace, and also to support our implementation of the
get_input_level() function for the timer.

This change also means that we can no longer rely on the timer's view of
the interrupt line to set the active state, because we no longer
maintain this state for mapped interrupts when exiting from the guest.
Instead, we only set the active state if the virtual interrupt is
active, and otherwise we simply let the timer fire again and raise the
virtual interrupt from the ISR.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 include/kvm/arm_arch_timer.h |  2 ++
 virt/kvm/arm/arch_timer.c    | 84 ++++++++++++++++++++------------------------
 2 files changed, 40 insertions(+), 46 deletions(-)

diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index 6e45608b2399..b1dcfde0a3ef 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -90,6 +90,8 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
 
 void kvm_timer_init_vhe(void);
 
+bool kvm_arch_timer_get_input_level(int vintid);
+
 #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.vtimer)
 #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.ptimer)
 
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index fb0533ed903d..d845d67b7062 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -343,6 +343,12 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
 	phys_timer_emulate(vcpu);
 }
 
+static void __timer_snapshot_state(struct arch_timer_context *timer)
+{
+	timer->cnt_ctl = read_sysreg_el0(cntv_ctl);
+	timer->cnt_cval = read_sysreg_el0(cntv_cval);
+}
+
 static void vtimer_save_state(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
@@ -354,10 +360,8 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
 	if (!vtimer->loaded)
 		goto out;
 
-	if (timer->enabled) {
-		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
-		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
-	}
+	if (timer->enabled)
+		__timer_snapshot_state(vtimer);
 
 	/* Disable the virtual timer */
 	write_sysreg_el0(0, cntv_ctl);
@@ -454,8 +458,7 @@ static void kvm_timer_vcpu_load_vgic(struct kvm_vcpu *vcpu)
 	bool phys_active;
 	int ret;
 
-	phys_active = vtimer->irq.level ||
-		      kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
+	phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
 
 	ret = irq_set_irqchip_state(host_vtimer_irq,
 				    IRQCHIP_STATE_ACTIVE,
@@ -535,54 +538,27 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 	set_cntvoff(0);
 }
 
-static void unmask_vtimer_irq(struct kvm_vcpu *vcpu)
+/*
+ * With a userspace irqchip we have to check if the guest de-asserted the
+ * timer and if so, unmask the timer irq signal on the host interrupt
+ * controller to ensure that we see future timer signals.
+ */
+static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 
 	if (unlikely(!irqchip_in_kernel(vcpu->kvm))) {
-		kvm_vtimer_update_mask_user(vcpu);
-		return;
-	}
-
-	/*
-	 * If the guest disabled the timer without acking the interrupt, then
-	 * we must make sure the physical and virtual active states are in
-	 * sync by deactivating the physical interrupt, because otherwise we
-	 * wouldn't see the next timer interrupt in the host.
-	 */
-	if (!kvm_vgic_map_is_active(vcpu, vtimer->irq.irq)) {
-		int ret;
-		ret = irq_set_irqchip_state(host_vtimer_irq,
-					    IRQCHIP_STATE_ACTIVE,
-					    false);
-		WARN_ON(ret);
+		__timer_snapshot_state(vtimer);
+		if (!kvm_timer_should_fire(vtimer)) {
+			kvm_timer_update_irq(vcpu, false, vtimer);
+			kvm_vtimer_update_mask_user(vcpu);
+		}
 	}
 }
 
-/**
- * kvm_timer_sync_hwstate - sync timer state from cpu
- * @vcpu: The vcpu pointer
- *
- * Check if any of the timers have expired while we were running in the guest,
- * and inject an interrupt if that was the case.
- */
 void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
-
-	/*
-	 * If we entered the guest with the vtimer output asserted we have to
-	 * check if the guest has modified the timer so that we should lower
-	 * the line at this point.
-	 */
-	if (vtimer->irq.level) {
-		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
-		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
-		if (!kvm_timer_should_fire(vtimer)) {
-			kvm_timer_update_irq(vcpu, false, vtimer);
-			unmask_vtimer_irq(vcpu);
-		}
-	}
+	unmask_vtimer_irq_user(vcpu);
 }
 
 int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)
@@ -813,6 +789,22 @@ static bool timer_irqs_are_valid(struct kvm_vcpu *vcpu)
 	return true;
 }
 
+bool kvm_arch_timer_get_input_level(int vintid)
+{
+	struct kvm_vcpu *vcpu = kvm_arm_get_running_vcpu();
+	struct arch_timer_context *timer;
+
+	if (vintid == vcpu_vtimer(vcpu)->irq.irq)
+		timer = vcpu_vtimer(vcpu);
+	else
+		BUG(); /* We only map the vtimer so far */
+
+	if (timer->loaded)
+		__timer_snapshot_state(timer);
+
+	return kvm_timer_should_fire(timer);
+}
+
 int kvm_timer_enable(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
@@ -835,7 +827,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 	}
 
 	ret = kvm_vgic_map_phys_irq(vcpu, host_vtimer_irq, vtimer->irq.irq,
-				    NULL);
+				    kvm_arch_timer_get_input_level);
 	if (ret)
 		return ret;
 
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 7/9] KVM: arm/arm64: Provide a get_input_level for the arch timer
@ 2017-12-20 11:36   ` Christoffer Dall
  0 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

The VGIC can now support the life-cycle of mapped level-triggered
interrupts, and we no longer have to read back the timer state on every
exit from the VM if we had an asserted timer interrupt signal, because
the VGIC already knows if we hit the unlikely case where the guest
disables the timer without ACKing the virtual timer interrupt.

This means we rework a bit of the code to factor out the functionality
to snapshot the timer state from vtimer_save_state(), and we can reuse
this functionality in the sync path when we have an irqchip in
userspace, and also to support our implementation of the
get_input_level() function for the timer.

This change also means that we can no longer rely on the timer's view of
the interrupt line to set the active state, because we no longer
maintain this state for mapped interrupts when exiting from the guest.
Instead, we only set the active state if the virtual interrupt is
active, and otherwise we simply let the timer fire again and raise the
virtual interrupt from the ISR.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 include/kvm/arm_arch_timer.h |  2 ++
 virt/kvm/arm/arch_timer.c    | 84 ++++++++++++++++++++------------------------
 2 files changed, 40 insertions(+), 46 deletions(-)

diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index 6e45608b2399..b1dcfde0a3ef 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -90,6 +90,8 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
 
 void kvm_timer_init_vhe(void);
 
+bool kvm_arch_timer_get_input_level(int vintid);
+
 #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.vtimer)
 #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.ptimer)
 
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index fb0533ed903d..d845d67b7062 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -343,6 +343,12 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
 	phys_timer_emulate(vcpu);
 }
 
+static void __timer_snapshot_state(struct arch_timer_context *timer)
+{
+	timer->cnt_ctl = read_sysreg_el0(cntv_ctl);
+	timer->cnt_cval = read_sysreg_el0(cntv_cval);
+}
+
 static void vtimer_save_state(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
@@ -354,10 +360,8 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
 	if (!vtimer->loaded)
 		goto out;
 
-	if (timer->enabled) {
-		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
-		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
-	}
+	if (timer->enabled)
+		__timer_snapshot_state(vtimer);
 
 	/* Disable the virtual timer */
 	write_sysreg_el0(0, cntv_ctl);
@@ -454,8 +458,7 @@ static void kvm_timer_vcpu_load_vgic(struct kvm_vcpu *vcpu)
 	bool phys_active;
 	int ret;
 
-	phys_active = vtimer->irq.level ||
-		      kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
+	phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
 
 	ret = irq_set_irqchip_state(host_vtimer_irq,
 				    IRQCHIP_STATE_ACTIVE,
@@ -535,54 +538,27 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 	set_cntvoff(0);
 }
 
-static void unmask_vtimer_irq(struct kvm_vcpu *vcpu)
+/*
+ * With a userspace irqchip we have to check if the guest de-asserted the
+ * timer and if so, unmask the timer irq signal on the host interrupt
+ * controller to ensure that we see future timer signals.
+ */
+static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 
 	if (unlikely(!irqchip_in_kernel(vcpu->kvm))) {
-		kvm_vtimer_update_mask_user(vcpu);
-		return;
-	}
-
-	/*
-	 * If the guest disabled the timer without acking the interrupt, then
-	 * we must make sure the physical and virtual active states are in
-	 * sync by deactivating the physical interrupt, because otherwise we
-	 * wouldn't see the next timer interrupt in the host.
-	 */
-	if (!kvm_vgic_map_is_active(vcpu, vtimer->irq.irq)) {
-		int ret;
-		ret = irq_set_irqchip_state(host_vtimer_irq,
-					    IRQCHIP_STATE_ACTIVE,
-					    false);
-		WARN_ON(ret);
+		__timer_snapshot_state(vtimer);
+		if (!kvm_timer_should_fire(vtimer)) {
+			kvm_timer_update_irq(vcpu, false, vtimer);
+			kvm_vtimer_update_mask_user(vcpu);
+		}
 	}
 }
 
-/**
- * kvm_timer_sync_hwstate - sync timer state from cpu
- * @vcpu: The vcpu pointer
- *
- * Check if any of the timers have expired while we were running in the guest,
- * and inject an interrupt if that was the case.
- */
 void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
-
-	/*
-	 * If we entered the guest with the vtimer output asserted we have to
-	 * check if the guest has modified the timer so that we should lower
-	 * the line at this point.
-	 */
-	if (vtimer->irq.level) {
-		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
-		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
-		if (!kvm_timer_should_fire(vtimer)) {
-			kvm_timer_update_irq(vcpu, false, vtimer);
-			unmask_vtimer_irq(vcpu);
-		}
-	}
+	unmask_vtimer_irq_user(vcpu);
 }
 
 int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)
@@ -813,6 +789,22 @@ static bool timer_irqs_are_valid(struct kvm_vcpu *vcpu)
 	return true;
 }
 
+bool kvm_arch_timer_get_input_level(int vintid)
+{
+	struct kvm_vcpu *vcpu = kvm_arm_get_running_vcpu();
+	struct arch_timer_context *timer;
+
+	if (vintid == vcpu_vtimer(vcpu)->irq.irq)
+		timer = vcpu_vtimer(vcpu);
+	else
+		BUG(); /* We only map the vtimer so far */
+
+	if (timer->loaded)
+		__timer_snapshot_state(timer);
+
+	return kvm_timer_should_fire(timer);
+}
+
 int kvm_timer_enable(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
@@ -835,7 +827,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 	}
 
 	ret = kvm_vgic_map_phys_irq(vcpu, host_vtimer_irq, vtimer->irq.irq,
-				    NULL);
+				    kvm_arch_timer_get_input_level);
 	if (ret)
 		return ret;
 
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 8/9] KVM: arm/arm64: Avoid work when userspace iqchips are not used
  2017-12-20 11:35 ` Christoffer Dall
@ 2017-12-20 11:36   ` Christoffer Dall
  -1 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:36 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Andre Przywara, kvm

We currently check if the VM has a userspace irqchip in several places
along the critical path, and if so, we do some work which is only
required for having an irqchip in userspace.  This is unfortunate, as we
could avoid doing any work entirely, if we didn't have to support
irqchip in userspace.

Realizing the userspace irqchip on ARM is mostly a developer or hobby
feature, and is unlikely to be used in servers or other scenarios where
performance is a priority, we can use a refcounted static key to only
check the irqchip configuration when we have at least one VM that uses
an irqchip in userspace.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm/include/asm/kvm_host.h   |  2 ++
 arch/arm64/include/asm/kvm_host.h |  2 ++
 virt/kvm/arm/arch_timer.c         |  6 ++--
 virt/kvm/arm/arm.c                | 59 ++++++++++++++++++++++++++++-----------
 4 files changed, 50 insertions(+), 19 deletions(-)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index a9f7d3f47134..6394fb99da7f 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -48,6 +48,8 @@
 	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
 #define KVM_REQ_IRQ_PENDING	KVM_ARCH_REQ(1)
 
+DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
+
 u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
 int __attribute_const__ kvm_target_cpu(void);
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ea6cb5b24258..e7218cf7df2a 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -47,6 +47,8 @@
 	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
 #define KVM_REQ_IRQ_PENDING	KVM_ARCH_REQ(1)
 
+DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
+
 int __attribute_const__ kvm_target_cpu(void);
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
 int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext);
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index d845d67b7062..cfcd0323deab 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -103,7 +103,8 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
 	if (kvm_timer_irq_can_fire(vtimer))
 		kvm_timer_update_irq(vcpu, true, vtimer);
 
-	if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
+	if (static_branch_unlikely(&userspace_irqchip_in_use) &&
+	    unlikely(!irqchip_in_kernel(vcpu->kvm)))
 		kvm_vtimer_update_mask_user(vcpu);
 
 	return IRQ_HANDLED;
@@ -284,7 +285,8 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
 	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_ctx->irq.irq,
 				   timer_ctx->irq.level);
 
-	if (likely(irqchip_in_kernel(vcpu->kvm))) {
+	if (!static_branch_unlikely(&userspace_irqchip_in_use) &&
+	    likely(irqchip_in_kernel(vcpu->kvm))) {
 		ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
 					  timer_ctx->irq.irq,
 					  timer_ctx->irq.level,
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 3610e132df8b..0cf0459134ff 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -74,6 +74,8 @@ static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
 	__this_cpu_write(kvm_arm_running_vcpu, vcpu);
 }
 
+DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
+
 /**
  * kvm_arm_get_running_vcpu - get the vcpu running on the current CPU.
  * Must be called from non-preemptible context
@@ -302,6 +304,8 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
 
 void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 {
+	if (vcpu->arch.has_run_once && unlikely(!irqchip_in_kernel(vcpu->kvm)))
+		static_branch_dec(&userspace_irqchip_in_use);
 	kvm_arch_vcpu_free(vcpu);
 }
 
@@ -522,14 +526,22 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
 
 	vcpu->arch.has_run_once = true;
 
-	/*
-	 * Map the VGIC hardware resources before running a vcpu the first
-	 * time on this VM.
-	 */
-	if (unlikely(irqchip_in_kernel(kvm) && !vgic_ready(kvm))) {
-		ret = kvm_vgic_map_resources(kvm);
-		if (ret)
-			return ret;
+	if (likely(irqchip_in_kernel(kvm))) {
+		/*
+		 * Map the VGIC hardware resources before running a vcpu the
+		 * first time on this VM.
+		 */
+		if (unlikely(!vgic_ready(kvm))) {
+			ret = kvm_vgic_map_resources(kvm);
+			if (ret)
+				return ret;
+		}
+	} else {
+		/*
+		 * Tell the rest of the code that there are userspace irqchip
+		 * VMs in the wild.
+		 */
+		static_branch_inc(&userspace_irqchip_in_use);
 	}
 
 	ret = kvm_timer_enable(vcpu);
@@ -664,18 +676,29 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		kvm_vgic_flush_hwstate(vcpu);
 
 		/*
-		 * If we have a singal pending, or need to notify a userspace
-		 * irqchip about timer or PMU level changes, then we exit (and
-		 * update the timer level state in kvm_timer_update_run
-		 * below).
+		 * Exit if we have a singal pending so that we can deliver the
+		 * signal to user space.
 		 */
-		if (signal_pending(current) ||
-		    kvm_timer_should_notify_user(vcpu) ||
-		    kvm_pmu_should_notify_user(vcpu)) {
+		if (signal_pending(current)) {
 			ret = -EINTR;
 			run->exit_reason = KVM_EXIT_INTR;
 		}
 
+		/*
+		 * If we're using a userspace irqchip, then check if we need
+		 * to tell a userspace irqchip about timer or PMU level
+		 * changes and if so, exit to userspace (the actual level
+		 * state gets updated in kvm_timer_update_run and
+		 * kvm_pmu_update_run below.
+		 */
+		if (static_branch_unlikely(&userspace_irqchip_in_use)) {
+			if (kvm_timer_should_notify_user(vcpu) ||
+			    kvm_pmu_should_notify_user(vcpu)) {
+				ret = -EINTR;
+				run->exit_reason = KVM_EXIT_INTR;
+			}
+		}
+
 		/*
 		 * Ensure we set mode to IN_GUEST_MODE after we disable
 		 * interrupts and before the final VCPU requests check.
@@ -688,7 +711,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		    kvm_request_pending(vcpu)) {
 			vcpu->mode = OUTSIDE_GUEST_MODE;
 			kvm_pmu_sync_hwstate(vcpu);
-			kvm_timer_sync_hwstate(vcpu);
+			if (static_branch_unlikely(&userspace_irqchip_in_use))
+				kvm_timer_sync_hwstate(vcpu);
 			kvm_vgic_sync_hwstate(vcpu);
 			local_irq_enable();
 			preempt_enable();
@@ -732,7 +756,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		 * we don't want vtimer interrupts to race with syncing the
 		 * timer virtual interrupt state.
 		 */
-		kvm_timer_sync_hwstate(vcpu);
+		if (static_branch_unlikely(&userspace_irqchip_in_use))
+			kvm_timer_sync_hwstate(vcpu);
 
 		/*
 		 * We may have taken a host interrupt in HYP mode (ie
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 8/9] KVM: arm/arm64: Avoid work when userspace iqchips are not used
@ 2017-12-20 11:36   ` Christoffer Dall
  0 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

We currently check if the VM has a userspace irqchip in several places
along the critical path, and if so, we do some work which is only
required for having an irqchip in userspace.  This is unfortunate, as we
could avoid doing any work entirely, if we didn't have to support
irqchip in userspace.

Realizing the userspace irqchip on ARM is mostly a developer or hobby
feature, and is unlikely to be used in servers or other scenarios where
performance is a priority, we can use a refcounted static key to only
check the irqchip configuration when we have at least one VM that uses
an irqchip in userspace.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm/include/asm/kvm_host.h   |  2 ++
 arch/arm64/include/asm/kvm_host.h |  2 ++
 virt/kvm/arm/arch_timer.c         |  6 ++--
 virt/kvm/arm/arm.c                | 59 ++++++++++++++++++++++++++++-----------
 4 files changed, 50 insertions(+), 19 deletions(-)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index a9f7d3f47134..6394fb99da7f 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -48,6 +48,8 @@
 	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
 #define KVM_REQ_IRQ_PENDING	KVM_ARCH_REQ(1)
 
+DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
+
 u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
 int __attribute_const__ kvm_target_cpu(void);
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ea6cb5b24258..e7218cf7df2a 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -47,6 +47,8 @@
 	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
 #define KVM_REQ_IRQ_PENDING	KVM_ARCH_REQ(1)
 
+DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
+
 int __attribute_const__ kvm_target_cpu(void);
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
 int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext);
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index d845d67b7062..cfcd0323deab 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -103,7 +103,8 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
 	if (kvm_timer_irq_can_fire(vtimer))
 		kvm_timer_update_irq(vcpu, true, vtimer);
 
-	if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
+	if (static_branch_unlikely(&userspace_irqchip_in_use) &&
+	    unlikely(!irqchip_in_kernel(vcpu->kvm)))
 		kvm_vtimer_update_mask_user(vcpu);
 
 	return IRQ_HANDLED;
@@ -284,7 +285,8 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
 	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_ctx->irq.irq,
 				   timer_ctx->irq.level);
 
-	if (likely(irqchip_in_kernel(vcpu->kvm))) {
+	if (!static_branch_unlikely(&userspace_irqchip_in_use) &&
+	    likely(irqchip_in_kernel(vcpu->kvm))) {
 		ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
 					  timer_ctx->irq.irq,
 					  timer_ctx->irq.level,
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 3610e132df8b..0cf0459134ff 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -74,6 +74,8 @@ static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
 	__this_cpu_write(kvm_arm_running_vcpu, vcpu);
 }
 
+DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
+
 /**
  * kvm_arm_get_running_vcpu - get the vcpu running on the current CPU.
  * Must be called from non-preemptible context
@@ -302,6 +304,8 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
 
 void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 {
+	if (vcpu->arch.has_run_once && unlikely(!irqchip_in_kernel(vcpu->kvm)))
+		static_branch_dec(&userspace_irqchip_in_use);
 	kvm_arch_vcpu_free(vcpu);
 }
 
@@ -522,14 +526,22 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
 
 	vcpu->arch.has_run_once = true;
 
-	/*
-	 * Map the VGIC hardware resources before running a vcpu the first
-	 * time on this VM.
-	 */
-	if (unlikely(irqchip_in_kernel(kvm) && !vgic_ready(kvm))) {
-		ret = kvm_vgic_map_resources(kvm);
-		if (ret)
-			return ret;
+	if (likely(irqchip_in_kernel(kvm))) {
+		/*
+		 * Map the VGIC hardware resources before running a vcpu the
+		 * first time on this VM.
+		 */
+		if (unlikely(!vgic_ready(kvm))) {
+			ret = kvm_vgic_map_resources(kvm);
+			if (ret)
+				return ret;
+		}
+	} else {
+		/*
+		 * Tell the rest of the code that there are userspace irqchip
+		 * VMs in the wild.
+		 */
+		static_branch_inc(&userspace_irqchip_in_use);
 	}
 
 	ret = kvm_timer_enable(vcpu);
@@ -664,18 +676,29 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		kvm_vgic_flush_hwstate(vcpu);
 
 		/*
-		 * If we have a singal pending, or need to notify a userspace
-		 * irqchip about timer or PMU level changes, then we exit (and
-		 * update the timer level state in kvm_timer_update_run
-		 * below).
+		 * Exit if we have a singal pending so that we can deliver the
+		 * signal to user space.
 		 */
-		if (signal_pending(current) ||
-		    kvm_timer_should_notify_user(vcpu) ||
-		    kvm_pmu_should_notify_user(vcpu)) {
+		if (signal_pending(current)) {
 			ret = -EINTR;
 			run->exit_reason = KVM_EXIT_INTR;
 		}
 
+		/*
+		 * If we're using a userspace irqchip, then check if we need
+		 * to tell a userspace irqchip about timer or PMU level
+		 * changes and if so, exit to userspace (the actual level
+		 * state gets updated in kvm_timer_update_run and
+		 * kvm_pmu_update_run below.
+		 */
+		if (static_branch_unlikely(&userspace_irqchip_in_use)) {
+			if (kvm_timer_should_notify_user(vcpu) ||
+			    kvm_pmu_should_notify_user(vcpu)) {
+				ret = -EINTR;
+				run->exit_reason = KVM_EXIT_INTR;
+			}
+		}
+
 		/*
 		 * Ensure we set mode to IN_GUEST_MODE after we disable
 		 * interrupts and before the final VCPU requests check.
@@ -688,7 +711,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		    kvm_request_pending(vcpu)) {
 			vcpu->mode = OUTSIDE_GUEST_MODE;
 			kvm_pmu_sync_hwstate(vcpu);
-			kvm_timer_sync_hwstate(vcpu);
+			if (static_branch_unlikely(&userspace_irqchip_in_use))
+				kvm_timer_sync_hwstate(vcpu);
 			kvm_vgic_sync_hwstate(vcpu);
 			local_irq_enable();
 			preempt_enable();
@@ -732,7 +756,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		 * we don't want vtimer interrupts to race with syncing the
 		 * timer virtual interrupt state.
 		 */
-		kvm_timer_sync_hwstate(vcpu);
+		if (static_branch_unlikely(&userspace_irqchip_in_use))
+			kvm_timer_sync_hwstate(vcpu);
 
 		/*
 		 * We may have taken a host interrupt in HYP mode (ie
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 9/9] KVM: arm/arm64: Delete outdated forwarded irq documentation
  2017-12-20 11:35 ` Christoffer Dall
@ 2017-12-20 11:36   ` Christoffer Dall
  -1 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:36 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Andre Przywara, kvm

The reason I added this documentation originally was that the concept of
"never taking the interrupt", but just use the timer to generate an exit
from the guest, was confusing to most, and we had to explain it several
times over.  But as we can clearly see, we've failed to update the
documentation as the code has evolved, and people who need to understand
these details are probably better off reading the code.

Let's lighten our maintenance burden slightly and just get rid of this.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt | 187 ---------------------
 1 file changed, 187 deletions(-)
 delete mode 100644 Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt

diff --git a/Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt b/Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt
deleted file mode 100644
index 38bca2835278..000000000000
--- a/Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt
+++ /dev/null
@@ -1,187 +0,0 @@
-KVM/ARM VGIC Forwarded Physical Interrupts
-==========================================
-
-The KVM/ARM code implements software support for the ARM Generic
-Interrupt Controller's (GIC's) hardware support for virtualization by
-allowing software to inject virtual interrupts to a VM, which the guest
-OS sees as regular interrupts.  The code is famously known as the VGIC.
-
-Some of these virtual interrupts, however, correspond to physical
-interrupts from real physical devices.  One example could be the
-architected timer, which itself supports virtualization, and therefore
-lets a guest OS program the hardware device directly to raise an
-interrupt at some point in time.  When such an interrupt is raised, the
-host OS initially handles the interrupt and must somehow signal this
-event as a virtual interrupt to the guest.  Another example could be a
-passthrough device, where the physical interrupts are initially handled
-by the host, but the device driver for the device lives in the guest OS
-and KVM must therefore somehow inject a virtual interrupt on behalf of
-the physical one to the guest OS.
-
-These virtual interrupts corresponding to a physical interrupt on the
-host are called forwarded physical interrupts, but are also sometimes
-referred to as 'virtualized physical interrupts' and 'mapped interrupts'.
-
-Forwarded physical interrupts are handled slightly differently compared
-to virtual interrupts generated purely by a software emulated device.
-
-
-The HW bit
-----------
-Virtual interrupts are signalled to the guest by programming the List
-Registers (LRs) on the GIC before running a VCPU.  The LR is programmed
-with the virtual IRQ number and the state of the interrupt (Pending,
-Active, or Pending+Active).  When the guest ACKs and EOIs a virtual
-interrupt, the LR state moves from Pending to Active, and finally to
-inactive.
-
-The LRs include an extra bit, called the HW bit.  When this bit is set,
-KVM must also program an additional field in the LR, the physical IRQ
-number, to link the virtual with the physical IRQ.
-
-When the HW bit is set, KVM must EITHER set the Pending OR the Active
-bit, never both at the same time.
-
-Setting the HW bit causes the hardware to deactivate the physical
-interrupt on the physical distributor when the guest deactivates the
-corresponding virtual interrupt.
-
-
-Forwarded Physical Interrupts Life Cycle
-----------------------------------------
-
-The state of forwarded physical interrupts is managed in the following way:
-
-  - The physical interrupt is acked by the host, and becomes active on
-    the physical distributor (*).
-  - KVM sets the LR.Pending bit, because this is the only way the GICV
-    interface is going to present it to the guest.
-  - LR.Pending will stay set as long as the guest has not acked the interrupt.
-  - LR.Pending transitions to LR.Active on the guest read of the IAR, as
-    expected.
-  - On guest EOI, the *physical distributor* active bit gets cleared,
-    but the LR.Active is left untouched (set).
-  - KVM clears the LR on VM exits when the physical distributor
-    active state has been cleared.
-
-(*): The host handling is slightly more complicated.  For some forwarded
-interrupts (shared), KVM directly sets the active state on the physical
-distributor before entering the guest, because the interrupt is never actually
-handled on the host (see details on the timer as an example below).  For other
-forwarded interrupts (non-shared) the host does not deactivate the interrupt
-when the host ISR completes, but leaves the interrupt active until the guest
-deactivates it.  Leaving the interrupt active is allowed, because Linux
-configures the physical GIC with EOIMode=1, which causes EOI operations to
-perform a priority drop allowing the GIC to receive other interrupts of the
-default priority.
-
-
-Forwarded Edge and Level Triggered PPIs and SPIs
-------------------------------------------------
-Forwarded physical interrupts injected should always be active on the
-physical distributor when injected to a guest.
-
-Level-triggered interrupts will keep the interrupt line to the GIC
-asserted, typically until the guest programs the device to deassert the
-line.  This means that the interrupt will remain pending on the physical
-distributor until the guest has reprogrammed the device.  Since we
-always run the VM with interrupts enabled on the CPU, a pending
-interrupt will exit the guest as soon as we switch into the guest,
-preventing the guest from ever making progress as the process repeats
-over and over.  Therefore, the active state on the physical distributor
-must be set when entering the guest, preventing the GIC from forwarding
-the pending interrupt to the CPU.  As soon as the guest deactivates the
-interrupt, the physical line is sampled by the hardware again and the host
-takes a new interrupt if and only if the physical line is still asserted.
-
-Edge-triggered interrupts do not exhibit the same problem with
-preventing guest execution that level-triggered interrupts do.  One
-option is to not use HW bit at all, and inject edge-triggered interrupts
-from a physical device as pure virtual interrupts.  But that would
-potentially slow down handling of the interrupt in the guest, because a
-physical interrupt occurring in the middle of the guest ISR would
-preempt the guest for the host to handle the interrupt.  Additionally,
-if you configure the system to handle interrupts on a separate physical
-core from that running your VCPU, you still have to interrupt the VCPU
-to queue the pending state onto the LR, even though the guest won't use
-this information until the guest ISR completes.  Therefore, the HW
-bit should always be set for forwarded edge-triggered interrupts.  With
-the HW bit set, the virtual interrupt is injected and additional
-physical interrupts occurring before the guest deactivates the interrupt
-simply mark the state on the physical distributor as Pending+Active.  As
-soon as the guest deactivates the interrupt, the host takes another
-interrupt if and only if there was a physical interrupt between injecting
-the forwarded interrupt to the guest and the guest deactivating the
-interrupt.
-
-Consequently, whenever we schedule a VCPU with one or more LRs with the
-HW bit set, the interrupt must also be active on the physical
-distributor.
-
-
-Forwarded LPIs
---------------
-LPIs, introduced in GICv3, are always edge-triggered and do not have an
-active state.  They become pending when a device signal them, and as
-soon as they are acked by the CPU, they are inactive again.
-
-It therefore doesn't make sense, and is not supported, to set the HW bit
-for physical LPIs that are forwarded to a VM as virtual interrupts,
-typically virtual SPIs.
-
-For LPIs, there is no other choice than to preempt the VCPU thread if
-necessary, and queue the pending state onto the LR.
-
-
-Putting It Together: The Architected Timer
-------------------------------------------
-The architected timer is a device that signals interrupts with level
-triggered semantics.  The timer hardware is directly accessed by VCPUs
-which program the timer to fire at some point in time.  Each VCPU on a
-system programs the timer to fire at different times, and therefore the
-hardware is multiplexed between multiple VCPUs.  This is implemented by
-context-switching the timer state along with each VCPU thread.
-
-However, this means that a scenario like the following is entirely
-possible, and in fact, typical:
-
-1.  KVM runs the VCPU
-2.  The guest programs the time to fire in T+100
-3.  The guest is idle and calls WFI (wait-for-interrupts)
-4.  The hardware traps to the host
-5.  KVM stores the timer state to memory and disables the hardware timer
-6.  KVM schedules a soft timer to fire in T+(100 - time since step 2)
-7.  KVM puts the VCPU thread to sleep (on a waitqueue)
-8.  The soft timer fires, waking up the VCPU thread
-9.  KVM reprograms the timer hardware with the VCPU's values
-10. KVM marks the timer interrupt as active on the physical distributor
-11. KVM injects a forwarded physical interrupt to the guest
-12. KVM runs the VCPU
-
-Notice that KVM injects a forwarded physical interrupt in step 11 without
-the corresponding interrupt having actually fired on the host.  That is
-exactly why we mark the timer interrupt as active in step 10, because
-the active state on the physical distributor is part of the state
-belonging to the timer hardware, which is context-switched along with
-the VCPU thread.
-
-If the guest does not idle because it is busy, the flow looks like this
-instead:
-
-1.  KVM runs the VCPU
-2.  The guest programs the time to fire in T+100
-4.  At T+100 the timer fires and a physical IRQ causes the VM to exit
-    (note that this initially only traps to EL2 and does not run the host ISR
-    until KVM has returned to the host).
-5.  With interrupts still disabled on the CPU coming back from the guest, KVM
-    stores the virtual timer state to memory and disables the virtual hw timer.
-6.  KVM looks at the timer state (in memory) and injects a forwarded physical
-    interrupt because it concludes the timer has expired.
-7.  KVM marks the timer interrupt as active on the physical distributor
-7.  KVM enables the timer, enables interrupts, and runs the VCPU
-
-Notice that again the forwarded physical interrupt is injected to the
-guest without having actually been handled on the host.  In this case it
-is because the physical interrupt is never actually seen by the host because the
-timer is disabled upon guest return, and the virtual forwarded interrupt is
-injected on the KVM guest entry path.
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v9 9/9] KVM: arm/arm64: Delete outdated forwarded irq documentation
@ 2017-12-20 11:36   ` Christoffer Dall
  0 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2017-12-20 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

The reason I added this documentation originally was that the concept of
"never taking the interrupt", but just use the timer to generate an exit
from the guest, was confusing to most, and we had to explain it several
times over.  But as we can clearly see, we've failed to update the
documentation as the code has evolved, and people who need to understand
these details are probably better off reading the code.

Let's lighten our maintenance burden slightly and just get rid of this.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt | 187 ---------------------
 1 file changed, 187 deletions(-)
 delete mode 100644 Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt

diff --git a/Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt b/Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt
deleted file mode 100644
index 38bca2835278..000000000000
--- a/Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt
+++ /dev/null
@@ -1,187 +0,0 @@
-KVM/ARM VGIC Forwarded Physical Interrupts
-==========================================
-
-The KVM/ARM code implements software support for the ARM Generic
-Interrupt Controller's (GIC's) hardware support for virtualization by
-allowing software to inject virtual interrupts to a VM, which the guest
-OS sees as regular interrupts.  The code is famously known as the VGIC.
-
-Some of these virtual interrupts, however, correspond to physical
-interrupts from real physical devices.  One example could be the
-architected timer, which itself supports virtualization, and therefore
-lets a guest OS program the hardware device directly to raise an
-interrupt at some point in time.  When such an interrupt is raised, the
-host OS initially handles the interrupt and must somehow signal this
-event as a virtual interrupt to the guest.  Another example could be a
-passthrough device, where the physical interrupts are initially handled
-by the host, but the device driver for the device lives in the guest OS
-and KVM must therefore somehow inject a virtual interrupt on behalf of
-the physical one to the guest OS.
-
-These virtual interrupts corresponding to a physical interrupt on the
-host are called forwarded physical interrupts, but are also sometimes
-referred to as 'virtualized physical interrupts' and 'mapped interrupts'.
-
-Forwarded physical interrupts are handled slightly differently compared
-to virtual interrupts generated purely by a software emulated device.
-
-
-The HW bit
-----------
-Virtual interrupts are signalled to the guest by programming the List
-Registers (LRs) on the GIC before running a VCPU.  The LR is programmed
-with the virtual IRQ number and the state of the interrupt (Pending,
-Active, or Pending+Active).  When the guest ACKs and EOIs a virtual
-interrupt, the LR state moves from Pending to Active, and finally to
-inactive.
-
-The LRs include an extra bit, called the HW bit.  When this bit is set,
-KVM must also program an additional field in the LR, the physical IRQ
-number, to link the virtual with the physical IRQ.
-
-When the HW bit is set, KVM must EITHER set the Pending OR the Active
-bit, never both at the same time.
-
-Setting the HW bit causes the hardware to deactivate the physical
-interrupt on the physical distributor when the guest deactivates the
-corresponding virtual interrupt.
-
-
-Forwarded Physical Interrupts Life Cycle
-----------------------------------------
-
-The state of forwarded physical interrupts is managed in the following way:
-
-  - The physical interrupt is acked by the host, and becomes active on
-    the physical distributor (*).
-  - KVM sets the LR.Pending bit, because this is the only way the GICV
-    interface is going to present it to the guest.
-  - LR.Pending will stay set as long as the guest has not acked the interrupt.
-  - LR.Pending transitions to LR.Active on the guest read of the IAR, as
-    expected.
-  - On guest EOI, the *physical distributor* active bit gets cleared,
-    but the LR.Active is left untouched (set).
-  - KVM clears the LR on VM exits when the physical distributor
-    active state has been cleared.
-
-(*): The host handling is slightly more complicated.  For some forwarded
-interrupts (shared), KVM directly sets the active state on the physical
-distributor before entering the guest, because the interrupt is never actually
-handled on the host (see details on the timer as an example below).  For other
-forwarded interrupts (non-shared) the host does not deactivate the interrupt
-when the host ISR completes, but leaves the interrupt active until the guest
-deactivates it.  Leaving the interrupt active is allowed, because Linux
-configures the physical GIC with EOIMode=1, which causes EOI operations to
-perform a priority drop allowing the GIC to receive other interrupts of the
-default priority.
-
-
-Forwarded Edge and Level Triggered PPIs and SPIs
-------------------------------------------------
-Forwarded physical interrupts injected should always be active on the
-physical distributor when injected to a guest.
-
-Level-triggered interrupts will keep the interrupt line to the GIC
-asserted, typically until the guest programs the device to deassert the
-line.  This means that the interrupt will remain pending on the physical
-distributor until the guest has reprogrammed the device.  Since we
-always run the VM with interrupts enabled on the CPU, a pending
-interrupt will exit the guest as soon as we switch into the guest,
-preventing the guest from ever making progress as the process repeats
-over and over.  Therefore, the active state on the physical distributor
-must be set when entering the guest, preventing the GIC from forwarding
-the pending interrupt to the CPU.  As soon as the guest deactivates the
-interrupt, the physical line is sampled by the hardware again and the host
-takes a new interrupt if and only if the physical line is still asserted.
-
-Edge-triggered interrupts do not exhibit the same problem with
-preventing guest execution that level-triggered interrupts do.  One
-option is to not use HW bit at all, and inject edge-triggered interrupts
-from a physical device as pure virtual interrupts.  But that would
-potentially slow down handling of the interrupt in the guest, because a
-physical interrupt occurring in the middle of the guest ISR would
-preempt the guest for the host to handle the interrupt.  Additionally,
-if you configure the system to handle interrupts on a separate physical
-core from that running your VCPU, you still have to interrupt the VCPU
-to queue the pending state onto the LR, even though the guest won't use
-this information until the guest ISR completes.  Therefore, the HW
-bit should always be set for forwarded edge-triggered interrupts.  With
-the HW bit set, the virtual interrupt is injected and additional
-physical interrupts occurring before the guest deactivates the interrupt
-simply mark the state on the physical distributor as Pending+Active.  As
-soon as the guest deactivates the interrupt, the host takes another
-interrupt if and only if there was a physical interrupt between injecting
-the forwarded interrupt to the guest and the guest deactivating the
-interrupt.
-
-Consequently, whenever we schedule a VCPU with one or more LRs with the
-HW bit set, the interrupt must also be active on the physical
-distributor.
-
-
-Forwarded LPIs
---------------
-LPIs, introduced in GICv3, are always edge-triggered and do not have an
-active state.  They become pending when a device signal them, and as
-soon as they are acked by the CPU, they are inactive again.
-
-It therefore doesn't make sense, and is not supported, to set the HW bit
-for physical LPIs that are forwarded to a VM as virtual interrupts,
-typically virtual SPIs.
-
-For LPIs, there is no other choice than to preempt the VCPU thread if
-necessary, and queue the pending state onto the LR.
-
-
-Putting It Together: The Architected Timer
-------------------------------------------
-The architected timer is a device that signals interrupts with level
-triggered semantics.  The timer hardware is directly accessed by VCPUs
-which program the timer to fire at some point in time.  Each VCPU on a
-system programs the timer to fire at different times, and therefore the
-hardware is multiplexed between multiple VCPUs.  This is implemented by
-context-switching the timer state along with each VCPU thread.
-
-However, this means that a scenario like the following is entirely
-possible, and in fact, typical:
-
-1.  KVM runs the VCPU
-2.  The guest programs the time to fire in T+100
-3.  The guest is idle and calls WFI (wait-for-interrupts)
-4.  The hardware traps to the host
-5.  KVM stores the timer state to memory and disables the hardware timer
-6.  KVM schedules a soft timer to fire in T+(100 - time since step 2)
-7.  KVM puts the VCPU thread to sleep (on a waitqueue)
-8.  The soft timer fires, waking up the VCPU thread
-9.  KVM reprograms the timer hardware with the VCPU's values
-10. KVM marks the timer interrupt as active on the physical distributor
-11. KVM injects a forwarded physical interrupt to the guest
-12. KVM runs the VCPU
-
-Notice that KVM injects a forwarded physical interrupt in step 11 without
-the corresponding interrupt having actually fired on the host.  That is
-exactly why we mark the timer interrupt as active in step 10, because
-the active state on the physical distributor is part of the state
-belonging to the timer hardware, which is context-switched along with
-the VCPU thread.
-
-If the guest does not idle because it is busy, the flow looks like this
-instead:
-
-1.  KVM runs the VCPU
-2.  The guest programs the time to fire in T+100
-4.  At T+100 the timer fires and a physical IRQ causes the VM to exit
-    (note that this initially only traps to EL2 and does not run the host ISR
-    until KVM has returned to the host).
-5.  With interrupts still disabled on the CPU coming back from the guest, KVM
-    stores the virtual timer state to memory and disables the virtual hw timer.
-6.  KVM looks at the timer state (in memory) and injects a forwarded physical
-    interrupt because it concludes the timer has expired.
-7.  KVM marks the timer interrupt as active on the physical distributor
-7.  KVM enables the timer, enables interrupts, and runs the VCPU
-
-Notice that again the forwarded physical interrupt is injected to the
-guest without having actually been handled on the host.  In this case it
-is because the physical interrupt is never actually seen by the host because the
-timer is disabled upon guest return, and the virtual forwarded interrupt is
-injected on the KVM guest entry path.
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH v9 8/9] KVM: arm/arm64: Avoid work when userspace iqchips are not used
  2017-12-20 11:36   ` Christoffer Dall
@ 2017-12-27 16:36     ` Marc Zyngier
  -1 siblings, 0 replies; 36+ messages in thread
From: Marc Zyngier @ 2017-12-27 16:36 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Andre Przywara, kvmarm, linux-arm-kernel, kvm

On Wed, 20 Dec 2017 11:36:05 +0000,
Christoffer Dall wrote:
> 
> We currently check if the VM has a userspace irqchip in several places
> along the critical path, and if so, we do some work which is only
> required for having an irqchip in userspace.  This is unfortunate, as we
> could avoid doing any work entirely, if we didn't have to support
> irqchip in userspace.
> 
> Realizing the userspace irqchip on ARM is mostly a developer or hobby
> feature, and is unlikely to be used in servers or other scenarios where
> performance is a priority, we can use a refcounted static key to only
> check the irqchip configuration when we have at least one VM that uses
> an irqchip in userspace.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm/include/asm/kvm_host.h   |  2 ++
>  arch/arm64/include/asm/kvm_host.h |  2 ++
>  virt/kvm/arm/arch_timer.c         |  6 ++--
>  virt/kvm/arm/arm.c                | 59 ++++++++++++++++++++++++++++-----------
>  4 files changed, 50 insertions(+), 19 deletions(-)
> 
> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> index a9f7d3f47134..6394fb99da7f 100644
> --- a/arch/arm/include/asm/kvm_host.h
> +++ b/arch/arm/include/asm/kvm_host.h
> @@ -48,6 +48,8 @@
>  	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
>  #define KVM_REQ_IRQ_PENDING	KVM_ARCH_REQ(1)
>  
> +DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> +
>  u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
>  int __attribute_const__ kvm_target_cpu(void);
>  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index ea6cb5b24258..e7218cf7df2a 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -47,6 +47,8 @@
>  	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
>  #define KVM_REQ_IRQ_PENDING	KVM_ARCH_REQ(1)
>  
> +DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> +
>  int __attribute_const__ kvm_target_cpu(void);
>  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
>  int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext);
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index d845d67b7062..cfcd0323deab 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -103,7 +103,8 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
>  	if (kvm_timer_irq_can_fire(vtimer))
>  		kvm_timer_update_irq(vcpu, true, vtimer);
>  
> -	if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
> +	if (static_branch_unlikely(&userspace_irqchip_in_use) &&
> +	    unlikely(!irqchip_in_kernel(vcpu->kvm)))
>  		kvm_vtimer_update_mask_user(vcpu);
>  
>  	return IRQ_HANDLED;
> @@ -284,7 +285,8 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
>  	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_ctx->irq.irq,
>  				   timer_ctx->irq.level);
>  
> -	if (likely(irqchip_in_kernel(vcpu->kvm))) {
> +	if (!static_branch_unlikely(&userspace_irqchip_in_use) &&
> +	    likely(irqchip_in_kernel(vcpu->kvm))) {
>  		ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
>  					  timer_ctx->irq.irq,
>  					  timer_ctx->irq.level,
> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> index 3610e132df8b..0cf0459134ff 100644
> --- a/virt/kvm/arm/arm.c
> +++ b/virt/kvm/arm/arm.c
> @@ -74,6 +74,8 @@ static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
>  	__this_cpu_write(kvm_arm_running_vcpu, vcpu);
>  }
>  
> +DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> +
>  /**
>   * kvm_arm_get_running_vcpu - get the vcpu running on the current CPU.
>   * Must be called from non-preemptible context
> @@ -302,6 +304,8 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
>  
>  void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
>  {
> +	if (vcpu->arch.has_run_once && unlikely(!irqchip_in_kernel(vcpu->kvm)))
> +		static_branch_dec(&userspace_irqchip_in_use);
>  	kvm_arch_vcpu_free(vcpu);
>  }
>  
> @@ -522,14 +526,22 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
>  
>  	vcpu->arch.has_run_once = true;
>  
> -	/*
> -	 * Map the VGIC hardware resources before running a vcpu the first
> -	 * time on this VM.
> -	 */
> -	if (unlikely(irqchip_in_kernel(kvm) && !vgic_ready(kvm))) {
> -		ret = kvm_vgic_map_resources(kvm);
> -		if (ret)
> -			return ret;
> +	if (likely(irqchip_in_kernel(kvm))) {
> +		/*
> +		 * Map the VGIC hardware resources before running a vcpu the
> +		 * first time on this VM.
> +		 */
> +		if (unlikely(!vgic_ready(kvm))) {
> +			ret = kvm_vgic_map_resources(kvm);
> +			if (ret)
> +				return ret;
> +		}
> +	} else {
> +		/*
> +		 * Tell the rest of the code that there are userspace irqchip
> +		 * VMs in the wild.
> +		 */
> +		static_branch_inc(&userspace_irqchip_in_use);
>  	}
>  
>  	ret = kvm_timer_enable(vcpu);
> @@ -664,18 +676,29 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  		kvm_vgic_flush_hwstate(vcpu);
>  
>  		/*
> -		 * If we have a singal pending, or need to notify a userspace
> -		 * irqchip about timer or PMU level changes, then we exit (and
> -		 * update the timer level state in kvm_timer_update_run
> -		 * below).
> +		 * Exit if we have a singal pending so that we can deliver the

nit: s/singal/signal/

> +		 * signal to user space.
>  		 */
> -		if (signal_pending(current) ||
> -		    kvm_timer_should_notify_user(vcpu) ||
> -		    kvm_pmu_should_notify_user(vcpu)) {
> +		if (signal_pending(current)) {
>  			ret = -EINTR;
>  			run->exit_reason = KVM_EXIT_INTR;
>  		}
>  
> +		/*
> +		 * If we're using a userspace irqchip, then check if we need
> +		 * to tell a userspace irqchip about timer or PMU level
> +		 * changes and if so, exit to userspace (the actual level
> +		 * state gets updated in kvm_timer_update_run and
> +		 * kvm_pmu_update_run below.

nit: missing closing parenthesis.

> +		 */
> +		if (static_branch_unlikely(&userspace_irqchip_in_use)) {
> +			if (kvm_timer_should_notify_user(vcpu) ||
> +			    kvm_pmu_should_notify_user(vcpu)) {
> +				ret = -EINTR;
> +				run->exit_reason = KVM_EXIT_INTR;
> +			}
> +		}
> +
>  		/*
>  		 * Ensure we set mode to IN_GUEST_MODE after we disable
>  		 * interrupts and before the final VCPU requests check.
> @@ -688,7 +711,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  		    kvm_request_pending(vcpu)) {
>  			vcpu->mode = OUTSIDE_GUEST_MODE;
>  			kvm_pmu_sync_hwstate(vcpu);
> -			kvm_timer_sync_hwstate(vcpu);
> +			if (static_branch_unlikely(&userspace_irqchip_in_use))
> +				kvm_timer_sync_hwstate(vcpu);
>  			kvm_vgic_sync_hwstate(vcpu);
>  			local_irq_enable();
>  			preempt_enable();
> @@ -732,7 +756,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  		 * we don't want vtimer interrupts to race with syncing the
>  		 * timer virtual interrupt state.
>  		 */
> -		kvm_timer_sync_hwstate(vcpu);
> +		if (static_branch_unlikely(&userspace_irqchip_in_use))
> +			kvm_timer_sync_hwstate(vcpu);
>  
>  		/*
>  		 * We may have taken a host interrupt in HYP mode (ie
> -- 
> 2.14.2
> 

Other than the trivial nits above:

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v9 8/9] KVM: arm/arm64: Avoid work when userspace iqchips are not used
@ 2017-12-27 16:36     ` Marc Zyngier
  0 siblings, 0 replies; 36+ messages in thread
From: Marc Zyngier @ 2017-12-27 16:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 20 Dec 2017 11:36:05 +0000,
Christoffer Dall wrote:
> 
> We currently check if the VM has a userspace irqchip in several places
> along the critical path, and if so, we do some work which is only
> required for having an irqchip in userspace.  This is unfortunate, as we
> could avoid doing any work entirely, if we didn't have to support
> irqchip in userspace.
> 
> Realizing the userspace irqchip on ARM is mostly a developer or hobby
> feature, and is unlikely to be used in servers or other scenarios where
> performance is a priority, we can use a refcounted static key to only
> check the irqchip configuration when we have at least one VM that uses
> an irqchip in userspace.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm/include/asm/kvm_host.h   |  2 ++
>  arch/arm64/include/asm/kvm_host.h |  2 ++
>  virt/kvm/arm/arch_timer.c         |  6 ++--
>  virt/kvm/arm/arm.c                | 59 ++++++++++++++++++++++++++++-----------
>  4 files changed, 50 insertions(+), 19 deletions(-)
> 
> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> index a9f7d3f47134..6394fb99da7f 100644
> --- a/arch/arm/include/asm/kvm_host.h
> +++ b/arch/arm/include/asm/kvm_host.h
> @@ -48,6 +48,8 @@
>  	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
>  #define KVM_REQ_IRQ_PENDING	KVM_ARCH_REQ(1)
>  
> +DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> +
>  u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
>  int __attribute_const__ kvm_target_cpu(void);
>  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index ea6cb5b24258..e7218cf7df2a 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -47,6 +47,8 @@
>  	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
>  #define KVM_REQ_IRQ_PENDING	KVM_ARCH_REQ(1)
>  
> +DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> +
>  int __attribute_const__ kvm_target_cpu(void);
>  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
>  int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext);
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index d845d67b7062..cfcd0323deab 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -103,7 +103,8 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
>  	if (kvm_timer_irq_can_fire(vtimer))
>  		kvm_timer_update_irq(vcpu, true, vtimer);
>  
> -	if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
> +	if (static_branch_unlikely(&userspace_irqchip_in_use) &&
> +	    unlikely(!irqchip_in_kernel(vcpu->kvm)))
>  		kvm_vtimer_update_mask_user(vcpu);
>  
>  	return IRQ_HANDLED;
> @@ -284,7 +285,8 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
>  	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_ctx->irq.irq,
>  				   timer_ctx->irq.level);
>  
> -	if (likely(irqchip_in_kernel(vcpu->kvm))) {
> +	if (!static_branch_unlikely(&userspace_irqchip_in_use) &&
> +	    likely(irqchip_in_kernel(vcpu->kvm))) {
>  		ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
>  					  timer_ctx->irq.irq,
>  					  timer_ctx->irq.level,
> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> index 3610e132df8b..0cf0459134ff 100644
> --- a/virt/kvm/arm/arm.c
> +++ b/virt/kvm/arm/arm.c
> @@ -74,6 +74,8 @@ static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
>  	__this_cpu_write(kvm_arm_running_vcpu, vcpu);
>  }
>  
> +DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> +
>  /**
>   * kvm_arm_get_running_vcpu - get the vcpu running on the current CPU.
>   * Must be called from non-preemptible context
> @@ -302,6 +304,8 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
>  
>  void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
>  {
> +	if (vcpu->arch.has_run_once && unlikely(!irqchip_in_kernel(vcpu->kvm)))
> +		static_branch_dec(&userspace_irqchip_in_use);
>  	kvm_arch_vcpu_free(vcpu);
>  }
>  
> @@ -522,14 +526,22 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
>  
>  	vcpu->arch.has_run_once = true;
>  
> -	/*
> -	 * Map the VGIC hardware resources before running a vcpu the first
> -	 * time on this VM.
> -	 */
> -	if (unlikely(irqchip_in_kernel(kvm) && !vgic_ready(kvm))) {
> -		ret = kvm_vgic_map_resources(kvm);
> -		if (ret)
> -			return ret;
> +	if (likely(irqchip_in_kernel(kvm))) {
> +		/*
> +		 * Map the VGIC hardware resources before running a vcpu the
> +		 * first time on this VM.
> +		 */
> +		if (unlikely(!vgic_ready(kvm))) {
> +			ret = kvm_vgic_map_resources(kvm);
> +			if (ret)
> +				return ret;
> +		}
> +	} else {
> +		/*
> +		 * Tell the rest of the code that there are userspace irqchip
> +		 * VMs in the wild.
> +		 */
> +		static_branch_inc(&userspace_irqchip_in_use);
>  	}
>  
>  	ret = kvm_timer_enable(vcpu);
> @@ -664,18 +676,29 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  		kvm_vgic_flush_hwstate(vcpu);
>  
>  		/*
> -		 * If we have a singal pending, or need to notify a userspace
> -		 * irqchip about timer or PMU level changes, then we exit (and
> -		 * update the timer level state in kvm_timer_update_run
> -		 * below).
> +		 * Exit if we have a singal pending so that we can deliver the

nit: s/singal/signal/

> +		 * signal to user space.
>  		 */
> -		if (signal_pending(current) ||
> -		    kvm_timer_should_notify_user(vcpu) ||
> -		    kvm_pmu_should_notify_user(vcpu)) {
> +		if (signal_pending(current)) {
>  			ret = -EINTR;
>  			run->exit_reason = KVM_EXIT_INTR;
>  		}
>  
> +		/*
> +		 * If we're using a userspace irqchip, then check if we need
> +		 * to tell a userspace irqchip about timer or PMU level
> +		 * changes and if so, exit to userspace (the actual level
> +		 * state gets updated in kvm_timer_update_run and
> +		 * kvm_pmu_update_run below.

nit: missing closing parenthesis.

> +		 */
> +		if (static_branch_unlikely(&userspace_irqchip_in_use)) {
> +			if (kvm_timer_should_notify_user(vcpu) ||
> +			    kvm_pmu_should_notify_user(vcpu)) {
> +				ret = -EINTR;
> +				run->exit_reason = KVM_EXIT_INTR;
> +			}
> +		}
> +
>  		/*
>  		 * Ensure we set mode to IN_GUEST_MODE after we disable
>  		 * interrupts and before the final VCPU requests check.
> @@ -688,7 +711,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  		    kvm_request_pending(vcpu)) {
>  			vcpu->mode = OUTSIDE_GUEST_MODE;
>  			kvm_pmu_sync_hwstate(vcpu);
> -			kvm_timer_sync_hwstate(vcpu);
> +			if (static_branch_unlikely(&userspace_irqchip_in_use))
> +				kvm_timer_sync_hwstate(vcpu);
>  			kvm_vgic_sync_hwstate(vcpu);
>  			local_irq_enable();
>  			preempt_enable();
> @@ -732,7 +756,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  		 * we don't want vtimer interrupts to race with syncing the
>  		 * timer virtual interrupt state.
>  		 */
> -		kvm_timer_sync_hwstate(vcpu);
> +		if (static_branch_unlikely(&userspace_irqchip_in_use))
> +			kvm_timer_sync_hwstate(vcpu);
>  
>  		/*
>  		 * We may have taken a host interrupt in HYP mode (ie
> -- 
> 2.14.2
> 

Other than the trivial nits above:

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v9 9/9] KVM: arm/arm64: Delete outdated forwarded irq documentation
  2017-12-20 11:36   ` Christoffer Dall
@ 2017-12-27 16:37     ` Marc Zyngier
  -1 siblings, 0 replies; 36+ messages in thread
From: Marc Zyngier @ 2017-12-27 16:37 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvmarm, linux-arm-kernel, kvm, Andre Przywara, Eric Auger

On Wed, 20 Dec 2017 11:36:06 +0000,
Christoffer Dall wrote:
> 
> The reason I added this documentation originally was that the concept of
> "never taking the interrupt", but just use the timer to generate an exit
> from the guest, was confusing to most, and we had to explain it several
> times over.  But as we can clearly see, we've failed to update the
> documentation as the code has evolved, and people who need to understand
> these details are probably better off reading the code.
> 
> Let's lighten our maintenance burden slightly and just get rid of this.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt | 187 ---------------------
>  1 file changed, 187 deletions(-)
>  delete mode 100644 Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v9 9/9] KVM: arm/arm64: Delete outdated forwarded irq documentation
@ 2017-12-27 16:37     ` Marc Zyngier
  0 siblings, 0 replies; 36+ messages in thread
From: Marc Zyngier @ 2017-12-27 16:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 20 Dec 2017 11:36:06 +0000,
Christoffer Dall wrote:
> 
> The reason I added this documentation originally was that the concept of
> "never taking the interrupt", but just use the timer to generate an exit
> from the guest, was confusing to most, and we had to explain it several
> times over.  But as we can clearly see, we've failed to update the
> documentation as the code has evolved, and people who need to understand
> these details are probably better off reading the code.
> 
> Let's lighten our maintenance burden slightly and just get rid of this.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt | 187 ---------------------
>  1 file changed, 187 deletions(-)
>  delete mode 100644 Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v9 8/9] KVM: arm/arm64: Avoid work when userspace iqchips are not used
  2017-12-27 16:36     ` Marc Zyngier
@ 2018-01-02  9:09       ` Christoffer Dall
  -1 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2018-01-02  9:09 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: kvmarm, linux-arm-kernel, kvm, Andre Przywara, Eric Auger

On Wed, Dec 27, 2017 at 04:36:04PM +0000, Marc Zyngier wrote:
> On Wed, 20 Dec 2017 11:36:05 +0000,
> Christoffer Dall wrote:
> > 
> > We currently check if the VM has a userspace irqchip in several places
> > along the critical path, and if so, we do some work which is only
> > required for having an irqchip in userspace.  This is unfortunate, as we
> > could avoid doing any work entirely, if we didn't have to support
> > irqchip in userspace.
> > 
> > Realizing the userspace irqchip on ARM is mostly a developer or hobby
> > feature, and is unlikely to be used in servers or other scenarios where
> > performance is a priority, we can use a refcounted static key to only
> > check the irqchip configuration when we have at least one VM that uses
> > an irqchip in userspace.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> >  arch/arm/include/asm/kvm_host.h   |  2 ++
> >  arch/arm64/include/asm/kvm_host.h |  2 ++
> >  virt/kvm/arm/arch_timer.c         |  6 ++--
> >  virt/kvm/arm/arm.c                | 59 ++++++++++++++++++++++++++++-----------
> >  4 files changed, 50 insertions(+), 19 deletions(-)
> > 
> > diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> > index a9f7d3f47134..6394fb99da7f 100644
> > --- a/arch/arm/include/asm/kvm_host.h
> > +++ b/arch/arm/include/asm/kvm_host.h
> > @@ -48,6 +48,8 @@
> >  	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
> >  #define KVM_REQ_IRQ_PENDING	KVM_ARCH_REQ(1)
> >  
> > +DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> > +
> >  u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
> >  int __attribute_const__ kvm_target_cpu(void);
> >  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index ea6cb5b24258..e7218cf7df2a 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -47,6 +47,8 @@
> >  	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
> >  #define KVM_REQ_IRQ_PENDING	KVM_ARCH_REQ(1)
> >  
> > +DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> > +
> >  int __attribute_const__ kvm_target_cpu(void);
> >  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> >  int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext);
> > diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> > index d845d67b7062..cfcd0323deab 100644
> > --- a/virt/kvm/arm/arch_timer.c
> > +++ b/virt/kvm/arm/arch_timer.c
> > @@ -103,7 +103,8 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
> >  	if (kvm_timer_irq_can_fire(vtimer))
> >  		kvm_timer_update_irq(vcpu, true, vtimer);
> >  
> > -	if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
> > +	if (static_branch_unlikely(&userspace_irqchip_in_use) &&
> > +	    unlikely(!irqchip_in_kernel(vcpu->kvm)))
> >  		kvm_vtimer_update_mask_user(vcpu);
> >  
> >  	return IRQ_HANDLED;
> > @@ -284,7 +285,8 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
> >  	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_ctx->irq.irq,
> >  				   timer_ctx->irq.level);
> >  
> > -	if (likely(irqchip_in_kernel(vcpu->kvm))) {
> > +	if (!static_branch_unlikely(&userspace_irqchip_in_use) &&
> > +	    likely(irqchip_in_kernel(vcpu->kvm))) {
> >  		ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
> >  					  timer_ctx->irq.irq,
> >  					  timer_ctx->irq.level,
> > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > index 3610e132df8b..0cf0459134ff 100644
> > --- a/virt/kvm/arm/arm.c
> > +++ b/virt/kvm/arm/arm.c
> > @@ -74,6 +74,8 @@ static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
> >  	__this_cpu_write(kvm_arm_running_vcpu, vcpu);
> >  }
> >  
> > +DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> > +
> >  /**
> >   * kvm_arm_get_running_vcpu - get the vcpu running on the current CPU.
> >   * Must be called from non-preemptible context
> > @@ -302,6 +304,8 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
> >  
> >  void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
> >  {
> > +	if (vcpu->arch.has_run_once && unlikely(!irqchip_in_kernel(vcpu->kvm)))
> > +		static_branch_dec(&userspace_irqchip_in_use);
> >  	kvm_arch_vcpu_free(vcpu);
> >  }
> >  
> > @@ -522,14 +526,22 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
> >  
> >  	vcpu->arch.has_run_once = true;
> >  
> > -	/*
> > -	 * Map the VGIC hardware resources before running a vcpu the first
> > -	 * time on this VM.
> > -	 */
> > -	if (unlikely(irqchip_in_kernel(kvm) && !vgic_ready(kvm))) {
> > -		ret = kvm_vgic_map_resources(kvm);
> > -		if (ret)
> > -			return ret;
> > +	if (likely(irqchip_in_kernel(kvm))) {
> > +		/*
> > +		 * Map the VGIC hardware resources before running a vcpu the
> > +		 * first time on this VM.
> > +		 */
> > +		if (unlikely(!vgic_ready(kvm))) {
> > +			ret = kvm_vgic_map_resources(kvm);
> > +			if (ret)
> > +				return ret;
> > +		}
> > +	} else {
> > +		/*
> > +		 * Tell the rest of the code that there are userspace irqchip
> > +		 * VMs in the wild.
> > +		 */
> > +		static_branch_inc(&userspace_irqchip_in_use);
> >  	}
> >  
> >  	ret = kvm_timer_enable(vcpu);
> > @@ -664,18 +676,29 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >  		kvm_vgic_flush_hwstate(vcpu);
> >  
> >  		/*
> > -		 * If we have a singal pending, or need to notify a userspace
> > -		 * irqchip about timer or PMU level changes, then we exit (and
> > -		 * update the timer level state in kvm_timer_update_run
> > -		 * below).
> > +		 * Exit if we have a singal pending so that we can deliver the
> 
> nit: s/singal/signal/
> 

dang, one more.

> > +		 * signal to user space.
> >  		 */
> > -		if (signal_pending(current) ||
> > -		    kvm_timer_should_notify_user(vcpu) ||
> > -		    kvm_pmu_should_notify_user(vcpu)) {
> > +		if (signal_pending(current)) {
> >  			ret = -EINTR;
> >  			run->exit_reason = KVM_EXIT_INTR;
> >  		}
> >  
> > +		/*
> > +		 * If we're using a userspace irqchip, then check if we need
> > +		 * to tell a userspace irqchip about timer or PMU level
> > +		 * changes and if so, exit to userspace (the actual level
> > +		 * state gets updated in kvm_timer_update_run and
> > +		 * kvm_pmu_update_run below.
> 
> nit: missing closing parenthesis.
> 
> > +		 */
> > +		if (static_branch_unlikely(&userspace_irqchip_in_use)) {
> > +			if (kvm_timer_should_notify_user(vcpu) ||
> > +			    kvm_pmu_should_notify_user(vcpu)) {
> > +				ret = -EINTR;
> > +				run->exit_reason = KVM_EXIT_INTR;
> > +			}
> > +		}
> > +
> >  		/*
> >  		 * Ensure we set mode to IN_GUEST_MODE after we disable
> >  		 * interrupts and before the final VCPU requests check.
> > @@ -688,7 +711,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >  		    kvm_request_pending(vcpu)) {
> >  			vcpu->mode = OUTSIDE_GUEST_MODE;
> >  			kvm_pmu_sync_hwstate(vcpu);
> > -			kvm_timer_sync_hwstate(vcpu);
> > +			if (static_branch_unlikely(&userspace_irqchip_in_use))
> > +				kvm_timer_sync_hwstate(vcpu);
> >  			kvm_vgic_sync_hwstate(vcpu);
> >  			local_irq_enable();
> >  			preempt_enable();
> > @@ -732,7 +756,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >  		 * we don't want vtimer interrupts to race with syncing the
> >  		 * timer virtual interrupt state.
> >  		 */
> > -		kvm_timer_sync_hwstate(vcpu);
> > +		if (static_branch_unlikely(&userspace_irqchip_in_use))
> > +			kvm_timer_sync_hwstate(vcpu);
> >  
> >  		/*
> >  		 * We may have taken a host interrupt in HYP mode (ie
> > -- 
> > 2.14.2
> > 
> 
> Other than the trivial nits above:
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> 
Thanks for this.

I've now queued this series and pushed it to kvmarm/next.

-Christoffer

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v9 8/9] KVM: arm/arm64: Avoid work when userspace iqchips are not used
@ 2018-01-02  9:09       ` Christoffer Dall
  0 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2018-01-02  9:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Dec 27, 2017 at 04:36:04PM +0000, Marc Zyngier wrote:
> On Wed, 20 Dec 2017 11:36:05 +0000,
> Christoffer Dall wrote:
> > 
> > We currently check if the VM has a userspace irqchip in several places
> > along the critical path, and if so, we do some work which is only
> > required for having an irqchip in userspace.  This is unfortunate, as we
> > could avoid doing any work entirely, if we didn't have to support
> > irqchip in userspace.
> > 
> > Realizing the userspace irqchip on ARM is mostly a developer or hobby
> > feature, and is unlikely to be used in servers or other scenarios where
> > performance is a priority, we can use a refcounted static key to only
> > check the irqchip configuration when we have at least one VM that uses
> > an irqchip in userspace.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> >  arch/arm/include/asm/kvm_host.h   |  2 ++
> >  arch/arm64/include/asm/kvm_host.h |  2 ++
> >  virt/kvm/arm/arch_timer.c         |  6 ++--
> >  virt/kvm/arm/arm.c                | 59 ++++++++++++++++++++++++++++-----------
> >  4 files changed, 50 insertions(+), 19 deletions(-)
> > 
> > diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> > index a9f7d3f47134..6394fb99da7f 100644
> > --- a/arch/arm/include/asm/kvm_host.h
> > +++ b/arch/arm/include/asm/kvm_host.h
> > @@ -48,6 +48,8 @@
> >  	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
> >  #define KVM_REQ_IRQ_PENDING	KVM_ARCH_REQ(1)
> >  
> > +DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> > +
> >  u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
> >  int __attribute_const__ kvm_target_cpu(void);
> >  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index ea6cb5b24258..e7218cf7df2a 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -47,6 +47,8 @@
> >  	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
> >  #define KVM_REQ_IRQ_PENDING	KVM_ARCH_REQ(1)
> >  
> > +DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> > +
> >  int __attribute_const__ kvm_target_cpu(void);
> >  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> >  int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext);
> > diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> > index d845d67b7062..cfcd0323deab 100644
> > --- a/virt/kvm/arm/arch_timer.c
> > +++ b/virt/kvm/arm/arch_timer.c
> > @@ -103,7 +103,8 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
> >  	if (kvm_timer_irq_can_fire(vtimer))
> >  		kvm_timer_update_irq(vcpu, true, vtimer);
> >  
> > -	if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
> > +	if (static_branch_unlikely(&userspace_irqchip_in_use) &&
> > +	    unlikely(!irqchip_in_kernel(vcpu->kvm)))
> >  		kvm_vtimer_update_mask_user(vcpu);
> >  
> >  	return IRQ_HANDLED;
> > @@ -284,7 +285,8 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
> >  	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_ctx->irq.irq,
> >  				   timer_ctx->irq.level);
> >  
> > -	if (likely(irqchip_in_kernel(vcpu->kvm))) {
> > +	if (!static_branch_unlikely(&userspace_irqchip_in_use) &&
> > +	    likely(irqchip_in_kernel(vcpu->kvm))) {
> >  		ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
> >  					  timer_ctx->irq.irq,
> >  					  timer_ctx->irq.level,
> > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > index 3610e132df8b..0cf0459134ff 100644
> > --- a/virt/kvm/arm/arm.c
> > +++ b/virt/kvm/arm/arm.c
> > @@ -74,6 +74,8 @@ static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
> >  	__this_cpu_write(kvm_arm_running_vcpu, vcpu);
> >  }
> >  
> > +DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> > +
> >  /**
> >   * kvm_arm_get_running_vcpu - get the vcpu running on the current CPU.
> >   * Must be called from non-preemptible context
> > @@ -302,6 +304,8 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
> >  
> >  void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
> >  {
> > +	if (vcpu->arch.has_run_once && unlikely(!irqchip_in_kernel(vcpu->kvm)))
> > +		static_branch_dec(&userspace_irqchip_in_use);
> >  	kvm_arch_vcpu_free(vcpu);
> >  }
> >  
> > @@ -522,14 +526,22 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
> >  
> >  	vcpu->arch.has_run_once = true;
> >  
> > -	/*
> > -	 * Map the VGIC hardware resources before running a vcpu the first
> > -	 * time on this VM.
> > -	 */
> > -	if (unlikely(irqchip_in_kernel(kvm) && !vgic_ready(kvm))) {
> > -		ret = kvm_vgic_map_resources(kvm);
> > -		if (ret)
> > -			return ret;
> > +	if (likely(irqchip_in_kernel(kvm))) {
> > +		/*
> > +		 * Map the VGIC hardware resources before running a vcpu the
> > +		 * first time on this VM.
> > +		 */
> > +		if (unlikely(!vgic_ready(kvm))) {
> > +			ret = kvm_vgic_map_resources(kvm);
> > +			if (ret)
> > +				return ret;
> > +		}
> > +	} else {
> > +		/*
> > +		 * Tell the rest of the code that there are userspace irqchip
> > +		 * VMs in the wild.
> > +		 */
> > +		static_branch_inc(&userspace_irqchip_in_use);
> >  	}
> >  
> >  	ret = kvm_timer_enable(vcpu);
> > @@ -664,18 +676,29 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >  		kvm_vgic_flush_hwstate(vcpu);
> >  
> >  		/*
> > -		 * If we have a singal pending, or need to notify a userspace
> > -		 * irqchip about timer or PMU level changes, then we exit (and
> > -		 * update the timer level state in kvm_timer_update_run
> > -		 * below).
> > +		 * Exit if we have a singal pending so that we can deliver the
> 
> nit: s/singal/signal/
> 

dang, one more.

> > +		 * signal to user space.
> >  		 */
> > -		if (signal_pending(current) ||
> > -		    kvm_timer_should_notify_user(vcpu) ||
> > -		    kvm_pmu_should_notify_user(vcpu)) {
> > +		if (signal_pending(current)) {
> >  			ret = -EINTR;
> >  			run->exit_reason = KVM_EXIT_INTR;
> >  		}
> >  
> > +		/*
> > +		 * If we're using a userspace irqchip, then check if we need
> > +		 * to tell a userspace irqchip about timer or PMU level
> > +		 * changes and if so, exit to userspace (the actual level
> > +		 * state gets updated in kvm_timer_update_run and
> > +		 * kvm_pmu_update_run below.
> 
> nit: missing closing parenthesis.
> 
> > +		 */
> > +		if (static_branch_unlikely(&userspace_irqchip_in_use)) {
> > +			if (kvm_timer_should_notify_user(vcpu) ||
> > +			    kvm_pmu_should_notify_user(vcpu)) {
> > +				ret = -EINTR;
> > +				run->exit_reason = KVM_EXIT_INTR;
> > +			}
> > +		}
> > +
> >  		/*
> >  		 * Ensure we set mode to IN_GUEST_MODE after we disable
> >  		 * interrupts and before the final VCPU requests check.
> > @@ -688,7 +711,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >  		    kvm_request_pending(vcpu)) {
> >  			vcpu->mode = OUTSIDE_GUEST_MODE;
> >  			kvm_pmu_sync_hwstate(vcpu);
> > -			kvm_timer_sync_hwstate(vcpu);
> > +			if (static_branch_unlikely(&userspace_irqchip_in_use))
> > +				kvm_timer_sync_hwstate(vcpu);
> >  			kvm_vgic_sync_hwstate(vcpu);
> >  			local_irq_enable();
> >  			preempt_enable();
> > @@ -732,7 +756,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >  		 * we don't want vtimer interrupts to race with syncing the
> >  		 * timer virtual interrupt state.
> >  		 */
> > -		kvm_timer_sync_hwstate(vcpu);
> > +		if (static_branch_unlikely(&userspace_irqchip_in_use))
> > +			kvm_timer_sync_hwstate(vcpu);
> >  
> >  		/*
> >  		 * We may have taken a host interrupt in HYP mode (ie
> > -- 
> > 2.14.2
> > 
> 
> Other than the trivial nits above:
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> 
Thanks for this.

I've now queued this series and pushed it to kvmarm/next.

-Christoffer

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v9 7/9] KVM: arm/arm64: Provide a get_input_level for the arch timer
  2017-12-20 11:36   ` Christoffer Dall
@ 2018-01-22 12:32     ` Tomasz Nowicki
  -1 siblings, 0 replies; 36+ messages in thread
From: Tomasz Nowicki @ 2018-01-22 12:32 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: Marc Zyngier, Andre Przywara, kvm

Hello Christoffer,

Please see my observations/comments below.

On 20.12.2017 12:36, Christoffer Dall wrote:
> The VGIC can now support the life-cycle of mapped level-triggered
> interrupts, and we no longer have to read back the timer state on every
> exit from the VM if we had an asserted timer interrupt signal, because
> the VGIC already knows if we hit the unlikely case where the guest
> disables the timer without ACKing the virtual timer interrupt.
> 
> This means we rework a bit of the code to factor out the functionality
> to snapshot the timer state from vtimer_save_state(), and we can reuse
> this functionality in the sync path when we have an irqchip in
> userspace, and also to support our implementation of the
> get_input_level() function for the timer.
> 
> This change also means that we can no longer rely on the timer's view of
> the interrupt line to set the active state, because we no longer
> maintain this state for mapped interrupts when exiting from the guest.
> Instead, we only set the active state if the virtual interrupt is
> active, and otherwise we simply let the timer fire again and raise the
> virtual interrupt from the ISR.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>   include/kvm/arm_arch_timer.h |  2 ++
>   virt/kvm/arm/arch_timer.c    | 84 ++++++++++++++++++++------------------------
>   2 files changed, 40 insertions(+), 46 deletions(-)
> 
> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> index 6e45608b2399..b1dcfde0a3ef 100644
> --- a/include/kvm/arm_arch_timer.h
> +++ b/include/kvm/arm_arch_timer.h
> @@ -90,6 +90,8 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
>   
>   void kvm_timer_init_vhe(void);
>   
> +bool kvm_arch_timer_get_input_level(int vintid);
> +
>   #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.vtimer)
>   #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.ptimer)
>   
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index fb0533ed903d..d845d67b7062 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -343,6 +343,12 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
>   	phys_timer_emulate(vcpu);
>   }
>   
> +static void __timer_snapshot_state(struct arch_timer_context *timer)
> +{
> +	timer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> +	timer->cnt_cval = read_sysreg_el0(cntv_cval);
> +}
> +
>   static void vtimer_save_state(struct kvm_vcpu *vcpu)
>   {
>   	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> @@ -354,10 +360,8 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
>   	if (!vtimer->loaded)
>   		goto out;
>   
> -	if (timer->enabled) {
> -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> -	}
> +	if (timer->enabled)
> +		__timer_snapshot_state(vtimer);
>   
>   	/* Disable the virtual timer */
>   	write_sysreg_el0(0, cntv_ctl);
> @@ -454,8 +458,7 @@ static void kvm_timer_vcpu_load_vgic(struct kvm_vcpu *vcpu)
>   	bool phys_active;
>   	int ret;
>   
> -	phys_active = vtimer->irq.level ||
> -		      kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
> +	phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
>   
>   	ret = irq_set_irqchip_state(host_vtimer_irq,
>   				    IRQCHIP_STATE_ACTIVE,
> @@ -535,54 +538,27 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
>   	set_cntvoff(0);
>   }
>   
> -static void unmask_vtimer_irq(struct kvm_vcpu *vcpu)
> +/*
> + * With a userspace irqchip we have to check if the guest de-asserted the
> + * timer and if so, unmask the timer irq signal on the host interrupt
> + * controller to ensure that we see future timer signals.
> + */
> +static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
>   {
>   	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>   
>   	if (unlikely(!irqchip_in_kernel(vcpu->kvm))) {
> -		kvm_vtimer_update_mask_user(vcpu);
> -		return;
> -	}
> -
> -	/*
> -	 * If the guest disabled the timer without acking the interrupt, then
> -	 * we must make sure the physical and virtual active states are in
> -	 * sync by deactivating the physical interrupt, because otherwise we
> -	 * wouldn't see the next timer interrupt in the host.
> -	 */
> -	if (!kvm_vgic_map_is_active(vcpu, vtimer->irq.irq)) {
> -		int ret;
> -		ret = irq_set_irqchip_state(host_vtimer_irq,
> -					    IRQCHIP_STATE_ACTIVE,
> -					    false);
> -		WARN_ON(ret);
> +		__timer_snapshot_state(vtimer);
> +		if (!kvm_timer_should_fire(vtimer)) {
> +			kvm_timer_update_irq(vcpu, false, vtimer);
> +			kvm_vtimer_update_mask_user(vcpu);
> +		}
>   	}
>   }
>   
> -/**
> - * kvm_timer_sync_hwstate - sync timer state from cpu
> - * @vcpu: The vcpu pointer
> - *
> - * Check if any of the timers have expired while we were running in the guest,
> - * and inject an interrupt if that was the case.
> - */
>   void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
>   {
> -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> -
> -	/*
> -	 * If we entered the guest with the vtimer output asserted we have to
> -	 * check if the guest has modified the timer so that we should lower
> -	 * the line at this point.
> -	 */
> -	if (vtimer->irq.level) {
> -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> -		if (!kvm_timer_should_fire(vtimer)) {
> -			kvm_timer_update_irq(vcpu, false, vtimer);
> -			unmask_vtimer_irq(vcpu);
> -		}
> -	}
> +	unmask_vtimer_irq_user(vcpu);
>   }

While testing your VHE optimization series [1] I noticed massive WFI 
exits on ThunderX2 so I bisected 'vhe-optimize-v3-with-fixes' branch of 
[2] down to this commit.

The host traps on WFI so that VCPU thread should be scheduled out for 
some time. However, this is not happening because kvm_vcpu_block() -> 
kvm_vcpu_check_block() gives negative value (vtimer->irq.level is 
asserted) and VCPU is woken up immediately. Nobody takes care about 
lowering the vtimer line in this case.

I reverted shape of above kvm_timer_sync_hwstate() and things are good 
now. Before I start digging I wanted to check with you. Can you please 
check on your side?

[1] https://www.spinics.net/lists/kvm/msg161941.html
[2] git://git.kernel.org/pub/scm/linux/kernel/git/cdall/linux.git

Thanks,
Tomasz

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v9 7/9] KVM: arm/arm64: Provide a get_input_level for the arch timer
@ 2018-01-22 12:32     ` Tomasz Nowicki
  0 siblings, 0 replies; 36+ messages in thread
From: Tomasz Nowicki @ 2018-01-22 12:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Christoffer,

Please see my observations/comments below.

On 20.12.2017 12:36, Christoffer Dall wrote:
> The VGIC can now support the life-cycle of mapped level-triggered
> interrupts, and we no longer have to read back the timer state on every
> exit from the VM if we had an asserted timer interrupt signal, because
> the VGIC already knows if we hit the unlikely case where the guest
> disables the timer without ACKing the virtual timer interrupt.
> 
> This means we rework a bit of the code to factor out the functionality
> to snapshot the timer state from vtimer_save_state(), and we can reuse
> this functionality in the sync path when we have an irqchip in
> userspace, and also to support our implementation of the
> get_input_level() function for the timer.
> 
> This change also means that we can no longer rely on the timer's view of
> the interrupt line to set the active state, because we no longer
> maintain this state for mapped interrupts when exiting from the guest.
> Instead, we only set the active state if the virtual interrupt is
> active, and otherwise we simply let the timer fire again and raise the
> virtual interrupt from the ISR.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>   include/kvm/arm_arch_timer.h |  2 ++
>   virt/kvm/arm/arch_timer.c    | 84 ++++++++++++++++++++------------------------
>   2 files changed, 40 insertions(+), 46 deletions(-)
> 
> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> index 6e45608b2399..b1dcfde0a3ef 100644
> --- a/include/kvm/arm_arch_timer.h
> +++ b/include/kvm/arm_arch_timer.h
> @@ -90,6 +90,8 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
>   
>   void kvm_timer_init_vhe(void);
>   
> +bool kvm_arch_timer_get_input_level(int vintid);
> +
>   #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.vtimer)
>   #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.ptimer)
>   
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index fb0533ed903d..d845d67b7062 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -343,6 +343,12 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
>   	phys_timer_emulate(vcpu);
>   }
>   
> +static void __timer_snapshot_state(struct arch_timer_context *timer)
> +{
> +	timer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> +	timer->cnt_cval = read_sysreg_el0(cntv_cval);
> +}
> +
>   static void vtimer_save_state(struct kvm_vcpu *vcpu)
>   {
>   	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> @@ -354,10 +360,8 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
>   	if (!vtimer->loaded)
>   		goto out;
>   
> -	if (timer->enabled) {
> -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> -	}
> +	if (timer->enabled)
> +		__timer_snapshot_state(vtimer);
>   
>   	/* Disable the virtual timer */
>   	write_sysreg_el0(0, cntv_ctl);
> @@ -454,8 +458,7 @@ static void kvm_timer_vcpu_load_vgic(struct kvm_vcpu *vcpu)
>   	bool phys_active;
>   	int ret;
>   
> -	phys_active = vtimer->irq.level ||
> -		      kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
> +	phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
>   
>   	ret = irq_set_irqchip_state(host_vtimer_irq,
>   				    IRQCHIP_STATE_ACTIVE,
> @@ -535,54 +538,27 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
>   	set_cntvoff(0);
>   }
>   
> -static void unmask_vtimer_irq(struct kvm_vcpu *vcpu)
> +/*
> + * With a userspace irqchip we have to check if the guest de-asserted the
> + * timer and if so, unmask the timer irq signal on the host interrupt
> + * controller to ensure that we see future timer signals.
> + */
> +static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
>   {
>   	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>   
>   	if (unlikely(!irqchip_in_kernel(vcpu->kvm))) {
> -		kvm_vtimer_update_mask_user(vcpu);
> -		return;
> -	}
> -
> -	/*
> -	 * If the guest disabled the timer without acking the interrupt, then
> -	 * we must make sure the physical and virtual active states are in
> -	 * sync by deactivating the physical interrupt, because otherwise we
> -	 * wouldn't see the next timer interrupt in the host.
> -	 */
> -	if (!kvm_vgic_map_is_active(vcpu, vtimer->irq.irq)) {
> -		int ret;
> -		ret = irq_set_irqchip_state(host_vtimer_irq,
> -					    IRQCHIP_STATE_ACTIVE,
> -					    false);
> -		WARN_ON(ret);
> +		__timer_snapshot_state(vtimer);
> +		if (!kvm_timer_should_fire(vtimer)) {
> +			kvm_timer_update_irq(vcpu, false, vtimer);
> +			kvm_vtimer_update_mask_user(vcpu);
> +		}
>   	}
>   }
>   
> -/**
> - * kvm_timer_sync_hwstate - sync timer state from cpu
> - * @vcpu: The vcpu pointer
> - *
> - * Check if any of the timers have expired while we were running in the guest,
> - * and inject an interrupt if that was the case.
> - */
>   void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
>   {
> -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> -
> -	/*
> -	 * If we entered the guest with the vtimer output asserted we have to
> -	 * check if the guest has modified the timer so that we should lower
> -	 * the line at this point.
> -	 */
> -	if (vtimer->irq.level) {
> -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> -		if (!kvm_timer_should_fire(vtimer)) {
> -			kvm_timer_update_irq(vcpu, false, vtimer);
> -			unmask_vtimer_irq(vcpu);
> -		}
> -	}
> +	unmask_vtimer_irq_user(vcpu);
>   }

While testing your VHE optimization series [1] I noticed massive WFI 
exits on ThunderX2 so I bisected 'vhe-optimize-v3-with-fixes' branch of 
[2] down to this commit.

The host traps on WFI so that VCPU thread should be scheduled out for 
some time. However, this is not happening because kvm_vcpu_block() -> 
kvm_vcpu_check_block() gives negative value (vtimer->irq.level is 
asserted) and VCPU is woken up immediately. Nobody takes care about 
lowering the vtimer line in this case.

I reverted shape of above kvm_timer_sync_hwstate() and things are good 
now. Before I start digging I wanted to check with you. Can you please 
check on your side?

[1] https://www.spinics.net/lists/kvm/msg161941.html
[2] git://git.kernel.org/pub/scm/linux/kernel/git/cdall/linux.git

Thanks,
Tomasz

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v9 7/9] KVM: arm/arm64: Provide a get_input_level for the arch timer
  2018-01-22 12:32     ` Tomasz Nowicki
@ 2018-01-22 17:58       ` Christoffer Dall
  -1 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2018-01-22 17:58 UTC (permalink / raw)
  To: Tomasz Nowicki
  Cc: Marc Zyngier, Andre Przywara, kvmarm, linux-arm-kernel, kvm

Hi Tomasz,

On Mon, Jan 22, 2018 at 01:32:57PM +0100, Tomasz Nowicki wrote:
> Please see my observations/comments below.
> 
> On 20.12.2017 12:36, Christoffer Dall wrote:
> >The VGIC can now support the life-cycle of mapped level-triggered
> >interrupts, and we no longer have to read back the timer state on every
> >exit from the VM if we had an asserted timer interrupt signal, because
> >the VGIC already knows if we hit the unlikely case where the guest
> >disables the timer without ACKing the virtual timer interrupt.
> >
> >This means we rework a bit of the code to factor out the functionality
> >to snapshot the timer state from vtimer_save_state(), and we can reuse
> >this functionality in the sync path when we have an irqchip in
> >userspace, and also to support our implementation of the
> >get_input_level() function for the timer.
> >
> >This change also means that we can no longer rely on the timer's view of
> >the interrupt line to set the active state, because we no longer
> >maintain this state for mapped interrupts when exiting from the guest.
> >Instead, we only set the active state if the virtual interrupt is
> >active, and otherwise we simply let the timer fire again and raise the
> >virtual interrupt from the ISR.
> >
> >Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> >Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >---
> >  include/kvm/arm_arch_timer.h |  2 ++
> >  virt/kvm/arm/arch_timer.c    | 84 ++++++++++++++++++++------------------------
> >  2 files changed, 40 insertions(+), 46 deletions(-)
> >
> >diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> >index 6e45608b2399..b1dcfde0a3ef 100644
> >--- a/include/kvm/arm_arch_timer.h
> >+++ b/include/kvm/arm_arch_timer.h
> >@@ -90,6 +90,8 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
> >  void kvm_timer_init_vhe(void);
> >+bool kvm_arch_timer_get_input_level(int vintid);
> >+
> >  #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.vtimer)
> >  #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.ptimer)
> >diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> >index fb0533ed903d..d845d67b7062 100644
> >--- a/virt/kvm/arm/arch_timer.c
> >+++ b/virt/kvm/arm/arch_timer.c
> >@@ -343,6 +343,12 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
> >  	phys_timer_emulate(vcpu);
> >  }
> >+static void __timer_snapshot_state(struct arch_timer_context *timer)
> >+{
> >+	timer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> >+	timer->cnt_cval = read_sysreg_el0(cntv_cval);
> >+}
> >+
> >  static void vtimer_save_state(struct kvm_vcpu *vcpu)
> >  {
> >  	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> >@@ -354,10 +360,8 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
> >  	if (!vtimer->loaded)
> >  		goto out;
> >-	if (timer->enabled) {
> >-		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> >-		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> >-	}
> >+	if (timer->enabled)
> >+		__timer_snapshot_state(vtimer);
> >  	/* Disable the virtual timer */
> >  	write_sysreg_el0(0, cntv_ctl);
> >@@ -454,8 +458,7 @@ static void kvm_timer_vcpu_load_vgic(struct kvm_vcpu *vcpu)
> >  	bool phys_active;
> >  	int ret;
> >-	phys_active = vtimer->irq.level ||
> >-		      kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
> >+	phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
> >  	ret = irq_set_irqchip_state(host_vtimer_irq,
> >  				    IRQCHIP_STATE_ACTIVE,
> >@@ -535,54 +538,27 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
> >  	set_cntvoff(0);
> >  }
> >-static void unmask_vtimer_irq(struct kvm_vcpu *vcpu)
> >+/*
> >+ * With a userspace irqchip we have to check if the guest de-asserted the
> >+ * timer and if so, unmask the timer irq signal on the host interrupt
> >+ * controller to ensure that we see future timer signals.
> >+ */
> >+static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
> >  {
> >  	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> >  	if (unlikely(!irqchip_in_kernel(vcpu->kvm))) {
> >-		kvm_vtimer_update_mask_user(vcpu);
> >-		return;
> >-	}
> >-
> >-	/*
> >-	 * If the guest disabled the timer without acking the interrupt, then
> >-	 * we must make sure the physical and virtual active states are in
> >-	 * sync by deactivating the physical interrupt, because otherwise we
> >-	 * wouldn't see the next timer interrupt in the host.
> >-	 */
> >-	if (!kvm_vgic_map_is_active(vcpu, vtimer->irq.irq)) {
> >-		int ret;
> >-		ret = irq_set_irqchip_state(host_vtimer_irq,
> >-					    IRQCHIP_STATE_ACTIVE,
> >-					    false);
> >-		WARN_ON(ret);
> >+		__timer_snapshot_state(vtimer);
> >+		if (!kvm_timer_should_fire(vtimer)) {
> >+			kvm_timer_update_irq(vcpu, false, vtimer);
> >+			kvm_vtimer_update_mask_user(vcpu);
> >+		}
> >  	}
> >  }
> >-/**
> >- * kvm_timer_sync_hwstate - sync timer state from cpu
> >- * @vcpu: The vcpu pointer
> >- *
> >- * Check if any of the timers have expired while we were running in the guest,
> >- * and inject an interrupt if that was the case.
> >- */
> >  void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
> >  {
> >-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> >-
> >-	/*
> >-	 * If we entered the guest with the vtimer output asserted we have to
> >-	 * check if the guest has modified the timer so that we should lower
> >-	 * the line at this point.
> >-	 */
> >-	if (vtimer->irq.level) {
> >-		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> >-		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> >-		if (!kvm_timer_should_fire(vtimer)) {
> >-			kvm_timer_update_irq(vcpu, false, vtimer);
> >-			unmask_vtimer_irq(vcpu);
> >-		}
> >-	}
> >+	unmask_vtimer_irq_user(vcpu);
> >  }
> 
> While testing your VHE optimization series [1] I noticed massive WFI exits
> on ThunderX2 so I bisected 'vhe-optimize-v3-with-fixes' branch of [2] down
> to this commit.

Thanks for doing that!

> 
> The host traps on WFI so that VCPU thread should be scheduled out for some
> time. However, this is not happening because kvm_vcpu_block() ->
> kvm_vcpu_check_block() gives negative value (vtimer->irq.level is asserted)
> and VCPU is woken up immediately. Nobody takes care about lowering the
> vtimer line in this case.

Indeed, this is a problem.  I thought this was properly handled, but I
think this part changed at some version of these patches.

> 
> I reverted shape of above kvm_timer_sync_hwstate() and things are good now.
> Before I start digging I wanted to check with you. Can you please check on
> your side?

I'd still like to not have kvm_timer_sync_hwstate() do any work, and I
think this can be accomplished by updating vtimer->irq.level in
vtimer_save_state().

I didn't observe that a guest couldn't sleep on WFI when I tested this
series, but I may have simply not noticed it on any of the platforms I
used for testing.   I'll investigate and come back to you.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v9 7/9] KVM: arm/arm64: Provide a get_input_level for the arch timer
@ 2018-01-22 17:58       ` Christoffer Dall
  0 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2018-01-22 17:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Tomasz,

On Mon, Jan 22, 2018 at 01:32:57PM +0100, Tomasz Nowicki wrote:
> Please see my observations/comments below.
> 
> On 20.12.2017 12:36, Christoffer Dall wrote:
> >The VGIC can now support the life-cycle of mapped level-triggered
> >interrupts, and we no longer have to read back the timer state on every
> >exit from the VM if we had an asserted timer interrupt signal, because
> >the VGIC already knows if we hit the unlikely case where the guest
> >disables the timer without ACKing the virtual timer interrupt.
> >
> >This means we rework a bit of the code to factor out the functionality
> >to snapshot the timer state from vtimer_save_state(), and we can reuse
> >this functionality in the sync path when we have an irqchip in
> >userspace, and also to support our implementation of the
> >get_input_level() function for the timer.
> >
> >This change also means that we can no longer rely on the timer's view of
> >the interrupt line to set the active state, because we no longer
> >maintain this state for mapped interrupts when exiting from the guest.
> >Instead, we only set the active state if the virtual interrupt is
> >active, and otherwise we simply let the timer fire again and raise the
> >virtual interrupt from the ISR.
> >
> >Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> >Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >---
> >  include/kvm/arm_arch_timer.h |  2 ++
> >  virt/kvm/arm/arch_timer.c    | 84 ++++++++++++++++++++------------------------
> >  2 files changed, 40 insertions(+), 46 deletions(-)
> >
> >diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> >index 6e45608b2399..b1dcfde0a3ef 100644
> >--- a/include/kvm/arm_arch_timer.h
> >+++ b/include/kvm/arm_arch_timer.h
> >@@ -90,6 +90,8 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
> >  void kvm_timer_init_vhe(void);
> >+bool kvm_arch_timer_get_input_level(int vintid);
> >+
> >  #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.vtimer)
> >  #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.ptimer)
> >diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> >index fb0533ed903d..d845d67b7062 100644
> >--- a/virt/kvm/arm/arch_timer.c
> >+++ b/virt/kvm/arm/arch_timer.c
> >@@ -343,6 +343,12 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
> >  	phys_timer_emulate(vcpu);
> >  }
> >+static void __timer_snapshot_state(struct arch_timer_context *timer)
> >+{
> >+	timer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> >+	timer->cnt_cval = read_sysreg_el0(cntv_cval);
> >+}
> >+
> >  static void vtimer_save_state(struct kvm_vcpu *vcpu)
> >  {
> >  	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> >@@ -354,10 +360,8 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
> >  	if (!vtimer->loaded)
> >  		goto out;
> >-	if (timer->enabled) {
> >-		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> >-		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> >-	}
> >+	if (timer->enabled)
> >+		__timer_snapshot_state(vtimer);
> >  	/* Disable the virtual timer */
> >  	write_sysreg_el0(0, cntv_ctl);
> >@@ -454,8 +458,7 @@ static void kvm_timer_vcpu_load_vgic(struct kvm_vcpu *vcpu)
> >  	bool phys_active;
> >  	int ret;
> >-	phys_active = vtimer->irq.level ||
> >-		      kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
> >+	phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
> >  	ret = irq_set_irqchip_state(host_vtimer_irq,
> >  				    IRQCHIP_STATE_ACTIVE,
> >@@ -535,54 +538,27 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
> >  	set_cntvoff(0);
> >  }
> >-static void unmask_vtimer_irq(struct kvm_vcpu *vcpu)
> >+/*
> >+ * With a userspace irqchip we have to check if the guest de-asserted the
> >+ * timer and if so, unmask the timer irq signal on the host interrupt
> >+ * controller to ensure that we see future timer signals.
> >+ */
> >+static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
> >  {
> >  	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> >  	if (unlikely(!irqchip_in_kernel(vcpu->kvm))) {
> >-		kvm_vtimer_update_mask_user(vcpu);
> >-		return;
> >-	}
> >-
> >-	/*
> >-	 * If the guest disabled the timer without acking the interrupt, then
> >-	 * we must make sure the physical and virtual active states are in
> >-	 * sync by deactivating the physical interrupt, because otherwise we
> >-	 * wouldn't see the next timer interrupt in the host.
> >-	 */
> >-	if (!kvm_vgic_map_is_active(vcpu, vtimer->irq.irq)) {
> >-		int ret;
> >-		ret = irq_set_irqchip_state(host_vtimer_irq,
> >-					    IRQCHIP_STATE_ACTIVE,
> >-					    false);
> >-		WARN_ON(ret);
> >+		__timer_snapshot_state(vtimer);
> >+		if (!kvm_timer_should_fire(vtimer)) {
> >+			kvm_timer_update_irq(vcpu, false, vtimer);
> >+			kvm_vtimer_update_mask_user(vcpu);
> >+		}
> >  	}
> >  }
> >-/**
> >- * kvm_timer_sync_hwstate - sync timer state from cpu
> >- * @vcpu: The vcpu pointer
> >- *
> >- * Check if any of the timers have expired while we were running in the guest,
> >- * and inject an interrupt if that was the case.
> >- */
> >  void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
> >  {
> >-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> >-
> >-	/*
> >-	 * If we entered the guest with the vtimer output asserted we have to
> >-	 * check if the guest has modified the timer so that we should lower
> >-	 * the line at this point.
> >-	 */
> >-	if (vtimer->irq.level) {
> >-		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> >-		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> >-		if (!kvm_timer_should_fire(vtimer)) {
> >-			kvm_timer_update_irq(vcpu, false, vtimer);
> >-			unmask_vtimer_irq(vcpu);
> >-		}
> >-	}
> >+	unmask_vtimer_irq_user(vcpu);
> >  }
> 
> While testing your VHE optimization series [1] I noticed massive WFI exits
> on ThunderX2 so I bisected 'vhe-optimize-v3-with-fixes' branch of [2] down
> to this commit.

Thanks for doing that!

> 
> The host traps on WFI so that VCPU thread should be scheduled out for some
> time. However, this is not happening because kvm_vcpu_block() ->
> kvm_vcpu_check_block() gives negative value (vtimer->irq.level is asserted)
> and VCPU is woken up immediately. Nobody takes care about lowering the
> vtimer line in this case.

Indeed, this is a problem.  I thought this was properly handled, but I
think this part changed at some version of these patches.

> 
> I reverted shape of above kvm_timer_sync_hwstate() and things are good now.
> Before I start digging I wanted to check with you. Can you please check on
> your side?

I'd still like to not have kvm_timer_sync_hwstate() do any work, and I
think this can be accomplished by updating vtimer->irq.level in
vtimer_save_state().

I didn't observe that a guest couldn't sleep on WFI when I tested this
series, but I may have simply not noticed it on any of the platforms I
used for testing.   I'll investigate and come back to you.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v9 7/9] KVM: arm/arm64: Provide a get_input_level for the arch timer
  2018-01-22 12:32     ` Tomasz Nowicki
@ 2018-01-30 12:49       ` Christoffer Dall
  -1 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2018-01-30 12:49 UTC (permalink / raw)
  To: Tomasz Nowicki
  Cc: kvmarm, linux-arm-kernel, Marc Zyngier, Andre Przywara, kvm

Hi Tomasz,

On Mon, Jan 22, 2018 at 01:32:57PM +0100, Tomasz Nowicki wrote:
> On 20.12.2017 12:36, Christoffer Dall wrote:
> >The VGIC can now support the life-cycle of mapped level-triggered
> >interrupts, and we no longer have to read back the timer state on every
> >exit from the VM if we had an asserted timer interrupt signal, because
> >the VGIC already knows if we hit the unlikely case where the guest
> >disables the timer without ACKing the virtual timer interrupt.
> >
> >This means we rework a bit of the code to factor out the functionality
> >to snapshot the timer state from vtimer_save_state(), and we can reuse
> >this functionality in the sync path when we have an irqchip in
> >userspace, and also to support our implementation of the
> >get_input_level() function for the timer.
> >
> >This change also means that we can no longer rely on the timer's view of
> >the interrupt line to set the active state, because we no longer
> >maintain this state for mapped interrupts when exiting from the guest.
> >Instead, we only set the active state if the virtual interrupt is
> >active, and otherwise we simply let the timer fire again and raise the
> >virtual interrupt from the ISR.
> >
> >Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> >Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >---
> >  include/kvm/arm_arch_timer.h |  2 ++
> >  virt/kvm/arm/arch_timer.c    | 84 ++++++++++++++++++++------------------------
> >  2 files changed, 40 insertions(+), 46 deletions(-)
> >
> >diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> >index 6e45608b2399..b1dcfde0a3ef 100644
> >--- a/include/kvm/arm_arch_timer.h
> >+++ b/include/kvm/arm_arch_timer.h
> >@@ -90,6 +90,8 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
> >  void kvm_timer_init_vhe(void);
> >+bool kvm_arch_timer_get_input_level(int vintid);
> >+
> >  #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.vtimer)
> >  #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.ptimer)
> >diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> >index fb0533ed903d..d845d67b7062 100644
> >--- a/virt/kvm/arm/arch_timer.c
> >+++ b/virt/kvm/arm/arch_timer.c
> >@@ -343,6 +343,12 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
> >  	phys_timer_emulate(vcpu);
> >  }
> >+static void __timer_snapshot_state(struct arch_timer_context *timer)
> >+{
> >+	timer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> >+	timer->cnt_cval = read_sysreg_el0(cntv_cval);
> >+}
> >+
> >  static void vtimer_save_state(struct kvm_vcpu *vcpu)
> >  {
> >  	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> >@@ -354,10 +360,8 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
> >  	if (!vtimer->loaded)
> >  		goto out;
> >-	if (timer->enabled) {
> >-		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> >-		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> >-	}
> >+	if (timer->enabled)
> >+		__timer_snapshot_state(vtimer);
> >  	/* Disable the virtual timer */
> >  	write_sysreg_el0(0, cntv_ctl);
> >@@ -454,8 +458,7 @@ static void kvm_timer_vcpu_load_vgic(struct kvm_vcpu *vcpu)
> >  	bool phys_active;
> >  	int ret;
> >-	phys_active = vtimer->irq.level ||
> >-		      kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
> >+	phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
> >  	ret = irq_set_irqchip_state(host_vtimer_irq,
> >  				    IRQCHIP_STATE_ACTIVE,
> >@@ -535,54 +538,27 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
> >  	set_cntvoff(0);
> >  }
> >-static void unmask_vtimer_irq(struct kvm_vcpu *vcpu)
> >+/*
> >+ * With a userspace irqchip we have to check if the guest de-asserted the
> >+ * timer and if so, unmask the timer irq signal on the host interrupt
> >+ * controller to ensure that we see future timer signals.
> >+ */
> >+static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
> >  {
> >  	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> >  	if (unlikely(!irqchip_in_kernel(vcpu->kvm))) {
> >-		kvm_vtimer_update_mask_user(vcpu);
> >-		return;
> >-	}
> >-
> >-	/*
> >-	 * If the guest disabled the timer without acking the interrupt, then
> >-	 * we must make sure the physical and virtual active states are in
> >-	 * sync by deactivating the physical interrupt, because otherwise we
> >-	 * wouldn't see the next timer interrupt in the host.
> >-	 */
> >-	if (!kvm_vgic_map_is_active(vcpu, vtimer->irq.irq)) {
> >-		int ret;
> >-		ret = irq_set_irqchip_state(host_vtimer_irq,
> >-					    IRQCHIP_STATE_ACTIVE,
> >-					    false);
> >-		WARN_ON(ret);
> >+		__timer_snapshot_state(vtimer);
> >+		if (!kvm_timer_should_fire(vtimer)) {
> >+			kvm_timer_update_irq(vcpu, false, vtimer);
> >+			kvm_vtimer_update_mask_user(vcpu);
> >+		}
> >  	}
> >  }
> >-/**
> >- * kvm_timer_sync_hwstate - sync timer state from cpu
> >- * @vcpu: The vcpu pointer
> >- *
> >- * Check if any of the timers have expired while we were running in the guest,
> >- * and inject an interrupt if that was the case.
> >- */
> >  void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
> >  {
> >-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> >-
> >-	/*
> >-	 * If we entered the guest with the vtimer output asserted we have to
> >-	 * check if the guest has modified the timer so that we should lower
> >-	 * the line at this point.
> >-	 */
> >-	if (vtimer->irq.level) {
> >-		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> >-		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> >-		if (!kvm_timer_should_fire(vtimer)) {
> >-			kvm_timer_update_irq(vcpu, false, vtimer);
> >-			unmask_vtimer_irq(vcpu);
> >-		}
> >-	}
> >+	unmask_vtimer_irq_user(vcpu);
> >  }
> 
> While testing your VHE optimization series [1] I noticed massive WFI exits
> on ThunderX2 so I bisected 'vhe-optimize-v3-with-fixes' branch of [2] down
> to this commit.
> 
> The host traps on WFI so that VCPU thread should be scheduled out for some
> time. However, this is not happening because kvm_vcpu_block() ->
> kvm_vcpu_check_block() gives negative value (vtimer->irq.level is asserted)
> and VCPU is woken up immediately. Nobody takes care about lowering the
> vtimer line in this case.
> 
> I reverted shape of above kvm_timer_sync_hwstate() and things are good now.
> Before I start digging I wanted to check with you. Can you please check on
> your side?
> 

This patch should fix the issue, thanks for pointing it out.
https://lists.cs.columbia.edu/pipermail/kvmarm/2018-January/029582.html

I'd be happy to hear if you can confirm this or not.

I forgot that my git auto-cc doesn't pick up reported-by tags (I should
fix that), so apologies for not cc'ing you on the series.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v9 7/9] KVM: arm/arm64: Provide a get_input_level for the arch timer
@ 2018-01-30 12:49       ` Christoffer Dall
  0 siblings, 0 replies; 36+ messages in thread
From: Christoffer Dall @ 2018-01-30 12:49 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Tomasz,

On Mon, Jan 22, 2018 at 01:32:57PM +0100, Tomasz Nowicki wrote:
> On 20.12.2017 12:36, Christoffer Dall wrote:
> >The VGIC can now support the life-cycle of mapped level-triggered
> >interrupts, and we no longer have to read back the timer state on every
> >exit from the VM if we had an asserted timer interrupt signal, because
> >the VGIC already knows if we hit the unlikely case where the guest
> >disables the timer without ACKing the virtual timer interrupt.
> >
> >This means we rework a bit of the code to factor out the functionality
> >to snapshot the timer state from vtimer_save_state(), and we can reuse
> >this functionality in the sync path when we have an irqchip in
> >userspace, and also to support our implementation of the
> >get_input_level() function for the timer.
> >
> >This change also means that we can no longer rely on the timer's view of
> >the interrupt line to set the active state, because we no longer
> >maintain this state for mapped interrupts when exiting from the guest.
> >Instead, we only set the active state if the virtual interrupt is
> >active, and otherwise we simply let the timer fire again and raise the
> >virtual interrupt from the ISR.
> >
> >Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> >Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >---
> >  include/kvm/arm_arch_timer.h |  2 ++
> >  virt/kvm/arm/arch_timer.c    | 84 ++++++++++++++++++++------------------------
> >  2 files changed, 40 insertions(+), 46 deletions(-)
> >
> >diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> >index 6e45608b2399..b1dcfde0a3ef 100644
> >--- a/include/kvm/arm_arch_timer.h
> >+++ b/include/kvm/arm_arch_timer.h
> >@@ -90,6 +90,8 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
> >  void kvm_timer_init_vhe(void);
> >+bool kvm_arch_timer_get_input_level(int vintid);
> >+
> >  #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.vtimer)
> >  #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.ptimer)
> >diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> >index fb0533ed903d..d845d67b7062 100644
> >--- a/virt/kvm/arm/arch_timer.c
> >+++ b/virt/kvm/arm/arch_timer.c
> >@@ -343,6 +343,12 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
> >  	phys_timer_emulate(vcpu);
> >  }
> >+static void __timer_snapshot_state(struct arch_timer_context *timer)
> >+{
> >+	timer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> >+	timer->cnt_cval = read_sysreg_el0(cntv_cval);
> >+}
> >+
> >  static void vtimer_save_state(struct kvm_vcpu *vcpu)
> >  {
> >  	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> >@@ -354,10 +360,8 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
> >  	if (!vtimer->loaded)
> >  		goto out;
> >-	if (timer->enabled) {
> >-		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> >-		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> >-	}
> >+	if (timer->enabled)
> >+		__timer_snapshot_state(vtimer);
> >  	/* Disable the virtual timer */
> >  	write_sysreg_el0(0, cntv_ctl);
> >@@ -454,8 +458,7 @@ static void kvm_timer_vcpu_load_vgic(struct kvm_vcpu *vcpu)
> >  	bool phys_active;
> >  	int ret;
> >-	phys_active = vtimer->irq.level ||
> >-		      kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
> >+	phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
> >  	ret = irq_set_irqchip_state(host_vtimer_irq,
> >  				    IRQCHIP_STATE_ACTIVE,
> >@@ -535,54 +538,27 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
> >  	set_cntvoff(0);
> >  }
> >-static void unmask_vtimer_irq(struct kvm_vcpu *vcpu)
> >+/*
> >+ * With a userspace irqchip we have to check if the guest de-asserted the
> >+ * timer and if so, unmask the timer irq signal on the host interrupt
> >+ * controller to ensure that we see future timer signals.
> >+ */
> >+static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
> >  {
> >  	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> >  	if (unlikely(!irqchip_in_kernel(vcpu->kvm))) {
> >-		kvm_vtimer_update_mask_user(vcpu);
> >-		return;
> >-	}
> >-
> >-	/*
> >-	 * If the guest disabled the timer without acking the interrupt, then
> >-	 * we must make sure the physical and virtual active states are in
> >-	 * sync by deactivating the physical interrupt, because otherwise we
> >-	 * wouldn't see the next timer interrupt in the host.
> >-	 */
> >-	if (!kvm_vgic_map_is_active(vcpu, vtimer->irq.irq)) {
> >-		int ret;
> >-		ret = irq_set_irqchip_state(host_vtimer_irq,
> >-					    IRQCHIP_STATE_ACTIVE,
> >-					    false);
> >-		WARN_ON(ret);
> >+		__timer_snapshot_state(vtimer);
> >+		if (!kvm_timer_should_fire(vtimer)) {
> >+			kvm_timer_update_irq(vcpu, false, vtimer);
> >+			kvm_vtimer_update_mask_user(vcpu);
> >+		}
> >  	}
> >  }
> >-/**
> >- * kvm_timer_sync_hwstate - sync timer state from cpu
> >- * @vcpu: The vcpu pointer
> >- *
> >- * Check if any of the timers have expired while we were running in the guest,
> >- * and inject an interrupt if that was the case.
> >- */
> >  void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
> >  {
> >-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> >-
> >-	/*
> >-	 * If we entered the guest with the vtimer output asserted we have to
> >-	 * check if the guest has modified the timer so that we should lower
> >-	 * the line at this point.
> >-	 */
> >-	if (vtimer->irq.level) {
> >-		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> >-		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> >-		if (!kvm_timer_should_fire(vtimer)) {
> >-			kvm_timer_update_irq(vcpu, false, vtimer);
> >-			unmask_vtimer_irq(vcpu);
> >-		}
> >-	}
> >+	unmask_vtimer_irq_user(vcpu);
> >  }
> 
> While testing your VHE optimization series [1] I noticed massive WFI exits
> on ThunderX2 so I bisected 'vhe-optimize-v3-with-fixes' branch of [2] down
> to this commit.
> 
> The host traps on WFI so that VCPU thread should be scheduled out for some
> time. However, this is not happening because kvm_vcpu_block() ->
> kvm_vcpu_check_block() gives negative value (vtimer->irq.level is asserted)
> and VCPU is woken up immediately. Nobody takes care about lowering the
> vtimer line in this case.
> 
> I reverted shape of above kvm_timer_sync_hwstate() and things are good now.
> Before I start digging I wanted to check with you. Can you please check on
> your side?
> 

This patch should fix the issue, thanks for pointing it out.
https://lists.cs.columbia.edu/pipermail/kvmarm/2018-January/029582.html

I'd be happy to hear if you can confirm this or not.

I forgot that my git auto-cc doesn't pick up reported-by tags (I should
fix that), so apologies for not cc'ing you on the series.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v9 7/9] KVM: arm/arm64: Provide a get_input_level for the arch timer
  2018-01-30 12:49       ` Christoffer Dall
@ 2018-01-31  8:32         ` Tomasz Nowicki
  -1 siblings, 0 replies; 36+ messages in thread
From: Tomasz Nowicki @ 2018-01-31  8:32 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Marc Zyngier, Andre Przywara, kvmarm, linux-arm-kernel, kvm

Hi Christoffer,

On 30.01.2018 13:49, Christoffer Dall wrote:
> Hi Tomasz,
> 
> On Mon, Jan 22, 2018 at 01:32:57PM +0100, Tomasz Nowicki wrote:
>> On 20.12.2017 12:36, Christoffer Dall wrote:
>>> The VGIC can now support the life-cycle of mapped level-triggered
>>> interrupts, and we no longer have to read back the timer state on every
>>> exit from the VM if we had an asserted timer interrupt signal, because
>>> the VGIC already knows if we hit the unlikely case where the guest
>>> disables the timer without ACKing the virtual timer interrupt.
>>>
>>> This means we rework a bit of the code to factor out the functionality
>>> to snapshot the timer state from vtimer_save_state(), and we can reuse
>>> this functionality in the sync path when we have an irqchip in
>>> userspace, and also to support our implementation of the
>>> get_input_level() function for the timer.
>>>
>>> This change also means that we can no longer rely on the timer's view of
>>> the interrupt line to set the active state, because we no longer
>>> maintain this state for mapped interrupts when exiting from the guest.
>>> Instead, we only set the active state if the virtual interrupt is
>>> active, and otherwise we simply let the timer fire again and raise the
>>> virtual interrupt from the ISR.
>>>
>>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>>> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>> ---
>>>   include/kvm/arm_arch_timer.h |  2 ++
>>>   virt/kvm/arm/arch_timer.c    | 84 ++++++++++++++++++++------------------------
>>>   2 files changed, 40 insertions(+), 46 deletions(-)
>>>
>>> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
>>> index 6e45608b2399..b1dcfde0a3ef 100644
>>> --- a/include/kvm/arm_arch_timer.h
>>> +++ b/include/kvm/arm_arch_timer.h
>>> @@ -90,6 +90,8 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
>>>   void kvm_timer_init_vhe(void);
>>> +bool kvm_arch_timer_get_input_level(int vintid);
>>> +
>>>   #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.vtimer)
>>>   #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.ptimer)
>>> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
>>> index fb0533ed903d..d845d67b7062 100644
>>> --- a/virt/kvm/arm/arch_timer.c
>>> +++ b/virt/kvm/arm/arch_timer.c
>>> @@ -343,6 +343,12 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
>>>   	phys_timer_emulate(vcpu);
>>>   }
>>> +static void __timer_snapshot_state(struct arch_timer_context *timer)
>>> +{
>>> +	timer->cnt_ctl = read_sysreg_el0(cntv_ctl);
>>> +	timer->cnt_cval = read_sysreg_el0(cntv_cval);
>>> +}
>>> +
>>>   static void vtimer_save_state(struct kvm_vcpu *vcpu)
>>>   {
>>>   	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
>>> @@ -354,10 +360,8 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
>>>   	if (!vtimer->loaded)
>>>   		goto out;
>>> -	if (timer->enabled) {
>>> -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
>>> -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
>>> -	}
>>> +	if (timer->enabled)
>>> +		__timer_snapshot_state(vtimer);
>>>   	/* Disable the virtual timer */
>>>   	write_sysreg_el0(0, cntv_ctl);
>>> @@ -454,8 +458,7 @@ static void kvm_timer_vcpu_load_vgic(struct kvm_vcpu *vcpu)
>>>   	bool phys_active;
>>>   	int ret;
>>> -	phys_active = vtimer->irq.level ||
>>> -		      kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
>>> +	phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
>>>   	ret = irq_set_irqchip_state(host_vtimer_irq,
>>>   				    IRQCHIP_STATE_ACTIVE,
>>> @@ -535,54 +538,27 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
>>>   	set_cntvoff(0);
>>>   }
>>> -static void unmask_vtimer_irq(struct kvm_vcpu *vcpu)
>>> +/*
>>> + * With a userspace irqchip we have to check if the guest de-asserted the
>>> + * timer and if so, unmask the timer irq signal on the host interrupt
>>> + * controller to ensure that we see future timer signals.
>>> + */
>>> +static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
>>>   {
>>>   	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>>>   	if (unlikely(!irqchip_in_kernel(vcpu->kvm))) {
>>> -		kvm_vtimer_update_mask_user(vcpu);
>>> -		return;
>>> -	}
>>> -
>>> -	/*
>>> -	 * If the guest disabled the timer without acking the interrupt, then
>>> -	 * we must make sure the physical and virtual active states are in
>>> -	 * sync by deactivating the physical interrupt, because otherwise we
>>> -	 * wouldn't see the next timer interrupt in the host.
>>> -	 */
>>> -	if (!kvm_vgic_map_is_active(vcpu, vtimer->irq.irq)) {
>>> -		int ret;
>>> -		ret = irq_set_irqchip_state(host_vtimer_irq,
>>> -					    IRQCHIP_STATE_ACTIVE,
>>> -					    false);
>>> -		WARN_ON(ret);
>>> +		__timer_snapshot_state(vtimer);
>>> +		if (!kvm_timer_should_fire(vtimer)) {
>>> +			kvm_timer_update_irq(vcpu, false, vtimer);
>>> +			kvm_vtimer_update_mask_user(vcpu);
>>> +		}
>>>   	}
>>>   }
>>> -/**
>>> - * kvm_timer_sync_hwstate - sync timer state from cpu
>>> - * @vcpu: The vcpu pointer
>>> - *
>>> - * Check if any of the timers have expired while we were running in the guest,
>>> - * and inject an interrupt if that was the case.
>>> - */
>>>   void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
>>>   {
>>> -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>>> -
>>> -	/*
>>> -	 * If we entered the guest with the vtimer output asserted we have to
>>> -	 * check if the guest has modified the timer so that we should lower
>>> -	 * the line at this point.
>>> -	 */
>>> -	if (vtimer->irq.level) {
>>> -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
>>> -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
>>> -		if (!kvm_timer_should_fire(vtimer)) {
>>> -			kvm_timer_update_irq(vcpu, false, vtimer);
>>> -			unmask_vtimer_irq(vcpu);
>>> -		}
>>> -	}
>>> +	unmask_vtimer_irq_user(vcpu);
>>>   }
>>
>> While testing your VHE optimization series [1] I noticed massive WFI exits
>> on ThunderX2 so I bisected 'vhe-optimize-v3-with-fixes' branch of [2] down
>> to this commit.
>>
>> The host traps on WFI so that VCPU thread should be scheduled out for some
>> time. However, this is not happening because kvm_vcpu_block() ->
>> kvm_vcpu_check_block() gives negative value (vtimer->irq.level is asserted)
>> and VCPU is woken up immediately. Nobody takes care about lowering the
>> vtimer line in this case.
>>
>> I reverted shape of above kvm_timer_sync_hwstate() and things are good now.
>> Before I start digging I wanted to check with you. Can you please check on
>> your side?
>>
> 
> This patch should fix the issue, thanks for pointing it out.
> https://lists.cs.columbia.edu/pipermail/kvmarm/2018-January/029582.html
> 
> I'd be happy to hear if you can confirm this or not.

Yes, the issue is fixed. Thanks!

> 
> I forgot that my git auto-cc doesn't pick up reported-by tags (I should
> fix that), so apologies for not cc'ing you on the series.
> 

No problem at all.

Tomasz

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v9 7/9] KVM: arm/arm64: Provide a get_input_level for the arch timer
@ 2018-01-31  8:32         ` Tomasz Nowicki
  0 siblings, 0 replies; 36+ messages in thread
From: Tomasz Nowicki @ 2018-01-31  8:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoffer,

On 30.01.2018 13:49, Christoffer Dall wrote:
> Hi Tomasz,
> 
> On Mon, Jan 22, 2018 at 01:32:57PM +0100, Tomasz Nowicki wrote:
>> On 20.12.2017 12:36, Christoffer Dall wrote:
>>> The VGIC can now support the life-cycle of mapped level-triggered
>>> interrupts, and we no longer have to read back the timer state on every
>>> exit from the VM if we had an asserted timer interrupt signal, because
>>> the VGIC already knows if we hit the unlikely case where the guest
>>> disables the timer without ACKing the virtual timer interrupt.
>>>
>>> This means we rework a bit of the code to factor out the functionality
>>> to snapshot the timer state from vtimer_save_state(), and we can reuse
>>> this functionality in the sync path when we have an irqchip in
>>> userspace, and also to support our implementation of the
>>> get_input_level() function for the timer.
>>>
>>> This change also means that we can no longer rely on the timer's view of
>>> the interrupt line to set the active state, because we no longer
>>> maintain this state for mapped interrupts when exiting from the guest.
>>> Instead, we only set the active state if the virtual interrupt is
>>> active, and otherwise we simply let the timer fire again and raise the
>>> virtual interrupt from the ISR.
>>>
>>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>>> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>> ---
>>>   include/kvm/arm_arch_timer.h |  2 ++
>>>   virt/kvm/arm/arch_timer.c    | 84 ++++++++++++++++++++------------------------
>>>   2 files changed, 40 insertions(+), 46 deletions(-)
>>>
>>> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
>>> index 6e45608b2399..b1dcfde0a3ef 100644
>>> --- a/include/kvm/arm_arch_timer.h
>>> +++ b/include/kvm/arm_arch_timer.h
>>> @@ -90,6 +90,8 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
>>>   void kvm_timer_init_vhe(void);
>>> +bool kvm_arch_timer_get_input_level(int vintid);
>>> +
>>>   #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.vtimer)
>>>   #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.ptimer)
>>> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
>>> index fb0533ed903d..d845d67b7062 100644
>>> --- a/virt/kvm/arm/arch_timer.c
>>> +++ b/virt/kvm/arm/arch_timer.c
>>> @@ -343,6 +343,12 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
>>>   	phys_timer_emulate(vcpu);
>>>   }
>>> +static void __timer_snapshot_state(struct arch_timer_context *timer)
>>> +{
>>> +	timer->cnt_ctl = read_sysreg_el0(cntv_ctl);
>>> +	timer->cnt_cval = read_sysreg_el0(cntv_cval);
>>> +}
>>> +
>>>   static void vtimer_save_state(struct kvm_vcpu *vcpu)
>>>   {
>>>   	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
>>> @@ -354,10 +360,8 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
>>>   	if (!vtimer->loaded)
>>>   		goto out;
>>> -	if (timer->enabled) {
>>> -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
>>> -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
>>> -	}
>>> +	if (timer->enabled)
>>> +		__timer_snapshot_state(vtimer);
>>>   	/* Disable the virtual timer */
>>>   	write_sysreg_el0(0, cntv_ctl);
>>> @@ -454,8 +458,7 @@ static void kvm_timer_vcpu_load_vgic(struct kvm_vcpu *vcpu)
>>>   	bool phys_active;
>>>   	int ret;
>>> -	phys_active = vtimer->irq.level ||
>>> -		      kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
>>> +	phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
>>>   	ret = irq_set_irqchip_state(host_vtimer_irq,
>>>   				    IRQCHIP_STATE_ACTIVE,
>>> @@ -535,54 +538,27 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
>>>   	set_cntvoff(0);
>>>   }
>>> -static void unmask_vtimer_irq(struct kvm_vcpu *vcpu)
>>> +/*
>>> + * With a userspace irqchip we have to check if the guest de-asserted the
>>> + * timer and if so, unmask the timer irq signal on the host interrupt
>>> + * controller to ensure that we see future timer signals.
>>> + */
>>> +static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
>>>   {
>>>   	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>>>   	if (unlikely(!irqchip_in_kernel(vcpu->kvm))) {
>>> -		kvm_vtimer_update_mask_user(vcpu);
>>> -		return;
>>> -	}
>>> -
>>> -	/*
>>> -	 * If the guest disabled the timer without acking the interrupt, then
>>> -	 * we must make sure the physical and virtual active states are in
>>> -	 * sync by deactivating the physical interrupt, because otherwise we
>>> -	 * wouldn't see the next timer interrupt in the host.
>>> -	 */
>>> -	if (!kvm_vgic_map_is_active(vcpu, vtimer->irq.irq)) {
>>> -		int ret;
>>> -		ret = irq_set_irqchip_state(host_vtimer_irq,
>>> -					    IRQCHIP_STATE_ACTIVE,
>>> -					    false);
>>> -		WARN_ON(ret);
>>> +		__timer_snapshot_state(vtimer);
>>> +		if (!kvm_timer_should_fire(vtimer)) {
>>> +			kvm_timer_update_irq(vcpu, false, vtimer);
>>> +			kvm_vtimer_update_mask_user(vcpu);
>>> +		}
>>>   	}
>>>   }
>>> -/**
>>> - * kvm_timer_sync_hwstate - sync timer state from cpu
>>> - * @vcpu: The vcpu pointer
>>> - *
>>> - * Check if any of the timers have expired while we were running in the guest,
>>> - * and inject an interrupt if that was the case.
>>> - */
>>>   void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
>>>   {
>>> -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>>> -
>>> -	/*
>>> -	 * If we entered the guest with the vtimer output asserted we have to
>>> -	 * check if the guest has modified the timer so that we should lower
>>> -	 * the line at this point.
>>> -	 */
>>> -	if (vtimer->irq.level) {
>>> -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
>>> -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
>>> -		if (!kvm_timer_should_fire(vtimer)) {
>>> -			kvm_timer_update_irq(vcpu, false, vtimer);
>>> -			unmask_vtimer_irq(vcpu);
>>> -		}
>>> -	}
>>> +	unmask_vtimer_irq_user(vcpu);
>>>   }
>>
>> While testing your VHE optimization series [1] I noticed massive WFI exits
>> on ThunderX2 so I bisected 'vhe-optimize-v3-with-fixes' branch of [2] down
>> to this commit.
>>
>> The host traps on WFI so that VCPU thread should be scheduled out for some
>> time. However, this is not happening because kvm_vcpu_block() ->
>> kvm_vcpu_check_block() gives negative value (vtimer->irq.level is asserted)
>> and VCPU is woken up immediately. Nobody takes care about lowering the
>> vtimer line in this case.
>>
>> I reverted shape of above kvm_timer_sync_hwstate() and things are good now.
>> Before I start digging I wanted to check with you. Can you please check on
>> your side?
>>
> 
> This patch should fix the issue, thanks for pointing it out.
> https://lists.cs.columbia.edu/pipermail/kvmarm/2018-January/029582.html
> 
> I'd be happy to hear if you can confirm this or not.

Yes, the issue is fixed. Thanks!

> 
> I forgot that my git auto-cc doesn't pick up reported-by tags (I should
> fix that), so apologies for not cc'ing you on the series.
> 

No problem at all.

Tomasz

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v9 7/9] KVM: arm/arm64: Provide a get_input_level for the arch timer
  2018-01-30 12:49       ` Christoffer Dall
@ 2018-01-31  8:32         ` Tomasz Nowicki
  -1 siblings, 0 replies; 36+ messages in thread
From: Tomasz Nowicki @ 2018-01-31  8:32 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvmarm, linux-arm-kernel, Marc Zyngier, Andre Przywara, kvm

Hi Christoffer,

On 30.01.2018 13:49, Christoffer Dall wrote:
> Hi Tomasz,
> 
> On Mon, Jan 22, 2018 at 01:32:57PM +0100, Tomasz Nowicki wrote:
>> On 20.12.2017 12:36, Christoffer Dall wrote:
>>> The VGIC can now support the life-cycle of mapped level-triggered
>>> interrupts, and we no longer have to read back the timer state on every
>>> exit from the VM if we had an asserted timer interrupt signal, because
>>> the VGIC already knows if we hit the unlikely case where the guest
>>> disables the timer without ACKing the virtual timer interrupt.
>>>
>>> This means we rework a bit of the code to factor out the functionality
>>> to snapshot the timer state from vtimer_save_state(), and we can reuse
>>> this functionality in the sync path when we have an irqchip in
>>> userspace, and also to support our implementation of the
>>> get_input_level() function for the timer.
>>>
>>> This change also means that we can no longer rely on the timer's view of
>>> the interrupt line to set the active state, because we no longer
>>> maintain this state for mapped interrupts when exiting from the guest.
>>> Instead, we only set the active state if the virtual interrupt is
>>> active, and otherwise we simply let the timer fire again and raise the
>>> virtual interrupt from the ISR.
>>>
>>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>>> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>> ---
>>>   include/kvm/arm_arch_timer.h |  2 ++
>>>   virt/kvm/arm/arch_timer.c    | 84 ++++++++++++++++++++------------------------
>>>   2 files changed, 40 insertions(+), 46 deletions(-)
>>>
>>> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
>>> index 6e45608b2399..b1dcfde0a3ef 100644
>>> --- a/include/kvm/arm_arch_timer.h
>>> +++ b/include/kvm/arm_arch_timer.h
>>> @@ -90,6 +90,8 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
>>>   void kvm_timer_init_vhe(void);
>>> +bool kvm_arch_timer_get_input_level(int vintid);
>>> +
>>>   #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.vtimer)
>>>   #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.ptimer)
>>> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
>>> index fb0533ed903d..d845d67b7062 100644
>>> --- a/virt/kvm/arm/arch_timer.c
>>> +++ b/virt/kvm/arm/arch_timer.c
>>> @@ -343,6 +343,12 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
>>>   	phys_timer_emulate(vcpu);
>>>   }
>>> +static void __timer_snapshot_state(struct arch_timer_context *timer)
>>> +{
>>> +	timer->cnt_ctl = read_sysreg_el0(cntv_ctl);
>>> +	timer->cnt_cval = read_sysreg_el0(cntv_cval);
>>> +}
>>> +
>>>   static void vtimer_save_state(struct kvm_vcpu *vcpu)
>>>   {
>>>   	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
>>> @@ -354,10 +360,8 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
>>>   	if (!vtimer->loaded)
>>>   		goto out;
>>> -	if (timer->enabled) {
>>> -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
>>> -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
>>> -	}
>>> +	if (timer->enabled)
>>> +		__timer_snapshot_state(vtimer);
>>>   	/* Disable the virtual timer */
>>>   	write_sysreg_el0(0, cntv_ctl);
>>> @@ -454,8 +458,7 @@ static void kvm_timer_vcpu_load_vgic(struct kvm_vcpu *vcpu)
>>>   	bool phys_active;
>>>   	int ret;
>>> -	phys_active = vtimer->irq.level ||
>>> -		      kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
>>> +	phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
>>>   	ret = irq_set_irqchip_state(host_vtimer_irq,
>>>   				    IRQCHIP_STATE_ACTIVE,
>>> @@ -535,54 +538,27 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
>>>   	set_cntvoff(0);
>>>   }
>>> -static void unmask_vtimer_irq(struct kvm_vcpu *vcpu)
>>> +/*
>>> + * With a userspace irqchip we have to check if the guest de-asserted the
>>> + * timer and if so, unmask the timer irq signal on the host interrupt
>>> + * controller to ensure that we see future timer signals.
>>> + */
>>> +static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
>>>   {
>>>   	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>>>   	if (unlikely(!irqchip_in_kernel(vcpu->kvm))) {
>>> -		kvm_vtimer_update_mask_user(vcpu);
>>> -		return;
>>> -	}
>>> -
>>> -	/*
>>> -	 * If the guest disabled the timer without acking the interrupt, then
>>> -	 * we must make sure the physical and virtual active states are in
>>> -	 * sync by deactivating the physical interrupt, because otherwise we
>>> -	 * wouldn't see the next timer interrupt in the host.
>>> -	 */
>>> -	if (!kvm_vgic_map_is_active(vcpu, vtimer->irq.irq)) {
>>> -		int ret;
>>> -		ret = irq_set_irqchip_state(host_vtimer_irq,
>>> -					    IRQCHIP_STATE_ACTIVE,
>>> -					    false);
>>> -		WARN_ON(ret);
>>> +		__timer_snapshot_state(vtimer);
>>> +		if (!kvm_timer_should_fire(vtimer)) {
>>> +			kvm_timer_update_irq(vcpu, false, vtimer);
>>> +			kvm_vtimer_update_mask_user(vcpu);
>>> +		}
>>>   	}
>>>   }
>>> -/**
>>> - * kvm_timer_sync_hwstate - sync timer state from cpu
>>> - * @vcpu: The vcpu pointer
>>> - *
>>> - * Check if any of the timers have expired while we were running in the guest,
>>> - * and inject an interrupt if that was the case.
>>> - */
>>>   void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
>>>   {
>>> -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>>> -
>>> -	/*
>>> -	 * If we entered the guest with the vtimer output asserted we have to
>>> -	 * check if the guest has modified the timer so that we should lower
>>> -	 * the line at this point.
>>> -	 */
>>> -	if (vtimer->irq.level) {
>>> -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
>>> -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
>>> -		if (!kvm_timer_should_fire(vtimer)) {
>>> -			kvm_timer_update_irq(vcpu, false, vtimer);
>>> -			unmask_vtimer_irq(vcpu);
>>> -		}
>>> -	}
>>> +	unmask_vtimer_irq_user(vcpu);
>>>   }
>>
>> While testing your VHE optimization series [1] I noticed massive WFI exits
>> on ThunderX2 so I bisected 'vhe-optimize-v3-with-fixes' branch of [2] down
>> to this commit.
>>
>> The host traps on WFI so that VCPU thread should be scheduled out for some
>> time. However, this is not happening because kvm_vcpu_block() ->
>> kvm_vcpu_check_block() gives negative value (vtimer->irq.level is asserted)
>> and VCPU is woken up immediately. Nobody takes care about lowering the
>> vtimer line in this case.
>>
>> I reverted shape of above kvm_timer_sync_hwstate() and things are good now.
>> Before I start digging I wanted to check with you. Can you please check on
>> your side?
>>
> 
> This patch should fix the issue, thanks for pointing it out.
> https://lists.cs.columbia.edu/pipermail/kvmarm/2018-January/029582.html
> 
> I'd be happy to hear if you can confirm this or not.

Yes, the issue is fixed. Thanks!

> 
> I forgot that my git auto-cc doesn't pick up reported-by tags (I should
> fix that), so apologies for not cc'ing you on the series.
> 

No problem at all.

Tomasz

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v9 7/9] KVM: arm/arm64: Provide a get_input_level for the arch timer
@ 2018-01-31  8:32         ` Tomasz Nowicki
  0 siblings, 0 replies; 36+ messages in thread
From: Tomasz Nowicki @ 2018-01-31  8:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoffer,

On 30.01.2018 13:49, Christoffer Dall wrote:
> Hi Tomasz,
> 
> On Mon, Jan 22, 2018 at 01:32:57PM +0100, Tomasz Nowicki wrote:
>> On 20.12.2017 12:36, Christoffer Dall wrote:
>>> The VGIC can now support the life-cycle of mapped level-triggered
>>> interrupts, and we no longer have to read back the timer state on every
>>> exit from the VM if we had an asserted timer interrupt signal, because
>>> the VGIC already knows if we hit the unlikely case where the guest
>>> disables the timer without ACKing the virtual timer interrupt.
>>>
>>> This means we rework a bit of the code to factor out the functionality
>>> to snapshot the timer state from vtimer_save_state(), and we can reuse
>>> this functionality in the sync path when we have an irqchip in
>>> userspace, and also to support our implementation of the
>>> get_input_level() function for the timer.
>>>
>>> This change also means that we can no longer rely on the timer's view of
>>> the interrupt line to set the active state, because we no longer
>>> maintain this state for mapped interrupts when exiting from the guest.
>>> Instead, we only set the active state if the virtual interrupt is
>>> active, and otherwise we simply let the timer fire again and raise the
>>> virtual interrupt from the ISR.
>>>
>>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>>> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>> ---
>>>   include/kvm/arm_arch_timer.h |  2 ++
>>>   virt/kvm/arm/arch_timer.c    | 84 ++++++++++++++++++++------------------------
>>>   2 files changed, 40 insertions(+), 46 deletions(-)
>>>
>>> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
>>> index 6e45608b2399..b1dcfde0a3ef 100644
>>> --- a/include/kvm/arm_arch_timer.h
>>> +++ b/include/kvm/arm_arch_timer.h
>>> @@ -90,6 +90,8 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
>>>   void kvm_timer_init_vhe(void);
>>> +bool kvm_arch_timer_get_input_level(int vintid);
>>> +
>>>   #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.vtimer)
>>>   #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.ptimer)
>>> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
>>> index fb0533ed903d..d845d67b7062 100644
>>> --- a/virt/kvm/arm/arch_timer.c
>>> +++ b/virt/kvm/arm/arch_timer.c
>>> @@ -343,6 +343,12 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
>>>   	phys_timer_emulate(vcpu);
>>>   }
>>> +static void __timer_snapshot_state(struct arch_timer_context *timer)
>>> +{
>>> +	timer->cnt_ctl = read_sysreg_el0(cntv_ctl);
>>> +	timer->cnt_cval = read_sysreg_el0(cntv_cval);
>>> +}
>>> +
>>>   static void vtimer_save_state(struct kvm_vcpu *vcpu)
>>>   {
>>>   	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
>>> @@ -354,10 +360,8 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
>>>   	if (!vtimer->loaded)
>>>   		goto out;
>>> -	if (timer->enabled) {
>>> -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
>>> -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
>>> -	}
>>> +	if (timer->enabled)
>>> +		__timer_snapshot_state(vtimer);
>>>   	/* Disable the virtual timer */
>>>   	write_sysreg_el0(0, cntv_ctl);
>>> @@ -454,8 +458,7 @@ static void kvm_timer_vcpu_load_vgic(struct kvm_vcpu *vcpu)
>>>   	bool phys_active;
>>>   	int ret;
>>> -	phys_active = vtimer->irq.level ||
>>> -		      kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
>>> +	phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
>>>   	ret = irq_set_irqchip_state(host_vtimer_irq,
>>>   				    IRQCHIP_STATE_ACTIVE,
>>> @@ -535,54 +538,27 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
>>>   	set_cntvoff(0);
>>>   }
>>> -static void unmask_vtimer_irq(struct kvm_vcpu *vcpu)
>>> +/*
>>> + * With a userspace irqchip we have to check if the guest de-asserted the
>>> + * timer and if so, unmask the timer irq signal on the host interrupt
>>> + * controller to ensure that we see future timer signals.
>>> + */
>>> +static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
>>>   {
>>>   	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>>>   	if (unlikely(!irqchip_in_kernel(vcpu->kvm))) {
>>> -		kvm_vtimer_update_mask_user(vcpu);
>>> -		return;
>>> -	}
>>> -
>>> -	/*
>>> -	 * If the guest disabled the timer without acking the interrupt, then
>>> -	 * we must make sure the physical and virtual active states are in
>>> -	 * sync by deactivating the physical interrupt, because otherwise we
>>> -	 * wouldn't see the next timer interrupt in the host.
>>> -	 */
>>> -	if (!kvm_vgic_map_is_active(vcpu, vtimer->irq.irq)) {
>>> -		int ret;
>>> -		ret = irq_set_irqchip_state(host_vtimer_irq,
>>> -					    IRQCHIP_STATE_ACTIVE,
>>> -					    false);
>>> -		WARN_ON(ret);
>>> +		__timer_snapshot_state(vtimer);
>>> +		if (!kvm_timer_should_fire(vtimer)) {
>>> +			kvm_timer_update_irq(vcpu, false, vtimer);
>>> +			kvm_vtimer_update_mask_user(vcpu);
>>> +		}
>>>   	}
>>>   }
>>> -/**
>>> - * kvm_timer_sync_hwstate - sync timer state from cpu
>>> - * @vcpu: The vcpu pointer
>>> - *
>>> - * Check if any of the timers have expired while we were running in the guest,
>>> - * and inject an interrupt if that was the case.
>>> - */
>>>   void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
>>>   {
>>> -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>>> -
>>> -	/*
>>> -	 * If we entered the guest with the vtimer output asserted we have to
>>> -	 * check if the guest has modified the timer so that we should lower
>>> -	 * the line at this point.
>>> -	 */
>>> -	if (vtimer->irq.level) {
>>> -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
>>> -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
>>> -		if (!kvm_timer_should_fire(vtimer)) {
>>> -			kvm_timer_update_irq(vcpu, false, vtimer);
>>> -			unmask_vtimer_irq(vcpu);
>>> -		}
>>> -	}
>>> +	unmask_vtimer_irq_user(vcpu);
>>>   }
>>
>> While testing your VHE optimization series [1] I noticed massive WFI exits
>> on ThunderX2 so I bisected 'vhe-optimize-v3-with-fixes' branch of [2] down
>> to this commit.
>>
>> The host traps on WFI so that VCPU thread should be scheduled out for some
>> time. However, this is not happening because kvm_vcpu_block() ->
>> kvm_vcpu_check_block() gives negative value (vtimer->irq.level is asserted)
>> and VCPU is woken up immediately. Nobody takes care about lowering the
>> vtimer line in this case.
>>
>> I reverted shape of above kvm_timer_sync_hwstate() and things are good now.
>> Before I start digging I wanted to check with you. Can you please check on
>> your side?
>>
> 
> This patch should fix the issue, thanks for pointing it out.
> https://lists.cs.columbia.edu/pipermail/kvmarm/2018-January/029582.html
> 
> I'd be happy to hear if you can confirm this or not.

Yes, the issue is fixed. Thanks!

> 
> I forgot that my git auto-cc doesn't pick up reported-by tags (I should
> fix that), so apologies for not cc'ing you on the series.
> 

No problem at all.

Tomasz

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2018-01-31  8:32 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-20 11:35 [PATCH v9 0/9] Handle forwarded level-triggered interrupts Christoffer Dall
2017-12-20 11:35 ` Christoffer Dall
2017-12-20 11:35 ` [PATCH v9 1/9] KVM: arm/arm64: Remove redundant preemptible checks Christoffer Dall
2017-12-20 11:35   ` Christoffer Dall
2017-12-20 11:35 ` [PATCH v9 2/9] KVM: arm/arm64: Factor out functionality to get vgic mmio requester_vcpu Christoffer Dall
2017-12-20 11:35   ` Christoffer Dall
2017-12-20 11:36 ` [PATCH v9 3/9] KVM: arm/arm64: Don't cache the timer IRQ level Christoffer Dall
2017-12-20 11:36   ` Christoffer Dall
2017-12-20 11:36 ` [PATCH v9 4/9] KVM: arm/arm64: vgic: Support level-triggered mapped interrupts Christoffer Dall
2017-12-20 11:36   ` Christoffer Dall
2017-12-20 11:36 ` [PATCH v9 5/9] KVM: arm/arm64: Support a vgic interrupt line level sample function Christoffer Dall
2017-12-20 11:36   ` Christoffer Dall
2017-12-20 11:36 ` [PATCH v9 6/9] KVM: arm/arm64: Support VGIC dist pend/active changes for mapped IRQs Christoffer Dall
2017-12-20 11:36   ` Christoffer Dall
2017-12-20 11:36 ` [PATCH v9 7/9] KVM: arm/arm64: Provide a get_input_level for the arch timer Christoffer Dall
2017-12-20 11:36   ` Christoffer Dall
2018-01-22 12:32   ` Tomasz Nowicki
2018-01-22 12:32     ` Tomasz Nowicki
2018-01-22 17:58     ` Christoffer Dall
2018-01-22 17:58       ` Christoffer Dall
2018-01-30 12:49     ` Christoffer Dall
2018-01-30 12:49       ` Christoffer Dall
2018-01-31  8:32       ` Tomasz Nowicki
2018-01-31  8:32         ` Tomasz Nowicki
2018-01-31  8:32       ` Tomasz Nowicki
2018-01-31  8:32         ` Tomasz Nowicki
2017-12-20 11:36 ` [PATCH v9 8/9] KVM: arm/arm64: Avoid work when userspace iqchips are not used Christoffer Dall
2017-12-20 11:36   ` Christoffer Dall
2017-12-27 16:36   ` Marc Zyngier
2017-12-27 16:36     ` Marc Zyngier
2018-01-02  9:09     ` Christoffer Dall
2018-01-02  9:09       ` Christoffer Dall
2017-12-20 11:36 ` [PATCH v9 9/9] KVM: arm/arm64: Delete outdated forwarded irq documentation Christoffer Dall
2017-12-20 11:36   ` Christoffer Dall
2017-12-27 16:37   ` Marc Zyngier
2017-12-27 16:37     ` Marc Zyngier

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.