Merge tag 'iwlwifi-next-for-kalle-2015-10-05' of git://git.kernel.org/pub/scm/linux...
authorKalle Valo <kvalo@codeaurora.org>
Wed, 7 Oct 2015 09:14:23 +0000 (12:14 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Wed, 7 Oct 2015 09:14:23 +0000 (12:14 +0300)
* more clean-ups towards multiple RX queues;
* some rate scaling fixes and improvements;
* some time-of-flight fixes;
* other generic improvements and clean-ups;

76 files changed:
drivers/bcma/main.c
drivers/net/wireless/airo.c
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.h
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/txrx.c
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.h
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/carl9170/rx.c
drivers/net/wireless/ath/dfs_pattern_detector.c
drivers/net/wireless/ath/dfs_pattern_detector.h
drivers/net/wireless/ath/dfs_pri_detector.c
drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
drivers/net/wireless/brcm80211/brcmfmac/btcoex.c
drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h
drivers/net/wireless/brcm80211/brcmfmac/chip.c
drivers/net/wireless/brcm80211/brcmfmac/chip.h
drivers/net/wireless/brcm80211/brcmfmac/core.c
drivers/net/wireless/brcm80211/brcmfmac/core.h
drivers/net/wireless/brcm80211/brcmfmac/debug.h
drivers/net/wireless/brcm80211/brcmfmac/feature.c
drivers/net/wireless/brcm80211/brcmfmac/flowring.c
drivers/net/wireless/brcm80211/brcmfmac/flowring.h
drivers/net/wireless/brcm80211/brcmfmac/fweh.c
drivers/net/wireless/brcm80211/brcmfmac/fweh.h
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
drivers/net/wireless/brcm80211/brcmfmac/p2p.c
drivers/net/wireless/brcm80211/brcmfmac/p2p.h
drivers/net/wireless/brcm80211/brcmfmac/pcie.c
drivers/net/wireless/brcm80211/brcmfmac/proto.h
drivers/net/wireless/brcm80211/brcmfmac/sdio.c
drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
drivers/net/wireless/mwifiex/11n_aggr.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/debugfs.c
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sdio.c
drivers/net/wireless/mwifiex/sta_cmd.c
drivers/net/wireless/mwifiex/sta_cmdresp.c
drivers/net/wireless/mwifiex/sta_event.c
drivers/net/wireless/mwifiex/sta_tx.c
drivers/net/wireless/mwifiex/tdls.c
drivers/net/wireless/mwifiex/txrx.c
drivers/net/wireless/mwifiex/uap_event.c
drivers/net/wireless/mwifiex/uap_txrx.c
drivers/net/wireless/mwifiex/usb.c
drivers/net/wireless/mwifiex/usb.h
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/ti/wl18xx/main.c
drivers/net/wireless/ti/wlcore/wlcore.h
drivers/ssb/main.c
drivers/ssb/pcmcia.c
drivers/ssb/sdio.c
drivers/ssb/ssb_private.h
include/linux/bcma/bcma.h

index 24882c1..59d8d0d 100644 (file)
@@ -436,13 +436,8 @@ int bcma_bus_register(struct bcma_bus *bus)
        }
 
        dev = bcma_bus_get_host_dev(bus);
-       /* TODO: remove check for IS_BUILTIN(CONFIG_BCMA) check when
-        * of_default_bus_match_table is exported or in some other way
-        * accessible. This is just a temporary workaround.
-        */
-       if (IS_BUILTIN(CONFIG_BCMA) && dev) {
-               of_platform_populate(dev->of_node, of_default_bus_match_table,
-                                    NULL, dev);
+       if (dev) {
+               of_platform_default_populate(dev->of_node, NULL, dev);
        }
 
        /* Cores providing flash access go before SPROM init */
index d0c97c2..8ae838d 100644 (file)
@@ -1237,6 +1237,7 @@ struct airo_info {
 
        int                     wep_capable;
        int                     max_wep_idx;
+       int                     last_auth;
 
        /* WPA-related stuff */
        unsigned int bssListFirst;
@@ -3266,6 +3267,7 @@ static void airo_handle_link(struct airo_info *ai)
                        wake_up_interruptible(&ai->thr_wait);
                } else
                        airo_send_event(ai->dev);
+               netif_carrier_on(ai->dev);
        } else if (!scan_forceloss) {
                if (auto_wep && !ai->expires) {
                        ai->expires = RUN_AT(3*HZ);
@@ -3276,6 +3278,9 @@ static void airo_handle_link(struct airo_info *ai)
                eth_zero_addr(wrqu.ap_addr.sa_data);
                wrqu.ap_addr.sa_family = ARPHRD_ETHER;
                wireless_send_event(ai->dev, SIOCGIWAP, &wrqu, NULL);
+               netif_carrier_off(ai->dev);
+       } else {
+               netif_carrier_off(ai->dev);
        }
 }
 
@@ -3612,6 +3617,7 @@ static void disable_MAC( struct airo_info *ai, int lock ) {
                return;
 
        if (test_bit(FLAG_ENABLED, &ai->flags)) {
+               netif_carrier_off(ai->dev);
                memset(&cmd, 0, sizeof(cmd));
                cmd.cmd = MAC_DISABLE; // disable in case already enabled
                issuecommand(ai, &cmd, &rsp);
@@ -3786,6 +3792,16 @@ badrx:
        }
 }
 
+static inline void set_auth_type(struct airo_info *local, int auth_type)
+{
+       local->config.authType = auth_type;
+       /* Cache the last auth type used (of AUTH_OPEN and AUTH_ENCRYPT).
+        * Used by airo_set_auth()
+        */
+       if (auth_type == AUTH_OPEN || auth_type == AUTH_ENCRYPT)
+               local->last_auth = auth_type;
+}
+
 static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
 {
        Cmd cmd;
@@ -3862,7 +3878,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
                                                "level scale");
                }
                ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
-               ai->config.authType = AUTH_OPEN;
+               set_auth_type(ai, AUTH_OPEN);
                ai->config.modulation = MOD_CCK;
 
                if (le16_to_cpu(cap_rid.len) >= sizeof(cap_rid) &&
@@ -4880,13 +4896,13 @@ static void proc_config_on_close(struct inode *inode, struct file *file)
                        line += 5;
                        switch( line[0] ) {
                        case 's':
-                               ai->config.authType = AUTH_SHAREDKEY;
+                               set_auth_type(ai, AUTH_SHAREDKEY);
                                break;
                        case 'e':
-                               ai->config.authType = AUTH_ENCRYPT;
+                               set_auth_type(ai, AUTH_ENCRYPT);
                                break;
                        default:
-                               ai->config.authType = AUTH_OPEN;
+                               set_auth_type(ai, AUTH_OPEN);
                                break;
                        }
                        set_bit (FLAG_COMMIT, &ai->flags);
@@ -6368,9 +6384,8 @@ static int airo_set_encode(struct net_device *dev,
                 * should be enabled (user may turn it off later)
                 * This is also how "iwconfig ethX key on" works */
                if((index == current_index) && (key.len > 0) &&
-                  (local->config.authType == AUTH_OPEN)) {
-                       local->config.authType = AUTH_ENCRYPT;
-               }
+                  (local->config.authType == AUTH_OPEN))
+                       set_auth_type(local, AUTH_ENCRYPT);
        } else {
                /* Do we want to just set the transmit key index ? */
                int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
@@ -6389,12 +6404,12 @@ static int airo_set_encode(struct net_device *dev,
                }
        }
        /* Read the flags */
-       if(dwrq->flags & IW_ENCODE_DISABLED)
-               local->config.authType = AUTH_OPEN;     // disable encryption
+       if (dwrq->flags & IW_ENCODE_DISABLED)
+               set_auth_type(local, AUTH_OPEN);        /* disable encryption */
        if(dwrq->flags & IW_ENCODE_RESTRICTED)
-               local->config.authType = AUTH_SHAREDKEY;        // Only Both
-       if(dwrq->flags & IW_ENCODE_OPEN)
-               local->config.authType = AUTH_ENCRYPT;  // Only Wep
+               set_auth_type(local, AUTH_SHAREDKEY);   /* Only Both */
+       if (dwrq->flags & IW_ENCODE_OPEN)
+               set_auth_type(local, AUTH_ENCRYPT);     /* Only Wep */
        /* Commit the changes to flags if needed */
        if (local->config.authType != currentAuthType)
                set_bit (FLAG_COMMIT, &local->flags);
@@ -6549,12 +6564,12 @@ static int airo_set_encodeext(struct net_device *dev,
        }
 
        /* Read the flags */
-       if(encoding->flags & IW_ENCODE_DISABLED)
-               local->config.authType = AUTH_OPEN;     // disable encryption
+       if (encoding->flags & IW_ENCODE_DISABLED)
+               set_auth_type(local, AUTH_OPEN);        /* disable encryption */
        if(encoding->flags & IW_ENCODE_RESTRICTED)
-               local->config.authType = AUTH_SHAREDKEY;        // Only Both
-       if(encoding->flags & IW_ENCODE_OPEN)
-               local->config.authType = AUTH_ENCRYPT;  // Only Wep
+               set_auth_type(local, AUTH_SHAREDKEY);   /* Only Both */
+       if (encoding->flags & IW_ENCODE_OPEN)
+               set_auth_type(local, AUTH_ENCRYPT);
        /* Commit the changes to flags if needed */
        if (local->config.authType != currentAuthType)
                set_bit (FLAG_COMMIT, &local->flags);
@@ -6659,9 +6674,9 @@ static int airo_set_auth(struct net_device *dev,
                if (param->value) {
                        /* Only change auth type if unencrypted */
                        if (currentAuthType == AUTH_OPEN)
-                               local->config.authType = AUTH_ENCRYPT;
+                               set_auth_type(local, AUTH_ENCRYPT);
                } else {
-                       local->config.authType = AUTH_OPEN;
+                       set_auth_type(local, AUTH_OPEN);
                }
 
                /* Commit the changes to flags if needed */
@@ -6670,13 +6685,14 @@ static int airo_set_auth(struct net_device *dev,
                break;
 
        case IW_AUTH_80211_AUTH_ALG: {
-                       /* FIXME: What about AUTH_OPEN?  This API seems to
-                        * disallow setting our auth to AUTH_OPEN.
-                        */
                        if (param->value & IW_AUTH_ALG_SHARED_KEY) {
-                               local->config.authType = AUTH_SHAREDKEY;
+                               set_auth_type(local, AUTH_SHAREDKEY);
                        } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
-                               local->config.authType = AUTH_ENCRYPT;
+                               /* We don't know here if WEP open system or
+                                * unencrypted mode was requested - so use the
+                                * last mode (of these two) used last time
+                                */
+                               set_auth_type(local, local->last_auth);
                        } else
                                return -EINVAL;
 
index b87b986..879625a 100644 (file)
@@ -34,16 +34,19 @@ unsigned int ath10k_debug_mask;
 static unsigned int ath10k_cryptmode_param;
 static bool uart_print;
 static bool skip_otp;
+static bool rawmode;
 
 module_param_named(debug_mask, ath10k_debug_mask, uint, 0644);
 module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644);
 module_param(uart_print, bool, 0644);
 module_param(skip_otp, bool, 0644);
+module_param(rawmode, bool, 0644);
 
 MODULE_PARM_DESC(debug_mask, "Debugging mask");
 MODULE_PARM_DESC(uart_print, "Uart target debugging");
 MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode");
 MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software");
+MODULE_PARM_DESC(rawmode, "Use raw 802.11 frame datapath");
 
 static const struct ath10k_hw_params ath10k_hw_params_list[] = {
        {
@@ -54,6 +57,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .has_shifted_cc_wraparound = true,
                .otp_exe_param = 0,
                .channel_counters_freq_hz = 88000,
+               .max_probe_resp_desc_thres = 0,
                .fw = {
                        .dir = QCA988X_HW_2_0_FW_DIR,
                        .fw = QCA988X_HW_2_0_FW_FILE,
@@ -70,6 +74,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .uart_pin = 6,
                .otp_exe_param = 0,
                .channel_counters_freq_hz = 88000,
+               .max_probe_resp_desc_thres = 0,
                .fw = {
                        .dir = QCA6174_HW_2_1_FW_DIR,
                        .fw = QCA6174_HW_2_1_FW_FILE,
@@ -86,6 +91,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .uart_pin = 6,
                .otp_exe_param = 0,
                .channel_counters_freq_hz = 88000,
+               .max_probe_resp_desc_thres = 0,
                .fw = {
                        .dir = QCA6174_HW_3_0_FW_DIR,
                        .fw = QCA6174_HW_3_0_FW_FILE,
@@ -102,6 +108,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .uart_pin = 6,
                .otp_exe_param = 0,
                .channel_counters_freq_hz = 88000,
+               .max_probe_resp_desc_thres = 0,
                .fw = {
                        /* uses same binaries as hw3.0 */
                        .dir = QCA6174_HW_3_0_FW_DIR,
@@ -120,6 +127,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .otp_exe_param = 0x00000700,
                .continuous_frag_desc = true,
                .channel_counters_freq_hz = 150000,
+               .max_probe_resp_desc_thres = 24,
                .fw = {
                        .dir = QCA99X0_HW_2_0_FW_DIR,
                        .fw = QCA99X0_HW_2_0_FW_FILE,
@@ -142,12 +150,17 @@ static const char *const ath10k_core_fw_feature_str[] = {
        [ATH10K_FW_FEATURE_IGNORE_OTP_RESULT] = "ignore-otp",
        [ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING] = "no-4addr-pad",
        [ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT] = "skip-clock-init",
+       [ATH10K_FW_FEATURE_RAW_MODE_SUPPORT] = "raw-mode",
 };
 
 static unsigned int ath10k_core_get_fw_feature_str(char *buf,
                                                   size_t buf_len,
                                                   enum ath10k_fw_features feat)
 {
+       /* make sure that ath10k_core_fw_feature_str[] gets updated */
+       BUILD_BUG_ON(ARRAY_SIZE(ath10k_core_fw_feature_str) !=
+                    ATH10K_FW_FEATURE_COUNT);
+
        if (feat >= ARRAY_SIZE(ath10k_core_fw_feature_str) ||
            WARN_ON(!ath10k_core_fw_feature_str[feat])) {
                return scnprintf(buf, buf_len, "bit%d", feat);
@@ -1117,6 +1130,15 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
        ar->htt.max_num_amsdu = ATH10K_HTT_MAX_NUM_AMSDU_DEFAULT;
        ar->htt.max_num_ampdu = ATH10K_HTT_MAX_NUM_AMPDU_DEFAULT;
 
+       if (rawmode) {
+               if (!test_bit(ATH10K_FW_FEATURE_RAW_MODE_SUPPORT,
+                             ar->fw_features)) {
+                       ath10k_err(ar, "rawmode = 1 requires support from firmware");
+                       return -EINVAL;
+               }
+               set_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags);
+       }
+
        if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
                ar->wmi.rx_decap_mode = ATH10K_HW_TXRX_RAW;
 
@@ -1714,6 +1736,7 @@ void ath10k_core_destroy(struct ath10k *ar)
        destroy_workqueue(ar->workqueue_aux);
 
        ath10k_debug_destroy(ar);
+       ath10k_wmi_free_host_mem(ar);
        ath10k_mac_destroy(ar);
 }
 EXPORT_SYMBOL(ath10k_core_destroy);
index 1254214..04e040a 100644 (file)
@@ -612,6 +612,11 @@ struct ath10k {
 
                u32 channel_counters_freq_hz;
 
+               /* Mgmt tx descriptors threshold for limiting probe response
+                * frames.
+                */
+               u32 max_probe_resp_desc_thres;
+
                struct ath10k_hw_params_fw {
                        const char *dir;
                        const char *fw;
index 5731875..5a8e4ea 100644 (file)
@@ -1485,6 +1485,7 @@ struct ath10k_htt {
        spinlock_t tx_lock;
        int max_num_pending_tx;
        int num_pending_tx;
+       int num_pending_mgmt_tx;
        struct idr pending_tx;
        wait_queue_head_t empty_tx_wq;
        struct dma_pool *tx_pool;
@@ -1587,7 +1588,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
                                u8 max_subfrms_ampdu,
                                u8 max_subfrms_amsdu);
 
-void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt);
+void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, bool limit_mgmt_desc);
 int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb);
 void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id);
 int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *);
index 1b7a043..606c1a3 100644 (file)
@@ -643,6 +643,8 @@ struct amsdu_subframe_hdr {
        __be16 len;
 } __packed;
 
+#define GROUP_ID_IS_SU_MIMO(x) ((x) == 0 || (x) == 63)
+
 static void ath10k_htt_rx_h_rates(struct ath10k *ar,
                                  struct ieee80211_rx_status *status,
                                  struct htt_rx_desc *rxd)
@@ -650,6 +652,7 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
        struct ieee80211_supported_band *sband;
        u8 cck, rate, bw, sgi, mcs, nss;
        u8 preamble = 0;
+       u8 group_id;
        u32 info1, info2, info3;
 
        info1 = __le32_to_cpu(rxd->ppdu_start.info1);
@@ -692,10 +695,50 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
        case HTT_RX_VHT_WITH_TXBF:
                /* VHT-SIG-A1 in info2, VHT-SIG-A2 in info3
                   TODO check this */
-               mcs = (info3 >> 4) & 0x0F;
-               nss = ((info2 >> 10) & 0x07) + 1;
                bw = info2 & 3;
                sgi = info3 & 1;
+               group_id = (info2 >> 4) & 0x3F;
+
+               if (GROUP_ID_IS_SU_MIMO(group_id)) {
+                       mcs = (info3 >> 4) & 0x0F;
+                       nss = ((info2 >> 10) & 0x07) + 1;
+               } else {
+                       /* Hardware doesn't decode VHT-SIG-B into Rx descriptor
+                        * so it's impossible to decode MCS. Also since
+                        * firmware consumes Group Id Management frames host
+                        * has no knowledge regarding group/user position
+                        * mapping so it's impossible to pick the correct Nsts
+                        * from VHT-SIG-A1.
+                        *
+                        * Bandwidth and SGI are valid so report the rateinfo
+                        * on best-effort basis.
+                        */
+                       mcs = 0;
+                       nss = 1;
+               }
+
+               if (mcs > 0x09) {
+                       ath10k_warn(ar, "invalid MCS received %u\n", mcs);
+                       ath10k_warn(ar, "rxd %08x mpdu start %08x %08x msdu start %08x %08x ppdu start %08x %08x %08x %08x %08x\n",
+                                   __le32_to_cpu(rxd->attention.flags),
+                                   __le32_to_cpu(rxd->mpdu_start.info0),
+                                   __le32_to_cpu(rxd->mpdu_start.info1),
+                                   __le32_to_cpu(rxd->msdu_start.common.info0),
+                                   __le32_to_cpu(rxd->msdu_start.common.info1),
+                                   rxd->ppdu_start.info0,
+                                   __le32_to_cpu(rxd->ppdu_start.info1),
+                                   __le32_to_cpu(rxd->ppdu_start.info2),
+                                   __le32_to_cpu(rxd->ppdu_start.info3),
+                                   __le32_to_cpu(rxd->ppdu_start.info4));
+
+                       ath10k_warn(ar, "msdu end %08x mpdu end %08x\n",
+                                   __le32_to_cpu(rxd->msdu_end.common.info0),
+                                   __le32_to_cpu(rxd->mpdu_end.info0));
+
+                       ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL,
+                                       "rx desc msdu payload: ",
+                                       rxd->msdu_payload, 50);
+               }
 
                status->rate_idx = mcs;
                status->vht_nss = nss;
index 43aa5e2..eb5ba9b 100644 (file)
 #include "txrx.h"
 #include "debug.h"
 
-void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
+void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, bool limit_mgmt_desc)
 {
+       if (limit_mgmt_desc)
+               htt->num_pending_mgmt_tx--;
+
        htt->num_pending_tx--;
        if (htt->num_pending_tx == htt->max_num_pending_tx - 1)
                ath10k_mac_tx_unlock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
 }
 
-static void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
+static void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt,
+                                     bool limit_mgmt_desc)
 {
        spin_lock_bh(&htt->tx_lock);
-       __ath10k_htt_tx_dec_pending(htt);
+       __ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc);
        spin_unlock_bh(&htt->tx_lock);
 }
 
-static int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt)
+static int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt,
+                                    bool limit_mgmt_desc, bool is_probe_resp)
 {
+       struct ath10k *ar = htt->ar;
        int ret = 0;
 
        spin_lock_bh(&htt->tx_lock);
@@ -47,6 +53,15 @@ static int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt)
                goto exit;
        }
 
+       if (limit_mgmt_desc) {
+               if (is_probe_resp && (htt->num_pending_mgmt_tx >
+                   ar->hw_params.max_probe_resp_desc_thres)) {
+                       ret = -EBUSY;
+                       goto exit;
+               }
+               htt->num_pending_mgmt_tx++;
+       }
+
        htt->num_pending_tx++;
        if (htt->num_pending_tx == htt->max_num_pending_tx)
                ath10k_mac_tx_lock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
@@ -417,8 +432,19 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
        int len = 0;
        int msdu_id = -1;
        int res;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
+       bool limit_mgmt_desc = false;
+       bool is_probe_resp = false;
+
+       if (ar->hw_params.max_probe_resp_desc_thres) {
+               limit_mgmt_desc = true;
+
+               if (ieee80211_is_probe_resp(hdr->frame_control))
+                       is_probe_resp = true;
+       }
+
+       res = ath10k_htt_tx_inc_pending(htt, limit_mgmt_desc, is_probe_resp);
 
-       res = ath10k_htt_tx_inc_pending(htt);
        if (res)
                goto err;
 
@@ -476,7 +502,7 @@ err_free_msdu_id:
        ath10k_htt_tx_free_msdu_id(htt, msdu_id);
        spin_unlock_bh(&htt->tx_lock);
 err_tx_dec:
-       ath10k_htt_tx_dec_pending(htt);
+       ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc);
 err:
        return res;
 }
@@ -498,8 +524,18 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
        dma_addr_t paddr = 0;
        u32 frags_paddr = 0;
        struct htt_msdu_ext_desc *ext_desc = NULL;
+       bool limit_mgmt_desc = false;
+       bool is_probe_resp = false;
+
+       if (unlikely(ieee80211_is_mgmt(hdr->frame_control)) &&
+           ar->hw_params.max_probe_resp_desc_thres) {
+               limit_mgmt_desc = true;
+
+               if (ieee80211_is_probe_resp(hdr->frame_control))
+                       is_probe_resp = true;
+       }
 
-       res = ath10k_htt_tx_inc_pending(htt);
+       res = ath10k_htt_tx_inc_pending(htt, limit_mgmt_desc, is_probe_resp);
        if (res)
                goto err;
 
@@ -528,7 +564,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
             ieee80211_has_protected(hdr->frame_control)) {
                skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
        } else if (!skb_cb->htt.nohwcrypt &&
-                  skb_cb->txmode == ATH10K_HW_TXRX_RAW) {
+                  skb_cb->txmode == ATH10K_HW_TXRX_RAW &&
+                  ieee80211_has_protected(hdr->frame_control)) {
                skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
        }
 
@@ -678,7 +715,7 @@ err_free_msdu_id:
        ath10k_htt_tx_free_msdu_id(htt, msdu_id);
        spin_unlock_bh(&htt->tx_lock);
 err_tx_dec:
-       ath10k_htt_tx_dec_pending(htt);
+       ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc);
 err:
        return res;
 }
