aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2014-07-14 09:25:25 -0400
committerKalle Valo <kvalo@qca.qualcomm.com>2014-07-15 04:18:58 -0400
commit2374b18684dfed2a0588efe4df716d16554da467 (patch)
tree47be53e5596ff37aafa1a0648778bf3083f63091 /drivers/net/wireless/ath
parenta491a920ff5c22cc09700a2660f6eac55b1ce4c1 (diff)
ath10k: fix bmi exchange tx/rx race
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>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c11
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.h3
2 files changed, 5 insertions, 9 deletions
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index d0004d59c97e..06840d101c45 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1362,8 +1362,6 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
1362 ath10k_ce_recv_buf_enqueue(ce_rx, &xfer, resp_paddr); 1362 ath10k_ce_recv_buf_enqueue(ce_rx, &xfer, resp_paddr);
1363 } 1363 }
1364 1364
1365 init_completion(&xfer.done);
1366
1367 ret = ath10k_ce_send(ce_tx, &xfer, req_paddr, req_len, -1, 0); 1365 ret = ath10k_ce_send(ce_tx, &xfer, req_paddr, req_len, -1, 0);
1368 if (ret) 1366 if (ret)
1369 goto err_resp; 1367 goto err_resp;
@@ -1414,10 +1412,7 @@ static void ath10k_pci_bmi_send_done(struct ath10k_ce_pipe *ce_state)
1414 &nbytes, &transfer_id)) 1412 &nbytes, &transfer_id))
1415 return; 1413 return;
1416 1414
1417 if (xfer->wait_for_resp) 1415 xfer->tx_done = true;
1418 return;
1419
1420 complete(&xfer->done);
1421} 1416}
1422 1417
1423static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state) 1418static 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)
1438 } 1433 }
1439 1434
1440 xfer->resp_len = nbytes; 1435 xfer->resp_len = nbytes;
1441 complete(&xfer->done); 1436 xfer->rx_done = true;
1442} 1437}
1443 1438
1444static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, 1439static 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,
1451 ath10k_pci_bmi_send_done(tx_pipe); 1446 ath10k_pci_bmi_send_done(tx_pipe);
1452 ath10k_pci_bmi_recv_data(rx_pipe); 1447 ath10k_pci_bmi_recv_data(rx_pipe);
1453 1448
1454 if (completion_done(&xfer->done)) 1449 if (xfer->tx_done && (xfer->rx_done == xfer->wait_for_resp))
1455 return 0; 1450 return 0;
1456 1451
1457 schedule(); 1452 schedule();
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index dfdebb4157aa..940129209990 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -38,7 +38,8 @@
38#define DIAG_TRANSFER_LIMIT 2048 38#define DIAG_TRANSFER_LIMIT 2048
39 39
40struct bmi_xfer { 40struct bmi_xfer {
41 struct completion done; 41 bool tx_done;
42 bool rx_done;
42 bool wait_for_resp; 43 bool wait_for_resp;
43 u32 resp_len; 44 u32 resp_len;
44}; 45};