Skip to content

Commit

Permalink
cxl/port: Fix find_cxl_root() for RCDs and simplify it
Browse files Browse the repository at this point in the history
The find_cxl_root() helper is used to lookup root decoders and other CXL
platform topology information for a given endpoint. It turns out that
for RCDs it has never worked. The result of find_cxl_root(&cxlmd->dev)
is always NULL for the RCH topology case because it expects to find a
cxl_port at the host-bridge. RCH topologies only have the root cxl_port
object with the host-bridge as a dport. While there are no reports of
this being a problem to date, by inspection region enumeration should
crash as a result of this problem, and it does in a local unit test for
this scenario.

However, an observation that ever since:

commit f17b558 ("cxl/pmem: Refactor nvdimm device registration, delete the workqueue")

...all callers of find_cxl_root() occur after the memdev connection to
the port topology has been established. That means that find_cxl_root()
can be simplified to a walk of the endpoint port topology to the root.
Switch to that arrangement which also fixes the RCD bug.

Fixes: a32320b ("cxl/region: Add region autodiscovery")
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/168002857715.50647.344876437247313909.stgit@dwillia2-xfh.jf.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
  • Loading branch information
Dan Williams committed Apr 4, 2023
1 parent b70c2cf commit d35b495
Show file tree
Hide file tree
Showing 5 changed files with 14 additions and 38 deletions.
6 changes: 3 additions & 3 deletions drivers/cxl/core/pmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ static int match_nvdimm_bridge(struct device *dev, void *data)
return is_cxl_nvdimm_bridge(dev);
}

struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *start)
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_memdev *cxlmd)
{
struct cxl_port *port = find_cxl_root(start);
struct cxl_port *port = find_cxl_root(dev_get_drvdata(&cxlmd->dev));
struct device *dev;

if (!port)
Expand Down Expand Up @@ -253,7 +253,7 @@ int devm_cxl_add_nvdimm(struct cxl_memdev *cxlmd)
struct device *dev;
int rc;

cxl_nvb = cxl_find_nvdimm_bridge(&cxlmd->dev);
cxl_nvb = cxl_find_nvdimm_bridge(cxlmd);
if (!cxl_nvb)
return -ENODEV;

Expand Down
38 changes: 7 additions & 31 deletions drivers/cxl/core/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -823,41 +823,17 @@ static bool dev_is_cxl_root_child(struct device *dev)
return false;
}

/* Find a 2nd level CXL port that has a dport that is an ancestor of @match */
static int match_root_child(struct device *dev, const void *match)
struct cxl_port *find_cxl_root(struct cxl_port *port)
{
const struct device *iter = NULL;
struct cxl_dport *dport;
struct cxl_port *port;

if (!dev_is_cxl_root_child(dev))
return 0;

port = to_cxl_port(dev);
iter = match;
while (iter) {
dport = cxl_find_dport_by_dev(port, iter);
if (dport)
break;
iter = iter->parent;
}

return !!iter;
}
struct cxl_port *iter = port;

struct cxl_port *find_cxl_root(struct device *dev)
{
struct device *port_dev;
struct cxl_port *root;
while (iter && !is_cxl_root(iter))
iter = to_cxl_port(iter->dev.parent);

port_dev = bus_find_device(&cxl_bus_type, NULL, dev, match_root_child);
if (!port_dev)
if (!iter)
return NULL;

root = to_cxl_port(port_dev->parent);
get_device(&root->dev);
put_device(port_dev);
return root;
get_device(&iter->dev);
return iter;
}
EXPORT_SYMBOL_NS_GPL(find_cxl_root, CXL);

Expand Down
2 changes: 1 addition & 1 deletion drivers/cxl/core/region.c
Original file line number Diff line number Diff line change
Expand Up @@ -2251,7 +2251,7 @@ static struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr)
* bridge for one device is the same for all.
*/
if (i == 0) {
cxl_nvb = cxl_find_nvdimm_bridge(&cxlmd->dev);
cxl_nvb = cxl_find_nvdimm_bridge(cxlmd);
if (!cxl_nvb) {
cxlr_pmem = ERR_PTR(-ENODEV);
goto out;
Expand Down
4 changes: 2 additions & 2 deletions drivers/cxl/cxl.h
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ 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,
resource_size_t component_reg_phys,
struct cxl_dport *parent_dport);
struct cxl_port *find_cxl_root(struct device *dev);
struct cxl_port *find_cxl_root(struct cxl_port *port);
int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd);
void cxl_bus_rescan(void);
void cxl_bus_drain(void);
Expand Down Expand Up @@ -760,7 +760,7 @@ struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev);
bool is_cxl_nvdimm(struct device *dev);
bool is_cxl_nvdimm_bridge(struct device *dev);
int devm_cxl_add_nvdimm(struct cxl_memdev *cxlmd);
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *dev);
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_memdev *cxlmd);

#ifdef CONFIG_CXL_REGION
bool is_cxl_pmem_region(struct device *dev);
Expand Down
2 changes: 1 addition & 1 deletion drivers/cxl/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
* This can't fail in practice as CXL root exit unregisters all
* descendant ports and that in turn synchronizes with cxl_port_probe()
*/
root = find_cxl_root(&cxlmd->dev);
root = find_cxl_root(port);

/*
* Now that all endpoint decoders are successfully enumerated, try to
Expand Down

0 comments on commit d35b495

Please sign in to comment.