aboutsummaryrefslogtreecommitdiffstats
path: root/pci
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2006-01-11 15:52:09 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2006-01-11 15:52:09 -0800
commit9a037602e512dbe57da6d1e33b34e9271e200fa4 (patch)
tree8c152c46225e82bd29c84d75284663f9990fc231 /pci
parent68aa69ec74575d546c16d103310234b013bccde2 (diff)
downloadpatches-9a037602e512dbe57da6d1e33b34e9271e200fa4.tar.gz
pci msi patches from sgi
Diffstat (limited to 'pci')
-rw-r--r--pci/pci-altix-msi-support.patch1005
-rw-r--r--pci/pci-msi-vector-targeting-abstractions.patch699
-rw-r--r--pci/pci-per-platform-ia64_-first-last-_device_vector-definitions.patch151
-rw-r--r--pci/pci-schedule-removal-of-pci_module_init.patch2
4 files changed, 1856 insertions, 1 deletions
diff --git a/pci/pci-altix-msi-support.patch b/pci/pci-altix-msi-support.patch
new file mode 100644
index 0000000000000..b3f79d2d5ca2b
--- /dev/null
+++ b/pci/pci-altix-msi-support.patch
@@ -0,0 +1,1005 @@
+From owner-linux-pci@atrey.karlin.mff.cuni.cz Wed Jan 11 15:43:59 2006
+Date: Wed, 11 Jan 2006 16:16:48 -0600 (CST)
+From: Mark Maule <maule@sgi.com>
+Cc: Tony Luck <tony.luck@intel.com>, gregkh@suse.de, Mark Maule <maule@sgi.com>
+Message-Id: <20060111221648.28765.41741.34942@attica.americas.sgi.com>
+Subject: PCI: altix: msi support
+
+MSI callouts for altix. Involves a fair amount of code reorg in sn irq.c
+code as well as adding some extensions to the altix PCI provider abstaction.
+
+Signed-off-by: Mark Maule <maule@sgi.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/ia64/sn/kernel/io_init.c | 2
+ arch/ia64/sn/kernel/irq.c | 144 +++++++++++---------
+ arch/ia64/sn/pci/msi.c | 200 ++++++++++++++++++++++++++++-
+ arch/ia64/sn/pci/pci_dma.c | 10 -
+ arch/ia64/sn/pci/pcibr/pcibr_dma.c | 62 ++++++--
+ arch/ia64/sn/pci/tioca_provider.c | 8 +
+ arch/ia64/sn/pci/tioce_provider.c | 65 ++++++---
+ include/asm-ia64/sn/intr.h | 10 +
+ include/asm-ia64/sn/pcibr_provider.h | 7 -
+ include/asm-ia64/sn/pcibus_provider_defs.h | 17 ++
+ include/asm-ia64/sn/tiocp.h | 3
+ 11 files changed, 407 insertions(+), 121 deletions(-)
+
+--- gregkh-2.6.orig/arch/ia64/sn/pci/msi.c
++++ gregkh-2.6/arch/ia64/sn/pci/msi.c
+@@ -6,13 +6,205 @@
+ * Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved.
+ */
+
+-#include <asm/errno.h>
++#include <linux/types.h>
++#include <linux/pci.h>
++#include <linux/cpumask.h>
++
++#include <asm/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;
++
++static void
++sn_msi_teardown(unsigned int vector)
++{
++ 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[vector].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[vector].pci_addr,
++ PCI_DMA_FROMDEVICE);
++ sn_msi_info[vector].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[vector].sn_irq_info = NULL;
++
++ return;
++}
+
+ int
+-sn_msi_init(void)
++sn_msi_setup(struct pci_dev *pdev, unsigned int vector,
++ u32 *addr_hi, u32 *addr_lo, u32 *data)
+ {
++ 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, vector, -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;
++
+ /*
+- * return error until MSI is supported on altix platforms
++ * Map the xio address into bus space
+ */
+- return -EINVAL;
++ 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[vector].sn_irq_info = sn_irq_info;
++ sn_msi_info[vector].pci_addr = bus_addr;
++
++ *addr_hi = (u32)(bus_addr >> 32);
++ *addr_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.
++ */
++ *data = 0x100 + (unsigned int)vector;
++
++#ifdef CONFIG_SMP
++ set_irq_affinity_info((vector & 0xff), sn_irq_info->irq_cpuid, 0);
++#endif
++
++ return 0;
++}
++
++static void
++sn_msi_target(unsigned int vector, unsigned int cpu,
++ u32 *addr_hi, u32 *addr_lo)
++{
++ 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;
++
++ sn_irq_info = sn_msi_info[vector].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)(*addr_hi) << 32 | (u64)(*addr_lo);
++ (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE);
++ sn_msi_info[vector].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[vector].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[vector].pci_addr = bus_addr;
++ *addr_hi = (u32)(bus_addr >> 32);
++ *addr_lo = (u32)(bus_addr & 0x00000000ffffffff);
++}
++
++struct msi_ops sn_msi_ops = {
++ .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_VECTORS, GFP_KERNEL);
++ if (! sn_msi_info)
++ return -ENOMEM;
++
++ msi_register(&sn_msi_ops);
++ return 0;
+ }
+--- gregkh-2.6.orig/arch/ia64/sn/kernel/io_init.c
++++ gregkh-2.6/arch/ia64/sn/kernel/io_init.c
+@@ -51,7 +51,7 @@ static int max_pcibus_number = 255; /* D
+ */
+
+ static dma_addr_t
+-sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size)
++sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size, int type)
+ {
+ return 0;
+ }
+--- gregkh-2.6.orig/arch/ia64/sn/kernel/irq.c
++++ gregkh-2.6/arch/ia64/sn/kernel/irq.c
+@@ -25,11 +25,11 @@ static void unregister_intr_pda(struct s
+
+ int sn_force_interrupt_flag = 1;
+ extern int sn_ioif_inited;
+-static struct list_head **sn_irq_lh;
++struct list_head **sn_irq_lh;
+ static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */
+
+-static inline uint64_t sn_intr_alloc(nasid_t local_nasid, int local_widget,
+- u64 sn_irq_info,
++uint64_t sn_intr_alloc(nasid_t local_nasid, int local_widget,
++ struct sn_irq_info *sn_irq_info,
+ int req_irq, nasid_t req_nasid,
+ int req_slice)
+ {
+@@ -39,12 +39,13 @@ static inline uint64_t sn_intr_alloc(nas
+
+ SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT,
+ (u64) SAL_INTR_ALLOC, (u64) local_nasid,
+- (u64) local_widget, (u64) sn_irq_info, (u64) req_irq,
++ (u64) local_widget, __pa(sn_irq_info), (u64) req_irq,
+ (u64) req_nasid, (u64) req_slice);
++
+ return ret_stuff.status;
+ }
+
+-static inline void sn_intr_free(nasid_t local_nasid, int local_widget,
++void sn_intr_free(nasid_t local_nasid, int local_widget,
+ struct sn_irq_info *sn_irq_info)
+ {
+ struct ia64_sal_retval ret_stuff;
+@@ -113,73 +114,91 @@ static void sn_end_irq(unsigned int irq)
+
+ static void sn_irq_info_free(struct rcu_head *head);
+
+-static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
++struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info,
++ nasid_t nasid, int slice)
+ {
+- struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
+- int cpuid, cpuphys;
++ int vector;
++ int cpuphys;
++ int64_t bridge;
++ int local_widget, status;
++ nasid_t local_nasid;
++ struct sn_irq_info *new_irq_info;
++ struct sn_pcibus_provider *pci_provider;
+
+- cpuid = first_cpu(mask);
+- cpuphys = cpu_physical_id(cpuid);
++ new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
++ if (new_irq_info == NULL)
++ return NULL;
+
+- list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
+- sn_irq_lh[irq], list) {
+- uint64_t bridge;
+- int local_widget, status;
+- nasid_t local_nasid;
+- struct sn_irq_info *new_irq_info;
+- struct sn_pcibus_provider *pci_provider;
+-
+- new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
+- if (new_irq_info == NULL)
+- break;
+- memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));
+-
+- bridge = (uint64_t) new_irq_info->irq_bridge;
+- if (!bridge) {
+- kfree(new_irq_info);
+- break; /* irq is not a device interrupt */
+- }
++ memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));
+
+- local_nasid = NASID_GET(bridge);
++ bridge = (uint64_t) new_irq_info->irq_bridge;
++ if (!bridge) {
++ kfree(new_irq_info);
++ return NULL; /* irq is not a device interrupt */
++ }
+
+- if (local_nasid & 1)
+- local_widget = TIO_SWIN_WIDGETNUM(bridge);
+- else
+- local_widget = SWIN_WIDGETNUM(bridge);
+-
+- /* Free the old PROM new_irq_info structure */
+- sn_intr_free(local_nasid, local_widget, new_irq_info);
+- /* Update kernels new_irq_info with new target info */
+- unregister_intr_pda(new_irq_info);
+-
+- /* allocate a new PROM new_irq_info struct */
+- status = sn_intr_alloc(local_nasid, local_widget,
+- __pa(new_irq_info), irq,
+- cpuid_to_nasid(cpuid),
+- cpuid_to_slice(cpuid));
+-
+- /* SAL call failed */
+- if (status) {
+- kfree(new_irq_info);
+- break;
+- }
++ local_nasid = NASID_GET(bridge);
+
+- new_irq_info->irq_cpuid = cpuid;
+- register_intr_pda(new_irq_info);
++ if (local_nasid & 1)
++ local_widget = TIO_SWIN_WIDGETNUM(bridge);
++ else
++ local_widget = SWIN_WIDGETNUM(bridge);
+
+- pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
+- if (pci_provider && pci_provider->target_interrupt)
+- (pci_provider->target_interrupt)(new_irq_info);
+-
+- spin_lock(&sn_irq_info_lock);
+- list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
+- spin_unlock(&sn_irq_info_lock);
+- call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
++ vector = sn_irq_info->irq_irq;
++ /* Free the old PROM new_irq_info structure */
++ sn_intr_free(local_nasid, local_widget, new_irq_info);
++ /* Update kernels new_irq_info with new target info */
++ unregister_intr_pda(new_irq_info);
++
++ /* allocate a new PROM new_irq_info struct */
++ status = sn_intr_alloc(local_nasid, local_widget,
++ new_irq_info, vector,
++ nasid, slice);
++
++ /* SAL call failed */
++ if (status) {
++ kfree(new_irq_info);
++ return NULL;
++ }
++
++ cpuphys = nasid_slice_to_cpuid(nasid, slice);
++ new_irq_info->irq_cpuid = cpuphys;
++ register_intr_pda(new_irq_info);
++
++ pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
++
++ /*
++ * If this represents a line interrupt, target it. If it's
++ * an msi (irq_int_bit < 0), it's already targeted.
++ */
++ if (new_irq_info->irq_int_bit >= 0 &&
++ pci_provider && pci_provider->target_interrupt)
++ (pci_provider->target_interrupt)(new_irq_info);
++
++ spin_lock(&sn_irq_info_lock);
++ list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
++ spin_unlock(&sn_irq_info_lock);
++ call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
+
+ #ifdef CONFIG_SMP
+- set_irq_affinity_info((irq & 0xff), cpuphys, 0);
++ set_irq_affinity_info((vector & 0xff), cpuphys, 0);
+ #endif
+- }
++
++ return new_irq_info;
++}
++
++static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
++{
++ struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
++ nasid_t nasid;
++ int slice;
++
++ nasid = cpuid_to_nasid(first_cpu(mask));
++ slice = cpuid_to_slice(first_cpu(mask));
++
++ list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
++ sn_irq_lh[irq], list)
++ (void)sn_retarget_vector(sn_irq_info, nasid, slice);
+ }
+
+ struct hw_interrupt_type irq_type_sn = {
+@@ -441,5 +460,4 @@ void sn_irq_lh_init(void)
+
+ INIT_LIST_HEAD(sn_irq_lh[i]);
+ }
+-
+ }
+--- gregkh-2.6.orig/arch/ia64/sn/pci/pci_dma.c
++++ gregkh-2.6/arch/ia64/sn/pci/pci_dma.c
+@@ -11,7 +11,7 @@
+
+ #include <linux/module.h>
+ #include <asm/dma.h>
+-#include <asm/sn/pcibr_provider.h>
++#include <asm/sn/intr.h>
+ #include <asm/sn/pcibus_provider_defs.h>
+ #include <asm/sn/pcidev.h>
+ #include <asm/sn/sn_sal.h>
+@@ -113,7 +113,8 @@ void *sn_dma_alloc_coherent(struct devic
+ * resources.
+ */
+
+- *dma_handle = provider->dma_map_consistent(pdev, phys_addr, size);
++ *dma_handle = provider->dma_map_consistent(pdev, phys_addr, size,
++ SN_DMA_ADDR_PHYS);
+ if (!*dma_handle) {
+ printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
+ free_pages((unsigned long)cpuaddr, get_order(size));
+@@ -176,7 +177,7 @@ dma_addr_t sn_dma_map_single(struct devi
+ BUG_ON(dev->bus != &pci_bus_type);
+
+ phys_addr = __pa(cpu_addr);
+- dma_addr = provider->dma_map(pdev, phys_addr, size);
++ dma_addr = provider->dma_map(pdev, phys_addr, size, SN_DMA_ADDR_PHYS);
+ if (!dma_addr) {
+ printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
+ return 0;
+@@ -260,7 +261,8 @@ int sn_dma_map_sg(struct device *dev, st
+ for (i = 0; i < nhwentries; i++, sg++) {
+ phys_addr = SG_ENT_PHYS_ADDRESS(sg);
+ sg->dma_address = provider->dma_map(pdev,
+- phys_addr, sg->length);
++ phys_addr, sg->length,
++ SN_DMA_ADDR_PHYS);
+
+ if (!sg->dma_address) {
+ printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
+--- gregkh-2.6.orig/arch/ia64/sn/pci/pcibr/pcibr_dma.c
++++ gregkh-2.6/arch/ia64/sn/pci/pcibr/pcibr_dma.c
+@@ -41,7 +41,7 @@ extern int sn_ioif_inited;
+
+ static dma_addr_t
+ pcibr_dmamap_ate32(struct pcidev_info *info,
+- uint64_t paddr, size_t req_size, uint64_t flags)
++ uint64_t paddr, size_t req_size, uint64_t flags, int dma_flags)
+ {
+
+ struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info;
+@@ -81,9 +81,12 @@ pcibr_dmamap_ate32(struct pcidev_info *i
+ if (IS_PCIX(pcibus_info))
+ ate_flags &= ~(PCI32_ATE_PREF);
+
+- xio_addr =
+- IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
+- PHYS_TO_TIODMA(paddr);
++ if (SN_DMA_ADDRTYPE(dma_flags == SN_DMA_ADDR_PHYS))
++ xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
++ PHYS_TO_TIODMA(paddr);
++ else
++ xio_addr = paddr;
++
+ offset = IOPGOFF(xio_addr);
+ ate = ate_flags | (xio_addr - offset);
+
+@@ -91,6 +94,13 @@ pcibr_dmamap_ate32(struct pcidev_info *i
+ if (IS_PIC_SOFT(pcibus_info)) {
+ ate |= (pcibus_info->pbi_hub_xid << PIC_ATE_TARGETID_SHFT);
+ }
++
++ /*
++ * If we're mapping for MSI, set the MSI bit in the ATE
++ */
++ if (dma_flags & SN_DMA_MSI)
++ ate |= PCI32_ATE_MSI;
++
+ ate_write(pcibus_info, ate_index, ate_count, ate);
+
+ /*
+@@ -105,20 +115,27 @@ pcibr_dmamap_ate32(struct pcidev_info *i
+ if (pcibus_info->pbi_devreg[internal_device] & PCIBR_DEV_SWAP_DIR)
+ ATE_SWAP_ON(pci_addr);
+
++
+ return pci_addr;
+ }
+
+ static dma_addr_t
+ pcibr_dmatrans_direct64(struct pcidev_info * info, uint64_t paddr,
+- uint64_t dma_attributes)
++ uint64_t dma_attributes, int dma_flags)
+ {
+ struct pcibus_info *pcibus_info = (struct pcibus_info *)
+ ((info->pdi_host_pcidev_info)->pdi_pcibus_info);
+ uint64_t pci_addr;
+
+ /* Translate to Crosstalk View of Physical Address */
+- pci_addr = (IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
+- PHYS_TO_TIODMA(paddr)) | dma_attributes;
++ if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS)
++ pci_addr = IS_PIC_SOFT(pcibus_info) ?
++ PHYS_TO_DMA(paddr) :
++ PHYS_TO_TIODMA(paddr) | dma_attributes;
++ else
++ pci_addr = IS_PIC_SOFT(pcibus_info) ?
++ paddr :
++ paddr | dma_attributes;
+
+ /* Handle Bus mode */
+ if (IS_PCIX(pcibus_info))
+@@ -130,7 +147,9 @@ pcibr_dmatrans_direct64(struct pcidev_in
+ ((uint64_t) pcibus_info->
+ pbi_hub_xid << PIC_PCI64_ATTR_TARG_SHFT);
+ } else
+- pci_addr |= TIOCP_PCI64_CMDTYPE_MEM;
++ pci_addr |= (dma_flags & SN_DMA_MSI) ?
++ TIOCP_PCI64_CMDTYPE_MSI :
++ TIOCP_PCI64_CMDTYPE_MEM;
+
+ /* If PCI mode, func zero uses VCHAN0, every other func uses VCHAN1 */
+ if (!IS_PCIX(pcibus_info) && PCI_FUNC(info->pdi_linux_pcidev->devfn))
+@@ -142,7 +161,7 @@ pcibr_dmatrans_direct64(struct pcidev_in
+
+ static dma_addr_t
+ pcibr_dmatrans_direct32(struct pcidev_info * info,
+- uint64_t paddr, size_t req_size, uint64_t flags)
++ uint64_t paddr, size_t req_size, uint64_t flags, int dma_flags)
+ {
+
+ struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info;
+@@ -158,8 +177,14 @@ pcibr_dmatrans_direct32(struct pcidev_in
+ return 0;
+ }
+
+- xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
+- PHYS_TO_TIODMA(paddr);
++ if (dma_flags & SN_DMA_MSI)
++ return 0;
++
++ if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS)
++ xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
++ PHYS_TO_TIODMA(paddr);
++ else
++ xio_addr = paddr;
+
+ xio_base = pcibus_info->pbi_dir_xbase;
+ offset = xio_addr - xio_base;
+@@ -331,7 +356,7 @@ void sn_dma_flush(uint64_t addr)
+ */
+
+ dma_addr_t
+-pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size)
++pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size, int dma_flags)
+ {
+ dma_addr_t dma_handle;
+ struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
+@@ -348,11 +373,11 @@ pcibr_dma_map(struct pci_dev * hwdev, un
+ */
+
+ dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr,
+- PCI64_ATTR_PREF);
++ PCI64_ATTR_PREF, dma_flags);
+ } else {
+ /* Handle 32-63 bit cards via direct mapping */
+ dma_handle = pcibr_dmatrans_direct32(pcidev_info, phys_addr,
+- size, 0);
++ size, 0, dma_flags);
+ if (!dma_handle) {
+ /*
+ * It is a 32 bit card and we cannot do direct mapping,
+@@ -360,7 +385,8 @@ pcibr_dma_map(struct pci_dev * hwdev, un
+ */
+
+ dma_handle = pcibr_dmamap_ate32(pcidev_info, phys_addr,
+- size, PCI32_ATE_PREF);
++ size, PCI32_ATE_PREF,
++ dma_flags);
+ }
+ }
+
+@@ -369,18 +395,18 @@ pcibr_dma_map(struct pci_dev * hwdev, un
+
+ dma_addr_t
+ pcibr_dma_map_consistent(struct pci_dev * hwdev, unsigned long phys_addr,
+- size_t size)
++ size_t size, int dma_flags)
+ {
+ dma_addr_t dma_handle;
+ struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
+
+ if (hwdev->dev.coherent_dma_mask == ~0UL) {
+ dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr,
+- PCI64_ATTR_BAR);
++ PCI64_ATTR_BAR, dma_flags);
+ } else {
+ dma_handle = (dma_addr_t) pcibr_dmamap_ate32(pcidev_info,
+ phys_addr, size,
+- PCI32_ATE_BAR);
++ PCI32_ATE_BAR, dma_flags);
+ }
+
+ return dma_handle;
+--- gregkh-2.6.orig/arch/ia64/sn/pci/tioca_provider.c
++++ gregkh-2.6/arch/ia64/sn/pci/tioca_provider.c
+@@ -515,11 +515,17 @@ tioca_dma_unmap(struct pci_dev *pdev, dm
+ * use the GART mapped mode.
+ */
+ static uint64_t
+-tioca_dma_map(struct pci_dev *pdev, uint64_t paddr, size_t byte_count)
++tioca_dma_map(struct pci_dev *pdev, uint64_t paddr, size_t byte_count, int dma_flags)
+ {
+ uint64_t mapaddr;
+
+ /*
++ * Not supported for now ...
++ */
++ if (dma_flags & SN_DMA_MSI)
++ return 0;
++
++ /*
+ * If card is 64 or 48 bit addresable, use a direct mapping. 32
+ * bit direct is so restrictive w.r.t. where the memory resides that
+ * we don't use it even though CA has some support.
+--- gregkh-2.6.orig/arch/ia64/sn/pci/tioce_provider.c
++++ gregkh-2.6/arch/ia64/sn/pci/tioce_provider.c
+@@ -52,7 +52,8 @@
+ (ATE_PAGE((start)+(len)-1, pagesize) - ATE_PAGE(start, pagesize) + 1)
+
+ #define ATE_VALID(ate) ((ate) & (1UL << 63))
+-#define ATE_MAKE(addr, ps) (((addr) & ~ATE_PAGEMASK(ps)) | (1UL << 63))
++#define ATE_MAKE(addr, ps, msi) \
++ (((addr) & ~ATE_PAGEMASK(ps)) | (1UL << 63) | ((msi)?(1UL << 62):0))
+
+ /*
+ * Flavors of ate-based mapping supported by tioce_alloc_map()
+@@ -78,15 +79,17 @@
+ *
+ * 63 - must be 1 to indicate d64 mode to CE hardware
+ * 62 - barrier bit ... controlled with tioce_dma_barrier()
+- * 61 - 0 since this is not an MSI transaction
++ * 61 - msi bit ... specified through dma_flags
+ * 60:54 - reserved, MBZ
+ */
+ static uint64_t
+-tioce_dma_d64(unsigned long ct_addr)
++tioce_dma_d64(unsigned long ct_addr, int dma_flags)
+ {
+ uint64_t bus_addr;
+
+ bus_addr = ct_addr | (1UL << 63);
++ if (dma_flags & SN_DMA_MSI)
++ bus_addr |= (1UL << 61);
+
+ return bus_addr;
+ }
+@@ -143,7 +146,7 @@ pcidev_to_tioce(struct pci_dev *pdev, st
+ */
+ static uint64_t
+ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port,
+- uint64_t ct_addr, int len)
++ uint64_t ct_addr, int len, int dma_flags)
+ {
+ int i;
+ int j;
+@@ -152,6 +155,7 @@ tioce_alloc_map(struct tioce_kernel *ce_
+ int entries;
+ int nates;
+ int pagesize;
++ int msi_capable, msi_wanted;
+ uint64_t *ate_shadow;
+ uint64_t *ate_reg;
+ uint64_t addr;
+@@ -173,6 +177,7 @@ tioce_alloc_map(struct tioce_kernel *ce_
+ ate_reg = ce_mmr->ce_ure_ate3240;
+ pagesize = ce_kern->ce_ate3240_pagesize;
+ bus_base = TIOCE_M32_MIN;
++ msi_capable = 1;
+ break;
+ case TIOCE_ATE_M40:
+ first = 0;
+@@ -181,6 +186,7 @@ tioce_alloc_map(struct tioce_kernel *ce_
+ ate_reg = ce_mmr->ce_ure_ate40;
+ pagesize = MB(64);
+ bus_base = TIOCE_M40_MIN;
++ msi_capable = 0;
+ break;
+ case TIOCE_ATE_M40S:
+ /*
+@@ -193,11 +199,16 @@ tioce_alloc_map(struct tioce_kernel *ce_
+ ate_reg = ce_mmr->ce_ure_ate3240;
+ pagesize = GB(16);
+ bus_base = TIOCE_M40S_MIN;
++ msi_capable = 0;
+ break;
+ default:
+ return 0;
+ }
+
++ msi_wanted = dma_flags & SN_DMA_MSI;
++ if (msi_wanted && !msi_capable)
++ return 0;
++
+ nates = ATE_NPAGES(ct_addr, len, pagesize);
+ if (nates > entries)
+ return 0;
+@@ -226,7 +237,7 @@ tioce_alloc_map(struct tioce_kernel *ce_
+ for (j = 0; j < nates; j++) {
+ uint64_t ate;
+
+- ate = ATE_MAKE(addr, pagesize);
++ ate = ATE_MAKE(addr, pagesize, msi_wanted);
+ ate_shadow[i + j] = ate;
+ writeq(ate, &ate_reg[i + j]);
+ addr += pagesize;
+@@ -253,7 +264,7 @@ tioce_alloc_map(struct tioce_kernel *ce_
+ * Map @paddr into 32-bit bus space of the CE associated with @pcidev_info.
+ */
+ static uint64_t
+-tioce_dma_d32(struct pci_dev *pdev, uint64_t ct_addr)
++tioce_dma_d32(struct pci_dev *pdev, uint64_t ct_addr, int dma_flags)
+ {
+ int dma_ok;
+ int port;
+@@ -263,6 +274,9 @@ tioce_dma_d32(struct pci_dev *pdev, uint
+ uint64_t ct_lower;
+ dma_addr_t bus_addr;
+
++ if (dma_flags & SN_DMA_MSI)
++ return 0;
++
+ ct_upper = ct_addr & ~0x3fffffffUL;
+ ct_lower = ct_addr & 0x3fffffffUL;
+
+@@ -387,7 +401,7 @@ tioce_dma_unmap(struct pci_dev *pdev, dm
+ */
+ static uint64_t
+ tioce_do_dma_map(struct pci_dev *pdev, uint64_t paddr, size_t byte_count,
+- int barrier)
++ int barrier, int dma_flags)
+ {
+ unsigned long flags;
+ uint64_t ct_addr;
+@@ -403,15 +417,18 @@ tioce_do_dma_map(struct pci_dev *pdev, u
+ if (dma_mask < 0x7fffffffUL)
+ return 0;
+
+- ct_addr = PHYS_TO_TIODMA(paddr);
++ if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS)
++ ct_addr = PHYS_TO_TIODMA(paddr);
++ else
++ ct_addr = paddr;
+
+ /*
+ * If the device can generate 64 bit addresses, create a D64 map.
+- * Since this should never fail, bypass the rest of the checks.
+ */
+ if (dma_mask == ~0UL) {
+- mapaddr = tioce_dma_d64(ct_addr);
+- goto dma_map_done;
++ mapaddr = tioce_dma_d64(ct_addr, dma_flags);
++ if (mapaddr)
++ goto dma_map_done;
+ }
+
+ pcidev_to_tioce(pdev, NULL, &ce_kern, &port);
+@@ -454,18 +471,22 @@ tioce_do_dma_map(struct pci_dev *pdev, u
+
+ if (byte_count > MB(64)) {
+ mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40S,
+- port, ct_addr, byte_count);
++ port, ct_addr, byte_count,
++ dma_flags);
+ if (!mapaddr)
+ mapaddr =
+ tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1,
+- ct_addr, byte_count);
++ ct_addr, byte_count,
++ dma_flags);
+ } else {
+ mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1,
+- ct_addr, byte_count);
++ ct_addr, byte_count,
++ dma_flags);
+ if (!mapaddr)
+ mapaddr =
+ tioce_alloc_map(ce_kern, TIOCE_ATE_M40S,
+- port, ct_addr, byte_count);
++ port, ct_addr, byte_count,
++ dma_flags);
+ }
+ }
+
+@@ -473,7 +494,7 @@ tioce_do_dma_map(struct pci_dev *pdev, u
+ * 32-bit direct is the next mode to try
+ */
+ if (!mapaddr && dma_mask >= 0xffffffffUL)
+- mapaddr = tioce_dma_d32(pdev, ct_addr);
++ mapaddr = tioce_dma_d32(pdev, ct_addr, dma_flags);
+
+ /*
+ * Last resort, try 32-bit ATE-based map.
+@@ -481,12 +502,12 @@ tioce_do_dma_map(struct pci_dev *pdev, u
+ if (!mapaddr)
+ mapaddr =
+ tioce_alloc_map(ce_kern, TIOCE_ATE_M32, -1, ct_addr,
+- byte_count);
++ byte_count, dma_flags);
+
+ spin_unlock_irqrestore(&ce_kern->ce_lock, flags);
+
+ dma_map_done:
+- if (mapaddr & barrier)
++ if (mapaddr && barrier)
+ mapaddr = tioce_dma_barrier(mapaddr, 1);
+
+ return mapaddr;
+@@ -502,9 +523,9 @@ dma_map_done:
+ * in the address.
+ */
+ static uint64_t
+-tioce_dma(struct pci_dev *pdev, uint64_t paddr, size_t byte_count)
++tioce_dma(struct pci_dev *pdev, uint64_t paddr, size_t byte_count, int dma_flags)
+ {
+- return tioce_do_dma_map(pdev, paddr, byte_count, 0);
++ return tioce_do_dma_map(pdev, paddr, byte_count, 0, dma_flags);
+ }
+
+ /**
+@@ -516,9 +537,9 @@ tioce_dma(struct pci_dev *pdev, uint64_t
+ * Simply call tioce_do_dma_map() to create a map with the barrier bit set
+ * in the address.
+ */ static uint64_t
+-tioce_dma_consistent(struct pci_dev *pdev, uint64_t paddr, size_t byte_count)
++tioce_dma_consistent(struct pci_dev *pdev, uint64_t paddr, size_t byte_count, int dma_flags)
+ {
+- return tioce_do_dma_map(pdev, paddr, byte_count, 1);
++ return tioce_do_dma_map(pdev, paddr, byte_count, 1, dma_flags);
+ }
+
+ /**
+--- gregkh-2.6.orig/include/asm-ia64/sn/intr.h
++++ gregkh-2.6/include/asm-ia64/sn/intr.h
+@@ -3,13 +3,14 @@
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
++ * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
+ */
+
+ #ifndef _ASM_IA64_SN_INTR_H
+ #define _ASM_IA64_SN_INTR_H
+
+ #include <linux/rcupdate.h>
++#include <asm/sn/types.h>
+
+ #define SGI_UART_VECTOR (0xe9)
+
+@@ -40,6 +41,7 @@ struct sn_irq_info {
+ int irq_cpuid; /* kernel logical cpuid */
+ int irq_irq; /* the IRQ number */
+ int irq_int_bit; /* Bridge interrupt pin */
++ /* <0 means MSI */
+ uint64_t irq_xtalkaddr; /* xtalkaddr IRQ is sent to */
+ int irq_bridge_type;/* pciio asic type (pciio.h) */
+ void *irq_bridge; /* bridge generating irq */
+@@ -53,6 +55,12 @@ struct sn_irq_info {
+ };
+
+ extern void sn_send_IPI_phys(int, long, int, int);
++extern uint64_t sn_intr_alloc(nasid_t, int,
++ struct sn_irq_info *,
++ int, nasid_t, int);
++extern void sn_intr_free(nasid_t, int, struct sn_irq_info *);
++extern struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *, nasid_t, int);
++extern struct list_head **sn_irq_lh;
+
+ #define CPU_VECTOR_TO_IRQ(cpuid,vector) (vector)
+
+--- gregkh-2.6.orig/include/asm-ia64/sn/pcibr_provider.h
++++ gregkh-2.6/include/asm-ia64/sn/pcibr_provider.h
+@@ -3,7 +3,7 @@
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+- * Copyright (C) 1992-1997,2000-2004 Silicon Graphics, Inc. All rights reserved.
++ * Copyright (C) 1992-1997,2000-2005 Silicon Graphics, Inc. All rights reserved.
+ */
+ #ifndef _ASM_IA64_SN_PCI_PCIBR_PROVIDER_H
+ #define _ASM_IA64_SN_PCI_PCIBR_PROVIDER_H
+@@ -55,6 +55,7 @@
+ #define PCI32_ATE_V (0x1 << 0)
+ #define PCI32_ATE_CO (0x1 << 1)
+ #define PCI32_ATE_PREC (0x1 << 2)
++#define PCI32_ATE_MSI (0x1 << 2)
+ #define PCI32_ATE_PREF (0x1 << 3)
+ #define PCI32_ATE_BAR (0x1 << 4)
+ #define PCI32_ATE_ADDR_SHFT 12
+@@ -129,8 +130,8 @@ pcibr_lock(struct pcibus_info *pcibus_in
+
+ extern int pcibr_init_provider(void);
+ extern void *pcibr_bus_fixup(struct pcibus_bussoft *, struct pci_controller *);
+-extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t);
+-extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t);
++extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t, int type);
++extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t, int type);
+ extern void pcibr_dma_unmap(struct pci_dev *, dma_addr_t, int);
+
+ /*
+--- gregkh-2.6.orig/include/asm-ia64/sn/pcibus_provider_defs.h
++++ gregkh-2.6/include/asm-ia64/sn/pcibus_provider_defs.h
+@@ -3,7 +3,7 @@
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
++ * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
+ */
+ #ifndef _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H
+ #define _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H
+@@ -45,13 +45,24 @@ struct pci_controller;
+ */
+
+ struct sn_pcibus_provider {
+- dma_addr_t (*dma_map)(struct pci_dev *, unsigned long, size_t);
+- dma_addr_t (*dma_map_consistent)(struct pci_dev *, unsigned long, size_t);
++ dma_addr_t (*dma_map)(struct pci_dev *, unsigned long, size_t, int flags);
++ dma_addr_t (*dma_map_consistent)(struct pci_dev *, unsigned long, size_t, int flags);
+ void (*dma_unmap)(struct pci_dev *, dma_addr_t, int);
+ void * (*bus_fixup)(struct pcibus_bussoft *, struct pci_controller *);
+ void (*force_interrupt)(struct sn_irq_info *);
+ void (*target_interrupt)(struct sn_irq_info *);
+ };
+
++/*
++ * Flags used by the map interfaces
++ * bits 3:0 specifies format of passed in address
++ * bit 4 specifies that address is to be used for MSI
++ */
++
++#define SN_DMA_ADDRTYPE(x) ((x) & 0xf)
++#define SN_DMA_ADDR_PHYS 1 /* address is an xio address. */
++#define SN_DMA_ADDR_XIO 2 /* address is phys memory */
++#define SN_DMA_MSI 0x10 /* Bus address is to be used for MSI */
++
+ extern struct sn_pcibus_provider *sn_pci_provider[];
+ #endif /* _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H */
+--- gregkh-2.6.orig/include/asm-ia64/sn/tiocp.h
++++ gregkh-2.6/include/asm-ia64/sn/tiocp.h
+@@ -3,13 +3,14 @@
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+- * Copyright (C) 2003-2004 Silicon Graphics, Inc. All rights reserved.
++ * Copyright (C) 2003-2005 Silicon Graphics, Inc. All rights reserved.
+ */
+ #ifndef _ASM_IA64_SN_PCI_TIOCP_H
+ #define _ASM_IA64_SN_PCI_TIOCP_H
+
+ #define TIOCP_HOST_INTR_ADDR 0x003FFFFFFFFFFFFFUL
+ #define TIOCP_PCI64_CMDTYPE_MEM (0x1ull << 60)
++#define TIOCP_PCI64_CMDTYPE_MSI (0x3ull << 60)
+
+
+ /*****************************************************************************
diff --git a/pci/pci-msi-vector-targeting-abstractions.patch b/pci/pci-msi-vector-targeting-abstractions.patch
new file mode 100644
index 0000000000000..6cee51d9b23c9
--- /dev/null
+++ b/pci/pci-msi-vector-targeting-abstractions.patch
@@ -0,0 +1,699 @@
+From owner-linux-pci@atrey.karlin.mff.cuni.cz Wed Jan 11 15:42:53 2006
+Date: Wed, 11 Jan 2006 16:16:38 -0600 (CST)
+From: Mark Maule <maule@sgi.com>
+Cc: Tony Luck <tony.luck@intel.com>, gregkh@suse.de, Mark Maule <maule@sgi.com>
+Message-Id: <20060111221638.28765.93442.80780@attica.americas.sgi.com>
+Subject: PCI: msi vector targeting abstractions
+
+Abstract portions of the MSI core for platforms that do not use standard
+APIC interrupt controllers. This is implemented through a new arch-specific
+msi setup routine, and a set of msi ops which can be set on a per platform
+basis.
+
+Signed-off-by: Mark Maule <maule@sgi.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/ia64/sn/pci/Makefile | 3
+ arch/ia64/sn/pci/msi.c | 18 +++++
+ drivers/pci/Makefile | 2
+ drivers/pci/msi-apic.c | 100 ++++++++++++++++++++++++++++
+ drivers/pci/msi.c | 146 ++++++++++++++++++++++-------------------
+ drivers/pci/msi.h | 63 -----------------
+ include/asm-i386/msi.h | 8 ++
+ include/asm-ia64/machvec.h | 7 +
+ include/asm-ia64/machvec_sn2.h | 2
+ include/asm-ia64/msi.h | 11 +++
+ include/asm-x86_64/msi.h | 8 ++
+ include/linux/pci.h | 62 +++++++++++++++++
+ 12 files changed, 301 insertions(+), 129 deletions(-)
+
+--- gregkh-2.6.orig/drivers/pci/msi.c
++++ gregkh-2.6/drivers/pci/msi.c
+@@ -23,8 +23,6 @@
+ #include "pci.h"
+ #include "msi.h"
+
+-#define MSI_TARGET_CPU first_cpu(cpu_online_map)
+-
+ static DEFINE_SPINLOCK(msi_lock);
+ static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
+ static kmem_cache_t* msi_cachep;
+@@ -40,6 +38,15 @@ int vector_irq[NR_VECTORS] = { [0 ... NR
+ u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
+ #endif
+
++static struct msi_ops *msi_ops;
++
++int
++msi_register(struct msi_ops *ops)
++{
++ msi_ops = ops;
++ return 0;
++}
++
+ static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
+ {
+ memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
+@@ -92,7 +99,7 @@ static void msi_set_mask_bit(unsigned in
+ static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
+ {
+ struct msi_desc *entry;
+- struct msg_address address;
++ u32 address_hi, address_lo;
+ unsigned int irq = vector;
+ unsigned int dest_cpu = first_cpu(cpu_mask);
+
+@@ -108,28 +115,36 @@ static void set_msi_affinity(unsigned in
+ if (!(pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI)))
+ return;
+
++ pci_read_config_dword(entry->dev, msi_upper_address_reg(pos),
++ &address_hi);
+ pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
+- &address.lo_address.value);
+- address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
+- address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
+- MSI_TARGET_CPU_SHIFT);
+- entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
++ &address_lo);
++
++ msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
++
++ pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
++ address_hi);
+ pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
+- address.lo_address.value);
++ address_lo);
+ set_native_irq_info(irq, cpu_mask);
+ break;
+ }
+ case PCI_CAP_ID_MSIX:
+ {
+- int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
++ int offset_hi =
++ entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
++ PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET;
++ int offset_lo =
++ entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
++ PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
++
++ address_hi = readl(entry->mask_base + offset_hi);
++ address_lo = readl(entry->mask_base + offset_lo);
+
+- address.lo_address.value = readl(entry->mask_base + offset);
+- address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
+- address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
+- MSI_TARGET_CPU_SHIFT);
+- entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
+- writel(address.lo_address.value, entry->mask_base + offset);
++ msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
++
++ writel(address_hi, entry->mask_base + offset_hi);
++ writel(address_lo, entry->mask_base + offset_lo);
+ set_native_irq_info(irq, cpu_mask);
+ break;
+ }
+@@ -251,30 +266,6 @@ static struct hw_interrupt_type msi_irq_
+ .set_affinity = set_msi_affinity
+ };
+
+-static void msi_data_init(struct msg_data *msi_data,
+- unsigned int vector)
+-{
+- memset(msi_data, 0, sizeof(struct msg_data));
+- msi_data->vector = (u8)vector;
+- msi_data->delivery_mode = MSI_DELIVERY_MODE;
+- msi_data->level = MSI_LEVEL_MODE;
+- msi_data->trigger = MSI_TRIGGER_MODE;
+-}
+-
+-static void msi_address_init(struct msg_address *msi_address)
+-{
+- unsigned int dest_id;
+- unsigned long dest_phys_id = cpu_physical_id(MSI_TARGET_CPU);
+-
+- memset(msi_address, 0, sizeof(struct msg_address));
+- msi_address->hi_address = (u32)0;
+- dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT);
+- msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE;
+- msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE;
+- msi_address->lo_address.u.dest_id = dest_id;
+- msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT);
+-}
+-
+ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
+ static int assign_msi_vector(void)
+ {
+@@ -369,6 +360,20 @@ static int msi_init(void)
+ return status;
+ }
+
++ if ((status = msi_arch_init()) < 0) {
++ pci_msi_enable = 0;
++ printk(KERN_WARNING
++ "PCI: MSI arch init failed. MSI disabled.\n");
++ return status;
++ }
++
++ if (! msi_ops) {
++ printk(KERN_WARNING
++ "PCI: MSI ops not registered. MSI disabled.\n");
++ status = -EINVAL;
++ return status;
++ }
++
+ if ((status = msi_cache_init()) < 0) {
+ pci_msi_enable = 0;
+ printk(KERN_WARNING "PCI: MSI cache init failed\n");
+@@ -512,9 +517,11 @@ void pci_scan_msi_device(struct pci_dev
+ **/
+ static int msi_capability_init(struct pci_dev *dev)
+ {
++ int status;
+ struct msi_desc *entry;
+- struct msg_address address;
+- struct msg_data data;
++ u32 address_lo;
++ u32 address_hi;
++ u32 data;
+ int pos, vector;
+ u16 control;
+
+@@ -541,23 +548,26 @@ static int msi_capability_init(struct pc
+ entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
+ is_64bit_address(control));
+ }
++ /* Configure MSI capability structure */
++ status = msi_ops->setup(dev, vector,
++ &address_hi,
++ &address_lo,
++ &data);
++ if (status < 0) {
++ kmem_cache_free(msi_cachep, entry);
++ return status;
++ }
+ /* Replace with MSI handler */
+ irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
+- /* Configure MSI capability structure */
+- msi_address_init(&address);
+- msi_data_init(&data, vector);
+- entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
+- MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
+- pci_write_config_dword(dev, msi_lower_address_reg(pos),
+- address.lo_address.value);
++
++ pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo);
+ if (is_64bit_address(control)) {
+ pci_write_config_dword(dev,
+- msi_upper_address_reg(pos), address.hi_address);
+- pci_write_config_word(dev,
+- msi_data_reg(pos, 1), *((u32*)&data));
++ msi_upper_address_reg(pos), address_hi);
++ pci_write_config_word(dev, msi_data_reg(pos, 1), data);
+ } else
+- pci_write_config_word(dev,
+- msi_data_reg(pos, 0), *((u32*)&data));
++ pci_write_config_word(dev, msi_data_reg(pos, 0), data);
++
+ if (entry->msi_attrib.maskbit) {
+ unsigned int maskbits, temp;
+ /* All MSIs are unmasked by default, Mask them all */
+@@ -592,13 +602,15 @@ static int msix_capability_init(struct p
+ struct msix_entry *entries, int nvec)
+ {
+ struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
+- struct msg_address address;
+- struct msg_data data;
++ u32 address_hi;
++ u32 address_lo;
++ u32 data;
+ int vector, pos, i, j, nr_entries, temp = 0;
+ u32 phys_addr, table_offset;
+ u16 control;
+ u8 bir;
+ void __iomem *base;
++ int status;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+ /* Request & Map MSI-X table region */
+@@ -645,18 +657,20 @@ static int msix_capability_init(struct p
+ /* Replace with MSI-X handler */
+ irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
+ /* Configure MSI-X capability structure */
+- msi_address_init(&address);
+- msi_data_init(&data, vector);
+- entry->msi_attrib.current_cpu =
+- ((address.lo_address.u.dest_id >>
+- MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
+- writel(address.lo_address.value,
++ status = msi_ops->setup(dev, vector,
++ &address_hi,
++ &address_lo,
++ &data);
++ if (status < 0)
++ break;
++
++ writel(address_lo,
+ base + j * PCI_MSIX_ENTRY_SIZE +
+ PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+- writel(address.hi_address,
++ writel(address_hi,
+ base + j * PCI_MSIX_ENTRY_SIZE +
+ PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+- writel(*(u32*)&data,
++ writel(data,
+ base + j * PCI_MSIX_ENTRY_SIZE +
+ PCI_MSIX_ENTRY_DATA_OFFSET);
+ attach_msi_entry(entry, vector);
+@@ -791,6 +805,8 @@ static int msi_free_vector(struct pci_de
+ void __iomem *base;
+ unsigned long flags;
+
++ msi_ops->teardown(vector);
++
+ spin_lock_irqsave(&msi_lock, flags);
+ entry = msi_desc[vector];
+ if (!entry || entry->dev != dev) {
+--- gregkh-2.6.orig/include/asm-i386/msi.h
++++ gregkh-2.6/include/asm-i386/msi.h
+@@ -12,4 +12,12 @@
+ #define LAST_DEVICE_VECTOR 232
+ #define MSI_TARGET_CPU_SHIFT 12
+
++extern struct msi_ops msi_apic_ops;
++
++static inline int msi_arch_init(void)
++{
++ msi_register(&msi_apic_ops);
++ return 0;
++}
++
+ #endif /* ASM_MSI_H */
+--- gregkh-2.6.orig/include/asm-x86_64/msi.h
++++ gregkh-2.6/include/asm-x86_64/msi.h
+@@ -13,4 +13,12 @@
+ #define LAST_DEVICE_VECTOR 232
+ #define MSI_TARGET_CPU_SHIFT 12
+
++extern struct msi_ops msi_apic_ops;
++
++static inline int msi_arch_init(void)
++{
++ msi_register_apic(&msi_apic_ops);
++ return 0;
++}
++
+ #endif /* ASM_MSI_H */
+--- gregkh-2.6.orig/include/asm-ia64/machvec.h
++++ gregkh-2.6/include/asm-ia64/machvec.h
+@@ -74,6 +74,7 @@ typedef unsigned char ia64_mv_readb_rela
+ 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);
+
+ static inline void
+ machvec_noop (void)
+@@ -146,6 +147,7 @@ extern void machvec_tlb_migrate_finish (
+ # define platform_readw_relaxed ia64_mv.readw_relaxed
+ # define platform_readl_relaxed ia64_mv.readl_relaxed
+ # define platform_readq_relaxed ia64_mv.readq_relaxed
++# define platform_msi_init ia64_mv.msi_init
+ # endif
+
+ /* __attribute__((__aligned__(16))) is required to make size of the
+@@ -194,6 +196,7 @@ struct ia64_machine_vector {
+ ia64_mv_readw_relaxed_t *readw_relaxed;
+ ia64_mv_readl_relaxed_t *readl_relaxed;
+ ia64_mv_readq_relaxed_t *readq_relaxed;
++ ia64_mv_msi_init_t *msi_init;
+ } __attribute__((__aligned__(16))); /* align attrib? see above comment */
+
+ #define MACHVEC_INIT(name) \
+@@ -238,6 +241,7 @@ struct ia64_machine_vector {
+ platform_readw_relaxed, \
+ platform_readl_relaxed, \
+ platform_readq_relaxed, \
++ platform_msi_init, \
+ }
+
+ extern struct ia64_machine_vector ia64_mv;
+@@ -386,5 +390,8 @@ extern ia64_mv_dma_supported swiotlb_dm
+ #ifndef platform_readq_relaxed
+ # define platform_readq_relaxed __ia64_readq_relaxed
+ #endif
++#ifndef platform_msi_init
++# define platform_msi_init ia64_msi_init
++#endif
+
+ #endif /* _ASM_IA64_MACHVEC_H */
+--- gregkh-2.6.orig/include/asm-ia64/machvec_sn2.h
++++ gregkh-2.6/include/asm-ia64/machvec_sn2.h
+@@ -71,6 +71,7 @@ extern ia64_mv_dma_sync_single_for_devic
+ extern ia64_mv_dma_sync_sg_for_device sn_dma_sync_sg_for_device;
+ extern ia64_mv_dma_mapping_error sn_dma_mapping_error;
+ extern ia64_mv_dma_supported sn_dma_supported;
++extern ia64_mv_msi_init_t sn_msi_init;
+
+ /*
+ * This stuff has dual use!
+@@ -120,6 +121,7 @@ extern ia64_mv_dma_supported sn_dma_sup
+ #define platform_dma_sync_sg_for_device sn_dma_sync_sg_for_device
+ #define platform_dma_mapping_error sn_dma_mapping_error
+ #define platform_dma_supported sn_dma_supported
++#define platform_msi_init sn_msi_init
+
+ #include <asm/sn/io.h>
+
+--- gregkh-2.6.orig/include/asm-ia64/msi.h
++++ gregkh-2.6/include/asm-ia64/msi.h
+@@ -14,4 +14,15 @@ static inline void set_intr_gate (int nr
+ #define ack_APIC_irq ia64_eoi
+ #define MSI_TARGET_CPU_SHIFT 4
+
++extern struct msi_ops msi_apic_ops;
++
++/* default ia64 msi init routine */
++static inline int ia64_msi_init(void)
++{
++ msi_register(&msi_apic_ops);
++ return 0;
++}
++
++#define msi_arch_init platform_msi_init
++
+ #endif /* ASM_MSI_H */
+--- gregkh-2.6.orig/arch/ia64/sn/pci/Makefile
++++ gregkh-2.6/arch/ia64/sn/pci/Makefile
+@@ -3,8 +3,9 @@
+ # License. See the file "COPYING" in the main directory of this archive
+ # for more details.
+ #
+-# Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
++# Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ #
+ # Makefile for the sn pci general routines.
+
+ obj-y := pci_dma.o tioca_provider.o tioce_provider.o pcibr/
++obj-$(CONFIG_PCI_MSI) += msi.o
+--- /dev/null
++++ gregkh-2.6/arch/ia64/sn/pci/msi.c
+@@ -0,0 +1,18 @@
++/*
++ * 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) 2005 Silicon Graphics, Inc. All Rights Reserved.
++ */
++
++#include <asm/errno.h>
++
++int
++sn_msi_init(void)
++{
++ /*
++ * return error until MSI is supported on altix platforms
++ */
++ return -EINVAL;
++}
+--- gregkh-2.6.orig/drivers/pci/Makefile
++++ gregkh-2.6/drivers/pci/Makefile
+@@ -26,7 +26,7 @@ obj-$(CONFIG_PPC32) += setup-irq.o
+ obj-$(CONFIG_PPC64) += setup-bus.o
+ obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
+ obj-$(CONFIG_X86_VISWS) += setup-irq.o
+-obj-$(CONFIG_PCI_MSI) += msi.o
++obj-$(CONFIG_PCI_MSI) += msi.o msi-apic.o
+
+ #
+ # ACPI Related PCI FW Functions
+--- /dev/null
++++ gregkh-2.6/drivers/pci/msi-apic.c
+@@ -0,0 +1,100 @@
++/*
++ * MSI hooks for standard x86 apic
++ */
++
++#include <linux/pci.h>
++#include <linux/irq.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 vector,
++ unsigned int dest_cpu,
++ u32 *address_hi, /* in/out */
++ u32 *address_lo) /* in/out */
++{
++ u32 addr = *address_lo;
++
++ addr &= MSI_ADDR_DESTID_MASK;
++ addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
++
++ *address_lo = addr;
++}
++
++static int
++msi_setup_apic(struct pci_dev *pdev, /* unused in generic */
++ unsigned int vector,
++ u32 *address_hi,
++ u32 *address_lo,
++ u32 *data)
++{
++ unsigned long dest_phys_id;
++
++ dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
++
++ *address_hi = 0;
++ *address_lo = MSI_ADDR_HEADER |
++ MSI_ADDR_DESTMODE_PHYS |
++ MSI_ADDR_REDIRECTION_CPU |
++ MSI_ADDR_DESTID_CPU(dest_phys_id);
++
++ *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 vector)
++{
++ return; /* no-op */
++}
++
++/*
++ * Generic ops used on most IA archs/platforms. Set with msi_register()
++ */
++
++struct msi_ops msi_apic_ops = {
++ .setup = msi_setup_apic,
++ .teardown = msi_teardown_apic,
++ .target = msi_target_apic,
++};
+--- gregkh-2.6.orig/drivers/pci/msi.h
++++ gregkh-2.6/drivers/pci/msi.h
+@@ -63,67 +63,6 @@ extern int pci_vector_resources(int last
+ #define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK)
+ #define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK)
+
+-/*
+- * MSI Defined Data Structures
+- */
+-#define MSI_ADDRESS_HEADER 0xfee
+-#define MSI_ADDRESS_HEADER_SHIFT 12
+-#define MSI_ADDRESS_HEADER_MASK 0xfff000
+-#define MSI_ADDRESS_DEST_ID_MASK 0xfff0000f
+-#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_PHYSICAL_MODE 0
+-#define MSI_LOGICAL_MODE 1
+-#define MSI_REDIRECTION_HINT_MODE 0
+-
+-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} */
+@@ -132,7 +71,7 @@ struct msi_desc {
+ __u8 reserved: 1; /* reserved */
+ __u8 entry_nr; /* specific enabled entry */
+ __u8 default_vector; /* default pre-assigned vector */
+- __u8 current_cpu; /* current destination cpu */
++ __u8 unused; /* formerly unused destination cpu*/
+ }msi_attrib;
+
+ struct {
+--- gregkh-2.6.orig/include/linux/pci.h
++++ gregkh-2.6/include/linux/pci.h
+@@ -546,6 +546,66 @@ struct msix_entry {
+ u16 entry; /* driver uses to specify entry, OS writes */
+ };
+
++/*
++ * 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 {
++ /**
++ * setup - generate an MSI bus address and data for a given vector
++ * @pdev: PCI device context (in)
++ * @vector: vector allocated by the msi core (in)
++ * @addr_hi: upper 32 bits of PCI bus MSI address (out)
++ * @addr_lo: lower 32 bits of PCI bus MSI address (out)
++ * @data: MSI data payload (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 vector,
++ u32 *addr_hi, u32 *addr_lo, u32 *data);
++
++ /**
++ * 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 vector);
++
++ /**
++ * 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 vector, unsigned int cpu,
++ u32 *addr_hi, u32 *addr_lo);
++};
++
+ #ifndef CONFIG_PCI_MSI
+ static inline void pci_scan_msi_device(struct pci_dev *dev) {}
+ static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
+@@ -554,6 +614,7 @@ static inline int pci_enable_msix(struct
+ struct msix_entry *entries, int nvec) {return -1;}
+ static inline void pci_disable_msix(struct pci_dev *dev) {}
+ static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
++static inline int msi_register(struct msi_ops *ops) {return -1;}
+ #else
+ extern void pci_scan_msi_device(struct pci_dev *dev);
+ extern int pci_enable_msi(struct pci_dev *dev);
+@@ -562,6 +623,7 @@ extern int pci_enable_msix(struct pci_de
+ 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);
++extern int msi_register(struct msi_ops *ops);
+ #endif
+
+ extern void pci_block_user_cfg_access(struct pci_dev *dev);
diff --git a/pci/pci-per-platform-ia64_-first-last-_device_vector-definitions.patch b/pci/pci-per-platform-ia64_-first-last-_device_vector-definitions.patch
new file mode 100644
index 0000000000000..7f0f544fe43ee
--- /dev/null
+++ b/pci/pci-per-platform-ia64_-first-last-_device_vector-definitions.patch
@@ -0,0 +1,151 @@
+From owner-linux-pci@atrey.karlin.mff.cuni.cz Wed Jan 11 15:43:21 2006
+Date: Wed, 11 Jan 2006 16:16:43 -0600 (CST)
+From: Mark Maule <maule@sgi.com>
+Cc: Tony Luck <tony.luck@intel.com>, gregkh@suse.de, Mark Maule <maule@sgi.com>
+Message-Id: <20060111221643.28765.38687.79085@attica.americas.sgi.com>
+Subject: PCI: per-platform IA64_{FIRST,LAST}_DEVICE_VECTOR definitions
+
+Abstract IA64_FIRST_DEVICE_VECTOR/IA64_LAST_DEVICE_VECTOR since SN platforms
+use a subset of the IA64 range. Implement this by making the above macros
+global variables which the platform can override in it setup code.
+
+Also add a reserve_irq_vector() routine used by SN to mark a vector's as
+in-use when that weren't allocated through assign_irq_vector().
+
+Signed-off-by: Mark Maule <maule@sgi.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/ia64/kernel/irq_ia64.c | 17 ++++++++++++++++-
+ arch/ia64/sn/kernel/irq.c | 7 +++++++
+ drivers/pci/msi.c | 7 ++++++-
+ include/asm-ia64/hw_irq.h | 15 +++++++++++++--
+ 4 files changed, 42 insertions(+), 4 deletions(-)
+
+--- gregkh-2.6.orig/arch/ia64/kernel/irq_ia64.c
++++ gregkh-2.6/arch/ia64/kernel/irq_ia64.c
+@@ -46,6 +46,10 @@
+
+ #define IRQ_DEBUG 0
+
++/* These can be overridden in platform_irq_init */
++int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR;
++int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR;
++
+ /* default base addr of IPI table */
+ void __iomem *ipi_base_addr = ((void __iomem *)
+ (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR));
+@@ -60,7 +64,7 @@ __u8 isa_irq_to_vector_map[16] = {
+ };
+ EXPORT_SYMBOL(isa_irq_to_vector_map);
+
+-static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
++static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_MAX_DEVICE_VECTORS)];
+
+ int
+ assign_irq_vector (int irq)
+@@ -89,6 +93,17 @@ free_irq_vector (int vector)
+ printk(KERN_WARNING "%s: double free!\n", __FUNCTION__);
+ }
+
++int
++reserve_irq_vector (int vector)
++{
++ if (vector < IA64_FIRST_DEVICE_VECTOR ||
++ vector > IA64_LAST_DEVICE_VECTOR)
++ return -EINVAL;
++
++ return test_and_set_bit(IA64_FIRST_DEVICE_VECTOR + vector,
++ ia64_vector_mask);
++}
++
+ #ifdef CONFIG_SMP
+ # define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE)
+ #else
+--- gregkh-2.6.orig/arch/ia64/sn/kernel/irq.c
++++ gregkh-2.6/arch/ia64/sn/kernel/irq.c
+@@ -203,6 +203,9 @@ void sn_irq_init(void)
+ int i;
+ irq_desc_t *base_desc = irq_desc;
+
++ ia64_first_device_vector = IA64_SN2_FIRST_DEVICE_VECTOR;
++ ia64_last_device_vector = IA64_SN2_LAST_DEVICE_VECTOR;
++
+ for (i = 0; i < NR_IRQS; i++) {
+ if (base_desc[i].handler == &no_irq_type) {
+ base_desc[i].handler = &irq_type_sn;
+@@ -287,6 +290,7 @@ void sn_irq_fixup(struct pci_dev *pci_de
+ /* link it into the sn_irq[irq] list */
+ spin_lock(&sn_irq_info_lock);
+ list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]);
++ reserve_irq_vector(sn_irq_info->irq_irq);
+ spin_unlock(&sn_irq_info_lock);
+
+ (void)register_intr_pda(sn_irq_info);
+@@ -310,8 +314,11 @@ void sn_irq_unfixup(struct pci_dev *pci_
+ spin_lock(&sn_irq_info_lock);
+ list_del_rcu(&sn_irq_info->list);
+ spin_unlock(&sn_irq_info_lock);
++ if (list_empty(sn_irq_lh[sn_irq_info->irq_irq]))
++ free_irq_vector(sn_irq_info->irq_irq);
+ call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
+ pci_dev_put(pci_dev);
++
+ }
+
+ static inline void
+--- gregkh-2.6.orig/include/asm-ia64/hw_irq.h
++++ gregkh-2.6/include/asm-ia64/hw_irq.h
+@@ -47,9 +47,19 @@ typedef u8 ia64_vector;
+ #define IA64_CMC_VECTOR 0x1f /* corrected machine-check interrupt vector */
+ /*
+ * Vectors 0x20-0x2f are reserved for legacy ISA IRQs.
++ * Use vectors 0x30-0xe7 as the default device vector range for ia64.
++ * Platforms may choose to reduce this range in platform_irq_setup, but the
++ * platform range must fall within
++ * [IA64_DEF_FIRST_DEVICE_VECTOR..IA64_DEF_LAST_DEVICE_VECTOR]
+ */
+-#define IA64_FIRST_DEVICE_VECTOR 0x30
+-#define IA64_LAST_DEVICE_VECTOR 0xe7
++extern int ia64_first_device_vector;
++extern int ia64_last_device_vector;
++
++#define IA64_DEF_FIRST_DEVICE_VECTOR 0x30
++#define IA64_DEF_LAST_DEVICE_VECTOR 0xe7
++#define IA64_FIRST_DEVICE_VECTOR ia64_first_device_vector
++#define IA64_LAST_DEVICE_VECTOR ia64_last_device_vector
++#define IA64_MAX_DEVICE_VECTORS (IA64_DEF_LAST_DEVICE_VECTOR - IA64_DEF_FIRST_DEVICE_VECTOR + 1)
+ #define IA64_NUM_DEVICE_VECTORS (IA64_LAST_DEVICE_VECTOR - IA64_FIRST_DEVICE_VECTOR + 1)
+
+ #define IA64_MCA_RENDEZ_VECTOR 0xe8 /* MCA rendez interrupt */
+@@ -83,6 +93,7 @@ extern struct hw_interrupt_type irq_type
+
+ extern int assign_irq_vector (int irq); /* allocate a free vector */
+ extern void free_irq_vector (int vector);
++extern int reserve_irq_vector (int vector);
+ extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
+ extern void register_percpu_irq (ia64_vector vec, struct irqaction *action);
+
+--- gregkh-2.6.orig/drivers/pci/msi.c
++++ gregkh-2.6/drivers/pci/msi.c
+@@ -35,7 +35,7 @@ static int nr_msix_devices;
+
+ #ifndef CONFIG_X86_IO_APIC
+ int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
+-u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
++u8 irq_vector[NR_IRQ_VECTORS];
+ #endif
+
+ static struct msi_ops *msi_ops;
+@@ -379,6 +379,11 @@ static int msi_init(void)
+ printk(KERN_WARNING "PCI: MSI cache init failed\n");
+ return status;
+ }
++
++#ifndef CONFIG_X86_IO_APIC
++ irq_vector[0] = FIRST_DEVICE_VECTOR;
++#endif
++
+ last_alloc_vector = assign_irq_vector(AUTO_ASSIGN);
+ if (last_alloc_vector < 0) {
+ pci_msi_enable = 0;
diff --git a/pci/pci-schedule-removal-of-pci_module_init.patch b/pci/pci-schedule-removal-of-pci_module_init.patch
index 4cd3a225672e6..c356aeb19f460 100644
--- a/pci/pci-schedule-removal-of-pci_module_init.patch
+++ b/pci/pci-schedule-removal-of-pci_module_init.patch
@@ -57,7 +57,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
static inline int pci_register_driver(struct pci_driver *driver)
{
return __pci_register_driver(driver, THIS_MODULE);
-@@ -621,6 +619,7 @@ static inline void pci_disable_device(st
+@@ -683,6 +681,7 @@ static inline void pci_disable_device(st
static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; }
static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;}
static inline int __pci_register_driver(struct pci_driver *drv, struct module *owner) { return 0;}