Support dimm loop detection for the AMD platform
Description:
- Support detection of the DIMM loop pattern for the AMD platform
Design:
- The ipmi handler netfn=0x38,cmd=0x33 handles BIC incoming
postcode and call the detection function to check if this
is the DIMM loop pattern of AMD platform and store those
patterns in an in-memory space.
Reference from Meta_BIOS_Requirement_Spec_v0.80
For AMD platform, the POST code looping pattern format should be:
(each group has 4 bytes)
●Group #0: [DDEE0000]
●Group #1: [DDEE] + Total Error Count
●Group #2: [DDEE] + Number of Error DIMM
●Group #3: [DDEE] + Dimm location
●Group #4: [DDEE] + major code
●Group #5: [DDEE] + minor code
Change-Id: I9598f71775936cea9a860a091bc74aefea8701f3
Signed-off-by: Delphine CC Chiu <Delphine_CC_Chiu@wiwynn.com>
diff --git a/include/biccommands.hpp b/include/biccommands.hpp
index dfce3a4..8466692 100644
--- a/include/biccommands.hpp
+++ b/include/biccommands.hpp
@@ -1,3 +1,5 @@
+#include <phosphor-logging/lg2.hpp>
+
#include <cstdint>
enum class fb_bic_cmds : uint8_t
@@ -8,6 +10,7 @@
CMD_OEM_SET_HOST_POWER_STATE = 0x0C,
CMD_OEM_GET_FLASH_SIZE = 0x19,
CMD_OEM_CLEAR_CMOS = 0x25,
+ CMD_OEM_1S_4BYTE_POST_BUF = 0x33,
};
// Flash size response length
diff --git a/include/types.hpp b/include/types.hpp
new file mode 100644
index 0000000..f6c0076
--- /dev/null
+++ b/include/types.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <iostream>
+#include <variant>
+#include <vector>
+
+namespace ipmi
+{
+
+constexpr size_t amdFourBytesPostCode = 4;
+
+namespace dimm
+{
+using hostId = size_t;
+struct dimmLoop
+{
+ size_t totalErrorCount;
+ bool gotPattern; // It gets the whole pattern success.
+ bool startDetect; // Dimm loop detection to use. After getting the anchor
+ // tag start to detected.
+ std::vector<std::vector<uint8_t>> postCode;
+};
+} // namespace dimm
+} // namespace ipmi
diff --git a/src/biccommands.cpp b/src/biccommands.cpp
index 49ae97f..ed3f6f8 100644
--- a/src/biccommands.cpp
+++ b/src/biccommands.cpp
@@ -20,6 +20,7 @@
#include <ipmid/api-types.hpp>
#include <ipmid/api.hpp>
#include <phosphor-logging/log.hpp>
+#include <types.hpp>
#include <iostream>
#include <variant>
@@ -42,6 +43,13 @@
int sendBicCmd(uint8_t, uint8_t, uint8_t, std::vector<uint8_t>&,
std::vector<uint8_t>&);
+constexpr std::array<uint8_t, 2> amdDimmLoopPrefix = {0xDD, 0xEE};
+
+namespace dimm
+{
+std::unordered_map<hostId, dimmLoop> dimmLoops;
+} // namespace dimm
+
//----------------------------------------------------------------------
// ipmiOemBicHandler (IPMI/Section - ) (CMD_OEM_BIC_INFO)
// This Function will handle BIC request for netfn=0x38 and cmd=1
@@ -71,10 +79,79 @@
res->cc, res->payload);
}
+void dimmLoopPatternDetection(size_t hostId, std::vector<uint8_t> data)
+{
+ if constexpr (postCodeSize != amdFourBytesPostCode)
+ {
+ return;
+ }
+
+ if (data.size() != amdFourBytesPostCode)
+ {
+ return;
+ }
+
+ /*
+ Reference from Meta_BIOS_Requirement_Spec_v0.80
+ For AMD platform, the POST code looping pattern format should be:
+ (each group has 4 bytes)
+ ●Group #0: [DDEE0000]
+ ●Group #1: [DDEE] + Total Error Count
+ ●Group #2: [DDEE] + Number of Error DIMM
+ ●Group #3: [DDEE] + Dimm location
+ ●Group #4: [DDEE] + major code
+ ●Group #5: [DDEE] + minor code
+ */
+ std::array<uint8_t, 2> prefix = {data[3], data[2]};
+
+ if (prefix != amdDimmLoopPrefix)
+ {
+ // Clear all the post code stored before.
+ if (dimm::dimmLoops[hostId].startDetect)
+ {
+ dimm::dimmLoops[hostId].totalErrorCount = 0;
+ dimm::dimmLoops[hostId].postCode.clear();
+
+ dimm::dimmLoops[hostId].startDetect = false;
+ }
+ return;
+ }
+
+ // Which means it already got the dimm loop, stop checking again.
+ if (dimm::dimmLoops[hostId].gotPattern)
+ {
+ return;
+ }
+
+ constexpr std::array<uint8_t, 4> anchorTag = {0x0, 0x0, 0xEE, 0xDD};
+ if (std::ranges::equal(anchorTag, data))
+ {
+ dimm::dimmLoops[hostId].startDetect = true;
+ }
+ if (dimm::dimmLoops[hostId].startDetect)
+ {
+ // The second one is error count
+ if (dimm::dimmLoops[hostId].postCode.size() % 6 == 1)
+ {
+ dimm::dimmLoops[hostId].totalErrorCount = (data[1] << 8) | data[0];
+ }
+
+ dimm::dimmLoops[hostId].postCode.push_back(data);
+
+ // Is the last element of dimmloop then stop to detect
+ if (dimm::dimmLoops[hostId].postCode.size() ==
+ (dimm::dimmLoops[hostId].totalErrorCount * 6))
+ {
+ // Gets whole pattern success
+ dimm::dimmLoops[hostId].gotPattern = true;
+ }
+ }
+}
+
//----------------------------------------------------------------------
// ipmiOemPostCodeHandler (CMD_OEM_BIC_POST_BUFFER_INFO)
// This Function will handle BIC incomming postcode from multi-host for
-// netfn=0x38 and cmd=0x08 send the response back to the sender.
+// netfn=0x38 and cmd=0x08 or 0x33 send the response back to the sender.
//----------------------------------------------------------------------
ipmi::RspType<IanaType> ipmiOemPostCodeHandler(ipmi::Context::ptr ctx,
@@ -85,6 +162,14 @@
// creating bus connection
auto conn = getSdBus();
+ auto hostId = findHost(ctx->hostIdx);
+ if (!hostId)
+ {
+ lg2::error("Invalid Host Id received");
+ return ipmi::responseInvalidCommand();
+ }
+ dimmLoopPatternDetection(*hostId, data);
+
using postcode_t = std::tuple<uint64_t, std::vector<uint8_t>>;
std::string dbusObjStr = dbusObj + std::to_string((ctx->hostIdx + 1));
@@ -317,6 +402,10 @@
static_cast<Cmd>(fb_bic_cmds::CMD_OEM_SEND_POST_BUFFER_TO_BMC),
ipmi::Privilege::User, ipmiOemPostCodeHandler);
ipmi::registerHandler(
+ ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
+ static_cast<Cmd>(fb_bic_cmds::CMD_OEM_1S_4BYTE_POST_BUF),
+ ipmi::Privilege::User, ipmiOemPostCodeHandler);
+ ipmi::registerHandler(
ipmi::prioOemBase, ipmi::netFnOemFive,
static_cast<Cmd>(fb_bic_cmds::CMD_OEM_GET_BIC_GPIO_STATE),
ipmi::Privilege::User, ipmiOemGetBicGpioState);