[PATCH v7 3/8] cxl/hdm: Add BI coherency support for endpoint decoders
Davidlohr Bueso <[email protected]> Tue, 28 Jul 2026 07:41:31 -0700
| Newsgroups | org.kernel.vger.linux-cxl |
|---|---|
| Message-ID | <[email protected]> |
Cache the HDM decoder's Supported Coherency Models on struct cxl_hdm. Region attach consults this to verify the HDM supports the region's coherency type. For uncommitted endpoint decoders, init_hdm_decoder() defaults target_type from supported_coherency: Type 3 devices default to HDM-DB when the HDM is device-coherent-only, HDM-H otherwise. Pre-committed decoders with the BI bit set are not supported because endpoint and port enumerations are independent -- at decoder enumeration cxlds->bi is not yet known, so the topology cannot be verified. Reviewed-by: Dave Jiang <[email protected]> Signed-off-by: Davidlohr Bueso <[email protected]> --- drivers/cxl/core/core.h | 1 + drivers/cxl/core/hdm.c | 35 ++++++++++++++++++++++++----------- drivers/cxl/cxl.h | 8 +++++++- drivers/cxl/cxlmem.h | 2 ++ 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index e36b55fd63bd..b7757de83012 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -215,6 +215,7 @@ struct cxl_hdm; int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm, struct cxl_endpoint_dvsec_info *info); int cxl_port_get_possible_dports(struct cxl_port *port); +enum cxl_decoder_type cxled_default_type(struct cxl_endpoint_decoder *cxled); #ifdef CONFIG_CXL_FEATURES struct cxl_feat_entry * diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index 0c80b76a5f9b..9da8aa211609 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -87,6 +87,8 @@ static void parse_hdm_decoder_caps(struct cxl_hdm *cxlhdm) cxlhdm->iw_cap_mask |= BIT(3) | BIT(6) | BIT(12); if (FIELD_GET(CXL_HDM_DECODER_INTERLEAVE_16_WAY, hdm_cap)) cxlhdm->iw_cap_mask |= BIT(16); + cxlhdm->supported_coherency = + FIELD_GET(CXL_HDM_DECODER_SUPPORTED_COHERENCY_MASK, hdm_cap); } static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info) @@ -968,6 +970,19 @@ static int cxl_setup_hdm_decoder_from_dvsec( return 0; } +enum cxl_decoder_type cxled_default_type(struct cxl_endpoint_decoder *cxled) +{ + struct cxl_dev_state *cxlds = cxled_to_memdev(cxled)->cxlds; + struct cxl_port *port = cxled_to_port(cxled); + struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev); + + if (cxlds->type == CXL_DEVTYPE_CLASSMEM && + cxlhdm->supported_coherency != CXL_HDM_DECODER_COHERENCY_DEV) + return CXL_DECODER_HOSTONLYMEM; + + return CXL_DECODER_DEVMEM; +} + static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, void __iomem *hdm, int which, u64 *dpa_base, struct cxl_endpoint_dvsec_info *info) @@ -1023,6 +1038,14 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, else cxld->target_type = CXL_DECODER_DEVMEM; + /* + * Autocommit BI-enabled decoders is not supported. + * At this point cxlds->bi is not yet setup, so there + * are no guarantees that the platform supports BI. + */ + if (FIELD_GET(CXL_HDM_DECODER0_CTRL_BI, ctrl)) + return -ENXIO; + guard(rwsem_write)(&cxl_rwsem.region); if (cxld->id != cxl_num_decoders_committed(port)) { dev_warn(&port->dev, @@ -1040,17 +1063,7 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, port->commit_end = cxld->id; } else { if (cxled) { - struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); - struct cxl_dev_state *cxlds = cxlmd->cxlds; - - /* - * Default by devtype until a device arrives that needs - * more precision. - */ - if (cxlds->type == CXL_DEVTYPE_CLASSMEM) - cxld->target_type = CXL_DECODER_HOSTONLYMEM; - else - cxld->target_type = CXL_DECODER_DEVMEM; + cxld->target_type = cxled_default_type(cxled); } else { /* To be overridden by region type at commit time */ cxld->target_type = CXL_DECODER_HOSTONLYMEM; diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index d00b8b7b778a..c323c38d0da2 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -50,7 +50,7 @@ extern const struct nvdimm_security_ops *cxl_security_ops; #define CXL_BI_RT_CAPABILITY_LENGTH 0xC #define CXL_BI_DECODER_CAPABILITY_LENGTH 0xC -/* HDM decoders CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure */ +/* HDM decoders CXL 4.0 8.2.4.20 CXL HDM Decoder Capability Structure */ #define CXL_HDM_DECODER_CAP_OFFSET 0x0 #define CXL_HDM_DECODER_COUNT_MASK GENMASK(3, 0) #define CXL_HDM_DECODER_TARGET_COUNT_MASK GENMASK(7, 4) @@ -58,6 +58,11 @@ extern const struct nvdimm_security_ops *cxl_security_ops; #define CXL_HDM_DECODER_INTERLEAVE_14_12 BIT(9) #define CXL_HDM_DECODER_INTERLEAVE_3_6_12_WAY BIT(11) #define CXL_HDM_DECODER_INTERLEAVE_16_WAY BIT(12) +#define CXL_HDM_DECODER_SUPPORTED_COHERENCY_MASK GENMASK(22, 21) +#define CXL_HDM_DECODER_COHERENCY_UNKNOWN 0x0 +#define CXL_HDM_DECODER_COHERENCY_DEV 0x1 +#define CXL_HDM_DECODER_COHERENCY_HOST 0x2 +#define CXL_HDM_DECODER_COHERENCY_BOTH 0x3 #define CXL_HDM_DECODER_CTRL_OFFSET 0x4 #define CXL_HDM_DECODER_ENABLE BIT(1) #define CXL_HDM_DECODER0_BASE_LOW_OFFSET(i) (0x20 * (i) + 0x10) @@ -72,6 +77,7 @@ extern const struct nvdimm_security_ops *cxl_security_ops; #define CXL_HDM_DECODER0_CTRL_COMMITTED BIT(10) #define CXL_HDM_DECODER0_CTRL_COMMIT_ERROR BIT(11) #define CXL_HDM_DECODER0_CTRL_HOSTONLY BIT(12) +#define CXL_HDM_DECODER0_CTRL_BI BIT(13) #define CXL_HDM_DECODER0_TL_LOW(i) (0x20 * (i) + 0x24) #define CXL_HDM_DECODER0_TL_HIGH(i) (0x20 * (i) + 0x28) #define CXL_HDM_DECODER0_SKIP_LOW(i) CXL_HDM_DECODER0_TL_LOW(i) diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index ed419d0c59f2..344424684cd6 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -859,6 +859,7 @@ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd); * @target_count: for switch decoders, max downstream port targets * @interleave_mask: interleave granularity capability, see check_interleave_cap() * @iw_cap_mask: bitmask of supported interleave ways, see check_interleave_cap() + * @supported_coherency: HDM Decoder Capability supported coherency models * @port: mapped cxl_port, see devm_cxl_setup_hdm() */ struct cxl_hdm { @@ -867,6 +868,7 @@ struct cxl_hdm { unsigned int target_count; unsigned int interleave_mask; unsigned long iw_cap_mask; + unsigned int supported_coherency; struct cxl_port *port; }; -- 2.39.5