diff options
author | Martin Braun <martin.braun@ettus.com> | 2019-07-03 15:27:58 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2019-11-26 11:49:30 -0800 |
commit | dd78c438ed31cbeac53bee1b402cb49e9948d0c2 (patch) | |
tree | 7e4fbe5144fabcd5595b260ed8baa731a48a2e69 /host/lib | |
parent | a36fc4604f9b37c46fd203d6461d0d38065a97e9 (diff) | |
download | uhd-dd78c438ed31cbeac53bee1b402cb49e9948d0c2.tar.gz uhd-dd78c438ed31cbeac53bee1b402cb49e9948d0c2.tar.bz2 uhd-dd78c438ed31cbeac53bee1b402cb49e9948d0c2.zip |
rfnoc: rfnoc_graph: Refactor class
- Remove duplicate calls to uhd::device::make
- Do a try/catch on full class initialization
- Separate setup_graph() into multiple sub-functions
- Improve const-correctness
Diffstat (limited to 'host/lib')
-rw-r--r-- | host/lib/rfnoc/rfnoc_graph.cpp | 252 |
1 files changed, 142 insertions, 110 deletions
diff --git a/host/lib/rfnoc/rfnoc_graph.cpp b/host/lib/rfnoc/rfnoc_graph.cpp index 4bf35cff1..fa6282c7d 100644 --- a/host/lib/rfnoc/rfnoc_graph.cpp +++ b/host/lib/rfnoc/rfnoc_graph.cpp @@ -34,13 +34,33 @@ 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); + rfnoc_graph_impl( + detail::rfnoc_device::sptr dev, const uhd::device_addr_t& dev_addr) try + : _device(dev), + _tree(_device->get_tree()), + _num_mboards(_tree->list("/mboards").size()), + _block_registry(std::make_unique<detail::block_container_t>()), + _graph(std::make_unique<uhd::rfnoc::detail::graph_t>()) { + // Now initialize all subsystems: + _init_mb_controllers(); + _init_gsm(); // Graph Stream Manager + for (size_t mb_idx = 0; mb_idx < _num_mboards; ++mb_idx) { + try { + // If anything fails here, we immediately deinit all the other + // blocks to avoid any more fallout, then safely bring down the + // device. + _init_blocks(mb_idx, dev_addr); + } catch (...) { + _block_registry->shutdown(); + throw; + } + } + UHD_LOG_TRACE(LOG_ID, "Initializing properties on all blocks..."); + _block_registry->init_props(); _init_sep_map(); _init_static_connections(); + } catch (...) { + throw uhd::runtime_error("Failure to create rfnoc_graph."); } ~rfnoc_graph_impl() @@ -255,21 +275,17 @@ private: /************************************************************************** * Device Setup *************************************************************************/ - void setup_graph(const uhd::device_addr_t& dev_addr) + void _init_mb_controllers() { - // Phase I: Initialize the motherboards - auto dev = uhd::device::make(dev_addr); - _device = boost::dynamic_pointer_cast<detail::rfnoc_device>(dev); - if (!_device) { - throw uhd::key_error(std::string("Found no RFNoC devices for ----->\n") - + dev_addr.to_pp_string()); - } - _tree = _device->get_tree(); - _num_mboards = _tree->list("/mboards").size(); + UHD_LOG_TRACE(LOG_ID, "Initializing MB controllers..."); for (size_t i = 0; i < _num_mboards; ++i) { _mb_controllers.emplace(i, _device->get_mb_controller(i)); } + } + void _init_gsm() + { + UHD_LOG_TRACE(LOG_ID, "Initializing GSM..."); // Create a graph stream manager // FIXME get these from mb_iface or something static const chdr::chdr_packet_factory pkt_factory( @@ -282,106 +298,104 @@ private: 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()); + UHD_LOG_ERROR(LOG_ID, "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 - // Iterate through the mboards - for (size_t mb_idx = 0; mb_idx < get_num_mboards(); ++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); - // Grab and stash the Client Zero for this mboard - detail::client_zero::sptr mb_cz = _gsm->get_client_zero(ctrl_sep_addr); - // Client zero port numbers are based on the control xbar numbers, - // which have the client 0 interface first, followed by stream - // endpoints, and then the blocks. - _client_zeros.emplace(mb_idx, mb_cz); - - const size_t num_blocks = mb_cz->get_num_blocks(); - const size_t first_block_port = 1 + mb_cz->get_num_stream_endpoints(); - - /* Flush and reset each block in the mboard - * We do this before we enumerate the blocks to ensure they're in a clean - * state before we construct their block controller, and so that we don't - * reset any setting that the block controller writes - */ - _flush_and_reset_mboard(mb_idx, mb_cz, num_blocks, first_block_port); - - // 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_info = 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_info.block_name, - block_count_map[block_factory_info.block_name]++); - // Get access to the clock interface objects. We have some rules - // here: - // - The ctrlport clock must always be provided through the - // BSP via mb_iface - // - The timebase clock can be set to "graph", which means the - // block takes care of the timebase itself (via property - // propagation). In that case, we generate a clock iface - // object on the fly here. - // - In all other cases, the BSP must provide us that clock - // iface object through the mb_iface - auto ctrlport_clk_iface = - mb.get_clock_iface(block_factory_info.ctrlport_clk); - auto tb_clk_iface = - (block_factory_info.timebase_clk == CLOCK_KEY_GRAPH) - ? std::make_shared<clock_iface>(CLOCK_KEY_GRAPH) - : mb.get_clock_iface(block_factory_info.timebase_clk); - // A "graph" clock is always "running" - if (block_factory_info.timebase_clk == CLOCK_KEY_GRAPH) { - tb_clk_iface->set_running(true); - } - auto block_reg_iface = _gsm->get_block_register_iface(ctrl_sep_addr, - portno, - *ctrlport_clk_iface.get(), - *tb_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->tb_clk_iface = tb_clk_iface; - make_args_uptr->ctrlport_clk_iface = ctrlport_clk_iface; - make_args_uptr->mb_control = (factory::has_requested_mb_access(noc_id) - ? _mb_controllers.at(mb_idx) - : nullptr); - const uhd::fs_path block_path( - uhd::fs_path("/blocks") / block_id.to_string()); - _tree->create<uint32_t>(block_path / "noc_id").set(noc_id); - make_args_uptr->tree = _tree->subtree(block_path); - make_args_uptr->args = dev_addr; // TODO filter the device args + // Initialize client zero and all block controllers for motherboard mb_idx + void _init_blocks(const size_t mb_idx, const uhd::device_addr_t& dev_addr) + { + UHD_LOG_TRACE(LOG_ID, "Initializing blocks for MB " << 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); + // Grab and stash the Client Zero for this mboard + detail::client_zero::sptr mb_cz = _gsm->get_client_zero(ctrl_sep_addr); + // Client zero port numbers are based on the control xbar numbers, + // which have the client 0 interface first, followed by stream + // endpoints, and then the blocks. + _client_zeros.emplace(mb_idx, mb_cz); + + const size_t num_blocks = mb_cz->get_num_blocks(); + const size_t first_block_port = 1 + mb_cz->get_num_stream_endpoints(); + + /* Flush and reset each block in the mboard + * We do this before we enumerate the blocks to ensure they're in a clean + * state before we construct their block controller, and so that we don't + * reset any setting that the block controller writes + */ + _flush_and_reset_mboard(mb_idx, mb_cz, num_blocks, first_block_port); + + // 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) { + const auto noc_id = mb_cz->get_noc_id(portno + first_block_port); + auto block_factory_info = 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_info.block_name, + block_count_map[block_factory_info.block_name]++); + // Get access to the clock interface objects. We have some rules + // here: + // - The ctrlport clock must always be provided through the + // BSP via mb_iface + // - The timebase clock can be set to CLOCK_KEY_GRAPH, which means + // the block takes care of the timebase itself (via property + // propagation). In that case, we generate a clock iface + // object on the fly here. + // - In all other cases, the BSP must provide us that clock + // iface object through the mb_iface + auto ctrlport_clk_iface = mb.get_clock_iface(block_factory_info.ctrlport_clk); + auto tb_clk_iface = (block_factory_info.timebase_clk == CLOCK_KEY_GRAPH) + ? std::make_shared<clock_iface>(CLOCK_KEY_GRAPH) + : mb.get_clock_iface(block_factory_info.timebase_clk); + // A "graph" clock is always "running" + if (block_factory_info.timebase_clk == CLOCK_KEY_GRAPH) { + tb_clk_iface->set_running(true); + } + auto block_reg_iface = _gsm->get_block_register_iface( + ctrl_sep_addr, portno, *ctrlport_clk_iface.get(), *tb_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->tb_clk_iface = tb_clk_iface; + make_args_uptr->ctrlport_clk_iface = ctrlport_clk_iface; + make_args_uptr->mb_control = (factory::has_requested_mb_access(noc_id) + ? _mb_controllers.at(mb_idx) + : nullptr); + const uhd::fs_path block_path(uhd::fs_path("/blocks") / block_id.to_string()); + _tree->create<uint32_t>(block_path / "noc_id").set(noc_id); + make_args_uptr->tree = _tree->subtree(block_path); + make_args_uptr->args = dev_addr; // TODO filter the device args + try { _block_registry->register_block( block_factory_info.factory_fn(std::move(make_args_uptr))); - _xbar_block_config[block_id.to_string()] = { - portno, noc_id, block_id.get_block_count()}; - - _port_block_map.insert({{mb_idx, portno + first_block_port}, block_id}); + } catch (...) { + UHD_LOG_ERROR( + LOG_ID, "Error during initialization of block " << block_id << "!"); + throw; } - } + _xbar_block_config[block_id.to_string()] = { + portno, noc_id, block_id.get_block_count()}; - UHD_LOG_TRACE("RFNOC::GRAPH", "Initializing properties on all blocks..."); - _block_registry->init_props(); + _port_block_map.insert({{mb_idx, portno + first_block_port}, block_id}); + } } void _init_sep_map() { - for (size_t mb_idx = 0; mb_idx < get_num_mboards(); ++mb_idx) { + for (size_t mb_idx = 0; mb_idx < _num_mboards; ++mb_idx) { auto remote_device_id = _device->get_mb_iface(mb_idx).get_remote_device_id(); auto& cz = _client_zeros.at(mb_idx); for (size_t sep_idx = 0; sep_idx < cz->get_num_stream_endpoints(); @@ -396,7 +410,7 @@ private: void _init_static_connections() { - UHD_LOG_TRACE("RFNOC::GRAPH", "Identifying static connections..."); + UHD_LOG_TRACE(LOG_ID, "Identifying static connections..."); for (auto& kv_cz : _client_zeros) { auto& adjacency_list = kv_cz.second->get_adjacency_list(); for (auto& edge : adjacency_list) { @@ -414,8 +428,7 @@ private: graph_edge.dst_port = edge.dst_blk_port; graph_edge.edge = graph_edge_t::edge_t::STATIC; _static_edges.push_back(graph_edge); - UHD_LOG_TRACE( - "RFNOC::GRAPH", "Static connection: " << graph_edge.to_string()); + UHD_LOG_TRACE(LOG_ID, "Static connection: " << graph_edge.to_string()); } } } @@ -532,7 +545,7 @@ private: const size_t num_blocks, const size_t first_block_port) { - UHD_LOG_TRACE("RFNOC::GRAPH", + UHD_LOG_TRACE(LOG_ID, std::string("Flushing and resetting blocks on mboard ") + std::to_string(mb_idx)); @@ -568,7 +581,7 @@ private: if (!bool(edge_o)) { const std::string err_msg = std::string("Cannot connect block ") + blk_info + ", port is unconnected in the FPGA!"; - UHD_LOG_ERROR("RFNOC::GRAPH", err_msg); + UHD_LOG_ERROR(LOG_ID, err_msg); throw uhd::routing_error(err_msg); } return edge_o.get(); @@ -580,13 +593,13 @@ private: //! Reference to the underlying device implementation detail::rfnoc_device::sptr _device; + //! Reference to the property tree + uhd::property_tree::sptr _tree; + //! Number of motherboards, this is technically redundant but useful for // easy lookups. size_t _num_mboards; - //! 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; @@ -627,7 +640,26 @@ private: /****************************************************************************** * Factory *****************************************************************************/ +namespace uhd { namespace rfnoc { namespace detail { + +// Simple factory: If we already have the device, simply pass it on +rfnoc_graph::sptr make_rfnoc_graph( + detail::rfnoc_device::sptr dev, const uhd::device_addr_t& device_addr) +{ + return std::make_shared<rfnoc_graph_impl>(dev, device_addr); +} + +}}} /* namespace uhd::rfnoc::detail */ + +// If we don't have a device yet, create it and see if it's really an RFNoC +// device. This is used by multi_usrp_rfnoc, for example. rfnoc_graph::sptr rfnoc_graph::make(const uhd::device_addr_t& device_addr) { - return std::make_shared<rfnoc_graph_impl>(device_addr); + auto dev = + boost::dynamic_pointer_cast<detail::rfnoc_device>(uhd::device::make(device_addr)); + if (!dev) { + throw uhd::key_error(std::string("No RFNoC devices found for ----->\n") + + device_addr.to_pp_string()); + } + return std::make_shared<rfnoc_graph_impl>(dev, device_addr); } |