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,43 @@ 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_sta_bt_wlan_coex_param *param;
struct conf_sg_settings *c = &wl->conf.sg;
int i, ret;
wl1271_debug(DEBUG_ACX, "acx sg sta cfg");
param = kzalloc(sizeof(*param), GFP_KERNEL);
if (!param) {
ret = -ENOMEM;
goto out;
}
/* BT-WLAN coext parameters */
for (i = 0; i < CONF_SG_STA_PARAMS_MAX; i++)
param->params[i] = cpu_to_le32(c->sta_params[i]);
param->param_idx = CONF_SG_PARAMS_ALL;
ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
if (ret < 0) {
wl1271_warning("failed to set sg config: %d", ret);
goto out;
}
out:
kfree(param);
return ret;
}
int wl1271_acx_ap_sg_cfg(struct wl1271 *wl)
{
struct acx_bt_wlan_coex_param *param;
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 cfg");
wl1271_debug(DEBUG_ACX, "acx sg ap cfg");
param = kzalloc(sizeof(*param), GFP_KERNEL);
if (!param) {
......@@ -555,8 +592,8 @@ 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_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,31 +424,42 @@ 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);
ret = wl1271_init_ap_rates(wl);
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_acx_max_tx_retry(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);
ret = wl1271_acx_ap_mem_cfg(wl);
if (ret < 0)
return ret;
ret = wl1271_acx_ap_max_tx_retry(wl);
return 0;
}
int wl1271_ap_init_templates(struct wl1271 *wl)
{
int ret;
ret = wl1271_ap_init_deauth_template(wl);
if (ret < 0)
return ret;
ret = wl1271_acx_ap_mem_cfg(wl);
ret = wl1271_ap_init_null_template(wl);
if (ret < 0)
return ret;
ret = wl1271_ap_init_qos_null_template(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;
......@@ -458,19 +468,56 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
{
int ret;
return wl1271_ap_init_templates(wl);
}
ret = wl1271_ap_init_deauth_template(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;
ret = wl1271_ap_init_null_template(wl);
/* 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;
ret = wl1271_ap_init_qos_null_template(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))
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
......@@ -51,7 +51,7 @@
static struct conf_drv_settings default_conf = {
.sg = {
.params = {
.sta_params = {
[CONF_SG_BT_PER_THRESHOLD] = 7500,
[CONF_SG_HV3_MAX_OVERRIDE] = 0,
[CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
......@@ -101,6 +101,61 @@ static struct conf_drv_settings default_conf = {
[CONF_SG_DHCP_TIME] = 5000,
[CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
},
.ap_params = {
[CONF_SG_BT_PER_THRESHOLD] = 7500,
[CONF_SG_HV3_MAX_OVERRIDE] = 0,
[CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
[CONF_SG_BT_LOAD_RATIO] = 50,
[CONF_SG_AUTO_PS_MODE] = 1,
[CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
[CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
[CONF_SG_ANTENNA_CONFIGURATION] = 0,
[CONF_SG_BEACON_MISS_PERCENT] = 60,
[CONF_SG_RATE_ADAPT_THRESH] = 64,
[CONF_SG_RATE_ADAPT_SNR] = 1,
[CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
[CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25,
[CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25,
[CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
[CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25,
[CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25,
[CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
[CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
[CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25,
[CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
[CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25,
[CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25,
[CONF_SG_RXT] = 1200,
[CONF_SG_TXT] = 1000,
[CONF_SG_ADAPTIVE_RXT_TXT] = 1,
[CONF_SG_PS_POLL_TIMEOUT] = 10,
[CONF_SG_UPSD_TIMEOUT] = 10,
[CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
[CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
[CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
[CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
[CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
[CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
[CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
[CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
[CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
[CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
[CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
[CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
[CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
[CONF_SG_HV3_MAX_SERVED] = 6,
[CONF_SG_DHCP_TIME] = 5000,
[CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
[CONF_SG_TEMP_PARAM_1] = 0,
[CONF_SG_TEMP_PARAM_2] = 0,
[CONF_SG_TEMP_PARAM_3] = 0,
[CONF_SG_TEMP_PARAM_4] = 0,
[CONF_SG_TEMP_PARAM_5] = 0,
[CONF_SG_AP_BEACON_MISS_TX] = 3,
[CONF_SG_RX_WINDOW_LENGTH] = 6,
[CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50,
[CONF_SG_TEMP_PARAM_6] = 1,
},
.state = CONF_SG_PROTECTIVE,
},
.rx = {
......@@ -108,7 +163,7 @@ static struct conf_drv_settings default_conf = {
.packet_detection_threshold = 0,
.ps_poll_timeout = 15,
.upsd_timeout = 15,
.rts_threshold = 2347,
.rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
.rx_cca_threshold = 0,
.irq_blk_threshold = 0xFFFF,
.irq_pkt_threshold = 0,
......@@ -154,46 +209,7 @@ static struct conf_drv_settings default_conf = {
.tx_op_limit = 1504,
},
},
.ap_rc_conf = {
[0] = {
.enabled_rates = CONF_TX_AP_ENABLED_RATES,
.short_retry_limit = 10,
.long_retry_limit = 10,
.aflags = 0,
},
[1] = {
.enabled_rates = CONF_TX_AP_ENABLED_RATES,
.short_retry_limit = 10,
.long_retry_limit = 10,
.aflags = 0,
},
[2] = {
.enabled_rates = CONF_TX_AP_ENABLED_RATES,
.short_retry_limit = 10,
.long_retry_limit = 10,
.aflags = 0,
},
[3] = {
.enabled_rates = CONF_TX_AP_ENABLED_RATES,
.short_retry_limit = 10,
.long_retry_limit = 10,
.aflags = 0,
},
},
.ap_mgmt_conf = {
.enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES,
.short_retry_limit = 10,
.long_retry_limit = 10,
.aflags = 0,
},
.ap_bcst_conf = {
.enabled_rates = CONF_HW_BIT_RATE_1MBPS,
.short_retry_limit = 10,
.long_retry_limit = 10,
.aflags = 0,
},
.max_tx_retries = 100,
.ap_aging_period = 300,
.ap_max_tx_retries = 100,
.tid_conf_count = 4,
.tid_conf = {
[CONF_TX_AC_BE] = {
......@@ -258,7 +274,7 @@ static struct conf_drv_settings default_conf = {
.bet_enable = CONF_BET_MODE_ENABLE,
.bet_max_consecutive = 50,
.psm_entry_retries = 5,
.psm_exit_retries = 255,
.psm_exit_retries = 16,
.psm_entry_nullfunc_retries = 3,
.psm_entry_hangover_period = 1,
.keep_alive_interval = 55000,
......@@ -305,7 +321,7 @@ static struct conf_drv_settings default_conf = {
.ssid_profiles = 1,
.rx_block_num = 70,
.tx_min_block_num = 40,
.dynamic_memory = 0,
.dynamic_memory = 1,
.min_req_tx_blocks = 100,
.min_req_rx_blocks = 22,
.tx_min = 27,
......@@ -320,10 +336,23 @@ static struct conf_drv_settings default_conf = {
.min_req_rx_blocks = 22,
.tx_min = 27,
},
.fm_coex = {
.enable = true,
.swallow_period = 5,
.n_divider_fref_set_1 = 0xff, /* default */
.n_divider_fref_set_2 = 12,
.m_divider_fref_set_1 = 148,
.m_divider_fref_set_2 = 0xffff, /* default */
.coex_pll_stabilization_time = 0xffffffff, /* default */
.ldo_stabilization_time = 0xffff, /* default */
.fm_disturbed_band_margin = 0xff, /* default */
.swallow_clk_diff = 0xff, /* default */
},
.hci_io_ds = HCI_IO_DS_6MA,
};
static void __wl1271_op_remove_interface(struct wl1271 *wl);
static void __wl1271_op_remove_interface(struct wl1271 *wl,
bool reset_tx_queues);
static void wl1271_free_ap_keys(struct wl1271 *wl);
......@@ -508,6 +537,11 @@ static int wl1271_plt_init(struct wl1271 *wl)
if (ret < 0)
goto out_free_memmap;
/* FM WLAN coexistence */
ret = wl1271_acx_fm_coex(wl);
if (ret < 0)
goto out_free_memmap;
/* Energy detection */
ret = wl1271_init_energy_detection(wl);
if (ret < 0)
......@@ -932,15 +966,25 @@ static void wl1271_recovery_work(struct work_struct *work)
if (wl->state != WL1271_STATE_ON)
goto out;
wl1271_info("Hardware recovery in progress.");
wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
ieee80211_connection_loss(wl->vif);
/* Prevent spurious TX during FW restart */
ieee80211_stop_queues(wl->hw);
/* reboot the chipset */
__wl1271_op_remove_interface(wl);
__wl1271_op_remove_interface(wl, false);
ieee80211_restart_hw(wl->hw);
/*
* Its safe to enable TX now - the queues are stopped after a request
* to restart the HW.
*/
ieee80211_wake_queues(wl->hw);
out:
mutex_unlock(&wl->mutex);
}
......@@ -1011,6 +1055,10 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
wl->chip.id);
/* end-of-transaction flag should be set in wl127x AP mode */
if (wl->bss_type == BSS_TYPE_AP_BSS)
wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
ret = wl1271_setup(wl);
if (ret < 0)
goto out;
......@@ -1273,7 +1321,7 @@ static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
skb->priority = WL1271_TID_MGMT;
/* Initialize all fields that might be used */
skb->queue_mapping = 0;
skb_set_queue_mapping(skb, 0);
memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
return skb;
......@@ -1440,7 +1488,8 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
return ret;
}
static void __wl1271_op_remove_interface(struct wl1271 *wl)
static void __wl1271_op_remove_interface(struct wl1271 *wl,
bool reset_tx_queues)
{
int i;
......@@ -1486,7 +1535,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
mutex_lock(&wl->mutex);
/* let's notify MAC80211 about the remaining pending TX frames */
wl1271_tx_reset(wl);
wl1271_tx_reset(wl, reset_tx_queues);
wl1271_power_off(wl);
memset(wl->bssid, 0, ETH_ALEN);
......@@ -1547,7 +1596,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
*/
if (wl->vif) {
WARN_ON(wl->vif != vif);
__wl1271_op_remove_interface(wl);
__wl1271_op_remove_interface(wl, true);
}
mutex_unlock(&wl->mutex);
......@@ -2284,7 +2333,7 @@ static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
if (ret < 0)
goto out;
ret = wl1271_acx_frag_threshold(wl, (u16)value);
ret = wl1271_acx_frag_threshold(wl, value);
if (ret < 0)
wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
......@@ -2312,7 +2361,7 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
if (ret < 0)
goto out;
ret = wl1271_acx_rts_threshold(wl, (u16) value);
ret = wl1271_acx_rts_threshold(wl, value);
if (ret < 0)
wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
......@@ -2455,24 +2504,19 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
if ((changed & BSS_CHANGED_BASIC_RATES)) {
u32 rates = bss_conf->basic_rates;
struct conf_tx_rate_class mgmt_rc;
wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
wl->basic_rate = wl1271_tx_min_rate_get(wl);
wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
wl->basic_rate_set);
/* update the AP management rate policy with the new rates */
mgmt_rc.enabled_rates = wl->basic_rate_set;
mgmt_rc.long_retry_limit = 10;
mgmt_rc.short_retry_limit = 10;
mgmt_rc.aflags = 0;
ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
ACX_TX_AP_MODE_MGMT_RATE);
ret = wl1271_init_ap_rates(wl);
if (ret < 0) {
wl1271_error("AP mgmt policy change failed %d", ret);
wl1271_error("AP rate policy change failed %d", ret);
goto out;
}
ret = wl1271_ap_init_templates(wl);
if (ret < 0)
goto out;
}
ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
......@@ -2505,6 +2549,24 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
}
}
if (changed & BSS_CHANGED_IBSS) {
wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
bss_conf->ibss_joined);
if (bss_conf->ibss_joined) {
u32 rates = bss_conf->basic_rates;
wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
rates);
wl->basic_rate = wl1271_tx_min_rate_get(wl);
/* by default, use 11b rates */
wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
ret = wl1271_acx_sta_rate_policies(wl);
if (ret < 0)
goto out;
}
}
ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
if (ret < 0)
goto out;
......@@ -2694,8 +2756,10 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
}
} else {
/* use defaults when not associated */
bool was_assoc =
!!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
&wl->flags);
clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
wl->aid = 0;
/* free probe-request template */
......@@ -2721,10 +2785,12 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
goto out;
/* restore the bssid filter and go to dummy bssid */
if (was_assoc) {
wl1271_unjoin(wl);
wl1271_dummy_join(wl);
}
}
}
ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
if (ret < 0)
......@@ -2954,12 +3020,6 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
}
bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
{
int id = hlid - WL1271_AP_STA_HLID_START;
return test_bit(id, wl->ap_hlid_map);
}
static int wl1271_op_sta_add(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
......@@ -3104,6 +3164,28 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
return ret;
}
static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
{
struct wl1271 *wl = hw->priv;
bool ret = false;
mutex_lock(&wl->mutex);
if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;
/* packets are considered pending if in the TX queue or the FW */
ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
/* the above is appropriate for STA mode for PS purposes */
WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
out:
mutex_unlock(&wl->mutex);
return ret;
}
/* can't be const, mac80211 writes to this */
static struct ieee80211_rate wl1271_rates[] = {
{ .bitrate = 10,
......@@ -3355,6 +3437,7 @@ static const struct ieee80211_ops wl1271_ops = {
.sta_add = wl1271_op_sta_add,
.sta_remove = wl1271_op_sta_remove,
.ampdu_action = wl1271_op_ampdu_action,
.tx_frames_pending = wl1271_tx_frames_pending,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
};
......@@ -3542,6 +3625,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
IEEE80211_HW_HAS_RATE_CONTROL |
IEEE80211_HW_CONNECTION_MONITOR |
IEEE80211_HW_SUPPORTS_CQM_RSSI |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_AP_LINK_PS;
wl->hw->wiphy->cipher_suites = cipher_suites;
......
......@@ -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);
/* 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,7 +806,9 @@ 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.
*/
if (reset_tx_queues)
wl1271_handle_tx_low_watermark(wl);
for (i = 0; i < ACX_TX_DESCRIPTORS; i++) {
......
......@@ -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