#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
 #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
 
        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 */
 
 
        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;
 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,
                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;
                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;
        }
 
 
 
        /* 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) {
 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);
 }
 
 
 
        /* 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
 
                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++;
 
         */
        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);
        }
        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
         * 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);
         * 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,
 
         * 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",
 
        {0x400, "INST_STORAGE"}, \
        {0x480, "INST_SEGMENT"}, \
        {0x500, "EXTERNAL"}, \
-       {0x501, "EXTERNAL_LEVEL"}, \
        {0x502, "EXTERNAL_HV"}, \
        {0x600, "ALIGNMENT"}, \
        {0x700, "PROGRAM"}, \
 
        {0x400, "INST_STORAGE"}, \
        {0x480, "INST_SEGMENT"}, \
        {0x500, "EXTERNAL"}, \
-       {0x501, "EXTERNAL_LEVEL"}, \
        {0x502, "EXTERNAL_HV"}, \
        {0x600, "ALIGNMENT"}, \
        {0x700, "PROGRAM"}, \