Monitoring tools want a device-wide VRAM total and current usage, but nouveau exposed neither outside of NOUVEAU_GETPARAM ioctls, which are awkward to use for some tools as they rely on pulling libdrm.
Add two read-only files in a device attribute group: mem_info_vram_total user-accessible VRAM, i.e. NOUVEAU_GETPARAM_FB_SIZE mem_info_vram_used bytes currently allocated from the VRAM TTM manager Both read nouveau's own framebuffer and TTM accounting, the exact source behind the FB_SIZE/VRAM_USED getparams, so they need no GSP and are present on every board, unlike the GSP-only RUSD group. total is the size of the pool used draws from, so used never exceeds total. used counts only memory nouveau itself allocated and can read below firmware-reserved usage. Signed-off-by: Mohamed Ahmed <[email protected]> --- .../ABI/testing/sysfs-driver-nouveau | 17 +++++- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + drivers/gpu/drm/nouveau/nouveau_sysfs.c | 61 +++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-driver-nouveau b/Documentation/ABI/testing/sysfs-driver-nouveau index 947474b9955d..968c3ac0c464 100644 --- a/Documentation/ABI/testing/sysfs-driver-nouveau +++ b/Documentation/ABI/testing/sysfs-driver-nouveau @@ -149,4 +149,19 @@ Date: June 2026 Contact: nouveau <[email protected]> Description: PCIe link telemetry. pcie_gen is a packed gen/width bitfield; - the remaining files are link error and event counters. \ No newline at end of file + the remaining files are link error and event counters. + +What: /sys/class/drm/card<n>/device/mem_info_vram_total +What: /sys/class/drm/card<n>/device/mem_info_vram_used +Date: June 2026 +Contact: nouveau <[email protected]> +Description: + The amount of VRAM usable for allocations and the amount currently + in use, in bytes, world-readable and read-only. mem_info_vram_total + is the installed VRAM minus the region firmware reserves. This is the + same value as NOUVEAU_GETPARAM_FB_SIZE, so it can read slightly below + the card's marketed size, and it is the size of the pool that + mem_info_vram_used draws from (so used never exceeds total). Both + come from nouveau's own framebuffer and TTM accounting (the same + source as the FB_SIZE/VRAM_USED ioctls) and are present on every + nouveau board, independent of GSP-RM. \ No newline at end of file diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index a3e343085cc1..a8ca86556e2f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -297,6 +297,7 @@ struct nouveau_drm { struct nouveau_hwmon *hwmon; struct nouveau_debugfs *debugfs; bool rusd_sysfs; + bool mem_sysfs; /* led management */ struct nouveau_led *led; diff --git a/drivers/gpu/drm/nouveau/nouveau_sysfs.c b/drivers/gpu/drm/nouveau/nouveau_sysfs.c index f3d9462deaba..789b3781bedc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sysfs.c +++ b/drivers/gpu/drm/nouveau/nouveau_sysfs.c @@ -7,11 +7,18 @@ * file is one decoded value; nvkm owns the units and conversions. A section * that is not supported on this board, or has not been polled yet, reads * -ENODATA. See Documentation/ABI/testing/sysfs-driver-nouveau for units. + * + * Also exposes global VRAM size and usage (mem_info_vram_total/used, bytes) + * from nouveau's own FB/TTM accounting. Unlike RUSD these do not need GSP and + * are present on every board. */ #include <linux/device.h> #include <linux/hwmon-sysfs.h> #include <linux/sysfs.h> +#include <drm/ttm/ttm_placement.h> +#include <drm/ttm/ttm_resource.h> + #include "nouveau_drv.h" #include "nouveau_sysfs.h" @@ -214,11 +221,60 @@ static const struct attribute_group rusd_group = { .attrs = rusd_attrs, }; +/* + * Global VRAM size and current usage, in bytes. These use the same source as the + * NOUVEAU_GETPARAM_FB_SIZE/VRAM_USED ioctls, and are exposed here as a more + * convenient way for monitoring tools to access the data. + * + * Unlike the RUSD group these need no GSP and are present on every board. + */ +static ssize_t +mem_info_vram_total_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct nouveau_drm *drm = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%llu\n", drm->client.device.info.ram_user); +} +static DEVICE_ATTR_RO(mem_info_vram_total); + +static ssize_t +mem_info_vram_used_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct nouveau_drm *drm = dev_get_drvdata(dev); + struct ttm_resource_manager *vram = ttm_manager_type(&drm->ttm.bdev, TTM_PL_VRAM); + + return sysfs_emit(buf, "%llu\n", ttm_resource_manager_usage(vram)); +} +static DEVICE_ATTR_RO(mem_info_vram_used); + +static struct attribute *nouveau_mem_attrs[] = { + &dev_attr_mem_info_vram_total.attr, + &dev_attr_mem_info_vram_used.attr, + NULL, +}; + +static const struct attribute_group nouveau_mem_group = { + .attrs = nouveau_mem_attrs, +}; + int nouveau_sysfs_init(struct nouveau_drm *drm) { int ret; + /* + * VRAM size/usage comes from nouveau's own accounting, so this group is + * present on every board (GSP or legacy). + * + * The group is NOT devm-managed on drm->dev->dev: that device's devres + * outlives nouveau's remove path (which frees the drm objects the files + * read), so it is torn down explicitly in nouveau_sysfs_fini() before that. + */ + ret = device_add_group(drm->dev->dev, &nouveau_mem_group); + if (ret) + return ret; + drm->mem_sysfs = true; + /* * Only GPUs running GSP with RUSD registered (r570+) get the group. On * everything else there is nothing to expose. All files appear when RUSD @@ -247,4 +303,9 @@ nouveau_sysfs_fini(struct nouveau_drm *drm) device_remove_group(drm->dev->dev, &rusd_group); drm->rusd_sysfs = false; } + + if (drm->mem_sysfs) { + device_remove_group(drm->dev->dev, &nouveau_mem_group); + drm->mem_sysfs = false; + } } -- 2.55.0
