VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / arch / ia64 / kernel / iosapic.c
index 9ef5f3e..f032ea1 100644 (file)
 #endif
 
 static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED;
-extern cpumask_t       __cacheline_aligned pending_irq_cpumask[NR_IRQS];
 
 /* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */
 
@@ -218,10 +217,8 @@ set_rte (unsigned int vector, unsigned int dest, int mask)
 
        spin_lock_irqsave(&iosapic_lock, flags);
        {
-               writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT);
-               writel(high32, addr + IOSAPIC_WINDOW);
-               writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
-               writel(low32, addr + IOSAPIC_WINDOW);
+               iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
+               iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
                iosapic_intr_info[vector].low32 = low32;
        }
        spin_unlock_irqrestore(&iosapic_lock, flags);
@@ -250,12 +247,9 @@ mask_irq (unsigned int irq)
 
        spin_lock_irqsave(&iosapic_lock, flags);
        {
-               writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
-
                /* set only the mask bit */
                low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
-
-               writel(low32, addr + IOSAPIC_WINDOW);
+               iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
        }
        spin_unlock_irqrestore(&iosapic_lock, flags);
 }
@@ -276,9 +270,8 @@ unmask_irq (unsigned int irq)
 
        spin_lock_irqsave(&iosapic_lock, flags);
        {
-               writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
                low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
-               writel(low32, addr + IOSAPIC_WINDOW);
+               iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
        }
        spin_unlock_irqrestore(&iosapic_lock, flags);
 }
@@ -326,30 +319,13 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask)
                        low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
 
                iosapic_intr_info[vec].low32 = low32;
-               writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT);
-               writel(high32, addr + IOSAPIC_WINDOW);
-               writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
-               writel(low32, addr + IOSAPIC_WINDOW);
+               iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
+               iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
        }
        spin_unlock_irqrestore(&iosapic_lock, flags);
 #endif
 }
 
-static inline void move_irq(int irq)
-{
-       /* note - we hold desc->lock */
-       cpumask_t tmp;
-       irq_desc_t *desc = irq_descp(irq);
-
-       if (!cpus_empty(pending_irq_cpumask[irq])) {
-               cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map);
-               if (unlikely(!cpus_empty(tmp))) {
-                       desc->handler->set_affinity(irq, pending_irq_cpumask[irq]);
-               }
-               cpus_clear(pending_irq_cpumask[irq]);
-       }
-}
-
 /*
  * Handlers for level-triggered interrupts.
  */
@@ -367,7 +343,7 @@ iosapic_end_level_irq (unsigned int irq)
        ia64_vector vec = irq_to_vector(irq);
 
        move_irq(irq);
-       writel(vec, iosapic_intr_info[vec].addr + IOSAPIC_EOI);
+       iosapic_eoi(iosapic_intr_info[vec].addr, vec);
 }
 
 #define iosapic_shutdown_level_irq     mask_irq
@@ -444,8 +420,7 @@ iosapic_version (char *addr)
         *      unsigned int reserved2 : 8;
         * }
         */