index 23afcda..bc421a5 100644 (file)
@@ -413,16 +413,6 @@ enum ath10k_hw_rate_cck {
 /* Number of Copy Engines supported */
 #define CE_COUNT ar->hw_values->ce_count
 
-/*
- * Total number of PCIe MSI interrupts requested for all interrupt sources.
- * PCIe standard forces this to be a power of 2.
- * Some Host OS's limit MSI requests that can be granted to 8
- * so for now we abide by this limit and avoid requesting more
- * than that.
- */
-#define MSI_NUM_REQUEST_LOG2   3
-#define MSI_NUM_REQUEST                (1<<MSI_NUM_REQUEST_LOG2)
-
 /*
  * Granted MSIs are assigned as follows:
  * Firmware uses the first
index 64674c9..3f6c1c4 100644 (file)
@@ -1070,6 +1070,7 @@ static bool ath10k_mac_monitor_vdev_is_needed(struct ath10k *ar)
                return false;
 
        return ar->monitor ||
+              ar->filter_flags & FIF_OTHER_BSS ||
               test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
 }
 
@@ -3617,9 +3618,6 @@ static int ath10k_start_scan(struct ath10k *ar,
        }
        spin_unlock_bh(&ar->data_lock);
 
-       /* Add a 200ms margin to account for event/command processing */
-       ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
-                                    msecs_to_jiffies(arg->max_scan_time+200));
        return 0;
 }
 
@@ -4064,21 +4062,56 @@ static u32 get_nss_from_chainmask(u16 chain_mask)
        return 1;
 }
 
+static int ath10k_mac_get_vht_cap_bf_sts(struct ath10k *ar)
+{
+       int nsts = ar->vht_cap_info;
+       nsts &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
+       nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
+
+       /* If firmware does not deliver to host number of space-time
+        * streams supported, assume it support up to 4 BF STS and return
+        * the value for VHT CAP: nsts-1)
+        * */
+       if (nsts == 0)
+               return 3;
+
+       return nsts;
+}
+
+static int ath10k_mac_get_vht_cap_bf_sound_dim(struct ath10k *ar)
+{
+       int sound_dim = ar->vht_cap_info;
+       sound_dim &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
+       sound_dim >>=IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
+
+       /* If the sounding dimension is not advertised by the firmware,
+        * let's use a default value of 1
+        */
+       if (sound_dim == 0)
+               return 1;
+
+       return sound_dim;
+}
+
 static int ath10k_mac_set_txbf_conf(struct ath10k_vif *arvif)
 {
        u32 value = 0;
        struct ath10k *ar = arvif->ar;
+       int nsts;
+       int sound_dim;
 
        if (ath10k_wmi_get_txbf_conf_scheme(ar) != WMI_TXBF_CONF_BEFORE_ASSOC)
                return 0;
 
+       nsts = ath10k_mac_get_vht_cap_bf_sts(ar);
        if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
                                IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE))
-               value |= SM((ar->num_rf_chains - 1), WMI_TXBF_STS_CAP_OFFSET);
+               value |= SM(nsts, WMI_TXBF_STS_CAP_OFFSET);
 
+       sound_dim = ath10k_mac_get_vht_cap_bf_sound_dim(ar);
        if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
                                IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE))
-               value |= SM((ar->num_rf_chains - 1), WMI_BF_SOUND_DIM_OFFSET);
+               value |= SM(sound_dim, WMI_BF_SOUND_DIM_OFFSET);
 
        if (!value)
                return 0;
@@ -4175,6 +4208,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
        case NL80211_IFTYPE_ADHOC:
                arvif->vdev_type = WMI_VDEV_TYPE_IBSS;
                break;
+       case NL80211_IFTYPE_MESH_POINT:
+               if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
+                       ret = -EINVAL;
+                       ath10k_warn(ar, "must load driver with rawmode=1 to add mesh interfaces\n");
+                       goto err;
+               }
+               arvif->vdev_type = WMI_VDEV_TYPE_AP;
+               break;
        case NL80211_IFTYPE_AP:
                arvif->vdev_type = WMI_VDEV_TYPE_AP;
 
@@ -4215,6 +4256,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
         * become corrupted, e.g. have garbled IEs or out-of-date TIM bitmap.
         */
        if (vif->type == NL80211_IFTYPE_ADHOC ||
+           vif->type == NL80211_IFTYPE_MESH_POINT ||
            vif->type == NL80211_IFTYPE_AP) {
                arvif->beacon_buf = dma_zalloc_coherent(ar->dev,
                                                        IEEE80211_MAX_FRAME_LEN,
@@ -4554,6 +4596,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                if (ret)
                        ath10k_warn(ar, "failed to update beacon template: %d\n",
                                    ret);
+
+               if (ieee80211_vif_is_mesh(vif)) {
+                       /* mesh doesn't use SSID but firmware needs it */
+                       strncpy(arvif->u.ap.ssid, "mesh",
+                               sizeof(arvif->u.ap.ssid));
+                       arvif->u.ap.ssid_len = 4;
+               }
        }
 
        if (changed & BSS_CHANGED_AP_PROBE_RESP) {
@@ -4751,6 +4800,11 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,
                spin_unlock_bh(&ar->data_lock);
        }
 
+       /* Add a 200ms margin to account for event/command processing */
+       ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
+                                    msecs_to_jiffies(arg.max_scan_time +
+                                                     200));
+
 exit:
        mutex_unlock(&ar->conf_mutex);
        return ret;
@@ -5293,6 +5347,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
        } else if (old_state == IEEE80211_STA_AUTH &&
                   new_state == IEEE80211_STA_ASSOC &&
                   (vif->type == NL80211_IFTYPE_AP ||
+                   vif->type == NL80211_IFTYPE_MESH_POINT ||
                    vif->type == NL80211_IFTYPE_ADHOC)) {
                /*
                 * New association.
@@ -5328,6 +5383,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
        } else if (old_state == IEEE80211_STA_ASSOC &&
                    new_state == IEEE80211_STA_AUTH &&
                    (vif->type == NL80211_IFTYPE_AP ||
+                    vif->type == NL80211_IFTYPE_MESH_POINT ||
                     vif->type == NL80211_IFTYPE_ADHOC)) {
                /*
                 * Disassociation.
@@ -5901,7 +5957,7 @@ ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar,
 }
 
 static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif,
-                                           u8 rate, u8 nss, u8 sgi)
+                                           u8 rate, u8 nss, u8 sgi, u8 ldpc)
 {
        struct ath10k *ar = arvif->ar;
        u32 vdev_param;
@@ -5934,6 +5990,13 @@ static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif,
                return ret;
        }
 
+       vdev_param = ar->wmi.vdev_param->ldpc;
+       ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, ldpc);
+       if (ret) {
+               ath10k_warn(ar, "failed to set ldpc param %d: %d\n", ldpc, ret);
+               return ret;
+       }
+
        return 0;
 }
 
@@ -5997,6 +6060,7 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
        u8 rate;
        u8 nss;
        u8 sgi;
+       u8 ldpc;
        int single_nss;
        int ret;
 
@@ -6006,6 +6070,7 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
        band = def.chan->band;
        ht_mcs_mask = mask->control[band].ht_mcs;
        vht_mcs_mask = mask->control[band].vht_mcs;
+       ldpc = !!(ar->ht_cap_info & WMI_HT_CAP_LDPC);
 
        sgi = mask->control[band].gi;
        if (sgi == NL80211_TXRATE_FORCE_LGI)
@@ -6044,7 +6109,7 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
 
        mutex_lock(&ar->conf_mutex);
 
-       ret = ath10k_mac_set_fixed_rate_params(arvif, rate, nss, sgi);
+       ret = ath10k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc);
        if (ret) {
                ath10k_warn(ar, "failed to set fixed rate params on vdev %i: %d\n",
                            arvif->vdev_id, ret);
@@ -6218,6 +6283,94 @@ ath10k_mac_update_rx_channel(struct ath10k *ar,
        rcu_read_unlock();
 }
 
+static void
+ath10k_mac_update_vif_chan(struct ath10k *ar,
+                          struct ieee80211_vif_chanctx_switch *vifs,
+                          int n_vifs)
+{
+       struct ath10k_vif *arvif;
+       int ret;
+       int i;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       /* First stop monitor interface. Some FW versions crash if there's a
+        * lone monitor interface.
+        */
+       if (ar->monitor_started)
+               ath10k_monitor_stop(ar);
+
+       for (i = 0; i < n_vifs; i++) {
+               arvif = ath10k_vif_to_arvif(vifs[i].vif);
+
+               ath10k_dbg(ar, ATH10K_DBG_MAC,
+                          "mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d\n",
+                          arvif->vdev_id,
+                          vifs[i].old_ctx->def.chan->center_freq,
+                          vifs[i].new_ctx->def.chan->center_freq,
+                          vifs[i].old_ctx->def.width,
+                          vifs[i].new_ctx->def.width);
+
+               if (WARN_ON(!arvif->is_started))
+                       continue;
+
+               if (WARN_ON(!arvif->is_up))
+                       continue;
+
+               ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
+               if (ret) {
+                       ath10k_warn(ar, "failed to down vdev %d: %d\n",
+                                   arvif->vdev_id, ret);
+                       continue;
+               }
+       }
+
+       /* All relevant vdevs are downed and associated channel resources
+        * should be available for the channel switch now.
+        */
+
+       spin_lock_bh(&ar->data_lock);
+       ath10k_mac_update_rx_channel(ar, NULL, vifs, n_vifs);
+       spin_unlock_bh(&ar->data_lock);
+
+       for (i = 0; i < n_vifs; i++) {
+               arvif = ath10k_vif_to_arvif(vifs[i].vif);
+
+               if (WARN_ON(!arvif->is_started))
+                       continue;
+
+               if (WARN_ON(!arvif->is_up))
+                       continue;
+
+               ret = ath10k_mac_setup_bcn_tmpl(arvif);
+               if (ret)
+                       ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n",
+                                   ret);
+
+               ret = ath10k_mac_setup_prb_tmpl(arvif);
+               if (ret)
+                       ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n",
+                                   ret);
+
+               ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def);
+               if (ret) {
+                       ath10k_warn(ar, "failed to restart vdev %d: %d\n",
+                                   arvif->vdev_id, ret);
+                       continue;
+               }
+
+               ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
+                                        arvif->bssid);
+               if (ret) {
+                       ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
+                                   arvif->vdev_id, ret);
+                       continue;
+               }
+       }
+
+       ath10k_monitor_recalc(ar);
+}
+
 static int
 ath10k_mac_op_add_chanctx(struct ieee80211_hw *hw,
                          struct ieee80211_chanctx_conf *ctx)
@@ -6264,12 +6417,52 @@ ath10k_mac_op_remove_chanctx(struct ieee80211_hw *hw,
        mutex_unlock(&ar->conf_mutex);
 }
 
+struct ath10k_mac_change_chanctx_arg {
+       struct ieee80211_chanctx_conf *ctx;
+       struct ieee80211_vif_chanctx_switch *vifs;
+       int n_vifs;
+       int next_vif;
+};
+
+static void
+ath10k_mac_change_chanctx_cnt_iter(void *data, u8 *mac,
+                                  struct ieee80211_vif *vif)
+{
+       struct ath10k_mac_change_chanctx_arg *arg = data;
+
+       if (rcu_access_pointer(vif->chanctx_conf) != arg->ctx)
+               return;
+
+       arg->n_vifs++;
+}
+
+static void
+ath10k_mac_change_chanctx_fill_iter(void *data, u8 *mac,
+                                   struct ieee80211_vif *vif)
+{
+       struct ath10k_mac_change_chanctx_arg *arg = data;
+       struct ieee80211_chanctx_conf *ctx;
+
+       ctx = rcu_access_pointer(vif->chanctx_conf);
+       if (ctx != arg->ctx)
+               return;
+
+       if (WARN_ON(arg->next_vif == arg->n_vifs))
+               return;
+
+       arg->vifs[arg->next_vif].vif = vif;
+       arg->vifs[arg->next_vif].old_ctx = ctx;
+       arg->vifs[arg->next_vif].new_ctx = ctx;
+       arg->next_vif++;
+}
+
 static void
 ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw,
                             struct ieee80211_chanctx_conf *ctx,
                             u32 changed)
 {
        struct ath10k *ar = hw->priv;
+       struct ath10k_mac_change_chanctx_arg arg = { .ctx = ctx };
 
        mutex_lock(&ar->conf_mutex);
 
@@ -6283,6 +6476,30 @@ ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw,
        if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL))
                goto unlock;
 
+       if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) {
+               ieee80211_iterate_active_interfaces_atomic(
+                                       hw,
+                                       IEEE80211_IFACE_ITER_NORMAL,
+                                       ath10k_mac_change_chanctx_cnt_iter,
+                                       &arg);
+               if (arg.n_vifs == 0)
+                       goto radar;
+
+               arg.vifs = kcalloc(arg.n_vifs, sizeof(arg.vifs[0]),
+                                  GFP_KERNEL);
+               if (!arg.vifs)
+                       goto radar;
+
+               ieee80211_iterate_active_interfaces_atomic(
+                                       hw,
+                                       IEEE80211_IFACE_ITER_NORMAL,
+                                       ath10k_mac_change_chanctx_fill_iter,
+                                       &arg);
+               ath10k_mac_update_vif_chan(ar, arg.vifs, arg.n_vifs);
+               kfree(arg.vifs);
+       }
+
+radar:
        ath10k_recalc_radar_detection(ar);
 
        /* FIXME: How to configure Rx chains properly? */
@@ -6402,91 +6619,13 @@ ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
                                 enum ieee80211_chanctx_switch_mode mode)
 {
        struct ath10k *ar = hw->priv;
-       struct ath10k_vif *arvif;
-       int ret;
-       int i;
 
        mutex_lock(&ar->conf_mutex);
 
        ath10k_dbg(ar, ATH10K_DBG_MAC,
                   "mac chanctx switch n_vifs %d mode %d\n",
                   n_vifs, mode);
-
-       /* First stop monitor interface. Some FW versions crash if there's a
-        * lone monitor interface.
-        */
-       if (ar->monitor_started)
-               ath10k_monitor_stop(ar);
-
-       for (i = 0; i < n_vifs; i++) {
-               arvif = ath10k_vif_to_arvif(vifs[i].vif);
-
-               ath10k_dbg(ar, ATH10K_DBG_MAC,
-                          "mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d\n",
-                          arvif->vdev_id,
-                          vifs[i].old_ctx->def.chan->center_freq,
-                          vifs[i].new_ctx->def.chan->center_freq,
-                          vifs[i].old_ctx->def.width,
-                          vifs[i].new_ctx->def.width);
-
-               if (WARN_ON(!arvif->is_started))
-                       continue;
-
-               if (WARN_ON(!arvif->is_up))
-                       continue;
-
-               ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
-               if (ret) {
-                       ath10k_warn(ar, "failed to down vdev %d: %d\n",
-                                   arvif->vdev_id, ret);
-                       continue;
-               }
-       }
-
-       /* All relevant vdevs are downed and associated channel resources
-        * should be available for the channel switch now.
-        */
-
-       spin_lock_bh(&ar->data_lock);
-       ath10k_mac_update_rx_channel(ar, NULL, vifs, n_vifs);
-       spin_unlock_bh(&ar->data_lock);
-
-       for (i = 0; i < n_vifs; i++) {
-               arvif = ath10k_vif_to_arvif(vifs[i].vif);
-
-               if (WARN_ON(!arvif->is_started))
-                       continue;
-
-               if (WARN_ON(!arvif->is_up))
-                       continue;
-
-               ret = ath10k_mac_setup_bcn_tmpl(arvif);
-               if (ret)
-                       ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n",
-                                   ret);
-
-               ret = ath10k_mac_setup_prb_tmpl(arvif);
-               if (ret)
-                       ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n",
-                                   ret);
-
-               ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def);
-               if (ret) {
-                       ath10k_warn(ar, "failed to restart vdev %d: %d\n",
-                                   arvif->vdev_id, ret);
-                       continue;
-               }
-
-               ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
-                                        arvif->bssid);
-               if (ret) {
-                       ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
-                                   arvif->vdev_id, ret);
-                       continue;
-               }
-       }
-
-       ath10k_monitor_recalc(ar);
+       ath10k_mac_update_vif_chan(ar, vifs, n_vifs);
 
        mutex_unlock(&ar->conf_mutex);
        return 0;
@@ -6642,6 +6781,9 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = {
        {
        .max    = 7,
        .types  = BIT(NL80211_IFTYPE_AP)
+#ifdef CONFIG_MAC80211_MESH
+               | BIT(NL80211_IFTYPE_MESH_POINT)
+#endif
        },
 };
 
@@ -6649,6 +6791,9 @@ static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = {
        {
        .max    = 8,
        .types  = BIT(NL80211_IFTYPE_AP)
+#ifdef CONFIG_MAC80211_MESH
+               | BIT(NL80211_IFTYPE_MESH_POINT)
+#endif
        },
 };
 
@@ -6686,6 +6831,9 @@ static const struct ieee80211_iface_limit ath10k_tlv_if_limit[] = {
        {
                .max = 2,
                .types = BIT(NL80211_IFTYPE_AP) |
+#ifdef CONFIG_MAC80211_MESH
+                        BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
                         BIT(NL80211_IFTYPE_P2P_CLIENT) |
                         BIT(NL80211_IFTYPE_P2P_GO),
        },
@@ -6707,6 +6855,9 @@ static const struct ieee80211_iface_limit ath10k_tlv_qcs_if_limit[] = {
        {
                .max = 1,
                .types = BIT(NL80211_IFTYPE_AP) |
+#ifdef CONFIG_MAC80211_MESH
+                        BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
                         BIT(NL80211_IFTYPE_P2P_GO),
        },
        {
@@ -6773,6 +6924,9 @@ static const struct ieee80211_iface_limit ath10k_10_4_if_limits[] = {
        {
                .max    = 16,
                .types  = BIT(NL80211_IFTYPE_AP)
+#ifdef CONFIG_MAC80211_MESH
+                       | BIT(NL80211_IFTYPE_MESH_POINT)
+#endif
        },
 };
 
@@ -6804,7 +6958,7 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
 
        if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
                                IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) {
-               val = ar->num_rf_chains - 1;
+               val = ath10k_mac_get_vht_cap_bf_sts(ar);
                val <<= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
                val &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
 
@@ -6813,7 +6967,7 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
 
        if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
                                IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) {
-               val = ar->num_rf_chains - 1;
+               val = ath10k_mac_get_vht_cap_bf_sound_dim(ar);
                val <<= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
                val &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
 
@@ -6997,7 +7151,8 @@ int ath10k_mac_register(struct ath10k *ar)
 
        ar->hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_STATION) |
-               BIT(NL80211_IFTYPE_AP);
+               BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_MESH_POINT);
 
        ar->hw->wiphy->available_antennas_rx = ar->supp_rx_chainmask;
        ar->hw->wiphy->available_antennas_tx = ar->supp_tx_chainmask;
index 1046ab6..110fcad 100644 (file)
@@ -2609,12 +2609,9 @@ static int ath10k_pci_request_irq(struct ath10k *ar)
                return ath10k_pci_request_irq_legacy(ar);
        case 1:
                return ath10k_pci_request_irq_msi(ar);
-       case MSI_NUM_REQUEST:
+       default:
                return ath10k_pci_request_irq_msix(ar);
        }
-
-       ath10k_warn(ar, "unknown irq configuration upon request\n");
-       return -EINVAL;
 }
 
 static void ath10k_pci_free_irq(struct ath10k *ar)
@@ -2657,7 +2654,7 @@ static int ath10k_pci_init_irq(struct ath10k *ar)
 
        /* Try MSI-X */
        if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO) {
-               ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
+               ar_pci->num_msi_intrs = MSI_ASSIGN_CE_MAX + 1;
                ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs,
                                           ar_pci->num_msi_intrs);
                if (ret > 0)
@@ -2705,18 +2702,13 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
        switch (ar_pci->num_msi_intrs) {
        case 0:
                ath10k_pci_deinit_irq_legacy(ar);
-               return 0;
-       case 1:
-               /* fall-through */
-       case MSI_NUM_REQUEST:
-               pci_disable_msi(ar_pci->pdev);
-               return 0;
+               break;
        default:
                pci_disable_msi(ar_pci->pdev);
+               break;
        }
 
-       ath10k_warn(ar, "unknown irq configuration upon deinit\n");
-       return -EINVAL;
+       return 0;
 }
 
 static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
index e4a9c4c..7db7d50 100644 (file)
@@ -52,6 +52,9 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
        struct ieee80211_tx_info *info;
        struct ath10k_skb_cb *skb_cb;
        struct sk_buff *msdu;
+       struct ieee80211_hdr *hdr;
+       __le16 fc;
+       bool limit_mgmt_desc = false;
 
        ath10k_dbg(ar, ATH10K_DBG_HTT,
                   "htt tx completion msdu_id %u discard %d no_ack %d success %d\n",
@@ -72,14 +75,21 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
                spin_unlock_bh(&htt->tx_lock);
                return;
        }
+
+       hdr = (struct ieee80211_hdr *)msdu->data;
+       fc = hdr->frame_control;
+
+       if (unlikely(ieee80211_is_mgmt(fc)) &&
+           ar->hw_params.max_probe_resp_desc_thres)
+               limit_mgmt_desc = true;
+
        ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
-       __ath10k_htt_tx_dec_pending(htt);
+       __ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc);
        if (htt->num_pending_tx == 0)
                wake_up(&htt->empty_tx_wq);
        spin_unlock_bh(&htt->tx_lock);
 
        skb_cb = ATH10K_SKB_CB(msdu);
-
        dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
 
        if (skb_cb->htt.txbuf)
index ce01107..87d9de2 100644 (file)
@@ -3917,6 +3917,53 @@ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
        return 0;
 }
 
+static bool
+ath10k_wmi_is_host_mem_allocated(struct ath10k *ar,
+                                const struct wlan_host_mem_req **mem_reqs,
+                                u32 num_mem_reqs)
+{
+       u32 req_id, num_units, unit_size, num_unit_info;
+       u32 pool_size;
+       int i, j;
+       bool found;
+
+       if (ar->wmi.num_mem_chunks != num_mem_reqs)
+               return false;
+
+       for (i = 0; i < num_mem_reqs; ++i) {
+               req_id = __le32_to_cpu(mem_reqs[i]->req_id);
+               num_units = __le32_to_cpu(mem_reqs[i]->num_units);
+               unit_size = __le32_to_cpu(mem_reqs[i]->unit_size);
+               num_unit_info = __le32_to_cpu(mem_reqs[i]->num_unit_info);
+
+               if (num_unit_info & NUM_UNITS_IS_NUM_ACTIVE_PEERS) {
+                       if (ar->num_active_peers)
+                               num_units = ar->num_active_peers + 1;
+                       else
+                               num_units = ar->max_num_peers + 1;
+               } else if (num_unit_info & NUM_UNITS_IS_NUM_PEERS) {
+                       num_units = ar->max_num_peers + 1;
+               } else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS) {
+                       num_units = ar->max_num_vdevs + 1;
+               }
+
+               found = false;
+               for (j = 0; j < ar->wmi.num_mem_chunks; j++) {
+                       if (ar->wmi.mem_chunks[j].req_id == req_id) {
+                               pool_size = num_units * round_up(unit_size, 4);
+                               if (ar->wmi.mem_chunks[j].len == pool_size) {
+                                       found = true;
+                                       break;
+                               }
+                       }
+               }
+               if (!found)
+                       return false;
+       }
+
+       return true;
+}
+
 static int
 ath10k_wmi_main_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
                                   struct wmi_svc_rdy_ev_arg *arg)
@@ -3997,6 +4044,7 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
        struct wmi_svc_rdy_ev_arg arg = {};
        u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
        int ret;
