Jim Yuan | f5da1de | 2019-03-25 09:49:24 -0700 | [diff] [blame] | 1 | From bdd6ce1bbfe0ee77feefe84662e961fb253c6195 Mon Sep 17 00:00:00 2001 |
| 2 | From: Jim Yuan <jim.yuan@supermicro.com> |
| 3 | Date: Fri, 22 Jul 2016 17:50:57 -0700 |
| 4 | Subject: [PATCH 10/14] Adjust APSS gain and offset from PWS FRU information. |
| 5 | |
| 6 | Signed-off-by: Jim Yuan <jim.yuan@supermicro.com> |
| 7 | --- |
| 8 | src/include/usr/ipmi/ipmiif.H | 4 +- |
| 9 | src/usr/htmgt/htmgt_cfgdata.C | 2 + |
| 10 | src/usr/hwpf/hwp/start_payload/start_payload.C | 212 +++++++++++++++++++++ |
| 11 | .../common/xmltohb/attribute_types_hb.xml | 2 + |
| 12 | 4 files changed, 218 insertions(+), 2 deletions(-) |
| 13 | |
| 14 | diff --git a/src/include/usr/ipmi/ipmiif.H b/src/include/usr/ipmi/ipmiif.H |
| 15 | index 9dfd8ee63..5416ddca0 100644 |
| 16 | --- a/src/include/usr/ipmi/ipmiif.H |
| 17 | +++ b/src/include/usr/ipmi/ipmiif.H |
| 18 | @@ -251,8 +251,8 @@ namespace IPMI |
| 19 | inline const command_t set_sel_time(void) |
| 20 | { return std::make_pair(NETFUN_STORAGE, 0x49); } |
| 21 | |
| 22 | - inline const command_t read_fru_data(void) |
| 23 | - { return std::make_pair(NETFUN_STORAGE, 0x11); } |
| 24 | + inline const command_t read_fru_data(void) |
| 25 | + { return std::make_pair(NETFUN_STORAGE, 0x11); } |
| 26 | |
| 27 | inline const command_t write_fru_data(void) |
| 28 | { return std::make_pair(NETFUN_STORAGE, 0x12); } |
| 29 | diff --git a/src/usr/htmgt/htmgt_cfgdata.C b/src/usr/htmgt/htmgt_cfgdata.C |
| 30 | index 19e7b21bf..7c42abdb6 100644 |
| 31 | --- a/src/usr/htmgt/htmgt_cfgdata.C |
| 32 | +++ b/src/usr/htmgt/htmgt_cfgdata.C |
| 33 | @@ -1025,6 +1025,8 @@ void getApssMessageData(uint8_t* o_data, |
| 34 | ATTR_ADC_CHANNEL_OFFSETS_type offset; |
| 35 | sys->tryGetAttr<ATTR_ADC_CHANNEL_OFFSETS>(offset); |
| 36 | |
| 37 | + TMGT_INF("getApssMessageData: gain is %d, offset is %d", gain[15], offset[15]); //jim |
| 38 | + |
| 39 | CPPASSERT(sizeof(function) == sizeof(ground)); |
| 40 | CPPASSERT(sizeof(function) == sizeof(gain)); |
| 41 | CPPASSERT(sizeof(function) == sizeof(offset)); |
| 42 | diff --git a/src/usr/hwpf/hwp/start_payload/start_payload.C b/src/usr/hwpf/hwp/start_payload/start_payload.C |
| 43 | index 5d7865a12..ad155f19e 100644 |
| 44 | --- a/src/usr/hwpf/hwp/start_payload/start_payload.C |
| 45 | +++ b/src/usr/hwpf/hwp/start_payload/start_payload.C |
| 46 | @@ -88,6 +88,7 @@ |
| 47 | #include <algorithm> |
| 48 | #include <config.h> |
| 49 | #include <ipmi/ipmiwatchdog.H> |
| 50 | +#include <ipmi/ipmiif.H> //jim |
| 51 | #include <vpd/vpd_if.H> |
| 52 | |
| 53 | #include <hwpf/hwpf_reasoncodes.H> |
| 54 | @@ -95,6 +96,7 @@ |
| 55 | // Uncomment these files as they become available: |
| 56 | // #include "host_start_payload/host_start_payload.H" |
| 57 | |
| 58 | + |
| 59 | namespace START_PAYLOAD |
| 60 | { |
| 61 | |
| 62 | @@ -277,6 +279,214 @@ errlHndl_t setMaxPstate ( void ) |
| 63 | } |
| 64 | #endif |
| 65 | |
| 66 | +//jim-start |
| 67 | +enum |
| 68 | +{ |
| 69 | +PWS_1600 = 0, |
| 70 | +PWS_1000 = 1, |
| 71 | +PWS_1200 = 2, |
| 72 | +PWS_UNKNOWN = 0xFE, |
| 73 | +}; |
| 74 | + |
| 75 | +uint8_t getPSUFRUFromIPMICommands(void) |
| 76 | +{ |
| 77 | + errlHndl_t l_err = NULL; |
| 78 | + uint8_t* frudata = new uint8_t[120]; |
| 79 | + size_t len = 4; |
| 80 | + uint8_t fru_header_version = 0; |
| 81 | + uint8_t j = 0, loop_break = 0, read_offset = 0; |
| 82 | + |
| 83 | + //create request data buffer |
| 84 | + uint8_t* data = new uint8_t[len]; |
| 85 | + |
| 86 | + IPMI::completion_code cc = IPMI::CC_UNKBAD; |
| 87 | + |
| 88 | + data[0] = 60; //try to read from PWS1. 60-PWS1, 61-PWS2 |
| 89 | + data[1] = 0x0; |
| 90 | + data[2] = 0x0; |
| 91 | + data[3] = 8; |
| 92 | + l_err = IPMI::sendrecv(IPMI::read_fru_data(), cc, len, data); |
| 93 | + |
| 94 | + for (uint8_t i = 0; i <= 8; i++ ) |
| 95 | + fru_header_version = data[1] & 0xF; //normal should be 0x01. |
| 96 | + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "fru header version is %x", fru_header_version); |
| 97 | + delete[] data; |
| 98 | + |
| 99 | + if((l_err == NULL) && (cc == IPMI::CC_OK) && (fru_header_version == 1)) |
| 100 | + { |
| 101 | + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "could get FRU from PWS1"); |
| 102 | + |
| 103 | + while ((l_err == NULL) && (loop_break == 0) && (read_offset < 100)) |
| 104 | + { |
| 105 | + //create request data buffer |
| 106 | + len = 4; //must set len every time |
| 107 | + uint8_t* data = new uint8_t[len]; |
| 108 | + |
| 109 | + IPMI::completion_code cc = IPMI::CC_UNKBAD; |
| 110 | + |
| 111 | + data[0] = 60; //read from PWS1 |
| 112 | + data[1] = read_offset; |
| 113 | + data[2] = 0x0; |
| 114 | + data[3] = 8; |
| 115 | + l_err = IPMI::sendrecv(IPMI::read_fru_data(), cc, len, data); |
| 116 | + |
| 117 | + if (cc != IPMI::CC_OK) loop_break = 1; |
| 118 | + |
| 119 | + read_offset += 8; |
| 120 | + for (uint8_t i = 1; i <= 8; i++ ) |
| 121 | + { |
| 122 | + frudata[j] = data[i]; |
| 123 | + j++; |
| 124 | + } |
| 125 | + delete[] data; |
| 126 | + } |
| 127 | + |
| 128 | + |
| 129 | + } |
| 130 | + else |
| 131 | + { |
| 132 | + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "could get FRU from PWS2"); |
| 133 | + |
| 134 | + while ((l_err == NULL) && (loop_break == 0) && (read_offset < 100)) |
| 135 | + { |
| 136 | + //create request data buffer |
| 137 | + len = 4;//must set len every time |
| 138 | + uint8_t* data = new uint8_t[len]; |
| 139 | + |
| 140 | + IPMI::completion_code cc = IPMI::CC_UNKBAD; |
| 141 | + |
| 142 | + data[0] = 61; //read from PWS2 |
| 143 | + data[1] = read_offset; |
| 144 | + data[2] = 0x0; |
| 145 | + data[3] = 8; |
| 146 | + l_err = IPMI::sendrecv(IPMI::read_fru_data(), cc, len, data); |
| 147 | + |
| 148 | + if (cc != IPMI::CC_OK) loop_break = 1; |
| 149 | + |
| 150 | + read_offset += 8; |
| 151 | + for (uint8_t i = 1; i <= 8; i++ ) |
| 152 | + { |
| 153 | + frudata[j] = data[i]; |
| 154 | + j++; |
| 155 | + } |
| 156 | + delete[] data; |
| 157 | + } |
| 158 | + |
| 159 | + } |
| 160 | + |
| 161 | + uint8_t product_info_offset, manufacture_name_offset, manufacture_name_length, product_name_offset, product_name_length; |
| 162 | + uint8_t product_partnumber_offset, product_partnumber_length; |
| 163 | + uint8_t fru_offset, powerSupplyFru = PWS_UNKNOWN; |
| 164 | + uint8_t pws1600[] = {'P','W','S','-','1','K','6','2','A','-','1','R'}; |
| 165 | + uint8_t pws1000[] = {'P','W','S','-','1','K','0','2','A','-','1','R'}; |
| 166 | + uint8_t pws1200[] = {'P','W','S','-','1','K','2','2','A','-','1','R'}; |
| 167 | + |
| 168 | + //code to calculate product part number size and offset. should use structure. refer to FRU spec. |
| 169 | + product_info_offset = frudata[4] * 8; |
| 170 | + manufacture_name_offset = product_info_offset + 3; |
| 171 | + manufacture_name_length = frudata[manufacture_name_offset] & 0x3F; |
| 172 | + product_name_offset = manufacture_name_offset + manufacture_name_length + 1; |
| 173 | + product_name_length = frudata[product_name_offset] & 0x3F; |
| 174 | + product_partnumber_offset = product_name_offset + product_name_length + 1; |
| 175 | + product_partnumber_length = frudata[product_partnumber_offset] & 0x3F; |
| 176 | + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "product_partnumber_length is %x", product_partnumber_length); |
| 177 | + fru_offset = product_partnumber_offset + 1; |
| 178 | + |
| 179 | + if (product_partnumber_length == 12) |
| 180 | + { |
| 181 | + for (uint8_t i = 0; pws1600[i] == frudata[fru_offset + i] ; i ++) |
| 182 | + if (i == 11) |
| 183 | + powerSupplyFru = PWS_1600; |
| 184 | + |
| 185 | + for (uint8_t i = 0; pws1000[i] == frudata[fru_offset + i] ; i ++) |
| 186 | + if (i == 11) |
| 187 | + powerSupplyFru = PWS_1000; |
| 188 | + |
| 189 | + for (uint8_t i = 0; pws1200[i] == frudata[fru_offset + i] ; i ++) |
| 190 | + if (i == 11) |
| 191 | + powerSupplyFru = PWS_1200; |
| 192 | + } |
| 193 | + else |
| 194 | + powerSupplyFru = PWS_UNKNOWN; |
| 195 | + |
| 196 | + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "powerSupplyFru is %x", powerSupplyFru); |
| 197 | + |
| 198 | + return powerSupplyFru; |
| 199 | + |
| 200 | +} |
| 201 | +//find apss channel number from XML. |
| 202 | +enum |
| 203 | +{ |
| 204 | +V12_SENSE = 0, |
| 205 | +PROC0_POWER = 1, |
| 206 | +PROC1_POWER = 2, |
| 207 | +PCIE_PROC0_POWER = 5, |
| 208 | +PCIE_PROC1_POWER = 6, |
| 209 | +TOTAL_SYSTEM_POWER = 15, |
| 210 | +}; |
| 211 | + |
| 212 | +void setAPSSGainOffsetFromPWSInfo(void) |
| 213 | +{ |
| 214 | + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "before load OCC"); |
| 215 | + |
| 216 | + //Get Gain/Offset ATTR |
| 217 | + TARGETING::Target* sys = NULL; |
| 218 | + targetService().getTopLevelTarget(sys); |
| 219 | + |
| 220 | + ATTR_ADC_CHANNEL_GAINS_type gain; |
| 221 | + sys->tryGetAttr<ATTR_ADC_CHANNEL_GAINS>(gain); |
| 222 | + |
| 223 | + ATTR_ADC_CHANNEL_OFFSETS_type offset; |
| 224 | + sys->tryGetAttr<ATTR_ADC_CHANNEL_OFFSETS>(offset); |
| 225 | + |
| 226 | + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "gain is %d, offset is %d", gain[15], offset[15]); |
| 227 | + |
| 228 | + //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 |
| 229 | + //const uint8_t SYS_CHANNEL = 15; //APSS Channel 15 is sys power, ie the gain/offset we need to tweak |
| 230 | + |
| 231 | + //Get power supply data from BMC |
| 232 | + uint8_t powerSupplyFru = getPSUFRUFromIPMICommands(); |
| 233 | + |
| 234 | + switch(powerSupplyFru) |
| 235 | + { |
| 236 | + case PWS_1600: //PWS-1K62A-1R (1600W): |
| 237 | + gain[TOTAL_SYSTEM_POWER] = 67800; |
| 238 | + offset[TOTAL_SYSTEM_POWER] = 0; |
| 239 | + break; |
| 240 | + |
| 241 | + case PWS_1000: //PWS-1K02A-1R (1000W): |
| 242 | + gain[TOTAL_SYSTEM_POWER] = 41500; |
| 243 | + offset[TOTAL_SYSTEM_POWER] = 0; |
| 244 | + break; |
| 245 | + |
| 246 | + case PWS_1200: //PWS-1K22A-1R (1200W): |
| 247 | + gain[TOTAL_SYSTEM_POWER] = 50000; |
| 248 | + offset[TOTAL_SYSTEM_POWER] = 0; |
| 249 | + break; |
| 250 | + |
| 251 | + default: |
| 252 | + //Do nothing, leave defaults |
| 253 | + //Gen error for user attention? |
| 254 | + break; |
| 255 | + } |
| 256 | + |
| 257 | + //Now write the attributes back so they get picked up by OCC code |
| 258 | + if (!sys->trySetAttr<ATTR_ADC_CHANNEL_GAINS>(gain)) |
| 259 | + { |
| 260 | + //unlikely, crash |
| 261 | + //Emit failing trace/console data |
| 262 | + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "set gain failed"); |
| 263 | + assert(0); |
| 264 | + } |
| 265 | + |
| 266 | + if (!sys->trySetAttr<ATTR_ADC_CHANNEL_OFFSETS>(offset)) |
| 267 | + { |
| 268 | + //unlikely, crash |
| 269 | + //Emit failing trace/console data |
| 270 | + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "set offset failed"); |
| 271 | + assert(0); |
| 272 | + } |
| 273 | +} |
| 274 | // |
| 275 | // Wrapper function to call host_runtime_setup |
| 276 | // |
| 277 | @@ -318,6 +528,8 @@ void* call_host_runtime_setup( void *io_pArgs ) |
| 278 | break; |
| 279 | } |
| 280 | |
| 281 | + setAPSSGainOffsetFromPWSInfo(); //jim add code before activate OCC. START_OCC_DURING_BOOT is defined in config. |
| 282 | + |
| 283 | bool l_activateOCC = is_avp_load(); |
| 284 | |
| 285 | #ifdef CONFIG_START_OCC_DURING_BOOT |
| 286 | diff --git a/src/usr/targeting/common/xmltohb/attribute_types_hb.xml b/src/usr/targeting/common/xmltohb/attribute_types_hb.xml |
| 287 | index c4eb6603d..64a0c9bae 100644 |
| 288 | --- a/src/usr/targeting/common/xmltohb/attribute_types_hb.xml |
| 289 | +++ b/src/usr/targeting/common/xmltohb/attribute_types_hb.xml |
| 290 | @@ -747,6 +747,7 @@ |
| 291 | </simpleType> |
| 292 | <persistency>non-volatile</persistency> |
| 293 | <readable/> |
| 294 | + <writeable/> |
| 295 | </attribute> |
| 296 | |
| 297 | <attribute> |
| 298 | @@ -758,6 +759,7 @@ |
| 299 | </simpleType> |
| 300 | <persistency>non-volatile</persistency> |
| 301 | <readable/> |
| 302 | + <writeable/> |
| 303 | </attribute> |
| 304 | |
| 305 | <attribute> |
| 306 | -- |
| 307 | 2.16.2.windows.1 |
| 308 | |