diff options
author | Chris Cain <cjcain@us.ibm.com> | 2017-01-10 14:32:13 -0600 |
---|---|---|
committer | Christopher J. Cain <cjcain@us.ibm.com> | 2017-01-18 18:40:21 -0500 |
commit | 6089fe0e7580b1c5030d1f380b1bc91c293e8bb9 (patch) | |
tree | 274c7e5e0c6a3214fd4c792266fbe8a396fa23d8 /src/occ_405/pss | |
parent | 4141b5f5fef2ba4b444aabbda1677e7f583cd4e8 (diff) | |
download | talos-occ-6089fe0e7580b1c5030d1f380b1bc91c293e8bb9.tar.gz talos-occ-6089fe0e7580b1c5030d1f380b1bc91c293e8bb9.zip |
AVS Bus divider, loadline and misc changes
- validate CRC in cmd response
- read current / voltage on alternating ticks (commands on both bus for each tick)
- calculate chip power (with loadline) and power for each tick
- update divider value for bus speed
- add error history counters and add them to logs
Change-Id: I33bce916dc2dffef6a6d616633a5f1266d7baa7e
RTC: 163992
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/34947
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Martha Broyles <mbroyles@us.ibm.com>
Reviewed-by: Christopher J. Cain <cjcain@us.ibm.com>
Diffstat (limited to 'src/occ_405/pss')
-rw-r--r-- | src/occ_405/pss/avsbus.c | 290 | ||||
-rwxr-xr-x | src/occ_405/pss/avsbus.h | 11 |
2 files changed, 203 insertions, 98 deletions
diff --git a/src/occ_405/pss/avsbus.c b/src/occ_405/pss/avsbus.c index b958271..6b76379 100644 --- a/src/occ_405/pss/avsbus.c +++ b/src/occ_405/pss/avsbus.c @@ -43,20 +43,16 @@ #define AVS_DBG(frmt,args...) #endif - // AVS Bus usage will be determined after receiving config data from TMGT bool G_avsbus_vdd_monitoring = FALSE; bool G_avsbus_vdn_monitoring = FALSE; -// The following constants are used after a command is put on the bus. -// The code will wait for the o2s_ongoing bit to change (which indicates cmd completion). -// Max wait time will be: O2S_ONGOING_CHECK_ATTEMPTS * O2S_ONGOING_CHECK_DELAY_NS (in nanoseconds) -const uint32_t O2S_ONGOING_CHECK_ATTEMPTS = 10; -const uint32_t O2S_ONGOING_CHECK_DELAY_NS = 100; +extern uint32_t G_nest_frequency_mhz; +#define AVSBUS_FREQUENCY_MHZ 10 // Number of read failures allowed before elog is created and reset requested. // This should be no longer than 4ms (or it will impact WOF calculations) -// (readings are taken every 500ms => 500us * 8 = 4ms) +// (readings are taken every 500us => 500us * 8 = 4ms) const uint8_t MAX_READ_ATTEMPTS = 8; // NOTE: OCC must use Bridge B, because Bridge A is reserved for PGPE @@ -142,13 +138,14 @@ void avsbus_init() // 2 o2s_cpol = 0 (positive active clock) // 3 o2s_cpha = 0 (first edge data launch/sample) // 4:13 o2s_clock_divider = set based on the nest frequency for the desired frequency of 10MHz (assumed speed) per O2SCTRL1_[a][n] description. - // = (nest_freq / (SPI_freq*8))-1 = (500M/(10M*8))-1 = 5.25 // 14:16 reserved // 17 o2s_nr_of_frames = 1 (2 frames to account for the first and second frames of an AVSBus command) // 18:63 reserved // 1r00DDDD DDDDDDrr r1rrrrrr rrrrrrrrr - value = 0x8014400000000000; - // TODO: RTC163992 - Determine correct o2s_clock_divider based on nest freq + value = 0x8000400000000000; + // calculate o2s_clock_divider based on nest freq and target bus freq + const uint64_t divider = (G_nest_frequency_mhz / (AVSBUS_FREQUENCY_MHZ * 8)) - 1; + value |= (divider << 50); if (bus0_monitoring) { out64(OCB_O2SCTRL10B, value); @@ -160,27 +157,29 @@ void avsbus_init() } -// Calculate and update command with correct CRC +// Calculate CRC for specified AVS Bus command // Function which generates a 3 bit CRC value for 29 bit data // from: ekb/chips/p9/procedures/hwp/lib/p9_avsbus_lib.C +// (CRC is bits 29:31 in the AVS bus command) +#define AVS_CRC_MASK 0x0000000700000000 #define AVS_CRC_DATA_MASK 0xFFFFFFF800000000 -void avs_crc_update(uint64_t *io_avs_cmd) +uint64_t avs_crc_calculate(const uint64_t i_avs_cmd) { //Polynomial= x^3 + x^1 + x^0 = 1*x^3 + 0*x^2 + 1*x^1 + 1*x^0 = divisor(1011) - uint64_t l_crc_value = 0; + uint64_t o_crc_value = 0; uint64_t l_polynomial = 0xB000000000000000; uint64_t l_msb = 0x8000000000000000; - l_crc_value = *io_avs_cmd & AVS_CRC_DATA_MASK; + o_crc_value = i_avs_cmd & AVS_CRC_DATA_MASK; - while (l_crc_value & AVS_CRC_DATA_MASK) + while (o_crc_value & AVS_CRC_DATA_MASK) { - if (l_crc_value & l_msb) + if (o_crc_value & l_msb) { //if l_msb is 1'b1, divide by l_polynomial and shift l_polynomial // to the right - l_crc_value = l_crc_value ^ l_polynomial; + o_crc_value = o_crc_value ^ l_polynomial; l_polynomial = l_polynomial >> 1; } else @@ -192,26 +191,22 @@ void avs_crc_update(uint64_t *io_avs_cmd) l_msb = l_msb >> 1; } - // Add CRC to avs command (lower 3 bits of cmd) - *io_avs_cmd |= l_crc_value; + return o_crc_value; } #define ERRORCOUNT_MAXTYPES 2 #define ERRORCOUNT_MAXCMDS 2 -// Read and return the voltage or current for specified rail -// (voltage units are mV, current units are in 10mA) -uint16_t avsbus_read(const avsbus_type_e i_type, - const avsbus_cmdtype_e i_cmdtype) +// Initiate read for specified type (Vdd/Vdn) and cmd (Voltage/Current) +void avsbus_read_start(const avsbus_type_e i_type, + const avsbus_cmdtype_e i_cmdtype) { if (isSafeStateRequested()) { // No need to attempt read if OCC will be reset - return 0; + return; } - uint16_t o_reading = 0; - bool l_failure = FALSE; avsbusData_t l_data; // Create error array for each type (Vdd/Vdn) and command (Voltage/Current) @@ -222,8 +217,6 @@ uint16_t avsbus_read(const avsbus_type_e i_type, l_cmd_index = 1; l_trace_cmd = 'C'; } - static uint32_t L_error_count[ERRORCOUNT_MAXTYPES][ERRORCOUNT_MAXCMDS] = {{0}}; - uint32_t * l_error_count = &L_error_count[i_type][l_cmd_index]; char l_trace_type = 'd'; if (AVSBUS_VDD == i_type) @@ -237,11 +230,12 @@ uint16_t avsbus_read(const avsbus_type_e i_type, } #ifdef AVSDEBUG - static bool L_traced[ERRORCOUNT_MAXTYPES][ERRORCOUNT_MAXCMDS] = {{0}}; - bool * l_traced = &L_traced[i_type][l_cmd_index]; - if (!*l_traced) + static uint32_t L_trace_count[ERRORCOUNT_MAXTYPES][ERRORCOUNT_MAXCMDS] = {{0}}; + uint32_t * l_trace_count = &L_trace_count[i_type][l_cmd_index]; + uint32_t DEBUG_TRACE_MAX = 2; + if (*l_trace_count < DEBUG_TRACE_MAX) { - TRAC_INFO("avsbus_read: Vd%c %c - bus[%d] rail[%d]", + TRAC_INFO("avsbus_read_start: Vd%c %c - bus[%d] rail[%d]", l_trace_type, l_trace_cmd, l_data.bus, l_data.rail); } #endif @@ -249,14 +243,10 @@ uint16_t avsbus_read(const avsbus_type_e i_type, // Determine register based on the bus number uint32_t o2scmd_reg = OCB_O2SCMD0B; uint32_t o2swd_reg = OCB_O2SWD0B; - uint32_t o2sst_reg = OCB_O2SST0B; - uint32_t o2srd_reg = OCB_O2SRD0B; if (1 == l_data.bus) { o2scmd_reg = OCB_O2SCMD1B; o2swd_reg = OCB_O2SWD1B; - o2sst_reg = OCB_O2SST1B; - o2srd_reg = OCB_O2SRD1B; } // Write O2SCMD[a][n] @@ -277,16 +267,87 @@ uint16_t avsbus_read(const avsbus_type_e i_type, // 29:31 CRC // 01110DDD DRRRR111 11111111 11111CCC value = 0x7007FFF800000000 | ((uint64_t) i_cmdtype << 55) | ((uint64_t)l_data.rail << 51); - avs_crc_update(&value); + // Calculate/add CRC + value |= avs_crc_calculate(value); out64(o2swd_reg, value); + // Read has been started so now just wait for HW to complete + // HW: Wait for bus op to complete // HW: arbitration between two bridges // HW: o2s_ongoning: 0 -> 1 // HW: execution completes // HW: o2s_ongoing 1 -> 0 - // Poll waiting for o2s_ongoing to change to 0 or an error bit is set +#ifdef AVSDEBUG + ++*l_trace_count; // DEBUG +#endif + +} // end avsbus_read_start() + + +// Read and return the voltage or current for specified rail +// (voltage units are mV, current units are in 10mA) +uint16_t avsbus_read(const avsbus_type_e i_type, + const avsbus_cmdtype_e i_cmdtype) +{ + if (isSafeStateRequested()) + { + // No need to attempt read if OCC will be reset + return 0; + } + + uint16_t o_reading = 0; + bool l_failure = FALSE; + + uint8_t l_cmd_index = 0; + char l_trace_cmd = 'V'; + if (i_cmdtype == AVSBUS_CURRENT) + { + l_cmd_index = 1; + l_trace_cmd = 'C'; + } + + // Static error counters for each type (Vdd/Vdn) and command (Voltage/Current) + static uint32_t L_error_count[ERRORCOUNT_MAXTYPES][ERRORCOUNT_MAXCMDS] = {{0}}; + uint32_t * l_error_count = &L_error_count[i_type][l_cmd_index]; + + char l_trace_type = 'd'; + avsbusData_t l_data = G_sysConfigData.avsbus_vdd; + if (AVSBUS_VDN == i_type) + { + l_trace_type = 'n'; + l_data = G_sysConfigData.avsbus_vdn; + } + +#ifdef AVSDEBUG + static uint32_t L_trace_count[ERRORCOUNT_MAXTYPES][ERRORCOUNT_MAXCMDS] = {{0}}; + uint32_t * l_trace_count = &L_trace_count[i_type][l_cmd_index]; + uint32_t DEBUG_TRACE_MAX = 2; + if (*l_trace_count < DEBUG_TRACE_MAX) + { + TRAC_INFO("avsbus_read: Vd%c %c - bus[%d] rail[%d]", + l_trace_type, l_trace_cmd, l_data.bus, l_data.rail); + } +#endif + + // Determine register based on the bus number + uint32_t o2sst_reg = OCB_O2SST0B; + uint32_t o2srd_reg = OCB_O2SRD0B; + if (1 == l_data.bus) + { + o2sst_reg = OCB_O2SST1B; + o2srd_reg = OCB_O2SRD1B; + } + + // HW: Wait for bus op to complete + // HW: arbitration between two bridges + // HW: o2s_ongoning: 0 -> 1 + // HW: execution completes + // HW: o2s_ongoing 1 -> 0 + + // Since read was started in previous tick, it should have already completed + // (no need to poll/wait on o2s_ongoing) enum occReasonCode rc = OCC_SUCCESS_REASON_CODE; uint64_t l_status = in64(o2sst_reg); // OCC O2S Status Register @@ -297,46 +358,16 @@ uint16_t avsbus_read(const avsbus_type_e i_type, // 7 FSM error // 8:63 reserved // GrrrrBrF rrrrrrrr rrrrrrrr rrrrrrrr - uint32_t l_max_attempts = O2S_ONGOING_CHECK_ATTEMPTS; - - while ((1 == (l_status >> 63)) && - (0 == (l_status & 0x0500000000000000))) - { - if (l_max_attempts-- == 0) - { - l_failure = TRUE; - (*l_error_count)++; - if ((*l_error_count == 1) || (*l_error_count == MAX_READ_ATTEMPTS)) - { - TRAC_ERR("avsbus_read: Vd%c %c timeout waiting for o2s_ongoing change O2SST[0x%08X] = [0x%08X] / Command[0x%08X]", - l_trace_type, l_trace_cmd, o2sst_reg, WORD_HIGH(l_status), WORD_HIGH(value)); - /* - * @errortype - * @moduleid PSS_MID_AVSBUS_READ - * @reasoncode AVSBUS_TIMEOUT - * @userdata1 AVS Bus type/bus/rail - * @userdata2 status - * @devdesc task_apss_complete_pwr_meas schedule failed - * @devdesc Timeout when reading AVS Bus - */ - rc = AVSBUS_TIMEOUT; - } - break; - } - // TODO: RTC 163992 - //ssx_sleep(SSX_NANOSECONDS(O2S_ONGOING_CHECK_DELAY_NS)); - l_status = in64(o2sst_reg); - } if (0 != (l_status & 0x0500000000000000)) { + // error bit was set l_failure = TRUE; (*l_error_count)++; if ((*l_error_count == 1) || (*l_error_count == MAX_READ_ATTEMPTS)) { - // error bit was set - TRAC_ERR("avsbus_read: Error found in Vd%c %c O2SST[0x%08X] = [0x%08X] / Command[0x%08X]", - l_trace_type, l_trace_cmd, o2sst_reg, WORD_HIGH(l_status), WORD_HIGH(value)); + TRAC_ERR("avsbus_read: Error found in Vd%c %c O2SST[0x%08X] = [0x%08X]", + l_trace_type, l_trace_cmd, o2sst_reg, WORD_HIGH(l_status)); /* * @errortype * @moduleid PSS_MID_AVSBUS_READ @@ -348,13 +379,31 @@ uint16_t avsbus_read(const avsbus_type_e i_type, rc = AVSBUS_ERROR; } } + else if (1 == (l_status >> 63)) // o2s_ongoing + { + // o2s_ongoing bit was still set (operation did not complete) + l_failure = TRUE; + (*l_error_count)++; + if ((*l_error_count == 1) || (*l_error_count == MAX_READ_ATTEMPTS)) + { + TRAC_ERR("avsbus_read: Vd%c %c timeout waiting for o2s_ongoing change O2SST[0x%08X] = [0x%08X]", + l_trace_type, l_trace_cmd, o2sst_reg, WORD_HIGH(l_status)); + /* + * @errortype + * @moduleid PSS_MID_AVSBUS_READ + * @reasoncode AVSBUS_TIMEOUT + * @userdata1 AVS Bus type/bus/rail + * @userdata2 status + * @devdesc Timeout when reading AVS Bus + */ + rc = AVSBUS_TIMEOUT; + } + } if (FALSE == l_failure) { // Read the response data - value = in64(o2srd_reg); - - // Check for valid command operation and extract read data + uint64_t value = in64(o2srd_reg); // AVS Bus response (read voltage or current): // 0:1 SlaveAck (0b00 from slave indicates good CRC and action was taken) // 2 0 @@ -363,11 +412,34 @@ uint16_t avsbus_read(const avsbus_type_e i_type, // 24:28 Reserved (must be all 1s) // 29:31 CRC // AA0SSSSS VVVVVVVV VVVVVVVV 11111CCC - if (0 == (value & 0xC000000000000000)) + + // Validate CRC + const uint64_t crc = avs_crc_calculate(value); + if (crc != (value & AVS_CRC_MASK)) + { + l_failure = TRUE; + (*l_error_count)++; + if ((*l_error_count == 1) || (*l_error_count == MAX_READ_ATTEMPTS)) + { + TRAC_ERR("avsbus_read: CRC mismatch in Vd%c %c rsp O2SRD[0x%08X] = [0x%08X] (calculated CRC 0x%08X)", + l_trace_type, l_trace_cmd, o2srd_reg, WORD_HIGH(value), WORD_HIGH(crc)); + /* + * @errortype + * @moduleid PSS_MID_AVSBUS_READ + * @reasoncode AVSBUS_CRC_ERROR + * @userdata1 AVS Bus type/bus/rail + * @userdata2 status + * @devdesc CRC error reading AVS Bus + */ + rc = AVSBUS_CRC_ERROR; + } + } + // Check for valid command operation and extract read data + else if (0 == (value & 0xC000000000000000)) { o_reading = (value >> 40) & 0x0000FFFF; #ifdef AVSDEBUG - if (!*l_traced) + if (*l_trace_count < DEBUG_TRACE_MAX) { if (i_cmdtype == AVSBUS_VOLTAGE) { @@ -403,31 +475,39 @@ uint16_t avsbus_read(const avsbus_type_e i_type, if (l_failure) { - if (*l_error_count == MAX_READ_ATTEMPTS) + enum occExtReasonCode exrc = ERC_AVSBUS_VDD_VOLTAGE_FAILURE; + if (AVSBUS_VDD == i_type) { - TRAC_ERR("avsbus_read: Reached %d consecutive Vd%c %c errors, requesting reset", - *l_error_count, l_trace_type, l_trace_cmd); - G_avsbus_vdd_monitoring = FALSE; - G_avsbus_vdn_monitoring = FALSE; - enum occExtReasonCode exrc = ERC_AVSBUS_VDD_VOLTAGE_FAILURE; - if (AVSBUS_VDD == i_type) + if (i_cmdtype == AVSBUS_CURRENT) { - if (i_cmdtype == AVSBUS_CURRENT) - { - exrc = ERC_AVSBUS_VDD_CURRENT_FAILURE; - } + exrc = ERC_AVSBUS_VDD_CURRENT_FAILURE; + INCREMENT_ERR_HISTORY(ERR_AVSBUS_VDD_CURRENT); } else { - if (i_cmdtype == AVSBUS_CURRENT) - { - exrc = ERC_AVSBUS_VDN_CURRENT_FAILURE; - } - else - { - exrc = ERC_AVSBUS_VDN_VOLTAGE_FAILURE; - } + INCREMENT_ERR_HISTORY(ERR_AVSBUS_VDD_VOLTAGE); + } + } + else + { + if (i_cmdtype == AVSBUS_CURRENT) + { + exrc = ERC_AVSBUS_VDN_CURRENT_FAILURE; + INCREMENT_ERR_HISTORY(ERR_AVSBUS_VDN_CURRENT); } + else + { + exrc = ERC_AVSBUS_VDN_VOLTAGE_FAILURE; + INCREMENT_ERR_HISTORY(ERR_AVSBUS_VDN_VOLTAGE); + } + } + + if (*l_error_count == MAX_READ_ATTEMPTS) + { + TRAC_ERR("avsbus_read: Reached %d consecutive Vd%c %c errors, requesting reset", + *l_error_count, l_trace_type, l_trace_cmd); + G_avsbus_vdd_monitoring = FALSE; + G_avsbus_vdn_monitoring = FALSE; errlHndl_t l_err = createErrl(PSS_MID_AVSBUS_READ, rc, exrc, @@ -444,8 +524,9 @@ uint16_t avsbus_read(const avsbus_type_e i_type, REQUEST_RESET(l_err); } } + #ifdef AVSDEBUG - *l_traced = TRUE; // DEBUG + ++*l_trace_count; // DEBUG #endif return o_reading; @@ -453,5 +534,22 @@ uint16_t avsbus_read(const avsbus_type_e i_type, } // end avsbus_read() +// Start the AVS Bus read for both buses (if enabled) +void initiate_avsbus_reads(avsbus_cmdtype_e i_cmdType) +{ + if (G_avsbus_vdd_monitoring) + { + // AVS Bus Vdd config data was received: + // Initiate AVS Bus read for Vdd (voltage or current) + avsbus_read_start(AVSBUS_VDD, i_cmdType); + } + + if (G_avsbus_vdn_monitoring) + { + // AVS Bus Vdn config data was received: + // Initiate AVS Bus read for Vdn (voltage or current) + avsbus_read_start(AVSBUS_VDN, i_cmdType); + } +} // end initiate_avsbus_reads() diff --git a/src/occ_405/pss/avsbus.h b/src/occ_405/pss/avsbus.h index f2dfb2e..80b91cf 100755 --- a/src/occ_405/pss/avsbus.h +++ b/src/occ_405/pss/avsbus.h @@ -48,9 +48,16 @@ typedef enum // Setup the AVS Bus for reading void avsbus_init(); -// Read and return the voltage or current for specified rail -// (voltage units are mV, current units are in 10mA) +// Initiate AVS Bus read for specified cmdtype (Voltage / Current) +// (results can then be read on the next tick) +void initiate_avsbus_reads(avsbus_cmdtype_e i_cmdType); + +// Process AVS Bus read results (or errors) for specified bus/cmdtype. +// Returns the data requested (voltage units are mV, current units are in 10mA) +// Predictive error will be logged after MAX_READ_ATTEMPTS failures on the specific +// bus/cmdtype and an OCC reset will be requested uint16_t avsbus_read(const avsbus_type_e i_type, const avsbus_cmdtype_e i_cmdtype); + #endif //_AVSBUS_H |