x86: add debug info for 32bit sparse_irq
[sfrench/cifs-2.6.git] / arch / x86 / kernel / io_apic_64.c
index 60d60061659cf06a05b6f544df28da42a33d16de..30d2e38113135a3a027093bab1260fa8f3d78a18 100644 (file)
@@ -111,44 +111,44 @@ static void init_one_irq_cfg(struct irq_cfg *cfg)
        memcpy(cfg, &irq_cfg_init, sizeof(struct irq_cfg));
 }
 
+static struct irq_cfg *irq_cfgx;
+static struct irq_cfg *irq_cfgx_free;
 static void __init init_work(void *data)
 {
        struct dyn_array *da = data;
        struct irq_cfg *cfg;
+       int legacy_count;
        int i;
 
        cfg = *da->name;
 
        memcpy(cfg, irq_cfg_legacy, sizeof(irq_cfg_legacy));
 
-       i = sizeof(irq_cfg_legacy)/sizeof(irq_cfg_legacy[0]);
-       for (; i < *da->nr; i++)
+       legacy_count = sizeof(irq_cfg_legacy)/sizeof(irq_cfg_legacy[0]);
+       for (i = legacy_count; i < *da->nr; i++)
                init_one_irq_cfg(&cfg[i]);
 
        for (i = 1; i < *da->nr; i++)
                cfg[i-1].next = &cfg[i];
+
+       irq_cfgx_free = &irq_cfgx[legacy_count];
+       irq_cfgx[legacy_count - 1].next = NULL;
 }
 
 #define for_each_irq_cfg(cfg)          \
-       for (cfg = irq_cfgx; cfg && cfg->irq != -1U; cfg = cfg->next)
+       for (cfg = irq_cfgx; cfg; cfg = cfg->next)
 
-static struct irq_cfg *irq_cfgx;
 DEFINE_DYN_ARRAY(irq_cfgx, sizeof(struct irq_cfg), nr_irq_cfg, PAGE_SIZE, init_work);
 
 static struct irq_cfg *irq_cfg(unsigned int irq)
 {
        struct irq_cfg *cfg;
 
-       BUG_ON(irq == -1U);
-
-       cfg = &irq_cfgx[0];
+       cfg = irq_cfgx;
        while (cfg) {
                if (cfg->irq == irq)
                        return cfg;
 
-               if (cfg->irq == -1U)
-                       return NULL;
-
                cfg = cfg->next;
        }
 
@@ -161,44 +161,70 @@ static struct irq_cfg *irq_cfg_alloc(unsigned int irq)
        int i;
        int count = 0;
 
-       BUG_ON(irq == -1U);
-
-       cfg_pri = cfg = &irq_cfgx[0];
+       cfg_pri = cfg = irq_cfgx;
        while (cfg) {
                if (cfg->irq == irq)
                        return cfg;
 
-               if (cfg->irq == -1U) {
-                       cfg->irq = irq;
-                       return cfg;
-               }
                cfg_pri = cfg;
                cfg = cfg->next;
                count++;
        }
 
-       /*
-        *  we run out of pre-allocate ones, allocate more
-        */
-       printk(KERN_DEBUG "try to get more irq_cfg %d\n", nr_irq_cfg);
+       if (!irq_cfgx_free) {
+               unsigned long phys;
+               unsigned long total_bytes;
+               /*
+                *  we run out of pre-allocate ones, allocate more
+                */
+               printk(KERN_DEBUG "try to get more irq_cfg %d\n", nr_irq_cfg);
 
-       if (after_bootmem)
-               cfg = kzalloc(sizeof(struct irq_cfg)*nr_irq_cfg, GFP_ATOMIC);
-       else
-               cfg = __alloc_bootmem_nopanic(sizeof(struct irq_cfg)*nr_irq_cfg, PAGE_SIZE, 0);
+               total_bytes = sizeof(struct irq_cfg) * nr_irq_cfg;
+               if (after_bootmem)
+                       cfg = kzalloc(total_bytes, GFP_ATOMIC);
+               else
+                       cfg = __alloc_bootmem_nopanic(total_bytes, PAGE_SIZE, 0);
 
-       if (!cfg)
-               panic("please boot with nr_irq_cfg= %d\n", count * 2);
+               if (!cfg)
+                       panic("please boot with nr_irq_cfg= %d\n", count * 2);
 
-       for (i = 0; i < nr_irq_cfg; i++)
-               init_one_irq_cfg(&cfg[i]);
+               phys = __pa(cfg);
+               printk(KERN_DEBUG "irq_irq ==> [%#lx - %#lx]\n", phys, phys + total_bytes);
 
-       for (i = 1; i < nr_irq_cfg; i++)
-               cfg[i-1].next = &cfg[i];
+               for (i = 0; i < nr_irq_cfg; i++)
+                       init_one_irq_cfg(&cfg[i]);
 
-       cfg->irq = irq;
-       cfg_pri->next = cfg;
+               for (i = 1; i < nr_irq_cfg; i++)
+                       cfg[i-1].next = &cfg[i];
+
+               irq_cfgx_free = cfg;
+       }
 
+       cfg = irq_cfgx_free;
+       irq_cfgx_free = irq_cfgx_free->next;
+       cfg->next = NULL;
+       if (cfg_pri)
+               cfg_pri->next = cfg;
+       else
+               irq_cfgx = cfg;
+       cfg->irq = irq;
+       printk(KERN_DEBUG "found new irq_cfg for irq %d\n", cfg->irq);
+#ifdef CONFIG_HAVE_SPARSE_IRQ_DEBUG
+       {
+               /* dump the results */
+               struct irq_cfg *cfg;
+               unsigned long phys;
+               unsigned long bytes = sizeof(struct irq_cfg);
+
+               printk(KERN_DEBUG "=========================== %d\n", irq);
+               printk(KERN_DEBUG "irq_cfg dump after get that for %d\n", irq);
+               for_each_irq_cfg(cfg) {
+                       phys = __pa(cfg);
+                       printk(KERN_DEBUG "irq_cfg %d ==> [%#lx - %#lx]\n", cfg->irq, phys, phys + bytes);
+               }
+               printk(KERN_DEBUG "===========================\n");
+       }
+#endif
        return cfg;
 }
 
