Merge branch 'wl12xx-next' into for-linville
This commit is contained in:
commit
f589cf4f2c
|
@ -42,16 +42,6 @@ config WL12XX_SDIO
|
|||
If you choose to build a module, it'll be called wl12xx_sdio.
|
||||
Say N if unsure.
|
||||
|
||||
config WL12XX_SDIO_TEST
|
||||
tristate "TI wl12xx SDIO testing support"
|
||||
depends on WL12XX && MMC && WL12XX_SDIO
|
||||
default n
|
||||
---help---
|
||||
This module adds support for the SDIO bus testing with the
|
||||
TI wl12xx chipsets. You probably don't want this unless you are
|
||||
testing a new hardware platform. Select this if you want to test the
|
||||
SDIO bus which is connected to the wl12xx chip.
|
||||
|
||||
config WL12XX_PLATFORM_DATA
|
||||
bool
|
||||
depends on WL12XX_SDIO != n || WL1251_SDIO != n
|
||||
|
|
|
@ -3,14 +3,11 @@ wl12xx-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \
|
|||
|
||||
wl12xx_spi-objs = spi.o
|
||||
wl12xx_sdio-objs = sdio.o
|
||||
wl12xx_sdio_test-objs = sdio_test.o
|
||||
|
||||
wl12xx-$(CONFIG_NL80211_TESTMODE) += testmode.o
|
||||
obj-$(CONFIG_WL12XX) += wl12xx.o
|
||||
obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o
|
||||
obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o
|
||||
|
||||
obj-$(CONFIG_WL12XX_SDIO_TEST) += wl12xx_sdio_test.o
|
||||
|
||||
# small builtin driver bit
|
||||
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o
|
||||
|
|
|
@ -29,11 +29,12 @@
|
|||
#include <linux/slab.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "wl12xx_80211.h"
|
||||
#include "reg.h"
|
||||
#include "ps.h"
|
||||
|
||||
int wl1271_acx_wake_up_conditions(struct wl1271 *wl)
|
||||
int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct acx_wake_up_condition *wake_up;
|
||||
int ret;
|
||||
|
@ -46,7 +47,7 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl)
|
|||
goto out;
|
||||
}
|
||||
|
||||
wake_up->role_id = wl->role_id;
|
||||
wake_up->role_id = wlvif->role_id;
|
||||
wake_up->wake_up_event = wl->conf.conn.wake_up_event;
|
||||
wake_up->listen_interval = wl->conf.conn.listen_interval;
|
||||
|
||||
|
@ -84,7 +85,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_tx_power(struct wl1271 *wl, int power)
|
||||
int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
int power)
|
||||
{
|
||||
struct acx_current_tx_power *acx;
|
||||
int ret;
|
||||
|
@ -100,7 +102,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power)
|
|||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->current_tx_power = power * 10;
|
||||
|
||||
ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
|
||||
|
@ -114,7 +116,7 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_feature_cfg(struct wl1271 *wl)
|
||||
int wl1271_acx_feature_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct acx_feature_config *feature;
|
||||
int ret;
|
||||
|
@ -128,7 +130,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->role_id = wlvif->role_id;
|
||||
feature->data_flow_options = 0;
|
||||
feature->options = 0;
|
||||
|
||||
|
@ -210,7 +212,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time)
|
||||
int wl1271_acx_slot(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum acx_slot_type slot_time)
|
||||
{
|
||||
struct acx_slot *slot;
|
||||
int ret;
|
||||
|
@ -223,7 +226,7 @@ int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time)
|
|||
goto out;
|
||||
}
|
||||
|
||||
slot->role_id = wl->role_id;
|
||||
slot->role_id = wlvif->role_id;
|
||||
slot->wone_index = STATION_WONE_INDEX;
|
||||
slot->slot_time = slot_time;
|
||||
|
||||
|
@ -238,8 +241,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
|
||||
void *mc_list, u32 mc_list_len)
|
||||
int wl1271_acx_group_address_tbl(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable, void *mc_list, u32 mc_list_len)
|
||||
{
|
||||
struct acx_dot11_grp_addr_tbl *acx;
|
||||
int ret;
|
||||
|
@ -253,7 +256,7 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
|
|||
}
|
||||
|
||||
/* MAC filtering */
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->enabled = enable;
|
||||
acx->num_groups = mc_list_len;
|
||||
memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN);
|
||||
|
@ -270,7 +273,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_service_period_timeout(struct wl1271 *wl)
|
||||
int wl1271_acx_service_period_timeout(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct acx_rx_timeout *rx_timeout;
|
||||
int ret;
|
||||
|
@ -283,7 +287,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->role_id = wlvif->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);
|
||||
|
||||
|
@ -300,7 +304,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold)
|
||||
int wl1271_acx_rts_threshold(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u32 rts_threshold)
|
||||
{
|
||||
struct acx_rts_threshold *rts;
|
||||
int ret;
|
||||
|
@ -320,7 +325,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold)
|
|||
goto out;
|
||||
}
|
||||
|
||||
rts->role_id = wl->role_id;
|
||||
rts->role_id = wlvif->role_id;
|
||||
rts->threshold = cpu_to_le16((u16)rts_threshold);
|
||||
|
||||
ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
|
||||
|
@ -363,7 +368,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter)
|
||||
int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable_filter)
|
||||
{
|
||||
struct acx_beacon_filter_option *beacon_filter = NULL;
|
||||
int ret = 0;
|
||||
|
@ -380,7 +386,7 @@ int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter)
|
|||
goto out;
|
||||
}
|
||||
|
||||
beacon_filter->role_id = wl->role_id;
|
||||
beacon_filter->role_id = wlvif->role_id;
|
||||
beacon_filter->enable = enable_filter;
|
||||
|
||||
/*
|
||||
|
@ -401,7 +407,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_beacon_filter_table(struct wl1271 *wl)
|
||||
int wl1271_acx_beacon_filter_table(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct acx_beacon_filter_ie_table *ie_table;
|
||||
int i, idx = 0;
|
||||
|
@ -417,7 +424,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->role_id = wlvif->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]);
|
||||
|
@ -458,7 +465,8 @@ out:
|
|||
|
||||
#define ACX_CONN_MONIT_DISABLE_VALUE 0xffffffff
|
||||
|
||||
int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable)
|
||||
int wl1271_acx_conn_monit_params(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable)
|
||||
{
|
||||
struct acx_conn_monit_params *acx;
|
||||
u32 threshold = ACX_CONN_MONIT_DISABLE_VALUE;
|
||||
|
@ -479,7 +487,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->role_id = wlvif->role_id;
|
||||
acx->synch_fail_thold = cpu_to_le32(threshold);
|
||||
acx->bss_lose_timeout = cpu_to_le32(timeout);
|
||||
|
||||
|
@ -582,7 +590,7 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_bcn_dtim_options(struct wl1271 *wl)
|
||||
int wl1271_acx_bcn_dtim_options(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct acx_beacon_broadcast *bb;
|
||||
int ret;
|
||||
|
@ -595,7 +603,7 @@ int wl1271_acx_bcn_dtim_options(struct wl1271 *wl)
|
|||
goto out;
|
||||
}
|
||||
|
||||
bb->role_id = wl->role_id;
|
||||
bb->role_id = wlvif->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;
|
||||
|
@ -612,7 +620,7 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_aid(struct wl1271 *wl, u16 aid)
|
||||
int wl1271_acx_aid(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 aid)
|
||||
{
|
||||
struct acx_aid *acx_aid;
|
||||
int ret;
|
||||
|
@ -625,7 +633,7 @@ int wl1271_acx_aid(struct wl1271 *wl, u16 aid)
|
|||
goto out;
|
||||
}
|
||||
|
||||
acx_aid->role_id = wl->role_id;
|
||||
acx_aid->role_id = wlvif->role_id;
|
||||
acx_aid->aid = cpu_to_le16(aid);
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid));
|
||||
|
@ -668,7 +676,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble)
|
||||
int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum acx_preamble_type preamble)
|
||||
{
|
||||
struct acx_preamble *acx;
|
||||
int ret;
|
||||
|
@ -681,7 +690,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble)
|
|||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->preamble = preamble;
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx));
|
||||
|
@ -695,7 +704,7 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_cts_protect(struct wl1271 *wl,
|
||||
int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum acx_ctsprotect_type ctsprotect)
|
||||
{
|
||||
struct acx_ctsprotect *acx;
|
||||
|
@ -709,7 +718,7 @@ int wl1271_acx_cts_protect(struct wl1271 *wl,
|
|||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->ctsprotect = ctsprotect;
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx));
|
||||
|
@ -739,7 +748,7 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
|
||||
int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct acx_rate_policy *acx;
|
||||
struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf;
|
||||
|
@ -755,11 +764,11 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
|
|||
}
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x",
|
||||
wl->basic_rate, wl->rate_set);
|
||||
wlvif->basic_rate, wlvif->rate_set);
|
||||
|
||||
/* configure one basic rate class */
|
||||
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_idx = cpu_to_le32(wlvif->sta.basic_rate_idx);
|
||||
acx->rate_policy.enabled_rates = cpu_to_le32(wlvif->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;
|
||||
|
@ -771,8 +780,8 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
|
|||
}
|
||||
|
||||
/* configure one AP supported rate class */
|
||||
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_idx = cpu_to_le32(wlvif->sta.ap_rate_idx);
|
||||
acx->rate_policy.enabled_rates = cpu_to_le32(wlvif->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;
|
||||
|
@ -788,7 +797,7 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
|
|||
* (p2p packets should always go out with OFDM rates, even
|
||||
* if we are currently connected to 11b AP)
|
||||
*/
|
||||
acx->rate_policy_idx = cpu_to_le32(ACX_TX_BASIC_RATE_P2P);
|
||||
acx->rate_policy_idx = cpu_to_le32(wlvif->sta.p2p_rate_idx);
|
||||
acx->rate_policy.enabled_rates =
|
||||
cpu_to_le32(CONF_TX_RATE_MASK_BASIC_P2P);
|
||||
acx->rate_policy.short_retry_limit = c->short_retry_limit;
|
||||
|
@ -839,8 +848,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
|
||||
u8 aifsn, u16 txop)
|
||||
int wl1271_acx_ac_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop)
|
||||
{
|
||||
struct acx_ac_cfg *acx;
|
||||
int ret = 0;
|
||||
|
@ -855,7 +864,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->role_id = wlvif->role_id;
|
||||
acx->ac = ac;
|
||||
acx->cw_min = cw_min;
|
||||
acx->cw_max = cpu_to_le16(cw_max);
|
||||
|
@ -873,7 +882,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
|
||||
int wl1271_acx_tid_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 queue_id, u8 channel_type,
|
||||
u8 tsid, u8 ps_scheme, u8 ack_policy,
|
||||
u32 apsd_conf0, u32 apsd_conf1)
|
||||
{
|
||||
|
@ -889,7 +899,7 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
|
|||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->queue_id = queue_id;
|
||||
acx->channel_type = channel_type;
|
||||
acx->tsid = tsid;
|
||||
|
@ -1098,7 +1108,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable)
|
||||
int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable)
|
||||
{
|
||||
struct wl1271_acx_bet_enable *acx = NULL;
|
||||
int ret = 0;
|
||||
|
@ -1114,7 +1125,7 @@ int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable)
|
|||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE;
|
||||
acx->max_consecutive = wl->conf.conn.bet_max_consecutive;
|
||||
|
||||
|
@ -1129,7 +1140,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address)
|
||||
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 enable, __be32 address)
|
||||
{
|
||||
struct wl1271_acx_arp_filter *acx;
|
||||
int ret;
|
||||
|
@ -1142,7 +1154,7 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address)
|
|||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->version = ACX_IPV4_VERSION;
|
||||
acx->enable = enable;
|
||||
|
||||
|
@ -1189,7 +1201,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable)
|
||||
int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable)
|
||||
{
|
||||
struct wl1271_acx_keep_alive_mode *acx = NULL;
|
||||
int ret = 0;
|
||||
|
@ -1202,7 +1215,7 @@ int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable)
|
|||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->enabled = enable;
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx));
|
||||
|
@ -1216,7 +1229,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid)
|
||||
int wl1271_acx_keep_alive_config(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 index, u8 tpl_valid)
|
||||
{
|
||||
struct wl1271_acx_keep_alive_config *acx = NULL;
|
||||
int ret = 0;
|
||||
|
@ -1229,7 +1243,7 @@ int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid)
|
|||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval);
|
||||
acx->index = index;
|
||||
acx->tpl_validation = tpl_valid;
|
||||
|
@ -1247,8 +1261,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
|
||||
s16 thold, u8 hyst)
|
||||
int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable, s16 thold, u8 hyst)
|
||||
{
|
||||
struct wl1271_acx_rssi_snr_trigger *acx = NULL;
|
||||
int ret = 0;
|
||||
|
@ -1261,9 +1275,9 @@ int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
|
|||
goto out;
|
||||
}
|
||||
|
||||
wl->last_rssi_event = -1;
|
||||
wlvif->last_rssi_event = -1;
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->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;
|
||||
|
@ -1288,7 +1302,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl)
|
||||
int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl1271_acx_rssi_snr_avg_weights *acx = NULL;
|
||||
struct conf_roam_trigger_settings *c = &wl->conf.roam_trigger;
|
||||
|
@ -1302,7 +1317,7 @@ int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl)
|
|||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->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;
|
||||
|
@ -1367,6 +1382,7 @@ out:
|
|||
}
|
||||
|
||||
int wl1271_acx_set_ht_information(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
u16 ht_operation_mode)
|
||||
{
|
||||
struct wl1271_acx_ht_information *acx;
|
||||
|
@ -1380,7 +1396,7 @@ int wl1271_acx_set_ht_information(struct wl1271 *wl,
|
|||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->ht_protection =
|
||||
(u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION);
|
||||
acx->rifs_mode = 0;
|
||||
|
@ -1402,7 +1418,8 @@ out:
|
|||
}
|
||||
|
||||
/* Configure BA session initiator/receiver parameters setting in the FW. */
|
||||
int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl)
|
||||
int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl1271_acx_ba_initiator_policy *acx;
|
||||
int ret;
|
||||
|
@ -1416,7 +1433,7 @@ int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl)
|
|||
}
|
||||
|
||||
/* set for the current role */
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->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;
|
||||
|
@ -1494,7 +1511,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable)
|
||||
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable)
|
||||
{
|
||||
struct wl1271_acx_ps_rx_streaming *rx_streaming;
|
||||
u32 conf_queues, enable_queues;
|
||||
|
@ -1523,7 +1541,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->role_id = wlvif->role_id;
|
||||
rx_streaming->tid = i;
|
||||
rx_streaming->enable = enable_queues & BIT(i);
|
||||
rx_streaming->period = wl->conf.rx_streaming.interval;
|
||||
|
@ -1542,7 +1560,7 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
|
||||
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl1271_acx_ap_max_tx_retry *acx = NULL;
|
||||
int ret;
|
||||
|
@ -1553,7 +1571,7 @@ int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
|
|||
if (!acx)
|
||||
return -ENOMEM;
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->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));
|
||||
|
@ -1567,7 +1585,7 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_config_ps(struct wl1271 *wl)
|
||||
int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl1271_acx_config_ps *config_ps;
|
||||
int ret;
|
||||
|
@ -1582,7 +1600,7 @@ int wl1271_acx_config_ps(struct wl1271 *wl)
|
|||
|
||||
config_ps->exit_retries = wl->conf.conn.psm_exit_retries;
|
||||
config_ps->enter_retries = wl->conf.conn.psm_entry_retries;
|
||||
config_ps->null_data_rate = cpu_to_le32(wl->basic_rate);
|
||||
config_ps->null_data_rate = cpu_to_le32(wlvif->basic_rate);
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_CONFIG_PS, config_ps,
|
||||
sizeof(*config_ps));
|
||||
|
|
|
@ -654,11 +654,6 @@ struct acx_rate_class {
|
|||
u8 reserved;
|
||||
};
|
||||
|
||||
#define ACX_TX_BASIC_RATE 0
|
||||
#define ACX_TX_AP_FULL_RATE 1
|
||||
#define ACX_TX_BASIC_RATE_P2P 2
|
||||
#define ACX_TX_AP_MODE_MGMT_RATE 4
|
||||
#define ACX_TX_AP_MODE_BCST_RATE 5
|
||||
struct acx_rate_policy {
|
||||
struct acx_header header;
|
||||
|
||||
|
@ -1234,39 +1229,49 @@ enum {
|
|||
};
|
||||
|
||||
|
||||
int wl1271_acx_wake_up_conditions(struct wl1271 *wl);
|
||||
int wl1271_acx_wake_up_conditions(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth);
|
||||
int wl1271_acx_tx_power(struct wl1271 *wl, int power);
|
||||
int wl1271_acx_feature_cfg(struct wl1271 *wl);
|
||||
int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
int power);
|
||||
int wl1271_acx_feature_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
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_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,
|
||||
void *mc_list, u32 mc_list_len);
|
||||
int wl1271_acx_service_period_timeout(struct wl1271 *wl);
|
||||
int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold);
|
||||
int wl1271_acx_slot(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum acx_slot_type slot_time);
|
||||
int wl1271_acx_group_address_tbl(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable, void *mc_list, u32 mc_list_len);
|
||||
int wl1271_acx_service_period_timeout(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_rts_threshold(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u32 rts_threshold);
|
||||
int wl1271_acx_dco_itrim_params(struct wl1271 *wl);
|
||||
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_beacon_filter_opt(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable_filter);
|
||||
int wl1271_acx_beacon_filter_table(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_conn_monit_params(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable);
|
||||
int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable);
|
||||
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);
|
||||
int wl1271_acx_bcn_dtim_options(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_aid(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 aid);
|
||||
int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask);
|
||||
int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble);
|
||||
int wl1271_acx_cts_protect(struct wl1271 *wl,
|
||||
int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum acx_preamble_type preamble);
|
||||
int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum acx_ctsprotect_type ctsprotect);
|
||||
int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
|
||||
int wl1271_acx_sta_rate_policies(struct wl1271 *wl);
|
||||
int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
|
||||
u8 idx);
|
||||
int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
|
||||
u8 aifsn, u16 txop);
|
||||
int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
|
||||
int wl1271_acx_ac_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop);
|
||||
int wl1271_acx_tid_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 queue_id, u8 channel_type,
|
||||
u8 tsid, u8 ps_scheme, u8 ack_policy,
|
||||
u32 apsd_conf0, u32 apsd_conf1);
|
||||
int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold);
|
||||
|
@ -1276,26 +1281,34 @@ 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);
|
||||
int wl1271_acx_smart_reflex(struct wl1271 *wl);
|
||||
int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
|
||||
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address);
|
||||
int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable);
|
||||
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 enable, __be32 address);
|
||||
int wl1271_acx_pm_config(struct wl1271 *wl);
|
||||
int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable);
|
||||
int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid);
|
||||
int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
|
||||
s16 thold, u8 hyst);
|
||||
int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl);
|
||||
int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *vif,
|
||||
bool enable);
|
||||
int wl1271_acx_keep_alive_config(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 index, u8 tpl_valid);
|
||||
int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable, s16 thold, u8 hyst);
|
||||
int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
|
||||
struct ieee80211_sta_ht_cap *ht_cap,
|
||||
bool allow_ht_operation, u8 hlid);
|
||||
int wl1271_acx_set_ht_information(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
u16 ht_operation_mode);
|
||||
int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl);
|
||||
int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif);
|
||||
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_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable);
|
||||
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
|
||||
int wl1271_acx_fm_coex(struct wl1271 *wl);
|
||||
int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/wl12xx.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "acx.h"
|
||||
#include "reg.h"
|
||||
#include "boot.h"
|
||||
|
@ -347,6 +348,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
|
|||
nvs_ptr += 3;
|
||||
|
||||
for (i = 0; i < burst_len; i++) {
|
||||
if (nvs_ptr + 3 >= (u8 *) wl->nvs + nvs_len)
|
||||
goto out_badnvs;
|
||||
|
||||
val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
|
||||
| (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
|
||||
|
||||
|
@ -358,6 +362,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
|
|||
nvs_ptr += 4;
|
||||
dest_addr += 4;
|
||||
}
|
||||
|
||||
if (nvs_ptr >= (u8 *) wl->nvs + nvs_len)
|
||||
goto out_badnvs;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -369,6 +376,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
|
|||
*/
|
||||
nvs_ptr = (u8 *)wl->nvs +
|
||||
ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4);
|
||||
|
||||
if (nvs_ptr >= (u8 *) wl->nvs + nvs_len)
|
||||
goto out_badnvs;
|
||||
|
||||
nvs_len -= nvs_ptr - (u8 *)wl->nvs;
|
||||
|
||||
/* Now we must set the partition correctly */
|
||||
|
@ -384,6 +395,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
|
|||
|
||||
kfree(nvs_aligned);
|
||||
return 0;
|
||||
|
||||
out_badnvs:
|
||||
wl1271_error("nvs data is malformed");
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <linux/slab.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "reg.h"
|
||||
#include "io.h"
|
||||
#include "acx.h"
|
||||
|
@ -120,6 +121,11 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
|
|||
if (!wl->nvs)
|
||||
return -ENODEV;
|
||||
|
||||
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
|
||||
wl1271_warning("FEM index from INI out of bounds");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
|
||||
if (!gen_parms)
|
||||
return -ENOMEM;
|
||||
|
@ -143,6 +149,12 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
|
|||
gp->tx_bip_fem_manufacturer =
|
||||
gen_parms->general_params.tx_bip_fem_manufacturer;
|
||||
|
||||
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
|
||||
wl1271_warning("FEM index from FW out of bounds");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
|
||||
answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
|
||||
|
||||
|
@ -162,6 +174,11 @@ int wl128x_cmd_general_parms(struct wl1271 *wl)
|
|||
if (!wl->nvs)
|
||||
return -ENODEV;
|
||||
|
||||
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
|
||||
wl1271_warning("FEM index from ini out of bounds");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
|
||||
if (!gen_parms)
|
||||
return -ENOMEM;
|
||||
|
@ -186,6 +203,12 @@ int wl128x_cmd_general_parms(struct wl1271 *wl)
|
|||
gp->tx_bip_fem_manufacturer =
|
||||
gen_parms->general_params.tx_bip_fem_manufacturer;
|
||||
|
||||
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
|
||||
wl1271_warning("FEM index from FW out of bounds");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
|
||||
answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
|
||||
|
||||
|
@ -358,7 +381,8 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id)
|
||||
int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type,
|
||||
u8 *role_id)
|
||||
{
|
||||
struct wl12xx_cmd_role_enable *cmd;
|
||||
int ret;
|
||||
|
@ -381,7 +405,7 @@ int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id)
|
|||
goto out_free;
|
||||
}
|
||||
|
||||
memcpy(cmd->mac_address, wl->mac_addr, ETH_ALEN);
|
||||
memcpy(cmd->mac_address, addr, ETH_ALEN);
|
||||
cmd->role_type = role_type;
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_ROLE_ENABLE, cmd, sizeof(*cmd), 0);
|
||||
|
@ -433,37 +457,41 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int wl12xx_allocate_link(struct wl1271 *wl, u8 *hlid)
|
||||
int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, 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);
|
||||
__set_bit(link, wlvif->links_map);
|
||||
*hlid = link;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wl12xx_free_link(struct wl1271 *wl, u8 *hlid)
|
||||
void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
|
||||
{
|
||||
if (*hlid == WL12XX_INVALID_LINK_ID)
|
||||
return;
|
||||
|
||||
__clear_bit(*hlid, wl->links_map);
|
||||
__clear_bit(*hlid, wlvif->links_map);
|
||||
*hlid = WL12XX_INVALID_LINK_ID;
|
||||
}
|
||||
|
||||
static int wl12xx_get_new_session_id(struct wl1271 *wl)
|
||||
static int wl12xx_get_new_session_id(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
if (wl->session_counter >= SESSION_COUNTER_MAX)
|
||||
wl->session_counter = 0;
|
||||
if (wlvif->session_counter >= SESSION_COUNTER_MAX)
|
||||
wlvif->session_counter = 0;
|
||||
|
||||
wl->session_counter++;
|
||||
wlvif->session_counter++;
|
||||
|
||||
return wl->session_counter;
|
||||
return wlvif->session_counter;
|
||||
}
|
||||
|
||||
int wl12xx_cmd_role_start_dev(struct wl1271 *wl)
|
||||
static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl12xx_cmd_role_start *cmd;
|
||||
int ret;
|
||||
|
@ -474,20 +502,20 @@ int wl12xx_cmd_role_start_dev(struct wl1271 *wl)
|
|||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wl->dev_role_id);
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wlvif->dev_role_id);
|
||||
|
||||
cmd->role_id = wl->dev_role_id;
|
||||
if (wl->band == IEEE80211_BAND_5GHZ)
|
||||
cmd->role_id = wlvif->dev_role_id;
|
||||
if (wlvif->band == IEEE80211_BAND_5GHZ)
|
||||
cmd->band = WL12XX_BAND_5GHZ;
|
||||
cmd->channel = wl->channel;
|
||||
cmd->channel = wlvif->channel;
|
||||
|
||||
if (wl->dev_hlid == WL12XX_INVALID_LINK_ID) {
|
||||
ret = wl12xx_allocate_link(wl, &wl->dev_hlid);
|
||||
if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) {
|
||||
ret = wl12xx_allocate_link(wl, wlvif, &wlvif->dev_hlid);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
}
|
||||
cmd->device.hlid = wl->dev_hlid;
|
||||
cmd->device.session = wl->session_counter;
|
||||
cmd->device.hlid = wlvif->dev_hlid;
|
||||
cmd->device.session = wlvif->session_counter;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d",
|
||||
cmd->role_id, cmd->device.hlid, cmd->device.session);
|
||||
|
@ -502,9 +530,7 @@ int wl12xx_cmd_role_start_dev(struct wl1271 *wl)
|
|||
|
||||
err_hlid:
|
||||
/* clear links on error */
|
||||
__clear_bit(wl->dev_hlid, wl->links_map);
|
||||
wl->dev_hlid = WL12XX_INVALID_LINK_ID;
|
||||
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid);
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
|
@ -513,12 +539,13 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl12xx_cmd_role_stop_dev(struct wl1271 *wl)
|
||||
static int wl12xx_cmd_role_stop_dev(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl12xx_cmd_role_stop *cmd;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(wl->dev_hlid == WL12XX_INVALID_LINK_ID))
|
||||
if (WARN_ON(wlvif->dev_hlid == WL12XX_INVALID_LINK_ID))
|
||||
return -EINVAL;
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
|
@ -529,7 +556,7 @@ int wl12xx_cmd_role_stop_dev(struct wl1271 *wl)
|
|||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role stop dev");
|
||||
|
||||
cmd->role_id = wl->dev_role_id;
|
||||
cmd->role_id = wlvif->dev_role_id;
|
||||
cmd->disc_type = DISCONNECT_IMMEDIATE;
|
||||
cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED);
|
||||
|
||||
|
@ -545,7 +572,7 @@ int wl12xx_cmd_role_stop_dev(struct wl1271 *wl)
|
|||
goto out_free;
|
||||
}
|
||||
|
||||
wl12xx_free_link(wl, &wl->dev_hlid);
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid);
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
|
@ -554,8 +581,9 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl12xx_cmd_role_start_sta(struct wl1271 *wl)
|
||||
int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct wl12xx_cmd_role_start *cmd;
|
||||
int ret;
|
||||
|
||||
|
@ -565,33 +593,33 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl)
|
|||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wl->role_id);
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wlvif->role_id);
|
||||
|
||||
cmd->role_id = wl->role_id;
|
||||
if (wl->band == IEEE80211_BAND_5GHZ)
|
||||
cmd->role_id = wlvif->role_id;
|
||||
if (wlvif->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->channel = wlvif->channel;
|
||||
cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
|
||||
cmd->sta.beacon_interval = cpu_to_le16(wlvif->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);
|
||||
cmd->sta.ssid_len = wlvif->ssid_len;
|
||||
memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len);
|
||||
memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN);
|
||||
cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set);
|
||||
|
||||
if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) {
|
||||
ret = wl12xx_allocate_link(wl, &wl->sta_hlid);
|
||||
if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) {
|
||||
ret = wl12xx_allocate_link(wl, wlvif, &wlvif->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);
|
||||
cmd->sta.hlid = wlvif->sta.hlid;
|
||||
cmd->sta.session = wl12xx_get_new_session_id(wl, wlvif);
|
||||
cmd->sta.remote_rates = cpu_to_le32(wlvif->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);
|
||||
wlvif->role_id, cmd->sta.hlid, cmd->sta.session,
|
||||
wlvif->basic_rate_set, wlvif->rate_set);
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
|
||||
if (ret < 0) {
|
||||
|
@ -603,7 +631,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl)
|
|||
|
||||
err_hlid:
|
||||
/* clear links on error. */
|
||||
wl12xx_free_link(wl, &wl->sta_hlid);
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid);
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
|
@ -613,12 +641,12 @@ out:
|
|||
}
|
||||
|
||||
/* use this function to stop ibss as well */
|
||||
int wl12xx_cmd_role_stop_sta(struct wl1271 *wl)
|
||||
int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl12xx_cmd_role_stop *cmd;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(wl->sta_hlid == WL12XX_INVALID_LINK_ID))
|
||||
if (WARN_ON(wlvif->sta.hlid == WL12XX_INVALID_LINK_ID))
|
||||
return -EINVAL;
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
|
@ -627,9 +655,9 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl)
|
|||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role stop sta %d", wl->role_id);
|
||||
wl1271_debug(DEBUG_CMD, "cmd role stop sta %d", wlvif->role_id);
|
||||
|
||||
cmd->role_id = wl->role_id;
|
||||
cmd->role_id = wlvif->role_id;
|
||||
cmd->disc_type = DISCONNECT_IMMEDIATE;
|
||||
cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED);
|
||||
|
||||
|
@ -639,7 +667,7 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl)
|
|||
goto out_free;
|
||||
}
|
||||
|
||||
wl12xx_free_link(wl, &wl->sta_hlid);
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid);
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
|
@ -648,16 +676,17 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
|
||||
int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl12xx_cmd_role_start *cmd;
|
||||
struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wl->role_id);
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id);
|
||||
|
||||
/* trying to use hidden SSID with an old hostapd version */
|
||||
if (wl->ssid_len == 0 && !bss_conf->hidden_ssid) {
|
||||
if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) {
|
||||
wl1271_error("got a null SSID from beacon/bss");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
@ -669,30 +698,30 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
|
|||
goto out;
|
||||
}
|
||||
|
||||
ret = wl12xx_allocate_link(wl, &wl->ap_global_hlid);
|
||||
ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.global_hlid);
|
||||
if (ret < 0)
|
||||
goto out_free;
|
||||
|
||||
ret = wl12xx_allocate_link(wl, &wl->ap_bcast_hlid);
|
||||
ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.bcast_hlid);
|
||||
if (ret < 0)
|
||||
goto out_free_global;
|
||||
|
||||
cmd->role_id = wl->role_id;
|
||||
cmd->role_id = wlvif->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.global_hlid = wlvif->ap.global_hlid;
|
||||
cmd->ap.broadcast_hlid = wlvif->ap.bcast_hlid;
|
||||
cmd->ap.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
|
||||
cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int);
|
||||
cmd->ap.dtim_interval = bss_conf->dtim_period;
|
||||
cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
|
||||
cmd->channel = wl->channel;
|
||||
cmd->channel = wlvif->channel;
|
||||
|
||||
if (!bss_conf->hidden_ssid) {
|
||||
/* take the SSID from the beacon for backward compatibility */
|
||||
cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC;
|
||||
cmd->ap.ssid_len = wl->ssid_len;
|
||||
memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len);
|
||||
cmd->ap.ssid_len = wlvif->ssid_len;
|
||||
memcpy(cmd->ap.ssid, wlvif->ssid, wlvif->ssid_len);
|
||||
} else {
|
||||
cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN;
|
||||
cmd->ap.ssid_len = bss_conf->ssid_len;
|
||||
|
@ -701,7 +730,7 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
|
|||
|
||||
cmd->ap.local_rates = cpu_to_le32(0xffffffff);
|
||||
|
||||
switch (wl->band) {
|
||||
switch (wlvif->band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
cmd->band = RADIO_BAND_2_4GHZ;
|
||||
break;
|
||||
|
@ -709,7 +738,7 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
|
|||
cmd->band = RADIO_BAND_5GHZ;
|
||||
break;
|
||||
default:
|
||||
wl1271_warning("ap start - unknown band: %d", (int)wl->band);
|
||||
wl1271_warning("ap start - unknown band: %d", (int)wlvif->band);
|
||||
cmd->band = RADIO_BAND_2_4GHZ;
|
||||
break;
|
||||
}
|
||||
|
@ -723,10 +752,10 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
|
|||
goto out_free;
|
||||
|
||||
out_free_bcast:
|
||||
wl12xx_free_link(wl, &wl->ap_bcast_hlid);
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid);
|
||||
|
||||
out_free_global:
|
||||
wl12xx_free_link(wl, &wl->ap_global_hlid);
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid);
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
|
@ -735,7 +764,7 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl12xx_cmd_role_stop_ap(struct wl1271 *wl)
|
||||
int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl12xx_cmd_role_stop *cmd;
|
||||
int ret;
|
||||
|
@ -746,9 +775,9 @@ int wl12xx_cmd_role_stop_ap(struct wl1271 *wl)
|
|||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role stop ap %d", wl->role_id);
|
||||
wl1271_debug(DEBUG_CMD, "cmd role stop ap %d", wlvif->role_id);
|
||||
|
||||
cmd->role_id = wl->role_id;
|
||||
cmd->role_id = wlvif->role_id;
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
|
||||
if (ret < 0) {
|
||||
|
@ -756,8 +785,8 @@ int wl12xx_cmd_role_stop_ap(struct wl1271 *wl)
|
|||
goto out_free;
|
||||
}
|
||||
|
||||
wl12xx_free_link(wl, &wl->ap_bcast_hlid);
|
||||
wl12xx_free_link(wl, &wl->ap_global_hlid);
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid);
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid);
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
|
@ -766,10 +795,11 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl12xx_cmd_role_start_ibss(struct wl1271 *wl)
|
||||
int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct wl12xx_cmd_role_start *cmd;
|
||||
struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
int ret;
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
|
@ -778,35 +808,36 @@ int wl12xx_cmd_role_start_ibss(struct wl1271 *wl)
|
|||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wl->role_id);
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wlvif->role_id);
|
||||
|
||||
cmd->role_id = wl->role_id;
|
||||
if (wl->band == IEEE80211_BAND_5GHZ)
|
||||
cmd->role_id = wlvif->role_id;
|
||||
if (wlvif->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->channel = wlvif->channel;
|
||||
cmd->ibss.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
|
||||
cmd->ibss.beacon_interval = cpu_to_le16(wlvif->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);
|
||||
cmd->ibss.ssid_len = wlvif->ssid_len;
|
||||
memcpy(cmd->ibss.ssid, wlvif->ssid, wlvif->ssid_len);
|
||||
memcpy(cmd->ibss.bssid, vif->bss_conf.bssid, ETH_ALEN);
|
||||
cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set);
|
||||
|
||||
if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) {
|
||||
ret = wl12xx_allocate_link(wl, &wl->sta_hlid);
|
||||
if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) {
|
||||
ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
}
|
||||
cmd->ibss.hlid = wl->sta_hlid;
|
||||
cmd->ibss.remote_rates = cpu_to_le32(wl->rate_set);
|
||||
cmd->ibss.hlid = wlvif->sta.hlid;
|
||||
cmd->ibss.remote_rates = cpu_to_le32(wlvif->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);
|
||||
wlvif->role_id, cmd->sta.hlid, cmd->sta.session,
|
||||
wlvif->basic_rate_set, wlvif->rate_set);
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "wl->bssid = %pM", wl->bssid);
|
||||
wl1271_debug(DEBUG_CMD, "vif->bss_conf.bssid = %pM",
|
||||
vif->bss_conf.bssid);
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
|
||||
if (ret < 0) {
|
||||
|
@ -818,7 +849,7 @@ int wl12xx_cmd_role_start_ibss(struct wl1271 *wl)
|
|||
|
||||
err_hlid:
|
||||
/* clear links on error. */
|
||||
wl12xx_free_link(wl, &wl->sta_hlid);
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid);
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
|
@ -962,7 +993,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
|
||||
int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 ps_mode)
|
||||
{
|
||||
struct wl1271_cmd_ps_params *ps_params = NULL;
|
||||
int ret = 0;
|
||||
|
@ -975,7 +1007,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
|
|||
goto out;
|
||||
}
|
||||
|
||||
ps_params->role_id = wl->role_id;
|
||||
ps_params->role_id = wlvif->role_id;
|
||||
ps_params->ps_mode = ps_mode;
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
|
||||
|
@ -1030,7 +1062,7 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_cmd_build_null_data(struct wl1271 *wl)
|
||||
int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct sk_buff *skb = NULL;
|
||||
int size;
|
||||
|
@ -1038,11 +1070,12 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl)
|
|||
int ret = -ENOMEM;
|
||||
|
||||
|
||||
if (wl->bss_type == BSS_TYPE_IBSS) {
|
||||
if (wlvif->bss_type == BSS_TYPE_IBSS) {
|
||||
size = sizeof(struct wl12xx_null_data_template);
|
||||
ptr = NULL;
|
||||
} else {
|
||||
skb = ieee80211_nullfunc_get(wl->hw, wl->vif);
|
||||
skb = ieee80211_nullfunc_get(wl->hw,
|
||||
wl12xx_wlvif_to_vif(wlvif));
|
||||
if (!skb)
|
||||
goto out;
|
||||
size = skb->len;
|
||||
|
@ -1050,7 +1083,7 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl)
|
|||
}
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0,
|
||||
wl->basic_rate);
|
||||
wlvif->basic_rate);
|
||||
|
||||
out:
|
||||
dev_kfree_skb(skb);
|
||||
|
@ -1061,19 +1094,21 @@ out:
|
|||
|
||||
}
|
||||
|
||||
int wl1271_cmd_build_klv_null_data(struct wl1271 *wl)
|
||||
int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct sk_buff *skb = NULL;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
skb = ieee80211_nullfunc_get(wl->hw, wl->vif);
|
||||
skb = ieee80211_nullfunc_get(wl->hw, vif);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV,
|
||||
skb->data, skb->len,
|
||||
CMD_TEMPL_KLV_IDX_NULL_DATA,
|
||||
wl->basic_rate);
|
||||
wlvif->basic_rate);
|
||||
|
||||
out:
|
||||
dev_kfree_skb(skb);
|
||||
|
@ -1084,32 +1119,35 @@ out:
|
|||
|
||||
}
|
||||
|
||||
int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
|
||||
int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u16 aid)
|
||||
{
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct sk_buff *skb;
|
||||
int ret = 0;
|
||||
|
||||
skb = ieee80211_pspoll_get(wl->hw, wl->vif);
|
||||
skb = ieee80211_pspoll_get(wl->hw, vif);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data,
|
||||
skb->len, 0, wl->basic_rate_set);
|
||||
skb->len, 0, wlvif->basic_rate_set);
|
||||
|
||||
out:
|
||||
dev_kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_cmd_build_probe_req(struct wl1271 *wl,
|
||||
int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *ie, size_t ie_len, u8 band)
|
||||
{
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct sk_buff *skb;
|
||||
int ret;
|
||||
u32 rate;
|
||||
|
||||
skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len,
|
||||
skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len,
|
||||
ie, ie_len);
|
||||
if (!skb) {
|
||||
ret = -ENOMEM;
|
||||
|
@ -1118,7 +1156,7 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl,
|
|||
|
||||
wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len);
|
||||
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
|
||||
rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
|
||||
if (band == IEEE80211_BAND_2GHZ)
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
|
||||
skb->data, skb->len, 0, rate);
|
||||
|
@ -1132,20 +1170,22 @@ out:
|
|||
}
|
||||
|
||||
struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
int ret;
|
||||
u32 rate;
|
||||
|
||||
if (!skb)
|
||||
skb = ieee80211_ap_probereq_get(wl->hw, wl->vif);
|
||||
skb = ieee80211_ap_probereq_get(wl->hw, vif);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len);
|
||||
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[wl->band]);
|
||||
if (wl->band == IEEE80211_BAND_2GHZ)
|
||||
rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]);
|
||||
if (wlvif->band == IEEE80211_BAND_2GHZ)
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
|
||||
skb->data, skb->len, 0, rate);
|
||||
else
|
||||
|
@ -1159,9 +1199,11 @@ out:
|
|||
return skb;
|
||||
}
|
||||
|
||||
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr)
|
||||
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
__be32 ip_addr)
|
||||
{
|
||||
int ret;
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct wl12xx_arp_rsp_template tmpl;
|
||||
struct ieee80211_hdr_3addr *hdr;
|
||||
struct arphdr *arp_hdr;
|
||||
|
@ -1173,8 +1215,8 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr)
|
|||
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_DATA |
|
||||
IEEE80211_FCTL_TODS);
|
||||
memcpy(hdr->addr1, wl->vif->bss_conf.bssid, ETH_ALEN);
|
||||
memcpy(hdr->addr2, wl->vif->addr, ETH_ALEN);
|
||||
memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN);
|
||||
memcpy(hdr->addr2, vif->addr, ETH_ALEN);
|
||||
memset(hdr->addr3, 0xff, ETH_ALEN);
|
||||
|
||||
/* llc layer */
|
||||
|
@ -1190,25 +1232,26 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr)
|
|||
arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY);
|
||||
|
||||
/* arp payload */
|
||||
memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN);
|
||||
memcpy(tmpl.sender_hw, vif->addr, ETH_ALEN);
|
||||
tmpl.sender_ip = ip_addr;
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP,
|
||||
&tmpl, sizeof(tmpl), 0,
|
||||
wl->basic_rate);
|
||||
wlvif->basic_rate);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_build_qos_null_data(struct wl1271 *wl)
|
||||
int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
struct ieee80211_qos_hdr template;
|
||||
|
||||
memset(&template, 0, sizeof(template));
|
||||
|
||||
memcpy(template.addr1, wl->bssid, ETH_ALEN);
|
||||
memcpy(template.addr2, wl->mac_addr, ETH_ALEN);
|
||||
memcpy(template.addr3, wl->bssid, ETH_ALEN);
|
||||
memcpy(template.addr1, vif->bss_conf.bssid, ETH_ALEN);
|
||||
memcpy(template.addr2, vif->addr, ETH_ALEN);
|
||||
memcpy(template.addr3, vif->bss_conf.bssid, ETH_ALEN);
|
||||
|
||||
template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_QOS_NULLFUNC |
|
||||
|
@ -1219,7 +1262,7 @@ int wl1271_build_qos_null_data(struct wl1271 *wl)
|
|||
|
||||
return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template,
|
||||
sizeof(template), 0,
|
||||
wl->basic_rate);
|
||||
wlvif->basic_rate);
|
||||
}
|
||||
|
||||
int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid)
|
||||
|
@ -1253,7 +1296,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
||||
int wl1271_cmd_set_sta_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u16 action, u8 id, u8 key_type,
|
||||
u8 key_size, const u8 *key, const u8 *addr,
|
||||
u32 tx_seq_32, u16 tx_seq_16)
|
||||
{
|
||||
|
@ -1261,7 +1305,7 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
|||
int ret = 0;
|
||||
|
||||
/* hlid might have already been deleted */
|
||||
if (wl->sta_hlid == WL12XX_INVALID_LINK_ID)
|
||||
if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
|
||||
return 0;
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
|
@ -1270,7 +1314,7 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
|||
goto out;
|
||||
}
|
||||
|
||||
cmd->hlid = wl->sta_hlid;
|
||||
cmd->hlid = wlvif->sta.hlid;
|
||||
|
||||
if (key_type == KEY_WEP)
|
||||
cmd->lid_key_type = WEP_DEFAULT_LID_TYPE;
|
||||
|
@ -1321,7 +1365,8 @@ out:
|
|||
* 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,
|
||||
int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u16 action, u8 id, u8 key_type,
|
||||
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
|
||||
u16 tx_seq_16)
|
||||
{
|
||||
|
@ -1333,7 +1378,7 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
|||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
if (hlid == wl->ap_bcast_hlid) {
|
||||
if (hlid == wlvif->ap.bcast_hlid) {
|
||||
if (key_type == KEY_WEP)
|
||||
lid_type = WEP_DEFAULT_LID_TYPE;
|
||||
else
|
||||
|
@ -1411,7 +1456,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
|
||||
int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct ieee80211_sta *sta, u8 hlid)
|
||||
{
|
||||
struct wl12xx_cmd_add_peer *cmd;
|
||||
int i, ret;
|
||||
|
@ -1438,13 +1484,13 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
|
|||
else
|
||||
cmd->psd_type[i] = WL1271_PSD_LEGACY;
|
||||
|
||||
sta_rates = sta->supp_rates[wl->band];
|
||||
sta_rates = sta->supp_rates[wlvif->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,
|
||||
wl->band));
|
||||
wlvif->band));
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x",
|
||||
cmd->supported_rates, sta->uapsd_queues);
|
||||
|
@ -1584,12 +1630,13 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int wl12xx_cmd_roc(struct wl1271 *wl, u8 role_id)
|
||||
static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 role_id)
|
||||
{
|
||||
struct wl12xx_cmd_roc *cmd;
|
||||
int ret = 0;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wl->channel, role_id);
|
||||
wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wlvif->channel, role_id);
|
||||
|
||||
if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID))
|
||||
return -EINVAL;
|
||||
|
@ -1601,8 +1648,8 @@ static int wl12xx_cmd_roc(struct wl1271 *wl, u8 role_id)
|
|||
}
|
||||
|
||||
cmd->role_id = role_id;
|
||||
cmd->channel = wl->channel;
|
||||
switch (wl->band) {
|
||||
cmd->channel = wlvif->channel;
|
||||
switch (wlvif->band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
cmd->band = RADIO_BAND_2_4GHZ;
|
||||
break;
|
||||
|
@ -1610,7 +1657,7 @@ static int wl12xx_cmd_roc(struct wl1271 *wl, u8 role_id)
|
|||
cmd->band = RADIO_BAND_5GHZ;
|
||||
break;
|
||||
default:
|
||||
wl1271_error("roc - unknown band: %d", (int)wl->band);
|
||||
wl1271_error("roc - unknown band: %d", (int)wlvif->band);
|
||||
ret = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
@ -1657,14 +1704,14 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl12xx_roc(struct wl1271 *wl, u8 role_id)
|
||||
int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (WARN_ON(test_bit(role_id, wl->roc_map)))
|
||||
return 0;
|
||||
|
||||
ret = wl12xx_cmd_roc(wl, role_id);
|
||||
ret = wl12xx_cmd_roc(wl, wlvif, role_id);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
|
@ -1753,3 +1800,50 @@ out_free:
|
|||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* start dev role and roc on its channel */
|
||||
int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(!(wlvif->bss_type == BSS_TYPE_STA_BSS ||
|
||||
wlvif->bss_type == BSS_TYPE_IBSS)))
|
||||
return -EINVAL;
|
||||
|
||||
ret = wl12xx_cmd_role_start_dev(wl, wlvif);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
|
||||
if (ret < 0)
|
||||
goto out_stop;
|
||||
|
||||
return 0;
|
||||
|
||||
out_stop:
|
||||
wl12xx_cmd_role_stop_dev(wl, wlvif);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* croc dev hlid, and stop the role */
|
||||
int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(!(wlvif->bss_type == BSS_TYPE_STA_BSS ||
|
||||
wlvif->bss_type == BSS_TYPE_IBSS)))
|
||||
return -EINVAL;
|
||||
|
||||
if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
|
||||
ret = wl12xx_croc(wl, wlvif->dev_role_id);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -36,45 +36,54 @@ 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 wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id);
|
||||
int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, 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 wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
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);
|
||||
int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
|
||||
int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode);
|
||||
int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 ps_mode);
|
||||
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
|
||||
size_t len);
|
||||
int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
|
||||
void *buf, size_t buf_len, int index, u32 rates);
|
||||
int wl1271_cmd_build_null_data(struct wl1271 *wl);
|
||||
int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid);
|
||||
int wl1271_cmd_build_probe_req(struct wl1271 *wl,
|
||||
int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u16 aid);
|
||||
int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *ie, size_t ie_len, u8 band);
|
||||
struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb);
|
||||
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_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
__be32 ip_addr);
|
||||
int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif);
|
||||
int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif);
|
||||
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,
|
||||
int wl1271_cmd_set_sta_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
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,
|
||||
int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u16 action, u8 id, u8 key_type,
|
||||
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
|
||||
u16 tx_seq_16);
|
||||
int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid);
|
||||
int wl12xx_roc(struct wl1271 *wl, u8 role_id);
|
||||
int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, 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_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
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);
|
||||
|
@ -82,6 +91,9 @@ int wl12xx_cmd_stop_fwlog(struct wl1271 *wl);
|
|||
int wl12xx_cmd_channel_switch(struct wl1271 *wl,
|
||||
struct ieee80211_channel_switch *ch_switch);
|
||||
int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl);
|
||||
int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 *hlid);
|
||||
void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid);
|
||||
|
||||
enum wl1271_commands {
|
||||
CMD_INTERROGATE = 1, /*use this to read information elements*/
|
||||
|
|
|
@ -440,6 +440,10 @@ struct conf_rx_settings {
|
|||
CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \
|
||||
CONF_HW_BIT_RATE_54MBPS)
|
||||
|
||||
#define CONF_TX_CCK_RATES (CONF_HW_BIT_RATE_1MBPS | \
|
||||
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \
|
||||
CONF_HW_BIT_RATE_11MBPS)
|
||||
|
||||
#define CONF_TX_OFDM_RATES (CONF_HW_BIT_RATE_6MBPS | \
|
||||
CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS | \
|
||||
CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* This file is part of wl12xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments. All rights reserved.
|
||||
* Copyright (C) 2008-2009 Nokia Corporation
|
||||
*
|
||||
* Contact: Luciano Coelho <coelho@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DEBUG_H__
|
||||
#define __DEBUG_H__
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
#define DRIVER_NAME "wl12xx"
|
||||
#define DRIVER_PREFIX DRIVER_NAME ": "
|
||||
|
||||
enum {
|
||||
DEBUG_NONE = 0,
|
||||
DEBUG_IRQ = BIT(0),
|
||||
DEBUG_SPI = BIT(1),
|
||||
DEBUG_BOOT = BIT(2),
|
||||
DEBUG_MAILBOX = BIT(3),
|
||||
DEBUG_TESTMODE = BIT(4),
|
||||
DEBUG_EVENT = BIT(5),
|
||||
DEBUG_TX = BIT(6),
|
||||
DEBUG_RX = BIT(7),
|
||||
DEBUG_SCAN = BIT(8),
|
||||
DEBUG_CRYPT = BIT(9),
|
||||
DEBUG_PSM = BIT(10),
|
||||
DEBUG_MAC80211 = BIT(11),
|
||||
DEBUG_CMD = BIT(12),
|
||||
DEBUG_ACX = BIT(13),
|
||||
DEBUG_SDIO = BIT(14),
|
||||
DEBUG_FILTERS = BIT(15),
|
||||
DEBUG_ADHOC = BIT(16),
|
||||
DEBUG_AP = BIT(17),
|
||||
DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP),
|
||||
DEBUG_ALL = ~0,
|
||||
};
|
||||
|
||||
extern u32 wl12xx_debug_level;
|
||||
|
||||
#define DEBUG_DUMP_LIMIT 1024
|
||||
|
||||
#define wl1271_error(fmt, arg...) \
|
||||
pr_err(DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
|
||||
|
||||
#define wl1271_warning(fmt, arg...) \
|
||||
pr_warning(DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
|
||||
|
||||
#define wl1271_notice(fmt, arg...) \
|
||||
pr_info(DRIVER_PREFIX fmt "\n", ##arg)
|
||||
|
||||
#define wl1271_info(fmt, arg...) \
|
||||
pr_info(DRIVER_PREFIX fmt "\n", ##arg)
|
||||
|
||||
#define wl1271_debug(level, fmt, arg...) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
pr_debug(DRIVER_PREFIX fmt "\n", ##arg); \
|
||||
} while (0)
|
||||
|
||||
/* TODO: use pr_debug_hex_dump when it becomes available */
|
||||
#define wl1271_dump(level, prefix, buf, len) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
|
||||
DUMP_PREFIX_OFFSET, 16, 1, \
|
||||
buf, \
|
||||
min_t(size_t, len, DEBUG_DUMP_LIMIT), \
|
||||
0); \
|
||||
} while (0)
|
||||
|
||||
#define wl1271_dump_ascii(level, prefix, buf, len) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
|
||||
DUMP_PREFIX_OFFSET, 16, 1, \
|
||||
buf, \
|
||||
min_t(size_t, len, DEBUG_DUMP_LIMIT), \
|
||||
true); \
|
||||
} while (0)
|
||||
|
||||
#endif /* __DEBUG_H__ */
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/slab.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "acx.h"
|
||||
#include "ps.h"
|
||||
#include "io.h"
|
||||
|
@ -346,29 +347,14 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
|
|||
DRIVER_STATE_PRINT_INT(tx_results_count);
|
||||
DRIVER_STATE_PRINT_LHEX(flags);
|
||||
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);
|
||||
DRIVER_STATE_PRINT_INT(state);
|
||||
DRIVER_STATE_PRINT_INT(bss_type);
|
||||
DRIVER_STATE_PRINT_INT(channel);
|
||||
DRIVER_STATE_PRINT_HEX(rate_set);
|
||||
DRIVER_STATE_PRINT_HEX(basic_rate_set);
|
||||
DRIVER_STATE_PRINT_HEX(basic_rate);
|
||||
DRIVER_STATE_PRINT_INT(band);
|
||||
DRIVER_STATE_PRINT_INT(beacon_int);
|
||||
DRIVER_STATE_PRINT_INT(psm_entry_retry);
|
||||
DRIVER_STATE_PRINT_INT(ps_poll_failures);
|
||||
DRIVER_STATE_PRINT_INT(power_level);
|
||||
DRIVER_STATE_PRINT_INT(rssi_thold);
|
||||
DRIVER_STATE_PRINT_INT(last_rssi_event);
|
||||
DRIVER_STATE_PRINT_INT(sg_enabled);
|
||||
DRIVER_STATE_PRINT_INT(enable_11a);
|
||||
DRIVER_STATE_PRINT_INT(noise);
|
||||
DRIVER_STATE_PRINT_LHEX(ap_hlid_map[0]);
|
||||
DRIVER_STATE_PRINT_INT(last_tx_hlid);
|
||||
DRIVER_STATE_PRINT_INT(ba_support);
|
||||
DRIVER_STATE_PRINT_HEX(ba_rx_bitmap);
|
||||
DRIVER_STATE_PRINT_HEX(ap_fw_ps_map);
|
||||
DRIVER_STATE_PRINT_LHEX(ap_ps_map);
|
||||
DRIVER_STATE_PRINT_HEX(quirks);
|
||||
|
@ -399,6 +385,115 @@ static const struct file_operations driver_state_ops = {
|
|||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wl1271 *wl = file->private_data;
|
||||
struct wl12xx_vif *wlvif;
|
||||
int ret, res = 0;
|
||||
const int buf_size = 4096;
|
||||
char *buf;
|
||||
char tmp_buf[64];
|
||||
|
||||
buf = kzalloc(buf_size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
#define VIF_STATE_PRINT(x, fmt) \
|
||||
(res += scnprintf(buf + res, buf_size - res, \
|
||||
#x " = " fmt "\n", wlvif->x))
|
||||
|
||||
#define VIF_STATE_PRINT_LONG(x) VIF_STATE_PRINT(x, "%ld")
|
||||
#define VIF_STATE_PRINT_INT(x) VIF_STATE_PRINT(x, "%d")
|
||||
#define VIF_STATE_PRINT_STR(x) VIF_STATE_PRINT(x, "%s")
|
||||
#define VIF_STATE_PRINT_LHEX(x) VIF_STATE_PRINT(x, "0x%lx")
|
||||
#define VIF_STATE_PRINT_LLHEX(x) VIF_STATE_PRINT(x, "0x%llx")
|
||||
#define VIF_STATE_PRINT_HEX(x) VIF_STATE_PRINT(x, "0x%x")
|
||||
|
||||
#define VIF_STATE_PRINT_NSTR(x, len) \
|
||||
do { \
|
||||
memset(tmp_buf, 0, sizeof(tmp_buf)); \
|
||||
memcpy(tmp_buf, wlvif->x, \
|
||||
min_t(u8, len, sizeof(tmp_buf) - 1)); \
|
||||
res += scnprintf(buf + res, buf_size - res, \
|
||||
#x " = %s\n", tmp_buf); \
|
||||
} while (0)
|
||||
|
||||
wl12xx_for_each_wlvif(wl, wlvif) {
|
||||
VIF_STATE_PRINT_INT(role_id);
|
||||
VIF_STATE_PRINT_INT(bss_type);
|
||||
VIF_STATE_PRINT_LHEX(flags);
|
||||
VIF_STATE_PRINT_INT(p2p);
|
||||
VIF_STATE_PRINT_INT(dev_role_id);
|
||||
VIF_STATE_PRINT_INT(dev_hlid);
|
||||
|
||||
if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
|
||||
wlvif->bss_type == BSS_TYPE_IBSS) {
|
||||
VIF_STATE_PRINT_INT(sta.hlid);
|
||||
VIF_STATE_PRINT_INT(sta.ba_rx_bitmap);
|
||||
VIF_STATE_PRINT_INT(sta.basic_rate_idx);
|
||||
VIF_STATE_PRINT_INT(sta.ap_rate_idx);
|
||||
VIF_STATE_PRINT_INT(sta.p2p_rate_idx);
|
||||
} else {
|
||||
VIF_STATE_PRINT_INT(ap.global_hlid);
|
||||
VIF_STATE_PRINT_INT(ap.bcast_hlid);
|
||||
VIF_STATE_PRINT_LHEX(ap.sta_hlid_map[0]);
|
||||
VIF_STATE_PRINT_INT(ap.mgmt_rate_idx);
|
||||
VIF_STATE_PRINT_INT(ap.bcast_rate_idx);
|
||||
VIF_STATE_PRINT_INT(ap.ucast_rate_idx[0]);
|
||||
VIF_STATE_PRINT_INT(ap.ucast_rate_idx[1]);
|
||||
VIF_STATE_PRINT_INT(ap.ucast_rate_idx[2]);
|
||||
VIF_STATE_PRINT_INT(ap.ucast_rate_idx[3]);
|
||||
}
|
||||
VIF_STATE_PRINT_INT(last_tx_hlid);
|
||||
VIF_STATE_PRINT_LHEX(links_map[0]);
|
||||
VIF_STATE_PRINT_NSTR(ssid, wlvif->ssid_len);
|
||||
VIF_STATE_PRINT_INT(band);
|
||||
VIF_STATE_PRINT_INT(channel);
|
||||
VIF_STATE_PRINT_HEX(bitrate_masks[0]);
|
||||
VIF_STATE_PRINT_HEX(bitrate_masks[1]);
|
||||
VIF_STATE_PRINT_HEX(basic_rate_set);
|
||||
VIF_STATE_PRINT_HEX(basic_rate);
|
||||
VIF_STATE_PRINT_HEX(rate_set);
|
||||
VIF_STATE_PRINT_INT(beacon_int);
|
||||
VIF_STATE_PRINT_INT(default_key);
|
||||
VIF_STATE_PRINT_INT(aid);
|
||||
VIF_STATE_PRINT_INT(session_counter);
|
||||
VIF_STATE_PRINT_INT(ps_poll_failures);
|
||||
VIF_STATE_PRINT_INT(psm_entry_retry);
|
||||
VIF_STATE_PRINT_INT(power_level);
|
||||
VIF_STATE_PRINT_INT(rssi_thold);
|
||||
VIF_STATE_PRINT_INT(last_rssi_event);
|
||||
VIF_STATE_PRINT_INT(ba_support);
|
||||
VIF_STATE_PRINT_INT(ba_allowed);
|
||||
VIF_STATE_PRINT_LLHEX(tx_security_seq);
|
||||
VIF_STATE_PRINT_INT(tx_security_last_seq_lsb);
|
||||
}
|
||||
|
||||
#undef VIF_STATE_PRINT_INT
|
||||
#undef VIF_STATE_PRINT_LONG
|
||||
#undef VIF_STATE_PRINT_HEX
|
||||
#undef VIF_STATE_PRINT_LHEX
|
||||
#undef VIF_STATE_PRINT_LLHEX
|
||||
#undef VIF_STATE_PRINT_STR
|
||||
#undef VIF_STATE_PRINT_NSTR
|
||||
#undef VIF_STATE_PRINT
|
||||
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, res);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations vifs_state_ops = {
|
||||
.read = vifs_state_read,
|
||||
.open = wl1271_open_file_generic,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t dtim_interval_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
|
@ -520,6 +615,7 @@ static ssize_t rx_streaming_interval_write(struct file *file,
|
|||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wl1271 *wl = file->private_data;
|
||||
struct wl12xx_vif *wlvif;
|
||||
unsigned long value;
|
||||
int ret;
|
||||
|
||||
|
@ -543,7 +639,9 @@ static ssize_t rx_streaming_interval_write(struct file *file,
|
|||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
wl1271_recalc_rx_streaming(wl);
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
wl1271_recalc_rx_streaming(wl, wlvif);
|
||||
}
|
||||
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
out:
|
||||
|
@ -572,6 +670,7 @@ static ssize_t rx_streaming_always_write(struct file *file,
|
|||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wl1271 *wl = file->private_data;
|
||||
struct wl12xx_vif *wlvif;
|
||||
unsigned long value;
|
||||
int ret;
|
||||
|
||||
|
@ -595,7 +694,9 @@ static ssize_t rx_streaming_always_write(struct file *file,
|
|||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
wl1271_recalc_rx_streaming(wl);
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
wl1271_recalc_rx_streaming(wl, wlvif);
|
||||
}
|
||||
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
out:
|
||||
|
@ -624,6 +725,7 @@ static ssize_t beacon_filtering_write(struct file *file,
|
|||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wl1271 *wl = file->private_data;
|
||||
struct wl12xx_vif *wlvif;
|
||||
char buf[10];
|
||||
size_t len;
|
||||
unsigned long value;
|
||||
|
@ -646,7 +748,9 @@ static ssize_t beacon_filtering_write(struct file *file,
|
|||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl1271_acx_beacon_filter_opt(wl, !!value);
|
||||
wl12xx_for_each_wlvif(wl, wlvif) {
|
||||
ret = wl1271_acx_beacon_filter_opt(wl, wlvif, !!value);
|
||||
}
|
||||
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
out:
|
||||
|
@ -770,6 +874,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
|
|||
DEBUGFS_ADD(gpio_power, rootdir);
|
||||
DEBUGFS_ADD(start_recovery, rootdir);
|
||||
DEBUGFS_ADD(driver_state, rootdir);
|
||||
DEBUGFS_ADD(vifs_state, rootdir);
|
||||
DEBUGFS_ADD(dtim_interval, rootdir);
|
||||
DEBUGFS_ADD(beacon_interval, rootdir);
|
||||
DEBUGFS_ADD(beacon_filtering, rootdir);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
*/
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "reg.h"
|
||||
#include "io.h"
|
||||
#include "event.h"
|
||||
|
@ -31,12 +32,16 @@
|
|||
|
||||
void wl1271_pspoll_work(struct work_struct *work)
|
||||
{
|
||||
struct ieee80211_vif *vif;
|
||||
struct wl12xx_vif *wlvif;
|
||||
struct delayed_work *dwork;
|
||||
struct wl1271 *wl;
|
||||
int ret;
|
||||
|
||||
dwork = container_of(work, struct delayed_work, work);
|
||||
wl = container_of(dwork, struct wl1271, pspoll_work);
|
||||
wlvif = container_of(dwork, struct wl12xx_vif, pspoll_work);
|
||||
vif = container_of((void *)wlvif, struct ieee80211_vif, drv_priv);
|
||||
wl = wlvif->wl;
|
||||
|
||||
wl1271_debug(DEBUG_EVENT, "pspoll work");
|
||||
|
||||
|
@ -45,10 +50,10 @@ void wl1271_pspoll_work(struct work_struct *work)
|
|||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
goto out;
|
||||
|
||||
if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags))
|
||||
if (!test_and_clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags))
|
||||
goto out;
|
||||
|
||||
if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
|
||||
if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
|
@ -60,31 +65,33 @@ void wl1271_pspoll_work(struct work_struct *work)
|
|||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true);
|
||||
wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
|
||||
wlvif->basic_rate, true);
|
||||
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
out:
|
||||
mutex_unlock(&wl->mutex);
|
||||
};
|
||||
|
||||
static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl)
|
||||
static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int delay = wl->conf.conn.ps_poll_recovery_period;
|
||||
int ret;
|
||||
|
||||
wl->ps_poll_failures++;
|
||||
if (wl->ps_poll_failures == 1)
|
||||
wlvif->ps_poll_failures++;
|
||||
if (wlvif->ps_poll_failures == 1)
|
||||
wl1271_info("AP with dysfunctional ps-poll, "
|
||||
"trying to work around it.");
|
||||
|
||||
/* force active mode receive data from the AP */
|
||||
if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
|
||||
ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
|
||||
wl->basic_rate, true);
|
||||
if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
|
||||
ret = wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
|
||||
wlvif->basic_rate, true);
|
||||
if (ret < 0)
|
||||
return;
|
||||
set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
|
||||
ieee80211_queue_delayed_work(wl->hw, &wl->pspoll_work,
|
||||
set_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
|
||||
ieee80211_queue_delayed_work(wl->hw, &wlvif->pspoll_work,
|
||||
msecs_to_jiffies(delay));
|
||||
}
|
||||
|
||||
|
@ -97,6 +104,7 @@ static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl)
|
|||
}
|
||||
|
||||
static int wl1271_event_ps_report(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct event_mailbox *mbox,
|
||||
bool *beacon_loss)
|
||||
{
|
||||
|
@ -109,41 +117,37 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
|
|||
case EVENT_ENTER_POWER_SAVE_FAIL:
|
||||
wl1271_debug(DEBUG_PSM, "PSM entry failed");
|
||||
|
||||
if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
|
||||
if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
|
||||
/* remain in active mode */
|
||||
wl->psm_entry_retry = 0;
|
||||
wlvif->psm_entry_retry = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (wl->psm_entry_retry < total_retries) {
|
||||
wl->psm_entry_retry++;
|
||||
ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
|
||||
wl->basic_rate, true);
|
||||
if (wlvif->psm_entry_retry < total_retries) {
|
||||
wlvif->psm_entry_retry++;
|
||||
ret = wl1271_ps_set_mode(wl, wlvif,
|
||||
STATION_POWER_SAVE_MODE,
|
||||
wlvif->basic_rate, true);
|
||||
} else {
|
||||
wl1271_info("No ack to nullfunc from AP.");
|
||||
wl->psm_entry_retry = 0;
|
||||
wlvif->psm_entry_retry = 0;
|
||||
*beacon_loss = true;
|
||||
}
|
||||
break;
|
||||
case EVENT_ENTER_POWER_SAVE_SUCCESS:
|
||||
wl->psm_entry_retry = 0;
|
||||
|
||||
/* enable beacon filtering */
|
||||
ret = wl1271_acx_beacon_filter_opt(wl, true);
|
||||
if (ret < 0)
|
||||
break;
|
||||
wlvif->psm_entry_retry = 0;
|
||||
|
||||
/*
|
||||
* BET has only a minor effect in 5GHz and masks
|
||||
* channel switch IEs, so we only enable BET on 2.4GHz
|
||||
*/
|
||||
if (wl->band == IEEE80211_BAND_2GHZ)
|
||||
if (wlvif->band == IEEE80211_BAND_2GHZ)
|
||||
/* enable beacon early termination */
|
||||
ret = wl1271_acx_bet_enable(wl, true);
|
||||
ret = wl1271_acx_bet_enable(wl, wlvif, true);
|
||||
|
||||
if (wl->ps_compl) {
|
||||
complete(wl->ps_compl);
|
||||
wl->ps_compl = NULL;
|
||||
if (wlvif->ps_compl) {
|
||||
complete(wlvif->ps_compl);
|
||||
wlvif->ps_compl = NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -154,39 +158,44 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
|
|||
}
|
||||
|
||||
static void wl1271_event_rssi_trigger(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct event_mailbox *mbox)
|
||||
{
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
enum nl80211_cqm_rssi_threshold_event event;
|
||||
s8 metric = mbox->rssi_snr_trigger_metric[0];
|
||||
|
||||
wl1271_debug(DEBUG_EVENT, "RSSI trigger metric: %d", metric);
|
||||
|
||||
if (metric <= wl->rssi_thold)
|
||||
if (metric <= wlvif->rssi_thold)
|
||||
event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
|
||||
else
|
||||
event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
|
||||
|
||||
if (event != wl->last_rssi_event)
|
||||
ieee80211_cqm_rssi_notify(wl->vif, event, GFP_KERNEL);
|
||||
wl->last_rssi_event = event;
|
||||
if (event != wlvif->last_rssi_event)
|
||||
ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL);
|
||||
wlvif->last_rssi_event = event;
|
||||
}
|
||||
|
||||
static void wl1271_stop_ba_event(struct wl1271 *wl)
|
||||
static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
if (wl->bss_type != BSS_TYPE_AP_BSS) {
|
||||
if (!wl->ba_rx_bitmap)
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
|
||||
if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
|
||||
if (!wlvif->sta.ba_rx_bitmap)
|
||||
return;
|
||||
ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap,
|
||||
wl->bssid);
|
||||
ieee80211_stop_rx_ba_session(vif, wlvif->sta.ba_rx_bitmap,
|
||||
vif->bss_conf.bssid);
|
||||
} else {
|
||||
int i;
|
||||
u8 hlid;
|
||||
struct wl1271_link *lnk;
|
||||
for (i = WL1271_AP_STA_HLID_START; i < AP_MAX_LINKS; i++) {
|
||||
lnk = &wl->links[i];
|
||||
if (!wl1271_is_active_sta(wl, i) || !lnk->ba_bitmap)
|
||||
for_each_set_bit(hlid, wlvif->ap.sta_hlid_map,
|
||||
WL12XX_MAX_LINKS) {
|
||||
lnk = &wl->links[hlid];
|
||||
if (!lnk->ba_bitmap)
|
||||
continue;
|
||||
|
||||
ieee80211_stop_rx_ba_session(wl->vif,
|
||||
ieee80211_stop_rx_ba_session(vif,
|
||||
lnk->ba_bitmap,
|
||||
lnk->addr);
|
||||
}
|
||||
|
@ -196,14 +205,23 @@ static void wl1271_stop_ba_event(struct wl1271 *wl)
|
|||
static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
|
||||
u8 enable)
|
||||
{
|
||||
struct ieee80211_vif *vif;
|
||||
struct wl12xx_vif *wlvif;
|
||||
|
||||
if (enable) {
|
||||
/* disable dynamic PS when requested by the firmware */
|
||||
ieee80211_disable_dyn_ps(wl->vif);
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
ieee80211_disable_dyn_ps(vif);
|
||||
}
|
||||
set_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
|
||||
} else {
|
||||
ieee80211_enable_dyn_ps(wl->vif);
|
||||
clear_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
|
||||
wl1271_recalc_rx_streaming(wl);
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
ieee80211_enable_dyn_ps(vif);
|
||||
wl1271_recalc_rx_streaming(wl, wlvif);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -217,10 +235,11 @@ static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
|
|||
|
||||
static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
||||
{
|
||||
struct ieee80211_vif *vif;
|
||||
struct wl12xx_vif *wlvif;
|
||||
int ret;
|
||||
u32 vector;
|
||||
bool beacon_loss = false;
|
||||
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
|
||||
bool disconnect_sta = false;
|
||||
unsigned long sta_bitmap = 0;
|
||||
|
||||
|
@ -234,7 +253,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
|||
wl1271_debug(DEBUG_EVENT, "status: 0x%x",
|
||||
mbox->scheduled_scan_status);
|
||||
|
||||
wl1271_scan_stm(wl);
|
||||
wl1271_scan_stm(wl, wl->scan_vif);
|
||||
}
|
||||
|
||||
if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
|
||||
|
@ -253,8 +272,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
|||
}
|
||||
}
|
||||
|
||||
if (vector & SOFT_GEMINI_SENSE_EVENT_ID &&
|
||||
wl->bss_type == BSS_TYPE_STA_BSS)
|
||||
if (vector & SOFT_GEMINI_SENSE_EVENT_ID)
|
||||
wl12xx_event_soft_gemini_sense(wl,
|
||||
mbox->soft_gemini_sense_info);
|
||||
|
||||
|
@ -267,40 +285,54 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
|||
* BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
|
||||
*
|
||||
*/
|
||||
if ((vector & BSS_LOSE_EVENT_ID) && !is_ap) {
|
||||
if (vector & BSS_LOSE_EVENT_ID) {
|
||||
/* TODO: check for multi-role */
|
||||
wl1271_info("Beacon loss detected.");
|
||||
|
||||
/* indicate to the stack, that beacons have been lost */
|
||||
beacon_loss = true;
|
||||
}
|
||||
|
||||
if ((vector & PS_REPORT_EVENT_ID) && !is_ap) {
|
||||
if (vector & PS_REPORT_EVENT_ID) {
|
||||
wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
|
||||
ret = wl1271_event_ps_report(wl, mbox, &beacon_loss);
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
ret = wl1271_event_ps_report(wl, wlvif,
|
||||
mbox, &beacon_loss);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if ((vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) && !is_ap)
|
||||
wl1271_event_pspoll_delivery_fail(wl);
|
||||
if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID)
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
wl1271_event_pspoll_delivery_fail(wl, wlvif);
|
||||
}
|
||||
|
||||
if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
|
||||
/* TODO: check actual multi-role support */
|
||||
wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
|
||||
if (wl->vif)
|
||||
wl1271_event_rssi_trigger(wl, mbox);
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
wl1271_event_rssi_trigger(wl, wlvif, mbox);
|
||||
}
|
||||
}
|
||||
|
||||
if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)) {
|
||||
if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) {
|
||||
u8 role_id = mbox->role_id;
|
||||
wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
|
||||
"ba_allowed = 0x%x", mbox->rx_ba_allowed);
|
||||
"ba_allowed = 0x%x, role_id=%d",
|
||||
mbox->rx_ba_allowed, role_id);
|
||||
|
||||
wl->ba_allowed = !!mbox->rx_ba_allowed;
|
||||
wl12xx_for_each_wlvif(wl, wlvif) {
|
||||
if (role_id != 0xff && role_id != wlvif->role_id)
|
||||
continue;
|
||||
|
||||
if (wl->vif && !wl->ba_allowed)
|
||||
wl1271_stop_ba_event(wl);
|
||||
wlvif->ba_allowed = !!mbox->rx_ba_allowed;
|
||||
if (!wlvif->ba_allowed)
|
||||
wl1271_stop_ba_event(wl, wlvif);
|
||||
}
|
||||
}
|
||||
|
||||
if ((vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) && !is_ap) {
|
||||
if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) {
|
||||
wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. "
|
||||
"status = 0x%x",
|
||||
mbox->channel_switch_status);
|
||||
|
@ -309,15 +341,23 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
|||
* 1) channel switch complete with status=0
|
||||
* 2) channel switch failed status=1
|
||||
*/
|
||||
if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags) &&
|
||||
(wl->vif))
|
||||
ieee80211_chswitch_done(wl->vif,
|
||||
mbox->channel_switch_status ? false : true);
|
||||
|
||||
/* TODO: configure only the relevant vif */
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
bool success;
|
||||
|
||||
if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS,
|
||||
&wl->flags))
|
||||
continue;
|
||||
|
||||
success = mbox->channel_switch_status ? false : true;
|
||||
ieee80211_chswitch_done(vif, success);
|
||||
}
|
||||
}
|
||||
|
||||
if ((vector & DUMMY_PACKET_EVENT_ID)) {
|
||||
wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
|
||||
if (wl->vif)
|
||||
wl1271_tx_dummy_packet(wl);
|
||||
}
|
||||
|
||||
|
@ -325,34 +365,41 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
|||
* "TX retries exceeded" has a different meaning according to mode.
|
||||
* In AP mode the offending station is disconnected.
|
||||
*/
|
||||
if ((vector & MAX_TX_RETRY_EVENT_ID) && is_ap) {
|
||||
if (vector & MAX_TX_RETRY_EVENT_ID) {
|
||||
wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID");
|
||||
sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded);
|
||||
disconnect_sta = true;
|
||||
}
|
||||
|
||||
if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) {
|
||||
if (vector & INACTIVE_STA_EVENT_ID) {
|
||||
wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
|
||||
sta_bitmap |= le16_to_cpu(mbox->sta_aging_status);
|
||||
disconnect_sta = true;
|
||||
}
|
||||
|
||||
if (is_ap && disconnect_sta) {
|
||||
if (disconnect_sta) {
|
||||
u32 num_packets = wl->conf.tx.max_tx_retries;
|
||||
struct ieee80211_sta *sta;
|
||||
const u8 *addr;
|
||||
int h;
|
||||
|
||||
for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS);
|
||||
h < AP_MAX_LINKS;
|
||||
h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) {
|
||||
if (!wl1271_is_active_sta(wl, h))
|
||||
for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) {
|
||||
bool found = false;
|
||||
/* find the ap vif connected to this sta */
|
||||
wl12xx_for_each_wlvif_ap(wl, wlvif) {
|
||||
if (!test_bit(h, wlvif->ap.sta_hlid_map))
|
||||
continue;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found)
|
||||
continue;
|
||||
|
||||
vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
addr = wl->links[h].addr;
|
||||
|
||||
rcu_read_lock();
|
||||
sta = ieee80211_find_sta(wl->vif, addr);
|
||||
sta = ieee80211_find_sta(vif, addr);
|
||||
if (sta) {
|
||||
wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
|
||||
ieee80211_report_low_ack(sta, num_packets);
|
||||
|
@ -361,8 +408,11 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
|||
}
|
||||
}
|
||||
|
||||
if (wl->vif && beacon_loss)
|
||||
ieee80211_connection_loss(wl->vif);
|
||||
if (beacon_loss)
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
ieee80211_connection_loss(vif);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -132,7 +132,4 @@ void wl1271_event_mbox_config(struct wl1271 *wl);
|
|||
int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
|
||||
void wl1271_pspoll_work(struct work_struct *work);
|
||||
|
||||
/* Functions from main.c */
|
||||
bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "init.h"
|
||||
#include "wl12xx_80211.h"
|
||||
#include "acx.h"
|
||||
|
@ -33,7 +34,7 @@
|
|||
#include "tx.h"
|
||||
#include "io.h"
|
||||
|
||||
int wl1271_sta_init_templates_config(struct wl1271 *wl)
|
||||
int wl1271_init_templates_config(struct wl1271 *wl)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
|
@ -64,7 +65,7 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl)
|
|||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL,
|
||||
sizeof
|
||||
(struct wl12xx_qos_null_data_template),
|
||||
(struct ieee80211_qos_hdr),
|
||||
0, WL1271_RATE_AUTOMATIC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -88,105 +89,6 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
|
||||
WL1271_CMD_TEMPL_DFLT_SIZE, i,
|
||||
WL1271_RATE_AUTOMATIC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_deauth_template(struct wl1271 *wl)
|
||||
{
|
||||
struct wl12xx_disconn_template *tmpl;
|
||||
int ret;
|
||||
u32 rate;
|
||||
|
||||
tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
|
||||
if (!tmpl) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_DEAUTH);
|
||||
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP,
|
||||
tmpl, sizeof(*tmpl), 0, rate);
|
||||
|
||||
out:
|
||||
kfree(tmpl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_null_template(struct wl1271 *wl)
|
||||
{
|
||||
struct ieee80211_hdr_3addr *nullfunc;
|
||||
int ret;
|
||||
u32 rate;
|
||||
|
||||
nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL);
|
||||
if (!nullfunc) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_NULLFUNC |
|
||||
IEEE80211_FCTL_FROMDS);
|
||||
|
||||
/* nullfunc->addr1 is filled by FW */
|
||||
|
||||
memcpy(nullfunc->addr2, wl->mac_addr, ETH_ALEN);
|
||||
memcpy(nullfunc->addr3, wl->mac_addr, ETH_ALEN);
|
||||
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc,
|
||||
sizeof(*nullfunc), 0, rate);
|
||||
|
||||
out:
|
||||
kfree(nullfunc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_qos_null_template(struct wl1271 *wl)
|
||||
{
|
||||
struct ieee80211_qos_hdr *qosnull;
|
||||
int ret;
|
||||
u32 rate;
|
||||
|
||||
qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL);
|
||||
if (!qosnull) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_QOS_NULLFUNC |
|
||||
IEEE80211_FCTL_FROMDS);
|
||||
|
||||
/* qosnull->addr1 is filled by FW */
|
||||
|
||||
memcpy(qosnull->addr2, wl->mac_addr, ETH_ALEN);
|
||||
memcpy(qosnull->addr3, wl->mac_addr, ETH_ALEN);
|
||||
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull,
|
||||
sizeof(*qosnull), 0, rate);
|
||||
|
||||
out:
|
||||
kfree(qosnull);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_templates_config(struct wl1271 *wl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Put very large empty placeholders for all templates. These
|
||||
* reserve memory for later.
|
||||
|
@ -210,22 +112,106 @@ static int wl1271_ap_init_templates_config(struct wl1271 *wl)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
|
||||
sizeof(struct wl12xx_null_data_template),
|
||||
0, WL1271_RATE_AUTOMATIC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL,
|
||||
sizeof
|
||||
(struct wl12xx_qos_null_data_template),
|
||||
0, WL1271_RATE_AUTOMATIC);
|
||||
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
|
||||
sizeof(struct ieee80211_qos_hdr),
|
||||
i, WL1271_RATE_AUTOMATIC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_deauth_template(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl12xx_disconn_template *tmpl;
|
||||
int ret;
|
||||
u32 rate;
|
||||
|
||||
tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
|
||||
if (!tmpl) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_DEAUTH);
|
||||
|
||||
rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP,
|
||||
tmpl, sizeof(*tmpl), 0, rate);
|
||||
|
||||
out:
|
||||
kfree(tmpl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_null_template(struct wl1271 *wl,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
struct ieee80211_hdr_3addr *nullfunc;
|
||||
int ret;
|
||||
u32 rate;
|
||||
|
||||
nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL);
|
||||
if (!nullfunc) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_NULLFUNC |
|
||||
IEEE80211_FCTL_FROMDS);
|
||||
|
||||
/* nullfunc->addr1 is filled by FW */
|
||||
|
||||
memcpy(nullfunc->addr2, vif->addr, ETH_ALEN);
|
||||
memcpy(nullfunc->addr3, vif->addr, ETH_ALEN);
|
||||
|
||||
rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc,
|
||||
sizeof(*nullfunc), 0, rate);
|
||||
|
||||
out:
|
||||
kfree(nullfunc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_qos_null_template(struct wl1271 *wl,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
struct ieee80211_qos_hdr *qosnull;
|
||||
int ret;
|
||||
u32 rate;
|
||||
|
||||
qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL);
|
||||
if (!qosnull) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_QOS_NULLFUNC |
|
||||
IEEE80211_FCTL_FROMDS);
|
||||
|
||||
/* qosnull->addr1 is filled by FW */
|
||||
|
||||
memcpy(qosnull->addr2, vif->addr, ETH_ALEN);
|
||||
memcpy(qosnull->addr3, vif->addr, ETH_ALEN);
|
||||
|
||||
rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull,
|
||||
sizeof(*qosnull), 0, rate);
|
||||
|
||||
out:
|
||||
kfree(qosnull);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl12xx_init_rx_config(struct wl1271 *wl)
|
||||
{
|
||||
int ret;
|
||||
|
@ -245,31 +231,40 @@ int wl1271_init_phy_config(struct wl1271 *wl)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_slot(wl, DEFAULT_SLOT_TIME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl12xx_init_phy_vif_config(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl1271_acx_slot(wl, wlvif, DEFAULT_SLOT_TIME);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_service_period_timeout(wl);
|
||||
ret = wl1271_acx_service_period_timeout(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_rts_threshold(wl, wl->hw->wiphy->rts_threshold);
|
||||
ret = wl1271_acx_rts_threshold(wl, wlvif, wl->hw->wiphy->rts_threshold);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_init_beacon_filter(struct wl1271 *wl)
|
||||
static int wl1271_init_sta_beacon_filter(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* disable beacon filtering at this stage */
|
||||
ret = wl1271_acx_beacon_filter_opt(wl, false);
|
||||
ret = wl1271_acx_beacon_filter_table(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_beacon_filter_table(wl);
|
||||
/* enable beacon filtering */
|
||||
ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -302,11 +297,12 @@ int wl1271_init_energy_detection(struct wl1271 *wl)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_init_beacon_broadcast(struct wl1271 *wl)
|
||||
static int wl1271_init_beacon_broadcast(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl1271_acx_bcn_dtim_options(wl);
|
||||
ret = wl1271_acx_bcn_dtim_options(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -327,7 +323,8 @@ static int wl12xx_init_fwlog(struct wl1271 *wl)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_sta_hw_init(struct wl1271 *wl)
|
||||
/* generic sta initialization (non vif-specific) */
|
||||
static int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -338,25 +335,7 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
|
|||
}
|
||||
|
||||
/* PS config */
|
||||
ret = wl1271_acx_config_ps(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_sta_init_templates_config(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_group_address_tbl(wl, true, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Initialize connection monitoring thresholds */
|
||||
ret = wl1271_acx_conn_monit_params(wl, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Beacon filtering */
|
||||
ret = wl1271_init_beacon_filter(wl);
|
||||
ret = wl12xx_acx_config_ps(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -365,103 +344,61 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Beacons and broadcast settings */
|
||||
ret = wl1271_init_beacon_broadcast(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure for ELP power saving */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure rssi/snr averaging weights */
|
||||
ret = wl1271_acx_rssi_snr_avg_weights(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_sta_rate_policies(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl12xx_acx_mem_cfg(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure the FW logger */
|
||||
ret = wl12xx_init_fwlog(wl);
|
||||
ret = wl1271_acx_sta_rate_policies(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl)
|
||||
static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
int ret, i;
|
||||
|
||||
/* disable all keep-alive templates */
|
||||
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
|
||||
ret = wl1271_acx_keep_alive_config(wl, i,
|
||||
ret = wl1271_acx_keep_alive_config(wl, wlvif, i,
|
||||
ACX_KEEP_ALIVE_TPL_INVALID);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* disable the keep-alive feature */
|
||||
ret = wl1271_acx_keep_alive_mode(wl, false);
|
||||
ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_ap_hw_init(struct wl1271 *wl)
|
||||
/* generic ap initialization (non vif-specific) */
|
||||
static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl1271_ap_init_templates_config(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure for power always on */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_init_ap_rates(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_ap_max_tx_retry(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl12xx_acx_mem_cfg(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* initialize Tx power */
|
||||
ret = wl1271_acx_tx_power(wl, wl->power_level);
|
||||
ret = wl1271_init_ap_rates(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wl1271_ap_init_templates(struct wl1271 *wl)
|
||||
int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
int ret;
|
||||
|
||||
ret = wl1271_ap_init_deauth_template(wl);
|
||||
ret = wl1271_ap_init_deauth_template(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_ap_init_null_template(wl);
|
||||
ret = wl1271_ap_init_null_template(wl, vif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_ap_init_qos_null_template(wl);
|
||||
ret = wl1271_ap_init_qos_null_template(wl, vif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -469,43 +406,45 @@ 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_beacon_filter_opt(wl, false);
|
||||
ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
|
||||
static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
return wl1271_ap_init_templates(wl);
|
||||
return wl1271_ap_init_templates(wl, vif);
|
||||
}
|
||||
|
||||
int wl1271_init_ap_rates(struct wl1271 *wl)
|
||||
int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int i, ret;
|
||||
struct conf_tx_rate_class rc;
|
||||
u32 supported_rates;
|
||||
|
||||
wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x", wl->basic_rate_set);
|
||||
wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x",
|
||||
wlvif->basic_rate_set);
|
||||
|
||||
if (wl->basic_rate_set == 0)
|
||||
if (wlvif->basic_rate_set == 0)
|
||||
return -EINVAL;
|
||||
|
||||
rc.enabled_rates = wl->basic_rate_set;
|
||||
rc.enabled_rates = wlvif->basic_rate_set;
|
||||
rc.long_retry_limit = 10;
|
||||
rc.short_retry_limit = 10;
|
||||
rc.aflags = 0;
|
||||
ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_MGMT_RATE);
|
||||
ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.mgmt_rate_idx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* use the min basic rate for AP broadcast/multicast */
|
||||
rc.enabled_rates = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
|
||||
rc.enabled_rates = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
rc.short_retry_limit = 10;
|
||||
rc.long_retry_limit = 10;
|
||||
rc.aflags = 0;
|
||||
ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_BCST_RATE);
|
||||
ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.bcast_rate_idx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -513,7 +452,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl)
|
|||
* If the basic rates contain OFDM rates, use OFDM only
|
||||
* rates for unicast TX as well. Else use all supported rates.
|
||||
*/
|
||||
if ((wl->basic_rate_set & CONF_TX_OFDM_RATES))
|
||||
if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES))
|
||||
supported_rates = CONF_TX_OFDM_RATES;
|
||||
else
|
||||
supported_rates = CONF_TX_AP_ENABLED_RATES;
|
||||
|
@ -527,7 +466,8 @@ int wl1271_init_ap_rates(struct wl1271 *wl)
|
|||
rc.short_retry_limit = 10;
|
||||
rc.long_retry_limit = 10;
|
||||
rc.aflags = 0;
|
||||
ret = wl1271_acx_ap_rate_policy(wl, &rc, i);
|
||||
ret = wl1271_acx_ap_rate_policy(wl, &rc,
|
||||
wlvif->ap.ucast_rate_idx[i]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
@ -535,24 +475,23 @@ int wl1271_init_ap_rates(struct wl1271 *wl)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_set_ba_policies(struct wl1271 *wl)
|
||||
static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
/* Reset the BA RX indicators */
|
||||
wl->ba_rx_bitmap = 0;
|
||||
wl->ba_allowed = true;
|
||||
wlvif->ba_allowed = true;
|
||||
wl->ba_rx_session_count = 0;
|
||||
|
||||
/* 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;
|
||||
if (wlvif->bss_type != BSS_TYPE_AP_BSS &&
|
||||
wlvif->bss_type != BSS_TYPE_STA_BSS) {
|
||||
wlvif->ba_support = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
wl->ba_support = true;
|
||||
wlvif->ba_support = true;
|
||||
|
||||
/* 802.11n initiator BA session setting */
|
||||
return wl12xx_acx_set_ba_initiator_policy(wl);
|
||||
return wl12xx_acx_set_ba_initiator_policy(wl, wlvif);
|
||||
}
|
||||
|
||||
int wl1271_chip_specific_init(struct wl1271 *wl)
|
||||
|
@ -562,7 +501,7 @@ int wl1271_chip_specific_init(struct wl1271 *wl)
|
|||
if (wl->chip.id == CHIP_ID_1283_PG20) {
|
||||
u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE;
|
||||
|
||||
if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT)
|
||||
if (!(wl->quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT))
|
||||
/* Enable SDIO padding */
|
||||
host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK;
|
||||
|
||||
|
@ -575,13 +514,150 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* vif-specifc initialization */
|
||||
static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl1271_acx_group_address_tbl(wl, wlvif, true, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Initialize connection monitoring thresholds */
|
||||
ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Beacon filtering */
|
||||
ret = wl1271_init_sta_beacon_filter(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Beacons and broadcast settings */
|
||||
ret = wl1271_init_beacon_broadcast(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure rssi/snr averaging weights */
|
||||
ret = wl1271_acx_rssi_snr_avg_weights(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vif-specific intialization */
|
||||
static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl1271_acx_ap_max_tx_retry(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* initialize Tx power */
|
||||
ret = wl1271_acx_tx_power(wl, wlvif, wlvif->power_level);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
struct conf_tx_ac_category *conf_ac;
|
||||
struct conf_tx_tid *conf_tid;
|
||||
bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
|
||||
int ret, i;
|
||||
|
||||
/*
|
||||
* consider all existing roles before configuring psm.
|
||||
* TODO: reconfigure on interface removal.
|
||||
*/
|
||||
if (!wl->ap_count) {
|
||||
if (is_ap) {
|
||||
/* Configure for power always on */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else if (!wl->sta_count) {
|
||||
/* Configure for ELP power saving */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mode specific init */
|
||||
if (is_ap) {
|
||||
ret = wl1271_ap_hw_init(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl12xx_init_ap_role(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
ret = wl1271_sta_hw_init(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl12xx_init_sta_role(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
wl12xx_init_phy_vif_config(wl, wlvif);
|
||||
|
||||
/* Default TID/AC configuration */
|
||||
BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
|
||||
for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
|
||||
conf_ac = &wl->conf.tx.ac_conf[i];
|
||||
ret = wl1271_acx_ac_cfg(wl, wlvif, conf_ac->ac,
|
||||
conf_ac->cw_min, conf_ac->cw_max,
|
||||
conf_ac->aifsn, conf_ac->tx_op_limit);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
conf_tid = &wl->conf.tx.tid_conf[i];
|
||||
ret = wl1271_acx_tid_cfg(wl, wlvif,
|
||||
conf_tid->queue_id,
|
||||
conf_tid->channel_type,
|
||||
conf_tid->tsid,
|
||||
conf_tid->ps_scheme,
|
||||
conf_tid->ack_policy,
|
||||
conf_tid->apsd_conf[0],
|
||||
conf_tid->apsd_conf[1]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configure HW encryption */
|
||||
ret = wl1271_acx_feature_cfg(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Mode specific init - post mem init */
|
||||
if (is_ap)
|
||||
ret = wl1271_ap_hw_init_post_mem(wl, vif);
|
||||
else
|
||||
ret = wl1271_sta_hw_init_post_mem(wl, vif);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure initiator BA sessions policies */
|
||||
ret = wl1271_set_ba_policies(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wl1271_hw_init(struct wl1271 *wl)
|
||||
{
|
||||
struct conf_tx_ac_category *conf_ac;
|
||||
struct conf_tx_tid *conf_tid;
|
||||
int ret, i;
|
||||
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
|
||||
int ret;
|
||||
|
||||
if (wl->chip.id == CHIP_ID_1283_PG20)
|
||||
ret = wl128x_cmd_general_parms(wl);
|
||||
|
@ -602,12 +678,17 @@ int wl1271_hw_init(struct wl1271 *wl)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Mode specific init */
|
||||
if (is_ap)
|
||||
ret = wl1271_ap_hw_init(wl);
|
||||
else
|
||||
ret = wl1271_sta_hw_init(wl);
|
||||
/* Init templates */
|
||||
ret = wl1271_init_templates_config(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl12xx_acx_mem_cfg(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure the FW logger */
|
||||
ret = wl12xx_init_fwlog(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -655,61 +736,20 @@ int wl1271_hw_init(struct wl1271 *wl)
|
|||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Default TID/AC configuration */
|
||||
BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
|
||||
for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
|
||||
conf_ac = &wl->conf.tx.ac_conf[i];
|
||||
ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
|
||||
conf_ac->cw_max, conf_ac->aifsn,
|
||||
conf_ac->tx_op_limit);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
conf_tid = &wl->conf.tx.tid_conf[i];
|
||||
ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
|
||||
conf_tid->channel_type,
|
||||
conf_tid->tsid,
|
||||
conf_tid->ps_scheme,
|
||||
conf_tid->ack_policy,
|
||||
conf_tid->apsd_conf[0],
|
||||
conf_tid->apsd_conf[1]);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
}
|
||||
|
||||
/* Enable data path */
|
||||
ret = wl1271_cmd_data_path(wl, 1);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Configure HW encryption */
|
||||
ret = wl1271_acx_feature_cfg(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* configure PM */
|
||||
ret = wl1271_acx_pm_config(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Mode specific init - post mem init */
|
||||
if (is_ap)
|
||||
ret = wl1271_ap_hw_init_post_mem(wl);
|
||||
else
|
||||
ret = wl1271_sta_hw_init_post_mem(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)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* configure hangover */
|
||||
ret = wl12xx_acx_config_hangover(wl);
|
||||
if (ret < 0)
|
||||
|
|
|
@ -27,13 +27,14 @@
|
|||
#include "wl12xx.h"
|
||||
|
||||
int wl1271_hw_init_power_auth(struct wl1271 *wl);
|
||||
int wl1271_sta_init_templates_config(struct wl1271 *wl);
|
||||
int wl1271_init_templates_config(struct wl1271 *wl);
|
||||
int wl1271_init_phy_config(struct wl1271 *wl);
|
||||
int wl1271_init_pta(struct wl1271 *wl);
|
||||
int wl1271_init_energy_detection(struct wl1271 *wl);
|
||||
int wl1271_chip_specific_init(struct wl1271 *wl);
|
||||
int wl1271_hw_init(struct wl1271 *wl);
|
||||
int wl1271_init_ap_rates(struct wl1271 *wl);
|
||||
int wl1271_ap_init_templates(struct wl1271 *wl);
|
||||
int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif);
|
||||
int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,8 +24,10 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "wl12xx_80211.h"
|
||||
#include "io.h"
|
||||
#include "tx.h"
|
||||
|
@ -46,7 +48,7 @@
|
|||
bool wl1271_set_block_size(struct wl1271 *wl)
|
||||
{
|
||||
if (wl->if_ops->set_block_size) {
|
||||
wl->if_ops->set_block_size(wl, WL12XX_BUS_BLOCK_SIZE);
|
||||
wl->if_ops->set_block_size(wl->dev, WL12XX_BUS_BLOCK_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -55,12 +57,12 @@ bool wl1271_set_block_size(struct wl1271 *wl)
|
|||
|
||||
void wl1271_disable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
wl->if_ops->disable_irq(wl);
|
||||
disable_irq(wl->irq);
|
||||
}
|
||||
|
||||
void wl1271_enable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
wl->if_ops->enable_irq(wl);
|
||||
enable_irq(wl->irq);
|
||||
}
|
||||
|
||||
/* Set the SPI partitions to access the chip addresses
|
||||
|
@ -128,13 +130,13 @@ EXPORT_SYMBOL_GPL(wl1271_set_partition);
|
|||
void wl1271_io_reset(struct wl1271 *wl)
|
||||
{
|
||||
if (wl->if_ops->reset)
|
||||
wl->if_ops->reset(wl);
|
||||
wl->if_ops->reset(wl->dev);
|
||||
}
|
||||
|
||||
void wl1271_io_init(struct wl1271 *wl)
|
||||
{
|
||||
if (wl->if_ops->init)
|
||||
wl->if_ops->init(wl);
|
||||
wl->if_ops->init(wl->dev);
|
||||
}
|
||||
|
||||
void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val)
|
||||
|
|
|
@ -51,23 +51,17 @@ void wl1271_enable_interrupts(struct wl1271 *wl);
|
|||
void wl1271_io_reset(struct wl1271 *wl);
|
||||
void wl1271_io_init(struct wl1271 *wl);
|
||||
|
||||
static inline struct device *wl1271_wl_to_dev(struct wl1271 *wl)
|
||||
{
|
||||
return wl->if_ops->dev(wl);
|
||||
}
|
||||
|
||||
|
||||
/* Raw target IO, address is not translated */
|
||||
static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
{
|
||||
wl->if_ops->write(wl, addr, buf, len, fixed);
|
||||
wl->if_ops->write(wl->dev, addr, buf, len, fixed);
|
||||
}
|
||||
|
||||
static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
{
|
||||
wl->if_ops->read(wl, addr, buf, len, fixed);
|
||||
wl->if_ops->read(wl->dev, addr, buf, len, fixed);
|
||||
}
|
||||
|
||||
static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr)
|
||||
|
@ -155,13 +149,13 @@ static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val)
|
|||
|
||||
static inline void wl1271_power_off(struct wl1271 *wl)
|
||||
{
|
||||
wl->if_ops->power(wl, false);
|
||||
wl->if_ops->power(wl->dev, false);
|
||||
clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
|
||||
}
|
||||
|
||||
static inline int wl1271_power_on(struct wl1271 *wl)
|
||||
{
|
||||
int ret = wl->if_ops->power(wl, true);
|
||||
int ret = wl->if_ops->power(wl->dev, true);
|
||||
if (ret == 0)
|
||||
set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
|
||||
|
||||
|
@ -176,15 +170,10 @@ u16 wl1271_top_reg_read(struct wl1271 *wl, int addr);
|
|||
int wl1271_set_partition(struct wl1271 *wl,
|
||||
struct wl1271_partition_set *p);
|
||||
|
||||
bool wl1271_set_block_size(struct wl1271 *wl);
|
||||
|
||||
/* Functions from wl1271_main.c */
|
||||
|
||||
int wl1271_register_hw(struct wl1271 *wl);
|
||||
void wl1271_unregister_hw(struct wl1271 *wl);
|
||||
int wl1271_init_ieee80211(struct wl1271 *wl);
|
||||
struct ieee80211_hw *wl1271_alloc_hw(void);
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -25,6 +25,7 @@
|
|||
#include "ps.h"
|
||||
#include "io.h"
|
||||
#include "tx.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define WL1271_WAKEUP_TIMEOUT 500
|
||||
|
||||
|
@ -32,6 +33,7 @@ void wl1271_elp_work(struct work_struct *work)
|
|||
{
|
||||
struct delayed_work *dwork;
|
||||
struct wl1271 *wl;
|
||||
struct wl12xx_vif *wlvif;
|
||||
|
||||
dwork = container_of(work, struct delayed_work, work);
|
||||
wl = container_of(dwork, struct wl1271, elp_work);
|
||||
|
@ -47,11 +49,15 @@ void wl1271_elp_work(struct work_struct *work)
|
|||
if (unlikely(!test_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))
|
||||
goto out;
|
||||
|
||||
if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) ||
|
||||
(!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
|
||||
!test_bit(WL1271_FLAG_IDLE, &wl->flags)))
|
||||
if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags))
|
||||
goto out;
|
||||
|
||||
wl12xx_for_each_wlvif(wl, wlvif) {
|
||||
if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) &&
|
||||
!test_bit(WL1271_FLAG_IDLE, &wl->flags))
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_PSM, "chip to elp");
|
||||
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
|
||||
set_bit(WL1271_FLAG_IN_ELP, &wl->flags);
|
||||
|
@ -65,13 +71,17 @@ out:
|
|||
/* Routines to toggle sleep mode while in ELP */
|
||||
void wl1271_ps_elp_sleep(struct wl1271 *wl)
|
||||
{
|
||||
struct wl12xx_vif *wlvif;
|
||||
|
||||
/* we shouldn't get consecutive sleep requests */
|
||||
if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))
|
||||
return;
|
||||
|
||||
if (!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
|
||||
wl12xx_for_each_wlvif(wl, wlvif) {
|
||||
if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) &&
|
||||
!test_bit(WL1271_FLAG_IDLE, &wl->flags))
|
||||
return;
|
||||
}
|
||||
|
||||
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
|
||||
msecs_to_jiffies(ELP_ENTRY_DELAY));
|
||||
|
@ -143,8 +153,8 @@ out:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
|
||||
u32 rates, bool send)
|
||||
int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum wl1271_cmd_ps_mode mode, u32 rates, bool send)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -152,39 +162,34 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
|
|||
case STATION_POWER_SAVE_MODE:
|
||||
wl1271_debug(DEBUG_PSM, "entering psm");
|
||||
|
||||
ret = wl1271_acx_wake_up_conditions(wl);
|
||||
ret = wl1271_acx_wake_up_conditions(wl, wlvif);
|
||||
if (ret < 0) {
|
||||
wl1271_error("couldn't set wake up conditions");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
|
||||
ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_POWER_SAVE_MODE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
set_bit(WL1271_FLAG_PSM, &wl->flags);
|
||||
set_bit(WLVIF_FLAG_PSM, &wlvif->flags);
|
||||
break;
|
||||
case STATION_ACTIVE_MODE:
|
||||
default:
|
||||
wl1271_debug(DEBUG_PSM, "leaving psm");
|
||||
|
||||
/* disable beacon early termination */
|
||||
if (wl->band == IEEE80211_BAND_2GHZ) {
|
||||
ret = wl1271_acx_bet_enable(wl, false);
|
||||
if (wlvif->band == IEEE80211_BAND_2GHZ) {
|
||||
ret = wl1271_acx_bet_enable(wl, wlvif, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* disable beacon filtering */
|
||||
ret = wl1271_acx_beacon_filter_opt(wl, false);
|
||||
ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_ACTIVE_MODE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
clear_bit(WL1271_FLAG_PSM, &wl->flags);
|
||||
clear_bit(WLVIF_FLAG_PSM, &wlvif->flags);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -223,9 +228,11 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
|
|||
wl1271_handle_tx_low_watermark(wl);
|
||||
}
|
||||
|
||||
void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues)
|
||||
void wl12xx_ps_link_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 hlid, bool clean_queues)
|
||||
{
|
||||
struct ieee80211_sta *sta;
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
|
||||
if (test_bit(hlid, &wl->ap_ps_map))
|
||||
return;
|
||||
|
@ -235,7 +242,7 @@ void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues)
|
|||
clean_queues);
|
||||
|
||||
rcu_read_lock();
|
||||
sta = ieee80211_find_sta(wl->vif, wl->links[hlid].addr);
|
||||
sta = ieee80211_find_sta(vif, wl->links[hlid].addr);
|
||||
if (!sta) {
|
||||
wl1271_error("could not find sta %pM for starting ps",
|
||||
wl->links[hlid].addr);
|
||||
|
@ -253,9 +260,10 @@ void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues)
|
|||
__set_bit(hlid, &wl->ap_ps_map);
|
||||
}
|
||||
|
||||
void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid)
|
||||
void wl12xx_ps_link_end(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
|
||||
{
|
||||
struct ieee80211_sta *sta;
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
|
||||
if (!test_bit(hlid, &wl->ap_ps_map))
|
||||
return;
|
||||
|
@ -265,7 +273,7 @@ void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid)
|
|||
__clear_bit(hlid, &wl->ap_ps_map);
|
||||
|
||||
rcu_read_lock();
|
||||
sta = ieee80211_find_sta(wl->vif, wl->links[hlid].addr);
|
||||
sta = ieee80211_find_sta(vif, wl->links[hlid].addr);
|
||||
if (!sta) {
|
||||
wl1271_error("could not find sta %pM for ending ps",
|
||||
wl->links[hlid].addr);
|
||||
|
|
|
@ -27,13 +27,14 @@
|
|||
#include "wl12xx.h"
|
||||
#include "acx.h"
|
||||
|
||||
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
|
||||
u32 rates, bool send);
|
||||
int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum wl1271_cmd_ps_mode mode, u32 rates, bool send);
|
||||
void wl1271_ps_elp_sleep(struct wl1271 *wl);
|
||||
int wl1271_ps_elp_wakeup(struct wl1271 *wl);
|
||||
void wl1271_elp_work(struct work_struct *work);
|
||||
void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues);
|
||||
void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid);
|
||||
void wl12xx_ps_link_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 hlid, bool clean_queues);
|
||||
void wl12xx_ps_link_end(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
|
||||
|
||||
#define WL1271_PS_COMPLETE_TIMEOUT 500
|
||||
|
||||
|
|
|
@ -408,7 +408,7 @@
|
|||
|
||||
|
||||
/* Firmware image load chunk size */
|
||||
#define CHUNK_SIZE 512
|
||||
#define CHUNK_SIZE 16384
|
||||
|
||||
/* Firmware image header size */
|
||||
#define FW_HDR_SIZE 8
|
||||
|
|
|
@ -25,9 +25,11 @@
|
|||
#include <linux/sched.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "acx.h"
|
||||
#include "reg.h"
|
||||
#include "rx.h"
|
||||
#include "tx.h"
|
||||
#include "io.h"
|
||||
|
||||
static u8 wl12xx_rx_get_mem_block(struct wl12xx_fw_status *status,
|
||||
|
@ -96,7 +98,7 @@ static void wl1271_rx_status(struct wl1271 *wl,
|
|||
}
|
||||
|
||||
static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||
bool unaligned)
|
||||
bool unaligned, u8 *hlid)
|
||||
{
|
||||
struct wl1271_rx_descriptor *desc;
|
||||
struct sk_buff *skb;
|
||||
|
@ -159,6 +161,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
|||
* payload aligned to 4 bytes.
|
||||
*/
|
||||
memcpy(buf, data + sizeof(*desc), length - sizeof(*desc));
|
||||
*hlid = desc->hlid;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
if (ieee80211_is_beacon(hdr->frame_control))
|
||||
|
@ -169,10 +172,10 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
|||
wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
|
||||
|
||||
seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
|
||||
wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d", skb,
|
||||
wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb,
|
||||
skb->len - desc->pad_len,
|
||||
beacon ? "beacon" : "",
|
||||
seq_num);
|
||||
seq_num, *hlid);
|
||||
|
||||
skb_trim(skb, skb->len - desc->pad_len);
|
||||
|
||||
|
@ -185,6 +188,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
|||
void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
|
||||
{
|
||||
struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
|
||||
unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
|
||||
u32 buf_size;
|
||||
u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
|
||||
u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
|
||||
|
@ -192,8 +196,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
|
|||
u32 mem_block;
|
||||
u32 pkt_length;
|
||||
u32 pkt_offset;
|
||||
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
|
||||
bool had_data = false;
|
||||
u8 hlid;
|
||||
bool unaligned = false;
|
||||
|
||||
while (drv_rx_counter != fw_rx_counter) {
|
||||
|
@ -253,8 +256,11 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
|
|||
*/
|
||||
if (wl1271_rx_handle_data(wl,
|
||||
wl->aggr_buf + pkt_offset,
|
||||
pkt_length, unaligned) == 1)
|
||||
had_data = true;
|
||||
pkt_length, unaligned,
|
||||
&hlid) == 1) {
|
||||
WARN_ON(hlid >= WL12XX_MAX_LINKS);
|
||||
__set_bit(hlid, active_hlids);
|
||||
}
|
||||
|
||||
wl->rx_counter++;
|
||||
drv_rx_counter++;
|
||||
|
@ -270,17 +276,5 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
|
|||
if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION)
|
||||
wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
|
||||
|
||||
if (!is_ap && wl->conf.rx_streaming.interval && had_data &&
|
||||
(wl->conf.rx_streaming.always ||
|
||||
test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) {
|
||||
u32 timeout = wl->conf.rx_streaming.duration;
|
||||
|
||||
/* restart rx streaming */
|
||||
if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
|
||||
ieee80211_queue_work(wl->hw,
|
||||
&wl->rx_streaming_enable_work);
|
||||
|
||||
mod_timer(&wl->rx_streaming_timer,
|
||||
jiffies + msecs_to_jiffies(timeout));
|
||||
}
|
||||
wl12xx_rearm_rx_streaming(wl, active_hlids);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/ieee80211.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "cmd.h"
|
||||
#include "scan.h"
|
||||
#include "acx.h"
|
||||
|
@ -34,6 +35,8 @@ void wl1271_scan_complete_work(struct work_struct *work)
|
|||
{
|
||||
struct delayed_work *dwork;
|
||||
struct wl1271 *wl;
|
||||
struct ieee80211_vif *vif;
|
||||
struct wl12xx_vif *wlvif;
|
||||
int ret;
|
||||
bool is_sta, is_ibss;
|
||||
|
||||
|
@ -50,28 +53,31 @@ void wl1271_scan_complete_work(struct work_struct *work)
|
|||
if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
|
||||
goto out;
|
||||
|
||||
vif = wl->scan_vif;
|
||||
wlvif = wl12xx_vif_to_data(vif);
|
||||
|
||||
wl->scan.state = WL1271_SCAN_STATE_IDLE;
|
||||
memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
|
||||
wl->scan.req = NULL;
|
||||
wl->scan_vif = NULL;
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
|
||||
if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
|
||||
/* restore hardware connection monitoring template */
|
||||
wl1271_cmd_build_ap_probe_req(wl, wl->probereq);
|
||||
wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->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))) &&
|
||||
!test_bit(wl->dev_role_id, wl->roc_map)) {
|
||||
is_sta = (wlvif->bss_type == BSS_TYPE_STA_BSS);
|
||||
is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
|
||||
if (((is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) ||
|
||||
(is_ibss && !test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags))) &&
|
||||
!test_bit(wlvif->dev_role_id, wl->roc_map)) {
|
||||
/* restore remain on channel */
|
||||
wl12xx_cmd_role_start_dev(wl);
|
||||
wl12xx_roc(wl, wl->dev_role_id);
|
||||
wl12xx_start_dev(wl, wlvif);
|
||||
}
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
|
||||
|
@ -155,9 +161,11 @@ static int wl1271_get_scan_channels(struct wl1271 *wl,
|
|||
|
||||
#define WL1271_NOTHING_TO_SCAN 1
|
||||
|
||||
static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
|
||||
static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif,
|
||||
enum ieee80211_band band,
|
||||
bool passive, u32 basic_rate)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
struct wl1271_cmd_scan *cmd;
|
||||
struct wl1271_cmd_trigger_scan_to *trigger;
|
||||
int ret;
|
||||
|
@ -177,11 +185,11 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
|
|||
if (passive)
|
||||
scan_options |= WL1271_SCAN_OPT_PASSIVE;
|
||||
|
||||
if (WARN_ON(wl->role_id == WL12XX_INVALID_ROLE_ID)) {
|
||||
if (WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
cmd->params.role_id = wl->role_id;
|
||||
cmd->params.role_id = wlvif->role_id;
|
||||
cmd->params.scan_options = cpu_to_le16(scan_options);
|
||||
|
||||
cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
|
||||
|
@ -194,7 +202,6 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
|
|||
|
||||
cmd->params.tx_rate = cpu_to_le32(basic_rate);
|
||||
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;
|
||||
cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
|
||||
|
||||
|
@ -208,11 +215,11 @@ 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);
|
||||
memcpy(cmd->addr, vif->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);
|
||||
ret = wl1271_cmd_build_probe_req(wl, wlvif, wl->scan.ssid,
|
||||
wl->scan.ssid_len, wl->scan.req->ie,
|
||||
wl->scan.req->ie_len, band);
|
||||
if (ret < 0) {
|
||||
wl1271_error("PROBE request template failed");
|
||||
goto out;
|
||||
|
@ -241,11 +248,12 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
void wl1271_scan_stm(struct wl1271 *wl)
|
||||
void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
int ret = 0;
|
||||
enum ieee80211_band band;
|
||||
u32 rate;
|
||||
u32 rate, mask;
|
||||
|
||||
switch (wl->scan.state) {
|
||||
case WL1271_SCAN_STATE_IDLE:
|
||||
|
@ -253,47 +261,59 @@ void wl1271_scan_stm(struct wl1271 *wl)
|
|||
|
||||
case WL1271_SCAN_STATE_2GHZ_ACTIVE:
|
||||
band = IEEE80211_BAND_2GHZ;
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
|
||||
ret = wl1271_scan_send(wl, band, false, rate);
|
||||
mask = wlvif->bitrate_masks[band];
|
||||
if (wl->scan.req->no_cck) {
|
||||
mask &= ~CONF_TX_CCK_RATES;
|
||||
if (!mask)
|
||||
mask = CONF_TX_RATE_MASK_BASIC_P2P;
|
||||
}
|
||||
rate = wl1271_tx_min_rate_get(wl, mask);
|
||||
ret = wl1271_scan_send(wl, vif, band, false, rate);
|
||||
if (ret == WL1271_NOTHING_TO_SCAN) {
|
||||
wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
|
||||
wl1271_scan_stm(wl);
|
||||
wl1271_scan_stm(wl, vif);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case WL1271_SCAN_STATE_2GHZ_PASSIVE:
|
||||
band = IEEE80211_BAND_2GHZ;
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
|
||||
ret = wl1271_scan_send(wl, band, true, rate);
|
||||
mask = wlvif->bitrate_masks[band];
|
||||
if (wl->scan.req->no_cck) {
|
||||
mask &= ~CONF_TX_CCK_RATES;
|
||||
if (!mask)
|
||||
mask = CONF_TX_RATE_MASK_BASIC_P2P;
|
||||
}
|
||||
rate = wl1271_tx_min_rate_get(wl, mask);
|
||||
ret = wl1271_scan_send(wl, vif, band, true, rate);
|
||||
if (ret == WL1271_NOTHING_TO_SCAN) {
|
||||
if (wl->enable_11a)
|
||||
wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
|
||||
else
|
||||
wl->scan.state = WL1271_SCAN_STATE_DONE;
|
||||
wl1271_scan_stm(wl);
|
||||
wl1271_scan_stm(wl, vif);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case WL1271_SCAN_STATE_5GHZ_ACTIVE:
|
||||
band = IEEE80211_BAND_5GHZ;
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
|
||||
ret = wl1271_scan_send(wl, band, false, rate);
|
||||
rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
|
||||
ret = wl1271_scan_send(wl, vif, band, false, rate);
|
||||
if (ret == WL1271_NOTHING_TO_SCAN) {
|
||||
wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
|
||||
wl1271_scan_stm(wl);
|
||||
wl1271_scan_stm(wl, vif);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case WL1271_SCAN_STATE_5GHZ_PASSIVE:
|
||||
band = IEEE80211_BAND_5GHZ;
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
|
||||
ret = wl1271_scan_send(wl, band, true, rate);
|
||||
rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
|
||||
ret = wl1271_scan_send(wl, vif, band, true, rate);
|
||||
if (ret == WL1271_NOTHING_TO_SCAN) {
|
||||
wl->scan.state = WL1271_SCAN_STATE_DONE;
|
||||
wl1271_scan_stm(wl);
|
||||
wl1271_scan_stm(wl, vif);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -317,7 +337,8 @@ void wl1271_scan_stm(struct wl1271 *wl)
|
|||
}
|
||||
}
|
||||
|
||||
int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
|
||||
int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
/*
|
||||
|
@ -338,6 +359,7 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
|
|||
wl->scan.ssid_len = 0;
|
||||
}
|
||||
|
||||
wl->scan_vif = vif;
|
||||
wl->scan.req = req;
|
||||
memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
|
||||
|
||||
|
@ -346,7 +368,7 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
|
|||
ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
|
||||
msecs_to_jiffies(WL1271_SCAN_TIMEOUT));
|
||||
|
||||
wl1271_scan_stm(wl);
|
||||
wl1271_scan_stm(wl, vif);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -550,6 +572,9 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
|
|||
* so they're used in probe requests.
|
||||
*/
|
||||
for (i = 0; i < req->n_ssids; i++) {
|
||||
if (!req->ssids[i].ssid_len)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < cmd->n_ssids; j++)
|
||||
if (!memcmp(req->ssids[i].ssid,
|
||||
cmd->ssids[j].ssid,
|
||||
|
@ -585,6 +610,7 @@ out:
|
|||
}
|
||||
|
||||
int wl1271_scan_sched_scan_config(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct cfg80211_sched_scan_request *req,
|
||||
struct ieee80211_sched_scan_ies *ies)
|
||||
{
|
||||
|
@ -631,7 +657,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
|
|||
}
|
||||
|
||||
if (!force_passive && cfg->active[0]) {
|
||||
ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid,
|
||||
ret = wl1271_cmd_build_probe_req(wl, wlvif, req->ssids[0].ssid,
|
||||
req->ssids[0].ssid_len,
|
||||
ies->ie[IEEE80211_BAND_2GHZ],
|
||||
ies->len[IEEE80211_BAND_2GHZ],
|
||||
|
@ -643,7 +669,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
|
|||
}
|
||||
|
||||
if (!force_passive && cfg->active[1]) {
|
||||
ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid,
|
||||
ret = wl1271_cmd_build_probe_req(wl, wlvif, req->ssids[0].ssid,
|
||||
req->ssids[0].ssid_len,
|
||||
ies->ie[IEEE80211_BAND_5GHZ],
|
||||
ies->len[IEEE80211_BAND_5GHZ],
|
||||
|
@ -667,14 +693,14 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_scan_sched_scan_start(struct wl1271 *wl)
|
||||
int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl1271_cmd_sched_scan_start *start;
|
||||
int ret = 0;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd periodic scan start");
|
||||
|
||||
if (wl->bss_type != BSS_TYPE_STA_BSS)
|
||||
if (wlvif->bss_type != BSS_TYPE_STA_BSS)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!test_bit(WL1271_FLAG_IDLE, &wl->flags))
|
||||
|
|
|
@ -26,18 +26,20 @@
|
|||
|
||||
#include "wl12xx.h"
|
||||
|
||||
int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
|
||||
int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
struct cfg80211_scan_request *req);
|
||||
int wl1271_scan_stop(struct wl1271 *wl);
|
||||
int wl1271_scan_build_probe_req(struct wl1271 *wl,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *ie, size_t ie_len, u8 band);
|
||||
void wl1271_scan_stm(struct wl1271 *wl);
|
||||
void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif);
|
||||
void wl1271_scan_complete_work(struct work_struct *work);
|
||||
int wl1271_scan_sched_scan_config(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct cfg80211_sched_scan_request *req,
|
||||
struct ieee80211_sched_scan_ies *ies);
|
||||
int wl1271_scan_sched_scan_start(struct wl1271 *wl);
|
||||
int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
void wl1271_scan_sched_scan_stop(struct wl1271 *wl);
|
||||
void wl1271_scan_sched_scan_results(struct wl1271 *wl);
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
#include <linux/mmc/sdio_ids.h>
|
||||
#include <linux/mmc/card.h>
|
||||
|
@ -44,77 +45,38 @@
|
|||
#define SDIO_DEVICE_ID_TI_WL1271 0x4076
|
||||
#endif
|
||||
|
||||
struct wl12xx_sdio_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *core;
|
||||
};
|
||||
|
||||
static const struct sdio_device_id wl1271_devices[] __devinitconst = {
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(sdio, wl1271_devices);
|
||||
|
||||
static void wl1271_sdio_set_block_size(struct wl1271 *wl, unsigned int blksz)
|
||||
static void wl1271_sdio_set_block_size(struct device *child,
|
||||
unsigned int blksz)
|
||||
{
|
||||
sdio_claim_host(wl->if_priv);
|
||||
sdio_set_block_size(wl->if_priv, blksz);
|
||||
sdio_release_host(wl->if_priv);
|
||||
struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
|
||||
struct sdio_func *func = dev_to_sdio_func(glue->dev);
|
||||
|
||||
sdio_claim_host(func);
|
||||
sdio_set_block_size(func, blksz);
|
||||
sdio_release_host(func);
|
||||
}
|
||||
|
||||
static inline struct sdio_func *wl_to_func(struct wl1271 *wl)
|
||||
{
|
||||
return wl->if_priv;
|
||||
}
|
||||
|
||||
static struct device *wl1271_sdio_wl_to_dev(struct wl1271 *wl)
|
||||
{
|
||||
return &(wl_to_func(wl)->dev);
|
||||
}
|
||||
|
||||
static irqreturn_t wl1271_hardirq(int irq, void *cookie)
|
||||
{
|
||||
struct wl1271 *wl = cookie;
|
||||
unsigned long flags;
|
||||
|
||||
wl1271_debug(DEBUG_IRQ, "IRQ");
|
||||
|
||||
/* complete the ELP completion */
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
|
||||
if (wl->elp_compl) {
|
||||
complete(wl->elp_compl);
|
||||
wl->elp_compl = NULL;
|
||||
}
|
||||
|
||||
if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
|
||||
/* don't enqueue a work right now. mark it as pending */
|
||||
set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
|
||||
wl1271_debug(DEBUG_IRQ, "should not enqueue work");
|
||||
disable_irq_nosync(wl->irq);
|
||||
pm_wakeup_event(wl1271_sdio_wl_to_dev(wl), 0);
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static void wl1271_sdio_disable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
disable_irq(wl->irq);
|
||||
}
|
||||
|
||||
static void wl1271_sdio_enable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
enable_irq(wl->irq);
|
||||
}
|
||||
|
||||
static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,
|
||||
static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
{
|
||||
int ret;
|
||||
struct sdio_func *func = wl_to_func(wl);
|
||||
struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
|
||||
struct sdio_func *func = dev_to_sdio_func(glue->dev);
|
||||
|
||||
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
|
||||
((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
|
||||
wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x",
|
||||
dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n",
|
||||
addr, ((u8 *)buf)[0]);
|
||||
} else {
|
||||
if (fixed)
|
||||
|
@ -122,29 +84,28 @@ static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,
|
|||
else
|
||||
ret = sdio_memcpy_fromio(func, buf, addr, len);
|
||||
|
||||
wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %zu bytes",
|
||||
dev_dbg(child->parent, "sdio read 53 addr 0x%x, %zu bytes\n",
|
||||
addr, len);
|
||||
wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
wl1271_error("sdio read failed (%d)", ret);
|
||||
dev_err(child->parent, "sdio read failed (%d)\n", ret);
|
||||
}
|
||||
|
||||
static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,
|
||||
static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
{
|
||||
int ret;
|
||||
struct sdio_func *func = wl_to_func(wl);
|
||||
struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
|
||||
struct sdio_func *func = dev_to_sdio_func(glue->dev);
|
||||
|
||||
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
|
||||
sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
|
||||
wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x",
|
||||
dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n",
|
||||
addr, ((u8 *)buf)[0]);
|
||||
} else {
|
||||
wl1271_debug(DEBUG_SDIO, "sdio write 53 addr 0x%x, %zu bytes",
|
||||
dev_dbg(child->parent, "sdio write 53 addr 0x%x, %zu bytes\n",
|
||||
addr, len);
|
||||
wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
|
||||
|
||||
if (fixed)
|
||||
ret = sdio_writesb(func, addr, buf, len);
|
||||
|
@ -153,13 +114,13 @@ static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,
|
|||
}
|
||||
|
||||
if (ret)
|
||||
wl1271_error("sdio write failed (%d)", ret);
|
||||
dev_err(child->parent, "sdio write failed (%d)\n", ret);
|
||||
}
|
||||
|
||||
static int wl1271_sdio_power_on(struct wl1271 *wl)
|
||||
static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue)
|
||||
{
|
||||
struct sdio_func *func = wl_to_func(wl);
|
||||
int ret;
|
||||
struct sdio_func *func = dev_to_sdio_func(glue->dev);
|
||||
|
||||
/* If enabled, tell runtime PM not to power off the card */
|
||||
if (pm_runtime_enabled(&func->dev)) {
|
||||
|
@ -180,10 +141,10 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_sdio_power_off(struct wl1271 *wl)
|
||||
static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue)
|
||||
{
|
||||
struct sdio_func *func = wl_to_func(wl);
|
||||
int ret;
|
||||
struct sdio_func *func = dev_to_sdio_func(glue->dev);
|
||||
|
||||
sdio_disable_func(func);
|
||||
sdio_release_host(func);
|
||||
|
@ -200,46 +161,43 @@ static int wl1271_sdio_power_off(struct wl1271 *wl)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
|
||||
static int wl12xx_sdio_set_power(struct device *child, bool enable)
|
||||
{
|
||||
struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
|
||||
|
||||
if (enable)
|
||||
return wl1271_sdio_power_on(wl);
|
||||
return wl12xx_sdio_power_on(glue);
|
||||
else
|
||||
return wl1271_sdio_power_off(wl);
|
||||
return wl12xx_sdio_power_off(glue);
|
||||
}
|
||||
|
||||
static struct wl1271_if_operations sdio_ops = {
|
||||
.read = wl1271_sdio_raw_read,
|
||||
.write = wl1271_sdio_raw_write,
|
||||
.power = wl1271_sdio_set_power,
|
||||
.dev = wl1271_sdio_wl_to_dev,
|
||||
.enable_irq = wl1271_sdio_enable_interrupts,
|
||||
.disable_irq = wl1271_sdio_disable_interrupts,
|
||||
.read = wl12xx_sdio_raw_read,
|
||||
.write = wl12xx_sdio_raw_write,
|
||||
.power = wl12xx_sdio_set_power,
|
||||
.set_block_size = wl1271_sdio_set_block_size,
|
||||
};
|
||||
|
||||
static int __devinit wl1271_probe(struct sdio_func *func,
|
||||
const struct sdio_device_id *id)
|
||||
{
|
||||
struct ieee80211_hw *hw;
|
||||
const struct wl12xx_platform_data *wlan_data;
|
||||
struct wl1271 *wl;
|
||||
unsigned long irqflags;
|
||||
struct wl12xx_platform_data *wlan_data;
|
||||
struct wl12xx_sdio_glue *glue;
|
||||
struct resource res[1];
|
||||
mmc_pm_flag_t mmcflags;
|
||||
int ret;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
/* We are only able to handle the wlan function */
|
||||
if (func->num != 0x02)
|
||||
return -ENODEV;
|
||||
|
||||
hw = wl1271_alloc_hw();
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue) {
|
||||
dev_err(&func->dev, "can't allocate glue\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl = hw->priv;
|
||||
|
||||
wl->if_priv = func;
|
||||
wl->if_ops = &sdio_ops;
|
||||
glue->dev = &func->dev;
|
||||
|
||||
/* Grab access to FN0 for ELP reg. */
|
||||
func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
|
||||
|
@ -250,80 +208,79 @@ static int __devinit wl1271_probe(struct sdio_func *func,
|
|||
wlan_data = wl12xx_get_platform_data();
|
||||
if (IS_ERR(wlan_data)) {
|
||||
ret = PTR_ERR(wlan_data);
|
||||
wl1271_error("missing wlan platform data: %d", ret);
|
||||
goto out_free;
|
||||
dev_err(glue->dev, "missing wlan platform data: %d\n", ret);
|
||||
goto out_free_glue;
|
||||
}
|
||||
|
||||
wl->irq = wlan_data->irq;
|
||||
wl->ref_clock = wlan_data->board_ref_clock;
|
||||
wl->tcxo_clock = wlan_data->board_tcxo_clock;
|
||||
wl->platform_quirks = wlan_data->platform_quirks;
|
||||
|
||||
if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
|
||||
irqflags = IRQF_TRIGGER_RISING;
|
||||
else
|
||||
irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
|
||||
|
||||
ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq,
|
||||
irqflags,
|
||||
DRIVER_NAME, wl);
|
||||
if (ret < 0) {
|
||||
wl1271_error("request_irq() failed: %d", ret);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
ret = enable_irq_wake(wl->irq);
|
||||
if (!ret) {
|
||||
wl->irq_wake_enabled = true;
|
||||
device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1);
|
||||
|
||||
/* if sdio can keep power while host is suspended, enable wow */
|
||||
mmcflags = sdio_get_host_pm_caps(func);
|
||||
wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags);
|
||||
dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags);
|
||||
|
||||
if (mmcflags & MMC_PM_KEEP_POWER)
|
||||
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
|
||||
}
|
||||
disable_irq(wl->irq);
|
||||
wlan_data->pwr_in_suspend = true;
|
||||
|
||||
ret = wl1271_init_ieee80211(wl);
|
||||
if (ret)
|
||||
goto out_irq;
|
||||
wlan_data->ops = &sdio_ops;
|
||||
|
||||
ret = wl1271_register_hw(wl);
|
||||
if (ret)
|
||||
goto out_irq;
|
||||
|
||||
sdio_set_drvdata(func, wl);
|
||||
sdio_set_drvdata(func, glue);
|
||||
|
||||
/* Tell PM core that we don't need the card to be powered now */
|
||||
pm_runtime_put_noidle(&func->dev);
|
||||
|
||||
glue->core = platform_device_alloc("wl12xx", -1);
|
||||
if (!glue->core) {
|
||||
dev_err(glue->dev, "can't allocate platform_device");
|
||||
ret = -ENOMEM;
|
||||
goto out_free_glue;
|
||||
}
|
||||
|
||||
glue->core->dev.parent = &func->dev;
|
||||
|
||||
memset(res, 0x00, sizeof(res));
|
||||
|
||||
res[0].start = wlan_data->irq;
|
||||
res[0].flags = IORESOURCE_IRQ;
|
||||
res[0].name = "irq";
|
||||
|
||||
ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res));
|
||||
if (ret) {
|
||||
dev_err(glue->dev, "can't add resources\n");
|
||||
goto out_dev_put;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(glue->core, wlan_data,
|
||||
sizeof(*wlan_data));
|
||||
if (ret) {
|
||||
dev_err(glue->dev, "can't add platform data\n");
|
||||
goto out_dev_put;
|
||||
}
|
||||
|
||||
ret = platform_device_add(glue->core);
|
||||
if (ret) {
|
||||
dev_err(glue->dev, "can't add platform device\n");
|
||||
goto out_dev_put;
|
||||
}
|
||||
return 0;
|
||||
|
||||
out_irq:
|
||||
free_irq(wl->irq, wl);
|
||||
out_dev_put:
|
||||
platform_device_put(glue->core);
|
||||
|
||||
out_free:
|
||||
wl1271_free_hw(wl);
|
||||
out_free_glue:
|
||||
kfree(glue);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit wl1271_remove(struct sdio_func *func)
|
||||
{
|
||||
struct wl1271 *wl = sdio_get_drvdata(func);
|
||||
struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func);
|
||||
|
||||
/* Undo decrement done above in wl1271_probe */
|
||||
pm_runtime_get_noresume(&func->dev);
|
||||
|
||||
wl1271_unregister_hw(wl);
|
||||
if (wl->irq_wake_enabled) {
|
||||
device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 0);
|
||||
disable_irq_wake(wl->irq);
|
||||
}
|
||||
free_irq(wl->irq, wl);
|
||||
wl1271_free_hw(wl);
|
||||
platform_device_del(glue->core);
|
||||
platform_device_put(glue->core);
|
||||
kfree(glue);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
@ -332,11 +289,12 @@ static int wl1271_suspend(struct device *dev)
|
|||
/* Tell MMC/SDIO core it's OK to power down the card
|
||||
* (if it isn't already), but not to remove it completely */
|
||||
struct sdio_func *func = dev_to_sdio_func(dev);
|
||||
struct wl1271 *wl = sdio_get_drvdata(func);
|
||||
struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func);
|
||||
struct wl1271 *wl = platform_get_drvdata(glue->core);
|
||||
mmc_pm_flag_t sdio_flags;
|
||||
int ret = 0;
|
||||
|
||||
wl1271_debug(DEBUG_MAC80211, "wl1271 suspend. wow_enabled: %d",
|
||||
dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n",
|
||||
wl->wow_enabled);
|
||||
|
||||
/* check whether sdio should keep power */
|
||||
|
@ -344,8 +302,8 @@ static int wl1271_suspend(struct device *dev)
|
|||
sdio_flags = sdio_get_host_pm_caps(func);
|
||||
|
||||
if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
|
||||
wl1271_error("can't keep power while host "
|
||||
"is suspended");
|
||||
dev_err(dev, "can't keep power while host "
|
||||
"is suspended\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
@ -353,7 +311,7 @@ static int wl1271_suspend(struct device *dev)
|
|||
/* keep power while host suspended */
|
||||
ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
|
||||
if (ret) {
|
||||
wl1271_error("error while trying to keep power");
|
||||
dev_err(dev, "error while trying to keep power\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -367,9 +325,10 @@ out:
|
|||
static int wl1271_resume(struct device *dev)
|
||||
{
|
||||
struct sdio_func *func = dev_to_sdio_func(dev);
|
||||
struct wl1271 *wl = sdio_get_drvdata(func);
|
||||
struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func);
|
||||
struct wl1271 *wl = platform_get_drvdata(glue->core);
|
||||
|
||||
wl1271_debug(DEBUG_MAC80211, "wl1271 resume");
|
||||
dev_dbg(dev, "wl1271 resume\n");
|
||||
if (wl->wow_enabled) {
|
||||
/* claim back host */
|
||||
sdio_claim_host(func);
|
||||
|
|
|
@ -1,543 +0,0 @@
|
|||
/*
|
||||
* SDIO testing driver for wl12xx
|
||||
*
|
||||
* Copyright (C) 2010 Nokia Corporation
|
||||
*
|
||||
* Contact: Roger Quadros <roger.quadros@nokia.com>
|
||||
*
|
||||
* wl12xx read/write routines taken from the main module
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/crc7.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
#include <linux/mmc/sdio_ids.h>
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/wl12xx.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "io.h"
|
||||
#include "boot.h"
|
||||
|
||||
#ifndef SDIO_VENDOR_ID_TI
|
||||
#define SDIO_VENDOR_ID_TI 0x0097
|
||||
#endif
|
||||
|
||||
#ifndef SDIO_DEVICE_ID_TI_WL1271
|
||||
#define SDIO_DEVICE_ID_TI_WL1271 0x4076
|
||||
#endif
|
||||
|
||||
static bool rx, tx;
|
||||
|
||||
module_param(rx, bool, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(rx, "Perform rx test. Default (0). "
|
||||
"This test continuously reads data from the SDIO device.\n");
|
||||
|
||||
module_param(tx, bool, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(tx, "Perform tx test. Default (0). "
|
||||
"This test continuously writes data to the SDIO device.\n");
|
||||
|
||||
struct wl1271_test {
|
||||
struct wl1271 wl;
|
||||
struct task_struct *test_task;
|
||||
};
|
||||
|
||||
static const struct sdio_device_id wl1271_devices[] = {
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) },
|
||||
{}
|
||||
};
|
||||
|
||||
static inline struct sdio_func *wl_to_func(struct wl1271 *wl)
|
||||
{
|
||||
return wl->if_priv;
|
||||
}
|
||||
|
||||
static struct device *wl1271_sdio_wl_to_dev(struct wl1271 *wl)
|
||||
{
|
||||
return &(wl_to_func(wl)->dev);
|
||||
}
|
||||
|
||||
static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sdio_func *func = wl_to_func(wl);
|
||||
|
||||
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
|
||||
((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
|
||||
wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x",
|
||||
addr, ((u8 *)buf)[0]);
|
||||
} else {
|
||||
if (fixed)
|
||||
ret = sdio_readsb(func, buf, addr, len);
|
||||
else
|
||||
ret = sdio_memcpy_fromio(func, buf, addr, len);
|
||||
|
||||
wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %zu bytes",
|
||||
addr, len);
|
||||
wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
wl1271_error("sdio read failed (%d)", ret);
|
||||
}
|
||||
|
||||
static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sdio_func *func = wl_to_func(wl);
|
||||
|
||||
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
|
||||
sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
|
||||
wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x",
|
||||
addr, ((u8 *)buf)[0]);
|
||||
} else {
|
||||
wl1271_debug(DEBUG_SDIO, "sdio write 53 addr 0x%x, %zu bytes",
|
||||
addr, len);
|
||||
wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
|
||||
|
||||
if (fixed)
|
||||
ret = sdio_writesb(func, addr, buf, len);
|
||||
else
|
||||
ret = sdio_memcpy_toio(func, addr, buf, len);
|
||||
}
|
||||
if (ret)
|
||||
wl1271_error("sdio write failed (%d)", ret);
|
||||
|
||||
}
|
||||
|
||||
static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
|
||||
{
|
||||
struct sdio_func *func = wl_to_func(wl);
|
||||
int ret;
|
||||
|
||||
/* Let the SDIO stack handle wlan_enable control, so we
|
||||
* keep host claimed while wlan is in use to keep wl1271
|
||||
* alive.
|
||||
*/
|
||||
if (enable) {
|
||||
/* Power up the card */
|
||||
ret = pm_runtime_get_sync(&func->dev);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* Runtime PM might be disabled, power up the card manually */
|
||||
ret = mmc_power_restore_host(func->card->host);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
sdio_claim_host(func);
|
||||
sdio_enable_func(func);
|
||||
} else {
|
||||
sdio_disable_func(func);
|
||||
sdio_release_host(func);
|
||||
|
||||
/* Runtime PM might be disabled, power off the card manually */
|
||||
ret = mmc_power_save_host(func->card->host);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* Power down the card */
|
||||
ret = pm_runtime_put_sync(&func->dev);
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void wl1271_sdio_disable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
}
|
||||
|
||||
static void wl1271_sdio_enable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static struct wl1271_if_operations sdio_ops = {
|
||||
.read = wl1271_sdio_raw_read,
|
||||
.write = wl1271_sdio_raw_write,
|
||||
.power = wl1271_sdio_set_power,
|
||||
.dev = wl1271_sdio_wl_to_dev,
|
||||
.enable_irq = wl1271_sdio_enable_interrupts,
|
||||
.disable_irq = wl1271_sdio_disable_interrupts,
|
||||
};
|
||||
|
||||
static void wl1271_fw_wakeup(struct wl1271 *wl)
|
||||
{
|
||||
u32 elp_reg;
|
||||
|
||||
elp_reg = ELPCTRL_WAKE_UP;
|
||||
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
|
||||
}
|
||||
|
||||
static int wl1271_fetch_firmware(struct wl1271 *wl)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
int ret;
|
||||
|
||||
if (wl->chip.id == CHIP_ID_1283_PG20)
|
||||
ret = request_firmware(&fw, WL128X_FW_NAME,
|
||||
wl1271_wl_to_dev(wl));
|
||||
else
|
||||
ret = request_firmware(&fw, WL127X_FW_NAME,
|
||||
wl1271_wl_to_dev(wl));
|
||||
|
||||
if (ret < 0) {
|
||||
wl1271_error("could not get firmware: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (fw->size % 4) {
|
||||
wl1271_error("firmware size is not multiple of 32 bits: %zu",
|
||||
fw->size);
|
||||
ret = -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl->fw_len = fw->size;
|
||||
wl->fw = vmalloc(wl->fw_len);
|
||||
|
||||
if (!wl->fw) {
|
||||
wl1271_error("could not allocate memory for the firmware");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(wl->fw, fw->data, wl->fw_len);
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
release_firmware(fw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_fetch_nvs(struct wl1271 *wl)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
int ret;
|
||||
|
||||
ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
|
||||
|
||||
if (ret < 0) {
|
||||
wl1271_error("could not get nvs file: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
|
||||
|
||||
if (!wl->nvs) {
|
||||
wl1271_error("could not allocate memory for the nvs file");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl->nvs_len = fw->size;
|
||||
|
||||
out:
|
||||
release_firmware(fw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_chip_wakeup(struct wl1271 *wl)
|
||||
{
|
||||
struct wl1271_partition_set partition;
|
||||
int ret;
|
||||
|
||||
msleep(WL1271_PRE_POWER_ON_SLEEP);
|
||||
ret = wl1271_power_on(wl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
msleep(WL1271_POWER_ON_SLEEP);
|
||||
|
||||
/* We don't need a real memory partition here, because we only want
|
||||
* to use the registers at this point. */
|
||||
memset(&partition, 0, sizeof(partition));
|
||||
partition.reg.start = REGISTERS_BASE;
|
||||
partition.reg.size = REGISTERS_DOWN_SIZE;
|
||||
wl1271_set_partition(wl, &partition);
|
||||
|
||||
/* ELP module wake up */
|
||||
wl1271_fw_wakeup(wl);
|
||||
|
||||
/* whal_FwCtrl_BootSm() */
|
||||
|
||||
/* 0. read chip id from CHIP_ID */
|
||||
wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
|
||||
|
||||
/* 1. check if chip id is valid */
|
||||
|
||||
switch (wl->chip.id) {
|
||||
case CHIP_ID_1271_PG10:
|
||||
wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
|
||||
wl->chip.id);
|
||||
break;
|
||||
case CHIP_ID_1271_PG20:
|
||||
wl1271_notice("chip id 0x%x (1271 PG20)",
|
||||
wl->chip.id);
|
||||
break;
|
||||
case CHIP_ID_1283_PG20:
|
||||
wl1271_notice("chip id 0x%x (1283 PG20)",
|
||||
wl->chip.id);
|
||||
break;
|
||||
case CHIP_ID_1283_PG10:
|
||||
default:
|
||||
wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct wl1271_partition_set part_down = {
|
||||
.mem = {
|
||||
.start = 0x00000000,
|
||||
.size = 0x000177c0
|
||||
},
|
||||
.reg = {
|
||||
.start = REGISTERS_BASE,
|
||||
.size = 0x00008800
|
||||
},
|
||||
.mem2 = {
|
||||
.start = 0x00000000,
|
||||
.size = 0x00000000
|
||||
},
|
||||
.mem3 = {
|
||||
.start = 0x00000000,
|
||||
.size = 0x00000000
|
||||
},
|
||||
};
|
||||
|
||||
static int tester(void *data)
|
||||
{
|
||||
struct wl1271 *wl = data;
|
||||
struct sdio_func *func = wl_to_func(wl);
|
||||
struct device *pdev = &func->dev;
|
||||
int ret = 0;
|
||||
bool rx_started = 0;
|
||||
bool tx_started = 0;
|
||||
uint8_t *tx_buf, *rx_buf;
|
||||
int test_size = PAGE_SIZE;
|
||||
u32 addr = 0;
|
||||
struct wl1271_partition_set partition;
|
||||
|
||||
/* We assume chip is powered up and firmware fetched */
|
||||
|
||||
memcpy(&partition, &part_down, sizeof(partition));
|
||||
partition.mem.start = addr;
|
||||
wl1271_set_partition(wl, &partition);
|
||||
|
||||
tx_buf = kmalloc(test_size, GFP_KERNEL);
|
||||
rx_buf = kmalloc(test_size, GFP_KERNEL);
|
||||
if (!tx_buf || !rx_buf) {
|
||||
dev_err(pdev,
|
||||
"Could not allocate memory. Test will not run.\n");
|
||||
ret = -ENOMEM;
|
||||
goto free;
|
||||
}
|
||||
|
||||
memset(tx_buf, 0x5a, test_size);
|
||||
|
||||
/* write something in data area so we can read it back */
|
||||
wl1271_write(wl, addr, tx_buf, test_size, false);
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
if (rx && !rx_started) {
|
||||
dev_info(pdev, "starting rx test\n");
|
||||
rx_started = 1;
|
||||
} else if (!rx && rx_started) {
|
||||
dev_info(pdev, "stopping rx test\n");
|
||||
rx_started = 0;
|
||||
}
|
||||
|
||||
if (tx && !tx_started) {
|
||||
dev_info(pdev, "starting tx test\n");
|
||||
tx_started = 1;
|
||||
} else if (!tx && tx_started) {
|
||||
dev_info(pdev, "stopping tx test\n");
|
||||
tx_started = 0;
|
||||
}
|
||||
|
||||
if (rx_started)
|
||||
wl1271_read(wl, addr, rx_buf, test_size, false);
|
||||
|
||||
if (tx_started)
|
||||
wl1271_write(wl, addr, tx_buf, test_size, false);
|
||||
|
||||
if (!rx_started && !tx_started)
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
free:
|
||||
kfree(tx_buf);
|
||||
kfree(rx_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit wl1271_probe(struct sdio_func *func,
|
||||
const struct sdio_device_id *id)
|
||||
{
|
||||
const struct wl12xx_platform_data *wlan_data;
|
||||
struct wl1271 *wl;
|
||||
struct wl1271_test *wl_test;
|
||||
int ret = 0;
|
||||
|
||||
/* wl1271 has 2 sdio functions we handle just the wlan part */
|
||||
if (func->num != 0x02)
|
||||
return -ENODEV;
|
||||
|
||||
wl_test = kzalloc(sizeof(struct wl1271_test), GFP_KERNEL);
|
||||
if (!wl_test) {
|
||||
dev_err(&func->dev, "Could not allocate memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
wl = &wl_test->wl;
|
||||
|
||||
wl->if_priv = func;
|
||||
wl->if_ops = &sdio_ops;
|
||||
|
||||
/* Grab access to FN0 for ELP reg. */
|
||||
func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
|
||||
|
||||
/* Use block mode for transferring over one block size of data */
|
||||
func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
|
||||
|
||||
wlan_data = wl12xx_get_platform_data();
|
||||
if (IS_ERR(wlan_data)) {
|
||||
ret = PTR_ERR(wlan_data);
|
||||
dev_err(&func->dev, "missing wlan platform data: %d\n", ret);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
wl->irq = wlan_data->irq;
|
||||
wl->ref_clock = wlan_data->board_ref_clock;
|
||||
wl->tcxo_clock = wlan_data->board_tcxo_clock;
|
||||
|
||||
sdio_set_drvdata(func, wl_test);
|
||||
|
||||
/* power up the device */
|
||||
ret = wl1271_chip_wakeup(wl);
|
||||
if (ret) {
|
||||
dev_err(&func->dev, "could not wake up chip\n");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (wl->fw == NULL) {
|
||||
ret = wl1271_fetch_firmware(wl);
|
||||
if (ret < 0) {
|
||||
dev_err(&func->dev, "firmware fetch error\n");
|
||||
goto out_off;
|
||||
}
|
||||
}
|
||||
|
||||
/* fetch NVS */
|
||||
if (wl->nvs == NULL) {
|
||||
ret = wl1271_fetch_nvs(wl);
|
||||
if (ret < 0) {
|
||||
dev_err(&func->dev, "NVS fetch error\n");
|
||||
goto out_off;
|
||||
}
|
||||
}
|
||||
|
||||
ret = wl1271_load_firmware(wl);
|
||||
if (ret < 0) {
|
||||
dev_err(&func->dev, "firmware load error: %d\n", ret);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
dev_info(&func->dev, "initialized\n");
|
||||
|
||||
/* I/O testing will be done in the tester thread */
|
||||
|
||||
wl_test->test_task = kthread_run(tester, wl, "sdio_tester");
|
||||
if (IS_ERR(wl_test->test_task)) {
|
||||
dev_err(&func->dev, "unable to create kernel thread\n");
|
||||
ret = PTR_ERR(wl_test->test_task);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_off:
|
||||
/* power off the chip */
|
||||
wl1271_power_off(wl);
|
||||
|
||||
out_free:
|
||||
kfree(wl_test);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit wl1271_remove(struct sdio_func *func)
|
||||
{
|
||||
struct wl1271_test *wl_test = sdio_get_drvdata(func);
|
||||
|
||||
/* stop the I/O test thread */
|
||||
kthread_stop(wl_test->test_task);
|
||||
|
||||
/* power off the chip */
|
||||
wl1271_power_off(&wl_test->wl);
|
||||
|
||||
vfree(wl_test->wl.fw);
|
||||
wl_test->wl.fw = NULL;
|
||||
kfree(wl_test->wl.nvs);
|
||||
wl_test->wl.nvs = NULL;
|
||||
|
||||
kfree(wl_test);
|
||||
}
|
||||
|
||||
static struct sdio_driver wl1271_sdio_driver = {
|
||||
.name = "wl12xx_sdio_test",
|
||||
.id_table = wl1271_devices,
|
||||
.probe = wl1271_probe,
|
||||
.remove = __devexit_p(wl1271_remove),
|
||||
};
|
||||
|
||||
static int __init wl1271_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sdio_register_driver(&wl1271_sdio_driver);
|
||||
if (ret < 0)
|
||||
pr_err("failed to register sdio driver: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(wl1271_init);
|
||||
|
||||
static void __exit wl1271_exit(void)
|
||||
{
|
||||
sdio_unregister_driver(&wl1271_sdio_driver);
|
||||
}
|
||||
module_exit(wl1271_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Roger Quadros <roger.quadros@nokia.com>");
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/crc7.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/wl12xx.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
|
@ -69,35 +70,22 @@
|
|||
|
||||
#define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE)
|
||||
|
||||
static inline struct spi_device *wl_to_spi(struct wl1271 *wl)
|
||||
{
|
||||
return wl->if_priv;
|
||||
}
|
||||
struct wl12xx_spi_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *core;
|
||||
};
|
||||
|
||||
static struct device *wl1271_spi_wl_to_dev(struct wl1271 *wl)
|
||||
{
|
||||
return &(wl_to_spi(wl)->dev);
|
||||
}
|
||||
|
||||
static void wl1271_spi_disable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
disable_irq(wl->irq);
|
||||
}
|
||||
|
||||
static void wl1271_spi_enable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
enable_irq(wl->irq);
|
||||
}
|
||||
|
||||
static void wl1271_spi_reset(struct wl1271 *wl)
|
||||
static void wl12xx_spi_reset(struct device *child)
|
||||
{
|
||||
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
|
||||
u8 *cmd;
|
||||
struct spi_transfer t;
|
||||
struct spi_message m;
|
||||
|
||||
cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
wl1271_error("could not allocate cmd for spi reset");
|
||||
dev_err(child->parent,
|
||||
"could not allocate cmd for spi reset\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -110,21 +98,22 @@ static void wl1271_spi_reset(struct wl1271 *wl)
|
|||
t.len = WSPI_INIT_CMD_LEN;
|
||||
spi_message_add_tail(&t, &m);
|
||||
|
||||
spi_sync(wl_to_spi(wl), &m);
|
||||
spi_sync(to_spi_device(glue->dev), &m);
|
||||
|
||||
wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
|
||||
kfree(cmd);
|
||||
}
|
||||
|
||||
static void wl1271_spi_init(struct wl1271 *wl)
|
||||
static void wl12xx_spi_init(struct device *child)
|
||||
{
|
||||
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
|
||||
u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;
|
||||
struct spi_transfer t;
|
||||
struct spi_message m;
|
||||
|
||||
cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
wl1271_error("could not allocate cmd for spi init");
|
||||
dev_err(child->parent,
|
||||
"could not allocate cmd for spi init\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -165,15 +154,16 @@ static void wl1271_spi_init(struct wl1271 *wl)
|
|||
t.len = WSPI_INIT_CMD_LEN;
|
||||
spi_message_add_tail(&t, &m);
|
||||
|
||||
spi_sync(wl_to_spi(wl), &m);
|
||||
wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
|
||||
spi_sync(to_spi_device(glue->dev), &m);
|
||||
kfree(cmd);
|
||||
}
|
||||
|
||||
#define WL1271_BUSY_WORD_TIMEOUT 1000
|
||||
|
||||
static int wl1271_spi_read_busy(struct wl1271 *wl)
|
||||
static int wl12xx_spi_read_busy(struct device *child)
|
||||
{
|
||||
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
|
||||
struct wl1271 *wl = dev_get_drvdata(child);
|
||||
struct spi_transfer t[1];
|
||||
struct spi_message m;
|
||||
u32 *busy_buf;
|
||||
|
@ -194,20 +184,22 @@ static int wl1271_spi_read_busy(struct wl1271 *wl)
|
|||
t[0].len = sizeof(u32);
|
||||
t[0].cs_change = true;
|
||||
spi_message_add_tail(&t[0], &m);
|
||||
spi_sync(wl_to_spi(wl), &m);
|
||||
spi_sync(to_spi_device(glue->dev), &m);
|
||||
|
||||
if (*busy_buf & 0x1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The SPI bus is unresponsive, the read failed. */
|
||||
wl1271_error("SPI read busy-word timeout!\n");
|
||||
dev_err(child->parent, "SPI read busy-word timeout!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
|
||||
static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
{
|
||||
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
|
||||
struct wl1271 *wl = dev_get_drvdata(child);
|
||||
struct spi_transfer t[2];
|
||||
struct spi_message m;
|
||||
u32 *busy_buf;
|
||||
|
@ -243,10 +235,10 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
|
|||
t[1].cs_change = true;
|
||||
spi_message_add_tail(&t[1], &m);
|
||||
|
||||
spi_sync(wl_to_spi(wl), &m);
|
||||
spi_sync(to_spi_device(glue->dev), &m);
|
||||
|
||||
if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) &&
|
||||
wl1271_spi_read_busy(wl)) {
|
||||
wl12xx_spi_read_busy(child)) {
|
||||
memset(buf, 0, chunk_len);
|
||||
return;
|
||||
}
|
||||
|
@ -259,10 +251,7 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
|
|||
t[0].cs_change = true;
|
||||
spi_message_add_tail(&t[0], &m);
|
||||
|
||||
spi_sync(wl_to_spi(wl), &m);
|
||||
|
||||
wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
|
||||
wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, chunk_len);
|
||||
spi_sync(to_spi_device(glue->dev), &m);
|
||||
|
||||
if (!fixed)
|
||||
addr += chunk_len;
|
||||
|
@ -271,9 +260,10 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
|
|||
}
|
||||
}
|
||||
|
||||
static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
|
||||
static void wl12xx_spi_raw_write(struct device *child, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
{
|
||||
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
|
||||
struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
|
||||
struct spi_message m;
|
||||
u32 commands[WSPI_MAX_NUM_OF_CHUNKS];
|
||||
|
@ -308,9 +298,6 @@ static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
|
|||
t[i].len = chunk_len;
|
||||
spi_message_add_tail(&t[i++], &m);
|
||||
|
||||
wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
|
||||
wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, chunk_len);
|
||||
|
||||
if (!fixed)
|
||||
addr += chunk_len;
|
||||
buf += chunk_len;
|
||||
|
@ -318,72 +305,41 @@ static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
|
|||
cmd++;
|
||||
}
|
||||
|
||||
spi_sync(wl_to_spi(wl), &m);
|
||||
}
|
||||
|
||||
static irqreturn_t wl1271_hardirq(int irq, void *cookie)
|
||||
{
|
||||
struct wl1271 *wl = cookie;
|
||||
unsigned long flags;
|
||||
|
||||
wl1271_debug(DEBUG_IRQ, "IRQ");
|
||||
|
||||
/* complete the ELP completion */
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
|
||||
if (wl->elp_compl) {
|
||||
complete(wl->elp_compl);
|
||||
wl->elp_compl = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static int wl1271_spi_set_power(struct wl1271 *wl, bool enable)
|
||||
{
|
||||
if (wl->set_power)
|
||||
wl->set_power(enable);
|
||||
|
||||
return 0;
|
||||
spi_sync(to_spi_device(glue->dev), &m);
|
||||
}
|
||||
|
||||
static struct wl1271_if_operations spi_ops = {
|
||||
.read = wl1271_spi_raw_read,
|
||||
.write = wl1271_spi_raw_write,
|
||||
.reset = wl1271_spi_reset,
|
||||
.init = wl1271_spi_init,
|
||||
.power = wl1271_spi_set_power,
|
||||
.dev = wl1271_spi_wl_to_dev,
|
||||
.enable_irq = wl1271_spi_enable_interrupts,
|
||||
.disable_irq = wl1271_spi_disable_interrupts,
|
||||
.read = wl12xx_spi_raw_read,
|
||||
.write = wl12xx_spi_raw_write,
|
||||
.reset = wl12xx_spi_reset,
|
||||
.init = wl12xx_spi_init,
|
||||
.set_block_size = NULL,
|
||||
};
|
||||
|
||||
static int __devinit wl1271_probe(struct spi_device *spi)
|
||||
{
|
||||
struct wl12xx_spi_glue *glue;
|
||||
struct wl12xx_platform_data *pdata;
|
||||
struct ieee80211_hw *hw;
|
||||
struct wl1271 *wl;
|
||||
unsigned long irqflags;
|
||||
int ret;
|
||||
struct resource res[1];
|
||||
int ret = -ENOMEM;
|
||||
|
||||
pdata = spi->dev.platform_data;
|
||||
if (!pdata) {
|
||||
wl1271_error("no platform data");
|
||||
dev_err(&spi->dev, "no platform data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hw = wl1271_alloc_hw();
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
pdata->ops = &spi_ops;
|
||||
|
||||
wl = hw->priv;
|
||||
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue) {
|
||||
dev_err(&spi->dev, "can't allocate glue\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&spi->dev, wl);
|
||||
wl->if_priv = spi;
|
||||
glue->dev = &spi->dev;
|
||||
|
||||
wl->if_ops = &spi_ops;
|
||||
spi_set_drvdata(spi, glue);
|
||||
|
||||
/* This is the only SPI value that we need to set here, the rest
|
||||
* comes from the board-peripherals file */
|
||||
|
@ -391,69 +347,61 @@ static int __devinit wl1271_probe(struct spi_device *spi)
|
|||
|
||||
ret = spi_setup(spi);
|
||||
if (ret < 0) {
|
||||
wl1271_error("spi_setup failed");
|
||||
goto out_free;
|
||||
dev_err(glue->dev, "spi_setup failed\n");
|
||||
goto out_free_glue;
|
||||
}
|
||||
|
||||
wl->set_power = pdata->set_power;
|
||||
if (!wl->set_power) {
|
||||
wl1271_error("set power function missing in platform data");
|
||||
ret = -ENODEV;
|
||||
goto out_free;
|
||||
glue->core = platform_device_alloc("wl12xx", -1);
|
||||
if (!glue->core) {
|
||||
dev_err(glue->dev, "can't allocate platform_device\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_free_glue;
|
||||
}
|
||||
|
||||
wl->ref_clock = pdata->board_ref_clock;
|
||||
wl->tcxo_clock = pdata->board_tcxo_clock;
|
||||
wl->platform_quirks = pdata->platform_quirks;
|
||||
glue->core->dev.parent = &spi->dev;
|
||||
|
||||
if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
|
||||
irqflags = IRQF_TRIGGER_RISING;
|
||||
else
|
||||
irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
|
||||
memset(res, 0x00, sizeof(res));
|
||||
|
||||
wl->irq = spi->irq;
|
||||
if (wl->irq < 0) {
|
||||
wl1271_error("irq missing in platform data");
|
||||
ret = -ENODEV;
|
||||
goto out_free;
|
||||
res[0].start = spi->irq;
|
||||
res[0].flags = IORESOURCE_IRQ;
|
||||
res[0].name = "irq";
|
||||
|
||||
ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res));
|
||||
if (ret) {
|
||||
dev_err(glue->dev, "can't add resources\n");
|
||||
goto out_dev_put;
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq,
|
||||
irqflags,
|
||||
DRIVER_NAME, wl);
|
||||
if (ret < 0) {
|
||||
wl1271_error("request_irq() failed: %d", ret);
|
||||
goto out_free;
|
||||
ret = platform_device_add_data(glue->core, pdata, sizeof(*pdata));
|
||||
if (ret) {
|
||||
dev_err(glue->dev, "can't add platform data\n");
|
||||
goto out_dev_put;
|
||||
}
|
||||
|
||||
disable_irq(wl->irq);
|
||||
|
||||
ret = wl1271_init_ieee80211(wl);
|
||||
if (ret)
|
||||
goto out_irq;
|
||||
|
||||
ret = wl1271_register_hw(wl);
|
||||
if (ret)
|
||||
goto out_irq;
|
||||
ret = platform_device_add(glue->core);
|
||||
if (ret) {
|
||||
dev_err(glue->dev, "can't register platform device\n");
|
||||
goto out_dev_put;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_irq:
|
||||
free_irq(wl->irq, wl);
|
||||
|
||||
out_free:
|
||||
wl1271_free_hw(wl);
|
||||
out_dev_put:
|
||||
platform_device_put(glue->core);
|
||||
|
||||
out_free_glue:
|
||||
kfree(glue);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit wl1271_remove(struct spi_device *spi)
|
||||
{
|
||||
struct wl1271 *wl = dev_get_drvdata(&spi->dev);
|
||||
struct wl12xx_spi_glue *glue = spi_get_drvdata(spi);
|
||||
|
||||
wl1271_unregister_hw(wl);
|
||||
free_irq(wl->irq, wl);
|
||||
wl1271_free_hw(wl);
|
||||
platform_device_del(glue->core);
|
||||
platform_device_put(glue->core);
|
||||
kfree(glue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -26,8 +26,10 @@
|
|||
#include <net/genetlink.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "acx.h"
|
||||
#include "reg.h"
|
||||
#include "ps.h"
|
||||
|
||||
#define WL1271_TM_MAX_DATA_LENGTH 1024
|
||||
|
||||
|
@ -87,31 +89,47 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
|
|||
return -EMSGSIZE;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
ret = wl1271_cmd_test(wl, buf, buf_len, answer);
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl1271_cmd_test(wl, buf, buf_len, answer);
|
||||
if (ret < 0) {
|
||||
wl1271_warning("testmode cmd test failed: %d", ret);
|
||||
return ret;
|
||||
goto out_sleep;
|
||||
}
|
||||
|
||||
if (answer) {
|
||||
len = nla_total_size(buf_len);
|
||||
skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
if (!skb) {
|
||||
ret = -ENOMEM;
|
||||
goto out_sleep;
|
||||
}
|
||||
|
||||
NLA_PUT(skb, WL1271_TM_ATTR_DATA, buf_len, buf);
|
||||
ret = cfg80211_testmode_reply(skb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto out_sleep;
|
||||
}
|
||||
|
||||
return 0;
|
||||
out_sleep:
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
out:
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
return ret;
|
||||
|
||||
nla_put_failure:
|
||||
kfree_skb(skb);
|
||||
return -EMSGSIZE;
|
||||
ret = -EMSGSIZE;
|
||||
goto out_sleep;
|
||||
}
|
||||
|
||||
static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[])
|
||||
|
@ -128,33 +146,53 @@ static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[])
|
|||
|
||||
ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]);
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd));
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
ret = -ENOMEM;
|
||||
goto out_sleep;
|
||||
}
|
||||
|
||||
ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd));
|
||||
if (ret < 0) {
|
||||
wl1271_warning("testmode cmd interrogate failed: %d", ret);
|
||||
kfree(cmd);
|
||||
return ret;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd));
|
||||
if (!skb) {
|
||||
kfree(cmd);
|
||||
return -ENOMEM;
|
||||
ret = -ENOMEM;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd);
|
||||
ret = cfg80211_testmode_reply(skb);
|
||||
if (ret < 0)
|
||||
goto out_free;
|
||||
|
||||
return 0;
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
out_sleep:
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
out:
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
return ret;
|
||||
|
||||
nla_put_failure:
|
||||
kfree_skb(skb);
|
||||
return -EMSGSIZE;
|
||||
ret = -EMSGSIZE;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[])
|
||||
|
|
|
@ -26,22 +26,24 @@
|
|||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "io.h"
|
||||
#include "reg.h"
|
||||
#include "ps.h"
|
||||
#include "tx.h"
|
||||
#include "event.h"
|
||||
|
||||
static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id)
|
||||
static int wl1271_set_default_wep_key(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif, u8 id)
|
||||
{
|
||||
int ret;
|
||||
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
|
||||
bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
|
||||
|
||||
if (is_ap)
|
||||
ret = wl12xx_cmd_set_default_wep_key(wl, id,
|
||||
wl->ap_bcast_hlid);
|
||||
wlvif->ap.bcast_hlid);
|
||||
else
|
||||
ret = wl12xx_cmd_set_default_wep_key(wl, id, wl->sta_hlid);
|
||||
ret = wl12xx_cmd_set_default_wep_key(wl, id, wlvif->sta.hlid);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -76,6 +78,7 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id)
|
|||
}
|
||||
|
||||
static int wl1271_tx_update_filters(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr;
|
||||
|
@ -92,15 +95,11 @@ static int wl1271_tx_update_filters(struct wl1271 *wl,
|
|||
if (!ieee80211_is_auth(hdr->frame_control))
|
||||
return 0;
|
||||
|
||||
if (wl->dev_hlid != WL12XX_INVALID_LINK_ID)
|
||||
if (wlvif->dev_hlid != WL12XX_INVALID_LINK_ID)
|
||||
goto out;
|
||||
|
||||
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);
|
||||
ret = wl12xx_start_dev(wl, wlvif);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
out:
|
||||
|
@ -123,16 +122,14 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
|
|||
wl1271_acx_set_inconnection_sta(wl, hdr->addr1);
|
||||
}
|
||||
|
||||
static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid)
|
||||
static void wl1271_tx_regulate_link(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
u8 hlid)
|
||||
{
|
||||
bool fw_ps, single_sta;
|
||||
u8 tx_pkts;
|
||||
|
||||
/* only regulate station links */
|
||||
if (hlid < WL1271_AP_STA_HLID_START)
|
||||
return;
|
||||
|
||||
if (WARN_ON(!wl1271_is_active_sta(wl, hlid)))
|
||||
if (WARN_ON(!test_bit(hlid, wlvif->links_map)))
|
||||
return;
|
||||
|
||||
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
|
||||
|
@ -146,7 +143,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid)
|
|||
* case FW-memory congestion is not a problem.
|
||||
*/
|
||||
if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
|
||||
wl1271_ps_link_start(wl, hlid, true);
|
||||
wl12xx_ps_link_start(wl, wlvif, hlid, true);
|
||||
}
|
||||
|
||||
bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
|
||||
|
@ -154,7 +151,8 @@ 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)
|
||||
u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb);
|
||||
|
||||
|
@ -167,49 +165,51 @@ u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb)
|
|||
} else {
|
||||
struct ieee80211_hdr *hdr;
|
||||
|
||||
if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
|
||||
if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
|
||||
return wl->system_hlid;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
if (ieee80211_is_mgmt(hdr->frame_control))
|
||||
return wl->ap_global_hlid;
|
||||
return wlvif->ap.global_hlid;
|
||||
else
|
||||
return wl->ap_bcast_hlid;
|
||||
return wlvif->ap.bcast_hlid;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb)
|
||||
u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
if (wl12xx_is_dummy_packet(wl, skb))
|
||||
if (!wlvif || 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 (wlvif->bss_type == BSS_TYPE_AP_BSS)
|
||||
return wl12xx_tx_get_hlid_ap(wl, wlvif, skb);
|
||||
|
||||
wl1271_tx_update_filters(wl, skb);
|
||||
wl1271_tx_update_filters(wl, wlvif, skb);
|
||||
|
||||
if ((test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
|
||||
test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags)) &&
|
||||
if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
|
||||
test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) &&
|
||||
!ieee80211_is_auth(hdr->frame_control) &&
|
||||
!ieee80211_is_assoc_req(hdr->frame_control))
|
||||
return wl->sta_hlid;
|
||||
return wlvif->sta.hlid;
|
||||
else
|
||||
return wl->dev_hlid;
|
||||
return wlvif->dev_hlid;
|
||||
}
|
||||
|
||||
static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl,
|
||||
unsigned int packet_length)
|
||||
{
|
||||
if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT)
|
||||
return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
|
||||
else
|
||||
if (wl->quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT)
|
||||
return ALIGN(packet_length, WL1271_TX_ALIGN_TO);
|
||||
else
|
||||
return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
|
||||
u32 buf_offset, u8 hlid)
|
||||
static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb, u32 extra, u32 buf_offset,
|
||||
u8 hlid)
|
||||
{
|
||||
struct wl1271_tx_hw_descr *desc;
|
||||
u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
|
||||
|
@ -217,6 +217,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
|
|||
u32 total_blocks;
|
||||
int id, ret = -EBUSY, ac;
|
||||
u32 spare_blocks = wl->tx_spare_blocks;
|
||||
bool is_dummy = false;
|
||||
|
||||
if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
|
||||
return -EAGAIN;
|
||||
|
@ -231,8 +232,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
|
|||
len = wl12xx_calc_packet_alignment(wl, total_len);
|
||||
|
||||
/* in case of a dummy packet, use default amount of spare mem blocks */
|
||||
if (unlikely(wl12xx_is_dummy_packet(wl, skb)))
|
||||
if (unlikely(wl12xx_is_dummy_packet(wl, skb))) {
|
||||
is_dummy = true;
|
||||
spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
|
||||
}
|
||||
|
||||
total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE +
|
||||
spare_blocks;
|
||||
|
@ -257,8 +260,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
|
|||
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
|
||||
wl->tx_allocated_pkts[ac]++;
|
||||
|
||||
if (wl->bss_type == BSS_TYPE_AP_BSS &&
|
||||
hlid >= WL1271_AP_STA_HLID_START)
|
||||
if (!is_dummy && wlvif &&
|
||||
wlvif->bss_type == BSS_TYPE_AP_BSS &&
|
||||
test_bit(hlid, wlvif->ap.sta_hlid_map))
|
||||
wl->links[hlid].allocated_pkts++;
|
||||
|
||||
ret = 0;
|
||||
|
@ -273,15 +277,16 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
|
||||
u32 extra, struct ieee80211_tx_info *control,
|
||||
u8 hlid)
|
||||
static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb, u32 extra,
|
||||
struct ieee80211_tx_info *control, u8 hlid)
|
||||
{
|
||||
struct timespec ts;
|
||||
struct wl1271_tx_hw_descr *desc;
|
||||
int aligned_len, ac, rate_idx;
|
||||
s64 hosttime;
|
||||
u16 tx_attr;
|
||||
bool is_dummy;
|
||||
|
||||
desc = (struct wl1271_tx_hw_descr *) skb->data;
|
||||
|
||||
|
@ -298,7 +303,8 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
|
|||
hosttime = (timespec_to_ns(&ts) >> 10);
|
||||
desc->start_time = cpu_to_le32(hosttime - wl->time_offset);
|
||||
|
||||
if (wl->bss_type != BSS_TYPE_AP_BSS)
|
||||
is_dummy = wl12xx_is_dummy_packet(wl, skb);
|
||||
if (is_dummy || !wlvif || wlvif->bss_type != BSS_TYPE_AP_BSS)
|
||||
desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU);
|
||||
else
|
||||
desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU);
|
||||
|
@ -307,39 +313,42 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
|
|||
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
|
||||
desc->tid = skb->priority;
|
||||
|
||||
if (wl12xx_is_dummy_packet(wl, skb)) {
|
||||
if (is_dummy) {
|
||||
/*
|
||||
* FW expects the dummy packet to have an invalid session id -
|
||||
* any session id that is different than the one set in the join
|
||||
*/
|
||||
tx_attr = ((~wl->session_counter) <<
|
||||
tx_attr = (SESSION_COUNTER_INVALID <<
|
||||
TX_HW_ATTR_OFST_SESSION_COUNTER) &
|
||||
TX_HW_ATTR_SESSION_COUNTER;
|
||||
|
||||
tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ;
|
||||
} else {
|
||||
} else if (wlvif) {
|
||||
/* configure the tx attributes */
|
||||
tx_attr =
|
||||
wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
|
||||
tx_attr = wlvif->session_counter <<
|
||||
TX_HW_ATTR_OFST_SESSION_COUNTER;
|
||||
}
|
||||
|
||||
desc->hlid = hlid;
|
||||
|
||||
if (wl->bss_type != BSS_TYPE_AP_BSS) {
|
||||
if (is_dummy || !wlvif)
|
||||
rate_idx = 0;
|
||||
else if (wlvif->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 */
|
||||
if (control->control.sta)
|
||||
rate_idx = ACX_TX_AP_FULL_RATE;
|
||||
if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
|
||||
rate_idx = wlvif->sta.p2p_rate_idx;
|
||||
else if (control->control.sta)
|
||||
rate_idx = wlvif->sta.ap_rate_idx;
|
||||
else
|
||||
rate_idx = ACX_TX_BASIC_RATE;
|
||||
rate_idx = wlvif->sta.basic_rate_idx;
|
||||
} else {
|
||||
if (hlid == wl->ap_global_hlid)
|
||||
rate_idx = ACX_TX_AP_MODE_MGMT_RATE;
|
||||
else if (hlid == wl->ap_bcast_hlid)
|
||||
rate_idx = ACX_TX_AP_MODE_BCST_RATE;
|
||||
if (hlid == wlvif->ap.global_hlid)
|
||||
rate_idx = wlvif->ap.mgmt_rate_idx;
|
||||
else if (hlid == wlvif->ap.bcast_hlid)
|
||||
rate_idx = wlvif->ap.bcast_rate_idx;
|
||||
else
|
||||
rate_idx = ac;
|
||||
rate_idx = wlvif->ap.ucast_rate_idx[ac];
|
||||
}
|
||||
|
||||
tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY;
|
||||
|
@ -379,20 +388,24 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
|
|||
}
|
||||
|
||||
/* caller must hold wl->mutex */
|
||||
static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
|
||||
u32 buf_offset)
|
||||
static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb, u32 buf_offset)
|
||||
{
|
||||
struct ieee80211_tx_info *info;
|
||||
u32 extra = 0;
|
||||
int ret = 0;
|
||||
u32 total_len;
|
||||
u8 hlid;
|
||||
bool is_dummy;
|
||||
|
||||
if (!skb)
|
||||
return -EINVAL;
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
/* TODO: handle dummy packets on multi-vifs */
|
||||
is_dummy = wl12xx_is_dummy_packet(wl, skb);
|
||||
|
||||
if (info->control.hw_key &&
|
||||
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP)
|
||||
extra = WL1271_TKIP_IV_SPACE;
|
||||
|
@ -405,29 +418,28 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
|
|||
is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) ||
|
||||
(cipher == WLAN_CIPHER_SUITE_WEP104);
|
||||
|
||||
if (unlikely(is_wep && wl->default_key != idx)) {
|
||||
ret = wl1271_set_default_wep_key(wl, idx);
|
||||
if (unlikely(is_wep && wlvif->default_key != idx)) {
|
||||
ret = wl1271_set_default_wep_key(wl, wlvif, idx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
wl->default_key = idx;
|
||||
wlvif->default_key = idx;
|
||||
}
|
||||
}
|
||||
|
||||
hlid = wl1271_tx_get_hlid(wl, skb);
|
||||
hlid = wl12xx_tx_get_hlid(wl, wlvif, 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);
|
||||
ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
wl1271_tx_fill_hdr(wl, skb, extra, info, hlid);
|
||||
wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid);
|
||||
|
||||
if (wl->bss_type == BSS_TYPE_AP_BSS) {
|
||||
if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) {
|
||||
wl1271_tx_ap_update_inconnection_sta(wl, skb);
|
||||
wl1271_tx_regulate_link(wl, hlid);
|
||||
wl1271_tx_regulate_link(wl, wlvif, hlid);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -444,7 +456,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
|
|||
memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len);
|
||||
|
||||
/* Revert side effects in the dummy packet skb, so it can be reused */
|
||||
if (wl12xx_is_dummy_packet(wl, skb))
|
||||
if (is_dummy)
|
||||
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
|
||||
|
||||
return total_len;
|
||||
|
@ -522,19 +534,18 @@ static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl,
|
|||
return &queues[q];
|
||||
}
|
||||
|
||||
static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl)
|
||||
static struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl,
|
||||
struct wl1271_link *lnk)
|
||||
{
|
||||
struct sk_buff *skb = NULL;
|
||||
struct sk_buff *skb;
|
||||
unsigned long flags;
|
||||
struct sk_buff_head *queue;
|
||||
|
||||
queue = wl1271_select_queue(wl, wl->tx_queue);
|
||||
queue = wl1271_select_queue(wl, lnk->tx_queue);
|
||||
if (!queue)
|
||||
goto out;
|
||||
return NULL;
|
||||
|
||||
skb = skb_dequeue(queue);
|
||||
|
||||
out:
|
||||
if (skb) {
|
||||
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
|
@ -545,43 +556,33 @@ out:
|
|||
return skb;
|
||||
}
|
||||
|
||||
static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
|
||||
static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct sk_buff *skb = NULL;
|
||||
unsigned long flags;
|
||||
int i, h, start_hlid;
|
||||
struct sk_buff_head *queue;
|
||||
|
||||
/* start from the link after the last one */
|
||||
start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS;
|
||||
start_hlid = (wlvif->last_tx_hlid + 1) % WL12XX_MAX_LINKS;
|
||||
|
||||
/* dequeue according to AC, round robin on each link */
|
||||
for (i = 0; i < AP_MAX_LINKS; i++) {
|
||||
h = (start_hlid + i) % AP_MAX_LINKS;
|
||||
for (i = 0; i < WL12XX_MAX_LINKS; i++) {
|
||||
h = (start_hlid + i) % WL12XX_MAX_LINKS;
|
||||
|
||||
/* only consider connected stations */
|
||||
if (h >= WL1271_AP_STA_HLID_START &&
|
||||
!test_bit(h - WL1271_AP_STA_HLID_START, wl->ap_hlid_map))
|
||||
if (!test_bit(h, wlvif->links_map))
|
||||
continue;
|
||||
|
||||
queue = wl1271_select_queue(wl, wl->links[h].tx_queue);
|
||||
if (!queue)
|
||||
skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[h]);
|
||||
if (!skb)
|
||||
continue;
|
||||
|
||||
skb = skb_dequeue(queue);
|
||||
if (skb)
|
||||
wlvif->last_tx_hlid = h;
|
||||
break;
|
||||
}
|
||||
|
||||
if (skb) {
|
||||
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
|
||||
wl->last_tx_hlid = h;
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
wl->tx_queue_count[q]--;
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
} else {
|
||||
wl->last_tx_hlid = 0;
|
||||
}
|
||||
if (!skb)
|
||||
wlvif->last_tx_hlid = 0;
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
@ -589,12 +590,32 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
|
|||
static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct wl12xx_vif *wlvif = wl->last_wlvif;
|
||||
struct sk_buff *skb = NULL;
|
||||
|
||||
if (wl->bss_type == BSS_TYPE_AP_BSS)
|
||||
skb = wl1271_ap_skb_dequeue(wl);
|
||||
else
|
||||
skb = wl1271_sta_skb_dequeue(wl);
|
||||
if (wlvif) {
|
||||
wl12xx_for_each_wlvif_continue(wl, wlvif) {
|
||||
skb = wl12xx_vif_skb_dequeue(wl, wlvif);
|
||||
if (skb) {
|
||||
wl->last_wlvif = wlvif;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* do another pass */
|
||||
if (!skb) {
|
||||
wl12xx_for_each_wlvif(wl, wlvif) {
|
||||
skb = wl12xx_vif_skb_dequeue(wl, wlvif);
|
||||
if (skb) {
|
||||
wl->last_wlvif = wlvif;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!skb)
|
||||
skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]);
|
||||
|
||||
if (!skb &&
|
||||
test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
|
||||
|
@ -610,21 +631,21 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
|
|||
return skb;
|
||||
}
|
||||
|
||||
static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
|
||||
static void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
unsigned long flags;
|
||||
int q = wl1271_tx_get_queue(skb_get_queue_mapping(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(wl, skb);
|
||||
} else {
|
||||
u8 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
|
||||
skb_queue_head(&wl->links[hlid].tx_queue[q], skb);
|
||||
|
||||
/* make sure we dequeue the same packet next time */
|
||||
wl->last_tx_hlid = (hlid + AP_MAX_LINKS - 1) % AP_MAX_LINKS;
|
||||
} else {
|
||||
skb_queue_head(&wl->tx_queue[q], skb);
|
||||
wlvif->last_tx_hlid = (hlid + WL12XX_MAX_LINKS - 1) %
|
||||
WL12XX_MAX_LINKS;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
|
@ -639,29 +660,71 @@ static bool wl1271_tx_is_data_present(struct sk_buff *skb)
|
|||
return ieee80211_is_data_present(hdr->frame_control);
|
||||
}
|
||||
|
||||
void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids)
|
||||
{
|
||||
struct wl12xx_vif *wlvif;
|
||||
u32 timeout;
|
||||
u8 hlid;
|
||||
|
||||
if (!wl->conf.rx_streaming.interval)
|
||||
return;
|
||||
|
||||
if (!wl->conf.rx_streaming.always &&
|
||||
!test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))
|
||||
return;
|
||||
|
||||
timeout = wl->conf.rx_streaming.duration;
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
bool found = false;
|
||||
for_each_set_bit(hlid, active_hlids, WL12XX_MAX_LINKS) {
|
||||
if (test_bit(hlid, wlvif->links_map)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
continue;
|
||||
|
||||
/* enable rx streaming */
|
||||
if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
|
||||
ieee80211_queue_work(wl->hw,
|
||||
&wlvif->rx_streaming_enable_work);
|
||||
|
||||
mod_timer(&wlvif->rx_streaming_timer,
|
||||
jiffies + msecs_to_jiffies(timeout));
|
||||
}
|
||||
}
|
||||
|
||||
void wl1271_tx_work_locked(struct wl1271 *wl)
|
||||
{
|
||||
struct wl12xx_vif *wlvif;
|
||||
struct sk_buff *skb;
|
||||
struct wl1271_tx_hw_descr *desc;
|
||||
u32 buf_offset = 0;
|
||||
bool sent_packets = false;
|
||||
bool had_data = false;
|
||||
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
|
||||
unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
|
||||
int ret;
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
return;
|
||||
|
||||
while ((skb = wl1271_skb_dequeue(wl))) {
|
||||
if (wl1271_tx_is_data_present(skb))
|
||||
had_data = true;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
bool has_data = false;
|
||||
|
||||
ret = wl1271_prepare_tx_frame(wl, skb, buf_offset);
|
||||
wlvif = NULL;
|
||||
if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif)
|
||||
wlvif = wl12xx_vif_to_data(info->control.vif);
|
||||
|
||||
has_data = wlvif && wl1271_tx_is_data_present(skb);
|
||||
ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset);
|
||||
if (ret == -EAGAIN) {
|
||||
/*
|
||||
* Aggregation buffer is full.
|
||||
* Flush buffer and try again.
|
||||
*/
|
||||
wl1271_skb_queue_head(wl, skb);
|
||||
wl1271_skb_queue_head(wl, wlvif, skb);
|
||||
wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
|
||||
buf_offset, true);
|
||||
sent_packets = true;
|
||||
|
@ -672,7 +735,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
|
|||
* Firmware buffer is full.
|
||||
* Queue back last skb, and stop aggregating.
|
||||
*/
|
||||
wl1271_skb_queue_head(wl, skb);
|
||||
wl1271_skb_queue_head(wl, wlvif, skb);
|
||||
/* No work left, avoid scheduling redundant tx work */
|
||||
set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
|
||||
goto out_ack;
|
||||
|
@ -682,6 +745,10 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
|
|||
}
|
||||
buf_offset += ret;
|
||||
wl->tx_packets_count++;
|
||||
if (has_data) {
|
||||
desc = (struct wl1271_tx_hw_descr *) skb->data;
|
||||
__set_bit(desc->hlid, active_hlids);
|
||||
}
|
||||
}
|
||||
|
||||
out_ack:
|
||||
|
@ -701,19 +768,7 @@ out_ack:
|
|||
|
||||
wl1271_handle_tx_low_watermark(wl);
|
||||
}
|
||||
if (!is_ap && wl->conf.rx_streaming.interval && had_data &&
|
||||
(wl->conf.rx_streaming.always ||
|
||||
test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) {
|
||||
u32 timeout = wl->conf.rx_streaming.duration;
|
||||
|
||||
/* enable rx streaming */
|
||||
if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
|
||||
ieee80211_queue_work(wl->hw,
|
||||
&wl->rx_streaming_enable_work);
|
||||
|
||||
mod_timer(&wl->rx_streaming_timer,
|
||||
jiffies + msecs_to_jiffies(timeout));
|
||||
}
|
||||
wl12xx_rearm_rx_streaming(wl, active_hlids);
|
||||
}
|
||||
|
||||
void wl1271_tx_work(struct work_struct *work)
|
||||
|
@ -737,6 +792,8 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
|
|||
struct wl1271_tx_hw_res_descr *result)
|
||||
{
|
||||
struct ieee80211_tx_info *info;
|
||||
struct ieee80211_vif *vif;
|
||||
struct wl12xx_vif *wlvif;
|
||||
struct sk_buff *skb;
|
||||
int id = result->id;
|
||||
int rate = -1;
|
||||
|
@ -756,11 +813,16 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
|
|||
return;
|
||||
}
|
||||
|
||||
/* info->control is valid as long as we don't update info->status */
|
||||
vif = info->control.vif;
|
||||
wlvif = wl12xx_vif_to_data(vif);
|
||||
|
||||
/* update the TX status info */
|
||||
if (result->status == TX_SUCCESS) {
|
||||
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
rate = wl1271_rate_to_idx(result->rate_class_index, wl->band);
|
||||
rate = wl1271_rate_to_idx(result->rate_class_index,
|
||||
wlvif->band);
|
||||
retries = result->ack_failures;
|
||||
} else if (result->status == TX_RETRY_EXCEEDED) {
|
||||
wl->stats.excessive_retries++;
|
||||
|
@ -783,14 +845,14 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
|
|||
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP ||
|
||||
info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) {
|
||||
u8 fw_lsb = result->tx_security_sequence_number_lsb;
|
||||
u8 cur_lsb = wl->tx_security_last_seq_lsb;
|
||||
u8 cur_lsb = wlvif->tx_security_last_seq_lsb;
|
||||
|
||||
/*
|
||||
* update security sequence number, taking care of potential
|
||||
* wrap-around
|
||||
*/
|
||||
wl->tx_security_seq += (fw_lsb - cur_lsb + 256) % 256;
|
||||
wl->tx_security_last_seq_lsb = fw_lsb;
|
||||
wlvif->tx_security_seq += (fw_lsb - cur_lsb) & 0xff;
|
||||
wlvif->tx_security_last_seq_lsb = fw_lsb;
|
||||
}
|
||||
|
||||
/* remove private header from packet */
|
||||
|
@ -886,39 +948,30 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
|
|||
}
|
||||
|
||||
/* caller must hold wl->mutex and TX must be stopped */
|
||||
void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
|
||||
void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int i;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_tx_info *info;
|
||||
|
||||
/* TX failure */
|
||||
if (wl->bss_type == BSS_TYPE_AP_BSS) {
|
||||
for (i = 0; i < AP_MAX_LINKS; i++) {
|
||||
wl1271_free_sta(wl, i);
|
||||
for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) {
|
||||
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
|
||||
wl1271_free_sta(wl, wlvif, i);
|
||||
else
|
||||
wlvif->sta.ba_rx_bitmap = 0;
|
||||
|
||||
wl1271_tx_reset_link_queues(wl, i);
|
||||
wl->links[i].allocated_pkts = 0;
|
||||
wl->links[i].prev_freed_pkts = 0;
|
||||
}
|
||||
wlvif->last_tx_hlid = 0;
|
||||
|
||||
wl->last_tx_hlid = 0;
|
||||
} else {
|
||||
for (i = 0; i < NUM_TX_QUEUES; i++) {
|
||||
while ((skb = skb_dequeue(&wl->tx_queue[i]))) {
|
||||
wl1271_debug(DEBUG_TX, "freeing skb 0x%p",
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wl->ba_rx_bitmap = 0;
|
||||
}
|
||||
/* caller must hold wl->mutex and TX must be stopped */
|
||||
void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
|
||||
{
|
||||
int i;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_tx_info *info;
|
||||
|
||||
for (i = 0; i < NUM_TX_QUEUES; i++)
|
||||
wl->tx_queue_count[i] = 0;
|
||||
|
|
|
@ -206,18 +206,23 @@ static inline int wl1271_tx_total_queue_count(struct wl1271 *wl)
|
|||
void wl1271_tx_work(struct work_struct *work);
|
||||
void wl1271_tx_work_locked(struct wl1271 *wl);
|
||||
void wl1271_tx_complete(struct wl1271 *wl);
|
||||
void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
|
||||
void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
|
||||
void wl1271_tx_flush(struct wl1271 *wl);
|
||||
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
|
||||
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
|
||||
enum ieee80211_band rate_band);
|
||||
u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set);
|
||||
u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb);
|
||||
u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb);
|
||||
u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb);
|
||||
void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid);
|
||||
void wl1271_handle_tx_low_watermark(struct wl1271 *wl);
|
||||
bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb);
|
||||
void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids);
|
||||
|
||||
/* from main.c */
|
||||
void wl1271_free_sta(struct wl1271 *wl, u8 hlid);
|
||||
void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -35,9 +35,6 @@
|
|||
#include "conf.h"
|
||||
#include "ini.h"
|
||||
|
||||
#define DRIVER_NAME "wl1271"
|
||||
#define DRIVER_PREFIX DRIVER_NAME ": "
|
||||
|
||||
/*
|
||||
* FW versions support BA 11n
|
||||
* versions marks x.x.x.50-60.x
|
||||
|
@ -45,73 +42,6 @@
|
|||
#define WL12XX_BA_SUPPORT_FW_COST_VER2_START 50
|
||||
#define WL12XX_BA_SUPPORT_FW_COST_VER2_END 60
|
||||
|
||||
enum {
|
||||
DEBUG_NONE = 0,
|
||||
DEBUG_IRQ = BIT(0),
|
||||
DEBUG_SPI = BIT(1),
|
||||
DEBUG_BOOT = BIT(2),
|
||||
DEBUG_MAILBOX = BIT(3),
|
||||
DEBUG_TESTMODE = BIT(4),
|
||||
DEBUG_EVENT = BIT(5),
|
||||
DEBUG_TX = BIT(6),
|
||||
DEBUG_RX = BIT(7),
|
||||
DEBUG_SCAN = BIT(8),
|
||||
DEBUG_CRYPT = BIT(9),
|
||||
DEBUG_PSM = BIT(10),
|
||||
DEBUG_MAC80211 = BIT(11),
|
||||
DEBUG_CMD = BIT(12),
|
||||
DEBUG_ACX = BIT(13),
|
||||
DEBUG_SDIO = BIT(14),
|
||||
DEBUG_FILTERS = BIT(15),
|
||||
DEBUG_ADHOC = BIT(16),
|
||||
DEBUG_AP = BIT(17),
|
||||
DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP),
|
||||
DEBUG_ALL = ~0,
|
||||
};
|
||||
|
||||
extern u32 wl12xx_debug_level;
|
||||
|
||||
#define DEBUG_DUMP_LIMIT 1024
|
||||
|
||||
#define wl1271_error(fmt, arg...) \
|
||||
pr_err(DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
|
||||
|
||||
#define wl1271_warning(fmt, arg...) \
|
||||
pr_warning(DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
|
||||
|
||||
#define wl1271_notice(fmt, arg...) \
|
||||
pr_info(DRIVER_PREFIX fmt "\n", ##arg)
|
||||
|
||||
#define wl1271_info(fmt, arg...) \
|
||||
pr_info(DRIVER_PREFIX fmt "\n", ##arg)
|
||||
|
||||
#define wl1271_debug(level, fmt, arg...) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
pr_debug(DRIVER_PREFIX fmt "\n", ##arg); \
|
||||
} while (0)
|
||||
|
||||
/* TODO: use pr_debug_hex_dump when it will be available */
|
||||
#define wl1271_dump(level, prefix, buf, len) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
|
||||
DUMP_PREFIX_OFFSET, 16, 1, \
|
||||
buf, \
|
||||
min_t(size_t, len, DEBUG_DUMP_LIMIT), \
|
||||
0); \
|
||||
} while (0)
|
||||
|
||||
#define wl1271_dump_ascii(level, prefix, buf, len) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
|
||||
DUMP_PREFIX_OFFSET, 16, 1, \
|
||||
buf, \
|
||||
min_t(size_t, len, DEBUG_DUMP_LIMIT), \
|
||||
true); \
|
||||
} while (0)
|
||||
|
||||
#define WL127X_FW_NAME "ti-connectivity/wl127x-fw-3.bin"
|
||||
#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-3.bin"
|
||||
|
||||
|
@ -142,15 +72,11 @@ extern u32 wl12xx_debug_level;
|
|||
#define WL12XX_INVALID_ROLE_ID 0xff
|
||||
#define WL12XX_INVALID_LINK_ID 0xff
|
||||
|
||||
#define WL12XX_MAX_RATE_POLICIES 16
|
||||
|
||||
/* 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 packets
|
||||
* to be transmitted to FW for a STA in PS-mode. Only when packets are
|
||||
|
@ -236,13 +162,6 @@ struct wl1271_stats {
|
|||
|
||||
#define AP_MAX_STATIONS 8
|
||||
|
||||
/* Broadcast and Global links + system link + links to stations */
|
||||
/*
|
||||
* TODO: when WL1271_AP_STA_HLID_START is no longer constant, change all
|
||||
* the places that use this.
|
||||
*/
|
||||
#define AP_MAX_LINKS (AP_MAX_STATIONS + WL1271_AP_STA_HLID_START)
|
||||
|
||||
/* FW status registers */
|
||||
struct wl12xx_fw_status {
|
||||
__le32 intr;
|
||||
|
@ -299,17 +218,14 @@ struct wl1271_scan {
|
|||
};
|
||||
|
||||
struct wl1271_if_operations {
|
||||
void (*read)(struct wl1271 *wl, int addr, void *buf, size_t len,
|
||||
void (*read)(struct device *child, int addr, void *buf, size_t len,
|
||||
bool fixed);
|
||||
void (*write)(struct wl1271 *wl, int addr, void *buf, size_t len,
|
||||
void (*write)(struct device *child, int addr, void *buf, size_t len,
|
||||
bool fixed);
|
||||
void (*reset)(struct wl1271 *wl);
|
||||
void (*init)(struct wl1271 *wl);
|
||||
int (*power)(struct wl1271 *wl, bool enable);
|
||||
struct device* (*dev)(struct wl1271 *wl);
|
||||
void (*enable_irq)(struct wl1271 *wl);
|
||||
void (*disable_irq)(struct wl1271 *wl);
|
||||
void (*set_block_size) (struct wl1271 *wl, unsigned int blksz);
|
||||
void (*reset)(struct device *child);
|
||||
void (*init)(struct device *child);
|
||||
int (*power)(struct device *child, bool enable);
|
||||
void (*set_block_size) (struct device *child, unsigned int blksz);
|
||||
};
|
||||
|
||||
#define MAX_NUM_KEYS 14
|
||||
|
@ -326,29 +242,33 @@ struct wl1271_ap_key {
|
|||
};
|
||||
|
||||
enum wl12xx_flags {
|
||||
WL1271_FLAG_STA_ASSOCIATED,
|
||||
WL1271_FLAG_IBSS_JOINED,
|
||||
WL1271_FLAG_GPIO_POWER,
|
||||
WL1271_FLAG_TX_QUEUE_STOPPED,
|
||||
WL1271_FLAG_TX_PENDING,
|
||||
WL1271_FLAG_IN_ELP,
|
||||
WL1271_FLAG_ELP_REQUESTED,
|
||||
WL1271_FLAG_PSM,
|
||||
WL1271_FLAG_PSM_REQUESTED,
|
||||
WL1271_FLAG_IRQ_RUNNING,
|
||||
WL1271_FLAG_IDLE,
|
||||
WL1271_FLAG_PSPOLL_FAILURE,
|
||||
WL1271_FLAG_STA_STATE_SENT,
|
||||
WL1271_FLAG_FW_TX_BUSY,
|
||||
WL1271_FLAG_AP_STARTED,
|
||||
WL1271_FLAG_IF_INITIALIZED,
|
||||
WL1271_FLAG_DUMMY_PACKET_PENDING,
|
||||
WL1271_FLAG_SUSPENDED,
|
||||
WL1271_FLAG_PENDING_WORK,
|
||||
WL1271_FLAG_SOFT_GEMINI,
|
||||
WL1271_FLAG_RX_STREAMING_STARTED,
|
||||
WL1271_FLAG_RECOVERY_IN_PROGRESS,
|
||||
WL1271_FLAG_CS_PROGRESS,
|
||||
};
|
||||
|
||||
enum wl12xx_vif_flags {
|
||||
WLVIF_FLAG_INITIALIZED,
|
||||
WLVIF_FLAG_STA_ASSOCIATED,
|
||||
WLVIF_FLAG_IBSS_JOINED,
|
||||
WLVIF_FLAG_AP_STARTED,
|
||||
WLVIF_FLAG_PSM,
|
||||
WLVIF_FLAG_PSM_REQUESTED,
|
||||
WLVIF_FLAG_STA_STATE_SENT,
|
||||
WLVIF_FLAG_RX_STREAMING_STARTED,
|
||||
WLVIF_FLAG_PSPOLL_FAILURE,
|
||||
WLVIF_FLAG_CS_PROGRESS,
|
||||
WLVIF_FLAG_AP_PROBE_RESP_SET,
|
||||
};
|
||||
|
||||
struct wl1271_link {
|
||||
|
@ -366,10 +286,11 @@ struct wl1271_link {
|
|||
};
|
||||
|
||||
struct wl1271 {
|
||||
struct platform_device *plat_dev;
|
||||
struct ieee80211_hw *hw;
|
||||
bool mac80211_registered;
|
||||
|
||||
struct device *dev;
|
||||
|
||||
void *if_priv;
|
||||
|
||||
struct wl1271_if_operations *if_ops;
|
||||
|
@ -399,25 +320,20 @@ struct wl1271 {
|
|||
|
||||
s8 hw_pg_ver;
|
||||
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u8 bss_type;
|
||||
u8 set_bss_type;
|
||||
u8 p2p; /* we are using p2p role */
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
|
||||
u8 ssid_len;
|
||||
int channel;
|
||||
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)];
|
||||
unsigned long rate_policies_map[
|
||||
BITS_TO_LONGS(WL12XX_MAX_RATE_POLICIES)];
|
||||
|
||||
struct list_head wlvif_list;
|
||||
|
||||
u8 sta_count;
|
||||
u8 ap_count;
|
||||
|
||||
struct wl1271_acx_mem_map *target_mem_map;
|
||||
|
||||
|
@ -440,11 +356,7 @@ struct wl1271 {
|
|||
/* Time-offset between host and chipset clocks */
|
||||
s64 time_offset;
|
||||
|
||||
/* Session counter for the chipset */
|
||||
int session_counter;
|
||||
|
||||
/* Frames scheduled for transmission, not handled yet */
|
||||
struct sk_buff_head tx_queue[NUM_TX_QUEUES];
|
||||
int tx_queue_count[NUM_TX_QUEUES];
|
||||
long stopped_queues_map;
|
||||
|
||||
|
@ -462,17 +374,6 @@ struct wl1271 {
|
|||
struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
|
||||
int tx_frames_cnt;
|
||||
|
||||
/*
|
||||
* Security sequence number
|
||||
* bits 0-15: lower 16 bits part of sequence number
|
||||
* bits 16-47: higher 32 bits part of sequence number
|
||||
* bits 48-63: not in use
|
||||
*/
|
||||
u64 tx_security_seq;
|
||||
|
||||
/* 8 bits of the last sequence number in use */
|
||||
u8 tx_security_last_seq_lsb;
|
||||
|
||||
/* FW Rx counter */
|
||||
u32 rx_counter;
|
||||
|
||||
|
@ -507,59 +408,21 @@ struct wl1271 {
|
|||
u32 mbox_ptr[2];
|
||||
|
||||
/* Are we currently scanning */
|
||||
struct ieee80211_vif *scan_vif;
|
||||
struct wl1271_scan scan;
|
||||
struct delayed_work scan_complete_work;
|
||||
|
||||
bool sched_scanning;
|
||||
|
||||
/* probe-req template for the current AP */
|
||||
struct sk_buff *probereq;
|
||||
|
||||
/* Our association ID */
|
||||
u16 aid;
|
||||
|
||||
/*
|
||||
* currently configured rate set:
|
||||
* bits 0-15 - 802.11abg rates
|
||||
* bits 16-23 - 802.11n MCS index mask
|
||||
* support only 1 stream, thus only 8 bits for the MCS rates (0-7).
|
||||
*/
|
||||
u32 basic_rate_set;
|
||||
u32 basic_rate;
|
||||
u32 rate_set;
|
||||
u32 bitrate_masks[IEEE80211_NUM_BANDS];
|
||||
|
||||
/* The current band */
|
||||
enum ieee80211_band band;
|
||||
|
||||
/* Beaconing interval (needed for ad-hoc) */
|
||||
u32 beacon_int;
|
||||
|
||||
/* Default key (for WEP) */
|
||||
u32 default_key;
|
||||
|
||||
/* Rx Streaming */
|
||||
struct work_struct rx_streaming_enable_work;
|
||||
struct work_struct rx_streaming_disable_work;
|
||||
struct timer_list rx_streaming_timer;
|
||||
|
||||
struct completion *elp_compl;
|
||||
struct completion *ps_compl;
|
||||
struct delayed_work elp_work;
|
||||
struct delayed_work pspoll_work;
|
||||
|
||||
/* counter for ps-poll delivery failures */
|
||||
int ps_poll_failures;
|
||||
|
||||
/* retry counter for PSM entries */
|
||||
u8 psm_entry_retry;
|
||||
|
||||
/* in dBm */
|
||||
int power_level;
|
||||
|
||||
int rssi_thold;
|
||||
int last_rssi_event;
|
||||
|
||||
struct wl1271_stats stats;
|
||||
|
||||
__le32 buffer_32;
|
||||
|
@ -583,20 +446,9 @@ struct wl1271 {
|
|||
/* Most recently reported noise in dBm */
|
||||
s8 noise;
|
||||
|
||||
/* map for HLIDs of associated stations - when operating in AP mode */
|
||||
unsigned long ap_hlid_map[BITS_TO_LONGS(AP_MAX_STATIONS)];
|
||||
|
||||
/* recoreded keys for AP-mode - set here before AP startup */
|
||||
struct wl1271_ap_key *recorded_ap_keys[MAX_NUM_KEYS];
|
||||
|
||||
/* bands supported by this instance of wl12xx */
|
||||
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
|
||||
|
||||
/* RX BA constraint value */
|
||||
bool ba_support;
|
||||
u8 ba_rx_bitmap;
|
||||
bool ba_allowed;
|
||||
|
||||
int tcxo_clock;
|
||||
|
||||
/*
|
||||
|
@ -610,10 +462,7 @@ struct wl1271 {
|
|||
* AP-mode - links indexed by HLID. The global and broadcast links
|
||||
* are always active.
|
||||
*/
|
||||
struct wl1271_link links[AP_MAX_LINKS];
|
||||
|
||||
/* the hlid of the link where the last transmitted skb came from */
|
||||
int last_tx_hlid;
|
||||
struct wl1271_link links[WL12XX_MAX_LINKS];
|
||||
|
||||
/* AP-mode - a bitmap of links currently in PS mode according to FW */
|
||||
u32 ap_fw_ps_map;
|
||||
|
@ -632,21 +481,173 @@ struct wl1271 {
|
|||
|
||||
/* AP-mode - number of currently connected stations */
|
||||
int active_sta_count;
|
||||
|
||||
/* last wlvif we transmitted from */
|
||||
struct wl12xx_vif *last_wlvif;
|
||||
};
|
||||
|
||||
struct wl1271_station {
|
||||
u8 hlid;
|
||||
};
|
||||
|
||||
struct wl12xx_vif {
|
||||
struct wl1271 *wl;
|
||||
struct list_head list;
|
||||
unsigned long flags;
|
||||
u8 bss_type;
|
||||
u8 p2p; /* we are using p2p role */
|
||||
u8 role_id;
|
||||
|
||||
/* sta/ibss specific */
|
||||
u8 dev_role_id;
|
||||
u8 dev_hlid;
|
||||
|
||||
union {
|
||||
struct {
|
||||
u8 hlid;
|
||||
u8 ba_rx_bitmap;
|
||||
|
||||
u8 basic_rate_idx;
|
||||
u8 ap_rate_idx;
|
||||
u8 p2p_rate_idx;
|
||||
} sta;
|
||||
struct {
|
||||
u8 global_hlid;
|
||||
u8 bcast_hlid;
|
||||
|
||||
/* HLIDs bitmap of associated stations */
|
||||
unsigned long sta_hlid_map[BITS_TO_LONGS(
|
||||
WL12XX_MAX_LINKS)];
|
||||
|
||||
/* recoreded keys - set here before AP startup */
|
||||
struct wl1271_ap_key *recorded_keys[MAX_NUM_KEYS];
|
||||
|
||||
u8 mgmt_rate_idx;
|
||||
u8 bcast_rate_idx;
|
||||
u8 ucast_rate_idx[CONF_TX_MAX_AC_COUNT];
|
||||
} ap;
|
||||
};
|
||||
|
||||
/* the hlid of the last transmitted skb */
|
||||
int last_tx_hlid;
|
||||
|
||||
unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
|
||||
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
|
||||
u8 ssid_len;
|
||||
|
||||
/* The current band */
|
||||
enum ieee80211_band band;
|
||||
int channel;
|
||||
|
||||
u32 bitrate_masks[IEEE80211_NUM_BANDS];
|
||||
u32 basic_rate_set;
|
||||
|
||||
/*
|
||||
* currently configured rate set:
|
||||
* bits 0-15 - 802.11abg rates
|
||||
* bits 16-23 - 802.11n MCS index mask
|
||||
* support only 1 stream, thus only 8 bits for the MCS rates (0-7).
|
||||
*/
|
||||
u32 basic_rate;
|
||||
u32 rate_set;
|
||||
|
||||
/* probe-req template for the current AP */
|
||||
struct sk_buff *probereq;
|
||||
|
||||
/* Beaconing interval (needed for ad-hoc) */
|
||||
u32 beacon_int;
|
||||
|
||||
/* Default key (for WEP) */
|
||||
u32 default_key;
|
||||
|
||||
/* Our association ID */
|
||||
u16 aid;
|
||||
|
||||
/* Session counter for the chipset */
|
||||
int session_counter;
|
||||
|
||||
struct completion *ps_compl;
|
||||
struct delayed_work pspoll_work;
|
||||
|
||||
/* counter for ps-poll delivery failures */
|
||||
int ps_poll_failures;
|
||||
|
||||
/* retry counter for PSM entries */
|
||||
u8 psm_entry_retry;
|
||||
|
||||
/* in dBm */
|
||||
int power_level;
|
||||
|
||||
int rssi_thold;
|
||||
int last_rssi_event;
|
||||
|
||||
/* RX BA constraint value */
|
||||
bool ba_support;
|
||||
bool ba_allowed;
|
||||
|
||||
/* Rx Streaming */
|
||||
struct work_struct rx_streaming_enable_work;
|
||||
struct work_struct rx_streaming_disable_work;
|
||||
struct timer_list rx_streaming_timer;
|
||||
|
||||
/*
|
||||
* This struct must be last!
|
||||
* data that has to be saved acrossed reconfigs (e.g. recovery)
|
||||
* should be declared in this struct.
|
||||
*/
|
||||
struct {
|
||||
u8 persistent[0];
|
||||
/*
|
||||
* Security sequence number
|
||||
* bits 0-15: lower 16 bits part of sequence number
|
||||
* bits 16-47: higher 32 bits part of sequence number
|
||||
* bits 48-63: not in use
|
||||
*/
|
||||
u64 tx_security_seq;
|
||||
|
||||
/* 8 bits of the last sequence number in use */
|
||||
u8 tx_security_last_seq_lsb;
|
||||
};
|
||||
};
|
||||
|
||||
static inline struct wl12xx_vif *wl12xx_vif_to_data(struct ieee80211_vif *vif)
|
||||
{
|
||||
return (struct wl12xx_vif *)vif->drv_priv;
|
||||
}
|
||||
|
||||
static inline
|
||||
struct ieee80211_vif *wl12xx_wlvif_to_vif(struct wl12xx_vif *wlvif)
|
||||
{
|
||||
return container_of((void *)wlvif, struct ieee80211_vif, drv_priv);
|
||||
}
|
||||
|
||||
#define wl12xx_for_each_wlvif(wl, wlvif) \
|
||||
list_for_each_entry(wlvif, &wl->wlvif_list, list)
|
||||
|
||||
#define wl12xx_for_each_wlvif_continue(wl, wlvif) \
|
||||
list_for_each_entry_continue(wlvif, &wl->wlvif_list, list)
|
||||
|
||||
#define wl12xx_for_each_wlvif_bss_type(wl, wlvif, _bss_type) \
|
||||
wl12xx_for_each_wlvif(wl, wlvif) \
|
||||
if (wlvif->bss_type == _bss_type)
|
||||
|
||||
#define wl12xx_for_each_wlvif_sta(wl, wlvif) \
|
||||
wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_STA_BSS)
|
||||
|
||||
#define wl12xx_for_each_wlvif_ap(wl, wlvif) \
|
||||
wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_AP_BSS)
|
||||
|
||||
int wl1271_plt_start(struct wl1271 *wl);
|
||||
int wl1271_plt_stop(struct wl1271 *wl);
|
||||
int wl1271_recalc_rx_streaming(struct wl1271 *wl);
|
||||
int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
void wl12xx_queue_recovery_work(struct wl1271 *wl);
|
||||
size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
|
||||
|
||||
#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
|
||||
|
||||
#define SESSION_COUNTER_MAX 7 /* maximum value for the session counter */
|
||||
#define SESSION_COUNTER_MAX 6 /* maximum value for the session counter */
|
||||
#define SESSION_COUNTER_INVALID 7 /* used with dummy_packet */
|
||||
|
||||
#define WL1271_DEFAULT_POWER_LEVEL 0
|
||||
|
||||
|
@ -669,8 +670,8 @@ 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)
|
||||
|
||||
/* WL128X requires aggregated packets to be aligned to the SDIO block size */
|
||||
#define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2)
|
||||
/* wl127x and SPI don't support SDIO block size alignment */
|
||||
#define WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT BIT(2)
|
||||
|
||||
/* Older firmwares did not implement the FW logger over bus feature */
|
||||
#define WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4)
|
||||
|
|
|
@ -116,11 +116,6 @@ struct wl12xx_ps_poll_template {
|
|||
u8 ta[ETH_ALEN];
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_qos_null_data_template {
|
||||
struct ieee80211_header header;
|
||||
__le16 qos_ctl;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_arp_rsp_template {
|
||||
struct ieee80211_hdr_3addr hdr;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/wl12xx.h>
|
||||
|
||||
static const struct wl12xx_platform_data *platform_data;
|
||||
static struct wl12xx_platform_data *platform_data;
|
||||
|
||||
int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
|
||||
{
|
||||
|
@ -18,7 +18,7 @@ int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
const struct wl12xx_platform_data *wl12xx_get_platform_data(void)
|
||||
struct wl12xx_platform_data *wl12xx_get_platform_data(void)
|
||||
{
|
||||
if (!platform_data)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
|
|
@ -54,6 +54,9 @@ struct wl12xx_platform_data {
|
|||
int board_ref_clock;
|
||||
int board_tcxo_clock;
|
||||
unsigned long platform_quirks;
|
||||
bool pwr_in_suspend;
|
||||
|
||||
struct wl1271_if_operations *ops;
|
||||
};
|
||||
|
||||
/* Platform does not support level trigger interrupts */
|
||||
|
@ -73,6 +76,6 @@ int wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
|
|||
|
||||
#endif
|
||||
|
||||
const struct wl12xx_platform_data *wl12xx_get_platform_data(void);
|
||||
struct wl12xx_platform_data *wl12xx_get_platform_data(void);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue