[Skiboot] [PATCH] sensor-groups: occ: Add support to disable/enable sensor group
Shilpasri G Bhat
shilpa.bhat at linux.vnet.ibm.com
Fri Nov 24 17:36:14 AEDT 2017
This patch adds a new opal call to enable/disable a sensor group. This
call is used to select the sensor groups that needs to be copied to
main memory by OCC at runtime.
Signed-off-by: Shilpasri G Bhat <shilpa.bhat at linux.vnet.ibm.com>
---
core/sensor.c | 12 ++
doc/opal-api/opal-sensor-group-enable-158.rst | 46 +++++
hw/occ-sensor.c | 243 +-----------------------
hw/occ.c | 137 ++++++++++++--
include/occ-sensor.h | 259 ++++++++++++++++++++++++++
include/opal-api.h | 3 +-
include/skiboot.h | 3 +-
7 files changed, 450 insertions(+), 253 deletions(-)
create mode 100644 doc/opal-api/opal-sensor-group-enable-158.rst
create mode 100644 include/occ-sensor.h
diff --git a/core/sensor.c b/core/sensor.c
index 0e2a5ca..4b7775d 100644
--- a/core/sensor.c
+++ b/core/sensor.c
@@ -53,6 +53,17 @@ static int opal_sensor_group_clear(u32 group_hndl, int token)
return OPAL_UNSUPPORTED;
}
+static int opal_sensor_group_enable(u32 group_hndl, int token, bool enable)
+{
+ switch (sensor_get_family(group_hndl)) {
+ case SENSOR_OCC:
+ return occ_sensor_group_enable(group_hndl, token, enable);
+ default:
+ break;
+ }
+
+ return OPAL_UNSUPPORTED;
+}
void sensor_init(void)
{
sensor_node = dt_new(opal_node, "sensors");
@@ -63,4 +74,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_GROUP_ENABLE, opal_sensor_group_enable, 3);
}
diff --git a/doc/opal-api/opal-sensor-group-enable-158.rst b/doc/opal-api/opal-sensor-group-enable-158.rst
new file mode 100644
index 0000000..2f7650f
--- /dev/null
+++ b/doc/opal-api/opal-sensor-group-enable-158.rst
@@ -0,0 +1,46 @@
+.. _opal-sensor-groups-enable:
+
+OPAL_SENSOR_GROUP_ENABLE
+==============================
+OPAL call to enable/disable the sensor group using a handle to identify
+the type of sensor group provided in the device tree.
+
+For example this call is used to disable/enable copying of sensor
+group by OCC to main memory.
+
+The call can be asynchronus, where the token parameter is used to wait
+for the completion.
+
+Parameters
+----------
+::
+ u32 handle
+ int token
+ bool enable
+
+Returns
+-------
+OPAL_SUCCESS
+ Success
+
+OPAL_UNSUPPORTED
+ No support to enable/disable the sensor group
+
+OPAL_HARDWARE
+ Unable to procced due to the current hardware state
+
+OPAL_PERMISSION
+ Hardware cannot take the request
+
+OPAL_ASYNC_COMPLETION
+ Request was sent and an async completion message will be sent with
+ token and status of the request.
+
+OPAL_BUSY
+ Previous request in progress
+
+OPAL_INTERNAL_ERROR
+ Error in request response
+
+OPAL_TIMEOUT
+ Timeout in request completion
diff --git a/hw/occ-sensor.c b/hw/occ-sensor.c
index 1042c11..c0c95ee 100644
--- a/hw/occ-sensor.c
+++ b/hw/occ-sensor.c
@@ -20,240 +20,7 @@
#include <sensor.h>
#include <device.h>
#include <cpu.h>
-
-/*
- * OCC Sensor Data
- *
- * OCC sensor data will use BAR2 (OCC Common is per physical drawer).
- * Starting address is at offset 0x00580000 from BAR2 base address.
- * Maximum size is 1.5MB.
- *
- * -------------------------------------------------------------------------
- * | Start (Offset from | End | Size |Description |
- * | BAR2 base address) | | | |
- * -------------------------------------------------------------------------
- * | 0x00580000 | 0x005A57FF |150kB |OCC 0 Sensor Data Block|
- * | 0x005A5800 | 0x005CAFFF |150kB |OCC 1 Sensor Data Block|
- * | : | : | : | : |
- * | 0x00686800 | 0x006ABFFF |150kB |OCC 7 Sensor Data Block|
- * | 0x006AC000 | 0x006FFFFF |336kB |Reserved |
- * -------------------------------------------------------------------------
- *
- *
- * OCC N Sensor Data Block Layout (150kB)
- *
- * The sensor data block layout is the same for each OCC N. It contains
- * sensor-header-block, sensor-names buffer, sensor-readings-ping buffer and
- * sensor-readings-pong buffer.
- *
- * ----------------------------------------------------------------------------
- * | Start (Offset from OCC | End | Size |Description |
- * | N Sensor Data Block) | | | |
- * ----------------------------------------------------------------------------
- * | 0x00000000 | 0x000003FF |1kB |Sensor Data Header Block |
- * | 0x00000400 | 0x0000CBFF |50kB |Sensor Names |
- * | 0x0000CC00 | 0x0000DBFF |4kB |Reserved |
- * | 0x0000DC00 | 0x00017BFF |40kB |Sensor Readings ping buffer|
- * | 0x00017C00 | 0x00018BFF |4kB |Reserved |
- * | 0x00018C00 | 0x00022BFF |40kB |Sensor Readings pong buffer|
- * | 0x00022C00 | 0x000257FF |11kB |Reserved |
- * ----------------------------------------------------------------------------
- *
- * Sensor Data Header Block : This is written once by the OCC during
- * initialization after a load or reset. Layout is defined in 'struct
- * occ_sensor_data_header'
- *
- * Sensor Names : This is written once by the OCC during initialization after a
- * load or reset. It contains static information for each sensor. The number of
- * sensors, format version and length of each sensor is defined in
- * 'Sensor Data Header Block'. Format of each sensor name is defined in
- * 'struct occ_sensor_name'. The first sensor starts at offset 0 followed
- * immediately by the next sensor.
- *
- * Sensor Readings Ping/Pong Buffer:
- * There are two 40kB buffers to store the sensor readings. One buffer that
- * is currently being updated by the OCC and one that is available to be read.
- * Each of these buffers will be of the same format. The number of sensors and
- * the format version of the ping and pong buffers is defined in the
- * 'Sensor Data Header Block'.
- *
- * Each sensor within the ping and pong buffers may be of a different format
- * and length. For each sensor the length and format is determined by its
- * 'struct occ_sensor_name.structure_type' in the Sensor Names buffer.
- *
- * --------------------------------------------------------------------------
- * | Offset | Byte0 | Byte1 | Byte2 | Byte3 | Byte4 | Byte5 | Byte6 | Byte7 |
- * --------------------------------------------------------------------------
- * | 0x0000 |Valid | Reserved |
- * | |(0x01) | |
- * --------------------------------------------------------------------------
- * | 0x0008 | Sensor Readings |
- * --------------------------------------------------------------------------
- * | : | : |
- * --------------------------------------------------------------------------
- * | 0xA000 | End of Data |
- * --------------------------------------------------------------------------
- *
- */
-
-#define MAX_OCCS 8
-#define MAX_CHARS_SENSOR_NAME 16
-#define MAX_CHARS_SENSOR_UNIT 4
-
-#define OCC_SENSOR_DATA_BLOCK_OFFSET 0x00580000
-#define OCC_SENSOR_DATA_BLOCK_SIZE 0x00025800
-
-enum occ_sensor_type {
- OCC_SENSOR_TYPE_GENERIC = 0x0001,
- OCC_SENSOR_TYPE_CURRENT = 0x0002,
- OCC_SENSOR_TYPE_VOLTAGE = 0x0004,
- OCC_SENSOR_TYPE_TEMPERATURE = 0x0008,
- OCC_SENSOR_TYPE_UTILIZATION = 0x0010,
- OCC_SENSOR_TYPE_TIME = 0x0020,
- OCC_SENSOR_TYPE_FREQUENCY = 0x0040,
- OCC_SENSOR_TYPE_POWER = 0x0080,
- OCC_SENSOR_TYPE_PERFORMANCE = 0x0200,
-};
-
-enum occ_sensor_location {
- OCC_SENSOR_LOC_SYSTEM = 0x0001,
- OCC_SENSOR_LOC_PROCESSOR = 0x0002,
- OCC_SENSOR_LOC_PARTITION = 0x0004,
- OCC_SENSOR_LOC_MEMORY = 0x0008,
- OCC_SENSOR_LOC_VRM = 0x0010,
- OCC_SENSOR_LOC_OCC = 0x0020,
- OCC_SENSOR_LOC_CORE = 0x0040,
- OCC_SENSOR_LOC_QUAD = 0x0080,
- OCC_SENSOR_LOC_GPU = 0x0100,
-};
-
-enum sensor_struct_type {
- OCC_SENSOR_READING_FULL = 0x01,
- OCC_SENSOR_READING_COUNTER = 0x02,
-};
-
-/**
- * struct occ_sensor_data_header - Sensor Data Header Block
- * @valid: When the value is 0x01 it indicates
- * that this header block and the sensor
- * names buffer are ready
- * @version: Format version of this block
- * @nr_sensors: Number of sensors in names, ping and
- * pong buffer
- * @reading_version: Format version of the Ping/Pong buffer
- * @names_offset: Offset to the location of names buffer
- * @names_version: Format version of names buffer
- * @names_length: Length of each sensor in names buffer
- * @reading_ping_offset: Offset to the location of Ping buffer
- * @reading_pong_offset: Offset to the location of Pong buffer
- * @pad/reserved: Unused data
- */
-struct occ_sensor_data_header {
- u8 valid;
- u8 version;
- u16 nr_sensors;
- u8 reading_version;
- u8 pad[3];
- u32 names_offset;
- u8 names_version;
- u8 name_length;
- u16 reserved;
- u32 reading_ping_offset;
- u32 reading_pong_offset;
-} __packed;
-
-/**
- * struct occ_sensor_name - Format of Sensor Name
- * @name: Sensor name
- * @units: Sensor units of measurement
- * @gsid: Global sensor id (OCC)
- * @freq: Update frequency
- * @scale_factor: Scaling factor
- * @type: Sensor type as defined in
- * 'enum occ_sensor_type'
- * @location: Sensor location as defined in
- * 'enum occ_sensor_location'
- * @structure_type: Indicates type of data structure used
- * for the sensor readings in the ping and
- * pong buffers for this sensor as defined
- * in 'enum sensor_struct_type'
- * @reading_offset: Offset from the start of the ping/pong
- * reading buffers for this sensor
- * @sensor_data: Sensor specific info
- * @pad: Padding to fit the size of 48 bytes.
- */
-struct occ_sensor_name {
- char name[MAX_CHARS_SENSOR_NAME];
- char units[MAX_CHARS_SENSOR_UNIT];
- u16 gsid;
- u32 freq;
- u32 scale_factor;
- u16 type;
- u16 location;
- u8 structure_type;
- u32 reading_offset;
- u8 sensor_data;
- u8 pad[8];
-} __packed;
-
-/**
- * struct occ_sensor_record - Sensor Reading Full
- * @gsid: Global sensor id (OCC)
- * @timestamp: Time base counter value while updating
- * the sensor
- * @sample: Latest sample of this sensor
- * @sample_min: Minimum value since last OCC reset
- * @sample_max: Maximum value since last OCC reset
- * @csm_min: Minimum value since last reset request
- * by CSM (CORAL)
- * @csm_max: Maximum value since last reset request
- * by CSM (CORAL)
- * @profiler_min: Minimum value since last reset request
- * by profiler (CORAL)
- * @profiler_max: Maximum value since last reset request
- * by profiler (CORAL)
- * @job_scheduler_min: Minimum value since last reset request
- * by job scheduler(CORAL)
- * @job_scheduler_max: Maximum value since last reset request
- * by job scheduler (CORAL)
- * @accumulator: Accumulator for this sensor
- * @update_tag: Count of the number of ticks that have
- * passed between updates
- * @pad: Padding to fit the size of 48 bytes
- */
-struct occ_sensor_record {
- u16 gsid;
- u64 timestamp;
- u16 sample;
- u16 sample_min;
- u16 sample_max;
- u16 csm_min;
- u16 csm_max;
- u16 profiler_min;
- u16 profiler_max;
- u16 job_scheduler_min;
- u16 job_scheduler_max;
- u64 accumulator;
- u32 update_tag;
- u8 pad[8];
-} __packed;
-
-/**
- * struct occ_sensor_counter - Sensor Reading Counter
- * @gsid: Global sensor id (OCC)
- * @timestamp: Time base counter value while updating
- * the sensor
- * @accumulator: Accumulator/Counter
- * @sample: Latest sample of this sensor (0/1)
- * @pad: Padding to fit the size of 24 bytes
- */
-struct occ_sensor_counter {
- u16 gsid;
- u64 timestamp;
- u64 accumulator;
- u8 sample;
- u8 pad[5];
-} __packed;
+#include <occ-sensor.h>
enum sensor_attr {
SENSOR_SAMPLE,
@@ -572,7 +339,7 @@ void occ_sensors_init(void)
for_each_chip(chip) {
struct occ_sensor_data_header *hb;
struct occ_sensor_name *md;
- u32 *phandles, phcount = 0;
+ u32 *phandles, *ptype, phcount = 0;
hb = get_sensor_header_block(occ_num);
md = get_names_block(hb);
@@ -583,6 +350,8 @@ void occ_sensors_init(void)
phandles = malloc(hb->nr_sensors * sizeof(u32));
assert(phandles);
+ ptype = malloc(hb->nr_sensors * sizeof(u32));
+ assert(ptype);
for (i = 0; i < hb->nr_sensors; i++) {
char name[30];
@@ -627,11 +396,13 @@ void occ_sensors_init(void)
if (md[i].location == OCC_SENSOR_LOC_CORE)
dt_add_property_cells(node, "ibm,pir", c->pir);
+ ptype[phcount] = md[i].type;
phandles[phcount++] = node->phandle;
}
occ_num++;
- occ_add_sensor_groups(sg, phandles, phcount, chip->id);
+ occ_add_sensor_groups(sg, phandles, ptype, phcount, chip->id);
free(phandles);
+ free(ptype);
}
if (!occ_num)
diff --git a/hw/occ.c b/hw/occ.c
index 8ad0dfe..281f5d3 100644
--- a/hw/occ.c
+++ b/hw/occ.c
@@ -31,6 +31,7 @@
#include <powercap.h>
#include <psr.h>
#include <sensor.h>
+#include <occ-sensor.h>
/* OCC Communication Area for PStates */
@@ -954,7 +955,7 @@ enum occ_cmd {
OCC_CMD_CLEAR_SENSOR_DATA,
OCC_CMD_SET_POWER_CAP,
OCC_CMD_SET_POWER_SHIFTING_RATIO,
- OCC_CMD_LAST
+ OCC_CMD_SELECT_SENSOR_GROUP,
};
struct opal_occ_cmd_info {
@@ -989,6 +990,13 @@ static struct opal_occ_cmd_info occ_cmds[] = {
PPC_BIT16(OCC_STATE_CHARACTERIZATION),
PPC_BIT8(OCC_ROLE_MASTER) | PPC_BIT8(OCC_ROLE_SLAVE)
},
+ { OCC_CMD_SELECT_SENSOR_GROUP,
+ 0xD3, 2, 2, 1000,
+ PPC_BIT16(OCC_STATE_OBSERVATION) |
+ PPC_BIT16(OCC_STATE_ACTIVE) |
+ PPC_BIT16(OCC_STATE_CHARACTERIZATION),
+ PPC_BIT8(OCC_ROLE_MASTER) | PPC_BIT8(OCC_ROLE_SLAVE)
+ },
};
enum occ_response_status {
@@ -1018,6 +1026,7 @@ static struct cmd_interface {
u8 *valid;
u32 chip_id;
u32 token;
+ u16 enabled_sensor_mask;
u8 occ_role;
u8 request_id;
bool cmd_in_progress;
@@ -1212,6 +1221,10 @@ static void handle_occ_rsp(uint32_t chip_id)
goto exit;
}
+ if (rsp->cmd == occ_cmds[OCC_CMD_SELECT_SENSOR_GROUP].cmd_value &&
+ rsp->status == OCC_RSP_SUCCESS)
+ chip->enabled_sensor_mask = *(u16 *)chip->cdata->data;
+
chip->cmd_in_progress = false;
queue_occ_rsp_msg(chip->token, read_occ_rsp(chip->rsp));
exit:
@@ -1252,6 +1265,7 @@ static void occ_cmd_interface_init(void)
init_lock(&chips[i].queue_lock);
chips[i].cmd_in_progress = false;
chips[i].request_id = 0;
+ chips[i].enabled_sensor_mask = OCC_ENABLED_SENSOR_MASK;
init_timer(&chips[i].timeout, occ_cmd_timeout_handler,
&chips[i]);
i++;
@@ -1500,16 +1514,93 @@ int occ_sensor_group_clear(u32 group_hndl, int token)
return opal_occ_command(&chips[i], token, &slimit_data);
}
-void occ_add_sensor_groups(struct dt_node *sg, u32 *phandles, int nr_phandles,
- int chipid)
+static u16 sensor_enable;
+static struct opal_occ_cmd_data sensor_mask_data = {
+ .data = (u8 *)&sensor_enable,
+ .cmd = OCC_CMD_SELECT_SENSOR_GROUP,
+};
+
+int occ_sensor_group_enable(u32 group_hndl, int token, bool enable)
+{
+ u16 type = sensor_get_rid(group_hndl);
+ u8 i = sensor_get_attr(group_hndl);
+
+ if (i > nr_occs)
+ return OPAL_UNSUPPORTED;
+
+ switch (type) {
+ case OCC_SENSOR_TYPE_GENERIC:
+ case OCC_SENSOR_TYPE_CURRENT:
+ case OCC_SENSOR_TYPE_VOLTAGE:
+ case OCC_SENSOR_TYPE_TEMPERATURE:
+ case OCC_SENSOR_TYPE_UTILIZATION:
+ case OCC_SENSOR_TYPE_TIME:
+ case OCC_SENSOR_TYPE_FREQUENCY:
+ case OCC_SENSOR_TYPE_POWER:
+ case OCC_SENSOR_TYPE_PERFORMANCE:
+ break;
+ default:
+ return OPAL_UNSUPPORTED;
+ }
+
+ if (!(*chips[i].valid))
+ return OPAL_HARDWARE;
+
+ if (enable && (type & chips[i].enabled_sensor_mask))
+ return OPAL_SUCCESS;
+ else if (!enable && !(type & chips[i].enabled_sensor_mask))
+ return OPAL_SUCCESS;
+
+ sensor_enable = enable ? type | chips[i].enabled_sensor_mask :
+ ~type & chips[i].enabled_sensor_mask;
+
+ return opal_occ_command(&chips[i], token, &sensor_mask_data);
+}
+
+void occ_add_sensor_groups(struct dt_node *sg, u32 *phandles, u32 *ptype,
+ int nr_phandles, int chipid)
{
- struct limit_group_info {
- int limit;
+ struct group_info {
+ int type;
const char *str;
- } limits[] = {
- { OCC_SENSOR_LIMIT_GROUP_CSM, "csm" },
- { OCC_SENSOR_LIMIT_GROUP_PROFILER, "profiler" },
- { OCC_SENSOR_LIMIT_GROUP_JOB_SCHED, "js" },
+ u32 ops;
+ } groups[] = {
+ { OCC_SENSOR_LIMIT_GROUP_CSM, "csm",
+ OPAL_SENSOR_GROUP_CLEAR
+ },
+ { OCC_SENSOR_LIMIT_GROUP_PROFILER, "profiler",
+ OPAL_SENSOR_GROUP_CLEAR
+ },
+ { OCC_SENSOR_LIMIT_GROUP_JOB_SCHED, "js",
+ OPAL_SENSOR_GROUP_CLEAR
+ },
+ { OCC_SENSOR_TYPE_GENERIC, "generic",
+ OPAL_SENSOR_GROUP_ENABLE
+ },
+ { OCC_SENSOR_TYPE_CURRENT, "current",
+ OPAL_SENSOR_GROUP_ENABLE
+ },
+ { OCC_SENSOR_TYPE_VOLTAGE, "voltage",
+ OPAL_SENSOR_GROUP_ENABLE
+ },
+ { OCC_SENSOR_TYPE_TEMPERATURE, "temperature",
+ OPAL_SENSOR_GROUP_ENABLE
+ },
+ { OCC_SENSOR_TYPE_UTILIZATION, "utilization",
+ OPAL_SENSOR_GROUP_ENABLE
+ },
+ { OCC_SENSOR_TYPE_TIME, "time",
+ OPAL_SENSOR_GROUP_ENABLE
+ },
+ { OCC_SENSOR_TYPE_FREQUENCY, "frequency",
+ OPAL_SENSOR_GROUP_ENABLE
+ },
+ { OCC_SENSOR_TYPE_POWER, "power",
+ OPAL_SENSOR_GROUP_ENABLE
+ },
+ { OCC_SENSOR_TYPE_PERFORMANCE, "performance",
+ OPAL_SENSOR_GROUP_ENABLE
+ },
};
int i, j;
@@ -1517,14 +1608,14 @@ void occ_add_sensor_groups(struct dt_node *sg, u32 *phandles, int nr_phandles,
if (chips[i].chip_id == chipid)
break;
- for (j = 0; j < ARRAY_SIZE(limits); j++) {
+ for (j = 0; j < ARRAY_SIZE(groups); j++) {
struct dt_node *node;
char name[20];
u32 handle;
- snprintf(name, 20, "occ-%s", limits[j].str);
+ snprintf(name, 20, "occ-%s", groups[j].str);
handle = sensor_make_handler(SENSOR_OCC, 0,
- limits[j].limit, i);
+ groups[j].type, i);
node = dt_new_addr(sg, name, handle);
if (!node) {
prerror("Failed to create sensor group nodes\n");
@@ -1532,10 +1623,26 @@ void occ_add_sensor_groups(struct dt_node *sg, u32 *phandles, int nr_phandles,
}
dt_add_property_cells(node, "sensor-group-id", handle);
- dt_add_property_string(node, "type", limits[j].str);
+ dt_add_property_string(node, "type", groups[j].str);
dt_add_property_cells(node, "ibm,chip-id", chipid);
- dt_add_property(node, "sensors", phandles, nr_phandles);
- dt_add_property_cells(node, "ops", OPAL_SENSOR_GROUP_CLEAR);
+ if (groups[j].ops == OPAL_SENSOR_GROUP_ENABLE) {
+ u32 *_phandles;
+ int k, pcount = 0;
+
+ _phandles = malloc(sizeof(u32) * nr_phandles);
+ assert(_phandles);
+ for (k = 0; k < nr_phandles; k++)
+ if (ptype[k] == groups[j].type)
+ _phandles[pcount++] = phandles[k];
+ if (pcount)
+ dt_add_property(node, "sensors", _phandles,
+ pcount);
+ free(_phandles);
+ } else {
+ dt_add_property(node, "sensors", phandles,
+ nr_phandles);
+ }
+ dt_add_property_cells(node, "ops", groups[j].ops);
}
}
diff --git a/include/occ-sensor.h b/include/occ-sensor.h
new file mode 100644
index 0000000..153f295
--- /dev/null
+++ b/include/occ-sensor.h
@@ -0,0 +1,259 @@
+/* Copyright 2017 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * OCC Sensor Data
+ *
+ * OCC sensor data will use BAR2 (OCC Common is per physical drawer).
+ * Starting address is at offset 0x00580000 from BAR2 base address.
+ * Maximum size is 1.5MB.
+ *
+ * -------------------------------------------------------------------------
+ * | Start (Offset from | End | Size |Description |
+ * | BAR2 base address) | | | |
+ * -------------------------------------------------------------------------
+ * | 0x00580000 | 0x005A57FF |150kB |OCC 0 Sensor Data Block|
+ * | 0x005A5800 | 0x005CAFFF |150kB |OCC 1 Sensor Data Block|
+ * | : | : | : | : |
+ * | 0x00686800 | 0x006ABFFF |150kB |OCC 7 Sensor Data Block|
+ * | 0x006AC000 | 0x006FFFFF |336kB |Reserved |
+ * -------------------------------------------------------------------------
+ *
+ *
+ * OCC N Sensor Data Block Layout (150kB)
+ *
+ * The sensor data block layout is the same for each OCC N. It contains
+ * sensor-header-block, sensor-names buffer, sensor-readings-ping buffer and
+ * sensor-readings-pong buffer.
+ *
+ * ----------------------------------------------------------------------------
+ * | Start (Offset from OCC | End | Size |Description |
+ * | N Sensor Data Block) | | | |
+ * ----------------------------------------------------------------------------
+ * | 0x00000000 | 0x000003FF |1kB |Sensor Data Header Block |
+ * | 0x00000400 | 0x0000CBFF |50kB |Sensor Names |
+ * | 0x0000CC00 | 0x0000DBFF |4kB |Reserved |
+ * | 0x0000DC00 | 0x00017BFF |40kB |Sensor Readings ping buffer|
+ * | 0x00017C00 | 0x00018BFF |4kB |Reserved |
+ * | 0x00018C00 | 0x00022BFF |40kB |Sensor Readings pong buffer|
+ * | 0x00022C00 | 0x000257FF |11kB |Reserved |
+ * ----------------------------------------------------------------------------
+ *
+ * Sensor Data Header Block : This is written once by the OCC during
+ * initialization after a load or reset. Layout is defined in 'struct
+ * occ_sensor_data_header'
+ *
+ * Sensor Names : This is written once by the OCC during initialization after a
+ * load or reset. It contains static information for each sensor. The number of
+ * sensors, format version and length of each sensor is defined in
+ * 'Sensor Data Header Block'. Format of each sensor name is defined in
+ * 'struct occ_sensor_name'. The first sensor starts at offset 0 followed
+ * immediately by the next sensor.
+ *
+ * Sensor Readings Ping/Pong Buffer:
+ * There are two 40kB buffers to store the sensor readings. One buffer that
+ * is currently being updated by the OCC and one that is available to be read.
+ * Each of these buffers will be of the same format. The number of sensors and
+ * the format version of the ping and pong buffers is defined in the
+ * 'Sensor Data Header Block'.
+ *
+ * Each sensor within the ping and pong buffers may be of a different format
+ * and length. For each sensor the length and format is determined by its
+ * 'struct occ_sensor_name.structure_type' in the Sensor Names buffer.
+ *
+ * --------------------------------------------------------------------------
+ * | Offset | Byte0 | Byte1 | Byte2 | Byte3 | Byte4 | Byte5 | Byte6 | Byte7 |
+ * --------------------------------------------------------------------------
+ * | 0x0000 |Valid | Reserved |
+ * | |(0x01) | |
+ * --------------------------------------------------------------------------
+ * | 0x0008 | Sensor Readings |
+ * --------------------------------------------------------------------------
+ * | : | : |
+ * --------------------------------------------------------------------------
+ * | 0xA000 | End of Data |
+ * --------------------------------------------------------------------------
+ *
+ */
+
+#define MAX_OCCS 8
+#define MAX_CHARS_SENSOR_NAME 16
+#define MAX_CHARS_SENSOR_UNIT 4
+
+#define OCC_SENSOR_DATA_BLOCK_OFFSET 0x00580000
+#define OCC_SENSOR_DATA_BLOCK_SIZE 0x00025800
+
+enum occ_sensor_type {
+ OCC_SENSOR_TYPE_GENERIC = 0x0001,
+ OCC_SENSOR_TYPE_CURRENT = 0x0002,
+ OCC_SENSOR_TYPE_VOLTAGE = 0x0004,
+ OCC_SENSOR_TYPE_TEMPERATURE = 0x0008,
+ OCC_SENSOR_TYPE_UTILIZATION = 0x0010,
+ OCC_SENSOR_TYPE_TIME = 0x0020,
+ OCC_SENSOR_TYPE_FREQUENCY = 0x0040,
+ OCC_SENSOR_TYPE_POWER = 0x0080,
+ OCC_SENSOR_TYPE_PERFORMANCE = 0x0200,
+};
+
+#define OCC_ENABLED_SENSOR_MASK (OCC_SENSOR_TYPE_GENERIC | \
+ OCC_SENSOR_TYPE_CURRENT | \
+ OCC_SENSOR_TYPE_VOLTAGE | \
+ OCC_SENSOR_TYPE_TIME | \
+ OCC_SENSOR_TYPE_TEMPERATURE | \
+ OCC_SENSOR_TYPE_POWER | \
+ OCC_SENSOR_TYPE_UTILIZATION | \
+ OCC_SENSOR_TYPE_FREQUENCY | \
+ OCC_SENSOR_TYPE_PERFORMANCE);
+
+enum occ_sensor_location {
+ OCC_SENSOR_LOC_SYSTEM = 0x0001,
+ OCC_SENSOR_LOC_PROCESSOR = 0x0002,
+ OCC_SENSOR_LOC_PARTITION = 0x0004,
+ OCC_SENSOR_LOC_MEMORY = 0x0008,
+ OCC_SENSOR_LOC_VRM = 0x0010,
+ OCC_SENSOR_LOC_OCC = 0x0020,
+ OCC_SENSOR_LOC_CORE = 0x0040,
+ OCC_SENSOR_LOC_QUAD = 0x0080,
+ OCC_SENSOR_LOC_GPU = 0x0100,
+};
+
+enum sensor_struct_type {
+ OCC_SENSOR_READING_FULL = 0x01,
+ OCC_SENSOR_READING_COUNTER = 0x02,
+};
+
+/**
+ * struct occ_sensor_data_header - Sensor Data Header Block
+ * @valid: When the value is 0x01 it indicates
+ * that this header block and the sensor
+ * names buffer are ready
+ * @version: Format version of this block
+ * @nr_sensors: Number of sensors in names, ping and
+ * pong buffer
+ * @reading_version: Format version of the Ping/Pong buffer
+ * @names_offset: Offset to the location of names buffer
+ * @names_version: Format version of names buffer
+ * @names_length: Length of each sensor in names buffer
+ * @reading_ping_offset: Offset to the location of Ping buffer
+ * @reading_pong_offset: Offset to the location of Pong buffer
+ * @pad/reserved: Unused data
+ */
+struct occ_sensor_data_header {
+ u8 valid;
+ u8 version;
+ u16 nr_sensors;
+ u8 reading_version;
+ u8 pad[3];
+ u32 names_offset;
+ u8 names_version;
+ u8 name_length;
+ u16 reserved;
+ u32 reading_ping_offset;
+ u32 reading_pong_offset;
+} __attribute__((__packed__));
+
+/**
+ * struct occ_sensor_name - Format of Sensor Name
+ * @name: Sensor name
+ * @units: Sensor units of measurement
+ * @gsid: Global sensor id (OCC)
+ * @freq: Update frequency
+ * @scale_factor: Scaling factor
+ * @type: Sensor type as defined in
+ * 'enum occ_sensor_type'
+ * @location: Sensor location as defined in
+ * 'enum occ_sensor_location'
+ * @structure_type: Indicates type of data structure used
+ * for the sensor readings in the ping and
+ * pong buffers for this sensor as defined
+ * in 'enum sensor_struct_type'
+ * @reading_offset: Offset from the start of the ping/pong
+ * reading buffers for this sensor
+ * @sensor_data: Sensor specific info
+ * @pad: Padding to fit the size of 48 bytes.
+ */
+struct occ_sensor_name {
+ char name[MAX_CHARS_SENSOR_NAME];
+ char units[MAX_CHARS_SENSOR_UNIT];
+ u16 gsid;
+ u32 freq;
+ u32 scale_factor;
+ u16 type;
+ u16 location;
+ u8 structure_type;
+ u32 reading_offset;
+ u8 sensor_data;
+ u8 pad[8];
+} __attribute__((__packed__));
+
+/**
+ * struct occ_sensor_record - Sensor Reading Full
+ * @gsid: Global sensor id (OCC)
+ * @timestamp: Time base counter value while updating
+ * the sensor
+ * @sample: Latest sample of this sensor
+ * @sample_min: Minimum value since last OCC reset
+ * @sample_max: Maximum value since last OCC reset
+ * @csm_min: Minimum value since last reset request
+ * by CSM (CORAL)
+ * @csm_max: Maximum value since last reset request
+ * by CSM (CORAL)
+ * @profiler_min: Minimum value since last reset request
+ * by profiler (CORAL)
+ * @profiler_max: Maximum value since last reset request
+ * by profiler (CORAL)
+ * @job_scheduler_min: Minimum value since last reset request
+ * by job scheduler(CORAL)
+ * @job_scheduler_max: Maximum value since last reset request
+ * by job scheduler (CORAL)
+ * @accumulator: Accumulator for this sensor
+ * @update_tag: Count of the number of ticks that have
+ * passed between updates
+ * @pad: Padding to fit the size of 48 bytes
+ */
+struct occ_sensor_record {
+ u16 gsid;
+ u64 timestamp;
+ u16 sample;
+ u16 sample_min;
+ u16 sample_max;
+ u16 csm_min;
+ u16 csm_max;
+ u16 profiler_min;
+ u16 profiler_max;
+ u16 job_scheduler_min;
+ u16 job_scheduler_max;
+ u64 accumulator;
+ u32 update_tag;
+ u8 pad[8];
+} __attribute__((__packed__));
+
+/**
+ * struct occ_sensor_counter - Sensor Reading Counter
+ * @gsid: Global sensor id (OCC)
+ * @timestamp: Time base counter value while updating
+ * the sensor
+ * @accumulator: Accumulator/Counter
+ * @sample: Latest sample of this sensor (0/1)
+ * @pad: Padding to fit the size of 24 bytes
+ */
+struct occ_sensor_counter {
+ u16 gsid;
+ u64 timestamp;
+ u64 accumulator;
+ u8 sample;
+ u8 pad[5];
+} __attribute__((__packed__));
diff --git a/include/opal-api.h b/include/opal-api.h
index 0bc036e..466640e 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_GROUP_ENABLE 158
+#define OPAL_LAST 158
/* Device tree flags */
diff --git a/include/skiboot.h b/include/skiboot.h
index db91325..1d6af7b 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -331,6 +331,7 @@ extern void occ_sensors_init(void);
extern int occ_sensor_read(u32 handle, u32 *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);
+ u32 *ptype, int nr_phandles, int chipid);
+extern int occ_sensor_group_enable(u32 group_hndl, int token, bool enable);
#endif /* __SKIBOOT_H */
--
1.8.3.1
More information about the Skiboot
mailing list