Skip to content

Commit 49572d5

Browse files
committed
Merge tag 'cxl-fixes-6.4-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
Pull compute express link fixes from Dan Williams: "The 'media ready' series prevents the driver from acting on bad capacity information, and it moves some checks earlier in the init sequence which impacts topics in the queue for 6.5. Additional hotplug testing uncovered a missing enable for memory decode. A debug crash fix is also included. Summary: - Stop trusting capacity data before the "media ready" indication - Add missing HDM decoder capability enable for the cold-plug case - Fix a debug message induced crash" * tag 'cxl-fixes-6.4-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl: cxl: Explicitly initialize resources when media is not ready cxl/port: Fix NULL pointer access in devm_cxl_add_port() cxl: Move cxl_await_media_ready() to before capacity info retrieval cxl: Wait Memory_Info_Valid before access memory related info cxl/port: Enable the HDM decoder capability for switch ports
2 parents 18713e8 + 793a539 commit 49572d5

File tree

12 files changed

+153
-29
lines changed

12 files changed

+153
-29
lines changed

drivers/cxl/core/mbox.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,7 @@ static int cxl_mem_get_partition_info(struct cxl_dev_state *cxlds)
10281028
* cxl_dev_state_identify() - Send the IDENTIFY command to the device.
10291029
* @cxlds: The device data for the operation
10301030
*
1031-
* Return: 0 if identify was executed successfully.
1031+
* Return: 0 if identify was executed successfully or media not ready.
10321032
*
10331033
* This will dispatch the identify command to the device and on success populate
10341034
* structures to be exported to sysfs.
@@ -1041,6 +1041,9 @@ int cxl_dev_state_identify(struct cxl_dev_state *cxlds)
10411041
u32 val;
10421042
int rc;
10431043

1044+
if (!cxlds->media_ready)
1045+
return 0;
1046+
10441047
mbox_cmd = (struct cxl_mbox_cmd) {
10451048
.opcode = CXL_MBOX_OP_IDENTIFY,
10461049
.size_out = sizeof(id),
@@ -1102,6 +1105,13 @@ int cxl_mem_create_range_info(struct cxl_dev_state *cxlds)
11021105
struct device *dev = cxlds->dev;
11031106
int rc;
11041107

1108+
if (!cxlds->media_ready) {
1109+
cxlds->dpa_res = DEFINE_RES_MEM(0, 0);
1110+
cxlds->ram_res = DEFINE_RES_MEM(0, 0);
1111+
cxlds->pmem_res = DEFINE_RES_MEM(0, 0);
1112+
return 0;
1113+
}
1114+
11051115
cxlds->dpa_res =
11061116
(struct resource)DEFINE_RES_MEM(0, cxlds->total_bytes);
11071117

drivers/cxl/core/pci.c

Lines changed: 99 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -101,23 +101,57 @@ int devm_cxl_port_enumerate_dports(struct cxl_port *port)
101101
}
102102
EXPORT_SYMBOL_NS_GPL(devm_cxl_port_enumerate_dports, CXL);
103103

104-
/*
105-
* Wait up to @media_ready_timeout for the device to report memory
106-
* active.
107-
*/
108-
int cxl_await_media_ready(struct cxl_dev_state *cxlds)
104+
static int cxl_dvsec_mem_range_valid(struct cxl_dev_state *cxlds, int id)
105+
{
106+
struct pci_dev *pdev = to_pci_dev(cxlds->dev);
107+
int d = cxlds->cxl_dvsec;
108+
bool valid = false;
109+
int rc, i;
110+
u32 temp;
111+
112+
if (id > CXL_DVSEC_RANGE_MAX)
113+
return -EINVAL;
114+
115+
/* Check MEM INFO VALID bit first, give up after 1s */
116+
i = 1;
117+
do {
118+
rc = pci_read_config_dword(pdev,
119+
d + CXL_DVSEC_RANGE_SIZE_LOW(id),
120+
&temp);
121+
if (rc)
122+
return rc;
123+
124+
valid = FIELD_GET(CXL_DVSEC_MEM_INFO_VALID, temp);
125+
if (valid)
126+
break;
127+
msleep(1000);
128+
} while (i--);
129+
130+
if (!valid) {
131+
dev_err(&pdev->dev,
132+
"Timeout awaiting memory range %d valid after 1s.\n",
133+
id);
134+
return -ETIMEDOUT;
135+
}
136+
137+
return 0;
138+
}
139+
140+
static int cxl_dvsec_mem_range_active(struct cxl_dev_state *cxlds, int id)
109141
{
110142
struct pci_dev *pdev = to_pci_dev(cxlds->dev);
111143
int d = cxlds->cxl_dvsec;
112144
bool active = false;
113-
u64 md_status;
114145
int rc, i;
146+
u32 temp;
115147

116-
for (i = media_ready_timeout; i; i--) {
117-
u32 temp;
148+
if (id > CXL_DVSEC_RANGE_MAX)
149+
return -EINVAL;
118150

151+
/* Check MEM ACTIVE bit, up to 60s timeout by default */
152+
for (i = media_ready_timeout; i; i--) {
119153
rc = pci_read_config_dword(
120-
pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(0), &temp);
154+
pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(id), &temp);
121155
if (rc)
122156
return rc;
123157

@@ -134,6 +168,39 @@ int cxl_await_media_ready(struct cxl_dev_state *cxlds)
134168
return -ETIMEDOUT;
135169
}
136170

171+
return 0;
172+
}
173+
174+
/*
175+
* Wait up to @media_ready_timeout for the device to report memory
176+
* active.
177+
*/
178+
int cxl_await_media_ready(struct cxl_dev_state *cxlds)
179+
{
180+
struct pci_dev *pdev = to_pci_dev(cxlds->dev);
181+
int d = cxlds->cxl_dvsec;
182+
int rc, i, hdm_count;
183+
u64 md_status;
184+
u16 cap;
185+
186+
rc = pci_read_config_word(pdev,
187+
d + CXL_DVSEC_CAP_OFFSET, &cap);
188+
if (rc)
189+
return rc;
190+
191+
hdm_count = FIELD_GET(CXL_DVSEC_HDM_COUNT_MASK, cap);
192+
for (i = 0; i < hdm_count; i++) {
193+
rc = cxl_dvsec_mem_range_valid(cxlds, i);
194+
if (rc)
195+
return rc;
196+
}
197+
198+
for (i = 0; i < hdm_count; i++) {
199+
rc = cxl_dvsec_mem_range_active(cxlds, i);
200+
if (rc)
201+
return rc;
202+
}
203+
137204
md_status = readq(cxlds->regs.memdev + CXLMDEV_STATUS_OFFSET);
138205
if (!CXLMDEV_READY(md_status))
139206
return -EIO;
@@ -241,17 +308,36 @@ static void disable_hdm(void *_cxlhdm)
241308
hdm + CXL_HDM_DECODER_CTRL_OFFSET);
242309
}
243310

244-
static int devm_cxl_enable_hdm(struct device *host, struct cxl_hdm *cxlhdm)
311+
int devm_cxl_enable_hdm(struct cxl_port *port, struct cxl_hdm *cxlhdm)
245312
{
246-
void __iomem *hdm = cxlhdm->regs.hdm_decoder;
313+
void __iomem *hdm;
247314
u32 global_ctrl;
248315

316+
/*
317+
* If the hdm capability was not mapped there is nothing to enable and
318+
* the caller is responsible for what happens next. For example,
319+
* emulate a passthrough decoder.
320+
*/
321+
if (IS_ERR(cxlhdm))
322+
return 0;
323+
324+
hdm = cxlhdm->regs.hdm_decoder;
249325
global_ctrl = readl(hdm + CXL_HDM_DECODER_CTRL_OFFSET);
326+
327+
/*
328+
* If the HDM decoder capability was enabled on entry, skip
329+
* registering disable_hdm() since this decode capability may be
330+
* owned by platform firmware.
331+
*/
332+
if (global_ctrl & CXL_HDM_DECODER_ENABLE)
333+
return 0;
334+
250335
writel(global_ctrl | CXL_HDM_DECODER_ENABLE,
251336
hdm + CXL_HDM_DECODER_CTRL_OFFSET);
252337

253-
return devm_add_action_or_reset(host, disable_hdm, cxlhdm);
338+
return devm_add_action_or_reset(&port->dev, disable_hdm, cxlhdm);
254339
}
340+
EXPORT_SYMBOL_NS_GPL(devm_cxl_enable_hdm, CXL);
255341

