Refactor SST host processor interface
In order to support future host processors that use a different
interface to SST, separate the SST logic into 1) high-level discovery
logic + D-Bus interfaces, and 2) low-level backend processor interface.
This is a pure refactor with no functional change.
Tested:
Ran sst-compare-redfish-os.py tool on platform with SPR host CPU, and
verified no mismatches reported.
Used sst-info.sh to change configs and verify new config was reflected
in Redfish.
Change-Id: I6825eb7541cbe2214844e7b64d462f2688dedcec
Signed-off-by: Jonathan Doman <jonathan.doman@intel.com>
diff --git a/include/cpuinfo_utils.hpp b/include/cpuinfo_utils.hpp
index ab2ea92..926c2d1 100644
--- a/include/cpuinfo_utils.hpp
+++ b/include/cpuinfo_utils.hpp
@@ -47,4 +47,43 @@
*/
void hostStateSetup(const std::shared_ptr<sdbusplus::asio::connection>& conn);
+constexpr uint64_t bit(uint8_t index)
+{
+ return (1ull << index);
+}
+
+/**
+ * Extract a bitfield from an input data by shifting and masking.
+ *
+ * @tparam Dest Destination type - mostly useful to avoid an extra static_cast
+ * at the call site. Defaults to the Src type if unspecified.
+ * @tparam Src Automatically deduced from the first positional parameter.
+ *
+ * @param data Input data.
+ * @param loBit 0-based index of the least significant bit to return.
+ * @param hiBit 0-based index of the most significant bit to return.
+ */
+template <typename Dest = std::monostate, typename Src>
+auto mask(Src data, unsigned int loBit, unsigned int hiBit)
+{
+ assert(hiBit >= loBit);
+ uint64_t d = data;
+ d >>= loBit;
+ d &= (1ull << (hiBit - loBit + 1)) - 1;
+ if constexpr (std::is_same_v<Dest, std::monostate>)
+ {
+ return static_cast<Src>(d);
+ }
+ else
+ {
+ return static_cast<Dest>(d);
+ }
+}
+
+namespace dbus
+{
+boost::asio::io_context& getIOContext();
+std::shared_ptr<sdbusplus::asio::connection> getConnection();
+} // namespace dbus
+
} // namespace cpu_info
diff --git a/include/speed_select.hpp b/include/speed_select.hpp
index aaa8b70..4b4189f 100644
--- a/include/speed_select.hpp
+++ b/include/speed_select.hpp
@@ -13,9 +13,14 @@
// limitations under the License.
#pragma once
+#include <peci.h>
+
#include <boost/asio/io_context.hpp>
#include <sdbusplus/asio/connection.hpp>
+#include <bitset>
+#include <iostream>
+
namespace cpu_info
{
namespace sst
@@ -36,5 +41,148 @@
void init(boost::asio::io_context& ioc,
const std::shared_ptr<sdbusplus::asio::connection>& conn);
+class PECIError : public std::runtime_error
+{
+ using std::runtime_error::runtime_error;
+};
+
+bool checkPECIStatus(EPECIStatus libStatus, uint8_t completionCode);
+
+constexpr int extendedModel(CPUModel model)
+{
+ return (model >> 16) & 0xF;
+}
+
+/**
+ * Construct a list of indexes of the set bits in the input value.
+ * E.g. fn(0x7A) -> {1,3,4,5,6}
+ *
+ * @param[in] mask Bitmask to convert.
+ *
+ * @return List of bit indexes.
+ */
+static std::vector<uint32_t> convertMaskToList(std::bitset<64> mask)
+{
+ std::vector<uint32_t> bitList;
+ for (size_t i = 0; i < mask.size(); ++i)
+ {
+ if (mask.test(i))
+ {
+ bitList.push_back(i);
+ }
+ }
+ return bitList;
+}
+
+using TurboEntry = std::tuple<uint32_t, size_t>;
+
+/**
+ * Abstract interface that must be implemented by backends, allowing discovery
+ * and control of a single CPU package.
+ */
+class SSTInterface
+{
+ public:
+ virtual ~SSTInterface()
+ {}
+
+ /**
+ * Whether the interface is ready to be used, or we need to wait longer. The
+ * backend may need to wait e.g. for the host BIOS to initialize the
+ * interface.
+ */
+ virtual bool ready() = 0;
+
+ /** Whether the processor supports the control ("set") functions. */
+ virtual bool supportsControl() = 0;
+
+ /** Whether SST-PP is enabled on the processor. */
+ virtual bool ppEnabled() = 0;
+ /** Return the current SST-PP configuration level */
+ virtual unsigned int currentLevel() = 0;
+ /** Return the maximum valid SST-PP configuration level */
+ virtual unsigned int numLevels() = 0;
+
+ /**
+ * Whether the given level is supported. The level indices may be
+ * discontinuous, so this function should be used before querying deeper
+ * properties of a level.
+ */
+ virtual bool levelSupported(unsigned int level) = 0;
+ /** Whether SST-BF is supported in a given level. */
+ virtual bool bfSupported(unsigned int level) = 0;
+ /** Whether SST-TF is supported in a given level. */
+ virtual bool tfSupported(unsigned int level) = 0;
+ /** Whether SST-BF is enabled in a given level. */
+ virtual bool bfEnabled(unsigned int level) = 0;
+ /** Whether SST-TF is enabled in a given level. */
+ virtual bool tfEnabled(unsigned int level) = 0;
+ /** Return the package Thermal Design Power in Watts for a given level. */
+ virtual unsigned int tdp(unsigned int level) = 0;
+ /** Return the number of cores enabled in a given level. */
+ virtual unsigned int coreCount(unsigned int level) = 0;
+ /** Return the list of enabled logical core indices for a given level. */
+ virtual std::vector<unsigned int> enabledCoreList(unsigned int level) = 0;
+ /**
+ * Return the list of TurboEntrys which define the SSE turbo profile for a
+ * given level.
+ */
+ virtual std::vector<TurboEntry> sseTurboProfile(unsigned int level) = 0;
+ /** Return the base frequency (P1) for a given level. */
+ virtual unsigned int p1Freq(unsigned int level) = 0;
+ /** Return the maximum single-core frequency (P0) for a given level. */
+ virtual unsigned int p0Freq(unsigned int level) = 0;
+ /**
+ * Return the DTS max or external Prochot temperature in degrees Celsius
+ * for a given level.
+ */
+ virtual unsigned int prochotTemp(unsigned int level) = 0;
+ /**
+ * Return the list of logical core indices which have high priority when
+ * SST-BF is enabled for a given level.
+ */
+ virtual std::vector<unsigned int>
+ bfHighPriorityCoreList(unsigned int level) = 0;
+ /** Return the high priority base frequency for a given level. */
+ virtual unsigned int bfHighPriorityFreq(unsigned int level) = 0;
+ /** Return the low priority base frequency for a given level. */
+ virtual unsigned int bfLowPriorityFreq(unsigned int level) = 0;
+
+ /** Enable or disable SST-BF for the current configuration. */
+ virtual void setBfEnabled(bool enable) = 0;
+ /** Enable or disable SST-TF for the current configuration. */
+ virtual void setTfEnabled(bool enable) = 0;
+ /** Change the current configuration to the given level. */
+ virtual void setCurrentLevel(unsigned int level) = 0;
+};
+
+/**
+ * BackendProvider represents a function which may create an SSTInterface given
+ * a CPU PECI address, and the CPU Model information. Usually the CPUModel is
+ * sufficient to determine if the backend is supported.
+ * Backend should return nullptr to indicate it doesn't support a given CPU.
+ * The SST upper layer will call the registered backend provider functions in
+ * arbitrary order until one of them returns a non-null pointer.
+ */
+using BackendProvider =
+ std::function<std::unique_ptr<SSTInterface>(uint8_t, CPUModel)>;
+
+/**
+ * Backends should use 1 instance of the SSTProviderRegistration macro at file
+ * scope to register their provider function. This static struct instance
+ * register the backend before main() is run, and prevents the upper layer from
+ * having to know about which backends exist.
+ */
+#define SSTProviderRegistration(fn) \
+ struct fn##Register \
+ { \
+ fn##Register() \
+ { \
+ std::cerr << "Registering SST Provider " #fn << std::endl; \
+ registerBackend(fn); \
+ } \
+ } fn##Instance;
+void registerBackend(BackendProvider);
+
} // namespace sst
} // namespace cpu_info