diff options
Diffstat (limited to 'host/lib/usrp/x300')
-rw-r--r-- | host/lib/usrp/x300/CMakeLists.txt | 2 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_dboard_iface.cpp | 123 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_fw_common.h | 2 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_fw_ctrl.cpp | 35 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_impl.cpp | 435 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_impl.hpp | 72 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_io_impl.cpp | 27 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_regs.hpp | 6 |
8 files changed, 491 insertions, 211 deletions
diff --git a/host/lib/usrp/x300/CMakeLists.txt b/host/lib/usrp/x300/CMakeLists.txt index 3d6348eec..f8b129f89 100644 --- a/host/lib/usrp/x300/CMakeLists.txt +++ b/host/lib/usrp/x300/CMakeLists.txt @@ -22,8 +22,6 @@ ######################################################################## # Conditionally configure the X300 support ######################################################################## -LIBUHD_REGISTER_COMPONENT("X300" ENABLE_X300 ON "ENABLE_LIBUHD" OFF OFF) - IF(ENABLE_X300) LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/x300_impl.cpp diff --git a/host/lib/usrp/x300/x300_dboard_iface.cpp b/host/lib/usrp/x300/x300_dboard_iface.cpp index 502630109..87f537874 100644 --- a/host/lib/usrp/x300/x300_dboard_iface.cpp +++ b/host/lib/usrp/x300/x300_dboard_iface.cpp @@ -1,5 +1,5 @@ // -// Copyright 2013,2015 Ettus Research LLC +// Copyright 2013,2015,2016 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -45,17 +45,19 @@ public: void write_aux_dac(unit_t, aux_dac_t, double); double read_aux_adc(unit_t, aux_adc_t); - void _set_pin_ctrl(unit_t, boost::uint16_t); - void _set_atr_reg(unit_t, atr_reg_t, boost::uint16_t); - void _set_gpio_ddr(unit_t, boost::uint16_t); - void _set_gpio_out(unit_t, boost::uint16_t); + void set_pin_ctrl(unit_t unit, boost::uint32_t value, boost::uint32_t mask = 0xffffffff); + boost::uint32_t get_pin_ctrl(unit_t unit); + void set_atr_reg(unit_t unit, atr_reg_t reg, boost::uint32_t value, boost::uint32_t mask = 0xffffffff); + boost::uint32_t get_atr_reg(unit_t unit, atr_reg_t reg); + void set_gpio_ddr(unit_t unit, boost::uint32_t value, boost::uint32_t mask = 0xffffffff); + boost::uint32_t get_gpio_ddr(unit_t unit); + void set_gpio_out(unit_t unit, boost::uint32_t value, boost::uint32_t mask = 0xffffffff); + boost::uint32_t get_gpio_out(unit_t unit); + boost::uint32_t read_gpio(unit_t unit); void set_command_time(const uhd::time_spec_t& t); uhd::time_spec_t get_command_time(void); - void set_gpio_debug(unit_t, int); - boost::uint16_t read_gpio(unit_t); - void write_i2c(boost::uint16_t, const byte_vector_t &); byte_vector_t read_i2c(boost::uint16_t, size_t); @@ -78,6 +80,11 @@ public: boost::uint32_t data, size_t num_bits ); + void set_fe_connection( + unit_t unit, + const std::string& fe_name, + const fe_connection_t& fe_conn + ); const x300_dboard_iface_config_t _config; uhd::dict<unit_t, ad5623_regs_t> _dac_regs; @@ -116,27 +123,6 @@ x300_dboard_iface::x300_dboard_iface(const x300_dboard_iface_config_t &config): this->set_clock_enabled(UNIT_RX, false); this->set_clock_enabled(UNIT_TX, false); - - - //some test code - /* - { - - this->write_aux_dac(UNIT_TX, AUX_DAC_A, .1); - this->write_aux_dac(UNIT_TX, AUX_DAC_B, 1); - this->write_aux_dac(UNIT_RX, AUX_DAC_A, 2); - this->write_aux_dac(UNIT_RX, AUX_DAC_B, 3); - while (1) - { - UHD_VAR(this->read_aux_adc(UNIT_TX, AUX_ADC_A)); - UHD_VAR(this->read_aux_adc(UNIT_TX, AUX_ADC_B)); - UHD_VAR(this->read_aux_adc(UNIT_RX, AUX_ADC_A)); - UHD_VAR(this->read_aux_adc(UNIT_RX, AUX_ADC_B)); - sleep(1); - } - } - */ - } x300_dboard_iface::~x300_dboard_iface(void) @@ -153,6 +139,8 @@ x300_dboard_iface::~x300_dboard_iface(void) **********************************************************************/ void x300_dboard_iface::set_clock_rate(unit_t unit, double rate) { + if (unit == UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported."); + // Just return if the requested rate is already set if (std::fabs(_clock_rates[unit] - rate) < std::numeric_limits<double>::epsilon()) return; @@ -165,17 +153,21 @@ void x300_dboard_iface::set_clock_rate(unit_t unit, double rate) case UNIT_TX: _config.clock->set_dboard_rate(_config.which_tx_clk, rate); break; + default: + UHD_THROW_INVALID_CODE_PATH(); } _clock_rates[unit] = rate; //set to shadow } double x300_dboard_iface::get_clock_rate(unit_t unit) { + if (unit == UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported."); return _clock_rates[unit]; //get from shadow } std::vector<double> x300_dboard_iface::get_clock_rates(unit_t unit) { + if (unit == UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported."); switch(unit) { case UNIT_RX: @@ -189,6 +181,7 @@ std::vector<double> x300_dboard_iface::get_clock_rates(unit_t unit) void x300_dboard_iface::set_clock_enabled(unit_t unit, bool enb) { + if (unit == UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported."); switch(unit) { case UNIT_RX: @@ -200,57 +193,74 @@ void x300_dboard_iface::set_clock_enabled(unit_t unit, bool enb) } } -double x300_dboard_iface::get_codec_rate(unit_t) +double x300_dboard_iface::get_codec_rate(unit_t unit) { + if (unit == UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported."); return _config.clock->get_master_clock_rate(); } /*********************************************************************** * GPIO **********************************************************************/ -void x300_dboard_iface::_set_pin_ctrl(unit_t unit, boost::uint16_t value) +void x300_dboard_iface::set_pin_ctrl(unit_t unit, boost::uint32_t value, boost::uint32_t mask) { - return _config.gpio->set_pin_ctrl(unit, value); + _config.gpio->set_pin_ctrl(unit, value, mask); } -void x300_dboard_iface::_set_gpio_ddr(unit_t unit, boost::uint16_t value) +boost::uint32_t x300_dboard_iface::get_pin_ctrl(unit_t unit) { - return _config.gpio->set_gpio_ddr(unit, value); + return _config.gpio->get_pin_ctrl(unit); } -void x300_dboard_iface::_set_gpio_out(unit_t unit, boost::uint16_t value) +void x300_dboard_iface::set_atr_reg(unit_t unit, atr_reg_t reg, boost::uint32_t value, boost::uint32_t mask) { - return _config.gpio->set_gpio_out(unit, value); + _config.gpio->set_atr_reg(unit, reg, value, mask); } -boost::uint16_t x300_dboard_iface::read_gpio(unit_t unit) +boost::uint32_t x300_dboard_iface::get_atr_reg(unit_t unit, atr_reg_t reg) { - return _config.gpio->read_gpio(unit); + return _config.gpio->get_atr_reg(unit, reg); +} + +void x300_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint32_t value, boost::uint32_t mask) +{ + _config.gpio->set_gpio_ddr(unit, value, mask); } -void x300_dboard_iface::_set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value) +boost::uint32_t x300_dboard_iface::get_gpio_ddr(unit_t unit) { - return _config.gpio->set_atr_reg(unit, atr, value); + return _config.gpio->get_gpio_ddr(unit); } -void x300_dboard_iface::set_gpio_debug(unit_t, int) +void x300_dboard_iface::set_gpio_out(unit_t unit, boost::uint32_t value, boost::uint32_t mask) { - throw uhd::not_implemented_error("no set_gpio_debug implemented"); + _config.gpio->set_gpio_out(unit, value, mask); +} + +boost::uint32_t x300_dboard_iface::get_gpio_out(unit_t unit) +{ + return _config.gpio->get_gpio_out(unit); +} + +boost::uint32_t x300_dboard_iface::read_gpio(unit_t unit) +{ + return _config.gpio->read_gpio(unit); } /*********************************************************************** * SPI **********************************************************************/ -#define toslaveno(unit) \ - (((unit) == dboard_iface::UNIT_TX)? _config.tx_spi_slaveno : _config.rx_spi_slaveno) - void x300_dboard_iface::write_spi( unit_t unit, const spi_config_t &config, boost::uint32_t data, size_t num_bits ){ - _config.spi->write_spi(toslaveno(unit), config, data, num_bits); + boost::uint32_t slave = 0; + if (unit == UNIT_TX) slave |= _config.tx_spi_slaveno; + if (unit == UNIT_RX) slave |= _config.rx_spi_slaveno; + + _config.spi->write_spi(int(slave), config, data, num_bits); } boost::uint32_t x300_dboard_iface::read_write_spi( @@ -259,7 +269,10 @@ boost::uint32_t x300_dboard_iface::read_write_spi( boost::uint32_t data, size_t num_bits ){ - return _config.spi->read_spi(toslaveno(unit), config, data, num_bits); + if (unit == UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported."); + return _config.spi->read_spi( + (unit==dboard_iface::UNIT_TX)?_config.tx_spi_slaveno:_config.rx_spi_slaveno, + config, data, num_bits); } /*********************************************************************** @@ -284,6 +297,7 @@ void x300_dboard_iface::_write_aux_dac(unit_t unit) (UNIT_RX, DB_RX_LSDAC_SEN) (UNIT_TX, DB_TX_LSDAC_SEN) ; + if (unit == UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported."); _config.spi->write_spi( unit_to_spi_dac[unit], spi_config_t::EDGE_FALL, _dac_regs[unit].get_reg(), 24 @@ -292,6 +306,8 @@ void x300_dboard_iface::_write_aux_dac(unit_t unit) void x300_dboard_iface::write_aux_dac(unit_t unit, aux_dac_t which, double value) { + if (unit == UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported."); + _dac_regs[unit].data = boost::math::iround(4095*value/3.3); _dac_regs[unit].cmd = ad5623_regs_t::CMD_WR_UP_DAC_CHAN_N; @@ -321,6 +337,8 @@ double x300_dboard_iface::read_aux_adc(unit_t unit, aux_adc_t which) (UNIT_TX, DB_TX_LSADC_SEN) ; + if (unit == UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported."); + //setup spi config args spi_config_t config; config.mosi_edge = spi_config_t::EDGE_FALL; @@ -356,3 +374,14 @@ void x300_dboard_iface::set_command_time(const uhd::time_spec_t& t) { _config.cmd_time_ctrl->set_time(t); } + +void x300_dboard_iface::set_fe_connection( + unit_t unit, const std::string& /*fe_name*/, + const fe_connection_t& fe_conn) +{ + if (unit == UNIT_RX) { + _config.rx_dsp->set_mux(fe_conn); + } else { + throw uhd::not_implemented_error("frontend connection not configurable for TX"); + } +} diff --git a/host/lib/usrp/x300/x300_fw_common.h b/host/lib/usrp/x300/x300_fw_common.h index 549fc9dfa..6039ee376 100644 --- a/host/lib/usrp/x300/x300_fw_common.h +++ b/host/lib/usrp/x300/x300_fw_common.h @@ -33,7 +33,7 @@ extern "C" { #define X300_REVISION_MIN 2 #define X300_FW_COMPAT_MAJOR 4 #define X300_FW_COMPAT_MINOR 0 -#define X300_FPGA_COMPAT_MAJOR 19 +#define X300_FPGA_COMPAT_MAJOR 20 //shared memory sections - in between the stack and the program space #define X300_FW_SHMEM_BASE 0x6000 diff --git a/host/lib/usrp/x300/x300_fw_ctrl.cpp b/host/lib/usrp/x300/x300_fw_ctrl.cpp index 3a8d984fb..25960ede0 100644 --- a/host/lib/usrp/x300/x300_fw_ctrl.cpp +++ b/host/lib/usrp/x300/x300_fw_ctrl.cpp @@ -37,6 +37,11 @@ class x300_ctrl_iface : public wb_iface public: enum {num_retries = 3}; + x300_ctrl_iface(bool enable_errors = true) : errors(enable_errors) + { + /* NOP */ + } + void flush(void) { boost::mutex::scoped_lock lock(reg_access); @@ -52,11 +57,11 @@ public: { return this->__poke32(addr, data); } - catch(const std::exception &ex) + catch(const uhd::io_error &ex) { - const std::string error_msg = str(boost::format( + std::string error_msg = str(boost::format( "x300 fw communication failure #%u\n%s") % i % ex.what()); - UHD_MSG(error) << error_msg << std::endl; + if (errors) UHD_MSG(error) << error_msg << std::endl; if (i == num_retries) throw uhd::io_error(error_msg); } } @@ -72,11 +77,11 @@ public: boost::uint32_t data = this->__peek32(addr); return data; } - catch(const std::exception &ex) + catch(const uhd::io_error &ex) { - const std::string error_msg = str(boost::format( + std::string error_msg = str(boost::format( "x300 fw communication failure #%u\n%s") % i % ex.what()); - UHD_MSG(error) << error_msg << std::endl; + if (errors) UHD_MSG(error) << error_msg << std::endl; if (i == num_retries) throw uhd::io_error(error_msg); } } @@ -84,6 +89,8 @@ public: } protected: + bool errors; + virtual void __poke32(const wb_addr_type addr, const boost::uint32_t data) = 0; virtual boost::uint32_t __peek32(const wb_addr_type addr) = 0; virtual void __flush() = 0; @@ -98,8 +105,8 @@ protected: class x300_ctrl_iface_enet : public x300_ctrl_iface { public: - x300_ctrl_iface_enet(uhd::transport::udp_simple::sptr udp): - udp(udp), seq(0) + x300_ctrl_iface_enet(uhd::transport::udp_simple::sptr udp, bool enable_errors = true): + x300_ctrl_iface(enable_errors), udp(udp), seq(0) { try { @@ -187,8 +194,8 @@ private: class x300_ctrl_iface_pcie : public x300_ctrl_iface { public: - x300_ctrl_iface_pcie(niriok_proxy::sptr drv_proxy): - _drv_proxy(drv_proxy) + x300_ctrl_iface_pcie(niriok_proxy::sptr drv_proxy, bool enable_errors = true): + x300_ctrl_iface(enable_errors), _drv_proxy(drv_proxy) { nirio_status status = 0; nirio_status_chain(_drv_proxy->set_attribute(RIO_ADDRESS_SPACE, BUS_INTERFACE), status); @@ -289,12 +296,12 @@ private: static const boost::uint32_t INIT_TIMEOUT_IN_MS = 5000; }; -wb_iface::sptr x300_make_ctrl_iface_enet(uhd::transport::udp_simple::sptr udp) +wb_iface::sptr x300_make_ctrl_iface_enet(uhd::transport::udp_simple::sptr udp, bool enable_errors = true) { - return wb_iface::sptr(new x300_ctrl_iface_enet(udp)); + return wb_iface::sptr(new x300_ctrl_iface_enet(udp, enable_errors)); } -wb_iface::sptr x300_make_ctrl_iface_pcie(niriok_proxy::sptr drv_proxy) +wb_iface::sptr x300_make_ctrl_iface_pcie(niriok_proxy::sptr drv_proxy, bool enable_errors = true) { - return wb_iface::sptr(new x300_ctrl_iface_pcie(drv_proxy)); + return wb_iface::sptr(new x300_ctrl_iface_pcie(drv_proxy, enable_errors)); } diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index c13c2ac07..85deaee90 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -18,9 +18,9 @@ #include "x300_impl.hpp" #include "x300_lvbitx.hpp" #include "x310_lvbitx.hpp" +#include "apply_corrections.hpp" #include <boost/algorithm/string.hpp> #include <boost/asio.hpp> -#include "apply_corrections.hpp" #include <uhd/utils/static.hpp> #include <uhd/utils/msg.hpp> #include <uhd/utils/paths.hpp> @@ -32,12 +32,14 @@ #include <boost/make_shared.hpp> #include <boost/functional/hash.hpp> #include <boost/assign/list_of.hpp> -#include <fstream> #include <uhd/transport/udp_zero_copy.hpp> #include <uhd/transport/udp_constants.hpp> +#include <uhd/transport/zero_copy_recv_offload.hpp> #include <uhd/transport/nirio_zero_copy.hpp> #include <uhd/transport/nirio/niusrprio_session.h> #include <uhd/utils/platform.hpp> +#include <uhd/types/sid.hpp> +#include <fstream> #define NIUSRPRIO_DEFAULT_RPC_PORT "5444" @@ -47,23 +49,38 @@ using namespace uhd; using namespace uhd::usrp; using namespace uhd::transport; using namespace uhd::niusrprio; +using namespace uhd::usrp::gpio_atr; using namespace uhd::usrp::x300; namespace asio = boost::asio; -/*********************************************************************** - * Discovery over the udp and pcie transport - **********************************************************************/ +static bool has_dram_buff(wb_iface::sptr zpu_ctrl) { + bool dramR0 = dma_fifo_core_3000::check( + zpu_ctrl, SR_ADDR(SET0_BASE, ZPU_SR_DRAM_FIFO0), SR_ADDR(SET0_BASE, ZPU_RB_DRAM_FIFO0)); + bool dramR1 = dma_fifo_core_3000::check( + zpu_ctrl, SR_ADDR(SET0_BASE, ZPU_SR_DRAM_FIFO1), SR_ADDR(SET0_BASE, ZPU_RB_DRAM_FIFO1)); + return (dramR0 and dramR1); +} + static std::string get_fpga_option(wb_iface::sptr zpu_ctrl) { - //1G = {0:1G, 1:1G} w/ DRAM, HG = {0:1G, 1:10G} w/ DRAM, XG = {0:10G, 1:10G} w/ DRAM - //HGS = {0:1G, 1:10G} w/ SRAM, XGS = {0:10G, 1:10G} w/ SRAM + //Possible options: + //1G = {0:1G, 1:1G} w/ DRAM, HG = {0:1G, 1:10G} w/ DRAM, XG = {0:10G, 1:10G} w/ DRAM + //1GS = {0:1G, 1:1G} w/ SRAM, HGS = {0:1G, 1:10G} w/ SRAM, XGS = {0:10G, 1:10G} w/ SRAM - //In the default configuration, UHD does not support the HG and XG images so - //they are never autodetected. + std::string option; bool eth0XG = (zpu_ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_ETH_TYPE0)) == 0x1); bool eth1XG = (zpu_ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_ETH_TYPE1)) == 0x1); - return (eth0XG && eth1XG) ? "XGS" : (eth1XG ? "HGS" : "1G"); + option = (eth0XG && eth1XG) ? "XG" : (eth1XG ? "HG" : "1G"); + + if (not has_dram_buff(zpu_ctrl)) { + option += "S"; + } + return option; } +/*********************************************************************** + * Discovery over the udp and pcie transport + **********************************************************************/ + //@TODO: Refactor the find functions to collapse common code for ethernet and PCIe static device_addrs_t x300_find_with_addr(const device_addr_t &hint) { @@ -96,7 +113,12 @@ static device_addrs_t x300_find_with_addr(const device_addr_t &hint) //This operation can throw due to compatibility mismatch. try { - wb_iface::sptr zpu_ctrl = x300_make_ctrl_iface_enet(udp_simple::make_connected(new_addr["addr"], BOOST_STRINGIZE(X300_FW_COMMS_UDP_PORT))); + wb_iface::sptr zpu_ctrl = x300_make_ctrl_iface_enet( + udp_simple::make_connected(new_addr["addr"], + BOOST_STRINGIZE(X300_FW_COMMS_UDP_PORT)), + false /* Suppress timeout errors */ + ); + if (x300_impl::is_claimed(zpu_ctrl)) continue; //claimed by another process new_addr["fpga"] = get_fpga_option(zpu_ctrl); @@ -193,7 +215,7 @@ static device_addrs_t x300_find_pcie(const device_addr_t &hint, bool explicit_qu if (get_pcie_zpu_iface_registry().has_key(resource_d)) { zpu_ctrl = get_pcie_zpu_iface_registry()[resource_d].lock(); } else { - zpu_ctrl = x300_make_ctrl_iface_pcie(kernel_proxy); + zpu_ctrl = x300_make_ctrl_iface_pcie(kernel_proxy, false /* suppress timeout errors */); //We don't put this zpu_ctrl in the registry because we need //a persistent niriok_proxy associated with the object } @@ -348,6 +370,8 @@ static void x300_load_fw(wb_iface::sptr fw_reg_ctrl, const std::string &file_nam if ((i & 0x1fff) == 0) UHD_MSG(status) << "." << std::flush; } + //Wait for fimrware to reboot. 3s is an upper bound + boost::this_thread::sleep(boost::posix_time::milliseconds(3000)); UHD_MSG(status) << " done!" << std::endl; } @@ -369,13 +393,133 @@ x300_impl::x300_impl(const uhd::device_addr_t &dev_addr) } } +void x300_impl::mboard_members_t::discover_eth( + const mboard_eeprom_t mb_eeprom, + const std::vector<std::string> &ip_addrs) +{ + // Clear any previous addresses added + eth_conns.clear(); + + // Index the MB EEPROM addresses + std::vector<std::string> mb_eeprom_addrs; + const size_t num_mb_eeprom_addrs = 4; + for (size_t i = 0; i < num_mb_eeprom_addrs; i++) { + const std::string key = "ip-addr" + boost::to_string(i); + + // Show a warning if there exists duplicate addresses in the mboard eeprom + if (std::find(mb_eeprom_addrs.begin(), mb_eeprom_addrs.end(), mb_eeprom[key]) != mb_eeprom_addrs.end()) { + UHD_MSG(warning) << str(boost::format( + "Duplicate IP address %s found in mboard EEPROM. " + "Device may not function properly.\nView and reprogram the values " + "using the usrp_burn_mb_eeprom utility.\n") % mb_eeprom[key]); + } + mb_eeprom_addrs.push_back(mb_eeprom[key]); + } + + BOOST_FOREACH(const std::string& addr, ip_addrs) { + x300_eth_conn_t conn_iface; + conn_iface.addr = addr; + conn_iface.type = X300_IFACE_NONE; + + // Decide from the mboard eeprom what IP corresponds + // to an interface + for (size_t i = 0; i < mb_eeprom_addrs.size(); i++) { + if (addr == mb_eeprom_addrs[i]) { + // Choose the interface based on the index parity + if (i % 2 == 0) { + conn_iface.type = X300_IFACE_ETH0; + } else { + conn_iface.type = X300_IFACE_ETH1; + } + break; + } + } + + // Check default IP addresses if we couldn't + // determine the IP from the mboard eeprom + if (conn_iface.type == X300_IFACE_NONE) { + UHD_MSG(warning) << str(boost::format( + "Address %s not found in mboard EEPROM. Address may be wrong or " + "the EEPROM may be corrupt.\n Attempting to continue with default " + "IP addresses.\n") % conn_iface.addr + ); + + if (addr == boost::asio::ip::address_v4( + boost::uint32_t(X300_DEFAULT_IP_ETH0_1G)).to_string()) { + conn_iface.type = X300_IFACE_ETH0; + } else if (addr == boost::asio::ip::address_v4( + boost::uint32_t(X300_DEFAULT_IP_ETH1_1G)).to_string()) { + conn_iface.type = X300_IFACE_ETH1; + } else if (addr == boost::asio::ip::address_v4( + boost::uint32_t(X300_DEFAULT_IP_ETH0_10G)).to_string()) { + conn_iface.type = X300_IFACE_ETH0; + } else if (addr == boost::asio::ip::address_v4( + boost::uint32_t(X300_DEFAULT_IP_ETH1_10G)).to_string()) { + conn_iface.type = X300_IFACE_ETH1; + } else { + throw uhd::assertion_error(str(boost::format( + "X300 Initialization Error: Failed to match address %s with " + "any addresses for the device. Please check the address.") + % conn_iface.addr + )); + } + } + + // Save to a vector of connections + if (conn_iface.type != X300_IFACE_NONE) { + // Check the address before we add it + try + { + wb_iface::sptr zpu_ctrl = x300_make_ctrl_iface_enet( + udp_simple::make_connected(conn_iface.addr, + BOOST_STRINGIZE(X300_FW_COMMS_UDP_PORT)), + false /* Suppress timeout errors */ + ); + + // Peek the ZPU ctrl to make sure this connection works + zpu_ctrl->peek32(0); + } + + // If the address does not work, throw an error + catch(std::exception &) + { + throw uhd::io_error(str(boost::format( + "X300 Initialization Error: Invalid address %s") + % conn_iface.addr)); + } + eth_conns.push_back(conn_iface); + } + } + + if (eth_conns.size() == 0) + throw uhd::assertion_error("X300 Initialization Error: No ethernet interfaces specified."); +} + void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) { const fs_path mb_path = "/mboards/"+boost::lexical_cast<std::string>(mb_i); mboard_members_t &mb = _mb[mb_i]; mb.initialization_done = false; - mb.addr = dev_addr.has_key("resource") ? dev_addr["resource"] : dev_addr["addr"]; + std::vector<std::string> eth_addrs; + // Not choosing eth0 based on resource might cause user issues + std::string eth0_addr = dev_addr.has_key("resource") ? dev_addr["resource"] : dev_addr["addr"]; + eth_addrs.push_back(eth0_addr); + + if (dev_addr.has_key("second_addr")) { + std::string eth1_addr = dev_addr["second_addr"]; + + // Ensure we do not have duplicate addresses + if (eth1_addr != eth0_addr) + eth_addrs.push_back(eth1_addr); + } + + // Initially store the first address provided to setup communication + // Once we read the eeprom, we use it to map IP to its interface + x300_eth_conn_t init; + init.addr = eth_addrs[0]; + mb.eth_conns.push_back(init); + mb.xport_path = dev_addr.has_key("resource") ? "nirio" : "eth"; mb.if_pkt_is_big_endian = mb.xport_path != "nirio"; @@ -452,7 +596,28 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) // Detect the frame size on the path to the USRP try { - _max_frame_sizes = determine_max_frame_size(mb.addr, req_max_frame_size); + 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_MSG(error) << e.what() << std::endl; } @@ -486,15 +651,15 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) UHD_MSG(status) << "Setup basic communication..." << std::endl; if (mb.xport_path == "nirio") { boost::mutex::scoped_lock(pcie_zpu_iface_registry_mutex); - if (get_pcie_zpu_iface_registry().has_key(mb.addr)) { + if (get_pcie_zpu_iface_registry().has_key(mb.get_pri_eth().addr)) { throw uhd::assertion_error("Someone else has a ZPU transport to the device open. Internal error!"); } else { mb.zpu_ctrl = x300_make_ctrl_iface_pcie(mb.rio_fpga_interface->get_kernel_proxy()); - get_pcie_zpu_iface_registry()[mb.addr] = boost::weak_ptr<wb_iface>(mb.zpu_ctrl); + get_pcie_zpu_iface_registry()[mb.get_pri_eth().addr] = boost::weak_ptr<wb_iface>(mb.zpu_ctrl); } } else { - mb.zpu_ctrl = x300_make_ctrl_iface_enet(udp_simple::make_connected(mb.addr, - BOOST_STRINGIZE(X300_FW_COMMS_UDP_PORT))); + mb.zpu_ctrl = x300_make_ctrl_iface_enet(udp_simple::make_connected( + mb.get_pri_eth().addr, BOOST_STRINGIZE(X300_FW_COMMS_UDP_PORT))); } mb.claimer_task = uhd::task::make(boost::bind(&x300_impl::claimer_loop, this, mb.zpu_ctrl)); @@ -561,7 +726,7 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) const mboard_eeprom_t mb_eeprom(*eeprom16, "X300"); _tree->create<mboard_eeprom_t>(mb_path / "eeprom") .set(mb_eeprom) - .subscribe(boost::bind(&x300_impl::set_mb_eeprom, this, mb.zpu_i2c, _1)); + .add_coerced_subscriber(boost::bind(&x300_impl::set_mb_eeprom, this, mb.zpu_i2c, _1)); bool recover_mb_eeprom = dev_addr.has_key("recover_mb_eeprom"); if (recover_mb_eeprom) { @@ -593,18 +758,9 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) //////////////////////////////////////////////////////////////////// // determine routing based on address match //////////////////////////////////////////////////////////////////// - mb.router_dst_here = X300_XB_DST_E0; //some default if eeprom not match - if (mb.xport_path == "nirio") { - mb.router_dst_here = X300_XB_DST_PCI; - } else { - if (mb.addr == mb_eeprom["ip-addr0"]) mb.router_dst_here = X300_XB_DST_E0; - else if (mb.addr == mb_eeprom["ip-addr1"]) mb.router_dst_here = X300_XB_DST_E1; - else if (mb.addr == mb_eeprom["ip-addr2"]) mb.router_dst_here = X300_XB_DST_E0; - else if (mb.addr == mb_eeprom["ip-addr3"]) mb.router_dst_here = X300_XB_DST_E1; - else if (mb.addr == boost::asio::ip::address_v4(boost::uint32_t(X300_DEFAULT_IP_ETH0_1G)).to_string()) mb.router_dst_here = X300_XB_DST_E0; - else if (mb.addr == boost::asio::ip::address_v4(boost::uint32_t(X300_DEFAULT_IP_ETH1_1G)).to_string()) mb.router_dst_here = X300_XB_DST_E1; - else if (mb.addr == boost::asio::ip::address_v4(boost::uint32_t(X300_DEFAULT_IP_ETH0_10G)).to_string()) mb.router_dst_here = X300_XB_DST_E0; - else if (mb.addr == boost::asio::ip::address_v4(boost::uint32_t(X300_DEFAULT_IP_ETH1_10G)).to_string()) mb.router_dst_here = X300_XB_DST_E1; + if (mb.xport_path != "nirio") { + // Discover ethernet interfaces + mb.discover_eth(mb_eeprom, eth_addrs); } //////////////////////////////////////////////////////////////////// @@ -684,7 +840,7 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) // create clock properties //////////////////////////////////////////////////////////////////// _tree->create<double>(mb_path / "tick_rate") - .publish(boost::bind(&x300_clock_ctrl::get_master_clock_rate, mb.clock)); + .set_publisher(boost::bind(&x300_clock_ctrl::get_master_clock_rate, mb.clock)); _tree->create<time_spec_t>(mb_path / "time" / "cmd"); @@ -713,7 +869,7 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) BOOST_FOREACH(const std::string &name, mb.gps->get_sensors()) { _tree->create<sensor_value_t>(mb_path / "sensors" / name) - .publish(boost::bind(&gps_ctrl::get_sensor, mb.gps, name)); + .set_publisher(boost::bind(&gps_ctrl::get_sensor, mb.gps, name)); } } else @@ -730,6 +886,36 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) } //////////////////////////////////////////////////////////////////// + // DRAM FIFO initialization + //////////////////////////////////////////////////////////////////// + mb.has_dram_buff = has_dram_buff(mb.zpu_ctrl); + if (mb.has_dram_buff) { + for (size_t i = 0; i < mboard_members_t::NUM_RADIOS; i++) { + static const size_t NUM_REGS = 8; + mb.dram_buff_ctrl[i] = dma_fifo_core_3000::make( + mb.zpu_ctrl, + SR_ADDR(SET0_BASE, ZPU_SR_DRAM_FIFO0+(i*NUM_REGS)), + SR_ADDR(SET0_BASE, ZPU_RB_DRAM_FIFO0+i)); + mb.dram_buff_ctrl[i]->resize(X300_DRAM_FIFO_SIZE * i, X300_DRAM_FIFO_SIZE); + + if (mb.dram_buff_ctrl[i]->ext_bist_supported()) { + UHD_MSG(status) << boost::format("Running BIST for DRAM FIFO %d... ") % i; + boost::uint32_t bisterr = mb.dram_buff_ctrl[i]->run_bist(); + if (bisterr != 0) { + throw uhd::runtime_error(str(boost::format("DRAM FIFO BIST failed! (code: %d)\n") % bisterr)); + } else { + double throughput = mb.dram_buff_ctrl[i]->get_bist_throughput(X300_BUS_CLOCK_RATE); + UHD_MSG(status) << (boost::format("pass (Throughput: %.1fMB/s)") % (throughput/1e6)) << std::endl; + } + } else { + if (mb.dram_buff_ctrl[i]->run_bist() != 0) { + throw uhd::runtime_error(str(boost::format("DRAM FIFO %d BIST failed!\n") % i)); + } + } + } + } + + //////////////////////////////////////////////////////////////////// // setup radios //////////////////////////////////////////////////////////////////// this->setup_radio(mb_i, "A", dev_addr); @@ -750,40 +936,40 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) //////////////////////////////////////////////////////////////////// // front panel gpio //////////////////////////////////////////////////////////////////// - mb.fp_gpio = gpio_core_200::make(mb.radio_perifs[0].ctrl, radio::sr_addr(radio::FP_GPIO), radio::RB32_FP_GPIO); + mb.fp_gpio = gpio_atr_3000::make(mb.radio_perifs[0].ctrl, radio::sr_addr(radio::FP_GPIO), radio::RB32_FP_GPIO); BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map) { _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / attr.second) .set(0) - .subscribe(boost::bind(&x300_impl::set_fp_gpio, this, mb.fp_gpio, attr.first, _1)); + .add_coerced_subscriber(boost::bind(&gpio_atr_3000::set_gpio_attr, mb.fp_gpio, attr.first, _1)); } _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / "READBACK") - .publish(boost::bind(&x300_impl::get_fp_gpio, this, mb.fp_gpio)); + .set_publisher(boost::bind(&gpio_atr_3000::read_gpio, mb.fp_gpio)); //////////////////////////////////////////////////////////////////// // register the time keepers - only one can be the highlander //////////////////////////////////////////////////////////////////// _tree->create<time_spec_t>(mb_path / "time" / "now") - .publish(boost::bind(&time_core_3000::get_time_now, mb.radio_perifs[0].time64)) - .subscribe(boost::bind(&x300_impl::sync_times, this, mb, _1)) + .set_publisher(boost::bind(&time_core_3000::get_time_now, mb.radio_perifs[0].time64)) + .add_coerced_subscriber(boost::bind(&x300_impl::sync_times, this, mb, _1)) .set(0.0); _tree->create<time_spec_t>(mb_path / "time" / "pps") - .publish(boost::bind(&time_core_3000::get_time_last_pps, mb.radio_perifs[0].time64)) - .subscribe(boost::bind(&time_core_3000::set_time_next_pps, mb.radio_perifs[0].time64, _1)) - .subscribe(boost::bind(&time_core_3000::set_time_next_pps, mb.radio_perifs[1].time64, _1)); + .set_publisher(boost::bind(&time_core_3000::get_time_last_pps, mb.radio_perifs[0].time64)) + .add_coerced_subscriber(boost::bind(&time_core_3000::set_time_next_pps, mb.radio_perifs[0].time64, _1)) + .add_coerced_subscriber(boost::bind(&time_core_3000::set_time_next_pps, mb.radio_perifs[1].time64, _1)); //////////////////////////////////////////////////////////////////// // setup time sources and properties //////////////////////////////////////////////////////////////////// _tree->create<std::string>(mb_path / "time_source" / "value") .set("internal") - .subscribe(boost::bind(&x300_impl::update_time_source, this, boost::ref(mb), _1)); + .add_coerced_subscriber(boost::bind(&x300_impl::update_time_source, this, boost::ref(mb), _1)); static const std::vector<std::string> time_sources = boost::assign::list_of("internal")("external")("gpsdo"); _tree->create<std::vector<std::string> >(mb_path / "time_source" / "options").set(time_sources); //setup the time output, default to ON _tree->create<bool>(mb_path / "time_source" / "output") - .subscribe(boost::bind(&x300_impl::set_time_source_out, this, boost::ref(mb), _1)) + .add_coerced_subscriber(boost::bind(&x300_impl::set_time_source_out, this, boost::ref(mb), _1)) .set(true); //////////////////////////////////////////////////////////////////// @@ -791,7 +977,7 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) //////////////////////////////////////////////////////////////////// _tree->create<std::string>(mb_path / "clock_source" / "value") .set("internal") - .subscribe(boost::bind(&x300_impl::update_clock_source, this, boost::ref(mb), _1)); + .add_coerced_subscriber(boost::bind(&x300_impl::update_clock_source, this, boost::ref(mb), _1)); static const std::vector<std::string> clock_source_options = boost::assign::list_of("internal")("external")("gpsdo"); _tree->create<std::vector<std::string> >(mb_path / "clock_source" / "options").set(clock_source_options); @@ -807,12 +993,12 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) //setup the clock output, default to ON _tree->create<bool>(mb_path / "clock_source" / "output") - .subscribe(boost::bind(&x300_clock_ctrl::set_ref_out, mb.clock, _1)); + .add_coerced_subscriber(boost::bind(&x300_clock_ctrl::set_ref_out, mb.clock, _1)); //initialize tick rate (must be done before setting time) _tree->access<double>(mb_path / "tick_rate") - .subscribe(boost::bind(&x300_impl::set_tick_rate, this, boost::ref(mb), _1)) - .subscribe(boost::bind(&x300_impl::update_tick_rate, this, boost::ref(mb), _1)) + .add_coerced_subscriber(boost::bind(&x300_impl::set_tick_rate, this, boost::ref(mb), _1)) + .add_coerced_subscriber(boost::bind(&x300_impl::update_tick_rate, this, boost::ref(mb), _1)) .set(mb.clock->get_master_clock_rate()); //////////////////////////////////////////////////////////////////// @@ -822,15 +1008,15 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) _tree->create<std::vector<size_t> >(mb_path / "rx_chan_dsp_mapping").set(default_map); _tree->create<std::vector<size_t> >(mb_path / "tx_chan_dsp_mapping").set(default_map); _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec") - .subscribe(boost::bind(&x300_impl::update_subdev_spec, this, "rx", mb_i, _1)); + .add_coerced_subscriber(boost::bind(&x300_impl::update_subdev_spec, this, "rx", mb_i, _1)); _tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec") - .subscribe(boost::bind(&x300_impl::update_subdev_spec, this, "tx", mb_i, _1)); + .add_coerced_subscriber(boost::bind(&x300_impl::update_subdev_spec, this, "tx", mb_i, _1)); //////////////////////////////////////////////////////////////////// // and do the misc mboard sensors //////////////////////////////////////////////////////////////////// _tree->create<sensor_value_t>(mb_path / "sensors" / "ref_locked") - .publish(boost::bind(&x300_impl::get_ref_locked, this, mb)); + .set_publisher(boost::bind(&x300_impl::get_ref_locked, this, mb)); //////////////////////////////////////////////////////////////////// // do some post-init tasks @@ -881,7 +1067,7 @@ x300_impl::~x300_impl(void) mb.zpu_ctrl->poke32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_CLAIM_SRC), 0); //If the process is killed, the entire registry will disappear so we //don't need to worry about unclean shutdowns here. - get_pcie_zpu_iface_registry().pop(mb.addr); + get_pcie_zpu_iface_registry().pop(mb.get_pri_eth().addr); } } } @@ -931,7 +1117,8 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name, con perif.spi = spi_core_3000::make(perif.ctrl, radio::sr_addr(radio::SPI), radio::RB32_SPI); perif.adc = x300_adc_ctrl::make(perif.spi, DB_ADC_SEN); perif.dac = x300_dac_ctrl::make(perif.spi, DB_DAC_SEN, mb.clock->get_master_clock_rate()); - perif.leds = gpio_core_200_32wo::make(perif.ctrl, radio::sr_addr(radio::LEDS)); + perif.leds = gpio_atr_3000::make_write_only(perif.ctrl, radio::sr_addr(radio::LEDS)); + perif.leds->set_atr_mode(MODE_ATR, 0xFFFFFFFF); perif.rx_fe = rx_frontend_core_200::make(perif.ctrl, radio::sr_addr(radio::RX_FRONT)); perif.rx_fe->set_dc_offset(rx_frontend_core_200::DEFAULT_DC_OFFSET_VALUE); perif.rx_fe->set_dc_offset_auto(rx_frontend_core_200::DEFAULT_DC_OFFSET_ENABLE); @@ -941,9 +1128,14 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name, con perif.framer = rx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::RX_CTRL)); perif.ddc = rx_dsp_core_3000::make(perif.ctrl, radio::sr_addr(radio::RX_DSP)); perif.ddc->set_link_rate(10e9/8); //whatever - perif.deframer = tx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_CTRL)); + perif.ddc->set_tick_rate(mb.clock->get_master_clock_rate()); + //The DRAM FIFO is treated as in internal radio FIFO for flow control purposes + tx_vita_core_3000::fc_monitor_loc fc_loc = + mb.has_dram_buff ? tx_vita_core_3000::FC_PRE_FIFO : tx_vita_core_3000::FC_PRE_RADIO; + perif.deframer = tx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_CTRL), fc_loc); perif.duc = tx_dsp_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_DSP)); perif.duc->set_link_rate(10e9/8); //whatever + perif.duc->set_tick_rate(mb.clock->get_master_clock_rate()); //////////////////////////////////////////////////////////////////// // create time control objects @@ -958,7 +1150,7 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name, con self_cal_adc_capture_delay(mb, radio_index, dev_addr.has_key("self_cal_adc_delay")); _tree->access<time_spec_t>(mb_path / "time" / "cmd") - .subscribe(boost::bind(&radio_ctrl_core_3000::set_time, perif.ctrl, _1)); + .add_coerced_subscriber(boost::bind(&radio_ctrl_core_3000::set_time, perif.ctrl, _1)); //////////////////////////////////////////////////////////////// // create codec control objects @@ -970,7 +1162,7 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name, con _tree->create<meta_range_t>(mb_path / "rx_codecs" / slot_name / "gains" / "digital" / "range").set(meta_range_t(0, 6.0, 0.5)); _tree->create<double>(mb_path / "rx_codecs" / slot_name / "gains" / "digital" / "value") - .subscribe(boost::bind(&x300_adc_ctrl::set_gain, perif.adc, _1)).set(0); + .add_coerced_subscriber(boost::bind(&x300_adc_ctrl::set_gain, perif.adc, _1)).set(0); //////////////////////////////////////////////////////////////////// // front end corrections @@ -984,10 +1176,10 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name, con const fs_path rx_dsp_path = mb_path / "rx_dsps" / str(boost::format("%u") % radio_index); perif.ddc->populate_subtree(_tree->subtree(rx_dsp_path)); _tree->access<double>(rx_dsp_path / "rate" / "value") - .subscribe(boost::bind(&x300_impl::update_rx_samp_rate, this, boost::ref(mb), radio_index, _1)) + .add_coerced_subscriber(boost::bind(&x300_impl::update_rx_samp_rate, this, boost::ref(mb), radio_index, _1)) ; _tree->create<stream_cmd_t>(rx_dsp_path / "stream_cmd") - .subscribe(boost::bind(&rx_vita_core_3000::issue_stream_command, perif.framer, _1)); + .add_coerced_subscriber(boost::bind(&rx_vita_core_3000::issue_stream_command, perif.framer, _1)); //////////////////////////////////////////////////////////////////// // connect tx dsp control objects @@ -995,7 +1187,7 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name, con const fs_path tx_dsp_path = mb_path / "tx_dsps" / str(boost::format("%u") % radio_index); perif.duc->populate_subtree(_tree->subtree(tx_dsp_path)); _tree->access<double>(tx_dsp_path / "rate" / "value") - .subscribe(boost::bind(&x300_impl::update_tx_samp_rate, this, boost::ref(mb), radio_index, _1)) + .add_coerced_subscriber(boost::bind(&x300_impl::update_tx_samp_rate, this, boost::ref(mb), radio_index, _1)) ; //////////////////////////////////////////////////////////////////// @@ -1005,54 +1197,53 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name, con const size_t j = (slot_name == "B")? 0x2 : 0x0; _tree->create<dboard_eeprom_t>(db_path / "rx_eeprom") .set(mb.db_eeproms[X300_DB0_RX_EEPROM | j]) - .subscribe(boost::bind(&x300_impl::set_db_eeprom, this, mb.zpu_i2c, (0x50 | X300_DB0_RX_EEPROM | j), _1)); + .add_coerced_subscriber(boost::bind(&x300_impl::set_db_eeprom, this, mb.zpu_i2c, (0x50 | X300_DB0_RX_EEPROM | j), _1)); _tree->create<dboard_eeprom_t>(db_path / "tx_eeprom") .set(mb.db_eeproms[X300_DB0_TX_EEPROM | j]) - .subscribe(boost::bind(&x300_impl::set_db_eeprom, this, mb.zpu_i2c, (0x50 | X300_DB0_TX_EEPROM | j), _1)); + .add_coerced_subscriber(boost::bind(&x300_impl::set_db_eeprom, this, mb.zpu_i2c, (0x50 | X300_DB0_TX_EEPROM | j), _1)); _tree->create<dboard_eeprom_t>(db_path / "gdb_eeprom") .set(mb.db_eeproms[X300_DB0_GDB_EEPROM | j]) - .subscribe(boost::bind(&x300_impl::set_db_eeprom, this, mb.zpu_i2c, (0x50 | X300_DB0_GDB_EEPROM | j), _1)); + .add_coerced_subscriber(boost::bind(&x300_impl::set_db_eeprom, this, mb.zpu_i2c, (0x50 | X300_DB0_GDB_EEPROM | j), _1)); //create a new dboard interface x300_dboard_iface_config_t db_config; - db_config.gpio = gpio_core_200::make(perif.ctrl, radio::sr_addr(radio::GPIO), radio::RB32_GPIO); + db_config.gpio = db_gpio_atr_3000::make(perif.ctrl, radio::sr_addr(radio::GPIO), radio::RB32_GPIO); db_config.spi = perif.spi; db_config.rx_spi_slaveno = DB_RX_SEN; db_config.tx_spi_slaveno = DB_TX_SEN; db_config.i2c = mb.zpu_i2c; db_config.clock = mb.clock; + db_config.rx_dsp = mb.radio_perifs[radio_index].ddc; db_config.which_rx_clk = (slot_name == "A")? X300_CLOCK_WHICH_DB0_RX : X300_CLOCK_WHICH_DB1_RX; db_config.which_tx_clk = (slot_name == "A")? X300_CLOCK_WHICH_DB0_TX : X300_CLOCK_WHICH_DB1_TX; db_config.dboard_slot = (slot_name == "A")? 0 : 1; db_config.cmd_time_ctrl = perif.ctrl; - _dboard_ifaces[db_path] = x300_make_dboard_iface(db_config); //create a new dboard manager - _tree->create<dboard_iface::sptr>(db_path / "iface").set(_dboard_ifaces[db_path]); _dboard_managers[db_path] = dboard_manager::make( mb.db_eeproms[X300_DB0_RX_EEPROM | j].id, mb.db_eeproms[X300_DB0_TX_EEPROM | j].id, mb.db_eeproms[X300_DB0_GDB_EEPROM | j].id, - _dboard_ifaces[db_path], + x300_make_dboard_iface(db_config), _tree->subtree(db_path) ); //now that dboard is created -- register into rx antenna event const std::string fe_name = _tree->list(db_path / "rx_frontends").front(); _tree->access<std::string>(db_path / "rx_frontends" / fe_name / "antenna" / "value") - .subscribe(boost::bind(&x300_impl::update_atr_leds, this, mb.radio_perifs[radio_index].leds, _1)); + .add_coerced_subscriber(boost::bind(&x300_impl::update_atr_leds, this, mb.radio_perifs[radio_index].leds, _1)); this->update_atr_leds(mb.radio_perifs[radio_index].leds, ""); //init anyway, even if never called //bind frontend corrections to the dboard freq props const fs_path db_tx_fe_path = db_path / "tx_frontends"; BOOST_FOREACH(const std::string &name, _tree->list(db_tx_fe_path)) { _tree->access<double>(db_tx_fe_path / name / "freq" / "value") - .subscribe(boost::bind(&x300_impl::set_tx_fe_corrections, this, mb_path, slot_name, _1)); + .add_coerced_subscriber(boost::bind(&x300_impl::set_tx_fe_corrections, this, mb_path, slot_name, _1)); } const fs_path db_rx_fe_path = db_path / "rx_frontends"; BOOST_FOREACH(const std::string &name, _tree->list(db_rx_fe_path)) { _tree->access<double>(db_rx_fe_path / name / "freq" / "value") - .subscribe(boost::bind(&x300_impl::set_rx_fe_corrections, this, mb_path, slot_name, _1)); + .add_coerced_subscriber(boost::bind(&x300_impl::set_rx_fe_corrections, this, mb_path, slot_name, _1)); } } @@ -1080,7 +1271,6 @@ boost::uint32_t get_pcie_dma_channel(boost::uint8_t destination, boost::uint8_t return ((radio_grp * RADIO_GRP_SIZE) + prefix); } - x300_impl::both_xports_t x300_impl::make_transport( const size_t mb_index, const boost::uint8_t& destination, @@ -1095,9 +1285,19 @@ x300_impl::both_xports_t x300_impl::make_transport( config.router_addr_there = X300_DEVICE_THERE; config.dst_prefix = prefix; config.router_dst_there = destination; - config.router_dst_here = mb.router_dst_here; - sid = this->allocate_sid(mb, config); + // Choose the endpoint based on the destination + size_t endpoint = 0; + if (destination == X300_XB_DST_R1) { + if (mb.eth_conns.size() > 1) + endpoint = 1; + } + + // Decide on the IP/Interface pair based on the endpoint index + std::string interface_addr = mb.eth_conns[endpoint].addr; + config.iface_index = mb.eth_conns[endpoint].type; + + sid = this->allocate_sid(mb, config); static const uhd::device_addr_t DEFAULT_XPORT_ARGS; const uhd::device_addr_t& xport_args = @@ -1144,17 +1344,23 @@ x300_impl::both_xports_t x300_impl::make_transport( * connection type.*/ size_t eth_data_rec_frame_size = 0; - if (mb.loaded_fpga_image == "HGS") { - if (mb.router_dst_here == X300_XB_DST_E0) { + fs_path mboard_path = fs_path("/mboards/"+boost::lexical_cast<std::string>(mb_index) / "link_max_rate"); + + if (mb.loaded_fpga_image.substr(0,2) == "HG") { + size_t max_link_rate = 0; + if (config.iface_index == X300_IFACE_ETH0) { eth_data_rec_frame_size = X300_1GE_DATA_FRAME_MAX_SIZE; - _tree->access<double>("/mboards/"+boost::lexical_cast<std::string>(mb_index) / "link_max_rate").set(X300_MAX_RATE_1GIGE); - } else if (mb.router_dst_here == X300_XB_DST_E1) { + max_link_rate += X300_MAX_RATE_1GIGE; + } else if (config.iface_index == X300_IFACE_ETH1) { eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE; - _tree->access<double>("/mboards/"+boost::lexical_cast<std::string>(mb_index) / "link_max_rate").set(X300_MAX_RATE_10GIGE); + max_link_rate += X300_MAX_RATE_10GIGE; } - } else if (mb.loaded_fpga_image == "XGS") { + _tree->access<double>(mboard_path).set(max_link_rate); + } else if (mb.loaded_fpga_image.substr(0,2) == "XG") { eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE; - _tree->access<double>("/mboards/"+boost::lexical_cast<std::string>(mb_index) / "link_max_rate").set(X300_MAX_RATE_10GIGE); + 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); } if (eth_data_rec_frame_size == 0) { @@ -1209,12 +1415,22 @@ x300_impl::both_xports_t x300_impl::make_transport( //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(mb.addr, + + xports.recv = udp_zero_copy::make( + interface_addr, BOOST_STRINGIZE(X300_VITA_UDP_PORT), default_buff_args, buff_params, xport_args); + // Create a threaded transport for the receive chain only + // Note that this shouldn't affect PCIe + if (prefix == X300_RADIO_DEST_PREFIX_RX) { + xports.recv = zero_copy_recv_offload::make( + xports.recv, + X300_THREAD_BUFFER_TIMEOUT + ); + } xports.send = xports.recv; //For the UDP transport the buffer size if the size of the socket buffer @@ -1229,7 +1445,7 @@ x300_impl::both_xports_t x300_impl::make_transport( //send a mini packet with SID into the ZPU //ZPU will reprogram the ethernet framer UHD_LOG << "programming packet for new xport on " - << mb.addr << std::hex << "sid 0x" << sid << std::dec << std::endl; + << mb.get_pri_eth().addr << std::hex << "sid 0x" << sid << std::dec << std::endl; //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(); @@ -1247,7 +1463,6 @@ x300_impl::both_xports_t x300_impl::make_transport( //ethernet framer has been programmed before we return. mb.zpu_ctrl->peek32(0); } - return xports; } @@ -1256,15 +1471,32 @@ boost::uint32_t x300_impl::allocate_sid(mboard_members_t &mb, const sid_config_t { const std::string &xport_path = mb.xport_path; const boost::uint32_t stream = (config.dst_prefix | (config.router_dst_there << 2)) & 0xff; + boost::uint8_t sid_ret_addr = X300_SRC_ADDR_ETH0; + boost::uint32_t xb_port = X300_XB_DST_E0; + + // Use the interface index to decide on the ethernet port + if (config.iface_index == X300_IFACE_ETH1) { + sid_ret_addr = X300_SRC_ADDR_ETH1; + xb_port = X300_XB_DST_E1; + } + + // Ensure we choose the right port in the case of NI-RIO + if (xport_path == "nirio") { + xb_port = X300_XB_DST_PCI; + } + + int int_sid_ret_addr = int(sid_ret_addr); const boost::uint32_t sid = 0 - | (X300_DEVICE_HERE << 24) + | (sid_ret_addr << 24) | (_sid_framer << 16) | (config.router_addr_there << 8) | (stream << 0) ; + UHD_LOG << std::hex << " sid 0x" << sid + << " return address 0x" << int_sid_ret_addr << " framer 0x" << _sid_framer << " stream 0x" << stream << " router_dst_there 0x" << int(config.router_dst_there) @@ -1278,7 +1510,7 @@ boost::uint32_t x300_impl::allocate_sid(mboard_members_t &mb, const sid_config_t mb.zpu_ctrl->poke32(SR_ADDR(SETXB_BASE, 256 + (stream)), config.router_dst_there); // Program CAM entry for returning packets to us (for example GR host via Eth0) // This type of packet does not match the XB_LOCAL address and is looked up in the lower half of the CAM - mb.zpu_ctrl->poke32(SR_ADDR(SETXB_BASE, 0 + (X300_DEVICE_HERE)), config.router_dst_here); + mb.zpu_ctrl->poke32(SR_ADDR(SETXB_BASE, 0 + (sid_ret_addr)), xb_port); if (xport_path == "nirio") { boost::uint32_t router_config_word = ((_sid_framer & 0xff) << 16) | //Return SID @@ -1296,16 +1528,16 @@ boost::uint32_t x300_impl::allocate_sid(mboard_members_t &mb, const sid_config_t return sid; } -void x300_impl::update_atr_leds(gpio_core_200_32wo::sptr leds, const std::string &rx_ant) +void x300_impl::update_atr_leds(gpio_atr_3000::sptr leds, const std::string &rx_ant) { const bool is_txrx = (rx_ant == "TX/RX"); const int rx_led = (1 << 2); const int tx_led = (1 << 1); const int txrx_led = (1 << 0); - leds->set_atr_reg(dboard_iface::ATR_REG_IDLE, 0); - leds->set_atr_reg(dboard_iface::ATR_REG_RX_ONLY, is_txrx? txrx_led : rx_led); - leds->set_atr_reg(dboard_iface::ATR_REG_TX_ONLY, tx_led); - leds->set_atr_reg(dboard_iface::ATR_REG_FULL_DUPLEX, rx_led | tx_led); + leds->set_atr_reg(ATR_REG_IDLE, 0); + leds->set_atr_reg(ATR_REG_RX_ONLY, is_txrx? txrx_led : rx_led); + leds->set_atr_reg(ATR_REG_TX_ONLY, tx_led); + leds->set_atr_reg(ATR_REG_FULL_DUPLEX, rx_led | tx_led); } void x300_impl::set_tick_rate(mboard_members_t &mb, const double rate) @@ -1315,7 +1547,6 @@ void x300_impl::set_tick_rate(mboard_members_t &mb, const double rate) perif.time64->set_tick_rate(rate); perif.framer->set_tick_rate(rate); perif.ddc->set_tick_rate(rate); - perif.deframer->set_tick_rate(rate); perif.duc->set_tick_rate(rate); } } @@ -1518,30 +1749,6 @@ void x300_impl::set_mb_eeprom(i2c_iface::sptr i2c, const mboard_eeprom_t &mb_eep } /*********************************************************************** - * front-panel GPIO - **********************************************************************/ - -boost::uint32_t x300_impl::get_fp_gpio(gpio_core_200::sptr gpio) -{ - return boost::uint32_t(gpio->read_gpio(dboard_iface::UNIT_RX)); -} - -void x300_impl::set_fp_gpio(gpio_core_200::sptr gpio, const gpio_attr_t attr, const boost::uint32_t value) -{ - switch (attr) - { - case GPIO_CTRL: return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value); - case GPIO_DDR: return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value); - case GPIO_OUT: return gpio->set_gpio_out(dboard_iface::UNIT_RX, value); - case GPIO_ATR_0X: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value); - case GPIO_ATR_RX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value); - case GPIO_ATR_TX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value); - case GPIO_ATR_XX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value); - default: UHD_THROW_INVALID_CODE_PATH(); - } -} - -/*********************************************************************** * claimer logic **********************************************************************/ @@ -1682,7 +1889,7 @@ void x300_impl::check_fpga_compat(const fs_path &mb_path, const mboard_members_t % image_loader_path % (members.xport_path == "eth" ? "addr" : "resource") - % members.addr); + % members.get_pri_eth().addr); throw uhd::runtime_error(str(boost::format( "Expected FPGA compatibility number %d, but got %d:\n" diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index e04b06d65..b5bbbe136 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -41,7 +41,8 @@ #include "radio_ctrl_core_3000.hpp" #include "rx_frontend_core_200.hpp" #include "tx_frontend_core_200.hpp" -#include "gpio_core_200.hpp" +#include "gpio_atr_3000.hpp" +#include "dma_fifo_core_3000.hpp" #include <boost/weak_ptr.hpp> #include <uhd/usrp/gps_ctrl.hpp> #include <uhd/usrp/mboard_eeprom.hpp> @@ -53,12 +54,15 @@ static const std::string X300_FW_FILE_NAME = "usrp_x300_fw.bin"; -static const double X300_DEFAULT_TICK_RATE = 200e6; //Hz -static const double X300_DEFAULT_DBOARD_CLK_RATE = 50e6; //Hz -static const double X300_BUS_CLOCK_RATE = 166.666667e6; //Hz +static const double X300_DEFAULT_TICK_RATE = 200e6; //Hz +static const double X300_DEFAULT_DBOARD_CLK_RATE = 50e6; //Hz +static const double X300_BUS_CLOCK_RATE = 166.666667e6; //Hz -static const size_t X300_TX_HW_BUFF_SIZE = 520*1024; //512K SRAM buffer + 8K 2Clk FIFO -static const size_t X300_TX_FC_RESPONSE_FREQ = 8; //per flow-control window +static const size_t X300_TX_HW_BUFF_SIZE_SRAM = 520*1024; //512K SRAM buffer + 8K 2Clk FIFO +static const size_t X300_TX_FC_RESPONSE_FREQ_SRAM = 8; //per flow-control window +static const size_t X300_TX_HW_BUFF_SIZE_DRAM = 128*1024; +static const size_t X300_TX_FC_RESPONSE_FREQ_DRAM = 32; +static const boost::uint32_t X300_DRAM_FIFO_SIZE = 32*1024*1024; static const size_t X300_RX_SW_BUFF_SIZE_ETH = 0x2000000;//32MiB For an ~8k frame size any size >32MiB is just wasted buffer space static const size_t X300_RX_SW_BUFF_SIZE_ETH_MACOS = 0x100000; //1Mib @@ -78,6 +82,8 @@ static const size_t X300_10GE_DATA_FRAME_MAX_SIZE = 8000; //bytes static const size_t X300_1GE_DATA_FRAME_MAX_SIZE = 1472; //bytes static const size_t X300_ETH_MSG_FRAME_SIZE = uhd::transport::udp_simple::mtu; //bytes +static const double X300_THREAD_BUFFER_TIMEOUT = 0.1; // Time in seconds + static const size_t X300_ETH_MSG_NUM_FRAMES = 64; static const size_t X300_ETH_DATA_NUM_FRAMES = 32; static const double X300_DEFAULT_SYSREF_RATE = 10e6; @@ -109,7 +115,8 @@ static const size_t X300_MAX_RATE_1GIGE = 100000000; // bytes/s #define X300_XB_DST_PCI 7 #define X300_DEVICE_THERE 2 -#define X300_DEVICE_HERE 0 +#define X300_SRC_ADDR_ETH0 0 +#define X300_SRC_ADDR_ETH1 1 //eeprom addrs for various boards enum @@ -122,14 +129,29 @@ enum X300_DB1_GDB_EEPROM = 0x3, }; +// Ethernet ports +enum x300_eth_iface_t +{ + X300_IFACE_NONE = 0, + X300_IFACE_ETH0 = 1, + X300_IFACE_ETH1 = 2, +}; + +struct x300_eth_conn_t +{ + std::string addr; + x300_eth_iface_t type; +}; + struct x300_dboard_iface_config_t { - gpio_core_200::sptr gpio; + uhd::usrp::gpio_atr::db_gpio_atr_3000::sptr gpio; spi_core_3000::sptr spi; size_t rx_spi_slaveno; size_t tx_spi_slaveno; i2c_core_100_wb32::sptr i2c; x300_clock_ctrl::sptr clock; + rx_dsp_core_3000::sptr rx_dsp; x300_clock_which_t which_rx_clk; x300_clock_which_t which_tx_clk; boost::uint8_t dboard_slot; @@ -139,8 +161,8 @@ struct x300_dboard_iface_config_t uhd::usrp::dboard_iface::sptr x300_make_dboard_iface(const x300_dboard_iface_config_t &); uhd::uart_iface::sptr x300_make_uart_iface(uhd::wb_iface::sptr iface); -uhd::wb_iface::sptr x300_make_ctrl_iface_enet(uhd::transport::udp_simple::sptr udp); -uhd::wb_iface::sptr x300_make_ctrl_iface_pcie(uhd::niusrprio::niriok_proxy::sptr drv_proxy); +uhd::wb_iface::sptr x300_make_ctrl_iface_enet(uhd::transport::udp_simple::sptr udp, bool enable_errors = true); +uhd::wb_iface::sptr x300_make_ctrl_iface_pcie(uhd::niusrprio::niriok_proxy::sptr drv_proxy, bool enable_errors = true); uhd::device_addrs_t x300_find(const uhd::device_addr_t &hint_); @@ -186,7 +208,7 @@ private: rx_dsp_core_3000::sptr ddc; tx_vita_core_3000::sptr deframer; tx_dsp_core_3000::sptr duc; - gpio_core_200_32wo::sptr leds; + uhd::usrp::gpio_atr::gpio_atr_3000::sptr leds; rx_frontend_core_200::sptr rx_fe; tx_frontend_core_200::sptr tx_fe; //Registers @@ -204,9 +226,20 @@ private: bool initialization_done; uhd::task::sptr claimer_task; - std::string addr; std::string xport_path; - int router_dst_here; + + std::vector<x300_eth_conn_t> eth_conns; + + // Discover the ethernet connections per motherboard + void discover_eth(const uhd::usrp::mboard_eeprom_t mb_eeprom, + const std::vector<std::string> &ip_addrs); + + // Get the primary ethernet connection + inline const x300_eth_conn_t& get_pri_eth() const + { + return eth_conns[0]; + } + uhd::device_addr_t send_args; uhd::device_addr_t recv_args; bool if_pkt_is_big_endian; @@ -227,10 +260,14 @@ private: return slot_name == "A" ? 0 : 1; } + bool has_dram_buff; + dma_fifo_core_3000::sptr dram_buff_ctrl[NUM_RADIOS]; + + //other perifs on mboard x300_clock_ctrl::sptr clock; uhd::gps_ctrl::sptr gps; - gpio_core_200::sptr fp_gpio; + uhd::usrp::gpio_atr::gpio_atr_3000::sptr fp_gpio; uhd::usrp::x300::fw_regmap_t::sptr fw_regmap; @@ -274,7 +311,7 @@ private: boost::uint8_t router_addr_there; boost::uint8_t dst_prefix; //2bits boost::uint8_t router_dst_there; - boost::uint8_t router_dst_here; + x300_eth_iface_t iface_index; }; boost::uint32_t allocate_sid(mboard_members_t &mb, const sid_config_t &config); @@ -328,7 +365,6 @@ private: //////////////////////////////////////////////////////////////////// uhd::dict<std::string, uhd::usrp::dboard_manager::sptr> _dboard_managers; - uhd::dict<std::string, uhd::usrp::dboard_iface::sptr> _dboard_ifaces; void set_rx_fe_corrections(const uhd::fs_path &mb_path, const std::string &fe_name, const double lo_freq); void set_tx_fe_corrections(const uhd::fs_path &mb_path, const std::string &fe_name, const double lo_freq); @@ -367,9 +403,7 @@ private: void check_fw_compat(const uhd::fs_path &mb_path, uhd::wb_iface::sptr iface); void check_fpga_compat(const uhd::fs_path &mb_path, const mboard_members_t &members); - void update_atr_leds(gpio_core_200_32wo::sptr, const std::string &ant); - boost::uint32_t get_fp_gpio(gpio_core_200::sptr); - void set_fp_gpio(gpio_core_200::sptr, const gpio_attr_t, const boost::uint32_t); + void update_atr_leds(uhd::usrp::gpio_atr::gpio_atr_3000::sptr, const std::string &ant); void self_cal_adc_capture_delay(mboard_members_t& mb, const size_t radio_i, bool print_status = false); double self_cal_adc_xfer_delay(mboard_members_t& mb, bool apply_delay = false); diff --git a/host/lib/usrp/x300/x300_io_impl.cpp b/host/lib/usrp/x300/x300_io_impl.cpp index e3515af0c..329405261 100644 --- a/host/lib/usrp/x300/x300_io_impl.cpp +++ b/host/lib/usrp/x300/x300_io_impl.cpp @@ -106,17 +106,16 @@ void x300_impl::update_subdev_spec(const std::string &tx_rx, const size_t mb_i, chan_to_dsp_map[i] = radio_idx; //extract connection - const std::string conn = _tree->access<std::string>(mb_root / "dboards" / spec[i].db_name / (tx_rx + "_frontends") / spec[i].sd_name / "connection").get(); - + const fs_path fe_path(mb_root / "dboards" / spec[i].db_name / (tx_rx + "_frontends") / spec[i].sd_name); + const std::string conn = _tree->access<std::string>(fe_path / "connection").get(); if (tx_rx == "tx") { //swap condition _mb[mb_i].radio_perifs[radio_idx].tx_fe->set_mux(conn); } else { - //swap condition - const bool fe_swapped = (conn == "QI" or conn == "Q"); - _mb[mb_i].radio_perifs[radio_idx].ddc->set_mux(conn, fe_swapped); - //see usrp/io_impl.cpp if multiple DSPs share the frontend: - _mb[mb_i].radio_perifs[radio_idx].rx_fe->set_mux(fe_swapped); + double if_freq = (_tree->exists(fe_path / "if_freq/value")) ? + _tree->access<double>(fe_path / "if_freq/value").get() : 0.0; + _mb[mb_i].radio_perifs[radio_idx].ddc->set_mux(usrp::fe_connection_t(conn, if_freq)); + _mb[mb_i].radio_perifs[radio_idx].rx_fe->set_mux(false); } } @@ -216,9 +215,10 @@ struct x300_tx_fc_guts_t * FC credit we have is C = F + M - N (i.e. we can send C more packets * before getting another ack). */ -static size_t get_tx_flow_control_window(size_t frame_size, const device_addr_t& tx_args) +static size_t get_tx_flow_control_window(size_t frame_size, const bool dram_buff, const device_addr_t& tx_args) { - double hw_buff_size = tx_args.cast<double>("send_buff_size", X300_TX_HW_BUFF_SIZE); + double default_buff_size = dram_buff ? X300_TX_HW_BUFF_SIZE_DRAM : X300_TX_HW_BUFF_SIZE_SRAM; + double hw_buff_size = tx_args.cast<double>("send_buff_size", default_buff_size); size_t window_in_pkts = (static_cast<size_t>(hw_buff_size) / frame_size); if (window_in_pkts == 0) { throw uhd::value_error("send_buff_size must be larger than the send_frame_size."); @@ -383,8 +383,8 @@ rx_streamer::sptr x300_impl::get_rx_stream(const uhd::stream_args_t &args_) both_xports_t xport = this->make_transport(mb_index, dest, X300_RADIO_DEST_PREFIX_RX, device_addr, data_sid); UHD_LOG << boost::format("data_sid = 0x%08x, actual recv_buff_size = %d\n") % data_sid % xport.recv_buff_size << std::endl; - // To calculate the max number of samples per packet, we assume the maximum header length - // to avoid fragmentation should the entire header be used. + // To calculate the max number of samples per packet, we assume the maximum header length + // to avoid fragmentation should the entire header be used. const size_t bpp = xport.recv->get_recv_frame_size() - X300_RX_MAX_HDR_LEN; // bytes per packet const size_t bpi = convert::get_bytes_per_item(args.otw_format); // bytes per item const size_t spp = unsigned(args.args.cast<double>("spp", bpp/bpi)); // samples per packet @@ -580,8 +580,9 @@ tx_streamer::sptr x300_impl::get_tx_stream(const uhd::stream_args_t &args_) perif.duc->setup(args); //flow control setup - size_t fc_window = get_tx_flow_control_window(xport.send->get_send_frame_size(), device_addr); //In packets - const size_t fc_handle_window = std::max<size_t>(1, fc_window/X300_TX_FC_RESPONSE_FREQ); + size_t fc_window = get_tx_flow_control_window(xport.send->get_send_frame_size(), mb.has_dram_buff, device_addr); //In packets + const size_t fc_handle_window = std::max<size_t>(1, + fc_window/ (mb.has_dram_buff ? X300_TX_FC_RESPONSE_FREQ_DRAM : X300_TX_FC_RESPONSE_FREQ_SRAM)); UHD_LOG << "TX Flow Control Window = " << fc_window << ", TX Flow Control Handler Window = " << fc_handle_window << std::endl; diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp index 3e0966c83..de3a3161a 100644 --- a/host/lib/usrp/x300/x300_regs.hpp +++ b/host/lib/usrp/x300/x300_regs.hpp @@ -42,7 +42,7 @@ static const uint32_t TIME = 128; static const uint32_t RX_DSP = 144; static const uint32_t TX_DSP = 184; static const uint32_t LEDS = 195; -static const uint32_t FP_GPIO = 200; +static const uint32_t FP_GPIO = 201; static const uint32_t RX_FRONT = 208; static const uint32_t TX_FRONT = 216; @@ -77,6 +77,8 @@ localparam ZPU_SR_XB_LOCAL = 03; localparam ZPU_SR_SPI = 32; localparam ZPU_SR_ETHINT0 = 40; localparam ZPU_SR_ETHINT1 = 56; +localparam ZPU_SR_DRAM_FIFO0 = 72; +localparam ZPU_SR_DRAM_FIFO1 = 80; //reset bits #define ZPU_SR_SW_RST_ETH_PHY (1<<0) @@ -89,6 +91,8 @@ localparam ZPU_RB_CLK_STATUS = 3; localparam ZPU_RB_COMPAT_NUM = 6; localparam ZPU_RB_ETH_TYPE0 = 4; localparam ZPU_RB_ETH_TYPE1 = 5; +localparam ZPU_RB_DRAM_FIFO0 = 10; +localparam ZPU_RB_DRAM_FIFO1 = 11; //spi slaves on radio #define DB_DAC_SEN (1 << 7) |