Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
authorKalle Valo <kvalo@codeaurora.org>
Tue, 14 Apr 2020 09:39:43 +0000 (12:39 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 14 Apr 2020 09:39:43 +0000 (12:39 +0300)
ath.git patches for v5.8. Major changes:

ath11k

* add debugfs file for testing ADDBA and DELBA

ath10k

* enable VHT160 and VHT80+80 modes

* enable radar detection in secondary segment

* sdio: disable TX complete indication to improve throughput

35 files changed:
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/hif.h
drivers/net/wireless/ath/ath10k/htc.c
drivers/net/wireless/ath/ath10k/htc.h
drivers/net/wireless/ath/ath10k/htt.c
drivers/net/wireless/ath/ath10k/htt.h
drivers/net/wireless/ath/ath10k/htt_rx.c
drivers/net/wireless/ath/ath10k/htt_tx.c
drivers/net/wireless/ath/ath10k/hw.h
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/pci.c
drivers/net/wireless/ath/ath10k/sdio.c
drivers/net/wireless/ath/ath10k/sdio.h
drivers/net/wireless/ath/ath10k/txrx.c
drivers/net/wireless/ath/ath10k/wmi-tlv.c
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.h
drivers/net/wireless/ath/ath11k/ahb.c
drivers/net/wireless/ath/ath11k/core.h
drivers/net/wireless/ath/ath11k/debug.h
drivers/net/wireless/ath/ath11k/debugfs_sta.c
drivers/net/wireless/ath/ath11k/dp.h
drivers/net/wireless/ath/ath11k/dp_rx.c
drivers/net/wireless/ath/ath11k/hal.h
drivers/net/wireless/ath/ath11k/peer.c
drivers/net/wireless/ath/ath11k/peer.h
drivers/net/wireless/ath/ath11k/trace.h
drivers/net/wireless/ath/ath11k/wmi.c
drivers/net/wireless/ath/ath11k/wmi.h
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/hif_usb.h
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_hst.c
drivers/net/wireless/ath/ath9k/wmi.c
drivers/net/wireless/ath/ath9k/wmi.h

index f26cc6989dadadd7418c9cdc6648a128ae90a669..52472bbcee1f8ebf6ce4d863238f6ae6ac78102d 100644 (file)
@@ -723,10 +723,7 @@ static int ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode)
        if (ret)
                return ret;
 
-       /* Data transfer is not initiated, when reduced Tx completion
-        * is used for SDIO. disable it until fixed
-        */
-       param &= ~HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;
+       param |= HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;
 
        /* Alternate credit size of 1544 as used by SDIO firmware is
         * not big enough for mac80211 / native wifi frames. disable it
index 496ee34a4d782b7ee96e15734b5a0fef1d821f07..0dd8973d0acffdd077b083435c41a4a97c101c73 100644 (file)
@@ -56,6 +56,8 @@ struct ath10k_hif_ops {
 
        int (*swap_mailbox)(struct ath10k *ar);
 
+       int (*get_htt_tx_complete)(struct ath10k *ar);
+
        int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id,
                                   u8 *ul_pipe, u8 *dl_pipe);
 
@@ -144,6 +146,13 @@ static inline int ath10k_hif_swap_mailbox(struct ath10k *ar)
        return 0;
 }
 
+static inline int ath10k_hif_get_htt_tx_complete(struct ath10k *ar)
+{
+       if (ar->hif.ops->get_htt_tx_complete)
+               return ar->hif.ops->get_htt_tx_complete(ar);
+       return 0;
+}
+
 static inline int ath10k_hif_map_service_to_pipe(struct ath10k *ar,
                                                 u16 service_id,
                                                 u8 *ul_pipe, u8 *dl_pipe)
index 2248d6c022f487b0d29b6c6806c6d6d6f0c23783..61ee413d902a7390178327627ef30ba80e4b7bc6 100644 (file)
@@ -660,6 +660,16 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
        return 0;
 }
 
+void ath10k_htc_change_tx_credit_flow(struct ath10k_htc *htc,
+                                     enum ath10k_htc_ep_id eid,
+                                     bool enable)
+{
+       struct ath10k *ar = htc->ar;
+       struct ath10k_htc_ep *ep = &ar->htc.endpoint[eid];
+
+       ep->tx_credit_flow_enabled = enable;
+}
+
 int ath10k_htc_connect_service(struct ath10k_htc *htc,
                               struct ath10k_htc_svc_conn_req *conn_req,
                               struct ath10k_htc_svc_conn_resp *conn_resp)
index 065c82d9d689fcd686e7bc606a0aa85592fd8448..14e5c3f712c11cfc018f7550d8935716c899fdfa 100644 (file)
@@ -386,6 +386,9 @@ int ath10k_htc_start(struct ath10k_htc *htc);
 int ath10k_htc_connect_service(struct ath10k_htc *htc,
                               struct ath10k_htc_svc_conn_req  *conn_req,
                               struct ath10k_htc_svc_conn_resp *conn_resp);
+void ath10k_htc_change_tx_credit_flow(struct ath10k_htc *htc,
+                                     enum ath10k_htc_ep_id eid,
+                                     bool enable);
 int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
                    struct sk_buff *packet);
 struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size);
index 7b75200ceae54a34fbf7bd56f12457c7cedee2ff..4354bf285ff1dd0fc2cf15eebf91f7ee25088add 100644 (file)
@@ -10,6 +10,7 @@
 #include "htt.h"
 #include "core.h"
 #include "debug.h"
+#include "hif.h"
 
 static const enum htt_t2h_msg_type htt_main_t2h_msg_types[] = {
        [HTT_MAIN_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
@@ -153,6 +154,10 @@ int ath10k_htt_connect(struct ath10k_htt *htt)
 
        htt->eid = conn_resp.eid;
 
+       htt->disable_tx_comp = ath10k_hif_get_htt_tx_complete(htt->ar);
+       if (htt->disable_tx_comp)
+               ath10k_htc_change_tx_credit_flow(&htt->ar->htc, htt->eid, true);
+
        return 0;
 }
 
index 4a12564fc30e28e320f540c2e9a4c3813ddbf263..b88c2f3787d81e12cdaff19ed2c929d76ec5406d 100644 (file)
@@ -150,9 +150,19 @@ enum htt_data_tx_desc_flags1 {
        HTT_DATA_TX_DESC_FLAGS1_MORE_IN_BATCH    = 1 << 12,
        HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD = 1 << 13,
        HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD = 1 << 14,
-       HTT_DATA_TX_DESC_FLAGS1_RSVD1            = 1 << 15
+       HTT_DATA_TX_DESC_FLAGS1_TX_COMPLETE      = 1 << 15
 };
 
+#define HTT_TX_CREDIT_DELTA_ABS_M      0xffff0000
+#define HTT_TX_CREDIT_DELTA_ABS_S      16
+#define HTT_TX_CREDIT_DELTA_ABS_GET(word) \
+           (((word) & HTT_TX_CREDIT_DELTA_ABS_M) >> HTT_TX_CREDIT_DELTA_ABS_S)
+
+#define HTT_TX_CREDIT_SIGN_BIT_M       0x00000100
+#define HTT_TX_CREDIT_SIGN_BIT_S       8
+#define HTT_TX_CREDIT_SIGN_BIT_GET(word) \
+           (((word) & HTT_TX_CREDIT_SIGN_BIT_M) >> HTT_TX_CREDIT_SIGN_BIT_S)
+
 enum htt_data_tx_ext_tid {
        HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST = 16,
        HTT_DATA_TX_EXT_TID_MGMT                = 17,
@@ -2021,6 +2031,7 @@ struct ath10k_htt {
        bool tx_mem_allocated;
        const struct ath10k_htt_tx_ops *tx_ops;
        const struct ath10k_htt_rx_ops *rx_ops;
+       bool disable_tx_comp;
 };
 
 struct ath10k_htt_tx_ops {
index f883f2a724dd96bbc467c8437c791426233dfb00..64e45bfa5d059f76807c4003d09a9ea23a13e38b 100644 (file)
@@ -3789,6 +3789,9 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
        }
        case HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION: {
                struct htt_tx_done tx_done = {};
+               struct ath10k_htt *htt = &ar->htt;
+               struct ath10k_htc *htc = &ar->htc;
+               struct ath10k_htc_ep *ep = &ar->htc.endpoint[htt->eid];
                int status = __le32_to_cpu(resp->mgmt_tx_completion.status);
                int info = __le32_to_cpu(resp->mgmt_tx_completion.info);
 
@@ -3814,6 +3817,12 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                        break;
                }
 
+               if (htt->disable_tx_comp) {
+                       spin_lock_bh(&htc->tx_lock);
+                       ep->tx_credits++;
+                       spin_unlock_bh(&htc->tx_lock);
+               }
+
                status = ath10k_txrx_tx_unref(htt, &tx_done);
                if (!status) {
                        spin_lock_bh(&htt->tx_lock);
@@ -3888,8 +3897,31 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                skb_queue_tail(&htt->rx_in_ord_compl_q, skb);
                return false;
        }
-       case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:
+       case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND: {
+               struct ath10k_htt *htt = &ar->htt;
+               struct ath10k_htc *htc = &ar->htc;
+               struct ath10k_htc_ep *ep = &ar->htc.endpoint[htt->eid];
+               u32 msg_word = __le32_to_cpu(*(__le32 *)resp);
+               int htt_credit_delta;
+
+               htt_credit_delta = HTT_TX_CREDIT_DELTA_ABS_GET(msg_word);
+               if (HTT_TX_CREDIT_SIGN_BIT_GET(msg_word))
+                       htt_credit_delta = -htt_credit_delta;
+
+               ath10k_dbg(ar, ATH10K_DBG_HTT,
+                          "htt credit update delta %d\n",
+                          htt_credit_delta);
+
+               if (htt->disable_tx_comp) {
+                       spin_lock_bh(&htc->tx_lock);
+                       ep->tx_credits += htt_credit_delta;
+                       spin_unlock_bh(&htc->tx_lock);
+                       ath10k_dbg(ar, ATH10K_DBG_HTT,
+                                  "htt credit total %d\n",
+                                  ep->tx_credits);
+               }
                break;
+       }
        case HTT_T2H_MSG_TYPE_CHAN_CHANGE: {
                u32 phymode = __le32_to_cpu(resp->chan_change.phymode);
                u32 freq = __le32_to_cpu(resp->chan_change.freq);
index e9d12ea708b62615b92f78ee31da85897f563547..bcecf05fe2fd9512fd090d47a1a7ecbc62fc0c5b 100644 (file)
@@ -543,7 +543,39 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt)
 
 void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
 {
+       struct ath10k_htt *htt = &ar->htt;
+       struct htt_tx_done tx_done = {0};
+       struct htt_cmd_hdr *htt_hdr;
+       struct htt_data_tx_desc *desc_hdr = NULL;
+       u16 flags1 = 0;
+       u8 msg_type = 0;
+
+       if (htt->disable_tx_comp) {
+               htt_hdr = (struct htt_cmd_hdr *)skb->data;
+               msg_type = htt_hdr->msg_type;
+
+               if (msg_type == HTT_H2T_MSG_TYPE_TX_FRM) {
+                       desc_hdr = (struct htt_data_tx_desc *)
+                               (skb->data + sizeof(*htt_hdr));
+                       flags1 = __le16_to_cpu(desc_hdr->flags1);
+               }
+       }
+
        dev_kfree_skb_any(skb);
+
+       if ((!htt->disable_tx_comp) || (msg_type != HTT_H2T_MSG_TYPE_TX_FRM))
+               return;
+
+       ath10k_dbg(ar, ATH10K_DBG_HTT,
+                  "htt tx complete msdu id:%u ,flags1:%x\n",
+                  __le16_to_cpu(desc_hdr->id), flags1);
+
+       if (flags1 & HTT_DATA_TX_DESC_FLAGS1_TX_COMPLETE)
+               return;
+
+       tx_done.status = HTT_TX_COMPL_STATE_ACK;
+       tx_done.msdu_id = __le16_to_cpu(desc_hdr->id);
+       ath10k_txrx_tx_unref(&ar->htt, &tx_done);
 }
 
 void ath10k_htt_hif_tx_complete(struct ath10k *ar, struct sk_buff *skb)
@@ -1279,6 +1311,9 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm
                flags0 |= SM(ATH10K_HW_TXRX_MGMT,
                             HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
                flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
+
+               if (htt->disable_tx_comp)
+                       flags1 |= HTT_DATA_TX_DESC_FLAGS1_TX_COMPLETE;
                break;
        }
 
index 970c736ac6bb961d12cde00e81aa9883aa1108d2..2a7af5861788e382acce0bae9afbc41806092a59 100644 (file)
@@ -765,7 +765,7 @@ ath10k_is_rssi_enable(struct ath10k_hw_params *hw,
 #define TARGET_TLV_NUM_TDLS_VDEVS              1
 #define TARGET_TLV_NUM_TIDS                    ((TARGET_TLV_NUM_PEERS) * 2)
 #define TARGET_TLV_NUM_MSDU_DESC               (1024 + 32)
-#define TARGET_TLV_NUM_MSDU_DESC_HL            64
+#define TARGET_TLV_NUM_MSDU_DESC_HL            1024
 #define TARGET_TLV_NUM_WOW_PATTERNS            22
 #define TARGET_TLV_MGMT_NUM_MSDU_DESC          (50)
 
index 2d03b8dd3b8c78b415cf446a7d00f87e2ae668df..a59a7a5631a8874b18abfec0e8acb2cf92445ef8 100644 (file)
@@ -2505,6 +2505,30 @@ ath10k_peer_assoc_h_vht_limit(u16 tx_mcs_set,
        return tx_mcs_set;
 }
 
+static u32 get_160mhz_nss_from_maxrate(int rate)
+{
+       u32 nss;
+
+       switch (rate) {
+       case 780:
+               nss = 1;
+               break;
+       case 1560:
+               nss = 2;
+               break;
+       case 2106:
+               nss = 3; /* not support MCS9 from spec*/
+               break;
+       case 3120:
+               nss = 4;
+               break;
+       default:
+                nss = 1;
+       }
+
+       return nss;
+}
+
 static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
                                    struct ieee80211_vif *vif,
                                    struct ieee80211_sta *sta,
