From cff6aa8ff884a06e37a49d8a536be427b8398834 Mon Sep 17 00:00:00 2001 From: Mark Meserve Date: Tue, 6 Jun 2017 15:40:58 -0500 Subject: twinrx: add reimport lo mode --- git_build_info | 0 host/lib/usrp/dboard/twinrx/twinrx_ctrl.cpp | 4 ++-- host/lib/usrp/dboard/twinrx/twinrx_ctrl.hpp | 4 ++-- host/lib/usrp/dboard/twinrx/twinrx_experts.cpp | 29 +++++++++++++++----------- 4 files changed, 21 insertions(+), 16 deletions(-) create mode 100644 git_build_info diff --git a/git_build_info b/git_build_info new file mode 100644 index 000000000..e69de29bb diff --git a/host/lib/usrp/dboard/twinrx/twinrx_ctrl.cpp b/host/lib/usrp/dboard/twinrx/twinrx_ctrl.cpp index 346f39589..3bb5931bc 100644 --- a/host/lib/usrp/dboard/twinrx/twinrx_ctrl.cpp +++ b/host/lib/usrp/dboard/twinrx/twinrx_ctrl.cpp @@ -309,7 +309,7 @@ public: boost::lock_guard lock(_mutex); if (ch == CH1 or ch == BOTH) { _cpld_regs->rf1_reg5.set(rm::rf1_reg5_t::SW14_CTRL_CH2, bool2bin(source!=LO_COMPANION)); - _cpld_regs->rf1_reg1.set(rm::rf1_reg1_t::SW15_CTRL_CH1, bool2bin(source==LO_EXTERNAL)); + _cpld_regs->rf1_reg1.set(rm::rf1_reg1_t::SW15_CTRL_CH1, bool2bin(source==LO_EXTERNAL||source==LO_REIMPORT)); _cpld_regs->rf1_reg1.set(rm::rf1_reg1_t::SW16_CTRL_CH1, bool2bin(source!=LO_INTERNAL)); _lo1_src[size_t(CH1)] = source; } @@ -332,7 +332,7 @@ public: _lo2_src[size_t(CH1)] = source; } if (ch == CH2 or ch == BOTH) { - _cpld_regs->if0_reg4.set(rm::if0_reg4_t::SW19_CTRL_CH1, bool2bin(source==LO_EXTERNAL)); + _cpld_regs->if0_reg4.set(rm::if0_reg4_t::SW19_CTRL_CH1, bool2bin(source==LO_EXTERNAL||source==LO_REIMPORT)); _cpld_regs->if0_reg0.set(rm::if0_reg0_t::SW20_CTRL_CH2, bool2bin(source==LO_INTERNAL||source==LO_DISABLED)); _cpld_regs->if0_reg4.set(rm::if0_reg4_t::SW21_CTRL_CH2, bool2bin(source==LO_INTERNAL)); _lo2_src[size_t(CH2)] = source; diff --git a/host/lib/usrp/dboard/twinrx/twinrx_ctrl.hpp b/host/lib/usrp/dboard/twinrx/twinrx_ctrl.hpp index 5537d00ab..2439addc4 100644 --- a/host/lib/usrp/dboard/twinrx/twinrx_ctrl.hpp +++ b/host/lib/usrp/dboard/twinrx/twinrx_ctrl.hpp @@ -35,7 +35,7 @@ public: virtual ~twinrx_ctrl() {} - enum channel_t { CH1 = 0, CH2 = 1, BOTH = 2}; + enum channel_t { CH1 = 0, CH2 = 1, BOTH = 2 }; enum preamp_state_t { PREAMP_LOWBAND, PREAMP_HIGHBAND, PREAMP_BYPASS }; @@ -43,7 +43,7 @@ public: enum preselector_path_t { PRESEL_PATH1, PRESEL_PATH2, PRESEL_PATH3, PRESEL_PATH4 }; - enum lo_source_t { LO_INTERNAL, LO_EXTERNAL, LO_COMPANION, LO_DISABLED }; + enum lo_source_t { LO_INTERNAL, LO_EXTERNAL, LO_COMPANION, LO_DISABLED, LO_REIMPORT }; enum lo_export_source_t { LO_CH1_SYNTH, LO_CH2_SYNTH, LO_EXPORT_DISABLED }; diff --git a/host/lib/usrp/dboard/twinrx/twinrx_experts.cpp b/host/lib/usrp/dboard/twinrx/twinrx_experts.cpp index 3b41972da..f4a1b8ac4 100644 --- a/host/lib/usrp/dboard/twinrx/twinrx_experts.cpp +++ b/host/lib/usrp/dboard/twinrx/twinrx_experts.cpp @@ -308,17 +308,18 @@ void twinrx_lo_config_expert::resolve() ("internal", twinrx_ctrl::LO_INTERNAL) ("external", twinrx_ctrl::LO_EXTERNAL) ("companion", twinrx_ctrl::LO_COMPANION) - ("disabled", twinrx_ctrl::LO_DISABLED); + ("disabled", twinrx_ctrl::LO_DISABLED) + ("reimport", twinrx_ctrl::LO_REIMPORT); if (src_lookup.has_key(_lo_source_ch0)) { _lo1_src_ch0 = _lo2_src_ch0 = src_lookup[_lo_source_ch0]; } else { - throw uhd::value_error("Invalid LO source for channel 0.Choose from {internal, external, companion}"); + throw uhd::value_error("Invalid LO source for channel 0.Choose from {internal, external, companion, reimport}"); } if (src_lookup.has_key(_lo_source_ch1)) { _lo1_src_ch1 = _lo2_src_ch1 = src_lookup[_lo_source_ch1]; } else { - throw uhd::value_error("Invalid LO source for channel 1.Choose from {internal, external, companion}"); + throw uhd::value_error("Invalid LO source for channel 1.Choose from {internal, external, companion, reimport}"); } twinrx_ctrl::lo_export_source_t export_src = twinrx_ctrl::LO_EXPORT_DISABLED; @@ -328,14 +329,16 @@ void twinrx_lo_config_expert::resolve() if (_lo_export_ch1 and (_lo_source_ch1 == "external")) { throw uhd::value_error("Cannot export an external LO for channel 1"); } + + // Determine which channel will provide the exported LO if (_lo_export_ch0 and _lo_export_ch1) { throw uhd::value_error("Cannot export LOs for both channels"); } else if (_lo_export_ch0) { - export_src = (_lo1_src_ch0 == twinrx_ctrl::LO_INTERNAL) ? - twinrx_ctrl::LO_CH1_SYNTH : twinrx_ctrl::LO_CH2_SYNTH; - } else if (_lo_export_ch1) { - export_src = (_lo1_src_ch1 == twinrx_ctrl::LO_INTERNAL) ? + export_src = (_lo1_src_ch0 == twinrx_ctrl::LO_COMPANION) ? twinrx_ctrl::LO_CH2_SYNTH : twinrx_ctrl::LO_CH1_SYNTH; + } else if (_lo_export_ch1) { + export_src = (_lo1_src_ch1 == twinrx_ctrl::LO_COMPANION) ? + twinrx_ctrl::LO_CH1_SYNTH : twinrx_ctrl::LO_CH2_SYNTH; } _lo1_export_src = _lo2_export_src = export_src; } @@ -350,14 +353,16 @@ void twinrx_lo_mapping_expert::resolve() static const size_t CH1_MSK = 0x2; // Determine which channels are "driving" each synthesizer - // First check for explicit requests i.e. lo_source "internal" or "companion" + // First check for explicit requests + // "internal" or "reimport" -> this channel + // "companion" -> other channel size_t synth_map[] = {0, 0}; - if (_lox_src_ch0 == twinrx_ctrl::LO_INTERNAL) { + if (_lox_src_ch0 == twinrx_ctrl::LO_INTERNAL or _lox_src_ch0 == twinrx_ctrl::LO_REIMPORT) { synth_map[0] = synth_map[0] | CH0_MSK; } else if (_lox_src_ch0 == twinrx_ctrl::LO_COMPANION) { synth_map[1] = synth_map[1] | CH0_MSK; } - if (_lox_src_ch1 == twinrx_ctrl::LO_INTERNAL) { + if (_lox_src_ch1 == twinrx_ctrl::LO_INTERNAL or _lox_src_ch1 == twinrx_ctrl::LO_REIMPORT) { synth_map[1] = synth_map[1] | CH1_MSK; } else if (_lox_src_ch1 == twinrx_ctrl::LO_COMPANION) { synth_map[0] = synth_map[0] | CH1_MSK; @@ -369,7 +374,7 @@ void twinrx_lo_mapping_expert::resolve() // to overlap tuning with signal dwell time. bool hopping_enabled = false; if (_lox_src_ch0 == twinrx_ctrl::LO_DISABLED) { - if (_lox_src_ch1 == twinrx_ctrl::LO_INTERNAL) { + if (_lox_src_ch1 == twinrx_ctrl::LO_INTERNAL or _lox_src_ch1 == twinrx_ctrl::LO_REIMPORT) { synth_map[0] = synth_map[0] | CH0_MSK; hopping_enabled = true; } else if (_lox_src_ch1 == twinrx_ctrl::LO_COMPANION) { @@ -378,7 +383,7 @@ void twinrx_lo_mapping_expert::resolve() } } if (_lox_src_ch1 == twinrx_ctrl::LO_DISABLED) { - if (_lox_src_ch0 == twinrx_ctrl::LO_INTERNAL) { + if (_lox_src_ch0 == twinrx_ctrl::LO_INTERNAL or _lox_src_ch0 == twinrx_ctrl::LO_REIMPORT) { synth_map[1] = synth_map[1] | CH1_MSK; hopping_enabled = true; } else if (_lox_src_ch0 == twinrx_ctrl::LO_COMPANION) { -- cgit v1.2.3 From 6ec8c4c04d473db6ca0cb7d5fe4babccbf25c2c6 Mon Sep 17 00:00:00 2001 From: Mark Meserve Date: Tue, 6 Jun 2017 15:59:39 -0500 Subject: twinrx: remove committed build artifact --- git_build_info | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 git_build_info diff --git a/git_build_info b/git_build_info deleted file mode 100644 index e69de29bb..000000000 -- cgit v1.2.3 From 84f3f9e0db94adfca5ee2d7e31bace9af34d6303 Mon Sep 17 00:00:00 2001 From: Mark Meserve Date: Thu, 8 Jun 2017 11:00:26 -0500 Subject: twinrx: add reimport to LO options on property tree --- host/lib/usrp/dboard/db_twinrx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/lib/usrp/dboard/db_twinrx.cpp b/host/lib/usrp/dboard/db_twinrx.cpp index 2af6bc4ff..20adbf849 100644 --- a/host/lib/usrp/dboard/db_twinrx.cpp +++ b/host/lib/usrp/dboard/db_twinrx.cpp @@ -112,7 +112,7 @@ public: "los/LO2/freq/value", prepend_ch("los/LO2/freq/desired", _ch_name), prepend_ch("los/LO2/freq/coerced", _ch_name), 0.0, AUTO_RESOLVE_ON_READ_WRITE); get_rx_subtree()->create >("los/all/source/options") - .set(boost::assign::list_of("internal")("external")("companion")("disabled")); + .set(boost::assign::list_of("internal")("external")("companion")("disabled")("reimport")); expert_factory::add_prop_node(_expert, get_rx_subtree(), "los/all/source/value", prepend_ch("los/all/source", _ch_name), "internal", AUTO_RESOLVE_ON_WRITE); -- cgit v1.2.3 From 2f7f873b7f0299ec1f8ae7c752246cb2f1608c0a Mon Sep 17 00:00:00 2001 From: Michael West Date: Wed, 29 Mar 2017 13:24:32 -0700 Subject: X300: Dual channel TX performance improvements --- host/lib/rfnoc/legacy_compat.cpp | 32 +++- host/lib/usrp/common/async_packet_handler.hpp | 6 +- host/lib/usrp/device3/device3_impl.hpp | 3 +- host/lib/usrp/device3/device3_io_impl.cpp | 218 +++++++++++++------------- host/lib/usrp/x300/x300_impl.cpp | 14 +- host/lib/usrp/x300/x300_impl.hpp | 2 + 6 files changed, 157 insertions(+), 118 deletions(-) diff --git a/host/lib/rfnoc/legacy_compat.cpp b/host/lib/rfnoc/legacy_compat.cpp index 7acaa898c..bf653a89a 100644 --- a/host/lib/rfnoc/legacy_compat.cpp +++ b/host/lib/rfnoc/legacy_compat.cpp @@ -45,6 +45,7 @@ using uhd::stream_cmd_t; ***********************************************************************/ static const std::string RADIO_BLOCK_NAME = "Radio"; static const std::string DFIFO_BLOCK_NAME = "DmaFIFO"; +static const std::string SFIFO_BLOCK_NAME = "FIFO"; static const std::string DDC_BLOCK_NAME = "DDC"; static const std::string DUC_BLOCK_NAME = "DUC"; static const size_t MAX_BYTES_PER_HEADER = @@ -131,6 +132,7 @@ public: _has_ducs(not args.has_key("skip_duc") and not device->find_blocks(DUC_BLOCK_NAME).empty()), _has_ddcs(not args.has_key("skip_ddc") and not device->find_blocks(DDC_BLOCK_NAME).empty()), _has_dmafifo(not args.has_key("skip_dram") and not device->find_blocks(DFIFO_BLOCK_NAME).empty()), + _has_sramfifo(not args.has_key("skip_sram") and not device->find_blocks(SFIFO_BLOCK_NAME).empty()), _num_mboards(_tree->list("/mboards").size()), _num_radios_per_board(device->find_blocks("0/Radio").size()), // These might throw, maybe we catch that and provide a nicer error message. _num_tx_chans_per_radio( @@ -165,8 +167,12 @@ public: } if (args.has_key("skip_dram")) { UHD_LEGACY_LOG() << "[legacy_compat] Skipping DRAM by user request." << std::endl; - } else if (not _has_dmafifo) { - UHD_MSG(warning) << "[legacy_compat] No DMA FIFO detected. You will only be able to transmit at slow rates." << std::endl; + } + if (args.has_key("skip_sram")) { + UHD_LEGACY_LOG() << "[legacy_compat] Skipping SRAM by user request." << std::endl; + } + if (not _has_dmafifo and not _has_sramfifo) { + UHD_MSG(warning) << "[legacy_compat] No FIFO detected. Higher transmit rates may encounter errors." << std::endl; } for (size_t mboard = 0; mboard < _num_mboards; mboard++) { @@ -522,7 +528,9 @@ private: // methods size_t &port_index ) { if (dir == uhd::TX_DIRECTION) { - if (_has_dmafifo) { + if (_has_sramfifo) { + return block_id_t(mboard_idx, SFIFO_BLOCK_NAME, radio_index).to_string(); + } else if (_has_dmafifo) { port_index = radio_index; return block_id_t(mboard_idx, DFIFO_BLOCK_NAME, 0).to_string(); } else { @@ -736,7 +744,15 @@ private: // methods block_id_t(mboard, RADIO_BLOCK_NAME, radio), chan, tx_bpp ); - if (_has_dmafifo) { + // Prioritize SRAM over DRAM for performance + if (_has_sramfifo) { + // We have SRAM FIFO *and* DUCs + _graph->connect( + block_id_t(mboard, SFIFO_BLOCK_NAME, radio), chan, + block_id_t(mboard, DUC_BLOCK_NAME, radio), chan, + tx_bpp + ); + } else if (_has_dmafifo) { // We have DMA FIFO *and* DUCs _graph->connect( block_id_t(mboard, DFIFO_BLOCK_NAME, 0), radio, @@ -744,6 +760,13 @@ private: // methods tx_bpp ); } + } else if (_has_sramfifo) { + // We have SRAM FIFO, *no* DUCs + _graph->connect( + block_id_t(mboard, SFIFO_BLOCK_NAME, radio), radio, + block_id_t(mboard, RADIO_BLOCK_NAME, radio), chan, + tx_bpp + ); } else if (_has_dmafifo) { // We have DMA FIFO, *no* DUCs _graph->connect( @@ -843,6 +866,7 @@ private: // attributes const bool _has_ducs; const bool _has_ddcs; const bool _has_dmafifo; + const bool _has_sramfifo; const size_t _num_mboards; const size_t _num_radios_per_board; const size_t _num_tx_chans_per_radio; diff --git a/host/lib/usrp/common/async_packet_handler.hpp b/host/lib/usrp/common/async_packet_handler.hpp index 20409c77a..4b162677b 100644 --- a/host/lib/usrp/common/async_packet_handler.hpp +++ b/host/lib/usrp/common/async_packet_handler.hpp @@ -40,7 +40,11 @@ namespace uhd{ namespace usrp{ //load into metadata metadata.channel = channel; metadata.has_time_spec = if_packet_info.has_tsf; - metadata.time_spec = time_spec_t::from_ticks(if_packet_info.tsf, tick_rate); + if (tick_rate == 0.0) { + metadata.time_spec = 0.0; + } else { + metadata.time_spec = time_spec_t::from_ticks(if_packet_info.tsf, tick_rate); + } metadata.event_code = async_metadata_t::event_code_t(to_host(payload[0]) & 0xff); //load user payload diff --git a/host/lib/usrp/device3/device3_impl.hpp b/host/lib/usrp/device3/device3_impl.hpp index 117e4af1c..22c93f25f 100644 --- a/host/lib/usrp/device3/device3_impl.hpp +++ b/host/lib/usrp/device3/device3_impl.hpp @@ -57,7 +57,8 @@ public: enum xport_type_t { CTRL = 0, TX_DATA, - RX_DATA + RX_DATA, + ASYNC_TX_MSG }; enum xport_t {AXI, ETH, PCIE}; diff --git a/host/lib/usrp/device3/device3_io_impl.cpp b/host/lib/usrp/device3/device3_io_impl.cpp index 199cb2786..dc4aacff8 100644 --- a/host/lib/usrp/device3/device3_io_impl.cpp +++ b/host/lib/usrp/device3/device3_io_impl.cpp @@ -298,23 +298,17 @@ static void handle_rx_flowctrl( /*********************************************************************** * TX Flow Control Functions **********************************************************************/ +#define DEVICE3_ASYNC_EVENT_CODE_FLOW_CTRL 0 + //! Stores the state of TX flow control struct tx_fc_cache_t { - tx_fc_cache_t(void): - stream_channel(0), - device_channel(0), - last_seq_out(0), + tx_fc_cache_t(size_t capacity): last_seq_ack(0), - last_seq_ack_cache(0) {} + space(capacity) {} - size_t stream_channel; - size_t device_channel; - size_t last_seq_out; - boost::atomic_size_t last_seq_ack; - size_t last_seq_ack_cache; - boost::shared_ptr async_queue; - boost::shared_ptr old_async_queue; + size_t last_seq_ack; + size_t space; }; /*! Return the size of the flow control window in packets. @@ -340,79 +334,74 @@ static size_t get_tx_flow_control_window( return window_in_pkts; } -// 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, - const double timeout -){ - return xport->get_send_buff(timeout); -} - static bool tx_flow_ctrl( - task::sptr /*holds ref*/, boost::shared_ptr fc_cache, - size_t fc_window, + zero_copy_if::sptr async_xport, + uint32_t (*endian_conv)(uint32_t), + void (*unpack)(const uint32_t *packet_buff, vrt::if_packet_info_t &), managed_buffer::sptr ) { - bool refresh_cache = false; - - // 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) { - if (refresh_cache) - { - // update the cached value from the atomic - fc_cache->last_seq_ack_cache = fc_cache->last_seq_ack; - } - - // 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_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) + // If there is space + if (fc_cache->space) { - // Packet will be sent - fc_cache->last_seq_out++; //update seq + // All is good - packet will be sent + fc_cache->space--; return true; } - else - { - if (refresh_cache) - { - // We have already refreshed the cache and still - // lack flow control permission to send new data. - - // A true busy loop choked out the message handler - // thread on machines with processor limitations - // (too few cores). Yield to allow flow control - // receiver thread to operate. - boost::this_thread::yield(); - } - else - { - // Allow the cache to refresh and try again to - // see if the device has granted flow control permission. - refresh_cache = true; - } - } + + // Look for a flow control message to update the space available in the buffer. + // A minimal timeout is used because larger timeouts can cause the thread to be + // scheduled out for too long at high data rates and result in underruns. + managed_recv_buffer::sptr buff = async_xport->get_recv_buff(0.000001); + if (buff) + { + vrt::if_packet_info_t if_packet_info; + if_packet_info.num_packet_words32 = buff->size()/sizeof(uint32_t); + const uint32_t *packet_buff = buff->cast(); + try { + unpack(packet_buff, if_packet_info); + } + catch(const std::exception &ex) + { + UHD_MSG(error) << "Error unpacking async flow control packet: " << ex.what() << std::endl; + continue; + } + + if (if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_FC) + { + UHD_MSG(error) << "Unexpected packet type received by flow control handler: " << if_packet_info.packet_type << std::endl; + continue; + } + + // update the amount of space + size_t seq_ack = endian_conv(packet_buff[if_packet_info.num_header_words32+1]); + fc_cache->space += (seq_ack - fc_cache->last_seq_ack) & HW_SEQ_NUM_MASK; + fc_cache->last_seq_ack = seq_ack; + } } return false; } -#define DEVICE3_ASYNC_EVENT_CODE_FLOW_CTRL 0 -/*! Handle incoming messages. If they're flow control, update the TX FC cache. - * Otherwise, send them to the async message queue for the user to poll. +/*********************************************************************** + * TX Async Message Functions + **********************************************************************/ +struct async_tx_info_t +{ + size_t stream_channel; + size_t device_channel; + boost::shared_ptr async_queue; + boost::shared_ptr old_async_queue; +}; + +/*! Handle incoming messages. + * Send them to the async message queue for the user to poll. * * This is run inside a uhd::task as long as this streamer lives. */ static void handle_tx_async_msgs( - boost::shared_ptr fc_cache, + boost::shared_ptr async_info, zero_copy_if::sptr xport, endianness_t endianness, boost::function get_tick_rate @@ -462,31 +451,21 @@ static void handle_tx_async_msgs( if_packet_info, packet_buff, tick_rate, - fc_cache->stream_channel + async_info->stream_channel ); - // TODO: Shouldn't we be polling if_packet_info.packet_type == PACKET_TYPE_FC? - // Thing is, on X300, packet_type == 0, so that wouldn't work. But it seems it should. - //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) { - fc_cache->last_seq_ack = metadata.user_payload[0]; - } - - //FC responses don't propagate up to the user so filter them here - if (metadata.event_code != DEVICE3_ASYNC_EVENT_CODE_FLOW_CTRL) { - fc_cache->async_queue->push_with_pop_on_full(metadata); - metadata.channel = fc_cache->device_channel; - fc_cache->old_async_queue->push_with_pop_on_full(metadata); + // Filter out any flow control messages and cache the rest + if (metadata.event_code == DEVICE3_ASYNC_EVENT_CODE_FLOW_CTRL) + { + UHD_MSG(error) << "Unexpected flow control message found in async message handling" << std::endl; + } else { + async_info->async_queue->push_with_pop_on_full(metadata); + metadata.channel = async_info->device_channel; + async_info->old_async_queue->push_with_pop_on_full(metadata); standard_async_msg_prints(metadata); } } - - -/*********************************************************************** - * Async Data - **********************************************************************/ bool device3_impl::recv_async_msg( async_metadata_t &async_metadata, double timeout ) @@ -726,6 +705,20 @@ void device3_impl::update_tx_streamers(double /* rate */) } } +// This class manages the lifetime of the TX async message handler task and transports +class device3_send_packet_streamer : public sph::send_packet_streamer +{ +public: + device3_send_packet_streamer(const size_t max_num_samps) : sph::send_packet_streamer(max_num_samps) {}; + ~device3_send_packet_streamer() { + _tx_async_msg_task.reset(); // Make sure the async task is destroyed before the transports + }; + + both_xports_t _xport; + both_xports_t _async_xport; + task::sptr _tx_async_msg_task; +}; + tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_) { boost::mutex::scoped_lock lock(_transport_setup_mutex); @@ -741,7 +734,7 @@ tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_) boost::shared_ptr async_md(new async_md_type(1000/*messages deep*/)); // II. Iterate over all channels - boost::shared_ptr my_streamer; + boost::shared_ptr my_streamer; // The terminator's lifetime is coupled to the streamer. // There is only one terminator. If the streamer has multiple channels, // it will be connected to each downstream block. @@ -753,6 +746,7 @@ tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_) args.args = chan_args[stream_i]; size_t mb_index = block_id.get_device_no(); size_t suggested_block_port = args.args.cast("block_port", rfnoc::ANY_PORT); + uhd::endianness_t endianness = get_transport_endianness(mb_index); // Access to this channel's block control uhd::rfnoc::sink_block_ctrl_base::sptr blk_ctrl = @@ -779,6 +773,7 @@ tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_) uhd::sid_t stream_address = blk_ctrl->get_address(block_port); UHD_STREAMER_LOG() << "[TX Streamer] creating tx stream " << tx_hints.to_string() << std::endl; both_xports_t xport = make_transport(stream_address, TX_DATA, tx_hints); + both_xports_t async_xport = make_transport(stream_address, ASYNC_TX_MSG, device_addr_t("")); UHD_STREAMER_LOG() << std::hex << "[TX Streamer] data_sid = " << xport.send_sid << std::dec << std::endl; // To calculate the max number of samples per packet, we assume the maximum header length @@ -790,8 +785,10 @@ tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_) //make the new streamer given the samples per packet if (not my_streamer) - my_streamer = boost::make_shared(spp); + my_streamer = boost::make_shared(spp); my_streamer->resize(chan_list.size()); + my_streamer->_xport = xport; + my_streamer->_async_xport = async_xport; //init some streamer stuff std::string conv_endianness; @@ -827,29 +824,30 @@ tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_) block_port ); - boost::shared_ptr fc_cache(new tx_fc_cache_t()); - fc_cache->stream_channel = stream_i; - fc_cache->device_channel = mb_index; - fc_cache->async_queue = async_md; - fc_cache->old_async_queue = _async_md; + boost::shared_ptr async_tx_info(new async_tx_info_t()); + async_tx_info->stream_channel = args.channels[stream_i]; + async_tx_info->device_channel = mb_index; + async_tx_info->async_queue = async_md; + async_tx_info->old_async_queue = _async_md; boost::function tick_rate_retriever = boost::bind( &rfnoc::tick_node_ctrl::get_tick_rate, send_terminator, std::set< rfnoc::node_ctrl_base::sptr >() // Need to specify default args with bind ); - task::sptr task = task::make( + + my_streamer->_tx_async_msg_task = task::make( boost::bind( &handle_tx_async_msgs, - fc_cache, - xport.recv, - get_transport_endianness(mb_index), + async_tx_info, + my_streamer->_async_xport.recv, + endianness, tick_rate_retriever ) ); blk_ctrl->sr_write(uhd::rfnoc::SR_CLEAR_RX_FC, 0xc1ea12, block_port); - blk_ctrl->sr_write(uhd::rfnoc::SR_RESP_IN_DST_SID, xport.recv_sid.get_dst(), block_port); + blk_ctrl->sr_write(uhd::rfnoc::SR_RESP_IN_DST_SID, my_streamer->_async_xport.recv_sid.get_dst(), block_port); UHD_STREAMER_LOG() << "[TX Streamer] resp_in_dst_sid == " << boost::format("0x%04X") % xport.recv_sid.get_dst() << std::endl; // FIXME: Once there is a better way to map the radio block and port @@ -864,7 +862,7 @@ tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_) UHD_STREAMER_LOG() << "[TX Streamer] Number of downstream radio nodes: " << downstream_radio_nodes.size() << std::endl; BOOST_FOREACH(const boost::shared_ptr &node, downstream_radio_nodes) { if (node->get_block_id() == radio_id) { - node->sr_write(uhd::rfnoc::SR_RESP_IN_DST_SID, xport.send_sid.get_src(), radio_port); + node->sr_write(uhd::rfnoc::SR_RESP_IN_DST_SID, my_streamer->_async_xport.recv_sid.get_dst(), radio_port); } } } else { @@ -877,23 +875,27 @@ tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_) std::vector > downstream_radio_nodes = blk_ctrl->find_downstream_node(); UHD_STREAMER_LOG() << "[TX Streamer] Number of downstream radio nodes: " << downstream_radio_nodes.size() << std::endl; BOOST_FOREACH(const boost::shared_ptr &node, downstream_radio_nodes) { - node->sr_write(uhd::rfnoc::SR_RESP_IN_DST_SID, xport.send_sid.get_src(), block_port); + node->sr_write(uhd::rfnoc::SR_RESP_IN_DST_SID, my_streamer->_async_xport.recv_sid.get_dst(), block_port); } } // Add flow control - xport.send = zero_copy_flow_ctrl::make( - xport.send, - boost::bind(&tx_flow_ctrl, task, fc_cache, fc_window, _1), + boost::shared_ptr fc_cache(new tx_fc_cache_t(fc_window)); + my_streamer->_xport.send = zero_copy_flow_ctrl::make( + my_streamer->_xport.send, + boost::bind( + &tx_flow_ctrl, + fc_cache, + my_streamer->_xport.recv, + (endianness == ENDIANNESS_BIG ? uhd::ntohx : uhd::wtohx), + (endianness == ENDIANNESS_BIG ? vrt::chdr::if_hdr_unpack_be : vrt::chdr::if_hdr_unpack_le), + _1), NULL); //Give the streamer a functor to get the send buffer - //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, xport.send, _1) + boost::bind(&zero_copy_if::get_send_buff, my_streamer->_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_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 4f3870357..934e2eaa5 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -511,6 +511,8 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_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 (dev_addr.has_key("second_addr")) { std::string eth1_addr = dev_addr["second_addr"]; @@ -1136,12 +1138,16 @@ uhd::both_xports_t x300_impl::make_transport( } else if (mb.xport_path == "eth") { // Decide on the IP/Interface pair based on the endpoint index - std::string interface_addr = mb.eth_conns[mb.next_src_addr].addr; + 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; + std::string interface_addr = mb.eth_conns[next_src_addr].addr; const uint32_t xbar_src_addr = - mb.next_src_addr==0 ? X300_SRC_ADDR0 : X300_SRC_ADDR1; + next_src_addr==0 ? X300_SRC_ADDR0 : X300_SRC_ADDR1; const uint32_t xbar_src_dst = - mb.eth_conns[mb.next_src_addr].type==X300_IFACE_ETH0 ? X300_XB_DST_E0 : X300_XB_DST_E1; - mb.next_src_addr = (mb.next_src_addr + 1) % mb.eth_conns.size(); + 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(); xports.send_sid = this->allocate_sid(mb, address, xbar_src_addr, xbar_src_dst); xports.recv_sid = xports.send_sid.reversed(); diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index 14120bd1f..8f4f81156 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -162,6 +162,8 @@ private: std::vector eth_conns; size_t next_src_addr; + size_t next_tx_src_addr; + size_t next_rx_src_addr; // Discover the ethernet connections per motherboard void discover_eth(const uhd::usrp::mboard_eeprom_t mb_eeprom, -- cgit v1.2.3 From 0b403340c3e924b642ba72679a8a1bfa23bbfd4c Mon Sep 17 00:00:00 2001 From: Michael West Date: Wed, 14 Jun 2017 10:22:25 -0700 Subject: X300: Implement single DMA channel for all async messages --- host/lib/usrp/device3/device3_impl.hpp | 4 +-- host/lib/usrp/device3/device3_io_impl.cpp | 2 +- host/lib/usrp/x300/x300_impl.cpp | 49 ++++++++++++++++++++++++------- host/lib/usrp/x300/x300_impl.hpp | 5 +++- 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/host/lib/usrp/device3/device3_impl.hpp b/host/lib/usrp/device3/device3_impl.hpp index 22c93f25f..043379108 100644 --- a/host/lib/usrp/device3/device3_impl.hpp +++ b/host/lib/usrp/device3/device3_impl.hpp @@ -56,9 +56,9 @@ public: //! The purpose of a transport enum xport_type_t { CTRL = 0, + ASYNC_MSG, TX_DATA, - RX_DATA, - ASYNC_TX_MSG + RX_DATA }; enum xport_t {AXI, ETH, PCIE}; diff --git a/host/lib/usrp/device3/device3_io_impl.cpp b/host/lib/usrp/device3/device3_io_impl.cpp index dc4aacff8..198ee4022 100644 --- a/host/lib/usrp/device3/device3_io_impl.cpp +++ b/host/lib/usrp/device3/device3_io_impl.cpp @@ -773,7 +773,7 @@ tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_) uhd::sid_t stream_address = blk_ctrl->get_address(block_port); UHD_STREAMER_LOG() << "[TX Streamer] creating tx stream " << tx_hints.to_string() << std::endl; both_xports_t xport = make_transport(stream_address, TX_DATA, tx_hints); - both_xports_t async_xport = make_transport(stream_address, ASYNC_TX_MSG, device_addr_t("")); + both_xports_t async_xport = make_transport(stream_address, ASYNC_MSG, device_addr_t("")); UHD_STREAMER_LOG() << std::hex << "[TX Streamer] data_sid = " << xport.send_sid << std::dec << std::endl; // To calculate the max number of samples per packet, we assume the maximum header length diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 934e2eaa5..71cb7f341 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -1039,9 +1039,12 @@ 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 FIRST_DATA_CHANNEL = 1; + 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(); @@ -1063,6 +1066,24 @@ static uint32_t extract_sid_from_pkt(void* pkt, size_t) { return uhd::sid_t(uhd::wtohx(static_cast(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 * max_muxed_ports; + buff_args.num_recv_frames = X300_PCIE_MSG_NUM_FRAMES * max_muxed_ports; + + 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, @@ -1084,19 +1105,25 @@ uhd::both_xports_t x300_impl::make_transport( if (not mb.ctrl_dma_xport) { //One underlying DMA channel will handle //all control traffic - zero_copy_xport_params ctrl_buff_args; - ctrl_buff_args.send_frame_size = X300_PCIE_MSG_FRAME_SIZE; - ctrl_buff_args.recv_frame_size = X300_PCIE_MSG_FRAME_SIZE; - ctrl_buff_args.num_send_frames = X300_PCIE_MSG_NUM_FRAMES * X300_PCIE_MAX_MUXED_XPORTS; - ctrl_buff_args.num_recv_frames = X300_PCIE_MSG_NUM_FRAMES * X300_PCIE_MAX_MUXED_XPORTS; - - zero_copy_if::sptr base_xport = nirio_zero_copy::make( - mb.rio_fpga_interface, dma_channel_num, - ctrl_buff_args, uhd::device_addr_t()); - mb.ctrl_dma_xport = muxed_zero_copy_if::make(base_xport, extract_sid_from_pkt, X300_PCIE_MAX_MUXED_XPORTS); + 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 { //Transport for data stream default_buff_args.send_frame_size = diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index 8f4f81156..982369396 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -62,7 +62,8 @@ 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_PCIE_MAX_MUXED_CTRL_XPORTS = 32; +static const size_t X300_PCIE_MAX_MUXED_ASYNC_XPORTS = 4; 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 @@ -205,6 +206,8 @@ private: std::map _dma_chan_pool; //! Control transport for one PCIe connection uhd::transport::muxed_zero_copy_if::sptr ctrl_dma_xport; + //! Async message transport + uhd::transport::muxed_zero_copy_if::sptr async_msg_dma_xport; /*! Allocate or return a previously allocated PCIe channel pair * -- cgit v1.2.3 From e1b686318fab1cb2b11542c28d82d810d1fc63a2 Mon Sep 17 00:00:00 2001 From: michael-west Date: Mon, 8 May 2017 11:48:45 -0700 Subject: X300: Fix DAC sync --- host/lib/usrp/x300/x300_adc_dac_utils.cpp | 47 ----------------------------- host/lib/usrp/x300/x300_radio_ctrl_impl.cpp | 20 ++++++++---- 2 files changed, 14 insertions(+), 53 deletions(-) diff --git a/host/lib/usrp/x300/x300_adc_dac_utils.cpp b/host/lib/usrp/x300/x300_adc_dac_utils.cpp index 6fd0ca50b..a6815286e 100644 --- a/host/lib/usrp/x300/x300_adc_dac_utils.cpp +++ b/host/lib/usrp/x300/x300_adc_dac_utils.cpp @@ -20,53 +20,6 @@ using namespace uhd::usrp::x300; -/*********************************************************************** - * DAC: Reset and synchronization operations - **********************************************************************/ - -void x300_impl::synchronize_dacs(const std::vector& radios) -{ - if (radios.size() < 2) return; //Nothing to synchronize - - //**PRECONDITION** - //This function assumes that all the VITA times in "radios" are synchronized - //to a common reference. Currently, this function is called in get_tx_stream - //which also has the same precondition. - - //Reinitialize and resync all DACs - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->dac->reset(); - } - - //Get a rough estimate of the cumulative command latency - boost::posix_time::ptime t_start = boost::posix_time::microsec_clock::local_time(); - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->ctrl->peek64(uhd::usrp::radio::RB64_TIME_NOW); //Discard value. We are just timing the call - } - boost::posix_time::time_duration t_elapsed = - boost::posix_time::microsec_clock::local_time() - t_start; - - //Add 100% of headroom + uncertaintly to the command time - uint64_t t_sync_us = (t_elapsed.total_microseconds() * 2) + 13000 /*Scheduler latency*/; - - //Pick radios[0] as the time reference. - uhd::time_spec_t sync_time = - radios[0]->time64->get_time_now() + uhd::time_spec_t(((double)t_sync_us)/1e6); - - //Send the sync command - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->ctrl->set_time(sync_time); - radios[i]->ctrl->poke32(uhd::usrp::radio::sr_addr(uhd::usrp::radio::DACSYNC), 0x1); //Arm FRAMEP/N sync pulse - radios[i]->ctrl->set_time(uhd::time_spec_t(0.0)); //Clear command time - } - - //Wait and check status - boost::this_thread::sleep(boost::posix_time::microseconds(t_sync_us)); - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->dac->verify_sync(); - } -} - /*********************************************************************** * ADC: Self-test operations **********************************************************************/ diff --git a/host/lib/usrp/x300/x300_radio_ctrl_impl.cpp b/host/lib/usrp/x300/x300_radio_ctrl_impl.cpp index 69eb51f55..a3bc2e691 100644 --- a/host/lib/usrp/x300/x300_radio_ctrl_impl.cpp +++ b/host/lib/usrp/x300/x300_radio_ctrl_impl.cpp @@ -608,8 +608,14 @@ void x300_radio_ctrl_impl::synchronize_dacs(const std::vectorset_command_tick_rate(radios[i]->_radio_clk_rate, IO_MASTER_RADIO); + radios[i]->_regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::DAC_SYNC, 0); + } + + //Add 100% of headroom + uncertainty to the command time + uint64_t t_sync_us = (t_elapsed.total_microseconds() * 2) + 16000 /*Scheduler latency*/; //Pick radios[0] as the time reference. uhd::time_spec_t sync_time = @@ -617,15 +623,17 @@ void x300_radio_ctrl_impl::synchronize_dacs(const std::vectorset_command_tick_rate(radios[i]->_radio_clk_rate, IO_MASTER_RADIO); - radios[i]->_regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_SYNC, 0); radios[i]->set_command_time(sync_time, IO_MASTER_RADIO); //Arm FRAMEP/N sync pulse by asserting a rising edge - radios[i]->_regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_SYNC, 1); - radios[i]->_regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_SYNC, 0); + radios[i]->_regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::DAC_SYNC, 1); radios[i]->set_command_time(uhd::time_spec_t(0.0), IO_MASTER_RADIO); } + //Reset FRAMEP/N to 0 + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->_regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::DAC_SYNC, 0); + } + //Wait and check status boost::this_thread::sleep(boost::posix_time::microseconds(t_sync_us)); for (size_t i = 0; i < radios.size(); i++) { -- cgit v1.2.3 From f0b328360d6a89c2541463feaf90589e5848f5b9 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Mon, 26 Jun 2017 13:29:23 -0700 Subject: Revert "xcvr: Query ref clock, not ADC/DAC clock" This reverts commit 60920644aa33d1a6f7a4dac30bdb890b9bc4301f. --- host/lib/usrp/dboard/db_xcvr2450.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp index 6876ee4be..ee69dbdad 100644 --- a/host/lib/usrp/dboard/db_xcvr2450.cpp +++ b/host/lib/usrp/dboard/db_xcvr2450.cpp @@ -371,7 +371,7 @@ double xcvr2450::set_lo_freq_core(double target_freq){ //variables used in the calculation below double scaler = xcvr2450::is_highband(target_freq)? (4.0/5.0) : (4.0/3.0); - double ref_freq = this->get_iface()->get_clock_rate(dboard_iface::UNIT_TX); + double ref_freq = this->get_iface()->get_codec_rate(dboard_iface::UNIT_TX); int R, intdiv = 131, fracdiv = 0; //loop through values until we get a match -- cgit v1.2.3 From d869f940146f074abf166f21cf066120b697149e Mon Sep 17 00:00:00 2001 From: Marcus Müller Date: Tue, 27 Jun 2017 11:39:48 +0200 Subject: Fix: field was bool, but needs to take values -1;1 --- host/utils/latency/include/Responder.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/host/utils/latency/include/Responder.hpp b/host/utils/latency/include/Responder.hpp index a9f616a24..31dcbc16b 100644 --- a/host/utils/latency/include/Responder.hpp +++ b/host/utils/latency/include/Responder.hpp @@ -88,8 +88,8 @@ class Responder bool combine_eob; bool pause; bool realtime; - bool invert; - bool output_value; + float invert; + float output_value; bool no_delay; bool allow_late_bursts; -- cgit v1.2.3 From 24db48766dff45b8fe8ed3031e09617ca92b84b6 Mon Sep 17 00:00:00 2001 From: michael-west Date: Tue, 23 May 2017 10:27:11 -0700 Subject: E300: Modify e300_poll_waiter to reduce minimum timeout and fix race condition --- host/lib/usrp/e300/e300_fifo_config.cpp | 38 +++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/host/lib/usrp/e300/e300_fifo_config.cpp b/host/lib/usrp/e300/e300_fifo_config.cpp index 4138bb581..43d14aa65 100644 --- a/host/lib/usrp/e300/e300_fifo_config.cpp +++ b/host/lib/usrp/e300/e300_fifo_config.cpp @@ -95,36 +95,44 @@ static UHD_INLINE size_t ZF_STREAM_OFF(const size_t which) struct e300_fifo_poll_waiter { e300_fifo_poll_waiter(const int fd): - fd(fd) + _fd(fd), + _poll_claimed(false) { //NOP } void wait(const double timeout) { - if (_poll_claimed.cas(1, 0)) + if (timeout == 0) { + return; + } + + boost::mutex::scoped_lock l(_mutex); + if (_poll_claimed) { - boost::mutex::scoped_lock l(mutex); - cond.wait(l); + _cond.timed_wait(l, boost::posix_time::microseconds(timeout*1000000)); } else { + _poll_claimed = true; + l.unlock(); struct pollfd fds[1]; - fds[0].fd = fd; + fds[0].fd = _fd; fds[0].events = POLLIN; ::poll(fds, 1, long(timeout*1000)); if (fds[0].revents & POLLIN) - ::read(fd, NULL, 0); + ::read(_fd, NULL, 0); - _poll_claimed.write(0); - cond.notify_all(); + l.lock(); + _poll_claimed = 0; + _cond.notify_all(); } } - uhd::atomic_uint32_t _poll_claimed; - boost::condition_variable cond; - boost::mutex mutex; - int fd; + boost::condition_variable _cond; + boost::mutex _mutex; + int _fd; + bool _poll_claimed; }; static const size_t DEFAULT_FRAME_SIZE = 2048; @@ -236,7 +244,7 @@ public: UHD_INLINE typename T::sptr get_buff(const double timeout) { const time_spec_t exit_time = time_spec_t::get_system_time() + time_spec_t(timeout); - do + while (1) { if (zf_peek32(_addrs.ctrl + ARBITER_RB_STATUS_OCC)) { @@ -248,10 +256,12 @@ public: _index = 0; return _buffs[_index++]->get_new(); } + if (time_spec_t::get_system_time() > exit_time) { + break; + } _waiter->wait(timeout); //boost::this_thread::sleep(boost::posix_time::milliseconds(1)); } - while (time_spec_t::get_system_time() < exit_time); return typename T::sptr(); } -- cgit v1.2.3