iwlwifi: mvm: handle BAR_FRAME_RELEASE (0xc2) notification
authorJohannes Berg <johannes.berg@intel.com>
Thu, 4 Jul 2019 15:24:47 +0000 (17:24 +0200)
committerLuca Coelho <luciano.coelho@intel.com>
Fri, 6 Sep 2019 12:52:05 +0000 (15:52 +0300)
In prior hardware generations (e.g. 9000 series), we received the BAR
frame with fake NSSN information to handle releasing frames from the
reorder buffer for the default queue, the other queues were getting
the FRAME_RELEASE notification in this case.

With multi-TID block-ack, the firmware no longer sends us the BAR
frame because the fake RX is quite big (just the metadata is around
48 bytes or so). Instead, it now sends us one (or multiple) special
release notifications (0xc2). The hardware consumes these as well,
but only generates the FRAME_RELEASE (0xc3) for queues other than
the default queue. We thus need to handle them in the same way we
handle the normal FRAME_RELEASE.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c

index 4d2274bcc0b50a115f27e348d100d281b7ac1f4b..22dff2c92d4f785b8c3c18de90890f3c82960888 100644 (file)
@@ -474,6 +474,13 @@ enum iwl_legacy_cmds {
         */
        REPLY_RX_MPDU_CMD = 0xc1,
 
+       /**
+        * @BAR_FRAME_RELEASE: Frame release from BAR notification, used for
+        *      multi-TID BAR (previously, the BAR frame itself was reported
+        *      instead). Uses &struct iwl_bar_frame_release.
+        */
+       BAR_FRAME_RELEASE = 0xc2,
+
        /**
         * @FRAME_RELEASE:
         * Frame release (reorder helper) notification, uses
index 9b0bb89599fc3325a61c4fe283bace44e73b1448..a93449db7bb200432aa5bb10bde3ffdf0b401e5b 100644 (file)
@@ -746,6 +746,38 @@ struct iwl_frame_release {
        __le16 nssn;
 };
 
+/**
+ * enum iwl_bar_frame_release_sta_tid - STA/TID information for BAR release
+ * @IWL_BAR_FRAME_RELEASE_TID_MASK: TID mask
+ * @IWL_BAR_FRAME_RELEASE_STA_MASK: STA mask
+ */
+enum iwl_bar_frame_release_sta_tid {
+       IWL_BAR_FRAME_RELEASE_TID_MASK = 0x0000000f,
+       IWL_BAR_FRAME_RELEASE_STA_MASK = 0x000001f0,
+};
+
+/**
+ * enum iwl_bar_frame_release_ba_info - BA information for BAR release
+ * @IWL_BAR_FRAME_RELEASE_NSSN_MASK: NSSN mask
+ * @IWL_BAR_FRAME_RELEASE_SN_MASK: SN mask (ignored by driver)
+ * @IWL_BAR_FRAME_RELEASE_BAID_MASK: BAID mask
+ */
+enum iwl_bar_frame_release_ba_info {
+       IWL_BAR_FRAME_RELEASE_NSSN_MASK = 0x00000fff,
+       IWL_BAR_FRAME_RELEASE_SN_MASK   = 0x00fff000,
+       IWL_BAR_FRAME_RELEASE_BAID_MASK = 0x3f000000,
+};
+
+/**
+ * struct iwl_bar_frame_release - frame release from BAR info
+ * @sta_tid: STA & TID information, see &enum iwl_bar_frame_release_sta_tid.
+ * @ba_info: BA information, see &enum iwl_bar_frame_release_ba_info.
+ */
+struct iwl_bar_frame_release {
+       __le32 sta_tid;
+       __le32 ba_info;
+} __packed; /* RX_BAR_TO_FRAME_RELEASE_API_S_VER_1 */
+
 enum iwl_rss_hash_func_en {
        IWL_RSS_HASH_TYPE_IPV4_TCP,
        IWL_RSS_HASH_TYPE_IPV4_UDP,
index b8a8369457b9f1c5f8a4f6bb2007646e685add34..843d00bf2bd55504d057075871968291f9897a3a 100644 (file)
@@ -1606,6 +1606,8 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
                                struct iwl_rx_cmd_buffer *rxb, int queue);
 void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi,
                              struct iwl_rx_cmd_buffer *rxb, int queue);
+void iwl_mvm_rx_bar_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi,
+                                 struct iwl_rx_cmd_buffer *rxb, int queue);
 int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask,
                            const u8 *data, u32 count, bool async);
 void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct napi_struct *napi,
index 35b393f8cd85c2fcc6f9a8076da353c0ee8675ff..961c7ab7950b4510678198744dde5565c4776def 100644 (file)
@@ -389,6 +389,7 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {
        HCMD_NAME(SCAN_ITERATION_COMPLETE_UMAC),
        HCMD_NAME(REPLY_RX_PHY_CMD),
        HCMD_NAME(REPLY_RX_MPDU_CMD),
+       HCMD_NAME(BAR_FRAME_RELEASE),
        HCMD_NAME(FRAME_RELEASE),
        HCMD_NAME(BA_NOTIF),
        HCMD_NAME(MCC_UPDATE_CMD),
@@ -1060,6 +1061,8 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode,
                iwl_mvm_rx_queue_notif(mvm, napi, rxb, 0);
        else if (cmd == WIDE_ID(LEGACY_GROUP, FRAME_RELEASE))
                iwl_mvm_rx_frame_release(mvm, napi, rxb, 0);
+       else if (cmd == WIDE_ID(LEGACY_GROUP, BAR_FRAME_RELEASE))
+               iwl_mvm_rx_bar_frame_release(mvm, napi, rxb, 0);
        else if (cmd == WIDE_ID(DATA_PATH_GROUP, RX_NO_DATA_NOTIF))
                iwl_mvm_rx_monitor_no_data(mvm, napi, rxb, 0);
        else
index f3f9e641ae701d04904573a435a29e7c92dea761..c48d6fb1640808c4458017ba970c92c3e4850ae9 100644 (file)
@@ -2014,3 +2014,42 @@ void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi,
                                          le16_to_cpu(release->nssn),
                                          queue, 0);
 }
+
+void iwl_mvm_rx_bar_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi,
+                                 struct iwl_rx_cmd_buffer *rxb, int queue)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_bar_frame_release *release = (void *)pkt->data;
+       unsigned int baid = le32_get_bits(release->ba_info,
+                                         IWL_BAR_FRAME_RELEASE_BAID_MASK);
+       unsigned int nssn = le32_get_bits(release->ba_info,
+                                         IWL_BAR_FRAME_RELEASE_NSSN_MASK);
+       unsigned int sta_id = le32_get_bits(release->sta_tid,
+                                           IWL_BAR_FRAME_RELEASE_STA_MASK);
+       unsigned int tid = le32_get_bits(release->sta_tid,
+                                        IWL_BAR_FRAME_RELEASE_TID_MASK);
+       struct iwl_mvm_baid_data *baid_data;
+
+       if (WARN_ON_ONCE(baid == IWL_RX_REORDER_DATA_INVALID_BAID ||
+                        baid >= ARRAY_SIZE(mvm->baid_map)))
+               return;
+
+       rcu_read_lock();
+       baid_data = rcu_dereference(mvm->baid_map[baid]);
+       if (!baid_data) {
+               IWL_DEBUG_RX(mvm,
+                            "Got valid BAID %d but not allocated, invalid BAR release!\n",
+                             baid);
+               goto out;
+       }
+
+       if (WARN(tid != baid_data->tid || sta_id != baid_data->sta_id,
+                "baid 0x%x is mapped to sta:%d tid:%d, but BAR release received for sta:%d tid:%d\n",
+                baid, baid_data->sta_id, baid_data->tid, sta_id,
+                tid))
+               goto out;
+
+       iwl_mvm_release_frames_from_notif(mvm, napi, baid, nssn, queue, 0);
+out:
+       rcu_read_unlock();
+}