From 341917490d7d68d2f7267a265b8820fc3f8ead1b Mon Sep 17 00:00:00 2001 From: Gustavo Pimentel Date: Wed, 18 Nov 2020 23:49:20 +0100 Subject: [PATCH 1/7] PCI: Decode PCIe 64 GT/s link speed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PCIe r6.0, sec 7.5.3.18, defines a new 64.0 GT/s bit in the Supported Link Speeds Vector of Link Capabilities 2. This patch does not affect the speed of the link, which should be negotiated automatically by the hardware; it only adds decoding when showing the speed to the user. Decode this new speed. Previously, reading the speed of a link operating at this speed showed "Unknown speed" instead of "64.0 GT/s". Link: https://lore.kernel.org/r/aaaab33fe18975e123a84aebce2adb85f44e2bbe.1605739760.git.gustavo.pimentel@synopsys.com Signed-off-by: Gustavo Pimentel Signed-off-by: Bjorn Helgaas Reviewed-by: Krzysztof WilczyƄski --- drivers/pci/pci.h | 6 ++++-- drivers/pci/probe.c | 3 ++- include/linux/pci.h | 1 + include/uapi/linux/pci_regs.h | 4 ++++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index f86cae9aa1f4..81bf905b545c 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)) diff --git a/include/linux/pci.h b/include/linux/pci.h index 22207a79762c..e007bc3e8b6e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -281,6 +281,7 @@ enum pci_bus_speed { PCIE_SPEED_8_0GT = 0x16, PCIE_SPEED_16_0GT = 0x17, PCIE_SPEED_32_0GT = 0x18, + PCIE_SPEED_64_0GT = 0x19, PCI_SPEED_UNKNOWN = 0xff, }; diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index a95d55f9f257..fe9d5dba2ba1 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -531,6 +531,7 @@ #define PCI_EXP_LNKCAP_SLS_8_0GB 0x00000003 /* LNKCAP2 SLS Vector bit 2 */ #define PCI_EXP_LNKCAP_SLS_16_0GB 0x00000004 /* LNKCAP2 SLS Vector bit 3 */ #define PCI_EXP_LNKCAP_SLS_32_0GB 0x00000005 /* LNKCAP2 SLS Vector bit 4 */ +#define PCI_EXP_LNKCAP_SLS_64_0GB 0x00000006 /* LNKCAP2 SLS Vector bit 5 */ #define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */ #define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */ #define PCI_EXP_LNKCAP_ASPM_L0S 0x00000400 /* ASPM L0s Support */ @@ -562,6 +563,7 @@ #define PCI_EXP_LNKSTA_CLS_8_0GB 0x0003 /* Current Link Speed 8.0GT/s */ #define PCI_EXP_LNKSTA_CLS_16_0GB 0x0004 /* Current Link Speed 16.0GT/s */ #define PCI_EXP_LNKSTA_CLS_32_0GB 0x0005 /* Current Link Speed 32.0GT/s */ +#define PCI_EXP_LNKSTA_CLS_64_0GB 0x0006 /* Current Link Speed 64.0GT/s */ #define PCI_EXP_LNKSTA_NLW 0x03f0 /* Negotiated Link Width */ #define PCI_EXP_LNKSTA_NLW_X1 0x0010 /* Current Link Width x1 */ #define PCI_EXP_LNKSTA_NLW_X2 0x0020 /* Current Link Width x2 */ @@ -670,6 +672,7 @@ #define PCI_EXP_LNKCAP2_SLS_8_0GB 0x00000008 /* Supported Speed 8GT/s */ #define PCI_EXP_LNKCAP2_SLS_16_0GB 0x00000010 /* Supported Speed 16GT/s */ #define PCI_EXP_LNKCAP2_SLS_32_0GB 0x00000020 /* Supported Speed 32GT/s */ +#define PCI_EXP_LNKCAP2_SLS_64_0GB 0x00000040 /* Supported Speed 64GT/s */ #define PCI_EXP_LNKCAP2_CROSSLINK 0x00000100 /* Crosslink supported */ #define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ #define PCI_EXP_LNKCTL2_TLS 0x000f @@ -678,6 +681,7 @@ #define PCI_EXP_LNKCTL2_TLS_8_0GT 0x0003 /* Supported Speed 8GT/s */ #define PCI_EXP_LNKCTL2_TLS_16_0GT 0x0004 /* Supported Speed 16GT/s */ #define PCI_EXP_LNKCTL2_TLS_32_0GT 0x0005 /* Supported Speed 32GT/s */ +#define PCI_EXP_LNKCTL2_TLS_64_0GT 0x0006 /* Supported Speed 64GT/s */ #define PCI_EXP_LNKCTL2_ENTER_COMP 0x0010 /* Enter Compliance */ #define PCI_EXP_LNKCTL2_TX_MARGIN 0x0380 /* Transmit Margin */ #define PCI_EXP_LNKCTL2_HASD 0x0020 /* HW Autonomous Speed Disable */ From 1f40704bb01b9fba9925006662a37373d514f26b Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Tue, 17 Nov 2020 13:44:08 +0800 Subject: [PATCH 2/7] PCI: Move pci_match_device() ahead of new_id_store() Move pci_match_device() and its dependencies (pci_match_id() and pci_device_id_any) ahead of new_id_store(). This is preparation work for calling pci_match_device() in new_id_store(). No functional changes. [bhelgaas: update function comments] Link: https://lore.kernel.org/r/20201117054409.3428-2-zhenzhong.duan@gmail.com Signed-off-by: Zhenzhong Duan Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-driver.c | 145 ++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 72 deletions(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 8b587fc97f7b..965b3d772cdf 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -89,6 +89,79 @@ static void pci_free_dynids(struct pci_driver *drv) spin_unlock(&drv->dynids.lock); } +/** + * 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 @@ -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; From 3853f9123c185eb4018f5ccd3cdda5968efb5e10 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Tue, 17 Nov 2020 13:44:09 +0800 Subject: [PATCH 3/7] PCI: Avoid duplicate IDs in driver dynamic IDs list When a device ID is written to /sys/bus/pci/drivers/.../new_id, we previously only checked the driver's static ID table for duplicates. Writing the same ID several times added it to the dynamic IDs list several times. This doesn't cause user-visible broken behavior, but remove_id_store() only removes one of the duplicate IDs, so if we add an ID several times, we would have to remove it the same number of times before it's completely gone. Fix it by calling pci_match_device(), which checks both dynamic and static IDs to avoid inserting duplicate IDs in dynamic IDs list. After fix, attempts to add an ID more than once cause an error: # echo "1af4 1041" > /sys/bus/pci/drivers/vfio-pci/new_id # echo "1af4 1041" > /sys/bus/pci/drivers/vfio-pci/new_id bash: echo: write error: File exists Link: https://lore.kernel.org/r/20201117054409.3428-3-zhenzhong.duan@gmail.com Signed-off-by: Zhenzhong Duan Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 965b3d772cdf..60b452ae6631 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -198,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); From f646c2a0a6685a8a30a150509b112c911b8feff3 Mon Sep 17 00:00:00 2001 From: Puranjay Mohan Date: Sun, 29 Nov 2020 22:16:26 +0530 Subject: [PATCH 4/7] PCI: Return u8 from pci_find_capability() and similar PCI Capabilities are linked in a list that must appear in the first 256 bytes of config space. Each capabilities list pointer is 8 bits. Change the return type of pci_find_capability() and supporting functions from int to u8 to match the specification. [bhelgaas: change other related interfaces, fix HyperTransport typos] Link: https://lore.kernel.org/r/20201129164626.12887-1-puranjay12@gmail.com Signed-off-by: Puranjay Mohan Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 42 +++++++++++++++++++++--------------------- include/linux/pci.h | 12 ++++++------ 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e578d34095e9..b3761e98377b 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); @@ -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) diff --git a/include/linux/pci.h b/include/linux/pci.h index e007bc3e8b6e..e615f8abdd79 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1064,12 +1064,13 @@ void pci_sort_breadthfirst(void); /* Generic PCI functions exported to card drivers */ -int pci_find_capability(struct pci_dev *dev, int cap); -int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap); +u8 pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap); +u8 pci_find_capability(struct pci_dev *dev, int cap); +u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap); +u8 pci_find_ht_capability(struct pci_dev *dev, int ht_cap); +u8 pci_find_next_ht_capability(struct pci_dev *dev, u8 pos, int ht_cap); int pci_find_ext_capability(struct pci_dev *dev, int cap); int pci_find_next_ext_capability(struct pci_dev *dev, int pos, int cap); -int pci_find_ht_capability(struct pci_dev *dev, int ht_cap); -int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap); struct pci_bus *pci_find_next_bus(const struct pci_bus *from); u64 pci_get_dsn(struct pci_dev *dev); @@ -1280,7 +1281,6 @@ void set_pcie_port_type(struct pci_dev *pdev); void set_pcie_hotplug_bridge(struct pci_dev *pdev); /* Functions for PCI Hotplug drivers to use */ -int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap); unsigned int pci_rescan_bus_bridge_resize(struct pci_dev *bridge); unsigned int pci_rescan_bus(struct pci_bus *bus); void pci_lock_rescan_remove(void); @@ -1720,7 +1720,7 @@ static inline int __pci_register_driver(struct pci_driver *drv, static inline int pci_register_driver(struct pci_driver *drv) { return 0; } static inline void pci_unregister_driver(struct pci_driver *drv) { } -static inline int pci_find_capability(struct pci_dev *dev, int cap) +static inline u8 pci_find_capability(struct pci_dev *dev, int cap) { return 0; } static inline int pci_find_next_capability(struct pci_dev *dev, u8 post, int cap) From ee8b1c478a9fbce9c64151ee561c124c4dcd66be Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 4 Dec 2020 15:14:07 -0600 Subject: [PATCH 5/7] PCI: Return u16 from pci_find_ext_capability() and similar PCI Express Extended Capabilities are in config space between offsets 256 and 4K. These offsets all fit in 16 bits. Change the return type of pci_find_ext_capability() and supporting functions from int to u16 to match the specification. Many callers use "int", which is fine, but there's no need to store more than a u16. Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 6 +++--- include/linux/pci.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b3761e98377b..85cb873266d3 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -527,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; @@ -582,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); } diff --git a/include/linux/pci.h b/include/linux/pci.h index e615f8abdd79..441e5753da0c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -381,7 +381,7 @@ struct pci_dev { struct pcie_link_state *link_state; /* ASPM link state */ unsigned int ltr_path:1; /* Latency Tolerance Reporting supported from root to here */ - int l1ss; /* L1SS Capability pointer */ + u16 l1ss; /* L1SS Capability pointer */ #endif unsigned int eetlp_prefix_path:1; /* End-to-End TLP Prefix */ @@ -1069,8 +1069,8 @@ u8 pci_find_capability(struct pci_dev *dev, int cap); u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap); u8 pci_find_ht_capability(struct pci_dev *dev, int ht_cap); u8 pci_find_next_ht_capability(struct pci_dev *dev, u8 pos, int ht_cap); -int pci_find_ext_capability(struct pci_dev *dev, int cap); -int pci_find_next_ext_capability(struct pci_dev *dev, int pos, int cap); +u16 pci_find_ext_capability(struct pci_dev *dev, int cap); +u16 pci_find_next_ext_capability(struct pci_dev *dev, u16 pos, int cap); struct pci_bus *pci_find_next_bus(const struct pci_bus *from); u64 pci_get_dsn(struct pci_dev *dev); From 0af6e21eed2778e68139941389460e2a00d6ef8e Mon Sep 17 00:00:00 2001 From: Alexander Lobakin Date: Thu, 19 Nov 2020 21:26:33 +0000 Subject: [PATCH 6/7] PCI: Keep both device and resource name for config space remaps Follow the rule taken in commit 35bd8c07db2c ("devres: keep both device name and resource name in pretty name") and keep both device and resource names while requesting memory regions for PCI config space to prettify e.g. /proc/iomem output: Before (DWC Host Controller): 18b00000-18b01fff : dbi 18b10000-18b11fff : config 18b20000-18b21fff : dbi 18b30000-18b31fff : config After: 18b00000-18b01fff : 18b00000.pci dbi 18b10000-18b11fff : 18b00000.pci config 18b20000-18b21fff : 18b20000.pci dbi 18b30000-18b31fff : 18b20000.pci config Link: https://lore.kernel.org/r/WbKfdybjZ6xNIUjcC5oC8NcuLqrJfkxQAlnO80ag@cp3-web-020.plabs.ch Signed-off-by: Alexander Lobakin Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 85cb873266d3..4706e23db8eb 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4188,7 +4188,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); From aa0b1574fd36f6929f0a3094342a08622c80b4d1 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 11 Dec 2020 21:17:35 +0100 Subject: [PATCH 7/7] PCI/ACPI: Fix companion lookup for device 0 on the root bus In some cases acpi_pci_find_companion() returns an incorrect device object as the ACPI companion for device 0 on the root bus (bus 0). On the affected systems that device is the PCI interface to the host bridge and the "ACPI companion" returned for it corresponds to a non-PCI device located in the SoC (e.g. a sensor on an I2C bus). As a result of this, the ACPI device object "attached" to PCI device 00:00.0 cannot be used for enumerating the device that is really represented by it which (of course) is problematic. Address that issue by preventing acpi_pci_find_companion() from returning a device object with a valid _HID (which by the spec should not be present uder ACPI device objects corresponding to PCI devices) for PCI device 00:00.0. [bhelgaas: use pci_is_root_bus()] Link: https://lore.kernel.org/linux-acpi/1409ba0c-1580-dc09-e6fe-a0c9bcda6462@gmail.com/ Link: https://lore.kernel.org/r/4673285.9aE2nYKHPr@kreacher Reported-by: Daniel Scally Tested-by: Daniel Scally Signed-off-by: Rafael J. Wysocki Signed-off-by: Bjorn Helgaas Reviewed-by: Daniel Scally --- drivers/pci/pci-acpi.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) 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; } /**