+       bool allocated;
 
        if (!skb) {
                ath10k_warn(ar, "invalid service ready event skb\n");
@@ -4073,6 +4121,18 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
         * and WMI_SERVICE_IRAM_TIDS, etc.
         */
 
+       allocated = ath10k_wmi_is_host_mem_allocated(ar, arg.mem_reqs,
+                                                    num_mem_reqs);
+       if (allocated)
+               goto skip_mem_alloc;
+
+       /* Either this event is received during boot time or there is a change
+        * in memory requirement from firmware when compared to last request.
+        * Free any old memory and do a fresh allocation based on the current
+        * memory requirement.
+        */
+       ath10k_wmi_free_host_mem(ar);
+
        for (i = 0; i < num_mem_reqs; ++i) {
                req_id = __le32_to_cpu(arg.mem_reqs[i]->req_id);
                num_units = __le32_to_cpu(arg.mem_reqs[i]->num_units);
@@ -4108,6 +4168,7 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
                        return;
        }
 
+skip_mem_alloc:
        ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x fw_build 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n",
                   __le32_to_cpu(arg.min_tx_power),
@@ -6660,15 +6721,10 @@ int ath10k_wmi_attach(struct ath10k *ar)
        return 0;
 }
 
-void ath10k_wmi_detach(struct ath10k *ar)
+void ath10k_wmi_free_host_mem(struct ath10k *ar)
 {
        int i;
 
-       cancel_work_sync(&ar->svc_rdy_work);
-
-       if (ar->svc_rdy_skb)
-               dev_kfree_skb(ar->svc_rdy_skb);
-
        /* free the host memory chunks requested by firmware */
        for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
                dma_free_coherent(ar->dev,
@@ -6679,3 +6735,11 @@ void ath10k_wmi_detach(struct ath10k *ar)
 
        ar->wmi.num_mem_chunks = 0;
 }
+
+void ath10k_wmi_detach(struct ath10k *ar)
+{
+       cancel_work_sync(&ar->svc_rdy_work);
+
+       if (ar->svc_rdy_skb)
+               dev_kfree_skb(ar->svc_rdy_skb);
+}
index 52d3503..3e5a159 100644 (file)
@@ -6067,6 +6067,7 @@ struct ath10k_fw_stats_peer;
 
 int ath10k_wmi_attach(struct ath10k *ar);
 void ath10k_wmi_detach(struct ath10k *ar);
+void ath10k_wmi_free_host_mem(struct ath10k *ar);
 int ath10k_wmi_wait_for_service_ready(struct ath10k *ar);
 int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar);
 
index 174442b..0c39199 100644 (file)
@@ -1249,7 +1249,8 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
                REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
                              AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, 0x0);
 
-       if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
+       if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+           AR_SREV_9561(ah)) {
                if (is_2g)
                        REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
                                      AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR,
@@ -1640,7 +1641,8 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
 
 skip_tx_iqcal:
        if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
-               if (AR_SREV_9330_11(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah)) {
+               if (AR_SREV_9330_11(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah) ||
+                   AR_SREV_9561(ah)) {
                        for (i = 0; i < AR9300_MAX_CHAINS; i++) {
                                if (!(ah->rxchainmask & (1 << i)))
                                        continue;
index c85c479..b42f4a9 100644 (file)
@@ -635,6 +635,7 @@ struct ath9k_vif_iter_data {
        int nstations; /* number of station vifs */
        int nwds;      /* number of WDS vifs */
        int nadhocs;   /* number of adhoc vifs */
+       int nocbs;     /* number of OCB vifs */
        struct ieee80211_vif *primary_sta;
 };
 
index da32c8f..6de64cf 100644 (file)
@@ -741,8 +741,8 @@ static int read_file_misc(struct seq_file *file, void *data)
                           i++, (int)(ctx->assigned), iter_data.naps,
                           iter_data.nstations,
                           iter_data.nmeshes, iter_data.nwds);
-               seq_printf(file, " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n",
-                          iter_data.nadhocs, sc->cur_chan->nvifs,
+               seq_printf(file, " ADHOC: %i OCB: %i TOTAL: %hi BEACON-VIF: %hi\n",
+                          iter_data.nadhocs, iter_data.nocbs, sc->cur_chan->nvifs,
                           sc->nbcnvifs);
        }
 
index efe77db..8647ab7 100644 (file)
@@ -740,7 +740,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
                BIT(NL80211_IFTYPE_AP) |
                BIT(NL80211_IFTYPE_P2P_GO) |
                BIT(NL80211_IFTYPE_P2P_CLIENT) |
-               BIT(NL80211_IFTYPE_MESH_POINT);
+               BIT(NL80211_IFTYPE_MESH_POINT) |
+               BIT(NL80211_IFTYPE_OCB);
 
        hw->wiphy->iface_combinations = &if_comb;
        hw->wiphy->n_iface_combinations = 1;
index 1dd0339..bdfff46 100644 (file)
@@ -1241,6 +1241,7 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode)
                        break;
                }
                /* fall through */
+       case NL80211_IFTYPE_OCB:
        case NL80211_IFTYPE_MESH_POINT:
        case NL80211_IFTYPE_AP:
                set |= AR_STA_ID1_STA_AP;
index 57f95f2..5d532c7 100644 (file)
@@ -855,7 +855,8 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
                        BIT(NL80211_IFTYPE_STATION) |
                        BIT(NL80211_IFTYPE_ADHOC) |
                        BIT(NL80211_IFTYPE_MESH_POINT) |
-                       BIT(NL80211_IFTYPE_WDS);
+                       BIT(NL80211_IFTYPE_WDS) |
+                       BIT(NL80211_IFTYPE_OCB);
 
                if (ath9k_is_chanctx_enabled())
                        hw->wiphy->interface_modes |=
index c27143b..56abb9d 100644 (file)
@@ -938,6 +938,9 @@ static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
                if (avp->assoc && !iter_data->primary_sta)
                        iter_data->primary_sta = vif;
                break;
+       case NL80211_IFTYPE_OCB:
+               iter_data->nocbs++;
+               break;
        case NL80211_IFTYPE_ADHOC:
                iter_data->nadhocs++;
                if (vif->bss_conf.enable_beacon)
@@ -1111,6 +1114,8 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
 
                if (iter_data.nmeshes)
                        ah->opmode = NL80211_IFTYPE_MESH_POINT;
+               else if (iter_data.nocbs)
+                       ah->opmode = NL80211_IFTYPE_OCB;
                else if (iter_data.nwds)
                        ah->opmode = NL80211_IFTYPE_AP;
                else if (iter_data.nadhocs)
@@ -1760,7 +1765,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                ath9k_calculate_summary_state(sc, avp->chanctx);
        }
 
-       if (changed & BSS_CHANGED_IBSS) {
+       if ((changed & BSS_CHANGED_IBSS) ||
+             (changed & BSS_CHANGED_OCB)) {
                memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
                common->curaid = bss_conf->aid;
                ath9k_hw_write_associd(sc->sc_ah);
index d3189da..994daf6 100644 (file)
@@ -403,7 +403,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
            (sc->cur_chan->nvifs <= 1) &&
            !(sc->cur_chan->rxfilter & FIF_BCN_PRBRESP_PROMISC))
                rfilt |= ATH9K_RX_FILTER_MYBEACON;
-       else
+       else if (sc->sc_ah->opmode != NL80211_IFTYPE_OCB)
                rfilt |= ATH9K_RX_FILTER_BEACON;
 
        if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
index 924135b..d66533c 100644 (file)
@@ -453,7 +453,7 @@ static void carl9170_rx_phy_status(struct ar9170 *ar,
        /* post-process RSSI */
        for (i = 0; i < 7; i++)
                if (phy->rssi[i] & 0x80)
-                       phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f;
+                       phy->rssi[i] = ((~phy->rssi[i] & 0x7f) + 1) & 0x7f;
 
        /* TODO: we could do something with phy_errors */
        status->signal = ar->noise[0] + phy->rssi_combined;
index 656ce42..9d68712 100644 (file)
 #include "dfs_pri_detector.h"
 #include "ath.h"
 
-/*
- * tolerated deviation of radar time stamp in usecs on both sides
- * TODO: this might need to be HW-dependent
- */
-#define PRI_TOLERANCE  16
-
 /**
  * struct radar_types - contains array of patterns defined for one DFS domain
  * @domain: DFS regulatory domain
@@ -121,7 +115,7 @@ static const struct radar_detector_specs jp_radar_ref_types[] = {
        JP_PATTERN(4, 0, 5, 150, 230, 1, 23, 50, false),
        JP_PATTERN(5, 6, 10, 200, 500, 1, 16, 50, false),
        JP_PATTERN(6, 11, 20, 200, 500, 1, 12, 50, false),
-       JP_PATTERN(7, 50, 100, 1000, 2000, 1, 20, 50, false),
+       JP_PATTERN(7, 50, 100, 1000, 2000, 1, 3, 50, false),
        JP_PATTERN(5, 0, 1, 333, 333, 1, 9, 50, false),
 };
 
index 25a43d6..92be353 100644 (file)
 #include <linux/list.h>
 #include <linux/nl80211.h>
 
+/* tolerated deviation of radar time stamp in usecs on both sides
+ * TODO: this might need to be HW-dependent
+ */
+#define PRI_TOLERANCE  16
+
 /**
  * struct ath_dfs_pool_stats - DFS Statistics for global pools
  */
index cc5c592..05b0464 100644 (file)
@@ -25,6 +25,9 @@ struct ath_dfs_pool_stats global_dfs_pool_stats = {};
 
 #define DFS_POOL_STAT_INC(c) (global_dfs_pool_stats.c++)
 #define DFS_POOL_STAT_DEC(c) (global_dfs_pool_stats.c--)
+#define GET_PRI_TO_USE(MIN, MAX, RUNTIME) \
+       (MIN + PRI_TOLERANCE == MAX - PRI_TOLERANCE ? \
+       MIN + PRI_TOLERANCE : RUNTIME)
 
 /**
  * struct pulse_elem - elements in pulse queue
@@ -243,7 +246,8 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde,
                ps.count_falses = 0;
                ps.first_ts = p->ts;
                ps.last_ts = ts;
-               ps.pri = ts - p->ts;
+               ps.pri = GET_PRI_TO_USE(pde->rs->pri_min,
+                       pde->rs->pri_max, ts - p->ts);
                ps.dur = ps.pri * (pde->rs->ppb - 1)
                                + 2 * pde->rs->max_pri_tolerance;
 
index 8e0e91c..288c84e 100644 (file)
@@ -272,10 +272,11 @@ brcmf_proto_bcdc_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset,
 }
 
 static int
-brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
-                        struct sk_buff *pktbuf)
+brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws,
+                        struct sk_buff *pktbuf, struct brcmf_if **ifp)
 {
        struct brcmf_proto_bcdc_header *h;
+       struct brcmf_if *tmp_if;
 
        brcmf_dbg(BCDC, "Enter\n");
 
@@ -289,30 +290,21 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
        trace_brcmf_bcdchdr(pktbuf->data);
        h = (struct brcmf_proto_bcdc_header *)(pktbuf->data);
 
-       *ifidx = BCDC_GET_IF_IDX(h);
-       if (*ifidx >= BRCMF_MAX_IFS) {
-               brcmf_err("rx data ifnum out of range (%d)\n", *ifidx);
+       tmp_if = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h));
+       if (!tmp_if) {
+               brcmf_dbg(INFO, "no matching ifp found\n");
                return -EBADE;
        }
-       /* The ifidx is the idx to map to matching netdev/ifp. When receiving
-        * events this is easy because it contains the bssidx which maps
-        * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
-        * bssidx 1 is used for p2p0 and no data can be received or
-        * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
-        */
-       if (*ifidx)
-               (*ifidx)++;
-
        if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) !=
            BCDC_PROTO_VER) {
                brcmf_err("%s: non-BCDC packet received, flags 0x%x\n",
-                         brcmf_ifname(drvr, *ifidx), h->flags);
+                         brcmf_ifname(drvr, tmp_if->ifidx), h->flags);
                return -EBADE;
        }
 
        if (h->flags & BCDC_FLAG_SUM_GOOD) {
                brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n",
-                         brcmf_ifname(drvr, *ifidx), h->flags);
+                         brcmf_ifname(drvr, tmp_if->ifidx), h->flags);
                pktbuf->ip_summed = CHECKSUM_UNNECESSARY;
        }
 
@@ -320,12 +312,14 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
 
        skb_pull(pktbuf, BCDC_HEADER_LEN);
        if (do_fws)
-               brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf);
+               brcmf_fws_hdrpull(tmp_if, h->data_offset << 2, pktbuf);
        else
                skb_pull(pktbuf, h->data_offset << 2);
 
        if (pktbuf->len == 0)
                return -ENODATA;
+
+       *ifp = tmp_if;
        return 0;
 }
 
index 0445163..4e33f96 100644 (file)
@@ -149,7 +149,7 @@ static s32 brcmf_btcoex_params_read(struct brcmf_if *ifp, u32 addr, u32 *data)
 static void brcmf_btcoex_boost_wifi(struct brcmf_btcoex_info *btci,
                                    bool trump_sco)
 {
-       struct brcmf_if *ifp = btci->cfg->pub->iflist[0];
+       struct brcmf_if *ifp = brcmf_get_ifp(btci->cfg->pub, 0);
 
        if (trump_sco && !btci->saved_regs_part2) {
                /* this should reduce eSCO agressive
@@ -468,7 +468,7 @@ int brcmf_btcoex_set_mode(struct brcmf_cfg80211_vif *vif,
 {
        struct brcmf_cfg80211_info *cfg = wiphy_priv(vif->wdev.wiphy);
        struct brcmf_btcoex_info *btci = cfg->btcoex;
-       struct brcmf_if *ifp = cfg->pub->iflist[0];
+       struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
 
        switch (mode) {
        case BRCMF_BTCOEX_DISABLED:
index a293275..891f4ed 100644 (file)
@@ -236,89 +236,6 @@ static int brcmf_roamoff;
 module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
 MODULE_PARM_DESC(roamoff, "do not use internal roaming engine");
 
-/* Quarter dBm units to mW
- * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
- * Table is offset so the last entry is largest mW value that fits in
- * a u16.
- */
-
-#define QDBM_OFFSET 153                /* Offset for first entry */
-#define QDBM_TABLE_LEN 40      /* Table size */
-
-/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
- * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
- */
-#define QDBM_TABLE_LOW_BOUND 6493      /* Low bound */
-
-/* Largest mW value that will round down to the last table entry,
- * QDBM_OFFSET + QDBM_TABLE_LEN-1.
- * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
- * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
- */
-#define QDBM_TABLE_HIGH_BOUND 64938    /* High bound */
-
-static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
-/* qdBm:       +0      +1      +2      +3      +4      +5      +6      +7 */
-/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
-/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
-/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
-/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
-/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
-};
-
-static u16 brcmf_qdbm_to_mw(u8 qdbm)
-{
-       uint factor = 1;
-       int idx = qdbm - QDBM_OFFSET;
-
-       if (idx >= QDBM_TABLE_LEN)
-               /* clamp to max u16 mW value */
-               return 0xFFFF;
-
-       /* scale the qdBm index up to the range of the table 0-40
-        * where an offset of 40 qdBm equals a factor of 10 mW.
-        */
-       while (idx < 0) {
-               idx += 40;
-               factor *= 10;
-       }
-
-       /* return the mW value scaled down to the correct factor of 10,
-        * adding in factor/2 to get proper rounding.
-        */
-       return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
-}
-
-static u8 brcmf_mw_to_qdbm(u16 mw)
-{
-       u8 qdbm;
-       int offset;
-       uint mw_uint = mw;
-       uint boundary;
-
-       /* handle boundary case */
-       if (mw_uint <= 1)
-               return 0;
-
-       offset = QDBM_OFFSET;
-
-       /* move mw into the range of the table */
-       while (mw_uint < QDBM_TABLE_LOW_BOUND) {
-               mw_uint *= 10;
-               offset -= 40;
-       }
-
-       for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
-               boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
-                                                   nqdBm_to_mW_map[qdbm]) / 2;
-               if (mw_uint < boundary)
-                       break;
-       }
-
-       qdbm += (u8) offset;
-
-       return qdbm;
-}
 
 static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
                               struct cfg80211_chan_def *ch)
@@ -860,6 +777,37 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
        s32 err = 0;
 
        brcmf_dbg(TRACE, "Enter, idx=%d, type=%d\n", ifp->bssidx, type);
+
+       /* WAR: There are a number of p2p interface related problems which
+        * need to be handled initially (before doing the validate).
+        * wpa_supplicant tends to do iface changes on p2p device/client/go
+        * which are not always possible/allowed. However we need to return
+        * OK otherwise the wpa_supplicant wont start. The situation differs
+        * on configuration and setup (p2pon=1 module param). The first check
+        * is to see if the request is a change to station for p2p iface.
+        */
+       if ((type == NL80211_IFTYPE_STATION) &&
+           ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
+            (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) ||
+            (vif->wdev.iftype == NL80211_IFTYPE_P2P_DEVICE))) {
+               brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
+               /* Now depending on whether module param p2pon=1 was used the
+                * response needs to be either 0 or EOPNOTSUPP. The reason is
+                * that if p2pon=1 is used, but a newer supplicant is used then
+                * we should return an error, as this combination wont work.
+                * In other situations 0 is returned and supplicant will start
+                * normally. It will give a trace in cfg80211, but it is the
+                * only way to get it working. Unfortunately this will result
+                * in situation where we wont support new supplicant in
+                * combination with module param p2pon=1, but that is the way
+                * it is. If the user tries this then unloading of driver might
+                * fail/lock.
+                */
+               if (cfg->p2p.p2pdev_dynamically)
+                       return -EOPNOTSUPP;
+               else
+                       return 0;
+       }
        err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type);
        if (err) {
                brcmf_err("iface validation failed: err=%d\n", err);
@@ -875,18 +823,6 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
                infra = 0;
                break;
        case NL80211_IFTYPE_STATION:
-               /* Ignore change for p2p IF. Unclear why supplicant does this */
-               if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
-                   (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
-                       brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
-                       /* WAR: It is unexpected to get a change of VIF for P2P
-                        * IF, but it happens. The request can not be handled
-                        * but returning EPERM causes a crash. Returning 0
-                        * without setting ieee80211_ptr->iftype causes trace
-                        * (WARN_ON) but it works with wpa_supplicant
-                        */
-                       return 0;
-               }
                infra = 1;
                break;
        case NL80211_IFTYPE_AP:
@@ -2017,16 +1953,14 @@ static s32
 brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
                            enum nl80211_tx_power_setting type, s32 mbm)
 {
-
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        struct net_device *ndev = cfg_to_ndev(cfg);
        struct brcmf_if *ifp = netdev_priv(ndev);
-       u16 txpwrmw;
-       s32 err = 0;
-       s32 disable = 0;
-       s32 dbm = MBM_TO_DBM(mbm);
+       s32 err;
+       s32 disable;
+       u32 qdbm = 127;
 
-       brcmf_dbg(TRACE, "Enter\n");
+       brcmf_dbg(TRACE, "Enter %d %d\n", type, mbm);
        if (!check_vif_up(ifp->vif))
                return -EIO;
 
@@ -2035,12 +1969,20 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
                break;
        case NL80211_TX_POWER_LIMITED:
        case NL80211_TX_POWER_FIXED:
-               if (dbm < 0) {
+               if (mbm < 0) {
                        brcmf_err("TX_POWER_FIXED - dbm is negative\n");
                        err = -EINVAL;
                        goto done;
                }
+               qdbm =  MBM_TO_DBM(4 * mbm);
+               if (qdbm > 127)
+                       qdbm = 127;
+               qdbm |= WL_TXPWR_OVERRIDE;
                break;
+       default:
+               brcmf_err("Unsupported type %d\n", type);
+               err = -EINVAL;
+               goto done;
        }
        /* Make sure radio is off or on as far as software is concerned */
        disable = WL_RADIO_SW_DISABLE << 16;
@@ -2048,52 +1990,44 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
        if (err)
                brcmf_err("WLC_SET_RADIO error (%d)\n", err);
 
-       if (dbm > 0xffff)
-               txpwrmw = 0xffff;
-       else
-               txpwrmw = (u16) dbm;
-       err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
-                                     (s32)brcmf_mw_to_qdbm(txpwrmw));
+       err = brcmf_fil_iovar_int_set(ifp, "qtxpower", qdbm);
        if (err)
                brcmf_err("qtxpower error (%d)\n", err);
-       cfg->conf->tx_power = dbm;
 
 done:
-       brcmf_dbg(TRACE, "Exit\n");
+       brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
        return err;
 }
 
-static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
-                                      struct wireless_dev *wdev,
-                                      s32 *dbm)
+static s32
+brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+                           s32 *dbm)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
-       struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
-       s32 txpwrdbm;
-       u8 result;
-       s32 err = 0;
+       struct net_device *ndev = cfg_to_ndev(cfg);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       s32 qdbm = 0;
+       s32 err;
 
        brcmf_dbg(TRACE, "Enter\n");
        if (!check_vif_up(ifp->vif))
                return -EIO;
 
-       err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
+       err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
        if (err) {
                brcmf_err("error (%d)\n", err);
                goto done;
        }
-
-       result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
-       *dbm = (s32) brcmf_qdbm_to_mw(result);
+       *dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
 
 done:
-       brcmf_dbg(TRACE, "Exit\n");
+       brcmf_dbg(TRACE, "Exit (0x%x %d)\n", qdbm, *dbm);
        return err;
 }
 
 static s32
 brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
-                              u8 key_idx, bool unicast, bool multicast)
+                                 u8 key_idx, bool unicast, bool multicast)
 {
        struct brcmf_if *ifp = netdev_priv(ndev);
        u32 index;
@@ -4747,7 +4681,8 @@ void brcmf_cfg80211_free_netdev(struct net_device *ndev)
        ifp = netdev_priv(ndev);
        vif = ifp->vif;
 
-       brcmf_free_vif(vif);
+       if (vif)
+               brcmf_free_vif(vif);
        free_netdev(ndev);
 }
 
@@ -4983,7 +4918,7 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
                brcmf_dbg(CONN, "AP mode link down\n");
                complete(&cfg->vif_disabled);
                if (ifp->vif->mbss)
-                       brcmf_remove_interface(ifp->drvr, ifp->bssidx);
+                       brcmf_remove_interface(ifp);
                return 0;
        }
 
@@ -6211,9 +6146,10 @@ static void brcmf_free_wiphy(struct wiphy *wiphy)
 }
 
 struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
-                                                 struct device *busdev)
+                                                 struct device *busdev,
+                                                 bool p2pdev_forced)
 {
-       struct net_device *ndev = drvr->iflist[0]->ndev;
+       struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
        struct brcmf_cfg80211_info *cfg;
        struct wiphy *wiphy;
        struct brcmf_cfg80211_vif *vif;
@@ -6303,7 +6239,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
                        *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
        }
 
-       err = brcmf_p2p_attach(cfg);
+       err = brcmf_p2p_attach(cfg, p2pdev_forced);
        if (err) {
                brcmf_err("P2P initilisation failed (%d)\n", err);
                goto wiphy_unreg_out;
@@ -6331,6 +6267,7 @@ wiphy_unreg_out:
 priv_out:
        wl_deinit_priv(cfg);
        brcmf_free_vif(vif);
+       ifp->vif = NULL;
 wiphy_out:
        brcmf_free_wiphy(wiphy);
        return NULL;
index d9e6d01..3f5e550 100644 (file)
@@ -469,7 +469,8 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg)
 }
 
 struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
-                                                 struct device *busdev);
+                                                 struct device *busdev,
+                                                 bool p2pdev_forced);
 void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
 s32 brcmf_cfg80211_up(struct net_device *ndev);
 s32 brcmf_cfg80211_down(struct net_device *ndev);
index 288f831..ffc3ace 100644 (file)
 /* ARM Cortex M3 core, ID 0x82a */
 #define BCM4329_CORE_ARM_BASE          0x18002000
 
