mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] kernel: add system_energy_efficiency syscall (nr 337)
@ 2026-09-20 10:07 林濬哲
  2026-09-20 10:20 ` Greg KH
  2026-09-20 10:59 ` 林濬哲
  0 siblings, 2 replies; 3+ messages in thread
From: 林濬哲 @ 2026-09-20 10:07 UTC (permalink / raw)
  To: linux-kernel
  Cc: x86, linux-api, luto, tglx, mingo, bp, dave.hansen, hpa, m18667909625

Add a new syscall that reports GPU presence and system-wide
energy information:

- mode 0: returns the number of display devices found on the PCI bus
- mode 1: returns an energy efficiency metric; prefers the real GPU
  power reported through hwmon, falls back to runtime PM status
  weights, plus the online CPU count
- mode 2: returns the real-time GPU power in milliwatts read from
  the hwmon power1_input channel exposed by GPU drivers
  (amdgpu/nouveau/radeon/nvidia); returns 0 if not reported

Signed-off-by: 林濬哲 <m18667909625@163.com>
Assisted-by: AI coding assistant (disclosed per kernel AI guidelines)
---
 arch/x86/entry/syscalls/syscall_64.tbl |   1 +
 include/linux/syscalls.h               |   2 +
 kernel/sys.c                           | 138 +++++++++++++++++++++++++
 3 files changed, 141 insertions(+)

diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index d5b6045b0090..f99649dfaa38 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -346,6 +346,7 @@
 334	common	rseq			sys_rseq
 335	common	uretprobe		sys_uretprobe
 336	common	uprobe			sys_uprobe
+337	common	system_energy_efficiency	sys_system_energy_efficiency
 # don't use numbers 387 through 423, add new calls after the last
 # 'common' entry
 424	common	pidfd_send_signal	sys_pidfd_send_signal
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 8413b624ad47..dfa9d31c20cd 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -1017,6 +1017,8 @@ asmlinkage long sys_uretprobe(void);
 
 asmlinkage long sys_uprobe(void);
 
+asmlinkage long sys_system_energy_efficiency(int __user *mode, int __user *value);
+
 /* pciconfig: alpha, arm, arm64, ia64, sparc */
 asmlinkage long sys_pciconfig_read(unsigned long bus, unsigned long dfn,
 				unsigned long off, unsigned long len,
diff --git a/kernel/sys.c b/kernel/sys.c
index 35b538ba843c..bb1106085d7e 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -22,6 +22,7 @@
 #include <linux/workqueue.h>
 #include <linux/capability.h>
 #include <linux/device.h>
+#include <linux/pci.h>
 #include <linux/key.h>
 #include <linux/times.h>
 #include <linux/posix-timers.h>
@@ -181,6 +182,143 @@ int fs_overflowgid = DEFAULT_FS_OVERFLOWGID;
 EXPORT_SYMBOL(fs_overflowuid);
 EXPORT_SYMBOL(fs_overflowgid);
 
+
+/*
+ * Read the real power consumption reported by GPU drivers via hwmon,
+ * in milliwatts. The hwmon ABI exposes power1_input in microwatts;
+ * amdgpu/nouveau/radeon/nvidia provide this channel on supported
+ * hardware. Returns 0 if no driver reports a power reading.
+ */
+static long gpu_hwmon_power_mw(void)
+{
+	static const char * const gpu_drivers[] = {
+		"amdgpu", "nouveau", "radeon", "nvidia",
+	};
+	char buf[32];
+	char path[64];
+	loff_t pos;
+	long total_uw = 0;
+	long val;
+	int i, j, ret;
+
+	for (i = 0; i < 32; i++) {
+		bool is_gpu = false;
+		struct file *fp;
+
+		snprintf(path, sizeof(path), "/sys/class/hwmon/hwmon%d/name", i);
+		fp = filp_open(path, O_RDONLY, 0);
+		if (IS_ERR(fp))
+			continue;
+
+		pos = 0;
+		ret = kernel_read(fp, buf, sizeof(buf) - 1, &pos);
+		filp_close(fp, NULL);
+		if (ret <= 0)
+			continue;
+		buf[ret] = '\0';
+
+		for (j = 0; j < ARRAY_SIZE(gpu_drivers); j++) {
+			if (!strncmp(buf, gpu_drivers[j], strlen(gpu_drivers[j]))) {
+				is_gpu = true;
+				break;
+			}
+		}
+		if (!is_gpu)
+			continue;
+
+		snprintf(path, sizeof(path), "/sys/class/hwmon/hwmon%d/power1_input", i);
+		fp = filp_open(path, O_RDONLY, 0);
+		if (IS_ERR(fp))
+			continue;
+
+		pos = 0;
+		ret = kernel_read(fp, buf, sizeof(buf) - 1, &pos);
+		filp_close(fp, NULL);
+		if (ret <= 0)
+			continue;
+		buf[ret] = '\0';
+
+		if (kstrtol(buf, 10, &val))
+			continue;
+
+		total_uw += val;
+	}
+
+	return total_uw / 1000;	/* microwatts -> milliwatts */
+}
+
+static int gpu_energy_estimate(int *gpus)
+{
+	static const int class_list[] = {
+		0x030000,	/* VGA compatible controller */
+		0x030200,	/* 3D controller (modern NVIDIA/AMD GPUs) */
+		0x030100,	/* XGA */
+		0x030080,	/* other display controller */
+	};
+	struct pci_dev *pdev;
+	int i, count = 0, energy = 0;
+
+	for (i = 0; i < ARRAY_SIZE(class_list); i++) {
+		pdev = NULL;
+		while ((pdev = pci_get_class(class_list[i], pdev)) != NULL) {
+			count++;
+			if (pdev->dev.power.runtime_status == RPM_ACTIVE)
+				energy += 100;
+			else
+				energy += 5;
+		}
+	}
+
+	if (gpus)
+		*gpus = count;
+
+	return energy;
+}
+
+SYSCALL_DEFINE2(system_energy_efficiency, int __user *, mode, int __user *, value)
+{
+	int mode_v, ret;
+	int gpu_num, gpu_energy;
+	long gpu_power_mw;
+
+	if (get_user(mode_v, mode))
+		return -EFAULT;
+
+	if (mode_v < 0 || mode_v > 2)
+		return -EINVAL;
+
+	gpu_energy = gpu_energy_estimate(&gpu_num);
+	gpu_power_mw = gpu_hwmon_power_mw();
+
+	switch (mode_v) {
+	case 0:
+		/* number of GPUs, 0 if the system has none */
+		ret = gpu_num;
+		break;
+	case 1:
+		/*
+		 * Energy efficiency metric: prefer the real GPU power
+		 * (mW) reported by the driver, fall back to runtime PM
+		 * status weights if no power channel exists, then add
+		 * the CPU part (online CPUs x 10)
+		 */
+		ret = (int)(gpu_power_mw ? gpu_power_mw : gpu_energy) +
+		      num_online_cpus() * 10;
+		break;
+	case 2:
+		/* real-time GPU power in mW, 0 if not reported */
+		ret = (int)gpu_power_mw;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (put_user(ret, value))
+		return -EFAULT;
+
+	return 0;
+}
+
 static const struct ctl_table overflow_sysctl_table[] = {
 	{
 		.procname	= "overflowuid",
-- 
2.54.0.windows.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-09-20 10:59 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-20 10:07 [PATCH] kernel: add system_energy_efficiency syscall (nr 337) 林濬哲
2026-09-20 10:20 ` Greg KH
2026-09-20 10:59 ` 林濬哲

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®