Re: [RFC PATCH 01/32] KVM: PPC: Book3S: Simplify external interrupt handling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Sep 21, 2018 at 08:01:32PM +1000, Paul Mackerras wrote:
> Currently we use two bits in the vcpu pending_exceptions bitmap to
> indicate that an external interrupt is pending for the guest, one
> for "one-shot" interrupts that are cleared when delivered, and one
> for interrupts that persist until cleared by an explicit action of
> the OS (e.g. an acknowledge to an interrupt controller).  The
> BOOK3S_IRQPRIO_EXTERNAL bit is used for one-shot interrupt requests
> and BOOK3S_IRQPRIO_EXTERNAL_LEVEL is used for persisting interrupts.
> 
> In practice BOOK3S_IRQPRIO_EXTERNAL never gets used, because our
> Book3S platforms generally, and pseries in particular, expect
> external interrupt requests to persist until they are acknowledged
> at the interrupt controller.  That combined with the confusion
> introduced by having two bits for what is essentially the same thing
> makes it attractive to simplify things by only using one bit.  This
> patch does that.
> 
> With this patch there is only BOOK3S_IRQPRIO_EXTERNAL, and by default
> it has the semantics of a persisting interrupt.  In order to avoid
> breaking the ABI, we introduce a new "external_oneshot" flag which
> preserves the behaviour of the KVM_INTERRUPT ioctl with the
> KVM_INTERRUPT_SET argument.
> 
> Signed-off-by: Paul Mackerras <paulus@xxxxxxxxxx>

Reviewed-by: David Gibson <david@xxxxxxxxxxxxxxxxxxxxx>

