diff mbox

[Xenial,SRU] KVM: PPC: Book3S HV: Re-enable XICS fast path for irqfd-generated interrupts

Message ID 1466034731-9291-1-git-send-email-tim.gardner@canonical.com
State New
Headers show

Commit Message

Tim Gardner June 15, 2016, 11:52 p.m. UTC
From: Paul Mackerras <paulus@ozlabs.org>

BugLink: http://bugs.launchpad.net/bugs/1592809

Commit c9a5eccac1ab ("kvm/eventfd: add arch-specific set_irq",
2015-10-16) added the possibility for architecture-specific code
to handle the generation of virtual interrupts in atomic context
where possible, without having to schedule a work function.

Since we can easily generate virtual interrupts on XICS without
having to do anything worse than take a spinlock, we define a
kvm_arch_set_irq_inatomic() for XICS.  We also remove kvm_set_msi()
since it is not used any more.

The one slightly tricky thing is that with the new interface, we
don't get told whether the interrupt is an MSI (or other edge
sensitive interrupt) vs. level-sensitive.  The difference as far
as interrupt generation is concerned is that for LSIs we have to
set the asserted flag so it will continue to fire until it is
explicitly cleared.

In fact the XICS code gets told which interrupts are LSIs by userspace
when it configures the interrupt via the KVM_DEV_XICS_GRP_SOURCES
attribute group on the XICS device.  To store this information, we add
a new "lsi" field to struct ics_irq_state.  With that we can also do a
better job of returning accurate values when reading the attribute
group.

Signed-off-by: Paul Mackerras <paulus@samba.org>
(cherry picked from commit b1a4286b8f3393857a205ec89607683161b75f90)
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
---
 arch/powerpc/kvm/book3s_xics.c | 25 +++++++++++++++----------
 arch/powerpc/kvm/book3s_xics.h |  1 +
 2 files changed, 16 insertions(+), 10 deletions(-)

Comments

Chris J Arges June 16, 2016, 6:37 a.m. UTC | #1
ACK clean cherry-pick, nothing newer that seems to need application.
--chris

On Thu, Jun 16, 2016 at 02:52:11AM +0300, Tim Gardner wrote:
> From: Paul Mackerras <paulus@ozlabs.org>
> 
> BugLink: http://bugs.launchpad.net/bugs/1592809
> 
> Commit c9a5eccac1ab ("kvm/eventfd: add arch-specific set_irq",
> 2015-10-16) added the possibility for architecture-specific code
> to handle the generation of virtual interrupts in atomic context
> where possible, without having to schedule a work function.
> 
> Since we can easily generate virtual interrupts on XICS without
> having to do anything worse than take a spinlock, we define a
> kvm_arch_set_irq_inatomic() for XICS.  We also remove kvm_set_msi()
> since it is not used any more.
> 
> The one slightly tricky thing is that with the new interface, we
> don't get told whether the interrupt is an MSI (or other edge
> sensitive interrupt) vs. level-sensitive.  The difference as far
> as interrupt generation is concerned is that for LSIs we have to
> set the asserted flag so it will continue to fire until it is
> explicitly cleared.
> 
> In fact the XICS code gets told which interrupts are LSIs by userspace
> when it configures the interrupt via the KVM_DEV_XICS_GRP_SOURCES
> attribute group on the XICS device.  To store this information, we add
> a new "lsi" field to struct ics_irq_state.  With that we can also do a
> better job of returning accurate values when reading the attribute
> group.
> 
> Signed-off-by: Paul Mackerras <paulus@samba.org>
> (cherry picked from commit b1a4286b8f3393857a205ec89607683161b75f90)
> Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
> ---
>  arch/powerpc/kvm/book3s_xics.c | 25 +++++++++++++++----------
>  arch/powerpc/kvm/book3s_xics.h |  1 +
>  2 files changed, 16 insertions(+), 10 deletions(-)
> 
> diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c
> index 905e94a..df75fc8 100644
> --- a/arch/powerpc/kvm/book3s_xics.c
> +++ b/arch/powerpc/kvm/book3s_xics.c
> @@ -92,7 +92,7 @@ static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level)
>  	 * we are the only setter, thus concurrent access is undefined
>  	 * to begin with.
>  	 */
> -	if (level == 1 || level == KVM_INTERRUPT_SET_LEVEL)
> +	if ((level == 1 && state->lsi) || level == KVM_INTERRUPT_SET_LEVEL)
>  		state->asserted = 1;
>  	else if (level == 0 || level == KVM_INTERRUPT_UNSET) {
>  		state->asserted = 0;
> @@ -1174,9 +1174,11 @@ static int xics_get_source(struct kvmppc_xics *xics, long irq, u64 addr)
>  			prio = irqp->saved_priority;
>  		}
>  		val |= prio << KVM_XICS_PRIORITY_SHIFT;
> -		if (irqp->asserted)
> -			val |= KVM_XICS_LEVEL_SENSITIVE | KVM_XICS_PENDING;
> -		else if (irqp->masked_pending || irqp->resend)
> +		if (irqp->lsi) {
> +			val |= KVM_XICS_LEVEL_SENSITIVE;
> +			if (irqp->asserted)
> +				val |= KVM_XICS_PENDING;
> +		} else if (irqp->masked_pending || irqp->resend)
>  			val |= KVM_XICS_PENDING;
>  		ret = 0;
>  	}
> @@ -1228,9 +1230,13 @@ static int xics_set_source(struct kvmppc_xics *xics, long irq, u64 addr)
>  	irqp->priority = prio;
>  	irqp->resend = 0;
>  	irqp->masked_pending = 0;
> +	irqp->lsi = 0;
>  	irqp->asserted = 0;
> -	if ((val & KVM_XICS_PENDING) && (val & KVM_XICS_LEVEL_SENSITIVE))
> -		irqp->asserted = 1;
> +	if (val & KVM_XICS_LEVEL_SENSITIVE) {
> +		irqp->lsi = 1;
> +		if (val & KVM_XICS_PENDING)
> +			irqp->asserted = 1;
> +	}
>  	irqp->exists = 1;
>  	arch_spin_unlock(&ics->lock);
>  	local_irq_restore(flags);
> @@ -1249,11 +1255,10 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level,
>  	return ics_deliver_irq(xics, irq, level);
>  }
>  
> -int kvm_set_msi(struct kvm_kernel_irq_routing_entry *irq_entry, struct kvm *kvm,
> -		int irq_source_id, int level, bool line_status)
> +int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *irq_entry,
> +			      struct kvm *kvm, int irq_source_id,
> +			      int level, bool line_status)
>  {
> -	if (!level)
> -		return -1;
>  	return kvm_set_irq(kvm, irq_source_id, irq_entry->gsi,
>  			   level, line_status);
>  }
> diff --git a/arch/powerpc/kvm/book3s_xics.h b/arch/powerpc/kvm/book3s_xics.h
> index 56ea44f..a46b954 100644
> --- a/arch/powerpc/kvm/book3s_xics.h
> +++ b/arch/powerpc/kvm/book3s_xics.h
> @@ -39,6 +39,7 @@ struct ics_irq_state {
>  	u8  saved_priority;
>  	u8  resend;
>  	u8  masked_pending;
> +	u8  lsi;		/* level-sensitive interrupt */
>  	u8  asserted; /* Only for LSI */
>  	u8  exists;
>  };
> -- 
> 2.7.4
> 
> 
> -- 
> kernel-team mailing list
> kernel-team@lists.ubuntu.com
> https://lists.ubuntu.com/mailman/listinfo/kernel-team
Kamal Mostafa June 16, 2016, 3:49 p.m. UTC | #2
Applied to X.

 -Kamal
