aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
authorBrent Stapleton <brent.stapleton@ettus.com>2019-06-03 14:07:58 -0700
committerMartin Braun <martin.braun@ettus.com>2019-11-26 11:49:23 -0800
commit03023905360dd2c9c17ba70ff1543b0c70f98ad4 (patch)
treeb907adaf95910f93608f35ce99c809bc81d3e688 /host
parentdebe5189364b0684500b7ce4cd8f45894a3e54e7 (diff)
downloaduhd-03023905360dd2c9c17ba70ff1543b0c70f98ad4.tar.gz
uhd-03023905360dd2c9c17ba70ff1543b0c70f98ad4.tar.bz2
uhd-03023905360dd2c9c17ba70ff1543b0c70f98ad4.zip
rfnoc: enumerate and construct block controllers, enable connect()
During construction of the rfnoc_graph, enumerate all of the connected blocks, construct their controllers, and store them in the graph.
Diffstat (limited to 'host')
-rw-r--r--host/include/uhd/rfnoc_graph.hpp23
-rw-r--r--host/lib/rfnoc/rfnoc_graph.cpp205
2 files changed, 217 insertions, 11 deletions
diff --git a/host/include/uhd/rfnoc_graph.hpp b/host/include/uhd/rfnoc_graph.hpp
index a0a9bf907..55563c6fc 100644
--- a/host/include/uhd/rfnoc_graph.hpp
+++ b/host/include/uhd/rfnoc_graph.hpp
@@ -36,9 +36,16 @@ public:
*/
using sptr = std::shared_ptr<rfnoc_graph>;
-
virtual ~rfnoc_graph() {}
+
+ //! Stuct to store information about which blocks are actually stored at a given port on the crossbar
+ struct block_xbar_info {
+ size_t xbar_port;
+ noc_block_base::noc_id_t noc_id;
+ size_t inst_num;
+ };
+
/******************************************
* Factory
******************************************/
@@ -113,7 +120,7 @@ public:
* \param block_id Canonical block name (e.g. "0/FFT#1").
* \note this access is not thread safe if peformed during block enumeration
*/
- noc_block_base::sptr get_block(const block_id_t& block_id) const;
+ virtual noc_block_base::sptr get_block(const block_id_t& block_id) const = 0;
/*! Same as get_block(), but with a type cast.
*
@@ -161,11 +168,11 @@ public:
* \throws connect_disallowed_on_dst
* if the destination port is statically connected to a *different* block
*/
- void connect(const block_id_t& src_blk,
+ virtual void connect(const block_id_t& src_blk,
size_t src_port,
const block_id_t& dst_blk,
size_t dst_port,
- bool skip_property_propagation = false);
+ bool skip_property_propagation = false) = 0;
/*! Connect TX streamer to an input of an NoC block
*
@@ -177,10 +184,10 @@ public:
* \throws connect_disallowed_on_dst
* if the destination port is statically connected to a *different* block
*/
- void connect(uhd::tx_streamer& streamer,
+ virtual void connect(uhd::tx_streamer& streamer,
size_t strm_port,
const block_id_t& dst_blk,
- size_t dst_port);
+ size_t dst_port) = 0;
/*! Connect RX streamer to an output of an NoC block
*
@@ -192,10 +199,10 @@ public:
* \throws connect_disallowed_on_src
* if the source port is statically connected to a *different* block
*/
- void connect(const block_id_t& src_blk,
+ virtual void connect(const block_id_t& src_blk,
size_t src_port,
uhd::rx_streamer& streamer,
- size_t strm_port);
+ size_t strm_port) = 0;
/*! Enumerate all the connections in the graph
*
diff --git a/host/lib/rfnoc/rfnoc_graph.cpp b/host/lib/rfnoc/rfnoc_graph.cpp
index 94d59da05..09e159282 100644
--- a/host/lib/rfnoc/rfnoc_graph.cpp
+++ b/host/lib/rfnoc/rfnoc_graph.cpp
@@ -4,13 +4,20 @@
// SPDX-License-Identifier: GPL-3.0-or-later
//
+#include <uhd/exception.hpp>
+#include <uhd/rfnoc/defaults.hpp>
+#include <uhd/rfnoc/mb_controller.hpp>
+#include <uhd/rfnoc/noc_block_make_args.hpp>
#include <uhd/rfnoc/node.hpp>
#include <uhd/rfnoc_graph.hpp>
-#include <uhd/rfnoc/mb_controller.hpp>
#include <uhdlib/rfnoc/block_container.hpp>
+#include <uhdlib/rfnoc/factory.hpp>
#include <uhdlib/rfnoc/graph.hpp>
+#include <uhdlib/rfnoc/graph_stream_manager.hpp>
#include <uhdlib/rfnoc/rfnoc_device.hpp>
+#include <uhdlib/utils/narrow.hpp>
#include <boost/shared_ptr.hpp> // FIXME remove when rfnoc_device is ready
+#include <memory>
using namespace uhd::rfnoc;
@@ -22,6 +29,8 @@ public:
* Structors
*************************************************************************/
rfnoc_graph_impl(const uhd::device_addr_t& dev_addr)
+ : _block_registry(std::make_unique<detail::block_container_t>())
+ , _graph(std::make_unique<uhd::rfnoc::detail::graph_t>())
{
setup_graph(dev_addr);
}
@@ -73,6 +82,7 @@ public:
get_block(dst_blk),
dst_port,
skip_property_propagation);
+ _physical_connect(src_blk, src_port, dst_blk, dst_port);
}
void connect(uhd::tx_streamer& /*streamer*/,
@@ -125,22 +135,79 @@ private:
+ dev_addr.to_pp_string());
}
+ // Create a graph stream manager
+ // FIXME get these from mb_iface or something
+ static const chdr::chdr_packet_factory pkt_factory(
+ CHDR_W_64, uhd::ENDIANNESS_BIG);
+ epid_allocator::sptr epid_alloc = std::make_shared<epid_allocator>();
+ // Create a collection of link definitions: (ID, MB) pairs
+ std::vector<std::pair<device_id_t, mb_iface*>> links;
+ // TODO fix device_id we're creating
+ links.push_back(std::make_pair(100, &_device->get_mb_iface(0)));
+ try {
+ _gsm = graph_stream_manager::make(pkt_factory, epid_alloc, links);
+ } catch (uhd::io_error& ex) {
+ UHD_LOG_ERROR("RFNOC::GRAPH", "IO Error during GSM initialization. " << ex.what());
+ throw;
+ }
+
// Configure endpoint_manager, make sure all routes are established
// FIXME
// Enumerate blocks, load them into the block registry
- // FIXME
+ // Iterate through the mboards
+ for (size_t mb_idx = 0; mb_idx < _device->get_num_mbs(); ++mb_idx) {
+ // Setup the interfaces for this mboard and get some configuration info
+ mb_iface& mb = _device->get_mb_iface(mb_idx);
+ // Ask GSM to allow us to talk to our remote mb
+ sep_addr_t ctrl_sep_addr(mb.get_remote_device_id(), 0);
+ _gsm->connect_host_to_device(ctrl_sep_addr);
+ detail::client_zero::sptr mb_cz = _gsm->get_client_zero(ctrl_sep_addr);
+ const size_t num_blocks = mb_cz->get_num_blocks();
+ const size_t first_block_port = 1 + mb_cz->get_num_stream_endpoints();
+
+ // Make a map to count the number of each block we have
+ std::unordered_map<std::string, uint16_t> block_count_map;
+
+ // Iterate through and register each of the blocks in this mboard
+ for (size_t portno = 0; portno < num_blocks; ++portno) {
+ auto noc_id = mb_cz->get_noc_id(portno + first_block_port);
+ auto block_factory_pair = factory::get_block_factory(noc_id);
+ auto block_info = mb_cz->get_block_info(portno + first_block_port);
+ block_id_t block_id(mb_idx,
+ block_factory_pair.second,
+ block_count_map[block_factory_pair.second]++);
+ auto clk_iface = std::make_shared<clock_iface>(block_id.to_string() + "_clock");
+ auto block_reg_iface = _gsm->get_block_register_iface(ctrl_sep_addr,
+ portno,
+ *clk_iface.get(),
+ *clk_iface.get());
+ auto make_args_uptr = std::make_unique<noc_block_base::make_args_t>();
+ make_args_uptr->noc_id = noc_id;
+ make_args_uptr->block_id = block_id;
+ make_args_uptr->num_input_ports = block_info.num_inputs;
+ make_args_uptr->num_output_ports = block_info.num_outputs;
+ make_args_uptr->reg_iface = block_reg_iface;
+ make_args_uptr->clk_iface = clk_iface;
+ make_args_uptr->mb_control = (factory::has_requested_mb_access(noc_id) ? _mb_controllers.at(mb_idx) : nullptr);
+ make_args_uptr->tree = _tree->subtree("/mboards/0"); /* FIXME Get the block's subtree */
+ make_args_uptr->args = dev_addr; // TODO filter the device args
+ _block_registry->register_block(block_factory_pair.first(std::move(make_args_uptr)));
+ _xbar_block_config[block_id.to_string()] = {
+ portno, noc_id, block_id.get_block_count()};
+ }
+ }
// Create graph, connect all static routes
// FIXME
}
-
/**************************************************************************
* Helpers
*************************************************************************/
/*! Internal connection helper
*
+ * Make the connections in the _graph, and set up property propagation
* Prerequisite: \p src_blk and \p dst_blk need to point to valid nodes
*/
void _connect(std::shared_ptr<node_t> src_blk,
@@ -156,6 +223,119 @@ private:
_graph->connect(src_blk.get(), dst_blk.get(), edge_info);
}
+ /*! Internal physical connection helper
+ *
+ * Make the connections in the physical device
+ *
+ * \throws connect_disallowed_on_src
+ * if the source port is statically connected to a *different* block
+ * \throws connect_disallowed_on_dst
+ * if the destination port is statically connected to a *different* block
+ */
+ void _physical_connect(const block_id_t& src_blk,
+ size_t src_port,
+ const block_id_t& dst_blk,
+ size_t dst_port)
+ {
+ auto src_blk_ctrl = get_block(src_blk);
+ auto dst_blk_ctrl = get_block(dst_blk);
+
+ /*
+ * Start by determining if the connection can be made
+ * Get the adjacency list and check if the connection is in it already
+ */
+ // Read the adjacency list for the source and destination blocks
+ auto src_mb_idx = src_blk.get_device_no();
+ auto src_cz = _gsm->get_client_zero(
+ sep_addr_t(_device->get_mb_iface(src_mb_idx).get_remote_device_id(), 0));
+ std::vector<detail::client_zero::edge_def_t>& adj_list =
+ src_cz->get_adjacency_list();
+ // Check the src_blk
+ auto src_blk_xbar_info =
+ _xbar_block_config.at(src_blk_ctrl->get_block_id().to_string());
+ // This "xbar_port" starts at the first block, so we need to add the client zero
+ // and stream endpoint ports
+ const auto src_xbar_port =
+ src_blk_xbar_info.xbar_port + src_cz->get_num_stream_endpoints() + 1;
+ // We can also find out which stream endpoint the src block is connected to
+ sep_inst_t src_sep;
+ for (detail::client_zero::edge_def_t edge : adj_list) {
+ if ((edge.src_blk_index == src_xbar_port)
+ and (edge.src_blk_port == src_port)) {
+ UHD_LOGGER_DEBUG("RFNOC::GRAPH")
+ << boost::format("Block found in adjacency list. %d:%d->%d:%d")
+ % edge.src_blk_index
+ % static_cast<unsigned int>(edge.src_blk_port)
+ % edge.dst_blk_index
+ % static_cast<unsigned int>(edge.dst_blk_port);
+ if (edge.dst_blk_index <= src_cz->get_num_stream_endpoints()) {
+ src_sep =
+ edge.dst_blk_index - 1 /* minus 1 because port 0 is client zero*/;
+ } else {
+ // TODO connect_disallowed_on_src?
+ // TODO put more info in exception
+ throw uhd::routing_error(
+ "Unable to connect to statically connected source port");
+ }
+ }
+ }
+
+ // Read the dst adjacency list if its different
+ // TODO they may be on the same mboard, which would make this redundant
+ auto dst_mb_idx = dst_blk.get_device_no();
+ auto dst_cz = _gsm->get_client_zero(
+ sep_addr_t(_device->get_mb_iface(dst_mb_idx).get_remote_device_id(), 0));
+ adj_list = dst_cz->get_adjacency_list();
+ // Check the dst blk
+ auto dst_blk_xbar_info =
+ _xbar_block_config.at(dst_blk_ctrl->get_block_id().to_string());
+ // This "xbar_port" starts at the first block, so we need to add the client zero
+ // and stream endpoint ports
+ const auto dst_xbar_port =
+ dst_blk_xbar_info.xbar_port + dst_cz->get_num_stream_endpoints() + 1;
+ // We can also find out which stream endpoint the dst block is connected to
+ sep_inst_t dst_sep;
+ for (detail::client_zero::edge_def_t edge : adj_list) {
+ if ((edge.dst_blk_index == dst_xbar_port)
+ and (edge.dst_blk_port == dst_port)) {
+ UHD_LOGGER_DEBUG("RFNOC::GRAPH")
+ << boost::format("Block found in adjacency list. %d:%d->%d:%d")
+ % edge.src_blk_index
+ % static_cast<unsigned int>(edge.src_blk_port)
+ % edge.dst_blk_index
+ % static_cast<unsigned int>(edge.dst_blk_port);
+ if (edge.src_blk_index <= dst_cz->get_num_stream_endpoints()) {
+ dst_sep =
+ edge.src_blk_index - 1 /* minus 1 because port 0 is client zero*/;
+ } else {
+ // TODO connect_disallowed_on_dst?
+ // TODO put more info in exception
+ throw uhd::routing_error(
+ "Unable to connect to statically connected destination port");
+ }
+ }
+ }
+
+ /* TODO: we checked if either port is used in a static connection (and its not if
+ * we've made it this far). We also need to check something else, but I can't
+ * remember what...
+ */
+
+ // At this point, we know the attempted connection is valid, so let's go ahead and
+ // make it
+ sep_addr_t src_sep_addr(
+ _device->get_mb_iface(src_mb_idx).get_remote_device_id(), src_sep);
+ sep_addr_t dst_sep_addr(
+ _device->get_mb_iface(dst_mb_idx).get_remote_device_id(), dst_sep);
+ auto strm_info = _gsm->create_device_to_device_data_stream(
+ dst_sep_addr, src_sep_addr, false, 0.1, 0.0, false);
+
+ UHD_LOGGER_INFO("RFNOC::GRAPH")
+ << boost::format("Data stream between EPID %d and EPID %d established "
+ "where downstream buffer can hold %lu bytes and %u packets")
+ % std::get<0>(strm_info).first % std::get<0>(strm_info).second
+ % std::get<1>(strm_info).bytes % std::get<1>(strm_info).packets;
+ }
/**************************************************************************
* Attributes
@@ -163,14 +343,33 @@ private:
//! Reference to the underlying device implementation
detail::rfnoc_device::sptr _device;
+ //! Reference to the property tree
+ uhd::property_tree::sptr _tree;
+
//! Registry for the blocks (it's a separate class)
std::unique_ptr<detail::block_container_t> _block_registry;
+ /*! Registry for the actual block connections on the crossbar
+ * When we register blocks in the _block_registry, we also need to store some
+ * information in this map so we can easily figure out which crossbar port a block
+ * controller is connected to
+ * \p keys are the string representation of the block ID
+ * \p values are the block crossbar information structs
+ * TODO: change from string block IDs to block_id_t with COOL custom hashing
+ */
+ std::unordered_map<std::string, block_xbar_info> _xbar_block_config;
+
//! Reference to the graph
std::unique_ptr<detail::graph_t> _graph;
//! Stash a list of motherboard controllers
std::unordered_map<size_t, mb_controller::sptr> _mb_controllers;
+
+ //! Stash of the client zeros for all motherboards
+ std::unordered_map<size_t, detail::client_zero::sptr> _client_zeros;
+
+ //! uptr to graph stream manager
+ graph_stream_manager::uptr _gsm;
}; /* class rfnoc_graph_impl */