Skip to content

Commit 56b3a13

Browse files
SriMNvidianvidia-bfigg
authored andcommitted
NVIDIA: VR: SAUCE: cxl: Add cxl_reset sysfs interface for PCI devices
BugLink: https://bugs.launchpad.net/bugs/2143032 Add a "cxl_reset" sysfs attribute to PCI devices that support CXL Reset (CXL r3.2 section 8.1.3.1). The attribute is visible only on devices with both CXL.cache and CXL.mem capabilities and the CXL Reset Capable bit set in the DVSEC. Writing "1" to the attribute triggers the full CXL reset flow via cxl_do_reset(). The interface is decoupled from memdev creation: when a CXL memdev exists, memory offlining and cache flush are performed; otherwise reset proceeds without the memory management. The sysfs attribute is managed entirely by the CXL module using sysfs_create_group() / sysfs_remove_group() rather than the PCI core's static attribute groups. This avoids cross-module symbol dependencies between the PCI core (always built-in) and CXL_BUS (potentially modular). At module init, existing PCI devices are scanned and a PCI bus notifier handles hot-plug/unplug. kernfs_drain() makes sure that any in-flight store() completes before sysfs_remove_group() returns, preventing use-after-free during module unload. Signed-off-by: Srirangan Madhavan <smadhavan@nvidia.com> (backported from https://lore.kernel.org/linux-cxl/20260306092322.148765-1-smadhavan@nvidia.com/) Signed-off-by: Jiandi An <jan@nvidia.com> Acked-by: Jamie Nguyen <jamien@nvidia.com> Acked-by: Nirmoy Das <nirmoyd@nvidia.com> Acked-by: Carol L Soto <csoto@nvidia.com> Acked-by: Matthew R. Ochs <mochs@nvidia.com> Signed-off-by: Brad Figg <bfigg@nvidia.com>
1 parent b77a669 commit 56b3a13

3 files changed

Lines changed: 118 additions & 0 deletions

File tree

drivers/cxl/core/core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ extern struct cxl_rwsem cxl_rwsem;
130130
int cxl_memdev_init(void);
131131
void cxl_memdev_exit(void);
132132
void cxl_mbox_init(void);
133+
void cxl_reset_sysfs_init(void);
134+
void cxl_reset_sysfs_exit(void);
133135

134136
enum cxl_poison_trace_type {
135137
CXL_POISON_TRACE_LIST,

drivers/cxl/core/pci.c

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,3 +1356,116 @@ static int cxl_do_reset(struct pci_dev *pdev)
13561356

13571357
return rc;
13581358
}
1359+
1360+
/*
1361+
* CXL reset sysfs attribute management.
1362+
*
1363+
* The cxl_reset attribute is added to PCI devices that advertise CXL Reset
1364+
* capability. Managed entirely by the CXL module via subsys_interface on
1365+
* pci_bus_type, avoiding cross-module symbol dependencies between the PCI
1366+
* core (built-in) and CXL (potentially modular).
1367+
*
1368+
* subsys_interface handles existing devices at register time and hot-plug
1369+
* add/remove automatically. On unregister, remove_dev runs for all tracked
1370+
* devices under bus core serialization.
1371+
*/
1372+
1373+
static bool pci_cxl_reset_capable(struct pci_dev *pdev)
1374+
{
1375+
int dvsec;
1376+
u16 cap;
1377+
1378+
dvsec = pci_find_dvsec_capability(pdev, PCI_VENDOR_ID_CXL,
1379+
PCI_DVSEC_CXL_DEVICE);
1380+
if (!dvsec)
1381+
return false;
1382+
1383+
if (pci_read_config_word(pdev, dvsec + PCI_DVSEC_CXL_CAP, &cap))
1384+
return false;
1385+
1386+
if (!(cap & PCI_DVSEC_CXL_CACHE_CAPABLE) ||
1387+
!(cap & PCI_DVSEC_CXL_MEM_CAPABLE))
1388+
return false;
1389+
1390+
return !!(cap & PCI_DVSEC_CXL_RST_CAPABLE);
1391+
}
1392+
1393+
static ssize_t cxl_reset_store(struct device *dev,
1394+
struct device_attribute *attr,
1395+
const char *buf, size_t count)
1396+
{
1397+
struct pci_dev *pdev = to_pci_dev(dev);
1398+
int rc;
1399+
1400+
if (!sysfs_streq(buf, "1"))
1401+
return -EINVAL;
1402+
1403+
rc = cxl_do_reset(pdev);
1404+
return rc ? rc : count;
1405+
}
1406+
static DEVICE_ATTR_WO(cxl_reset);
1407+
1408+
static umode_t cxl_reset_attr_is_visible(struct kobject *kobj,
1409+
struct attribute *a, int n)
1410+
{
1411+
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
1412+
1413+
if (!pci_cxl_reset_capable(pdev))
1414+
return 0;
1415+
1416+
return a->mode;
1417+
}
1418+
1419+
static struct attribute *cxl_reset_attrs[] = {
1420+
&dev_attr_cxl_reset.attr,
1421+
NULL,
1422+
};
1423+
1424+
static const struct attribute_group cxl_reset_attr_group = {
1425+
.attrs = cxl_reset_attrs,
1426+
.is_visible = cxl_reset_attr_is_visible,
1427+
};
1428+
1429+
static int cxl_reset_add_dev(struct device *dev,
1430+
struct subsys_interface *sif)
1431+
{
1432+
struct pci_dev *pdev = to_pci_dev(dev);
1433+
1434+
if (!pci_cxl_reset_capable(pdev))
1435+
return 0;
1436+
1437+
return sysfs_create_group(&dev->kobj, &cxl_reset_attr_group);
1438+
}
1439+
1440+
static void cxl_reset_remove_dev(struct device *dev,
1441+
struct subsys_interface *sif)
1442+
{
1443+
struct pci_dev *pdev = to_pci_dev(dev);
1444+
1445+
if (!pci_cxl_reset_capable(pdev))
1446+
return;
1447+
1448+
sysfs_remove_group(&dev->kobj, &cxl_reset_attr_group);
1449+
}
1450+
1451+
static struct subsys_interface cxl_reset_interface = {
1452+
.name = "cxl_reset",
1453+
.subsys = &pci_bus_type,
1454+
.add_dev = cxl_reset_add_dev,
1455+
.remove_dev = cxl_reset_remove_dev,
1456+
};
1457+
1458+
void cxl_reset_sysfs_init(void)
1459+
{
1460+
int rc;
1461+
1462+
rc = subsys_interface_register(&cxl_reset_interface);
1463+
if (rc)
1464+
pr_warn("CXL: failed to register cxl_reset interface (%d)\n",
1465+
rc);
1466+
}
1467+
1468+
void cxl_reset_sysfs_exit(void)
1469+
{
1470+
subsys_interface_unregister(&cxl_reset_interface);
1471+
}

drivers/cxl/core/port.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2489,6 +2489,8 @@ static __init int cxl_core_init(void)
24892489
if (rc)
24902490
goto err_ras;
24912491

2492+
cxl_reset_sysfs_init();
2493+
24922494
return 0;
24932495

24942496
err_ras:
@@ -2504,6 +2506,7 @@ static __init int cxl_core_init(void)
25042506

25052507
static void cxl_core_exit(void)
25062508
{
2509+
cxl_reset_sysfs_exit();
25072510
cxl_ras_exit();
25082511
cxl_region_exit();
25092512
bus_unregister(&cxl_bus_type);

0 commit comments

Comments
 (0)