wil6210: fix race condition between BACK event and Rx data
[deliverable/linux.git] / drivers / net / wireless / ath / wil6210 / wmi.c
index 97909f0b3ef86dc7b3e149e5c64568240a8a798b..c3682c3ae89651b331bf570cf2a0688b983288c6 100644 (file)
@@ -597,27 +597,40 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
                return;
        }
 
+       mutex_lock(&wil->mutex);
+
        cid = wil->vring2cid_tid[evt->ringid][0];
        if (cid >= WIL6210_MAX_CID) {
                wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid);
-               return;
+               goto out;
        }
 
        sta = &wil->sta[cid];
        if (sta->status == wil_sta_unused) {
                wil_err(wil, "CID %d unused\n", cid);
-               return;
+               goto out;
        }
 
        wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr);
        for (i = 0; i < WIL_STA_TID_NUM; i++) {
-               struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
+               struct wil_tid_ampdu_rx *r;
+               unsigned long flags;
+
+               spin_lock_irqsave(&sta->tid_rx_lock, flags);
+
+               r = sta->tid_rx[i];
                sta->tid_rx[i] = NULL;
                wil_tid_ampdu_rx_free(wil, r);
+
+               spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
+
                if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize)
                        sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil,
                                                evt->agg_wsize, 0);
        }
+
+out:
+       mutex_unlock(&wil->mutex);
 }
 
 static const struct {
@@ -655,7 +668,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
        unsigned n;
 
        if (!test_bit(wil_status_reset_done, &wil->status)) {
-               wil_err(wil, "Reset not completed\n");
+               wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
                return;
        }
 
This page took 0.024907 seconds and 5 git commands to generate.