ath10k: prevent endless pci rx loop
authorMichal Kazior <michal.kazior@tieto.com>
Mon, 21 Jul 2014 18:03:10 +0000 (21:03 +0300)
committerKalle Valo <kvalo@qca.qualcomm.com>
Tue, 22 Jul 2014 18:31:08 +0000 (21:31 +0300)
It was possible to enter an endless loop while
processing a single pci copy engine pipe. This
could effectively render ath10k incapable of
responding to any requests.

An example case when this could happen is when
firmware generates a lot of events, e.g. spectral
scan phyerr via WMI.

Reported-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath10k/pci.c

index 06840d101c45cb74c9fd0655fa943b623cf1f7c6..0ffff205478d3d5bdbf974f0fe090ff265663ba6 100644 (file)
@@ -726,18 +726,12 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
        unsigned int nbytes, max_nbytes;
        unsigned int transfer_id;
        unsigned int flags;
-       int err;
+       int err, num_replenish = 0;
 
        while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,
                                             &ce_data, &nbytes, &transfer_id,
                                             &flags) == 0) {
-               err = ath10k_pci_post_rx_pipe(pipe_info, 1);
-               if (unlikely(err)) {
-                       /* FIXME: retry */
-                       ath10k_warn("failed to replenish CE rx ring %d: %d\n",
-                                   pipe_info->pipe_num, err);
-               }
-
+               num_replenish++;
                skb = transfer_context;
                max_nbytes = skb->len + skb_tailroom(skb);
                dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,
@@ -753,6 +747,13 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
                skb_put(skb, nbytes);
                cb->rx_completion(ar, skb, pipe_info->pipe_num);
        }
+
+       err = ath10k_pci_post_rx_pipe(pipe_info, num_replenish);
+       if (unlikely(err)) {
+               /* FIXME: retry */
+               ath10k_warn("failed to replenish CE rx ring %d (%d bufs): %d\n",
+                           pipe_info->pipe_num, num_replenish, err);
+       }
 }
 
 static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,