diff options
Diffstat (limited to 'host/lib/usrp/x300/x300_impl.cpp')
| -rw-r--r-- | host/lib/usrp/x300/x300_impl.cpp | 1218 | 
1 files changed, 68 insertions, 1150 deletions
| diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 8ad1433d3..59ba1153b 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -1,278 +1,42 @@  //  // Copyright 2013-2016 Ettus Research LLC  // Copyright 2018 Ettus Research, a National Instruments Company +// Copyright 2019 Ettus Research, a National Instruments Brand  //  // SPDX-License-Identifier: GPL-3.0-or-later  //  #include "x300_impl.hpp" -#include "x300_lvbitx.hpp" +#include "x300_claim.hpp" +#include "x300_mb_eeprom.hpp"  #include "x300_mb_eeprom_iface.hpp"  #include "x300_mboard_type.hpp" -#include "x310_lvbitx.hpp"  #include <uhd/transport/if_addrs.hpp> -#include <uhd/transport/nirio/niusrprio_session.h> -#include <uhd/transport/nirio_zero_copy.hpp> -#include <uhd/transport/udp_constants.hpp> -#include <uhd/transport/udp_zero_copy.hpp> -#include <uhd/transport/zero_copy_recv_offload.hpp>  #include <uhd/types/sid.hpp>  #include <uhd/usrp/subdev_spec.hpp>  #include <uhd/utils/log.hpp>  #include <uhd/utils/math.hpp>  #include <uhd/utils/paths.hpp> -#include <uhd/utils/platform.hpp>  #include <uhd/utils/safe_call.hpp>  #include <uhd/utils/static.hpp> -#include <uhdlib/usrp/common/apply_corrections.hpp> -#ifdef HAVE_DPDK -#    include <uhdlib/transport/dpdk_simple.hpp> -#    include <uhdlib/transport/dpdk_zero_copy.hpp> -#endif  #include <boost/algorithm/string.hpp> -#include <boost/asio.hpp>  #include <boost/make_shared.hpp>  #include <chrono>  #include <fstream>  #include <thread> +uhd::uart_iface::sptr x300_make_uart_iface(uhd::wb_iface::sptr iface); +  using namespace uhd;  using namespace uhd::usrp;  using namespace uhd::rfnoc; -using namespace uhd::transport; -using namespace uhd::niusrprio; -using namespace uhd::usrp::gpio_atr;  using namespace uhd::usrp::x300;  namespace asio = boost::asio; -/****************************************************************************** - * Helpers - *****************************************************************************/ -namespace { - -constexpr unsigned int X300_UDP_RESERVED_FRAME_SIZE = 64; - -} // namespace - -static x300_impl::udp_simple_factory_t x300_get_udp_factory(const device_addr_t& args) -{ -    x300_impl::udp_simple_factory_t udp_make_connected = udp_simple::make_connected; -    if (args.has_key("use_dpdk")) { -#ifdef HAVE_DPDK -        udp_make_connected = [](const std::string& addr, const std::string& port) { -            auto& ctx = uhd::transport::uhd_dpdk_ctx::get(); -            return dpdk_simple::make_connected(ctx, addr, port); -        }; -#else -        UHD_LOG_WARNING( -            "DPDK", "Detected use_dpdk argument, but DPDK support not built in."); -#endif -    } -    return udp_make_connected; -} -  /***********************************************************************   * Discovery over the udp and pcie transport   **********************************************************************/ -//@TODO: Refactor the find functions to collapse common code for ethernet and PCIe -static device_addrs_t x300_find_with_addr(const device_addr_t& hint) -{ -    x300_impl::udp_simple_factory_t udp_make_broadcast = udp_simple::make_broadcast; -    x300_impl::udp_simple_factory_t udp_make_connected = x300_get_udp_factory(hint); -#ifdef HAVE_DPDK -    if (hint.has_key("use_dpdk")) { -        auto& dpdk_ctx = uhd::transport::uhd_dpdk_ctx::get(); -        if (not dpdk_ctx.is_init_done()) { -            dpdk_ctx.init(hint); -        } -        udp_make_broadcast = [](const std::string& addr, const std::string& port) { -            auto& ctx = uhd::transport::uhd_dpdk_ctx::get(); -            return dpdk_simple::make_broadcast(ctx, addr, port); -        }; -    } -#endif -    udp_simple::sptr comm = -        udp_make_broadcast(hint["addr"], BOOST_STRINGIZE(X300_FW_COMMS_UDP_PORT)); - -    // load request struct -    x300_fw_comms_t request = x300_fw_comms_t(); -    request.flags           = uhd::htonx<uint32_t>(X300_FW_COMMS_FLAGS_ACK); -    request.sequence        = uhd::htonx<uint32_t>(std::rand()); - -    // send request -    comm->send(asio::buffer(&request, sizeof(request))); - -    // loop for replies until timeout -    device_addrs_t addrs; -    while (true) { -        char buff[X300_FW_COMMS_MTU] = {}; -        const size_t nbytes          = comm->recv(asio::buffer(buff), 0.050); -        if (nbytes == 0) -            break; -        const x300_fw_comms_t* reply = (const x300_fw_comms_t*)buff; -        if (request.flags != reply->flags) -            continue; -        if (request.sequence != reply->sequence) -            continue; -        device_addr_t new_addr; -        new_addr["type"] = "x300"; -        new_addr["addr"] = comm->get_recv_addr(); - -        // Attempt to read the name from the EEPROM and perform filtering. -        // This operation can throw due to compatibility mismatch. -        try { -            wb_iface::sptr zpu_ctrl = x300_make_ctrl_iface_enet( -                udp_make_connected( -                    new_addr["addr"], BOOST_STRINGIZE(X300_FW_COMMS_UDP_PORT)), -                false /* Suppress timeout errors */ -            ); - -            new_addr["fpga"] = get_fpga_option(zpu_ctrl); - -            i2c_core_100_wb32::sptr zpu_i2c = -                i2c_core_100_wb32::make(zpu_ctrl, I2C1_BASE); -            x300_mb_eeprom_iface::sptr eeprom_iface = -                x300_mb_eeprom_iface::make(zpu_ctrl, zpu_i2c); -            const mboard_eeprom_t mb_eeprom = x300_impl::get_mb_eeprom(eeprom_iface); -            if (mb_eeprom.size() == 0 -                or x300_impl::claim_status(zpu_ctrl) == x300_impl::CLAIMED_BY_OTHER) { -                // Skip device claimed by another process -                continue; -            } -            new_addr["name"]               = mb_eeprom["name"]; -            new_addr["serial"]             = mb_eeprom["serial"]; -            const std::string product_name = -                map_mb_type_to_product_name(get_mb_type_from_eeprom(mb_eeprom)); -            if (!product_name.empty()) { -                new_addr["product"] = product_name; -            } -        } catch (const std::exception&) { -            // set these values as empty string so the device may still be found -            // and the filter's below can still operate on the discovered device -            new_addr["name"]   = ""; -            new_addr["serial"] = ""; -        } -        // filter the discovered device below by matching optional keys -        if ((not hint.has_key("name") or hint["name"] == new_addr["name"]) -            and (not hint.has_key("serial") or hint["serial"] == new_addr["serial"]) -            and (not hint.has_key("product") or hint["product"] == new_addr["product"])) { -            addrs.push_back(new_addr); -        } -    } - -    return addrs; -} - - -// We need a zpu xport registry to ensure synchronization between the static finder method -// and the instances of the x300_impl class. -typedef uhd::dict<std::string, boost::weak_ptr<wb_iface>> pcie_zpu_iface_registry_t; -UHD_SINGLETON_FCN(pcie_zpu_iface_registry_t, get_pcie_zpu_iface_registry) -static boost::mutex pcie_zpu_iface_registry_mutex; - -static device_addrs_t x300_find_pcie(const device_addr_t& hint, bool explicit_query) -{ -    std::string rpc_port_name(std::to_string(NIUSRPRIO_DEFAULT_RPC_PORT)); -    if (hint.has_key("niusrpriorpc_port")) { -        rpc_port_name = hint["niusrpriorpc_port"]; -    } - -    device_addrs_t addrs; -    niusrprio_session::device_info_vtr dev_info_vtr; -    nirio_status status = niusrprio_session::enumerate(rpc_port_name, dev_info_vtr); -    if (explicit_query) -        nirio_status_to_exception( -            status, "x300_find_pcie: Error enumerating NI-RIO devices."); - -    for (niusrprio_session::device_info& dev_info : dev_info_vtr) { -        device_addr_t new_addr; -        new_addr["type"]     = "x300"; -        new_addr["resource"] = dev_info.resource_name; -        std::string resource_d(dev_info.resource_name); -        boost::to_upper(resource_d); - -        const std::string product_name = map_mb_type_to_product_name( -            x300_impl::get_mb_type_from_pcie(resource_d, rpc_port_name)); -        if (product_name.empty()) { -            continue; -        } else { -            new_addr["product"] = product_name; -        } - -        niriok_proxy::sptr kernel_proxy = -            niriok_proxy::make_and_open(dev_info.interface_path); - -        // Attempt to read the name from the EEPROM and perform filtering. -        // This operation can throw due to compatibility mismatch. -        try { -            // This block could throw an exception if the user is switching to using UHD -            // after LabVIEW FPGA. In that case, skip reading the name and serial and pick -            // a default FPGA flavor. During make, a new image will be loaded and -            // everything will be OK - -            wb_iface::sptr zpu_ctrl; - -            // Hold on to the registry mutex as long as zpu_ctrl is alive -            // to prevent any use by different threads while enumerating -            boost::mutex::scoped_lock lock(pcie_zpu_iface_registry_mutex); - -            if (get_pcie_zpu_iface_registry().has_key(resource_d)) { -                zpu_ctrl = get_pcie_zpu_iface_registry()[resource_d].lock(); -                if (!zpu_ctrl) { -                    get_pcie_zpu_iface_registry().pop(resource_d); -                } -            } - -            // if the registry didn't have a key OR that key was an orphaned weak_ptr -            if (!zpu_ctrl) { -                zpu_ctrl = x300_make_ctrl_iface_pcie( -                    kernel_proxy, false /* suppress timeout errors */); -                // We don't put this zpu_ctrl in the registry because we need -                // a persistent niriok_proxy associated with the object -            } - -            // Attempt to autodetect the FPGA type -            if (not hint.has_key("fpga")) { -                new_addr["fpga"] = get_fpga_option(zpu_ctrl); -            } - -            i2c_core_100_wb32::sptr zpu_i2c = -                i2c_core_100_wb32::make(zpu_ctrl, I2C1_BASE); -            x300_mb_eeprom_iface::sptr eeprom_iface = -                x300_mb_eeprom_iface::make(zpu_ctrl, zpu_i2c); -            const mboard_eeprom_t mb_eeprom = x300_impl::get_mb_eeprom(eeprom_iface); -            if (mb_eeprom.size() == 0 -                or x300_impl::claim_status(zpu_ctrl) == x300_impl::CLAIMED_BY_OTHER) { -                // Skip device claimed by another process -                continue; -            } -            new_addr["name"]   = mb_eeprom["name"]; -            new_addr["serial"] = mb_eeprom["serial"]; -        } catch (const std::exception&) { -            // set these values as empty string so the device may still be found -            // and the filter's below can still operate on the discovered device -            if (not hint.has_key("fpga")) { -                new_addr["fpga"] = "HG"; -            } -            new_addr["name"]   = ""; -            new_addr["serial"] = ""; -        } - -        // filter the discovered device below by matching optional keys -        std::string resource_i = hint.has_key("resource") ? hint["resource"] : ""; -        boost::to_upper(resource_i); - -        if ((not hint.has_key("resource") or resource_i == resource_d) -            and (not hint.has_key("name") or hint["name"] == new_addr["name"]) -            and (not hint.has_key("serial") or hint["serial"] == new_addr["serial"]) -            and (not hint.has_key("product") or hint["product"] == new_addr["product"])) { -            addrs.push_back(new_addr); -        } -    } -    return addrs; -} -  device_addrs_t x300_find(const device_addr_t& hint_)  {      // handle the multi-device discovery @@ -303,15 +67,15 @@ device_addrs_t x300_find(const device_addr_t& hint_)      hints.resize(1); // in case it was empty      device_addr_t hint = hints[0];      device_addrs_t addrs; -    if (hint.has_key("type") and hint["type"] != "x300") +    if (hint.has_key("type") and hint["type"] != "x300") {          return addrs; - +    }      // use the address given      if (hint.has_key("addr")) {          device_addrs_t reply_addrs;          try { -            reply_addrs = x300_find_with_addr(hint); +            reply_addrs = eth_manager::find(hint);          } catch (const std::exception& ex) {              UHD_LOGGER_ERROR("X300") << "X300 Network discovery error " << ex.what();          } catch (...) { @@ -322,7 +86,7 @@ device_addrs_t x300_find(const device_addr_t& hint_)      if (!hint.has_key("resource")) {          // otherwise, no address was specified, send a broadcast on each interface -        for (const if_addrs_t& if_addrs : get_if_addrs()) { +        for (const transport::if_addrs_t& if_addrs : transport::get_if_addrs()) {              // avoid the loopback device              if (if_addrs.inet == asio::ip::address_v4::loopback().to_string())                  continue; @@ -355,9 +119,10 @@ device_addrs_t x300_find(const device_addr_t& hint_)          }      } -    device_addrs_t pcie_addrs = x300_find_pcie(hint, hint.has_key("resource")); -    if (not pcie_addrs.empty()) +    device_addrs_t pcie_addrs = pcie_manager::find(hint, hint.has_key("resource")); +    if (not pcie_addrs.empty()) {          addrs.insert(addrs.end(), pcie_addrs.begin(), pcie_addrs.end()); +    }      return addrs;  } @@ -406,8 +171,6 @@ x300_impl::x300_impl(const uhd::device_addr_t& dev_addr) : device3_impl(), _sid_      UHD_LOGGER_INFO("X300") << "X300 initialization sequence...";      _tree->create<std::string>("/name").set("X-Series Device"); -    _x300_make_udp_connected = x300_get_udp_factory(dev_addr); -      const device_addrs_t device_args = separate_device_addr(dev_addr);      _mb.resize(device_args.size()); @@ -437,208 +200,13 @@ x300_impl::x300_impl(const uhd::device_addr_t& dev_addr) : device3_impl(), _sid_      }  } -void x300_impl::mboard_members_t::discover_eth( -    const mboard_eeprom_t mb_eeprom, const std::vector<std::string>& ip_addrs) -{ -    x300_impl::udp_simple_factory_t udp_make_connected = x300_get_udp_factory(send_args); - -    // Clear any previous addresses added -    eth_conns.clear(); - -    // Index the MB EEPROM addresses -    std::vector<std::string> mb_eeprom_addrs; -    const size_t num_mb_eeprom_addrs = 4; -    for (size_t i = 0; i < num_mb_eeprom_addrs; i++) { -        const std::string key = "ip-addr" + boost::to_string(i); - -        // Show a warning if there exists duplicate addresses in the mboard eeprom -        if (std::find(mb_eeprom_addrs.begin(), mb_eeprom_addrs.end(), mb_eeprom[key]) -            != mb_eeprom_addrs.end()) { -            UHD_LOGGER_WARNING("X300") << str( -                boost::format( -                    "Duplicate IP address %s found in mboard EEPROM. " -                    "Device may not function properly. View and reprogram the values " -                    "using the usrp_burn_mb_eeprom utility.") -                % mb_eeprom[key]); -        } -        mb_eeprom_addrs.push_back(mb_eeprom[key]); -    } - -    for (const std::string& addr : ip_addrs) { -        x300_eth_conn_t conn_iface; -        conn_iface.addr = addr; -        conn_iface.type = X300_IFACE_NONE; - -        // Decide from the mboard eeprom what IP corresponds -        // to an interface -        for (size_t i = 0; i < mb_eeprom_addrs.size(); i++) { -            if (addr == mb_eeprom_addrs[i]) { -                // Choose the interface based on the index parity -                if (i % 2 == 0) { -                    conn_iface.type      = X300_IFACE_ETH0; -                    conn_iface.link_rate = loaded_fpga_image == "HG" -                                               ? x300::MAX_RATE_1GIGE -                                               : x300::MAX_RATE_10GIGE; -                } else { -                    conn_iface.type      = X300_IFACE_ETH1; -                    conn_iface.link_rate = x300::MAX_RATE_10GIGE; -                } -                break; -            } -        } - -        // Check default IP addresses if we couldn't -        // determine the IP from the mboard eeprom -        if (conn_iface.type == X300_IFACE_NONE) { -            UHD_LOGGER_WARNING("X300") << str( -                boost::format( -                    "Address %s not found in mboard EEPROM. Address may be wrong or " -                    "the EEPROM may be corrupt. Attempting to continue with default " -                    "IP addresses.") -                % conn_iface.addr); - -            if (addr -                == boost::asio::ip::address_v4(uint32_t(X300_DEFAULT_IP_ETH0_1G)) -                       .to_string()) { -                conn_iface.type      = X300_IFACE_ETH0; -                conn_iface.link_rate = x300::MAX_RATE_1GIGE; -            } else if (addr -                       == boost::asio::ip::address_v4(uint32_t(X300_DEFAULT_IP_ETH1_1G)) -                              .to_string()) { -                conn_iface.type      = X300_IFACE_ETH1; -                conn_iface.link_rate = x300::MAX_RATE_1GIGE; -            } else if (addr -                       == boost::asio::ip::address_v4(uint32_t(X300_DEFAULT_IP_ETH0_10G)) -                              .to_string()) { -                conn_iface.type      = X300_IFACE_ETH0; -                conn_iface.link_rate = x300::MAX_RATE_10GIGE; -            } else if (addr -                       == boost::asio::ip::address_v4(uint32_t(X300_DEFAULT_IP_ETH1_10G)) -                              .to_string()) { -                conn_iface.type      = X300_IFACE_ETH1; -                conn_iface.link_rate = x300::MAX_RATE_10GIGE; -            } else { -                throw uhd::assertion_error( -                    str(boost::format( -                            "X300 Initialization Error: Failed to match address %s with " -                            "any addresses for the device. Please check the address.") -                        % conn_iface.addr)); -            } -        } - -        // Save to a vector of connections -        if (conn_iface.type != X300_IFACE_NONE) { -            // Check the address before we add it -            try { -                wb_iface::sptr zpu_ctrl = x300_make_ctrl_iface_enet( -                    udp_make_connected( -                        conn_iface.addr, BOOST_STRINGIZE(X300_FW_COMMS_UDP_PORT)), -                    false /* Suppress timeout errors */ -                ); - -                // Peek the ZPU ctrl to make sure this connection works -                zpu_ctrl->peek32(0); -            } - -            // If the address does not work, throw an error -            catch (std::exception&) { -                throw uhd::io_error( -                    str(boost::format("X300 Initialization Error: Invalid address %s") -                        % conn_iface.addr)); -            } -            eth_conns.push_back(conn_iface); -        } -    } - -    if (eth_conns.size() == 0) -        throw uhd::assertion_error( -            "X300 Initialization Error: No ethernet interfaces specified."); -} -  void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t& dev_addr)  {      const fs_path mb_path  = fs_path("/mboards") / mb_i;      mboard_members_t& mb   = _mb[mb_i]; -    mb.initialization_done = false; - -    const std::string thread_id( -        boost::lexical_cast<std::string>(boost::this_thread::get_id())); -    const std::string thread_msg( -        "Thread ID " + thread_id + " for motherboard " + std::to_string(mb_i)); -      mb.args.parse(dev_addr); - -    std::vector<std::string> eth_addrs; -    // Not choosing eth0 based on resource might cause user issues -    std::string eth0_addr = dev_addr.has_key("resource") ? dev_addr["resource"] -                                                         : dev_addr["addr"]; -    eth_addrs.push_back(eth0_addr); - -    mb.next_src_addr    = 0; // Host source address for blocks -    mb.next_tx_src_addr = 0; -    mb.next_rx_src_addr = 0; -    if (not mb.args.get_second_addr().empty()) { -        std::string eth1_addr = mb.args.get_second_addr(); - -        // Ensure we do not have duplicate addresses -        if (eth1_addr != eth0_addr) -            eth_addrs.push_back(eth1_addr); -    } - -    // Initially store the first address provided to setup communication -    // Once we read the eeprom, we use it to map IP to its interface -    x300_eth_conn_t init; -    init.addr = eth_addrs[0]; -    mb.eth_conns.push_back(init); - -    mb.xport_path           = dev_addr.has_key("resource") ? "nirio" : "eth"; -    mb.if_pkt_is_big_endian = mb.xport_path != "nirio"; - -    if (mb.xport_path == "nirio") { -        nirio_status status = 0; - -        const std::string rpc_port_name = mb.args.get_niusrprio_rpc_port(); -        UHD_LOGGER_INFO("X300") -            << boost::format("Connecting to niusrpriorpc at localhost:%s...") -                   % rpc_port_name; - -        // Instantiate the correct lvbitx object -        nifpga_lvbitx::sptr lvbitx; -        switch (get_mb_type_from_pcie(mb.args.get_resource(), rpc_port_name)) { -            case USRP_X300_MB: -                lvbitx.reset(new x300_lvbitx(dev_addr["fpga"])); -                break; -            case USRP_X310_MB: -            case USRP_X310_MB_NI_2974: -                lvbitx.reset(new x310_lvbitx(dev_addr["fpga"])); -                break; -            default: -                nirio_status_to_exception( -                    status, "Motherboard detection error. Please ensure that you \ -                    have a valid USRP X3x0, NI USRP-294xR, NI USRP-295xR or NI USRP-2974 device and that all the device \ -                    drivers have loaded successfully."); -        } -        // Load the lvbitx onto the device -        UHD_LOGGER_INFO("X300") -            << boost::format("Using LVBITX bitfile %s...") % lvbitx->get_bitfile_path(); -        mb.rio_fpga_interface.reset( -            new niusrprio_session(dev_addr["resource"], rpc_port_name)); -        nirio_status_chain( -            mb.rio_fpga_interface->open(lvbitx, dev_addr.has_key("download-fpga")), -            status); -        nirio_status_to_exception(status, "x300_impl: Could not initialize RIO session."); - -        // Tell the quirks object which FIFOs carry TX stream data -        const uint32_t tx_data_fifos[2] = { -            x300::RADIO_DEST_PREFIX_TX, x300::RADIO_DEST_PREFIX_TX + 3}; -        mb.rio_fpga_interface->get_kernel_proxy()->get_rio_quirks().register_tx_streams( -            tx_data_fifos, 2); - -        _tree->create<size_t>(mb_path / "mtu/recv").set(x300::PCIE_RX_DATA_FRAME_SIZE); -        _tree->create<size_t>(mb_path / "mtu/send").set(x300::PCIE_TX_DATA_FRAME_SIZE); -        _tree->create<double>(mb_path / "link_max_rate").set(x300::MAX_RATE_PCIE); -    } - +    mb.xport_path = dev_addr.has_key("resource") ? xport_path_t::NIRIO +                                                 : xport_path_t::ETH;      for (const std::string& key : dev_addr.keys()) {          if (key.find("recv") != std::string::npos)              mb.recv_args[key] = dev_addr[key]; @@ -646,37 +214,23 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t& dev_addr)              mb.send_args[key] = dev_addr[key];      } -#ifdef HAVE_DPDK -    if (dev_addr.has_key("use_dpdk")) { -        mb.recv_args["use_dpdk"] = dev_addr["use_dpdk"]; -        mb.send_args["use_dpdk"] = dev_addr["use_dpdk"]; -    } -#endif - -    // create basic communication      UHD_LOGGER_DEBUG("X300") << "Setting up basic communication..."; -    if (mb.xport_path == "nirio") { -        boost::mutex::scoped_lock lock(pcie_zpu_iface_registry_mutex); -        if (get_pcie_zpu_iface_registry().has_key(mb.get_pri_eth().addr)) { -            throw uhd::assertion_error( -                "Someone else has a ZPU transport to the device open. Internal error!"); -        } else { -            mb.zpu_ctrl = -                x300_make_ctrl_iface_pcie(mb.rio_fpga_interface->get_kernel_proxy()); -            get_pcie_zpu_iface_registry()[mb.get_pri_eth().addr] = -                boost::weak_ptr<wb_iface>(mb.zpu_ctrl); -        } +    if (mb.xport_path == xport_path_t::NIRIO) { +        mb.pcie_mgr = +            std::unique_ptr<pcie_manager>(new pcie_manager(mb.args, _tree, mb_path)); +        mb.zpu_ctrl = mb.pcie_mgr->get_ctrl_iface();      } else { -        mb.zpu_ctrl = x300_make_ctrl_iface_enet(_x300_make_udp_connected( -            mb.get_pri_eth().addr, BOOST_STRINGIZE(X300_FW_COMMS_UDP_PORT))); +        mb.eth_mgr = +            std::unique_ptr<eth_manager>(new eth_manager(mb.args, _tree, mb_path)); +        mb.zpu_ctrl = mb.eth_mgr->get_ctrl_iface();      }      // Claim device      if (not try_to_claim(mb.zpu_ctrl)) {          throw uhd::runtime_error("Failed to claim device");      } -    mb.claimer_task = uhd::task::make( -        [this, mb]() { this->claimer_loop(mb.zpu_ctrl); }, "x300_claimer"); +    mb.claimer_task = +        uhd::task::make([&mb]() { claimer_loop(mb.zpu_ctrl); }, "x300_claimer");      // extract the FW path for the X300      // and live load fw over ethernet link @@ -741,8 +295,8 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t& dev_addr)          // Initialize the property with a current copy of the EEPROM contents          .set(mb_eeprom)          // Whenever this property is written, update the chip -        .add_coerced_subscriber([this, eeprom16](const mboard_eeprom_t& mb_eeprom) { -            this->set_mb_eeprom(eeprom16, mb_eeprom); +        .add_coerced_subscriber([eeprom16](const mboard_eeprom_t& mb_eeprom) { +            set_mb_eeprom(eeprom16, mb_eeprom);          });      if (mb.args.get_recover_mb_eeprom()) { @@ -775,131 +329,10 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t& dev_addr)      ////////////////////////////////////////////////////////////////////      // discover interfaces, frame sizes, and link rates      //////////////////////////////////////////////////////////////////// -    if (mb.xport_path == "nirio") { -        _max_frame_sizes.recv_frame_size = PCIE_RX_DATA_FRAME_SIZE; -        _max_frame_sizes.send_frame_size = PCIE_TX_DATA_FRAME_SIZE; -    } else if (mb.xport_path == "eth") { -        double link_max_rate = 0.0; - -        // Discover ethernet interfaces -        mb.discover_eth(mb_eeprom, eth_addrs); - -        /* This is an ETH connection. Figure out what the maximum supported frame -         * size is for the transport in the up and down directions. The frame size -         * depends on the host PC's NIC's MTU settings. To determine the frame size, -         * we test for support up to an expected "ceiling". If the user -         * specified a frame size, we use that frame size as the ceiling. If no -         * frame size was specified, we use the maximum UHD frame size. -         * -         * To optimize performance, the frame size should be greater than or equal -         * to the frame size that UHD uses so that frames don't get split across -         * multiple transmission units - this is why the limits passed into the -         * 'determine_max_frame_size' function are actually frame sizes. */ -        frame_size_t req_max_frame_size; -        req_max_frame_size.recv_frame_size = -            (mb.recv_args.has_key("recv_frame_size")) -                ? boost::lexical_cast<size_t>(mb.recv_args["recv_frame_size"]) -                : x300::DATA_FRAME_MAX_SIZE; -        req_max_frame_size.send_frame_size = -            (mb.send_args.has_key("send_frame_size")) -                ? boost::lexical_cast<size_t>(mb.send_args["send_frame_size"]) -                : x300::DATA_FRAME_MAX_SIZE; - -#if defined UHD_PLATFORM_LINUX -        const std::string mtu_tool("ip link"); -#elif defined UHD_PLATFORM_WIN32 -        const std::string mtu_tool("netsh"); -#else -        const std::string mtu_tool("ifconfig"); -#endif - -        // Detect the frame size on the path to the USRP -        try { -            frame_size_t pri_frame_sizes = -                determine_max_frame_size(eth_addrs.at(0), req_max_frame_size); - -            _max_frame_sizes = pri_frame_sizes; -            if (eth_addrs.size() > 1) { -                frame_size_t sec_frame_sizes = -                    determine_max_frame_size(eth_addrs.at(1), req_max_frame_size); - -                // Choose the minimum of the max frame sizes -                // to ensure we don't exceed any one of the links' MTU -                _max_frame_sizes.recv_frame_size = std::min( -                    pri_frame_sizes.recv_frame_size, sec_frame_sizes.recv_frame_size); - -                _max_frame_sizes.send_frame_size = std::min( -                    pri_frame_sizes.send_frame_size, sec_frame_sizes.send_frame_size); -            } -        } catch (std::exception& e) { -            UHD_LOGGER_ERROR("X300") << e.what(); -        } - -        if ((mb.recv_args.has_key("recv_frame_size")) -            && (req_max_frame_size.recv_frame_size > _max_frame_sizes.recv_frame_size)) { -            UHD_LOGGER_WARNING("X300") -                << boost::format("You requested a receive frame size of (%lu) but your " -                                 "NIC's max frame size is (%lu).") -                       % req_max_frame_size.recv_frame_size -                       % _max_frame_sizes.recv_frame_size -                << boost::format("Please verify your NIC's MTU setting using '%s' or set " -                                 "the recv_frame_size argument appropriately.") -                       % mtu_tool -                << "UHD will use the auto-detected max frame size for this connection."; -        } - -        if ((mb.send_args.has_key("send_frame_size")) -            && (req_max_frame_size.send_frame_size > _max_frame_sizes.send_frame_size)) { -            UHD_LOGGER_WARNING("X300") -                << boost::format("You requested a send frame size of (%lu) but your " -                                 "NIC's max frame size is (%lu).") -                       % req_max_frame_size.send_frame_size -                       % _max_frame_sizes.send_frame_size -                << boost::format("Please verify your NIC's MTU setting using '%s' or set " -                                 "the send_frame_size argument appropriately.") -                       % mtu_tool -                << "UHD will use the auto-detected max frame size for this connection."; -        } - -        // Check frame sizes -        for (auto conn : mb.eth_conns) { -            link_max_rate += conn.link_rate; - -            size_t rec_send_frame_size = conn.link_rate == x300::MAX_RATE_1GIGE -                                             ? x300::GE_DATA_FRAME_SEND_SIZE -                                             : x300::XGE_DATA_FRAME_SEND_SIZE; -            size_t rec_recv_frame_size = conn.link_rate == x300::MAX_RATE_1GIGE -                                             ? x300::GE_DATA_FRAME_RECV_SIZE -                                             : x300::XGE_DATA_FRAME_RECV_SIZE; - -            if (_max_frame_sizes.send_frame_size < rec_send_frame_size) { -                UHD_LOGGER_WARNING("X300") -                    << boost::format("For the %s connection, UHD recommends a send frame " -                                     "size of at least %lu for best\nperformance, but " -                                     "your configuration will only allow %lu.") -                           % conn.addr % rec_send_frame_size -                           % _max_frame_sizes.send_frame_size -                    << "This may negatively impact your maximum achievable sample " -                       "rate.\nCheck the MTU on the interface and/or the send_frame_size " -                       "argument."; -            } - -            if (_max_frame_sizes.recv_frame_size < rec_recv_frame_size) { -                UHD_LOGGER_WARNING("X300") -                    << boost::format("For the %s connection, UHD recommends a receive " -                                     "frame size of at least %lu for best\nperformance, " -                                     "but your configuration will only allow %lu.") -                           % conn.addr % rec_recv_frame_size -                           % _max_frame_sizes.recv_frame_size -                    << "This may negatively impact your maximum achievable sample " -                       "rate.\nCheck the MTU on the interface and/or the recv_frame_size " -                       "argument."; -            } -        } - -        _tree->create<size_t>(mb_path / "mtu/recv").set(_max_frame_sizes.recv_frame_size); -        _tree->create<size_t>(mb_path / "mtu/send").set(_max_frame_sizes.send_frame_size); -        _tree->create<double>(mb_path / "link_max_rate").set(link_max_rate); +    if (mb.xport_path == xport_path_t::NIRIO) { +        mb.pcie_mgr->init_link(); +    } else if (mb.xport_path == xport_path_t::ETH) { +        mb.eth_mgr->init_link(mb_eeprom, mb.loaded_fpga_image);      }      //////////////////////////////////////////////////////////////////// @@ -930,7 +363,7 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t& dev_addr)      ////////////////////////////////////////////////////////////////////      // create clock properties      //////////////////////////////////////////////////////////////////// -    _tree->create<double>(mb_path / "master_clock_rate").set_publisher([mb]() { +    _tree->create<double>(mb_path / "master_clock_rate").set_publisher([&mb]() {          return mb.clock->get_master_clock_rate();      }); @@ -940,7 +373,7 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t& dev_addr)      ////////////////////////////////////////////////////////////////////      // Create the GPSDO control      //////////////////////////////////////////////////////////////////// -    static const uint32_t dont_look_for_gpsdo = 0x1234abcdul; +    static constexpr uint32_t dont_look_for_gpsdo = 0x1234abcdul;      // otherwise if not disabled, look for the internal GPSDO      if (mb.zpu_ctrl->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_GPSDO_STATUS)) @@ -972,10 +405,8 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t& dev_addr)          .add_coerced_subscriber([this, &mb](const std::string& time_source) {              this->update_time_source(mb, time_source);          }); -    static const std::vector<std::string> time_sources = { -        "internal", "external", "gpsdo"};      _tree->create<std::vector<std::string>>(mb_path / "time_source" / "options") -        .set(time_sources); +        .set(TIME_SOURCE_OPTIONS);      // setup the time output, default to ON      _tree->create<bool>(mb_path / "time_source" / "output") @@ -992,10 +423,8 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t& dev_addr)          .add_coerced_subscriber([this, &mb](const std::string& clock_source) {              this->update_clock_source(mb, clock_source);          }); -    static const std::vector<std::string> clock_source_options = { -        "internal", "external", "gpsdo"};      _tree->create<std::vector<std::string>>(mb_path / "clock_source" / "options") -        .set(clock_source_options); +        .set(CLOCK_SOURCE_OPTIONS);      // setup external reference options. default to 10 MHz input reference      _tree->create<std::string>(mb_path / "clock_source" / "external"); @@ -1107,14 +536,10 @@ x300_impl::~x300_impl(void)          for (mboard_members_t& mb : _mb) {              // kill the claimer task and unclaim the device              mb.claimer_task.reset(); -            { // Critical section -                boost::mutex::scoped_lock lock(pcie_zpu_iface_registry_mutex); +            if (mb.xport_path == xport_path_t::NIRIO) { +                mb.pcie_mgr->release_ctrl_iface([&mb]() { release(mb.zpu_ctrl); }); +            } else {                  release(mb.zpu_ctrl); -                // If the process is killed, the entire registry will disappear so we -                // don't need to worry about unclean shutdowns here. -                if (get_pcie_zpu_iface_registry().has_key(mb.get_pri_eth().addr)) { -                    get_pcie_zpu_iface_registry().pop(mb.get_pri_eth().addr); -                }              }          }      } catch (...) { @@ -1122,67 +547,13 @@ x300_impl::~x300_impl(void)      }  } -uint32_t x300_impl::mboard_members_t::allocate_pcie_dma_chan( -    const uhd::sid_t& tx_sid, const xport_type_t xport_type) -{ -    static const uint32_t CTRL_CHANNEL       = 0; -    static const uint32_t ASYNC_MSG_CHANNEL  = 1; -    static const uint32_t FIRST_DATA_CHANNEL = 2; -    if (xport_type == CTRL) { -        return CTRL_CHANNEL; -    } else if (xport_type == ASYNC_MSG) { -        return ASYNC_MSG_CHANNEL; -    } else { -        // sid_t has no comparison defined, so we need to convert it uint32_t -        uint32_t raw_sid = tx_sid.get(); - -        if (_dma_chan_pool.count(raw_sid) == 0) { -            size_t channel = _dma_chan_pool.size() + FIRST_DATA_CHANNEL; -            if (channel > x300::PCIE_MAX_CHANNELS) { -                throw uhd::runtime_error( -                    "Trying to allocate more DMA channels than are available"); -            } -            _dma_chan_pool[raw_sid] = channel; -            UHD_LOGGER_DEBUG("X300") -                << "Assigning PCIe DMA channel " << _dma_chan_pool[raw_sid] << " to SID " -                << tx_sid.to_pp_string_hex(); -        } - -        return _dma_chan_pool[raw_sid]; -    } -} - -static uint32_t extract_sid_from_pkt(void* pkt, size_t) -{ -    return uhd::sid_t(uhd::wtohx(static_cast<const uint32_t*>(pkt)[1])).get_dst(); -} - -static uhd::transport::muxed_zero_copy_if::sptr make_muxed_pcie_msg_xport( -    uhd::niusrprio::niusrprio_session::sptr rio_fpga_interface, -    uint32_t dma_channel_num, -    size_t max_muxed_ports) -{ -    zero_copy_xport_params buff_args; -    buff_args.send_frame_size = x300::PCIE_MSG_FRAME_SIZE; -    buff_args.recv_frame_size = x300::PCIE_MSG_FRAME_SIZE; -    buff_args.num_send_frames = x300::PCIE_MSG_NUM_FRAMES; -    buff_args.num_recv_frames = x300::PCIE_MSG_NUM_FRAMES; - -    zero_copy_if::sptr base_xport = nirio_zero_copy::make( -        rio_fpga_interface, dma_channel_num, buff_args, uhd::device_addr_t()); -    return muxed_zero_copy_if::make(base_xport, extract_sid_from_pkt, max_muxed_ports); -} -  uhd::both_xports_t x300_impl::make_transport(const uhd::sid_t& address,      const xport_type_t xport_type,      const uhd::device_addr_t& args)  { -    const size_t mb_index                = address.get_dst_addr() - x300::DST_ADDR; -    mboard_members_t& mb                 = _mb[mb_index]; -    zero_copy_xport_params default_buff_args; - +    const size_t mb_index = address.get_dst_addr() - x300::DST_ADDR; +    mboard_members_t& mb  = _mb[mb_index];      both_xports_t xports; -    xports.endianness = mb.if_pkt_is_big_endian ? ENDIANNESS_BIG : ENDIANNESS_LITTLE;      // Calculate MTU based on MTU in args and device limitations      const size_t send_mtu = args.cast<size_t>("mtu", @@ -1190,183 +561,24 @@ uhd::both_xports_t x300_impl::make_transport(const uhd::sid_t& address,      const size_t recv_mtu = args.cast<size_t>("mtu",          get_mtu(mb_index, uhd::RX_DIRECTION)); -    if (mb.xport_path == "nirio") { -        xports.lossless = true; +    if (mb.xport_path == xport_path_t::NIRIO) {          xports.send_sid =              this->allocate_sid(mb, address, x300::SRC_ADDR0, x300::XB_DST_PCI);          xports.recv_sid = xports.send_sid.reversed(); - -        uint32_t dma_channel_num = mb.allocate_pcie_dma_chan(xports.send_sid, xport_type); -        if (xport_type == CTRL) { -            // Transport for control stream -            if (not mb.ctrl_dma_xport) { -                // One underlying DMA channel will handle -                // all control traffic -                mb.ctrl_dma_xport = make_muxed_pcie_msg_xport(mb.rio_fpga_interface, -                    dma_channel_num, -                    x300::PCIE_MAX_MUXED_CTRL_XPORTS); -            } -            // Create a virtual control transport -            xports.recv = mb.ctrl_dma_xport->make_stream(xports.recv_sid.get_dst()); -        } else if (xport_type == ASYNC_MSG) { -            // Transport for async message stream -            if (not mb.async_msg_dma_xport) { -                // One underlying DMA channel will handle -                // all async message traffic -                mb.async_msg_dma_xport = make_muxed_pcie_msg_xport(mb.rio_fpga_interface, -                    dma_channel_num, -                    x300::PCIE_MAX_MUXED_ASYNC_XPORTS); -            } -            // Create a virtual async message transport -            xports.recv = mb.async_msg_dma_xport->make_stream(xports.recv_sid.get_dst()); -        } else if (xport_type == TX_DATA) { -            default_buff_args.send_frame_size = args.cast<size_t>( -                "send_frame_size", std::min(send_mtu, -                x300::PCIE_TX_DATA_FRAME_SIZE)); -            default_buff_args.num_send_frames = args.cast<size_t>( -                "num_send_frames", x300::PCIE_TX_DATA_NUM_FRAMES); -            default_buff_args.send_buff_size = args.cast<size_t>( -                "send_buff_size", 0); -            default_buff_args.recv_frame_size = x300::PCIE_MSG_FRAME_SIZE; -            default_buff_args.num_recv_frames = x300::PCIE_MSG_NUM_FRAMES; -            xports.recv = nirio_zero_copy::make( -                mb.rio_fpga_interface, dma_channel_num, default_buff_args); -        } else if (xport_type == RX_DATA) { -            default_buff_args.send_frame_size = x300::PCIE_MSG_FRAME_SIZE; -            default_buff_args.num_send_frames = x300::PCIE_MSG_NUM_FRAMES; -            default_buff_args.recv_frame_size = args.cast<size_t>( -                "recv_frame_size", std::min(recv_mtu, -                x300::PCIE_RX_DATA_FRAME_SIZE)); -            default_buff_args.num_recv_frames = args.cast<size_t>( -                "num_recv_frames", x300::PCIE_RX_DATA_NUM_FRAMES); -            default_buff_args.recv_buff_size = args.cast<size_t>( -                "recv_buff_size", 0); -            xports.recv = nirio_zero_copy::make( -                mb.rio_fpga_interface, dma_channel_num, default_buff_args); -        } - -        xports.send = xports.recv; - -        // Router config word is: -        // - Upper 16 bits: Destination address (e.g. 0.0) -        // - Lower 16 bits: DMA channel -        uint32_t router_config_word = (xports.recv_sid.get_dst() << 16) | dma_channel_num; -        mb.rio_fpga_interface->get_kernel_proxy()->poke( -            PCIE_ROUTER_REG(0), router_config_word); - -        // For the nirio transport, buffer size is depends on the frame size and num -        // frames -        xports.recv_buff_size = -            xports.recv->get_num_recv_frames() * xports.recv->get_recv_frame_size(); -        xports.send_buff_size = -            xports.send->get_num_send_frames() * xports.send->get_send_frame_size(); - -#ifdef HAVE_DPDK -    } else if (mb.xport_path == "eth" and mb.recv_args.has_key("use_dpdk")) { -        auto& dpdk_ctx = uhd::transport::uhd_dpdk_ctx::get(); -        // Decide on the IP/Interface pair based on the endpoint index -        size_t& next_src_addr = xport_type == TX_DATA -                                    ? mb.next_tx_src_addr -                                    : xport_type == RX_DATA ? mb.next_rx_src_addr -                                                            : mb.next_src_addr; -        x300_eth_conn_t conn         = mb.eth_conns[next_src_addr]; -        const uint32_t xbar_src_addr = next_src_addr == 0 ? x300::SRC_ADDR0 -                                                          : x300::SRC_ADDR1; -        const uint32_t xbar_src_dst = conn.type == X300_IFACE_ETH0 ? x300::XB_DST_E0 -                                                                   : x300::XB_DST_E1; - -        // Do not increment src addr for tx_data by default, using dual ethernet -        // with the DMA FIFO causes sequence errors to DMA FIFO bandwidth -        // limitations. -        if (xport_type != TX_DATA || mb.args.get_enable_tx_dual_eth()) { -            next_src_addr = (next_src_addr + 1) % mb.eth_conns.size(); -        } - -        xports.send_sid = this->allocate_sid(mb, address, xbar_src_addr, xbar_src_dst); -        xports.recv_sid = xports.send_sid.reversed(); - -        // Set size and number of frames -        default_buff_args.send_frame_size = std::min(send_mtu, -                x300::ETH_MSG_FRAME_SIZE); -        default_buff_args.recv_frame_size = std::min(recv_mtu, -                x300::ETH_MSG_FRAME_SIZE); -        default_buff_args.num_recv_frames = x300::ETH_MSG_NUM_FRAMES; -        default_buff_args.num_send_frames = x300::ETH_MSG_NUM_FRAMES; -        if (xport_type == CTRL) { -            // Increasing number of recv frames here because ctrl_iface uses it -            // to determine how many control packets can be in flight before it -            // must wait for an ACK -            default_buff_args.num_recv_frames = -                uhd::rfnoc::CMD_FIFO_SIZE / uhd::rfnoc::MAX_CMD_PKT_SIZE; -        } else if (xport_type == TX_DATA) { -            size_t default_frame_size = conn.link_rate == x300::MAX_RATE_1GIGE -                                            ? x300::GE_DATA_FRAME_SEND_SIZE -                                            : x300::XGE_DATA_FRAME_SEND_SIZE; -            default_buff_args.send_frame_size = -                args.cast<size_t>("send_frame_size", -                std::min(default_frame_size, send_mtu)); -            default_buff_args.num_send_frames = -                args.cast<size_t>("num_send_frames", -                default_buff_args.num_send_frames); -            default_buff_args.send_buff_size = -                args.cast<size_t>("send_buff_size", 0); -        } else if (xport_type == RX_DATA) { -            size_t default_frame_size = conn.link_rate == x300::MAX_RATE_1GIGE -                                            ? x300::GE_DATA_FRAME_RECV_SIZE -                                            : x300::XGE_DATA_FRAME_RECV_SIZE; -            default_buff_args.recv_frame_size = -                args.cast<size_t>("recv_frame_size", -                std::min(default_frame_size, recv_mtu)); -            default_buff_args.num_recv_frames = -                args.cast<size_t>("num_recv_frames", -                default_buff_args.num_recv_frames); -            default_buff_args.recv_buff_size = -                args.cast<size_t>("recv_buff_size", 0); -        } - -        int dpdk_port_id = dpdk_ctx.get_route(conn.addr); -        if (dpdk_port_id < 0) { -            throw uhd::runtime_error( -                "Could not find a DPDK port with route to " + conn.addr); -        } -        auto recv = transport::dpdk_zero_copy::make( -            dpdk_ctx, -            (const unsigned int) dpdk_port_id, -            conn.addr, -            BOOST_STRINGIZE(X300_VITA_UDP_PORT), -            "0", -            default_buff_args, -            uhd::device_addr_t() -        ); - -        xports.recv = recv; // Note: This is a type cast! -        xports.send = xports.recv; -        xports.recv_buff_size = -            (default_buff_args.recv_frame_size - X300_UDP_RESERVED_FRAME_SIZE) -            * default_buff_args.num_recv_frames; -        xports.send_buff_size = -            (default_buff_args.send_frame_size - X300_UDP_RESERVED_FRAME_SIZE) -            * default_buff_args.num_send_frames; -        UHD_LOG_TRACE("BUFF", -            "num_recv_frames=" -                << default_buff_args.num_recv_frames -                << ", num_send_frames=" << default_buff_args.num_send_frames -                << ", recv_frame_size=" << default_buff_args.recv_frame_size -                << ", send_frame_size=" << default_buff_args.send_frame_size); -        // send a mini packet with SID into the ZPU -        // ZPU will reprogram the ethernet framer -        UHD_LOGGER_DEBUG("X300") << "programming packet for new xport on " << conn.addr -                                 << " sid " << xports.send_sid; -        // YES, get a __send__ buffer from the __recv__ socket -        //-- this is the only way to program the framer for recv: -        managed_send_buffer::sptr buff = xports.recv->get_send_buff(); -        buff->cast<uint32_t*>()[0]     = 0; // eth dispatch looks for != 0 -        buff->cast<uint32_t*>()[1]     = uhd::htonx(xports.send_sid.get()); -        buff->commit(8); -        buff.reset(); +        return mb.pcie_mgr->make_transport(xports, xport_type, args, send_mtu, recv_mtu); +    } else if (mb.xport_path == xport_path_t::ETH) { +        xports = mb.eth_mgr->make_transport(xports, +            xport_type, +            args, +            send_mtu, +            recv_mtu, +            [this, &mb, address](const uint32_t src_addr, const uint32_t src_dst) { +                return this->allocate_sid(mb, address, src_addr, src_dst); +            });          // reprogram the ethernet dispatcher's udp port (should be safe to always set) -        UHD_LOGGER_TRACE("X300") << "reprogram the ethernet dispatcher's udp port"; +        UHD_LOGGER_TRACE("X300") +            << "reprogram the ethernet dispatcher's udp port to " << X300_VITA_UDP_PORT;          mb.zpu_ctrl->poke32(              SR_ADDR(SET0_BASE, (ZPU_SR_ETHINT0 + 8 + 3)), X300_VITA_UDP_PORT);          mb.zpu_ctrl->poke32( @@ -1375,128 +587,10 @@ uhd::both_xports_t x300_impl::make_transport(const uhd::sid_t& address,          // Do a peek to an arbitrary address to guarantee that the          // ethernet framer has been programmed before we return.          mb.zpu_ctrl->peek32(0); -#endif -    } else if (mb.xport_path == "eth") { -        // Decide on the IP/Interface pair based on the endpoint index -        size_t& next_src_addr = xport_type == TX_DATA -                                    ? mb.next_tx_src_addr -                                    : xport_type == RX_DATA ? mb.next_rx_src_addr -                                                            : mb.next_src_addr; -        x300_eth_conn_t conn         = mb.eth_conns[next_src_addr]; -        const uint32_t xbar_src_addr = next_src_addr == 0 ? x300::SRC_ADDR0 -                                                          : x300::SRC_ADDR1; -        const uint32_t xbar_src_dst = conn.type == X300_IFACE_ETH0 ? x300::XB_DST_E0 -                                                                   : x300::XB_DST_E1; - -        // Do not increment src addr for tx_data by default, using dual ethernet -        // with the DMA FIFO causes sequence errors to DMA FIFO bandwidth -        // limitations. -        if (xport_type != TX_DATA || mb.args.get_enable_tx_dual_eth()) { -            next_src_addr = (next_src_addr + 1) % mb.eth_conns.size(); -        } - -        xports.send_sid = this->allocate_sid(mb, address, xbar_src_addr, xbar_src_dst); -        xports.recv_sid = xports.send_sid.reversed(); - -        // Set size and number of frames -        default_buff_args.send_frame_size = std::min(send_mtu, -                x300::ETH_MSG_FRAME_SIZE); -        default_buff_args.recv_frame_size = std::min(recv_mtu, -                x300::ETH_MSG_FRAME_SIZE); -        // Buffering is done in the socket buffers, so size them relative to -        // the link rate -        default_buff_args.send_buff_size = conn.link_rate / 50; // 20ms -        default_buff_args.recv_buff_size = std::max(conn.link_rate / 50, -            x300::ETH_MSG_NUM_FRAMES -                * x300::ETH_MSG_FRAME_SIZE); // enough to hold greater of 20ms or number -                                             // of msg frames -        // There is no need for more than 1 send and recv frame since the -        // buffering is done in the socket buffers -        default_buff_args.num_send_frames = 1; -        default_buff_args.num_recv_frames = 1; -        if (xport_type == CTRL) { -            // Increasing number of recv frames here because ctrl_iface uses it -            // to determine how many control packets can be in flight before it -            // must wait for an ACK -            default_buff_args.num_recv_frames = -                uhd::rfnoc::CMD_FIFO_SIZE / uhd::rfnoc::MAX_CMD_PKT_SIZE; -        } else if (xport_type == TX_DATA) { -            size_t default_frame_size = conn.link_rate == x300::MAX_RATE_1GIGE -                                            ? x300::GE_DATA_FRAME_SEND_SIZE -                                            : x300::XGE_DATA_FRAME_SEND_SIZE; -            default_buff_args.send_frame_size = -                args.cast<size_t>("send_frame_size", -                std::min(default_frame_size, send_mtu)); -            default_buff_args.num_send_frames = -                args.cast<size_t>("num_send_frames", -                default_buff_args.num_send_frames); -            default_buff_args.send_buff_size = -                args.cast<size_t>("send_buff_size", -                default_buff_args.send_buff_size); -        } else if (xport_type == RX_DATA) { -            size_t default_frame_size = conn.link_rate == x300::MAX_RATE_1GIGE -                                            ? x300::GE_DATA_FRAME_RECV_SIZE -                                            : x300::XGE_DATA_FRAME_RECV_SIZE; -            default_buff_args.recv_frame_size = -                args.cast<size_t>("recv_frame_size", -                std::min(default_frame_size, recv_mtu)); -            // set some buffers so the offload thread actually offloads the -            // socket I/O -            default_buff_args.num_recv_frames = -                args.cast<size_t>("num_recv_frames", 2); -            default_buff_args.recv_buff_size = -                args.cast<size_t>("recv_buff_size", -                default_buff_args.recv_buff_size); -        } -        // make a new transport - fpga has no idea how to talk to us on this yet -        udp_zero_copy::buff_params buff_params; -        xports.recv = udp_zero_copy::make(conn.addr, -            BOOST_STRINGIZE(X300_VITA_UDP_PORT), -            default_buff_args, -            buff_params); - -        // Create a threaded transport for the receive chain only -        // Note that this shouldn't affect PCIe -        if (xport_type == RX_DATA) { -            xports.recv = zero_copy_recv_offload::make( -                xports.recv, x300::RECV_OFFLOAD_BUFFER_TIMEOUT); -        } -        xports.send = xports.recv; - -        // For the UDP transport the buffer size is the size of the socket buffer -        // in the kernel -        xports.recv_buff_size = buff_params.recv_buff_size; -        xports.send_buff_size = buff_params.send_buff_size; - -        // clear the ethernet dispatcher's udp port -        // NOT clearing this, the dispatcher is now intelligent -        //_zpu_ctrl->poke32(SR_ADDR(SET0_BASE, (ZPU_SR_ETHINT0+8+3)), 0); - -        // send a mini packet with SID into the ZPU -        // ZPU will reprogram the ethernet framer -        UHD_LOGGER_DEBUG("X300") << "programming packet for new xport on " << conn.addr -                                 << " sid " << xports.send_sid; -        // YES, get a __send__ buffer from the __recv__ socket -        //-- this is the only way to program the framer for recv: -        managed_send_buffer::sptr buff = xports.recv->get_send_buff(); -        buff->cast<uint32_t*>()[0]     = 0; // eth dispatch looks for != 0 -        buff->cast<uint32_t*>()[1]     = uhd::htonx(xports.send_sid.get()); -        buff->commit(8); -        buff.reset(); - -        // reprogram the ethernet dispatcher's udp port (should be safe to always set) -        UHD_LOGGER_TRACE("X300") << "reprogram the ethernet dispatcher's udp port"; -        mb.zpu_ctrl->poke32( -            SR_ADDR(SET0_BASE, (ZPU_SR_ETHINT0 + 8 + 3)), X300_VITA_UDP_PORT); -        mb.zpu_ctrl->poke32( -            SR_ADDR(SET0_BASE, (ZPU_SR_ETHINT1 + 8 + 3)), X300_VITA_UDP_PORT); - -        // Do a peek to an arbitrary address to guarantee that the -        // ethernet framer has been programmed before we return. -        mb.zpu_ctrl->peek32(0); +        return xports;      } -    return xports; +    UHD_THROW_INVALID_CODE_PATH();  } @@ -1719,177 +813,20 @@ bool x300_impl::is_pps_present(mboard_members_t& mb)  }  /*********************************************************************** - * claimer logic - **********************************************************************/ - -void x300_impl::claimer_loop(wb_iface::sptr iface) -{ -    claim(iface); -    std::this_thread::sleep_for(std::chrono::seconds(1)); -} - -x300_impl::claim_status_t x300_impl::claim_status(wb_iface::sptr iface) -{ -    claim_status_t claim_status = CLAIMED_BY_OTHER; // Default to most restrictive -    auto timeout_time = std::chrono::steady_clock::now() + std::chrono::seconds(1); -    while (std::chrono::steady_clock::now() < timeout_time) { -        // If timed out, then device is definitely unclaimed -        if (iface->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_STATUS)) == 0) { -            claim_status = UNCLAIMED; -            break; -        } - -        // otherwise check claim src to determine if another thread with the same src has -        // claimed the device -        uint32_t hash = iface->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_SRC)); -        if (hash == 0) { -            // A non-zero claim status and an empty hash means the claim might -            // be in the process of being released.  This is possible because -            // older firmware takes a long time to update the status.  Wait and -            // check status again. -            std::this_thread::sleep_for(std::chrono::milliseconds(5)); -            continue; -        } -        claim_status = (hash == get_process_hash() ? CLAIMED_BY_US : CLAIMED_BY_OTHER); -        break; -    } -    return claim_status; -} - -void x300_impl::claim(wb_iface::sptr iface) -{ -    iface->poke32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_TIME), uint32_t(time(NULL))); -    iface->poke32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_SRC), get_process_hash()); -} - -bool x300_impl::try_to_claim(wb_iface::sptr iface, long timeout_ms) -{ -    const auto timeout_time = -        std::chrono::steady_clock::now() + std::chrono::milliseconds(timeout_ms); -    while (1) { -        claim_status_t status = claim_status(iface); -        if (status == UNCLAIMED) { -            claim(iface); -            // It takes the claimer 10ms to update status, so wait 20ms before verifying -            // claim -            std::this_thread::sleep_for(std::chrono::milliseconds(20)); -            continue; -        } -        if (status == CLAIMED_BY_US) { -            break; -        } -        if (std::chrono::steady_clock::now() > timeout_time) { -            // Another process owns the device - give up -            return false; -        } -        std::this_thread::sleep_for(std::chrono::milliseconds(100)); -    } -    return true; -} - -void x300_impl::release(wb_iface::sptr iface) -{ -    iface->poke32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_TIME), 0); -    iface->poke32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_SRC), 0); -} - -/***********************************************************************   * Frame size detection   **********************************************************************/ -x300_impl::frame_size_t x300_impl::determine_max_frame_size( -    const std::string& addr, const frame_size_t& user_frame_size) +size_t x300_impl::get_mtu(const size_t mb_index, const uhd::direction_t dir)  { -    udp_simple::sptr udp = -        _x300_make_udp_connected(addr, BOOST_STRINGIZE(X300_MTU_DETECT_UDP_PORT)); - -    std::vector<uint8_t> buffer( -        std::max(user_frame_size.recv_frame_size, user_frame_size.send_frame_size)); -    x300_mtu_t* request              = reinterpret_cast<x300_mtu_t*>(&buffer.front()); -    static const double echo_timeout = 0.020; // 20 ms - -    // test holler - check if its supported in this fw version -    request->flags = uhd::htonx<uint32_t>(X300_MTU_DETECT_ECHO_REQUEST); -    request->size  = uhd::htonx<uint32_t>(sizeof(x300_mtu_t)); -    udp->send(boost::asio::buffer(buffer, sizeof(x300_mtu_t))); -    udp->recv(boost::asio::buffer(buffer), echo_timeout); -    if (!(uhd::ntohx<uint32_t>(request->flags) & X300_MTU_DETECT_ECHO_REPLY)) -        throw uhd::not_implemented_error("Holler protocol not implemented"); - -    // Reducing range of (min,max) by setting max value to 10gig max_frame_size as larger -    // sizes are not supported -    size_t min_recv_frame_size = sizeof(x300_mtu_t); -    size_t max_recv_frame_size = -        std::min(user_frame_size.recv_frame_size, x300::DATA_FRAME_MAX_SIZE) & size_t(~3); -    size_t min_send_frame_size = sizeof(x300_mtu_t); -    size_t max_send_frame_size = -        std::min(user_frame_size.send_frame_size, x300::DATA_FRAME_MAX_SIZE) & size_t(~3); - -    UHD_LOGGER_DEBUG("X300") << "Determining maximum frame size... "; -    while (min_recv_frame_size < max_recv_frame_size) { -        size_t test_frame_size = (max_recv_frame_size / 2 + min_recv_frame_size / 2 + 3) -                                 & ~3; - -        request->flags = uhd::htonx<uint32_t>(X300_MTU_DETECT_ECHO_REQUEST); -        request->size  = uhd::htonx<uint32_t>(test_frame_size); -        udp->send(boost::asio::buffer(buffer, sizeof(x300_mtu_t))); - -        size_t len = udp->recv(boost::asio::buffer(buffer), echo_timeout); - -        if (len >= test_frame_size) -            min_recv_frame_size = test_frame_size; -        else -            max_recv_frame_size = test_frame_size - 4; -    } - -    if (min_recv_frame_size < IP_PROTOCOL_MIN_MTU_SIZE - IP_PROTOCOL_UDP_PLUS_IP_HEADER) { -        throw uhd::runtime_error("System receive MTU size is less than the minimum " -                                 "required by the IP protocol."); -    } - -    while (min_send_frame_size < max_send_frame_size) { -        size_t test_frame_size = (max_send_frame_size / 2 + min_send_frame_size / 2 + 3) -                                 & ~3; - -        request->flags = uhd::htonx<uint32_t>(X300_MTU_DETECT_ECHO_REQUEST); -        request->size  = uhd::htonx<uint32_t>(sizeof(x300_mtu_t)); -        udp->send(boost::asio::buffer(buffer, test_frame_size)); - -        size_t len = udp->recv(boost::asio::buffer(buffer), echo_timeout); -        if (len >= sizeof(x300_mtu_t)) -            len = uhd::ntohx<uint32_t>(request->size); - -        if (len >= test_frame_size) -            min_send_frame_size = test_frame_size; -        else -            max_send_frame_size = test_frame_size - 4; -    } - -    if (min_send_frame_size < IP_PROTOCOL_MIN_MTU_SIZE - IP_PROTOCOL_UDP_PLUS_IP_HEADER) { -        throw uhd::runtime_error( -            "System send MTU size is less than the minimum required by the IP protocol."); +    auto& mb = _mb.at(mb_index); +    if (mb.xport_path == xport_path_t::NIRIO) { +        return mb.pcie_mgr->get_mtu(dir);      } - -    frame_size_t frame_size; -    // There are cases when NICs accept oversized packets, in which case we'd falsely -    // detect a larger-than-possible frame size. A safe and sensible value is the minimum -    // of the recv and send frame sizes. -    frame_size.recv_frame_size = std::min(min_recv_frame_size, min_send_frame_size); -    frame_size.send_frame_size = std::min(min_recv_frame_size, min_send_frame_size); -    UHD_LOGGER_INFO("X300") << "Maximum frame size: " << frame_size.send_frame_size -                            << " bytes."; -    return frame_size; -} - -size_t x300_impl::get_mtu(const size_t /*mb_index*/, const uhd::direction_t dir) -{ -    return (dir == RX_DIRECTION) ? _max_frame_sizes.recv_frame_size : -                                   _max_frame_sizes.send_frame_size; +    return mb.eth_mgr->get_mtu(dir);  }  /***********************************************************************   * compat checks   **********************************************************************/ -  void x300_impl::check_fw_compat(const fs_path& mb_path, const mboard_members_t& members)  {      auto iface = members.zpu_ctrl; @@ -1901,10 +838,11 @@ void x300_impl::check_fw_compat(const fs_path& mb_path, const mboard_members_t&      if (compat_major != X300_FW_COMPAT_MAJOR) {          const std::string image_loader_path =              (fs::path(uhd::get_pkg_path()) / "bin" / "uhd_image_loader").string(); -        const std::string image_loader_cmd = -            str(boost::format("\"%s\" --args=\"type=x300,%s=%s\"") % image_loader_path -                % (members.xport_path == "eth" ? "addr" : "resource") -                % members.get_pri_eth().addr); +        const std::string image_loader_cmd = str( +            boost::format("\"%s\" --args=\"type=x300,%s=%s\"") % image_loader_path +            % (members.xport_path == xport_path_t::ETH ? "addr" : "resource") +            % (members.xport_path == xport_path_t::ETH ? members.args.get_first_addr() +                                                       : members.args.get_resource()));          throw uhd::runtime_error(              str(boost::format( @@ -1934,10 +872,11 @@ void x300_impl::check_fpga_compat(const fs_path& mb_path, const mboard_members_t      if (compat_major != X300_FPGA_COMPAT_MAJOR) {          std::string image_loader_path =              (fs::path(uhd::get_pkg_path()) / "bin" / "uhd_image_loader").string(); -        std::string image_loader_cmd = -            str(boost::format("\"%s\" --args=\"type=x300,%s=%s\"") % image_loader_path -                % (members.xport_path == "eth" ? "addr" : "resource") -                % members.get_pri_eth().addr); +        std::string image_loader_cmd = str( +            boost::format("\"%s\" --args=\"type=x300,%s=%s\"") % image_loader_path +            % (members.xport_path == xport_path_t::ETH ? "addr" : "resource") +            % (members.xport_path == xport_path_t::ETH ? members.args.get_first_addr() +                                                       : members.args.get_resource()));          throw uhd::runtime_error(              str(boost::format( @@ -1967,24 +906,3 @@ void x300_impl::check_fpga_compat(const fs_path& mb_path, const mboard_members_t                                 << " git hash: " << git_hash_str);  } -x300_mboard_t x300_impl::get_mb_type_from_pcie( -    const std::string& resource, const std::string& rpc_port) -{ -    // Detect the PCIe product ID to distinguish between X300 and X310 -    nirio_status status = NiRio_Status_Success; -    uint32_t pid; -    niriok_proxy::sptr discovery_proxy = -        niusrprio_session::create_kernel_proxy(resource, rpc_port); -    if (discovery_proxy) { -        nirio_status_chain( -            discovery_proxy->get_attribute(RIO_PRODUCT_NUMBER, pid), status); -        discovery_proxy->close(); -        if (nirio_status_not_fatal(status)) { -            return map_pid_to_mb_type(pid); -        } -    } - -    UHD_LOGGER_WARNING("X300") << "NI-RIO Error -- unable to determine motherboard type!"; -    return UNKNOWN; -} - | 
