diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2006-01-11 15:52:09 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-01-11 15:52:09 -0800 |
commit | 9a037602e512dbe57da6d1e33b34e9271e200fa4 (patch) | |
tree | 8c152c46225e82bd29c84d75284663f9990fc231 /pci | |
parent | 68aa69ec74575d546c16d103310234b013bccde2 (diff) | |
download | patches-9a037602e512dbe57da6d1e33b34e9271e200fa4.tar.gz |
pci msi patches from sgi
Diffstat (limited to 'pci')
-rw-r--r-- | pci/pci-altix-msi-support.patch | 1005 | ||||
-rw-r--r-- | pci/pci-msi-vector-targeting-abstractions.patch | 699 | ||||
-rw-r--r-- | pci/pci-per-platform-ia64_-first-last-_device_vector-definitions.patch | 151 | ||||
-rw-r--r-- | pci/pci-schedule-removal-of-pci_module_init.patch | 2 |
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;} |