nvmesensor: Update MTU and frequency for MI ports
This CL adds the support to change the local and remote MTU
to maximum supported by the endpoint. Also, change the frequency to
400kHz. The CL performs the following steps in order:
1. setup MCTP ep
2. open nvme EP
3. read mi_data_structure_subsys_info to find Number of Ports
4. iterate the mi_data_structure_port_info to find SMBus Port
5. nvme_mi_mi_config_get_smbus_freq() to find max supported frequency
6. nvme_mi_mi_config_set_smbus_freq() change freq to 400kHz (if not)
7. nvme_mi_mi_config_set_mctp_mtu() change MTU to maximum supported
8. miConfigureLocalRouteMtu() change local route MTU
Tested:
https://paste.googleplex.com/6307677318676480
Change-Id: I256a433f530730895cd5727040cdd15732dbebe5
Signed-off-by: Muhammad Usama <muhammadusama@google.com>
diff --git a/recipes-phosphor/sensors/dbus-sensors/0024-nvmesensor-Update-MTU-and-frequency-for-MI-ports.patch b/recipes-phosphor/sensors/dbus-sensors/0024-nvmesensor-Update-MTU-and-frequency-for-MI-ports.patch
new file mode 100644
index 0000000..a51a119
--- /dev/null
+++ b/recipes-phosphor/sensors/dbus-sensors/0024-nvmesensor-Update-MTU-and-frequency-for-MI-ports.patch
@@ -0,0 +1,704 @@
+From a90ebcb0739cff5394417a0f90956a861cb4ce54 Mon Sep 17 00:00:00 2001
+From: Muhammad Usama <muhammadusama@google.com>
+Date: Tue, 21 Nov 2023 23:37:53 +0000
+Subject: [PATCH] nvmesensor: Update MTU and frequency for MI ports
+
+This CL adds the support to change the local and remote MTU
+to maximum supported by the endpoint. Also, change the frequency to
+400kHz. The CL performs the following steps in order:
+
+1. setup MCTP ep
+2. open nvme EP
+3. read mi_data_structure_subsys_info to find Number of Ports
+4. iterate the mi_data_structure_port_info to find SMBus Port
+5. nvme_mi_mi_config_get_smbus_freq() to find max supported frequency
+6. nvme_mi_mi_config_set_smbus_freq() change freq to 400kHz (if not)
+7. nvme_mi_mi_config_set_mctp_mtu() change MTU to maximum supported
+8. miConfigureLocalRouteMtu() change local route MTU
+
+Tested:
+https://paste.googleplex.com/6307677318676480
+
+Signed-off-by: Muhammad Usama <muhammadusama@google.com>
+---
+ src/NVMeIntf.hpp | 2 +
+ src/NVMeMi.cpp | 426 +++++++++++++++++++++++++++++++++--------
+ src/NVMeMi.hpp | 36 +++-
+ src/NVMeSensorMain.cpp | 3 +
+ 4 files changed, 386 insertions(+), 81 deletions(-)
+
+diff --git a/src/NVMeIntf.hpp b/src/NVMeIntf.hpp
+index 3f10a14..7de7a33 100644
+--- a/src/NVMeIntf.hpp
++++ b/src/NVMeIntf.hpp
+@@ -171,6 +171,8 @@ class NVMeMiIntf
+ const std::vector<nvme_mi_ctrl_t>&)>
+ cb) = 0;
+
++ virtual void start() = 0;
++
+ virtual ~NVMeMiIntf() = default;
+
+ virtual void adminIdentify(
+diff --git a/src/NVMeMi.cpp b/src/NVMeMi.cpp
+index d50d041..a9b65f9 100644
+--- a/src/NVMeMi.cpp
++++ b/src/NVMeMi.cpp
+@@ -31,8 +31,11 @@ NVMeMi::NVMeMi(boost::asio::io_context& io,
+ // reset to unassigned nid/eid and endpoint
+ nid = -1;
+ eid = 0;
++ mtu = 64;
+ mctpPath.erase();
+ nvmeEP = nullptr;
++ mctpStatus = Status::Reset;
++ startLoopRunning = false;
+
+ // set update the worker thread
+ if (!nvmeRoot)
+@@ -74,97 +77,138 @@ NVMeMi::NVMeMi(boost::asio::io_context& io,
+ powerCallback = setupPowerMatchCallback(conn, [this](PowerState, bool) {
+ if (::readingStateGood(this->readState))
+ {
+- initMCTP();
++ start();
+ }
+ else
+ {
+- closeMCTP();
++ stop();
+ }
+ });
+ }
+-
+- // TODO: check the powerstate.
+- initMCTP();
+ }
+
+-void NVMeMi::initMCTP()
++void NVMeMi::start()
+ {
+- // already initiated
+- if (isMCTPconnect())
++ // already in start loop
++ if (startLoopRunning)
+ {
+ return;
+ }
+
+- // init mctp ep via mctpd
+- std::unique_lock<std::mutex> lock(mctpMtx);
+- std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
+- << "start MCTP initialization" << std::endl;
+- int i = 0;
+- for (;; i++)
++ if (mctpStatus == Status::Reset)
+ {
+- try
++ // init mctp ep via mctpd
++ std::unique_lock<std::mutex> lock(mctpMtx);
++ std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
++ << "start MCTP initialization" << std::endl;
++ int i = 0;
++ for (;; i++)
+ {
+- auto msg = dbus.new_method_call(
+- "xyz.openbmc_project.MCTP", "/xyz/openbmc_project/mctp",
+- "au.com.CodeConstruct.MCTP", "SetupEndpoint");
++ try
++ {
++ auto msg = dbus.new_method_call(
++ "xyz.openbmc_project.MCTP", "/xyz/openbmc_project/mctp",
++ "au.com.CodeConstruct.MCTP", "SetupEndpoint");
+
+- msg.append("mctpi2c" + std::to_string(bus));
+- msg.append(std::vector<uint8_t>{static_cast<uint8_t>(addr)});
+- auto reply = msg.call(); // throw SdBusError
++ msg.append("mctpi2c" + std::to_string(bus));
++ msg.append(std::vector<uint8_t>{static_cast<uint8_t>(addr)});
++ auto reply = msg.call(); // throw SdBusError
+
+- reply.read(eid);
+- reply.read(nid);
+- reply.read(mctpPath);
+- break;
+- }
+- catch (const std::exception& e)
+- {
+- if (i < 5)
+- {
+- std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
+- << "retry to SetupEndpoint: " << e.what()
+- << std::endl;
++ reply.read(eid);
++ reply.read(nid);
++ reply.read(mctpPath);
++ break;
+ }
+- else
++ catch (const std::exception& e)
+ {
+- nid = -1;
+- eid = 0;
+- mctpPath.erase();
+- nvmeEP = nullptr;
+- std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
+- << "fail to init MCTP endpoint: " << e.what()
+- << std::endl;
+- return;
++ if (i < 5)
++ {
++ std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
++ << "retry to SetupEndpoint: " << e.what()
++ << std::endl;
++ }
++ else
++ {
++ nid = -1;
++ eid = 0;
++ mtu = 64;
++ mctpPath.erase();
++ nvmeEP = nullptr;
++ mctpStatus = Status::Reset;
++ std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
++ << "fail to init MCTP endpoint: " << e.what()
++ << std::endl;
++ return;
++ }
+ }
+ }
++ // open mctp endpoint
++ nvmeEP = nvme_mi_open_mctp(nvmeRoot, nid, eid);
++ if (nvmeEP == nullptr)
++ {
++ nid = -1;
++ eid = 0;
++ mtu = 64;
++ // MCTPd won't expect to delete the ep object, just to erase the
++ // record here.
++ mctpPath.erase();
++ nvmeEP = nullptr;
++ mctpStatus = Status::Reset;
++ std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
++ << "can't open MCTP endpoint "
++ << std::to_string(nid) + ":" + std::to_string(eid)
++ << std::endl;
++ return;
++ }
++ // TODO: make a flag to indicate the next health poll should return
++ // no_such_device error. This is to inform the subsystem that the
++ // connected has been reset or hot-swapped.
++
++ mctpStatus = Status::Initiated;
+ }
+
+- // open mctp endpoint
+- nvmeEP = nvme_mi_open_mctp(nvmeRoot, nid, eid);
+- if (nvmeEP == nullptr)
++ if (mctpStatus == Status::Initiated)
+ {
+- nid = -1;
+- eid = 0;
+- // MCTPd won't expect to delete the ep object, just to erase the record
+- // here.
+- mctpPath.erase();
+- nvmeEP = nullptr;
+- std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
+- << "can't open MCTP endpoint "
+- << std::to_string(nid) + ":" + std::to_string(eid)
+- << std::endl;
++ startLoopRunning = true;
++ auto timer = std::make_shared<boost::asio::steady_timer>(
++ io, std::chrono::milliseconds(500));
++ timer->async_wait([this, timer](boost::system::error_code ec) {
++ if (ec)
++ {
++ startLoopRunning = false;
++ return;
++ }
++ miSetMCTPConfiguration(
++ [self{shared_from_this()}](const std::error_code& ec) {
++ if (ec)
++ {
++ std::cerr << "[bus: " << self->bus
++ << ", addr: " << self->addr << "]"
++ << "Failed setting up MTU for the MCTP endpoint. "
++ << std::to_string(self->nid) + ":" +
++ std::to_string(self->eid)
++ << std::endl;
++ self->startLoopRunning = false;
++ self->start();
++ return;
++ }
++ auto rc = self->configureLocalRouteMtu();
++ if (rc)
++ {
++ self->startLoopRunning = false;
++ self->start();
++ return;
++ }
++ self->startLoopRunning = false;
++ self->mctpStatus = Status::Connected;
++ });
++ });
+ }
+- // TODO: make a flag to indicate the next health poll should return
+- // no_such_device error. This is to inform the subsystem that the connected
+- // has been reset or hot-swapped.
+- std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
+- << "finish MCTP initialization. "
+- << std::to_string(nid) + ":" + std::to_string(eid) << std::endl;
+ }
+
+-void NVMeMi::closeMCTP()
++void NVMeMi::stop()
+ {
+- if (!isMCTPconnect())
++ if (mctpStatus == Status::Reset)
+ {
+ return;
+ }
+@@ -181,15 +225,17 @@ void NVMeMi::closeMCTP()
+
+ nid = -1;
+ eid = 0;
++ mtu = 64;
+ mctpPath.erase();
+ nvmeEP = nullptr;
++ mctpStatus = Status::Reset;
+ std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
+ << "finish MCTP closure." << std::endl;
+ }
+
+ bool NVMeMi::isMCTPconnect() const
+ {
+- return nid >= 0 && !mctpPath.empty() && nvmeEP != nullptr;
++ return mctpStatus == Status::Connected;
+ }
+
+ NVMeMi::Worker::Worker()
+@@ -230,7 +276,7 @@ NVMeMi::Worker::~Worker()
+ }
+ NVMeMi::~NVMeMi()
+ {
+- closeMCTP();
++ stop();
+ }
+
+ void NVMeMi::Worker::post(std::function<void(void)>&& func)
+@@ -273,22 +319,244 @@ std::error_code NVMeMi::try_post(std::function<void(void)>&& func)
+ return std::error_code();
+ }
+
+-void NVMeMi::miSubsystemHealthStatusPoll(
+- std::function<void(const std::error_code&, nvme_mi_nvm_ss_health_status*)>&&
+- cb)
++void NVMeMi::miConfigureSMBusFrequency(
++ uint8_t port_id, uint8_t max_supported_freq,
++ std::function<void(const std::error_code&)>&& cb)
+ {
+ if (!nvmeEP)
+ {
+ std::cerr << "[bus: " << bus << ", addr: " << addr
+ << ", eid: " << static_cast<int>(eid) << "]"
+ << "nvme endpoint is invalid" << std::endl;
++ io.post([cb{std::move(cb)}]() {
++ cb(std::make_error_code(std::errc::no_such_device));
++ });
++ mctpStatus = Status::Reset;
++ return;
++ }
++ try
++ {
++ post([port_id, max_supported_freq, self{shared_from_this()},
++ cb{std::move(cb)}]() mutable {
++ enum nvme_mi_config_smbus_freq smbusFreq;
++ auto rc = nvme_mi_mi_config_get_smbus_freq(self->nvmeEP, port_id,
++ &smbusFreq);
++ if (rc)
++ {
++ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid)
++ << "] failed to get the SMBus frequency "
++ << std::endl;
++ }
++ else if (smbusFreq == NVME_MI_CONFIG_SMBUS_FREQ_100kHz)
++ {
++ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid)
++ << "] Setting the SMBus frequency to 400kHz\n";
++ rc = nvme_mi_mi_config_set_smbus_freq(
++ self->nvmeEP, port_id, NVME_MI_CONFIG_SMBUS_FREQ_400kHz);
++ if (rc)
++ {
++ std::cerr << "[bus: " << self->bus
++ << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid)
++ << "] failed to set the SMBus frequency\n";
++ }
++ }
++ if (rc)
++ {
++ self->io.post([cb{std::move(cb)}]() {
++ cb(std::make_error_code(std::errc::bad_message));
++ });
++ return;
++ }
++ self->io.post([cb{std::move(cb)}]() { cb({}); });
++ });
++ }
++ catch (const std::runtime_error& e)
++ {
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]" << e.what()
++ << std::endl;
++ return;
++ }
++}
+
++void NVMeMi::miConfigureRemoteMCTP(
++ uint8_t port, uint16_t mtu, uint8_t max_supported_freq,
++ std::function<void(const std::error_code&)>&& cb)
++{
++ if (!nvmeEP)
++ {
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]"
++ << "nvme endpoint is invalid" << std::endl;
+ io.post([cb{std::move(cb)}]() {
+- cb(std::make_error_code(std::errc::no_such_device), nullptr);
++ cb(std::make_error_code(std::errc::no_such_device));
+ });
++ mctpStatus = Status::Reset;
+ return;
+ }
++ try
++ {
++ post([port, mtu, max_supported_freq, self{shared_from_this()},
++ cb{std::move(cb)}]() mutable {
++ auto rc = nvme_mi_mi_config_set_mctp_mtu(self->nvmeEP, port, mtu);
++ if (rc)
++ {
++ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << " failed to set remote MCTP MTU for port :"
++ << unsigned(port) << std::endl;
++ self->io.post([cb{std::move(cb)}]() {
++ cb(std::make_error_code(std::errc::bad_message));
++ });
++ }
++ self->mtu = mtu;
++ if (max_supported_freq >= 2)
++ {
++ self->miConfigureSMBusFrequency(port, max_supported_freq,
++ std::move(cb));
++ return;
++ }
++ self->io.post([cb{std::move(cb)}]() { cb({}); });
++ });
++ }
++ catch (const std::runtime_error& e)
++ {
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]" << e.what()
++ << std::endl;
++ io.post([cb{std::move(cb)}]() {
++ cb(std::make_error_code(std::errc::no_such_device));
++ });
++ return;
++ }
++}
++
++void NVMeMi::miSetMCTPConfiguration(
++ std::function<void(const std::error_code&)>&& cb)
++{
++ if (!nvmeEP)
++ {
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]"
++ << "nvme endpoint is invalid" << std::endl;
++ io.post([cb{std::move(cb)}]() {
++ cb(std::make_error_code(std::errc::no_such_device));
++ });
++ mctpStatus = Status::Reset;
++ return;
++ }
++ try
++ {
++ post([cb{std::move(cb)}, self{shared_from_this()}]() mutable {
++ struct nvme_mi_read_nvm_ss_info ssInfo;
++ auto rc = nvme_mi_mi_read_mi_data_subsys(self->nvmeEP, &ssInfo);
++ if (rc)
++ {
++ std::cerr << "Failed reading subsystem info failing: "
++ << std::strerror(errno) << std::endl;
++ self->io.post([cb{std::move(cb)}]() {
++ cb(std::make_error_code(std::errc::bad_message));
++ });
++ return;
++ }
++
++ for (uint8_t port_id = 0; port_id <= ssInfo.nump; port_id++)
++ {
++ struct nvme_mi_read_port_info portInfo;
++ auto rc = nvme_mi_mi_read_mi_data_port(self->nvmeEP, port_id,
++ &portInfo);
++ if (rc)
++ {
++ /* PCIe port might not be ready right after AC/DC cycle. */
++ std::cerr << "[bus: " << self->bus
++ << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid)
++ << "] failed reading port info for port_id: "
++ << unsigned(port_id) << std::endl;
++ }
++ else if (portInfo.portt == 0x2)
++ {
++ // SMBus ports = 0x2
++ uint16_t supportedMtu = portInfo.mmctptus;
++ uint8_t supportedFreq = portInfo.smb.mme_freq;
++ self->miConfigureRemoteMCTP(port_id, supportedMtu,
++ supportedFreq, std::move(cb));
++ return;
++ }
++ }
++ });
++ }
++ catch (const std::runtime_error& e)
++ {
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]" << e.what()
++ << std::endl;
++ io.post([cb{std::move(cb)}]() {
++ cb(std::make_error_code(std::errc::no_such_device));
++ });
++ return;
++ }
++}
++
++int NVMeMi::configureLocalRouteMtu()
++{
++ int i = 0;
++ for (;; i++)
++ {
++ try
++ {
++ auto path = std::string("/xyz/openbmc_project/mctp/") +
++ std::to_string(nid) + "/" + std::to_string(eid);
++ auto msg = dbus.new_method_call(
++ "xyz.openbmc_project.MCTP", path.c_str(),
++ "au.com.CodeConstruct.MCTP.Endpoint", "SetMTU");
++
++ // 4 bytes for the MCTP header
++ uint32_t mctpMtu = mtu + 4;
++ msg.append(mctpMtu);
++ auto reply = msg.call();
++ break;
++ }
++ catch (const std::exception& e)
++ {
++ if (i < 5)
++ {
++ std::cerr << "[bus: " << bus << ", addr: " << addr << ", eid: "
++ << "] retry to set MCTP route MTU : " << e.what()
++ << std::endl;
++ }
++ else
++ {
++ std::cerr << "[bus: " << bus << ", addr: " << addr << ", eid: "
++ << "] failed to set MCTP route MTU : " << e.what()
++ << std::endl;
++ return -1;
++ }
++ }
++ }
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << std::to_string(eid)
++ << "] finished MCTP initialization. MTU: " << mtu << std::endl;
++ return 0;
++}
+
++void NVMeMi::miSubsystemHealthStatusPoll(
++ std::function<void(const std::error_code&, nvme_mi_nvm_ss_health_status*)>&&
++ cb)
++{
++ if (mctpStatus != Status::Connected)
++ {
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]"
++ << " MCTP connection is not established" << std::endl;
++ io.post([cb{std::move(cb)}]() {
++ cb(std::make_error_code(std::errc::not_connected), nullptr);
++ });
++ return;
++ }
+ try
+ {
+ post([self{shared_from_this()}, cb{std::move(cb)}]() {
+@@ -343,12 +611,12 @@ void NVMeMi::miScanCtrl(std::function<void(const std::error_code&,
+ const std::vector<nvme_mi_ctrl_t>&)>
+ cb)
+ {
+- if (!nvmeEP)
++ if (mctpStatus != Status::Connected)
+ {
+ std::cerr << "nvme endpoint is invalid" << std::endl;
+
+ io.post([cb{std::move(cb)}]() {
+- cb(std::make_error_code(std::errc::no_such_device), {});
++ cb(std::make_error_code(std::errc::not_connected), {});
+ });
+ return;
+ }
+@@ -409,7 +677,7 @@ void NVMeMi::adminIdentify(
+ nvme_mi_ctrl_t ctrl, nvme_identify_cns cns, uint32_t nsid, uint16_t cntid,
+ std::function<void(nvme_ex_ptr, std::span<uint8_t>)>&& cb)
+ {
+- if (!nvmeEP)
++ if (mctpStatus != Status::Connected)
+ {
+ std::cerr << "nvme endpoint is invalid" << std::endl;
+ io.post([cb{std::move(cb)}]() {
+@@ -640,13 +908,13 @@ void NVMeMi::adminGetLogPage(
+ uint16_t lsi,
+ std::function<void(const std::error_code&, std::span<uint8_t>)>&& cb)
+ {
+- if (!nvmeEP)
++ if (mctpStatus != Status::Connected)
+ {
+ std::cerr << "[bus: " << bus << ", addr: " << addr
+ << ", eid: " << static_cast<int>(eid) << "]"
+ << "nvme endpoint is invalid" << std::endl;
+ io.post([cb{std::move(cb)}]() {
+- cb(std::make_error_code(std::errc::no_such_device), {});
++ cb(std::make_error_code(std::errc::not_connected), {});
+ });
+ return;
+ }
+@@ -890,13 +1158,13 @@ void NVMeMi::adminXfer(
+ std::function<void(const std::error_code&, const nvme_mi_admin_resp_hdr&,
+ std::span<uint8_t>)>&& cb)
+ {
+- if (!nvmeEP)
++ if (mctpStatus != Status::Connected)
+ {
+ std::cerr << "[bus: " << bus << ", addr: " << addr
+ << ", eid: " << static_cast<int>(eid) << "]"
+ << "nvme endpoint is invalid" << std::endl;
+ io.post([cb{std::move(cb)}]() {
+- cb(std::make_error_code(std::errc::no_such_device), {}, {});
++ cb(std::make_error_code(std::errc::not_connected), {}, {});
+ });
+ return;
+ }
+@@ -973,13 +1241,13 @@ void NVMeMi::adminFwCommit(
+ nvme_mi_ctrl_t ctrl, nvme_fw_commit_ca action, uint8_t slot, bool bpid,
+ std::function<void(const std::error_code&, nvme_status_field)>&& cb)
+ {
+- if (!nvmeEP)
++ if (mctpStatus != Status::Connected)
+ {
+ std::cerr << "[bus: " << bus << ", addr: " << addr
+ << ", eid: " << static_cast<int>(eid) << "]"
+ << "nvme endpoint is invalid" << std::endl;
+ io.post([cb{std::move(cb)}]() {
+- cb(std::make_error_code(std::errc::no_such_device),
++ cb(std::make_error_code(std::errc::not_connected),
+ nvme_status_field::NVME_SC_MASK);
+ });
+ return;
+@@ -1052,7 +1320,7 @@ void NVMeMi::adminFwDownloadChunk(
+ int attempt_count,
+ std::function<void(const std::error_code&, nvme_status_field)>&& cb)
+ {
+- if (!nvmeEP)
++ if (mctpStatus != Status::Connected)
+ {
+ std::cerr << "nvme endpoint is invalid" << std::endl;
+ io.post([cb{std::move(cb)}]() {
+diff --git a/src/NVMeMi.hpp b/src/NVMeMi.hpp
+index 17b88ba..0e5f50f 100644
+--- a/src/NVMeMi.hpp
++++ b/src/NVMeMi.hpp
+@@ -95,6 +95,8 @@ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
+ uint8_t passes, uint32_t pattern, bool invert_pattern,
+ std::function<void(nvme_ex_ptr ex)>&& cb) override;
+
++ void start() override;
++
+ private:
+ // the transfer size for nvme mi messages.
+ // define in github.com/linux-nvme/libnvme/blob/master/src/nvme/mi.c
+@@ -119,6 +121,7 @@ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
+
+ int nid;
+ uint8_t eid;
++ uint16_t mtu;
+ std::string mctpPath;
+
+ std::mutex mctpMtx;
+@@ -140,6 +143,23 @@ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
+ void post(std::function<void(void)>&& func);
+ };
+
++ // A state machine to represent the current status of the MCTP connection.
++ // In Reset state, the MCTP endpoint (EP) is not setup with the device. In
++ // event of successful setup and opening of EP, the status will change to
++ // Initiated. The status will change to Connected, once the MTU of local and
++ // device side MTU and frequency is changed. In an event of connection EP
++ // closure, the status will move back to Reset.
++ enum class Status
++ {
++ Reset,
++ Initiated,
++ Connected,
++ };
++
++ bool startLoopRunning;
++
++ Status mctpStatus;
++
+ // A map from root bus number to the Worker
+ // This map means to reuse the same worker for all NVMe EP under the same
+ // I2C root bus. There is no real physical concurrency among the i2c/mctp
+@@ -151,9 +171,21 @@ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
+ std::shared_ptr<Worker> worker;
+ void post(std::function<void(void)>&& func);
+
+- void initMCTP();
++ void stop();
++
++ void
++ miConfigureRemoteMCTP(uint8_t port, uint16_t mtu,
++ uint8_t max_supported_freq,
++ std::function<void(const std::error_code&)>&& cb);
++
++ void miConfigureSMBusFrequency(
++ uint8_t port_id, uint8_t max_supported_freq,
++ std::function<void(const std::error_code&)>&& cb);
++
++ void miSetMCTPConfiguration(
++ std::function<void(const std::error_code&)>&& cb);
+
+- void closeMCTP();
++ int configureLocalRouteMtu();
+
+ bool isMCTPconnect() const;
+
+diff --git a/src/NVMeSensorMain.cpp b/src/NVMeSensorMain.cpp
+index 1265403..ac6ea23 100644
+--- a/src/NVMeSensorMain.cpp
++++ b/src/NVMeSensorMain.cpp
+@@ -217,6 +217,9 @@ static void handleConfigurations(
+ io, dbusConnection, *busNumber, *address, singleThreadMode,
+ powerState);
+
++ auto nvme = std::get<std::shared_ptr<NVMeMiIntf>>(
++ nvmeMi.getInferface());
++ nvme->start();
+ nvmeInterfaces.emplace(interfacePath, nvmeMi);
+ }
+ catch (std::exception& ex)
+--
+2.43.0.rc1.413.gea7ed67945-goog
+
diff --git a/recipes-phosphor/sensors/dbus-sensors_%.bbappend b/recipes-phosphor/sensors/dbus-sensors_%.bbappend
index 3e2ca5e..6124cc3 100644
--- a/recipes-phosphor/sensors/dbus-sensors_%.bbappend
+++ b/recipes-phosphor/sensors/dbus-sensors_%.bbappend
@@ -94,6 +94,7 @@
file://0021-nvmesensor-use-processSecondaryControllerList-to-rep.patch \
file://0022-nvmesensor-refactor-createVolume-and-createNamespace.patch \
file://0023-nvmesensor-add-1s-timeout-for-mi-worker-condition_va.patch \
+ file://0024-nvmesensor-Update-MTU-and-frequency-for-MI-ports.patch \
"
PACKAGECONFIG[nvmesensor] = "-Dnvme=enabled, -Dnvme=disabled, libnvme"
SYSTEMD_SERVICE:${PN} += "${@bb.utils.contains('PACKAGECONFIG', 'nvmesensor', \