ath10k: workaround boot issues with KVM/PCI-passthrough
authorMichal Kazior <michal.kazior@tieto.com>
Wed, 16 Jul 2014 13:01:39 +0000 (15:01 +0200)
committerKalle Valo <kvalo@qca.qualcomm.com>
Mon, 21 Jul 2014 17:44:39 +0000 (20:44 +0300)
Apparently iomap writes that unmask CE irqs aren't
propagated properly sometimes. Before failing try
to poll for the control response message as it may
have been delivered without an interrupt.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath10k/htc.c

index e493db4b4a41fade30415e85c3dede5d4ea3f584..5fdc40d3b378303a77edb1b39fc46cb5c3660d0a 100644 (file)
@@ -546,7 +546,7 @@ static u8 ath10k_htc_get_credit_allocation(struct ath10k_htc *htc,
 
 int ath10k_htc_wait_target(struct ath10k_htc *htc)
 {
-       int status = 0;
+       int i, status = 0;
        struct ath10k_htc_svc_conn_req conn_req;
        struct ath10k_htc_svc_conn_resp conn_resp;
        struct ath10k_htc_msg *msg;
@@ -556,10 +556,26 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
 
        status = wait_for_completion_timeout(&htc->ctl_resp,
                                             ATH10K_HTC_WAIT_TIMEOUT_HZ);
-       if (status <= 0) {
+       if (status == 0) {
+               /* Workaround: In some cases the PCI HIF doesn't
+                * receive interrupt for the control response message
+                * even if the buffer was completed. It is suspected
+                * iomap writes unmasking PCI CE irqs aren't propagated
+                * properly in KVM PCI-passthrough sometimes.
+                */
+               ath10k_warn("failed to receive control response completion, polling..\n");
+
+               for (i = 0; i < CE_COUNT; i++)
+                       ath10k_hif_send_complete_check(htc->ar, i, 1);
+
+               status = wait_for_completion_timeout(&htc->ctl_resp,
+                                       ATH10K_HTC_WAIT_TIMEOUT_HZ);
+
                if (status == 0)
                        status = -ETIMEDOUT;
+       }
 
+       if (status < 0) {
                ath10k_err("ctl_resp never came in (%d)\n", status);
                return status;
        }