@@ -2512,6 +2536,7 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
 {
        const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
        struct ath10k_vif *arvif = (void *)vif->drv_priv;
+       struct ath10k_hw_params *hw = &ar->hw_params;
        struct cfg80211_chan_def def;
        enum nl80211_band band;
        const u16 *vht_mcs_mask;
@@ -2578,22 +2603,38 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
        arg->peer_vht_rates.tx_mcs_set = ath10k_peer_assoc_h_vht_limit(
                __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map), vht_mcs_mask);
 
-       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
-                  sta->addr, arg->peer_max_mpdu, arg->peer_flags);
+       /* Configure bandwidth-NSS mapping to FW
+        * for the chip's tx chains setting on 160Mhz bw
+        */
+       if (arg->peer_phymode == MODE_11AC_VHT160 ||
+           arg->peer_phymode == MODE_11AC_VHT80_80) {
+               u32 rx_nss;
+               u32 max_rate;
 
-       if (arg->peer_vht_rates.rx_max_rate &&
-           (sta->vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK)) {
-               switch (arg->peer_vht_rates.rx_max_rate) {
-               case 1560:
-                       /* Must be 2x2 at 160Mhz is all it can do. */
-                       arg->peer_bw_rxnss_override = 2;
-                       break;
-               case 780:
-                       /* Can only do 1x1 at 160Mhz (Long Guard Interval) */
-                       arg->peer_bw_rxnss_override = 1;
-                       break;
+               max_rate = arg->peer_vht_rates.rx_max_rate;
+               rx_nss = get_160mhz_nss_from_maxrate(max_rate);
+
+               if (rx_nss == 0)
+                       rx_nss = arg->peer_num_spatial_streams;
+               else
+                       rx_nss = min(arg->peer_num_spatial_streams, rx_nss);
+
+               max_rate = hw->vht160_mcs_tx_highest;
+               rx_nss = min(rx_nss, get_160mhz_nss_from_maxrate(max_rate));
+
+               arg->peer_bw_rxnss_override =
+                       FIELD_PREP(WMI_PEER_NSS_MAP_ENABLE, 1) |
+                       FIELD_PREP(WMI_PEER_NSS_160MHZ_MASK, (rx_nss - 1));
+
+               if (arg->peer_phymode == MODE_11AC_VHT80_80) {
+                       arg->peer_bw_rxnss_override |=
+                       FIELD_PREP(WMI_PEER_NSS_80_80MHZ_MASK, (rx_nss - 1));
                }
        }
+       ath10k_dbg(ar, ATH10K_DBG_MAC,
+                  "mac vht peer %pM max_mpdu %d flags 0x%x peer_rx_nss_override 0x%x\n",
+                  sta->addr, arg->peer_max_mpdu,
+                  arg->peer_flags, arg->peer_bw_rxnss_override);
 }
 
 static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
@@ -2745,9 +2786,9 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar,
        ath10k_peer_assoc_h_crypto(ar, vif, sta, arg);
        ath10k_peer_assoc_h_rates(ar, vif, sta, arg);
        ath10k_peer_assoc_h_ht(ar, vif, sta, arg);
+       ath10k_peer_assoc_h_phymode(ar, vif, sta, arg);
        ath10k_peer_assoc_h_vht(ar, vif, sta, arg);
        ath10k_peer_assoc_h_qos(ar, vif, sta, arg);
-       ath10k_peer_assoc_h_phymode(ar, vif, sta, arg);
 
        return 0;
 }
