ath10k: prevent pci tx/rx starvation
authorMichal Kazior <michal.kazior@tieto.com>
Thu, 27 Nov 2014 10:09:38 +0000 (11:09 +0100)
committerKalle Valo <kvalo@qca.qualcomm.com>
Mon, 1 Dec 2014 07:27:27 +0000 (09:27 +0200)
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>
drivers/net/wireless/ath/ath10k/pci.c

index 95e9066..7abb836 100644 (file)
@@ -823,20 +823,24 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
        struct ath10k *ar = ce_state->ar;
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;
        struct ath10k *ar = ce_state->ar;
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;
-       void *transfer_context;
+       struct sk_buff_head list;
+       struct sk_buff *skb;
        u32 ce_data;
        unsigned int nbytes;
        unsigned int transfer_id;
 
        u32 ce_data;
        unsigned int nbytes;
        unsigned int transfer_id;
 
-       while (ath10k_ce_completed_send_next(ce_state, &transfer_context,
-                                            &ce_data, &nbytes,
-                                            &transfer_id) == 0) {
+       __skb_queue_head_init(&list);
+       while (ath10k_ce_completed_send_next(ce_state, (void **)&skb, &ce_data,
+                                            &nbytes, &transfer_id) == 0) {
                /* no need to call tx completion for NULL pointers */
                /* no need to call tx completion for NULL pointers */
-               if (transfer_context == NULL)
+               if (skb == NULL)
                        continue;
 
                        continue;
 
-               cb->tx_completion(ar, transfer_context);
+               __skb_queue_tail(&list, skb);
        }
        }
+
+       while ((skb = __skb_dequeue(&list)))
+               cb->tx_completion(ar, skb);
 }
 
 /* Called by lower (CE) layer when data is received from the Target. */
 }
 
 /* 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)
        struct ath10k_pci_pipe *pipe_info =  &ar_pci->pipe_info[ce_state->id];
        struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;
        struct sk_buff *skb;
        struct ath10k_pci_pipe *pipe_info =  &ar_pci->pipe_info[ce_state->id];
        struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;
        struct sk_buff *skb;
+       struct sk_buff_head list;
        void *transfer_context;
        u32 ce_data;
        unsigned int nbytes, max_nbytes;
        unsigned int transfer_id;
        unsigned int flags;
 
        void *transfer_context;
        u32 ce_data;
        unsigned int nbytes, max_nbytes;
        unsigned int transfer_id;
        unsigned int flags;
 
+       __skb_queue_head_init(&list);
        while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,
                                             &ce_data, &nbytes, &transfer_id,
                                             &flags) == 0) {
        while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,
                                             &ce_data, &nbytes, &transfer_id,
                                             &flags) == 0) {
@@ -869,7 +875,10 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
                }
 
                skb_put(skb, nbytes);
                }
 
                skb_put(skb, nbytes);
+               __skb_queue_tail(&list, skb);
+       }
 
 
+       while ((skb = __skb_dequeue(&list))) {
                ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n",
                           ce_state->id, skb->len);
                ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ",
                ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n",
                           ce_state->id, skb->len);
                ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ",