[PATCH] Rough draft of power/energy sensor support for lm-sensors

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi all,

Here is a patch to lm-sensors3 SVN to add support for power and energy
sensors that are reported via sysfs.  The energyX_input name follows
the changes that I proposed making to
Documentation/hwmon/sysfs-interface.txt a month ago.  I was able to get
the sensors command to report the new power/energy sensors that are in
the ibmpex driver with this patch, though I've not done anything more
than basic read testing.

Questions?  Comments?  I suspect MAX_SENSOR_TYPES should be moved to
lib/sensors.h, though whoever encoded the '6' into sysfs.c would know
for sure.  As an aside, I can break this patch into smaller chunks if
that is desirable, though the combined patch itself is small.

Signed-off-by: Darrick J. Wong <djwong at us.ibm.com>

Index: lib/sensors.h
===================================================================
--- lib/sensors.h	(revision 5140)
+++ lib/sensors.h	(working copy)
@@ -130,6 +130,8 @@
 	SENSORS_FEATURE_IN		= 0x00,
 	SENSORS_FEATURE_FAN		= 0x01,
 	SENSORS_FEATURE_TEMP		= 0x02,
+	SENSORS_FEATURE_POWER		= 0x03,
+	SENSORS_FEATURE_ENERGY		= 0x04,
 	SENSORS_FEATURE_VID		= 0x10,
 	SENSORS_FEATURE_BEEP_ENABLE	= 0x18,
 	SENSORS_FEATURE_UNKNOWN		= INT_MAX,
@@ -168,6 +170,13 @@
 	SENSORS_SUBFEATURE_TEMP_OFFSET,
 	SENSORS_SUBFEATURE_TEMP_BEEP,
 
+	SENSORS_SUBFEATURE_POWER_AVERAGE = SENSORS_FEATURE_POWER << 8,
+	SENSORS_SUBFEATURE_POWER_AVERAGE_HIGHEST,
+	SENSORS_SUBFEATURE_POWER_AVERAGE_LOWEST,
+	SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL,
+
+	SENSORS_SUBFEATURE_ENERGY_INPUT = SENSORS_FEATURE_ENERGY << 8,
+
 	SENSORS_SUBFEATURE_VID = SENSORS_FEATURE_VID << 8,
 
 	SENSORS_SUBFEATURE_BEEP_ENABLE = SENSORS_FEATURE_BEEP_ENABLE << 8,
Index: lib/sysfs.c
===================================================================
--- lib/sysfs.c	(revision 5140)
+++ lib/sysfs.c	(working copy)
@@ -137,11 +137,13 @@
 
 #define MAX_SENSORS_PER_TYPE	20
 #define MAX_SUBFEATURES		8
+#define MAX_SENSOR_TYPES	5
 /* Room for all 3 types (in, fan, temp) with all their subfeatures + VID
    + misc features */
 #define ALL_POSSIBLE_SUBFEATURES \
-				(MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * 6 \
-				 + MAX_SENSORS_PER_TYPE + 1)
+				(MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * \
+				 MAX_SENSOR_TYPES * 2 + \
+				 MAX_SENSORS_PER_TYPE + 1)
 
 static
 int get_type_scaling(sensors_subfeature_type type)
@@ -152,6 +154,10 @@
 		return 1000;
 	case SENSORS_SUBFEATURE_FAN_INPUT:
 		return 1;
+	case SENSORS_SUBFEATURE_POWER_AVERAGE:
+		return 1000000;
+	case SENSORS_SUBFEATURE_ENERGY_INPUT:
+		return 1000000;
 	}
 
 	switch (type) {
@@ -172,6 +178,8 @@
 	case SENSORS_FEATURE_IN:
 	case SENSORS_FEATURE_FAN:
 	case SENSORS_FEATURE_TEMP:
+	case SENSORS_FEATURE_POWER:
+	case SENSORS_FEATURE_ENERGY:
 		underscore = strchr(sfname, '_');
 		name = strndup(sfname, underscore - sfname);
 		break;
@@ -231,6 +239,19 @@
 	{ NULL, 0 }
 };
 