@@ -4563,13 +4604,6 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
                vht_cap.cap |= val;
        }
 
-       /* Currently the firmware seems to be buggy, don't enable 80+80
-        * mode until that's resolved.
-        */
-       if ((ar->vht_cap_info & IEEE80211_VHT_CAP_SHORT_GI_160) &&
-           (ar->vht_cap_info & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) == 0)
-               vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
-
        mcs_map = 0;
        for (i = 0; i < 8; i++) {
                if ((i < ar->num_rf_chains) && (ar->cfg_tx_chainmask & BIT(i)))
@@ -8625,7 +8659,9 @@ static const struct ieee80211_iface_combination ath10k_10_4_if_comb[] = {
                .radar_detect_widths =  BIT(NL80211_CHAN_WIDTH_20_NOHT) |
                                        BIT(NL80211_CHAN_WIDTH_20) |
                                        BIT(NL80211_CHAN_WIDTH_40) |
-                                       BIT(NL80211_CHAN_WIDTH_80),
+                                       BIT(NL80211_CHAN_WIDTH_80) |
+                                       BIT(NL80211_CHAN_WIDTH_80P80) |
+                                       BIT(NL80211_CHAN_WIDTH_160),
 #endif
        },
 };
@@ -8643,7 +8679,9 @@ ieee80211_iface_combination ath10k_10_4_bcn_int_if_comb[] = {
                .radar_detect_widths =  BIT(NL80211_CHAN_WIDTH_20_NOHT) |
                                        BIT(NL80211_CHAN_WIDTH_20) |
                                        BIT(NL80211_CHAN_WIDTH_40) |
-                                       BIT(NL80211_CHAN_WIDTH_80),
+                                       BIT(NL80211_CHAN_WIDTH_80) |
+                                       BIT(NL80211_CHAN_WIDTH_80P80) |
+                                       BIT(NL80211_CHAN_WIDTH_160),
 #endif
        },
 };
index ded7a220a4aab29c184c82b3d69d36be5062f2a3..cd1c5d60261f7b7c35fc905209e25446537dbd2b 100644 (file)
@@ -2074,6 +2074,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
        ath10k_pci_irq_sync(ar);
        napi_synchronize(&ar->napi);
        napi_disable(&ar->napi);
+       cancel_work_sync(&ar_pci->dump_work);
 
        /* Most likely the device has HTT Rx ring configured. The only way to
         * prevent the device from accessing (and possible corrupting) host
index 1f709b65c29b2bd40d5c3b8553728a4fedd014b3..5a0db342e5ad42810c00bedfca138545a8f208f4 100644 (file)
@@ -1752,6 +1752,28 @@ static int ath10k_sdio_hif_swap_mailbox(struct ath10k *ar)
        return 0;
 }
 
+static int ath10k_sdio_get_htt_tx_complete(struct ath10k *ar)
+{
+       u32 addr, val;
+       int ret;
+
+       addr = host_interest_item_address(HI_ITEM(hi_acs_flags));
+
+       ret = ath10k_sdio_hif_diag_read32(ar, addr, &val);
+       if (ret) {
+               ath10k_warn(ar,
+                           "unable to read hi_acs_flags for htt tx comple : %d\n", ret);
+               return ret;
+       }
+
+       ret = (val & HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_FW_ACK);
+
+       ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio reduce tx complete fw%sack\n",
+                  ret ? " " : " not ");
+
+       return ret;
+}
+
 /* HIF start/stop */
 
 static int ath10k_sdio_hif_start(struct ath10k *ar)
