diff -urN oldtree/arch/i386/kernel/io_apic.c newtree.2/arch/i386/kernel/io_apic.c
--- oldtree/arch/i386/kernel/io_apic.c	2006-09-24 17:03:56.000000000 -0400
+++ newtree.2/arch/i386/kernel/io_apic.c	2006-09-28 16:40:32.000000000 -0400
@@ -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 @@
  * 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 @@
 	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 */
 
 /*
diff -urN oldtree/arch/ia64/kernel/Makefile newtree.2/arch/ia64/kernel/Makefile
--- oldtree/arch/ia64/kernel/Makefile	2006-09-24 17:03:56.000000000 -0400
+++ newtree.2/arch/ia64/kernel/Makefile	2006-09-28 16:40:37.000000000 -0400
@@ -31,6 +31,7 @@
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o crash.o
 obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR)	+= uncached.o
 obj-$(CONFIG_AUDIT)		+= audit.o
+obj-$(CONFIG_PCI_MSI)		+= msi_ia64.o
 mca_recovery-y			+= mca_drv.o mca_drv_asm.o
 
 obj-$(CONFIG_IA64_ESI)		+= esi.o
diff -urN oldtree/arch/ia64/kernel/msi_ia64.c newtree.2/arch/ia64/kernel/msi_ia64.c
--- oldtree/arch/ia64/kernel/msi_ia64.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree.2/arch/ia64/kernel/msi_ia64.c	2006-09-28 16:40:37.000000000 -0400
@@ -0,0 +1,143 @@
+/*
+ * MSI hooks for standard x86 apic
+ */
+
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <linux/msi.h>
+#include <asm/smp.h>
+
+/*
+ * Shifts for APIC-based data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT		0
+#define	    MSI_DATA_VECTOR(v)		(((u8)v) << MSI_DATA_VECTOR_SHIFT)
+
+#define MSI_DATA_DELIVERY_SHIFT		8
+#define     MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_SHIFT)
+#define     MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT		14
+#define     MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
+#define     MSI_DATA_LEVEL_ASSERT	(1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT		15
+#define     MSI_DATA_TRIGGER_EDGE	(0 << MSI_DATA_TRIGGER_SHIFT)
+#define     MSI_DATA_TRIGGER_LEVEL	(1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * 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
+#define     MSI_ADDR_DESTID_CPU(cpu)	((cpu) << MSI_TARGET_CPU_SHIFT)
+
+#define MSI_ADDR_DESTMODE_SHIFT		2
+#define     MSI_ADDR_DESTMODE_PHYS	(0 << MSI_ADDR_DESTMODE_SHIFT)
+#define	    MSI_ADDR_DESTMODE_LOGIC	(1 << MSI_ADDR_DESTMODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT	3
+#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;
+
+#ifdef CONFIG_SMP
+static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
+{
+	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;
+
+	write_msi_msg(irq, &msg);
+	set_native_irq_info(irq, cpu_mask);
+}
+#endif /* CONFIG_SMP */
+
+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 =
+		MSI_ADDR_HEADER |
+		MSI_ADDR_DESTMODE_PHYS |
+		MSI_ADDR_REDIRECTION_CPU |
+		MSI_ADDR_DESTID_CPU(dest_phys_id);
+
+	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;
+}
+
+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 IA64 platforms.
+ */
+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);
+}
diff -urN oldtree/arch/ia64/sn/kernel/Makefile newtree.2/arch/ia64/sn/kernel/Makefile
--- oldtree/arch/ia64/sn/kernel/Makefile	2006-09-24 17:03:56.000000000 -0400
+++ newtree.2/arch/ia64/sn/kernel/Makefile	2006-09-28 16:40:37.000000000 -0400
@@ -19,3 +19,4 @@
 obj-$(CONFIG_IA64_SGI_SN_XP)	+= xpc.o
 xpc-y				:= xpc_main.o xpc_channel.o xpc_partition.o
 obj-$(CONFIG_IA64_SGI_SN_XP)	+= xpnet.o
