Skip to content

Commit 52cc48a

Browse files
committed
cxl/hdm: Limit emulation to the number of range registers
Recall that range register emulation seeks to treat the 2 potential range registers as Linux CXL "decoder" objects. The number of range registers can be 1 or 2, while HDM decoder ranges can include more than 2. Be careful not to confuse DVSEC range count with HDM capability decoder count. Commit to range register earlier in devm_cxl_setup_hdm(). Otherwise, a device with more HDM decoders than range registers can set @cxlhdm->decoder_count to an invalid value. Avoid introducing a forward declaration by just moving the definition of should_emulate_decoders() earlier in the file. should_emulate_decoders() is unchanged. Tested-by: Dave Jiang <dave.jiang@intel.com> Fixes: d7a2153 ("cxl/hdm: Add emulation when HDM decoders are not committed") Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Reviewed-by: Dave Jiang <dave.jiang@intel.com> Link: https://lore.kernel.org/r/168012574932.221280.15944705098679646436.stgit@dwillia2-xfh.jf.intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent 9ff3eec commit 52cc48a

File tree

1 file changed

+46
-36
lines changed

1 file changed

+46
-36
lines changed

drivers/cxl/core/hdm.c

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,42 @@ static int map_hdm_decoder_regs(struct cxl_port *port, void __iomem *crb,
101101
BIT(CXL_CM_CAP_CAP_ID_HDM));
102102
}
103103

104+
static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info)
105+
{
106+
struct cxl_hdm *cxlhdm;
107+
void __iomem *hdm;
108+
u32 ctrl;
109+
int i;
110+
111+
if (!info)
112+
return false;
113+
114+
cxlhdm = dev_get_drvdata(&info->port->dev);
115+
hdm = cxlhdm->regs.hdm_decoder;
116+
117+
if (!hdm)
118+
return true;
119+
120+
/*
121+
* If HDM decoders are present and the driver is in control of
122+
* Mem_Enable skip DVSEC based emulation
123+
*/
124+
if (!info->mem_enabled)
125+
return false;
126+
127+
/*
128+
* If any decoders are committed already, there should not be any
129+
* emulated DVSEC decoders.
130+
*/
131+
for (i = 0; i < cxlhdm->decoder_count; i++) {
132+
ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i));
133+
if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl))
134+
return false;
135+
}
136+
137+
return true;
138+
}
139+
104140
/**
105141
* devm_cxl_setup_hdm - map HDM decoder component registers
106142
* @port: cxl_port to map
@@ -140,6 +176,16 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
140176
return ERR_PTR(-ENXIO);
141177
}
142178

179+
/*
180+
* Now that the hdm capability is parsed, decide if range
181+
* register emulation is needed and fixup cxlhdm accordingly.
182+
*/
183+
if (should_emulate_decoders(info)) {
184+
dev_dbg(dev, "Fallback map %d range register%s\n", info->ranges,
185+
info->ranges > 1 ? "s" : "");
186+
cxlhdm->decoder_count = info->ranges;
187+
}
188+
143189
return cxlhdm;
144190
}
145191
EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_hdm, CXL);
@@ -717,42 +763,6 @@ static int cxl_setup_hdm_decoder_from_dvsec(struct cxl_port *port,
717763
return 0;
718764
}
719765

720-
static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info)
721-
{
722-
struct cxl_hdm *cxlhdm;
723-
void __iomem *hdm;
724-
u32 ctrl;
725-
int i;
726-
727-
if (!info)
728-
return false;
729-
730-
cxlhdm = dev_get_drvdata(&info->port->dev);
731-
hdm = cxlhdm->regs.hdm_decoder;
732-
733-
if (!hdm)
734-
return true;
735-
736-
/*
737-
* If HDM decoders are present and the driver is in control of
738-
* Mem_Enable skip DVSEC based emulation
739-
*/
740-
if (!info->mem_enabled)
741-
return false;
742-
743-
/*
744-
* If any decoders are committed already, there should not be any
745-
* emulated DVSEC decoders.
746-
*/
747-
for (i = 0; i < cxlhdm->decoder_count; i++) {
748-
ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i));
749-
if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl))
750-
return false;
751-
}
752-
753-
return true;
754-
}
755-
756766
static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
757767
int *target_map, void __iomem *hdm, int which,
758768
u64 *dpa_base, struct cxl_endpoint_dvsec_info *info)

0 commit comments

Comments
 (0)