-       writel(IOSAPIC_VERSION, addr + IOSAPIC_REG_SELECT);
-       return readl(IOSAPIC_WINDOW + addr);
+       return iosapic_read(addr, IOSAPIC_VERSION);
 }
 
 /*
@@ -483,7 +458,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
 
        index = find_iosapic(gsi);
        if (index < 0) {
-               printk(KERN_WARNING "%s: No IOSAPIC for GSI 0x%x\n", __FUNCTION__, gsi);
+               printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi);
                return;
        }
 
@@ -512,6 +487,42 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
        }
 }
 
+static unsigned int
+get_target_cpu (void)
+{
+#ifdef CONFIG_SMP
+       static int cpu = -1;
+
+       /*
+        * If the platform supports redirection via XTP, let it
+        * distribute interrupts.
+        */
+       if (smp_int_redirect & SMP_IRQ_REDIRECTION)
+               return hard_smp_processor_id();
+
+       /*
+        * Some interrupts (ACPI SCI, for instance) are registered
+        * before the BSP is marked as online.
+        */
+       if (!cpu_online(smp_processor_id()))
+               return hard_smp_processor_id();
+
+       /*
+        * Otherwise, round-robin interrupt vectors across all the
+        * processors.  (It'd be nice if we could be smarter in the
+        * case of NUMA.)
+        */
+       do {
+               if (++cpu >= NR_CPUS)
+                       cpu = 0;
+       } while (!cpu_online(cpu));
+
+       return cpu_physical_id(cpu);
+#else
+       return hard_smp_processor_id();
+#endif
+}
+
 /*
  * ACPI can describe IOSAPIC interrupts via static tables and namespace
  * methods.  This provides an interface to register those interrupts and
@@ -522,21 +533,35 @@ iosapic_register_intr (unsigned int gsi,
                       unsigned long polarity, unsigned long trigger)
 {
        int vector;
-       unsigned int dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
+       unsigned int dest;
+       unsigned long flags;
 
-       vector = gsi_to_vector(gsi);
-       if (vector < 0)
-               vector = assign_irq_vector(AUTO_ASSIGN);
+       /*
+        * If this GSI has already been registered (i.e., it's a
+        * shared interrupt, or we lost a race to register it),
+        * don't touch the RTE.
+        */
+       spin_lock_irqsave(&iosapic_lock, flags);
+       {
+               vector = gsi_to_vector(gsi);
+               if (vector > 0) {
+                       spin_unlock_irqrestore(&iosapic_lock, flags);
+                       return vector;
+               }
 
-       register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
-                     polarity, trigger);
+               vector = assign_irq_vector(AUTO_ASSIGN);
+               dest = get_target_cpu();
+               register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
+                       polarity, trigger);
+       }
+       spin_unlock_irqrestore(&iosapic_lock, flags);
 
-       printk(KERN_INFO "GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
-              gsi, (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
-              (trigger == IOSAPIC_EDGE ? "edge" : "level"), dest, vector);
+       printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
+              gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
+              (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
+              cpu_logical_id(dest), dest, vector);
 
-       /* program the IOSAPIC routing table */
-       set_rte(vector, dest, 0);
+       set_rte(vector, dest, 1);
        return vector;
 }
 
@@ -549,8 +574,9 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
                                int iosapic_vector, u16 eid, u16 id,
                                unsigned long polarity, unsigned long trigger)
 {
+       static const char * const name[] = {"unknown", "PMI", "INIT", "CPEI"};
        unsigned char delivery;
-       int vector;
+       int vector, mask = 0;
        unsigned int dest = ((id << 8) | eid) & 0xffff;
 
        switch (int_type) {
@@ -570,21 +596,22 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
              case ACPI_INTERRUPT_CPEI:
                vector = IA64_CPE_VECTOR;
                delivery = IOSAPIC_LOWEST_PRIORITY;
+               mask = 1;
                break;
              default:
-               printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type\n");
+               printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type 0x%x\n", int_type);
                return -1;
        }
 
-       register_intr(gsi, vector, delivery, polarity,
-                     trigger);
+       register_intr(gsi, vector, delivery, polarity, trigger);
 
-       printk(KERN_INFO "PLATFORM int 0x%x: GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
-              int_type, gsi, (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
-              (trigger == IOSAPIC_EDGE ? "edge" : "level"), dest, vector);
+       printk(KERN_INFO "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
+              int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown",
+              int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
+              (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
+              cpu_logical_id(dest), dest, vector);
 
-       /* program the IOSAPIC routing table */
-       set_rte(vector, dest, 0);
+       set_rte(vector, dest, mask);
        return vector;
 }
 
@@ -599,18 +626,18 @@ iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
                          unsigned long trigger)
 {
        int vector;
-       unsigned int dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
+       unsigned int dest = hard_smp_processor_id();
 
        vector = isa_irq_to_vector(isa_irq);
 
        register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
 
-       DBG("ISA: IRQ %u -> GSI 0x%x (%s,%s) -> CPU 0x%04x vector %d\n",
-           isa_irq, gsi, polarity == IOSAPIC_POL_HIGH ? "high" : "low",
-           trigger == IOSAPIC_EDGE ? "edge" : "level", dest, vector);
+       DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n",
+           isa_irq, gsi, trigger == IOSAPIC_EDGE ? "edge" : "level",
+           polarity == IOSAPIC_POL_HIGH ? "high" : "low",
+           cpu_logical_id(dest), dest, vector);
 
-       /* program the IOSAPIC routing table */
-       set_rte(vector, dest, 0);
+       set_rte(vector, dest, 1);
 }
 
 void __init