@@ -400,7 +426,6 @@ static inline void io_apic_sync(unsigned int apic)
        struct irq_cfg *cfg;                                            \
        struct irq_pin_list *entry;                                     \
                                                                        \
-       BUG_ON(irq >= nr_irqs);                                         \
        cfg = irq_cfg(irq);                                             \
        entry = cfg->irq_2_pin;                                         \
        for (;;) {                                                      \
@@ -480,7 +505,6 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector)
        struct irq_cfg *cfg;
        struct irq_pin_list *entry;
 
-       BUG_ON(irq >= nr_irqs);
        cfg = irq_cfg(irq);
        entry = cfg->irq_2_pin;
        for (;;) {
@@ -549,7 +573,6 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
        struct irq_cfg *cfg;
        struct irq_pin_list *entry;
 
-       BUG_ON(irq >= nr_irqs);
        /* first time to refer irq_cfg, so with new */
        cfg = irq_cfg_alloc(irq);
        entry = cfg->irq_2_pin;
@@ -841,7 +864,6 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
                                best_guess = irq;
                }
        }
-       BUG_ON(best_guess >= nr_irqs);
        return best_guess;
 }
 
@@ -973,7 +995,6 @@ static int pin_2_irq(int idx, int apic, int pin)
                        irq += nr_ioapic_registers[i++];
                irq += pin;
        }
-       BUG_ON(irq >= nr_irqs);
        return irq;
 }
 
@@ -1008,7 +1029,6 @@ static int __assign_irq_vector(int irq, cpumask_t mask)
        int cpu;
        struct irq_cfg *cfg;
 
-       BUG_ON((unsigned)irq >= nr_irqs);
        cfg = irq_cfg(irq);
 
        /* Only try and allocate irqs on cpus that are present */
@@ -1082,7 +1102,6 @@ static void __clear_irq_vector(int irq)
        cpumask_t mask;
        int cpu, vector;
 
-       BUG_ON((unsigned)irq >= nr_irqs);
        cfg = irq_cfg(irq);
        BUG_ON(!cfg->vector);
 
