// // Copyright 2019 Ettus Research, a National Instruments Brand // // SPDX-License-Identifier: GPL-3.0-or-later // #include "x300_impl.hpp" #include using namespace uhd::rfnoc; using uhd::transport::link_type_t; static uhd::usrp::io_service_args_t get_default_io_srv_args() { // TODO: Need better defaults, taking into account the link type and ensuring // that the number of frames is appropriate uhd::usrp::io_service_args_t args; args.recv_offload = false; args.send_offload = false; return args; } x300_impl::x300_mb_iface::x300_mb_iface(uhd::usrp::x300::conn_manager::sptr conn_mgr, const double radio_clk_freq, const uhd::rfnoc::device_id_t remote_dev_id) : _remote_dev_id(remote_dev_id) , _bus_clk(std::make_shared( "bus_clk", uhd::usrp::x300::BUS_CLOCK_RATE, false)) , _radio_clk( std::make_shared("radio_clk", radio_clk_freq, false)) , _conn_mgr(conn_mgr) { UHD_ASSERT_THROW(_conn_mgr); _bus_clk->set_running(true); _radio_clk->set_running(true); } x300_impl::x300_mb_iface::~x300_mb_iface() = default; uint16_t x300_impl::x300_mb_iface::get_proto_ver() { // TODO: Get from from a hardware register return 0x0100; } uhd::rfnoc::chdr_w_t x300_impl::x300_mb_iface::get_chdr_w() { // TODO: Get from from a hardware register return uhd::rfnoc::CHDR_W_64; } uhd::endianness_t x300_impl::x300_mb_iface::get_endianness( const uhd::rfnoc::device_id_t /*local_device_id*/) { // FIXME return uhd::ENDIANNESS_LITTLE; } uhd::rfnoc::device_id_t x300_impl::x300_mb_iface::get_remote_device_id() { return _remote_dev_id; } std::vector x300_impl::x300_mb_iface::get_local_device_ids() { return _conn_mgr->get_local_device_ids(); } uhd::transport::adapter_id_t x300_impl::x300_mb_iface::get_adapter_id( const uhd::rfnoc::device_id_t local_device_id) { return _adapter_map[local_device_id]; } void x300_impl::x300_mb_iface::reset_network() { // FIXME } uhd::rfnoc::clock_iface::sptr x300_impl::x300_mb_iface::get_clock_iface( const std::string& clock_name) { if (clock_name == "radio_clk") { return _radio_clk; } if (clock_name == "bus_clk") { return _bus_clk; } UHD_LOG_ERROR("X300", "Invalid timebase clock name: " + clock_name); throw uhd::key_error("[X300] Invalid timebase clock name: " + clock_name); } uhd::rfnoc::chdr_ctrl_xport::sptr x300_impl::x300_mb_iface::make_ctrl_transport( uhd::rfnoc::device_id_t local_device_id, const uhd::rfnoc::sep_id_t& local_epid) { using namespace uhd::transport; send_link_if::sptr send_link; recv_link_if::sptr recv_link; bool lossy_xport; std::tie(send_link, std::ignore, recv_link, std::ignore, lossy_xport, std::ignore) = _conn_mgr->get_links(link_type_t::CTRL, local_device_id, local_epid, uhd::rfnoc::sep_id_t(), uhd::device_addr_t()); /* Associate local device ID with the adapter */ _adapter_map[local_device_id] = send_link->get_send_adapter_id(); auto io_srv = get_io_srv_mgr()->connect_links(recv_link, send_link, link_type_t::CTRL); auto xport = 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 x300_impl::x300_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 std::string& streamer_id) { using namespace uhd::transport; const uhd::rfnoc::sep_addr_t local_sep_addr = addrs.second; const uhd::rfnoc::sep_id_t remote_epid = epids.first; const uhd::rfnoc::sep_id_t local_epid = epids.second; send_link_if::sptr send_link; recv_link_if::sptr recv_link; size_t recv_buff_size; bool lossy_xport, packet_fc; std::tie(send_link, std::ignore, recv_link, recv_buff_size, lossy_xport, packet_fc) = _conn_mgr->get_links(link_type_t::RX_DATA, local_sep_addr.first, local_epid, remote_epid, xport_args); /* Associate local device ID with the adapter */ _adapter_map[local_sep_addr.first] = send_link->get_send_adapter_id(); const uhd::rfnoc::stream_buff_params_t recv_capacity = {recv_buff_size, packet_fc ? static_cast(recv_link->get_num_recv_frames()) : uhd::rfnoc::MAX_FC_CAPACITY_PKTS}; const double ratio = 1.0 / 32; // Configure flow control frequency to use either bytes only or packets only uhd::rfnoc::stream_buff_params_t fc_freq; if (packet_fc) { fc_freq = {uhd::rfnoc::MAX_FC_FREQ_BYTES, static_cast(std::ceil(recv_link->get_num_recv_frames() * ratio))}; } else { fc_freq = {static_cast(std::ceil(double(recv_buff_size) * ratio)), uhd::rfnoc::MAX_FC_FREQ_PKTS}; } uhd::rfnoc::stream_buff_params_t fc_headroom = {0, 0}; auto cfg_io_srv = get_io_srv_mgr()->connect_links(recv_link, send_link, link_type_t::CTRL); auto fc_params = uhd::rfnoc::chdr_rx_data_xport::configure_sep(cfg_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); get_io_srv_mgr()->disconnect_links(recv_link, send_link); cfg_io_srv.reset(); // Connect the links to an I/O service auto io_srv = get_io_srv_mgr()->connect_links(recv_link, send_link, link_type_t::RX_DATA, get_default_io_srv_args(), xport_args, streamer_id); // Create the data transport auto rx_xport = std::make_unique(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 x300_impl::x300_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 std::string& streamer_id) { using namespace uhd::transport; const uhd::rfnoc::sep_addr_t local_sep_addr = addrs.first; const uhd::rfnoc::sep_id_t remote_epid = epids.second; const uhd::rfnoc::sep_id_t local_epid = epids.first; send_link_if::sptr send_link; recv_link_if::sptr recv_link; bool lossy_xport; std::tie(send_link, std::ignore, recv_link, std::ignore, lossy_xport, std::ignore) = _conn_mgr->get_links(link_type_t::TX_DATA, local_sep_addr.first, local_epid, remote_epid, 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 cfg_io_srv = get_io_srv_mgr()->connect_links(recv_link, send_link, link_type_t::CTRL); const auto buff_capacity = chdr_tx_data_xport::configure_sep(cfg_io_srv, recv_link, send_link, _pkt_factory, mgmt_portal, epids, pyld_buff_fmt, mdata_buff_fmt, fc_freq_ratio, fc_headroom_ratio); get_io_srv_mgr()->disconnect_links(recv_link, send_link); cfg_io_srv.reset(); // Connect the links to an I/O service auto io_srv = get_io_srv_mgr()->connect_links(recv_link, send_link, link_type_t::TX_DATA, get_default_io_srv_args(), xport_args, streamer_id); // Create the data transport auto tx_xport = std::make_unique(io_srv, recv_link, send_link, _pkt_factory, epids, send_link->get_num_send_frames(), buff_capacity); return tx_xport; }