|
@@ -129,12 +129,9 @@ struct irq_pin_list {
|
|
|
struct irq_pin_list *next;
|
|
|
};
|
|
|
|
|
|
-static struct irq_pin_list *get_one_free_irq_2_pin(int cpu)
|
|
|
+static struct irq_pin_list *get_one_free_irq_2_pin(int node)
|
|
|
{
|
|
|
struct irq_pin_list *pin;
|
|
|
- int node;
|
|
|
-
|
|
|
- node = cpu_to_node(cpu);
|
|
|
|
|
|
pin = kzalloc_node(sizeof(*pin), GFP_ATOMIC, node);
|
|
|
|
|
@@ -148,9 +145,6 @@ struct irq_cfg {
|
|
|
unsigned move_cleanup_count;
|
|
|
u8 vector;
|
|
|
u8 move_in_progress : 1;
|
|
|
-#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
|
|
|
- u8 move_desc_pending : 1;
|
|
|
-#endif
|
|
|
};
|
|
|
|
|
|
/* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
|
|
@@ -212,12 +206,9 @@ static struct irq_cfg *irq_cfg(unsigned int irq)
|
|
|
return cfg;
|
|
|
}
|
|
|
|
|
|
-static struct irq_cfg *get_one_free_irq_cfg(int cpu)
|
|
|
+static struct irq_cfg *get_one_free_irq_cfg(int node)
|
|
|
{
|
|
|
struct irq_cfg *cfg;
|
|
|
- int node;
|
|
|
-
|
|
|
- node = cpu_to_node(cpu);
|
|
|
|
|
|
cfg = kzalloc_node(sizeof(*cfg), GFP_ATOMIC, node);
|
|
|
if (cfg) {
|
|
@@ -238,13 +229,13 @@ static struct irq_cfg *get_one_free_irq_cfg(int cpu)
|
|
|
return cfg;
|
|
|
}
|
|
|
|
|
|
-int arch_init_chip_data(struct irq_desc *desc, int cpu)
|
|
|
+int arch_init_chip_data(struct irq_desc *desc, int node)
|
|
|
{
|
|
|
struct irq_cfg *cfg;
|
|
|
|
|
|
cfg = desc->chip_data;
|
|
|
if (!cfg) {
|
|
|
- desc->chip_data = get_one_free_irq_cfg(cpu);
|
|
|
+ desc->chip_data = get_one_free_irq_cfg(node);
|
|
|
if (!desc->chip_data) {
|
|
|
printk(KERN_ERR "can not alloc irq_cfg\n");
|
|
|
BUG_ON(1);
|
|
@@ -254,10 +245,9 @@ int arch_init_chip_data(struct irq_desc *desc, int cpu)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
|
|
|
-
|
|
|
+/* for move_irq_desc */
|
|
|
static void
|
|
|
-init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int cpu)
|
|
|
+init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int node)
|
|
|
{
|
|
|
struct irq_pin_list *old_entry, *head, *tail, *entry;
|
|
|
|
|
@@ -266,7 +256,7 @@ init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int cpu)
|
|
|
if (!old_entry)
|
|
|
return;
|
|
|
|
|
|
- entry = get_one_free_irq_2_pin(cpu);
|
|
|
+ entry = get_one_free_irq_2_pin(node);
|
|
|
if (!entry)
|
|
|
return;
|
|
|
|
|
@@ -276,7 +266,7 @@ init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int cpu)
|
|
|
tail = entry;
|
|
|
old_entry = old_entry->next;
|
|
|
while (old_entry) {
|
|
|
- entry = get_one_free_irq_2_pin(cpu);
|
|
|
+ entry = get_one_free_irq_2_pin(node);
|
|
|
if (!entry) {
|
|
|
entry = head;
|
|
|
while (entry) {
|
|
@@ -316,12 +306,12 @@ static void free_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg)
|
|
|
}
|
|
|
|
|
|
void arch_init_copy_chip_data(struct irq_desc *old_desc,
|
|
|
- struct irq_desc *desc, int cpu)
|
|
|
+ struct irq_desc *desc, int node)
|
|
|
{
|
|
|
struct irq_cfg *cfg;
|
|
|
struct irq_cfg *old_cfg;
|
|
|
|
|
|
- cfg = get_one_free_irq_cfg(cpu);
|
|
|
+ cfg = get_one_free_irq_cfg(node);
|
|
|
|
|
|
if (!cfg)
|
|
|
return;
|
|
@@ -332,7 +322,7 @@ void arch_init_copy_chip_data(struct irq_desc *old_desc,
|
|
|
|
|
|
memcpy(cfg, old_cfg, sizeof(struct irq_cfg));
|
|
|
|
|
|
- init_copy_irq_2_pin(old_cfg, cfg, cpu);
|
|
|
+ init_copy_irq_2_pin(old_cfg, cfg, node);
|
|
|
}
|
|
|
|
|
|
static void free_irq_cfg(struct irq_cfg *old_cfg)
|
|
@@ -356,19 +346,7 @@ void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc)
|
|
|
old_desc->chip_data = NULL;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-static void
|
|
|
-set_extra_move_desc(struct irq_desc *desc, const struct cpumask *mask)
|
|
|
-{
|
|
|
- struct irq_cfg *cfg = desc->chip_data;
|
|
|
-
|
|
|
- if (!cfg->move_in_progress) {
|
|
|
- /* it means that domain is not changed */
|
|
|
- if (!cpumask_intersects(desc->affinity, mask))
|
|
|
- cfg->move_desc_pending = 1;
|
|
|
- }
|
|
|
-}
|
|
|
-#endif
|
|
|
+/* end for move_irq_desc */
|
|
|
|
|
|
#else
|
|
|
static struct irq_cfg *irq_cfg(unsigned int irq)
|
|
@@ -378,13 +356,6 @@ static struct irq_cfg *irq_cfg(unsigned int irq)
|
|
|
|
|
|
#endif
|
|
|
|
|
|
-#ifndef CONFIG_NUMA_MIGRATE_IRQ_DESC
|
|
|
-static inline void
|
|
|
-set_extra_move_desc(struct irq_desc *desc, const struct cpumask *mask)
|
|
|
-{
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
struct io_apic {
|
|
|
unsigned int index;
|
|
|
unsigned int unused[3];
|
|
@@ -518,132 +489,18 @@ static void ioapic_mask_entry(int apic, int pin)
|
|
|
spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_SMP
|
|
|
-static void send_cleanup_vector(struct irq_cfg *cfg)
|
|
|
-{
|
|
|
- cpumask_var_t cleanup_mask;
|
|
|
-
|
|
|
- if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
|
|
|
- unsigned int i;
|
|
|
- cfg->move_cleanup_count = 0;
|
|
|
- for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
|
|
|
- cfg->move_cleanup_count++;
|
|
|
- for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
|
|
|
- apic->send_IPI_mask(cpumask_of(i), IRQ_MOVE_CLEANUP_VECTOR);
|
|
|
- } else {
|
|
|
- cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask);
|
|
|
- cfg->move_cleanup_count = cpumask_weight(cleanup_mask);
|
|
|
- apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
|
|
|
- free_cpumask_var(cleanup_mask);
|
|
|
- }
|
|
|
- cfg->move_in_progress = 0;
|
|
|
-}
|
|
|
-
|
|
|
-static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg)
|
|
|
-{
|
|
|
- int apic, pin;
|
|
|
- struct irq_pin_list *entry;
|
|
|
- u8 vector = cfg->vector;
|
|
|
-
|
|
|
- entry = cfg->irq_2_pin;
|
|
|
- for (;;) {
|
|
|
- unsigned int reg;
|
|
|
-
|
|
|
- if (!entry)
|
|
|
- break;
|
|
|
-
|
|
|
- apic = entry->apic;
|
|
|
- pin = entry->pin;
|
|
|
- /*
|
|
|
- * With interrupt-remapping, destination information comes
|
|
|
- * from interrupt-remapping table entry.
|
|
|
- */
|
|
|
- if (!irq_remapped(irq))
|
|
|
- io_apic_write(apic, 0x11 + pin*2, dest);
|
|
|
- reg = io_apic_read(apic, 0x10 + pin*2);
|
|
|
- reg &= ~IO_APIC_REDIR_VECTOR_MASK;
|
|
|
- reg |= vector;
|
|
|
- io_apic_modify(apic, 0x10 + pin*2, reg);
|
|
|
- if (!entry->next)
|
|
|
- break;
|
|
|
- entry = entry->next;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask);
|
|
|
-
|
|
|
-/*
|
|
|
- * Either sets desc->affinity to a valid value, and returns
|
|
|
- * ->cpu_mask_to_apicid of that, or returns BAD_APICID and
|
|
|
- * leaves desc->affinity untouched.
|
|
|
- */
|
|
|
-static unsigned int
|
|
|
-set_desc_affinity(struct irq_desc *desc, const struct cpumask *mask)
|
|
|
-{
|
|
|
- struct irq_cfg *cfg;
|
|
|
- unsigned int irq;
|
|
|
-
|
|
|
- if (!cpumask_intersects(mask, cpu_online_mask))
|
|
|
- return BAD_APICID;
|
|
|
-
|
|
|
- irq = desc->irq;
|
|
|
- cfg = desc->chip_data;
|
|
|
- if (assign_irq_vector(irq, cfg, mask))
|
|
|
- return BAD_APICID;
|
|
|
-
|
|
|
- /* check that before desc->addinity get updated */
|
|
|
- set_extra_move_desc(desc, mask);
|
|
|
-
|
|
|
- cpumask_copy(desc->affinity, mask);
|
|
|
-
|
|
|
- return apic->cpu_mask_to_apicid_and(desc->affinity, cfg->domain);
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-set_ioapic_affinity_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
|
|
|
-{
|
|
|
- struct irq_cfg *cfg;
|
|
|
- unsigned long flags;
|
|
|
- unsigned int dest;
|
|
|
- unsigned int irq;
|
|
|
-
|
|
|
- irq = desc->irq;
|
|
|
- cfg = desc->chip_data;
|
|
|
-
|
|
|
- spin_lock_irqsave(&ioapic_lock, flags);
|
|
|
- dest = set_desc_affinity(desc, mask);
|
|
|
- if (dest != BAD_APICID) {
|
|
|
- /* Only the high 8 bits are valid. */
|
|
|
- dest = SET_APIC_LOGICAL_ID(dest);
|
|
|
- __target_IO_APIC_irq(irq, dest, cfg);
|
|
|
- }
|
|
|
- spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-set_ioapic_affinity_irq(unsigned int irq, const struct cpumask *mask)
|
|
|
-{
|
|
|
- struct irq_desc *desc;
|
|
|
-
|
|
|
- desc = irq_to_desc(irq);
|
|
|
-
|
|
|
- set_ioapic_affinity_irq_desc(desc, mask);
|
|
|
-}
|
|
|
-#endif /* CONFIG_SMP */
|
|
|
-
|
|
|
/*
|
|
|
* 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
|
|
|
* fast in the common case, and fast for shared ISA-space IRQs.
|
|
|
*/
|
|
|
-static void add_pin_to_irq_cpu(struct irq_cfg *cfg, int cpu, int apic, int pin)
|
|
|
+static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
|
|
|
{
|
|
|
struct irq_pin_list *entry;
|
|
|
|
|
|
entry = cfg->irq_2_pin;
|
|
|
if (!entry) {
|
|
|
- entry = get_one_free_irq_2_pin(cpu);
|
|
|
+ entry = get_one_free_irq_2_pin(node);
|
|
|
if (!entry) {
|
|
|
printk(KERN_ERR "can not alloc irq_2_pin to add %d - %d\n",
|
|
|
apic, pin);
|
|
@@ -663,7 +520,7 @@ static void add_pin_to_irq_cpu(struct irq_cfg *cfg, int cpu, int apic, int pin)
|
|
|
entry = entry->next;
|
|
|
}
|
|
|
|
|
|
- entry->next = get_one_free_irq_2_pin(cpu);
|
|
|
+ entry->next = get_one_free_irq_2_pin(node);
|
|
|
entry = entry->next;
|
|
|
entry->apic = apic;
|
|
|
entry->pin = pin;
|
|
@@ -672,7 +529,7 @@ static void add_pin_to_irq_cpu(struct irq_cfg *cfg, int cpu, int apic, int pin)
|
|
|
/*
|
|
|
* Reroute an IRQ to a different pin.
|
|
|
*/
|
|
|
-static void __init replace_pin_at_irq_cpu(struct irq_cfg *cfg, int cpu,
|
|
|
+static void __init replace_pin_at_irq_node(struct irq_cfg *cfg, int node,
|
|
|
int oldapic, int oldpin,
|
|
|
int newapic, int newpin)
|
|
|
{
|
|
@@ -692,7 +549,7 @@ static void __init replace_pin_at_irq_cpu(struct irq_cfg *cfg, int cpu,
|
|
|
|
|
|
/* why? call replace before add? */
|
|
|
if (!replaced)
|
|
|
- add_pin_to_irq_cpu(cfg, cpu, newapic, newpin);
|
|
|
+ add_pin_to_irq_node(cfg, node, newapic, newpin);
|
|
|
}
|
|
|
|
|
|
static inline void io_apic_modify_irq(struct irq_cfg *cfg,
|
|
@@ -850,7 +707,6 @@ static int __init ioapic_pirq_setup(char *str)
|
|
|
__setup("pirq=", ioapic_pirq_setup);
|
|
|
#endif /* CONFIG_X86_32 */
|
|
|
|
|
|
-#ifdef CONFIG_INTR_REMAP
|
|
|
struct IO_APIC_route_entry **alloc_ioapic_entries(void)
|
|
|
{
|
|
|
int apic;
|
|
@@ -948,20 +804,6 @@ int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-void reinit_intr_remapped_IO_APIC(int intr_remapping,
|
|
|
- struct IO_APIC_route_entry **ioapic_entries)
|
|
|
-
|
|
|
-{
|
|
|
- /*
|
|
|
- * for now plain restore of previous settings.
|
|
|
- * TBD: In the case of OS enabling interrupt-remapping,
|
|
|
- * IO-APIC RTE's need to be setup to point to interrupt-remapping
|
|
|
- * table entries. for now, do a plain restore, and wait for
|
|
|
- * the setup_IO_APIC_irqs() to do proper initialization.
|
|
|
- */
|
|
|
- restore_IO_APIC_setup(ioapic_entries);
|
|
|
-}
|
|
|
-
|
|
|
void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries)
|
|
|
{
|
|
|
int apic;
|
|
@@ -971,7 +813,6 @@ void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries)
|
|
|
|
|
|
kfree(ioapic_entries);
|
|
|
}
|
|
|
-#endif
|
|
|
|
|
|
/*
|
|
|
* Find the IRQ entry number of a certain pin.
|
|
@@ -1032,54 +873,6 @@ static int __init find_isa_irq_apic(int irq, int type)
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Find a specific PCI IRQ entry.
|
|
|
- * Not an __init, possibly needed by modules
|
|
|
- */
|
|
|
-static int pin_2_irq(int idx, int apic, int pin);
|
|
|
-
|
|
|
-int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
|
|
|
-{
|
|
|
- int apic, i, best_guess = -1;
|
|
|
-
|
|
|
- apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
|
|
|
- bus, slot, pin);
|
|
|
- if (test_bit(bus, mp_bus_not_pci)) {
|
|
|
- apic_printk(APIC_VERBOSE, "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- for (i = 0; i < mp_irq_entries; i++) {
|
|
|
- int lbus = mp_irqs[i].srcbus;
|
|
|
-
|
|
|
- for (apic = 0; apic < nr_ioapics; apic++)
|
|
|
- if (mp_ioapics[apic].apicid == mp_irqs[i].dstapic ||
|
|
|
- mp_irqs[i].dstapic == MP_APIC_ALL)
|
|
|
- break;
|
|
|
-
|
|
|
- if (!test_bit(lbus, mp_bus_not_pci) &&
|
|
|
- !mp_irqs[i].irqtype &&
|
|
|
- (bus == lbus) &&
|
|
|
- (slot == ((mp_irqs[i].srcbusirq >> 2) & 0x1f))) {
|
|
|
- int irq = pin_2_irq(i, apic, mp_irqs[i].dstirq);
|
|
|
-
|
|
|
- if (!(apic || IO_APIC_IRQ(irq)))
|
|
|
- continue;
|
|
|
-
|
|
|
- if (pin == (mp_irqs[i].srcbusirq & 3))
|
|
|
- return irq;
|
|
|
- /*
|
|
|
- * Use the first all-but-pin matching entry as a
|
|
|
- * best-guess fuzzy result for broken mptables.
|
|
|
- */
|
|
|
- if (best_guess < 0)
|
|
|
- best_guess = irq;
|
|
|
- }
|
|
|
- }
|
|
|
- return best_guess;
|
|
|
-}
|
|
|
-
|
|
|
-EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
|
|
|
-
|
|
|
#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
|
|
|
/*
|
|
|
* EISA Edge/Level control register, ELCR
|
|
@@ -1298,6 +1091,64 @@ static int pin_2_irq(int idx, int apic, int pin)
|
|
|
return irq;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Find a specific PCI IRQ entry.
|
|
|
+ * Not an __init, possibly needed by modules
|
|
|
+ */
|
|
|
+int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin,
|
|
|
+ struct io_apic_irq_attr *irq_attr)
|
|
|
+{
|
|
|
+ int apic, i, best_guess = -1;
|
|
|
+
|
|
|
+ apic_printk(APIC_DEBUG,
|
|
|
+ "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
|
|
|
+ bus, slot, pin);
|
|
|
+ if (test_bit(bus, mp_bus_not_pci)) {
|
|
|
+ apic_printk(APIC_VERBOSE,
|
|
|
+ "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ for (i = 0; i < mp_irq_entries; i++) {
|
|
|
+ int lbus = mp_irqs[i].srcbus;
|
|
|
+
|
|
|
+ for (apic = 0; apic < nr_ioapics; apic++)
|
|
|
+ if (mp_ioapics[apic].apicid == mp_irqs[i].dstapic ||
|
|
|
+ mp_irqs[i].dstapic == MP_APIC_ALL)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (!test_bit(lbus, mp_bus_not_pci) &&
|
|
|
+ !mp_irqs[i].irqtype &&
|
|
|
+ (bus == lbus) &&
|
|
|
+ (slot == ((mp_irqs[i].srcbusirq >> 2) & 0x1f))) {
|
|
|
+ int irq = pin_2_irq(i, apic, mp_irqs[i].dstirq);
|
|
|
+
|
|
|
+ if (!(apic || IO_APIC_IRQ(irq)))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (pin == (mp_irqs[i].srcbusirq & 3)) {
|
|
|
+ set_io_apic_irq_attr(irq_attr, apic,
|
|
|
+ mp_irqs[i].dstirq,
|
|
|
+ irq_trigger(i),
|
|
|
+ irq_polarity(i));
|
|
|
+ return irq;
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ * Use the first all-but-pin matching entry as a
|
|
|
+ * best-guess fuzzy result for broken mptables.
|
|
|
+ */
|
|
|
+ if (best_guess < 0) {
|
|
|
+ set_io_apic_irq_attr(irq_attr, apic,
|
|
|
+ mp_irqs[i].dstirq,
|
|
|
+ irq_trigger(i),
|
|
|
+ irq_polarity(i));
|
|
|
+ best_guess = irq;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return best_guess;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
|
|
|
+
|
|
|
void lock_vector_lock(void)
|
|
|
{
|
|
|
/* Used to the online set of cpus does not change
|
|
@@ -1628,58 +1479,70 @@ static void setup_IO_APIC_irq(int apic_id, int pin, unsigned int irq, struct irq
|
|
|
ioapic_write_entry(apic_id, pin, entry);
|
|
|
}
|
|
|
|
|
|
+static struct {
|
|
|
+ DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1);
|
|
|
+} mp_ioapic_routing[MAX_IO_APICS];
|
|
|
+
|
|
|
static void __init setup_IO_APIC_irqs(void)
|
|
|
{
|
|
|
- int apic_id, pin, idx, irq;
|
|
|
+ int apic_id = 0, pin, idx, irq;
|
|
|
int notcon = 0;
|
|
|
struct irq_desc *desc;
|
|
|
struct irq_cfg *cfg;
|
|
|
- int cpu = boot_cpu_id;
|
|
|
+ int node = cpu_to_node(boot_cpu_id);
|
|
|
|
|
|
apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n");
|
|
|
|
|
|
- for (apic_id = 0; apic_id < nr_ioapics; apic_id++) {
|
|
|
- for (pin = 0; pin < nr_ioapic_registers[apic_id]; pin++) {
|
|
|
-
|
|
|
- idx = find_irq_entry(apic_id, pin, mp_INT);
|
|
|
- if (idx == -1) {
|
|
|
- if (!notcon) {
|
|
|
- notcon = 1;
|
|
|
- apic_printk(APIC_VERBOSE,
|
|
|
- KERN_DEBUG " %d-%d",
|
|
|
- mp_ioapics[apic_id].apicid, pin);
|
|
|
- } else
|
|
|
- apic_printk(APIC_VERBOSE, " %d-%d",
|
|
|
- mp_ioapics[apic_id].apicid, pin);
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (notcon) {
|
|
|
- apic_printk(APIC_VERBOSE,
|
|
|
- " (apicid-pin) not connected\n");
|
|
|
- notcon = 0;
|
|
|
- }
|
|
|
+#ifdef CONFIG_ACPI
|
|
|
+ if (!acpi_disabled && acpi_ioapic) {
|
|
|
+ apic_id = mp_find_ioapic(0);
|
|
|
+ if (apic_id < 0)
|
|
|
+ apic_id = 0;
|
|
|
+ }
|
|
|
+#endif
|
|
|
|
|
|
- irq = pin_2_irq(idx, apic_id, pin);
|
|
|
+ for (pin = 0; pin < nr_ioapic_registers[apic_id]; pin++) {
|
|
|
+ idx = find_irq_entry(apic_id, pin, mp_INT);
|
|
|
+ if (idx == -1) {
|
|
|
+ if (!notcon) {
|
|
|
+ notcon = 1;
|
|
|
+ apic_printk(APIC_VERBOSE,
|
|
|
+ KERN_DEBUG " %d-%d",
|
|
|
+ mp_ioapics[apic_id].apicid, pin);
|
|
|
+ } else
|
|
|
+ apic_printk(APIC_VERBOSE, " %d-%d",
|
|
|
+ mp_ioapics[apic_id].apicid, pin);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (notcon) {
|
|
|
+ apic_printk(APIC_VERBOSE,
|
|
|
+ " (apicid-pin) not connected\n");
|
|
|
+ notcon = 0;
|
|
|
+ }
|
|
|
|
|
|
- /*
|
|
|
- * Skip the timer IRQ if there's a quirk handler
|
|
|
- * installed and if it returns 1:
|
|
|
- */
|
|
|
- if (apic->multi_timer_check &&
|
|
|
- apic->multi_timer_check(apic_id, irq))
|
|
|
- continue;
|
|
|
+ irq = pin_2_irq(idx, apic_id, pin);
|
|
|
|
|
|
- desc = irq_to_desc_alloc_cpu(irq, cpu);
|
|
|
- if (!desc) {
|
|
|
- printk(KERN_INFO "can not get irq_desc for %d\n", irq);
|
|
|
- continue;
|
|
|
- }
|
|
|
- cfg = desc->chip_data;
|
|
|
- add_pin_to_irq_cpu(cfg, cpu, apic_id, pin);
|
|
|
+ /*
|
|
|
+ * Skip the timer IRQ if there's a quirk handler
|
|
|
+ * installed and if it returns 1:
|
|
|
+ */
|
|
|
+ if (apic->multi_timer_check &&
|
|
|
+ apic->multi_timer_check(apic_id, irq))
|
|
|
+ continue;
|
|
|
|
|
|
- setup_IO_APIC_irq(apic_id, pin, irq, desc,
|
|
|
- irq_trigger(idx), irq_polarity(idx));
|
|
|
+ desc = irq_to_desc_alloc_node(irq, node);
|
|
|
+ if (!desc) {
|
|
|
+ printk(KERN_INFO "can not get irq_desc for %d\n", irq);
|
|
|
+ continue;
|
|
|
}
|
|
|
+ cfg = desc->chip_data;
|
|
|
+ add_pin_to_irq_node(cfg, node, apic_id, pin);
|
|
|
+ /*
|
|
|
+ * don't mark it in pin_programmed, so later acpi could
|
|
|
+ * set it correctly when irq < 16
|
|
|
+ */
|
|
|
+ setup_IO_APIC_irq(apic_id, pin, irq, desc,
|
|
|
+ irq_trigger(idx), irq_polarity(idx));
|
|
|
}
|
|
|
|
|
|
if (notcon)
|
|
@@ -1869,7 +1732,7 @@ __apicdebuginit(void) print_APIC_bitfield(int base)
|
|
|
|
|
|
__apicdebuginit(void) print_local_APIC(void *dummy)
|
|
|
{
|
|
|
- unsigned int v, ver, maxlvt;
|
|
|
+ unsigned int i, v, ver, maxlvt;
|
|
|
u64 icr;
|
|
|
|
|
|
if (apic_verbosity == APIC_QUIET)
|
|
@@ -1957,6 +1820,18 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
|
|
|
printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v);
|
|
|
v = apic_read(APIC_TDCR);
|
|
|
printk(KERN_DEBUG "... APIC TDCR: %08x\n", v);
|
|
|
+
|
|
|
+ if (boot_cpu_has(X86_FEATURE_EXTAPIC)) {
|
|
|
+ v = apic_read(APIC_EFEAT);
|
|
|
+ maxlvt = (v >> 16) & 0xff;
|
|
|
+ printk(KERN_DEBUG "... APIC EFEAT: %08x\n", v);
|
|
|
+ v = apic_read(APIC_ECTRL);
|
|
|
+ printk(KERN_DEBUG "... APIC ECTRL: %08x\n", v);
|
|
|
+ for (i = 0; i < maxlvt; i++) {
|
|
|
+ v = apic_read(APIC_EILVTn(i));
|
|
|
+ printk(KERN_DEBUG "... APIC EILVT%d: %08x\n", i, v);
|
|
|
+ }
|
|
|
+ }
|
|
|
printk("\n");
|
|
|
}
|
|
|
|
|
@@ -2005,6 +1880,11 @@ __apicdebuginit(void) print_PIC(void)
|
|
|
__apicdebuginit(int) print_all_ICs(void)
|
|
|
{
|
|
|
print_PIC();
|
|
|
+
|
|
|
+ /* don't print out if apic is not there */
|
|
|
+ if (!cpu_has_apic || disable_apic)
|
|
|
+ return 0;
|
|
|
+
|
|
|
print_all_local_APICs();
|
|
|
print_IO_APIC();
|
|
|
|
|
@@ -2360,9 +2240,121 @@ static int ioapic_retrigger_irq(unsigned int irq)
|
|
|
*/
|
|
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
+static void send_cleanup_vector(struct irq_cfg *cfg)
|
|
|
+{
|
|
|
+ cpumask_var_t cleanup_mask;
|
|
|
+
|
|
|
+ if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
|
|
|
+ unsigned int i;
|
|
|
+ cfg->move_cleanup_count = 0;
|
|
|
+ for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
|
|
|
+ cfg->move_cleanup_count++;
|
|
|
+ for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
|
|
|
+ apic->send_IPI_mask(cpumask_of(i), IRQ_MOVE_CLEANUP_VECTOR);
|
|
|
+ } else {
|
|
|
+ cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask);
|
|
|
+ cfg->move_cleanup_count = cpumask_weight(cleanup_mask);
|
|
|
+ apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
|
|
|
+ free_cpumask_var(cleanup_mask);
|
|
|
+ }
|
|
|
+ cfg->move_in_progress = 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg)
|
|
|
+{
|
|
|
+ int apic, pin;
|
|
|
+ struct irq_pin_list *entry;
|
|
|
+ u8 vector = cfg->vector;
|
|
|
+
|
|
|
+ entry = cfg->irq_2_pin;
|
|
|
+ for (;;) {
|
|
|
+ unsigned int reg;
|
|
|
+
|
|
|
+ if (!entry)
|
|
|
+ break;
|
|
|
+
|
|
|
+ apic = entry->apic;
|
|
|
+ pin = entry->pin;
|
|
|
+ /*
|
|
|
+ * With interrupt-remapping, destination information comes
|
|
|
+ * from interrupt-remapping table entry.
|
|
|
+ */
|
|
|
+ if (!irq_remapped(irq))
|
|
|
+ io_apic_write(apic, 0x11 + pin*2, dest);
|
|
|
+ reg = io_apic_read(apic, 0x10 + pin*2);
|
|
|
+ reg &= ~IO_APIC_REDIR_VECTOR_MASK;
|
|
|
+ reg |= vector;
|
|
|
+ io_apic_modify(apic, 0x10 + pin*2, reg);
|
|
|
+ if (!entry->next)
|
|
|
+ break;
|
|
|
+ entry = entry->next;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask);
|
|
|
+
|
|
|
+/*
|
|
|
+ * Either sets desc->affinity to a valid value, and returns
|
|
|
+ * ->cpu_mask_to_apicid of that, or returns BAD_APICID and
|
|
|
+ * leaves desc->affinity untouched.
|
|
|
+ */
|
|
|
+static unsigned int
|
|
|
+set_desc_affinity(struct irq_desc *desc, const struct cpumask *mask)
|
|
|
+{
|
|
|
+ struct irq_cfg *cfg;
|
|
|
+ unsigned int irq;
|
|
|
+
|
|
|
+ if (!cpumask_intersects(mask, cpu_online_mask))
|
|
|
+ return BAD_APICID;
|
|
|
+
|
|
|
+ irq = desc->irq;
|
|
|
+ cfg = desc->chip_data;
|
|
|
+ if (assign_irq_vector(irq, cfg, mask))
|
|
|
+ return BAD_APICID;
|
|
|
+
|
|
|
+ cpumask_copy(desc->affinity, mask);
|
|
|
+
|
|
|
+ return apic->cpu_mask_to_apicid_and(desc->affinity, cfg->domain);
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+set_ioapic_affinity_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
|
|
|
+{
|
|
|
+ struct irq_cfg *cfg;
|
|
|
+ unsigned long flags;
|
|
|
+ unsigned int dest;
|
|
|
+ unsigned int irq;
|
|
|
+ int ret = -1;
|
|
|
+
|
|
|
+ irq = desc->irq;
|
|
|
+ cfg = desc->chip_data;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&ioapic_lock, flags);
|
|
|
+ dest = set_desc_affinity(desc, mask);
|
|
|
+ if (dest != BAD_APICID) {
|
|
|
+ /* Only the high 8 bits are valid. */
|
|
|
+ dest = SET_APIC_LOGICAL_ID(dest);
|
|
|
+ __target_IO_APIC_irq(irq, dest, cfg);
|
|
|
+ ret = 0;
|
|
|
+ }
|
|
|
+ spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+set_ioapic_affinity_irq(unsigned int irq, const struct cpumask *mask)
|
|
|
+{
|
|
|
+ struct irq_desc *desc;
|
|
|
+
|
|
|
+ desc = irq_to_desc(irq);
|
|
|
+
|
|
|
+ return set_ioapic_affinity_irq_desc(desc, mask);
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef CONFIG_INTR_REMAP
|
|
|
|
|
|
-#ifdef CONFIG_INTR_REMAP
|
|
|
-
|
|
|
/*
|
|
|
* Migrate the IO-APIC irq in the presence of intr-remapping.
|
|
|
*
|
|
@@ -2374,26 +2366,25 @@ static int ioapic_retrigger_irq(unsigned int irq)
|
|
|
* Real vector that is used for interrupting cpu will be coming from
|
|
|
* the interrupt-remapping table entry.
|
|
|
*/
|
|
|
-static void
|
|
|
+static int
|
|
|
migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
|
|
|
{
|
|
|
struct irq_cfg *cfg;
|
|
|
struct irte irte;
|
|
|
unsigned int dest;
|
|
|
unsigned int irq;
|
|
|
+ int ret = -1;
|
|
|
|
|
|
if (!cpumask_intersects(mask, cpu_online_mask))
|
|
|
- return;
|
|
|
+ return ret;
|
|
|
|
|
|
irq = desc->irq;
|
|
|
if (get_irte(irq, &irte))
|
|
|
- return;
|
|
|
+ return ret;
|
|
|
|
|
|
cfg = desc->chip_data;
|
|
|
if (assign_irq_vector(irq, cfg, mask))
|
|
|
- return;
|
|
|
-
|
|
|
- set_extra_move_desc(desc, mask);
|
|
|
+ return ret;
|
|
|
|
|
|
dest = apic->cpu_mask_to_apicid_and(cfg->domain, mask);
|
|
|
|
|
@@ -2409,27 +2400,30 @@ migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
|
|
|
send_cleanup_vector(cfg);
|
|
|
|
|
|
cpumask_copy(desc->affinity, mask);
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* Migrates the IRQ destination in the process context.
|
|
|
*/
|
|
|
-static void set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
|
|
|
+static int set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
|
|
|
const struct cpumask *mask)
|
|
|
{
|
|
|
- migrate_ioapic_irq_desc(desc, mask);
|
|
|
+ return migrate_ioapic_irq_desc(desc, mask);
|
|
|
}
|
|
|
-static void set_ir_ioapic_affinity_irq(unsigned int irq,
|
|
|
+static int set_ir_ioapic_affinity_irq(unsigned int irq,
|
|
|
const struct cpumask *mask)
|
|
|
{
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
|
|
|
|
|
- set_ir_ioapic_affinity_irq_desc(desc, mask);
|
|
|
+ return set_ir_ioapic_affinity_irq_desc(desc, mask);
|
|
|
}
|
|
|
#else
|
|
|
-static inline void set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
|
|
|
+static inline int set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
|
|
|
const struct cpumask *mask)
|
|
|
{
|
|
|
+ return 0;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
@@ -2491,86 +2485,19 @@ static void irq_complete_move(struct irq_desc **descp)
|
|
|
struct irq_cfg *cfg = desc->chip_data;
|
|
|
unsigned vector, me;
|
|
|
|
|
|
- if (likely(!cfg->move_in_progress)) {
|
|
|
-#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
|
|
|
- if (likely(!cfg->move_desc_pending))
|
|
|
- return;
|
|
|
-
|
|
|
- /* domain has not changed, but affinity did */
|
|
|
- me = smp_processor_id();
|
|
|
- if (cpumask_test_cpu(me, desc->affinity)) {
|
|
|
- *descp = desc = move_irq_desc(desc, me);
|
|
|
- /* get the new one */
|
|
|
- cfg = desc->chip_data;
|
|
|
- cfg->move_desc_pending = 0;
|
|
|
- }
|
|
|
-#endif
|
|
|
+ if (likely(!cfg->move_in_progress))
|
|
|
return;
|
|
|
- }
|
|
|
|
|
|
vector = ~get_irq_regs()->orig_ax;
|
|
|
me = smp_processor_id();
|
|
|
|
|
|
- if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain)) {
|
|
|
-#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
|
|
|
- *descp = desc = move_irq_desc(desc, me);
|
|
|
- /* get the new one */
|
|
|
- cfg = desc->chip_data;
|
|
|
-#endif
|
|
|
+ if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
|
|
|
send_cleanup_vector(cfg);
|
|
|
- }
|
|
|
}
|
|
|
#else
|
|
|
static inline void irq_complete_move(struct irq_desc **descp) {}
|
|
|
#endif
|
|
|
|
|
|
-static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
|
|
|
-{
|
|
|
- int apic, pin;
|
|
|
- struct irq_pin_list *entry;
|
|
|
-
|
|
|
- entry = cfg->irq_2_pin;
|
|
|
- for (;;) {
|
|
|
-
|
|
|
- if (!entry)
|
|
|
- break;
|
|
|
-
|
|
|
- apic = entry->apic;
|
|
|
- pin = entry->pin;
|
|
|
- io_apic_eoi(apic, pin);
|
|
|
- entry = entry->next;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-eoi_ioapic_irq(struct irq_desc *desc)
|
|
|
-{
|
|
|
- struct irq_cfg *cfg;
|
|
|
- unsigned long flags;
|
|
|
- unsigned int irq;
|
|
|
-
|
|
|
- irq = desc->irq;
|
|
|
- cfg = desc->chip_data;
|
|
|
-
|
|
|
- spin_lock_irqsave(&ioapic_lock, flags);
|
|
|
- __eoi_ioapic_irq(irq, cfg);
|
|
|
- spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
|
-}
|
|
|
-
|
|
|
-#ifdef CONFIG_X86_X2APIC
|
|
|
-static void ack_x2apic_level(unsigned int irq)
|
|
|
-{
|
|
|
- struct irq_desc *desc = irq_to_desc(irq);
|
|
|
- ack_x2APIC_irq();
|
|
|
- eoi_ioapic_irq(desc);
|
|
|
-}
|
|
|
-
|
|
|
-static void ack_x2apic_edge(unsigned int irq)
|
|
|
-{
|
|
|
- ack_x2APIC_irq();
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
static void ack_apic_edge(unsigned int irq)
|
|
|
{
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
|
@@ -2634,9 +2561,6 @@ static void ack_apic_level(unsigned int irq)
|
|
|
*/
|
|
|
ack_APIC_irq();
|
|
|
|
|
|
- if (irq_remapped(irq))
|
|
|
- eoi_ioapic_irq(desc);
|
|
|
-
|
|
|
/* Now we can move and renable the irq */
|
|
|
if (unlikely(do_unmask_irq)) {
|
|
|
/* Only migrate the irq if the ack has been received.
|
|
@@ -2683,22 +2607,50 @@ static void ack_apic_level(unsigned int irq)
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_INTR_REMAP
|
|
|
+static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
|
|
|
+{
|
|
|
+ int apic, pin;
|
|
|
+ struct irq_pin_list *entry;
|
|
|
+
|
|
|
+ entry = cfg->irq_2_pin;
|
|
|
+ for (;;) {
|
|
|
+
|
|
|
+ if (!entry)
|
|
|
+ break;
|
|
|
+
|
|
|
+ apic = entry->apic;
|
|
|
+ pin = entry->pin;
|
|
|
+ io_apic_eoi(apic, pin);
|
|
|
+ entry = entry->next;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+eoi_ioapic_irq(struct irq_desc *desc)
|
|
|
+{
|
|
|
+ struct irq_cfg *cfg;
|
|
|
+ unsigned long flags;
|
|
|
+ unsigned int irq;
|
|
|
+
|
|
|
+ irq = desc->irq;
|
|
|
+ cfg = desc->chip_data;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&ioapic_lock, flags);
|
|
|
+ __eoi_ioapic_irq(irq, cfg);
|
|
|
+ spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
|
+}
|
|
|
+
|
|
|
static void ir_ack_apic_edge(unsigned int irq)
|
|
|
{
|
|
|
-#ifdef CONFIG_X86_X2APIC
|
|
|
- if (x2apic_enabled())
|
|
|
- return ack_x2apic_edge(irq);
|
|
|
-#endif
|
|
|
- return ack_apic_edge(irq);
|
|
|
+ ack_APIC_irq();
|
|
|
}
|
|
|
|
|
|
static void ir_ack_apic_level(unsigned int irq)
|
|
|
{
|
|
|
-#ifdef CONFIG_X86_X2APIC
|
|
|
- if (x2apic_enabled())
|
|
|
- return ack_x2apic_level(irq);
|
|
|
-#endif
|
|
|
- return ack_apic_level(irq);
|
|
|
+ struct irq_desc *desc = irq_to_desc(irq);
|
|
|
+
|
|
|
+ ack_APIC_irq();
|
|
|
+ eoi_ioapic_irq(desc);
|
|
|
}
|
|
|
#endif /* CONFIG_INTR_REMAP */
|
|
|
|
|
@@ -2903,7 +2855,7 @@ static inline void __init check_timer(void)
|
|
|
{
|
|
|
struct irq_desc *desc = irq_to_desc(0);
|
|
|
struct irq_cfg *cfg = desc->chip_data;
|
|
|
- int cpu = boot_cpu_id;
|
|
|
+ int node = cpu_to_node(boot_cpu_id);
|
|
|
int apic1, pin1, apic2, pin2;
|
|
|
unsigned long flags;
|
|
|
int no_pin1 = 0;
|
|
@@ -2969,7 +2921,7 @@ static inline void __init check_timer(void)
|
|
|
* Ok, does IRQ0 through the IOAPIC work?
|
|
|
*/
|
|
|
if (no_pin1) {
|
|
|
- add_pin_to_irq_cpu(cfg, cpu, apic1, pin1);
|
|
|
+ add_pin_to_irq_node(cfg, node, apic1, pin1);
|
|
|
setup_timer_IRQ0_pin(apic1, pin1, cfg->vector);
|
|
|
} else {
|
|
|
/* for edge trigger, setup_IO_APIC_irq already
|
|
@@ -3006,7 +2958,7 @@ static inline void __init check_timer(void)
|
|
|
/*
|
|
|
* legacy devices should be connected to IO APIC #0
|
|
|
*/
|
|
|
- replace_pin_at_irq_cpu(cfg, cpu, apic1, pin1, apic2, pin2);
|
|
|
+ replace_pin_at_irq_node(cfg, node, apic1, pin1, apic2, pin2);
|
|
|
setup_timer_IRQ0_pin(apic2, pin2, cfg->vector);
|
|
|
enable_8259A_irq(0);
|
|
|
if (timer_irq_works()) {
|
|
@@ -3218,14 +3170,13 @@ static int nr_irqs_gsi = NR_IRQS_LEGACY;
|
|
|
/*
|
|
|
* Dynamic irq allocate and deallocation
|
|
|
*/
|
|
|
-unsigned int create_irq_nr(unsigned int irq_want)
|
|
|
+unsigned int create_irq_nr(unsigned int irq_want, int node)
|
|
|
{
|
|
|
/* Allocate an unused irq */
|
|
|
unsigned int irq;
|
|
|
unsigned int new;
|
|
|
unsigned long flags;
|
|
|
struct irq_cfg *cfg_new = NULL;
|
|
|
- int cpu = boot_cpu_id;
|
|
|
struct irq_desc *desc_new = NULL;
|
|
|
|
|
|
irq = 0;
|
|
@@ -3234,7 +3185,7 @@ unsigned int create_irq_nr(unsigned int irq_want)
|
|
|
|
|
|
spin_lock_irqsave(&vector_lock, flags);
|
|
|
for (new = irq_want; new < nr_irqs; new++) {
|
|
|
- desc_new = irq_to_desc_alloc_cpu(new, cpu);
|
|
|
+ desc_new = irq_to_desc_alloc_node(new, node);
|
|
|
if (!desc_new) {
|
|
|
printk(KERN_INFO "can not get irq_desc for %d\n", new);
|
|
|
continue;
|
|
@@ -3243,6 +3194,9 @@ unsigned int create_irq_nr(unsigned int irq_want)
|
|
|
|
|
|
if (cfg_new->vector != 0)
|
|
|
continue;
|
|
|
+
|
|
|
+ desc_new = move_irq_desc(desc_new, node);
|
|
|
+
|
|
|
if (__assign_irq_vector(new, cfg_new, apic->target_cpus()) == 0)
|
|
|
irq = new;
|
|
|
break;
|
|
@@ -3260,11 +3214,12 @@ unsigned int create_irq_nr(unsigned int irq_want)
|
|
|
|
|
|
int create_irq(void)
|
|
|
{
|
|
|
+ int node = cpu_to_node(boot_cpu_id);
|
|
|
unsigned int irq_want;
|
|
|
int irq;
|
|
|
|
|
|
irq_want = nr_irqs_gsi;
|
|
|
- irq = create_irq_nr(irq_want);
|
|
|
+ irq = create_irq_nr(irq_want, node);
|
|
|
|
|
|
if (irq == 0)
|
|
|
irq = -1;
|
|
@@ -3366,7 +3321,7 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
-static void set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
+static int set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
{
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
|
|
struct irq_cfg *cfg;
|
|
@@ -3375,7 +3330,7 @@ static void set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
|
|
|
dest = set_desc_affinity(desc, mask);
|
|
|
if (dest == BAD_APICID)
|
|
|
- return;
|
|
|
+ return -1;
|
|
|
|
|
|
cfg = desc->chip_data;
|
|
|
|
|
@@ -3387,13 +3342,15 @@ static void set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
msg.address_lo |= MSI_ADDR_DEST_ID(dest);
|
|
|
|
|
|
write_msi_msg_desc(desc, &msg);
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
#ifdef CONFIG_INTR_REMAP
|
|
|
/*
|
|
|
* Migrate the MSI irq to another cpumask. This migration is
|
|
|
* done in the process context using interrupt-remapping hardware.
|
|
|
*/
|
|
|
-static void
|
|
|
+static int
|
|
|
ir_set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
{
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
|
@@ -3402,11 +3359,11 @@ ir_set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
struct irte irte;
|
|
|
|
|
|
if (get_irte(irq, &irte))
|
|
|
- return;
|
|
|
+ return -1;
|
|
|
|
|
|
dest = set_desc_affinity(desc, mask);
|
|
|
if (dest == BAD_APICID)
|
|
|
- return;
|
|
|
+ return -1;
|
|
|
|
|
|
irte.vector = cfg->vector;
|
|
|
irte.dest_id = IRTE_DEST(dest);
|
|
@@ -3423,6 +3380,8 @@ ir_set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
*/
|
|
|
if (cfg->move_in_progress)
|
|
|
send_cleanup_vector(cfg);
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
#endif
|
|
@@ -3518,15 +3477,17 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
|
|
|
unsigned int irq_want;
|
|
|
struct intel_iommu *iommu = NULL;
|
|
|
int index = 0;
|
|
|
+ int node;
|
|
|
|
|
|
/* x86 doesn't support multiple MSI yet */
|
|
|
if (type == PCI_CAP_ID_MSI && nvec > 1)
|
|
|
return 1;
|
|
|
|
|
|
+ node = dev_to_node(&dev->dev);
|
|
|
irq_want = nr_irqs_gsi;
|
|
|
sub_handle = 0;
|
|
|
list_for_each_entry(msidesc, &dev->msi_list, list) {
|
|
|
- irq = create_irq_nr(irq_want);
|
|
|
+ irq = create_irq_nr(irq_want, node);
|
|
|
if (irq == 0)
|
|
|
return -1;
|
|
|
irq_want = irq + 1;
|
|
@@ -3576,7 +3537,7 @@ void arch_teardown_msi_irq(unsigned int irq)
|
|
|
|
|
|
#if defined (CONFIG_DMAR) || defined (CONFIG_INTR_REMAP)
|
|
|
#ifdef CONFIG_SMP
|
|
|
-static void dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
+static int dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
{
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
|
|
struct irq_cfg *cfg;
|
|
@@ -3585,7 +3546,7 @@ static void dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
|
|
|
dest = set_desc_affinity(desc, mask);
|
|
|
if (dest == BAD_APICID)
|
|
|
- return;
|
|
|
+ return -1;
|
|
|
|
|
|
cfg = desc->chip_data;
|
|
|
|
|
@@ -3597,6 +3558,8 @@ static void dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
msg.address_lo |= MSI_ADDR_DEST_ID(dest);
|
|
|
|
|
|
dmar_msi_write(irq, &msg);
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
#endif /* CONFIG_SMP */
|
|
@@ -3630,7 +3593,7 @@ int arch_setup_dmar_msi(unsigned int irq)
|
|
|
#ifdef CONFIG_HPET_TIMER
|
|
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
-static void hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
+static int hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
{
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
|
|
struct irq_cfg *cfg;
|
|
@@ -3639,7 +3602,7 @@ static void hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
|
|
|
dest = set_desc_affinity(desc, mask);
|
|
|
if (dest == BAD_APICID)
|
|
|
- return;
|
|
|
+ return -1;
|
|
|
|
|
|
cfg = desc->chip_data;
|
|
|
|
|
@@ -3651,6 +3614,8 @@ static void hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
msg.address_lo |= MSI_ADDR_DEST_ID(dest);
|
|
|
|
|
|
hpet_msi_write(irq, &msg);
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
#endif /* CONFIG_SMP */
|
|
@@ -3707,7 +3672,7 @@ static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
|
|
|
write_ht_irq_msg(irq, &msg);
|
|
|
}
|
|
|
|
|
|
-static void set_ht_irq_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
+static int set_ht_irq_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
{
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
|
|
struct irq_cfg *cfg;
|
|
@@ -3715,11 +3680,13 @@ static void set_ht_irq_affinity(unsigned int irq, const struct cpumask *mask)
|
|
|
|
|
|
dest = set_desc_affinity(desc, mask);
|
|
|
if (dest == BAD_APICID)
|
|
|
- return;
|
|
|
+ return -1;
|
|
|
|
|
|
cfg = desc->chip_data;
|
|
|
|
|
|
target_ht_irq(irq, dest, cfg->vector);
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
#endif
|
|
@@ -3794,6 +3761,8 @@ int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
|
|
|
unsigned long flags;
|
|
|
int err;
|
|
|
|
|
|
+ BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
|
|
|
+
|
|
|
cfg = irq_cfg(irq);
|
|
|
|
|
|
err = assign_irq_vector(irq, cfg, eligible_cpu);
|
|
@@ -3807,15 +3776,13 @@ int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
|
|
|
|
|
|
mmr_value = 0;
|
|
|
entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
|
|
|
- BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
|
|
|
-
|
|
|
- entry->vector = cfg->vector;
|
|
|
- entry->delivery_mode = apic->irq_delivery_mode;
|
|
|
- entry->dest_mode = apic->irq_dest_mode;
|
|
|
- entry->polarity = 0;
|
|
|
- entry->trigger = 0;
|
|
|
- entry->mask = 0;
|
|
|
- entry->dest = apic->cpu_mask_to_apicid(eligible_cpu);
|
|
|
+ entry->vector = cfg->vector;
|
|
|
+ entry->delivery_mode = apic->irq_delivery_mode;
|
|
|
+ entry->dest_mode = apic->irq_dest_mode;
|
|
|
+ entry->polarity = 0;
|
|
|
+ entry->trigger = 0;
|
|
|
+ entry->mask = 0;
|
|
|
+ entry->dest = apic->cpu_mask_to_apicid(eligible_cpu);
|
|
|
|
|
|
mmr_pnode = uv_blade_to_pnode(mmr_blade);
|
|
|
uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
|
|
@@ -3833,10 +3800,10 @@ void arch_disable_uv_irq(int mmr_blade, unsigned long mmr_offset)
|
|
|
struct uv_IO_APIC_route_entry *entry;
|
|
|
int mmr_pnode;
|
|
|
|
|
|
+ BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
|
|
|
+
|
|
|
mmr_value = 0;
|
|
|
entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
|
|
|
- BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
|
|
|
-
|
|
|
entry->mask = 1;
|
|
|
|
|
|
mmr_pnode = uv_blade_to_pnode(mmr_blade);
|
|
@@ -3900,6 +3867,71 @@ int __init arch_probe_nr_irqs(void)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+static int __io_apic_set_pci_routing(struct device *dev, int irq,
|
|
|
+ struct io_apic_irq_attr *irq_attr)
|
|
|
+{
|
|
|
+ struct irq_desc *desc;
|
|
|
+ struct irq_cfg *cfg;
|
|
|
+ int node;
|
|
|
+ int ioapic, pin;
|
|
|
+ int trigger, polarity;
|
|
|
+
|
|
|
+ ioapic = irq_attr->ioapic;
|
|
|
+ if (!IO_APIC_IRQ(irq)) {
|
|
|
+ apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
|
|
|
+ ioapic);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dev)
|
|
|
+ node = dev_to_node(dev);
|
|
|
+ else
|
|
|
+ node = cpu_to_node(boot_cpu_id);
|
|
|
+
|
|
|
+ desc = irq_to_desc_alloc_node(irq, node);
|
|
|
+ if (!desc) {
|
|
|
+ printk(KERN_INFO "can not get irq_desc %d\n", irq);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ pin = irq_attr->ioapic_pin;
|
|
|
+ trigger = irq_attr->trigger;
|
|
|
+ polarity = irq_attr->polarity;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * IRQs < 16 are already in the irq_2_pin[] map
|
|
|
+ */
|
|
|
+ if (irq >= NR_IRQS_LEGACY) {
|
|
|
+ cfg = desc->chip_data;
|
|
|
+ add_pin_to_irq_node(cfg, node, ioapic, pin);
|
|
|
+ }
|
|
|
+
|
|
|
+ setup_IO_APIC_irq(ioapic, pin, irq, desc, trigger, polarity);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int io_apic_set_pci_routing(struct device *dev, int irq,
|
|
|
+ struct io_apic_irq_attr *irq_attr)
|
|
|
+{
|
|
|
+ int ioapic, pin;
|
|
|
+ /*
|
|
|
+ * Avoid pin reprogramming. PRTs typically include entries
|
|
|
+ * with redundant pin->gsi mappings (but unique PCI devices);
|
|
|
+ * we only program the IOAPIC on the first.
|
|
|
+ */
|
|
|
+ ioapic = irq_attr->ioapic;
|
|
|
+ pin = irq_attr->ioapic_pin;
|
|
|
+ if (test_bit(pin, mp_ioapic_routing[ioapic].pin_programmed)) {
|
|
|
+ pr_debug("Pin %d-%d already programmed\n",
|
|
|
+ mp_ioapics[ioapic].apicid, pin);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ set_bit(pin, mp_ioapic_routing[ioapic].pin_programmed);
|
|
|
+
|
|
|
+ return __io_apic_set_pci_routing(dev, irq, irq_attr);
|
|
|
+}
|
|
|
+
|
|
|
/* --------------------------------------------------------------------------
|
|
|
ACPI-based IOAPIC Configuration
|
|
|
-------------------------------------------------------------------------- */
|
|
@@ -3994,38 +4026,6 @@ int __init io_apic_get_version(int ioapic)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int polarity)
|
|
|
-{
|
|
|
- struct irq_desc *desc;
|
|
|
- struct irq_cfg *cfg;
|
|
|
- int cpu = boot_cpu_id;
|
|
|
-
|
|
|
- if (!IO_APIC_IRQ(irq)) {
|
|
|
- apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
|
|
|
- ioapic);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- desc = irq_to_desc_alloc_cpu(irq, cpu);
|
|
|
- if (!desc) {
|
|
|
- printk(KERN_INFO "can not get irq_desc %d\n", irq);
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * IRQs < 16 are already in the irq_2_pin[] map
|
|
|
- */
|
|
|
- if (irq >= NR_IRQS_LEGACY) {
|
|
|
- cfg = desc->chip_data;
|
|
|
- add_pin_to_irq_cpu(cfg, cpu, ioapic, pin);
|
|
|
- }
|
|
|
-
|
|
|
- setup_IO_APIC_irq(ioapic, pin, irq, desc, triggering, polarity);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity)
|
|
|
{
|
|
|
int i;
|
|
@@ -4055,51 +4055,44 @@ int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity)
|
|
|
#ifdef CONFIG_SMP
|
|
|
void __init setup_ioapic_dest(void)
|
|
|
{
|
|
|
- int pin, ioapic, irq, irq_entry;
|
|
|
+ int pin, ioapic = 0, irq, irq_entry;
|
|
|
struct irq_desc *desc;
|
|
|
- struct irq_cfg *cfg;
|
|
|
const struct cpumask *mask;
|
|
|
|
|
|
if (skip_ioapic_setup == 1)
|
|
|
return;
|
|
|
|
|
|
- for (ioapic = 0; ioapic < nr_ioapics; ioapic++) {
|
|
|
- for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) {
|
|
|
- irq_entry = find_irq_entry(ioapic, pin, mp_INT);
|
|
|
- if (irq_entry == -1)
|
|
|
- continue;
|
|
|
- irq = pin_2_irq(irq_entry, ioapic, pin);
|
|
|
-
|
|
|
- /* setup_IO_APIC_irqs could fail to get vector for some device
|
|
|
- * when you have too many devices, because at that time only boot
|
|
|
- * cpu is online.
|
|
|
- */
|
|
|
- desc = irq_to_desc(irq);
|
|
|
- cfg = desc->chip_data;
|
|
|
- if (!cfg->vector) {
|
|
|
- setup_IO_APIC_irq(ioapic, pin, irq, desc,
|
|
|
- irq_trigger(irq_entry),
|
|
|
- irq_polarity(irq_entry));
|
|
|
- continue;
|
|
|
+#ifdef CONFIG_ACPI
|
|
|
+ if (!acpi_disabled && acpi_ioapic) {
|
|
|
+ ioapic = mp_find_ioapic(0);
|
|
|
+ if (ioapic < 0)
|
|
|
+ ioapic = 0;
|
|
|
+ }
|
|
|
+#endif
|
|
|
|
|
|
- }
|
|
|
+ for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) {
|
|
|
+ irq_entry = find_irq_entry(ioapic, pin, mp_INT);
|
|
|
+ if (irq_entry == -1)
|
|
|
+ continue;
|
|
|
+ irq = pin_2_irq(irq_entry, ioapic, pin);
|
|
|
|
|
|
- /*
|
|
|
- * Honour affinities which have been set in early boot
|
|
|
- */
|
|
|
- if (desc->status &
|
|
|
- (IRQ_NO_BALANCING | IRQ_AFFINITY_SET))
|
|
|
- mask = desc->affinity;
|
|
|
- else
|
|
|
- mask = apic->target_cpus();
|
|
|
+ desc = irq_to_desc(irq);
|
|
|
|
|
|
- if (intr_remapping_enabled)
|
|
|
- set_ir_ioapic_affinity_irq_desc(desc, mask);
|
|
|
- else
|
|
|
- set_ioapic_affinity_irq_desc(desc, mask);
|
|
|
- }
|
|
|
+ /*
|
|
|
+ * Honour affinities which have been set in early boot
|
|
|
+ */
|
|
|
+ if (desc->status &
|
|
|
+ (IRQ_NO_BALANCING | IRQ_AFFINITY_SET))
|
|
|
+ mask = desc->affinity;
|
|
|
+ else
|
|
|
+ mask = apic->target_cpus();
|
|
|
|
|
|
+ if (intr_remapping_enabled)
|
|
|
+ set_ir_ioapic_affinity_irq_desc(desc, mask);
|
|
|
+ else
|
|
|
+ set_ioapic_affinity_irq_desc(desc, mask);
|
|
|
}
|
|
|
+
|
|
|
}
|
|
|
#endif
|
|
|
|