| From bdd6ce1bbfe0ee77feefe84662e961fb253c6195 Mon Sep 17 00:00:00 2001 |
| From: Jim Yuan <jim.yuan@supermicro.com> |
| Date: Fri, 22 Jul 2016 17:50:57 -0700 |
| Subject: [PATCH 10/14] Adjust APSS gain and offset from PWS FRU information. |
| |
| Signed-off-by: Jim Yuan <jim.yuan@supermicro.com> |
| --- |
| src/include/usr/ipmi/ipmiif.H | 4 +- |
| src/usr/htmgt/htmgt_cfgdata.C | 2 + |
| src/usr/hwpf/hwp/start_payload/start_payload.C | 212 +++++++++++++++++++++ |
| .../common/xmltohb/attribute_types_hb.xml | 2 + |
| 4 files changed, 218 insertions(+), 2 deletions(-) |
| |
| diff --git a/src/include/usr/ipmi/ipmiif.H b/src/include/usr/ipmi/ipmiif.H |
| index 9dfd8ee63..5416ddca0 100644 |
| --- a/src/include/usr/ipmi/ipmiif.H |
| +++ b/src/include/usr/ipmi/ipmiif.H |
| @@ -251,8 +251,8 @@ namespace IPMI |
| inline const command_t set_sel_time(void) |
| { return std::make_pair(NETFUN_STORAGE, 0x49); } |
| |
| - inline const command_t read_fru_data(void) |
| - { return std::make_pair(NETFUN_STORAGE, 0x11); } |
| + inline const command_t read_fru_data(void) |
| + { return std::make_pair(NETFUN_STORAGE, 0x11); } |
| |
| inline const command_t write_fru_data(void) |
| { return std::make_pair(NETFUN_STORAGE, 0x12); } |
| diff --git a/src/usr/htmgt/htmgt_cfgdata.C b/src/usr/htmgt/htmgt_cfgdata.C |
| index 19e7b21bf..7c42abdb6 100644 |
| --- a/src/usr/htmgt/htmgt_cfgdata.C |
| +++ b/src/usr/htmgt/htmgt_cfgdata.C |
| @@ -1025,6 +1025,8 @@ void getApssMessageData(uint8_t* o_data, |
| ATTR_ADC_CHANNEL_OFFSETS_type offset; |
| sys->tryGetAttr<ATTR_ADC_CHANNEL_OFFSETS>(offset); |
| |
| + TMGT_INF("getApssMessageData: gain is %d, offset is %d", gain[15], offset[15]); //jim |
| + |
| CPPASSERT(sizeof(function) == sizeof(ground)); |
| CPPASSERT(sizeof(function) == sizeof(gain)); |
| CPPASSERT(sizeof(function) == sizeof(offset)); |
| diff --git a/src/usr/hwpf/hwp/start_payload/start_payload.C b/src/usr/hwpf/hwp/start_payload/start_payload.C |
| index 5d7865a12..ad155f19e 100644 |
| --- a/src/usr/hwpf/hwp/start_payload/start_payload.C |
| +++ b/src/usr/hwpf/hwp/start_payload/start_payload.C |
| @@ -88,6 +88,7 @@ |
| #include <algorithm> |
| #include <config.h> |
| #include <ipmi/ipmiwatchdog.H> |
| +#include <ipmi/ipmiif.H> //jim |
| #include <vpd/vpd_if.H> |
| |
| #include <hwpf/hwpf_reasoncodes.H> |
| @@ -95,6 +96,7 @@ |
| // Uncomment these files as they become available: |
| // #include "host_start_payload/host_start_payload.H" |
| |
| + |
| namespace START_PAYLOAD |
| { |
| |
| @@ -277,6 +279,214 @@ errlHndl_t setMaxPstate ( void ) |
| } |
| #endif |
| |
| +//jim-start |
| +enum |
| +{ |
| +PWS_1600 = 0, |
| +PWS_1000 = 1, |
| +PWS_1200 = 2, |
| +PWS_UNKNOWN = 0xFE, |
| +}; |
| + |
| +uint8_t getPSUFRUFromIPMICommands(void) |
| +{ |
| + errlHndl_t l_err = NULL; |
| + uint8_t* frudata = new uint8_t[120]; |
| + size_t len = 4; |
| + uint8_t fru_header_version = 0; |
| + uint8_t j = 0, loop_break = 0, read_offset = 0; |
| + |
| + //create request data buffer |
| + uint8_t* data = new uint8_t[len]; |
| + |
| + IPMI::completion_code cc = IPMI::CC_UNKBAD; |
| + |
| + data[0] = 60; //try to read from PWS1. 60-PWS1, 61-PWS2 |
| + data[1] = 0x0; |
| + data[2] = 0x0; |
| + data[3] = 8; |
| + l_err = IPMI::sendrecv(IPMI::read_fru_data(), cc, len, data); |
| + |
| + for (uint8_t i = 0; i <= 8; i++ ) |
| + fru_header_version = data[1] & 0xF; //normal should be 0x01. |
| + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "fru header version is %x", fru_header_version); |
| + delete[] data; |
| + |
| + if((l_err == NULL) && (cc == IPMI::CC_OK) && (fru_header_version == 1)) |
| + { |
| + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "could get FRU from PWS1"); |
| + |
| + while ((l_err == NULL) && (loop_break == 0) && (read_offset < 100)) |
| + { |
| + //create request data buffer |
| + len = 4; //must set len every time |
| + uint8_t* data = new uint8_t[len]; |
| + |
| + IPMI::completion_code cc = IPMI::CC_UNKBAD; |
| + |
| + data[0] = 60; //read from PWS1 |
| + data[1] = read_offset; |
| + data[2] = 0x0; |
| + data[3] = 8; |
| + l_err = IPMI::sendrecv(IPMI::read_fru_data(), cc, len, data); |
| + |
| + if (cc != IPMI::CC_OK) loop_break = 1; |
| + |
| + read_offset += 8; |
| + for (uint8_t i = 1; i <= 8; i++ ) |
| + { |
| + frudata[j] = data[i]; |
| + j++; |
| + } |
| + delete[] data; |
| + } |
| + |
| + |
| + } |
| + else |
| + { |
| + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "could get FRU from PWS2"); |
| + |
| + while ((l_err == NULL) && (loop_break == 0) && (read_offset < 100)) |
| + { |
| + //create request data buffer |
| + len = 4;//must set len every time |
| + uint8_t* data = new uint8_t[len]; |
| + |
| + IPMI::completion_code cc = IPMI::CC_UNKBAD; |
| + |
| + data[0] = 61; //read from PWS2 |
| + data[1] = read_offset; |
| + data[2] = 0x0; |
| + data[3] = 8; |
| + l_err = IPMI::sendrecv(IPMI::read_fru_data(), cc, len, data); |
| + |
| + if (cc != IPMI::CC_OK) loop_break = 1; |
| + |
| + read_offset += 8; |
| + for (uint8_t i = 1; i <= 8; i++ ) |
| + { |
| + frudata[j] = data[i]; |
| + j++; |
| + } |
| + delete[] data; |
| + } |
| + |
| + } |
| + |
| + uint8_t product_info_offset, manufacture_name_offset, manufacture_name_length, product_name_offset, product_name_length; |
| + uint8_t product_partnumber_offset, product_partnumber_length; |
| + uint8_t fru_offset, powerSupplyFru = PWS_UNKNOWN; |
| + uint8_t pws1600[] = {'P','W','S','-','1','K','6','2','A','-','1','R'}; |
| + uint8_t pws1000[] = {'P','W','S','-','1','K','0','2','A','-','1','R'}; |
| + uint8_t pws1200[] = {'P','W','S','-','1','K','2','2','A','-','1','R'}; |
| + |
| + //code to calculate product part number size and offset. should use structure. refer to FRU spec. |
| + product_info_offset = frudata[4] * 8; |
| + manufacture_name_offset = product_info_offset + 3; |
| + manufacture_name_length = frudata[manufacture_name_offset] & 0x3F; |
| + product_name_offset = manufacture_name_offset + manufacture_name_length + 1; |
| + product_name_length = frudata[product_name_offset] & 0x3F; |
| + product_partnumber_offset = product_name_offset + product_name_length + 1; |
| + product_partnumber_length = frudata[product_partnumber_offset] & 0x3F; |
| + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "product_partnumber_length is %x", product_partnumber_length); |
| + fru_offset = product_partnumber_offset + 1; |
| + |
| + if (product_partnumber_length == 12) |
| + { |
| + for (uint8_t i = 0; pws1600[i] == frudata[fru_offset + i] ; i ++) |
| + if (i == 11) |
| + powerSupplyFru = PWS_1600; |
| + |
| + for (uint8_t i = 0; pws1000[i] == frudata[fru_offset + i] ; i ++) |
| + if (i == 11) |
| + powerSupplyFru = PWS_1000; |
| + |
| + for (uint8_t i = 0; pws1200[i] == frudata[fru_offset + i] ; i ++) |
| + if (i == 11) |
| + powerSupplyFru = PWS_1200; |
| + } |
| + else |
| + powerSupplyFru = PWS_UNKNOWN; |
| + |
| + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "powerSupplyFru is %x", powerSupplyFru); |
| + |
| + return powerSupplyFru; |
| + |
| +} |
| +//find apss channel number from XML. |
| +enum |
| +{ |
| +V12_SENSE = 0, |
| +PROC0_POWER = 1, |
| +PROC1_POWER = 2, |
| +PCIE_PROC0_POWER = 5, |
| +PCIE_PROC1_POWER = 6, |
| +TOTAL_SYSTEM_POWER = 15, |
| +}; |
| + |
| +void setAPSSGainOffsetFromPWSInfo(void) |
| +{ |
| + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "before load OCC"); |
| + |
| + //Get Gain/Offset ATTR |
| + TARGETING::Target* sys = NULL; |
| + targetService().getTopLevelTarget(sys); |
| + |
| + ATTR_ADC_CHANNEL_GAINS_type gain; |
| + sys->tryGetAttr<ATTR_ADC_CHANNEL_GAINS>(gain); |
| + |
| + ATTR_ADC_CHANNEL_OFFSETS_type offset; |
| + sys->tryGetAttr<ATTR_ADC_CHANNEL_OFFSETS>(offset); |
| + |
| + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "gain is %d, offset is %d", gain[15], offset[15]); |
| + |
| + //Note that the function/ APSS channel ids can be indirect. I've hardcoded here, you will need to look at the XML to find the channel/function number that matches |
| + //const uint8_t SYS_CHANNEL = 15; //APSS Channel 15 is sys power, ie the gain/offset we need to tweak |
| + |
| + //Get power supply data from BMC |
| + uint8_t powerSupplyFru = getPSUFRUFromIPMICommands(); |
| + |
| + switch(powerSupplyFru) |
| + { |
| + case PWS_1600: //PWS-1K62A-1R (1600W): |
| + gain[TOTAL_SYSTEM_POWER] = 67800; |
| + offset[TOTAL_SYSTEM_POWER] = 0; |
| + break; |
| + |
| + case PWS_1000: //PWS-1K02A-1R (1000W): |
| + gain[TOTAL_SYSTEM_POWER] = 41500; |
| + offset[TOTAL_SYSTEM_POWER] = 0; |
| + break; |
| + |
| + case PWS_1200: //PWS-1K22A-1R (1200W): |
| + gain[TOTAL_SYSTEM_POWER] = 50000; |
| + offset[TOTAL_SYSTEM_POWER] = 0; |
| + break; |
| + |
| + default: |
| + //Do nothing, leave defaults |
| + //Gen error for user attention? |
| + break; |
| + } |
| + |
| + //Now write the attributes back so they get picked up by OCC code |
| + if (!sys->trySetAttr<ATTR_ADC_CHANNEL_GAINS>(gain)) |
| + { |
| + //unlikely, crash |
| + //Emit failing trace/console data |
| + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "set gain failed"); |
| + assert(0); |
| + } |
| + |
| + if (!sys->trySetAttr<ATTR_ADC_CHANNEL_OFFSETS>(offset)) |
| + { |
| + //unlikely, crash |
| + //Emit failing trace/console data |
| + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "set offset failed"); |
| + assert(0); |
| + } |
| +} |
| // |
| // Wrapper function to call host_runtime_setup |
| // |
| @@ -318,6 +528,8 @@ void* call_host_runtime_setup( void *io_pArgs ) |
| break; |
| } |
| |
| + setAPSSGainOffsetFromPWSInfo(); //jim add code before activate OCC. START_OCC_DURING_BOOT is defined in config. |
| + |
| bool l_activateOCC = is_avp_load(); |
| |
| #ifdef CONFIG_START_OCC_DURING_BOOT |
| diff --git a/src/usr/targeting/common/xmltohb/attribute_types_hb.xml b/src/usr/targeting/common/xmltohb/attribute_types_hb.xml |
| index c4eb6603d..64a0c9bae 100644 |
| --- a/src/usr/targeting/common/xmltohb/attribute_types_hb.xml |
| +++ b/src/usr/targeting/common/xmltohb/attribute_types_hb.xml |
| @@ -747,6 +747,7 @@ |
| </simpleType> |
| <persistency>non-volatile</persistency> |
| <readable/> |
| + <writeable/> |
| </attribute> |
| |
| <attribute> |
| @@ -758,6 +759,7 @@ |
| </simpleType> |
| <persistency>non-volatile</persistency> |
| <readable/> |
| + <writeable/> |
| </attribute> |
| |
| <attribute> |
| -- |
| 2.16.2.windows.1 |
| |