+/* Max possibly supported memory size (limited by IO mapped memory) */
+#define BRCMF_CHIP_MAX_MEMSIZE         (4 * 1024 * 1024)
+
 #define CORE_SB(base, field) \
                (base + SBCONFIGOFF + offsetof(struct sbconfig, field))
 #define        SBCOREREV(sbidh) \
@@ -205,6 +208,7 @@ struct sbsocramregs {
 };
 
 #define SOCRAMREGOFFS(_f)      offsetof(struct sbsocramregs, _f)
+#define SYSMEMREGOFFS(_f)      offsetof(struct sbsocramregs, _f)
 
 #define ARMCR4_CAP             (0x04)
 #define ARMCR4_BANKIDX         (0x40)
@@ -513,6 +517,9 @@ static int brcmf_chip_cores_check(struct brcmf_chip_priv *ci)
                case BCMA_CORE_ARM_CR4:
                        cpu_found = true;
                        break;
+               case BCMA_CORE_ARM_CA7:
+                       cpu_found = true;
+                       break;
                default:
                        break;
                }
@@ -611,6 +618,29 @@ static void brcmf_chip_socram_ramsize(struct brcmf_core_priv *sr, u32 *ramsize,
        }
 }
 
+/** Return the SYS MEM size */
+static u32 brcmf_chip_sysmem_ramsize(struct brcmf_core_priv *sysmem)
+{
+       u32 memsize = 0;
+       u32 coreinfo;
+       u32 idx;
+       u32 nb;
+       u32 banksize;
+
+       if (!brcmf_chip_iscoreup(&sysmem->pub))
+               brcmf_chip_resetcore(&sysmem->pub, 0, 0, 0);
+
+       coreinfo = brcmf_chip_core_read32(sysmem, SYSMEMREGOFFS(coreinfo));
+       nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
+
+       for (idx = 0; idx < nb; idx++) {
+               brcmf_chip_socram_banksize(sysmem, idx, &banksize);
+               memsize += banksize;
+       }
+
+       return memsize;
+}
+
 /** Return the TCM-RAM size of the ARMCR4 core. */
 static u32 brcmf_chip_tcm_ramsize(struct brcmf_core_priv *cr4)
 {
@@ -644,6 +674,7 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci)
                return 0x198000;
        case BRCM_CC_4335_CHIP_ID:
        case BRCM_CC_4339_CHIP_ID:
+       case BRCM_CC_4350_CHIP_ID:
        case BRCM_CC_4354_CHIP_ID:
        case BRCM_CC_4356_CHIP_ID:
        case BRCM_CC_43567_CHIP_ID:
@@ -652,6 +683,9 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci)
        case BRCM_CC_4358_CHIP_ID:
        case BRCM_CC_43602_CHIP_ID:
                return 0x180000;
+       case BRCM_CC_4365_CHIP_ID:
+       case BRCM_CC_4366_CHIP_ID:
+               return 0x200000;
        default:
                brcmf_err("unknown chip: %s\n", ci->pub.name);
                break;
@@ -674,10 +708,28 @@ static int brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci)
                        return -EINVAL;
                }
        } else {
-               mem = brcmf_chip_get_core(&ci->pub, BCMA_CORE_INTERNAL_MEM);
-               mem_core = container_of(mem, struct brcmf_core_priv, pub);
-               brcmf_chip_socram_ramsize(mem_core, &ci->pub.ramsize,
-                                         &ci->pub.srsize);
+               mem = brcmf_chip_get_core(&ci->pub, BCMA_CORE_SYS_MEM);
+               if (mem) {
+                       mem_core = container_of(mem, struct brcmf_core_priv,
+                                               pub);
+                       ci->pub.ramsize = brcmf_chip_sysmem_ramsize(mem_core);
+                       ci->pub.rambase = brcmf_chip_tcm_rambase(ci);
+                       if (!ci->pub.rambase) {
+                               brcmf_err("RAM base not provided with ARM CA7 core\n");
+                               return -EINVAL;
+                       }
+               } else {
+                       mem = brcmf_chip_get_core(&ci->pub,
+                                                 BCMA_CORE_INTERNAL_MEM);
+                       if (!mem) {
+                               brcmf_err("No memory cores found\n");
+                               return -ENOMEM;
+                       }
+                       mem_core = container_of(mem, struct brcmf_core_priv,
+                                               pub);
+                       brcmf_chip_socram_ramsize(mem_core, &ci->pub.ramsize,
+                                                 &ci->pub.srsize);
+               }
        }
        brcmf_dbg(INFO, "RAM: base=0x%x size=%d (0x%x) sr=%d (0x%x)\n",
                  ci->pub.rambase, ci->pub.ramsize, ci->pub.ramsize,
@@ -687,6 +739,12 @@ static int brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci)
                brcmf_err("RAM size is undetermined\n");
                return -ENOMEM;
        }
+
+       if (ci->pub.ramsize > BRCMF_CHIP_MAX_MEMSIZE) {
+               brcmf_err("RAM size is incorrect\n");
+               return -ENOMEM;
+       }
+
        return 0;
 }
 
@@ -899,13 +957,22 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci)
 
        /* assure chip is passive for core access */
        brcmf_chip_set_passive(&ci->pub);
+
+       /* Call bus specific reset function now. Cores have been determined
+        * but further access may require a chip specific reset at this point.
+        */
+       if (ci->ops->reset) {
+               ci->ops->reset(ci->ctx, &ci->pub);
+               brcmf_chip_set_passive(&ci->pub);
+       }
+
        return brcmf_chip_get_raminfo(ci);
 }
 
 static void brcmf_chip_disable_arm(struct brcmf_chip_priv *chip, u16 id)
 {
        struct brcmf_core *core;
-       struct brcmf_core_priv *cr4;
+       struct brcmf_core_priv *cpu;
        u32 val;
 
 
@@ -918,10 +985,11 @@ static void brcmf_chip_disable_arm(struct brcmf_chip_priv *chip, u16 id)
                brcmf_chip_coredisable(core, 0, 0);
                break;
        case BCMA_CORE_ARM_CR4:
-               cr4 = container_of(core, struct brcmf_core_priv, pub);
+       case BCMA_CORE_ARM_CA7:
+               cpu = container_of(core, struct brcmf_core_priv, pub);
 
                /* clear all IOCTL bits except HALT bit */
-               val = chip->ops->read32(chip->ctx, cr4->wrapbase + BCMA_IOCTL);
+               val = chip->ops->read32(chip->ctx, cpu->wrapbase + BCMA_IOCTL);
                val &= ARMCR4_BCMA_IOCTL_CPUHALT;
                brcmf_chip_resetcore(core, val, ARMCR4_BCMA_IOCTL_CPUHALT,
                                     ARMCR4_BCMA_IOCTL_CPUHALT);
@@ -1143,6 +1211,33 @@ static bool brcmf_chip_cr4_set_active(struct brcmf_chip_priv *chip, u32 rstvec)
        return true;
 }
 
+static inline void
+brcmf_chip_ca7_set_passive(struct brcmf_chip_priv *chip)
+{
+       struct brcmf_core *core;
+
+       brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CA7);
+
+       core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211);
+       brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET |
+                                  D11_BCMA_IOCTL_PHYCLOCKEN,
+                            D11_BCMA_IOCTL_PHYCLOCKEN,
+                            D11_BCMA_IOCTL_PHYCLOCKEN);
+}
+
+static bool brcmf_chip_ca7_set_active(struct brcmf_chip_priv *chip, u32 rstvec)
+{
+       struct brcmf_core *core;
+
+       chip->ops->activate(chip->ctx, &chip->pub, rstvec);
+
+       /* restore ARM */
+       core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CA7);
+       brcmf_chip_resetcore(core, ARMCR4_BCMA_IOCTL_CPUHALT, 0, 0);
+
+       return true;
+}
+
 void brcmf_chip_set_passive(struct brcmf_chip *pub)
 {
        struct brcmf_chip_priv *chip;
@@ -1156,8 +1251,16 @@ void brcmf_chip_set_passive(struct brcmf_chip *pub)
                brcmf_chip_cr4_set_passive(chip);
                return;
        }
-
-       brcmf_chip_cm3_set_passive(chip);
+       arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CA7);
+       if (arm) {
+               brcmf_chip_ca7_set_passive(chip);
+               return;
+       }
+       arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CM3);
+       if (arm) {
+               brcmf_chip_cm3_set_passive(chip);
+               return;
+       }
 }
 
 bool brcmf_chip_set_active(struct brcmf_chip *pub, u32 rstvec)
@@ -1171,8 +1274,14 @@ bool brcmf_chip_set_active(struct brcmf_chip *pub, u32 rstvec)
        arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CR4);
        if (arm)
                return brcmf_chip_cr4_set_active(chip, rstvec);
+       arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CA7);
+       if (arm)
+               return brcmf_chip_ca7_set_active(chip, rstvec);
+       arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CM3);
+       if (arm)
+               return brcmf_chip_cm3_set_active(chip);
 
-       return brcmf_chip_cm3_set_active(chip);
+       return false;
 }
 
 bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
index 60dcb38..f6b5fee 100644 (file)
@@ -73,6 +73,7 @@ struct brcmf_buscore_ops {
        u32 (*read32)(void *ctx, u32 addr);
        void (*write32)(void *ctx, u32 addr, u32 value);
        int (*prepare)(void *ctx);
+       int (*reset)(void *ctx, struct brcmf_chip *chip);
        int (*setup)(void *ctx, struct brcmf_chip *chip);
        void (*activate)(void *ctx, struct brcmf_chip *chip, u32 rstvec);
 };
index fe9d3fb..8c2a280 100644 (file)
@@ -53,6 +53,8 @@ MODULE_LICENSE("Dual BSD/GPL");
 #define BRCMF_RXREORDER_EXPIDX_VALID           0x08
 #define BRCMF_RXREORDER_NEW_HOLE               0x10
 
+#define BRCMF_BSSIDX_INVALID                   -1
+
 /* Error bits */
 int brcmf_msg_level;
 module_param_named(debug, brcmf_msg_level, int, S_IRUSR | S_IWUSR);
@@ -60,10 +62,8 @@ MODULE_PARM_DESC(debug, "level of debug output");
 
 /* P2P0 enable */
 static int brcmf_p2p_enable;
-#ifdef CONFIG_BRCMDBG
 module_param_named(p2pon, brcmf_p2p_enable, int, 0);
-MODULE_PARM_DESC(p2pon, "enable p2p management functionality");
-#endif
+MODULE_PARM_DESC(p2pon, "enable legacy p2p management functionality");
 
 char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
 {
@@ -83,6 +83,24 @@ char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
        return "<if_none>";
 }
 
+struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx)
+{
+       struct brcmf_if *ifp;
+       s32 bssidx;
+
+       if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
+               brcmf_err("ifidx %d out of range\n", ifidx);
+               return NULL;
+       }
+
+       ifp = NULL;
+       bssidx = drvr->if2bss[ifidx];
+       if (bssidx >= 0)
+               ifp = drvr->iflist[bssidx];
+
+       return ifp;
+}
+
 static void _brcmf_set_multicast_list(struct work_struct *work)
 {
        struct brcmf_if *ifp;
@@ -520,17 +538,15 @@ void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
        struct brcmf_pub *drvr = bus_if->drvr;
        struct brcmf_skb_reorder_data *rd;
-       u8 ifidx;
        int ret;
 
        brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
 
        /* process and remove protocol-specific header */
-       ret = brcmf_proto_hdrpull(drvr, true, &ifidx, skb);
-       ifp = drvr->iflist[ifidx];
+       ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp);
 
        if (ret || !ifp || !ifp->ndev) {
-               if ((ret != -ENODATA) && ifp)
+               if (ret != -ENODATA && ifp)
                        ifp->stats.rx_errors++;
                brcmu_pkt_buf_free_skb(skb);
                return;
@@ -543,17 +559,11 @@ void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)
                brcmf_netif_rx(ifp, skb);
 }
 
-void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
-                     bool success)
+void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
 {
-       struct brcmf_if *ifp;
        struct ethhdr *eh;
        u16 type;
 
-       ifp = drvr->iflist[ifidx];
-       if (!ifp)
-               goto done;
-
        eh = (struct ethhdr *)(txp->data);
        type = ntohs(eh->h_proto);
 
@@ -565,7 +575,7 @@ void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
 
        if (!success)
                ifp->stats.tx_errors++;
-done:
+
        brcmu_pkt_buf_free_skb(txp);
 }
 
@@ -573,17 +583,17 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
 {
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
        struct brcmf_pub *drvr = bus_if->drvr;
-       u8 ifidx;
+       struct brcmf_if *ifp;
 
        /* await txstatus signal for firmware if active */
        if (brcmf_fws_fc_active(drvr->fws)) {
                if (!success)
                        brcmf_fws_bustxfail(drvr->fws, txp);
        } else {
-               if (brcmf_proto_hdrpull(drvr, false, &ifidx, txp))
+               if (brcmf_proto_hdrpull(drvr, false, txp, &ifp))
                        brcmu_pkt_buf_free_skb(txp);
                else
-                       brcmf_txfinalize(drvr, txp, ifidx, success);
+                       brcmf_txfinalize(ifp, txp, success);
        }
 }
 
@@ -708,8 +718,6 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
        }
 
        brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
-
-       ndev->destructor = brcmf_cfg80211_free_netdev;
        return 0;
 
 fail:
@@ -719,6 +727,14 @@ fail:
        return -EBADE;
 }
 
+static void brcmf_net_detach(struct net_device *ndev)
+{
+       if (ndev->reg_state == NETREG_REGISTERED)
+               unregister_netdev(ndev);
+       else
+               brcmf_cfg80211_free_netdev(ndev);
+}
+
 static int brcmf_net_p2p_open(struct net_device *ndev)
 {
        brcmf_dbg(TRACE, "Enter\n");
@@ -778,7 +794,7 @@ fail:
 }
 
 struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
-                             char *name, u8 *mac_addr)
+                             bool is_p2pdev, char *name, u8 *mac_addr)
 {
        struct brcmf_if *ifp;
        struct net_device *ndev;
@@ -795,8 +811,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
                          ifp->ndev->name);
                if (ifidx) {
                        netif_stop_queue(ifp->ndev);
-                       unregister_netdev(ifp->ndev);
-                       free_netdev(ifp->ndev);
+                       brcmf_net_detach(ifp->ndev);
                        drvr->iflist[bssidx] = NULL;
                } else {
                        brcmf_err("ignore IF event\n");
@@ -804,7 +819,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
                }
        }
 
-       if (!brcmf_p2p_enable && bssidx == 1) {
+       if (!brcmf_p2p_enable && is_p2pdev) {
                /* this is P2P_DEVICE interface */
                brcmf_dbg(INFO, "allocate non-netdev interface\n");
                ifp = kzalloc(sizeof(*ifp), GFP_KERNEL);
@@ -818,8 +833,12 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
                if (!ndev)
                        return ERR_PTR(-ENOMEM);
 
+               ndev->destructor = brcmf_cfg80211_free_netdev;
                ifp = netdev_priv(ndev);
                ifp->ndev = ndev;
+               /* store mapping ifidx to bssidx */
+               if (drvr->if2bss[ifidx] == BRCMF_BSSIDX_INVALID)
+                       drvr->if2bss[ifidx] = bssidx;
        }
 
        ifp->drvr = drvr;
@@ -850,6 +869,8 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
                return;
        }
        brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx);
+       if (drvr->if2bss[ifp->ifidx] == bssidx)
+               drvr->if2bss[ifp->ifidx] = BRCMF_BSSIDX_INVALID;
        if (ifp->ndev) {
                if (bssidx == 0) {
                        if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
@@ -865,17 +886,28 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
                        cancel_work_sync(&ifp->setmacaddr_work);
                        cancel_work_sync(&ifp->multicast_work);
                }
-               /* unregister will take care of freeing it */
-               unregister_netdev(ifp->ndev);
+               brcmf_net_detach(ifp->ndev);
+       } else {
+               /* Only p2p device interfaces which get dynamically created
+                * end up here. In this case the p2p module should be informed
+                * about the removal of the interface within the firmware. If
+                * not then p2p commands towards the firmware will cause some
+                * serious troublesome side effects. The p2p module will clean
+                * up the ifp if needed.
+                */
+               brcmf_p2p_ifp_removed(ifp);
+               kfree(ifp);
        }
 }
 
-void brcmf_remove_interface(struct brcmf_pub *drvr, u32 bssidx)
+void brcmf_remove_interface(struct brcmf_if *ifp)
 {
-       if (drvr->iflist[bssidx]) {
-               brcmf_fws_del_interface(drvr->iflist[bssidx]);
-               brcmf_del_if(drvr, bssidx);
-       }
+       if (!ifp || WARN_ON(ifp->drvr->iflist[ifp->bssidx] != ifp))
+               return;
+       brcmf_dbg(TRACE, "Enter, bssidx=%d, ifidx=%d\n", ifp->bssidx,
+                 ifp->ifidx);
+       brcmf_fws_del_interface(ifp);
+       brcmf_del_if(ifp->drvr, ifp->bssidx);
 }
 
 int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr)
@@ -906,6 +938,7 @@ int brcmf_attach(struct device *dev)
 {
        struct brcmf_pub *drvr = NULL;
        int ret = 0;
+       int i;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -914,6 +947,9 @@ int brcmf_attach(struct device *dev)
        if (!drvr)
                return -ENOMEM;
 
+       for (i = 0; i < ARRAY_SIZE(drvr->if2bss); i++)
+               drvr->if2bss[i] = BRCMF_BSSIDX_INVALID;
+
        mutex_init(&drvr->proto_block);
 
        /* Link to bus module */
@@ -981,12 +1017,12 @@ int brcmf_bus_start(struct device *dev)
        brcmf_dbg(TRACE, "\n");
 
        /* add primary networking interface */
-       ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL);
+       ifp = brcmf_add_if(drvr, 0, 0, false, "wlan%d", NULL);
        if (IS_ERR(ifp))
                return PTR_ERR(ifp);
 
        if (brcmf_p2p_enable)
-               p2p_ifp = brcmf_add_if(drvr, 1, 0, "p2p%d", NULL);
+               p2p_ifp = brcmf_add_if(drvr, 1, 0, false, "p2p%d", NULL);
        else
                p2p_ifp = NULL;
        if (IS_ERR(p2p_ifp))
@@ -1017,7 +1053,8 @@ int brcmf_bus_start(struct device *dev)
 
        brcmf_fws_add_interface(ifp);
 
-       drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev);
+       drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev,
+                                            brcmf_p2p_enable);
        if (drvr->config == NULL) {
                ret = -ENOMEM;
                goto fail;
@@ -1031,17 +1068,20 @@ int brcmf_bus_start(struct device *dev)
 fail:
        if (ret < 0) {
                brcmf_err("failed: %d\n", ret);
-               brcmf_cfg80211_detach(drvr->config);
+               if (drvr->config) {
+                       brcmf_cfg80211_detach(drvr->config);
+                       drvr->config = NULL;
+               }
                if (drvr->fws) {
                        brcmf_fws_del_interface(ifp);
                        brcmf_fws_deinit(drvr);
                }
                if (drvr->iflist[0]) {
-                       free_netdev(ifp->ndev);
+                       brcmf_net_detach(ifp->ndev);
                        drvr->iflist[0] = NULL;
                }
                if (p2p_ifp) {
-                       free_netdev(p2p_ifp->ndev);
+                       brcmf_net_detach(p2p_ifp->ndev);
                        drvr->iflist[1] = NULL;
                }
                return ret;
@@ -1105,7 +1145,7 @@ void brcmf_detach(struct device *dev)
 
        /* make sure primary interface removed last */
        for (i = BRCMF_MAX_IFS-1; i > -1; i--)
-               brcmf_remove_interface(drvr, i);
+               brcmf_remove_interface(drvr->iflist[i]);
 
        brcmf_cfg80211_detach(drvr->config);
 
index 7463041..d81ff95 100644 (file)
@@ -122,6 +122,7 @@ struct brcmf_pub {
        struct mac_address addresses[BRCMF_MAX_IFS];
 
        struct brcmf_if *iflist[BRCMF_MAX_IFS];
+       s32 if2bss[BRCMF_MAX_IFS];
 
        struct mutex proto_block;
        unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
@@ -202,16 +203,15 @@ int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp);
 
 /* Return pointer to interface name */
 char *brcmf_ifname(struct brcmf_pub *drvr, int idx);
-
+struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx);
 int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
 struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
-                             char *name, u8 *mac_addr);
-void brcmf_remove_interface(struct brcmf_pub *drvr, u32 bssidx);
+                             bool is_p2pdev, char *name, u8 *mac_addr);
+void brcmf_remove_interface(struct brcmf_if *ifp);
 int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr);
 void brcmf_txflowblock_if(struct brcmf_if *ifp,
                          enum brcmf_netif_stop_reason reason, bool state);
-void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
-                     bool success);
+void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
 void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
 
 /* Sets dongle media info (drv_version, mac address). */
index eb0b8c4..48648ca 100644 (file)
@@ -37,6 +37,7 @@
 #define BRCMF_SDIO_VAL         0x00020000
 #define BRCMF_MSGBUF_VAL       0x00040000
 #define BRCMF_PCIE_VAL         0x00080000
+#define BRCMF_FWCON_VAL                0x00100000
 
 /* set default print format */
 #undef pr_fmt
