diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2020-12-15 15:11:06 -0600 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2020-12-15 15:11:06 -0600 |
commit | e8722508dd78609b453b960d0b8163749d1f78b8 (patch) | |
tree | a52de7312d11a7ad41a04e00084b45a9557fa204 /drivers/pci | |
parent | 1559c4b588ecd9f230b7b64d871a850e185412e8 (diff) | |
parent | aa0b1574fd36f6929f0a3094342a08622c80b4d1 (diff) | |
download | lwn-e8722508dd78609b453b960d0b8163749d1f78b8.tar.gz lwn-e8722508dd78609b453b960d0b8163749d1f78b8.zip |
Merge branch 'pci/enumeration'
- Decode PCIe 64 GT/s link speed (Gustavo Pimentel)
- De-duplicate Device IDs in the driver dynamic IDs list (Zhenzhong Duan)
- Return u8 from pci_find_capability() and similar (Puranjay Mohan)
- Return u16 from pci_find_ext_capability() and similar (Bjorn Helgaas)
- Include both device and resource name in config space resources
(Alexander Lobakin)
- Fix ACPI companion lookup for device 0 on the root bus (Rafael J.
Wysocki)
* pci/enumeration:
PCI/ACPI: Fix companion lookup for device 0 on the root bus
PCI: Keep both device and resource name for config space remaps
PCI: Return u16 from pci_find_ext_capability() and similar
PCI: Return u8 from pci_find_capability() and similar
PCI: Avoid duplicate IDs in driver dynamic IDs list
PCI: Move pci_match_device() ahead of new_id_store()
PCI: Decode PCIe 64 GT/s link speed
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pci-acpi.c | 22 | ||||
-rw-r--r-- | drivers/pci/pci-driver.c | 147 | ||||
-rw-r--r-- | drivers/pci/pci.c | 57 | ||||
-rw-r--r-- | drivers/pci/pci.h | 6 | ||||
-rw-r--r-- | drivers/pci/probe.c | 3 |
5 files changed, 133 insertions, 102 deletions
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index bf03648c2072..4937de8250ca 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -1162,14 +1162,34 @@ void acpi_pci_remove_bus(struct pci_bus *bus) static struct acpi_device *acpi_pci_find_companion(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); + struct acpi_device *adev; bool check_children; u64 addr; check_children = pci_is_bridge(pci_dev); /* Please ref to ACPI spec for the syntax of _ADR */ addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); - return acpi_find_child_device(ACPI_COMPANION(dev->parent), addr, + adev = acpi_find_child_device(ACPI_COMPANION(dev->parent), addr, check_children); + + /* + * There may be ACPI device objects in the ACPI namespace that are + * children of the device object representing the host bridge, but don't + * represent PCI devices. Both _HID and _ADR may be present for them, + * even though that is against the specification (for example, see + * Section 6.1 of ACPI 6.3), but in many cases the _ADR returns 0 which + * appears to indicate that they should not be taken into consideration + * as potential companions of PCI devices on the root bus. + * + * To catch this special case, disregard the returned device object if + * it has a valid _HID, addr is 0 and the PCI device at hand is on the + * root bus. + */ + if (adev && adev->pnp.type.platform_id && !addr && + pci_is_root_bus(pci_dev->bus)) + return NULL; + + return adev; } /** diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 8b587fc97f7b..60b452ae6631 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -90,6 +90,79 @@ static void pci_free_dynids(struct pci_driver *drv) } /** + * pci_match_id - See if a PCI device matches a given pci_id table + * @ids: array of PCI device ID structures to search in + * @dev: the PCI device structure to match against. + * + * Used by a driver to check whether a PCI device is in its list of + * supported devices. Returns the matching pci_device_id structure or + * %NULL if there is no match. + * + * Deprecated; don't use this as it will not catch any dynamic IDs + * that a driver might want to check for. + */ +const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, + struct pci_dev *dev) +{ + if (ids) { + while (ids->vendor || ids->subvendor || ids->class_mask) { + if (pci_match_one_device(ids, dev)) + return ids; + ids++; + } + } + return NULL; +} +EXPORT_SYMBOL(pci_match_id); + +static const struct pci_device_id pci_device_id_any = { + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, +}; + +/** + * pci_match_device - See if a device matches a driver's list of IDs + * @drv: the PCI driver to match against + * @dev: the PCI device structure to match against + * + * Used by a driver to check whether a PCI device is in its list of + * supported devices or in the dynids list, which may have been augmented + * via the sysfs "new_id" file. Returns the matching pci_device_id + * structure or %NULL if there is no match. + */ +static const struct pci_device_id *pci_match_device(struct pci_driver *drv, + struct pci_dev *dev) +{ + struct pci_dynid *dynid; + const struct pci_device_id *found_id = NULL; + + /* When driver_override is set, only bind to the matching driver */ + if (dev->driver_override && strcmp(dev->driver_override, drv->name)) + return NULL; + + /* Look at the dynamic ids first, before the static ones */ + spin_lock(&drv->dynids.lock); + list_for_each_entry(dynid, &drv->dynids.list, node) { + if (pci_match_one_device(&dynid->id, dev)) { + found_id = &dynid->id; + break; + } + } + spin_unlock(&drv->dynids.lock); + + if (!found_id) + found_id = pci_match_id(drv->id_table, dev); + + /* driver_override will always match, send a dummy id */ + if (!found_id && dev->driver_override) + found_id = &pci_device_id_any; + + return found_id; +} + +/** * store_new_id - sysfs frontend to pci_add_dynid() * @driver: target device driver * @buf: buffer for scanning device ID data @@ -125,7 +198,7 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf, pdev->subsystem_device = subdevice; pdev->class = class; - if (pci_match_id(pdrv->id_table, pdev)) + if (pci_match_device(pdrv, pdev)) retval = -EEXIST; kfree(pdev); @@ -208,78 +281,6 @@ static struct attribute *pci_drv_attrs[] = { }; ATTRIBUTE_GROUPS(pci_drv); -/** - * pci_match_id - See if a pci device matches a given pci_id table - * @ids: array of PCI device id structures to search in - * @dev: the PCI device structure to match against. - * - * Used by a driver to check whether a PCI device present in the - * system is in its list of supported devices. Returns the matching - * pci_device_id structure or %NULL if there is no match. - * - * Deprecated, don't use this as it will not catch any dynamic ids - * that a driver might want to check for. - */ -const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, - struct pci_dev *dev) -{ - if (ids) { - while (ids->vendor || ids->subvendor || ids->class_mask) { - if (pci_match_one_device(ids, dev)) - return ids; - ids++; - } - } - return NULL; -} -EXPORT_SYMBOL(pci_match_id); - -static const struct pci_device_id pci_device_id_any = { - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, -}; - -/** - * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure - * @drv: the PCI driver to match against - * @dev: the PCI device structure to match against - * - * Used by a driver to check whether a PCI device present in the - * system is in its list of supported devices. Returns the matching - * pci_device_id structure or %NULL if there is no match. - */ -static const struct pci_device_id *pci_match_device(struct pci_driver *drv, - struct pci_dev *dev) -{ - struct pci_dynid *dynid; - const struct pci_device_id *found_id = NULL; - - /* When driver_override is set, only bind to the matching driver */ - if (dev->driver_override && strcmp(dev->driver_override, drv->name)) - return NULL; - - /* Look at the dynamic ids first, before the static ones */ - spin_lock(&drv->dynids.lock); - list_for_each_entry(dynid, &drv->dynids.list, node) { - if (pci_match_one_device(&dynid->id, dev)) { - found_id = &dynid->id; - break; - } - } - spin_unlock(&drv->dynids.lock); - - if (!found_id) - found_id = pci_match_id(drv->id_table, dev); - - /* driver_override will always match, send a dummy id */ - if (!found_id && dev->driver_override) - found_id = &pci_device_id_any; - - return found_id; -} - struct drv_dev_and_id { struct pci_driver *drv; struct pci_dev *dev; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index eb52c28c3a1a..d4ccfd9e6db9 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -399,8 +399,8 @@ found: return 1; } -static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn, - u8 pos, int cap, int *ttl) +static u8 __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn, + u8 pos, int cap, int *ttl) { u8 id; u16 ent; @@ -423,22 +423,22 @@ static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn, return 0; } -static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, - u8 pos, int cap) +static u8 __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, + u8 pos, int cap) { int ttl = PCI_FIND_CAP_TTL; return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl); } -int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap) +u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap) { return __pci_find_next_cap(dev->bus, dev->devfn, pos + PCI_CAP_LIST_NEXT, cap); } EXPORT_SYMBOL_GPL(pci_find_next_capability); -static int __pci_bus_find_cap_start(struct pci_bus *bus, +static u8 __pci_bus_find_cap_start(struct pci_bus *bus, unsigned int devfn, u8 hdr_type) { u16 status; @@ -477,9 +477,9 @@ static int __pci_bus_find_cap_start(struct pci_bus *bus, * %PCI_CAP_ID_PCIX PCI-X * %PCI_CAP_ID_EXP PCI Express */ -int pci_find_capability(struct pci_dev *dev, int cap) +u8 pci_find_capability(struct pci_dev *dev, int cap) { - int pos; + u8 pos; pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type); if (pos) @@ -502,10 +502,9 @@ EXPORT_SYMBOL(pci_find_capability); * device's PCI configuration space or 0 in case the device does not * support it. */ -int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap) +u8 pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap) { - int pos; - u8 hdr_type; + u8 hdr_type, pos; pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type); @@ -528,11 +527,11 @@ EXPORT_SYMBOL(pci_bus_find_capability); * not support it. Some capabilities can occur several times, e.g., the * vendor-specific capability, and this provides a way to find them all. */ -int pci_find_next_ext_capability(struct pci_dev *dev, int start, int cap) +u16 pci_find_next_ext_capability(struct pci_dev *dev, u16 start, int cap) { u32 header; int ttl; - int pos = PCI_CFG_SPACE_SIZE; + u16 pos = PCI_CFG_SPACE_SIZE; /* minimum 8 bytes per capability */ ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; @@ -583,7 +582,7 @@ EXPORT_SYMBOL_GPL(pci_find_next_ext_capability); * %PCI_EXT_CAP_ID_DSN Device Serial Number * %PCI_EXT_CAP_ID_PWR Power Budgeting */ -int pci_find_ext_capability(struct pci_dev *dev, int cap) +u16 pci_find_ext_capability(struct pci_dev *dev, int cap) { return pci_find_next_ext_capability(dev, 0, cap); } @@ -623,7 +622,7 @@ u64 pci_get_dsn(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_get_dsn); -static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap) +static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap) { int rc, ttl = PCI_FIND_CAP_TTL; u8 cap, mask; @@ -650,11 +649,12 @@ static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap) return 0; } + /** - * pci_find_next_ht_capability - query a device's Hypertransport capabilities + * pci_find_next_ht_capability - query a device's HyperTransport capabilities * @dev: PCI device to query * @pos: Position from which to continue searching - * @ht_cap: Hypertransport capability code + * @ht_cap: HyperTransport capability code * * To be used in conjunction with pci_find_ht_capability() to search for * all capabilities matching @ht_cap. @pos should always be a value returned @@ -663,26 +663,26 @@ static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap) * NB. To be 100% safe against broken PCI devices, the caller should take * steps to avoid an infinite loop. */ -int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap) +u8 pci_find_next_ht_capability(struct pci_dev *dev, u8 pos, int ht_cap) { return __pci_find_next_ht_cap(dev, pos + PCI_CAP_LIST_NEXT, ht_cap); } EXPORT_SYMBOL_GPL(pci_find_next_ht_capability); /** - * pci_find_ht_capability - query a device's Hypertransport capabilities + * pci_find_ht_capability - query a device's HyperTransport capabilities * @dev: PCI device to query - * @ht_cap: Hypertransport capability code + * @ht_cap: HyperTransport capability code * - * Tell if a device supports a given Hypertransport capability. + * Tell if a device supports a given HyperTransport capability. * Returns an address within the device's PCI configuration space * or 0 in case the device does not support the request capability. * The address points to the PCI capability, of type PCI_CAP_ID_HT, - * which has a Hypertransport capability matching @ht_cap. + * which has a HyperTransport capability matching @ht_cap. */ -int pci_find_ht_capability(struct pci_dev *dev, int ht_cap) +u8 pci_find_ht_capability(struct pci_dev *dev, int ht_cap) { - int pos; + u8 pos; pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type); if (pos) @@ -4195,7 +4195,14 @@ void __iomem *devm_pci_remap_cfg_resource(struct device *dev, } size = resource_size(res); - name = res->name ?: dev_name(dev); + + if (res->name) + name = devm_kasprintf(dev, GFP_KERNEL, "%s %s", dev_name(dev), + res->name); + else + name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL); + if (!name) + return IOMEM_ERR_PTR(-ENOMEM); if (!devm_request_mem_region(dev, res->start, size, name)) { dev_err(dev, "can't request region for resource %pR\n", res); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 60308cd1cffc..8d57d3845784 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -294,7 +294,8 @@ void pci_bus_put(struct pci_bus *bus); /* PCIe link information from Link Capabilities 2 */ #define PCIE_LNKCAP2_SLS2SPEED(lnkcap2) \ - ((lnkcap2) & PCI_EXP_LNKCAP2_SLS_32_0GB ? PCIE_SPEED_32_0GT : \ + ((lnkcap2) & PCI_EXP_LNKCAP2_SLS_64_0GB ? PCIE_SPEED_64_0GT : \ + (lnkcap2) & PCI_EXP_LNKCAP2_SLS_32_0GB ? PCIE_SPEED_32_0GT : \ (lnkcap2) & PCI_EXP_LNKCAP2_SLS_16_0GB ? PCIE_SPEED_16_0GT : \ (lnkcap2) & PCI_EXP_LNKCAP2_SLS_8_0GB ? PCIE_SPEED_8_0GT : \ (lnkcap2) & PCI_EXP_LNKCAP2_SLS_5_0GB ? PCIE_SPEED_5_0GT : \ @@ -303,7 +304,8 @@ void pci_bus_put(struct pci_bus *bus); /* PCIe speed to Mb/s reduced by encoding overhead */ #define PCIE_SPEED2MBS_ENC(speed) \ - ((speed) == PCIE_SPEED_32_0GT ? 32000*128/130 : \ + ((speed) == PCIE_SPEED_64_0GT ? 64000*128/130 : \ + (speed) == PCIE_SPEED_32_0GT ? 32000*128/130 : \ (speed) == PCIE_SPEED_16_0GT ? 16000*128/130 : \ (speed) == PCIE_SPEED_8_0GT ? 8000*128/130 : \ (speed) == PCIE_SPEED_5_0GT ? 5000*8/10 : \ diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 4289030b0fff..fe2e00f5fc4c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -677,7 +677,7 @@ const unsigned char pcie_link_speed[] = { PCIE_SPEED_8_0GT, /* 3 */ PCIE_SPEED_16_0GT, /* 4 */ PCIE_SPEED_32_0GT, /* 5 */ - PCI_SPEED_UNKNOWN, /* 6 */ + PCIE_SPEED_64_0GT, /* 6 */ PCI_SPEED_UNKNOWN, /* 7 */ PCI_SPEED_UNKNOWN, /* 8 */ PCI_SPEED_UNKNOWN, /* 9 */ @@ -719,6 +719,7 @@ const char *pci_speed_string(enum pci_bus_speed speed) "8.0 GT/s PCIe", /* 0x16 */ "16.0 GT/s PCIe", /* 0x17 */ "32.0 GT/s PCIe", /* 0x18 */ + "64.0 GT/s PCIe", /* 0x19 */ }; if (speed < ARRAY_SIZE(speed_strings)) |