+static const struct subfeature_type_match power_matches[] = {
+	{ "average", SENSORS_SUBFEATURE_POWER_AVERAGE },
+	{ "average_highest", SENSORS_SUBFEATURE_POWER_AVERAGE_HIGHEST },
+	{ "average_lowest", SENSORS_SUBFEATURE_POWER_AVERAGE_LOWEST },
+	{ "average_interval", SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL },
+	{ NULL, 0 }
+};
+
+static const struct subfeature_type_match energy_matches[] = {
+	{ "input", SENSORS_SUBFEATURE_ENERGY_INPUT },
+	{ NULL, 0 }
+};
+
 static const struct subfeature_type_match cpu_matches[] = {
 	{ "vid", SENSORS_SUBFEATURE_VID },
 	{ NULL, 0 }
@@ -241,6 +262,8 @@
 	{ "in%d%c", in_matches },
 	{ "fan%d%c", fan_matches },
 	{ "cpu%d%c", cpu_matches },
+	{ "power%d%c", power_matches },
+	{ "energy%d%c", energy_matches },
 };
 
 /* Return the subfeature type and channel number based on the subfeature
@@ -326,10 +349,12 @@
 
 		/* Adjust the channel number */
 		switch (sftype & 0xFF00) {
-			case SENSORS_SUBFEATURE_FAN_INPUT:
-			case SENSORS_SUBFEATURE_TEMP_INPUT:
-				nr--;
-				break;
+		case SENSORS_SUBFEATURE_FAN_INPUT:
+		case SENSORS_SUBFEATURE_TEMP_INPUT:
+		case SENSORS_SUBFEATURE_POWER_AVERAGE:
+		case SENSORS_SUBFEATURE_ENERGY_INPUT:
+			nr--;
+			break;
 		}
 
 		if (nr < 0 || nr >= MAX_SENSORS_PER_TYPE) {
@@ -346,11 +371,12 @@
 		   sorted table */
 		switch (sftype) {
 		case SENSORS_SUBFEATURE_VID:
-			i = nr + MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * 6;
+			i = nr + MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES *
+			    MAX_SENSOR_TYPES * 2;
 			break;
 		case SENSORS_SUBFEATURE_BEEP_ENABLE:
-			i = MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * 6 +
-			    MAX_SENSORS_PER_TYPE;
+			i = MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES *
+			    MAX_SENSOR_TYPES * 2 + MAX_SENSORS_PER_TYPE;
 			break;
 		default:
 			i = (sftype >> 8) * MAX_SENSORS_PER_TYPE *
@@ -388,7 +414,8 @@
 		if (!all_subfeatures[i].name)
 			continue;
 
-		if (i >= MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * 6 ||
+		if (i >= MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES *
+		    MAX_SENSOR_TYPES * 2 ||
 		    i / (MAX_SUBFEATURES * 2) != prev_slot) {
 			fnum++;
 			prev_slot = i / (MAX_SUBFEATURES * 2);
@@ -409,7 +436,8 @@
 			continue;
 
 		/* New main feature? */
-		if (i >= MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * 6 ||
+		if (i >= MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES *
+		    MAX_SENSOR_TYPES * 2 ||
 		    i / (MAX_SUBFEATURES * 2) != prev_slot) {
 			ftype = all_subfeatures[i].type >> 8;
 			fnum++;
Index: prog/sensors/chips.c
===================================================================
--- prog/sensors/chips.c	(revision 5140)
+++ prog/sensors/chips.c	(working copy)
@@ -43,7 +43,7 @@
 				"%s!\n", feature->name);
 			continue;
 		}
-		printf("%s:\n", label);
+		printf("%s\n", label);
 		free(label);
 
 		b = 0;
@@ -400,6 +400,71 @@
 	printf("\n");
 }
 
+static void print_chip_power(const sensors_chip_name *name,
+			     const sensors_feature *feature,
+			     int label_size)
+{
+	const sensors_subfeature *sf, *sfmin, *sfmax;
+	char *label;
+
+	if (!(label = sensors_get_label(name, feature))) {
+		fprintf(stderr, "ERROR: Can't get label of feature %s!\n",
+			feature->name);
+		return;
+	}
+	print_label(label, label_size);
+	free(label);
+
+	sf = sensors_get_subfeature(name, feature,
+				    SENSORS_SUBFEATURE_POWER_AVERAGE);
+	if (sf)
+		printf("%4.0f W", get_value(name, sf));
+	else
+		printf("     N/A");
+
+	sfmin = sensors_get_subfeature(name, feature,
+				      SENSORS_SUBFEATURE_POWER_AVERAGE_HIGHEST);
+	sfmax = sensors_get_subfeature(name, feature,
+				       SENSORS_SUBFEATURE_POWER_AVERAGE_LOWEST);
+	if (sfmin && sfmax)
+		printf("  (min = %4.0f W, max = %1.0f W)",
+		       get_value(name, sfmin),
+		       get_value(name, sfmax));
+	else if (sfmin)
+		printf("  (min = %4.0f W)",
+		       get_value(name, sfmin));
+	else if (sfmax)
+		printf("  (max = %1.0f W)",
+		       get_value(name, sfmax));
+
+	printf("\n");
+}
+
+static void print_chip_energy(const sensors_chip_name *name,
+			      const sensors_feature *feature,
+			      int label_size)
+{
+	const sensors_subfeature *sf;
+	char *label;
+
+	if (!(label = sensors_get_label(name, feature))) {
+		fprintf(stderr, "ERROR: Can't get label of feature %s!\n",
+			feature->name);
+		return;
+	}
+	print_label(label, label_size);
+	free(label);
+
+	sf = sensors_get_subfeature(name, feature,
+				    SENSORS_SUBFEATURE_ENERGY_INPUT);
+	if (sf)
+		printf("%4.0f J", get_value(name, sf));
+	else
+		printf("     N/A");
+
+	printf("\n");
+}
+
 static void print_chip_vid(const sensors_chip_name *name,
 			   const sensors_feature *feature,
 			   int label_size)
@@ -467,6 +532,12 @@
 		case SENSORS_FEATURE_BEEP_ENABLE:
 			print_chip_beep_enable(name, feature, label_size);
 			break;
+		case SENSORS_FEATURE_POWER:
+			print_chip_power(name, feature, label_size);
+			break;
+		case SENSORS_FEATURE_ENERGY:
+			print_chip_energy(name, feature, label_size);
+			break;
 		default:
 			continue;
 		}




[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux