Skip to content

Commit d7094de

Browse files
SriMNvidiakobak2026
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> (cherry picked 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> (cherry picked from commit 6e96f7e nv-kernels/24.04_linux-nvidia-6.17-next) Signed-off-by: Koba Ko <kobak@nvidia.com>
1 parent 6a4cd40 commit d7094de

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
@@ -138,6 +138,8 @@ extern struct cxl_rwsem cxl_rwsem;
138138
int cxl_memdev_init(void);
139139
void cxl_memdev_exit(void);
140140
void cxl_mbox_init(void);
141+
void cxl_reset_sysfs_init(void);
142+
void cxl_reset_sysfs_exit(void);
141143

142144
enum cxl_poison_trace_type {
143145
CXL_POISON_TRACE_LIST,

drivers/cxl/core/pci.c

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

13921392
return __cxl_do_reset(pdev, cxlmd, dvsec);
13931393
}
1394+
1395+
/*
1396+
* CXL reset sysfs attribute management.
1397+
*
1398+
* The cxl_reset attribute is added to PCI devices that advertise CXL Reset
1399+
* capability. Managed entirely by the CXL module via subsys_interface on
1400+
* pci_bus_type, avoiding cross-module symbol dependencies between the PCI
1401+
* core (built-in) and CXL (potentially modular).
1402+
*
1403+
* subsys_interface handles existing devices at register time and hot-plug
1404+
* add/remove automatically. On unregister, remove_dev runs for all tracked
1405+
* devices under bus core serialization.
1406+
*/
1407+
1408+
static bool pci_cxl_reset_capable(struct pci_dev *pdev)
1409+
{
1410+
int dvsec;
1411+
u16 cap;
1412+
1413+
dvsec = pci_find_dvsec_capability(pdev, PCI_VENDOR_ID_CXL,
1414+
PCI_DVSEC_CXL_DEVICE);
1415+
if (!dvsec)
1416+
return false;
1417+
1418+
if (pci_read_config_word(pdev, dvsec + PCI_DVSEC_CXL_CAP, &cap))
1419+
return false;
1420+
1421+
if (!(cap & PCI_DVSEC_CXL_CACHE_CAPABLE) ||
1422+
!(cap & PCI_DVSEC_CXL_MEM_CAPABLE))
1423+
return false;
1424+
1425+
return !!(cap & PCI_DVSEC_CXL_RST_CAPABLE);
1426+
}
1427+
1428+
static ssize_t cxl_reset_store(struct device *dev,
1429+
struct device_attribute *attr,
1430+
const char *buf, size_t count)
1431+
{
1432+
struct pci_dev *pdev = to_pci_dev(dev);
1433+
int rc;
1434+
1435+
if (!sysfs_streq(buf, "1"))
1436+
return -EINVAL;
1437+
1438+
rc = cxl_do_reset(pdev);
1439+
return rc ? rc : count;
1440+
}
1441+
static DEVICE_ATTR_WO(cxl_reset);
1442+
1443+
static umode_t cxl_reset_attr_is_visible(struct kobject *kobj,
1444+
struct attribute *a, int n)
1445+
{
1446+
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
1447+
1448+
if (!pci_cxl_reset_capable(pdev))
1449+
return 0;
1450+
1451+
return a->mode;
1452+
}
1453+
1454+
static struct attribute *cxl_reset_attrs[] = {
1455+
&dev_attr_cxl_reset.attr,
1456+
NULL,
1457+
};
1458+
1459+
static const struct attribute_group cxl_reset_attr_group = {
1460+
.attrs = cxl_reset_attrs,
1461+
.is_visible = cxl_reset_attr_is_visible,
1462+
};
1463+
1464+
static int cxl_reset_add_dev(struct device *dev,
1465+
struct subsys_interface *sif)
1466+
{
1467+
struct pci_dev *pdev = to_pci_dev(dev);
1468+
1469+
if (!pci_cxl_reset_capable(pdev))
1470+
return 0;
1471+
1472+
return sysfs_create_group(&dev->kobj, &cxl_reset_attr_group);
1473+
}
1474+
1475+
static void cxl_reset_remove_dev(struct device *dev,
1476+
struct subsys_interface *sif)
1477+
{
1478+
struct pci_dev *pdev = to_pci_dev(dev);
1479+
1480+
if (!pci_cxl_reset_capable(pdev))
1481+
return;
1482+
1483+
sysfs_remove_group(&dev->kobj, &cxl_reset_attr_group);
1484+
}
1485+
1486+
static struct subsys_interface cxl_reset_interface = {
1487+
.name = "cxl_reset",
1488+
.subsys = &pci_bus_type,
1489+
.add_dev = cxl_reset_add_dev,
1490+
.remove_dev = cxl_reset_remove_dev,
1491+
};
1492+
1493+
void cxl_reset_sysfs_init(void)
1494+
{
1495+
int rc;
1496+
1497+
rc = subsys_interface_register(&cxl_reset_interface);
1498+
if (rc)
1499+
pr_warn("CXL: failed to register cxl_reset interface (%d)\n",
1500+
rc);
1501+
}
1502+
1503+
void cxl_reset_sysfs_exit(void)
1504+
{
1505+
subsys_interface_unregister(&cxl_reset_interface);
1506+
}

drivers/cxl/core/port.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2531,6 +2531,8 @@ static __init int cxl_core_init(void)
25312531
if (rc)
25322532
goto err_ras;
25332533

2534+
cxl_reset_sysfs_init();
2535+
25342536
return 0;
25352537

25362538
err_ras:
@@ -2546,6 +2548,7 @@ static __init int cxl_core_init(void)
25462548

25472549
static void cxl_core_exit(void)
25482550
{
2551+
cxl_reset_sysfs_exit();
25492552
cxl_ras_exit();
25502553
cxl_region_exit();
25512554
bus_unregister(&cxl_bus_type);

0 commit comments

Comments
 (0)