static struct irq_info *legacy_info_ptrs[NR_IRQS_LEGACY];
 
 static struct irq_chip xen_dynamic_chip;
+static struct irq_chip xen_lateeoi_chip;
 static struct irq_chip xen_percpu_chip;
 static struct irq_chip xen_pirq_chip;
 static void enable_dynirq(struct irq_data *data);
 }
 EXPORT_SYMBOL_GPL(notify_remote_via_irq);
 
+static void xen_irq_lateeoi_locked(struct irq_info *info)
+{
+       evtchn_port_t evtchn;
+
+       evtchn = info->evtchn;
+       if (!VALID_EVTCHN(evtchn))
+               return;
+
+       unmask_evtchn(evtchn);
+}
+
+void xen_irq_lateeoi(unsigned int irq, unsigned int eoi_flags)
+{
+       struct irq_info *info;
+       unsigned long flags;
+
+       read_lock_irqsave(&evtchn_rwlock, flags);
+
+       info = info_for_irq(irq);
+
+       if (info)
+               xen_irq_lateeoi_locked(info);
+
+       read_unlock_irqrestore(&evtchn_rwlock, flags);
+}
+EXPORT_SYMBOL_GPL(xen_irq_lateeoi);
+
 static void xen_irq_init(unsigned irq)
 {
        struct irq_info *info;
 }
 EXPORT_SYMBOL_GPL(xen_pirq_from_irq);
 
-int bind_evtchn_to_irq(unsigned int evtchn)
+static int bind_evtchn_to_irq_chip(evtchn_port_t evtchn, struct irq_chip *chip)
 {
        int irq;
        int ret;
                if (irq < 0)
                        goto out;
 
-               irq_set_chip_and_handler_name(irq, &xen_dynamic_chip,
+               irq_set_chip_and_handler_name(irq, chip,
                                              handle_edge_irq, "event");
 
                ret = xen_irq_info_evtchn_setup(irq, evtchn);
 
        return irq;
 }
+
+int bind_evtchn_to_irq(evtchn_port_t evtchn)
+{
+       return bind_evtchn_to_irq_chip(evtchn, &xen_dynamic_chip);
+}
 EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
 
+int bind_evtchn_to_irq_lateeoi(evtchn_port_t evtchn)
+{
+       return bind_evtchn_to_irq_chip(evtchn, &xen_lateeoi_chip);
+}
+EXPORT_SYMBOL_GPL(bind_evtchn_to_irq_lateeoi);
+
 static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
 {
        struct evtchn_bind_ipi bind_ipi;
        return irq;
 }
 
-int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
-                                  unsigned int remote_port)
+static int bind_interdomain_evtchn_to_irq_chip(unsigned int remote_domain,
+                                              evtchn_port_t remote_port,
+                                              struct irq_chip *chip)
 {
        struct evtchn_bind_interdomain bind_interdomain;
        int err;
        err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
                                          &bind_interdomain);
 
-       return err ? : bind_evtchn_to_irq(bind_interdomain.local_port);
+       return err ? : bind_evtchn_to_irq_chip(bind_interdomain.local_port,
+                                              chip);
+}
+
+int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
+                                  evtchn_port_t remote_port)
+{
+       return bind_interdomain_evtchn_to_irq_chip(remote_domain, remote_port,
+                                                  &xen_dynamic_chip);
 }
 EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irq);
 
+int bind_interdomain_evtchn_to_irq_lateeoi(unsigned int remote_domain,
+                                          evtchn_port_t remote_port)
+{
+       return bind_interdomain_evtchn_to_irq_chip(remote_domain, remote_port,
+                                                  &xen_lateeoi_chip);
+}
+EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irq_lateeoi);
+
 static int find_virq(unsigned int virq, unsigned int cpu)
 {
        struct evtchn_status status;
        mutex_unlock(&irq_mapping_update_lock);
 }
 
-int bind_evtchn_to_irqhandler(unsigned int evtchn,
-                             irq_handler_t handler,
-                             unsigned long irqflags,
-                             const char *devname, void *dev_id)
+static int bind_evtchn_to_irqhandler_chip(evtchn_port_t evtchn,
+                                         irq_handler_t handler,
+                                         unsigned long irqflags,
+                                         const char *devname, void *dev_id,
+                                         struct irq_chip *chip)
 {
        int irq, retval;
 
-       irq = bind_evtchn_to_irq(evtchn);
+       irq = bind_evtchn_to_irq_chip(evtchn, chip);
        if (irq < 0)
                return irq;
        retval = request_irq(irq, handler, irqflags, devname, dev_id);
 
        return irq;
 }
+
+int bind_evtchn_to_irqhandler(evtchn_port_t evtchn,
+                             irq_handler_t handler,
+                             unsigned long irqflags,
+                             const char *devname, void *dev_id)
+{
+       return bind_evtchn_to_irqhandler_chip(evtchn, handler, irqflags,
+                                             devname, dev_id,
+                                             &xen_dynamic_chip);
+}
 EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler);
 
