aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/lib/include/uhdlib/rfnoc/epid_allocator.hpp9
-rw-r--r--host/lib/include/uhdlib/rfnoc/graph_stream_manager.hpp50
-rw-r--r--host/lib/include/uhdlib/rfnoc/link_stream_manager.hpp89
-rw-r--r--host/lib/include/uhdlib/rfnoc/mgmt_portal.hpp31
-rw-r--r--host/lib/include/uhdlib/rfnoc/rfnoc_common.hpp18
-rw-r--r--host/lib/rfnoc/epid_allocator.cpp14
-rw-r--r--host/lib/rfnoc/graph_stream_manager.cpp104
-rw-r--r--host/lib/rfnoc/link_stream_manager.cpp98
-rw-r--r--host/lib/rfnoc/mgmt_portal.cpp76
9 files changed, 408 insertions, 81 deletions
diff --git a/host/lib/include/uhdlib/rfnoc/epid_allocator.hpp b/host/lib/include/uhdlib/rfnoc/epid_allocator.hpp
index c92ca013d..ec23dcb50 100644
--- a/host/lib/include/uhdlib/rfnoc/epid_allocator.hpp
+++ b/host/lib/include/uhdlib/rfnoc/epid_allocator.hpp
@@ -33,12 +33,19 @@ public:
*/
sep_id_t allocate_epid(const sep_addr_t& addr);
+ /*! \brief Get a pre-allocated EPID. Throws an exception is not allocated
+ *
+ * \param addr The physical address (device, instance) of the stream endpoint
+ * \return The allocated EPID
+ */
+ sep_id_t get_epid(const sep_addr_t& addr);
+
/*! \brief Lookup an EPID and return the address associated with it.
*
* \param epid The allocated EPID
* \return The physical address (device, instance) of the stream endpoint
*/
- sep_addr_t lookup_epid(const sep_id_t& epid) const;
+ sep_addr_t lookup_addr(const sep_id_t& epid) const;
/*! \brief Deallocate the specified EPID.
*
diff --git a/host/lib/include/uhdlib/rfnoc/graph_stream_manager.hpp b/host/lib/include/uhdlib/rfnoc/graph_stream_manager.hpp
index 81657453d..120b0e0f8 100644
--- a/host/lib/include/uhdlib/rfnoc/graph_stream_manager.hpp
+++ b/host/lib/include/uhdlib/rfnoc/graph_stream_manager.hpp
@@ -15,6 +15,7 @@
#include <functional>
#include <memory>
#include <set>
+#include <tuple>
namespace uhd { namespace rfnoc {
@@ -41,25 +42,34 @@ public:
*/
virtual const std::set<sep_addr_t>& get_reachable_endpoints() const = 0;
- /*! \brief Initialize a control endpoint to the specified destination
+ /*! \brief Connect the host to the specified destination and create a control stream
*
* \param dst_addr The physical address of the destination endpoint
* \param via_device The preference for the device to take to get to the destination
* \return A pair (source, destination) endpoint IDs for the control stream
*/
- virtual sep_id_pair_t init_ctrl_stream(
- sep_addr_t dst_addr, device_id_t via_device = NULL_DEVICE_ID) = 0;
+ virtual sep_id_pair_t connect_host_to_device(
+ sep_addr_t dst_addr, device_id_t host_device = NULL_DEVICE_ID) = 0;
+
+ /*! \brief Connect two remote endpoints to each other
+ *
+ * \param dst_addr The physical address of the destination endpoint
+ * \param src_addr The physical address of the source endpoint
+ * \return A pair (source, destination) endpoint IDs for the src/dst
+ */
+ virtual sep_id_pair_t connect_device_to_device(
+ sep_addr_t dst_addr, sep_addr_t src_addr) = 0;
/*! \brief Get a register iface (ctrlport endpoint) to a particular block
*
- * \param dst_epid The endpoint ID of the destination
+ * \param dst_addr The physical address of the destination endpoint
* \param block_index The index of the block in the device
* \param client_clk The clock that is driving the ctrlport slave
* \param timebase_clk The clock that is driving the timebase
* \param via_device The preference for the device to take to get to the destination
* \return An interface to the ctrlport endpoint
*/
- virtual ctrlport_endpoint::sptr get_block_register_iface(sep_id_t dst_epid,
+ virtual ctrlport_endpoint::sptr get_block_register_iface(sep_addr_t dst_addr,
uint16_t block_index,
const clock_iface& client_clk,
const clock_iface& timebase_clk,
@@ -72,8 +82,36 @@ public:
* \return An interface to the client zero instance
*/
virtual detail::client_zero::sptr get_client_zero(
- sep_id_t dst_epid, device_id_t via_device = NULL_DEVICE_ID) const = 0;
+ sep_addr_t dst_addr, device_id_t via_device = NULL_DEVICE_ID) const = 0;
+ /*! Configure a flow controlled data stream from the endpoint with ID src_epid to the
+ * endpoint with ID dst_epid
+ *
+ * \param dst_addr The physical address of the destination endpoint
+ * \param src_addr The physical address of the source endpoint
+ * \param lossy_xport Is the transport lossy?
+ * \param fc_freq_ratio Flow control response frequency as a ratio of the buff params
+ * \param fc_headroom_ratio Flow control headroom as a ratio of the buff params
+ * \param reset Optionally reset the stream
+ */
+ virtual std::tuple<sep_id_pair_t, stream_buff_params_t>
+ create_device_to_device_data_stream(const sep_addr_t dst_addr,
+ const sep_addr_t src_addr,
+ const bool lossy_xport,
+ const double fc_freq_ratio,
+ const double fc_headroom_ratio,
+ const bool reset = false) = 0;
+
+ // TODO: Implement functions to get graph-wide streamers
+
+ /*!
+ * \brief Create a graph_stream_manager and return a unique_ptr to it
+ *
+ * \param pkt_factory A factory for generating CHDR packets
+ * \param epid_alloc The allocator for all EPIDs in the graph
+ * \param links Pairs of host devices and motherboards that should be connected
+ * \return A unique_ptr to the newly-created graph_stream_manager
+ */
static uptr make(const chdr::chdr_packet_factory& pkt_factory,
const epid_allocator::sptr& epid_alloc,
const std::vector<std::pair<device_id_t, mb_iface*>>& links);
diff --git a/host/lib/include/uhdlib/rfnoc/link_stream_manager.hpp b/host/lib/include/uhdlib/rfnoc/link_stream_manager.hpp
index c31bf8987..4ff69bb3e 100644
--- a/host/lib/include/uhdlib/rfnoc/link_stream_manager.hpp
+++ b/host/lib/include/uhdlib/rfnoc/link_stream_manager.hpp
@@ -13,12 +13,19 @@
#include <uhdlib/rfnoc/mb_iface.hpp>
#include <functional>
#include <memory>
+#include <set>
namespace uhd { namespace rfnoc {
/*! A class that is responsible managing all data endpoints, control endpoints and client
- * zero instances accessible via a physical link. There must be one instance this this
- * class per physical link (Ethernet cable, PCIe connection, etc)
+ * zero instances accessible via a logical link between the host device and
+ * motherboard.
+ *
+ * Note that each transport adapter on the host has its own set of streaming endpoints,
+ * and thus, the host's device_id_t uniquely identifies the host-side transport adapter
+ * to use for packet transmission/reception.
+ *
+ * There must be one instance of this class per logical link.
*/
class link_stream_manager
{
@@ -39,12 +46,30 @@ public:
*/
virtual const std::set<sep_addr_t>& get_reachable_endpoints() const = 0;
- /*! \brief Initialize a control endpoint to the specified destination
+ /*! \brief Connect the host to the specified destination and init a control endpoint
*
* \param dst_addr The physical address of the destination endpoint
* \return A pair (source, destination) endpoint IDs for the control stream
*/
- virtual sep_id_pair_t init_ctrl_stream(sep_addr_t dst_addr) = 0;
+ virtual sep_id_pair_t connect_host_to_device(sep_addr_t dst_addr) = 0;
+
+ /*! \brief Check if the two specified endpoints can be connected remotely
+ *
+ * \param dst_addr The physical address of the destination endpoint
+ * \param src_addr The physical address of the source endpoint
+ * \return true if the endpoints can be connected
+ */
+ virtual bool can_connect_device_to_device(
+ sep_addr_t dst_addr, sep_addr_t src_addr) const = 0;
+
+ /*! \brief Connect two remote endpoints to each other
+ *
+ * \param dst_addr The physical address of the destination endpoint
+ * \param src_addr The physical address of the source endpoint
+ * \return A pair (source, destination) endpoint IDs for the src/dst
+ */
+ virtual sep_id_pair_t connect_device_to_device(
+ sep_addr_t dst_addr, sep_addr_t src_addr) = 0;
/*! \brief Get a register iface (ctrlport endpoint) to a particular block
*
@@ -66,15 +91,61 @@ public:
*/
virtual detail::client_zero::sptr get_client_zero(sep_id_t dst_epid) const = 0;
- /*! \brief Create a data stream
+ /*! Configure a flow controlled data stream from the endpoint with ID src_epid to the
+ * endpoint with ID dst_epid
*
* \param dst_epid The endpoint ID of the destination
- * \param vc The virtual channel
- * \param xport_args The transport argument
+ * \param src_epid The endpoint ID of the source
+ * \param lossy_xport Is the transport lossy?
+ * \param fc_freq_ratio Flow control response frequency as a ratio of the buff params
+ * \param fc_headroom_ratio Flow control headroom as a ratio of the buff params
+ * \param reset Optionally reset the stream
+ */
+ virtual stream_buff_params_t create_device_to_device_data_stream(
+ const sep_id_t& dst_epid,
+ const sep_id_t& src_epid,
+ const bool lossy_xport,
+ const double fc_freq_ratio,
+ const double fc_headroom_ratio,
+ const bool reset = false) = 0;
+
+ /*! \brief Create a data stream going from the host to the device
+ *
+ * \param dst_addr The address of the destination stream endpoint
+ * \param lossy_xport Is the transport lossy?
+ * \param pyld_buff_fmt Datatype of SW buffer that holds the data payload
+ * \param mdata_buff_fmt Datatype of SW buffer that holds the data metadata
+ * \param fc_freq_ratio Flow control response frequency as a ratio of the buff params
+ * \param fc_headroom_ratio Flow control headroom as a ratio of the buff params
+ * \param xport_args The transport arguments
+ * \return An transport instance
+ */
+ virtual chdr_data_xport_t create_host_to_device_data_stream(const sep_addr_t dst_addr,
+ const bool lossy_xport,
+ const sw_buff_t pyld_buff_fmt,
+ const sw_buff_t mdata_buff_fmt,
+ const double fc_freq_ratio,
+ const double fc_headroom_ratio,
+ const device_addr_t& xport_args) = 0;
+
+ /*! \brief Create a data stream going from the device to the host
+ *
+ * \param dst_addr The address of the destination stream endpoint
+ * \param lossy_xport Is the transport lossy?
+ * \param pyld_buff_fmt Datatype of SW buffer that holds the data payload
+ * \param mdata_buff_fmt Datatype of SW buffer that holds the data metadata
+ * \param fc_freq_ratio Flow control response frequency as a ratio of the buff params
+ * \param fc_headroom_ratio Flow control headroom as a ratio of the buff params
+ * \param xport_args The transport arguments
* \return An transport instance
*/
- virtual chdr_data_xport_t create_data_stream(
- sep_addr_t dst_addr, sep_vc_t vc, const device_addr_t& xport_args) = 0;
+ virtual chdr_data_xport_t create_device_to_host_data_stream(const sep_addr_t src_addr,
+ const bool lossy_xport,
+ const sw_buff_t pyld_buff_fmt,
+ const sw_buff_t mdata_buff_fmt,
+ const double fc_freq_ratio,
+ const double fc_headroom_ratio,
+ const device_addr_t& xport_args) = 0;
static uptr make(const chdr::chdr_packet_factory& pkt_factory,
mb_iface& mb_if,
diff --git a/host/lib/include/uhdlib/rfnoc/mgmt_portal.hpp b/host/lib/include/uhdlib/rfnoc/mgmt_portal.hpp
index 12f40f172..1412d0e3d 100644
--- a/host/lib/include/uhdlib/rfnoc/mgmt_portal.hpp
+++ b/host/lib/include/uhdlib/rfnoc/mgmt_portal.hpp
@@ -9,6 +9,7 @@
#include <uhdlib/rfnoc/chdr_types.hpp>
#include <memory>
+#include <set>
namespace uhd { namespace rfnoc { namespace mgmt {
@@ -26,13 +27,6 @@ public:
using xport_cfg_fn_t = std::function<void(
device_id_t devid, uint16_t inst, uint8_t subtype, chdr::mgmt_hop_t& hop)>;
- //! Flow control buffer configuration parameters
- struct buff_params_t
- {
- uint64_t bytes;
- uint32_t packets;
- };
-
//! Information about a stream endpoint
struct sep_info_t
{
@@ -50,9 +44,6 @@ public:
sep_addr_t addr;
};
- //! The data type of the buffer used to capture/generate data
- enum sw_buff_t { BUFF_U64 = 0, BUFF_U32 = 1, BUFF_U16 = 2, BUFF_U8 = 3 };
-
virtual ~mgmt_portal() = 0;
//! Get addresses for all stream endpoints reachable from this SW mgmt portal
@@ -90,6 +81,14 @@ public:
//
virtual void setup_local_route(const sep_id_t& dst_epid) = 0;
+ //! Can a route from between the source and destination endpoints be established?
+ //
+ // \param dst_epid The endpoint ID of the destination
+ // \param src_epid The endpoint ID of the source
+ //
+ virtual bool can_remote_route(
+ const sep_addr_t& dst_addr, const sep_addr_t& src_addr) const = 0;
+
//! Setup a route from between the source and destination endpoints
//
// After a route is established, it should be possible for the source to send packets
@@ -121,8 +120,8 @@ public:
const bool lossy_xport,
const sw_buff_t pyld_buff_fmt,
const sw_buff_t mdata_buff_fmt,
- const buff_params_t& fc_freq,
- const buff_params_t& fc_headroom,
+ const stream_buff_params_t& fc_freq,
+ const stream_buff_params_t& fc_headroom,
const bool reset = false) = 0;
//! Finish configuring a flow controlled receive data stream from the endpoint with
@@ -130,7 +129,7 @@ public:
//
// \param epid The endpoint ID of the data source
//
- virtual buff_params_t config_local_rx_stream_commit(
+ virtual stream_buff_params_t config_local_rx_stream_commit(
const sep_id_t& epid, const double timeout = 0.2) = 0;
//! Configure a flow controlled transmit data stream from this SW mgmt portal to the
@@ -156,11 +155,11 @@ public:
// \param fc_freq Flow control response frequency parameters
// \param fc_freq Flow control headroom parameters
//
- virtual buff_params_t config_remote_stream(const sep_id_t& dst_epid,
+ virtual stream_buff_params_t config_remote_stream(const sep_id_t& dst_epid,
const sep_id_t& src_epid,
const bool lossy_xport,
- const buff_params_t& fc_freq,
- const buff_params_t& fc_headroom,
+ const stream_buff_params_t& fc_freq,
+ const stream_buff_params_t& fc_headroom,
const bool reset = false,
const double timeout = 0.2) = 0;
diff --git a/host/lib/include/uhdlib/rfnoc/rfnoc_common.hpp b/host/lib/include/uhdlib/rfnoc/rfnoc_common.hpp
index bac510f04..c08c8d74a 100644
--- a/host/lib/include/uhdlib/rfnoc/rfnoc_common.hpp
+++ b/host/lib/include/uhdlib/rfnoc/rfnoc_common.hpp
@@ -56,16 +56,26 @@ static constexpr sep_addr_t NULL_DEVICE_ADDR{NULL_DEVICE_ID, 0};
static constexpr sep_id_t NULL_EPID = 0;
+//! Flow control buffer configuration parameters
+struct stream_buff_params_t
+{
+ uint64_t bytes;
+ uint32_t packets;
+};
+
+//! The data type of the buffer used to capture/generate data
+enum sw_buff_t { BUFF_U64 = 0, BUFF_U32 = 1, BUFF_U16 = 2, BUFF_U8 = 3 };
+
// TODO: Update these
struct chdr_ctrl_xport_t
{
chdr_ctrl_xport_t() = default;
uhd::transport::zero_copy_if::sptr recv;
uhd::transport::zero_copy_if::sptr send;
- size_t recv_buff_size = 0;
- size_t send_buff_size = 0;
- sep_id_t src_epid = 0;
- sep_id_t dst_epid = 0;
+ stream_buff_params_t recv_buff_params{0, 0};
+ stream_buff_params_t send_buff_params{0, 0};
+ sep_id_t src_epid{0};
+ sep_id_t dst_epid{0};
};
using chdr_data_xport_t = chdr_ctrl_xport_t;
diff --git a/host/lib/rfnoc/epid_allocator.cpp b/host/lib/rfnoc/epid_allocator.cpp
index 984b1716e..97a30dc64 100644
--- a/host/lib/rfnoc/epid_allocator.cpp
+++ b/host/lib/rfnoc/epid_allocator.cpp
@@ -27,7 +27,19 @@ sep_id_t epid_allocator::allocate_epid(const sep_addr_t& addr)
}
}
-sep_addr_t epid_allocator::lookup_epid(const sep_id_t& epid) const
+sep_id_t epid_allocator::get_epid(const sep_addr_t& addr)
+{
+ std::lock_guard<std::mutex> lock(_mutex);
+
+ if (_epid_map.count(addr) != 0) {
+ return _epid_map.at(addr);
+ } else {
+ throw uhd::lookup_error(
+ "An EPID has not been allocated for the requested endpoint");
+ }
+}
+
+sep_addr_t epid_allocator::lookup_addr(const sep_id_t& epid) const
{
std::lock_guard<std::mutex> lock(_mutex);
diff --git a/host/lib/rfnoc/graph_stream_manager.cpp b/host/lib/rfnoc/graph_stream_manager.cpp
index 06f78dad4..f2024786a 100644
--- a/host/lib/rfnoc/graph_stream_manager.cpp
+++ b/host/lib/rfnoc/graph_stream_manager.cpp
@@ -61,32 +61,120 @@ public:
return retval;
}
- virtual sep_id_pair_t init_ctrl_stream(
- sep_addr_t dst_addr, device_id_t via_device = NULL_DEVICE_ID)
+ virtual sep_id_pair_t connect_host_to_device(
+ sep_addr_t dst_addr, device_id_t host_device = NULL_DEVICE_ID)
{
- return _link_mgrs.at(_check_dst_and_find_src(dst_addr, via_device))
- ->init_ctrl_stream(dst_addr);
+ UHD_LOGGER_DEBUG("RFNOC::GRAPH")
+ << boost::format("Connecting the Host to Endpoint %d:%d through Device "
+ "%d (0 = no preference)... ")
+ % dst_addr.first % dst_addr.second % host_device;
+
+ // When we connect, we setup a route and fire up a control stream between
+ // the endpoints
+ device_id_t gateway = _check_dst_and_find_src(dst_addr, host_device);
+ sep_id_pair_t epid_pair =
+ _link_mgrs.at(gateway)->connect_host_to_device(dst_addr);
+ UHD_LOGGER_DEBUG("RFNOC::GRAPH")
+ << boost::format("Connection to Endpoint %d:%d completed through Device %d. "
+ "Using EPIDs %d -> %d.")
+ % dst_addr.first % dst_addr.second % gateway % epid_pair.first
+ % epid_pair.second;
+
+ return epid_pair;
}
- virtual ctrlport_endpoint::sptr get_block_register_iface(sep_id_t dst_epid,
+ virtual sep_id_pair_t connect_device_to_device(
+ sep_addr_t dst_addr, sep_addr_t src_addr)
+ {
+ UHD_LOGGER_DEBUG("RFNOC::GRAPH")
+ << boost::format("Connecting the Endpoint %d:%d to Endpoint %d:%d...")
+ % src_addr.first % src_addr.second % dst_addr.first % dst_addr.second;
+
+ // Iterate through all link managers and check if they are capable of connecting
+ // the requested endpoints. If no one can connect then the endpoints may actually
+ // not share a common crossbar or we don't have enough connectivity in the
+ // software session to reach the common crossbar.
+ for (auto& kv : _link_mgrs) {
+ if (kv.second->can_connect_device_to_device(dst_addr, src_addr)) {
+ sep_id_pair_t epid_pair =
+ kv.second->connect_device_to_device(dst_addr, src_addr);
+ UHD_LOGGER_DEBUG("RFNOC::GRAPH")
+ << boost::format("Connection from Endpoint %d:%d to Endpoint %d:%d "
+ "completed through Device %d. Using "
+ "EPIDs %d -> %d.")
+ % src_addr.first % src_addr.second % dst_addr.first
+ % dst_addr.second % kv.first % epid_pair.first
+ % epid_pair.second;
+ return epid_pair;
+ }
+ }
+ throw uhd::routing_error("The specified destination is unreachable from the "
+ "specified source endpoint");
+ }
+
+ virtual ctrlport_endpoint::sptr get_block_register_iface(sep_addr_t dst_addr,
uint16_t block_index,
const clock_iface& client_clk,
const clock_iface& timebase_clk,
device_id_t via_device = NULL_DEVICE_ID)
{
- sep_addr_t dst_addr = _epid_alloc->lookup_epid(dst_epid);
+ // We must be connected to dst_addr before getting a register iface
+ sep_id_t dst_epid = _epid_alloc->get_epid(dst_addr);
return _link_mgrs.at(_check_dst_and_find_src(dst_addr, via_device))
->get_block_register_iface(dst_epid, block_index, client_clk, timebase_clk);
}
virtual detail::client_zero::sptr get_client_zero(
- sep_id_t dst_epid, device_id_t via_device = NULL_DEVICE_ID) const
+ sep_addr_t dst_addr, device_id_t via_device = NULL_DEVICE_ID) const
{
- sep_addr_t dst_addr = _epid_alloc->lookup_epid(dst_epid);
+ // We must be connected to dst_addr before getting a client zero
+ sep_id_t dst_epid = _epid_alloc->get_epid(dst_addr);
return _link_mgrs.at(_check_dst_and_find_src(dst_addr, via_device))
->get_client_zero(dst_epid);
}
+ virtual std::tuple<sep_id_pair_t, stream_buff_params_t>
+ create_device_to_device_data_stream(const sep_addr_t dst_addr,
+ const sep_addr_t src_addr,
+ const bool lossy_xport,
+ const double fc_freq_ratio,
+ const double fc_headroom_ratio,
+ const bool reset = false)
+ {
+ UHD_LOGGER_DEBUG("RFNOC::GRAPH")
+ << boost::format(
+ "Initializing data stream from Endpoint %d:%d to Endpoint %d:%d...")
+ % src_addr.first % src_addr.second % dst_addr.first % dst_addr.second;
+
+ // Iterate through all link managers and check if they are capable of connecting
+ // the requested endpoints. If no one can connect then the endpoints may actually
+ // not share a common crossbar or we don't have enough connectivity in the
+ // software session to reach the common crossbar.
+ for (auto& kv : _link_mgrs) {
+ if (kv.second->can_connect_device_to_device(dst_addr, src_addr)) {
+ sep_id_pair_t epid_pair =
+ kv.second->connect_device_to_device(dst_addr, src_addr);
+ UHD_LOGGER_DEBUG("RFNOC::GRAPH")
+ << boost::format("Connection from Endpoint %d:%d to Endpoint %d:%d "
+ "completed through Device %d. Using "
+ "EPIDs %d -> %d.")
+ % src_addr.first % src_addr.second % dst_addr.first
+ % dst_addr.second % kv.first % epid_pair.first
+ % epid_pair.second;
+ stream_buff_params_t buff_params =
+ kv.second->create_device_to_device_data_stream(epid_pair.second,
+ epid_pair.first,
+ lossy_xport,
+ fc_freq_ratio,
+ fc_headroom_ratio,
+ reset);
+ return std::make_tuple(epid_pair, buff_params);
+ }
+ }
+ throw uhd::routing_error("The specified destination is unreachable from the "
+ "specified source endpoint");
+ }
+
private:
device_id_t _check_dst_and_find_src(sep_addr_t dst_addr, device_id_t via_device) const
{
diff --git a/host/lib/rfnoc/link_stream_manager.cpp b/host/lib/rfnoc/link_stream_manager.cpp
index 0faec94e3..bd330e313 100644
--- a/host/lib/rfnoc/link_stream_manager.cpp
+++ b/host/lib/rfnoc/link_stream_manager.cpp
@@ -6,7 +6,6 @@
#include <uhd/exception.hpp>
#include <uhd/transport/muxed_zero_copy_if.hpp>
-#include <uhd/utils/log.hpp>
#include <uhdlib/rfnoc/chdr_ctrl_endpoint.hpp>
#include <uhdlib/rfnoc/link_stream_manager.hpp>
#include <uhdlib/rfnoc/mgmt_portal.hpp>
@@ -22,6 +21,8 @@ using namespace uhd::rfnoc::detail;
constexpr sep_inst_t SEP_INST_MGMT_CTRL = 0;
constexpr sep_inst_t SEP_INST_DATA_BASE = 1;
+constexpr double STREAM_SETUP_TIMEOUT = 0.2;
+
link_stream_manager::~link_stream_manager() = default;
class link_stream_manager_impl : public link_stream_manager
@@ -109,15 +110,18 @@ public:
return _mgmt_portal->get_reachable_endpoints();
}
- virtual sep_id_pair_t init_ctrl_stream(sep_addr_t dst_addr)
+ virtual bool can_connect_device_to_device(
+ sep_addr_t dst_addr, sep_addr_t src_addr) const
+ {
+ return _mgmt_portal->can_remote_route(dst_addr, src_addr);
+ }
+
+ virtual sep_id_pair_t connect_host_to_device(sep_addr_t dst_addr)
{
+ _ensure_ep_is_reachable(dst_addr);
+
// Allocate EPIDs
sep_id_t dst_epid = _epid_alloc->allocate_epid(dst_addr);
- UHD_LOGGER_DEBUG("RFNOC::LINK_MGR")
- << boost::format("Initializing control stream to Endpoint %d:%d with EPID "
- "%d...")
- % dst_addr.first % dst_addr.second % dst_epid;
- _ensure_ep_is_reachable(dst_addr);
// Make sure that the software side of the endpoint is initialized and reachable
if (_ctrl_ep == nullptr) {
@@ -142,6 +146,25 @@ public:
return sep_id_pair_t(_my_mgmt_ctrl_epid, dst_epid);
}
+ virtual sep_id_pair_t connect_device_to_device(
+ sep_addr_t dst_addr, sep_addr_t src_addr)
+ {
+ _ensure_ep_is_reachable(dst_addr);
+ _ensure_ep_is_reachable(src_addr);
+
+ // Allocate EPIDs
+ sep_id_t dst_epid = _epid_alloc->allocate_epid(dst_addr);
+ sep_id_t src_epid = _epid_alloc->allocate_epid(src_addr);
+
+ // Initialize endpoints
+ _mgmt_portal->initialize_endpoint(dst_addr, dst_epid);
+ _mgmt_portal->initialize_endpoint(src_addr, src_epid);
+
+ _mgmt_portal->setup_remote_route(dst_epid, src_epid);
+
+ return sep_id_pair_t(src_epid, dst_epid);
+ }
+
virtual ctrlport_endpoint::sptr get_block_register_iface(sep_id_t dst_epid,
uint16_t block_index,
const clock_iface& client_clk,
@@ -179,8 +202,54 @@ public:
return _client_zero_map.at(dst_epid);
}
- virtual chdr_data_xport_t create_data_stream(
- sep_addr_t dst_addr, sep_vc_t /*vc*/, const device_addr_t& xport_args)
+ virtual stream_buff_params_t create_device_to_device_data_stream(
+ const sep_id_t& dst_epid,
+ const sep_id_t& src_epid,
+ const bool lossy_xport,
+ const double fc_freq_ratio,
+ const double fc_headroom_ratio,
+ const bool reset = false)
+ {
+ // We assume that the devices are already connected (because this API requires
+ // EPIDs)
+
+ // Setup a stream
+ stream_buff_params_t buff_params = _mgmt_portal->config_remote_stream(dst_epid,
+ src_epid,
+ lossy_xport,
+ stream_buff_params_t{1, 1}, // Dummy frequency
+ stream_buff_params_t{0, 0}, // Dummy headroom
+ false,
+ STREAM_SETUP_TIMEOUT);
+
+ // Compute FC frequency and headroom based on buff parameters
+ stream_buff_params_t fc_freq{
+ static_cast<uint64_t>(std::ceil(double(buff_params.bytes) * fc_freq_ratio)),
+ static_cast<uint32_t>(
+ std::ceil(double(buff_params.packets) * fc_freq_ratio))};
+ stream_buff_params_t fc_headroom{
+ static_cast<uint64_t>(
+ std::ceil(double(buff_params.bytes) * fc_headroom_ratio)),
+ static_cast<uint32_t>(
+ std::ceil(double(buff_params.packets) * fc_headroom_ratio))};
+
+ // Reconfigure flow control using the new frequency and headroom
+ return _mgmt_portal->config_remote_stream(dst_epid,
+ src_epid,
+ lossy_xport,
+ fc_freq,
+ fc_headroom,
+ reset,
+ STREAM_SETUP_TIMEOUT);
+ }
+
+ virtual chdr_data_xport_t create_host_to_device_data_stream(const sep_addr_t dst_addr,
+ const bool lossy_xport,
+ const sw_buff_t pyld_buff_fmt,
+ const sw_buff_t mdata_buff_fmt,
+ const double fc_freq_ratio,
+ const double fc_headroom_ratio,
+ const device_addr_t& xport_args)
{
// Create a new source endpoint and EPID
sep_addr_t sw_epid_addr(_my_device_id, SEP_INST_DATA_BASE + (_data_ep_inst++));
@@ -219,6 +288,17 @@ public:
return xport;
}
+ virtual chdr_data_xport_t create_device_to_host_data_stream(const sep_addr_t src_addr,
+ const bool lossy_xport,
+ const sw_buff_t pyld_buff_fmt,
+ const sw_buff_t mdata_buff_fmt,
+ const double fc_freq_ratio,
+ const double fc_headroom_ratio,
+ const device_addr_t& xport_args)
+ {
+ // TODO: Implement me
+ }
+
private:
void _ensure_ep_is_reachable(const sep_addr_t& ep_addr_)
{
diff --git a/host/lib/rfnoc/mgmt_portal.cpp b/host/lib/rfnoc/mgmt_portal.cpp
index deb9f9166..ba54f83d0 100644
--- a/host/lib/rfnoc/mgmt_portal.cpp
+++ b/host/lib/rfnoc/mgmt_portal.cpp
@@ -43,10 +43,8 @@ constexpr uint32_t RESET_AND_FLUSH_ISTRM = (1 << 1);
constexpr uint32_t RESET_AND_FLUSH_CTRL = (1 << 2);
constexpr uint32_t RESET_AND_FLUSH_ALL = 0x7;
-constexpr uint32_t BUILD_CTRL_STATUS_WORD(bool cfg_start,
- bool xport_lossy,
- mgmt_portal::sw_buff_t pyld_buff_fmt,
- mgmt_portal::sw_buff_t mdata_buff_fmt)
+constexpr uint32_t BUILD_CTRL_STATUS_WORD(
+ bool cfg_start, bool xport_lossy, sw_buff_t pyld_buff_fmt, sw_buff_t mdata_buff_fmt)
{
return (cfg_start ? 1 : 0) | (xport_lossy ? 2 : 0)
| (static_cast<uint32_t>(pyld_buff_fmt) << 2)
@@ -346,29 +344,52 @@ public:
% dst_epid % to_string(node_addr)));
}
- virtual void setup_remote_route(const sep_id_t& dst_epid, const sep_id_t& src_epid)
+ virtual bool can_remote_route(
+ const sep_addr_t& dst_addr, const sep_addr_t& src_addr) const
{
std::lock_guard<std::recursive_mutex> lock(_mutex);
+ if ((_discovered_ep_set.count(dst_addr) == 0)
+ || (_discovered_ep_set.count(src_addr) == 0)) {
+ // Can't route to/from something if we don't know about it
+ return false;
+ }
+
+ UHD_ASSERT_THROW(_node_addr_map.count(node_id_t(dst_addr)) > 0);
+ UHD_ASSERT_THROW(_node_addr_map.count(node_id_t(src_addr)) > 0);
+
// Lookup the src and dst node address using the endpoint ID
- const node_addr_t& dst_node_addr = _lookup_sep_node_addr(dst_epid);
- const node_addr_t& src_node_addr = _lookup_sep_node_addr(src_epid);
+ const node_addr_t& dst_node_addr = _node_addr_map.at(node_id_t(dst_addr));
+ const node_addr_t& src_node_addr = _node_addr_map.at(node_id_t(src_addr));
// Find a common parent (could be faster than n^2 but meh, this is easier)
- bool found_common_parent = false;
for (const auto& dnode : dst_node_addr) {
for (const auto& snode : src_node_addr) {
- found_common_parent =
- ((dnode.first == snode.first) && dnode.first.type == NODE_TYPE_XBAR);
- if (found_common_parent)
- break;
+ if (dnode.first == snode.first && dnode.first.type == NODE_TYPE_XBAR) {
+ return true;
+ }
}
- if (found_common_parent)
- break;
}
- if (!found_common_parent) {
- throw uhd::routing_error("setup_remote_route: Route setup failed. The "
- "endpoints don't share a common crossbar parent.");
+ return false;
+ }
+
+ virtual void setup_remote_route(const sep_id_t& dst_epid, const sep_id_t& src_epid)
+ {
+ std::lock_guard<std::recursive_mutex> lock(_mutex);
+
+ if (not is_endpoint_initialized(dst_epid)) {
+ throw uhd::routing_error("Route setup failed. The destination endpoint was "
+ "not initialized and bound to an EPID");
+ }
+ if (not is_endpoint_initialized(src_epid)) {
+ throw uhd::routing_error("Route setup failed. The source endpoint was "
+ "not initialized and bound to an EPID");
+ }
+
+ if (not can_remote_route(
+ _epid_addr_map.at(dst_epid), _epid_addr_map.at(src_epid))) {
+ throw uhd::routing_error("Route setup failed. The endpoints don't share a "
+ "common crossbar parent.");
}
// If we setup local routes from this host to both the source and destination
@@ -393,8 +414,8 @@ public:
const bool lossy_xport,
const sw_buff_t pyld_buff_fmt,
const sw_buff_t mdata_buff_fmt,
- const buff_params_t& fc_freq,
- const buff_params_t& fc_headroom,
+ const stream_buff_params_t& fc_freq,
+ const stream_buff_params_t& fc_headroom,
const bool reset = false)
{
std::lock_guard<std::recursive_mutex> lock(_mutex);
@@ -433,7 +454,7 @@ public:
(boost::format("Initiated RX stream setup for EPID=%d") % epid));
}
- virtual buff_params_t config_local_rx_stream_commit(
+ virtual stream_buff_params_t config_local_rx_stream_commit(
const sep_id_t& epid, const double timeout = 0.2)
{
std::lock_guard<std::recursive_mutex> lock(_mutex);
@@ -487,11 +508,11 @@ public:
(boost::format("Finished TX stream setup for EPID=%d") % epid));
}
- virtual buff_params_t config_remote_stream(const sep_id_t& dst_epid,
+ virtual stream_buff_params_t config_remote_stream(const sep_id_t& dst_epid,
const sep_id_t& src_epid,
const bool lossy_xport,
- const buff_params_t& fc_freq,
- const buff_params_t& fc_headroom,
+ const stream_buff_params_t& fc_freq,
+ const stream_buff_params_t& fc_headroom,
const bool reset = false,
const double timeout = 0.2)
{
@@ -743,8 +764,8 @@ private: // Functions
void _push_ostrm_flow_control_config(const bool lossy_xport,
const sw_buff_t pyld_buff_fmt,
const sw_buff_t mdata_buff_fmt,
- const buff_params_t& fc_freq,
- const buff_params_t& fc_headroom,
+ const stream_buff_params_t& fc_freq,
+ const stream_buff_params_t& fc_headroom,
mgmt_hop_t& hop)
{
// Validate flow control parameters
@@ -780,7 +801,8 @@ private: // Functions
}
// Send/recv a management transaction that will get the output stream status
- std::tuple<uint32_t, buff_params_t> _get_ostrm_status(const node_addr_t& node_addr)
+ std::tuple<uint32_t, stream_buff_params_t> _get_ostrm_status(
+ const node_addr_t& node_addr)
{
// Build a management transaction to first get to the node
mgmt_payload status_xact;
@@ -824,7 +846,7 @@ private: // Functions
mgmt_op_t::cfg_payload cap_bytes_hi = rhop.get_op(3).get_op_payload();
mgmt_op_t::cfg_payload cap_pkts = rhop.get_op(4).get_op_payload();
- buff_params_t buff_params;
+ stream_buff_params_t buff_params;
buff_params.bytes = static_cast<uint64_t>(cap_bytes_lo.data)
| (static_cast<uint64_t>(cap_bytes_hi.data) << 32);
buff_params.packets = static_cast<uint32_t>(cap_pkts.data);