Commit 376cf5d3 authored by John W. Linville's avatar John W. Linville

Merge branch 'for-linville' of git://github.com/lucacoelho/wl12xx

parents 12e62d6f 045c745f
...@@ -19,16 +19,6 @@ config WL12XX ...@@ -19,16 +19,6 @@ config WL12XX
If you choose to build a module, it will be called wl12xx. Say N if If you choose to build a module, it will be called wl12xx. Say N if
unsure. 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 config WL12XX_SPI
tristate "TI wl12xx SPI support" tristate "TI wl12xx SPI support"
depends on WL12XX && SPI_MASTER depends on WL12XX && SPI_MASTER
......
...@@ -1691,3 +1691,43 @@ int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl) ...@@ -1691,3 +1691,43 @@ int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl)
kfree(acx); kfree(acx);
return ret; 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;
}
...@@ -1144,6 +1144,23 @@ struct wl12xx_acx_set_rate_mgmt_params { ...@@ -1144,6 +1144,23 @@ struct wl12xx_acx_set_rate_mgmt_params {
u8 padding2[2]; u8 padding2[2];
} __packed; } __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 { enum {
ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003, ACX_MEM_CFG = 0x0003,
...@@ -1281,5 +1298,6 @@ int wl1271_acx_config_ps(struct wl1271 *wl); ...@@ -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_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
int wl1271_acx_fm_coex(struct wl1271 *wl); int wl1271_acx_fm_coex(struct wl1271 *wl);
int wl12xx_acx_set_rate_mgmt_params(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__ */ #endif /* __WL1271_ACX_H__ */
...@@ -895,7 +895,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) ...@@ -895,7 +895,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
struct acx_header *acx = buf; struct acx_header *acx = buf;
int ret; int ret;
wl1271_debug(DEBUG_CMD, "cmd configure"); wl1271_debug(DEBUG_CMD, "cmd configure (%d)", id);
acx->id = cpu_to_le16(id); acx->id = cpu_to_le16(id);
...@@ -1413,7 +1413,7 @@ int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid) ...@@ -1413,7 +1413,7 @@ int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid)
int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
{ {
struct wl12xx_cmd_add_peer *cmd; struct wl12xx_cmd_add_peer *cmd;
int ret; int i, ret;
u32 sta_rates; u32 sta_rates;
wl1271_debug(DEBUG_CMD, "cmd add peer %d", (int)hlid); wl1271_debug(DEBUG_CMD, "cmd add peer %d", (int)hlid);
...@@ -1424,15 +1424,19 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) ...@@ -1424,15 +1424,19 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
goto out; goto out;
} }
/* currently we don't support UAPSD */
cmd->sp_len = 0;
memcpy(cmd->addr, sta->addr, ETH_ALEN); memcpy(cmd->addr, sta->addr, ETH_ALEN);
cmd->bss_index = WL1271_AP_BSS_INDEX; cmd->bss_index = WL1271_AP_BSS_INDEX;
cmd->aid = sta->aid; cmd->aid = sta->aid;
cmd->hlid = hlid; cmd->hlid = hlid;
cmd->sp_len = sta->max_sp;
cmd->wmm = sta->wme ? 1 : 0; 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]; sta_rates = sta->supp_rates[wl->band];
if (sta->ht_cap.ht_supported) if (sta->ht_cap.ht_supported)
sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET; sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET;
...@@ -1440,7 +1444,8 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) ...@@ -1440,7 +1444,8 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
cmd->supported_rates = 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));
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); ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0);
if (ret < 0) { if (ret < 0) {
......
...@@ -591,6 +591,13 @@ enum wl12xx_ssid_type { ...@@ -591,6 +591,13 @@ enum wl12xx_ssid_type {
WL12XX_SSID_TYPE_ANY = 2, 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 wl12xx_cmd_add_peer {
struct wl1271_cmd_header header; struct wl1271_cmd_header header;
......
...@@ -915,14 +915,6 @@ struct conf_conn_settings { ...@@ -915,14 +915,6 @@ struct conf_conn_settings {
*/ */
u8 psm_entry_nullfunc_retries; 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 * Specifies the interval of the connection keep-alive null-func
...@@ -1236,6 +1228,20 @@ struct conf_rate_policy_settings { ...@@ -1236,6 +1228,20 @@ struct conf_rate_policy_settings {
u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES]; 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_drv_settings {
struct conf_sg_settings sg; struct conf_sg_settings sg;
struct conf_rx_settings rx; struct conf_rx_settings rx;
...@@ -1254,6 +1260,7 @@ struct conf_drv_settings { ...@@ -1254,6 +1260,7 @@ struct conf_drv_settings {
struct conf_rx_streaming_settings rx_streaming; struct conf_rx_streaming_settings rx_streaming;
struct conf_fwlog fwlog; struct conf_fwlog fwlog;
struct conf_rate_policy_settings rate; struct conf_rate_policy_settings rate;
struct conf_hangover_settings hangover;
u8 hci_io_ds; u8 hci_io_ds;
}; };
......
...@@ -265,18 +265,10 @@ static ssize_t gpio_power_write(struct file *file, ...@@ -265,18 +265,10 @@ static ssize_t gpio_power_write(struct file *file,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct wl1271 *wl = file->private_data; struct wl1271 *wl = file->private_data;
char buf[10];
size_t len;
unsigned long value; unsigned long value;
int ret; int ret;
len = min(count, sizeof(buf) - 1); ret = kstrtoul_from_user(user_buf, count, 10, &value);
if (copy_from_user(buf, user_buf, len)) {
return -EFAULT;
}
buf[len] = '\0';
ret = kstrtoul(buf, 0, &value);
if (ret < 0) { if (ret < 0) {
wl1271_warning("illegal value in gpio_power"); wl1271_warning("illegal value in gpio_power");
return -EINVAL; return -EINVAL;
...@@ -427,17 +419,10 @@ static ssize_t dtim_interval_write(struct file *file, ...@@ -427,17 +419,10 @@ static ssize_t dtim_interval_write(struct file *file,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct wl1271 *wl = file->private_data; struct wl1271 *wl = file->private_data;
char buf[10];
size_t len;
unsigned long value; unsigned long value;
int ret; int ret;
len = min(count, sizeof(buf) - 1); ret = kstrtoul_from_user(user_buf, count, 10, &value);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
ret = kstrtoul(buf, 0, &value);
if (ret < 0) { if (ret < 0) {
wl1271_warning("illegal value for dtim_interval"); wl1271_warning("illegal value for dtim_interval");
return -EINVAL; return -EINVAL;
...@@ -492,17 +477,10 @@ static ssize_t beacon_interval_write(struct file *file, ...@@ -492,17 +477,10 @@ static ssize_t beacon_interval_write(struct file *file,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct wl1271 *wl = file->private_data; struct wl1271 *wl = file->private_data;
char buf[10];
size_t len;
unsigned long value; unsigned long value;
int ret; int ret;
len = min(count, sizeof(buf) - 1); ret = kstrtoul_from_user(user_buf, count, 10, &value);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
ret = kstrtoul(buf, 0, &value);
if (ret < 0) { if (ret < 0) {
wl1271_warning("illegal value for beacon_interval"); wl1271_warning("illegal value for beacon_interval");
return -EINVAL; return -EINVAL;
...@@ -542,17 +520,10 @@ static ssize_t rx_streaming_interval_write(struct file *file, ...@@ -542,17 +520,10 @@ static ssize_t rx_streaming_interval_write(struct file *file,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct wl1271 *wl = file->private_data; struct wl1271 *wl = file->private_data;
char buf[10];
size_t len;
unsigned long value; unsigned long value;
int ret; int ret;
len = min(count, sizeof(buf) - 1); ret = kstrtoul_from_user(user_buf, count, 10, &value);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
ret = kstrtoul(buf, 0, &value);
if (ret < 0) { if (ret < 0) {
wl1271_warning("illegal value in rx_streaming_interval!"); wl1271_warning("illegal value in rx_streaming_interval!");
return -EINVAL; return -EINVAL;
...@@ -601,17 +572,10 @@ static ssize_t rx_streaming_always_write(struct file *file, ...@@ -601,17 +572,10 @@ static ssize_t rx_streaming_always_write(struct file *file,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct wl1271 *wl = file->private_data; struct wl1271 *wl = file->private_data;
char buf[10];
size_t len;
unsigned long value; unsigned long value;
int ret; int ret;
len = min(count, sizeof(buf) - 1); ret = kstrtoul_from_user(user_buf, count, 10, &value);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
ret = kstrtoul(buf, 0, &value);
if (ret < 0) { if (ret < 0) {
wl1271_warning("illegal value in rx_streaming_write!"); wl1271_warning("illegal value in rx_streaming_write!");
return -EINVAL; return -EINVAL;
...@@ -655,6 +619,47 @@ static const struct file_operations rx_streaming_always_ops = { ...@@ -655,6 +619,47 @@ static const struct file_operations rx_streaming_always_ops = {
.llseek = default_llseek, .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, static int wl1271_debugfs_add_files(struct wl1271 *wl,
struct dentry *rootdir) struct dentry *rootdir)
{ {
...@@ -767,6 +772,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl, ...@@ -767,6 +772,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
DEBUGFS_ADD(driver_state, rootdir); DEBUGFS_ADD(driver_state, rootdir);
DEBUGFS_ADD(dtim_interval, rootdir); DEBUGFS_ADD(dtim_interval, rootdir);
DEBUGFS_ADD(beacon_interval, rootdir); DEBUGFS_ADD(beacon_interval, rootdir);
DEBUGFS_ADD(beacon_filtering, rootdir);
streaming = debugfs_create_dir("rx_streaming", rootdir); streaming = debugfs_create_dir("rx_streaming", rootdir);
if (!streaming || IS_ERR(streaming)) if (!streaming || IS_ERR(streaming))
......
...@@ -171,19 +171,26 @@ static void wl1271_event_rssi_trigger(struct wl1271 *wl, ...@@ -171,19 +171,26 @@ static void wl1271_event_rssi_trigger(struct wl1271 *wl,
wl->last_rssi_event = event; 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 */ if (wl->bss_type != BSS_TYPE_AP_BSS) {
wl->ba_allowed = !!ba_allowed; if (!wl->ba_rx_bitmap)
return;
/* ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap,
* Return in case: wl->bssid);
* there are not BA open or the event indication is to allowed BA } else {
*/ int i;
if ((!wl->ba_rx_bitmap) || (wl->ba_allowed)) struct wl1271_link *lnk;
return; for (i = WL1271_AP_STA_HLID_START; i < WL12XX_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, 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) ...@@ -283,12 +290,14 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
wl1271_event_rssi_trigger(wl, 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. " wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
"ba_allowed = 0x%x", mbox->rx_ba_allowed); "ba_allowed = 0x%x", mbox->rx_ba_allowed);
if (wl->vif) wl->ba_allowed = !!mbox->rx_ba_allowed;
wl1271_stop_ba_event(wl, mbox->rx_ba_allowed);
if (wl->vif && !wl->ba_allowed)
wl1271_stop_ba_event(wl);
} }
if ((vector & DUMMY_PACKET_EVENT_ID)) { if ((vector & DUMMY_PACKET_EVENT_ID)) {
......
...@@ -707,6 +707,11 @@ int wl1271_hw_init(struct wl1271 *wl) ...@@ -707,6 +707,11 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
goto out_free_memmap; goto out_free_memmap;
/* configure hangover */
ret = wl12xx_acx_config_hangover(wl);
if (ret < 0)
goto out_free_memmap;
return 0; return 0;
out_free_memmap: out_free_memmap:
......
...@@ -239,7 +239,6 @@ static struct conf_drv_settings default_conf = { ...@@ -239,7 +239,6 @@ static struct conf_drv_settings default_conf = {
.psm_entry_retries = 8, .psm_entry_retries = 8,
.psm_exit_retries = 16, .psm_exit_retries = 16,
.psm_entry_nullfunc_retries = 3, .psm_entry_nullfunc_retries = 3,
.psm_entry_hangover_period = 1,
.keep_alive_interval = 55000, .keep_alive_interval = 55000,
.max_listen_interval = 20, .max_listen_interval = 20,
}, },
...@@ -267,8 +266,8 @@ static struct conf_drv_settings default_conf = { ...@@ -267,8 +266,8 @@ static struct conf_drv_settings default_conf = {
}, },
.sched_scan = { .sched_scan = {
/* sched_scan requires dwell times in TU instead of TU/1000 */ /* sched_scan requires dwell times in TU instead of TU/1000 */
.min_dwell_time_active = 8, .min_dwell_time_active = 30,
.max_dwell_time_active = 30, .max_dwell_time_active = 60,
.dwell_time_passive = 100, .dwell_time_passive = 100,
.dwell_time_dfs = 150, .dwell_time_dfs = 150,
.num_probe_reqs = 2, .num_probe_reqs = 2,
...@@ -359,9 +358,23 @@ static struct conf_drv_settings default_conf = { ...@@ -359,9 +358,23 @@ static struct conf_drv_settings default_conf = {
0x00, 0x00, 0x00, 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 char *fwlog_param;
static bool bug_on_recovery;
static void __wl1271_op_remove_interface(struct wl1271 *wl, static void __wl1271_op_remove_interface(struct wl1271 *wl,
bool reset_tx_queues); bool reset_tx_queues);
...@@ -757,13 +770,14 @@ static int wl1271_plt_init(struct wl1271 *wl) ...@@ -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) 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 */ /* only regulate station links */
if (hlid < WL1271_AP_STA_HLID_START) if (hlid < WL1271_AP_STA_HLID_START)
return; return;
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); 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 * 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) ...@@ -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) if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
wl1271_ps_link_end(wl, hlid); 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); wl1271_ps_link_start(wl, hlid, true);
} }
...@@ -1213,6 +1231,8 @@ static void wl1271_recovery_work(struct work_struct *work) ...@@ -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", wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4)); wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
BUG_ON(bug_on_recovery);
/* /*
* Advance security sequence number to overcome potential progress * Advance security sequence number to overcome potential progress
* in the firmware during recovery. This doens't hurt if the network is * 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) ...@@ -1222,9 +1242,6 @@ static void wl1271_recovery_work(struct work_struct *work)
test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING; 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 */ /* Prevent spurious TX during FW restart */
ieee80211_stop_queues(wl->hw); ieee80211_stop_queues(wl->hw);
...@@ -1528,7 +1545,13 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -1528,7 +1545,13 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
int wl1271_tx_dummy_packet(struct wl1271 *wl) int wl1271_tx_dummy_packet(struct wl1271 *wl)
{ {
unsigned long flags; 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); spin_lock_irqsave(&wl->wl_lock, flags);
set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
...@@ -1802,10 +1825,16 @@ static u8 wl12xx_get_role_type(struct wl1271 *wl) ...@@ -1802,10 +1825,16 @@ static u8 wl12xx_get_role_type(struct wl1271 *wl)
{ {
switch (wl->bss_type) { switch (wl->bss_type) {
case BSS_TYPE_AP_BSS: 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: 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: case BSS_TYPE_IBSS:
return WL1271_ROLE_IBSS; return WL1271_ROLE_IBSS;
...@@ -1827,7 +1856,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, ...@@ -1827,7 +1856,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
bool booted = false; bool booted = false;
wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", 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); mutex_lock(&wl->mutex);
if (wl->vif) { if (wl->vif) {
...@@ -1847,7 +1876,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, ...@@ -1847,7 +1876,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto out; 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: case NL80211_IFTYPE_STATION:
wl->bss_type = BSS_TYPE_STA_BSS; wl->bss_type = BSS_TYPE_STA_BSS;
wl->set_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, ...@@ -1856,6 +1888,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
wl->bss_type = BSS_TYPE_IBSS; wl->bss_type = BSS_TYPE_IBSS;
wl->set_bss_type = BSS_TYPE_STA_BSS; wl->set_bss_type = BSS_TYPE_STA_BSS;
break; break;
case NL80211_IFTYPE_P2P_GO:
wl->p2p = 1;
/* fall-through */
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
wl->bss_type = BSS_TYPE_AP_BSS; wl->bss_type = BSS_TYPE_AP_BSS;
break; break;
...@@ -2051,6 +2086,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, ...@@ -2051,6 +2086,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl->ssid_len = 0; wl->ssid_len = 0;
wl->bss_type = MAX_BSS_TYPE; wl->bss_type = MAX_BSS_TYPE;
wl->set_bss_type = MAX_BSS_TYPE; wl->set_bss_type = MAX_BSS_TYPE;
wl->p2p = 0;
wl->band = IEEE80211_BAND_2GHZ; wl->band = IEEE80211_BAND_2GHZ;
wl->rx_counter = 0; wl->rx_counter = 0;
...@@ -2075,6 +2111,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, ...@@ -2075,6 +2111,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
memset(wl->roles_map, 0, sizeof(wl->roles_map)); memset(wl->roles_map, 0, sizeof(wl->roles_map));
memset(wl->links_map, 0, sizeof(wl->links_map)); memset(wl->links_map, 0, sizeof(wl->links_map));
memset(wl->roc_map, 0, sizeof(wl->roc_map)); memset(wl->roc_map, 0, sizeof(wl->roc_map));
wl->active_sta_count = 0;
/* The system link is always allocated */ /* The system link is always allocated */
__set_bit(WL12XX_SYSTEM_HLID, wl->links_map); __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
...@@ -3729,14 +3766,18 @@ static int wl1271_allocate_sta(struct wl1271 *wl, ...@@ -3729,14 +3766,18 @@ static int wl1271_allocate_sta(struct wl1271 *wl,
wl_sta->hlid = WL1271_AP_STA_HLID_START + id; wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
*hlid = wl_sta->hlid; *hlid = wl_sta->hlid;
memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN); memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
wl->active_sta_count++;
return 0; 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; 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; return;
clear_bit(id, wl->ap_hlid_map); clear_bit(id, wl->ap_hlid_map);
...@@ -3745,6 +3786,7 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid) ...@@ -3745,6 +3786,7 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
wl1271_tx_reset_link_queues(wl, hlid); wl1271_tx_reset_link_queues(wl, hlid);
__clear_bit(hlid, &wl->ap_ps_map); __clear_bit(hlid, &wl->ap_ps_map);
__clear_bit(hlid, (unsigned long *)&wl->ap_fw_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, static int wl1271_op_sta_add(struct ieee80211_hw *hw,
...@@ -4066,7 +4108,6 @@ static const u8 wl1271_rate_to_idx_2ghz[] = { ...@@ -4066,7 +4108,6 @@ static const u8 wl1271_rate_to_idx_2ghz[] = {
/* 11n STA capabilities */ /* 11n STA capabilities */
#define HW_RX_HIGHEST_RATE 72 #define HW_RX_HIGHEST_RATE 72
#ifdef CONFIG_WL12XX_HT
#define WL12XX_HT_CAP { \ #define WL12XX_HT_CAP { \
.cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \ .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \ (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
...@@ -4079,11 +4120,6 @@ static const u8 wl1271_rate_to_idx_2ghz[] = { ...@@ -4079,11 +4120,6 @@ static const u8 wl1271_rate_to_idx_2ghz[] = {
.tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
}, \ }, \
} }
#else
#define WL12XX_HT_CAP { \
.ht_supported = false, \
}
#endif
/* can't be const, mac80211 writes to this */ /* can't be const, mac80211 writes to this */
static struct ieee80211_supported_band wl1271_band_2ghz = { static struct ieee80211_supported_band wl1271_band_2ghz = {
...@@ -4483,15 +4519,19 @@ int wl1271_init_ieee80211(struct wl1271 *wl) ...@@ -4483,15 +4519,19 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
IEEE80211_HW_SUPPORTS_CQM_RSSI | IEEE80211_HW_SUPPORTS_CQM_RSSI |
IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_SPECTRUM_MGMT | 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->cipher_suites = cipher_suites;
wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | 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_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 * Maximum length of elements in scanning probe request templates
* should be the maximum length possible for a template, without * should be the maximum length possible for a template, without
...@@ -4500,6 +4540,8 @@ int wl1271_init_ieee80211(struct wl1271 *wl) ...@@ -4500,6 +4540,8 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE - wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
sizeof(struct ieee80211_header); sizeof(struct ieee80211_header);
wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
/* make sure all our channels fit in the scanned_ch bitmask */ /* make sure all our channels fit in the scanned_ch bitmask */
BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
ARRAY_SIZE(wl1271_channels_5ghz) > ARRAY_SIZE(wl1271_channels_5ghz) >
...@@ -4625,6 +4667,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) ...@@ -4625,6 +4667,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->session_counter = 0; wl->session_counter = 0;
wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID; wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
wl->ap_global_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, setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
(unsigned long) wl); (unsigned long) wl);
wl->fwlog_size = 0; wl->fwlog_size = 0;
...@@ -4776,6 +4819,9 @@ module_param_named(fwlog, fwlog_param, charp, 0); ...@@ -4776,6 +4819,9 @@ module_param_named(fwlog, fwlog_param, charp, 0);
MODULE_PARM_DESC(keymap, MODULE_PARM_DESC(keymap,
"FW logger options: continuous, ondemand, dbgpins or disable"); "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_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
...@@ -199,15 +199,19 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid) ...@@ -199,15 +199,19 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
unsigned long flags; unsigned long flags;
int filtered[NUM_TX_QUEUES]; 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++) { for (i = 0; i < NUM_TX_QUEUES; i++) {
filtered[i] = 0; filtered[i] = 0;
while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { 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 = IEEE80211_SKB_CB(skb);
info->flags |= IEEE80211_TX_STAT_TX_FILTERED; info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
info->status.rates[0].idx = -1; info->status.rates[0].idx = -1;
ieee80211_tx_status_ni(wl->hw, skb); ieee80211_tx_status_ni(wl->hw, skb);
filtered[i]++;
} }
} }
......
...@@ -66,11 +66,9 @@ static void wl1271_rx_status(struct wl1271 *wl, ...@@ -66,11 +66,9 @@ static void wl1271_rx_status(struct wl1271 *wl,
status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band); status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band);
#ifdef CONFIG_WL12XX_HT
/* 11n support */ /* 11n support */
if (desc->rate <= CONF_HW_RXTX_RATE_MCS0) if (desc->rate <= CONF_HW_RXTX_RATE_MCS0)
status->flag |= RX_FLAG_HT; status->flag |= RX_FLAG_HT;
#endif
status->signal = desc->rssi; status->signal = desc->rssi;
...@@ -107,6 +105,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, ...@@ -107,6 +105,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
u8 beacon = 0; u8 beacon = 0;
u8 is_data = 0; u8 is_data = 0;
u8 reserved = unaligned ? NET_IP_ALIGN : 0; u8 reserved = unaligned ? NET_IP_ALIGN : 0;
u16 seq_num;
/* /*
* In PLT mode we seem to get frames and mac80211 warns about them, * 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, ...@@ -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_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, skb->len - desc->pad_len,
beacon ? "beacon" : ""); beacon ? "beacon" : "",
seq_num);
skb_trim(skb, skb->len - desc->pad_len); skb_trim(skb, skb->len - desc->pad_len);
......
...@@ -65,8 +65,9 @@ void wl1271_scan_complete_work(struct work_struct *work) ...@@ -65,8 +65,9 @@ void wl1271_scan_complete_work(struct work_struct *work)
/* return to ROC if needed */ /* return to ROC if needed */
is_sta = (wl->bss_type == BSS_TYPE_STA_BSS); is_sta = (wl->bss_type == BSS_TYPE_STA_BSS);
is_ibss = (wl->bss_type == BSS_TYPE_IBSS); is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
if ((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) || if (((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) ||
(is_ibss && !test_bit(WL1271_FLAG_IBSS_JOINED, &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 */ /* restore remain on channel */
wl12xx_cmd_role_start_dev(wl); wl12xx_cmd_role_start_dev(wl);
wl12xx_roc(wl, wl->dev_role_id); wl12xx_roc(wl, wl->dev_role_id);
...@@ -164,9 +165,6 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, ...@@ -164,9 +165,6 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
goto out; 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 */ /* No SSIDs means that we have a forced passive scan */
if (passive || wl->scan.req->n_ssids == 0) if (passive || wl->scan.req->n_ssids == 0)
scan_options |= WL1271_SCAN_OPT_PASSIVE; scan_options |= WL1271_SCAN_OPT_PASSIVE;
...@@ -473,34 +471,86 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl, ...@@ -473,34 +471,86 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
cfg->passive[2] || cfg->active[2]; cfg->passive[2] || cfg->active[2];
} }
/* Returns 0 if no wildcard is used, 1 if wildcard is used or a /* Returns the scan type to be used or a negative value on error */
* negative value on error */
static int static int
wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
struct cfg80211_sched_scan_request *req) struct cfg80211_sched_scan_request *req)
{ {
struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL; struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL;
struct cfg80211_ssid *ssid = req->ssids; struct cfg80211_match_set *sets = req->match_sets;
int ret, wildcard = 0; 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"); 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); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) if (!cmd) {
return -ENOMEM; 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; cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC;
} else { cmd->ssids[cmd->n_ssids].len = sets[i].ssid.ssid_len;
cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_HIDDEN; 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)); wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd));
...@@ -509,13 +559,15 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, ...@@ -509,13 +559,15 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
sizeof(*cmd), 0); sizeof(*cmd), 0);
if (ret < 0) { if (ret < 0) {
wl1271_error("cmd sched scan ssid list failed"); wl1271_error("cmd sched scan ssid list failed");
goto out; goto out_free;
} }
ret = wildcard; out_free:
out:
kfree(cmd); kfree(cmd);
return ret; out:
if (ret < 0)
return ret;
return type;
} }
int wl1271_scan_sched_scan_config(struct wl1271 *wl, int wl1271_scan_sched_scan_config(struct wl1271 *wl,
...@@ -550,21 +602,13 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, ...@@ -550,21 +602,13 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
cfg->intervals[i] = cpu_to_le32(req->interval); cfg->intervals[i] = cpu_to_le32(req->interval);
cfg->ssid_len = 0; cfg->ssid_len = 0;
if (req->n_ssids == 0) { ret = wl12xx_scan_sched_scan_ssid_list(wl, req);
wl1271_debug(DEBUG_SCAN, "using SCAN_SSID_FILTER_ANY"); if (ret < 0)
cfg->filter_type = SCAN_SSID_FILTER_ANY; goto out;
} else {
ret = wl12xx_scan_sched_scan_ssid_list(wl, req); cfg->filter_type = ret;
if (ret < 0)
goto out; wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type);
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)) { if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) {
wl1271_error("scan channel list is empty"); wl1271_error("scan channel list is empty");
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "reg.h" #include "reg.h"
#include "ps.h" #include "ps.h"
#include "tx.h" #include "tx.h"
#include "event.h"
static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id) static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id)
{ {
...@@ -125,25 +126,31 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, ...@@ -125,25 +126,31 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid)
{ {
bool fw_ps; bool fw_ps, single_sta;
u8 tx_pkts; u8 tx_pkts;
/* only regulate station links */ /* only regulate station links */
if (hlid < WL1271_AP_STA_HLID_START) if (hlid < WL1271_AP_STA_HLID_START)
return; return;
if (WARN_ON(!wl1271_is_active_sta(wl, hlid)))
return;
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
tx_pkts = wl->links[hlid].allocated_pkts; 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 * 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. * 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); 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; return wl->dummy_packet == skb;
} }
...@@ -453,7 +460,6 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) ...@@ -453,7 +460,6 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
rate_set >>= 1; rate_set >>= 1;
} }
#ifdef CONFIG_WL12XX_HT
/* MCS rates indication are on bits 16 - 23 */ /* MCS rates indication are on bits 16 - 23 */
rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates;
...@@ -462,7 +468,6 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) ...@@ -462,7 +468,6 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit);
rate_set >>= 1; rate_set >>= 1;
} }
#endif
return enabled_rates; return enabled_rates;
} }
...@@ -886,6 +891,7 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) ...@@ -886,6 +891,7 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
/* TX failure */ /* TX failure */
if (wl->bss_type == BSS_TYPE_AP_BSS) { if (wl->bss_type == BSS_TYPE_AP_BSS) {
for (i = 0; i < AP_MAX_LINKS; i++) { for (i = 0; i < AP_MAX_LINKS; i++) {
wl1271_free_sta(wl, i);
wl1271_tx_reset_link_queues(wl, i); wl1271_tx_reset_link_queues(wl, i);
wl->links[i].allocated_pkts = 0; wl->links[i].allocated_pkts = 0;
wl->links[i].prev_freed_pkts = 0; wl->links[i].prev_freed_pkts = 0;
...@@ -905,10 +911,14 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) ...@@ -905,10 +911,14 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
ieee80211_tx_status_ni(wl->hw, skb); 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; wl->stopped_queues_map = 0;
/* /*
......
...@@ -214,5 +214,9 @@ u32 wl1271_tx_min_rate_get(struct wl1271 *wl); ...@@ -214,5 +214,9 @@ u32 wl1271_tx_min_rate_get(struct wl1271 *wl);
u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb); 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_tx_reset_link_queues(struct wl1271 *wl, u8 hlid);
void wl1271_handle_tx_low_watermark(struct wl1271 *wl); 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 #endif
...@@ -234,14 +234,14 @@ struct wl1271_stats { ...@@ -234,14 +234,14 @@ struct wl1271_stats {
#define NUM_TX_QUEUES 4 #define NUM_TX_QUEUES 4
#define NUM_RX_PKT_DESC 8 #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 */ /* Broadcast and Global links + system link + links to stations */
/* /*
* TODO: when WL1271_AP_STA_HLID_START is no longer constant, change all * TODO: when WL1271_AP_STA_HLID_START is no longer constant, change all
* the places that use this. * 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 */ /* FW status registers */
struct wl12xx_fw_status { struct wl12xx_fw_status {
...@@ -402,6 +402,7 @@ struct wl1271 { ...@@ -402,6 +402,7 @@ struct wl1271 {
u8 mac_addr[ETH_ALEN]; u8 mac_addr[ETH_ALEN];
u8 bss_type; u8 bss_type;
u8 set_bss_type; u8 set_bss_type;
u8 p2p; /* we are using p2p role */
u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
u8 ssid_len; u8 ssid_len;
int channel; int channel;
...@@ -626,6 +627,9 @@ struct wl1271 { ...@@ -626,6 +627,9 @@ struct wl1271 {
/* number of currently active RX BA sessions */ /* number of currently active RX BA sessions */
int ba_rx_session_count; int ba_rx_session_count;
/* AP-mode - number of currently connected stations */
int active_sta_count;
}; };
struct wl1271_station { struct wl1271_station {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment