diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/access.c | 6 | ||||
-rw-r--r-- | drivers/pci/hotplug-pci.c | 30 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 51 | ||||
-rw-r--r-- | drivers/pci/hotplug/cpci_hotplug_pci.c | 35 | ||||
-rw-r--r-- | drivers/pci/hotplug/cpqphp_pci.c | 8 | ||||
-rw-r--r-- | drivers/pci/hotplug/ibmphp_core.c | 8 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_pci.c | 28 | ||||
-rw-r--r-- | drivers/pci/hotplug/sgi_hotplug.c | 12 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_pci.c | 45 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_sysfs.c | 6 | ||||
-rw-r--r-- | drivers/pci/iov.c | 4 | ||||
-rw-r--r-- | drivers/pci/pci.c | 256 | ||||
-rw-r--r-- | drivers/pci/pci.h | 9 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_acpi.c | 2 | ||||
-rw-r--r-- | drivers/pci/probe.c | 191 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 116 | ||||
-rw-r--r-- | drivers/pci/remove.c | 1 | ||||
-rw-r--r-- | drivers/pci/search.c | 2 | ||||
-rw-r--r-- | drivers/pci/setup-bus.c | 24 |
19 files changed, 526 insertions, 308 deletions
diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 2a581642c237..ba91a7e17519 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -162,7 +162,8 @@ int pci_user_read_config_##size \ if (ret > 0) \ ret = -EINVAL; \ return ret; \ -} +} \ +EXPORT_SYMBOL_GPL(pci_user_read_config_##size); /* Returns 0 on success, negative values indicate error. */ #define PCI_USER_WRITE_CONFIG(size,type) \ @@ -181,7 +182,8 @@ int pci_user_write_config_##size \ if (ret > 0) \ ret = -EINVAL; \ return ret; \ -} +} \ +EXPORT_SYMBOL_GPL(pci_user_write_config_##size); PCI_USER_READ_CONFIG(byte, u8) PCI_USER_READ_CONFIG(word, u16) diff --git a/drivers/pci/hotplug-pci.c b/drivers/pci/hotplug-pci.c index d3509cdeb554..6258dc260d9f 100644 --- a/drivers/pci/hotplug-pci.c +++ b/drivers/pci/hotplug-pci.c @@ -4,18 +4,26 @@ #include <linux/export.h> #include "pci.h" - -unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus) +int __ref pci_hp_add_bridge(struct pci_dev *dev) { - unsigned int max; - - max = pci_scan_child_bus(bus); + struct pci_bus *parent = dev->bus; + int pass, busnr, start = parent->busn_res.start; + int end = parent->busn_res.end; - /* - * Make the discovered devices available. - */ - pci_bus_add_devices(bus); + for (busnr = start; busnr <= end; busnr++) { + if (!pci_find_bus(pci_domain_nr(parent), busnr)) + break; + } + if (busnr-- > end) { + printk(KERN_ERR "No bus number available for hot-added bridge %s\n", + pci_name(dev)); + return -1; + } + for (pass = 0; pass < 2; pass++) + busnr = pci_scan_bridge(parent, dev, busnr, pass); + if (!dev->subordinate) + return -1; - return max; + return 0; } -EXPORT_SYMBOL(pci_do_scan_bus); +EXPORT_SYMBOL_GPL(pci_hp_add_bridge); diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 09bf37721842..395c67d3d296 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -100,11 +100,11 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val, PCI_PRIMARY_BUS, &buses); - if (((buses >> 8) & 0xff) != bus->secondary) { + if (((buses >> 8) & 0xff) != bus->busn_res.start) { buses = (buses & 0xff000000) | ((unsigned int)(bus->primary) << 0) - | ((unsigned int)(bus->secondary) << 8) - | ((unsigned int)(bus->subordinate) << 16); + | ((unsigned int)(bus->busn_res.start) << 8) + | ((unsigned int)(bus->busn_res.end) << 16); pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); } return NOTIFY_OK; @@ -697,7 +697,7 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus) * bus->subordinate value because it could have * padding in it. */ - max = bus->secondary; + max = bus->busn_res.start; list_for_each(tmp, &bus->children) { n = pci_bus_max_busnr(pci_bus_b(tmp)); @@ -883,6 +883,24 @@ static void disable_bridges(struct pci_bus *bus) } } +/* return first device in slot, acquiring a reference on it */ +static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot) +{ + struct pci_bus *bus = slot->bridge->pci_bus; + struct pci_dev *dev; + struct pci_dev *ret = NULL; + + down_read(&pci_bus_sem); + list_for_each_entry(dev, &bus->devices, bus_list) + if (PCI_SLOT(dev->devfn) == slot->device) { + ret = pci_dev_get(dev); + break; + } + up_read(&pci_bus_sem); + + return ret; +} + /** * disable_device - disable a slot * @slot: ACPI PHP slot @@ -898,6 +916,7 @@ static int disable_device(struct acpiphp_slot *slot) pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0)); if (!pdev) goto err_exit; + pci_dev_put(pdev); list_for_each_entry(func, &slot->funcs, sibling) { if (func->bridge) { @@ -906,18 +925,22 @@ static int disable_device(struct acpiphp_slot *slot) (u32)1, NULL, NULL); func->bridge = NULL; } + } - pdev = pci_get_slot(slot->bridge->pci_bus, - PCI_DEVFN(slot->device, func->function)); - if (pdev) { - pci_stop_bus_device(pdev); - if (pdev->subordinate) { - disable_bridges(pdev->subordinate); - pci_disable_device(pdev); - } - __pci_remove_bus_device(pdev); - pci_dev_put(pdev); + /* + * enable_device() enumerates all functions in this device via + * pci_scan_slot(), whether they have associated ACPI hotplug + * methods (_EJ0, etc.) or not. Therefore, we remove all functions + * here. + */ + while ((pdev = dev_in_slot(slot))) { + pci_stop_bus_device(pdev); + if (pdev->subordinate) { + disable_bridges(pdev->subordinate); + pci_disable_device(pdev); } + __pci_remove_bus_device(pdev); + pci_dev_put(pdev); } list_for_each_entry(func, &slot->funcs, sibling) { diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index ae853ccd0cd5..dcc75c785443 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -285,42 +285,19 @@ int __ref cpci_configure_slot(struct slot *slot) for (fn = 0; fn < 8; fn++) { struct pci_dev *dev; - dev = pci_get_slot(parent, PCI_DEVFN(PCI_SLOT(slot->devfn), fn)); + dev = pci_get_slot(parent, + PCI_DEVFN(PCI_SLOT(slot->devfn), fn)); if (!dev) continue; if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || - (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) { - /* Find an unused bus number for the new bridge */ - struct pci_bus *child; - unsigned char busnr, start = parent->secondary; - unsigned char end = parent->subordinate; - - for (busnr = start; busnr <= end; busnr++) { - if (!pci_find_bus(pci_domain_nr(parent), - busnr)) - break; - } - if (busnr >= end) { - err("No free bus for hot-added bridge\n"); - pci_dev_put(dev); - continue; - } - child = pci_add_new_bus(parent, dev, busnr); - if (!child) { - err("Cannot add new bus for %s\n", - pci_name(dev)); - pci_dev_put(dev); - continue; - } - child->subordinate = pci_do_scan_bus(child); - pci_bus_size_bridges(child); - } + (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) + pci_hp_add_bridge(dev); pci_dev_put(dev); } - pci_bus_assign_resources(parent); + pci_assign_unassigned_bridge_resources(parent->self); + pci_bus_add_devices(parent); - pci_enable_bridges(parent); dbg("%s - exit", __func__); return 0; diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 1c8494021a42..09801c6945ce 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -83,7 +83,6 @@ static void __iomem *detect_HRT_floating_pointer(void __iomem *begin, void __iom int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) { - unsigned char bus; struct pci_bus *child; int num; @@ -106,9 +105,10 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) } if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus); - child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus); - pci_do_scan_bus(child); + pci_hp_add_bridge(func->pci_dev); + child = func->pci_dev->subordinate; + if (child) + pci_bus_add_devices(child); } pci_dev_put(func->pci_dev); diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index 4fda7e6a86a7..7dccad5fc891 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -775,7 +775,6 @@ static u8 bus_structure_fixup(u8 busno) static int ibm_configure_device(struct pci_func *func) { - unsigned char bus; struct pci_bus *child; int num; int flag = 0; /* this is to make sure we don't double scan the bus, @@ -805,9 +804,10 @@ static int ibm_configure_device(struct pci_func *func) } } if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) { - pci_read_config_byte(func->dev, PCI_SECONDARY_BUS, &bus); - child = pci_add_new_bus(func->dev->bus, func->dev, bus); - pci_do_scan_bus(child); + pci_hp_add_bridge(func->dev); + child = func->dev->subordinate; + if (child) + pci_bus_add_devices(child); } return 0; diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 47d9dc06b109..09cecaf450c5 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -34,29 +34,6 @@ #include "../pci.h" #include "pciehp.h" -static int __ref pciehp_add_bridge(struct pci_dev *dev) -{ - struct pci_bus *parent = dev->bus; - int pass, busnr, start = parent->secondary; - int end = parent->subordinate; - - for (busnr = start; busnr <= end; busnr++) { - if (!pci_find_bus(pci_domain_nr(parent), busnr)) - break; - } - if (busnr-- > end) { - err("No bus number available for hot-added bridge %s\n", - pci_name(dev)); - return -1; - } - for (pass = 0; pass < 2; pass++) - busnr = pci_scan_bridge(parent, dev, busnr, pass); - if (!dev->subordinate) - return -1; - - return 0; -} - int pciehp_configure_device(struct slot *p_slot) { struct pci_dev *dev; @@ -85,9 +62,8 @@ int pciehp_configure_device(struct slot *p_slot) if (!dev) continue; if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || - (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) { - pciehp_add_bridge(dev); - } + (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) + pci_hp_add_bridge(dev); pci_dev_put(dev); } diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index de573113c102..f64ca92253da 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -397,13 +397,11 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) else sn_io_slot_fixup(dev); if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - unsigned char sec_bus; - pci_read_config_byte(dev, PCI_SECONDARY_BUS, - &sec_bus); - new_bus = pci_add_new_bus(dev->bus, dev, - sec_bus); - pci_scan_child_bus(new_bus); - new_ppb = 1; + pci_hp_add_bridge(dev); + if (dev->subordinate) { + new_bus = dev->subordinate; + new_ppb = 1; + } } pci_dev_put(dev); } diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index df7e4bfadae3..c627ed9957d1 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c @@ -37,9 +37,10 @@ int __ref shpchp_configure_device(struct slot *p_slot) { struct pci_dev *dev; - struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; - int num, fn; struct controller *ctrl = p_slot->ctrl; + struct pci_dev *bridge = ctrl->pci_dev; + struct pci_bus *parent = bridge->subordinate; + int num, fn; dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0)); if (dev) { @@ -61,39 +62,23 @@ int __ref shpchp_configure_device(struct slot *p_slot) if (!dev) continue; if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || - (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) { - /* Find an unused bus number for the new bridge */ - struct pci_bus *child; - unsigned char busnr, start = parent->secondary; - unsigned char end = parent->subordinate; - for (busnr = start; busnr <= end; busnr++) { - if (!pci_find_bus(pci_domain_nr(parent), - busnr)) - break; - } - if (busnr > end) { - ctrl_err(ctrl, - "No free bus for hot-added bridge\n"); - pci_dev_put(dev); - continue; - } - child = pci_add_new_bus(parent, dev, busnr); - if (!child) { - ctrl_err(ctrl, "Cannot add new bus for %s\n", - pci_name(dev)); - pci_dev_put(dev); - continue; - } - child->subordinate = pci_do_scan_bus(child); - pci_bus_size_bridges(child); - } + (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) + pci_hp_add_bridge(dev); + pci_dev_put(dev); + } + + pci_assign_unassigned_bridge_resources(bridge); + + for (fn = 0; fn < 8; fn++) { + dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn)); + if (!dev) + continue; pci_configure_slot(dev); pci_dev_put(dev); } - pci_bus_assign_resources(parent); pci_bus_add_devices(parent); - pci_enable_bridges(parent); + return 0; } diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c index efa30da1ae8f..eeb23ceae4a8 100644 --- a/drivers/pci/hotplug/shpchp_sysfs.c +++ b/drivers/pci/hotplug/shpchp_sysfs.c @@ -73,13 +73,13 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha } } out += sprintf(out, "Free resources: bus numbers\n"); - for (busnr = bus->secondary; busnr <= bus->subordinate; busnr++) { + for (busnr = bus->busn_res.start; busnr <= bus->busn_res.end; busnr++) { if (!pci_find_bus(pci_domain_nr(bus), busnr)) break; } - if (busnr < bus->subordinate) + if (busnr < bus->busn_res.end) out += sprintf(out, "start = %8.8x, length = %8.8x\n", - busnr, (bus->subordinate - busnr)); + busnr, (int)(bus->busn_res.end - busnr)); return out - buf; } diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 6554e1a0f634..74bbaf82638d 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -47,7 +47,7 @@ static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr) if (!child) return NULL; - child->subordinate = busnr; + pci_bus_insert_busn_res(child, busnr, busnr); child->dev.parent = bus->bridge; rc = pci_bus_add_child(child); if (rc) { @@ -327,7 +327,7 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) iov->offset = offset; iov->stride = stride; - if (virtfn_bus(dev, nr_virtfn - 1) > dev->bus->subordinate) { + if (virtfn_bus(dev, nr_virtfn - 1) > dev->bus->busn_res.end) { dev_err(&dev->dev, "SR-IOV: bus number out of range\n"); return -ENOMEM; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7f1310e58534..87928fde77b0 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -110,7 +110,7 @@ unsigned char pci_bus_max_busnr(struct pci_bus* bus) struct list_head *tmp; unsigned char max, n; - max = bus->subordinate; + max = bus->busn_res.end; list_for_each(tmp, &bus->children) { n = pci_bus_max_busnr(pci_bus_b(tmp)); if(n > max) @@ -136,30 +136,6 @@ void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar) EXPORT_SYMBOL_GPL(pci_ioremap_bar); #endif -#if 0 -/** - * pci_max_busnr - returns maximum PCI bus number - * - * Returns the highest PCI bus number present in the system global list of - * PCI buses. - */ -unsigned char __devinit -pci_max_busnr(void) -{ - struct pci_bus *bus = NULL; - unsigned char max, n; - - max = 0; - while ((bus = pci_find_next_bus(bus)) != NULL) { - n = pci_bus_max_busnr(bus); - if(n > max) - max = n; - } - return max; -} - -#endif /* 0 */ - #define PCI_FIND_CAP_TTL 48 static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn, @@ -278,6 +254,38 @@ int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap) } /** + * pci_pcie_cap2 - query for devices' PCI_CAP_ID_EXP v2 capability structure + * @dev: PCI device to check + * + * Like pci_pcie_cap() but also checks that the PCIe capability version is + * >= 2. Note that v1 capability structures could be sparse in that not + * all register fields were required. v2 requires the entire structure to + * be present size wise, while still allowing for non-implemented registers + * to exist but they must be hardwired to 0. + * + * Due to the differences in the versions of capability structures, one + * must be careful not to try and access non-existant registers that may + * exist in early versions - v1 - of Express devices. + * + * Returns the offset of the PCIe capability structure as long as the + * capability version is >= 2; otherwise 0 is returned. + */ +static int pci_pcie_cap2(struct pci_dev *dev) +{ + u16 flags; + int pos; + + pos = pci_pcie_cap(dev); + if (pos) { + pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &flags); + if ((flags & PCI_EXP_FLAGS_VERS) < 2) + pos = 0; + } + + return pos; +} + +/** * pci_find_ext_capability - Find an extended capability * @dev: PCI device to query * @cap: capability code @@ -329,49 +337,6 @@ int pci_find_ext_capability(struct pci_dev *dev, int cap) } EXPORT_SYMBOL_GPL(pci_find_ext_capability); -/** - * pci_bus_find_ext_capability - find an extended capability - * @bus: the PCI bus to query - * @devfn: PCI device to query - * @cap: capability code - * - * Like pci_find_ext_capability() but works for pci devices that do not have a - * pci_dev structure set up yet. - * - * Returns the address of the requested capability structure within the - * device's PCI configuration space or 0 in case the device does not - * support it. - */ -int pci_bus_find_ext_capability(struct pci_bus *bus, unsigned int devfn, - int cap) -{ - u32 header; - int ttl; - int pos = PCI_CFG_SPACE_SIZE; - - /* minimum 8 bytes per capability */ - ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; - - if (!pci_bus_read_config_dword(bus, devfn, pos, &header)) - return 0; - if (header == 0xffffffff || header == 0) - return 0; - - while (ttl-- > 0) { - if (PCI_EXT_CAP_ID(header) == cap) - return pos; - - pos = PCI_EXT_CAP_NEXT(header); - if (pos < PCI_CFG_SPACE_SIZE) - break; - - if (!pci_bus_read_config_dword(bus, devfn, pos, &header)) - break; - } - - return 0; -} - static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap) { int rc, ttl = PCI_FIND_CAP_TTL; @@ -822,12 +787,6 @@ EXPORT_SYMBOL(pci_choose_state); ((flags & PCI_EXP_FLAGS_VERS) > 1 || \ (type == PCI_EXP_TYPE_ROOT_PORT || \ type == PCI_EXP_TYPE_RC_EC)) -#define pcie_cap_has_devctl2(type, flags) \ - ((flags & PCI_EXP_FLAGS_VERS) > 1) -#define pcie_cap_has_lnkctl2(type, flags) \ - ((flags & PCI_EXP_FLAGS_VERS) > 1) -#define pcie_cap_has_sltctl2(type, flags) \ - ((flags & PCI_EXP_FLAGS_VERS) > 1) static struct pci_cap_saved_state *pci_find_saved_cap( struct pci_dev *pci_dev, char cap) @@ -870,13 +829,14 @@ static int pci_save_pcie_state(struct pci_dev *dev) pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]); if (pcie_cap_has_rtctl(dev->pcie_type, flags)) pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]); - if (pcie_cap_has_devctl2(dev->pcie_type, flags)) - pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &cap[i++]); - if (pcie_cap_has_lnkctl2(dev->pcie_type, flags)) - pci_read_config_word(dev, pos + PCI_EXP_LNKCTL2, &cap[i++]); - if (pcie_cap_has_sltctl2(dev->pcie_type, flags)) - pci_read_config_word(dev, pos + PCI_EXP_SLTCTL2, &cap[i++]); + pos = pci_pcie_cap2(dev); + if (!pos) + return 0; + + pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &cap[i++]); + pci_read_config_word(dev, pos + PCI_EXP_LNKCTL2, &cap[i++]); + pci_read_config_word(dev, pos + PCI_EXP_SLTCTL2, &cap[i++]); return 0; } @@ -903,12 +863,14 @@ static void pci_restore_pcie_state(struct pci_dev *dev) pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]); if (pcie_cap_has_rtctl(dev->pcie_type, flags)) pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]); - if (pcie_cap_has_devctl2(dev->pcie_type, flags)) - pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, cap[i++]); - if (pcie_cap_has_lnkctl2(dev->pcie_type, flags)) - pci_write_config_word(dev, pos + PCI_EXP_LNKCTL2, cap[i++]); - if (pcie_cap_has_sltctl2(dev->pcie_type, flags)) - pci_write_config_word(dev, pos + PCI_EXP_SLTCTL2, cap[i++]); + + pos = pci_pcie_cap2(dev); + if (!pos) + return; + + pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, cap[i++]); + pci_write_config_word(dev, pos + PCI_EXP_LNKCTL2, cap[i++]); + pci_write_config_word(dev, pos + PCI_EXP_SLTCTL2, cap[i++]); } @@ -1983,7 +1945,7 @@ void pci_enable_ari(struct pci_dev *dev) { int pos; u32 cap; - u16 flags, ctrl; + u16 ctrl; struct pci_dev *bridge; if (pcie_ari_disabled || !pci_is_pcie(dev) || dev->devfn) @@ -1994,18 +1956,14 @@ void pci_enable_ari(struct pci_dev *dev) return; bridge = dev->bus->self; - if (!bridge || !pci_is_pcie(bridge)) + if (!bridge) return; - pos = pci_pcie_cap(bridge); + /* ARI is a PCIe cap v2 feature */ + pos = pci_pcie_cap2(bridge); if (!pos) return; - /* ARI is a PCIe v2 feature */ - pci_read_config_word(bridge, pos + PCI_EXP_FLAGS, &flags); - if ((flags & PCI_EXP_FLAGS_VERS) < 2) - return; - pci_read_config_dword(bridge, pos + PCI_EXP_DEVCAP2, &cap); if (!(cap & PCI_EXP_DEVCAP2_ARI)) return; @@ -2018,7 +1976,7 @@ void pci_enable_ari(struct pci_dev *dev) } /** - * pci_enable_ido - enable ID-based ordering on a device + * pci_enable_ido - enable ID-based Ordering on a device * @dev: the PCI device * @type: which types of IDO to enable * @@ -2031,7 +1989,8 @@ void pci_enable_ido(struct pci_dev *dev, unsigned long type) int pos; u16 ctrl; - pos = pci_pcie_cap(dev); + /* ID-based Ordering is a PCIe cap v2 feature */ + pos = pci_pcie_cap2(dev); if (!pos) return; @@ -2054,10 +2013,8 @@ void pci_disable_ido(struct pci_dev *dev, unsigned long type) int pos; u16 ctrl; - if (!pci_is_pcie(dev)) - return; - - pos = pci_pcie_cap(dev); + /* ID-based Ordering is a PCIe cap v2 feature */ + pos = pci_pcie_cap2(dev); if (!pos) return; @@ -2096,10 +2053,8 @@ int pci_enable_obff(struct pci_dev *dev, enum pci_obff_signal_type type) u16 ctrl; int ret; - if (!pci_is_pcie(dev)) - return -ENOTSUPP; - - pos = pci_pcie_cap(dev); + /* OBFF is a PCIe cap v2 feature */ + pos = pci_pcie_cap2(dev); if (!pos) return -ENOTSUPP; @@ -2149,10 +2104,8 @@ void pci_disable_obff(struct pci_dev *dev) int pos; u16 ctrl; - if (!pci_is_pcie(dev)) - return; - - pos = pci_pcie_cap(dev); + /* OBFF is a PCIe cap v2 feature */ + pos = pci_pcie_cap2(dev); if (!pos) return; @@ -2169,15 +2122,13 @@ EXPORT_SYMBOL(pci_disable_obff); * RETURNS: * True if @dev supports latency tolerance reporting, false otherwise. */ -bool pci_ltr_supported(struct pci_dev *dev) +static bool pci_ltr_supported(struct pci_dev *dev) { int pos; u32 cap; - if (!pci_is_pcie(dev)) - return false; - - pos = pci_pcie_cap(dev); + /* LTR is a PCIe cap v2 feature */ + pos = pci_pcie_cap2(dev); if (!pos) return false; @@ -2185,7 +2136,6 @@ bool pci_ltr_supported(struct pci_dev *dev) return cap & PCI_EXP_DEVCAP2_LTR; } -EXPORT_SYMBOL(pci_ltr_supported); /** * pci_enable_ltr - enable latency tolerance reporting @@ -2206,7 +2156,8 @@ int pci_enable_ltr(struct pci_dev *dev) if (!pci_ltr_supported(dev)) return -ENOTSUPP; - pos = pci_pcie_cap(dev); + /* LTR is a PCIe cap v2 feature */ + pos = pci_pcie_cap2(dev); if (!pos) return -ENOTSUPP; @@ -2241,7 +2192,8 @@ void pci_disable_ltr(struct pci_dev *dev) if (!pci_ltr_supported(dev)) return; - pos = pci_pcie_cap(dev); + /* LTR is a PCIe cap v2 feature */ + pos = pci_pcie_cap2(dev); if (!pos) return; @@ -2360,6 +2312,75 @@ void pci_enable_acs(struct pci_dev *dev) } /** + * pci_acs_enabled - test ACS against required flags for a given device + * @pdev: device to test + * @acs_flags: required PCI ACS flags + * + * Return true if the device supports the provided flags. Automatically + * filters out flags that are not implemented on multifunction devices. + */ +bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags) +{ + int pos, ret; + u16 ctrl; + + ret = pci_dev_specific_acs_enabled(pdev, acs_flags); + if (ret >= 0) + return ret > 0; + + if (!pci_is_pcie(pdev)) + return false; + + /* Filter out flags not applicable to multifunction */ + if (pdev->multifunction) + acs_flags &= (PCI_ACS_RR | PCI_ACS_CR | + PCI_ACS_EC | PCI_ACS_DT); + + if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM || + pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT || + pdev->multifunction) { + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS); + if (!pos) + return false; + + pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl); + if ((ctrl & acs_flags) != acs_flags) + return false; + } + + return true; +} + +/** + * pci_acs_path_enable - test ACS flags from start to end in a hierarchy + * @start: starting downstream device + * @end: ending upstream device or NULL to search to the root bus + * @acs_flags: required flags + * + * Walk up a device tree from start to end testing PCI ACS support. If + * any step along the way does not support the required flags, return false. + */ +bool pci_acs_path_enabled(struct pci_dev *start, + struct pci_dev *end, u16 acs_flags) +{ + struct pci_dev *pdev, *parent = start; + + do { + pdev = parent; + + if (!pci_acs_enabled(pdev, acs_flags)) + return false; + + if (pci_is_root_bus(pdev->bus)) + return (end == NULL); + + parent = pdev->bus->self; + } while (pdev != end); + + return true; +} + +/** * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge * @dev: the PCI device * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD) @@ -2876,6 +2897,9 @@ bool pci_intx_mask_supported(struct pci_dev *dev) bool mask_supported = false; u16 orig, new; + if (dev->broken_intx_masking) + return false; + pci_cfg_access_lock(dev); pci_read_config_word(dev, PCI_COMMAND, &orig); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index e4943479b234..4884d77d33b6 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -86,13 +86,6 @@ static inline bool pci_is_bridge(struct pci_dev *pci_dev) return !!(pci_dev->subordinate); } -extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); -extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val); -extern int pci_user_read_config_dword(struct pci_dev *dev, int where, u32 *val); -extern int pci_user_write_config_byte(struct pci_dev *dev, int where, u8 val); -extern int pci_user_write_config_word(struct pci_dev *dev, int where, u16 val); -extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val); - struct pci_vpd_ops { ssize_t (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf); ssize_t (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf); @@ -124,7 +117,7 @@ static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; } #endif /* Functions for PCI Hotplug drivers to use */ -extern unsigned int pci_do_scan_bus(struct pci_bus *bus); +int pci_hp_add_bridge(struct pci_dev *dev); #ifdef HAVE_PCI_LEGACY extern void pci_create_legacy_files(struct pci_bus *bus); diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index 275bf158ffa7..124f20ff11b2 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c @@ -59,7 +59,7 @@ static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data) p = (struct acpi_hest_aer_common *)(hest_hdr + 1); if (p->flags & ACPI_HEST_GLOBAL) { - if ((info->pci_dev->is_pcie && + if ((pci_is_pcie(info->pci_dev) && info->pci_dev->pcie_type == pcie_type) || bridge) ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); } else diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a7a504fc82b9..cd06c8478267 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -16,10 +16,47 @@ #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ #define CARDBUS_RESERVE_BUSNR 3 +struct resource busn_resource = { + .name = "PCI busn", + .start = 0, + .end = 255, + .flags = IORESOURCE_BUS, +}; + /* Ugh. Need to stop exporting this to modules. */ LIST_HEAD(pci_root_buses); EXPORT_SYMBOL(pci_root_buses); +static LIST_HEAD(pci_domain_busn_res_list); + +struct pci_domain_busn_res { + struct list_head list; + struct resource res; + int domain_nr; +}; + +static struct resource *get_pci_domain_busn_res(int domain_nr) +{ + struct pci_domain_busn_res *r; + + list_for_each_entry(r, &pci_domain_busn_res_list, list) + if (r->domain_nr == domain_nr) + return &r->res; + + r = kzalloc(sizeof(*r), GFP_KERNEL); + if (!r) + return NULL; + + r->domain_nr = domain_nr; + r->res.start = 0; + r->res.end = 0xff; + r->res.flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED; + + list_add_tail(&r->list, &pci_domain_busn_res_list); + + return &r->res; +} + static int find_anything(struct device *dev, void *data) { return 1; @@ -383,8 +420,8 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */ return; - dev_info(&dev->dev, "PCI bridge to [bus %02x-%02x]%s\n", - child->secondary, child->subordinate, + dev_info(&dev->dev, "PCI bridge to %pR%s\n", + &child->busn_res, dev->transparent ? " (subtractive decode)" : ""); pci_bus_remove_resources(child); @@ -601,9 +638,9 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, * Set up the primary, secondary and subordinate * bus numbers. */ - child->number = child->secondary = busnr; - child->primary = parent->secondary; - child->subordinate = 0xff; + child->number = child->busn_res.start = busnr; + child->primary = parent->busn_res.start; + child->busn_res.end = 0xff; if (!bridge) return child; @@ -645,8 +682,8 @@ static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max) if (!pcibios_assign_all_busses()) return; - while (parent->parent && parent->subordinate < max) { - parent->subordinate = max; + while (parent->parent && parent->busn_res.end < max) { + parent->busn_res.end = max; pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, max); parent = parent->parent; } @@ -720,15 +757,15 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, if (!child) goto out; child->primary = primary; - child->subordinate = subordinate; + pci_bus_insert_busn_res(child, secondary, subordinate); child->bridge_ctl = bctl; } cmax = pci_scan_child_bus(child); if (cmax > max) max = cmax; - if (child->subordinate > max) - max = child->subordinate; + if (child->busn_res.end > max) + max = child->busn_res.end; } else { /* * We need to assign a number to this bus which we always @@ -758,11 +795,12 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, child = pci_add_new_bus(bus, dev, ++max); if (!child) goto out; + pci_bus_insert_busn_res(child, max, 0xff); } buses = (buses & 0xff000000) | ((unsigned int)(child->primary) << 0) - | ((unsigned int)(child->secondary) << 8) - | ((unsigned int)(child->subordinate) << 16); + | ((unsigned int)(child->busn_res.start) << 8) + | ((unsigned int)(child->busn_res.end) << 16); /* * yenta.c forces a secondary latency timer of 176. @@ -807,8 +845,8 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, break; while (parent->parent) { if ((!pcibios_assign_all_busses()) && - (parent->subordinate > max) && - (parent->subordinate <= max+i)) { + (parent->busn_res.end > max) && + (parent->busn_res.end <= max+i)) { j = 1; } parent = parent->parent; @@ -829,7 +867,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, /* * Set the subordinate bus number to its real value. */ - child->subordinate = max; + pci_bus_update_busn_res_end(child, max); pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max); } @@ -839,19 +877,19 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, /* Has only triggered on CardBus, fixup is in yenta_socket */ while (bus->parent) { - if ((child->subordinate > bus->subordinate) || - (child->number > bus->subordinate) || + if ((child->busn_res.end > bus->busn_res.end) || + (child->number > bus->busn_res.end) || (child->number < bus->number) || - (child->subordinate < bus->number)) { - dev_info(&child->dev, "[bus %02x-%02x] %s " - "hidden behind%s bridge %s [bus %02x-%02x]\n", - child->number, child->subordinate, - (bus->number > child->subordinate && - bus->subordinate < child->number) ? + (child->busn_res.end < bus->number)) { + dev_info(&child->dev, "%pR %s " + "hidden behind%s bridge %s %pR\n", + &child->busn_res, + (bus->number > child->busn_res.end && + bus->busn_res.end < child->number) ? "wholly" : "partially", bus->self->transparent ? " transparent" : "", dev_name(&bus->dev), - bus->number, bus->subordinate); + &bus->busn_res); } bus = bus->parent; } @@ -1550,7 +1588,7 @@ EXPORT_SYMBOL_GPL(pcie_bus_configure_settings); unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus) { - unsigned int devfn, pass, max = bus->secondary; + unsigned int devfn, pass, max = bus->busn_res.start; struct pci_dev *dev; dev_dbg(&bus->dev, "scanning bus\n"); @@ -1644,7 +1682,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, /* Create legacy_io and legacy_mem files for this bus */ pci_create_legacy_files(b); - b->number = b->secondary = bus; + b->number = b->busn_res.start = bus; if (parent) dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev)); @@ -1656,7 +1694,10 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, list_move_tail(&window->list, &bridge->windows); res = window->res; offset = window->offset; - pci_bus_add_resource(b, res, 0); + if (res->flags & IORESOURCE_BUS) + pci_bus_insert_busn_res(b, bus, res->end); + else + pci_bus_add_resource(b, res, 0); if (offset) { if (resource_type(res) == IORESOURCE_IO) fmt = " (bus address [%#06llx-%#06llx])"; @@ -1686,16 +1727,104 @@ err_out: return NULL; } +int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max) +{ + struct resource *res = &b->busn_res; + struct resource *parent_res, *conflict; + + res->start = bus; + res->end = bus_max; + res->flags = IORESOURCE_BUS; + + if (!pci_is_root_bus(b)) + parent_res = &b->parent->busn_res; + else { + parent_res = get_pci_domain_busn_res(pci_domain_nr(b)); + res->flags |= IORESOURCE_PCI_FIXED; + } + + conflict = insert_resource_conflict(parent_res, res); + + if (conflict) + dev_printk(KERN_DEBUG, &b->dev, + "busn_res: can not insert %pR under %s%pR (conflicts with %s %pR)\n", + res, pci_is_root_bus(b) ? "domain " : "", + parent_res, conflict->name, conflict); + else + dev_printk(KERN_DEBUG, &b->dev, + "busn_res: %pR is inserted under %s%pR\n", + res, pci_is_root_bus(b) ? "domain " : "", + parent_res); + + return conflict == NULL; +} + +int pci_bus_update_busn_res_end(struct pci_bus *b, int bus_max) +{ + struct resource *res = &b->busn_res; + struct resource old_res = *res; + resource_size_t size; + int ret; + + if (res->start > bus_max) + return -EINVAL; + + size = bus_max - res->start + 1; + ret = adjust_resource(res, res->start, size); + dev_printk(KERN_DEBUG, &b->dev, + "busn_res: %pR end %s updated to %02x\n", + &old_res, ret ? "can not be" : "is", bus_max); + + if (!ret && !res->parent) + pci_bus_insert_busn_res(b, res->start, res->end); + + return ret; +} + +void pci_bus_release_busn_res(struct pci_bus *b) +{ + struct resource *res = &b->busn_res; + int ret; + + if (!res->flags || !res->parent) + return; + + ret = release_resource(res); + dev_printk(KERN_DEBUG, &b->dev, + "busn_res: %pR %s released\n", + res, ret ? "can not be" : "is"); +} + struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata, struct list_head *resources) { + struct pci_host_bridge_window *window; + bool found = false; struct pci_bus *b; + int max; + + list_for_each_entry(window, resources, list) + if (window->res->flags & IORESOURCE_BUS) { + found = true; + break; + } b = pci_create_root_bus(parent, bus, ops, sysdata, resources); if (!b) return NULL; - b->subordinate = pci_scan_child_bus(b); + if (!found) { + dev_info(&b->dev, + "No busn resource found for root bus, will use [bus %02x-ff]\n", + bus); + pci_bus_insert_busn_res(b, bus, 255); + } + + max = pci_scan_child_bus(b); + + if (!found) + pci_bus_update_busn_res_end(b, max); + pci_bus_add_devices(b); return b; } @@ -1710,9 +1839,10 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, pci_add_resource(&resources, &ioport_resource); pci_add_resource(&resources, &iomem_resource); + pci_add_resource(&resources, &busn_resource); b = pci_create_root_bus(parent, bus, ops, sysdata, &resources); if (b) - b->subordinate = pci_scan_child_bus(b); + pci_scan_child_bus(b); else pci_free_resource_list(&resources); return b; @@ -1727,9 +1857,10 @@ struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops, pci_add_resource(&resources, &ioport_resource); pci_add_resource(&resources, &iomem_resource); + pci_add_resource(&resources, &busn_resource); b = pci_create_root_bus(NULL, bus, ops, sysdata, &resources); if (b) { - b->subordinate = pci_scan_child_bus(b); + pci_scan_child_bus(b); pci_bus_add_devices(b); } else { pci_free_resource_list(&resources); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 2a7521677541..a2d9d330a01e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -253,7 +253,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx) * workaround applied too * [Info kindly provided by ALi] */ -static void __init quirk_alimagik(struct pci_dev *dev) +static void __devinit quirk_alimagik(struct pci_dev *dev) { if ((pci_pci_problems&PCIPCI_ALIMAGIK)==0) { dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); @@ -789,7 +789,7 @@ static void __devinit quirk_amd_ioapic(struct pci_dev *dev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic); -static void __init quirk_ioapic_rmw(struct pci_dev *dev) +static void __devinit quirk_ioapic_rmw(struct pci_dev *dev) { if (dev->devfn == 0 && dev->bus->number == 0) sis_apic_bug = 1; @@ -801,7 +801,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw); * Some settings of MMRBC can lead to data corruption so block changes. * See AMD 8131 HyperTransport PCI-X Tunnel Revision Guide */ -static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev) +static void __devinit quirk_amd_8131_mmrbc(struct pci_dev *dev) { if (dev->subordinate && dev->revision <= 0x12) { dev_info(&dev->dev, "AMD8131 rev %x detected; " @@ -1082,7 +1082,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB /* * Intel 82801CAM ICH3-M datasheet says IDE modes must be the same */ -static void __init quirk_ide_samemode(struct pci_dev *pdev) +static void __devinit quirk_ide_samemode(struct pci_dev *pdev) { u8 prog; @@ -1121,7 +1121,7 @@ DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_VIA, PCI_ANY_ID, /* This was originally an Alpha specific thing, but it really fits here. * The i82375 PCI/EISA bridge appears as non-classified. Fix that. */ -static void __init quirk_eisa_bridge(struct pci_dev *dev) +static void __devinit quirk_eisa_bridge(struct pci_dev *dev) { dev->class = PCI_CLASS_BRIDGE_EISA << 8; } @@ -1155,7 +1155,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_e */ static int asus_hides_smbus; -static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) +static void __devinit asus_hides_smbus_hostbridge(struct pci_dev *dev) { if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK)) { if (dev->device == PCI_DEVICE_ID_INTEL_82845_HB) @@ -1538,7 +1538,7 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB3 #endif #ifdef CONFIG_X86_IO_APIC -static void __init quirk_alder_ioapic(struct pci_dev *pdev) +static void __devinit quirk_alder_ioapic(struct pci_dev *pdev) { int i; @@ -1777,7 +1777,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS, qui * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes. * Re-allocate the region if needed... */ -static void __init quirk_tc86c001_ide(struct pci_dev *dev) +static void __devinit quirk_tc86c001_ide(struct pci_dev *dev) { struct resource *r = &dev->resource[0]; @@ -2169,7 +2169,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8624, quirk_tile_plx_gen1); * aware of it. Instead of setting the flag on all busses in the * machine, simply disable MSI globally. */ -static void __init quirk_disable_all_msi(struct pci_dev *dev) +static void __devinit quirk_disable_all_msi(struct pci_dev *dev) { pci_no_msi(); dev_warn(&dev->dev, "MSI quirk detected; MSI disabled\n"); @@ -2929,6 +2929,20 @@ static void __devinit disable_igfx_irq(struct pci_dev *dev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); +/* + * Some devices may pass our check in pci_intx_mask_supported if + * PCI_COMMAND_INTX_DISABLE works though they actually do not properly + * support this feature. + */ +static void __devinit quirk_broken_intx_masking(struct pci_dev *dev) +{ + dev->broken_intx_masking = 1; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CHELSIO, 0x0030, + quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_HEADER(0x1814, 0x0601, /* Ralink RT2800 802.11n PCI */ + quirk_broken_intx_masking); + static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end) { @@ -3179,3 +3193,87 @@ int pci_dev_specific_reset(struct pci_dev *dev, int probe) return -ENOTTY; } + +static struct pci_dev *pci_func_0_dma_source(struct pci_dev *dev) +{ + if (!PCI_FUNC(dev->devfn)) + return pci_dev_get(dev); + + return pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); +} + +static const struct pci_dev_dma_source { + u16 vendor; + u16 device; + struct pci_dev *(*dma_source)(struct pci_dev *dev); +} pci_dev_dma_source[] = { + /* + * https://bugzilla.redhat.com/show_bug.cgi?id=605888 + * + * Some Ricoh devices use the function 0 source ID for DMA on + * other functions of a multifunction device. The DMA devices + * is therefore function 0, which will have implications of the + * iommu grouping of these devices. + */ + { PCI_VENDOR_ID_RICOH, 0xe822, pci_func_0_dma_source }, + { PCI_VENDOR_ID_RICOH, 0xe230, pci_func_0_dma_source }, + { PCI_VENDOR_ID_RICOH, 0xe832, pci_func_0_dma_source }, + { PCI_VENDOR_ID_RICOH, 0xe476, pci_func_0_dma_source }, + { 0 } +}; + +/* + * IOMMUs with isolation capabilities need to be programmed with the + * correct source ID of a device. In most cases, the source ID matches + * the device doing the DMA, but sometimes hardware is broken and will + * tag the DMA as being sourced from a different device. This function + * allows that translation. Note that the reference count of the + * returned device is incremented on all paths. + */ +struct pci_dev *pci_get_dma_source(struct pci_dev *dev) +{ + const struct pci_dev_dma_source *i; + + for (i = pci_dev_dma_source; i->dma_source; i++) { + if ((i->vendor == dev->vendor || + i->vendor == (u16)PCI_ANY_ID) && + (i->device == dev->device || + i->device == (u16)PCI_ANY_ID)) + return i->dma_source(dev); + } + + return pci_dev_get(dev); +} + +static const struct pci_dev_acs_enabled { + u16 vendor; + u16 device; + int (*acs_enabled)(struct pci_dev *dev, u16 acs_flags); +} pci_dev_acs_enabled[] = { + { 0 } +}; + +int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags) +{ + const struct pci_dev_acs_enabled *i; + int ret; + + /* + * Allow devices that do not expose standard PCIe ACS capabilities + * or control to indicate their support here. Multi-function express + * devices which do not allow internal peer-to-peer between functions, + * but do not implement PCIe ACS may wish to return true here. + */ + for (i = pci_dev_acs_enabled; i->acs_enabled; i++) { + if ((i->vendor == dev->vendor || + i->vendor == (u16)PCI_ANY_ID) && + (i->device == dev->device || + i->device == (u16)PCI_ANY_ID)) { + ret = i->acs_enabled(dev, acs_flags); + if (ret >= 0) + return ret; + } + } + + return -ENOTTY; +} diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index fd77e2bde2e8..04a4861b4749 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -68,6 +68,7 @@ void pci_remove_bus(struct pci_bus *pci_bus) down_write(&pci_bus_sem); list_del(&pci_bus->node); + pci_bus_release_busn_res(pci_bus); up_write(&pci_bus_sem); if (!pci_bus->is_added) return; diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 9d75dc8ca602..993d4a0a2469 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -15,6 +15,8 @@ #include "pci.h" DECLARE_RWSEM(pci_bus_sem); +EXPORT_SYMBOL_GPL(pci_bus_sem); + /* * find the upstream PCIe-to-PCI bridge of a PCI device * if the device is PCIE, return NULL diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 9165d25cc792..561e41cf102d 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -404,8 +404,8 @@ void pci_setup_cardbus(struct pci_bus *bus) struct resource *res; struct pci_bus_region region; - dev_info(&bridge->dev, "CardBus bridge to [bus %02x-%02x]\n", - bus->secondary, bus->subordinate); + dev_info(&bridge->dev, "CardBus bridge to %pR\n", + &bus->busn_res); res = bus->resource[0]; pcibios_resource_to_bus(bridge, ®ion, res); @@ -553,8 +553,8 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type) { struct pci_dev *bridge = bus->self; - dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n", - bus->secondary, bus->subordinate); + dev_info(&bridge->dev, "PCI bridge to %pR\n", + &bus->busn_res); if (type & IORESOURCE_IO) pci_setup_bridge_io(bus); @@ -745,8 +745,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, if (!size0 && !size1) { if (b_res->start || b_res->end) dev_info(&bus->self->dev, "disabling bridge window " - "%pR to [bus %02x-%02x] (unused)\n", b_res, - bus->secondary, bus->subordinate); + "%pR to %pR (unused)\n", b_res, + &bus->busn_res); b_res->flags = 0; return; } @@ -757,8 +757,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, if (size1 > size0 && realloc_head) { add_to_list(realloc_head, bus->self, b_res, size1-size0, 4096); dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window " - "%pR to [bus %02x-%02x] add_size %lx\n", b_res, - bus->secondary, bus->subordinate, size1-size0); + "%pR to %pR add_size %lx\n", b_res, + &bus->busn_res, size1-size0); } } @@ -863,8 +863,8 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, if (!size0 && !size1) { if (b_res->start || b_res->end) dev_info(&bus->self->dev, "disabling bridge window " - "%pR to [bus %02x-%02x] (unused)\n", b_res, - bus->secondary, bus->subordinate); + "%pR to %pR (unused)\n", b_res, + &bus->busn_res); b_res->flags = 0; return 1; } @@ -874,8 +874,8 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, if (size1 > size0 && realloc_head) { add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align); dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window " - "%pR to [bus %02x-%02x] add_size %llx\n", b_res, - bus->secondary, bus->subordinate, (unsigned long long)size1-size0); + "%pR to %pR add_size %llx\n", b_res, + &bus->busn_res, (unsigned long long)size1-size0); } return 1; } |