From 0ce131c5a8d84cd3bb022d9a40a806518e05ba15 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 29 May 2012 11:41:54 -0700 Subject: [PATCH] UPSTREAM: mwifiex: backport some 3.5 patches to 3.4 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 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 Reviewed-by: Doug Anderson Commit-Ready: Sam Leffler --- drivers/net/wireless/mwifiex/cfg80211.c | 112 ++++++++++++++++--- drivers/net/wireless/mwifiex/cfp.c | 31 ++++++ drivers/net/wireless/mwifiex/debugfs.c | 2 +- drivers/net/wireless/mwifiex/fw.h | 24 ++++- drivers/net/wireless/mwifiex/init.c | 2 + drivers/net/wireless/mwifiex/ioctl.h | 52 ++++----- drivers/net/wireless/mwifiex/join.c | 50 ++++++++- drivers/net/wireless/mwifiex/main.c | 106 +++++++++--------- drivers/net/wireless/mwifiex/main.h | 32 +++--- drivers/net/wireless/mwifiex/pcie.c | 3 + drivers/net/wireless/mwifiex/scan.c | 68 +++++------- drivers/net/wireless/mwifiex/sdio.c | 3 + drivers/net/wireless/mwifiex/sdio.h | 8 +- drivers/net/wireless/mwifiex/sta_cmd.c | 98 +++++++++++++++++ drivers/net/wireless/mwifiex/sta_cmdresp.c | 80 ++++++++------ drivers/net/wireless/mwifiex/sta_event.c | 15 ++- drivers/net/wireless/mwifiex/sta_ioctl.c | 120 ++++++++++----------- 17 files changed, 552 insertions(+), 254 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 65050384c42b..c78ea873a63a 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -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; diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c index 2fe1c33765b8..560871b0e236 100644 --- a/drivers/net/wireless/mwifiex/cfp.c +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -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. diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index 1a845074c52a..a870b5885c09 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -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", diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index e98fc5af73dc..f42da1e4a34d 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -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; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 54bb4839b57c..0d55c5b542d7 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -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; diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 7ca4e8234f3e..f0f95524e96b 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -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 diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 8f9382b9c3ca..c1ac42b012d0 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -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); diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 9d1b3ca6334b..245b7329e0c9 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -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); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 35225e9b1080..7411b7d4d86d 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -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); diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 5867facd415d..13fbc4eb1595 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -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) diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index aff9cd763f2b..43f233f5bf89 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -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"); diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index f8012e2b7f7c..1aa45c4295bb 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -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); diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index a3fb322205b0..0ead152e3d1e 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -193,7 +193,7 @@ 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) \ @@ -211,7 +211,7 @@ 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) \ @@ -242,7 +242,7 @@ 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 { \ @@ -250,7 +250,7 @@ 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 */ diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 6c8e4594b48b..1f7110577b9d 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -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); diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 4da19ed0f078..3aa54243dea9 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -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); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index cc531b536a56..f6bbb9307f86 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -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: diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index d7b11defafe0..58970e0f7d13 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -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 -- 2.20.1