cxl/acpi: Convert CFMWS parsing to ACPI sub-table helpers
authorDan Williams <dan.j.williams@intel.com>
Fri, 29 Oct 2021 19:51:48 +0000 (12:51 -0700)
committerDan Williams <dan.j.williams@intel.com>
Mon, 15 Nov 2021 19:02:59 +0000 (11:02 -0800)
The cxl_acpi driver originally open-coded its table parsing since the
ACPI subtable helpers were marked __init and only used in early NUMA
initialization.  Now that those helpers have been exported for driver
usage replace the open-coded solution with the common one.

Cc: Alison Schofield <alison.schofield@intel.com>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://lore.kernel.org/r/163553710810.2509508.14686373989517930921.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/cxl/Kconfig
drivers/cxl/acpi.c

index e6de221..67c9137 100644 (file)
@@ -51,6 +51,7 @@ config CXL_ACPI
        tristate "CXL ACPI: Platform Support"
        depends on ACPI
        default CXL_BUS
+       select ACPI_TABLE_LIB
        help
          Enable support for host managed device memory (HDM) resources
          published by a platform's ACPI CXL memory layout description.  See
index dadc7f6..7820082 100644 (file)
@@ -8,8 +8,6 @@
 #include <linux/pci.h>
 #include "cxl.h"
 
-static struct acpi_table_header *acpi_cedt;
-
 /* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */
 #define CFMWS_INTERLEAVE_WAYS(x)       (1 << (x)->interleave_ways)
 #define CFMWS_INTERLEAVE_GRANULARITY(x)        ((x)->granularity + 8)
@@ -74,134 +72,63 @@ static int cxl_acpi_cfmws_verify(struct device *dev,
        return 0;
 }
 
