[ipmi] Generate bifurcation for item without associations This CL make IPMI dynamic bifurcation to generate bifurcation for device without association. This is the case for devices like Y-cable on RP. Only the primary side of y-cable has downstream, the other side(P1) doesn't have dowmstream. Without this fix, P1 side of the Y-cable doesn't have the right bifurcation. Tested: All sides of Y-cable has 8x8 bifurcation root@lcsqli-j6-nfd01:~# for slot in 1 2 5 6; do echo -n "Slot $slot Bifurcation: "; ipmitool raw 0x2e 0x32 0x79 0x2b 0x00 0x0f $slot; done Slot 1 Bifurcation: 79 2b 00 0f 02 08 08 Slot 2 Bifurcation: 79 2b 00 0f 02 08 08 Slot 5 Bifurcation: 79 2b 00 0f 02 08 08 Slot 6 Bifurcation: 79 2b 00 0f 02 08 08 Google-Bug-Id: 483873442 Change-Id: I17fa5095a29cd219c3d5dee5f28dc8d835e35c52 Signed-off-by: Tao Ke <taok@google.com>
diff --git a/recipes-google/ipmi/google-ipmi-sys/0001-pcie_bifurcation-Fetch-highest-level-bifurcation-at-.patch b/recipes-google/ipmi/google-ipmi-sys/0001-pcie_bifurcation-Fetch-highest-level-bifurcation-at-.patch index 38a4652..63e000f 100644 --- a/recipes-google/ipmi/google-ipmi-sys/0001-pcie_bifurcation-Fetch-highest-level-bifurcation-at-.patch +++ b/recipes-google/ipmi/google-ipmi-sys/0001-pcie_bifurcation-Fetch-highest-level-bifurcation-at-.patch
@@ -41,28 +41,28 @@ Change-Id: I0c473ae5657533113958b0b57f3145dd072f9b8a --- - bifurcation/bifurcation.hpp | 140 +++++++++++++++++- - bifurcation/bifurcation_dynamic.cpp | 193 ++++++++++++++++++++++++ + bifurcation/bifurcation.hpp | 159 +++++++++++++++- + bifurcation/bifurcation_dynamic.cpp | 222 +++++++++++++++++++++++ bifurcation/bifurcation_static.cpp | 3 +- bifurcation/meson.build | 1 + - handler.cpp | 55 ++++++- + handler.cpp | 55 +++++- handler.hpp | 7 +- handler_impl.hpp | 14 +- ipmi.cpp | 4 +- - meson.build | 9 ++ + meson.build | 9 + meson.options | 13 ++ pcie_bifurcation.cpp | 9 +- pcie_bifurcation.hpp | 5 +- - test/bifurcation_mock.hpp | 53 +++++++ + test/bifurcation_mock.hpp | 56 ++++++ test/handler_mock.hpp | 3 +- - test/handler_unittest.cpp | 221 +++++++++++++++++++++++++++- - test/pcie_bifurcation_unittest.cpp | 66 ++++++++- - 16 files changed, 768 insertions(+), 28 deletions(-) + test/handler_unittest.cpp | 271 +++++++++++++++++++++++++++- + test/pcie_bifurcation_unittest.cpp | 66 ++++++- + 16 files changed, 869 insertions(+), 28 deletions(-) create mode 100644 bifurcation/bifurcation_dynamic.cpp create mode 100644 test/bifurcation_mock.hpp diff --git a/bifurcation/bifurcation.hpp b/bifurcation/bifurcation.hpp -index b774aa0..70394b4 100644 +index b774aa0..7b406aa 100644 --- a/bifurcation/bifurcation.hpp +++ b/bifurcation/bifurcation.hpp @@ -13,8 +13,11 @@ @@ -100,7 +100,7 @@ class BifurcationInterface { public: -@@ -34,16 +53,62 @@ class BifurcationInterface +@@ -34,16 +53,72 @@ class BifurcationInterface /** * Get the Bifurcation of the device at the i2c bus * @@ -143,6 +143,16 @@ + ::ipmi::Context::ptr ctx, const std::string& path) noexcept = 0; + + /** ++ * Request the SupportedChannels from the PCIeSlot dbus object ++ * ++ * @param[in] ctx IPMI Context Pointer ++ * @param[in] path Dbus object path for PCIeSlot ++ * @return the SupportedChannels of the dbus object ++ */ ++ virtual std::optional<uint64_t> pcieSlotChannels( ++ ::ipmi::Context::ptr ctx, const std::string& path) noexcept = 0; ++ ++ /** + * Physical Association that is conatained_by the target dbus object. + * + * @param[in] ctx IPMI Context Pointer @@ -164,7 +174,7 @@ static std::reference_wrapper<BifurcationInterface> createBifurcation() { static BifurcationStatic bifurcationStatic; -@@ -54,7 +119,31 @@ class BifurcationStatic : public BifurcationInterface +@@ -54,7 +129,37 @@ class BifurcationStatic : public BifurcationInterface BifurcationStatic(std::string_view bifurcationFile); std::optional<std::vector<uint8_t>> getBifurcation( @@ -189,6 +199,12 @@ + return std::nullopt; + }; + ++ std::optional<uint64_t> pcieSlotChannels( ++ ::ipmi::Context::ptr, const std::string&) noexcept override ++ { ++ return std::nullopt; ++ }; ++ + std::vector<std::string> physicalAssociations( + ::ipmi::Context::ptr, const std::string&) noexcept override + { @@ -197,7 +213,7 @@ protected: BifurcationStatic(); -@@ -63,5 +152,52 @@ class BifurcationStatic : public BifurcationInterface +@@ -63,5 +168,55 @@ class BifurcationStatic : public BifurcationInterface std::string bifurcationFile; }; @@ -230,6 +246,9 @@ + std::optional<uint64_t> pcieSlotLanes( + ::ipmi::Context::ptr ctx, const std::string& path) noexcept override; + ++ std::optional<uint64_t> pcieSlotChannels( ++ ::ipmi::Context::ptr ctx, const std::string& path) noexcept override; ++ + std::vector<std::string> physicalAssociations( + ::ipmi::Context::ptr ctx, const std::string& path) noexcept override; + @@ -252,10 +271,10 @@ } // namespace google diff --git a/bifurcation/bifurcation_dynamic.cpp b/bifurcation/bifurcation_dynamic.cpp new file mode 100644 -index 0000000..ca299cc +index 0000000..53f959a --- /dev/null +++ b/bifurcation/bifurcation_dynamic.cpp -@@ -0,0 +1,193 @@ +@@ -0,0 +1,222 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); @@ -362,6 +381,23 @@ + return std::get<uint64_t>(deviceLanes); +} + ++std::optional<uint64_t> ++ BifurcationDynamic::pcieSlotChannels(::ipmi::Context::ptr ctx, ++ const std::string& path) noexcept ++{ ++ boost::system::error_code ec; ++ std::variant<uint64_t> channels = ++ ctx->bus->yield_method_call<std::variant<uint64_t>>( ++ ctx->yield, ec, kEntityManagerServiceName, path, ++ "org.freedesktop.DBus.Properties", "Get", kPCIeSlotInterfaceName, ++ "SupportedChannels"); ++ if (ec) ++ { ++ return std::nullopt; ++ } ++ return std::get<uint64_t>(channels); ++} ++ +std::vector<std::string> + BifurcationDynamic::physicalAssociations(::ipmi::Context::ptr ctx, + const std::string& path) noexcept @@ -417,7 +453,19 @@ + return std::vector<uint8_t>(); + } + -+ if (totalLanes < maxLanes) ++ if (bifurication.empty()) ++ { ++ auto channels = pcieSlotChannels(ctx, path).value_or(1); ++ if (channels > 1 && (maxLanes % channels == 0)) ++ { ++ bifurication.assign(channels, maxLanes / channels); ++ } ++ else ++ { ++ bifurication.emplace_back(maxLanes); ++ } ++ } ++ else if (totalLanes < maxLanes) + { + bifurication.emplace_back(maxLanes - totalLanes); + } @@ -656,9 +704,17 @@ return linuxBootDone(data, handler); case SysGetAccelVrSettings: diff --git a/meson.build b/meson.build +index 39ae9c5..d0b6394 100644 --- a/meson.build +++ b/meson.build -@@ -19,2 +19,10 @@ conf_data.set10('IPMI_ALLOWLIST', get_option('ipmi_allowlist')) +@@ -13,10 +13,19 @@ conf_data.set_quoted( + 'STATIC_BIFURCATION_CONFIG', + get_option('static-bifurcation'), + ) ++ + conf_data.set_quoted('CPU_CONFIG_PATH', get_option('cpu-config-path')) + + conf_data.set10('IPMI_ALLOWLIST', get_option('ipmi_allowlist')) +if get_option('dynamic-bifurcation').allowed() + conf_data.set('DYNAMIC_BIFURCATION', 'true') @@ -669,6 +725,8 @@ +endif + conf_h = configure_file(output: 'config.h', configuration: conf_data) + + bm_conf_data = configuration_data() diff --git a/meson.options b/meson.options index 4239f04..8a8125b 100644 --- a/meson.options @@ -756,10 +814,10 @@ } // namespace google diff --git a/test/bifurcation_mock.hpp b/test/bifurcation_mock.hpp new file mode 100644 -index 0000000..7d40e8d +index 0000000..4c2936e --- /dev/null +++ b/test/bifurcation_mock.hpp -@@ -0,0 +1,53 @@ +@@ -0,0 +1,56 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); @@ -806,6 +864,9 @@ + MOCK_METHOD((std::optional<uint64_t>), pcieSlotLanes, + (::ipmi::Context::ptr, const std::string&), + (noexcept, override)); ++ MOCK_METHOD((std::optional<uint64_t>), pcieSlotChannels, ++ (::ipmi::Context::ptr, const std::string&), ++ (noexcept, override)); + MOCK_METHOD(std::vector<std::string>, physicalAssociations, + (::ipmi::Context::ptr, const std::string&), + (noexcept, override)); @@ -829,7 +890,7 @@ MOCK_METHOD(void, accelSetVrSettings, (::ipmi::Context::ptr, uint8_t, uint8_t, uint16_t), diff --git a/test/handler_unittest.cpp b/test/handler_unittest.cpp -index d28014a..e69a307 100644 +index d28014a..2f6ab1f 100644 --- a/test/handler_unittest.cpp +++ b/test/handler_unittest.cpp @@ -12,9 +12,13 @@ @@ -896,7 +957,7 @@ EXPECT_TRUE(bifurcation.empty()); } } -@@ -722,6 +729,212 @@ TEST(HandlerTest, GetCoreCountWithExtraKeys) +@@ -722,6 +729,262 @@ TEST(HandlerTest, GetCoreCountWithExtraKeys) std::remove(testFilename); } @@ -906,6 +967,7 @@ + uint8_t bus; + std::optional<uint8_t> lanes; + std::optional<std::vector<std::string>> association; ++ std::optional<uint64_t> channels = std::nullopt; +}; + +void createPhysicalAssociation(BifurcationDynamicMock& bifurcationHelper, @@ -936,6 +998,8 @@ + } + EXPECT_CALL(bifurcationHelper, pcieSlotLanes(_, device.name)) + .WillRepeatedly(Return(device.lanes)); ++ EXPECT_CALL(bifurcationHelper, pcieSlotChannels(_, device.name)) ++ .WillRepeatedly(Return(device.channels)); + EXPECT_CALL(bifurcationHelper, physicalAssociations(_, device.name)) + .WillRepeatedly(Return(device.association.value())); + } @@ -1106,6 +1170,53 @@ + std::remove(testFilename); +} + ++TEST(HandlerTest, PcieBifurcationDynamicChannels) ++{ ++ std::vector<std::string> baseAssociations = { ++ "slot-10", "slot-20", "slot-30", ++ }; ++ std::vector<PhysicalTopology> topology = { ++ {"slot-10", 10, 16, std::vector<std::string>{}, 2}, ++ {"slot-20", 20, 16, std::vector<std::string>{}, 4}, ++ {"slot-30", 30, 16, std::vector<std::string>{}, 3}, ++ }; ++ HandlerMock hMock; ++ BifurcationDynamicMock bifurcationHelper; ++ ++ createPhysicalAssociation(bifurcationHelper, baseAssociations, topology); ++ ++ const char* testFilename = "test_channels.json"; ++ std::string contents = R"( ++ { ++ "add_in_card": [ ++ {"instance": 10, "name": "/PE0"}, ++ {"instance": 20, "name": "/PE1"}, ++ {"instance": 30, "name": "/PE2"} ++ ] ++ } ++ )"; ++ std::ofstream outputJson(testFilename); ++ outputJson << contents; ++ outputJson.flush(); ++ outputJson.close(); ++ ++ Handler h(std::ref(bifurcationHelper), testFilename); ++ ++ // 16 lanes, 2 channels -> (8, 8) ++ auto bifurcation = h.pcieBifurcation(nullptr, 0, true); ++ EXPECT_THAT(bifurcation, ElementsAre(8, 8)); ++ ++ // 16 lanes, 4 channels -> (4, 4, 4, 4) ++ bifurcation = h.pcieBifurcation(nullptr, 1, true); ++ EXPECT_THAT(bifurcation, ElementsAre(4, 4, 4, 4)); ++ ++ // 16 lanes, 3 channels (not divisible) -> fallback to (16) ++ bifurcation = h.pcieBifurcation(nullptr, 2, true); ++ EXPECT_THAT(bifurcation, ElementsAre(16)); ++ ++ std::remove(testFilename); ++} ++ // TODO: Add checks for other functions of handler. } // namespace ipmi @@ -1220,5 +1331,5 @@ } // namespace ipmi -- -2.53.0.473.g4a7958ca14-goog +2.55.0.1007.g17ff1f9808-goog