Skip to content

Commit

Permalink
HTMGT: Memory Throttling and Power Capping support
Browse files Browse the repository at this point in the history
- Enable DIMM thermal monitoring
- Implement VRM thermal monitoring support
- Implement memory throttle calculations
- Move HTMGT only attributes to _openpower xml files
System owner will need to update the following for full support:
OPEN_POWER_MIN_MEM_UTILIZATION_POWER_CAP
OPEN_POWER_VRM_READ_TIMEOUT_SEC

Change-Id: Ib7f31e58c62af4b66edc3989156ebc6e636cc741
RTC: 153942
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/41982
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Reviewed-by: Martha Broyles <mbroyles@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
  • Loading branch information
cjcain authored and dcrowell77 committed Jun 22, 2017
1 parent ccb7468 commit 7d4cab0
Show file tree
Hide file tree
Showing 13 changed files with 917 additions and 559 deletions.
1 change: 1 addition & 0 deletions src/include/usr/isteps/istep21list.H
Expand Up @@ -125,6 +125,7 @@ const DepModInfo g_istep21Dependancies = {
DEP_LIB(libpm.so),
#ifdef CONFIG_HTMGT
DEP_LIB(libhtmgt.so),
DEP_LIB(libisteps_mss.so),
#endif
NULL
}
Expand Down
6 changes: 5 additions & 1 deletion src/usr/htmgt/htmgt.C
Expand Up @@ -77,7 +77,11 @@ namespace HTMGT
{
#ifndef __HOSTBOOT_RUNTIME
// Calc memory throttles (once per IPL)
calcMemThrottles();
l_err = calcMemThrottles();
if( l_err )
{
break;
}
#endif

// Make sure OCCs are ready for communication
Expand Down
180 changes: 130 additions & 50 deletions src/usr/htmgt/htmgt_cfgdata.C
Expand Up @@ -31,6 +31,7 @@
#include "ipmi/ipmisensor.H"
#include <htmgt/htmgt_reasoncodes.H>
#include <fapi2_attribute_service.H>
#include "htmgt_memthrottles.H"

using namespace TARGETING;

Expand Down Expand Up @@ -159,10 +160,10 @@ namespace HTMGT
break;

case OCC_CFGDATA_MEM_THROTTLE:
if (int_flags_set(FLAG_SEND_MEM_CONFIG))
if (!int_flags_set(FLAG_DISABLE_MEM_CONFIG))
{
getMemThrottleMessageData(occ->getTarget(),
cmdData, cmdDataLen);
occInstance, cmdData, cmdDataLen);
}
break;

Expand Down Expand Up @@ -238,10 +239,8 @@ enum occCfgDataVersion
{
OCC_CFGDATA_FREQ_POINT_VERSION = 0x20,
OCC_CFGDATA_APSS_VERSION = 0x20,
OCC_CFGDATA_MEM_CONFIG_VERSION = 0x21,
OCC_CFGDATA_PCAP_CONFIG_VERSION = 0x20,
OCC_CFGDATA_SYS_CONFIG_VERSION = 0x20,
OCC_CFGDATA_MEM_THROTTLE_VERSION = 0x20,
OCC_CFGDATA_TCT_CONFIG_VERSION = 0x20,
OCC_CFGDATA_AVSBUS_CONFIG_VERSION = 0X01,
};
Expand Down Expand Up @@ -289,7 +288,6 @@ void writeMemConfigData( uint8_t *& o_data,
//Byte 11 Nimbus DIMM Temp i2c address
// Cumulus Reserved for Cumulus
o_data[io_index++] = i_i2cDevAddr;

}


