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

Reply via email to