#endif
 
-/**
- * i40e_detect_recover_hung_queue - Function to detect and recover hung_queue
- * @q_idx: TX queue number
- * @vsi: Pointer to VSI struct
- *
- * This function checks specified queue for given VSI. Detects hung condition.
- * We proactively detect hung TX queues by checking if interrupts are disabled
- * but there are pending descriptors.  If it appears hung, attempt to recover
- * by triggering a SW interrupt.
- **/
-static void i40e_detect_recover_hung_queue(int q_idx, struct i40e_vsi *vsi)
-{
-       struct i40e_ring *tx_ring = NULL;
-       struct i40e_pf  *pf;
-       u32 val, tx_pending;
-       int i;
-
-       pf = vsi->back;
-
-       /* now that we have an index, find the tx_ring struct */
-       for (i = 0; i < vsi->num_queue_pairs; i++) {
-               if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc) {
-                       if (q_idx == vsi->tx_rings[i]->queue_index) {
-                               tx_ring = vsi->tx_rings[i];
-                               break;
-                       }
-               }
-       }
-
-       if (!tx_ring)
-               return;
-
-       /* Read interrupt register */
-       if (pf->flags & I40E_FLAG_MSIX_ENABLED)
-               val = rd32(&pf->hw,
-                          I40E_PFINT_DYN_CTLN(tx_ring->q_vector->v_idx +
-                                              tx_ring->vsi->base_vector - 1));
-       else
-               val = rd32(&pf->hw, I40E_PFINT_DYN_CTL0);
-
-       tx_pending = i40e_get_tx_pending(tx_ring);
-
-       /* Interrupts are disabled and TX pending is non-zero,
-        * trigger the SW interrupt (don't wait). Worst case
-        * there will be one extra interrupt which may result
-        * into not cleaning any queues because queues are cleaned.
-        */
-       if (tx_pending && (!(val & I40E_PFINT_DYN_CTLN_INTENA_MASK)))
-               i40e_force_wb(vsi, tx_ring->q_vector);
-}
-
-/**
- * i40e_detect_recover_hung - Function to detect and recover hung_queues
- * @pf:  pointer to PF struct
- *
- * LAN VSI has netdev and netdev has TX queues. This function is to check
- * each of those TX queues if they are hung, trigger recovery by issuing
- * SW interrupt.
- **/
-static void i40e_detect_recover_hung(struct i40e_pf *pf)
-{
-       struct net_device *netdev;
-       struct i40e_vsi *vsi;
-       unsigned int i;
-
-       /* Only for LAN VSI */
-       vsi = pf->vsi[pf->lan_vsi];
-
-       if (!vsi)
-               return;
-
-       /* Make sure, VSI state is not DOWN/RECOVERY_PENDING */
-       if (test_bit(__I40E_VSI_DOWN, vsi->back->state) ||
-           test_bit(__I40E_RESET_RECOVERY_PENDING, vsi->back->state))
-               return;
-
-       /* Make sure type is MAIN VSI */
-       if (vsi->type != I40E_VSI_MAIN)
-               return;
-
-       netdev = vsi->netdev;
-       if (!netdev)
-               return;
-
-       /* Bail out if netif_carrier is not OK */
-       if (!netif_carrier_ok(netdev))
-               return;
-
-       /* Go thru' TX queues for netdev */
-       for (i = 0; i < netdev->num_tx_queues; i++) {
-               struct netdev_queue *q;
-
-               q = netdev_get_tx_queue(netdev, i);
-               if (q)
-                       i40e_detect_recover_hung_queue(i, vsi);
-       }
-}
-
 /**
  * i40e_get_iscsi_tc_map - Return TC map for iSCSI APP
  * @pf: pointer to PF
        if (test_and_set_bit(__I40E_SERVICE_SCHED, pf->state))
                return;
 
-       i40e_detect_recover_hung(pf);
+       i40e_detect_recover_hung(pf->vsi[pf->lan_vsi]);
        i40e_sync_filters_subtask(pf);
        i40e_reset_subtask(pf);
        i40e_handle_mdd_event(pf);
 
        return 0;
 }
 
+/**
+ * i40e_detect_recover_hung - Function to detect and recover hung_queues
+ * @vsi:  pointer to vsi struct with tx queues
+ *
+ * VSI has netdev and netdev has TX queues. This function is to check each of
+ * those TX queues if they are hung, trigger recovery by issuing SW interrupt.
+ **/
+void i40e_detect_recover_hung(struct i40e_vsi *vsi)
+{
+       struct i40e_ring *tx_ring = NULL;
+       struct net_device *netdev;
+       unsigned int i;
+       int packets;
+
+       if (!vsi)
+               return;
+
+       if (test_bit(__I40E_VSI_DOWN, vsi->state))
+               return;
+
+       netdev = vsi->netdev;
+       if (!netdev)
+               return;
+
+       if (!netif_carrier_ok(netdev))
+               return;
+
+       for (i = 0; i < vsi->num_queue_pairs; i++) {
+               tx_ring = vsi->tx_rings[i];
+               if (tx_ring && tx_ring->desc) {
+                       /* If packet counter has not changed the queue is
+                        * likely stalled, so force an interrupt for this
+                        * queue.
+                        *
+                        * prev_pkt_ctr would be negative if there was no
+                        * pending work.
+                        */
+                       packets = tx_ring->stats.packets & INT_MAX;
+                       if (tx_ring->tx_stats.prev_pkt_ctr == packets) {
+                               i40e_force_wb(vsi, tx_ring->q_vector);
+                               continue;
+                       }
+
+                       /* Memory barrier between read of packet count and call
+                        * to i40e_get_tx_pending()
+                        */
+                       smp_rmb();
+                       tx_ring->tx_stats.prev_pkt_ctr =
+                           i40e_get_tx_pending(tx_ring) ? packets : -1;
+               }
+       }
+}
+
 #define WB_STRIDE 4
 
 /**
 
        tx_ring->next_to_use = 0;
        tx_ring->next_to_clean = 0;
+       tx_ring->tx_stats.prev_pkt_ctr = -1;
        return 0;
 
 err:
 
        u64 tx_done_old;
        u64 tx_linearize;
        u64 tx_force_wb;
+       int prev_pkt_ctr;
 };
 
 struct i40e_rx_queue_stats {
 int i40e_napi_poll(struct napi_struct *napi, int budget);
 void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector);
 u32 i40e_get_tx_pending(struct i40e_ring *ring);
+void i40e_detect_recover_hung(struct i40e_vsi *vsi);
 int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size);
 bool __i40e_chk_linearize(struct sk_buff *skb);
 
 
        return 0;
 }
 
+/**
+ * i40evf_detect_recover_hung - Function to detect and recover hung_queues
+ * @vsi:  pointer to vsi struct with tx queues
+ *
+ * VSI has netdev and netdev has TX queues. This function is to check each of
+ * those TX queues if they are hung, trigger recovery by issuing SW interrupt.
+ **/
+void i40evf_detect_recover_hung(struct i40e_vsi *vsi)
+{
+       struct i40e_ring *tx_ring = NULL;
+       struct net_device *netdev;
+       unsigned int i;
+       int packets;
+
+       if (!vsi)
+               return;
+
+       if (test_bit(__I40E_VSI_DOWN, vsi->state))
+               return;
+
+       netdev = vsi->netdev;
+       if (!netdev)
+               return;
+
+       if (!netif_carrier_ok(netdev))
+               return;
+
+       for (i = 0; i < vsi->back->num_active_queues; i++) {
+               tx_ring = &vsi->back->tx_rings[i];
+               if (tx_ring && tx_ring->desc) {
+                       /* If packet counter has not changed the queue is
+                        * likely stalled, so force an interrupt for this
+                        * queue.
+                        *
+                        * prev_pkt_ctr would be negative if there was no
+                        * pending work.
+                        */
+                       packets = tx_ring->stats.packets & INT_MAX;
+                       if (tx_ring->tx_stats.prev_pkt_ctr == packets) {
+                               i40evf_force_wb(vsi, tx_ring->q_vector);
+                               continue;
+                       }
+
+                       /* Memory barrier between read of packet count and call
+                        * to i40evf_get_tx_pending()
+                        */
+                       smp_rmb();
+                       tx_ring->tx_stats.prev_pkt_ctr =
+                         i40evf_get_tx_pending(tx_ring, false) ? packets : -1;
+               }
+       }
+}
+
 #define WB_STRIDE 4
 
 /**
 
        tx_ring->next_to_use = 0;
        tx_ring->next_to_clean = 0;
+       tx_ring->tx_stats.prev_pkt_ctr = -1;
        return 0;
 
 err:
 
        u64 tx_done_old;
        u64 tx_linearize;
        u64 tx_force_wb;
+       int prev_pkt_ctr;
        u64 tx_lost_interrupt;
 };
 
 int i40evf_napi_poll(struct napi_struct *napi, int budget);
 void i40evf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector);
 u32 i40evf_get_tx_pending(struct i40e_ring *ring, bool in_sw);
+void i40evf_detect_recover_hung(struct i40e_vsi *vsi);
 int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size);
 bool __i40evf_chk_linearize(struct sk_buff *skb);
 
 
        if (adapter->state == __I40EVF_RUNNING)
                i40evf_request_stats(adapter);
 watchdog_done:
+       if (adapter->state == __I40EVF_RUNNING)
+               i40evf_detect_recover_hung(&adapter->vsi);
        clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
 restart_watchdog:
        if (adapter->state == __I40EVF_REMOVE)