116a2ced3SJonathan Doman // Copyright (c) 2022 Intel Corporation 216a2ced3SJonathan Doman // 316a2ced3SJonathan Doman // Licensed under the Apache License, Version 2.0 (the "License"); 416a2ced3SJonathan Doman // you may not use this file except in compliance with the License. 516a2ced3SJonathan Doman // You may obtain a copy of the License at 616a2ced3SJonathan Doman // 716a2ced3SJonathan Doman // http://www.apache.org/licenses/LICENSE-2.0 816a2ced3SJonathan Doman // 916a2ced3SJonathan Doman // Unless required by applicable law or agreed to in writing, software 1016a2ced3SJonathan Doman // distributed under the License is distributed on an "AS IS" BASIS, 1116a2ced3SJonathan Doman // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1216a2ced3SJonathan Doman // See the License for the specific language governing permissions and 1316a2ced3SJonathan Doman // limitations under the License. 1416a2ced3SJonathan Doman 1516a2ced3SJonathan Doman #include "cpuinfo_utils.hpp" 1616a2ced3SJonathan Doman #include "speed_select.hpp" 1716a2ced3SJonathan Doman 1816a2ced3SJonathan Doman #include <iostream> 1916a2ced3SJonathan Doman 2016a2ced3SJonathan Doman namespace cpu_info 2116a2ced3SJonathan Doman { 2216a2ced3SJonathan Doman namespace sst 2316a2ced3SJonathan Doman { 2416a2ced3SJonathan Doman 2516a2ced3SJonathan Doman /** 2616a2ced3SJonathan Doman * Convenience RAII object for Wake-On-PECI (WOP) management, since PECI Config 2716a2ced3SJonathan Doman * Local accesses to the OS Mailbox require the package to pop up to PC2. Also 2816a2ced3SJonathan Doman * provides PCode OS Mailbox routine. 2916a2ced3SJonathan Doman * 3016a2ced3SJonathan Doman * Since multiple applications may be modifing WOP, we'll use this algorithm: 3116a2ced3SJonathan Doman * Whenever a PECI command fails with associated error code, set WOP bit and 3216a2ced3SJonathan Doman * retry command. Upon manager destruction, clear WOP bit only if we previously 3316a2ced3SJonathan Doman * set it. 3416a2ced3SJonathan Doman */ 3516a2ced3SJonathan Doman struct PECIManager 3616a2ced3SJonathan Doman { 3716a2ced3SJonathan Doman uint8_t peciAddress; 3816a2ced3SJonathan Doman bool peciWoken; 3916a2ced3SJonathan Doman CPUModel cpuModel; 4016a2ced3SJonathan Doman uint8_t mbBus; 4116a2ced3SJonathan Doman 4216a2ced3SJonathan Doman PECIManager(uint8_t address, CPUModel model) : 4316a2ced3SJonathan Doman peciAddress(address), peciWoken(false), cpuModel(model) 4416a2ced3SJonathan Doman { 4516a2ced3SJonathan Doman mbBus = (model == icx) ? mbBusICX : mbBusOther; 4616a2ced3SJonathan Doman } 4716a2ced3SJonathan Doman 4816a2ced3SJonathan Doman ~PECIManager() 4916a2ced3SJonathan Doman { 5016a2ced3SJonathan Doman // If we're being destroyed due to a PECIError, try to clear the mode 5116a2ced3SJonathan Doman // bit, but catch and ignore any duplicate error it might raise to 5216a2ced3SJonathan Doman // prevent termination. 5316a2ced3SJonathan Doman try 5416a2ced3SJonathan Doman { 5516a2ced3SJonathan Doman if (peciWoken) 5616a2ced3SJonathan Doman { 5716a2ced3SJonathan Doman setWakeOnPECI(false); 5816a2ced3SJonathan Doman } 5916a2ced3SJonathan Doman } 6016a2ced3SJonathan Doman catch (const PECIError& err) 6116a2ced3SJonathan Doman {} 6216a2ced3SJonathan Doman } 6316a2ced3SJonathan Doman 6416a2ced3SJonathan Doman static bool isSleeping(EPECIStatus libStatus, uint8_t completionCode) 6516a2ced3SJonathan Doman { 6616a2ced3SJonathan Doman // PECI completion code defined in peci-ioctl.h which is not available 6716a2ced3SJonathan Doman // for us to include. 6816a2ced3SJonathan Doman constexpr int PECI_DEV_CC_UNAVAIL_RESOURCE = 0x82; 6916a2ced3SJonathan Doman // Observed library returning DRIVER_ERR for reads and TIMEOUT for 7016a2ced3SJonathan Doman // writes while PECI is sleeping. Either way, the completion code from 7116a2ced3SJonathan Doman // PECI client should be reliable indicator of need to set WOP. 7216a2ced3SJonathan Doman return libStatus != PECI_CC_SUCCESS && 7316a2ced3SJonathan Doman completionCode == PECI_DEV_CC_UNAVAIL_RESOURCE; 7416a2ced3SJonathan Doman } 7516a2ced3SJonathan Doman 7616a2ced3SJonathan Doman /** 7716a2ced3SJonathan Doman * Send a single PECI PCS write to modify the Wake-On-PECI mode bit 7816a2ced3SJonathan Doman */ 7916a2ced3SJonathan Doman void setWakeOnPECI(bool enable) 8016a2ced3SJonathan Doman { 8116a2ced3SJonathan Doman uint8_t completionCode; 82*c39d3dfcSPatrick Williams EPECIStatus libStatus = peci_WrPkgConfig(peciAddress, 5, enable ? 1 : 0, 83*c39d3dfcSPatrick Williams 0, sizeof(uint32_t), 84*c39d3dfcSPatrick Williams &completionCode); 8516a2ced3SJonathan Doman if (!checkPECIStatus(libStatus, completionCode)) 8616a2ced3SJonathan Doman { 8716a2ced3SJonathan Doman throw PECIError("Failed to set Wake-On-PECI mode bit"); 8816a2ced3SJonathan Doman } 8916a2ced3SJonathan Doman 9016a2ced3SJonathan Doman if (enable) 9116a2ced3SJonathan Doman { 9216a2ced3SJonathan Doman peciWoken = true; 9316a2ced3SJonathan Doman } 9416a2ced3SJonathan Doman } 9516a2ced3SJonathan Doman 9616a2ced3SJonathan Doman // PCode OS Mailbox interface register locations 9716a2ced3SJonathan Doman static constexpr int mbBusICX = 14; 9816a2ced3SJonathan Doman static constexpr int mbBusOther = 31; 9916a2ced3SJonathan Doman static constexpr int mbSegment = 0; 10016a2ced3SJonathan Doman static constexpr int mbDevice = 30; 10116a2ced3SJonathan Doman static constexpr int mbFunction = 1; 10216a2ced3SJonathan Doman static constexpr int mbDataReg = 0xA0; 10316a2ced3SJonathan Doman static constexpr int mbInterfaceReg = 0xA4; 10416a2ced3SJonathan Doman static constexpr int mbRegSize = sizeof(uint32_t); 10516a2ced3SJonathan Doman 10616a2ced3SJonathan Doman enum class MailboxStatus 10716a2ced3SJonathan Doman { 10816a2ced3SJonathan Doman NoError = 0x0, 10916a2ced3SJonathan Doman InvalidCommand = 0x1, 11016a2ced3SJonathan Doman IllegalData = 0x16 11116a2ced3SJonathan Doman }; 11216a2ced3SJonathan Doman 11316a2ced3SJonathan Doman /** 11416a2ced3SJonathan Doman * Send a single Write PCI Config Local command, targeting the PCU CR1 11516a2ced3SJonathan Doman * register block. 11616a2ced3SJonathan Doman * 11716a2ced3SJonathan Doman * @param[in] regAddress PCI Offset of register. 11816a2ced3SJonathan Doman * @param[in] data Data to write. 11916a2ced3SJonathan Doman */ 12016a2ced3SJonathan Doman void wrMailboxReg(uint16_t regAddress, uint32_t data) 12116a2ced3SJonathan Doman { 12216a2ced3SJonathan Doman uint8_t completionCode; 12316a2ced3SJonathan Doman bool tryWaking = true; 12416a2ced3SJonathan Doman while (true) 12516a2ced3SJonathan Doman { 12616a2ced3SJonathan Doman EPECIStatus libStatus = peci_WrEndPointPCIConfigLocal( 12716a2ced3SJonathan Doman peciAddress, mbSegment, mbBus, mbDevice, mbFunction, regAddress, 12816a2ced3SJonathan Doman mbRegSize, data, &completionCode); 12916a2ced3SJonathan Doman if (tryWaking && isSleeping(libStatus, completionCode)) 13016a2ced3SJonathan Doman { 13116a2ced3SJonathan Doman setWakeOnPECI(true); 13216a2ced3SJonathan Doman tryWaking = false; 13316a2ced3SJonathan Doman continue; 13416a2ced3SJonathan Doman } 13516a2ced3SJonathan Doman else if (!checkPECIStatus(libStatus, completionCode)) 13616a2ced3SJonathan Doman { 13716a2ced3SJonathan Doman throw PECIError("Failed to write mailbox reg"); 13816a2ced3SJonathan Doman } 13916a2ced3SJonathan Doman break; 14016a2ced3SJonathan Doman } 14116a2ced3SJonathan Doman } 14216a2ced3SJonathan Doman 14316a2ced3SJonathan Doman /** 14416a2ced3SJonathan Doman * Send a single Read PCI Config Local command, targeting the PCU CR1 14516a2ced3SJonathan Doman * register block. 14616a2ced3SJonathan Doman * 14716a2ced3SJonathan Doman * @param[in] regAddress PCI offset of register. 14816a2ced3SJonathan Doman * 14916a2ced3SJonathan Doman * @return Register value 15016a2ced3SJonathan Doman */ 15116a2ced3SJonathan Doman uint32_t rdMailboxReg(uint16_t regAddress) 15216a2ced3SJonathan Doman { 15316a2ced3SJonathan Doman uint8_t completionCode; 15416a2ced3SJonathan Doman uint32_t outputData; 15516a2ced3SJonathan Doman bool tryWaking = true; 15616a2ced3SJonathan Doman while (true) 15716a2ced3SJonathan Doman { 15816a2ced3SJonathan Doman EPECIStatus libStatus = peci_RdEndPointConfigPciLocal( 15916a2ced3SJonathan Doman peciAddress, mbSegment, mbBus, mbDevice, mbFunction, regAddress, 16016a2ced3SJonathan Doman mbRegSize, reinterpret_cast<uint8_t*>(&outputData), 16116a2ced3SJonathan Doman &completionCode); 16216a2ced3SJonathan Doman if (tryWaking && isSleeping(libStatus, completionCode)) 16316a2ced3SJonathan Doman { 16416a2ced3SJonathan Doman setWakeOnPECI(true); 16516a2ced3SJonathan Doman tryWaking = false; 16616a2ced3SJonathan Doman continue; 16716a2ced3SJonathan Doman } 16816a2ced3SJonathan Doman if (!checkPECIStatus(libStatus, completionCode)) 16916a2ced3SJonathan Doman { 17016a2ced3SJonathan Doman throw PECIError("Failed to read mailbox reg"); 17116a2ced3SJonathan Doman } 17216a2ced3SJonathan Doman break; 17316a2ced3SJonathan Doman } 17416a2ced3SJonathan Doman return outputData; 17516a2ced3SJonathan Doman } 17616a2ced3SJonathan Doman 17716a2ced3SJonathan Doman /** 17816a2ced3SJonathan Doman * Send command on PCode OS Mailbox interface. 17916a2ced3SJonathan Doman * 18016a2ced3SJonathan Doman * @param[in] command Main command ID. 18116a2ced3SJonathan Doman * @param[in] subCommand Sub command ID. 18216a2ced3SJonathan Doman * @param[in] inputData Data to put in mailbox. Is always written, but 18316a2ced3SJonathan Doman * will be ignored by PCode if command is a 18416a2ced3SJonathan Doman * "getter". 18516a2ced3SJonathan Doman * @param[out] responseCode Optional parameter to receive the 18616a2ced3SJonathan Doman * mailbox-level response status. If null, a 18716a2ced3SJonathan Doman * PECIError will be thrown for error status. 18816a2ced3SJonathan Doman * 18916a2ced3SJonathan Doman * @return Data returned in mailbox. Value is undefined if command is a 19016a2ced3SJonathan Doman * "setter". 19116a2ced3SJonathan Doman */ 19216a2ced3SJonathan Doman uint32_t sendPECIOSMailboxCmd(uint8_t command, uint8_t subCommand, 19316a2ced3SJonathan Doman uint32_t inputData = 0, 19416a2ced3SJonathan Doman MailboxStatus* responseCode = nullptr) 19516a2ced3SJonathan Doman { 19616a2ced3SJonathan Doman // The simple mailbox algorithm just says to wait until the busy bit 19716a2ced3SJonathan Doman // is clear, but we'll give up after 10 tries. It's arbitrary but that's 19816a2ced3SJonathan Doman // quite long wall clock time. 19916a2ced3SJonathan Doman constexpr int mbRetries = 10; 20016a2ced3SJonathan Doman constexpr uint32_t mbBusyBit = bit(31); 20116a2ced3SJonathan Doman 20216a2ced3SJonathan Doman // Wait until RUN_BUSY == 0 20316a2ced3SJonathan Doman int attempts = mbRetries; 20416a2ced3SJonathan Doman while ((rdMailboxReg(mbInterfaceReg) & mbBusyBit) != 0 && 20516a2ced3SJonathan Doman --attempts > 0) 20616a2ced3SJonathan Doman ; 20716a2ced3SJonathan Doman if (attempts == 0) 20816a2ced3SJonathan Doman { 20916a2ced3SJonathan Doman throw PECIError("OS Mailbox failed to become free"); 21016a2ced3SJonathan Doman } 21116a2ced3SJonathan Doman 21216a2ced3SJonathan Doman // Write required command specific input data to data register 21316a2ced3SJonathan Doman wrMailboxReg(mbDataReg, inputData); 21416a2ced3SJonathan Doman 21516a2ced3SJonathan Doman // Write required command specific command/sub-command values and set 21616a2ced3SJonathan Doman // RUN_BUSY bit in interface register. 21716a2ced3SJonathan Doman uint32_t interfaceReg = 21816a2ced3SJonathan Doman mbBusyBit | (static_cast<uint32_t>(subCommand) << 8) | command; 21916a2ced3SJonathan Doman wrMailboxReg(mbInterfaceReg, interfaceReg); 22016a2ced3SJonathan Doman 22116a2ced3SJonathan Doman // Wait until RUN_BUSY == 0 22216a2ced3SJonathan Doman attempts = mbRetries; 22316a2ced3SJonathan Doman do 22416a2ced3SJonathan Doman { 22516a2ced3SJonathan Doman interfaceReg = rdMailboxReg(mbInterfaceReg); 22616a2ced3SJonathan Doman } while ((interfaceReg & mbBusyBit) != 0 && --attempts > 0); 22716a2ced3SJonathan Doman if (attempts == 0) 22816a2ced3SJonathan Doman { 22916a2ced3SJonathan Doman throw PECIError("OS Mailbox failed to return"); 23016a2ced3SJonathan Doman } 23116a2ced3SJonathan Doman 23216a2ced3SJonathan Doman // Read command return status or error code from interface register 23316a2ced3SJonathan Doman auto status = static_cast<MailboxStatus>(interfaceReg & 0xFF); 23416a2ced3SJonathan Doman if (responseCode != nullptr) 23516a2ced3SJonathan Doman { 23616a2ced3SJonathan Doman *responseCode = status; 23716a2ced3SJonathan Doman } 23816a2ced3SJonathan Doman else if (status != MailboxStatus::NoError) 23916a2ced3SJonathan Doman { 24016a2ced3SJonathan Doman throw PECIError(std::string("OS Mailbox returned with error: ") + 24116a2ced3SJonathan Doman std::to_string(static_cast<int>(status))); 24216a2ced3SJonathan Doman } 24316a2ced3SJonathan Doman 24416a2ced3SJonathan Doman // Read command return data from the data register 24516a2ced3SJonathan Doman return rdMailboxReg(mbDataReg); 24616a2ced3SJonathan Doman } 24716a2ced3SJonathan Doman }; 24816a2ced3SJonathan Doman 24916a2ced3SJonathan Doman /** 25016a2ced3SJonathan Doman * Base class for set of PECI OS Mailbox commands. 25116a2ced3SJonathan Doman * Constructing it runs the command and stores the value for use by derived 25216a2ced3SJonathan Doman * class accessor methods. 25316a2ced3SJonathan Doman */ 25416a2ced3SJonathan Doman template <uint8_t subcommand> 25516a2ced3SJonathan Doman struct OsMailboxCommand 25616a2ced3SJonathan Doman { 25716a2ced3SJonathan Doman enum ErrorPolicy 25816a2ced3SJonathan Doman { 25916a2ced3SJonathan Doman Throw, 26016a2ced3SJonathan Doman NoThrow 26116a2ced3SJonathan Doman }; 26216a2ced3SJonathan Doman 26316a2ced3SJonathan Doman uint32_t value; 26416a2ced3SJonathan Doman PECIManager::MailboxStatus status; 26516a2ced3SJonathan Doman /** 26616a2ced3SJonathan Doman * Construct the command object with required PECI address and up to 4 26716a2ced3SJonathan Doman * optional 1-byte input data parameters. 26816a2ced3SJonathan Doman */ 26916a2ced3SJonathan Doman OsMailboxCommand(PECIManager& pm, uint8_t param1 = 0, uint8_t param2 = 0, 27016a2ced3SJonathan Doman uint8_t param3 = 0, uint8_t param4 = 0) : 27116a2ced3SJonathan Doman OsMailboxCommand(pm, ErrorPolicy::Throw, param1, param2, param3, param4) 27216a2ced3SJonathan Doman {} 27316a2ced3SJonathan Doman 27416a2ced3SJonathan Doman OsMailboxCommand(PECIManager& pm, ErrorPolicy errorPolicy, 27516a2ced3SJonathan Doman uint8_t param1 = 0, uint8_t param2 = 0, uint8_t param3 = 0, 27616a2ced3SJonathan Doman uint8_t param4 = 0) 27716a2ced3SJonathan Doman { 27816a2ced3SJonathan Doman DEBUG_PRINT << "Running OS Mailbox command " 27916a2ced3SJonathan Doman << static_cast<int>(subcommand) << '\n'; 280*c39d3dfcSPatrick Williams PECIManager::MailboxStatus* callStatus = errorPolicy == Throw ? nullptr 281*c39d3dfcSPatrick Williams : &status; 28216a2ced3SJonathan Doman uint32_t param = (static_cast<uint32_t>(param4) << 24) | 28316a2ced3SJonathan Doman (static_cast<uint32_t>(param3) << 16) | 28416a2ced3SJonathan Doman (static_cast<uint32_t>(param2) << 8) | param1; 28516a2ced3SJonathan Doman value = pm.sendPECIOSMailboxCmd(0x7F, subcommand, param, callStatus); 28616a2ced3SJonathan Doman } 28716a2ced3SJonathan Doman 28816a2ced3SJonathan Doman /** Return whether the mailbox status indicated success or not. */ 28916a2ced3SJonathan Doman bool success() const 29016a2ced3SJonathan Doman { 29116a2ced3SJonathan Doman return status == PECIManager::MailboxStatus::NoError; 29216a2ced3SJonathan Doman } 29316a2ced3SJonathan Doman }; 29416a2ced3SJonathan Doman 29516a2ced3SJonathan Doman /** 29616a2ced3SJonathan Doman * Macro to define a derived class accessor method. 29716a2ced3SJonathan Doman * 29816a2ced3SJonathan Doman * @param[in] type Return type of accessor method. 29916a2ced3SJonathan Doman * @param[in] name Name of accessor method. 30016a2ced3SJonathan Doman * @param[in] hibit Most significant bit of field to access. 30116a2ced3SJonathan Doman * @param[in] lobit Least significant bit of field to access. 30216a2ced3SJonathan Doman */ 30316a2ced3SJonathan Doman #define FIELD(type, name, hibit, lobit) \ 30416a2ced3SJonathan Doman type name() const \ 30516a2ced3SJonathan Doman { \ 30616a2ced3SJonathan Doman return (value >> lobit) & (bit(hibit - lobit + 1) - 1); \ 30716a2ced3SJonathan Doman } 30816a2ced3SJonathan Doman 30916a2ced3SJonathan Doman struct GetLevelsInfo : OsMailboxCommand<0x0> 31016a2ced3SJonathan Doman { 31116a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 31216a2ced3SJonathan Doman FIELD(bool, enabled, 31, 31) 31316a2ced3SJonathan Doman FIELD(bool, lock, 24, 24) 31416a2ced3SJonathan Doman FIELD(unsigned, currentConfigTdpLevel, 23, 16) 31516a2ced3SJonathan Doman FIELD(unsigned, configTdpLevels, 15, 8) 31616a2ced3SJonathan Doman FIELD(unsigned, version, 7, 0) 31716a2ced3SJonathan Doman }; 31816a2ced3SJonathan Doman 31916a2ced3SJonathan Doman struct GetConfigTdpControl : OsMailboxCommand<0x1> 32016a2ced3SJonathan Doman { 32116a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 32216a2ced3SJonathan Doman FIELD(bool, pbfEnabled, 17, 17); 32316a2ced3SJonathan Doman FIELD(bool, factEnabled, 16, 16); 32416a2ced3SJonathan Doman FIELD(bool, pbfSupport, 1, 1); 32516a2ced3SJonathan Doman FIELD(bool, factSupport, 0, 0); 32616a2ced3SJonathan Doman }; 32716a2ced3SJonathan Doman 32816a2ced3SJonathan Doman struct SetConfigTdpControl : OsMailboxCommand<0x2> 32916a2ced3SJonathan Doman { 33016a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 33116a2ced3SJonathan Doman }; 33216a2ced3SJonathan Doman 33316a2ced3SJonathan Doman struct GetTdpInfo : OsMailboxCommand<0x3> 33416a2ced3SJonathan Doman { 33516a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 33616a2ced3SJonathan Doman FIELD(unsigned, tdpRatio, 23, 16); 33716a2ced3SJonathan Doman FIELD(unsigned, pkgTdp, 14, 0); 33816a2ced3SJonathan Doman }; 33916a2ced3SJonathan Doman 34016a2ced3SJonathan Doman struct GetCoreMask : OsMailboxCommand<0x6> 34116a2ced3SJonathan Doman { 34216a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 34316a2ced3SJonathan Doman FIELD(uint32_t, coresMask, 31, 0); 34416a2ced3SJonathan Doman }; 34516a2ced3SJonathan Doman 34616a2ced3SJonathan Doman struct GetTurboLimitRatios : OsMailboxCommand<0x7> 34716a2ced3SJonathan Doman { 34816a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 34916a2ced3SJonathan Doman }; 35016a2ced3SJonathan Doman 35116a2ced3SJonathan Doman struct SetLevel : OsMailboxCommand<0x8> 35216a2ced3SJonathan Doman { 35316a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 35416a2ced3SJonathan Doman }; 35516a2ced3SJonathan Doman 35616a2ced3SJonathan Doman struct GetRatioInfo : OsMailboxCommand<0xC> 35716a2ced3SJonathan Doman { 35816a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 35916a2ced3SJonathan Doman FIELD(unsigned, pm, 31, 24); 36016a2ced3SJonathan Doman FIELD(unsigned, pn, 23, 16); 36116a2ced3SJonathan Doman FIELD(unsigned, p1, 15, 8); 36216a2ced3SJonathan Doman FIELD(unsigned, p0, 7, 0); 36316a2ced3SJonathan Doman }; 36416a2ced3SJonathan Doman 36516a2ced3SJonathan Doman struct GetTjmaxInfo : OsMailboxCommand<0x5> 36616a2ced3SJonathan Doman { 36716a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 36816a2ced3SJonathan Doman FIELD(unsigned, tProchot, 7, 0); 36916a2ced3SJonathan Doman }; 37016a2ced3SJonathan Doman 37116a2ced3SJonathan Doman struct PbfGetCoreMaskInfo : OsMailboxCommand<0x20> 37216a2ced3SJonathan Doman { 37316a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 37416a2ced3SJonathan Doman FIELD(uint32_t, p1HiCoreMask, 31, 0); 37516a2ced3SJonathan Doman }; 37616a2ced3SJonathan Doman 37716a2ced3SJonathan Doman struct PbfGetP1HiP1LoInfo : OsMailboxCommand<0x21> 37816a2ced3SJonathan Doman { 37916a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 38016a2ced3SJonathan Doman FIELD(unsigned, p1Hi, 15, 8); 38116a2ced3SJonathan Doman FIELD(unsigned, p1Lo, 7, 0); 38216a2ced3SJonathan Doman }; 38316a2ced3SJonathan Doman 38416a2ced3SJonathan Doman /** 38516a2ced3SJonathan Doman * Implementation of SSTInterface based on OS Mailbox interface supported on ICX 38616a2ced3SJonathan Doman * and SPR processors. 38716a2ced3SJonathan Doman * It's expected that an instance of this class will be created for each 38816a2ced3SJonathan Doman * "atomic" set of operations. 38916a2ced3SJonathan Doman */ 39016a2ced3SJonathan Doman class SSTMailbox : public SSTInterface 39116a2ced3SJonathan Doman { 39216a2ced3SJonathan Doman private: 39316a2ced3SJonathan Doman uint8_t address; 39416a2ced3SJonathan Doman CPUModel model; 39516a2ced3SJonathan Doman PECIManager pm; 39616a2ced3SJonathan Doman 39716a2ced3SJonathan Doman static constexpr int mhzPerRatio = 100; 39816a2ced3SJonathan Doman 39916a2ced3SJonathan Doman public: 40016a2ced3SJonathan Doman SSTMailbox(uint8_t _address, CPUModel _model) : 40116a2ced3SJonathan Doman address(_address), model(_model), 40216a2ced3SJonathan Doman pm(static_cast<uint8_t>(address), model) 40316a2ced3SJonathan Doman {} 404*c39d3dfcSPatrick Williams ~SSTMailbox() {} 40516a2ced3SJonathan Doman 40616a2ced3SJonathan Doman bool ready() override 40716a2ced3SJonathan Doman { 40816a2ced3SJonathan Doman return true; 40916a2ced3SJonathan Doman } 41016a2ced3SJonathan Doman 41116a2ced3SJonathan Doman bool supportsControl() override 41216a2ced3SJonathan Doman { 413949f634dSJonathan Doman switch (model) 414949f634dSJonathan Doman { 415949f634dSJonathan Doman case spr: 416949f634dSJonathan Doman case emr: 417949f634dSJonathan Doman return true; 418949f634dSJonathan Doman default: 419949f634dSJonathan Doman return false; 420949f634dSJonathan Doman } 42116a2ced3SJonathan Doman } 42216a2ced3SJonathan Doman 42316a2ced3SJonathan Doman unsigned int currentLevel() override 42416a2ced3SJonathan Doman { 42516a2ced3SJonathan Doman return GetLevelsInfo(pm).currentConfigTdpLevel(); 42616a2ced3SJonathan Doman } 427b4c3bcd7SJonathan Doman unsigned int maxLevel() override 42816a2ced3SJonathan Doman { 42916a2ced3SJonathan Doman return GetLevelsInfo(pm).configTdpLevels(); 43016a2ced3SJonathan Doman } 43116a2ced3SJonathan Doman bool ppEnabled() override 43216a2ced3SJonathan Doman { 43316a2ced3SJonathan Doman return GetLevelsInfo(pm).enabled(); 43416a2ced3SJonathan Doman } 43516a2ced3SJonathan Doman 43616a2ced3SJonathan Doman bool levelSupported(unsigned int level) override 43716a2ced3SJonathan Doman { 43816a2ced3SJonathan Doman GetConfigTdpControl tdpControl( 43916a2ced3SJonathan Doman pm, GetConfigTdpControl::ErrorPolicy::NoThrow, 44016a2ced3SJonathan Doman static_cast<uint8_t>(level)); 44116a2ced3SJonathan Doman return tdpControl.success(); 44216a2ced3SJonathan Doman } 44316a2ced3SJonathan Doman bool bfSupported(unsigned int level) override 44416a2ced3SJonathan Doman { 44516a2ced3SJonathan Doman return GetConfigTdpControl(pm, static_cast<uint8_t>(level)) 44616a2ced3SJonathan Doman .pbfSupport(); 44716a2ced3SJonathan Doman } 44816a2ced3SJonathan Doman bool tfSupported(unsigned int level) override 44916a2ced3SJonathan Doman { 45016a2ced3SJonathan Doman return GetConfigTdpControl(pm, static_cast<uint8_t>(level)) 45116a2ced3SJonathan Doman .factSupport(); 45216a2ced3SJonathan Doman } 45316a2ced3SJonathan Doman bool bfEnabled(unsigned int level) override 45416a2ced3SJonathan Doman { 45516a2ced3SJonathan Doman return GetConfigTdpControl(pm, static_cast<uint8_t>(level)) 45616a2ced3SJonathan Doman .pbfEnabled(); 45716a2ced3SJonathan Doman } 45816a2ced3SJonathan Doman bool tfEnabled(unsigned int level) override 45916a2ced3SJonathan Doman { 46016a2ced3SJonathan Doman return GetConfigTdpControl(pm, static_cast<uint8_t>(level)) 46116a2ced3SJonathan Doman .factEnabled(); 46216a2ced3SJonathan Doman } 46316a2ced3SJonathan Doman unsigned int tdp(unsigned int level) override 46416a2ced3SJonathan Doman { 46516a2ced3SJonathan Doman return GetTdpInfo(pm, static_cast<uint8_t>(level)).pkgTdp(); 46616a2ced3SJonathan Doman } 46716a2ced3SJonathan Doman unsigned int coreCount(unsigned int level) override 46816a2ced3SJonathan Doman { 46916a2ced3SJonathan Doman return enabledCoreList(level).size(); 47016a2ced3SJonathan Doman } 47116a2ced3SJonathan Doman std::vector<unsigned int> enabledCoreList(unsigned int level) override 47216a2ced3SJonathan Doman { 47316a2ced3SJonathan Doman uint64_t coreMaskLo = 47416a2ced3SJonathan Doman GetCoreMask(pm, static_cast<uint8_t>(level), 0).coresMask(); 47516a2ced3SJonathan Doman uint64_t coreMaskHi = 47616a2ced3SJonathan Doman GetCoreMask(pm, static_cast<uint8_t>(level), 1).coresMask(); 47716a2ced3SJonathan Doman std::bitset<64> coreMask = (coreMaskHi << 32 | coreMaskLo); 47816a2ced3SJonathan Doman return convertMaskToList(coreMask); 47916a2ced3SJonathan Doman } 48016a2ced3SJonathan Doman std::vector<TurboEntry> sseTurboProfile(unsigned int level) override 48116a2ced3SJonathan Doman { 48216a2ced3SJonathan Doman // Read the Turbo Ratio Limit Cores MSR which is used to generate the 48316a2ced3SJonathan Doman // Turbo Profile for each profile. This is a package scope MSR, so just 48416a2ced3SJonathan Doman // read thread 0. 48516a2ced3SJonathan Doman uint64_t trlCores; 48616a2ced3SJonathan Doman uint8_t cc; 48716a2ced3SJonathan Doman EPECIStatus status = peci_RdIAMSR(static_cast<uint8_t>(address), 0, 48816a2ced3SJonathan Doman 0x1AE, &trlCores, &cc); 48916a2ced3SJonathan Doman if (!checkPECIStatus(status, cc)) 49016a2ced3SJonathan Doman { 49116a2ced3SJonathan Doman throw PECIError("Failed to read TRL MSR"); 49216a2ced3SJonathan Doman } 49316a2ced3SJonathan Doman 49416a2ced3SJonathan Doman std::vector<TurboEntry> turboSpeeds; 49516a2ced3SJonathan Doman uint64_t limitRatioLo = 49616a2ced3SJonathan Doman GetTurboLimitRatios(pm, static_cast<uint8_t>(level), 0, 0).value; 49716a2ced3SJonathan Doman uint64_t limitRatioHi = 49816a2ced3SJonathan Doman GetTurboLimitRatios(pm, static_cast<uint8_t>(level), 1, 0).value; 49916a2ced3SJonathan Doman uint64_t limitRatios = (limitRatioHi << 32) | limitRatioLo; 50016a2ced3SJonathan Doman 50116a2ced3SJonathan Doman constexpr int maxTFBuckets = 8; 50216a2ced3SJonathan Doman for (int i = 0; i < maxTFBuckets; ++i) 50316a2ced3SJonathan Doman { 50416a2ced3SJonathan Doman size_t bucketCount = trlCores & 0xFF; 50516a2ced3SJonathan Doman int bucketSpeed = limitRatios & 0xFF; 50616a2ced3SJonathan Doman if (bucketCount != 0 && bucketSpeed != 0) 50716a2ced3SJonathan Doman { 50816a2ced3SJonathan Doman turboSpeeds.push_back({bucketSpeed * mhzPerRatio, bucketCount}); 50916a2ced3SJonathan Doman } 51016a2ced3SJonathan Doman 51116a2ced3SJonathan Doman trlCores >>= 8; 51216a2ced3SJonathan Doman limitRatios >>= 8; 51316a2ced3SJonathan Doman } 51416a2ced3SJonathan Doman return turboSpeeds; 51516a2ced3SJonathan Doman } 51616a2ced3SJonathan Doman unsigned int p1Freq(unsigned int level) override 51716a2ced3SJonathan Doman { 51816a2ced3SJonathan Doman return GetRatioInfo(pm, static_cast<uint8_t>(level)).p1() * mhzPerRatio; 51916a2ced3SJonathan Doman } 52016a2ced3SJonathan Doman unsigned int p0Freq(unsigned int level) override 52116a2ced3SJonathan Doman { 52216a2ced3SJonathan Doman return GetRatioInfo(pm, static_cast<uint8_t>(level)).p0() * mhzPerRatio; 52316a2ced3SJonathan Doman } 52416a2ced3SJonathan Doman unsigned int prochotTemp(unsigned int level) override 52516a2ced3SJonathan Doman { 52616a2ced3SJonathan Doman return GetTjmaxInfo(pm, static_cast<uint8_t>(level)).tProchot(); 52716a2ced3SJonathan Doman } 52816a2ced3SJonathan Doman std::vector<unsigned int> 52916a2ced3SJonathan Doman bfHighPriorityCoreList(unsigned int level) override 53016a2ced3SJonathan Doman { 531*c39d3dfcSPatrick Williams uint64_t coreMaskLo = PbfGetCoreMaskInfo(pm, 532*c39d3dfcSPatrick Williams static_cast<uint8_t>(level), 0) 53316a2ced3SJonathan Doman .p1HiCoreMask(); 534*c39d3dfcSPatrick Williams uint64_t coreMaskHi = PbfGetCoreMaskInfo(pm, 535*c39d3dfcSPatrick Williams static_cast<uint8_t>(level), 1) 53616a2ced3SJonathan Doman .p1HiCoreMask(); 53716a2ced3SJonathan Doman std::bitset<64> hiFreqCoreList = (coreMaskHi << 32) | coreMaskLo; 53816a2ced3SJonathan Doman return convertMaskToList(hiFreqCoreList); 53916a2ced3SJonathan Doman } 54016a2ced3SJonathan Doman unsigned int bfHighPriorityFreq(unsigned int level) override 54116a2ced3SJonathan Doman { 54216a2ced3SJonathan Doman return PbfGetP1HiP1LoInfo(pm, static_cast<uint8_t>(level)).p1Hi() * 54316a2ced3SJonathan Doman mhzPerRatio; 54416a2ced3SJonathan Doman } 54516a2ced3SJonathan Doman unsigned int bfLowPriorityFreq(unsigned int level) override 54616a2ced3SJonathan Doman { 54716a2ced3SJonathan Doman return PbfGetP1HiP1LoInfo(pm, static_cast<uint8_t>(level)).p1Lo() * 54816a2ced3SJonathan Doman mhzPerRatio; 54916a2ced3SJonathan Doman } 55016a2ced3SJonathan Doman 55116a2ced3SJonathan Doman void setBfEnabled(bool enable) override 55216a2ced3SJonathan Doman { 55316a2ced3SJonathan Doman GetConfigTdpControl getTDPControl(pm); 55416a2ced3SJonathan Doman bool tfEnabled = false; 55516a2ced3SJonathan Doman uint8_t param = (enable ? bit(1) : 0) | (tfEnabled ? bit(0) : 0); 55616a2ced3SJonathan Doman SetConfigTdpControl(pm, 0, 0, param); 55716a2ced3SJonathan Doman } 55816a2ced3SJonathan Doman void setTfEnabled(bool enable) override 55916a2ced3SJonathan Doman { 56016a2ced3SJonathan Doman // TODO: use cached BF value 56116a2ced3SJonathan Doman bool bfEnabled = false; 56216a2ced3SJonathan Doman uint8_t param = (bfEnabled ? bit(1) : 0) | (enable ? bit(0) : 0); 56316a2ced3SJonathan Doman SetConfigTdpControl(pm, 0, 0, param); 56416a2ced3SJonathan Doman } 56516a2ced3SJonathan Doman void setCurrentLevel(unsigned int level) override 56616a2ced3SJonathan Doman { 56716a2ced3SJonathan Doman SetLevel(pm, static_cast<uint8_t>(level)); 56816a2ced3SJonathan Doman } 56916a2ced3SJonathan Doman }; 57016a2ced3SJonathan Doman 57116a2ced3SJonathan Doman static std::unique_ptr<SSTInterface> createMailbox(uint8_t address, 57216a2ced3SJonathan Doman CPUModel model) 57316a2ced3SJonathan Doman { 57416a2ced3SJonathan Doman DEBUG_PRINT << "createMailbox\n"; 575949f634dSJonathan Doman switch (model) 57616a2ced3SJonathan Doman { 577949f634dSJonathan Doman case icx: 578949f634dSJonathan Doman case icxd: 579949f634dSJonathan Doman case spr: 580949f634dSJonathan Doman case emr: 58116a2ced3SJonathan Doman return std::make_unique<SSTMailbox>(address, model); 582949f634dSJonathan Doman default: 58316a2ced3SJonathan Doman return nullptr; 58416a2ced3SJonathan Doman } 585949f634dSJonathan Doman } 58616a2ced3SJonathan Doman 58716a2ced3SJonathan Doman SSTProviderRegistration(createMailbox); 58816a2ced3SJonathan Doman 58916a2ced3SJonathan Doman } // namespace sst 59016a2ced3SJonathan Doman } // namespace cpu_info 591