diff --git a/core/sensor.c b/core/sensor.c index b1289648d349..9bc204a3a9e0 100644 --- a/core/sensor.c +++ b/core/sensor.c @@ -1,4 +1,4 @@ -/* Copyright 2013-2015 IBM Corp. +/* Copyright 2013-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. @@ -126,6 +126,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"); @@ -139,4 +150,5 @@ void sensor_init(void) opal_register(OPAL_SENSOR_READ, opal_sensor_read, 3); opal_register(OPAL_SENSOR_GROUP_CLEAR, opal_sensor_group_clear, 2); opal_register(OPAL_SENSOR_READ_U64, opal_sensor_read_u64, 3); + opal_register(OPAL_SENSOR_GROUP_ENABLE, opal_sensor_group_enable, 3); } diff --git a/doc/opal-api/opal-sensor-group-enable-160.rst b/doc/opal-api/opal-sensor-group-enable-160.rst new file mode 100644 index 000000000000..b702dd5f01cb --- /dev/null +++ b/doc/opal-api/opal-sensor-group-enable-160.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 cab96f899014..090e0f07012e 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 #include #include - -/* - * 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 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 eae03cd7f664..3e92b9a9d539 100644 --- a/hw/occ.c +++ b/hw/occ.c @@ -31,6 +31,7 @@ #include #include #include +#include /* 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); } } diff --git a/include/occ-sensor.h b/include/occ-sensor.h new file mode 100644 index 000000000000..67ffae86e699 --- /dev/null +++ b/include/occ-sensor.h @@ -0,0 +1,264 @@ +/* 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 + +/* + * 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, +}; + +#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_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; +} __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 05fe767bc26a..7c169b042fd3 100644 --- a/include/opal-api.h +++ b/include/opal-api.h @@ -1,4 +1,4 @@ -/* Copyright 2013-2014 IBM Corp. +/* Copyright 2013-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. @@ -216,7 +216,8 @@ #define OPAL_PCI_SET_P2P 157 #define OPAL_QUIESCE 158 #define OPAL_SENSOR_READ_U64 159 -#define OPAL_LAST 159 +#define OPAL_SENSOR_GROUP_ENABLE 160 +#define OPAL_LAST 160 #define QUIESCE_HOLD 1 /* Spin all calls at entry */ #define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */ diff --git a/include/skiboot.h b/include/skiboot.h index d140ab2191f3..f2b3d1130f4d 100644 --- a/include/skiboot.h +++ b/include/skiboot.h @@ -355,6 +355,7 @@ extern void occ_sensors_init(void); extern int occ_sensor_read(u32 handle, u64 *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 */