Skip to content

Commit d35b495

Browse files
committed
cxl/port: Fix find_cxl_root() for RCDs and simplify it
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>
1 parent b70c2cf commit d35b495

File tree

5 files changed

+14
-38
lines changed

5 files changed

+14
-38
lines changed

drivers/cxl/core/pmem.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ static int match_nvdimm_bridge(struct device *dev, void *data)
6262
return is_cxl_nvdimm_bridge(dev);
6363
}
6464

65-
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *start)
65+
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_memdev *cxlmd)
6666
{
67-
struct cxl_port *port = find_cxl_root(start);
67+
struct cxl_port *port = find_cxl_root(dev_get_drvdata(&cxlmd->dev));
6868
struct device *dev;
6969

7070
if (!port)
@@ -253,7 +253,7 @@ int devm_cxl_add_nvdimm(struct cxl_memdev *cxlmd)
253253
struct device *dev;
254254
int rc;
255255

256-
cxl_nvb = cxl_find_nvdimm_bridge(&cxlmd->dev);
256+
cxl_nvb = cxl_find_nvdimm_bridge(cxlmd);
257257
if (!cxl_nvb)
258258
return -ENODEV;
259259

drivers/cxl/core/port.c

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -823,41 +823,17 @@ static bool dev_is_cxl_root_child(struct device *dev)
823823
return false;
824824
}
825825

826-
/* Find a 2nd level CXL port that has a dport that is an ancestor of @match */
827-
static int match_root_child(struct device *dev, const void *match)
826+
struct cxl_port *find_cxl_root(struct cxl_port *port)
828827
{
829-
const struct device *iter = NULL;
830-
struct cxl_dport *dport;
831-
struct cxl_port *port;
832-
833-
if (!dev_is_cxl_root_child(dev))
834-
return 0;
835-
836-
port = to_cxl_port(dev);
837-
iter = match;
838-
while (iter) {
839-
dport = cxl_find_dport_by_dev(port, iter);
840-
if (dport)
841-
break;
842-
iter = iter->parent;
843-
}
844-
845-
return !!iter;
846-
}
828+
struct cxl_port *iter = port;
847829

848-
struct cxl_port *find_cxl_root(struct device *dev)
849-
{
850-
struct device *port_dev;
851-
struct cxl_port *root;
830+
while (iter && !is_cxl_root(iter))
831+
iter = to_cxl_port(iter->dev.parent);
852832

853-
port_dev = bus_find_device(&cxl_bus_type, NULL, dev, match_root_child);
854-
if (!port_dev)
833+
if (!iter)
855834
return NULL;
856-
857-
root = to_cxl_port(port_dev->parent);
858-
get_device(&root->dev);
859-
put_device(port_dev);
860-
return root;
835+
get_device(&iter->dev);
836+
return iter;
861837
}
862838
EXPORT_SYMBOL_NS_GPL(find_cxl_root, CXL);
863839

drivers/cxl/core/region.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2251,7 +2251,7 @@ static struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr)
22512251
* bridge for one device is the same for all.
22522252
*/
22532253
if (i == 0) {
2254-
cxl_nvb = cxl_find_nvdimm_bridge(&cxlmd->dev);
2254+
cxl_nvb = cxl_find_nvdimm_bridge(cxlmd);
22552255
if (!cxl_nvb) {
22562256
cxlr_pmem = ERR_PTR(-ENODEV);
22572257
goto out;

drivers/cxl/cxl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,7 @@ struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port);
658658
struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
659659
resource_size_t component_reg_phys,
660660
struct cxl_dport *parent_dport);
661-
struct cxl_port *find_cxl_root(struct device *dev);
661+
struct cxl_port *find_cxl_root(struct cxl_port *port);
662662
int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd);
663663
void cxl_bus_rescan(void);
664664
void cxl_bus_drain(void);
@@ -760,7 +760,7 @@ struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev);
760760
bool is_cxl_nvdimm(struct device *dev);
761761
bool is_cxl_nvdimm_bridge(struct device *dev);
762762
int devm_cxl_add_nvdimm(struct cxl_memdev *cxlmd);
763-
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *dev);
763+
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_memdev *cxlmd);
764764

765765
#ifdef CONFIG_CXL_REGION
766766
bool is_cxl_pmem_region(struct device *dev);

drivers/cxl/port.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
119119
* This can't fail in practice as CXL root exit unregisters all
120120
* descendant ports and that in turn synchronizes with cxl_port_probe()
121121
*/
122-
root = find_cxl_root(&cxlmd->dev);
122+
root = find_cxl_root(port);
123123

124124
/*
125125
* Now that all endpoint decoders are successfully enumerated, try to

0 commit comments

Comments
 (0)