@@ -2026,6 +2048,7 @@ static const struct ath10k_hif_ops ath10k_sdio_hif_ops = {
        .start                  = ath10k_sdio_hif_start,
        .stop                   = ath10k_sdio_hif_stop,
        .swap_mailbox           = ath10k_sdio_hif_swap_mailbox,
+       .get_htt_tx_complete    = ath10k_sdio_get_htt_tx_complete,
        .map_service_to_pipe    = ath10k_sdio_hif_map_service_to_pipe,
        .get_default_pipe       = ath10k_sdio_hif_get_default_pipe,
        .send_complete_check    = ath10k_sdio_hif_send_complete_check,
index 33195f49acabc478088026c96802428e8a93b414..1c987494ad22c3c5835eb6fbaee722b6563236f3 100644 (file)
@@ -37,7 +37,7 @@
        (ATH10K_SDIO_MAX_BUFFER_SIZE - sizeof(struct ath10k_htc_hdr))
 
 #define ATH10K_HIF_MBOX_NUM_MAX                 4
-#define ATH10K_SDIO_BUS_REQUEST_MAX_NUM         64
+#define ATH10K_SDIO_BUS_REQUEST_MAX_NUM         1024
 
 #define ATH10K_SDIO_HIF_COMMUNICATION_TIMEOUT_HZ (100 * HZ)
 
@@ -98,6 +98,7 @@
 #define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF 0xFFFEFFFF
 #define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_ON 0x10000
 
+/* TODO: remove this and use skb->cb instead, much cleaner approach */
 struct ath10k_sdio_bus_request {
        struct list_head list;
 
index 39abf8b1290351617435dc2e50a44b233a68d29b..f46b9083bbf10941bd60778cca6e66044aefa98f 100644 (file)
@@ -84,9 +84,11 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
                wake_up(&htt->empty_tx_wq);
        spin_unlock_bh(&htt->tx_lock);
 
+       rcu_read_lock();
        if (txq && txq->sta && skb_cb->airtime_est)
                ieee80211_sta_register_airtime(txq->sta, txq->tid,
                                               skb_cb->airtime_est, 0);
+       rcu_read_unlock();
 
        if (ar->bus_param.dev_type != ATH10K_DEV_TYPE_HL)
                dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
index 4e68debda9bfc57e7f3e5682d9d51d74b048537d..e1ab900f26622d9fd878323cc8decaa12f6405f9 100644 (file)
@@ -2123,7 +2123,7 @@ ath10k_wmi_tlv_op_gen_vdev_start(struct ath10k *ar,
        tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL);
        tlv->len = __cpu_to_le16(sizeof(*ch));
        ch = (void *)tlv->value;
-       ath10k_wmi_put_wmi_channel(ch, &arg->channel);
+       ath10k_wmi_put_wmi_channel(ar, ch, &arg->channel);
 
        ptr += sizeof(*tlv);
        ptr += sizeof(*ch);
@@ -2763,7 +2763,7 @@ ath10k_wmi_tlv_op_gen_scan_chan_list(struct ath10k *ar,
                tlv->len = __cpu_to_le16(sizeof(*ci));
                ci = (void *)tlv->value;
 
-               ath10k_wmi_put_wmi_channel(ci, ch);
+               ath10k_wmi_put_wmi_channel(ar, ci, ch);
 
                chans += sizeof(*tlv);
                chans += sizeof(*ci);
@@ -3450,7 +3450,7 @@ ath10k_wmi_tlv_op_gen_tdls_peer_update(struct ath10k *ar,
                tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL);
                tlv->len = __cpu_to_le16(sizeof(*chan));
                chan = (void *)tlv->value;
-               ath10k_wmi_put_wmi_channel(chan, &chan_arg[i]);
+               ath10k_wmi_put_wmi_channel(ar, chan, &chan_arg[i]);
 
                ptr += sizeof(*tlv);
                ptr += sizeof(*chan);
index 2ea77bb880b19247414ffa3bd7a846a41c761c88..4a3a698fe05976fbf0fd95f735be5a7501b93b75 100644 (file)
@@ -1694,10 +1694,11 @@ static const struct wmi_peer_flags_map wmi_10_2_peer_flags_map = {
        .bw160 = WMI_10_2_PEER_160MHZ,
 };
 
-void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
+void ath10k_wmi_put_wmi_channel(struct ath10k *ar, struct wmi_channel *ch,
                                const struct wmi_channel_arg *arg)
 {
        u32 flags = 0;
+       struct ieee80211_channel *chan = NULL;
 
        memset(ch, 0, sizeof(*ch));
 
@@ -1714,12 +1715,39 @@ void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
        if (arg->chan_radar)
                flags |= WMI_CHAN_FLAG_DFS;
 
+       ch->band_center_freq2 = 0;
        ch->mhz = __cpu_to_le32(arg->freq);
        ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1);
-       if (arg->mode == MODE_11AC_VHT80_80)
+       if (arg->mode == MODE_11AC_VHT80_80) {
                ch->band_center_freq2 = __cpu_to_le32(arg->band_center_freq2);
-       else
-               ch->band_center_freq2 = 0;
+               chan = ieee80211_get_channel(ar->hw->wiphy,
+                                            arg->band_center_freq2 - 10);
+       }
+
+       if (arg->mode == MODE_11AC_VHT160) {
+               u32 band_center_freq1;
+               u32 band_center_freq2;
+
+               if (arg->freq > arg->band_center_freq1) {
+                       band_center_freq1 = arg->band_center_freq1 + 40;
+                       band_center_freq2 = arg->band_center_freq1 - 40;
+               } else {
+                       band_center_freq1 = arg->band_center_freq1 - 40;
+                       band_center_freq2 = arg->band_center_freq1 + 40;
+               }
+
+               ch->band_center_freq1 =
+                                       __cpu_to_le32(band_center_freq1);
+               /* Minus 10 to get a defined 5G channel frequency*/
+               chan = ieee80211_get_channel(ar->hw->wiphy,
+                                            band_center_freq2 - 10);
+               /* The center frequency of the entire VHT160 */
+               ch->band_center_freq2 = __cpu_to_le32(arg->band_center_freq1);
+       }
+
+       if (chan && chan->flags & IEEE80211_CHAN_RADAR)
+               flags |= WMI_CHAN_FLAG_DFS_CFREQ2;
+
        ch->min_power = arg->min_power;
        ch->max_power = arg->max_power;
        ch->reg_power = arg->max_reg_power;
@@ -7165,7 +7193,7 @@ ath10k_wmi_op_gen_vdev_start(struct ath10k *ar,
                memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len);
        }
 
-       ath10k_wmi_put_wmi_channel(&cmd->chan, &arg->channel);
+       ath10k_wmi_put_wmi_channel(ar, &cmd->chan, &arg->channel);
 
        ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, ch_flags: 0x%0X, max_power: %d\n",
@@ -7537,7 +7565,7 @@ ath10k_wmi_op_gen_scan_chan_list(struct ath10k *ar,
                ch = &arg->channels[i];
                ci = &cmd->chan_info[i];
 
-               ath10k_wmi_put_wmi_channel(ci, ch);
+               ath10k_wmi_put_wmi_channel(ar, ci, ch);
        }
 
        return skb;
@@ -7628,12 +7656,8 @@ ath10k_wmi_peer_assoc_fill_10_4(struct ath10k *ar, void *buf,
        struct wmi_10_4_peer_assoc_complete_cmd *cmd = buf;
 
        ath10k_wmi_peer_assoc_fill_10_2(ar, buf, arg);
-       if (arg->peer_bw_rxnss_override)
-               cmd->peer_bw_rxnss_override =
-                       __cpu_to_le32((arg->peer_bw_rxnss_override - 1) |
-                                     BIT(PEER_BW_RXNSS_OVERRIDE_OFFSET));
-       else
-               cmd->peer_bw_rxnss_override = 0;
+       cmd->peer_bw_rxnss_override =
+               __cpu_to_le32(arg->peer_bw_rxnss_override);
 }
 
 static int
@@ -8945,7 +8969,7 @@ ath10k_wmi_10_4_gen_tdls_peer_update(struct ath10k *ar,
 
        for (i = 0; i < cap->peer_chan_len; i++) {
                chan = (struct wmi_channel *)&peer_cap->peer_chan_list[i];
-               ath10k_wmi_put_wmi_channel(chan, &chan_arg[i]);
+               ath10k_wmi_put_wmi_channel(ar, chan, &chan_arg[i]);
        }
 
        ath10k_dbg(ar, ATH10K_DBG_WMI,
index 6df415778374b20beb04a105f1f9f397ba3565e2..209070714d1a76c6e2464e060da3ee45c3e3b779 100644 (file)
@@ -2094,7 +2094,8 @@ enum wmi_channel_change_cause {
 
 /* Indicate reason for channel switch */
 #define WMI_CHANNEL_CHANGE_CAUSE_CSA (1 << 13)
-
+/* DFS required on channel for 2nd segment of VHT160 and VHT80+80*/
+#define WMI_CHAN_FLAG_DFS_CFREQ2  (1 << 15)
 #define WMI_MAX_SPATIAL_STREAM        3 /* default max ss */
 
 /* HT Capabilities*/
@@ -6508,7 +6509,10 @@ struct wmi_10_2_peer_assoc_complete_cmd {
        __le32 info0; /* WMI_PEER_ASSOC_INFO0_ */
 } __packed;
 
-#define PEER_BW_RXNSS_OVERRIDE_OFFSET  31
+/* NSS Mapping to FW */
+#define WMI_PEER_NSS_MAP_ENABLE        BIT(31)
+#define WMI_PEER_NSS_160MHZ_MASK       GENMASK(2, 0)
+#define WMI_PEER_NSS_80_80MHZ_MASK     GENMASK(5, 3)
 
 struct wmi_10_4_peer_assoc_complete_cmd {
        struct wmi_10_2_peer_assoc_complete_cmd cmd;
@@ -7348,7 +7352,7 @@ void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn,
                                      const struct wmi_start_scan_arg *arg);
 void ath10k_wmi_set_wmm_param(struct wmi_wmm_params *params,
                              const struct wmi_wmm_params_arg *arg);
-void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
+void ath10k_wmi_put_wmi_channel(struct ath10k *ar, struct wmi_channel *ch,
                                const struct wmi_channel_arg *arg);
 int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg);
 
index 59342d2797ca9a49826410302465617a36ca0d5c..3b2b76d602f2c697f8bba33af7a66ca1b2a28424 100644 (file)
@@ -788,7 +788,7 @@ static int ath11k_ahb_ext_irq_config(struct ath11k_base *ab)
                        irq = platform_get_irq_byname(ab->pdev,
                                                      irq_name[irq_idx]);
                        ab->irq_num[irq_idx] = irq;
-                       irq_set_status_flags(irq, IRQ_NOAUTOEN);
+                       irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_DISABLE_UNLAZY);
                        ret = request_irq(irq, ath11k_ahb_ext_interrupt_handler,
                                          IRQF_TRIGGER_RISING,
                                          irq_name[irq_idx], irq_grp);
index 6e7b8ecd09a6bdef5dd5b67aa43737981c25fadb..b4c3e0418eefcad6243fcb6b92a7a1cf548cba4c 100644 (file)
@@ -341,6 +341,11 @@ struct ath11k_sta {
        u8 rssi_comb;
        struct ath11k_htt_tx_stats *tx_stats;
        struct ath11k_rx_peer_stats *rx_stats;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       /* protected by conf_mutex */
+       bool aggr_mode;
+#endif
 };
 
 #define ATH11K_NUM_CHANS 41
@@ -650,6 +655,7 @@ struct ath11k_base {
                /* protected by data_lock */
                u32 fw_crash_counter;
        } stats;
+       u32 pktlog_defs_checksum;
 };
 
 struct ath11k_fw_stats_pdev {
index 97e7306c506d9eb1d9f6739612d6b8156c820809..4a3ff8227187c5223dd0caa4bfa4cb280dd8e4ab 100644 (file)
@@ -112,6 +112,12 @@ enum ath11k_pktlog_enum {
        ATH11K_PKTLOG_TYPE_LITE_RX      = 24,
 };
 
+enum ath11k_dbg_aggr_mode {
+       ATH11K_DBG_AGGR_MODE_AUTO,
+       ATH11K_DBG_AGGR_MODE_MANUAL,
+       ATH11K_DBG_AGGR_MODE_MAX,
+};
+
 __printf(2, 3) void ath11k_info(struct ath11k_base *ab, const char *fmt, ...);
 __printf(2, 3) void ath11k_err(struct ath11k_base *ab, const char *fmt, ...);
 __printf(2, 3) void ath11k_warn(struct ath11k_base *ab, const char *fmt, ...);
index 389dac2192380dd4e0f38bf15e6dad1148a3ef0f..68963cfc5097f90a7e166323f612d60b1d5776d5 100644 (file)
@@ -533,6 +533,222 @@ static const struct file_operations fops_peer_pktlog = {
        .llseek = default_llseek,
 };
 
+static ssize_t ath11k_dbg_sta_write_delba(struct file *file,
+                                         const char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       struct ieee80211_sta *sta = file->private_data;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k *ar = arsta->arvif->ar;
+       u32 tid, initiator, reason;
+       int ret;
+       char buf[64] = {0};
+
+       ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
+                                    user_buf, count);
+       if (ret <= 0)
+               return ret;
+
+       ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
+       if (ret != 3)
+               return -EINVAL;
+
+       /* Valid TID values are 0 through 15 */
+       if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
+               return -EINVAL;
+
+       mutex_lock(&ar->conf_mutex);
+       if (ar->state != ATH11K_STATE_ON ||
+           arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
+               ret = count;
+               goto out;
+       }
+
+       ret = ath11k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
+                                   tid, initiator, reason);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
+                           arsta->arvif->vdev_id, sta->addr, tid, initiator,
+                           reason);
+       }
+       ret = count;
+out:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static const struct file_operations fops_delba = {
+       .write = ath11k_dbg_sta_write_delba,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static ssize_t ath11k_dbg_sta_write_addba_resp(struct file *file,
+                                              const char __user *user_buf,
+                                              size_t count, loff_t *ppos)
+{
+       struct ieee80211_sta *sta = file->private_data;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k *ar = arsta->arvif->ar;
+       u32 tid, status;
+       int ret;
+       char buf[64] = {0};
+
+       ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
+                                    user_buf, count);
+       if (ret <= 0)
+               return ret;
+
+       ret = sscanf(buf, "%u %u", &tid, &status);
+       if (ret != 2)
+               return -EINVAL;
+
+       /* Valid TID values are 0 through 15 */
+       if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
+               return -EINVAL;
+
+       mutex_lock(&ar->conf_mutex);
+       if (ar->state != ATH11K_STATE_ON ||
+           arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
+               ret = count;
+               goto out;
+       }
+
+       ret = ath11k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
+                                       tid, status);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
+                           arsta->arvif->vdev_id, sta->addr, tid, status);
+       }
+       ret = count;
+out:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static const struct file_operations fops_addba_resp = {
+       .write = ath11k_dbg_sta_write_addba_resp,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static ssize_t ath11k_dbg_sta_write_addba(struct file *file,
+                                         const char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       struct ieee80211_sta *sta = file->private_data;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k *ar = arsta->arvif->ar;
+       u32 tid, buf_size;
+       int ret;
+       char buf[64] = {0};
+
+       ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
+                                    user_buf, count);
+       if (ret <= 0)
+               return ret;
+
+       ret = sscanf(buf, "%u %u", &tid, &buf_size);
+       if (ret != 2)
+               return -EINVAL;
+
+       /* Valid TID values are 0 through 15 */
+       if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
+               return -EINVAL;
+
+       mutex_lock(&ar->conf_mutex);
+       if (ar->state != ATH11K_STATE_ON ||
+           arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
+               ret = count;
+               goto out;
+       }
+
+       ret = ath11k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
+                                   tid, buf_size);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
+                           arsta->arvif->vdev_id, sta->addr, tid, buf_size);
+       }
+
+       ret = count;
+out:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static const struct file_operations fops_addba = {
+       .write = ath11k_dbg_sta_write_addba,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static ssize_t ath11k_dbg_sta_read_aggr_mode(struct file *file,
+                                            char __user *user_buf,
+                                            size_t count, loff_t *ppos)
+{
+       struct ieee80211_sta *sta = file->private_data;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k *ar = arsta->arvif->ar;
+       char buf[64];
+       int len = 0;
+
+       mutex_lock(&ar->conf_mutex);
+       len = scnprintf(buf, sizeof(buf) - len,
+                       "aggregation mode: %s\n\n%s\n%s\n",
+                       (arsta->aggr_mode == ATH11K_DBG_AGGR_MODE_AUTO) ?
+                       "auto" : "manual", "auto = 0", "manual = 1");
+       mutex_unlock(&ar->conf_mutex);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath11k_dbg_sta_write_aggr_mode(struct file *file,
+                                             const char __user *user_buf,
+                                             size_t count, loff_t *ppos)
+{
+       struct ieee80211_sta *sta = file->private_data;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k *ar = arsta->arvif->ar;
+       u32 aggr_mode;
+       int ret;
+
+       if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
+               return -EINVAL;
+
+       if (aggr_mode >= ATH11K_DBG_AGGR_MODE_MAX)
+               return -EINVAL;
+
+       mutex_lock(&ar->conf_mutex);
+       if (ar->state != ATH11K_STATE_ON ||
+           aggr_mode == arsta->aggr_mode) {
+               ret = count;
+               goto out;
+       }
+
+       ret = ath11k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to clear addba session ret: %d\n",
+                           ret);
+               goto out;
+       }
+
+       arsta->aggr_mode = aggr_mode;
+out:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static const struct file_operations fops_aggr_mode = {
+       .read = ath11k_dbg_sta_read_aggr_mode,
+       .write = ath11k_dbg_sta_write_aggr_mode,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
 void ath11k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                            struct ieee80211_sta *sta, struct dentry *dir)
 {
@@ -550,4 +766,9 @@ void ath11k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 
        debugfs_create_file("peer_pktlog", 0644, dir, sta,
                            &fops_peer_pktlog);
+
+       debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);
+       debugfs_create_file("addba", 0200, dir, sta, &fops_addba);
+       debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);
+       debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
 }
