diff options
author | Brent Stapleton <brent.stapleton@ettus.com> | 2019-06-03 14:07:58 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2019-11-26 11:49:23 -0800 |
commit | 03023905360dd2c9c17ba70ff1543b0c70f98ad4 (patch) | |
tree | b907adaf95910f93608f35ce99c809bc81d3e688 /host | |
parent | debe5189364b0684500b7ce4cd8f45894a3e54e7 (diff) | |
download | uhd-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.hpp | 23 | ||||
-rw-r--r-- | host/lib/rfnoc/rfnoc_graph.cpp | 205 |
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 */ |