+obj-$(CONFIG_PCI_MSI)		+= msi_sn.o
diff -urN oldtree/arch/ia64/sn/kernel/msi_sn.c newtree.2/arch/ia64/sn/kernel/msi_sn.c
--- oldtree/arch/ia64/sn/kernel/msi_sn.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree.2/arch/ia64/sn/kernel/msi_sn.c	2006-09-28 16:40:37.000000000 -0400
@@ -0,0 +1,230 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+#include <linux/cpumask.h>
+#include <linux/msi.h>
+
+#include <asm/sn/addrs.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/pcidev.h>
+#include <asm/sn/nodepda.h>
+
+struct sn_msi_info {
+	u64 pci_addr;
+	struct sn_irq_info *sn_irq_info;
+};
+
+static struct sn_msi_info sn_msi_info[NR_IRQS];
+
+static struct irq_chip sn_msi_chip;
+
+void sn_teardown_msi_irq(unsigned int irq)
+{
+	nasid_t nasid;
+	int widget;
+	struct pci_dev *pdev;
+	struct pcidev_info *sn_pdev;
+	struct sn_irq_info *sn_irq_info;
+	struct pcibus_bussoft *bussoft;
+	struct sn_pcibus_provider *provider;
+
+	sn_irq_info = sn_msi_info[irq].sn_irq_info;
+	if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
+		return;
+
+	sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
+	pdev = sn_pdev->pdi_linux_pcidev;
+	provider = SN_PCIDEV_BUSPROVIDER(pdev);
+
+	(*provider->dma_unmap)(pdev,
+			       sn_msi_info[irq].pci_addr,
+			       PCI_DMA_FROMDEVICE);
+	sn_msi_info[irq].pci_addr = 0;
+
+	bussoft = SN_PCIDEV_BUSSOFT(pdev);
+	nasid = NASID_GET(bussoft->bs_base);
+	widget = (nasid & 1) ?
+			TIO_SWIN_WIDGETNUM(bussoft->bs_base) :
+			SWIN_WIDGETNUM(bussoft->bs_base);
+
+	sn_intr_free(nasid, widget, sn_irq_info);
+	sn_msi_info[irq].sn_irq_info = NULL;
+
+	return;
+}
+
+int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+{
+	struct msi_msg msg;
+	struct msi_desc *entry;
+	int widget;
+	int status;
+	nasid_t nasid;
+	u64 bus_addr;
+	struct sn_irq_info *sn_irq_info;
+	struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
+	struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
+
+	entry = get_irq_data(irq);
+	if (!entry->msi_attrib.is_64)
+		return -EINVAL;
+
+	if (bussoft == NULL)
+		return -EINVAL;
+
+	if (provider == NULL || provider->dma_map_consistent == NULL)
+		return -EINVAL;
+
+	/*
+	 * Set up the vector plumbing.  Let the prom (via sn_intr_alloc)
+	 * decide which cpu to direct this msi at by default.
+	 */
+
+	nasid = NASID_GET(bussoft->bs_base);
+	widget = (nasid & 1) ?
+			TIO_SWIN_WIDGETNUM(bussoft->bs_base) :
+			SWIN_WIDGETNUM(bussoft->bs_base);
+
+	sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
+	if (! sn_irq_info)
+		return -ENOMEM;
+
+	status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1);
+	if (status) {
+		kfree(sn_irq_info);
+		return -ENOMEM;
+	}
+
+	sn_irq_info->irq_int_bit = -1;		/* mark this as an MSI irq */
+	sn_irq_fixup(pdev, sn_irq_info);
+
+	/* Prom probably should fill these in, but doesn't ... */
+	sn_irq_info->irq_bridge_type = bussoft->bs_asic_type;
+	sn_irq_info->irq_bridge = (void *)bussoft->bs_base;
+
+	/*
+	 * Map the xio address into bus space
+	 */
+	bus_addr = (*provider->dma_map_consistent)(pdev,
+					sn_irq_info->irq_xtalkaddr,
+					sizeof(sn_irq_info->irq_xtalkaddr),
+					SN_DMA_MSI|SN_DMA_ADDR_XIO);
+	if (! bus_addr) {
+		sn_intr_free(nasid, widget, sn_irq_info);
+		kfree(sn_irq_info);
+		return -ENOMEM;
+	}
+
+	sn_msi_info[irq].sn_irq_info = sn_irq_info;
+	sn_msi_info[irq].pci_addr = bus_addr;
+
+	msg.address_hi = (u32)(bus_addr >> 32);
+	msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
+
+	/*
+	 * In the SN platform, bit 16 is a "send vector" bit which
+	 * must be present in order to move the vector through the system.
+	 */
+	msg.data = 0x100 + irq;
+
+#ifdef CONFIG_SMP
+	set_irq_affinity_info(irq, sn_irq_info->irq_cpuid, 0);
+#endif
+
+	write_msi_msg(irq, &msg);
+	set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);
+
+	return 0;
+}
+
+#ifdef CONFIG_SMP
+static void sn_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
+{
+	struct msi_msg msg;
+	int slice;
+	nasid_t nasid;
+	u64 bus_addr;
+	struct pci_dev *pdev;
+	struct pcidev_info *sn_pdev;
+	struct sn_irq_info *sn_irq_info;
+	struct sn_irq_info *new_irq_info;
+	struct sn_pcibus_provider *provider;
+	unsigned int cpu;
+
+	cpu = first_cpu(cpu_mask);
+	sn_irq_info = sn_msi_info[irq].sn_irq_info;
+	if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
+		return;
+
+	/*
+	 * Release XIO resources for the old MSI PCI address
+	 */
+
+	read_msi_msg(irq, &msg);
+        sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
+	pdev = sn_pdev->pdi_linux_pcidev;
+	provider = SN_PCIDEV_BUSPROVIDER(pdev);
+
+	bus_addr = (u64)(msg.address_hi) << 32 | (u64)(msg.address_lo);
+	(*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE);
+	sn_msi_info[irq].pci_addr = 0;
+
+	nasid = cpuid_to_nasid(cpu);
+	slice = cpuid_to_slice(cpu);
+
+	new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice);
+	sn_msi_info[irq].sn_irq_info = new_irq_info;
+	if (new_irq_info == NULL)
+		return;
+
+	/*
+	 * Map the xio address into bus space
+	 */
+
+	bus_addr = (*provider->dma_map_consistent)(pdev,
+					new_irq_info->irq_xtalkaddr,
+					sizeof(new_irq_info->irq_xtalkaddr),
+					SN_DMA_MSI|SN_DMA_ADDR_XIO);
+
+	sn_msi_info[irq].pci_addr = bus_addr;
+	msg.address_hi = (u32)(bus_addr >> 32);
+	msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
+
+	write_msi_msg(irq, &msg);
+	set_native_irq_info(irq, cpu_mask);
+}
+#endif /* CONFIG_SMP */
+
+static void sn_ack_msi_irq(unsigned int irq)
+{
+	move_native_irq(irq);
+	ia64_eoi();
+}
+
+static int sn_msi_retrigger_irq(unsigned int irq)
+{
+	unsigned int vector = irq;
+	ia64_resend_irq(vector);
+
+	return 1;
+}
+
+static struct irq_chip sn_msi_chip = {
+	.name		= "PCI-MSI",
+	.mask		= mask_msi_irq,
+	.unmask		= unmask_msi_irq,
+	.ack		= sn_ack_msi_irq,
+#ifdef CONFIG_SMP
+	.set_affinity	= sn_set_msi_irq_affinity,
+#endif
+	.retrigger	= sn_msi_retrigger_irq,
+};
diff -urN oldtree/arch/x86_64/kernel/io_apic.c newtree.2/arch/x86_64/kernel/io_apic.c
--- oldtree/arch/x86_64/kernel/io_apic.c	2006-09-24 17:03:56.000000000 -0400
+++ newtree.2/arch/x86_64/kernel/io_apic.c	2006-09-28 16:40:32.000000000 -0400
@@ -30,6 +30,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/acpi.h>
 #include <linux/sysdev.h>
+#include <linux/msi.h>
 #ifdef CONFIG_ACPI
 #include <acpi/acpi_bus.h>
 #endif
@@ -1701,11 +1702,8 @@
  * 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;
 
@@ -1739,39 +1737,76 @@
 	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;
+
+	cpus_and(mask, tmp, CPU_MASK_ALL);
 
 	vector = assign_irq_vector(irq, mask);
-	if (vector > 0) {
-		cpumask_t tmp;
+	if (vector < 0)
+		return;
 
-		cpus_clear(tmp);
-		cpu_set(vector >> 8, tmp);
-		dest = cpu_mask_to_apicid(tmp);
+	cpus_clear(tmp);
+	cpu_set(vector >> 8, tmp);
+	dest = cpu_mask_to_apicid(tmp);
 
-		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);
-	}
+	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_apic_edge,
+#ifdef CONFIG_SMP
+	.set_affinity	= set_msi_irq_affinity,
+#endif
+	.retrigger	= ioapic_retrigger_irq,
 };
 
