diff mbox series

[RFC,5/8] cxl: create emulated cxl_hdm for devices that do not have HDM decoders

Message ID 166984996390.2805382.1358232383903012041.stgit@djiang5-desk3.ch.intel.com
State Superseded
Headers show
Series cxl: Introduce HDM decoder emulation from DVSEC range registers | expand

Commit Message

Dave Jiang Nov. 30, 2022, 11:12 p.m. UTC
CXL rev3 spec 8.1.3
RCDs may not have HDM register blocks. Create a fake HDM with information
from the CXL PCIe DVSEC registers. The decoder count will be set to the
HDM count retrieved from the DVSEC cap register.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
 drivers/cxl/core/hdm.c |   27 ++++++++++++++++++++++++++-
 drivers/cxl/core/pci.c |    9 ++++++---
 drivers/cxl/cxl.h      |    3 ++-
 drivers/cxl/cxlmem.h   |    1 +
 drivers/cxl/port.c     |    2 +-
 5 files changed, 36 insertions(+), 6 deletions(-)

Comments

Jonathan Cameron Dec. 19, 2022, 4:52 p.m. UTC | #1
On Wed, 30 Nov 2022 16:12:43 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> CXL rev3 spec 8.1.3
> RCDs may not have HDM register blocks. Create a fake HDM with information
> from the CXL PCIe DVSEC registers. The decoder count will be set to the
> HDM count retrieved from the DVSEC cap register.
> 
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
One comment inline that probably doesn't matter about setting
the target_count = 1.
If you need it to be 0 (which isn't normally a valid option) then
perhaps a comment on why.

> ---
>  drivers/cxl/core/hdm.c |   27 ++++++++++++++++++++++++++-
>  drivers/cxl/core/pci.c |    9 ++++++---
>  drivers/cxl/cxl.h      |    3 ++-
>  drivers/cxl/cxlmem.h   |    1 +
>  drivers/cxl/port.c     |    2 +-
>  5 files changed, 36 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
> index 9773a5efaefd..3a9e9b854587 100644
> --- a/drivers/cxl/core/hdm.c
> +++ b/drivers/cxl/core/hdm.c
> @@ -96,11 +96,31 @@ static void __iomem *map_hdm_decoder_regs(struct cxl_port *port,
>  	return crb + map.hdm_decoder.offset;
>  }
>  
> +static struct cxl_hdm *devm_cxl_setup_emulated_hdm(struct cxl_port *port,
> +						   struct cxl_endpoint_dvsec_info *info)
> +{
> +	struct device *dev = &port->dev;
> +	struct cxl_hdm *cxlhdm;
> +
> +	if (!info->mem_enabled)
> +		return ERR_PTR(-ENODEV);
> +
> +	cxlhdm = devm_kzalloc(dev, sizeof(*cxlhdm), GFP_KERNEL);
> +	if (!cxlhdm)
> +		return ERR_PTR(-ENOMEM);
> +
> +	cxlhdm->port = port;
> +	cxlhdm->decoder_count = info->ranges;

Whilst I assume target_count isn't used, perhaps better to set it here
for consistency as 0 isn't a valid value for the HDM decoder related field.


> +	dev_set_drvdata(&port->dev, cxlhdm);

blank line here preferred.

> +	return cxlhdm;
> +}
> +
diff mbox series

Patch

diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
index 9773a5efaefd..3a9e9b854587 100644
--- a/drivers/cxl/core/hdm.c
+++ b/drivers/cxl/core/hdm.c
@@ -96,11 +96,31 @@  static void __iomem *map_hdm_decoder_regs(struct cxl_port *port,
 	return crb + map.hdm_decoder.offset;
 }
 
+static struct cxl_hdm *devm_cxl_setup_emulated_hdm(struct cxl_port *port,
+						   struct cxl_endpoint_dvsec_info *info)
+{
+	struct device *dev = &port->dev;
+	struct cxl_hdm *cxlhdm;
+
+	if (!info->mem_enabled)
+		return ERR_PTR(-ENODEV);
+
+	cxlhdm = devm_kzalloc(dev, sizeof(*cxlhdm), GFP_KERNEL);
+	if (!cxlhdm)
+		return ERR_PTR(-ENOMEM);
+
+	cxlhdm->port = port;
+	cxlhdm->decoder_count = info->ranges;
+	dev_set_drvdata(&port->dev, cxlhdm);
+	return cxlhdm;
+}
+
 /**
  * devm_cxl_setup_hdm - map HDM decoder component registers
  * @port: cxl_port to map
  */
-struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port)
+struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
+				   struct cxl_endpoint_dvsec_info *info)
 {
 	struct device *dev = &port->dev;
 	void __iomem *crb, *hdm;
@@ -111,9 +131,14 @@  struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port)
 		return ERR_PTR(-ENOMEM);
 
 	cxlhdm->port = port;
+	if (port->parent_dport->rch)
+		cxlhdm->rcd = true;
 	crb = devm_cxl_iomap_block(dev, port->component_reg_phys,
 				   CXL_COMPONENT_REG_BLOCK_SIZE);
 	if (!crb) {
+		if (info->mem_enabled)
+			return devm_cxl_setup_emulated_hdm(port, info);
+
 		dev_err(dev, "No component registers mapped\n");
 		return ERR_PTR(-ENXIO);
 	}
diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 5e44fe23fa76..009c11b43303 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -374,16 +374,19 @@  int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
 	struct cxl_port *port = cxlhdm->port;
 	struct cxl_port *root;
 	int i, rc, allowed;
-	u32 global_ctrl;
+	u32 global_ctrl = 0;
 
-	global_ctrl = readl(hdm + CXL_HDM_DECODER_CTRL_OFFSET);
+	if (hdm)
+		global_ctrl = readl(hdm + CXL_HDM_DECODER_CTRL_OFFSET);
 
 	/*
 	 * If the HDM Decoder Capability is already enabled then assume
 	 * that some other agent like platform firmware set it up.
 	 */
-	if (global_ctrl & CXL_HDM_DECODER_ENABLE)
+	if (global_ctrl & CXL_HDM_DECODER_ENABLE || (!hdm && info->mem_enabled))
 		return devm_cxl_enable_mem(&port->dev, cxlds);
+	else if (!hdm)
+		return -ENODEV;
 
 	root = to_cxl_port(port->dev.parent);
 	while (!is_cxl_root(root) && is_cxl_port(root->dev.parent))
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 3fe1043a7796..b2eea921bd5f 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -604,7 +604,8 @@  struct cxl_endpoint_dvsec_info {
 };
 
 struct cxl_hdm;
-struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port);
+struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
+				   struct cxl_endpoint_dvsec_info *info);
 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);
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index fd8ed573fbf9..6d477590559c 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -402,6 +402,7 @@  struct cxl_hdm {
 	unsigned int target_count;
 	unsigned int interleave_mask;
 	struct cxl_port *port;
+	bool rcd;
 };
 
 struct seq_file;
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index 3dedf3dd534a..910ebfc19a45 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -55,7 +55,7 @@  static int cxl_port_probe(struct device *dev)
 			return rc;
 	}
 
-	cxlhdm = devm_cxl_setup_hdm(port);
+	cxlhdm = devm_cxl_setup_hdm(port, &info);
 	if (IS_ERR(cxlhdm))
 		return PTR_ERR(cxlhdm);