-static void cxl_add_cfmws_decoders(struct device *dev,
-                                  struct cxl_port *root_port)
+struct cxl_cfmws_context {
+       struct device *dev;
+       struct cxl_port *root_port;
+};
+
+static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
+                          const unsigned long end)
 {
        int target_map[CXL_DECODER_MAX_INTERLEAVE];
+       struct cxl_cfmws_context *ctx = arg;
+       struct cxl_port *root_port = ctx->root_port;
+       struct device *dev = ctx->dev;
        struct acpi_cedt_cfmws *cfmws;
        struct cxl_decoder *cxld;
-       acpi_size len, cur = 0;
-       void *cedt_subtable;
-       int rc;
-
-       len = acpi_cedt->length - sizeof(*acpi_cedt);
-       cedt_subtable = acpi_cedt + 1;
-
-       while (cur < len) {
-               struct acpi_cedt_header *c = cedt_subtable + cur;
-               int i;
-
-               if (c->type != ACPI_CEDT_TYPE_CFMWS) {
-                       cur += c->length;
-                       continue;
-               }
+       int rc, i;
 
-               cfmws = cedt_subtable + cur;
+       cfmws = (struct acpi_cedt_cfmws *) header;
 
-               if (cfmws->header.length < sizeof(*cfmws)) {
-                       dev_warn_once(dev,
-                                     "CFMWS entry skipped:invalid length:%u\n",
-                                     cfmws->header.length);
-                       cur += c->length;
-                       continue;
-               }
-
-               rc = cxl_acpi_cfmws_verify(dev, cfmws);
-               if (rc) {
-                       dev_err(dev, "CFMWS range %#llx-%#llx not registered\n",
-                               cfmws->base_hpa, cfmws->base_hpa +
-                               cfmws->window_size - 1);
-                       cur += c->length;
-                       continue;
-               }
-
-               for (i = 0; i < CFMWS_INTERLEAVE_WAYS(cfmws); i++)
-                       target_map[i] = cfmws->interleave_targets[i];
-
-               cxld = cxl_decoder_alloc(root_port,
-                                        CFMWS_INTERLEAVE_WAYS(cfmws));
-               if (IS_ERR(cxld))
-                       goto next;
-
-               cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions);
-               cxld->target_type = CXL_DECODER_EXPANDER;
-               cxld->range = (struct range) {
-                       .start = cfmws->base_hpa,
-                       .end = cfmws->base_hpa + cfmws->window_size - 1,
-               };
-               cxld->interleave_ways = CFMWS_INTERLEAVE_WAYS(cfmws);
-               cxld->interleave_granularity =
-                       CFMWS_INTERLEAVE_GRANULARITY(cfmws);
-
-               rc = cxl_decoder_add(cxld, target_map);
-               if (rc)
-                       put_device(&cxld->dev);
-               else
-                       rc = cxl_decoder_autoremove(dev, cxld);
-               if (rc) {
-                       dev_err(dev, "Failed to add decoder for %#llx-%#llx\n",
-                               cfmws->base_hpa, cfmws->base_hpa +
-                               cfmws->window_size - 1);
-                       goto next;
-               }
-               dev_dbg(dev, "add: %s range %#llx-%#llx\n",
-                       dev_name(&cxld->dev), cfmws->base_hpa,
+       rc = cxl_acpi_cfmws_verify(dev, cfmws);
+       if (rc) {
+               dev_err(dev, "CFMWS range %#llx-%#llx not registered\n",
+                       cfmws->base_hpa,
                        cfmws->base_hpa + cfmws->window_size - 1);
-next:
-               cur += c->length;
+               return 0;
        }
-}
-
-static struct acpi_cedt_chbs *cxl_acpi_match_chbs(struct device *dev, u32 uid)
-{
-       struct acpi_cedt_chbs *chbs, *chbs_match = NULL;
-       acpi_size len, cur = 0;
-       void *cedt_subtable;
 
-       len = acpi_cedt->length - sizeof(*acpi_cedt);
-       cedt_subtable = acpi_cedt + 1;
+       for (i = 0; i < CFMWS_INTERLEAVE_WAYS(cfmws); i++)
+               target_map[i] = cfmws->interleave_targets[i];
 
-       while (cur < len) {
-               struct acpi_cedt_header *c = cedt_subtable + cur;
-
-               if (c->type != ACPI_CEDT_TYPE_CHBS) {
-                       cur += c->length;
-                       continue;
-               }
-
-               chbs = cedt_subtable + cur;
-
-               if (chbs->header.length < sizeof(*chbs)) {
-                       dev_warn_once(dev,
-                                     "CHBS entry skipped: invalid length:%u\n",
-                                     chbs->header.length);
-                       cur += c->length;
-                       continue;
-               }
-
-               if (chbs->uid != uid) {
-                       cur += c->length;
-                       continue;
-               }
+       cxld = cxl_decoder_alloc(root_port, CFMWS_INTERLEAVE_WAYS(cfmws));
+       if (IS_ERR(cxld))
+               return 0;
 
-               if (chbs_match) {
-                       dev_warn_once(dev,
-                                     "CHBS entry skipped: duplicate UID:%u\n",
-                                     uid);
-                       cur += c->length;
-                       continue;
-               }
+       cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions);
+       cxld->target_type = CXL_DECODER_EXPANDER;
+       cxld->range = (struct range){
+               .start = cfmws->base_hpa,
+               .end = cfmws->base_hpa + cfmws->window_size - 1,
+       };
+       cxld->interleave_ways = CFMWS_INTERLEAVE_WAYS(cfmws);
+       cxld->interleave_granularity = CFMWS_INTERLEAVE_GRANULARITY(cfmws);
 
-               chbs_match = chbs;
-               cur += c->length;
+       rc = cxl_decoder_add(cxld, target_map);
+       if (rc)
+               put_device(&cxld->dev);
+       else
+               rc = cxl_decoder_autoremove(dev, cxld);
+       if (rc) {
+               dev_err(dev, "Failed to add decoder for %#llx-%#llx\n",
+                       cfmws->base_hpa,
+                       cfmws->base_hpa + cfmws->window_size - 1);
+               return 0;
        }
+       dev_dbg(dev, "add: %s range %#llx-%#llx\n", dev_name(&cxld->dev),
+               cfmws->base_hpa, cfmws->base_hpa + cfmws->window_size - 1);
 
-       return chbs_match ? chbs_match : ERR_PTR(-ENODEV);
-}
-
-static resource_size_t get_chbcr(struct acpi_cedt_chbs *chbs)
-{
-       return IS_ERR(chbs) ? CXL_RESOURCE_NONE : chbs->base;
+       return 0;
 }
 
 __mock int match_add_root_ports(struct pci_dev *pdev, void *data)
@@ -355,12 +282,35 @@ static int add_host_bridge_uport(struct device *match, void *arg)
        return rc;
 }
 
