aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAshish Chaudhari <ashish@ettus.com>2018-07-19 17:08:45 -0700
committerMartin Braun <martin.braun@ettus.com>2018-07-24 14:39:08 -0700
commit8b16ab706fb4768f802ddb65a81fc26e1562cb0d (patch)
tree884a58e82ede9298795308688e898a01c931ac1f
parentdd9cc213ca5bd49783b3942d8486278aed8735c8 (diff)
downloaduhd-8b16ab706fb4768f802ddb65a81fc26e1562cb0d.tar.gz
uhd-8b16ab706fb4768f802ddb65a81fc26e1562cb0d.tar.bz2
uhd-8b16ab706fb4768f802ddb65a81fc26e1562cb0d.zip
rfnoc: Enabled SW flush mechanism impl'd in noc_shell
- UHD will now "disconnect" the noc_block data-path from the crossbar when the block's dtor is invoked. This allows long running or slow blocks to empty out rapidly during teardown. - UHD will also attempt to flush at init time in case a block is destroyed abnormally. The goal of the flush mechanism is to not lock up the FPGA - noc_shell compat number is now 3
m---------fpga-src0
-rw-r--r--host/include/uhd/rfnoc/block_ctrl_base.hpp3
-rw-r--r--host/include/uhd/rfnoc/constants.hpp2
-rw-r--r--host/lib/rfnoc/block_ctrl_base.cpp86
-rw-r--r--host/lib/usrp/device3/device3_io_impl.cpp6
-rw-r--r--images/manifest.txt10
6 files changed, 97 insertions, 10 deletions
diff --git a/fpga-src b/fpga-src
-Subproject 2e310fae0a6a7354c250fca36060daaeaac1535
+Subproject f27926410328883a315d5230146936d2d782bd0
diff --git a/host/include/uhd/rfnoc/block_ctrl_base.hpp b/host/include/uhd/rfnoc/block_ctrl_base.hpp
index 63939a114..0405ed8b7 100644
--- a/host/include/uhd/rfnoc/block_ctrl_base.hpp
+++ b/host/include/uhd/rfnoc/block_ctrl_base.hpp
@@ -401,6 +401,9 @@ private:
//! Helper to create a lambda to read tick rate
double get_command_tick_rate(const size_t port);
+ //! Helper to flush any in-flight packets for this block
+ bool _flush(const size_t port = 0);
+
/***********************************************************************
* Private members
**********************************************************************/
diff --git a/host/include/uhd/rfnoc/constants.hpp b/host/include/uhd/rfnoc/constants.hpp
index 94cca3e7a..6df4c535f 100644
--- a/host/include/uhd/rfnoc/constants.hpp
+++ b/host/include/uhd/rfnoc/constants.hpp
@@ -25,7 +25,7 @@ static const std::string XML_PATH_ENV = "UHD_RFNOC_DIR";
//! If the block name can't be automatically detected, this name is used
static const std::string DEFAULT_BLOCK_NAME = "Block";
static const uint64_t DEFAULT_NOC_ID = 0xFFFFFFFFFFFFFFFF;
-static const size_t NOC_SHELL_COMPAT_MAJOR = 2;
+static const size_t NOC_SHELL_COMPAT_MAJOR = 3;
static const size_t NOC_SHELL_COMPAT_MINOR = 0;
static const size_t MAX_PACKET_SIZE = 8000; // bytes
diff --git a/host/lib/rfnoc/block_ctrl_base.cpp b/host/lib/rfnoc/block_ctrl_base.cpp
index 0b9f6d281..c7884f291 100644
--- a/host/lib/rfnoc/block_ctrl_base.cpp
+++ b/host/lib/rfnoc/block_ctrl_base.cpp
@@ -19,6 +19,8 @@
#include <uhdlib/rfnoc/wb_iface_adapter.hpp>
#include <boost/format.hpp>
#include <boost/bind.hpp>
+#include <chrono>
+#include <thread>
using namespace uhd;
using namespace uhd::rfnoc;
@@ -72,6 +74,20 @@ block_ctrl_base::block_ctrl_base(
_tree->create<uint64_t>(_root_path / "noc_id").set(_noc_id);
/*** Reset block state *******************************************/
+ // We don't know the state of the data-path of this block before
+ // we initialize. If everything tore down properly, the data-path
+ // should be disconnected and thus idle. Reconfiguration of parameters
+ // like SIDs is safe to do in that scenario.
+ // However, if data is still streaming, block configuration
+ // can potentially lock up noc_shell. So we flush the data-path here.
+
+ // Flush is a block-level operation that can be triggered
+ // from any block port.
+ // Do it once before clearing...
+ if (get_ctrl_ports().size() > 0) {
+ _flush(get_ctrl_ports().front());
+ }
+ // Clear flow control and misc state
clear();
/*** Configure ports ****************************************************/
@@ -129,6 +145,17 @@ block_ctrl_base::block_ctrl_base(
block_ctrl_base::~block_ctrl_base()
{
+ if (get_ctrl_ports().size() > 0) {
+ // Notify the data-path gatekeeper in noc_shell that we are done
+ // with this block. This operation disconnects the noc_block
+ // data-path from noc_shell which dumps all input and output
+ // packets that are in flight, for now and until the setting is
+ // disabled. This prevents long-running blocks without a tear-down
+ // mechanism to gracefully flush.
+ const size_t port = get_ctrl_ports().front();
+ sr_write(SR_CLEAR_TX_FC, 0x2, port); // Disconnect TX data-path
+ sr_write(SR_CLEAR_RX_FC, 0x2, port); // Disconnect RX data-path
+ }
_tree->remove(_root_path);
}
@@ -558,6 +585,59 @@ stream_sig_t block_ctrl_base::_resolve_port_def(const blockdef::port_t &port_def
return stream_sig;
}
+bool block_ctrl_base::_flush(const size_t port)
+{
+ UHD_LOG_DEBUG(unique_id(), "block_ctrl_base::_flush()");
+
+ auto is_data_streaming = [this](int time_ms) -> bool {
+ // noc_shell has 2 16-bit counters (one for TX and one for RX) in the top
+ // 32 bits of the SR_READBACK_REG_GLOBAL_PARAMS. For all the checks below
+ // we want to make sure that the counts are not changing i.e. no data is
+ // streaming. So we just look at the two counters together as a single
+ // 32-bit quantity.
+ auto old_cnts = static_cast<uint32_t>(this->sr_read64(SR_READBACK_REG_GLOBAL_PARAMS) >> 32);
+ std::this_thread::sleep_for(std::chrono::milliseconds(time_ms));
+ auto new_cnts = static_cast<uint32_t>(this->sr_read64(SR_READBACK_REG_GLOBAL_PARAMS) >> 32);
+ return (new_cnts != old_cnts);
+ };
+
+ // Initial check for activity
+ // We use a 10ms window to check for activity which detects a stream with approx
+ // 100 packets per second
+ constexpr int INITIAL_CHK_WINDOW_MS = 10;
+ if (not is_data_streaming(INITIAL_CHK_WINDOW_MS)) return true;
+
+ UHD_LOG_DEBUG(unique_id(), "block_ctrl_base::_flush(recovery mode)");
+ // We noticed streaming data. This is most likely because the last
+ // session terminated abnormally or if logic in a noc_block is
+ // misbehaving. This is a situation that we may not be able to
+ // recover from because we are in a partially initialized state.
+ // We will try to at least not lock up the FPGA.
+
+ // Disconnect the RX and TX data paths and let them flush.
+ // A timeout of 2s is chosen to be conservative. It needs to account for:
+ // - Upstream blocks that weren't terminated to run out of FC credits
+ // - This block which might be finishing up with its data output
+ constexpr int FLUSH_TIMEOUT_MS = 2000; // This is approximate
+ bool success = false;
+ sr_write(SR_CLEAR_TX_FC, 0x2, port); // Disconnect TX data-path
+ sr_write(SR_CLEAR_RX_FC, 0x2, port); // Disconnect RX data-path
+ for (int i = 0; i < FLUSH_TIMEOUT_MS/10; i++) {
+ if (not is_data_streaming(10)) {
+ success = true;
+ break;
+ }
+ }
+ sr_write(SR_CLEAR_TX_FC, 0x0, port); // Enable TX data-path
+ sr_write(SR_CLEAR_RX_FC, 0x0, port); // Enable RX data-path
+
+ UHD_LOGGER_WARNING(unique_id()) <<
+ "This block seems to be busy most likely due to the abnormal termination of a previous session. " <<
+ "Attempted recovery but it may not have worked depending on the behavior of other blocks in the design. " <<
+ "Please restart the application.";
+ return success;
+}
+
/***********************************************************************
* Hooks & Derivables
@@ -565,8 +645,10 @@ stream_sig_t block_ctrl_base::_resolve_port_def(const blockdef::port_t &port_def
void block_ctrl_base::_clear(const size_t port)
{
UHD_LOG_TRACE(unique_id(), "block_ctrl_base::_clear()");
- sr_write(SR_CLEAR_TX_FC, 0x00C1EA12, port); // 'CLEAR', but we can write anything, really
- sr_write(SR_CLEAR_RX_FC, 0x00C1EA12, port); // 'CLEAR', but we can write anything, really
+ sr_write(SR_CLEAR_TX_FC, 0x1, port); // Write 1 to trigger a single cycle clear event
+ sr_write(SR_CLEAR_TX_FC, 0x0, port); // Write 0 to reset the clear flag
+ sr_write(SR_CLEAR_RX_FC, 0x1, port); // Write 1 to trigger a single cycle clear event
+ sr_write(SR_CLEAR_RX_FC, 0x0, port); // Write 0 to reset the clear flag
}
void block_ctrl_base::_set_command_time(const time_spec_t & /*time_spec*/, const size_t /*port*/)
diff --git a/host/lib/usrp/device3/device3_io_impl.cpp b/host/lib/usrp/device3/device3_io_impl.cpp
index 236269ceb..8882552af 100644
--- a/host/lib/usrp/device3/device3_io_impl.cpp
+++ b/host/lib/usrp/device3/device3_io_impl.cpp
@@ -556,7 +556,8 @@ rx_streamer::sptr device3_impl::get_rx_stream(const stream_args_t &args_)
// See noc_shell.v, in the section called Stream Source for details.
// Setting SR_CLEAR_TX_FC will actually also clear the destination and
// other settings.
- blk_ctrl->sr_write(uhd::rfnoc::SR_CLEAR_TX_FC, 0xc1ea12, block_port);
+ blk_ctrl->sr_write(uhd::rfnoc::SR_CLEAR_TX_FC, 0x1, block_port);
+ blk_ctrl->sr_write(uhd::rfnoc::SR_CLEAR_TX_FC, 0x0, block_port);
blk_ctrl->set_destination(xport.send_sid.get_src(), block_port);
blk_ctrl->sr_write(uhd::rfnoc::SR_RESP_OUT_DST_SID, xport.send_sid.get_src(), block_port);
@@ -845,7 +846,8 @@ tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_)
"tx_async_msgs_task"
);
- blk_ctrl->sr_write(uhd::rfnoc::SR_CLEAR_RX_FC, 0xc1ea12, block_port);
+ blk_ctrl->sr_write(uhd::rfnoc::SR_CLEAR_RX_FC, 0x1, block_port);
+ blk_ctrl->sr_write(uhd::rfnoc::SR_CLEAR_RX_FC, 0x0, block_port);
blk_ctrl->sr_write(uhd::rfnoc::SR_RESP_IN_DST_SID, my_streamer->_async_xport.recv_sid.get_dst(), block_port);
UHD_TX_STREAMER_LOG() << "resp_in_dst_sid == " << boost::format("0x%04X") % xport.recv_sid.get_dst() ;
diff --git a/images/manifest.txt b/images/manifest.txt
index 3fcf88342..266f564ab 100644
--- a/images/manifest.txt
+++ b/images/manifest.txt
@@ -1,18 +1,18 @@
# UHD Image Manifest File
# Target hash url SHA256
# X300-Series
-x3xx_x310_fpga_default fpga-1107862 x3xx/fpga-1107862/x3xx_x310_fpga_default-g1107862.zip e1f59031b7c7f5fa166a46636c7b12df6ede5470138cfb71e3860e2945f180e8
-x3xx_x300_fpga_default fpga-1107862 x3xx/fpga-1107862/x3xx_x300_fpga_default-g1107862.zip f90a760837bea61d144cf9940ac24db72959ad075444de0d94c2724a78beb402
+x3xx_x310_fpga_default fpga-f279264 x3xx/fpga-f279264/x3xx_x310_fpga_default-gf279264.zip a9d0f4b9f75bca4724333f3320989b2f9a56cf75e3a7bc569b4e868af3feb095
+x3xx_x300_fpga_default fpga-f279264 x3xx/fpga-f279264/x3xx_x300_fpga_default-gf279264.zip 872c3833dc03ed8ff5a6dea2053d7ccb353a63ba760b82c4a48c3c3b839a725c
# Example daughterboard targets (none currently exist)
#x3xx_twinrx_cpld_default example_target
#dboard_ubx_cpld_default example_target
# E-Series
-e3xx_e310_fpga_default fpga-1107862 e3xx/fpga-1107862/e3xx_e310_fpga_default-g1107862.zip 52f8451fd459b2a3113903284adea11474a9efb8eaef45b986233c0693f10549
+e3xx_e310_fpga_default fpga-f279264 e3xx/fpga-f279264/e3xx_e310_fpga_default-gf279264.zip 707428e8703b29ad9df60725f25fed78223deab5f4a7becf4ed1886b43f18f92
e3xx_e310_fpga_rfnoc fpga-d6a878b e3xx/fpga-d6a878b/e3xx_e310_fpga_rfnoc-gd6a878b.zip 5c9b89fb6293423644868c22e914de386a9af39ff031da6800a1cf39a90ea73b
# N300-Series
-n3xx_n310_fpga_default fpga-1107862 n3xx/fpga-1107862/n3xx_n310_fpga_default-g1107862.zip fc80462f2e144d9745b0b480aa513f426e48df46ad18dc85cbb8fdb3cb162355
-n3xx_n300_fpga_default fpga-1107862 n3xx/fpga-1107862/n3xx_n300_fpga_default-g1107862.zip 1e7ae1429825811531149f87f82dfcbc06cf63e1fc3752517edf104950406c36
+n3xx_n310_fpga_default fpga-f279264 n3xx/fpga-f279264/n3xx_n310_fpga_default-gf279264.zip e31c2a71014e7fdb140e00ef3f6e9814b720e0f8de4544d2bad8a50cf1c61ce1
+n3xx_n300_fpga_default fpga-f279264 n3xx/fpga-f279264/n3xx_n300_fpga_default-gf279264.zip 83f880d2b79f666a8fe660aa949cd1c1eaf5256d31036696fd270ae59491acc6
#n3xx_n310_fpga_aurora fpga-1107862 n3xx/fpga-1107862/n3xx_n310_fpga_aurora-g1107862.zip 3926d6b247a8f931809460d3957cec51f8407cd3f7aea6f4f3b91d1bbb427c7d
#n3xx_n300_fpga_aurora fpga-1107862 n3xx/fpga-1107862/n3xx_n300_fpga_aurora-g1107862.zip e34e9343572adfba905433a1570cb394fe45207d442268d0fa400c3406253530
#n3xx_n310_cpld_default fpga-6bea23d n3xx/fpga-6bea23d/n3xx_n310_cpld_default-g6bea23d.zip 0