Skip to content

Commit 29317f8

Browse files
djbwdavejiang
authored andcommitted
cxl/mem: Introduce cxl_memdev_attach for CXL-dependent operation
Unlike the cxl_pci class driver that opportunistically enables memory expansion with no other dependent functionality, CXL accelerator drivers have distinct PCIe-only and CXL-enhanced operation states. If CXL is available some additional coherent memory/cache operations can be enabled, otherwise traditional DMA+MMIO over PCIe/CXL.io is a fallback. This constitutes a new mode of operation where the caller of devm_cxl_add_memdev() wants to make a "go/no-go" decision about running in CXL accelerated mode or falling back to PCIe-only operation. Part of that decision making process likely also includes additional CXL-acceleration-specific resource setup. Encapsulate both of those requirements into 'struct cxl_memdev_attach' that provides a ->probe() callback. The probe callback runs in cxl_mem_probe() context, after the port topology is successfully attached for the given memdev. It supports a contract where, upon successful return from devm_cxl_add_memdev(), everything needed for CXL accelerated operation has been enabled. Additionally the presence of @cxlmd->attach indicates that the accelerator driver be detached when CXL operation ends. This conceptually makes a CXL link loss event mirror a PCIe link loss event which results in triggering the ->remove() callback of affected devices+drivers. A driver can re-attach to recover back to PCIe-only operation. Live recovery, i.e. without a ->remove()/->probe() cycle, is left as a future consideration. [ dj: Repalce with updated commit log from Dan ] Cc: Smita Koralahalli <Smita.KoralahalliChannabasappa@amd.com> Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com> Reviewed-by: Dave Jiang <dave.jiang@intel.com> Tested-by: Alejandro Lucero <alucerop@amd.com> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Link: https://patch.msgid.link/20251216005616.3090129-7-dan.j.williams@intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
1 parent f2546eb commit 29317f8

5 files changed

Lines changed: 57 additions & 12 deletions

File tree

drivers/cxl/core/memdev.c

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -641,14 +641,24 @@ static void detach_memdev(struct work_struct *work)
641641
struct cxl_memdev *cxlmd;
642642

643643
cxlmd = container_of(work, typeof(*cxlmd), detach_work);
644-
device_release_driver(&cxlmd->dev);
644+
645+
/*
646+
* When the creator of @cxlmd sets ->attach it indicates CXL operation
647+
* is required. In that case, @cxlmd detach escalates to parent device
648+
* detach.
649+
*/
650+
if (cxlmd->attach)
651+
device_release_driver(cxlmd->dev.parent);
652+
else
653+
device_release_driver(&cxlmd->dev);
645654
put_device(&cxlmd->dev);
646655
}
647656

648657
static struct lock_class_key cxl_memdev_key;
649658

