linux-cxl.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/2] CXL ACPI tables for object creation
@ 2021-06-17  1:11 Alison Schofield
  2021-06-17  1:11 ` [PATCH v3 1/2] cxl/acpi: Add the Host Bridge base address to CXL port objects Alison Schofield
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Alison Schofield @ 2021-06-17  1:11 UTC (permalink / raw)
  To: Ben Widawsky, Dan Williams, Ira Weiny, Alison Schofield,
	Vishal Verma, Jonathan Cameron
  Cc: linux-cxl, linux-kernel, linux-acpi

Jonathan - I updated Patch 2 so I didn't keep your Reviewed-by tag.

Changes since v2 [1]:
- Warn and continue, rather than error out, on these acpi table parsing issues:
  table length mismatch for either CHBS or CFMWS; duplicate uid's for CHBS.
  (Ben, Jonathan)
- Update flow in cxl_acpi_match_chbs()  (Ben, Jonathan)
- Improve naming cedt_table->acpi_cedt, cedt_base->cedt_subtable (Ben)
- Emit debug message only if CFMWS is greater than its expected length (Ben)
- Update the dev_err messages wrt the CFMWS expected length failure.
- Remove blank line before error handling block (Jonathan)
- Rebase to the CXL pending branch [2]

[1]: https://lore.kernel.org/linux-cxl/cover.1623800340.git.alison.schofield@intel.com/ 
[2]: https://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl.git/log/?h=pending

--
Parse the ACPI CXL Early Discovery Table (CEDT) and use the CHBS & CFMWS
when creating port and decoder objects.

CHBS: CXL Host Bridge Structure - Patch 1
CFMWS: CXL Fixed Memory Window Structure - Patch 2

Alison Schofield (2):
  cxl/acpi: Add the Host Bridge base address to CXL port objects
  cxl/acpi: Use the ACPI CFMWS to create static decoder objects

 drivers/cxl/acpi.c | 217 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 212 insertions(+), 5 deletions(-)


base-commit: 21083f51521fb0f60dbac591f175c3ed48435af4
-- 
2.26.2

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v3 1/2] cxl/acpi: Add the Host Bridge base address to CXL port objects
  2021-06-17  1:11 [PATCH v3 0/2] CXL ACPI tables for object creation Alison Schofield
@ 2021-06-17  1:11 ` Alison Schofield
  2021-06-17  8:57   ` Jonathan Cameron
  2021-06-17  1:11 ` [PATCH v3 2/2] cxl/acpi: Use the ACPI CFMWS to create static decoder objects Alison Schofield
  2021-06-17 15:41 ` [PATCH v3 0/2] CXL ACPI tables for object creation Ben Widawsky
  2 siblings, 1 reply; 7+ messages in thread
From: Alison Schofield @ 2021-06-17  1:11 UTC (permalink / raw)
  To: Ben Widawsky, Dan Williams, Ira Weiny, Alison Schofield,
	Vishal Verma, Jonathan Cameron
  Cc: linux-cxl, linux-kernel, linux-acpi

The base address for the Host Bridge port component registers is located
in the CXL Host Bridge Structure (CHBS) of the ACPI CXL Early Discovery
Table (CEDT). Retrieve the CHBS for each Host Bridge (ACPI0016 device)
and include that base address in the port object.

Co-developed-by: Vishal Verma <vishal.l.verma@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Signed-off-by: Alison Schofield <alison.schofield@intel.com>
---
 drivers/cxl/acpi.c | 98 +++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 93 insertions(+), 5 deletions(-)

diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
index 8a723f7f3f73..852b5c270464 100644
--- a/drivers/cxl/acpi.c
+++ b/drivers/cxl/acpi.c
@@ -8,6 +8,58 @@
 #include <linux/pci.h>
 #include "cxl.h"
 
+static struct acpi_table_header *acpi_cedt;
+
+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;
+
+	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 (dev_WARN_ONCE(dev, chbs->header.length < sizeof(*chbs),
+				  "CHBS entry skipped: invalid length:%u\n",
+				  chbs->header.length)) {
+			cur += c->length;
+			continue;
+		}
+
+		if (chbs->uid != uid) {
+			cur += c->length;
+			continue;
+		}
+
+		if (dev_WARN_ONCE(dev, chbs_match,
+				  "CHBS entry skipped: duplicate UID:%u\n",
+				  uid)) {
+			cur += c->length;
+			continue;
+		}
+
+		chbs_match = chbs;
+		cur += c->length;
+	}
+
+	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;
+}
+
 struct cxl_walk_context {
 	struct device *dev;
 	struct pci_bus *root;
@@ -50,6 +102,21 @@ static int match_add_root_ports(struct pci_dev *pdev, void *data)
 	return 0;
 }
 
+static struct cxl_dport *find_dport_by_dev(struct cxl_port *port, struct device *dev)
+{
+	struct cxl_dport *dport;
+
+	device_lock(&port->dev);
+	list_for_each_entry(dport, &port->dports, list)
+		if (dport->dport == dev) {
+			device_unlock(&port->dev);
+			return dport;
+		}
+
+	device_unlock(&port->dev);
+	return NULL;
+}
+
 static struct acpi_device *to_cxl_host_bridge(struct device *dev)
 {
 	struct acpi_device *adev = to_acpi_device(dev);
@@ -71,6 +138,7 @@ static int add_host_bridge_uport(struct device *match, void *arg)
 	struct acpi_pci_root *pci_root;
 	struct cxl_walk_context ctx;
 	struct cxl_decoder *cxld;
+	struct cxl_dport *dport;
 	struct cxl_port *port;
 
 	if (!bridge)
@@ -80,8 +148,14 @@ static int add_host_bridge_uport(struct device *match, void *arg)
 	if (!pci_root)
 		return -ENXIO;
 
-	/* TODO: fold in CEDT.CHBS retrieval */
-	port = devm_cxl_add_port(host, match, CXL_RESOURCE_NONE, root_port);
+	dport = find_dport_by_dev(root_port, match);
+	if (!dport) {
+		dev_dbg(host, "host bridge expected and not found\n");
+		return -ENODEV;
+	}
+
+	port = devm_cxl_add_port(host, match, dport->component_reg_phys,
+				 root_port);
 	if (IS_ERR(port))
 		return PTR_ERR(port);
 	dev_dbg(host, "%s: add: %s\n", dev_name(match), dev_name(&port->dev));
@@ -120,6 +194,7 @@ 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_port *root_port = arg;
 	struct device *host = root_port->dev.parent;
 	struct acpi_device *bridge = to_cxl_host_bridge(match);
@@ -135,7 +210,12 @@ static int add_host_bridge_dport(struct device *match, void *arg)
 		return -ENODEV;
 	}
 
-	rc = cxl_add_dport(root_port, match, uid, CXL_RESOURCE_NONE);
+	chbs = cxl_acpi_match_chbs(host, uid);
+	if (IS_ERR(chbs))
+		dev_dbg(host, "No CHBS found for Host Bridge: %s\n",
+			dev_name(match));
+
+	rc = cxl_add_dport(root_port, match, uid, get_chbcr(chbs));
 	if (rc) {
 		dev_err(host, "failed to add downstream port: %s\n",
 			dev_name(match));
@@ -172,6 +252,7 @@ static int add_root_nvdimm_bridge(struct device *match, void *data)
 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);
@@ -181,10 +262,14 @@ static int cxl_acpi_probe(struct platform_device *pdev)
 		return PTR_ERR(root_port);
 	dev_dbg(host, "add: %s\n", dev_name(&root_port->dev));
 
+	status = acpi_get_table(ACPI_SIG_CEDT, 0, &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)
-		return rc;
+		goto out;
 
 	/*
 	 * Root level scanned with host-bridge as dports, now scan host-bridges
@@ -193,11 +278,14 @@ 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)
-		return rc;
+		goto out;
 
 	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;
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v3 2/2] cxl/acpi: Use the ACPI CFMWS to create static decoder objects
  2021-06-17  1:11 [PATCH v3 0/2] CXL ACPI tables for object creation Alison Schofield
  2021-06-17  1:11 ` [PATCH v3 1/2] cxl/acpi: Add the Host Bridge base address to CXL port objects Alison Schofield