diff mbox

Patch

diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c
index 905e94a..df75fc8 100644
--- a/arch/powerpc/kvm/book3s_xics.c
+++ b/arch/powerpc/kvm/book3s_xics.c
@@ -92,7 +92,7 @@  static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level)
 	 * we are the only setter, thus concurrent access is undefined
 	 * to begin with.
 	 */
-	if (level == 1 || level == KVM_INTERRUPT_SET_LEVEL)
+	if ((level == 1 && state->lsi) || level == KVM_INTERRUPT_SET_LEVEL)
 		state->asserted = 1;
 	else if (level == 0 || level == KVM_INTERRUPT_UNSET) {
 		state->asserted = 0;
@@ -1174,9 +1174,11 @@  static int xics_get_source(struct kvmppc_xics *xics, long irq, u64 addr)
 			prio = irqp->saved_priority;
 		}
 		val |= prio << KVM_XICS_PRIORITY_SHIFT;
-		if (irqp->asserted)
-			val |= KVM_XICS_LEVEL_SENSITIVE | KVM_XICS_PENDING;
-		else if (irqp->masked_pending || irqp->resend)
+		if (irqp->lsi) {
+			val |= KVM_XICS_LEVEL_SENSITIVE;
+			if (irqp->asserted)
+				val |= KVM_XICS_PENDING;
+		} else if (irqp->masked_pending || irqp->resend)
 			val |= KVM_XICS_PENDING;
 		ret = 0;
 	}
@@ -1228,9 +1230,13 @@  static int xics_set_source(struct kvmppc_xics *xics, long irq, u64 addr)
 	irqp->priority = prio;
 	irqp->resend = 0;
 	irqp->masked_pending = 0;
+	irqp->lsi = 0;
 	irqp->asserted = 0;
-	if ((val & KVM_XICS_PENDING) && (val & KVM_XICS_LEVEL_SENSITIVE))
-		irqp->asserted = 1;
+	if (val & KVM_XICS_LEVEL_SENSITIVE) {
+		irqp->lsi = 1;
+		if (val & KVM_XICS_PENDING)
+			irqp->asserted = 1;
+	}
 	irqp->exists = 1;
 	arch_spin_unlock(&ics->lock);
 	local_irq_restore(flags);
@@ -1249,11 +1255,10 @@  int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level,
 	return ics_deliver_irq(xics, irq, level);
 }
 
-int kvm_set_msi(struct kvm_kernel_irq_routing_entry *irq_entry, struct kvm *kvm,
-		int irq_source_id, int level, bool line_status)
+int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *irq_entry,
+			      struct kvm *kvm, int irq_source_id,
+			      int level, bool line_status)
 {
-	if (!level)
-		return -1;
 	return kvm_set_irq(kvm, irq_source_id, irq_entry->gsi,
 			   level, line_status);
 }
diff --git a/arch/powerpc/kvm/book3s_xics.h b/arch/powerpc/kvm/book3s_xics.h
index 56ea44f..a46b954 100644
--- a/arch/powerpc/kvm/book3s_xics.h
+++ b/arch/powerpc/kvm/book3s_xics.h
@@ -39,6 +39,7 @@  struct ics_irq_state {
 	u8  saved_priority;
 	u8  resend;
 	u8  masked_pending;
+	u8  lsi;		/* level-sensitive interrupt */
 	u8  asserted; /* Only for LSI */
 	u8  exists;
 };