@@ -665,104 +692,3 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
                        iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
        }
 }
-
-void
-iosapic_enable_intr (unsigned int vector)
-{
-       unsigned int dest;
-       irq_desc_t *desc;
-
-       /*
-        * In the case of a shared interrupt, do not re-route the vector, and
-        * especially do not mask a running interrupt (startup will not get
-        * called for a shared interrupt).
-        */
-       desc = irq_descp(vector);
-       if (desc->action)
-               return;
-
-#ifdef CONFIG_SMP
-       /*
-        * For platforms that do not support interrupt redirect via the XTP interface, we
-        * can round-robin the PCI device interrupts to the processors
-        */
-       if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) {
-               static int cpu_index = -1;
-
-               do
-                       if (++cpu_index >= NR_CPUS)
-                               cpu_index = 0;
-               while (!cpu_online(cpu_index));
-
-               dest = cpu_physical_id(cpu_index) & 0xffff;
-       } else {
-               /*
-                * Direct the interrupt vector to the current cpu, platform redirection
-                * will distribute them.
-                */
-               dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
-       }
-#else
-       /* direct the interrupt vector to the running cpu id */
-       dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
-#endif
-       set_rte(vector, dest, 1);
-
-       printk(KERN_INFO "IOSAPIC: vector %d -> CPU 0x%04x, enabled\n",
-              vector, dest);
-}
-
-#ifdef CONFIG_ACPI_PCI
-
-void __init
-iosapic_parse_prt (void)
-{
-       struct acpi_prt_entry *entry;
-       struct list_head *node;
-       unsigned int gsi;
-       int vector;
-       char pci_id[16];
-       struct hw_interrupt_type *irq_type = &irq_type_iosapic_level;
-       irq_desc_t *idesc;
-
-       list_for_each(node, &acpi_prt.entries) {
-               entry = list_entry(node, struct acpi_prt_entry, node);
-
-               /* We're only interested in static (non-link) entries.  */
-               if (entry->link.handle)
-                       continue;
-
-               gsi = entry->link.index;
-
-               vector = gsi_to_vector(gsi);
-               if (vector < 0) {
-                       if (find_iosapic(gsi) < 0)
-                               continue;
-
-                       /* allocate a vector for this interrupt line */
-                       if (pcat_compat && (gsi < 16))
-                               vector = isa_irq_to_vector(gsi);
-                       else
-                               /* new GSI; allocate a vector for it */
-                               vector = assign_irq_vector(AUTO_ASSIGN);
-
-                       register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
-                                     IOSAPIC_LEVEL);
-               }
-               entry->irq = vector;
-               snprintf(pci_id, sizeof(pci_id), "%02x:%02x:%02x[%c]",
-                        entry->id.segment, entry->id.bus, entry->id.device, 'A' + entry->pin);
-
-               /*
-                * If vector was previously initialized to a different
-                * handler, re-initialize.
-                */
-               idesc = irq_descp(vector);
-               if (idesc->handler != irq_type)
-                       register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
-                                     IOSAPIC_LEVEL);
-
-       }
-}
-
-#endif /* CONFIG_ACPI */