650659
static struct cxl_memdev *cxl_memdev_alloc(struct cxl_dev_state *cxlds,
651-
const struct file_operations *fops)
660+
const struct file_operations *fops,
661+
const struct cxl_memdev_attach *attach)
652662
{
653663
struct cxl_memdev *cxlmd;
654664
struct device *dev;
@@ -664,6 +674,8 @@ static struct cxl_memdev *cxl_memdev_alloc(struct cxl_dev_state *cxlds,
664674
goto err;
665675
cxlmd->id = rc;
666676
cxlmd->depth = -1;
677+
cxlmd->attach = attach;
678+
cxlmd->endpoint = ERR_PTR(-ENXIO);
667679

668680
dev = &cxlmd->dev;
669681
device_initialize(dev);
@@ -1081,6 +1093,18 @@ static struct cxl_memdev *cxl_memdev_autoremove(struct cxl_memdev *cxlmd)
10811093
{
10821094
int rc;
10831095

1096+
/*
1097+
* If @attach is provided fail if the driver is not attached upon
1098+
* return. Note that failure here could be the result of a race to
1099+
* teardown the CXL port topology. I.e. cxl_mem_probe() could have
1100+
* succeeded and then cxl_mem unbound before the lock is acquired.
1101+
*/
1102+
guard(device)(&cxlmd->dev);
1103+
if (cxlmd->attach && !cxlmd->dev.driver) {
1104+
cxl_memdev_unregister(cxlmd);
1105+
return ERR_PTR(-ENXIO);
1106+
}
1107+
10841108
rc = devm_add_action_or_reset(cxlmd->cxlds->dev, cxl_memdev_unregister,
10851109
cxlmd);
10861110
if (rc)
@@ -1093,13 +1117,14 @@ static struct cxl_memdev *cxl_memdev_autoremove(struct cxl_memdev *cxlmd)
10931117
* Core helper for devm_cxl_add_memdev() that wants to both create a device and
10941118
* assert to the caller that upon return cxl_mem::probe() has been invoked.
10951119
*/
1096-
struct cxl_memdev *__devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
1120+
struct cxl_memdev *__devm_cxl_add_memdev(struct cxl_dev_state *cxlds,
1121+
const struct cxl_memdev_attach *attach)
10971122
{
10981123
struct device *dev;
10991124
int rc;
11001125

11011126
struct cxl_memdev *cxlmd __free(put_cxlmd) =
1102-
cxl_memdev_alloc(cxlds, &cxl_memdev_fops);
1127+
cxl_memdev_alloc(cxlds, &cxl_memdev_fops, attach);
11031128
if (IS_ERR(cxlmd))
11041129
return cxlmd;
11051130

drivers/cxl/cxlmem.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
(FIELD_GET(CXLMDEV_RESET_NEEDED_MASK, status) != \
3535
CXLMDEV_RESET_NEEDED_NOT)
3636

37+
struct cxl_memdev_attach {
38+
int (*probe)(struct cxl_memdev *cxlmd);
39+
};
40+
3741
/**
3842
* struct cxl_memdev - CXL bus object representing a Type-3 Memory Device
3943
* @dev: driver core device object
@@ -43,6 +47,7 @@
4347
* @cxl_nvb: coordinate removal of @cxl_nvd if present
4448
* @cxl_nvd: optional bridge to an nvdimm if the device supports pmem
4549
* @endpoint: connection to the CXL port topology for this memory device
50+
* @attach: creator of this memdev depends on CXL link attach to operate
4651
* @id: id number of this memdev instance.
4752
* @depth: endpoint port depth
4853
* @scrub_cycle: current scrub cycle set for this device
@@ -59,6 +64,7 @@ struct cxl_memdev {
5964
struct cxl_nvdimm_bridge *cxl_nvb;
6065
struct cxl_nvdimm *cxl_nvd;
6166
struct cxl_port *endpoint;
67+
const struct cxl_memdev_attach *attach;
6268
int id;
6369
int depth;
6470
u8 scrub_cycle;
@@ -95,8 +101,10 @@ static inline bool is_cxl_endpoint(struct cxl_port *port)
95101
return is_cxl_memdev(port->uport_dev);
96102
}
97103

98-
struct cxl_memdev *__devm_cxl_add_memdev(struct cxl_dev_state *cxlds);
99-
struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds);
104+
struct cxl_memdev *__devm_cxl_add_memdev(struct cxl_dev_state *cxlds,
105+
const struct cxl_memdev_attach *attach);
106+
struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds,
107+
const struct cxl_memdev_attach *attach);
100108
int devm_cxl_sanitize_setup_notifier(struct device *host,
101109
struct cxl_memdev *cxlmd);
102110
struct cxl_memdev_state;

drivers/cxl/mem.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ static int cxl_mem_probe(struct device *dev)
142142
return rc;
143143
}
144144

145+
if (cxlmd->attach) {
146+
rc = cxlmd->attach->probe(cxlmd);
147+
if (rc)
148+
return rc;
149+
}
150+
145151
rc = devm_cxl_memdev_edac_register(cxlmd);
146152
if (rc)
147153
dev_dbg(dev, "CXL memdev EDAC registration failed rc=%d\n", rc);
@@ -166,17 +172,23 @@ static int cxl_mem_probe(struct device *dev)
166172
/**
167173
* devm_cxl_add_memdev - Add a CXL memory device
168174
* @cxlds: CXL device state to associate with the memdev
175+
* @attach: Caller depends on CXL topology attachment
169176
*
170177
* Upon return the device will have had a chance to attach to the
171-
* cxl_mem driver, but may fail if the CXL topology is not ready
172-
* (hardware CXL link down, or software platform CXL root not attached)
178+
* cxl_mem driver, but may fail to attach if the CXL topology is not ready
179+
* (hardware CXL link down, or software platform CXL root not attached).
180+
*
181+
* When @attach is NULL it indicates the caller wants the memdev to remain
182+
* registered even if it does not immediately attach to the CXL hierarchy. When
183+
* @attach is provided a cxl_mem_probe() failure leads to failure of this routine.
173184
*
174185
* The parent of the resulting device and the devm context for allocations is
175186
* @cxlds->dev.
176187
*/
177-
struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
188+
struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds,
189+
const struct cxl_memdev_attach *attach)
178190
{
179-
return __devm_cxl_add_memdev(cxlds);
191+
return __devm_cxl_add_memdev(cxlds, attach);
180192
}
181193
EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, "CXL");
182194

drivers/cxl/pci.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1006,7 +1006,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
10061006
if (rc)
10071007
dev_dbg(&pdev->dev, "No CXL Features discovered\n");
10081008

1009-
cxlmd = devm_cxl_add_memdev(cxlds);
1009+
cxlmd = devm_cxl_add_memdev(cxlds, NULL);
10101010
if (IS_ERR(cxlmd))
10111011
return PTR_ERR(cxlmd);
10121012

tools/testing/cxl/test/mem.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1767,7 +1767,7 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
17671767

17681768
cxl_mock_add_event_logs(&mdata->mes);
17691769

1770-
cxlmd = devm_cxl_add_memdev(cxlds);
1770+
cxlmd = devm_cxl_add_memdev(cxlds, NULL);
17711771
if (IS_ERR(cxlmd))
17721772
return PTR_ERR(cxlmd);
17731773

0 commit comments

Comments
 (0)