index 551f9c9fb8472d5b6c24d9f2bcaa6c97d3a79756..d4e19dc4bce16310f0723ae3157adab363219c07 100644 (file)
@@ -169,8 +169,8 @@ struct ath11k_pdev_dp {
 
 #define DP_WBM_RELEASE_RING_SIZE       64
 #define DP_TCL_DATA_RING_SIZE          512
-#define DP_TX_COMP_RING_SIZE           8192
-#define DP_TX_IDR_SIZE                 (DP_TX_COMP_RING_SIZE << 1)
+#define DP_TX_COMP_RING_SIZE           32768
+#define DP_TX_IDR_SIZE                 DP_TX_COMP_RING_SIZE
 #define DP_TCL_CMD_RING_SIZE           32
 #define DP_TCL_STATUS_RING_SIZE                32
 #define DP_REO_DST_RING_MAX            4
index f74a0e74bf3e5a259819786dfd1c8ee7578e3cab..203fd44ff352424db32068742fd112c9dd05dfac 100644 (file)
@@ -1491,7 +1491,8 @@ static void ath11k_htt_pktlog(struct ath11k_base *ab, struct sk_buff *skb)
                return;
        }
 
-       trace_ath11k_htt_pktlog(ar, data->payload, hdr->size);
+       trace_ath11k_htt_pktlog(ar, data->payload, hdr->size,
+                               ar->ab->pktlog_defs_checksum);
 }
 
 static void ath11k_htt_backpressure_event_handler(struct ath11k_base *ab,
@@ -2402,12 +2403,12 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id,
 
 try_again:
        while ((rx_desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) {
-               struct hal_reo_dest_ring *desc = (struct hal_reo_dest_ring *)rx_desc;
+               struct hal_reo_dest_ring desc = *(struct hal_reo_dest_ring *)rx_desc;
                enum hal_reo_dest_ring_push_reason push_reason;
                u32 cookie;
 
                cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
-                                  desc->buf_addr_info.info1);
+                                  desc.buf_addr_info.info1);
                buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID,
                                   cookie);
                mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, cookie);
@@ -2435,7 +2436,7 @@ try_again:
                total_msdu_reaped++;
 
                push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON,
-                                       desc->info0);
+                                       desc.info0);
                if (push_reason !=
                    HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) {
                        dev_kfree_skb_any(msdu);
@@ -2443,15 +2444,15 @@ try_again:
                        continue;
                }
 
