/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/usr/htmgt/htmgt_cfgdata.C $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2014,2015 */ /* [+] International Business Machines Corp. */ /* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ /* You may obtain a copy of the License at */ /* */ /* http://www.apache.org/licenses/LICENSE-2.0 */ /* */ /* Unless required by applicable law or agreed to in writing, software */ /* distributed under the License is distributed on an "AS IS" BASIS, */ /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ /* implied. See the License for the specific language governing */ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ #include #include #include #include "htmgt_cfgdata.H" #include "htmgt_utility.H" #include "htmgt_poll.H" #include "ipmi/ipmisensor.H" using namespace TARGETING; //for unit testing //#define TRACUCOMP(args...) TMGT_INF(args) #define TRACUCOMP(args...) namespace HTMGT { // Send config format data to all OCCs void sendOccConfigData(const occCfgDataFormat i_requestedFormat) { if (G_debug_trace & DEBUG_TRACE_VERBOSE) { TMGT_INF("sendOccConfigData called"); } uint8_t cmdData[OCC_MAX_DATA_LENGTH] = {0}; uint64_t cmdDataLen = OCC_MAX_DATA_LENGTH; const occCfgDataTable_t* start = &occCfgDataTable[0]; const occCfgDataTable_t* end = &occCfgDataTable[OCC_CONFIG_TABLE_SIZE]; bool validFormat = true; if (OCC_CFGDATA_CLEAR_ALL != i_requestedFormat) { const occCfgDataTable_t * target = std::find(start, end, i_requestedFormat); if (target != end) { // only need to send a single packet start = target; end = start+1; } else { TMGT_ERR("sendOccConfigData: Invalid cfg format supplied %d", i_requestedFormat); validFormat = false; } } if (validFormat) { // Loop through all functional OCCs std::vector occList = OccManager::getOccArray(); for (std::vector::iterator itr = occList.begin(); itr < occList.end(); itr++) { Occ * occ = (*itr); const uint8_t occInstance = occ->getInstance(); const occRole role = occ->getRole(); // Loop through all config data types for (const occCfgDataTable_t *itr = start; itr < end; ++itr) { const occCfgDataFormat format = itr->format; bool sendData = true; // Make sure format is supported by this OCC if (TARGET_MASTER == itr->targets) { if (OCC_ROLE_MASTER != role) { sendData = false; } } // Make sure data is supported in the current state const occStateId state = occ->getState(); if (CFGSTATE_STANDBY == itr->supportedStates) { if (OCC_STATE_STANDBY != state) { sendData = false; } } else if (CFGSTATE_SBYOBS == itr->supportedStates) { if ((OCC_STATE_STANDBY != state) && (OCC_STATE_OBSERVATION != state)) { sendData = false; } } if (sendData) { cmdDataLen = OCC_MAX_DATA_LENGTH; switch(format) { case OCC_CFGDATA_PSTATE_SSTRUCT: getPstateTableMessageData(occ->getTarget(), cmdData, cmdDataLen); break; case OCC_CFGDATA_FREQ_POINT: getFrequencyPointMessageData(cmdData, cmdDataLen); break; case OCC_CFGDATA_OCC_ROLE: getOCCRoleMessageData(OCC_ROLE_MASTER == occ->getRole(), OCC_ROLE_FIR_MASTER == occ->getRole(), cmdData, cmdDataLen); break; case OCC_CFGDATA_APSS_CONFIG: getApssMessageData(cmdData, cmdDataLen); break; case OCC_CFGDATA_MEM_CONFIG: getMemConfigMessageData(occ->getTarget(), true, cmdData, cmdDataLen); break; case OCC_CFGDATA_FIR_SCOMS: TMGT_ERR("NO FIR SCOMS AVAILABLE YET"); cmdDataLen = 0; break; case OCC_CFGDATA_PCAP_CONFIG: getPowerCapMessageData(cmdData, cmdDataLen); break; case OCC_CFGDATA_SYS_CONFIG: getSystemConfigMessageData(occ->getTarget(), cmdData, cmdDataLen); break; case OCC_CFGDATA_MEM_THROTTLE: getMemThrottleMessageData(occ->getTarget(), cmdData, cmdDataLen); break; case OCC_CFGDATA_TCT_CONFIG: getThermalControlMessageData(cmdData, cmdDataLen); break; default: TMGT_ERR("send_occ_config_data: Unsupported" " format type 0x%02X", format); cmdDataLen = 0; } if (cmdDataLen > 0) { TMGT_INF("send_occ_config_data: Sending config" " 0x%02X to OCC%d", format, occInstance); OccCmd cmd(occ, OCC_CMD_SETUP_CFG_DATA, cmdDataLen, cmdData); errlHndl_t l_err = cmd.sendOccCmd(); if (l_err != NULL) { TMGT_ERR("send_occ_config_data: OCC%d cfg " "format 0x%02X failed with rc=0x%04X", occInstance, format, l_err->reasonCode()); ERRORLOG::errlCommit(l_err, HTMGT_COMP_ID); } else { if (OCC_RC_SUCCESS != cmd.getRspStatus()) { TMGT_ERR("send_occ_config_data: OCC%d cfg " "format 0x%02X had bad rsp status" " 0x%02X for sysConfig", occInstance, format, cmd.getRspStatus()); } } // Send poll between config packets to flush errors l_err = OccManager::sendOccPoll(); if (l_err) { ERRORLOG::errlCommit(l_err, HTMGT_COMP_ID); } } } // if (sendData) } // for each config format } // for each OCC } } // end send_occ_config_data() /** OCC configuration data message versions */ enum occCfgDataVersion { OCC_CFGDATA_PSTATE_VERSION = 0x10, OCC_CFGDATA_FREQ_POINT_VERSION = 0x10, OCC_CFGDATA_APSS_VERSION = 0x10, OCC_CFGDATA_MEM_CONFIG_VERSION = 0x10, OCC_CFGDATA_PCAP_CONFIG_VERSION = 0x10, OCC_CFGDATA_SYS_CONFIG_VERSION = 0x10, OCC_CFGDATA_MEM_THROTTLE_VERSION = 0x10, OCC_CFGDATA_TCT_CONFIG_VERSION = 0x10 }; void getMemConfigMessageData(const TargetHandle_t i_occ, bool i_monitoringEnabled, uint8_t* o_data, uint64_t & o_size) { uint64_t index = 0; assert(o_data != NULL); o_data[index++] = OCC_CFGDATA_MEM_CONFIG; o_data[index++] = OCC_CFGDATA_MEM_CONFIG_VERSION; size_t numSetsOffset = index++; //Will fill in numSets at the end //Next, the following format repeats per set of data //Bytes 0-3: Reserved //Bytes 4-5 hardware sensor ID //Bytes 6-7: temperature sensor ID //Byte 8: Centaur position 0-7 //Byte 9: DIMM position 0-7 //Bytes 10-11: Reserved if (i_monitoringEnabled) { TargetHandleList centaurs; TargetHandleList mbas; TargetHandleList dimms; TargetHandleList::const_iterator centaur; TargetHandleList::const_iterator mba; TargetHandleList::const_iterator dimm; uint8_t centPos = 0; uint8_t dimmPos = 0; uint8_t numSets = 0; uint16_t sensor = 0; ConstTargetHandle_t proc = getParentChip(i_occ); assert(proc != NULL); getChildAffinityTargets(centaurs, proc, CLASS_CHIP, TYPE_MEMBUF); TRACUCOMP("Proc 0x%X has %d centaurs", proc->getAttr(), centaurs.size()); for (centaur=centaurs.begin(); centaur!=centaurs.end(); ++centaur) { numSets++; //Do the entry for the Centaur itself //Reserved memset(&o_data[index], 0, 4); index += 4; //Hardware Sensor ID sensor = UTIL::getSensorNumber(*centaur, SENSOR_NAME_MEMBUF_STATE); memcpy(&o_data[index], &sensor, 2); index += 2; //Temperature Sensor ID sensor = UTIL::getSensorNumber(*centaur, SENSOR_NAME_MEMBUF_TEMP); memcpy(&o_data[index], &sensor, 2); index += 2; //Centaur # centPos = (*centaur)->getAttr(); o_data[index++] = centPos; //Dimm # (0xFF since a centaur) o_data[index++] = 0xFF; //Reserved memset(&o_data[index], 0, 2); index += 2; mbas.clear(); getChildAffinityTargets(mbas, *centaur, CLASS_UNIT, TYPE_MBA); for (mba=mbas.begin(); mba!=mbas.end(); ++mba) { dimms.clear(); getChildAffinityTargets(dimms, *mba, CLASS_LOGICAL_CARD, TYPE_DIMM); TRACUCOMP("MBA 0x%X has %d DIMMs", (*mba)->getAttr(), dimms.size()); for (dimm=dimms.begin(); dimm!=dimms.end(); ++dimm) { //Fill in the DIMM entry numSets++; //Reserved memset(&o_data[index], 0, 4); index += 4; //Hardware Sensor ID sensor = UTIL::getSensorNumber(*dimm, SENSOR_NAME_DIMM_STATE); memcpy(&o_data[index], &sensor, 2); index += 2; //Temperature Sensor ID sensor = UTIL::getSensorNumber(*dimm, SENSOR_NAME_DIMM_TEMP); memcpy(&o_data[index], &sensor, 2); index += 2; //Centaur # o_data[index++] = centPos; //DIMM # dimmPos = getOCCDIMMPos(*mba, *dimm); o_data[index++] = dimmPos; //Reserved memset(&o_data[index], 0, 2); index += 2; } } } TMGT_INF("getMemConfigMessageData: returning %d" " sets of data for OCC 0x%X", numSets, i_occ->getAttr()); o_data[numSetsOffset] = numSets; } else { TMGT_INF("getMemConfigMessageData: Mem monitoring is disabled"); //A zero in byte 2 (numSets) means monitoring is disabled o_data[2] = 0; } o_size = index; } void getMemThrottleMessageData(const TargetHandle_t i_occ, uint8_t* o_data, uint64_t & o_size) { uint8_t centPos = 0; uint8_t mbaPos = 0; uint8_t numSets = 0; uint64_t index = 0; uint16_t numerator = 0; ConstTargetHandle_t proc = getParentChip(i_occ); assert(proc != NULL); assert(o_data != NULL); o_data[index++] = OCC_CFGDATA_MEM_THROTTLE; o_data[index++] = OCC_CFGDATA_MEM_THROTTLE_VERSION; index++; //Will fill in numSets at the end TargetHandleList centaurs; TargetHandleList mbas; TargetHandleList::const_iterator centaur; TargetHandleList::const_iterator mba; getChildAffinityTargets(centaurs, proc, CLASS_CHIP, TYPE_MEMBUF); //Next, the following format repeats per set/MBA: //Byte 0: Centaur position 0-7 //Byte 1: MBA Position 0-1 //Bytes 2-3: min OT N_PER_MBA //bytes 4-5: redundant power N_PER_MBA //bytes 6-7: redundant power N_PER_CHIP //bytes 8-9: oversubscription N_PER_MBA //bytes 10-11: oversubscription N_PER_CHIP for (centaur=centaurs.begin(); centaur!=centaurs.end(); ++centaur) { centPos = (*centaur)->getAttr(); mbas.clear(); getChildAffinityTargets(mbas, *centaur, CLASS_UNIT, TYPE_MBA); for (mba=mbas.begin(); mba!=mbas.end(); ++mba) { numSets++; mbaPos = (*mba)->getAttr(); TRACUCOMP("centPos = %d, mbaPos = %d", centPos, mbaPos); o_data[index++] = centPos; o_data[index++] = mbaPos; numerator = (*mba)->getAttr(); memcpy(&o_data[index], &numerator, 2); index += 2; numerator = (*mba)->getAttr(); memcpy(&o_data[index], &numerator, 2); index += 2; numerator = (*mba)->getAttr(); memcpy(&o_data[index], &numerator, 2); index += 2; numerator = (*mba)->getAttr(); memcpy(&o_data[index], &numerator, 2); index += 2; numerator = (*mba)->getAttr(); memcpy(&o_data[index], &numerator, 2); index += 2; } } TMGT_INF("getMemThrottleMessageData: returning %d" " sets of data for OCC 0x%X", numSets, i_occ->getAttr()); o_data[2] = numSets; o_size = index; } void getOCCRoleMessageData(bool i_master, bool i_firMaster, uint8_t* o_data, uint64_t & o_size) { assert(o_data != NULL); o_data[0] = OCC_CFGDATA_OCC_ROLE; o_data[1] = OCC_ROLE_SLAVE; if (i_master) { o_data[1] = OCC_ROLE_MASTER; } if (i_firMaster) { o_data[1] |= OCC_ROLE_FIR_MASTER; } o_size = 2; } void getPowerCapMessageData(uint8_t* o_data, uint64_t & o_size) { uint64_t index = 0; uint16_t pcap = 0; Target* sys = NULL; targetService().getTopLevelTarget(sys); assert(sys != NULL); assert(o_data != NULL); o_data[index++] = OCC_CFGDATA_PCAP_CONFIG; o_data[index++] = OCC_CFGDATA_PCAP_CONFIG_VERSION; //Minimum Power Cap pcap = sys->getAttr(); memcpy(&o_data[index], &pcap, 2); index += 2; //System Maximum Power Cap pcap = sys->getAttr(); memcpy(&o_data[index], &pcap, 2); index += 2; //Oversubscription Power Cap pcap = sys->getAttr(); memcpy(&o_data[index], &pcap, 2); index += 2; o_size = index; } void getSystemConfigMessageData(const TargetHandle_t i_occ, uint8_t* o_data, uint64_t & o_size) { uint64_t index = 0; uint16_t sensor = 0; assert(o_data != NULL); o_data[index++] = OCC_CFGDATA_SYS_CONFIG; o_data[index++] = OCC_CFGDATA_SYS_CONFIG_VERSION; //System Type o_data[index++] = OCC_CFGDATA_OPENPOWER_SYSTEMTYPE; //processor sensor ID ConstTargetHandle_t proc = getParentChip(i_occ); sensor = UTIL::getSensorNumber(proc, SENSOR_NAME_PROC_STATE); memcpy(&o_data[index], &sensor, 2); index += 2; //Next 12*4 bytes are for core sensors. //If a new processor with more cores comes along, //this command will have to change. TargetHandleList cores; TargetHandleList::iterator coreIt; getChildChiplets(cores, proc, TYPE_CORE, false); uint16_t tempSensor = 0; uint16_t freqSensor = 0; for (uint64_t core=0; coregetAttr(); o_data[index++] = sys->getAttr(); o_data[index++] = sys->getAttr(); o_data[index++] = CFGDATA_FRU_TYPE_MEMBUF; o_data[index++] = sys-> getAttr(); o_data[index++] = sys->getAttr(); o_data[index++] = sys->getAttr(); o_data[index++] = CFGDATA_FRU_TYPE_DIMM; o_data[index++] = sys->getAttr(); o_data[index++] = sys->getAttr(); o_data[index++] = sys->getAttr(); o_size = index; } void getFrequencyPointMessageData(uint8_t* o_data, uint64_t & o_size) { uint64_t index = 0; uint16_t min = 0; uint16_t max = 0; uint16_t nominal = 0; Target* sys = NULL; targetService().getTopLevelTarget(sys); assert(sys != NULL); assert(o_data != NULL); o_data[index++] = OCC_CFGDATA_FREQ_POINT; o_data[index++] = OCC_CFGDATA_FREQ_POINT_VERSION; //Nominal Frequency in MHz nominal = sys->getAttr(); memcpy(&o_data[index], &nominal, 2); index += 2; //Maximum Frequency in MHz uint8_t turboAllowed = sys->getAttr(); //If Turbo isn't allowed, then we send up the //nominal frequency for this value. if (turboAllowed) { max = sys->getAttr(); } else { max = nominal; } memcpy(&o_data[index], &max, 2); index += 2; //Minimum Frequency in MHz min = sys->getAttr(); memcpy(&o_data[index], &min, 2); index += 2; TMGT_INF("Frequency Points: Nominal %d, Max %d, Min %d", (uint32_t)nominal, (uint32_t)max, (uint32_t)min); o_size = index; } void getPstateTableMessageData(const TargetHandle_t i_occTarget, uint8_t* o_data, uint64_t & io_size) { uint64_t msg_size = sizeof(ATTR_PSTATE_TABLE_type) + 4; assert(io_size >= msg_size); if(io_size > msg_size) { io_size = msg_size; } o_data[0] = OCC_CFGDATA_PSTATE_SSTRUCT; o_data[1] = 0; // reserved o_data[2] = 0; // reserved o_data[3] = 0; // reserved // Read data from attribute for specified occ ATTR_PSTATE_TABLE_type * pstateDataPtr = reinterpret_cast(o_data + 4); i_occTarget->tryGetAttr(*pstateDataPtr); } void getApssMessageData(uint8_t* o_data, uint64_t & o_size) { Target* sys = NULL; targetService().getTopLevelTarget(sys); ATTR_ADC_CHANNEL_FUNC_IDS_type function; sys->tryGetAttr(function); ATTR_ADC_CHANNEL_GNDS_type ground; sys->tryGetAttr(ground); ATTR_ADC_CHANNEL_GAINS_type gain; sys->tryGetAttr(gain); ATTR_ADC_CHANNEL_OFFSETS_type offset; sys->tryGetAttr(offset); CPPASSERT(sizeof(function) == sizeof(ground)); CPPASSERT(sizeof(function) == sizeof(gain)); CPPASSERT(sizeof(function) == sizeof(offset)); //The APSS function below hardcodes 16 channels, //so everything better agree. CPPASSERT(sizeof(function) == 16); const uint16_t (*sensors)[16] = NULL; errlHndl_t err = SENSOR::getAPSSChannelSensorNumbers(sensors); if (err) { TMGT_ERR("getApssMessageData: Call to getAPSSChannelSensorNumbers " "failed."); ERRORLOG::errlCommit(err, HTMGT_COMP_ID); sensors = NULL; } o_data[0] = OCC_CFGDATA_APSS_CONFIG; o_data[1] = OCC_CFGDATA_APSS_VERSION; o_data[2] = 0; o_data[3] = 0; uint64_t idx = 4; uint16_t sensorId = 0; for(uint64_t channel = 0; channel < sizeof(function); ++channel) { o_data[idx] = function[channel]; // ADC Channel assignement idx += sizeof(uint8_t); sensorId = 0; if (sensors != NULL) { sensorId = (*sensors)[channel]; } memcpy(o_data+idx,&sensorId,sizeof(uint16_t)); // Sensor ID idx += sizeof(uint16_t); o_data[idx] = ground[channel]; // Ground Select idx += sizeof(uint8_t); memcpy(o_data+idx, &gain[channel], sizeof(uint32_t)); // Gain idx += sizeof(uint32_t); memcpy(o_data+idx, &offset[channel], sizeof(uint32_t)); // offset idx += sizeof(uint32_t); } ATTR_APSS_GPIO_PORT_MODES_type gpioMode; sys->tryGetAttr(gpioMode); ATTR_APSS_GPIO_PORT_PINS_type gpioPin; sys->tryGetAttr(gpioPin); uint64_t pinsPerPort = sizeof(ATTR_APSS_GPIO_PORT_PINS_type) / sizeof(ATTR_APSS_GPIO_PORT_MODES_type); uint64_t pinIdx = 0; for(uint64_t port = 0; port < sizeof(gpioMode); ++port) { o_data[idx] = gpioMode[port]; idx += sizeof(uint8_t); o_data[idx] = 0; idx += sizeof(uint8_t); memcpy(o_data + idx, gpioPin+pinIdx, pinsPerPort); idx += pinsPerPort; pinIdx += pinsPerPort; } o_size = idx; } }