[Skiboot] [PATCH] sensors: occ: Support reading u64 sensor values

Shilpasri G Bhat shilpa.bhat at linux.vnet.ibm.com
Tue Nov 14 20:05:44 AEDT 2017


This patch adds new OPAL call to read sensor values of type u64. It
also exports energy sensors in device-tree.

Signed-off-by: Shilpasri G Bhat <shilpa.bhat at linux.vnet.ibm.com>
---
 core/sensor.c      |  14 ++++
 hw/occ-sensor.c    | 210 ++++++++++++++++++++++++++++++++++++++---------------
 include/opal-api.h |   3 +-
 include/skiboot.h  |   2 +-
 4 files changed, 169 insertions(+), 60 deletions(-)

diff --git a/core/sensor.c b/core/sensor.c
index 57b21bc..4eeed20 100644
--- a/core/sensor.c
+++ b/core/sensor.c
@@ -41,6 +41,19 @@ static int64_t opal_sensor_read(uint32_t sensor_hndl, int token,
 	return OPAL_UNSUPPORTED;
 }
 
+static int64_t opal_sensor_read_long(u32 sensor_hndl, int token __unused,
+				     u64 *sensor_data)
+{
+	switch (sensor_get_family(sensor_hndl)) {
+	case SENSOR_OCC:
+		return occ_sensor_read(sensor_hndl, sensor_data);
+	default:
+		break;
+	}
+
+	return OPAL_UNSUPPORTED;
+}
+
 static int opal_sensor_group_clear(u32 group_hndl, int token)
 {
 	switch (sensor_get_family(group_hndl)) {
@@ -63,4 +76,5 @@ void sensor_init(void)
 	/* Register OPAL interface */
 	opal_register(OPAL_SENSOR_READ, opal_sensor_read, 3);
 	opal_register(OPAL_SENSOR_GROUP_CLEAR, opal_sensor_group_clear, 2);
+	opal_register(OPAL_SENSOR_READ64, opal_sensor_read_long, 3);
 }
diff --git a/hw/occ-sensor.c b/hw/occ-sensor.c
index 1042c11..4ed0e6a 100644
--- a/hw/occ-sensor.c
+++ b/hw/occ-sensor.c
@@ -261,6 +261,7 @@ enum sensor_attr {
 	SENSOR_SAMPLE_MAX,
 	SENSOR_CSM_MIN,		/* CSM's min/max */
 	SENSOR_CSM_MAX,
+	SENSOR_ACCUMULATOR,
 	MAX_SENSOR_ATTR,
 };
 
@@ -317,22 +318,48 @@ static inline u32 sensor_handler(int occ_num, int sensor_id, int attr)
 	return sensor_make_handler(SENSOR_OCC, occ_num, sensor_id, attr);
 }
 
