summary refs log tree commit diff
path: root/drivers/pci/msi-apic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/msi-apic.c')
-rw-r--r--drivers/pci/msi-apic.c86
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);
+}