Skip to content

Commit eb0764b

Browse files
committed
cxl/port: Enable the HDM decoder capability for switch ports
Derick noticed, when testing hot plug, that hot-add behaves nominally after a removal. However, if the hot-add is done without a prior removal, CXL.mem accesses fail. It turns out that the original implementation of the port driver and region programming wrongly assumed that platform-firmware always enables the host-bridge HDM decoder capability. Add support turning on switch-level HDM decoders in the case where platform-firmware has not. The implementation is careful to only arrange for the enable to be undone if the current instance of the driver was the one that did the enable. This is to interoperate with platform-firmware that may expect CXL.mem to remain active after the driver is shutdown. This comes at the cost of potentially not shutting down the enable on kexec flows, but it is mitigated by the fact that the related HDM decoders still need to be enabled on an individual basis. Cc: <stable@vger.kernel.org> Reported-by: Derick Marks <derick.w.marks@intel.com> Fixes: 54cdbf8 ("cxl/port: Add a driver for 'struct cxl_port' objects") Reviewed-by: Ira Weiny <ira.weiny@intel.com> Link: https://lore.kernel.org/r/168437998331.403037.15719879757678389217.stgit@dwillia2-xfh.jf.intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent f1fcbaa commit eb0764b

File tree

5 files changed

+49
-9
lines changed

5 files changed

+49
-9
lines changed

drivers/cxl/core/pci.c

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,17 +241,36 @@ static void disable_hdm(void *_cxlhdm)
241241
hdm + CXL_HDM_DECODER_CTRL_OFFSET);
242242
}
243243

244-
static int devm_cxl_enable_hdm(struct device *host, struct cxl_hdm *cxlhdm)
244+
int devm_cxl_enable_hdm(struct cxl_port *port, struct cxl_hdm *cxlhdm)
245245
{
246-
void __iomem *hdm = cxlhdm->regs.hdm_decoder;
246+
void __iomem *hdm;
247247
u32 global_ctrl;
248248

249+
/*
250+
* If the hdm capability was not mapped there is nothing to enable and
251+
* the caller is responsible for what happens next. For example,
252+
* emulate a passthrough decoder.
253+
*/
254+
if (IS_ERR(cxlhdm))
255+
return 0;
256+
257+
hdm = cxlhdm->regs.hdm_decoder;
249258
global_ctrl = readl(hdm + CXL_HDM_DECODER_CTRL_OFFSET);
259+
260+
/*
261+
* If the HDM decoder capability was enabled on entry, skip
262+
* registering disable_hdm() since this decode capability may be
263+
* owned by platform firmware.
264+
*/
265+
if (global_ctrl & CXL_HDM_DECODER_ENABLE)
266+
return 0;
267+
250268
writel(global_ctrl | CXL_HDM_DECODER_ENABLE,
251269
hdm + CXL_HDM_DECODER_CTRL_OFFSET);
252270

253-
return devm_add_action_or_reset(host, disable_hdm, cxlhdm);
271+
return devm_add_action_or_reset(&port->dev, disable_hdm, cxlhdm);
254272
}
273+
EXPORT_SYMBOL_NS_GPL(devm_cxl_enable_hdm, CXL);
255274

256275
int cxl_dvsec_rr_decode(struct device *dev, int d,
257276
struct cxl_endpoint_dvsec_info *info)
@@ -425,7 +444,7 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
425444
if (info->mem_enabled)
426445
return 0;
427446

428-
rc = devm_cxl_enable_hdm(&port->dev, cxlhdm);
447+
rc = devm_cxl_enable_hdm(port, cxlhdm);
429448
if (rc)
430449
return rc;
431450

drivers/cxl/cxl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,7 @@ struct cxl_endpoint_dvsec_info {
710710
struct cxl_hdm;
711711
struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
712712
struct cxl_endpoint_dvsec_info *info);
713+
int devm_cxl_enable_hdm(struct cxl_port *port, struct cxl_hdm *cxlhdm);
713714
int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
714715
struct cxl_endpoint_dvsec_info *info);
715716
int devm_cxl_add_passthrough_decoder(struct cxl_port *port);

drivers/cxl/port.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,17 @@ static int discover_region(struct device *dev, void *root)
6060
static int cxl_switch_port_probe(struct cxl_port *port)
6161
{
6262
struct cxl_hdm *cxlhdm;
63-
int rc;
63+
int rc, nr_dports;
6464

65-
rc = devm_cxl_port_enumerate_dports(port);
66-
if (rc < 0)
67-
return rc;
65+
nr_dports = devm_cxl_port_enumerate_dports(port);
66+
if (nr_dports < 0)
67+
return nr_dports;
6868

6969
cxlhdm = devm_cxl_setup_hdm(port, NULL);
70+
rc = devm_cxl_enable_hdm(port, cxlhdm);
71+
if (rc)
72+
return rc;
73+
7074
if (!IS_ERR(cxlhdm))
7175
return devm_cxl_enumerate_decoders(cxlhdm, NULL);
7276

@@ -75,7 +79,7 @@ static int cxl_switch_port_probe(struct cxl_port *port)
7579
return PTR_ERR(cxlhdm);
7680
}
7781

78-
if (rc == 1) {
82+
if (nr_dports == 1) {
7983
dev_dbg(&port->dev, "Fallback to passthrough decoder\n");
8084
return devm_cxl_add_passthrough_decoder(port);
8185
}

tools/testing/cxl/Kbuild

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ ldflags-y += --wrap=acpi_pci_find_root
66
ldflags-y += --wrap=nvdimm_bus_register
77
ldflags-y += --wrap=devm_cxl_port_enumerate_dports
88
ldflags-y += --wrap=devm_cxl_setup_hdm
9+
ldflags-y += --wrap=devm_cxl_enable_hdm
910
ldflags-y += --wrap=devm_cxl_add_passthrough_decoder
1011
ldflags-y += --wrap=devm_cxl_enumerate_decoders
1112
ldflags-y += --wrap=cxl_await_media_ready

tools/testing/cxl/test/mock.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,21 @@ struct cxl_hdm *__wrap_devm_cxl_setup_hdm(struct cxl_port *port,
149149
}
150150
EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_setup_hdm, CXL);
151151

152+
int __wrap_devm_cxl_enable_hdm(struct cxl_port *port, struct cxl_hdm *cxlhdm)
153+
{
154+
int index, rc;
155+
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
156+
157+
if (ops && ops->is_mock_port(port->uport))
158+
rc = 0;
159+
else
160+
rc = devm_cxl_enable_hdm(port, cxlhdm);
161+
put_cxl_mock_ops(index);
162+
163+
return rc;
164+
}
165+
EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_enable_hdm, CXL);
166+
152167
int __wrap_devm_cxl_add_passthrough_decoder(struct cxl_port *port)
153168
{
154169
int rc, index;

0 commit comments

Comments
 (0)