> ---
>  arch/powerpc/include/asm/kvm_asm.h             |  4 +--
>  arch/powerpc/include/asm/kvm_host.h            |  1 +
>  arch/powerpc/kvm/book3s.c                      | 43 ++++++++++++++++++++------
>  arch/powerpc/kvm/book3s_hv_rm_xics.c           |  5 ++-
>  arch/powerpc/kvm/book3s_hv_rmhandlers.S        |  4 +--
>  arch/powerpc/kvm/book3s_pr.c                   |  1 -
>  arch/powerpc/kvm/book3s_xics.c                 | 11 +++----
>  arch/powerpc/kvm/book3s_xive_template.c        |  2 +-
>  arch/powerpc/kvm/trace_book3s.h                |  1 -
>  tools/perf/arch/powerpc/util/book3s_hv_exits.h |  1 -
>  10 files changed, 44 insertions(+), 29 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h
> index a790d5c..1f32191 100644
> --- a/arch/powerpc/include/asm/kvm_asm.h
> +++ b/arch/powerpc/include/asm/kvm_asm.h
> @@ -84,7 +84,6 @@
>  #define BOOK3S_INTERRUPT_INST_STORAGE	0x400
>  #define BOOK3S_INTERRUPT_INST_SEGMENT	0x480
>  #define BOOK3S_INTERRUPT_EXTERNAL	0x500
> -#define BOOK3S_INTERRUPT_EXTERNAL_LEVEL	0x501
>  #define BOOK3S_INTERRUPT_EXTERNAL_HV	0x502
>  #define BOOK3S_INTERRUPT_ALIGNMENT	0x600
>  #define BOOK3S_INTERRUPT_PROGRAM	0x700
> @@ -134,8 +133,7 @@
>  #define BOOK3S_IRQPRIO_EXTERNAL			14
>  #define BOOK3S_IRQPRIO_DECREMENTER		15
>  #define BOOK3S_IRQPRIO_PERFORMANCE_MONITOR	16
> -#define BOOK3S_IRQPRIO_EXTERNAL_LEVEL		17
> -#define BOOK3S_IRQPRIO_MAX			18
> +#define BOOK3S_IRQPRIO_MAX			17
>  
>  #define BOOK3S_HFLAG_DCBZ32			0x1
>  #define BOOK3S_HFLAG_SLB			0x2
> diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
> index 906bcbdf..3cd0b9f 100644
> --- a/arch/powerpc/include/asm/kvm_host.h
> +++ b/arch/powerpc/include/asm/kvm_host.h
> @@ -707,6 +707,7 @@ struct kvm_vcpu_arch {
>  	u8 hcall_needed;
>  	u8 epr_flags; /* KVMPPC_EPR_xxx */
>  	u8 epr_needed;
> +	u8 external_oneshot;	/* clear external irq after delivery */
>  
>  	u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */
>  
> diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
> index 87348e4..66a5521 100644
> --- a/arch/powerpc/kvm/book3s.c
> +++ b/arch/powerpc/kvm/book3s.c
> @@ -150,7 +150,6 @@ static int kvmppc_book3s_vec2irqprio(unsigned int vec)
>  	case 0x400: prio = BOOK3S_IRQPRIO_INST_STORAGE;		break;
>  	case 0x480: prio = BOOK3S_IRQPRIO_INST_SEGMENT;		break;
>  	case 0x500: prio = BOOK3S_IRQPRIO_EXTERNAL;		break;
> -	case 0x501: prio = BOOK3S_IRQPRIO_EXTERNAL_LEVEL;	break;
>  	case 0x600: prio = BOOK3S_IRQPRIO_ALIGNMENT;		break;
>  	case 0x700: prio = BOOK3S_IRQPRIO_PROGRAM;		break;
>  	case 0x800: prio = BOOK3S_IRQPRIO_FP_UNAVAIL;		break;
> @@ -236,18 +235,35 @@ EXPORT_SYMBOL_GPL(kvmppc_core_dequeue_dec);
>  void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
>                                  struct kvm_interrupt *irq)
>  {
> -	unsigned int vec = BOOK3S_INTERRUPT_EXTERNAL;
> -
> -	if (irq->irq == KVM_INTERRUPT_SET_LEVEL)
> -		vec = BOOK3S_INTERRUPT_EXTERNAL_LEVEL;
> +	/*
> +	 * This case (KVM_INTERRUPT_SET) should never actually arise for
> +	 * a pseries guest (because pseries guests expect their interrupt
> +	 * controllers to continue asserting an external interrupt request
> +	 * until it is acknowledged at the interrupt controller), but is
> +	 * included to avoid ABI breakage and potentially for other
> +	 * sorts of guest.
> +	 *
> +	 * There is a subtlety here: HV KVM does not test the
> +	 * external_oneshot flag in the code that synthesizes
> +	 * external interrupts for the guest just before entering
> +	 * the guest.  That is OK even if userspace did do a
> +	 * KVM_INTERRUPT_SET on a pseries guest vcpu, because the
> +	 * caller (kvm_vcpu_ioctl_interrupt) does a kvm_vcpu_kick()
> +	 * which ends up doing a smp_send_reschedule(), which will
> +	 * pull the guest all the way out to the host, meaning that
> +	 * we will call kvmppc_core_prepare_to_enter() before entering
> +	 * the guest again, and that will handle the external_oneshot
> +	 * flag correctly.
> +	 */
> +	if (irq->irq == KVM_INTERRUPT_SET)
> +		vcpu->arch.external_oneshot = 1;
>  
> -	kvmppc_book3s_queue_irqprio(vcpu, vec);
> +	kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL);
>  }
>  
>  void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu)
>  {
>  	kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL);
> -	kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL_LEVEL);
>  }
>  
>  void kvmppc_core_queue_data_storage(struct kvm_vcpu *vcpu, ulong dar,
> @@ -278,7 +294,6 @@ static int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu,
>  		vec = BOOK3S_INTERRUPT_DECREMENTER;
>  		break;
>  	case BOOK3S_IRQPRIO_EXTERNAL:
> -	case BOOK3S_IRQPRIO_EXTERNAL_LEVEL:
>  		deliver = (kvmppc_get_msr(vcpu) & MSR_EE) && !crit;
>  		vec = BOOK3S_INTERRUPT_EXTERNAL;
>  		break;
> @@ -352,8 +367,16 @@ static bool clear_irqprio(struct kvm_vcpu *vcpu, unsigned int priority)
>  		case BOOK3S_IRQPRIO_DECREMENTER:
>  			/* DEC interrupts get cleared by mtdec */
>  			return false;
> -		case BOOK3S_IRQPRIO_EXTERNAL_LEVEL:
> -			/* External interrupts get cleared by userspace */
> +		case BOOK3S_IRQPRIO_EXTERNAL:
> +			/*
> +			 * External interrupts get cleared by userspace
> +			 * except when set by the KVM_INTERRUPT ioctl with
> +			 * KVM_INTERRUPT_SET (not KVM_INTERRUPT_SET_LEVEL).
> +			 */
> +			if (vcpu->arch.external_oneshot) {
> +				vcpu->arch.external_oneshot = 0;
> +				return true;
> +			}
>  			return false;
>  	}
>  
> diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c b/arch/powerpc/kvm/book3s_hv_rm_xics.c
> index 758d1d2..8b9f356 100644
> --- a/arch/powerpc/kvm/book3s_hv_rm_xics.c
> +++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c
> @@ -136,7 +136,7 @@ static void icp_rm_set_vcpu_irq(struct kvm_vcpu *vcpu,
>  
>  	/* Mark the target VCPU as having an interrupt pending */
>  	vcpu->stat.queue_intr++;
> -	set_bit(BOOK3S_IRQPRIO_EXTERNAL_LEVEL, &vcpu->arch.pending_exceptions);
> +	set_bit(BOOK3S_IRQPRIO_EXTERNAL, &vcpu->arch.pending_exceptions);
>  
>  	/* Kick self ? Just set MER and return */
>  	if (vcpu == this_vcpu) {
> @@ -170,8 +170,7 @@ static void icp_rm_set_vcpu_irq(struct kvm_vcpu *vcpu,
>  static void icp_rm_clr_vcpu_irq(struct kvm_vcpu *vcpu)
>  {
>  	/* Note: Only called on self ! */
> -	clear_bit(BOOK3S_IRQPRIO_EXTERNAL_LEVEL,
> -		  &vcpu->arch.pending_exceptions);
> +	clear_bit(BOOK3S_IRQPRIO_EXTERNAL, &vcpu->arch.pending_exceptions);
>  	mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~LPCR_MER);
>  }
>  
> diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> index 1d14046..77960e6 100644
> --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> @@ -1122,11 +1122,11 @@ kvmppc_cede_reentry:		/* r4 = vcpu, r13 = paca */
>  
>  	/* Check if we can deliver an external or decrementer interrupt now */
>  	ld	r0, VCPU_PENDING_EXC(r4)
> -	rldicl	r0, r0, 64 - BOOK3S_IRQPRIO_EXTERNAL_LEVEL, 63
> +	rldicl	r0, r0, 64 - BOOK3S_IRQPRIO_EXTERNAL, 63
>  	cmpdi	cr1, r0, 0
>  	andi.	r8, r11, MSR_EE
>  	mfspr	r8, SPRN_LPCR
> -	/* Insert EXTERNAL_LEVEL bit into LPCR at the MER bit position */
> +	/* Insert EXTERNAL bit into LPCR at the MER bit position */
>  	rldimi	r8, r0, LPCR_MER_SH, 63 - LPCR_MER_SH
>  	mtspr	SPRN_LPCR, r8
>  	isync
> diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
> index 614ebb4..059683e4 100644
> --- a/arch/powerpc/kvm/book3s_pr.c
> +++ b/arch/powerpc/kvm/book3s_pr.c
> @@ -1246,7 +1246,6 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
>  		r = RESUME_GUEST;
>  		break;
>  	case BOOK3S_INTERRUPT_EXTERNAL:
> -	case BOOK3S_INTERRUPT_EXTERNAL_LEVEL:
>  	case BOOK3S_INTERRUPT_EXTERNAL_HV:
>  	case BOOK3S_INTERRUPT_H_VIRT:
>  		vcpu->stat.ext_intr_exits++;
> diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c
> index b8356cd..d9ba1b0 100644
> --- a/arch/powerpc/kvm/book3s_xics.c
> +++ b/arch/powerpc/kvm/book3s_xics.c
> @@ -310,7 +310,7 @@ static inline bool icp_try_update(struct kvmppc_icp *icp,
>  	 */
>  	if (new.out_ee) {
>  		kvmppc_book3s_queue_irqprio(icp->vcpu,
> -					    BOOK3S_INTERRUPT_EXTERNAL_LEVEL);
> +					    BOOK3S_INTERRUPT_EXTERNAL);
>  		if (!change_self)
>  			kvmppc_fast_vcpu_kick(icp->vcpu);
>  	}
> @@ -593,8 +593,7 @@ static noinline unsigned long kvmppc_h_xirr(struct kvm_vcpu *vcpu)
>  	u32 xirr;
>  
>  	/* First, remove EE from the processor */
> -	kvmppc_book3s_dequeue_irqprio(icp->vcpu,
> -				      BOOK3S_INTERRUPT_EXTERNAL_LEVEL);
> +	kvmppc_book3s_dequeue_irqprio(icp->vcpu, BOOK3S_INTERRUPT_EXTERNAL);
>  
>  	/*
>  	 * ICP State: Accept_Interrupt
> @@ -754,8 +753,7 @@ static noinline void kvmppc_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr)
>  	 * We can remove EE from the current processor, the update
>  	 * transaction will set it again if needed
>  	 */
> -	kvmppc_book3s_dequeue_irqprio(icp->vcpu,
> -				      BOOK3S_INTERRUPT_EXTERNAL_LEVEL);
> +	kvmppc_book3s_dequeue_irqprio(icp->vcpu, BOOK3S_INTERRUPT_EXTERNAL);
>  
>  	do {
>  		old_state = new_state = READ_ONCE(icp->state);
> @@ -1167,8 +1165,7 @@ int kvmppc_xics_set_icp(struct kvm_vcpu *vcpu, u64 icpval)
>  	 * Deassert the CPU interrupt request.
>  	 * icp_try_update will reassert it if necessary.
>  	 */
> -	kvmppc_book3s_dequeue_irqprio(icp->vcpu,
> -				      BOOK3S_INTERRUPT_EXTERNAL_LEVEL);
> +	kvmppc_book3s_dequeue_irqprio(icp->vcpu, BOOK3S_INTERRUPT_EXTERNAL);
>  
>  	/*
>  	 * Note that if we displace an interrupt from old_state.xisr,
> diff --git a/arch/powerpc/kvm/book3s_xive_template.c b/arch/powerpc/kvm/book3s_xive_template.c
> index 4171ede..203ea65 100644
> --- a/arch/powerpc/kvm/book3s_xive_template.c
> +++ b/arch/powerpc/kvm/book3s_xive_template.c
> @@ -285,7 +285,7 @@ X_STATIC unsigned long GLUE(X_PFX,h_xirr)(struct kvm_vcpu *vcpu)
>  	 * set by pull or an escalation interrupts).
>  	 */
>  	if (test_bit(BOOK3S_IRQPRIO_EXTERNAL, &vcpu->arch.pending_exceptions))
> -		clear_bit(BOOK3S_IRQPRIO_EXTERNAL_LEVEL,
> +		clear_bit(BOOK3S_IRQPRIO_EXTERNAL,
>  			  &vcpu->arch.pending_exceptions);
>  
>  	pr_devel(" new pending=0x%02x hw_cppr=%d cppr=%d\n",
> diff --git a/arch/powerpc/kvm/trace_book3s.h b/arch/powerpc/kvm/trace_book3s.h
> index f3b2375..372a82f 100644
> --- a/arch/powerpc/kvm/trace_book3s.h
> +++ b/arch/powerpc/kvm/trace_book3s.h
> @@ -14,7 +14,6 @@
>  	{0x400, "INST_STORAGE"}, \
>  	{0x480, "INST_SEGMENT"}, \
>  	{0x500, "EXTERNAL"}, \
> -	{0x501, "EXTERNAL_LEVEL"}, \
>  	{0x502, "EXTERNAL_HV"}, \
>  	{0x600, "ALIGNMENT"}, \
>  	{0x700, "PROGRAM"}, \
> diff --git a/tools/perf/arch/powerpc/util/book3s_hv_exits.h b/tools/perf/arch/powerpc/util/book3s_hv_exits.h
> index 853b95d1..2011376 100644
> --- a/tools/perf/arch/powerpc/util/book3s_hv_exits.h
> +++ b/tools/perf/arch/powerpc/util/book3s_hv_exits.h
> @@ -15,7 +15,6 @@
>  	{0x400, "INST_STORAGE"}, \
>  	{0x480, "INST_SEGMENT"}, \
>  	{0x500, "EXTERNAL"}, \
> -	{0x501, "EXTERNAL_LEVEL"}, \
>  	{0x502, "EXTERNAL_HV"}, \
>  	{0x600, "ALIGNMENT"}, \
>  	{0x700, "PROGRAM"}, \

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux