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/pss | |
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/pss')
-rwxr-xr-x | src/occ_405/pss/apss.c | 838 | ||||
-rw-r--r-- | src/occ_405/pss/apss.h | 138 | ||||
-rwxr-xr-x | src/occ_405/pss/dpss.c | 189 | ||||
-rwxr-xr-x | src/occ_405/pss/dpss.h | 40 | ||||
-rwxr-xr-x | src/occ_405/pss/pss_service_codes.h | 43 | ||||
-rwxr-xr-x | src/occ_405/pss/test/Makefile | 79 | ||||
-rwxr-xr-x | src/occ_405/pss/test/app.mk | 102 | ||||
-rwxr-xr-x | src/occ_405/pss/test/apsstest.c | 415 |
8 files changed, 1844 insertions, 0 deletions
diff --git a/src/occ_405/pss/apss.c b/src/occ_405/pss/apss.c new file mode 100755 index 0000000..4c2cc59 --- /dev/null +++ b/src/occ_405/pss/apss.c @@ -0,0 +1,838 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/pss/apss.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 */ + +#include "ssx.h" + +#include <trac_interface.h> +#include <apss.h> +#include <occ_common.h> +#include <comp_ids.h> +#include <pss_service_codes.h> +#include <occ_service_codes.h> +#include <trac.h> +#include <state.h> +#include <occ_sys_config.h> +#include <dcom.h> +#include "pss_constants.h" + +// Threshold for calling out the redundant APSS +#define MAX_BACKUP_FAILURES 8 + +// Configure both GPIOs (directoin/drive/interrupts): All Input, All 1's, No Interrupts +const apssGpioConfigStruct_t G_gpio_config[2] = { {0x00, 0xFF, 0x00}, {0x00, 0xFF, 0x00} }; + +// Configure streaming of: 16 ADCs, 2 GPIOs +const apssCompositeConfigStruct_t G_apss_composite_config = { 16, 2 }; + +// Power Measurements (read from APSS every RealTime loop) +apssPwrMeasStruct_t G_apss_pwr_meas = { {0} }; + +GPE_BUFFER(initGpioArgs_t G_gpe_apss_initialize_gpio_args); +GPE_BUFFER(setCompositeModeArgs_t G_gpe_apss_set_composite_mode_args); + +uint64_t G_gpe_apss_time_start; +uint64_t G_gpe_apss_time_end; + +// Flag for requesting APSS recovery when OCC detects all zeroes or data out of sync +bool G_apss_recovery_requested = FALSE; + +GPE_BUFFER(apss_start_args_t G_gpe_start_pwr_meas_read_args); +GPE_BUFFER(apss_continue_args_t G_gpe_continue_pwr_meas_read_args); +GPE_BUFFER(apss_complete_args_t G_gpe_complete_pwr_meas_read_args); + +PoreEntryPoint GPE_apss_start_pwr_meas_read; +PoreEntryPoint GPE_apss_continue_pwr_meas_read; +PoreEntryPoint GPE_apss_complete_pwr_meas_read; + +// Up / down counter for redundant apss failures +uint32_t G_backup_fail_count = 0; + +// Used to tell slave inbox that pwr meas is complete +volatile bool G_ApssPwrMeasCompleted = FALSE; + +// Function Specification +// +// Name: dumpHexString +// +// Description: TODO Add description +// +// End Function Specification +#if ( (!defined(NO_TRAC_STRINGS)) && defined(TRAC_TO_SIMICS) ) + +// Utility function to dump hex data to screen +void dumpHexString(const void *i_data, const unsigned int len, const char *string) +{ + unsigned int i, j; + char text[17]; + uint8_t *data = (uint8_t*)i_data; + unsigned int l_len = len; + + text[16] = '\0'; + if (string != NULL) + { + printf("%s\n", string); + } + + if (len > 0x0800) l_len = 0x800; + for(i = 0; i < l_len; i++) + { + if (i % 16 == 0) + { + if (i > 0) printf(" \"%s\"\n", text); + printf(" %04x:",i); + } + if (i % 4 == 0) printf(" "); + + printf("%02x",(int)data[i]); + if (isprint(data[i])) text[i%16] = data[i]; + else text[i%16] = '.'; + } + if ((i%16) != 0) { + text[i%16] = '\0'; + for(j = (i % 16); j < 16; ++j) { + printf(" "); + if (j % 4 == 0) printf(" "); + } + } + printf(" \"%s\"\n", text); + return; +} +#endif + +// Function Specification +// +// Name: do_apss_recovery +// +// Description: Collect FFDC and attempt recovery for APSS failures +// +// End Function Specification +void do_apss_recovery(void) +{ +#define PSS_START_COMMAND 0x8000000000000000ull +#define PSS_RESET_COMMAND 0x4000000000000000ull + int l_scom_rc = 0; + uint32_t l_scom_addr; + uint64_t l_spi_adc_ctrl0; + uint64_t l_spi_adc_ctrl1; + uint64_t l_spi_adc_ctrl2; + uint64_t l_spi_adc_status; + uint64_t l_spi_adc_reset; + uint64_t l_spi_adc_wdata; + + + TRAC_ERR("detected invalid power data[%08x%08x]", + (uint32_t)(G_gpe_continue_pwr_meas_read_args.meas_data[0] >> 32), + (uint32_t)(G_gpe_continue_pwr_meas_read_args.meas_data[0] & 0x00000000ffffffffull)); + + do + { + // Collect SPI ADC FFDC data + l_scom_addr = SPIPSS_ADC_RESET_REG; + l_scom_rc = _getscom(l_scom_addr, &l_spi_adc_reset, SCOM_TIMEOUT); + if(l_scom_rc) + { + break; + } + l_scom_addr = SPIPSS_ADC_CTRL_REG0; + l_scom_rc = _getscom(l_scom_addr, &l_spi_adc_ctrl0, SCOM_TIMEOUT); + if(l_scom_rc) + { + break; + } + l_scom_addr = SPIPSS_ADC_CTRL_REG1; + l_scom_rc = _getscom(l_scom_addr, &l_spi_adc_ctrl1, SCOM_TIMEOUT); + if(l_scom_rc) + { + break; + } + l_scom_addr = SPIPSS_ADC_CTRL_REG2; + l_scom_rc = _getscom(l_scom_addr, &l_spi_adc_ctrl2, SCOM_TIMEOUT); + if(l_scom_rc) + { + break; + } + l_scom_addr = SPIPSS_ADC_STATUS_REG; + l_scom_rc = _getscom(l_scom_addr, &l_spi_adc_status, SCOM_TIMEOUT); + if(l_scom_rc) + { + break; + } + l_scom_addr = SPIPSS_ADC_WDATA_REG; + l_scom_rc = _getscom(l_scom_addr, &l_spi_adc_wdata, SCOM_TIMEOUT); + if(l_scom_rc) + { + break; + } + + TRAC_ERR("70000[%08x] 70001[%08x] 70002[%08x] 70003|70005[%08x] 70010[%08x]", + (uint32_t)(l_spi_adc_ctrl0 >> 32), + (uint32_t)(l_spi_adc_ctrl1 >> 32), + (uint32_t)(l_spi_adc_ctrl2 >> 32), + (uint32_t)((l_spi_adc_status >> 32) | (l_spi_adc_reset >> 48)), // Stuff reset register in lower 16 bits + (uint32_t)(l_spi_adc_wdata >> 32)); + + // Special error handling on OCC backup. Keep an up/down counter of + // fail/success and log predictive error when we reach the limit. + if(G_occ_role == OCC_SLAVE) + { + if(G_backup_fail_count < MAX_BACKUP_FAILURES) + { + // Increment the up/down counter + G_backup_fail_count++; + } + else + { + //We're logging the error so stop running apss tasks + rtl_stop_task(TASK_ID_APSS_START); + rtl_stop_task(TASK_ID_APSS_CONT); + rtl_stop_task(TASK_ID_APSS_DONE); + + TRAC_INFO("Redundant APSS has exceeded failure threshold. Logging Error"); + + /* + * @errortype + * @moduleid PSS_MID_DO_APSS_RECOVERY + * @reasoncode REDUNDANT_APSS_GPE_FAILURE + * @userdata1 0 + * @userdata2 0 + * @userdata4 OCC_NO_EXTENDED_RC + * @devdesc Redundant APSS failure. Power Management Redundancy Lost. + */ + errlHndl_t l_err = createErrl(PSS_MID_DO_APSS_RECOVERY, + REDUNDANT_APSS_GPE_FAILURE, + OCC_NO_EXTENDED_RC, + ERRL_SEV_PREDICTIVE, + NULL, + DEFAULT_TRACE_SIZE, + 0, + 0); + + // APSS callout + addCalloutToErrl(l_err, + ERRL_CALLOUT_TYPE_HUID, + G_sysConfigData.apss_huid, + ERRL_CALLOUT_PRIORITY_HIGH); + // Processor callout + addCalloutToErrl(l_err, + ERRL_CALLOUT_TYPE_HUID, + G_sysConfigData.proc_huid, + ERRL_CALLOUT_PRIORITY_LOW); + // Backplane callout + addCalloutToErrl(l_err, + ERRL_CALLOUT_TYPE_HUID, + G_sysConfigData.backplane_huid, + ERRL_CALLOUT_PRIORITY_LOW); + // Firmware callout + addCalloutToErrl(l_err, + ERRL_CALLOUT_TYPE_COMPONENT_ID, + ERRL_COMPONENT_ID_FIRMWARE, + ERRL_CALLOUT_PRIORITY_MED); + + commitErrl(&l_err); + + break; + } + } + + TRAC_INFO("Starting APSS recovery. fail_count=%d", G_backup_fail_count); + + // Reset the ADC engine + l_scom_addr = SPIPSS_ADC_RESET_REG; + l_scom_rc = _putscom(l_scom_addr, PSS_RESET_COMMAND, SCOM_TIMEOUT); + if(l_scom_rc) + { + break; + } + + // Zero out the reset register + l_scom_rc = _putscom(l_scom_addr, 0, SCOM_TIMEOUT); + if(l_scom_rc) + { + break; + } + + // Attempt recovery by sending the apss + // command that was set up earlier by initialization GPE + l_scom_addr = SPIPSS_P2S_COMMAND_REG; + l_scom_rc = _putscom(l_scom_addr, PSS_START_COMMAND, SCOM_TIMEOUT); + if(l_scom_rc) + { + break; + } + }while(0); + + // Just trace it if we get a scom failure trying to collect FFDC + if(l_scom_rc) + { + TRAC_ERR("apss recovery scom failure. addr=0x%08x, rc=0x%08x", l_scom_addr, l_scom_rc); + } +} + +// Note: The complete request must be global, since it must stick around until after the +// GPE program has completed (in order to do the callback). +PoreFlex G_meas_start_request; +// Function Specification +// +// Name: task_apss_start_pwr_meas +// +// Description: Start the GPE program to request power measurement data from APSS +// If previous call had failed, commit the error and request reset +// +// Task Flags: RTL_FLAG_MSTR, RTL_FLAG_OBS, RTL_FLAG_ACTIVE, RTL_FLAG_APSS_PRES +// +// End Function Specification +void task_apss_start_pwr_meas(struct task *i_self) +{ + int l_rc = 0; + static bool L_scheduled = FALSE; + static bool L_idle_traced = FALSE; + static bool L_ffdc_collected = FALSE; + + // Create/schedule GPE_start_pwr_meas_read (non-blocking) + APSS_DBG("GPE_start_pwr_meas_read started\n"); + + do + { + if (!async_request_is_idle(&G_meas_start_request.request)) + { + if (!L_idle_traced) + { + TRAC_ERR("task_apss_start_pwr_meas: request is not idle."); + L_idle_traced = TRUE; + } + break; + } + + // Check if we need to try recovering the apss + if(G_apss_recovery_requested) + { + // Do recovery then wait until next tick to do anything more. + do_apss_recovery(); + break; + } + + if (L_scheduled) + { + if ((ASYNC_REQUEST_STATE_COMPLETE != G_meas_start_request.request.completion_state) || + (0 != G_gpe_start_pwr_meas_read_args.error.error)) + { + //error should only be non-zero in the case where the GPE timed out waiting for + //the APSS master to complete the last operation. Just keep retrying until + //DCOM resets us due to not having valid power data. + TRAC_ERR("task_apss_start_pwr_meas: request is not complete or failed with an error(rc:0x%08X, ffdc:0x%08X%08X). " \ + "CompletionState:0x%X.", + G_gpe_start_pwr_meas_read_args.error.rc, + G_gpe_start_pwr_meas_read_args.error.ffdc >> 32, + G_gpe_start_pwr_meas_read_args.error.ffdc, + G_meas_start_request.request.completion_state); + + // Collect FFDC and log error once. + if (!L_ffdc_collected) + { + errlHndl_t l_err = NULL; + + /* + * @errortype + * @moduleid PSS_MID_APSS_START_MEAS + * @reasoncode APSS_GPE_FAILURE + * @userdata1 GPE returned rc code + * @userdata4 ERC_APSS_COMPLETE_FAILURE + * @devdesc Failure getting power measurement data from APSS + */ + l_err = createErrl(PSS_MID_APSS_START_MEAS, // i_modId + APSS_GPE_FAILURE, // i_reasonCode + ERC_APSS_COMPLETE_FAILURE, + ERRL_SEV_INFORMATIONAL, + NULL, + DEFAULT_TRACE_SIZE, + G_gpe_start_pwr_meas_read_args.error.rc, + 0); + + addUsrDtlsToErrl(l_err, + (uint8_t*)&G_meas_start_request.ffdc, + sizeof(G_meas_start_request.ffdc), + ERRL_STRUCT_VERSION_1, + ERRL_USR_DTL_BINARY_DATA); + + // Commit Error + commitErrl(&l_err); + + // Set to true so that we don't log this error again. + L_ffdc_collected = TRUE; + } + } + } + + // Clear these out prior to starting the GPE (GPE only sets them) + G_gpe_start_pwr_meas_read_args.error.error = 0; + G_gpe_start_pwr_meas_read_args.error.ffdc = 0; + + // Submit the next request + l_rc = pore_flex_schedule(&G_meas_start_request); + if (0 != l_rc) + { + errlHndl_t l_err = NULL; + + TRAC_ERR("task_apss_start_pwr_meas: schedule failed w/rc=0x%08X (%d us)", l_rc, + (int) ((ssx_timebase_get())/(SSX_TIMEBASE_FREQUENCY_HZ/1000000))); + + /* + * @errortype + * @moduleid PSS_MID_APSS_START_MEAS + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 GPE shedule returned rc code + * @userdata2 0 + * @userdata4 ERC_APSS_SCHEDULE_FAILURE + * @devdesc task_apss_start_pwr_meas schedule failed + */ + l_err = createErrl(PSS_MID_APSS_START_MEAS, + SSX_GENERIC_FAILURE, + ERC_APSS_SCHEDULE_FAILURE, + ERRL_SEV_PREDICTIVE, + NULL, + DEFAULT_TRACE_SIZE, + l_rc, + 0); + + // Request reset since this should never happen. + REQUEST_RESET(l_err); + L_scheduled = FALSE; + break; + } + + L_scheduled = TRUE; + + + }while (0); + + + APSS_DBG("GPE_start_pwr_meas_read finished w/rc=0x%08X\n", G_gpe_start_pwr_meas_read_args.error.rc); + APSS_DBG_HEXDUMP(&G_gpe_start_pwr_meas_read_args, sizeof(G_gpe_start_pwr_meas_read_args), "G_gpe_start_pwr_meas_read_args"); + G_ApssPwrMeasCompleted = FALSE; // Will complete when 3rd task is complete. + G_gpe_apss_time_start = ssx_timebase_get(); + + +} // end task_apss_start_pwr_meas() + + +// Note: The complete request must be global, since it must stick around until after the +// GPE program has completed (in order to do the callback). +PoreFlex G_meas_cont_request; +// Function Specification +// +// Name: task_apss_continue_pwr_meas +// +// Description: Start GPE to collect 1st block of power measurement data and request +// the 2nd block +// If previous call had failed, commit the error and request reset +// +// Task Flags: RTL_FLAG_MSTR, RTL_FLAG_OBS, RTL_FLAG_ACTIVE, RTL_FLAG_APSS_PRES +// +// End Function Specification +void task_apss_continue_pwr_meas(struct task *i_self) +{ + int l_rc = 0; + static bool L_scheduled = FALSE; + static bool L_idle_traced = FALSE; + static bool L_ffdc_collected = FALSE; + + // Create/schedule GPE_apss_continue_pwr_meas_read (non-blocking) + APSS_DBG("Calling task_apss_continue_pwr_meas.\n"); + + do + { + if (!async_request_is_idle(&G_meas_cont_request.request)) + { + if (!L_idle_traced) + { + TRAC_ERR("task_apss_continue_pwr_meas: request is not idle."); + L_idle_traced = TRUE; + } + break; + } + + //Don't run anything if apss recovery is in progress + if(G_apss_recovery_requested) + { + break; + } + + if (L_scheduled) + { + if ((ASYNC_REQUEST_STATE_COMPLETE != G_meas_cont_request.request.completion_state) || + (0 != G_gpe_continue_pwr_meas_read_args.error.error)) + { + //error should only be non-zero in the case where the GPE timed out waiting for + //the APSS master to complete the last operation. Just keep retrying until + //DCOM resets us due to not having valid power data. + TRAC_ERR("task_apss_continue_pwr_meas: request is not complete or failed with an error(rc:0x%08X, ffdc:0x%08X%08X). " \ + "CompletionState:0x%X.", + G_gpe_continue_pwr_meas_read_args.error.rc, + G_gpe_continue_pwr_meas_read_args.error.ffdc >> 32, + G_gpe_continue_pwr_meas_read_args.error.ffdc, + G_meas_cont_request.request.completion_state); + + + // Collect FFDC and log error once. + if (!L_ffdc_collected) + { + errlHndl_t l_err = NULL; + + /* + * @errortype + * @moduleid PSS_MID_APSS_CONT_MEAS + * @reasoncode APSS_GPE_FAILURE + * @userdata1 GPE returned rc code + * @userdata2 0 + * @userdata4 ERC_APSS_COMPLETE_FAILURE + * @devdesc Failure getting power measurement data from APSS + */ + l_err = createErrl(PSS_MID_APSS_CONT_MEAS, // i_modId + APSS_GPE_FAILURE, // i_reasonCode + ERC_APSS_COMPLETE_FAILURE, + ERRL_SEV_INFORMATIONAL, + NULL, + DEFAULT_TRACE_SIZE, + G_gpe_continue_pwr_meas_read_args.error.rc, + 0); + + addUsrDtlsToErrl(l_err, + (uint8_t*)&G_meas_cont_request.ffdc, + sizeof(G_meas_cont_request.ffdc), + ERRL_STRUCT_VERSION_1, + ERRL_USR_DTL_BINARY_DATA); + + // Commit Error + commitErrl(&l_err); + + // Set to true so that we don't log this error again. + L_ffdc_collected = TRUE; + } + } + } + + // Clear these out prior to starting the GPE (GPE only sets them) + G_gpe_continue_pwr_meas_read_args.error.error = 0; + G_gpe_continue_pwr_meas_read_args.error.ffdc = 0; + + // Submit the next request + l_rc = pore_flex_schedule(&G_meas_cont_request); + if (0 != l_rc) + { + errlHndl_t l_err = NULL; + + TRAC_ERR("task_apss_cont_pwr_meas: schedule failed w/rc=0x%08X (%d us)", l_rc, + (int) ((ssx_timebase_get())/(SSX_TIMEBASE_FREQUENCY_HZ/1000000))); + + /* + * @errortype + * @moduleid PSS_MID_APSS_CONT_MEAS + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 GPE shedule returned rc code + * @userdata2 0 + * @userdata4 ERC_APSS_SCHEDULE_FAILURE + * @devdesc task_apss_continue_pwr_meas schedule failed + */ + l_err = createErrl(PSS_MID_APSS_CONT_MEAS, + SSX_GENERIC_FAILURE, + ERC_APSS_SCHEDULE_FAILURE, + ERRL_SEV_PREDICTIVE, + NULL, + DEFAULT_TRACE_SIZE, + l_rc, + 0); + + // Request reset since this should never happen. + REQUEST_RESET(l_err); + L_scheduled = FALSE; + break; + } + + L_scheduled = TRUE; + + }while (0); + + APSS_DBG("task_apss_continue_pwr_meas: finished w/rc=0x%08X\n", G_gpe_continue_pwr_meas_read_args.error.rc); + APSS_DBG_HEXDUMP(&G_gpe_continue_pwr_meas_read_args, sizeof(G_gpe_continue_pwr_meas_read_args), "G_gpe_continue_pwr_meas_read_args"); + +} // end task_apss_continue_pwr_meas + +// Function Specification +// +// Name: reformat_meas_data +// +// Description: Extract measurement from GPE programs into G_apss_pwr_meas structure +// This function is called when the GPE completes the final measurement +// collection for this loop. +// +// End Function Specification +#define APSS_ADC_SEQ_MASK 0xf000f000f000f000ull +#define APSS_ADC_SEQ_CHECK 0x0000100020003000ull +void reformat_meas_data() +{ + APSS_DBG("GPE_complete_pwr_meas_read finished w/rc=0x%08X\n", G_gpe_complete_pwr_meas_read_args.error.rc); + APSS_DBG_HEXDUMP(&G_gpe_complete_pwr_meas_read_args, sizeof(G_gpe_complete_pwr_meas_read_args), "G_gpe_complete_pwr_meas_read_args"); + + do + { + // Make sure complete was successful + if (G_gpe_complete_pwr_meas_read_args.error.error) + { + break; + } + + // Check that the first 4 sequence nibbles are 0, 1, 2, 3 in the ADC data + if (((G_gpe_continue_pwr_meas_read_args.meas_data[0] & APSS_ADC_SEQ_MASK) != APSS_ADC_SEQ_CHECK) || + !(G_gpe_continue_pwr_meas_read_args.meas_data[0] & ~APSS_ADC_SEQ_MASK)) + { + // Recovery will begin on the next tick + G_apss_recovery_requested = TRUE; + break; + } + + // Decrement up/down fail counter for backup on success. + if(G_backup_fail_count) + { + G_backup_fail_count--; + } + + // Don't do the copy unless this is the master OCC + if(G_occ_role == OCC_MASTER) + { + + // Fail every 16 seconds + APSS_DBG("Populate meas data:\n"); + + // Merge continue/complete data into a single buffer + const uint16_t l_continue_meas_length = sizeof(G_gpe_continue_pwr_meas_read_args.meas_data); + const uint16_t l_complete_meas_length = sizeof(G_gpe_complete_pwr_meas_read_args.meas_data); + uint8_t l_buffer[l_continue_meas_length+l_complete_meas_length]; + memcpy(&l_buffer[ 0], G_gpe_continue_pwr_meas_read_args.meas_data, l_continue_meas_length); + memcpy(&l_buffer[l_continue_meas_length], G_gpe_complete_pwr_meas_read_args.meas_data, l_complete_meas_length); + APSS_DBG_HEXDUMP(l_buffer, sizeof(l_buffer), "l_buffer"); + + // Copy measurements into correct struction locations (based on composite config) + uint16_t l_index = 0; + memcpy(G_apss_pwr_meas.adc, &l_buffer[l_index], (G_apss_composite_config.numAdcChannelsToRead * 2)); + l_index += (G_apss_composite_config.numAdcChannelsToRead * 2); + memcpy(G_apss_pwr_meas.gpio, &l_buffer[l_index], (G_apss_composite_config.numGpioPortsToRead * 2)); + // TOD is always located at same offset + memcpy(&G_apss_pwr_meas.tod, &l_buffer[l_continue_meas_length+l_complete_meas_length-8], 8); + + APSS_DBG("...into structure: (%d ADC, %d GPIO)\n", G_apss_composite_config.numAdcChannelsToRead, + G_apss_composite_config.numGpioPortsToRead); + APSS_DBG_HEXDUMP(&G_apss_pwr_meas, sizeof(G_apss_pwr_meas), "G_apss_pwr_meas"); + } + + // Mark apss pwr meas completed and valid + G_ApssPwrMeasCompleted = TRUE; + G_gpe_apss_time_end = ssx_timebase_get(); + APSS_DBG("APSS Completed - %d\n",(int) ssx_timebase_get()); + }while(0); +} + + +// Note: The complete request must be global, since it must stick around until after the +// GPE program has completed (in order to do the callback). +PoreFlex G_meas_complete_request; + +// Function Specification +// +// Name: task_apss_complete_pwr_meas +// +// Description: Start GPE to collect 2nd block of power measurement data and TOD. +// If previous call had failed, commit the error and request reset +// +// Task Flags: RTL_FLAG_MSTR, RTL_FLAG_OBS, RTL_FLAG_ACTIVE, RTL_FLAG_APSS_PRES +// +// End Function Specification +void task_apss_complete_pwr_meas(struct task *i_self) +{ + int l_rc = 0; + static bool L_scheduled = FALSE; + static bool L_idle_traced = FALSE; + static bool L_ffdc_collected = FALSE; + + // Create/schedule GPE_apss_complete_pwr_meas_read (non-blocking) + APSS_DBG("Calling task_apss_complete_pwr_meas.\n"); + + do + { + if (!async_request_is_idle(&G_meas_complete_request.request)) + { + if (!L_idle_traced) + { + TRAC_ERR("task_apss_complete_pwr_meas: request is not idle."); + L_idle_traced = TRUE; + } + break; + } + + if(G_apss_recovery_requested) + { + // Allow apss measurement to proceed on next tick + G_apss_recovery_requested = FALSE; + break; + } + + + if (L_scheduled) + { + if ((ASYNC_REQUEST_STATE_COMPLETE != G_meas_complete_request.request.completion_state) || + (0 != G_gpe_complete_pwr_meas_read_args.error.error)) + { + // Error should only be non-zero in the case where the GPE timed out waiting for + // the APSS master to complete the last operation. Just keep retrying until + // DCOM resets us due to not having valid power data. + TRAC_ERR("task_apss_complete_pwr_meas: request is not complete or failed with an error(rc:0x%08X, ffdc:0x%08X%08X). " \ + "CompletionState:0x%X.", + G_gpe_complete_pwr_meas_read_args.error.rc, + G_gpe_complete_pwr_meas_read_args.error.ffdc >> 32, + G_gpe_complete_pwr_meas_read_args.error.ffdc, + G_meas_complete_request.request.completion_state); + + // Collect FFDC and log error once. + if (!L_ffdc_collected) + { + errlHndl_t l_err = NULL; + + /* + * @errortype + * @moduleid PSS_MID_APSS_COMPLETE_MEAS + * @reasoncode APSS_GPE_FAILURE + * @userdata1 GPE returned rc code + * @userdata2 0 + * @userdata4 ERC_APSS_COMPLETE_FAILURE + * @devdesc Failure getting power measurement data from APSS + */ + l_err = createErrl(PSS_MID_APSS_COMPLETE_MEAS, // i_modId + APSS_GPE_FAILURE, // i_reasonCode + ERC_APSS_COMPLETE_FAILURE, + ERRL_SEV_INFORMATIONAL, + NULL, + DEFAULT_TRACE_SIZE, + G_gpe_complete_pwr_meas_read_args.error.rc, + 0); + + addUsrDtlsToErrl(l_err, + (uint8_t*)&G_meas_complete_request.ffdc, + sizeof(G_meas_complete_request.ffdc), + ERRL_STRUCT_VERSION_1, + ERRL_USR_DTL_BINARY_DATA); + + // Commit Error + commitErrl(&l_err); + + // Set to true so that we don't log this error again. + L_ffdc_collected = TRUE; + } + } + } + + // Clear these out prior to starting the GPE (GPE only sets them) + G_gpe_complete_pwr_meas_read_args.error.error = 0; + G_gpe_complete_pwr_meas_read_args.error.ffdc = 0; + + // Submit the next request + l_rc = pore_flex_schedule(&G_meas_complete_request); + if (0 != l_rc) + { + errlHndl_t l_err = NULL; + + TRAC_ERR("task_apss_complete_pwr_meas: schedule failed w/rc=0x%08X (%d us)", l_rc, + (int) ((ssx_timebase_get())/(SSX_TIMEBASE_FREQUENCY_HZ/1000000))); + + /* + * @errortype + * @moduleid PSS_MID_APSS_COMPLETE_MEAS + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 GPE shedule returned rc code + * @userdata2 0 + * @userdata4 ERC_APSS_SCHEDULE_FAILURE + * @devdesc task_apss_complete_pwr_meas schedule failed + */ + l_err = createErrl(PSS_MID_APSS_COMPLETE_MEAS, + SSX_GENERIC_FAILURE, + ERC_APSS_SCHEDULE_FAILURE, + ERRL_SEV_PREDICTIVE, + NULL, + DEFAULT_TRACE_SIZE, + l_rc, + 0); + + // Request reset since this should never happen. + REQUEST_RESET(l_err); + L_scheduled = FALSE; + break; + } + + L_scheduled = TRUE; + + + }while (0); + + APSS_DBG("task_apss_complete_pwr_meas: finished w/rc=0x%08X\n", G_gpe_complete_pwr_meas_read_args.error.rc); + APSS_DBG_HEXDUMP(&G_gpe_complete_pwr_meas_read_args, sizeof(G_gpe_complete_pwr_meas_read_args), "G_gpe_complete_pwr_meas_read_args"); + + +} // end task_apss_complete_pwr_meas + +bool apss_gpio_get(uint8_t i_pin_number, uint8_t *o_pin_value) +{ + bool l_valid = FALSE; + + if( (i_pin_number != SYSCFG_INVALID_PIN) && (o_pin_value != NULL) ) + { + // Check if G_dcom_slv_inbox_rx is valid. + // The default value is all 0, so check if it's no-zero + bool l_dcom_data_valid = FALSE; + int i=0; + for(;i<sizeof(G_dcom_slv_inbox_rx);i++) + { + if( ((char*)&G_dcom_slv_inbox_rx)[i] != 0 ) + { + l_dcom_data_valid = TRUE; + break; + } + } + + if( l_dcom_data_valid == TRUE) + { + uint8_t l_gpio_port = i_pin_number/NUM_OF_APSS_PINS_PER_GPIO_PORT; + uint8_t l_gpio_mask = 0x1 << i_pin_number % NUM_OF_APSS_PINS_PER_GPIO_PORT; + l_valid = TRUE; + if( G_dcom_slv_inbox_rx.gpio[l_gpio_port] & l_gpio_mask ) + { + *o_pin_value = 1; + } + else + { + *o_pin_value = 0; + } + } + } + return l_valid; +} + diff --git a/src/occ_405/pss/apss.h b/src/occ_405/pss/apss.h new file mode 100644 index 0000000..8abd42e --- /dev/null +++ b/src/occ_405/pss/apss.h @@ -0,0 +1,138 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/pss/apss.h $ */ +/* */ +/* 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 */ + +#ifndef _APSS_H +#define _APSS_H + +#include <occ_common.h> +#include <trac_interface.h> +#include <errl.h> +#include <gpe_export.h> +#include <rtls.h> + +#define NUM_OF_APSS_GPIO_PORTS 2 +#define NUM_OF_APSS_PINS_PER_GPIO_PORT 8 +#define MAX_APSS_ADC_CHANNELS 16 +#define MAX_APSS_GPIO_PORTS NUM_OF_APSS_GPIO_PORTS +#define MEAS_PADDING_REQUIRED (28-MAX_APSS_ADC_CHANNELS+MAX_APSS_GPIO_PORTS) +#define APSS_12BIT_ADC_MASK 0x0fff + +#if ( (!defined(NO_TRAC_STRINGS)) && defined(TRAC_TO_SIMICS) ) +void dumpHexString(const void *i_data, const unsigned int len, const char *string); +#endif + +#define APSS_DATA_FAIL_PMAX_RAIL 16 //Number of steps before we lower Pmax_rail to nominal. This should allow for 4ms/16ticks with no APSS data. +#define APSS_DATA_FAIL_MAX 400 //Number of steps we reach before reseting OCC. This should allow for 100ms/400ticks with no APSS data. +#define APSS_DATA_FAILURE_STEP 1 //Number of steps to increment FAIL_COUNT due to a failed APSS data collection. +#define APSS_ERRORLOG_RESET_THRESHOLD 16 //When to allow apss tasks to log another error if count goes back to 0 again. + +extern uint16_t G_apss_fail_updown_count; //Used to keep count of number of APSS data collection fails. + +//Decrement APSS_FAIL_COUNT to 0. +#define APSS_SUCCESS() {(G_apss_fail_updown_count = 0);} + +// Increment APSS_FAIL_COUNT by APSS_DATA_FAILURE_STEP to a maximum of APSS_DATA_FAIL_MAX. +#define APSS_FAIL() {((APSS_DATA_FAIL_MAX - G_apss_fail_updown_count) >= APSS_DATA_FAILURE_STEP)? \ + (G_apss_fail_updown_count += APSS_DATA_FAILURE_STEP): \ + (G_apss_fail_updown_count = APSS_DATA_FAIL_MAX);} + +struct apssGpioConfigStruct +{ + uint8_t direction; + uint8_t drive; + uint8_t interrupt; +} __attribute__ ((__packed__)); +typedef struct apssGpioConfigStruct apssGpioConfigStruct_t; + +struct apssCompositeConfigStruct +{ + uint8_t numAdcChannelsToRead; + uint8_t numGpioPortsToRead; +} __attribute__ ((__packed__)); +typedef struct apssCompositeConfigStruct apssCompositeConfigStruct_t; + +struct apssPwrMeasStruct +{ + uint16_t adc[MAX_APSS_ADC_CHANNELS]; + uint16_t gpio[MAX_APSS_GPIO_PORTS]; + uint16_t pad[MEAS_PADDING_REQUIRED]; // padding to allow TOD to be 8 byte aligned + uint64_t tod; // Time of Day that the ADC Collection Completed +} __attribute__ ((__packed__)); +typedef struct apssPwrMeasStruct apssPwrMeasStruct_t; + +typedef struct { + PoreGpeErrorStruct error; + apssGpioConfigStruct_t config0; // G_gpio_config[0] (input to APSS) + apssGpioConfigStruct_t config1; // G_gpio_config[1] (input to APSS) +} initGpioArgs_t; + +typedef struct { + PoreGpeErrorStruct error; + apssCompositeConfigStruct_t config; // G_apss_composite_config (input to APSS) +} setCompositeModeArgs_t; + +typedef struct +{ + PoreGpeErrorStruct error; +} apss_start_args_t; + +typedef struct { + PoreGpeErrorStruct error; + uint64_t meas_data[4]; // G_apss_pwr_meas (1st block of data) (output from APSS) +} apss_continue_args_t; + +typedef struct { + PoreGpeErrorStruct error; + uint64_t meas_data[4]; // G_apss_pwr_meas (2nd block of data) (output from APSS) +} apss_complete_args_t; + +// @TODO - Does G_gpio_config and G_apss_composite_config need to be used outside of APSS? If not I will remove from .h +// G_gpio_config: configuration for APSS GPIO pins (default all input, all 1's, not int) +extern const apssGpioConfigStruct_t G_gpio_config[NUM_OF_APSS_GPIO_PORTS]; +// G_apss_composite_config: system parms needed to select correct composite command options +extern const apssCompositeConfigStruct_t G_apss_composite_config; + +// G_apss_pwr_meas: power, temp and GPIO readings that OCC gathers from APSS every tick +extern apssPwrMeasStruct_t G_apss_pwr_meas; + +// Used to tell slave inbox that pwr meas is complete +extern volatile bool G_ApssPwrMeasCompleted; + +extern initGpioArgs_t G_gpe_apss_initialize_gpio_args; +extern setCompositeModeArgs_t G_gpe_apss_set_composite_mode_args; + +extern uint64_t G_gpe_apss_time_start; +extern uint64_t G_gpe_apss_time_end; + +// apss_initialize is product applet +void task_apss_start_pwr_meas(task_t *i_self); +void task_apss_continue_pwr_meas(task_t *i_self); +void task_apss_complete_pwr_meas(task_t *i_self); + +void apss_test_pwr_meas(); // @temp cc - used to test measurements +void reformat_meas_data(); +bool apss_gpio_get(uint8_t i_pin_number, uint8_t *o_pin_value); + +#endif //_APSS_H diff --git a/src/occ_405/pss/dpss.c b/src/occ_405/pss/dpss.c new file mode 100755 index 0000000..6db3cdc --- /dev/null +++ b/src/occ_405/pss/dpss.c @@ -0,0 +1,189 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/pss/dpss.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 */ + +#include "ssx.h" + +#include <dpss.h> +#include <trac.h> +#include <occ_common.h> +#include <comp_ids.h> +#include <occ_sys_config.h> +#include <trac_interface.h> +#include <occ_service_codes.h> +#include <pss_service_codes.h> +#include <state.h> +#include <amec_oversub.h> +#include <ppc405_irq.h> + +// Macro creates a 'bridge' handler that converts the initial fast-mode to full- +// mode interrupt handler +SSX_IRQ_FAST2FULL(isr_dpss_oversubscription_handler, isr_dpss_oversubscription_handler_full); + +// Increment a counter each time we see a phantom interrupt (used by health monitor thread) +uint32_t G_occ_phantom_critical_count = 0; +uint32_t G_occ_phantom_noncritical_count = 0; + +// Function Specification +// +// Name: isr_dpss_oversubscription_handler_full +// +// Description: From the flow diagram: +// Will eventually be doing something to set the Pstates & Memory +// Throttles when this interrupt occurs, but for now just put in this +// comment and no code besides clearing the irq and tracing the fact that +// we got an interrupt. +// +// End Function Specification +void isr_dpss_oversubscription_handler_full(void *private, SsxIrqId irq, int priority) +{ + SsxMachineContext ctx; + + // disable further interrupts at this level + ssx_irq_disable(irq); + + // enter the protected context + ssx_critical_section_enter( SSX_CRITICAL, &ctx ); + + // clear this irq + ssx_irq_status_clear(irq); + + // exit the protected context + ssx_critical_section_exit( &ctx ); + + // call oversub isr + amec_oversub_isr(); + + // re-enable interrupts at this level + ssx_irq_enable(irq); + +} // end isr_dpss_oversubscription_handler_full + +// Function Specification +// +// Name: occ_phantom_irq_handler +// +// Description: +// handler for an interrupt that fired and then went away before +// we could read what it was. +// +// End Function Specification +void occ_phantom_irq_handler(void* i_arg, SsxIrqId i_irq, int i_critical) +{ + if(i_critical == SSX_CRITICAL) + { + G_occ_phantom_critical_count++; + } + else + { + G_occ_phantom_noncritical_count++; + } +} + +// Function Specification +// +// Name: dpss_oversubscription_irq_initialize +// +// Description: +// Installs the power oversubscription IRQ handler for the DPSS +// +// End Function Specification +errlHndl_t dpss_oversubscription_irq_initialize() +{ + int rc = 0; + errlHndl_t l_err = NULL; + + // NOTE: It is believed that the oversubscription interrupt bounces + // on and off as power supplies are re-inserted. If it happens quickly enough + // it will clear the interrupt before the code has a chance to see the cause + // of the interrupt. The default phantom handler would then be invoked and + // cause occ to panic. Instead, we just increment a counter and log an info + // error. + __ppc405_phantom_irq.handler = occ_phantom_irq_handler; + + // Disable the IRQ while we work on it + ssx_irq_disable(PGP_IRQ_EXTERNAL_TRAP); + + // Setup the IRQ + rc = ssx_irq_setup(PGP_IRQ_EXTERNAL_TRAP, + SSX_IRQ_POLARITY_ACTIVE_LOW, + SSX_IRQ_TRIGGER_LEVEL_SENSITIVE); + + if( rc ) { + TRAC_ERR("%s: Failed IRQ setup.", __FUNCTION__); + + /*@ + * @moduleid PSS_MID_DPSS_OVS_IRQ_INIT + * @reasonCode SSX_GENERIC_FAILURE + * @severity ERRL_SEV_PREDICTIVE + * @userdata1 ssx_irq_setup return code + * @userdata4 ERC_SSX_IRQ_SETUP_FAILURE + * @devdesc Firmware failure initializing DPSS IRQ + */ + l_err = createErrl( PSS_MID_DPSS_OVS_IRQ_INIT, // i_modId + SSX_GENERIC_FAILURE, // i_reasonCode + ERC_SSX_IRQ_SETUP_FAILURE, + ERRL_SEV_PREDICTIVE, + NULL, // tracDesc_t i_trace + 0, // i_traceSz + rc, // i_userData1 + 0); // i_userData2 + } + else { + // Set the IRQ handler + rc = ssx_irq_handler_set(PGP_IRQ_EXTERNAL_TRAP, + isr_dpss_oversubscription_handler, + NULL, + SSX_NONCRITICAL); + + if( rc ) { + TRAC_ERR("%s: Failed to set the IRQ handler.", __FUNCTION__); + + /*@ + * @moduleid PSS_MID_DPSS_OVS_IRQ_INIT + * @reasonCode SSX_GENERIC_FAILURE + * @severity ERRL_SEV_PREDICTIVE + * @userdata1 ssx_irq_handler_set return code + * @userdata4 ERC_SSX_IRQ_HANDLER_SET_FAILURE + * @devdesc Firmware failure setting up DPSS routine + */ + l_err = createErrl( PSS_MID_DPSS_OVS_IRQ_INIT, // i_modId + SSX_GENERIC_FAILURE, // i_reasonCode + ERC_SSX_IRQ_HANDLER_SET_FAILURE, + ERRL_SEV_PREDICTIVE, + NULL, // tracDesc_t i_trace + 0, // i_traceSz + rc, // i_userData1 + 0); // i_userData2 + } + else { + // Enable the IRQ + ssx_irq_status_clear(PGP_IRQ_EXTERNAL_TRAP); + ssx_irq_enable(PGP_IRQ_EXTERNAL_TRAP); + } + } + + return l_err; +} // end dpss_oversubscription_irq_initialize + diff --git a/src/occ_405/pss/dpss.h b/src/occ_405/pss/dpss.h new file mode 100755 index 0000000..6b42f72 --- /dev/null +++ b/src/occ_405/pss/dpss.h @@ -0,0 +1,40 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/pss/dpss.h $ */ +/* */ +/* 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 */ + +#ifndef _DPSS_H +#define _DPSS_H + +#include <errl.h> +#include <rtls.h> + +// dpss_initialize is part of the dpss init applet + +// DPSS oversubscription IRQ handler +void isr_dpss_oversubscription_handler_full(void *private, SsxIrqId irq, int priority); + +// Installs the DPSS oversubscription IRQ handler +errlHndl_t dpss_oversubscription_irq_initialize(); + +#endif //_DPSS_H diff --git a/src/occ_405/pss/pss_service_codes.h b/src/occ_405/pss/pss_service_codes.h new file mode 100755 index 0000000..a4eda54 --- /dev/null +++ b/src/occ_405/pss/pss_service_codes.h @@ -0,0 +1,43 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/pss/pss_service_codes.h $ */ +/* */ +/* 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 */ + +#ifndef _PSS_SERVICE_CODES_H_ +#define _PSS_SERVICE_CODES_H_ + +#include <comp_ids.h> + +enum pssModuleId +{ + PSS_MID_APSS_INIT = PSS_COMP_ID | 0x00, + PSS_MID_APSS_START_MEAS = PSS_COMP_ID | 0x01, + PSS_MID_APSS_CONT_MEAS = PSS_COMP_ID | 0x02, + PSS_MID_APSS_COMPLETE_MEAS = PSS_COMP_ID | 0x03, + PSS_MID_DPSS_INIT = PSS_COMP_ID | 0x04, + PSS_MID_DPSS_OVS_IRQ_INIT = PSS_COMP_ID | 0x05, + PSS_MID_DPSS_RD_STATUS = PSS_COMP_ID | 0x06, + PSS_MID_DO_APSS_RECOVERY = PSS_COMP_ID | 0x07, +}; + +#endif /* #ifndef _PSS_SERVICE_CODES_H_ */ diff --git a/src/occ_405/pss/test/Makefile b/src/occ_405/pss/test/Makefile new file mode 100755 index 0000000..045693b --- /dev/null +++ b/src/occ_405/pss/test/Makefile @@ -0,0 +1,79 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/occ_405/pss/test/Makefile $ +# +# 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 + +apsstest_CFILES = \ + ../../common.c \ + ../../errl/errl.c \ + ../../thread/threadSch.c \ + ../apss.c \ + apsstest.c +all_cfiles = ${apsstest_CFILES} + + +occ_GPEFILES = ../../gpe/apss_init.S \ + ../../gpe/apss_composite.S \ + ../../gpe/apss_meas_read_start.S \ + ../../gpe/apss_meas_read_cont.S \ + ../../gpe/apss_meas_read_complete.S \ + ../../gpe/pore_test.S +all_gpefiles = ${occ_GPEFILES} + + +APP = apsstest +APP_INCLUDES += -I../../../ssx +APP_INCLUDES += -I../../../lib +APP_INCLUDES += -I../../incl +APP_INCLUDES += -I../../trac +APP_INCLUDES += -I../../async +APP_INCLUDES += -I../../errl +APP_INCLUDES += -I../../gpe +APP_INCLUDES += -I../../thread +#APP_INCLUDES += -I../../aplt +#APP_INCLUDES += -I../../rtls +#APP_INCLUDES += -I../../sensor +APP_INCLUDES += -I../../pss +APP_INCLUDES += -I. + +D = -DSIMICS_MAGIC_PANIC=1 + +#D = -DVERIFICATION=1 \ + -DSSX_STACK_CHECK=0 \ + -DINITIALIZE_PMC=0 \ + -DINITIALIZE_SIMICS_IO=0 \ + -DINITIALIZE_RTX_IO=1 \ + -DINITIALIZE_PBA=1 \ + -DSIMICS_MAGIC_PANIC=1 \ + -DSSX_KERNEL_TRACE_ENABLE=1 + + +SOURCES = ${all_cfiles} ${all_gpefiles} +MODE = validation + +PGP_ASYNC_SUPPORT = 1 + +include ./app.mk + +pgas: + $(CC) $(CFLAGS) -c -Wa,-al -Wa,--listing-cont-lines='10' ${all_gpefiles} diff --git a/src/occ_405/pss/test/app.mk b/src/occ_405/pss/test/app.mk new file mode 100755 index 0000000..c1cf490 --- /dev/null +++ b/src/occ_405/pss/test/app.mk @@ -0,0 +1,102 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/occ_405/pss/test/app.mk $ +# +# 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 + +OCC = ../../ +SSX = ../../../ssx +LIB = ../../../lib +PGP = $(SSX)/pgp + +ifeq "$(MODE)" "firmware" +SSX_TIMER_SUPPORT = 0 +SSX_THREAD_SUPPORT = 0 +endif + +#******************************************************************************* +# Export +#******************************************************************************* +export SSX_TIMER_SUPPORT +export SSX_THREAD_SUPPORT +export PPC405_MMU_SUPPORT +export PGP_ASYNC_SUPPORT + +#******************************************************************************* +# Flags +#******************************************************************************* + +INCLUDES = -I $(OCC) -I$(LIB) + +include $(PGP)/ssx.mk + +C-OBJECTS = $(SOURCES:.c=.o) +OBJECTS = $(C-OBJECTS:.S=.o) + +LDFLAGS = -L $(SSX)/ssx -L $(SSX)/ppc32 -L $(SSX)/ppc405 -L $(SSX)/pgp \ + -L $(OCC) -L $(LIB) -lssx -lppc32 + + +DEFS += $(D) + +#******************************************************************************* +# compilation +#******************************************************************************* +all: $(OBJECTS) libssx.a + $(MAKE) -C $(PGP) DEFS="$(DEFS)" -e + $(CPP) -P $(DEFS) < $(PGP)/linkssx.cmd > linkscript + $(LD) $(OBJECTS) \ + -Tlinkscript $(LDFLAGS) -Map $(APP).map -Bstatic -o $(APP).out + $(OBJCOPY) -O binary $(APP).out $(APP).bin + $(OBJDUMP) -d $(APP).out > $(APP).dis + + +libssx.a: + $(MAKE) -C $(LIB) DEFS="$(DEFS)" -e + +#******************************************************************************* +# clean +#******************************************************************************* + +.PHONY : clean +clean: + rm -f *.o *.d *.d.* *.out *.bin *.srec *.dis *.map linkscript + rm -f ./*/*.o ./*/*.d ./*/*.d.* + +.PHONY : clean_all +clean_all: + $(MAKE) clean + $(MAKE) -C $(PGP) clean + +#******************************************************************************* +# Doxygen +#******************************************************************************* + +.PHONY : doc +doc: + doxygen doc/Doxyfile + +#******************************************************************************* +# .d file creation +#******************************************************************************* + +-include $(OBJECTS:.o=.d) diff --git a/src/occ_405/pss/test/apsstest.c b/src/occ_405/pss/test/apsstest.c new file mode 100755 index 0000000..768bdbe --- /dev/null +++ b/src/occ_405/pss/test/apsstest.c @@ -0,0 +1,415 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/pss/test/apsstest.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 */ + +#include "ssx.h" +#include "ssx_io.h" +#include "simics_stdio.h" +#include <thread.h> +#include <threadSch.h> +#include <errl.h> +#include <apss.h> + +// Period in which to run #timer_routine +#define TIMER_INTERVAL (SsxInterval) SSX_MICROSECONDS(5000) +SsxSemaphore prcd_sem; + +int g_j = 0; +int g_k = 0; + +SimicsStdio simics_stdout; +SimicsStdio simics_stderr; + +uint8_t noncritical_stack[NONCRITICAL_STACK_SIZE]; +uint8_t critical_stack[CRITICAL_STACK_SIZE]; + +SsxTimer G_test_timer; + +extern void timer_routine(void *private); +extern void rtloop_ocb_init(void); + +// Function Specification +// +// Name: pgp_validation_ssx_main_hook +// +// Description: +// +// End Function Specification +void pgp_validation_ssx_main_hook(void) +{ + +} + +// Function Specification +// +// Name: Cmd_Hndl_thread_routine +// +// Description: +// +// End Function Specification +//TODO placeholder +void Cmd_Hndl_thread_routine(void *arg) +{ + do + { + int x=0; + for(x=0; x < 1000; x++) + { + + } + //printf("Thread A running"); + }while(1); + +} + +// Function Specification +// +// Name: App_thread_routine +// +// Description: +// +// End Function Specification +void App_thread_routine(void *arg) +{ + int z=0; + do + { + int x=0; + for(x=0; x < 10000; x++) + { + z++; + } + }while(1); + +} + +// Function Specification +// +// Name: Thermal_Monitor_thread_routine +// +// Description: +// +// End Function Specification +void Thermal_Monitor_thread_routine(void *arg) +{ + int z=0; + do + { + int x=0; + for(x=0; x < 10000; x++) + { + z++; + } + //printf("Thread A running"); + }while(1); + +} + +// Function Specification +// +// Name: Hlth_Monitor_thread_routine +// +// Description: +// +// End Function Specification +void Hlth_Monitor_thread_routine(void *arg) +{ + int z=0; + do + { + int x=0; + for(x=0; x < 10000; x++) + { + z++; + } + //printf("Thread A running"); + }while(1); + +} + +// Function Specification +// +// Name: FFDC_thread_routine +// +// Description: +// +// End Function Specification +void FFDC_thread_routine(void *arg) +{ + int z=0; + do + { + int x=0; + for(x=0; x < 10000; x++) + { + z++; + } + //printf("Thread A running"); + }while(1); + +} + +/** PRCD Thread + * + * This thread loops as the highest priority thread, where it currently + * just + * + */ +// Function Specification +// +// Name: prcd_thread_routine +// +// Description: +// +// End Function Specification +void prcd_thread_routine(void *private) +{ + while(1) + { + // Just sit here until this semaphore is posted, which will never happen. + ssx_semaphore_pend(&prcd_sem, SSX_WAIT_FOREVER); + + // Only trace the first XX times that this function loops + if(g_j < 20) + { + g_k = 0; + g_j++; + + } + } +} + + +// Function Specification +// +// Name: apss_test_pwr_meas +// +// Description: Request the full power measurement data in a single function call for TESTING ONLY +// +// End Function Specification +extern PoreEntryPoint pore_test; // Sleep for specified amount of time... +void apss_test_pwr_meas(void) +{ + task_apss_start_pwr_meas(); + + // Schedule GPE program to delay to ensure the data is available... (BLOCKING) + // bad: 48, good: 56 + PoreFlex test_request; + DEBUG_PRINTF(("apss_test_pwr_meas: delay...\n")); + pore_flex_create(&test_request, + &pore_gpe0_queue, + (void*)pore_test, // entry_point + (uint32_t)56, // entry_point argument + NULL, // callback, + NULL, // callback arg + ASYNC_REQUEST_BLOCKING); // options + pore_flex_schedule(&test_request); + DEBUG_PRINTF(("apss_test_pwr_meas: delay complete\n")); + + task_apss_continue_pwr_meas(); + + task_apss_complete_pwr_meas(); + +} // end apss_test_pwr_meas() + + + + +/** Main Thread + * + * This thread currently just loops as the lowest priority thread, handling + * the lowest priority tasks. + * + */ +// Function Specification +// +// Name: main_thread_routine +// +// Description: +// +// End Function Specification +void main_thread_routine(void *private) +{ + // Start the critical 250uS timer + ssx_timer_schedule(&timer, 1, TIMER_INTERVAL); + + // Initialize APSS + errlHndl_t l_errl = apss_initialize(); + if (l_errl) + { + // init failed, attempt one more time before giving up + printf("ERROR: apss_initialize failed! (retrying)\n"); + setErrlSevToInfo(l_errl); + commitErrl(&l_errl); + + l_errl = apss_initialize(); + if (l_errl) + { + printf("ERROR: apss_initialize failed again! (OCC will be reset)"); + commitErrl(&l_errl); + + // $TODO - Request Reset + } + } + + // Attempt to retrieve 3 sets of measurements + printf("Attempting to gather power measurements\n"); + apss_test_pwr_meas(); + apss_test_pwr_meas(); + apss_test_pwr_meas(); + + while(1) + { + // Only trace the first XX times that this function loops + if(g_k < 3) + { + g_k++; + + // TRACE: Main Thread + } + + + // Sleep for 1000 before we run the loop again + ssx_sleep_absolute(1000); + } +} + +// Function Specification +// +// Name: dump_thread_info +// +// Description: +// +// End Function Specification +void dump_thread_info(void *arg) +{ + + printf("dumping thread info--------------------------\n"); + int l_rc = 0; + SsxThreadState l_state = 0; + SsxThreadPriority l_pri = 0; + int l_runnable=0; + int x=0; + for(x=0; x < THREADS_TO_SCHEDULE; x++) + { + l_rc = ssx_thread_info_get(G_scheduledThreads[x], + &l_state, + &l_pri, + &l_runnable); + + printf("Thread %p: State %x priority %x runnable %x rc %x Global index %x\n",G_scheduledThreads[x], + l_state, + l_pri, + l_runnable, + l_rc, + G_threadSchedulerIndex); + + } + +} + +/** Entry point for OCC execution + * + * main() currently initalizes our trace buffer along with creating threads + * and timers for execution. Note that once main runs ssx_start_threads, we + * never return as the SSX kernel takes over. + * + */ +// Function Specification +// +// Name: main +// +// Description: +// +// End Function Specification +int main(int argc, char **argv) +{ + //locals + errlHndl_t l_errl = NULL; + + // Initialize Trace Buffers immediately, so they can be used + // from this point on. + //TRAC_init_buffers(); + + // Initialize stdout so we can do printf from within simics env + simics_stdout_create(&simics_stdout); + simics_stderr_create(&simics_stderr); + stdout = (FILE *)(&simics_stdout); + stderr = (FILE *)(&simics_stderr); + + printf("Inside apsstest main\n"); + + // Initialize SSX Stacks (note that this also reinitializes the time base to 0) + ssx_initialize((SsxAddress)noncritical_stack, NONCRITICAL_STACK_SIZE, + (SsxAddress)critical_stack, CRITICAL_STACK_SIZE, + 0); + + // Create Global Semaphores + ssx_semaphore_create(&prcd_sem, 0, 13); + + // Create Threads + ssx_thread_create(&main_thread, + main_thread_routine, + (void *)0, + (SsxAddress)main_thread_stack, + THREAD_STACK_SIZE, + 1); + + // Create Threads + ssx_thread_create(&prcd_thread, + prcd_thread_routine, + (void *)0, + (SsxAddress)prcd_thread_stack, + THREAD_STACK_SIZE, + 0); + + // Make Threads runnable + ssx_thread_resume(&main_thread); + ssx_thread_resume(&prcd_thread); + + //Initialize the thread scheduler + l_errl = initThreadScheduler(); + + if( l_errl ) + { + // Trace and commit error + + // TODO add trace + + // commit log + // NOTE: log should be deleted by reader mechanism + commitErrl( &l_errl ); + } + + //kick off timer + ssx_timer_create(&G_test_timer, dump_thread_info, 0); + ssx_timer_schedule(&G_test_timer, 1, 500000000); + + + // Enter SSX Kernel + ssx_start_threads(); + + return 0; +} + |