Commit 890641b2 authored by John W. Linville's avatar John W. Linville
parents eaef6a93 25eaea30
......@@ -325,12 +325,19 @@ int wl1271_acx_service_period_timeout(struct wl1271 *wl)
return ret;
}
int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold)
int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold)
{
struct acx_rts_threshold *rts;
int ret;
wl1271_debug(DEBUG_ACX, "acx rts threshold");
/*
* If the RTS threshold is not configured or out of range, use the
* default value.
*/
if (rts_threshold > IEEE80211_MAX_RTS_THRESHOLD)
rts_threshold = wl->conf.rx.rts_threshold;
wl1271_debug(DEBUG_ACX, "acx rts threshold: %d", rts_threshold);
rts = kzalloc(sizeof(*rts), GFP_KERNEL);
if (!rts) {
......@@ -338,7 +345,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold)
goto out;
}
rts->threshold = cpu_to_le16(rts_threshold);
rts->threshold = cpu_to_le16((u16)rts_threshold);
ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
if (ret < 0) {
......@@ -540,13 +547,13 @@ int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable)
return ret;
}
int wl1271_acx_sg_cfg(struct wl1271 *wl)
int wl1271_acx_sta_sg_cfg(struct wl1271 *wl)
{
struct acx_bt_wlan_coex_param *param;
struct acx_sta_bt_wlan_coex_param *param;
struct conf_sg_settings *c = &wl->conf.sg;
int i, ret;
wl1271_debug(DEBUG_ACX, "acx sg cfg");
wl1271_debug(DEBUG_ACX, "acx sg sta cfg");
param = kzalloc(sizeof(*param), GFP_KERNEL);
if (!param) {
......@@ -555,8 +562,38 @@ int wl1271_acx_sg_cfg(struct wl1271 *wl)
}
/* BT-WLAN coext parameters */
for (i = 0; i < CONF_SG_PARAMS_MAX; i++)
param->params[i] = cpu_to_le32(c->params[i]);
for (i = 0; i < CONF_SG_STA_PARAMS_MAX; i++)
param->params[i] = cpu_to_le32(c->sta_params[i]);
param->param_idx = CONF_SG_PARAMS_ALL;
ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
if (ret < 0) {
wl1271_warning("failed to set sg config: %d", ret);
goto out;
}
out:
kfree(param);
return ret;
}
int wl1271_acx_ap_sg_cfg(struct wl1271 *wl)
{
struct acx_ap_bt_wlan_coex_param *param;
struct conf_sg_settings *c = &wl->conf.sg;
int i, ret;
wl1271_debug(DEBUG_ACX, "acx sg ap cfg");
param = kzalloc(sizeof(*param), GFP_KERNEL);
if (!param) {
ret = -ENOMEM;
goto out;
}
/* BT-WLAN coext parameters */
for (i = 0; i < CONF_SG_AP_PARAMS_MAX; i++)
param->params[i] = cpu_to_le32(c->ap_params[i]);
param->param_idx = CONF_SG_PARAMS_ALL;
ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
......@@ -804,7 +841,8 @@ int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
struct acx_ap_rate_policy *acx;
int ret = 0;
wl1271_debug(DEBUG_ACX, "acx ap rate policy");
wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x",
idx, c->enabled_rates);
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
......@@ -898,12 +936,19 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
return ret;
}
int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold)
int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold)
{
struct acx_frag_threshold *acx;
int ret = 0;
wl1271_debug(DEBUG_ACX, "acx frag threshold");
/*
* If the fragmentation is not configured or out of range, use the
* default value.
*/
if (frag_threshold > IEEE80211_MAX_FRAG_THRESHOLD)
frag_threshold = wl->conf.tx.frag_threshold;
wl1271_debug(DEBUG_ACX, "acx frag threshold: %d", frag_threshold);
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
......@@ -912,7 +957,7 @@ int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold)
goto out;
}
acx->frag_threshold = cpu_to_le16(frag_threshold);
acx->frag_threshold = cpu_to_le16((u16)frag_threshold);
ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of frag threshold failed: %d", ret);
......@@ -954,6 +999,7 @@ int wl1271_acx_tx_config_options(struct wl1271 *wl)
int wl1271_acx_ap_mem_cfg(struct wl1271 *wl)
{
struct wl1271_acx_ap_config_memory *mem_conf;
struct conf_memory_settings *mem;
int ret;
wl1271_debug(DEBUG_ACX, "wl1271 mem cfg");
......@@ -964,14 +1010,21 @@ int wl1271_acx_ap_mem_cfg(struct wl1271 *wl)
goto out;
}
if (wl->chip.id == CHIP_ID_1283_PG20)
/*
* FIXME: The 128x AP FW does not yet support dynamic memory.
* Use the base memory configuration for 128x for now. This
* should be fine tuned in the future.
*/
mem = &wl->conf.mem_wl128x;
else
mem = &wl->conf.mem_wl127x;
/* memory config */
/* FIXME: for now we always use mem_wl127x for AP, because it
* doesn't support dynamic memory and we don't have the
* optimal values for wl128x without dynamic memory yet */
mem_conf->num_stations = wl->conf.mem_wl127x.num_stations;
mem_conf->rx_mem_block_num = wl->conf.mem_wl127x.rx_block_num;
mem_conf->tx_min_mem_block_num = wl->conf.mem_wl127x.tx_min_block_num;
mem_conf->num_ssid_profiles = wl->conf.mem_wl127x.ssid_profiles;
mem_conf->num_stations = mem->num_stations;
mem_conf->rx_mem_block_num = mem->rx_block_num;
mem_conf->tx_min_mem_block_num = mem->tx_min_block_num;
mem_conf->num_ssid_profiles = mem->ssid_profiles;
mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS);
ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
......@@ -1524,46 +1577,22 @@ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
return ret;
}
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
int wl1271_acx_max_tx_retry(struct wl1271 *wl)
{
struct wl1271_acx_ap_max_tx_retry *acx = NULL;
struct wl1271_acx_max_tx_retry *acx = NULL;
int ret;
wl1271_debug(DEBUG_ACX, "acx ap max tx retry");
wl1271_debug(DEBUG_ACX, "acx max tx retry");
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx)
return -ENOMEM;
acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries);
acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries);
ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx ap max tx retry failed: %d", ret);
goto out;
}
out:
kfree(acx);
return ret;
}
int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl)
{
struct wl1271_acx_sta_max_tx_retry *acx = NULL;
int ret;
wl1271_debug(DEBUG_ACX, "acx sta max tx retry");
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx)
return -ENOMEM;
acx->max_tx_retry = wl->conf.tx.max_tx_retries;
ret = wl1271_cmd_configure(wl, ACX_CONS_TX_FAILURE, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx sta max tx retry failed: %d", ret);
wl1271_warning("acx max tx retry failed: %d", ret);
goto out;
}
......@@ -1626,3 +1655,68 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr)
kfree(acx);
return ret;
}
int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable)
{
struct acx_ap_beacon_filter *acx = NULL;
int ret;
wl1271_debug(DEBUG_ACX, "acx set ap beacon filter: %d", enable);
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx)
return -ENOMEM;
acx->enable = enable ? 1 : 0;
ret = wl1271_cmd_configure(wl, ACX_AP_BEACON_FILTER_OPT,
acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx set ap beacon filter failed: %d", ret);
goto out;
}
out:
kfree(acx);
return ret;
}
int wl1271_acx_fm_coex(struct wl1271 *wl)
{
struct wl1271_acx_fm_coex *acx;
int ret;
wl1271_debug(DEBUG_ACX, "acx fm coex setting");
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}
acx->enable = wl->conf.fm_coex.enable;
acx->swallow_period = wl->conf.fm_coex.swallow_period;
acx->n_divider_fref_set_1 = wl->conf.fm_coex.n_divider_fref_set_1;
acx->n_divider_fref_set_2 = wl->conf.fm_coex.n_divider_fref_set_2;
acx->m_divider_fref_set_1 =
cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_1);
acx->m_divider_fref_set_2 =
cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_2);
acx->coex_pll_stabilization_time =
cpu_to_le32(wl->conf.fm_coex.coex_pll_stabilization_time);
acx->ldo_stabilization_time =
cpu_to_le16(wl->conf.fm_coex.ldo_stabilization_time);
acx->fm_disturbed_band_margin =
wl->conf.fm_coex.fm_disturbed_band_margin;
acx->swallow_clk_diff = wl->conf.fm_coex.swallow_clk_diff;
ret = wl1271_cmd_configure(wl, ACX_FM_COEX_CFG, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx fm coex setting failed: %d", ret);
goto out;
}
out:
kfree(acx);
return ret;
}
......@@ -303,7 +303,6 @@ struct acx_beacon_filter_option {
struct acx_header header;
u8 enable;
/*
* The number of beacons without the unicast TIM
* bit set that the firmware buffers before
......@@ -370,14 +369,23 @@ struct acx_bt_wlan_coex {
u8 pad[3];
} __packed;
struct acx_bt_wlan_coex_param {
struct acx_sta_bt_wlan_coex_param {
struct acx_header header;
__le32 params[CONF_SG_PARAMS_MAX];
__le32 params[CONF_SG_STA_PARAMS_MAX];
u8 param_idx;
u8 padding[3];
} __packed;
struct acx_ap_bt_wlan_coex_param {
struct acx_header header;
__le32 params[CONF_SG_AP_PARAMS_MAX];
u8 param_idx;
u8 padding[3];
} __packed;
struct acx_dco_itrim_params {
struct acx_header header;
......@@ -1145,7 +1153,7 @@ struct wl1271_acx_fw_tsf_information {
u8 padding[3];
} __packed;
struct wl1271_acx_ap_max_tx_retry {
struct wl1271_acx_max_tx_retry {
struct acx_header header;
/*
......@@ -1156,13 +1164,6 @@ struct wl1271_acx_ap_max_tx_retry {
u8 padding_1[2];
} __packed;
struct wl1271_acx_sta_max_tx_retry {
struct acx_header header;
u8 max_tx_retry;
u8 padding_1[3];
} __packed;
struct wl1271_acx_config_ps {
struct acx_header header;
......@@ -1179,6 +1180,72 @@ struct wl1271_acx_inconnection_sta {
u8 padding1[2];
} __packed;
struct acx_ap_beacon_filter {
struct acx_header header;
u8 enable;
u8 pad[3];
} __packed;
/*
* ACX_FM_COEX_CFG
* set the FM co-existence parameters.
*/
struct wl1271_acx_fm_coex {
struct acx_header header;
/* enable(1) / disable(0) the FM Coex feature */
u8 enable;
/*
* Swallow period used in COEX PLL swallowing mechanism.
* 0xFF = use FW default
*/
u8 swallow_period;
/*
* The N divider used in COEX PLL swallowing mechanism for Fref of
* 38.4/19.2 Mhz. 0xFF = use FW default
*/
u8 n_divider_fref_set_1;
/*
* The N divider used in COEX PLL swallowing mechanism for Fref of
* 26/52 Mhz. 0xFF = use FW default
*/
u8 n_divider_fref_set_2;
/*
* The M divider used in COEX PLL swallowing mechanism for Fref of
* 38.4/19.2 Mhz. 0xFFFF = use FW default
*/
__le16 m_divider_fref_set_1;
/*
* The M divider used in COEX PLL swallowing mechanism for Fref of
* 26/52 Mhz. 0xFFFF = use FW default
*/
__le16 m_divider_fref_set_2;
/*
* The time duration in uSec required for COEX PLL to stabilize.
* 0xFFFFFFFF = use FW default
*/
__le32 coex_pll_stabilization_time;
/*
* The time duration in uSec required for LDO to stabilize.
* 0xFFFFFFFF = use FW default
*/
__le16 ldo_stabilization_time;
/*
* The disturbed frequency band margin around the disturbed frequency
* center (single sided).
* For example, if 2 is configured, the following channels will be
* considered disturbed channel:
* 80 +- 0.1 MHz, 91 +- 0.1 MHz, 98 +- 0.1 MHz, 102 +- 0.1 MH
* 0xFF = use FW default
*/
u8 fm_disturbed_band_margin;
/*
* The swallow clock difference of the swallowing mechanism.
* 0xFF = use FW default
*/
u8 swallow_clk_diff;
} __packed;
enum {
ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003,
......@@ -1197,6 +1264,7 @@ enum {
ACX_TID_CFG = 0x001A,
ACX_PS_RX_STREAMING = 0x001B,
ACX_BEACON_FILTER_OPT = 0x001F,
ACX_AP_BEACON_FILTER_OPT = 0x0020,
ACX_NOISE_HIST = 0x0021,
ACX_HDK_VERSION = 0x0022, /* ??? */
ACX_PD_THRESHOLD = 0x0023,
......@@ -1208,6 +1276,7 @@ enum {
ACX_BCN_DTIM_OPTIONS = 0x0031,
ACX_SG_ENABLE = 0x0032,
ACX_SG_CFG = 0x0033,
ACX_FM_COEX_CFG = 0x0034,
ACX_BEACON_FILTER_TABLE = 0x0038,
ACX_ARP_IP_FILTER = 0x0039,
ACX_ROAMING_STATISTICS_TBL = 0x003B,
......@@ -1264,13 +1333,14 @@ 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, u16 rts_threshold);
int wl1271_acx_rts_threshold(struct wl1271 *wl, 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_sg_enable(struct wl1271 *wl, bool enable);
int wl1271_acx_sg_cfg(struct wl1271 *wl);
int wl1271_acx_sta_sg_cfg(struct wl1271 *wl);
int wl1271_acx_ap_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);
......@@ -1287,7 +1357,7 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
int wl1271_acx_tid_cfg(struct wl1271 *wl, 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, u16 frag_threshold);
int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold);
int wl1271_acx_tx_config_options(struct wl1271 *wl);
int wl1271_acx_ap_mem_cfg(struct wl1271 *wl);
int wl1271_acx_sta_mem_cfg(struct wl1271 *wl);
......@@ -1314,9 +1384,10 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl,
int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
bool enable);
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl);
int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl);
int wl1271_acx_max_tx_retry(struct wl1271 *wl);
int wl1271_acx_config_ps(struct wl1271 *wl);
int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable);
int wl1271_acx_fm_coex(struct wl1271 *wl);
#endif /* __WL1271_ACX_H__ */
......@@ -478,12 +478,10 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
DISCONNECT_EVENT_COMPLETE_ID |
RSSI_SNR_TRIGGER_0_EVENT_ID |
PSPOLL_DELIVERY_FAILURE_EVENT_ID |
SOFT_GEMINI_SENSE_EVENT_ID |
MAX_TX_RETRY_EVENT_ID;
SOFT_GEMINI_SENSE_EVENT_ID;
if (wl->bss_type == BSS_TYPE_AP_BSS)
wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID |
INACTIVE_STA_EVENT_ID;
wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID;
else
wl->event_mask |= DUMMY_PACKET_EVENT_ID;
......
......@@ -76,7 +76,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
if (time_after(jiffies, timeout)) {
wl1271_error("command complete timeout");
ret = -ETIMEDOUT;
goto out;
goto fail;
}
poll_count++;
......@@ -96,14 +96,17 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
status = le16_to_cpu(cmd->status);
if (status != CMD_STATUS_SUCCESS) {
wl1271_error("command execute failure %d", status);
ieee80211_queue_work(wl->hw, &wl->recovery_work);
ret = -EIO;
goto fail;
}
wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
WL1271_ACX_INTR_CMD_COMPLETE);
return 0;
out:
fail:
WARN_ON(1);
ieee80211_queue_work(wl->hw, &wl->recovery_work);
return ret;
}
......@@ -129,6 +132,9 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
if (gp->tx_bip_fem_auto_detect)
answer = true;
/* Override the REF CLK from the NVS with the one from platform data */
gen_parms->general_params.ref_clock = wl->ref_clock;
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
if (ret < 0) {
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
......@@ -168,6 +174,10 @@ int wl128x_cmd_general_parms(struct wl1271 *wl)
if (gp->tx_bip_fem_auto_detect)
answer = true;
/* Replace REF and TCXO CLKs with the ones from platform data */
gen_parms->general_params.ref_clock = wl->ref_clock;
gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock;
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
if (ret < 0) {
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
......@@ -1070,7 +1080,7 @@ int wl1271_cmd_start_bss(struct wl1271 *wl)
memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN);
cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC);
cmd->bss_index = WL1271_AP_BSS_INDEX;
cmd->global_hlid = WL1271_AP_GLOBAL_HLID;
cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID;
......
......@@ -396,12 +396,43 @@ enum {
CONF_SG_TEMP_PARAM_3,
CONF_SG_TEMP_PARAM_4,
CONF_SG_TEMP_PARAM_5,
CONF_SG_PARAMS_MAX,
/*
* AP beacon miss
*
* Range: 0 - 255
*/
CONF_SG_AP_BEACON_MISS_TX,
/*
* AP RX window length
*
* Range: 0 - 50
*/
CONF_SG_RX_WINDOW_LENGTH,
/*
* AP connection protection time
*
* Range: 0 - 5000
*/
CONF_SG_AP_CONNECTION_PROTECTION_TIME,
CONF_SG_TEMP_PARAM_6,
CONF_SG_TEMP_PARAM_7,
CONF_SG_TEMP_PARAM_8,
CONF_SG_TEMP_PARAM_9,
CONF_SG_TEMP_PARAM_10,
CONF_SG_STA_PARAMS_MAX = CONF_SG_TEMP_PARAM_5 + 1,
CONF_SG_AP_PARAMS_MAX = CONF_SG_TEMP_PARAM_10 + 1,
CONF_SG_PARAMS_ALL = 0xff
};
struct conf_sg_settings {
u32 params[CONF_SG_PARAMS_MAX];
u32 sta_params[CONF_SG_STA_PARAMS_MAX];
u32 ap_params[CONF_SG_AP_PARAMS_MAX];
u8 state;
};
......@@ -509,6 +540,12 @@ struct conf_rx_settings {
CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \
CONF_HW_BIT_RATE_54MBPS)
#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 | \
CONF_HW_BIT_RATE_54MBPS)
/*
* Default rates for management traffic when operating in AP mode. This
* should be configured according to the basic rate set of the AP
......@@ -516,6 +553,13 @@ struct conf_rx_settings {
#define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS)
/*
* Default rates for working as IBSS. use 11b rates
*/
#define CONF_TX_IBSS_DEFAULT_RATES (CONF_HW_BIT_RATE_1MBPS | \
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \
CONF_HW_BIT_RATE_11MBPS);
struct conf_tx_rate_class {
/*
......@@ -667,34 +711,10 @@ struct conf_tx_settings {
struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT];
/*
* Configuration for rate classes in AP-mode. These rate classes
* are for the AC TX queues
*/
struct conf_tx_rate_class ap_rc_conf[CONF_TX_MAX_AC_COUNT];
/*
* Management TX rate class for AP-mode.
*/
struct conf_tx_rate_class ap_mgmt_conf;
/*
* Broadcast TX rate class for AP-mode.
*/
struct conf_tx_rate_class ap_bcst_conf;
/*
* Allow this number of TX retries to a connected station/AP before an
* AP-mode - allow this number of TX retries to a station before an
* event is triggered from FW.
* In AP-mode the hlids of unreachable stations are given in the
* "sta_tx_retry_exceeded" member in the event mailbox.
*/
u8 max_tx_retries;
/*
* AP-mode - after this number of seconds a connected station is
* considered inactive.
*/
u16 ap_aging_period;
u16 ap_max_tx_retries;
/*
* Configuration for TID parameters.
......@@ -1192,6 +1212,19 @@ struct conf_memory_settings {
u8 tx_min;
};
struct conf_fm_coex {
u8 enable;
u8 swallow_period;
u8 n_divider_fref_set_1;
u8 n_divider_fref_set_2;
u16 m_divider_fref_set_1;
u16 m_divider_fref_set_2;
u32 coex_pll_stabilization_time;
u16 ldo_stabilization_time;
u8 fm_disturbed_band_margin;
u8 swallow_clk_diff;
};
struct conf_drv_settings {
struct conf_sg_settings sg;
struct conf_rx_settings rx;
......@@ -1205,6 +1238,7 @@ struct conf_drv_settings {
struct conf_ht_setting ht;
struct conf_memory_settings mem_wl127x;
struct conf_memory_settings mem_wl128x;
struct conf_fm_coex fm_coex;
u8 hci_io_ds;
};
......
......@@ -291,6 +291,241 @@ static const struct file_operations gpio_power_ops = {
.llseek = default_llseek,
};
static ssize_t start_recovery_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
mutex_lock(&wl->mutex);
ieee80211_queue_work(wl->hw, &wl->recovery_work);
mutex_unlock(&wl->mutex);
return count;
}
static const struct file_operations start_recovery_ops = {
.write = start_recovery_write,
.open = wl1271_open_file_generic,
.llseek = default_llseek,
};
static ssize_t driver_state_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
int res = 0;
char buf[1024];
mutex_lock(&wl->mutex);
#define DRIVER_STATE_PRINT(x, fmt) \
(res += scnprintf(buf + res, sizeof(buf) - res,\
#x " = " fmt "\n", wl->x))
#define DRIVER_STATE_PRINT_LONG(x) DRIVER_STATE_PRINT(x, "%ld")
#define DRIVER_STATE_PRINT_INT(x) DRIVER_STATE_PRINT(x, "%d")
#define DRIVER_STATE_PRINT_STR(x) DRIVER_STATE_PRINT(x, "%s")
#define DRIVER_STATE_PRINT_LHEX(x) DRIVER_STATE_PRINT(x, "0x%lx")
#define DRIVER_STATE_PRINT_HEX(x) DRIVER_STATE_PRINT(x, "0x%x")
DRIVER_STATE_PRINT_INT(tx_blocks_available);
DRIVER_STATE_PRINT_INT(tx_allocated_blocks);
DRIVER_STATE_PRINT_INT(tx_frames_cnt);
DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
DRIVER_STATE_PRINT_INT(tx_queue_count);
DRIVER_STATE_PRINT_INT(tx_packets_count);
DRIVER_STATE_PRINT_INT(tx_results_count);
DRIVER_STATE_PRINT_LHEX(flags);
DRIVER_STATE_PRINT_INT(tx_blocks_freed[0]);
DRIVER_STATE_PRINT_INT(tx_blocks_freed[1]);
DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]);
DRIVER_STATE_PRINT_INT(tx_blocks_freed[3]);
DRIVER_STATE_PRINT_INT(tx_security_last_seq);
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_HEX(filters);
DRIVER_STATE_PRINT_HEX(rx_config);
DRIVER_STATE_PRINT_HEX(rx_filter);
DRIVER_STATE_PRINT_INT(power_level);
DRIVER_STATE_PRINT_INT(rssi_thold);
DRIVER_STATE_PRINT_INT(last_rssi_event);
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);
DRIVER_STATE_PRINT_HEX(irq);
DRIVER_STATE_PRINT_HEX(ref_clock);
DRIVER_STATE_PRINT_HEX(tcxo_clock);
DRIVER_STATE_PRINT_HEX(hw_pg_ver);
DRIVER_STATE_PRINT_HEX(platform_quirks);
DRIVER_STATE_PRINT_HEX(chip.id);
DRIVER_STATE_PRINT_STR(chip.fw_ver_str);
#undef DRIVER_STATE_PRINT_INT
#undef DRIVER_STATE_PRINT_LONG
#undef DRIVER_STATE_PRINT_HEX
#undef DRIVER_STATE_PRINT_LHEX
#undef DRIVER_STATE_PRINT_STR
#undef DRIVER_STATE_PRINT
mutex_unlock(&wl->mutex);
return simple_read_from_buffer(user_buf, count, ppos, buf, res);
}
static const struct file_operations driver_state_ops = {
.read = driver_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)
{
struct wl1271 *wl = file->private_data;
u8 value;
if (wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_DTIM ||
wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_N_DTIM)
value = wl->conf.conn.listen_interval;
else
value = 0;
return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value);
}
static ssize_t dtim_interval_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
char buf[10];
size_t len;
unsigned long value;
int ret;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
ret = kstrtoul(buf, 0, &value);
if (ret < 0) {
wl1271_warning("illegal value for dtim_interval");
return -EINVAL;
}
if (value < 1 || value > 10) {
wl1271_warning("dtim value is not in valid range");
return -ERANGE;
}
mutex_lock(&wl->mutex);
wl->conf.conn.listen_interval = value;
/* for some reason there are different event types for 1 and >1 */
if (value == 1)
wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_DTIM;
else
wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM;
/*
* we don't reconfigure ACX_WAKE_UP_CONDITIONS now, so it will only
* take effect on the next time we enter psm.
*/
mutex_unlock(&wl->mutex);
return count;
}
static const struct file_operations dtim_interval_ops = {
.read = dtim_interval_read,
.write = dtim_interval_write,
.open = wl1271_open_file_generic,
.llseek = default_llseek,
};
static ssize_t beacon_interval_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
u8 value;
if (wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_BEACON ||
wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_N_BEACONS)
value = wl->conf.conn.listen_interval;
else
value = 0;
return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value);
}
static ssize_t beacon_interval_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
char buf[10];
size_t len;
unsigned long value;
int ret;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
ret = kstrtoul(buf, 0, &value);
if (ret < 0) {
wl1271_warning("illegal value for beacon_interval");
return -EINVAL;
}
if (value < 1 || value > 255) {
wl1271_warning("beacon interval value is not in valid range");
return -ERANGE;
}
mutex_lock(&wl->mutex);
wl->conf.conn.listen_interval = value;
/* for some reason there are different event types for 1 and >1 */
if (value == 1)
wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_BEACON;
else
wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_N_BEACONS;
/*
* we don't reconfigure ACX_WAKE_UP_CONDITIONS now, so it will only
* take effect on the next time we enter psm.
*/
mutex_unlock(&wl->mutex);
return count;
}
static const struct file_operations beacon_interval_ops = {
.read = beacon_interval_read,
.write = beacon_interval_write,
.open = wl1271_open_file_generic,
.llseek = default_llseek,
};
static int wl1271_debugfs_add_files(struct wl1271 *wl,
struct dentry *rootdir)
{
......@@ -399,6 +634,10 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
DEBUGFS_ADD(excessive_retries, rootdir);
DEBUGFS_ADD(gpio_power, rootdir);
DEBUGFS_ADD(start_recovery, rootdir);
DEBUGFS_ADD(driver_state, rootdir);
DEBUGFS_ADD(dtim_interval, rootdir);
DEBUGFS_ADD(beacon_interval, rootdir);
return 0;
......
......@@ -174,8 +174,6 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
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;
wl1271_event_mbox_dump(mbox);
......@@ -237,54 +235,9 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
wl1271_tx_dummy_packet(wl);
}
/*
* "TX retries exceeded" has a different meaning according to mode.
* In AP mode the offending station is disconnected. In STA mode we
* report connection loss.
*/
if (vector & MAX_TX_RETRY_EVENT_ID) {
wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID");
if (is_ap) {
sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded);
disconnect_sta = true;
} else {
beacon_loss = true;
}
}
if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) {
wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
sta_bitmap |= le16_to_cpu(mbox->sta_aging_status);
disconnect_sta = true;
}
if (wl->vif && beacon_loss)
ieee80211_connection_loss(wl->vif);
if (is_ap && 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))
continue;
addr = wl->links[h].addr;
rcu_read_lock();
sta = ieee80211_find_sta(wl->vif, addr);
if (sta) {
wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
ieee80211_report_low_ack(sta, num_packets);
}
rcu_read_unlock();
}
}
return 0;
}
......
......@@ -58,16 +58,13 @@ enum {
CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17),
BSS_LOSE_EVENT_ID = BIT(18),
REGAINED_BSS_EVENT_ID = BIT(19),
MAX_TX_RETRY_EVENT_ID = BIT(20),
ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20),
/* STA: dummy paket for dynamic mem blocks */
DUMMY_PACKET_EVENT_ID = BIT(21),
/* AP: STA remove complete */
STA_REMOVE_COMPLETE_EVENT_ID = BIT(21),
SOFT_GEMINI_SENSE_EVENT_ID = BIT(22),
/* STA: SG prediction */
SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23),
/* AP: Inactive STA */
INACTIVE_STA_EVENT_ID = BIT(23),
SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24),
PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25),
DBG_EVENT_ID = BIT(26),
......@@ -122,11 +119,7 @@ struct event_mailbox {
/* AP FW only */
u8 hlid_removed;
/* a bitmap of hlids for stations that have been inactive too long */
__le16 sta_aging_status;
/* a bitmap of hlids for stations which didn't respond to TX */
__le16 sta_tx_retry_exceeded;
u8 reserved_5[24];
......@@ -137,7 +130,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
......@@ -258,7 +258,7 @@ int wl1271_init_phy_config(struct wl1271 *wl)
if (ret < 0)
return ret;
ret = wl1271_acx_rts_threshold(wl, wl->conf.rx.rts_threshold);
ret = wl1271_acx_rts_threshold(wl, wl->hw->wiphy->rts_threshold);
if (ret < 0)
return ret;
......@@ -285,7 +285,10 @@ int wl1271_init_pta(struct wl1271 *wl)
{
int ret;
ret = wl1271_acx_sg_cfg(wl);
if (wl->bss_type == BSS_TYPE_AP_BSS)
ret = wl1271_acx_ap_sg_cfg(wl);
else
ret = wl1271_acx_sta_sg_cfg(wl);
if (ret < 0)
return ret;
......@@ -351,8 +354,8 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;
/* Bluetooth WLAN coexistence */
ret = wl1271_init_pta(wl);
/* FM WLAN coexistence */
ret = wl1271_acx_fm_coex(wl);
if (ret < 0)
return ret;
......@@ -375,10 +378,6 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;
ret = wl1271_acx_sta_max_tx_retry(wl);
if (ret < 0)
return ret;
ret = wl1271_acx_sta_mem_cfg(wl);
if (ret < 0)
return ret;
......@@ -414,7 +413,7 @@ static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl)
static int wl1271_ap_hw_init(struct wl1271 *wl)
{
int ret, i;
int ret;
ret = wl1271_ap_init_templates_config(wl);
if (ret < 0)
......@@ -425,27 +424,11 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;
/* Configure initial TX rate classes */
for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
ret = wl1271_acx_ap_rate_policy(wl,
&wl->conf.tx.ap_rc_conf[i], i);
if (ret < 0)
return ret;
}
ret = wl1271_acx_ap_rate_policy(wl,
&wl->conf.tx.ap_mgmt_conf,
ACX_TX_AP_MODE_MGMT_RATE);
ret = wl1271_init_ap_rates(wl);
if (ret < 0)
return ret;
ret = wl1271_acx_ap_rate_policy(wl,
&wl->conf.tx.ap_bcst_conf,
ACX_TX_AP_MODE_BCST_RATE);
if (ret < 0)
return ret;
ret = wl1271_acx_ap_max_tx_retry(wl);
ret = wl1271_acx_max_tx_retry(wl);
if (ret < 0)
return ret;
......@@ -456,7 +439,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
return 0;
}
static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
int wl1271_ap_init_templates(struct wl1271 *wl)
{
int ret;
......@@ -472,6 +455,70 @@ static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
if (ret < 0)
return ret;
/*
* when operating as AP we want to receive external beacons for
* configuring ERP protection.
*/
ret = wl1271_acx_set_ap_beacon_filter(wl, false);
if (ret < 0)
return ret;
return 0;
}
static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
{
return wl1271_ap_init_templates(wl);
}
int wl1271_init_ap_rates(struct wl1271 *wl)
{
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);
if (wl->basic_rate_set == 0)
return -EINVAL;
rc.enabled_rates = wl->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);
if (ret < 0)
return ret;
/* use the min basic rate for AP broadcast/multicast */
rc.enabled_rates = wl1271_tx_min_rate_get(wl);
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);
if (ret < 0)
return ret;
/*
* 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))
supported_rates = CONF_TX_OFDM_RATES;
else
supported_rates = CONF_TX_AP_ENABLED_RATES;
/* configure unicast TX rate classes */
for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
rc.enabled_rates = supported_rates;
rc.short_retry_limit = 10;
rc.long_retry_limit = 10;
rc.aflags = 0;
ret = wl1271_acx_ap_rate_policy(wl, &rc, i);
if (ret < 0)
return ret;
}
return 0;
}
......@@ -567,6 +614,11 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;
/* Bluetooth WLAN coexistence */
ret = wl1271_init_pta(wl);
if (ret < 0)
return ret;
/* Default memory configuration */
ret = wl1271_acx_init_mem_config(wl);
if (ret < 0)
......@@ -606,7 +658,7 @@ int wl1271_hw_init(struct wl1271 *wl)
goto out_free_memmap;
/* Default fragmentation threshold */
ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold);
if (ret < 0)
goto out_free_memmap;
......
......@@ -33,5 +33,7 @@ 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);
#endif
This diff is collapsed.
......@@ -43,6 +43,10 @@ void wl1271_elp_work(struct work_struct *work)
if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;
/* our work might have been already cancelled */
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)))
......@@ -61,12 +65,16 @@ void wl1271_elp_work(struct work_struct *work)
/* Routines to toggle sleep mode while in ELP */
void wl1271_ps_elp_sleep(struct wl1271 *wl)
{
if (test_bit(WL1271_FLAG_PSM, &wl->flags) ||
test_bit(WL1271_FLAG_IDLE, &wl->flags)) {
cancel_delayed_work(&wl->elp_work);
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
msecs_to_jiffies(ELP_ENTRY_DELAY));
}
/* 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) &&
!test_bit(WL1271_FLAG_IDLE, &wl->flags))
return;
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
msecs_to_jiffies(ELP_ENTRY_DELAY));
}
int wl1271_ps_elp_wakeup(struct wl1271 *wl)
......@@ -77,6 +85,16 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
u32 start_time = jiffies;
bool pending = false;
/*
* we might try to wake up even if we didn't go to sleep
* before (e.g. on boot)
*/
if (!test_and_clear_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))
return 0;
/* don't cancel_sync as it might contend for a mutex and deadlock */
cancel_delayed_work(&wl->elp_work);
if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags))
return 0;
......
......@@ -76,12 +76,15 @@ static void wl1271_rx_status(struct wl1271 *wl,
status->band);
if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK;
if (likely(!(desc->status & WL1271_RX_DESC_DECRYPT_FAIL)))
status->flag |= RX_FLAG_DECRYPTED;
if (unlikely(desc->status & WL1271_RX_DESC_MIC_FAIL))
status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED |
RX_FLAG_DECRYPTED;
if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) {
status->flag |= RX_FLAG_MMIC_ERROR;
wl1271_warning("Michael MIC error");
}
}
}
......@@ -100,6 +103,25 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
if (unlikely(wl->state == WL1271_STATE_PLT))
return -EINVAL;
/* the data read starts with the descriptor */
desc = (struct wl1271_rx_descriptor *) data;
switch (desc->status & WL1271_RX_DESC_STATUS_MASK) {
/* discard corrupted packets */
case WL1271_RX_DESC_DRIVER_RX_Q_FAIL:
case WL1271_RX_DESC_DECRYPT_FAIL:
wl1271_warning("corrupted packet in RX with status: 0x%x",
desc->status & WL1271_RX_DESC_STATUS_MASK);
return -EINVAL;
case WL1271_RX_DESC_SUCCESS:
case WL1271_RX_DESC_MIC_FAIL:
break;
default:
wl1271_error("invalid RX descriptor status: 0x%x",
desc->status & WL1271_RX_DESC_STATUS_MASK);
return -EINVAL;
}
skb = __dev_alloc_skb(length, GFP_KERNEL);
if (!skb) {
wl1271_error("Couldn't allocate RX frame");
......@@ -109,9 +131,6 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
buf = skb_put(skb, length);
memcpy(buf, data, length);
/* the data read starts with the descriptor */
desc = (struct wl1271_rx_descriptor *) buf;
/* now we pull the descriptor out of the buffer */
skb_pull(skb, sizeof(*desc));
......@@ -121,7 +140,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb,
skb->len - desc->pad_len,
beacon ? "beacon" : "");
skb_trim(skb, skb->len - desc->pad_len);
......
......@@ -65,6 +65,9 @@ static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb)
static void wl1271_free_tx_id(struct wl1271 *wl, int id)
{
if (__test_and_clear_bit(id, wl->tx_frames_map)) {
if (unlikely(wl->tx_frames_cnt == ACX_TX_DESCRIPTORS))
clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
wl->tx_frames[id] = NULL;
wl->tx_frames_cnt--;
}
......@@ -630,7 +633,7 @@ void wl1271_tx_work(struct work_struct *work)
wl1271_tx_work_locked(wl);
wl1271_ps_elp_wakeup(wl);
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
}
......@@ -766,8 +769,8 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
wl1271_handle_tx_low_watermark(wl);
}
/* caller must hold wl->mutex */
void wl1271_tx_reset(struct wl1271 *wl)
/* caller must hold wl->mutex and TX must be stopped */
void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
{
int i;
struct sk_buff *skb;
......@@ -803,8 +806,10 @@ void wl1271_tx_reset(struct wl1271 *wl)
/*
* Make sure the driver is at a consistent state, in case this
* function is called from a context other than interface removal.
* This call will always wake the TX queues.
*/
wl1271_handle_tx_low_watermark(wl);
if (reset_tx_queues)
wl1271_handle_tx_low_watermark(wl);
for (i = 0; i < ACX_TX_DESCRIPTORS; i++) {
if (wl->tx_frames[i] == NULL)
......
......@@ -185,7 +185,7 @@ static inline int wl1271_tx_get_queue(int queue)
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);
void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
void wl1271_tx_flush(struct wl1271 *wl);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
......
......@@ -172,6 +172,7 @@ extern u32 wl12xx_debug_level;
#define WL1271_PS_STA_MAX_BLOCKS (2 * 9)
#define WL1271_AP_BSS_INDEX 0
#define WL1271_AP_DEF_INACTIV_SEC 300
#define WL1271_AP_DEF_BEACON_EXP 20
#define ACX_TX_DESCRIPTORS 32
......@@ -345,6 +346,7 @@ enum wl12xx_flags {
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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment