UPSTREAM: mwifiex: backport some 3.5 patches to 3.4
authorBing Zhao <bzhao@marvell.com>
Tue, 29 May 2012 18:41:54 +0000 (11:41 -0700)
committerOlof Johansson <olofj@chromium.org>
Wed, 20 Jun 2012 19:07:59 +0000 (12:07 -0700)
A collection of mwifiex patches since tag 'v3.4'

All following patches are available at the upstream git tree (for 3.5):
(internal tag: m20120416-3.4rc3)

b5abcf0219263f4e961dca71cbe26e06c5b0ee68 mwifiex: corrections in timestamp related code
9558a407dd00f6cd7f93b923768e8ee255fa4444 mwifiex: code cleanup in BSS handling
428ca8a7065354877db63ceabfc493107686eebe mwifiex: update pcie8766 scratch register addresses
59a4cc2539076f868f2a3fcd7a3385a26928a27a mwifiex: use asynchronous firmware loading
13d7ba78b514d8b720a82b9bddaaee0c004f2a1f mwifiex: add support for WPS2.0
5e218b7ab86ed6eb3d1432146c49cbb8733414d0 mwifiex: display correct country information in debugfs "info"
9e04a7c6d45fd70be55fcb48ec49f55dad9928f7 mwifiex: set default regulatory domain
d35ccaa4768ee39f7bb3c23394703d1da587c731 mwifiex: fix typo in RSSI_HIGH event handling
4fb25c5914e0c79e236a327833af7f581225f790 wireless, mwifiex: drop redundant NULL test before call to release_firmware()
da951c2417ec1020d0d00813da36f38e395994e9 wireless: Remove unnecessary ; from while (0) macros
99fec5dee8f717daf2b1789e8ac5913863c6dee8 mwifiex: don't use IEEE80211_MAX_QUEUES
fa444bf88ce2ba17d24dd0bb279e3106acf86bed mwifiex: add set_cqm_rssi_config handler support
7013d3e267ef41b3dfdfedbbe6c3d3e666f0f138 mwifiex: support STATION_INFO_SIGNAL_AVG
958a4a862f41eee27091b726de7ffa08c8488ce9 mwifiex: remove redundant signal handling code
f85aae6bec67075b6f19f14adfced6f1eb9061b9 mwifiex: add cfg80211 dump_station handler
c9919be642252baae7a80cacff52a3ed586b0547 mwifiex: update signal strength in mBm units

Signed-off-by: Bing Zhao <bzhao@marvell.com>
BUG=chrome-os-partner:9887, chrome-os-partner:8923
TEST=iw mlan0 scan reports reasonable data

Change-Id: Ie6bfb097a4204a84f0880b76a67aeeb008f57b05
Reviewed-on: https://gerrit-int.chromium.org/18798
Tested-by: Sam Leffler <sleffler@google.com>
Reviewed-by: Doug Anderson <dianders@google.com>
Commit-Ready: Sam Leffler <sleffler@google.com>

17 files changed:
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/cfp.c
drivers/net/wireless/mwifiex/debugfs.c
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/ioctl.h
drivers/net/wireless/mwifiex/join.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/sdio.h
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_ioctl.c

index 6505038..c78ea87 100644 (file)
@@ -516,25 +516,23 @@ static int
 mwifiex_dump_station_info(struct mwifiex_private *priv,
                          struct station_info *sinfo)
 {
-       struct mwifiex_ds_get_signal signal;
        struct mwifiex_rate_cfg rate;
-       int ret = 0;
 
        sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES |
-               STATION_INFO_RX_PACKETS |
-               STATION_INFO_TX_PACKETS
-               | STATION_INFO_SIGNAL | STATION_INFO_TX_BITRATE;
+                       STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS |
+                       STATION_INFO_TX_BITRATE |
+                       STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG;
 
        /* Get signal information from the firmware */
-       memset(&signal, 0, sizeof(struct mwifiex_ds_get_signal));
-       if (mwifiex_get_signal_info(priv, &signal)) {
-               dev_err(priv->adapter->dev, "getting signal information\n");
-               ret = -EFAULT;
+       if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_RSSI_INFO,
+                                 HostCmd_ACT_GEN_GET, 0, NULL)) {
+               dev_err(priv->adapter->dev, "failed to get signal information\n");
+               return -EFAULT;
        }
 
        if (mwifiex_drv_get_data_rate(priv, &rate)) {
                dev_err(priv->adapter->dev, "getting data rate\n");
-               ret = -EFAULT;
+               return -EFAULT;
        }
 
        /* Get DTIM period information from firmware */
@@ -557,11 +555,12 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
                        sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
        }
 
+       sinfo->signal_avg = priv->bcn_rssi_avg;
        sinfo->rx_bytes = priv->stats.rx_bytes;
        sinfo->tx_bytes = priv->stats.tx_bytes;
        sinfo->rx_packets = priv->stats.rx_packets;
        sinfo->tx_packets = priv->stats.tx_packets;
-       sinfo->signal = priv->qual_level;
+       sinfo->signal = priv->bcn_rssi_avg;
        /* bit rate is in 500 kb/s units. Convert it to 100kb/s units */
        sinfo->txrate.legacy = rate.rate * 5;
 
@@ -581,7 +580,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
                        priv->curr_bss_params.bss_descriptor.beacon_period;
        }
 
-       return ret;
+       return 0;
 }
 
 /*
@@ -604,6 +603,23 @@ mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
        return mwifiex_dump_station_info(priv, sinfo);
 }
 
+/*
+ * CFG802.11 operation handler to dump station information.
+ */
+static int
+mwifiex_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
+                             int idx, u8 *mac, struct station_info *sinfo)
+{
+       struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+       if (!priv->media_connected || idx)
+               return -ENOENT;
+
+       memcpy(mac, priv->cfg_bssid, ETH_ALEN);
+
+       return mwifiex_dump_station_info(priv, sinfo);
+}
+
 /* Supported rates to be advertised to the cfg80211 */
 
 static struct ieee80211_rate mwifiex_rates[] = {
@@ -749,6 +765,45 @@ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
        return 0;
 }
 
+/*
+ * CFG802.11 operation handler for connection quality monitoring.
+ *
+ * This function subscribes/unsubscribes HIGH_RSSI and LOW_RSSI
+ * events to FW.
+ */
+static int mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
+                                               struct net_device *dev,
+                                               s32 rssi_thold, u32 rssi_hyst)
+{
+       struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+       struct mwifiex_ds_misc_subsc_evt subsc_evt;
+
+       priv->cqm_rssi_thold = rssi_thold;
+       priv->cqm_rssi_hyst = rssi_hyst;
+
+       memset(&subsc_evt, 0x00, sizeof(struct mwifiex_ds_misc_subsc_evt));
+       subsc_evt.events = BITMASK_BCN_RSSI_LOW | BITMASK_BCN_RSSI_HIGH;
+
+       /* Subscribe/unsubscribe low and high rssi events */
+       if (rssi_thold && rssi_hyst) {
+               subsc_evt.action = HostCmd_ACT_BITWISE_SET;
+               subsc_evt.bcn_l_rssi_cfg.abs_value = abs(rssi_thold);
+               subsc_evt.bcn_h_rssi_cfg.abs_value = abs(rssi_thold);
+               subsc_evt.bcn_l_rssi_cfg.evt_freq = 1;
+               subsc_evt.bcn_h_rssi_cfg.evt_freq = 1;
+               return mwifiex_send_cmd_sync(priv,
+                                            HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
+                                            0, 0, &subsc_evt);
+       } else {
+               subsc_evt.action = HostCmd_ACT_BITWISE_CLR;
+               return mwifiex_send_cmd_sync(priv,
+                                            HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
+                                            0, 0, &subsc_evt);
+       }
+
+       return 0;
+}
+
 /*
  * CFG802.11 operation handler for disconnection request.
  *
@@ -1107,6 +1162,17 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
        priv->user_scan_cfg->num_ssids = request->n_ssids;
        priv->user_scan_cfg->ssid_list = request->ssids;
 
+       if (request->ie && request->ie_len) {
+               for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) {
+                       if (priv->vs_ie[i].mask != MWIFIEX_VSIE_MASK_CLEAR)
+                               continue;
+                       priv->vs_ie[i].mask = MWIFIEX_VSIE_MASK_SCAN;
+                       memcpy(&priv->vs_ie[i].ie, request->ie,
+                              request->ie_len);
+                       break;
+               }
+       }
+
        for (i = 0; i < request->n_channels; i++) {
                chan = request->channels[i];
                priv->user_scan_cfg->chan_list[i].chan_number = chan->hw_value;
@@ -1124,6 +1190,15 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
        if (mwifiex_set_user_scan_ioctl(priv, priv->user_scan_cfg))
                return -EFAULT;
 
+       if (request->ie && request->ie_len) {
+               for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) {
+                       if (priv->vs_ie[i].mask == MWIFIEX_VSIE_MASK_SCAN) {
+                               priv->vs_ie[i].mask = MWIFIEX_VSIE_MASK_CLEAR;
+                               memset(&priv->vs_ie[i].ie, 0,
+                                      MWIFIEX_MAX_VSIE_LEN);
+                       }
+               }
+       }
        return 0;
 }
 
@@ -1340,6 +1415,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
        .connect = mwifiex_cfg80211_connect,
        .disconnect = mwifiex_cfg80211_disconnect,
        .get_station = mwifiex_cfg80211_get_station,
+       .dump_station = mwifiex_cfg80211_dump_station,
        .set_wiphy_params = mwifiex_cfg80211_set_wiphy_params,
        .set_channel = mwifiex_cfg80211_set_channel,
        .join_ibss = mwifiex_cfg80211_join_ibss,
@@ -1350,6 +1426,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
        .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt,
        .set_tx_power = mwifiex_cfg80211_set_tx_power,
        .set_bitrate_mask = mwifiex_cfg80211_set_bitrate_mask,
+       .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config,
 };
 
 /*
@@ -1365,6 +1442,7 @@ int mwifiex_register_cfg80211(struct mwifiex_private *priv)
        void *wdev_priv;
        struct wireless_dev *wdev;
        struct ieee80211_sta_ht_cap *ht_info;
+       u8 *country_code;
 
        wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
        if (!wdev) {
@@ -1381,6 +1459,7 @@ int mwifiex_register_cfg80211(struct mwifiex_private *priv)
        }
        wdev->iftype = NL80211_IFTYPE_STATION;
        wdev->wiphy->max_scan_ssids = 10;
+       wdev->wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN;
        wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                                       BIT(NL80211_IFTYPE_ADHOC);
 
@@ -1403,8 +1482,8 @@ int mwifiex_register_cfg80211(struct mwifiex_private *priv)
        memcpy(wdev->wiphy->perm_addr, priv->curr_addr, ETH_ALEN);
        wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
 
-       /* Reserve space for bss band information */
-       wdev->wiphy->bss_priv_size = sizeof(u8);
+       /* Reserve space for mwifiex specific private data for BSS */
+       wdev->wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);
 
        wdev->wiphy->reg_notifier = mwifiex_reg_notifier;
 
@@ -1427,6 +1506,11 @@ int mwifiex_register_cfg80211(struct mwifiex_private *priv)
                        "info: successfully registered wiphy device\n");
        }
 
+       country_code = mwifiex_11d_code_2_region(priv->adapter->region_code);
+       if (country_code && regulatory_hint(wdev->wiphy, country_code))
+               dev_err(priv->adapter->dev,
+                       "%s: regulatory_hint failed\n", __func__);
+
        priv->wdev = wdev;
 
        return ret;
index 2fe1c33..560871b 100644 (file)
@@ -71,6 +71,37 @@ u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30,
 
 static u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
 
+struct region_code_mapping {
+       u8 code;
+       u8 region[IEEE80211_COUNTRY_STRING_LEN];
+};
+
+static struct region_code_mapping region_code_mapping_t[] = {
+       { 0x10, "US " }, /* US FCC */
+       { 0x20, "CA " }, /* IC Canada */
+       { 0x30, "EU " }, /* ETSI */
+       { 0x31, "ES " }, /* Spain */
+       { 0x32, "FR " }, /* France */
+       { 0x40, "JP " }, /* Japan */
+       { 0x41, "JP " }, /* Japan */
+       { 0x50, "CN " }, /* China */
+};
+
+/* This function converts integer code to region string */
+u8 *mwifiex_11d_code_2_region(u8 code)
+{
+       u8 i;
+       u8 size = sizeof(region_code_mapping_t)/
+                               sizeof(struct region_code_mapping);
+
+       /* Look for code in mapping table */
+       for (i = 0; i < size; i++)
+               if (region_code_mapping_t[i].code == code)
+                       return region_code_mapping_t[i].region;
+
+       return NULL;
+}
+
 /*
  * This function maps an index in supported rates table into
  * the corresponding data rate.
index 1a84507..a870b58 100644 (file)
@@ -212,7 +212,7 @@ mwifiex_info_read(struct file *file, char __user *ubuf,
                p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid);
                p += sprintf(p, "bssid=\"%pM\"\n", info.bssid);
                p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
-               p += sprintf(p, "region_code = \"%02x\"\n", info.region_code);
+               p += sprintf(p, "country_code = \"%s\"\n", info.country_code);
 
                netdev_for_each_mc_addr(ha, netdev)
                        p += sprintf(p, "multicast_address[%d]=\"%pM\"\n",
index e98fc5a..f42da1e 100644 (file)
@@ -92,16 +92,19 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define TLV_TYPE_KEY_MATERIAL       (PROPRIETARY_TLV_BASE_ID + 0)
 #define TLV_TYPE_CHANLIST           (PROPRIETARY_TLV_BASE_ID + 1)
 #define TLV_TYPE_NUMPROBES          (PROPRIETARY_TLV_BASE_ID + 2)
+#define TLV_TYPE_RSSI_LOW           (PROPRIETARY_TLV_BASE_ID + 4)
 #define TLV_TYPE_PASSTHROUGH        (PROPRIETARY_TLV_BASE_ID + 10)
 #define TLV_TYPE_WMMQSTATUS         (PROPRIETARY_TLV_BASE_ID + 16)
 #define TLV_TYPE_WILDCARDSSID       (PROPRIETARY_TLV_BASE_ID + 18)
 #define TLV_TYPE_TSFTIMESTAMP       (PROPRIETARY_TLV_BASE_ID + 19)
+#define TLV_TYPE_RSSI_HIGH          (PROPRIETARY_TLV_BASE_ID + 22)
 #define TLV_TYPE_AUTH_TYPE          (PROPRIETARY_TLV_BASE_ID + 31)
 #define TLV_TYPE_CHANNELBANDLIST    (PROPRIETARY_TLV_BASE_ID + 42)
 #define TLV_TYPE_RATE_DROP_CONTROL  (PROPRIETARY_TLV_BASE_ID + 82)
 #define TLV_TYPE_RATE_SCOPE         (PROPRIETARY_TLV_BASE_ID + 83)
 #define TLV_TYPE_POWER_GROUP        (PROPRIETARY_TLV_BASE_ID + 84)
 #define TLV_TYPE_WAPI_IE            (PROPRIETARY_TLV_BASE_ID + 94)
+#define TLV_TYPE_MGMT_IE            (PROPRIETARY_TLV_BASE_ID + 105)
 #define TLV_TYPE_AUTO_DS_PARAM      (PROPRIETARY_TLV_BASE_ID + 113)
 #define TLV_TYPE_PS_PARAM           (PROPRIETARY_TLV_BASE_ID + 114)
 
@@ -194,6 +197,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define HostCmd_CMD_802_11_KEY_MATERIAL               0x005e
 #define HostCmd_CMD_802_11_BG_SCAN_QUERY              0x006c
 #define HostCmd_CMD_WMM_GET_STATUS                    0x0071
+#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT            0x0075
 #define HostCmd_CMD_802_11_TX_RATE_QUERY              0x007f
 #define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS     0x0083
 #define HostCmd_CMD_VERSION_EXT                       0x0097
@@ -228,6 +232,8 @@ enum ENH_PS_MODES {
 #define HostCmd_RET_BIT                       0x8000
 #define HostCmd_ACT_GEN_GET                   0x0000
 #define HostCmd_ACT_GEN_SET                   0x0001
+#define HostCmd_ACT_BITWISE_SET               0x0002
+#define HostCmd_ACT_BITWISE_CLR               0x0003
 #define HostCmd_RESULT_OK                     0x0000
 
 #define HostCmd_ACT_MAC_RX_ON                 0x0001
@@ -813,7 +819,7 @@ struct host_cmd_ds_txpwr_cfg {
 struct mwifiex_bcn_param {
        u8 bssid[ETH_ALEN];
        u8 rssi;
-       __le32 timestamp[2];
+       __le64 timestamp;
        __le16 beacon_period;
        __le16 cap_info_bitmap;
 } __packed;
@@ -1007,7 +1013,7 @@ struct ieee_types_wmm_parameter {
        struct ieee_types_vendor_header vend_hdr;
        u8 qos_info_bitmap;
        u8 reserved;
-       struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_MAX_QUEUES];
+       struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_NUM_ACS];
 } __packed;
 
 struct ieee_types_wmm_info {
@@ -1028,7 +1034,7 @@ struct ieee_types_wmm_info {
 
 struct host_cmd_ds_wmm_get_status {
        u8 queue_status_tlv[sizeof(struct mwifiex_ie_types_wmm_queue_status) *
-                             IEEE80211_MAX_QUEUES];
+                             IEEE80211_NUM_ACS];
        u8 wmm_param_tlv[sizeof(struct ieee_types_wmm_parameter) + 2];
 } __packed;
 
@@ -1146,6 +1152,17 @@ struct host_cmd_ds_pcie_details {
        u32 sleep_cookie_addr_hi;
 } __packed;
 
+struct mwifiex_ie_types_rssi_threshold {
+       struct mwifiex_ie_types_header header;
+       u8 abs_value;
+       u8 evt_freq;
+} __packed;
+
+struct host_cmd_ds_802_11_subsc_evt {
+       __le16 action;
+       __le16 events;
+} __packed;
+
 struct host_cmd_ds_command {
        __le16 command;
        __le16 size;
@@ -1195,6 +1212,7 @@ struct host_cmd_ds_command {
                struct host_cmd_ds_set_bss_mode bss_mode;
                struct host_cmd_ds_pcie_details pcie_host_spec;
                struct host_cmd_ds_802_11_eeprom_access eeprom;
+               struct host_cmd_ds_802_11_subsc_evt subsc_evt;
        } params;
 } __packed;
 
index 54bb483..0d55c5b 100644 (file)
@@ -131,6 +131,8 @@ static int mwifiex_init_priv(struct mwifiex_private *priv)
        priv->wmm_qosinfo = 0;
        priv->curr_bcn_buf = NULL;
        priv->curr_bcn_size = 0;
+       priv->wps_ie = NULL;
+       priv->wps_ie_len = 0;
 
        priv->scan_block = false;
 
index 7ca4e82..f0f9552 100644 (file)
@@ -85,34 +85,6 @@ struct mwifiex_ds_get_stats {
        u32 wep_icv_error[4];
 };
 
-#define BCN_RSSI_AVG_MASK               0x00000002
-#define BCN_NF_AVG_MASK                 0x00000200
-#define ALL_RSSI_INFO_MASK              0x00000fff
-
-struct mwifiex_ds_get_signal {
-       /*
-        * Bit0:  Last Beacon RSSI,  Bit1:  Average Beacon RSSI,
-        * Bit2:  Last Data RSSI,    Bit3:  Average Data RSSI,
-        * Bit4:  Last Beacon SNR,   Bit5:  Average Beacon SNR,
-        * Bit6:  Last Data SNR,     Bit7:  Average Data SNR,
-        * Bit8:  Last Beacon NF,    Bit9:  Average Beacon NF,
-        * Bit10: Last Data NF,      Bit11: Average Data NF
-        */
-       u16 selector;
-       s16 bcn_rssi_last;
-       s16 bcn_rssi_avg;
-       s16 data_rssi_last;
-       s16 data_rssi_avg;
-       s16 bcn_snr_last;
-       s16 bcn_snr_avg;
-       s16 data_snr_last;
-       s16 data_snr_avg;
-       s16 bcn_nf_last;
-       s16 bcn_nf_avg;
-       s16 data_nf_last;
-       s16 data_nf_avg;
-};
-
 #define MWIFIEX_MAX_VER_STR_LEN    128
 
 struct mwifiex_ver_ext {
@@ -124,7 +96,7 @@ struct mwifiex_bss_info {
        u32 bss_mode;
        struct cfg80211_ssid ssid;
        u32 bss_chan;
-       u32 region_code;
+       u8 country_code[3];
        u32 media_connected;
        u32 max_power_level;
        u32 min_power_level;
@@ -308,8 +280,30 @@ struct mwifiex_ds_misc_cmd {
        u8 cmd[MWIFIEX_SIZE_OF_CMD_BUFFER];
 };
 
+#define BITMASK_BCN_RSSI_LOW   BIT(0)
+#define BITMASK_BCN_RSSI_HIGH  BIT(4)
+
+enum subsc_evt_rssi_state {
+       EVENT_HANDLED,
+       RSSI_LOW_RECVD,
+       RSSI_HIGH_RECVD
+};
+
+struct subsc_evt_cfg {
+       u8 abs_value;
+       u8 evt_freq;
+};
+
+struct mwifiex_ds_misc_subsc_evt {
+       u16 action;
+       u16 events;
+       struct subsc_evt_cfg bcn_l_rssi_cfg;
+       struct subsc_evt_cfg bcn_h_rssi_cfg;
+};
+
 #define MWIFIEX_MAX_VSIE_LEN       (256)
 #define MWIFIEX_MAX_VSIE_NUM       (8)
+#define MWIFIEX_VSIE_MASK_CLEAR    0x00
 #define MWIFIEX_VSIE_MASK_SCAN     0x01
 #define MWIFIEX_VSIE_MASK_ASSOC    0x02
 #define MWIFIEX_VSIE_MASK_ADHOC    0x04
index 8f9382b..c1ac42b 100644 (file)
@@ -118,15 +118,15 @@ mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer,
        *buffer += sizeof(tsf_tlv.header);
 
        /* TSF at the time when beacon/probe_response was received */
-       tsf_val = cpu_to_le64(bss_desc->network_tsf);
+       tsf_val = cpu_to_le64(bss_desc->fw_tsf);
        memcpy(*buffer, &tsf_val, sizeof(tsf_val));
        *buffer += sizeof(tsf_val);
 
-       memcpy(&tsf_val, bss_desc->time_stamp, sizeof(tsf_val));
+       tsf_val = cpu_to_le64(bss_desc->timestamp);
 
        dev_dbg(priv->adapter->dev,
                "info: %s: TSF offset calc: %016llx - %016llx\n",
-               __func__, tsf_val, bss_desc->network_tsf);
+               __func__, bss_desc->timestamp, bss_desc->fw_tsf);
 
        memcpy(*buffer, &tsf_val, sizeof(tsf_val));
        *buffer += sizeof(tsf_val);
@@ -224,6 +224,48 @@ mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv,
        return 0;
 }
 
+/*
+ * This function appends a WPS IE. It is called from the network join command
+ * preparation routine.
+ *
+ * If the IE buffer has been setup by the application, this routine appends
+ * the buffer as a WPS TLV type to the request.
+ */
+static int
+mwifiex_cmd_append_wps_ie(struct mwifiex_private *priv, u8 **buffer)
+{
+       int retLen = 0;
+       struct mwifiex_ie_types_header ie_header;
+
+       if (!buffer || !*buffer)
+               return 0;
+
+       /*
+        * If there is a wps ie buffer setup, append it to the return
+        * parameter buffer pointer.
+        */
+       if (priv->wps_ie_len) {
+               dev_dbg(priv->adapter->dev, "cmd: append wps ie %d to %p\n",
+                       priv->wps_ie_len, *buffer);
+
+               /* Wrap the generic IE buffer with a pass through TLV type */
+               ie_header.type = cpu_to_le16(TLV_TYPE_MGMT_IE);
+               ie_header.len = cpu_to_le16(priv->wps_ie_len);
+               memcpy(*buffer, &ie_header, sizeof(ie_header));
+               *buffer += sizeof(ie_header);
+               retLen += sizeof(ie_header);
+
+               memcpy(*buffer, priv->wps_ie, priv->wps_ie_len);
+               *buffer += priv->wps_ie_len;
+               retLen += priv->wps_ie_len;
+
+       }
+
+       kfree(priv->wps_ie);
+       priv->wps_ie_len = 0;
+       return retLen;
+}
+
 /*
  * This function appends a WAPI IE.
  *
@@ -480,6 +522,8 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
        if (priv->sec_info.wapi_enabled && priv->wapi_ie_len)
                mwifiex_cmd_append_wapi_ie(priv, &pos);
 
+       if (priv->wps.session_enable && priv->wps_ie_len)
+               mwifiex_cmd_append_wps_ie(priv, &pos);
 
        mwifiex_cmd_append_generic_ie(priv, &pos);
 
index 9d1b3ca..245b732 100644 (file)
@@ -292,29 +292,28 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter)
 }
 
 /*
- * This function initializes the hardware and firmware.
+ * This function gets firmware and initializes it.
  *
  * The main initialization steps followed are -
  *      - Download the correct firmware to card
- *      - Allocate and initialize the adapter structure
- *      - Initialize the private structures
  *      - Issue the init commands to firmware
  */
-static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
+static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
 {
-       int ret, err;
+       int ret;
+       char fmt[64];
+       struct mwifiex_private *priv;
+       struct mwifiex_adapter *adapter = context;
        struct mwifiex_fw_image fw;
 
-       memset(&fw, 0, sizeof(struct mwifiex_fw_image));
-
-       err = request_firmware(&adapter->firmware, adapter->fw_name,
-                              adapter->dev);
-       if (err < 0) {
-               dev_err(adapter->dev, "request_firmware() returned"
-                               " error code %#x\n", err);
-               ret = -1;
+       if (!firmware) {
+               dev_err(adapter->dev,
+                       "Failed to get firmware %s\n", adapter->fw_name);
                goto done;
        }
+
+       memset(&fw, 0, sizeof(struct mwifiex_fw_image));
+       adapter->firmware = firmware;
        fw.fw_buf = (u8 *) adapter->firmware->data;
        fw.fw_len = adapter->firmware->size;
 
@@ -335,17 +334,54 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
        /* Wait for mwifiex_init to complete */
        wait_event_interruptible(adapter->init_wait_q,
                                 adapter->init_wait_q_woken);
-       if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) {
-               ret = -1;
+       if (adapter->hw_status != MWIFIEX_HW_STATUS_READY)
                goto done;
+
+       priv = adapter->priv[0];
+       if (mwifiex_register_cfg80211(priv) != 0) {
+               dev_err(adapter->dev, "cannot register with cfg80211\n");
+               goto err_init_fw;
+       }
+
+       rtnl_lock();
+       /* Create station interface by default */
+       if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d",
+                                     NL80211_IFTYPE_STATION, NULL, NULL)) {
+               dev_err(adapter->dev, "cannot create default STA interface\n");
+               goto err_add_intf;
        }
-       ret = 0;
+       rtnl_unlock();
+
+       mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
+       dev_notice(adapter->dev, "driver_version = %s\n", fmt);
+       goto done;
 
+err_add_intf:
+       mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev);
+       rtnl_unlock();
+err_init_fw:
+       pr_debug("info: %s: unregister device\n", __func__);
+       adapter->if_ops.unregister_dev(adapter);
 done:
-       if (adapter->firmware)
-               release_firmware(adapter->firmware);
-       if (ret)
-               ret = -1;
+       release_firmware(adapter->firmware);
+       complete(&adapter->fw_load);
+       return;
+}
+
+/*
+ * This function initializes the hardware and gets firmware.
+ */
+static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
+{
+       int ret;
+
+       init_completion(&adapter->fw_load);
+       ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name,
+                                     adapter->dev, GFP_KERNEL, adapter,
+                                     mwifiex_fw_dpc);
+       if (ret < 0)
+               dev_err(adapter->dev,
+                       "request_firmware_nowait() returned error %d\n", ret);
        return ret;
 }
 
@@ -650,8 +686,6 @@ mwifiex_add_card(void *card, struct semaphore *sem,
                 struct mwifiex_if_ops *if_ops, u8 iface_type)
 {
        struct mwifiex_adapter *adapter;
-       char fmt[64];
-       struct mwifiex_private *priv;
 
        if (down_interruptible(sem))
                goto exit_sem_err;
@@ -692,37 +726,9 @@ mwifiex_add_card(void *card, struct semaphore *sem,
                goto err_init_fw;
        }
 
-       priv = adapter->priv[0];
-
-       if (mwifiex_register_cfg80211(priv) != 0) {
-               dev_err(adapter->dev, "cannot register netdevice"
-                              " with cfg80211\n");
-                       goto err_init_fw;
-       }
-
-       rtnl_lock();
-       /* Create station interface by default */
-       if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d",
-                                     NL80211_IFTYPE_STATION, NULL, NULL)) {
-               rtnl_unlock();
-               dev_err(adapter->dev, "cannot create default station"
-                               " interface\n");
-               goto err_add_intf;
-       }
-
-       rtnl_unlock();
-
        up(sem);
-
-       mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
-       dev_notice(adapter->dev, "driver_version = %s\n", fmt);
-
        return 0;
 
-err_add_intf:
-       rtnl_lock();
-       mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev);
-       rtnl_unlock();
 err_init_fw:
        pr_debug("info: %s: unregister device\n", __func__);
        adapter->if_ops.unregister_dev(adapter);
index 35225e9..7411b7d 100644 (file)
@@ -201,10 +201,10 @@ struct mwifiex_wmm_desc {
        u32 packets_out[MAX_NUM_TID];
        /* spin lock to protect ra_list */
        spinlock_t ra_list_spinlock;
-       struct mwifiex_wmm_ac_status ac_status[IEEE80211_MAX_QUEUES];
-       enum mwifiex_wmm_ac_e ac_down_graded_vals[IEEE80211_MAX_QUEUES];
+       struct mwifiex_wmm_ac_status ac_status[IEEE80211_NUM_ACS];
+       enum mwifiex_wmm_ac_e ac_down_graded_vals[IEEE80211_NUM_ACS];
        u32 drv_pkt_delay_max;
-       u8 queue_priority[IEEE80211_MAX_QUEUES];
+       u8 queue_priority[IEEE80211_NUM_ACS];
        u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1];     /* UP: 0 to 7 */
        /* Number of transmit packets queued */
        atomic_t tx_pkts_queued;
@@ -260,8 +260,8 @@ struct mwifiex_bssdescriptor {
         * BAND_A(0X04): 'a' band
         */
        u16 bss_band;
-       u64 network_tsf;
-       u8 time_stamp[8];
+       u64 fw_tsf;
+       u64 timestamp;
        union ieee_types_phy_param_set phy_param_set;
        union ieee_types_ss_param_set ss_param_set;
        u16 cap_info_bitmap;
@@ -407,6 +407,8 @@ struct mwifiex_private {
        struct host_cmd_ds_802_11_key_material aes_key;
        u8 wapi_ie[256];
        u8 wapi_ie_len;
+       u8 *wps_ie;
+       u8 wps_ie_len;
        u8 wmm_required;
        u8 wmm_enabled;
        u8 wmm_qosinfo;
@@ -448,7 +450,6 @@ struct mwifiex_private {
        struct dentry *dfs_dev_dir;
 #endif
        u8 nick_name[16];
-       u8 qual_level, qual_noise;
        u16 current_key_index;
        struct semaphore async_sem;
        u8 scan_pending_on_block;
@@ -459,6 +460,9 @@ struct mwifiex_private {
        u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
        struct wps wps;
        u8 scan_block;
+       s32 cqm_rssi_thold;
+       u32 cqm_rssi_hyst;
+       u8 subsc_evt_rssi_state;
 };
 
 enum mwifiex_ba_status {
@@ -518,6 +522,11 @@ struct cmd_ctrl_node {
        u8 cmd_wait_q_woken;
 };
 
+struct mwifiex_bss_priv {
+       u8 band;
+       u64 fw_tsf;
+};
+
 struct mwifiex_if_ops {
        int (*init_if) (struct mwifiex_adapter *);
        void (*cleanup_if) (struct mwifiex_adapter *);
@@ -651,6 +660,7 @@ struct mwifiex_adapter {
        u8 scan_wait_q_woken;
        struct cmd_ctrl_node *cmd_queued;
        spinlock_t queue_lock;          /* lock for tx queues */
+       struct completion fw_load;
 };
 
 int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@@ -896,8 +906,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
 int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type);
 int mwifiex_enable_hs(struct mwifiex_adapter *adapter);
 int mwifiex_disable_auto_ds(struct mwifiex_private *priv);
-int mwifiex_get_signal_info(struct mwifiex_private *priv,
-                           struct mwifiex_ds_get_signal *signal);
 int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
                              struct mwifiex_rate_cfg *rate);
 int mwifiex_request_scan(struct mwifiex_private *priv,
@@ -950,13 +958,10 @@ int mwifiex_bss_set_channel(struct mwifiex_private *,
 int mwifiex_get_bss_info(struct mwifiex_private *,
                         struct mwifiex_bss_info *);
 int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
-                             u8 *bssid, s32 rssi, u8 *ie_buf,
-                             size_t ie_len, u16 beacon_period,
-                             u16 cap_info_bitmap, u8 band,
+                             struct cfg80211_bss *bss,
                              struct mwifiex_bssdescriptor *bss_desc);
 int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
-                               struct mwifiex_bssdescriptor *bss_entry,
-                               u8 *ie_buf, u32 ie_len);
+                                   struct mwifiex_bssdescriptor *bss_entry);
 int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
                                        struct mwifiex_bssdescriptor *bss_desc);
 
@@ -965,6 +970,7 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
                                        u32 *flags, struct vif_params *params);
 int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev);
 
+u8 *mwifiex_11d_code_2_region(u8 code);
 
 #ifdef CONFIG_DEBUG_FS
 void mwifiex_debugfs_init(void);
index 5867fac..13fbc4e 100644 (file)
@@ -119,6 +119,9 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
        if (!adapter || !adapter->priv_num)
                return;
 
+       /* In case driver is removed when asynchronous FW load is in progress */
+       wait_for_completion(&adapter->fw_load);
+
        if (user_rmmod) {
 #ifdef CONFIG_PM
                if (adapter->is_suspended)
index aff9cd7..43f233f 100644 (file)
@@ -1048,10 +1048,8 @@ mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter,
  * This function parses provided beacon buffer and updates
  * respective fields in bss descriptor structure.
  */
-int
-mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
-                               struct mwifiex_bssdescriptor *bss_entry,
-                               u8 *ie_buf, u32 ie_len)
+int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
+                                   struct mwifiex_bssdescriptor *bss_entry)
 {
        int ret = 0;
        u8 element_id;
@@ -1073,10 +1071,8 @@ mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
 
        found_data_rate_ie = false;
        rate_size = 0;
-       current_ptr = ie_buf;
-       bytes_left = ie_len;
-       bss_entry->beacon_buf = ie_buf;
-       bss_entry->beacon_buf_size = ie_len;
+       current_ptr = bss_entry->beacon_buf;
+       bytes_left = bss_entry->beacon_buf_size;
 
        /* Process variable IE */
        while (bytes_left >= 2) {
@@ -1447,15 +1443,12 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
        return ret;
 }
 
-static int
-mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid,
-                              s32 rssi, const u8 *ie_buf, size_t ie_len,
-                              u16 beacon_period, u16 cap_info_bitmap, u8 band)
+static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
+                                         struct cfg80211_bss *bss)
 {
        struct mwifiex_bssdescriptor *bss_desc;
        int ret;
        unsigned long flags;
-       u8 *beacon_ie;
 
        /* Allocate and fill new bss descriptor */
        bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor),
@@ -1465,16 +1458,7 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid,
                return -ENOMEM;
        }
 
-       beacon_ie = kmemdup(ie_buf, ie_len, GFP_KERNEL);
-       if (!beacon_ie) {
-               kfree(bss_desc);
-               dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n");
-               return -ENOMEM;
-       }
-
-       ret = mwifiex_fill_new_bss_desc(priv, bssid, rssi, beacon_ie,
-                                       ie_len, beacon_period,
-                                       cap_info_bitmap, band, bss_desc);
+       ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);
        if (ret)
                goto done;
 
@@ -1514,7 +1498,6 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid,
 
 done:
        kfree(bss_desc);
-       kfree(beacon_ie);
        return 0;
 }
 
@@ -1620,14 +1603,16 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                const u8 *ie_buf;
                size_t ie_len;
                u16 channel = 0;
-               u64 network_tsf = 0;
+               u64 fw_tsf = 0;
                u16 beacon_size = 0;
                u32 curr_bcn_bytes;
                u32 freq;
                u16 beacon_period;
                u16 cap_info_bitmap;
                u8 *current_ptr;
+               u64 timestamp;
                struct mwifiex_bcn_param *bcn_param;
+               struct mwifiex_bss_priv *bss_priv;
 
                if (bytes_left >= sizeof(beacon_size)) {
                        /* Extract & convert beacon size from command buffer */
@@ -1667,9 +1652,11 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
 
                memcpy(bssid, bcn_param->bssid, ETH_ALEN);
 
-               rssi = (s32) (bcn_param->rssi);
-               dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", rssi);
+               rssi = (s32) bcn_param->rssi;
+               rssi = (-rssi) * 100;           /* Convert dBm to mBm */
+               dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%d\n", rssi);
 
+               timestamp = le64_to_cpu(bcn_param->timestamp);
                beacon_period = le16_to_cpu(bcn_param->beacon_period);
 
                cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap);
@@ -1709,14 +1696,13 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
 
                /*
                 * If the TSF TLV was appended to the scan results, save this
-                * entry's TSF value in the networkTSF field.The networkTSF is
-                * the firmware's TSF value at the time the beacon or probe
-                * response was received.
+                * entry's TSF value in the fw_tsf field. It is the firmware's
+                * TSF value at the time the beacon or probe response was
+                * received.
                 */
                if (tsf_tlv)
-                       memcpy(&network_tsf,
-                              &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
-                              sizeof(network_tsf));
+                       memcpy(&fw_tsf, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
+                              sizeof(fw_tsf));
 
                if (channel) {
                        struct ieee80211_channel *chan;
@@ -1739,21 +1725,19 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
 
                        if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
                                bss = cfg80211_inform_bss(priv->wdev->wiphy,
-                                             chan, bssid, network_tsf,
+                                             chan, bssid, timestamp,
                                              cap_info_bitmap, beacon_period,
                                              ie_buf, ie_len, rssi, GFP_KERNEL);
-                               *(u8 *)bss->priv = band;
-                               cfg80211_put_bss(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, bssid, rssi,
-                                                        ie_buf, ie_len,
-                                                        beacon_period,
-                                                        cap_info_bitmap, band);
+                                       mwifiex_update_curr_bss_params(priv,
+                                                                      bss);
+                               cfg80211_put_bss(bss);
                        }
                } else {
                        dev_dbg(adapter->dev, "missing BSS channel IE\n");
index f8012e2..1aa45c4 100644 (file)
@@ -123,6 +123,9 @@ mwifiex_sdio_remove(struct sdio_func *func)
        if (!adapter || !adapter->priv_num)
                return;
 
+       /* In case driver is removed when asynchronous FW load is in progress */
+       wait_for_completion(&adapter->fw_load);
+
        if (user_rmmod) {
                if (adapter->is_suspended)
                        mwifiex_sdio_resume(adapter->dev);
index a3fb322..0ead152 100644 (file)
                a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+(MAX_PORT - \
                                                a->mp_end_port)));      \
        a->mpa_tx.pkt_cnt++;                                            \
-} while (0);
+} while (0)
 
 /* SDIO Tx aggregation limit ? */
 #define MP_TX_AGGR_PKT_LIMIT_REACHED(a)                                        \
        a->mpa_tx.buf_len = 0;                                          \
        a->mpa_tx.ports = 0;                                            \
        a->mpa_tx.start_port = 0;                                       \
-} while (0);
+} while (0)
 
 /* SDIO Rx aggregation limit ? */
 #define MP_RX_AGGR_PKT_LIMIT_REACHED(a)                                        \
        a->mpa_rx.skb_arr[a->mpa_rx.pkt_cnt] = skb;                     \
        a->mpa_rx.len_arr[a->mpa_rx.pkt_cnt] = skb->len;                \
        a->mpa_rx.pkt_cnt++;                                            \
-} while (0);
+} while (0)
 
 /* Reset SDIO Rx aggregation buffer parameters */
 #define MP_RX_AGGR_BUF_RESET(a) do {                                   \
        a->mpa_rx.buf_len = 0;                                          \
        a->mpa_rx.ports = 0;                                            \
        a->mpa_rx.start_port = 0;                                       \
-} while (0);
+} while (0)
 
 
 /* data structure for SDIO MPA TX */
index 6c8e459..1f71105 100644 (file)
@@ -906,6 +906,101 @@ mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv,
        return 0;
 }
 
+/*
+ * This function prepares command for event subscription, configuration
+ * and query. Events can be subscribed or unsubscribed. Current subscribed
+ * events can be queried. Also, current subscribed events are reported in
+ * every FW response.
+ */
+static int
+mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv,
+                            struct host_cmd_ds_command *cmd,
+                            struct mwifiex_ds_misc_subsc_evt *subsc_evt_cfg)
+{
+       struct host_cmd_ds_802_11_subsc_evt *subsc_evt = &cmd->params.subsc_evt;
+       struct mwifiex_ie_types_rssi_threshold *rssi_tlv;
+       u16 event_bitmap;
+       u8 *pos;
+
+       cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SUBSCRIBE_EVENT);
+       cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_subsc_evt) +
+                               S_DS_GEN);
+
+       subsc_evt->action = cpu_to_le16(subsc_evt_cfg->action);
+       dev_dbg(priv->adapter->dev, "cmd: action: %d\n", subsc_evt_cfg->action);
+
+       /*For query requests, no configuration TLV structures are to be added.*/
+       if (subsc_evt_cfg->action == HostCmd_ACT_GEN_GET)
+               return 0;
+
+       subsc_evt->events = cpu_to_le16(subsc_evt_cfg->events);
+
+       event_bitmap = subsc_evt_cfg->events;
+       dev_dbg(priv->adapter->dev, "cmd: event bitmap : %16x\n",
+               event_bitmap);
+
+       if (((subsc_evt_cfg->action == HostCmd_ACT_BITWISE_CLR) ||
+            (subsc_evt_cfg->action == HostCmd_ACT_BITWISE_SET)) &&
+           (event_bitmap == 0)) {
+               dev_dbg(priv->adapter->dev, "Error: No event specified "
+                       "for bitwise action type\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Append TLV structures for each of the specified events for
+        * subscribing or re-configuring. This is not required for
+        * bitwise unsubscribing request.
+        */
+       if (subsc_evt_cfg->action == HostCmd_ACT_BITWISE_CLR)
+               return 0;
+
+       pos = ((u8 *)subsc_evt) +
+                       sizeof(struct host_cmd_ds_802_11_subsc_evt);
+
+       if (event_bitmap & BITMASK_BCN_RSSI_LOW) {
+               rssi_tlv = (struct mwifiex_ie_types_rssi_threshold *) pos;
+
+               rssi_tlv->header.type = cpu_to_le16(TLV_TYPE_RSSI_LOW);
+               rssi_tlv->header.len =
+                   cpu_to_le16(sizeof(struct mwifiex_ie_types_rssi_threshold) -
+                               sizeof(struct mwifiex_ie_types_header));
+               rssi_tlv->abs_value = subsc_evt_cfg->bcn_l_rssi_cfg.abs_value;
+               rssi_tlv->evt_freq = subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq;
+
+               dev_dbg(priv->adapter->dev, "Cfg Beacon Low Rssi event, "
+                       "RSSI:-%d dBm, Freq:%d\n",
+                       subsc_evt_cfg->bcn_l_rssi_cfg.abs_value,
+                       subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq);
+
+               pos += sizeof(struct mwifiex_ie_types_rssi_threshold);
+               le16_add_cpu(&cmd->size,
+                            sizeof(struct mwifiex_ie_types_rssi_threshold));
+       }
+
+       if (event_bitmap & BITMASK_BCN_RSSI_HIGH) {
+               rssi_tlv = (struct mwifiex_ie_types_rssi_threshold *) pos;
+
+               rssi_tlv->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH);
+               rssi_tlv->header.len =
+                   cpu_to_le16(sizeof(struct mwifiex_ie_types_rssi_threshold) -
+                               sizeof(struct mwifiex_ie_types_header));
+               rssi_tlv->abs_value = subsc_evt_cfg->bcn_h_rssi_cfg.abs_value;
+               rssi_tlv->evt_freq = subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq;
+
+               dev_dbg(priv->adapter->dev, "Cfg Beacon High Rssi event, "
+                       "RSSI:-%d dBm, Freq:%d\n",
+                       subsc_evt_cfg->bcn_h_rssi_cfg.abs_value,
+                       subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq);
+
+               pos += sizeof(struct mwifiex_ie_types_rssi_threshold);
+               le16_add_cpu(&cmd->size,
+                            sizeof(struct mwifiex_ie_types_rssi_threshold));
+       }
+
+       return 0;
+}
+
 /*
  * This function prepares the commands before sending them to the firmware.
  *
@@ -1086,6 +1181,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
        case HostCmd_CMD_PCIE_DESC_DETAILS:
                ret = mwifiex_cmd_pcie_host_spec(priv, cmd_ptr, cmd_action);
                break;
+       case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
+               ret = mwifiex_cmd_802_11_subsc_evt(priv, cmd_ptr, data_buf);
+               break;
        default:
                dev_err(priv->adapter->dev,
                        "PREP_CMD: unknown cmd- %#x\n", cmd_no);
index 4da19ed..3aa5424 100644 (file)
@@ -119,11 +119,11 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
  * calculated SNR values.
  */
 static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv,
-                                       struct host_cmd_ds_command *resp,
-                                       struct mwifiex_ds_get_signal *signal)
+                                       struct host_cmd_ds_command *resp)
 {
        struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp =
                                                &resp->params.rssi_info_rsp;
+       struct mwifiex_ds_misc_subsc_evt subsc_evt;
 
        priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last);
        priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last);
@@ -137,34 +137,29 @@ static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv,
        priv->bcn_rssi_avg = le16_to_cpu(rssi_info_rsp->bcn_rssi_avg);
        priv->bcn_nf_avg = le16_to_cpu(rssi_info_rsp->bcn_nf_avg);
 
-       /* Need to indicate IOCTL complete */
-       if (signal) {
-               memset(signal, 0, sizeof(*signal));
-
-               signal->selector = ALL_RSSI_INFO_MASK;
-
-               /* RSSI */
-               signal->bcn_rssi_last = priv->bcn_rssi_last;
-               signal->bcn_rssi_avg = priv->bcn_rssi_avg;
-               signal->data_rssi_last = priv->data_rssi_last;
-               signal->data_rssi_avg = priv->data_rssi_avg;
-
-               /* SNR */
-               signal->bcn_snr_last =
-                       CAL_SNR(priv->bcn_rssi_last, priv->bcn_nf_last);
-               signal->bcn_snr_avg =
-                       CAL_SNR(priv->bcn_rssi_avg, priv->bcn_nf_avg);
-               signal->data_snr_last =
-                       CAL_SNR(priv->data_rssi_last, priv->data_nf_last);
-               signal->data_snr_avg =
-                       CAL_SNR(priv->data_rssi_avg, priv->data_nf_avg);
-
-               /* NF */
-               signal->bcn_nf_last = priv->bcn_nf_last;
-               signal->bcn_nf_avg = priv->bcn_nf_avg;
-               signal->data_nf_last = priv->data_nf_last;
-               signal->data_nf_avg = priv->data_nf_avg;
+       if (priv->subsc_evt_rssi_state == EVENT_HANDLED)
+               return 0;
+
+       /* Resubscribe low and high rssi events with new thresholds */
+       memset(&subsc_evt, 0x00, sizeof(struct mwifiex_ds_misc_subsc_evt));
+       subsc_evt.events = BITMASK_BCN_RSSI_LOW | BITMASK_BCN_RSSI_HIGH;
+       subsc_evt.action = HostCmd_ACT_BITWISE_SET;
+       if (priv->subsc_evt_rssi_state == RSSI_LOW_RECVD) {
+               subsc_evt.bcn_l_rssi_cfg.abs_value = abs(priv->bcn_rssi_avg -
+                               priv->cqm_rssi_hyst);
+               subsc_evt.bcn_h_rssi_cfg.abs_value = abs(priv->cqm_rssi_thold);
+       } else if (priv->subsc_evt_rssi_state == RSSI_HIGH_RECVD) {
+               subsc_evt.bcn_l_rssi_cfg.abs_value = abs(priv->cqm_rssi_thold);
+               subsc_evt.bcn_h_rssi_cfg.abs_value = abs(priv->bcn_rssi_avg +
+                               priv->cqm_rssi_hyst);
        }
+       subsc_evt.bcn_l_rssi_cfg.evt_freq = 1;
+       subsc_evt.bcn_h_rssi_cfg.evt_freq = 1;
+
+       priv->subsc_evt_rssi_state = EVENT_HANDLED;
+
+       mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
+                              0, 0, &subsc_evt);
 
        return 0;
 }
@@ -784,6 +779,28 @@ static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv,
        return 0;
 }
 
+/*
+ * This function handles the command response for subscribe event command.
+ */
+static int mwifiex_ret_subsc_evt(struct mwifiex_private *priv,
+                                struct host_cmd_ds_command *resp,
+                                struct mwifiex_ds_misc_subsc_evt *sub_event)
+{
+       struct host_cmd_ds_802_11_subsc_evt *cmd_sub_event =
+               (struct host_cmd_ds_802_11_subsc_evt *)&resp->params.subsc_evt;
+
+       /* For every subscribe event command (Get/Set/Clear), FW reports the
+        * current set of subscribed events*/
+       dev_dbg(priv->adapter->dev, "Bitmap of currently subscribed events: %16x\n",
+               le16_to_cpu(cmd_sub_event->events));
+
+       /*Return the subscribed event info for a Get request*/
+       if (sub_event)
+               sub_event->events = le16_to_cpu(cmd_sub_event->events);
+
+       return 0;
+}
+
 /*
  * This function handles the command responses.
  *
@@ -853,7 +870,7 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
                ret = mwifiex_ret_get_log(priv, resp, data_buf);
                break;
        case HostCmd_CMD_RSSI_INFO:
-               ret = mwifiex_ret_802_11_rssi_info(priv, resp, data_buf);
+               ret = mwifiex_ret_802_11_rssi_info(priv, resp);
                break;
        case HostCmd_CMD_802_11_SNMP_MIB:
                ret = mwifiex_ret_802_11_snmp_mib(priv, resp, data_buf);
@@ -924,6 +941,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
                break;
        case HostCmd_CMD_PCIE_DESC_DETAILS:
                break;
+       case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
+               ret = mwifiex_ret_subsc_evt(priv, resp, data_buf);
+               break;
        default:
                dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
                        resp->command);
index cc531b5..f6bbb93 100644 (file)
@@ -128,9 +128,6 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv)
                mwifiex_stop_net_dev_queue(priv->netdev, adapter);
        if (netif_carrier_ok(priv->netdev))
                netif_carrier_off(priv->netdev);
-       /* Reset wireless stats signal info */
-       priv->qual_level = 0;
-       priv->qual_noise = 0;
 }
 
 /*
@@ -317,6 +314,12 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                break;
 
        case EVENT_RSSI_LOW:
+               cfg80211_cqm_rssi_notify(priv->netdev,
+                                        NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+                                        GFP_KERNEL);
+               mwifiex_send_cmd_async(priv, HostCmd_CMD_RSSI_INFO,
+                                      HostCmd_ACT_GEN_GET, 0, NULL);
+               priv->subsc_evt_rssi_state = RSSI_LOW_RECVD;
                dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n");
                break;
        case EVENT_SNR_LOW:
@@ -326,6 +329,12 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                dev_dbg(adapter->dev, "event: MAX_FAIL\n");
                break;
        case EVENT_RSSI_HIGH:
+               cfg80211_cqm_rssi_notify(priv->netdev,
+                                        NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+                                        GFP_KERNEL);
+               mwifiex_send_cmd_async(priv, HostCmd_CMD_RSSI_INFO,
+                                      HostCmd_ACT_GEN_GET, 0, NULL);
+               priv->subsc_evt_rssi_state = RSSI_HIGH_RECVD;
                dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n");
                break;
        case EVENT_SNR_HIGH:
index d7b11de..58970e0 100644 (file)
@@ -155,20 +155,29 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
  * information.
  */
 int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
-                             u8 *bssid, s32 rssi, u8 *ie_buf,
-                             size_t ie_len, u16 beacon_period,
-                             u16 cap_info_bitmap, u8 band,
+                             struct cfg80211_bss *bss,
                              struct mwifiex_bssdescriptor *bss_desc)
 {
        int ret;
+       u8 *beacon_ie;
+       struct mwifiex_bss_priv *bss_priv = (void *)bss->priv;
 
-       memcpy(bss_desc->mac_address, bssid, ETH_ALEN);
-       bss_desc->rssi = rssi;
-       bss_desc->beacon_buf = ie_buf;
-       bss_desc->beacon_buf_size = ie_len;
-       bss_desc->beacon_period = beacon_period;
-       bss_desc->cap_info_bitmap = cap_info_bitmap;
-       bss_desc->bss_band = band;
+       beacon_ie = kmemdup(bss->information_elements, bss->len_beacon_ies,
+                           GFP_KERNEL);
+       if (!beacon_ie) {
+               dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n");
+               return -ENOMEM;
+       }
+
+       memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN);
+       bss_desc->rssi = bss->signal;
+       bss_desc->beacon_buf = beacon_ie;
+       bss_desc->beacon_buf_size = bss->len_beacon_ies;
+       bss_desc->beacon_period = bss->beacon_interval;
+       bss_desc->cap_info_bitmap = bss->capability;
+       bss_desc->bss_band = bss_priv->band;
+       bss_desc->fw_tsf = bss_priv->fw_tsf;
+       bss_desc->timestamp = bss->tsf;
        if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
                dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n");
                bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
@@ -180,9 +189,9 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
        else
                bss_desc->bss_mode = NL80211_IFTYPE_STATION;
 
-       ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc,
-                                             ie_buf, ie_len);
+       ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);
 
+       kfree(beacon_ie);
        return ret;
 }
 
@@ -197,7 +206,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
        int ret;
        struct mwifiex_adapter *adapter = priv->adapter;
        struct mwifiex_bssdescriptor *bss_desc = NULL;
-       u8 *beacon_ie = NULL;
 
        priv->scan_block = false;
 
@@ -210,19 +218,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
                        return -ENOMEM;
                }
 
-               beacon_ie = kmemdup(bss->information_elements,
-                                       bss->len_beacon_ies, GFP_KERNEL);
-               if (!beacon_ie) {
-                       kfree(bss_desc);
-                       dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n");
-                       return -ENOMEM;
-               }
-
-               ret = mwifiex_fill_new_bss_desc(priv, bss->bssid, bss->signal,
-                                               beacon_ie, bss->len_beacon_ies,
-                                               bss->beacon_interval,
-                                               bss->capability,
-                                               *(u8 *)bss->priv, bss_desc);
+               ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);
                if (ret)
                        goto done;
        }
@@ -269,7 +265,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
                    (!mwifiex_ssid_cmp(&priv->curr_bss_params.bss_descriptor.
                                       ssid, &bss_desc->ssid))) {
                        kfree(bss_desc);
-                       kfree(beacon_ie);
                        return 0;
                }
 
@@ -304,7 +299,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
 
 done:
        kfree(bss_desc);
-       kfree(beacon_ie);
        return ret;
 }
 
@@ -468,7 +462,8 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv,
 
        info->bss_chan = bss_desc->channel;
 
-       info->region_code = adapter->region_code;
+       memcpy(info->country_code, priv->country_code,
+              IEEE80211_COUNTRY_STRING_LEN);
 
        info->media_connected = priv->media_connected;
 
@@ -995,6 +990,39 @@ static int mwifiex_set_wapi_ie(struct mwifiex_private *priv,
        return 0;
 }
 
+/*
+ * IOCTL request handler to set/reset WPS IE.
+ *
+ * The supplied WPS IE is treated as a opaque buffer. Only the first field
+ * is checked to internally enable WPS. If buffer length is zero, the existing
+ * WPS IE is reset.
+ */
+static int mwifiex_set_wps_ie(struct mwifiex_private *priv,
+                              u8 *ie_data_ptr, u16 ie_len)
+{
+       if (ie_len) {
+               priv->wps_ie = kzalloc(MWIFIEX_MAX_VSIE_LEN, GFP_KERNEL);
+               if (!priv->wps_ie)
+                       return -ENOMEM;
+               if (ie_len > sizeof(priv->wps_ie)) {
+                       dev_dbg(priv->adapter->dev,
+                               "info: failed to copy WPS IE, too big\n");
+                       kfree(priv->wps_ie);
+                       return -1;
+               }
+               memcpy(priv->wps_ie, ie_data_ptr, ie_len);
+               priv->wps_ie_len = ie_len;
+               dev_dbg(priv->adapter->dev, "cmd: Set wps_ie_len=%d IE=%#x\n",
+                       priv->wps_ie_len, priv->wps_ie[0]);
+       } else {
+               kfree(priv->wps_ie);
+               priv->wps_ie_len = ie_len;
+               dev_dbg(priv->adapter->dev,
+                       "info: Reset wps_ie_len=%d\n", priv->wps_ie_len);
+       }
+       return 0;
+}
+
 /*
  * IOCTL request handler to set WAPI key.
  *
@@ -1184,39 +1212,6 @@ mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
        return 0;
 }
 
-/*
- * Sends IOCTL request to get signal information.
- *
- * This function allocates the IOCTL request buffer, fills it
- * with requisite parameters and calls the IOCTL handler.
- */
-int mwifiex_get_signal_info(struct mwifiex_private *priv,
-                           struct mwifiex_ds_get_signal *signal)
-{
-       int status;
-
-       signal->selector = ALL_RSSI_INFO_MASK;
-
-       /* Signal info can be obtained only if connected */
-       if (!priv->media_connected) {
-               dev_dbg(priv->adapter->dev,
-                       "info: Can not get signal in disconnected state\n");
-               return -1;
-       }
-
-       status = mwifiex_send_cmd_sync(priv, HostCmd_CMD_RSSI_INFO,
-                                      HostCmd_ACT_GEN_GET, 0, signal);
-
-       if (!status) {
-               if (signal->selector & BCN_RSSI_AVG_MASK)
-                       priv->qual_level = signal->bcn_rssi_avg;
-               if (signal->selector & BCN_NF_AVG_MASK)
-                       priv->qual_noise = signal->bcn_nf_avg;
-       }
-
-       return status;
-}
-
 /*
  * Sends IOCTL request to set encoding parameters.
  *
@@ -1441,6 +1436,7 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
                        priv->wps.session_enable = true;
                        dev_dbg(priv->adapter->dev,
                                "info: WPS Session Enabled.\n");
+                       ret = mwifiex_set_wps_ie(priv, ie_data_ptr, ie_len);
                }
 
                /* Append the passed data to the end of the