Expand All @@ -301,7 +299,7 @@ void getMemConfigMessageData(const TargetHandle_t i_occ,
assert(o_data != nullptr);

o_data[index++] = OCC_CFGDATA_MEM_CONFIG;
o_data[index++] = OCC_CFGDATA_MEM_CONFIG_VERSION;
o_data[index++] = 0x21; // version

//System reference needed for these ATTR.
Target* sys = nullptr;
Expand All @@ -328,7 +326,7 @@ void getMemConfigMessageData(const TargetHandle_t i_occ,
//Byte 5: Number of data sets.
size_t numSetsOffset = index++; //Will fill in numSets at the end

if (int_flags_set(FLAG_SEND_MEM_CONFIG))
if (!int_flags_set(FLAG_DISABLE_MEM_CONFIG))
{
TargetHandleList centaurs;
TargetHandleList mbas;
Expand Down Expand Up @@ -458,6 +456,7 @@ void getMemConfigMessageData(const TargetHandle_t i_occ,


void getMemThrottleMessageData(const TargetHandle_t i_occ,
const uint8_t i_occ_instance,
uint8_t* o_data, uint64_t & o_size)
{
uint8_t numSets = 0;
Expand All @@ -467,17 +466,17 @@ void getMemThrottleMessageData(const TargetHandle_t i_occ,
assert(proc != nullptr);
assert(o_data != nullptr);

TargetHandleList centaurs;
//Get all functional MCSs
TargetHandleList mcs_list;
getAllChiplets(mcs_list, TYPE_MCS, true);
TMGT_INF("calcMemThrottles: found %d MCSs", mcs_list.size());

o_data[index++] = OCC_CFGDATA_MEM_THROTTLE;
o_data[index++] = OCC_CFGDATA_MEM_THROTTLE_VERSION;
o_data[index++] = 0x20; // version;

//Byte 3: Number of memory throttling data sets.
size_t numSetsOffset = index++; //Will fill in numSets at the end


getChildAffinityTargets(centaurs, proc, CLASS_CHIP, TYPE_MEMBUF);

//Next, the following format repeats per set/MBA:
//Byte 0: Cumulus: Centaur position 0-7
// Nimbus : Memory Controller
Expand All @@ -489,49 +488,112 @@ void getMemThrottleMessageData(const TargetHandle_t i_occ,
//Bytes 8-9: Turbo N_PER_CHIP
//Bytes 10-11: Max mem power with throttle @Turbo
//Bytes 12-13: Power Capping N_PER_MBA
//Bytes 14-15: Power Capping N_PER_MBA
//Bytes 14-15: Power Capping N_PER_CHIP
//Bytes 16-17: Max mem power with throttle @PowerCapping
//Bytes 18-19: Nominal Power N_PER_MBA
//Bytes 20-21: Nominal Power N_PER_CHIP
//Bytes 22-23: Max mem power with throttle @Nominal
//Bytes 24-29: Reserved

// Hard coding until we can get mem throttle cfg data
for (uint8_t entry = 0; entry < 2; ++entry)
for(const auto & mcs_target : mcs_list)
{
o_data[index++] = 0x00; //MC01
o_data[index++] = entry; // Port
o_data[index++] = 0x44; // Min N Per MBA
o_data[index++] = 0x44;
o_data[index++] = 0x01; // Max mem pwr at min throttle
o_data[index++] = 0x00;
o_data[index++] = 0x45; // Turbo N per MBA
o_data[index++] = 0x56;
o_data[index++] = 0x55; // Turbo N per chip
o_data[index++] = 0x5F;
o_data[index++] = 0x01; // Max mem pwr at turbo
o_data[index++] = 0x10;
o_data[index++] = 0x45; // Power capping N per MBA
o_data[index++] = 0x56;
o_data[index++] = 0x55; // Power capping N per chip
o_data[index++] = 0x5F;
o_data[index++] = 0x01; // Max mem pwr at power capping
o_data[index++] = 0x20;
o_data[index++] = 0x45; // Nominal N per MBA
o_data[index++] = 0x56;
o_data[index++] = 0x55; // Nominal N per chip
o_data[index++] = 0x5F;
o_data[index++] = 0x01; // Max mem pwr at Nominal
o_data[index++] = 0x30;
o_data[index++] = 0x00; // reserved
o_data[index++] = 0x00;
o_data[index++] = 0x00;
o_data[index++] = 0x00;
o_data[index++] = 0x00;
o_data[index++] = 0x00;
++numSets ;
}
uint8_t mcs_unit = 0xFF;
if (!mcs_target->tryGetAttr<TARGETING::ATTR_CHIP_UNIT>(mcs_unit))
{
uint32_t mcs_huid = 0xFFFFFFFF;
mcs_target->tryGetAttr<TARGETING::ATTR_HUID>(mcs_huid);
TMGT_ERR("calcMemThrottles: Unable to determine MCS unit for HUID"
" 0x%04X", mcs_huid);
continue;
}
ConstTargetHandle_t proc_target = getParentChip(mcs_target);
assert(proc_target != nullptr);

// Make sure this MCS is for the current OCC/Proc
if (i_occ_instance == proc_target->getAttr<TARGETING::ATTR_POSITION>())
{
// Read the throttle and power values for this MCS
ATTR_OT_MIN_N_PER_MBA_type npm_min;
ATTR_OT_MEM_POWER_type power_min;
mcs_target->tryGetAttr<ATTR_OT_MIN_N_PER_MBA>(npm_min);
mcs_target->tryGetAttr<ATTR_OT_MEM_POWER>(power_min);
ATTR_N_PLUS_ONE_N_PER_MBA_type npm_redun;
ATTR_N_PLUS_ONE_N_PER_CHIP_type npc_redun;
ATTR_N_PLUS_ONE_MEM_POWER_type power_redun;
mcs_target->tryGetAttr<ATTR_N_PLUS_ONE_N_PER_MBA>(npm_redun);
mcs_target->tryGetAttr<ATTR_N_PLUS_ONE_N_PER_CHIP>(npc_redun);
mcs_target->tryGetAttr<ATTR_N_PLUS_ONE_MEM_POWER>(power_redun);
ATTR_POWERCAP_N_PER_MBA_type npm_pcap;
ATTR_POWERCAP_N_PER_CHIP_type npc_pcap;
ATTR_POWERCAP_MEM_POWER_type power_pcap;
mcs_target->tryGetAttr<ATTR_POWERCAP_N_PER_MBA>(npm_pcap);
mcs_target->tryGetAttr<ATTR_POWERCAP_N_PER_CHIP>(npc_pcap);
mcs_target->tryGetAttr<ATTR_POWERCAP_MEM_POWER>(power_pcap);

// Query the functional MCAs for this MCS
TARGETING::TargetHandleList mca_list;
getChildAffinityTargetsByState(mca_list, mcs_target, CLASS_UNIT,
TYPE_MCA, UTIL_FILTER_FUNCTIONAL);
for(const auto & mca_target : mca_list)
{
// unit identifies unique MCA under a processor
uint8_t mca_unit = 0xFF;
mca_target->tryGetAttr<TARGETING::ATTR_CHIP_UNIT>(mca_unit);
const uint8_t mca_rel_pos = mca_unit % 2;
if ((npm_min[mca_rel_pos] == 0) ||
(npm_redun[mca_rel_pos] == 0) ||
(npm_pcap[mca_rel_pos] == 0))
{
TMGT_ERR("calcMemThrottles: MCS%d/MCA%d [%d]"
" - Ignored due to null throttle",
mcs_unit, mca_unit, mca_rel_pos);
TMGT_ERR("N/slot: Min=%d, Turbo=%d, Pcap=%d",
npm_min[mca_rel_pos], npm_redun[mca_rel_pos],
npm_pcap[mca_rel_pos]);
continue;
}
if (mca_rel_pos >= TMGT_MAX_MCA_PER_MCS)
{
TMGT_ERR("calcMemThrottles: OCC%d / MCS%d / MCA%d"
" - Ignored due invalid MCA position: %d",
i_occ_instance, mcs_unit, mca_unit, mca_rel_pos);
continue;
}
TMGT_INF("calcMemThrottles: OCC%d / MCS%d / MCA%d [%d]",
i_occ_instance, mcs_unit, mca_unit, mca_rel_pos);
// OCC expects phyMC=0 for (MCS0-1) and 1 for (MCS2-3)
// MCS MCA MCA OCC OCC
// unit unit relPos phyMC phyPort
// 0 0 0 0 0
// 0 1 1 0 1
// 1 2 0 0 2
// 1 3 1 0 3
// 2 4 0 1 0
// 2 5 1 1 1
// 3 6 0 1 2
// 3 7 1 1 3
o_data[index] = mcs_unit >> 1; // MC (0-1)
o_data[index+1] = mca_unit % 4; // Phy Port (0-3)
// Minimum
UINT16_PUT(&o_data[index+ 2], npm_min[mca_rel_pos]);
UINT16_PUT(&o_data[index+ 4], power_min[mca_rel_pos]);
// Turbo
UINT16_PUT(&o_data[index+ 6], npm_redun[mca_rel_pos]);
UINT16_PUT(&o_data[index+ 8], npc_redun[mca_rel_pos]);
UINT16_PUT(&o_data[index+10], power_redun[mca_rel_pos]);
// Power Capping
UINT16_PUT(&o_data[index+12], npm_pcap[mca_rel_pos]);
UINT16_PUT(&o_data[index+14], npc_pcap[mca_rel_pos]);
UINT16_PUT(&o_data[index+16], power_pcap[mca_rel_pos]);
// Nominal (same as Turbo)
UINT16_PUT(&o_data[index+18], npm_redun[mca_rel_pos]);
UINT16_PUT(&o_data[index+20], npc_redun[mca_rel_pos]);
UINT16_PUT(&o_data[index+22], power_redun[mca_rel_pos]);
index += 30;
++numSets ;
}
}
}

TMGT_INF("getMemThrottleMessageData: returning %d"
" sets of data for OCC 0x%X",
Expand Down Expand Up @@ -669,8 +731,13 @@ void getPowerCapMessageData(uint8_t* o_data, uint64_t & o_size)
index += 2;

// Quick Power Drop Power Cap
ATTR_OPEN_POWER_N_BULK_POWER_LIMIT_WATTS_type qpd_pcap =
sys->getAttr<ATTR_OPEN_POWER_N_BULK_POWER_LIMIT_WATTS>();
ATTR_OPEN_POWER_N_BULK_POWER_LIMIT_WATTS_type qpd_pcap;
if ( ! sys->tryGetAttr
<ATTR_OPEN_POWER_N_BULK_POWER_LIMIT_WATTS>(qpd_pcap))
{
// attr does not exist, so disable by sending 0
qpd_pcap = 0;
}
UINT16_PUT(&o_data[index], qpd_pcap);
index += 2;

Expand Down Expand Up @@ -846,7 +913,7 @@ void getThermalControlMessageData(uint8_t* o_data,
l_numSets++;
}

// Dimm
// DIMM
o_data[index++] = CFGDATA_FRU_TYPE_DIMM;
l_DVFS_temp =l_sys->getAttr<ATTR_OPEN_POWER_DIMM_THROTTLE_TEMP_DEG_C>();
l_ERR_temp =l_sys->getAttr<ATTR_OPEN_POWER_DIMM_ERROR_TEMP_DEG_C>();
Expand All @@ -864,6 +931,19 @@ void getThermalControlMessageData(uint8_t* o_data,
o_data[index++] = l_timeout;
l_numSets++;

// VRM
l_timeout = l_sys->getAttr<ATTR_OPEN_POWER_VRM_READ_TIMEOUT_SEC>();
if (l_timeout != 0)
{
o_data[index++] = CFGDATA_FRU_TYPE_VRM;
o_data[index++] = 0xFF;
o_data[index++] = 0xFF;
o_data[index++] = 0xFF;
o_data[index++] = 0xFF;
o_data[index++] = l_timeout;
l_numSets++;
}

o_data[l_numSetsOffset] = l_numSets;
o_size = index;

Expand Down
3 changes: 3 additions & 0 deletions src/usr/htmgt/htmgt_cfgdata.H
Expand Up @@ -71,6 +71,7 @@ namespace HTMGT
CFGDATA_FRU_TYPE_PROC = 0x00,
CFGDATA_FRU_TYPE_MEMBUF = 0x01,
CFGDATA_FRU_TYPE_DIMM = 0x02,
CFGDATA_FRU_TYPE_VRM = 0x03,

CFDATA_DVFS_NOT_DEFINED = 0xFF,
};
Expand Down Expand Up @@ -146,11 +147,13 @@ namespace HTMGT
* including the format and version numbers.
*
* @param[in] i_occ - the OCC to gather data for
* @param[in] i_occ_instance - OCC instance number
* @param[in] o_data - preallocated buffer to fill in
* @param[out] o_size - set to the message size
* @pre o_data is large enough.
*/
void getMemThrottleMessageData(const TARGETING::TargetHandle_t i_occ,
const uint8_t i_occ_instance,
uint8_t* o_data, uint64_t & o_size);


Expand Down

0 comments on commit 7d4cab0

Please sign in to comment.