-int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
-                                         unsigned int remote_port,
-                                         irq_handler_t handler,
-                                         unsigned long irqflags,
-                                         const char *devname,
-                                         void *dev_id)
+int bind_evtchn_to_irqhandler_lateeoi(evtchn_port_t evtchn,
+                                     irq_handler_t handler,
+                                     unsigned long irqflags,
+                                     const char *devname, void *dev_id)
+{
+       return bind_evtchn_to_irqhandler_chip(evtchn, handler, irqflags,
+                                             devname, dev_id,
+                                             &xen_lateeoi_chip);
+}
+EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler_lateeoi);
+
+static int bind_interdomain_evtchn_to_irqhandler_chip(
+               unsigned int remote_domain, evtchn_port_t remote_port,
+               irq_handler_t handler, unsigned long irqflags,
+               const char *devname, void *dev_id, struct irq_chip *chip)
 {
        int irq, retval;
 
-       irq = bind_interdomain_evtchn_to_irq(remote_domain, remote_port);
+       irq = bind_interdomain_evtchn_to_irq_chip(remote_domain, remote_port,
+                                                 chip);
        if (irq < 0)
                return irq;
 
 
        return irq;
 }
+
+int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
+                                         evtchn_port_t remote_port,
+                                         irq_handler_t handler,
+                                         unsigned long irqflags,
+                                         const char *devname,
+                                         void *dev_id)
+{
+       return bind_interdomain_evtchn_to_irqhandler_chip(remote_domain,
+                               remote_port, handler, irqflags, devname,
+                               dev_id, &xen_dynamic_chip);
+}
 EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irqhandler);
 
+int bind_interdomain_evtchn_to_irqhandler_lateeoi(unsigned int remote_domain,
+                                                 evtchn_port_t remote_port,
+                                                 irq_handler_t handler,
+                                                 unsigned long irqflags,
+                                                 const char *devname,
+                                                 void *dev_id)
+{
+       return bind_interdomain_evtchn_to_irqhandler_chip(remote_domain,
+                               remote_port, handler, irqflags, devname,
+                               dev_id, &xen_lateeoi_chip);
+}
+EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irqhandler_lateeoi);
+
 int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
                            irq_handler_t handler,
                            unsigned long irqflags, const char *devname, void *dev_id)
        .irq_retrigger          = retrigger_dynirq,
 };
 
+static struct irq_chip xen_lateeoi_chip __read_mostly = {
+       /* The chip name needs to contain "xen-dyn" for irqbalance to work. */
+       .name                   = "xen-dyn-lateeoi",
+
+       .irq_disable            = disable_dynirq,
+       .irq_mask               = disable_dynirq,
+       .irq_unmask             = enable_dynirq,
+
+       .irq_ack                = mask_ack_dynirq,
+       .irq_mask_ack           = mask_ack_dynirq,
+
+       .irq_set_affinity       = set_affinity_irq,
+       .irq_retrigger          = retrigger_dynirq,
+};
+
 static struct irq_chip xen_pirq_chip __read_mostly = {
        .name                   = "xen-pirq",
 
 
 
 unsigned xen_evtchn_nr_channels(void);
 
-int bind_evtchn_to_irq(unsigned int evtchn);
-int bind_evtchn_to_irqhandler(unsigned int evtchn,
+int bind_evtchn_to_irq(evtchn_port_t evtchn);
+int bind_evtchn_to_irq_lateeoi(evtchn_port_t evtchn);
+int bind_evtchn_to_irqhandler(evtchn_port_t evtchn,
                              irq_handler_t handler,
                              unsigned long irqflags, const char *devname,
                              void *dev_id);
+int bind_evtchn_to_irqhandler_lateeoi(evtchn_port_t evtchn,
+                                     irq_handler_t handler,
+                                     unsigned long irqflags, const char *devname,
+                                     void *dev_id);
 int bind_virq_to_irq(unsigned int virq, unsigned int cpu, bool percpu);
 int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
                            irq_handler_t handler,
                           const char *devname,
                           void *dev_id);
 int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
-                                  unsigned int remote_port);
+                                  evtchn_port_t remote_port);
+int bind_interdomain_evtchn_to_irq_lateeoi(unsigned int remote_domain,
+                                          evtchn_port_t remote_port);
 int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
-                                         unsigned int remote_port,
+                                         evtchn_port_t remote_port,
                                          irq_handler_t handler,
                                          unsigned long irqflags,
                                          const char *devname,
                                          void *dev_id);
+int bind_interdomain_evtchn_to_irqhandler_lateeoi(unsigned int remote_domain,
+                                                 evtchn_port_t remote_port,
+                                                 irq_handler_t handler,
+                                                 unsigned long irqflags,
+                                                 const char *devname,
+                                                 void *dev_id);
 
 /*
  * Common unbind function for all event sources. Takes IRQ to unbind from.
  */
 void unbind_from_irqhandler(unsigned int irq, void *dev_id);
 
+/*
+ * Send late EOI for an IRQ bound to an event channel via one of the *_lateeoi
+ * functions above.
+ */
+void xen_irq_lateeoi(unsigned int irq, unsigned int eoi_flags);
+/* Signal an event was spurious, i.e. there was no action resulting from it. */
+#define XEN_EOI_FLAG_SPURIOUS  0x00000001
+
 #define XEN_IRQ_PRIORITY_MAX     EVTCHN_FIFO_PRIORITY_MAX
 #define XEN_IRQ_PRIORITY_DEFAULT EVTCHN_FIFO_PRIORITY_DEFAULT
 #define XEN_IRQ_PRIORITY_MIN     EVTCHN_FIFO_PRIORITY_MIN