aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorDaniel Wagner <daniel.wagner@bmw-carit.de>2016-08-18 09:12:05 -0400
committerKalle Valo <kvalo@qca.qualcomm.com>2016-09-09 08:15:28 -0400
commit78a9e170388b672f609cb6e8e097e0ddca24e6f5 (patch)
treea65d4d02671cfc506722ae2cb1d222ddf65b920c /drivers/net/wireless/ath
parentcabd34d0e9c47ac8747e7a1d871e10acdb8e980f (diff)
carl9170: Fix wrong completion usage
carl9170_usb_stop() is used from several places to flush and cleanup any pending work. The normal pattern is to send a request and wait for the irq handler to call complete(). The completion is not reinitialized during normal operation and as the old comment indicates it is important to keep calls to wait_for_completion_timeout() and complete() balanced. Calling complete_all() brings this equilibirum out of balance and needs to be fixed by a reinit_completion(). But that opens a small race window. It is possible that the sequence of complete_all(), reinit_completion() is faster than the wait_for_completion_timeout() can do its work. The wake up is not lost but the done counter test is after reinit_completion() has been executed. The only reason we don't see carl9170_exec_cmd() hang forever is we use the timeout version of wait_for_copletion(). Let's fix this by reinitializing the completion (that is just setting done counter to 0) just before we send out an request. Now, carl9170_usb_stop() can be sure a complete() call is enough to make progess since there is only one waiter at max. This is a common pattern also seen in various drivers which use completion. Signed-off-by: Daniel Wagner <daniel.wagner@bmw-carit.de> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/carl9170/usb.c6
1 files changed, 2 insertions, 4 deletions
diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c
index 76842e6ca38e..99ab20334d21 100644
--- a/drivers/net/wireless/ath/carl9170/usb.c
+++ b/drivers/net/wireless/ath/carl9170/usb.c
@@ -670,6 +670,7 @@ int carl9170_exec_cmd(struct ar9170 *ar, const enum carl9170_cmd_oids cmd,
670 ar->readlen = outlen; 670 ar->readlen = outlen;
671 spin_unlock_bh(&ar->cmd_lock); 671 spin_unlock_bh(&ar->cmd_lock);
672 672
673 reinit_completion(&ar->cmd_wait);
673 err = __carl9170_exec_cmd(ar, &ar->cmd, false); 674 err = __carl9170_exec_cmd(ar, &ar->cmd, false);
674 675
675 if (!(cmd & CARL9170_CMD_ASYNC_FLAG)) { 676 if (!(cmd & CARL9170_CMD_ASYNC_FLAG)) {
@@ -778,10 +779,7 @@ void carl9170_usb_stop(struct ar9170 *ar)
778 spin_lock_bh(&ar->cmd_lock); 779 spin_lock_bh(&ar->cmd_lock);
779 ar->readlen = 0; 780 ar->readlen = 0;
780 spin_unlock_bh(&ar->cmd_lock); 781 spin_unlock_bh(&ar->cmd_lock);
781 complete_all(&ar->cmd_wait); 782 complete(&ar->cmd_wait);
782
783 /* This is required to prevent an early completion on _start */
784 reinit_completion(&ar->cmd_wait);
785 783
786 /* 784 /*
787 * Note: 785 * Note: