aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/occ-sensor.c111
1 files changed, 107 insertions, 4 deletions
diff --git a/hw/occ-sensor.c b/hw/occ-sensor.c
index 15b137f..cab96f8 100644
--- a/hw/occ-sensor.c
+++ b/hw/occ-sensor.c
@@ -275,32 +275,80 @@ enum sensor_attr {
OCC_SENSOR_TYPE_TEMPERATURE | \
OCC_SENSOR_TYPE_POWER)
+/*
+ * Standard HWMON linux interface expects the below units for the
+ * environment sensors:
+ * - Current : milliampere
+ * - Voltage : millivolt
+ * - Temperature : millidegree Celsius (scaled in kernel)
+ * - Power : microWatt (scaled in kernel)
+ * - Energy : microJoule
+ */
+
+/*
+ * OCC sensor units are obtained after scaling the sensor values.
+ * https://github.com/open-power/occ/blob/master/src/occ_405/sensor/sensor_info.c
+ */
+
static struct str_map {
const char *occ_str;
const char *opal_str;
} str_maps[] = {
{"PWRSYS", "System"},
+ /* Bulk power of the system: Watt */
{"PWRFAN", "Fan"},
+ /* Power consumption of the system fans: Watt */
{"PWRIO", "IO"},
+ /* Power consumption of the IO subsystem: Watt */
{"PWRSTORE", "Storage"},
+ /* Power comsumption of the storage subsystem: Watt */
{"PWRGPU", "GPU"},
+ /* Power consumption for GPUs per socket read from APSS: Watt */
{"PWRAPSSCH", "APSS"},
+ /* Power Provided by APSS channel x (where x=0…15): Watt */
{"PWRPROC", ""},
+ /* Power consumption for this Processor: Watt */
{"PWRVDD", "Vdd"},
- {"CURVDD", "Vdd"},
- {"VOLTVDDSENSE", "Vdd Remote Sense"},
- {"VOLTVDD", "Vdd"},
+ /* Power consumption for this Processor's Vdd(AVSBus readings): Watt */
{"PWRVDN", "Vdn"},
+ /* Power consumption for  this Processor's Vdn (nest)
+ * Calculated from AVSBus readings: Watt */
+ {"PWRMEM", "Memory"},
+ /* Power consumption for Memory  for this Processor read from APSS:
+ * Watt */
+ {"CURVDD", "Vdd"},
+ /* Processor Vdd Current (read from AVSBus): Ampere */
{"CURVDN", "Vdn"},
+ /* Processor Vdn Current (read from AVSBus): Ampere */
+ {"VOLTVDDSENSE", "Vdd Remote Sense"},
+ /* Vdd Voltage at the remote sense.
+ * AVS reading adjusted for loadline: millivolt */
{"VOLTVDNSENSE", "Vdn Remote Sense"},
+ /* Vdn Voltage at the remote sense.
+ * AVS reading adjusted for loadline: millivolt */
+ {"VOLTVDD", "Vdd"},
+ /* Processor Vdd Voltage (read from AVSBus): millivolt */
{"VOLTVDN", "Vdn"},
- {"PWRMEM", "Memory"},
+ /* Processor Vdn Voltage (read from AVSBus): millivolt */
{"TEMPC", "Core"},
+ /* Average temperature of core DTS sensors for Processor's Core y:
+ * Celsius */
{"TEMPQ", "Quad"},
+ /* Average temperature of quad (in cache) DTS sensors for
+ * Processor’s Quad y: Celsius */
{"TEMPNEST", "Nest"},
+ /* Average temperature of nest DTS sensors: Celsius */
{"TEMPPROCTHRMC", "Core"},
+ /* The combined weighted core/quad temperature for processor core y:
+ * Celsius */
{"TEMPDIMM", "DIMM"},
+ /* DIMM temperature for DIMM x: Celsius */
{"TEMPGPU", "GPU"},
+ /* GPU x (0..2) board temperature: Celsius */
+ /* TEMPGPUxMEM: GPU x hottest HBM temperature (individual memory
+ * temperatures are not available): Celsius */
+ {"TEMPVDD", "VRM VDD"},
+ /* VRM Vdd temperature: Celsius */
};
static u64 occ_sensor_base;
@@ -323,6 +371,52 @@ static inline u32 sensor_handler(int occ_num, int sensor_id, int attr)
return sensor_make_handler(SENSOR_OCC, occ_num, sensor_id, attr);
}
+/*
+ * The scaling factor for the sensors is encoded in the below format:
+ * (((UINT32)mantissa << 8) | (UINT32)((UINT8) 256 + (UINT8)exp))
+ * https://github.com/open-power/occ/blob/master/src/occ_405/sensor/sensor.h
+ */
+static void scale_sensor(struct occ_sensor_name *md, u64 *sensor)
+{
+ u32 factor = md->scale_factor;
+ int i;
+ s8 exp;
+
+ if (md->type == OCC_SENSOR_TYPE_CURRENT)
+ *sensor *= 1000; //convert to mA
+
+ *sensor *= factor >> 8;
+ exp = factor & 0xFF;
+
+ if (exp > 0) {
+ for (i = labs(exp); i > 0; i--)
+ *sensor *= 10;
+ } else {
+ for (i = labs(exp); sensor && i > 0; i--)
+ *sensor /= 10;
+ }
+}
+
+static void scale_energy(struct occ_sensor_name *md, u64 *sensor)
+{
+ u32 factor = md->freq;
+ int i;
+ s8 exp;
+
+ *sensor *= 1000000; //convert to uJ
+
+ *sensor /= factor >> 8;
+ exp = factor & 0xFF;
+
+ if (exp > 0) {
+ for (i = labs(exp); sensor && i > 0; i--)
+ *sensor /= 10;
+ } else {
+ for (i = labs(exp); i > 0; i--)
+ *sensor *= 10;
+ }
+}
+
static u64 read_sensor(struct occ_sensor_record *sensor, int attr)
{
switch (attr) {
@@ -397,6 +491,7 @@ static void *select_sensor_buffer(struct occ_sensor_data_header *hb, int id)
int occ_sensor_read(u32 handle, u64 *data)
{
struct occ_sensor_data_header *hb;
+ struct occ_sensor_name *md;
u16 id = sensor_get_rid(handle);
u8 occ_num = sensor_get_frc(handle);
u8 attr = sensor_get_attr(handle);
@@ -421,6 +516,14 @@ int occ_sensor_read(u32 handle, u64 *data)
return OPAL_HARDWARE;
*data = read_sensor(buff, attr);
+ if (!*data)
+ return OPAL_SUCCESS;
+
+ md = get_names_block(hb);
+ if (md[id].type == OCC_SENSOR_TYPE_POWER && attr == SENSOR_ACCUMULATOR)
+ scale_energy(&md[id], data);
+ else
+ scale_sensor(&md[id], data);
return OPAL_SUCCESS;
}