diff options
Diffstat (limited to 'host/lib/usrp')
| -rw-r--r-- | host/lib/usrp/device3/device3_io_impl.cpp | 68 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_fw_ctrl.cpp | 2 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_impl.cpp | 8 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_impl.hpp | 21 | 
4 files changed, 61 insertions, 38 deletions
diff --git a/host/lib/usrp/device3/device3_io_impl.cpp b/host/lib/usrp/device3/device3_io_impl.cpp index 8a42fe148..46cc0ee5a 100644 --- a/host/lib/usrp/device3/device3_io_impl.cpp +++ b/host/lib/usrp/device3/device3_io_impl.cpp @@ -31,6 +31,8 @@  #include "../../rfnoc/tx_stream_terminator.hpp"  #include <uhd/rfnoc/rate_node_ctrl.hpp>  #include <uhd/rfnoc/radio_ctrl.hpp> +#include <uhd/transport/zero_copy_flow_ctrl.hpp> +#include <boost/atomic.hpp>  #define UHD_TX_STREAMER_LOG() UHD_LOGGER_TRACE("STREAMER")  #define UHD_RX_STREAMER_LOG() UHD_LOGGER_TRACE("STREAMER") @@ -305,12 +307,13 @@ struct tx_fc_cache_t          device_channel(0),          last_seq_out(0),          last_seq_ack(0), -        seq_queue(1){} +        last_seq_ack_cache(0) {} +      size_t stream_channel;      size_t device_channel;      size_t last_seq_out; -    size_t last_seq_ack; -    uhd::transport::bounded_buffer<size_t> seq_queue; +    boost::atomic_size_t last_seq_ack; +    size_t last_seq_ack_cache;      boost::shared_ptr<device3_impl::async_md_type> async_queue;      boost::shared_ptr<device3_impl::async_md_type> old_async_queue;  }; @@ -338,33 +341,43 @@ static size_t get_tx_flow_control_window(      return window_in_pkts;  } -static managed_send_buffer::sptr get_tx_buff_with_flowctrl( -    task::sptr /*holds ref*/, -    boost::shared_ptr<tx_fc_cache_t> fc_cache, +// TODO: Remove this function +// This function only exists to make sure the transport is not destroyed +// until it is no longer needed. +static managed_send_buffer::sptr get_tx_buff(      zero_copy_if::sptr xport, -    size_t fc_window,      const double timeout  ){ +    return xport->get_send_buff(timeout); +} + +static bool tx_flow_ctrl( +    task::sptr /*holds ref*/, +    boost::shared_ptr<tx_fc_cache_t> fc_cache, +    size_t fc_window, +    managed_buffer::sptr +) { +    // Busy loop waiting for flow control update.  This is necessary because +    // at this point there is data trying to be sent and it must be sent as +    // quickly as possible when the flow control update arrives to avoid +    // underruns at high rates.  This is also OK because it only occurs when +    // data needs to be sent and flow control is holding it back.      while (true)      {          // delta is the amount of FC credit we've used up -        const size_t delta = (fc_cache->last_seq_out & HW_SEQ_NUM_MASK) - (fc_cache->last_seq_ack & HW_SEQ_NUM_MASK); +        const size_t delta = (fc_cache->last_seq_out & HW_SEQ_NUM_MASK) - +            (fc_cache->last_seq_ack_cache & HW_SEQ_NUM_MASK);          // If we want to send another packet, we must have FC credit left          if ((delta & HW_SEQ_NUM_MASK) < fc_window) -            break; - -        // If credit is all used up, we check seq_queue for more. -        const bool ok = fc_cache->seq_queue.pop_with_timed_wait(fc_cache->last_seq_ack, timeout); -        if (not ok) { -            return managed_send_buffer::sptr(); //timeout waiting for flow control +        { +            // Packet will be sent +            fc_cache->last_seq_out++; //update seq +            return true;          } +        // update the cached value from the atomic +        fc_cache->last_seq_ack_cache = fc_cache->last_seq_ack;      } - -    managed_send_buffer::sptr buff = xport->get_send_buff(timeout); -    if (buff) { -        fc_cache->last_seq_out++; //update seq, this will actually be a send -    } -    return buff; +    return false;  }  #define DEVICE3_ASYNC_EVENT_CODE_FLOW_CTRL 0 @@ -381,7 +394,9 @@ static void handle_tx_async_msgs(  ) {      managed_recv_buffer::sptr buff = xport->get_recv_buff();      if (not buff) +    {          return; +    }      //extract packet info      vrt::if_packet_info_t if_packet_info; @@ -430,8 +445,7 @@ static void handle_tx_async_msgs(      //The FC response and the burst ack are two indicators that the radio      //consumed packets. Use them to update the FC metadata      if (metadata.event_code == DEVICE3_ASYNC_EVENT_CODE_FLOW_CTRL) { -        const size_t seq = metadata.user_payload[0]; -        fc_cache->seq_queue.push_with_pop_on_full(seq); +        fc_cache->last_seq_ack = metadata.user_payload[0];      }      //FC responses don't propagate up to the user so filter them here @@ -842,13 +856,19 @@ tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_)              }          } +        // Add flow control +        xport.send = zero_copy_flow_ctrl::make( +            xport.send, +            boost::bind(&tx_flow_ctrl, task, fc_cache, fc_window, _1), +            NULL); +          //Give the streamer a functor to get the send buffer -        //get_tx_buff_with_flowctrl is static so bind has no lifetime issues +        //get_tx_buff is static so bind has no lifetime issues          //xport.send (sptr) is required to add streamer->data-transport lifetime dependency          //task (sptr) is required to add  a streamer->async-handler lifetime dependency          my_streamer->set_xport_chan_get_buff(              stream_i, -            boost::bind(&get_tx_buff_with_flowctrl, task, fc_cache, xport.send, fc_window, _1) +            boost::bind(&get_tx_buff, xport.send, _1)          );          //Give the streamer a functor handled received async messages          my_streamer->set_async_receiver( diff --git a/host/lib/usrp/x300/x300_fw_ctrl.cpp b/host/lib/usrp/x300/x300_fw_ctrl.cpp index 1df0fa611..5ff40c966 100644 --- a/host/lib/usrp/x300/x300_fw_ctrl.cpp +++ b/host/lib/usrp/x300/x300_fw_ctrl.cpp @@ -292,7 +292,7 @@ protected:  private:      niriok_proxy::sptr _drv_proxy; -    static const uint32_t READ_TIMEOUT_IN_MS = 10; +    static const uint32_t READ_TIMEOUT_IN_MS = 100;      static const uint32_t INIT_TIMEOUT_IN_MS = 5000;  }; diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 785f7b4a3..ac08cf565 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -1128,14 +1128,14 @@ uhd::both_xports_t x300_impl::make_transport(                  ? X300_PCIE_RX_DATA_FRAME_SIZE                  : X300_PCIE_MSG_FRAME_SIZE; -            default_buff_args.num_send_frames = -                (xport_type == TX_DATA) -                ? X300_PCIE_DATA_NUM_FRAMES +			default_buff_args.num_send_frames = +				(xport_type == TX_DATA) +                ? X300_PCIE_TX_DATA_NUM_FRAMES                  : X300_PCIE_MSG_NUM_FRAMES;              default_buff_args.num_recv_frames =                  (xport_type == RX_DATA) -                ? X300_PCIE_DATA_NUM_FRAMES +                ? X300_PCIE_RX_DATA_NUM_FRAMES                  : X300_PCIE_MSG_NUM_FRAMES;              xports.recv = nirio_zero_copy::make( diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index 2de295bd9..27f3f130e 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -52,15 +52,18 @@ static const size_t X300_RX_SW_BUFF_SIZE_ETH        = 0x2000000;//32MiB    For a  static const size_t X300_RX_SW_BUFF_SIZE_ETH_MACOS  = 0x100000; //1Mib  //The FIFO closest to the DMA controller is 1023 elements deep for RX and 1029 elements deep for TX -//where an element is 8 bytes. For best throughput ensure that the data frame fits in these buffers. -//Also ensure that the kernel has enough frames to hold buffered TX and RX data -static const size_t X300_PCIE_RX_DATA_FRAME_SIZE    = 8184;     //bytes -static const size_t X300_PCIE_TX_DATA_FRAME_SIZE    = 8184;     //bytes -static const size_t X300_PCIE_DATA_NUM_FRAMES       = 2048; -static const size_t X300_PCIE_MSG_FRAME_SIZE        = 256;      //bytes -static const size_t X300_PCIE_MSG_NUM_FRAMES        = 64; -static const size_t X300_PCIE_MAX_CHANNELS          = 6; -static const size_t X300_PCIE_MAX_MUXED_XPORTS      = 32; +//where an element is 8 bytes. The buffers (number of frames * frame size) must be aligned to the +//memory page size.  For the control, we are getting lucky because 64 frames * 256 bytes each aligns +//with the typical page size of 4096 bytes.  Since most page sizes are 4096 bytes or some multiple of +//that, keep the number of frames * frame size aligned to it. +static const size_t X300_PCIE_RX_DATA_FRAME_SIZE        = 4096;     //bytes +static const size_t X300_PCIE_RX_DATA_NUM_FRAMES        = 4096; +static const size_t X300_PCIE_TX_DATA_FRAME_SIZE        = 4096;     //bytes +static const size_t X300_PCIE_TX_DATA_NUM_FRAMES	    = 4096; +static const size_t X300_PCIE_MSG_FRAME_SIZE            = 256;      //bytes +static const size_t X300_PCIE_MSG_NUM_FRAMES            = 64; +static const size_t X300_PCIE_MAX_CHANNELS              = 6; +static const size_t X300_PCIE_MAX_MUXED_XPORTS          = 32;  static const size_t X300_10GE_DATA_FRAME_MAX_SIZE   = 8000;     // CHDR packet size in bytes  static const size_t X300_1GE_DATA_FRAME_MAX_SIZE    = 1472;     // CHDR packet size in bytes  | 
