1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright(c) 2021 Intel Corporation. All rights reserved. */
3 #include <linux/device.h>
12 * Compute Express Link protocols are layered on top of PCIe. CXL core provides
13 * a set of helpers for CXL interactions which occur via PCIe.
16 struct cxl_walk_context {
18 struct cxl_port *port;
24 static int match_add_dports(struct pci_dev *pdev, void *data)
26 struct cxl_walk_context *ctx = data;
27 struct cxl_port *port = ctx->port;
28 int type = pci_pcie_type(pdev);
29 struct cxl_register_map map;
30 struct cxl_dport *dport;
34 if (pdev->bus != ctx->bus)
36 if (!pci_is_pcie(pdev))
38 if (type != ctx->type)
40 if (pci_read_config_dword(pdev, pci_pcie_cap(pdev) + PCI_EXP_LNKCAP,
44 rc = cxl_find_regblock(pdev, CXL_REGLOC_RBI_COMPONENT, &map);
46 dev_dbg(&port->dev, "failed to find component registers\n");
48 port_num = FIELD_GET(PCI_EXP_LNKCAP_PN, lnkcap);
49 dport = devm_cxl_add_dport(port, &pdev->dev, port_num,
50 cxl_regmap_to_base(pdev, &map));
52 ctx->error = PTR_ERR(dport);
53 return PTR_ERR(dport);
57 dev_dbg(&port->dev, "add dport%d: %s\n", port_num, dev_name(&pdev->dev));
63 * devm_cxl_port_enumerate_dports - enumerate downstream ports of the upstream port
64 * @port: cxl_port whose ->uport is the upstream of dports to be enumerated
66 * Returns a positive number of dports enumerated or a negative error
69 int devm_cxl_port_enumerate_dports(struct cxl_port *port)
71 struct pci_bus *bus = cxl_port_to_pci_bus(port);
72 struct cxl_walk_context ctx;
78 if (pci_is_root_bus(bus))
79 type = PCI_EXP_TYPE_ROOT_PORT;
81 type = PCI_EXP_TYPE_DOWNSTREAM;
83 ctx = (struct cxl_walk_context) {
88 pci_walk_bus(bus, match_add_dports, &ctx);
96 EXPORT_SYMBOL_NS_GPL(devm_cxl_port_enumerate_dports, CXL);