1*16a2ced3SJonathan Doman // Copyright (c) 2022 Intel Corporation 2*16a2ced3SJonathan Doman // 3*16a2ced3SJonathan Doman // Licensed under the Apache License, Version 2.0 (the "License"); 4*16a2ced3SJonathan Doman // you may not use this file except in compliance with the License. 5*16a2ced3SJonathan Doman // You may obtain a copy of the License at 6*16a2ced3SJonathan Doman // 7*16a2ced3SJonathan Doman // http://www.apache.org/licenses/LICENSE-2.0 8*16a2ced3SJonathan Doman // 9*16a2ced3SJonathan Doman // Unless required by applicable law or agreed to in writing, software 10*16a2ced3SJonathan Doman // distributed under the License is distributed on an "AS IS" BASIS, 11*16a2ced3SJonathan Doman // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*16a2ced3SJonathan Doman // See the License for the specific language governing permissions and 13*16a2ced3SJonathan Doman // limitations under the License. 14*16a2ced3SJonathan Doman 15*16a2ced3SJonathan Doman #include "cpuinfo_utils.hpp" 16*16a2ced3SJonathan Doman #include "speed_select.hpp" 17*16a2ced3SJonathan Doman 18*16a2ced3SJonathan Doman #include <iostream> 19*16a2ced3SJonathan Doman 20*16a2ced3SJonathan Doman namespace cpu_info 21*16a2ced3SJonathan Doman { 22*16a2ced3SJonathan Doman namespace sst 23*16a2ced3SJonathan Doman { 24*16a2ced3SJonathan Doman 25*16a2ced3SJonathan Doman /** 26*16a2ced3SJonathan Doman * Convenience RAII object for Wake-On-PECI (WOP) management, since PECI Config 27*16a2ced3SJonathan Doman * Local accesses to the OS Mailbox require the package to pop up to PC2. Also 28*16a2ced3SJonathan Doman * provides PCode OS Mailbox routine. 29*16a2ced3SJonathan Doman * 30*16a2ced3SJonathan Doman * Since multiple applications may be modifing WOP, we'll use this algorithm: 31*16a2ced3SJonathan Doman * Whenever a PECI command fails with associated error code, set WOP bit and 32*16a2ced3SJonathan Doman * retry command. Upon manager destruction, clear WOP bit only if we previously 33*16a2ced3SJonathan Doman * set it. 34*16a2ced3SJonathan Doman */ 35*16a2ced3SJonathan Doman struct PECIManager 36*16a2ced3SJonathan Doman { 37*16a2ced3SJonathan Doman uint8_t peciAddress; 38*16a2ced3SJonathan Doman bool peciWoken; 39*16a2ced3SJonathan Doman CPUModel cpuModel; 40*16a2ced3SJonathan Doman uint8_t mbBus; 41*16a2ced3SJonathan Doman 42*16a2ced3SJonathan Doman PECIManager(uint8_t address, CPUModel model) : 43*16a2ced3SJonathan Doman peciAddress(address), peciWoken(false), cpuModel(model) 44*16a2ced3SJonathan Doman { 45*16a2ced3SJonathan Doman mbBus = (model == icx) ? mbBusICX : mbBusOther; 46*16a2ced3SJonathan Doman } 47*16a2ced3SJonathan Doman 48*16a2ced3SJonathan Doman ~PECIManager() 49*16a2ced3SJonathan Doman { 50*16a2ced3SJonathan Doman // If we're being destroyed due to a PECIError, try to clear the mode 51*16a2ced3SJonathan Doman // bit, but catch and ignore any duplicate error it might raise to 52*16a2ced3SJonathan Doman // prevent termination. 53*16a2ced3SJonathan Doman try 54*16a2ced3SJonathan Doman { 55*16a2ced3SJonathan Doman if (peciWoken) 56*16a2ced3SJonathan Doman { 57*16a2ced3SJonathan Doman setWakeOnPECI(false); 58*16a2ced3SJonathan Doman } 59*16a2ced3SJonathan Doman } 60*16a2ced3SJonathan Doman catch (const PECIError& err) 61*16a2ced3SJonathan Doman {} 62*16a2ced3SJonathan Doman } 63*16a2ced3SJonathan Doman 64*16a2ced3SJonathan Doman static bool isSleeping(EPECIStatus libStatus, uint8_t completionCode) 65*16a2ced3SJonathan Doman { 66*16a2ced3SJonathan Doman // PECI completion code defined in peci-ioctl.h which is not available 67*16a2ced3SJonathan Doman // for us to include. 68*16a2ced3SJonathan Doman constexpr int PECI_DEV_CC_UNAVAIL_RESOURCE = 0x82; 69*16a2ced3SJonathan Doman // Observed library returning DRIVER_ERR for reads and TIMEOUT for 70*16a2ced3SJonathan Doman // writes while PECI is sleeping. Either way, the completion code from 71*16a2ced3SJonathan Doman // PECI client should be reliable indicator of need to set WOP. 72*16a2ced3SJonathan Doman return libStatus != PECI_CC_SUCCESS && 73*16a2ced3SJonathan Doman completionCode == PECI_DEV_CC_UNAVAIL_RESOURCE; 74*16a2ced3SJonathan Doman } 75*16a2ced3SJonathan Doman 76*16a2ced3SJonathan Doman /** 77*16a2ced3SJonathan Doman * Send a single PECI PCS write to modify the Wake-On-PECI mode bit 78*16a2ced3SJonathan Doman */ 79*16a2ced3SJonathan Doman void setWakeOnPECI(bool enable) 80*16a2ced3SJonathan Doman { 81*16a2ced3SJonathan Doman uint8_t completionCode; 82*16a2ced3SJonathan Doman EPECIStatus libStatus = 83*16a2ced3SJonathan Doman peci_WrPkgConfig(peciAddress, 5, enable ? 1 : 0, 0, 84*16a2ced3SJonathan Doman sizeof(uint32_t), &completionCode); 85*16a2ced3SJonathan Doman if (!checkPECIStatus(libStatus, completionCode)) 86*16a2ced3SJonathan Doman { 87*16a2ced3SJonathan Doman throw PECIError("Failed to set Wake-On-PECI mode bit"); 88*16a2ced3SJonathan Doman } 89*16a2ced3SJonathan Doman 90*16a2ced3SJonathan Doman if (enable) 91*16a2ced3SJonathan Doman { 92*16a2ced3SJonathan Doman peciWoken = true; 93*16a2ced3SJonathan Doman } 94*16a2ced3SJonathan Doman } 95*16a2ced3SJonathan Doman 96*16a2ced3SJonathan Doman // PCode OS Mailbox interface register locations 97*16a2ced3SJonathan Doman static constexpr int mbBusICX = 14; 98*16a2ced3SJonathan Doman static constexpr int mbBusOther = 31; 99*16a2ced3SJonathan Doman static constexpr int mbSegment = 0; 100*16a2ced3SJonathan Doman static constexpr int mbDevice = 30; 101*16a2ced3SJonathan Doman static constexpr int mbFunction = 1; 102*16a2ced3SJonathan Doman static constexpr int mbDataReg = 0xA0; 103*16a2ced3SJonathan Doman static constexpr int mbInterfaceReg = 0xA4; 104*16a2ced3SJonathan Doman static constexpr int mbRegSize = sizeof(uint32_t); 105*16a2ced3SJonathan Doman 106*16a2ced3SJonathan Doman enum class MailboxStatus 107*16a2ced3SJonathan Doman { 108*16a2ced3SJonathan Doman NoError = 0x0, 109*16a2ced3SJonathan Doman InvalidCommand = 0x1, 110*16a2ced3SJonathan Doman IllegalData = 0x16 111*16a2ced3SJonathan Doman }; 112*16a2ced3SJonathan Doman 113*16a2ced3SJonathan Doman /** 114*16a2ced3SJonathan Doman * Send a single Write PCI Config Local command, targeting the PCU CR1 115*16a2ced3SJonathan Doman * register block. 116*16a2ced3SJonathan Doman * 117*16a2ced3SJonathan Doman * @param[in] regAddress PCI Offset of register. 118*16a2ced3SJonathan Doman * @param[in] data Data to write. 119*16a2ced3SJonathan Doman */ 120*16a2ced3SJonathan Doman void wrMailboxReg(uint16_t regAddress, uint32_t data) 121*16a2ced3SJonathan Doman { 122*16a2ced3SJonathan Doman uint8_t completionCode; 123*16a2ced3SJonathan Doman bool tryWaking = true; 124*16a2ced3SJonathan Doman while (true) 125*16a2ced3SJonathan Doman { 126*16a2ced3SJonathan Doman EPECIStatus libStatus = peci_WrEndPointPCIConfigLocal( 127*16a2ced3SJonathan Doman peciAddress, mbSegment, mbBus, mbDevice, mbFunction, regAddress, 128*16a2ced3SJonathan Doman mbRegSize, data, &completionCode); 129*16a2ced3SJonathan Doman if (tryWaking && isSleeping(libStatus, completionCode)) 130*16a2ced3SJonathan Doman { 131*16a2ced3SJonathan Doman setWakeOnPECI(true); 132*16a2ced3SJonathan Doman tryWaking = false; 133*16a2ced3SJonathan Doman continue; 134*16a2ced3SJonathan Doman } 135*16a2ced3SJonathan Doman else if (!checkPECIStatus(libStatus, completionCode)) 136*16a2ced3SJonathan Doman { 137*16a2ced3SJonathan Doman throw PECIError("Failed to write mailbox reg"); 138*16a2ced3SJonathan Doman } 139*16a2ced3SJonathan Doman break; 140*16a2ced3SJonathan Doman } 141*16a2ced3SJonathan Doman } 142*16a2ced3SJonathan Doman 143*16a2ced3SJonathan Doman /** 144*16a2ced3SJonathan Doman * Send a single Read PCI Config Local command, targeting the PCU CR1 145*16a2ced3SJonathan Doman * register block. 146*16a2ced3SJonathan Doman * 147*16a2ced3SJonathan Doman * @param[in] regAddress PCI offset of register. 148*16a2ced3SJonathan Doman * 149*16a2ced3SJonathan Doman * @return Register value 150*16a2ced3SJonathan Doman */ 151*16a2ced3SJonathan Doman uint32_t rdMailboxReg(uint16_t regAddress) 152*16a2ced3SJonathan Doman { 153*16a2ced3SJonathan Doman uint8_t completionCode; 154*16a2ced3SJonathan Doman uint32_t outputData; 155*16a2ced3SJonathan Doman bool tryWaking = true; 156*16a2ced3SJonathan Doman while (true) 157*16a2ced3SJonathan Doman { 158*16a2ced3SJonathan Doman EPECIStatus libStatus = peci_RdEndPointConfigPciLocal( 159*16a2ced3SJonathan Doman peciAddress, mbSegment, mbBus, mbDevice, mbFunction, regAddress, 160*16a2ced3SJonathan Doman mbRegSize, reinterpret_cast<uint8_t*>(&outputData), 161*16a2ced3SJonathan Doman &completionCode); 162*16a2ced3SJonathan Doman if (tryWaking && isSleeping(libStatus, completionCode)) 163*16a2ced3SJonathan Doman { 164*16a2ced3SJonathan Doman setWakeOnPECI(true); 165*16a2ced3SJonathan Doman tryWaking = false; 166*16a2ced3SJonathan Doman continue; 167*16a2ced3SJonathan Doman } 168*16a2ced3SJonathan Doman if (!checkPECIStatus(libStatus, completionCode)) 169*16a2ced3SJonathan Doman { 170*16a2ced3SJonathan Doman throw PECIError("Failed to read mailbox reg"); 171*16a2ced3SJonathan Doman } 172*16a2ced3SJonathan Doman break; 173*16a2ced3SJonathan Doman } 174*16a2ced3SJonathan Doman return outputData; 175*16a2ced3SJonathan Doman } 176*16a2ced3SJonathan Doman 177*16a2ced3SJonathan Doman /** 178*16a2ced3SJonathan Doman * Send command on PCode OS Mailbox interface. 179*16a2ced3SJonathan Doman * 180*16a2ced3SJonathan Doman * @param[in] command Main command ID. 181*16a2ced3SJonathan Doman * @param[in] subCommand Sub command ID. 182*16a2ced3SJonathan Doman * @param[in] inputData Data to put in mailbox. Is always written, but 183*16a2ced3SJonathan Doman * will be ignored by PCode if command is a 184*16a2ced3SJonathan Doman * "getter". 185*16a2ced3SJonathan Doman * @param[out] responseCode Optional parameter to receive the 186*16a2ced3SJonathan Doman * mailbox-level response status. If null, a 187*16a2ced3SJonathan Doman * PECIError will be thrown for error status. 188*16a2ced3SJonathan Doman * 189*16a2ced3SJonathan Doman * @return Data returned in mailbox. Value is undefined if command is a 190*16a2ced3SJonathan Doman * "setter". 191*16a2ced3SJonathan Doman */ 192*16a2ced3SJonathan Doman uint32_t sendPECIOSMailboxCmd(uint8_t command, uint8_t subCommand, 193*16a2ced3SJonathan Doman uint32_t inputData = 0, 194*16a2ced3SJonathan Doman MailboxStatus* responseCode = nullptr) 195*16a2ced3SJonathan Doman { 196*16a2ced3SJonathan Doman // The simple mailbox algorithm just says to wait until the busy bit 197*16a2ced3SJonathan Doman // is clear, but we'll give up after 10 tries. It's arbitrary but that's 198*16a2ced3SJonathan Doman // quite long wall clock time. 199*16a2ced3SJonathan Doman constexpr int mbRetries = 10; 200*16a2ced3SJonathan Doman constexpr uint32_t mbBusyBit = bit(31); 201*16a2ced3SJonathan Doman 202*16a2ced3SJonathan Doman // Wait until RUN_BUSY == 0 203*16a2ced3SJonathan Doman int attempts = mbRetries; 204*16a2ced3SJonathan Doman while ((rdMailboxReg(mbInterfaceReg) & mbBusyBit) != 0 && 205*16a2ced3SJonathan Doman --attempts > 0) 206*16a2ced3SJonathan Doman ; 207*16a2ced3SJonathan Doman if (attempts == 0) 208*16a2ced3SJonathan Doman { 209*16a2ced3SJonathan Doman throw PECIError("OS Mailbox failed to become free"); 210*16a2ced3SJonathan Doman } 211*16a2ced3SJonathan Doman 212*16a2ced3SJonathan Doman // Write required command specific input data to data register 213*16a2ced3SJonathan Doman wrMailboxReg(mbDataReg, inputData); 214*16a2ced3SJonathan Doman 215*16a2ced3SJonathan Doman // Write required command specific command/sub-command values and set 216*16a2ced3SJonathan Doman // RUN_BUSY bit in interface register. 217*16a2ced3SJonathan Doman uint32_t interfaceReg = 218*16a2ced3SJonathan Doman mbBusyBit | (static_cast<uint32_t>(subCommand) << 8) | command; 219*16a2ced3SJonathan Doman wrMailboxReg(mbInterfaceReg, interfaceReg); 220*16a2ced3SJonathan Doman 221*16a2ced3SJonathan Doman // Wait until RUN_BUSY == 0 222*16a2ced3SJonathan Doman attempts = mbRetries; 223*16a2ced3SJonathan Doman do 224*16a2ced3SJonathan Doman { 225*16a2ced3SJonathan Doman interfaceReg = rdMailboxReg(mbInterfaceReg); 226*16a2ced3SJonathan Doman } while ((interfaceReg & mbBusyBit) != 0 && --attempts > 0); 227*16a2ced3SJonathan Doman if (attempts == 0) 228*16a2ced3SJonathan Doman { 229*16a2ced3SJonathan Doman throw PECIError("OS Mailbox failed to return"); 230*16a2ced3SJonathan Doman } 231*16a2ced3SJonathan Doman 232*16a2ced3SJonathan Doman // Read command return status or error code from interface register 233*16a2ced3SJonathan Doman auto status = static_cast<MailboxStatus>(interfaceReg & 0xFF); 234*16a2ced3SJonathan Doman if (responseCode != nullptr) 235*16a2ced3SJonathan Doman { 236*16a2ced3SJonathan Doman *responseCode = status; 237*16a2ced3SJonathan Doman } 238*16a2ced3SJonathan Doman else if (status != MailboxStatus::NoError) 239*16a2ced3SJonathan Doman { 240*16a2ced3SJonathan Doman throw PECIError(std::string("OS Mailbox returned with error: ") + 241*16a2ced3SJonathan Doman std::to_string(static_cast<int>(status))); 242*16a2ced3SJonathan Doman } 243*16a2ced3SJonathan Doman 244*16a2ced3SJonathan Doman // Read command return data from the data register 245*16a2ced3SJonathan Doman return rdMailboxReg(mbDataReg); 246*16a2ced3SJonathan Doman } 247*16a2ced3SJonathan Doman }; 248*16a2ced3SJonathan Doman 249*16a2ced3SJonathan Doman /** 250*16a2ced3SJonathan Doman * Base class for set of PECI OS Mailbox commands. 251*16a2ced3SJonathan Doman * Constructing it runs the command and stores the value for use by derived 252*16a2ced3SJonathan Doman * class accessor methods. 253*16a2ced3SJonathan Doman */ 254*16a2ced3SJonathan Doman template <uint8_t subcommand> 255*16a2ced3SJonathan Doman struct OsMailboxCommand 256*16a2ced3SJonathan Doman { 257*16a2ced3SJonathan Doman enum ErrorPolicy 258*16a2ced3SJonathan Doman { 259*16a2ced3SJonathan Doman Throw, 260*16a2ced3SJonathan Doman NoThrow 261*16a2ced3SJonathan Doman }; 262*16a2ced3SJonathan Doman 263*16a2ced3SJonathan Doman uint32_t value; 264*16a2ced3SJonathan Doman PECIManager::MailboxStatus status; 265*16a2ced3SJonathan Doman /** 266*16a2ced3SJonathan Doman * Construct the command object with required PECI address and up to 4 267*16a2ced3SJonathan Doman * optional 1-byte input data parameters. 268*16a2ced3SJonathan Doman */ 269*16a2ced3SJonathan Doman OsMailboxCommand(PECIManager& pm, uint8_t param1 = 0, uint8_t param2 = 0, 270*16a2ced3SJonathan Doman uint8_t param3 = 0, uint8_t param4 = 0) : 271*16a2ced3SJonathan Doman OsMailboxCommand(pm, ErrorPolicy::Throw, param1, param2, param3, param4) 272*16a2ced3SJonathan Doman {} 273*16a2ced3SJonathan Doman 274*16a2ced3SJonathan Doman OsMailboxCommand(PECIManager& pm, ErrorPolicy errorPolicy, 275*16a2ced3SJonathan Doman uint8_t param1 = 0, uint8_t param2 = 0, uint8_t param3 = 0, 276*16a2ced3SJonathan Doman uint8_t param4 = 0) 277*16a2ced3SJonathan Doman { 278*16a2ced3SJonathan Doman DEBUG_PRINT << "Running OS Mailbox command " 279*16a2ced3SJonathan Doman << static_cast<int>(subcommand) << '\n'; 280*16a2ced3SJonathan Doman PECIManager::MailboxStatus* callStatus = 281*16a2ced3SJonathan Doman errorPolicy == Throw ? nullptr : &status; 282*16a2ced3SJonathan Doman uint32_t param = (static_cast<uint32_t>(param4) << 24) | 283*16a2ced3SJonathan Doman (static_cast<uint32_t>(param3) << 16) | 284*16a2ced3SJonathan Doman (static_cast<uint32_t>(param2) << 8) | param1; 285*16a2ced3SJonathan Doman value = pm.sendPECIOSMailboxCmd(0x7F, subcommand, param, callStatus); 286*16a2ced3SJonathan Doman } 287*16a2ced3SJonathan Doman 288*16a2ced3SJonathan Doman /** Return whether the mailbox status indicated success or not. */ 289*16a2ced3SJonathan Doman bool success() const 290*16a2ced3SJonathan Doman { 291*16a2ced3SJonathan Doman return status == PECIManager::MailboxStatus::NoError; 292*16a2ced3SJonathan Doman } 293*16a2ced3SJonathan Doman }; 294*16a2ced3SJonathan Doman 295*16a2ced3SJonathan Doman /** 296*16a2ced3SJonathan Doman * Macro to define a derived class accessor method. 297*16a2ced3SJonathan Doman * 298*16a2ced3SJonathan Doman * @param[in] type Return type of accessor method. 299*16a2ced3SJonathan Doman * @param[in] name Name of accessor method. 300*16a2ced3SJonathan Doman * @param[in] hibit Most significant bit of field to access. 301*16a2ced3SJonathan Doman * @param[in] lobit Least significant bit of field to access. 302*16a2ced3SJonathan Doman */ 303*16a2ced3SJonathan Doman #define FIELD(type, name, hibit, lobit) \ 304*16a2ced3SJonathan Doman type name() const \ 305*16a2ced3SJonathan Doman { \ 306*16a2ced3SJonathan Doman return (value >> lobit) & (bit(hibit - lobit + 1) - 1); \ 307*16a2ced3SJonathan Doman } 308*16a2ced3SJonathan Doman 309*16a2ced3SJonathan Doman struct GetLevelsInfo : OsMailboxCommand<0x0> 310*16a2ced3SJonathan Doman { 311*16a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 312*16a2ced3SJonathan Doman FIELD(bool, enabled, 31, 31) 313*16a2ced3SJonathan Doman FIELD(bool, lock, 24, 24) 314*16a2ced3SJonathan Doman FIELD(unsigned, currentConfigTdpLevel, 23, 16) 315*16a2ced3SJonathan Doman FIELD(unsigned, configTdpLevels, 15, 8) 316*16a2ced3SJonathan Doman FIELD(unsigned, version, 7, 0) 317*16a2ced3SJonathan Doman }; 318*16a2ced3SJonathan Doman 319*16a2ced3SJonathan Doman struct GetConfigTdpControl : OsMailboxCommand<0x1> 320*16a2ced3SJonathan Doman { 321*16a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 322*16a2ced3SJonathan Doman FIELD(bool, pbfEnabled, 17, 17); 323*16a2ced3SJonathan Doman FIELD(bool, factEnabled, 16, 16); 324*16a2ced3SJonathan Doman FIELD(bool, pbfSupport, 1, 1); 325*16a2ced3SJonathan Doman FIELD(bool, factSupport, 0, 0); 326*16a2ced3SJonathan Doman }; 327*16a2ced3SJonathan Doman 328*16a2ced3SJonathan Doman struct SetConfigTdpControl : OsMailboxCommand<0x2> 329*16a2ced3SJonathan Doman { 330*16a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 331*16a2ced3SJonathan Doman }; 332*16a2ced3SJonathan Doman 333*16a2ced3SJonathan Doman struct GetTdpInfo : OsMailboxCommand<0x3> 334*16a2ced3SJonathan Doman { 335*16a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 336*16a2ced3SJonathan Doman FIELD(unsigned, tdpRatio, 23, 16); 337*16a2ced3SJonathan Doman FIELD(unsigned, pkgTdp, 14, 0); 338*16a2ced3SJonathan Doman }; 339*16a2ced3SJonathan Doman 340*16a2ced3SJonathan Doman struct GetCoreMask : OsMailboxCommand<0x6> 341*16a2ced3SJonathan Doman { 342*16a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 343*16a2ced3SJonathan Doman FIELD(uint32_t, coresMask, 31, 0); 344*16a2ced3SJonathan Doman }; 345*16a2ced3SJonathan Doman 346*16a2ced3SJonathan Doman struct GetTurboLimitRatios : OsMailboxCommand<0x7> 347*16a2ced3SJonathan Doman { 348*16a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 349*16a2ced3SJonathan Doman }; 350*16a2ced3SJonathan Doman 351*16a2ced3SJonathan Doman struct SetLevel : OsMailboxCommand<0x8> 352*16a2ced3SJonathan Doman { 353*16a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 354*16a2ced3SJonathan Doman }; 355*16a2ced3SJonathan Doman 356*16a2ced3SJonathan Doman struct GetRatioInfo : OsMailboxCommand<0xC> 357*16a2ced3SJonathan Doman { 358*16a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 359*16a2ced3SJonathan Doman FIELD(unsigned, pm, 31, 24); 360*16a2ced3SJonathan Doman FIELD(unsigned, pn, 23, 16); 361*16a2ced3SJonathan Doman FIELD(unsigned, p1, 15, 8); 362*16a2ced3SJonathan Doman FIELD(unsigned, p0, 7, 0); 363*16a2ced3SJonathan Doman }; 364*16a2ced3SJonathan Doman 365*16a2ced3SJonathan Doman struct GetTjmaxInfo : OsMailboxCommand<0x5> 366*16a2ced3SJonathan Doman { 367*16a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 368*16a2ced3SJonathan Doman FIELD(unsigned, tProchot, 7, 0); 369*16a2ced3SJonathan Doman }; 370*16a2ced3SJonathan Doman 371*16a2ced3SJonathan Doman struct PbfGetCoreMaskInfo : OsMailboxCommand<0x20> 372*16a2ced3SJonathan Doman { 373*16a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 374*16a2ced3SJonathan Doman FIELD(uint32_t, p1HiCoreMask, 31, 0); 375*16a2ced3SJonathan Doman }; 376*16a2ced3SJonathan Doman 377*16a2ced3SJonathan Doman struct PbfGetP1HiP1LoInfo : OsMailboxCommand<0x21> 378*16a2ced3SJonathan Doman { 379*16a2ced3SJonathan Doman using OsMailboxCommand::OsMailboxCommand; 380*16a2ced3SJonathan Doman FIELD(unsigned, p1Hi, 15, 8); 381*16a2ced3SJonathan Doman FIELD(unsigned, p1Lo, 7, 0); 382*16a2ced3SJonathan Doman }; 383*16a2ced3SJonathan Doman 384*16a2ced3SJonathan Doman /** 385*16a2ced3SJonathan Doman * Implementation of SSTInterface based on OS Mailbox interface supported on ICX 386*16a2ced3SJonathan Doman * and SPR processors. 387*16a2ced3SJonathan Doman * It's expected that an instance of this class will be created for each 388*16a2ced3SJonathan Doman * "atomic" set of operations. 389*16a2ced3SJonathan Doman */ 390*16a2ced3SJonathan Doman class SSTMailbox : public SSTInterface 391*16a2ced3SJonathan Doman { 392*16a2ced3SJonathan Doman private: 393*16a2ced3SJonathan Doman uint8_t address; 394*16a2ced3SJonathan Doman CPUModel model; 395*16a2ced3SJonathan Doman PECIManager pm; 396*16a2ced3SJonathan Doman 397*16a2ced3SJonathan Doman static constexpr int mhzPerRatio = 100; 398*16a2ced3SJonathan Doman 399*16a2ced3SJonathan Doman public: 400*16a2ced3SJonathan Doman SSTMailbox(uint8_t _address, CPUModel _model) : 401*16a2ced3SJonathan Doman address(_address), model(_model), 402*16a2ced3SJonathan Doman pm(static_cast<uint8_t>(address), model) 403*16a2ced3SJonathan Doman {} 404*16a2ced3SJonathan Doman ~SSTMailbox() 405*16a2ced3SJonathan Doman {} 406*16a2ced3SJonathan Doman 407*16a2ced3SJonathan Doman bool ready() override 408*16a2ced3SJonathan Doman { 409*16a2ced3SJonathan Doman return true; 410*16a2ced3SJonathan Doman } 411*16a2ced3SJonathan Doman 412*16a2ced3SJonathan Doman bool supportsControl() override 413*16a2ced3SJonathan Doman { 414*16a2ced3SJonathan Doman return model == spr; 415*16a2ced3SJonathan Doman } 416*16a2ced3SJonathan Doman 417*16a2ced3SJonathan Doman unsigned int currentLevel() override 418*16a2ced3SJonathan Doman { 419*16a2ced3SJonathan Doman return GetLevelsInfo(pm).currentConfigTdpLevel(); 420*16a2ced3SJonathan Doman } 421*16a2ced3SJonathan Doman unsigned int numLevels() override 422*16a2ced3SJonathan Doman { 423*16a2ced3SJonathan Doman return GetLevelsInfo(pm).configTdpLevels(); 424*16a2ced3SJonathan Doman } 425*16a2ced3SJonathan Doman bool ppEnabled() override 426*16a2ced3SJonathan Doman { 427*16a2ced3SJonathan Doman return GetLevelsInfo(pm).enabled(); 428*16a2ced3SJonathan Doman } 429*16a2ced3SJonathan Doman 430*16a2ced3SJonathan Doman bool levelSupported(unsigned int level) override 431*16a2ced3SJonathan Doman { 432*16a2ced3SJonathan Doman GetConfigTdpControl tdpControl( 433*16a2ced3SJonathan Doman pm, GetConfigTdpControl::ErrorPolicy::NoThrow, 434*16a2ced3SJonathan Doman static_cast<uint8_t>(level)); 435*16a2ced3SJonathan Doman return tdpControl.success(); 436*16a2ced3SJonathan Doman } 437*16a2ced3SJonathan Doman bool bfSupported(unsigned int level) override 438*16a2ced3SJonathan Doman { 439*16a2ced3SJonathan Doman return GetConfigTdpControl(pm, static_cast<uint8_t>(level)) 440*16a2ced3SJonathan Doman .pbfSupport(); 441*16a2ced3SJonathan Doman } 442*16a2ced3SJonathan Doman bool tfSupported(unsigned int level) override 443*16a2ced3SJonathan Doman { 444*16a2ced3SJonathan Doman return GetConfigTdpControl(pm, static_cast<uint8_t>(level)) 445*16a2ced3SJonathan Doman .factSupport(); 446*16a2ced3SJonathan Doman } 447*16a2ced3SJonathan Doman bool bfEnabled(unsigned int level) override 448*16a2ced3SJonathan Doman { 449*16a2ced3SJonathan Doman return GetConfigTdpControl(pm, static_cast<uint8_t>(level)) 450*16a2ced3SJonathan Doman .pbfEnabled(); 451*16a2ced3SJonathan Doman } 452*16a2ced3SJonathan Doman bool tfEnabled(unsigned int level) override 453*16a2ced3SJonathan Doman { 454*16a2ced3SJonathan Doman return GetConfigTdpControl(pm, static_cast<uint8_t>(level)) 455*16a2ced3SJonathan Doman .factEnabled(); 456*16a2ced3SJonathan Doman } 457*16a2ced3SJonathan Doman unsigned int tdp(unsigned int level) override 458*16a2ced3SJonathan Doman { 459*16a2ced3SJonathan Doman return GetTdpInfo(pm, static_cast<uint8_t>(level)).pkgTdp(); 460*16a2ced3SJonathan Doman } 461*16a2ced3SJonathan Doman unsigned int coreCount(unsigned int level) override 462*16a2ced3SJonathan Doman { 463*16a2ced3SJonathan Doman return enabledCoreList(level).size(); 464*16a2ced3SJonathan Doman } 465*16a2ced3SJonathan Doman std::vector<unsigned int> enabledCoreList(unsigned int level) override 466*16a2ced3SJonathan Doman { 467*16a2ced3SJonathan Doman uint64_t coreMaskLo = 468*16a2ced3SJonathan Doman GetCoreMask(pm, static_cast<uint8_t>(level), 0).coresMask(); 469*16a2ced3SJonathan Doman uint64_t coreMaskHi = 470*16a2ced3SJonathan Doman GetCoreMask(pm, static_cast<uint8_t>(level), 1).coresMask(); 471*16a2ced3SJonathan Doman std::bitset<64> coreMask = (coreMaskHi << 32 | coreMaskLo); 472*16a2ced3SJonathan Doman return convertMaskToList(coreMask); 473*16a2ced3SJonathan Doman } 474*16a2ced3SJonathan Doman std::vector<TurboEntry> sseTurboProfile(unsigned int level) override 475*16a2ced3SJonathan Doman { 476*16a2ced3SJonathan Doman // Read the Turbo Ratio Limit Cores MSR which is used to generate the 477*16a2ced3SJonathan Doman // Turbo Profile for each profile. This is a package scope MSR, so just 478*16a2ced3SJonathan Doman // read thread 0. 479*16a2ced3SJonathan Doman uint64_t trlCores; 480*16a2ced3SJonathan Doman uint8_t cc; 481*16a2ced3SJonathan Doman EPECIStatus status = peci_RdIAMSR(static_cast<uint8_t>(address), 0, 482*16a2ced3SJonathan Doman 0x1AE, &trlCores, &cc); 483*16a2ced3SJonathan Doman if (!checkPECIStatus(status, cc)) 484*16a2ced3SJonathan Doman { 485*16a2ced3SJonathan Doman throw PECIError("Failed to read TRL MSR"); 486*16a2ced3SJonathan Doman } 487*16a2ced3SJonathan Doman 488*16a2ced3SJonathan Doman std::vector<TurboEntry> turboSpeeds; 489*16a2ced3SJonathan Doman uint64_t limitRatioLo = 490*16a2ced3SJonathan Doman GetTurboLimitRatios(pm, static_cast<uint8_t>(level), 0, 0).value; 491*16a2ced3SJonathan Doman uint64_t limitRatioHi = 492*16a2ced3SJonathan Doman GetTurboLimitRatios(pm, static_cast<uint8_t>(level), 1, 0).value; 493*16a2ced3SJonathan Doman uint64_t limitRatios = (limitRatioHi << 32) | limitRatioLo; 494*16a2ced3SJonathan Doman 495*16a2ced3SJonathan Doman constexpr int maxTFBuckets = 8; 496*16a2ced3SJonathan Doman for (int i = 0; i < maxTFBuckets; ++i) 497*16a2ced3SJonathan Doman { 498*16a2ced3SJonathan Doman size_t bucketCount = trlCores & 0xFF; 499*16a2ced3SJonathan Doman int bucketSpeed = limitRatios & 0xFF; 500*16a2ced3SJonathan Doman if (bucketCount != 0 && bucketSpeed != 0) 501*16a2ced3SJonathan Doman { 502*16a2ced3SJonathan Doman turboSpeeds.push_back({bucketSpeed * mhzPerRatio, bucketCount}); 503*16a2ced3SJonathan Doman } 504*16a2ced3SJonathan Doman 505*16a2ced3SJonathan Doman trlCores >>= 8; 506*16a2ced3SJonathan Doman limitRatios >>= 8; 507*16a2ced3SJonathan Doman } 508*16a2ced3SJonathan Doman return turboSpeeds; 509*16a2ced3SJonathan Doman } 510*16a2ced3SJonathan Doman unsigned int p1Freq(unsigned int level) override 511*16a2ced3SJonathan Doman { 512*16a2ced3SJonathan Doman return GetRatioInfo(pm, static_cast<uint8_t>(level)).p1() * mhzPerRatio; 513*16a2ced3SJonathan Doman } 514*16a2ced3SJonathan Doman unsigned int p0Freq(unsigned int level) override 515*16a2ced3SJonathan Doman { 516*16a2ced3SJonathan Doman return GetRatioInfo(pm, static_cast<uint8_t>(level)).p0() * mhzPerRatio; 517*16a2ced3SJonathan Doman } 518*16a2ced3SJonathan Doman unsigned int prochotTemp(unsigned int level) override 519*16a2ced3SJonathan Doman { 520*16a2ced3SJonathan Doman return GetTjmaxInfo(pm, static_cast<uint8_t>(level)).tProchot(); 521*16a2ced3SJonathan Doman } 522*16a2ced3SJonathan Doman std::vector<unsigned int> 523*16a2ced3SJonathan Doman bfHighPriorityCoreList(unsigned int level) override 524*16a2ced3SJonathan Doman { 525*16a2ced3SJonathan Doman uint64_t coreMaskLo = 526*16a2ced3SJonathan Doman PbfGetCoreMaskInfo(pm, static_cast<uint8_t>(level), 0) 527*16a2ced3SJonathan Doman .p1HiCoreMask(); 528*16a2ced3SJonathan Doman uint64_t coreMaskHi = 529*16a2ced3SJonathan Doman PbfGetCoreMaskInfo(pm, static_cast<uint8_t>(level), 1) 530*16a2ced3SJonathan Doman .p1HiCoreMask(); 531*16a2ced3SJonathan Doman std::bitset<64> hiFreqCoreList = (coreMaskHi << 32) | coreMaskLo; 532*16a2ced3SJonathan Doman return convertMaskToList(hiFreqCoreList); 533*16a2ced3SJonathan Doman } 534*16a2ced3SJonathan Doman unsigned int bfHighPriorityFreq(unsigned int level) override 535*16a2ced3SJonathan Doman { 536*16a2ced3SJonathan Doman return PbfGetP1HiP1LoInfo(pm, static_cast<uint8_t>(level)).p1Hi() * 537*16a2ced3SJonathan Doman mhzPerRatio; 538*16a2ced3SJonathan Doman } 539*16a2ced3SJonathan Doman unsigned int bfLowPriorityFreq(unsigned int level) override 540*16a2ced3SJonathan Doman { 541*16a2ced3SJonathan Doman return PbfGetP1HiP1LoInfo(pm, static_cast<uint8_t>(level)).p1Lo() * 542*16a2ced3SJonathan Doman mhzPerRatio; 543*16a2ced3SJonathan Doman } 544*16a2ced3SJonathan Doman 545*16a2ced3SJonathan Doman void setBfEnabled(bool enable) override 546*16a2ced3SJonathan Doman { 547*16a2ced3SJonathan Doman GetConfigTdpControl getTDPControl(pm); 548*16a2ced3SJonathan Doman bool tfEnabled = false; 549*16a2ced3SJonathan Doman uint8_t param = (enable ? bit(1) : 0) | (tfEnabled ? bit(0) : 0); 550*16a2ced3SJonathan Doman SetConfigTdpControl(pm, 0, 0, param); 551*16a2ced3SJonathan Doman } 552*16a2ced3SJonathan Doman void setTfEnabled(bool enable) override 553*16a2ced3SJonathan Doman { 554*16a2ced3SJonathan Doman // TODO: use cached BF value 555*16a2ced3SJonathan Doman bool bfEnabled = false; 556*16a2ced3SJonathan Doman uint8_t param = (bfEnabled ? bit(1) : 0) | (enable ? bit(0) : 0); 557*16a2ced3SJonathan Doman SetConfigTdpControl(pm, 0, 0, param); 558*16a2ced3SJonathan Doman } 559*16a2ced3SJonathan Doman void setCurrentLevel(unsigned int level) override 560*16a2ced3SJonathan Doman { 561*16a2ced3SJonathan Doman SetLevel(pm, static_cast<uint8_t>(level)); 562*16a2ced3SJonathan Doman } 563*16a2ced3SJonathan Doman }; 564*16a2ced3SJonathan Doman 565*16a2ced3SJonathan Doman static std::unique_ptr<SSTInterface> createMailbox(uint8_t address, 566*16a2ced3SJonathan Doman CPUModel model) 567*16a2ced3SJonathan Doman { 568*16a2ced3SJonathan Doman DEBUG_PRINT << "createMailbox\n"; 569*16a2ced3SJonathan Doman if (model == icx || model == icxd || model == spr) 570*16a2ced3SJonathan Doman { 571*16a2ced3SJonathan Doman return std::make_unique<SSTMailbox>(address, model); 572*16a2ced3SJonathan Doman } 573*16a2ced3SJonathan Doman 574*16a2ced3SJonathan Doman return nullptr; 575*16a2ced3SJonathan Doman } 576*16a2ced3SJonathan Doman 577*16a2ced3SJonathan Doman SSTProviderRegistration(createMailbox); 578*16a2ced3SJonathan Doman 579*16a2ced3SJonathan Doman } // namespace sst 580*16a2ced3SJonathan Doman } // namespace cpu_info 581