#ifdef CONFIG_X86_64
 
-static inline void acpi_madt_oem_check(char *oem_id, char *oem_table_id)
-{
-}
 extern void __init clustered_apic_check(void);
-static inline int ioapic_setup_disabled(void)
-{
-       return 0;
-}
 
+extern int gsi_irq_sharing(int gsi);
 #include <asm/proto.h>
 
+static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) { return 0; }
+
+
 #else                          /* X86 */
 
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <mach_mpparse.h>
 #endif                         /* CONFIG_X86_LOCAL_APIC */
 
+static inline int gsi_irq_sharing(int gsi) { return gsi; }
+
 #endif                         /* X86 */
 
 #define BAD_MADT_ENTRY(entry, end) (                                       \
                *irq = IO_APIC_VECTOR(gsi);
        else
 #endif
-               *irq = gsi;
+               *irq = gsi_irq_sharing(gsi);
        return 0;
 }
 
 
  * Rough estimation of how many shared IRQs there are, can
  * be changed anytime.
  */
-#define MAX_PLUS_SHARED_IRQS NR_IRQS
+#define MAX_PLUS_SHARED_IRQS NR_IRQ_VECTORS
 #define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
 
 /*
        int pin;                                                        \
        struct irq_pin_list *entry = irq_2_pin + irq;                   \
                                                                        \
+       BUG_ON(irq >= NR_IRQS);                                         \
        for (;;) {                                                      \
                unsigned int reg;                                       \
                pin = entry->pin;                                       \
 }
 #endif
 
+static u8 gsi_2_irq[NR_IRQ_VECTORS] = { [0 ... NR_IRQ_VECTORS-1] = 0xFF };
+
 /*
  * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
  * shared ISA-space IRQs, so we have to support them. We are super
        static int first_free_entry = NR_IRQS;
        struct irq_pin_list *entry = irq_2_pin + irq;
 
+       BUG_ON(irq >= NR_IRQS);
        while (entry->next)
                entry = irq_2_pin + entry->next;
 
                entry->next = first_free_entry;
                entry = irq_2_pin + entry->next;
                if (++first_free_entry >= PIN_MAP_SIZE)
-                       panic("io_apic.c: whoops");
+                       panic("io_apic.c: ran out of irq_2_pin entries!");
        }
        entry->apic = apic;
        entry->pin = pin;
                                best_guess = irq;
                }
        }
+       BUG_ON(best_guess >= NR_IRQS);
        return best_guess;
 }
 
        return MPBIOS_trigger(idx);
 }
 
+static int next_irq = 16;
+
+/*
+ * gsi_irq_sharing -- Name overload!  "irq" can be either a legacy IRQ
+ * in the range 0-15, a linux IRQ in the range 0-223, or a GSI number
+ * from ACPI, which can reach 800 in large boxen.
+ *
+ * Compact the sparse GSI space into a sequential IRQ series and reuse
+ * vectors if possible.
+ */
+int gsi_irq_sharing(int gsi)
+{
+       int i, tries, vector;
+
+       BUG_ON(gsi >= NR_IRQ_VECTORS);
+
+       if (platform_legacy_irq(gsi))
+               return gsi;
+
+       if (gsi_2_irq[gsi] != 0xFF)
+               return (int)gsi_2_irq[gsi];
+
+       tries = NR_IRQS;
+  try_again:
+       vector = assign_irq_vector(gsi);
+
+       /*
+        * Sharing vectors means sharing IRQs, so scan irq_vectors for previous
+        * use of vector and if found, return that IRQ.  However, we never want
+        * to share legacy IRQs, which usually have a different trigger mode
+        * than PCI.
+        */
+       for (i = 0; i < NR_IRQS; i++)
+               if (IO_APIC_VECTOR(i) == vector)
+                       break;
+       if (platform_legacy_irq(i)) {
+               if (--tries >= 0) {
+                       IO_APIC_VECTOR(i) = 0;
+                       goto try_again;
+               }
+               panic("gsi_irq_sharing: didn't find an IRQ using vector 0x%02X for GSI %d", vector, gsi);
+       }
+       if (i < NR_IRQS) {
+               gsi_2_irq[gsi] = i;
+               printk(KERN_INFO "GSI %d sharing vector 0x%02X and IRQ %d\n",
+                               gsi, vector, i);
+               return i;
+       }
+
+       i = next_irq++;
+       BUG_ON(i >= NR_IRQS);
+       gsi_2_irq[gsi] = i;
+       IO_APIC_VECTOR(i) = vector;
+       printk(KERN_INFO "GSI %d assigned vector 0x%02X and IRQ %d\n",
+                       gsi, vector, i);
+       return i;
+}
+
 static int pin_2_irq(int idx, int apic, int pin)
 {
        int irq, i;
                        while (i < apic)
                                irq += nr_ioapic_registers[i++];
                        irq += pin;
+                       irq = gsi_irq_sharing(irq);
                        break;
                }
                default:
                        break;
                }
        }
+       BUG_ON(irq >= NR_IRQS);
 
        /*
         * PCI IRQ command line redirection. Yes, limits are hardcoded.
                        }
                }
        }
+       BUG_ON(irq >= NR_IRQS);
        return irq;
 }
 
 {
        static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
 
-       BUG_ON(irq >= NR_IRQ_VECTORS);
-       if (IO_APIC_VECTOR(irq) > 0)
+       BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
+       if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0)
                return IO_APIC_VECTOR(irq);
 next:
        current_vector += 8;
                goto next;
 
        if (current_vector >= FIRST_SYSTEM_VECTOR) {
-               offset++;
-               if (!(offset%8))
-                       return -ENOSPC;
+               /* If we run out of vectors on large boxen, must share them. */
+               offset = (offset + 1) % 8;
                current_vector = FIRST_DEVICE_VECTOR + offset;
        }
 
        entry.polarity = active_high_low;
        entry.mask = 1;                                  /* Disabled (masked) */
 
+       irq = gsi_irq_sharing(irq);
        /*
         * IRQs < 16 are already in the irq_2_pin[] map
         */
 
 
 static inline void set_intr_gate(int nr, void *func) 
 { 
+       BUG_ON((unsigned)nr > 0xFF);
        _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, 0); 
 } 
 
 static inline void set_intr_gate_ist(int nr, void *func, unsigned ist) 
 { 
+       BUG_ON((unsigned)nr > 0xFF);
        _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, ist); 
 } 
 
 static inline void set_system_gate(int nr, void *func) 
 { 
+       BUG_ON((unsigned)nr > 0xFF);
        _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, 0); 
 }