+struct cxl_chbs_context {
+       unsigned long long uid;
+       resource_size_t chbcr;
+};
+
+static int cxl_get_chbcr(union acpi_subtable_headers *header, void *arg,
+                        const unsigned long end)
+{
+       struct cxl_chbs_context *ctx = arg;
+       struct acpi_cedt_chbs *chbs;
+
+       if (ctx->chbcr)
+               return 0;
+
+       chbs = (struct acpi_cedt_chbs *) header;
+
+       if (ctx->uid != chbs->uid)
+               return 0;
+       ctx->chbcr = chbs->base;
+
+       return 0;
+}
+
 static int add_host_bridge_dport(struct device *match, void *arg)
 {
        int rc;
        acpi_status status;
        unsigned long long uid;
-       struct acpi_cedt_chbs *chbs;
+       struct cxl_chbs_context ctx;
        struct cxl_port *root_port = arg;
        struct device *host = root_port->dev.parent;
        struct acpi_device *bridge = to_cxl_host_bridge(host, match);
@@ -376,14 +326,18 @@ static int add_host_bridge_dport(struct device *match, void *arg)
                return -ENODEV;
        }
 
-       chbs = cxl_acpi_match_chbs(host, uid);
-       if (IS_ERR(chbs)) {
+       ctx = (struct cxl_chbs_context) {
+               .uid = uid,
+       };
+       acpi_table_parse_cedt(ACPI_CEDT_TYPE_CHBS, cxl_get_chbcr, &ctx);
+
+       if (ctx.chbcr == 0) {
                dev_warn(host, "No CHBS found for Host Bridge: %s\n",
                         dev_name(match));
                return 0;
        }
 
-       rc = cxl_add_dport(root_port, match, uid, get_chbcr(chbs));
+       rc = cxl_add_dport(root_port, match, uid, ctx.chbcr);
        if (rc) {
                dev_err(host, "failed to add downstream port: %s\n",
                        dev_name(match));
@@ -417,40 +371,29 @@ static int add_root_nvdimm_bridge(struct device *match, void *data)
        return 1;
 }
 
-static u32 cedt_instance(struct platform_device *pdev)
-{
-       const bool *native_acpi0017 = acpi_device_get_match_data(&pdev->dev);
-
-       if (native_acpi0017 && *native_acpi0017)
-               return 0;
-
-       /* for cxl_test request a non-canonical instance */
-       return U32_MAX;
-}
-
 static int cxl_acpi_probe(struct platform_device *pdev)
 {
        int rc;
-       acpi_status status;
        struct cxl_port *root_port;
        struct device *host = &pdev->dev;
        struct acpi_device *adev = ACPI_COMPANION(host);
+       struct cxl_cfmws_context ctx;
 
        root_port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL);
        if (IS_ERR(root_port))
                return PTR_ERR(root_port);
        dev_dbg(host, "add: %s\n", dev_name(&root_port->dev));
 
-       status = acpi_get_table(ACPI_SIG_CEDT, cedt_instance(pdev), &acpi_cedt);
-       if (ACPI_FAILURE(status))
-               return -ENXIO;
-
        rc = bus_for_each_dev(adev->dev.bus, NULL, root_port,
                              add_host_bridge_dport);
-       if (rc)
-               goto out;
+       if (rc < 0)
+               return rc;
 
-       cxl_add_cfmws_decoders(host, root_port);
+       ctx = (struct cxl_cfmws_context) {
+               .dev = host,
+               .root_port = root_port,
+       };
+       acpi_table_parse_cedt(ACPI_CEDT_TYPE_CFMWS, cxl_parse_cfmws, &ctx);
 
        /*
         * Root level scanned with host-bridge as dports, now scan host-bridges
@@ -458,24 +401,20 @@ static int cxl_acpi_probe(struct platform_device *pdev)
         */
        rc = bus_for_each_dev(adev->dev.bus, NULL, root_port,
                              add_host_bridge_uport);
-       if (rc)
-               goto out;
+       if (rc < 0)
+               return rc;
 
        if (IS_ENABLED(CONFIG_CXL_PMEM))
                rc = device_for_each_child(&root_port->dev, root_port,
                                           add_root_nvdimm_bridge);
-
-out:
-       acpi_put_table(acpi_cedt);
        if (rc < 0)
                return rc;
+
        return 0;
 }
 
-static bool native_acpi0017 = true;
-
 static const struct acpi_device_id cxl_acpi_ids[] = {
-       { "ACPI0017", (unsigned long) &native_acpi0017 },
+       { "ACPI0017" },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, cxl_acpi_ids);
@@ -491,3 +430,4 @@ static struct platform_driver cxl_acpi_driver = {
 module_platform_driver(cxl_acpi_driver);
 MODULE_LICENSE("GPL v2");
 MODULE_IMPORT_NS(CXL);
+MODULE_IMPORT_NS(ACPI);