1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright(c) 2021 Intel Corporation. All rights reserved. */ 3 #include <linux/device.h> 4 #include <linux/pci.h> 5 #include <cxlpci.h> 6 #include <cxl.h> 7 #include "core.h" 8 9 /** 10 * DOC: cxl core pci 11 * 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. 14 */ 15 16 struct cxl_walk_context { 17 struct pci_bus *bus; 18 struct cxl_port *port; 19 int type; 20 int error; 21 int count; 22 }; 23 24 static int match_add_dports(struct pci_dev *pdev, void *data) 25 { 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; 31 u32 lnkcap, port_num; 32 int rc; 33 34 if (pdev->bus != ctx->bus) 35 return 0; 36 if (!pci_is_pcie(pdev)) 37 return 0; 38 if (type != ctx->type) 39 return 0; 40 if (pci_read_config_dword(pdev, pci_pcie_cap(pdev) + PCI_EXP_LNKCAP, 41 &lnkcap)) 42 return 0; 43 44 rc = cxl_find_regblock(pdev, CXL_REGLOC_RBI_COMPONENT, &map); 45 if (rc) 46 dev_dbg(&port->dev, "failed to find component registers\n"); 47 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)); 51 if (IS_ERR(dport)) { 52 ctx->error = PTR_ERR(dport); 53 return PTR_ERR(dport); 54 } 55 ctx->count++; 56 57 dev_dbg(&port->dev, "add dport%d: %s\n", port_num, dev_name(&pdev->dev)); 58 59 return 0; 60 } 61 62 /** 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 65 * 66 * Returns a positive number of dports enumerated or a negative error 67 * code. 68 */ 69 int devm_cxl_port_enumerate_dports(struct cxl_port *port) 70 { 71 struct pci_bus *bus = cxl_port_to_pci_bus(port); 72 struct cxl_walk_context ctx; 73 int type; 74 75 if (!bus) 76 return -ENXIO; 77 78 if (pci_is_root_bus(bus)) 79 type = PCI_EXP_TYPE_ROOT_PORT; 80 else 81 type = PCI_EXP_TYPE_DOWNSTREAM; 82 83 ctx = (struct cxl_walk_context) { 84 .port = port, 85 .bus = bus, 86 .type = type, 87 }; 88 pci_walk_bus(bus, match_add_dports, &ctx); 89 90 if (ctx.count == 0) 91 return -ENODEV; 92 if (ctx.error) 93 return ctx.error; 94 return ctx.count; 95 } 96 EXPORT_SYMBOL_NS_GPL(devm_cxl_port_enumerate_dports, CXL); 97