diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2006-02-22 21:16:30 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-02-22 21:16:30 -0800 |
commit | d167529dacbad453f1449e5e78b4857c6e687bf0 (patch) | |
tree | 651bab959bbc0204bef30d17f8368f100f6a8421 /pci | |
parent | eb6b406dcc7096974eec722b436e0f05eca353a4 (diff) | |
download | patches-d167529dacbad453f1449e5e78b4857c6e687bf0.tar.gz |
more pci usb and spi patches
Diffstat (limited to 'pci')
-rw-r--r-- | pci/pci-fix-problems-with-msi-x-on-ia64.patch | 115 | ||||
-rw-r--r-- | pci/pci-msi-save-restore-for-suspend-resume.patch | 417 | ||||
-rw-r--r-- | pci/pci-pci-cardbus-cards-hidden-needs-pci-assign-busses-to-fix.patch | 141 | ||||
-rw-r--r-- | pci/pci-remove-msi-save-restore-code-in-specific-driver.patch | 116 | ||||
-rw-r--r-- | pci/pci-resource-address-mismatch.patch | 122 |
5 files changed, 911 insertions, 0 deletions
diff --git a/pci/pci-fix-problems-with-msi-x-on-ia64.patch b/pci/pci-fix-problems-with-msi-x-on-ia64.patch new file mode 100644 index 0000000000000..e42d7e79db720 --- /dev/null +++ b/pci/pci-fix-problems-with-msi-x-on-ia64.patch @@ -0,0 +1,115 @@ +From grundler@cup.hp.com Thu Feb 16 23:58:22 2006 +Date: Thu, 16 Feb 2006 23:58:29 -0800 +From: Grant Grundler <iod00d@hp.com> +To: Greg KH <gregkh@suse.de> +Cc: "Miller, Mike (OS Dev)" <Mike.Miller@hp.com> +Subject: PCI: fix problems with MSI-X on ia64 +Message-ID: <20060217075829.GB22451@esmail.cup.hp.com> +Content-Disposition: inline + +Use "unsigned long" when dealing with PCI resources. +The BAR Indicator Register (BIR) can be a 64-bit value +or the resource could be a 64-bit host physical address. + +Enables ib_mthca and cciss drivers to use MSI-X on ia64 HW. +Problem showed up now because of new system firmware on one platform. +Symptom will either be memory corruption or MCA. + +Second part of this patch deals with "useless" code. +We walk through the steps to find the phys_addr and then +don't use the result. I suspect the intent was to zero +out the respective MSI-X entry but I'm not sure at the moment. +Delete the code inside the #if 0/#endif if it's really +not needed. + +Signed-off-by: Grant Grundler <iod00d@hp.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + +--- + drivers/pci/msi.c | 37 ++++++++++++++++++++++++------------- + 1 file changed, 24 insertions(+), 13 deletions(-) + +--- gregkh-2.6.orig/drivers/pci/msi.c ++++ gregkh-2.6/drivers/pci/msi.c +@@ -805,7 +805,8 @@ static int msix_capability_init(struct p + u32 address_lo; + u32 data; + int vector, pos, i, j, nr_entries, temp = 0; +- u32 phys_addr, table_offset; ++ unsigned long phys_addr; ++ u32 table_offset; + u16 control; + u8 bir; + void __iomem *base; +@@ -815,11 +816,11 @@ static int msix_capability_init(struct p + /* Request & Map MSI-X table region */ + pci_read_config_word(dev, msi_control_reg(pos), &control); + nr_entries = multi_msix_capable(control); +- pci_read_config_dword(dev, msix_table_offset_reg(pos), +- &table_offset); ++ ++ pci_read_config_dword(dev, msix_table_offset_reg(pos), &table_offset); + bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); +- phys_addr = pci_resource_start (dev, bir); +- phys_addr += (u32)(table_offset & ~PCI_MSIX_FLAGS_BIRMASK); ++ table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; ++ phys_addr = pci_resource_start (dev, bir) + table_offset; + base = ioremap_nocache(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE); + if (base == NULL) + return -ENOMEM; +@@ -1059,8 +1060,10 @@ static int msi_free_vector(struct pci_de + * Detect last MSI-X vector to be released. + * Release the MSI-X memory-mapped table. + */ ++#if 0 + int pos, nr_entries; +- u32 phys_addr, table_offset; ++ unsigned long phys_addr; ++ u32 table_offset; + u16 control; + u8 bir; + +@@ -1071,9 +1074,12 @@ static int msi_free_vector(struct pci_de + pci_read_config_dword(dev, msix_table_offset_reg(pos), + &table_offset); + bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); +- phys_addr = pci_resource_start (dev, bir); +- phys_addr += (u32)(table_offset & +- ~PCI_MSIX_FLAGS_BIRMASK); ++ table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; ++ phys_addr = pci_resource_start(dev, bir) + table_offset; ++/* ++ * FIXME! and what did you want to do with phys_addr? ++ */ ++#endif + iounmap(base); + } + } +@@ -1340,7 +1346,9 @@ void msi_remove_pci_irq_vectors(struct p + msi_free_vector(dev, vector, 0); + if (warning) { + /* Force to release the MSI-X memory-mapped table */ +- u32 phys_addr, table_offset; ++#if 0 ++ unsigned long phys_addr; ++ u32 table_offset; + u16 control; + u8 bir; + +@@ -1349,9 +1357,12 @@ void msi_remove_pci_irq_vectors(struct p + pci_read_config_dword(dev, msix_table_offset_reg(pos), + &table_offset); + bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); +- phys_addr = pci_resource_start (dev, bir); +- phys_addr += (u32)(table_offset & +- ~PCI_MSIX_FLAGS_BIRMASK); ++ table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; ++ phys_addr = pci_resource_start(dev, bir) + table_offset; ++/* ++ * FIXME! and what did you want to do with phys_addr? ++ */ ++#endif + iounmap(base); + printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " + "called without free_irq() on all MSI-X vectors\n", diff --git a/pci/pci-msi-save-restore-for-suspend-resume.patch b/pci/pci-msi-save-restore-for-suspend-resume.patch new file mode 100644 index 0000000000000..acf089517e216 --- /dev/null +++ b/pci/pci-msi-save-restore-for-suspend-resume.patch @@ -0,0 +1,417 @@ +From shaohua.li@intel.com Wed Feb 22 00:14:36 2006 +From: Shaohua Li <shaohua.li@intel.com> +Subject: PCI: MSI(X) save/restore for suspend/resume +To: Greg KH <greg@kroah.com> +Cc: Andrew Morton <akpm@osdl.org> +Date: Wed, 22 Feb 2006 16:13:55 +0800 +Message-Id: <1140596035.6056.16.camel@sli10-desk.sh.intel.com> + +Add MSI(X) configure space save/restore in generic PCI helper. + +Signed-off-by: Shaohua Li <shaohua.li@intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/pci/msi.c | 261 +++++++++++++++++++++++++++++++++++++++++++++------- + drivers/pci/pci.c | 9 + + drivers/pci/pci.h | 12 ++ + include/linux/pci.h | 31 ++++++ + 4 files changed, 282 insertions(+), 31 deletions(-) + +--- gregkh-2.6.orig/include/linux/pci.h ++++ gregkh-2.6/include/linux/pci.h +@@ -100,6 +100,12 @@ enum pci_bus_flags { + PCI_BUS_FLAGS_NO_MSI = (pci_bus_flags_t) 1, + }; + ++struct pci_cap_saved_state { ++ struct hlist_node next; ++ char cap_nr; ++ u32 data[0]; ++}; ++ + /* + * The pci_dev structure is used to describe PCI devices. + */ +@@ -159,6 +165,7 @@ struct pci_dev { + unsigned int block_ucfg_access:1; /* userspace config space access is blocked */ + + u32 saved_config_space[16]; /* config space saved at suspend time */ ++ struct hlist_head saved_cap_space; + struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */ + int rom_attr_enabled; /* has display of the rom attribute been enabled? */ + struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ +@@ -169,6 +176,30 @@ struct pci_dev { + #define to_pci_dev(n) container_of(n, struct pci_dev, dev) + #define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL) + ++static inline struct pci_cap_saved_state *pci_find_saved_cap( ++ struct pci_dev *pci_dev,char cap) ++{ ++ struct pci_cap_saved_state *tmp; ++ struct hlist_node *pos; ++ ++ hlist_for_each_entry(tmp, pos, &pci_dev->saved_cap_space, next) { ++ if (tmp->cap_nr == cap) ++ return tmp; ++ } ++ return NULL; ++} ++ ++static inline void pci_add_saved_cap(struct pci_dev *pci_dev, ++ struct pci_cap_saved_state *new_cap) ++{ ++ hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space); ++} ++ ++static inline void pci_remove_saved_cap(struct pci_cap_saved_state *cap) ++{ ++ hlist_del(&cap->next); ++} ++ + /* + * For PCI devices, the region numbers are assigned this way: + * +--- gregkh-2.6.orig/drivers/pci/pci.h ++++ gregkh-2.6/drivers/pci/pci.h +@@ -57,6 +57,18 @@ static inline void disable_msi_mode(stru + static inline int msi_register(struct msi_ops *ops) { return 0; } + #endif + ++#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM) ++int pci_save_msi_state(struct pci_dev *dev); ++int pci_save_msix_state(struct pci_dev *dev); ++int pci_restore_msi_state(struct pci_dev *dev); ++int pci_restore_msix_state(struct pci_dev *dev); ++#else ++static inline int pci_save_msi_state(struct pci_dev *dev) { return 0; } ++static inline int pci_save_msix_state(struct pci_dev *dev) { return 0; } ++static inline int pci_restore_msi_state(struct pci_dev *dev) { return 0; } ++static inline int pci_restore_msix_state(struct pci_dev *dev) { return 0; } ++#endif ++ + extern int pcie_mch_quirk; + extern struct device_attribute pci_dev_attrs[]; + extern struct class_device_attribute class_device_attr_cpuaffinity; +--- gregkh-2.6.orig/drivers/pci/pci.c ++++ gregkh-2.6/drivers/pci/pci.c +@@ -444,6 +444,11 @@ pci_save_state(struct pci_dev *dev) + /* XXX: 100% dword access ok here? */ + for (i = 0; i < 16; i++) + pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]); ++ if ((i = pci_save_msi_state(dev)) != 0) ++ return i; ++ if ((i = pci_save_msix_state(dev)) != 0) ++ return i; ++ + return 0; + } + +@@ -458,6 +463,10 @@ pci_restore_state(struct pci_dev *dev) + + for (i = 0; i < 16; i++) + pci_write_config_dword(dev,i * 4, dev->saved_config_space[i]); ++ if ((i = pci_restore_msi_state(dev)) != 0) ++ return i; ++ if ((i = pci_restore_msix_state(dev)) != 0) ++ return i; + return 0; + } + +--- gregkh-2.6.orig/drivers/pci/msi.c ++++ gregkh-2.6/drivers/pci/msi.c +@@ -514,6 +514,221 @@ void pci_scan_msi_device(struct pci_dev + nr_reserved_vectors++; + } + ++#ifdef CONFIG_PM ++int pci_save_msi_state(struct pci_dev *dev) ++{ ++ int pos, i = 0; ++ u16 control; ++ struct pci_cap_saved_state *save_state; ++ u32 *cap; ++ ++ if (!pci_msi_enable || dev->no_msi) ++ return 0; ++ pos = pci_find_capability(dev, PCI_CAP_ID_MSI); ++ if (pos) ++ return 0; ++ ++ pci_read_config_word(dev, msi_control_reg(pos), &control); ++ if (!(control & PCI_MSI_FLAGS_ENABLE)) ++ return 0; ++ ++ save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u32) * 5, ++ GFP_KERNEL); ++ if (!save_state) { ++ printk(KERN_ERR "Out of memory in pci_save_msi_state\n"); ++ return -ENOMEM; ++ } ++ cap = &save_state->data[0]; ++ ++ pci_read_config_dword(dev, pos, &cap[i++]); ++ control = cap[0] >> 16; ++ pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, &cap[i++]); ++ if (control & PCI_MSI_FLAGS_64BIT) { ++ pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, &cap[i++]); ++ pci_read_config_dword(dev, pos + PCI_MSI_DATA_64, &cap[i++]); ++ } else ++ pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); ++ if (control & PCI_MSI_FLAGS_MASKBIT) ++ pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]); ++ disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); ++ save_state->cap_nr = PCI_CAP_ID_MSI; ++ pci_add_saved_cap(dev, save_state); ++ return 0; ++} ++ ++int pci_restore_msi_state(struct pci_dev *dev) ++{ ++ int i = 0, pos; ++ u16 control; ++ struct pci_cap_saved_state *save_state; ++ u32 *cap; ++ ++ save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSI); ++ pos = pci_find_capability(dev, PCI_CAP_ID_MSI); ++ if (!save_state || pos <= 0) ++ return 0; ++ cap = &save_state->data[0]; ++ ++ control = cap[i++] >> 16; ++ pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, cap[i++]); ++ if (control & PCI_MSI_FLAGS_64BIT) { ++ pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, cap[i++]); ++ pci_write_config_dword(dev, pos + PCI_MSI_DATA_64, cap[i++]); ++ } else ++ pci_write_config_dword(dev, pos + PCI_MSI_DATA_32, cap[i++]); ++ if (control & PCI_MSI_FLAGS_MASKBIT) ++ pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, cap[i++]); ++ pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); ++ enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); ++ pci_remove_saved_cap(save_state); ++ kfree(save_state); ++ return 0; ++} ++ ++int pci_save_msix_state(struct pci_dev *dev) ++{ ++ int pos; ++ u16 control; ++ struct pci_cap_saved_state *save_state; ++ ++ if (!pci_msi_enable || dev->no_msi) ++ return 0; ++ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); ++ if (pos <= 0) ++ return 0; ++ ++ pci_read_config_word(dev, msi_control_reg(pos), &control); ++ if (!(control & PCI_MSIX_FLAGS_ENABLE)) ++ return 0; ++ save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u16), ++ GFP_KERNEL); ++ if (!save_state) { ++ printk(KERN_ERR "Out of memory in pci_save_msix_state\n"); ++ return -ENOMEM; ++ } ++ *((u16 *)&save_state->data[0]) = control; ++ ++ disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); ++ save_state->cap_nr = PCI_CAP_ID_MSIX; ++ pci_add_saved_cap(dev, save_state); ++ return 0; ++} ++ ++int pci_restore_msix_state(struct pci_dev *dev) ++{ ++ u16 save; ++ int pos; ++ int vector, head, tail = 0; ++ void __iomem *base; ++ int j; ++ u32 address_hi; ++ u32 address_lo; ++ u32 data; ++ struct msi_desc *entry; ++ int temp; ++ struct pci_cap_saved_state *save_state; ++ int status = 0; ++ ++ save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX); ++ if (!save_state) ++ return 0; ++ save = *((u16 *)&save_state->data[0]); ++ pci_remove_saved_cap(save_state); ++ kfree(save_state); ++ ++ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); ++ if (pos <= 0) ++ return 0; ++ ++ /* route the table */ ++ temp = dev->irq; ++ if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) ++ return -EINVAL; ++ vector = head = dev->irq; ++ while (head != tail) { ++ entry = msi_desc[vector]; ++ base = entry->mask_base; ++ j = entry->msi_attrib.entry_nr; ++ ++ /* Configure MSI-X capability structure */ ++ 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, ++ base + j * PCI_MSIX_ENTRY_SIZE + ++ PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); ++ writel(data, ++ base + j * PCI_MSIX_ENTRY_SIZE + ++ PCI_MSIX_ENTRY_DATA_OFFSET); ++ ++ tail = msi_desc[vector]->link.tail; ++ vector = tail; ++ } ++ dev->irq = temp; ++ ++ if (status) { ++ printk(KERN_ERR "PCI %s: restore MSI-X configs failed\n", pci_name(dev)); ++ return status; ++ } ++ ++ pci_write_config_word(dev, msi_control_reg(pos), save); ++ enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); ++ return 0; ++} ++#endif ++ ++static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) ++{ ++ u32 address_lo; ++ u32 address_hi; ++ u32 data; ++ int pos, vector = dev->irq; ++ u16 control; ++ int status; ++ ++ pos = pci_find_capability(dev, PCI_CAP_ID_MSI); ++ pci_read_config_word(dev, msi_control_reg(pos), &control); ++ ++ /* Configure MSI capability structure */ ++ 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); ++ pci_write_config_word(dev, msi_data_reg(pos, 1), data); ++ } else ++ 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 */ ++ pci_read_config_dword(dev, ++ msi_mask_bits_reg(pos, is_64bit_address(control)), ++ &maskbits); ++ temp = (1 << multi_msi_capable(control)); ++ temp = ((temp - 1) & ~temp); ++ maskbits |= temp; ++ pci_write_config_dword(dev, ++ msi_mask_bits_reg(pos, is_64bit_address(control)), ++ maskbits); ++ } ++ ++ return 0; ++} ++ + /** + * msi_capability_init - configure device's MSI capability structure + * @dev: pointer to the pci_dev data structure of MSI device function +@@ -527,9 +742,6 @@ static int msi_capability_init(struct pc + { + int status; + struct msi_desc *entry; +- u32 address_lo; +- u32 address_hi; +- u32 data; + int pos, vector; + u16 control; + +@@ -558,11 +770,8 @@ 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); ++ ++ status = msi_register_init(dev, entry); + if (status < 0) { + dev->irq = entry->msi_attrib.default_vector; + kmem_cache_free(msi_cachep, entry); +@@ -571,27 +780,6 @@ static int msi_capability_init(struct pc + /* Replace with MSI handler */ + irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); + +- 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); +- pci_write_config_word(dev, msi_data_reg(pos, 1), data); +- } else +- 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 */ +- pci_read_config_dword(dev, +- msi_mask_bits_reg(pos, is_64bit_address(control)), +- &maskbits); +- temp = (1 << multi_msi_capable(control)); +- temp = ((temp - 1) & ~temp); +- maskbits |= temp; +- pci_write_config_dword(dev, +- msi_mask_bits_reg(pos, is_64bit_address(control)), +- maskbits); +- } + attach_msi_entry(entry, vector); + /* Set MSI enabled bits */ + enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); +@@ -750,8 +938,19 @@ int pci_enable_msi(struct pci_dev* dev) + vector_irq[dev->irq] = -1; + nr_released_vectors--; + spin_unlock_irqrestore(&msi_lock, flags); +- 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 0; ++ } ++ /* Reroute failed, free the vector */ ++ spin_lock_irqsave(&msi_lock, flags); ++ vector_irq[dev->irq] = 0; /* free it */ ++ nr_released_vectors++; ++ spin_unlock_irqrestore(&msi_lock, flags); ++ /* Restore dev->irq to its default pin-assertion vector */ ++ dev->irq = temp; ++ return status; + } + spin_unlock_irqrestore(&msi_lock, flags); + dev->irq = temp; diff --git a/pci/pci-pci-cardbus-cards-hidden-needs-pci-assign-busses-to-fix.patch b/pci/pci-pci-cardbus-cards-hidden-needs-pci-assign-busses-to-fix.patch new file mode 100644 index 0000000000000..37f1a94a3e6ad --- /dev/null +++ b/pci/pci-pci-cardbus-cards-hidden-needs-pci-assign-busses-to-fix.patch @@ -0,0 +1,141 @@ +From akpm@osdl.org Sat Feb 18 01:39:27 2006 +Message-Id: <200602180938.k1I9cE5L005247@shell0.pdx.osdl.net> +From: Bernhard Kaindl <bk@suse.de> +Subject: PCI: PCI/Cardbus cards hidden, needs pci=assign-busses to fix +To: bk@suse.de, alan@lxorguk.ukuu.org.uk, greg@kroah.com, ink@jurassic.park.msu.ru, linux@dominikbrodowski.net, rmk@arm.linux.org.uk +Date: Sat, 18 Feb 2006 01:36:55 -0800 + + +From: Bernhard Kaindl <bk@suse.de> + +"In some cases, especially on modern laptops with a lot of PCI and cardbus +bridges, we're unable to assign correct secondary/subordinate bus numbers +to all cardbus bridges due to BIOS limitations unless we are using +"pci=assign-busses" boot option." -- Ivan Kokshaysky (from a patch comment) + +Without it, Cardbus cards inserted are never seen by PCI because the parent +PCI-PCI Bridge of the Cardbus bridge will not pass and translate Type 1 PCI +configuration cycles correctly and the system will fail to find and +initialise the PCI devices in the system. + +Reference: PCI-PCI Bridges: PCI Configuration Cycles and PCI Bus Numbering: +http://www.science.unitn.it/~fiorella/guidelinux/tlk/node72.html + +The reason for this is that: + ``All PCI busses located behind a PCI-PCI bridge must reside between the +secondary bus number and the subordinate bus number (inclusive).'' + +"pci=assign-busses" makes pcibios_assign_all_busses return 1 and this +turns on PCI renumbering during PCI probing. + +Alan suggested to use DMI automatically set assign-busses on problem systems. + +The only question for me was where to put it. I put it directly before +scanning PCI bus into pcibios_scan_root() because it's called from legacy, +acpi and numa and so it can be one place for all systems and configurations +which may need it. + +AMD64 Laptops are also affected and fixed by assign-busses, and the code is +also incuded from arch/x86_64/pci/ that place will also work for x86_64 +kernels, I only ifdef'-ed the x86-only Laptop in this example. + +Affected and known or assumed to be fixed with it are (found by googling): + +* ASUS Z71V and L3s +* Samsung X20 +* Compaq R3140us and all Compaq R3000 series laptops with TI1620 Controller, + also Compaq R4000 series (from a kernel.org bugreport) +* HP zv5000z (AMD64 3700+, known that fixup_parent_subordinate_busnr fixes it) +* HP zv5200z +* IBM ThinkPad 240 +* An IBM ThinkPad (1.8 GHz Pentium M) debugged by Pavel Machek + gives the correspondig message which detects the possible problem. +* MSI S260 / Medion SIM 2100 MD 95600 + +The patch also expands the "try pci=assign-busses" warning so testers will +help us to update the DMI table. + +Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru> +Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> +Cc: Dominik Brodowski <linux@dominikbrodowski.net> +Cc: Russell King <rmk@arm.linux.org.uk> +Signed-off-by: Andrew Morton <akpm@osdl.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + arch/i386/pci/common.c | 32 ++++++++++++++++++++++++++++++++ + drivers/pci/probe.c | 4 +++- + 2 files changed, 35 insertions(+), 1 deletion(-) + +--- gregkh-2.6.orig/arch/i386/pci/common.c ++++ gregkh-2.6/arch/i386/pci/common.c +@@ -8,6 +8,7 @@ + #include <linux/pci.h> + #include <linux/ioport.h> + #include <linux/init.h> ++#include <linux/dmi.h> + + #include <asm/acpi.h> + #include <asm/segment.h> +@@ -124,12 +125,43 @@ void __devinit pcibios_fixup_bus(struct + pci_read_bridge_bases(b); + } + ++/* ++ * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus) ++ */ ++#ifdef __i386__ ++static int __devinit assign_all_busses(struct dmi_system_id *d) ++{ ++ pci_probe |= PCI_ASSIGN_ALL_BUSSES; ++ printk(KERN_INFO "%s detected: enabling PCI bus# renumbering" ++ " (pci=assign-busses)\n", d->ident); ++ return 0; ++} ++#endif ++ ++/* ++ * Laptops which need pci=assign-busses to see Cardbus cards ++ */ ++static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { ++#ifdef __i386__ ++ { ++ .callback = assign_all_busses, ++ .ident = "Samsung X20 Laptop", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Samsung Electronics"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "SX20S"), ++ }, ++ }, ++#endif /* __i386__ */ ++ {} ++}; + + struct pci_bus * __devinit pcibios_scan_root(int busnum) + { + struct pci_bus *bus = NULL; + struct pci_sysdata *sd; + ++ dmi_check_system(pciprobe_dmi_table); ++ + while ((bus = pci_find_next_bus(bus)) != NULL) { + if (bus->number == busnum) { + /* Already scanned */ +--- gregkh-2.6.orig/drivers/pci/probe.c ++++ gregkh-2.6/drivers/pci/probe.c +@@ -589,13 +589,15 @@ int __devinit pci_scan_bridge(struct pci + (child->number > bus->subordinate) || + (child->number < bus->number) || + (child->subordinate < bus->number)) { +- printk(KERN_WARNING "PCI: Bus #%02x (-#%02x) may be " ++ printk(KERN_WARNING "PCI: Bus #%02x (-#%02x) is " + "hidden behind%s bridge #%02x (-#%02x)%s\n", + child->number, child->subordinate, + bus->self->transparent ? " transparent" : " ", + bus->number, bus->subordinate, + pcibios_assign_all_busses() ? " " : + " (try 'pci=assign-busses')"); ++ printk(KERN_WARNING "Please report the result to " ++ "linux-kernel to fix this permanently\n"); + } + bus = bus->parent; + } diff --git a/pci/pci-remove-msi-save-restore-code-in-specific-driver.patch b/pci/pci-remove-msi-save-restore-code-in-specific-driver.patch new file mode 100644 index 0000000000000..296c9f1bc8b7c --- /dev/null +++ b/pci/pci-remove-msi-save-restore-code-in-specific-driver.patch @@ -0,0 +1,116 @@ +From owner-linux-pci@atrey.karlin.mff.cuni.cz Wed Feb 22 20:57:19 2006 +Subject: PCI: remove msi save/restore code in specific driver +From: Shaohua Li <shaohua.li@intel.com> +To: Cc: Andrew Morton <akpm@osdl.org>, Greg <greg@kroah.com> +Date: Wed, 08 Feb 2006 17:11:40 +0800 +Message-Id: <1139389900.14976.13.camel@sli10-desk.sh.intel.com> + +Remove pcie port driver's msi save/restore code. + +Signed-off-by: Shaohua Li <shaohua.li@intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/pci/pcie/portdrv.h | 1 + drivers/pci/pcie/portdrv_pci.c | 66 ++--------------------------------------- + 2 files changed, 4 insertions(+), 63 deletions(-) + +--- gregkh-2.6.orig/drivers/pci/pcie/portdrv.h ++++ gregkh-2.6/drivers/pci/pcie/portdrv.h +@@ -29,7 +29,6 @@ + + struct pcie_port_device_ext { + int interrupt_mode; /* [0:INTx | 1:MSI | 2:MSI-X] */ +- unsigned int saved_msi_config_space[5]; + }; + + extern struct bus_type pcie_port_bus_type; +--- gregkh-2.6.orig/drivers/pci/pcie/portdrv_pci.c ++++ gregkh-2.6/drivers/pci/pcie/portdrv_pci.c +@@ -30,75 +30,16 @@ MODULE_LICENSE("GPL"); + /* global data */ + static const char device_name[] = "pcieport-driver"; + +-static void pci_save_msi_state(struct pci_dev *dev) ++static int pcie_portdrv_save_config(struct pci_dev *dev) + { +- struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); +- int i = 0, pos; +- u16 control; +- +- if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0) +- return; +- +- pci_read_config_dword(dev, pos, &p_ext->saved_msi_config_space[i++]); +- control = p_ext->saved_msi_config_space[0] >> 16; +- pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, +- &p_ext->saved_msi_config_space[i++]); +- if (control & PCI_MSI_FLAGS_64BIT) { +- pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, +- &p_ext->saved_msi_config_space[i++]); +- pci_read_config_dword(dev, pos + PCI_MSI_DATA_64, +- &p_ext->saved_msi_config_space[i++]); +- } else +- pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, +- &p_ext->saved_msi_config_space[i++]); +- if (control & PCI_MSI_FLAGS_MASKBIT) +- pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, +- &p_ext->saved_msi_config_space[i++]); +-} +- +-static void pci_restore_msi_state(struct pci_dev *dev) +-{ +- struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); +- int i = 0, pos; +- u16 control; +- +- if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0) +- return; +- +- control = p_ext->saved_msi_config_space[i++] >> 16; +- pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); +- pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, +- p_ext->saved_msi_config_space[i++]); +- if (control & PCI_MSI_FLAGS_64BIT) { +- pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, +- p_ext->saved_msi_config_space[i++]); +- pci_write_config_dword(dev, pos + PCI_MSI_DATA_64, +- p_ext->saved_msi_config_space[i++]); +- } else +- pci_write_config_dword(dev, pos + PCI_MSI_DATA_32, +- p_ext->saved_msi_config_space[i++]); +- if (control & PCI_MSI_FLAGS_MASKBIT) +- pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, +- p_ext->saved_msi_config_space[i++]); +-} +- +-static void pcie_portdrv_save_config(struct pci_dev *dev) +-{ +- struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); +- +- pci_save_state(dev); +- if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE) +- pci_save_msi_state(dev); ++ return pci_save_state(dev); + } + + static int pcie_portdrv_restore_config(struct pci_dev *dev) + { +- struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); + int retval; + + pci_restore_state(dev); +- if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE) +- pci_restore_msi_state(dev); + retval = pci_enable_device(dev); + if (retval) + return retval; +@@ -149,7 +90,8 @@ static int pcie_portdrv_suspend (struct + { + int ret = pcie_port_device_suspend(dev, state); + +- pcie_portdrv_save_config(dev); ++ if (!ret) ++ ret = pcie_portdrv_save_config(dev); + return ret; + } + diff --git a/pci/pci-resource-address-mismatch.patch b/pci/pci-resource-address-mismatch.patch new file mode 100644 index 0000000000000..356248673131c --- /dev/null +++ b/pci/pci-resource-address-mismatch.patch @@ -0,0 +1,122 @@ +From akpm@osdl.org Wed Feb 22 15:48:22 2006 +Message-Id: <200602222348.k1MNmIhI032277@shell0.pdx.osdl.net> +From: Linus Torvalds <torvalds@osdl.org> +Subject: PCI: resource address mismatch +To: torvalds@osdl.org, adaplas@pol.net, bjk@luxsci.net, greg@kroah.com, ink@jurassic.park.msu.ru, mm-commits@vger.kernel.org +Date: Wed, 22 Feb 2006 15:50:30 -0800 + + +From: Linus Torvalds <torvalds@osdl.org> + +On Tue, 21 Feb 2006, Ivan Kokshaysky wrote: +> There are two bogus entries in the BIOS memory map table which are +> conflicting with a prefetchable memory range of the AGP bridge: +> +> BIOS-e820: 00000000fec00000 - 00000000fec01000 (reserved) +> BIOS-e820: 00000000fee00000 - 00000000fee01000 (reserved) +> +> 0000:00:02.0 PCI bridge: Silicon Integrated Systems [SiS] Virtual PCI-to-PCI bridge (AGP) (prog-if 00 [Normal decode]) +> Flags: bus master, fast devsel, latency 0 +> Bus: primary=00, secondary=01, subordinate=01, sec-latency=0 +> I/O behind bridge: 0000c000-0000cfff +> Memory behind bridge: e7e00000-e7efffff +> Prefetchable memory behind bridge: fec00000-ffcfffff +> ^^^^^^^^^^^^^^^^^ + +Yes. However, it's pretty clear that the e820 entries are there for a +reason. Probably they are a hack by the BIOS maintainers to keep Windows +from stomping/moving that region, exactly because they want to keep the +bridge where it is (or, it's actually for the BIOS itself - the BIOS +tables are a horrid mess, and BIOS engineers are pretty hacky people: +they'll add random entries to make their own broken algorithms do the +"right thing"). + +> Starting from 2.6.13, kernel tries to resolve that sort of conflicts, +> so that prefetch window of the bridge and the framebuffer memory behind +> it get moved to 0x10000000. + +I think we could (and probably should) solve this another way: consider +the ACPI "reserved regions" from the e820 map exactly the same way that we +do other ACPI hints - they should restrict _new_ allocations, but not +impact stuff we figure out on our own. + +Basically, right now we assign _unassigned_ resources at "fs_initcall" +time. If we were to add in the e820 "reserved region" stuff before that +(but after we've done PCI discovery), we'd probably do the right thing. + +Right now we do the e820 reserved regions very early indeed: we call +"register_memory()" from setup_arch(). We could move at least part of it +(the part that registers the resources) down a bit. + +Here's a test-patch. I'm not saying we should absolutely do this, but it +might be interesting to try... + +Cc: "Antonino A. Daplas" <adaplas@pol.net> +Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru> +Cc: <bjk@luxsci.net> +Signed-off-by: Andrew Morton <akpm@osdl.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + arch/i386/kernel/efi.c | 2 +- + arch/i386/kernel/setup.c | 22 +++++++++++++++++----- + 2 files changed, 18 insertions(+), 6 deletions(-) + +--- gregkh-2.6.orig/arch/i386/kernel/efi.c ++++ gregkh-2.6/arch/i386/kernel/efi.c +@@ -539,7 +539,7 @@ efi_initialize_iomem_resources(struct re + if ((md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) > + 0x100000000ULL) + continue; +- res = alloc_bootmem_low(sizeof(struct resource)); ++ res = kzalloc(sizeof(struct resource), GFP_ATOMIC); + switch (md->type) { + case EFI_RESERVED_TYPE: + res->name = "Reserved Memory"; +--- gregkh-2.6.orig/arch/i386/kernel/setup.c ++++ gregkh-2.6/arch/i386/kernel/setup.c +@@ -1288,7 +1288,7 @@ legacy_init_iomem_resources(struct resou + struct resource *res; + if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL) + continue; +- res = alloc_bootmem_low(sizeof(struct resource)); ++ res = kzalloc(sizeof(struct resource), GFP_ATOMIC); + switch (e820.map[i].type) { + case E820_RAM: res->name = "System RAM"; break; + case E820_ACPI: res->name = "ACPI Tables"; break; +@@ -1316,13 +1316,15 @@ legacy_init_iomem_resources(struct resou + + /* + * Request address space for all standard resources ++ * ++ * This is called just before pcibios_assign_resources(), which is also ++ * an fs_initcall, but is linked in later (in arch/i386/pci/i386.c). + */ +-static void __init register_memory(void) ++static int __init request_standard_resources(void) + { +- unsigned long gapstart, gapsize, round; +- unsigned long long last; +- int i; ++ int i; + ++ printk("Setting up standard PCI resources\n"); + if (efi_enabled) + efi_initialize_iomem_resources(&code_resource, &data_resource); + else +@@ -1334,6 +1336,16 @@ static void __init register_memory(void) + /* request I/O space for devices used on all i[345]86 PCs */ + for (i = 0; i < STANDARD_IO_RESOURCES; i++) + request_resource(&ioport_resource, &standard_io_resources[i]); ++ return 0; ++} ++ ++fs_initcall(request_standard_resources); ++ ++static void __init register_memory(void) ++{ ++ unsigned long gapstart, gapsize, round; ++ unsigned long long last; ++ int i; + + /* + * Search for the bigest gap in the low 32 bits of the e820 |