Commit f036d4ea authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] ia32 Message Signalled Interrupt support

From: long <tlnguyen@snoqualmie.dp.intel.com>


Add support for Message Signalled Interrupt delivery on ia32.

With a fix from Zwane Mwaikambo <zwane@arm.linux.org.uk>
parent 82b699a6
This diff is collapsed.
...@@ -1030,6 +1030,25 @@ config PCI_DIRECT ...@@ -1030,6 +1030,25 @@ config PCI_DIRECT
depends on PCI && ((PCI_GODIRECT || PCI_GOANY) || X86_VISWS) depends on PCI && ((PCI_GODIRECT || PCI_GOANY) || X86_VISWS)
default y default y
config PCI_USE_VECTOR
bool "Vector-based interrupt indexing"
depends on X86_LOCAL_APIC
default n
help
This replaces the current existing IRQ-based index interrupt scheme
with the vector-base index scheme. The advantages of vector base
over IRQ base are listed below:
1) Support MSI implementation.
2) Support future IOxAPIC hotplug
Note that this enables MSI, Message Signaled Interrupt, on all
MSI capable device functions detected if users also install the
MSI patch. Message Signal Interrupt enables an MSI-capable
hardware device to send an inbound Memory Write on its PCI bus
instead of asserting IRQ signal on device IRQ pin.
If you don't know what to do here, say N.
source "drivers/pci/Kconfig" source "drivers/pci/Kconfig"
config ISA config ISA
......
...@@ -419,8 +419,10 @@ void __init init_IRQ(void) ...@@ -419,8 +419,10 @@ void __init init_IRQ(void)
* us. (some of these will be overridden and become * us. (some of these will be overridden and become
* 'special' SMP interrupts) * 'special' SMP interrupts)
*/ */
for (i = 0; i < NR_IRQS; i++) { for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
int vector = FIRST_EXTERNAL_VECTOR + i; int vector = FIRST_EXTERNAL_VECTOR + i;
if (i >= NR_IRQS)
break;
if (vector != SYSCALL_VECTOR) if (vector != SYSCALL_VECTOR)
set_intr_gate(vector, interrupt[i]); set_intr_gate(vector, interrupt[i]);
} }
......
...@@ -76,6 +76,14 @@ static struct irq_pin_list { ...@@ -76,6 +76,14 @@ static struct irq_pin_list {
int apic, pin, next; int apic, pin, next;
} irq_2_pin[PIN_MAP_SIZE]; } irq_2_pin[PIN_MAP_SIZE];
#ifdef CONFIG_PCI_USE_VECTOR
int vector_irq[NR_IRQS] = { [0 ... NR_IRQS -1] = -1};
#define vector_to_irq(vector) \
(platform_legacy_irq(vector) ? vector : vector_irq[vector])
#else
#define vector_to_irq(vector) (vector)
#endif
/* /*
* The common case is 1:1 IRQ<->pin mappings. Sometimes there are * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
* shared ISA-space IRQs, so we have to support them. We are super * shared ISA-space IRQs, so we have to support them. We are super
...@@ -249,7 +257,7 @@ static void clear_IO_APIC (void) ...@@ -249,7 +257,7 @@ static void clear_IO_APIC (void)
clear_IO_APIC_pin(apic, pin); clear_IO_APIC_pin(apic, pin);
} }
static void set_ioapic_affinity(unsigned int irq, cpumask_t cpumask) static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
{ {
unsigned long flags; unsigned long flags;
int pin; int pin;
...@@ -288,7 +296,7 @@ static void set_ioapic_affinity(unsigned int irq, cpumask_t cpumask) ...@@ -288,7 +296,7 @@ static void set_ioapic_affinity(unsigned int irq, cpumask_t cpumask)
extern cpumask_t irq_affinity[NR_IRQS]; extern cpumask_t irq_affinity[NR_IRQS];
static cpumask_t __cacheline_aligned pending_irq_balance_cpumask[NR_IRQS]; cpumask_t __cacheline_aligned pending_irq_balance_cpumask[NR_IRQS];
#define IRQBALANCE_CHECK_ARCH -999 #define IRQBALANCE_CHECK_ARCH -999
static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH; static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH;
...@@ -670,13 +678,11 @@ static int __init irqbalance_disable(char *str) ...@@ -670,13 +678,11 @@ static int __init irqbalance_disable(char *str)
__setup("noirqbalance", irqbalance_disable); __setup("noirqbalance", irqbalance_disable);
static void set_ioapic_affinity(unsigned int irq, cpumask_t mask);
static inline void move_irq(int irq) static inline void move_irq(int irq)
{ {
/* note - we hold the desc->lock */ /* note - we hold the desc->lock */
if (unlikely(!cpus_empty(pending_irq_balance_cpumask[irq]))) { if (unlikely(!cpus_empty(pending_irq_balance_cpumask[irq]))) {
set_ioapic_affinity(irq, pending_irq_balance_cpumask[irq]); set_ioapic_affinity_irq(irq, pending_irq_balance_cpumask[irq]);
cpus_clear(pending_irq_balance_cpumask[irq]); cpus_clear(pending_irq_balance_cpumask[irq]);
} }
} }
...@@ -853,7 +859,7 @@ void __init setup_ioapic_dest(cpumask_t mask) ...@@ -853,7 +859,7 @@ void __init setup_ioapic_dest(cpumask_t mask)
if (irq_entry == -1) if (irq_entry == -1)
continue; continue;
irq = pin_2_irq(irq_entry, ioapic, pin); irq = pin_2_irq(irq_entry, ioapic, pin);
set_ioapic_affinity(irq, mask); set_ioapic_affinity_irq(irq, mask);
} }
} }
...@@ -1141,7 +1147,8 @@ static inline int IO_APIC_irq_trigger(int irq) ...@@ -1141,7 +1147,8 @@ static inline int IO_APIC_irq_trigger(int irq)
/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 }; u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
static int __init assign_irq_vector(int irq) #ifndef CONFIG_PCI_USE_VECTOR
int __init assign_irq_vector(int irq)
{ {
static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
BUG_ON(irq >= NR_IRQ_VECTORS); BUG_ON(irq >= NR_IRQ_VECTORS);
...@@ -1158,11 +1165,36 @@ static int __init assign_irq_vector(int irq) ...@@ -1158,11 +1165,36 @@ static int __init assign_irq_vector(int irq)
} }
IO_APIC_VECTOR(irq) = current_vector; IO_APIC_VECTOR(irq) = current_vector;
return current_vector; return current_vector;
} }
#endif
static struct hw_interrupt_type ioapic_level_type;
static struct hw_interrupt_type ioapic_edge_type;
#define IOAPIC_AUTO -1
#define IOAPIC_EDGE 0
#define IOAPIC_LEVEL 1
static struct hw_interrupt_type ioapic_level_irq_type; static inline void ioapic_register_intr(int irq, int vector, unsigned long trigger)
static struct hw_interrupt_type ioapic_edge_irq_type; {
if (use_pci_vector() && !platform_legacy_irq(irq)) {
if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
trigger == IOAPIC_LEVEL)
irq_desc[vector].handler = &ioapic_level_type;
else
irq_desc[vector].handler = &ioapic_edge_type;
set_intr_gate(vector, interrupt[vector]);
} else {
if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
trigger == IOAPIC_LEVEL)
irq_desc[irq].handler = &ioapic_level_type;
else
irq_desc[irq].handler = &ioapic_edge_type;
set_intr_gate(vector, interrupt[irq]);
}
}
void __init setup_IO_APIC_irqs(void) void __init setup_IO_APIC_irqs(void)
{ {
...@@ -1220,13 +1252,7 @@ void __init setup_IO_APIC_irqs(void) ...@@ -1220,13 +1252,7 @@ void __init setup_IO_APIC_irqs(void)
if (IO_APIC_IRQ(irq)) { if (IO_APIC_IRQ(irq)) {
vector = assign_irq_vector(irq); vector = assign_irq_vector(irq);
entry.vector = vector; entry.vector = vector;
ioapic_register_intr(irq, vector, IOAPIC_AUTO);
if (IO_APIC_irq_trigger(irq))
irq_desc[irq].handler = &ioapic_level_irq_type;
else
irq_desc[irq].handler = &ioapic_edge_irq_type;
set_intr_gate(vector, interrupt[irq]);
if (!apic && (irq < 16)) if (!apic && (irq < 16))
disable_8259A_irq(irq); disable_8259A_irq(irq);
...@@ -1273,7 +1299,7 @@ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) ...@@ -1273,7 +1299,7 @@ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector)
* The timer IRQ doesn't have to know that behind the * The timer IRQ doesn't have to know that behind the
* scene we have a 8259A-master in AEOI mode ... * scene we have a 8259A-master in AEOI mode ...
*/ */
irq_desc[0].handler = &ioapic_edge_irq_type; irq_desc[0].handler = &ioapic_edge_type;
/* /*
* Add it to the IO-APIC irq-routing table: * Add it to the IO-APIC irq-routing table:
...@@ -1763,9 +1789,6 @@ static int __init timer_irq_works(void) ...@@ -1763,9 +1789,6 @@ static int __init timer_irq_works(void)
* that was delayed but this is now handled in the device * that was delayed but this is now handled in the device
* independent code. * independent code.
*/ */
#define enable_edge_ioapic_irq unmask_IO_APIC_irq
static void disable_edge_ioapic_irq (unsigned int irq) { /* nothing */ }
/* /*
* Starting up a edge-triggered IO-APIC interrupt is * Starting up a edge-triggered IO-APIC interrupt is
...@@ -1776,7 +1799,6 @@ static void disable_edge_ioapic_irq (unsigned int irq) { /* nothing */ } ...@@ -1776,7 +1799,6 @@ static void disable_edge_ioapic_irq (unsigned int irq) { /* nothing */ }
* 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...
*/ */
static unsigned int startup_edge_ioapic_irq(unsigned int irq) static unsigned int startup_edge_ioapic_irq(unsigned int irq)
{ {
int was_pending = 0; int was_pending = 0;
...@@ -1794,8 +1816,6 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq) ...@@ -1794,8 +1816,6 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq)
return was_pending; return was_pending;
} }
#define shutdown_edge_ioapic_irq disable_edge_ioapic_irq
/* /*
* Once we have recorded IRQ_PENDING already, we can mask the * Once we have recorded IRQ_PENDING already, we can mask the
* interrupt for real. This prevents IRQ storms from unhandled * interrupt for real. This prevents IRQ storms from unhandled
...@@ -1810,9 +1830,6 @@ static void ack_edge_ioapic_irq(unsigned int irq) ...@@ -1810,9 +1830,6 @@ static void ack_edge_ioapic_irq(unsigned int irq)
ack_APIC_irq(); ack_APIC_irq();
} }
static void end_edge_ioapic_irq (unsigned int i) { /* nothing */ }
/* /*
* Level triggered interrupts can just be masked, * Level triggered interrupts can just be masked,
* and shutting down and starting up the interrupt * and shutting down and starting up the interrupt
...@@ -1834,10 +1851,6 @@ static unsigned int startup_level_ioapic_irq (unsigned int irq) ...@@ -1834,10 +1851,6 @@ static unsigned int startup_level_ioapic_irq (unsigned int irq)
return 0; /* don't check for pending */ return 0; /* don't check for pending */
} }
#define shutdown_level_ioapic_irq mask_IO_APIC_irq
#define enable_level_ioapic_irq unmask_IO_APIC_irq
#define disable_level_ioapic_irq mask_IO_APIC_irq
static void end_level_ioapic_irq (unsigned int irq) static void end_level_ioapic_irq (unsigned int irq)
{ {
unsigned long v; unsigned long v;
...@@ -1864,6 +1877,7 @@ static void end_level_ioapic_irq (unsigned int irq) ...@@ -1864,6 +1877,7 @@ static void end_level_ioapic_irq (unsigned int irq)
* The idea is from Manfred Spraul. --macro * The idea is from Manfred Spraul. --macro
*/ */
i = IO_APIC_VECTOR(irq); i = IO_APIC_VECTOR(irq);
v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
ack_APIC_irq(); ack_APIC_irq();
...@@ -1898,7 +1912,57 @@ static void end_level_ioapic_irq (unsigned int irq) ...@@ -1898,7 +1912,57 @@ static void end_level_ioapic_irq (unsigned int irq)
} }
} }
static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ } #ifdef CONFIG_PCI_USE_VECTOR
static unsigned int startup_edge_ioapic_vector(unsigned int vector)
{
int irq = vector_to_irq(vector);
return startup_edge_ioapic_irq(irq);
}
static void ack_edge_ioapic_vector(unsigned int vector)
{
int irq = vector_to_irq(vector);
ack_edge_ioapic_irq(irq);
}
static unsigned int startup_level_ioapic_vector (unsigned int vector)
{
int irq = vector_to_irq(vector);
return startup_level_ioapic_irq (irq);
}
static void end_level_ioapic_vector (unsigned int vector)
{
int irq = vector_to_irq(vector);
end_level_ioapic_irq(irq);
}
static void mask_IO_APIC_vector (unsigned int vector)
{
int irq = vector_to_irq(vector);
mask_IO_APIC_irq(irq);
}
static void unmask_IO_APIC_vector (unsigned int vector)
{
int irq = vector_to_irq(vector);
unmask_IO_APIC_irq(irq);
}
static void set_ioapic_affinity_vector (unsigned int vector,
cpumask_t cpu_mask)
{
int irq = vector_to_irq(vector);
set_ioapic_affinity_irq(irq, cpu_mask);
}
#endif
/* /*
* Level and edge triggered IO-APIC interrupts need different handling, * Level and edge triggered IO-APIC interrupts need different handling,
...@@ -1908,26 +1972,25 @@ static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ } ...@@ -1908,26 +1972,25 @@ static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ }
* edge-triggered handler, without risking IRQ storms and other ugly * edge-triggered handler, without risking IRQ storms and other ugly
* races. * races.
*/ */
static struct hw_interrupt_type ioapic_edge_type = {
static struct hw_interrupt_type ioapic_edge_irq_type = {
.typename = "IO-APIC-edge", .typename = "IO-APIC-edge",
.startup = startup_edge_ioapic_irq, .startup = startup_edge_ioapic,
.shutdown = shutdown_edge_ioapic_irq, .shutdown = shutdown_edge_ioapic,
.enable = enable_edge_ioapic_irq, .enable = enable_edge_ioapic,
.disable = disable_edge_ioapic_irq, .disable = disable_edge_ioapic,
.ack = ack_edge_ioapic_irq, .ack = ack_edge_ioapic,
.end = end_edge_ioapic_irq, .end = end_edge_ioapic,
.set_affinity = set_ioapic_affinity, .set_affinity = set_ioapic_affinity,
}; };
static struct hw_interrupt_type ioapic_level_irq_type = { static struct hw_interrupt_type ioapic_level_type = {
.typename = "IO-APIC-level", .typename = "IO-APIC-level",
.startup = startup_level_ioapic_irq, .startup = startup_level_ioapic,
.shutdown = shutdown_level_ioapic_irq, .shutdown = shutdown_level_ioapic,
.enable = enable_level_ioapic_irq, .enable = enable_level_ioapic,
.disable = disable_level_ioapic_irq, .disable = disable_level_ioapic,
.ack = mask_and_ack_level_ioapic_irq, .ack = mask_and_ack_level_ioapic,
.end = end_level_ioapic_irq, .end = end_level_ioapic,
.set_affinity = set_ioapic_affinity, .set_affinity = set_ioapic_affinity,
}; };
...@@ -1947,7 +2010,13 @@ static inline void init_IO_APIC_traps(void) ...@@ -1947,7 +2010,13 @@ static inline void init_IO_APIC_traps(void)
* 0x80, because int 0x80 is hm, kind of importantish. ;) * 0x80, because int 0x80 is hm, kind of importantish. ;)
*/ */
for (irq = 0; irq < NR_IRQS ; irq++) { for (irq = 0; irq < NR_IRQS ; irq++) {
if (IO_APIC_IRQ(irq) && !IO_APIC_VECTOR(irq)) { int tmp = irq;
if (use_pci_vector()) {
if (!platform_legacy_irq(tmp))
if ((tmp = vector_to_irq(tmp)) == -1)
continue;
}
if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) {
/* /*
* Hmm.. We don't have an entry for this, * Hmm.. We don't have an entry for this,
* so default to an old-fashioned 8259 * so default to an old-fashioned 8259
...@@ -2379,10 +2448,12 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a ...@@ -2379,10 +2448,12 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a
"IRQ %d Mode:%i Active:%i)\n", ioapic, "IRQ %d Mode:%i Active:%i)\n", ioapic,
mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low); mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low);
if (use_pci_vector() && !platform_legacy_irq(irq))
irq = IO_APIC_VECTOR(irq);
if (edge_level) { if (edge_level) {
irq_desc[irq].handler = &ioapic_level_irq_type; irq_desc[irq].handler = &ioapic_level_type;
} else { } else {
irq_desc[irq].handler = &ioapic_edge_irq_type; irq_desc[irq].handler = &ioapic_edge_type;
} }
set_intr_gate(entry.vector, interrupt[irq]); set_intr_gate(entry.vector, interrupt[irq]);
......
...@@ -1147,15 +1147,19 @@ void __init mp_parse_prt (void) ...@@ -1147,15 +1147,19 @@ void __init mp_parse_prt (void)
if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) { if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
printk(KERN_DEBUG "Pin %d-%d already programmed\n", printk(KERN_DEBUG "Pin %d-%d already programmed\n",
mp_ioapic_routing[ioapic].apic_id, ioapic_pin); mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
if (use_pci_vector() && !platform_legacy_irq(irq))
irq = IO_APIC_VECTOR(irq);
entry->irq = irq; entry->irq = irq;
continue; continue;
} }
mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit); mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
if (!io_apic_set_pci_routing(ioapic, ioapic_pin, irq, edge_level, active_high_low)) if (!io_apic_set_pci_routing(ioapic, ioapic_pin, irq, edge_level, active_high_low)) {
if (use_pci_vector() && !platform_legacy_irq(irq))
irq = IO_APIC_VECTOR(irq);
entry->irq = irq; entry->irq = irq;
}
printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n", printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n",
entry->id.segment, entry->id.bus, entry->id.segment, entry->id.bus,
entry->id.device, ('A' + entry->pin), entry->id.device, ('A' + entry->pin),
......
...@@ -805,8 +805,10 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) ...@@ -805,8 +805,10 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
if ( dev2->irq && dev2->irq != irq && \ if ( dev2->irq && dev2->irq != irq && \
(!(pci_probe & PCI_USE_PIRQ_MASK) || \ (!(pci_probe & PCI_USE_PIRQ_MASK) || \
((1 << dev2->irq) & mask)) ) { ((1 << dev2->irq) & mask)) ) {
#ifndef CONFIG_PCI_USE_VECTOR
printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n", printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n",
pci_name(dev2), dev2->irq, irq); pci_name(dev2), dev2->irq, irq);
#endif
continue; continue;
} }
dev2->irq = irq; dev2->irq = irq;
...@@ -870,6 +872,10 @@ static void __init pcibios_fixup_irqs(void) ...@@ -870,6 +872,10 @@ static void __init pcibios_fixup_irqs(void)
bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq); bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq);
} }
if (irq >= 0) { if (irq >= 0) {
if (use_pci_vector() &&
!platform_legacy_irq(irq))
irq = IO_APIC_VECTOR(irq);
printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n", printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
dev->bus->number, PCI_SLOT(dev->devfn), pin, irq); dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
dev->irq = irq; dev->irq = irq;
......
...@@ -237,7 +237,7 @@ acpi_pci_irq_add_prt ( ...@@ -237,7 +237,7 @@ acpi_pci_irq_add_prt (
PCI Interrupt Routing Support PCI Interrupt Routing Support
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
static int int
acpi_pci_irq_lookup (struct pci_bus *bus, int device, int pin) acpi_pci_irq_lookup (struct pci_bus *bus, int device, int pin)
{ {
struct acpi_prt_entry *entry = NULL; struct acpi_prt_entry *entry = NULL;
......
...@@ -27,6 +27,7 @@ obj-$(CONFIG_PPC64) += setup-bus.o ...@@ -27,6 +27,7 @@ obj-$(CONFIG_PPC64) += setup-bus.o
obj-$(CONFIG_SGI_IP27) += setup-irq.o obj-$(CONFIG_SGI_IP27) += setup-irq.o
obj-$(CONFIG_SGI_IP32) += setup-irq.o obj-$(CONFIG_SGI_IP32) += setup-irq.o
obj-$(CONFIG_X86_VISWS) += setup-irq.o obj-$(CONFIG_X86_VISWS) += setup-irq.o
obj-$(CONFIG_PCI_USE_VECTOR) += msi.o
# Cardbus & CompactPCI use setup-bus # Cardbus & CompactPCI use setup-bus
obj-$(CONFIG_HOTPLUG) += setup-bus.o obj-$(CONFIG_HOTPLUG) += setup-bus.o
......
This diff is collapsed.
...@@ -552,6 +552,7 @@ int __devinit pci_scan_slot(struct pci_bus *bus, int devfn) ...@@ -552,6 +552,7 @@ int __devinit pci_scan_slot(struct pci_bus *bus, int devfn)
struct pci_dev *dev; struct pci_dev *dev;
dev = pci_scan_device(bus, devfn); dev = pci_scan_device(bus, devfn);
pci_scan_msi_device(dev);
if (func == 0) { if (func == 0) {
if (!dev) if (!dev)
break; break;
......
...@@ -14,6 +14,8 @@ static void pci_free_resources(struct pci_dev *dev) ...@@ -14,6 +14,8 @@ static void pci_free_resources(struct pci_dev *dev)
{ {
int i; int i;
msi_remove_pci_irq_vectors(dev);
for (i = 0; i < PCI_NUM_RESOURCES; i++) { for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *res = dev->resource + i; struct resource *res = dev->resource + i;
if (res->parent) if (res->parent)
......
...@@ -41,6 +41,7 @@ asmlinkage void apic_timer_interrupt(void); ...@@ -41,6 +41,7 @@ asmlinkage void apic_timer_interrupt(void);
asmlinkage void error_interrupt(void); asmlinkage void error_interrupt(void);
asmlinkage void spurious_interrupt(void); asmlinkage void spurious_interrupt(void);
asmlinkage void thermal_interrupt(struct pt_regs); asmlinkage void thermal_interrupt(struct pt_regs);
#define platform_legacy_irq(irq) ((irq) < 16)
#endif #endif
void mask_irq(unsigned int irq); void mask_irq(unsigned int irq);
......
...@@ -13,6 +13,46 @@ ...@@ -13,6 +13,46 @@
#ifdef CONFIG_X86_IO_APIC #ifdef CONFIG_X86_IO_APIC
#ifdef CONFIG_PCI_USE_VECTOR
static inline int use_pci_vector(void) {return 1;}
static inline void disable_edge_ioapic_vector(unsigned int vector) { }
static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
static inline void end_edge_ioapic_vector (unsigned int vector) { }
#define startup_level_ioapic startup_level_ioapic_vector
#define shutdown_level_ioapic mask_IO_APIC_vector
#define enable_level_ioapic unmask_IO_APIC_vector
#define disable_level_ioapic mask_IO_APIC_vector
#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector
#define end_level_ioapic end_level_ioapic_vector
#define set_ioapic_affinity set_ioapic_affinity_vector
#define startup_edge_ioapic startup_edge_ioapic_vector
#define shutdown_edge_ioapic disable_edge_ioapic_vector
#define enable_edge_ioapic unmask_IO_APIC_vector
#define disable_edge_ioapic disable_edge_ioapic_vector
#define ack_edge_ioapic ack_edge_ioapic_vector
#define end_edge_ioapic end_edge_ioapic_vector
#else
static inline int use_pci_vector(void) {return 0;}
static inline void disable_edge_ioapic_irq(unsigned int irq) { }
static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { }
static inline void end_edge_ioapic_irq (unsigned int irq) { }
#define startup_level_ioapic startup_level_ioapic_irq
#define shutdown_level_ioapic mask_IO_APIC_irq
#define enable_level_ioapic unmask_IO_APIC_irq
#define disable_level_ioapic mask_IO_APIC_irq
#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq
#define end_level_ioapic end_level_ioapic_irq
#define set_ioapic_affinity set_ioapic_affinity_irq
#define startup_edge_ioapic startup_edge_ioapic_irq
#define shutdown_edge_ioapic disable_edge_ioapic_irq
#define enable_edge_ioapic unmask_IO_APIC_irq
#define disable_edge_ioapic disable_edge_ioapic_irq
#define ack_edge_ioapic ack_edge_ioapic_irq
#define end_edge_ioapic end_edge_ioapic_irq
#endif
#define APIC_MISMATCH_DEBUG #define APIC_MISMATCH_DEBUG
#define IO_APIC_BASE(idx) \ #define IO_APIC_BASE(idx) \
...@@ -177,4 +217,6 @@ extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level ...@@ -177,4 +217,6 @@ extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level
#define io_apic_assign_pci_irqs 0 #define io_apic_assign_pci_irqs 0
#endif #endif
extern int assign_irq_vector(int irq);
#endif #endif
...@@ -76,6 +76,18 @@ ...@@ -76,6 +76,18 @@
* Since vectors 0x00-0x1f are used/reserved for the CPU, * Since vectors 0x00-0x1f are used/reserved for the CPU,
* the usable vector space is 0x20-0xff (224 vectors) * the usable vector space is 0x20-0xff (224 vectors)
*/ */
/*
* The maximum number of vectors supported by i386 processors
* is limited to 256. For processors other than i386, NR_VECTORS
* should be changed accordingly.
*/
#define NR_VECTORS 256
#ifdef CONFIG_PCI_USE_VECTOR
#define NR_IRQS FIRST_SYSTEM_VECTOR
#define NR_IRQ_VECTORS NR_IRQS
#else
#ifdef CONFIG_X86_IO_APIC #ifdef CONFIG_X86_IO_APIC
#define NR_IRQS 224 #define NR_IRQS 224
# if (224 >= 32 * NR_CPUS) # if (224 >= 32 * NR_CPUS)
...@@ -87,6 +99,7 @@ ...@@ -87,6 +99,7 @@
#define NR_IRQS 16 #define NR_IRQS 16
#define NR_IRQ_VECTORS NR_IRQS #define NR_IRQ_VECTORS NR_IRQS
#endif #endif
#endif
#define FPU_IRQ 13 #define FPU_IRQ 13
......
...@@ -173,6 +173,8 @@ static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) { ...@@ -173,6 +173,8 @@ static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {
static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {} static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
#endif #endif
#define platform_legacy_irq(irq) ((irq) < 16)
#endif #endif
#endif /* _ASM_HW_IRQ_H */ #endif /* _ASM_HW_IRQ_H */
...@@ -174,6 +174,25 @@ extern int sis_apic_bug; /* dummy */ ...@@ -174,6 +174,25 @@ extern int sis_apic_bug; /* dummy */
#define io_apic_assign_pci_irqs 0 #define io_apic_assign_pci_irqs 0
#endif #endif
static inline int use_pci_vector(void) {return 0;}
static inline void disable_edge_ioapic_irq(unsigned int irq) { }
static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { }
static inline void end_edge_ioapic_irq (unsigned int irq) { }
#define startup_level_ioapic startup_level_ioapic_irq
#define shutdown_level_ioapic mask_IO_APIC_irq
#define enable_level_ioapic unmask_IO_APIC_irq
#define disable_level_ioapic mask_IO_APIC_irq
#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq
#define end_level_ioapic end_level_ioapic_irq
#define set_ioapic_affinity set_ioapic_affinity_irq
#define startup_edge_ioapic startup_edge_ioapic_irq
#define shutdown_edge_ioapic disable_edge_ioapic_irq
#define enable_edge_ioapic unmask_IO_APIC_irq
#define disable_edge_ioapic disable_edge_ioapic_irq
#define ack_edge_ioapic ack_edge_ioapic_irq
#define end_edge_ioapic end_edge_ioapic_irq
void enable_NMI_through_LVT0 (void * dummy); void enable_NMI_through_LVT0 (void * dummy);
#endif #endif
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ #define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */
#define PCI_COMMAND_SERR 0x100 /* Enable SERR */ #define PCI_COMMAND_SERR 0x100 /* Enable SERR */
#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ #define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */
#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
#define PCI_STATUS 0x06 /* 16 bits */ #define PCI_STATUS 0x06 /* 16 bits */
#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ #define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
...@@ -198,6 +199,8 @@ ...@@ -198,6 +199,8 @@
#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ #define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */
#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ #define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */
#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ #define PCI_CAP_ID_PCIX 0x07 /* PCI-X */
#define PCI_CAP_ID_EXP 0x10 /* PCI Express */
#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ #define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */
#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ #define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */
#define PCI_CAP_SIZEOF 4 #define PCI_CAP_SIZEOF 4
...@@ -275,11 +278,13 @@ ...@@ -275,11 +278,13 @@
#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */ #define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */
#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */ #define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */
#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */ #define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */
#define PCI_MSI_FLAGS_MASKBIT 0x100 /* 64-bit mask bits allowed */
#define PCI_MSI_RFU 3 /* Rest of capability flags */ #define PCI_MSI_RFU 3 /* Rest of capability flags */
#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */ #define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */
#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ #define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */ #define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */
#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ #define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
#define PCI_MSI_MASK_BIT 16 /* Mask bits register */
/* CompactPCI Hotswap Register */ /* CompactPCI Hotswap Register */
...@@ -695,6 +700,18 @@ void pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t addr); ...@@ -695,6 +700,18 @@ void pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t addr);
extern struct pci_dev *isa_bridge; extern struct pci_dev *isa_bridge;
#endif #endif
#ifndef CONFIG_PCI_USE_VECTOR
static inline void pci_scan_msi_device(struct pci_dev *dev) {}
static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
#else
extern void pci_scan_msi_device(struct pci_dev *dev);
extern int pci_enable_msi(struct pci_dev *dev);
extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
extern int msi_alloc_vectors(struct pci_dev* dev, int *vector, int nvec);
extern int msi_free_vectors(struct pci_dev* dev, int *vector, int nvec);
#endif
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */
/* Include architecture-dependent settings and functions */ /* Include architecture-dependent settings and functions */
......
/*
* ../include/linux/pci_msi.h
*
*/
#ifndef _ASM_PCI_MSI_H
#define _ASM_PCI_MSI_H
#include <linux/pci.h>
#define MSI_AUTO -1
#define NR_REPEATS 23
#define NR_RESERVED_VECTORS 3 /*FIRST_DEVICE_VECTOR,FIRST_SYSTEM_VECTOR,0x80 */
/*
* Assume the maximum number of hot plug slots supported by the system is about
* ten. The worstcase is that each of these slots is hot-added with a device,
* which has two MSI/MSI-X capable functions. To avoid any MSI-X driver, which
* attempts to request all available vectors, NR_HP_RESERVED_VECTORS is defined
* as below to ensure at least one message is assigned to each detected MSI/
* MSI-X device function.
*/
#define NR_HP_RESERVED_VECTORS 20
extern int vector_irq[NR_IRQS];
extern cpumask_t pending_irq_balance_cpumask[NR_IRQS];
extern void (*interrupt[NR_IRQS])(void);
#ifdef CONFIG_SMP
#define set_msi_irq_affinity set_msi_affinity
#else
#define set_msi_irq_affinity NULL
static inline void move_msi(int vector) {}
#endif
#ifndef CONFIG_X86_IO_APIC
static inline int get_ioapic_vector(struct pci_dev *dev) { return -1;}
static inline void restore_ioapic_irq_handler(int irq) {}
#else
extern void restore_ioapic_irq_handler(int irq);
#endif
/*
* MSI-X Address Register
*/
#define PCI_MSIX_FLAGS_QSIZE 0x7FF
#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
#define PCI_MSIX_FLAGS_BITMASK (1 << 0)
#define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET 0
#define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET 4
#define PCI_MSIX_ENTRY_DATA_OFFSET 8
#define PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET 12
#define PCI_MSIX_ENTRY_SIZE 16
#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
#define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO)
#define msi_upper_address_reg(base) (base + PCI_MSI_ADDRESS_HI)
#define msi_data_reg(base, is64bit) \
( (is64bit == 1) ? base+PCI_MSI_DATA_64 : base+PCI_MSI_DATA_32 )
#define msi_mask_bits_reg(base, is64bit) \
( (is64bit == 1) ? base+PCI_MSI_MASK_BIT : base+PCI_MSI_MASK_BIT-4)
#define msi_disable(control) control &= ~PCI_MSI_FLAGS_ENABLE
#define multi_msi_capable(control) \
(1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1))
#define multi_msi_enable(control, num) \
control |= (((num >> 1) << 4) & PCI_MSI_FLAGS_QSIZE);
#define is_64bit_address(control) (control & PCI_MSI_FLAGS_64BIT)
#define is_mask_bit_support(control) (control & PCI_MSI_FLAGS_MASKBIT)
#define msi_enable(control, num) multi_msi_enable(control, num); \
control |= PCI_MSI_FLAGS_ENABLE
#define msix_control_reg msi_control_reg
#define msix_table_offset_reg(base) (base + 0x04)
#define msix_pba_offset_reg(base) (base + 0x08)
#define msix_enable(control) control |= PCI_MSIX_FLAGS_ENABLE
#define msix_disable(control) control &= ~PCI_MSIX_FLAGS_ENABLE
#define msix_table_size(control) ((control & PCI_MSIX_FLAGS_QSIZE)+1)
#define multi_msix_capable msix_table_size
#define msix_unmask(address) (address & ~PCI_MSIX_FLAGS_BITMASK)
#define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK)
#define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK)
extern char __dbg_str_buf[256];
#define _DEFINE_DBG_BUFFER char __dbg_str_buf[256];
#define _DBG_K_TRACE_ENTRY ((unsigned int)0x00000001)
#define _DBG_K_TRACE_EXIT ((unsigned int)0x00000002)
#define _DBG_K_INFO ((unsigned int)0x00000004)
#define _DBG_K_ERROR ((unsigned int)0x00000008)
#define _DBG_K_TRACE (_DBG_K_TRACE_ENTRY | _DBG_K_TRACE_EXIT)
#define _DEBUG_LEVEL (_DBG_K_INFO | _DBG_K_ERROR | _DBG_K_TRACE)
#define _DBG_PRINT( dbg_flags, args... ) \
if ( _DEBUG_LEVEL & (dbg_flags) ) \
{ \
int len; \
len = sprintf(__dbg_str_buf, "%s:%d: %s ", \
__FILE__, __LINE__, __FUNCTION__ ); \
sprintf(__dbg_str_buf + len, args); \
printk(KERN_INFO "%s\n", __dbg_str_buf); \
}
#define MSI_FUNCTION_TRACE_ENTER \
_DBG_PRINT (_DBG_K_TRACE_ENTRY, "%s", "[Entry]");
#define MSI_FUNCTION_TRACE_EXIT \
_DBG_PRINT (_DBG_K_TRACE_EXIT, "%s", "[Entry]");
/*
* MSI Defined Data Structures
*/
#define MSI_ADDRESS_HEADER 0xfee
#define MSI_ADDRESS_HEADER_SHIFT 12
#define MSI_ADDRESS_HEADER_MASK 0xfff000
#define MSI_TARGET_CPU_SHIFT 4
#define MSI_TARGET_CPU_MASK 0xff
#define MSI_DELIVERY_MODE 0
#define MSI_LEVEL_MODE 1 /* Edge always assert */
#define MSI_TRIGGER_MODE 0 /* MSI is edge sensitive */
#define MSI_LOGICAL_MODE 1
#define MSI_REDIRECTION_HINT_MODE 0
#ifdef CONFIG_SMP
#define MSI_TARGET_CPU logical_smp_processor_id()
#else
#define MSI_TARGET_CPU TARGET_CPUS
#endif
struct msg_data {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u32 vector : 8;
__u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */
__u32 reserved_1 : 3;
__u32 level : 1; /* 0: deassert | 1: assert */
__u32 trigger : 1; /* 0: edge | 1: level */
__u32 reserved_2 : 16;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u32 reserved_2 : 16;
__u32 trigger : 1; /* 0: edge | 1: level */
__u32 level : 1; /* 0: deassert | 1: assert */
__u32 reserved_1 : 3;
__u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */
__u32 vector : 8;
#else
#error "Bitfield endianness not defined! Check your byteorder.h"
#endif
} __attribute__ ((packed));
struct msg_address {
union {
struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u32 reserved_1 : 2;
__u32 dest_mode : 1; /*0:physic | 1:logic */
__u32 redirection_hint: 1; /*0: dedicated CPU
1: lowest priority */
__u32 reserved_2 : 4;
__u32 dest_id : 24; /* Destination ID */
#elif defined(__BIG_ENDIAN_BITFIELD)
__u32 dest_id : 24; /* Destination ID */
__u32 reserved_2 : 4;
__u32 redirection_hint: 1; /*0: dedicated CPU
1: lowest priority */
__u32 dest_mode : 1; /*0:physic | 1:logic */
__u32 reserved_1 : 2;
#else
#error "Bitfield endianness not defined! Check your byteorder.h"
#endif
}u;
__u32 value;
}lo_address;
__u32 hi_address;
} __attribute__ ((packed));
struct msi_desc {
struct {
__u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */
__u8 maskbit : 1; /* mask-pending bit supported ? */
__u8 reserved: 2; /* reserved */
__u8 entry_nr; /* specific enabled entry */
__u8 default_vector; /* default pre-assigned vector */
__u8 current_cpu; /* current destination cpu */
}msi_attrib;
struct {
__u16 head;
__u16 tail;
}link;
unsigned long mask_base;
struct pci_dev *dev;
};
#endif /* _ASM_PCI_MSI_H */
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