@@ -78,6 +79,7 @@ do {                                                          \
 #define BRCMF_GLOM_ON()                (brcmf_msg_level & BRCMF_GLOM_VAL)
 #define BRCMF_EVENT_ON()       (brcmf_msg_level & BRCMF_EVENT_VAL)
 #define BRCMF_FIL_ON()         (brcmf_msg_level & BRCMF_FIL_VAL)
+#define BRCMF_FWCON_ON()       (brcmf_msg_level & BRCMF_FWCON_VAL)
 
 #else /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */
 
@@ -90,6 +92,7 @@ do {                                                          \
 #define BRCMF_GLOM_ON()                0
 #define BRCMF_EVENT_ON()       0
 #define BRCMF_FIL_ON()         0
+#define BRCMF_FWCON_ON()       0
 
 #endif /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */
 
index 1e94e94..44bb306 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/netdevice.h>
+#include <linux/module.h>
 
 #include <brcm_hw_ids.h>
 #include "core.h"
 #include "fwil.h"
 #include "feature.h"
 
+
+/* Module param feature_disable (global for all devices) */
+static int brcmf_feature_disable;
+module_param_named(feature_disable, brcmf_feature_disable, int, 0);
+MODULE_PARM_DESC(feature_disable, "Disable features");
+
 /*
  * expand feature list to array of feature strings.
  */
@@ -121,7 +128,7 @@ static void brcmf_feat_iovar_int_set(struct brcmf_if *ifp,
 
 void brcmf_feat_attach(struct brcmf_pub *drvr)
 {
-       struct brcmf_if *ifp = drvr->iflist[0];
+       struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
 
        brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan");
        brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn");
@@ -131,6 +138,12 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
                brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
        brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_P2P, "p2p");
 
+       if (brcmf_feature_disable) {
+               brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n",
+                         ifp->drvr->feat_flags, brcmf_feature_disable);
+               ifp->drvr->feat_flags &= ~brcmf_feature_disable;
+       }
+
        /* set chip related quirks */
        switch (drvr->bus_if->chip) {
        case BRCM_CC_43236_CHIP_ID:
index 8d1ab4a..2ca783f 100644 (file)
@@ -221,7 +221,7 @@ static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid,
 
        bus_if = dev_get_drvdata(flow->dev);
        drvr = bus_if->drvr;
-       ifp = drvr->iflist[ifidx];
+       ifp = brcmf_get_ifp(drvr, ifidx);
        brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW, blocked);
 
        spin_unlock_irqrestore(&flow->block_lock, flags);
index 5551861..95fd1c9 100644 (file)
@@ -34,7 +34,7 @@ enum ring_status {
 };
 
 struct brcmf_flowring_ring {
-       u8 hash_id;
+       u16 hash_id;
        bool blocked;
        enum ring_status status;
        struct sk_buff_head skblist;
index ec62492..383d6fa 100644 (file)
@@ -179,25 +179,28 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
 {
        struct brcmf_if_event *ifevent = data;
        struct brcmf_if *ifp;
+       bool is_p2pdev;
        int err = 0;
 
        brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u role: %u\n",
                  ifevent->action, ifevent->ifidx, ifevent->bssidx,
                  ifevent->flags, ifevent->role);
 
-       /* The P2P Device interface event must not be ignored
-        * contrary to what firmware tells us. The only way to
-        * distinguish the P2P Device is by looking at the ifidx
-        * and bssidx received.
+       /* The P2P Device interface event must not be ignored contrary to what
+        * firmware tells us. Older firmware uses p2p noif, with sta role.
+        * This should be accepted when p2pdev_setup is ongoing. TDLS setup will
+        * use the same ifevent and should be ignored.
         */
-       if (!(ifevent->ifidx == 0 && ifevent->bssidx == 1) &&
-           (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) {
+       is_p2pdev = ((ifevent->flags & BRCMF_E_IF_FLAG_NOIF) &&
+                    (ifevent->role == BRCMF_E_IF_ROLE_P2P_CLIENT ||
+                     ((ifevent->role == BRCMF_E_IF_ROLE_STA) &&
+                      (drvr->fweh.p2pdev_setup_ongoing))));
+       if (!is_p2pdev && (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) {
                brcmf_dbg(EVENT, "event can be ignored\n");
                return;
        }
        if (ifevent->ifidx >= BRCMF_MAX_IFS) {
-               brcmf_err("invalid interface index: %u\n",
-                         ifevent->ifidx);
+               brcmf_err("invalid interface index: %u\n", ifevent->ifidx);
                return;
        }
 
@@ -207,7 +210,7 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
                brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname,
                          emsg->addr);
                ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx,
-                                  emsg->ifname, emsg->addr);
+                                  is_p2pdev, emsg->ifname, emsg->addr);
                if (IS_ERR(ifp))
                        return;
                brcmf_fws_add_interface(ifp);
@@ -222,7 +225,7 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
        err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
 
        if (ifp && ifevent->action == BRCMF_E_IF_DEL)
-               brcmf_remove_interface(drvr, ifevent->bssidx);
+               brcmf_remove_interface(ifp);
 }
 
 /**
@@ -297,8 +300,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
                        goto event_free;
                }
 
-               if ((event->code == BRCMF_E_TDLS_PEER_EVENT) &&
-                   (emsg.bsscfgidx == 1))
+               if (event->code == BRCMF_E_TDLS_PEER_EVENT)
                        ifp = drvr->iflist[0];
                else
                        ifp = drvr->iflist[emsg.bsscfgidx];
@@ -314,6 +316,17 @@ event_free:
        }
 }
 
+/**
+ * brcmf_fweh_p2pdev_setup() - P2P device setup ongoing (or not).
+ *
+ * @ifp: ifp on which setup is taking place or finished.
+ * @ongoing: p2p device setup in progress (or not).
+ */
+void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing)
+{
+       ifp->drvr->fweh.p2pdev_setup_ongoing = ongoing;
+}
+
 /**
  * brcmf_fweh_attach() - initialize firmware event handling.
  *
@@ -335,7 +348,7 @@ void brcmf_fweh_attach(struct brcmf_pub *drvr)
 void brcmf_fweh_detach(struct brcmf_pub *drvr)
 {
        struct brcmf_fweh_info *fweh = &drvr->fweh;
-       struct brcmf_if *ifp = drvr->iflist[0];
+       struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
        s8 eventmask[BRCMF_EVENTING_MASK_LEN];
 
        if (ifp) {
index 1326898..d9a9428 100644 (file)
@@ -230,12 +230,14 @@ typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp,
 /**
  * struct brcmf_fweh_info - firmware event handling information.
  *
+ * @p2pdev_setup_ongoing: P2P device creation in progress.
  * @event_work: event worker.
  * @evt_q_lock: lock for event queue protection.
  * @event_q: event queue.
  * @evt_handler: registered event handlers.
  */
 struct brcmf_fweh_info {
+       bool p2pdev_setup_ongoing;
        struct work_struct event_work;
        spinlock_t evt_q_lock;
        struct list_head event_q;
@@ -255,6 +257,7 @@ void brcmf_fweh_unregister(struct brcmf_pub *drvr,
 int brcmf_fweh_activate_events(struct brcmf_if *ifp);
 void brcmf_fweh_process_event(struct brcmf_pub *drvr,
                              struct brcmf_event *event_packet);
+void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing);
 
 static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
                                          struct sk_buff *skb)
index 5017eaa..086cac3 100644 (file)
@@ -972,7 +972,7 @@ static void
 brcmf_fws_flow_control_check(struct brcmf_fws_info *fws, struct pktq *pq,
                             u8 if_id)
 {
-       struct brcmf_if *ifp = fws->drvr->iflist[!if_id ? 0 : if_id + 1];
+       struct brcmf_if *ifp = brcmf_get_ifp(fws->drvr, if_id);
 
        if (WARN_ON(!ifp))
                return;
@@ -1398,7 +1398,7 @@ done:
 }
 
 static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
-                                        struct sk_buff *skb, u8 ifidx,
+                                        struct sk_buff *skb,
                                         u32 genbit, u16 seq)
 {
        struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
@@ -1448,7 +1448,7 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
        struct sk_buff *skb;
        struct brcmf_skbuff_cb *skcb;
        struct brcmf_fws_mac_descriptor *entry = NULL;
-       u8 ifidx;
+       struct brcmf_if *ifp;
 
        brcmf_dbg(DATA, "flags %d\n", flags);
 
@@ -1497,15 +1497,16 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
        }
        brcmf_fws_macdesc_return_req_credit(skb);
 
-       if (brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb)) {
+       ret = brcmf_proto_hdrpull(fws->drvr, false, skb, &ifp);
+       if (ret) {
                brcmu_pkt_buf_free_skb(skb);
                return -EINVAL;
        }
        if (!remove_from_hanger)
-               ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifidx,
+               ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb,
                                                    genbit, seq);
        if (remove_from_hanger || ret)
-               brcmf_txfinalize(fws->drvr, skb, ifidx, true);
+               brcmf_txfinalize(ifp, skb, true);
 
        return 0;
 }
@@ -1615,11 +1616,10 @@ static int brcmf_fws_notify_bcmc_credit_support(struct brcmf_if *ifp,
        return 0;
 }
 
-int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
-                     struct sk_buff *skb)
+void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb)
 {
        struct brcmf_skb_reorder_data *rd;
-       struct brcmf_fws_info *fws = drvr->fws;
+       struct brcmf_fws_info *fws = ifp->drvr->fws;
        u8 *signal_data;
        s16 data_len;
        u8 type;
@@ -1629,20 +1629,20 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
        s32 err;
 
        brcmf_dbg(HDRS, "enter: ifidx %d, skblen %u, sig %d\n",
-                 ifidx, skb->len, signal_len);
+                 ifp->ifidx, skb->len, siglen);
 
-       WARN_ON(signal_len > skb->len);
+       WARN_ON(siglen > skb->len);
 
-       if (!signal_len)
-               return 0;
+       if (!siglen)
+               return;
        /* if flow control disabled, skip to packet data and leave */
        if ((!fws) || (!fws->fw_signals)) {
-               skb_pull(skb, signal_len);
-               return 0;
+               skb_pull(skb, siglen);
+               return;
        }
 
        fws->stats.header_pulls++;
-       data_len = signal_len;
+       data_len = siglen;
        signal_data = skb->data;
 
        status = BRCMF_FWS_RET_OK_NOSCHEDULE;
@@ -1730,14 +1730,12 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
        /* signalling processing result does
         * not affect the actual ethernet packet.
         */
-       skb_pull(skb, signal_len);
+       skb_pull(skb, siglen);
 
        /* this may be a signal-only packet
         */
        if (skb->len == 0)
                fws->stats.header_only_pkt++;
-
-       return 0;
 }
 
 static u8 brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
@@ -1848,7 +1846,7 @@ static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
                entry->transit_count--;
                if (entry->suppressed)
                        entry->suppr_transit_count--;
-               brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
+               (void)brcmf_proto_hdrpull(fws->drvr, false, skb, NULL);
                goto rollback;
        }
 
@@ -1904,7 +1902,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
        if (fws->avoid_queueing) {
                rc = brcmf_proto_txdata(drvr, ifp->ifidx, 0, skb);
                if (rc < 0)
-                       brcmf_txfinalize(drvr, skb, ifp->ifidx, false);
+                       brcmf_txfinalize(ifp, skb, false);
                return rc;
        }
 
@@ -1928,7 +1926,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
                brcmf_fws_schedule_deq(fws);
        } else {
                brcmf_err("drop skb: no hanger slot\n");
-               brcmf_txfinalize(drvr, skb, ifp->ifidx, false);
+               brcmf_txfinalize(ifp, skb, false);
                rc = -ENOMEM;
        }
        brcmf_fws_unlock(fws);
@@ -2008,8 +2006,9 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
                                ret = brcmf_proto_txdata(drvr, ifidx, 0, skb);
                                brcmf_fws_lock(fws);
                                if (ret < 0)
-                                       brcmf_txfinalize(drvr, skb, ifidx,
-                                                        false);
+                                       brcmf_txfinalize(brcmf_get_ifp(drvr,
+                                                                      ifidx),
+                                                        skb, false);
                                if (fws->bus_flow_blocked)
                                        break;
                        }
@@ -2117,6 +2116,7 @@ static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data)
 int brcmf_fws_init(struct brcmf_pub *drvr)
 {
        struct brcmf_fws_info *fws;
+       struct brcmf_if *ifp;
        u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS;
        int rc;
        u32 mode;
@@ -2176,21 +2176,22 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
         * continue. Set mode back to none indicating not enabled.
         */
        fws->fw_signals = true;
-       if (brcmf_fil_iovar_int_set(drvr->iflist[0], "tlv", tlv)) {
+       ifp = brcmf_get_ifp(drvr, 0);
+       if (brcmf_fil_iovar_int_set(ifp, "tlv", tlv)) {
                brcmf_err("failed to set bdcv2 tlv signaling\n");
                fws->fcmode = BRCMF_FWS_FCMODE_NONE;
                fws->fw_signals = false;
        }
 
-       if (brcmf_fil_iovar_int_set(drvr->iflist[0], "ampdu_hostreorder", 1))
+       if (brcmf_fil_iovar_int_set(ifp, "ampdu_hostreorder", 1))
                brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n");
 
        /* Enable seq number reuse, if supported */
-       if (brcmf_fil_iovar_int_get(drvr->iflist[0], "wlfc_mode", &mode) == 0) {
+       if (brcmf_fil_iovar_int_get(ifp, "wlfc_mode", &mode) == 0) {
                if (BRCMF_FWS_MODE_GET_REUSESEQ(mode)) {
                        mode = 0;
                        BRCMF_FWS_MODE_SET_REUSESEQ(mode, 1);
-                       if (brcmf_fil_iovar_int_set(drvr->iflist[0],
+                       if (brcmf_fil_iovar_int_set(ifp,
                                                    "wlfc_mode", mode) == 0) {
                                BRCMF_FWS_MODE_SET_REUSESEQ(fws->mode, 1);
                        }
index 9fc8609..a36bac1 100644 (file)
@@ -21,8 +21,7 @@
 int brcmf_fws_init(struct brcmf_pub *drvr);
 void brcmf_fws_deinit(struct brcmf_pub *drvr);
 bool brcmf_fws_fc_active(struct brcmf_fws_info *fws);
-int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
-                     struct sk_buff *skb);
+void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb);
 int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb);
 
 void brcmf_fws_reset_interface(struct brcmf_if *ifp);
index 7b2136c..7eff9de 100644 (file)
@@ -522,7 +522,7 @@ static int brcmf_msgbuf_set_dcmd(struct brcmf_pub *drvr, int ifidx,
 
 
 static int brcmf_msgbuf_hdrpull(struct brcmf_pub *drvr, bool do_fws,
-                               u8 *ifidx, struct sk_buff *skb)
+                               struct sk_buff *skb, struct brcmf_if **ifp)
 {
        return -ENODEV;
 }
@@ -873,7 +873,11 @@ brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf)
        commonring = msgbuf->flowrings[flowid];
        atomic_dec(&commonring->outstanding_tx);
 
-       brcmf_txfinalize(msgbuf->drvr, skb, tx_status->msg.ifidx, true);
+       /* Hante: i believe this was a bug as tx_status->msg.ifidx was used
+        * in brcmf_txfinalize as index in drvr->iflist. Can you confirm/deny?
+        */
+       brcmf_txfinalize(brcmf_get_ifp(msgbuf->drvr, tx_status->msg.ifidx),
+                        skb, true);
 }
 
 
@@ -1081,15 +1085,7 @@ brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb,
 {
        struct brcmf_if *ifp;
 
-       /* The ifidx is the idx to map to matching netdev/ifp. When receiving
-        * events this is easy because it contains the bssidx which maps
-        * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
-        * bssidx 1 is used for p2p0 and no data can be received or
-        * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
-        */
-       if (ifidx)
-               (ifidx)++;
-       ifp = msgbuf->drvr->iflist[ifidx];
+       ifp = brcmf_get_ifp(msgbuf->drvr, ifidx);
        if (!ifp || !ifp->ndev) {
                brcmf_err("Received pkt for invalid ifidx %d\n", ifidx);
                brcmu_pkt_buf_free_skb(skb);
index a9ba775..37a8c35 100644 (file)
@@ -2084,11 +2084,13 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p,
        brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
 
        brcmf_cfg80211_arm_vif_event(p2p->cfg, p2p_vif);
+       brcmf_fweh_p2pdev_setup(pri_ifp, true);
 
        /* Initialize P2P Discovery in the firmware */
        err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
        if (err < 0) {
                brcmf_err("set p2p_disc error\n");
+               brcmf_fweh_p2pdev_setup(pri_ifp, false);
                brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL);
                goto fail;
        }
@@ -2097,6 +2099,7 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p,
        err = brcmf_cfg80211_wait_vif_event_timeout(p2p->cfg, BRCMF_E_IF_ADD,
                                                    msecs_to_jiffies(1500));
        brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL);
+       brcmf_fweh_p2pdev_setup(pri_ifp, false);
        if (!err) {
                brcmf_err("timeout occurred\n");
                err = -EIO;
@@ -2130,20 +2133,6 @@ fail:
        return ERR_PTR(err);
 }
 
-/**
- * brcmf_p2p_delete_p2pdev() - delete P2P_DEVICE virtual interface.
- *
- * @vif: virtual interface object to delete.
- */
-static void brcmf_p2p_delete_p2pdev(struct brcmf_p2p_info *p2p,
-                                   struct brcmf_cfg80211_vif *vif)
-{
-       cfg80211_unregister_wdev(&vif->wdev);
-       p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
-       brcmf_remove_interface(vif->ifp->drvr, vif->ifp->bssidx);
-       brcmf_free_vif(vif);
-}
-
 /**
  * brcmf_p2p_add_vif() - create a new P2P virtual interface.
  *
@@ -2255,6 +2244,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
        brcmf_dbg(TRACE, "delete P2P vif\n");
        vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
 
+       brcmf_cfg80211_arm_vif_event(cfg, vif);
        switch (vif->wdev.iftype) {
        case NL80211_IFTYPE_P2P_CLIENT:
                if (test_bit(BRCMF_VIF_STATUS_DISCONNECTING, &vif->sme_state))
@@ -2267,10 +2257,10 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
                break;
 
        case NL80211_IFTYPE_P2P_DEVICE:
+               if (!p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
+                       return 0;
                brcmf_p2p_cancel_remain_on_channel(vif->ifp);
                brcmf_p2p_deinit_discovery(p2p);
-               brcmf_p2p_delete_p2pdev(p2p, vif);
-               return 0;
        default:
                return -ENOTSUPP;
        }
@@ -2282,10 +2272,11 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
                wait_for_completion_timeout(&cfg->vif_disabled,
                                            msecs_to_jiffies(500));
 
-       brcmf_vif_clear_mgmt_ies(vif);
-
-       brcmf_cfg80211_arm_vif_event(cfg, vif);
-       err = brcmf_p2p_release_p2p_if(vif);
+       err = 0;
+       if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE) {
+               brcmf_vif_clear_mgmt_ies(vif);
+               err = brcmf_p2p_release_p2p_if(vif);
+       }
        if (!err) {
                /* wait for firmware event */
                err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL,
@@ -2295,12 +2286,31 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
                else
                        err = 0;
        }
+       if (err)
+               brcmf_remove_interface(vif->ifp);
+
        brcmf_cfg80211_arm_vif_event(cfg, NULL);
-       p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL;
+       if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE)
+               p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL;
 
        return err;
 }
 
+void brcmf_p2p_ifp_removed(struct brcmf_if *ifp)
+{
+       struct brcmf_cfg80211_info *cfg;
+       struct brcmf_cfg80211_vif *vif;
+
+       brcmf_dbg(INFO, "P2P: device interface removed\n");
+       vif = ifp->vif;
+       cfg = wdev_to_cfg(&vif->wdev);
+       cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+       rtnl_lock();
+       cfg80211_unregister_wdev(&vif->wdev);
+       rtnl_unlock();
+       brcmf_free_vif(vif);
+}
+
 int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
@@ -2324,11 +2334,19 @@ void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev)
        struct brcmf_cfg80211_vif *vif;
 
        vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
-       mutex_lock(&cfg->usr_sync);
-       (void)brcmf_p2p_deinit_discovery(p2p);
-       brcmf_abort_scanning(cfg);
-       clear_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);
-       mutex_unlock(&cfg->usr_sync);
+       /* This call can be result of the unregister_wdev call. In that case
+        * we dont want to do anything anymore. Just return. The config vif
+        * will have been cleared at this point.
+        */
+       if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif == vif) {
+               mutex_lock(&cfg->usr_sync);
+               /* Set the discovery state to SCAN */
+               (void)brcmf_p2p_set_discover_state(vif->ifp,
+                                                  WL_P2P_DISC_ST_SCAN, 0, 0);
+               brcmf_abort_scanning(cfg);
+               clear_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);
+               mutex_unlock(&cfg->usr_sync);
+       }
 }
 
 /**
@@ -2336,7 +2354,7 @@ void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev)
  *
  * @cfg: driver private data for cfg80211 interface.
  */
-s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
+s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced)
 {
        struct brcmf_if *pri_ifp;
        struct brcmf_if *p2p_ifp;
@@ -2351,11 +2369,15 @@ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
 
        drvr = cfg->pub;
 
-       pri_ifp = drvr->iflist[0];
-       p2p_ifp = drvr->iflist[1];
-
+       pri_ifp = brcmf_get_ifp(drvr, 0);
        p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif;
 
+       if (p2pdev_forced) {
+               p2p_ifp = drvr->iflist[1];
+       } else {
+               p2p_ifp = NULL;
+               p2p->p2pdev_dynamically = true;
+       }
        if (p2p_ifp) {
                p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE,
                                          false);
@@ -2377,6 +2399,8 @@ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
                memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
                brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
 
+               brcmf_fweh_p2pdev_setup(pri_ifp, true);
+
                /* Initialize P2P Discovery in the firmware */
                err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
                if (err < 0) {
@@ -2403,8 +2427,9 @@ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
                INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler);
                init_completion(&p2p->afx_hdl.act_frm_scan);
                init_completion(&p2p->wait_next_af);
-       }
 exit:
+               brcmf_fweh_p2pdev_setup(pri_ifp, false);
+       }
        return err;
 }
 
@@ -2421,10 +2446,7 @@ void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
        if (vif != NULL) {
                brcmf_p2p_cancel_remain_on_channel(vif->ifp);
                brcmf_p2p_deinit_discovery(p2p);
-               /* remove discovery interface */
-               rtnl_lock();
-               brcmf_p2p_delete_p2pdev(p2p, vif);
-               rtnl_unlock();
+               brcmf_remove_interface(vif->ifp);
        }
        /* just set it all to zero */
        memset(p2p, 0, sizeof(*p2p));
index 872f382..5d49059 100644 (file)
@@ -124,6 +124,7 @@ struct afx_hdl {
  * @wait_next_af: thread synchronizing struct.
  * @gon_req_action: about to send go negotiation requets frame.
  * @block_gon_req_tx: drop tx go negotiation requets frame.
+ * @p2pdev_dynamically: is p2p device if created by module param or supplicant.
  */
 struct brcmf_p2p_info {
        struct brcmf_cfg80211_info *cfg;
@@ -144,9 +145,10 @@ struct brcmf_p2p_info {
        struct completion wait_next_af;
        bool gon_req_action;
        bool block_gon_req_tx;
+       bool p2pdev_dynamically;
 };
 
-s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg);
+s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced);
 void brcmf_p2p_detach(struct brcmf_p2p_info *p2p);
 struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
                                       unsigned char name_assign_type,
@@ -155,6 +157,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
 int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev);
 int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
                       enum brcmf_fil_p2p_if_types if_type);
+void brcmf_p2p_ifp_removed(struct brcmf_if *ifp);
 int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev);
 void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev);
 int brcmf_p2p_scan_prep(struct wiphy *wiphy,
index 3a98c43..30baf35 100644 (file)
@@ -47,12 +47,18 @@ enum brcmf_pcie_state {
 
 #define BRCMF_PCIE_43602_FW_NAME               "brcm/brcmfmac43602-pcie.bin"
 #define BRCMF_PCIE_43602_NVRAM_NAME            "brcm/brcmfmac43602-pcie.txt"
+#define BRCMF_PCIE_4350_FW_NAME                        "brcm/brcmfmac4350-pcie.bin"
+#define BRCMF_PCIE_4350_NVRAM_NAME             "brcm/brcmfmac4350-pcie.txt"
 #define BRCMF_PCIE_4356_FW_NAME                        "brcm/brcmfmac4356-pcie.bin"
 #define BRCMF_PCIE_4356_NVRAM_NAME             "brcm/brcmfmac4356-pcie.txt"
 #define BRCMF_PCIE_43570_FW_NAME               "brcm/brcmfmac43570-pcie.bin"
 #define BRCMF_PCIE_43570_NVRAM_NAME            "brcm/brcmfmac43570-pcie.txt"
 #define BRCMF_PCIE_4358_FW_NAME                        "brcm/brcmfmac4358-pcie.bin"
 #define BRCMF_PCIE_4358_NVRAM_NAME             "brcm/brcmfmac4358-pcie.txt"
+#define BRCMF_PCIE_4365_FW_NAME                        "brcm/brcmfmac4365b-pcie.bin"
+#define BRCMF_PCIE_4365_NVRAM_NAME             "brcm/brcmfmac4365b-pcie.txt"
+#define BRCMF_PCIE_4366_FW_NAME                        "brcm/brcmfmac4366b-pcie.bin"
+#define BRCMF_PCIE_4366_NVRAM_NAME             "brcm/brcmfmac4366b-pcie.txt"
 
 #define BRCMF_PCIE_FW_UP_TIMEOUT               2000 /* msec */
 
@@ -74,6 +80,8 @@ enum brcmf_pcie_state {
 #define BRCMF_PCIE_REG_INTMASK                 0x94
 #define BRCMF_PCIE_REG_SBMBX                   0x98
 
+#define BRCMF_PCIE_REG_LINK_STATUS_CTRL                0xBC
+
 #define BRCMF_PCIE_PCIE2REG_INTMASK            0x24
 #define BRCMF_PCIE_PCIE2REG_MAILBOXINT         0x48
 #define BRCMF_PCIE_PCIE2REG_MAILBOXMASK                0x4C
@@ -192,12 +200,18 @@ enum brcmf_pcie_state {
 
 MODULE_FIRMWARE(BRCMF_PCIE_43602_FW_NAME);
 MODULE_FIRMWARE(BRCMF_PCIE_43602_NVRAM_NAME);
+MODULE_FIRMWARE(BRCMF_PCIE_4350_FW_NAME);
+MODULE_FIRMWARE(BRCMF_PCIE_4350_NVRAM_NAME);
 MODULE_FIRMWARE(BRCMF_PCIE_4356_FW_NAME);
 MODULE_FIRMWARE(BRCMF_PCIE_4356_NVRAM_NAME);
 MODULE_FIRMWARE(BRCMF_PCIE_43570_FW_NAME);
 MODULE_FIRMWARE(BRCMF_PCIE_43570_NVRAM_NAME);
 MODULE_FIRMWARE(BRCMF_PCIE_4358_FW_NAME);
 MODULE_FIRMWARE(BRCMF_PCIE_4358_NVRAM_NAME);
+MODULE_FIRMWARE(BRCMF_PCIE_4365_FW_NAME);
+MODULE_FIRMWARE(BRCMF_PCIE_4365_NVRAM_NAME);
+MODULE_FIRMWARE(BRCMF_PCIE_4366_FW_NAME);
+MODULE_FIRMWARE(BRCMF_PCIE_4366_NVRAM_NAME);
 
 
 struct brcmf_pcie_console {
@@ -466,6 +480,7 @@ brcmf_pcie_select_core(struct brcmf_pciedev_info *devinfo, u16 coreid)
 
 static void brcmf_pcie_reset_device(struct brcmf_pciedev_info *devinfo)
 {
+       struct brcmf_core *core;
        u16 cfg_offset[] = { BRCMF_PCIE_CFGREG_STATUS_CMD,
                             BRCMF_PCIE_CFGREG_PM_CSR,
                             BRCMF_PCIE_CFGREG_MSI_CAP,
@@ -484,32 +499,38 @@ static void brcmf_pcie_reset_device(struct brcmf_pciedev_info *devinfo)
        if (!devinfo->ci)
                return;
 
+       /* Disable ASPM */
        brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
-       brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR,
-                              BRCMF_PCIE_CFGREG_LINK_STATUS_CTRL);
-       lsc = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGDATA);
+       pci_read_config_dword(devinfo->pdev, BRCMF_PCIE_REG_LINK_STATUS_CTRL,
+                             &lsc);
        val = lsc & (~BRCMF_PCIE_LINK_STATUS_CTRL_ASPM_ENAB);
-       brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGDATA, val);
+       pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_LINK_STATUS_CTRL,
+                              val);
 
+       /* Watchdog reset */
        brcmf_pcie_select_core(devinfo, BCMA_CORE_CHIPCOMMON);
        WRITECC32(devinfo, watchdog, 4);
        msleep(100);
 
+       /* Restore ASPM */
        brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
-       brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR,
-                              BRCMF_PCIE_CFGREG_LINK_STATUS_CTRL);
-       brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGDATA, lsc);
-
-       brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
-       for (i = 0; i < ARRAY_SIZE(cfg_offset); i++) {
-               brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR,
-                                      cfg_offset[i]);
-               val = brcmf_pcie_read_reg32(devinfo,
-                                           BRCMF_PCIE_PCIE2REG_CONFIGDATA);
-               brcmf_dbg(PCIE, "config offset 0x%04x, value 0x%04x\n",
-                         cfg_offset[i], val);
-               brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGDATA,
-                                      val);
+       pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_LINK_STATUS_CTRL,
+                              lsc);
+
+       core = brcmf_chip_get_core(devinfo->ci, BCMA_CORE_PCIE2);
+       if (core->rev <= 13) {
+               for (i = 0; i < ARRAY_SIZE(cfg_offset); i++) {
+                       brcmf_pcie_write_reg32(devinfo,
+                                              BRCMF_PCIE_PCIE2REG_CONFIGADDR,
+                                              cfg_offset[i]);
+                       val = brcmf_pcie_read_reg32(devinfo,
+                               BRCMF_PCIE_PCIE2REG_CONFIGDATA);
+                       brcmf_dbg(PCIE, "config offset 0x%04x, value 0x%04x\n",
+                                 cfg_offset[i], val);
+                       brcmf_pcie_write_reg32(devinfo,
+                                              BRCMF_PCIE_PCIE2REG_CONFIGDATA,
+                                              val);
+               }
        }
 }
 
@@ -519,8 +540,6 @@ static void brcmf_pcie_attach(struct brcmf_pciedev_info *devinfo)
        u32 config;
 
        brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
-       if (brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_INTMASK) != 0)
-               brcmf_pcie_reset_device(devinfo);
        /* BAR1 window may not be sized properly */
        brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
        brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR, 0x4e0);
@@ -644,7 +663,7 @@ static void brcmf_pcie_bus_console_init(struct brcmf_pciedev_info *devinfo)
        addr = console->base_addr + BRCMF_CONSOLE_BUFSIZE_OFFSET;
        console->bufsize = brcmf_pcie_read_tcm32(devinfo, addr);
 
-       brcmf_dbg(PCIE, "Console: base %x, buf %x, size %d\n",
+       brcmf_dbg(FWCON, "Console: base %x, buf %x, size %d\n",
                  console->base_addr, console->buf_addr, console->bufsize);
 }
 
@@ -656,6 +675,9 @@ static void brcmf_pcie_bus_console_read(struct brcmf_pciedev_info *devinfo)
        u8 ch;
        u32 newidx;
 
+       if (!BRCMF_FWCON_ON())
+               return;
+
        console = &devinfo->shared.console;
        addr = console->base_addr + BRCMF_CONSOLE_WRITEIDX_OFFSET;
        newidx = brcmf_pcie_read_tcm32(devinfo, addr);
@@ -677,7 +699,7 @@ static void brcmf_pcie_bus_console_read(struct brcmf_pciedev_info *devinfo)
                }
                if (ch == '\n') {
                        console->log_str[console->log_idx] = 0;
-                       brcmf_dbg(PCIE, "CONSOLE: %s", console->log_str);
+                       pr_debug("CONSOLE: %s", console->log_str);
                        console->log_idx = 0;
                }
        }
@@ -1408,6 +1430,10 @@ static int brcmf_pcie_get_fwnames(struct brcmf_pciedev_info *devinfo)
                fw_name = BRCMF_PCIE_43602_FW_NAME;
                nvram_name = BRCMF_PCIE_43602_NVRAM_NAME;
                break;
+       case BRCM_CC_4350_CHIP_ID:
+               fw_name = BRCMF_PCIE_4350_FW_NAME;
+               nvram_name = BRCMF_PCIE_4350_NVRAM_NAME;
+               break;
        case BRCM_CC_4356_CHIP_ID:
                fw_name = BRCMF_PCIE_4356_FW_NAME;
                nvram_name = BRCMF_PCIE_4356_NVRAM_NAME;
@@ -1422,6 +1448,14 @@ static int brcmf_pcie_get_fwnames(struct brcmf_pciedev_info *devinfo)
                fw_name = BRCMF_PCIE_4358_FW_NAME;
                nvram_name = BRCMF_PCIE_4358_NVRAM_NAME;
                break;
+       case BRCM_CC_4365_CHIP_ID:
+               fw_name = BRCMF_PCIE_4365_FW_NAME;
+               nvram_name = BRCMF_PCIE_4365_NVRAM_NAME;
+               break;
+       case BRCM_CC_4366_CHIP_ID:
+               fw_name = BRCMF_PCIE_4366_FW_NAME;
+               nvram_name = BRCMF_PCIE_4366_NVRAM_NAME;
+               break;
        default:
                brcmf_err("Unsupported chip 0x%04x\n", devinfo->ci->chip);
                return -ENODEV;
@@ -1633,6 +1667,23 @@ static int brcmf_pcie_buscoreprep(void *ctx)
 }
 
 
+static int brcmf_pcie_buscore_reset(void *ctx, struct brcmf_chip *chip)
+{
+       struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx;
+       u32 val;
+
+       devinfo->ci = chip;
+       brcmf_pcie_reset_device(devinfo);
+
+       val = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT);
+       if (val != 0xffffffff)
+               brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT,
+                                      val);
+
+       return 0;
+}
+
+
 static void brcmf_pcie_buscore_activate(void *ctx, struct brcmf_chip *chip,
                                        u32 rstvec)
 {
@@ -1644,6 +1695,7 @@ static void brcmf_pcie_buscore_activate(void *ctx, struct brcmf_chip *chip,
 
 static const struct brcmf_buscore_ops brcmf_pcie_buscore_ops = {
        .prepare = brcmf_pcie_buscoreprep,
+       .reset = brcmf_pcie_buscore_reset,
        .activate = brcmf_pcie_buscore_activate,
        .read32 = brcmf_pcie_buscore_read32,
        .write32 = brcmf_pcie_buscore_write32,
@@ -1811,7 +1863,6 @@ brcmf_pcie_remove(struct pci_dev *pdev)
                brcmf_pcie_intr_disable(devinfo);
 
        brcmf_detach(&pdev->dev);
-       brcmf_pcie_reset_device(devinfo);
 
        kfree(bus->bus_priv.pcie);
        kfree(bus->msgbuf->flowrings);
@@ -1929,6 +1980,7 @@ cleanup:
        PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 }
 
 static struct pci_device_id brcmf_pcie_devid_table[] = {
+       BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID),
        BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID),
        BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID),
        BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID),
@@ -1937,6 +1989,12 @@ static struct pci_device_id brcmf_pcie_devid_table[] = {
        BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_2G_DEVICE_ID),
        BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_5G_DEVICE_ID),
        BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_RAW_DEVICE_ID),
+       BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_DEVICE_ID),
+       BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_2G_DEVICE_ID),
+       BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_5G_DEVICE_ID),
+       BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_DEVICE_ID),
+       BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID),
+       BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID),
        { /* end: all zeroes */ }
 };
 
index 971172f..d55119d 100644 (file)
@@ -24,8 +24,8 @@ enum proto_addr_mode {
 
 
 struct brcmf_proto {
-       int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
-                      struct sk_buff *skb);
+       int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws,
+                      struct sk_buff *skb, struct brcmf_if **ifp);
        int (*query_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd,
                          void *buf, uint len);
        int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
@@ -46,9 +46,19 @@ int brcmf_proto_attach(struct brcmf_pub *drvr);
 void brcmf_proto_detach(struct brcmf_pub *drvr);
 
 static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws,
-                                     u8 *ifidx, struct sk_buff *skb)
+                                     struct sk_buff *skb,
+                                     struct brcmf_if **ifp)
 {
-       return drvr->proto->hdrpull(drvr, do_fws, ifidx, skb);
+       struct brcmf_if *tmp = NULL;
+
+       /* assure protocol is always called with
+        * non-null initialized pointer.
+        */
+       if (ifp)
+               *ifp = NULL;
+       else
+               ifp = &tmp;
+       return drvr->proto->hdrpull(drvr, do_fws, skb, ifp);
 }
 static inline int brcmf_proto_query_dcmd(struct brcmf_pub *drvr, int ifidx,
                                         uint cmd, void *buf, uint len)
index f990e3d..7f574f2 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/atomic.h>
 #include <linux/kernel.h>
 #include <linux/kthread.h>
 #include <linux/printk.h>
@@ -123,6 +124,7 @@ struct rte_console {
 
 #define BRCMF_FIRSTREAD        (1 << 6)
 
+#define BRCMF_CONSOLE  10      /* watchdog interval to poll console */
 
 /* SBSDIO_DEVICE_CTL */
 
@@ -3204,6 +3206,8 @@ static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
        if (IS_ERR_OR_NULL(dentry))
                return;
 
+       bus->console_interval = BRCMF_CONSOLE;
+
        brcmf_debugfs_add_entry(drvr, "forensics", brcmf_sdio_forensic_read);
        brcmf_debugfs_add_entry(drvr, "counters",
                                brcmf_debugfs_sdio_count_read);
@@ -3613,7 +3617,7 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
        }
 #ifdef DEBUG
        /* Poll for console output periodically */
-       if (bus->sdiodev->state == BRCMF_SDIOD_DATA &&
+       if (bus->sdiodev->state == BRCMF_SDIOD_DATA && BRCMF_FWCON_ON() &&
            bus->console_interval != 0) {
                bus->console.count += BRCMF_WD_POLL_MS;
                if (bus->console.count >= bus->console_interval) {
index 7a6daa3..d823734 100644 (file)
@@ -39,6 +39,7 @@
 #define BRCM_CC_4339_CHIP_ID           0x4339
 #define BRCM_CC_43430_CHIP_ID          43430
 #define BRCM_CC_4345_CHIP_ID           0x4345
+#define BRCM_CC_4350_CHIP_ID           0x4350
 #define BRCM_CC_4354_CHIP_ID           0x4354
 #define BRCM_CC_4356_CHIP_ID           0x4356
 #define BRCM_CC_43566_CHIP_ID          43566
@@ -47,6 +48,8 @@
 #define BRCM_CC_43570_CHIP_ID          43570
 #define BRCM_CC_4358_CHIP_ID           0x4358
 #define BRCM_CC_43602_CHIP_ID          43602
+#define BRCM_CC_4365_CHIP_ID           0x4365
+#define BRCM_CC_4366_CHIP_ID           0x4366
 
 /* USB Device IDs */
 #define BRCM_USB_43143_DEVICE_ID       0xbd1e
@@ -56,6 +59,7 @@
 #define BRCM_USB_BCMFW_DEVICE_ID       0x0bdc
 
 /* PCIE Device IDs */
+#define BRCM_PCIE_4350_DEVICE_ID       0x43a3
 #define BRCM_PCIE_4354_DEVICE_ID       0x43df
 #define BRCM_PCIE_4356_DEVICE_ID       0x43ec
 #define BRCM_PCIE_43567_DEVICE_ID      0x43d3
 #define BRCM_PCIE_43602_2G_DEVICE_ID   0x43bb
 #define BRCM_PCIE_43602_5G_DEVICE_ID   0x43bc
 #define BRCM_PCIE_43602_RAW_DEVICE_ID  43602
+#define BRCM_PCIE_4365_DEVICE_ID       0x43ca
+#define BRCM_PCIE_4365_2G_DEVICE_ID    0x43cb
+#define BRCM_PCIE_4365_5G_DEVICE_ID    0x43cc
+#define BRCM_PCIE_4366_DEVICE_ID       0x43c3
+#define BRCM_PCIE_4366_2G_DEVICE_ID    0x43c4
+#define BRCM_PCIE_4366_5G_DEVICE_ID    0x43c5
+
 
 /* brcmsmac IDs */
 #define BCM4313_D11N2G_ID      0x4727  /* 4313 802.11n 2.4G device */
index f7c7172..2c5ffa1 100644 (file)
@@ -202,6 +202,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
                tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT;
        tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_AGGR_PKT;
        skb_aggr->priority = skb_src->priority;
+       skb_aggr->tstamp = skb_src->tstamp;
 
        do_gettimeofday(&tv);
        skb_aggr->tstamp = timeval_to_ktime(tv);
@@ -258,8 +259,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
        }
 
        if (adapter->iface_type == MWIFIEX_USB) {
-               adapter->data_sent = true;
-               ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_USB_EP_DATA,
+               ret = adapter->if_ops.host_to_card(adapter, priv->usb_port,
                                                   skb_aggr, NULL);
        } else {
                if (skb_src)
@@ -299,16 +299,12 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
                mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
                break;
        case -1:
-               if (adapter->iface_type != MWIFIEX_PCIE)
-                       adapter->data_sent = false;
                mwifiex_dbg(adapter, ERROR, "%s: host_to_card failed: %#x\n",
                            __func__, ret);
                adapter->dbg.num_tx_host_to_card_failure++;
                mwifiex_write_data_complete(adapter, skb_aggr, 1, ret);
                return 0;
        case -EINPROGRESS:
-               if (adapter->iface_type != MWIFIEX_PCIE)
-                       adapter->data_sent = false;
                break;
        case 0:
                mwifiex_write_data_complete(adapter, skb_aggr, 1, ret);
index ff63cb5..30cbafb 100644 (file)
@@ -1994,8 +1994,10 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
                                  CFG80211_BSS_FTYPE_UNKNOWN,
                                  bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
                                  0, ie_buf, ie_len, 0, GFP_KERNEL);
-       cfg80211_put_bss(priv->wdev.wiphy, bss);
-       memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN);
+       if (bss) {
+               cfg80211_put_bss(priv->wdev.wiphy, bss);
+               ether_addr_copy(priv->cfg_bssid, bss_info.bssid);
+       }
 
        return 0;
 }
@@ -2859,14 +2861,14 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
        case NL80211_IFTYPE_UNSPECIFIED:
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_ADHOC:
-               adapter->curr_iface_comb.sta_intf++;
+               adapter->curr_iface_comb.sta_intf--;
                break;
        case NL80211_IFTYPE_AP:
-               adapter->curr_iface_comb.uap_intf++;
+               adapter->curr_iface_comb.uap_intf--;
                break;
        case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_P2P_GO:
-               adapter->curr_iface_comb.p2p_intf++;
+               adapter->curr_iface_comb.p2p_intf--;
                break;
        default:
                mwifiex_dbg(adapter, ERROR,
index 5a0636d..5583856 100644 (file)
@@ -731,7 +731,7 @@ mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,
                (struct mwifiex_private *) file->private_data;
        unsigned long addr = get_zeroed_page(GFP_KERNEL);
        char *buf = (char *) addr;
-       int pos = 0, ret = 0, i;
+       int pos, ret, i;
        u8 value[MAX_EEPROM_DATA];
 
        if (!buf)
@@ -739,7 +739,7 @@ mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,
 
        if (saved_offset == -1) {
                /* No command has been given */
-               pos += snprintf(buf, PAGE_SIZE, "0");
+               pos = snprintf(buf, PAGE_SIZE, "0");
                goto done;
        }
 
@@ -748,17 +748,17 @@ mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,
                                  (u16) saved_bytes, value);
        if (ret) {
                ret = -EINVAL;
-               goto done;
+               goto out_free;
        }
 
-       pos += snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes);
+       pos = snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes);
 
        for (i = 0; i < saved_bytes; i++)
-               pos += snprintf(buf + strlen(buf), PAGE_SIZE, "%d ", value[i]);
-
-       ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
+               pos += scnprintf(buf + pos, PAGE_SIZE - pos, "%d ", value[i]);
 
 done:
+       ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
+out_free:
        free_page(addr);
        return ret;
 }
