Commit cbdbc5eb authored by John W. Linville's avatar John W. Linville
parents 8d8d3fdc e5e2f24b
...@@ -6742,12 +6742,12 @@ S: Maintained ...@@ -6742,12 +6742,12 @@ S: Maintained
F: drivers/net/wireless/wl1251/* F: drivers/net/wireless/wl1251/*
WL1271 WIRELESS DRIVER WL1271 WIRELESS DRIVER
M: Luciano Coelho <luciano.coelho@nokia.com> M: Luciano Coelho <coelho@ti.com>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org W: http://wireless.kernel.org/en/users/Drivers/wl12xx
T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
S: Maintained S: Maintained
F: drivers/net/wireless/wl12xx/wl1271* F: drivers/net/wireless/wl12xx/
F: include/linux/wl12xx.h F: include/linux/wl12xx.h
WL3501 WIRELESS PCMCIA CARD DRIVER WL3501 WIRELESS PCMCIA CARD DRIVER
......
...@@ -751,10 +751,10 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) ...@@ -751,10 +751,10 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
return 0; return 0;
} }
int wl1271_acx_rate_policies(struct wl1271 *wl) int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
{ {
struct acx_rate_policy *acx; struct acx_sta_rate_policy *acx;
struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf; struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf;
int idx = 0; int idx = 0;
int ret = 0; int ret = 0;
...@@ -794,6 +794,38 @@ int wl1271_acx_rate_policies(struct wl1271 *wl) ...@@ -794,6 +794,38 @@ int wl1271_acx_rate_policies(struct wl1271 *wl)
return ret; return ret;
} }
int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
u8 idx)
{
struct acx_ap_rate_policy *acx;
int ret = 0;
wl1271_debug(DEBUG_ACX, "acx ap rate policy");
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}
acx->rate_policy.enabled_rates = cpu_to_le32(c->enabled_rates);
acx->rate_policy.short_retry_limit = c->short_retry_limit;
acx->rate_policy.long_retry_limit = c->long_retry_limit;
acx->rate_policy.aflags = c->aflags;
acx->rate_policy_idx = cpu_to_le32(idx);
ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of ap rate policy failed: %d", ret);
goto out;
}
out:
kfree(acx);
return ret;
}
int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
u8 aifsn, u16 txop) u8 aifsn, u16 txop)
{ {
...@@ -1233,6 +1265,7 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, ...@@ -1233,6 +1265,7 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
struct wl1271_acx_ht_capabilities *acx; struct wl1271_acx_ht_capabilities *acx;
u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
int ret = 0; int ret = 0;
u32 ht_capabilites = 0;
wl1271_debug(DEBUG_ACX, "acx ht capabilities setting"); wl1271_debug(DEBUG_ACX, "acx ht capabilities setting");
...@@ -1244,16 +1277,16 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, ...@@ -1244,16 +1277,16 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
/* Allow HT Operation ? */ /* Allow HT Operation ? */
if (allow_ht_operation) { if (allow_ht_operation) {
acx->ht_capabilites = ht_capabilites =
WL1271_ACX_FW_CAP_HT_OPERATION; WL1271_ACX_FW_CAP_HT_OPERATION;
if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD) if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD)
acx->ht_capabilites |= ht_capabilites |=
WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT; WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT;
if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
acx->ht_capabilites |= ht_capabilites |=
WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS; WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS;
if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT) if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT)
acx->ht_capabilites |= ht_capabilites |=
WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION; WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION;
/* get data from A-MPDU parameters field */ /* get data from A-MPDU parameters field */
...@@ -1261,10 +1294,10 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, ...@@ -1261,10 +1294,10 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
acx->ampdu_min_spacing = ht_cap->ampdu_density; acx->ampdu_min_spacing = ht_cap->ampdu_density;
memcpy(acx->mac_address, mac_address, ETH_ALEN); memcpy(acx->mac_address, mac_address, ETH_ALEN);
} else { /* HT operations are not allowed */
acx->ht_capabilites = 0;
} }
acx->ht_capabilites = cpu_to_le32(ht_capabilites);
ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx));
if (ret < 0) { if (ret < 0) {
wl1271_warning("acx ht capabilities setting failed: %d", ret); wl1271_warning("acx ht capabilities setting failed: %d", ret);
...@@ -1309,6 +1342,91 @@ int wl1271_acx_set_ht_information(struct wl1271 *wl, ...@@ -1309,6 +1342,91 @@ int wl1271_acx_set_ht_information(struct wl1271 *wl,
return ret; return ret;
} }
/* Configure BA session initiator/receiver parameters setting in the FW. */
int wl1271_acx_set_ba_session(struct wl1271 *wl,
enum ieee80211_back_parties direction,
u8 tid_index, u8 policy)
{
struct wl1271_acx_ba_session_policy *acx;
int ret;
wl1271_debug(DEBUG_ACX, "acx ba session setting");
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}
/* ANY role */
acx->role_id = 0xff;
acx->tid = tid_index;
acx->enable = policy;
acx->ba_direction = direction;
switch (direction) {
case WLAN_BACK_INITIATOR:
acx->win_size = wl->conf.ht.tx_ba_win_size;
acx->inactivity_timeout = wl->conf.ht.inactivity_timeout;
break;
case WLAN_BACK_RECIPIENT:
acx->win_size = RX_BA_WIN_SIZE;
acx->inactivity_timeout = 0;
break;
default:
wl1271_error("Incorrect acx command id=%x\n", direction);
ret = -EINVAL;
goto out;
}
ret = wl1271_cmd_configure(wl,
ACX_BA_SESSION_POLICY_CFG,
acx,
sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx ba session setting failed: %d", ret);
goto out;
}
out:
kfree(acx);
return ret;
}
/* setup BA session receiver setting in the FW. */
int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
bool enable)
{
struct wl1271_acx_ba_receiver_setup *acx;
int ret;
wl1271_debug(DEBUG_ACX, "acx ba receiver session setting");
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}
/* Single link for now */
acx->link_id = 1;
acx->tid = tid_index;
acx->enable = enable;
acx->win_size = 0;
acx->ssn = ssn;
ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx,
sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx ba receiver session failed: %d", ret);
goto out;
}
out:
kfree(acx);
return ret;
}
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime) int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
{ {
struct wl1271_acx_fw_tsf_information *tsf_info; struct wl1271_acx_fw_tsf_information *tsf_info;
...@@ -1334,3 +1452,27 @@ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime) ...@@ -1334,3 +1452,27 @@ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
kfree(tsf_info); kfree(tsf_info);
return ret; return ret;
} }
int wl1271_acx_max_tx_retry(struct wl1271 *wl)
{
struct wl1271_acx_max_tx_retry *acx = NULL;
int ret;
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.ap_max_tx_retries);
ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx max tx retry failed: %d", ret);
goto out;
}
out:
kfree(acx);
return ret;
}
...@@ -747,13 +747,23 @@ struct acx_rate_class { ...@@ -747,13 +747,23 @@ struct acx_rate_class {
#define ACX_TX_BASIC_RATE 0 #define ACX_TX_BASIC_RATE 0
#define ACX_TX_AP_FULL_RATE 1 #define ACX_TX_AP_FULL_RATE 1
#define ACX_TX_RATE_POLICY_CNT 2 #define ACX_TX_RATE_POLICY_CNT 2
struct acx_rate_policy { struct acx_sta_rate_policy {
struct acx_header header; struct acx_header header;
__le32 rate_class_cnt; __le32 rate_class_cnt;
struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES]; struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES];
} __packed; } __packed;
#define ACX_TX_AP_MODE_MGMT_RATE 4
#define ACX_TX_AP_MODE_BCST_RATE 5
struct acx_ap_rate_policy {
struct acx_header header;
__le32 rate_policy_idx;
struct acx_rate_class rate_policy;
} __packed;
struct acx_ac_cfg { struct acx_ac_cfg {
struct acx_header header; struct acx_header header;
u8 ac; u8 ac;
...@@ -1051,6 +1061,59 @@ struct wl1271_acx_ht_information { ...@@ -1051,6 +1061,59 @@ struct wl1271_acx_ht_information {
u8 padding[3]; u8 padding[3];
} __packed; } __packed;
#define RX_BA_WIN_SIZE 8
struct wl1271_acx_ba_session_policy {
struct acx_header header;
/*
* Specifies role Id, Range 0-7, 0xFF means ANY role.
* Future use. For now this field is irrelevant
*/
u8 role_id;
/*
* Specifies Link Id, Range 0-31, 0xFF means ANY Link Id.
* Not applicable if Role Id is set to ANY.
*/
u8 link_id;
u8 tid;
u8 enable;
/* Windows size in number of packets */
u16 win_size;
/*
* As initiator inactivity timeout in time units(TU) of 1024us.
* As receiver reserved
*/
u16 inactivity_timeout;
/* Initiator = 1/Receiver = 0 */
u8 ba_direction;
u8 padding[3];
} __packed;
struct wl1271_acx_ba_receiver_setup {
struct acx_header header;
/* Specifies Link Id, Range 0-31, 0xFF means ANY Link Id */
u8 link_id;
u8 tid;
u8 enable;
u8 padding[1];
/* Windows size in number of packets */
u16 win_size;
/* BA session starting sequence number. RANGE 0-FFF */
u16 ssn;
} __packed;
struct wl1271_acx_fw_tsf_information { struct wl1271_acx_fw_tsf_information {
struct acx_header header; struct acx_header header;
...@@ -1062,6 +1125,17 @@ struct wl1271_acx_fw_tsf_information { ...@@ -1062,6 +1125,17 @@ struct wl1271_acx_fw_tsf_information {
u8 padding[3]; u8 padding[3];
} __packed; } __packed;
struct wl1271_acx_max_tx_retry {
struct acx_header header;
/*
* the number of frames transmission failures before
* issuing the aging event.
*/
__le16 max_tx_retry;
u8 padding_1[2];
} __packed;
enum { enum {
ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003, ACX_MEM_CFG = 0x0003,
...@@ -1113,12 +1187,13 @@ enum { ...@@ -1113,12 +1187,13 @@ enum {
ACX_RSSI_SNR_WEIGHTS = 0x0052, ACX_RSSI_SNR_WEIGHTS = 0x0052,
ACX_KEEP_ALIVE_MODE = 0x0053, ACX_KEEP_ALIVE_MODE = 0x0053,
ACX_SET_KEEP_ALIVE_CONFIG = 0x0054, ACX_SET_KEEP_ALIVE_CONFIG = 0x0054,
ACX_BA_SESSION_RESPONDER_POLICY = 0x0055, ACX_BA_SESSION_POLICY_CFG = 0x0055,
ACX_BA_SESSION_INITIATOR_POLICY = 0x0056, ACX_BA_SESSION_RX_SETUP = 0x0056,
ACX_PEER_HT_CAP = 0x0057, ACX_PEER_HT_CAP = 0x0057,
ACX_HT_BSS_OPERATION = 0x0058, ACX_HT_BSS_OPERATION = 0x0058,
ACX_COEX_ACTIVITY = 0x0059, ACX_COEX_ACTIVITY = 0x0059,
ACX_SET_DCO_ITRIM_PARAMS = 0x0061, ACX_SET_DCO_ITRIM_PARAMS = 0x0061,
ACX_MAX_TX_FAILURE = 0x0072,
DOT11_RX_MSDU_LIFE_TIME = 0x1004, DOT11_RX_MSDU_LIFE_TIME = 0x1004,
DOT11_CUR_TX_PWR = 0x100D, DOT11_CUR_TX_PWR = 0x100D,
DOT11_RX_DOT11_MODE = 0x1012, DOT11_RX_DOT11_MODE = 0x1012,
...@@ -1160,7 +1235,9 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); ...@@ -1160,7 +1235,9 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble);
int wl1271_acx_cts_protect(struct wl1271 *wl, int wl1271_acx_cts_protect(struct wl1271 *wl,
enum acx_ctsprotect_type ctsprotect); enum acx_ctsprotect_type ctsprotect);
int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
int wl1271_acx_rate_policies(struct wl1271 *wl); int wl1271_acx_sta_rate_policies(struct wl1271 *wl);
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, int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
u8 aifsn, u16 txop); u8 aifsn, u16 txop);
int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
...@@ -1185,6 +1262,12 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, ...@@ -1185,6 +1262,12 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
bool allow_ht_operation); bool allow_ht_operation);
int wl1271_acx_set_ht_information(struct wl1271 *wl, int wl1271_acx_set_ht_information(struct wl1271 *wl,
u16 ht_operation_mode); u16 ht_operation_mode);
int wl1271_acx_set_ba_session(struct wl1271 *wl,
enum ieee80211_back_parties direction,
u8 tid_index, u8 policy);
int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
bool enable);
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
int wl1271_acx_max_tx_retry(struct wl1271 *wl);
#endif /* __WL1271_ACX_H__ */ #endif /* __WL1271_ACX_H__ */
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "boot.h" #include "boot.h"
#include "io.h" #include "io.h"
#include "event.h" #include "event.h"
#include "rx.h"
static struct wl1271_partition_set part_table[PART_TABLE_LEN] = { static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
[PART_DOWN] = { [PART_DOWN] = {
...@@ -100,6 +101,22 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) ...@@ -100,6 +101,22 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
} }
static void wl1271_parse_fw_ver(struct wl1271 *wl)
{
int ret;
ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u",
&wl->chip.fw_ver[0], &wl->chip.fw_ver[1],
&wl->chip.fw_ver[2], &wl->chip.fw_ver[3],
&wl->chip.fw_ver[4]);
if (ret != 5) {
wl1271_warning("fw version incorrect value");
memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver));
return;
}
}
static void wl1271_boot_fw_version(struct wl1271 *wl) static void wl1271_boot_fw_version(struct wl1271 *wl)
{ {
struct wl1271_static_data static_data; struct wl1271_static_data static_data;
...@@ -107,11 +124,13 @@ static void wl1271_boot_fw_version(struct wl1271 *wl) ...@@ -107,11 +124,13 @@ static void wl1271_boot_fw_version(struct wl1271 *wl)
wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data), wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data),
false); false);
strncpy(wl->chip.fw_ver, static_data.fw_version, strncpy(wl->chip.fw_ver_str, static_data.fw_version,
sizeof(wl->chip.fw_ver)); sizeof(wl->chip.fw_ver_str));
/* make sure the string is NULL-terminated */ /* make sure the string is NULL-terminated */
wl->chip.fw_ver[sizeof(wl->chip.fw_ver) - 1] = '\0'; wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0';
wl1271_parse_fw_ver(wl);
} }
static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
...@@ -231,7 +250,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -231,7 +250,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
*/ */
if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || if (wl->nvs_len == sizeof(struct wl1271_nvs_file) ||
wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) {
if (wl->nvs->general_params.dual_mode_select) /* for now 11a is unsupported in AP mode */
if (wl->bss_type != BSS_TYPE_AP_BSS &&
wl->nvs->general_params.dual_mode_select)
wl->enable_11a = true; wl->enable_11a = true;
} }
...@@ -431,6 +452,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) ...@@ -431,6 +452,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
PSPOLL_DELIVERY_FAILURE_EVENT_ID | PSPOLL_DELIVERY_FAILURE_EVENT_ID |
SOFT_GEMINI_SENSE_EVENT_ID; SOFT_GEMINI_SENSE_EVENT_ID;
if (wl->bss_type == BSS_TYPE_AP_BSS)
wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID;
ret = wl1271_event_unmask(wl); ret = wl1271_event_unmask(wl);
if (ret < 0) { if (ret < 0) {
wl1271_error("EVENT mask setting failed"); wl1271_error("EVENT mask setting failed");
...@@ -595,8 +619,7 @@ int wl1271_boot(struct wl1271 *wl) ...@@ -595,8 +619,7 @@ int wl1271_boot(struct wl1271 *wl)
wl1271_boot_enable_interrupts(wl); wl1271_boot_enable_interrupts(wl);
/* set the wl1271 default filters */ /* set the wl1271 default filters */
wl->rx_config = WL1271_DEFAULT_RX_CONFIG; wl1271_set_default_filters(wl);
wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
wl1271_event_mbox_config(wl); wl1271_event_mbox_config(wl);
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "wl12xx_80211.h" #include "wl12xx_80211.h"
#include "cmd.h" #include "cmd.h"
#include "event.h" #include "event.h"
#include "tx.h"
#define WL1271_CMD_FAST_POLL_COUNT 50 #define WL1271_CMD_FAST_POLL_COUNT 50
...@@ -221,7 +222,7 @@ int wl1271_cmd_ext_radio_parms(struct wl1271 *wl) ...@@ -221,7 +222,7 @@ int wl1271_cmd_ext_radio_parms(struct wl1271 *wl)
* Poll the mailbox event field until any of the bits in the mask is set or a * Poll the mailbox event field until any of the bits in the mask is set or a
* timeout occurs (WL1271_EVENT_TIMEOUT in msecs) * timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
*/ */
static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask)
{ {
u32 events_vector, event; u32 events_vector, event;
unsigned long timeout; unsigned long timeout;
...@@ -230,7 +231,8 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) ...@@ -230,7 +231,8 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
do { do {
if (time_after(jiffies, timeout)) { if (time_after(jiffies, timeout)) {
ieee80211_queue_work(wl->hw, &wl->recovery_work); wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
(int)mask);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
...@@ -248,6 +250,19 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) ...@@ -248,6 +250,19 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
return 0; return 0;
} }
static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
{
int ret;
ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask);
if (ret != 0) {
ieee80211_queue_work(wl->hw, &wl->recovery_work);
return ret;
}
return 0;
}
int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
{ {
struct wl1271_cmd_join *join; struct wl1271_cmd_join *join;
...@@ -490,8 +505,8 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, ...@@ -490,8 +505,8 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
cmd->len = cpu_to_le16(buf_len); cmd->len = cpu_to_le16(buf_len);
cmd->template_type = template_id; cmd->template_type = template_id;
cmd->enabled_rates = cpu_to_le32(rates); cmd->enabled_rates = cpu_to_le32(rates);
cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit; cmd->short_retry_limit = wl->conf.tx.tmpl_short_retry_limit;
cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit; cmd->long_retry_limit = wl->conf.tx.tmpl_long_retry_limit;
cmd->index = index; cmd->index = index;
if (buf) if (buf)
...@@ -659,15 +674,15 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr) ...@@ -659,15 +674,15 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr)
/* llc layer */ /* llc layer */
memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header)); memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header));
tmpl.llc_type = htons(ETH_P_ARP); tmpl.llc_type = cpu_to_be16(ETH_P_ARP);
/* arp header */ /* arp header */
arp_hdr = &tmpl.arp_hdr; arp_hdr = &tmpl.arp_hdr;
arp_hdr->ar_hrd = htons(ARPHRD_ETHER); arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER);
arp_hdr->ar_pro = htons(ETH_P_IP); arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP);
arp_hdr->ar_hln = ETH_ALEN; arp_hdr->ar_hln = ETH_ALEN;
arp_hdr->ar_pln = 4; arp_hdr->ar_pln = 4;
arp_hdr->ar_op = htons(ARPOP_REPLY); arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY);
/* arp payload */ /* arp payload */
memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN); memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN);
...@@ -702,9 +717,9 @@ int wl1271_build_qos_null_data(struct wl1271 *wl) ...@@ -702,9 +717,9 @@ int wl1271_build_qos_null_data(struct wl1271 *wl)
wl->basic_rate); wl->basic_rate);
} }
int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id)
{ {
struct wl1271_cmd_set_keys *cmd; struct wl1271_cmd_set_sta_keys *cmd;
int ret = 0; int ret = 0;
wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id);
...@@ -731,11 +746,42 @@ int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) ...@@ -731,11 +746,42 @@ int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
return ret; return ret;
} }
int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id)
{
struct wl1271_cmd_set_ap_keys *cmd;
int ret = 0;
wl1271_debug(DEBUG_CMD, "cmd set_ap_default_wep_key %d", id);
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
cmd->hlid = WL1271_AP_BROADCAST_HLID;
cmd->key_id = id;
cmd->lid_key_type = WEP_DEFAULT_LID_TYPE;
cmd->key_action = cpu_to_le16(KEY_SET_ID);
cmd->key_type = KEY_WEP;
ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_warning("cmd set_ap_default_wep_key failed: %d", ret);
goto out;
}
out:
kfree(cmd);
return ret;
}
int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, const u8 *addr, u8 key_size, const u8 *key, const u8 *addr,
u32 tx_seq_32, u16 tx_seq_16) u32 tx_seq_32, u16 tx_seq_16)
{ {
struct wl1271_cmd_set_keys *cmd; struct wl1271_cmd_set_sta_keys *cmd;
int ret = 0; int ret = 0;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
...@@ -788,6 +834,67 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, ...@@ -788,6 +834,67 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
return ret; return ret;
} }
int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
u16 tx_seq_16)
{
struct wl1271_cmd_set_ap_keys *cmd;
int ret = 0;
u8 lid_type;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd)
return -ENOMEM;
if (hlid == WL1271_AP_BROADCAST_HLID) {
if (key_type == KEY_WEP)
lid_type = WEP_DEFAULT_LID_TYPE;
else
lid_type = BROADCAST_LID_TYPE;
} else {
lid_type = UNICAST_LID_TYPE;
}
wl1271_debug(DEBUG_CRYPT, "ap key action: %d id: %d lid: %d type: %d"
" hlid: %d", (int)action, (int)id, (int)lid_type,
(int)key_type, (int)hlid);
cmd->lid_key_type = lid_type;
cmd->hlid = hlid;
cmd->key_action = cpu_to_le16(action);
cmd->key_size = key_size;
cmd->key_type = key_type;
cmd->key_id = id;
cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);
if (key_type == KEY_TKIP) {
/*
* We get the key in the following form:
* TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
* but the target is expecting:
* TKIP - RX MIC - TX MIC
*/
memcpy(cmd->key, key, 16);
memcpy(cmd->key + 16, key + 24, 8);
memcpy(cmd->key + 24, key + 16, 8);
} else {
memcpy(cmd->key, key, key_size);
}
wl1271_dump(DEBUG_CRYPT, "TARGET AP KEY: ", cmd, sizeof(*cmd));
ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_warning("could not set ap keys");
goto out;
}
out:
kfree(cmd);
return ret;
}
int wl1271_cmd_disconnect(struct wl1271 *wl) int wl1271_cmd_disconnect(struct wl1271 *wl)
{ {
struct wl1271_cmd_disconnect *cmd; struct wl1271_cmd_disconnect *cmd;
...@@ -850,3 +957,180 @@ int wl1271_cmd_set_sta_state(struct wl1271 *wl) ...@@ -850,3 +957,180 @@ int wl1271_cmd_set_sta_state(struct wl1271 *wl)
out: out:
return ret; return ret;
} }
int wl1271_cmd_start_bss(struct wl1271 *wl)
{
struct wl1271_cmd_bss_start *cmd;
struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
int ret;
wl1271_debug(DEBUG_CMD, "cmd start bss");
/*
* FIXME: We currently do not support hidden SSID. The real SSID
* should be fetched from mac80211 first.
*/
if (wl->ssid_len == 0) {
wl1271_warning("Hidden SSID currently not supported for AP");
ret = -EINVAL;
goto out;
}
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN);
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;
cmd->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
cmd->beacon_interval = cpu_to_le16(wl->beacon_int);
cmd->dtim_interval = bss_conf->dtim_period;
cmd->beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
cmd->channel = wl->channel;
cmd->ssid_len = wl->ssid_len;
cmd->ssid_type = SSID_TYPE_PUBLIC;
memcpy(cmd->ssid, wl->ssid, wl->ssid_len);
switch (wl->band) {
case IEEE80211_BAND_2GHZ:
cmd->band = RADIO_BAND_2_4GHZ;
break;
case IEEE80211_BAND_5GHZ:
cmd->band = RADIO_BAND_5GHZ;
break;
default:
wl1271_warning("bss start - unknown band: %d", (int)wl->band);
cmd->band = RADIO_BAND_2_4GHZ;
break;
}
ret = wl1271_cmd_send(wl, CMD_BSS_START, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to initiate cmd start bss");
goto out_free;
}
out_free:
kfree(cmd);
out:
return ret;
}
int wl1271_cmd_stop_bss(struct wl1271 *wl)
{
struct wl1271_cmd_bss_start *cmd;
int ret;
wl1271_debug(DEBUG_CMD, "cmd stop bss");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
cmd->bss_index = WL1271_AP_BSS_INDEX;
ret = wl1271_cmd_send(wl, CMD_BSS_STOP, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to initiate cmd stop bss");
goto out_free;
}
out_free:
kfree(cmd);
out:
return ret;
}
int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
{
struct wl1271_cmd_add_sta *cmd;
int ret;
wl1271_debug(DEBUG_CMD, "cmd add sta %d", (int)hlid);
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
/* currently we don't support UAPSD */
cmd->sp_len = 0;
memcpy(cmd->addr, sta->addr, ETH_ALEN);
cmd->bss_index = WL1271_AP_BSS_INDEX;
cmd->aid = sta->aid;
cmd->hlid = hlid;
/*
* FIXME: Does STA support QOS? We need to propagate this info from
* hostapd. Currently not that important since this is only used for
* sending the correct flavor of null-data packet in response to a
* trigger.
*/
cmd->wmm = 0;
cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl,
sta->supp_rates[wl->band]));
wl1271_debug(DEBUG_CMD, "new sta rates: 0x%x", cmd->supported_rates);
ret = wl1271_cmd_send(wl, CMD_ADD_STA, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to initiate cmd add sta");
goto out_free;
}
out_free:
kfree(cmd);
out:
return ret;
}
int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid)
{
struct wl1271_cmd_remove_sta *cmd;
int ret;
wl1271_debug(DEBUG_CMD, "cmd remove sta %d", (int)hlid);
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
cmd->hlid = hlid;
/* We never send a deauth, mac80211 is in charge of this */
cmd->reason_opcode = 0;
cmd->send_deauth_flag = 0;
ret = wl1271_cmd_send(wl, CMD_REMOVE_STA, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to initiate cmd remove sta");
goto out_free;
}
/*
* We are ok with a timeout here. The event is sometimes not sent
* due to a firmware bug.
*/
wl1271_cmd_wait_for_event_or_timeout(wl, STA_REMOVE_COMPLETE_EVENT_ID);
out_free:
kfree(cmd);
out:
return ret;
}
...@@ -54,12 +54,20 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, ...@@ -54,12 +54,20 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr); int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr);
int wl1271_build_qos_null_data(struct wl1271 *wl); int wl1271_build_qos_null_data(struct wl1271 *wl);
int wl1271_cmd_build_klv_null_data(struct wl1271 *wl); int wl1271_cmd_build_klv_null_data(struct wl1271 *wl);
int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id);
int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id);
u8 key_size, const u8 *key, const u8 *addr, int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u32 tx_seq_32, u16 tx_seq_16); u8 key_size, const u8 *key, const u8 *addr,
u32 tx_seq_32, u16 tx_seq_16);
int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
u16 tx_seq_16);
int wl1271_cmd_disconnect(struct wl1271 *wl); int wl1271_cmd_disconnect(struct wl1271 *wl);
int wl1271_cmd_set_sta_state(struct wl1271 *wl); int wl1271_cmd_set_sta_state(struct wl1271 *wl);
int wl1271_cmd_start_bss(struct wl1271 *wl);
int wl1271_cmd_stop_bss(struct wl1271 *wl);
int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid);
int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid);
enum wl1271_commands { enum wl1271_commands {
CMD_INTERROGATE = 1, /*use this to read information elements*/ CMD_INTERROGATE = 1, /*use this to read information elements*/
...@@ -98,6 +106,12 @@ enum wl1271_commands { ...@@ -98,6 +106,12 @@ enum wl1271_commands {
CMD_STOP_PERIODIC_SCAN = 51, CMD_STOP_PERIODIC_SCAN = 51,
CMD_SET_STA_STATE = 52, CMD_SET_STA_STATE = 52,
/* AP mode commands */
CMD_BSS_START = 60,
CMD_BSS_STOP = 61,
CMD_ADD_STA = 62,
CMD_REMOVE_STA = 63,
NUM_COMMANDS, NUM_COMMANDS,
MAX_COMMAND_ID = 0xFFFF, MAX_COMMAND_ID = 0xFFFF,
}; };
...@@ -126,6 +140,13 @@ enum cmd_templ { ...@@ -126,6 +140,13 @@ enum cmd_templ {
* For CTS-to-self (FastCTS) mechanism * For CTS-to-self (FastCTS) mechanism
* for BT/WLAN coexistence (SoftGemini). */ * for BT/WLAN coexistence (SoftGemini). */
CMD_TEMPL_ARP_RSP, CMD_TEMPL_ARP_RSP,
/* AP-mode specific */
CMD_TEMPL_AP_BEACON = 13,
CMD_TEMPL_AP_PROBE_RESPONSE,
CMD_TEMPL_AP_ARP_RSP,
CMD_TEMPL_DEAUTH_AP,
CMD_TEMPL_MAX = 0xff CMD_TEMPL_MAX = 0xff
}; };
...@@ -270,7 +291,6 @@ struct wl1271_cmd_ps_params { ...@@ -270,7 +291,6 @@ struct wl1271_cmd_ps_params {
/* HW encryption keys */ /* HW encryption keys */
#define NUM_ACCESS_CATEGORIES_COPY 4 #define NUM_ACCESS_CATEGORIES_COPY 4
#define MAX_KEY_SIZE 32
enum wl1271_cmd_key_action { enum wl1271_cmd_key_action {
KEY_ADD_OR_REPLACE = 1, KEY_ADD_OR_REPLACE = 1,
...@@ -289,7 +309,7 @@ enum wl1271_cmd_key_type { ...@@ -289,7 +309,7 @@ enum wl1271_cmd_key_type {
/* FIXME: Add description for key-types */ /* FIXME: Add description for key-types */
struct wl1271_cmd_set_keys { struct wl1271_cmd_set_sta_keys {
struct wl1271_cmd_header header; struct wl1271_cmd_header header;
/* Ignored for default WEP key */ /* Ignored for default WEP key */
...@@ -318,6 +338,57 @@ struct wl1271_cmd_set_keys { ...@@ -318,6 +338,57 @@ struct wl1271_cmd_set_keys {
__le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
} __packed; } __packed;
enum wl1271_cmd_lid_key_type {
UNICAST_LID_TYPE = 0,
BROADCAST_LID_TYPE = 1,
WEP_DEFAULT_LID_TYPE = 2
};
struct wl1271_cmd_set_ap_keys {
struct wl1271_cmd_header header;
/*
* Indicates whether the HLID is a unicast key set
* or broadcast key set. A special value 0xFF is
* used to indicate that the HLID is on WEP-default
* (multi-hlids). of type wl1271_cmd_lid_key_type.
*/
u8 hlid;
/*
* In WEP-default network (hlid == 0xFF) used to
* indicate which network STA/IBSS/AP role should be
* changed
*/
u8 lid_key_type;
/*
* Key ID - For TKIP and AES key types, this field
* indicates the value that should be inserted into
* the KeyID field of frames transmitted using this
* key entry. For broadcast keys the index use as a
* marker for TX/RX key.
* For WEP default network (HLID=0xFF), this field
* indicates the ID of the key to add or remove.
*/
u8 key_id;
u8 reserved_1;
/* key_action_e */
__le16 key_action;
/* key size in bytes */
u8 key_size;
/* key_type_e */
u8 key_type;
/* This field holds the security key data to add to the STA table */
u8 key[MAX_KEY_SIZE];
__le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
__le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
} __packed;
struct wl1271_cmd_test_header { struct wl1271_cmd_test_header {
u8 id; u8 id;
u8 padding[3]; u8 padding[3];
...@@ -412,4 +483,68 @@ struct wl1271_cmd_set_sta_state { ...@@ -412,4 +483,68 @@ struct wl1271_cmd_set_sta_state {
u8 padding[3]; u8 padding[3];
} __packed; } __packed;
enum wl1271_ssid_type {
SSID_TYPE_PUBLIC = 0,
SSID_TYPE_HIDDEN = 1
};
struct wl1271_cmd_bss_start {
struct wl1271_cmd_header header;
/* wl1271_ssid_type */
u8 ssid_type;
u8 ssid_len;
u8 ssid[IW_ESSID_MAX_SIZE];
u8 padding_1[2];
/* Basic rate set */
__le32 basic_rate_set;
/* Aging period in seconds*/
__le16 aging_period;
/*
* This field specifies the time between target beacon
* transmission times (TBTTs), in time units (TUs).
* Valid values are 1 to 1024.
*/
__le16 beacon_interval;
u8 bssid[ETH_ALEN];
u8 bss_index;
/* Radio band */
u8 band;
u8 channel;
/* The host link id for the AP's global queue */
u8 global_hlid;
/* The host link id for the AP's broadcast queue */
u8 broadcast_hlid;
/* DTIM count */
u8 dtim_interval;
/* Beacon expiry time in ms */
u8 beacon_expiry;
u8 padding_2[3];
} __packed;
struct wl1271_cmd_add_sta {
struct wl1271_cmd_header header;
u8 addr[ETH_ALEN];
u8 hlid;
u8 aid;
u8 psd_type[NUM_ACCESS_CATEGORIES_COPY];
__le32 supported_rates;
u8 bss_index;
u8 sp_len;
u8 wmm;
u8 padding1;
} __packed;
struct wl1271_cmd_remove_sta {
struct wl1271_cmd_header header;
u8 hlid;
u8 reason_opcode;
u8 send_deauth_flag;
u8 padding1;
} __packed;
#endif /* __WL1271_CMD_H__ */ #endif /* __WL1271_CMD_H__ */
...@@ -496,6 +496,26 @@ struct conf_rx_settings { ...@@ -496,6 +496,26 @@ struct conf_rx_settings {
CONF_HW_BIT_RATE_2MBPS) CONF_HW_BIT_RATE_2MBPS)
#define CONF_TX_RATE_RETRY_LIMIT 10 #define CONF_TX_RATE_RETRY_LIMIT 10
/*
* Rates supported for data packets when operating as AP. Note the absense
* of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop
* one. The rate dropped is not mandatory under any operating mode.
*/
#define CONF_TX_AP_ENABLED_RATES (CONF_HW_BIT_RATE_1MBPS | \
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \
CONF_HW_BIT_RATE_6MBPS | CONF_HW_BIT_RATE_9MBPS | \
CONF_HW_BIT_RATE_11MBPS | CONF_HW_BIT_RATE_12MBPS | \
CONF_HW_BIT_RATE_18MBPS | 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
*/
#define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS)
struct conf_tx_rate_class { struct conf_tx_rate_class {
/* /*
...@@ -636,9 +656,9 @@ struct conf_tx_settings { ...@@ -636,9 +656,9 @@ struct conf_tx_settings {
/* /*
* Configuration for rate classes for TX (currently only one * Configuration for rate classes for TX (currently only one
* rate class supported.) * rate class supported). Used in non-AP mode.
*/ */
struct conf_tx_rate_class rc_conf; struct conf_tx_rate_class sta_rc_conf;
/* /*
* Configuration for access categories for TX rate control. * Configuration for access categories for TX rate control.
...@@ -646,6 +666,28 @@ struct conf_tx_settings { ...@@ -646,6 +666,28 @@ struct conf_tx_settings {
u8 ac_conf_count; u8 ac_conf_count;
struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT]; 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;
/*
* AP-mode - allow this number of TX retries to a station before an
* event is triggered from FW.
*/
u16 ap_max_tx_retries;
/* /*
* Configuration for TID parameters. * Configuration for TID parameters.
*/ */
...@@ -687,6 +729,12 @@ struct conf_tx_settings { ...@@ -687,6 +729,12 @@ struct conf_tx_settings {
* Range: CONF_HW_BIT_RATE_* bit mask * Range: CONF_HW_BIT_RATE_* bit mask
*/ */
u32 basic_rate_5; u32 basic_rate_5;
/*
* TX retry limits for templates
*/
u8 tmpl_short_retry_limit;
u8 tmpl_long_retry_limit;
}; };
enum { enum {
...@@ -1036,30 +1084,30 @@ struct conf_scan_settings { ...@@ -1036,30 +1084,30 @@ struct conf_scan_settings {
/* /*
* The minimum time to wait on each channel for active scans * The minimum time to wait on each channel for active scans
* *
* Range: 0 - 65536 tu * Range: u32 tu/1000
*/ */
u16 min_dwell_time_active; u32 min_dwell_time_active;
/* /*
* The maximum time to wait on each channel for active scans * The maximum time to wait on each channel for active scans
* *
* Range: 0 - 65536 tu * Range: u32 tu/1000
*/ */
u16 max_dwell_time_active; u32 max_dwell_time_active;
/* /*
* The maximum time to wait on each channel for passive scans * The minimum time to wait on each channel for passive scans
* *
* Range: 0 - 65536 tu * Range: u32 tu/1000
*/ */
u16 min_dwell_time_passive; u32 min_dwell_time_passive;
/* /*
* The maximum time to wait on each channel for passive scans * The maximum time to wait on each channel for passive scans
* *
* Range: 0 - 65536 tu * Range: u32 tu/1000
*/ */
u16 max_dwell_time_passive; u32 max_dwell_time_passive;
/* /*
* Number of probe requests to transmit on each active scan channel * Number of probe requests to transmit on each active scan channel
...@@ -1090,6 +1138,11 @@ struct conf_rf_settings { ...@@ -1090,6 +1138,11 @@ struct conf_rf_settings {
u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5];
}; };
struct conf_ht_setting {
u16 tx_ba_win_size;
u16 inactivity_timeout;
};
struct conf_drv_settings { struct conf_drv_settings {
struct conf_sg_settings sg; struct conf_sg_settings sg;
struct conf_rx_settings rx; struct conf_rx_settings rx;
...@@ -1100,6 +1153,7 @@ struct conf_drv_settings { ...@@ -1100,6 +1153,7 @@ struct conf_drv_settings {
struct conf_roam_trigger_settings roam_trigger; struct conf_roam_trigger_settings roam_trigger;
struct conf_scan_settings scan; struct conf_scan_settings scan;
struct conf_rf_settings rf; struct conf_rf_settings rf;
struct conf_ht_setting ht;
}; };
#endif #endif
...@@ -261,27 +261,25 @@ static ssize_t gpio_power_write(struct file *file, ...@@ -261,27 +261,25 @@ static ssize_t gpio_power_write(struct file *file,
unsigned long value; unsigned long value;
int ret; int ret;
mutex_lock(&wl->mutex);
len = min(count, sizeof(buf) - 1); len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len)) { if (copy_from_user(buf, user_buf, len)) {
ret = -EFAULT; return -EFAULT;
goto out;
} }
buf[len] = '\0'; buf[len] = '\0';
ret = strict_strtoul(buf, 0, &value); ret = strict_strtoul(buf, 0, &value);
if (ret < 0) { if (ret < 0) {
wl1271_warning("illegal value in gpio_power"); wl1271_warning("illegal value in gpio_power");
goto out; return -EINVAL;
} }
mutex_lock(&wl->mutex);
if (value) if (value)
wl1271_power_on(wl); wl1271_power_on(wl);
else else
wl1271_power_off(wl); wl1271_power_off(wl);
out:
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
return count; return count;
} }
...@@ -293,12 +291,13 @@ static const struct file_operations gpio_power_ops = { ...@@ -293,12 +291,13 @@ static const struct file_operations gpio_power_ops = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static int wl1271_debugfs_add_files(struct wl1271 *wl) static int wl1271_debugfs_add_files(struct wl1271 *wl,
struct dentry *rootdir)
{ {
int ret = 0; int ret = 0;
struct dentry *entry, *stats; struct dentry *entry, *stats;
stats = debugfs_create_dir("fw-statistics", wl->rootdir); stats = debugfs_create_dir("fw-statistics", rootdir);
if (!stats || IS_ERR(stats)) { if (!stats || IS_ERR(stats)) {
entry = stats; entry = stats;
goto err; goto err;
...@@ -395,16 +394,11 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl) ...@@ -395,16 +394,11 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl)
DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data);
DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
DEBUGFS_ADD(tx_queue_len, wl->rootdir); DEBUGFS_ADD(tx_queue_len, rootdir);
DEBUGFS_ADD(retry_count, wl->rootdir); DEBUGFS_ADD(retry_count, rootdir);
DEBUGFS_ADD(excessive_retries, wl->rootdir); DEBUGFS_ADD(excessive_retries, rootdir);
DEBUGFS_ADD(gpio_power, wl->rootdir);
entry = debugfs_create_x32("debug_level", 0600, wl->rootdir, DEBUGFS_ADD(gpio_power, rootdir);
&wl12xx_debug_level);
if (!entry || IS_ERR(entry))
goto err;
return 0; return 0;
...@@ -419,7 +413,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl) ...@@ -419,7 +413,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl)
void wl1271_debugfs_reset(struct wl1271 *wl) void wl1271_debugfs_reset(struct wl1271 *wl)
{ {
if (!wl->rootdir) if (!wl->stats.fw_stats)
return; return;
memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats));
...@@ -430,13 +424,13 @@ void wl1271_debugfs_reset(struct wl1271 *wl) ...@@ -430,13 +424,13 @@ void wl1271_debugfs_reset(struct wl1271 *wl)
int wl1271_debugfs_init(struct wl1271 *wl) int wl1271_debugfs_init(struct wl1271 *wl)
{ {
int ret; int ret;
struct dentry *rootdir;
wl->rootdir = debugfs_create_dir(KBUILD_MODNAME, rootdir = debugfs_create_dir(KBUILD_MODNAME,
wl->hw->wiphy->debugfsdir); wl->hw->wiphy->debugfsdir);
if (IS_ERR(wl->rootdir)) { if (IS_ERR(rootdir)) {
ret = PTR_ERR(wl->rootdir); ret = PTR_ERR(rootdir);
wl->rootdir = NULL;
goto err; goto err;
} }
...@@ -450,7 +444,7 @@ int wl1271_debugfs_init(struct wl1271 *wl) ...@@ -450,7 +444,7 @@ int wl1271_debugfs_init(struct wl1271 *wl)
wl->stats.fw_stats_update = jiffies; wl->stats.fw_stats_update = jiffies;
ret = wl1271_debugfs_add_files(wl); ret = wl1271_debugfs_add_files(wl, rootdir);
if (ret < 0) if (ret < 0)
goto err_file; goto err_file;
...@@ -462,8 +456,7 @@ int wl1271_debugfs_init(struct wl1271 *wl) ...@@ -462,8 +456,7 @@ int wl1271_debugfs_init(struct wl1271 *wl)
wl->stats.fw_stats = NULL; wl->stats.fw_stats = NULL;
err_fw: err_fw:
debugfs_remove_recursive(wl->rootdir); debugfs_remove_recursive(rootdir);
wl->rootdir = NULL;
err: err:
return ret; return ret;
...@@ -473,8 +466,4 @@ void wl1271_debugfs_exit(struct wl1271 *wl) ...@@ -473,8 +466,4 @@ void wl1271_debugfs_exit(struct wl1271 *wl)
{ {
kfree(wl->stats.fw_stats); kfree(wl->stats.fw_stats);
wl->stats.fw_stats = NULL; wl->stats.fw_stats = NULL;
debugfs_remove_recursive(wl->rootdir);
wl->rootdir = NULL;
} }
...@@ -186,6 +186,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) ...@@ -186,6 +186,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
int ret; int ret;
u32 vector; u32 vector;
bool beacon_loss = false; bool beacon_loss = false;
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
wl1271_event_mbox_dump(mbox); wl1271_event_mbox_dump(mbox);
...@@ -218,21 +219,21 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) ...@@ -218,21 +219,21 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
* BSS_LOSE_EVENT, beacon loss has to be reported to the stack. * BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
* *
*/ */
if (vector & BSS_LOSE_EVENT_ID) { if ((vector & BSS_LOSE_EVENT_ID) && !is_ap) {
wl1271_info("Beacon loss detected."); wl1271_info("Beacon loss detected.");
/* indicate to the stack, that beacons have been lost */ /* indicate to the stack, that beacons have been lost */
beacon_loss = true; beacon_loss = true;
} }
if (vector & PS_REPORT_EVENT_ID) { if ((vector & PS_REPORT_EVENT_ID) && !is_ap) {
wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT"); wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
ret = wl1271_event_ps_report(wl, mbox, &beacon_loss); ret = wl1271_event_ps_report(wl, mbox, &beacon_loss);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) if ((vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) && !is_ap)
wl1271_event_pspoll_delivery_fail(wl); wl1271_event_pspoll_delivery_fail(wl);
if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
......
...@@ -59,6 +59,7 @@ enum { ...@@ -59,6 +59,7 @@ enum {
BSS_LOSE_EVENT_ID = BIT(18), BSS_LOSE_EVENT_ID = BIT(18),
REGAINED_BSS_EVENT_ID = BIT(19), REGAINED_BSS_EVENT_ID = BIT(19),
ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20),
STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), /* AP */
SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), SOFT_GEMINI_SENSE_EVENT_ID = BIT(22),
SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23),
SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24),
...@@ -115,7 +116,12 @@ struct event_mailbox { ...@@ -115,7 +116,12 @@ struct event_mailbox {
u8 scheduled_scan_status; u8 scheduled_scan_status;
u8 ps_status; u8 ps_status;
u8 reserved_5[29]; /* AP FW only */
u8 hlid_removed;
__le16 sta_aging_status;
__le16 sta_tx_retry_exceeded;
u8 reserved_5[24];
} __packed; } __packed;
int wl1271_event_unmask(struct wl1271 *wl); int wl1271_event_unmask(struct wl1271 *wl);
......
This diff is collapsed.
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include "wl12xx.h" #include "wl12xx.h"
int wl1271_hw_init_power_auth(struct wl1271 *wl); int wl1271_hw_init_power_auth(struct wl1271 *wl);
int wl1271_init_templates_config(struct wl1271 *wl); int wl1271_sta_init_templates_config(struct wl1271 *wl);
int wl1271_init_phy_config(struct wl1271 *wl); int wl1271_init_phy_config(struct wl1271 *wl);
int wl1271_init_pta(struct wl1271 *wl); int wl1271_init_pta(struct wl1271 *wl);
int wl1271_init_energy_detection(struct wl1271 *wl); int wl1271_init_energy_detection(struct wl1271 *wl);
......
This diff is collapsed.
...@@ -198,6 +198,16 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) ...@@ -198,6 +198,16 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
pkt_offset += pkt_length; pkt_offset += pkt_length;
} }
} }
wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
cpu_to_le32(wl->rx_counter)); }
void wl1271_set_default_filters(struct wl1271 *wl)
{
if (wl->bss_type == BSS_TYPE_AP_BSS) {
wl->rx_config = WL1271_DEFAULT_AP_RX_CONFIG;
wl->rx_filter = WL1271_DEFAULT_AP_RX_FILTER;
} else {
wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
}
} }
...@@ -86,8 +86,9 @@ ...@@ -86,8 +86,9 @@
/* /*
* RX Descriptor status * RX Descriptor status
* *
* Bits 0-2 - status * Bits 0-2 - error code
* Bits 3-7 - reserved * Bits 3-5 - process_id tag (AP mode FW)
* Bits 6-7 - reserved
*/ */
#define WL1271_RX_DESC_STATUS_MASK 0x07 #define WL1271_RX_DESC_STATUS_MASK 0x07
...@@ -110,12 +111,16 @@ struct wl1271_rx_descriptor { ...@@ -110,12 +111,16 @@ struct wl1271_rx_descriptor {
u8 snr; u8 snr;
__le32 timestamp; __le32 timestamp;
u8 packet_class; u8 packet_class;
u8 process_id; union {
u8 process_id; /* STA FW */
u8 hlid; /* AP FW */
} __packed;
u8 pad_len; u8 pad_len;
u8 reserved; u8 reserved;
} __packed; } __packed;
void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status); void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
void wl1271_set_default_filters(struct wl1271 *wl);
#endif #endif
...@@ -345,3 +345,4 @@ MODULE_LICENSE("GPL"); ...@@ -345,3 +345,4 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>"); MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
MODULE_FIRMWARE(WL1271_FW_NAME); MODULE_FIRMWARE(WL1271_FW_NAME);
MODULE_FIRMWARE(WL1271_AP_FW_NAME);
...@@ -110,9 +110,9 @@ static void wl1271_spi_reset(struct wl1271 *wl) ...@@ -110,9 +110,9 @@ static void wl1271_spi_reset(struct wl1271 *wl)
spi_message_add_tail(&t, &m); spi_message_add_tail(&t, &m);
spi_sync(wl_to_spi(wl), &m); spi_sync(wl_to_spi(wl), &m);
kfree(cmd);
wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
kfree(cmd);
} }
static void wl1271_spi_init(struct wl1271 *wl) static void wl1271_spi_init(struct wl1271 *wl)
...@@ -495,4 +495,5 @@ MODULE_LICENSE("GPL"); ...@@ -495,4 +495,5 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>"); MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
MODULE_FIRMWARE(WL1271_FW_NAME); MODULE_FIRMWARE(WL1271_FW_NAME);
MODULE_FIRMWARE(WL1271_AP_FW_NAME);
MODULE_ALIAS("spi:wl1271"); MODULE_ALIAS("spi:wl1271");
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/etherdevice.h>
#include "wl12xx.h" #include "wl12xx.h"
#include "io.h" #include "io.h"
...@@ -30,6 +31,23 @@ ...@@ -30,6 +31,23 @@
#include "ps.h" #include "ps.h"
#include "tx.h" #include "tx.h"
static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id)
{
int ret;
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
if (is_ap)
ret = wl1271_cmd_set_ap_default_wep_key(wl, id);
else
ret = wl1271_cmd_set_sta_default_wep_key(wl, id);
if (ret < 0)
return ret;
wl1271_debug(DEBUG_CRYPT, "default wep key idx: %d", (int)id);
return 0;
}
static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb)
{ {
int id; int id;
...@@ -99,7 +117,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, ...@@ -99,7 +117,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
{ {
struct timespec ts; struct timespec ts;
struct wl1271_tx_hw_descr *desc; struct wl1271_tx_hw_descr *desc;
int pad, ac; int pad, ac, rate_idx;
s64 hosttime; s64 hosttime;
u16 tx_attr; u16 tx_attr;
...@@ -117,7 +135,11 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, ...@@ -117,7 +135,11 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
getnstimeofday(&ts); getnstimeofday(&ts);
hosttime = (timespec_to_ns(&ts) >> 10); hosttime = (timespec_to_ns(&ts) >> 10);
desc->start_time = cpu_to_le32(hosttime - wl->time_offset); desc->start_time = cpu_to_le32(hosttime - wl->time_offset);
desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU);
if (wl->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);
/* configure the tx attributes */ /* configure the tx attributes */
tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
...@@ -125,7 +147,41 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, ...@@ -125,7 +147,41 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
/* queue (we use same identifiers for tid's and ac's */ /* queue (we use same identifiers for tid's and ac's */
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
desc->tid = ac; desc->tid = ac;
desc->aid = TX_HW_DEFAULT_AID;
if (wl->bss_type != BSS_TYPE_AP_BSS) {
desc->aid = TX_HW_DEFAULT_AID;
/* 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;
else
rate_idx = ACX_TX_BASIC_RATE;
} else {
if (control->control.sta) {
struct wl1271_station *wl_sta;
wl_sta = (struct wl1271_station *)
control->control.sta->drv_priv;
desc->hlid = wl_sta->hlid;
rate_idx = ac;
} else {
struct ieee80211_hdr *hdr;
hdr = (struct ieee80211_hdr *)
(skb->data + sizeof(*desc));
if (ieee80211_is_mgmt(hdr->frame_control)) {
desc->hlid = WL1271_AP_GLOBAL_HLID;
rate_idx = ACX_TX_AP_MODE_MGMT_RATE;
} else {
desc->hlid = WL1271_AP_BROADCAST_HLID;
rate_idx = ACX_TX_AP_MODE_BCST_RATE;
}
}
}
tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY;
desc->reserved = 0; desc->reserved = 0;
/* align the length (and store in terms of words) */ /* align the length (and store in terms of words) */
...@@ -136,14 +192,12 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, ...@@ -136,14 +192,12 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
pad = pad - skb->len; pad = pad - skb->len;
tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
/* 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)
tx_attr |= ACX_TX_AP_FULL_RATE << TX_HW_ATTR_OFST_RATE_POLICY;
desc->tx_attr = cpu_to_le16(tx_attr); desc->tx_attr = cpu_to_le16(tx_attr);
wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d "
"tx_attr: 0x%x len: %d life: %d mem: %d", pad, desc->hlid,
le16_to_cpu(desc->tx_attr), le16_to_cpu(desc->length),
le16_to_cpu(desc->life_time), desc->total_mem_blocks);
} }
/* caller must hold wl->mutex */ /* caller must hold wl->mutex */
...@@ -153,7 +207,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, ...@@ -153,7 +207,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
u32 extra = 0; u32 extra = 0;
int ret = 0; int ret = 0;
u8 idx;
u32 total_len; u32 total_len;
if (!skb) if (!skb)
...@@ -166,11 +219,15 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, ...@@ -166,11 +219,15 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
extra = WL1271_TKIP_IV_SPACE; extra = WL1271_TKIP_IV_SPACE;
if (info->control.hw_key) { if (info->control.hw_key) {
idx = info->control.hw_key->hw_key_idx; bool is_wep;
u8 idx = info->control.hw_key->hw_key_idx;
u32 cipher = info->control.hw_key->cipher;
is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) ||
(cipher == WLAN_CIPHER_SUITE_WEP104);
/* FIXME: do we have to do this if we're not using WEP? */ if (unlikely(is_wep && wl->default_key != idx)) {
if (unlikely(wl->default_key != idx)) { ret = wl1271_set_default_wep_key(wl, idx);
ret = wl1271_cmd_set_default_wep_key(wl, idx);
if (ret < 0) if (ret < 0)
return ret; return ret;
wl->default_key = idx; wl->default_key = idx;
...@@ -303,7 +360,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl) ...@@ -303,7 +360,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
woken_up = true; woken_up = true;
wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates); wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates);
wl1271_acx_rate_policies(wl); wl1271_acx_sta_rate_policies(wl);
} }
while ((skb = wl1271_skb_dequeue(wl))) { while ((skb = wl1271_skb_dequeue(wl))) {
...@@ -521,3 +578,21 @@ void wl1271_tx_flush(struct wl1271 *wl) ...@@ -521,3 +578,21 @@ void wl1271_tx_flush(struct wl1271 *wl)
wl1271_warning("Unable to flush all TX buffers, timed out."); wl1271_warning("Unable to flush all TX buffers, timed out.");
} }
u32 wl1271_tx_min_rate_get(struct wl1271 *wl)
{
int i;
u32 rate = 0;
if (!wl->basic_rate_set) {
WARN_ON(1);
wl->basic_rate_set = wl->conf.tx.basic_rate;
}
for (i = 0; !rate; i++) {
if ((wl->basic_rate_set >> i) & 0x1)
rate = 1 << i;
}
return rate;
}
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#define TX_HW_BLOCK_SIZE 252 #define TX_HW_BLOCK_SIZE 252
#define TX_HW_MGMT_PKT_LIFETIME_TU 2000 #define TX_HW_MGMT_PKT_LIFETIME_TU 2000
#define TX_HW_AP_MODE_PKT_LIFETIME_TU 8000
/* The chipset reference driver states, that the "aid" value 1 /* The chipset reference driver states, that the "aid" value 1
* is for infra-BSS, but is still always used */ * is for infra-BSS, but is still always used */
#define TX_HW_DEFAULT_AID 1 #define TX_HW_DEFAULT_AID 1
...@@ -77,8 +78,12 @@ struct wl1271_tx_hw_descr { ...@@ -77,8 +78,12 @@ struct wl1271_tx_hw_descr {
u8 id; u8 id;
/* The packet TID value (as User-Priority) */ /* The packet TID value (as User-Priority) */
u8 tid; u8 tid;
/* Identifier of the remote STA in IBSS, 1 in infra-BSS */ union {
u8 aid; /* STA - Identifier of the remote STA in IBSS, 1 in infra-BSS */
u8 aid;
/* AP - host link ID (HLID) */
u8 hlid;
} __packed;
u8 reserved; u8 reserved;
} __packed; } __packed;
...@@ -146,5 +151,6 @@ void wl1271_tx_reset(struct wl1271 *wl); ...@@ -146,5 +151,6 @@ void wl1271_tx_reset(struct wl1271 *wl);
void wl1271_tx_flush(struct wl1271 *wl); void wl1271_tx_flush(struct wl1271 *wl);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
u32 wl1271_tx_min_rate_get(struct wl1271 *wl);
#endif #endif
...@@ -38,6 +38,13 @@ ...@@ -38,6 +38,13 @@
#define DRIVER_NAME "wl1271" #define DRIVER_NAME "wl1271"
#define DRIVER_PREFIX DRIVER_NAME ": " #define DRIVER_PREFIX DRIVER_NAME ": "
/*
* FW versions support BA 11n
* versions marks x.x.x.50-60.x
*/
#define WL12XX_BA_SUPPORT_FW_COST_VER2_START 50
#define WL12XX_BA_SUPPORT_FW_COST_VER2_END 60
enum { enum {
DEBUG_NONE = 0, DEBUG_NONE = 0,
DEBUG_IRQ = BIT(0), DEBUG_IRQ = BIT(0),
...@@ -57,6 +64,8 @@ enum { ...@@ -57,6 +64,8 @@ enum {
DEBUG_SDIO = BIT(14), DEBUG_SDIO = BIT(14),
DEBUG_FILTERS = BIT(15), DEBUG_FILTERS = BIT(15),
DEBUG_ADHOC = BIT(16), DEBUG_ADHOC = BIT(16),
DEBUG_AP = BIT(17),
DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP),
DEBUG_ALL = ~0, DEBUG_ALL = ~0,
}; };
...@@ -103,16 +112,27 @@ extern u32 wl12xx_debug_level; ...@@ -103,16 +112,27 @@ extern u32 wl12xx_debug_level;
true); \ true); \
} while (0) } while (0)
#define WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ #define WL1271_DEFAULT_STA_RX_CONFIG (CFG_UNI_FILTER_EN | \
CFG_BSSID_FILTER_EN | \ CFG_BSSID_FILTER_EN | \
CFG_MC_FILTER_EN) CFG_MC_FILTER_EN)
#define WL1271_DEFAULT_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \ #define WL1271_DEFAULT_STA_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \
CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \ CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
CFG_RX_CTL_EN | CFG_RX_BCN_EN | \ CFG_RX_CTL_EN | CFG_RX_BCN_EN | \
CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
#define WL1271_DEFAULT_AP_RX_CONFIG 0
#define WL1271_DEFAULT_AP_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PREQ_EN | \
CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
CFG_RX_CTL_EN | CFG_RX_AUTH_EN | \
CFG_RX_ASSOC_EN)
#define WL1271_FW_NAME "wl1271-fw.bin" #define WL1271_FW_NAME "wl1271-fw.bin"
#define WL1271_AP_FW_NAME "wl1271-fw-ap.bin"
#define WL1271_NVS_NAME "wl1271-nvs.bin" #define WL1271_NVS_NAME "wl1271-nvs.bin"
#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
...@@ -129,6 +149,14 @@ extern u32 wl12xx_debug_level; ...@@ -129,6 +149,14 @@ extern u32 wl12xx_debug_level;
#define WL1271_DEFAULT_BEACON_INT 100 #define WL1271_DEFAULT_BEACON_INT 100
#define WL1271_DEFAULT_DTIM_PERIOD 1 #define WL1271_DEFAULT_DTIM_PERIOD 1
#define WL1271_AP_GLOBAL_HLID 0
#define WL1271_AP_BROADCAST_HLID 1
#define WL1271_AP_STA_HLID_START 2
#define WL1271_AP_BSS_INDEX 0
#define WL1271_AP_DEF_INACTIV_SEC 300
#define WL1271_AP_DEF_BEACON_EXP 20
#define ACX_TX_DESCRIPTORS 32 #define ACX_TX_DESCRIPTORS 32
#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) #define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
...@@ -161,10 +189,13 @@ struct wl1271_partition_set { ...@@ -161,10 +189,13 @@ struct wl1271_partition_set {
struct wl1271; struct wl1271;
#define WL12XX_NUM_FW_VER 5
/* FIXME: I'm not sure about this structure name */ /* FIXME: I'm not sure about this structure name */
struct wl1271_chip { struct wl1271_chip {
u32 id; u32 id;
char fw_ver[21]; char fw_ver_str[ETHTOOL_BUSINFO_LEN];
unsigned int fw_ver[WL12XX_NUM_FW_VER];
}; };
struct wl1271_stats { struct wl1271_stats {
...@@ -178,6 +209,11 @@ struct wl1271_stats { ...@@ -178,6 +209,11 @@ struct wl1271_stats {
#define NUM_TX_QUEUES 4 #define NUM_TX_QUEUES 4
#define NUM_RX_PKT_DESC 8 #define NUM_RX_PKT_DESC 8
#define AP_MAX_STATIONS 5
/* Broadcast and Global links + links to stations */
#define AP_MAX_LINKS (AP_MAX_STATIONS + 2)
/* FW status registers */ /* FW status registers */
struct wl1271_fw_status { struct wl1271_fw_status {
__le32 intr; __le32 intr;
...@@ -188,7 +224,18 @@ struct wl1271_fw_status { ...@@ -188,7 +224,18 @@ struct wl1271_fw_status {
__le32 rx_pkt_descs[NUM_RX_PKT_DESC]; __le32 rx_pkt_descs[NUM_RX_PKT_DESC];
__le32 tx_released_blks[NUM_TX_QUEUES]; __le32 tx_released_blks[NUM_TX_QUEUES];
__le32 fw_localtime; __le32 fw_localtime;
__le32 padding[2];
/* Next fields valid only in AP FW */
/*
* A bitmap (where each bit represents a single HLID)
* to indicate if the station is in PS mode.
*/
__le32 link_ps_bitmap;
/* Number of freed MBs per HLID */
u8 tx_lnk_free_blks[AP_MAX_LINKS];
u8 padding_1[1];
} __packed; } __packed;
struct wl1271_rx_mem_pool_addr { struct wl1271_rx_mem_pool_addr {
...@@ -218,6 +265,19 @@ struct wl1271_if_operations { ...@@ -218,6 +265,19 @@ struct wl1271_if_operations {
void (*disable_irq)(struct wl1271 *wl); void (*disable_irq)(struct wl1271 *wl);
}; };
#define MAX_NUM_KEYS 14
#define MAX_KEY_SIZE 32
struct wl1271_ap_key {
u8 id;
u8 key_type;
u8 key_size;
u8 key[MAX_KEY_SIZE];
u8 hlid;
u32 tx_seq_32;
u16 tx_seq_16;
};
struct wl1271 { struct wl1271 {
struct platform_device *plat_dev; struct platform_device *plat_dev;
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
...@@ -251,6 +311,7 @@ struct wl1271 { ...@@ -251,6 +311,7 @@ struct wl1271 {
#define WL1271_FLAG_PSPOLL_FAILURE (12) #define WL1271_FLAG_PSPOLL_FAILURE (12)
#define WL1271_FLAG_STA_STATE_SENT (13) #define WL1271_FLAG_STA_STATE_SENT (13)
#define WL1271_FLAG_FW_TX_BUSY (14) #define WL1271_FLAG_FW_TX_BUSY (14)
#define WL1271_FLAG_AP_STARTED (15)
unsigned long flags; unsigned long flags;
struct wl1271_partition_set part; struct wl1271_partition_set part;
...@@ -262,6 +323,7 @@ struct wl1271 { ...@@ -262,6 +323,7 @@ struct wl1271 {
u8 *fw; u8 *fw;
size_t fw_len; size_t fw_len;
u8 fw_bss_type;
struct wl1271_nvs_file *nvs; struct wl1271_nvs_file *nvs;
size_t nvs_len; size_t nvs_len;
...@@ -378,7 +440,6 @@ struct wl1271 { ...@@ -378,7 +440,6 @@ struct wl1271 {
int last_rssi_event; int last_rssi_event;
struct wl1271_stats stats; struct wl1271_stats stats;
struct dentry *rootdir;
__le32 buffer_32; __le32 buffer_32;
u32 buffer_cmd; u32 buffer_cmd;
...@@ -400,6 +461,23 @@ struct wl1271 { ...@@ -400,6 +461,23 @@ struct wl1271 {
/* Most recently reported noise in dBm */ /* Most recently reported noise in dBm */
s8 noise; 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;
};
struct wl1271_station {
u8 hlid;
}; };
int wl1271_plt_start(struct wl1271 *wl); int wl1271_plt_start(struct wl1271 *wl);
......
...@@ -138,13 +138,13 @@ struct wl12xx_arp_rsp_template { ...@@ -138,13 +138,13 @@ struct wl12xx_arp_rsp_template {
struct ieee80211_hdr_3addr hdr; struct ieee80211_hdr_3addr hdr;
u8 llc_hdr[sizeof(rfc1042_header)]; u8 llc_hdr[sizeof(rfc1042_header)];
u16 llc_type; __be16 llc_type;
struct arphdr arp_hdr; struct arphdr arp_hdr;
u8 sender_hw[ETH_ALEN]; u8 sender_hw[ETH_ALEN];
u32 sender_ip; __be32 sender_ip;
u8 target_hw[ETH_ALEN]; u8 target_hw[ETH_ALEN];
u32 target_ip; __be32 target_ip;
} __packed; } __packed;
...@@ -160,4 +160,9 @@ struct wl12xx_probe_resp_template { ...@@ -160,4 +160,9 @@ struct wl12xx_probe_resp_template {
struct wl12xx_ie_country country; struct wl12xx_ie_country country;
} __packed; } __packed;
struct wl12xx_disconn_template {
struct ieee80211_header header;
__le16 disconn_reason;
} __packed;
#endif #endif
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