add handler logic to handle i2c pcie commands
Add handler logic to manage the i2c pcie commands and their
corresponding data structure.
Tested: Only ran unit-tests (added new ones).
Change-Id: Ibd65d6745202dbf6bd67cd2cb480914ca6ae4ed1
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/handler.cpp b/handler.cpp
index 041f77b..341e195 100644
--- a/handler.cpp
+++ b/handler.cpp
@@ -257,6 +257,22 @@
return name;
}
+void Handler::buildI2cPcieMapping()
+{
+ _pcie_i2c_map = buildPcieMap();
+}
+
+size_t Handler::getI2cPcieMappingSize() const
+{
+ return _pcie_i2c_map.size();
+}
+
+std::tuple<std::uint32_t, std::string>
+ Handler::getI2cEntry(unsigned int entry) const
+{
+ return _pcie_i2c_map[entry];
+}
+
const std::string defaultConfigFile =
"/usr/share/ipmi-entity-association/entity_association_map.json";
diff --git a/handler.hpp b/handler.hpp
index ec77657..ae84945 100644
--- a/handler.hpp
+++ b/handler.hpp
@@ -5,6 +5,7 @@
#include <nlohmann/json.hpp>
#include <string>
#include <tuple>
+#include <vector>
namespace google
{
@@ -67,6 +68,27 @@
*/
virtual std::string getEntityName(std::uint8_t id,
std::uint8_t instance) = 0;
+
+ /**
+ * Populate the i2c-pcie mapping vector.
+ */
+ virtual void buildI2cPcieMapping() = 0;
+
+ /**
+ * Return the size of the i2c-pcie mapping vector.
+ *
+ * @return the size of the vector holding the i2c-pcie mapping tuples.
+ */
+ virtual size_t getI2cPcieMappingSize() const = 0;
+
+ /**
+ * Return a copy of the entry in the vector.
+ *
+ * @param[in] entry - the index into the vector.
+ * @return the tuple at that index.
+ */
+ virtual std::tuple<std::uint32_t, std::string>
+ getI2cEntry(unsigned int entry) const = 0;
};
class Handler : public HandlerInterface
@@ -81,6 +103,10 @@
VersionTuple getCpldVersion(unsigned int id) const override;
void psuResetDelay(std::uint32_t delay) const override;
std::string getEntityName(std::uint8_t id, std::uint8_t instance) override;
+ void buildI2cPcieMapping() override;
+ size_t getI2cPcieMappingSize() const override;
+ std::tuple<std::uint32_t, std::string>
+ getI2cEntry(unsigned int entry) const override;
private:
std::string _configFile;
@@ -97,6 +123,8 @@
{0x20, "memory_device"}};
nlohmann::json _entityConfig{};
+
+ std::vector<std::tuple<uint32_t, std::string>> _pcie_i2c_map;
};
/**
diff --git a/pcie_i2c.cpp b/pcie_i2c.cpp
index 5f45650..07b04b9 100644
--- a/pcie_i2c.cpp
+++ b/pcie_i2c.cpp
@@ -30,17 +30,10 @@
namespace ipmi
{
-namespace
-{
-
#ifndef MAX_IPMI_BUFFER
#define MAX_IPMI_BUFFER 64
#endif
-std::vector<std::tuple<uint32_t, std::string>> pcie_i2c_map;
-
-} // namespace
-
struct PcieSlotCountRequest
{
uint8_t subcommand;
@@ -67,7 +60,7 @@
} __attribute__((packed));
ipmi_ret_t PcieSlotCount(const uint8_t* reqBuf, uint8_t* replyBuf,
- size_t* dataLen)
+ size_t* dataLen, HandlerInterface* handler)
{
if ((*dataLen) < sizeof(struct PcieSlotCountRequest))
{
@@ -77,12 +70,12 @@
}
// If there are already entries in the vector, clear them.
- pcie_i2c_map = buildPcieMap();
+ handler->buildI2cPcieMapping();
struct PcieSlotCountReply reply;
reply.subcommand = SysPcieSlotCount;
// Fill the pcie slot count as the number of entries in the vector.
- reply.value = pcie_i2c_map.size();
+ reply.value = handler->getI2cPcieMappingSize();
std::memcpy(&replyBuf[0], &reply, sizeof(reply));
@@ -93,7 +86,7 @@
}
ipmi_ret_t PcieSlotI2cBusMapping(const uint8_t* reqBuf, uint8_t* replyBuf,
- size_t* dataLen)
+ size_t* dataLen, HandlerInterface* handler)
{
struct PcieSlotI2cBusMappingRequest request;
@@ -105,7 +98,8 @@
}
// If there are no entries in the vector return error.
- if (pcie_i2c_map.empty())
+ size_t mapSize = handler->getI2cPcieMappingSize();
+ if (mapSize == 0)
{
return IPMI_CC_INVALID_RESERVATION_ID;
}
@@ -114,14 +108,15 @@
// The valid entries range from 0 to N - 1, N being the total number of
// entries in the vector.
- if (request.entry >= pcie_i2c_map.size())
+ if (request.entry >= mapSize)
{
return IPMI_CC_PARM_OUT_OF_RANGE;
}
// Get the i2c bus number and the pcie slot name from the vector.
- uint32_t i2c_bus_number = std::get<0>(pcie_i2c_map[request.entry]);
- std::string pcie_slot_name = std::get<1>(pcie_i2c_map[request.entry]);
+ auto i2cEntry = handler->getI2cEntry(request.entry);
+ uint32_t i2c_bus_number = std::get<0>(i2cEntry);
+ std::string pcie_slot_name = std::get<1>(i2cEntry);
int length =
sizeof(struct PcieSlotI2cBusMappingReply) + pcie_slot_name.length();
diff --git a/pcie_i2c.hpp b/pcie_i2c.hpp
index 3985698..fb4e6d3 100644
--- a/pcie_i2c.hpp
+++ b/pcie_i2c.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include "handler.hpp"
+
#include <ipmid/api.h>
namespace google
@@ -10,12 +12,14 @@
// Handle the pcie slot count command.
// Sys can query the number of pcie slots.
ipmi_ret_t PcieSlotCount(const uint8_t* reqBuf, uint8_t* replyBuf,
- size_t* dataLen);
+ size_t* dataLen,
+ HandlerInterface* handler = &handlerImpl);
// Handle the pcie slot to i2c bus mapping command.
// Sys can query which i2c bus is routed to which pcie slot.
ipmi_ret_t PcieSlotI2cBusMapping(const uint8_t* reqBuf, uint8_t* replyBuf,
- size_t* dataLen);
+ size_t* dataLen,
+ HandlerInterface* handler = &handlerImpl);
} // namespace ipmi
} // namespace google
diff --git a/test/Makefile.am b/test/Makefile.am
index 0243d44..b9ad829 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -38,3 +38,7 @@
check_PROGRAMS += entity_unittest
entity_unittest_SOURCES = entity_unittest.cpp
entity_unittest_LDADD = $(top_builddir)/libsyscmds_common.la
+
+check_PROGRAMS += pcie_unittest
+pcie_unittest_SOURCES = pcie_unittest.cpp
+pcie_unittest_LDADD = $(top_builddir)/libsyscmds_common.la
diff --git a/test/handler_mock.hpp b/test/handler_mock.hpp
index 6394f68..b97cce3 100644
--- a/test/handler_mock.hpp
+++ b/test/handler_mock.hpp
@@ -22,6 +22,10 @@
std::uint8_t>(unsigned int));
MOCK_CONST_METHOD1(psuResetDelay, void(std::uint32_t));
MOCK_METHOD2(getEntityName, std::string(std::uint8_t, std::uint8_t));
+ MOCK_METHOD0(buildI2cPcieMapping, void());
+ MOCK_CONST_METHOD0(getI2cPcieMappingSize, size_t());
+ MOCK_CONST_METHOD1(getI2cEntry,
+ std::tuple<std::uint32_t, std::string>(unsigned int));
};
} // namespace ipmi
diff --git a/test/pcie_unittest.cpp b/test/pcie_unittest.cpp
new file mode 100644
index 0000000..34926ee
--- /dev/null
+++ b/test/pcie_unittest.cpp
@@ -0,0 +1,99 @@
+#include "handler_mock.hpp"
+#include "main.hpp"
+#include "pcie_i2c.hpp"
+
+#include <cstdint>
+#include <cstring>
+#include <tuple>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#define MAX_IPMI_BUFFER 64
+
+using ::testing::Return;
+
+namespace google
+{
+namespace ipmi
+{
+
+TEST(PcieI2cCommandTest, PcieSlotCountTest)
+{
+ std::vector<std::uint8_t> request = {SysOEMCommands::SysPcieSlotCount};
+ size_t dataLen = request.size();
+ std::uint8_t reply[MAX_IPMI_BUFFER];
+ size_t expectedSize = 3;
+
+ HandlerMock hMock;
+ EXPECT_CALL(hMock, buildI2cPcieMapping());
+ EXPECT_CALL(hMock, getI2cPcieMappingSize()).WillOnce(Return(expectedSize));
+ EXPECT_EQ(IPMI_CC_OK,
+ PcieSlotCount(request.data(), reply, &dataLen, &hMock));
+ EXPECT_EQ(expectedSize, reply[1]);
+}
+
+TEST(PcieI2cCommandTest, PcieSlotEntryRequestTooShort)
+{
+ std::vector<std::uint8_t> request = {
+ SysOEMCommands::SysPcieSlotI2cBusMapping};
+ size_t dataLen = request.size();
+ std::uint8_t reply[MAX_IPMI_BUFFER];
+
+ HandlerMock hMock;
+ EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID,
+ PcieSlotI2cBusMapping(request.data(), reply, &dataLen, &hMock));
+}
+
+TEST(PcieI2cCommandTest, PcieSlotEntryRequestUnsupportedByPlatform)
+{
+ // If there is no mapping in the device-tree, then the map is of size zero.
+ std::vector<std::uint8_t> request = {
+ SysOEMCommands::SysPcieSlotI2cBusMapping, 0};
+ size_t dataLen = request.size();
+ std::uint8_t reply[MAX_IPMI_BUFFER];
+
+ HandlerMock hMock;
+ EXPECT_CALL(hMock, getI2cPcieMappingSize()).WillOnce(Return(0));
+ EXPECT_EQ(IPMI_CC_INVALID_RESERVATION_ID,
+ PcieSlotI2cBusMapping(request.data(), reply, &dataLen, &hMock));
+}
+
+TEST(PcieI2cCommandTest, PcieSlotEntryRequestInvalidIndex)
+{
+ // index of 1 is invalid if length is 1.
+ std::vector<std::uint8_t> request = {
+ SysOEMCommands::SysPcieSlotI2cBusMapping, 1};
+ size_t dataLen = request.size();
+ std::uint8_t reply[MAX_IPMI_BUFFER];
+
+ HandlerMock hMock;
+ EXPECT_CALL(hMock, getI2cPcieMappingSize()).WillOnce(Return(1));
+ EXPECT_EQ(IPMI_CC_PARM_OUT_OF_RANGE,
+ PcieSlotI2cBusMapping(request.data(), reply, &dataLen, &hMock));
+}
+
+TEST(PcieI2cCommandTest, PcieSlotEntryRequestValidIndex)
+{
+ unsigned int index = 0;
+ std::vector<std::uint8_t> request = {
+ SysOEMCommands::SysPcieSlotI2cBusMapping,
+ static_cast<std::uint8_t>(index)};
+ size_t dataLen = request.size();
+ std::uint8_t reply[MAX_IPMI_BUFFER];
+ std::string slotName = "abcd";
+ std::uint32_t busNum = 5;
+
+ HandlerMock hMock;
+ EXPECT_CALL(hMock, getI2cPcieMappingSize()).WillOnce(Return(1));
+ EXPECT_CALL(hMock, getI2cEntry(index))
+ .WillOnce(Return(std::make_tuple(busNum, slotName)));
+ EXPECT_EQ(IPMI_CC_OK,
+ PcieSlotI2cBusMapping(request.data(), reply, &dataLen, &hMock));
+ EXPECT_EQ(busNum, reply[1]);
+ EXPECT_EQ(slotName.length(), reply[2]);
+ EXPECT_EQ(0, std::memcmp(slotName.c_str(), &reply[3], reply[2]));
+}
+
+} // namespace ipmi
+} // namespace google