diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2006-04-13 16:59:01 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-04-13 16:59:01 -0700 |
commit | a5de3b68f706cc28f0d94ee85a21d4a234014942 (patch) | |
tree | aa0452abd187dae57a5d48750b4c3c2c577ce506 /pci | |
parent | 6939471a340468dc686845aef597be6c4a3346aa (diff) | |
download | patches-a5de3b68f706cc28f0d94ee85a21d4a234014942.tar.gz |
patches added and refresh
Diffstat (limited to 'pci')
-rw-r--r-- | pci/pci-64-bit-resources-drivers-net-changes.patch | 4 | ||||
-rw-r--r-- | pci/pci-64-bit-resources-drivers-others-changes.patch | 2 | ||||
-rw-r--r-- | pci/pci-msi-abstractions-and-support-for-altix.patch | 827 |
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 */ |