@@ -1131,7 +1150,12 @@ static void ioapic_register_intr(int irq, unsigned long trigger)
 {
        struct irq_desc *desc;
 
-       desc = irq_to_desc(irq);
+       /* first time to use this irq_desc */
+       if (irq < 16)
+               desc = irq_to_desc(irq);
+       else
+               desc = irq_to_desc_alloc(irq);
+
        if (trigger)
                desc->status |= IRQ_LEVEL;
        else
@@ -1370,6 +1394,8 @@ __apicdebuginit(void) print_IO_APIC(void)
        printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mp_apicid);
        printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw);
        printk(KERN_DEBUG ".......    : physical APIC id: %02X\n", reg_00.bits.ID);
+       printk(KERN_DEBUG ".......    : Delivery Type: %X\n", reg_00.bits.delivery_type);
+       printk(KERN_DEBUG ".......    : LTS          : %X\n", reg_00.bits.LTS);
 
        printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)&reg_01);
        printk(KERN_DEBUG ".......     : max redirection entries: %04X\n", reg_01.bits.entries);
@@ -1924,10 +1950,11 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void)
                struct irq_desc *desc;
                struct irq_cfg *cfg;
                irq = __get_cpu_var(vector_irq)[vector];
-               if (irq >= nr_irqs)
-                       continue;
 
                desc = irq_to_desc(irq);
+               if (!desc)
+                       continue;
+
                cfg = irq_cfg(irq);
                spin_lock(&desc->lock);
                if (!cfg->move_cleanup_count)
@@ -2495,17 +2522,21 @@ device_initcall(ioapic_init_sysfs);
 /*
  * Dynamic irq allocate and deallocation
  */
-int create_irq(void)
+unsigned int create_irq_nr(unsigned int irq_want)
 {
        /* Allocate an unused irq */
-       int irq;
-       int new;
+       unsigned int irq;
+       unsigned int new;
        unsigned long flags;
        struct irq_cfg *cfg_new;
 
-       irq = -ENOSPC;
+#ifndef CONFIG_HAVE_SPARSE_IRQ
+       irq_want = nr_irqs - 1;
+#endif
+
+       irq = 0;
        spin_lock_irqsave(&vector_lock, flags);
-       for (new = (nr_irqs - 1); new >= 0; new--) {
+       for (new = irq_want; new > 0; new--) {
                if (platform_legacy_irq(new))
                        continue;
                cfg_new = irq_cfg(new);
@@ -2520,12 +2551,24 @@ int create_irq(void)
        }
        spin_unlock_irqrestore(&vector_lock, flags);
 
-       if (irq >= 0) {
+       if (irq > 0) {
                dynamic_irq_init(irq);
        }
        return irq;
 }
 
+int create_irq(void)
+{
+       int irq;
+
+       irq = create_irq_nr(nr_irqs - 1);
+
+       if (irq == 0)
+               irq = -1;
+
+       return irq;
+}
+
 void destroy_irq(unsigned int irq)
 {
        unsigned long flags;
@@ -2778,13 +2821,29 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq)
        return 0;
 }
 
+static unsigned int build_irq_for_pci_dev(struct pci_dev *dev)
+{
+       unsigned int irq;
+
+       irq = dev->bus->number;
+       irq <<= 8;
+       irq |= dev->devfn;
+       irq <<= 12;
+
+       return irq;
+}
+
 int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
 {
-       int irq, ret;
+       unsigned int irq;
+       int ret;
+       unsigned int irq_want;
+
+       irq_want = build_irq_for_pci_dev(dev) + 0x100;
 
-       irq = create_irq();
-       if (irq < 0)
-               return irq;
+       irq = create_irq_nr(irq_want);
+       if (irq == 0)
+               return -1;
 
 #ifdef CONFIG_INTR_REMAP
        if (!intr_remapping_enabled)
@@ -2811,18 +2870,22 @@ error:
 
 int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 {
-       int irq, ret, sub_handle;
+       unsigned int irq;
+       int ret, sub_handle;
        struct msi_desc *desc;
+       unsigned int irq_want;
+
 #ifdef CONFIG_INTR_REMAP
        struct intel_iommu *iommu = 0;
        int index = 0;
 #endif
 
+       irq_want = build_irq_for_pci_dev(dev) + 0x100;
        sub_handle = 0;
        list_for_each_entry(desc, &dev->msi_list, list) {
-               irq = create_irq();
-               if (irq < 0)
-                       return irq;
+               irq = create_irq_nr(irq_want--);
+               if (irq == 0)
+                       return -1;
 #ifdef CONFIG_INTR_REMAP
                if (!intr_remapping_enabled)
                        goto no_ir;