diff options
Diffstat (limited to 'drivers/net/ethernet/amazon/ena/ena_netdev.c')
-rw-r--r-- | drivers/net/ethernet/amazon/ena/ena_netdev.c | 68 |
1 files changed, 61 insertions, 7 deletions
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index fbe21a817bd8..6975150d144e 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -161,6 +161,8 @@ static void ena_init_io_rings_common(struct ena_adapter *adapter, ring->per_napi_packets = 0; ring->per_napi_bytes = 0; ring->cpu = 0; + ring->first_interrupt = false; + ring->no_interrupt_event_cnt = 0; u64_stats_init(&ring->syncp); } @@ -1277,6 +1279,9 @@ static irqreturn_t ena_intr_msix_io(int irq, void *data) { struct ena_napi *ena_napi = data; + ena_napi->tx_ring->first_interrupt = true; + ena_napi->rx_ring->first_interrupt = true; + napi_schedule_irqoff(&ena_napi->napi); return IRQ_HANDLED; @@ -2663,8 +2668,32 @@ static void ena_fw_reset_device(struct work_struct *work) rtnl_unlock(); } -static int check_missing_comp_in_queue(struct ena_adapter *adapter, - struct ena_ring *tx_ring) +static int check_for_rx_interrupt_queue(struct ena_adapter *adapter, + struct ena_ring *rx_ring) +{ + if (likely(rx_ring->first_interrupt)) + return 0; + + if (ena_com_cq_empty(rx_ring->ena_com_io_cq)) + return 0; + + rx_ring->no_interrupt_event_cnt++; + + if (rx_ring->no_interrupt_event_cnt == ENA_MAX_NO_INTERRUPT_ITERATIONS) { + netif_err(adapter, rx_err, adapter->netdev, + "Potential MSIX issue on Rx side Queue = %d. Reset the device\n", + rx_ring->qid); + adapter->reset_reason = ENA_REGS_RESET_MISS_INTERRUPT; + smp_mb__before_atomic(); + set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); + return -EIO; + } + + return 0; +} + +static int check_missing_comp_in_tx_queue(struct ena_adapter *adapter, + struct ena_ring *tx_ring) { struct ena_tx_buffer *tx_buf; unsigned long last_jiffies; @@ -2674,8 +2703,27 @@ static int check_missing_comp_in_queue(struct ena_adapter *adapter, for (i = 0; i < tx_ring->ring_size; i++) { tx_buf = &tx_ring->tx_buffer_info[i]; last_jiffies = tx_buf->last_jiffies; - if (unlikely(last_jiffies && - time_is_before_jiffies(last_jiffies + adapter->missing_tx_completion_to))) { + + if (last_jiffies == 0) + /* no pending Tx at this location */ + continue; + + if (unlikely(!tx_ring->first_interrupt && time_is_before_jiffies(last_jiffies + + 2 * adapter->missing_tx_completion_to))) { + /* If after graceful period interrupt is still not + * received, we schedule a reset + */ + netif_err(adapter, tx_err, adapter->netdev, + "Potential MSIX issue on Tx side Queue = %d. Reset the device\n", + tx_ring->qid); + adapter->reset_reason = ENA_REGS_RESET_MISS_INTERRUPT; + smp_mb__before_atomic(); + set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); + return -EIO; + } + + if (unlikely(time_is_before_jiffies(last_jiffies + + adapter->missing_tx_completion_to))) { if (!tx_buf->print_once) netif_notice(adapter, tx_err, adapter->netdev, "Found a Tx that wasn't completed on time, qid %d, index %d.\n", @@ -2704,9 +2752,10 @@ static int check_missing_comp_in_queue(struct ena_adapter *adapter, return rc; } -static void check_for_missing_tx_completions(struct ena_adapter *adapter) +static void check_for_missing_completions(struct ena_adapter *adapter) { struct ena_ring *tx_ring; + struct ena_ring *rx_ring; int i, budget, rc; /* Make sure the driver doesn't turn the device in other process */ @@ -2725,8 +2774,13 @@ static void check_for_missing_tx_completions(struct ena_adapter *adapter) for (i = adapter->last_monitored_tx_qid; i < adapter->num_queues; i++) { tx_ring = &adapter->tx_ring[i]; + rx_ring = &adapter->rx_ring[i]; + + rc = check_missing_comp_in_tx_queue(adapter, tx_ring); + if (unlikely(rc)) + return; - rc = check_missing_comp_in_queue(adapter, tx_ring); + rc = check_for_rx_interrupt_queue(adapter, rx_ring); if (unlikely(rc)) return; @@ -2885,7 +2939,7 @@ static void ena_timer_service(struct timer_list *t) check_for_admin_com_state(adapter); - check_for_missing_tx_completions(adapter); + check_for_missing_completions(adapter); check_for_empty_rx_ring(adapter); |