diff options
Diffstat (limited to 'arch/i386/kernel/io_apic.c')
-rw-r--r-- | arch/i386/kernel/io_apic.c | 81 |
1 files changed, 58 insertions, 23 deletions
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 100406b..5a12527 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -32,6 +32,7 @@ #include <linux/module.h> #include <linux/sysdev.h> #include <linux/pci.h> +#include <linux/msi.h> #include <asm/io.h> #include <asm/smp.h> @@ -2455,11 +2456,8 @@ void destroy_irq(unsigned int irq) * MSI mesage composition */ #ifdef CONFIG_PCI_MSI -static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) +static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) { - /* For now always this code always uses physical delivery - * mode. - */ int vector; unsigned dest; @@ -2489,34 +2487,71 @@ static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg return vector; } -static void msi_msg_teardown(unsigned int irq) -{ - return; -} - -static void msi_msg_set_affinity(unsigned int irq, cpumask_t mask, struct msi_msg *msg) +#ifdef CONFIG_SMP +static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) { + struct msi_msg msg; + unsigned int dest; + cpumask_t tmp; int vector; - unsigned dest; + + cpus_and(tmp, mask, cpu_online_map); + if (cpus_empty(tmp)) + tmp = TARGET_CPUS; vector = assign_irq_vector(irq); - if (vector > 0) { - dest = cpu_mask_to_apicid(mask); + if (vector < 0) + return; - msg->data &= ~MSI_DATA_VECTOR_MASK; - msg->data |= MSI_DATA_VECTOR(vector); - msg->address_lo &= ~MSI_ADDR_DEST_ID_MASK; - msg->address_lo |= MSI_ADDR_DEST_ID(dest); - } + dest = cpu_mask_to_apicid(mask); + + read_msi_msg(irq, &msg); + + msg.data &= ~MSI_DATA_VECTOR_MASK; + msg.data |= MSI_DATA_VECTOR(vector); + msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; + msg.address_lo |= MSI_ADDR_DEST_ID(dest); + + write_msi_msg(irq, &msg); + set_native_irq_info(irq, mask); } +#endif /* CONFIG_SMP */ -struct msi_ops arch_msi_ops = { - .needs_64bit_address = 0, - .setup = msi_msg_setup, - .teardown = msi_msg_teardown, - .target = msi_msg_set_affinity, +/* + * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, + * which implement the MSI or MSI-X Capability Structure. + */ +static struct irq_chip msi_chip = { + .name = "PCI-MSI", + .unmask = unmask_msi_irq, + .mask = mask_msi_irq, + .ack = ack_ioapic_irq, +#ifdef CONFIG_SMP + .set_affinity = set_msi_irq_affinity, +#endif + .retrigger = ioapic_retrigger_irq, }; +int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) +{ + struct msi_msg msg; + int ret; + ret = msi_compose_msg(dev, irq, &msg); + if (ret < 0) + return ret; + + write_msi_msg(irq, &msg); + + set_irq_chip_and_handler(irq, &msi_chip, handle_edge_irq); + + return 0; +} + +void arch_teardown_msi_irq(unsigned int irq) +{ + return; +} + #endif /* CONFIG_PCI_MSI */ /* |