diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r-- | drivers/net/wireless/wl12xx/Kconfig | 10 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/Makefile | 6 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/acx.c | 40 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/acx.h | 18 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/cmd.c | 60 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/cmd.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/conf.h | 29 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/debugfs.c | 88 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/event.c | 37 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/init.c | 22 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/main.c | 300 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/ps.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/rx.c | 9 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/scan.c | 166 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/sdio_test.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/tx.c | 60 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/tx.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl12xx.h | 13 |
18 files changed, 633 insertions, 264 deletions
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 07bcb15..3fe388b 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -19,16 +19,6 @@ config WL12XX If you choose to build a module, it will be called wl12xx. Say N if unsure. -config WL12XX_HT - bool "TI wl12xx 802.11 HT support (EXPERIMENTAL)" - depends on WL12XX && EXPERIMENTAL - default n - ---help--- - This will enable 802.11 HT support in the wl12xx module. - - That configuration is temporary due to the code incomplete and - still in testing process. - config WL12XX_SPI tristate "TI wl12xx SPI support" depends on WL12XX && SPI_MASTER diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index 521c041..621b348 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,16 +1,16 @@ wl12xx-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \ boot.o init.o debugfs.o scan.o -wl12xx_spi-objs = spi.o +wl12xx_spi-objs = spi.o wl12xx_sdio-objs = sdio.o -wl12xx_sdio_test-objs = sdio_test.o +wl12xx_sdio_test-objs = sdio_test.o wl12xx-$(CONFIG_NL80211_TESTMODE) += testmode.o obj-$(CONFIG_WL12XX) += wl12xx.o obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o -obj-$(CONFIG_WL12XX_SDIO_TEST) += wl12xx_sdio_test.o +obj-$(CONFIG_WL12XX_SDIO_TEST) += wl12xx_sdio_test.o # small builtin driver bit obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index f2838ae..399849e 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -1687,3 +1687,43 @@ out: kfree(acx); return ret; } + +int wl12xx_acx_config_hangover(struct wl1271 *wl) +{ + struct wl12xx_acx_config_hangover *acx; + struct conf_hangover_settings *conf = &wl->conf.hangover; + int ret; + + wl1271_debug(DEBUG_ACX, "acx config hangover"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->recover_time = cpu_to_le32(conf->recover_time); + acx->hangover_period = conf->hangover_period; + acx->dynamic_mode = conf->dynamic_mode; + acx->early_termination_mode = conf->early_termination_mode; + acx->max_period = conf->max_period; + acx->min_period = conf->min_period; + acx->increase_delta = conf->increase_delta; + acx->decrease_delta = conf->decrease_delta; + acx->quiet_time = conf->quiet_time; + acx->increase_time = conf->increase_time; + acx->window_size = acx->window_size; + + ret = wl1271_cmd_configure(wl, ACX_CONFIG_HANGOVER, acx, + sizeof(*acx)); + + if (ret < 0) { + wl1271_warning("acx config hangover failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; + +} diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 758c596..556ee4e 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -1144,6 +1144,23 @@ struct wl12xx_acx_set_rate_mgmt_params { u8 padding2[2]; } __packed; +struct wl12xx_acx_config_hangover { + struct acx_header header; + + __le32 recover_time; + u8 hangover_period; + u8 dynamic_mode; + u8 early_termination_mode; + u8 max_period; + u8 min_period; + u8 increase_delta; + u8 decrease_delta; + u8 quiet_time; + u8 increase_time; + u8 window_size; + u8 padding[2]; +} __packed; + enum { ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_MEM_CFG = 0x0003, @@ -1281,5 +1298,6 @@ int wl1271_acx_config_ps(struct wl1271 *wl); int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); int wl1271_acx_fm_coex(struct wl1271 *wl); int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl); +int wl12xx_acx_config_hangover(struct wl1271 *wl); #endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 817bc18..287fe95 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -661,12 +661,9 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl) wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wl->role_id); - /* - * We currently do not support hidden SSID. The real SSID - * should be fetched from mac80211 first. - */ - if (wl->ssid_len == 0) { - wl1271_warning("Hidden SSID currently not supported for AP"); + /* trying to use hidden SSID with an old hostapd version */ + if (wl->ssid_len == 0 && !bss_conf->hidden_ssid) { + wl1271_error("got a null SSID from beacon/bss"); ret = -EINVAL; goto out; } @@ -695,9 +692,18 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl) cmd->ap.dtim_interval = bss_conf->dtim_period; cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; cmd->channel = wl->channel; - cmd->ap.ssid_len = wl->ssid_len; - cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC; - memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len); + + if (!bss_conf->hidden_ssid) { + /* take the SSID from the beacon for backward compatibility */ + cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC; + cmd->ap.ssid_len = wl->ssid_len; + memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len); + } else { + cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN; + cmd->ap.ssid_len = bss_conf->ssid_len; + memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len); + } + cmd->ap.local_rates = cpu_to_le32(0xffffffff); switch (wl->band) { @@ -895,7 +901,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) struct acx_header *acx = buf; int ret; - wl1271_debug(DEBUG_CMD, "cmd configure"); + wl1271_debug(DEBUG_CMD, "cmd configure (%d)", id); acx->id = cpu_to_le16(id); @@ -1106,6 +1112,7 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, { struct sk_buff *skb; int ret; + u32 rate; skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, ie, ie_len); @@ -1116,14 +1123,13 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); if (band == IEEE80211_BAND_2GHZ) ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, - skb->data, skb->len, 0, - wl->conf.tx.basic_rate); + skb->data, skb->len, 0, rate); else ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, - skb->data, skb->len, 0, - wl->conf.tx.basic_rate_5); + skb->data, skb->len, 0, rate); out: dev_kfree_skb(skb); @@ -1134,6 +1140,7 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, struct sk_buff *skb) { int ret; + u32 rate; if (!skb) skb = ieee80211_ap_probereq_get(wl->hw, wl->vif); @@ -1142,14 +1149,13 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len); + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[wl->band]); if (wl->band == IEEE80211_BAND_2GHZ) ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, - skb->data, skb->len, 0, - wl->conf.tx.basic_rate); + skb->data, skb->len, 0, rate); else ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, - skb->data, skb->len, 0, - wl->conf.tx.basic_rate_5); + skb->data, skb->len, 0, rate); if (ret < 0) wl1271_error("Unable to set ap probe request template."); @@ -1413,7 +1419,7 @@ out: int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) { struct wl12xx_cmd_add_peer *cmd; - int ret; + int i, ret; u32 sta_rates; wl1271_debug(DEBUG_CMD, "cmd add peer %d", (int)hlid); @@ -1424,23 +1430,29 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) goto out; } - /* currently we don't support UAPSD */ - cmd->sp_len = 0; - memcpy(cmd->addr, sta->addr, ETH_ALEN); cmd->bss_index = WL1271_AP_BSS_INDEX; cmd->aid = sta->aid; cmd->hlid = hlid; + cmd->sp_len = sta->max_sp; cmd->wmm = sta->wme ? 1 : 0; + for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++) + if (sta->wme && (sta->uapsd_queues & BIT(i))) + cmd->psd_type[i] = WL1271_PSD_UPSD_TRIGGER; + else + cmd->psd_type[i] = WL1271_PSD_LEGACY; + sta_rates = sta->supp_rates[wl->band]; if (sta->ht_cap.ht_supported) sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET; cmd->supported_rates = - cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates)); + cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates, + wl->band)); - wl1271_debug(DEBUG_CMD, "new peer rates: 0x%x", cmd->supported_rates); + wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x", + cmd->supported_rates, sta->uapsd_queues); ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0); if (ret < 0) { diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 22c2f37..8e4d11e 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -591,6 +591,13 @@ enum wl12xx_ssid_type { WL12XX_SSID_TYPE_ANY = 2, }; +enum wl1271_psd_type { + WL1271_PSD_LEGACY = 0, + WL1271_PSD_UPSD_TRIGGER = 1, + WL1271_PSD_LEGACY_PSPOLL = 2, + WL1271_PSD_SAPSD = 3 +}; + struct wl12xx_cmd_add_peer { struct wl1271_cmd_header header; diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 82f205c..6a6805c 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -454,12 +454,10 @@ struct conf_rx_settings { #define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \ CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS) -/* - * Default rates for working as IBSS. use 11b rates - */ +/* default rates for working as IBSS (11b and OFDM) */ #define CONF_TX_IBSS_DEFAULT_RATES (CONF_HW_BIT_RATE_1MBPS | \ CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ - CONF_HW_BIT_RATE_11MBPS); + CONF_HW_BIT_RATE_11MBPS | CONF_TX_OFDM_RATES); struct conf_tx_rate_class { @@ -916,14 +914,6 @@ struct conf_conn_settings { u8 psm_entry_nullfunc_retries; /* - * Specifies the time to linger in active mode after successfully - * transmitting the PSM entry null-func frame. - * - * Range 0 - 255 TU's - */ - u8 psm_entry_hangover_period; - - /* * * Specifies the interval of the connection keep-alive null-func * frame in ms. @@ -1236,6 +1226,20 @@ struct conf_rate_policy_settings { u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES]; }; +struct conf_hangover_settings { + u32 recover_time; + u8 hangover_period; + u8 dynamic_mode; + u8 early_termination_mode; + u8 max_period; + u8 min_period; + u8 increase_delta; + u8 decrease_delta; + u8 quiet_time; + u8 increase_time; + u8 window_size; +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; @@ -1254,6 +1258,7 @@ struct conf_drv_settings { struct conf_rx_streaming_settings rx_streaming; struct conf_fwlog fwlog; struct conf_rate_policy_settings rate; + struct conf_hangover_settings hangover; u8 hci_io_ds; }; diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index d59354f..3999fd5 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -265,18 +265,10 @@ static ssize_t gpio_power_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; unsigned long value; int ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) { - return -EFAULT; - } - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &value); + ret = kstrtoul_from_user(user_buf, count, 10, &value); if (ret < 0) { wl1271_warning("illegal value in gpio_power"); return -EINVAL; @@ -427,17 +419,10 @@ static ssize_t dtim_interval_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; unsigned long value; int ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &value); + ret = kstrtoul_from_user(user_buf, count, 10, &value); if (ret < 0) { wl1271_warning("illegal value for dtim_interval"); return -EINVAL; @@ -492,17 +477,10 @@ static ssize_t beacon_interval_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; unsigned long value; int ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &value); + ret = kstrtoul_from_user(user_buf, count, 10, &value); if (ret < 0) { wl1271_warning("illegal value for beacon_interval"); return -EINVAL; @@ -542,17 +520,10 @@ static ssize_t rx_streaming_interval_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; unsigned long value; int ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &value); + ret = kstrtoul_from_user(user_buf, count, 10, &value); if (ret < 0) { wl1271_warning("illegal value in rx_streaming_interval!"); return -EINVAL; @@ -601,17 +572,10 @@ static ssize_t rx_streaming_always_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; unsigned long value; int ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &value); + ret = kstrtoul_from_user(user_buf, count, 10, &value); if (ret < 0) { wl1271_warning("illegal value in rx_streaming_write!"); return -EINVAL; @@ -655,6 +619,47 @@ static const struct file_operations rx_streaming_always_ops = { .llseek = default_llseek, }; +static ssize_t beacon_filtering_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + char buf[10]; + size_t len; + unsigned long value; + int ret; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + buf[len] = '\0'; + + ret = kstrtoul(buf, 0, &value); + if (ret < 0) { + wl1271_warning("illegal value for beacon_filtering!"); + return -EINVAL; + } + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_acx_beacon_filter_opt(wl, !!value); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + return count; +} + +static const struct file_operations beacon_filtering_ops = { + .write = beacon_filtering_write, + .open = wl1271_open_file_generic, + .llseek = default_llseek, +}; + static int wl1271_debugfs_add_files(struct wl1271 *wl, struct dentry *rootdir) { @@ -767,6 +772,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl, DEBUGFS_ADD(driver_state, rootdir); DEBUGFS_ADD(dtim_interval, rootdir); DEBUGFS_ADD(beacon_interval, rootdir); + DEBUGFS_ADD(beacon_filtering, rootdir); streaming = debugfs_create_dir("rx_streaming", rootdir); if (!streaming || IS_ERR(streaming)) diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index 0bd7b02..e66db69 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -171,19 +171,26 @@ static void wl1271_event_rssi_trigger(struct wl1271 *wl, wl->last_rssi_event = event; } -static void wl1271_stop_ba_event(struct wl1271 *wl, u8 ba_allowed) +static void wl1271_stop_ba_event(struct wl1271 *wl) { - /* Convert the value to bool */ - wl->ba_allowed = !!ba_allowed; - - /* - * Return in case: - * there are not BA open or the event indication is to allowed BA - */ - if ((!wl->ba_rx_bitmap) || (wl->ba_allowed)) - return; + if (wl->bss_type != BSS_TYPE_AP_BSS) { + if (!wl->ba_rx_bitmap) + return; + ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, + wl->bssid); + } else { + int i; + struct wl1271_link *lnk; + for (i = WL1271_AP_STA_HLID_START; i < AP_MAX_LINKS; i++) { + lnk = &wl->links[i]; + if (!wl1271_is_active_sta(wl, i) || !lnk->ba_bitmap) + continue; - ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, wl->bssid); + ieee80211_stop_rx_ba_session(wl->vif, + lnk->ba_bitmap, + lnk->addr); + } + } } static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl, @@ -283,12 +290,14 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_event_rssi_trigger(wl, mbox); } - if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) && !is_ap) { + if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)) { wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. " "ba_allowed = 0x%x", mbox->rx_ba_allowed); - if (wl->vif) - wl1271_stop_ba_event(wl, mbox->rx_ba_allowed); + wl->ba_allowed = !!mbox->rx_ba_allowed; + + if (wl->vif && !wl->ba_allowed) + wl1271_stop_ba_event(wl); } if ((vector & DUMMY_PACKET_EVENT_ID)) { diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index b13bebe..04db64c 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -103,6 +103,7 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl) { struct wl12xx_disconn_template *tmpl; int ret; + u32 rate; tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL); if (!tmpl) { @@ -113,9 +114,9 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl) tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH); + rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, - tmpl, sizeof(*tmpl), 0, - wl1271_tx_min_rate_get(wl)); + tmpl, sizeof(*tmpl), 0, rate); out: kfree(tmpl); @@ -126,6 +127,7 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl) { struct ieee80211_hdr_3addr *nullfunc; int ret; + u32 rate; nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL); if (!nullfunc) { @@ -142,9 +144,9 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl) memcpy(nullfunc->addr2, wl->mac_addr, ETH_ALEN); memcpy(nullfunc->addr3, wl->mac_addr, ETH_ALEN); + rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc, - sizeof(*nullfunc), 0, - wl1271_tx_min_rate_get(wl)); + sizeof(*nullfunc), 0, rate); out: kfree(nullfunc); @@ -155,6 +157,7 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl) { struct ieee80211_qos_hdr *qosnull; int ret; + u32 rate; qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL); if (!qosnull) { @@ -171,9 +174,9 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl) memcpy(qosnull->addr2, wl->mac_addr, ETH_ALEN); memcpy(qosnull->addr3, wl->mac_addr, ETH_ALEN); + rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull, - sizeof(*qosnull), 0, - wl1271_tx_min_rate_get(wl)); + sizeof(*qosnull), 0, rate); out: kfree(qosnull); @@ -498,7 +501,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl) return ret; /* use the min basic rate for AP broadcast/multicast */ - rc.enabled_rates = wl1271_tx_min_rate_get(wl); + rc.enabled_rates = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); rc.short_retry_limit = 10; rc.long_retry_limit = 10; rc.aflags = 0; @@ -707,6 +710,11 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; + /* configure hangover */ + ret = wl12xx_acx_config_hangover(wl); + if (ret < 0) + goto out_free_memmap; + return 0; out_free_memmap: diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index bde8402..7d409b0 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -239,7 +239,6 @@ static struct conf_drv_settings default_conf = { .psm_entry_retries = 8, .psm_exit_retries = 16, .psm_entry_nullfunc_retries = 3, - .psm_entry_hangover_period = 1, .keep_alive_interval = 55000, .max_listen_interval = 20, }, @@ -267,8 +266,8 @@ static struct conf_drv_settings default_conf = { }, .sched_scan = { /* sched_scan requires dwell times in TU instead of TU/1000 */ - .min_dwell_time_active = 8, - .max_dwell_time_active = 30, + .min_dwell_time_active = 30, + .max_dwell_time_active = 60, .dwell_time_passive = 100, .dwell_time_dfs = 150, .num_probe_reqs = 2, @@ -359,9 +358,23 @@ static struct conf_drv_settings default_conf = { 0x00, 0x00, 0x00, }, }, + .hangover = { + .recover_time = 0, + .hangover_period = 20, + .dynamic_mode = 1, + .early_termination_mode = 1, + .max_period = 20, + .min_period = 1, + .increase_delta = 1, + .decrease_delta = 2, + .quiet_time = 4, + .increase_time = 1, + .window_size = 16, + }, }; static char *fwlog_param; +static bool bug_on_recovery; static void __wl1271_op_remove_interface(struct wl1271 *wl, bool reset_tx_queues); @@ -757,13 +770,14 @@ static int wl1271_plt_init(struct wl1271 *wl) static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts) { - bool fw_ps; + bool fw_ps, single_sta; /* only regulate station links */ if (hlid < WL1271_AP_STA_HLID_START) return; fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); + single_sta = (wl->active_sta_count == 1); /* * Wake up from high level PS if the STA is asleep with too little @@ -772,8 +786,12 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts) if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS) wl1271_ps_link_end(wl, hlid); - /* Start high-level PS if the STA is asleep with enough blocks in FW */ - else if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) + /* + * Start high-level PS if the STA is asleep with enough blocks in FW. + * Make an exception if this is the only connected station. In this + * case FW-memory congestion is not a problem. + */ + else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) wl1271_ps_link_start(wl, hlid, true); } @@ -1213,6 +1231,8 @@ static void wl1271_recovery_work(struct work_struct *work) wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x", wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4)); + BUG_ON(bug_on_recovery); + /* * Advance security sequence number to overcome potential progress * in the firmware during recovery. This doens't hurt if the network is @@ -1222,9 +1242,6 @@ static void wl1271_recovery_work(struct work_struct *work) test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING; - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) - ieee80211_connection_loss(wl->vif); - /* Prevent spurious TX during FW restart */ ieee80211_stop_queues(wl->hw); @@ -1528,7 +1545,13 @@ out: int wl1271_tx_dummy_packet(struct wl1271 *wl) { unsigned long flags; - int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet)); + int q; + + /* no need to queue a new dummy packet if one is already pending */ + if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) + return 0; + + q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet)); spin_lock_irqsave(&wl->wl_lock, flags); set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); @@ -1802,10 +1825,16 @@ static u8 wl12xx_get_role_type(struct wl1271 *wl) { switch (wl->bss_type) { case BSS_TYPE_AP_BSS: - return WL1271_ROLE_AP; + if (wl->p2p) + return WL1271_ROLE_P2P_GO; + else + return WL1271_ROLE_AP; case BSS_TYPE_STA_BSS: - return WL1271_ROLE_STA; + if (wl->p2p) + return WL1271_ROLE_P2P_CL; + else + return WL1271_ROLE_STA; case BSS_TYPE_IBSS: return WL1271_ROLE_IBSS; @@ -1827,7 +1856,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, bool booted = false; wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", - vif->type, vif->addr); + ieee80211_vif_type_p2p(vif), vif->addr); mutex_lock(&wl->mutex); if (wl->vif) { @@ -1847,7 +1876,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, goto out; } - switch (vif->type) { + switch (ieee80211_vif_type_p2p(vif)) { + case NL80211_IFTYPE_P2P_CLIENT: + wl->p2p = 1; + /* fall-through */ case NL80211_IFTYPE_STATION: wl->bss_type = BSS_TYPE_STA_BSS; wl->set_bss_type = BSS_TYPE_STA_BSS; @@ -1856,6 +1888,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, wl->bss_type = BSS_TYPE_IBSS; wl->set_bss_type = BSS_TYPE_STA_BSS; break; + case NL80211_IFTYPE_P2P_GO: + wl->p2p = 1; + /* fall-through */ case NL80211_IFTYPE_AP: wl->bss_type = BSS_TYPE_AP_BSS; break; @@ -2051,6 +2086,7 @@ deinit: wl->ssid_len = 0; wl->bss_type = MAX_BSS_TYPE; wl->set_bss_type = MAX_BSS_TYPE; + wl->p2p = 0; wl->band = IEEE80211_BAND_2GHZ; wl->rx_counter = 0; @@ -2063,6 +2099,8 @@ deinit: wl->time_offset = 0; wl->session_counter = 0; wl->rate_set = CONF_TX_RATE_MASK_BASIC; + wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate; + wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5; wl->vif = NULL; wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; wl1271_free_ap_keys(wl); @@ -2075,6 +2113,7 @@ deinit: memset(wl->roles_map, 0, sizeof(wl->roles_map)); memset(wl->links_map, 0, sizeof(wl->links_map)); memset(wl->roc_map, 0, sizeof(wl->roc_map)); + wl->active_sta_count = 0; /* The system link is always allocated */ __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); @@ -2200,14 +2239,8 @@ out: static void wl1271_set_band_rate(struct wl1271 *wl) { - if (wl->band == IEEE80211_BAND_2GHZ) { - wl->basic_rate_set = wl->conf.tx.basic_rate; - 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; - } - + wl->basic_rate_set = wl->bitrate_masks[wl->band]; + wl->rate_set = wl->basic_rate_set; } static bool wl12xx_is_roc(struct wl1271 *wl) @@ -2236,7 +2269,7 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle) if (ret < 0) goto out; } - wl->rate_set = wl1271_tx_min_rate_get(wl); + wl->rate_set = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) goto out; @@ -2318,6 +2351,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_CHANNEL && ((wl->band != conf->channel->band) || (wl->channel != channel))) { + /* send all pending packets */ + wl1271_tx_work_locked(wl); wl->band = conf->channel->band; wl->channel = channel; @@ -2331,7 +2366,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) wl1271_set_band_rate(wl); - wl->basic_rate = wl1271_tx_min_rate_get(wl); + wl->basic_rate = + wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) wl1271_warning("rate policy for channel " @@ -3032,6 +3068,93 @@ static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb, return 0; } +static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset) +{ + int len; + const u8 *next, *end = skb->data + skb->len; + u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset, + skb->len - ieoffset); + if (!ie) + return; + len = ie[1] + 2; + next = ie + len; + memmove(ie, next, end - next); + skb_trim(skb, skb->len - len); +} + +static void wl12xx_remove_vendor_ie(struct sk_buff *skb, + unsigned int oui, u8 oui_type, + int ieoffset) +{ + int len; + const u8 *next, *end = skb->data + skb->len; + u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type, + skb->data + ieoffset, + skb->len - ieoffset); + if (!ie) + return; + len = ie[1] + 2; + next = ie + len; + memmove(ie, next, end - next); + skb_trim(skb, skb->len - len); +} + +static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, + u8 *probe_rsp_data, + size_t probe_rsp_len, + u32 rates) +{ + struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf; + u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE]; + int ssid_ie_offset, ie_offset, templ_len; + const u8 *ptr; + + /* no need to change probe response if the SSID is set correctly */ + if (wl->ssid_len > 0) + return wl1271_cmd_template_set(wl, + CMD_TEMPL_AP_PROBE_RESPONSE, + probe_rsp_data, + probe_rsp_len, 0, + rates); + + if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) { + wl1271_error("probe_rsp template too big"); + return -EINVAL; + } + + /* start searching from IE offset */ + ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + + ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset, + probe_rsp_len - ie_offset); + if (!ptr) { + wl1271_error("No SSID in beacon!"); + return -EINVAL; + } + + ssid_ie_offset = ptr - probe_rsp_data; + ptr += (ptr[1] + 2); + + memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset); + + /* insert SSID from bss_conf */ + probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID; + probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len; + memcpy(probe_rsp_templ + ssid_ie_offset + 2, + bss_conf->ssid, bss_conf->ssid_len); + templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len; + + memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len, + ptr, probe_rsp_len - (ptr - probe_rsp_data)); + templ_len += probe_rsp_len - (ptr - probe_rsp_data); + + return wl1271_cmd_template_set(wl, + CMD_TEMPL_AP_PROBE_RESPONSE, + probe_rsp_templ, + templ_len, 0, + rates); +} + static int wl1271_bss_erp_info_changed(struct wl1271 *wl, struct ieee80211_bss_conf *bss_conf, u32 changed) @@ -3088,6 +3211,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, if ((changed & BSS_CHANGED_BEACON)) { struct ieee80211_hdr *hdr; + u32 min_rate; int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable); struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif); @@ -3103,28 +3227,46 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, dev_kfree_skb(beacon); goto out; } + min_rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON : CMD_TEMPL_BEACON; ret = wl1271_cmd_template_set(wl, tmpl_id, beacon->data, beacon->len, 0, - wl1271_tx_min_rate_get(wl)); + min_rate); if (ret < 0) { dev_kfree_skb(beacon); goto out; } + /* remove TIM ie from probe response */ + wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset); + + /* + * remove p2p ie from probe response. + * the fw reponds to probe requests that don't include + * the p2p ie. probe requests with p2p ie will be passed, + * and will be responded by the supplicant (the spec + * forbids including the p2p ie when responding to probe + * requests that didn't include it). + */ + wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA, + WLAN_OUI_TYPE_WFA_P2P, ieoffset); + hdr = (struct ieee80211_hdr *) beacon->data; hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); - - tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE : - CMD_TEMPL_PROBE_RESPONSE; - ret = wl1271_cmd_template_set(wl, - tmpl_id, - beacon->data, - beacon->len, 0, - wl1271_tx_min_rate_get(wl)); + if (is_ap) + ret = wl1271_ap_set_probe_resp_tmpl(wl, + beacon->data, + beacon->len, + min_rate); + else + ret = wl1271_cmd_template_set(wl, + CMD_TEMPL_PROBE_RESPONSE, + beacon->data, + beacon->len, 0, + min_rate); dev_kfree_skb(beacon); if (ret < 0) goto out; @@ -3145,8 +3287,10 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, if ((changed & BSS_CHANGED_BASIC_RATES)) { u32 rates = bss_conf->basic_rates; - wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates); - wl->basic_rate = wl1271_tx_min_rate_get(wl); + wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates, + wl->band); + wl->basic_rate = wl1271_tx_min_rate_get(wl, + wl->basic_rate_set); ret = wl1271_init_ap_rates(wl); if (ret < 0) { @@ -3328,12 +3472,15 @@ sta_not_found: * to use with control frames. */ rates = bss_conf->basic_rates; - wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, - rates); - wl->basic_rate = wl1271_tx_min_rate_get(wl); + wl->basic_rate_set = + wl1271_tx_enabled_rates_get(wl, rates, + wl->band); + wl->basic_rate = + wl1271_tx_min_rate_get(wl, wl->basic_rate_set); if (sta_rate_set) wl->rate_set = wl1271_tx_enabled_rates_get(wl, - sta_rate_set); + sta_rate_set, + wl->band); ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) goto out; @@ -3380,7 +3527,8 @@ sta_not_found: /* revert back to minimum rates for the current band */ wl1271_set_band_rate(wl); - wl->basic_rate = wl1271_tx_min_rate_get(wl); + wl->basic_rate = + wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) goto out; @@ -3431,11 +3579,13 @@ sta_not_found: if (bss_conf->ibss_joined) { u32 rates = bss_conf->basic_rates; - wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, - rates); - wl->basic_rate = wl1271_tx_min_rate_get(wl); + wl->basic_rate_set = + wl1271_tx_enabled_rates_get(wl, rates, + wl->band); + wl->basic_rate = + wl1271_tx_min_rate_get(wl, wl->basic_rate_set); - /* by default, use 11b rates */ + /* by default, use 11b + OFDM rates */ wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES; ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) @@ -3665,7 +3815,8 @@ out: return ret; } -static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw) +static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct wl1271 *wl = hw->priv; @@ -3729,14 +3880,18 @@ static int wl1271_allocate_sta(struct wl1271 *wl, wl_sta->hlid = WL1271_AP_STA_HLID_START + id; *hlid = wl_sta->hlid; memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN); + wl->active_sta_count++; return 0; } -static void wl1271_free_sta(struct wl1271 *wl, u8 hlid) +void wl1271_free_sta(struct wl1271 *wl, u8 hlid) { int id = hlid - WL1271_AP_STA_HLID_START; - if (WARN_ON(!test_bit(id, wl->ap_hlid_map))) + if (hlid < WL1271_AP_STA_HLID_START) + return; + + if (!test_bit(id, wl->ap_hlid_map)) return; clear_bit(id, wl->ap_hlid_map); @@ -3745,6 +3900,7 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid) wl1271_tx_reset_link_queues(wl, hlid); __clear_bit(hlid, &wl->ap_ps_map); __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); + wl->active_sta_count--; } static int wl1271_op_sta_add(struct ieee80211_hw *hw, @@ -3950,6 +4106,29 @@ out: return ret; } +static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct wl1271 *wl = hw->priv; + int i; + + wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x", + mask->control[NL80211_BAND_2GHZ].legacy, + mask->control[NL80211_BAND_5GHZ].legacy); + + mutex_lock(&wl->mutex); + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) + wl->bitrate_masks[i] = + wl1271_tx_enabled_rates_get(wl, + mask->control[i].legacy, + i); + mutex_unlock(&wl->mutex); + + return 0; +} + static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; @@ -4066,7 +4245,6 @@ static const u8 wl1271_rate_to_idx_2ghz[] = { /* 11n STA capabilities */ #define HW_RX_HIGHEST_RATE 72 -#ifdef CONFIG_WL12XX_HT #define WL12XX_HT_CAP { \ .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \ (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \ @@ -4079,11 +4257,6 @@ static const u8 wl1271_rate_to_idx_2ghz[] = { .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ }, \ } -#else -#define WL12XX_HT_CAP { \ - .ht_supported = false, \ -} -#endif /* can't be const, mac80211 writes to this */ static struct ieee80211_supported_band wl1271_band_2ghz = { @@ -4231,6 +4404,7 @@ static const struct ieee80211_ops wl1271_ops = { .sta_remove = wl1271_op_sta_remove, .ampdu_action = wl1271_op_ampdu_action, .tx_frames_pending = wl1271_tx_frames_pending, + .set_bitrate_mask = wl12xx_set_bitrate_mask, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; @@ -4483,15 +4657,19 @@ int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_SUPPORTS_CQM_RSSI | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_AP_LINK_PS; + IEEE80211_HW_AP_LINK_PS | + IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_TX_AMPDU_SETUP_IN_HW; wl->hw->wiphy->cipher_suites = cipher_suites; wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); + BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); wl->hw->wiphy->max_scan_ssids = 1; - wl->hw->wiphy->max_sched_scan_ssids = 8; + wl->hw->wiphy->max_sched_scan_ssids = 16; + wl->hw->wiphy->max_match_sets = 16; /* * Maximum length of elements in scanning probe request templates * should be the maximum length possible for a template, without @@ -4500,6 +4678,8 @@ int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE - sizeof(struct ieee80211_header); + wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; + /* make sure all our channels fit in the scanned_ch bitmask */ BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + ARRAY_SIZE(wl1271_channels_5ghz) > @@ -4543,6 +4723,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void) int i, j, ret; unsigned int order; + BUILD_BUG_ON(AP_MAX_LINKS > WL12XX_MAX_LINKS); + hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); if (!hw) { wl1271_error("could not alloc ieee80211_hw"); @@ -4625,6 +4807,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->session_counter = 0; wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID; wl->ap_global_hlid = WL12XX_INVALID_LINK_ID; + wl->active_sta_count = 0; setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer, (unsigned long) wl); wl->fwlog_size = 0; @@ -4644,6 +4827,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void) /* Apply default driver configuration. */ wl1271_conf_init(wl); + wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate; + wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5; order = get_order(WL1271_AGGR_BUFFER_SIZE); wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); @@ -4776,6 +4961,9 @@ module_param_named(fwlog, fwlog_param, charp, 0); MODULE_PARM_DESC(keymap, "FW logger options: continuous, ondemand, dbgpins or disable"); +module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery"); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index 4b720b1..c15ebf2 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -199,15 +199,19 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid) unsigned long flags; int filtered[NUM_TX_QUEUES]; - /* filter all frames currently the low level queus for this hlid */ + /* filter all frames currently in the low level queues for this hlid */ for (i = 0; i < NUM_TX_QUEUES; i++) { filtered[i] = 0; while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { + filtered[i]++; + + if (WARN_ON(wl12xx_is_dummy_packet(wl, skb))) + continue; + info = IEEE80211_SKB_CB(skb); info->flags |= IEEE80211_TX_STAT_TX_FILTERED; info->status.rates[0].idx = -1; ieee80211_tx_status_ni(wl->hw, skb); - filtered[i]++; } } diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 78d8410..dee4cfe 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -66,11 +66,9 @@ static void wl1271_rx_status(struct wl1271 *wl, status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band); -#ifdef CONFIG_WL12XX_HT /* 11n support */ if (desc->rate <= CONF_HW_RXTX_RATE_MCS0) status->flag |= RX_FLAG_HT; -#endif status->signal = desc->rssi; @@ -107,6 +105,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, u8 beacon = 0; u8 is_data = 0; u8 reserved = unaligned ? NET_IP_ALIGN : 0; + u16 seq_num; /* * In PLT mode we seem to get frames and mac80211 warns about them, @@ -169,9 +168,11 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); - wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, + seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d", skb, skb->len - desc->pad_len, - beacon ? "beacon" : ""); + beacon ? "beacon" : "", + seq_num); skb_trim(skb, skb->len - desc->pad_len); diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index af4ad23..128ccb7 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -28,6 +28,7 @@ #include "scan.h" #include "acx.h" #include "ps.h" +#include "tx.h" void wl1271_scan_complete_work(struct work_struct *work) { @@ -65,8 +66,9 @@ void wl1271_scan_complete_work(struct work_struct *work) /* return to ROC if needed */ is_sta = (wl->bss_type == BSS_TYPE_STA_BSS); is_ibss = (wl->bss_type == BSS_TYPE_IBSS); - if ((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) || - (is_ibss && !test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))) { + if (((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) || + (is_ibss && !test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))) && + !test_bit(wl->dev_role_id, wl->roc_map)) { /* restore remain on channel */ wl12xx_cmd_role_start_dev(wl); wl12xx_roc(wl, wl->dev_role_id); @@ -98,14 +100,18 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, for (i = 0, j = 0; i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS; i++) { - flags = req->channels[i]->flags; if (!test_bit(i, wl->scan.scanned_ch) && !(flags & IEEE80211_CHAN_DISABLED) && - ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) && - (req->channels[i]->band == band)) { - + (req->channels[i]->band == band) && + /* + * In passive scans, we scan all remaining + * channels, even if not marked as such. + * In active scans, we only scan channels not + * marked as passive. + */ + (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) { wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", req->channels[i]->band, req->channels[i]->center_freq); @@ -157,6 +163,10 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, int ret; u16 scan_options = 0; + /* skip active scans if we don't have SSIDs */ + if (!passive && wl->scan.req->n_ssids == 0) + return WL1271_NOTHING_TO_SCAN; + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); if (!cmd || !trigger) { @@ -164,11 +174,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, goto out; } - /* We always use high priority scans */ - scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH; - - /* No SSIDs means that we have a forced passive scan */ - if (passive || wl->scan.req->n_ssids == 0) + if (passive) scan_options |= WL1271_SCAN_OPT_PASSIVE; if (WARN_ON(wl->role_id == WL12XX_INVALID_ROLE_ID)) { @@ -238,14 +244,17 @@ out: void wl1271_scan_stm(struct wl1271 *wl) { int ret = 0; + enum ieee80211_band band; + u32 rate; switch (wl->scan.state) { case WL1271_SCAN_STATE_IDLE: break; case WL1271_SCAN_STATE_2GHZ_ACTIVE: - ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false, - wl->conf.tx.basic_rate); + band = IEEE80211_BAND_2GHZ; + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); + ret = wl1271_scan_send(wl, band, false, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; wl1271_scan_stm(wl); @@ -254,8 +263,9 @@ void wl1271_scan_stm(struct wl1271 *wl) break; case WL1271_SCAN_STATE_2GHZ_PASSIVE: - ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true, - wl->conf.tx.basic_rate); + band = IEEE80211_BAND_2GHZ; + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); + ret = wl1271_scan_send(wl, band, true, rate); if (ret == WL1271_NOTHING_TO_SCAN) { if (wl->enable_11a) wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; @@ -267,8 +277,9 @@ void wl1271_scan_stm(struct wl1271 *wl) break; case WL1271_SCAN_STATE_5GHZ_ACTIVE: - ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false, - wl->conf.tx.basic_rate_5); + band = IEEE80211_BAND_5GHZ; + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); + ret = wl1271_scan_send(wl, band, false, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; wl1271_scan_stm(wl); @@ -277,8 +288,9 @@ void wl1271_scan_stm(struct wl1271 *wl) break; case WL1271_SCAN_STATE_5GHZ_PASSIVE: - ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true, - wl->conf.tx.basic_rate_5); + band = IEEE80211_BAND_5GHZ; + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); + ret = wl1271_scan_send(wl, band, true, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_DONE; wl1271_scan_stm(wl); @@ -473,34 +485,86 @@ 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 */ +/* Returns the scan type to be 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; + struct cfg80211_match_set *sets = req->match_sets; + struct cfg80211_ssid *ssids = req->ssids; + int ret = 0, type, i, j, n_match_ssids = 0; wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list"); + /* count the match sets that contain SSIDs */ + for (i = 0; i < req->n_match_sets; i++) + if (sets[i].ssid.ssid_len > 0) + n_match_ssids++; + + /* No filter, no ssids or only bcast ssid */ + if (!n_match_ssids && + (!req->n_ssids || + (req->n_ssids == 1 && req->ssids[0].ssid_len == 0))) { + type = SCAN_SSID_FILTER_ANY; + goto out; + } + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + if (!n_match_ssids) { + /* No filter, with ssids */ + type = SCAN_SSID_FILTER_DISABLED; + + for (i = 0; i < req->n_ssids; i++) { + cmd->ssids[cmd->n_ssids].type = (ssids[i].ssid_len) ? + SCAN_SSID_TYPE_HIDDEN : SCAN_SSID_TYPE_PUBLIC; + cmd->ssids[cmd->n_ssids].len = ssids[i].ssid_len; + memcpy(cmd->ssids[cmd->n_ssids].ssid, ssids[i].ssid, + ssids[i].ssid_len); + cmd->n_ssids++; + } + } else { + type = SCAN_SSID_FILTER_LIST; + + /* Add all SSIDs from the filters */ + for (i = 0; i < req->n_match_sets; i++) { + /* ignore sets without SSIDs */ + if (!sets[i].ssid.ssid_len) + continue; - while ((cmd->n_ssids < req->n_ssids) && ssid) { - if (ssid->ssid_len == 0) { - wildcard = 1; 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 = sets[i].ssid.ssid_len; + memcpy(cmd->ssids[cmd->n_ssids].ssid, + sets[i].ssid.ssid, sets[i].ssid.ssid_len); + cmd->n_ssids++; + } + if ((req->n_ssids > 1) || + (req->n_ssids == 1 && req->ssids[0].ssid_len > 0)) { + /* + * Mark all the SSIDs passed in the SSID list as HIDDEN, + * so they're used in probe requests. + */ + for (i = 0; i < req->n_ssids; i++) { + for (j = 0; j < cmd->n_ssids; j++) + if (!memcmp(req->ssids[i].ssid, + cmd->ssids[j].ssid, + req->ssids[i].ssid_len)) { + cmd->ssids[j].type = + SCAN_SSID_TYPE_HIDDEN; + break; + } + /* Fail if SSID isn't present in the filters */ + if (j == req->n_ssids) { + ret = -EINVAL; + goto out_free; + } + } } - 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)); @@ -509,13 +573,15 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("cmd sched scan ssid list failed"); - goto out; + goto out_free; } - ret = wildcard; -out: +out_free: kfree(cmd); - return ret; +out: + if (ret < 0) + return ret; + return type; } int wl1271_scan_sched_scan_config(struct wl1271 *wl, @@ -550,21 +616,13 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, cfg->intervals[i] = cpu_to_le32(req->interval); 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; - } 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; - } - } + ret = wl12xx_scan_sched_scan_ssid_list(wl, req); + if (ret < 0) + goto out; + + cfg->filter_type = ret; + + wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type); if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) { wl1271_error("scan channel list is empty"); diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c index c361049..f25d5d9 100644 --- a/drivers/net/wireless/wl12xx/sdio_test.c +++ b/drivers/net/wireless/wl12xx/sdio_test.c @@ -30,6 +30,7 @@ #include <linux/mmc/sdio_func.h> #include <linux/mmc/sdio_ids.h> #include <linux/mmc/card.h> +#include <linux/mmc/host.h> #include <linux/gpio.h> #include <linux/wl12xx.h> #include <linux/kthread.h> @@ -142,14 +143,23 @@ static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable) ret = pm_runtime_get_sync(&func->dev); if (ret < 0) goto out; + + /* Runtime PM might be disabled, power up the card manually */ + ret = mmc_power_restore_host(func->card->host); + if (ret < 0) + goto out; + sdio_claim_host(func); sdio_enable_func(func); - sdio_release_host(func); } else { - sdio_claim_host(func); sdio_disable_func(func); sdio_release_host(func); + /* Runtime PM might be disabled, power off the card manually */ + ret = mmc_power_save_host(func->card->host); + if (ret < 0) + goto out; + /* Power down the card */ ret = pm_runtime_put_sync(&func->dev); } @@ -433,7 +443,6 @@ static int __devinit wl1271_probe(struct sdio_func *func, sdio_set_drvdata(func, wl_test); - /* power up the device */ ret = wl1271_chip_wakeup(wl); if (ret) { diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 08227e6..bad9e29 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -30,6 +30,7 @@ #include "reg.h" #include "ps.h" #include "tx.h" +#include "event.h" static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id) { @@ -80,8 +81,7 @@ static int wl1271_tx_update_filters(struct wl1271 *wl, struct ieee80211_hdr *hdr; int ret; - hdr = (struct ieee80211_hdr *)(skb->data + - sizeof(struct wl1271_tx_hw_descr)); + hdr = (struct ieee80211_hdr *)skb->data; /* * stop bssid-based filtering before transmitting authentication @@ -125,25 +125,31 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) { - bool fw_ps; + bool fw_ps, single_sta; u8 tx_pkts; /* only regulate station links */ if (hlid < WL1271_AP_STA_HLID_START) return; + if (WARN_ON(!wl1271_is_active_sta(wl, hlid))) + return; + fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); tx_pkts = wl->links[hlid].allocated_pkts; + single_sta = (wl->active_sta_count == 1); /* * if in FW PS and there is enough data in FW we can put the link * into high-level PS and clean out its TX queues. + * Make an exception if this is the only connected station. In this + * case FW-memory congestion is not a problem. */ - if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) + if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) wl1271_ps_link_start(wl, hlid, true); } -static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) +bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) { return wl->dummy_packet == skb; } @@ -174,14 +180,20 @@ u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb) static u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + if (wl12xx_is_dummy_packet(wl, skb)) return wl->system_hlid; if (wl->bss_type == BSS_TYPE_AP_BSS) return wl12xx_tx_get_hlid_ap(wl, skb); - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) || - test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags)) + wl1271_tx_update_filters(wl, skb); + + if ((test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) || + test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags)) && + !ieee80211_is_auth(hdr->frame_control) && + !ieee80211_is_assoc_req(hdr->frame_control)) return wl->sta_hlid; else return wl->dev_hlid; @@ -416,8 +428,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, if (wl->bss_type == BSS_TYPE_AP_BSS) { wl1271_tx_ap_update_inconnection_sta(wl, skb); wl1271_tx_regulate_link(wl, hlid); - } else { - wl1271_tx_update_filters(wl, skb); } /* @@ -440,20 +450,20 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, return total_len; } -u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) +u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, + enum ieee80211_band rate_band) { struct ieee80211_supported_band *band; u32 enabled_rates = 0; int bit; - band = wl->hw->wiphy->bands[wl->band]; + band = wl->hw->wiphy->bands[rate_band]; for (bit = 0; bit < band->n_bitrates; bit++) { if (rate_set & 0x1) enabled_rates |= band->bitrates[bit].hw_value; rate_set >>= 1; } -#ifdef CONFIG_WL12XX_HT /* MCS rates indication are on bits 16 - 23 */ rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; @@ -462,7 +472,6 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); rate_set >>= 1; } -#endif return enabled_rates; } @@ -886,6 +895,7 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) /* TX failure */ if (wl->bss_type == BSS_TYPE_AP_BSS) { for (i = 0; i < AP_MAX_LINKS; i++) { + wl1271_free_sta(wl, i); wl1271_tx_reset_link_queues(wl, i); wl->links[i].allocated_pkts = 0; wl->links[i].prev_freed_pkts = 0; @@ -905,10 +915,14 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) ieee80211_tx_status_ni(wl->hw, skb); } } - wl->tx_queue_count[i] = 0; } + + wl->ba_rx_bitmap = 0; } + for (i = 0; i < NUM_TX_QUEUES; i++) + wl->tx_queue_count[i] = 0; + wl->stopped_queues_map = 0; /* @@ -976,20 +990,10 @@ void wl1271_tx_flush(struct wl1271 *wl) wl1271_warning("Unable to flush all TX buffers, timed out."); } -u32 wl1271_tx_min_rate_get(struct wl1271 *wl) +u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set) { - int i; - u32 rate = 0; - - if (!wl->basic_rate_set) { - WARN_ON(1); - wl->basic_rate_set = wl->conf.tx.basic_rate; - } - - for (i = 0; !rate; i++) { - if ((wl->basic_rate_set >> i) & 0x1) - rate = 1 << i; - } + if (WARN_ON(!rate_set)) + return 0; - return rate; + return BIT(__ffs(rate_set)); } diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index 6519be4..dc4f09a 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -209,10 +209,15 @@ void wl1271_tx_complete(struct wl1271 *wl); void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues); void wl1271_tx_flush(struct wl1271 *wl); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); -u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); -u32 wl1271_tx_min_rate_get(struct wl1271 *wl); +u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, + enum ieee80211_band rate_band); +u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set); u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb); void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid); void wl1271_handle_tx_low_watermark(struct wl1271 *wl); +bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb); + +/* from main.c */ +void wl1271_free_sta(struct wl1271 *wl, u8 hlid); #endif diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index fb2753c..997f532 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -138,7 +138,7 @@ extern u32 wl12xx_debug_level; #define WL1271_DEFAULT_DTIM_PERIOD 1 #define WL12XX_MAX_ROLES 4 -#define WL12XX_MAX_LINKS 8 +#define WL12XX_MAX_LINKS 12 #define WL12XX_INVALID_ROLE_ID 0xff #define WL12XX_INVALID_LINK_ID 0xff @@ -234,14 +234,14 @@ struct wl1271_stats { #define NUM_TX_QUEUES 4 #define NUM_RX_PKT_DESC 8 -#define AP_MAX_STATIONS 5 +#define AP_MAX_STATIONS 8 /* Broadcast and Global links + system link + links to stations */ /* * TODO: when WL1271_AP_STA_HLID_START is no longer constant, change all * the places that use this. */ -#define AP_MAX_LINKS (AP_MAX_STATIONS + 3) +#define AP_MAX_LINKS (AP_MAX_STATIONS + WL1271_AP_STA_HLID_START) /* FW status registers */ struct wl12xx_fw_status { @@ -279,7 +279,7 @@ struct wl12xx_fw_status { /* Cumulative counter of released Voice memory blocks */ u8 tx_voice_released_blks; - u8 padding_1[7]; + u8 padding_1[3]; __le32 log_start_addr; } __packed; @@ -402,6 +402,7 @@ struct wl1271 { u8 mac_addr[ETH_ALEN]; u8 bss_type; u8 set_bss_type; + u8 p2p; /* we are using p2p role */ u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; u8 ssid_len; int channel; @@ -525,6 +526,7 @@ struct wl1271 { u32 basic_rate_set; u32 basic_rate; u32 rate_set; + u32 bitrate_masks[IEEE80211_NUM_BANDS]; /* The current band */ enum ieee80211_band band; @@ -626,6 +628,9 @@ struct wl1271 { /* number of currently active RX BA sessions */ int ba_rx_session_count; + + /* AP-mode - number of currently connected stations */ + int active_sta_count; }; struct wl1271_station { |