|
|
|
@ -92,21 +92,21 @@ static struct ioapic {
|
|
|
|
|
DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1);
|
|
|
|
|
} ioapics[MAX_IO_APICS];
|
|
|
|
|
|
|
|
|
|
#define mpc_ioapic_ver(id) ioapics[id].mp_config.apicver
|
|
|
|
|
#define mpc_ioapic_ver(ioapic_idx) ioapics[ioapic_idx].mp_config.apicver
|
|
|
|
|
|
|
|
|
|
int mpc_ioapic_id(int id)
|
|
|
|
|
int mpc_ioapic_id(int ioapic_idx)
|
|
|
|
|
{
|
|
|
|
|
return ioapics[id].mp_config.apicid;
|
|
|
|
|
return ioapics[ioapic_idx].mp_config.apicid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int mpc_ioapic_addr(int id)
|
|
|
|
|
unsigned int mpc_ioapic_addr(int ioapic_idx)
|
|
|
|
|
{
|
|
|
|
|
return ioapics[id].mp_config.apicaddr;
|
|
|
|
|
return ioapics[ioapic_idx].mp_config.apicaddr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct mp_ioapic_gsi *mp_ioapic_gsi_routing(int id)
|
|
|
|
|
struct mp_ioapic_gsi *mp_ioapic_gsi_routing(int ioapic_idx)
|
|
|
|
|
{
|
|
|
|
|
return &ioapics[id].gsi_config;
|
|
|
|
|
return &ioapics[ioapic_idx].gsi_config;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int nr_ioapics;
|
|
|
|
@ -186,11 +186,7 @@ static struct irq_pin_list *alloc_irq_pin_list(int node)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
|
|
|
|
|
#ifdef CONFIG_SPARSE_IRQ
|
|
|
|
|
static struct irq_cfg irq_cfgx[NR_IRQS_LEGACY];
|
|
|
|
|
#else
|
|
|
|
|
static struct irq_cfg irq_cfgx[NR_IRQS];
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
int __init arch_early_irq_init(void)
|
|
|
|
|
{
|
|
|
|
@ -234,7 +230,6 @@ int __init arch_early_irq_init(void)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SPARSE_IRQ
|
|
|
|
|
static struct irq_cfg *irq_cfg(unsigned int irq)
|
|
|
|
|
{
|
|
|
|
|
return irq_get_chip_data(irq);
|
|
|
|
@ -269,22 +264,6 @@ static void free_irq_cfg(unsigned int at, struct irq_cfg *cfg)
|
|
|
|
|
kfree(cfg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
struct irq_cfg *irq_cfg(unsigned int irq)
|
|
|
|
|
{
|
|
|
|
|
return irq < nr_irqs ? irq_cfgx + irq : NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct irq_cfg *alloc_irq_cfg(unsigned int irq, int node)
|
|
|
|
|
{
|
|
|
|
|
return irq_cfgx + irq;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void free_irq_cfg(unsigned int at, struct irq_cfg *cfg) { }
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node)
|
|
|
|
|
{
|
|
|
|
|
int res = irq_alloc_desc_at(at, node);
|
|
|
|
@ -802,13 +781,13 @@ int restore_ioapic_entries(void)
|
|
|
|
|
/*
|
|
|
|
|
* Find the IRQ entry number of a certain pin.
|
|
|
|
|
*/
|
|
|
|
|
static int find_irq_entry(int apic, int pin, int type)
|
|
|
|
|
static int find_irq_entry(int ioapic_idx, int pin, int type)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < mp_irq_entries; i++)
|
|
|
|
|
if (mp_irqs[i].irqtype == type &&
|
|
|
|
|
(mp_irqs[i].dstapic == mpc_ioapic_id(apic) ||
|
|
|
|
|
(mp_irqs[i].dstapic == mpc_ioapic_id(ioapic_idx) ||
|
|
|
|
|
mp_irqs[i].dstapic == MP_APIC_ALL) &&
|
|
|
|
|
mp_irqs[i].dstirq == pin)
|
|
|
|
|
return i;
|
|
|
|
@ -847,12 +826,13 @@ static int __init find_isa_irq_apic(int irq, int type)
|
|
|
|
|
(mp_irqs[i].srcbusirq == irq))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i < mp_irq_entries) {
|
|
|
|
|
int apic;
|
|
|
|
|
for(apic = 0; apic < nr_ioapics; apic++) {
|
|
|
|
|
if (mpc_ioapic_id(apic) == mp_irqs[i].dstapic)
|
|
|
|
|
return apic;
|
|
|
|
|
}
|
|
|
|
|
int ioapic_idx;
|
|
|
|
|
|
|
|
|
|
for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++)
|
|
|
|
|
if (mpc_ioapic_id(ioapic_idx) == mp_irqs[i].dstapic)
|
|
|
|
|
return ioapic_idx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
@ -1067,7 +1047,7 @@ static int pin_2_irq(int idx, int apic, int pin)
|
|
|
|
|
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;
|
|
|
|
|
int ioapic_idx, i, best_guess = -1;
|
|
|
|
|
|
|
|
|
|
apic_printk(APIC_DEBUG,
|
|
|
|
|
"querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
|
|
|
|
@ -1080,8 +1060,8 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin,
|
|
|
|
|
for (i = 0; i < mp_irq_entries; i++) {
|
|
|
|
|
int lbus = mp_irqs[i].srcbus;
|
|
|
|
|
|
|
|
|
|
for (apic = 0; apic < nr_ioapics; apic++)
|
|
|
|
|
if (mpc_ioapic_id(apic) == mp_irqs[i].dstapic ||
|
|
|
|
|
for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++)
|
|
|
|
|
if (mpc_ioapic_id(ioapic_idx) == mp_irqs[i].dstapic ||
|
|
|
|
|
mp_irqs[i].dstapic == MP_APIC_ALL)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
@ -1089,13 +1069,13 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin,
|
|
|
|
|
!mp_irqs[i].irqtype &&
|
|
|
|
|
(bus == lbus) &&
|
|
|
|
|
(slot == ((mp_irqs[i].srcbusirq >> 2) & 0x1f))) {
|
|
|
|
|
int irq = pin_2_irq(i, apic, mp_irqs[i].dstirq);
|
|
|
|
|
int irq = pin_2_irq(i, ioapic_idx, mp_irqs[i].dstirq);
|
|
|
|
|
|
|
|
|
|
if (!(apic || IO_APIC_IRQ(irq)))
|
|
|
|
|
if (!(ioapic_idx || IO_APIC_IRQ(irq)))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (pin == (mp_irqs[i].srcbusirq & 3)) {
|
|
|
|
|
set_io_apic_irq_attr(irq_attr, apic,
|
|
|
|
|
set_io_apic_irq_attr(irq_attr, ioapic_idx,
|
|
|
|
|
mp_irqs[i].dstirq,
|
|
|
|
|
irq_trigger(i),
|
|
|
|
|
irq_polarity(i));
|
|
|
|
@ -1106,7 +1086,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin,
|
|
|
|
|
* best-guess fuzzy result for broken mptables.
|
|
|
|
|
*/
|
|
|
|
|
if (best_guess < 0) {
|
|
|
|
|
set_io_apic_irq_attr(irq_attr, apic,
|
|
|
|
|
set_io_apic_irq_attr(irq_attr, ioapic_idx,
|
|
|
|
|
mp_irqs[i].dstirq,
|
|
|
|
|
irq_trigger(i),
|
|
|
|
|
irq_polarity(i));
|
|
|
|
@ -1344,77 +1324,100 @@ static void ioapic_register_intr(unsigned int irq, struct irq_cfg *cfg,
|
|
|
|
|
fasteoi ? "fasteoi" : "edge");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int setup_ioapic_entry(int apic_id, int irq,
|
|
|
|
|
struct IO_APIC_route_entry *entry,
|
|
|
|
|
unsigned int destination, int trigger,
|
|
|
|
|
int polarity, int vector, int pin)
|
|
|
|
|
|
|
|
|
|
static int setup_ir_ioapic_entry(int irq,
|
|
|
|
|
struct IR_IO_APIC_route_entry *entry,
|
|
|
|
|
unsigned int destination, int vector,
|
|
|
|
|
struct io_apic_irq_attr *attr)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* add it to the IO-APIC irq-routing table:
|
|
|
|
|
*/
|
|
|
|
|
memset(entry,0,sizeof(*entry));
|
|
|
|
|
int index;
|
|
|
|
|
struct irte irte;
|
|
|
|
|
int ioapic_id = mpc_ioapic_id(attr->ioapic);
|
|
|
|
|
struct intel_iommu *iommu = map_ioapic_to_ir(ioapic_id);
|
|
|
|
|
|
|
|
|
|
if (intr_remapping_enabled) {
|
|
|
|
|
struct intel_iommu *iommu = map_ioapic_to_ir(apic_id);
|
|
|
|
|
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_id);
|
|
|
|
|
|
|
|
|
|
index = alloc_irte(iommu, irq, 1);
|
|
|
|
|
if (index < 0)
|
|
|
|
|
panic("Failed to allocate IRTE for ioapic %d\n", apic_id);
|
|
|
|
|
|
|
|
|
|
prepare_irte(&irte, vector, destination);
|
|
|
|
|
|
|
|
|
|
/* Set source-id of interrupt request */
|
|
|
|
|
set_ioapic_sid(&irte, apic_id);
|
|
|
|
|
|
|
|
|
|
modify_irte(irq, &irte);
|
|
|
|
|
|
|
|
|
|
ir_entry->index2 = (index >> 15) & 0x1;
|
|
|
|
|
ir_entry->zero = 0;
|
|
|
|
|
ir_entry->format = 1;
|
|
|
|
|
ir_entry->index = (index & 0x7fff);
|
|
|
|
|
/*
|
|
|
|
|
* IO-APIC RTE will be configured with virtual vector.
|
|
|
|
|
* irq handler will do the explicit EOI to the io-apic.
|
|
|
|
|
*/
|
|
|
|
|
ir_entry->vector = pin;
|
|
|
|
|
|
|
|
|
|
apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: "
|
|
|
|
|
"Set IRTE entry (P:%d FPD:%d Dst_Mode:%d "
|
|
|
|
|
"Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X "
|
|
|
|
|
"Avail:%X Vector:%02X Dest:%08X "
|
|
|
|
|
"SID:%04X SQ:%X SVT:%X)\n",
|
|
|
|
|
apic_id, irte.present, irte.fpd, irte.dst_mode,
|
|
|
|
|
irte.redir_hint, irte.trigger_mode, irte.dlvry_mode,
|
|
|
|
|
irte.avail, irte.vector, irte.dest_id,
|
|
|
|
|
irte.sid, irte.sq, irte.svt);
|
|
|
|
|
} else {
|
|
|
|
|
entry->delivery_mode = apic->irq_delivery_mode;
|
|
|
|
|
entry->dest_mode = apic->irq_dest_mode;
|
|
|
|
|
entry->dest = destination;
|
|
|
|
|
entry->vector = vector;
|
|
|
|
|
if (!iommu) {
|
|
|
|
|
pr_warn("No mapping iommu for ioapic %d\n", ioapic_id);
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
entry->mask = 0; /* enable IRQ */
|
|
|
|
|
entry->trigger = trigger;
|
|
|
|
|
entry->polarity = polarity;
|
|
|
|
|
index = alloc_irte(iommu, irq, 1);
|
|
|
|
|
if (index < 0) {
|
|
|
|
|
pr_warn("Failed to allocate IRTE for ioapic %d\n", ioapic_id);
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prepare_irte(&irte, vector, destination);
|
|
|
|
|
|
|
|
|
|
/* Set source-id of interrupt request */
|
|
|
|
|
set_ioapic_sid(&irte, ioapic_id);
|
|
|
|
|
|
|
|
|
|
modify_irte(irq, &irte);
|
|
|
|
|
|
|
|
|
|
apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: "
|
|
|
|
|
"Set IRTE entry (P:%d FPD:%d Dst_Mode:%d "
|
|
|
|
|
"Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X "
|
|
|
|
|
"Avail:%X Vector:%02X Dest:%08X "
|
|
|
|
|
"SID:%04X SQ:%X SVT:%X)\n",
|
|
|
|
|
attr->ioapic, irte.present, irte.fpd, irte.dst_mode,
|
|
|
|
|
irte.redir_hint, irte.trigger_mode, irte.dlvry_mode,
|
|
|
|
|
irte.avail, irte.vector, irte.dest_id,
|
|
|
|
|
irte.sid, irte.sq, irte.svt);
|
|
|
|
|
|
|
|
|
|
memset(entry, 0, sizeof(*entry));
|
|
|
|
|
|
|
|
|
|
entry->index2 = (index >> 15) & 0x1;
|
|
|
|
|
entry->zero = 0;
|
|
|
|
|
entry->format = 1;
|
|
|
|
|
entry->index = (index & 0x7fff);
|
|
|
|
|
/*
|
|
|
|
|
* IO-APIC RTE will be configured with virtual vector.
|
|
|
|
|
* irq handler will do the explicit EOI to the io-apic.
|
|
|
|
|
*/
|
|
|
|
|
entry->vector = attr->ioapic_pin;
|
|
|
|
|
entry->mask = 0; /* enable IRQ */
|
|
|
|
|
entry->trigger = attr->trigger;
|
|
|
|
|
entry->polarity = attr->polarity;
|
|
|
|
|
|
|
|
|
|
/* Mask level triggered irqs.
|
|
|
|
|
* Use IRQ_DELAYED_DISABLE for edge triggered irqs.
|
|
|
|
|
*/
|
|
|
|
|
if (trigger)
|
|
|
|
|
if (attr->trigger)
|
|
|
|
|
entry->mask = 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void setup_ioapic_irq(int apic_id, int pin, unsigned int irq,
|
|
|
|
|
struct irq_cfg *cfg, int trigger, int polarity)
|
|
|
|
|
static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
|
|
|
|
|
unsigned int destination, int vector,
|
|
|
|
|
struct io_apic_irq_attr *attr)
|
|
|
|
|
{
|
|
|
|
|
if (intr_remapping_enabled)
|
|
|
|
|
return setup_ir_ioapic_entry(irq,
|
|
|
|
|
(struct IR_IO_APIC_route_entry *)entry,
|
|
|
|
|
destination, vector, attr);
|
|
|
|
|
|
|
|
|
|
memset(entry, 0, sizeof(*entry));
|
|
|
|
|
|
|
|
|
|
entry->delivery_mode = apic->irq_delivery_mode;
|
|
|
|
|
entry->dest_mode = apic->irq_dest_mode;
|
|
|
|
|
entry->dest = destination;
|
|
|
|
|
entry->vector = vector;
|
|
|
|
|
entry->mask = 0; /* enable IRQ */
|
|
|
|
|
entry->trigger = attr->trigger;
|
|
|
|
|
entry->polarity = attr->polarity;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Mask level triggered irqs.
|
|
|
|
|
* Use IRQ_DELAYED_DISABLE for edge triggered irqs.
|
|
|
|
|
*/
|
|
|
|
|
if (attr->trigger)
|
|
|
|
|
entry->mask = 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg,
|
|
|
|
|
struct io_apic_irq_attr *attr)
|
|
|
|
|
{
|
|
|
|
|
struct IO_APIC_route_entry entry;
|
|
|
|
|
unsigned int dest;
|
|
|
|
@ -1437,49 +1440,48 @@ static void setup_ioapic_irq(int apic_id, int pin, unsigned int irq,
|
|
|
|
|
apic_printk(APIC_VERBOSE,KERN_DEBUG
|
|
|
|
|
"IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> "
|
|
|
|
|
"IRQ %d Mode:%i Active:%i Dest:%d)\n",
|
|
|
|
|
apic_id, mpc_ioapic_id(apic_id), pin, cfg->vector,
|
|
|
|
|
irq, trigger, polarity, dest);
|
|
|
|
|
attr->ioapic, mpc_ioapic_id(attr->ioapic), attr->ioapic_pin,
|
|
|
|
|
cfg->vector, irq, attr->trigger, attr->polarity, dest);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (setup_ioapic_entry(mpc_ioapic_id(apic_id), irq, &entry,
|
|
|
|
|
dest, trigger, polarity, cfg->vector, pin)) {
|
|
|
|
|
printk("Failed to setup ioapic entry for ioapic %d, pin %d\n",
|
|
|
|
|
mpc_ioapic_id(apic_id), pin);
|
|
|
|
|
if (setup_ioapic_entry(irq, &entry, dest, cfg->vector, attr)) {
|
|
|
|
|
pr_warn("Failed to setup ioapic entry for ioapic %d, pin %d\n",
|
|
|
|
|
mpc_ioapic_id(attr->ioapic), attr->ioapic_pin);
|
|
|
|
|
__clear_irq_vector(irq, cfg);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ioapic_register_intr(irq, cfg, trigger);
|
|
|
|
|
ioapic_register_intr(irq, cfg, attr->trigger);
|
|
|
|
|
if (irq < legacy_pic->nr_legacy_irqs)
|
|
|
|
|
legacy_pic->mask(irq);
|
|
|
|
|
|
|
|
|
|
ioapic_write_entry(apic_id, pin, entry);
|
|
|
|
|
ioapic_write_entry(attr->ioapic, attr->ioapic_pin, entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool __init io_apic_pin_not_connected(int idx, int apic_id, int pin)
|
|
|
|
|
static bool __init io_apic_pin_not_connected(int idx, int ioapic_idx, int pin)
|
|
|
|
|
{
|
|
|
|
|
if (idx != -1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
apic_printk(APIC_VERBOSE, KERN_DEBUG " apic %d pin %d not connected\n",
|
|
|
|
|
mpc_ioapic_id(apic_id), pin);
|
|
|
|
|
mpc_ioapic_id(ioapic_idx), pin);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init __io_apic_setup_irqs(unsigned int apic_id)
|
|
|
|
|
static void __init __io_apic_setup_irqs(unsigned int ioapic_idx)
|
|
|
|
|
{
|
|
|
|
|
int idx, node = cpu_to_node(0);
|
|
|
|
|
struct io_apic_irq_attr attr;
|
|
|
|
|
unsigned int pin, irq;
|
|
|
|
|
|
|
|
|
|
for (pin = 0; pin < ioapics[apic_id].nr_registers; pin++) {
|
|
|
|
|
idx = find_irq_entry(apic_id, pin, mp_INT);
|
|
|
|
|
if (io_apic_pin_not_connected(idx, apic_id, pin))
|
|
|
|
|
for (pin = 0; pin < ioapics[ioapic_idx].nr_registers; pin++) {
|
|
|
|
|
idx = find_irq_entry(ioapic_idx, pin, mp_INT);
|
|
|
|
|
if (io_apic_pin_not_connected(idx, ioapic_idx, pin))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
irq = pin_2_irq(idx, apic_id, pin);
|
|
|
|
|
irq = pin_2_irq(idx, ioapic_idx, pin);
|
|
|
|
|
|
|
|
|
|
if ((apic_id > 0) && (irq > 16))
|
|
|
|
|
if ((ioapic_idx > 0) && (irq > 16))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -1487,10 +1489,10 @@ static void __init __io_apic_setup_irqs(unsigned int apic_id)
|
|
|
|
|
* installed and if it returns 1:
|
|
|
|
|
*/
|
|
|
|
|
if (apic->multi_timer_check &&
|
|
|
|
|
apic->multi_timer_check(apic_id, irq))
|
|
|
|
|
apic->multi_timer_check(ioapic_idx, irq))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
set_io_apic_irq_attr(&attr, apic_id, pin, irq_trigger(idx),
|
|
|
|
|
set_io_apic_irq_attr(&attr, ioapic_idx, pin, irq_trigger(idx),
|
|
|
|
|
irq_polarity(idx));
|
|
|
|
|
|
|
|
|
|
io_apic_setup_irq_pin(irq, node, &attr);
|
|
|
|
@ -1499,12 +1501,12 @@ static void __init __io_apic_setup_irqs(unsigned int apic_id)
|
|
|
|
|
|
|
|
|
|
static void __init setup_IO_APIC_irqs(void)
|
|
|
|
|
{
|
|
|
|
|
unsigned int apic_id;
|
|
|
|
|
unsigned int ioapic_idx;
|
|
|
|
|
|
|
|
|
|
apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n");
|
|
|
|
|
|
|
|
|
|
for (apic_id = 0; apic_id < nr_ioapics; apic_id++)
|
|
|
|
|
__io_apic_setup_irqs(apic_id);
|
|
|
|
|
for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++)
|
|
|
|
|
__io_apic_setup_irqs(ioapic_idx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -1514,28 +1516,28 @@ static void __init setup_IO_APIC_irqs(void)
|
|
|
|
|
*/
|
|
|
|
|
void setup_IO_APIC_irq_extra(u32 gsi)
|
|
|
|
|
{
|
|
|
|
|
int apic_id = 0, pin, idx, irq, node = cpu_to_node(0);
|
|
|
|
|
int ioapic_idx = 0, pin, idx, irq, node = cpu_to_node(0);
|
|
|
|
|
struct io_apic_irq_attr attr;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Convert 'gsi' to 'ioapic.pin'.
|
|
|
|
|
*/
|
|
|
|
|
apic_id = mp_find_ioapic(gsi);
|
|
|
|
|
if (apic_id < 0)
|
|
|
|
|
ioapic_idx = mp_find_ioapic(gsi);
|
|
|
|
|
if (ioapic_idx < 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
pin = mp_find_ioapic_pin(apic_id, gsi);
|
|
|
|
|
idx = find_irq_entry(apic_id, pin, mp_INT);
|
|
|
|
|
pin = mp_find_ioapic_pin(ioapic_idx, gsi);
|
|
|
|
|
idx = find_irq_entry(ioapic_idx, pin, mp_INT);
|
|
|
|
|
if (idx == -1)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
irq = pin_2_irq(idx, apic_id, pin);
|
|
|
|
|
irq = pin_2_irq(idx, ioapic_idx, pin);
|
|
|
|
|
|
|
|
|
|
/* Only handle the non legacy irqs on secondary ioapics */
|
|
|
|
|
if (apic_id == 0 || irq < NR_IRQS_LEGACY)
|
|
|
|
|
if (ioapic_idx == 0 || irq < NR_IRQS_LEGACY)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
set_io_apic_irq_attr(&attr, apic_id, pin, irq_trigger(idx),
|
|
|
|
|
set_io_apic_irq_attr(&attr, ioapic_idx, pin, irq_trigger(idx),
|
|
|
|
|
irq_polarity(idx));
|
|
|
|
|
|
|
|
|
|
io_apic_setup_irq_pin_once(irq, node, &attr);
|
|
|
|
@ -1544,8 +1546,8 @@ void setup_IO_APIC_irq_extra(u32 gsi)
|
|
|
|
|
/*
|
|
|
|
|
* Set up the timer pin, possibly with the 8259A-master behind.
|
|
|
|
|
*/
|
|
|
|
|
static void __init setup_timer_IRQ0_pin(unsigned int apic_id, unsigned int pin,
|
|
|
|
|
int vector)
|
|
|
|
|
static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx,
|
|
|
|
|
unsigned int pin, int vector)
|
|
|
|
|
{
|
|
|
|
|
struct IO_APIC_route_entry entry;
|
|
|
|
|
|
|
|
|
@ -1576,45 +1578,29 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic_id, unsigned int pin,
|
|
|
|
|
/*
|
|
|
|
|
* Add it to the IO-APIC irq-routing table:
|
|
|
|
|
*/
|
|
|
|
|
ioapic_write_entry(apic_id, pin, entry);
|
|
|
|
|
ioapic_write_entry(ioapic_idx, pin, entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__apicdebuginit(void) print_IO_APIC(void)
|
|
|
|
|
__apicdebuginit(void) print_IO_APIC(int ioapic_idx)
|
|
|
|
|
{
|
|
|
|
|
int apic, i;
|
|
|
|
|
int i;
|
|
|
|
|
union IO_APIC_reg_00 reg_00;
|
|
|
|
|
union IO_APIC_reg_01 reg_01;
|
|
|
|
|
union IO_APIC_reg_02 reg_02;
|
|
|
|
|
union IO_APIC_reg_03 reg_03;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
struct irq_cfg *cfg;
|
|
|
|
|
unsigned int irq;
|
|
|
|
|
|
|
|
|
|
printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
|
|
|
|
|
for (i = 0; i < nr_ioapics; i++)
|
|
|
|
|
printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n",
|
|
|
|
|
mpc_ioapic_id(i), ioapics[i].nr_registers);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We are a bit conservative about what we expect. We have to
|
|
|
|
|
* know about every hardware change ASAP.
|
|
|
|
|
*/
|
|
|
|
|
printk(KERN_INFO "testing the IO APIC.......................\n");
|
|
|
|
|
|
|
|
|
|
for (apic = 0; apic < nr_ioapics; apic++) {
|
|
|
|
|
|
|
|
|
|
raw_spin_lock_irqsave(&ioapic_lock, flags);
|
|
|
|
|
reg_00.raw = io_apic_read(apic, 0);
|
|
|
|
|
reg_01.raw = io_apic_read(apic, 1);
|
|
|
|
|
reg_00.raw = io_apic_read(ioapic_idx, 0);
|
|
|
|
|
reg_01.raw = io_apic_read(ioapic_idx, 1);
|
|
|
|
|
if (reg_01.bits.version >= 0x10)
|
|
|
|
|
reg_02.raw = io_apic_read(apic, 2);
|
|
|
|
|
reg_02.raw = io_apic_read(ioapic_idx, 2);
|
|
|
|
|
if (reg_01.bits.version >= 0x20)
|
|
|
|
|
reg_03.raw = io_apic_read(apic, 3);
|
|
|
|
|
reg_03.raw = io_apic_read(ioapic_idx, 3);
|
|
|
|
|
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
|
|
|
|
|
|
|
|
printk("\n");
|
|
|
|
|
printk(KERN_DEBUG "IO APIC #%d......\n", mpc_ioapic_id(apic));
|
|
|
|
|
printk(KERN_DEBUG "IO APIC #%d......\n", mpc_ioapic_id(ioapic_idx));
|
|
|
|
|
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 "....... : Delivery Type: %X\n", reg_00.bits.delivery_type);
|
|
|
|
@ -1664,7 +1650,7 @@ __apicdebuginit(void) print_IO_APIC(void)
|
|
|
|
|
struct IO_APIC_route_entry entry;
|
|
|
|
|
struct IR_IO_APIC_route_entry *ir_entry;
|
|
|
|
|
|
|
|
|
|
entry = ioapic_read_entry(apic, i);
|
|
|
|
|
entry = ioapic_read_entry(ioapic_idx, i);
|
|
|
|
|
ir_entry = (struct IR_IO_APIC_route_entry *) &entry;
|
|
|
|
|
printk(KERN_DEBUG " %02x %04X ",
|
|
|
|
|
i,
|
|
|
|
@ -1685,7 +1671,7 @@ __apicdebuginit(void) print_IO_APIC(void)
|
|
|
|
|
} else {
|
|
|
|
|
struct IO_APIC_route_entry entry;
|
|
|
|
|
|
|
|
|
|
entry = ioapic_read_entry(apic, i);
|
|
|
|
|
entry = ioapic_read_entry(ioapic_idx, i);
|
|
|
|
|
printk(KERN_DEBUG " %02x %02X ",
|
|
|
|
|
i,
|
|
|
|
|
entry.dest
|
|
|
|
@ -1703,7 +1689,28 @@ __apicdebuginit(void) print_IO_APIC(void)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__apicdebuginit(void) print_IO_APICs(void)
|
|
|
|
|
{
|
|
|
|
|
int ioapic_idx;
|
|
|
|
|
struct irq_cfg *cfg;
|
|
|
|
|
unsigned int irq;
|
|
|
|
|
|
|
|
|
|
printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
|
|
|
|
|
for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++)
|
|
|
|
|
printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n",
|
|
|
|
|
mpc_ioapic_id(ioapic_idx),
|
|
|
|
|
ioapics[ioapic_idx].nr_registers);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We are a bit conservative about what we expect. We have to
|
|
|
|
|
* know about every hardware change ASAP.
|
|
|
|
|
*/
|
|
|
|
|
printk(KERN_INFO "testing the IO APIC.......................\n");
|
|
|
|
|
|
|
|
|
|
for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++)
|
|
|
|
|
print_IO_APIC(ioapic_idx);
|
|
|
|
|
|
|
|
|
|
printk(KERN_DEBUG "IRQ to pin mappings:\n");
|
|
|
|
|
for_each_active_irq(irq) {
|
|
|
|
@ -1722,8 +1729,6 @@ __apicdebuginit(void) print_IO_APIC(void)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printk(KERN_INFO ".................................... done.\n");
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__apicdebuginit(void) print_APIC_field(int base)
|
|
|
|
@ -1917,7 +1922,7 @@ __apicdebuginit(int) print_ICs(void)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
print_local_APICs(show_lapic);
|
|
|
|
|
print_IO_APIC();
|
|
|
|
|
print_IO_APICs();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -2042,7 +2047,7 @@ void __init setup_ioapic_ids_from_mpc_nocheck(void)
|
|
|
|
|
{
|
|
|
|
|
union IO_APIC_reg_00 reg_00;
|
|
|
|
|
physid_mask_t phys_id_present_map;
|
|
|
|
|
int apic_id;
|
|
|
|
|
int ioapic_idx;
|
|
|
|
|
int i;
|
|
|
|
|
unsigned char old_id;
|
|
|
|
|
unsigned long flags;
|
|
|
|
@ -2056,21 +2061,20 @@ void __init setup_ioapic_ids_from_mpc_nocheck(void)
|
|
|
|
|
/*
|
|
|
|
|
* Set the IOAPIC ID to the value stored in the MPC table.
|
|
|
|
|
*/
|
|
|
|
|
for (apic_id = 0; apic_id < nr_ioapics; apic_id++) {
|
|
|
|
|
|
|
|
|
|
for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++) {
|
|
|
|
|
/* Read the register 0 value */
|
|
|
|
|
raw_spin_lock_irqsave(&ioapic_lock, flags);
|
|
|
|
|
reg_00.raw = io_apic_read(apic_id, 0);
|
|
|
|
|
reg_00.raw = io_apic_read(ioapic_idx, 0);
|
|
|
|
|
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
|
|
|
|
|
|
|
|
old_id = mpc_ioapic_id(apic_id);
|
|
|
|
|
old_id = mpc_ioapic_id(ioapic_idx);
|
|
|
|
|
|
|
|
|
|
if (mpc_ioapic_id(apic_id) >= get_physical_broadcast()) {
|
|
|
|
|
if (mpc_ioapic_id(ioapic_idx) >= get_physical_broadcast()) {
|
|
|
|
|
printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
|
|
|
|
|
apic_id, mpc_ioapic_id(apic_id));
|
|
|
|
|
ioapic_idx, mpc_ioapic_id(ioapic_idx));
|
|
|
|
|
printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
|
|
|
|
|
reg_00.bits.ID);
|
|
|
|
|
ioapics[apic_id].mp_config.apicid = reg_00.bits.ID;
|
|
|
|
|
ioapics[ioapic_idx].mp_config.apicid = reg_00.bits.ID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -2079,9 +2083,9 @@ void __init setup_ioapic_ids_from_mpc_nocheck(void)
|
|
|
|
|
* 'stuck on smp_invalidate_needed IPI wait' messages.
|
|
|
|
|
*/
|
|
|
|
|
if (apic->check_apicid_used(&phys_id_present_map,
|
|
|
|
|
mpc_ioapic_id(apic_id))) {
|
|
|
|
|
mpc_ioapic_id(ioapic_idx))) {
|
|
|
|
|
printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
|
|
|
|
|
apic_id, mpc_ioapic_id(apic_id));
|
|
|
|
|
ioapic_idx, mpc_ioapic_id(ioapic_idx));
|
|
|
|
|
for (i = 0; i < get_physical_broadcast(); i++)
|
|
|
|
|
if (!physid_isset(i, phys_id_present_map))
|
|
|
|
|
break;
|
|
|
|
@ -2090,14 +2094,14 @@ void __init setup_ioapic_ids_from_mpc_nocheck(void)
|
|
|
|
|
printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
|
|
|
|
|
i);
|
|
|
|
|
physid_set(i, phys_id_present_map);
|
|
|
|
|
ioapics[apic_id].mp_config.apicid = i;
|
|
|
|
|
ioapics[ioapic_idx].mp_config.apicid = i;
|
|
|
|
|
} else {
|
|
|
|
|
physid_mask_t tmp;
|
|
|
|
|
apic->apicid_to_cpu_present(mpc_ioapic_id(apic_id),
|
|
|
|
|
apic->apicid_to_cpu_present(mpc_ioapic_id(ioapic_idx),
|
|
|
|
|
&tmp);
|
|
|
|
|
apic_printk(APIC_VERBOSE, "Setting %d in the "
|
|
|
|
|
"phys_id_present_map\n",
|
|
|
|
|
mpc_ioapic_id(apic_id));
|
|
|
|
|
mpc_ioapic_id(ioapic_idx));
|
|
|
|
|
physids_or(phys_id_present_map, phys_id_present_map, tmp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2105,35 +2109,35 @@ void __init setup_ioapic_ids_from_mpc_nocheck(void)
|
|
|
|
|
* We need to adjust the IRQ routing table
|
|
|
|
|
* if the ID changed.
|
|
|
|
|
*/
|
|
|
|
|
if (old_id != mpc_ioapic_id(apic_id))
|
|
|
|
|
if (old_id != mpc_ioapic_id(ioapic_idx))
|
|
|
|
|
for (i = 0; i < mp_irq_entries; i++)
|
|
|
|
|
if (mp_irqs[i].dstapic == old_id)
|
|
|
|
|
mp_irqs[i].dstapic
|
|
|
|
|
= mpc_ioapic_id(apic_id);
|
|
|
|
|
= mpc_ioapic_id(ioapic_idx);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Update the ID register according to the right value
|
|
|
|
|
* from the MPC table if they are different.
|
|
|
|
|
*/
|
|
|
|
|
if (mpc_ioapic_id(apic_id) == reg_00.bits.ID)
|
|
|
|
|
if (mpc_ioapic_id(ioapic_idx) == reg_00.bits.ID)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
apic_printk(APIC_VERBOSE, KERN_INFO
|
|
|
|
|
"...changing IO-APIC physical APIC ID to %d ...",
|
|
|
|
|
mpc_ioapic_id(apic_id));
|
|
|
|
|
mpc_ioapic_id(ioapic_idx));
|
|
|
|
|
|
|
|
|
|
reg_00.bits.ID = mpc_ioapic_id(apic_id);
|
|
|
|
|
reg_00.bits.ID = mpc_ioapic_id(ioapic_idx);
|
|
|
|
|
raw_spin_lock_irqsave(&ioapic_lock, flags);
|
|
|
|
|
io_apic_write(apic_id, 0, reg_00.raw);
|
|
|
|
|
io_apic_write(ioapic_idx, 0, reg_00.raw);
|
|
|
|
|
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Sanity check
|
|
|
|
|
*/
|
|
|
|
|
raw_spin_lock_irqsave(&ioapic_lock, flags);
|
|
|
|
|
reg_00.raw = io_apic_read(apic_id, 0);
|
|
|
|
|
reg_00.raw = io_apic_read(ioapic_idx, 0);
|
|
|
|
|
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
|
|
|
if (reg_00.bits.ID != mpc_ioapic_id(apic_id))
|
|
|
|
|
if (reg_00.bits.ID != mpc_ioapic_id(ioapic_idx))
|
|
|
|
|
printk("could not set ID!\n");
|
|
|
|
|
else
|
|
|
|
|
apic_printk(APIC_VERBOSE, " ok.\n");
|
|
|
|
@ -3001,27 +3005,26 @@ static int __init io_apic_bug_finalize(void)
|
|
|
|
|
|
|
|
|
|
late_initcall(io_apic_bug_finalize);
|
|
|
|
|
|
|
|
|
|
static void resume_ioapic_id(int ioapic_id)
|
|
|
|
|
static void resume_ioapic_id(int ioapic_idx)
|
|
|
|
|
{
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
union IO_APIC_reg_00 reg_00;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
raw_spin_lock_irqsave(&ioapic_lock, flags);
|
|
|
|
|
reg_00.raw = io_apic_read(ioapic_id, 0);
|
|
|
|
|
if (reg_00.bits.ID != mpc_ioapic_id(ioapic_id)) {
|
|
|
|
|
reg_00.bits.ID = mpc_ioapic_id(ioapic_id);
|
|
|
|
|
io_apic_write(ioapic_id, 0, reg_00.raw);
|
|
|
|
|
reg_00.raw = io_apic_read(ioapic_idx, 0);
|
|
|
|
|
if (reg_00.bits.ID != mpc_ioapic_id(ioapic_idx)) {
|
|
|
|
|
reg_00.bits.ID = mpc_ioapic_id(ioapic_idx);
|
|
|
|
|
io_apic_write(ioapic_idx, 0, reg_00.raw);
|
|
|
|
|
}
|
|
|
|
|
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ioapic_resume(void)
|
|
|
|
|
{
|
|
|
|
|
int ioapic_id;
|
|
|
|
|
int ioapic_idx;
|
|
|
|
|
|
|
|
|
|
for (ioapic_id = nr_ioapics - 1; ioapic_id >= 0; ioapic_id--)
|
|
|
|
|
resume_ioapic_id(ioapic_id);
|
|
|
|
|
for (ioapic_idx = nr_ioapics - 1; ioapic_idx >= 0; ioapic_idx--)
|
|
|
|
|
resume_ioapic_id(ioapic_idx);
|
|
|
|
|
|
|
|
|
|
restore_ioapic_entries();
|
|
|
|
|
}
|
|
|
|
@ -3558,26 +3561,25 @@ io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
ret = __add_pin_to_irq_node(cfg, node, attr->ioapic, attr->ioapic_pin);
|
|
|
|
|
if (!ret)
|
|
|
|
|
setup_ioapic_irq(attr->ioapic, attr->ioapic_pin, irq, cfg,
|
|
|
|
|
attr->trigger, attr->polarity);
|
|
|
|
|
setup_ioapic_irq(irq, cfg, attr);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int io_apic_setup_irq_pin_once(unsigned int irq, int node,
|
|
|
|
|
struct io_apic_irq_attr *attr)
|
|
|
|
|
{
|
|
|
|
|
unsigned int id = attr->ioapic, pin = attr->ioapic_pin;
|
|
|
|
|
unsigned int ioapic_idx = attr->ioapic, pin = attr->ioapic_pin;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
/* Avoid redundant programming */
|
|
|
|
|
if (test_bit(pin, ioapics[id].pin_programmed)) {
|
|
|
|
|
if (test_bit(pin, ioapics[ioapic_idx].pin_programmed)) {
|
|
|
|
|
pr_debug("Pin %d-%d already programmed\n",
|
|
|
|
|
mpc_ioapic_id(id), pin);
|
|
|
|
|
mpc_ioapic_id(ioapic_idx), pin);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
ret = io_apic_setup_irq_pin(irq, node, attr);
|
|
|
|
|
if (!ret)
|
|
|
|
|
set_bit(pin, ioapics[id].pin_programmed);
|
|
|
|
|
set_bit(pin, ioapics[ioapic_idx].pin_programmed);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3613,7 +3615,6 @@ int get_nr_irqs_gsi(void)
|
|
|
|
|
return nr_irqs_gsi;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SPARSE_IRQ
|
|
|
|
|
int __init arch_probe_nr_irqs(void)
|
|
|
|
|
{
|
|
|
|
|
int nr;
|
|
|
|
@ -3633,7 +3634,6 @@ int __init arch_probe_nr_irqs(void)
|
|
|
|
|
|
|
|
|
|
return NR_IRQS_LEGACY;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
int io_apic_set_pci_routing(struct device *dev, int irq,
|
|
|
|
|
struct io_apic_irq_attr *irq_attr)
|
|
|
|
|