summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuciano Coelho <coelho@ti.com>2011-08-22 12:39:03 +0300
committerLuciano Coelho <coelho@ti.com>2011-08-22 12:39:03 +0300
commit6b0fb65ef84634068ae5071b2b93108e76d0a000 (patch)
treec20d221fd57d6d62e0a3d3b2289193f32ad34e54
parent5551f7f2cdfc3c20979fcabce56c444a936bbab9 (diff)
parent04b4d69c89593d907d81a4aa33e4e42a632fe436 (diff)
Merge branch 'wl12xx-next'wl12xx-2011-08-22
-rw-r--r--drivers/net/wireless/wl12xx/acx.c322
-rw-r--r--drivers/net/wireless/wl12xx/acx.h394
-rw-r--r--drivers/net/wireless/wl12xx/boot.c30
-rw-r--r--drivers/net/wireless/wl12xx/cmd.c793
-rw-r--r--drivers/net/wireless/wl12xx/cmd.h329
-rw-r--r--drivers/net/wireless/wl12xx/conf.h352
-rw-r--r--drivers/net/wireless/wl12xx/debugfs.c17
-rw-r--r--drivers/net/wireless/wl12xx/event.c6
-rw-r--r--drivers/net/wireless/wl12xx/event.h80
-rw-r--r--drivers/net/wireless/wl12xx/init.c91
-rw-r--r--drivers/net/wireless/wl12xx/io.h1
-rw-r--r--drivers/net/wireless/wl12xx/main.c949
-rw-r--r--drivers/net/wireless/wl12xx/ps.c4
-rw-r--r--drivers/net/wireless/wl12xx/reg.h75
-rw-r--r--drivers/net/wireless/wl12xx/rx.c29
-rw-r--r--drivers/net/wireless/wl12xx/rx.h10
-rw-r--r--drivers/net/wireless/wl12xx/scan.c38
-rw-r--r--drivers/net/wireless/wl12xx/scan.h25
-rw-r--r--drivers/net/wireless/wl12xx/sdio.c4
-rw-r--r--drivers/net/wireless/wl12xx/spi.c4
-rw-r--r--drivers/net/wireless/wl12xx/tx.c136
-rw-r--r--drivers/net/wireless/wl12xx/tx.h16
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h153
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx_80211.h25
24 files changed, 2037 insertions, 1846 deletions
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index 34f6ab53e51..f2838ae07da 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -46,6 +46,7 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl)
goto out;
}
+ wake_up->role_id = wl->role_id;
wake_up->wake_up_event = wl->conf.conn.wake_up_event;
wake_up->listen_interval = wl->conf.conn.listen_interval;
@@ -99,6 +100,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power)
goto out;
}
+ acx->role_id = wl->role_id;
acx->current_tx_power = power * 10;
ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
@@ -126,6 +128,7 @@ int wl1271_acx_feature_cfg(struct wl1271 *wl)
}
/* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
+ feature->role_id = wl->role_id;
feature->data_flow_options = 0;
feature->options = 0;
@@ -181,34 +184,6 @@ out:
return ret;
}
-int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter)
-{
- struct acx_rx_config *rx_config;
- int ret;
-
- wl1271_debug(DEBUG_ACX, "acx rx config");
-
- rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL);
- if (!rx_config) {
- ret = -ENOMEM;
- goto out;
- }
-
- rx_config->config_options = cpu_to_le32(config);
- rx_config->filter_options = cpu_to_le32(filter);
-
- ret = wl1271_cmd_configure(wl, ACX_RX_CFG,
- rx_config, sizeof(*rx_config));
- if (ret < 0) {
- wl1271_warning("failed to set rx config: %d", ret);
- goto out;
- }
-
-out:
- kfree(rx_config);
- return ret;
-}
-
int wl1271_acx_pd_threshold(struct wl1271 *wl)
{
struct acx_packet_detection *pd;
@@ -248,6 +223,7 @@ int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time)
goto out;
}
+ slot->role_id = wl->role_id;
slot->wone_index = STATION_WONE_INDEX;
slot->slot_time = slot_time;
@@ -277,6 +253,7 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
}
/* MAC filtering */
+ acx->role_id = wl->role_id;
acx->enabled = enable;
acx->num_groups = mc_list_len;
memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN);
@@ -306,6 +283,7 @@ int wl1271_acx_service_period_timeout(struct wl1271 *wl)
wl1271_debug(DEBUG_ACX, "acx service period timeout");
+ rx_timeout->role_id = wl->role_id;
rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout);
rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout);
@@ -342,6 +320,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold)
goto out;
}
+ rts->role_id = wl->role_id;
rts->threshold = cpu_to_le16((u16)rts_threshold);
ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
@@ -401,6 +380,7 @@ int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter)
goto out;
}
+ beacon_filter->role_id = wl->role_id;
beacon_filter->enable = enable_filter;
/*
@@ -437,6 +417,7 @@ int wl1271_acx_beacon_filter_table(struct wl1271 *wl)
}
/* configure default beacon pass-through rules */
+ ie_table->role_id = wl->role_id;
ie_table->num_ie = 0;
for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) {
struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]);
@@ -498,6 +479,7 @@ int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable)
timeout = wl->conf.conn.bss_lose_timeout;
}
+ acx->role_id = wl->role_id;
acx->synch_fail_thold = cpu_to_le32(threshold);
acx->bss_lose_timeout = cpu_to_le32(timeout);
@@ -544,43 +526,13 @@ out:
return ret;
}
-int wl1271_acx_sta_sg_cfg(struct wl1271 *wl)
-{
- struct acx_sta_bt_wlan_coex_param *param;
- struct conf_sg_settings *c = &wl->conf.sg;
- int i, ret;
-
- wl1271_debug(DEBUG_ACX, "acx sg sta cfg");
-
- param = kzalloc(sizeof(*param), GFP_KERNEL);
- if (!param) {
- ret = -ENOMEM;
- goto out;
- }
-
- /* BT-WLAN coext parameters */
- for (i = 0; i < CONF_SG_STA_PARAMS_MAX; i++)
- param->params[i] = cpu_to_le32(c->sta_params[i]);
- param->param_idx = CONF_SG_PARAMS_ALL;
-
- ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
- if (ret < 0) {
- wl1271_warning("failed to set sg config: %d", ret);
- goto out;
- }
-
-out:
- kfree(param);
- return ret;
-}
-
-int wl1271_acx_ap_sg_cfg(struct wl1271 *wl)
+int wl12xx_acx_sg_cfg(struct wl1271 *wl)
{
- struct acx_ap_bt_wlan_coex_param *param;
+ struct acx_bt_wlan_coex_param *param;
struct conf_sg_settings *c = &wl->conf.sg;
int i, ret;
- wl1271_debug(DEBUG_ACX, "acx sg ap cfg");
+ wl1271_debug(DEBUG_ACX, "acx sg cfg");
param = kzalloc(sizeof(*param), GFP_KERNEL);
if (!param) {
@@ -589,8 +541,8 @@ int wl1271_acx_ap_sg_cfg(struct wl1271 *wl)
}
/* BT-WLAN coext parameters */
- for (i = 0; i < CONF_SG_AP_PARAMS_MAX; i++)
- param->params[i] = cpu_to_le32(c->ap_params[i]);
+ for (i = 0; i < CONF_SG_PARAMS_MAX; i++)
+ param->params[i] = cpu_to_le32(c->params[i]);
param->param_idx = CONF_SG_PARAMS_ALL;
ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
@@ -643,6 +595,7 @@ int wl1271_acx_bcn_dtim_options(struct wl1271 *wl)
goto out;
}
+ bb->role_id = wl->role_id;
bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout);
bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout);
bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps;
@@ -672,6 +625,7 @@ int wl1271_acx_aid(struct wl1271 *wl, u16 aid)
goto out;
}
+ acx_aid->role_id = wl->role_id;
acx_aid->aid = cpu_to_le16(aid);
ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid));
@@ -727,6 +681,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble)
goto out;
}
+ acx->role_id = wl->role_id;
acx->preamble = preamble;
ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx));
@@ -754,6 +709,7 @@ int wl1271_acx_cts_protect(struct wl1271 *wl,
goto out;
}
+ acx->role_id = wl->role_id;
acx->ctsprotect = ctsprotect;
ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx));
@@ -785,9 +741,8 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
{
- struct acx_sta_rate_policy *acx;
+ struct acx_rate_policy *acx;
struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf;
- int idx = 0;
int ret = 0;
wl1271_debug(DEBUG_ACX, "acx rate policies");
@@ -799,25 +754,30 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
goto out;
}
+ wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x",
+ wl->basic_rate, wl->rate_set);
+
/* configure one basic rate class */
- idx = ACX_TX_BASIC_RATE;
- acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate);
- acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
- acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
- acx->rate_class[idx].aflags = c->aflags;
+ acx->rate_policy_idx = cpu_to_le32(ACX_TX_BASIC_RATE);
+ acx->rate_policy.enabled_rates = cpu_to_le32(wl->basic_rate);
+ acx->rate_policy.short_retry_limit = c->short_retry_limit;
+ acx->rate_policy.long_retry_limit = c->long_retry_limit;
+ acx->rate_policy.aflags = c->aflags;
+
+ ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("Setting of rate policies failed: %d", ret);
+ goto out;
+ }
/* configure one AP supported rate class */
- idx = ACX_TX_AP_FULL_RATE;
- acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set);
- acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
- acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
- acx->rate_class[idx].aflags = c->aflags;
+ acx->rate_policy_idx = cpu_to_le32(ACX_TX_AP_FULL_RATE);
+ acx->rate_policy.enabled_rates = cpu_to_le32(wl->rate_set);
+ acx->rate_policy.short_retry_limit = c->short_retry_limit;
+ acx->rate_policy.long_retry_limit = c->long_retry_limit;
+ acx->rate_policy.aflags = c->aflags;
- acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT);
- wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x",
- acx->rate_class[ACX_TX_BASIC_RATE].enabled_rates,
- acx->rate_class[ACX_TX_AP_FULL_RATE].enabled_rates);
ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
if (ret < 0) {
@@ -833,7 +793,7 @@ out:
int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
u8 idx)
{
- struct acx_ap_rate_policy *acx;
+ struct acx_rate_policy *acx;
int ret = 0;
wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x",
@@ -879,6 +839,7 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
goto out;
}
+ acx->role_id = wl->role_id;
acx->ac = ac;
acx->cw_min = cw_min;
acx->cw_max = cpu_to_le16(cw_max);
@@ -912,6 +873,7 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
goto out;
}
+ acx->role_id = wl->role_id;
acx->queue_id = queue_id;
acx->channel_type = channel_type;
acx->tsid = tsid;
@@ -991,52 +953,9 @@ out:
return ret;
}
-int wl1271_acx_ap_mem_cfg(struct wl1271 *wl)
-{
- struct wl1271_acx_ap_config_memory *mem_conf;
- struct conf_memory_settings *mem;
- int ret;
-
- wl1271_debug(DEBUG_ACX, "wl1271 mem cfg");
-
- mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL);
- if (!mem_conf) {
- ret = -ENOMEM;
- goto out;
- }
-
- if (wl->chip.id == CHIP_ID_1283_PG20)
- /*
- * FIXME: The 128x AP FW does not yet support dynamic memory.
- * Use the base memory configuration for 128x for now. This
- * should be fine tuned in the future.
- */
- mem = &wl->conf.mem_wl128x;
- else
- mem = &wl->conf.mem_wl127x;
-
- /* memory config */
- mem_conf->num_stations = mem->num_stations;
- mem_conf->rx_mem_block_num = mem->rx_block_num;
- mem_conf->tx_min_mem_block_num = mem->tx_min_block_num;
- mem_conf->num_ssid_profiles = mem->ssid_profiles;
- mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS);
-
- ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
- sizeof(*mem_conf));
- if (ret < 0) {
- wl1271_warning("wl1271 mem config failed: %d", ret);
- goto out;
- }
-
-out:
- kfree(mem_conf);
- return ret;
-}
-
-int wl1271_acx_sta_mem_cfg(struct wl1271 *wl)
+int wl12xx_acx_mem_cfg(struct wl1271 *wl)
{
- struct wl1271_acx_sta_config_memory *mem_conf;
+ struct wl12xx_acx_config_memory *mem_conf;
struct conf_memory_settings *mem;
int ret;
@@ -1179,6 +1098,7 @@ int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable)
goto out;
}
+ acx->role_id = wl->role_id;
acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE;
acx->max_consecutive = wl->conf.conn.bet_max_consecutive;
@@ -1206,6 +1126,7 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address)
goto out;
}
+ acx->role_id = wl->role_id;
acx->version = ACX_IPV4_VERSION;
acx->enable = enable;
@@ -1265,6 +1186,7 @@ int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable)
goto out;
}
+ acx->role_id = wl->role_id;
acx->enabled = enable;
ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx));
@@ -1291,6 +1213,7 @@ int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid)
goto out;
}
+ acx->role_id = wl->role_id;
acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval);
acx->index = index;
acx->tpl_validation = tpl_valid;
@@ -1324,6 +1247,7 @@ int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
wl->last_rssi_event = -1;
+ acx->role_id = wl->role_id;
acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing);
acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON;
acx->type = WL1271_ACX_TRIG_TYPE_EDGE;
@@ -1362,6 +1286,7 @@ int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl)
goto out;
}
+ acx->role_id = wl->role_id;
acx->rssi_beacon = c->avg_weight_rssi_beacon;
acx->rssi_data = c->avg_weight_rssi_data;
acx->snr_beacon = c->avg_weight_snr_beacon;
@@ -1380,14 +1305,15 @@ out:
int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
- bool allow_ht_operation)
+ bool allow_ht_operation, u8 hlid)
{
struct wl1271_acx_ht_capabilities *acx;
- u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
int ret = 0;
u32 ht_capabilites = 0;
- wl1271_debug(DEBUG_ACX, "acx ht capabilities setting");
+ wl1271_debug(DEBUG_ACX, "acx ht capabilities setting "
+ "sta supp: %d sta cap: %d", ht_cap->ht_supported,
+ ht_cap->cap);
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
@@ -1395,26 +1321,22 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
goto out;
}
- /* Allow HT Operation ? */
- if (allow_ht_operation) {
- ht_capabilites =
- WL1271_ACX_FW_CAP_HT_OPERATION;
- if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD)
- ht_capabilites |=
- WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT;
- if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
- ht_capabilites |=
- WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS;
- if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT)
- ht_capabilites |=
- WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION;
+ if (allow_ht_operation && ht_cap->ht_supported) {
+ /* no need to translate capabilities - use the spec values */
+ ht_capabilites = ht_cap->cap;
+
+ /*
+ * this bit is not employed by the spec but only by FW to
+ * indicate peer HT support
+ */
+ ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION;
/* get data from A-MPDU parameters field */
acx->ampdu_max_length = ht_cap->ampdu_factor;
acx->ampdu_min_spacing = ht_cap->ampdu_density;
}
- memcpy(acx->mac_address, mac_address, ETH_ALEN);
+ acx->hlid = hlid;
acx->ht_capabilites = cpu_to_le32(ht_capabilites);
ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx));
@@ -1442,6 +1364,7 @@ int wl1271_acx_set_ht_information(struct wl1271 *wl,
goto out;
}
+ acx->role_id = wl->role_id;
acx->ht_protection =
(u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION);
acx->rifs_mode = 0;
@@ -1463,14 +1386,12 @@ out:
}
/* Configure BA session initiator/receiver parameters setting in the FW. */
-int wl1271_acx_set_ba_session(struct wl1271 *wl,
- enum ieee80211_back_parties direction,
- u8 tid_index, u8 policy)
+int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl)
{
- struct wl1271_acx_ba_session_policy *acx;
+ struct wl1271_acx_ba_initiator_policy *acx;
int ret;
- wl1271_debug(DEBUG_ACX, "acx ba session setting");
+ wl1271_debug(DEBUG_ACX, "acx ba initiator policy");
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
@@ -1478,33 +1399,18 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl,
goto out;
}
- /* ANY role */
- acx->role_id = 0xff;
- acx->tid = tid_index;
- acx->enable = policy;
- acx->ba_direction = direction;
-
- switch (direction) {
- case WLAN_BACK_INITIATOR:
- acx->win_size = wl->conf.ht.tx_ba_win_size;
- acx->inactivity_timeout = wl->conf.ht.inactivity_timeout;
- break;
- case WLAN_BACK_RECIPIENT:
- acx->win_size = RX_BA_WIN_SIZE;
- acx->inactivity_timeout = 0;
- break;
- default:
- wl1271_error("Incorrect acx command id=%x\n", direction);
- ret = -EINVAL;
- goto out;
- }
+ /* set for the current role */
+ acx->role_id = wl->role_id;
+ acx->tid_bitmap = wl->conf.ht.tx_ba_tid_bitmap;
+ acx->win_size = wl->conf.ht.tx_ba_win_size;
+ acx->inactivity_timeout = wl->conf.ht.inactivity_timeout;
ret = wl1271_cmd_configure(wl,
- ACX_BA_SESSION_POLICY_CFG,
+ ACX_BA_SESSION_INIT_POLICY,
acx,
sizeof(*acx));
if (ret < 0) {
- wl1271_warning("acx ba session setting failed: %d", ret);
+ wl1271_warning("acx ba initiator policy failed: %d", ret);
goto out;
}
@@ -1514,8 +1420,8 @@ out:
}
/* setup BA session receiver setting in the FW. */
-int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
- bool enable)
+int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
+ u16 ssn, bool enable, u8 peer_hlid)
{
struct wl1271_acx_ba_receiver_setup *acx;
int ret;
@@ -1528,11 +1434,10 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
goto out;
}
- /* Single link for now */
- acx->link_id = 1;
+ acx->hlid = peer_hlid;
acx->tid = tid_index;
acx->enable = enable;
- acx->win_size = 0;
+ acx->win_size = wl->conf.ht.rx_ba_win_size;
acx->ssn = ssn;
ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx,
@@ -1602,6 +1507,7 @@ int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable)
if (!(conf_queues & BIT(i)))
continue;
+ rx_streaming->role_id = wl->role_id;
rx_streaming->tid = i;
rx_streaming->enable = enable_queues & BIT(i);
rx_streaming->period = wl->conf.rx_streaming.interval;
@@ -1631,6 +1537,7 @@ int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
if (!acx)
return -ENOMEM;
+ acx->role_id = wl->role_id;
acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries);
ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx));
@@ -1699,31 +1606,6 @@ out:
return ret;
}
-int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable)
-{
- struct acx_ap_beacon_filter *acx = NULL;
- int ret;
-
- wl1271_debug(DEBUG_ACX, "acx set ap beacon filter: %d", enable);
-
- acx = kzalloc(sizeof(*acx), GFP_KERNEL);
- if (!acx)
- return -ENOMEM;
-
- acx->enable = enable ? 1 : 0;
-
- ret = wl1271_cmd_configure(wl, ACX_AP_BEACON_FILTER_OPT,
- acx, sizeof(*acx));
- if (ret < 0) {
- wl1271_warning("acx set ap beacon filter failed: %d", ret);
- goto out;
- }
-
-out:
- kfree(acx);
- return ret;
-}
-
int wl1271_acx_fm_coex(struct wl1271 *wl)
{
struct wl1271_acx_fm_coex *acx;
@@ -1763,3 +1645,45 @@ out:
kfree(acx);
return ret;
}
+
+int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl)
+{
+ struct wl12xx_acx_set_rate_mgmt_params *acx = NULL;
+ struct conf_rate_policy_settings *conf = &wl->conf.rate;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx set rate mgmt params");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx)
+ return -ENOMEM;
+
+ acx->index = ACX_RATE_MGMT_ALL_PARAMS;
+ acx->rate_retry_score = cpu_to_le16(conf->rate_retry_score);
+ acx->per_add = cpu_to_le16(conf->per_add);
+ acx->per_th1 = cpu_to_le16(conf->per_th1);
+ acx->per_th2 = cpu_to_le16(conf->per_th2);
+ acx->max_per = cpu_to_le16(conf->max_per);
+ acx->inverse_curiosity_factor = conf->inverse_curiosity_factor;
+ acx->tx_fail_low_th = conf->tx_fail_low_th;
+ acx->tx_fail_high_th = conf->tx_fail_high_th;
+ acx->per_alpha_shift = conf->per_alpha_shift;
+ acx->per_add_shift = conf->per_add_shift;
+ acx->per_beta1_shift = conf->per_beta1_shift;
+ acx->per_beta2_shift = conf->per_beta2_shift;
+ acx->rate_check_up = conf->rate_check_up;
+ acx->rate_check_down = conf->rate_check_down;
+ memcpy(acx->rate_retry_policy, conf->rate_retry_policy,
+ sizeof(acx->rate_retry_policy));
+
+ ret = wl1271_cmd_configure(wl, ACX_SET_RATE_MGMT_PARAMS,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx set rate mgmt params 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 d2eb86eccc0..758c596f62f 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -101,6 +101,17 @@ struct acx_error_counter {
__le32 seq_num_miss;
} __packed;
+enum wl12xx_role {
+ WL1271_ROLE_STA = 0,
+ WL1271_ROLE_IBSS,
+ WL1271_ROLE_AP,
+ WL1271_ROLE_DEVICE,
+ WL1271_ROLE_P2P_CL,
+ WL1271_ROLE_P2P_GO,
+
+ WL12XX_INVALID_ROLE_TYPE = 0xff
+};
+
enum wl1271_psm_mode {
/* Active mode */
WL1271_PSM_CAM = 0,
@@ -160,94 +171,6 @@ struct acx_rx_msdu_lifetime {
__le32 lifetime;
} __packed;
-/*
- * RX Config Options Table
- * Bit Definition
- * === ==========
- * 31:14 Reserved
- * 13 Copy RX Status - when set, write three receive status words
- * to top of rx'd MPDUs.
- * When cleared, do not write three status words (added rev 1.5)
- * 12 Reserved
- * 11 RX Complete upon FCS error - when set, give rx complete
- * interrupt for FCS errors, after the rx filtering, e.g. unicast
- * frames not to us with FCS error will not generate an interrupt.
- * 10 SSID Filter Enable - When set, the WiLink discards all beacon,
- * probe request, and probe response frames with an SSID that does
- * not match the SSID specified by the host in the START/JOIN
- * command.
- * When clear, the WiLink receives frames with any SSID.
- * 9 Broadcast Filter Enable - When set, the WiLink discards all
- * broadcast frames. When clear, the WiLink receives all received
- * broadcast frames.
- * 8:6 Reserved
- * 5 BSSID Filter Enable - When set, the WiLink discards any frames
- * with a BSSID that does not match the BSSID specified by the
- * host.
- * When clear, the WiLink receives frames from any BSSID.
- * 4 MAC Addr Filter - When set, the WiLink discards any frames
- * with a destination address that does not match the MAC address
- * of the adaptor.
- * When clear, the WiLink receives frames destined to any MAC
- * address.
- * 3 Promiscuous - When set, the WiLink receives all valid frames
- * (i.e., all frames that pass the FCS check).
- * When clear, only frames that pass the other filters specified
- * are received.
- * 2 FCS - When set, the WiLink includes the FCS with the received
- * frame.
- * When cleared, the FCS is discarded.
- * 1 PLCP header - When set, write all data from baseband to frame
- * buffer including PHY header.
- * 0 Reserved - Always equal to 0.
- *
- * RX Filter Options Table
- * Bit Definition
- * === ==========
- * 31:12 Reserved - Always equal to 0.
- * 11 Association - When set, the WiLink receives all association
- * related frames (association request/response, reassocation
- * request/response, and disassociation). When clear, these frames
- * are discarded.
- * 10 Auth/De auth - When set, the WiLink receives all authentication
- * and de-authentication frames. When clear, these frames are
- * discarded.
- * 9 Beacon - When set, the WiLink receives all beacon frames.
- * When clear, these frames are discarded.
- * 8 Contention Free - When set, the WiLink receives all contention
- * free frames.
- * When clear, these frames are discarded.
- * 7 Control - When set, the WiLink receives all control frames.
- * When clear, these frames are discarded.
- * 6 Data - When set, the WiLink receives all data frames.
- * When clear, these frames are discarded.
- * 5 FCS Error - When set, the WiLink receives frames that have FCS
- * errors.
- * When clear, these frames are discarded.
- * 4 Management - When set, the WiLink receives all management
- * frames.
- * When clear, these frames are discarded.
- * 3 Probe Request - When set, the WiLink receives all probe request
- * frames.
- * When clear, these frames are discarded.
- * 2 Probe Response - When set, the WiLink receives all probe
- * response frames.
- * When clear, these frames are discarded.
- * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK
- * frames.
- * When clear, these frames are discarded.
- * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames
- * that have reserved frame types and sub types as defined by the
- * 802.11 specification.
- * When clear, these frames are discarded.
- */
-struct acx_rx_config {
- struct acx_header header;
-
- __le32 config_options;
- __le32 filter_options;
-} __packed;
-
struct acx_packet_detection {
struct acx_header header;
@@ -267,9 +190,10 @@ enum acx_slot_type {
struct acx_slot {
struct acx_header header;
+ u8 role_id;
u8 wone_index; /* Reserved */
u8 slot_time;
- u8 reserved[6];
+ u8 reserved[5];
} __packed;
@@ -279,29 +203,35 @@ struct acx_slot {
struct acx_dot11_grp_addr_tbl {
struct acx_header header;
+ u8 role_id;
u8 enabled;
u8 num_groups;
- u8 pad[2];
+ u8 pad[1];
u8 mac_table[ADDRESS_GROUP_MAX_LEN];
} __packed;
struct acx_rx_timeout {
struct acx_header header;
+ u8 role_id;
+ u8 reserved;
__le16 ps_poll_timeout;
__le16 upsd_timeout;
+ u8 padding[2];
} __packed;
struct acx_rts_threshold {
struct acx_header header;
+ u8 role_id;
+ u8 reserved;
__le16 threshold;
- u8 pad[2];
} __packed;
struct acx_beacon_filter_option {
struct acx_header header;
+ u8 role_id;
u8 enable;
/*
* The number of beacons without the unicast TIM
@@ -311,7 +241,7 @@ struct acx_beacon_filter_option {
* without the unicast TIM bit set are dropped.
*/
u8 max_num_beacons;
- u8 pad[2];
+ u8 pad[1];
} __packed;
/*
@@ -350,14 +280,17 @@ struct acx_beacon_filter_option {
struct acx_beacon_filter_ie_table {
struct acx_header header;
+ u8 role_id;
u8 num_ie;
- u8 pad[3];
+ u8 pad[2];
u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
} __packed;
struct acx_conn_monit_params {
struct acx_header header;
+ u8 role_id;
+ u8 padding[3];
__le32 synch_fail_thold; /* number of beacons missed */
__le32 bss_lose_timeout; /* number of TU's from synch fail */
} __packed;
@@ -369,23 +302,14 @@ struct acx_bt_wlan_coex {
u8 pad[3];
} __packed;
-struct acx_sta_bt_wlan_coex_param {
- struct acx_header header;
-
- __le32 params[CONF_SG_STA_PARAMS_MAX];
- u8 param_idx;
- u8 padding[3];
-} __packed;
-
-struct acx_ap_bt_wlan_coex_param {
+struct acx_bt_wlan_coex_param {
struct acx_header header;
- __le32 params[CONF_SG_AP_PARAMS_MAX];
+ __le32 params[CONF_SG_PARAMS_MAX];
u8 param_idx;
u8 padding[3];
} __packed;
-
struct acx_dco_itrim_params {
struct acx_header header;
@@ -406,15 +330,16 @@ struct acx_energy_detection {
struct acx_beacon_broadcast {
struct acx_header header;
- __le16 beacon_rx_timeout;
- __le16 broadcast_timeout;
-
+ u8 role_id;
/* Enables receiving of broadcast packets in PS mode */
u8 rx_broadcast_in_ps;
+ __le16 beacon_rx_timeout;
+ __le16 broadcast_timeout;
+
/* Consecutive PS Poll failures before updating the host */
u8 ps_poll_threshold;
- u8 pad[2];
+ u8 pad[1];
} __packed;
struct acx_event_mask {
@@ -424,35 +349,6 @@ struct acx_event_mask {
__le32 high_event_mask; /* Unused */
} __packed;
-#define CFG_RX_FCS BIT(2)
-#define CFG_RX_ALL_GOOD BIT(3)
-#define CFG_UNI_FILTER_EN BIT(4)
-#define CFG_BSSID_FILTER_EN BIT(5)
-#define CFG_MC_FILTER_EN BIT(6)
-#define CFG_MC_ADDR0_EN BIT(7)
-#define CFG_MC_ADDR1_EN BIT(8)
-#define CFG_BC_REJECT_EN BIT(9)
-#define CFG_SSID_FILTER_EN BIT(10)
-#define CFG_RX_INT_FCS_ERROR BIT(11)
-#define CFG_RX_INT_ENCRYPTED BIT(12)
-#define CFG_RX_WR_RX_STATUS BIT(13)
-#define CFG_RX_FILTER_NULTI BIT(14)
-#define CFG_RX_RESERVE BIT(15)
-#define CFG_RX_TIMESTAMP_TSF BIT(16)
-
-#define CFG_RX_RSV_EN BIT(0)
-#define CFG_RX_RCTS_ACK BIT(1)
-#define CFG_RX_PRSP_EN BIT(2)
-#define CFG_RX_PREQ_EN BIT(3)
-#define CFG_RX_MGMT_EN BIT(4)
-#define CFG_RX_FCS_ERROR BIT(5)
-#define CFG_RX_DATA_EN BIT(6)
-#define CFG_RX_CTL_EN BIT(7)
-#define CFG_RX_CF_EN BIT(8)
-#define CFG_RX_BCN_EN BIT(9)
-#define CFG_RX_AUTH_EN BIT(10)
-#define CFG_RX_ASSOC_EN BIT(11)
-
#define SCAN_PASSIVE BIT(0)
#define SCAN_5GHZ_BAND BIT(1)
#define SCAN_TRIGGERED BIT(2)
@@ -465,6 +361,8 @@ struct acx_event_mask {
struct acx_feature_config {
struct acx_header header;
+ u8 role_id;
+ u8 padding[3];
__le32 options;
__le32 data_flow_options;
} __packed;
@@ -472,16 +370,18 @@ struct acx_feature_config {
struct acx_current_tx_power {
struct acx_header header;
+ u8 role_id;
u8 current_tx_power;
- u8 padding[3];
+ u8 padding[2];
} __packed;
struct acx_wake_up_condition {
struct acx_header header;
+ u8 role_id;
u8 wake_up_event; /* Only one bit can be set */
u8 listen_interval;
- u8 pad[2];
+ u8 pad[1];
} __packed;
struct acx_aid {
@@ -490,8 +390,9 @@ struct acx_aid {
/*
* To be set when associated with an AP.
*/
+ u8 role_id;
+ u8 reserved;
__le16 aid;
- u8 pad[2];
} __packed;
enum acx_preamble_type {
@@ -506,8 +407,9 @@ struct acx_preamble {
* When set, the WiLink transmits the frames with a short preamble and
* when cleared, the WiLink transmits the frames with a long preamble.
*/
+ u8 role_id;
u8 preamble;
- u8 padding[3];
+ u8 padding[2];
} __packed;
enum acx_ctsprotect_type {
@@ -517,8 +419,9 @@ enum acx_ctsprotect_type {
struct acx_ctsprotect {
struct acx_header header;
+ u8 role_id;
u8 ctsprotect;
- u8 padding[3];
+ u8 padding[2];
} __packed;
struct acx_tx_statistics {
@@ -753,18 +656,9 @@ struct acx_rate_class {
#define ACX_TX_BASIC_RATE 0
#define ACX_TX_AP_FULL_RATE 1
-#define ACX_TX_RATE_POLICY_CNT 2
-struct acx_sta_rate_policy {
- struct acx_header header;
-
- __le32 rate_class_cnt;
- struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES];
-} __packed;
-
-
#define ACX_TX_AP_MODE_MGMT_RATE 4
#define ACX_TX_AP_MODE_BCST_RATE 5
-struct acx_ap_rate_policy {
+struct acx_rate_policy {
struct acx_header header;
__le32 rate_policy_idx;
@@ -773,22 +667,23 @@ struct acx_ap_rate_policy {
struct acx_ac_cfg {
struct acx_header header;
+ u8 role_id;
u8 ac;
+ u8 aifsn;
u8 cw_min;
__le16 cw_max;
- u8 aifsn;
- u8 reserved;
__le16 tx_op_limit;
} __packed;
struct acx_tid_config {
struct acx_header header;
+ u8 role_id;
u8 queue_id;
u8 channel_type;
u8 tsid;
u8 ps_scheme;
u8 ack_policy;
- u8 padding[3];
+ u8 padding[2];
__le32 apsd_conf[2];
} __packed;
@@ -804,19 +699,7 @@ struct acx_tx_config_options {
__le16 tx_compl_threshold; /* number of packets */
} __packed;
-#define ACX_TX_DESCRIPTORS 32
-
-struct wl1271_acx_ap_config_memory {
- struct acx_header header;
-
- u8 rx_mem_block_num;
- u8 tx_min_mem_block_num;
- u8 num_stations;
- u8 num_ssid_profiles;
- __le32 total_tx_descriptors;
-} __packed;
-
-struct wl1271_acx_sta_config_memory {
+struct wl12xx_acx_config_memory {
struct acx_header header;
u8 rx_mem_block_num;
@@ -890,9 +773,10 @@ struct wl1271_acx_rx_config_opt {
struct wl1271_acx_bet_enable {
struct acx_header header;
+ u8 role_id;
u8 enable;
u8 max_consecutive;
- u8 padding[2];
+ u8 padding[1];
} __packed;
#define ACX_IPV4_VERSION 4
@@ -905,9 +789,10 @@ struct wl1271_acx_bet_enable {
struct wl1271_acx_arp_filter {
struct acx_header header;
+ u8 role_id;
u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */
u8 enable; /* bitmap of enabled ARP filtering features */
- u8 padding[2];
+ u8 padding[1];
u8 address[16]; /* The configured device IP address - all ARP
requests directed to this IP address will pass
through. For IPv4, the first four bytes are
@@ -925,8 +810,9 @@ struct wl1271_acx_pm_config {
struct wl1271_acx_keep_alive_mode {
struct acx_header header;
+ u8 role_id;
u8 enabled;
- u8 padding[3];
+ u8 padding[2];
} __packed;
enum {
@@ -942,11 +828,11 @@ enum {
struct wl1271_acx_keep_alive_config {
struct acx_header header;
- __le32 period;
+ u8 role_id;
u8 index;
u8 tpl_validation;
u8 trigger;
- u8 padding;
+ __le32 period;
} __packed;
#define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0)
@@ -990,26 +876,33 @@ enum {
struct wl1271_acx_rssi_snr_trigger {
struct acx_header header;
- __le16 threshold;
- __le16 pacing; /* 0 - 60000 ms */
+ u8 role_id;
u8 metric;
u8 type;
u8 dir;
+ __le16 threshold;
+ __le16 pacing; /* 0 - 60000 ms */
u8 hysteresis;
u8 index;
u8 enable;
- u8 padding[2];
+ u8 padding[1];
};
struct wl1271_acx_rssi_snr_avg_weights {
struct acx_header header;
+ u8 role_id;
+ u8 padding[3];
u8 rssi_beacon;
u8 rssi_data;
u8 snr_beacon;
u8 snr_data;
};
+
+/* special capability bit (not employed by the 802.11n spec) */
+#define WL12XX_HT_CAP_HT_OPERATION BIT(16)
+
/*
* ACX_PEER_HT_CAP
* Configure HT capabilities - declare the capabilities of the peer
@@ -1018,28 +911,11 @@ struct wl1271_acx_rssi_snr_avg_weights {
struct wl1271_acx_ht_capabilities {
struct acx_header header;
- /*
- * bit 0 - Allow HT Operation
- * bit 1 - Allow Greenfield format in TX
- * bit 2 - Allow Short GI in TX
- * bit 3 - Allow L-SIG TXOP Protection in TX
- * bit 4 - Allow HT Control fields in TX.
- * Note, driver will still leave space for HT control in packets
- * regardless of the value of this field. FW will be responsible
- * to drop the HT field from any frame when this Bit set to 0.
- * bit 5 - Allow RD initiation in TXOP. FW is allowed to initate RD.
- * Exact policy setting for this feature is TBD.
- * Note, this bit can only be set to 1 if bit 3 is set to 1.
- */
+ /* bitmask of capability bits supported by the peer */
__le32 ht_capabilites;
- /*
- * Indicates to which peer these capabilities apply.
- * For infrastructure use ff:ff:ff:ff:ff:ff that indicates relevance
- * for all peers.
- * Only valid for IBSS/DLS operation.
- */
- u8 mac_address[ETH_ALEN];
+ /* Indicates to which link these capabilities apply. */
+ u8 hlid;
/*
* This the maximum A-MPDU length supported by the AP. The FW may not
@@ -1049,16 +925,9 @@ struct wl1271_acx_ht_capabilities {
/* This is the minimal spacing required when sending A-MPDUs to the AP*/
u8 ampdu_min_spacing;
-} __packed;
-
-/* HT Capabilites Fw Bit Mask Mapping */
-#define WL1271_ACX_FW_CAP_HT_OPERATION BIT(0)
-#define WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT BIT(1)
-#define WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS BIT(2)
-#define WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION BIT(3)
-#define WL1271_ACX_FW_CAP_HT_CONTROL_FIELDS BIT(4)
-#define WL1271_ACX_FW_CAP_RD_INITIATION BIT(5)
+ u8 padding;
+} __packed;
/*
* ACX_HT_BSS_OPERATION
@@ -1067,6 +936,8 @@ struct wl1271_acx_ht_capabilities {
struct wl1271_acx_ht_information {
struct acx_header header;
+ u8 role_id;
+
/* Values: 0 - RIFS not allowed, 1 - RIFS allowed */
u8 rifs_mode;
@@ -1088,60 +959,51 @@ struct wl1271_acx_ht_information {
*/
u8 dual_cts_protection;
- u8 padding[3];
+ u8 padding[2];
} __packed;
-#define RX_BA_WIN_SIZE 8
+#define RX_BA_MAX_SESSIONS 2
-struct wl1271_acx_ba_session_policy {
+struct wl1271_acx_ba_initiator_policy {
struct acx_header header;
- /*
- * Specifies role Id, Range 0-7, 0xFF means ANY role.
- * Future use. For now this field is irrelevant
- */
+
+ /* Specifies role Id, Range 0-7, 0xFF means ANY role. */
u8 role_id;
+
/*
- * Specifies Link Id, Range 0-31, 0xFF means ANY Link Id.
- * Not applicable if Role Id is set to ANY.
+ * Per TID setting for allowing TX BA. Set a bit to 1 to allow
+ * TX BA sessions for the corresponding TID.
*/
- u8 link_id;
-
- u8 tid;
-
- u8 enable;
+ u8 tid_bitmap;
/* Windows size in number of packets */
- u16 win_size;
+ u8 win_size;
- /*
- * As initiator inactivity timeout in time units(TU) of 1024us.
- * As receiver reserved
- */
- u16 inactivity_timeout;
+ u8 padding1[1];
- /* Initiator = 1/Receiver = 0 */
- u8 ba_direction;
+ /* As initiator inactivity timeout in time units(TU) of 1024us */
+ u16 inactivity_timeout;
- u8 padding[3];
+ u8 padding[2];
} __packed;
struct wl1271_acx_ba_receiver_setup {
struct acx_header header;
- /* Specifies Link Id, Range 0-31, 0xFF means ANY Link Id */
- u8 link_id;
+ /* Specifies link id, range 0-31 */
+ u8 hlid;
u8 tid;
u8 enable;
- u8 padding[1];
-
/* Windows size in number of packets */
- u16 win_size;
+ u8 win_size;
/* BA session starting sequence number. RANGE 0-FFF */
u16 ssn;
+
+ u8 padding[2];
} __packed;
struct wl1271_acx_fw_tsf_information {
@@ -1158,6 +1020,7 @@ struct wl1271_acx_fw_tsf_information {
struct wl1271_acx_ps_rx_streaming {
struct acx_header header;
+ u8 role_id;
u8 tid;
u8 enable;
@@ -1166,17 +1029,20 @@ struct wl1271_acx_ps_rx_streaming {
/* timeout before first trigger (0-200 msec) */
u8 timeout;
+ u8 padding[3];
} __packed;
struct wl1271_acx_ap_max_tx_retry {
struct acx_header header;
+ u8 role_id;
+ u8 padding_1;
+
/*
* the number of frames transmission failures before
* issuing the aging event.
*/
__le16 max_tx_retry;
- u8 padding_1[2];
} __packed;
struct wl1271_acx_config_ps {
@@ -1195,13 +1061,6 @@ struct wl1271_acx_inconnection_sta {
u8 padding1[2];
} __packed;
-struct acx_ap_beacon_filter {
- struct acx_header header;
-
- u8 enable;
- u8 pad[3];
-} __packed;
-
/*
* ACX_FM_COEX_CFG
* set the FM co-existence parameters.
@@ -1261,6 +1120,30 @@ struct wl1271_acx_fm_coex {
u8 swallow_clk_diff;
} __packed;
+#define ACX_RATE_MGMT_ALL_PARAMS 0xff
+struct wl12xx_acx_set_rate_mgmt_params {
+ struct acx_header header;
+
+ u8 index; /* 0xff to configure all params */
+ u8 padding1;
+ __le16 rate_retry_score;
+ __le16 per_add;
+ __le16 per_th1;
+ __le16 per_th2;
+ __le16 max_per;
+ u8 inverse_curiosity_factor;
+ u8 tx_fail_low_th;
+ u8 tx_fail_high_th;
+ u8 per_alpha_shift;
+ u8 per_add_shift;
+ u8 per_beta1_shift;
+ u8 per_beta2_shift;
+ u8 rate_check_up;
+ u8 rate_check_down;
+ u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES];
+ u8 padding2[2];
+} __packed;
+
enum {
ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003,
@@ -1268,10 +1151,7 @@ enum {
ACX_AC_CFG = 0x0007,
ACX_MEM_MAP = 0x0008,
ACX_AID = 0x000A,
- /* ACX_FW_REV is missing in the ref driver, but seems to work */
- ACX_FW_REV = 0x000D,
ACX_MEDIUM_USAGE = 0x000F,
- ACX_RX_CFG = 0x0010,
ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */
ACX_STATISTICS = 0x0013, /* Debug API */
ACX_PWR_CONSUMPTION_STATISTICS = 0x0014,
@@ -1279,7 +1159,6 @@ enum {
ACX_TID_CFG = 0x001A,
ACX_PS_RX_STREAMING = 0x001B,
ACX_BEACON_FILTER_OPT = 0x001F,
- ACX_AP_BEACON_FILTER_OPT = 0x0020,
ACX_NOISE_HIST = 0x0021,
ACX_HDK_VERSION = 0x0022, /* ??? */
ACX_PD_THRESHOLD = 0x0023,
@@ -1287,7 +1166,6 @@ enum {
ACX_CCA_THRESHOLD = 0x0025,
ACX_EVENT_MBOX_MASK = 0x0026,
ACX_CONN_MONIT_PARAMS = 0x002D,
- ACX_CONS_TX_FAILURE = 0x002F,
ACX_BCN_DTIM_OPTIONS = 0x0031,
ACX_SG_ENABLE = 0x0032,
ACX_SG_CFG = 0x0033,
@@ -1314,11 +1192,14 @@ enum {
ACX_RSSI_SNR_WEIGHTS = 0x0052,
ACX_KEEP_ALIVE_MODE = 0x0053,
ACX_SET_KEEP_ALIVE_CONFIG = 0x0054,
- ACX_BA_SESSION_POLICY_CFG = 0x0055,
+ ACX_BA_SESSION_INIT_POLICY = 0x0055,
ACX_BA_SESSION_RX_SETUP = 0x0056,
ACX_PEER_HT_CAP = 0x0057,
ACX_HT_BSS_OPERATION = 0x0058,
ACX_COEX_ACTIVITY = 0x0059,
+ ACX_BURST_MODE = 0x005C,
+ ACX_SET_RATE_MGMT_PARAMS = 0x005D,
+ ACX_SET_RATE_ADAPT_PARAMS = 0x0060,
ACX_SET_DCO_ITRIM_PARAMS = 0x0061,
ACX_GEN_FW_CMD = 0x0070,
ACX_HOST_IF_CFG_BITMAP = 0x0071,
@@ -1342,7 +1223,6 @@ int wl1271_acx_feature_cfg(struct wl1271 *wl);
int wl1271_acx_mem_map(struct wl1271 *wl,
struct acx_header *mem_map, size_t len);
int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl);
-int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter);
int wl1271_acx_pd_threshold(struct wl1271 *wl);
int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time);
int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
@@ -1354,8 +1234,7 @@ int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter);
int wl1271_acx_beacon_filter_table(struct wl1271 *wl);
int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable);
int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable);
-int wl1271_acx_sta_sg_cfg(struct wl1271 *wl);
-int wl1271_acx_ap_sg_cfg(struct wl1271 *wl);
+int wl12xx_acx_sg_cfg(struct wl1271 *wl);
int wl1271_acx_cca_threshold(struct wl1271 *wl);
int wl1271_acx_bcn_dtim_options(struct wl1271 *wl);
int wl1271_acx_aid(struct wl1271 *wl, u16 aid);
@@ -1374,8 +1253,7 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
u32 apsd_conf0, u32 apsd_conf1);
int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold);
int wl1271_acx_tx_config_options(struct wl1271 *wl);
-int wl1271_acx_ap_mem_cfg(struct wl1271 *wl);
-int wl1271_acx_sta_mem_cfg(struct wl1271 *wl);
+int wl12xx_acx_mem_cfg(struct wl1271 *wl);
int wl1271_acx_init_mem_config(struct wl1271 *wl);
int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap);
int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
@@ -1390,20 +1268,18 @@ int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl);
int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
- bool allow_ht_operation);
+ bool allow_ht_operation, u8 hlid);
int wl1271_acx_set_ht_information(struct wl1271 *wl,
u16 ht_operation_mode);
-int wl1271_acx_set_ba_session(struct wl1271 *wl,
- enum ieee80211_back_parties direction,
- u8 tid_index, u8 policy);
-int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
- bool enable);
+int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl);
+int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
+ u16 ssn, bool enable, u8 peer_hlid);
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable);
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl);
int wl1271_acx_config_ps(struct wl1271 *wl);
int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
-int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable);
int wl1271_acx_fm_coex(struct wl1271 *wl);
+int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl);
#endif /* __WL1271_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c
index a816f2ffa6a..cc70422c057 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/boot.c
@@ -107,16 +107,6 @@ static unsigned int wl12xx_get_fw_ver_quirks(struct wl1271 *wl)
unsigned int quirks = 0;
unsigned int *fw_ver = wl->chip.fw_ver;
- /* Only for wl127x */
- if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
- /* Check STA version */
- (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
- (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
- /* Check AP version */
- ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
- (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
- quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
-
/* Only new station firmwares support routing fw logs to the host */
if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
(fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN))
@@ -504,21 +494,18 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
wl->event_mask = BSS_LOSE_EVENT_ID |
SCAN_COMPLETE_EVENT_ID |
PS_REPORT_EVENT_ID |
- JOIN_EVENT_COMPLETE_ID |
DISCONNECT_EVENT_COMPLETE_ID |
RSSI_SNR_TRIGGER_0_EVENT_ID |
PSPOLL_DELIVERY_FAILURE_EVENT_ID |
SOFT_GEMINI_SENSE_EVENT_ID |
PERIODIC_SCAN_REPORT_EVENT_ID |
- PERIODIC_SCAN_COMPLETE_EVENT_ID;
-
- if (wl->bss_type == BSS_TYPE_AP_BSS)
- wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID |
- INACTIVE_STA_EVENT_ID |
- MAX_TX_RETRY_EVENT_ID;
- else
- wl->event_mask |= DUMMY_PACKET_EVENT_ID |
- BA_SESSION_RX_CONSTRAINT_EVENT_ID;
+ PERIODIC_SCAN_COMPLETE_EVENT_ID |
+ DUMMY_PACKET_EVENT_ID |
+ PEER_REMOVE_COMPLETE_EVENT_ID |
+ BA_SESSION_RX_CONSTRAINT_EVENT_ID |
+ REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
+ INACTIVE_STA_EVENT_ID |
+ MAX_TX_RETRY_EVENT_ID;
ret = wl1271_event_unmask(wl);
if (ret < 0) {
@@ -855,9 +842,6 @@ int wl1271_boot(struct wl1271 *wl)
/* Enable firmware interrupts now */
wl1271_boot_enable_interrupts(wl);
- /* set the wl1271 default filters */
- wl1271_set_default_filters(wl);
-
wl1271_event_mbox_config(wl);
out:
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 97dd237a958..817bc183bc8 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -363,63 +363,470 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
return 0;
}
-int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
+int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id)
{
- struct wl1271_cmd_join *join;
- int ret, i;
- u8 *bssid;
+ struct wl12xx_cmd_role_enable *cmd;
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "cmd role enable");
- join = kzalloc(sizeof(*join), GFP_KERNEL);
- if (!join) {
+ if (WARN_ON(*role_id != WL12XX_INVALID_ROLE_ID))
+ return -EBUSY;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
ret = -ENOMEM;
goto out;
}
- wl1271_debug(DEBUG_CMD, "cmd join");
+ /* get role id */
+ cmd->role_id = find_first_zero_bit(wl->roles_map, WL12XX_MAX_ROLES);
+ if (cmd->role_id >= WL12XX_MAX_ROLES) {
+ ret = -EBUSY;
+ goto out_free;
+ }
+
+ memcpy(cmd->mac_address, wl->mac_addr, ETH_ALEN);
+ cmd->role_type = role_type;
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_ENABLE, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role enable");
+ goto out_free;
+ }
+
+ __set_bit(cmd->role_id, wl->roles_map);
+ *role_id = cmd->role_id;
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id)
+{
+ struct wl12xx_cmd_role_disable *cmd;
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "cmd role disable");
+
+ if (WARN_ON(*role_id == WL12XX_INVALID_ROLE_ID))
+ return -ENOENT;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ cmd->role_id = *role_id;
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_DISABLE, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role disable");
+ goto out_free;
+ }
+
+ __clear_bit(*role_id, wl->roles_map);
+ *role_id = WL12XX_INVALID_ROLE_ID;
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+static int wl12xx_allocate_link(struct wl1271 *wl, u8 *hlid)
+{
+ u8 link = find_first_zero_bit(wl->links_map, WL12XX_MAX_LINKS);
+ if (link >= WL12XX_MAX_LINKS)
+ return -EBUSY;
+
+ __set_bit(link, wl->links_map);
+ *hlid = link;
+ return 0;
+}
+
+static void wl12xx_free_link(struct wl1271 *wl, u8 *hlid)
+{
+ if (*hlid == WL12XX_INVALID_LINK_ID)
+ return;
+
+ __clear_bit(*hlid, wl->links_map);
+ *hlid = WL12XX_INVALID_LINK_ID;
+}
+
+static int wl12xx_get_new_session_id(struct wl1271 *wl)
+{
+ if (wl->session_counter >= SESSION_COUNTER_MAX)
+ wl->session_counter = 0;
+
+ wl->session_counter++;
- /* Reverse order BSSID */
- bssid = (u8 *) &join->bssid_lsb;
- for (i = 0; i < ETH_ALEN; i++)
- bssid[i] = wl->bssid[ETH_ALEN - i - 1];
+ return wl->session_counter;
+}
+
+int wl12xx_cmd_role_start_dev(struct wl1271 *wl)
+{
+ struct wl12xx_cmd_role_start *cmd;
+ int ret;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
- join->rx_config_options = cpu_to_le32(wl->rx_config);
- join->rx_filter_options = cpu_to_le32(wl->rx_filter);
- join->bss_type = bss_type;
- join->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
- join->supported_rate_set = cpu_to_le32(wl->rate_set);
+ wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wl->dev_role_id);
+ cmd->role_id = wl->dev_role_id;
if (wl->band == IEEE80211_BAND_5GHZ)
- join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ;
+ cmd->band = WL12XX_BAND_5GHZ;
+ cmd->channel = wl->channel;
+
+ if (wl->dev_hlid == WL12XX_INVALID_LINK_ID) {
+ ret = wl12xx_allocate_link(wl, &wl->dev_hlid);
+ if (ret)
+ goto out_free;
+ }
+ cmd->device.hlid = wl->dev_hlid;
+ cmd->device.session = wl->session_counter;
+
+ wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d",
+ cmd->role_id, cmd->device.hlid, cmd->device.session);
- join->beacon_interval = cpu_to_le16(wl->beacon_int);
- join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD;
+ ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role enable");
+ goto err_hlid;
+ }
+
+ goto out_free;
+
+err_hlid:
+ /* clear links on error */
+ __clear_bit(wl->dev_hlid, wl->links_map);
+ wl->dev_hlid = WL12XX_INVALID_LINK_ID;
+
+
+out_free:
+ kfree(cmd);
- join->channel = wl->channel;
- join->ssid_len = wl->ssid_len;
- memcpy(join->ssid, wl->ssid, wl->ssid_len);
+out:
+ return ret;
+}
- join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
+int wl12xx_cmd_role_stop_dev(struct wl1271 *wl)
+{
+ struct wl12xx_cmd_role_stop *cmd;
+ int ret;
- wl1271_debug(DEBUG_CMD, "cmd join: basic_rate_set=0x%x, rate_set=0x%x",
- join->basic_rate_set, join->supported_rate_set);
+ if (WARN_ON(wl->dev_hlid == WL12XX_INVALID_LINK_ID))
+ return -EINVAL;
- ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join), 0);
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd role stop dev");
+
+ cmd->role_id = wl->dev_role_id;
+ cmd->disc_type = DISCONNECT_IMMEDIATE;
+ cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED);
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to initiate cmd join");
+ wl1271_error("failed to initiate cmd role stop");
goto out_free;
}
- ret = wl1271_cmd_wait_for_event(wl, JOIN_EVENT_COMPLETE_ID);
+ ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
+ if (ret < 0) {
+ wl1271_error("cmd role stop dev event completion error");
+ goto out_free;
+ }
+
+ wl12xx_free_link(wl, &wl->dev_hlid);
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+int wl12xx_cmd_role_start_sta(struct wl1271 *wl)
+{
+ struct wl12xx_cmd_role_start *cmd;
+ int ret;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wl->role_id);
+
+ cmd->role_id = wl->role_id;
+ if (wl->band == IEEE80211_BAND_5GHZ)
+ cmd->band = WL12XX_BAND_5GHZ;
+ cmd->channel = wl->channel;
+ cmd->sta.basic_rate_set = cpu_to_le32(wl->basic_rate_set);
+ cmd->sta.beacon_interval = cpu_to_le16(wl->beacon_int);
+ cmd->sta.ssid_type = WL12XX_SSID_TYPE_ANY;
+ cmd->sta.ssid_len = wl->ssid_len;
+ memcpy(cmd->sta.ssid, wl->ssid, wl->ssid_len);
+ memcpy(cmd->sta.bssid, wl->bssid, ETH_ALEN);
+ cmd->sta.local_rates = cpu_to_le32(wl->rate_set);
+
+ if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) {
+ ret = wl12xx_allocate_link(wl, &wl->sta_hlid);
+ if (ret)
+ goto out_free;
+ }
+ cmd->sta.hlid = wl->sta_hlid;
+ cmd->sta.session = wl12xx_get_new_session_id(wl);
+ cmd->sta.remote_rates = cpu_to_le32(wl->rate_set);
+
+ wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
+ "basic_rate_set: 0x%x, remote_rates: 0x%x",
+ wl->role_id, cmd->sta.hlid, cmd->sta.session,
+ wl->basic_rate_set, wl->rate_set);
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role start sta");
+ goto err_hlid;
+ }
+
+ goto out_free;
+
+err_hlid:
+ /* clear links on error. */
+ wl12xx_free_link(wl, &wl->sta_hlid);
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+/* use this function to stop ibss as well */
+int wl12xx_cmd_role_stop_sta(struct wl1271 *wl)
+{
+ struct wl12xx_cmd_role_stop *cmd;
+ int ret;
+
+ if (WARN_ON(wl->sta_hlid == WL12XX_INVALID_LINK_ID))
+ return -EINVAL;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd role stop sta %d", wl->role_id);
+
+ cmd->role_id = wl->role_id;
+ cmd->disc_type = DISCONNECT_IMMEDIATE;
+ cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED);
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role stop sta");
+ goto out_free;
+ }
+
+ wl12xx_free_link(wl, &wl->sta_hlid);
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
+{
+ struct wl12xx_cmd_role_start *cmd;
+ struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
+ int ret;
+
+ 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");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = wl12xx_allocate_link(wl, &wl->ap_global_hlid);
if (ret < 0)
- wl1271_error("cmd join event completion error");
+ goto out_free;
+
+ ret = wl12xx_allocate_link(wl, &wl->ap_bcast_hlid);
+ if (ret < 0)
+ goto out_free_global;
+
+ cmd->role_id = wl->role_id;
+ cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
+ cmd->ap.bss_index = WL1271_AP_BSS_INDEX;
+ cmd->ap.global_hlid = wl->ap_global_hlid;
+ cmd->ap.broadcast_hlid = wl->ap_bcast_hlid;
+ cmd->ap.basic_rate_set = cpu_to_le32(wl->basic_rate_set);
+ cmd->ap.beacon_interval = cpu_to_le16(wl->beacon_int);
+ 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);
+ cmd->ap.local_rates = cpu_to_le32(0xffffffff);
+
+ switch (wl->band) {
+ case IEEE80211_BAND_2GHZ:
+ cmd->band = RADIO_BAND_2_4GHZ;
+ break;
+ case IEEE80211_BAND_5GHZ:
+ cmd->band = RADIO_BAND_5GHZ;
+ break;
+ default:
+ wl1271_warning("ap start - unknown band: %d", (int)wl->band);
+ cmd->band = RADIO_BAND_2_4GHZ;
+ break;
+ }
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role start ap");
+ goto out_free_bcast;
+ }
+
+ goto out_free;
+
+out_free_bcast:
+ wl12xx_free_link(wl, &wl->ap_bcast_hlid);
+
+out_free_global:
+ wl12xx_free_link(wl, &wl->ap_global_hlid);
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+int wl12xx_cmd_role_stop_ap(struct wl1271 *wl)
+{
+ struct wl12xx_cmd_role_stop *cmd;
+ int ret;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd role stop ap %d", wl->role_id);
+
+ cmd->role_id = wl->role_id;
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role stop ap");
+ goto out_free;
+ }
+
+ wl12xx_free_link(wl, &wl->ap_bcast_hlid);
+ wl12xx_free_link(wl, &wl->ap_global_hlid);
out_free:
- kfree(join);
+ kfree(cmd);
out:
return ret;
}
+int wl12xx_cmd_role_start_ibss(struct wl1271 *wl)
+{
+ struct wl12xx_cmd_role_start *cmd;
+ struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
+ int ret;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wl->role_id);
+
+ cmd->role_id = wl->role_id;
+ if (wl->band == IEEE80211_BAND_5GHZ)
+ cmd->band = WL12XX_BAND_5GHZ;
+ cmd->channel = wl->channel;
+ cmd->ibss.basic_rate_set = cpu_to_le32(wl->basic_rate_set);
+ cmd->ibss.beacon_interval = cpu_to_le16(wl->beacon_int);
+ cmd->ibss.dtim_interval = bss_conf->dtim_period;
+ cmd->ibss.ssid_type = WL12XX_SSID_TYPE_ANY;
+ cmd->ibss.ssid_len = wl->ssid_len;
+ memcpy(cmd->ibss.ssid, wl->ssid, wl->ssid_len);
+ memcpy(cmd->ibss.bssid, wl->bssid, ETH_ALEN);
+ cmd->sta.local_rates = cpu_to_le32(wl->rate_set);
+
+ if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) {
+ ret = wl12xx_allocate_link(wl, &wl->sta_hlid);
+ if (ret)
+ goto out_free;
+ }
+ cmd->ibss.hlid = wl->sta_hlid;
+ cmd->ibss.remote_rates = cpu_to_le32(wl->rate_set);
+
+ wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
+ "basic_rate_set: 0x%x, remote_rates: 0x%x",
+ wl->role_id, cmd->sta.hlid, cmd->sta.session,
+ wl->basic_rate_set, wl->rate_set);
+
+ wl1271_debug(DEBUG_CMD, "wl->bssid = %pM", wl->bssid);
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role enable");
+ goto err_hlid;
+ }
+
+ goto out_free;
+
+err_hlid:
+ /* clear links on error. */
+ wl12xx_free_link(wl, &wl->sta_hlid);
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+
/**
* send test command to firmware
*
@@ -567,6 +974,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
goto out;
}
+ ps_params->role_id = wl->role_id;
ps_params->ps_mode = ps_mode;
ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
@@ -813,9 +1221,9 @@ int wl1271_build_qos_null_data(struct wl1271 *wl)
wl->basic_rate);
}
-int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id)
+int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid)
{
- struct wl1271_cmd_set_sta_keys *cmd;
+ struct wl1271_cmd_set_keys *cmd;
int ret = 0;
wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id);
@@ -826,36 +1234,7 @@ int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id)
goto out;
}
- cmd->id = id;
- cmd->key_action = cpu_to_le16(KEY_SET_ID);
- cmd->key_type = KEY_WEP;
-
- ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
- if (ret < 0) {
- wl1271_warning("cmd set_default_wep_key failed: %d", ret);
- goto out;
- }
-
-out:
- kfree(cmd);
-
- return ret;
-}
-
-int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id)
-{
- struct wl1271_cmd_set_ap_keys *cmd;
- int ret = 0;
-
- wl1271_debug(DEBUG_CMD, "cmd set_ap_default_wep_key %d", id);
-
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (!cmd) {
- ret = -ENOMEM;
- goto out;
- }
-
- cmd->hlid = WL1271_AP_BROADCAST_HLID;
+ cmd->hlid = hlid;
cmd->key_id = id;
cmd->lid_key_type = WEP_DEFAULT_LID_TYPE;
cmd->key_action = cpu_to_le16(KEY_SET_ID);
@@ -863,7 +1242,7 @@ int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id)
ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_warning("cmd set_ap_default_wep_key failed: %d", ret);
+ wl1271_warning("cmd set_default_wep_key failed: %d", ret);
goto out;
}
@@ -877,17 +1256,27 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, const u8 *addr,
u32 tx_seq_32, u16 tx_seq_16)
{
- struct wl1271_cmd_set_sta_keys *cmd;
+ struct wl1271_cmd_set_keys *cmd;
int ret = 0;
+ /* hlid might have already been deleted */
+ if (wl->sta_hlid == WL12XX_INVALID_LINK_ID)
+ return 0;
+
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
- if (key_type != KEY_WEP)
- memcpy(cmd->addr, addr, ETH_ALEN);
+ cmd->hlid = wl->sta_hlid;
+
+ if (key_type == KEY_WEP)
+ cmd->lid_key_type = WEP_DEFAULT_LID_TYPE;
+ else if (is_broadcast_ether_addr(addr))
+ cmd->lid_key_type = BROADCAST_LID_TYPE;
+ else
+ cmd->lid_key_type = UNICAST_LID_TYPE;
cmd->key_action = cpu_to_le16(action);
cmd->key_size = key_size;
@@ -896,10 +1285,7 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);
- /* we have only one SSID profile */
- cmd->ssid_profile = 0;
-
- cmd->id = id;
+ cmd->key_id = id;
if (key_type == KEY_TKIP) {
/*
@@ -930,11 +1316,15 @@ out:
return ret;
}
+/*
+ * TODO: merge with sta/ibss into 1 set_key function.
+ * note there are slight diffs
+ */
int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
u16 tx_seq_16)
{
- struct wl1271_cmd_set_ap_keys *cmd;
+ struct wl1271_cmd_set_keys *cmd;
int ret = 0;
u8 lid_type;
@@ -942,7 +1332,7 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
if (!cmd)
return -ENOMEM;
- if (hlid == WL1271_AP_BROADCAST_HLID) {
+ if (hlid == wl->ap_bcast_hlid) {
if (key_type == KEY_WEP)
lid_type = WEP_DEFAULT_LID_TYPE;
else
@@ -991,12 +1381,12 @@ out:
return ret;
}
-int wl1271_cmd_disconnect(struct wl1271 *wl)
+int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid)
{
- struct wl1271_cmd_disconnect *cmd;
+ struct wl12xx_cmd_set_peer_state *cmd;
int ret = 0;
- wl1271_debug(DEBUG_CMD, "cmd disconnect");
+ wl1271_debug(DEBUG_CMD, "cmd set peer state (hlid=%d)", hlid);
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1004,21 +1394,15 @@ int wl1271_cmd_disconnect(struct wl1271 *wl)
goto out;
}
- cmd->rx_config_options = cpu_to_le32(wl->rx_config);
- cmd->rx_filter_options = cpu_to_le32(wl->rx_filter);
- /* disconnect reason is not used in immediate disconnections */
- cmd->type = DISCONNECT_IMMEDIATE;
+ cmd->hlid = hlid;
+ cmd->state = WL1271_CMD_STA_STATE_CONNECTED;
- ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd), 0);
+ ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to send disconnect command");
+ wl1271_error("failed to send set peer state command");
goto out_free;
}
- ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
- if (ret < 0)
- wl1271_error("cmd disconnect event completion error");
-
out_free:
kfree(cmd);
@@ -1026,12 +1410,13 @@ out:
return ret;
}
-int wl1271_cmd_set_sta_state(struct wl1271 *wl)
+int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
{
- struct wl1271_cmd_set_sta_state *cmd;
- int ret = 0;
+ struct wl12xx_cmd_add_peer *cmd;
+ int ret;
+ u32 sta_rates;
- wl1271_debug(DEBUG_CMD, "cmd set sta state");
+ wl1271_debug(DEBUG_CMD, "cmd add peer %d", (int)hlid);
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1039,11 +1424,27 @@ int wl1271_cmd_set_sta_state(struct wl1271 *wl)
goto out;
}
- cmd->state = WL1271_CMD_STA_STATE_CONNECTED;
+ /* 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->wmm = sta->wme ? 1 : 0;
+
+ 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));
- ret = wl1271_cmd_send(wl, CMD_SET_STA_STATE, cmd, sizeof(*cmd), 0);
+ wl1271_debug(DEBUG_CMD, "new peer rates: 0x%x", cmd->supported_rates);
+
+ ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to send set STA state command");
+ wl1271_error("failed to initiate cmd add peer");
goto out_free;
}
@@ -1054,23 +1455,12 @@ out:
return ret;
}
-int wl1271_cmd_start_bss(struct wl1271 *wl)
+int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
{
- struct wl1271_cmd_bss_start *cmd;
- struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
+ struct wl12xx_cmd_remove_peer *cmd;
int ret;
- wl1271_debug(DEBUG_CMD, "cmd start bss");
-
- /*
- * FIXME: 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");
- ret = -EINVAL;
- goto out;
- }
+ wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid);
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1078,40 +1468,24 @@ int wl1271_cmd_start_bss(struct wl1271 *wl)
goto out;
}
- memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN);
-
- cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
- cmd->bss_index = WL1271_AP_BSS_INDEX;
- cmd->global_hlid = WL1271_AP_GLOBAL_HLID;
- cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID;
- cmd->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
- cmd->beacon_interval = cpu_to_le16(wl->beacon_int);
- cmd->dtim_interval = bss_conf->dtim_period;
- cmd->beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
- cmd->channel = wl->channel;
- cmd->ssid_len = wl->ssid_len;
- cmd->ssid_type = SSID_TYPE_PUBLIC;
- memcpy(cmd->ssid, wl->ssid, wl->ssid_len);
-
- switch (wl->band) {
- case IEEE80211_BAND_2GHZ:
- cmd->band = RADIO_BAND_2_4GHZ;
- break;
- case IEEE80211_BAND_5GHZ:
- cmd->band = RADIO_BAND_5GHZ;
- break;
- default:
- wl1271_warning("bss start - unknown band: %d", (int)wl->band);
- cmd->band = RADIO_BAND_2_4GHZ;
- break;
- }
+ cmd->hlid = hlid;
+ /* We never send a deauth, mac80211 is in charge of this */
+ cmd->reason_opcode = 0;
+ cmd->send_deauth_flag = 0;
- ret = wl1271_cmd_send(wl, CMD_BSS_START, cmd, sizeof(*cmd), 0);
+ ret = wl1271_cmd_send(wl, CMD_REMOVE_PEER, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to initiate cmd start bss");
+ wl1271_error("failed to initiate cmd remove peer");
goto out_free;
}
+ /*
+ * We are ok with a timeout here. The event is sometimes not sent
+ * due to a firmware bug.
+ */
+ wl1271_cmd_wait_for_event_or_timeout(wl,
+ PEER_REMOVE_COMPLETE_EVENT_ID);
+
out_free:
kfree(cmd);
@@ -1119,12 +1493,12 @@ out:
return ret;
}
-int wl1271_cmd_stop_bss(struct wl1271 *wl)
+int wl12xx_cmd_config_fwlog(struct wl1271 *wl)
{
- struct wl1271_cmd_bss_start *cmd;
- int ret;
+ struct wl12xx_cmd_config_fwlog *cmd;
+ int ret = 0;
- wl1271_debug(DEBUG_CMD, "cmd stop bss");
+ wl1271_debug(DEBUG_CMD, "cmd config firmware logger");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1132,11 +1506,15 @@ int wl1271_cmd_stop_bss(struct wl1271 *wl)
goto out;
}
- cmd->bss_index = WL1271_AP_BSS_INDEX;
+ cmd->logger_mode = wl->conf.fwlog.mode;
+ cmd->log_severity = wl->conf.fwlog.severity;
+ cmd->timestamp = wl->conf.fwlog.timestamp;
+ cmd->output = wl->conf.fwlog.output;
+ cmd->threshold = wl->conf.fwlog.threshold;
- ret = wl1271_cmd_send(wl, CMD_BSS_STOP, cmd, sizeof(*cmd), 0);
+ ret = wl1271_cmd_send(wl, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to initiate cmd stop bss");
+ wl1271_error("failed to send config firmware logger command");
goto out_free;
}
@@ -1147,12 +1525,12 @@ out:
return ret;
}
-int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
+int wl12xx_cmd_start_fwlog(struct wl1271 *wl)
{
- struct wl1271_cmd_add_sta *cmd;
- int ret;
+ struct wl12xx_cmd_start_fwlog *cmd;
+ int ret = 0;
- wl1271_debug(DEBUG_CMD, "cmd add sta %d", (int)hlid);
+ wl1271_debug(DEBUG_CMD, "cmd start firmware logger");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1160,23 +1538,9 @@ int wl1271_cmd_add_sta(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->wmm = sta->wme ? 1 : 0;
-
- cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl,
- sta->supp_rates[wl->band]));
-
- wl1271_debug(DEBUG_CMD, "new sta rates: 0x%x", cmd->supported_rates);
-
- ret = wl1271_cmd_send(wl, CMD_ADD_STA, cmd, sizeof(*cmd), 0);
+ ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to initiate cmd add sta");
+ wl1271_error("failed to send start firmware logger command");
goto out_free;
}
@@ -1187,12 +1551,12 @@ out:
return ret;
}
-int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid)
+int wl12xx_cmd_stop_fwlog(struct wl1271 *wl)
{
- struct wl1271_cmd_remove_sta *cmd;
- int ret;
+ struct wl12xx_cmd_stop_fwlog *cmd;
+ int ret = 0;
- wl1271_debug(DEBUG_CMD, "cmd remove sta %d", (int)hlid);
+ wl1271_debug(DEBUG_CMD, "cmd stop firmware logger");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1200,23 +1564,12 @@ int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid)
goto out;
}
- cmd->hlid = hlid;
- /* We never send a deauth, mac80211 is in charge of this */
- cmd->reason_opcode = 0;
- cmd->send_deauth_flag = 0;
-
- ret = wl1271_cmd_send(wl, CMD_REMOVE_STA, cmd, sizeof(*cmd), 0);
+ ret = wl1271_cmd_send(wl, CMD_STOP_FWLOGGER, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to initiate cmd remove sta");
+ wl1271_error("failed to send stop firmware logger command");
goto out_free;
}
- /*
- * We are ok with a timeout here. The event is sometimes not sent
- * due to a firmware bug.
- */
- wl1271_cmd_wait_for_event_or_timeout(wl, STA_REMOVE_COMPLETE_EVENT_ID);
-
out_free:
kfree(cmd);
@@ -1224,12 +1577,15 @@ out:
return ret;
}
-int wl12xx_cmd_config_fwlog(struct wl1271 *wl)
+static int wl12xx_cmd_roc(struct wl1271 *wl, u8 role_id)
{
- struct wl12xx_cmd_config_fwlog *cmd;
+ struct wl12xx_cmd_roc *cmd;
int ret = 0;
- wl1271_debug(DEBUG_CMD, "cmd config firmware logger");
+ wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wl->channel, role_id);
+
+ if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID))
+ return -EINVAL;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1237,15 +1593,25 @@ int wl12xx_cmd_config_fwlog(struct wl1271 *wl)
goto out;
}
- cmd->logger_mode = wl->conf.fwlog.mode;
- cmd->log_severity = wl->conf.fwlog.severity;
- cmd->timestamp = wl->conf.fwlog.timestamp;
- cmd->output = wl->conf.fwlog.output;
- cmd->threshold = wl->conf.fwlog.threshold;
+ cmd->role_id = role_id;
+ cmd->channel = wl->channel;
+ switch (wl->band) {
+ case IEEE80211_BAND_2GHZ:
+ cmd->band = RADIO_BAND_2_4GHZ;
+ break;
+ case IEEE80211_BAND_5GHZ:
+ cmd->band = RADIO_BAND_5GHZ;
+ break;
+ default:
+ wl1271_error("roc - unknown band: %d", (int)wl->band);
+ ret = -EINVAL;
+ goto out_free;
+ }
- ret = wl1271_cmd_send(wl, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0);
+
+ ret = wl1271_cmd_send(wl, CMD_REMAIN_ON_CHANNEL, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to send config firmware logger command");
+ wl1271_error("failed to send ROC command");
goto out_free;
}
@@ -1256,22 +1622,24 @@ out:
return ret;
}
-int wl12xx_cmd_start_fwlog(struct wl1271 *wl)
+static int wl12xx_cmd_croc(struct wl1271 *wl, u8 role_id)
{
- struct wl12xx_cmd_start_fwlog *cmd;
+ struct wl12xx_cmd_croc *cmd;
int ret = 0;
- wl1271_debug(DEBUG_CMD, "cmd start firmware logger");
+ wl1271_debug(DEBUG_CMD, "cmd croc (%d)", role_id);
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
+ cmd->role_id = role_id;
- ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0);
+ ret = wl1271_cmd_send(wl, CMD_CANCEL_REMAIN_ON_CHANNEL, cmd,
+ sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to send start firmware logger command");
+ wl1271_error("failed to send ROC command");
goto out_free;
}
@@ -1282,28 +1650,41 @@ out:
return ret;
}
-int wl12xx_cmd_stop_fwlog(struct wl1271 *wl)
+int wl12xx_roc(struct wl1271 *wl, u8 role_id)
{
- struct wl12xx_cmd_stop_fwlog *cmd;
int ret = 0;
- wl1271_debug(DEBUG_CMD, "cmd stop firmware logger");
+ if (WARN_ON(test_bit(role_id, wl->roc_map)))
+ return 0;
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (!cmd) {
- ret = -ENOMEM;
+ ret = wl12xx_cmd_roc(wl, role_id);
+ if (ret < 0)
goto out;
- }
- ret = wl1271_cmd_send(wl, CMD_STOP_FWLOGGER, cmd, sizeof(*cmd), 0);
+ ret = wl1271_cmd_wait_for_event(wl,
+ REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID);
if (ret < 0) {
- wl1271_error("failed to send stop firmware logger command");
- goto out_free;
+ wl1271_error("cmd roc event completion error");
+ goto out;
}
-out_free:
- kfree(cmd);
+ __set_bit(role_id, wl->roc_map);
+out:
+ return ret;
+}
+
+int wl12xx_croc(struct wl1271 *wl, u8 role_id)
+{
+ int ret = 0;
+
+ if (WARN_ON(!test_bit(role_id, wl->roc_map)))
+ return 0;
+
+ ret = wl12xx_cmd_croc(wl, role_id);
+ if (ret < 0)
+ goto out;
+ __clear_bit(role_id, wl->roc_map);
out:
return ret;
}
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index bba077ecd94..22c2f373dd0 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -36,7 +36,15 @@ int wl128x_cmd_general_parms(struct wl1271 *wl);
int wl1271_cmd_radio_parms(struct wl1271 *wl);
int wl128x_cmd_radio_parms(struct wl1271 *wl);
int wl1271_cmd_ext_radio_parms(struct wl1271 *wl);
-int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type);
+int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id);
+int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id);
+int wl12xx_cmd_role_start_dev(struct wl1271 *wl);
+int wl12xx_cmd_role_stop_dev(struct wl1271 *wl);
+int wl12xx_cmd_role_start_sta(struct wl1271 *wl);
+int wl12xx_cmd_role_stop_sta(struct wl1271 *wl);
+int wl12xx_cmd_role_start_ap(struct wl1271 *wl);
+int wl12xx_cmd_role_stop_ap(struct wl1271 *wl);
+int wl12xx_cmd_role_start_ibss(struct wl1271 *wl);
int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
@@ -56,20 +64,18 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr);
int wl1271_build_qos_null_data(struct wl1271 *wl);
int wl1271_cmd_build_klv_null_data(struct wl1271 *wl);
-int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id);
-int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id);
+int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid);
int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, const u8 *addr,
u32 tx_seq_32, u16 tx_seq_16);
int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
u16 tx_seq_16);
-int wl1271_cmd_disconnect(struct wl1271 *wl);
-int wl1271_cmd_set_sta_state(struct wl1271 *wl);
-int wl1271_cmd_start_bss(struct wl1271 *wl);
-int wl1271_cmd_stop_bss(struct wl1271 *wl);
-int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid);
-int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid);
+int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid);
+int wl12xx_roc(struct wl1271 *wl, u8 role_id);
+int wl12xx_croc(struct wl1271 *wl, u8 role_id);
+int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid);
+int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid);
int wl12xx_cmd_config_fwlog(struct wl1271 *wl);
int wl12xx_cmd_start_fwlog(struct wl1271 *wl);
int wl12xx_cmd_stop_fwlog(struct wl1271 *wl);
@@ -83,25 +89,21 @@ enum wl1271_commands {
CMD_DISABLE_TX = 6,
CMD_SCAN = 8,
CMD_STOP_SCAN = 9,
- CMD_START_JOIN = 11,
CMD_SET_KEYS = 12,
CMD_READ_MEMORY = 13,
CMD_WRITE_MEMORY = 14,
CMD_SET_TEMPLATE = 19,
CMD_TEST = 23,
CMD_NOISE_HIST = 28,
- CMD_LNA_CONTROL = 32,
+ CMD_QUIET_ELEMENT_SET_STATE = 29,
CMD_SET_BCN_MODE = 33,
CMD_MEASUREMENT = 34,
CMD_STOP_MEASUREMENT = 35,
- CMD_DISCONNECT = 36,
CMD_SET_PS_MODE = 37,
CMD_CHANNEL_SWITCH = 38,
CMD_STOP_CHANNEL_SWICTH = 39,
CMD_AP_DISCOVERY = 40,
CMD_STOP_AP_DISCOVERY = 41,
- CMD_SPS_SCAN = 42,
- CMD_STOP_SPS_SCAN = 43,
CMD_HEALTH_CHECK = 45,
CMD_DEBUG = 46,
CMD_TRIGGER_SCAN_TO = 47,
@@ -109,16 +111,30 @@ enum wl1271_commands {
CMD_CONNECTION_SCAN_SSID_CFG = 49,
CMD_START_PERIODIC_SCAN = 50,
CMD_STOP_PERIODIC_SCAN = 51,
- CMD_SET_STA_STATE = 52,
- CMD_CONFIG_FWLOGGER = 53,
- CMD_START_FWLOGGER = 54,
- CMD_STOP_FWLOGGER = 55,
+ CMD_SET_PEER_STATE = 52,
+ CMD_REMAIN_ON_CHANNEL = 53,
+ CMD_CANCEL_REMAIN_ON_CHANNEL = 54,
- /* AP mode commands */
- CMD_BSS_START = 60,
- CMD_BSS_STOP = 61,
- CMD_ADD_STA = 62,
- CMD_REMOVE_STA = 63,
+ CMD_CONFIG_FWLOGGER = 55,
+ CMD_START_FWLOGGER = 56,
+ CMD_STOP_FWLOGGER = 57,
+
+ /* AP commands */
+ CMD_ADD_PEER = 62,
+ CMD_REMOVE_PEER = 63,
+
+ /* Role API */
+ CMD_ROLE_ENABLE = 70,
+ CMD_ROLE_DISABLE = 71,
+ CMD_ROLE_START = 72,
+ CMD_ROLE_STOP = 73,
+
+ /* WIFI Direct */
+ CMD_WFD_START_DISCOVERY = 80,
+ CMD_WFD_STOP_DISCOVERY = 81,
+ CMD_WFD_ATTRIBUTE_CONFIG = 82,
+
+ CMD_NOP = 100,
NUM_COMMANDS,
MAX_COMMAND_ID = 0xFFFF,
@@ -147,21 +163,20 @@ enum cmd_templ {
CMD_TEMPL_CTS, /*
* For CTS-to-self (FastCTS) mechanism
* for BT/WLAN coexistence (SoftGemini). */
- CMD_TEMPL_ARP_RSP,
- CMD_TEMPL_LINK_MEASUREMENT_REPORT,
-
- /* AP-mode specific */
- CMD_TEMPL_AP_BEACON = 13,
+ CMD_TEMPL_AP_BEACON,
CMD_TEMPL_AP_PROBE_RESPONSE,
- CMD_TEMPL_AP_ARP_RSP,
+ CMD_TEMPL_ARP_RSP,
CMD_TEMPL_DEAUTH_AP,
+ CMD_TEMPL_TEMPORARY,
+ CMD_TEMPL_LINK_MEASUREMENT_REPORT,
CMD_TEMPL_MAX = 0xff
};
/* unit ms */
#define WL1271_COMMAND_TIMEOUT 2000
-#define WL1271_CMD_TEMPL_MAX_SIZE 252
+#define WL1271_CMD_TEMPL_DFLT_SIZE 252
+#define WL1271_CMD_TEMPL_MAX_SIZE 548
#define WL1271_EVENT_TIMEOUT 750
struct wl1271_cmd_header {
@@ -193,6 +208,8 @@ enum {
CMD_STATUS_WRONG_NESTING = 19,
CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/
CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/
+ CMD_STATUS_TEMPLATE_OOM = 23,
+ CMD_STATUS_NO_RX_BA_SESSION = 24,
MAX_COMMAND_STATUS = 0xff
};
@@ -210,38 +227,114 @@ enum {
#define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1
#define WL1271_JOIN_CMD_BSS_TYPE_5GHZ 0x10
-struct wl1271_cmd_join {
+struct wl12xx_cmd_role_enable {
struct wl1271_cmd_header header;
- __le32 bssid_lsb;
- __le16 bssid_msb;
- __le16 beacon_interval; /* in TBTTs */
- __le32 rx_config_options;
- __le32 rx_filter_options;
+ u8 role_id;
+ u8 role_type;
+ u8 mac_address[ETH_ALEN];
+} __packed;
- /*
- * The target uses this field to determine the rate at
- * which to transmit control frame responses (such as
- * ACK or CTS frames).
- */
- __le32 basic_rate_set;
- __le32 supported_rate_set;
- u8 dtim_interval;
- /*
- * bits 0-2: This bitwise field specifies the type
- * of BSS to start or join (BSS_TYPE_*).
- * bit 4: Band - The radio band in which to join
- * or start.
- * 0 - 2.4GHz band
- * 1 - 5GHz band
- * bits 3, 5-7: Reserved
- */
- u8 bss_type;
+struct wl12xx_cmd_role_disable {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 padding[3];
+} __packed;
+
+enum wl12xx_band {
+ WL12XX_BAND_2_4GHZ = 0,
+ WL12XX_BAND_5GHZ = 1,
+ WL12XX_BAND_JAPAN_4_9_GHZ = 2,
+ WL12XX_BAND_DEFAULT = WL12XX_BAND_2_4GHZ,
+ WL12XX_BAND_INVALID = 0x7E,
+ WL12XX_BAND_MAX_RADIO = 0x7F,
+};
+
+struct wl12xx_cmd_role_start {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 band;
u8 channel;
- u8 ssid_len;
- u8 ssid[IEEE80211_MAX_SSID_LEN];
- u8 ctrl; /* JOIN_CMD_CTRL_* */
- u8 reserved[3];
+ u8 padding;
+
+ union {
+ struct {
+ u8 hlid;
+ u8 session;
+ u8 padding_1[54];
+ } __packed device;
+ /* sta & p2p_cli use the same struct */
+ struct {
+ u8 bssid[ETH_ALEN];
+ u8 hlid; /* data hlid */
+ u8 session;
+ __le32 remote_rates; /* remote supported rates */
+
+ /*
+ * The target uses this field to determine the rate at
+ * which to transmit control frame responses (such as
+ * ACK or CTS frames).
+ */
+ __le32 basic_rate_set;
+ __le32 local_rates; /* local supported rates */
+
+ u8 ssid_type;
+ u8 ssid_len;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+
+ __le16 beacon_interval; /* in TBTTs */
+ } __packed sta;
+ struct {
+ u8 bssid[ETH_ALEN];
+ u8 hlid; /* data hlid */
+ u8 dtim_interval;
+ __le32 remote_rates; /* remote supported rates */
+
+ __le32 basic_rate_set;
+ __le32 local_rates; /* local supported rates */
+
+ u8 ssid_type;
+ u8 ssid_len;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+
+ __le16 beacon_interval; /* in TBTTs */
+
+ u8 padding_1[4];
+ } __packed ibss;
+ /* ap & p2p_go use the same struct */
+ struct {
+ __le16 aging_period; /* in secs */
+ u8 beacon_expiry; /* in ms */
+ u8 bss_index;
+ /* The host link id for the AP's global queue */
+ u8 global_hlid;
+ /* The host link id for the AP's broadcast queue */
+ u8 broadcast_hlid;
+
+ __le16 beacon_interval; /* in TBTTs */
+
+ __le32 basic_rate_set;
+ __le32 local_rates; /* local supported rates */
+
+ u8 dtim_interval;
+
+ u8 ssid_type;
+ u8 ssid_len;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+
+ u8 padding_1[5];
+ } __packed ap;
+ };
+} __packed;
+
+struct wl12xx_cmd_role_stop {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 disc_type; /* only STA and P2P_CLI */
+ __le16 reason; /* only STA and P2P_CLI */
} __packed;
struct cmd_enabledisable_path {
@@ -287,8 +380,9 @@ enum wl1271_cmd_ps_mode {
struct wl1271_cmd_ps_params {
struct wl1271_cmd_header header;
+ u8 role_id;
u8 ps_mode; /* STATION_* */
- u8 padding[3];
+ u8 padding[2];
} __packed;
/* HW encryption keys */
@@ -301,6 +395,12 @@ enum wl1271_cmd_key_action {
MAX_KEY_ACTION = 0xffff,
};
+enum wl1271_cmd_lid_key_type {
+ UNICAST_LID_TYPE = 0,
+ BROADCAST_LID_TYPE = 1,
+ WEP_DEFAULT_LID_TYPE = 2
+};
+
enum wl1271_cmd_key_type {
KEY_NONE = 0,
KEY_WEP = 1,
@@ -309,44 +409,7 @@ enum wl1271_cmd_key_type {
KEY_GEM = 4,
};
-/* FIXME: Add description for key-types */
-
-struct wl1271_cmd_set_sta_keys {
- struct wl1271_cmd_header header;
-
- /* Ignored for default WEP key */
- u8 addr[ETH_ALEN];
-
- /* key_action_e */
- __le16 key_action;
-
- __le16 reserved_1;
-
- /* key size in bytes */
- u8 key_size;
-
- /* key_type_e */
- u8 key_type;
- u8 ssid_profile;
-
- /*
- * TKIP, AES: frame's key id field.
- * For WEP default key: key id;
- */
- u8 id;
- u8 reserved_2[6];
- u8 key[MAX_KEY_SIZE];
- __le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
- __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
-} __packed;
-
-enum wl1271_cmd_lid_key_type {
- UNICAST_LID_TYPE = 0,
- BROADCAST_LID_TYPE = 1,
- WEP_DEFAULT_LID_TYPE = 2
-};
-
-struct wl1271_cmd_set_ap_keys {
+struct wl1271_cmd_set_keys {
struct wl1271_cmd_header header;
/*
@@ -496,69 +559,39 @@ enum wl1271_disconnect_type {
DISCONNECT_DISASSOC
};
-struct wl1271_cmd_disconnect {
- struct wl1271_cmd_header header;
-
- __le32 rx_config_options;
- __le32 rx_filter_options;
-
- __le16 reason;
- u8 type;
-
- u8 padding;
-} __packed;
-
#define WL1271_CMD_STA_STATE_CONNECTED 1
-struct wl1271_cmd_set_sta_state {
+struct wl12xx_cmd_set_peer_state {
struct wl1271_cmd_header header;
+ u8 hlid;
u8 state;
- u8 padding[3];
+ u8 padding[2];
} __packed;
-enum wl1271_ssid_type {
- SSID_TYPE_PUBLIC = 0,
- SSID_TYPE_HIDDEN = 1
+struct wl12xx_cmd_roc {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 channel;
+ u8 band;
+ u8 padding;
};
-struct wl1271_cmd_bss_start {
+struct wl12xx_cmd_croc {
struct wl1271_cmd_header header;
- /* wl1271_ssid_type */
- u8 ssid_type;
- u8 ssid_len;
- u8 ssid[IEEE80211_MAX_SSID_LEN];
- u8 padding_1[2];
-
- /* Basic rate set */
- __le32 basic_rate_set;
- /* Aging period in seconds*/
- __le16 aging_period;
+ u8 role_id;
+ u8 padding[3];
+};
- /*
- * This field specifies the time between target beacon
- * transmission times (TBTTs), in time units (TUs).
- * Valid values are 1 to 1024.
- */
- __le16 beacon_interval;
- u8 bssid[ETH_ALEN];
- u8 bss_index;
- /* Radio band */
- u8 band;
- u8 channel;
- /* The host link id for the AP's global queue */
- u8 global_hlid;
- /* The host link id for the AP's broadcast queue */
- u8 broadcast_hlid;
- /* DTIM count */
- u8 dtim_interval;
- /* Beacon expiry time in ms */
- u8 beacon_expiry;
- u8 padding_2[3];
-} __packed;
+enum wl12xx_ssid_type {
+ WL12XX_SSID_TYPE_PUBLIC = 0,
+ WL12XX_SSID_TYPE_HIDDEN = 1,
+ WL12XX_SSID_TYPE_ANY = 2,
+};
-struct wl1271_cmd_add_sta {
+struct wl12xx_cmd_add_peer {
struct wl1271_cmd_header header;
u8 addr[ETH_ALEN];
@@ -572,7 +605,7 @@ struct wl1271_cmd_add_sta {
u8 padding1;
} __packed;
-struct wl1271_cmd_remove_sta {
+struct wl12xx_cmd_remove_peer {
struct wl1271_cmd_header header;
u8 hlid;
diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index 6080e01d92c..82f205c4334 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -99,40 +99,75 @@ enum {
enum {
/*
- * PER threshold in PPM of the BT voice
+ * Configure the min and max time BT gains the antenna
+ * in WLAN / BT master basic rate
*
- * Range: 0 - 10000000
+ * Range: 0 - 255 (ms)
*/
- CONF_SG_BT_PER_THRESHOLD = 0,
+ CONF_SG_ACL_BT_MASTER_MIN_BR = 0,
+ CONF_SG_ACL_BT_MASTER_MAX_BR,
/*
- * Number of consequent RX_ACTIVE activities to override BT voice
- * frames to ensure WLAN connection
+ * Configure the min and max time BT gains the antenna
+ * in WLAN / BT slave basic rate
*
- * Range: 0 - 100
+ * Range: 0 - 255 (ms)
*/
- CONF_SG_HV3_MAX_OVERRIDE,
+ CONF_SG_ACL_BT_SLAVE_MIN_BR,
+ CONF_SG_ACL_BT_SLAVE_MAX_BR,
/*
- * Defines the PER threshold of the BT voice
+ * Configure the min and max time BT gains the antenna
+ * in WLAN / BT master EDR
*
- * Range: 0 - 65000
+ * Range: 0 - 255 (ms)
*/
- CONF_SG_BT_NFS_SAMPLE_INTERVAL,
+ CONF_SG_ACL_BT_MASTER_MIN_EDR,
+ CONF_SG_ACL_BT_MASTER_MAX_EDR,
/*
- * Defines the load ratio of BT
+ * Configure the min and max time BT gains the antenna
+ * in WLAN / BT slave EDR
*
- * Range: 0 - 100 (%)
+ * Range: 0 - 255 (ms)
*/
- CONF_SG_BT_LOAD_RATIO,
+ CONF_SG_ACL_BT_SLAVE_MIN_EDR,
+ CONF_SG_ACL_BT_SLAVE_MAX_EDR,
/*
- * Defines whether the SG will force WLAN host to enter/exit PSM
+ * The maximum time WLAN can gain the antenna
+ * in WLAN PSM / BT master/slave BR
*
- * Range: 1 - SG can force, 0 - host handles PSM
+ * Range: 0 - 255 (ms)
*/
- CONF_SG_AUTO_PS_MODE,
+ CONF_SG_ACL_WLAN_PS_MASTER_BR,
+ CONF_SG_ACL_WLAN_PS_SLAVE_BR,
+
+ /*
+ * The maximum time WLAN can gain the antenna
+ * in WLAN PSM / BT master/slave EDR
+ *
+ * Range: 0 - 255 (ms)
+ */
+ CONF_SG_ACL_WLAN_PS_MASTER_EDR,
+ CONF_SG_ACL_WLAN_PS_SLAVE_EDR,
+
+ /* TODO: explain these values */
+ CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR,
+ CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR,
+ CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR,
+ CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR,
+ CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR,
+ CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR,
+ CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR,
+ CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR,
+
+ CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR,
+ CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR,
+ CONF_SG_ACL_PASSIVE_SCAN_BT_BR,
+ CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR,
+ CONF_SG_ACL_PASSIVE_SCAN_BT_EDR,
+ CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR,
/*
* Compensation percentage of probe requests when scan initiated
@@ -151,102 +186,70 @@ enum {
CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3,
/*
- * Defines antenna configuration (single/dual antenna)
- *
- * Range: 0 - single antenna, 1 - dual antenna
- */
- CONF_SG_ANTENNA_CONFIGURATION,
-
- /*
- * The threshold (percent) of max consequtive beacon misses before
- * increasing priority of beacon reception.
- *
- * Range: 0 - 100 (%)
- */
- CONF_SG_BEACON_MISS_PERCENT,
-
- /*
- * The rate threshold below which receiving a data frame from the AP
- * will increase the priority of the data frame above BT traffic.
- *
- * Range: 0,2, 5(=5.5), 6, 9, 11, 12, 18, 24, 36, 48, 54
- */
- CONF_SG_RATE_ADAPT_THRESH,
-
- /*
- * Not used currently.
+ * Compensation percentage of WLAN active scan window if initiated
+ * during BT A2DP
*
- * Range: 0
+ * Range: 0 - 1000 (%)
*/
- CONF_SG_RATE_ADAPT_SNR,
+ CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP,
/*
- * Configure the min and max time BT gains the antenna
- * in WLAN PSM / BT master basic rate
+ * Compensation percentage of WLAN passive scan window if initiated
+ * during BT A2DP BR
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 1000 (%)
*/
- CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR,
- CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR,
+ CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR,
/*
- * The time after it expires no new WLAN trigger frame is trasmitted
- * in WLAN PSM / BT master basic rate
+ * Compensation percentage of WLAN passive scan window if initiated
+ * during BT A2DP EDR
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 1000 (%)
*/
- CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR,
+ CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR,
/*
- * Configure the min and max time BT gains the antenna
- * in WLAN PSM / BT slave basic rate
+ * Compensation percentage of WLAN passive scan window if initiated
+ * during BT voice
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 1000 (%)
*/
- CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR,
- CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR,
+ CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3,
- /*
- * The time after it expires no new WLAN trigger frame is trasmitted
- * in WLAN PSM / BT slave basic rate
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR,
+ /* TODO: explain these values */
+ CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN,
+ CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN,
+ CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN,
/*
- * Configure the min and max time BT gains the antenna
- * in WLAN PSM / BT master EDR
+ * Defines whether the SG will force WLAN host to enter/exit PSM
*
- * Range: 0 - 255 (ms)
+ * Range: 1 - SG can force, 0 - host handles PSM
*/
- CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR,
- CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR,
+ CONF_SG_STA_FORCE_PS_IN_BT_SCO,
/*
- * The time after it expires no new WLAN trigger frame is trasmitted
- * in WLAN PSM / BT master EDR
+ * Defines antenna configuration (single/dual antenna)
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - single antenna, 1 - dual antenna
*/
- CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR,
+ CONF_SG_ANTENNA_CONFIGURATION,
/*
- * Configure the min and max time BT gains the antenna
- * in WLAN PSM / BT slave EDR
+ * The threshold (percent) of max consecutive beacon misses before
+ * increasing priority of beacon reception.
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 100 (%)
*/
- CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR,
- CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR,
+ CONF_SG_BEACON_MISS_PERCENT,
/*
- * The time after it expires no new WLAN trigger frame is trasmitted
- * in WLAN PSM / BT slave EDR
+ * Protection time of the DHCP procedure.
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 100000 (ms)
*/
- CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR,
+ CONF_SG_DHCP_TIME,
/*
* RX guard time before the beginning of a new BT voice frame during
@@ -273,166 +276,59 @@ enum {
*/
CONF_SG_ADAPTIVE_RXT_TXT,
- /*
- * The used WLAN legacy service period during active BT ACL link
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_PS_POLL_TIMEOUT,
-
- /*
- * The used WLAN UPSD service period during active BT ACL link
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_UPSD_TIMEOUT,
-
- /*
- * Configure the min and max time BT gains the antenna
- * in WLAN Active / BT master EDR
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR,
- CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR,
-
- /*
- * The maximum time WLAN can gain the antenna for
- * in WLAN Active / BT master EDR
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR,
-
- /*
- * Configure the min and max time BT gains the antenna
- * in WLAN Active / BT slave EDR
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR,
- CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR,
+ /* TODO: explain this value */
+ CONF_SG_GENERAL_USAGE_BIT_MAP,
/*
- * The maximum time WLAN can gain the antenna for
- * in WLAN Active / BT slave EDR
+ * Number of consecutive BT voice frames not interrupted by WLAN
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 100
*/
- CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR,
+ CONF_SG_HV3_MAX_SERVED,
/*
- * Configure the min and max time BT gains the antenna
- * in WLAN Active / BT basic rate
+ * The used WLAN legacy service period during active BT ACL link
*
* Range: 0 - 255 (ms)
*/
- CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR,
- CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR,
+ CONF_SG_PS_POLL_TIMEOUT,
/*
- * The maximum time WLAN can gain the antenna for
- * in WLAN Active / BT basic rate
+ * The used WLAN UPSD service period during active BT ACL link
*
* Range: 0 - 255 (ms)
*/
- CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR,
-
- /*
- * Compensation percentage of WLAN passive scan window if initiated
- * during BT voice
- *
- * Range: 0 - 1000 (%)
- */
- CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3,
-
- /*
- * Compensation percentage of WLAN passive scan window if initiated
- * during BT A2DP
- *
- * Range: 0 - 1000 (%)
- */
- CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP,
-
- /*
- * Fixed time ensured for BT traffic to gain the antenna during WLAN
- * passive scan.
- *
- * Range: 0 - 1000 ms
- */
- CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME,
-
- /*
- * Fixed time ensured for WLAN traffic to gain the antenna during WLAN
- * passive scan.
- *
- * Range: 0 - 1000 ms
- */
- CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME,
+ CONF_SG_UPSD_TIMEOUT,
- /*
- * Number of consequent BT voice frames not interrupted by WLAN
- *
- * Range: 0 - 100
- */
- CONF_SG_HV3_MAX_SERVED,
+ CONF_SG_CONSECUTIVE_CTS_THRESHOLD,
+ CONF_SG_STA_RX_WINDOW_AFTER_DTIM,
+ CONF_SG_STA_CONNECTION_PROTECTION_TIME,
- /*
- * Protection time of the DHCP procedure.
- *
- * Range: 0 - 100000 (ms)
- */
- CONF_SG_DHCP_TIME,
+ /* AP params */
+ CONF_AP_BEACON_MISS_TX,
+ CONF_AP_RX_WINDOW_AFTER_BEACON,
+ CONF_AP_BEACON_WINDOW_INTERVAL,
+ CONF_AP_CONNECTION_PROTECTION_TIME,
+ CONF_AP_BT_ACL_VAL_BT_SERVE_TIME,
+ CONF_AP_BT_ACL_VAL_WL_SERVE_TIME,
- /*
- * Compensation percentage of WLAN active scan window if initiated
- * during BT A2DP
- *
- * Range: 0 - 1000 (%)
- */
- CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP,
CONF_SG_TEMP_PARAM_1,
CONF_SG_TEMP_PARAM_2,
CONF_SG_TEMP_PARAM_3,
CONF_SG_TEMP_PARAM_4,
CONF_SG_TEMP_PARAM_5,
-
- /*
- * AP beacon miss
- *
- * Range: 0 - 255
- */
- CONF_SG_AP_BEACON_MISS_TX,
-
- /*
- * AP RX window length
- *
- * Range: 0 - 50
- */
- CONF_SG_RX_WINDOW_LENGTH,
-
- /*
- * AP connection protection time
- *
- * Range: 0 - 5000
- */
- CONF_SG_AP_CONNECTION_PROTECTION_TIME,
-
CONF_SG_TEMP_PARAM_6,
CONF_SG_TEMP_PARAM_7,
CONF_SG_TEMP_PARAM_8,
CONF_SG_TEMP_PARAM_9,
CONF_SG_TEMP_PARAM_10,
- CONF_SG_STA_PARAMS_MAX = CONF_SG_TEMP_PARAM_5 + 1,
- CONF_SG_AP_PARAMS_MAX = CONF_SG_TEMP_PARAM_10 + 1,
-
+ CONF_SG_PARAMS_MAX,
CONF_SG_PARAMS_ALL = 0xff
};
struct conf_sg_settings {
- u32 sta_params[CONF_SG_STA_PARAMS_MAX];
- u32 ap_params[CONF_SG_AP_PARAMS_MAX];
+ u32 params[CONF_SG_PARAMS_MAX];
u8 state;
};
@@ -545,6 +441,11 @@ struct conf_rx_settings {
CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \
CONF_HW_BIT_RATE_54MBPS)
+#define CONF_TX_MCS_RATES (CONF_HW_BIT_RATE_MCS_0 | \
+ CONF_HW_BIT_RATE_MCS_1 | CONF_HW_BIT_RATE_MCS_2 | \
+ CONF_HW_BIT_RATE_MCS_3 | CONF_HW_BIT_RATE_MCS_4 | \
+ CONF_HW_BIT_RATE_MCS_5 | CONF_HW_BIT_RATE_MCS_6 | \
+ CONF_HW_BIT_RATE_MCS_7)
/*
* Default rates for management traffic when operating in AP mode. This
@@ -661,6 +562,9 @@ struct conf_tx_ac_category {
#define CONF_TX_MAX_TID_COUNT 8
+/* Allow TX BA on all TIDs but 6,7. These are currently reserved in the FW */
+#define CONF_TX_BA_ENABLED_TID_BITMAP 0x3F
+
enum {
CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/
CONF_CHANNEL_TYPE_EDCF = 1, /* EDCA*/
@@ -913,7 +817,7 @@ struct conf_conn_settings {
struct conf_bcn_filt_rule bcn_filt_ie[CONF_MAX_BCN_FILT_IE_COUNT];
/*
- * The number of consequtive beacons to lose, before the firmware
+ * The number of consecutive beacons to lose, before the firmware
* becomes out of synch.
*
* Range: u32
@@ -951,7 +855,7 @@ struct conf_conn_settings {
u8 rx_broadcast_in_ps;
/*
- * Consequtive PS Poll failures before sending event to driver
+ * Consecutive PS Poll failures before sending event to driver
*
* Range: u8
*/
@@ -1199,8 +1103,12 @@ struct conf_rf_settings {
};
struct conf_ht_setting {
- u16 tx_ba_win_size;
+ u8 rx_ba_win_size;
+ u8 tx_ba_win_size;
u16 inactivity_timeout;
+
+ /* bitmap of enabled TIDs for TX BA sessions */
+ u8 tx_ba_tid_bitmap;
};
struct conf_memory_settings {
@@ -1309,6 +1217,25 @@ struct conf_fwlog {
u8 threshold;
};
+#define ACX_RATE_MGMT_NUM_OF_RATES 13
+struct conf_rate_policy_settings {
+ u16 rate_retry_score;
+ u16 per_add;
+ u16 per_th1;
+ u16 per_th2;
+ u16 max_per;
+ u8 inverse_curiosity_factor;
+ u8 tx_fail_low_th;
+ u8 tx_fail_high_th;
+ u8 per_alpha_shift;
+ u8 per_add_shift;
+ u8 per_beta1_shift;
+ u8 per_beta2_shift;
+ u8 rate_check_up;
+ u8 rate_check_down;
+ u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES];
+};
+
struct conf_drv_settings {
struct conf_sg_settings sg;
struct conf_rx_settings rx;
@@ -1326,6 +1253,7 @@ struct conf_drv_settings {
struct conf_fm_coex fm_coex;
struct conf_rx_streaming_settings rx_streaming;
struct conf_fwlog fwlog;
+ struct conf_rate_policy_settings rate;
u8 hci_io_ds;
};
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 37934b5601c..d59354f5370 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -339,10 +339,11 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
#define DRIVER_STATE_PRINT_HEX(x) DRIVER_STATE_PRINT(x, "0x%x")
DRIVER_STATE_PRINT_INT(tx_blocks_available);
- DRIVER_STATE_PRINT_INT(tx_allocated_blocks[0]);
- DRIVER_STATE_PRINT_INT(tx_allocated_blocks[1]);
- DRIVER_STATE_PRINT_INT(tx_allocated_blocks[2]);
- DRIVER_STATE_PRINT_INT(tx_allocated_blocks[3]);
+ DRIVER_STATE_PRINT_INT(tx_allocated_blocks);
+ DRIVER_STATE_PRINT_INT(tx_allocated_pkts[0]);
+ DRIVER_STATE_PRINT_INT(tx_allocated_pkts[1]);
+ DRIVER_STATE_PRINT_INT(tx_allocated_pkts[2]);
+ DRIVER_STATE_PRINT_INT(tx_allocated_pkts[3]);
DRIVER_STATE_PRINT_INT(tx_frames_cnt);
DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
DRIVER_STATE_PRINT_INT(tx_queue_count[0]);
@@ -352,10 +353,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
DRIVER_STATE_PRINT_INT(tx_packets_count);
DRIVER_STATE_PRINT_INT(tx_results_count);
DRIVER_STATE_PRINT_LHEX(flags);
- DRIVER_STATE_PRINT_INT(tx_blocks_freed[0]);
- DRIVER_STATE_PRINT_INT(tx_blocks_freed[1]);
- DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]);
- DRIVER_STATE_PRINT_INT(tx_blocks_freed[3]);
+ DRIVER_STATE_PRINT_INT(tx_blocks_freed);
DRIVER_STATE_PRINT_INT(tx_security_last_seq_lsb);
DRIVER_STATE_PRINT_INT(rx_counter);
DRIVER_STATE_PRINT_INT(session_counter);
@@ -369,9 +367,6 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
DRIVER_STATE_PRINT_INT(beacon_int);
DRIVER_STATE_PRINT_INT(psm_entry_retry);
DRIVER_STATE_PRINT_INT(ps_poll_failures);
- DRIVER_STATE_PRINT_HEX(filters);
- DRIVER_STATE_PRINT_HEX(rx_config);
- DRIVER_STATE_PRINT_HEX(rx_filter);
DRIVER_STATE_PRINT_INT(power_level);
DRIVER_STATE_PRINT_INT(rssi_thold);
DRIVER_STATE_PRINT_INT(last_rssi_event);
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c
index 304aaa2ee01..0bd7b020a42 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/event.c
@@ -285,13 +285,13 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) && !is_ap) {
wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
- "ba_allowed = 0x%x", mbox->ba_allowed);
+ "ba_allowed = 0x%x", mbox->rx_ba_allowed);
if (wl->vif)
- wl1271_stop_ba_event(wl, mbox->ba_allowed);
+ wl1271_stop_ba_event(wl, mbox->rx_ba_allowed);
}
- if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) {
+ if ((vector & DUMMY_PACKET_EVENT_ID)) {
wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
if (wl->vif)
wl1271_tx_dummy_packet(wl);
diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h
index e524ad6fe4e..49c1a0ede5b 100644
--- a/drivers/net/wireless/wl12xx/event.h
+++ b/drivers/net/wireless/wl12xx/event.h
@@ -49,32 +49,27 @@ enum {
MEASUREMENT_START_EVENT_ID = BIT(8),
MEASUREMENT_COMPLETE_EVENT_ID = BIT(9),
SCAN_COMPLETE_EVENT_ID = BIT(10),
- SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(11),
+ WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11),
AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12),
PS_REPORT_EVENT_ID = BIT(13),
PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14),
DISCONNECT_EVENT_COMPLETE_ID = BIT(15),
- JOIN_EVENT_COMPLETE_ID = BIT(16),
+ /* BIT(16) is reserved */
CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17),
BSS_LOSE_EVENT_ID = BIT(18),
REGAINED_BSS_EVENT_ID = BIT(19),
MAX_TX_RETRY_EVENT_ID = BIT(20),
- /* STA: dummy paket for dynamic mem blocks */
- DUMMY_PACKET_EVENT_ID = BIT(21),
- /* AP: STA remove complete */
- STA_REMOVE_COMPLETE_EVENT_ID = BIT(21),
+ DUMMY_PACKET_EVENT_ID = BIT(21),
SOFT_GEMINI_SENSE_EVENT_ID = BIT(22),
- /* STA: SG prediction */
- SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23),
- /* AP: Inactive STA */
- INACTIVE_STA_EVENT_ID = BIT(23),
+ CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID = BIT(23),
SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24),
PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25),
- DBG_EVENT_ID = BIT(26),
- HEALTH_CHECK_REPLY_EVENT_ID = BIT(27),
+ INACTIVE_STA_EVENT_ID = BIT(26),
+ PEER_REMOVE_COMPLETE_EVENT_ID = BIT(27),
PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28),
PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29),
BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(30),
+ REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(31),
EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff,
};
@@ -83,15 +78,6 @@ enum {
EVENT_ENTER_POWER_SAVE_SUCCESS,
};
-struct event_debug_report {
- u8 debug_event_id;
- u8 num_params;
- __le16 pad;
- __le32 report_1;
- __le32 report_2;
- __le32 report_3;
-} __packed;
-
#define NUM_OF_RSSI_SNR_TRIGGERS 8
struct event_mailbox {
@@ -100,49 +86,45 @@ struct event_mailbox {
__le32 reserved_1;
__le32 reserved_2;
- u8 dbg_event_id;
- u8 num_relevant_params;
- __le16 reserved_3;
- __le32 event_report_p1;
- __le32 event_report_p2;
- __le32 event_report_p3;
-
u8 number_of_scan_results;
u8 scan_tag;
- u8 reserved_4[2];
- __le32 compl_scheduled_scan_status;
+ u8 completed_scan_status;
+ u8 reserved_3;
- __le16 scheduled_scan_attended_channels;
u8 soft_gemini_sense_info;
u8 soft_gemini_protective_info;
s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
u8 channel_switch_status;
u8 scheduled_scan_status;
u8 ps_status;
+ /* tuned channel (roc) */
+ u8 roc_channel;
- /* AP FW only */
- u8 hlid_removed;
+ __le16 hlid_removed_bitmap;
- /* a bitmap of hlids for stations that have been inactive too long */
+ /* bitmap of aged stations (by HLID) */
__le16 sta_aging_status;
- /* a bitmap of hlids for stations which didn't respond to TX */
+ /* bitmap of stations (by HLID) which exceeded max tx retries */
__le16 sta_tx_retry_exceeded;
- /*
- * Bitmap, Each bit set represents the Role ID for which this constraint
- * is set. Range: 0 - FF, FF means ANY role
- */
- u8 ba_role_id;
- /*
- * Bitmap, Each bit set represents the Link ID for which this constraint
- * is set. Not applicable if ba_role_id is set to ANY role (FF).
- * Range: 0 - FFFF, FFFF means ANY link in that role
- */
- u8 ba_link_id;
- u8 ba_allowed;
-
- u8 reserved_5[21];
+ /* discovery completed results */
+ u8 discovery_tag;
+ u8 number_of_preq_results;
+ u8 number_of_prsp_results;
+ u8 reserved_5;
+
+ /* rx ba constraint */
+ u8 role_id; /* 0xFF means any role. */
+ u8 rx_ba_allowed;
+ u8 reserved_6[2];
+
+ u8 ps_poll_delivery_failure_role_ids;
+ u8 stopped_role_ids;
+ u8 started_role_ids;
+ u8 change_auto_mode_timeout;
+
+ u8 reserved_7[12];
} __packed;
int wl1271_event_unmask(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index c3e9a2e4410..b13bebea95e 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -39,13 +39,13 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl)
/* send empty templates for fw memory reservation */
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
- WL1271_CMD_TEMPL_MAX_SIZE,
+ WL1271_CMD_TEMPL_DFLT_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
- NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0,
+ NULL, WL1271_CMD_TEMPL_DFLT_SIZE, 0,
WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
@@ -70,15 +70,13 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl)
return ret;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL,
- sizeof
- (struct wl12xx_probe_resp_template),
+ WL1271_CMD_TEMPL_DFLT_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL,
- sizeof
- (struct wl12xx_beacon_template),
+ WL1271_CMD_TEMPL_DFLT_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
@@ -92,7 +90,7 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl)
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
- WL1271_CMD_TEMPL_MAX_SIZE, i,
+ WL1271_CMD_TEMPL_DFLT_SIZE, i,
WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
@@ -191,15 +189,13 @@ static int wl1271_ap_init_templates_config(struct wl1271 *wl)
* reserve memory for later.
*/
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
- sizeof
- (struct wl12xx_probe_resp_template),
+ WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL,
- sizeof
- (struct wl12xx_beacon_template),
+ WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
@@ -227,7 +223,7 @@ static int wl1271_ap_init_templates_config(struct wl1271 *wl)
return 0;
}
-static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter)
+static int wl12xx_init_rx_config(struct wl1271 *wl)
{
int ret;
@@ -235,10 +231,6 @@ static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter)
if (ret < 0)
return ret;
- ret = wl1271_acx_rx_config(wl, config, filter);
- if (ret < 0)
- return ret;
-
return 0;
}
@@ -285,10 +277,7 @@ int wl1271_init_pta(struct wl1271 *wl)
{
int ret;
- if (wl->bss_type == BSS_TYPE_AP_BSS)
- ret = wl1271_acx_ap_sg_cfg(wl);
- else
- ret = wl1271_acx_sta_sg_cfg(wl);
+ ret = wl12xx_acx_sg_cfg(wl);
if (ret < 0)
return ret;
@@ -392,7 +381,7 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;
- ret = wl1271_acx_sta_mem_cfg(wl);
+ ret = wl12xx_acx_mem_cfg(wl);
if (ret < 0)
return ret;
@@ -408,12 +397,6 @@ static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl)
{
int ret, i;
- ret = wl1271_cmd_set_sta_default_wep_key(wl, wl->default_key);
- if (ret < 0) {
- wl1271_warning("couldn't set default key");
- return ret;
- }
-
/* disable all keep-alive templates */
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
ret = wl1271_acx_keep_alive_config(wl, i,
@@ -451,7 +434,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;
- ret = wl1271_acx_ap_mem_cfg(wl);
+ ret = wl12xx_acx_mem_cfg(wl);
if (ret < 0)
return ret;
@@ -483,7 +466,7 @@ int wl1271_ap_init_templates(struct wl1271 *wl)
* when operating as AP we want to receive external beacons for
* configuring ERP protection.
*/
- ret = wl1271_acx_set_ap_beacon_filter(wl, false);
+ ret = wl1271_acx_beacon_filter_opt(wl, false);
if (ret < 0)
return ret;
@@ -532,6 +515,9 @@ int wl1271_init_ap_rates(struct wl1271 *wl)
else
supported_rates = CONF_TX_AP_ENABLED_RATES;
+ /* unconditionally enable HT rates */
+ supported_rates |= CONF_TX_MCS_RATES;
+
/* configure unicast TX rate classes */
for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
rc.enabled_rates = supported_rates;
@@ -546,41 +532,24 @@ int wl1271_init_ap_rates(struct wl1271 *wl)
return 0;
}
-static void wl1271_check_ba_support(struct wl1271 *wl)
-{
- /* validate FW cose ver x.x.x.50-60.x */
- if ((wl->chip.fw_ver[3] >= WL12XX_BA_SUPPORT_FW_COST_VER2_START) &&
- (wl->chip.fw_ver[3] < WL12XX_BA_SUPPORT_FW_COST_VER2_END)) {
- wl->ba_support = true;
- return;
- }
-
- wl->ba_support = false;
-}
-
static int wl1271_set_ba_policies(struct wl1271 *wl)
{
- u8 tid_index;
- int ret = 0;
-
/* Reset the BA RX indicators */
wl->ba_rx_bitmap = 0;
wl->ba_allowed = true;
+ wl->ba_rx_session_count = 0;
- /* validate that FW support BA */
- wl1271_check_ba_support(wl);
+ /* BA is supported in STA/AP modes */
+ if (wl->bss_type != BSS_TYPE_AP_BSS &&
+ wl->bss_type != BSS_TYPE_STA_BSS) {
+ wl->ba_support = false;
+ return 0;
+ }
- if (wl->ba_support)
- /* 802.11n initiator BA session setting */
- for (tid_index = 0; tid_index < CONF_TX_MAX_TID_COUNT;
- ++tid_index) {
- ret = wl1271_acx_set_ba_session(wl, WLAN_BACK_INITIATOR,
- tid_index, true);
- if (ret < 0)
- break;
- }
+ wl->ba_support = true;
- return ret;
+ /* 802.11n initiator BA session setting */
+ return wl12xx_acx_set_ba_initiator_policy(wl);
}
int wl1271_chip_specific_init(struct wl1271 *wl)
@@ -650,11 +619,7 @@ int wl1271_hw_init(struct wl1271 *wl)
return ret;
/* RX config */
- ret = wl1271_init_rx_config(wl,
- RX_CFG_PROMISCUOUS | RX_CFG_TSF,
- RX_FILTER_OPTION_DEF);
- /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
- RX_FILTER_OPTION_FILTER_ALL); */
+ ret = wl12xx_init_rx_config(wl);
if (ret < 0)
goto out_free_memmap;
@@ -733,6 +698,10 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
goto out_free_memmap;
+ ret = wl12xx_acx_set_rate_mgmt_params(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
/* Configure initiator BA sessions policies */
ret = wl1271_set_ba_policies(wl);
if (ret < 0)
diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h
index a2fe4f506ad..e839341dfaf 100644
--- a/drivers/net/wireless/wl12xx/io.h
+++ b/drivers/net/wireless/wl12xx/io.h
@@ -186,6 +186,5 @@ int wl1271_free_hw(struct wl1271 *wl);
irqreturn_t wl1271_irq(int irq, void *data);
bool wl1271_set_block_size(struct wl1271 *wl);
int wl1271_tx_dummy_packet(struct wl1271 *wl);
-void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters);
#endif
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 98258fe0e29..82f4408e89a 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -52,110 +52,67 @@
static struct conf_drv_settings default_conf = {
.sg = {
- .sta_params = {
- [CONF_SG_BT_PER_THRESHOLD] = 7500,
- [CONF_SG_HV3_MAX_OVERRIDE] = 0,
- [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
- [CONF_SG_BT_LOAD_RATIO] = 200,
- [CONF_SG_AUTO_PS_MODE] = 1,
- [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
- [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
- [CONF_SG_ANTENNA_CONFIGURATION] = 0,
- [CONF_SG_BEACON_MISS_PERCENT] = 60,
- [CONF_SG_RATE_ADAPT_THRESH] = 12,
- [CONF_SG_RATE_ADAPT_SNR] = 0,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
- /* Note: with UPSD, this should be 4 */
- [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
- /* Note: with UPDS, this should be 15 */
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
- /* Note: with UPDS, this should be 50 */
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
- /* Note: with UPDS, this should be 10 */
- [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
- [CONF_SG_RXT] = 1200,
- [CONF_SG_TXT] = 1000,
- [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
- [CONF_SG_PS_POLL_TIMEOUT] = 10,
- [CONF_SG_UPSD_TIMEOUT] = 10,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
- [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
- [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
- [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
- [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
- [CONF_SG_HV3_MAX_SERVED] = 6,
- [CONF_SG_DHCP_TIME] = 5000,
- [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
- },
- .ap_params = {
- [CONF_SG_BT_PER_THRESHOLD] = 7500,
- [CONF_SG_HV3_MAX_OVERRIDE] = 0,
- [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
- [CONF_SG_BT_LOAD_RATIO] = 50,
- [CONF_SG_AUTO_PS_MODE] = 1,
- [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
- [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
- [CONF_SG_ANTENNA_CONFIGURATION] = 0,
- [CONF_SG_BEACON_MISS_PERCENT] = 60,
- [CONF_SG_RATE_ADAPT_THRESH] = 64,
- [CONF_SG_RATE_ADAPT_SNR] = 1,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25,
- [CONF_SG_RXT] = 1200,
- [CONF_SG_TXT] = 1000,
- [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
- [CONF_SG_PS_POLL_TIMEOUT] = 10,
- [CONF_SG_UPSD_TIMEOUT] = 10,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
- [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
- [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
- [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
- [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
- [CONF_SG_HV3_MAX_SERVED] = 6,
- [CONF_SG_DHCP_TIME] = 5000,
- [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
- [CONF_SG_TEMP_PARAM_1] = 0,
- [CONF_SG_TEMP_PARAM_2] = 0,
- [CONF_SG_TEMP_PARAM_3] = 0,
- [CONF_SG_TEMP_PARAM_4] = 0,
- [CONF_SG_TEMP_PARAM_5] = 0,
- [CONF_SG_AP_BEACON_MISS_TX] = 3,
- [CONF_SG_RX_WINDOW_LENGTH] = 6,
- [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50,
- [CONF_SG_TEMP_PARAM_6] = 1,
+ .params = {
+ [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
+ [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
+ [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
+ [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
+ [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
+ [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
+ [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
+ [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
+ [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
+ [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
+ [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
+ [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
+ [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
+ [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
+ [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
+ [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
+ [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
+ [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
+ [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
+ [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
+ [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
+ [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
+ [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
+ [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
+ [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
+ [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
+ /* active scan params */
+ [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
+ [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
+ [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
+ /* passive scan params */
+ [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
+ [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
+ [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
+ /* passive scan in dual antenna params */
+ [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
+ [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
+ [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
+ /* general params */
+ [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
+ [CONF_SG_ANTENNA_CONFIGURATION] = 0,
+ [CONF_SG_BEACON_MISS_PERCENT] = 60,
+ [CONF_SG_DHCP_TIME] = 5000,
+ [CONF_SG_RXT] = 1200,
+ [CONF_SG_TXT] = 1000,
+ [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
+ [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
+ [CONF_SG_HV3_MAX_SERVED] = 6,
+ [CONF_SG_PS_POLL_TIMEOUT] = 10,
+ [CONF_SG_UPSD_TIMEOUT] = 10,
+ [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
+ [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
+ [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
+ /* AP params */
+ [CONF_AP_BEACON_MISS_TX] = 3,
+ [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
+ [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
+ [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
+ [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
+ [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
},
.state = CONF_SG_PROTECTIVE,
},
@@ -329,8 +286,10 @@ static struct conf_drv_settings default_conf = {
},
},
.ht = {
+ .rx_ba_win_size = 8,
.tx_ba_win_size = 64,
.inactivity_timeout = 10000,
+ .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
},
.mem_wl127x = {
.num_stations = 1,
@@ -379,6 +338,27 @@ static struct conf_drv_settings default_conf = {
.threshold = 0,
},
.hci_io_ds = HCI_IO_DS_6MA,
+ .rate = {
+ .rate_retry_score = 32000,
+ .per_add = 8192,
+ .per_th1 = 2048,
+ .per_th2 = 4096,
+ .max_per = 8100,
+ .inverse_curiosity_factor = 5,
+ .tx_fail_low_th = 4,
+ .tx_fail_high_th = 10,
+ .per_alpha_shift = 4,
+ .per_add_shift = 13,
+ .per_beta1_shift = 10,
+ .per_beta2_shift = 8,
+ .rate_check_up = 2,
+ .rate_check_down = 12,
+ .rate_retry_policy = {
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00,
+ },
+ },
};
static char *fwlog_param;
@@ -415,10 +395,12 @@ static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
return 0;
- ret = wl1271_cmd_set_sta_state(wl);
+ ret = wl12xx_cmd_set_peer_state(wl, wl->sta_hlid);
if (ret < 0)
return ret;
+ wl12xx_croc(wl, wl->role_id);
+
wl1271_info("Association completed.");
return 0;
}
@@ -718,7 +700,7 @@ static int wl1271_plt_init(struct wl1271 *wl)
if (ret < 0)
goto out_free_memmap;
- ret = wl1271_acx_sta_mem_cfg(wl);
+ ret = wl12xx_acx_mem_cfg(wl);
if (ret < 0)
goto out_free_memmap;
@@ -773,7 +755,7 @@ static int wl1271_plt_init(struct wl1271 *wl)
return ret;
}
-static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
+static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
{
bool fw_ps;
@@ -785,21 +767,35 @@ static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
/*
* Wake up from high level PS if the STA is asleep with too little
- * blocks in FW or if the STA is awake.
+ * packets in FW or if the STA is awake.
*/
- if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
+ 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_blks >= WL1271_PS_STA_MAX_BLOCKS)
+ else if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl1271_ps_link_start(wl, hlid, true);
}
-static void wl1271_irq_update_links_status(struct wl1271 *wl,
- struct wl1271_fw_ap_status *status)
+bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
+{
+ int id;
+
+ /* global/broadcast "stations" are always active */
+ if (hlid < WL1271_AP_STA_HLID_START)
+ return true;
+
+ id = hlid - WL1271_AP_STA_HLID_START;
+ return test_bit(id, wl->ap_hlid_map);
+}
+
+static void wl12xx_irq_update_links_status(struct wl1271 *wl,
+ struct wl12xx_fw_status *status)
{
u32 cur_fw_ps_map;
- u8 hlid;
+ u8 hlid, cnt;
+
+ /* TODO: also use link_fast_bitmap here */
cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
if (wl->ap_fw_ps_map != cur_fw_ps_map) {
@@ -812,45 +808,30 @@ static void wl1271_irq_update_links_status(struct wl1271 *wl,
}
for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
- u8 cnt = status->tx_lnk_free_blks[hlid] -
- wl->links[hlid].prev_freed_blks;
-
- wl->links[hlid].prev_freed_blks =
- status->tx_lnk_free_blks[hlid];
- wl->links[hlid].allocated_blks -= cnt;
-
- wl1271_irq_ps_regulate_link(wl, hlid,
- wl->links[hlid].allocated_blks);
- }
-}
+ if (!wl1271_is_active_sta(wl, hlid))
+ continue;
-static u32 wl1271_tx_allocated_blocks(struct wl1271 *wl)
-{
- int i;
- u32 total_alloc_blocks = 0;
+ cnt = status->tx_lnk_free_pkts[hlid] -
+ wl->links[hlid].prev_freed_pkts;
- for (i = 0; i < NUM_TX_QUEUES; i++)
- total_alloc_blocks += wl->tx_allocated_blocks[i];
+ wl->links[hlid].prev_freed_pkts =
+ status->tx_lnk_free_pkts[hlid];
+ wl->links[hlid].allocated_pkts -= cnt;
- return total_alloc_blocks;
+ wl12xx_irq_ps_regulate_link(wl, hlid,
+ wl->links[hlid].allocated_pkts);
+ }
}
-static void wl1271_fw_status(struct wl1271 *wl,
- struct wl1271_fw_full_status *full_status)
+static void wl12xx_fw_status(struct wl1271 *wl,
+ struct wl12xx_fw_status *status)
{
- struct wl1271_fw_common_status *status = &full_status->common;
struct timespec ts;
u32 old_tx_blk_count = wl->tx_blocks_available;
- u32 freed_blocks = 0, ac_freed_blocks;
+ int avail, freed_blocks;
int i;
- if (wl->bss_type == BSS_TYPE_AP_BSS) {
- wl1271_raw_read(wl, FW_STATUS_ADDR, status,
- sizeof(struct wl1271_fw_ap_status), false);
- } else {
- wl1271_raw_read(wl, FW_STATUS_ADDR, status,
- sizeof(struct wl1271_fw_sta_status), false);
- }
+ wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
"drv_rx_counter = %d, tx_results_counter = %d)",
@@ -859,42 +840,49 @@ static void wl1271_fw_status(struct wl1271 *wl,
status->drv_rx_counter,
status->tx_results_counter);
- /* update number of available TX blocks */
for (i = 0; i < NUM_TX_QUEUES; i++) {
- ac_freed_blocks = le32_to_cpu(status->tx_released_blks[i]) -
- wl->tx_blocks_freed[i];
- freed_blocks += ac_freed_blocks;
+ /* prevent wrap-around in freed-packets counter */
+ wl->tx_allocated_pkts[i] -=
+ (status->tx_released_pkts[i] -
+ wl->tx_pkts_freed[i]) & 0xff;
- wl->tx_allocated_blocks[i] -= ac_freed_blocks;
-
- wl->tx_blocks_freed[i] =
- le32_to_cpu(status->tx_released_blks[i]);
+ wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
}
- if (wl->bss_type == BSS_TYPE_AP_BSS) {
- /* Update num of allocated TX blocks per link and ps status */
- wl1271_irq_update_links_status(wl, &full_status->ap);
- wl->tx_blocks_available += freed_blocks;
- } else {
- int avail = full_status->sta.tx_total -
- wl1271_tx_allocated_blocks(wl);
+ /* prevent wrap-around in total blocks counter */
+ if (likely(wl->tx_blocks_freed <=
+ le32_to_cpu(status->total_released_blks)))
+ freed_blocks = le32_to_cpu(status->total_released_blks) -
+ wl->tx_blocks_freed;
+ else
+ freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
+ le32_to_cpu(status->total_released_blks);
- /*
- * The FW might change the total number of TX memblocks before
- * we get a notification about blocks being released. Thus, the
- * available blocks calculation might yield a temporary result
- * which is lower than the actual available blocks. Keeping in
- * mind that only blocks that were allocated can be moved from
- * TX to RX, tx_blocks_available should never decrease here.
- */
- wl->tx_blocks_available = max((int)wl->tx_blocks_available,
- avail);
- }
+ wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
+
+ wl->tx_allocated_blocks -= freed_blocks;
+
+ avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
+
+ /*
+ * The FW might change the total number of TX memblocks before
+ * we get a notification about blocks being released. Thus, the
+ * available blocks calculation might yield a temporary result
+ * which is lower than the actual available blocks. Keeping in
+ * mind that only blocks that were allocated can be moved from
+ * TX to RX, tx_blocks_available should never decrease here.
+ */
+ wl->tx_blocks_available = max((int)wl->tx_blocks_available,
+ avail);
/* if more blocks are available now, tx work can be scheduled */
if (wl->tx_blocks_available > old_tx_blk_count)
clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
+ /* for AP update num of allocated TX blocks per link and ps status */
+ if (wl->bss_type == BSS_TYPE_AP_BSS)
+ wl12xx_irq_update_links_status(wl, status);
+
/* update the host-chipset time offset */
getnstimeofday(&ts);
wl->time_offset = (timespec_to_ns(&ts) >> 10) -
@@ -967,8 +955,8 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
smp_mb__after_clear_bit();
- wl1271_fw_status(wl, wl->fw_status);
- intr = le32_to_cpu(wl->fw_status->common.intr);
+ wl12xx_fw_status(wl, wl->fw_status);
+ intr = le32_to_cpu(wl->fw_status->intr);
intr &= WL1271_INTR_MASK;
if (!intr) {
done = true;
@@ -987,7 +975,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
if (likely(intr & WL1271_ACX_INTR_DATA)) {
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
- wl1271_rx(wl, &wl->fw_status->common);
+ wl12xx_rx(wl, wl->fw_status);
/* Check if any tx blocks were freed */
spin_lock_irqsave(&wl->wl_lock, flags);
@@ -1004,7 +992,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
}
/* check for tx results */
- if (wl->fw_status->common.tx_results_counter !=
+ if (wl->fw_status->tx_results_counter !=
(wl->tx_results_count & 0xff))
wl1271_tx_complete(wl);
@@ -1056,25 +1044,10 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
const char *fw_name;
int ret;
- switch (wl->bss_type) {
- case BSS_TYPE_AP_BSS:
- if (wl->chip.id == CHIP_ID_1283_PG20)
- fw_name = WL128X_AP_FW_NAME;
- else
- fw_name = WL127X_AP_FW_NAME;
- break;
- case BSS_TYPE_IBSS:
- case BSS_TYPE_STA_BSS:
- if (wl->chip.id == CHIP_ID_1283_PG20)
- fw_name = WL128X_FW_NAME;
- else
- fw_name = WL1271_FW_NAME;
- break;
- default:
- wl1271_error("no compatible firmware for bss_type %d",
- wl->bss_type);
- return -EINVAL;
- }
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ fw_name = WL128X_FW_NAME;
+ else
+ fw_name = WL127X_FW_NAME;
wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
@@ -1103,7 +1076,6 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
}
memcpy(wl->fw, fw->data, wl->fw_len);
- wl->fw_bss_type = wl->bss_type;
ret = 0;
out:
@@ -1194,8 +1166,8 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
wl12xx_cmd_stop_fwlog(wl);
/* Read the first memory block address */
- wl1271_fw_status(wl, wl->fw_status);
- first_addr = __le32_to_cpu(wl->fw_status->sta.log_start_addr);
+ wl12xx_fw_status(wl, wl->fw_status);
+ first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
if (!first_addr)
goto out;
@@ -1211,7 +1183,7 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
* of each memory block hold the hardware address of the next
* one. The last memory block points to the first one.
*/
- addr = __le32_to_cpup((__le32 *)block);
+ addr = le32_to_cpup((__le32 *)block);
if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
break;
@@ -1374,8 +1346,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
goto out;
}
- /* Make sure the firmware type matches the BSS type */
- if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
+ if (wl->fw == NULL) {
ret = wl1271_fetch_firmware(wl);
if (ret < 0)
goto out;
@@ -1510,10 +1481,25 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
q = wl1271_tx_get_queue(mapping);
if (wl->bss_type == BSS_TYPE_AP_BSS)
- hlid = wl1271_tx_get_hlid(skb);
+ hlid = wl12xx_tx_get_hlid_ap(wl, skb);
spin_lock_irqsave(&wl->wl_lock, flags);
+ /* queue the packet */
+ if (wl->bss_type == BSS_TYPE_AP_BSS) {
+ if (!wl1271_is_active_sta(wl, hlid)) {
+ wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d",
+ hlid, q);
+ dev_kfree_skb(skb);
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
+ skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
+ } else {
+ skb_queue_tail(&wl->tx_queue[q], skb);
+ }
+
wl->tx_queue_count[q]++;
/*
@@ -1526,14 +1512,6 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
set_bit(q, &wl->stopped_queues_map);
}
- /* queue the packet */
- if (wl->bss_type == BSS_TYPE_AP_BSS) {
- wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
- skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
- } else {
- skb_queue_tail(&wl->tx_queue[q], skb);
- }
-
/*
* The chip specific setup must run before the first TX packet -
* before that, the tx_work will not be initialized!
@@ -1543,6 +1521,7 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
!test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
ieee80211_queue_work(wl->hw, &wl->tx_work);
+out:
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
@@ -1679,7 +1658,7 @@ static int wl1271_configure_suspend_ap(struct wl1271 *wl)
if (ret < 0)
goto out_unlock;
- ret = wl1271_acx_set_ap_beacon_filter(wl, true);
+ ret = wl1271_acx_beacon_filter_opt(wl, true);
wl1271_ps_elp_sleep(wl);
out_unlock:
@@ -1717,7 +1696,7 @@ static void wl1271_configure_resume(struct wl1271 *wl)
wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
wl->basic_rate, true);
} else if (is_ap) {
- wl1271_acx_set_ap_beacon_filter(wl, false);
+ wl1271_acx_beacon_filter_opt(wl, false);
}
wl1271_ps_elp_sleep(wl);
@@ -1809,9 +1788,6 @@ static int wl1271_op_start(struct ieee80211_hw *hw)
*
* The MAC address is first known when the corresponding interface
* is added. That is where we will initialize the hardware.
- *
- * In addition, we currently have different firmwares for AP and managed
- * operation. We will know which to boot according to interface type.
*/
return 0;
@@ -1822,6 +1798,24 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
}
+static u8 wl12xx_get_role_type(struct wl1271 *wl)
+{
+ switch (wl->bss_type) {
+ case BSS_TYPE_AP_BSS:
+ return WL1271_ROLE_AP;
+
+ case BSS_TYPE_STA_BSS:
+ return WL1271_ROLE_STA;
+
+ case BSS_TYPE_IBSS:
+ return WL1271_ROLE_IBSS;
+
+ default:
+ wl1271_error("invalid bss_type: %d", wl->bss_type);
+ }
+ return WL12XX_INVALID_ROLE_TYPE;
+}
+
static int wl1271_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -1829,6 +1823,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
struct wiphy *wiphy = hw->wiphy;
int retries = WL1271_BOOT_RETRIES;
int ret = 0;
+ u8 role_type;
bool booted = false;
wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
@@ -1869,6 +1864,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
+ role_type = wl12xx_get_role_type(wl);
+ if (role_type == WL12XX_INVALID_ROLE_TYPE) {
+ ret = -EINVAL;
+ goto out;
+ }
memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
if (wl->state != WL1271_STATE_OFF) {
@@ -1888,6 +1888,25 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
if (ret < 0)
goto power_off;
+ if (wl->bss_type == BSS_TYPE_STA_BSS ||
+ wl->bss_type == BSS_TYPE_IBSS) {
+ /*
+ * The device role is a special role used for
+ * rx and tx frames prior to association (as
+ * the STA role can get packets only from
+ * its associated bssid)
+ */
+ ret = wl12xx_cmd_role_enable(wl,
+ WL1271_ROLE_DEVICE,
+ &wl->dev_role_id);
+ if (ret < 0)
+ goto irq_disable;
+ }
+
+ ret = wl12xx_cmd_role_enable(wl, role_type, &wl->role_id);
+ if (ret < 0)
+ goto irq_disable;
+
ret = wl1271_hw_init(wl);
if (ret < 0)
goto irq_disable;
@@ -1952,7 +1971,7 @@ out:
static void __wl1271_op_remove_interface(struct wl1271 *wl,
bool reset_tx_queues)
{
- int i;
+ int ret, i;
wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
@@ -1977,6 +1996,31 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
ieee80211_scan_completed(wl->hw, true);
}
+ if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
+ /* disable active roles */
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto deinit;
+
+ if (wl->bss_type == BSS_TYPE_STA_BSS) {
+ ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id);
+ if (ret < 0)
+ goto deinit;
+ }
+
+ ret = wl12xx_cmd_role_disable(wl, &wl->role_id);
+ if (ret < 0)
+ goto deinit;
+
+ wl1271_ps_elp_sleep(wl);
+ }
+deinit:
+ /* clear all hlids (except system_hlid) */
+ wl->sta_hlid = WL12XX_INVALID_LINK_ID;
+ wl->dev_hlid = WL12XX_INVALID_LINK_ID;
+ wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
+ wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
+
/*
* this must be before the cancel_work calls below, so that the work
* functions don't perform further work.
@@ -2013,18 +2057,26 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl->psm_entry_retry = 0;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
wl->tx_blocks_available = 0;
+ wl->tx_allocated_blocks = 0;
wl->tx_results_count = 0;
wl->tx_packets_count = 0;
wl->time_offset = 0;
wl->session_counter = 0;
wl->rate_set = CONF_TX_RATE_MASK_BASIC;
wl->vif = NULL;
- wl->filters = 0;
wl1271_free_ap_keys(wl);
memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
wl->ap_fw_ps_map = 0;
wl->ap_ps_map = 0;
wl->sched_scanning = false;
+ wl->role_id = WL12XX_INVALID_ROLE_ID;
+ wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
+ 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));
+
+ /* The system link is always allocated */
+ __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
/*
* this is performed after the cancel_work calls and the associated
@@ -2033,9 +2085,11 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
*/
wl->flags = 0;
+ wl->tx_blocks_freed = 0;
+
for (i = 0; i < NUM_TX_QUEUES; i++) {
- wl->tx_blocks_freed[i] = 0;
- wl->tx_allocated_blocks[i] = 0;
+ wl->tx_pkts_freed[i] = 0;
+ wl->tx_allocated_pkts[i] = 0;
}
wl1271_debugfs_reset(wl);
@@ -2067,64 +2121,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
cancel_work_sync(&wl->recovery_work);
}
-void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
-{
- wl1271_set_default_filters(wl);
-
- /* combine requested filters with current filter config */
- filters = wl->filters | filters;
-
- wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
-
- if (filters & FIF_PROMISC_IN_BSS) {
- wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
- wl->rx_config &= ~CFG_UNI_FILTER_EN;
- wl->rx_config |= CFG_BSSID_FILTER_EN;
- }
- if (filters & FIF_BCN_PRBRESP_PROMISC) {
- wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
- wl->rx_config &= ~CFG_BSSID_FILTER_EN;
- wl->rx_config &= ~CFG_SSID_FILTER_EN;
- }
- if (filters & FIF_OTHER_BSS) {
- wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
- wl->rx_config &= ~CFG_BSSID_FILTER_EN;
- }
- if (filters & FIF_CONTROL) {
- wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
- wl->rx_filter |= CFG_RX_CTL_EN;
- }
- if (filters & FIF_FCSFAIL) {
- wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
- wl->rx_filter |= CFG_RX_FCS_ERROR;
- }
-}
-
-static int wl1271_dummy_join(struct wl1271 *wl)
-{
- int ret = 0;
- /* we need to use a dummy BSSID for now */
- static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
- 0xad, 0xbe, 0xef };
-
- memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
-
- /* pass through frames from all BSS */
- wl1271_configure_filters(wl, FIF_OTHER_BSS);
-
- ret = wl1271_cmd_join(wl, wl->set_bss_type);
- if (ret < 0)
- goto out;
-
- set_bit(WL1271_FLAG_JOINED, &wl->flags);
-
-out:
- return ret;
-}
-
static int wl1271_join(struct wl1271 *wl, bool set_assoc)
{
int ret;
+ bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
/*
* One of the side effects of the JOIN command is that is clears
@@ -2141,12 +2141,13 @@ static int wl1271_join(struct wl1271 *wl, bool set_assoc)
if (set_assoc)
set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
- ret = wl1271_cmd_join(wl, wl->set_bss_type);
+ if (is_ibss)
+ ret = wl12xx_cmd_role_start_ibss(wl);
+ else
+ ret = wl12xx_cmd_role_start_sta(wl);
if (ret < 0)
goto out;
- set_bit(WL1271_FLAG_JOINED, &wl->flags);
-
if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
goto out;
@@ -2182,20 +2183,16 @@ static int wl1271_unjoin(struct wl1271 *wl)
int ret;
/* to stop listening to a channel, we disconnect */
- ret = wl1271_cmd_disconnect(wl);
+ ret = wl12xx_cmd_role_stop_sta(wl);
if (ret < 0)
goto out;
- clear_bit(WL1271_FLAG_JOINED, &wl->flags);
memset(wl->bssid, 0, ETH_ALEN);
/* reset TX security counters on a clean disconnect */
wl->tx_security_last_seq_lsb = 0;
wl->tx_security_seq = 0;
- /* stop filtering packets based on bssid */
- wl1271_configure_filters(wl, FIF_OTHER_BSS);
-
out:
return ret;
}
@@ -2208,13 +2205,29 @@ static void wl1271_set_band_rate(struct wl1271 *wl)
wl->basic_rate_set = wl->conf.tx.basic_rate_5;
}
+static bool wl12xx_is_roc(struct wl1271 *wl)
+{
+ u8 role_id;
+
+ role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
+ if (role_id >= WL12XX_MAX_ROLES)
+ return false;
+
+ return true;
+}
+
static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
{
int ret;
if (idle) {
- if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
- ret = wl1271_unjoin(wl);
+ /* no need to croc if we weren't busy (e.g. during boot) */
+ if (wl12xx_is_roc(wl)) {
+ ret = wl12xx_croc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out;
+
+ ret = wl12xx_cmd_role_stop_dev(wl);
if (ret < 0)
goto out;
}
@@ -2229,18 +2242,17 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
goto out;
set_bit(WL1271_FLAG_IDLE, &wl->flags);
} else {
- /* increment the session counter */
- wl->session_counter++;
- if (wl->session_counter >= SESSION_COUNTER_MAX)
- wl->session_counter = 0;
-
/* The current firmware only supports sched_scan in idle */
if (wl->sched_scanning) {
wl1271_scan_sched_scan_stop(wl);
ieee80211_sched_scan_stopped(wl->hw);
}
- ret = wl1271_dummy_join(wl);
+ ret = wl12xx_cmd_role_start_dev(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl12xx_roc(wl, wl->dev_role_id);
if (ret < 0)
goto out;
clear_bit(WL1271_FLAG_IDLE, &wl->flags);
@@ -2320,11 +2332,34 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
wl1271_warning("rate policy for channel "
"failed %d", ret);
- if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
+ if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
+ if (wl12xx_is_roc(wl)) {
+ /* roaming */
+ ret = wl12xx_croc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out_sleep;
+ }
ret = wl1271_join(wl, false);
if (ret < 0)
wl1271_warning("cmd join on channel "
"failed %d", ret);
+ } else {
+ /*
+ * change the ROC channel. do it only if we are
+ * not idle. otherwise, CROC will be called
+ * anyway.
+ */
+ if (wl12xx_is_roc(wl) &&
+ !(conf->flags & IEEE80211_CONF_IDLE)) {
+ ret = wl12xx_croc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out_sleep;
+
+ ret = wl12xx_roc(wl, wl->dev_role_id);
+ if (ret < 0)
+ wl1271_warning("roc failed %d",
+ ret);
+ }
}
}
}
@@ -2464,18 +2499,11 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
goto out_sleep;
}
- /* determine, whether supported filter values have changed */
- if (changed == 0)
- goto out_sleep;
-
- /* configure filters */
- wl->filters = *total;
- wl1271_configure_filters(wl, 0);
-
- /* apply configured filters */
- ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
- if (ret < 0)
- goto out_sleep;
+ /*
+ * the fw doesn't provide an api to configure the filters. instead,
+ * the filters configuration is based on the active roles / ROC
+ * state.
+ */
out_sleep:
wl1271_ps_elp_sleep(wl);
@@ -2547,14 +2575,19 @@ static int wl1271_ap_init_hwenc(struct wl1271 *wl)
bool wep_key_added = false;
for (i = 0; i < MAX_NUM_KEYS; i++) {
+ u8 hlid;
if (wl->recorded_ap_keys[i] == NULL)
break;
key = wl->recorded_ap_keys[i];
+ hlid = key->hlid;
+ if (hlid == WL12XX_INVALID_LINK_ID)
+ hlid = wl->ap_bcast_hlid;
+
ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
key->id, key->key_type,
key->key_size, key->key,
- key->hlid, key->tx_seq_32,
+ hlid, key->tx_seq_32,
key->tx_seq_16);
if (ret < 0)
goto out;
@@ -2564,7 +2597,8 @@ static int wl1271_ap_init_hwenc(struct wl1271 *wl)
}
if (wep_key_added) {
- ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
+ ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
+ wl->ap_bcast_hlid);
if (ret < 0)
goto out;
}
@@ -2589,7 +2623,7 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
wl_sta = (struct wl1271_station *)sta->drv_priv;
hlid = wl_sta->hlid;
} else {
- hlid = WL1271_AP_BROADCAST_HLID;
+ hlid = wl->ap_bcast_hlid;
}
if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
@@ -2633,6 +2667,11 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
return 0;
+ /* don't remove key if hlid was already deleted */
+ if (action == KEY_REMOVE &&
+ wl->sta_hlid == WL12XX_INVALID_LINK_ID)
+ return 0;
+
ret = wl1271_cmd_set_sta_key(wl, action,
id, key_type, key_size,
key, addr, tx_seq_32,
@@ -2642,8 +2681,9 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
/* the default WEP key needs to be configured at least once */
if (key_type == KEY_WEP) {
- ret = wl1271_cmd_set_sta_default_wep_key(wl,
- wl->default_key);
+ ret = wl12xx_cmd_set_default_wep_key(wl,
+ wl->default_key,
+ wl->sta_hlid);
if (ret < 0)
return ret;
}
@@ -2785,10 +2825,20 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- ret = wl1271_scan(hw->priv, ssid, len, req);
+ /* cancel ROC before scanning */
+ if (wl12xx_is_roc(wl)) {
+ if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
+ /* don't allow scanning right now */
+ ret = -EBUSY;
+ goto out_sleep;
+ }
+ wl12xx_croc(wl, wl->dev_role_id);
+ wl12xx_cmd_role_stop_dev(wl);
+ }
+ ret = wl1271_scan(hw->priv, ssid, len, req);
+out_sleep:
wl1271_ps_elp_sleep(wl);
-
out:
mutex_unlock(&wl->mutex);
@@ -3100,20 +3150,20 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
if (bss_conf->enable_beacon) {
if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
- ret = wl1271_cmd_start_bss(wl);
+ ret = wl12xx_cmd_role_start_ap(wl);
if (ret < 0)
goto out;
- set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
- wl1271_debug(DEBUG_AP, "started AP");
-
ret = wl1271_ap_init_hwenc(wl);
if (ret < 0)
goto out;
+
+ set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
+ wl1271_debug(DEBUG_AP, "started AP");
}
} else {
if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
- ret = wl1271_cmd_stop_bss(wl);
+ ret = wl12xx_cmd_role_stop_ap(wl);
if (ret < 0)
goto out;
@@ -3126,6 +3176,18 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
if (ret < 0)
goto out;
+
+ /* Handle HT information change */
+ if ((changed & BSS_CHANGED_HT) &&
+ (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
+ ret = wl1271_acx_set_ht_information(wl,
+ bss_conf->ht_operation_mode);
+ if (ret < 0) {
+ wl1271_warning("Set ht information failed %d", ret);
+ goto out;
+ }
+ }
+
out:
return;
}
@@ -3138,6 +3200,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
{
bool do_join = false, set_assoc = false;
bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
+ bool ibss_joined = false;
u32 sta_rate_set = 0;
int ret;
struct ieee80211_sta *sta;
@@ -3151,14 +3214,28 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
goto out;
}
- if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
+ if (changed & BSS_CHANGED_IBSS) {
+ if (bss_conf->ibss_joined) {
+ set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
+ ibss_joined = true;
+ } else {
+ if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
+ &wl->flags)) {
+ wl1271_unjoin(wl);
+ wl12xx_cmd_role_start_dev(wl);
+ wl12xx_roc(wl, wl->dev_role_id);
+ }
+ }
+ }
+
+ if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
do_join = true;
/* Need to update the SSID (for filtering etc) */
- if ((changed & BSS_CHANGED_BEACON) && is_ibss)
+ if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
do_join = true;
- if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
+ if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
bss_conf->enable_beacon ? "enabled" : "disabled");
@@ -3198,17 +3275,17 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
if (ret < 0)
goto out;
- /* filter out all packets not from this BSSID */
- wl1271_configure_filters(wl, 0);
-
/* Need to update the BSSID (for filtering etc) */
do_join = true;
}
}
- rcu_read_lock();
- sta = ieee80211_find_sta(vif, bss_conf->bssid);
- if (sta) {
+ if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
+ rcu_read_lock();
+ sta = ieee80211_find_sta(vif, bss_conf->bssid);
+ if (!sta)
+ goto sta_not_found;
+
/* save the supp_rates of the ap */
sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
if (sta->ht_cap.ht_supported)
@@ -3216,38 +3293,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
(sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
sta_ht_cap = sta->ht_cap;
sta_exists = true;
- }
- rcu_read_unlock();
- if (sta_exists) {
- /* handle new association with HT and HT information change */
- if ((changed & BSS_CHANGED_HT) &&
- (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
- ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
- true);
- if (ret < 0) {
- wl1271_warning("Set ht cap true failed %d",
- ret);
- goto out;
- }
- ret = wl1271_acx_set_ht_information(wl,
- bss_conf->ht_operation_mode);
- if (ret < 0) {
- wl1271_warning("Set ht information failed %d",
- ret);
- goto out;
- }
- }
- /* handle new association without HT and disassociation */
- else if (changed & BSS_CHANGED_ASSOC) {
- ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
- false);
- if (ret < 0) {
- wl1271_warning("Set ht cap false failed %d",
- ret);
- goto out;
- }
- }
+sta_not_found:
+ rcu_read_unlock();
}
if ((changed & BSS_CHANGED_ASSOC)) {
@@ -3315,7 +3363,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
bool was_assoc =
!!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
&wl->flags);
- clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
+ bool was_ifup =
+ !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
+ &wl->flags);
wl->aid = 0;
/* free probe-request template */
@@ -3342,8 +3392,32 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
/* restore the bssid filter and go to dummy bssid */
if (was_assoc) {
+ u32 conf_flags = wl->hw->conf.flags;
+ /*
+ * we might have to disable roc, if there was
+ * no IF_OPER_UP notification.
+ */
+ if (!was_ifup) {
+ ret = wl12xx_croc(wl, wl->role_id);
+ if (ret < 0)
+ goto out;
+ }
+ /*
+ * (we also need to disable roc in case of
+ * roaming on the same channel. until we will
+ * have a better flow...)
+ */
+ if (test_bit(wl->dev_role_id, wl->roc_map)) {
+ ret = wl12xx_croc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out;
+ }
+
wl1271_unjoin(wl);
- wl1271_dummy_join(wl);
+ if (!(conf_flags & IEEE80211_CONF_IDLE)) {
+ wl12xx_cmd_role_start_dev(wl);
+ wl12xx_roc(wl, wl->dev_role_id);
+ }
}
}
}
@@ -3404,7 +3478,68 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
wl1271_warning("cmd join failed %d", ret);
goto out;
}
- wl1271_check_operstate(wl, ieee80211_get_operstate(vif));
+
+ /* ROC until connected (after EAPOL exchange) */
+ if (!is_ibss) {
+ ret = wl12xx_roc(wl, wl->role_id);
+ if (ret < 0)
+ goto out;
+
+ wl1271_check_operstate(wl,
+ ieee80211_get_operstate(vif));
+ }
+ /*
+ * stop device role if started (we might already be in
+ * STA role). TODO: make it better.
+ */
+ if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) {
+ ret = wl12xx_croc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out;
+
+ ret = wl12xx_cmd_role_stop_dev(wl);
+ if (ret < 0)
+ goto out;
+ }
+ }
+
+ /* Handle new association with HT. Do this after join. */
+ if (sta_exists) {
+ if ((changed & BSS_CHANGED_HT) &&
+ (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
+ ret = wl1271_acx_set_ht_capabilities(wl,
+ &sta_ht_cap,
+ true,
+ wl->sta_hlid);
+ if (ret < 0) {
+ wl1271_warning("Set ht cap true failed %d",
+ ret);
+ goto out;
+ }
+ }
+ /* handle new association without HT and disassociation */
+ else if (changed & BSS_CHANGED_ASSOC) {
+ ret = wl1271_acx_set_ht_capabilities(wl,
+ &sta_ht_cap,
+ false,
+ wl->sta_hlid);
+ if (ret < 0) {
+ wl1271_warning("Set ht cap false failed %d",
+ ret);
+ goto out;
+ }
+ }
+ }
+
+ /* Handle HT information change. Done after join. */
+ if ((changed & BSS_CHANGED_HT) &&
+ (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
+ ret = wl1271_acx_set_ht_information(wl,
+ bss_conf->ht_operation_mode);
+ if (ret < 0) {
+ wl1271_warning("Set ht information failed %d", ret);
+ goto out;
+ }
}
out:
@@ -3574,7 +3709,7 @@ static int wl1271_allocate_sta(struct wl1271 *wl,
}
wl_sta = (struct wl1271_station *)sta->drv_priv;
- __set_bit(id, wl->ap_hlid_map);
+ set_bit(id, wl->ap_hlid_map);
wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
*hlid = wl_sta->hlid;
memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
@@ -3588,19 +3723,14 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
return;
- __clear_bit(id, wl->ap_hlid_map);
+ clear_bit(id, wl->ap_hlid_map);
memset(wl->links[hlid].addr, 0, ETH_ALEN);
+ wl->links[hlid].ba_bitmap = 0;
wl1271_tx_reset_link_queues(wl, hlid);
__clear_bit(hlid, &wl->ap_ps_map);
__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
}
-bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
-{
- int id = hlid - WL1271_AP_STA_HLID_START;
- return test_bit(id, wl->ap_hlid_map);
-}
-
static int wl1271_op_sta_add(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
@@ -3627,7 +3757,15 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw,
if (ret < 0)
goto out_free_sta;
- ret = wl1271_cmd_add_sta(wl, sta, hlid);
+ ret = wl12xx_cmd_add_peer(wl, sta, hlid);
+ if (ret < 0)
+ goto out_sleep;
+
+ ret = wl12xx_cmd_set_peer_state(wl, hlid);
+ if (ret < 0)
+ goto out_sleep;
+
+ ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
if (ret < 0)
goto out_sleep;
@@ -3670,7 +3808,7 @@ static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
+ ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
if (ret < 0)
goto out_sleep;
@@ -3692,6 +3830,14 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
{
struct wl1271 *wl = hw->priv;
int ret;
+ u8 hlid, *ba_bitmap;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
+ tid);
+
+ /* sanity check - the fields in FW are only 8bits wide */
+ if (WARN_ON(tid > 0xFF))
+ return -ENOTSUPP;
mutex_lock(&wl->mutex);
@@ -3700,6 +3846,20 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
goto out;
}
+ if (wl->bss_type == BSS_TYPE_STA_BSS) {
+ hlid = wl->sta_hlid;
+ ba_bitmap = &wl->ba_rx_bitmap;
+ } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
+ struct wl1271_station *wl_sta;
+
+ wl_sta = (struct wl1271_station *)sta->drv_priv;
+ hlid = wl_sta->hlid;
+ ba_bitmap = &wl->links[hlid].ba_bitmap;
+ } else {
+ ret = -EINVAL;
+ goto out;
+ }
+
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
@@ -3709,20 +3869,46 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
switch (action) {
case IEEE80211_AMPDU_RX_START:
- if ((wl->ba_support) && (wl->ba_allowed)) {
- ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
- true);
- if (!ret)
- wl->ba_rx_bitmap |= BIT(tid);
- } else {
+ if (!wl->ba_support || !wl->ba_allowed) {
ret = -ENOTSUPP;
+ break;
+ }
+
+ if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
+ ret = -EBUSY;
+ wl1271_error("exceeded max RX BA sessions");
+ break;
+ }
+
+ if (*ba_bitmap & BIT(tid)) {
+ ret = -EINVAL;
+ wl1271_error("cannot enable RX BA session on active "
+ "tid: %d", tid);
+ break;
+ }
+
+ ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
+ hlid);
+ if (!ret) {
+ *ba_bitmap |= BIT(tid);
+ wl->ba_rx_session_count++;
}
break;
case IEEE80211_AMPDU_RX_STOP:
- ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
- if (!ret)
- wl->ba_rx_bitmap &= ~BIT(tid);
+ if (!(*ba_bitmap & BIT(tid))) {
+ ret = -EINVAL;
+ wl1271_error("no active RX BA session on tid: %d",
+ tid);
+ break;
+ }
+
+ ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
+ hlid);
+ if (!ret) {
+ *ba_bitmap &= ~BIT(tid);
+ wl->ba_rx_session_count--;
+ }
break;
/*
@@ -4294,7 +4480,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
* should be the maximum length possible for a template, without
* the IEEE80211 header of the template
*/
- wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
+ wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
sizeof(struct ieee80211_header);
/* make sure all our channels fit in the scanned_ch bitmask */
@@ -4393,8 +4579,6 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
wl->default_key = 0;
wl->rx_counter = 0;
- wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
- wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
wl->psm_entry_retry = 0;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
@@ -4407,7 +4591,6 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->hw_pg_ver = -1;
wl->bss_type = MAX_BSS_TYPE;
wl->set_bss_type = MAX_BSS_TYPE;
- wl->fw_bss_type = MAX_BSS_TYPE;
wl->last_tx_hlid = 0;
wl->ap_ps_map = 0;
wl->ap_fw_ps_map = 0;
@@ -4416,12 +4599,22 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->sched_scanning = false;
wl->tx_security_seq = 0;
wl->tx_security_last_seq_lsb = 0;
-
+ wl->role_id = WL12XX_INVALID_ROLE_ID;
+ wl->system_hlid = WL12XX_SYSTEM_HLID;
+ wl->sta_hlid = WL12XX_INVALID_LINK_ID;
+ wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
+ wl->dev_hlid = WL12XX_INVALID_LINK_ID;
+ wl->session_counter = 0;
+ wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
+ wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
(unsigned long) wl);
wl->fwlog_size = 0;
init_waitqueue_head(&wl->fwlog_waitq);
+ /* The system link is always allocated */
+ __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
+
memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
wl->tx_frames[i] = NULL;
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c
index 3548377ab9c..4b720b1b9f6 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -226,8 +226,8 @@ void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues)
if (test_bit(hlid, &wl->ap_ps_map))
return;
- wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d blks %d "
- "clean_queues %d", hlid, wl->links[hlid].allocated_blks,
+ wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d pkts %d "
+ "clean_queues %d", hlid, wl->links[hlid].allocated_pkts,
clean_queues);
rcu_read_lock();
diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h
index 440a4ee9cb4..3f570f39758 100644
--- a/drivers/net/wireless/wl12xx/reg.h
+++ b/drivers/net/wireless/wl12xx/reg.h
@@ -296,81 +296,6 @@
===============================================*/
#define REG_EVENT_MAILBOX_PTR (SCR_PAD1)
-
-/* Misc */
-
-#define REG_ENABLE_TX_RX (ENABLE)
-/*
- * Rx configuration (filter) information element
- * ---------------------------------------------
- */
-#define REG_RX_CONFIG (RX_CFG)
-#define REG_RX_FILTER (RX_FILTER_CFG)
-
-
-#define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002
-
-/* promiscuous - receives all valid frames */
-#define RX_CFG_PROMISCUOUS 0x0008
-
-/* receives frames from any BSSID */
-#define RX_CFG_BSSID 0x0020
-
-/* receives frames destined to any MAC address */
-#define RX_CFG_MAC 0x0010
-
-#define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010
-#define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000
-#define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020
-#define RX_CFG_ENABLE_ANY_BSSID 0x0000
-
-/* discards all broadcast frames */
-#define RX_CFG_DISABLE_BCAST 0x0200
-
-#define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400
-#define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800
-#define RX_CFG_COPY_RX_STATUS 0x2000
-#define RX_CFG_TSF 0x10000
-
-#define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \
- RX_CFG_ENABLE_ONLY_MY_BSSID)
-
-#define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\
- | RX_CFG_ENABLE_ANY_BSSID)
-
-#define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \
- RX_CFG_ENABLE_ANY_BSSID)
-
-#define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\
- | RX_CFG_ENABLE_ONLY_MY_BSSID)
-
-#define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \
- | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \
- | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF)
-
-#define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC)
-
-#define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \
- RX_CFG_ENABLE_ONLY_MY_DEST_MAC)
-
-#define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \
- RX_CFG_ENABLE_ONLY_MY_DEST_MAC)
-
-#define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\
- | CFG_RX_CTL_EN | CFG_RX_BCN_EN\
- | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
-
-#define RX_FILTER_OPTION_FILTER_ALL 0
-
-#define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\
- | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN)
-
-#define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\
- | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\
- | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\
- | CFG_RX_PRSP_EN)
-
-
/*===============================================
EEPROM Read/Write Request 32bit RW
------------------------------------------
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c
index 46f4af6ca72..78d8410da1f 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/rx.c
@@ -30,21 +30,21 @@
#include "rx.h"
#include "io.h"
-static u8 wl1271_rx_get_mem_block(struct wl1271_fw_common_status *status,
+static u8 wl12xx_rx_get_mem_block(struct wl12xx_fw_status *status,
u32 drv_rx_counter)
{
return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
RX_MEM_BLOCK_MASK;
}
-static u32 wl1271_rx_get_buf_size(struct wl1271_fw_common_status *status,
- u32 drv_rx_counter)
+static u32 wl12xx_rx_get_buf_size(struct wl12xx_fw_status *status,
+ u32 drv_rx_counter)
{
return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV;
}
-static bool wl1271_rx_get_unaligned(struct wl1271_fw_common_status *status,
+static bool wl12xx_rx_get_unaligned(struct wl12xx_fw_status *status,
u32 drv_rx_counter)
{
/* Convert the value to bool */
@@ -181,7 +181,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
return is_data;
}
-void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
+void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
{
struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
u32 buf_size;
@@ -199,7 +199,7 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
buf_size = 0;
rx_counter = drv_rx_counter;
while (rx_counter != fw_rx_counter) {
- pkt_length = wl1271_rx_get_buf_size(status, rx_counter);
+ pkt_length = wl12xx_rx_get_buf_size(status, rx_counter);
if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE)
break;
buf_size += pkt_length;
@@ -218,7 +218,7 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
* For aggregated packets, only the first memory block
* should be retrieved. The FW takes care of the rest.
*/
- mem_block = wl1271_rx_get_mem_block(status,
+ mem_block = wl12xx_rx_get_mem_block(status,
drv_rx_counter);
wl->rx_mem_pool_addr.addr = (mem_block << 8) +
@@ -239,10 +239,10 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
/* Split data into separate packets */
pkt_offset = 0;
while (pkt_offset < buf_size) {
- pkt_length = wl1271_rx_get_buf_size(status,
+ pkt_length = wl12xx_rx_get_buf_size(status,
drv_rx_counter);
- unaligned = wl1271_rx_get_unaligned(status,
+ unaligned = wl12xx_rx_get_unaligned(status,
drv_rx_counter);
/*
@@ -283,14 +283,3 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
jiffies + msecs_to_jiffies(timeout));
}
}
-
-void wl1271_set_default_filters(struct wl1271 *wl)
-{
- if (wl->bss_type == BSS_TYPE_AP_BSS) {
- wl->rx_config = WL1271_DEFAULT_AP_RX_CONFIG;
- wl->rx_filter = WL1271_DEFAULT_AP_RX_FILTER;
- } else {
- wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
- wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
- }
-}
diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h
index 0325b9de612..86ba6b1d0cd 100644
--- a/drivers/net/wireless/wl12xx/rx.h
+++ b/drivers/net/wireless/wl12xx/rx.h
@@ -86,7 +86,7 @@
* Bits 3-5 - process_id tag (AP mode FW)
* Bits 6-7 - reserved
*/
-#define WL1271_RX_DESC_STATUS_MASK 0x07
+#define WL1271_RX_DESC_STATUS_MASK 0x03
#define WL1271_RX_DESC_SUCCESS 0x00
#define WL1271_RX_DESC_DECRYPT_FAIL 0x01
@@ -121,16 +121,12 @@ struct wl1271_rx_descriptor {
u8 snr;
__le32 timestamp;
u8 packet_class;
- union {
- u8 process_id; /* STA FW */
- u8 hlid; /* AP FW */
- } __packed;
+ u8 hlid;
u8 pad_len;
u8 reserved;
} __packed;
-void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status);
+void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
-void wl1271_set_default_filters(struct wl1271 *wl);
#endif
diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c
index edfe01c321c..7229eaa8901 100644
--- a/drivers/net/wireless/wl12xx/scan.c
+++ b/drivers/net/wireless/wl12xx/scan.c
@@ -33,6 +33,8 @@ void wl1271_scan_complete_work(struct work_struct *work)
{
struct delayed_work *dwork;
struct wl1271 *wl;
+ int ret;
+ bool is_sta, is_ibss;
dwork = container_of(work, struct delayed_work, work);
wl = container_of(dwork, struct wl1271, scan_complete_work);
@@ -50,21 +52,34 @@ void wl1271_scan_complete_work(struct work_struct *work)
wl->scan.state = WL1271_SCAN_STATE_IDLE;
memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
wl->scan.req = NULL;
- ieee80211_scan_completed(wl->hw, false);
- /* restore hardware connection monitoring template */
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
- if (wl1271_ps_elp_wakeup(wl) == 0) {
- wl1271_cmd_build_ap_probe_req(wl, wl->probereq);
- wl1271_ps_elp_sleep(wl);
- }
+ /* restore hardware connection monitoring template */
+ wl1271_cmd_build_ap_probe_req(wl, wl->probereq);
+ }
+
+ /* 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))) {
+ /* restore remain on channel */
+ wl12xx_cmd_role_start_dev(wl);
+ wl12xx_roc(wl, wl->dev_role_id);
}
+ wl1271_ps_elp_sleep(wl);
if (wl->scan.failed) {
wl1271_info("Scan completed due to error.");
wl12xx_queue_recovery_work(wl);
}
+ ieee80211_scan_completed(wl->hw, false);
+
out:
mutex_unlock(&wl->mutex);
@@ -156,6 +171,11 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
if (passive || wl->scan.req->n_ssids == 0)
scan_options |= WL1271_SCAN_OPT_PASSIVE;
+ if (WARN_ON(wl->role_id == WL12XX_INVALID_ROLE_ID)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ cmd->params.role_id = wl->role_id;
cmd->params.scan_options = cpu_to_le16(scan_options);
cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
@@ -167,10 +187,6 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
}
cmd->params.tx_rate = cpu_to_le32(basic_rate);
- cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
- cmd->params.rx_filter_options =
- cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
-
cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
cmd->params.tx_rate = cpu_to_le32(basic_rate);
cmd->params.tid_trigger = 0;
@@ -186,6 +202,8 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len);
}
+ memcpy(cmd->addr, wl->mac_addr, ETH_ALEN);
+
ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len,
wl->scan.req->ie, wl->scan.req->ie_len,
band);
diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h
index 0b2a2987439..92115156522 100644
--- a/drivers/net/wireless/wl12xx/scan.h
+++ b/drivers/net/wireless/wl12xx/scan.h
@@ -46,7 +46,10 @@ void wl1271_scan_sched_scan_results(struct wl1271 *wl);
#define WL1271_SCAN_CURRENT_TX_PWR 0
#define WL1271_SCAN_OPT_ACTIVE 0
#define WL1271_SCAN_OPT_PASSIVE 1
+#define WL1271_SCAN_OPT_TRIGGERED_SCAN 2
#define WL1271_SCAN_OPT_PRIORITY_HIGH 4
+/* scan even if we fail to enter psm */
+#define WL1271_SCAN_OPT_FORCE 8
#define WL1271_SCAN_BAND_2_4_GHZ 0
#define WL1271_SCAN_BAND_5_GHZ 1
@@ -62,27 +65,27 @@ enum {
};
struct basic_scan_params {
- __le32 rx_config_options;
- __le32 rx_filter_options;
/* Scan option flags (WL1271_SCAN_OPT_*) */
__le16 scan_options;
+ u8 role_id;
/* Number of scan channels in the list (maximum 30) */
u8 n_ch;
/* This field indicates the number of probe requests to send
per channel for an active scan */
u8 n_probe_reqs;
- /* Rate bit field for sending the probes */
- __le32 tx_rate;
u8 tid_trigger;
u8 ssid_len;
- /* in order to align */
- u8 padding1[2];
+ u8 use_ssid_list;
+
+ /* Rate bit field for sending the probes */
+ __le32 tx_rate;
+
u8 ssid[IEEE80211_MAX_SSID_LEN];
/* Band to scan */
u8 band;
- u8 use_ssid_list;
+
u8 scan_tag;
- u8 padding2;
+ u8 padding2[2];
} __packed;
struct basic_scan_channel_params {
@@ -105,6 +108,10 @@ struct wl1271_cmd_scan {
struct basic_scan_params params;
struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
+
+ /* src mac address */
+ u8 addr[ETH_ALEN];
+ u8 padding[2];
} __packed;
struct wl1271_cmd_trigger_scan_to {
@@ -184,7 +191,7 @@ struct wl1271_cmd_sched_scan_config {
} __packed;
-#define SCHED_SCAN_MAX_SSIDS 8
+#define SCHED_SCAN_MAX_SSIDS 16
enum {
SCAN_SSID_TYPE_PUBLIC = 0,
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index 5cf18c2c23f..ac2e5661397 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -412,7 +412,5 @@ module_exit(wl1271_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
-MODULE_FIRMWARE(WL1271_FW_NAME);
+MODULE_FIRMWARE(WL127X_FW_NAME);
MODULE_FIRMWARE(WL128X_FW_NAME);
-MODULE_FIRMWARE(WL127X_AP_FW_NAME);
-MODULE_FIRMWARE(WL128X_AP_FW_NAME);
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c
index e0b3736d7e1..0f971867786 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -486,8 +486,6 @@ module_exit(wl1271_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
-MODULE_FIRMWARE(WL1271_FW_NAME);
+MODULE_FIRMWARE(WL127X_FW_NAME);
MODULE_FIRMWARE(WL128X_FW_NAME);
-MODULE_FIRMWARE(WL127X_AP_FW_NAME);
-MODULE_FIRMWARE(WL128X_AP_FW_NAME);
MODULE_ALIAS("spi:wl1271");
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 48fde96ce0d..0f1578577b1 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -37,9 +37,10 @@ static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id)
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
if (is_ap)
- ret = wl1271_cmd_set_ap_default_wep_key(wl, id);
+ ret = wl12xx_cmd_set_default_wep_key(wl, id,
+ wl->ap_bcast_hlid);
else
- ret = wl1271_cmd_set_sta_default_wep_key(wl, id);
+ ret = wl12xx_cmd_set_default_wep_key(wl, id, wl->sta_hlid);
if (ret < 0)
return ret;
@@ -77,6 +78,7 @@ static int wl1271_tx_update_filters(struct wl1271 *wl,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
+ int ret;
hdr = (struct ieee80211_hdr *)(skb->data +
sizeof(struct wl1271_tx_hw_descr));
@@ -90,9 +92,19 @@ static int wl1271_tx_update_filters(struct wl1271 *wl,
if (!ieee80211_is_auth(hdr->frame_control))
return 0;
- wl1271_configure_filters(wl, FIF_OTHER_BSS);
+ if (wl->dev_hlid != WL12XX_INVALID_LINK_ID)
+ goto out;
- return wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
+ wl1271_debug(DEBUG_CMD, "starting device role for roaming");
+ ret = wl12xx_cmd_role_start_dev(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl12xx_roc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out;
+out:
+ return 0;
}
static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
@@ -114,24 +126,29 @@ 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;
- u8 tx_blks;
+ u8 tx_pkts;
/* only regulate station links */
if (hlid < WL1271_AP_STA_HLID_START)
return;
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
- tx_blks = wl->links[hlid].allocated_blks;
+ tx_pkts = wl->links[hlid].allocated_pkts;
/*
* 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.
*/
- if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
+ if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl1271_ps_link_start(wl, hlid, true);
}
-u8 wl1271_tx_get_hlid(struct sk_buff *skb)
+static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
+{
+ return wl->dummy_packet == skb;
+}
+
+u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb)
{
struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb);
@@ -144,14 +161,32 @@ u8 wl1271_tx_get_hlid(struct sk_buff *skb)
} else {
struct ieee80211_hdr *hdr;
+ if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
+ return wl->system_hlid;
+
hdr = (struct ieee80211_hdr *)skb->data;
if (ieee80211_is_mgmt(hdr->frame_control))
- return WL1271_AP_GLOBAL_HLID;
+ return wl->ap_global_hlid;
else
- return WL1271_AP_BROADCAST_HLID;
+ return wl->ap_bcast_hlid;
}
}
+static u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb)
+{
+ 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))
+ return wl->sta_hlid;
+ else
+ return wl->dev_hlid;
+}
+
static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl,
unsigned int packet_length)
{
@@ -169,12 +204,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
u32 len;
u32 total_blocks;
int id, ret = -EBUSY, ac;
- u32 spare_blocks;
- if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS))
- spare_blocks = 2;
- else
- spare_blocks = 1;
+ /* we use 1 spare block */
+ u32 spare_blocks = 1;
if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
return -EAGAIN;
@@ -206,12 +238,14 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
desc->id = id;
wl->tx_blocks_available -= total_blocks;
+ wl->tx_allocated_blocks += total_blocks;
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
- wl->tx_allocated_blocks[ac] += total_blocks;
+ wl->tx_allocated_pkts[ac]++;
- if (wl->bss_type == BSS_TYPE_AP_BSS)
- wl->links[hlid].allocated_blks += total_blocks;
+ if (wl->bss_type == BSS_TYPE_AP_BSS &&
+ hlid >= WL1271_AP_STA_HLID_START)
+ wl->links[hlid].allocated_pkts++;
ret = 0;
@@ -225,11 +259,6 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
return ret;
}
-static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
-{
- return wl->dummy_packet == skb;
-}
-
static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
u32 extra, struct ieee80211_tx_info *control,
u8 hlid)
@@ -280,9 +309,9 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
}
- if (wl->bss_type != BSS_TYPE_AP_BSS) {
- desc->aid = hlid;
+ desc->hlid = hlid;
+ if (wl->bss_type != BSS_TYPE_AP_BSS) {
/* if the packets are destined for AP (have a STA entry)
send them with AP rate policies, otherwise use default
basic rates */
@@ -291,18 +320,12 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
else
rate_idx = ACX_TX_BASIC_RATE;
} else {
- desc->hlid = hlid;
- switch (hlid) {
- case WL1271_AP_GLOBAL_HLID:
+ if (hlid == wl->ap_global_hlid)
rate_idx = ACX_TX_AP_MODE_MGMT_RATE;
- break;
- case WL1271_AP_BROADCAST_HLID:
+ else if (hlid == wl->ap_bcast_hlid)
rate_idx = ACX_TX_AP_MODE_BCST_RATE;
- break;
- default:
+ else
rate_idx = ac;
- break;
- }
}
tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY;
@@ -376,10 +399,11 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
}
}
- if (wl->bss_type == BSS_TYPE_AP_BSS)
- hlid = wl1271_tx_get_hlid(skb);
- else
- hlid = TX_HW_DEFAULT_AID;
+ hlid = wl1271_tx_get_hlid(wl, skb);
+ if (hlid == WL12XX_INVALID_LINK_ID) {
+ wl1271_error("invalid hlid. dropping skb 0x%p", skb);
+ return -EINVAL;
+ }
ret = wl1271_tx_allocate(wl, skb, extra, buf_offset, hlid);
if (ret < 0)
@@ -462,20 +486,24 @@ void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl,
struct sk_buff_head *queues)
{
- int i, q = -1;
- u32 min_blks = 0xffffffff;
+ int i, q = -1, ac;
+ u32 min_pkts = 0xffffffff;
/*
* Find a non-empty ac where:
* 1. There are packets to transmit
* 2. The FW has the least allocated blocks
+ *
+ * We prioritize the ACs according to VO>VI>BE>BK
*/
- for (i = 0; i < NUM_TX_QUEUES; i++)
- if (!skb_queue_empty(&queues[i]) &&
- (wl->tx_allocated_blocks[i] < min_blks)) {
- q = i;
- min_blks = wl->tx_allocated_blocks[q];
+ for (i = 0; i < NUM_TX_QUEUES; i++) {
+ ac = wl1271_tx_get_queue(i);
+ if (!skb_queue_empty(&queues[ac]) &&
+ (wl->tx_allocated_pkts[ac] < min_pkts)) {
+ q = ac;
+ min_pkts = wl->tx_allocated_pkts[q];
}
+ }
if (q == -1)
return NULL;
@@ -579,7 +607,7 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
if (wl12xx_is_dummy_packet(wl, skb)) {
set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
} else if (wl->bss_type == BSS_TYPE_AP_BSS) {
- u8 hlid = wl1271_tx_get_hlid(skb);
+ u8 hlid = wl1271_tx_get_hlid(wl, skb);
skb_queue_head(&wl->links[hlid].tx_queue[q], skb);
/* make sure we dequeue the same packet next time */
@@ -826,10 +854,14 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
total[i] = 0;
while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb);
- info = IEEE80211_SKB_CB(skb);
- info->status.rates[0].idx = -1;
- info->status.rates[0].count = 0;
- ieee80211_tx_status_ni(wl->hw, skb);
+
+ if (!wl12xx_is_dummy_packet(wl, skb)) {
+ info = IEEE80211_SKB_CB(skb);
+ info->status.rates[0].idx = -1;
+ info->status.rates[0].count = 0;
+ ieee80211_tx_status_ni(wl->hw, skb);
+ }
+
total[i]++;
}
}
@@ -853,8 +885,8 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
if (wl->bss_type == BSS_TYPE_AP_BSS) {
for (i = 0; i < AP_MAX_LINKS; i++) {
wl1271_tx_reset_link_queues(wl, i);
- wl->links[i].allocated_blks = 0;
- wl->links[i].prev_freed_blks = 0;
+ wl->links[i].allocated_pkts = 0;
+ wl->links[i].prev_freed_pkts = 0;
}
wl->last_tx_hlid = 0;
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index 5d719b5a3d1..7da35c0e411 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -29,9 +29,6 @@
#define TX_HW_MGMT_PKT_LIFETIME_TU 2000
#define TX_HW_AP_MODE_PKT_LIFETIME_TU 8000
-/* The chipset reference driver states, that the "aid" value 1
- * is for infra-BSS, but is still always used */
-#define TX_HW_DEFAULT_AID 1
#define TX_HW_ATTR_SAVE_RETRIES BIT(0)
#define TX_HW_ATTR_HEADER_PAD BIT(1)
@@ -116,12 +113,8 @@ struct wl1271_tx_hw_descr {
u8 id;
/* The packet TID value (as User-Priority) */
u8 tid;
- union {
- /* STA - Identifier of the remote STA in IBSS, 1 in infra-BSS */
- u8 aid;
- /* AP - host link ID (HLID) */
- u8 hlid;
- } __packed;
+ /* host link ID (HLID) */
+ u8 hlid;
u8 reserved;
} __packed;
@@ -133,7 +126,8 @@ enum wl1271_tx_hw_res_status {
TX_TIMEOUT = 4,
TX_KEY_NOT_FOUND = 5,
TX_PEER_NOT_FOUND = 6,
- TX_SESSION_MISMATCH = 7
+ TX_SESSION_MISMATCH = 7,
+ TX_LINK_NOT_VALID = 8,
};
struct wl1271_tx_hw_res_descr {
@@ -216,7 +210,7 @@ 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);
-u8 wl1271_tx_get_hlid(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_handle_tx_low_watermark(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 0bc29356ebe..61a7c2163ea 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -112,28 +112,8 @@ extern u32 wl12xx_debug_level;
true); \
} while (0)
-#define WL1271_DEFAULT_STA_RX_CONFIG (CFG_UNI_FILTER_EN | \
- CFG_BSSID_FILTER_EN | \
- CFG_MC_FILTER_EN)
-
-#define WL1271_DEFAULT_STA_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \
- CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
- CFG_RX_CTL_EN | CFG_RX_BCN_EN | \
- CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
-
-#define WL1271_DEFAULT_AP_RX_CONFIG 0
-
-#define WL1271_DEFAULT_AP_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PREQ_EN | \
- CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
- CFG_RX_CTL_EN | CFG_RX_AUTH_EN | \
- CFG_RX_ASSOC_EN)
-
-
-
-#define WL1271_FW_NAME "ti-connectivity/wl1271-fw-2.bin"
-#define WL128X_FW_NAME "ti-connectivity/wl128x-fw.bin"
-#define WL127X_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin"
-#define WL128X_AP_FW_NAME "ti-connectivity/wl128x-fw-ap.bin"
+#define WL127X_FW_NAME "ti-connectivity/wl127x-fw-3.bin"
+#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-3.bin"
/*
* wl127x and wl128x are using the same NVS file name. However, the
@@ -157,25 +137,34 @@ extern u32 wl12xx_debug_level;
#define WL1271_DEFAULT_BEACON_INT 100
#define WL1271_DEFAULT_DTIM_PERIOD 1
-#define WL1271_AP_GLOBAL_HLID 0
-#define WL1271_AP_BROADCAST_HLID 1
-#define WL1271_AP_STA_HLID_START 2
+#define WL12XX_MAX_ROLES 4
+#define WL12XX_MAX_LINKS 8
+#define WL12XX_INVALID_ROLE_ID 0xff
+#define WL12XX_INVALID_LINK_ID 0xff
+
+/* Defined by FW as 0. Will not be freed or allocated. */
+#define WL12XX_SYSTEM_HLID 0
+
+/*
+ * TODO: we currently don't support multirole. remove
+ * this constant from the code when we do.
+ */
+#define WL1271_AP_STA_HLID_START 3
/*
- * When in AP-mode, we allow (at least) this number of mem-blocks
+ * When in AP-mode, we allow (at least) this number of packets
* to be transmitted to FW for a STA in PS-mode. Only when packets are
* present in the FW buffers it will wake the sleeping STA. We want to put
* enough packets for the driver to transmit all of its buffered data before
- * the STA goes to sleep again. But we don't want to take too much mem-blocks
+ * the STA goes to sleep again. But we don't want to take too much memory
* as it might hurt the throughput of active STAs.
- * The number of blocks (18) is enough for 2 large packets.
*/
-#define WL1271_PS_STA_MAX_BLOCKS (2 * 9)
+#define WL1271_PS_STA_MAX_PACKETS 2
#define WL1271_AP_BSS_INDEX 0
#define WL1271_AP_DEF_BEACON_EXP 20
-#define ACX_TX_DESCRIPTORS 32
+#define ACX_TX_DESCRIPTORS 16
#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
@@ -247,26 +236,22 @@ struct wl1271_stats {
#define AP_MAX_STATIONS 5
-/* Broadcast and Global links + links to stations */
-#define AP_MAX_LINKS (AP_MAX_STATIONS + 2)
+/* 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)
-/* FW status registers common for AP/STA */
-struct wl1271_fw_common_status {
+/* FW status registers */
+struct wl12xx_fw_status {
__le32 intr;
u8 fw_rx_counter;
u8 drv_rx_counter;
u8 reserved;
u8 tx_results_counter;
__le32 rx_pkt_descs[NUM_RX_PKT_DESC];
- __le32 tx_released_blks[NUM_TX_QUEUES];
__le32 fw_localtime;
-} __packed;
-
-/* FW status registers for AP */
-struct wl1271_fw_ap_status {
- struct wl1271_fw_common_status common;
-
- /* Next fields valid only in AP FW */
/*
* A bitmap (where each bit represents a single HLID)
@@ -274,29 +259,29 @@ struct wl1271_fw_ap_status {
*/
__le32 link_ps_bitmap;
- /* Number of freed MBs per HLID */
- u8 tx_lnk_free_blks[AP_MAX_LINKS];
- u8 padding_1[1];
-} __packed;
+ /*
+ * A bitmap (where each bit represents a single HLID) to indicate
+ * if the station is in Fast mode
+ */
+ __le32 link_fast_bitmap;
-/* FW status registers for STA */
-struct wl1271_fw_sta_status {
- struct wl1271_fw_common_status common;
+ /* Cumulative counter of total released mem blocks since FW-reset */
+ __le32 total_released_blks;
- u8 tx_total;
- u8 reserved1;
- __le16 reserved2;
- __le32 log_start_addr;
-} __packed;
+ /* Size (in Memory Blocks) of TX pool */
+ __le32 tx_total;
-struct wl1271_fw_full_status {
- union {
- struct wl1271_fw_common_status common;
- struct wl1271_fw_sta_status sta;
- struct wl1271_fw_ap_status ap;
- };
-} __packed;
+ /* Cumulative counter of released packets per AC */
+ u8 tx_released_pkts[NUM_TX_QUEUES];
+
+ /* Cumulative counter of freed packets per HLID */
+ u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS];
+ /* Cumulative counter of released Voice memory blocks */
+ u8 tx_voice_released_blks;
+ u8 padding_1[7];
+ __le32 log_start_addr;
+} __packed;
struct wl1271_rx_mem_pool_addr {
u32 addr;
@@ -342,7 +327,7 @@ struct wl1271_ap_key {
enum wl12xx_flags {
WL1271_FLAG_STA_ASSOCIATED,
- WL1271_FLAG_JOINED,
+ WL1271_FLAG_IBSS_JOINED,
WL1271_FLAG_GPIO_POWER,
WL1271_FLAG_TX_QUEUE_STOPPED,
WL1271_FLAG_TX_PENDING,
@@ -369,11 +354,14 @@ struct wl1271_link {
/* AP-mode - TX queue per AC in link */
struct sk_buff_head tx_queue[NUM_TX_QUEUES];
- /* accounting for allocated / available TX blocks in FW */
- u8 allocated_blks;
- u8 prev_freed_blks;
+ /* accounting for allocated / freed packets in FW */
+ u8 allocated_pkts;
+ u8 prev_freed_pkts;
u8 addr[ETH_ALEN];
+
+ /* bitmap of TIDs where RX BA sessions are active for this link */
+ u8 ba_bitmap;
};
struct wl1271 {
@@ -405,7 +393,6 @@ struct wl1271 {
u8 *fw;
size_t fw_len;
- u8 fw_bss_type;
void *nvs;
size_t nvs_len;
@@ -418,15 +405,30 @@ struct wl1271 {
u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
u8 ssid_len;
int channel;
+ u8 role_id;
+ u8 dev_role_id;
+ u8 system_hlid;
+ u8 sta_hlid;
+ u8 dev_hlid;
+ u8 ap_global_hlid;
+ u8 ap_bcast_hlid;
+
+ unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
+ unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
+ unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
struct wl1271_acx_mem_map *target_mem_map;
/* Accounting for allocated / available TX blocks on HW */
- u32 tx_blocks_freed[NUM_TX_QUEUES];
+ u32 tx_blocks_freed;
u32 tx_blocks_available;
- u32 tx_allocated_blocks[NUM_TX_QUEUES];
+ u32 tx_allocated_blocks;
u32 tx_results_count;
+ /* Accounting for allocated / available Tx packets in HW */
+ u32 tx_pkts_freed[NUM_TX_QUEUES];
+ u32 tx_allocated_pkts[NUM_TX_QUEUES];
+
/* Transmitted TX packets counter for chipset interface */
u32 tx_packets_count;
@@ -535,10 +537,6 @@ struct wl1271 {
struct work_struct rx_streaming_disable_work;
struct timer_list rx_streaming_timer;
- unsigned int filters;
- unsigned int rx_config;
- unsigned int rx_filter;
-
struct completion *elp_compl;
struct completion *ps_compl;
struct delayed_work elp_work;
@@ -562,7 +560,7 @@ struct wl1271 {
u32 buffer_cmd;
u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
- struct wl1271_fw_full_status *fw_status;
+ struct wl12xx_fw_status *fw_status;
struct wl1271_tx_hw_res_if *tx_res_if;
struct ieee80211_vif *vif;
@@ -622,6 +620,9 @@ struct wl1271 {
/* Platform limitations */
unsigned int platform_quirks;
+
+ /* number of currently active RX BA sessions */
+ int ba_rx_session_count;
};
struct wl1271_station {
@@ -659,12 +660,6 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
/* Each RX/TX transaction requires an end-of-transaction transfer */
#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0)
-/*
- * Older firmwares use 2 spare TX blocks
- * (for STA < 6.1.3.50.58 or for AP < 6.2.0.0.47)
- */
-#define WL12XX_QUIRK_USE_2_SPARE_BLOCKS BIT(1)
-
/* WL128X requires aggregated packets to be aligned to the SDIO block size */
#define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2)
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h
index f334ea08172..f7971d3b089 100644
--- a/drivers/net/wireless/wl12xx/wl12xx_80211.h
+++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h
@@ -105,18 +105,6 @@ struct wl12xx_ie_country {
/* Templates */
-struct wl12xx_beacon_template {
- struct ieee80211_header header;
- __le32 time_stamp[2];
- __le16 beacon_interval;
- __le16 capability;
- struct wl12xx_ie_ssid ssid;
- struct wl12xx_ie_rates rates;
- struct wl12xx_ie_rates ext_rates;
- struct wl12xx_ie_ds_params ds_params;
- struct wl12xx_ie_country country;
-} __packed;
-
struct wl12xx_null_data_template {
struct ieee80211_header header;
} __packed;
@@ -146,19 +134,6 @@ struct wl12xx_arp_rsp_template {
__be32 target_ip;
} __packed;
-
-struct wl12xx_probe_resp_template {
- struct ieee80211_header header;
- __le32 time_stamp[2];
- __le16 beacon_interval;
- __le16 capability;
- struct wl12xx_ie_ssid ssid;
- struct wl12xx_ie_rates rates;
- struct wl12xx_ie_rates ext_rates;
- struct wl12xx_ie_ds_params ds_params;
- struct wl12xx_ie_country country;
-} __packed;
-
struct wl12xx_disconn_template {
struct ieee80211_header header;
__le16 disconn_reason;