From e9eb8cbe77139470651c858b8b7a3d20d332cf47 Mon Sep 17 00:00:00 2001 From: Guy Eilam Date: Tue, 16 Aug 2011 19:49:12 +0300 Subject: [PATCH 1/7] wl12xx: use 2 spare TX blocks for GEM cipher Add tx_spare_blocks member to the wl1271 struct for more generic configuration of the amount of spare TX blocks that should be used. The default value is 1. In case GEM cipher is used by the STA, we need 2 spare TX blocks instead of just 1. Signed-off-by: Guy Eilam Acked-by: Arik Nemtsov Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 13 +++++++++++++ drivers/net/wireless/wl12xx/tx.c | 8 +++++--- drivers/net/wireless/wl12xx/tx.h | 1 + drivers/net/wireless/wl12xx/wl12xx.h | 3 +++ 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 82f4408e89ad..20e7bc78a7fe 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2064,6 +2064,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, wl->session_counter = 0; wl->rate_set = CONF_TX_RATE_MASK_BASIC; wl->vif = NULL; + wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; wl1271_free_ap_keys(wl); memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map)); wl->ap_fw_ps_map = 0; @@ -2653,6 +2654,17 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + /* + * A STA set to GEM cipher requires 2 tx spare blocks. + * Return to default value when GEM cipher key is removed + */ + if (key_type == KEY_GEM) { + if (action == KEY_ADD_OR_REPLACE) + wl->tx_spare_blocks = 2; + else if (action == KEY_REMOVE) + wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; + } + addr = sta ? sta->addr : bcast_addr; if (is_zero_ether_addr(addr)) { @@ -4599,6 +4611,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->sched_scanning = false; wl->tx_security_seq = 0; wl->tx_security_last_seq_lsb = 0; + wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; wl->role_id = WL12XX_INVALID_ROLE_ID; wl->system_hlid = WL12XX_SYSTEM_HLID; wl->sta_hlid = WL12XX_INVALID_LINK_ID; diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 0f1578577b1a..08227e69616b 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -204,9 +204,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, u32 len; u32 total_blocks; int id, ret = -EBUSY, ac; - - /* we use 1 spare block */ - u32 spare_blocks = 1; + u32 spare_blocks = wl->tx_spare_blocks; if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) return -EAGAIN; @@ -220,6 +218,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, in the firmware */ len = wl12xx_calc_packet_alignment(wl, total_len); + /* in case of a dummy packet, use default amount of spare mem blocks */ + if (unlikely(wl12xx_is_dummy_packet(wl, skb))) + spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; + total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + spare_blocks; diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index 7da35c0e411b..6519be4b2c38 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -25,6 +25,7 @@ #ifndef __TX_H__ #define __TX_H__ +#define TX_HW_BLOCK_SPARE_DEFAULT 1 #define TX_HW_BLOCK_SIZE 252 #define TX_HW_MGMT_PKT_LIFETIME_TU 2000 diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 61a7c2163ea2..fb2753c46300 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -425,6 +425,9 @@ struct wl1271 { u32 tx_allocated_blocks; u32 tx_results_count; + /* amount of spare TX blocks to use */ + u32 tx_spare_blocks; + /* Accounting for allocated / available Tx packets in HW */ u32 tx_pkts_freed[NUM_TX_QUEUES]; u32 tx_allocated_pkts[NUM_TX_QUEUES]; From cabb81c9a8d8dd7e5f220244246332ab24ef6d80 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Tue, 23 Aug 2011 15:56:22 +0300 Subject: [PATCH 2/7] wl12xx: allow 11a AP-mode for wl127x devices There was a check preventing 127x devices from using the 11a band when operating as AP. Since we now support this functionality, remove the check. With this patch, a 11a AP starts ok on 127x cards. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/boot.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index cc70422c0575..6d5664bfc37d 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -294,9 +294,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) */ if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { - /* for now 11a is unsupported in AP mode */ - if (wl->bss_type != BSS_TYPE_AP_BSS && - nvs->general_params.dual_mode_select) + if (nvs->general_params.dual_mode_select) wl->enable_11a = true; } From 53835a2d19f533acb0de2466d1ece7b673556419 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 23 Aug 2011 15:56:23 +0300 Subject: [PATCH 3/7] wl12xx: initialize rate_set on band rates initialization In some corner cases, (invalid) 11g rates were used while working on 11a band. Take care of it by initializing rate_set according to the configured band. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 20e7bc78a7fe..3702e61a89f6 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2200,10 +2200,14 @@ static int wl1271_unjoin(struct wl1271 *wl) static void wl1271_set_band_rate(struct wl1271 *wl) { - if (wl->band == IEEE80211_BAND_2GHZ) + if (wl->band == IEEE80211_BAND_2GHZ) { wl->basic_rate_set = wl->conf.tx.basic_rate; - else + wl->rate_set = wl->conf.tx.basic_rate; + } else { wl->basic_rate_set = wl->conf.tx.basic_rate_5; + wl->rate_set = wl->conf.tx.basic_rate_5; + } + } static bool wl12xx_is_roc(struct wl1271 *wl) From a879ed790a6108a3372be2d22a1ae81f59ab8db8 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 23 Aug 2011 16:37:02 +0300 Subject: [PATCH 4/7] wl12xx: increase psm_entry_retries In congested env, sometimes 5 psm entry retries are not enough. Increase the retries count to 8. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 3702e61a89f6..3edc1d867836 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -236,7 +236,7 @@ static struct conf_drv_settings default_conf = { .ps_poll_recovery_period = 700, .bet_enable = CONF_BET_MODE_ENABLE, .bet_max_consecutive = 50, - .psm_entry_retries = 5, + .psm_entry_retries = 8, .psm_exit_retries = 16, .psm_entry_nullfunc_retries = 3, .psm_entry_hangover_period = 1, From 05dba3550603b9dc8609b5ea7c3ffba4e3bb97f2 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 23 Aug 2011 16:37:01 +0300 Subject: [PATCH 5/7] wl12xx: enter psm only after station role was started The station didn't get into psm after recovery, because psm was configured before sta role was started. Move wl1271_ps_set_mode() to be executed only after the role was started. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 3edc1d867836..0f72af9fc267 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3361,19 +3361,6 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ret = wl1271_acx_conn_monit_params(wl, true); if (ret < 0) goto out; - - /* If we want to go in PSM but we're not there yet */ - if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && - !test_bit(WL1271_FLAG_PSM, &wl->flags)) { - enum wl1271_cmd_ps_mode mode; - - mode = STATION_POWER_SAVE_MODE; - ret = wl1271_ps_set_mode(wl, mode, - wl->basic_rate, - true); - if (ret < 0) - goto out; - } } else { /* use defaults when not associated */ bool was_assoc = @@ -3517,6 +3504,19 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, if (ret < 0) goto out; } + + /* If we want to go in PSM but we're not there yet */ + if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && + !test_bit(WL1271_FLAG_PSM, &wl->flags)) { + enum wl1271_cmd_ps_mode mode; + + mode = STATION_POWER_SAVE_MODE; + ret = wl1271_ps_set_mode(wl, mode, + wl->basic_rate, + true); + if (ret < 0) + goto out; + } } /* Handle new association with HT. Do this after join. */ From f952079a19c69843f4da2f7e0da008192421c6ce Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 23 Aug 2011 18:34:44 +0300 Subject: [PATCH 6/7] wl12xx: add support for multiple SSIDs in sched_scan The wl12xx firmwares support multiple SSIDs in a single sched_scan run. This patch implements support for it. We use three different types os sched_scan: FILTER_ANY (ie. not filtering, only wildcard SSID in the probe_reqs); FILTER_LIST (ie. send out probe_reqs with the specified SSIDs and only report if they are found); and FILTER_DISABLED (ie. send out probe_reqs with the specified SSIDs, but report anything found). Since we still don't have proper filter support in nl80211/cfg80211 yet, we cannot use filters when the wildcard SSID is used. Thus, we will not filter anything if the wildcard SSID is specified. Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 1 + drivers/net/wireless/wl12xx/scan.c | 63 ++++++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 0f72af9fc267..bde84027ab7f 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -4491,6 +4491,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); wl->hw->wiphy->max_scan_ssids = 1; + wl->hw->wiphy->max_sched_scan_ssids = 8; /* * Maximum length of elements in scanning probe request templates * should be the maximum length possible for a template, without diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 7229eaa89018..af9d53c8e19c 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -473,6 +473,48 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl, cfg->passive[2] || cfg->active[2]; } +/* Returns 0 if no wildcard is used, 1 if wildcard is used or a + * negative value on error */ +static int +wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, + struct cfg80211_sched_scan_request *req) +{ + struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL; + struct cfg80211_ssid *ssid = req->ssids; + int ret, wildcard = 0; + + wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + while ((cmd->n_ssids < req->n_ssids) && ssid) { + if (ssid->ssid_len == 0) + wildcard = 1; + cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_HIDDEN; + cmd->ssids[cmd->n_ssids].len = ssid->ssid_len; + memcpy(cmd->ssids[cmd->n_ssids].ssid, ssid->ssid, + ssid->ssid_len); + ssid++; + cmd->n_ssids++; + } + + wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd)); + + ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd, + sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("cmd sched scan ssid list failed"); + goto out; + } + + ret = wildcard; +out: + kfree(cmd); + return ret; +} + int wl1271_scan_sched_scan_config(struct wl1271 *wl, struct cfg80211_sched_scan_request *req, struct ieee80211_sched_scan_ies *ies) @@ -504,14 +546,21 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++) cfg->intervals[i] = cpu_to_le32(req->interval); - if (!force_passive && req->ssids[0].ssid_len && req->ssids[0].ssid) { - cfg->filter_type = SCAN_SSID_FILTER_SPECIFIC; - cfg->ssid_len = req->ssids[0].ssid_len; - memcpy(cfg->ssid, req->ssids[0].ssid, - req->ssids[0].ssid_len); - } else { + cfg->ssid_len = 0; + if (req->n_ssids == 0) { + wl1271_debug(DEBUG_SCAN, "using SCAN_SSID_FILTER_ANY"); cfg->filter_type = SCAN_SSID_FILTER_ANY; - cfg->ssid_len = 0; + } else { + ret = wl12xx_scan_sched_scan_ssid_list(wl, req); + if (ret < 0) + goto out; + if (ret) { + wl1271_debug(DEBUG_SCAN, "using SCAN_SSID_FILTER_DISABLED"); + cfg->filter_type = SCAN_SSID_FILTER_DISABLED; + } else { + wl1271_debug(DEBUG_SCAN, "using SCAN_SSID_FILTER_LIST"); + cfg->filter_type = SCAN_SSID_FILTER_LIST; + } } if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) { From bd4932b8ee2fbdbcf168930de9dcfed1018a085d Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 23 Aug 2011 18:34:45 +0300 Subject: [PATCH 7/7] wl12xx: use SCAN_SSID_TYPE_PUBLIC when using the wildcard in sched_scan When we are scanning for the wildcard SSID in a scheduled scan, we should use SCAN_SSID_TYPE_PUBLIC so that we don't filter out the scan results. Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/scan.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index af9d53c8e19c..af4ad2353f59 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -490,9 +490,12 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, return -ENOMEM; while ((cmd->n_ssids < req->n_ssids) && ssid) { - if (ssid->ssid_len == 0) + if (ssid->ssid_len == 0) { wildcard = 1; - cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_HIDDEN; + cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC; + } else { + cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_HIDDEN; + } cmd->ssids[cmd->n_ssids].len = ssid->ssid_len; memcpy(cmd->ssids[cmd->n_ssids].ssid, ssid->ssid, ssid->ssid_len);