-#endif
+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 */
 
 /*
  * Hypertransport interrupt support
diff -urN oldtree/drivers/pci/Makefile newtree.2/drivers/pci/Makefile
--- oldtree/drivers/pci/Makefile	2006-09-24 17:03:56.000000000 -0400
+++ newtree.2/drivers/pci/Makefile	2006-09-28 16:40:37.000000000 -0400
@@ -14,6 +14,9 @@
 # Build the PCI Hotplug drivers if we were asked to
 obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
 
+# Build the PCI MSI interrupt support
+obj-$(CONFIG_PCI_MSI) += msi.o
+
 #
 # Some architectures use the generic PCI setup functions
 #
@@ -28,12 +31,6 @@
 obj-$(CONFIG_X86_VISWS) += setup-irq.o
 obj-$(CONFIG_HT_IRQ) += htirq.o
 
-msiobj-y := msi.o
-msiobj-$(CONFIG_IA64) += msi-apic.o
-msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
-msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
-obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
-
 #
 # ACPI Related PCI FW Functions
 #
diff -urN oldtree/drivers/pci/msi-altix.c newtree.2/drivers/pci/msi-altix.c
--- oldtree/drivers/pci/msi-altix.c	2006-09-24 17:03:56.000000000 -0400
+++ newtree.2/drivers/pci/msi-altix.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,211 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2006 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/cpumask.h>
-
-#include <asm/sn/addrs.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/pcidev.h>
-#include <asm/sn/nodepda.h>
-
-#include "msi.h"
-
-struct sn_msi_info {
-	u64 pci_addr;
-	struct sn_irq_info *sn_irq_info;
-};
-
-static struct sn_msi_info *sn_msi_info;
-
-static void
-sn_msi_teardown(unsigned int irq)
-{
-	nasid_t nasid;
-	int widget;
-	struct pci_dev *pdev;
-	struct pcidev_info *sn_pdev;
-	struct sn_irq_info *sn_irq_info;
-	struct pcibus_bussoft *bussoft;
-	struct sn_pcibus_provider *provider;
-
-	sn_irq_info = sn_msi_info[irq].sn_irq_info;
-	if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
-		return;
-
-	sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
-	pdev = sn_pdev->pdi_linux_pcidev;
-	provider = SN_PCIDEV_BUSPROVIDER(pdev);
-
-	(*provider->dma_unmap)(pdev,
-			       sn_msi_info[irq].pci_addr,
-			       PCI_DMA_FROMDEVICE);
-	sn_msi_info[irq].pci_addr = 0;
-
-	bussoft = SN_PCIDEV_BUSSOFT(pdev);
-	nasid = NASID_GET(bussoft->bs_base);
-	widget = (nasid & 1) ?
-			TIO_SWIN_WIDGETNUM(bussoft->bs_base) :
-			SWIN_WIDGETNUM(bussoft->bs_base);
-
-	sn_intr_free(nasid, widget, sn_irq_info);
-	sn_msi_info[irq].sn_irq_info = NULL;
-
-	return;
-}
-
-int
-sn_msi_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
-{
-	int widget;
-	int status;
-	nasid_t nasid;
-	u64 bus_addr;
-	struct sn_irq_info *sn_irq_info;
-	struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
-	struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
-
-	if (bussoft == NULL)
-		return -EINVAL;
-
-	if (provider == NULL || provider->dma_map_consistent == NULL)
-		return -EINVAL;
-
-	/*
-	 * Set up the vector plumbing.  Let the prom (via sn_intr_alloc)
-	 * decide which cpu to direct this msi at by default.
-	 */
-
-	nasid = NASID_GET(bussoft->bs_base);
-	widget = (nasid & 1) ?
-			TIO_SWIN_WIDGETNUM(bussoft->bs_base) :
-			SWIN_WIDGETNUM(bussoft->bs_base);
-
-	sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
-	if (! sn_irq_info)
-		return -ENOMEM;
-
-	status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1);
-	if (status) {
-		kfree(sn_irq_info);
-		return -ENOMEM;
-	}
-
-	sn_irq_info->irq_int_bit = -1;		/* mark this as an MSI irq */
-	sn_irq_fixup(pdev, sn_irq_info);
-
-	/* Prom probably should fill these in, but doesn't ... */
-	sn_irq_info->irq_bridge_type = bussoft->bs_asic_type;
-	sn_irq_info->irq_bridge = (void *)bussoft->bs_base;
-
-	/*
-	 * Map the xio address into bus space
-	 */
-	bus_addr = (*provider->dma_map_consistent)(pdev,
-					sn_irq_info->irq_xtalkaddr,
-					sizeof(sn_irq_info->irq_xtalkaddr),
-					SN_DMA_MSI|SN_DMA_ADDR_XIO);
-	if (! bus_addr) {
-		sn_intr_free(nasid, widget, sn_irq_info);
-		kfree(sn_irq_info);
-		return -ENOMEM;
-	}
-
-	sn_msi_info[irq].sn_irq_info = sn_irq_info;
-	sn_msi_info[irq].pci_addr = bus_addr;
-
-	msg->address_hi = (u32)(bus_addr >> 32);
-	msg->address_lo = (u32)(bus_addr & 0x00000000ffffffff);
-
-	/*
-	 * In the SN platform, bit 16 is a "send vector" bit which
-	 * must be present in order to move the vector through the system.
-	 */
-	msg->data = 0x100 + irq;
-
-#ifdef CONFIG_SMP
-	set_irq_affinity_info(irq, sn_irq_info->irq_cpuid, 0);
-#endif
-
-	return 0;
-}
-
-static void
-sn_msi_target(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg)
-{
-	int slice;
-	nasid_t nasid;
-	u64 bus_addr;
-	struct pci_dev *pdev;
-	struct pcidev_info *sn_pdev;
-	struct sn_irq_info *sn_irq_info;
-	struct sn_irq_info *new_irq_info;
-	struct sn_pcibus_provider *provider;
-	unsigned int cpu;
-
-	cpu = first_cpu(cpu_mask);
-	sn_irq_info = sn_msi_info[irq].sn_irq_info;
-	if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
-		return;
-
-	/*
-	 * Release XIO resources for the old MSI PCI address
-	 */
-
-        sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
-	pdev = sn_pdev->pdi_linux_pcidev;
-	provider = SN_PCIDEV_BUSPROVIDER(pdev);
-
-	bus_addr = (u64)(msg->address_hi) << 32 | (u64)(msg->address_lo);
-	(*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE);
-	sn_msi_info[irq].pci_addr = 0;
-
-	nasid = cpuid_to_nasid(cpu);
-	slice = cpuid_to_slice(cpu);
-
-	new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice);
-	sn_msi_info[irq].sn_irq_info = new_irq_info;
-	if (new_irq_info == NULL)
-		return;
-
-	/*
-	 * Map the xio address into bus space
-	 */
-
-	bus_addr = (*provider->dma_map_consistent)(pdev,
-					new_irq_info->irq_xtalkaddr,
-					sizeof(new_irq_info->irq_xtalkaddr),
-					SN_DMA_MSI|SN_DMA_ADDR_XIO);
-
-	sn_msi_info[irq].pci_addr = bus_addr;
-	msg->address_hi = (u32)(bus_addr >> 32);
-	msg->address_lo = (u32)(bus_addr & 0x00000000ffffffff);
-}
-
-struct msi_ops sn_msi_ops = {
-	.needs_64bit_address = 1,
-	.setup = sn_msi_setup,
-	.teardown = sn_msi_teardown,
-#ifdef CONFIG_SMP
-	.target = sn_msi_target,
-#endif
-};
-
-int
-sn_msi_init(void)
-{
-	sn_msi_info =
-		kzalloc(sizeof(struct sn_msi_info) * NR_IRQS, GFP_KERNEL);
-	if (! sn_msi_info)
-		return -ENOMEM;
-
-	msi_register(&sn_msi_ops);
-	return 0;
-}
diff -urN oldtree/drivers/pci/msi-apic.c newtree.2/drivers/pci/msi-apic.c
--- oldtree/drivers/pci/msi-apic.c	2006-09-24 17:03:56.000000000 -0400
+++ newtree.2/drivers/pci/msi-apic.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,101 +0,0 @@
-/*
- * MSI hooks for standard x86 apic
- */
-
-#include <linux/pci.h>
-#include <linux/irq.h>
-#include <asm/smp.h>
-
-#include "msi.h"
-
-/*
- * Shifts for APIC-based data
- */
-
-#define MSI_DATA_VECTOR_SHIFT		0
-#define	    MSI_DATA_VECTOR(v)		(((u8)v) << MSI_DATA_VECTOR_SHIFT)
-
-#define MSI_DATA_DELIVERY_SHIFT		8
-#define     MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_SHIFT)
-#define     MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_SHIFT)
-
-#define MSI_DATA_LEVEL_SHIFT		14
-#define     MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
-#define     MSI_DATA_LEVEL_ASSERT	(1 << MSI_DATA_LEVEL_SHIFT)
-
-#define MSI_DATA_TRIGGER_SHIFT		15
-#define     MSI_DATA_TRIGGER_EDGE	(0 << MSI_DATA_TRIGGER_SHIFT)
-#define     MSI_DATA_TRIGGER_LEVEL	(1 << MSI_DATA_TRIGGER_SHIFT)
-
-/*
- * Shift/mask fields for APIC-based bus address
- */
-
-#define MSI_ADDR_HEADER			0xfee00000
-
-#define MSI_ADDR_DESTID_MASK		0xfff0000f
-#define     MSI_ADDR_DESTID_CPU(cpu)	((cpu) << MSI_TARGET_CPU_SHIFT)
-
-#define MSI_ADDR_DESTMODE_SHIFT		2
-#define     MSI_ADDR_DESTMODE_PHYS	(0 << MSI_ADDR_DESTMODE_SHIFT)
-#define	    MSI_ADDR_DESTMODE_LOGIC	(1 << MSI_ADDR_DESTMODE_SHIFT)
-
-#define MSI_ADDR_REDIRECTION_SHIFT	3
-#define     MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT)
-#define     MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT)
-
-
-static void
-msi_target_apic(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg)
-{
-	u32 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;
-}
-
-static int
-msi_setup_apic(struct pci_dev *pdev,	/* unused in generic */
-		unsigned int irq,
-		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 =
-		MSI_ADDR_HEADER |
-		MSI_ADDR_DESTMODE_PHYS |
-		MSI_ADDR_REDIRECTION_CPU |
-		MSI_ADDR_DESTID_CPU(dest_phys_id);
-
-	msg->data =
-		MSI_DATA_TRIGGER_EDGE |
-		MSI_DATA_LEVEL_ASSERT |
-		MSI_DATA_DELIVERY_FIXED |
-		MSI_DATA_VECTOR(vector);
-
-	return 0;
-}
-
-static void
-msi_teardown_apic(unsigned int irq)
-{
-	return;		/* no-op */
-}
-
-/*
- * Generic ops used on most IA archs/platforms.  Set with msi_register()
- */
-
-struct msi_ops msi_apic_ops = {
-	.needs_64bit_address = 0,
-	.setup = msi_setup_apic,
-	.teardown = msi_teardown_apic,
-	.target = msi_target_apic,
-};
diff -urN oldtree/drivers/pci/msi.c newtree.2/drivers/pci/msi.c
--- oldtree/drivers/pci/msi.c	2006-09-24 17:03:56.000000000 -0400
+++ newtree.2/drivers/pci/msi.c	2006-09-28 16:40:32.000000000 -0400
@@ -15,6 +15,7 @@
 #include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
