diff options
Diffstat (limited to 'host/lib/usrp/x300/x300_impl.cpp')
| -rw-r--r-- | host/lib/usrp/x300/x300_impl.cpp | 347 | 
1 files changed, 177 insertions, 170 deletions
| diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 60be75f2b..d0915d592 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -473,8 +473,10 @@ void x300_impl::mboard_members_t::discover_eth(                  // 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;              } @@ -492,15 +494,19 @@ void x300_impl::mboard_members_t::discover_eth(              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 " @@ -624,91 +630,6 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)          if (key.find("send") != std::string::npos) mb.send_args[key] = dev_addr[key];      } -    if (mb.xport_path == "eth" ) { -        /* 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 PIC'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_10GE_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_10GE_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.recv_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." -            ; -        } - -        _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(X300_MAX_RATE_10GIGE); -    } -      //create basic communication      UHD_LOGGER_DEBUG("X300") << "Setting up basic communication...";      if (mb.xport_path == "nirio") { @@ -828,11 +749,129 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)      _tree->create<std::string>(mb_path / "codename").set("Yetti");      //////////////////////////////////////////////////////////////////// -    // determine routing based on address match +    // discover ethernet interfaces, frame sizes, and link rates      //////////////////////////////////////////////////////////////////// -    if (mb.xport_path != "nirio") { +    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_1GE_DATA_FRAME_SEND_SIZE : X300_10GE_DATA_FRAME_SEND_SIZE; +            size_t rec_recv_frame_size = conn.link_rate == X300_MAX_RATE_1GIGE ? X300_1GE_DATA_FRAME_RECV_SIZE : X300_10GE_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);      }      //////////////////////////////////////////////////////////////////// @@ -1264,97 +1303,66 @@ uhd::both_xports_t x300_impl::make_transport(              xport_type == TX_DATA ? mb.next_tx_src_addr :              xport_type == RX_DATA ? mb.next_rx_src_addr :              mb.next_src_addr; -        std::string interface_addr = mb.eth_conns[next_src_addr].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 = -            mb.eth_conns[next_src_addr].type==X300_IFACE_ETH0 ? X300_XB_DST_E0 : X300_XB_DST_E1; -        next_src_addr = (next_src_addr + 1) % mb.eth_conns.size(); +            conn.type==X300_IFACE_ETH0 ? X300_XB_DST_E0 : X300_XB_DST_E1; +        if (xport_type != TX_DATA) 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(); -        /* Determine what the recommended frame size is for this -         * connection type.*/ -        size_t eth_data_rec_frame_size = 0; - -        fs_path mboard_path = fs_path("/mboards") / mb_index / "link_max_rate"; - -        if (mb.loaded_fpga_image == "HG") { -            size_t max_link_rate = 0; -            if (xbar_src_dst == X300_XB_DST_E0) { -                eth_data_rec_frame_size = X300_1GE_DATA_FRAME_MAX_SIZE; -                max_link_rate += X300_MAX_RATE_1GIGE; -            } else if (xbar_src_dst == X300_XB_DST_E1) { -                eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE; -                max_link_rate += X300_MAX_RATE_10GIGE; +        // Set size and number of frames +        size_t system_max_send_frame_size = (size_t) _max_frame_sizes.send_frame_size; +        size_t system_max_recv_frame_size = (size_t) _max_frame_sizes.recv_frame_size; +        default_buff_args.send_frame_size = std::min(system_max_send_frame_size, X300_ETH_MSG_FRAME_SIZE); +        default_buff_args.recv_frame_size = std::min(system_max_recv_frame_size, X300_ETH_MSG_FRAME_SIZE); +        default_buff_args.num_send_frames = 1;  // never need multiple frames on send +        default_buff_args.num_recv_frames = 1;  // only need multiple frames with offload thread +        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 +        if (xport_type == TX_DATA)  +        { +            size_t default_frame_size = conn.link_rate == X300_MAX_RATE_1GIGE ? X300_1GE_DATA_FRAME_SEND_SIZE : X300_10GE_DATA_FRAME_SEND_SIZE; +            default_buff_args.send_frame_size = args.cast<size_t>("send_frame_size", std::min(default_frame_size, system_max_send_frame_size)); +            if (default_buff_args.send_frame_size > system_max_send_frame_size) +            { +                UHD_LOGGER_WARNING("X300") +                        << boost::format("Requested send_frame_size of %d exceeds the maximum allowed on the %s connection.  Using %d.") +                        % default_buff_args.send_frame_size +                        % conn.addr +                        % system_max_send_frame_size +                        ; +                default_buff_args.send_frame_size = system_max_send_frame_size;              } -            _tree->access<double>(mboard_path).set(max_link_rate); -        } else if (mb.loaded_fpga_image == "XG" or mb.loaded_fpga_image == "XA") { -            eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE; -            size_t max_link_rate = X300_MAX_RATE_10GIGE; -            max_link_rate *= mb.eth_conns.size(); -            _tree->access<double>(mboard_path).set(max_link_rate); -        } else if (mb.loaded_fpga_image == "HA") { -            eth_data_rec_frame_size = X300_1GE_DATA_FRAME_MAX_SIZE; -            size_t max_link_rate = X300_MAX_RATE_1GIGE; -            max_link_rate *= mb.eth_conns.size(); -            _tree->access<double>(mboard_path).set(max_link_rate); -        } - -        if (eth_data_rec_frame_size == 0) { -            throw uhd::runtime_error("Unable to determine ETH link type.");          } +        else if (xport_type == RX_DATA)  +        { +            size_t default_frame_size = conn.link_rate == X300_MAX_RATE_1GIGE ? X300_1GE_DATA_FRAME_RECV_SIZE : X300_10GE_DATA_FRAME_RECV_SIZE; +            default_buff_args.recv_frame_size = args.cast<size_t>("recv_frame_size", std::min(default_frame_size, system_max_recv_frame_size)); +            if (default_buff_args.recv_frame_size > system_max_recv_frame_size) +            { +                UHD_LOGGER_WARNING("X300") +                        << boost::format("Requested recv_frame_size of %d exceeds the maximum allowed on the %s connection.  Using %d.") +                        % default_buff_args.recv_frame_size +                        % conn.addr +                        % system_max_recv_frame_size +                        ; +                default_buff_args.recv_frame_size = system_max_recv_frame_size; +            } +            // set default buffering for data +            default_buff_args.recv_buff_size = conn.link_rate / 10; // 100ms +            default_buff_args.num_recv_frames = 2;  // set some buffers so the offload thread actually offloads the socket I/O -        /* Print a warning if the system's max available frame size is less than the most optimal -         * frame size for this type of connection. */ -        if (_max_frame_sizes.send_frame_size < eth_data_rec_frame_size) { -            UHD_LOGGER_WARNING("X300") -                << boost::format("For this connection, UHD recommends a send frame size of at least %lu for best\nperformance, but your system's MTU will only allow %lu.") -                % eth_data_rec_frame_size -                % _max_frame_sizes.send_frame_size -                << "This may negatively impact your maximum achievable sample rate." -            ; +            // set buffering for flow control messages +            default_buff_args.num_send_frames = 1;          } -        if (_max_frame_sizes.recv_frame_size < eth_data_rec_frame_size) { -            UHD_LOGGER_WARNING("X300") -                << boost::format("For this connection, UHD recommends a receive frame size of at least %lu for best\nperformance, but your system's MTU will only allow %lu.") -                % eth_data_rec_frame_size -                % _max_frame_sizes.recv_frame_size -                << "This may negatively impact your maximum achievable sample rate." -            ; -        } - -        size_t system_max_send_frame_size = (size_t) _max_frame_sizes.send_frame_size; -        size_t system_max_recv_frame_size = (size_t) _max_frame_sizes.recv_frame_size; - -        // Make sure frame sizes do not exceed the max available value supported by UHD -        default_buff_args.send_frame_size = -            (xport_type == TX_DATA) -            ? std::min(system_max_send_frame_size, X300_10GE_DATA_FRAME_MAX_SIZE) -            : std::min(system_max_send_frame_size, X300_ETH_MSG_FRAME_SIZE); - -        default_buff_args.recv_frame_size = -            (xport_type == RX_DATA) -            ? std::min(system_max_recv_frame_size, X300_10GE_DATA_FRAME_MAX_SIZE) -            : std::min(system_max_recv_frame_size, X300_ETH_MSG_FRAME_SIZE); - -        default_buff_args.num_send_frames = -            (xport_type == TX_DATA) -            ? X300_ETH_DATA_NUM_FRAMES -            : X300_ETH_MSG_NUM_FRAMES; - -        default_buff_args.num_recv_frames = -            (xport_type == RX_DATA) -            ? X300_ETH_DATA_NUM_FRAMES -            : X300_ETH_MSG_NUM_FRAMES; -          //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( -                interface_addr, +                conn.addr,                  BOOST_STRINGIZE(X300_VITA_UDP_PORT),                  default_buff_args,                  buff_params, @@ -1365,12 +1373,12 @@ uhd::both_xports_t x300_impl::make_transport(          if (xport_type == RX_DATA) {              xports.recv = zero_copy_recv_offload::make(                      xports.recv, -                    X300_THREAD_BUFFER_TIMEOUT +                    X300_RECV_OFFLOAD_BUFFER_TIMEOUT              );          }          xports.send = xports.recv; -        //For the UDP transport the buffer size if the size of the socket buffer +        //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; @@ -1381,9 +1389,8 @@ uhd::both_xports_t x300_impl::make_transport(          //send a mini packet with SID into the ZPU          //ZPU will reprogram the ethernet framer -        UHD_LOGGER_TRACE("X300") -            << "programming packet for new xport on " -            << interface_addr <<  " sid " << xports.send_sid; +        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(); @@ -1691,9 +1698,9 @@ x300_impl::frame_size_t x300_impl::determine_max_frame_size(const std::string &a      //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_10GE_DATA_FRAME_MAX_SIZE) & size_t(~3); +    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_10GE_DATA_FRAME_MAX_SIZE) & size_t(~3); +    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) | 