256342
int cxl_dvsec_rr_decode(struct device *dev, int d,
257343
struct cxl_endpoint_dvsec_info *info)
@@ -425,7 +511,7 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
425511
if (info->mem_enabled)
426512
return 0;
427513

428-
rc = devm_cxl_enable_hdm(&port->dev, cxlhdm);
514+
rc = devm_cxl_enable_hdm(port, cxlhdm);
429515
if (rc)
430516
return rc;
431517

drivers/cxl/core/port.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -750,11 +750,10 @@ struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
750750

751751
parent_port = parent_dport ? parent_dport->port : NULL;
752752
if (IS_ERR(port)) {
753-
dev_dbg(uport, "Failed to add %s%s%s%s: %ld\n",
754-
dev_name(&port->dev),
755-
parent_port ? " to " : "",
753+
dev_dbg(uport, "Failed to add%s%s%s: %ld\n",
754+
parent_port ? " port to " : "",
756755
parent_port ? dev_name(&parent_port->dev) : "",
757-
parent_port ? "" : " (root port)",
756+
parent_port ? "" : " root port",
758757
PTR_ERR(port));
759758
} else {
760759
dev_dbg(uport, "%s added%s%s%s\n",

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/cxlmem.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ struct cxl_poison_state {
266266
* @regs: Parsed register blocks
267267
* @cxl_dvsec: Offset to the PCIe device DVSEC
268268
* @rcd: operating in RCD mode (CXL 3.0 9.11.8 CXL Devices Attached to an RCH)
269+
* @media_ready: Indicate whether the device media is usable
269270
* @payload_size: Size of space for payload
270271
* (CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register)
271272
* @lsa_size: Size of Label Storage Area
@@ -303,6 +304,7 @@ struct cxl_dev_state {
303304
int cxl_dvsec;
304305

305306
bool rcd;
307+
bool media_ready;
306308
size_t payload_size;
307309
size_t lsa_size;
308310
struct mutex mbox_mutex; /* Protects device mailbox and firmware */

drivers/cxl/cxlpci.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#define CXL_DVSEC_RANGE_BASE_LOW(i) (0x24 + (i * 0x10))
3232
#define CXL_DVSEC_MEM_BASE_LOW_MASK GENMASK(31, 28)
3333

34+
#define CXL_DVSEC_RANGE_MAX 2
35+
3436
/* CXL 2.0 8.1.4: Non-CXL Function Map DVSEC */
3537
#define CXL_DVSEC_FUNCTION_MAP 2
3638

drivers/cxl/mem.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ static int cxl_mem_probe(struct device *dev)
124124
struct dentry *dentry;
125125
int rc;
126126

127+
if (!cxlds->media_ready)
128+
return -EBUSY;
129+
127130
/*
128131
* Someone is trying to reattach this device after it lost its port
129132
* connection (an endpoint port previously registered by this memdev was

drivers/cxl/pci.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,12 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
708708
if (rc)
709709
dev_dbg(&pdev->dev, "Failed to map RAS capability.\n");
710710

711+
rc = cxl_await_media_ready(cxlds);
712+
if (rc == 0)
713+
cxlds->media_ready = true;
714+
else
715+
dev_warn(&pdev->dev, "Media not active (%d)\n", rc);
716+
711717
rc = cxl_pci_setup_mailbox(cxlds);
712718
if (rc)
713719
return rc;

drivers/cxl/port.c

Lines changed: 9 additions & 11 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
}
@@ -113,12 +117,6 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
113117
if (rc)
114118
return rc;
115119

116-
rc = cxl_await_media_ready(cxlds);
117-
if (rc) {
118-
dev_err(&port->dev, "Media not active (%d)\n", rc);
119-
return rc;
120-
}
121-
122120
rc = devm_cxl_enumerate_decoders(cxlhdm, &info);
123121
if (rc)
124122
return rc;

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

0 commit comments

Comments
 (0)