diff --git a/[refs] b/[refs] index afe7733154c3..c235434e7632 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: f611f2da99420abc973c32cdbddbf5c365d0a20c +refs/heads/master: dc5f219e88294b93009eef946251251ffffb6d60 diff --git a/trunk/arch/x86/pci/xen.c b/trunk/arch/x86/pci/xen.c index 2a12f3dbdd02..25cd4a07d09f 100644 --- a/trunk/arch/x86/pci/xen.c +++ b/trunk/arch/x86/pci/xen.c @@ -226,27 +226,21 @@ static int xen_pcifront_enable_irq(struct pci_dev *dev) { int rc; int share = 1; - u8 gsi; - rc = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &gsi); - if (rc < 0) { - dev_warn(&dev->dev, "Xen PCI: failed to read interrupt line: %d\n", - rc); - return rc; - } + dev_info(&dev->dev, "Xen PCI enabling IRQ: %d\n", dev->irq); - if (gsi < NR_IRQS_LEGACY) + if (dev->irq < 0) + return -EINVAL; + + if (dev->irq < NR_IRQS_LEGACY) share = 0; - rc = xen_allocate_pirq(gsi, share, "pcifront"); + rc = xen_allocate_pirq(dev->irq, share, "pcifront"); if (rc < 0) { - dev_warn(&dev->dev, "Xen PCI: failed to register GSI%d: %d\n", - gsi, rc); + dev_warn(&dev->dev, "Xen PCI IRQ: %d, failed to register:%d\n", + dev->irq, rc); return rc; } - - dev->irq = rc; - dev_info(&dev->dev, "Xen PCI mapped GSI%d to IRQ%d\n", gsi, dev->irq); return 0; } diff --git a/trunk/arch/x86/xen/time.c b/trunk/arch/x86/xen/time.c index 2e2d370a47b1..067759e3d6a5 100644 --- a/trunk/arch/x86/xen/time.c +++ b/trunk/arch/x86/xen/time.c @@ -397,9 +397,7 @@ void xen_setup_timer(int cpu) name = ""; irq = bind_virq_to_irqhandler(VIRQ_TIMER, cpu, xen_timer_interrupt, - IRQF_DISABLED|IRQF_PERCPU| - IRQF_NOBALANCING|IRQF_TIMER| - IRQF_FORCE_RESUME, + IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING|IRQF_TIMER, name, NULL); evt = &per_cpu(xen_clock_events, cpu); diff --git a/trunk/drivers/xen/events.c b/trunk/drivers/xen/events.c index 5aa422a3c3cd..74681478100a 100644 --- a/trunk/drivers/xen/events.c +++ b/trunk/drivers/xen/events.c @@ -277,7 +277,7 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) BUG_ON(irq == -1); #ifdef CONFIG_SMP - cpumask_copy(irq_to_desc(irq)->irq_data.affinity, cpumask_of(cpu)); + cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu)); #endif clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq))); @@ -294,7 +294,7 @@ static void init_evtchn_cpu_bindings(void) /* By default all event channels notify CPU#0. */ for_each_irq_desc(i, desc) { - cpumask_copy(desc->irq_data.affinity, cpumask_of(0)); + cpumask_copy(desc->affinity, cpumask_of(0)); } #endif @@ -376,69 +376,81 @@ static void unmask_evtchn(int port) put_cpu(); } -static int xen_allocate_irq_dynamic(void) +static int get_nr_hw_irqs(void) { - int first = 0; - int irq; + int ret = 1; #ifdef CONFIG_X86_IO_APIC - /* - * For an HVM guest or domain 0 which see "real" (emulated or - * actual repectively) GSIs we allocate dynamic IRQs - * e.g. those corresponding to event channels or MSIs - * etc. from the range above those "real" GSIs to avoid - * collisions. - */ - if (xen_initial_domain() || xen_hvm_domain()) - first = get_nr_irqs_gsi(); + ret = get_nr_irqs_gsi(); #endif -retry: - irq = irq_alloc_desc_from(first, -1); + return ret; +} - if (irq == -ENOMEM && first > NR_IRQS_LEGACY) { - printk(KERN_ERR "Out of dynamic IRQ space and eating into GSI space. You should increase nr_irqs\n"); - first = max(NR_IRQS_LEGACY, first - NR_IRQS_LEGACY); - goto retry; - } +static int find_unbound_pirq(int type) +{ + int rc, i; + struct physdev_get_free_pirq op_get_free_pirq; + op_get_free_pirq.type = type; - if (irq < 0) - panic("No available IRQ to bind to: increase nr_irqs!\n"); + rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq); + if (!rc) + return op_get_free_pirq.pirq; - return irq; + for (i = 0; i < nr_irqs; i++) { + if (pirq_to_irq[i] < 0) + return i; + } + return -1; } -static int xen_allocate_irq_gsi(unsigned gsi) +static int find_unbound_irq(void) { - int irq; + struct irq_data *data; + int irq, res; + int bottom = get_nr_hw_irqs(); + int top = nr_irqs-1; - /* - * A PV guest has no concept of a GSI (since it has no ACPI - * nor access to/knowledge of the physical APICs). Therefore - * all IRQs are dynamically allocated from the entire IRQ - * space. + if (bottom == nr_irqs) + goto no_irqs; + + /* This loop starts from the top of IRQ space and goes down. + * We need this b/c if we have a PCI device in a Xen PV guest + * we do not have an IO-APIC (though the backend might have them) + * mapped in. To not have a collision of physical IRQs with the Xen + * event channels start at the top of the IRQ space for virtual IRQs. */ - if (xen_pv_domain() && !xen_initial_domain()) - return xen_allocate_irq_dynamic(); + for (irq = top; irq > bottom; irq--) { + data = irq_get_irq_data(irq); + /* only 15->0 have init'd desc; handle irq > 16 */ + if (!data) + break; + if (data->chip == &no_irq_chip) + break; + if (data->chip != &xen_dynamic_chip) + continue; + if (irq_info[irq].type == IRQT_UNBOUND) + return irq; + } - /* Legacy IRQ descriptors are already allocated by the arch. */ - if (gsi < NR_IRQS_LEGACY) - return gsi; + if (irq == bottom) + goto no_irqs; - irq = irq_alloc_desc_at(gsi, -1); - if (irq < 0) - panic("Unable to allocate to IRQ%d (%d)\n", gsi, irq); + res = irq_alloc_desc_at(irq, -1); + + if (WARN_ON(res != irq)) + return -1; return irq; + +no_irqs: + panic("No available IRQ to bind to: increase nr_irqs!\n"); } -static void xen_free_irq(unsigned irq) +static bool identity_mapped_irq(unsigned irq) { - /* Legacy IRQ descriptors are managed by the arch. */ - if (irq < NR_IRQS_LEGACY) - return; - - irq_free_desc(irq); + /* identity map all the hardware irqs */ + return irq < get_nr_hw_irqs(); } static void pirq_unmask_notify(int irq) @@ -474,7 +486,7 @@ static bool probing_irq(int irq) return desc && desc->action == NULL; } -static unsigned int __startup_pirq(unsigned int irq) +static unsigned int startup_pirq(unsigned int irq) { struct evtchn_bind_pirq bind_pirq; struct irq_info *info = info_for_irq(irq); @@ -512,15 +524,9 @@ static unsigned int __startup_pirq(unsigned int irq) return 0; } -static unsigned int startup_pirq(struct irq_data *data) -{ - return __startup_pirq(data->irq); -} - -static void shutdown_pirq(struct irq_data *data) +static void shutdown_pirq(unsigned int irq) { struct evtchn_close close; - unsigned int irq = data->irq; struct irq_info *info = info_for_irq(irq); int evtchn = evtchn_from_irq(irq); @@ -540,20 +546,20 @@ static void shutdown_pirq(struct irq_data *data) info->evtchn = 0; } -static void enable_pirq(struct irq_data *data) +static void enable_pirq(unsigned int irq) { - startup_pirq(data); + startup_pirq(irq); } -static void disable_pirq(struct irq_data *data) +static void disable_pirq(unsigned int irq) { } -static void ack_pirq(struct irq_data *data) +static void ack_pirq(unsigned int irq) { - int evtchn = evtchn_from_irq(data->irq); + int evtchn = evtchn_from_irq(irq); - move_native_irq(data->irq); + move_native_irq(irq); if (VALID_EVTCHN(evtchn)) { mask_evtchn(evtchn); @@ -561,6 +567,23 @@ static void ack_pirq(struct irq_data *data) } } +static void end_pirq(unsigned int irq) +{ + int evtchn = evtchn_from_irq(irq); + struct irq_desc *desc = irq_to_desc(irq); + + if (WARN_ON(!desc)) + return; + + if ((desc->status & (IRQ_DISABLED|IRQ_PENDING)) == + (IRQ_DISABLED|IRQ_PENDING)) { + shutdown_pirq(irq); + } else if (VALID_EVTCHN(evtchn)) { + unmask_evtchn(evtchn); + pirq_unmask_notify(irq); + } +} + static int find_irq_by_gsi(unsigned gsi) { int irq; @@ -615,7 +638,14 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name) goto out; /* XXX need refcount? */ } - irq = xen_allocate_irq_gsi(gsi); + /* If we are a PV guest, we don't have GSIs (no ACPI passed). Therefore + * we are using the !xen_initial_domain() to drop in the function.*/ + if (identity_mapped_irq(gsi) || (!xen_initial_domain() && + xen_pv_domain())) { + irq = gsi; + irq_alloc_desc_at(irq, -1); + } else + irq = find_unbound_irq(); set_irq_chip_and_handler_name(irq, &xen_pirq_chip, handle_level_irq, name); @@ -628,7 +658,7 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name) * this in the priv domain. */ if (xen_initial_domain() && HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op)) { - xen_free_irq(irq); + irq_free_desc(irq); irq = -ENOSPC; goto out; } @@ -647,29 +677,12 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name) #include #include "../pci/msi.h" -static int find_unbound_pirq(int type) -{ - int rc, i; - struct physdev_get_free_pirq op_get_free_pirq; - op_get_free_pirq.type = type; - - rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq); - if (!rc) - return op_get_free_pirq.pirq; - - for (i = 0; i < nr_irqs; i++) { - if (pirq_to_irq[i] < 0) - return i; - } - return -1; -} - void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc) { spin_lock(&irq_mapping_update_lock); if (alloc & XEN_ALLOC_IRQ) { - *irq = xen_allocate_irq_dynamic(); + *irq = find_unbound_irq(); if (*irq == -1) goto out; } @@ -719,7 +732,7 @@ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type) spin_lock(&irq_mapping_update_lock); - irq = xen_allocate_irq_dynamic(); + irq = find_unbound_irq(); if (irq == -1) goto out; @@ -728,7 +741,7 @@ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type) if (rc) { printk(KERN_WARNING "xen map irq failed %d\n", rc); - xen_free_irq(irq); + irq_free_desc(irq); irq = -1; goto out; @@ -770,7 +783,7 @@ int xen_destroy_irq(int irq) } irq_info[irq] = mk_unbound_info(); - xen_free_irq(irq); + irq_free_desc(irq); out: spin_unlock(&irq_mapping_update_lock); @@ -801,7 +814,7 @@ int bind_evtchn_to_irq(unsigned int evtchn) irq = evtchn_to_irq[evtchn]; if (irq == -1) { - irq = xen_allocate_irq_dynamic(); + irq = find_unbound_irq(); set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, handle_fasteoi_irq, "event"); @@ -826,7 +839,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) irq = per_cpu(ipi_to_irq, cpu)[ipi]; if (irq == -1) { - irq = xen_allocate_irq_dynamic(); + irq = find_unbound_irq(); if (irq < 0) goto out; @@ -862,7 +875,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu) irq = per_cpu(virq_to_irq, cpu)[virq]; if (irq == -1) { - irq = xen_allocate_irq_dynamic(); + irq = find_unbound_irq(); set_irq_chip_and_handler_name(irq, &xen_percpu_chip, handle_percpu_irq, "virq"); @@ -921,7 +934,7 @@ static void unbind_from_irq(unsigned int irq) if (irq_info[irq].type != IRQT_UNBOUND) { irq_info[irq] = mk_unbound_info(); - xen_free_irq(irq); + irq_free_desc(irq); } spin_unlock(&irq_mapping_update_lock); @@ -1221,12 +1234,11 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu) return 0; } -static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest, - bool force) +static int set_affinity_irq(unsigned irq, const struct cpumask *dest) { unsigned tcpu = cpumask_first(dest); - return rebind_irq_to_cpu(data->irq, tcpu); + return rebind_irq_to_cpu(irq, tcpu); } int resend_irq_on_evtchn(unsigned int irq) @@ -1245,35 +1257,35 @@ int resend_irq_on_evtchn(unsigned int irq) return 1; } -static void enable_dynirq(struct irq_data *data) +static void enable_dynirq(unsigned int irq) { - int evtchn = evtchn_from_irq(data->irq); + int evtchn = evtchn_from_irq(irq); if (VALID_EVTCHN(evtchn)) unmask_evtchn(evtchn); } -static void disable_dynirq(struct irq_data *data) +static void disable_dynirq(unsigned int irq) { - int evtchn = evtchn_from_irq(data->irq); + int evtchn = evtchn_from_irq(irq); if (VALID_EVTCHN(evtchn)) mask_evtchn(evtchn); } -static void ack_dynirq(struct irq_data *data) +static void ack_dynirq(unsigned int irq) { - int evtchn = evtchn_from_irq(data->irq); + int evtchn = evtchn_from_irq(irq); - move_masked_irq(data->irq); + move_masked_irq(irq); if (VALID_EVTCHN(evtchn)) unmask_evtchn(evtchn); } -static int retrigger_dynirq(struct irq_data *data) +static int retrigger_dynirq(unsigned int irq) { - int evtchn = evtchn_from_irq(data->irq); + int evtchn = evtchn_from_irq(irq); struct shared_info *sh = HYPERVISOR_shared_info; int ret = 0; @@ -1322,7 +1334,7 @@ static void restore_cpu_pirqs(void) printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq); - __startup_pirq(irq); + startup_pirq(irq); } } @@ -1474,44 +1486,45 @@ void xen_irq_resume(void) } static struct irq_chip xen_dynamic_chip __read_mostly = { - .name = "xen-dyn", + .name = "xen-dyn", - .irq_disable = disable_dynirq, - .irq_mask = disable_dynirq, - .irq_unmask = enable_dynirq, + .disable = disable_dynirq, + .mask = disable_dynirq, + .unmask = enable_dynirq, - .irq_eoi = ack_dynirq, - .irq_set_affinity = set_affinity_irq, - .irq_retrigger = retrigger_dynirq, + .eoi = ack_dynirq, + .set_affinity = set_affinity_irq, + .retrigger = retrigger_dynirq, }; static struct irq_chip xen_pirq_chip __read_mostly = { - .name = "xen-pirq", + .name = "xen-pirq", - .irq_startup = startup_pirq, - .irq_shutdown = shutdown_pirq, + .startup = startup_pirq, + .shutdown = shutdown_pirq, - .irq_enable = enable_pirq, - .irq_unmask = enable_pirq, + .enable = enable_pirq, + .unmask = enable_pirq, - .irq_disable = disable_pirq, - .irq_mask = disable_pirq, + .disable = disable_pirq, + .mask = disable_pirq, - .irq_ack = ack_pirq, + .ack = ack_pirq, + .end = end_pirq, - .irq_set_affinity = set_affinity_irq, + .set_affinity = set_affinity_irq, - .irq_retrigger = retrigger_dynirq, + .retrigger = retrigger_dynirq, }; static struct irq_chip xen_percpu_chip __read_mostly = { - .name = "xen-percpu", + .name = "xen-percpu", - .irq_disable = disable_dynirq, - .irq_mask = disable_dynirq, - .irq_unmask = enable_dynirq, + .disable = disable_dynirq, + .mask = disable_dynirq, + .unmask = enable_dynirq, - .irq_ack = ack_dynirq, + .ack = ack_dynirq, }; int xen_set_callback_via(uint64_t via) diff --git a/trunk/include/linux/interrupt.h b/trunk/include/linux/interrupt.h index 55e0d4253e49..d746da19c6a2 100644 --- a/trunk/include/linux/interrupt.h +++ b/trunk/include/linux/interrupt.h @@ -55,7 +55,7 @@ * Used by threaded interrupts which need to keep the * irq line disabled until the threaded handler has been run. * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend - * + * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set */ #define IRQF_DISABLED 0x00000020 #define IRQF_SAMPLE_RANDOM 0x00000040 @@ -67,6 +67,7 @@ #define IRQF_IRQPOLL 0x00001000 #define IRQF_ONESHOT 0x00002000 #define IRQF_NO_SUSPEND 0x00004000 +#define IRQF_FORCE_RESUME 0x00008000 #define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND) diff --git a/trunk/kernel/irq/manage.c b/trunk/kernel/irq/manage.c index 0caa59f747dd..b4198ee8cfdf 100644 --- a/trunk/kernel/irq/manage.c +++ b/trunk/kernel/irq/manage.c @@ -282,8 +282,17 @@ EXPORT_SYMBOL(disable_irq); void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume) { - if (resume) + if (resume) { + if (!(desc->status & IRQ_SUSPENDED)) { + if (!desc->action) + return; + if (!(desc->action->flags & IRQF_FORCE_RESUME)) + return; + /* Pretend that it got disabled ! */ + desc->depth++; + } desc->status &= ~IRQ_SUSPENDED; + } switch (desc->depth) { case 0: diff --git a/trunk/kernel/irq/pm.c b/trunk/kernel/irq/pm.c index 0d4005d85b03..d6bfb89cce91 100644 --- a/trunk/kernel/irq/pm.c +++ b/trunk/kernel/irq/pm.c @@ -53,9 +53,6 @@ void resume_device_irqs(void) for_each_irq_desc(irq, desc) { unsigned long flags; - if (!(desc->status & IRQ_SUSPENDED)) - continue; - raw_spin_lock_irqsave(&desc->lock, flags); __enable_irq(desc, irq, true); raw_spin_unlock_irqrestore(&desc->lock, flags);