Commit 54168ed7 authored by Ingo Molnar's avatar Ingo Molnar

x86: make io_apic_32.c the same as io_apic_64.c

Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 047c8fdb
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
#include <linux/htirq.h> #include <linux/htirq.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/jiffies.h> /* time_after() */ #include <linux/jiffies.h> /* time_after() */
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
#include <acpi/acpi_bus.h> #include <acpi/acpi_bus.h>
#endif #endif
...@@ -64,8 +64,8 @@ ...@@ -64,8 +64,8 @@
#define __apicdebuginit(type) static type __init #define __apicdebuginit(type) static type __init
/* /*
* Is the SiS APIC rmw bug present ? * Is the SiS APIC rmw bug present ?
* -1 = don't know, 0 = no, 1 = yes * -1 = don't know, 0 = no, 1 = yes
*/ */
int sis_apic_bug = -1; int sis_apic_bug = -1;
...@@ -102,7 +102,7 @@ DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES); ...@@ -102,7 +102,7 @@ DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);
int skip_ioapic_setup; int skip_ioapic_setup;
static int __init parse_noapic(char *arg) static int __init parse_noapic(char *str)
{ {
/* disable IO-APIC */ /* disable IO-APIC */
disable_ioapic_setup(); disable_ioapic_setup();
...@@ -188,7 +188,7 @@ static void __init init_work(void *data) ...@@ -188,7 +188,7 @@ static void __init init_work(void *data)
irq_cfgx[legacy_count - 1].next = NULL; irq_cfgx[legacy_count - 1].next = NULL;
} }
#define for_each_irq_cfg(cfg) \ #define for_each_irq_cfg(cfg) \
for (cfg = irq_cfgx; cfg; cfg = cfg->next) for (cfg = irq_cfgx; cfg; cfg = cfg->next)
DEFINE_DYN_ARRAY(irq_cfgx, sizeof(struct irq_cfg), nr_irq_cfg, PAGE_SIZE, init_work); DEFINE_DYN_ARRAY(irq_cfgx, sizeof(struct irq_cfg), nr_irq_cfg, PAGE_SIZE, init_work);
...@@ -262,7 +262,6 @@ static struct irq_cfg *irq_cfg_alloc(unsigned int irq) ...@@ -262,7 +262,6 @@ static struct irq_cfg *irq_cfg_alloc(unsigned int irq)
irq_cfgx = cfg; irq_cfgx = cfg;
cfg->irq = irq; cfg->irq = irq;
printk(KERN_DEBUG "found new irq_cfg for irq %d\n", cfg->irq); printk(KERN_DEBUG "found new irq_cfg for irq %d\n", cfg->irq);
#ifdef CONFIG_HAVE_SPARSE_IRQ_DEBUG #ifdef CONFIG_HAVE_SPARSE_IRQ_DEBUG
{ {
/* dump the results */ /* dump the results */
...@@ -384,9 +383,9 @@ static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned i ...@@ -384,9 +383,9 @@ static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned i
*/ */
static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value) static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
{ {
volatile struct io_apic __iomem *io_apic = io_apic_base(apic); struct io_apic __iomem *io_apic = io_apic_base(apic);
if (sis_apic_bug) if (sis_apic_bug)
writel(reg, &io_apic->index); writel(reg, &io_apic->index);
writel(value, &io_apic->data); writel(value, &io_apic->data);
} }
...@@ -494,11 +493,20 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector) ...@@ -494,11 +493,20 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector)
apic = entry->apic; apic = entry->apic;
pin = entry->pin; pin = entry->pin;
#ifdef CONFIG_INTR_REMAP
/*
* With interrupt-remapping, destination information comes
* from interrupt-remapping table entry.
*/
if (!irq_remapped(irq))
io_apic_write(apic, 0x11 + pin*2, dest);
#else
io_apic_write(apic, 0x11 + pin*2, dest); io_apic_write(apic, 0x11 + pin*2, dest);
#endif
reg = io_apic_read(apic, 0x10 + pin*2); reg = io_apic_read(apic, 0x10 + pin*2);
reg &= ~IO_APIC_REDIR_VECTOR_MASK; reg &= ~IO_APIC_REDIR_VECTOR_MASK;
reg |= vector; reg |= vector;
io_apic_modify(apic, 0x10 + pin *2, reg); io_apic_modify(apic, 0x10 + pin*2, reg);
if (!entry->next) if (!entry->next)
break; break;
entry = entry->next; entry = entry->next;
...@@ -513,6 +521,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) ...@@ -513,6 +521,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
unsigned long flags; unsigned long flags;
unsigned int dest; unsigned int dest;
cpumask_t tmp; cpumask_t tmp;
struct irq_desc *desc;
cpus_and(tmp, mask, cpu_online_map); cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp)) if (cpus_empty(tmp))
...@@ -529,12 +538,12 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) ...@@ -529,12 +538,12 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
*/ */
dest = SET_APIC_LOGICAL_ID(dest); dest = SET_APIC_LOGICAL_ID(dest);
desc = irq_to_desc(irq);
spin_lock_irqsave(&ioapic_lock, flags); spin_lock_irqsave(&ioapic_lock, flags);
__target_IO_APIC_irq(irq, dest, cfg->vector); __target_IO_APIC_irq(irq, dest, cfg->vector);
irq_to_desc(irq)->affinity = mask; desc->affinity = mask;
spin_unlock_irqrestore(&ioapic_lock, flags); spin_unlock_irqrestore(&ioapic_lock, flags);
} }
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
/* /*
...@@ -699,7 +708,7 @@ static void __unmask_and_level_IO_APIC_irq(unsigned int irq) ...@@ -699,7 +708,7 @@ static void __unmask_and_level_IO_APIC_irq(unsigned int irq)
#endif #endif
static void mask_IO_APIC_irq(unsigned int irq) static void mask_IO_APIC_irq (unsigned int irq)
{ {
unsigned long flags; unsigned long flags;
...@@ -708,7 +717,7 @@ static void mask_IO_APIC_irq(unsigned int irq) ...@@ -708,7 +717,7 @@ static void mask_IO_APIC_irq(unsigned int irq)
spin_unlock_irqrestore(&ioapic_lock, flags); spin_unlock_irqrestore(&ioapic_lock, flags);
} }
static void unmask_IO_APIC_irq(unsigned int irq) static void unmask_IO_APIC_irq (unsigned int irq)
{ {
unsigned long flags; unsigned long flags;
...@@ -725,14 +734,13 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) ...@@ -725,14 +734,13 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
entry = ioapic_read_entry(apic, pin); entry = ioapic_read_entry(apic, pin);
if (entry.delivery_mode == dest_SMI) if (entry.delivery_mode == dest_SMI)
return; return;
/* /*
* Disable it in the IO-APIC irq-routing table: * Disable it in the IO-APIC irq-routing table:
*/ */
ioapic_mask_entry(apic, pin); ioapic_mask_entry(apic, pin);
} }
static void clear_IO_APIC(void) static void clear_IO_APIC (void)
{ {
int apic, pin; int apic, pin;
...@@ -741,7 +749,7 @@ static void clear_IO_APIC(void) ...@@ -741,7 +749,7 @@ static void clear_IO_APIC(void)
clear_IO_APIC_pin(apic, pin); clear_IO_APIC_pin(apic, pin);
} }
#ifndef CONFIG_SMP #if !defined(CONFIG_SMP) && defined(CONFIG_X86_32)
void send_IPI_self(int vector) void send_IPI_self(int vector)
{ {
unsigned int cfg; unsigned int cfg;
...@@ -756,9 +764,9 @@ void send_IPI_self(int vector) ...@@ -756,9 +764,9 @@ void send_IPI_self(int vector)
*/ */
apic_write(APIC_ICR, cfg); apic_write(APIC_ICR, cfg);
} }
#endif /* !CONFIG_SMP */ #endif /* !CONFIG_SMP && CONFIG_X86_32*/
#ifdef CONFIG_X86_32
/* /*
* support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to
* specific CPU-side IRQs. * specific CPU-side IRQs.
...@@ -797,6 +805,75 @@ static int __init ioapic_pirq_setup(char *str) ...@@ -797,6 +805,75 @@ static int __init ioapic_pirq_setup(char *str)
} }
__setup("pirq=", ioapic_pirq_setup); __setup("pirq=", ioapic_pirq_setup);
#endif /* CONFIG_X86_32 */
#ifdef CONFIG_INTR_REMAP
/* I/O APIC RTE contents at the OS boot up */
static struct IO_APIC_route_entry *early_ioapic_entries[MAX_IO_APICS];
/*
* Saves and masks all the unmasked IO-APIC RTE's
*/
int save_mask_IO_APIC_setup(void)
{
union IO_APIC_reg_01 reg_01;
unsigned long flags;
int apic, pin;
/*
* The number of IO-APIC IRQ registers (== #pins):
*/
for (apic = 0; apic < nr_ioapics; apic++) {
spin_lock_irqsave(&ioapic_lock, flags);
reg_01.raw = io_apic_read(apic, 1);
spin_unlock_irqrestore(&ioapic_lock, flags);
nr_ioapic_registers[apic] = reg_01.bits.entries+1;
}
for (apic = 0; apic < nr_ioapics; apic++) {
early_ioapic_entries[apic] =
kzalloc(sizeof(struct IO_APIC_route_entry) *
nr_ioapic_registers[apic], GFP_KERNEL);
if (!early_ioapic_entries[apic])
return -ENOMEM;
}
for (apic = 0; apic < nr_ioapics; apic++)
for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
struct IO_APIC_route_entry entry;
entry = early_ioapic_entries[apic][pin] =
ioapic_read_entry(apic, pin);
if (!entry.mask) {
entry.mask = 1;
ioapic_write_entry(apic, pin, entry);
}
}
return 0;
}
void restore_IO_APIC_setup(void)
{
int apic, pin;
for (apic = 0; apic < nr_ioapics; apic++)
for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
ioapic_write_entry(apic, pin,
early_ioapic_entries[apic][pin]);
}
void reinit_intr_remapped_IO_APIC(int intr_remapping)
{
/*
* 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();
}
#endif
/* /*
* Find the IRQ entry number of a certain pin. * Find the IRQ entry number of a certain pin.
...@@ -848,7 +925,7 @@ static int __init find_isa_irq_apic(int irq, int type) ...@@ -848,7 +925,7 @@ static int __init find_isa_irq_apic(int irq, int type)
} }
if (i < mp_irq_entries) { if (i < mp_irq_entries) {
int apic; int apic;
for (apic = 0; apic < nr_ioapics; apic++) { for(apic = 0; apic < nr_ioapics; apic++) {
if (mp_ioapics[apic].mp_apicid == mp_irqs[i].mp_dstapic) if (mp_ioapics[apic].mp_apicid == mp_irqs[i].mp_dstapic)
return apic; return apic;
} }
...@@ -867,10 +944,10 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) ...@@ -867,10 +944,10 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
{ {
int apic, i, best_guess = -1; int apic, i, best_guess = -1;
apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, " apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
"slot:%d, pin:%d.\n", bus, slot, pin); bus, slot, pin);
if (test_bit(bus, mp_bus_not_pci)) { if (test_bit(bus, mp_bus_not_pci)) {
printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus); apic_printk(APIC_VERBOSE, "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
return -1; return -1;
} }
for (i = 0; i < mp_irq_entries; i++) { for (i = 0; i < mp_irq_entries; i++) {
...@@ -885,7 +962,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) ...@@ -885,7 +962,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
!mp_irqs[i].mp_irqtype && !mp_irqs[i].mp_irqtype &&
(bus == lbus) && (bus == lbus) &&
(slot == ((mp_irqs[i].mp_srcbusirq >> 2) & 0x1f))) { (slot == ((mp_irqs[i].mp_srcbusirq >> 2) & 0x1f))) {
int irq = pin_2_irq(i, apic, mp_irqs[i].mp_dstirq); int irq = pin_2_irq(i,apic,mp_irqs[i].mp_dstirq);
if (!(apic || IO_APIC_IRQ(irq))) if (!(apic || IO_APIC_IRQ(irq)))
continue; continue;
...@@ -902,6 +979,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) ...@@ -902,6 +979,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
} }
return best_guess; return best_guess;
} }
EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector); EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
#if defined(CONFIG_EISA) || defined(CONFIG_MCA) #if defined(CONFIG_EISA) || defined(CONFIG_MCA)
...@@ -918,6 +996,7 @@ static int EISA_ELCR(unsigned int irq) ...@@ -918,6 +996,7 @@ static int EISA_ELCR(unsigned int irq)
"Broken MPtable reports ISA irq %d\n", irq); "Broken MPtable reports ISA irq %d\n", irq);
return 0; return 0;
} }
#endif #endif
/* ISA interrupts are always polarity zero edge triggered, /* ISA interrupts are always polarity zero edge triggered,
...@@ -954,36 +1033,36 @@ static int MPBIOS_polarity(int idx) ...@@ -954,36 +1033,36 @@ static int MPBIOS_polarity(int idx)
/* /*
* Determine IRQ line polarity (high active or low active): * Determine IRQ line polarity (high active or low active):
*/ */
switch (mp_irqs[idx].mp_irqflag & 3) { switch (mp_irqs[idx].mp_irqflag & 3)
case 0: /* conforms, ie. bus-type dependent polarity */
{
polarity = test_bit(bus, mp_bus_not_pci)?
default_ISA_polarity(idx):
default_PCI_polarity(idx);
break;
}
case 1: /* high active */
{
polarity = 0;
break;
}
case 2: /* reserved */
{
printk(KERN_WARNING "broken BIOS!!\n");
polarity = 1;
break;
}
case 3: /* low active */
{
polarity = 1;
break;
}
default: /* invalid */
{ {
printk(KERN_WARNING "broken BIOS!!\n"); case 0: /* conforms, ie. bus-type dependent polarity */
polarity = 1; if (test_bit(bus, mp_bus_not_pci))
break; polarity = default_ISA_polarity(idx);
} else
polarity = default_PCI_polarity(idx);
break;
case 1: /* high active */
{
polarity = 0;
break;
}
case 2: /* reserved */
{
printk(KERN_WARNING "broken BIOS!!\n");
polarity = 1;
break;
}
case 3: /* low active */
{
polarity = 1;
break;
}
default: /* invalid */
{
printk(KERN_WARNING "broken BIOS!!\n");
polarity = 1;
break;
}
} }
return polarity; return polarity;
} }
...@@ -996,67 +1075,67 @@ static int MPBIOS_trigger(int idx) ...@@ -996,67 +1075,67 @@ static int MPBIOS_trigger(int idx)
/* /*
* Determine IRQ trigger mode (edge or level sensitive): * Determine IRQ trigger mode (edge or level sensitive):
*/ */
switch ((mp_irqs[idx].mp_irqflag>>2) & 3) { switch ((mp_irqs[idx].mp_irqflag>>2) & 3)
case 0: /* conforms, ie. bus-type dependent */
{ {
trigger = test_bit(bus, mp_bus_not_pci)? case 0: /* conforms, ie. bus-type dependent */
default_ISA_trigger(idx): if (test_bit(bus, mp_bus_not_pci))
default_PCI_trigger(idx); trigger = default_ISA_trigger(idx);
else
trigger = default_PCI_trigger(idx);
#if defined(CONFIG_EISA) || defined(CONFIG_MCA) #if defined(CONFIG_EISA) || defined(CONFIG_MCA)
switch (mp_bus_id_to_type[bus]) { switch (mp_bus_id_to_type[bus]) {
case MP_BUS_ISA: /* ISA pin */ case MP_BUS_ISA: /* ISA pin */
{ {
/* set before the switch */ /* set before the switch */
break;
}
case MP_BUS_EISA: /* EISA pin */
{
trigger = default_EISA_trigger(idx);
break;
}
case MP_BUS_PCI: /* PCI pin */
{
/* set before the switch */
break;
}
case MP_BUS_MCA: /* MCA pin */
{
trigger = default_MCA_trigger(idx);
break;
}
default:
{
printk(KERN_WARNING "broken BIOS!!\n");
trigger = 1;
break;
}
}
#endif
break; break;
} case 1: /* edge */
case MP_BUS_EISA: /* EISA pin */
{ {
trigger = default_EISA_trigger(idx); trigger = 0;
break; break;
} }
case MP_BUS_PCI: /* PCI pin */ case 2: /* reserved */
{ {
/* set before the switch */ printk(KERN_WARNING "broken BIOS!!\n");
trigger = 1;
break; break;
} }
case MP_BUS_MCA: /* MCA pin */ case 3: /* level */
{ {
trigger = default_MCA_trigger(idx); trigger = 1;
break; break;
} }
default: default: /* invalid */
{ {
printk(KERN_WARNING "broken BIOS!!\n"); printk(KERN_WARNING "broken BIOS!!\n");
trigger = 1; trigger = 0;
break; break;
} }
} }
#endif
break;
}
case 1: /* edge */
{
trigger = 0;
break;
}
case 2: /* reserved */
{
printk(KERN_WARNING "broken BIOS!!\n");
trigger = 1;
break;
}
case 3: /* level */
{
trigger = 1;
break;
}
default: /* invalid */
{
printk(KERN_WARNING "broken BIOS!!\n");
trigger = 0;
break;
}
}
return trigger; return trigger;
} }
...@@ -1082,9 +1161,9 @@ static int pin_2_irq(int idx, int apic, int pin) ...@@ -1082,9 +1161,9 @@ static int pin_2_irq(int idx, int apic, int pin)
if (mp_irqs[idx].mp_dstirq != pin) if (mp_irqs[idx].mp_dstirq != pin)
printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n"); printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n");
if (test_bit(bus, mp_bus_not_pci)) if (test_bit(bus, mp_bus_not_pci)) {
irq = mp_irqs[idx].mp_srcbusirq; irq = mp_irqs[idx].mp_srcbusirq;
else { } else {
/* /*
* PCI IRQs are mapped in order * PCI IRQs are mapped in order
*/ */
...@@ -1092,14 +1171,14 @@ static int pin_2_irq(int idx, int apic, int pin) ...@@ -1092,14 +1171,14 @@ static int pin_2_irq(int idx, int apic, int pin)
while (i < apic) while (i < apic)
irq += nr_ioapic_registers[i++]; irq += nr_ioapic_registers[i++];
irq += pin; irq += pin;
/*
/* * For MPS mode, so far only needed by ES7000 platform
* For MPS mode, so far only needed by ES7000 platform */
*/ if (ioapic_renumber_irq)
if (ioapic_renumber_irq) irq = ioapic_renumber_irq(apic, irq);
irq = ioapic_renumber_irq(apic, irq);
} }
#ifdef CONFIG_X86_32
/* /*
* PCI IRQ command line redirection. Yes, limits are hardcoded. * PCI IRQ command line redirection. Yes, limits are hardcoded.
*/ */
...@@ -1116,6 +1195,8 @@ static int pin_2_irq(int idx, int apic, int pin) ...@@ -1116,6 +1195,8 @@ static int pin_2_irq(int idx, int apic, int pin)
} }
} }
} }
#endif
return irq; return irq;
} }
...@@ -1145,74 +1226,70 @@ static int __assign_irq_vector(int irq, cpumask_t mask) ...@@ -1145,74 +1226,70 @@ static int __assign_irq_vector(int irq, cpumask_t mask)
* Also, we've got to be careful not to trash gate * Also, we've got to be careful not to trash gate
* 0x80, because int 0x80 is hm, kind of importantish. ;) * 0x80, because int 0x80 is hm, kind of importantish. ;)
*/ */
static int current_vector = FIRST_DEVICE_VECTOR, current_offset = 0; static int current_vector = FIRST_DEVICE_VECTOR, current_offset = 0;
unsigned int old_vector; unsigned int old_vector;
int cpu; int cpu;
struct irq_cfg *cfg; struct irq_cfg *cfg;
cfg = irq_cfg(irq); cfg = irq_cfg(irq);
/* Only try and allocate irqs on cpus that are present */ /* Only try and allocate irqs on cpus that are present */
cpus_and(mask, mask, cpu_online_map); cpus_and(mask, mask, cpu_online_map);
if ((cfg->move_in_progress) || cfg->move_cleanup_count) if ((cfg->move_in_progress) || cfg->move_cleanup_count)
return -EBUSY; return -EBUSY;
old_vector = cfg->vector; old_vector = cfg->vector;
if (old_vector) { if (old_vector) {
cpumask_t tmp; cpumask_t tmp;
cpus_and(tmp, cfg->domain, mask); cpus_and(tmp, cfg->domain, mask);
if (!cpus_empty(tmp)) if (!cpus_empty(tmp))
return 0; return 0;
} }
for_each_cpu_mask_nr(cpu, mask) { for_each_cpu_mask_nr(cpu, mask) {
cpumask_t domain, new_mask; cpumask_t domain, new_mask;
int new_cpu; int new_cpu;
int vector, offset; int vector, offset;
domain = vector_allocation_domain(cpu); domain = vector_allocation_domain(cpu);
cpus_and(new_mask, domain, cpu_online_map); cpus_and(new_mask, domain, cpu_online_map);
vector = current_vector; vector = current_vector;
offset = current_offset; offset = current_offset;
next: next:
vector += 8; vector += 8;
if (vector >= first_system_vector) { if (vector >= first_system_vector) {
/* If we run out of vectors on large boxen, must share them. */ /* If we run out of vectors on large boxen, must share them. */
offset = (offset + 1) % 8; offset = (offset + 1) % 8;
vector = FIRST_DEVICE_VECTOR + offset; vector = FIRST_DEVICE_VECTOR + offset;
} }
if (unlikely(current_vector == vector)) if (unlikely(current_vector == vector))
continue; continue;
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
if (vector == IA32_SYSCALL_VECTOR) if (vector == IA32_SYSCALL_VECTOR)
goto next; goto next;
#else #else
if (vector == SYSCALL_VECTOR) if (vector == SYSCALL_VECTOR)
goto next; goto next;
#endif #endif
for_each_cpu_mask_nr(new_cpu, new_mask) for_each_cpu_mask_nr(new_cpu, new_mask)
if (per_cpu(vector_irq, new_cpu)[vector] != -1) if (per_cpu(vector_irq, new_cpu)[vector] != -1)
goto next; goto next;
/* Found one! */ /* Found one! */
current_vector = vector; current_vector = vector;
current_offset = offset; current_offset = offset;
if (old_vector) { if (old_vector) {
cfg->move_in_progress = 1; cfg->move_in_progress = 1;
cfg->old_domain = cfg->domain; cfg->old_domain = cfg->domain;
}
printk(KERN_DEBUG "assign_irq_vector: irq %d vector %#x cpu ", irq, vector);
for_each_cpu_mask_nr(new_cpu, new_mask) {
per_cpu(vector_irq, new_cpu)[vector] = irq;
printk(KERN_CONT " %d ", new_cpu);
} }
printk(KERN_CONT "\n"); for_each_cpu_mask_nr(new_cpu, new_mask)
cfg->vector = vector; per_cpu(vector_irq, new_cpu)[vector] = irq;
cfg->domain = domain; cfg->vector = vector;
return 0; cfg->domain = domain;
} return 0;
return -ENOSPC; }
return -ENOSPC;
} }
static int assign_irq_vector(int irq, cpumask_t mask) static int assign_irq_vector(int irq, cpumask_t mask)
...@@ -1223,7 +1300,6 @@ static int assign_irq_vector(int irq, cpumask_t mask) ...@@ -1223,7 +1300,6 @@ static int assign_irq_vector(int irq, cpumask_t mask)
spin_lock_irqsave(&vector_lock, flags); spin_lock_irqsave(&vector_lock, flags);
err = __assign_irq_vector(irq, mask); err = __assign_irq_vector(irq, mask);
spin_unlock_irqrestore(&vector_lock, flags); spin_unlock_irqrestore(&vector_lock, flags);
return err; return err;
} }
...@@ -1269,36 +1345,39 @@ void __setup_vector_irq(int cpu) ...@@ -1269,36 +1345,39 @@ void __setup_vector_irq(int cpu)
cfg = irq_cfg(irq); cfg = irq_cfg(irq);
if (!cpu_isset(cpu, cfg->domain)) if (!cpu_isset(cpu, cfg->domain))
per_cpu(vector_irq, cpu)[vector] = -1; per_cpu(vector_irq, cpu)[vector] = -1;
} }
} }
static struct irq_chip ioapic_chip; static struct irq_chip ioapic_chip;
#ifdef CONFIG_INTR_REMAP
static struct irq_chip ir_ioapic_chip;
#endif
#define IOAPIC_AUTO -1 #define IOAPIC_AUTO -1
#define IOAPIC_EDGE 0 #define IOAPIC_EDGE 0
#define IOAPIC_LEVEL 1 #define IOAPIC_LEVEL 1
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
static inline int IO_APIC_irq_trigger(int irq) static inline int IO_APIC_irq_trigger(int irq)
{ {
int apic, idx, pin; int apic, idx, pin;
for (apic = 0; apic < nr_ioapics; apic++) { for (apic = 0; apic < nr_ioapics; apic++) {
for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
idx = find_irq_entry(apic, pin, mp_INT); idx = find_irq_entry(apic, pin, mp_INT);
if ((idx != -1) && (irq == pin_2_irq(idx, apic, pin))) if ((idx != -1) && (irq == pin_2_irq(idx, apic, pin)))
return irq_trigger(idx); return irq_trigger(idx);
} }
} }
/* /*
* nonexistent IRQs are edge default * nonexistent IRQs are edge default
*/ */
return 0; return 0;
} }
#else #else
static inline int IO_APIC_irq_trigger(int irq) static inline int IO_APIC_irq_trigger(int irq)
{ {
return 1; return 1;
} }
#endif #endif
...@@ -1318,13 +1397,27 @@ static void ioapic_register_intr(int irq, unsigned long trigger) ...@@ -1318,13 +1397,27 @@ static void ioapic_register_intr(int irq, unsigned long trigger)
else else
desc->status &= ~IRQ_LEVEL; desc->status &= ~IRQ_LEVEL;
#ifdef CONFIG_INTR_REMAP
if (irq_remapped(irq)) {
desc->status |= IRQ_MOVE_PCNTXT;
if (trigger)
set_irq_chip_and_handler_name(irq, &ir_ioapic_chip,
handle_fasteoi_irq,
"fasteoi");
else
set_irq_chip_and_handler_name(irq, &ir_ioapic_chip,
handle_edge_irq, "edge");
return;
}
#endif
if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
trigger == IOAPIC_LEVEL) trigger == IOAPIC_LEVEL)
set_irq_chip_and_handler_name(irq, &ioapic_chip, set_irq_chip_and_handler_name(irq, &ioapic_chip,
handle_fasteoi_irq, "fasteoi"); handle_fasteoi_irq,
"fasteoi");
else else
set_irq_chip_and_handler_name(irq, &ioapic_chip, set_irq_chip_and_handler_name(irq, &ioapic_chip,
handle_edge_irq, "edge"); handle_edge_irq, "edge");
} }
static int setup_ioapic_entry(int apic, int irq, static int setup_ioapic_entry(int apic, int irq,
...@@ -1337,11 +1430,45 @@ static int setup_ioapic_entry(int apic, int irq, ...@@ -1337,11 +1430,45 @@ static int setup_ioapic_entry(int apic, int irq,
*/ */
memset(entry,0,sizeof(*entry)); memset(entry,0,sizeof(*entry));
entry->delivery_mode = INT_DELIVERY_MODE; #ifdef CONFIG_INTR_REMAP
entry->dest_mode = INT_DEST_MODE; if (intr_remapping_enabled) {
entry->dest = destination; struct intel_iommu *iommu = map_ioapic_to_ir(apic);
struct irte irte;
struct IR_IO_APIC_route_entry *ir_entry =
(struct IR_IO_APIC_route_entry *) entry;
int index;
if (!iommu)
panic("No mapping iommu for ioapic %d\n", apic);
index = alloc_irte(iommu, irq, 1);
if (index < 0)
panic("Failed to allocate IRTE for ioapic %d\n", apic);
memset(&irte, 0, sizeof(irte));
irte.present = 1;
irte.dst_mode = INT_DEST_MODE;
irte.trigger_mode = trigger;
irte.dlvry_mode = INT_DELIVERY_MODE;
irte.vector = vector;
irte.dest_id = IRTE_DEST(destination);
modify_irte(irq, &irte);
ir_entry->index2 = (index >> 15) & 0x1;
ir_entry->zero = 0;
ir_entry->format = 1;
ir_entry->index = (index & 0x7fff);
} else
#endif
{
entry->delivery_mode = INT_DELIVERY_MODE;
entry->dest_mode = INT_DEST_MODE;
entry->dest = destination;
}
entry->mask = 0; /* enable IRQ */ entry->mask = 0; /* enable IRQ */
entry->trigger = trigger; entry->trigger = trigger;
entry->polarity = polarity; entry->polarity = polarity;
entry->vector = vector; entry->vector = vector;
...@@ -1351,12 +1478,11 @@ static int setup_ioapic_entry(int apic, int irq, ...@@ -1351,12 +1478,11 @@ static int setup_ioapic_entry(int apic, int irq,
*/ */
if (trigger) if (trigger)
entry->mask = 1; entry->mask = 1;
return 0; return 0;
} }
static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq, static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq,
int trigger, int polarity) int trigger, int polarity)
{ {
struct irq_cfg *cfg; struct irq_cfg *cfg;
struct IO_APIC_route_entry entry; struct IO_APIC_route_entry entry;
...@@ -1420,10 +1546,10 @@ static void __init setup_IO_APIC_irqs(void) ...@@ -1420,10 +1546,10 @@ static void __init setup_IO_APIC_irqs(void)
} }
irq = pin_2_irq(idx, apic, pin); irq = pin_2_irq(idx, apic, pin);
#ifdef CONFIG_X86_32
if (multi_timer_check(apic, irq)) if (multi_timer_check(apic, irq))
continue; continue;
#endif
add_pin_to_irq(irq, apic, pin); add_pin_to_irq(irq, apic, pin);
setup_IO_APIC_irq(apic, pin, irq, setup_IO_APIC_irq(apic, pin, irq,
...@@ -1443,6 +1569,11 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic, unsigned int pin, ...@@ -1443,6 +1569,11 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic, unsigned int pin,
{ {
struct IO_APIC_route_entry entry; struct IO_APIC_route_entry entry;
#ifdef CONFIG_INTR_REMAP
if (intr_remapping_enabled)
return;
#endif
memset(&entry, 0, sizeof(entry)); memset(&entry, 0, sizeof(entry));
/* /*
...@@ -1461,7 +1592,7 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic, unsigned int pin, ...@@ -1461,7 +1592,7 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic, unsigned int pin,
* The timer IRQ doesn't have to know that behind the * The timer IRQ doesn't have to know that behind the
* scene we may have a 8259A-master in AEOI mode ... * scene we may have a 8259A-master in AEOI mode ...
*/ */
ioapic_register_intr(0, IOAPIC_EDGE); set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge");
/* /*
* Add it to the IO-APIC irq-routing table: * Add it to the IO-APIC irq-routing table:
...@@ -1501,17 +1632,18 @@ __apicdebuginit(void) print_IO_APIC(void) ...@@ -1501,17 +1632,18 @@ __apicdebuginit(void) print_IO_APIC(void)
reg_01.raw = io_apic_read(apic, 1); reg_01.raw = io_apic_read(apic, 1);
if (reg_01.bits.version >= 0x10) if (reg_01.bits.version >= 0x10)
reg_02.raw = io_apic_read(apic, 2); reg_02.raw = io_apic_read(apic, 2);
if (reg_01.bits.version >= 0x20) if (reg_01.bits.version >= 0x20)
reg_03.raw = io_apic_read(apic, 3); reg_03.raw = io_apic_read(apic, 3);
spin_unlock_irqrestore(&ioapic_lock, flags); spin_unlock_irqrestore(&ioapic_lock, flags);
printk("\n");
printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mp_apicid); 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 ".... register #00: %08X\n", reg_00.raw);
printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID); 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 "....... : Delivery Type: %X\n", reg_00.bits.delivery_type);
printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.bits.LTS); printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.bits.LTS);
printk(KERN_DEBUG ".... register #01: %08X\n", reg_01.raw); printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)&reg_01);
printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries); printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries);
printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ); printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ);
...@@ -1548,7 +1680,10 @@ __apicdebuginit(void) print_IO_APIC(void) ...@@ -1548,7 +1680,10 @@ __apicdebuginit(void) print_IO_APIC(void)
entry = ioapic_read_entry(apic, i); entry = ioapic_read_entry(apic, i);
printk(KERN_DEBUG " %02x %02X ", i, entry.dest); printk(KERN_DEBUG " %02x %03X ",
i,
entry.dest
);
printk("%1d %1d %1d %1d %1d %1d %1d %02X\n", printk("%1d %1d %1d %1d %1d %1d %1d %02X\n",
entry.mask, entry.mask,
...@@ -1567,7 +1702,7 @@ __apicdebuginit(void) print_IO_APIC(void) ...@@ -1567,7 +1702,7 @@ __apicdebuginit(void) print_IO_APIC(void)
struct irq_pin_list *entry = cfg->irq_2_pin; struct irq_pin_list *entry = cfg->irq_2_pin;
if (!entry) if (!entry)
continue; continue;
printk(KERN_DEBUG "IRQ%d ", i); printk(KERN_DEBUG "IRQ%d ", cfg->irq);
for (;;) { for (;;) {
printk("-> %d:%d", entry->apic, entry->pin); printk("-> %d:%d", entry->apic, entry->pin);
if (!entry->next) if (!entry->next)
...@@ -1614,8 +1749,7 @@ __apicdebuginit(void) print_local_APIC(void *dummy) ...@@ -1614,8 +1749,7 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n", printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
smp_processor_id(), hard_smp_processor_id()); smp_processor_id(), hard_smp_processor_id());
v = apic_read(APIC_ID); v = apic_read(APIC_ID);
printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, read_apic_id());
GET_APIC_ID(v));
v = apic_read(APIC_LVR); v = apic_read(APIC_LVR);
printk(KERN_INFO "... APIC VERSION: %08x\n", v); printk(KERN_INFO "... APIC VERSION: %08x\n", v);
ver = GET_APIC_VERSION(v); ver = GET_APIC_VERSION(v);
...@@ -1624,7 +1758,7 @@ __apicdebuginit(void) print_local_APIC(void *dummy) ...@@ -1624,7 +1758,7 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
v = apic_read(APIC_TASKPRI); v = apic_read(APIC_TASKPRI);
printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK); printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);
if (APIC_INTEGRATED(ver)) { /* !82489DX */ if (APIC_INTEGRATED(ver)) { /* !82489DX */
v = apic_read(APIC_ARBPRI); v = apic_read(APIC_ARBPRI);
printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v, printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v,
v & APIC_ARBPRI_MASK); v & APIC_ARBPRI_MASK);
...@@ -1650,9 +1784,10 @@ __apicdebuginit(void) print_local_APIC(void *dummy) ...@@ -1650,9 +1784,10 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
printk(KERN_DEBUG "... APIC IRR field:\n"); printk(KERN_DEBUG "... APIC IRR field:\n");
print_APIC_bitfield(APIC_IRR); print_APIC_bitfield(APIC_IRR);
if (APIC_INTEGRATED(ver)) { /* !82489DX */ if (APIC_INTEGRATED(ver)) { /* !82489DX */
if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
apic_write(APIC_ESR, 0); apic_write(APIC_ESR, 0);
v = apic_read(APIC_ESR); v = apic_read(APIC_ESR);
printk(KERN_DEBUG "... APIC ESR: %08x\n", v); printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
} }
...@@ -1710,11 +1845,11 @@ __apicdebuginit(void) print_PIC(void) ...@@ -1710,11 +1845,11 @@ __apicdebuginit(void) print_PIC(void)
v = inb(0xa0) << 8 | inb(0x20); v = inb(0xa0) << 8 | inb(0x20);
printk(KERN_DEBUG "... PIC IRR: %04x\n", v); printk(KERN_DEBUG "... PIC IRR: %04x\n", v);
outb(0x0b, 0xa0); outb(0x0b,0xa0);
outb(0x0b, 0x20); outb(0x0b,0x20);
v = inb(0xa0) << 8 | inb(0x20); v = inb(0xa0) << 8 | inb(0x20);
outb(0x0a, 0xa0); outb(0x0a,0xa0);
outb(0x0a, 0x20); outb(0x0a,0x20);
spin_unlock_irqrestore(&i8259A_lock, flags); spin_unlock_irqrestore(&i8259A_lock, flags);
...@@ -1739,16 +1874,19 @@ fs_initcall(print_all_ICs); ...@@ -1739,16 +1874,19 @@ fs_initcall(print_all_ICs);
/* Where if anywhere is the i8259 connect in external int mode */ /* Where if anywhere is the i8259 connect in external int mode */
static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
static void __init enable_IO_APIC(void) void __init enable_IO_APIC(void)
{ {
union IO_APIC_reg_01 reg_01; union IO_APIC_reg_01 reg_01;
int i8259_apic, i8259_pin; int i8259_apic, i8259_pin;
int i, apic; int apic;
unsigned long flags; unsigned long flags;
#ifdef CONFIG_X86_32
int i;
if (!pirqs_enabled) if (!pirqs_enabled)
for (i = 0; i < MAX_PIRQS; i++) for (i = 0; i < MAX_PIRQS; i++)
pirq_entries[i] = -1; pirq_entries[i] = -1;
#endif
/* /*
* The number of IO-APIC IRQ registers (== #pins): * The number of IO-APIC IRQ registers (== #pins):
...@@ -1759,7 +1897,7 @@ static void __init enable_IO_APIC(void) ...@@ -1759,7 +1897,7 @@ static void __init enable_IO_APIC(void)
spin_unlock_irqrestore(&ioapic_lock, flags); spin_unlock_irqrestore(&ioapic_lock, flags);
nr_ioapic_registers[apic] = reg_01.bits.entries+1; nr_ioapic_registers[apic] = reg_01.bits.entries+1;
} }
for (apic = 0; apic < nr_ioapics; apic++) { for(apic = 0; apic < nr_ioapics; apic++) {
int pin; int pin;
/* See if any of the pins is in ExtINT mode */ /* See if any of the pins is in ExtINT mode */
for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
...@@ -1830,16 +1968,18 @@ void disable_IO_APIC(void) ...@@ -1830,16 +1968,18 @@ void disable_IO_APIC(void)
entry.dest_mode = 0; /* Physical */ entry.dest_mode = 0; /* Physical */
entry.delivery_mode = dest_ExtINT; /* ExtInt */ entry.delivery_mode = dest_ExtINT; /* ExtInt */
entry.vector = 0; entry.vector = 0;
entry.dest = read_apic_id(); entry.dest = read_apic_id();
/* /*
* Add it to the IO-APIC irq-routing table: * Add it to the IO-APIC irq-routing table:
*/ */
ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry); ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry);
} }
disconnect_bsp_APIC(ioapic_i8259.pin != -1); disconnect_bsp_APIC(ioapic_i8259.pin != -1);
} }
#ifdef CONFIG_X86_32
/* /*
* function to set the IO-APIC physical IDs based on the * function to set the IO-APIC physical IDs based on the
* values stored in the MPC table. * values stored in the MPC table.
...@@ -1940,8 +2080,6 @@ static void __init setup_ioapic_ids_from_mpc(void) ...@@ -1940,8 +2080,6 @@ static void __init setup_ioapic_ids_from_mpc(void)
reg_00.bits.ID = mp_ioapics[apic].mp_apicid; reg_00.bits.ID = mp_ioapics[apic].mp_apicid;
spin_lock_irqsave(&ioapic_lock, flags); spin_lock_irqsave(&ioapic_lock, flags);
io_apic_write(apic, 0, reg_00.raw);
spin_unlock_irqrestore(&ioapic_lock, flags);
/* /*
* Sanity check * Sanity check
...@@ -1955,6 +2093,7 @@ static void __init setup_ioapic_ids_from_mpc(void) ...@@ -1955,6 +2093,7 @@ static void __init setup_ioapic_ids_from_mpc(void)
apic_printk(APIC_VERBOSE, " ok.\n"); apic_printk(APIC_VERBOSE, " ok.\n");
} }
} }
#endif
int no_timer_check __initdata; int no_timer_check __initdata;
...@@ -1994,9 +2133,10 @@ static int __init timer_irq_works(void) ...@@ -1994,9 +2133,10 @@ static int __init timer_irq_works(void)
* might have cached one ExtINT interrupt. Finally, at * might have cached one ExtINT interrupt. Finally, at
* least one tick may be lost due to delays. * least one tick may be lost due to delays.
*/ */
/* jiffies wrap? */
if (time_after(jiffies, t1 + 4)) if (time_after(jiffies, t1 + 4))
return 1; return 1;
return 0; return 0;
} }
...@@ -2014,8 +2154,6 @@ static int __init timer_irq_works(void) ...@@ -2014,8 +2154,6 @@ static int __init timer_irq_works(void)
*/ */
/* /*
* Startup quirk:
*
* Starting up a edge-triggered IO-APIC interrupt is * Starting up a edge-triggered IO-APIC interrupt is
* nasty - we need to make sure that we get the edge. * nasty - we need to make sure that we get the edge.
* If it is already asserted for some reason, we need * If it is already asserted for some reason, we need
...@@ -2023,9 +2161,8 @@ static int __init timer_irq_works(void) ...@@ -2023,9 +2161,8 @@ static int __init timer_irq_works(void)
* *
* This is not complete - we should be able to fake * This is not complete - we should be able to fake
* an edge even if it isn't on the 8259A... * an edge even if it isn't on the 8259A...
*
* (We do this for level-triggered IRQs too - it cannot hurt.)
*/ */
static unsigned int startup_ioapic_irq(unsigned int irq) static unsigned int startup_ioapic_irq(unsigned int irq)
{ {
int was_pending = 0; int was_pending = 0;
...@@ -2043,70 +2180,254 @@ static unsigned int startup_ioapic_irq(unsigned int irq) ...@@ -2043,70 +2180,254 @@ static unsigned int startup_ioapic_irq(unsigned int irq)
return was_pending; return was_pending;
} }
#ifdef CONFIG_X86_64
static int ioapic_retrigger_irq(unsigned int irq) static int ioapic_retrigger_irq(unsigned int irq)
{ {
send_IPI_self(irq_cfg(irq)->vector);
struct irq_cfg *cfg = irq_cfg(irq);
unsigned long flags;
spin_lock_irqsave(&vector_lock, flags);
send_IPI_mask(cpumask_of_cpu(first_cpu(cfg->domain)), cfg->vector);
spin_unlock_irqrestore(&vector_lock, flags);
return 1; return 1;
} }
#else
#ifdef CONFIG_SMP static int ioapic_retrigger_irq(unsigned int irq)
asmlinkage void smp_irq_move_cleanup_interrupt(void)
{ {
unsigned vector, me; send_IPI_self(irq_cfg(irq)->vector);
ack_APIC_irq();
irq_enter();
me = smp_processor_id();
for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
unsigned int irq;
struct irq_desc *desc;
struct irq_cfg *cfg;
irq = __get_cpu_var(vector_irq)[vector];
desc = irq_to_desc(irq); return 1;
if (!desc) }
continue; #endif
cfg = irq_cfg(irq); /*
spin_lock(&desc->lock); * Level and edge triggered IO-APIC interrupts need different handling,
if (!cfg->move_cleanup_count) * so we use two separate IRQ descriptors. Edge triggered IRQs can be
goto unlock; * handled with the level-triggered descriptor, but that one has slightly
* more overhead. Level-triggered interrupts cannot be handled with the
* edge-triggered handler, without risking IRQ storms and other ugly
* races.
*/
if ((vector == cfg->vector) && cpu_isset(me, cfg->domain)) #ifdef CONFIG_SMP
goto unlock;
__get_cpu_var(vector_irq)[vector] = -1; #ifdef CONFIG_INTR_REMAP
cfg->move_cleanup_count--; static void ir_irq_migration(struct work_struct *work);
unlock:
spin_unlock(&desc->lock);
}
irq_exit(); static DECLARE_DELAYED_WORK(ir_migration_work, ir_irq_migration);
}
static void irq_complete_move(unsigned int irq) /*
* Migrate the IO-APIC irq in the presence of intr-remapping.
*
* For edge triggered, irq migration is a simple atomic update(of vector
* and cpu destination) of IRTE and flush the hardware cache.
*
* For level triggered, we need to modify the io-apic RTE aswell with the update
* vector information, along with modifying IRTE with vector and destination.
* So irq migration for level triggered is little bit more complex compared to
* edge triggered migration. But the good news is, we use the same algorithm
* for level triggered migration as we have today, only difference being,
* we now initiate the irq migration from process context instead of the
* interrupt context.
*
* In future, when we do a directed EOI (combined with cpu EOI broadcast
* suppression) to the IO-APIC, level triggered irq migration will also be
* as simple as edge triggered migration and we can do the irq migration
* with a simple atomic update to IO-APIC RTE.
*/
static void migrate_ioapic_irq(int irq, cpumask_t mask)
{ {
struct irq_cfg *cfg = irq_cfg(irq); struct irq_cfg *cfg;
unsigned vector, me; struct irq_desc *desc;
cpumask_t tmp, cleanup_mask;
struct irte irte;
int modify_ioapic_rte;
unsigned int dest;
unsigned long flags;
if (likely(!cfg->move_in_progress)) cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp))
return; return;
vector = ~get_irq_regs()->orig_ax; if (get_irte(irq, &irte))
me = smp_processor_id(); return;
if ((vector == cfg->vector) && cpu_isset(me, cfg->domain)) {
cpumask_t cleanup_mask;
cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map); if (assign_irq_vector(irq, mask))
cfg->move_cleanup_count = cpus_weight(cleanup_mask); return;
send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
cfg = irq_cfg(irq);
cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp);
desc = irq_to_desc(irq);
modify_ioapic_rte = desc->status & IRQ_LEVEL;
if (modify_ioapic_rte) {
spin_lock_irqsave(&ioapic_lock, flags);
__target_IO_APIC_irq(irq, dest, cfg->vector);
spin_unlock_irqrestore(&ioapic_lock, flags);
}
irte.vector = cfg->vector;
irte.dest_id = IRTE_DEST(dest);
/*
* Modified the IRTE and flushes the Interrupt entry cache.
*/
modify_irte(irq, &irte);
if (cfg->move_in_progress) {
cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
cfg->move_cleanup_count = cpus_weight(cleanup_mask);
send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
cfg->move_in_progress = 0;
}
desc->affinity = mask;
}
static int migrate_irq_remapped_level(int irq)
{
int ret = -1;
struct irq_desc *desc = irq_to_desc(irq);
mask_IO_APIC_irq(irq);
if (io_apic_level_ack_pending(irq)) {
/*
* Interrupt in progress. Migrating irq now will change the
* vector information in the IO-APIC RTE and that will confuse
* the EOI broadcast performed by cpu.
* So, delay the irq migration to the next instance.
*/
schedule_delayed_work(&ir_migration_work, 1);
goto unmask;
}
/* everthing is clear. we have right of way */
migrate_ioapic_irq(irq, desc->pending_mask);
ret = 0;
desc->status &= ~IRQ_MOVE_PENDING;
cpus_clear(desc->pending_mask);
unmask:
unmask_IO_APIC_irq(irq);
return ret;
}
static void ir_irq_migration(struct work_struct *work)
{
unsigned int irq;
struct irq_desc *desc;
for_each_irq_desc(irq, desc) {
if (desc->status & IRQ_MOVE_PENDING) {
unsigned long flags;
spin_lock_irqsave(&desc->lock, flags);
if (!desc->chip->set_affinity ||
!(desc->status & IRQ_MOVE_PENDING)) {
desc->status &= ~IRQ_MOVE_PENDING;
spin_unlock_irqrestore(&desc->lock, flags);
continue;
}
desc->chip->set_affinity(irq, desc->pending_mask);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
}
/*
* Migrates the IRQ destination in the process context.
*/
static void set_ir_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
{
struct irq_desc *desc = irq_to_desc(irq);
if (desc->status & IRQ_LEVEL) {
desc->status |= IRQ_MOVE_PENDING;
desc->pending_mask = mask;
migrate_irq_remapped_level(irq);
return;
}
migrate_ioapic_irq(irq, mask);
}
#endif
asmlinkage void smp_irq_move_cleanup_interrupt(void)
{
unsigned vector, me;
ack_APIC_irq();
#ifdef CONFIG_X86_64
exit_idle();
#endif
irq_enter();
me = smp_processor_id();
for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
unsigned int irq;
struct irq_desc *desc;
struct irq_cfg *cfg;
irq = __get_cpu_var(vector_irq)[vector];
desc = irq_to_desc(irq);
if (!desc)
continue;
cfg = irq_cfg(irq);
spin_lock(&desc->lock);
if (!cfg->move_cleanup_count)
goto unlock;
if ((vector == cfg->vector) && cpu_isset(me, cfg->domain))
goto unlock;
__get_cpu_var(vector_irq)[vector] = -1;
cfg->move_cleanup_count--;
unlock:
spin_unlock(&desc->lock);
}
irq_exit();
}
static void irq_complete_move(unsigned int irq)
{
struct irq_cfg *cfg = irq_cfg(irq);
unsigned vector, me;
if (likely(!cfg->move_in_progress))
return;
vector = ~get_irq_regs()->orig_ax;
me = smp_processor_id();
if ((vector == cfg->vector) && cpu_isset(me, cfg->domain)) {
cpumask_t cleanup_mask;
cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
cfg->move_cleanup_count = cpus_weight(cleanup_mask);
send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
cfg->move_in_progress = 0; cfg->move_in_progress = 0;
} }
} }
#else #else
static inline void irq_complete_move(unsigned int irq) {} static inline void irq_complete_move(unsigned int irq) {}
#endif #endif
#ifdef CONFIG_INTR_REMAP
static void ack_x2apic_level(unsigned int irq)
{
ack_x2APIC_irq();
}
static void ack_x2apic_edge(unsigned int irq)
{
ack_x2APIC_irq();
}
#endif
static void ack_apic_edge(unsigned int irq) static void ack_apic_edge(unsigned int irq)
{ {
...@@ -2118,55 +2439,55 @@ static void ack_apic_edge(unsigned int irq) ...@@ -2118,55 +2439,55 @@ static void ack_apic_edge(unsigned int irq)
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
static void ack_apic_level(unsigned int irq) static void ack_apic_level(unsigned int irq)
{ {
int do_unmask_irq = 0; int do_unmask_irq = 0;
irq_complete_move(irq); irq_complete_move(irq);
#ifdef CONFIG_GENERIC_PENDING_IRQ #ifdef CONFIG_GENERIC_PENDING_IRQ
/* If we are moving the irq we need to mask it */ /* If we are moving the irq we need to mask it */
if (unlikely(desc->status & IRQ_MOVE_PENDING)) { if (unlikely(irq_to_desc(irq)->status & IRQ_MOVE_PENDING)) {
do_unmask_irq = 1; do_unmask_irq = 1;
mask_IO_APIC_irq(irq); mask_IO_APIC_irq(irq);
} }
#endif #endif
/* /*
* We must acknowledge the irq before we move it or the acknowledge will * We must acknowledge the irq before we move it or the acknowledge will
* not propagate properly. * not propagate properly.
*/ */
ack_APIC_irq(); ack_APIC_irq();
/* Now we can move and renable the irq */ /* Now we can move and renable the irq */
if (unlikely(do_unmask_irq)) { if (unlikely(do_unmask_irq)) {
/* Only migrate the irq if the ack has been received. /* Only migrate the irq if the ack has been received.
* *
* On rare occasions the broadcast level triggered ack gets * On rare occasions the broadcast level triggered ack gets
* delayed going to ioapics, and if we reprogram the * delayed going to ioapics, and if we reprogram the
* vector while Remote IRR is still set the irq will never * vector while Remote IRR is still set the irq will never
* fire again. * fire again.
* *
* To prevent this scenario we read the Remote IRR bit * To prevent this scenario we read the Remote IRR bit
* of the ioapic. This has two effects. * of the ioapic. This has two effects.
* - On any sane system the read of the ioapic will * - On any sane system the read of the ioapic will
* flush writes (and acks) going to the ioapic from * flush writes (and acks) going to the ioapic from
* this cpu. * this cpu.
* - We get to see if the ACK has actually been delivered. * - We get to see if the ACK has actually been delivered.
* *
* Based on failed experiments of reprogramming the * Based on failed experiments of reprogramming the
* ioapic entry from outside of irq context starting * ioapic entry from outside of irq context starting
* with masking the ioapic entry and then polling until * with masking the ioapic entry and then polling until
* Remote IRR was clear before reprogramming the * Remote IRR was clear before reprogramming the
* ioapic I don't trust the Remote IRR bit to be * ioapic I don't trust the Remote IRR bit to be
* completey accurate. * completey accurate.
* *
* However there appears to be no other way to plug * However there appears to be no other way to plug
* this race, so if the Remote IRR bit is not * this race, so if the Remote IRR bit is not
* accurate and is causing problems then it is a hardware bug * accurate and is causing problems then it is a hardware bug
* and you can go talk to the chipset vendor about it. * and you can go talk to the chipset vendor about it.
*/ */
if (!io_apic_level_ack_pending(irq)) if (!io_apic_level_ack_pending(irq))
move_masked_irq(irq, desc); move_masked_irq(irq);
unmask_IO_APIC_irq(irq); unmask_IO_APIC_irq(irq);
} }
} }
#else #else
atomic_t irq_mis_count; atomic_t irq_mis_count;
...@@ -2177,25 +2498,25 @@ static void ack_apic_level(unsigned int irq) ...@@ -2177,25 +2498,25 @@ static void ack_apic_level(unsigned int irq)
irq_complete_move(irq); irq_complete_move(irq);
move_native_irq(irq); move_native_irq(irq);
/* /*
* It appears there is an erratum which affects at least version 0x11 * It appears there is an erratum which affects at least version 0x11
* of I/O APIC (that's the 82093AA and cores integrated into various * of I/O APIC (that's the 82093AA and cores integrated into various
* chipsets). Under certain conditions a level-triggered interrupt is * chipsets). Under certain conditions a level-triggered interrupt is
* erroneously delivered as edge-triggered one but the respective IRR * erroneously delivered as edge-triggered one but the respective IRR
* bit gets set nevertheless. As a result the I/O unit expects an EOI * bit gets set nevertheless. As a result the I/O unit expects an EOI
* message but it will never arrive and further interrupts are blocked * message but it will never arrive and further interrupts are blocked
* from the source. The exact reason is so far unknown, but the * from the source. The exact reason is so far unknown, but the
* phenomenon was observed when two consecutive interrupt requests * phenomenon was observed when two consecutive interrupt requests
* from a given source get delivered to the same CPU and the source is * from a given source get delivered to the same CPU and the source is
* temporarily disabled in between. * temporarily disabled in between.
* *
* A workaround is to simulate an EOI message manually. We achieve it * A workaround is to simulate an EOI message manually. We achieve it
* by setting the trigger mode to edge and then to level when the edge * by setting the trigger mode to edge and then to level when the edge
* trigger mode gets detected in the TMR of a local APIC for a * trigger mode gets detected in the TMR of a local APIC for a
* level-triggered interrupt. We mask the source for the time of the * level-triggered interrupt. We mask the source for the time of the
* operation to prevent an edge-triggered interrupt escaping meanwhile. * operation to prevent an edge-triggered interrupt escaping meanwhile.
* The idea is from Manfred Spraul. --macro * The idea is from Manfred Spraul. --macro
*/ */
i = irq_cfg(irq)->vector; i = irq_cfg(irq)->vector;
v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
...@@ -2225,6 +2546,20 @@ static struct irq_chip ioapic_chip __read_mostly = { ...@@ -2225,6 +2546,20 @@ static struct irq_chip ioapic_chip __read_mostly = {
.retrigger = ioapic_retrigger_irq, .retrigger = ioapic_retrigger_irq,
}; };
#ifdef CONFIG_INTR_REMAP
static struct irq_chip ir_ioapic_chip __read_mostly = {
.name = "IR-IO-APIC",
.startup = startup_ioapic_irq,
.mask = mask_IO_APIC_irq,
.unmask = unmask_IO_APIC_irq,
.ack = ack_x2apic_edge,
.eoi = ack_x2apic_level,
#ifdef CONFIG_SMP
.set_affinity = set_ir_ioapic_affinity_irq,
#endif
.retrigger = ioapic_retrigger_irq,
};
#endif
static inline void init_IO_APIC_traps(void) static inline void init_IO_APIC_traps(void)
{ {
...@@ -2282,7 +2617,7 @@ static void unmask_lapic_irq(unsigned int irq) ...@@ -2282,7 +2617,7 @@ static void unmask_lapic_irq(unsigned int irq)
apic_write(APIC_LVT0, v & ~APIC_LVT_MASKED); apic_write(APIC_LVT0, v & ~APIC_LVT_MASKED);
} }
static void ack_lapic_irq(unsigned int irq) static void ack_lapic_irq (unsigned int irq)
{ {
ack_APIC_irq(); ack_APIC_irq();
} }
...@@ -2383,12 +2718,12 @@ static inline void __init unlock_ExtINT_logic(void) ...@@ -2383,12 +2718,12 @@ static inline void __init unlock_ExtINT_logic(void)
static int disable_timer_pin_1 __initdata; static int disable_timer_pin_1 __initdata;
/* Actually the next is obsolete, but keep it for paranoid reasons -AK */ /* Actually the next is obsolete, but keep it for paranoid reasons -AK */
static int __init parse_disable_timer_pin_1(char *arg) static int __init disable_timer_pin_setup(char *arg)
{ {
disable_timer_pin_1 = 1; disable_timer_pin_1 = 1;
return 0; return 0;
} }
early_param("disable_timer_pin_1", parse_disable_timer_pin_1); early_param("disable_timer_pin_1", disable_timer_pin_setup);
int timer_through_8259 __initdata; int timer_through_8259 __initdata;
...@@ -2397,6 +2732,8 @@ int timer_through_8259 __initdata; ...@@ -2397,6 +2732,8 @@ int timer_through_8259 __initdata;
* a wide range of boards and BIOS bugs. Fortunately only the timer IRQ * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ
* is so screwy. Thanks to Brian Perkins for testing/hacking this beast * is so screwy. Thanks to Brian Perkins for testing/hacking this beast
* fanatically on his truly buggy board. * fanatically on his truly buggy board.
*
* FIXME: really need to revamp this for all platforms.
*/ */
static inline void __init check_timer(void) static inline void __init check_timer(void)
{ {
...@@ -2408,8 +2745,8 @@ static inline void __init check_timer(void) ...@@ -2408,8 +2745,8 @@ static inline void __init check_timer(void)
local_irq_save(flags); local_irq_save(flags);
ver = apic_read(APIC_LVR); ver = apic_read(APIC_LVR);
ver = GET_APIC_VERSION(ver); ver = GET_APIC_VERSION(ver);
/* /*
* get/set the timer IRQ vector: * get/set the timer IRQ vector:
...@@ -2428,7 +2765,9 @@ static inline void __init check_timer(void) ...@@ -2428,7 +2765,9 @@ static inline void __init check_timer(void)
*/ */
apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
init_8259A(1); init_8259A(1);
#ifdef CONFIG_X86_32
timer_ack = (nmi_watchdog == NMI_IO_APIC && !APIC_INTEGRATED(ver)); timer_ack = (nmi_watchdog == NMI_IO_APIC && !APIC_INTEGRATED(ver));
#endif
pin1 = find_isa_irq_pin(0, mp_INT); pin1 = find_isa_irq_pin(0, mp_INT);
apic1 = find_isa_irq_apic(0, mp_INT); apic1 = find_isa_irq_apic(0, mp_INT);
...@@ -2447,6 +2786,10 @@ static inline void __init check_timer(void) ...@@ -2447,6 +2786,10 @@ static inline void __init check_timer(void)
* 8259A. * 8259A.
*/ */
if (pin1 == -1) { if (pin1 == -1) {
#ifdef CONFIG_INTR_REMAP
if (intr_remapping_enabled)
panic("BIOS bug: timer not connected to IO-APIC");
#endif
pin1 = pin2; pin1 = pin2;
apic1 = apic2; apic1 = apic2;
no_pin1 = 1; no_pin1 = 1;
...@@ -2473,6 +2816,10 @@ static inline void __init check_timer(void) ...@@ -2473,6 +2816,10 @@ static inline void __init check_timer(void)
clear_IO_APIC_pin(0, pin1); clear_IO_APIC_pin(0, pin1);
goto out; goto out;
} }
#ifdef CONFIG_INTR_REMAP
if (intr_remapping_enabled)
panic("timer doesn't work through Interrupt-remapped IO-APIC");
#endif
clear_IO_APIC_pin(apic1, pin1); clear_IO_APIC_pin(apic1, pin1);
if (!no_pin1) if (!no_pin1)
apic_printk(APIC_QUIET, KERN_ERR "..MP-BIOS bug: " apic_printk(APIC_QUIET, KERN_ERR "..MP-BIOS bug: "
...@@ -2512,7 +2859,9 @@ static inline void __init check_timer(void) ...@@ -2512,7 +2859,9 @@ static inline void __init check_timer(void)
"through the IO-APIC - disabling NMI Watchdog!\n"); "through the IO-APIC - disabling NMI Watchdog!\n");
nmi_watchdog = NMI_NONE; nmi_watchdog = NMI_NONE;
} }
#ifdef CONFIG_X86_32
timer_ack = 0; timer_ack = 0;
#endif
apic_printk(APIC_QUIET, KERN_INFO apic_printk(APIC_QUIET, KERN_INFO
"...trying to set up timer as Virtual Wire IRQ...\n"); "...trying to set up timer as Virtual Wire IRQ...\n");
...@@ -2570,17 +2919,25 @@ out: ...@@ -2570,17 +2919,25 @@ out:
void __init setup_IO_APIC(void) void __init setup_IO_APIC(void)
{ {
#ifdef CONFIG_X86_32
enable_IO_APIC(); enable_IO_APIC();
#else
/*
* calling enable_IO_APIC() is moved to setup_local_APIC for BP
*/
#endif
io_apic_irqs = ~PIC_IRQS; io_apic_irqs = ~PIC_IRQS;
printk("ENABLING IO-APIC IRQs\n"); apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n");
/*
/* * Set up IO-APIC IRQ routing.
* Set up IO-APIC IRQ routing. */
*/ #ifdef CONFIG_X86_32
if (!acpi_ioapic) if (!acpi_ioapic)
setup_ioapic_ids_from_mpc(); setup_ioapic_ids_from_mpc();
#endif
sync_Arb_IDs(); sync_Arb_IDs();
setup_IO_APIC_irqs(); setup_IO_APIC_irqs();
init_IO_APIC_traps(); init_IO_APIC_traps();
...@@ -2588,15 +2945,15 @@ void __init setup_IO_APIC(void) ...@@ -2588,15 +2945,15 @@ void __init setup_IO_APIC(void)
} }
/* /*
* Called after all the initialization is done. If we didnt find any * Called after all the initialization is done. If we didnt find any
* APIC bugs then we can allow the modify fast path * APIC bugs then we can allow the modify fast path
*/ */
static int __init io_apic_bug_finalize(void) static int __init io_apic_bug_finalize(void)
{ {
if (sis_apic_bug == -1) if (sis_apic_bug == -1)
sis_apic_bug = 0; sis_apic_bug = 0;
return 0; return 0;
} }
late_initcall(io_apic_bug_finalize); late_initcall(io_apic_bug_finalize);
...@@ -2605,7 +2962,7 @@ struct sysfs_ioapic_data { ...@@ -2605,7 +2962,7 @@ struct sysfs_ioapic_data {
struct sys_device dev; struct sys_device dev;
struct IO_APIC_route_entry entry[0]; struct IO_APIC_route_entry entry[0];
}; };
static struct sysfs_ioapic_data *mp_ioapic_data[MAX_IO_APICS]; static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS];
static int ioapic_suspend(struct sys_device *dev, pm_message_t state) static int ioapic_suspend(struct sys_device *dev, pm_message_t state)
{ {
...@@ -2615,8 +2972,8 @@ static int ioapic_suspend(struct sys_device *dev, pm_message_t state) ...@@ -2615,8 +2972,8 @@ static int ioapic_suspend(struct sys_device *dev, pm_message_t state)
data = container_of(dev, struct sysfs_ioapic_data, dev); data = container_of(dev, struct sysfs_ioapic_data, dev);
entry = data->entry; entry = data->entry;
for (i = 0; i < nr_ioapic_registers[dev->id]; i++) for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ )
entry[i] = ioapic_read_entry(dev->id, i); *entry = ioapic_read_entry(dev->id, i);
return 0; return 0;
} }
...@@ -2653,14 +3010,14 @@ static struct sysdev_class ioapic_sysdev_class = { ...@@ -2653,14 +3010,14 @@ static struct sysdev_class ioapic_sysdev_class = {
static int __init ioapic_init_sysfs(void) static int __init ioapic_init_sysfs(void)
{ {
struct sys_device *dev; struct sys_device * dev;
int i, size, error = 0; int i, size, error;
error = sysdev_class_register(&ioapic_sysdev_class); error = sysdev_class_register(&ioapic_sysdev_class);
if (error) if (error)
return error; return error;
for (i = 0; i < nr_ioapics; i++) { for (i = 0; i < nr_ioapics; i++ ) {
size = sizeof(struct sys_device) + nr_ioapic_registers[i] size = sizeof(struct sys_device) + nr_ioapic_registers[i]
* sizeof(struct IO_APIC_route_entry); * sizeof(struct IO_APIC_route_entry);
mp_ioapic_data[i] = kzalloc(size, GFP_KERNEL); mp_ioapic_data[i] = kzalloc(size, GFP_KERNEL);
...@@ -2691,18 +3048,18 @@ device_initcall(ioapic_init_sysfs); ...@@ -2691,18 +3048,18 @@ device_initcall(ioapic_init_sysfs);
unsigned int create_irq_nr(unsigned int irq_want) unsigned int create_irq_nr(unsigned int irq_want)
{ {
/* Allocate an unused irq */ /* Allocate an unused irq */
unsigned int irq, new; unsigned int irq;
unsigned int new;
unsigned long flags; unsigned long flags;
struct irq_cfg *cfg_new; struct irq_cfg *cfg_new;
#ifndef CONFIG_HAVE_SPARSE_IRQ #ifndef CONFIG_HAVE_SPARSE_IRQ
/* only can use bus/dev/fn.. when per_cpu vector is used */
irq_want = nr_irqs - 1; irq_want = nr_irqs - 1;
#endif #endif
irq = 0; irq = 0;
spin_lock_irqsave(&vector_lock, flags); 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)) if (platform_legacy_irq(new))
continue; continue;
cfg_new = irq_cfg(new); cfg_new = irq_cfg(new);
...@@ -2725,7 +3082,14 @@ unsigned int create_irq_nr(unsigned int irq_want) ...@@ -2725,7 +3082,14 @@ unsigned int create_irq_nr(unsigned int irq_want)
int create_irq(void) int create_irq(void)
{ {
return create_irq_nr(nr_irqs - 1); int irq;
irq = create_irq_nr(nr_irqs - 1);
if (irq == 0)
irq = -1;
return irq;
} }
void destroy_irq(unsigned int irq) void destroy_irq(unsigned int irq)
...@@ -2734,6 +3098,9 @@ void destroy_irq(unsigned int irq) ...@@ -2734,6 +3098,9 @@ void destroy_irq(unsigned int irq)
dynamic_irq_cleanup(irq); dynamic_irq_cleanup(irq);
#ifdef CONFIG_INTR_REMAP
free_irte(irq);
#endif
spin_lock_irqsave(&vector_lock, flags); spin_lock_irqsave(&vector_lock, flags);
__clear_irq_vector(irq); __clear_irq_vector(irq);
spin_unlock_irqrestore(&vector_lock, flags); spin_unlock_irqrestore(&vector_lock, flags);
...@@ -2759,25 +3126,54 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms ...@@ -2759,25 +3126,54 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
cpus_and(tmp, cfg->domain, tmp); cpus_and(tmp, cfg->domain, tmp);
dest = cpu_mask_to_apicid(tmp); dest = cpu_mask_to_apicid(tmp);
msg->address_hi = MSI_ADDR_BASE_HI; #ifdef CONFIG_INTR_REMAP
msg->address_lo = if (irq_remapped(irq)) {
MSI_ADDR_BASE_LO | struct irte irte;
((INT_DEST_MODE == 0) ? int ir_index;
MSI_ADDR_DEST_MODE_PHYSICAL: u16 sub_handle;
MSI_ADDR_DEST_MODE_LOGICAL) |
((INT_DELIVERY_MODE != dest_LowestPrio) ? ir_index = map_irq_to_irte_handle(irq, &sub_handle);
MSI_ADDR_REDIRECTION_CPU: BUG_ON(ir_index == -1);
MSI_ADDR_REDIRECTION_LOWPRI) |
MSI_ADDR_DEST_ID(dest); memset (&irte, 0, sizeof(irte));
msg->data = irte.present = 1;
MSI_DATA_TRIGGER_EDGE | irte.dst_mode = INT_DEST_MODE;
MSI_DATA_LEVEL_ASSERT | irte.trigger_mode = 0; /* edge */
((INT_DELIVERY_MODE != dest_LowestPrio) ? irte.dlvry_mode = INT_DELIVERY_MODE;
MSI_DATA_DELIVERY_FIXED: irte.vector = cfg->vector;
MSI_DATA_DELIVERY_LOWPRI) | irte.dest_id = IRTE_DEST(dest);
MSI_DATA_VECTOR(cfg->vector);
modify_irte(irq, &irte);
msg->address_hi = MSI_ADDR_BASE_HI;
msg->data = sub_handle;
msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT |
MSI_ADDR_IR_SHV |
MSI_ADDR_IR_INDEX1(ir_index) |
MSI_ADDR_IR_INDEX2(ir_index);
} else
#endif
{
msg->address_hi = MSI_ADDR_BASE_HI;
msg->address_lo =
MSI_ADDR_BASE_LO |
((INT_DEST_MODE == 0) ?
MSI_ADDR_DEST_MODE_PHYSICAL:
MSI_ADDR_DEST_MODE_LOGICAL) |
((INT_DELIVERY_MODE != dest_LowestPrio) ?
MSI_ADDR_REDIRECTION_CPU:
MSI_ADDR_REDIRECTION_LOWPRI) |
MSI_ADDR_DEST_ID(dest);
msg->data =
MSI_DATA_TRIGGER_EDGE |
MSI_DATA_LEVEL_ASSERT |
((INT_DELIVERY_MODE != dest_LowestPrio) ?
MSI_DATA_DELIVERY_FIXED:
MSI_DATA_DELIVERY_LOWPRI) |
MSI_DATA_VECTOR(cfg->vector);
}
return err; return err;
} }
...@@ -2788,6 +3184,7 @@ static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) ...@@ -2788,6 +3184,7 @@ static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
struct msi_msg msg; struct msi_msg msg;
unsigned int dest; unsigned int dest;
cpumask_t tmp; cpumask_t tmp;
struct irq_desc *desc;
cpus_and(tmp, mask, cpu_online_map); cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp)) if (cpus_empty(tmp))
...@@ -2808,8 +3205,61 @@ static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) ...@@ -2808,8 +3205,61 @@ static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
msg.address_lo |= MSI_ADDR_DEST_ID(dest); msg.address_lo |= MSI_ADDR_DEST_ID(dest);
write_msi_msg(irq, &msg); write_msi_msg(irq, &msg);
irq_to_desc(irq)->affinity = mask; desc = irq_to_desc(irq);
desc->affinity = mask;
} }
#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 ir_set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
{
struct irq_cfg *cfg;
unsigned int dest;
cpumask_t tmp, cleanup_mask;
struct irte irte;
struct irq_desc *desc;
cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp))
return;
if (get_irte(irq, &irte))
return;
if (assign_irq_vector(irq, mask))
return;
cfg = irq_cfg(irq);
cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp);
irte.vector = cfg->vector;
irte.dest_id = IRTE_DEST(dest);
/*
* atomically update the IRTE with the new destination and vector.
*/
modify_irte(irq, &irte);
/*
* After this point, all the interrupts will start arriving
* at the new destination. So, time to cleanup the previous
* vector allocation.
*/
if (cfg->move_in_progress) {
cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
cfg->move_cleanup_count = cpus_weight(cleanup_mask);
send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
cfg->move_in_progress = 0;
}
desc = irq_to_desc(irq);
desc->affinity = mask;
}
#endif
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
/* /*
...@@ -2827,6 +3277,45 @@ static struct irq_chip msi_chip = { ...@@ -2827,6 +3277,45 @@ static struct irq_chip msi_chip = {
.retrigger = ioapic_retrigger_irq, .retrigger = ioapic_retrigger_irq,
}; };
#ifdef CONFIG_INTR_REMAP
static struct irq_chip msi_ir_chip = {
.name = "IR-PCI-MSI",
.unmask = unmask_msi_irq,
.mask = mask_msi_irq,
.ack = ack_x2apic_edge,
#ifdef CONFIG_SMP
.set_affinity = ir_set_msi_irq_affinity,
#endif
.retrigger = ioapic_retrigger_irq,
};
/*
* Map the PCI dev to the corresponding remapping hardware unit
* and allocate 'nvec' consecutive interrupt-remapping table entries
* in it.
*/
static int msi_alloc_irte(struct pci_dev *dev, int irq, int nvec)
{
struct intel_iommu *iommu;
int index;
iommu = map_dev_to_ir(dev);
if (!iommu) {
printk(KERN_ERR
"Unable to map PCI %s to iommu\n", pci_name(dev));
return -ENOENT;
}
index = alloc_irte(iommu, irq, nvec);
if (index < 0) {
printk(KERN_ERR
"Unable to allocate %d IRTE for PCI %s\n", nvec,
pci_name(dev));
return -ENOSPC;
}
return index;
}
#endif
static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq) static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq)
{ {
...@@ -2840,7 +3329,17 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq) ...@@ -2840,7 +3329,17 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq)
set_irq_msi(irq, desc); set_irq_msi(irq, desc);
write_msi_msg(irq, &msg); write_msi_msg(irq, &msg);
set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge"); #ifdef CONFIG_INTR_REMAP
if (irq_remapped(irq)) {
struct irq_desc *desc = irq_to_desc(irq);
/*
* irq migration in process context
*/
desc->status |= IRQ_MOVE_PCNTXT;
set_irq_chip_and_handler_name(irq, &msi_ir_chip, handle_edge_irq, "edge");
} else
#endif
set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
return 0; return 0;
} }
...@@ -2859,59 +3358,164 @@ static unsigned int build_irq_for_pci_dev(struct pci_dev *dev) ...@@ -2859,59 +3358,164 @@ static unsigned int build_irq_for_pci_dev(struct pci_dev *dev)
int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) 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; unsigned int irq_want;
irq_want = build_irq_for_pci_dev(dev) + 0x100; irq_want = build_irq_for_pci_dev(dev) + 0x100;
irq = create_irq_nr(irq_want); irq = create_irq_nr(irq_want);
if (irq == 0) if (irq == 0)
return -1; return -1;
#ifdef CONFIG_INTR_REMAP
if (!intr_remapping_enabled)
goto no_ir;
ret = msi_alloc_irte(dev, irq, 1);
if (ret < 0)
goto error;
no_ir:
#endif
ret = setup_msi_irq(dev, desc, irq); ret = setup_msi_irq(dev, desc, irq);
if (ret < 0) { if (ret < 0) {
destroy_irq(irq); destroy_irq(irq);
return ret; return ret;
} }
return 0; return 0;
#ifdef CONFIG_INTR_REMAP
error:
destroy_irq(irq);
return ret;
#endif
} }
int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{ {
unsigned int irq; unsigned int irq;
int ret, sub_handle; int ret, sub_handle;
struct msi_desc *desc; struct msi_desc *desc;
unsigned int irq_want; unsigned int irq_want;
irq_want = build_irq_for_pci_dev(dev) + 0x100; #ifdef CONFIG_INTR_REMAP
sub_handle = 0; struct intel_iommu *iommu = 0;
list_for_each_entry(desc, &dev->msi_list, list) { int index = 0;
irq = create_irq_nr(irq_want--); #endif
if (irq == 0)
return -1; irq_want = build_irq_for_pci_dev(dev) + 0x100;
ret = setup_msi_irq(dev, desc, irq); sub_handle = 0;
if (ret < 0) list_for_each_entry(desc, &dev->msi_list, list) {
goto error; irq = create_irq_nr(irq_want--);
sub_handle++; if (irq == 0)
} return -1;
return 0; #ifdef CONFIG_INTR_REMAP
if (!intr_remapping_enabled)
goto no_ir;
if (!sub_handle) {
/*
* allocate the consecutive block of IRTE's
* for 'nvec'
*/
index = msi_alloc_irte(dev, irq, nvec);
if (index < 0) {
ret = index;
goto error;
}
} else {
iommu = map_dev_to_ir(dev);
if (!iommu) {
ret = -ENOENT;
goto error;
}
/*
* setup the mapping between the irq and the IRTE
* base index, the sub_handle pointing to the
* appropriate interrupt remap table entry.
*/
set_irte_irq(irq, iommu, index, sub_handle);
}
no_ir:
#endif
ret = setup_msi_irq(dev, desc, irq);
if (ret < 0)
goto error;
sub_handle++;
}
return 0;
error: error:
destroy_irq(irq); destroy_irq(irq);
return ret; return ret;
} }
void arch_teardown_msi_irq(unsigned int irq) void arch_teardown_msi_irq(unsigned int irq)
{ {
destroy_irq(irq); destroy_irq(irq);
} }
#endif /* CONFIG_PCI_MSI */ #ifdef CONFIG_DMAR
#ifdef CONFIG_SMP
static void dmar_msi_set_affinity(unsigned int irq, cpumask_t mask)
{
struct irq_cfg *cfg;
struct msi_msg msg;
unsigned int dest;
cpumask_t tmp;
struct irq_desc *desc;
cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp))
return;
if (assign_irq_vector(irq, mask))
return;
cfg = irq_cfg(irq);
cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp);
dmar_msi_read(irq, &msg);
msg.data &= ~MSI_DATA_VECTOR_MASK;
msg.data |= MSI_DATA_VECTOR(cfg->vector);
msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
msg.address_lo |= MSI_ADDR_DEST_ID(dest);
dmar_msi_write(irq, &msg);
desc = irq_to_desc(irq);
desc->affinity = mask;
}
#endif /* CONFIG_SMP */
struct irq_chip dmar_msi_type = {
.name = "DMAR_MSI",
.unmask = dmar_msi_unmask,
.mask = dmar_msi_mask,
.ack = ack_apic_edge,
#ifdef CONFIG_SMP
.set_affinity = dmar_msi_set_affinity,
#endif
.retrigger = ioapic_retrigger_irq,
};
int arch_setup_dmar_msi(unsigned int irq)
{
int ret;
struct msi_msg msg;
ret = msi_compose_msg(NULL, irq, &msg);
if (ret < 0)
return ret;
dmar_msi_write(irq, &msg);
set_irq_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
"edge");
return 0;
}
#endif
#endif /* CONFIG_PCI_MSI */
/* /*
* Hypertransport interrupt support * Hypertransport interrupt support
*/ */
...@@ -2938,6 +3542,7 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) ...@@ -2938,6 +3542,7 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
struct irq_cfg *cfg; struct irq_cfg *cfg;
unsigned int dest; unsigned int dest;
cpumask_t tmp; cpumask_t tmp;
struct irq_desc *desc;
cpus_and(tmp, mask, cpu_online_map); cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp)) if (cpus_empty(tmp))
...@@ -2951,7 +3556,8 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) ...@@ -2951,7 +3556,8 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
dest = cpu_mask_to_apicid(tmp); dest = cpu_mask_to_apicid(tmp);
target_ht_irq(irq, dest, cfg->vector); target_ht_irq(irq, dest, cfg->vector);
irq_to_desc(irq)->affinity = mask; desc = irq_to_desc(irq);
desc->affinity = mask;
} }
#endif #endif
...@@ -2974,7 +3580,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) ...@@ -2974,7 +3580,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
tmp = TARGET_CPUS; tmp = TARGET_CPUS;
err = assign_irq_vector(irq, tmp); err = assign_irq_vector(irq, tmp);
if ( !err) { if (!err) {
struct ht_irq_msg msg; struct ht_irq_msg msg;
unsigned dest; unsigned dest;
...@@ -3007,11 +3613,12 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) ...@@ -3007,11 +3613,12 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
#endif /* CONFIG_HT_IRQ */ #endif /* CONFIG_HT_IRQ */
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
ACPI-based IOAPIC Configuration ACPI-based IOAPIC Configuration
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
#ifdef CONFIG_X86_32
int __init io_apic_get_unique_id(int ioapic, int apic_id) int __init io_apic_get_unique_id(int ioapic, int apic_id)
{ {
union IO_APIC_reg_00 reg_00; union IO_APIC_reg_00 reg_00;
...@@ -3086,7 +3693,6 @@ int __init io_apic_get_unique_id(int ioapic, int apic_id) ...@@ -3086,7 +3693,6 @@ int __init io_apic_get_unique_id(int ioapic, int apic_id)
return apic_id; return apic_id;
} }
int __init io_apic_get_version(int ioapic) int __init io_apic_get_version(int ioapic)
{ {
union IO_APIC_reg_01 reg_01; union IO_APIC_reg_01 reg_01;
...@@ -3098,9 +3704,9 @@ int __init io_apic_get_version(int ioapic) ...@@ -3098,9 +3704,9 @@ int __init io_apic_get_version(int ioapic)
return reg_01.bits.version; return reg_01.bits.version;
} }
#endif
int __init io_apic_get_redir_entries (int ioapic)
int __init io_apic_get_redir_entries(int ioapic)
{ {
union IO_APIC_reg_01 reg_01; union IO_APIC_reg_01 reg_01;
unsigned long flags; unsigned long flags;
...@@ -3113,10 +3719,10 @@ int __init io_apic_get_redir_entries(int ioapic) ...@@ -3113,10 +3719,10 @@ int __init io_apic_get_redir_entries(int ioapic)
} }
int io_apic_set_pci_routing(int ioapic, int pin, int irq, int triggering, int polarity) int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int polarity)
{ {
if (!IO_APIC_IRQ(irq)) { if (!IO_APIC_IRQ(irq)) {
printk(KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
ioapic); ioapic);
return -EINVAL; return -EINVAL;
} }
...@@ -3132,6 +3738,7 @@ int io_apic_set_pci_routing(int ioapic, int pin, int irq, int triggering, int po ...@@ -3132,6 +3738,7 @@ int io_apic_set_pci_routing(int ioapic, int pin, int irq, int triggering, int po
return 0; return 0;
} }
int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity) int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity)
{ {
int i; int i;
...@@ -3163,7 +3770,6 @@ void __init setup_ioapic_dest(void) ...@@ -3163,7 +3770,6 @@ void __init setup_ioapic_dest(void)
{ {
int pin, ioapic, irq, irq_entry; int pin, ioapic, irq, irq_entry;
struct irq_cfg *cfg; struct irq_cfg *cfg;
struct irq_desc *desc;
if (skip_ioapic_setup == 1) if (skip_ioapic_setup == 1)
return; return;
...@@ -3184,43 +3790,124 @@ void __init setup_ioapic_dest(void) ...@@ -3184,43 +3790,124 @@ void __init setup_ioapic_dest(void)
setup_IO_APIC_irq(ioapic, pin, irq, setup_IO_APIC_irq(ioapic, pin, irq,
irq_trigger(irq_entry), irq_trigger(irq_entry),
irq_polarity(irq_entry)); irq_polarity(irq_entry));
else { #ifdef CONFIG_INTR_REMAP
desc = irq_to_desc(irq); else if (intr_remapping_enabled)
set_ir_ioapic_affinity_irq(irq, TARGET_CPUS);
#endif
else
set_ioapic_affinity_irq(irq, TARGET_CPUS); set_ioapic_affinity_irq(irq, TARGET_CPUS);
}
} }
} }
} }
#endif #endif
#ifdef CONFIG_X86_64
#define IOAPIC_RESOURCE_NAME_SIZE 11
static struct resource *ioapic_resources;
static struct resource * __init ioapic_setup_resources(void)
{
unsigned long n;
struct resource *res;
char *mem;
int i;
if (nr_ioapics <= 0)
return NULL;
n = IOAPIC_RESOURCE_NAME_SIZE + sizeof(struct resource);
n *= nr_ioapics;
mem = alloc_bootmem(n);
res = (void *)mem;
if (mem != NULL) {
mem += sizeof(struct resource) * nr_ioapics;
for (i = 0; i < nr_ioapics; i++) {
res[i].name = mem;
res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY;
sprintf(mem, "IOAPIC %u", i);
mem += IOAPIC_RESOURCE_NAME_SIZE;
}
}
ioapic_resources = res;
return res;
}
#endif
void __init ioapic_init_mappings(void) void __init ioapic_init_mappings(void)
{ {
unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
int i; int i;
#ifdef CONFIG_X86_64
struct resource *ioapic_res;
ioapic_res = ioapic_setup_resources();
#endif
for (i = 0; i < nr_ioapics; i++) { for (i = 0; i < nr_ioapics; i++) {
if (smp_found_config) { if (smp_found_config) {
ioapic_phys = mp_ioapics[i].mp_apicaddr; ioapic_phys = mp_ioapics[i].mp_apicaddr;
if (!ioapic_phys) { #ifdef CONFIG_X86_32
printk(KERN_ERR if (!ioapic_phys) {
"WARNING: bogus zero IO-APIC " printk(KERN_ERR
"address found in MPTABLE, " "WARNING: bogus zero IO-APIC "
"disabling IO/APIC support!\n"); "address found in MPTABLE, "
smp_found_config = 0; "disabling IO/APIC support!\n");
skip_ioapic_setup = 1; smp_found_config = 0;
goto fake_ioapic_page; skip_ioapic_setup = 1;
} goto fake_ioapic_page;
}
#endif
} else { } else {
#ifdef CONFIG_X86_32
fake_ioapic_page: fake_ioapic_page:
#endif
ioapic_phys = (unsigned long) ioapic_phys = (unsigned long)
alloc_bootmem_pages(PAGE_SIZE); alloc_bootmem_pages(PAGE_SIZE);
ioapic_phys = __pa(ioapic_phys); ioapic_phys = __pa(ioapic_phys);
} }
set_fixmap_nocache(idx, ioapic_phys); set_fixmap_nocache(idx, ioapic_phys);
printk(KERN_DEBUG "mapped IOAPIC to %08lx (%08lx)\n", apic_printk(APIC_VERBOSE,
__fix_to_virt(idx), ioapic_phys); "mapped IOAPIC to %08lx (%08lx)\n",
__fix_to_virt(idx), ioapic_phys);
idx++; idx++;
#ifdef CONFIG_X86_64
if (ioapic_res != NULL) {
ioapic_res->start = ioapic_phys;
ioapic_res->end = ioapic_phys + (4 * 1024) - 1;
ioapic_res++;
}
#endif
} }
} }
#ifdef CONFIG_X86_64
static int __init ioapic_insert_resources(void)
{
int i;
struct resource *r = ioapic_resources;
if (!r) {
printk(KERN_ERR
"IO APIC resources could be not be allocated.\n");
return -1;
}
for (i = 0; i < nr_ioapics; i++) {
insert_resource(&iomem_resource, r);
r++;
}
return 0;
}
/* Insert the IO APIC resources after PCI initialization has occured to handle
* IO APICS that are mapped in on a BAR in PCI space. */
late_initcall(ioapic_insert_resources);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment