aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp')
-rw-r--r--host/lib/usrp/device3/device3_io_impl.cpp68
-rw-r--r--host/lib/usrp/x300/x300_fw_ctrl.cpp2
-rw-r--r--host/lib/usrp/x300/x300_impl.cpp8
-rw-r--r--host/lib/usrp/x300/x300_impl.hpp21
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