by kvm.  The 'data' member contains the written data if 'is_write' is
 true, and should be filled by application code otherwise.
 
-NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO, KVM_EXIT_OSI, KVM_EXIT_DCR
-      and KVM_EXIT_PAPR the corresponding
+NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO, KVM_EXIT_OSI, KVM_EXIT_DCR,
+      KVM_EXIT_PAPR and KVM_EXIT_EPR the corresponding
 operations are complete (and guest state is consistent) only after userspace
 has re-entered the kernel with KVM_RUN.  The kernel side will first finish
 incomplete operations and then check for pending signals.  Userspace
 subchannel_nr, io_int_parm and io_int_word contain the parameters for that
 interrupt. ipb is needed for instruction parameter decoding.
 
+               /* KVM_EXIT_EPR */
+               struct {
+                       __u32 epr;
+               } epr;
+
+On FSL BookE PowerPC chips, the interrupt controller has a fast patch
+interrupt acknowledge path to the core. When the core successfully
+delivers an interrupt, it automatically populates the EPR register with
+the interrupt vector number and acknowledges the interrupt inside
+the interrupt controller.
+
+In case the interrupt controller lives in user space, we need to do
+the interrupt acknowledge cycle through it to fetch the next to be
+delivered interrupt vector using this exit.
+
+It gets triggered whenever both KVM_CAP_PPC_EPR are enabled and an
+external interrupt has just been delivered into the guest. User space
+should put the acknowledged interrupt vector into the 'epr' field.
+
                /* Fix the size of the union. */
                char padding[256];
        };
 
 When this capability is enabled, KVM_EXIT_S390_TSCH will occur on TEST
 SUBCHANNEL intercepts.
+
+6.5 KVM_CAP_PPC_EPR
+
+Architectures: ppc
+Parameters: args[0] defines whether the proxy facility is active
+Returns: 0 on success; -1 on error
+
+This capability enables or disables the delivery of interrupts through the
+external proxy facility.
+
+When enabled (args[0] != 0), every time the guest gets an external interrupt
+delivered, it automatically exits into user space with a KVM_EXIT_EPR exit
+to receive the topmost interrupt vector.
+
+When disabled (args[0] == 0), behavior is as if this facility is unsupported.
+
+When this capability is enabled, KVM_EXIT_EPR can occur.
 
        u8 sane;
        u8 cpu_type;
        u8 hcall_needed;
+       u8 epr_enabled;
+       u8 epr_needed;
 
        u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */
 
 
 {}
 #endif
 
+static inline void kvmppc_set_epr(struct kvm_vcpu *vcpu, u32 epr)
+{
+#ifdef CONFIG_KVM_BOOKE_HV
+       mtspr(SPRN_GEPR, epr);
+#elif defined(CONFIG_BOOKE)
+       vcpu->arch.epr = epr;
+#endif
+}
+
 int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu,
                              struct kvm_config_tlb *cfg);
 int kvm_vcpu_ioctl_dirty_tlb(struct kvm_vcpu *vcpu,
 
 {
        int allowed = 0;
        ulong msr_mask = 0;
-       bool update_esr = false, update_dear = false;
+       bool update_esr = false, update_dear = false, update_epr = false;
        ulong crit_raw = vcpu->arch.shared->critical;
        ulong crit_r1 = kvmppc_get_gpr(vcpu, 1);
        bool crit;
                keep_irq = true;
        }
 
+       if ((priority == BOOKE_IRQPRIO_EXTERNAL) && vcpu->arch.epr_enabled)
+               update_epr = true;
+
        switch (priority) {
        case BOOKE_IRQPRIO_DTLB_MISS:
        case BOOKE_IRQPRIO_DATA_STORAGE:
                        set_guest_esr(vcpu, vcpu->arch.queued_esr);
                if (update_dear == true)
                        set_guest_dear(vcpu, vcpu->arch.queued_dear);
+               if (update_epr == true)
+                       kvm_make_request(KVM_REQ_EPR_EXIT, vcpu);
 
                new_msr &= msr_mask;
 #if defined(CONFIG_64BIT)
                r = 0;
        }
 
+       if (kvm_check_request(KVM_REQ_EPR_EXIT, vcpu)) {
+               vcpu->run->epr.epr = 0;
+               vcpu->arch.epr_needed = true;
+               vcpu->run->exit_reason = KVM_EXIT_EPR;
+               r = 0;
+       }
+
        return r;
 }
 
 
 #ifdef CONFIG_BOOKE
        case KVM_CAP_PPC_BOOKE_SREGS:
        case KVM_CAP_PPC_BOOKE_WATCHDOG:
+       case KVM_CAP_PPC_EPR:
 #else
        case KVM_CAP_PPC_SEGSTATE:
        case KVM_CAP_PPC_HIOR:
                for (i = 0; i < 9; ++i)
                        kvmppc_set_gpr(vcpu, 4 + i, run->papr_hcall.args[i]);
                vcpu->arch.hcall_needed = 0;
+#ifdef CONFIG_BOOKE
+       } else if (vcpu->arch.epr_needed) {
+               kvmppc_set_epr(vcpu, run->epr.epr);
+               vcpu->arch.epr_needed = 0;
+#endif
        }
 
        r = kvmppc_vcpu_run(run, vcpu);
                r = 0;
                vcpu->arch.papr_enabled = true;
                break;
+       case KVM_CAP_PPC_EPR:
+               r = 0;
+               vcpu->arch.epr_enabled = cap->args[0];
+               break;
 #ifdef CONFIG_BOOKE
        case KVM_CAP_PPC_BOOKE_WATCHDOG:
                r = 0;
 
 #define KVM_REQ_WATCHDOG          18
 #define KVM_REQ_MASTERCLOCK_UPDATE 19
 #define KVM_REQ_MCLOCK_INPROGRESS 20
+#define KVM_REQ_EPR_EXIT          21
 
 #define KVM_USERSPACE_IRQ_SOURCE_ID            0
 #define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID       1
 
 #define KVM_EXIT_S390_UCONTROL   20
 #define KVM_EXIT_WATCHDOG         21
 #define KVM_EXIT_S390_TSCH        22
+#define KVM_EXIT_EPR              23
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
                        __u32 ipb;
                        __u8 dequeued;
                } s390_tsch;
+               /* KVM_EXIT_EPR */
+               struct {
+                       __u32 epr;
+               } epr;
                /* Fix the size of the union. */
                char padding[256];
        };
 #define KVM_CAP_PPC_BOOKE_WATCHDOG 83
 #define KVM_CAP_PPC_HTAB_FD 84
 #define KVM_CAP_S390_CSS_SUPPORT 85
+#define KVM_CAP_PPC_EPR 86
 
 #ifdef KVM_CAP_IRQ_ROUTING