Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cxl/mem: Enumerate port targets before adding endpoints

The port scanning algorithm in devm_cxl_enumerate_ports() walks up the
topology and adds cxl_port objects starting from the root down to the
endpoint. When those ports are initially created they know all their
dports, but they do not know the downstream cxl_port instance that
represents the next descendant in the topology. Rework create_endpoint()
into devm_cxl_add_endpoint() that enumerates the downstream cxl_port
topology into each port's 'struct cxl_ep' record for each endpoint it
that the port is an ancestor.

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Link: https://lore.kernel.org/r/20220624041950.559155-7-dan.j.williams@intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+47 -29
+41
drivers/cxl/core/port.c
··· 1087 1087 return xa_load(&port->endpoints, (unsigned long)&cxlmd->dev); 1088 1088 } 1089 1089 1090 + int devm_cxl_add_endpoint(struct cxl_memdev *cxlmd, 1091 + struct cxl_dport *parent_dport) 1092 + { 1093 + struct cxl_port *parent_port = parent_dport->port; 1094 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 1095 + struct cxl_port *endpoint, *iter, *down; 1096 + int rc; 1097 + 1098 + /* 1099 + * Now that the path to the root is established record all the 1100 + * intervening ports in the chain. 1101 + */ 1102 + for (iter = parent_port, down = NULL; !is_cxl_root(iter); 1103 + down = iter, iter = to_cxl_port(iter->dev.parent)) { 1104 + struct cxl_ep *ep; 1105 + 1106 + ep = cxl_ep_load(iter, cxlmd); 1107 + ep->next = down; 1108 + } 1109 + 1110 + endpoint = devm_cxl_add_port(&parent_port->dev, &cxlmd->dev, 1111 + cxlds->component_reg_phys, parent_dport); 1112 + if (IS_ERR(endpoint)) 1113 + return PTR_ERR(endpoint); 1114 + 1115 + dev_dbg(&cxlmd->dev, "add: %s\n", dev_name(&endpoint->dev)); 1116 + 1117 + rc = cxl_endpoint_autoremove(cxlmd, endpoint); 1118 + if (rc) 1119 + return rc; 1120 + 1121 + if (!endpoint->dev.driver) { 1122 + dev_err(&cxlmd->dev, "%s failed probe\n", 1123 + dev_name(&endpoint->dev)); 1124 + return -ENXIO; 1125 + } 1126 + 1127 + return 0; 1128 + } 1129 + EXPORT_SYMBOL_NS_GPL(devm_cxl_add_endpoint, CXL); 1130 + 1090 1131 static void cxl_detach_ep(void *data) 1091 1132 { 1092 1133 struct cxl_memdev *cxlmd = data;
+5
drivers/cxl/cxl.h
··· 385 385 * struct cxl_ep - track an endpoint's interest in a port 386 386 * @ep: device that hosts a generic CXL endpoint (expander or accelerator) 387 387 * @dport: which dport routes to this endpoint on @port 388 + * @next: cxl switch port across the link attached to @dport NULL if 389 + * attached to an endpoint 388 390 */ 389 391 struct cxl_ep { 390 392 struct device *ep; 391 393 struct cxl_dport *dport; 394 + struct cxl_port *next; 392 395 }; 393 396 394 397 /* ··· 414 411 struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport, 415 412 resource_size_t component_reg_phys, 416 413 struct cxl_dport *parent_dport); 414 + int devm_cxl_add_endpoint(struct cxl_memdev *cxlmd, 415 + struct cxl_dport *parent_dport); 417 416 struct cxl_port *find_cxl_root(struct device *dev); 418 417 int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd); 419 418 int cxl_bus_rescan(void);
+1 -29
drivers/cxl/mem.c
··· 25 25 * in higher level operations. 26 26 */ 27 27 28 - static int create_endpoint(struct cxl_memdev *cxlmd, 29 - struct cxl_dport *parent_dport) 30 - { 31 - struct cxl_port *parent_port = parent_dport->port; 32 - struct cxl_dev_state *cxlds = cxlmd->cxlds; 33 - struct cxl_port *endpoint; 34 - int rc; 35 - 36 - endpoint = devm_cxl_add_port(&parent_port->dev, &cxlmd->dev, 37 - cxlds->component_reg_phys, parent_dport); 38 - if (IS_ERR(endpoint)) 39 - return PTR_ERR(endpoint); 40 - 41 - dev_dbg(&cxlmd->dev, "add: %s\n", dev_name(&endpoint->dev)); 42 - 43 - rc = cxl_endpoint_autoremove(cxlmd, endpoint); 44 - if (rc) 45 - return rc; 46 - 47 - if (!endpoint->dev.driver) { 48 - dev_err(&cxlmd->dev, "%s failed probe\n", 49 - dev_name(&endpoint->dev)); 50 - return -ENXIO; 51 - } 52 - 53 - return 0; 54 - } 55 - 56 28 static void enable_suspend(void *data) 57 29 { 58 30 cxl_mem_active_dec(); ··· 88 116 goto unlock; 89 117 } 90 118 91 - rc = create_endpoint(cxlmd, dport); 119 + rc = devm_cxl_add_endpoint(cxlmd, dport); 92 120 unlock: 93 121 device_unlock(&parent_port->dev); 94 122 put_device(&parent_port->dev);