-               rxcb->is_first_msdu = !!(desc->rx_msdu_info.info0 &
+               rxcb->is_first_msdu = !!(desc.rx_msdu_info.info0 &
                                         RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU);
-               rxcb->is_last_msdu = !!(desc->rx_msdu_info.info0 &
+               rxcb->is_last_msdu = !!(desc.rx_msdu_info.info0 &
                                        RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU);
-               rxcb->is_continuation = !!(desc->rx_msdu_info.info0 &
+               rxcb->is_continuation = !!(desc.rx_msdu_info.info0 &
                                           RX_MSDU_DESC_INFO0_MSDU_CONTINUATION);
                rxcb->mac_id = mac_id;
                rxcb->tid = FIELD_GET(HAL_REO_DEST_RING_INFO0_RX_QUEUE_NUM,
-                                     desc->info0);
+                                     desc.info0);
 
                __skb_queue_tail(&msdu_list, msdu);
 
index 7722822a0456e287b62d3ccac17fa10f165b8fcc..780a3e11b6098cf41f218d7fd3eca870d208a630 100644 (file)
@@ -599,7 +599,7 @@ struct hal_srng {
 /* Interrupt mitigation - timer threshold in us */
 #define HAL_SRNG_INT_TIMER_THRESHOLD_TX 1000
 #define HAL_SRNG_INT_TIMER_THRESHOLD_RX 500
-#define HAL_SRNG_INT_TIMER_THRESHOLD_OTHER 1000
+#define HAL_SRNG_INT_TIMER_THRESHOLD_OTHER 256
 
 /* HW SRNG configuration table */
 struct hal_srng_config {
index f43deacc01bd6d466370bf48eea27638eed30a4b..297172538620d70e442e013d61022a881e567c2f 100644 (file)
@@ -17,7 +17,26 @@ struct ath11k_peer *ath11k_peer_find(struct ath11k_base *ab, int vdev_id,
        list_for_each_entry(peer, &ab->peers, list) {
                if (peer->vdev_id != vdev_id)
                        continue;
-               if (memcmp(peer->addr, addr, ETH_ALEN))
+               if (!ether_addr_equal(peer->addr, addr))
+                       continue;
+
+               return peer;
+       }
+
+       return NULL;
+}
+
+static struct ath11k_peer *ath11k_peer_find_by_pdev_idx(struct ath11k_base *ab,
+                                                       u8 pdev_idx, const u8 *addr)
+{
+       struct ath11k_peer *peer;
+
+       lockdep_assert_held(&ab->base_lock);
+
+       list_for_each_entry(peer, &ab->peers, list) {
+               if (peer->pdev_idx != pdev_idx)
+                       continue;
+               if (!ether_addr_equal(peer->addr, addr))
                        continue;
 
                return peer;
@@ -34,7 +53,7 @@ struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab,
        lockdep_assert_held(&ab->base_lock);
 
        list_for_each_entry(peer, &ab->peers, list) {
-               if (memcmp(peer->addr, addr, ETH_ALEN))
+               if (!ether_addr_equal(peer->addr, addr))
                        continue;
 
                return peer;
@@ -200,6 +219,17 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
                return -ENOBUFS;
        }
 
+       spin_lock_bh(&ar->ab->base_lock);
+       peer = ath11k_peer_find_by_pdev_idx(ar->ab, ar->pdev_idx, param->peer_addr);
+       if (peer) {
+               spin_unlock_bh(&ar->ab->base_lock);
+               ath11k_info(ar->ab,
+                           "ignoring the peer %pM creation on same pdev idx %d\n",
+                           param->peer_addr, ar->pdev_idx);
+               return -EINVAL;
+       }
+       spin_unlock_bh(&ar->ab->base_lock);
+
        ret = ath11k_wmi_send_peer_create_cmd(ar, param);
        if (ret) {
                ath11k_warn(ar->ab,
@@ -225,6 +255,7 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
                return -ENOENT;
        }
 
+       peer->pdev_idx = ar->pdev_idx;
        peer->sta = sta;
        arvif->ast_hash = peer->ast_hash;
 
index ccca1523a6ea055e7229421e338358bf7b7812d7..5d125ce8984e3b495784dd214ae6e8ec749f871e 100644 (file)
@@ -13,6 +13,7 @@ struct ath11k_peer {
        u8 addr[ETH_ALEN];
        int peer_id;
        u16 ast_hash;
+       u8 pdev_idx;
 
        /* protected by ab->data_lock */
        struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
index 8700a622be7bd3bab1592a83a0f13bdbba2584dc..66d0aae7816cb6e107a44a28c77bfc122a727606 100644 (file)
@@ -21,14 +21,16 @@ static inline void trace_ ## name(proto) {}
 #define TRACE_SYSTEM ath11k
 
 TRACE_EVENT(ath11k_htt_pktlog,
-           TP_PROTO(struct ath11k *ar, const void *buf, u16 buf_len),
+           TP_PROTO(struct ath11k *ar, const void *buf, u16 buf_len,
+                    u32 pktlog_checksum),
 
-       TP_ARGS(ar, buf, buf_len),
+       TP_ARGS(ar, buf, buf_len, pktlog_checksum),
 
        TP_STRUCT__entry(
                __string(device, dev_name(ar->ab->dev))
                __string(driver, dev_driver_string(ar->ab->dev))
                __field(u16, buf_len)
+               __field(u32, pktlog_checksum)
                __dynamic_array(u8, pktlog, buf_len)
        ),
 
@@ -36,14 +38,16 @@ TRACE_EVENT(ath11k_htt_pktlog,
                __assign_str(device, dev_name(ar->ab->dev));
                __assign_str(driver, dev_driver_string(ar->ab->dev));
                __entry->buf_len = buf_len;
+               __entry->pktlog_checksum = pktlog_checksum;
                memcpy(__get_dynamic_array(pktlog), buf, buf_len);
        ),
 
        TP_printk(
-               "%s %s size %hu",
+               "%s %s size %hu pktlog_checksum %d",
                __get_str(driver),
                __get_str(device),
-               __entry->buf_len
+               __entry->buf_len,
+               __entry->pktlog_checksum
         )
 );
 
index e7ce36966d6a74ec0bd2646f84ea573344e5e4e0..c2a97237768740656e833187c242b4d76f4ab049 100644 (file)
@@ -87,8 +87,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = {
                = { .min_len = sizeof(struct wmi_pdev_bss_chan_info_event) },
        [WMI_TAG_VDEV_INSTALL_KEY_COMPLETE_EVENT]
                = { .min_len = sizeof(struct wmi_vdev_install_key_compl_event) },
-       [WMI_TAG_READY_EVENT]
-               = {.min_len = sizeof(struct wmi_ready_event) },
+       [WMI_TAG_READY_EVENT] = {
+               .min_len = sizeof(struct wmi_ready_event_min) },
        [WMI_TAG_SERVICE_AVAILABLE_EVENT]
                = {.min_len = sizeof(struct wmi_service_available_event) },
        [WMI_TAG_PEER_ASSOC_CONF_EVENT]
@@ -2368,6 +2368,146 @@ int ath11k_wmi_send_dfs_phyerr_offload_enable_cmd(struct ath11k *ar,
        return ret;
 }
 
+int ath11k_wmi_delba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac,
+                         u32 tid, u32 initiator, u32 reason)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_delba_send_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_delba_send_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_DELBA_SEND_CMD) |
+                       FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = vdev_id;
+       ether_addr_copy(cmd->peer_macaddr.addr, mac);
+       cmd->tid = tid;
+       cmd->initiator = initiator;
+       cmd->reasoncode = reason;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "wmi delba send vdev_id 0x%X mac_addr %pM tid %u initiator %u reason %u\n",
+                  vdev_id, mac, tid, initiator, reason);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_DELBA_SEND_CMDID);
+
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_DELBA_SEND_CMDID cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_addba_set_resp(struct ath11k *ar, u32 vdev_id, const u8 *mac,
+                             u32 tid, u32 status)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_addba_setresponse_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_addba_setresponse_cmd *)skb->data;
+       cmd->tlv_header =
+               FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ADDBA_SETRESPONSE_CMD) |
+               FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = vdev_id;
+       ether_addr_copy(cmd->peer_macaddr.addr, mac);
+       cmd->tid = tid;
+       cmd->statuscode = status;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "wmi addba set resp vdev_id 0x%X mac_addr %pM tid %u status %u\n",
+                  vdev_id, mac, tid, status);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_ADDBA_SET_RESP_CMDID);
+
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_ADDBA_SET_RESP_CMDID cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_addba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac,
+                         u32 tid, u32 buf_size)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_addba_send_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_addba_send_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ADDBA_SEND_CMD) |
+               FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = vdev_id;
+       ether_addr_copy(cmd->peer_macaddr.addr, mac);
+       cmd->tid = tid;
+       cmd->buffersize = buf_size;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "wmi addba send vdev_id 0x%X mac_addr %pM tid %u bufsize %u\n",
+                  vdev_id, mac, tid, buf_size);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_ADDBA_SEND_CMDID);
+
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_ADDBA_SEND_CMDID cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_addba_clear_resp(struct ath11k *ar, u32 vdev_id, const u8 *mac)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_addba_clear_resp_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_addba_clear_resp_cmd *)skb->data;
+       cmd->tlv_header =
+               FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ADDBA_CLEAR_RESP_CMD) |
+               FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = vdev_id;
+       ether_addr_copy(cmd->peer_macaddr.addr, mac);
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "wmi addba clear resp vdev_id 0x%X mac_addr %pM\n",
+                  vdev_id, mac);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_ADDBA_CLEAR_RESP_CMDID);
+
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_ADDBA_CLEAR_RESP_CMDID cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
 int ath11k_wmi_pdev_peer_pktlog_filter(struct ath11k *ar, u8 *addr, u8 enable)
 {
        struct ath11k_pdev_wmi *wmi = ar->wmi;
@@ -2779,7 +2919,7 @@ int ath11k_wmi_send_bss_color_change_enable_cmd(struct ath11k *ar, u32 vdev_id,
        ret = ath11k_wmi_cmd_send(wmi, skb,
                                  WMI_BSS_COLOR_CHANGE_ENABLE_CMDID);
        if (ret) {
-               ath11k_warn(ab, "Failed to send WMI_TWT_DIeABLE_CMDID");
+               ath11k_warn(ab, "Failed to send WMI_BSS_COLOR_CHANGE_ENABLE_CMDID");
                dev_kfree_skb(skb);
        }
        return ret;
@@ -3105,7 +3245,7 @@ int ath11k_wmi_cmd_init(struct ath11k_base *ab)
        config.beacon_tx_offload_max_vdev = ab->num_radios * TARGET_MAX_BCN_OFFLD;
        config.rx_batchmode = TARGET_RX_BATCHMODE;
        config.peer_map_unmap_v2_support = 1;
-       config.twt_ap_pdev_count = 2;
+       config.twt_ap_pdev_count = ab->num_radios;
        config.twt_ap_sta_count = 1000;
 
        memcpy(&wmi_sc->wlan_resource_config, &config, sizeof(config));
@@ -3740,8 +3880,9 @@ static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id,
 
        ieee80211_tx_status_irqsafe(ar->hw, msdu);
 
-       WARN_ON_ONCE(atomic_read(&ar->num_pending_mgmt_tx) == 0);
-       atomic_dec(&ar->num_pending_mgmt_tx);
+       /* WARN when we received this event without doing any mgmt tx */
+       if (atomic_dec_if_positive(&ar->num_pending_mgmt_tx) < 0)
+               WARN_ON_ONCE(1);
 
        return 0;
 }
@@ -4851,7 +4992,7 @@ static int ath11k_wmi_tlv_rdy_parse(struct ath11k_base *ab, u16 tag, u16 len,
                                    const void *ptr, void *data)
 {
        struct wmi_tlv_rdy_parse *rdy_parse = data;
-       struct wmi_ready_event *fixed_param;
+       struct wmi_ready_event fixed_param;
        struct wmi_mac_addr *addr_list;
        struct ath11k_pdev *pdev;
        u32 num_mac_addr;
@@ -4859,11 +5000,16 @@ static int ath11k_wmi_tlv_rdy_parse(struct ath11k_base *ab, u16 tag, u16 len,
 
        switch (tag) {
        case WMI_TAG_READY_EVENT:
-               fixed_param = (struct wmi_ready_event *)ptr;
-               ab->wlan_init_status = fixed_param->status;
-               rdy_parse->num_extra_mac_addr = fixed_param->num_extra_mac_addr;
-
-               ether_addr_copy(ab->mac_addr, fixed_param->mac_addr.addr);
+               memset(&fixed_param, 0, sizeof(fixed_param));
+               memcpy(&fixed_param, (struct wmi_ready_event *)ptr,
+                      min_t(u16, sizeof(fixed_param), len));
+               ab->wlan_init_status = fixed_param.ready_event_min.status;
+               rdy_parse->num_extra_mac_addr =
+                       fixed_param.ready_event_min.num_extra_mac_addr;
+
+               ether_addr_copy(ab->mac_addr,
+                               fixed_param.ready_event_min.mac_addr.addr);
+               ab->pktlog_defs_checksum = fixed_param.pktlog_defs_checksum;
                ab->wmi_ready = true;
                break;
        case WMI_TAG_ARRAY_FIXED_STRUCT:
index 510f9c6bc1d78a56140602c5f6f95d0036535793..ba05935b715a5d72cb950216ec65d6c13b1b9f34 100644 (file)
@@ -2345,7 +2345,7 @@ struct wmi_mac_addr {
        } __packed;
 } __packed;
 
-struct wmi_ready_event {
+struct wmi_ready_event_min {
        struct wmi_abi_version fw_abi_vers;
        struct wmi_mac_addr mac_addr;
        u32 status;
@@ -2355,6 +2355,12 @@ struct wmi_ready_event {
        u32 num_extra_peers;
 } __packed;
 
+struct wmi_ready_event {
+       struct wmi_ready_event_min ready_event_min;
+       u32 max_ast_index;
+       u32 pktlog_defs_checksum;
+} __packed;
+
 struct wmi_service_available_event {
        u32 wmi_service_segment_offset;
        u32 wmi_service_segment_bitmap[WMI_SERVICE_SEGMENT_BM_SIZE32];
@@ -3649,6 +3655,37 @@ struct wmi_therm_throt_level_config_info {
        u32 prio;
 } __packed;
 
+struct wmi_delba_send_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+       u32 tid;
+       u32 initiator;
+       u32 reasoncode;
+} __packed;
+
+struct wmi_addba_setresponse_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+       u32 tid;
+       u32 statuscode;
+} __packed;
+
+struct wmi_addba_send_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+       u32 tid;
+       u32 buffersize;
+} __packed;
+
+struct wmi_addba_clear_resp_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+} __packed;
+
 struct wmi_pdev_pktlog_filter_info {
        u32 tlv_header;
        struct wmi_mac_addr peer_macaddr;
@@ -4822,6 +4859,13 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar,
                                       struct scan_chan_list_params *chan_list);
 int ath11k_wmi_send_dfs_phyerr_offload_enable_cmd(struct ath11k *ar,
                                                  u32 pdev_id);
+int ath11k_wmi_addba_clear_resp(struct ath11k *ar, u32 vdev_id, const u8 *mac);
+int ath11k_wmi_addba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac,
+                         u32 tid, u32 buf_size);
+int ath11k_wmi_addba_set_resp(struct ath11k *ar, u32 vdev_id, const u8 *mac,
+                             u32 tid, u32 status);
+int ath11k_wmi_delba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac,
+                         u32 tid, u32 initiator, u32 reason);
 int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar,
                                            u32 vdev_id, u32 bcn_ctrl_op);
 int
