+static int check_for_tx_completion_in_queue(struct ena_adapter *adapter,
+ struct ena_ring *tx_ring)
+{
+ struct ena_tx_buffer *tx_buf;
+ uint64_t timestamp;
+ uint64_t completion_delay;
+ uint32_t missed_tx = 0;
+ unsigned int i;
+ int rc = 0;
+
+ for (i = 0; i < tx_ring->ring_size; ++i) {
+ tx_buf = &tx_ring->tx_buffer_info[i];
+ timestamp = tx_buf->timestamp;
+
+ if (timestamp == 0)
+ continue;
+
+ completion_delay = rte_get_timer_cycles() - timestamp;
+ if (completion_delay > adapter->missing_tx_completion_to) {
+ if (unlikely(!tx_buf->print_once)) {
+ PMD_TX_LOG(WARNING,
+ "Found a Tx that wasn't completed on time, qid %d, index %d. "
+ "Missing Tx outstanding for %" PRIu64 " msecs.\n",
+ tx_ring->id, i, completion_delay /
+ rte_get_timer_hz() * 1000);
+ tx_buf->print_once = true;
+ }
+ ++missed_tx;
+ }
+ }
+
+ if (unlikely(missed_tx > tx_ring->missing_tx_completion_threshold)) {
+ PMD_DRV_LOG(ERR,
+ "The number of lost Tx completions is above the threshold (%d > %d). "
+ "Trigger the device reset.\n",
+ missed_tx,
+ tx_ring->missing_tx_completion_threshold);
+ adapter->reset_reason = ENA_REGS_RESET_MISS_TX_CMPL;
+ adapter->trigger_reset = true;
+ rc = -EIO;
+ }
+
+ tx_ring->tx_stats.missed_tx += missed_tx;
+
+ return rc;
+}
+
+static void check_for_tx_completions(struct ena_adapter *adapter)
+{
+ struct ena_ring *tx_ring;
+ uint64_t tx_cleanup_delay;
+ size_t qid;
+ int budget;
+ uint16_t nb_tx_queues = adapter->edev_data->nb_tx_queues;
+
+ if (adapter->missing_tx_completion_to == ENA_HW_HINTS_NO_TIMEOUT)
+ return;
+
+ nb_tx_queues = adapter->edev_data->nb_tx_queues;
+ budget = adapter->missing_tx_completion_budget;
+
+ qid = adapter->last_tx_comp_qid;
+ while (budget-- > 0) {
+ tx_ring = &adapter->tx_ring[qid];
+
+ /* Tx cleanup is called only by the burst function and can be
+ * called dynamically by the application. Also cleanup is
+ * limited by the threshold. To avoid false detection of the
+ * missing HW Tx completion, get the delay since last cleanup
+ * function was called.
+ */
+ tx_cleanup_delay = rte_get_timer_cycles() -
+ tx_ring->last_cleanup_ticks;
+ if (tx_cleanup_delay < adapter->tx_cleanup_stall_delay)
+ check_for_tx_completion_in_queue(adapter, tx_ring);
+ qid = (qid + 1) % nb_tx_queues;
+ }
+
+ adapter->last_tx_comp_qid = qid;
+}
+