diff options
Diffstat (limited to 'src/lib/heartbeat.c')
-rwxr-xr-x | src/lib/heartbeat.c | 328 |
1 files changed, 0 insertions, 328 deletions
diff --git a/src/lib/heartbeat.c b/src/lib/heartbeat.c deleted file mode 100755 index 51be390..0000000 --- a/src/lib/heartbeat.c +++ /dev/null @@ -1,328 +0,0 @@ -// $Id: heartbeat.c,v 1.5 2014/07/16 18:07:35 daviddu Exp $ -// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/heartbeat.c,v $ -//----------------------------------------------------------------------------- -// *! (C) Copyright International Business Machines Corp. 2013 -// *! All Rights Reserved -- Property of IBM -// *! *** IBM Confidential *** -//----------------------------------------------------------------------------- - -/// \file heartbeat.c -/// \brief PgP PMC/PCBS heartbeat configuration procedures - -#include "ssx.h" -#include "heartbeat.h" - -/// Configure/Enable/Disable the pmc heartbeat register. -/// -/// \param enable 1 = enable, 0 = disable, all other values will cause error. -/// -/// \param req_time_us heartbeat interval time request (in microseconds). -/// If the pmc does not detect a heartbeat within this time the pmc will -/// set the corresponding fir bit and enter safe mode. This interval -/// is the requested value. The return value will be the actual setting. -/// The procedure well attempt to get as close to the requested time as possible -/// without choosing a setting lower then requested. -/// Legal values: 1-4194240 (us). Ignored if force = 1 or enable = 0 -/// -/// \param force 1 = force safe mode (debug), 0 = do not force, all other values -/// will cause an error. enable = 0 and force = 1 will return an error -/// -/// \param[out] o_time_us Actual configured time rounded down to the nearest us. -/// This will be as close as the procedure could get to the requested time given -/// the frequency and pulse time settings. Returns 0 if hearbeat was disabled or -/// if safe mode was forced. -/// -/// \retval 0 Success -/// -/// \retval -HB_INVALID_ARGUMENT_PMC One of the arguments was invalid in -/// some way - -int -pmc_hb_config(unsigned int enable, - unsigned int req_time_us, - unsigned int force, - unsigned int *o_time_us - ) - -{ - pmc_parameter_reg0_t ppr0; - pmc_occ_heartbeat_reg_t pohr; - tpc_hpr2_t l_hpr2; - uint64_t divider, pulses, total_pulses, hp_freq; - int rc = 0; - - // @dyd SW238882 fix - // remove req_time_us overflow check since the upper boundary of - // the req_time_us doesnt depand on certain static value but based on - // the value set in hang_pulse_2_reg at runtime. - if (SSX_ERROR_CHECK_API) { - SSX_ERROR_IF((enable > 1) || - (force > 1) || - ((req_time_us < 1) && enable && (! force)) || - ((force == 1 && enable == 0)), - HB_INVALID_ARGUMENT_PMC); - } - - do { - - // in case firmware does not call ocb_timer_setup - // before calling this procedure to setup g_ocb_timer_divider - rc = getscom(TPC_HPR2, &l_hpr2.value); - if(rc) break; - g_ocb_timer_divider = 1 << l_hpr2.fields.hang_pulse_reg; - - // calculation based on pmc_occ_heartbeat_reg defination - hp_freq = (__ssx_timebase_frequency_mhz/g_ocb_timer_divider); - if(hp_freq < 1) - hp_freq = 1; - total_pulses = (req_time_us * hp_freq); - - // this may be an overkill for safety but no one should notice - if ((req_time_us*__ssx_timebase_frequency_mhz) % g_ocb_timer_divider) { - total_pulses++; - } - - divider = 0; - // determine values for predivider and number of pulses. - if (force || (! enable)) { // predivider a don't care in this case - pulses = 0; - *o_time_us = 0; - } else { - // can count up to 2^16 pulses with no pre-divide, first determine - // minimum pre-divider needed - do { - divider++; - } while ((((divider << 16) - 1) / total_pulses) < 1); - - // @dyd SW238882 fix - // underflow case - // since pmc heartbeat counter counts with nest_nclk/4 - // instead of hang pulse when hangpulse_predivider==0, - // this procedure doesnt allow predivider to be set to - // zero as it is a special case which doesnt work with - // occ heartbeat time value calculated by this procedure. - // Given hangpulse_predivider = divider - 1, - // set divider to 2 if it is 1, zero not possible. - if (divider < 2) { - divider = 2; - //rc = HB_UNDERFLOW_DIVIDER_PMC; - //break; - } - // overflow case - // since hangpulse_predivider field is only 6 bit long, - // check the overflow first, set to maximum if larger. - if (divider > 64) { - divider = 64; - //rc = HB_OVERFLOW_DIVIDER_PMC; - //break; - } - - // divider is determined, now setup number of pulses - pulses = total_pulses / divider; - if (total_pulses % divider) { - pulses++; - } - - // @dyd SW238882 fix - // there is no underflow case for pulses, because pulses=0 as - // intended immediate timeout is allowed, plus no mathematical - // substraction from pulses is done; however there is an overflow - // case: the value of pulses doesnt fit into 16 bits HW field. - // Here we set pulses to the maximum value that HW allows, - // and use the o_time_us to feedback the caller this is done. - if (pulses > 0xFFFF) { - pulses = 0xFFFF; - //rc = HB_OVERFLOW_PULSES_PMC; - // break; - } - - // calculating real timeout duration - // that this procedure is going to set - *o_time_us = (divider*pulses)/hp_freq; - - // @dyd SW238882 fix - // in force == 0 && enable == 1 case - // disable heartbeat first before reset hang pulse predivider - // and new heartbeat time value to prevent immediate timeout. - // if force == 1 then it is intended to be immediate timeout anyway - // if enable == 0 then it is going to set this bit to zero anyway - pohr.value = 0; - pohr.fields.pmc_occ_heartbeat_en = 0; - if (cfam_id() == CFAM_CHIP_ID_MURANO_10) { - out32(PMC_OCC_HEARTBEAT_REG, pohr.value); - } - out32(PMC_OCC_HEARTBEAT_REG, pohr.value); - } - - // Note through experiments, the divider=predivider+1 isnt always - // in effect in hardware due to missing last pulse in tight timing, - // some setup will end up with just divider=predivider; therefore, - // in order to not result unexpected heartbeat timeout, always - // set divider to predivider to be safe. - if (enable && (! force)) { - ppr0.value = in32(PMC_PARAMETER_REG0); - ppr0.fields.hangpulse_predivider = divider; - out32(PMC_PARAMETER_REG0, ppr0.value); - } - - pohr.value = 0; - pohr.fields.pmc_occ_heartbeat_en = enable; - pohr.fields.pmc_occ_heartbeat_time = pulses; - // Due to Issue HW219480, the heartbeat register needs to be written - // Twice in order for the heartbeat count value to take correctly. - // Technically it would not be harmful to just double-write in - // every case, but this is currently written to only double-write - // if a Murano dd1.0 part is detected - if (cfam_id() == CFAM_CHIP_ID_MURANO_10) { - out32(PMC_OCC_HEARTBEAT_REG, pohr.value); - } - out32(PMC_OCC_HEARTBEAT_REG, pohr.value); - - }while(0); - return rc; - -} - - - -/// Configure/Enable/Disable the pcbs heartbeat registers. -/// -/// \param enable 1 = enable, 0 = disable, all other values will cause error. -/// -/// \param cores Use this mask to select which cores to update. This routine -/// will cross reference the current pmc deconfig vector and only update -/// those cores that are both selected here and configured. -/// -/// \param hb_reg 32-bit unsigned address of register to setup as the -/// PCBS heartbeat register. This must be a PCBS address. -/// Ignored unless enable = 1 -/// -/// \param req_time_us heartbeat interval time request (in microseconds). -/// If the pcbs does not detect a heartbeat within this time the pcbs will -/// set the corresponding fir bit and enter safe mode. This interval -/// is the requested value. The return value will be the actual setting and -/// the procedure will attempt go get as close to possible to this without -/// choosing a setting lower then requested. -/// Legal values: 1 - 16320 (ignored unless enable = 1) -/// -/// \param force 1 = force safe mode (debug), 0 = do not force, all other values -/// will cause an error. In PCBS, the force safe mode is not related to -/// the heartbeat so forcing safe mode while also enabling the heartbeat -/// is allowed. -/// -/// \param[out] o_time_us Actual configured time in us. This represents the -/// actual setting rounded down to the nearest us. 0 if heartbeat was disabled. -/// -/// \retval 0 Success - -/// \retval -HB_INVALID_ARGUMENT_PCBS One of the arguments was invalid in -/// some way -/// -/// \retval others This API may also return non-0 codes from -/// getscom()/putscom() - - -int -pcbs_hb_config(unsigned int enable, - ChipConfigCores cores, - uint32_t hb_reg, - unsigned int req_time_us, - unsigned int force, - unsigned int *o_time_us) -{ - pcbs_occ_heartbeat_reg_t pohr; - pcbs_pmgp1_reg_t pp1r; - pmc_core_deconfiguration_reg_t pcdr; - uint32_t reg_offset; - uint32_t pp1r_addr; - uint64_t pp1r_data; - ChipConfigCores core_list; - ChipConfigCores deconfig; - int core; - int rc = 0; - unsigned int pulses; - - reg_offset = hb_reg - PCBS_PIB_BASE; - - if (SSX_ERROR_CHECK_API) { - SSX_ERROR_IF((enable > 1) || - ((reg_offset > 0xFF) && enable) || - ((req_time_us < 64) && enable) || - ((req_time_us > 16320) && enable) || - (force > 1), - HB_INVALID_ARGUMENT_PCBS); - } - - - do { - - // calculation based on pcbs_occ_heartbeat_reg defination - pulses = req_time_us/64; - if (req_time_us % 64) { - pulses++; - } - - // @dyd SW238882 fix - // overflow handling: HW only allows 8 bits in the field. - // set pulses to maximum allowed value in HW if it overflows, - // and o_time_us will feedback to caller this is done. - if (pulses > 0xFF) { - pulses = 0xFF; - //rc = HB_PULSES_OVERFLOW_PCBS; - //break; - } - // underflow case, pulses cannot be zero due to undefined HW behavior - if (pulses < 1) { - pulses = 1; - //rc = HB_PULSES_UNDERFLOW_PCBS; - //break; - } - - pp1r.value = 0; - pp1r.fields.force_safe_mode = 1; - if (force) { - pp1r_addr = PCBS_PMGP1_REG_OR; - pp1r_data = pp1r.value; - } else { - pp1r_addr = PCBS_PMGP1_REG_AND; - pp1r_data = ~(pp1r.value); - } - - pcdr.value = in32(PMC_CORE_DECONFIGURATION_REG); - deconfig = pcdr.fields.core_chiplet_deconf_vector; - - pohr.value = 0; - pohr.fields.occ_heartbeat_enable = enable; - pohr.fields.occ_heartbeat_time = pulses; - pohr.fields.occ_heartbeat_reg_addr_offset = reg_offset; - - if (enable) { - *o_time_us = pulses * 64; - } else { - *o_time_us = 0; - } - - do { - core_list = cores & (~deconfig); - for (core = 0; core < PGP_NCORES; core++, core_list <<= 1) { - if (core_list & 0x8000) { - // read modify write to preserve psafe - rc = getscom(CORE_CHIPLET_ADDRESS(PCBS_OCC_HEARTBEAT_REG, - core), &pohr.value); - if (rc) break; - pohr.fields.occ_heartbeat_enable = enable; - pohr.fields.occ_heartbeat_time = pulses; - pohr.fields.occ_heartbeat_reg_addr_offset = reg_offset; - rc = putscom(CORE_CHIPLET_ADDRESS(PCBS_OCC_HEARTBEAT_REG, - core), pohr.value); - if (rc) break; - rc = putscom(CORE_CHIPLET_ADDRESS(pp1r_addr, core), - pp1r_data); - if (rc) break; - } - } - } while (0); - - }while(0); - return rc; -} |