diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2014-11-27 05:09:38 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2014-12-01 02:27:27 -0500 |
commit | 1cb86d47d43fee49e9d5b13e742bce811bb59512 (patch) | |
tree | 9029b1480c5e2e7111efc49dcfe2bfaedaa9a7a3 /drivers/net/wireless/ath/ath10k/pci.c | |
parent | d84a512dca23c4330be4d4ffaf29b4d49438f12e (diff) |
ath10k: prevent pci tx/rx starvation
In theory it was possible to starve the system if
a tx/rx handler could implicitly trigger more
tx/rx pci events.
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/ath10k/pci.c')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/pci.c | 21 |
1 files changed, 15 insertions, 6 deletions
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 95e90668f67c..7abb8367119a 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c | |||
@@ -823,20 +823,24 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state) | |||
823 | struct ath10k *ar = ce_state->ar; | 823 | struct ath10k *ar = ce_state->ar; |
824 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 824 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
825 | struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; | 825 | struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; |
826 | void *transfer_context; | 826 | struct sk_buff_head list; |
827 | struct sk_buff *skb; | ||
827 | u32 ce_data; | 828 | u32 ce_data; |
828 | unsigned int nbytes; | 829 | unsigned int nbytes; |
829 | unsigned int transfer_id; | 830 | unsigned int transfer_id; |
830 | 831 | ||
831 | while (ath10k_ce_completed_send_next(ce_state, &transfer_context, | 832 | __skb_queue_head_init(&list); |
832 | &ce_data, &nbytes, | 833 | while (ath10k_ce_completed_send_next(ce_state, (void **)&skb, &ce_data, |
833 | &transfer_id) == 0) { | 834 | &nbytes, &transfer_id) == 0) { |
834 | /* no need to call tx completion for NULL pointers */ | 835 | /* no need to call tx completion for NULL pointers */ |
835 | if (transfer_context == NULL) | 836 | if (skb == NULL) |
836 | continue; | 837 | continue; |
837 | 838 | ||
838 | cb->tx_completion(ar, transfer_context); | 839 | __skb_queue_tail(&list, skb); |
839 | } | 840 | } |
841 | |||
842 | while ((skb = __skb_dequeue(&list))) | ||
843 | cb->tx_completion(ar, skb); | ||
840 | } | 844 | } |
841 | 845 | ||
842 | /* Called by lower (CE) layer when data is received from the Target. */ | 846 | /* Called by lower (CE) layer when data is received from the Target. */ |
@@ -847,12 +851,14 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) | |||
847 | struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id]; | 851 | struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id]; |
848 | struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; | 852 | struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; |
849 | struct sk_buff *skb; | 853 | struct sk_buff *skb; |
854 | struct sk_buff_head list; | ||
850 | void *transfer_context; | 855 | void *transfer_context; |
851 | u32 ce_data; | 856 | u32 ce_data; |
852 | unsigned int nbytes, max_nbytes; | 857 | unsigned int nbytes, max_nbytes; |
853 | unsigned int transfer_id; | 858 | unsigned int transfer_id; |
854 | unsigned int flags; | 859 | unsigned int flags; |
855 | 860 | ||
861 | __skb_queue_head_init(&list); | ||
856 | while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, | 862 | while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, |
857 | &ce_data, &nbytes, &transfer_id, | 863 | &ce_data, &nbytes, &transfer_id, |
858 | &flags) == 0) { | 864 | &flags) == 0) { |
@@ -869,7 +875,10 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) | |||
869 | } | 875 | } |
870 | 876 | ||
871 | skb_put(skb, nbytes); | 877 | skb_put(skb, nbytes); |
878 | __skb_queue_tail(&list, skb); | ||
879 | } | ||
872 | 880 | ||
881 | while ((skb = __skb_dequeue(&list))) { | ||
873 | ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n", | 882 | ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n", |
874 | ce_state->id, skb->len); | 883 | ce_state->id, skb->len); |
875 | ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ", | 884 | ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ", |