summaryrefslogtreecommitdiffstats
path: root/hw/occ-sensor.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/occ-sensor.c')
-rw-r--r--hw/occ-sensor.c189
1 files changed, 119 insertions, 70 deletions
diff --git a/hw/occ-sensor.c b/hw/occ-sensor.c
index 4a25a9b3..15b137f3 100644
--- a/hw/occ-sensor.c
+++ b/hw/occ-sensor.c
@@ -266,6 +266,7 @@ enum sensor_attr {
SENSOR_SAMPLE_MAX,
SENSOR_CSM_MIN, /* CSM's min/max */
SENSOR_CSM_MAX,
+ SENSOR_ACCUMULATOR,
MAX_SENSOR_ATTR,
};
@@ -322,36 +323,41 @@ 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, u64 *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 void *select_sensor_buffer(struct occ_sensor_data_header *hb, int id)
{
- 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;
+ void *buffer = NULL;
- if (attr > MAX_SENSOR_ATTR)
- return OPAL_PARAMETER;
+ if (!hb)
+ return NULL;
- hb = get_sensor_header_block(occ_num);
md = get_names_block(hb);
- if (hb->valid != 1)
- return OPAL_HARDWARE;
-
- if (id > hb->nr_sensors)
- return OPAL_PARAMETER;
-
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
@@ -360,40 +366,61 @@ int occ_sensor_read(u32 handle, u64 *data)
* 1 0 Read Ping
* 1 1 Read the buffer with latest timestamp
*/
+
if (*ping && *pong) {
- if (sping->timestamp > spong->timestamp)
- sensor = sping;
- else
- sensor = spong;
+ u64 tping, tpong;
+ u64 ping_buf = (u64)ping + md[id].reading_offset;
+ u64 pong_buf = (u64)pong + md[id].reading_offset;
+ tping = ((struct occ_sensor_record *)ping_buf)->timestamp;
+ tpong = ((struct occ_sensor_record *)pong_buf)->timestamp;
+
+ if (tping > tpong)
+ buffer = ping;
+ else
+ 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;
+ return NULL;
}
- 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;
- break;
- case SENSOR_CSM_MAX:
- *data = sensor->csm_max;
- break;
- default:
- *data = 0;
- }
+ assert(buffer);
+ buffer = (void *)((u64)buffer + md[id].reading_offset);
+
+ return buffer;
+}
+
+int occ_sensor_read(u32 handle, u64 *data)
+{
+ struct occ_sensor_data_header *hb;
+ u16 id = sensor_get_rid(handle);
+ u8 occ_num = sensor_get_frc(handle);
+ u8 attr = sensor_get_attr(handle);
+ void *buff;
+
+ if (occ_num > MAX_OCCS)
+ return OPAL_PARAMETER;
+
+ if (attr > MAX_SENSOR_ATTR)
+ return OPAL_PARAMETER;
+
+ hb = get_sensor_header_block(occ_num);
+
+ if (hb->valid != 1)
+ return OPAL_HARDWARE;
+
+ if (id > hb->nr_sensors)
+ return OPAL_PARAMETER;
+
+ buff = select_sensor_buffer(hb, id);
+ if (!buff)
+ return OPAL_HARDWARE;
+
+ *data = read_sensor(buff, attr);
return OPAL_SUCCESS;
}
@@ -565,6 +592,38 @@ static bool check_sensor_sample(struct occ_sensor_data_header *hb, u32 offset)
return ping->sample || pong->sample;
}
+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_cells(node, "reg", 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) {
+ 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");
+ *phandle = node->phandle;
+}
+
void occ_sensors_init(void)
{
struct proc_chip *chip;
@@ -613,11 +672,8 @@ 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;
if (md[i].structure_type != OCC_SENSOR_READING_FULL)
continue;
@@ -644,29 +700,22 @@ 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);
+ add_sensor_node(loc, type, i, SENSOR_SAMPLE, &md[i],
+ &phandles[phcount], c->pir, occ_num,
+ chip->id);
+ phcount++;
- dt_add_property_string(node, "sensor-type", type);
- dt_add_property_cells(node, "sensor-data", handler);
- dt_add_property_cells(node, "reg", 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);
+ /* 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++;
+ }
- if (md[i].location == OCC_SENSOR_LOC_CORE)
- dt_add_property_cells(node, "ibm,pir", c->pir);
- phandles[phcount++] = node->phandle;
}
occ_num++;
occ_add_sensor_groups(sg, phandles, phcount, chip->id);
OpenPOWER on IntegriCloud