Merge tag 'wireless-drivers-next-for-davem-2016-09-29' of git://git.kernel.org/pub...
[cascardo/linux.git] / drivers / net / wireless / intel / iwlwifi / mvm / rxmq.c
index 08d8a8a..a57c6ef 100644 (file)
@@ -418,10 +418,11 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
 
                ssn = ieee80211_sn_inc(ssn);
 
-               /* holes are valid since nssn indicates frames were received. */
-               if (skb_queue_empty(skb_list) || !skb_peek_tail(skb_list))
-                       continue;
-               /* Empty the list. Will have more than one frame for A-MSDU */
+               /*
+                * Empty the list. Will have more than one frame for A-MSDU.
+                * Empty list is valid as well since nssn indicates frames were
+                * received.
+                */
                while ((skb = __skb_dequeue(skb_list))) {
                        iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb,
                                                        reorder_buf->queue,
@@ -434,7 +435,7 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
        if (reorder_buf->num_stored && !reorder_buf->removed) {
                u16 index = reorder_buf->head_sn % reorder_buf->buf_size;
 
-               while (!skb_peek_tail(&reorder_buf->entries[index]))
+               while (skb_queue_empty(&reorder_buf->entries[index]))
                        index = (index + 1) % reorder_buf->buf_size;
                /* modify timer to match next frame's expiration time */
                mod_timer(&reorder_buf->reorder_timer,
@@ -452,17 +453,17 @@ void iwl_mvm_reorder_timer_expired(unsigned long data)
        u16 sn = 0, index = 0;
        bool expired = false;
 
-       spin_lock_bh(&buf->lock);
+       spin_lock(&buf->lock);
 
        if (!buf->num_stored || buf->removed) {
-               spin_unlock_bh(&buf->lock);
+               spin_unlock(&buf->lock);
                return;
        }
 
        for (i = 0; i < buf->buf_size ; i++) {
                index = (buf->head_sn + i) % buf->buf_size;
 
-               if (!skb_peek_tail(&buf->entries[index]))
+               if (skb_queue_empty(&buf->entries[index]))
                        continue;
                if (!time_after(jiffies, buf->reorder_time[index] +
                                RX_REORDER_BUF_TIMEOUT_MQ))
@@ -492,7 +493,7 @@ void iwl_mvm_reorder_timer_expired(unsigned long data)
                          buf->reorder_time[index] +
                          1 + RX_REORDER_BUF_TIMEOUT_MQ);
        }
-       spin_unlock_bh(&buf->lock);
+       spin_unlock(&buf->lock);
 }
 
 static void iwl_mvm_del_ba(struct iwl_mvm *mvm, int queue,
@@ -503,7 +504,7 @@ static void iwl_mvm_del_ba(struct iwl_mvm *mvm, int queue,
        struct iwl_mvm_reorder_buffer *reorder_buf;
        u8 baid = data->baid;
 
-       if (WARN_ON_ONCE(baid >= IWL_RX_REORDER_DATA_INVALID_BAID))
+       if (WARN_ONCE(baid >= IWL_MAX_BAID, "invalid BAID: %x\n", baid))
                return;
 
        rcu_read_lock();
@@ -590,6 +591,11 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
        baid = (reorder & IWL_RX_MPDU_REORDER_BAID_MASK) >>
                IWL_RX_MPDU_REORDER_BAID_SHIFT;
 
+       /*
+        * This also covers the case of receiving a Block Ack Request
+        * outside a BA session; we'll pass it to mac80211 and that
+        * then sends a delBA action frame.
+        */
        if (baid == IWL_RX_REORDER_DATA_INVALID_BAID)
                return false;
 
@@ -599,9 +605,10 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
 
        mvm_sta = iwl_mvm_sta_from_mac80211(sta);
 
-       /* not a data packet */
-       if (!ieee80211_is_data_qos(hdr->frame_control) ||
-           is_multicast_ether_addr(hdr->addr1))
+       /* not a data packet or a bar */
+       if (!ieee80211_is_back_req(hdr->frame_control) &&
+           (!ieee80211_is_data_qos(hdr->frame_control) ||
+            is_multicast_ether_addr(hdr->addr1)))
                return false;
 
        if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
@@ -625,6 +632,11 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
 
        spin_lock_bh(&buffer->lock);
 
+       if (ieee80211_is_back_req(hdr->frame_control)) {
+               iwl_mvm_release_frames(mvm, sta, napi, buffer, nssn);
+               goto drop;
+       }
+
        /*
         * If there was a significant jump in the nssn - adjust.
         * If the SN is smaller than the NSSN it might need to first go into