Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmake/PlatformBspTests.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ add_executable(bsp_tests
fboss/platform/bsp_tests/WatchdogTests.cpp
fboss/platform/bsp_tests/XcvrTests.cpp
fboss/platform/bsp_tests/HwmonTests.cpp
fboss/platform/bsp_tests/MdioTests.cpp
)

target_link_libraries(bsp_tests
Expand All @@ -89,6 +90,7 @@ target_link_libraries(bsp_tests
bsp_test_utils
platform_manager_i2c_explorer
platform_manager_config_cpp2
device_mdio
Folly::folly
${GFLAGS}
)
Expand Down
9 changes: 9 additions & 0 deletions fboss/platform/bsp_tests/BspTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ class BspTest : public ::testing::Test {
return std::nullopt;
}

const std::optional<DeviceTestData> getDeviceTestData(
const std::string& pmName) const {
RuntimeConfig conf = GetRuntimeConfig();
if (conf.testData()->contains(pmName)) {
return conf.testData()->at(pmName);
}
return std::nullopt;
}

const std::optional<std::string> getExpectedErrorReason(
const std::string& pmName,
ExpectedErrorType type) const {
Expand Down
219 changes: 219 additions & 0 deletions fboss/platform/bsp_tests/MdioTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#include <filesystem>
#include <string>
#include <vector>

#include <fmt/format.h>
#include <folly/logging/xlog.h>
#include <gtest/gtest.h>

#include "fboss/mdio/BspDeviceMdio.h"
#include "fboss/platform/bsp_tests/BspTest.h"
#include "fboss/platform/bsp_tests/utils/CdevUtils.h"

namespace facebook::fboss::platform::bsp_tests {

constexpr auto kMdioBusCtrlPathPrefix = "/sys/class/mdio_bus/mdio_controller.";
constexpr auto kMdioBusDevPathPrefix = "/dev/fb-mdio-";

class MdioTest : public BspTest {
protected:
std::optional<MdioTestData> getMdioTestData(const std::string& pmName) {
auto testDataOpt = getDeviceTestData(pmName);
if (testDataOpt.has_value() && testDataOpt->mdioTestData().has_value()) {
return testDataOpt->mdioTestData().value();
}
return std::nullopt;
}
};

class MdioAuxDevice {
public:
MdioAuxDevice(
const PciDeviceInfo& pciInfo,
const fbiob::AuxData& auxDevice,
int32_t id)
: pciInfo_(pciInfo), auxDevice_(auxDevice), id_(id) {
CdevUtils::createNewDevice(pciInfo_, auxDevice_, id_);
}

~MdioAuxDevice() {
try {
CdevUtils::deleteDevice(pciInfo_, auxDevice_, id_);
} catch (const std::exception& e) {
// Destructors should not throw. Just log the error.
XLOG(ERR) << "Failed to delete MDIO_BUS device in destructor: "
<< e.what();
}
}

// Prevent copying
MdioAuxDevice(const MdioAuxDevice&) = delete;
MdioAuxDevice& operator=(const MdioAuxDevice&) = delete;

private:
const PciDeviceInfo& pciInfo_;
const fbiob::AuxData& auxDevice_;
int32_t id_;
};

// Test create MDIO bus
TEST_F(MdioTest, CreateMdioBus) {
const auto& devices = *GetRuntimeConfig().devices();
if (devices.empty()) {
GTEST_SKIP() << "No devices found in runtime config";
return;
}

for (const auto& device : devices) {
// Skip devices without aux devices
if (device.auxDevices()->empty()) {
continue;
}

int32_t id = 0;
for (const auto& auxDevice : *device.auxDevices()) {
// Skip non-MDIO devices
if (*auxDevice.type() != fbiob::AuxDeviceType::MDIO_BUS) {
continue;
}

id++;

try {
std::string mdioDevPath =
fmt::format("{}{}", kMdioBusDevPathPrefix, id);
{
MdioAuxDevice mdioAuxDevice(*device.pciInfo(), auxDevice, id);

XLOG(DBG4) << "Created MDIO_BUS device for PM: " << *auxDevice.name();

// Check that the dev files exist
ASSERT_TRUE(std::filesystem::exists(mdioDevPath))
<< "MDIO_BUS device file does not exist: " << mdioDevPath;

// Expected sysfs files in MDIO_BUS Ctrl directory
std::vector<std::string> expectedFiles = {"reset_bus"};
// Check that the expected sysfs files exist
std::vector<std::string> missingFiles;
for (const auto& file : expectedFiles) {
if (!std::filesystem::exists(
fmt::format("{}{}/{}", kMdioBusCtrlPathPrefix, id, file))) {
missingFiles.push_back(file);
}
}

ASSERT_TRUE(missingFiles.empty())
<< "Expected sysfs files do not exist: "
<< folly::join(", ", missingFiles);
}

ASSERT_FALSE(std::filesystem::exists(mdioDevPath))
<< "MDIO_BUS device file was not deleted: " << mdioDevPath;

} catch (const std::exception& e) {
FAIL() << "Exception during MDIO_BUS device creation: " << e.what();
}
}
}
}

// Test MDIO_BUS read and write
TEST_F(MdioTest, MdioBusReadAndWrite) {
const auto& devices = *GetRuntimeConfig().devices();
if (devices.empty()) {
GTEST_SKIP() << "No devices found in runtime config";
return;
}

for (const auto& device : devices) {
// Skip devices without aux devices
if (device.auxDevices()->empty()) {
continue;
}

int32_t id = 0;
for (const auto& auxDevice : *device.auxDevices()) {
// Skip non-MDIO devices
if (*auxDevice.type() != fbiob::AuxDeviceType::MDIO_BUS) {
continue;
}

id++;

try {
std::string mdioDevPath =
fmt::format("{}{}", kMdioBusDevPathPrefix, id);
{
MdioAuxDevice mdioAuxDevice(*device.pciInfo(), auxDevice, id);

XLOG(DBG4) << "Created MDIO_BUS device for PM: " << *auxDevice.name();

// Create MdioController instance,

MdioController<BspDeviceMdio> mdioController(id, 1, id, mdioDevPath);
mdioController.init();

auto mdioTestDataOpt = getMdioTestData(*auxDevice.name());
if (mdioTestDataOpt) {
const auto& mdioTestData = *mdioTestDataOpt;

auto devAddr = 1;

for (const auto& test : *mdioTestData.mdioWriteData()) {
auto phyAddr = static_cast<uint8_t>(test.phyAddress().value());
auto regAddr = static_cast<uint16_t>(test.regAddress().value());
auto setValue = static_cast<uint16_t>(test.setValue().value());
// Read and write to the specified register

XLOG(DBG4) << fmt::format(
"Writing to MDIO_BUS device, PM: {}, phyAddr: 0x{:x}, devAddr: 0x{:x}, regAddr: 0x{:x}, setValue: 0x{:x}",
*auxDevice.name(),
phyAddr,
devAddr,
regAddr,
setValue);

mdioController.writeCl45(phyAddr, devAddr, regAddr, setValue);
auto readValue =
mdioController.readCl45(phyAddr, devAddr, regAddr);
EXPECT_EQ(readValue, setValue) << fmt::format(
"MDIO_BUS write/read value mismatch for phyAddr: 0x{:x}, regAddr: 0x{:x}",
phyAddr,
regAddr);
}

for (const auto& test : *mdioTestData.mdioReadData()) {
// Read from the specified register
auto phyAddr = static_cast<uint8_t>(test.phyAddress().value());
auto regAddr = static_cast<uint16_t>(test.regAddress().value());
auto expectedValue =
static_cast<uint16_t>(test.expected().value());

XLOG(DBG4) << fmt::format(
"Reading from MDIO_BUS device, PM: {}, phyAddr: 0x{:x}, devAddr: 0x{:x}, regAddr: 0x{:x}",
*auxDevice.name(),
phyAddr,
devAddr,
regAddr);

auto readValue =
mdioController.readCl45(phyAddr, devAddr, regAddr);
EXPECT_EQ(readValue, expectedValue) << fmt::format(
"MDIO_BUS read value mismatch for phyAddr: 0x{:x}, regAddr: 0x{:x}",
phyAddr,
regAddr);
}
}
}

ASSERT_FALSE(std::filesystem::exists(mdioDevPath))
<< "MDIO_BUS device file was not deleted: " << mdioDevPath;
} catch (const std::exception& e) {
FAIL() << "Exception during MDIO_BUS read test: " << e.what();
}
}
}
}

} // namespace facebook::fboss::platform::bsp_tests
9 changes: 9 additions & 0 deletions fboss/platform/bsp_tests/RuntimeConfigBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ fbiob::AuxData RuntimeConfigBuilder::createSpiAuxData(
return auxData;
}

fbiob::AuxData RuntimeConfigBuilder::createMdioAuxData(
const FpgaIpBlockConfig& mdioBus) {
auto auxData = createBaseAuxData(mdioBus, fbiob::AuxDeviceType::MDIO_BUS);
return auxData;
}

facebook::fboss::platform::bsp_tests::I2CAdapter*
RuntimeConfigBuilder::findAdapter(
std::map<std::string, facebook::fboss::platform::bsp_tests::I2CAdapter>&
Expand Down Expand Up @@ -285,6 +291,9 @@ RuntimeConfig RuntimeConfigBuilder::buildRuntimeConfig(
for (const auto& spiMaster : *dev.spiMasterConfigs()) {
pciDevice.auxDevices()->push_back(createSpiAuxData(spiMaster));
}
for (const auto& mdioBusConfig : Utils::createMdioBusConfigs(dev)) {
pciDevice.auxDevices()->push_back(createMdioAuxData(mdioBusConfig));
}
devices.push_back(pciDevice);
}
}
Expand Down
1 change: 1 addition & 0 deletions fboss/platform/bsp_tests/RuntimeConfigBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class RuntimeConfigBuilder {
fbiob::AuxData createFanAuxData(const FanPwmCtrlConfig& fanCtrl);
fbiob::AuxData createSpiAuxData(const SpiMasterConfig& spiMaster);
fbiob::AuxData createIdpromAuxData(const IdpromConfig& idpromConfig);
fbiob::AuxData createMdioAuxData(const FpgaIpBlockConfig& mdioBus);
facebook::fboss::platform::bsp_tests::I2CAdapter* findAdapter(
std::map<std::string, facebook::fboss::platform::bsp_tests::I2CAdapter>&
adapters,
Expand Down
18 changes: 18 additions & 0 deletions fboss/platform/bsp_tests/bsp_tests_config.thrift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ struct DeviceTestData {
3: optional GpioTestData gpioTestData;
4: optional WatchdogTestData watchdogTestData;
5: optional LedTestData ledTestData;
6: optional MdioTestData mdioTestData;
}

struct I2CTestData {
Expand Down Expand Up @@ -81,3 +82,20 @@ struct WatchdogTestData {
struct LedTestData {
1: bool createsLeds;
}

struct MdioTestData {
1: list<MdioWriteData> mdioWriteData;
2: list<MdioReadData> mdioReadData;
}

struct MdioWriteData {
1: i32 phyAddress;
2: i32 regAddress;
3: i32 setValue;
}

struct MdioReadData {
1: i32 phyAddress;
2: i32 regAddress;
3: i32 expected;
}
1 change: 1 addition & 0 deletions fboss/platform/bsp_tests/fbiob_device_config.thrift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ enum AuxDeviceType {
XCVR = 4,
GPIO = 5,
SYSLED = 6,
MDIO_BUS = 7,
}

struct I2cData {
Expand Down
3 changes: 3 additions & 0 deletions fboss/platform/bsp_tests/utils/CdevUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ struct fbiob_aux_data getFbiobAuxData(const AuxData& auxDevice, int32_t id) {
case AuxDeviceType::SYSLED:
// Do nothing
break;
case AuxDeviceType::MDIO_BUS:
// Do nothing
break;
}

return auxData;
Expand Down
Loading
Loading