Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / drivers / xen / events.c
index 7523719..0eb8a57 100644 (file)
@@ -432,7 +432,8 @@ static int __must_check xen_allocate_irq_dynamic(void)
 
        irq = irq_alloc_desc_from(first, -1);
 
-       xen_irq_init(irq);
+       if (irq >= 0)
+               xen_irq_init(irq);
 
        return irq;
 }
@@ -713,7 +714,7 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
        mutex_lock(&irq_mapping_update_lock);
 
        irq = xen_allocate_irq_dynamic();
-       if (irq == -1)
+       if (irq < 0)
                goto out;
 
        irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_edge_irq,
@@ -729,7 +730,7 @@ out:
 error_irq:
        mutex_unlock(&irq_mapping_update_lock);
        xen_free_irq(irq);
-       return -1;
+       return ret;
 }
 #endif
 
@@ -779,7 +780,7 @@ int xen_irq_from_pirq(unsigned pirq)
        mutex_lock(&irq_mapping_update_lock);
 
        list_for_each_entry(info, &xen_irq_list_head, list) {
-               if (info == NULL || info->type != IRQT_PIRQ)
+               if (info->type != IRQT_PIRQ)
                        continue;
                irq = info->irq;
                if (info->u.pirq.pirq == pirq)
@@ -872,11 +873,32 @@ static int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
        return err ? : bind_evtchn_to_irq(bind_interdomain.local_port);
 }
 
+static int find_virq(unsigned int virq, unsigned int cpu)
+{
+       struct evtchn_status status;
+       int port, rc = -ENOENT;
+
+       memset(&status, 0, sizeof(status));
+       for (port = 0; port <= NR_EVENT_CHANNELS; port++) {
+               status.dom = DOMID_SELF;
+               status.port = port;
+               rc = HYPERVISOR_event_channel_op(EVTCHNOP_status, &status);
+               if (rc < 0)
+                       continue;
+               if (status.status != EVTCHNSTAT_virq)
+                       continue;
+               if (status.u.virq == virq && status.vcpu == cpu) {
+                       rc = port;
+                       break;
+               }
+       }
+       return rc;
+}
 
 int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
 {
        struct evtchn_bind_virq bind_virq;
-       int evtchn, irq;
+       int evtchn, irq, ret;
 
        mutex_lock(&irq_mapping_update_lock);
 
@@ -892,10 +914,16 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
 
                bind_virq.virq = virq;
                bind_virq.vcpu = cpu;
-               if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
-                                               &bind_virq) != 0)
-                       BUG();
-               evtchn = bind_virq.port;
+               ret = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
+                                               &bind_virq);
+               if (ret == 0)
+                       evtchn = bind_virq.port;
+               else {
+                       if (ret == -EEXIST)
+                               ret = find_virq(virq, cpu);
+                       BUG_ON(ret < 0);
+                       evtchn = ret;
+               }
 
                xen_irq_info_virq_init(cpu, irq, evtchn, virq);
 
@@ -1021,7 +1049,7 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi,
        if (irq < 0)
                return irq;
 
-       irqflags |= IRQF_NO_SUSPEND | IRQF_FORCE_RESUME;
+       irqflags |= IRQF_NO_SUSPEND | IRQF_FORCE_RESUME | IRQF_EARLY_RESUME;
        retval = request_irq(irq, handler, irqflags, devname, dev_id);
        if (retval != 0) {
                unbind_from_irq(irq);
@@ -1670,6 +1698,7 @@ void __init xen_init_IRQ(void)
 
        evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq),
                                    GFP_KERNEL);
+       BUG_ON(!evtchn_to_irq);
        for (i = 0; i < NR_EVENT_CHANNELS; i++)
                evtchn_to_irq[i] = -1;