cxl/hdm: Emulate HDM decoder from DVSEC range registers
authorDave Jiang <dave.jiang@intel.com>
Tue, 14 Feb 2023 19:41:24 +0000 (11:41 -0800)
committerDan Williams <dan.j.williams@intel.com>
Tue, 14 Feb 2023 23:45:21 +0000 (15:45 -0800)
In the case where HDM decoder register block exists but is not programmed
and at the same time the DVSEC range register range is active, populate the
CXL decoder object 'cxl_decoder' with info from DVSEC range registers.

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/167640368454.935665.13806415120298330717.stgit@dwillia2-xfh.jf.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/cxl/core/hdm.c
drivers/cxl/core/pci.c
drivers/cxl/cxl.h
drivers/cxl/port.c
tools/testing/cxl/test/cxl.c
tools/testing/cxl/test/mock.c
tools/testing/cxl/test/mock.h

index dcc16d7..c0f2244 100644 (file)
@@ -679,9 +679,34 @@ static int cxl_decoder_reset(struct cxl_decoder *cxld)
        return 0;
 }
 
+static int cxl_setup_hdm_decoder_from_dvsec(struct cxl_port *port,
+                                           struct cxl_decoder *cxld, int which,
+                                           struct cxl_endpoint_dvsec_info *info)
+{
+       if (!is_cxl_endpoint(port))
+               return -EOPNOTSUPP;
+
+       if (!range_len(&info->dvsec_range[which]))
+               return -ENOENT;
+
+       cxld->target_type = CXL_DECODER_EXPANDER;
+       cxld->commit = NULL;
+       cxld->reset = NULL;
+       cxld->hpa_range = info->dvsec_range[which];
+
+       /*
+        * Set the emulated decoder as locked pending additional support to
+        * change the range registers at run time.
+        */
+       cxld->flags |= CXL_DECODER_F_ENABLE | CXL_DECODER_F_LOCK;
+       port->commit_end = cxld->id;
+
+       return 0;
+}
+
 static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
                            int *target_map, void __iomem *hdm, int which,
-                           u64 *dpa_base)
+                           u64 *dpa_base, struct cxl_endpoint_dvsec_info *info)
 {
        struct cxl_endpoint_decoder *cxled = NULL;
        u64 size, base, skip, dpa_size;
@@ -717,6 +742,9 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
                .end = base + size - 1,
        };
 
+       if (cxled && !committed && range_len(&info->dvsec_range[which]))
+               return cxl_setup_hdm_decoder_from_dvsec(port, cxld, which, info);
+
        /* decoders are enabled if committed */
        if (committed) {
                cxld->flags |= CXL_DECODER_F_ENABLE;
@@ -790,7 +818,8 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
  * devm_cxl_enumerate_decoders - add decoder objects per HDM register set
  * @cxlhdm: Structure to populate with HDM capabilities
  */
-int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
+int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
+                               struct cxl_endpoint_dvsec_info *info)
 {
        void __iomem *hdm = cxlhdm->regs.hdm_decoder;
        struct cxl_port *port = cxlhdm->port;
@@ -842,7 +871,8 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
                        cxld = &cxlsd->cxld;
                }
 
-               rc = init_hdm_decoder(port, cxld, target_map, hdm, i, &dpa_base);
+               rc = init_hdm_decoder(port, cxld, target_map, hdm, i,
+                                     &dpa_base, info);
                if (rc) {
                        put_device(&cxld->dev);
                        return rc;
index d0b2548..4df0b35 100644 (file)
@@ -426,7 +426,7 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
         * Decoder Capability Enable.
         */
        if (info->mem_enabled)
-               return -EBUSY;
+               return 0;
 
        rc = devm_cxl_enable_hdm(&port->dev, cxlhdm);
        if (rc)
index fc01ce9..fe9d759 100644 (file)
@@ -644,7 +644,8 @@ struct cxl_endpoint_dvsec_info {
 
 struct cxl_hdm;
 struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port);
-int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm);
+int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
+                               struct cxl_endpoint_dvsec_info *info);
 int devm_cxl_add_passthrough_decoder(struct cxl_port *port);
 int cxl_dvsec_rr_decode(struct device *dev, int dvsec,
                        struct cxl_endpoint_dvsec_info *info);
index 9e09728..d3a708e 100644 (file)
@@ -78,7 +78,7 @@ static int cxl_port_probe(struct device *dev)
                }
        }
 
-       rc = devm_cxl_enumerate_decoders(cxlhdm);
+       rc = devm_cxl_enumerate_decoders(cxlhdm, &info);
        if (rc) {
                dev_err(dev, "Couldn't enumerate decoders (%d)\n", rc);
                return rc;
index 30ee680..3b4916a 100644 (file)
@@ -701,7 +701,8 @@ static int mock_decoder_reset(struct cxl_decoder *cxld)
        return 0;
 }
 
-static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
+static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
+                                      struct cxl_endpoint_dvsec_info *info)
 {
        struct cxl_port *port = cxlhdm->port;
        struct cxl_port *parent_port = to_cxl_port(port->dev.parent);
index 2a13f47..3116c9f 100644 (file)
@@ -162,16 +162,17 @@ int __wrap_devm_cxl_add_passthrough_decoder(struct cxl_port *port)
 }
 EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_passthrough_decoder, CXL);
 
-int __wrap_devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
+int __wrap_devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
+                                      struct cxl_endpoint_dvsec_info *info)
 {
        int rc, index;
        struct cxl_port *port = cxlhdm->port;
        struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
 
        if (ops && ops->is_mock_port(port->uport))
-               rc = ops->devm_cxl_enumerate_decoders(cxlhdm);
+               rc = ops->devm_cxl_enumerate_decoders(cxlhdm, info);
        else
-               rc = devm_cxl_enumerate_decoders(cxlhdm);
+               rc = devm_cxl_enumerate_decoders(cxlhdm, info);
        put_cxl_mock_ops(index);
 
        return rc;
index ef33f15..e377ced 100644 (file)
@@ -25,7 +25,8 @@ struct cxl_mock_ops {
        int (*devm_cxl_port_enumerate_dports)(struct cxl_port *port);
        struct cxl_hdm *(*devm_cxl_setup_hdm)(struct cxl_port *port);
        int (*devm_cxl_add_passthrough_decoder)(struct cxl_port *port);
-       int (*devm_cxl_enumerate_decoders)(struct cxl_hdm *hdm);
+       int (*devm_cxl_enumerate_decoders)(
+               struct cxl_hdm *hdm, struct cxl_endpoint_dvsec_info *info);
 };
 
 void register_cxl_mock_ops(struct cxl_mock_ops *ops);