index dd0c32379375af8d63a4ad95212266de2bf3766f..4ed21dad6a8e16040d177c3ff9ef7c7e09035b3f 100644 (file)
@@ -612,6 +612,11 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
                        hif_dev->remain_skb = nskb;
                        spin_unlock(&hif_dev->rx_lock);
                } else {
+                       if (pool_index == MAX_PKT_NUM_IN_TRANSFER) {
+                               dev_err(&hif_dev->udev->dev,
+                                       "ath9k_htc: over RX MAX_PKT_NUM\n");
+                               goto err;
+                       }
                        nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
                        if (!nskb) {
                                dev_err(&hif_dev->udev->dev,
@@ -638,9 +643,9 @@ err:
 
 static void ath9k_hif_usb_rx_cb(struct urb *urb)
 {
-       struct sk_buff *skb = (struct sk_buff *) urb->context;
-       struct hif_device_usb *hif_dev =
-               usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
+       struct rx_buf *rx_buf = (struct rx_buf *)urb->context;
+       struct hif_device_usb *hif_dev = rx_buf->hif_dev;
+       struct sk_buff *skb = rx_buf->skb;
        int ret;
 
        if (!skb)
@@ -680,14 +685,15 @@ resubmit:
        return;
 free:
        kfree_skb(skb);
+       kfree(rx_buf);
 }
 
 static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
 {
-       struct sk_buff *skb = (struct sk_buff *) urb->context;
+       struct rx_buf *rx_buf = (struct rx_buf *)urb->context;
+       struct hif_device_usb *hif_dev = rx_buf->hif_dev;
+       struct sk_buff *skb = rx_buf->skb;
        struct sk_buff *nskb;
-       struct hif_device_usb *hif_dev =
-               usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
        int ret;
 
        if (!skb)
@@ -745,6 +751,7 @@ resubmit:
        return;
 free:
        kfree_skb(skb);
+       kfree(rx_buf);
        urb->context = NULL;
 }
 
@@ -790,7 +797,7 @@ static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
        init_usb_anchor(&hif_dev->mgmt_submitted);
 
        for (i = 0; i < MAX_TX_URB_NUM; i++) {
-               tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL);
+               tx_buf = kzalloc(sizeof(*tx_buf), GFP_KERNEL);
                if (!tx_buf)
                        goto err;
 
@@ -827,8 +834,9 @@ static void ath9k_hif_usb_dealloc_rx_urbs(struct hif_device_usb *hif_dev)
 
 static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev)
 {
-       struct urb *urb = NULL;
+       struct rx_buf *rx_buf = NULL;
        struct sk_buff *skb = NULL;
+       struct urb *urb = NULL;
        int i, ret;
 
        init_usb_anchor(&hif_dev->rx_submitted);
@@ -836,6 +844,12 @@ static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev)
 
        for (i = 0; i < MAX_RX_URB_NUM; i++) {
 
+               rx_buf = kzalloc(sizeof(*rx_buf), GFP_KERNEL);
+               if (!rx_buf) {
+                       ret = -ENOMEM;
+                       goto err_rxb;
+               }
+
                /* Allocate URB */
                urb = usb_alloc_urb(0, GFP_KERNEL);
                if (urb == NULL) {
@@ -850,11 +864,14 @@ static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev)
                        goto err_skb;
                }
 
+               rx_buf->hif_dev = hif_dev;
+               rx_buf->skb = skb;
+
                usb_fill_bulk_urb(urb, hif_dev->udev,
                                  usb_rcvbulkpipe(hif_dev->udev,
                                                  USB_WLAN_RX_PIPE),
                                  skb->data, MAX_RX_BUF_SIZE,
-                                 ath9k_hif_usb_rx_cb, skb);
+                                 ath9k_hif_usb_rx_cb, rx_buf);
 
                /* Anchor URB */
                usb_anchor_urb(urb, &hif_dev->rx_submitted);
@@ -880,6 +897,8 @@ err_submit:
 err_skb:
        usb_free_urb(urb);
 err_urb:
+       kfree(rx_buf);
+err_rxb:
        ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
        return ret;
 }
@@ -891,14 +910,21 @@ static void ath9k_hif_usb_dealloc_reg_in_urbs(struct hif_device_usb *hif_dev)
 
 static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev)
 {
-       struct urb *urb = NULL;
+       struct rx_buf *rx_buf = NULL;
        struct sk_buff *skb = NULL;
+       struct urb *urb = NULL;
        int i, ret;
 
        init_usb_anchor(&hif_dev->reg_in_submitted);
 
        for (i = 0; i < MAX_REG_IN_URB_NUM; i++) {
 
+               rx_buf = kzalloc(sizeof(*rx_buf), GFP_KERNEL);
+               if (!rx_buf) {
+                       ret = -ENOMEM;
+                       goto err_rxb;
+               }
+
                /* Allocate URB */
                urb = usb_alloc_urb(0, GFP_KERNEL);
                if (urb == NULL) {
@@ -913,11 +939,14 @@ static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev)
                        goto err_skb;
                }
 
+               rx_buf->hif_dev = hif_dev;
+               rx_buf->skb = skb;
+
                usb_fill_int_urb(urb, hif_dev->udev,
                                  usb_rcvintpipe(hif_dev->udev,
                                                  USB_REG_IN_PIPE),
                                  skb->data, MAX_REG_IN_BUF_SIZE,
-                                 ath9k_hif_usb_reg_in_cb, skb, 1);
+                                 ath9k_hif_usb_reg_in_cb, rx_buf, 1);
 
                /* Anchor URB */
                usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
@@ -943,6 +972,8 @@ err_submit:
 err_skb:
        usb_free_urb(urb);
 err_urb:
+       kfree(rx_buf);
+err_rxb:
        ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev);
        return ret;
 }
@@ -973,7 +1004,7 @@ err:
        return -ENOMEM;
 }
 
-static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
+void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
 {
        usb_kill_anchored_urbs(&hif_dev->regout_submitted);
        ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev);
@@ -1341,8 +1372,9 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
 
        if (hif_dev->flags & HIF_USB_READY) {
                ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged);
-               ath9k_htc_hw_free(hif_dev->htc_handle);
                ath9k_hif_usb_dev_deinit(hif_dev);
+               ath9k_destoy_wmi(hif_dev->htc_handle->drv_priv);
+               ath9k_htc_hw_free(hif_dev->htc_handle);
        }
 
        usb_set_intfdata(interface, NULL);
index 7846916aa01df2a00a5f2a7a6332b514190c5114..5985aa15ca931386d58e06fea36402f10835936d 100644 (file)
@@ -86,6 +86,11 @@ struct tx_buf {
        struct list_head list;
 };
 
+struct rx_buf {
+       struct sk_buff *skb;
+       struct hif_device_usb *hif_dev;
+};
+
 #define HIF_USB_TX_STOP  BIT(0)
 #define HIF_USB_TX_FLUSH BIT(1)
 
@@ -133,5 +138,6 @@ struct hif_device_usb {
 
 int ath9k_hif_usb_init(void);
 void ath9k_hif_usb_exit(void);
+void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev);
 
 #endif /* HTC_USB_H */
index d961095ab01f6f7bced49ee846a10f0ae40f97e6..40a065028ebecf219634660e501476a4b25e502a 100644 (file)
@@ -931,8 +931,9 @@ err_init:
 int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
                           u16 devid, char *product, u32 drv_info)
 {
-       struct ieee80211_hw *hw;
+       struct hif_device_usb *hif_dev;
        struct ath9k_htc_priv *priv;
+       struct ieee80211_hw *hw;
        int ret;
 
        hw = ieee80211_alloc_hw(sizeof(struct ath9k_htc_priv), &ath9k_htc_ops);
@@ -967,7 +968,10 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
        return 0;
 
 err_init:
-       ath9k_deinit_wmi(priv);
+       ath9k_stop_wmi(priv);
+       hif_dev = (struct hif_device_usb *)htc_handle->hif_dev;
+       ath9k_hif_usb_dealloc_urbs(hif_dev);
+       ath9k_destoy_wmi(priv);
 err_free:
        ieee80211_free_hw(hw);
        return ret;
@@ -982,7 +986,7 @@ void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug)
                        htc_handle->drv_priv->ah->ah_flags |= AH_UNPLUGGED;
 
                ath9k_deinit_device(htc_handle->drv_priv);
-               ath9k_deinit_wmi(htc_handle->drv_priv);
+               ath9k_stop_wmi(htc_handle->drv_priv);
                ieee80211_free_hw(htc_handle->drv_priv->hw);
        }
 }
index d091c8ebdcf08244796021150d9d261ee43d2564..d2e062eaf56149b3ea76d452d75ecf81f9154a1b 100644 (file)
@@ -113,6 +113,9 @@ static void htc_process_conn_rsp(struct htc_target *target,
 
        if (svc_rspmsg->status == HTC_SERVICE_SUCCESS) {
                epid = svc_rspmsg->endpoint_id;
+               if (epid < 0 || epid >= ENDPOINT_MAX)
+                       return;
+
                service_id = be16_to_cpu(svc_rspmsg->service_id);
                max_msglen = be16_to_cpu(svc_rspmsg->max_msg_len);
                endpoint = &target->endpoint[epid];
@@ -170,7 +173,6 @@ static int htc_config_pipe_credits(struct htc_target *target)
        time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
        if (!time_left) {
                dev_err(target->dev, "HTC credit config timeout\n");
-               kfree_skb(skb);
                return -ETIMEDOUT;
        }
 
@@ -206,7 +208,6 @@ static int htc_setup_complete(struct htc_target *target)
        time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
        if (!time_left) {
                dev_err(target->dev, "HTC start timeout\n");
-               kfree_skb(skb);
                return -ETIMEDOUT;
        }
 
@@ -279,7 +280,6 @@ int htc_connect_service(struct htc_target *target,
        if (!time_left) {
                dev_err(target->dev, "Service connection timeout for: %d\n",
                        service_connreq->service_id);
-               kfree_skb(skb);
                return -ETIMEDOUT;
        }
 
index cdc146091194828af19d3ba984b56e3928ced896..e7a3127395be9c8aecf88d8cff2e12295aa4bc0c 100644 (file)
@@ -112,14 +112,17 @@ struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv)
        return wmi;
 }
 
-void ath9k_deinit_wmi(struct ath9k_htc_priv *priv)
+void ath9k_stop_wmi(struct ath9k_htc_priv *priv)
 {
        struct wmi *wmi = priv->wmi;
 
        mutex_lock(&wmi->op_mutex);
        wmi->stopped = true;
        mutex_unlock(&wmi->op_mutex);
+}
 
+void ath9k_destoy_wmi(struct ath9k_htc_priv *priv)
+{
        kfree(priv->wmi);
 }
 
@@ -336,7 +339,6 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
                ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n",
                        wmi_cmd_to_name(cmd_id));
                mutex_unlock(&wmi->op_mutex);
-               kfree_skb(skb);
                return -ETIMEDOUT;
        }
 
index 380175d5ecd7a7d54e22d27fb434efa65dfcdd10..d8b9122062324cf244af2eb7dcd4f8e2ef5ebb42 100644 (file)
@@ -179,7 +179,6 @@ struct wmi {
 };
 
 struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv);
-void ath9k_deinit_wmi(struct ath9k_htc_priv *priv);
 int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi,
                      enum htc_endpoint_id *wmi_ctrl_epid);
 int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
@@ -189,6 +188,8 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
 void ath9k_wmi_event_tasklet(unsigned long data);
 void ath9k_fatal_work(struct work_struct *work);
 void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv);
+void ath9k_stop_wmi(struct ath9k_htc_priv *priv);
+void ath9k_destoy_wmi(struct ath9k_htc_priv *priv);
 
 #define WMI_CMD(_wmi_cmd)                                              \
        do {                                                            \