diff options
Diffstat (limited to 'drivers/pci/msi-apic.c')
-rw-r--r-- | drivers/pci/msi-apic.c | 86 |
1 files changed, 64 insertions, 22 deletions
diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c index afc0ed13aa89..822e59a1b822 100644 --- a/drivers/pci/msi-apic.c +++ b/drivers/pci/msi-apic.c @@ -4,10 +4,9 @@ #include <linux/pci.h> #include <linux/irq.h> +#include <linux/msi.h> #include <asm/smp.h> -#include "msi.h" - /* * Shifts for APIC-based data */ @@ -31,6 +30,7 @@ * Shift/mask fields for APIC-based bus address */ +#define MSI_TARGET_CPU_SHIFT 4 #define MSI_ADDR_HEADER 0xfee00000 #define MSI_ADDR_DESTID_MASK 0xfff0000f @@ -44,58 +44,100 @@ #define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) #define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) +static struct irq_chip ia64_msi_chip; -static void -msi_target_apic(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg) +#ifdef CONFIG_SMP +static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask) { - u32 addr = msg->address_lo; + struct msi_msg msg; + u32 addr; + + read_msi_msg(irq, &msg); + addr = msg.address_lo; addr &= MSI_ADDR_DESTID_MASK; addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask))); + msg.address_lo = addr; - msg->address_lo = addr; + write_msi_msg(irq, &msg); + set_native_irq_info(irq, cpu_mask); } +#endif /* CONFIG_SMP */ -static int -msi_setup_apic(struct pci_dev *pdev, /* unused in generic */ - unsigned int irq, - struct msi_msg *msg) +int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) { + struct msi_msg msg; unsigned long dest_phys_id; unsigned int vector; dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); vector = irq; - msg->address_hi = 0; - msg->address_lo = + msg.address_hi = 0; + msg.address_lo = MSI_ADDR_HEADER | MSI_ADDR_DESTMODE_PHYS | MSI_ADDR_REDIRECTION_CPU | MSI_ADDR_DESTID_CPU(dest_phys_id); - msg->data = + msg.data = MSI_DATA_TRIGGER_EDGE | MSI_DATA_LEVEL_ASSERT | MSI_DATA_DELIVERY_FIXED | MSI_DATA_VECTOR(vector); + write_msi_msg(irq, &msg); + set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq); + return 0; } -static void -msi_teardown_apic(unsigned int irq) +void ia64_teardown_msi_irq(unsigned int irq) { return; /* no-op */ } +static void ia64_ack_msi_irq(unsigned int irq) +{ + move_native_irq(irq); + ia64_eoi(); +} + +static int ia64_msi_retrigger_irq(unsigned int irq) +{ + unsigned int vector = irq; + ia64_resend_irq(vector); + + return 1; +} + /* - * Generic ops used on most IA archs/platforms. Set with msi_register() + * Generic ops used on most IA64 platforms. */ - -struct msi_ops msi_apic_ops = { - .needs_64bit_address = 0, - .setup = msi_setup_apic, - .teardown = msi_teardown_apic, - .target = msi_target_apic, +static struct irq_chip ia64_msi_chip = { + .name = "PCI-MSI", + .mask = mask_msi_irq, + .unmask = unmask_msi_irq, + .ack = ia64_ack_msi_irq, +#ifdef CONFIG_SMP + .set_affinity = ia64_set_msi_irq_affinity, +#endif + .retrigger = ia64_msi_retrigger_irq, }; + + +int arch_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) +{ + if (platform_setup_msi_irq) + return platform_setup_msi_irq(irq, pdev); + + return ia64_setup_msi_irq(irq, pdev); +} + +void arch_teardown_msi_irq(unsigned int irq) +{ + if (platform_teardown_msi_irq) + return platform_teardown_msi_irq(irq); + + return ia64_teardown_msi_irq(irq); +} |