index 3ec2ac8..0e6f029 100644 (file)
@@ -104,6 +104,7 @@ enum KEY_TYPE_ID {
 enum mwifiex_usb_ep {
        MWIFIEX_USB_EP_CMD_EVENT = 1,
        MWIFIEX_USB_EP_DATA = 2,
+       MWIFIEX_USB_EP_DATA_CH2 = 3,
 };
 
 enum MWIFIEX_802_11_PRIVACY_FILTER {
@@ -173,6 +174,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define TLV_TYPE_COALESCE_RULE      (PROPRIETARY_TLV_BASE_ID + 154)
 #define TLV_TYPE_KEY_PARAM_V2       (PROPRIETARY_TLV_BASE_ID + 156)
 #define TLV_TYPE_MULTI_CHAN_INFO    (PROPRIETARY_TLV_BASE_ID + 183)
+#define TLV_TYPE_MC_GROUP_INFO      (PROPRIETARY_TLV_BASE_ID + 184)
 #define TLV_TYPE_TDLS_IDLE_TIMEOUT  (PROPRIETARY_TLV_BASE_ID + 194)
 #define TLV_TYPE_SCAN_CHANNEL_GAP   (PROPRIETARY_TLV_BASE_ID + 197)
 #define TLV_TYPE_API_REV            (PROPRIETARY_TLV_BASE_ID + 199)
@@ -1984,6 +1986,22 @@ struct mwifiex_ie_types_multi_chan_info {
        u8 tlv_buffer[0];
 } __packed;
 
+struct mwifiex_ie_types_mc_group_info {
+       struct mwifiex_ie_types_header header;
+       u8 chan_group_id;
+       u8 chan_buf_weight;
+       u8 band_config;
+       u8 chan_num;
+       u32 chan_time;
+       u32 reserved;
+       union {
+               u8 sdio_func_num;
+               u8 usb_ep_num;
+       } hid_num;
+       u8 intf_num;
+       u8 bss_type_numlist[0];
+} __packed;
+
 struct meas_rpt_map {
        u8 rssi:3;
        u8 unmeasured:1;
index 5d3ae63..de74a77 100644 (file)
@@ -78,6 +78,7 @@ int mwifiex_init_priv(struct mwifiex_private *priv)
        priv->media_connected = false;
        eth_broadcast_addr(priv->curr_addr);
        priv->port_open = false;
+       priv->usb_port = MWIFIEX_USB_EP_DATA;
        priv->pkt_tx_ctrl = 0;
        priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
        priv->data_rate = 0;    /* Initially indicate the rate as auto */
index 278dc94..6e3faa7 100644 (file)
@@ -294,9 +294,15 @@ process_start:
                        /* We have tried to wakeup the card already */
                        if (adapter->pm_wakeup_fw_try)
                                break;
-                       if (adapter->ps_state != PS_STATE_AWAKE ||
-                           adapter->tx_lock_flag)
+                       if (adapter->ps_state != PS_STATE_AWAKE)
                                break;
+                       if (adapter->tx_lock_flag) {
+                               if (adapter->iface_type == MWIFIEX_USB) {
+                                       if (!adapter->usb_mc_setup)
+                                               break;
+                               } else
+                                       break;
+                       }
 
                        if ((!adapter->scan_chan_gap_enabled &&
                             adapter->scan_processing) || adapter->data_sent ||
@@ -345,11 +351,18 @@ process_start:
                 */
                if ((adapter->ps_state == PS_STATE_SLEEP) ||
                    (adapter->ps_state == PS_STATE_PRE_SLEEP) ||
-                   (adapter->ps_state == PS_STATE_SLEEP_CFM) ||
-                   adapter->tx_lock_flag){
+                   (adapter->ps_state == PS_STATE_SLEEP_CFM)) {
                        continue;
                }
 
+               if (adapter->tx_lock_flag) {
+                       if (adapter->iface_type == MWIFIEX_USB) {
+                               if (!adapter->usb_mc_setup)
+                                       continue;
+                       } else
+                               continue;
+               }
+
                if (!adapter->cmd_sent && !adapter->curr_cmd &&
                    mwifiex_is_send_cmd_allowed
                    (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) {
@@ -359,6 +372,13 @@ process_start:
                        }
                }
 
+               /** If USB Multi channel setup ongoing,
+                *  wait for ready to tx data.
+                */
+               if (adapter->iface_type == MWIFIEX_USB &&
+                   adapter->usb_mc_setup)
+                       continue;
+
                if ((adapter->scan_chan_gap_enabled ||
                     !adapter->scan_processing) &&
                    !adapter->data_sent &&
@@ -928,6 +948,32 @@ mwifiex_tx_timeout(struct net_device *dev)
        }
 }
 
+void mwifiex_multi_chan_resync(struct mwifiex_adapter *adapter)
+{
+       struct usb_card_rec *card = adapter->card;
+       struct mwifiex_private *priv;
+       u16 tx_buf_size;
+       int i, ret;
+
+       card->mc_resync_flag = true;
+       for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) {
+               if (atomic_read(&card->port[i].tx_data_urb_pending)) {
+                       mwifiex_dbg(adapter, WARN, "pending data urb in sys\n");
+                       return;
+               }
+       }
+
+       card->mc_resync_flag = false;
+       tx_buf_size = 0xffff;
+       priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
+                              HostCmd_ACT_GEN_SET, 0, &tx_buf_size, false);
+       if (ret)
+               mwifiex_dbg(adapter, ERROR,
+                           "send reconfig tx buf size cmd err\n");
+}
+EXPORT_SYMBOL_GPL(mwifiex_multi_chan_resync);
+
 void mwifiex_drv_info_dump(struct mwifiex_adapter *adapter)
 {
        void *p;
@@ -963,8 +1009,10 @@ void mwifiex_drv_info_dump(struct mwifiex_adapter *adapter)
                cardp = (struct usb_card_rec *)adapter->card;
                p += sprintf(p, "tx_cmd_urb_pending = %d\n",
                             atomic_read(&cardp->tx_cmd_urb_pending));
-               p += sprintf(p, "tx_data_urb_pending = %d\n",
-                            atomic_read(&cardp->tx_data_urb_pending));
+               p += sprintf(p, "tx_data_urb_pending_port_0 = %d\n",
+                            atomic_read(&cardp->port[0].tx_data_urb_pending));
+               p += sprintf(p, "tx_data_urb_pending_port_1 = %d\n",
+                            atomic_read(&cardp->port[1].tx_data_urb_pending));
                p += sprintf(p, "rx_cmd_urb_pending = %d\n",
                             atomic_read(&cardp->rx_cmd_urb_pending));
                p += sprintf(p, "rx_data_urb_pending = %d\n",
@@ -1447,6 +1495,26 @@ exit_sem_err:
 }
 EXPORT_SYMBOL_GPL(mwifiex_remove_card);
 
+void _mwifiex_dbg(const struct mwifiex_adapter *adapter, int mask,
+                 const char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       if (!adapter->dev || !(adapter->debug_mask & mask))
+               return;
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       dev_info(adapter->dev, "%pV", &vaf);
+
+       va_end(args);
+}
+EXPORT_SYMBOL_GPL(_mwifiex_dbg);
+
 /*
  * This function initializes the module.
  *
index 6b95121..3959f1c 100644 (file)
@@ -48,6 +48,9 @@
 
 extern const char driver_version[];
 
+struct mwifiex_adapter;
+struct mwifiex_private;
+
 enum {
        MWIFIEX_ASYNC_CMD,
        MWIFIEX_SYNC_CMD
@@ -180,12 +183,11 @@ enum MWIFIEX_DEBUG_LEVEL {
                                        MWIFIEX_DBG_FATAL | \
                                        MWIFIEX_DBG_ERROR)
 
-#define mwifiex_dbg(adapter, dbg_mask, fmt, args...)           \
-do {                                                           \
-       if ((adapter)->debug_mask & MWIFIEX_DBG_##dbg_mask)     \
-               if ((adapter)->dev)                             \
-                       dev_info((adapter)->dev, fmt, ## args); \
-} while (0)
+__printf(3, 4)
+void _mwifiex_dbg(const struct mwifiex_adapter *adapter, int mask,
+                 const char *fmt, ...);
+#define mwifiex_dbg(adapter, mask, fmt, ...)                           \
+       _mwifiex_dbg(adapter, MWIFIEX_DBG_##mask, fmt, ##__VA_ARGS__)
 
 #define DEBUG_DUMP_DATA_MAX_LEN                128
 #define mwifiex_dbg_dump(adapter, dbg_mask, str, buf, len)     \
@@ -506,9 +508,6 @@ enum mwifiex_iface_work_flags {
        MWIFIEX_IFACE_WORK_CARD_RESET,
 };
 
-struct mwifiex_adapter;
-struct mwifiex_private;
-
 struct mwifiex_private {
        struct mwifiex_adapter *adapter;
        u8 bss_type;
@@ -520,6 +519,7 @@ struct mwifiex_private {
        u8 curr_addr[ETH_ALEN];
        u8 media_connected;
        u8 port_open;
+       u8 usb_port;
        u32 num_tx_timeout;
        /* track consecutive timeout */
        u8 tx_timeout_cnt;
@@ -816,6 +816,8 @@ struct mwifiex_if_ops {
        void (*iface_work)(struct work_struct *work);
        void (*submit_rem_rx_urbs)(struct mwifiex_adapter *adapter);
        void (*deaggr_pkt)(struct mwifiex_adapter *, struct sk_buff *);
+       void (*multi_port_resync)(struct mwifiex_adapter *);
+       bool (*is_port_ready)(struct mwifiex_private *);
 };
 
 struct mwifiex_adapter {
@@ -861,6 +863,8 @@ struct mwifiex_adapter {
        u8 more_task_flag;
        u16 tx_buf_size;
        u16 curr_tx_buf_size;
+       /* sdio single port rx aggregation capability */
+       bool host_disable_sdio_rx_aggr;
        bool sdio_rx_aggr_enable;
        u16 sdio_rx_block_size;
        u32 ioport;
@@ -988,6 +992,8 @@ struct mwifiex_adapter {
        u8 coex_rx_win_size;
        bool drcs_enabled;
        u8 active_scan_triggered;
+       bool usb_mc_status;
+       bool usb_mc_setup;
 };
 
 void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
@@ -1561,6 +1567,7 @@ void mwifiex_process_tx_pause_event(struct mwifiex_private *priv,
                                    struct sk_buff *event);
 void mwifiex_process_multi_chan_event(struct mwifiex_private *priv,
                                      struct sk_buff *event_skb);
+void mwifiex_multi_chan_resync(struct mwifiex_adapter *adapter);
 
 #ifdef CONFIG_DEBUG_FS
 void mwifiex_debugfs_init(void);
index 408b684..21192b6 100644 (file)
@@ -1815,7 +1815,6 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
        if (!card->evt_buf_list[rdptr]) {
                skb_push(skb, INTF_HEADER_LEN);
                skb_put(skb, MAX_EVENT_SIZE - skb->len);
-               memset(skb->data, 0, MAX_EVENT_SIZE);
                if (mwifiex_map_pci_memory(adapter, skb,
                                           MAX_EVENT_SIZE,
                                           PCI_DMA_FROMDEVICE))
index 5847863..c20017c 100644 (file)
@@ -1839,14 +1839,18 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
                                            bssid, timestamp,
                                            cap_info_bitmap, beacon_period,
                                            ie_buf, ie_len, rssi, GFP_KERNEL);
-                       bss_priv = (struct mwifiex_bss_priv *)bss->priv;
-                       bss_priv->band = band;
-                       bss_priv->fw_tsf = fw_tsf;
-                       if (priv->media_connected &&
-                           !memcmp(bssid, priv->curr_bss_params.bss_descriptor
-                                   .mac_address, ETH_ALEN))
-                               mwifiex_update_curr_bss_params(priv, bss);
-                       cfg80211_put_bss(priv->wdev.wiphy, bss);
+                       if (bss) {
+                               bss_priv = (struct mwifiex_bss_priv *)bss->priv;
+                               bss_priv->band = band;
+                               bss_priv->fw_tsf = fw_tsf;
+                               if (priv->media_connected &&
+                                   !memcmp(bssid, priv->curr_bss_params.
+                                           bss_descriptor.mac_address,
+                                           ETH_ALEN))
+                                       mwifiex_update_curr_bss_params(priv,
+                                                                      bss);
+                               cfg80211_put_bss(priv->wdev.wiphy, bss);
+                       }
 
                        if ((chan->flags & IEEE80211_CHAN_RADAR) ||
                            (chan->flags & IEEE80211_CHAN_NO_IR)) {
@@ -1889,7 +1893,7 @@ mwifiex_active_scan_req_for_passive_chan(struct mwifiex_private *priv)
        u8 id = 0;
        struct mwifiex_user_scan_cfg  *user_scan_cfg;
 
-       if (adapter->active_scan_triggered) {
+       if (adapter->active_scan_triggered || !priv->scan_request) {
                adapter->active_scan_triggered = false;
                return 0;
        }
index 5d05c6f..78a8474 100644 (file)
@@ -1606,8 +1606,9 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
                                (rx_len + MWIFIEX_SDIO_BLOCK_SIZE -
                                 1) / MWIFIEX_SDIO_BLOCK_SIZE;
                        if (rx_len <= INTF_HEADER_LEN ||
-                           (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) >
-                            card->mpa_rx.buf_size) {
+                           (card->mpa_rx.enabled &&
+                            ((rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) >
+                             card->mpa_rx.buf_size))) {
                                mwifiex_dbg(adapter, ERROR,
                                            "invalid rx_len=%d\n",
                                            rx_len);
@@ -1925,6 +1926,8 @@ error:
        if (ret) {
                kfree(card->mpa_tx.buf);
                kfree(card->mpa_rx.buf);
+               card->mpa_tx.buf_size = 0;
+               card->mpa_rx.buf_size = 0;
        }
 
        return ret;
@@ -2055,16 +2058,26 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
        ret = mwifiex_alloc_sdio_mpa_buffers(adapter,
                                             card->mp_tx_agg_buf_size,
                                             card->mp_rx_agg_buf_size);
-       if (ret) {
-               mwifiex_dbg(adapter, ERROR,
-                           "failed to alloc sdio mp-a buffers\n");
-               kfree(card->mp_regs);
-               return -1;
+
+       /* Allocate 32k MPA Tx/Rx buffers if 64k memory allocation fails */
+       if (ret && (card->mp_tx_agg_buf_size == MWIFIEX_MP_AGGR_BUF_SIZE_MAX ||
+                   card->mp_rx_agg_buf_size == MWIFIEX_MP_AGGR_BUF_SIZE_MAX)) {
+               /* Disable rx single port aggregation */
+               adapter->host_disable_sdio_rx_aggr = true;
+
+               ret = mwifiex_alloc_sdio_mpa_buffers
+                       (adapter, MWIFIEX_MP_AGGR_BUF_SIZE_32K,
+                        MWIFIEX_MP_AGGR_BUF_SIZE_32K);
+               if (ret) {
+                       /* Disable multi port aggregation */
+                       card->mpa_tx.enabled = 0;
+                       card->mpa_rx.enabled = 0;
+               }
        }
 
        adapter->auto_tdls = card->can_auto_tdls;
        adapter->ext_scan = card->can_ext_scan;
-       return ret;
+       return 0;
 }
 
 /*
index a49a80d..504b321 100644 (file)
@@ -2125,7 +2125,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
 
                /** Set SDIO Single Port RX Aggr Info */
                if (priv->adapter->iface_type == MWIFIEX_SDIO &&
-                   ISSUPP_SDIO_SPA_ENABLED(priv->adapter->fw_cap_info)) {
+                   ISSUPP_SDIO_SPA_ENABLED(priv->adapter->fw_cap_info) &&
+                   !priv->adapter->host_disable_sdio_rx_aggr) {
                        sdio_sp_rx_aggr_enable = true;
                        ret = mwifiex_send_cmd(priv,
                                               HostCmd_CMD_SDIO_SP_RX_AGGR_CFG,
index 87b69d8..d096163 100644 (file)
@@ -1128,6 +1128,17 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
                ret = mwifiex_ret_11n_addba_resp(priv, resp);
                break;
        case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+               if (0xffff == (u16)le16_to_cpu(resp->params.tx_buf.buff_size)) {
+                       if (adapter->iface_type == MWIFIEX_USB &&
+                           adapter->usb_mc_setup) {
+                               if (adapter->if_ops.multi_port_resync)
+                                       adapter->if_ops.
+                                               multi_port_resync(adapter);
+                               adapter->usb_mc_setup = false;
+                               adapter->tx_lock_flag = false;
+                       }
+                       break;
+               }
                adapter->tx_buf_size = (u16) le16_to_cpu(resp->params.
                                                             tx_buf.buff_size);
                adapter->tx_buf_size = (adapter->tx_buf_size
index 3d18c58..ff3ee9d 100644 (file)
@@ -313,24 +313,78 @@ void mwifiex_process_multi_chan_event(struct mwifiex_private *priv,
                                      struct sk_buff *event_skb)
 {
        struct mwifiex_ie_types_multi_chan_info *chan_info;
-       u16 status;
+       struct mwifiex_ie_types_mc_group_info *grp_info;
+       struct mwifiex_adapter *adapter = priv->adapter;
+       struct mwifiex_ie_types_header *tlv;
+       u16 tlv_buf_left, tlv_type, tlv_len;
+       int intf_num, bss_type, bss_num, i;
+       struct mwifiex_private *intf_priv;
 
+       tlv_buf_left = event_skb->len - sizeof(u32);
        chan_info = (void *)event_skb->data + sizeof(u32);
 
-       if (le16_to_cpu(chan_info->header.type) != TLV_TYPE_MULTI_CHAN_INFO) {
-               mwifiex_dbg(priv->adapter, ERROR,
+       if (le16_to_cpu(chan_info->header.type) != TLV_TYPE_MULTI_CHAN_INFO ||
+           tlv_buf_left < sizeof(struct mwifiex_ie_types_multi_chan_info)) {
+               mwifiex_dbg(adapter, ERROR,
                            "unknown TLV in chan_info event\n");
                return;
        }
 
-       status = le16_to_cpu(chan_info->status);
+       adapter->usb_mc_status = le16_to_cpu(chan_info->status);
+       mwifiex_dbg(adapter, EVENT, "multi chan operation %s\n",
+                   adapter->usb_mc_status ? "started" : "over");
 
-       if (status) {
-               mwifiex_dbg(priv->adapter, EVENT,
-                           "multi-channel operation started\n");
-       } else {
-               mwifiex_dbg(priv->adapter, EVENT,
-                           "multi-channel operation over\n");
+       tlv_buf_left -= sizeof(struct mwifiex_ie_types_multi_chan_info);
+       tlv = (struct mwifiex_ie_types_header *)chan_info->tlv_buffer;
+
+       while (tlv_buf_left >= (int)sizeof(struct mwifiex_ie_types_header)) {
+               tlv_type = le16_to_cpu(tlv->type);
+               tlv_len  = le16_to_cpu(tlv->len);
+               if ((sizeof(struct mwifiex_ie_types_header) + tlv_len) >
+                   tlv_buf_left) {
+                       mwifiex_dbg(adapter, ERROR, "wrong tlv: tlvLen=%d,\t"
+                                   "tlvBufLeft=%d\n", tlv_len, tlv_buf_left);
+                       break;
+               }
+               if (tlv_type != TLV_TYPE_MC_GROUP_INFO) {
+                       mwifiex_dbg(adapter, ERROR, "wrong tlv type: 0x%x\n",
+                                   tlv_type);
+                       break;
+               }
+
+               grp_info = (struct mwifiex_ie_types_mc_group_info *)tlv;
+               intf_num = grp_info->intf_num;
+               for (i = 0; i < intf_num; i++) {
+                       bss_type = grp_info->bss_type_numlist[i] >> 4;
+                       bss_num = grp_info->bss_type_numlist[i] & BSS_NUM_MASK;
+                       intf_priv = mwifiex_get_priv_by_id(adapter, bss_num,
+                                                          bss_type);
+                       if (!intf_priv) {
+                               mwifiex_dbg(adapter, ERROR,
+                                           "Invalid bss_type bss_num\t"
+                                           "in multi channel event\n");
+                               continue;
+                       }
+                       if (adapter->iface_type == MWIFIEX_USB) {
+                               u8 ep;
+
+                               ep = grp_info->hid_num.usb_ep_num;
+                               if (ep == MWIFIEX_USB_EP_DATA ||
+                                   ep == MWIFIEX_USB_EP_DATA_CH2)
+                                       intf_priv->usb_port = ep;
+                       }
+               }
+
+               tlv_buf_left -= sizeof(struct mwifiex_ie_types_header) +
+                               tlv_len;
+               tlv = (void *)((u8 *)tlv + tlv_len +
+                              sizeof(struct mwifiex_ie_types_header));
+       }
+
+       if (adapter->iface_type == MWIFIEX_USB) {
+               adapter->tx_lock_flag = true;
+               adapter->usb_mc_setup = true;
+               mwifiex_multi_chan_resync(adapter);
        }
 }
 
@@ -562,7 +616,9 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                adapter->tx_lock_flag = false;
                if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) {
                        if (mwifiex_check_last_packet_indication(priv)) {
-                               if (adapter->data_sent) {
+                               if (adapter->data_sent ||
+                                   (adapter->if_ops.is_port_ready &&
+                                    !adapter->if_ops.is_port_ready(priv))) {
                                        adapter->ps_state = PS_STATE_AWAKE;
                                        adapter->pm_wakeup_card_req = false;
                                        adapter->pm_wakeup_fw_try = false;
index 355ac59..f6683ea 100644 (file)
@@ -153,6 +153,10 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
        if (adapter->data_sent)
                return -1;
 
+       if (adapter->if_ops.is_port_ready &&
+           !adapter->if_ops.is_port_ready(priv))
+               return -1;
+
        skb = dev_alloc_skb(data_len);
        if (!skb)
                return -1;
@@ -174,7 +178,7 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
        local_tx_pd->bss_type = priv->bss_type;
 
        if (adapter->iface_type == MWIFIEX_USB) {
-               ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_USB_EP_DATA,
+               ret = adapter->if_ops.host_to_card(adapter, priv->usb_port,
                                                   skb, NULL);
        } else {
                skb_push(skb, INTF_HEADER_LEN);
@@ -191,7 +195,6 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
                adapter->dbg.num_tx_host_to_card_failure++;
                break;
        case -1:
-               adapter->data_sent = false;
                dev_kfree_skb_any(skb);
                mwifiex_dbg(adapter, ERROR,
                            "%s: host_to_card failed: ret=%d\n",
index b3e163d..9275f9c 100644 (file)
@@ -204,6 +204,12 @@ mwifiex_tdls_add_ht_oper(struct mwifiex_private *priv, const u8 *mac,
                return -1;
        }
 
+       if (!(le16_to_cpu(sta_ptr->tdls_cap.ht_capb.cap_info))) {
+               mwifiex_dbg(priv->adapter, WARN,
+                           "TDLS peer doesn't support ht capabilities\n");
+               return 0;
+       }
+
        pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_operation) + 2);
        *pos++ = WLAN_EID_HT_OPERATION;
        *pos++ = sizeof(struct ieee80211_ht_operation);
@@ -252,6 +258,12 @@ static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv,
                return -1;
        }
 
+       if (!(le32_to_cpu(sta_ptr->tdls_cap.vhtcap.vht_cap_info))) {
+               mwifiex_dbg(adapter, WARN,
+                           "TDLS peer doesn't support vht capabilities\n");
+               return 0;
+       }
+
        if (!mwifiex_is_bss_in_11ac_mode(priv)) {
                if (sta_ptr->tdls_cap.extcap.ext_capab[7] &
                   WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) {
index 8b1e5b5..bf6182b 100644 (file)
@@ -115,9 +115,8 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
                if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
                        local_tx_pd = (struct txpd *)(head_ptr + hroom);
                if (adapter->iface_type == MWIFIEX_USB) {
-                       adapter->data_sent = true;
                        ret = adapter->if_ops.host_to_card(adapter,
-                                                          MWIFIEX_USB_EP_DATA,
+                                                          priv->usb_port,
                                                           skb, NULL);
                } else {
                        ret = adapter->if_ops.host_to_card(adapter,
@@ -130,7 +129,7 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
 
        switch (ret) {
        case -ENOSR:
-               mwifiex_dbg(adapter, ERROR, "data: -ENOSR is returned\n");
+               mwifiex_dbg(adapter, DATA, "data: -ENOSR is returned\n");
                break;
        case -EBUSY:
                if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
@@ -142,8 +141,6 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
                mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
                break;
        case -1:
-               if (adapter->iface_type != MWIFIEX_PCIE)
-                       adapter->data_sent = false;
                mwifiex_dbg(adapter, ERROR,
                            "mwifiex_write_data_async failed: 0x%X\n",
                            ret);
@@ -151,8 +148,6 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
                mwifiex_write_data_complete(adapter, skb, 0, ret);
                break;
        case -EINPROGRESS:
-               if (adapter->iface_type != MWIFIEX_PCIE)
-                       adapter->data_sent = false;
                break;
        case 0:
                mwifiex_write_data_complete(adapter, skb, 0, ret);
@@ -193,9 +188,8 @@ static int mwifiex_host_to_card(struct mwifiex_adapter *adapter,
        }
 
        if (adapter->iface_type == MWIFIEX_USB) {
-               adapter->data_sent = true;
                ret = adapter->if_ops.host_to_card(adapter,
-                                                  MWIFIEX_USB_EP_DATA,
+                                                  priv->usb_port,
                                                   skb, NULL);
        } else {
                ret = adapter->if_ops.host_to_card(adapter,
@@ -222,16 +216,12 @@ static int mwifiex_host_to_card(struct mwifiex_adapter *adapter,
                mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
                break;
        case -1:
-               if (adapter->iface_type != MWIFIEX_PCIE)
-                       adapter->data_sent = false;
                mwifiex_dbg(adapter, ERROR,
                            "mwifiex_write_data_async failed: 0x%X\n", ret);
                adapter->dbg.num_tx_host_to_card_failure++;
                mwifiex_write_data_complete(adapter, skb, 0, ret);
                break;
        case -EINPROGRESS:
-               if (adapter->iface_type != MWIFIEX_PCIE)
-                       adapter->data_sent = false;
                break;
        case 0:
                mwifiex_write_data_complete(adapter, skb, 0, ret);
@@ -306,9 +296,6 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
        if (!priv)
                goto done;
 
-       if (adapter->iface_type == MWIFIEX_USB)
-               adapter->data_sent = false;
-
        mwifiex_set_trans_start(priv->netdev);
        if (!status) {
                priv->stats.tx_packets++;
index 46c972a..078834c 100644 (file)
@@ -269,7 +269,9 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
                adapter->tx_lock_flag = false;
                if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) {
                        if (mwifiex_check_last_packet_indication(priv)) {
-                               if (adapter->data_sent) {
+                               if (adapter->data_sent ||
+                                   (adapter->if_ops.is_port_ready &&
+                                    !adapter->if_ops.is_port_ready(priv))) {
                                        adapter->ps_state = PS_STATE_AWAKE;
                                        adapter->pm_wakeup_card_req = false;
                                        adapter->pm_wakeup_fw_try = false;
index 8766741..74d5d72 100644 (file)
@@ -31,7 +31,8 @@
  */
 static bool
 mwifiex_uap_del_tx_pkts_in_ralist(struct mwifiex_private *priv,
-                                 struct list_head *ra_list_head)
+                                 struct list_head *ra_list_head,
+                                 int tid)
 {
        struct mwifiex_ra_list_tbl *ra_list;
        struct sk_buff *skb, *tmp;
@@ -49,7 +50,10 @@ mwifiex_uap_del_tx_pkts_in_ralist(struct mwifiex_private *priv,
                                __skb_unlink(skb, &ra_list->skb_head);
                                mwifiex_write_data_complete(adapter, skb, 0,
                                                            -1);
-                               atomic_dec(&priv->wmm.tx_pkts_queued);
+                               if (ra_list->tx_paused)
+                                       priv->wmm.pkts_paused[tid]--;
+                               else
+                                       atomic_dec(&priv->wmm.tx_pkts_queued);
                                pkt_deleted = true;
                        }
                        if ((atomic_read(&adapter->pending_bridged_pkts) <=
@@ -77,7 +81,7 @@ static void mwifiex_uap_cleanup_tx_queues(struct mwifiex_private *priv)
                if (priv->del_list_idx == MAX_NUM_TID)
                        priv->del_list_idx = 0;
                ra_list = &priv->wmm.tid_tbl_ptr[priv->del_list_idx].ra_list;
-               if (mwifiex_uap_del_tx_pkts_in_ralist(priv, ra_list)) {
+               if (mwifiex_uap_del_tx_pkts_in_ralist(priv, ra_list, i)) {
                        priv->del_list_idx++;
                        break;
                }
index 5e789b2..9f5356e 100644 (file)
@@ -264,6 +264,8 @@ static void mwifiex_usb_tx_complete(struct urb *urb)
        struct urb_context *context = (struct urb_context *)(urb->context);
        struct mwifiex_adapter *adapter = context->adapter;
        struct usb_card_rec *card = adapter->card;
+       struct usb_tx_data_port *port;
+       int i;
 
        mwifiex_dbg(adapter, INFO,
                    "%s: status: %d\n", __func__, urb->status);
@@ -276,11 +278,22 @@ static void mwifiex_usb_tx_complete(struct urb *urb)
        } else {
                mwifiex_dbg(adapter, DATA,
                            "%s: DATA\n", __func__);
-               atomic_dec(&card->tx_data_urb_pending);
+               for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) {
+                       port = &card->port[i];
+                       if (context->ep == port->tx_data_ep) {
+                               atomic_dec(&port->tx_data_urb_pending);
+                               port->block_status = false;
+                               break;
+                       }
+               }
+               adapter->data_sent = false;
                mwifiex_write_data_complete(adapter, context->skb, 0,
                                            urb->status ? -1 : 0);
        }
 
+       if (card->mc_resync_flag)
+               mwifiex_multi_chan_resync(adapter);
+
        mwifiex_queue_main_work(adapter);
 
        return;
@@ -327,7 +340,8 @@ static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size)
 
 static void mwifiex_usb_free(struct usb_card_rec *card)
 {
-       int i;
+       struct usb_tx_data_port *port;
+       int i, j;
 
        if (atomic_read(&card->rx_cmd_urb_pending) && card->rx_cmd.urb)
                usb_kill_urb(card->rx_cmd.urb);
@@ -345,9 +359,12 @@ static void mwifiex_usb_free(struct usb_card_rec *card)
                card->rx_data_list[i].urb = NULL;
        }
 
-       for (i = 0; i < MWIFIEX_TX_DATA_URB; i++) {
-               usb_free_urb(card->tx_data_list[i].urb);
-               card->tx_data_list[i].urb = NULL;
+       for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) {
+               port = &card->port[i];
+               for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) {
+                       usb_free_urb(port->tx_data_list[j].urb);
+                       port->tx_data_list[j].urb = NULL;
+               }
        }
 
        usb_free_urb(card->tx_cmd.urb);
@@ -437,8 +454,18 @@ static int mwifiex_usb_probe(struct usb_interface *intf,
                        pr_debug("info: bulk OUT: max pkt size: %d, addr: %d\n",
                                 le16_to_cpu(epd->wMaxPacketSize),
                                 epd->bEndpointAddress);
-                       card->tx_data_ep = usb_endpoint_num(epd);
-                       atomic_set(&card->tx_data_urb_pending, 0);
+                       card->port[0].tx_data_ep = usb_endpoint_num(epd);
+                       atomic_set(&card->port[0].tx_data_urb_pending, 0);
+               }
+               if (usb_endpoint_dir_out(epd) &&
+                   usb_endpoint_num(epd) == MWIFIEX_USB_EP_DATA_CH2 &&
+                   usb_endpoint_xfer_bulk(epd)) {
+                       pr_debug("info: bulk OUT chan2:\t"
+                                "max pkt size: %d, addr: %d\n",
+                                le16_to_cpu(epd->wMaxPacketSize),
+                                epd->bEndpointAddress);
+                       card->port[1].tx_data_ep = usb_endpoint_num(epd);
+                       atomic_set(&card->port[1].tx_data_urb_pending, 0);
                }
                if (usb_endpoint_dir_out(epd) &&
                    usb_endpoint_num(epd) == MWIFIEX_USB_EP_CMD_EVENT &&
@@ -480,7 +507,8 @@ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct usb_card_rec *card = usb_get_intfdata(intf);
        struct mwifiex_adapter *adapter;
-       int i;
+       struct usb_tx_data_port *port;
+       int i, j;
 
        if (!card || !card->adapter) {
                pr_err("%s: card or card->adapter is NULL\n", __func__);
@@ -511,9 +539,13 @@ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message)
                        if (card->rx_data_list[i].urb)
                                usb_kill_urb(card->rx_data_list[i].urb);
 
-       for (i = 0; i < MWIFIEX_TX_DATA_URB; i++)
-               if (card->tx_data_list[i].urb)
-                       usb_kill_urb(card->tx_data_list[i].urb);
+       for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) {
+               port = &card->port[i];
+               for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) {
+                       if (port->tx_data_list[j].urb)
+                               usb_kill_urb(port->tx_data_list[j].urb);
+               }
+       }
 
        if (card->tx_cmd.urb)
                usb_kill_urb(card->tx_cmd.urb);
@@ -625,7 +657,8 @@ static struct usb_driver mwifiex_usb_driver = {
 static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter)
 {
        struct usb_card_rec *card = (struct usb_card_rec *)adapter->card;
-       int i;
+       struct usb_tx_data_port *port;
+       int i, j;
 
        card->tx_cmd.adapter = adapter;
        card->tx_cmd.ep = card->tx_cmd_ep;
@@ -637,17 +670,25 @@ static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter)
                return -ENOMEM;
        }
 
-       card->tx_data_ix = 0;
-
-       for (i = 0; i < MWIFIEX_TX_DATA_URB; i++) {
-               card->tx_data_list[i].adapter = adapter;
-               card->tx_data_list[i].ep = card->tx_data_ep;
-
-               card->tx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (!card->tx_data_list[i].urb) {
-                       mwifiex_dbg(adapter, ERROR,
-                                   "tx_data_list[] urb allocation failed\n");
-                       return -ENOMEM;
+       for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) {
+               port = &card->port[i];
+               if (!port->tx_data_ep)
+                       continue;
+               port->tx_data_ix = 0;
+               if (port->tx_data_ep == MWIFIEX_USB_EP_DATA)
+                       port->block_status = false;
+               else
+                       port->block_status = true;
+               for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) {
+                       port->tx_data_list[j].adapter = adapter;
+                       port->tx_data_list[j].ep = port->tx_data_ep;
+                       port->tx_data_list[j].urb =
+                                       usb_alloc_urb(0, GFP_KERNEL);
+                       if (!port->tx_data_list[j].urb) {
+                               mwifiex_dbg(adapter, ERROR,
+                                           "urb allocation failed\n");
+                               return -ENOMEM;
+                       }
                }
        }
 
@@ -736,15 +777,89 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf,
        return ret;
 }
 
+static void mwifiex_usb_port_resync(struct mwifiex_adapter *adapter)
+{
+       struct usb_card_rec *card = adapter->card;
+       u8 active_port = MWIFIEX_USB_EP_DATA;
+       struct mwifiex_private *priv = NULL;
+       int i;
+
+       if (adapter->usb_mc_status) {
+               for (i = 0; i < adapter->priv_num; i++) {
+                       priv = adapter->priv[i];
+                       if (!priv)
+                               continue;
+                       if ((priv->bss_role == MWIFIEX_BSS_ROLE_UAP &&
+                            !priv->bss_started) ||
+                           (priv->bss_role == MWIFIEX_BSS_ROLE_STA &&
+                            !priv->media_connected))
+                               priv->usb_port = MWIFIEX_USB_EP_DATA;
+               }
+               for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++)
+                       card->port[i].block_status = false;
+       } else {
+               for (i = 0; i < adapter->priv_num; i++) {
+                       priv = adapter->priv[i];
+                       if (!priv)
+                               continue;
+                       if ((priv->bss_role == MWIFIEX_BSS_ROLE_UAP &&
+                            priv->bss_started) ||
+                           (priv->bss_role == MWIFIEX_BSS_ROLE_STA &&
+                            priv->media_connected)) {
+                               active_port = priv->usb_port;
+                               break;
+                       }
+               }
+               for (i = 0; i < adapter->priv_num; i++) {
+                       priv = adapter->priv[i];
+                       if (priv)
+                               priv->usb_port = active_port;
+               }
+               for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) {
+                       if (active_port == card->port[i].tx_data_ep)
+                               card->port[i].block_status = false;
+                       else
+                               card->port[i].block_status = true;
+               }
+       }
+}
+
+static bool mwifiex_usb_is_port_ready(struct mwifiex_private *priv)
+{
+       struct usb_card_rec *card = priv->adapter->card;
+       int idx;
+
+       for (idx = 0; idx < MWIFIEX_TX_DATA_PORT; idx++) {
+               if (priv->usb_port == card->port[idx].tx_data_ep)
+                       return !card->port[idx].block_status;
+       }
+
+       return false;
+}
+
+static inline u8 mwifiex_usb_data_sent(struct mwifiex_adapter *adapter)
+{
+       struct usb_card_rec *card = adapter->card;
+       int i;
+
+       for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++)
+               if (!card->port[i].block_status)
+                       return false;
+
+       return true;
+}
+
 /* This function write a command/data packet to card. */
 static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
                                    struct sk_buff *skb,
                                    struct mwifiex_tx_param *tx_param)
 {
        struct usb_card_rec *card = adapter->card;
-       struct urb_context *context;
+       struct urb_context *context = NULL;
+       struct usb_tx_data_port *port = NULL;
        u8 *data = (u8 *)skb->data;
        struct urb *tx_urb;
+       int idx, ret;
 
        if (adapter->is_suspended) {
                mwifiex_dbg(adapter, ERROR,
@@ -757,19 +872,31 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
                return -1;
        }
 
-       if (ep == card->tx_data_ep &&
-           atomic_read(&card->tx_data_urb_pending) >= MWIFIEX_TX_DATA_URB) {
-               return -EBUSY;
-       }
-
        mwifiex_dbg(adapter, INFO, "%s: ep=%d\n", __func__, ep);
 
        if (ep == card->tx_cmd_ep) {
                context = &card->tx_cmd;
        } else {
-               if (card->tx_data_ix >= MWIFIEX_TX_DATA_URB)
-                       card->tx_data_ix = 0;
-               context = &card->tx_data_list[card->tx_data_ix++];
+               for (idx = 0; idx < MWIFIEX_TX_DATA_PORT; idx++) {
+                       if (ep == card->port[idx].tx_data_ep) {
+                               port = &card->port[idx];
+                               if (atomic_read(&port->tx_data_urb_pending)
+                                   >= MWIFIEX_TX_DATA_URB) {
+                                       port->block_status = true;
+                                       ret = -EBUSY;
+                                       goto done;
+                               }
+                               if (port->tx_data_ix >= MWIFIEX_TX_DATA_URB)
+                                       port->tx_data_ix = 0;
+                               context =
+                                       &port->tx_data_list[port->tx_data_ix++];
+                               break;
+                       }
+               }
+               if (!port) {
+                       mwifiex_dbg(adapter, ERROR, "Wrong usb tx data port\n");
+                       return -1;
+               }
        }
 
        context->adapter = adapter;
@@ -786,7 +913,7 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
        if (ep == card->tx_cmd_ep)
                atomic_inc(&card->tx_cmd_urb_pending);
        else
-               atomic_inc(&card->tx_data_urb_pending);
+               atomic_inc(&port->tx_data_urb_pending);
 
        if (usb_submit_urb(tx_urb, GFP_ATOMIC)) {
                mwifiex_dbg(adapter, ERROR,
@@ -794,22 +921,32 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
                if (ep == card->tx_cmd_ep) {
                        atomic_dec(&card->tx_cmd_urb_pending);
                } else {
-                       atomic_dec(&card->tx_data_urb_pending);
-                       if (card->tx_data_ix)
-                               card->tx_data_ix--;
+                       atomic_dec(&port->tx_data_urb_pending);
+                       port->block_status = false;
+                       if (port->tx_data_ix)
+                               port->tx_data_ix--;
                        else
-                               card->tx_data_ix = MWIFIEX_TX_DATA_URB;
+                               port->tx_data_ix = MWIFIEX_TX_DATA_URB;
                }
 
                return -1;
        } else {
-               if (ep == card->tx_data_ep &&
-                   atomic_read(&card->tx_data_urb_pending) ==
-                                                       MWIFIEX_TX_DATA_URB)
-                       return -ENOSR;
+               if (ep != card->tx_cmd_ep &&
+                   atomic_read(&port->tx_data_urb_pending) ==
+                                                       MWIFIEX_TX_DATA_URB) {
+                       port->block_status = true;
+                       ret = -ENOSR;
+                       goto done;
+               }
        }
 
        return -EINPROGRESS;
+
+done:
+       if (ep != card->tx_cmd_ep)
+               adapter->data_sent = mwifiex_usb_data_sent(adapter);
+
+       return ret;
 }
 
 /* This function register usb device and initialize parameter. */
@@ -853,6 +990,9 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
                break;
        }
 
+       adapter->usb_mc_status = false;
+       adapter->usb_mc_setup = false;
+
        return 0;
 }
 
@@ -1082,6 +1222,8 @@ static struct mwifiex_if_ops usb_ops = {
        .event_complete =       mwifiex_usb_cmd_event_complete,
        .host_to_card =         mwifiex_usb_host_to_card,
        .submit_rem_rx_urbs =   mwifiex_usb_submit_rem_rx_urbs,
+       .multi_port_resync =    mwifiex_usb_port_resync,
+       .is_port_ready =        mwifiex_usb_is_port_ready,
 };
 
 /* This function initializes the USB driver module.
index f0051f8..bab10ee 100644 (file)
@@ -40,6 +40,7 @@
 #define USB8XXX_FW_READY       2
 #define USB8XXX_FW_MAX_RETRY   3
 
+#define MWIFIEX_TX_DATA_PORT   2
 #define MWIFIEX_TX_DATA_URB    6
 #define MWIFIEX_RX_DATA_URB    6
 #define MWIFIEX_USB_TIMEOUT    100
@@ -64,6 +65,14 @@ struct urb_context {
        u8 ep;
 };
 
+struct usb_tx_data_port {
+       u8 tx_data_ep;
+       u8 block_status;
+       atomic_t tx_data_urb_pending;
+       int tx_data_ix;
+       struct urb_context tx_data_list[MWIFIEX_TX_DATA_URB];
+};
+
 struct usb_card_rec {
        struct mwifiex_adapter *adapter;
        struct usb_device *udev;
@@ -75,14 +84,12 @@ struct usb_card_rec {
        u8 usb_boot_state;
        u8 rx_data_ep;
        atomic_t rx_data_urb_pending;
-       u8 tx_data_ep;
        u8 tx_cmd_ep;
-       atomic_t tx_data_urb_pending;
        atomic_t tx_cmd_urb_pending;
        int bulk_out_maxpktsize;
        struct urb_context tx_cmd;
-       int tx_data_ix;
-       struct urb_context tx_data_list[MWIFIEX_TX_DATA_URB];
+       u8 mc_resync_flag;
+       struct usb_tx_data_port port[MWIFIEX_TX_DATA_PORT];
 };
 
 struct fw_header {
index 173d366..7bbdfe4 100644 (file)
@@ -160,7 +160,6 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra)
                ra_list->tdls_link = false;
                ra_list->ba_status = BA_SETUP_NONE;
                ra_list->amsdu_in_ampdu = false;
-               ra_list->tx_paused = false;
                if (!mwifiex_queuing_ra_based(priv)) {
                        if (mwifiex_is_tdls_link_setup
                                (mwifiex_get_tdls_link_status(priv, ra))) {
@@ -173,6 +172,8 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra)
                } else {
                        spin_lock_irqsave(&priv->sta_list_spinlock, flags);
                        node = mwifiex_get_sta_entry(priv, ra);
+                       if (node)
+                               ra_list->tx_paused = node->tx_pause;
                        ra_list->is_11n_enabled =
                                      mwifiex_is_sta_11n_enabled(priv, node);
                        if (ra_list->is_11n_enabled)
@@ -451,7 +452,21 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
 
 int mwifiex_bypass_txlist_empty(struct mwifiex_adapter *adapter)
 {
-       return atomic_read(&adapter->bypass_tx_pending) ? false : true;
+       struct mwifiex_private *priv;
+       int i;
+
+       for (i = 0; i < adapter->priv_num; i++) {
+               priv = adapter->priv[i];
+               if (!priv)
+                       continue;
+               if (adapter->if_ops.is_port_ready &&
+                   !adapter->if_ops.is_port_ready(priv))
+                       continue;
+               if (!skb_queue_empty(&priv->bypass_txq))
+                       return false;
+       }
+
+       return true;
 }
 
 /*
@@ -465,9 +480,14 @@ mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter)
 
        for (i = 0; i < adapter->priv_num; ++i) {
                priv = adapter->priv[i];
-               if (priv && !priv->port_open)
+               if (!priv)
+                       continue;
+               if (!priv->port_open)
+                       continue;
+               if (adapter->if_ops.is_port_ready &&
+                   !adapter->if_ops.is_port_ready(priv))
                        continue;
-               if (priv && atomic_read(&priv->wmm.tx_pkts_queued))
+               if (atomic_read(&priv->wmm.tx_pkts_queued))
                        return false;
        }
 
@@ -737,7 +757,11 @@ mwifiex_wmm_del_peer_ra_list(struct mwifiex_private *priv, const u8 *ra_addr)
                if (!ra_list)
                        continue;
                mwifiex_wmm_del_pkts_in_ralist_node(priv, ra_list);
-               atomic_sub(ra_list->total_pkt_count, &priv->wmm.tx_pkts_queued);
+               if (ra_list->tx_paused)
+                       priv->wmm.pkts_paused[i] -= ra_list->total_pkt_count;
+               else
+                       atomic_sub(ra_list->total_pkt_count,
+                                  &priv->wmm.tx_pkts_queued);
                list_del(&ra_list->list);
                kfree(ra_list);
        }
@@ -1086,6 +1110,10 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
                            (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0))
                                continue;
 
+                       if (adapter->if_ops.is_port_ready &&
+                           !adapter->if_ops.is_port_ready(priv_tmp))
+                               continue;
+
                        /* iterate over the WMM queues of the BSS */
                        hqp = &priv_tmp->wmm.highest_queued_prio;
                        for (i = atomic_read(hqp); i >= LOW_PRIO_TID; --i) {
@@ -1321,8 +1349,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
        spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
 
        if (adapter->iface_type == MWIFIEX_USB) {
-               adapter->data_sent = true;
-               ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_USB_EP_DATA,
+               ret = adapter->if_ops.host_to_card(adapter, priv->usb_port,
                                                   skb, NULL);
        } else {
                tx_param.next_pkt_len =
@@ -1351,15 +1378,11 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
                                       ra_list_flags);
                break;
        case -1:
-               if (adapter->iface_type != MWIFIEX_PCIE)
-                       adapter->data_sent = false;
                mwifiex_dbg(adapter, ERROR, "host_to_card failed: %#x\n", ret);
                adapter->dbg.num_tx_host_to_card_failure++;
                mwifiex_write_data_complete(adapter, skb, 0, ret);
                break;
        case -EINPROGRESS:
-               if (adapter->iface_type != MWIFIEX_PCIE)
-                       adapter->data_sent = false;
                break;
        case 0:
                mwifiex_write_data_complete(adapter, skb, 0, ret);
@@ -1467,6 +1490,13 @@ void mwifiex_process_bypass_tx(struct mwifiex_adapter *adapter)
        for (i = 0; i < adapter->priv_num; ++i) {
                priv = adapter->priv[i];
 
+               if (!priv)
+                       continue;
+
+               if (adapter->if_ops.is_port_ready &&
+                   !adapter->if_ops.is_port_ready(priv))
+                       continue;
+
                if (skb_queue_empty(&priv->bypass_txq))
                        continue;
 
index abbf054..50cce42 100644 (file)
@@ -2115,3 +2115,4 @@ MODULE_PARM_DESC(num_rx_desc_param,
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
 MODULE_FIRMWARE(WL18XX_FW_NAME);
+MODULE_FIRMWARE(WL18XX_CONF_FILE_NAME);
index a1b6040..906be6a 100644 (file)
@@ -318,7 +318,7 @@ struct wl1271 {
        bool watchdog_recovery;
 
        /* Reg domain last configuration */
-       u32 reg_ch_conf_last[2];
+       u32 reg_ch_conf_last[2]  __aligned(8);
        /* Reg domain pending configuration */
        u32 reg_ch_conf_pending[2];
 
index a48a743..8cf23a2 100644 (file)
@@ -876,7 +876,6 @@ int ssb_bus_pcibus_register(struct ssb_bus *bus, struct pci_dev *host_pci)
 
        return err;
 }
-EXPORT_SYMBOL(ssb_bus_pcibus_register);
 #endif /* CONFIG_SSB_PCIHOST */
 
 #ifdef CONFIG_SSB_PCMCIAHOST
index b413e01..f03422b 100644 (file)
@@ -147,8 +147,7 @@ error:
        return err;
 }
 
-int ssb_pcmcia_switch_core(struct ssb_bus *bus,
-                          struct ssb_device *dev)
+static int ssb_pcmcia_switch_core(struct ssb_bus *bus, struct ssb_device *dev)
 {
        int err;
 
index b2d36f7..2278e43 100644 (file)
@@ -200,7 +200,7 @@ out:
 }
 
 /* host must be already claimed */
-int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev)
+static int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev)
 {
        u8 coreidx = dev->core_index;
        u32 sbaddr;
index eb507a5..8a2ebc8 100644 (file)
@@ -85,8 +85,6 @@ static inline int ssb_pci_init(struct ssb_bus *bus)
 
 /* pcmcia.c */
 #ifdef CONFIG_SSB_PCMCIAHOST
-extern int ssb_pcmcia_switch_core(struct ssb_bus *bus,
-                                 struct ssb_device *dev);
 extern int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
                                     u8 coreidx);
 extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus,
@@ -98,11 +96,6 @@ extern void ssb_pcmcia_exit(struct ssb_bus *bus);
 extern int ssb_pcmcia_init(struct ssb_bus *bus);
 extern const struct ssb_bus_ops ssb_pcmcia_ops;
 #else /* CONFIG_SSB_PCMCIAHOST */
-static inline int ssb_pcmcia_switch_core(struct ssb_bus *bus,
-                                        struct ssb_device *dev)
-{
-       return 0;
-}
 static inline int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
                                            u8 coreidx)
 {
@@ -132,9 +125,7 @@ extern int ssb_sdio_get_invariants(struct ssb_bus *bus,
                                     struct ssb_init_invariants *iv);
 
 extern u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset);
-extern int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev);
 extern int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx);
-extern int ssb_sdio_hardware_setup(struct ssb_bus *bus);
 extern void ssb_sdio_exit(struct ssb_bus *bus);
 extern int ssb_sdio_init(struct ssb_bus *bus);
 
@@ -144,19 +135,10 @@ static inline u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset)
 {
        return 0;
 }
-static inline int ssb_sdio_switch_core(struct ssb_bus *bus,
-                                        struct ssb_device *dev)
-{
-       return 0;
-}
 static inline int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
 {
        return 0;
 }
-static inline int ssb_sdio_hardware_setup(struct ssb_bus *bus)
-{
-       return 0;
-}
 static inline void ssb_sdio_exit(struct ssb_bus *bus)
 {
 }
index 2ff4a99..3feb1b2 100644 (file)
@@ -151,6 +151,8 @@ struct bcma_host_ops {
 #define BCMA_CORE_PCIE2                        0x83C   /* PCI Express Gen2 */
 #define BCMA_CORE_USB30_DEV            0x83D
 #define BCMA_CORE_ARM_CR4              0x83E
+#define BCMA_CORE_ARM_CA7              0x847
+#define BCMA_CORE_SYS_MEM              0x849
 #define BCMA_CORE_DEFAULT              0xFFF
 
 #define BCMA_MAX_NR_CORES              16