cxl/pci: Break out range register decoding from cxl_hdm_decode_init()
authorDave Jiang <dave.jiang@intel.com>
Tue, 14 Feb 2023 19:41:08 +0000 (11:41 -0800)
committerDan Williams <dan.j.williams@intel.com>
Tue, 14 Feb 2023 23:45:21 +0000 (15:45 -0800)
There are 2 scenarios that requires additional handling. 1. A device that
has active ranges in DVSEC range registers (RR) but no HDM decoder register
block. 2. A device that has both RR active and HDM, but the HDM decoders
are not programmed. The goal is to create emulated decoder software structs
based on the RR.

Move the CXL DVSEC range register decoding code block from
cxl_hdm_decode_init() to its own function. Refactor code in preparation for
the HDM decoder emulation.  There is no functionality change to the code.
Name the new function to cxl_dvsec_rr_decode().

The only change is to set range->start and range->end to CXL_RESOURCE_NONE
and skipping the reading of base registers if the range size is 0, which
equates to range not active.

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

index 57764e9..52bf6b4 100644 (file)
@@ -141,11 +141,10 @@ int cxl_await_media_ready(struct cxl_dev_state *cxlds)
 }
 EXPORT_SYMBOL_NS_GPL(cxl_await_media_ready, CXL);
 
-static int wait_for_valid(struct cxl_dev_state *cxlds)
+static int wait_for_valid(struct pci_dev *pdev, int d)
 {
-       struct pci_dev *pdev = to_pci_dev(cxlds->dev);
-       int d = cxlds->cxl_dvsec, rc;
        u32 val;
+       int rc;
 
        /*
         * Memory_Info_Valid: When set, indicates that the CXL Range 1 Size high
@@ -334,20 +333,11 @@ static bool __cxl_hdm_decode_init(struct cxl_dev_state *cxlds,
        return true;
 }
 
-/**
- * cxl_hdm_decode_init() - Setup HDM decoding for the endpoint
- * @cxlds: Device state
- * @cxlhdm: Mapped HDM decoder Capability
- *
- * Try to enable the endpoint's HDM Decoder Capability
- */
-int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm)
+static int cxl_dvsec_rr_decode(struct device *dev, int d,
+                              struct cxl_endpoint_dvsec_info *info)
 {
-       struct pci_dev *pdev = to_pci_dev(cxlds->dev);
-       struct cxl_endpoint_dvsec_info info = { 0 };
+       struct pci_dev *pdev = to_pci_dev(dev);
        int hdm_count, rc, i, ranges = 0;
-       struct device *dev = &pdev->dev;
-       int d = cxlds->cxl_dvsec;
        u16 cap, ctrl;
 
        if (!d) {
@@ -378,7 +368,7 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm)
        if (!hdm_count || hdm_count > 2)
                return -EINVAL;
 
-       rc = wait_for_valid(cxlds);
+       rc = wait_for_valid(pdev, d);
        if (rc) {
                dev_dbg(dev, "Failure awaiting MEM_INFO_VALID (%d)\n", rc);
                return rc;
@@ -389,9 +379,9 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm)
         * disabled, and they will remain moot after the HDM Decoder
         * capability is enabled.
         */
-       info.mem_enabled = FIELD_GET(CXL_DVSEC_MEM_ENABLE, ctrl);
-       if (!info.mem_enabled)
-               goto hdm_init;
+       info->mem_enabled = FIELD_GET(CXL_DVSEC_MEM_ENABLE, ctrl);
+       if (!info->mem_enabled)
+               return 0;
 
        for (i = 0; i < hdm_count; i++) {
                u64 base, size;
@@ -410,6 +400,13 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm)
                        return rc;
 
                size |= temp & CXL_DVSEC_MEM_SIZE_LOW_MASK;
+               if (!size) {
+                       info->dvsec_range[i] = (struct range) {
+                               .start = 0,
+                               .end = CXL_RESOURCE_NONE,
+                       };
+                       continue;
+               }
 
                rc = pci_read_config_dword(
                        pdev, d + CXL_DVSEC_RANGE_BASE_HIGH(i), &temp);
@@ -425,22 +422,41 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm)
 
                base |= temp & CXL_DVSEC_MEM_BASE_LOW_MASK;
 
-               info.dvsec_range[i] = (struct range) {
+               info->dvsec_range[i] = (struct range) {
                        .start = base,
                        .end = base + size - 1
                };
 
-               if (size)
-                       ranges++;
+               ranges++;
        }
 
-       info.ranges = ranges;
+       info->ranges = ranges;
+
+       return 0;
+}
+
+/**
+ * cxl_hdm_decode_init() - Setup HDM decoding for the endpoint
+ * @cxlds: Device state
+ * @cxlhdm: Mapped HDM decoder Capability
+ *
+ * Try to enable the endpoint's HDM Decoder Capability
+ */
+int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm)
+{
+       struct cxl_endpoint_dvsec_info info = { 0 };
+       struct device *dev = cxlds->dev;
+       int d = cxlds->cxl_dvsec;
+       int rc;
+
+       rc = cxl_dvsec_rr_decode(dev, d, &info);
+       if (rc < 0)
+               return rc;
 
        /*
         * If DVSEC ranges are being used instead of HDM decoder registers there
         * is no use in trying to manage those.
         */
-hdm_init:
        if (!__cxl_hdm_decode_init(cxlds, cxlhdm, &info)) {
                dev_err(dev,
                        "Legacy range registers configuration prevents HDM operation.\n");