cxl/region: Clarify when a cxld->commit() callback is mandatory
authorDan Williams <dan.j.williams@intel.com>
Sat, 17 Dec 2022 01:33:38 +0000 (17:33 -0800)
committerDan Williams <dan.j.williams@intel.com>
Wed, 25 Jan 2023 23:29:17 +0000 (15:29 -0800)
Both cxl_switch_decoders() and cxl_endpoint_decoders() are considered by
cxl_region_decode_commit(). Flag cases where cxl_switch_decoders with
multiple targets, or cxl_endpoint_decoders do not have a commit callback
set. The switch case is unlikely to happen since switches are only
enumerated by the CXL core, but the endpoint case may support decoders
defined by drivers outside of drivers/cxl, like accerator drivers.

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Link: https://lore.kernel.org/r/167124081824.1626103.1555704405392757219.stgit@dwillia2-xfh.jf.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/cxl/core/region.c

index c11a6ab5e48d5c551aa83a1b1ebe377cca8ae57b..60828d01972acf313c84b234162a25258c87662b 100644 (file)
@@ -156,6 +156,22 @@ static int cxl_region_decode_reset(struct cxl_region *cxlr, int count)
        return 0;
 }
 
+static int commit_decoder(struct cxl_decoder *cxld)
+{
+       struct cxl_switch_decoder *cxlsd = NULL;
+
+       if (cxld->commit)
+               return cxld->commit(cxld);
+
+       if (is_switch_decoder(&cxld->dev))
+               cxlsd = to_cxl_switch_decoder(&cxld->dev);
+
+       if (dev_WARN_ONCE(&cxld->dev, !cxlsd || cxlsd->nr_targets > 1,
+                         "->commit() is required\n"))
+               return -ENXIO;
+       return 0;
+}
+
 static int cxl_region_decode_commit(struct cxl_region *cxlr)
 {
        struct cxl_region_params *p = &cxlr->params;
@@ -174,8 +190,7 @@ static int cxl_region_decode_commit(struct cxl_region *cxlr)
                     iter = to_cxl_port(iter->dev.parent)) {
                        cxl_rr = cxl_rr_load(iter, cxlr);
                        cxld = cxl_rr->decoder;
-                       if (cxld->commit)
-                               rc = cxld->commit(cxld);
+                       rc = commit_decoder(cxld);
                        if (rc)
                                break;
                }