#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. */
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);
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);
}
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);
}
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.
*/
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
* unsigned int reserved2 : 8;
* }
*/
- writel(IOSAPIC_VERSION, addr + IOSAPIC_REG_SELECT);
- return readl(IOSAPIC_WINDOW + addr);
+ return iosapic_read(addr, IOSAPIC_VERSION);
}
/*
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;
}
}
}
+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
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;
}
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) {
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;
}
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
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 */