aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/x300/x300_impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/x300/x300_impl.cpp')
-rw-r--r--host/lib/usrp/x300/x300_impl.cpp1218
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;
-}
-