diff options
author | William Bryan <wilbryan@us.ibm.com> | 2015-08-03 12:38:58 -0500 |
---|---|---|
committer | William A. Bryan <wilbryan@us.ibm.com> | 2015-08-03 15:32:27 -0500 |
commit | 420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3 (patch) | |
tree | c9f6691eddba39193e39aa769367e1267fb9fc86 /src/occ_405/amec/amec_sensors_core.c | |
parent | adade8c8ef30ed519322674c762d95663009c5d4 (diff) | |
download | talos-occ-420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3.tar.gz talos-occ-420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3.zip |
new ssx and lib files
Change-Id: I2328b1e86d59e3788910687d762fb70ec680058f
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/19503
Reviewed-by: William A. Bryan <wilbryan@us.ibm.com>
Tested-by: William A. Bryan <wilbryan@us.ibm.com>
Diffstat (limited to 'src/occ_405/amec/amec_sensors_core.c')
-rwxr-xr-x | src/occ_405/amec/amec_sensors_core.c | 882 |
1 files changed, 882 insertions, 0 deletions
diff --git a/src/occ_405/amec/amec_sensors_core.c b/src/occ_405/amec/amec_sensors_core.c new file mode 100755 index 0000000..bdea518 --- /dev/null +++ b/src/occ_405/amec/amec_sensors_core.c @@ -0,0 +1,882 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ/amec/amec_sensors_core.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* [+] 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 */ + +/******************************************************************************/ +/* Includes */ +/******************************************************************************/ +#include <occ_common.h> +#include <ssx.h> +#include <errl.h> // Error logging +#include "sensor.h" +#include "rtls.h" +#include "occ_sys_config.h" +#include "occ_service_codes.h" // for SSX_GENERIC_FAILURE +#include "dcom.h" +#include "proc_data.h" +#include "amec_smh.h" +#include "amec_slave_smh.h" +#include <trac.h> +#include "amec_sys.h" +#include "sensor_enum.h" +#include "amec_service_codes.h" +#include <amec_sensors_core.h> +#include "amec_perfcount.h" + +/******************************************************************************/ +/* Globals */ +/******************************************************************************/ + +/******************************************************************************/ +/* Forward Declarations */ +/******************************************************************************/ +void amec_calc_dts_sensors(gpe_bulk_core_data_t * i_core_data_ptr, uint8_t i_core); +//void amec_calc_cpm_sensors(gpe_bulk_core_data_t * i_core_data_ptr, uint8_t i_core); //CPM - Commented out as requested by Malcolm +void amec_calc_freq_and_util_sensors(gpe_bulk_core_data_t * i_core_data_ptr, uint8_t i_core); +void amec_calc_ips_sensors(gpe_bulk_core_data_t * i_core_data_ptr, uint8_t i_core); +void amec_calc_spurr(uint8_t i_core); + +//************************************************************************* +// Code +//************************************************************************* + +// Function Specification +// +// Name: amec_update_fast_core_data_sensors +// +// Description: Updates sensors that have data grabbed by the fast core data +// task. +// +// Thread: RealTime Loop +// +// End Function Specification +void amec_update_fast_core_data_sensors(void) +{ + // ------------------------------------------------------ + // Update Fast Core Data Sensors + // ------------------------------------------------------ + // SensorNameCx = PCBS Local Pstate Freq Target (per core) + // TODclock = TOD Clock? + + // Need to comment this out because l_tod is always zero, which messes + // up proper sensor updates. Proper updating is done below in the core level + // sensor updates. + + //gpe_fast_core_data_t * l_core = proc_get_fast_core_data_ptr(); + // uint32_t l_tod = l_core->tod; + + //if( l_core != NULL) + //{ + // GPEtickdur0 = duration of last tick's PORE-GPE0 duration + // sensor_update( AMECSENSOR_PTR(TODclock0), CONVERT_UINT32_UINT8_UPPER_HIGH(l_tod) ); + // sensor_update( AMECSENSOR_PTR(TODclock1), CONVERT_UINT32_UINT16_MIDDLE(l_tod) ); + // sensor_update( AMECSENSOR_PTR(TODclock2), ((uint16_t) (CONVERT_UINT32_UINT8_LOWER_LOW(l_tod))) << 8); + //} + + // TODO: Don't know what to update from the PCBS LPstate Target Freq Status Reg + //for(int i=0; i++; i<MAX_NUM_HW_CORES) + //{ + // sensor_update(&sensor, + // G_read_fast_core_data_ptr->core_data[i].pcbs_lpstate_freq_target_sr); + //} +} + + +// Function Specification +// +// Name: amec_update_proc_core_sensors +// +// Description: Update all the sensors for a given proc +// +// Thread: RealTime Loop +// +// End Function Specification +void amec_update_proc_core_sensors(uint8_t i_core) +{ + gpe_bulk_core_data_t * l_core_data_ptr; + int i; + uint16_t l_temp16 = 0; + uint32_t l_temp32 = 0; + + // Make sure the core is present, and that it has updated data. + if(CORE_PRESENT(i_core) && CORE_UPDATED(i_core)) + { + // Clear flag indicating core was updated by proc task + CLEAR_CORE_UPDATED(i_core); + + // Get pointer to core data + l_core_data_ptr = proc_get_bulk_core_data_ptr(i_core); + + //------------------------------------------------------- + // Thermal Sensors & Calc + //------------------------------------------------------- + amec_calc_dts_sensors(l_core_data_ptr, i_core); + + //------------------------------------------------------- + //CPM - Commented out as requested by Malcolm + // ------------------------------------------------------ + // amec_calc_cpm_sensors(l_core_data_ptr, i_core); + + //------------------------------------------------------- + // Util / Freq + //------------------------------------------------------- + // Skip this update if there was an empath collection error + if (!CORE_EMPATH_ERROR(i_core)) + { + amec_calc_freq_and_util_sensors(l_core_data_ptr,i_core); + } + + //------------------------------------------------------- + // Performance counter - This function should be called + // after amec_calc_freq_and_util_sensors(). + //------------------------------------------------------- + amec_calc_dps_util_counters(i_core); + + //------------------------------------------------------- + // IPS + //------------------------------------------------------- + // Skip this update if there was an empath collection error + if (!CORE_EMPATH_ERROR(i_core)) + { + amec_calc_ips_sensors(l_core_data_ptr,i_core); + } + + //------------------------------------------------------- + // SPURR + //------------------------------------------------------- + amec_calc_spurr(i_core); + + // ------------------------------------------------------ + // Update PREVIOUS values for next time + // ------------------------------------------------------ + g_amec->proc[0].core[i_core].prev_PC_RAW_Th_CYCLES = l_core_data_ptr->per_thread[0].raw_cycles; + + // Skip empath updates if there was an empath collection error on this core + if (!CORE_EMPATH_ERROR(i_core)) + { + g_amec->proc[0].core[i_core].prev_PC_RAW_CYCLES = l_core_data_ptr->empath.raw_cycles; + g_amec->proc[0].core[i_core].prev_PC_RUN_CYCLES = l_core_data_ptr->empath.run_cycles; + g_amec->proc[0].core[i_core].prev_PC_COMPLETED = l_core_data_ptr->empath.completion; + g_amec->proc[0].core[i_core].prev_PC_DISPATCH = l_core_data_ptr->empath.dispatch; + g_amec->proc[0].core[i_core].prev_tod_2mhz = l_core_data_ptr->empath.tod_2mhz; + g_amec->proc[0].core[i_core].prev_FREQ_SENS_BUSY = l_core_data_ptr->empath.freq_sens_busy; + g_amec->proc[0].core[i_core].prev_FREQ_SENS_FINISH = l_core_data_ptr->empath.freq_sens_finish; + } + + for(i=0; i<MAX_THREADS_PER_CORE; i++) + { + g_amec->proc[0].core[i_core].thread[i].prev_PC_RUN_Th_CYCLES = l_core_data_ptr->per_thread[i].run_cycles; + } + + // Final step is to update TOD sensors + // Extract 32 bits with 16usec resolution + l_temp32 = (uint32_t)(G_dcom_slv_inbox_doorbell_rx.tod>>13); + l_temp16 = (uint16_t)(l_temp32); + // low 16 bits is 16usec resolution with 512MHz TOD clock + sensor_update( AMECSENSOR_PTR(TODclock0), l_temp16); + l_temp16 = (uint16_t)(l_temp32>>16); + // mid 16 bits is 1.05sec resolution with 512MHz TOD clock + sensor_update( AMECSENSOR_PTR(TODclock1), l_temp16); + l_temp16 = (uint16_t)(G_dcom_slv_inbox_doorbell_rx.tod>>45); + // hi 3 bits in 0.796 day resolution with 512MHz TOD clock + sensor_update( AMECSENSOR_PTR(TODclock2), l_temp16); + } +} + + +// Function Specification +// +// Name: amec_calc_dts_sensors +// +// Description: Compute core temperature. This function is called every +// 2ms/core. +// +// Thread: RealTime Loop +// +// End Function Specification +void amec_calc_dts_sensors(gpe_bulk_core_data_t * i_core_data_ptr, uint8_t i_core) +{ +#define DTS_PER_CORE 4 +#define DTS_INVALID_MASK 0x0C00 + + uint32_t k, l_core_avg, l_core_hot, l_sensor_count; + uint32_t l_oha_status_reg = 0; + uint32_t l_pm_state_hist_reg = 0; + uint16_t l_dts[DTS_PER_CORE]; + BOOLEAN l_update_sensor = FALSE; + + // Build up array of DTS values + // DTS sensors are in the format of uint64_t dts0 : 12; + // uint64_t thermal_trip0 : 2; + // uint64_t spare0 : 1; + // uint64_t valid0 : 1; + // + // so we will need to convert them before they are used in loop below. + l_dts[0] = i_core_data_ptr->dts_cpm.sensors_v0.fields.dts0; + l_dts[1] = i_core_data_ptr->dts_cpm.sensors_v0.fields.dts1; + l_dts[2] = i_core_data_ptr->dts_cpm.sensors_v0.fields.dts2; + l_dts[3] = i_core_data_ptr->dts_cpm.sensors_v1.fields.dts4; + + // Read the low-order bytes of the OHA Status register + l_oha_status_reg = i_core_data_ptr->oha.oha_ro_status_reg.words.low_order; + + // Read the high-order bytes of PM State History register for this core + l_pm_state_hist_reg = i_core_data_ptr->pcb_slave.pm_history.words.high_order; + + // Check if we were able to collect core data + if(l_oha_status_reg & CORE_DATA_CORE_SENSORS_COLLECTED) + { + // Check if all DTS readings in the core are valid. The field sensors_v0 + // contains core-related data + if(i_core_data_ptr->dts_cpm.sensors_v0.fields.valid0 || + i_core_data_ptr->dts_cpm.sensors_v0.fields.valid1 || + i_core_data_ptr->dts_cpm.sensors_v0.fields.valid2) + { + l_update_sensor = TRUE; + } + } + // Check if we were able to collect L3 data + if(l_oha_status_reg & CORE_DATA_L3_SENSORS_COLLECTED) + { + // Check if DTS reading in the L3 is valid. The field sensors_v1 contains + // L3-related data + if(i_core_data_ptr->dts_cpm.sensors_v1.fields.valid4) + { + l_update_sensor = TRUE; + } + } + // Check if this core has been in fast winkle OR deep winkle + if(((l_pm_state_hist_reg & OCC_PM_STATE_MASK) == OCC_PAST_FAST_WINKLE) || + ((l_pm_state_hist_reg & OCC_PM_STATE_MASK) == OCC_PAST_DEEP_WINKLE)) + { + l_update_sensor = TRUE; + } + + // Update the thermal sensor associated with this core + if(l_update_sensor) + { + //calculate average temperature from all DTS's for this core + for(l_sensor_count = DTS_PER_CORE, l_core_hot = 0, + l_core_avg = 0, k = 0; + k < DTS_PER_CORE; k++) + { + //Hardware bug workaround: Temperatures reaching 0 degrees C + //can show up as negative numbers. To fix this, we discount + //values that have the 2 MSB's set. + if((l_dts[k] & DTS_INVALID_MASK) == DTS_INVALID_MASK) + { + l_dts[k] = 0; + } + + l_core_avg += l_dts[k]; + if(l_dts[k] > l_core_hot) + { + l_core_hot = l_dts[k]; + } + // Assume 0 degrees to mean bad sensor and don't let it bring the + // average reading down. + else if(l_dts[k] == 0) + { + l_sensor_count--; + } + } + + if(l_sensor_count == DTS_PER_CORE) + { + //For the common case, compiler converts this to a fast multiplication + //operation when one of the operands is a constant. + l_core_avg /= DTS_PER_CORE; + } + else if(l_sensor_count) //prevent div by 0 if all sensors are zero + { + //otherwise, use the slower division routine when both operands are + //unknown at compile time. + l_core_avg /= l_sensor_count; + } + + // Update sensors & Interim Data + sensor_update( AMECSENSOR_ARRAY_PTR(TEMP2MSP0C0,i_core), l_core_avg); + g_amec->proc[0].core[i_core].dts_hottest = l_core_hot; + } +} + + +//CPM - Commented out as requested by Malcolm +/* void amec_calc_cpm_sensors(gpe_bulk_core_data_t * i_core_data_ptr, uint8_t i_core) +{ +#define CPM_PER_CORE 4 + + uint32_t k, l_cpm_min = 0xffffffff; + uint16_t l_cpm[CPM_PER_CORE]; + + l_cpm[0] = i_core_data_ptr->dts_cpm.sensors_v8.fields.encoded_cpm0; + l_cpm[1] = i_core_data_ptr->dts_cpm.sensors_v8.fields.encoded_cpm1; + l_cpm[2] = i_core_data_ptr->dts_cpm.sensors_v8.fields.encoded_cpm2; + l_cpm[3] = i_core_data_ptr->dts_cpm.sensors_v9.fields.encoded_cpm4; + + //calculate min CPM from all CPM's for this core + for(k = 0; k < CPM_PER_CORE; k++) + { + if(l_cpm[k] < l_cpm_min) + { + l_cpm_min = l_cpm[k]; + } + } + + sensor_update( AMECSENSOR_ARRAY_PTR(CPM2MSP0C0,i_core), l_cpm_min); +} +*/ + +// Function Specification +// +// Name: amec_calc_freq_and_util_sensors +// +// Description: Compute the frequency and utilization sensors for a given core. +// This function is called every 2ms/core. +// +// Thread: RealTime Loop +// +// End Function Specification +void amec_calc_freq_and_util_sensors(gpe_bulk_core_data_t * i_core_data_ptr, uint8_t i_core) +{ + BOOLEAN l_core_sleep_winkle = FALSE; + uint32_t l_pm_state_hist_reg = 0; + uint32_t temp32 = 0; + uint32_t temp32a = 0; + uint16_t temp16 = 0; + uint16_t temp16a = 0; + uint16_t l_core_util = 0; + uint16_t l_core_freq = 0; + uint16_t l_time_interval = 0; + uint32_t l_cycles2ms = 0; + int i; + + // Read the high-order bytes of PM State History register for this core + l_pm_state_hist_reg = i_core_data_ptr->pcb_slave.pm_history.words.high_order; + + // If core is in fast/deep sleep mode or fast/winkle mode, then set a flag + // indicating this + if(l_pm_state_hist_reg & OCC_PAST_CORE_CLK_STOP) + { + l_core_sleep_winkle = TRUE; + } + + // ------------------------------------------------------ + // Per Core Frequency + // ------------------------------------------------------ + // <amec_formula> + // Result: Calculated Core Frequency + // Sensor: FREQA2MSP0C0 + // Timescale: 2ms + // Units: MHz + // Min/Max: 0/6000 (UPPER_LIMIT_PROC_FREQ_MHZ=6000) + // Formula: cyc_delta = (RAW_CYCLES[t=now] - RAW_CYCLES[t=-2ms]) + // time_delta = (TOD[t=now] - TOD[t=-2ms]) + // frequency(MHz) = (cyc_delta / time_delta) * (2M TOD ticks / 1 second) + // = (2 * cyc_delta) / time_delta + // </amec_formula> + + // Compute Delta in PC_RAW_CYCLES + temp32 = i_core_data_ptr->empath.raw_cycles; + temp32a = g_amec->proc[0].core[i_core].prev_PC_RAW_CYCLES; + temp32 = l_cycles2ms = temp32 - temp32a; + + if( (cfam_id() == CFAM_CHIP_ID_MURANO_10) + || (cfam_id() == CFAM_CHIP_ID_MURANO_11) + || (cfam_id() == CFAM_CHIP_ID_MURANO_12) ) + { + temp32a = AMEC_US_PER_SMH_PERIOD; // using fixed 2000us is showing 3% error. + temp32 = temp32 / temp32a; + } + else + { + temp32a = (i_core_data_ptr->empath.tod_2mhz - + g_amec->proc[0].core[i_core].prev_tod_2mhz); + temp32 = (2 * temp32) / temp32a; + } + + // TODO: Remove this once we have the OHA Power Proxy legacy mode stuff working. + if(temp32 < UPPER_LIMIT_PROC_FREQ_MHZ) + { + // Update Sensor for this core + if(l_core_sleep_winkle) + { + l_core_freq = 0; + } + else + { + l_core_freq = (uint16_t) temp32; + } + sensor_update( AMECSENSOR_ARRAY_PTR(FREQA2MSP0C0,i_core), l_core_freq); + } + + // ------------------------------------------------------ + // Per Core Utilization + // ------------------------------------------------------ + // <amec_formula> + // Result: Calculated Core Utilization + // Sensor: UTIL2MSP0C0 + // Timescale: 2ms + // Units: 0.01 % + // Min/Max: 0/10000 (0/100%) + // Formula: cyc_delta = (RAW_CYCLES[t=now] - RAW_CYCLES[t=-2ms]) + // run_delta = (RUN_CYCLES[t=now] - RUN_CYCLES[t=-2ms]) + // + // UTIL(in %) = run_delta / cyc_delta + // </amec_formula> + + // Compute Delta in PC_RUN_CYCLES + temp32 = i_core_data_ptr->empath.run_cycles; + temp32a = g_amec->proc[0].core[i_core].prev_PC_RUN_CYCLES; + temp32 = temp32 - temp32a; + + temp32 = temp32 >> 8; // Drop non-significant bits + temp16 = (uint16_t) temp32; // Cast to uint16 for mult below + temp16a = 10000; // Mult * 10000 to get finer resolution for 0.01% + temp32 = ((uint32_t)temp16a)*((uint32_t)temp16); + + temp32a = l_cycles2ms; // Get Raw cycles + temp32a = temp32a >> 8; // Drop non-significant bits + + // Calculate Utilization + temp32 = temp32 / temp32a; + if(temp32a == 0) // Prevent a divide by zero + { + temp32 = 0; + } + + // Update Sensor for this core + if(l_core_sleep_winkle) + { + l_core_util = 0; + } + else + { + l_core_util = (uint16_t) temp32; + } + sensor_update(AMECSENSOR_ARRAY_PTR(UTIL2MSP0C0, i_core), l_core_util); + + + // ------------------------------------------------------ + // Per Thread Utilization + // ------------------------------------------------------ + // <amec_formula> + // Result: Calculated Core Utilization + // Sensor: None + // Timescale: 2ms + // Units: 0.01 % + // Min/Max: 0/10000 (0/100%) + // Formula: cyc_delta = (RAW_CYCLES[t=now] - RAW_CYCLES[t=-2ms]) + // run_delta = (RUN_CYCLES[t=now] - RUN_CYCLES[t=-2ms]) + // + // UTIL(in %) = run_delta / cyc_delta + // </amec_formula> + + // Get RAW CYCLES for Thread + temp32 = i_core_data_ptr->per_thread[0].raw_cycles; + temp32a = g_amec->proc[0].core[i_core].prev_PC_RAW_Th_CYCLES; + temp32 = l_cycles2ms = temp32 - temp32a; + + for(i=0; i<MAX_THREADS_PER_CORE; i++) + { + // Get Run Counters for Thread + temp32 = i_core_data_ptr->per_thread[i].run_cycles; + temp32a = g_amec->proc[0].core[i_core].thread[i].prev_PC_RUN_Th_CYCLES; + temp32 = temp32 - temp32a; + + temp32 = temp32 >> 8; // Drop non-significant bits + temp16 = (uint16_t) temp32; // Cast to uint16 for mult below + temp16a = 10000; // Mult * 10000 to get finer resolution for 0.01% + temp32 = ((uint32_t)temp16a)*((uint32_t)temp16); + + temp32a = l_cycles2ms; + temp32a = temp32a >> 8; // Drop non-significant bits + + // Calculate Utilization + temp32 = temp32 / temp32a; + + // Update per thread value for this core + if(l_core_sleep_winkle) + { + temp32 = 0; + } + g_amec->proc[0].core[i_core].thread[i].util2ms_thread = (uint16_t) temp32; + } + + // No sensors to update for perThread Util + + // ------------------------------------------------------ + // Per Core Sleep/Winkle Count + // ------------------------------------------------------ + + // Get Current Idle State of Chiplet + // The SLEEPCNT and WINKLECNT sensors are updated in amec_slv_state_0() function + temp16 = CONVERT_UINT64_UINT16_UPPER(i_core_data_ptr->pcb_slave.pm_history.value); + temp16 = temp16 & 0xE000; + temp16 = temp16 >> 13; + switch(temp16) + { + case 0: break; // Run State + case 1: break; // Special Wakeup + case 2: break; // Nap + case 3: SETBIT(g_amec->proc[0].sleep_cnt,i_core); break; // Legacy Sleep + case 4: SETBIT(g_amec->proc[0].sleep_cnt,i_core); break; // Fast Sleep + case 5: SETBIT(g_amec->proc[0].sleep_cnt,i_core); break; // Deep Sleep + case 6: SETBIT(g_amec->proc[0].winkle_cnt,i_core); break; // Fast Winkle + case 7: SETBIT(g_amec->proc[0].winkle_cnt,i_core); break; // Deep Winkle + } + + // ------------------------------------------------------ + // Core Memory Hierarchy C LPARx Utilization counters + // ------------------------------------------------------ + for(i=0; i<4; i++) + { + // Extract the utilization counter + temp32 = i_core_data_ptr->per_partition_memory.count[i]; + + // Convert counter to 0.01 Mrps resolution. Since we access every 2 ms: + // ((2ms read * 500) / 10000) + temp32a = temp32 - g_amec->proc[0].core[i_core].prev_lpar_mem_cnt[i]; + g_amec->proc[0].core[i_core].prev_lpar_mem_cnt[i] = temp32; + temp32 = (temp32a * 5) / 100; + + // Store the bandwidth for this LPAR + g_amec->proc[0].core[i_core].membw[i] = (uint16_t)temp32; + } + + // Sum up all the memory bandwidth data from the LPARs + temp32 = g_amec->proc[0].core[i_core].membw[0] + + g_amec->proc[0].core[i_core].membw[1] + + g_amec->proc[0].core[i_core].membw[2] + + g_amec->proc[0].core[i_core].membw[3]; + + // Divide by two due to a bug in the hardware + temp32 = temp32/2; + + // See if core is sleeping/winkled + if(l_core_sleep_winkle) + { + temp32 = 0; + } + // Update Sensor for this core + sensor_update( AMECSENSOR_ARRAY_PTR(CMBW2MSP0C0,i_core), (uint16_t) temp32); + + // ------------------------------------------------------ + // Core Stall counters + // ------------------------------------------------------ + temp32 = i_core_data_ptr->empath.freq_sens_busy; + temp32a = g_amec->proc[0].core[i_core].prev_FREQ_SENS_BUSY; + temp32 = temp32 - temp32a; + temp32 = temp32 >> 8; + + // See if core is sleeping/winkled + if(l_core_sleep_winkle) + { + temp32 = 0; + } + + // Update Sensor for this core + sensor_update( AMECSENSOR_ARRAY_PTR(NOTBZE2MSP0C0,i_core), (uint16_t) temp32); + + temp32 = i_core_data_ptr->empath.freq_sens_finish; + temp32a = g_amec->proc[0].core[i_core].prev_FREQ_SENS_FINISH; + temp32 = temp32 - temp32a; + temp32 = temp32 >> 8; + + // See if core is sleeping/winkled + if(l_core_sleep_winkle) + { + temp32 = 0; + } + + // Update Sensor for this core + sensor_update( AMECSENSOR_ARRAY_PTR(NOTFIN2MSP0C0,i_core), (uint16_t) temp32); + + // ------------------------------------------------------ + // Per Core Normalized Average Utilization + // ------------------------------------------------------ + // <amec_formula> + // Result: Calculated Normalized Average Core Utilization + // Sensor: NUTIL3SP0C0 + // Timescale: 2ms (3s rolling average) + // Units: 0.01 % + // Min/Max: 0/10000 (0/100%) + // </amec_formula> + + // Determine the time interval for the rolling average calculation + l_time_interval = AMEC_DPS_SAMPLING_RATE * AMEC_IPS_AVRG_INTERVAL; + + // Increment our sample count but prevent it from wrapping + if(g_amec->proc[0].core[i_core].sample_count < UINT16_MAX) + { + g_amec->proc[0].core[i_core].sample_count++; + } + + if(g_amec->proc[0].core[i_core].sample_count == l_time_interval) + { + // Increase resolution of the UTIL accumulator by two decimal places + temp32 = AMECSENSOR_ARRAY_PTR(UTIL2MSP0C0,i_core)->accumulator * 100; + // Calculate average utilization of this core + temp32 = temp32 / g_amec->proc[0].core[i_core].sample_count; + g_amec->proc[0].core[i_core].avg_util = temp32; + + // Increase resolution of the FREQA accumulator by two decimal places + temp32 = AMECSENSOR_ARRAY_PTR(FREQA2MSP0C0,i_core)->accumulator * 100; + // Calculate average frequency of this core + temp32 = temp32 / g_amec->proc[0].core[i_core].sample_count; + g_amec->proc[0].core[i_core].avg_freq = temp32; + } + + if(g_amec->proc[0].core[i_core].sample_count > l_time_interval) + { + // Calculate average utilization for this core + temp32 = (uint32_t) g_amec->proc[0].core[i_core].avg_util; + temp32 = temp32 * (l_time_interval-1); + temp32 = temp32 + l_core_util*100; + g_amec->proc[0].core[i_core].avg_util = temp32 / l_time_interval; + + // Could be needed for increase accuracy + //if(g_amec->proc[0].core[i_core].avg_util > 9000) + //{ This rounds up only! + //g_amec->proc[0].core[i_core].avg_util = (temp32+ (1500-1)) / 1500; + //} + + // Calculate average frequency for this core + temp32 = (uint32_t) g_amec->proc[0].core[i_core].avg_freq; + temp32 = temp32 * (l_time_interval-1); + temp32 = temp32 + l_core_freq*100; + g_amec->proc[0].core[i_core].avg_freq = temp32 / l_time_interval; + } + + // Calculate the normalized utilization for this core + if(g_amec->proc[0].core[i_core].avg_freq != 0) + { + // First, revert back to the original resolution of the sensors + temp32 = g_amec->proc[0].core[i_core].avg_util / 100; + temp32a = g_amec->proc[0].core[i_core].avg_freq / 100; + + // Compute now the normalized utilization as follows: + // Normalized utilization = (Average_utilization)/(Average_frequency) * Fnom + // Note: The 100000 constant is to increase the precision of our division + temp32 = (temp32 * 100000) / temp32a; + temp32 = (temp32 * G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL]) / 100000; + + // Update sensor for this core + if(l_core_sleep_winkle) + { + sensor_update(AMECSENSOR_ARRAY_PTR(NUTIL3SP0C0, i_core), 0); + } + else + { + sensor_update(AMECSENSOR_ARRAY_PTR(NUTIL3SP0C0, i_core), (uint16_t)temp32); + } + } +} + + +void amec_calc_ips_sensors(gpe_bulk_core_data_t * i_core_data_ptr, uint8_t i_core) +{ +#define TWO_PWR_24_MASK 0x00FFFFFF +#define TWO_PWR_20_MASK 0x000FFFFF + + /*------------------------------------------------------------------------*/ + /* Local Variables */ + /*------------------------------------------------------------------------*/ + INT32 cyc1 = 0; //cycle counts + INT32 cyc2 = 0; + UINT32 fin1 = 0; //finished instruction counts + UINT32 fin2 = 0; + INT32 disp1 = 0; //dispatched instruction counts + INT32 disp2 = 0; + UINT32 temp32 = 0; + UINT32 ticks_2mhz = 0; // IPS sensor interval in 2mhz ticks + BOOLEAN l_core_sleep_winkle = FALSE; + uint32_t l_pm_state_hist_reg = 0; + + + // Read the high-order bytes of PM State History register for this core + l_pm_state_hist_reg = i_core_data_ptr->pcb_slave.pm_history.words.high_order; + + // If core is in fast/deep sleep mode or fast/winkle mode, then set a flag + // indicating this + if(l_pm_state_hist_reg & OCC_PAST_CORE_CLK_STOP) + { + l_core_sleep_winkle = TRUE; + } + + /*------------------------------------------------------------------------*/ + /* Code */ + /*------------------------------------------------------------------------*/ + + // Get Run Cycles + cyc1 = i_core_data_ptr->empath.run_cycles; + cyc2 = g_amec->proc[0].core[i_core].prev_PC_RUN_CYCLES; + cyc2 = cyc1 - cyc2; + + // Following lines look bogus...the counters are supposed to be 32-bit + // since we are doing 24-bit unsigned math, we need to account for the + // overflow case. If this occurs, we mask off the "overflow" to make it behave + // like a 32-bit subtraction overflow would. Commenting them out. + //if ( cyc2 < 0 ) + //{ + // cyc2 &= TWO_PWR_24_MASK; + //} + + fin1 = i_core_data_ptr->empath.completion; + fin2 = g_amec->proc[0].core[i_core].prev_PC_COMPLETED; + fin2 = fin1 - fin2; + + // Is this counting every completed instruction or 1 of every 16? + // Why are we masking 20 bits of a 32-bit counter? Commenting these lines out. + //if ( fin2 < 0 ) + //{ + // fin2 &= TWO_PWR_20_MASK; + //} + + disp1 = i_core_data_ptr->empath.dispatch; + disp2 = g_amec->proc[0].core[i_core].prev_PC_DISPATCH; + disp2 = disp1 - disp2; + + if ( disp2 < 0 ) + { + disp2 &= TWO_PWR_20_MASK; + } + + // ------------------------------------------------------ + // Per Core IPC Calculation + // ------------------------------------------------------ + // <amec_formula> + // Result: Calculated Instructions per Cycle + // Sensor: None + // Timescale: 2ms + // Units: 0.01 IPC + // Min/Max: ? + // Formula: ipc_delta = (INST_COMPLETE[t=now] - INST_COMPLETE[t=-2ms]) + // run_cycles = (RUN_CYCLES[t=now] - RUN_CYCLES[t=-2ms]) + // 100 = Convert 0.01 DPC + // + // IPC(in 0.01 IPC) = (ipc_delta * 100) / run_cycles + // </amec_formula> + temp32 = (fin2 * 100); // In units of IPS + temp32 = temp32 / cyc2; // In units of 0.01 DPC + g_amec->proc[0].core[i_core].ipc = temp32; + + + // ------------------------------------------------------ + // Per Core DPC Calculation + // ------------------------------------------------------ + // <amec_formula> + // Result: Calculated dispatched Instructions per Cycle + // Sensor: None + // Timescale: 2ms + // Units: 0.2Mips + // Min/Max: ? + // Formula: dpc_delta = (INST_DISPATCH[t=now] - INST_DISPATCH[t=-2ms]) + // run_cycles = (RUN_CYCLES[t=now] - RUN_CYCLES[t=-2ms]) + // 100 = Convert 0.01 DPC + // + // DPC(in 0.01DPC) = (dpc_delta * 100) / run_cycles + // </amec_formula> + temp32 = (disp2 * 100); // In units of IPS + temp32 = temp32 / cyc2; // In units of 0.01 DPC + g_amec->proc[0].core[i_core].dpc = temp32; + + // ------------------------------------------------------ + // Per Core DPS Calculation + // ------------------------------------------------------ + // <amec_formula> + // Result: Calculated dispatched Instructions per Second + // Sensor: None + // Timescale: 2ms + // Units: 0.2Mips + // Min/Max: ? + // Formula: dps_delta = (INST_DISPATCH[t=now] - INST_DISPATCH[t=-2ms]) + // 500 = # of 2ms periods in 1 second + // 50,000 = Convert IPS to 0.2MIPS + // + // DPS(in 0.2Mips) = (dps_delta * 500) / 50,000 + // </amec_formula> + temp32 = (disp2 * AMEC_SMH_PERIODS_IN_1SEC); // In untis of IPS + temp32 = temp32 / 50000; // In units of 0.2Mips (max 327675 Mips for uint16_t) + g_amec->proc[0].core[i_core].dps = temp32; + + // ------------------------------------------------------ + // Per Core IPS Calculation + // ------------------------------------------------------ + // <amec_formula> + // Result: Calculated Instructions per Second + // Sensor: IPS2MSP0C0 + // Timescale: 2ms + // Units: 0.2Mips + // Min/Max: ? + // Formula: + // comp_delta = (INST_COMPLETE[t=now] - INST_COMPLETE[t=-2ms]) + // ticks_delta = (TOD[t=now] - TOD[t=-2ms]) + // MIPS = comp_delta (insns/interval) * (1 interval per ticks_delta 2mhz ticks) * (2M 2mhz ticks / s) / 1M + // = (2* fin2) / ticks_2mhz + // Note: For best resolution do multiply first and division last. + // </amec_formula> + + ticks_2mhz = i_core_data_ptr->empath.tod_2mhz - + g_amec->proc[0].core[i_core].prev_tod_2mhz; + temp32 = (fin2 << 1) / ticks_2mhz; + // See if core is sleeping/winkled + if(l_core_sleep_winkle) + { + temp32 = 0; + } + sensor_update( AMECSENSOR_ARRAY_PTR(IPS2MSP0C0,i_core), (uint16_t) temp32); +} + + +// Function Specification +// +// Name: amec_calc_spurr +// +// Description: Do SPURR calculation. Must run after FreqA is calculated. +// +// Thread: RealTime Loop +// +// End Function Specification +void amec_calc_spurr(uint8_t i_core) +{ + uint16_t l_actual_freq = AMECSENSOR_ARRAY_PTR(FREQA2MSP0C0, i_core)->sample; + uint16_t l_nominal = 2790; + uint32_t temp32; + + // Sanity Check on Freq + if(l_actual_freq < UPPER_LIMIT_PROC_FREQ_MHZ) + { + temp32 = ((uint32_t) (l_actual_freq * 1000) / l_nominal); + + // Scale for SPURR Register (64 = Nominal, 32 = Nom-50%) + temp32 = (temp32 * 64) / 1000; + + sensor_update( AMECSENSOR_ARRAY_PTR(SPURR2MSP0C0,i_core), (uint16_t) temp32); + } +} + +/*----------------------------------------------------------------------------*/ +/* End */ +/*----------------------------------------------------------------------------*/ |