diff mbox series

[v2,1/3] cxl: Add check for result of interleave ways plus granularity combo

Message ID 166026221529.1454405.7141583168966440657.stgit@djiang5-desk4.jf.intel.com
State Superseded
Headers show
Series Add sanity check for interleave setup | expand

Commit Message

Dave Jiang Aug. 11, 2022, 11:56 p.m. UTC
Add a helper function to check the combination of interleave ways and
interleave granularity together is sane against the interleave mask from
the HDM decoder. Add the check to cxl_region_attach() to make sure the
region config is sane. Add the check to cxl_port_setup_targets() to make
sure the port setup config is also sane.

Calculation refers to CXL spec v3 8.2.4.19.13 implementation note #3.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
 drivers/cxl/core/region.c |   11 ++++++++++-
 drivers/cxl/cxlmem.h      |   37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 1 deletion(-)

Comments

Dan Williams Aug. 12, 2022, 12:59 a.m. UTC | #1
Dave Jiang wrote:
> Add a helper function to check the combination of interleave ways and
> interleave granularity together is sane against the interleave mask from
> the HDM decoder. Add the check to cxl_region_attach() to make sure the
> region config is sane. Add the check to cxl_port_setup_targets() to make
> sure the port setup config is also sane.
> 
> Calculation refers to CXL spec v3 8.2.4.19.13 implementation note #3.
> 
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> ---
>  drivers/cxl/core/region.c |   11 ++++++++++-
>  drivers/cxl/cxlmem.h      |   37 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 47 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
> index cf5d5811fe4c..6f77ad22d47d 100644
> --- a/drivers/cxl/core/region.c
> +++ b/drivers/cxl/core/region.c
> @@ -1081,6 +1081,10 @@ static int cxl_port_setup_targets(struct cxl_port *port,
>  		return rc;
>  	}
>  
> +	rc = cxl_interleave_capable(port, &cxlr->dev, iw, ig);
> +	if (rc)
> +		return rc;
> +
>  	cxld->interleave_ways = iw;
>  	cxld->interleave_granularity = ig;
>  	dev_dbg(&cxlr->dev, "%s:%s iw: %d ig: %d\n", dev_name(port->uport),
> @@ -1218,6 +1222,12 @@ static int cxl_region_attach(struct cxl_region *cxlr,
>  		return -EBUSY;
>  	}
>  
> +	ep_port = cxled_to_port(cxled);
> +	rc = cxl_interleave_capable(ep_port, &cxlr->dev, p->interleave_ways,
> +				    p->interleave_granularity);
> +	if (rc)
> +		return rc;
> +
>  	for (i = 0; i < p->interleave_ways; i++) {
>  		struct cxl_endpoint_decoder *cxled_target;
>  		struct cxl_memdev *cxlmd_target;
> @@ -1236,7 +1246,6 @@ static int cxl_region_attach(struct cxl_region *cxlr,
>  		}
>  	}
>  
> -	ep_port = cxled_to_port(cxled);
>  	root_port = cxlrd_to_port(cxlrd);
>  	dport = cxl_find_dport_by_dev(root_port, ep_port->host_bridge);
>  	if (!dport) {
> diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
> index 88e3a8e54b6a..625fce0b6c2c 100644
> --- a/drivers/cxl/cxlmem.h
> +++ b/drivers/cxl/cxlmem.h
> @@ -401,6 +401,43 @@ struct cxl_hdm {
>  	struct cxl_port *port;
>  };
>  
> +static inline int cxl_interleave_capable(struct cxl_port *port,
> +					 struct device *dev,
> +					 int ways, int granularity)
> +{
> +	struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev);
> +	unsigned int addr_mask;
> +	u16 eig;
> +	u8 eiw;
> +	int rc;
> +
> +	rc = granularity_to_cxl(granularity, &eig);
> +	if (rc)
> +		return rc;
> +
> +	rc = ways_to_cxl(ways, &eiw);
> +	if (rc)
> +		return rc;
> +
> +	if (eiw == 0)
> +		return 0;
> +
> +	if (is_power_of_2(eiw))
> +		addr_mask = GENMASK(eig + 8 + eiw - 1, eig + 8);
> +	else
> +		addr_mask = GENMASK((eig + eiw) / 3 - 1, eig + 8);
> +
> +	if (~cxlhdm->interleave_mask & addr_mask) {
> +		dev_warn(dev,
> +			 "%s:%s interleave (eig: %d eiw: %d mask: %#x) exceed cap (mask: %#x)\n",
> +			 dev_name(port->uport), dev_name(&port->dev), eig, eiw,
> +			 cxlhdm->interleave_mask, addr_mask);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}

Looks good, just this function is too big to be a static inline. It's
also not used outside of core/region.c, so it can just be private to
core/region.c.

Other than that you can add:

Reviewed-by: Dan Williams <dan.j.williams@intel.com>
diff mbox series

Patch

diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index cf5d5811fe4c..6f77ad22d47d 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -1081,6 +1081,10 @@  static int cxl_port_setup_targets(struct cxl_port *port,
 		return rc;
 	}
 
+	rc = cxl_interleave_capable(port, &cxlr->dev, iw, ig);
+	if (rc)
+		return rc;
+
 	cxld->interleave_ways = iw;
 	cxld->interleave_granularity = ig;
 	dev_dbg(&cxlr->dev, "%s:%s iw: %d ig: %d\n", dev_name(port->uport),
@@ -1218,6 +1222,12 @@  static int cxl_region_attach(struct cxl_region *cxlr,
 		return -EBUSY;
 	}
 
+	ep_port = cxled_to_port(cxled);
+	rc = cxl_interleave_capable(ep_port, &cxlr->dev, p->interleave_ways,
+				    p->interleave_granularity);
+	if (rc)
+		return rc;
+
 	for (i = 0; i < p->interleave_ways; i++) {
 		struct cxl_endpoint_decoder *cxled_target;
 		struct cxl_memdev *cxlmd_target;
@@ -1236,7 +1246,6 @@  static int cxl_region_attach(struct cxl_region *cxlr,
 		}
 	}
 
-	ep_port = cxled_to_port(cxled);
 	root_port = cxlrd_to_port(cxlrd);
 	dport = cxl_find_dport_by_dev(root_port, ep_port->host_bridge);
 	if (!dport) {
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index 88e3a8e54b6a..625fce0b6c2c 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -401,6 +401,43 @@  struct cxl_hdm {
 	struct cxl_port *port;
 };
 
+static inline int cxl_interleave_capable(struct cxl_port *port,
+					 struct device *dev,
+					 int ways, int granularity)
+{
+	struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev);
+	unsigned int addr_mask;
+	u16 eig;
+	u8 eiw;
+	int rc;
+
+	rc = granularity_to_cxl(granularity, &eig);
+	if (rc)
+		return rc;
+
+	rc = ways_to_cxl(ways, &eiw);
+	if (rc)
+		return rc;
+
+	if (eiw == 0)
+		return 0;
+
+	if (is_power_of_2(eiw))
+		addr_mask = GENMASK(eig + 8 + eiw - 1, eig + 8);
+	else
+		addr_mask = GENMASK((eig + eiw) / 3 - 1, eig + 8);
+
+	if (~cxlhdm->interleave_mask & addr_mask) {
+		dev_warn(dev,
+			 "%s:%s interleave (eig: %d eiw: %d mask: %#x) exceed cap (mask: %#x)\n",
+			 dev_name(port->uport), dev_name(&port->dev), eig, eiw,
+			 cxlhdm->interleave_mask, addr_mask);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 struct seq_file;
 struct dentry *cxl_debugfs_create_dir(const char *dir);
 void cxl_dpa_debug(struct seq_file *file, struct cxl_dev_state *cxlds);