Commit 46bf6958 authored by John W. Linville's avatar John W. Linville
parents e7480bbb 4b48e687
...@@ -6321,7 +6321,7 @@ WL1271 WIRELESS DRIVER ...@@ -6321,7 +6321,7 @@ WL1271 WIRELESS DRIVER
M: Luciano Coelho <luciano.coelho@nokia.com> M: Luciano Coelho <luciano.coelho@nokia.com>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org W: http://wireless.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.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/wl1271*
F: include/linux/wl12xx.h F: include/linux/wl12xx.h
......
...@@ -213,7 +213,7 @@ static struct omap2_hsmmc_info mmc[] __initdata = { ...@@ -213,7 +213,7 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
{ {
.name = "wl1271", .name = "wl1271",
.mmc = 3, .mmc = 3,
.wires = 4, .caps = MMC_CAP_4_BIT_DATA,
.gpio_wp = -EINVAL, .gpio_wp = -EINVAL,
.gpio_cd = -EINVAL, .gpio_cd = -EINVAL,
.nonremovable = true, .nonremovable = true,
......
...@@ -117,10 +117,7 @@ enum { ...@@ -117,10 +117,7 @@ enum {
#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
/* #define WL1271_CIPHER_SUITE_GEM 0x00147201
* Enable/disable 802.11a support for WL1273
*/
#undef WL1271_80211A_ENABLED
#define WL1271_BUSY_WORD_CNT 1 #define WL1271_BUSY_WORD_CNT 1
#define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32)) #define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32))
...@@ -133,6 +130,8 @@ enum { ...@@ -133,6 +130,8 @@ enum {
#define ACX_TX_DESCRIPTORS 32 #define ACX_TX_DESCRIPTORS 32
#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
enum wl1271_state { enum wl1271_state {
WL1271_STATE_OFF, WL1271_STATE_OFF,
WL1271_STATE_ON, WL1271_STATE_ON,
...@@ -301,6 +300,7 @@ struct wl1271_rx_mem_pool_addr { ...@@ -301,6 +300,7 @@ struct wl1271_rx_mem_pool_addr {
struct wl1271_scan { struct wl1271_scan {
struct cfg80211_scan_request *req; struct cfg80211_scan_request *req;
bool *scanned_ch; bool *scanned_ch;
bool failed;
u8 state; u8 state;
u8 ssid[IW_ESSID_MAX_SIZE+1]; u8 ssid[IW_ESSID_MAX_SIZE+1];
size_t ssid_len; size_t ssid_len;
...@@ -350,6 +350,7 @@ struct wl1271 { ...@@ -350,6 +350,7 @@ struct wl1271 {
#define WL1271_FLAG_IDLE (10) #define WL1271_FLAG_IDLE (10)
#define WL1271_FLAG_IDLE_REQUESTED (11) #define WL1271_FLAG_IDLE_REQUESTED (11)
#define WL1271_FLAG_PSPOLL_FAILURE (12) #define WL1271_FLAG_PSPOLL_FAILURE (12)
#define WL1271_FLAG_STA_STATE_SENT (13)
unsigned long flags; unsigned long flags;
struct wl1271_partition_set part; struct wl1271_partition_set part;
...@@ -362,6 +363,7 @@ struct wl1271 { ...@@ -362,6 +363,7 @@ struct wl1271 {
u8 *fw; u8 *fw;
size_t fw_len; size_t fw_len;
struct wl1271_nvs_file *nvs; struct wl1271_nvs_file *nvs;
size_t nvs_len;
s8 hw_pg_ver; s8 hw_pg_ver;
...@@ -408,9 +410,15 @@ struct wl1271 { ...@@ -408,9 +410,15 @@ struct wl1271 {
/* Rx memory pool address */ /* Rx memory pool address */
struct wl1271_rx_mem_pool_addr rx_mem_pool_addr; struct wl1271_rx_mem_pool_addr rx_mem_pool_addr;
/* Intermediate buffer, used for packet aggregation */
u8 *aggr_buf;
/* The target interrupt mask */ /* The target interrupt mask */
struct work_struct irq_work; struct work_struct irq_work;
/* Hardware recovery work */
struct work_struct recovery_work;
/* The mbox event mask */ /* The mbox event mask */
u32 event_mask; u32 event_mask;
...@@ -419,6 +427,7 @@ struct wl1271 { ...@@ -419,6 +427,7 @@ struct wl1271 {
/* Are we currently scanning */ /* Are we currently scanning */
struct wl1271_scan scan; struct wl1271_scan scan;
struct delayed_work scan_complete_work;
/* Our association ID */ /* Our association ID */
u16 aid; u16 aid;
...@@ -475,6 +484,8 @@ struct wl1271 { ...@@ -475,6 +484,8 @@ struct wl1271 {
bool sg_enabled; bool sg_enabled;
bool enable_11a;
struct list_head list; struct list_head list;
/* Most recently reported noise in dBm */ /* Most recently reported noise in dBm */
...@@ -498,14 +509,4 @@ int wl1271_plt_stop(struct wl1271 *wl); ...@@ -498,14 +509,4 @@ int wl1271_plt_stop(struct wl1271 *wl);
#define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */ #define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */
#define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */
static inline bool wl1271_11a_enabled(void)
{
/* FIXME: this could be determined based on the NVS-INI file */
#ifdef WL1271_80211A_ENABLED
return true;
#else
return false;
#endif
}
#endif #endif
...@@ -86,40 +86,6 @@ int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth) ...@@ -86,40 +86,6 @@ int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth)
return ret; return ret;
} }
int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len)
{
struct acx_revision *rev;
int ret;
wl1271_debug(DEBUG_ACX, "acx fw rev");
rev = kzalloc(sizeof(*rev), GFP_KERNEL);
if (!rev) {
ret = -ENOMEM;
goto out;
}
ret = wl1271_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev));
if (ret < 0) {
wl1271_warning("ACX_FW_REV interrogate failed");
goto out;
}
/* be careful with the buffer sizes */
strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version)));
/*
* if the firmware version string is exactly
* sizeof(rev->fw_version) long or fw_len is less than
* sizeof(rev->fw_version) it won't be null terminated
*/
buf[min(len, sizeof(rev->fw_version)) - 1] = '\0';
out:
kfree(rev);
return ret;
}
int wl1271_acx_tx_power(struct wl1271 *wl, int power) int wl1271_acx_tx_power(struct wl1271 *wl, int power)
{ {
struct acx_current_tx_power *acx; struct acx_current_tx_power *acx;
......
...@@ -100,35 +100,6 @@ struct acx_error_counter { ...@@ -100,35 +100,6 @@ struct acx_error_counter {
__le32 seq_num_miss; __le32 seq_num_miss;
} __packed; } __packed;
struct acx_revision {
struct acx_header header;
/*
* The WiLink firmware version, an ASCII string x.x.x.x,
* that uniquely identifies the current firmware.
* The left most digit is incremented each time a
* significant change is made to the firmware, such as
* code redesign or new platform support.
* The second digit is incremented when major enhancements
* are added or major fixes are made.
* The third digit is incremented for each GA release.
* The fourth digit is incremented for each build.
* The first two digits identify a firmware release version,
* in other words, a unique set of features.
* The first three digits identify a GA release.
*/
char fw_version[20];
/*
* This 4 byte field specifies the WiLink hardware version.
* bits 0 - 15: Reserved.
* bits 16 - 23: Version ID - The WiLink version ID
* (1 = first spin, 2 = second spin, and so on).
* bits 24 - 31: Chip ID - The WiLink chip ID.
*/
__le32 hw_version;
} __packed;
enum wl1271_psm_mode { enum wl1271_psm_mode {
/* Active mode */ /* Active mode */
WL1271_PSM_CAM = 0, WL1271_PSM_CAM = 0,
...@@ -1060,7 +1031,6 @@ enum { ...@@ -1060,7 +1031,6 @@ enum {
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_SMART_REFLEX_DEBUG = 0x005A,
ACX_SET_DCO_ITRIM_PARAMS = 0x0061, ACX_SET_DCO_ITRIM_PARAMS = 0x0061,
DOT11_RX_MSDU_LIFE_TIME = 0x1004, DOT11_RX_MSDU_LIFE_TIME = 0x1004,
DOT11_CUR_TX_PWR = 0x100D, DOT11_CUR_TX_PWR = 0x100D,
...@@ -1077,7 +1047,6 @@ enum { ...@@ -1077,7 +1047,6 @@ enum {
int wl1271_acx_wake_up_conditions(struct wl1271 *wl); int wl1271_acx_wake_up_conditions(struct wl1271 *wl);
int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth); int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth);
int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len);
int wl1271_acx_tx_power(struct wl1271 *wl, int power); int wl1271_acx_tx_power(struct wl1271 *wl, int power);
int wl1271_acx_feature_cfg(struct wl1271 *wl); int wl1271_acx_feature_cfg(struct wl1271 *wl);
int wl1271_acx_mem_map(struct wl1271 *wl, int wl1271_acx_mem_map(struct wl1271 *wl,
......
...@@ -225,6 +225,28 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -225,6 +225,28 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
if (wl->nvs == NULL) if (wl->nvs == NULL)
return -ENODEV; return -ENODEV;
/*
* FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
* configurations) can be removed when those NVS files stop floating
* around.
*/
if (wl->nvs_len == sizeof(struct wl1271_nvs_file) ||
wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) {
if (wl->nvs->general_params.dual_mode_select)
wl->enable_11a = true;
}
if (wl->nvs_len != sizeof(struct wl1271_nvs_file) &&
(wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
wl->enable_11a)) {
wl1271_error("nvs size is not as expected: %zu != %zu",
wl->nvs_len, sizeof(struct wl1271_nvs_file));
kfree(wl->nvs);
wl->nvs = NULL;
wl->nvs_len = 0;
return -EILSEQ;
}
/* only the first part of the NVS needs to be uploaded */ /* only the first part of the NVS needs to be uploaded */
nvs_len = sizeof(wl->nvs->nvs); nvs_len = sizeof(wl->nvs->nvs);
nvs_ptr = (u8 *)wl->nvs->nvs; nvs_ptr = (u8 *)wl->nvs->nvs;
...@@ -251,8 +273,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -251,8 +273,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
burst_len = nvs_ptr[0]; burst_len = nvs_ptr[0];
dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
/* FIXME: Due to our new wl1271_translate_reg_addr function, /*
we need to add the REGISTER_BASE to the destination */ * Due to our new wl1271_translate_reg_addr function,
* we need to add the REGISTER_BASE to the destination
*/
dest_addr += REGISTERS_BASE; dest_addr += REGISTERS_BASE;
/* We move our pointer to the data */ /* We move our pointer to the data */
...@@ -280,8 +304,6 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -280,8 +304,6 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4); ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4);
nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs; nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs;
/* FIXME: The driver sets the partition here, but this is not needed,
since it sets to the same one as currently in use */
/* Now we must set the partition correctly */ /* Now we must set the partition correctly */
wl1271_set_partition(wl, &part_table[PART_WORK]); wl1271_set_partition(wl, &part_table[PART_WORK]);
...@@ -291,9 +313,6 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -291,9 +313,6 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
return -ENOMEM; return -ENOMEM;
/* And finally we upload the NVS tables */ /* And finally we upload the NVS tables */
/* FIXME: In wl1271, we upload everything at once.
No endianness handling needed here?! The ref driver doesn't do
anything about it at this point */
wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false); wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
kfree(nvs_aligned); kfree(nvs_aligned);
...@@ -491,10 +510,7 @@ int wl1271_boot(struct wl1271 *wl) ...@@ -491,10 +510,7 @@ int wl1271_boot(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be pause &= ~(WU_COUNTER_PAUSE_VAL);
* WU_COUNTER_PAUSE_VAL instead of
* 0x3ff (magic number ). How does
* this work?! */
pause |= WU_COUNTER_PAUSE_VAL; pause |= WU_COUNTER_PAUSE_VAL;
wl1271_write32(wl, WU_COUNTER_PAUSE, pause); wl1271_write32(wl, WU_COUNTER_PAUSE, pause);
...@@ -548,7 +564,6 @@ int wl1271_boot(struct wl1271 *wl) ...@@ -548,7 +564,6 @@ int wl1271_boot(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
goto out; goto out;
/* FIXME: Need to check whether this is really what we want */
wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_ALL_EVENTS_VECTOR); WL1271_ACX_ALL_EVENTS_VECTOR);
......
...@@ -94,6 +94,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, ...@@ -94,6 +94,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
status = le16_to_cpu(cmd->status); status = le16_to_cpu(cmd->status);
if (status != CMD_STATUS_SUCCESS) { if (status != CMD_STATUS_SUCCESS) {
wl1271_error("command execute failure %d", status); wl1271_error("command execute failure %d", status);
ieee80211_queue_work(wl->hw, &wl->recovery_work);
ret = -EIO; ret = -EIO;
} }
...@@ -170,6 +171,39 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) ...@@ -170,6 +171,39 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
return ret; return ret;
} }
int wl1271_cmd_ext_radio_parms(struct wl1271 *wl)
{
struct wl1271_ext_radio_parms_cmd *ext_radio_parms;
struct conf_rf_settings *rf = &wl->conf.rf;
int ret;
if (!wl->nvs)
return -ENODEV;
ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL);
if (!ext_radio_parms)
return -ENOMEM;
ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM;
memcpy(ext_radio_parms->tx_per_channel_power_compensation_2,
rf->tx_per_channel_power_compensation_2,
CONF_TX_PWR_COMPENSATION_LEN_2);
memcpy(ext_radio_parms->tx_per_channel_power_compensation_5,
rf->tx_per_channel_power_compensation_5,
CONF_TX_PWR_COMPENSATION_LEN_5);
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ",
ext_radio_parms, sizeof(*ext_radio_parms));
ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0);
if (ret < 0)
wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed");
kfree(ext_radio_parms);
return ret;
}
/* /*
* 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)
...@@ -182,8 +216,10 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) ...@@ -182,8 +216,10 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
do { do {
if (time_after(jiffies, timeout)) if (time_after(jiffies, timeout)) {
ieee80211_queue_work(wl->hw, &wl->recovery_work);
return -ETIMEDOUT; return -ETIMEDOUT;
}
msleep(1); msleep(1);
...@@ -390,18 +426,11 @@ int wl1271_cmd_data_path(struct wl1271 *wl, bool enable) ...@@ -390,18 +426,11 @@ int wl1271_cmd_data_path(struct wl1271 *wl, bool enable)
return ret; return ret;
} }
int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send) int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, u32 rates, bool send)
{ {
struct wl1271_cmd_ps_params *ps_params = NULL; struct wl1271_cmd_ps_params *ps_params = NULL;
int ret = 0; int ret = 0;
/* FIXME: this should be in ps.c */
ret = wl1271_acx_wake_up_conditions(wl);
if (ret < 0) {
wl1271_error("couldn't set wake up conditions");
goto out;
}
wl1271_debug(DEBUG_CMD, "cmd set ps mode"); wl1271_debug(DEBUG_CMD, "cmd set ps mode");
ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
...@@ -412,9 +441,9 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send) ...@@ -412,9 +441,9 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send)
ps_params->ps_mode = ps_mode; ps_params->ps_mode = ps_mode;
ps_params->send_null_data = send; ps_params->send_null_data = send;
ps_params->retries = 5; ps_params->retries = wl->conf.conn.psm_entry_nullfunc_retries;
ps_params->hang_over_period = 1; ps_params->hang_over_period = wl->conf.conn.psm_entry_hangover_period;
ps_params->null_data_rate = cpu_to_le32(wl->basic_rate_set); ps_params->null_data_rate = cpu_to_le32(rates);
ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
sizeof(*ps_params), 0); sizeof(*ps_params), 0);
...@@ -428,41 +457,6 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send) ...@@ -428,41 +457,6 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send)
return ret; return ret;
} }
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
size_t len)
{
struct cmd_read_write_memory *cmd;
int ret = 0;
wl1271_debug(DEBUG_CMD, "cmd read memory");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
WARN_ON(len > MAX_READ_SIZE);
len = min_t(size_t, len, MAX_READ_SIZE);
cmd->addr = cpu_to_le32(addr);
cmd->size = cpu_to_le32(len);
ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd),
sizeof(*cmd));
if (ret < 0) {
wl1271_error("read memory command failed: %d", ret);
goto out;
}
/* the read command got in */
memcpy(answer, cmd->value, len);
out:
kfree(cmd);
return ret;
}
int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
void *buf, size_t buf_len, int index, u32 rates) void *buf, size_t buf_len, int index, u32 rates)
{ {
...@@ -523,7 +517,7 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl) ...@@ -523,7 +517,7 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl)
} }
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0, ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0,
WL1271_RATE_AUTOMATIC); wl->basic_rate);
out: out:
dev_kfree_skb(skb); dev_kfree_skb(skb);
...@@ -546,7 +540,7 @@ int wl1271_cmd_build_klv_null_data(struct wl1271 *wl) ...@@ -546,7 +540,7 @@ int wl1271_cmd_build_klv_null_data(struct wl1271 *wl)
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV,
skb->data, skb->len, skb->data, skb->len,
CMD_TEMPL_KLV_IDX_NULL_DATA, CMD_TEMPL_KLV_IDX_NULL_DATA,
WL1271_RATE_AUTOMATIC); wl->basic_rate);
out: out:
dev_kfree_skb(skb); dev_kfree_skb(skb);
...@@ -623,7 +617,7 @@ int wl1271_build_qos_null_data(struct wl1271 *wl) ...@@ -623,7 +617,7 @@ int wl1271_build_qos_null_data(struct wl1271 *wl)
return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template, return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template,
sizeof(template), 0, sizeof(template), 0,
WL1271_RATE_AUTOMATIC); wl->basic_rate);
} }
int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
...@@ -746,3 +740,31 @@ int wl1271_cmd_disconnect(struct wl1271 *wl) ...@@ -746,3 +740,31 @@ int wl1271_cmd_disconnect(struct wl1271 *wl)
out: out:
return ret; return ret;
} }
int wl1271_cmd_set_sta_state(struct wl1271 *wl)
{
struct wl1271_cmd_set_sta_state *cmd;
int ret = 0;
wl1271_debug(DEBUG_CMD, "cmd set sta state");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
cmd->state = WL1271_CMD_STA_STATE_CONNECTED;
ret = wl1271_cmd_send(wl, CMD_SET_STA_STATE, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to send set STA state command");
goto out_free;
}
out_free:
kfree(cmd);
out:
return ret;
}
...@@ -33,12 +33,13 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, ...@@ -33,12 +33,13 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
size_t res_len); size_t res_len);
int wl1271_cmd_general_parms(struct wl1271 *wl); int wl1271_cmd_general_parms(struct wl1271 *wl);
int wl1271_cmd_radio_parms(struct wl1271 *wl); int wl1271_cmd_radio_parms(struct wl1271 *wl);
int wl1271_cmd_ext_radio_parms(struct wl1271 *wl);
int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type); int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type);
int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send); int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, u32 rates, bool send);
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
size_t len); size_t len);
int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
...@@ -55,6 +56,7 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, ...@@ -55,6 +56,7 @@ int wl1271_cmd_set_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);
int wl1271_cmd_disconnect(struct wl1271 *wl); int wl1271_cmd_disconnect(struct wl1271 *wl);
int wl1271_cmd_set_sta_state(struct wl1271 *wl);
enum wl1271_commands { enum wl1271_commands {
CMD_INTERROGATE = 1, /*use this to read information elements*/ CMD_INTERROGATE = 1, /*use this to read information elements*/
...@@ -160,41 +162,6 @@ enum { ...@@ -160,41 +162,6 @@ enum {
MAX_COMMAND_STATUS = 0xff MAX_COMMAND_STATUS = 0xff
}; };
/*
* CMD_READ_MEMORY
*
* The host issues this command to read the WiLink device memory/registers.
*
* Note: The Base Band address has special handling (16 bits registers and
* addresses). For more information, see the hardware specification.
*/
/*
* CMD_WRITE_MEMORY
*
* The host issues this command to write the WiLink device memory/registers.
*
* The Base Band address has special handling (16 bits registers and
* addresses). For more information, see the hardware specification.
*/
#define MAX_READ_SIZE 256
struct cmd_read_write_memory {
struct wl1271_cmd_header header;
/* The address of the memory to read from or write to.*/
__le32 addr;
/* The amount of data in bytes to read from or write to the WiLink
* device.*/
__le32 size;
/* The actual value read from or written to the Wilink. The source
of this field is the Host in WRITE command or the Wilink in READ
command. */
u8 value[MAX_READ_SIZE];
} __packed;
#define CMDMBOX_HEADER_LEN 4 #define CMDMBOX_HEADER_LEN 4
#define CMDMBOX_INFO_ELEM_HEADER_LEN 4 #define CMDMBOX_INFO_ELEM_HEADER_LEN 4
...@@ -313,7 +280,7 @@ enum wl1271_cmd_key_type { ...@@ -313,7 +280,7 @@ enum wl1271_cmd_key_type {
KEY_WEP = 1, KEY_WEP = 1,
KEY_TKIP = 2, KEY_TKIP = 2,
KEY_AES = 3, KEY_AES = 3,
KEY_GEM = 4 KEY_GEM = 4,
}; };
/* FIXME: Add description for key-types */ /* FIXME: Add description for key-types */
...@@ -365,6 +332,7 @@ enum wl1271_channel_tune_bands { ...@@ -365,6 +332,7 @@ enum wl1271_channel_tune_bands {
#define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d #define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d
#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 #define TEST_CMD_INI_FILE_RADIO_PARAM 0x19
#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E #define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E
#define TEST_CMD_INI_FILE_RF_EXTENDED_PARAM 0x26
struct wl1271_general_parms_cmd { struct wl1271_general_parms_cmd {
struct wl1271_cmd_header header; struct wl1271_cmd_header header;
...@@ -397,6 +365,16 @@ struct wl1271_radio_parms_cmd { ...@@ -397,6 +365,16 @@ struct wl1271_radio_parms_cmd {
u8 padding3[2]; u8 padding3[2];
} __packed; } __packed;
struct wl1271_ext_radio_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2];
u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5];
u8 padding[3];
} __packed;
struct wl1271_cmd_cal_channel_tune { struct wl1271_cmd_cal_channel_tune {
struct wl1271_cmd_header header; struct wl1271_cmd_header header;
...@@ -469,4 +447,13 @@ struct wl1271_cmd_disconnect { ...@@ -469,4 +447,13 @@ struct wl1271_cmd_disconnect {
u8 padding; u8 padding;
} __packed; } __packed;
#define WL1271_CMD_STA_STATE_CONNECTED 1
struct wl1271_cmd_set_sta_state {
struct wl1271_cmd_header header;
u8 state;
u8 padding[3];
} __packed;
#endif /* __WL1271_CMD_H__ */ #endif /* __WL1271_CMD_H__ */
...@@ -595,7 +595,7 @@ struct conf_tx_ac_category { ...@@ -595,7 +595,7 @@ struct conf_tx_ac_category {
u16 tx_op_limit; u16 tx_op_limit;
}; };
#define CONF_TX_MAX_TID_COUNT 7 #define CONF_TX_MAX_TID_COUNT 8
enum { enum {
CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/ CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/
...@@ -911,6 +911,22 @@ struct conf_conn_settings { ...@@ -911,6 +911,22 @@ struct conf_conn_settings {
*/ */
u8 psm_entry_retries; u8 psm_entry_retries;
/*
* Specifies the maximum number of times to try transmit the PSM entry
* null-func frame for each PSM entry attempt
*
* Range 0 - 255
*/
u8 psm_entry_nullfunc_retries;
/*
* Specifies the time to linger in active mode after successfully
* transmitting the PSM entry null-func frame.
*
* Range 0 - 255 TU's
*/
u8 psm_entry_hangover_period;
/* /*
* *
* Specifies the interval of the connection keep-alive null-func * Specifies the interval of the connection keep-alive null-func
...@@ -1016,6 +1032,64 @@ struct conf_roam_trigger_settings { ...@@ -1016,6 +1032,64 @@ struct conf_roam_trigger_settings {
u8 avg_weight_snr_data; u8 avg_weight_snr_data;
}; };
struct conf_scan_settings {
/*
* The minimum time to wait on each channel for active scans
*
* Range: 0 - 65536 tu
*/
u16 min_dwell_time_active;
/*
* The maximum time to wait on each channel for active scans
*
* Range: 0 - 65536 tu
*/
u16 max_dwell_time_active;
/*
* The maximum time to wait on each channel for passive scans
*
* Range: 0 - 65536 tu
*/
u16 min_dwell_time_passive;
/*
* The maximum time to wait on each channel for passive scans
*
* Range: 0 - 65536 tu
*/
u16 max_dwell_time_passive;
/*
* Number of probe requests to transmit on each active scan channel
*
* Range: u8
*/
u16 num_probe_reqs;
};
/* these are number of channels on the band divided by two, rounded up */
#define CONF_TX_PWR_COMPENSATION_LEN_2 7
#define CONF_TX_PWR_COMPENSATION_LEN_5 18
struct conf_rf_settings {
/*
* Per channel power compensation for 2.4GHz
*
* Range: s8
*/
u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2];
/*
* Per channel power compensation for 5GHz
*
* Range: s8
*/
u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5];
};
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;
...@@ -1024,6 +1098,8 @@ struct conf_drv_settings { ...@@ -1024,6 +1098,8 @@ struct conf_drv_settings {
struct conf_itrim_settings itrim; struct conf_itrim_settings itrim;
struct conf_pm_config_settings pm_config; struct conf_pm_config_settings pm_config;
struct conf_roam_trigger_settings roam_trigger; struct conf_roam_trigger_settings roam_trigger;
struct conf_scan_settings scan;
struct conf_rf_settings rf;
}; };
#endif #endif
...@@ -41,6 +41,9 @@ void wl1271_pspoll_work(struct work_struct *work) ...@@ -41,6 +41,9 @@ void wl1271_pspoll_work(struct work_struct *work)
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;
if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags)) if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags))
goto out; goto out;
...@@ -52,7 +55,7 @@ void wl1271_pspoll_work(struct work_struct *work) ...@@ -52,7 +55,7 @@ void wl1271_pspoll_work(struct work_struct *work)
* delivery failure occurred, and no-one changed state since, so * delivery failure occurred, and no-one changed state since, so
* we should go back to powersave. * we should go back to powersave.
*/ */
wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, true); wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true);
out: out:
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
...@@ -70,7 +73,8 @@ static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl) ...@@ -70,7 +73,8 @@ static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl)
/* force active mode receive data from the AP */ /* force active mode receive data from the AP */
if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, true); ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
wl->basic_rate, true);
if (ret < 0) if (ret < 0)
return; return;
set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags); set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
...@@ -91,6 +95,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl, ...@@ -91,6 +95,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
bool *beacon_loss) bool *beacon_loss)
{ {
int ret = 0; int ret = 0;
u32 total_retries = wl->conf.conn.psm_entry_retries;
wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status); wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status);
...@@ -104,10 +109,10 @@ static int wl1271_event_ps_report(struct wl1271 *wl, ...@@ -104,10 +109,10 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
break; break;
} }
if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) { if (wl->psm_entry_retry < total_retries) {
wl->psm_entry_retry++; wl->psm_entry_retry++;
ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
true); wl->basic_rate, true);
} else { } else {
wl1271_info("No ack to nullfunc from AP."); wl1271_info("No ack to nullfunc from AP.");
wl->psm_entry_retry = 0; wl->psm_entry_retry = 0;
...@@ -143,7 +148,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl, ...@@ -143,7 +148,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
/* make sure the firmware goes to active mode - the frame to /* make sure the firmware goes to active mode - the frame to
be sent next will indicate to the AP, that we are active. */ be sent next will indicate to the AP, that we are active. */
ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
false); wl->basic_rate, false);
break; break;
case EVENT_EXIT_POWER_SAVE_SUCCESS: case EVENT_EXIT_POWER_SAVE_SUCCESS:
default: default:
......
...@@ -53,6 +53,7 @@ static int wl1271_init_hwenc_config(struct wl1271 *wl) ...@@ -53,6 +53,7 @@ static int wl1271_init_hwenc_config(struct wl1271 *wl)
int wl1271_init_templates_config(struct wl1271 *wl) int wl1271_init_templates_config(struct wl1271 *wl)
{ {
int ret, i; int ret, i;
size_t size;
/* send empty templates for fw memory reservation */ /* send empty templates for fw memory reservation */
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
...@@ -61,14 +62,12 @@ int wl1271_init_templates_config(struct wl1271 *wl) ...@@ -61,14 +62,12 @@ int wl1271_init_templates_config(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
return ret; return ret;
if (wl1271_11a_enabled()) { size = sizeof(struct wl12xx_probe_req_template);
size_t size = sizeof(struct wl12xx_probe_req_template);
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
NULL, size, 0, NULL, size, 0,
WL1271_RATE_AUTOMATIC); WL1271_RATE_AUTOMATIC);
if (ret < 0) if (ret < 0)
return ret; return ret;
}
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
sizeof(struct wl12xx_null_data_template), sizeof(struct wl12xx_null_data_template),
...@@ -223,6 +222,10 @@ int wl1271_hw_init(struct wl1271 *wl) ...@@ -223,6 +222,10 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = wl1271_cmd_ext_radio_parms(wl);
if (ret < 0)
return ret;
/* Template settings */ /* Template settings */
ret = wl1271_init_templates_config(wl); ret = wl1271_init_templates_config(wl);
if (ret < 0) if (ret < 0)
...@@ -291,8 +294,16 @@ int wl1271_hw_init(struct wl1271 *wl) ...@@ -291,8 +294,16 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
goto out_free_memmap; goto out_free_memmap;
/* Default TID configuration */ /* Default TID/AC configuration */
BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
conf_ac = &wl->conf.tx.ac_conf[i];
ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
conf_ac->cw_max, conf_ac->aifsn,
conf_ac->tx_op_limit);
if (ret < 0)
goto out_free_memmap;
conf_tid = &wl->conf.tx.tid_conf[i]; conf_tid = &wl->conf.tx.tid_conf[i];
ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id, ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
conf_tid->channel_type, conf_tid->channel_type,
...@@ -305,16 +316,6 @@ int wl1271_hw_init(struct wl1271 *wl) ...@@ -305,16 +316,6 @@ int wl1271_hw_init(struct wl1271 *wl)
goto out_free_memmap; goto out_free_memmap;
} }
/* Default AC configuration */
for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
conf_ac = &wl->conf.tx.ac_conf[i];
ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
conf_ac->cw_max, conf_ac->aifsn,
conf_ac->tx_op_limit);
if (ret < 0)
goto out_free_memmap;
}
/* Configure TX rate classes */ /* Configure TX rate classes */
ret = wl1271_acx_rate_policies(wl); ret = wl1271_acx_rate_policies(wl);
if (ret < 0) if (ret < 0)
......
...@@ -124,28 +124,28 @@ static struct conf_drv_settings default_conf = { ...@@ -124,28 +124,28 @@ static struct conf_drv_settings default_conf = {
}, },
.ac_conf_count = 4, .ac_conf_count = 4,
.ac_conf = { .ac_conf = {
[0] = { [CONF_TX_AC_BE] = {
.ac = CONF_TX_AC_BE, .ac = CONF_TX_AC_BE,
.cw_min = 15, .cw_min = 15,
.cw_max = 63, .cw_max = 63,
.aifsn = 3, .aifsn = 3,
.tx_op_limit = 0, .tx_op_limit = 0,
}, },
[1] = { [CONF_TX_AC_BK] = {
.ac = CONF_TX_AC_BK, .ac = CONF_TX_AC_BK,
.cw_min = 15, .cw_min = 15,
.cw_max = 63, .cw_max = 63,
.aifsn = 7, .aifsn = 7,
.tx_op_limit = 0, .tx_op_limit = 0,
}, },
[2] = { [CONF_TX_AC_VI] = {
.ac = CONF_TX_AC_VI, .ac = CONF_TX_AC_VI,
.cw_min = 15, .cw_min = 15,
.cw_max = 63, .cw_max = 63,
.aifsn = CONF_TX_AIFS_PIFS, .aifsn = CONF_TX_AIFS_PIFS,
.tx_op_limit = 3008, .tx_op_limit = 3008,
}, },
[3] = { [CONF_TX_AC_VO] = {
.ac = CONF_TX_AC_VO, .ac = CONF_TX_AC_VO,
.cw_min = 15, .cw_min = 15,
.cw_max = 63, .cw_max = 63,
...@@ -153,64 +153,40 @@ static struct conf_drv_settings default_conf = { ...@@ -153,64 +153,40 @@ static struct conf_drv_settings default_conf = {
.tx_op_limit = 1504, .tx_op_limit = 1504,
}, },
}, },
.tid_conf_count = 7, .tid_conf_count = 4,
.tid_conf = { .tid_conf = {
[0] = { [CONF_TX_AC_BE] = {
.queue_id = 0, .queue_id = CONF_TX_AC_BE,
.channel_type = CONF_CHANNEL_TYPE_DCF, .channel_type = CONF_CHANNEL_TYPE_EDCF,
.tsid = CONF_TX_AC_BE,
.ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0},
},
[1] = {
.queue_id = 1,
.channel_type = CONF_CHANNEL_TYPE_DCF,
.tsid = CONF_TX_AC_BE, .tsid = CONF_TX_AC_BE,
.ps_scheme = CONF_PS_SCHEME_LEGACY, .ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY, .ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0}, .apsd_conf = {0, 0},
}, },
[2] = { [CONF_TX_AC_BK] = {
.queue_id = 2, .queue_id = CONF_TX_AC_BK,
.channel_type = CONF_CHANNEL_TYPE_DCF, .channel_type = CONF_CHANNEL_TYPE_EDCF,
.tsid = CONF_TX_AC_BE, .tsid = CONF_TX_AC_BK,
.ps_scheme = CONF_PS_SCHEME_LEGACY, .ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY, .ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0}, .apsd_conf = {0, 0},
}, },
[3] = { [CONF_TX_AC_VI] = {
.queue_id = 3, .queue_id = CONF_TX_AC_VI,
.channel_type = CONF_CHANNEL_TYPE_DCF, .channel_type = CONF_CHANNEL_TYPE_EDCF,
.tsid = CONF_TX_AC_BE, .tsid = CONF_TX_AC_VI,
.ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0},
},
[4] = {
.queue_id = 4,
.channel_type = CONF_CHANNEL_TYPE_DCF,
.tsid = CONF_TX_AC_BE,
.ps_scheme = CONF_PS_SCHEME_LEGACY, .ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY, .ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0}, .apsd_conf = {0, 0},
}, },
[5] = { [CONF_TX_AC_VO] = {
.queue_id = 5, .queue_id = CONF_TX_AC_VO,
.channel_type = CONF_CHANNEL_TYPE_DCF, .channel_type = CONF_CHANNEL_TYPE_EDCF,
.tsid = CONF_TX_AC_BE, .tsid = CONF_TX_AC_VO,
.ps_scheme = CONF_PS_SCHEME_LEGACY, .ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY, .ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0}, .apsd_conf = {0, 0},
}, },
[6] = {
.queue_id = 6,
.channel_type = CONF_CHANNEL_TYPE_DCF,
.tsid = CONF_TX_AC_BE,
.ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0},
}
}, },
.frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
.tx_compl_timeout = 700, .tx_compl_timeout = 700,
...@@ -238,7 +214,9 @@ static struct conf_drv_settings default_conf = { ...@@ -238,7 +214,9 @@ static struct conf_drv_settings default_conf = {
.ps_poll_recovery_period = 700, .ps_poll_recovery_period = 700,
.bet_enable = CONF_BET_MODE_ENABLE, .bet_enable = CONF_BET_MODE_ENABLE,
.bet_max_consecutive = 10, .bet_max_consecutive = 10,
.psm_entry_retries = 3, .psm_entry_retries = 5,
.psm_entry_nullfunc_retries = 3,
.psm_entry_hangover_period = 1,
.keep_alive_interval = 55000, .keep_alive_interval = 55000,
.max_listen_interval = 20, .max_listen_interval = 20,
}, },
...@@ -251,15 +229,34 @@ static struct conf_drv_settings default_conf = { ...@@ -251,15 +229,34 @@ static struct conf_drv_settings default_conf = {
.host_fast_wakeup_support = false .host_fast_wakeup_support = false
}, },
.roam_trigger = { .roam_trigger = {
/* FIXME: due to firmware bug, must use value 1 for now */
.trigger_pacing = 1, .trigger_pacing = 1,
.avg_weight_rssi_beacon = 20, .avg_weight_rssi_beacon = 20,
.avg_weight_rssi_data = 10, .avg_weight_rssi_data = 10,
.avg_weight_snr_beacon = 20, .avg_weight_snr_beacon = 20,
.avg_weight_snr_data = 10 .avg_weight_snr_data = 10
} },
.scan = {
.min_dwell_time_active = 7500,
.max_dwell_time_active = 30000,
.min_dwell_time_passive = 30000,
.max_dwell_time_passive = 60000,
.num_probe_reqs = 2,
},
.rf = {
.tx_per_channel_power_compensation_2 = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
.tx_per_channel_power_compensation_5 = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
},
}; };
static void __wl1271_op_remove_interface(struct wl1271 *wl);
static void wl1271_device_release(struct device *dev) static void wl1271_device_release(struct device *dev)
{ {
...@@ -277,6 +274,67 @@ static struct platform_device wl1271_device = { ...@@ -277,6 +274,67 @@ static struct platform_device wl1271_device = {
static LIST_HEAD(wl_list); static LIST_HEAD(wl_list);
static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
void *arg)
{
struct net_device *dev = arg;
struct wireless_dev *wdev;
struct wiphy *wiphy;
struct ieee80211_hw *hw;
struct wl1271 *wl;
struct wl1271 *wl_temp;
int ret = 0;
/* Check that this notification is for us. */
if (what != NETDEV_CHANGE)
return NOTIFY_DONE;
wdev = dev->ieee80211_ptr;
if (wdev == NULL)
return NOTIFY_DONE;
wiphy = wdev->wiphy;
if (wiphy == NULL)
return NOTIFY_DONE;
hw = wiphy_priv(wiphy);
if (hw == NULL)
return NOTIFY_DONE;
wl_temp = hw->priv;
list_for_each_entry(wl, &wl_list, list) {
if (wl == wl_temp)
break;
}
if (wl != wl_temp)
return NOTIFY_DONE;
mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF)
goto out;
if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
goto out;
ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0)
goto out;
if ((dev->operstate == IF_OPER_UP) &&
!test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
wl1271_cmd_set_sta_state(wl);
wl1271_info("Association completed.");
}
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
return NOTIFY_OK;
}
static void wl1271_conf_init(struct wl1271 *wl) static void wl1271_conf_init(struct wl1271 *wl)
{ {
...@@ -309,6 +367,10 @@ static int wl1271_plt_init(struct wl1271 *wl) ...@@ -309,6 +367,10 @@ static int wl1271_plt_init(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = wl1271_cmd_ext_radio_parms(wl);
if (ret < 0)
return ret;
ret = wl1271_init_templates_config(wl); ret = wl1271_init_templates_config(wl);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -346,8 +408,16 @@ static int wl1271_plt_init(struct wl1271 *wl) ...@@ -346,8 +408,16 @@ static int wl1271_plt_init(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
goto out_free_memmap; goto out_free_memmap;
/* Default TID configuration */ /* Default TID/AC configuration */
BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
conf_ac = &wl->conf.tx.ac_conf[i];
ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
conf_ac->cw_max, conf_ac->aifsn,
conf_ac->tx_op_limit);
if (ret < 0)
goto out_free_memmap;
conf_tid = &wl->conf.tx.tid_conf[i]; conf_tid = &wl->conf.tx.tid_conf[i];
ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id, ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
conf_tid->channel_type, conf_tid->channel_type,
...@@ -360,16 +430,6 @@ static int wl1271_plt_init(struct wl1271 *wl) ...@@ -360,16 +430,6 @@ static int wl1271_plt_init(struct wl1271 *wl)
goto out_free_memmap; goto out_free_memmap;
} }
/* Default AC configuration */
for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
conf_ac = &wl->conf.tx.ac_conf[i];
ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
conf_ac->cw_max, conf_ac->aifsn,
conf_ac->tx_op_limit);
if (ret < 0)
goto out_free_memmap;
}
/* Enable data path */ /* Enable data path */
ret = wl1271_cmd_data_path(wl, 1); ret = wl1271_cmd_data_path(wl, 1);
if (ret < 0) if (ret < 0)
...@@ -562,20 +622,6 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) ...@@ -562,20 +622,6 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
return ret; return ret;
} }
/*
* FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
* configurations) can be removed when those NVS files stop floating
* around.
*/
if (fw->size != sizeof(struct wl1271_nvs_file) &&
(fw->size != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
wl1271_11a_enabled())) {
wl1271_error("nvs size is not as expected: %zu != %zu",
fw->size, sizeof(struct wl1271_nvs_file));
ret = -EILSEQ;
goto out;
}
wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
if (!wl->nvs) { if (!wl->nvs) {
...@@ -584,12 +630,37 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) ...@@ -584,12 +630,37 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
goto out; goto out;
} }
wl->nvs_len = fw->size;
out: out:
release_firmware(fw); release_firmware(fw);
return ret; return ret;
} }
static void wl1271_recovery_work(struct work_struct *work)
{
struct wl1271 *wl =
container_of(work, struct wl1271, recovery_work);
mutex_lock(&wl->mutex);
if (wl->state != WL1271_STATE_ON)
goto out;
wl1271_info("Hardware recovery in progress.");
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
ieee80211_connection_loss(wl->vif);
/* reboot the chipset */
__wl1271_op_remove_interface(wl);
ieee80211_restart_hw(wl->hw);
out:
mutex_unlock(&wl->mutex);
}
static void wl1271_fw_wakeup(struct wl1271 *wl) static void wl1271_fw_wakeup(struct wl1271 *wl)
{ {
u32 elp_reg; u32 elp_reg;
...@@ -610,8 +681,6 @@ static int wl1271_setup(struct wl1271 *wl) ...@@ -610,8 +681,6 @@ static int wl1271_setup(struct wl1271 *wl)
return -ENOMEM; return -ENOMEM;
} }
INIT_WORK(&wl->irq_work, wl1271_irq_work);
INIT_WORK(&wl->tx_work, wl1271_tx_work);
return 0; return 0;
} }
...@@ -768,10 +837,12 @@ int wl1271_plt_stop(struct wl1271 *wl) ...@@ -768,10 +837,12 @@ int wl1271_plt_stop(struct wl1271 *wl)
out: out:
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
cancel_work_sync(&wl->irq_work);
cancel_work_sync(&wl->recovery_work);
return ret; return ret;
} }
static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{ {
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
...@@ -814,6 +885,10 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -814,6 +885,10 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
static struct notifier_block wl1271_dev_notifier = {
.notifier_call = wl1271_dev_notify,
};
static int wl1271_op_start(struct ieee80211_hw *hw) static int wl1271_op_start(struct ieee80211_hw *hw)
{ {
wl1271_debug(DEBUG_MAC80211, "mac80211 start"); wl1271_debug(DEBUG_MAC80211, "mac80211 start");
...@@ -930,13 +1005,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, ...@@ -930,13 +1005,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
return ret; return ret;
} }
static void wl1271_op_remove_interface(struct ieee80211_hw *hw, static void __wl1271_op_remove_interface(struct wl1271 *wl)
struct ieee80211_vif *vif)
{ {
struct wl1271 *wl = hw->priv;
int i; int i;
mutex_lock(&wl->mutex);
wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
wl1271_info("down"); wl1271_info("down");
...@@ -950,10 +1022,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, ...@@ -950,10 +1022,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
ieee80211_enable_dyn_ps(wl->vif); ieee80211_enable_dyn_ps(wl->vif);
if (wl->scan.state != WL1271_SCAN_STATE_IDLE) { if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
ieee80211_scan_completed(wl->hw, true);
wl->scan.state = WL1271_SCAN_STATE_IDLE; wl->scan.state = WL1271_SCAN_STATE_IDLE;
kfree(wl->scan.scanned_ch); kfree(wl->scan.scanned_ch);
wl->scan.scanned_ch = NULL; wl->scan.scanned_ch = NULL;
ieee80211_scan_completed(wl->hw, true);
} }
wl->state = WL1271_STATE_OFF; wl->state = WL1271_STATE_OFF;
...@@ -962,9 +1034,11 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, ...@@ -962,9 +1034,11 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
cancel_delayed_work_sync(&wl->scan_complete_work);
cancel_work_sync(&wl->irq_work); cancel_work_sync(&wl->irq_work);
cancel_work_sync(&wl->tx_work); cancel_work_sync(&wl->tx_work);
cancel_delayed_work_sync(&wl->pspoll_work); cancel_delayed_work_sync(&wl->pspoll_work);
cancel_delayed_work_sync(&wl->elp_work);
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
...@@ -1006,8 +1080,19 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, ...@@ -1006,8 +1080,19 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
wl->tx_res_if = NULL; wl->tx_res_if = NULL;
kfree(wl->target_mem_map); kfree(wl->target_mem_map);
wl->target_mem_map = NULL; wl->target_mem_map = NULL;
}
static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct wl1271 *wl = hw->priv;
mutex_lock(&wl->mutex);
WARN_ON(wl->vif != vif);
__wl1271_op_remove_interface(wl);
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
cancel_work_sync(&wl->recovery_work);
} }
static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
...@@ -1289,7 +1374,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) ...@@ -1289,7 +1374,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
wl1271_debug(DEBUG_PSM, "psm enabled"); wl1271_debug(DEBUG_PSM, "psm enabled");
ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
true); wl->basic_rate, true);
} }
} else if (!(conf->flags & IEEE80211_CONF_PS) && } else if (!(conf->flags & IEEE80211_CONF_PS) &&
test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
...@@ -1299,7 +1384,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) ...@@ -1299,7 +1384,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
if (test_bit(WL1271_FLAG_PSM, &wl->flags)) if (test_bit(WL1271_FLAG_PSM, &wl->flags))
ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
true); wl->basic_rate, true);
} }
if (conf->power_level != wl->power_level) { if (conf->power_level != wl->power_level) {
...@@ -1476,6 +1561,11 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -1476,6 +1561,11 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
break; break;
case WL1271_CIPHER_SUITE_GEM:
key_type = KEY_GEM;
tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
break;
default: default:
wl1271_error("Unknown key algo 0x%x", key_conf->cipher); wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
...@@ -1559,9 +1649,6 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, ...@@ -1559,9 +1649,6 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
if (ret < 0) if (ret < 0)
goto out; goto out;
if (wl1271_11a_enabled())
ret = wl1271_scan(hw->priv, ssid, len, req);
else
ret = wl1271_scan(hw->priv, ssid, len, req); ret = wl1271_scan(hw->priv, ssid, len, req);
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
...@@ -1777,12 +1864,15 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -1777,12 +1864,15 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
!test_bit(WL1271_FLAG_PSM, &wl->flags)) { !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
mode = STATION_POWER_SAVE_MODE; mode = STATION_POWER_SAVE_MODE;
ret = wl1271_ps_set_mode(wl, mode, true); ret = wl1271_ps_set_mode(wl, mode,
wl->basic_rate,
true);
if (ret < 0) if (ret < 0)
goto out_sleep; goto out_sleep;
} }
} else { } else {
/* use defaults when not associated */ /* use defaults when not associated */
clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
wl->aid = 0; wl->aid = 0;
...@@ -1994,21 +2084,24 @@ static struct ieee80211_rate wl1271_rates[] = { ...@@ -1994,21 +2084,24 @@ static struct ieee80211_rate wl1271_rates[] = {
.hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
}; };
/* can't be const, mac80211 writes to this */ /*
* Can't be const, mac80211 writes to this. The order of the channels here
* is designed to improve scanning.
*/
static struct ieee80211_channel wl1271_channels[] = { static struct ieee80211_channel wl1271_channels[] = {
{ .hw_value = 1, .center_freq = 2412, .max_power = 25 }, { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
{ .hw_value = 2, .center_freq = 2417, .max_power = 25 },
{ .hw_value = 3, .center_freq = 2422, .max_power = 25 },
{ .hw_value = 4, .center_freq = 2427, .max_power = 25 },
{ .hw_value = 5, .center_freq = 2432, .max_power = 25 }, { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
{ .hw_value = 6, .center_freq = 2437, .max_power = 25 },
{ .hw_value = 7, .center_freq = 2442, .max_power = 25 },
{ .hw_value = 8, .center_freq = 2447, .max_power = 25 },
{ .hw_value = 9, .center_freq = 2452, .max_power = 25 }, { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
{ .hw_value = 10, .center_freq = 2457, .max_power = 25 },
{ .hw_value = 11, .center_freq = 2462, .max_power = 25 },
{ .hw_value = 12, .center_freq = 2467, .max_power = 25 },
{ .hw_value = 13, .center_freq = 2472, .max_power = 25 }, { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
{ .hw_value = 4, .center_freq = 2427, .max_power = 25 },
{ .hw_value = 8, .center_freq = 2447, .max_power = 25 },
{ .hw_value = 12, .center_freq = 2467, .max_power = 25 },
{ .hw_value = 3, .center_freq = 2422, .max_power = 25 },
{ .hw_value = 7, .center_freq = 2442, .max_power = 25 },
{ .hw_value = 11, .center_freq = 2462, .max_power = 25 },
{ .hw_value = 2, .center_freq = 2417, .max_power = 25 },
{ .hw_value = 6, .center_freq = 2437, .max_power = 25 },
{ .hw_value = 10, .center_freq = 2457, .max_power = 25 },
}; };
/* mapping to indexes for wl1271_rates */ /* mapping to indexes for wl1271_rates */
...@@ -2077,49 +2170,52 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = { ...@@ -2077,49 +2170,52 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = {
.hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
}; };
/* 5 GHz band channels for WL1273 */ /*
* 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
* The order of the channels here is designed to improve scanning.
*/
static struct ieee80211_channel wl1271_channels_5ghz[] = { static struct ieee80211_channel wl1271_channels_5ghz[] = {
{ .hw_value = 183, .center_freq = 4915}, { .hw_value = 183, .center_freq = 4915},
{ .hw_value = 184, .center_freq = 4920},
{ .hw_value = 185, .center_freq = 4925},
{ .hw_value = 187, .center_freq = 4935},
{ .hw_value = 188, .center_freq = 4940}, { .hw_value = 188, .center_freq = 4940},
{ .hw_value = 189, .center_freq = 4945},
{ .hw_value = 192, .center_freq = 4960},
{ .hw_value = 196, .center_freq = 4980},
{ .hw_value = 7, .center_freq = 5035},
{ .hw_value = 8, .center_freq = 5040}, { .hw_value = 8, .center_freq = 5040},
{ .hw_value = 9, .center_freq = 5045},
{ .hw_value = 11, .center_freq = 5055},
{ .hw_value = 12, .center_freq = 5060},
{ .hw_value = 16, .center_freq = 5080},
{ .hw_value = 34, .center_freq = 5170}, { .hw_value = 34, .center_freq = 5170},
{ .hw_value = 36, .center_freq = 5180},
{ .hw_value = 38, .center_freq = 5190},
{ .hw_value = 40, .center_freq = 5200},
{ .hw_value = 42, .center_freq = 5210},
{ .hw_value = 44, .center_freq = 5220}, { .hw_value = 44, .center_freq = 5220},
{ .hw_value = 46, .center_freq = 5230},
{ .hw_value = 48, .center_freq = 5240},
{ .hw_value = 52, .center_freq = 5260},
{ .hw_value = 56, .center_freq = 5280},
{ .hw_value = 60, .center_freq = 5300}, { .hw_value = 60, .center_freq = 5300},
{ .hw_value = 64, .center_freq = 5320},
{ .hw_value = 100, .center_freq = 5500},
{ .hw_value = 104, .center_freq = 5520},
{ .hw_value = 108, .center_freq = 5540},
{ .hw_value = 112, .center_freq = 5560}, { .hw_value = 112, .center_freq = 5560},
{ .hw_value = 116, .center_freq = 5580},
{ .hw_value = 120, .center_freq = 5600},
{ .hw_value = 124, .center_freq = 5620},
{ .hw_value = 128, .center_freq = 5640},
{ .hw_value = 132, .center_freq = 5660}, { .hw_value = 132, .center_freq = 5660},
{ .hw_value = 157, .center_freq = 5785},
{ .hw_value = 184, .center_freq = 4920},
{ .hw_value = 189, .center_freq = 4945},
{ .hw_value = 9, .center_freq = 5045},
{ .hw_value = 36, .center_freq = 5180},
{ .hw_value = 46, .center_freq = 5230},
{ .hw_value = 64, .center_freq = 5320},
{ .hw_value = 116, .center_freq = 5580},
{ .hw_value = 136, .center_freq = 5680}, { .hw_value = 136, .center_freq = 5680},
{ .hw_value = 192, .center_freq = 4960},
{ .hw_value = 11, .center_freq = 5055},
{ .hw_value = 38, .center_freq = 5190},
{ .hw_value = 48, .center_freq = 5240},
{ .hw_value = 100, .center_freq = 5500},
{ .hw_value = 120, .center_freq = 5600},
{ .hw_value = 140, .center_freq = 5700}, { .hw_value = 140, .center_freq = 5700},
{ .hw_value = 185, .center_freq = 4925},
{ .hw_value = 196, .center_freq = 4980},
{ .hw_value = 12, .center_freq = 5060},
{ .hw_value = 40, .center_freq = 5200},
{ .hw_value = 52, .center_freq = 5260},
{ .hw_value = 104, .center_freq = 5520},
{ .hw_value = 124, .center_freq = 5620},
{ .hw_value = 149, .center_freq = 5745}, { .hw_value = 149, .center_freq = 5745},
{ .hw_value = 153, .center_freq = 5765},
{ .hw_value = 157, .center_freq = 5785},
{ .hw_value = 161, .center_freq = 5805}, { .hw_value = 161, .center_freq = 5805},
{ .hw_value = 187, .center_freq = 4935},
{ .hw_value = 7, .center_freq = 5035},
{ .hw_value = 16, .center_freq = 5080},
{ .hw_value = 42, .center_freq = 5210},
{ .hw_value = 56, .center_freq = 5280},
{ .hw_value = 108, .center_freq = 5540},
{ .hw_value = 128, .center_freq = 5640},
{ .hw_value = 153, .center_freq = 5765},
{ .hw_value = 165, .center_freq = 5825}, { .hw_value = 165, .center_freq = 5825},
}; };
...@@ -2212,8 +2308,7 @@ static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev, ...@@ -2212,8 +2308,7 @@ static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
struct wl1271 *wl = dev_get_drvdata(dev); struct wl1271 *wl = dev_get_drvdata(dev);
ssize_t len; ssize_t len;
/* FIXME: what's the maximum length of buf? page size?*/ len = PAGE_SIZE;
len = 500;
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n", len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
...@@ -2274,8 +2369,7 @@ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev, ...@@ -2274,8 +2369,7 @@ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
struct wl1271 *wl = dev_get_drvdata(dev); struct wl1271 *wl = dev_get_drvdata(dev);
ssize_t len; ssize_t len;
/* FIXME: what's the maximum length of buf? page size?*/ len = PAGE_SIZE;
len = 500;
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (wl->hw_pg_ver >= 0) if (wl->hw_pg_ver >= 0)
...@@ -2307,6 +2401,8 @@ int wl1271_register_hw(struct wl1271 *wl) ...@@ -2307,6 +2401,8 @@ int wl1271_register_hw(struct wl1271 *wl)
wl->mac80211_registered = true; wl->mac80211_registered = true;
register_netdevice_notifier(&wl1271_dev_notifier);
wl1271_notice("loaded"); wl1271_notice("loaded");
return 0; return 0;
...@@ -2315,6 +2411,7 @@ EXPORT_SYMBOL_GPL(wl1271_register_hw); ...@@ -2315,6 +2411,7 @@ EXPORT_SYMBOL_GPL(wl1271_register_hw);
void wl1271_unregister_hw(struct wl1271 *wl) void wl1271_unregister_hw(struct wl1271 *wl)
{ {
unregister_netdevice_notifier(&wl1271_dev_notifier);
ieee80211_unregister_hw(wl->hw); ieee80211_unregister_hw(wl->hw);
wl->mac80211_registered = false; wl->mac80211_registered = false;
...@@ -2323,6 +2420,14 @@ EXPORT_SYMBOL_GPL(wl1271_unregister_hw); ...@@ -2323,6 +2420,14 @@ EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
int wl1271_init_ieee80211(struct wl1271 *wl) int wl1271_init_ieee80211(struct wl1271 *wl)
{ {
static const u32 cipher_suites[] = {
WLAN_CIPHER_SUITE_WEP40,
WLAN_CIPHER_SUITE_WEP104,
WLAN_CIPHER_SUITE_TKIP,
WLAN_CIPHER_SUITE_CCMP,
WL1271_CIPHER_SUITE_GEM,
};
/* The tx descriptor buffer and the TKIP space. */ /* The tx descriptor buffer and the TKIP space. */
wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE + wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
sizeof(struct wl1271_tx_hw_descr); sizeof(struct wl1271_tx_hw_descr);
...@@ -2340,12 +2445,13 @@ int wl1271_init_ieee80211(struct wl1271 *wl) ...@@ -2340,12 +2445,13 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_CONNECTION_MONITOR |
IEEE80211_HW_SUPPORTS_CQM_RSSI; IEEE80211_HW_SUPPORTS_CQM_RSSI;
wl->hw->wiphy->cipher_suites = cipher_suites;
wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC); BIT(NL80211_IFTYPE_ADHOC);
wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->max_scan_ssids = 1;
wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
if (wl1271_11a_enabled())
wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz; wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
wl->hw->queues = 4; wl->hw->queues = 4;
...@@ -2365,6 +2471,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) ...@@ -2365,6 +2471,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
struct platform_device *plat_dev = NULL; struct platform_device *plat_dev = NULL;
struct wl1271 *wl; struct wl1271 *wl;
int i, ret; int i, ret;
unsigned int order;
hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
if (!hw) { if (!hw) {
...@@ -2392,6 +2499,10 @@ struct ieee80211_hw *wl1271_alloc_hw(void) ...@@ -2392,6 +2499,10 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work); INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
INIT_WORK(&wl->irq_work, wl1271_irq_work);
INIT_WORK(&wl->tx_work, wl1271_tx_work);
INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
wl->channel = WL1271_DEFAULT_CHANNEL; wl->channel = WL1271_DEFAULT_CHANNEL;
wl->beacon_int = WL1271_DEFAULT_BEACON_INT; wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
wl->default_key = 0; wl->default_key = 0;
...@@ -2423,11 +2534,18 @@ struct ieee80211_hw *wl1271_alloc_hw(void) ...@@ -2423,11 +2534,18 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl1271_debugfs_init(wl); wl1271_debugfs_init(wl);
order = get_order(WL1271_AGGR_BUFFER_SIZE);
wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
if (!wl->aggr_buf) {
ret = -ENOMEM;
goto err_hw;
}
/* Register platform device */ /* Register platform device */
ret = platform_device_register(wl->plat_dev); ret = platform_device_register(wl->plat_dev);
if (ret) { if (ret) {
wl1271_error("couldn't register platform device"); wl1271_error("couldn't register platform device");
goto err_hw; goto err_aggr;
} }
dev_set_drvdata(&wl->plat_dev->dev, wl); dev_set_drvdata(&wl->plat_dev->dev, wl);
...@@ -2453,6 +2571,9 @@ struct ieee80211_hw *wl1271_alloc_hw(void) ...@@ -2453,6 +2571,9 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
err_platform: err_platform:
platform_device_unregister(wl->plat_dev); platform_device_unregister(wl->plat_dev);
err_aggr:
free_pages((unsigned long)wl->aggr_buf, order);
err_hw: err_hw:
wl1271_debugfs_exit(wl); wl1271_debugfs_exit(wl);
kfree(plat_dev); kfree(plat_dev);
...@@ -2469,6 +2590,8 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw); ...@@ -2469,6 +2590,8 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
int wl1271_free_hw(struct wl1271 *wl) int wl1271_free_hw(struct wl1271 *wl)
{ {
platform_device_unregister(wl->plat_dev); platform_device_unregister(wl->plat_dev);
free_pages((unsigned long)wl->aggr_buf,
get_order(WL1271_AGGR_BUFFER_SIZE));
kfree(wl->plat_dev); kfree(wl->plat_dev);
wl1271_debugfs_exit(wl); wl1271_debugfs_exit(wl);
......
...@@ -39,6 +39,9 @@ void wl1271_elp_work(struct work_struct *work) ...@@ -39,6 +39,9 @@ void wl1271_elp_work(struct work_struct *work)
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;
if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) || if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) ||
(!test_bit(WL1271_FLAG_PSM, &wl->flags) && (!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
!test_bit(WL1271_FLAG_IDLE, &wl->flags))) !test_bit(WL1271_FLAG_IDLE, &wl->flags)))
...@@ -96,6 +99,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) ...@@ -96,6 +99,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
&compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT));
if (ret == 0) { if (ret == 0) {
wl1271_error("ELP wakeup timeout!"); wl1271_error("ELP wakeup timeout!");
ieee80211_queue_work(wl->hw, &wl->recovery_work);
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
goto err; goto err;
} else if (ret < 0) { } else if (ret < 0) {
...@@ -121,7 +125,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) ...@@ -121,7 +125,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
} }
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
bool send) u32 rates, bool send)
{ {
int ret; int ret;
...@@ -129,7 +133,14 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, ...@@ -129,7 +133,14 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
case STATION_POWER_SAVE_MODE: case STATION_POWER_SAVE_MODE:
wl1271_debug(DEBUG_PSM, "entering psm"); wl1271_debug(DEBUG_PSM, "entering psm");
ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE, send); ret = wl1271_acx_wake_up_conditions(wl);
if (ret < 0) {
wl1271_error("couldn't set wake up conditions");
return ret;
}
ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE,
rates, send);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -152,7 +163,8 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, ...@@ -152,7 +163,8 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE, send); ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE,
rates, send);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "wl1271_acx.h" #include "wl1271_acx.h"
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
bool send); u32 rates, bool send);
void wl1271_ps_elp_sleep(struct wl1271 *wl); void wl1271_ps_elp_sleep(struct wl1271 *wl);
int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake); int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake);
void wl1271_elp_work(struct work_struct *work); void wl1271_elp_work(struct work_struct *work);
......
...@@ -74,7 +74,7 @@ static void wl1271_rx_status(struct wl1271 *wl, ...@@ -74,7 +74,7 @@ static void wl1271_rx_status(struct wl1271 *wl,
} }
} }
static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
{ {
struct wl1271_rx_descriptor *desc; struct wl1271_rx_descriptor *desc;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -87,16 +87,16 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) ...@@ -87,16 +87,16 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
* workaround this by not retrieving them at all. * workaround this by not retrieving them at all.
*/ */
if (unlikely(wl->state == WL1271_STATE_PLT)) if (unlikely(wl->state == WL1271_STATE_PLT))
return; return -EINVAL;
skb = __dev_alloc_skb(length, GFP_KERNEL); skb = __dev_alloc_skb(length, GFP_KERNEL);
if (!skb) { if (!skb) {
wl1271_error("Couldn't allocate RX frame"); wl1271_error("Couldn't allocate RX frame");
return; return -ENOMEM;
} }
buf = skb_put(skb, length); buf = skb_put(skb, length);
wl1271_read(wl, WL1271_SLV_MEM_DATA, buf, length, true); memcpy(buf, data, length);
/* the data read starts with the descriptor */ /* the data read starts with the descriptor */
desc = (struct wl1271_rx_descriptor *) buf; desc = (struct wl1271_rx_descriptor *) buf;
...@@ -116,6 +116,8 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) ...@@ -116,6 +116,8 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
skb_trim(skb, skb->len - desc->pad_len); skb_trim(skb, skb->len - desc->pad_len);
ieee80211_rx_ni(wl->hw, skb); ieee80211_rx_ni(wl->hw, skb);
return 0;
} }
void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
...@@ -124,31 +126,60 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) ...@@ -124,31 +126,60 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
u32 buf_size; u32 buf_size;
u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
u32 rx_counter;
u32 mem_block; u32 mem_block;
u32 pkt_length;
u32 pkt_offset;
while (drv_rx_counter != fw_rx_counter) { while (drv_rx_counter != fw_rx_counter) {
mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter); buf_size = 0;
buf_size = wl1271_rx_get_buf_size(status, drv_rx_counter); rx_counter = drv_rx_counter;
while (rx_counter != fw_rx_counter) {
pkt_length = wl1271_rx_get_buf_size(status, rx_counter);
if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE)
break;
buf_size += pkt_length;
rx_counter++;
rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
}
if (buf_size == 0) { if (buf_size == 0) {
wl1271_warning("received empty data"); wl1271_warning("received empty data");
break; break;
} }
/*
* Choose the block we want to read
* For aggregated packets, only the first memory block should
* be retrieved. The FW takes care of the rest.
*/
mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter);
wl->rx_mem_pool_addr.addr = (mem_block << 8) + wl->rx_mem_pool_addr.addr = (mem_block << 8) +
le32_to_cpu(wl_mem_map->packet_memory_pool_start); le32_to_cpu(wl_mem_map->packet_memory_pool_start);
wl->rx_mem_pool_addr.addr_extra = wl->rx_mem_pool_addr.addr_extra =
wl->rx_mem_pool_addr.addr + 4; wl->rx_mem_pool_addr.addr + 4;
/* Choose the block we want to read */
wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr, wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr,
sizeof(wl->rx_mem_pool_addr), false); sizeof(wl->rx_mem_pool_addr), false);
wl1271_rx_handle_data(wl, buf_size); /* Read all available packets at once */
wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
buf_size, true);
/* Split data into separate packets */
pkt_offset = 0;
while (pkt_offset < buf_size) {
pkt_length = wl1271_rx_get_buf_size(status,
drv_rx_counter);
if (wl1271_rx_handle_data(wl,
wl->aggr_buf + pkt_offset,
pkt_length) < 0)
break;
wl->rx_counter++; wl->rx_counter++;
drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; drv_rx_counter++;
drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
pkt_offset += pkt_length;
} }
}
wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS,
cpu_to_le32(wl->rx_counter));
} }
...@@ -28,11 +28,43 @@ ...@@ -28,11 +28,43 @@
#include "wl1271_scan.h" #include "wl1271_scan.h"
#include "wl1271_acx.h" #include "wl1271_acx.h"
void wl1271_scan_complete_work(struct work_struct *work)
{
struct delayed_work *dwork;
struct wl1271 *wl;
dwork = container_of(work, struct delayed_work, work);
wl = container_of(dwork, struct wl1271, scan_complete_work);
wl1271_debug(DEBUG_SCAN, "Scanning complete");
mutex_lock(&wl->mutex);
if (wl->scan.state == WL1271_SCAN_STATE_IDLE) {
mutex_unlock(&wl->mutex);
return;
}
wl->scan.state = WL1271_SCAN_STATE_IDLE;
kfree(wl->scan.scanned_ch);
wl->scan.scanned_ch = NULL;
mutex_unlock(&wl->mutex);
ieee80211_scan_completed(wl->hw, false);
if (wl->scan.failed) {
wl1271_info("Scan completed due to error.");
ieee80211_queue_work(wl->hw, &wl->recovery_work);
}
}
static int wl1271_get_scan_channels(struct wl1271 *wl, static int wl1271_get_scan_channels(struct wl1271 *wl,
struct cfg80211_scan_request *req, struct cfg80211_scan_request *req,
struct basic_scan_channel_params *channels, struct basic_scan_channel_params *channels,
enum ieee80211_band band, bool passive) enum ieee80211_band band, bool passive)
{ {
struct conf_scan_settings *c = &wl->conf.scan;
int i, j; int i, j;
u32 flags; u32 flags;
...@@ -60,10 +92,17 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, ...@@ -60,10 +92,17 @@ static int wl1271_get_scan_channels(struct wl1271 *wl,
wl1271_debug(DEBUG_SCAN, "beacon_found %d", wl1271_debug(DEBUG_SCAN, "beacon_found %d",
req->channels[i]->beacon_found); req->channels[i]->beacon_found);
if (!passive) {
channels[j].min_duration = channels[j].min_duration =
cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); cpu_to_le32(c->min_dwell_time_active);
channels[j].max_duration = channels[j].max_duration =
cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); cpu_to_le32(c->max_dwell_time_active);
} else {
channels[j].min_duration =
cpu_to_le32(c->min_dwell_time_passive);
channels[j].max_duration =
cpu_to_le32(c->max_dwell_time_passive);
}
channels[j].early_termination = 0; channels[j].early_termination = 0;
channels[j].tx_power_att = req->channels[i]->max_power; channels[j].tx_power_att = req->channels[i]->max_power;
channels[j].channel = req->channels[i]->hw_value; channels[j].channel = req->channels[i]->hw_value;
...@@ -100,8 +139,11 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, ...@@ -100,8 +139,11 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
/* We always use high priority scans */ /* We always use high priority scans */
scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH; scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH;
if(passive)
/* No SSIDs means that we have a forced passive scan */
if (passive || wl->scan.req->n_ssids == 0)
scan_options |= WL1271_SCAN_OPT_PASSIVE; scan_options |= WL1271_SCAN_OPT_PASSIVE;
cmd->params.scan_options = cpu_to_le16(scan_options); cmd->params.scan_options = cpu_to_le16(scan_options);
cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
...@@ -117,7 +159,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, ...@@ -117,7 +159,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
cmd->params.rx_filter_options = cmd->params.rx_filter_options =
cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
cmd->params.n_probe_reqs = WL1271_SCAN_PROBE_REQS; cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
cmd->params.tx_rate = cpu_to_le32(basic_rate); cmd->params.tx_rate = cpu_to_le32(basic_rate);
cmd->params.tid_trigger = 0; cmd->params.tid_trigger = 0;
cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
...@@ -165,7 +207,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, ...@@ -165,7 +207,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
void wl1271_scan_stm(struct wl1271 *wl) void wl1271_scan_stm(struct wl1271 *wl)
{ {
int ret; int ret = 0;
switch (wl->scan.state) { switch (wl->scan.state) {
case WL1271_SCAN_STATE_IDLE: case WL1271_SCAN_STATE_IDLE:
...@@ -185,7 +227,7 @@ void wl1271_scan_stm(struct wl1271 *wl) ...@@ -185,7 +227,7 @@ void wl1271_scan_stm(struct wl1271 *wl)
ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true, ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true,
wl->conf.tx.basic_rate); wl->conf.tx.basic_rate);
if (ret == WL1271_NOTHING_TO_SCAN) { if (ret == WL1271_NOTHING_TO_SCAN) {
if (wl1271_11a_enabled()) if (wl->enable_11a)
wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
else else
wl->scan.state = WL1271_SCAN_STATE_DONE; wl->scan.state = WL1271_SCAN_STATE_DONE;
...@@ -215,18 +257,22 @@ void wl1271_scan_stm(struct wl1271 *wl) ...@@ -215,18 +257,22 @@ void wl1271_scan_stm(struct wl1271 *wl)
break; break;
case WL1271_SCAN_STATE_DONE: case WL1271_SCAN_STATE_DONE:
ieee80211_scan_completed(wl->hw, false); wl->scan.failed = false;
cancel_delayed_work(&wl->scan_complete_work);
kfree(wl->scan.scanned_ch); ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
wl->scan.scanned_ch = NULL; msecs_to_jiffies(0));
wl->scan.state = WL1271_SCAN_STATE_IDLE;
break; break;
default: default:
wl1271_error("invalid scan state"); wl1271_error("invalid scan state");
break; break;
} }
if (ret < 0) {
cancel_delayed_work(&wl->scan_complete_work);
ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
msecs_to_jiffies(0));
}
} }
int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
...@@ -249,6 +295,11 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, ...@@ -249,6 +295,11 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
wl->scan.scanned_ch = kzalloc(req->n_channels * wl->scan.scanned_ch = kzalloc(req->n_channels *
sizeof(*wl->scan.scanned_ch), sizeof(*wl->scan.scanned_ch),
GFP_KERNEL); GFP_KERNEL);
/* we assume failure so that timeout scenarios are handled correctly */
wl->scan.failed = true;
ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
msecs_to_jiffies(WL1271_SCAN_TIMEOUT));
wl1271_scan_stm(wl); wl1271_scan_stm(wl);
return 0; return 0;
......
...@@ -32,6 +32,7 @@ int wl1271_scan_build_probe_req(struct wl1271 *wl, ...@@ -32,6 +32,7 @@ int wl1271_scan_build_probe_req(struct wl1271 *wl,
const u8 *ssid, size_t ssid_len, const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len, u8 band); const u8 *ie, size_t ie_len, u8 band);
void wl1271_scan_stm(struct wl1271 *wl); void wl1271_scan_stm(struct wl1271 *wl);
void wl1271_scan_complete_work(struct work_struct *work);
#define WL1271_SCAN_MAX_CHANNELS 24 #define WL1271_SCAN_MAX_CHANNELS 24
#define WL1271_SCAN_DEFAULT_TAG 1 #define WL1271_SCAN_DEFAULT_TAG 1
...@@ -39,11 +40,10 @@ void wl1271_scan_stm(struct wl1271 *wl); ...@@ -39,11 +40,10 @@ void wl1271_scan_stm(struct wl1271 *wl);
#define WL1271_SCAN_OPT_ACTIVE 0 #define WL1271_SCAN_OPT_ACTIVE 0
#define WL1271_SCAN_OPT_PASSIVE 1 #define WL1271_SCAN_OPT_PASSIVE 1
#define WL1271_SCAN_OPT_PRIORITY_HIGH 4 #define WL1271_SCAN_OPT_PRIORITY_HIGH 4
#define WL1271_SCAN_CHAN_MIN_DURATION 30000 /* TU */
#define WL1271_SCAN_CHAN_MAX_DURATION 60000 /* TU */
#define WL1271_SCAN_BAND_2_4_GHZ 0 #define WL1271_SCAN_BAND_2_4_GHZ 0
#define WL1271_SCAN_BAND_5_GHZ 1 #define WL1271_SCAN_BAND_5_GHZ 1
#define WL1271_SCAN_PROBE_REQS 3
#define WL1271_SCAN_TIMEOUT 10000 /* msec */
enum { enum {
WL1271_SCAN_STATE_IDLE, WL1271_SCAN_STATE_IDLE,
......
...@@ -274,9 +274,8 @@ static void __devexit wl1271_remove(struct sdio_func *func) ...@@ -274,9 +274,8 @@ static void __devexit wl1271_remove(struct sdio_func *func)
{ {
struct wl1271 *wl = sdio_get_drvdata(func); struct wl1271 *wl = sdio_get_drvdata(func);
free_irq(wl->irq, wl);
wl1271_unregister_hw(wl); wl1271_unregister_hw(wl);
free_irq(wl->irq, wl);
wl1271_free_hw(wl); wl1271_free_hw(wl);
} }
......
...@@ -63,6 +63,11 @@ ...@@ -63,6 +63,11 @@
((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32)) ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32))
#define HW_ACCESS_WSPI_INIT_CMD_MASK 0 #define HW_ACCESS_WSPI_INIT_CMD_MASK 0
/* HW limitation: maximum possible chunk size is 4095 bytes */
#define WSPI_MAX_CHUNK_SIZE 4092
#define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE)
static inline struct spi_device *wl_to_spi(struct wl1271 *wl) static inline struct spi_device *wl_to_spi(struct wl1271 *wl)
{ {
return wl->if_priv; return wl->if_priv;
...@@ -202,17 +207,22 @@ static int wl1271_spi_read_busy(struct wl1271 *wl) ...@@ -202,17 +207,22 @@ static int wl1271_spi_read_busy(struct wl1271 *wl)
static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed) size_t len, bool fixed)
{ {
struct spi_transfer t[3]; struct spi_transfer t[2];
struct spi_message m; struct spi_message m;
u32 *busy_buf; u32 *busy_buf;
u32 *cmd; u32 *cmd;
u32 chunk_len;
while (len > 0) {
chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len);
cmd = &wl->buffer_cmd; cmd = &wl->buffer_cmd;
busy_buf = wl->buffer_busyword; busy_buf = wl->buffer_busyword;
*cmd = 0; *cmd = 0;
*cmd |= WSPI_CMD_READ; *cmd |= WSPI_CMD_READ;
*cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) &
WSPI_CMD_BYTE_LENGTH;
*cmd |= addr & WSPI_CMD_BYTE_ADDR; *cmd |= addr & WSPI_CMD_BYTE_ADDR;
if (fixed) if (fixed)
...@@ -236,7 +246,7 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, ...@@ -236,7 +246,7 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) &&
wl1271_spi_read_busy(wl)) { wl1271_spi_read_busy(wl)) {
memset(buf, 0, len); memset(buf, 0, chunk_len);
return; return;
} }
...@@ -244,48 +254,70 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, ...@@ -244,48 +254,70 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
memset(t, 0, sizeof(t)); memset(t, 0, sizeof(t));
t[0].rx_buf = buf; t[0].rx_buf = buf;
t[0].len = len; t[0].len = chunk_len;
t[0].cs_change = true; t[0].cs_change = true;
spi_message_add_tail(&t[0], &m); spi_message_add_tail(&t[0], &m);
spi_sync(wl_to_spi(wl), &m); spi_sync(wl_to_spi(wl), &m);
wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, chunk_len);
if (!fixed)
addr += chunk_len;
buf += chunk_len;
len -= chunk_len;
}
} }
static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed) size_t len, bool fixed)
{ {
struct spi_transfer t[2]; struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
struct spi_message m; struct spi_message m;
u32 commands[WSPI_MAX_NUM_OF_CHUNKS];
u32 *cmd; u32 *cmd;
u32 chunk_len;
int i;
cmd = &wl->buffer_cmd; WARN_ON(len > WL1271_AGGR_BUFFER_SIZE);
spi_message_init(&m);
memset(t, 0, sizeof(t));
cmd = &commands[0];
i = 0;
while (len > 0) {
chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len);
*cmd = 0; *cmd = 0;
*cmd |= WSPI_CMD_WRITE; *cmd |= WSPI_CMD_WRITE;
*cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) &
WSPI_CMD_BYTE_LENGTH;
*cmd |= addr & WSPI_CMD_BYTE_ADDR; *cmd |= addr & WSPI_CMD_BYTE_ADDR;
if (fixed) if (fixed)
*cmd |= WSPI_CMD_FIXED; *cmd |= WSPI_CMD_FIXED;
spi_message_init(&m); t[i].tx_buf = cmd;
memset(t, 0, sizeof(t)); t[i].len = sizeof(*cmd);
spi_message_add_tail(&t[i++], &m);
t[0].tx_buf = cmd; t[i].tx_buf = buf;
t[0].len = sizeof(*cmd); t[i].len = chunk_len;
spi_message_add_tail(&t[0], &m); spi_message_add_tail(&t[i++], &m);
t[1].tx_buf = buf; wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
t[1].len = len; wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, chunk_len);
spi_message_add_tail(&t[1], &m);
spi_sync(wl_to_spi(wl), &m); if (!fixed)
addr += chunk_len;
buf += chunk_len;
len -= chunk_len;
cmd++;
}
wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); spi_sync(wl_to_spi(wl), &m);
wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
} }
static irqreturn_t wl1271_irq(int irq, void *cookie) static irqreturn_t wl1271_irq(int irq, void *cookie)
...@@ -416,9 +448,8 @@ static int __devexit wl1271_remove(struct spi_device *spi) ...@@ -416,9 +448,8 @@ static int __devexit wl1271_remove(struct spi_device *spi)
{ {
struct wl1271 *wl = dev_get_drvdata(&spi->dev); struct wl1271 *wl = dev_get_drvdata(&spi->dev);
free_irq(wl->irq, wl);
wl1271_unregister_hw(wl); wl1271_unregister_hw(wl);
free_irq(wl->irq, wl);
wl1271_free_hw(wl); wl1271_free_hw(wl);
return 0; return 0;
......
...@@ -199,19 +199,6 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) ...@@ -199,19 +199,6 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
buf = nla_data(tb[WL1271_TM_ATTR_DATA]); buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
len = nla_len(tb[WL1271_TM_ATTR_DATA]); len = nla_len(tb[WL1271_TM_ATTR_DATA]);
/*
* FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
* configurations) can be removed when those NVS files stop floating
* around.
*/
if (len != sizeof(struct wl1271_nvs_file) &&
(len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
wl1271_11a_enabled())) {
wl1271_error("nvs size is not as expected: %zu != %zu",
len, sizeof(struct wl1271_nvs_file));
return -EMSGSIZE;
}
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
kfree(wl->nvs); kfree(wl->nvs);
...@@ -224,6 +211,7 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) ...@@ -224,6 +211,7 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
} }
memcpy(wl->nvs, buf, len); memcpy(wl->nvs, buf, len);
wl->nvs_len = len;
wl1271_debug(DEBUG_TESTMODE, "testmode pushed nvs"); wl1271_debug(DEBUG_TESTMODE, "testmode pushed nvs");
......
...@@ -43,13 +43,17 @@ static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb) ...@@ -43,13 +43,17 @@ static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb)
return -EBUSY; return -EBUSY;
} }
static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
u32 buf_offset)
{ {
struct wl1271_tx_hw_descr *desc; struct wl1271_tx_hw_descr *desc;
u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
u32 total_blocks; u32 total_blocks;
int id, ret = -EBUSY; int id, ret = -EBUSY;
if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
return -EBUSY;
/* allocate free identifier for the packet */ /* allocate free identifier for the packet */
id = wl1271_tx_id(wl, skb); id = wl1271_tx_id(wl, skb);
if (id < 0) if (id < 0)
...@@ -82,7 +86,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) ...@@ -82,7 +86,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
return ret; return ret;
} }
static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
u32 extra, struct ieee80211_tx_info *control) u32 extra, struct ieee80211_tx_info *control)
{ {
struct timespec ts; struct timespec ts;
...@@ -110,9 +114,9 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, ...@@ -110,9 +114,9 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
/* 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;
/* queue */ /* 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 = wl1271_tx_ac_to_tid(ac); desc->tid = ac;
desc->aid = TX_HW_DEFAULT_AID; desc->aid = TX_HW_DEFAULT_AID;
desc->reserved = 0; desc->reserved = 0;
...@@ -133,59 +137,17 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, ...@@ -133,59 +137,17 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
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", pad);
return 0;
}
static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb,
struct ieee80211_tx_info *control)
{
struct wl1271_tx_hw_descr *desc;
int len;
/* FIXME: This is a workaround for getting non-aligned packets.
This happens at least with EAPOL packets from the user space.
Our DMA requires packets to be aligned on a 4-byte boundary.
*/
if (unlikely((long)skb->data & 0x03)) {
int offset = (4 - (long)skb->data) & 0x03;
wl1271_debug(DEBUG_TX, "skb offset %d", offset);
/* check whether the current skb can be used */
if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) {
unsigned char *src = skb->data;
/* align the buffer on a 4-byte boundary */
skb_reserve(skb, offset);
memmove(skb->data, src, skb->len);
} else {
wl1271_info("No handler, fixme!");
return -EINVAL;
}
}
len = WL1271_TX_ALIGN(skb->len);
/* perform a fixed address block write with the packet */
wl1271_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true);
/* write packet new counter into the write access register */
wl->tx_packets_count++;
desc = (struct wl1271_tx_hw_descr *) skb->data;
wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)",
desc->id, skb, len, desc->length);
return 0;
} }
/* caller must hold wl->mutex */ /* caller must hold wl->mutex */
static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
u32 buf_offset)
{ {
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
u32 extra = 0; u32 extra = 0;
int ret = 0; int ret = 0;
u8 idx; u8 idx;
u32 total_len;
if (!skb) if (!skb)
return -EINVAL; return -EINVAL;
...@@ -208,19 +170,22 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) ...@@ -208,19 +170,22 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
} }
} }
ret = wl1271_tx_allocate(wl, skb, extra); ret = wl1271_tx_allocate(wl, skb, extra, buf_offset);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = wl1271_tx_fill_hdr(wl, skb, extra, info); wl1271_tx_fill_hdr(wl, skb, extra, info);
if (ret < 0)
return ret;
ret = wl1271_tx_send_packet(wl, skb, info); /*
if (ret < 0) * The length of each packet is stored in terms of words. Thus, we must
return ret; * pad the skb data to make sure its length is aligned.
* The number of padding bytes is computed and set in wl1271_tx_fill_hdr
*/
total_len = WL1271_TX_ALIGN(skb->len);
memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len);
memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len);
return ret; return total_len;
} }
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
...@@ -245,7 +210,7 @@ void wl1271_tx_work(struct work_struct *work) ...@@ -245,7 +210,7 @@ void wl1271_tx_work(struct work_struct *work)
struct sk_buff *skb; struct sk_buff *skb;
bool woken_up = false; bool woken_up = false;
u32 sta_rates = 0; u32 sta_rates = 0;
u32 prev_tx_packets_count; u32 buf_offset;
int ret; int ret;
/* check if the rates supported by the AP have changed */ /* check if the rates supported by the AP have changed */
...@@ -262,14 +227,15 @@ void wl1271_tx_work(struct work_struct *work) ...@@ -262,14 +227,15 @@ void wl1271_tx_work(struct work_struct *work)
if (unlikely(wl->state == WL1271_STATE_OFF)) if (unlikely(wl->state == WL1271_STATE_OFF))
goto out; goto out;
prev_tx_packets_count = wl->tx_packets_count;
/* if rates have changed, re-configure the rate policy */ /* if rates have changed, re-configure the rate policy */
if (unlikely(sta_rates)) { if (unlikely(sta_rates)) {
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_rate_policies(wl);
} }
/* Prepare the transfer buffer, by aggregating all
* available packets */
buf_offset = 0;
while ((skb = skb_dequeue(&wl->tx_queue))) { while ((skb = skb_dequeue(&wl->tx_queue))) {
if (!woken_up) { if (!woken_up) {
ret = wl1271_ps_elp_wakeup(wl, false); ret = wl1271_ps_elp_wakeup(wl, false);
...@@ -278,21 +244,30 @@ void wl1271_tx_work(struct work_struct *work) ...@@ -278,21 +244,30 @@ void wl1271_tx_work(struct work_struct *work)
woken_up = true; woken_up = true;
} }
ret = wl1271_tx_frame(wl, skb); ret = wl1271_prepare_tx_frame(wl, skb, buf_offset);
if (ret == -EBUSY) { if (ret == -EBUSY) {
/* firmware buffer is full, lets stop transmitting. */ /*
* Either the firmware buffer is full, or the
* aggregation buffer is.
* Queue back last skb, and stop aggregating.
*/
skb_queue_head(&wl->tx_queue, skb); skb_queue_head(&wl->tx_queue, skb);
goto out_ack; goto out_ack;
} else if (ret < 0) { } else if (ret < 0) {
dev_kfree_skb(skb); dev_kfree_skb(skb);
goto out_ack; goto out_ack;
} }
buf_offset += ret;
wl->tx_packets_count++;
} }
out_ack: out_ack:
if (buf_offset) {
wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
buf_offset, true);
/* interrupt the firmware with the new packets */ /* interrupt the firmware with the new packets */
if (prev_tx_packets_count != wl->tx_packets_count)
wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
}
out: out:
if (woken_up) if (woken_up)
...@@ -422,8 +397,6 @@ void wl1271_tx_reset(struct wl1271 *wl) ...@@ -422,8 +397,6 @@ void wl1271_tx_reset(struct wl1271 *wl)
struct sk_buff *skb; struct sk_buff *skb;
/* TX failure */ /* TX failure */
/* control->flags = 0; FIXME */
while ((skb = skb_dequeue(&wl->tx_queue))) { while ((skb = skb_dequeue(&wl->tx_queue))) {
wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
ieee80211_tx_status(wl->hw, skb); ieee80211_tx_status(wl->hw, skb);
......
...@@ -139,23 +139,6 @@ static inline int wl1271_tx_get_queue(int queue) ...@@ -139,23 +139,6 @@ static inline int wl1271_tx_get_queue(int queue)
} }
} }
/* wl1271 tx descriptor needs the tid and we need to convert it from ac */
static inline int wl1271_tx_ac_to_tid(int ac)
{
switch (ac) {
case 0:
return 0;
case 1:
return 2;
case 2:
return 4;
case 3:
return 6;
default:
return 0;
}
}
void wl1271_tx_work(struct work_struct *work); void wl1271_tx_work(struct work_struct *work);
void wl1271_tx_complete(struct wl1271 *wl); void wl1271_tx_complete(struct wl1271 *wl);
void wl1271_tx_reset(struct wl1271 *wl); void wl1271_tx_reset(struct wl1271 *wl);
......
...@@ -32,7 +32,20 @@ struct wl12xx_platform_data { ...@@ -32,7 +32,20 @@ struct wl12xx_platform_data {
int board_ref_clock; int board_ref_clock;
}; };
#ifdef CONFIG_WL12XX_PLATFORM_DATA
int wl12xx_set_platform_data(const struct wl12xx_platform_data *data); int wl12xx_set_platform_data(const struct wl12xx_platform_data *data);
#else
static inline
int wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
{
return -ENOSYS;
}
#endif
const struct wl12xx_platform_data *wl12xx_get_platform_data(void); const struct wl12xx_platform_data *wl12xx_get_platform_data(void);
#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