@ 2021-06-17  1:11 ` Alison Schofield
  2021-06-17  9:00   ` Jonathan Cameron
  2021-06-17 15:43   ` Ben Widawsky
  2021-06-17 15:41 ` [PATCH v3 0/2] CXL ACPI tables for object creation Ben Widawsky
  2 siblings, 2 replies; 7+ messages in thread
From: Alison Schofield @ 2021-06-17  1:11 UTC (permalink / raw)
  To: Ben Widawsky, Dan Williams, Ira Weiny, Alison Schofield,
	Vishal Verma, Jonathan Cameron
  Cc: linux-cxl, linux-kernel, linux-acpi

The ACPI CXL Early Discovery Table (CEDT) includes a list of CXL memory
resources in CXL Fixed Memory Window Structures (CFMWS). Retrieve each
CFMWS in the CEDT and add a cxl_decoder object to the root port (root0)
for each memory resource.

Signed-off-by: Alison Schofield <alison.schofield@intel.com>
---
 drivers/cxl/acpi.c | 119 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
index 852b5c270464..018f5ac73b78 100644
--- a/drivers/cxl/acpi.c
+++ b/drivers/cxl/acpi.c
@@ -10,6 +10,123 @@
 
 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)
+
+static unsigned long cfmws_to_decoder_flags(int restrictions)
+{
+	unsigned long flags = 0;
+
+	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_TYPE2)
+		flags |= CXL_DECODER_F_TYPE2;
+	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_TYPE3)
+		flags |= CXL_DECODER_F_TYPE3;
+	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_VOLATILE)
+		flags |= CXL_DECODER_F_RAM;
+	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_PMEM)
+		flags |= CXL_DECODER_F_PMEM;
+	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_FIXED)
+		flags |= CXL_DECODER_F_LOCK;
+
+	return flags;
+}
+
+static int cxl_acpi_cfmws_verify(struct device *dev,
+				 struct acpi_cedt_cfmws *cfmws)
+{
+	int expected_len;
+
+	if (cfmws->interleave_arithmetic != ACPI_CEDT_CFMWS_ARITHMETIC_MODULO) {
+		dev_err(dev, "CFMWS Unsupported Interleave Arithmetic\n");
+		return -EINVAL;
+	}
+
+	if (!IS_ALIGNED(cfmws->base_hpa, SZ_256M)) {
+		dev_err(dev, "CFMWS Base HPA not 256MB aligned\n");
+		return -EINVAL;
+	}
+
+	if (!IS_ALIGNED(cfmws->window_size, SZ_256M)) {
+		dev_err(dev, "CFMWS Window Size not 256MB aligned\n");
+		return -EINVAL;
+	}
+
+	expected_len = struct_size((cfmws), interleave_targets,
+				   CFMWS_INTERLEAVE_WAYS(cfmws));
+
+	if (cfmws->header.length < expected_len) {
+		dev_err(dev, "CFMWS length %d less than expected %d\n",
+			cfmws->header.length, expected_len);
+		return -EINVAL;
+	}
+
+	if (cfmws->header.length > expected_len)
+		dev_dbg(dev, "CFMWS length %d greater than expected %d\n",
+			cfmws->header.length, expected_len);
+
+	return 0;
+}
+
+static void cxl_add_cfmws_decoders(struct device *dev,
+				   struct cxl_port *root_port)
+{
+	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;
+
+		if (c->type != ACPI_CEDT_TYPE_CFMWS) {
+			cur += c->length;
+			continue;
+		}
+
+		cfmws = cedt_subtable + cur;
+
+		if (dev_WARN_ONCE(dev, cfmws->header.length < sizeof(*cfmws),
+				  "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;
+		}
+
+		cxld = devm_cxl_add_decoder(dev, root_port,
+				CFMWS_INTERLEAVE_WAYS(cfmws),
+				cfmws->base_hpa, cfmws->window_size,
+				CFMWS_INTERLEAVE_WAYS(cfmws),
+				CFMWS_INTERLEAVE_GRANULARITY(cfmws),
+				CXL_DECODER_EXPANDER,
+				cfmws_to_decoder_flags(cfmws->restrictions));
+
+		if (IS_ERR(cxld)) {
+			dev_err(dev, "Failed to add decoder for %#llx-%#llx\n",
+				cfmws->base_hpa, cfmws->base_hpa +
+				cfmws->window_size - 1);
+		} else {
+			dev_dbg(dev, "add: %s range %#llx-%#llx\n",
+				dev_name(&cxld->dev), cfmws->base_hpa,
+				 cfmws->base_hpa + cfmws->window_size - 1);
+		}
+		cur += c->length;
+	}
+}
+
 static struct acpi_cedt_chbs *cxl_acpi_match_chbs(struct device *dev, u32 uid)
 {
 	struct acpi_cedt_chbs *chbs, *chbs_match = NULL;
@@ -271,6 +388,8 @@ static int cxl_acpi_probe(struct platform_device *pdev)
 	if (rc)
 		goto out;
 
+	cxl_add_cfmws_decoders(host, root_port);
+
 	/*
 	 * Root level scanned with host-bridge as dports, now scan host-bridges
 	 * for their role as CXL uports to their CXL-capable PCIe Root Ports.
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v3 1/2] cxl/acpi: Add the Host Bridge base address to CXL port objects
  2021-06-17  1:11 ` [PATCH v3 1/2] cxl/acpi: Add the Host Bridge base address to CXL port objects Alison Schofield
@ 2021-06-17  8:57   ` Jonathan Cameron
  0 siblings, 0 replies; 7+ messages in thread
From: Jonathan Cameron @ 2021-06-17  8:57 UTC (permalink / raw)
  To: Alison Schofield
  Cc: Ben Widawsky, Dan Williams, Ira Weiny, Vishal Verma, linux-cxl,
	linux-kernel, linux-acpi

On Wed, 16 Jun 2021 18:11:07 -0700
Alison Schofield <alison.schofield@intel.com> wrote:

> The base address for the Host Bridge port component registers is located
> in the CXL Host Bridge Structure (CHBS) of the ACPI CXL Early Discovery
> Table (CEDT). Retrieve the CHBS for each Host Bridge (ACPI0016 device)
> and include that base address in the port object.
> 
> Co-developed-by: Vishal Verma <vishal.l.verma@intel.com>
> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
> Signed-off-by: Alison Schofield <alison.schofield@intel.com>

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

> ---
>  drivers/cxl/acpi.c | 98 +++++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 93 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
> index 8a723f7f3f73..852b5c270464 100644
> --- a/drivers/cxl/acpi.c
> +++ b/drivers/cxl/acpi.c
> @@ -8,6 +8,58 @@
>  #include <linux/pci.h>
>  #include "cxl.h"
>  
> +static struct acpi_table_header *acpi_cedt;
> +
> +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;
> +
> +	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 (dev_WARN_ONCE(dev, chbs->header.length < sizeof(*chbs),
> +				  "CHBS entry skipped: invalid length:%u\n",
> +				  chbs->header.length)) {
> +			cur += c->length;
> +			continue;
> +		}
> +
> +		if (chbs->uid != uid) {
> +			cur += c->length;
> +			continue;
> +		}
> +
> +		if (dev_WARN_ONCE(dev, chbs_match,
> +				  "CHBS entry skipped: duplicate UID:%u\n",
> +				  uid)) {
> +			cur += c->length;
> +			continue;
> +		}
> +
> +		chbs_match = chbs;
> +		cur += c->length;
> +	}
> +
> +	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;
> +}
> +
>  struct cxl_walk_context {
>  	struct device *dev;
>  	struct pci_bus *root;
> @@ -50,6 +102,21 @@ static int match_add_root_ports(struct pci_dev *pdev, void *data)
>  	return 0;
>  }
>  
> +static struct cxl_dport *find_dport_by_dev(struct cxl_port *port, struct device *dev)
> +{
> +	struct cxl_dport *dport;
> +
> +	device_lock(&port->dev);
> +	list_for_each_entry(dport, &port->dports, list)
> +		if (dport->dport == dev) {
> +			device_unlock(&port->dev);
> +			return dport;
> +		}
> +
> +	device_unlock(&port->dev);
> +	return NULL;
> +}
> +
>  static struct acpi_device *to_cxl_host_bridge(struct device *dev)
>  {
>  	struct acpi_device *adev = to_acpi_device(dev);
> @@ -71,6 +138,7 @@ static int add_host_bridge_uport(struct device *match, void *arg)
>  	struct acpi_pci_root *pci_root;
>  	struct cxl_walk_context ctx;
>  	struct cxl_decoder *cxld;
> +	struct cxl_dport *dport;
>  	struct cxl_port *port;
>  
>  	if (!bridge)
> @@ -80,8 +148,14 @@ static int add_host_bridge_uport(struct device *match, void *arg)
>  	if (!pci_root)
>  		return -ENXIO;
>  
> -	/* TODO: fold in CEDT.CHBS retrieval */
> -	port = devm_cxl_add_port(host, match, CXL_RESOURCE_NONE, root_port);
> +	dport = find_dport_by_dev(root_port, match);
> +	if (!dport) {
> +		dev_dbg(host, "host bridge expected and not found\n");
> +		return -ENODEV;
> +	}
> +
> +	port = devm_cxl_add_port(host, match, dport->component_reg_phys,
> +				 root_port);
>  	if (IS_ERR(port))
>  		return PTR_ERR(port);
>  	dev_dbg(host, "%s: add: %s\n", dev_name(match), dev_name(&port->dev));
> @@ -120,6 +194,7 @@ 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_port *root_port = arg;
>  	struct device *host = root_port->dev.parent;
>  	struct acpi_device *bridge = to_cxl_host_bridge(match);
> @@ -135,7 +210,12 @@ static int add_host_bridge_dport(struct device *match, void *arg)
>  		return -ENODEV;
>  	}
>  
> -	rc = cxl_add_dport(root_port, match, uid, CXL_RESOURCE_NONE);
> +	chbs = cxl_acpi_match_chbs(host, uid);
> +	if (IS_ERR(chbs))
> +		dev_dbg(host, "No CHBS found for Host Bridge: %s\n",
> +			dev_name(match));
> +
> +	rc = cxl_add_dport(root_port, match, uid, get_chbcr(chbs));
>  	if (rc) {
>  		dev_err(host, "failed to add downstream port: %s\n",
>  			dev_name(match));
> @@ -172,6 +252,7 @@ static int add_root_nvdimm_bridge(struct device *match, void *data)
>  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);
> @@ -181,10 +262,14 @@ static int cxl_acpi_probe(struct platform_device *pdev)
>  		return PTR_ERR(root_port);
>  	dev_dbg(host, "add: %s\n", dev_name(&root_port->dev));
>  
> +	status = acpi_get_table(ACPI_SIG_CEDT, 0, &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)
> -		return rc;
> +		goto out;
>  
>  	/*
>  	 * Root level scanned with host-bridge as dports, now scan host-bridges
> @@ -193,11 +278,14 @@ 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)
> -		return rc;
> +		goto out;
>  
>  	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;


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v3 2/2] cxl/acpi: Use the ACPI CFMWS to create static decoder objects
  2021-06-17  1:11 ` [PATCH v3 2/2] cxl/acpi: Use the ACPI CFMWS to create static decoder objects Alison Schofield
@ 2021-06-17  9:00   ` Jonathan Cameron
  2021-06-17 15:43   ` Ben Widawsky
  1 sibling, 0 replies; 7+ messages in thread
From: Jonathan Cameron @ 2021-06-17  9:00 UTC (permalink / raw)
  To: Alison Schofield
  Cc: Ben Widawsky, Dan Williams, Ira Weiny, Vishal Verma, linux-cxl,
	linux-kernel, linux-acpi

On Wed, 16 Jun 2021 18:11:08 -0700
Alison Schofield <alison.schofield@intel.com> wrote:

> The ACPI CXL Early Discovery Table (CEDT) includes a list of CXL memory
> resources in CXL Fixed Memory Window Structures (CFMWS). Retrieve each
> CFMWS in the CEDT and add a cxl_decoder object to the root port (root0)
> for each memory resource.
> 
> Signed-off-by: Alison Schofield <alison.schofield@intel.com>

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

> ---
>  drivers/cxl/acpi.c | 119 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 119 insertions(+)
> 
> diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
> index 852b5c270464..018f5ac73b78 100644
> --- a/drivers/cxl/acpi.c
> +++ b/drivers/cxl/acpi.c
> @@ -10,6 +10,123 @@
>  
>  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)
> +
> +static unsigned long cfmws_to_decoder_flags(int restrictions)
> +{
> +	unsigned long flags = 0;
> +
> +	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_TYPE2)
> +		flags |= CXL_DECODER_F_TYPE2;
> +	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_TYPE3)
> +		flags |= CXL_DECODER_F_TYPE3;
> +	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_VOLATILE)
> +		flags |= CXL_DECODER_F_RAM;
> +	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_PMEM)
> +		flags |= CXL_DECODER_F_PMEM;
> +	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_FIXED)
> +		flags |= CXL_DECODER_F_LOCK;
> +
> +	return flags;
> +}
> +
> +static int cxl_acpi_cfmws_verify(struct device *dev,
> +				 struct acpi_cedt_cfmws *cfmws)
> +{
> +	int expected_len;
> +
> +	if (cfmws->interleave_arithmetic != ACPI_CEDT_CFMWS_ARITHMETIC_MODULO) {
> +		dev_err(dev, "CFMWS Unsupported Interleave Arithmetic\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!IS_ALIGNED(cfmws->base_hpa, SZ_256M)) {
> +		dev_err(dev, "CFMWS Base HPA not 256MB aligned\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!IS_ALIGNED(cfmws->window_size, SZ_256M)) {
> +		dev_err(dev, "CFMWS Window Size not 256MB aligned\n");
> +		return -EINVAL;
> +	}
> +
> +	expected_len = struct_size((cfmws), interleave_targets,
> +				   CFMWS_INTERLEAVE_WAYS(cfmws));
> +
> +	if (cfmws->header.length < expected_len) {
> +		dev_err(dev, "CFMWS length %d less than expected %d\n",
> +			cfmws->header.length, expected_len);
> +		return -EINVAL;
> +	}
> +
> +	if (cfmws->header.length > expected_len)
> +		dev_dbg(dev, "CFMWS length %d greater than expected %d\n",
> +			cfmws->header.length, expected_len);
> +
> +	return 0;
> +}
> +
> +static void cxl_add_cfmws_decoders(struct device *dev,
> +				   struct cxl_port *root_port)
> +{
> +	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;
> +
> +		if (c->type != ACPI_CEDT_TYPE_CFMWS) {
> +			cur += c->length;
> +			continue;
> +		}
> +
> +		cfmws = cedt_subtable + cur;
> +
> +		if (dev_WARN_ONCE(dev, cfmws->header.length < sizeof(*cfmws),
> +				  "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;
> +		}
> +
> +		cxld = devm_cxl_add_decoder(dev, root_port,
> +				CFMWS_INTERLEAVE_WAYS(cfmws),
> +				cfmws->base_hpa, cfmws->window_size,
> +				CFMWS_INTERLEAVE_WAYS(cfmws),
> +				CFMWS_INTERLEAVE_GRANULARITY(cfmws),
> +				CXL_DECODER_EXPANDER,
> +				cfmws_to_decoder_flags(cfmws->restrictions));
> +
> +		if (IS_ERR(cxld)) {
> +			dev_err(dev, "Failed to add decoder for %#llx-%#llx\n",
> +				cfmws->base_hpa, cfmws->base_hpa +
> +				cfmws->window_size - 1);

This sounds rather fatal... I guess it'll be exposed later as we won't have
any means of using the decoder so we don't have to error out here though.

> +		} else {
> +			dev_dbg(dev, "add: %s range %#llx-%#llx\n",
> +				dev_name(&cxld->dev), cfmws->base_hpa,
> +				 cfmws->base_hpa + cfmws->window_size - 1);
> +		}
> +		cur += c->length;
> +	}
> +}
> +
>  static struct acpi_cedt_chbs *cxl_acpi_match_chbs(struct device *dev, u32 uid)
>  {
>  	struct acpi_cedt_chbs *chbs, *chbs_match = NULL;
> @@ -271,6 +388,8 @@ static int cxl_acpi_probe(struct platform_device *pdev)
>  	if (rc)
>  		goto out;
>  
> +	cxl_add_cfmws_decoders(host, root_port);
> +
>  	/*
>  	 * Root level scanned with host-bridge as dports, now scan host-bridges
>  	 * for their role as CXL uports to their CXL-capable PCIe Root Ports.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v3 0/2] CXL ACPI tables for object creation
  2021-06-17  1:11 [PATCH v3 0/2] CXL ACPI tables for object creation Alison Schofield
  2021-06-17  1:11 ` [PATCH v3 1/2] cxl/acpi: Add the Host Bridge base address to CXL port objects Alison Schofield
  2021-06-17  1:11 ` [PATCH v3 2/2] cxl/acpi: Use the ACPI CFMWS to create static decoder objects Alison Schofield
@ 2021-06-17 15:41 ` Ben Widawsky
  2 siblings, 0 replies; 7+ messages in thread
From: Ben Widawsky @ 2021-06-17 15:41 UTC (permalink / raw)
  To: Alison Schofield
  Cc: Dan Williams, Ira Weiny, Vishal Verma, Jonathan Cameron,
	linux-cxl, linux-kernel, linux-acpi

On 21-06-16 18:11:06, Alison Schofield wrote:
> Jonathan - I updated Patch 2 so I didn't keep your Reviewed-by tag.
> 
> Changes since v2 [1]:
> - Warn and continue, rather than error out, on these acpi table parsing issues:
>   table length mismatch for either CHBS or CFMWS; duplicate uid's for CHBS.
>   (Ben, Jonathan)
> - Update flow in cxl_acpi_match_chbs()  (Ben, Jonathan)
> - Improve naming cedt_table->acpi_cedt, cedt_base->cedt_subtable (Ben)
> - Emit debug message only if CFMWS is greater than its expected length (Ben)
> - Update the dev_err messages wrt the CFMWS expected length failure.
> - Remove blank line before error handling block (Jonathan)
> - Rebase to the CXL pending branch [2]
> 
> [1]: https://lore.kernel.org/linux-cxl/cover.1623800340.git.alison.schofield@intel.com/ 
> [2]: https://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl.git/log/?h=pending
> 
> --
> Parse the ACPI CXL Early Discovery Table (CEDT) and use the CHBS & CFMWS
> when creating port and decoder objects.
> 
> CHBS: CXL Host Bridge Structure - Patch 1
> CFMWS: CXL Fixed Memory Window Structure - Patch 2
> 
> Alison Schofield (2):
>   cxl/acpi: Add the Host Bridge base address to CXL port objects
>   cxl/acpi: Use the ACPI CFMWS to create static decoder objects
> 
>  drivers/cxl/acpi.c | 217 +++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 212 insertions(+), 5 deletions(-)
> 
> 
> base-commit: 21083f51521fb0f60dbac591f175c3ed48435af4

It might be nice to add a header kdoc for acpi.c now that it's become sufficiently
complex. Can be follow-on patch.

Both are:
Reviewed-by: Ben Widawsky <ben.widawsky@intel.com>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v3 2/2] cxl/acpi: Use the ACPI CFMWS to create static decoder objects
  2021-06-17  1:11 ` [PATCH v3 2/2] cxl/acpi: Use the ACPI CFMWS to create static decoder objects Alison Schofield
  2021-06-17  9:00   ` Jonathan Cameron
@ 2021-06-17 15:43   ` Ben Widawsky
  1 sibling, 0 replies; 7+ messages in thread
From: Ben Widawsky @ 2021-06-17 15:43 UTC (permalink / raw)
  To: Alison Schofield
  Cc: Dan Williams, Ira Weiny, Vishal Verma, Jonathan Cameron,
	linux-cxl, linux-kernel, linux-acpi

On 21-06-16 18:11:08, Alison Schofield wrote:
> The ACPI CXL Early Discovery Table (CEDT) includes a list of CXL memory
> resources in CXL Fixed Memory Window Structures (CFMWS). Retrieve each
> CFMWS in the CEDT and add a cxl_decoder object to the root port (root0)
> for each memory resource.
> 
> Signed-off-by: Alison Schofield <alison.schofield@intel.com>
> ---
>  drivers/cxl/acpi.c | 119 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 119 insertions(+)
> 
> diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
> index 852b5c270464..018f5ac73b78 100644
> --- a/drivers/cxl/acpi.c
> +++ b/drivers/cxl/acpi.c
> @@ -10,6 +10,123 @@
>  
>  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)
> +
> +static unsigned long cfmws_to_decoder_flags(int restrictions)
> +{
> +	unsigned long flags = 0;
> +
> +	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_TYPE2)
> +		flags |= CXL_DECODER_F_TYPE2;
> +	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_TYPE3)
> +		flags |= CXL_DECODER_F_TYPE3;
> +	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_VOLATILE)
> +		flags |= CXL_DECODER_F_RAM;
> +	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_PMEM)
> +		flags |= CXL_DECODER_F_PMEM;
> +	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_FIXED)
> +		flags |= CXL_DECODER_F_LOCK;
> +
> +	return flags;
> +}
> +
> +static int cxl_acpi_cfmws_verify(struct device *dev,
> +				 struct acpi_cedt_cfmws *cfmws)
> +{
> +	int expected_len;
> +
> +	if (cfmws->interleave_arithmetic != ACPI_CEDT_CFMWS_ARITHMETIC_MODULO) {
> +		dev_err(dev, "CFMWS Unsupported Interleave Arithmetic\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!IS_ALIGNED(cfmws->base_hpa, SZ_256M)) {
> +		dev_err(dev, "CFMWS Base HPA not 256MB aligned\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!IS_ALIGNED(cfmws->window_size, SZ_256M)) {
> +		dev_err(dev, "CFMWS Window Size not 256MB aligned\n");
> +		return -EINVAL;
> +	}
> +
> +	expected_len = struct_size((cfmws), interleave_targets,
> +				   CFMWS_INTERLEAVE_WAYS(cfmws));
> +
> +	if (cfmws->header.length < expected_len) {
> +		dev_err(dev, "CFMWS length %d less than expected %d\n",
> +			cfmws->header.length, expected_len);
> +		return -EINVAL;
> +	}
> +
> +	if (cfmws->header.length > expected_len)
> +		dev_dbg(dev, "CFMWS length %d greater than expected %d\n",
> +			cfmws->header.length, expected_len);
> +
> +	return 0;
> +}
> +
> +static void cxl_add_cfmws_decoders(struct device *dev,
> +				   struct cxl_port *root_port)
> +{
> +	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;
> +
> +		if (c->type != ACPI_CEDT_TYPE_CFMWS) {
> +			cur += c->length;
> +			continue;
> +		}
> +
> +		cfmws = cedt_subtable + cur;
> +
> +		if (dev_WARN_ONCE(dev, cfmws->header.length < sizeof(*cfmws),
> +				  "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;
> +		}
> +
> +		cxld = devm_cxl_add_decoder(dev, root_port,
> +				CFMWS_INTERLEAVE_WAYS(cfmws),
> +				cfmws->base_hpa, cfmws->window_size,
> +				CFMWS_INTERLEAVE_WAYS(cfmws),
> +				CFMWS_INTERLEAVE_GRANULARITY(cfmws),
> +				CXL_DECODER_EXPANDER,
> +				cfmws_to_decoder_flags(cfmws->restrictions));

checkpatch complains here for me.

CHECK: Alignment should match open parenthesis
#122: FILE: drivers/cxl/acpi.c:110:
+		cxld = devm_cxl_add_decoder(dev, root_port,
+				CFMWS_INTERLEAVE_WAYS(cfmws),


> +
> +		if (IS_ERR(cxld)) {
> +			dev_err(dev, "Failed to add decoder for %#llx-%#llx\n",
> +				cfmws->base_hpa, cfmws->base_hpa +
> +				cfmws->window_size - 1);
> +		} else {
> +			dev_dbg(dev, "add: %s range %#llx-%#llx\n",
> +				dev_name(&cxld->dev), cfmws->base_hpa,
> +				 cfmws->base_hpa + cfmws->window_size - 1);
> +		}
> +		cur += c->length;
> +	}
> +}
> +
>  static struct acpi_cedt_chbs *cxl_acpi_match_chbs(struct device *dev, u32 uid)
>  {
>  	struct acpi_cedt_chbs *chbs, *chbs_match = NULL;
> @@ -271,6 +388,8 @@ static int cxl_acpi_probe(struct platform_device *pdev)
>  	if (rc)
>  		goto out;
>  
> +	cxl_add_cfmws_decoders(host, root_port);
> +
>  	/*
>  	 * Root level scanned with host-bridge as dports, now scan host-bridges
>  	 * for their role as CXL uports to their CXL-capable PCIe Root Ports.
> -- 
> 2.26.2
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-06-17 15:45 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-17  1:11 [PATCH v3 0/2] CXL ACPI tables for object creation Alison Schofield
2021-06-17  1:11 ` [PATCH v3 1/2] cxl/acpi: Add the Host Bridge base address to CXL port objects Alison Schofield
2021-06-17  8:57   ` Jonathan Cameron
2021-06-17  1:11 ` [PATCH v3 2/2] cxl/acpi: Use the ACPI CFMWS to create static decoder objects Alison Schofield
2021-06-17  9:00   ` Jonathan Cameron
2021-06-17 15:43   ` Ben Widawsky
2021-06-17 15:41 ` [PATCH v3 0/2] CXL ACPI tables for object creation Ben Widawsky

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).