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>
This commit is contained in:
parent
538831f1be
commit
7f8faf96a2
|
@ -1087,6 +1087,47 @@ static struct cxl_ep *cxl_ep_load(struct cxl_port *port,
|
||||||
return xa_load(&port->endpoints, (unsigned long)&cxlmd->dev);
|
return xa_load(&port->endpoints, (unsigned long)&cxlmd->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int devm_cxl_add_endpoint(struct cxl_memdev *cxlmd,
|
||||||
|
struct cxl_dport *parent_dport)
|
||||||
|
{
|
||||||
|
struct cxl_port *parent_port = parent_dport->port;
|
||||||
|
struct cxl_dev_state *cxlds = cxlmd->cxlds;
|
||||||
|
struct cxl_port *endpoint, *iter, *down;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now that the path to the root is established record all the
|
||||||
|
* intervening ports in the chain.
|
||||||
|
*/
|
||||||
|
for (iter = parent_port, down = NULL; !is_cxl_root(iter);
|
||||||
|
down = iter, iter = to_cxl_port(iter->dev.parent)) {
|
||||||
|
struct cxl_ep *ep;
|
||||||
|
|
||||||
|
ep = cxl_ep_load(iter, cxlmd);
|
||||||
|
ep->next = down;
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint = devm_cxl_add_port(&parent_port->dev, &cxlmd->dev,
|
||||||
|
cxlds->component_reg_phys, parent_dport);
|
||||||
|
if (IS_ERR(endpoint))
|
||||||
|
return PTR_ERR(endpoint);
|
||||||
|
|
||||||
|
dev_dbg(&cxlmd->dev, "add: %s\n", dev_name(&endpoint->dev));
|
||||||
|
|
||||||
|
rc = cxl_endpoint_autoremove(cxlmd, endpoint);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (!endpoint->dev.driver) {
|
||||||
|
dev_err(&cxlmd->dev, "%s failed probe\n",
|
||||||
|
dev_name(&endpoint->dev));
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_NS_GPL(devm_cxl_add_endpoint, CXL);
|
||||||
|
|
||||||
static void cxl_detach_ep(void *data)
|
static void cxl_detach_ep(void *data)
|
||||||
{
|
{
|
||||||
struct cxl_memdev *cxlmd = data;
|
struct cxl_memdev *cxlmd = data;
|
||||||
|
|
|
@ -385,10 +385,13 @@ struct cxl_dport {
|
||||||
* struct cxl_ep - track an endpoint's interest in a port
|
* struct cxl_ep - track an endpoint's interest in a port
|
||||||
* @ep: device that hosts a generic CXL endpoint (expander or accelerator)
|
* @ep: device that hosts a generic CXL endpoint (expander or accelerator)
|
||||||
* @dport: which dport routes to this endpoint on @port
|
* @dport: which dport routes to this endpoint on @port
|
||||||
|
* @next: cxl switch port across the link attached to @dport NULL if
|
||||||
|
* attached to an endpoint
|
||||||
*/
|
*/
|
||||||
struct cxl_ep {
|
struct cxl_ep {
|
||||||
struct device *ep;
|
struct device *ep;
|
||||||
struct cxl_dport *dport;
|
struct cxl_dport *dport;
|
||||||
|
struct cxl_port *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -411,6 +414,8 @@ struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port);
|
||||||
struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
|
struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
|
||||||
resource_size_t component_reg_phys,
|
resource_size_t component_reg_phys,
|
||||||
struct cxl_dport *parent_dport);
|
struct cxl_dport *parent_dport);
|
||||||
|
int devm_cxl_add_endpoint(struct cxl_memdev *cxlmd,
|
||||||
|
struct cxl_dport *parent_dport);
|
||||||
struct cxl_port *find_cxl_root(struct device *dev);
|
struct cxl_port *find_cxl_root(struct device *dev);
|
||||||
int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd);
|
int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd);
|
||||||
int cxl_bus_rescan(void);
|
int cxl_bus_rescan(void);
|
||||||
|
|
|
@ -25,34 +25,6 @@
|
||||||
* in higher level operations.
|
* in higher level operations.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int create_endpoint(struct cxl_memdev *cxlmd,
|
|
||||||
struct cxl_dport *parent_dport)
|
|
||||||
{
|
|
||||||
struct cxl_port *parent_port = parent_dport->port;
|
|
||||||
struct cxl_dev_state *cxlds = cxlmd->cxlds;
|
|
||||||
struct cxl_port *endpoint;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
endpoint = devm_cxl_add_port(&parent_port->dev, &cxlmd->dev,
|
|
||||||
cxlds->component_reg_phys, parent_dport);
|
|
||||||
if (IS_ERR(endpoint))
|
|
||||||
return PTR_ERR(endpoint);
|
|
||||||
|
|
||||||
dev_dbg(&cxlmd->dev, "add: %s\n", dev_name(&endpoint->dev));
|
|
||||||
|
|
||||||
rc = cxl_endpoint_autoremove(cxlmd, endpoint);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
if (!endpoint->dev.driver) {
|
|
||||||
dev_err(&cxlmd->dev, "%s failed probe\n",
|
|
||||||
dev_name(&endpoint->dev));
|
|
||||||
return -ENXIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void enable_suspend(void *data)
|
static void enable_suspend(void *data)
|
||||||
{
|
{
|
||||||
cxl_mem_active_dec();
|
cxl_mem_active_dec();
|
||||||
|
@ -116,7 +88,7 @@ static int cxl_mem_probe(struct device *dev)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = create_endpoint(cxlmd, dport);
|
rc = devm_cxl_add_endpoint(cxlmd, dport);
|
||||||
unlock:
|
unlock:
|
||||||
device_unlock(&parent_port->dev);
|
device_unlock(&parent_port->dev);
|
||||||
put_device(&parent_port->dev);
|
put_device(&parent_port->dev);
|
||||||
|
|
Loading…
Reference in New Issue