diff options
| -rw-r--r-- | firmware/microblaze/apps/txrx_uhd.c | 2 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/fw_common.h | 2 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/io_impl.cpp | 103 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/mboard_impl.cpp | 14 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.cpp | 4 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 7 | 
6 files changed, 110 insertions, 22 deletions
| diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index 1dd6e80ac..e38eb621d 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -372,7 +372,7 @@ eth_pkt_inspector(dbsm_t *sm, int bufno)    // In the future, a hardware state machine will do this...    if ( //warning! magic numbers approaching....        (((buff + ((2 + 14 + 20)/sizeof(uint32_t)))[0] & 0xffff) == USRP2_UDP_DATA_PORT) && -      ((buff + ((2 + 14 + 20 + 8)/sizeof(uint32_t)))[0] != USRP2_INVALID_VRT_HEADER) +      ((buff + ((2 + 14 + 20 + 8)/sizeof(uint32_t)))[1] != USRP2_INVALID_VRT_HEADER)    ) return false;    //test if its an ip recovery packet diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index e812e1221..783e5c772 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -34,7 +34,7 @@ extern "C" {  //fpga and firmware compatibility numbers  #define USRP2_FPGA_COMPAT_NUM 2 -#define USRP2_FW_COMPAT_NUM 6 +#define USRP2_FW_COMPAT_NUM 7  //used to differentiate control packets over data port  #define USRP2_INVALID_VRT_HEADER 0 diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index b7585afe9..6d5eb488c 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -32,6 +32,9 @@ using namespace uhd::usrp;  using namespace uhd::transport;  namespace asio = boost::asio; +/*********************************************************************** + * constants + **********************************************************************/  static const int underflow_flags = 0      | async_metadata_t::EVENT_CODE_UNDERFLOW      | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET @@ -40,6 +43,67 @@ static const int underflow_flags = 0  static const size_t vrt_send_header_offset_words32 = 1;  /*********************************************************************** + * flow control monitor for a single tx channel + *  - the pirate thread calls update + *  - the get send buffer calls check + **********************************************************************/ +class flow_control_monitor{ +public: +    typedef boost::shared_ptr<flow_control_monitor> sptr; + +    /*! +     * Make a new flow control monitor. +     * \param max_seqs_out num seqs before throttling +     */ +    flow_control_monitor(size_t max_seqs_out){ +        _last_seq_out = 0; +        _last_seq_ack = 0; +        _max_seqs_out = max_seqs_out; +    } + +    /*! +     * Check the flow control condition. +     * \param seq the sequence to go out +     * \param timeout the timeout in seconds +     * \return false on timeout +     */ +    UHD_INLINE bool check_fc_condition(boost::uint16_t seq, double timeout){ +        boost::unique_lock<boost::mutex> lock(_fc_mutex); +        _last_seq_out = seq; +        return _fc_cond.timed_wait( +            lock, +            boost::posix_time::microseconds(long(timeout*1e6)), +            boost::bind(&flow_control_monitor::ready, this) +        ); +    } + +    /*! +     * Update the flow control condition. +     * \param seq the last sequence number to be ACK'd +     */ +    UHD_INLINE void update_fc_condition(boost::uint16_t seq){ +        boost::unique_lock<boost::mutex> lock(_fc_mutex); +        _last_seq_ack = seq; +        lock.unlock(); +        _fc_cond.notify_one(); +    } + +private: +    bool ready(void){ +        //return true; +        //std::cout << "_last_seq_out " << _last_seq_out << std::endl; +        //std::cout << "_last_seq_ack " << _last_seq_ack << std::endl; +        //std::cout << "boost::uint16_t(_last_seq_out -_last_seq_ack) " << boost::uint16_t(_last_seq_out -_last_seq_ack) << std::endl; +        return boost::uint16_t(_last_seq_out -_last_seq_ack) < boost::uint16_t(_max_seqs_out); +    } + +    boost::mutex _fc_mutex; +    boost::condition _fc_cond; +    boost::uint16_t _last_seq_out, _last_seq_ack; +    size_t _max_seqs_out; +}; + +/***********************************************************************   * io impl details (internal to this file)   * - pirate crew   * - alignment buffer @@ -49,12 +113,14 @@ static const size_t vrt_send_header_offset_words32 = 1;  struct usrp2_impl::io_impl{      typedef alignment_buffer<managed_recv_buffer::sptr, time_spec_t> alignment_buffer_type; -    io_impl(size_t num_frames, size_t width): +    io_impl(size_t num_recv_frames, size_t send_frame_size, size_t width):          packet_handler_recv_state(width), -        recv_pirate_booty(alignment_buffer_type::make(num_frames, width)), +        recv_pirate_booty(alignment_buffer_type::make(num_recv_frames, width)),          async_msg_fifo(bounded_buffer<async_metadata_t>::make(100/*messages deep*/))      { -        /* NOP */ +        for (size_t i = 0; i < width; i++) fc_mons.push_back( +            flow_control_monitor::sptr(new flow_control_monitor(usrp2_impl::sram_bytes/send_frame_size)) +        );      }      ~io_impl(void){ @@ -76,19 +142,22 @@ struct usrp2_impl::io_impl{          UHD_ASSERT_THROW(trans.size() == buffs.size());          //calculate the 16-bit sequence number for the special header -        const boost::uint32_t next_seq = uhd::htonx(boost::uint32_t( -            packet_handler_send_state.next_packet_seq & 0xffff -        )); +        const boost::uint16_t seq_num = boost::uint16_t(packet_handler_send_state.next_packet_seq & 0xffff); +        const boost::uint32_t fc_word32 = uhd::htonx(boost::uint32_t(seq_num));          //grab a managed buffer for each index          for (size_t i = 0; i < buffs.size(); i++){ +            if (not fc_mons[i]->check_fc_condition(seq_num, timeout)) return false;              buffs[i] = trans[i]->get_send_buff(timeout);              if (not buffs[i].get()) return false; -            buffs[i]->cast<boost::uint32_t *>()[0] = next_seq; +            buffs[i]->cast<boost::uint32_t *>()[0] = fc_word32;          }          return true;      } +    //flow control monitors +    std::vector<flow_control_monitor::sptr> fc_mons; +      //state management for the vrt packet handler code      vrt_packet_handler::recv_state packet_handler_recv_state;      vrt_packet_handler::send_state packet_handler_send_state; @@ -138,6 +207,13 @@ void usrp2_impl::io_impl::recv_pirate_loop(                  );                  metadata.event_code = vrt_packet_handler::get_context_code<async_metadata_t::event_code_t>(vrt_hdr, if_packet_info); +                //catch the flow control packets and react +                if (metadata.event_code == 0){ +                    boost::uint32_t fc_word32 = uhd::ntohx((vrt_hdr + if_packet_info.num_header_words32)[1]); +                    this->fc_mons[index]->update_fc_condition(fc_word32 & 0xffff); +                    continue; +                } +                  //print the famous U, and push the metadata into the message queue                  if (metadata.event_code & underflow_flags) std::cerr << "U" << std::flush;                  async_msg_fifo->push_with_pop_on_full(metadata); @@ -172,21 +248,22 @@ void usrp2_impl::io_init(void){      //send a small data packet so the usrp2 knows the udp source port      BOOST_FOREACH(zero_copy_if::sptr data_transport, _data_transports){          managed_send_buffer::sptr send_buff = data_transport->get_send_buff(); -        static const boost::uint32_t data = uhd::htonx( -            boost::uint32_t(USRP2_INVALID_VRT_HEADER) -        ); +        static const boost::uint32_t data[2] = { +            uhd::htonx(boost::uint32_t(0 /* don't care seq num */)), +            uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER)) +        };          std::memcpy(send_buff->cast<void*>(), &data, sizeof(data));          send_buff->commit(sizeof(data));          //drain the recv buffers (may have junk)          while (data_transport->get_recv_buff().get()){};      } -    //the number of recv frames is the number for the first transport      //the assumption is that all data transports should be identical -    size_t num_frames = _data_transports.front()->get_num_recv_frames(); +    const size_t num_recv_frames = _data_transports.front()->get_num_recv_frames(); +    const size_t send_frame_size = _data_transports.front()->get_send_frame_size();      //create new io impl -    _io_impl = UHD_PIMPL_MAKE(io_impl, (num_frames, _data_transports.size())); +    _io_impl = UHD_PIMPL_MAKE(io_impl, (num_recv_frames, send_frame_size, _data_transports.size()));      //create a new pirate thread for each zc if (yarr!!)      for (size_t i = 0; i < _data_transports.size(); i++){ diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index a0e6adfad..37e69b39d 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -38,10 +38,11 @@ using namespace uhd::usrp;  usrp2_mboard_impl::usrp2_mboard_impl(      size_t index,      transport::udp_simple::sptr ctrl_transport, -    size_t recv_frame_size +    size_t recv_samps_per_packet, +    size_t send_bytes_per_packet  ):      _index(index), -    _recv_frame_size(recv_frame_size) +    _recv_samps_per_packet(recv_samps_per_packet)  {      //make a new interface for usrp2 stuff      _iface = usrp2_iface::make(ctrl_transport); @@ -75,7 +76,7 @@ usrp2_mboard_impl::usrp2_mboard_impl(      this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);      //init the rx control registers -    _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _recv_frame_size); +    _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _recv_samps_per_packet);      _iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1);      _iface->poke32(U2_REG_RX_CTRL_CLEAR_OVERRUN, 1); //reset      _iface->poke32(U2_REG_RX_CTRL_VRT_HEADER, 0 @@ -93,6 +94,11 @@ usrp2_mboard_impl::usrp2_mboard_impl(      _iface->poke32(U2_REG_TX_CTRL_CLEAR_STATE, 1); //reset      _iface->poke32(U2_REG_TX_CTRL_REPORT_SID, 1);  //sid 1 (different from rx)      _iface->poke32(U2_REG_TX_CTRL_POLICY, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET); +    const size_t cycles_per_ack = size_t(_clock_ctrl->get_master_clock_rate()/100); //100 aps +    //_iface->poke32(U2_REG_TX_CTRL_CYCLES_PER_ACK, U2_FLAG_TX_CTRL_ACK_ENB | cycles_per_ack); //FIXME total pause frames +    static const double sram_frac = 1.0/8.0; //fraction of sram to fill before ack +    const size_t packets_per_ack = size_t(usrp2_impl::sram_bytes*sram_frac/send_bytes_per_packet); +    _iface->poke32(U2_REG_TX_CTRL_PACKETS_PER_ACK, U2_FLAG_TX_CTRL_ACK_ENB | packets_per_ack);      //init the ddc      init_ddc_config(); @@ -178,7 +184,7 @@ void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){  void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){      _iface->poke32(U2_REG_RX_CTRL_STREAM_CMD, dsp_type1::calc_stream_cmd_word( -        stream_cmd, _recv_frame_size +        stream_cmd, _recv_samps_per_packet      ));      _iface->poke32(U2_REG_RX_CTRL_TIME_SECS,  boost::uint32_t(stream_cmd.time_spec.get_full_secs()));      _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_tick_count(get_master_clock_freq())); diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 8429a2593..79bf2b260 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -173,7 +173,9 @@ usrp2_impl::usrp2_impl(      //create a new mboard handler for each control transport      for(size_t i = 0; i < ctrl_transports.size(); i++){          _mboards.push_back(usrp2_mboard_impl::sptr(new usrp2_mboard_impl( -            i, ctrl_transports[i], this->get_max_recv_samps_per_packet() +            i, ctrl_transports[i], +            this->get_max_recv_samps_per_packet(), +            _data_transports[i]->get_send_frame_size()          )));          //use an empty name when there is only one mboard          std::string name = (ctrl_transports.size() > 1)? boost::lexical_cast<std::string>(i) : ""; diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 6d35e925d..2077b0a50 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -84,7 +84,8 @@ public:      usrp2_mboard_impl(          size_t index,          uhd::transport::udp_simple::sptr, -        size_t recv_frame_size +        size_t recv_samps_per_packet, +        size_t send_bytes_per_packet      );      ~usrp2_mboard_impl(void); @@ -95,7 +96,7 @@ public:  private:      size_t _index;      int _rev_hi, _rev_lo; -    const size_t _recv_frame_size; +    const size_t _recv_samps_per_packet;      //properties for this mboard      void get(const wax::obj &, wax::obj &); @@ -171,6 +172,8 @@ private:   */  class usrp2_impl : public uhd::device{  public: +    static const size_t sram_bytes = size_t(1 << 20); +      /*!       * Create a new usrp2 impl base.       * \param ctrl_transports the udp transports for control | 
