diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2014-07-21 14:03:10 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2014-07-22 14:31:08 -0400 |
commit | c29a380e4a8157f8bf6a91c216a77439a293c93d (patch) | |
tree | 65a68c69c59b804f56ab0af4f1179d8ea3d4abd5 /drivers/net/wireless/ath | |
parent | c21c64d145e64d92a6c8f8e13c9b6b5b711832eb (diff) |
ath10k: prevent endless pci rx loop
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>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/pci.c | 17 |
1 files changed, 9 insertions, 8 deletions
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 06840d101c45..0ffff205478d 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c | |||
@@ -726,18 +726,12 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) | |||
726 | unsigned int nbytes, max_nbytes; | 726 | unsigned int nbytes, max_nbytes; |
727 | unsigned int transfer_id; | 727 | unsigned int transfer_id; |
728 | unsigned int flags; | 728 | unsigned int flags; |
729 | int err; | 729 | int err, num_replenish = 0; |
730 | 730 | ||
731 | while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, | 731 | while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, |
732 | &ce_data, &nbytes, &transfer_id, | 732 | &ce_data, &nbytes, &transfer_id, |
733 | &flags) == 0) { | 733 | &flags) == 0) { |
734 | err = ath10k_pci_post_rx_pipe(pipe_info, 1); | 734 | num_replenish++; |
735 | if (unlikely(err)) { | ||
736 | /* FIXME: retry */ | ||
737 | ath10k_warn("failed to replenish CE rx ring %d: %d\n", | ||
738 | pipe_info->pipe_num, err); | ||
739 | } | ||
740 | |||
741 | skb = transfer_context; | 735 | skb = transfer_context; |
742 | max_nbytes = skb->len + skb_tailroom(skb); | 736 | max_nbytes = skb->len + skb_tailroom(skb); |
743 | dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, | 737 | 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) | |||
753 | skb_put(skb, nbytes); | 747 | skb_put(skb, nbytes); |
754 | cb->rx_completion(ar, skb, pipe_info->pipe_num); | 748 | cb->rx_completion(ar, skb, pipe_info->pipe_num); |
755 | } | 749 | } |
750 | |||
751 | err = ath10k_pci_post_rx_pipe(pipe_info, num_replenish); | ||
752 | if (unlikely(err)) { | ||
753 | /* FIXME: retry */ | ||
754 | ath10k_warn("failed to replenish CE rx ring %d (%d bufs): %d\n", | ||
755 | pipe_info->pipe_num, num_replenish, err); | ||
756 | } | ||
756 | } | 757 | } |
757 | 758 | ||
758 | static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, | 759 | static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, |