ath10k: fix bmi exchange tx/rx race
authorMichal Kazior <michal.kazior@tieto.com>
Mon, 14 Jul 2014 13:25:25 +0000 (16:25 +0300)
committerKalle Valo <kvalo@qca.qualcomm.com>
Tue, 15 Jul 2014 08:18:58 +0000 (11:18 +0300)
It was possible for tx completion not to be
processed. In that case an old stack pointer was
left on copy engine tx ring. Next bmi exchange
would immediately pop it and use complete() on the
completion struct there causing corruption.

Make sure to wait for both tx and rx completions
properly.

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
drivers/net/wireless/ath/ath10k/pci.h

index d0004d59c97ec6c9292266662d9fd93cdd9eaf5e..06840d101c45cb74c9fd0655fa943b623cf1f7c6 100644 (file)
@@ -1362,8 +1362,6 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
                ath10k_ce_recv_buf_enqueue(ce_rx, &xfer, resp_paddr);
        }
 
-       init_completion(&xfer.done);
-
        ret = ath10k_ce_send(ce_tx, &xfer, req_paddr, req_len, -1, 0);
        if (ret)
                goto err_resp;
@@ -1414,10 +1412,7 @@ static void ath10k_pci_bmi_send_done(struct ath10k_ce_pipe *ce_state)
                                          &nbytes, &transfer_id))
                return;
 
-       if (xfer->wait_for_resp)
-               return;
-
-       complete(&xfer->done);
+       xfer->tx_done = true;
 }
 
 static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)
@@ -1438,7 +1433,7 @@ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)
        }
 
        xfer->resp_len = nbytes;
-       complete(&xfer->done);
+       xfer->rx_done = true;
 }
 
 static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
@@ -1451,7 +1446,7 @@ static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
                ath10k_pci_bmi_send_done(tx_pipe);
                ath10k_pci_bmi_recv_data(rx_pipe);
 
-               if (completion_done(&xfer->done))
+               if (xfer->tx_done && (xfer->rx_done == xfer->wait_for_resp))
                        return 0;
 
                schedule();
index dfdebb4157aa177acde13ea1149b5a7490c5593e..940129209990337a1a99f79599014abc48b6b605 100644 (file)
@@ -38,7 +38,8 @@
 #define DIAG_TRANSFER_LIMIT 2048
 
 struct bmi_xfer {
-       struct completion done;
+       bool tx_done;
+       bool rx_done;
        bool wait_for_resp;
        u32 resp_len;
 };