From 2f3dd9e14af82d8c7bcc0f154d6fc06fa96d279a Mon Sep 17 00:00:00 2001 From: Shawn McCarney Date: Mon, 15 May 2017 09:11:32 -0500 Subject: OCC: Non-GPU Sensors to main memory: Phase 3 A subset of OCC sensors are now copied to main memory. Includes sensors using both the full and counter sensor readings structures. Also made the following changes to the sensor system: * Added timestamp field to sensor_t Change-Id: Ibd3044a1be09160c2d6bdb06ac3c291f874f714b RTC: 153674 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/42016 Tested-by: FSP CI Jenkins Reviewed-by: Christopher J. Cain Reviewed-by: Martha Broyles --- src/occ_405/amec/amec_slave_smh.c | 93 +- src/occ_405/amec/amec_slave_smh.h | 8 +- src/occ_405/dcom/dcom.h | 4 + src/occ_405/occLinkInputFile | 1 + src/occ_405/occ_service_codes.h | 17 +- src/occ_405/sensor/sensor.c | 16 +- src/occ_405/sensor/sensor.h | 1 + src/occ_405/sensor/sensor_main_memory.c | 1511 +++++++++++++++++++++++++++++ src/occ_405/sensor/sensor_main_memory.h | 306 ++++++ src/occ_405/sensor/sensor_service_codes.h | 18 +- src/occ_405/topfiles.mk | 1 + 11 files changed, 1957 insertions(+), 19 deletions(-) create mode 100644 src/occ_405/sensor/sensor_main_memory.c create mode 100644 src/occ_405/sensor/sensor_main_memory.h (limited to 'src/occ_405') diff --git a/src/occ_405/amec/amec_slave_smh.c b/src/occ_405/amec/amec_slave_smh.c index 841c699..b37ab45 100755 --- a/src/occ_405/amec/amec_slave_smh.c +++ b/src/occ_405/amec/amec_slave_smh.c @@ -59,6 +59,9 @@ #include #include #include +#include // For CURRENT_STATE(), OCC_STATE_* +#include // For DATA_get_present_cnfgdata() +#include // For main_mem_sensors_*() //*************************************************************************/ // Externs @@ -120,6 +123,25 @@ const smh_tbl_t amec_slv_state_1_substate_table[AMEC_SMH_STATES_PER_LVL] = {amec_slv_substate_1_7, NULL}, }; +// -------------------------------------------------------- +// AMEC Slave State 2 Substate Table +// -------------------------------------------------------- +// Each function inside this state table runs once every 16ms. +// +// No Substates +// +const smh_tbl_t amec_slv_state_2_substate_table[AMEC_SMH_STATES_PER_LVL] = +{ + {amec_slv_substate_2_0, NULL}, // Substate 2.0 + {NULL, NULL}, // Substate 2.1 (not used) + {NULL, NULL}, // Substate 2.2 (not used) + {NULL, NULL}, // Substate 2.3 (not used) + {amec_slv_substate_2_4, NULL}, // Substate 2.4 + {NULL, NULL}, // Substate 2.5 (not used) + {NULL, NULL}, // Substate 2.6 (not used) + {NULL, NULL}, // Substate 2.7 (not used) +}; + // -------------------------------------------------------- // AMEC Slave State 3 Substate Table // -------------------------------------------------------- @@ -183,13 +205,11 @@ const smh_tbl_t amec_slv_state_7_substate_table[AMEC_SMH_STATES_PER_LVL] = // -------------------------------------------------------- // Each function inside this state table runs once every 2ms. // -// No Substates -// const smh_tbl_t amec_slv_state_table[AMEC_SMH_STATES_PER_LVL] = { {amec_slv_state_0, NULL}, {amec_slv_state_1, amec_slv_state_1_substate_table}, - {amec_slv_state_2, NULL}, + {amec_slv_state_2, amec_slv_state_2_substate_table}, {amec_slv_state_3, amec_slv_state_3_substate_table}, {amec_slv_state_4, NULL}, {amec_slv_state_5, amec_slv_state_5_substate_table}, @@ -289,6 +309,50 @@ void amec_slv_check_apss_fail(void) } +// Function Specification +// +// Name: amec_slv_update_main_mem_sensors +// +// Description: Initializes and updates the main memory sensors. +// +// End Function Specification +void amec_slv_update_main_mem_sensors(void) +{ + // Don't initialize/update main memory sensors during a state transition + if (SMGR_is_state_transitioning()) + { + return; + } + + // If main memory sensors have not been initialized + if (!G_main_mem_sensors_initialized) + { + // Make sure OCC role has been set. Role required for initialization. + if (DATA_get_present_cnfgdata() & DATA_MASK_SET_ROLE) + { + // Initialize main memory sensors. Write static sensor data to main + // memory. Must call multiple times due to BCE copy size + // limitations. Sets G_main_mem_sensors_initialized to true when + // all initialization is done. + main_mem_sensors_init(); + } + } + else + { + // Main memory sensors have been initialized. Check if the OCC is in + // the proper state to update the sensor readings in main memory. + if ((CURRENT_STATE() == OCC_STATE_OBSERVATION) || + (CURRENT_STATE() == OCC_STATE_ACTIVE) || + (CURRENT_STATE() == OCC_STATE_CHARACTERIZATION)) + { + // Update main memory sensors. Write dynamic sensor readings data + // to main memory. + main_mem_sensors_update(); + } + } +} + + // Function Specification // // Name: amec_slv_common_tasks_pre @@ -769,6 +833,29 @@ void amec_slv_substate_1_7(void) } +// Function Specification +// +// Name: amec_slv_substate_2_0 +// amec_slv_substate_2_4 +// +// Description: slave substate amec_slv_substate_2_0 +// slave substate amec_slv_substate_2_4 +// other substates of state 2 are not currently used +// +// End Function Specification +void amec_slv_substate_2_0(void) +{ + AMEC_DBG("\tAMEC Slave State 2.0\n"); + amec_slv_update_main_mem_sensors(); +} + +void amec_slv_substate_2_4(void) +{ + AMEC_DBG("\tAMEC Slave State 2.4\n"); + amec_slv_update_main_mem_sensors(); +} + + // Function Specification // // Name: amec_slv_substate_3_0 diff --git a/src/occ_405/amec/amec_slave_smh.h b/src/occ_405/amec/amec_slave_smh.h index d511c63..a10f419 100755 --- a/src/occ_405/amec/amec_slave_smh.h +++ b/src/occ_405/amec/amec_slave_smh.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* Contributors Listed Below - COPYRIGHT 2011,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -71,6 +71,8 @@ extern bool G_apss_lower_pmax_rail; //************************************************************************* void amec_slv_check_apss_fail(void); +void amec_slv_update_main_mem_sensors(void); + void amec_update_proc_core_group(uint8_t); // PRE: slave common tasks @@ -98,6 +100,10 @@ void amec_slv_substate_1_5(void); void amec_slv_substate_1_6(void); void amec_slv_substate_1_7(void); +// Slave SubState 2 (6 SubStates unused) +void amec_slv_substate_2_0(void); +void amec_slv_substate_2_4(void); + // Slave SubState 3 void amec_slv_substate_3_0(void); void amec_slv_substate_3_1(void); diff --git a/src/occ_405/dcom/dcom.h b/src/occ_405/dcom/dcom.h index 9fb1efd..1bd69e1 100755 --- a/src/occ_405/dcom/dcom.h +++ b/src/occ_405/dcom/dcom.h @@ -120,6 +120,10 @@ #define DCOM_DOORBELL_HW_ERR 0x04 #define DCOM_DOORBELL_RX_TIMEOUT_ERR 0x02 +// GPU / Sensor Data +#define SENSOR_DATA_COMMON_OFFSET 0x00580000 +#define SENSOR_DATA_COMMON_ADDRESS (COMMON_BASE_ADDRESS+SENSOR_DATA_COMMON_OFFSET) + // POB Id structure typedef struct { diff --git a/src/occ_405/occLinkInputFile b/src/occ_405/occLinkInputFile index 4b446c4..0ee9eca 100644 --- a/src/occ_405/occLinkInputFile +++ b/src/occ_405/occLinkInputFile @@ -81,6 +81,7 @@ INPUT ( amec_amester.o rtls.o scom.o sensor_info.o + sensor_main_memory.o sensor_query_list.o sensor_table.o sensor.o diff --git a/src/occ_405/occ_service_codes.h b/src/occ_405/occ_service_codes.h index 417aa2d..a39d31a 100644 --- a/src/occ_405/occ_service_codes.h +++ b/src/occ_405/occ_service_codes.h @@ -127,13 +127,16 @@ enum occReasonCode GPE_REQUEST_TASK_NOT_IDLE = 0xD7, GPE_REQUEST_RC_FAILURE = 0xD8, - WOF_VFRT_REQ_FAILURE = 0xD8, - WOF_DISABLED_RC = 0xD9, - WOF_VFRT_ALIGNMENT_ERROR = 0xDA, - INVALID_MAGIC_NUMBER = 0xDB, - DIVIDE_BY_ZERO_ERROR = 0xDC, - INVALID_FREQUENCY = 0xDD, - WOF_RE_ENABLED = 0xDE, + WOF_VFRT_REQ_FAILURE = 0xD9, + WOF_DISABLED_RC = 0xDA, + WOF_VFRT_ALIGNMENT_ERROR = 0xDB, + INVALID_MAGIC_NUMBER = 0xDC, + DIVIDE_BY_ZERO_ERROR = 0xDD, + INVALID_FREQUENCY = 0xDE, + WOF_RE_ENABLED = 0xDF, + + /// Error copying sensors to main memory + SENSOR_MAIN_MEM_ERROR = 0xE0, /// Success! OCC_SUCCESS_REASON_CODE = 0xFF, diff --git a/src/occ_405/sensor/sensor.c b/src/occ_405/sensor/sensor.c index 9aedc9f..73c2a5e 100755 --- a/src/occ_405/sensor/sensor.c +++ b/src/occ_405/sensor/sensor.c @@ -25,13 +25,14 @@ -#include // sensor structure and other defines +#include // sensor structure and other defines #include // For size_t needed by memset -#include // For memset -#include "ssx_io.h" // For sprintf -#include // OCC reason codes +#include // For memset +#include "ssx_io.h" // For sprintf +#include // OCC reason codes #include // sensor module ids -#include // Trace macros +#include // Trace macros +#include // For G_current_tick #define UINT16_MIN 0 @@ -149,6 +150,7 @@ void sensor_reset( sensor_t * io_sensor_ptr) { if( io_sensor_ptr != NULL) { + io_sensor_ptr->timestamp = 0x0; io_sensor_ptr->accumulator = 0x0; io_sensor_ptr->sample = 0x0; @@ -266,6 +268,9 @@ void sensor_update( sensor_t * io_sensor_ptr, const uint16_t i_sensor_value) sensor_reset(io_sensor_ptr); } + // update timestamp + io_sensor_ptr->timestamp = G_current_tick; + // update sample value io_sensor_ptr->sample = i_sensor_value; @@ -280,6 +285,7 @@ void sensor_update( sensor_t * io_sensor_ptr, const uint16_t i_sensor_value) // add sample value to accumulator io_sensor_ptr->accumulator += i_sensor_value; + // increment update tag io_sensor_ptr->update_tag += 1; } diff --git a/src/occ_405/sensor/sensor.h b/src/occ_405/sensor/sensor.h index 7b49865..c28b0cd 100755 --- a/src/occ_405/sensor/sensor.h +++ b/src/occ_405/sensor/sensor.h @@ -171,6 +171,7 @@ typedef struct sensorStatus sensorStatus_t; struct sensor { uint16_t gsid; // Global Sensor ID + uint64_t timestamp; // Timestamp for latest sample uint16_t sample; // Latest sample of this sensor uint16_t sample_min; // Minimum value since last OCC reset uint16_t sample_max; // Maximum value since last OCC reset diff --git a/src/occ_405/sensor/sensor_main_memory.c b/src/occ_405/sensor/sensor_main_memory.c new file mode 100644 index 0000000..39f2b21 --- /dev/null +++ b/src/occ_405/sensor/sensor_main_memory.c @@ -0,0 +1,1511 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/sensor/sensor_main_memory.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017,2017 */ +/* [+] International Business Machines 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. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +/** + * @file sensor_main_memory.c + * + * This file defines the functions and global variables for copying a subset of + * the OCC sensors to main memory. See the header file for more information. + */ + +//****************************************************************************** +// Includes +//****************************************************************************** +#include // Primary header +#include // For uint*_t +#include // For memset(), memcpy() +#include // For sensor data structures +#include // For bool +#include // For G_occ_role, OCC_SLAVE +#include // For size_t, DMA_BUFFER, STATIC_ASSERT +#include // For OCC reason codes +#include // For sensor module ids +#include // For trace macros +#include // For bce_request_*(), async_request_is_idle() +#include // For G_apss_ch_to_function + + +//****************************************************************************** +// Main Memory Sensors - Private Defines/Structs/Globals +//****************************************************************************** + +/** + * Main memory sensor struct. Represents one OCC sensor that should be copied + * to main memory. Uses bit fields to reduce memory usage. + */ +typedef struct __attribute__ ((packed)) +{ + uint16_t gsid; ///< Global Sensor ID + uint8_t smf_mode : 1; ///< Is sensor copied when SMF mode enabled? + uint8_t master_only : 1; ///< Is sensor only available from master OCC? + uint8_t valid : 1; ///< Is sensor valid (able to be copied)? + uint8_t enabled : 1; ///< Is sensor enabled (chosen to be copied)? + uint8_t struct_ver : 2; ///< See MM_SENSOR_NAMES_STRUCT_VERSION_VALUES +} main_mem_sensor_t; + +/** + * Macro to build one main_mem_sensor_t instance. + */ +#define MAIN_MEM_SENSOR(gsid, smf_mode, master_only) \ + { gsid, smf_mode, master_only, true, true, MM_SENSOR_NAMES_STRUCT_VERSION_FULL } + +/** + * Macro to build main_mem_sensor_t instances for all processor cores. + */ +#define MAIN_MEM_CORE_SENSORS(gsid_prefix, smf_mode, master_only) \ + MAIN_MEM_SENSOR(gsid_prefix##0 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##1 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##2 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##3 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##4 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##5 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##6 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##7 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##8 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##9 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##10 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##11 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##12 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##13 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##14 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##15 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##16 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##17 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##18 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##19 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##20 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##21 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##22 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##23 , smf_mode, master_only) + +/** + * Macro to build main_mem_sensor_t instances for all memory DIMMs. + */ +#define MAIN_MEM_DIMM_SENSORS(gsid_prefix, smf_mode, master_only) \ + MAIN_MEM_SENSOR(gsid_prefix##00 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##01 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##02 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##03 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##04 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##05 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##06 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##07 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##08 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##09 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##10 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##11 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##12 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##13 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##14 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##15 , smf_mode, master_only) + +/** + * Macro to build main_mem_sensor_t instances for all APSS channels. + */ +#define MAIN_MEM_APSSCH_SENSORS(gsid_prefix, smf_mode, master_only) \ + MAIN_MEM_SENSOR(gsid_prefix##0 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##1 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##2 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##3 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##4 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##5 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##6 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##7 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##8 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##9 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##10 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##11 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##12 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##13 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##14 , smf_mode, master_only) , \ + MAIN_MEM_SENSOR(gsid_prefix##15 , smf_mode, master_only) + +/** + * Array of main memory sensors. This is the set of OCC sensors that will be + * copied to main memory. + * + * Note the array is NOT indexed by global sensor ID. This is because only a + * subset of OCC sensors are copied to main memory. + * + * The sensors MUST be grouped by sensor type (AMEC_SENSOR_TYPE). Sensors are + * enabled/disabled by type, so we want sensors of the same type in contiguous + * memory in the Sensor Readings Buffer. This will minimize the number of BCE + * copy operations needed to update the sensor readings when some sensors are + * disabled. + */ +main_mem_sensor_t G_main_mem_sensors[] = +{ + // AMEC_SENSOR_TYPE_TEMP: gsid smf_mode master_only + MAIN_MEM_CORE_SENSORS (TEMPPROCTHRMC, false, false), + MAIN_MEM_DIMM_SENSORS (TEMPDIMM, false, false), + + // AMEC_SENSOR_TYPE_UTIL: gsid smf_mode master_only + MAIN_MEM_CORE_SENSORS (UTILC, false, false), + + // AMEC_SENSOR_TYPE_FREQ: gsid smf_mode master_only + MAIN_MEM_CORE_SENSORS (FREQAC, true, false), + + // AMEC_SENSOR_TYPE_POWER: gsid smf_mode master_only + MAIN_MEM_SENSOR (PWRSYS, true, true ), + MAIN_MEM_APSSCH_SENSORS (PWRAPSSCH, true, true ), + MAIN_MEM_SENSOR (PWRPROC, true, false), + + // AMEC_SENSOR_TYPE_PERF: gsid smf_mode master_only + MAIN_MEM_SENSOR (PROCPWRTHROT, false, false), + MAIN_MEM_SENSOR (PROCOTTHROT, false, false), + MAIN_MEM_SENSOR (MEMPWRTHROT, false, false), + MAIN_MEM_SENSOR (MEMOTTHROT, false, false) +}; + +/** + * Number of main memory sensors (in G_main_mem_sensors). + * + * Note that some sensors might not be valid or enabled, and as a result they + * will not be copied to main memory. + */ +#define MAIN_MEM_SENSOR_COUNT (sizeof(G_main_mem_sensors) / sizeof(G_main_mem_sensors[0])) + +/* + * Check if Sensor Names Block is too small to hold all of the main memory + * sensors. If so generate a compile-time error. + */ +#define MM_SENSOR_NAMES_SIZE_NEEDED \ + (MAIN_MEM_SENSOR_COUNT * sizeof(mm_sensor_names_entry_t)) +STATIC_ASSERT( (MM_SENSOR_NAMES_SIZE_NEEDED > MM_SENSOR_NAMES_SIZE) ) + +/* + * Check if Sensor Readings Buffer is too small to hold all of the main memory + * sensors. If so generate a compile-time error. + * + * Note: This assumes the 'worst case' scenario where all main memory sensors + * use the full sensor readings structure. In reality a few of the main memory + * sensors use the smaller counter sensor readings structure. If full accuracy + * is required, a new #define could be created that contained the number of + * sensors using the counter structure. The equation could then use this new + * #define to calculate the exact number of bytes needed. + */ +#define MM_SENSOR_READINGS_SIZE_NEEDED \ + (sizeof(mm_sensor_readings_buf_header_t) + \ + (MAIN_MEM_SENSOR_COUNT * sizeof(mm_sensor_readings_full_t))) +STATIC_ASSERT( (MM_SENSOR_READINGS_SIZE_NEEDED > MM_SENSOR_READINGS_SIZE) ) + + +//****************************************************************************** +// Block Copy Engine (BCE) - Private Defines/Globals +//****************************************************************************** + +/** + * Size of the buffer used with the Block Copy Engine. 4kB is the maximum size + * supported by the BCE. + */ +#define MM_SENSORS_BCE_BUF_SIZE 4096 + +/** + * Buffer that contains sensor data to copy to main memory using the BCE. Use + * DMA_BUFFER macro so buffer is 128-byte aligned as required by the BCE. + */ +DMA_BUFFER(uint8_t G_mm_sensors_bce_buffer[MM_SENSORS_BCE_BUF_SIZE]) = {0}; + +/** + * BCE request structure. Used by BCE functions to schedule copy request. + */ +BceRequest G_mm_sensors_bce_req; + +/** + * Specifies whether the BCE request was scheduled. If false, the request + * finished or has never been scheduled/initialized. + */ +bool G_mm_sensors_bce_req_scheduled = false; + +/** + * Minimum number of bytes that can be written by the BCE. Since the BCE write + * size has to be a multiple of 128, the minimum is 128. + */ +#define MM_SENSORS_MIN_WRITE_SIZE 128 + +/** + * Buffer used to save 128 bytes from a BCE write so they can later be modified. + * + * The minimum write size of the Block Copy Engine is 128 bytes. This is + * problematic when trying to write less than 128 bytes, such as when modifying + * one field in a previously written data structure in main memory. + * + * To work around this limitation, a 128 byte range can be saved in this buffer. + * The saved bytes can be modified later, copied back into the BCE buffer, and + * re-written to main memory. + * + * Example: + * BCE Buffer Contents: AABBBBCDEE... + * BCE Buffer Offset: 0123456789... + * ^ + * | + * field to modify later + * + * AA is the two byte value of field A, BBBB is the four byte value of field + * B, etc. + * + * We want to later change the value of field C at offset 6. However, we must + * write at least 128 bytes. To do this, we need to save the values of the + * bytes before this field (offset 0-5) and after this field (offset 7-127). + */ +uint8_t G_mm_sensors_save_buffer[MM_SENSORS_MIN_WRITE_SIZE] = {0}; + +/** + * Buffer used to save the last 128 bytes written by the BCE. + * + * The Block Copy Engine requires the main memory address to be 128-byte + * aligned. This is problematic when trying to write to a non-aligned address, + * such as when writing data structures whose size is not a multiple of 128. + * + * To work around this limitation the following technique is used: + * - The BCE buffer is always associated with a 128-byte aligned address. + * - Data structures are stored in the BCE buffer until it is full. + * - No partial data structures are stored in the BCE buffer. The buffer is + * padded with zero bytes at the end if needed. + * - The BCE buffer is copied to main memory. + * - The last 128 bytes of the BCE buffer are stored in G_mm_sensors_last_write_buf. + * - The BCE buffer is cleared. + * - The 128 bytes in G_mm_sensors_last_write_buf are copied to the beginning + * of the BCE buffer. + * - The BCE buffer is now associated with the address of the 128 byte range + * stored in G_mm_sensors_last_write_buf. + * - More data structures are stored in the BCE buffer. If the first data + * structure stored has a non-aligned address, the data structure will be + * stored at a non-zero offset from the beginning of the BCE buffer. The + * preceding bytes in the BCE buffer will have the correct contents due to + * G_mm_sensors_last_write_buf. + * + * Example: + * BCE Buffer Contents: ...XXXXX...XXXXX000 + * ^ + * | + * offset of next data structure + * + * Bytes marked with an 'X' represent data structures stored in the last 128 + * bytes of the BCE buffer. Bytes marked with a '0' represent the remaining + * empty space in the buffer. Those bytes contain the value 0x00. + * + * Only 3 bytes of empty space remain in the BCE buffer. The next data + * structure to write requires 48 bytes. We do not write partial data + * structures, so we will wait until the next BCE operation to write that data + * structure. + * + * The address for the next BCE operation must be 128-byte aligned. The + * address where the next data structure will be stored is NOT 128-byte + * aligned. To work around this, we save the last 128 bytes of the BCE + * buffer. When we start the next BCE operation, we copy those 128 bytes into + * the beginning of the BCE buffer. + * + * Next BCE Buffer Contents: XXXXX...XXXXX000... + * ^ ^ + * | | + * | offset of next data structure + * 128-byte aligned address + */ +uint8_t G_mm_sensors_last_write_buf[MM_SENSORS_MIN_WRITE_SIZE] = {0}; + +/** + * Main memory address associated with the bytes in G_mm_sensors_last_write_buf. + */ +uint32_t G_mm_sensors_last_write_buf_addr = 0x00000000; + +/** + * Returns the specified number aligned to a 128-byte boundary. Rounds the + * number up to the next multiple of 128 if needed. + * + * This macro is used when calculating how many bytes to write using the BCE. + * The BCE write length must be a multiple of 128. + */ +#define MM_SENSORS_ALIGN_128_UP(number) \ + ((((number) % 128) == 0) ? (number) : ((number) + (128 - ((number) % 128)))) + +/** + * Returns the specified number aligned to a 128-byte boundary. Rounds the + * number down to the previous multiple of 128 if needed. + * + * This macro is used when determining the main memory address for a BCE write. + * The main memory address must be 128-byte aligned. + */ +#define MM_SENSORS_ALIGN_128_DOWN(number) \ + ((((number) % 128) == 0) ? (number) : ((number) - ((number) % 128))) + + +//****************************************************************************** +// Other Private Defines/Enums/Structs/Globals +//****************************************************************************** + +/** + * States of the main memory sensors system. The state name indicates the + * action that needs to be taken. + */ +typedef enum +{ + MM_SENSORS_WRITE_DATA_HEADER, ///< Write Sensor Data Header Block + MM_SENSORS_WRITE_SENSOR_NAMES, ///< Write Sensor Names Block + MM_SENSORS_VALIDATE_DATA_HEADER, ///< Set valid field in Data Header Block + MM_SENSORS_WRITE_SENSOR_READINGS, ///< Write Sensor Readings Buffer + MM_SENSORS_VALIDATE_SENSOR_READINGS, ///< Set valid field in Readings Buffer +} MM_SENSORS_STATE; + +/** + * Current state of the main memory sensors system + */ +uint8_t G_mm_sensors_state = MM_SENSORS_WRITE_DATA_HEADER; + +/** + * Address of the current Sensor Readings Buffer. Value will be either + * MM_SENSOR_READINGS_PING_ADDRESS or MM_SENSOR_READINGS_PONG_ADDRESS. + * main_mem_sensors_update() alternates between the ping and pong buffer. + * + * Note the value cannot be initialized here (at compile time) because the + * address is dependent on which OCC we are on. + */ +uint32_t G_mm_sensor_readings_buf_addr; + +/** + * Offset to the first sensor readings in a Sensor Readings Buffer. They are + * located after the Sensor Readings Buffer Header. + */ +#define MM_SENSORS_FIRST_READINGS_OFFSET sizeof(mm_sensor_readings_buf_header_t) + + +//****************************************************************************** +// Public Globals +//****************************************************************************** + +// See description in header file +bool G_main_mem_sensors_initialized = false; + +// See description in header file +bool G_main_mem_sensors_smf_mode_enabled = false; + + +//****************************************************************************** +// Private Functions +//****************************************************************************** + +/** + * Initializes internal data structures. + */ +void mm_sensors_init_internals(void) +{ + // Initialize address of current Sensor Readings Buffer address. Start with + // ping buffer. main_mem_sensors_update() alternates between ping and pong. + G_mm_sensor_readings_buf_addr = MM_SENSOR_READINGS_PING_ADDRESS; + + // Initialize the array of main memory sensors. Set sensor fields that + // cannot be initialized at compile time. + uint16_t l_index; + for (l_index = 0; l_index < MAIN_MEM_SENSOR_COUNT; ++l_index) + { + main_mem_sensor_t * l_mm_sensor = &G_main_mem_sensors[l_index]; + + // Set valid field based on SMF mode and OCC role + if (G_main_mem_sensors_smf_mode_enabled && !l_mm_sensor->smf_mode) + { + // SMF mode is enabled and sensor is not copied when in SMF mode + l_mm_sensor->valid = false; + } + else if ((G_occ_role == OCC_SLAVE) && l_mm_sensor->master_only) + { + // OCC is a slave and sensor is only available from the OCC master + l_mm_sensor->valid = false; + } + else + { + l_mm_sensor->valid = true; + } + + // Set struct_ver field based on units field in corresponding sensor_info_t. + // Units value of "#" means use counter structure for sensor readings. + uint16_t l_gsid = l_mm_sensor->gsid; + const char * l_units = G_sensor_info[l_gsid].sensor.units; + if ((l_units[0] == '#') && (l_units[1] == '\0')) + { + l_mm_sensor->struct_ver = MM_SENSOR_NAMES_STRUCT_VERSION_COUNTER; + } + else + { + l_mm_sensor->struct_ver = MM_SENSOR_NAMES_STRUCT_VERSION_FULL; + } + } +} + + +/** + * Returns the number of valid main memory sensors for this OCC. Static sensor + * data is only copied to main memory when the sensor is valid. Some sensors + * are invalid if SMF mode is enabled or the OCC is a slave. + * + * @return Number of valid main memory sensors + */ +uint16_t mm_sensors_valid_sensor_count(void) +{ + uint16_t l_count = 0; + + // Loop through all main memory sensors + uint16_t l_index; + for (l_index = 0; l_index < MAIN_MEM_SENSOR_COUNT; ++l_index) + { + if (G_main_mem_sensors[l_index].valid) + { + ++l_count; + } + } + + return l_count; +} + + +/** + * Returns the number of main memory sensors that are both valid and enabled. + * Sensor readings (dynamic data) are only copied to main memory when the sensor + * is valid and enabled. + * + * Sensors may be invalid due to the SMF Mode or OCC role. Sensors are enabled + * or disabled dynamically by external software such as OPAL. + * + * @return Number of main memory sensors that are both valid and enabled + */ +uint16_t mm_sensors_valid_enabled_sensor_count(void) +{ + uint16_t l_count = 0; + + // Loop through all main memory sensors + uint16_t l_index; + for (l_index = 0; l_index < MAIN_MEM_SENSOR_COUNT; ++l_index) + { + if (G_main_mem_sensors[l_index].valid && G_main_mem_sensors[l_index].enabled) + { + ++l_count; + } + } + + return l_count; +} + + +/** + * Logs an error caused by the Block Copy Engine. Does nothing if a BCE error + * has already been logged. + * + * Note that the required error log comment containing tags like 'userdata4' and + * 'devdesc' must be located by the call to this function. It is not located + * inside this function because the value of those tags varies. + * + * @param i_modId Module ID + * @param i_extReasonCode Extended reason code + * @param i_userData1 Userdata1 value + * @param i_userData2 Userdata2 value + */ +void mm_sensors_log_bce_error(uint16_t i_modId, uint16_t i_extReasonCode, + uint32_t i_userData1, uint32_t i_userData2) +{ + static bool L_error_logged = false; + if (!L_error_logged) + { + // Create and commit error + errlHndl_t l_errl = createErrl(i_modId, // Module ID + SENSOR_MAIN_MEM_ERROR, // Reason code + i_extReasonCode, // Extended reason code + ERRL_SEV_INFORMATIONAL, // Severity + NULL, // Trace Buffers + DEFAULT_TRACE_SIZE, // Trace Size + i_userData1, // Userdata1 + i_userData2); // Userdata2 + commitErrl(&l_errl); + L_error_logged = true; + } +} + + +/** + * Returns whether the global BCE request struct is idle and ready for re-use. + * Returns true immediately if the request was not scheduled. If the request + * was scheduled, checks to see if it has finished. + * + * @param i_caller_mod_id Module ID of calling function in case an error occurs + * @return True if BCE request is idle, false otherwise + */ +bool mm_sensors_is_bce_req_idle(uint16_t i_caller_mod_id) +{ + // Number of times we've waited for current request to finish + static uint8_t L_wait_count = 0; + + // If the request was not previously scheduled, then it is idle. This also + // handles the case where the request has not been initialized yet. + if (!G_mm_sensors_bce_req_scheduled) + { + return true; + } + + // Request was scheduled; check if it finished and is now idle + if (async_request_is_idle(&G_mm_sensors_bce_req.request)) + { + // Request is now idle and ready for re-use + G_mm_sensors_bce_req_scheduled = false; + + // If we were waiting for request to finish, trace and clear wait count + if (L_wait_count > 0) + { + TRAC_INFO("mm_sensors_is_bce_req_idle: " + "Request finished after waiting %u times: caller=0x%04X", + L_wait_count, i_caller_mod_id); + L_wait_count = 0; + } + return true; + } + + // Request was scheduled but has not finished. Increment wait count unless + // we are already at the max (to avoid overflow). + if (L_wait_count < UINT8_MAX) + { + ++L_wait_count; + } + + // If this is the first time we've waited for this request, trace it + if (L_wait_count == 1) + { + TRAC_INFO("mm_sensors_is_bce_req_idle: " + "Waiting for request to finish: caller=0x%04X", + i_caller_mod_id); + } + + // If this is the second time we've waited for this request, log BCE error + if (L_wait_count == 2) + { + /* @ + * @errortype + * @moduleid MM_SENSORS_IS_BCE_REQ_IDLE_MOD + * @reasoncode SENSOR_MAIN_MEM_ERROR + * @userdata1 Caller module ID + * @userdata2 0 + * @userdata4 ERC_GENERIC_TIMEOUT + * @devdesc BCE request not finished after waiting twice + */ + mm_sensors_log_bce_error(MM_SENSORS_IS_BCE_REQ_IDLE_MOD, ERC_GENERIC_TIMEOUT, + i_caller_mod_id, 0); + } + + // Return false since request is not idle + return false; +} + + +/** + * Copies the specified number of bytes from G_mm_sensors_bce_buffer to + * the specified main memory address using the Block Copy Engine (BCE). + * + * Schedules the copy request with the BCE but does not block waiting for the + * request to finish. Call mm_sensors_is_bce_req_idle() to determine when the + * request is finished and the copying has occurred. + * + * This function must not be called if a previous copy request has not yet + * finished. + * + * @param i_main_mem_addr Main memory address to which bytes will be copied. + * Must be 128-byte aligned. + * @param i_byte_count Number of bytes to copy. Must be multiple of 128. + * Must be <= MM_SENSORS_BCE_BUF_SIZE. If 0 specified, + * function will return true and will not use the BCE. + * @param i_caller_mod_id Module ID of the calling function in case an error occurs + * @return True if BCE request was successfully scheduled, false otherwise + */ +bool mm_sensors_bce_copy(uint32_t i_main_mem_addr, size_t i_byte_count, + uint16_t i_caller_mod_id) +{ + // Verify main memory address and byte count are valid + static bool L_traced_param_error = false; + if (((i_main_mem_addr % 128) != 0) || ((i_byte_count % 128) != 0) || + (i_byte_count > MM_SENSORS_BCE_BUF_SIZE)) + { + if (!L_traced_param_error) + { + TRAC_ERR("mm_sensors_bce_copy: Input parameter error: " + "address=0x%08X length=%u caller=0x%04X", + i_main_mem_addr, i_byte_count, i_caller_mod_id); + L_traced_param_error = true; + } + return false; + } + + // Check if a copy request was previously scheduled and is not yet finished + static bool L_traced_sched_error = false; + if (G_mm_sensors_bce_req_scheduled) + { + if (!L_traced_sched_error) + { + TRAC_ERR("mm_sensors_bce_copy: Previous request not finished: caller=0x%04X", + i_caller_mod_id); + L_traced_sched_error = true; + } + return false; + } + + // Check if byte count is 0. If so return true and don't use BCE. + if (i_byte_count == 0) + { + return true; + } + + // Create BCE request + int l_rc = bce_request_create(&G_mm_sensors_bce_req, // Block copy request + &G_pba_bcue_queue, // Queue (SRAM up to mainstore) + i_main_mem_addr, // Mainstore address + (uint32_t) &G_mm_sensors_bce_buffer, // SRAM start address + i_byte_count, // Size of copy + SSX_WAIT_FOREVER, // No timeout + NULL, // No call back + NULL, // No call back args + 0x00); // No options; non-blocking + if (l_rc != SSX_OK) + { + TRAC_ERR("mm_sensors_bce_copy: Request create failure: rc=0x%08X caller=0x%04X", + -l_rc, i_caller_mod_id); + /* @ + * @errortype + * @moduleid MM_SENSORS_BCE_COPY_MOD + * @reasoncode SENSOR_MAIN_MEM_ERROR + * @userdata1 Return code from bce_request_create() + * @userdata2 Caller module ID + * @userdata4 ERC_BCE_REQUEST_CREATE_FAILURE + * @devdesc Failed to create BCE request + */ + mm_sensors_log_bce_error(MM_SENSORS_BCE_COPY_MOD, ERC_BCE_REQUEST_CREATE_FAILURE, + -l_rc, i_caller_mod_id); + return false; + } + + // Schedule BCE request + l_rc = bce_request_schedule(&G_mm_sensors_bce_req); + if (l_rc != SSX_OK) + { + TRAC_ERR("mm_sensors_bce_copy: Request schedule failure: rc=0x%08X caller=0x%04X", + -l_rc, i_caller_mod_id); + /* @ + * @errortype + * @moduleid MM_SENSORS_BCE_COPY_MOD + * @reasoncode SENSOR_MAIN_MEM_ERROR + * @userdata1 Return code from bce_request_schedule() + * @userdata2 Caller module ID + * @userdata4 ERC_BCE_REQUEST_SCHEDULE_FAILURE + * @devdesc Failed to schedule BCE request + */ + mm_sensors_log_bce_error(MM_SENSORS_BCE_COPY_MOD, ERC_BCE_REQUEST_SCHEDULE_FAILURE, + -l_rc, i_caller_mod_id); + return false; + } + + // Successfully scheduled request. Copy is not blocking, so need to check + // whether it finished later. Set flag indicating request is scheduled. + G_mm_sensors_bce_req_scheduled = true; + return true; +} + + +/** + * Saves the last 128 bytes that were written using the BCE buffer. The bytes + * are stored in G_mm_sensors_last_write_buf. The main memory address of the + * last 128 bytes is stored in G_mm_sensors_last_write_buf_addr. + * + * See documentation by G_mm_sensors_last_write_buf for more details on how this + * buffer is used. + * + * @param i_main_mem_addr Main memory address where BCE buffer was written. + * Must be 128-byte aligned. + * @param i_byte_count Number of bytes written. Must be multiple of 128. + */ +void mm_sensors_save_last_write(uint32_t i_main_mem_addr, size_t i_byte_count) +{ + // Make sure at least 128 bytes were written + if (i_byte_count >= MM_SENSORS_MIN_WRITE_SIZE) + { + // Calculate BCE buffer offset to last 128 bytes + uint16_t l_offset = i_byte_count - MM_SENSORS_MIN_WRITE_SIZE; + + // Copy last 128 bytes into last write buffer + memcpy(G_mm_sensors_last_write_buf, &G_mm_sensors_bce_buffer[l_offset], + MM_SENSORS_MIN_WRITE_SIZE); + + // Save main memory address where last 128 bytes were written + G_mm_sensors_last_write_buf_addr = i_main_mem_addr + l_offset; + } +} + + +/** + * Initializes the specified Sensor Data Header Block struct. + * + * @param o_header Header to initialize + */ +void mm_sensors_init_data_header(mm_sensor_data_header_block_t * o_header) +{ + // Get number of valid sensors that will be copied to main memory. Some + // sensors may be invalid due to the SMF mode or OCC role. + uint16_t l_number_of_valid_sensors = mm_sensors_valid_sensor_count(); + + // Zero out entire structure including reserved bytes + memset(o_header, 0x00, sizeof(mm_sensor_data_header_block_t)); + + // Set struct field values. The valid field is set to false (0x00) because + // the Sensor Names Block has not yet been written. + o_header->valid = MM_SENSOR_DATA_HEADER_VALID_FALSE; + o_header->header_version = MM_SENSOR_DATA_HEADER_VERSION; + o_header->number_of_sensors = l_number_of_valid_sensors; + o_header->sensor_readings_version = MM_SENSOR_READINGS_VERSION; + o_header->sensor_names_offset = MM_SENSOR_NAMES_OFFSET; + o_header->sensor_names_version = MM_SENSOR_NAMES_VERSION; + o_header->bytes_per_sensor_name = sizeof(mm_sensor_names_entry_t); + o_header->ping_buffer_offset = MM_SENSOR_READINGS_PING_OFFSET; + o_header->pong_buffer_offset = MM_SENSOR_READINGS_PONG_OFFSET; +} + + +/** + * Writes the Sensor Data Header Block in main memory. If successful, changes + * the current state to MM_SENSORS_WRITE_SENSOR_NAMES. + */ +void mm_sensors_write_data_header(void) +{ + // Clear the BCE buffer + memset(G_mm_sensors_bce_buffer, 0x00, MM_SENSORS_BCE_BUF_SIZE); + + // Initialize a mm_sensor_data_header_block_t struct + mm_sensor_data_header_block_t l_header; + mm_sensors_init_data_header(&l_header); + + // Copy struct bytes to BCE buffer + memcpy(G_mm_sensors_bce_buffer, &l_header, sizeof(l_header)); + + // Save the first 128 bytes of the BCE buffer. Needed later by + // mm_sensors_validate_data_header() to modify the valid field of the header. + memcpy(G_mm_sensors_save_buffer, G_mm_sensors_bce_buffer, MM_SENSORS_MIN_WRITE_SIZE); + + // Calculate number of bytes to copy. The BCE requires this to be a + // multiple of 128. May end up copying extra zeroed out bytes in BCE buffer. + size_t l_byte_count = sizeof(l_header); + l_byte_count = MM_SENSORS_ALIGN_128_UP(l_byte_count); + + // Copy Sensor Data Header Block to main memory using BCE + if (mm_sensors_bce_copy(MM_SENSOR_DATA_HEADER_ADDRESS, l_byte_count, + MM_SENSORS_WRITE_DATA_HDR_MOD)) + { + // Copy succeeded. Change state to write Sensor Names Block. + G_mm_sensors_state = MM_SENSORS_WRITE_SENSOR_NAMES; + } +} + + +/** + * Validates the Sensor Data Header Block in main memory. + * + * Sets the valid field in the Sensor Data Header Block to true indicating that + * the Sensor Names Block has been written. + * + * If successful: + * - Sets G_main_mem_sensors_initialized to true + * - Changes current state to MM_SENSORS_WRITE_SENSOR_READINGS. + */ +void mm_sensors_validate_data_header(void) +{ + // Clear the BCE buffer + memset(G_mm_sensors_bce_buffer, 0x00, MM_SENSORS_BCE_BUF_SIZE); + + // We need to modify the valid field of the Sensor Data Header Block. + // However, the BCE does not support writing a single byte. The minimum + // write size is 128 bytes. To work around this, we saved the first 128 + // bytes of header data in mm_sensors_write_data_header(). Copy those saved + // bytes back into the BCE buffer. + memcpy(G_mm_sensors_bce_buffer, G_mm_sensors_save_buffer, MM_SENSORS_MIN_WRITE_SIZE); + + // Cast BCE buffer to a mm_sensor_data_header_block_t * + mm_sensor_data_header_block_t * l_header = + (mm_sensor_data_header_block_t *) (&G_mm_sensors_bce_buffer); + + // Set the valid field to true since Sensor Names Block has been written + l_header->valid = MM_SENSOR_DATA_HEADER_VALID_TRUE; + + // Copy first 128 bytes of Sensor Data Header Block to main memory using BCE + if (mm_sensors_bce_copy(MM_SENSOR_DATA_HEADER_ADDRESS, MM_SENSORS_MIN_WRITE_SIZE, + MM_SENSORS_VALIDATE_DATA_HDR_MOD)) + { + // Copy succeeded. Set global indicating all initialization complete. + G_main_mem_sensors_initialized = true; + + // Change state to write to Sensor Readings Buffer + G_mm_sensors_state = MM_SENSORS_WRITE_SENSOR_READINGS; + } +} + + +/** + * Initializes the specified Sensor Names Block entry. Sets entry fields to + * the static sensor data for the specified main memory sensor. + * + * @param i_mm_sensor Main memory sensor + * @param i_readings_offset Offset to sensor readings in Sensor Readings Buffer + * @param o_entry Sensor Names Block entry to initialize + */ +void mm_sensors_init_names_entry(const main_mem_sensor_t * i_mm_sensor, + uint32_t i_readings_offset, + mm_sensor_names_entry_t * o_entry) +{ + // Get GSID of main memory sensor + uint16_t l_gsid = i_mm_sensor->gsid; + + // Find the sensor specific info, if any + uint8_t l_sensor_specific_info1 = 0; + if ((l_gsid >= PWRAPSSCH0) && (l_gsid <= PWRAPSSCH15)) + { + // For APSS channel sensors, set to ADC func ID + uint8_t l_channel_num = (l_gsid - PWRAPSSCH0); + l_sensor_specific_info1 = G_apss_ch_to_function[l_channel_num]; + } + + // Get sensor_info_t struct with static data for this sensor + const sensor_info_t * l_sensor_info = &G_sensor_info[l_gsid]; + + // Zero out entire entry structure including reserved bytes + memset(o_entry, 0x00, sizeof(mm_sensor_names_entry_t)); + + // Set entry struct field values + memcpy(o_entry->name, l_sensor_info->name, MAX_SENSOR_NAME_SZ); + memcpy(o_entry->units, l_sensor_info->sensor.units, MAX_SENSOR_UNIT_SZ); + o_entry->gsid = l_gsid; + o_entry->freq = l_sensor_info->sensor.freq; + o_entry->scale_factor = l_sensor_info->sensor.scalefactor; + o_entry->type = l_sensor_info->sensor.type; + o_entry->location = l_sensor_info->sensor.location; + o_entry->sensor_structure_version = i_mm_sensor->struct_ver; + o_entry->reading_offset = i_readings_offset; + o_entry->sensor_specific_info1 = l_sensor_specific_info1; +} + + +/** + * Writes static sensor data to the Sensor Names Block in main memory. + * + * Only valid sensors are written to the Sensor Names Block. Sensors may be + * invalid due to the SMF Mode or OCC role. + * + * This function must be called repeatedly until the entire Sensor Names Block + * has been written. The BCE can copy a maximum of 4kB at a time, and the + * Sensor Names Block is up to 50kB. Non-blocking copies are performed, so each + * time this function is called it will schedule a copy of up to 4kB. Static + * variables are used to save state across function calls. + * + * When using the BCE, the main memory address and byte count must both be + * 128-byte aligned. The Sensor Names Block entries are not a multiple of 128 + * bytes in length. If the BCE buffer is nearly full and does not have enough + * room for another complete Sensor Names Block entry, the entry will not be + * partially written. The BCE buffer will be padded at the end with zeroes, and + * the entry will be written next time the function is called. + * + * When calling this function more than once, the main memory address of the + * next Sensor Names Block entry will probably not be 128-byte aligned. The + * buffer G_mm_sensors_last_write_buf is used to work around this. See the + * doxygen comments by G_mm_sensors_last_write_buf for more information. + * + * When the Sensor Names Block has been completely written this function changes + * the current state to MM_SENSORS_VALIDATE_DATA_HEADER. + */ +void mm_sensors_write_sensor_names(void) +{ + // Saved state from previous function call + static uint16_t L_saved_sensor_index = 0; + static uint32_t L_saved_entry_offset = 0; + static uint32_t L_saved_readings_offset = MM_SENSORS_FIRST_READINGS_OFFSET; + + // Load saved state from previous function call into local variables + uint16_t l_sensor_index = L_saved_sensor_index; + uint32_t l_entry_offset = L_saved_entry_offset; + uint32_t l_readings_offset = L_saved_readings_offset; + + // Calculate main memory address for writing to the Sensor Names Block. The + // address must be 128-byte aligned. + uint32_t l_entry_addr = MM_SENSOR_NAMES_ADDRESS + l_entry_offset; + uint32_t l_write_addr = MM_SENSORS_ALIGN_128_DOWN(l_entry_addr); + + // Calculate offset within BCE buffer where current entry should be stored. + // Since the write address must be 128-byte aligned, the current entry might + // not start at the beginning of the BCE buffer. + uint16_t l_bce_buf_offset = l_entry_addr - l_write_addr; + + // Clear the BCE buffer + memset(G_mm_sensors_bce_buffer, 0x00, MM_SENSORS_BCE_BUF_SIZE); + + // If we previously wrote bytes to the same 128-byte aligned address, copy + // those bytes from the last write buffer. This will retain the value of + // the bytes that precede the current names entry. + if (G_mm_sensors_last_write_buf_addr == l_write_addr) + { + memcpy(G_mm_sensors_bce_buffer, G_mm_sensors_last_write_buf, + MM_SENSORS_MIN_WRITE_SIZE); + } + + // Loop through main memory sensors storing sensor names entries in BCE buffer + mm_sensor_names_entry_t l_entry; + size_t l_entry_size = sizeof(l_entry); + for (; l_sensor_index < MAIN_MEM_SENSOR_COUNT; ++l_sensor_index) + { + // Exit loop if BCE buffer does not have room for this entry + if ((l_bce_buf_offset + l_entry_size) > MM_SENSORS_BCE_BUF_SIZE) + { + break; + } + + // Skip sensor if it is not valid + main_mem_sensor_t * l_mm_sensor = &G_main_mem_sensors[l_sensor_index]; + if (!l_mm_sensor->valid) + { + continue; + } + + // Store sensor names entry in BCE buffer + mm_sensors_init_names_entry(l_mm_sensor, l_readings_offset, &l_entry); + memcpy(&G_mm_sensors_bce_buffer[l_bce_buf_offset], &l_entry, l_entry_size); + l_bce_buf_offset += l_entry_size; + l_entry_offset += l_entry_size; + l_readings_offset += MM_SENSOR_READINGS_STRUCT_SIZE(l_mm_sensor->struct_ver); + } + + // Calculate number of bytes to copy. The BCE requires this to be a + // multiple of 128. May end up copying extra zeroed out bytes in buffer. + size_t l_byte_count = MM_SENSORS_ALIGN_128_UP(l_bce_buf_offset); + + // Copy BCE buffer to Sensor Names Block in main memory + if (mm_sensors_bce_copy(l_write_addr, l_byte_count, MM_SENSORS_WRITE_NAMES_MOD)) + { + // Copy succeeded. Save state for next time function called. + L_saved_sensor_index = l_sensor_index; + L_saved_entry_offset = l_entry_offset; + L_saved_readings_offset = l_readings_offset; + + // Save last 128 bytes we wrote in case we need it for alignment + mm_sensors_save_last_write(l_write_addr, l_byte_count); + + // If all sensors have been written to the Sensor Names Block + if (l_sensor_index >= MAIN_MEM_SENSOR_COUNT) + { + // Change state to validate the Sensor Data Header Block + G_mm_sensors_state = MM_SENSORS_VALIDATE_DATA_HEADER; + } + } +} + + +/** + * Initializes the specified Sensor Readings Buffer Header struct. + * + * @param o_header Header to initialize + */ +void mm_sensors_init_readings_buf_header(mm_sensor_readings_buf_header_t * o_header) +{ + // Zero out entire header structure including reserved bytes + memset(o_header, 0x00, sizeof(mm_sensor_readings_buf_header_t)); + + // Set field values in Sensor Readings Buffer Header (currently only one field). + // Set valid field to false. Buffer is not valid until all readings copied. + o_header->valid = MM_SENSOR_READINGS_VALID_FALSE; +} + + +/** + * Skips the sensor readings for the current sensor. Does not store them in the + * BCE buffer. + * + * If the BCE buffer is currently empty, io_write_addr may be moved forward to + * the address for the next sensor. This avoids devoting BCE buffer space to + * the skipped sensor. + * + * @param i_mm_sensor Main memory sensor to skip + * @param io_readings_offset Offset to current sensor's readings within Sensor + * Readings Buffer + * @param io_write_addr Main memory address where the BCE buffer will be written + * @param i_byte_count Number of bytes in BCE buffer + */ +void mm_sensors_skip_readings(const main_mem_sensor_t * i_mm_sensor, + uint32_t * io_readings_offset, uint32_t * io_write_addr, + size_t i_byte_count) +{ + // If sensor is not valid, there is nothing to do. Invalid sensors are not + // written to the Sensor Names Block or the Sensor Readings Buffer. + if (!i_mm_sensor->valid) + { + return; + } + + // Sensor is valid but not enabled. It was written to the Sensor Names + // Block and has an offset defined within the Sensor Readings Buffer. + // However since it is not enabled we are not copying the readings. Do not + // modify i_byte_count since we are not storing readings in the BCE buffer. + + // Move the sensor readings offset to the next sensor + *io_readings_offset += MM_SENSOR_READINGS_STRUCT_SIZE(i_mm_sensor->struct_ver); + + // Check if BCE buffer is empty. If so, we can move the main memory address + // associated with the BCE buffer forward to the next sensor. + if (i_byte_count == 0) + { + // Calculate main memory address for writing the next sensor's readings. + // The address must be 128-byte aligned. + uint32_t l_next_readings_addr = G_mm_sensor_readings_buf_addr + *io_readings_offset; + uint32_t l_new_write_addr = MM_SENSORS_ALIGN_128_DOWN(l_next_readings_addr); + + // If the new main memory address is different + if (l_new_write_addr != *io_write_addr) + { + // Move forward to new write address + *io_write_addr = l_new_write_addr; + + // Clear the first 128 bytes of the BCE buffer. We may have copied in + // the last 128 bytes of sensor readings that were previously written. + // Those bytes are no longer correct since our address has changed. + memset(G_mm_sensors_bce_buffer, 0x00, MM_SENSORS_MIN_WRITE_SIZE); + } + } +} + + +/** + * Initializes the specified Full Sensor Readings Structure. Obtains sensor + * readings for the specified main memory sensor. + * + * @param i_mm_sensor Main memory sensor + * @param o_readings Full sensor readings structure to initialize + */ +void mm_sensors_init_readings_full(const main_mem_sensor_t * i_mm_sensor, + mm_sensor_readings_full_t * o_readings) +{ + // Get GSID of main memory sensor + uint16_t l_gsid = i_mm_sensor->gsid; + + // Get pointer to corresponding sensor_t that holds the sensor readings + const sensor_t * l_sensor = G_amec_sensor_list[l_gsid]; + + // Zero out entire readings structure including reserved bytes + memset(o_readings, 0x00, sizeof(mm_sensor_readings_full_t)); + + // Set struct field values + o_readings->gsid = l_gsid; + o_readings->timestamp = l_sensor->timestamp; + o_readings->sample = l_sensor->sample; + o_readings->sample_min = l_sensor->sample_min; + o_readings->sample_max = l_sensor->sample_max; + o_readings->csm_sample_min = l_sensor->csm_sample_min; + o_readings->csm_sample_max = l_sensor->csm_sample_max; + o_readings->profiler_sample_min = l_sensor->profiler_sample_min; + o_readings->profiler_sample_max = l_sensor->profiler_sample_max; + o_readings->job_s_sample_min = l_sensor->job_s_sample_min; + o_readings->job_s_sample_max = l_sensor->job_s_sample_max; + o_readings->accumulator = l_sensor->accumulator; + o_readings->update_tag = l_sensor->update_tag; +} + + +/** + * Initializes the specified Counter Sensor Readings Structure. Obtains sensor + * readings for the specified main memory sensor. + * + * @param i_mm_sensor Main memory sensor + * @param o_readings Counter sensor readings structure to initialize + */ +void mm_sensors_init_readings_counter(const main_mem_sensor_t * i_mm_sensor, + mm_sensor_readings_counter_t * o_readings) +{ + // Get GSID of main memory sensor + uint16_t l_gsid = i_mm_sensor->gsid; + + // Get pointer to corresponding sensor_t that holds the sensor readings + const sensor_t * l_sensor = G_amec_sensor_list[l_gsid]; + + // Zero out entire readings structure including reserved bytes + memset(o_readings, 0x00, sizeof(mm_sensor_readings_counter_t)); + + // Set struct field values + o_readings->gsid = l_gsid; + o_readings->timestamp = l_sensor->timestamp; + o_readings->accumulator = l_sensor->accumulator; + o_readings->sample = (l_sensor->sample > 0) ? 1 : 0; +} + + +/** + * Stores sensor readings in the BCE buffer at the specified offset for the + * specified sensor. + * + * @param i_mm_sensor Main memory sensor whose readings to store + * @param i_bce_buf_offset Offset in BCE buffer where readings should be stored + * @param io_readings_offset Offset to current sensor's readings within Sensor + * Readings Buffer + * @param o_byte_count Number of bytes in BCE buffer + */ +void mm_sensors_store_readings(const main_mem_sensor_t * i_mm_sensor, + uint16_t i_bce_buf_offset, uint32_t * io_readings_offset, + size_t * o_byte_count) +{ + // Store the correct sensor readings structure version + size_t l_readings_size = 0; + if (i_mm_sensor->struct_ver == MM_SENSOR_NAMES_STRUCT_VERSION_FULL) + { + // Store full sensor readings structure in BCE buffer + mm_sensor_readings_full_t l_readings; + mm_sensors_init_readings_full(i_mm_sensor, &l_readings); + l_readings_size = sizeof(l_readings); + memcpy(&G_mm_sensors_bce_buffer[i_bce_buf_offset], &l_readings, l_readings_size); + } + else + { + // Store counter sensor readings structure in BCE buffer + mm_sensor_readings_counter_t l_readings; + mm_sensors_init_readings_counter(i_mm_sensor, &l_readings); + l_readings_size = sizeof(l_readings); + memcpy(&G_mm_sensors_bce_buffer[i_bce_buf_offset], &l_readings, l_readings_size); + } + + // Move the sensor readings offset to the next sensor + *io_readings_offset += l_readings_size; + + // Update the number of bytes in the BCE buffer. Note that we do not simply + // add l_readings_size to o_byte_count. That is because we may have skipped + // one or more previous sensors because they were disabled. Skipped sensors + // do not update the byte count. We now need to write the entire BCE buffer + // up to this sensor's readings. Any disabled sensors within the BCE buffer + // range will have zeroes written to their offset in the Sensor Readings Buffer. + *o_byte_count = (i_bce_buf_offset + l_readings_size); +} + + +/** + * Writes sensor readings (dynamic data) to the current Sensor Readings Buffer + * (ping/pong) in main memory. + * + * Only valid and enabled sensors are written to the Sensor Readings Buffer. + * Sensors may be invalid due to the SMF Mode or OCC role. Sensors are enabled + * or disabled dynamically by external software such as OPAL. + * + * This function must be called repeatedly until the entire Sensor Readings + * Buffer has been written. The BCE can copy a maximum of 4kB at a time, and a + * Sensor Readings Buffer is up to 40kB. Non-blocking copies are performed, so + * each time this function is called it will schedule a copy of up to 4kB. + * Static variables are used to save state across function calls. + * + * When using the BCE, the main memory address and byte count must both be + * 128-byte aligned. The sensor readings structures are not a multiple of 128 + * bytes in length. If the BCE buffer is nearly full and does not have enough + * room for another complete sensor readings structure, the structure will not + * be partially written. The BCE buffer will be padded at the end with zeroes, + * and the structure will be written next time the function is called. + * + * When calling this function more than once, the main memory address of the + * next sensor readings structure will probably not be 128-byte aligned. The + * buffer G_mm_sensors_last_write_buf is used to work around this. See the + * doxygen comments by G_mm_sensors_last_write_buf for more information. + * + * When the Sensor Readings Buffer has been completely written this function + * changes the current state to MM_SENSORS_VALIDATE_SENSOR_READINGS. + */ +void mm_sensors_write_sensor_readings(void) +{ + // Saved state from previous function call + static uint16_t L_saved_sensor_index = 0; + static uint32_t L_saved_readings_offset = MM_SENSORS_FIRST_READINGS_OFFSET; + + // Load saved state from previous function call into local variables + uint16_t l_sensor_index = L_saved_sensor_index; + uint32_t l_readings_offset = L_saved_readings_offset; + + // If this is the first sensor and no sensors are valid and enabled, exit + // immediately. There are no sensor readings to write to main memory. + if ((l_sensor_index == 0) && (mm_sensors_valid_enabled_sensor_count() == 0)) + { + return; + } + + // Clear the BCE buffer + memset(G_mm_sensors_bce_buffer, 0x00, MM_SENSORS_BCE_BUF_SIZE); + + // Number of bytes we want to write in the BCE buffer + size_t l_byte_count = 0; + + // Main memory address for writing to the Sensor Readings Buffer + uint32_t l_write_addr; + + // If this is the first sensor + if (l_sensor_index == 0) + { + // Set main memory write address to beginning of Sensor Readings Buffer + l_write_addr = G_mm_sensor_readings_buf_addr; + + // Store Sensor Readings Buffer Header in BCE buffer + mm_sensor_readings_buf_header_t l_header; + mm_sensors_init_readings_buf_header(&l_header); + memcpy(G_mm_sensors_bce_buffer, &l_header, sizeof(l_header)); + l_byte_count = sizeof(l_header); + } + else + { + // Not the first sensor. Calculate main memory address for writing to + // the Sensor Readings Buffer. The address must be 128-byte aligned. + uint32_t l_readings_addr = G_mm_sensor_readings_buf_addr + l_readings_offset; + l_write_addr = MM_SENSORS_ALIGN_128_DOWN(l_readings_addr); + + // If we previously wrote bytes to the same 128-byte aligned address, copy + // those bytes from the last write buffer. This will retain the value of + // the bytes that precede the current sensor readings. + if (G_mm_sensors_last_write_buf_addr == l_write_addr) + { + memcpy(G_mm_sensors_bce_buffer, G_mm_sensors_last_write_buf, + MM_SENSORS_MIN_WRITE_SIZE); + } + } + + // Loop through main memory sensors storing readings in BCE buffer + for (; l_sensor_index < MAIN_MEM_SENSOR_COUNT; ++l_sensor_index) + { + // Exit loop if BCE buffer does not have room for this sensor's readings + main_mem_sensor_t * l_mm_sensor = &G_main_mem_sensors[l_sensor_index]; + uint32_t l_readings_addr = G_mm_sensor_readings_buf_addr + l_readings_offset; + uint16_t l_bce_buf_offset = l_readings_addr - l_write_addr; + size_t l_readings_size = MM_SENSOR_READINGS_STRUCT_SIZE(l_mm_sensor->struct_ver); + if ((l_bce_buf_offset + l_readings_size) > MM_SENSORS_BCE_BUF_SIZE) + { + break; + } + + // Skip sensor readings if sensor is not valid or not enabled + if (!l_mm_sensor->valid || !l_mm_sensor->enabled) + { + mm_sensors_skip_readings(l_mm_sensor, &l_readings_offset, &l_write_addr, + l_byte_count); + continue; + } + + // Store sensor readings in BCE buffer + mm_sensors_store_readings(l_mm_sensor, l_bce_buf_offset, &l_readings_offset, + &l_byte_count); + } + + // If we started at the first sensor, save first 128 bytes of the BCE + // buffer. Needed later by mm_sensors_validate_sensor_readings() to modify + // the valid field in the Sensor Readings Buffer Header. + if (L_saved_sensor_index == 0) + { + memcpy(G_mm_sensors_save_buffer, G_mm_sensors_bce_buffer, MM_SENSORS_MIN_WRITE_SIZE); + } + + // Calculate number of bytes to copy. The BCE requires this to be a + // multiple of 128. May end up copying extra zeroed out bytes in buffer. + l_byte_count = MM_SENSORS_ALIGN_128_UP(l_byte_count); + + // Copy BCE buffer to Sensor Readings Buffer in main memory + if (mm_sensors_bce_copy(l_write_addr, l_byte_count, MM_SENSORS_WRITE_READINGS_MOD)) + { + // Copy succeeded. Save state for next time function called. + L_saved_sensor_index = l_sensor_index; + L_saved_readings_offset = l_readings_offset; + + // Save last 128 bytes we wrote in case we need it for alignment + mm_sensors_save_last_write(l_write_addr, l_byte_count); + + // If all sensors have been written to the Sensor Readings Buffer + if (l_sensor_index >= MAIN_MEM_SENSOR_COUNT) + { + // Reset state. Next time this function is called we will be + // writing to the other Sensor Readings Buffer (ping/pong). + L_saved_sensor_index = 0; + L_saved_readings_offset = MM_SENSORS_FIRST_READINGS_OFFSET; + + // Change state to validate current Sensor Readings Buffer + G_mm_sensors_state = MM_SENSORS_VALIDATE_SENSOR_READINGS; + } + } +} + + +/** + * Validates the current Sensor Readings Buffer in main memory. + * + * Sets the valid field in the Sensor Readings Buffer Header to true indicating + * that all sensor readings have been written. + * + * If successful: + * - Switches the current Sensor Readings Buffer (ping/pong) + * - Changes current state to MM_SENSORS_WRITE_SENSOR_READINGS. + */ +void mm_sensors_validate_sensor_readings(void) +{ + // Clear the BCE buffer + memset(G_mm_sensors_bce_buffer, 0x00, MM_SENSORS_BCE_BUF_SIZE); + + // We need to modify the valid field of the Sensor Readings Buffer Header. + // However, the BCE does not support writing a single byte. The minimum + // write size is 128 bytes. To work around this, we saved the first 128 + // bytes of the Sensor Readings Buffer (including the header) in + // mm_sensors_write_sensor_readings(). Copy those saved bytes back into the + // BCE buffer. + memcpy(G_mm_sensors_bce_buffer, G_mm_sensors_save_buffer, MM_SENSORS_MIN_WRITE_SIZE); + + // Cast BCE buffer to a mm_sensor_readings_buf_header_t * + mm_sensor_readings_buf_header_t * l_header = + (mm_sensor_readings_buf_header_t *) (&G_mm_sensors_bce_buffer); + + // Set the valid field to true since all sensor readings have been written + l_header->valid = MM_SENSOR_READINGS_VALID_TRUE; + + // Copy first 128 bytes of Sensor Readings Buffer to main memory using BCE + if (mm_sensors_bce_copy(G_mm_sensor_readings_buf_addr, MM_SENSORS_MIN_WRITE_SIZE, + MM_SENSORS_VALIDATE_READINGS_MOD)) + { + // Copy succeeded. Switch to other Sensor Readings Buffer (ping/pong). + G_mm_sensor_readings_buf_addr = + (G_mm_sensor_readings_buf_addr == MM_SENSOR_READINGS_PING_ADDRESS) ? + MM_SENSOR_READINGS_PONG_ADDRESS : MM_SENSOR_READINGS_PING_ADDRESS; + + // Change state to write sensor readings to other buffer + G_mm_sensors_state = MM_SENSORS_WRITE_SENSOR_READINGS; + } +} + + +//****************************************************************************** +// Public Functions +//****************************************************************************** + +// See description in header file +void main_mem_sensors_init(void) +{ + // Initialize internal data structures if not done before + static bool L_initialized_internals = false; + if (!L_initialized_internals) + { + mm_sensors_init_internals(); + L_initialized_internals = true; + } + + // If initialization is already complete exit immediately + static bool L_traced_init_complete_err = false; + if (G_main_mem_sensors_initialized) + { + // Trace if this is the first time we encountered the error + if (!L_traced_init_complete_err) + { + TRAC_ERR("main_mem_sensors_init: Initialization is already complete"); + L_traced_init_complete_err = true; + } + return; + } + + // Check if there is a scheduled BCE request that has not finished. If so + // we must exit and try again later. + if (!mm_sensors_is_bce_req_idle(MM_SENSORS_INIT_MOD)) + { + return; + } + + // Write main memory data structures that contain static sensor data. Write + // data for current state. Data cannot all be written at once due to BCE + // size limitations and non-blocking writes. + switch (G_mm_sensors_state) + { + case MM_SENSORS_WRITE_DATA_HEADER: + mm_sensors_write_data_header(); + break; + case MM_SENSORS_WRITE_SENSOR_NAMES: + mm_sensors_write_sensor_names(); + break; + case MM_SENSORS_VALIDATE_DATA_HEADER: + mm_sensors_validate_data_header(); + break; + } + + // If initialization is now complete trace the event + if (G_main_mem_sensors_initialized) + { + TRAC_IMP("main_mem_sensors_init: Initialization complete for all %u valid sensors", + mm_sensors_valid_sensor_count()); + } +} + + +// See description in header file +void main_mem_sensors_update(void) +{ + // Make sure main memory sensor initialization is complete + static bool L_traced_init_err = false; + if (!G_main_mem_sensors_initialized) + { + // Trace if this is the first time we encountered the error + if (!L_traced_init_err) + { + TRAC_ERR("main_mem_sensors_update: Main memory sensors not initialized"); + L_traced_init_err = true; + } + return; + } + + // Check if there is a scheduled BCE request that has not finished. If so + // we must exit and try again later. + if (!mm_sensors_is_bce_req_idle(MM_SENSORS_UPDATE_MOD)) + { + return; + } + + // Write sensor readings to main memory. Write data for current state. + // Data cannot all be written at once due to BCE size limitations and + // non-blocking writes. + switch (G_mm_sensors_state) + { + case MM_SENSORS_WRITE_SENSOR_READINGS: + mm_sensors_write_sensor_readings(); + break; + case MM_SENSORS_VALIDATE_SENSOR_READINGS: + mm_sensors_validate_sensor_readings(); + break; + } +} + + +// See description in header file +void main_mem_sensors_set_enabled(AMEC_SENSOR_TYPE i_sensor_type, bool i_enabled) +{ + // Loop through all main memory sensors + uint16_t l_index; + for (l_index = 0; l_index < MAIN_MEM_SENSOR_COUNT; ++l_index) + { + // Get GSID of main memory sensor + uint16_t l_gsid = G_main_mem_sensors[l_index].gsid; + + // Get sensor type from associated sensor_info_t + uint16_t l_sensor_type = G_sensor_info[l_gsid].sensor.type; + + // If i_sensor_type parameter includes current sensor's type + if (i_sensor_type & l_sensor_type) + { + // Set enabled state of current sensor + G_main_mem_sensors[l_index].enabled = i_enabled; + } + } +} diff --git a/src/occ_405/sensor/sensor_main_memory.h b/src/occ_405/sensor/sensor_main_memory.h new file mode 100644 index 0000000..f9cd29f --- /dev/null +++ b/src/occ_405/sensor/sensor_main_memory.h @@ -0,0 +1,306 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/sensor/sensor_main_memory.h $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017,2017 */ +/* [+] International Business Machines 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. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#ifndef _SENSOR_MAIN_MEMORY_H +#define _SENSOR_MAIN_MEMORY_H + +/** + * @file sensor_main_memory.h + * + * This file declares the functions and global variables for copying a subset of + * the OCC sensors to main memory. + * + * The sensor data is stored in the "GPU / Sensor Data" section of the OCC + * Common image in main memory. + * + * Within that section, each OCC has a separate Sensor Data Block for its sensor + * data: + * - OCC 0 Sensor Data Block + * - OCC 1 Sensor Data Block + * - ... + * - OCC 7 Sensor Data Block + * + * A Sensor Data Block contains the following: + * - Sensor Data Header Block + * - Sensor Names Block + * - Sensor Readings Ping Buffer + * - Sensor Readings Pong Buffer + * + * The Sensor Data Header Block is written once by the OCC during + * initialization. It contains static data that describes the Sensor Names + * Block and Sensor Readings Buffers. + * + * The Sensor Names Block is also written once by the OCC during initialization. + * It contains static data about the sensors being copied, such as the sensor + * name, global sensor ID, and sensor type. + * + * The Sensor Readings Ping and Pong Buffers are updated continually by the OCC. + * These buffers contain the dynamic sensor data, such as the current sample, + * timestamp, and maximum value. The OCC alternates between the two buffers so + * that one buffer is always complete and readable by OPAL. + * + * For more information see the OCC Firmware Interface Specification document. + */ + +//****************************************************************************** +// Includes +//****************************************************************************** +#include // For bool +#include // For uint*_t +#include // For sensor defines and enums +#include // For G_pbax_id, SENSOR_DATA_COMMON_ADDRESS + + +//****************************************************************************** +// Sensor Data Block +//****************************************************************************** + +#define MM_SENSOR_DATA_BLOCK_SIZE 0x00025800 /* 150kB */ +#define MM_SENSOR_DATA_BLOCK_OFFSET (G_pbax_id.chip_id * MM_SENSOR_DATA_BLOCK_SIZE) +#define MM_SENSOR_DATA_BLOCK_ADDRESS (SENSOR_DATA_COMMON_ADDRESS + \ + MM_SENSOR_DATA_BLOCK_OFFSET) + + +//****************************************************************************** +// Sensor Data Header Block +//****************************************************************************** + +#define MM_SENSOR_DATA_HEADER_SIZE 0x00000400 /* 1kB */ +#define MM_SENSOR_DATA_HEADER_OFFSET 0x00000000 +#define MM_SENSOR_DATA_HEADER_ADDRESS (MM_SENSOR_DATA_BLOCK_ADDRESS + \ + MM_SENSOR_DATA_HEADER_OFFSET) +#define MM_SENSOR_DATA_HEADER_VERSION 0x01 + +/** + * Values for the 'valid' field of the Sensor Data Header Block + */ +typedef enum +{ + MM_SENSOR_DATA_HEADER_VALID_FALSE = 0x00, + MM_SENSOR_DATA_HEADER_VALID_TRUE = 0x01, +} MM_SENSOR_DATA_HEADER_VALID_VALUES; + +/** + * Sensor Data Header Block + */ +typedef struct __attribute__ ((packed)) +{ + uint8_t valid; + uint8_t header_version; + uint16_t number_of_sensors; + uint8_t sensor_readings_version; + uint8_t reserved_1[3]; + uint32_t sensor_names_offset; + uint8_t sensor_names_version; + uint8_t bytes_per_sensor_name; + uint8_t reserved_2[2]; + uint32_t ping_buffer_offset; + uint32_t pong_buffer_offset; + uint8_t reserved_3[1000]; +} mm_sensor_data_header_block_t; + + +//****************************************************************************** +// Sensor Names Block +//****************************************************************************** + +#define MM_SENSOR_NAMES_SIZE 0x0000C800 /* 50kB */ +#define MM_SENSOR_NAMES_OFFSET 0x00000400 +#define MM_SENSOR_NAMES_ADDRESS (MM_SENSOR_DATA_BLOCK_ADDRESS + \ + MM_SENSOR_NAMES_OFFSET) +#define MM_SENSOR_NAMES_VERSION 0x01 + +/** + * Values for the 'sensor_structure_version' field of a Sensor Names Block Entry + */ +typedef enum +{ + MM_SENSOR_NAMES_STRUCT_VERSION_FULL = 0x01, + MM_SENSOR_NAMES_STRUCT_VERSION_COUNTER = 0x02, +} MM_SENSOR_NAMES_STRUCT_VERSION_VALUES; + +/** + * Sensor Names Block Entry + */ +typedef struct __attribute__ ((packed)) +{ + char name[MAX_SENSOR_NAME_SZ]; + char units[MAX_SENSOR_UNIT_SZ]; + uint16_t gsid; + uint32_t freq; + uint32_t scale_factor; + uint16_t type; + uint16_t location; + uint8_t sensor_structure_version; + uint32_t reading_offset; + uint8_t sensor_specific_info1; + uint8_t reserved[8]; +} mm_sensor_names_entry_t; + + +//****************************************************************************** +// Sensor Readings Buffers +//****************************************************************************** + +#define MM_SENSOR_READINGS_SIZE 0x0000A000 /* 40kB */ +#define MM_SENSOR_READINGS_PING_OFFSET 0x0000DC00 +#define MM_SENSOR_READINGS_PONG_OFFSET 0x00018C00 +#define MM_SENSOR_READINGS_PING_ADDRESS (MM_SENSOR_DATA_BLOCK_ADDRESS + \ + MM_SENSOR_READINGS_PING_OFFSET) +#define MM_SENSOR_READINGS_PONG_ADDRESS (MM_SENSOR_DATA_BLOCK_ADDRESS + \ + MM_SENSOR_READINGS_PONG_OFFSET) +#define MM_SENSOR_READINGS_VERSION 0x01 + +/** + * Values for the 'valid' field of a Sensor Readings Buffer Header + */ +typedef enum +{ + MM_SENSOR_READINGS_VALID_FALSE = 0x00, + MM_SENSOR_READINGS_VALID_TRUE = 0x01, +} MM_SENSOR_READINGS_VALID_VALUES; + +/** + * Sensor Readings Buffer Header + */ +typedef struct __attribute__ ((packed)) +{ + uint8_t valid; + uint8_t reserved[7]; +} mm_sensor_readings_buf_header_t; + +/** + * Full Sensor Readings Structure. Used when structure version is + * MM_SENSOR_NAMES_STRUCT_VERSION_FULL. + */ +typedef struct __attribute__ ((packed)) +{ + uint16_t gsid; + uint64_t timestamp; + uint16_t sample; + uint16_t sample_min; + uint16_t sample_max; + uint16_t csm_sample_min; + uint16_t csm_sample_max; + uint16_t profiler_sample_min; + uint16_t profiler_sample_max; + uint16_t job_s_sample_min; + uint16_t job_s_sample_max; + uint64_t accumulator; + uint32_t update_tag; + uint8_t reserved[8]; +} mm_sensor_readings_full_t; + +/** + * Counter Sensor Readings Structure. Used when structure version is + * MM_SENSOR_NAMES_STRUCT_VERSION_COUNTER. + */ +typedef struct __attribute__ ((packed)) +{ + uint16_t gsid; + uint64_t timestamp; + uint64_t accumulator; + uint8_t sample; + uint8_t reserved[5]; +} mm_sensor_readings_counter_t; + +/** + * Returns the size of the specified sensor readings structure version. + * See MM_SENSOR_NAMES_STRUCT_VERSION_VALUES. + */ +#define MM_SENSOR_READINGS_STRUCT_SIZE(sensor_structure_version) \ + (((sensor_structure_version) == MM_SENSOR_NAMES_STRUCT_VERSION_FULL) ? \ + sizeof(mm_sensor_readings_full_t) : \ + sizeof(mm_sensor_readings_counter_t)) + + +//****************************************************************************** +// Globals +//****************************************************************************** + +/** + * Indicates whether the main memory sensors have been initialized. If false, + * main_mem_sensors_init() needs to be called. + */ +extern bool G_main_mem_sensors_initialized; + +/** + * Indicates whether Secure Memory (SMF) mode is enabled. When secure mode is + * enabled only a subset of sensors will be copied to main memory. Default + * value is false (not enabled). + */ +extern bool G_main_mem_sensors_smf_mode_enabled; + + +//****************************************************************************** +// Function Prototypes +//****************************************************************************** + +/** + * Initializes the main memory sensors. Writes static sensor data to main + * memory. + * + * Performs the following tasks: + * - Initializes internal data structures + * - Writes the Sensor Data Header Block in main memory + * - Writes the Sensor Names Block in main memory + * - Sets G_main_mem_sensors_initialized to true if all initialization is done + * + * This function must be called repeatedly until G_main_mem_sensors_initialized + * is true. This is due to a limit on how much data can be written to main + * memory at once. + */ +void main_mem_sensors_init(void); + + +/** + * Updates the main memory sensors. Writes dynamic sensor data to main memory. + * + * There are two Sensor Readings Buffers (ping and pong) in main memory used to + * store dynamic sensor data. This function will automatically alternate + * between the two buffers. + * + * This function should be called repeatedly from a timer. It will update a + * portion of a Sensor Readings Buffer with the most recent data. There is a + * limit on how much data can be copied to main memory at once, so multiple + * calls are required to completely update one Sensor Readings Buffer. + * + * Note: This function cannot be called until after main_mem_sensors_init() has + * completely initialized the main memory sensors. + */ +void main_mem_sensors_update(void); + + +/** + * Sets the enabled state of all main memory sensors of the specified type(s). + * + * @param i_sensor_type Sensor type(s) to enable or disable. Contains one or + * more values of the AMEC_SENSOR_TYPE enum OR'd together. + * @param i_enabled True to enable the sensors, false to disable the sensors + */ +void main_mem_sensors_set_enabled(AMEC_SENSOR_TYPE i_sensor_type, bool i_enabled); + + +#endif // _SENSOR_MAIN_MEMORY_H diff --git a/src/occ_405/sensor/sensor_service_codes.h b/src/occ_405/sensor/sensor_service_codes.h index 517d9e3..397a2d5 100755 --- a/src/occ_405/sensor/sensor_service_codes.h +++ b/src/occ_405/sensor/sensor_service_codes.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* Contributors Listed Below - COPYRIGHT 2011,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -30,8 +30,20 @@ enum occSensorModuleId { - SENSOR_QUERY_LIST = SNSR_COMP_ID | 0x00, - SENSOR_INITIALIZE = SNSR_COMP_ID | 0x01, + // Sensors + SENSOR_QUERY_LIST = SNSR_COMP_ID | 0x00, + SENSOR_INITIALIZE = SNSR_COMP_ID | 0x01, + + // Main memory sensors + MM_SENSORS_INIT_MOD = SNSR_COMP_ID | 0x10, + MM_SENSORS_UPDATE_MOD = SNSR_COMP_ID | 0x11, + MM_SENSORS_BCE_COPY_MOD = SNSR_COMP_ID | 0x12, + MM_SENSORS_IS_BCE_REQ_IDLE_MOD = SNSR_COMP_ID | 0x13, + MM_SENSORS_WRITE_DATA_HDR_MOD = SNSR_COMP_ID | 0x14, + MM_SENSORS_VALIDATE_DATA_HDR_MOD = SNSR_COMP_ID | 0x15, + MM_SENSORS_WRITE_NAMES_MOD = SNSR_COMP_ID | 0x16, + MM_SENSORS_WRITE_READINGS_MOD = SNSR_COMP_ID | 0x17, + MM_SENSORS_VALIDATE_READINGS_MOD = SNSR_COMP_ID | 0x18, }; #endif /* #ifndef _SENSOR_SERVICE_CODES_H_ */ diff --git a/src/occ_405/topfiles.mk b/src/occ_405/topfiles.mk index 6b9f1eb..61f9348 100644 --- a/src/occ_405/topfiles.mk +++ b/src/occ_405/topfiles.mk @@ -94,6 +94,7 @@ TOP-C-SOURCES = amec/amec_analytics.c \ rtls/rtls.c \ scom.c \ sensor/sensor_info.c \ + sensor/sensor_main_memory.c \ sensor/sensor_query_list.c \ sensor/sensor_table.c \ sensor/sensor.c \ -- cgit v1.2.1