-int occ_sensor_read(u32 handle, u32 *data)
+static u64 read_sensor(struct occ_sensor_record *sensor, int attr)
+{
+	switch (attr) {
+	case SENSOR_SAMPLE:
+		return sensor->sample;
+	case SENSOR_SAMPLE_MIN:
+		return sensor->sample_min;
+	case SENSOR_SAMPLE_MAX:
+		return sensor->sample_max;
+	case SENSOR_CSM_MIN:
+		return sensor->csm_min;
+	case SENSOR_CSM_MAX:
+		return sensor->csm_max;
+	case SENSOR_ACCUMULATOR:
+		return sensor->accumulator;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static u64 read_counter(struct occ_sensor_counter *ctr, int attr)
+{
+	switch (attr) {
+	case SENSOR_SAMPLE:
+		return ctr->sample;
+	case SENSOR_ACCUMULATOR:
+		return ctr->accumulator;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int select_buffer_and_read(int occ_num, int id, int attr, u64 *val)
 {
 	struct occ_sensor_data_header *hb;
 	struct occ_sensor_name *md;
-	struct occ_sensor_record *sping, *spong;
-	struct occ_sensor_record *sensor = NULL;
 	u8 *ping, *pong;
-	u16 id = sensor_get_rid(handle);
-	u8 occ_num = sensor_get_frc(handle);
-	u8 attr = sensor_get_attr(handle);
-
-	if (occ_num > MAX_OCCS)
-		return OPAL_PARAMETER;
-
-	if (attr > MAX_SENSOR_ATTR)
-		return OPAL_PARAMETER;
+	void *buffer;
 
 	hb = get_sensor_header_block(occ_num);
 	md = get_names_block(hb);
@@ -345,8 +372,6 @@ int occ_sensor_read(u32 handle, u32 *data)
 
 	ping = (u8 *)((u64)hb + hb->reading_ping_offset);
 	pong = (u8 *)((u64)hb + hb->reading_pong_offset);
-	sping = (struct occ_sensor_record *)((u64)ping + md[id].reading_offset);
-	spong = (struct occ_sensor_record *)((u64)pong + md[id].reading_offset);
 
 	/* Check which buffer is valid  and read the data from that.
 	 * Ping Pong	Action
@@ -355,41 +380,73 @@ int occ_sensor_read(u32 handle, u32 *data)
 	 *  1	0	Read Ping
 	 *  1	1	Read the buffer with latest timestamp
 	 */
+
 	if (*ping && *pong) {
-		if (sping->timestamp > spong->timestamp)
-			sensor = sping;
+		u64 tping, tpong;
+
+		if (md[id].structure_type == OCC_SENSOR_READING_FULL) {
+			tping = ((struct occ_sensor_record *)((u64)ping +
+					md[id].reading_offset))->timestamp;
+			tpong = ((struct occ_sensor_record *)((u64)pong +
+					md[id].reading_offset))->timestamp;
+		} else {
+			tping = ((struct occ_sensor_counter *)((u64)ping +
+					md[id].reading_offset))->timestamp;
+			tpong = ((struct occ_sensor_counter *)((u64)pong +
+					md[id].reading_offset))->timestamp;
+		}
+		if (tping > tpong)
+			buffer = ping;
 		else
-			sensor = spong;
-
+			buffer = pong;
 	} else if (*ping && !*pong) {
-		sensor = sping;
+		buffer = ping;
 	} else if (!*ping && *pong) {
-		sensor = spong;
+		buffer = pong;
 	} else if (!*ping && !*pong) {
 		prlog(PR_DEBUG, "OCC: Both ping and pong sensor buffers are invalid\n");
 		return OPAL_HARDWARE;
 	}
 
-	switch (attr) {
-	case SENSOR_SAMPLE:
-		*data = sensor->sample;
-		break;
-	case SENSOR_SAMPLE_MIN:
-		*data = sensor->sample_min;
-		break;
-	case SENSOR_SAMPLE_MAX:
-		*data = sensor->sample_max;
-		break;
-	case SENSOR_CSM_MIN:
-		*data = sensor->csm_min;
+	buffer = (void *)((u64)buffer + md[id].reading_offset);
+
+	switch (md[id].structure_type) {
+	case OCC_SENSOR_READING_FULL:
+		*val = read_sensor(buffer, attr);
 		break;
-	case SENSOR_CSM_MAX:
-		*data = sensor->csm_max;
+	case OCC_SENSOR_READING_COUNTER:
+		*val = read_counter(buffer, attr);
 		break;
 	default:
-		*data = 0;
+		return OPAL_UNSUPPORTED;
 	}
 
+	return 0;
+}
+
+int occ_sensor_read(u32 handle, void *data)
+{
+	u64 val;
+	u16 id = sensor_get_rid(handle);
+	u8 occ_num = sensor_get_frc(handle);
+	u8 attr = sensor_get_attr(handle);
+	int rc;
+
+	if (occ_num > MAX_OCCS)
+		return OPAL_PARAMETER;
+
+	if (attr > MAX_SENSOR_ATTR)
+		return OPAL_PARAMETER;
+
+	rc = select_buffer_and_read(occ_num, id, attr, &val);
+	if (rc)
+		return rc;
+
+	if (attr == SENSOR_ACCUMULATOR)
+		*(u64 *)data = val;
+	else
+		*(u32 *)data = val;
+
 	return OPAL_SUCCESS;
 }
 
@@ -543,6 +600,41 @@ static const char *get_sensor_loc_string(enum occ_sensor_location loc)
 	return "unknown";
 }
 
+static void add_sensor_node(const char *loc, const char *type, int i, int attr,
+			    struct occ_sensor_name *md, u32 *phandle, u32 pir,
+			    u32 occ_num, u32 chipid)
+{
+	char name[30];
+	struct dt_node *node;
+	u32 handler;
+
+	snprintf(name, sizeof(name), "%s-%s", loc, type);
+	handler = sensor_handler(occ_num, i, attr);
+	node = dt_new_addr(sensor_node, name, handler);
+	dt_add_property_string(node, "sensor-type", type);
+	dt_add_property_cells(node, "sensor-data", handler);
+	dt_add_property_string(node, "occ_label", md->name);
+	add_sensor_label(node, md, chipid);
+
+	if (md->location == OCC_SENSOR_LOC_CORE)
+		dt_add_property_cells(node, "ibm,pir", pir);
+
+	if (attr == SENSOR_SAMPLE) {
+		dt_add_property_string(node, "compatible", "ibm,opal-sensor");
+
+		handler = sensor_handler(occ_num, i, SENSOR_CSM_MAX);
+		dt_add_property_cells(node, "sensor-data-max", handler);
+
+		handler = sensor_handler(occ_num, i, SENSOR_CSM_MIN);
+		dt_add_property_cells(node, "sensor-data-min", handler);
+	} else if (attr == SENSOR_ACCUMULATOR) {
+		dt_add_property_string(node, "compatible",
+				       "ibm,opal-sensor-counter");
+	}
+
+	*phandle = node->phandle;
+}
+
 void occ_sensors_init(void)
 {
 	struct proc_chip *chip;
@@ -585,11 +677,9 @@ void occ_sensors_init(void)
 		assert(phandles);
 
 		for (i = 0; i < hb->nr_sensors; i++) {
-			char name[30];
 			const char *type, *loc;
-			struct dt_node *node;
 			struct cpu_thread *c = NULL;
-			u32 handler;
+			int attr;
 
 			if (!(md[i].type & HWMON_SENSORS_MASK))
 				continue;
@@ -606,28 +696,32 @@ void occ_sensors_init(void)
 
 			type = get_sensor_type_string(md[i].type);
 			loc = get_sensor_loc_string(md[i].location);
-			snprintf(name, sizeof(name), "%s-%s", loc, type);
-
-			handler = sensor_handler(occ_num, i, SENSOR_SAMPLE);
-			node = dt_new_addr(sensor_node, name, handler);
-
-			dt_add_property_string(node, "sensor-type", type);
-			dt_add_property_cells(node, "sensor-data", handler);
-
-			handler = sensor_handler(occ_num, i, SENSOR_CSM_MAX);
-			dt_add_property_cells(node, "sensor-data-max", handler);
 
-			handler = sensor_handler(occ_num, i, SENSOR_CSM_MIN);
-			dt_add_property_cells(node, "sensor-data-min", handler);
-
-			dt_add_property_string(node, "compatible",
-					       "ibm,opal-sensor");
-			dt_add_property_string(node, "occ_label", md[i].name);
-			add_sensor_label(node, &md[i], chip->id);
+			switch (md[i].structure_type) {
+			case OCC_SENSOR_READING_FULL:
+				attr = SENSOR_SAMPLE;
+				break;
+			case OCC_SENSOR_READING_COUNTER:
+				attr = SENSOR_ACCUMULATOR;
+				break;
+			default:
+				continue;
+			}
 
-			if (md[i].location == OCC_SENSOR_LOC_CORE)
-				dt_add_property_cells(node, "ibm,pir", c->pir);
-			phandles[phcount++] = node->phandle;
+			add_sensor_node(loc, type, i, attr, &md[i],
+					&phandles[phcount], c->pir, occ_num,
+					chip->id);
+			phcount++;
+
+			/* Add energy sensors */
+			if (md[i].type == OCC_SENSOR_TYPE_POWER &&
+			    md[i].structure_type == OCC_SENSOR_READING_FULL) {
+				add_sensor_node(loc, "energy", i,
+						SENSOR_ACCUMULATOR, &md[i],
+						&phandles[phcount], c->pir,
+						occ_num, chip->id);
+				phcount++;
+			}
 		}
 		occ_num++;
 		occ_add_sensor_groups(sg, phandles, phcount, chip->id);
diff --git a/include/opal-api.h b/include/opal-api.h
index 0bc036e..3f3dbff 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -214,7 +214,8 @@
 #define OPAL_SET_POWER_SHIFT_RATIO		155
 #define OPAL_SENSOR_GROUP_CLEAR			156
 #define OPAL_PCI_SET_P2P			157
-#define OPAL_LAST				157
+#define OPAL_SENSOR_READ64			158
+#define OPAL_LAST				158
 
 /* Device tree flags */
 
diff --git a/include/skiboot.h b/include/skiboot.h
index db91325..893d673 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -328,7 +328,7 @@ extern int fake_nvram_write(uint32_t offset, void *src, uint32_t size);
 
 /* OCC Inband Sensors */
 extern void occ_sensors_init(void);
-extern int occ_sensor_read(u32 handle, u32 *data);
+extern int occ_sensor_read(u32 handle, void *data);
 extern int occ_sensor_group_clear(u32 group_hndl, int token);
 extern void occ_add_sensor_groups(struct dt_node *sg, u32  *phandles,
 				  int nr_phandles, int chipid);
-- 
1.8.3.1



More information about the Skiboot mailing list