+#include <linux/msi.h>
 
 #include <asm/errno.h>
 #include <asm/io.h>
@@ -29,15 +30,6 @@
 
 static int pci_msi_enable = 1;
 
-static struct msi_ops *msi_ops;
-
-int
-msi_register(struct msi_ops *ops)
-{
-	msi_ops = ops;
-	return 0;
-}
-
 static int msi_cache_init(void)
 {
 	msi_cachep = kmem_cache_create("msi_cache", sizeof(struct msi_desc),
@@ -53,21 +45,20 @@
 	struct msi_desc *entry;
 
 	entry = msi_desc[irq];
-	if (!entry || !entry->dev || !entry->mask_base)
-		return;
+	BUG_ON(!entry || !entry->dev);
 	switch (entry->msi_attrib.type) {
 	case PCI_CAP_ID_MSI:
-	{
-		int		pos;
-		u32		mask_bits;
-
-		pos = (long)entry->mask_base;
-		pci_read_config_dword(entry->dev, pos, &mask_bits);
-		mask_bits &= ~(1);
-		mask_bits |= flag;
-		pci_write_config_dword(entry->dev, pos, mask_bits);
+		if (entry->msi_attrib.maskbit) {
+			int		pos;
+			u32		mask_bits;
+
+			pos = (long)entry->mask_base;
+			pci_read_config_dword(entry->dev, pos, &mask_bits);
+			mask_bits &= ~(1);
+			mask_bits |= flag;
+			pci_write_config_dword(entry->dev, pos, mask_bits);
+		}
 		break;
-	}
 	case PCI_CAP_ID_MSIX:
 	{
 		int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
@@ -76,12 +67,14 @@
 		break;
 	}
 	default:
+		BUG();
 		break;
 	}
 }
 
-static void read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
+void read_msi_msg(unsigned int irq, struct msi_msg *msg)
 {
+	struct msi_desc *entry = get_irq_data(irq);
 	switch(entry->msi_attrib.type) {
 	case PCI_CAP_ID_MSI:
 	{
@@ -118,8 +111,9 @@
 	}
 }
 
-static void write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
+void write_msi_msg(unsigned int irq, struct msi_msg *msg)
 {
+	struct msi_desc *entry = get_irq_data(irq);
 	switch (entry->msi_attrib.type) {
 	case PCI_CAP_ID_MSI:
 	{
@@ -157,135 +151,16 @@
 	}
 }
 
-#ifdef CONFIG_SMP
-static void set_msi_affinity(unsigned int irq, cpumask_t cpu_mask)
-{
-	struct msi_desc *entry;
-	struct msi_msg msg;
-
-	entry = msi_desc[irq];
-	if (!entry || !entry->dev)
-		return;
-
-	read_msi_msg(entry, &msg);
-	msi_ops->target(irq, cpu_mask, &msg);
-	write_msi_msg(entry, &msg);
-	set_native_irq_info(irq, cpu_mask);
-}
-#else
-#define set_msi_affinity NULL
-#endif /* CONFIG_SMP */
-
-static void mask_MSI_irq(unsigned int irq)
+void mask_msi_irq(unsigned int irq)
 {
 	msi_set_mask_bit(irq, 1);
 }
 
-static void unmask_MSI_irq(unsigned int irq)
+void unmask_msi_irq(unsigned int irq)
 {
 	msi_set_mask_bit(irq, 0);
 }
 
-static unsigned int startup_msi_irq_wo_maskbit(unsigned int irq)
-{
-	struct msi_desc *entry;
-	unsigned long flags;
-
-	spin_lock_irqsave(&msi_lock, flags);
-	entry = msi_desc[irq];
-	if (!entry || !entry->dev) {
-		spin_unlock_irqrestore(&msi_lock, flags);
-		return 0;
-	}
-	entry->msi_attrib.state = 1;	/* Mark it active */
-	spin_unlock_irqrestore(&msi_lock, flags);
-
-	return 0;	/* never anything pending */
-}
-
-static unsigned int startup_msi_irq_w_maskbit(unsigned int irq)
-{
-	startup_msi_irq_wo_maskbit(irq);
-	unmask_MSI_irq(irq);
-	return 0;	/* never anything pending */
-}
-
-static void shutdown_msi_irq(unsigned int irq)
-{
-	struct msi_desc *entry;
-	unsigned long flags;
-
-	spin_lock_irqsave(&msi_lock, flags);
-	entry = msi_desc[irq];
-	if (entry && entry->dev)
-		entry->msi_attrib.state = 0;	/* Mark it not active */
-	spin_unlock_irqrestore(&msi_lock, flags);
-}
-
-static void end_msi_irq_wo_maskbit(unsigned int irq)
-{
-	move_native_irq(irq);
-	ack_APIC_irq();
-}
-
-static void end_msi_irq_w_maskbit(unsigned int irq)
-{
-	move_native_irq(irq);
-	unmask_MSI_irq(irq);
-	ack_APIC_irq();
-}
-
-static void do_nothing(unsigned int irq)
-{
-}
-
-/*
- * Interrupt Type for MSI-X PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI-X Capability Structure.
- */
-static struct hw_interrupt_type msix_irq_type = {
-	.typename	= "PCI-MSI-X",
-	.startup	= startup_msi_irq_w_maskbit,
-	.shutdown	= shutdown_msi_irq,
-	.enable		= unmask_MSI_irq,
-	.disable	= mask_MSI_irq,
-	.ack		= mask_MSI_irq,
-	.end		= end_msi_irq_w_maskbit,
-	.set_affinity	= set_msi_affinity
-};
-
-/*
- * Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI Capability Structure with
- * Mask-and-Pending Bits.
- */
-static struct hw_interrupt_type msi_irq_w_maskbit_type = {
-	.typename	= "PCI-MSI",
-	.startup	= startup_msi_irq_w_maskbit,
-	.shutdown	= shutdown_msi_irq,
-	.enable		= unmask_MSI_irq,
-	.disable	= mask_MSI_irq,
-	.ack		= mask_MSI_irq,
-	.end		= end_msi_irq_w_maskbit,
-	.set_affinity	= set_msi_affinity
-};
-
-/*
- * Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI Capability Structure without
- * Mask-and-Pending Bits.
- */
-static struct hw_interrupt_type msi_irq_wo_maskbit_type = {
-	.typename	= "PCI-MSI",
-	.startup	= startup_msi_irq_wo_maskbit,
-	.shutdown	= shutdown_msi_irq,
-	.enable		= do_nothing,
-	.disable	= do_nothing,
-	.ack		= do_nothing,
-	.end		= end_msi_irq_wo_maskbit,
-	.set_affinity	= set_msi_affinity
-};
-
 static int msi_free_irq(struct pci_dev* dev, int irq);
 static int msi_init(void)
 {
@@ -301,22 +176,6 @@
 		return status;
 	}
 
-	status = msi_arch_init();
-	if (status < 0) {
-		pci_msi_enable = 0;
-		printk(KERN_WARNING
-		       "PCI: MSI arch init failed.  MSI disabled.\n");
-		return status;
-	}
-
-	if (! msi_ops) {
-		pci_msi_enable = 0;
-		printk(KERN_WARNING
-		       "PCI: MSI ops not registered. MSI disabled.\n");
-		status = -EINVAL;
-		return status;
-	}
-
 	status = msi_cache_init();
 	if (status < 0) {
 		pci_msi_enable = 0;
@@ -350,7 +209,7 @@
 	spin_unlock_irqrestore(&msi_lock, flags);
 }
 
-static int create_msi_irq(struct hw_interrupt_type *handler)
+static int create_msi_irq(void)
 {
 	struct msi_desc *entry;
 	int irq;
@@ -365,7 +224,6 @@
 		return -EBUSY;
 	}
 
-	set_irq_chip(irq, handler);
 	set_irq_data(irq, entry);
 
 	return irq;
@@ -555,7 +413,7 @@
 		struct msi_desc *entry;
 
 		entry = msi_desc[irq];
-		read_msi_msg(entry, &entry->msg_save);
+		read_msi_msg(irq, &entry->msg_save);
 
 		tail = msi_desc[irq]->link.tail;
 		irq = tail;
@@ -594,7 +452,7 @@
 	irq = head = dev->irq;
 	while (head != tail) {
 		entry = msi_desc[irq];
-		write_msi_msg(entry, &entry->msg_save);
+		write_msi_msg(irq, &entry->msg_save);
 
 		tail = msi_desc[irq]->link.tail;
 		irq = tail;
@@ -606,39 +464,6 @@
 }
 #endif
 
-static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry)
-{
-	int status;
-	struct msi_msg msg;
-	int pos;
-	u16 control;
-
-	pos = entry->msi_attrib.pos;
-	pci_read_config_word(dev, msi_control_reg(pos), &control);
-
-	/* Configure MSI capability structure */
-	status = msi_ops->setup(dev, dev->irq, &msg);
-	if (status < 0)
-		return status;
-
-	write_msi_msg(entry, &msg);
-	if (entry->msi_attrib.maskbit) {
-		unsigned int maskbits, temp;
-		/* All MSIs are unmasked by default, Mask them all */
-		pci_read_config_dword(dev,
-			msi_mask_bits_reg(pos, is_64bit_address(control)),
-			&maskbits);
-		temp = (1 << multi_msi_capable(control));
-		temp = ((temp - 1) & ~temp);
-		maskbits |= temp;
-		pci_write_config_dword(dev,
-			msi_mask_bits_reg(pos, is_64bit_address(control)),
-			maskbits);
-	}
-
-	return 0;
-}
-
 /**
  * msi_capability_init - configure device's MSI capability structure
  * @dev: pointer to the pci_dev data structure of MSI device function
@@ -654,16 +479,11 @@
 	struct msi_desc *entry;
 	int pos, irq;
 	u16 control;
-	struct hw_interrupt_type *handler;
 
    	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
 	pci_read_config_word(dev, msi_control_reg(pos), &control);
 	/* MSI Entry Initialization */
-	handler = &msi_irq_wo_maskbit_type;
-	if (is_mask_bit_support(control))
-		handler = &msi_irq_w_maskbit_type;
-
-	irq = create_msi_irq(handler);
+	irq = create_msi_irq();
 	if (irq < 0)
 		return irq;
 
@@ -671,22 +491,32 @@
 	entry->link.head = irq;
 	entry->link.tail = irq;
 	entry->msi_attrib.type = PCI_CAP_ID_MSI;
-	entry->msi_attrib.state = 0;			/* Mark it not active */
 	entry->msi_attrib.is_64 = is_64bit_address(control);
 	entry->msi_attrib.entry_nr = 0;
 	entry->msi_attrib.maskbit = is_mask_bit_support(control);
 	entry->msi_attrib.default_irq = dev->irq;	/* Save IOAPIC IRQ */
 	entry->msi_attrib.pos = pos;
-	dev->irq = irq;
-	entry->dev = dev;
 	if (is_mask_bit_support(control)) {
 		entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
 				is_64bit_address(control));
 	}
+	entry->dev = dev;
+	if (entry->msi_attrib.maskbit) {
+		unsigned int maskbits, temp;
+		/* All MSIs are unmasked by default, Mask them all */
+		pci_read_config_dword(dev,
+			msi_mask_bits_reg(pos, is_64bit_address(control)),
+			&maskbits);
+		temp = (1 << multi_msi_capable(control));
+		temp = ((temp - 1) & ~temp);
+		maskbits |= temp;
+		pci_write_config_dword(dev,
+			msi_mask_bits_reg(pos, is_64bit_address(control)),
+			maskbits);
+	}
 	/* Configure MSI capability structure */
-	status = msi_register_init(dev, entry);
-	if (status != 0) {
-		dev->irq = entry->msi_attrib.default_irq;
+	status = arch_setup_msi_irq(irq, dev);
+	if (status < 0) {
 		destroy_msi_irq(irq);
 		return status;
 	}
@@ -695,6 +525,7 @@
 	/* Set MSI enabled bits	 */
 	enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
 
+	dev->irq = irq;
 	return 0;
 }
 
@@ -712,7 +543,6 @@
 				struct msix_entry *entries, int nvec)
 {
 	struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
-	struct msi_msg msg;
 	int status;
 	int irq, pos, i, j, nr_entries, temp = 0;
 	unsigned long phys_addr;
@@ -736,7 +566,7 @@
 
 	/* MSI-X Table Initialization */
 	for (i = 0; i < nvec; i++) {
-		irq = create_msi_irq(&msix_irq_type);
+		irq = create_msi_irq();
 		if (irq < 0)
 			break;
 
@@ -744,7 +574,6 @@
  		j = entries[i].entry;
  		entries[i].vector = irq;
 		entry->msi_attrib.type = PCI_CAP_ID_MSIX;
- 		entry->msi_attrib.state = 0;		/* Mark it not active */
 		entry->msi_attrib.is_64 = 1;
 		entry->msi_attrib.entry_nr = j;
 		entry->msi_attrib.maskbit = 1;
@@ -765,13 +594,12 @@
 		temp = irq;
 		tail = entry;
 		/* Configure MSI-X capability structure */
-		status = msi_ops->setup(dev, irq, &msg);
+		status = arch_setup_msi_irq(irq, dev);
 		if (status < 0) {
 			destroy_msi_irq(irq);
 			break;
 		}
 
-		write_msi_msg(entry, &msg);
 		attach_msi_entry(entry, irq);
 	}
 	if (i != nvec) {
@@ -835,7 +663,6 @@
 int pci_enable_msi(struct pci_dev* dev)
 {
 	int pos, temp, status;
-	u16 control;
 
 	if (pci_msi_supported(dev) < 0)
 		return -EINVAL;
@@ -850,10 +677,6 @@
 	if (!pos)
 		return -EINVAL;
 
-	pci_read_config_word(dev, msi_control_reg(pos), &control);
-	if (!is_64bit_address(control) && msi_ops->needs_64bit_address)
-		return -EINVAL;
-
 	WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI));
 
 	/* Check whether driver already requested for MSI-X irqs */
@@ -897,12 +720,12 @@
 		spin_unlock_irqrestore(&msi_lock, flags);
 		return;
 	}
-	if (entry->msi_attrib.state) {
+	if (irq_has_action(dev->irq)) {
 		spin_unlock_irqrestore(&msi_lock, flags);
 		printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without "
 		       "free_irq() on MSI irq %d\n",
 		       pci_name(dev), dev->irq);
-		BUG_ON(entry->msi_attrib.state > 0);
+		BUG_ON(irq_has_action(dev->irq));
 	} else {
 		default_irq = entry->msi_attrib.default_irq;
 		spin_unlock_irqrestore(&msi_lock, flags);
@@ -920,7 +743,7 @@
 	void __iomem *base;
 	unsigned long flags;
 
-	msi_ops->teardown(irq);
+	arch_teardown_msi_irq(irq);
 
 	spin_lock_irqsave(&msi_lock, flags);
 	entry = msi_desc[irq];
@@ -1035,17 +858,16 @@
 
 	temp = dev->irq;
 	if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
-		int state, irq, head, tail = 0, warning = 0;
+		int irq, head, tail = 0, warning = 0;
 		unsigned long flags;
 
 		irq = head = dev->irq;
 		dev->irq = temp;			/* Restore pin IRQ */
 		while (head != tail) {
 			spin_lock_irqsave(&msi_lock, flags);
-			state = msi_desc[irq]->msi_attrib.state;
 			tail = msi_desc[irq]->link.tail;
 			spin_unlock_irqrestore(&msi_lock, flags);
-			if (state)
+			if (irq_has_action(irq))
 				warning = 1;
 			else if (irq != head)	/* Release MSI-X irq */
 				msi_free_irq(dev, irq);
@@ -1072,7 +894,7 @@
  **/
 void msi_remove_pci_irq_vectors(struct pci_dev* dev)
 {
-	int state, pos, temp;
+	int pos, temp;
 	unsigned long flags;
 
 	if (!pci_msi_enable || !dev)
@@ -1081,14 +903,11 @@
 	temp = dev->irq;		/* Save IOAPIC IRQ */
 	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
 	if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
-		spin_lock_irqsave(&msi_lock, flags);
-		state = msi_desc[dev->irq]->msi_attrib.state;
-		spin_unlock_irqrestore(&msi_lock, flags);
-		if (state) {
+		if (irq_has_action(dev->irq)) {
 			printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
 			       "called without free_irq() on MSI irq %d\n",
 			       pci_name(dev), dev->irq);
-			BUG_ON(state > 0);
+			BUG_ON(irq_has_action(dev->irq));
 		} else /* Release MSI irq assigned to this device */
 			msi_free_irq(dev, dev->irq);
 		dev->irq = temp;		/* Restore IOAPIC IRQ */
@@ -1101,11 +920,10 @@
 		irq = head = dev->irq;
 		while (head != tail) {
 			spin_lock_irqsave(&msi_lock, flags);
-			state = msi_desc[irq]->msi_attrib.state;
 			tail = msi_desc[irq]->link.tail;
 			base = msi_desc[irq]->mask_base;
 			spin_unlock_irqrestore(&msi_lock, flags);
-			if (state)
+			if (irq_has_action(irq))
 				warning = 1;
 			else if (irq != head) /* Release MSI-X irq */
 				msi_free_irq(dev, irq);
diff -urN oldtree/drivers/pci/msi.h newtree.2/drivers/pci/msi.h
--- oldtree/drivers/pci/msi.h	2006-09-24 17:03:56.000000000 -0400
+++ newtree.2/drivers/pci/msi.h	2006-09-28 16:40:32.000000000 -0400
@@ -6,8 +6,6 @@
 #ifndef MSI_H
 #define MSI_H
 
-#include <asm/msi.h>
-
 /*
  * MSI-X Address Register
  */
@@ -49,29 +47,4 @@
 #define msix_mask(address)		(address | PCI_MSIX_FLAGS_BITMASK)
 #define msix_is_pending(address) 	(address & PCI_MSIX_FLAGS_PENDMASK)
 
-struct msi_desc {
-	struct {
-		__u8	type	: 5; 	/* {0: unused, 5h:MSI, 11h:MSI-X} */
-		__u8	maskbit	: 1; 	/* mask-pending bit supported ?   */
-		__u8	state	: 1; 	/* {0: free, 1: busy}		  */
-		__u8	is_64	: 1;	/* Address size: 0=32bit 1=64bit  */
-		__u8	pos;	 	/* Location of the msi capability */
-		__u16	entry_nr;    	/* specific enabled entry 	  */
-		unsigned default_irq;	/* default pre-assigned irq	  */
-	}msi_attrib;
-
-	struct {
-		__u16	head;
-		__u16	tail;
-	}link;
-
-	void __iomem *mask_base;
-	struct pci_dev *dev;
-
-#ifdef CONFIG_PM
-	/* PM save area for MSIX address/data */
-	struct msi_msg msg_save;
-#endif
-};
-
 #endif /* MSI_H */
diff -urN oldtree/include/asm-i386/msi.h newtree.2/include/asm-i386/msi.h
--- oldtree/include/asm-i386/msi.h	2006-09-24 17:03:56.000000000 -0400
+++ newtree.2/include/asm-i386/msi.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
- */
-
-#ifndef ASM_MSI_H
-#define ASM_MSI_H
-
-#include <asm/desc.h>
-#include <mach_apic.h>
-
-extern struct msi_ops arch_msi_ops;
-
-static inline int msi_arch_init(void)
-{
-	msi_register(&arch_msi_ops);
-	return 0;
-}
-
-#endif /* ASM_MSI_H */
diff -urN oldtree/include/asm-ia64/machvec.h newtree.2/include/asm-ia64/machvec.h
--- oldtree/include/asm-ia64/machvec.h	2006-09-24 17:03:56.000000000 -0400
+++ newtree.2/include/asm-ia64/machvec.h	2006-09-28 16:40:32.000000000 -0400
@@ -20,6 +20,7 @@
 struct mm_struct;
 struct pci_bus;
 struct task_struct;
+struct pci_dev;
 
 typedef void ia64_mv_setup_t (char **);
 typedef void ia64_mv_cpu_init_t (void);
@@ -75,7 +76,9 @@
 typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
 typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
 typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
-typedef int ia64_mv_msi_init_t (void);
+
+typedef int ia64_mv_setup_msi_irq_t (unsigned int irq, struct pci_dev *pdev);
+typedef void ia64_mv_teardown_msi_irq_t (unsigned int irq);
 
 static inline void
 machvec_noop (void)
@@ -154,7 +157,8 @@
 #  define platform_readl_relaxed        ia64_mv.readl_relaxed
 #  define platform_readq_relaxed        ia64_mv.readq_relaxed
 #  define platform_migrate		ia64_mv.migrate
-#  define platform_msi_init		ia64_mv.msi_init
+#  define platform_setup_msi_irq	ia64_mv.setup_msi_irq
+#  define platform_teardown_msi_irq	ia64_mv.teardown_msi_irq
 # endif
 
 /* __attribute__((__aligned__(16))) is required to make size of the
@@ -204,7 +208,8 @@
 	ia64_mv_readl_relaxed_t *readl_relaxed;
 	ia64_mv_readq_relaxed_t *readq_relaxed;
 	ia64_mv_migrate_t *migrate;
-	ia64_mv_msi_init_t *msi_init;
+	ia64_mv_setup_msi_irq_t *setup_msi_irq;
+	ia64_mv_teardown_msi_irq_t *teardown_msi_irq;
 } __attribute__((__aligned__(16))); /* align attrib? see above comment */
 
 #define MACHVEC_INIT(name)			\
@@ -250,7 +255,8 @@
 	platform_readl_relaxed,			\
 	platform_readq_relaxed,			\
 	platform_migrate,			\
-	platform_msi_init,			\
+	platform_setup_msi_irq,			\
+	platform_teardown_msi_irq,		\
 }
 
 extern struct ia64_machine_vector ia64_mv;
@@ -404,8 +410,11 @@
 #ifndef platform_migrate
 # define platform_migrate machvec_noop_task
 #endif
-#ifndef platform_msi_init
-# define platform_msi_init	((ia64_mv_msi_init_t*)NULL)
+#ifndef platform_setup_msi_irq
+# define platform_setup_msi_irq		((ia64_mv_setup_msi_irq_t*)NULL)
+#endif
+#ifndef platform_teardown_msi_irq
+# define platform_teardown_msi_irq	((ia64_mv_teardown_msi_irq_t*)NULL)
 #endif
 
 #endif /* _ASM_IA64_MACHVEC_H */
diff -urN oldtree/include/asm-ia64/machvec_sn2.h newtree.2/include/asm-ia64/machvec_sn2.h
--- oldtree/include/asm-ia64/machvec_sn2.h	2006-09-24 17:03:56.000000000 -0400
+++ newtree.2/include/asm-ia64/machvec_sn2.h	2006-09-28 16:40:32.000000000 -0400
@@ -67,7 +67,8 @@
 extern ia64_mv_dma_mapping_error	sn_dma_mapping_error;
 extern ia64_mv_dma_supported		sn_dma_supported;
 extern ia64_mv_migrate_t		sn_migrate;
-extern ia64_mv_msi_init_t		sn_msi_init;
+extern ia64_mv_setup_msi_irq_t		sn_setup_msi_irq;
+extern ia64_mv_teardown_msi_irq_t	sn_teardown_msi_irq;
 
 
 /*
@@ -120,9 +121,11 @@
 #define platform_dma_supported		sn_dma_supported
 #define platform_migrate		sn_migrate
 #ifdef CONFIG_PCI_MSI
-#define platform_msi_init		sn_msi_init
+#define platform_setup_msi_irq		sn_setup_msi_irq
+#define platform_teardown_msi_irq	sn_teardown_msi_irq
 #else
-#define platform_msi_init		((ia64_mv_msi_init_t*)NULL)
+#define platform_setup_msi_irq		((ia64_mv_setup_msi_irq_t*)NULL)
+#define platform_teardown_msi_irq	((ia64_mv_teardown_msi_irq_t*)NULL)
 #endif
 
 #include <asm/sn/io.h>
diff -urN oldtree/include/asm-ia64/msi.h newtree.2/include/asm-ia64/msi.h
--- oldtree/include/asm-ia64/msi.h	2006-09-24 17:03:56.000000000 -0400
+++ newtree.2/include/asm-ia64/msi.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
- */
-
-#ifndef ASM_MSI_H
-#define ASM_MSI_H
-
-#define NR_VECTORS		NR_IRQS
-#define FIRST_DEVICE_VECTOR 	IA64_FIRST_DEVICE_VECTOR
-#define LAST_DEVICE_VECTOR	IA64_LAST_DEVICE_VECTOR
-static inline void set_intr_gate (int nr, void *func) {}
-#define IO_APIC_VECTOR(irq)	(irq)
-#define ack_APIC_irq		ia64_eoi
-#define MSI_TARGET_CPU_SHIFT	4
-
-extern struct msi_ops msi_apic_ops;
-
-static inline int msi_arch_init(void)
-{
-	if (platform_msi_init)
-		return platform_msi_init();
-
-	/* default ops for most ia64 platforms */
-	msi_register(&msi_apic_ops);
-	return 0;
-}
-
-#endif /* ASM_MSI_H */
diff -urN oldtree/include/asm-x86_64/msi.h newtree.2/include/asm-x86_64/msi.h
--- oldtree/include/asm-x86_64/msi.h	2006-09-24 17:03:56.000000000 -0400
+++ newtree.2/include/asm-x86_64/msi.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
- */
-
-#ifndef ASM_MSI_H
-#define ASM_MSI_H
-
-#include <asm/desc.h>
-#include <asm/mach_apic.h>
-#include <asm/smp.h>
-
-extern struct msi_ops arch_msi_ops;
-
-static inline int msi_arch_init(void)
-{
-	msi_register(&arch_msi_ops);
-	return 0;
-}
-
-#endif /* ASM_MSI_H */
diff -urN oldtree/include/linux/irq.h newtree.2/include/linux/irq.h
--- oldtree/include/linux/irq.h	2006-09-24 17:03:56.000000000 -0400
+++ newtree.2/include/linux/irq.h	2006-09-28 16:40:22.000000000 -0400
@@ -373,6 +373,13 @@
 extern int create_irq(void);
 extern void destroy_irq(unsigned int irq);
 
+/* Test to see if a driver has successfully requested an irq */
+static inline int irq_has_action(unsigned int irq)
+{
+	struct irq_desc *desc = irq_desc + irq;
+	return desc->action != NULL;
+}
+
 /* Dynamic irq helper functions */
 extern void dynamic_irq_init(unsigned int irq);
 extern void dynamic_irq_cleanup(unsigned int irq);
diff -urN oldtree/include/linux/msi.h newtree.2/include/linux/msi.h
--- oldtree/include/linux/msi.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree.2/include/linux/msi.h	2006-09-28 16:40:32.000000000 -0400
@@ -0,0 +1,49 @@
+#ifndef LINUX_MSI_H
+#define LINUX_MSI_H
+
+struct msi_msg {
+	u32	address_lo;	/* low 32 bits of msi message address */
+	u32	address_hi;	/* high 32 bits of msi message address */
+	u32	data;		/* 16 bits of msi message data */
+};
+
+/* Heper functions */
+extern void mask_msi_irq(unsigned int irq);
+extern void unmask_msi_irq(unsigned int irq);
+extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
+
+extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
+
+struct msi_desc {
+	struct {
+		__u8	type	: 5; 	/* {0: unused, 5h:MSI, 11h:MSI-X} */
+		__u8	maskbit	: 1; 	/* mask-pending bit supported ?   */
+		__u8	unused	: 1;
+		__u8	is_64	: 1;	/* Address size: 0=32bit 1=64bit  */
+		__u8	pos;	 	/* Location of the msi capability */
+		__u16	entry_nr;    	/* specific enabled entry 	  */
+		unsigned default_irq;	/* default pre-assigned irq	  */
+	}msi_attrib;
+
+	struct {
+		__u16	head;
+		__u16	tail;
+	}link;
+
+	void __iomem *mask_base;
+	struct pci_dev *dev;
+
+#ifdef CONFIG_PM
+	/* PM save area for MSIX address/data */
+	struct msi_msg msg_save;
+#endif
+};
+
+/*
+ * The arch hook for setup up msi irqs
+ */
+int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev);
+void arch_teardown_msi_irq(unsigned int irq);
+
+
+#endif /* LINUX_MSI_H */
diff -urN oldtree/include/linux/pci.h newtree.2/include/linux/pci.h
--- oldtree/include/linux/pci.h	2006-09-24 17:03:56.000000000 -0400
+++ newtree.2/include/linux/pci.h	2006-09-28 16:40:32.000000000 -0400
@@ -599,11 +599,6 @@
 	u16	entry;	/* driver uses to specify entry, OS writes */
 };
 
-struct msi_msg {
-	u32	address_lo;	/* low 32 bits of msi message address */
-	u32	address_hi;	/* high 32 bits of msi message address */
-	u32	data;		/* 16 bits of msi message data */
-};
 
 #ifndef CONFIG_PCI_MSI
 static inline void pci_scan_msi_device(struct pci_dev *dev) {}
@@ -621,68 +616,6 @@
 	struct msix_entry *entries, int nvec);
 extern void pci_disable_msix(struct pci_dev *dev);
 extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
-
-/*
- * MSI operation vector.  Used by the msi core code (drivers/pci/msi.c)
- * to abstract platform-specific tasks relating to MSI address generation
- * and resource management.
- */
-struct msi_ops {
-	int needs_64bit_address;
-	/**
-	 * setup - generate an MSI bus address and data for a given vector
-	 * @pdev: PCI device context (in)
-	 * @irq: irq allocated by the msi core (in)
-	 * @msg: PCI bus address and data for msi message (out)
-	 *
-	 * Description: The setup op is used to generate a PCI bus addres and
-	 * data which the msi core will program into the card MSI capability
-	 * registers.  The setup routine is responsible for picking an initial
-	 * cpu to target the MSI at.  The setup routine is responsible for
-	 * examining pdev to determine the MSI capabilities of the card and
-	 * generating a suitable address/data.  The setup routine is
-	 * responsible for allocating and tracking any system resources it
-	 * needs to route the MSI to the cpu it picks, and for associating
-	 * those resources with the passed in vector.
-	 *
-	 * Returns 0 if the MSI address/data was successfully setup.
-	 **/
-
-	int	(*setup)    (struct pci_dev *pdev, unsigned int irq,
-			     struct msi_msg *msg);
-
-	/**
-	 * teardown - release resources allocated by setup
-	 * @vector: vector context for resources (in)
-	 *
-	 * Description:  The teardown op is used to release any resources
-	 * that were allocated in the setup routine associated with the passed
-	 * in vector.
-	 **/
-
-	void	(*teardown) (unsigned int irq);
-
-	/**
-	 * target - retarget an MSI at a different cpu
-	 * @vector: vector context for resources (in)
-	 * @cpu:  new cpu to direct vector at (in)
-	 * @addr_hi: new value of PCI bus upper 32 bits (in/out)
-	 * @addr_lo: new value of PCI bus lower 32 bits (in/out)
-	 *
-	 * Description:  The target op is used to redirect an MSI vector
-	 * at a different cpu.  addr_hi/addr_lo coming in are the existing
-	 * values that the MSI core has programmed into the card.  The
-	 * target code is responsible for freeing any resources (if any)
-	 * associated with the old address, and generating a new PCI bus
-	 * addr_hi/addr_lo that will redirect the vector at the indicated cpu.
-	 **/
-
-	void	(*target)   (unsigned int irq, cpumask_t cpumask,
-			     struct msi_msg *msg);
-};
-
-extern int msi_register(struct msi_ops *ops);
-
 #endif
 
 #ifdef CONFIG_HT_IRQ
diff -urN oldtree/kernel/irq/chip.c newtree.2/kernel/irq/chip.c
--- oldtree/kernel/irq/chip.c	2006-09-27 13:49:56.000000000 -0400
+++ newtree.2/kernel/irq/chip.c	2006-09-28 16:40:22.000000000 -0400
@@ -151,6 +151,13 @@
 
 	desc = irq_desc + irq;
 	spin_lock_irqsave(&desc->lock, flags);
+	if (desc->action) {
+		spin_unlock_irqrestore(&desc->lock, flags);
+		printk(KERN_ERR "Destroying IRQ%d without calling free_irq\n",
+			irq);
+		WARN_ON(1);
+		return;
+	}
 	desc->handle_irq = handle_bad_irq;
 	desc->chip = &no_irq_chip;
 	spin_unlock_irqrestore(&desc->lock, flags);
Files oldtree/scripts/kconfig/mconf and newtree.2/scripts/kconfig/mconf differ
