aboutsummaryrefslogtreecommitdiffstats
path: root/pci
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2006-04-13 16:59:01 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2006-04-13 16:59:01 -0700
commita5de3b68f706cc28f0d94ee85a21d4a234014942 (patch)
treeaa0452abd187dae57a5d48750b4c3c2c577ce506 /pci
parent6939471a340468dc686845aef597be6c4a3346aa (diff)
downloadpatches-a5de3b68f706cc28f0d94ee85a21d4a234014942.tar.gz
patches added and refresh
Diffstat (limited to 'pci')
-rw-r--r--pci/pci-64-bit-resources-drivers-net-changes.patch4
-rw-r--r--pci/pci-64-bit-resources-drivers-others-changes.patch2
-rw-r--r--pci/pci-msi-abstractions-and-support-for-altix.patch827
3 files changed, 830 insertions, 3 deletions
diff --git a/pci/pci-64-bit-resources-drivers-net-changes.patch b/pci/pci-64-bit-resources-drivers-net-changes.patch
index 2d477b33ae115..d1df02ed604e1 100644
--- a/pci/pci-64-bit-resources-drivers-net-changes.patch
+++ b/pci/pci-64-bit-resources-drivers-net-changes.patch
@@ -113,7 +113,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
--- gregkh-2.6.orig/drivers/net/skge.c
+++ gregkh-2.6/drivers/net/skge.c
-@@ -3327,8 +3327,8 @@ static int __devinit skge_probe(struct p
+@@ -3329,8 +3329,8 @@ static int __devinit skge_probe(struct p
if (err)
goto err_out_free_irq;
@@ -126,7 +126,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
if ((dev = skge_devinit(hw, 0, using_dac)) == NULL)
--- gregkh-2.6.orig/drivers/net/sky2.c
+++ gregkh-2.6/drivers/net/sky2.c
-@@ -3231,9 +3231,9 @@ static int __devinit sky2_probe(struct p
+@@ -3229,9 +3229,9 @@ static int __devinit sky2_probe(struct p
if (err)
goto err_out_iounmap;
diff --git a/pci/pci-64-bit-resources-drivers-others-changes.patch b/pci/pci-64-bit-resources-drivers-others-changes.patch
index a91665f8010b3..cb436d35f2582 100644
--- a/pci/pci-64-bit-resources-drivers-others-changes.patch
+++ b/pci/pci-64-bit-resources-drivers-others-changes.patch
@@ -175,7 +175,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
--- gregkh-2.6.orig/drivers/infiniband/hw/mthca/mthca_main.c
+++ gregkh-2.6/drivers/infiniband/hw/mthca/mthca_main.c
-@@ -157,8 +157,9 @@ static int __devinit mthca_dev_lim(struc
+@@ -172,8 +172,9 @@ static int __devinit mthca_dev_lim(struc
if (dev_lim->uar_size > pci_resource_len(mdev->pdev, 2)) {
mthca_err(mdev, "HCA reported UAR size of 0x%x bigger than "
diff --git a/pci/pci-msi-abstractions-and-support-for-altix.patch b/pci/pci-msi-abstractions-and-support-for-altix.patch
new file mode 100644
index 0000000000000..dc8dd851f81f9
--- /dev/null
+++ b/pci/pci-msi-abstractions-and-support-for-altix.patch
@@ -0,0 +1,827 @@
+From maule@lnx-maule.americas.sgi.com Thu Apr 13 16:51:11 2006
+Date: Mon, 10 Apr 2006 21:17:48 -0500
+From: Mark Maule <maule@sgi.com>
+To: Shaohua Li <shaohua.li@intel.com>
+Cc: Greg KH <greg@kroah.com>
+Subject: PCI: msi abstractions and support for altix
+Message-ID: <20060411021748.GA9342@sgi.com>
+Content-Disposition: inline
+
+
+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>
+
+---
+ drivers/pci/Makefile | 6 -
+ drivers/pci/msi-altix.c | 18 +++
+ drivers/pci/msi-apic.c | 100 +++++++++++++++++++
+ drivers/pci/msi.c | 210 +++++++++++++++++++++++++----------------
+ drivers/pci/msi.h | 133 +++++++++++++------------
+ include/asm-i386/msi.h | 8 +
+ include/asm-ia64/machvec.h | 7 +
+ include/asm-ia64/machvec_sn2.h | 7 +
+ include/asm-ia64/msi.h | 12 ++
+ include/asm-x86_64/msi.h | 8 +
+ 10 files changed, 366 insertions(+), 143 deletions(-)
+
+--- gregkh-2.6.orig/drivers/pci/Makefile
++++ gregkh-2.6/drivers/pci/Makefile
+@@ -26,7 +26,11 @@ 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
++
++msiobj-y := msi.o msi-apic.o
++msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
++msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
++obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
+
+ #
+ # ACPI Related PCI FW Functions
+--- /dev/null
++++ gregkh-2.6/drivers/pci/msi-altix.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) 2006 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;
++}
+--- /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.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)
+ 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,13 +360,29 @@ static int msi_init(void)
+ return status;
+ }
+
++ status = msi_arch_init();
++ if (status < 0) {
++ pci_msi_enable = 0;
++ printk(KERN_WARNING
++ "PCI: MSI arch init failed. MSI disabled.\n");
++ return status;
++ }
++
++ if (! msi_ops) {
++ printk(KERN_WARNING
++ "PCI: MSI ops not registered. MSI disabled.\n");
++ status = -EINVAL;
++ return status;
++ }
++
++ last_alloc_vector = assign_irq_vector(AUTO_ASSIGN);
+ status = msi_cache_init();
+ if (status < 0) {
+ pci_msi_enable = 0;
+ printk(KERN_WARNING "PCI: MSI cache init failed\n");
+ return status;
+ }
+- last_alloc_vector = assign_irq_vector(AUTO_ASSIGN);
++
+ if (last_alloc_vector < 0) {
+ pci_msi_enable = 0;
+ printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n");
+@@ -575,6 +582,8 @@ void pci_restore_msi_state(struct pci_de
+ int pci_save_msix_state(struct pci_dev *dev)
+ {
+ int pos;
++ int temp;
++ int vector, head, tail = 0;
+ u16 control;
+ struct pci_cap_saved_state *save_state;
+
+@@ -582,6 +591,7 @@ int pci_save_msix_state(struct pci_dev *
+ if (pos <= 0 || dev->no_msi)
+ return 0;
+
++ /* save the capability */
+ pci_read_config_word(dev, msi_control_reg(pos), &control);
+ if (!(control & PCI_MSIX_FLAGS_ENABLE))
+ return 0;
+@@ -593,6 +603,38 @@ int pci_save_msix_state(struct pci_dev *
+ }
+ *((u16 *)&save_state->data[0]) = control;
+
++ /* save the table */
++ temp = dev->irq;
++ if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
++ kfree(save_state);
++ return -EINVAL;
++ }
++
++ vector = head = dev->irq;
++ while (head != tail) {
++ int j;
++ void __iomem *base;
++ struct msi_desc *entry;
++
++ entry = msi_desc[vector];
++ base = entry->mask_base;
++ j = entry->msi_attrib.entry_nr;
++
++ entry->address_lo_save =
++ readl(base + j * PCI_MSIX_ENTRY_SIZE +
++ PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
++ entry->address_hi_save =
++ readl(base + j * PCI_MSIX_ENTRY_SIZE +
++ PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
++ entry->data_save =
++ readl(base + j * PCI_MSIX_ENTRY_SIZE +
++ PCI_MSIX_ENTRY_DATA_OFFSET);
++
++ tail = msi_desc[vector]->link.tail;
++ vector = tail;
++ }
++ dev->irq = temp;
++
+ disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
+ save_state->cap_nr = PCI_CAP_ID_MSIX;
+ pci_add_saved_cap(dev, save_state);
+@@ -606,8 +648,6 @@ void pci_restore_msix_state(struct pci_d
+ int vector, head, tail = 0;
+ void __iomem *base;
+ int j;
+- struct msg_address address;
+- struct msg_data data;
+ struct msi_desc *entry;
+ int temp;
+ struct pci_cap_saved_state *save_state;
+@@ -633,20 +673,13 @@ void pci_restore_msix_state(struct pci_d
+ base = entry->mask_base;
+ j = entry->msi_attrib.entry_nr;
+
+- msi_address_init(&address);
+- msi_data_init(&data, vector);
+-
+- address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
+- address.lo_address.value |= entry->msi_attrib.current_cpu <<
+- MSI_TARGET_CPU_SHIFT;
+-
+- writel(address.lo_address.value,
++ writel(entry->address_lo_save,
+ base + j * PCI_MSIX_ENTRY_SIZE +
+ PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+- writel(address.hi_address,
++ writel(entry->address_hi_save,
+ base + j * PCI_MSIX_ENTRY_SIZE +
+ PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+- writel(*(u32*)&data,
++ writel(entry->data_save,
+ base + j * PCI_MSIX_ENTRY_SIZE +
+ PCI_MSIX_ENTRY_DATA_OFFSET);
+
+@@ -660,30 +693,32 @@ void pci_restore_msix_state(struct pci_d
+ }
+ #endif
+
+-static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry)
++static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry)
+ {
+- struct msg_address address;
+- struct msg_data data;
++ int status;
++ u32 address_hi;
++ u32 address_lo;
++ u32 data;
+ int pos, vector = dev->irq;
+ u16 control;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+ pci_read_config_word(dev, msi_control_reg(pos), &control);
++
+ /* 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);
++ status = msi_ops->setup(dev, vector, &address_hi, &address_lo, &data);
++ if (status < 0)
++ return status;
++
++ 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);
++ msi_upper_address_reg(pos), address_hi);
+ pci_write_config_word(dev,
+- msi_data_reg(pos, 1), *((u32*)&data));
++ msi_data_reg(pos, 1), data);
+ } else
+ pci_write_config_word(dev,
+- msi_data_reg(pos, 0), *((u32*)&data));
++ msi_data_reg(pos, 0), data);
+ if (entry->msi_attrib.maskbit) {
+ unsigned int maskbits, temp;
+ /* All MSIs are unmasked by default, Mask them all */
+@@ -697,6 +732,8 @@ static void msi_register_init(struct pci
+ msi_mask_bits_reg(pos, is_64bit_address(control)),
+ maskbits);
+ }
++
++ return 0;
+ }
+
+ /**
+@@ -710,6 +747,7 @@ static void msi_register_init(struct pci
+ **/
+ static int msi_capability_init(struct pci_dev *dev)
+ {
++ int status;
+ struct msi_desc *entry;
+ int pos, vector;
+ u16 control;
+@@ -742,7 +780,12 @@ static int msi_capability_init(struct pc
+ /* Replace with MSI handler */
+ irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
+ /* Configure MSI capability structure */
+- msi_register_init(dev, entry);
++ status = msi_register_init(dev, entry);
++ if (status != 0) {
++ dev->irq = entry->msi_attrib.default_vector;
++ kmem_cache_free(msi_cachep, entry);
++ return status;
++ }
+
+ attach_msi_entry(entry, vector);
+ /* Set MSI enabled bits */
+@@ -765,8 +808,10 @@ 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 status;
+ int vector, pos, i, j, nr_entries, temp = 0;
+ unsigned long phys_addr;
+ u32 table_offset;
+@@ -820,18 +865,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);
+@@ -899,9 +946,10 @@ int pci_enable_msi(struct pci_dev* dev)
+ vector_irq[dev->irq] = -1;
+ nr_released_vectors--;
+ spin_unlock_irqrestore(&msi_lock, flags);
+- msi_register_init(dev, msi_desc[dev->irq]);
+- enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+- return 0;
++ status = msi_register_init(dev, msi_desc[dev->irq]);
++ if (status == 0)
++ enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
++ return status;
+ }
+ spin_unlock_irqrestore(&msi_lock, flags);
+ dev->irq = temp;
+@@ -978,6 +1026,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/drivers/pci/msi.h
++++ gregkh-2.6/drivers/pci/msi.h
+@@ -6,6 +6,68 @@
+ #ifndef MSI_H
+ #define MSI_H
+
++/*
++ * 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);
++};
++
++extern int msi_register(struct msi_ops *ops);
++
+ #include <asm/msi.h>
+
+ /*
+@@ -63,67 +125,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 +133,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 {
+@@ -142,6 +143,14 @@ struct msi_desc {
+
+ void __iomem *mask_base;
+ struct pci_dev *dev;
++
++#ifdef CONFIG_PM
++ /* PM save area for MSIX address/data */
++
++ u32 address_hi_save;
++ u32 address_lo_save;
++ u32 data_save;
++#endif
+ };
+
+ #endif /* MSI_H */
+--- 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-ia64/machvec.h
++++ gregkh-2.6/include/asm-ia64/machvec.h
+@@ -76,6 +76,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)
+@@ -154,6 +155,7 @@ extern void machvec_tlb_migrate_finish (
+ # define platform_readl_relaxed ia64_mv.readl_relaxed
+ # define platform_readq_relaxed ia64_mv.readq_relaxed
+ # define platform_migrate ia64_mv.migrate
++# define platform_msi_init ia64_mv.msi_init
+ # endif
+
+ /* __attribute__((__aligned__(16))) is required to make size of the
+@@ -203,6 +205,7 @@ struct ia64_machine_vector {
+ ia64_mv_readl_relaxed_t *readl_relaxed;
+ ia64_mv_readq_relaxed_t *readq_relaxed;
+ ia64_mv_migrate_t *migrate;
++ ia64_mv_msi_init_t *msi_init;
+ } __attribute__((__aligned__(16))); /* align attrib? see above comment */
+
+ #define MACHVEC_INIT(name) \
+@@ -248,6 +251,7 @@ struct ia64_machine_vector {
+ platform_readl_relaxed, \
+ platform_readq_relaxed, \
+ platform_migrate, \
++ platform_msi_init, \
+ }
+
+ extern struct ia64_machine_vector ia64_mv;
+@@ -399,5 +403,8 @@ extern ia64_mv_dma_supported swiotlb_dm
+ #ifndef platform_migrate
+ # define platform_migrate machvec_noop_task
+ #endif
++#ifndef platform_msi_init
++# define platform_msi_init ((ia64_mv_msi_init_t*)NULL)
++#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
+@@ -67,6 +67,8 @@ extern ia64_mv_dma_sync_sg_for_device sn
+ extern ia64_mv_dma_mapping_error sn_dma_mapping_error;
+ extern ia64_mv_dma_supported sn_dma_supported;
+ extern ia64_mv_migrate_t sn_migrate;
++extern ia64_mv_msi_init_t sn_msi_init;
++
+
+ /*
+ * This stuff has dual use!
+@@ -117,6 +119,11 @@ extern ia64_mv_migrate_t sn_migrate;
+ #define platform_dma_mapping_error sn_dma_mapping_error
+ #define platform_dma_supported sn_dma_supported
+ #define platform_migrate sn_migrate
++#ifdef CONFIG_PCI_MSI
++#define platform_msi_init sn_msi_init
++#else
++#define platform_msi_init ((ia64_mv_msi_init_t*)NULL)
++#endif
+
+ #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,16 @@ 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;
++
++static inline int msi_arch_init(void)
++{
++ if (platform_msi_init)
++ return platform_msi_init();
++
++ /* default ops for most ia64 platforms */
++ msi_register(&msi_apic_ops);
++ return 0;
++}
++
+ #endif /* ASM_MSI_H */
+--- 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(&msi_apic_ops);
++ return 0;
++}
++
+ #endif /* ASM_MSI_H */