aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorShilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com>2017-12-22 10:34:08 +0530
committerStewart Smith <stewart@linux.vnet.ibm.com>2018-02-21 13:28:08 +1100
commit99505c03f49312c5cc7d40a90728b048857a1078 (patch)
tree819d3ccc264b514f4760f55627d189683116bcb6 /hw
parentad0861c914e8b1b7d81da2cbb7decad5b183200e (diff)
downloadskiboot-99505c03f49312c5cc7d40a90728b048857a1078.zip
skiboot-99505c03f49312c5cc7d40a90728b048857a1078.tar.gz
skiboot-99505c03f49312c5cc7d40a90728b048857a1078.tar.bz2
sensor-groups: occ: Add support to disable/enable sensor group
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@linux.vnet.ibm.com> [stewart: rebase and bump OPAL API number] Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/occ-sensor.c263
-rw-r--r--hw/occ.c137
2 files changed, 137 insertions, 263 deletions
diff --git a/hw/occ-sensor.c b/hw/occ-sensor.c
index cab96f8..090e0f0 100644
--- a/hw/occ-sensor.c
+++ b/hw/occ-sensor.c
@@ -1,4 +1,4 @@
-/* Copyright 2017 IBM Corp.
+/* Copyright 2017-2018 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,245 +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
-
-/*
- * These should match the definitions inside the OCC source:
- * occ/src/occ_405/sensor/sensor_info.c
- */
-
-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_GPU = 0x0080,
- OCC_SENSOR_LOC_QUAD = 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,
@@ -696,8 +458,8 @@ static bool check_sensor_sample(struct occ_sensor_data_header *hb, u32 offset)
}
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)
+ struct occ_sensor_name *md, u32 *phandle, u32 *ptype,
+ u32 pir, u32 occ_num, u32 chipid)
{
char name[30];
struct dt_node *node;
@@ -715,6 +477,8 @@ static void add_sensor_node(const char *loc, const char *type, int i, int attr,
if (md->location == OCC_SENSOR_LOC_CORE)
dt_add_property_cells(node, "ibm,pir", pir);
+ *ptype = md->type;
+
if (attr == SENSOR_SAMPLE) {
handler = sensor_handler(occ_num, i, SENSOR_CSM_MAX);
dt_add_property_cells(node, "sensor-data-max", handler);
@@ -762,7 +526,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);
@@ -773,6 +537,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++) {
const char *type, *loc;
@@ -805,8 +571,8 @@ void occ_sensors_init(void)
loc = get_sensor_loc_string(md[i].location);
add_sensor_node(loc, type, i, SENSOR_SAMPLE, &md[i],
- &phandles[phcount], c->pir, occ_num,
- chip->id);
+ &phandles[phcount], &ptype[phcount],
+ c->pir, occ_num, chip->id);
phcount++;
/* Add energy sensors */
@@ -814,15 +580,16 @@ void occ_sensors_init(void)
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);
+ &phandles[phcount], &ptype[phcount],
+ c->pir, occ_num, chip->id);
phcount++;
}
}
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 eae03cd..3e92b9a 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++;
@@ -1503,16 +1517,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;
@@ -1520,14 +1611,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");
@@ -1535,11 +1626,27 @@ 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);
dt_add_property_cells(node, "reg", handle);
+ 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);
}
}