aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/mpmd
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/mpmd')
-rw-r--r--host/lib/usrp/mpmd/CMakeLists.txt10
-rw-r--r--host/lib/usrp/mpmd/mpmd_find.cpp11
-rw-r--r--host/lib/usrp/mpmd/mpmd_image_loader.cpp2
-rw-r--r--host/lib/usrp/mpmd/mpmd_impl.cpp127
-rw-r--r--host/lib/usrp/mpmd/mpmd_impl.hpp100
-rw-r--r--host/lib/usrp/mpmd/mpmd_link_if_ctrl_base.hpp56
-rw-r--r--host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.cpp (renamed from host/lib/usrp/mpmd/mpmd_xport_ctrl_dpdk_udp.cpp)16
-rw-r--r--host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.hpp (renamed from host/lib/usrp/mpmd/mpmd_xport_ctrl_dpdk_udp.hpp)10
-rw-r--r--host/lib/usrp/mpmd/mpmd_link_if_ctrl_liberio.cpp135
-rw-r--r--host/lib/usrp/mpmd/mpmd_link_if_ctrl_liberio.hpp64
-rw-r--r--host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.cpp279
-rw-r--r--host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.hpp61
-rw-r--r--host/lib/usrp/mpmd/mpmd_link_if_mgr.cpp135
-rw-r--r--host/lib/usrp/mpmd/mpmd_link_if_mgr.hpp (renamed from host/lib/usrp/mpmd/mpmd_xport_mgr.hpp)80
-rw-r--r--host/lib/usrp/mpmd/mpmd_mb_controller.cpp142
-rw-r--r--host/lib/usrp/mpmd/mpmd_mb_controller.hpp73
-rw-r--r--host/lib/usrp/mpmd/mpmd_mb_iface.cpp301
-rw-r--r--host/lib/usrp/mpmd/mpmd_mb_iface.hpp68
-rw-r--r--host/lib/usrp/mpmd/mpmd_mboard_impl.cpp96
-rw-r--r--host/lib/usrp/mpmd/mpmd_prop_tree.cpp12
-rw-r--r--host/lib/usrp/mpmd/mpmd_xport.cpp62
-rw-r--r--host/lib/usrp/mpmd/mpmd_xport_ctrl_base.hpp44
-rw-r--r--host/lib/usrp/mpmd/mpmd_xport_ctrl_liberio.cpp194
-rw-r--r--host/lib/usrp/mpmd/mpmd_xport_ctrl_liberio.hpp56
-rw-r--r--host/lib/usrp/mpmd/mpmd_xport_ctrl_udp.cpp265
-rw-r--r--host/lib/usrp/mpmd/mpmd_xport_ctrl_udp.hpp45
-rw-r--r--host/lib/usrp/mpmd/mpmd_xport_mgr.cpp173
27 files changed, 1384 insertions, 1233 deletions
diff --git a/host/lib/usrp/mpmd/CMakeLists.txt b/host/lib/usrp/mpmd/CMakeLists.txt
index 21511e6da..18c9c6cbd 100644
--- a/host/lib/usrp/mpmd/CMakeLists.txt
+++ b/host/lib/usrp/mpmd/CMakeLists.txt
@@ -21,21 +21,21 @@ if(ENABLE_MPMD)
${CMAKE_CURRENT_SOURCE_DIR}/mpmd_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mpmd_mboard_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mpmd_mb_controller.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_mb_iface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mpmd_prop_tree.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_xport.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_xport_mgr.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_xport_ctrl_udp.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_link_if_mgr.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_link_if_ctrl_udp.cpp
)
if(ENABLE_LIBERIO)
LIBUHD_APPEND_SOURCES(
- ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_xport_ctrl_liberio.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_link_if_ctrl_liberio.cpp
)
endif(ENABLE_LIBERIO)
if(ENABLE_DPDK)
LIBUHD_APPEND_SOURCES(
- ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_xport_ctrl_dpdk_udp.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_link_if_ctrl_dpdk_udp.cpp
)
endif(ENABLE_DPDK)
diff --git a/host/lib/usrp/mpmd/mpmd_find.cpp b/host/lib/usrp/mpmd/mpmd_find.cpp
index 2b8e1350d..3e8bcc72f 100644
--- a/host/lib/usrp/mpmd/mpmd_find.cpp
+++ b/host/lib/usrp/mpmd/mpmd_find.cpp
@@ -8,6 +8,7 @@
#include "mpmd_devices.hpp"
#include "mpmd_impl.hpp"
+#include "mpmd_link_if_mgr.hpp"
#include <uhdlib/transport/dpdk_common.hpp>
#include <uhd/transport/if_addrs.hpp>
#include <uhd/transport/udp_simple.hpp>
@@ -89,7 +90,7 @@ device_addrs_t mpmd_find_with_addr(
// Create result to return
device_addr_t new_addr;
- new_addr[xport::MGMT_ADDR_KEY] = recv_addr;
+ new_addr[MGMT_ADDR_KEY] = recv_addr;
new_addr["type"] = "mpmd"; // hwd will overwrite this
// remove ident string and put other informations into device_args dict
result.erase(result.begin());
@@ -101,7 +102,7 @@ device_addrs_t mpmd_find_with_addr(
el,
[](const char& in) { return in == '='; },
boost::token_compress_on);
- if (value[0] != xport::MGMT_ADDR_KEY) {
+ if (value[0] != MGMT_ADDR_KEY) {
new_addr[value[0]] = value[1];
}
}
@@ -132,12 +133,12 @@ device_addrs_t mpmd_find_with_addrs(const device_addrs_t& hints)
found_devices.reserve(hints.size());
for (const auto& hint : hints) {
if (not(hint.has_key(xport::FIRST_ADDR_KEY)
- or hint.has_key(xport::MGMT_ADDR_KEY))) {
+ or hint.has_key(MGMT_ADDR_KEY))) {
UHD_LOG_DEBUG("MPMD FIND", "No address given in hint " << hint.to_string());
continue;
}
const std::string mgmt_addr =
- hint.get(xport::MGMT_ADDR_KEY, hint.get(xport::FIRST_ADDR_KEY, ""));
+ hint.get(MGMT_ADDR_KEY, hint.get(xport::FIRST_ADDR_KEY, ""));
device_addrs_t reply_addrs = mpmd_find_with_addr(mgmt_addr, hint);
if (reply_addrs.size() > 1) {
UHD_LOG_ERROR("MPMD",
@@ -217,7 +218,7 @@ device_addrs_t mpmd_find(const device_addr_t& hint_)
// Scenario 1): User gave us at least one address
if (not hints.empty()
and (hints[0].has_key(xport::FIRST_ADDR_KEY)
- or hints[0].has_key(xport::MGMT_ADDR_KEY))) {
+ or hints[0].has_key(MGMT_ADDR_KEY))) {
// Note: We don't try and connect to the devices in this mode, because
// we only get here if the user specified addresses, and we assume she
// knows what she's doing.
diff --git a/host/lib/usrp/mpmd/mpmd_image_loader.cpp b/host/lib/usrp/mpmd/mpmd_image_loader.cpp
index d5c7d3da9..3a285da3e 100644
--- a/host/lib/usrp/mpmd/mpmd_image_loader.cpp
+++ b/host/lib/usrp/mpmd/mpmd_image_loader.cpp
@@ -13,6 +13,7 @@
#include <uhd/types/component_file.hpp>
#include <uhd/types/eeprom.hpp>
#include <uhd/utils/paths.hpp>
+#include <uhd/utils/static.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem/convenience.hpp>
#include <fstream>
@@ -216,6 +217,7 @@ static bool mpmd_image_loader(const image_loader::image_loader_args_t& image_loa
return true;
}
+
}} // namespace uhd::
UHD_STATIC_BLOCK(register_mpm_image_loader)
diff --git a/host/lib/usrp/mpmd/mpmd_impl.cpp b/host/lib/usrp/mpmd/mpmd_impl.cpp
index 05d847060..30a3c5804 100644
--- a/host/lib/usrp/mpmd/mpmd_impl.cpp
+++ b/host/lib/usrp/mpmd/mpmd_impl.cpp
@@ -14,11 +14,11 @@
#include <uhd/utils/tasks.hpp>
#include <uhdlib/rfnoc/radio_ctrl_impl.hpp>
#include <uhdlib/rfnoc/rpc_block_ctrl.hpp>
-#include <../device3/device3_impl.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/asio.hpp>
#include <boost/make_shared.hpp>
#include <boost/thread.hpp>
+#include <chrono>
#include <future>
#include <memory>
#include <mutex>
@@ -34,11 +34,10 @@ namespace {
/*************************************************************************
* Local constants
************************************************************************/
-const size_t MPMD_CROSSBAR_MAX_LADDR = 255;
//! Most pessimistic time for a CHDR query to go to device and back
const double MPMD_CHDR_MAX_RTT = 0.02;
-//! MPM Compatibility number
-const std::vector<size_t> MPM_COMPAT_NUM = {1, 2};
+//! MPM Compatibility number {MAJOR, MINOR}
+const std::vector<size_t> MPM_COMPAT_NUM = {2, 0};
/*************************************************************************
* Helper functions
@@ -155,7 +154,7 @@ const std::string mpmd_impl::MPM_ECHO_CMD = "MPM-ECHO";
* Structors
****************************************************************************/
mpmd_impl::mpmd_impl(const device_addr_t& device_args)
- : usrp::device3_impl(), _device_args(device_args)
+ : rfnoc_device(), _device_args(device_args)
{
const device_addrs_t mb_args = separate_device_addr(device_args);
const size_t num_mboards = mb_args.size();
@@ -175,20 +174,12 @@ mpmd_impl::mpmd_impl(const device_addr_t& device_args)
_mb.push_back(claim_and_make(mb_args[mb_i]));
}
- // Next figure out the number of base xport addresses. This way, we
- // can run _mb[*]->init() in parallel on all the _mb.
- // This can *not* be parallelized.
- std::vector<size_t> base_xport_addr(num_mboards, 2); // Starts at 2 [sic]
- for (size_t mb_i = 0; mb_i < num_mboards - 1; ++mb_i) {
- base_xport_addr[mb_i + 1] = base_xport_addr[mb_i] + _mb[mb_i]->num_xbars;
- }
-
if (not skip_init) {
// Run the actual device initialization. This can run in parallel.
for (size_t mb_i = 0; mb_i < num_mboards; ++mb_i) {
// Note: This is the only place we do compat number checks. They're
// effectively disabled for skip_init=1
- setup_mb(_mb[mb_i].get(), mb_i, base_xport_addr[mb_i]);
+ setup_mb(_mb[mb_i].get(), mb_i);
}
} else {
UHD_LOG_DEBUG("MPMD", "Claimed device, but skipped init.");
@@ -205,12 +196,6 @@ mpmd_impl::mpmd_impl(const device_addr_t& device_args)
}
if (not skip_init) {
- // This can be parallelized, because the blocks of individual mboards
- // live on different subtrees.
- for (size_t mb_i = 0; mb_i < mb_args.size(); ++mb_i) {
- setup_rfnoc_blocks(_mb[mb_i].get(), mb_i, mb_args[mb_i]);
- }
-
// FIXME this section only makes sense for when the time source is external.
// So, check for that, or something similar.
// This section of code assumes that the prop tree is set and we have access
@@ -218,12 +203,6 @@ mpmd_impl::mpmd_impl(const device_addr_t& device_args)
if (device_args.has_key("sync_time")) {
reset_time_synchronized(_tree);
}
-
- auto filtered_block_args = device_args; // TODO actually filter
- // Blocks will finalize their own setup in this function. They have
- // (and might need) full access to the prop tree, the timekeepers, etc.
- // This is already internally parallelized.
- setup_rpc_blocks(filtered_block_args, serialize_init);
} else {
UHD_LOG_INFO("MPMD", "Claimed device without full initialization.");
}
@@ -231,7 +210,6 @@ mpmd_impl::mpmd_impl(const device_addr_t& device_args)
mpmd_impl::~mpmd_impl()
{
- _rfnoc_block_ctrl.clear();
_tree.reset();
_mb.clear();
}
@@ -241,7 +219,7 @@ mpmd_impl::~mpmd_impl()
****************************************************************************/
mpmd_mboard_impl::uptr mpmd_impl::claim_and_make(const uhd::device_addr_t& device_args)
{
- const std::string rpc_addr = device_args.get(xport::MGMT_ADDR_KEY);
+ const std::string rpc_addr = device_args.get(MGMT_ADDR_KEY);
UHD_LOGGER_DEBUG("MPMD") << "Device args: `" << device_args.to_string()
<< "'. RPC address: " << rpc_addr;
@@ -254,8 +232,7 @@ mpmd_mboard_impl::uptr mpmd_impl::claim_and_make(const uhd::device_addr_t& devic
return mpmd_mboard_impl::make(device_args, rpc_addr);
}
-void mpmd_impl::setup_mb(
- mpmd_mboard_impl* mb, const size_t mb_index, const size_t base_xport_addr)
+void mpmd_impl::setup_mb(mpmd_mboard_impl* mb, const size_t mb_index)
{
assert_compat_number_throw("MPM",
MPM_COMPAT_NUM,
@@ -264,94 +241,8 @@ void mpmd_impl::setup_mb(
UHD_LOG_DEBUG("MPMD", "Initializing mboard " << mb_index);
mb->init();
- for (size_t xbar_index = 0; xbar_index < mb->num_xbars; xbar_index++) {
- mb->set_xbar_local_addr(xbar_index, base_xport_addr + xbar_index);
- }
-}
-
-void mpmd_impl::setup_rfnoc_blocks(mpmd_mboard_impl* mb,
- const size_t mb_index,
- const uhd::device_addr_t& ctrl_xport_args)
-{
- UHD_LOG_TRACE(
- "MPMD", "Mboard " << mb_index << " reports " << mb->num_xbars << " crossbar(s).");
- // TODO: The args apply to all xbars, which may or may not be true
- for (size_t xbar_index = 0; xbar_index < mb->num_xbars; xbar_index++) {
- // Pull the number of blocks and base port from the args, if available.
- // Otherwise, get the values from MPM.
- const size_t num_blocks =
- ctrl_xport_args.has_key("rfnoc_num_blocks")
- ? ctrl_xport_args.cast<size_t>("rfnoc_num_blocks", 0)
- : mb->rpc->request<size_t>("get_num_blocks", xbar_index);
- const size_t base_port =
- ctrl_xport_args.has_key("rfnoc_base_port")
- ? ctrl_xport_args.cast<size_t>("rfnoc_base_port", 0)
- : mb->rpc->request<size_t>("get_base_port", xbar_index);
- const size_t local_addr = mb->get_xbar_local_addr(xbar_index);
- UHD_LOGGER_TRACE("MPMD")
- << "Enumerating RFNoC blocks for xbar " << xbar_index
- << ". Total blocks: " << num_blocks << " Base port: " << base_port
- << " Local address: " << local_addr;
- if (ctrl_xport_args.has_key("rfnoc_num_blocks")
- or ctrl_xport_args.has_key("rfnoc_base_port")) {
- // TODO: Remove this warning once we're confident this is
- // (relatively) safe and useful. Also add documentation to
- // usrp_n3xx.dox
- UHD_LOGGER_WARNING("MPMD")
- << "Overriding default RFNoC configuration. You are using an "
- << "experimental development feature, which may go away in "
- << "future versions.";
- }
-
- try {
- enumerate_rfnoc_blocks(mb_index,
- num_blocks,
- base_port,
- uhd::sid_t(0, 0, local_addr, 0),
- ctrl_xport_args);
- } catch (const std::exception& ex) {
- UHD_LOGGER_ERROR("MPMD") << "Failure during block enumeration: " << ex.what();
- throw uhd::runtime_error("Failed to run enumerate_rfnoc_blocks()");
- }
- }
-}
-
-void mpmd_impl::setup_rpc_blocks(
- const device_addr_t& block_args, const bool serialize_init)
-{
- std::vector<std::future<void>> task_list;
- // If we don't force async, most compilers, at least now, will default to
- // deferred.
- const auto launch_policy = serialize_init ? std::launch::deferred
- : std::launch::async;
-
- // Preload all the tasks (they might start running on emplace_back)
- for (const auto& block_ctrl : _rfnoc_block_ctrl) {
- auto rpc_block_id = block_ctrl->get_block_id();
- if (has_block<uhd::rfnoc::rpc_block_ctrl>(rpc_block_id)) {
- const size_t mboard_idx = rpc_block_id.get_device_no();
- auto rpc_block_ctrl =
- get_block_ctrl<uhd::rfnoc::rpc_block_ctrl>(rpc_block_id);
- auto rpc_sptr = _mb[mboard_idx]->rpc;
- task_list.emplace_back(std::async(
- launch_policy, [rpc_block_id, rpc_block_ctrl, &block_args, rpc_sptr]() {
- UHD_LOGGER_DEBUG("MPMD")
- << "Adding RPC access to block: " << rpc_block_id
- << " Block args: " << block_args.to_string();
- rpc_block_ctrl->set_rpc_client(rpc_sptr, block_args);
- }));
- }
- }
-
- // Execute all the calls to set_rpc_client(), either concurrently, or
- // serially
- for (auto& task : task_list) {
- task.get();
- }
-}
-
-size_t mpmd_impl::get_mtu(const size_t mb_index, const uhd::direction_t dir) {
- return _mb[mb_index]->get_mtu(dir);
+ UHD_ASSERT_THROW(mb->mb_ctrl);
+ register_mb_controller(mb_index, mb->mb_ctrl);
}
/*****************************************************************************
diff --git a/host/lib/usrp/mpmd/mpmd_impl.hpp b/host/lib/usrp/mpmd/mpmd_impl.hpp
index bdb6bd691..e1dde49b5 100644
--- a/host/lib/usrp/mpmd/mpmd_impl.hpp
+++ b/host/lib/usrp/mpmd/mpmd_impl.hpp
@@ -7,14 +7,14 @@
#ifndef INCLUDED_MPMD_IMPL_HPP
#define INCLUDED_MPMD_IMPL_HPP
-#include "../device3/device3_impl.hpp"
-#include "mpmd_xport_mgr.hpp"
#include <uhd/property_tree.hpp>
#include <uhd/stream.hpp>
-#include <uhd/transport/muxed_zero_copy_if.hpp>
#include <uhd/types/device_addr.hpp>
#include <uhd/types/dict.hpp>
#include <uhd/utils/tasks.hpp>
+#include <uhdlib/rfnoc/rfnoc_device.hpp>
+#include <uhdlib/rfnoc/clock_iface.hpp>
+#include <uhdlib/usrp/common/mpmd_mb_controller.hpp>
#include <uhdlib/utils/rpc.hpp>
#include <boost/optional.hpp>
#include <map>
@@ -34,6 +34,8 @@ static constexpr size_t MPMD_DEFAULT_RPC_TIMEOUT = 2000;
static constexpr size_t MPMD_SHORT_RPC_TIMEOUT = 2000;
//! Claimer loop timeout value for RPC calls (ms).
static constexpr size_t MPMD_CLAIMER_RPC_TIMEOUT = 10000;
+//! Ethernet address for management and RPC communication
+static const std::string MGMT_ADDR_KEY = "mgmt_addr";
namespace uhd { namespace mpmd {
@@ -46,6 +48,11 @@ public:
using uptr = std::unique_ptr<mpmd_mboard_impl>;
using dev_info = std::map<std::string, std::string>;
+ //! MPMD-specific implementation of the mb_iface
+ //
+ // This handles the transport management
+ class mpmd_mb_iface;
+
/*** Static helper *******************************************************/
/*! Will run some checks to determine if this device can be reached from
* the current UHD session
@@ -73,9 +80,11 @@ public:
*/
static uptr make(const uhd::device_addr_t& mb_args, const std::string& addr);
- /*** Init ****************************************************************/
+ /*** API *****************************************************************/
void init();
+ uhd::rfnoc::mb_iface& get_mb_iface();
+
/*** Public attributes ***************************************************/
//! These are the args given by the user, with some filtering/preprocessing
uhd::device_addr_t mb_args;
@@ -88,6 +97,12 @@ public:
// to be populated at all.
std::vector<uhd::device_addr_t> dboard_info;
+ //! Reference to this motherboards mb_iface
+ std::unique_ptr<mpmd_mb_iface> mb_iface;
+
+ //! Reference to this motherboards mb_controller
+ uhd::rfnoc::mpmd_mb_controller::sptr mb_ctrl;
+
/*! Reference to the RPC client for this motherboard
*
* We store a shared ptr, because we might share it with some of the RFNoC
@@ -95,41 +110,9 @@ public:
*/
uhd::rpc_client::sptr rpc;
- //! Number of RFNoC crossbars on this device
- const size_t num_xbars;
-
/*************************************************************************
* API
************************************************************************/
- //! Configure a crossbar to have a certain local address
- void set_xbar_local_addr(const size_t xbar_index, const size_t local_addr);
-
- //! Return the local address of a given crossbar
- size_t get_xbar_local_addr(const size_t xbar_index) const
- {
- return xbar_local_addrs.at(xbar_index);
- }
-
- //! Device-specific make_transport implementation
- //
- // A major difference to the mpmd_impl::make_transport() is the meaning of
- // the first argument (\p sid). mpmd_impl::make_transport() will add a
- // source part to the SID which needs to be taken into account in this
- // function.
- //
- // \param sid The full SID of this transport (UHD to device)
- // \param xport_type Transport type (CTRL, RX_DATA, ...)
- // \param args Any kind of args passed in via get_?x_stream()
- uhd::both_xports_t make_transport(const sid_t& sid,
- usrp::device3_impl::xport_type_t xport_type,
- const uhd::device_addr_t& args);
-
- size_t get_mtu(const uhd::direction_t dir) const;
-
-
- uhd::device_addr_t get_rx_hints() const;
- uhd::device_addr_t get_tx_hints() const;
-
/*! Setting this flag will enable a mode where a reclaim failure is
* acceptable.
*
@@ -177,18 +160,10 @@ private:
/*************************************************************************
* Private attributes
************************************************************************/
- //! Stores a list of local addresses of the crossbars. The local address is
- // what we use when addressing a crossbar in a CHDR header.
- std::vector<size_t> xbar_local_addrs;
-
/*! Continuously reclaims the device.
*/
uhd::task::sptr _claimer_task;
- uhd::mpmd::xport::mpmd_xport_mgr::uptr _xport_mgr;
- uhd::device_addr_t send_args;
- uhd::device_addr_t recv_args;
-
/*! This flag is only used within the claim() function. Go look there if you
* really need to know what it does.
*/
@@ -208,7 +183,7 @@ private:
* are taken care of by MPM itself, it is not necessary to write a specific
* derived class for every single type of MPM device.
*/
-class mpmd_impl : public uhd::usrp::device3_impl
+class mpmd_impl : public uhd::rfnoc::detail::rfnoc_device
{
public:
//! Device arg key which will allow finding all devices, even those not
@@ -242,17 +217,17 @@ public:
/**************************************************************************
* API
************************************************************************/
- uhd::both_xports_t make_transport(const uhd::sid_t&,
- uhd::usrp::device3_impl::xport_type_t,
- const uhd::device_addr_t&);
-
- //! get mtu
- size_t get_mtu(const size_t, const uhd::direction_t);
+ uhd::rfnoc::mb_iface& get_mb_iface(const size_t mb_idx)
+ {
+ if (mb_idx >= _mb.size()) {
+ throw uhd::index_error(
+ std::string("Cannot get mb_iface, invalid motherboard index: ")
+ + std::to_string(mb_idx));
+ }
+ return _mb.at(mb_idx)->get_mb_iface();
+ }
private:
- uhd::device_addr_t get_rx_hints(size_t mb_index);
- uhd::device_addr_t get_tx_hints(size_t mb_index);
-
/*************************************************************************
* Private methods/helpers
************************************************************************/
@@ -272,21 +247,7 @@ private:
* \param device_args Device args
*
*/
- void setup_mb(
- mpmd_mboard_impl* mb, const size_t mb_index, const size_t base_xport_addr);
-
- //! Setup all RFNoC blocks running on mboard \p mb_i
- void setup_rfnoc_blocks(
- mpmd_mboard_impl* mb, const size_t mb_i, const uhd::device_addr_t& block_args);
-
- //! Configure all blocks that require access to an RPC client
- void setup_rpc_blocks(
- const uhd::device_addr_t& block_args, const bool serialize_init);
-
- /*! Return the index of the motherboard given the local address of a
- * crossbar
- */
- size_t identify_mboard_by_xbar_addr(const size_t xbar_addr) const;
+ void setup_mb(mpmd_mboard_impl* mb, const size_t mb_index);
/*! Initialize property tree for a single device.
*
@@ -297,7 +258,6 @@ private:
static void init_property_tree(
uhd::property_tree::sptr tree, fs_path mb_path, mpmd_mboard_impl* mb);
-
/*************************************************************************
* Private attributes
************************************************************************/
diff --git a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_base.hpp b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_base.hpp
new file mode 100644
index 000000000..a9cb456e5
--- /dev/null
+++ b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_base.hpp
@@ -0,0 +1,56 @@
+//
+// Copyright 2017 Ettus Research, a National Instruments Company
+// Copyright 2019 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_MPMD_XPORT_CTRL_BASE_HPP
+#define INCLUDED_MPMD_XPORT_CTRL_BASE_HPP
+
+#include "mpmd_link_if_mgr.hpp"
+#include <uhd/types/device_addr.hpp>
+#include <uhdlib/rfnoc/chdr_packet.hpp>
+#include <uhdlib/transport/links.hpp>
+#include <memory>
+
+namespace uhd { namespace mpmd { namespace xport {
+
+/*! Transport manager implementation base
+ */
+class mpmd_link_if_ctrl_base
+{
+public:
+ using uptr = std::unique_ptr<mpmd_link_if_ctrl_base>;
+ virtual ~mpmd_link_if_ctrl_base() {}
+
+ virtual size_t get_num_links() const = 0;
+
+ /*! Return links object
+ *
+ * \param link_idx The number of the link to use. link_idx < get_num_links()
+ * must hold true. link_idx is often 0. Example: When
+ * the underlying transport is Ethernet, and the user
+ * specified both addr and second_addr, then get_num_links()
+ * equals 2 and link_idx can also be 1.
+ * \param link_type CTRL, RX_DATA, or TX_DATA (for configuring the link)
+ * \param link_args Link-specific additional information that the underlying
+ * mpmd_link_if_ctrl instantiation can use
+ */
+ virtual uhd::transport::both_links_t get_link(const size_t link_idx,
+ const uhd::transport::link_type_t link_type,
+ const uhd::device_addr_t& link_args) = 0;
+
+ //! Return the underlying link's MTU in bytes
+ virtual size_t get_mtu(const uhd::direction_t dir) const = 0;
+
+ //! Return the rate of the underlying link in bytes/sec
+ virtual double get_link_rate(const size_t link_idx) const = 0;
+
+ //! Get the packet factory associated with this link
+ virtual const uhd::rfnoc::chdr::chdr_packet_factory& get_packet_factory() const = 0;
+};
+
+}}} /* namespace uhd::mpmd::xport */
+
+#endif /* INCLUDED_MPMD_XPORT_CTRL_BASE_HPP */
diff --git a/host/lib/usrp/mpmd/mpmd_xport_ctrl_dpdk_udp.cpp b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.cpp
index 38d295728..baf0dde3e 100644
--- a/host/lib/usrp/mpmd/mpmd_xport_ctrl_dpdk_udp.cpp
+++ b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.cpp
@@ -5,8 +5,8 @@
//
#include "mpmd_impl.hpp"
-#include "mpmd_xport_mgr.hpp"
-#include "mpmd_xport_ctrl_dpdk_udp.hpp"
+#include "mpmd_link_if_mgr.hpp"
+#include "mpmd_link_if_ctrl_dpdk_udp.hpp"
#include <uhd/transport/udp_simple.hpp>
#include <uhd/transport/udp_constants.hpp>
#include <uhdlib/transport/dpdk_zero_copy.hpp>
@@ -161,7 +161,7 @@ size_t discover_mtu(
}
-mpmd_xport_ctrl_dpdk_udp::mpmd_xport_ctrl_dpdk_udp(
+mpmd_link_if_ctrl_dpdk_udp::mpmd_link_if_ctrl_dpdk_udp(
const uhd::device_addr_t& mb_args
) : _mb_args(mb_args)
, _ctx(uhd::transport::uhd_dpdk_ctx::get())
@@ -193,8 +193,8 @@ mpmd_xport_ctrl_dpdk_udp::mpmd_xport_ctrl_dpdk_udp(
}
uhd::both_xports_t
-mpmd_xport_ctrl_dpdk_udp::make_transport(
- mpmd_xport_mgr::xport_info_t &xport_info,
+mpmd_link_if_ctrl_dpdk_udp::make_transport(
+ mpmd_link_if_mgr::xport_info_t &xport_info,
const usrp::device3_impl::xport_type_t xport_type,
const uhd::device_addr_t& xport_args
) {
@@ -264,14 +264,14 @@ mpmd_xport_ctrl_dpdk_udp::make_transport(
return xports;
}
-bool mpmd_xport_ctrl_dpdk_udp::is_valid(
- const mpmd_xport_mgr::xport_info_t& xport_info
+bool mpmd_link_if_ctrl_dpdk_udp::is_valid(
+ const mpmd_link_if_mgr::xport_info_t& xport_info
) const {
int dpdk_port_id = _ctx.get_route(xport_info.at("ipv4"));
return (dpdk_port_id >= 0);
}
-size_t mpmd_xport_ctrl_dpdk_udp::get_mtu(const uhd::direction_t /*dir*/) const
+size_t mpmd_link_if_ctrl_dpdk_udp::get_mtu(const uhd::direction_t /*dir*/) const
{
return _mtu;
}
diff --git a/host/lib/usrp/mpmd/mpmd_xport_ctrl_dpdk_udp.hpp b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.hpp
index 943cd44d6..4423b4340 100644
--- a/host/lib/usrp/mpmd/mpmd_xport_ctrl_dpdk_udp.hpp
+++ b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.hpp
@@ -7,7 +7,7 @@
#ifndef INCLUDED_MPMD_XPORT_CTRL_DPDK_UDP_HPP
#define INCLUDED_MPMD_XPORT_CTRL_DPDK_UDP_HPP
-#include "mpmd_xport_ctrl_base.hpp"
+#include "mpmd_link_if_ctrl_base.hpp"
#include <uhd/types/device_addr.hpp>
#include <uhdlib/transport/dpdk_zero_copy.hpp>
#include "../device3/device3_impl.hpp"
@@ -18,21 +18,21 @@ namespace uhd { namespace mpmd { namespace xport {
*
* Opens UDP sockets
*/
-class mpmd_xport_ctrl_dpdk_udp : public mpmd_xport_ctrl_base
+class mpmd_link_if_ctrl_dpdk_udp : public mpmd_link_if_ctrl_base
{
public:
- mpmd_xport_ctrl_dpdk_udp(
+ mpmd_link_if_ctrl_dpdk_udp(
const uhd::device_addr_t& mb_args
);
both_xports_t make_transport(
- mpmd_xport_mgr::xport_info_t& xport_info,
+ mpmd_link_if_mgr::xport_info_t& xport_info,
const usrp::device3_impl::xport_type_t xport_type,
const uhd::device_addr_t& xport_args
);
bool is_valid(
- const mpmd_xport_mgr::xport_info_t& xport_info
+ const mpmd_link_if_mgr::xport_info_t& xport_info
) const;
size_t get_mtu(
diff --git a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_liberio.cpp b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_liberio.cpp
new file mode 100644
index 000000000..ed8f4395e
--- /dev/null
+++ b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_liberio.cpp
@@ -0,0 +1,135 @@
+//
+// Copyright 2017 Ettus Research, National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include "mpmd_link_if_ctrl_liberio.hpp"
+#include <uhd/rfnoc/constants.hpp>
+#include <uhd/utils/byteswap.hpp>
+#include <uhd/utils/log.hpp>
+#include <uhdlib/transport/inline_io_service.hpp>
+#include <uhdlib/transport/liberio_link.hpp>
+
+using namespace uhd;
+using namespace uhd::transport;
+using namespace uhd::mpmd::xport;
+
+const uhd::rfnoc::chdr::chdr_packet_factory mpmd_link_if_ctrl_liberio::_pkt_factory(
+ uhd::rfnoc::CHDR_W_64, ENDIANNESS_LITTLE);
+
+namespace {
+
+//! The default MTU will be this number times the page size
+const size_t LIBERIO_PAGES_PER_BUF = 2;
+//! The default MTU
+const size_t LIBERIO_DEFAULT_MTU = LIBERIO_PAGES_PER_BUF * getpagesize();
+//! The default link_rate (8 Bytes * 200 MHz)
+const double LIBERIO_DEFAULT_LINK_RATE = 200e6 * 8;
+//! Number of descriptors that liberio allocates (receive)
+const size_t LIBERIO_NUM_RECV_FRAMES = 128;
+//! Number of descriptors that liberio allocates (send)
+const size_t LIBERIO_NUM_SEND_FRAMES = 128;
+//! MTU for largest non-data packet accepted (arbitrarily-determined...)
+// Note: Management frames must fit here, and it determines the padded RX size
+const size_t LIBERIO_MAX_NONDATA_PACKET_SIZE = 128;
+
+std::vector<mpmd_link_if_ctrl_liberio::liberio_link_info_t>
+get_liberio_info_from_xport_info(
+ const mpmd_link_if_mgr::xport_info_list_t& link_info_list)
+{
+ std::vector<mpmd_link_if_ctrl_liberio::liberio_link_info_t> result;
+ for (const auto& link_info : link_info_list) {
+ if (!link_info.count("tx_dev")) {
+ UHD_LOG_ERROR("MPMD::XPORT::LIBERIO",
+ "Invalid response from get_chdr_link_options()! No `tx_dev' key!");
+ throw uhd::runtime_error(
+ "Invalid response from get_chdr_link_options()! No `tx_dev' key!");
+ }
+ if (!link_info.count("rx_dev")) {
+ UHD_LOG_ERROR("MPMD::XPORT::LIBERIO",
+ "Invalid response from get_chdr_link_options()! No `rx_dev' key!");
+ throw uhd::runtime_error(
+ "Invalid response from get_chdr_link_options()! No `rx_dev' key!");
+ }
+ const std::string tx_dev = link_info.at("tx_dev");
+ const std::string rx_dev = link_info.at("rx_dev");
+ result.emplace_back(
+ mpmd_link_if_ctrl_liberio::liberio_link_info_t{tx_dev, rx_dev});
+ }
+
+ return result;
+}
+
+} // namespace
+
+
+/******************************************************************************
+ * Structors
+ *****************************************************************************/
+mpmd_link_if_ctrl_liberio::mpmd_link_if_ctrl_liberio(const uhd::device_addr_t& mb_args,
+ const mpmd_link_if_mgr::xport_info_list_t& xport_info)
+ : _mb_args(mb_args)
+ , _recv_args(filter_args(mb_args, "recv"))
+ , _send_args(filter_args(mb_args, "send"))
+ , _dma_channels(get_liberio_info_from_xport_info(xport_info))
+ , _link_rate(LIBERIO_DEFAULT_LINK_RATE) // FIXME
+{
+ // nop
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+uhd::transport::both_links_t mpmd_link_if_ctrl_liberio::get_link(const size_t link_idx,
+ const uhd::transport::link_type_t link_type,
+ const uhd::device_addr_t& link_args)
+{
+ UHD_ASSERT_THROW(link_idx == 0);
+ if (_next_channel >= _dma_channels.size()) {
+ UHD_LOG_ERROR(
+ "MPMD::XPORT::LIBERIO", "Cannot create liberio link: DMA channels exhausted");
+ throw uhd::runtime_error("Cannot create liberio link: DMA channels exhausted");
+ }
+ auto link_info = _dma_channels.at(_next_channel++);
+
+ /* FIXME: Should have common infrastructure for creating I/O services */
+ auto io_srv = uhd::transport::inline_io_service::make();
+ link_params_t link_params;
+ if (link_type == link_type_t::RX_DATA) {
+ link_params.recv_frame_size = get_mtu(uhd::RX_DIRECTION); // FIXME
+ link_params.send_frame_size = LIBERIO_MAX_NONDATA_PACKET_SIZE; // FIXME
+ } else if (link_type == link_type_t::TX_DATA) {
+ link_params.recv_frame_size = LIBERIO_MAX_NONDATA_PACKET_SIZE; // FIXME
+ link_params.send_frame_size = get_mtu(uhd::TX_DIRECTION); // FIXME
+ } else {
+ link_params.recv_frame_size = LIBERIO_MAX_NONDATA_PACKET_SIZE; // FIXME
+ link_params.send_frame_size = LIBERIO_MAX_NONDATA_PACKET_SIZE; // FIXME
+ }
+ link_params.num_recv_frames = LIBERIO_NUM_RECV_FRAMES; // FIXME
+ link_params.num_send_frames = LIBERIO_NUM_SEND_FRAMES; // FIXME
+
+ // Liberio doesn't need in-band flow control, so pretend have very large buffers
+ link_params.recv_buff_size = std::numeric_limits<size_t>::max();
+ link_params.send_buff_size = std::numeric_limits<size_t>::max();
+ auto link = uhd::transport::liberio_link::make(
+ link_info.first, link_info.second, link_params);
+ io_srv->attach_send_link(link);
+ io_srv->attach_recv_link(link);
+ return std::tuple<io_service::sptr,
+ send_link_if::sptr,
+ size_t,
+ recv_link_if::sptr,
+ size_t,
+ bool>(io_srv,
+ link,
+ link_params.send_buff_size,
+ link,
+ link_params.recv_buff_size,
+ false);
+}
+
+size_t mpmd_link_if_ctrl_liberio::get_mtu(const uhd::direction_t /*dir*/) const
+{
+ return LIBERIO_DEFAULT_MTU; // FIXME
+}
diff --git a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_liberio.hpp b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_liberio.hpp
new file mode 100644
index 000000000..09fb24f8e
--- /dev/null
+++ b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_liberio.hpp
@@ -0,0 +1,64 @@
+//
+// Copyright 2017 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_MPMD_XPORT_CTRL_LIBERIO_HPP
+#define INCLUDED_MPMD_XPORT_CTRL_LIBERIO_HPP
+
+#include "mpmd_link_if_ctrl_base.hpp"
+#include <uhd/types/device_addr.hpp>
+
+namespace uhd { namespace mpmd { namespace xport {
+
+/*! Liberio transport manager
+ */
+class mpmd_link_if_ctrl_liberio : public mpmd_link_if_ctrl_base
+{
+public:
+ /* For liberio, get_chdr_link_options returns information about DMA engines.
+ * We assume there is only ever one liberio link available
+ * first = tx path
+ * second = rx path
+ */
+ using liberio_link_info_t = std::pair<std::string, std::string>;
+
+ mpmd_link_if_ctrl_liberio(const uhd::device_addr_t& mb_args,
+ const mpmd_link_if_mgr::xport_info_list_t& xport_info);
+
+ size_t get_num_links() const { return 1; }
+
+ uhd::transport::both_links_t get_link(
+ const size_t link_idx, const uhd::transport::link_type_t link_type,
+ const uhd::device_addr_t& link_args);
+
+ size_t get_mtu(const uhd::direction_t) const;
+
+ double get_link_rate(const size_t /*link_idx*/) const { return _link_rate; }
+
+ const uhd::rfnoc::chdr::chdr_packet_factory& get_packet_factory() const
+ {
+ return _pkt_factory;
+ }
+
+private:
+
+ const uhd::device_addr_t _mb_args;
+ const uhd::dict<std::string, std::string> _recv_args;
+ const uhd::dict<std::string, std::string> _send_args;
+ //! A list of DMA channels we can use for links
+ std::vector<liberio_link_info_t> _dma_channels;
+ double _link_rate;
+
+ /*! An index representing the next DMA channel to use, for a simple
+ * allocation of channels. For get_link(), increment for each new link, and
+ * throw an exception if _next_channel > number of DMA channels.
+ */
+ size_t _next_channel = 0;
+ static const uhd::rfnoc::chdr::chdr_packet_factory _pkt_factory;
+};
+
+}}} /* namespace uhd::mpmd::xport */
+
+#endif /* INCLUDED_MPMD_XPORT_CTRL_LIBERIO_HPP */
diff --git a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.cpp b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.cpp
new file mode 100644
index 000000000..c2d746f92
--- /dev/null
+++ b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.cpp
@@ -0,0 +1,279 @@
+//
+// Copyright 2017 Ettus Research, National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include "mpmd_link_if_ctrl_udp.hpp"
+#include "mpmd_impl.hpp"
+#include "mpmd_link_if_mgr.hpp"
+#include <uhd/transport/udp_constants.hpp>
+#include <uhd/transport/udp_simple.hpp>
+#include <uhd/transport/udp_zero_copy.hpp>
+#include <uhdlib/transport/inline_io_service.hpp>
+#include <uhdlib/transport/udp_boost_asio_link.hpp>
+#include <uhdlib/utils/narrow.hpp>
+#include <string>
+
+using namespace uhd;
+using namespace uhd::transport;
+using namespace uhd::mpmd::xport;
+
+const uhd::rfnoc::chdr::chdr_packet_factory mpmd_link_if_ctrl_udp::_pkt_factory(
+ uhd::rfnoc::CHDR_W_64, ENDIANNESS_BIG);
+
+namespace {
+
+//! Maximum CHDR packet size in bytes
+const size_t MPMD_10GE_DATA_FRAME_MAX_SIZE = 8000;
+
+//! Maximum CHDR packet size in bytes
+const size_t MPMD_10GE_ASYNCMSG_FRAME_MAX_SIZE = 1472;
+
+//! Number of send/recv frames
+const size_t MPMD_ETH_NUM_FRAMES = 32;
+
+//!
+const double MPMD_BUFFER_DEPTH = 20.0e-3; // s
+//! For MTU discovery, the time we wait for a packet before calling it
+// oversized (seconds).
+const double MPMD_MTU_DISCOVERY_TIMEOUT = 0.02;
+
+// TODO: move these to appropriate header file for all other devices
+const size_t MAX_RATE_1GIGE = 1e9 / 8; // byte/s
+const size_t MAX_RATE_10GIGE = 10e9 / 8; // byte/s
+
+
+mpmd_link_if_ctrl_udp::udp_link_info_map get_udp_info_from_xport_info(
+ const mpmd_link_if_mgr::xport_info_list_t& link_info_list)
+{
+ mpmd_link_if_ctrl_udp::udp_link_info_map result;
+ for (const auto& link_info : link_info_list) {
+ if (!link_info.count("ipv4")) {
+ UHD_LOG_ERROR("MPMD::XPORT::UDP",
+ "Invalid response from get_chdr_link_options()! No `ipv4' key!");
+ throw uhd::runtime_error(
+ "Invalid response from get_chdr_link_options()! No `ipv4' key!");
+ }
+ if (!link_info.count("port")) {
+ UHD_LOG_ERROR("MPMD::XPORT::UDP",
+ "Invalid response from get_chdr_link_options()! No `port' key!");
+ throw uhd::runtime_error(
+ "Invalid response from get_chdr_link_options()! No `port' key!");
+ }
+ const std::string udp_port = link_info.at("port");
+ const size_t link_rate = link_info.count("link_rate")
+ ? std::stoul(link_info.at("link_rate"))
+ : MAX_RATE_1GIGE;
+ result.emplace(link_info.at("ipv4"),
+ mpmd_link_if_ctrl_udp::udp_link_info_t{udp_port, link_rate});
+ }
+
+ return result;
+}
+
+std::vector<std::string> get_addrs_from_mb_args(const uhd::device_addr_t& mb_args,
+ const mpmd_link_if_ctrl_udp::udp_link_info_map& link_info_list)
+{
+ // mb_args must always include addr
+ if (not mb_args.has_key(FIRST_ADDR_KEY)) {
+ UHD_LOG_WARNING("MPMD::XPORT::UDP",
+ "The `" << FIRST_ADDR_KEY
+ << "' key must be specified in "
+ "device args to create an Ethernet transport to an RFNoC block");
+ return {};
+ }
+ std::vector<std::string> addrs{mb_args[FIRST_ADDR_KEY]};
+ if (mb_args.has_key(SECOND_ADDR_KEY)) {
+ addrs.push_back(mb_args[SECOND_ADDR_KEY]);
+ }
+ // This is where in UHD we encode the knowledge about what
+ // get_chdr_link_options() returns to us.
+ for (const auto& ip_addr : addrs) {
+ if (link_info_list.count(ip_addr)) {
+ continue;
+ }
+ UHD_LOG_WARNING("MPMD::XPORT::UDP",
+ "Cannot create UDP link to device: The IP address `"
+ << ip_addr << "' is requested, but not reachable.");
+ return {};
+ }
+
+ return addrs;
+}
+
+/*! Do a binary search to discover MTU
+ *
+ * Uses the MPM echo service to figure out MTU. We simply send a bunch of
+ * packets and see if they come back until we converged on the path MTU.
+ * The end result must lie between \p min_frame_size and \p max_frame_size.
+ *
+ * \param address IP address
+ * \param port UDP port (yeah it's a string!)
+ * \param min_frame_size Minimum frame size, initialize algorithm to start
+ * with this value
+ * \param max_frame_size Maximum frame size, initialize algorithm to start
+ * with this value
+ * \param echo_timeout Timeout value in seconds. For frame sizes that
+ * exceed the MTU, we don't expect a response, and this
+ * is the amount of time we'll wait before we assume
+ * the frame size exceeds the MTU.
+ */
+size_t discover_mtu(const std::string& address,
+ const std::string& port,
+ size_t min_frame_size,
+ size_t max_frame_size,
+ const double echo_timeout = 0.020)
+{
+ const size_t echo_prefix_offset = uhd::mpmd::mpmd_impl::MPM_ECHO_CMD.size();
+ const size_t mtu_hdr_len = echo_prefix_offset + 10;
+ UHD_ASSERT_THROW(min_frame_size < max_frame_size);
+ UHD_ASSERT_THROW(min_frame_size % 4 == 0);
+ UHD_ASSERT_THROW(max_frame_size % 4 == 0);
+ UHD_ASSERT_THROW(min_frame_size >= echo_prefix_offset + mtu_hdr_len);
+ using namespace uhd::transport;
+ // The return port will probably differ from the discovery port, so we
+ // need a "broadcast" UDP connection; using make_connected() would
+ // drop packets
+ udp_simple::sptr udp = udp_simple::make_broadcast(address, port);
+ std::string send_buf(uhd::mpmd::mpmd_impl::MPM_ECHO_CMD);
+ send_buf.resize(max_frame_size, '#');
+ UHD_ASSERT_THROW(send_buf.size() == max_frame_size);
+ std::vector<uint8_t> recv_buf;
+ recv_buf.resize(max_frame_size, ' ');
+
+ // Little helper to check returned packets match the sent ones
+ auto require_bufs_match = [&recv_buf, &send_buf, mtu_hdr_len](const size_t len) {
+ if (len < mtu_hdr_len
+ or std::memcmp((void*)&recv_buf[0], (void*)&send_buf[0], mtu_hdr_len) != 0) {
+ throw uhd::runtime_error("Unexpected content of MTU "
+ "discovery return packet!");
+ }
+ };
+ UHD_LOG_TRACE("MPMD", "Determining UDP MTU... ");
+ size_t seq_no = 0;
+ while (min_frame_size < max_frame_size) {
+ // Only test multiples of 4 bytes!
+ const size_t test_frame_size = (max_frame_size / 2 + min_frame_size / 2 + 3)
+ & ~size_t(3);
+ // Encode sequence number and current size in the string, makes it
+ // easy to debug in code or Wireshark. Is also used for identifying
+ // response packets.
+ std::sprintf(
+ &send_buf[echo_prefix_offset], ";%04lu,%04lu", seq_no++, test_frame_size);
+ UHD_LOG_TRACE("MPMD", "Testing frame size " << test_frame_size);
+ udp->send(boost::asio::buffer(&send_buf[0], test_frame_size));
+
+ const size_t len = udp->recv(boost::asio::buffer(recv_buf), echo_timeout);
+ if (len == 0) {
+ // Nothing received, so this is probably too big
+ max_frame_size = test_frame_size - 4;
+ } else if (len >= test_frame_size) {
+ // Size went through, so bump the minimum
+ require_bufs_match(len);
+ min_frame_size = test_frame_size;
+ } else if (len < test_frame_size) {
+ // This is an odd case. Something must have snipped the packet
+ // on the way back. Still, we'll just back off and try
+ // something smaller.
+ UHD_LOG_DEBUG("MPMD", "Unexpected packet truncation during MTU discovery.");
+ require_bufs_match(len);
+ max_frame_size = len;
+ }
+ }
+ UHD_LOG_DEBUG("MPMD", "Path MTU for address " << address << ": " << min_frame_size);
+ return min_frame_size;
+}
+
+} // namespace
+
+
+/******************************************************************************
+ * Structors
+ *****************************************************************************/
+mpmd_link_if_ctrl_udp::mpmd_link_if_ctrl_udp(const uhd::device_addr_t& mb_args,
+ const mpmd_link_if_mgr::xport_info_list_t& xport_info)
+ : _mb_args(mb_args)
+ , _recv_args(filter_args(mb_args, "recv"))
+ , _send_args(filter_args(mb_args, "send"))
+ , _udp_info(get_udp_info_from_xport_info(xport_info))
+ , _mtu(MPMD_10GE_DATA_FRAME_MAX_SIZE)
+{
+ const std::string mpm_discovery_port = _mb_args.get(
+ mpmd_impl::MPM_DISCOVERY_PORT_KEY, std::to_string(mpmd_impl::MPM_DISCOVERY_PORT));
+ auto discover_mtu_for_ip = [mpm_discovery_port](const std::string& ip_addr) {
+ return discover_mtu(ip_addr,
+ mpm_discovery_port,
+ IP_PROTOCOL_MIN_MTU_SIZE - IP_PROTOCOL_UDP_PLUS_IP_HEADER,
+ MPMD_10GE_DATA_FRAME_MAX_SIZE,
+ MPMD_MTU_DISCOVERY_TIMEOUT);
+ };
+
+ const std::vector<std::string> requested_addrs(
+ get_addrs_from_mb_args(mb_args, _udp_info));
+ for (const auto& ip_addr : requested_addrs) {
+ try {
+ // If MTU discovery fails, we gracefully recover, but declare that
+ // link invalid.
+ _mtu = std::min(_mtu, discover_mtu_for_ip(ip_addr));
+ _available_addrs.push_back(ip_addr);
+ } catch (const uhd::exception& ex) {
+ UHD_LOG_WARNING("MPMD::XPORT::UDP",
+ "Error during MTU discovery on address " << ip_addr << ": " << ex.what());
+ }
+ }
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+uhd::transport::both_links_t mpmd_link_if_ctrl_udp::get_link(const size_t link_idx,
+ const uhd::transport::link_type_t /*link_type*/,
+ const uhd::device_addr_t& /*link_args*/)
+{
+ UHD_ASSERT_THROW(link_idx < _available_addrs.size());
+ const std::string ip_addr = _available_addrs.at(link_idx);
+ const std::string udp_port = _udp_info.at(ip_addr).udp_port;
+
+ /* FIXME: Should have common infrastructure for creating I/O services */
+ auto io_srv = uhd::transport::inline_io_service::make();
+ link_params_t link_params;
+ link_params.num_recv_frames = MPMD_ETH_NUM_FRAMES; // FIXME
+ link_params.num_send_frames = MPMD_ETH_NUM_FRAMES; // FIXME
+ link_params.recv_frame_size = get_mtu(uhd::RX_DIRECTION); // FIXME
+ link_params.send_frame_size = get_mtu(uhd::TX_DIRECTION); // FIXME
+ link_params.recv_buff_size = MPMD_BUFFER_DEPTH * MAX_RATE_10GIGE; // FIXME
+ link_params.send_buff_size = MPMD_BUFFER_DEPTH * MAX_RATE_10GIGE; // FIXME
+ auto link = uhd::transport::udp_boost_asio_link::make(ip_addr,
+ udp_port,
+ link_params,
+ link_params.recv_buff_size, // FIXME
+ link_params.send_buff_size); // FIXME
+ io_srv->attach_send_link(link);
+ io_srv->attach_recv_link(link);
+ return std::tuple<io_service::sptr,
+ send_link_if::sptr,
+ size_t,
+ recv_link_if::sptr,
+ size_t,
+ bool>(
+ io_srv, link, link_params.send_buff_size, link, link_params.recv_buff_size, true);
+}
+
+size_t mpmd_link_if_ctrl_udp::get_num_links() const
+{
+ return _available_addrs.size();
+}
+
+//! Return the rate of the underlying link in bytes/sec
+double mpmd_link_if_ctrl_udp::get_link_rate(const size_t link_idx) const
+{
+ UHD_ASSERT_THROW(link_idx < get_num_links());
+ return _udp_info.at(_available_addrs.at(link_idx)).link_rate;
+}
+
+const uhd::rfnoc::chdr::chdr_packet_factory&
+mpmd_link_if_ctrl_udp::get_packet_factory() const
+{
+ return _pkt_factory;
+}
diff --git a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.hpp b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.hpp
new file mode 100644
index 000000000..4c8ecade7
--- /dev/null
+++ b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.hpp
@@ -0,0 +1,61 @@
+//
+// Copyright 2017 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_MPMD_XPORT_CTRL_UDP_HPP
+#define INCLUDED_MPMD_XPORT_CTRL_UDP_HPP
+
+#include "mpmd_link_if_ctrl_base.hpp"
+#include "mpmd_link_if_mgr.hpp"
+#include <uhd/types/device_addr.hpp>
+#include <unordered_map>
+
+namespace uhd { namespace mpmd { namespace xport {
+
+/*! UDP link interface controller
+ *
+ * Opens UDP sockets
+ */
+class mpmd_link_if_ctrl_udp : public mpmd_link_if_ctrl_base
+{
+public:
+ struct udp_link_info_t
+ {
+ std::string udp_port;
+ size_t link_rate;
+ };
+
+ using udp_link_info_map = std::unordered_map<std::string, udp_link_info_t>;
+
+ mpmd_link_if_ctrl_udp(const uhd::device_addr_t& mb_args,
+ const mpmd_link_if_mgr::xport_info_list_t& xport_info);
+
+ size_t get_num_links() const;
+ uhd::transport::both_links_t get_link(const size_t link_idx,
+ const uhd::transport::link_type_t link_type,
+ const uhd::device_addr_t& link_args);
+ size_t get_mtu(const uhd::direction_t) const
+ {
+ return _mtu;
+ }
+ double get_link_rate(const size_t link_idx) const;
+ const uhd::rfnoc::chdr::chdr_packet_factory& get_packet_factory() const;
+
+private:
+ const uhd::device_addr_t _mb_args;
+ const uhd::dict<std::string, std::string> _recv_args;
+ const uhd::dict<std::string, std::string> _send_args;
+ //!
+ udp_link_info_map _udp_info;
+ //! A list of IP addresses we can connect our CHDR connections to
+ std::vector<std::string> _available_addrs;
+ //! MTU
+ size_t _mtu;
+ static const uhd::rfnoc::chdr::chdr_packet_factory _pkt_factory;
+};
+
+}}} /* namespace uhd::mpmd::xport */
+
+#endif /* INCLUDED_MPMD_XPORT_CTRL_UDP_HPP */
diff --git a/host/lib/usrp/mpmd/mpmd_link_if_mgr.cpp b/host/lib/usrp/mpmd/mpmd_link_if_mgr.cpp
new file mode 100644
index 000000000..6bb6cae3a
--- /dev/null
+++ b/host/lib/usrp/mpmd/mpmd_link_if_mgr.cpp
@@ -0,0 +1,135 @@
+//
+// Copyright 2017 Ettus Research, National Instruments Company
+// Copyright 2019 Ettus Research, National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include "mpmd_link_if_mgr.hpp"
+#include "mpmd_impl.hpp"
+#include "mpmd_link_if_ctrl_base.hpp"
+#include "mpmd_link_if_ctrl_udp.hpp"
+#ifdef HAVE_LIBERIO
+# include "mpmd_link_if_ctrl_liberio.hpp"
+#endif
+#ifdef HAVE_DPDK
+# include "mpmd_link_if_ctrl_dpdk_udp.hpp"
+#endif
+
+uhd::dict<std::string, std::string> uhd::mpmd::xport::filter_args(
+ const uhd::device_addr_t& args, const std::string& prefix)
+{
+ uhd::dict<std::string, std::string> filtered_args;
+ for (const std::string& key : args.keys()) {
+ if (key.find(prefix) != std::string::npos) {
+ filtered_args[key] = args[key];
+ }
+ }
+
+ return filtered_args;
+}
+
+using namespace uhd::mpmd::xport;
+
+class mpmd_link_if_mgr_impl : public mpmd_link_if_mgr
+{
+public:
+ mpmd_link_if_mgr_impl(const uhd::device_addr_t& mb_args) : _mb_args(mb_args) {}
+
+ /**************************************************************************
+ * API (see mpmd_link_if_mgr.hpp)
+ *************************************************************************/
+ bool connect(const std::string& link_type, const xport_info_list_t& xport_info)
+ {
+ auto link_if_ctrl = make_link_if_ctrl(link_type, xport_info);
+ if (!link_if_ctrl) {
+ UHD_LOG_WARNING(
+ "MPMD::XPORT", "Unable to create xport ctrl for link type " << link_type);
+ return false;
+ }
+ if (link_if_ctrl->get_num_links() == 0) {
+ UHD_LOG_TRACE("MPMD::XPORT",
+ "Link type " << link_type
+ << " has no valid links in this configuration.");
+ return false;
+ }
+ const size_t xport_idx = _link_if_ctrls.size();
+ for (size_t link_idx = 0; link_idx < link_if_ctrl->get_num_links(); link_idx++) {
+ _link_link_if_ctrl_map.push_back(std::make_pair(xport_idx, link_idx));
+ }
+ _link_if_ctrls.push_back(std::move(link_if_ctrl));
+ return true;
+ }
+
+ size_t get_num_links()
+ {
+ return _link_link_if_ctrl_map.size();
+ }
+
+ uhd::transport::both_links_t get_link(const size_t link_idx,
+ const uhd::transport::link_type_t link_type,
+ const uhd::device_addr_t& link_args)
+ {
+ const size_t link_if_ctrl_idx = _link_link_if_ctrl_map.at(link_idx).first;
+ const size_t xport_link_idx = _link_link_if_ctrl_map.at(link_idx).second;
+ return _link_if_ctrls.at(link_if_ctrl_idx)
+ ->get_link(xport_link_idx, link_type, link_args);
+ }
+
+ size_t get_mtu(const size_t link_idx, const uhd::direction_t dir) const
+ {
+ return _link_if_ctrls.at(_link_link_if_ctrl_map.at(link_idx).first)->get_mtu(dir);
+ }
+
+ const uhd::rfnoc::chdr::chdr_packet_factory& get_packet_factory(
+ const size_t link_idx) const
+ {
+ const size_t link_if_ctrl_idx = _link_link_if_ctrl_map.at(link_idx).first;
+ return _link_if_ctrls.at(link_if_ctrl_idx)->get_packet_factory();
+ }
+
+private:
+ /**************************************************************************
+ * Private methods / helpers
+ *************************************************************************/
+ mpmd_link_if_ctrl_base::uptr make_link_if_ctrl(
+ const std::string& link_type, const xport_info_list_t& xport_info)
+ {
+ // Here, we hard-code the list of available transport types
+ if (link_type == "udp") {
+#ifdef HAVE_DPDK
+ // if (_mb_args.has_key("use_dpdk")) {
+ // return std::make_unique<mpmd_link_if_ctrl_dpdk_udp>(_mb_args,
+ // xport_info);
+ //}
+#endif
+ return std::make_unique<mpmd_link_if_ctrl_udp>(_mb_args, xport_info);
+#ifdef HAVE_LIBERIO
+ } else if (link_type == "liberio") {
+ return std::make_unique<mpmd_link_if_ctrl_liberio>(_mb_args, xport_info);
+#endif
+ }
+ UHD_LOG_WARNING("MPMD", "Cannot instantiate transport medium " << link_type);
+ return nullptr;
+ }
+
+ /**************************************************************************
+ * Private attributes
+ *************************************************************************/
+ //! Cache available xport manager implementations
+ //
+ // Should only every be populated by connect()
+ std::vector<mpmd_link_if_ctrl_base::uptr> _link_if_ctrls;
+ // Maps link index to link_if_ctrl index. To look up the xport ctrl for link
+ // number L, do something like this:
+ // auto& link_if_ctrl = _link_if_ctrls.at(_link_link_if_ctrl_map.at(L).first);
+ std::vector<std::pair<size_t, size_t>> _link_link_if_ctrl_map;
+
+ //! Motherboard args, can contain things like 'recv_buff_size'
+ const uhd::device_addr_t _mb_args;
+};
+
+mpmd_link_if_mgr::uptr mpmd_link_if_mgr::make(const uhd::device_addr_t& mb_args)
+{
+ return std::make_unique<mpmd_link_if_mgr_impl>(mb_args);
+}
diff --git a/host/lib/usrp/mpmd/mpmd_xport_mgr.hpp b/host/lib/usrp/mpmd/mpmd_link_if_mgr.hpp
index 3d96e5ec6..4b0ba4212 100644
--- a/host/lib/usrp/mpmd/mpmd_xport_mgr.hpp
+++ b/host/lib/usrp/mpmd/mpmd_link_if_mgr.hpp
@@ -4,11 +4,14 @@
// SPDX-License-Identifier: GPL-3.0-or-later
//
-#ifndef INCLUDED_MPMD_XPORT_MGR_HPP
-#define INCLUDED_MPMD_XPORT_MGR_HPP
+#ifndef INCLUDED_MPMD_LINK_IF_MGR_HPP
+#define INCLUDED_MPMD_LINK_IF_MGR_HPP
-#include "../device3/device3_impl.hpp"
+#include <uhd/types/device_addr.hpp>
#include <uhd/types/dict.hpp>
+#include <uhd/types/direction.hpp>
+#include <uhdlib/rfnoc/chdr_packet.hpp>
+#include <uhdlib/transport/links.hpp>
#include <map>
#include <memory>
#include <string>
@@ -20,8 +23,6 @@ namespace uhd { namespace mpmd { namespace xport {
* Transport specifiers
*/
-//! Ethernet address for management and RPC communication
-const std::string MGMT_ADDR_KEY = "mgmt_addr";
//! Primary Ethernet address for streaming and RFNoC communication
const std::string FIRST_ADDR_KEY = "addr";
//! Secondary Ethernet address for streaming and RFNoC communication
@@ -45,13 +46,13 @@ uhd::dict<std::string, std::string> filter_args(
* medium. For example, if the medium is Ethernet/UDP, this class will create
* sockets.
*/
-class mpmd_xport_mgr
+class mpmd_link_if_mgr
{
public:
- using uptr = std::unique_ptr<mpmd_xport_mgr>;
+ using uptr = std::unique_ptr<mpmd_link_if_mgr>;
using xport_info_t = std::map<std::string, std::string>;
using xport_info_list_t = std::vector<std::map<std::string, std::string>>;
- virtual ~mpmd_xport_mgr() {}
+ virtual ~mpmd_link_if_mgr() {}
/*! Return a reference to a transport manager
*
@@ -65,6 +66,45 @@ public:
*/
static uptr make(const uhd::device_addr_t& mb_args);
+ /*! Attempt to open a CHDR-capable link to the remote device
+ *
+ * This will compare the mb_args (passed in at construction) with
+ * \p xport_info to see if it can connect this way. For example, if
+ * \p xport_type is "udp", then it will see if it can find the `addr` key
+ * from mb_args in the \p xport_info. If yes, it will use that for
+ * connections.
+ *
+ * \param xport_type The type of xport ("udp", "liberio", ...)
+ * \param xport_info The available information on this transport. For
+ * example, if the xport_type is "udp", then this would
+ * contain the available IP addresses.
+ * \returns true on success
+ */
+ virtual bool connect(
+ const std::string& xport_type, const xport_info_list_t& xport_info) = 0;
+
+ /*! The number of available links
+ *
+ * If zero, it means that there is no valid connection to the device.
+ *
+ */
+ virtual size_t get_num_links() = 0;
+
+ /*! Return links object
+ *
+ * \param link_idx The number of the link to use. link_idx < get_num_links()
+ * must hold true. link_idx is often 0. Example: When
+ * the underlying transport is Ethernet, and the user
+ * specified both addr and second_addr, then get_num_links()
+ * equals 2 and link_idx can also be 1.
+ * \param link_type CTRL, RX_DATA, or TX_DATA (for configuring the link)
+ * \param link_args Link-specific additional information that the underlying
+ * mpmd_link_if_ctrl instantiation can use
+ */
+ virtual uhd::transport::both_links_t get_link(const size_t link_idx,
+ const uhd::transport::link_type_t link_type,
+ const uhd::device_addr_t& link_args) = 0;
+
/*! Create a transports object
*
* Implementation details depend on the underlying implementation.
@@ -90,16 +130,28 @@ public:
* The latter needs to get sent back to MPM to complete the
* transport handshake.
*/
- virtual both_xports_t make_transport(const xport_info_list_t& xport_info_list,
- const usrp::device3_impl::xport_type_t xport_type,
- const uhd::device_addr_t& xport_args,
- xport_info_t& xport_info_out) = 0;
+ //virtual both_xports_t make_transport(const xport_info_list_t& xport_info_list,
+ //const usrp::device3_impl::xport_type_t xport_type,
+ //const uhd::device_addr_t& xport_args,
+ //xport_info_t& xport_info_out) = 0;
/*! Return the path MTU for whatever this manager lets us do
*/
- virtual size_t get_mtu(const uhd::direction_t dir) const = 0;
+ virtual size_t get_mtu(const size_t link_idx, const uhd::direction_t dir) const = 0;
+
+ /*! Get packet factory from associated link_mgr
+ *
+ * \param link_idx The number of the link to use. link_idx < get_num_links()
+ * must hold true. link_idx is often 0. Example: When
+ * the underlying transport is Ethernet, and the user
+ * specified both addr and second_addr, then get_num_links()
+ * equals 2 and link_idx can also be 1.
+ * \return a CHDR packet factory
+ */
+ virtual const uhd::rfnoc::chdr::chdr_packet_factory& get_packet_factory(
+ const size_t link_idx) const = 0;
};
}}} /* namespace uhd::mpmd::xport */
-#endif /* INCLUDED_MPMD_XPORT_MGR_HPP */
+#endif /* INCLUDED_MPMD_LINK_IF_MGR_HPP */
diff --git a/host/lib/usrp/mpmd/mpmd_mb_controller.cpp b/host/lib/usrp/mpmd/mpmd_mb_controller.cpp
index 6c2954fb8..e9310d01d 100644
--- a/host/lib/usrp/mpmd/mpmd_mb_controller.cpp
+++ b/host/lib/usrp/mpmd/mpmd_mb_controller.cpp
@@ -4,11 +4,34 @@
// SPDX-License-Identifier: GPL-3.0-or-later
//
-#include "mpmd_mb_controller.hpp"
+#include <uhdlib/usrp/common/mpmd_mb_controller.hpp>
using namespace uhd::rfnoc;
+using namespace uhd;
+namespace {
+ //! Default timeout value for tRPC calls that we know can take long (ms)
+ constexpr size_t MPMD_DEFAULT_LONG_TIMEOUT = 12000; // ms
+}
+
+mpmd_mb_controller::mpmd_mb_controller(
+ uhd::rpc_client::sptr rpcc, uhd::device_addr_t device_info)
+ : _rpc(rpcc), _device_info(device_info)
+{
+ const size_t num_tks = _rpc->request_with_token<size_t>("get_num_timekeepers");
+ for (size_t tk_idx = 0; tk_idx < num_tks; tk_idx++) {
+ register_timekeeper(tk_idx, std::make_shared<mpmd_timekeeper>(tk_idx, _rpc));
+ }
+
+ auto sensor_list =
+ _rpc->request_with_token<std::vector<std::string>>("get_mb_sensors");
+ UHD_LOG_DEBUG("MPMD", "Found " << sensor_list.size() << " motherboard sensors.");
+ _sensor_names.insert(sensor_list.cbegin(), sensor_list.cend());
+}
+/******************************************************************************
+ * Timekeeper API
+ *****************************************************************************/
uint64_t mpmd_mb_controller::mpmd_timekeeper::get_ticks_now()
{
return _rpc->request_with_token<uint64_t>("get_timekeeper_time", _tk_idx, false);
@@ -34,3 +57,120 @@ void mpmd_mb_controller::mpmd_timekeeper::set_period(const uint64_t period_ns)
_rpc->notify_with_token("set_tick_period", _tk_idx, period_ns);
}
+void mpmd_mb_controller::mpmd_timekeeper::update_tick_rate(const double tick_rate)
+{
+ set_tick_rate(tick_rate);
+}
+
+/******************************************************************************
+ * Motherboard Control API (see mb_controller.hpp)
+ *****************************************************************************/
+std::string mpmd_mb_controller::get_mboard_name() const
+{
+ return _device_info.get("name", "UNKNOWN");
+}
+
+void mpmd_mb_controller::set_time_source(const std::string& source)
+{
+ _rpc->notify_with_token(MPMD_DEFAULT_LONG_TIMEOUT, "set_time_source", source);
+}
+
+std::string mpmd_mb_controller::get_time_source() const
+{
+ return _rpc->request_with_token<std::string>("get_time_source");
+}
+
+std::vector<std::string> mpmd_mb_controller::get_time_sources() const
+{
+ return _rpc->request_with_token<std::vector<std::string>>("get_time_sources");
+}
+
+void mpmd_mb_controller::set_clock_source(const std::string& source)
+{
+ _rpc->notify_with_token(MPMD_DEFAULT_LONG_TIMEOUT, "set_clock_source", source);
+}
+
+std::string mpmd_mb_controller::get_clock_source() const
+{
+ return _rpc->request_with_token<std::string>("get_clock_source");
+}
+
+std::vector<std::string> mpmd_mb_controller::get_clock_sources() const
+{
+ return _rpc->request_with_token<std::vector<std::string>>("get_clock_sources");
+}
+
+void mpmd_mb_controller::set_sync_source(const std::string& clock_source, const std::string& time_source)
+{
+ uhd::device_addr_t sync_source;
+ sync_source["clock_source"] = clock_source;
+ sync_source["time_source"] = time_source;
+ set_sync_source(sync_source);
+}
+
+void mpmd_mb_controller::set_sync_source(const device_addr_t& sync_source)
+{
+ std::map<std::string, std::string> sync_source_map;
+ for (const auto& key : sync_source.keys()) {
+ sync_source_map[key] = sync_source.get(key);
+ }
+ _rpc->notify_with_token(
+ MPMD_DEFAULT_LONG_TIMEOUT, "set_clock_source", sync_source_map);
+}
+
+device_addr_t mpmd_mb_controller::get_sync_source() const
+{
+ const auto sync_source_map =
+ _rpc->request_with_token<std::map<std::string, std::string>>("get_sync_source");
+ return device_addr_t(sync_source_map);
+}
+
+std::vector<device_addr_t> mpmd_mb_controller::get_sync_sources()
+{
+ std::vector<device_addr_t> result;
+ const auto sync_sources =
+ _rpc->request_with_token<std::vector<std::map<std::string, std::string>>>(
+ "get_sync_sources");
+ for (auto& sync_source : sync_sources) {
+ result.push_back(device_addr_t(sync_source));
+ }
+
+ return result;
+}
+
+void mpmd_mb_controller::set_clock_source_out(const bool /*enb*/)
+{
+ throw uhd::not_implemented_error(
+ "set_clock_source_out() not implemented on this device!");
+}
+
+void mpmd_mb_controller::set_time_source_out(const bool /*enb*/)
+{
+ throw uhd::not_implemented_error(
+ "set_time_source_out() not implemented on this device!");
+}
+
+sensor_value_t mpmd_mb_controller::get_sensor(const std::string& name)
+{
+ if (!_sensor_names.count(name)) {
+ throw uhd::key_error(std::string("Invalid motherboard sensor name: ") + name);
+ }
+ return sensor_value_t(
+ _rpc->request_with_token<sensor_value_t::sensor_map_t>("get_mb_sensor", name));
+}
+
+std::vector<std::string> mpmd_mb_controller::get_sensor_names()
+{
+ std::vector<std::string> sensor_names(_sensor_names.cbegin(), _sensor_names.cend());
+ return sensor_names;
+}
+
+uhd::usrp::mboard_eeprom_t mpmd_mb_controller::get_eeprom()
+{
+ auto mb_eeprom =
+ _rpc->request_with_token<std::map<std::string, std::string>>("get_mb_eeprom");
+ uhd::usrp::mboard_eeprom_t mb_eeprom_dict(
+ mb_eeprom.cbegin(), mb_eeprom.cend());
+ return mb_eeprom_dict;
+}
+
diff --git a/host/lib/usrp/mpmd/mpmd_mb_controller.hpp b/host/lib/usrp/mpmd/mpmd_mb_controller.hpp
deleted file mode 100644
index 65e5dc468..000000000
--- a/host/lib/usrp/mpmd/mpmd_mb_controller.hpp
+++ /dev/null
@@ -1,73 +0,0 @@
-//
-// Copyright 2019 Ettus Research, a National Instruments Brand
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#ifndef INCLUDED_LIBUHD_MPMD_MB_CONTROLLER_HPP
-#define INCLUDED_LIBUHD_MPMD_MB_CONTROLLER_HPP
-
-#include <uhd/rfnoc/mb_controller.hpp>
-#include <uhdlib/utils/rpc.hpp>
-
-namespace uhd { namespace rfnoc {
-
-/*! X300-Specific version of the mb_controller
- *
- * Reminder: There is one of these per motherboard.
- */
-class mpmd_mb_controller : public mb_controller
-{
-public:
-
-
- //! Return reference to the RPC client
- uhd::rpc_client::sptr get_rpc_client() { return _rpc; }
-
- //! X300-specific version of the timekeeper controls
- class mpmd_timekeeper : public mb_controller::timekeeper
- {
- public:
- mpmd_timekeeper(const size_t tk_idx, uhd::rpc_client::sptr rpc_client)
- : _tk_idx(tk_idx), _rpc(rpc_client)
- {
- // nop
- }
-
- uint64_t get_ticks_now();
-
- uint64_t get_ticks_last_pps();
-
- void set_ticks_now(const uint64_t ticks);
-
- void set_ticks_next_pps(const uint64_t ticks);
-
- void set_period(const uint64_t period_ns);
-
- private:
- /*! Shorthand to perform an RPC request. Saves some typing.
- */
- template <typename return_type, typename... Args>
- return_type request(std::string const& func_name, Args&&... args)
- {
- UHD_LOG_TRACE("X300MBCTRL", "[RPC] Calling " << func_name);
- return _rpc->request_with_token<return_type>(
- func_name, std::forward<Args>(args)...);
- };
-
- const size_t _tk_idx;
-
- uhd::rpc_client::sptr _rpc;
- };
-
-private:
- /**************************************************************************
- * Attributes
- *************************************************************************/
- //! Reference to RPC interface
- uhd::rpc_client::sptr _rpc;
-};
-
-}} // namespace uhd::rfnoc
-
-#endif /* INCLUDED_LIBUHD_MPMD_MB_CONTROLLER_HPP */
diff --git a/host/lib/usrp/mpmd/mpmd_mb_iface.cpp b/host/lib/usrp/mpmd/mpmd_mb_iface.cpp
new file mode 100644
index 000000000..e713cc7a3
--- /dev/null
+++ b/host/lib/usrp/mpmd/mpmd_mb_iface.cpp
@@ -0,0 +1,301 @@
+//
+// Copyright 2018 Ettus Research, a National Instruments Company
+// Copyright 2019 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include "mpmd_mb_iface.hpp"
+#include "mpmd_link_if_mgr.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/log.hpp>
+#include <uhdlib/rfnoc/device_id.hpp>
+
+using namespace uhd::rfnoc;
+using namespace uhd::mpmd;
+
+mpmd_mboard_impl::mpmd_mb_iface::mpmd_mb_iface(
+ const uhd::device_addr_t& mb_args, uhd::rpc_client::sptr rpc)
+ : _mb_args(mb_args), _rpc(rpc), _link_if_mgr(xport::mpmd_link_if_mgr::make(mb_args))
+{
+ _remote_device_id = allocate_device_id();
+ UHD_LOG_TRACE("MPMD::MB_IFACE", "Assigning device_id " << _remote_device_id);
+ _rpc->notify_with_token("set_device_id", _remote_device_id);
+}
+
+/******************************************************************************
+ * mpmd_mb_iface API
+ *****************************************************************************/
+void mpmd_mboard_impl::mpmd_mb_iface::init()
+{
+ UHD_LOG_TRACE("MPMD::MB_IFACE", "Requesting clock ifaces...");
+ auto clock_ifaces = _rpc->request_with_token<clock_iface_list_t>("get_clocks");
+ for (auto& clock : clock_ifaces) {
+ auto iface = std::make_shared<uhd::rfnoc::clock_iface>(
+ clock.at("name"), std::stod(clock.at("freq")), clock.count("mutable"));
+ _clock_ifaces[clock.at("name")] = iface;
+ iface->set_running(true);
+ UHD_LOG_DEBUG("MPMD::MB_IFACE",
+ "Adding clock iface `"
+ << clock.at("name") << "`, frequency: " << (iface->get_freq() / 1e6)
+ << " MHz, mutable: " << (iface->is_mutable() ? "Yes" : "No"));
+ }
+ UHD_LOG_TRACE("MPMD::MB_IFACE", "Requesting CHDR link types...");
+ auto chdr_link_types =
+ _rpc->request_with_token<std::vector<std::string>>("get_chdr_link_types");
+ UHD_LOG_TRACE(
+ "MPMD::MB_IFACE", "Found " << chdr_link_types.size() << " link type(s)");
+ for (const auto& type : chdr_link_types) {
+ UHD_LOG_TRACE("MPMD::MB_IFACE", "Trying link type `" << type << "'");
+ const auto xport_info =
+ _rpc->request_with_token<xport::mpmd_link_if_mgr::xport_info_list_t>(
+ "get_chdr_link_options", type);
+ // User may have specified: addr=192.168.10.2, second_addr=
+ // MPM may have said: "my addresses are 192.168.10.2 and 192.168.20.2"
+ if (_link_if_mgr->connect(type, xport_info)) {
+ UHD_LOG_TRACE("MPMD::MB_IFACE", "Link type " << type << " successful.");
+ }
+ }
+
+ if (_link_if_mgr->get_num_links() == 0) {
+ UHD_LOG_ERROR("MPMD::MB_IFACE", "No CHDR connection available!");
+ throw uhd::runtime_error("No CHDR connection available!");
+ }
+
+ for (size_t link_idx = 0; link_idx < _link_if_mgr->get_num_links(); link_idx++) {
+ _local_device_id_map.emplace(allocate_device_id(), link_idx);
+ }
+}
+
+/******************************************************************************
+ * mb_iface API
+ *****************************************************************************/
+uint16_t mpmd_mboard_impl::mpmd_mb_iface::get_proto_ver()
+{
+ return _rpc->request_with_token<uint16_t>("get_proto_ver");
+}
+
+uhd::rfnoc::chdr_w_t mpmd_mboard_impl::mpmd_mb_iface::get_chdr_w()
+{
+ const auto chdr_w_bits = _rpc->request_with_token<size_t>("get_chdr_width");
+ switch (chdr_w_bits) {
+ case 512:
+ return CHDR_W_512;
+ case 256:
+ return CHDR_W_256;
+ case 128:
+ return CHDR_W_128;
+ case 64:
+ return CHDR_W_64;
+ }
+ throw uhd::runtime_error(std::string("Device reporting invalid CHDR width: ")
+ + std::to_string(chdr_w_bits));
+}
+
+uhd::endianness_t mpmd_mboard_impl::mpmd_mb_iface::get_endianness(
+ const uhd::rfnoc::device_id_t local_device_id)
+{
+ uhd::rfnoc::device_id_t lookup_id = local_device_id;
+ if (lookup_id == NULL_DEVICE_ID) {
+ for (auto& ids : _local_device_id_map) {
+ lookup_id = ids.first;
+ break;
+ }
+ }
+ const size_t link_idx = _local_device_id_map.at(lookup_id);
+ auto& pkt_factory = _link_if_mgr->get_packet_factory(link_idx);
+ return pkt_factory.get_endianness();
+}
+
+uhd::rfnoc::device_id_t mpmd_mboard_impl::mpmd_mb_iface::get_remote_device_id()
+{
+ return _remote_device_id;
+}
+
+std::vector<device_id_t> mpmd_mboard_impl::mpmd_mb_iface::get_local_device_ids()
+{
+ std::vector<device_id_t> device_ids;
+ for (auto& local_dev_id_pair : _local_device_id_map) {
+ device_ids.push_back(local_dev_id_pair.first);
+ }
+ return device_ids;
+}
+
+uhd::transport::adapter_id_t mpmd_mboard_impl::mpmd_mb_iface::get_adapter_id(
+ const uhd::rfnoc::device_id_t local_device_id)
+{
+ return _adapter_map.at(local_device_id);
+}
+
+void mpmd_mboard_impl::mpmd_mb_iface::reset_network()
+{
+ // FIXME
+}
+
+uhd::rfnoc::clock_iface::sptr mpmd_mboard_impl::mpmd_mb_iface::get_clock_iface(
+ const std::string& clock_name)
+{
+ if (_clock_ifaces.count(clock_name)) {
+ return _clock_ifaces.at(clock_name);
+ } else {
+ UHD_LOG_ERROR("MPMD::MB_IFACE", "Invalid timebase clock name: " + clock_name);
+ throw uhd::key_error(
+ "[MPMD_MB::IFACE] Invalid timebase clock name: " + clock_name);
+ }
+}
+
+uhd::rfnoc::chdr_ctrl_xport::sptr mpmd_mboard_impl::mpmd_mb_iface::make_ctrl_transport(
+ uhd::rfnoc::device_id_t local_device_id, const uhd::rfnoc::sep_id_t& local_epid)
+{
+ if (!_local_device_id_map.count(local_device_id)) {
+ throw uhd::key_error(std::string("[MPMD::MB_IFACE] Cannot create control "
+ "transport: Unknown local device ID ")
+ + std::to_string(local_device_id));
+ }
+ const size_t link_idx = _local_device_id_map.at(local_device_id);
+ uhd::transport::io_service::sptr io_srv;
+ uhd::transport::send_link_if::sptr send_link;
+ uhd::transport::recv_link_if::sptr recv_link;
+ std::tie(io_srv, send_link, std::ignore, recv_link, std::ignore, std::ignore) =
+ _link_if_mgr->get_link(
+ link_idx, uhd::transport::link_type_t::CTRL, uhd::device_addr_t());
+
+ /* Associate local device ID with the adapter */
+ _adapter_map[local_device_id] = send_link->get_send_adapter_id();
+
+ auto pkt_factory = _link_if_mgr->get_packet_factory(link_idx);
+ auto xport = uhd::rfnoc::chdr_ctrl_xport::make(io_srv,
+ send_link,
+ recv_link,
+ pkt_factory,
+ local_epid,
+ send_link->get_num_send_frames(),
+ recv_link->get_num_recv_frames());
+ return xport;
+}
+
+uhd::rfnoc::chdr_rx_data_xport::uptr
+mpmd_mboard_impl::mpmd_mb_iface::make_rx_data_transport(
+ uhd::rfnoc::mgmt::mgmt_portal& mgmt_portal,
+ const uhd::rfnoc::sep_addr_pair_t& addrs,
+ const uhd::rfnoc::sep_id_pair_t& epids,
+ const uhd::rfnoc::sw_buff_t pyld_buff_fmt,
+ const uhd::rfnoc::sw_buff_t mdata_buff_fmt,
+ const uhd::device_addr_t& xport_args)
+{
+ const uhd::rfnoc::sep_addr_t local_sep_addr = addrs.second;
+
+ if (!_local_device_id_map.count(local_sep_addr.first)) {
+ throw uhd::key_error(std::string("[MPMD::MB_IFACE] Cannot create RX data "
+ "transport: Unknown local device ID ")
+ + std::to_string(local_sep_addr.first));
+ }
+ const size_t link_idx = _local_device_id_map.at(local_sep_addr.first);
+
+ uhd::transport::io_service::sptr io_srv;
+ uhd::transport::send_link_if::sptr send_link;
+ uhd::transport::recv_link_if::sptr recv_link;
+ bool lossy_xport;
+ size_t recv_buff_size;
+ std::tie(io_srv, send_link, std::ignore, recv_link, recv_buff_size, lossy_xport) =
+ _link_if_mgr->get_link(
+ link_idx, uhd::transport::link_type_t::RX_DATA, xport_args);
+
+ /* Associate local device ID with the adapter */
+ _adapter_map[local_sep_addr.first] = send_link->get_send_adapter_id();
+
+ // TODO: configure this based on the transport type
+ const stream_buff_params_t recv_capacity = {
+ recv_buff_size, uhd::rfnoc::MAX_FC_CAPACITY_PKTS};
+
+ const double ratio = 1.0 / 32;
+
+ // Configure flow control frequency to use bytes only for UDP
+ stream_buff_params_t fc_freq = {
+ static_cast<uint64_t>(std::ceil(double(recv_buff_size) * ratio)),
+ uhd::rfnoc::MAX_FC_FREQ_PKTS};
+
+ stream_buff_params_t fc_headroom = {0, 0};
+
+ // Create the data transport
+ auto pkt_factory = _link_if_mgr->get_packet_factory(link_idx);
+ auto fc_params = chdr_rx_data_xport::configure_sep(io_srv,
+ recv_link,
+ send_link,
+ pkt_factory,
+ mgmt_portal,
+ epids,
+ pyld_buff_fmt,
+ mdata_buff_fmt,
+ recv_capacity,
+ fc_freq,
+ fc_headroom,
+ lossy_xport);
+ auto rx_xport = std::make_unique<chdr_rx_data_xport>(io_srv,
+ recv_link,
+ send_link,
+ pkt_factory,
+ epids,
+ recv_link->get_num_recv_frames(),
+ fc_params);
+
+ return rx_xport;
+}
+
+uhd::rfnoc::chdr_tx_data_xport::uptr
+mpmd_mboard_impl::mpmd_mb_iface::make_tx_data_transport(
+ uhd::rfnoc::mgmt::mgmt_portal& mgmt_portal,
+ const uhd::rfnoc::sep_addr_pair_t& addrs,
+ const uhd::rfnoc::sep_id_pair_t& epids,
+ const uhd::rfnoc::sw_buff_t pyld_buff_fmt,
+ const uhd::rfnoc::sw_buff_t mdata_buff_fmt,
+ const uhd::device_addr_t& xport_args)
+{
+ const uhd::rfnoc::sep_addr_t local_sep_addr = addrs.first;
+
+ if (!_local_device_id_map.count(local_sep_addr.first)) {
+ throw uhd::key_error(std::string("[MPMD::MB_IFACE] Cannot create TX data "
+ "transport: Unknown local device ID ")
+ + std::to_string(local_sep_addr.first));
+ }
+ const size_t link_idx = _local_device_id_map.at(local_sep_addr.first);
+
+ uhd::transport::io_service::sptr io_srv;
+ uhd::transport::send_link_if::sptr send_link;
+ uhd::transport::recv_link_if::sptr recv_link;
+ bool lossy_xport;
+ std::tie(io_srv, send_link, std::ignore, recv_link, std::ignore, lossy_xport) =
+ _link_if_mgr->get_link(
+ link_idx, uhd::transport::link_type_t::TX_DATA, xport_args);
+
+ /* Associate local device ID with the adapter */
+ _adapter_map[local_sep_addr.first] = send_link->get_send_adapter_id();
+
+ // TODO: configure this based on the transport type
+ const double fc_freq_ratio = 1.0 / 8;
+ const double fc_headroom_ratio = 0;
+
+ auto pkt_factory = _link_if_mgr->get_packet_factory(link_idx);
+ const auto buff_capacity = chdr_tx_data_xport::configure_sep(io_srv,
+ recv_link,
+ send_link,
+ pkt_factory,
+ mgmt_portal,
+ epids,
+ pyld_buff_fmt,
+ mdata_buff_fmt,
+ fc_freq_ratio,
+ fc_headroom_ratio);
+
+ // Create the data transport
+ auto tx_xport = std::make_unique<chdr_tx_data_xport>(io_srv,
+ recv_link,
+ send_link,
+ pkt_factory,
+ epids,
+ send_link->get_num_send_frames(),
+ buff_capacity);
+
+
+ return tx_xport;
+}
diff --git a/host/lib/usrp/mpmd/mpmd_mb_iface.hpp b/host/lib/usrp/mpmd/mpmd_mb_iface.hpp
new file mode 100644
index 000000000..4e47dd35a
--- /dev/null
+++ b/host/lib/usrp/mpmd/mpmd_mb_iface.hpp
@@ -0,0 +1,68 @@
+//
+// Copyright 2019 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_MPMD_MB_IFACE_HPP
+#define INCLUDED_MPMD_MB_IFACE_HPP
+
+#include "mpmd_impl.hpp"
+#include "mpmd_link_if_mgr.hpp"
+#include <uhdlib/rfnoc/mb_iface.hpp>
+#include <map>
+#include <unordered_map>
+
+namespace uhd { namespace mpmd {
+
+class mpmd_mboard_impl::mpmd_mb_iface : public uhd::rfnoc::mb_iface
+{
+public:
+ using uptr = std::unique_ptr<mpmd_mb_iface>;
+ using clock_iface_list_t = std::vector<std::map<std::string, std::string>>;
+ mpmd_mb_iface(const uhd::device_addr_t& mb_args, uhd::rpc_client::sptr rpc);
+ ~mpmd_mb_iface() = default;
+
+ /*** mpmd_mb_iface API calls *****************************************/
+ //! Initialize transports
+ void init();
+
+ /*** mb_iface API calls **********************************************/
+ uint16_t get_proto_ver();
+ uhd::rfnoc::chdr_w_t get_chdr_w();
+ uhd::endianness_t get_endianness(const uhd::rfnoc::device_id_t local_device_id);
+ uhd::rfnoc::device_id_t get_remote_device_id();
+ std::vector<uhd::rfnoc::device_id_t> get_local_device_ids();
+ uhd::transport::adapter_id_t get_adapter_id(const uhd::rfnoc::device_id_t local_device_id);
+ void reset_network();
+ uhd::rfnoc::clock_iface::sptr get_clock_iface(const std::string& clock_name);
+ uhd::rfnoc::chdr_ctrl_xport::sptr make_ctrl_transport(
+ uhd::rfnoc::device_id_t local_device_id, const uhd::rfnoc::sep_id_t& local_epid);
+ uhd::rfnoc::chdr_rx_data_xport::uptr make_rx_data_transport(
+ uhd::rfnoc::mgmt::mgmt_portal& mgmt_portal,
+ const uhd::rfnoc::sep_addr_pair_t& addrs,
+ const uhd::rfnoc::sep_id_pair_t& epids,
+ const uhd::rfnoc::sw_buff_t pyld_buff_fmt,
+ const uhd::rfnoc::sw_buff_t mdata_buff_fmt,
+ const uhd::device_addr_t& xport_args);
+ uhd::rfnoc::chdr_tx_data_xport::uptr make_tx_data_transport(
+ uhd::rfnoc::mgmt::mgmt_portal& mgmt_portal,
+ const uhd::rfnoc::sep_addr_pair_t& addrs,
+ const uhd::rfnoc::sep_id_pair_t& epids,
+ const uhd::rfnoc::sw_buff_t pyld_buff_fmt,
+ const uhd::rfnoc::sw_buff_t mdata_buff_fmt,
+ const uhd::device_addr_t& xport_args);
+
+private:
+ uhd::device_addr_t _mb_args;
+ uhd::rpc_client::sptr _rpc;
+ xport::mpmd_link_if_mgr::uptr _link_if_mgr;
+ uhd::rfnoc::device_id_t _remote_device_id;
+ std::map<uhd::rfnoc::device_id_t, size_t> _local_device_id_map;
+ std::unordered_map<uhd::rfnoc::device_id_t, uhd::transport::adapter_id_t> _adapter_map;
+ std::map<std::string, uhd::rfnoc::clock_iface::sptr> _clock_ifaces;
+};
+
+}} /* namespace uhd::mpmd */
+
+#endif /* INCLUDED_MPMD_MB_IFACE_HPP */
diff --git a/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp b/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp
index 83b47b485..5c8fd5485 100644
--- a/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp
+++ b/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp
@@ -6,11 +6,13 @@
//
#include "mpmd_impl.hpp"
+#include "mpmd_mb_iface.hpp"
#include <uhd/transport/udp_simple.hpp>
#include <uhd/utils/log.hpp>
#include <uhd/utils/safe_call.hpp>
#include <chrono>
#include <thread>
+#include <memory>
namespace {
/*************************************************************************
@@ -177,8 +179,8 @@ boost::optional<device_addr_t> mpmd_mboard_impl::is_device_reachable(
{
UHD_LOG_TRACE(
"MPMD", "Checking accessibility of device `" << device_addr.to_string() << "'");
- UHD_ASSERT_THROW(device_addr.has_key(xport::MGMT_ADDR_KEY));
- const std::string rpc_addr = device_addr.get(xport::MGMT_ADDR_KEY);
+ UHD_ASSERT_THROW(device_addr.has_key(MGMT_ADDR_KEY));
+ const std::string rpc_addr = device_addr.get(MGMT_ADDR_KEY);
const size_t rpc_port =
device_addr.cast<size_t>(mpmd_impl::MPM_RPC_PORT_KEY, mpmd_impl::MPM_RPC_PORT);
// 1) Read back device info
@@ -258,15 +260,10 @@ mpmd_mboard_impl::mpmd_mboard_impl(
const device_addr_t& mb_args_, const std::string& rpc_server_addr)
: mb_args(mb_args_)
, rpc(make_mpm_rpc_client(rpc_server_addr, mb_args_))
- , num_xbars(rpc->request<size_t>("get_num_xbars"))
, _claim_rpc(make_mpm_rpc_client(rpc_server_addr, mb_args, MPMD_CLAIMER_RPC_TIMEOUT))
- // xbar_local_addrs is not yet valid after this!
- , xbar_local_addrs(num_xbars, 0xFF)
- , _xport_mgr(xport::mpmd_xport_mgr::make(mb_args))
{
UHD_LOGGER_TRACE("MPMD") << "Initializing mboard, connecting to RPC server address: "
- << rpc_server_addr << " mboard args: " << mb_args.to_string()
- << " number of crossbars: " << num_xbars;
+ << rpc_server_addr << " mboard args: " << mb_args.to_string();
_claimer_task = claim_device_and_make_task();
if (mb_args_.has_key(MPMD_MEAS_LATENCY_KEY)) {
@@ -278,7 +275,7 @@ mpmd_mboard_impl::mpmd_mboard_impl(
for (const auto& info_pair : device_info_dict) {
device_info[info_pair.first] = info_pair.second;
}
- UHD_LOGGER_TRACE("MPMD") << "MPM reports device info: " << device_info.to_string();
+ UHD_LOG_DEBUG("MPMD", "MPM reports device info: " << device_info.to_string());
/// Get dboard info
const auto dboards_info = rpc->request<std::vector<dev_info>>("get_dboard_info");
UHD_ASSERT_THROW(this->dboard_info.size() == 0);
@@ -293,19 +290,16 @@ mpmd_mboard_impl::mpmd_mboard_impl(
this->dboard_info.push_back(this_db_info);
}
- for (const std::string& key : mb_args_.keys()) {
- if (key.find("recv") != std::string::npos)
- recv_args[key] = mb_args_[key];
- if (key.find("send") != std::string::npos)
- send_args[key] = mb_args_[key];
- }
+ // Initialize mb_iface and mb_controller
+ mb_iface = std::make_unique<mpmd_mb_iface>(mb_args, rpc);
+ mb_ctrl = std::make_shared<rfnoc::mpmd_mb_controller>(rpc, device_info);
}
mpmd_mboard_impl::~mpmd_mboard_impl()
{
// Destroy the claimer task to avoid spurious asynchronous reclaim call
// after the unclaim.
- UHD_SAFE_CALL(dump_logs(); _claimer_task.reset(); _xport_mgr.reset();
+ UHD_SAFE_CALL(dump_logs(); _claimer_task.reset();
if (not rpc->request_with_token<bool>("unclaim")) {
UHD_LOG_WARNING("MPMD", "Failure to ack unclaim!");
});
@@ -317,79 +311,15 @@ mpmd_mboard_impl::~mpmd_mboard_impl()
void mpmd_mboard_impl::init()
{
init_device(rpc, mb_args);
- // RFNoC block clocks are now on. Noc-IDs can be read back.
+ mb_iface->init();
}
/*****************************************************************************
* API
****************************************************************************/
-void mpmd_mboard_impl::set_xbar_local_addr(
- const size_t xbar_index, const size_t local_addr)
-{
- UHD_ASSERT_THROW(
- rpc->request_with_token<bool>("set_xbar_local_addr", xbar_index, local_addr));
- UHD_ASSERT_THROW(xbar_index < xbar_local_addrs.size());
- xbar_local_addrs.at(xbar_index) = local_addr;
-}
-
-uhd::both_xports_t mpmd_mboard_impl::make_transport(const sid_t& sid,
- usrp::device3_impl::xport_type_t xport_type,
- const uhd::device_addr_t& xport_args)
-{
- const std::string xport_type_str = [xport_type]() {
- switch (xport_type) {
- case mpmd_impl::CTRL:
- return "CTRL";
- case mpmd_impl::ASYNC_MSG:
- return "ASYNC_MSG";
- case mpmd_impl::RX_DATA:
- return "RX_DATA";
- case mpmd_impl::TX_DATA:
- return "TX_DATA";
- default:
- UHD_THROW_INVALID_CODE_PATH();
- };
- }();
-
- UHD_LOGGER_TRACE("MPMD") << __func__
- << "(): Creating new transport of type: " << xport_type_str;
-
- using namespace uhd::mpmd::xport;
- const auto xport_info_list =
- rpc->request_with_token<mpmd_xport_mgr::xport_info_list_t>(
- "request_xport", sid.get_dst(), sid.get_src(), xport_type_str);
- UHD_LOGGER_TRACE("MPMD") << __func__ << "(): request_xport() gave us "
- << xport_info_list.size() << " option(s).";
- if (xport_info_list.empty()) {
- UHD_LOG_ERROR("MPMD", "No viable transport path found!");
- throw uhd::runtime_error("No viable transport path found!");
- }
-
- xport::mpmd_xport_mgr::xport_info_t xport_info_out;
- auto xports = _xport_mgr->make_transport(
- xport_info_list, xport_type, xport_args, xport_info_out);
-
- if (not rpc->request_with_token<bool>("commit_xport", xport_info_out)) {
- UHD_LOG_ERROR("MPMD", "Failed to create UDP transport!");
- throw uhd::runtime_error("commit_xport() failed!");
- }
-
- return xports;
-}
-
-size_t mpmd_mboard_impl::get_mtu(const uhd::direction_t dir) const
-{
- return _xport_mgr->get_mtu(dir);
-}
-
-uhd::device_addr_t mpmd_mboard_impl::get_rx_hints() const
-{
- return recv_args;
-}
-
-uhd::device_addr_t mpmd_mboard_impl::get_tx_hints() const
+uhd::rfnoc::mb_iface& mpmd_mboard_impl::get_mb_iface()
{
- return send_args;
+ return *(mb_iface.get());
}
/*****************************************************************************
diff --git a/host/lib/usrp/mpmd/mpmd_prop_tree.cpp b/host/lib/usrp/mpmd/mpmd_prop_tree.cpp
index 51b88b0e6..dc559f91b 100644
--- a/host/lib/usrp/mpmd/mpmd_prop_tree.cpp
+++ b/host/lib/usrp/mpmd/mpmd_prop_tree.cpp
@@ -194,16 +194,4 @@ void mpmd_impl::init_property_tree(
return _get_component_info(comp_name, mb);
}); // Done adding component to property tree
}
-
- /*** MTUs ***********************************************************/
- tree->create<size_t>(mb_path / "mtu/recv")
- .add_coerced_subscriber([](const size_t) {
- throw uhd::runtime_error("Attempting to write read-only value (MTU)!");
- })
- .set_publisher([mb]() { return mb->get_mtu(uhd::RX_DIRECTION); });
- tree->create<size_t>(mb_path / "mtu/send")
- .add_coerced_subscriber([](const size_t) {
- throw uhd::runtime_error("Attempting to write read-only value (MTU)!");
- })
- .set_publisher([mb]() { return mb->get_mtu(uhd::TX_DIRECTION); });
}
diff --git a/host/lib/usrp/mpmd/mpmd_xport.cpp b/host/lib/usrp/mpmd/mpmd_xport.cpp
deleted file mode 100644
index 3ef6a074c..000000000
--- a/host/lib/usrp/mpmd/mpmd_xport.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-//
-// Copyright 2017 Ettus Research, National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-// make_transport logic for mpmd_impl. Note that mpmd_xport_mgr.* has most of
-// the actual transport logic, this for transport-related APIs.
-
-#include "mpmd_impl.hpp"
-#include "mpmd_xport_mgr.hpp"
-
-using namespace uhd;
-using namespace uhd::mpmd;
-
-uhd::device_addr_t mpmd_impl::get_rx_hints(size_t mb_index)
-{
- return _mb.at(mb_index)->get_rx_hints();
-}
-
-uhd::device_addr_t mpmd_impl::get_tx_hints(size_t mb_index)
-{
- return _mb.at(mb_index)->get_tx_hints();
-}
-
-size_t mpmd_impl::identify_mboard_by_xbar_addr(const size_t xbar_addr) const
-{
- for (size_t mb_index = 0; mb_index < _mb.size(); mb_index++) {
- for (size_t xbar_index = 0; xbar_index < _mb[mb_index]->num_xbars; xbar_index++) {
- if (_mb.at(mb_index)->get_xbar_local_addr(xbar_index) == xbar_addr) {
- return mb_index;
- }
- }
- }
- throw uhd::lookup_error(
- str(boost::format("Cannot identify mboard for crossbar address %d") % xbar_addr));
-}
-
-both_xports_t mpmd_impl::make_transport(const sid_t& dst_address,
- usrp::device3_impl::xport_type_t xport_type,
- const uhd::device_addr_t& args)
-{
- const size_t mb_index = identify_mboard_by_xbar_addr(dst_address.get_dst_addr());
-
- const sid_t sid(0,
- 0, // Not actually an address, more of an 'ignore me' value
- dst_address.get_dst_addr(),
- dst_address.get_dst_endpoint());
- UHD_LOGGER_TRACE("MPMD") << "Creating new transport to mboard: " << mb_index
- << " SID: " << sid.to_pp_string_hex()
- << " User-defined xport args: " << args.to_string();
-
- both_xports_t xports = _mb[mb_index]->make_transport(sid, xport_type, args);
- UHD_LOGGER_TRACE("MPMD") << "xport info: send_sid=="
- << xports.send_sid.to_pp_string_hex()
- << " recv_sid==" << xports.recv_sid.to_pp_string_hex()
- << " endianness=="
- << (xports.endianness == uhd::ENDIANNESS_BIG ? "BE" : "LE")
- << " recv_buff_size==" << xports.recv_buff_size
- << " send_buff_size==" << xports.send_buff_size;
- return xports;
-}
diff --git a/host/lib/usrp/mpmd/mpmd_xport_ctrl_base.hpp b/host/lib/usrp/mpmd/mpmd_xport_ctrl_base.hpp
deleted file mode 100644
index a7fff9262..000000000
--- a/host/lib/usrp/mpmd/mpmd_xport_ctrl_base.hpp
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// Copyright 2017 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#ifndef INCLUDED_MPMD_XPORT_CTRL_BASE_HPP
-#define INCLUDED_MPMD_XPORT_CTRL_BASE_HPP
-
-#include "../device3/device3_impl.hpp"
-#include "mpmd_xport_mgr.hpp"
-#include <uhd/types/device_addr.hpp>
-#include <memory>
-
-namespace uhd { namespace mpmd { namespace xport {
-
-/*! Transport manager implementation base
- */
-class mpmd_xport_ctrl_base
-{
-public:
- using uptr = std::unique_ptr<mpmd_xport_ctrl_base>;
- virtual ~mpmd_xport_ctrl_base() {}
-
- /*! This is the final step of a make_transport() sequence
- *
- * \param xport_info Contains all necessary transport info. The
- * implementation may update this!
- * \param xport_type CTRL, ASYNC_MSG, ... (see xport_type_t)
- * \param xport_args Additional arguments. These can come from the user.
- */
- virtual both_xports_t make_transport(mpmd_xport_mgr::xport_info_t& xport_info,
- const usrp::device3_impl::xport_type_t xport_type,
- const uhd::device_addr_t& xport_args) = 0;
-
- //! Assert if an xport_info is even valid/feasible/available
- virtual bool is_valid(const mpmd_xport_mgr::xport_info_t& xport_info) const = 0;
-
- virtual size_t get_mtu(const uhd::direction_t dir) const = 0;
-};
-
-}}} /* namespace uhd::mpmd::xport */
-
-#endif /* INCLUDED_MPMD_XPORT_CTRL_BASE_HPP */
diff --git a/host/lib/usrp/mpmd/mpmd_xport_ctrl_liberio.cpp b/host/lib/usrp/mpmd/mpmd_xport_ctrl_liberio.cpp
deleted file mode 100644
index c53eb97a1..000000000
--- a/host/lib/usrp/mpmd/mpmd_xport_ctrl_liberio.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-//
-// Copyright 2017 Ettus Research, National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "mpmd_xport_ctrl_liberio.hpp"
-#include "../transport/liberio_zero_copy.hpp"
-#include <uhd/transport/udp_zero_copy.hpp>
-#include <uhd/utils/byteswap.hpp>
-#include <uhd/rfnoc/constants.hpp>
-
-using namespace uhd;
-using namespace uhd::mpmd::xport;
-
-namespace {
-
-//! Max frame size of a control packet in bytes
-const size_t LIBERIO_CTRL_FRAME_MAX_SIZE = 128;
-//! Max frame size of an async message packet in bytes
-const size_t LIBERIO_ASYNC_FRAME_MAX_SIZE = 256;
-//! Max frame size of a flow control packet in bytes
-const size_t LIBERIO_FC_FRAME_MAX_SIZE = 64;
-//! The max MTU will be this number times the page size
-const size_t LIBERIO_PAGES_PER_BUF = 2;
-//! Number of descriptors that liberio allocates (receive)
-const size_t LIBERIO_NUM_RECV_FRAMES = 128;
-//! Number of descriptors that liberio allocates (send)
-const size_t LIBERIO_NUM_SEND_FRAMES = 128;
-
-uint32_t extract_sid_from_pkt(void* pkt, size_t)
-{
- return uhd::sid_t(uhd::wtohx(static_cast<const uint32_t*>(pkt)[1])).get_dst();
-}
-
-} // namespace
-
-mpmd_xport_ctrl_liberio::mpmd_xport_ctrl_liberio(const uhd::device_addr_t& mb_args)
- : _mb_args(mb_args)
- , _recv_args(filter_args(mb_args, "recv"))
- , _send_args(filter_args(mb_args, "send"))
-{
- // nop
-}
-
-
-uhd::both_xports_t mpmd_xport_ctrl_liberio::make_transport(
- mpmd_xport_mgr::xport_info_t& xport_info,
- const usrp::device3_impl::xport_type_t xport_type,
- const uhd::device_addr_t& xport_args_)
-{
- auto xport_args = (xport_type == usrp::device3_impl::CTRL) ?
- uhd::device_addr_t() : xport_args_;
-
- // Constrain by this transport's MTU and the MTU passed in
- const size_t send_mtu = std::min(get_mtu(uhd::TX_DIRECTION),
- xport_args.cast<size_t>("mtu", get_mtu(uhd::TX_DIRECTION)));
- const size_t recv_mtu = std::min(get_mtu(uhd::RX_DIRECTION),
- xport_args.cast<size_t>("mtu", get_mtu(uhd::RX_DIRECTION)));
- size_t send_frame_size = xport_args.cast<size_t>("send_frame_size", send_mtu);
- size_t recv_frame_size = xport_args.cast<size_t>("recv_frame_size", recv_mtu);
-
- // Check any user supplied frame sizes and constrain to MTU
- if (xport_args.has_key("send_frame_size") and
- xport_type == usrp::device3_impl::TX_DATA)
- {
- if (send_frame_size > send_mtu) {
- UHD_LOGGER_WARNING("MPMD")
- << boost::format("Requested send_frame_size of %d exceeds the "
- "maximum supported by the hardware. Using %d.")
- % send_frame_size % send_mtu;
- send_frame_size = send_mtu;
- }
- }
- if (xport_args.has_key("recv_frame_size") and
- xport_type == usrp::device3_impl::RX_DATA)
- {
- size_t recv_frame_size = xport_args.cast<size_t>("recv_frame_size", recv_mtu);
- if (recv_frame_size > recv_mtu) {
- UHD_LOGGER_WARNING("MPMD")
- << boost::format("Requested recv_frame_size of %d exceeds the "
- "maximum supported by the hardware. Using %d.")
- % recv_frame_size % recv_mtu;
- recv_frame_size = recv_mtu;
- }
- }
-
- transport::zero_copy_xport_params default_buff_args;
- /* default ones for RX / TX, override below */
-
- default_buff_args.send_frame_size = send_mtu;
- default_buff_args.recv_frame_size = recv_mtu;
- default_buff_args.num_recv_frames = LIBERIO_NUM_RECV_FRAMES;
- default_buff_args.num_send_frames = LIBERIO_NUM_SEND_FRAMES;
-
- if (xport_type == usrp::device3_impl::CTRL) {
- default_buff_args.send_frame_size = LIBERIO_CTRL_FRAME_MAX_SIZE;
- default_buff_args.recv_frame_size = LIBERIO_CTRL_FRAME_MAX_SIZE;
- default_buff_args.num_recv_frames = uhd::rfnoc::CMD_FIFO_SIZE /
- uhd::rfnoc::MAX_CMD_PKT_SIZE;
- default_buff_args.num_send_frames = uhd::rfnoc::CMD_FIFO_SIZE /
- uhd::rfnoc::MAX_CMD_PKT_SIZE;
- } else if (xport_type == usrp::device3_impl::ASYNC_MSG) {
- default_buff_args.send_frame_size = LIBERIO_ASYNC_FRAME_MAX_SIZE;
- default_buff_args.recv_frame_size = LIBERIO_ASYNC_FRAME_MAX_SIZE;
- } else if (xport_type == usrp::device3_impl::RX_DATA) {
- default_buff_args.recv_frame_size = recv_frame_size;
- default_buff_args.send_frame_size = LIBERIO_FC_FRAME_MAX_SIZE;
- } else {
- default_buff_args.recv_frame_size = LIBERIO_FC_FRAME_MAX_SIZE;
- default_buff_args.send_frame_size = send_frame_size;
- }
-
- const std::string tx_dev = xport_info["tx_dev"];
- const std::string rx_dev = xport_info["rx_dev"];
-
- both_xports_t xports;
- xports.lossless = true;
- xports.endianness = uhd::ENDIANNESS_LITTLE;
- xports.send_sid = sid_t(xport_info["send_sid"]);
- xports.recv_sid = xports.send_sid.reversed();
-
- if (xport_type == usrp::device3_impl::CTRL) {
- UHD_ASSERT_THROW(xport_info["muxed"] == "True");
- if (not _ctrl_dma_xport) {
- _ctrl_dma_xport =
- make_muxed_liberio_xport(tx_dev, rx_dev, default_buff_args,
- uhd::rfnoc::MAX_NUM_BLOCKS * uhd::rfnoc::MAX_NUM_PORTS);
- }
-
- UHD_LOGGER_TRACE("MPMD")
- << "Making (muxed) stream with num " << xports.recv_sid.get_dst();
- xports.recv = _ctrl_dma_xport->make_stream(xports.recv_sid.get_dst());
- } else if (xport_type == usrp::device3_impl::ASYNC_MSG) {
- UHD_ASSERT_THROW(xport_info["muxed"] == "True");
- if (not _async_msg_dma_xport) {
- _async_msg_dma_xport =
- make_muxed_liberio_xport(tx_dev, rx_dev, default_buff_args,
- uhd::rfnoc::MAX_NUM_BLOCKS * uhd::rfnoc::MAX_NUM_PORTS);
- }
-
- UHD_LOGGER_TRACE("MPMD")
- << "making (muxed) stream with num " << xports.recv_sid.get_dst();
- xports.recv = _async_msg_dma_xport->make_stream(xports.recv_sid.get_dst());
- } else {
- // Create muxed transport in case of less DMA channels
- if (xport_info["muxed"] == "True") {
- if (not _data_dma_xport) {
- _data_dma_xport =
- make_muxed_liberio_xport(tx_dev, rx_dev, default_buff_args,
- uhd::rfnoc::MAX_NUM_BLOCKS * uhd::rfnoc::MAX_NUM_PORTS);
- }
-
- UHD_LOGGER_TRACE("MPMD")
- << "Making (muxed) stream with num " << xports.recv_sid.get_dst();
- xports.recv = _data_dma_xport->make_stream(xports.recv_sid.get_dst());
- }
- else {
- xports.recv =
- transport::liberio_zero_copy::make(tx_dev, rx_dev, default_buff_args);
- }
- }
-
- // Finish both_xports_t object and return:
- xports.recv_buff_size = default_buff_args.recv_frame_size *
- default_buff_args.num_recv_frames;
- xports.send_buff_size = default_buff_args.send_frame_size *
- default_buff_args.num_send_frames;
- xports.send = xports.recv;
- return xports;
-}
-
-bool mpmd_xport_ctrl_liberio::is_valid(
- const mpmd_xport_mgr::xport_info_t& xport_info) const
-{
- return xport_info.at("type") == "liberio";
-}
-
-size_t mpmd_xport_ctrl_liberio::get_mtu(const uhd::direction_t /*dir*/) const
-{
- return LIBERIO_PAGES_PER_BUF * getpagesize();
-}
-
-uhd::transport::muxed_zero_copy_if::sptr
-mpmd_xport_ctrl_liberio::make_muxed_liberio_xport(const std::string& tx_dev,
- const std::string& rx_dev,
- const uhd::transport::zero_copy_xport_params& buff_args,
- const size_t max_muxed_ports)
-{
- auto base_xport = transport::liberio_zero_copy::make(tx_dev, rx_dev, buff_args);
-
- return uhd::transport::muxed_zero_copy_if::make(
- base_xport, extract_sid_from_pkt, max_muxed_ports);
-}
diff --git a/host/lib/usrp/mpmd/mpmd_xport_ctrl_liberio.hpp b/host/lib/usrp/mpmd/mpmd_xport_ctrl_liberio.hpp
deleted file mode 100644
index 36f02fe46..000000000
--- a/host/lib/usrp/mpmd/mpmd_xport_ctrl_liberio.hpp
+++ /dev/null
@@ -1,56 +0,0 @@
-//
-// Copyright 2017 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#ifndef INCLUDED_MPMD_XPORT_ctrl_liberio_HPP
-#define INCLUDED_MPMD_XPORT_ctrl_liberio_HPP
-
-#include "../device3/device3_impl.hpp"
-#include "mpmd_xport_ctrl_base.hpp"
-#include <uhd/transport/muxed_zero_copy_if.hpp>
-#include <uhd/types/device_addr.hpp>
-
-namespace uhd { namespace mpmd { namespace xport {
-
-/*! Liberio transport manager
- */
-class mpmd_xport_ctrl_liberio : public mpmd_xport_ctrl_base
-{
-public:
- mpmd_xport_ctrl_liberio(const uhd::device_addr_t& mb_args);
-
- /*! Open DMA interface to kernel (and thus to FPGA DMA engine)
- */
- both_xports_t make_transport(mpmd_xport_mgr::xport_info_t& xport_info,
- const usrp::device3_impl::xport_type_t xport_type,
- const uhd::device_addr_t& xport_args);
-
- bool is_valid(const mpmd_xport_mgr::xport_info_t& xport_info) const;
-
- size_t get_mtu(const uhd::direction_t dir) const;
-
-private:
- /*! Create a muxed liberio transport for control packets */
- uhd::transport::muxed_zero_copy_if::sptr make_muxed_liberio_xport(
- const std::string& tx_dev,
- const std::string& rx_dev,
- const uhd::transport::zero_copy_xport_params& buff_args,
- const size_t max_muxed_ports);
-
- const uhd::device_addr_t _mb_args;
- const uhd::dict<std::string, std::string> _recv_args;
- const uhd::dict<std::string, std::string> _send_args;
-
- //! Control transport for one liberio connection
- uhd::transport::muxed_zero_copy_if::sptr _ctrl_dma_xport;
- //! Data transport for one liberio connection
- uhd::transport::muxed_zero_copy_if::sptr _data_dma_xport;
- //! Control transport for one liberio connection
- uhd::transport::muxed_zero_copy_if::sptr _async_msg_dma_xport;
-};
-
-}}} /* namespace uhd::mpmd::xport */
-
-#endif /* INCLUDED_MPMD_XPORT_ctrl_liberio_HPP */
diff --git a/host/lib/usrp/mpmd/mpmd_xport_ctrl_udp.cpp b/host/lib/usrp/mpmd/mpmd_xport_ctrl_udp.cpp
deleted file mode 100644
index 20b94899c..000000000
--- a/host/lib/usrp/mpmd/mpmd_xport_ctrl_udp.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-//
-// Copyright 2017 Ettus Research, National Instruments Company
-// Copyright 2019 Ettus Research, National Instruments Brand
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "mpmd_xport_ctrl_udp.hpp"
-#include "mpmd_impl.hpp"
-#include "mpmd_xport_mgr.hpp"
-#include <uhd/transport/udp_constants.hpp>
-#include <uhd/transport/udp_simple.hpp>
-#include <uhd/transport/udp_zero_copy.hpp>
-
-
-using namespace uhd;
-using namespace uhd::mpmd::xport;
-
-namespace {
-
-//! Maximum CHDR packet size in bytes
-const size_t MPMD_10GE_DATA_FRAME_MAX_SIZE = 4000;
-
-//! Default number of send frames
-const size_t MPMD_UDP_DEFAULT_NUM_SEND_FRAMES = 1;
-//! Default number of recv frames
-const size_t MPMD_UDP_DEFAULT_NUM_RECV_FRAMES = 1;
-//! Default message frame size
-const size_t MPMD_UDP_MSG_FRAME_SIZE = 256;
-//! Default 1GbE send frame size
-const size_t MPMD_UDP_1GE_DEFAULT_SEND_FRAME_SIZE = 1472;
-//! Default 1GbE receive frame size
-const size_t MPMD_UDP_1GE_DEFAULT_RECV_FRAME_SIZE = 1472;
-//! Default 10GbE send frame size
-const size_t MPMD_UDP_10GE_DEFAULT_SEND_FRAME_SIZE = 4000;
-//! Default 10GbE receive frame size
-const size_t MPMD_UDP_10GE_DEFAULT_RECV_FRAME_SIZE = 4000;
-
-//!
-const double MPMD_BUFFER_DEPTH = 50.0e-3; // s
-//! For MTU discovery, the time we wait for a packet before calling it
-// oversized (seconds).
-const double MPMD_MTU_DISCOVERY_TIMEOUT = 0.02;
-
-// TODO: move these to appropriate header file for all other devices
-const double MAX_RATE_1GIGE = 1e9 / 8; // byte/s
-const double MAX_RATE_10GIGE = 10e9 / 8; // byte/s
-
-std::vector<std::string> get_addrs_from_mb_args(const uhd::device_addr_t& mb_args)
-{
- // mb_args must always include addr
- if (not mb_args.has_key(FIRST_ADDR_KEY)) {
- throw uhd::runtime_error(
- "The " + FIRST_ADDR_KEY
- + " key must be specified in "
- "device args to create an Ethernet transport to an RFNoC block");
- }
- std::vector<std::string> addrs{mb_args[FIRST_ADDR_KEY]};
- if (mb_args.has_key(SECOND_ADDR_KEY)) {
- addrs.push_back(mb_args[SECOND_ADDR_KEY]);
- }
- return addrs;
-}
-
-/*! Do a binary search to discover MTU
- *
- * Uses the MPM echo service to figure out MTU. We simply send a bunch of
- * packets and see if they come back until we converged on the path MTU.
- * The end result must lie between \p min_frame_size and \p max_frame_size.
- *
- * \param address IP address
- * \param port UDP port (yeah it's a string!)
- * \param min_frame_size Minimum frame size, initialize algorithm to start
- * with this value
- * \param max_frame_size Maximum frame size, initialize algorithm to start
- * with this value
- * \param echo_timeout Timeout value in seconds. For frame sizes that
- * exceed the MTU, we don't expect a response, and this
- * is the amount of time we'll wait before we assume
- * the frame size exceeds the MTU.
- */
-size_t discover_mtu(const std::string& address,
- const std::string& port,
- size_t min_frame_size,
- size_t max_frame_size,
- const double echo_timeout = 0.020)
-{
- const size_t echo_prefix_offset = uhd::mpmd::mpmd_impl::MPM_ECHO_CMD.size();
- const size_t mtu_hdr_len = echo_prefix_offset + 10;
- UHD_ASSERT_THROW(min_frame_size < max_frame_size);
- UHD_ASSERT_THROW(min_frame_size % 4 == 0);
- UHD_ASSERT_THROW(max_frame_size % 4 == 0);
- UHD_ASSERT_THROW(min_frame_size >= echo_prefix_offset + mtu_hdr_len);
- using namespace uhd::transport;
- // The return port will probably differ from the discovery port, so we
- // need a "broadcast" UDP connection; using make_connected() would
- // drop packets
- udp_simple::sptr udp = udp_simple::make_broadcast(address, port);
- std::string send_buf(uhd::mpmd::mpmd_impl::MPM_ECHO_CMD);
- send_buf.resize(max_frame_size, '#');
- UHD_ASSERT_THROW(send_buf.size() == max_frame_size);
- std::vector<uint8_t> recv_buf;
- recv_buf.resize(max_frame_size, ' ');
-
- // Little helper to check returned packets match the sent ones
- auto require_bufs_match = [&recv_buf, &send_buf, mtu_hdr_len](const size_t len) {
- if (len < mtu_hdr_len
- or std::memcmp((void*)&recv_buf[0], (void*)&send_buf[0], mtu_hdr_len) != 0) {
- throw uhd::runtime_error("Unexpected content of MTU "
- "discovery return packet!");
- }
- };
- UHD_LOG_TRACE("MPMD", "Determining UDP MTU... ");
- size_t seq_no = 0;
- while (min_frame_size < max_frame_size) {
- // Only test multiples of 4 bytes!
- const size_t test_frame_size = (max_frame_size / 2 + min_frame_size / 2 + 3)
- & ~size_t(3);
- // Encode sequence number and current size in the string, makes it
- // easy to debug in code or Wireshark. Is also used for identifying
- // response packets.
- std::sprintf(
- &send_buf[echo_prefix_offset], ";%04lu,%04lu", seq_no++, test_frame_size);
- UHD_LOG_TRACE("MPMD", "Testing frame size " << test_frame_size);
- udp->send(boost::asio::buffer(&send_buf[0], test_frame_size));
-
- const size_t len = udp->recv(boost::asio::buffer(recv_buf), echo_timeout);
- if (len == 0) {
- // Nothing received, so this is probably too big
- max_frame_size = test_frame_size - 4;
- } else if (len >= test_frame_size) {
- // Size went through, so bump the minimum
- require_bufs_match(len);
- min_frame_size = test_frame_size;
- } else if (len < test_frame_size) {
- // This is an odd case. Something must have snipped the packet
- // on the way back. Still, we'll just back off and try
- // something smaller.
- UHD_LOG_DEBUG("MPMD", "Unexpected packet truncation during MTU discovery.");
- require_bufs_match(len);
- max_frame_size = len;
- }
- }
- UHD_LOG_DEBUG("MPMD", "Path MTU for address " << address << ": " << min_frame_size);
- return min_frame_size;
-}
-
-} // namespace
-
-
-mpmd_xport_ctrl_udp::mpmd_xport_ctrl_udp(const uhd::device_addr_t& mb_args)
- : _mb_args(mb_args)
- , _recv_args(filter_args(mb_args, "recv"))
- , _send_args(filter_args(mb_args, "send"))
- , _available_addrs(get_addrs_from_mb_args(mb_args))
- , _mtu(MPMD_10GE_DATA_FRAME_MAX_SIZE)
-{
- const std::string mpm_discovery_port = _mb_args.get(
- mpmd_impl::MPM_DISCOVERY_PORT_KEY, std::to_string(mpmd_impl::MPM_DISCOVERY_PORT));
- auto discover_mtu_for_ip = [mpm_discovery_port](const std::string& ip_addr) {
- return discover_mtu(ip_addr,
- mpm_discovery_port,
- IP_PROTOCOL_MIN_MTU_SIZE - IP_PROTOCOL_UDP_PLUS_IP_HEADER,
- MPMD_10GE_DATA_FRAME_MAX_SIZE,
- MPMD_MTU_DISCOVERY_TIMEOUT);
- };
-
- for (const auto& ip_addr : _available_addrs) {
- _mtu = std::min(_mtu, discover_mtu_for_ip(ip_addr));
- }
-}
-
-uhd::both_xports_t mpmd_xport_ctrl_udp::make_transport(
- mpmd_xport_mgr::xport_info_t& xport_info,
- const usrp::device3_impl::xport_type_t xport_type,
- const uhd::device_addr_t& xport_args)
-{
-
- double link_speed = MAX_RATE_1GIGE;
- if (xport_info.count("link_speed") == 0) {
- UHD_LOG_WARNING("MPMD",
- "Could not determine link speed; using 1GibE max speed of "
- << MAX_RATE_1GIGE);
- } else {
- link_speed = xport_info.at("link_speed") == "10000" ? MAX_RATE_10GIGE
- : MAX_RATE_1GIGE;
- }
-
- // Constrain by this transport's MTU and the MTU in the xport_args
- const size_t send_mtu = std::min(get_mtu(uhd::TX_DIRECTION),
- xport_args.cast<size_t>("mtu", get_mtu(uhd::TX_DIRECTION)));
- const size_t recv_mtu = std::min(get_mtu(uhd::RX_DIRECTION),
- xport_args.cast<size_t>("mtu", get_mtu(uhd::RX_DIRECTION)));
-
- // Create actual UDP transport
- transport::zero_copy_xport_params default_buff_args;
- default_buff_args.num_send_frames = MPMD_UDP_DEFAULT_NUM_SEND_FRAMES;
- default_buff_args.num_recv_frames = MPMD_UDP_DEFAULT_NUM_RECV_FRAMES;
- default_buff_args.recv_frame_size = MPMD_UDP_MSG_FRAME_SIZE;
- default_buff_args.send_frame_size = MPMD_UDP_MSG_FRAME_SIZE;
- default_buff_args.recv_buff_size = link_speed * MPMD_BUFFER_DEPTH;
- default_buff_args.send_buff_size = link_speed * MPMD_BUFFER_DEPTH;
- if (xport_type == usrp::device3_impl::CTRL) {
- default_buff_args.num_recv_frames =
- uhd::rfnoc::CMD_FIFO_SIZE / uhd::rfnoc::MAX_CMD_PKT_SIZE;
- } else if (xport_type == usrp::device3_impl::TX_DATA) {
- const size_t default_frame_size = (link_speed == MAX_RATE_10GIGE ?
- MPMD_UDP_10GE_DEFAULT_SEND_FRAME_SIZE :
- MPMD_UDP_1GE_DEFAULT_SEND_FRAME_SIZE);
- default_buff_args.send_frame_size =
- xport_args.cast<size_t>("send_frame_size",
- std::min(default_frame_size, send_mtu));
- default_buff_args.num_send_frames =
- xport_args.cast<size_t>("num_send_frames",
- default_buff_args.num_send_frames);
- default_buff_args.send_buff_size =
- xport_args.cast<size_t>("send_buff_size",
- default_buff_args.send_buff_size);
- } else if (xport_type == usrp::device3_impl::RX_DATA) {
- const size_t default_frame_size = (link_speed == MAX_RATE_10GIGE ?
- MPMD_UDP_10GE_DEFAULT_RECV_FRAME_SIZE :
- MPMD_UDP_1GE_DEFAULT_RECV_FRAME_SIZE);
- default_buff_args.recv_frame_size =
- xport_args.cast<size_t>("recv_frame_size",
- std::min(default_frame_size, recv_mtu));
- default_buff_args.num_recv_frames =
- xport_args.cast<size_t>("num_recv_frames",
- default_buff_args.num_recv_frames);
- default_buff_args.recv_buff_size =
- xport_args.cast<size_t>("recv_buff_size",
- default_buff_args.recv_buff_size);
- }
- transport::udp_zero_copy::buff_params buff_params;
- auto recv = transport::udp_zero_copy::make(xport_info["ipv4"],
- xport_info["port"],
- default_buff_args,
- buff_params);
- const uint16_t port = recv->get_local_port();
- const std::string src_ip_addr = recv->get_local_addr();
- xport_info["src_port"] = std::to_string(port);
- xport_info["src_ipv4"] = src_ip_addr;
-
- // Create both_xports_t object and finish:
- both_xports_t xports;
- xports.endianness = uhd::ENDIANNESS_BIG;
- xports.send_sid = sid_t(xport_info["send_sid"]);
- xports.recv_sid = xports.send_sid.reversed();
- xports.recv_buff_size = buff_params.recv_buff_size;
- xports.send_buff_size = buff_params.send_buff_size;
- xports.recv = recv; // Note: This is a type cast!
- xports.send = recv; // This too
- return xports;
-}
-
-bool mpmd_xport_ctrl_udp::is_valid(const mpmd_xport_mgr::xport_info_t& xport_info) const
-{
- return std::find(
- _available_addrs.cbegin(), _available_addrs.cend(), xport_info.at("ipv4"))
- != _available_addrs.cend();
-}
-
-size_t mpmd_xport_ctrl_udp::get_mtu(const uhd::direction_t /*dir*/) const
-{
- return _mtu;
-}
diff --git a/host/lib/usrp/mpmd/mpmd_xport_ctrl_udp.hpp b/host/lib/usrp/mpmd/mpmd_xport_ctrl_udp.hpp
deleted file mode 100644
index 86301bb2a..000000000
--- a/host/lib/usrp/mpmd/mpmd_xport_ctrl_udp.hpp
+++ /dev/null
@@ -1,45 +0,0 @@
-//
-// Copyright 2017 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#ifndef INCLUDED_MPMD_XPORT_ctrl_udp_HPP
-#define INCLUDED_MPMD_XPORT_ctrl_udp_HPP
-
-#include "../device3/device3_impl.hpp"
-#include "mpmd_xport_ctrl_base.hpp"
-#include <uhd/types/device_addr.hpp>
-
-namespace uhd { namespace mpmd { namespace xport {
-
-/*! UDP transport manager
- *
- * Opens UDP sockets
- */
-class mpmd_xport_ctrl_udp : public mpmd_xport_ctrl_base
-{
-public:
- mpmd_xport_ctrl_udp(const uhd::device_addr_t& mb_args);
-
- both_xports_t make_transport(mpmd_xport_mgr::xport_info_t& xport_info,
- const usrp::device3_impl::xport_type_t xport_type,
- const uhd::device_addr_t& xport_args);
-
- bool is_valid(const mpmd_xport_mgr::xport_info_t& xport_info) const;
-
- size_t get_mtu(const uhd::direction_t dir) const;
-
-private:
- const uhd::device_addr_t _mb_args;
- const uhd::dict<std::string, std::string> _recv_args;
- const uhd::dict<std::string, std::string> _send_args;
- //! A list of IP addresses we can connect our CHDR connections to
- const std::vector<std::string> _available_addrs;
- //! MTU
- size_t _mtu;
-};
-
-}}} /* namespace uhd::mpmd::xport */
-
-#endif /* INCLUDED_MPMD_XPORT_ctrl_udp_HPP */
diff --git a/host/lib/usrp/mpmd/mpmd_xport_mgr.cpp b/host/lib/usrp/mpmd/mpmd_xport_mgr.cpp
deleted file mode 100644
index d3023e3af..000000000
--- a/host/lib/usrp/mpmd/mpmd_xport_mgr.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-//
-// Copyright 2017 Ettus Research, National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "mpmd_xport_mgr.hpp"
-#include "mpmd_impl.hpp"
-#include "mpmd_xport_ctrl_base.hpp"
-#include "mpmd_xport_ctrl_udp.hpp"
-#ifdef HAVE_LIBERIO
-# include "mpmd_xport_ctrl_liberio.hpp"
-#endif
-#ifdef HAVE_DPDK
-# include "mpmd_xport_ctrl_dpdk_udp.hpp"
-#endif
-
-uhd::dict<std::string, std::string> uhd::mpmd::xport::filter_args(
- const uhd::device_addr_t& args, const std::string& prefix)
-{
- uhd::dict<std::string, std::string> filtered_args;
- for (const std::string& key : args.keys()) {
- if (key.find(prefix) != std::string::npos) {
- filtered_args[key] = args[key];
- }
- }
-
- return filtered_args;
-}
-
-using namespace uhd::mpmd::xport;
-
-class mpmd_xport_mgr_impl : public mpmd_xport_mgr
-{
-public:
- mpmd_xport_mgr_impl(const uhd::device_addr_t& mb_args) : _mb_args(mb_args)
- {
- // nop
- }
-
- /**************************************************************************
- * API (see mpmd_xport_mgr.hpp)
- *************************************************************************/
- uhd::both_xports_t make_transport(const xport_info_list_t& xport_info_list,
- const uhd::usrp::device3_impl::xport_type_t xport_type,
- const uhd::device_addr_t& xport_args,
- xport_info_t& xport_info_out)
- {
- for (const auto& xport_info : xport_info_list) {
- require_xport_mgr(xport_info.at("type"));
- }
-
- // Run our incredibly smart selection algorithm
- xport_info_out = select_xport_option(xport_info_list);
- const std::string xport_medium = xport_info_out.at("type");
- UHD_LOG_TRACE("MPMD", __func__ << "(): xport medium is " << xport_medium);
-
- UHD_ASSERT_THROW(_xport_ctrls.count(xport_medium) > 0);
- UHD_ASSERT_THROW(_xport_ctrls.at(xport_medium));
- // When we've picked our preferred option, pass it to the transport
- // implementation for execution:
- return _xport_ctrls.at(xport_medium)
- ->make_transport(xport_info_out, xport_type, xport_args);
- }
-
- size_t get_mtu(const uhd::direction_t dir) const
- {
- if (_xport_ctrls.empty()) {
- UHD_LOG_WARNING("MPMD",
- "Cannot determine MTU, no transport controls have been "
- "established!");
- return 0;
- }
-
- size_t mtu = ~size_t(0);
- for (const auto& xport_ctrl_pair : _xport_ctrls) {
- mtu = std::min(mtu, xport_ctrl_pair.second->get_mtu(dir));
- }
-
- return mtu;
- }
-
-
-private:
- /**************************************************************************
- * Private methods / helpers
- *************************************************************************/
- /*! Picks a transport option based on available data
- *
- * \param xport_info_list List of available options, they all need to be
- * valid choices.
- *
- * \returns One element of \p xport_info_list based on a selection
- * algorithm.
- */
- xport_info_t select_xport_option(const xport_info_list_t& xport_info_list) const
- {
- for (const auto& xport_info : xport_info_list) {
- const std::string xport_medium = xport_info.at("type");
- if (_xport_ctrls.count(xport_medium) != 0 and _xport_ctrls.at(xport_medium)
- and _xport_ctrls.at(xport_medium)->is_valid(xport_info)) {
- return xport_info;
- }
- }
-
- throw uhd::runtime_error(
- "Could not select a transport option! "
- "Either a transport hint was not specified or the specified "
- "hint does not support communication with RFNoC blocks.");
- }
-
- //! Create an instance of an xport manager implementation
- //
- // \param xport_medium "UDP" or "liberio"
- // \param mb_args Device args
- mpmd_xport_ctrl_base::uptr make_mgr_impl(
- const std::string& xport_medium, const uhd::device_addr_t& mb_args) const
- {
- if (xport_medium == "UDP") {
-#ifdef HAVE_DPDK
- if (mb_args.has_key("use_dpdk")) {
- return mpmd_xport_ctrl_base::uptr(new mpmd_xport_ctrl_dpdk_udp(mb_args));
- }
-#endif
- return mpmd_xport_ctrl_base::uptr(new mpmd_xport_ctrl_udp(mb_args));
-#ifdef HAVE_LIBERIO
- } else if (xport_medium == "liberio") {
- return mpmd_xport_ctrl_base::uptr(new mpmd_xport_ctrl_liberio(mb_args));
-#endif
- } else {
- UHD_LOG_WARNING(
- "MPMD", "Cannot instantiate transport medium " << xport_medium);
- return nullptr;
- }
- }
-
- //! This will try to make _xport_ctrls contain a valid transport manager
- // for \p xport_medium
- //
- // When this function returns, it will be possible to access
- // this->_xport_ctrls[xport_medium].
- //
- // \param xport_medium Type of transport, e.g. "UDP", "liberio", ...
- //
- // \throws uhd::key_error if \p xport_medium is not known or registered
- void require_xport_mgr(const std::string& xport_medium)
- {
- if (_xport_ctrls.count(xport_medium) == 0) {
- UHD_LOG_TRACE(
- "MPMD", "Instantiating transport manager `" << xport_medium << "'");
- auto mgr_impl = make_mgr_impl(xport_medium, _mb_args);
- if (mgr_impl) {
- _xport_ctrls[xport_medium] = std::move(mgr_impl);
- }
- }
- }
-
- /**************************************************************************
- * Private attributes
- *************************************************************************/
- //! Cache available xport manager implementations
- //
- // Should only every be populated by require_xport_mgr()
- std::unordered_map<std::string, mpmd_xport_ctrl_base::uptr> _xport_ctrls;
-
- //! Motherboard args, can contain things like 'recv_buff_size'
- const uhd::device_addr_t _mb_args;
-};
-
-mpmd_xport_mgr::uptr mpmd_xport_mgr::make(const uhd::device_addr_t& mb_args)
-{
- return mpmd_xport_mgr::uptr(new mpmd_xport_mgr_impl(mb_args));
-}