drivers/pci/controller/cadence/pci-j721e.c | 3 ++- .../pci/controller/dwc/pcie-designware-host.c | 2 +- drivers/pci/controller/dwc/pcie-designware.c | 2 +- drivers/pci/controller/dwc/pcie-qcom-common.c | 2 +- drivers/pci/controller/dwc/pcie-qcom-ep.c | 4 ++-- drivers/pci/controller/dwc/pcie-qcom.c | 6 +++--- drivers/pci/controller/dwc/pcie-tegra194.c | 2 +- drivers/pci/controller/pcie-brcmstb.c | 5 +++-- drivers/pci/controller/pcie-mediatek-gen3.c | 2 +- drivers/pci/controller/pcie-rzg3s-host.c | 2 +- drivers/pci/of.c | 16 ++++++++-------- drivers/pci/pci.h | 2 ++ drivers/pci/probe.c | 16 ++++++++++++++++ 13 files changed, 42 insertions(+), 22 deletions(-)
Hi, This series moves the validation from the common OF function to the individual PCIe controller drivers. To protect against out-of-bounds accesses to the pcie_link_speed[] array, we first introduce a helper function pcie_get_link_speed() that safely returns the speed value (or PCI_SPEED_UNKNOWN) for a given generation number. Then all direct uses of pcie_link_speed[] as an array are converted to use the new helper, ensuring that even if an invalid generation number reaches those code paths, no out-of-bounds access occurs. For several drivers that read the "max-link-speed" property (pci-j721e, brcmstb, mediatek-gen3, rzg3s-host), we add an explicit validation step: if the value is missing, out of range, or unsupported by the hardware, a safe default is used (usually Gen2). Other drivers (mainly DesignWare glue drivers) rely on the helper to safely handle invalid values, but do not yet include fallback logic or warnings. Finally, the range check is removed from of_pci_get_max_link_speed(), so that future PCIe generations can be supported without modifying drivers/pci/of.c. --- Changes for v9: - Modify the parameter passed to pcie_get_link_speed to unsigned int. If the DT configuration specifies max-link-speed = -1, the obtained max_link_speed will be 0xff. Therefore, it will be greater than the length of the array pcie_link_speed. Thus, the condition speed <= 0 is removed. (For patch 0001. Shawn) - Modify the commit message for patch 0005. (Shawn) Changes for v8: https://patchwork.kernel.org/project/linux-pci/cover/20260312163652.113228-1-18255117159@163.com/ - Expand series from 2 to 5 patches to introduce pcie_get_link_speed() helper and split validation into per-driver changes. - Add pcie_get_link_speed() helper for safe pcie_link_speed[] array access (Bjorn) - Move max-link-speed validation from DWC core to individual drivers; add explicit fallback logic only for pci-j721e, brcmstb, mediatek-gen3, rzg3s-host. - Convert all remaining direct pcie_link_speed[] accesses to use the new helper. - Update commit messages to reflect the new design. Changes for v7: https://patchwork.kernel.org/project/linux-pci/cover/20260308142629.75392-1-18255117159@163.com/ - Add validation in dw_pcie_get_link_speed() (Bjorn) - Modify it so that two patches constitute one series. Changes for v6: https://patchwork.kernel.org/project/linux-pci/patch/20251218132036.308094-1-18255117159@163.com/ - It'd be good to return the actual errno as of_property_read_u32() can return -EINVAL, -ENODATA and -EOVERFLOW. (Mani) Changes for v5: https://patchwork.kernel.org/project/linux-pci/patch/20251218125909.305300-1-18255117159@163.com/ - Delete the check for speed. (Mani) Changes for v4: https://patchwork.kernel.org/project/linux-pci/patch/20251105134701.182795-1-18255117159@163.com/ - Add pcie_max_supported_link_speed.(Ilpo) Changes for v3: https://patchwork.kernel.org/project/linux-pci/patch/20251101164132.14145-1-18255117159@163.com/ - Modify the commit message. - Add Reviewed-by tag. Changes for v2: https://patchwork.kernel.org/project/linux-pci/cover/20250529021026.475861-1-18255117159@163.com/ - The following files have been deleted: Documentation/devicetree/bindings/pci/pci.txt Update to this file again: dtschema/schemas/pci/pci-bus-common.yaml --- Hans Zhang (5): PCI: Add pcie_get_link_speed() helper for safe array access PCI: dwc: Use pcie_get_link_speed() and validate max-link-speed PCI: j721e: Validate max-link-speed from DT PCI: controller: Validate max-link-speed PCI: of: Remove max-link-speed generation validation drivers/pci/controller/cadence/pci-j721e.c | 3 ++- .../pci/controller/dwc/pcie-designware-host.c | 2 +- drivers/pci/controller/dwc/pcie-designware.c | 2 +- drivers/pci/controller/dwc/pcie-qcom-common.c | 2 +- drivers/pci/controller/dwc/pcie-qcom-ep.c | 4 ++-- drivers/pci/controller/dwc/pcie-qcom.c | 6 +++--- drivers/pci/controller/dwc/pcie-tegra194.c | 2 +- drivers/pci/controller/pcie-brcmstb.c | 5 +++-- drivers/pci/controller/pcie-mediatek-gen3.c | 2 +- drivers/pci/controller/pcie-rzg3s-host.c | 2 +- drivers/pci/of.c | 16 ++++++++-------- drivers/pci/pci.h | 2 ++ drivers/pci/probe.c | 16 ++++++++++++++++ 13 files changed, 42 insertions(+), 22 deletions(-) base-commit: 80234b5ab240f52fa45d201e899e207b9265ef91 -- 2.34.1
On Sat, 14 Mar 2026 00:55:17 +0800, Hans Zhang wrote:
> This series moves the validation from the common OF function to the
> individual PCIe controller drivers. To protect against out-of-bounds
> accesses to the pcie_link_speed[] array, we first introduce a helper
> function pcie_get_link_speed() that safely returns the speed value
> (or PCI_SPEED_UNKNOWN) for a given generation number.
>
> Then all direct uses of pcie_link_speed[] as an array are converted to
> use the new helper, ensuring that even if an invalid generation number
> reaches those code paths, no out-of-bounds access occurs.
>
> [...]
Applied, thanks!
[1/5] PCI: Add pcie_get_link_speed() helper for safe array access
commit: df61f4732adf9de5ad1f5e71b7670710c1597d18
[2/5] PCI: dwc: Use pcie_get_link_speed() helper for safe array access
commit: d884b0e51459175f17ddc52759ea4533bb752130
[3/5] PCI: j721e: Validate max-link-speed from DT
commit: 1542ac6d83d0b5706f45e2937de7b4f7b8c4831d
[4/5] PCI: controller: Validate max-link-speed
commit: d0cc5918a1d539344190cbb19fa3ae0e7b0dca1e
[5/5] PCI: of: Remove max-link-speed generation validation
commit: 15217c7015c0e1804925693c55d721aad8987e32
Best regards,
--
Manivannan Sadhasivam <mani@kernel.org>
On Sat, Mar 14, 2026 at 12:55:17AM +0800, Hans Zhang wrote:
> Hi,
>
> This series moves the validation from the common OF function to the
> individual PCIe controller drivers. To protect against out-of-bounds
> accesses to the pcie_link_speed[] array, we first introduce a helper
> function pcie_get_link_speed() that safely returns the speed value
> (or PCI_SPEED_UNKNOWN) for a given generation number.
>
> Then all direct uses of pcie_link_speed[] as an array are converted to
> use the new helper, ensuring that even if an invalid generation number
> reaches those code paths, no out-of-bounds access occurs.
>
> For several drivers that read the "max-link-speed" property
> (pci-j721e, brcmstb, mediatek-gen3, rzg3s-host), we add an explicit
> validation step: if the value is missing, out of range, or unsupported
> by the hardware, a safe default is used (usually Gen2). Other drivers
> (mainly DesignWare glue drivers) rely on the helper to safely handle
> invalid values, but do not yet include fallback logic or warnings.
>
> Finally, the range check is removed from of_pci_get_max_link_speed(),
> so that future PCIe generations can be supported without modifying
> drivers/pci/of.c.
Thanks for this series.
We still have a couple references to pcie_link_speed[] that bypass
pcie_get_link_speed(). These are safe because PCI_EXP_LNKSTA_CLS is
0xf and pcie_link_speed[] is size 16, but I'm not sure the direct
reference is necessary.
The array itself is exported, which I suppose we needed for modular
PCI controller drivers, but we probably don't need it now that
pcie_get_link_speed() is exported?
$ git grep "\<pcie_link_speed\>"
drivers/pci/pci-sysfs.c: speed = pcie_link_speed[linkstat & PCI_EXP_LNKSTA_CLS];
drivers/pci/pci.c: return pcie_link_speed[FIELD_GET(PCI_EXP_LNKSTA_CLS, lnksta)];
drivers/pci/pci.h:extern const unsigned char pcie_link_speed[];
drivers/pci/pci.h: bus->cur_bus_speed = pcie_link_speed[linksta & PCI_EXP_LNKSTA_CLS];
drivers/pci/probe.c:const unsigned char pcie_link_speed[] = {
drivers/pci/probe.c:EXPORT_SYMBOL_GPL(pcie_link_speed);
drivers/pci/probe.c: if (speed >= ARRAY_SIZE(pcie_link_speed))
drivers/pci/probe.c: return pcie_link_speed[speed];
drivers/pci/probe.c: bus->max_bus_speed = pcie_link_speed[linkcap & PCI_EXP_LNKCAP_SLS];
On 3/28/26 00:42, Bjorn Helgaas wrote:
> On Sat, Mar 14, 2026 at 12:55:17AM +0800, Hans Zhang wrote:
>> Hi,
>>
>> This series moves the validation from the common OF function to the
>> individual PCIe controller drivers. To protect against out-of-bounds
>> accesses to the pcie_link_speed[] array, we first introduce a helper
>> function pcie_get_link_speed() that safely returns the speed value
>> (or PCI_SPEED_UNKNOWN) for a given generation number.
>>
>> Then all direct uses of pcie_link_speed[] as an array are converted to
>> use the new helper, ensuring that even if an invalid generation number
>> reaches those code paths, no out-of-bounds access occurs.
>>
>> For several drivers that read the "max-link-speed" property
>> (pci-j721e, brcmstb, mediatek-gen3, rzg3s-host), we add an explicit
>> validation step: if the value is missing, out of range, or unsupported
>> by the hardware, a safe default is used (usually Gen2). Other drivers
>> (mainly DesignWare glue drivers) rely on the helper to safely handle
>> invalid values, but do not yet include fallback logic or warnings.
>>
>> Finally, the range check is removed from of_pci_get_max_link_speed(),
>> so that future PCIe generations can be supported without modifying
>> drivers/pci/of.c.
>
> Thanks for this series.
>
> We still have a couple references to pcie_link_speed[] that bypass
> pcie_get_link_speed(). These are safe because PCI_EXP_LNKSTA_CLS is
> 0xf and pcie_link_speed[] is size 16, but I'm not sure the direct
> reference is necessary.
>
> The array itself is exported, which I suppose we needed for modular
> PCI controller drivers, but we probably don't need it now that
> pcie_get_link_speed() is exported?
>
> $ git grep "\<pcie_link_speed\>"
> drivers/pci/pci-sysfs.c: speed = pcie_link_speed[linkstat & PCI_EXP_LNKSTA_CLS];
> drivers/pci/pci.c: return pcie_link_speed[FIELD_GET(PCI_EXP_LNKSTA_CLS, lnksta)];
> drivers/pci/pci.h:extern const unsigned char pcie_link_speed[];
> drivers/pci/pci.h: bus->cur_bus_speed = pcie_link_speed[linksta & PCI_EXP_LNKSTA_CLS];
> drivers/pci/probe.c:const unsigned char pcie_link_speed[] = {
> drivers/pci/probe.c:EXPORT_SYMBOL_GPL(pcie_link_speed);
> drivers/pci/probe.c: if (speed >= ARRAY_SIZE(pcie_link_speed))
> drivers/pci/probe.c: return pcie_link_speed[speed];
> drivers/pci/probe.c: bus->max_bus_speed = pcie_link_speed[linkcap & PCI_EXP_LNKCAP_SLS];
Hi Bjorn,
Yes, I also realized that this array is directly used in other places.
So I submitted this series and I would appreciate it if you could review
it to ensure its correctness.
See also this series:
https://patchwork.kernel.org/project/linux-pci/patch/20260315160057.127639-1-18255117159@163.com/
Best regards,
Hans
© 2016 - 2026 Red Hat, Inc.