Commit 333c0dbf authored by John W. Linville's avatar John W. Linville
parents 115f9450 95dac04f
......@@ -11,7 +11,6 @@ config WL12XX
depends on WL12XX_MENU && GENERIC_HARDIRQS
depends on INET
select FW_LOADER
select CRC7
---help---
This module adds support for wireless adapters based on TI wl1271 and
TI wl1273 chipsets. This module does *not* include support for wl1251.
......@@ -33,6 +32,7 @@ config WL12XX_HT
config WL12XX_SPI
tristate "TI wl12xx SPI support"
depends on WL12XX && SPI_MASTER
select CRC7
---help---
This module adds support for the SPI interface of adapters using
TI wl12xx chipsets. Select this if your platform is using
......
......@@ -25,7 +25,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/crc7.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
......@@ -1068,6 +1067,7 @@ int wl1271_acx_sta_mem_cfg(struct wl1271 *wl)
mem_conf->tx_free_req = mem->min_req_tx_blocks;
mem_conf->rx_free_req = mem->min_req_rx_blocks;
mem_conf->tx_min = mem->tx_min;
mem_conf->fwlog_blocks = wl->conf.fwlog.mem_blocks;
ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
sizeof(*mem_conf));
......@@ -1577,6 +1577,53 @@ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
return ret;
}
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable)
{
struct wl1271_acx_ps_rx_streaming *rx_streaming;
u32 conf_queues, enable_queues;
int i, ret = 0;
wl1271_debug(DEBUG_ACX, "acx ps rx streaming");
rx_streaming = kzalloc(sizeof(*rx_streaming), GFP_KERNEL);
if (!rx_streaming) {
ret = -ENOMEM;
goto out;
}
conf_queues = wl->conf.rx_streaming.queues;
if (enable)
enable_queues = conf_queues;
else
enable_queues = 0;
for (i = 0; i < 8; i++) {
/*
* Skip non-changed queues, to avoid redundant acxs.
* this check assumes conf.rx_streaming.queues can't
* be changed while rx_streaming is enabled.
*/
if (!(conf_queues & BIT(i)))
continue;
rx_streaming->tid = i;
rx_streaming->enable = enable_queues & BIT(i);
rx_streaming->period = wl->conf.rx_streaming.interval;
rx_streaming->timeout = wl->conf.rx_streaming.interval;
ret = wl1271_cmd_configure(wl, ACX_PS_RX_STREAMING,
rx_streaming,
sizeof(*rx_streaming));
if (ret < 0) {
wl1271_warning("acx ps rx streaming failed: %d", ret);
goto out;
}
}
out:
kfree(rx_streaming);
return ret;
}
int wl1271_acx_max_tx_retry(struct wl1271 *wl)
{
struct wl1271_acx_max_tx_retry *acx = NULL;
......
......@@ -828,6 +828,8 @@ struct wl1271_acx_sta_config_memory {
u8 tx_free_req;
u8 rx_free_req;
u8 tx_min;
u8 fwlog_blocks;
u8 padding[3];
} __packed;
struct wl1271_acx_mem_map {
......@@ -1153,6 +1155,19 @@ struct wl1271_acx_fw_tsf_information {
u8 padding[3];
} __packed;
struct wl1271_acx_ps_rx_streaming {
struct acx_header header;
u8 tid;
u8 enable;
/* interval between triggers (10-100 msec) */
u8 period;
/* timeout before first trigger (0-200 msec) */
u8 timeout;
} __packed;
struct wl1271_acx_max_tx_retry {
struct acx_header header;
......@@ -1384,6 +1399,7 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl,
int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
bool enable);
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable);
int wl1271_acx_max_tx_retry(struct wl1271 *wl);
int wl1271_acx_config_ps(struct wl1271 *wl);
int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
......
......@@ -102,6 +102,33 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
}
static unsigned int wl12xx_get_fw_ver_quirks(struct wl1271 *wl)
{
unsigned int quirks = 0;
unsigned int *fw_ver = wl->chip.fw_ver;
/* Only for wl127x */
if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
/* Check STA version */
(((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
(fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
/* Check AP version */
((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
(fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
/* Only new station firmwares support routing fw logs to the host */
if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
(fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN))
quirks |= WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED;
/* This feature is not yet supported for AP mode */
if (fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP)
quirks |= WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED;
return quirks;
}
static void wl1271_parse_fw_ver(struct wl1271 *wl)
{
int ret;
......@@ -116,6 +143,9 @@ static void wl1271_parse_fw_ver(struct wl1271 *wl)
memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver));
return;
}
/* Check if any quirks are needed with older fw versions */
wl->quirks |= wl12xx_get_fw_ver_quirks(wl);
}
static void wl1271_boot_fw_version(struct wl1271 *wl)
......@@ -749,6 +779,9 @@ int wl1271_load_firmware(struct wl1271 *wl)
clk |= (wl->ref_clock << 1) << 4;
}
if (wl->quirks & WL12XX_QUIRK_LPD_MODE)
clk |= SCRATCH_ENABLE_LPD;
wl1271_write32(wl, DRPW_SCRATCH_START, clk);
wl1271_set_partition(wl, &part_table[PART_WORK]);
......
......@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/crc7.h>
#include <linux/spi/spi.h>
#include <linux/etherdevice.h>
#include <linux/ieee80211.h>
......@@ -106,7 +105,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
fail:
WARN_ON(1);
ieee80211_queue_work(wl->hw, &wl->recovery_work);
wl12xx_queue_recovery_work(wl);
return ret;
}
......@@ -135,6 +134,11 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
/* Override the REF CLK from the NVS with the one from platform data */
gen_parms->general_params.ref_clock = wl->ref_clock;
/* LPD mode enable (bits 6-7) in WL1271 AP mode only */
if (wl->quirks & WL12XX_QUIRK_LPD_MODE)
gen_parms->general_params.general_settings |=
GENERAL_SETTINGS_DRPW_LPD;
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
if (ret < 0) {
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
......@@ -352,7 +356,7 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask);
if (ret != 0) {
ieee80211_queue_work(wl->hw, &wl->recovery_work);
wl12xx_queue_recovery_work(wl);
return ret;
}
......@@ -1223,3 +1227,87 @@ int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid)
out:
return ret;
}
int wl12xx_cmd_config_fwlog(struct wl1271 *wl)
{
struct wl12xx_cmd_config_fwlog *cmd;
int ret = 0;
wl1271_debug(DEBUG_CMD, "cmd config firmware logger");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
cmd->logger_mode = wl->conf.fwlog.mode;
cmd->log_severity = wl->conf.fwlog.severity;
cmd->timestamp = wl->conf.fwlog.timestamp;
cmd->output = wl->conf.fwlog.output;
cmd->threshold = wl->conf.fwlog.threshold;
ret = wl1271_cmd_send(wl, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to send config firmware logger command");
goto out_free;
}
out_free:
kfree(cmd);
out:
return ret;
}
int wl12xx_cmd_start_fwlog(struct wl1271 *wl)
{
struct wl12xx_cmd_start_fwlog *cmd;
int ret = 0;
wl1271_debug(DEBUG_CMD, "cmd start firmware logger");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to send start firmware logger command");
goto out_free;
}
out_free:
kfree(cmd);
out:
return ret;
}
int wl12xx_cmd_stop_fwlog(struct wl1271 *wl)
{
struct wl12xx_cmd_stop_fwlog *cmd;
int ret = 0;
wl1271_debug(DEBUG_CMD, "cmd stop firmware logger");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
ret = wl1271_cmd_send(wl, CMD_STOP_FWLOGGER, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to send stop firmware logger command");
goto out_free;
}
out_free:
kfree(cmd);
out:
return ret;
}
......@@ -70,6 +70,9 @@ int wl1271_cmd_start_bss(struct wl1271 *wl);
int wl1271_cmd_stop_bss(struct wl1271 *wl);
int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid);
int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid);
int wl12xx_cmd_config_fwlog(struct wl1271 *wl);
int wl12xx_cmd_start_fwlog(struct wl1271 *wl);
int wl12xx_cmd_stop_fwlog(struct wl1271 *wl);
enum wl1271_commands {
CMD_INTERROGATE = 1, /*use this to read information elements*/
......@@ -107,6 +110,9 @@ enum wl1271_commands {
CMD_START_PERIODIC_SCAN = 50,
CMD_STOP_PERIODIC_SCAN = 51,
CMD_SET_STA_STATE = 52,
CMD_CONFIG_FWLOGGER = 53,
CMD_START_FWLOGGER = 54,
CMD_STOP_FWLOGGER = 55,
/* AP mode commands */
CMD_BSS_START = 60,
......@@ -575,4 +581,60 @@ struct wl1271_cmd_remove_sta {
u8 padding1;
} __packed;
/*
* Continuous mode - packets are transferred to the host periodically
* via the data path.
* On demand - Log messages are stored in a cyclic buffer in the
* firmware, and only transferred to the host when explicitly requested
*/
enum wl12xx_fwlogger_log_mode {
WL12XX_FWLOG_CONTINUOUS,
WL12XX_FWLOG_ON_DEMAND
};
/* Include/exclude timestamps from the log messages */
enum wl12xx_fwlogger_timestamp {
WL12XX_FWLOG_TIMESTAMP_DISABLED,
WL12XX_FWLOG_TIMESTAMP_ENABLED
};
/*
* Logs can be routed to the debug pinouts (where available), to the host bus
* (SDIO/SPI), or dropped
*/
enum wl12xx_fwlogger_output {
WL12XX_FWLOG_OUTPUT_NONE,
WL12XX_FWLOG_OUTPUT_DBG_PINS,
WL12XX_FWLOG_OUTPUT_HOST,
};
struct wl12xx_cmd_config_fwlog {
struct wl1271_cmd_header header;
/* See enum wl12xx_fwlogger_log_mode */
u8 logger_mode;
/* Minimum log level threshold */
u8 log_severity;
/* Include/exclude timestamps from the log messages */
u8 timestamp;
/* See enum wl1271_fwlogger_output */
u8 output;
/* Regulates the frequency of log messages */
u8 threshold;
u8 padding[3];
} __packed;
struct wl12xx_cmd_start_fwlog {
struct wl1271_cmd_header header;
} __packed;
struct wl12xx_cmd_stop_fwlog {
struct wl1271_cmd_header header;
} __packed;
#endif /* __WL1271_CMD_H__ */
......@@ -1248,6 +1248,59 @@ struct conf_fm_coex {
u8 swallow_clk_diff;
};
struct conf_rx_streaming_settings {
/*
* RX Streaming duration (in msec) from last tx/rx
*
* Range: u32
*/
u32 duration;
/*
* Bitmap of tids to be polled during RX streaming.
* (Note: it doesn't look like it really matters)
*
* Range: 0x1-0xff
*/
u8 queues;
/*
* RX Streaming interval.
* (Note:this value is also used as the rx streaming timeout)
* Range: 0 (disabled), 10 - 100
*/
u8 interval;
/*
* enable rx streaming also when there is no coex activity
*/
u8 always;
};
struct conf_fwlog {
/* Continuous or on-demand */
u8 mode;
/*
* Number of memory blocks dedicated for the FW logger
*
* Range: 1-3, or 0 to disable the FW logger
*/
u8 mem_blocks;
/* Minimum log level threshold */
u8 severity;
/* Include/exclude timestamps from the log messages */
u8 timestamp;
/* See enum wl1271_fwlogger_output */
u8 output;
/* Regulates the frequency of log messages */
u8 threshold;
};
struct conf_drv_settings {
struct conf_sg_settings sg;
struct conf_rx_settings rx;
......@@ -1263,6 +1316,8 @@ struct conf_drv_settings {
struct conf_memory_settings mem_wl127x;
struct conf_memory_settings mem_wl128x;
struct conf_fm_coex fm_coex;
struct conf_rx_streaming_settings rx_streaming;
struct conf_fwlog fwlog;
u8 hci_io_ds;
};
......
......@@ -71,6 +71,14 @@ static const struct file_operations name## _ops = { \
if (!entry || IS_ERR(entry)) \
goto err; \
#define DEBUGFS_ADD_PREFIX(prefix, name, parent) \
do { \
entry = debugfs_create_file(#name, 0400, parent, \
wl, &prefix## _## name## _ops); \
if (!entry || IS_ERR(entry)) \
goto err; \
} while (0);
#define DEBUGFS_FWSTATS_FILE(sub, name, fmt) \
static ssize_t sub## _ ##name## _read(struct file *file, \
char __user *userbuf, \
......@@ -298,7 +306,7 @@ static ssize_t start_recovery_write(struct file *file,
struct wl1271 *wl = file->private_data;
mutex_lock(&wl->mutex);
ieee80211_queue_work(wl->hw, &wl->recovery_work);
wl12xx_queue_recovery_work(wl);
mutex_unlock(&wl->mutex);
return count;
......@@ -527,11 +535,129 @@ static const struct file_operations beacon_interval_ops = {
.llseek = default_llseek,
};
static ssize_t rx_streaming_interval_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
char buf[10];
size_t len;
unsigned long value;
int ret;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
ret = kstrtoul(buf, 0, &value);
if (ret < 0) {
wl1271_warning("illegal value in rx_streaming_interval!");
return -EINVAL;
}
/* valid values: 0, 10-100 */
if (value && (value < 10 || value > 100)) {
wl1271_warning("value is not in range!");
return -ERANGE;
}
mutex_lock(&wl->mutex);
wl->conf.rx_streaming.interval = value;
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
wl1271_recalc_rx_streaming(wl);
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
return count;
}
static ssize_t rx_streaming_interval_read(struct file *file,
char __user *userbuf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
return wl1271_format_buffer(userbuf, count, ppos,
"%d\n", wl->conf.rx_streaming.interval);
}
static const struct file_operations rx_streaming_interval_ops = {
.read = rx_streaming_interval_read,
.write = rx_streaming_interval_write,
.open = wl1271_open_file_generic,
.llseek = default_llseek,
};
static ssize_t rx_streaming_always_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
char buf[10];
size_t len;
unsigned long value;
int ret;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
ret = kstrtoul(buf, 0, &value);
if (ret < 0) {
wl1271_warning("illegal value in rx_streaming_write!");
return -EINVAL;
}
/* valid values: 0, 10-100 */
if (!(value == 0 || value == 1)) {
wl1271_warning("value is not in valid!");
return -EINVAL;
}
mutex_lock(&wl->mutex);
wl->conf.rx_streaming.always = value;
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
wl1271_recalc_rx_streaming(wl);
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
return count;
}
static ssize_t rx_streaming_always_read(struct file *file,
char __user *userbuf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
return wl1271_format_buffer(userbuf, count, ppos,
"%d\n", wl->conf.rx_streaming.always);
}
static const struct file_operations rx_streaming_always_ops = {
.read = rx_streaming_always_read,
.write = rx_streaming_always_write,
.open = wl1271_open_file_generic,
.llseek = default_llseek,
};
static int wl1271_debugfs_add_files(struct wl1271 *wl,
struct dentry *rootdir)
{
int ret = 0;
struct dentry *entry, *stats;
struct dentry *entry, *stats, *streaming;
stats = debugfs_create_dir("fw-statistics", rootdir);
if (!stats || IS_ERR(stats)) {
......@@ -640,6 +766,14 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
DEBUGFS_ADD(dtim_interval, rootdir);
DEBUGFS_ADD(beacon_interval, rootdir);
streaming = debugfs_create_dir("rx_streaming", rootdir);
if (!streaming || IS_ERR(streaming))
goto err;
DEBUGFS_ADD_PREFIX(rx_streaming, interval, streaming);
DEBUGFS_ADD_PREFIX(rx_streaming, always, streaming);
return 0;
err:
......
......@@ -133,10 +133,13 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
if (ret < 0)
break;
/* enable beacon early termination */
ret = wl1271_acx_bet_enable(wl, true);
if (ret < 0)
break;
/*
* BET has only a minor effect in 5GHz and masks
* channel switch IEs, so we only enable BET on 2.4GHz
*/
if (wl->band == IEEE80211_BAND_2GHZ)
/* enable beacon early termination */
ret = wl1271_acx_bet_enable(wl, true);
if (wl->ps_compl) {
complete(wl->ps_compl);
......@@ -183,6 +186,21 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, u8 ba_allowed)
ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, wl->bssid);
}
static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
u8 enable)
{
if (enable) {
/* disable dynamic PS when requested by the firmware */
ieee80211_disable_dyn_ps(wl->vif);
set_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
} else {
ieee80211_enable_dyn_ps(wl->vif);
clear_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
wl1271_recalc_rx_streaming(wl);
}
}
static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
{
wl1271_debug(DEBUG_EVENT, "MBOX DUMP:");
......@@ -226,14 +244,10 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
}
}
/* disable dynamic PS when requested by the firmware */
if (vector & SOFT_GEMINI_SENSE_EVENT_ID &&
wl->bss_type == BSS_TYPE_STA_BSS) {
if (mbox->soft_gemini_sense_info)
ieee80211_disable_dyn_ps(wl->vif);
else
ieee80211_enable_dyn_ps(wl->vif);
}
wl->bss_type == BSS_TYPE_STA_BSS)
wl12xx_event_soft_gemini_sense(wl,
mbox->soft_gemini_sense_info);
/*
* The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
......
......@@ -24,6 +24,9 @@
#ifndef __INI_H__
#define __INI_H__
#define GENERAL_SETTINGS_DRPW_LPD 0xc0
#define SCRATCH_ENABLE_LPD BIT(25)
#define WL1271_INI_MAX_SMART_REFLEX_PARAM 16
struct wl1271_ini_general_params {
......
......@@ -321,6 +321,20 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl)
return 0;
}
static int wl12xx_init_fwlog(struct wl1271 *wl)
{
int ret;
if (wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED)
return 0;
ret = wl12xx_cmd_config_fwlog(wl);
if (ret < 0)
return ret;
return 0;
}
static int wl1271_sta_hw_init(struct wl1271 *wl)
{
int ret;
......@@ -382,6 +396,11 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;
/* Configure the FW logger */
ret = wl12xx_init_fwlog(wl);
if (ret < 0)
return ret;
return 0;
}
......
......@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/crc7.h>
#include <linux/spi/spi.h>
#include "wl12xx.h"
......@@ -128,12 +127,14 @@ EXPORT_SYMBOL_GPL(wl1271_set_partition);
void wl1271_io_reset(struct wl1271 *wl)
{
wl->if_ops->reset(wl);
if (wl->if_ops->reset)
wl->if_ops->reset(wl);
}
void wl1271_io_init(struct wl1271 *wl)
{
wl->if_ops->init(wl);
if (wl->if_ops->init)
wl->if_ops->init(wl);
}
void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val)
......
......@@ -128,6 +128,20 @@ static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf,
wl1271_raw_write(wl, physical, buf, len, fixed);
}
static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr,
void *buf, size_t len, bool fixed)
{
int physical;
int addr;
/* Addresses are stored internally as addresses to 32 bytes blocks */
addr = hwaddr << 5;
physical = wl1271_translate_addr(wl, addr);
wl1271_raw_read(wl, physical, buf, len, fixed);
}
static inline u32 wl1271_read32(struct wl1271 *wl, int addr)
{
return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr));
......
This diff is collapsed.
......@@ -118,7 +118,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
&compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT));
if (ret == 0) {
wl1271_error("ELP wakeup timeout!");
ieee80211_queue_work(wl->hw, &wl->recovery_work);
wl12xx_queue_recovery_work(wl);
ret = -ETIMEDOUT;
goto err;
} else if (ret < 0) {
......@@ -169,9 +169,11 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
wl1271_debug(DEBUG_PSM, "leaving psm");
/* disable beacon early termination */
ret = wl1271_acx_bet_enable(wl, false);
if (ret < 0)
return ret;
if (wl->band == IEEE80211_BAND_2GHZ) {
ret = wl1271_acx_bet_enable(wl, false);
if (ret < 0)
return ret;
}
/* disable beacon filtering */
ret = wl1271_acx_beacon_filter_opt(wl, false);
......@@ -202,7 +204,7 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
info = IEEE80211_SKB_CB(skb);
info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
info->status.rates[0].idx = -1;
ieee80211_tx_status(wl->hw, skb);
ieee80211_tx_status_ni(wl->hw, skb);
filtered++;
}
}
......
......@@ -22,6 +22,7 @@
*/
#include <linux/gfp.h>
#include <linux/sched.h>
#include "wl12xx.h"
#include "acx.h"
......@@ -95,6 +96,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
struct ieee80211_hdr *hdr;
u8 *buf;
u8 beacon = 0;
u8 is_data = 0;
/*
* In PLT mode we seem to get frames and mac80211 warns about them,
......@@ -106,6 +108,13 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
/* the data read starts with the descriptor */
desc = (struct wl1271_rx_descriptor *) data;
if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) {
size_t len = length - sizeof(*desc);
wl12xx_copy_fwlog(wl, data + sizeof(*desc), len);
wake_up_interruptible(&wl->fwlog_waitq);
return 0;
}
switch (desc->status & WL1271_RX_DESC_STATUS_MASK) {
/* discard corrupted packets */
case WL1271_RX_DESC_DRIVER_RX_Q_FAIL:
......@@ -137,6 +146,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
hdr = (struct ieee80211_hdr *)skb->data;
if (ieee80211_is_beacon(hdr->frame_control))
beacon = 1;
if (ieee80211_is_data_present(hdr->frame_control))
is_data = 1;
wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
......@@ -147,9 +158,9 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
skb_trim(skb, skb->len - desc->pad_len);
skb_queue_tail(&wl->deferred_rx_queue, skb);
ieee80211_queue_work(wl->hw, &wl->netstack_work);
queue_work(wl->freezable_wq, &wl->netstack_work);
return 0;
return is_data;
}
void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
......@@ -162,6 +173,8 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
u32 mem_block;
u32 pkt_length;
u32 pkt_offset;
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
bool had_data = false;
while (drv_rx_counter != fw_rx_counter) {
buf_size = 0;
......@@ -214,9 +227,11 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
* conditions, in that case the received frame will just
* be dropped.
*/
wl1271_rx_handle_data(wl,
wl->aggr_buf + pkt_offset,
pkt_length);
if (wl1271_rx_handle_data(wl,
wl->aggr_buf + pkt_offset,
pkt_length) == 1)
had_data = true;
wl->rx_counter++;
drv_rx_counter++;
drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
......@@ -230,6 +245,20 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
*/
if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION)
wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
if (!is_ap && wl->conf.rx_streaming.interval && had_data &&
(wl->conf.rx_streaming.always ||
test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) {
u32 timeout = wl->conf.rx_streaming.duration;
/* restart rx streaming */
if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
ieee80211_queue_work(wl->hw,
&wl->rx_streaming_enable_work);
mod_timer(&wl->rx_streaming_timer,
jiffies + msecs_to_jiffies(timeout));
}
}
void wl1271_set_default_filters(struct wl1271 *wl)
......
......@@ -97,6 +97,18 @@
#define RX_BUF_SIZE_MASK 0xFFF00
#define RX_BUF_SIZE_SHIFT_DIV 6
enum {
WL12XX_RX_CLASS_UNKNOWN,
WL12XX_RX_CLASS_MANAGEMENT,
WL12XX_RX_CLASS_DATA,
WL12XX_RX_CLASS_QOS_DATA,
WL12XX_RX_CLASS_BCN_PRBRSP,
WL12XX_RX_CLASS_EAPOL,
WL12XX_RX_CLASS_BA_EVENT,
WL12XX_RX_CLASS_AMSDU,
WL12XX_RX_CLASS_LOGGER,
};
struct wl1271_rx_descriptor {
__le16 length;
u8 status;
......
......@@ -62,7 +62,7 @@ void wl1271_scan_complete_work(struct work_struct *work)
if (wl->scan.failed) {
wl1271_info("Scan completed due to error.");
ieee80211_queue_work(wl->hw, &wl->recovery_work);
wl12xx_queue_recovery_work(wl);
}
out:
......@@ -326,7 +326,7 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
struct cfg80211_sched_scan_request *req,
struct conn_scan_ch_params *channels,
u32 band, bool radar, bool passive,
int start)
int start, int max_channels)
{
struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
int i, j;
......@@ -334,7 +334,7 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
bool force_passive = !req->n_ssids;
for (i = 0, j = start;
i < req->n_channels && j < MAX_CHANNELS_ALL_BANDS;
i < req->n_channels && j < max_channels;
i++) {
flags = req->channels[i]->flags;
......@@ -380,46 +380,42 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
return j - start;
}
static int
static bool
wl1271_scan_sched_scan_channels(struct wl1271 *wl,
struct cfg80211_sched_scan_request *req,
struct wl1271_cmd_sched_scan_config *cfg)
{
int idx = 0;
cfg->passive[0] =
wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2,
IEEE80211_BAND_2GHZ,
false, true, idx);
idx += cfg->passive[0];
false, true, 0,
MAX_CHANNELS_2GHZ);
cfg->active[0] =
wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2,
IEEE80211_BAND_2GHZ,
false, false, idx);
/*
* 5GHz channels always start at position 14, not immediately
* after the last 2.4GHz channel
*/
idx = 14;
false, false,
cfg->passive[0],
MAX_CHANNELS_2GHZ);
cfg->passive[1] =
wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
IEEE80211_BAND_5GHZ,
false, true, idx);
idx += cfg->passive[1];
false, true, 0,
MAX_CHANNELS_5GHZ);
cfg->dfs =
wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
IEEE80211_BAND_5GHZ,
true, true, idx);
idx += cfg->dfs;
true, true,
cfg->passive[1],
MAX_CHANNELS_5GHZ);
cfg->active[1] =
wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
IEEE80211_BAND_5GHZ,
false, false, idx);
idx += cfg->active[1];
false, false,
cfg->passive[1] + cfg->dfs,
MAX_CHANNELS_5GHZ);
/* 802.11j channels are not supported yet */
cfg->passive[2] = 0;
cfg->active[2] = 0;
wl1271_debug(DEBUG_SCAN, " 2.4GHz: active %d passive %d",
cfg->active[0], cfg->passive[0]);
......@@ -427,7 +423,9 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
cfg->active[1], cfg->passive[1]);
wl1271_debug(DEBUG_SCAN, " DFS: %d", cfg->dfs);
return idx;
return cfg->passive[0] || cfg->active[0] ||
cfg->passive[1] || cfg->active[1] || cfg->dfs ||
cfg->passive[2] || cfg->active[2];
}
int wl1271_scan_sched_scan_config(struct wl1271 *wl,
......@@ -436,7 +434,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
{
struct wl1271_cmd_sched_scan_config *cfg = NULL;
struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
int i, total_channels, ret;
int i, ret;
bool force_passive = !req->n_ssids;
wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
......@@ -471,8 +469,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
cfg->ssid_len = 0;
}
total_channels = wl1271_scan_sched_scan_channels(wl, req, cfg);
if (total_channels == 0) {
if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) {
wl1271_error("scan channel list is empty");
ret = -EINVAL;
goto out;
......
......@@ -112,18 +112,13 @@ struct wl1271_cmd_trigger_scan_to {
__le32 timeout;
} __packed;
#define MAX_CHANNELS_ALL_BANDS 41
#define MAX_CHANNELS_2GHZ 14
#define MAX_CHANNELS_5GHZ 23
#define MAX_CHANNELS_4GHZ 4
#define SCAN_MAX_CYCLE_INTERVALS 16
#define SCAN_MAX_BANDS 3
enum {
SCAN_CHANNEL_TYPE_2GHZ_PASSIVE,
SCAN_CHANNEL_TYPE_2GHZ_ACTIVE,
SCAN_CHANNEL_TYPE_5GHZ_PASSIVE,
SCAN_CHANNEL_TYPE_5GHZ_ACTIVE,
SCAN_CHANNEL_TYPE_5GHZ_DFS,
};
enum {
SCAN_SSID_FILTER_ANY = 0,
SCAN_SSID_FILTER_SPECIFIC = 1,
......@@ -182,7 +177,9 @@ struct wl1271_cmd_sched_scan_config {
u8 padding[3];
struct conn_scan_ch_params channels[MAX_CHANNELS_ALL_BANDS];
struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ];
struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
} __packed;
......
......@@ -23,7 +23,6 @@
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/crc7.h>
#include <linux/vmalloc.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
......@@ -45,7 +44,7 @@
#define SDIO_DEVICE_ID_TI_WL1271 0x4076
#endif
static const struct sdio_device_id wl1271_devices[] = {
static const struct sdio_device_id wl1271_devices[] __devinitconst = {
{ SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) },
{}
};
......@@ -107,14 +106,6 @@ static void wl1271_sdio_enable_interrupts(struct wl1271 *wl)
enable_irq(wl->irq);
}
static void wl1271_sdio_reset(struct wl1271 *wl)
{
}
static void wl1271_sdio_init(struct wl1271 *wl)
{
}
static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed)
{
......@@ -170,10 +161,12 @@ static int wl1271_sdio_power_on(struct wl1271 *wl)
struct sdio_func *func = wl_to_func(wl);
int ret;
/* Make sure the card will not be powered off by runtime PM */
ret = pm_runtime_get_sync(&func->dev);
if (ret < 0)
goto out;
/* If enabled, tell runtime PM not to power off the card */
if (pm_runtime_enabled(&func->dev)) {
ret = pm_runtime_get_sync(&func->dev);
if (ret)
goto out;
}
/* Runtime PM might be disabled, so power up the card manually */
ret = mmc_power_restore_host(func->card->host);
......@@ -200,8 +193,11 @@ static int wl1271_sdio_power_off(struct wl1271 *wl)
if (ret < 0)
return ret;
/* Let runtime PM know the card is powered off */
return pm_runtime_put_sync(&func->dev);
/* If enabled, let runtime PM know the card is powered off */
if (pm_runtime_enabled(&func->dev))
ret = pm_runtime_put_sync(&func->dev);
return ret;
}
static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
......@@ -215,8 +211,6 @@ static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
static struct wl1271_if_operations sdio_ops = {
.read = wl1271_sdio_raw_read,
.write = wl1271_sdio_raw_write,
.reset = wl1271_sdio_reset,
.init = wl1271_sdio_init,
.power = wl1271_sdio_set_power,
.dev = wl1271_sdio_wl_to_dev,
.enable_irq = wl1271_sdio_enable_interrupts,
......@@ -278,17 +272,19 @@ static int __devinit wl1271_probe(struct sdio_func *func,
goto out_free;
}
enable_irq_wake(wl->irq);
device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1);
disable_irq(wl->irq);
ret = enable_irq_wake(wl->irq);
if (!ret) {
wl->irq_wake_enabled = true;
device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1);
/* if sdio can keep power while host is suspended, enable wow */
mmcflags = sdio_get_host_pm_caps(func);
wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags);
/* if sdio can keep power while host is suspended, enable wow */
mmcflags = sdio_get_host_pm_caps(func);
wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags);
if (mmcflags & MMC_PM_KEEP_POWER)
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
if (mmcflags & MMC_PM_KEEP_POWER)
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
}
disable_irq(wl->irq);
ret = wl1271_init_ieee80211(wl);
if (ret)
......@@ -303,8 +299,6 @@ static int __devinit wl1271_probe(struct sdio_func *func,
/* Tell PM core that we don't need the card to be powered now */
pm_runtime_put_noidle(&func->dev);
wl1271_notice("initialized");
return 0;
out_irq:
......@@ -324,8 +318,10 @@ static void __devexit wl1271_remove(struct sdio_func *func)
pm_runtime_get_noresume(&func->dev);
wl1271_unregister_hw(wl);
device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 0);
disable_irq_wake(wl->irq);
if (wl->irq_wake_enabled) {
device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 0);
disable_irq_wake(wl->irq);
}
free_irq(wl->irq, wl);
wl1271_free_hw(wl);
}
......@@ -402,23 +398,12 @@ static struct sdio_driver wl1271_sdio_driver = {
static int __init wl1271_init(void)
{
int ret;
ret = sdio_register_driver(&wl1271_sdio_driver);
if (ret < 0) {
wl1271_error("failed to register sdio driver: %d", ret);
goto out;
}
out:
return ret;
return sdio_register_driver(&wl1271_sdio_driver);
}
static void __exit wl1271_exit(void)
{
sdio_unregister_driver(&wl1271_sdio_driver);
wl1271_notice("unloaded");
}
module_init(wl1271_init);
......
......@@ -435,8 +435,6 @@ static int __devinit wl1271_probe(struct spi_device *spi)
if (ret)
goto out_irq;
wl1271_notice("initialized");
return 0;
out_irq:
......@@ -473,23 +471,12 @@ static struct spi_driver wl1271_spi_driver = {
static int __init wl1271_init(void)
{
int ret;
ret = spi_register_driver(&wl1271_spi_driver);
if (ret < 0) {
wl1271_error("failed to register spi driver: %d", ret);
goto out;
}
out:
return ret;
return spi_register_driver(&wl1271_spi_driver);
}
static void __exit wl1271_exit(void)
{
spi_unregister_driver(&wl1271_spi_driver);
wl1271_notice("unloaded");
}
module_init(wl1271_init);
......
......@@ -260,7 +260,7 @@ static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[])
{
wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover");
ieee80211_queue_work(wl->hw, &wl->recovery_work);
wl12xx_queue_recovery_work(wl);
return 0;
}
......
......@@ -562,17 +562,29 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
static bool wl1271_tx_is_data_present(struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
return ieee80211_is_data_present(hdr->frame_control);
}
void wl1271_tx_work_locked(struct wl1271 *wl)
{
struct sk_buff *skb;
u32 buf_offset = 0;
bool sent_packets = false;
bool had_data = false;
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
int ret;
if (unlikely(wl->state == WL1271_STATE_OFF))
return;
while ((skb = wl1271_skb_dequeue(wl))) {
if (wl1271_tx_is_data_present(skb))
had_data = true;
ret = wl1271_prepare_tx_frame(wl, skb, buf_offset);
if (ret == -EAGAIN) {
/*
......@@ -619,6 +631,19 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
wl1271_handle_tx_low_watermark(wl);
}
if (!is_ap && wl->conf.rx_streaming.interval && had_data &&
(wl->conf.rx_streaming.always ||
test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) {
u32 timeout = wl->conf.rx_streaming.duration;
/* enable rx streaming */
if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
ieee80211_queue_work(wl->hw,
&wl->rx_streaming_enable_work);
mod_timer(&wl->rx_streaming_timer,
jiffies + msecs_to_jiffies(timeout));
}
}
void wl1271_tx_work(struct work_struct *work)
......@@ -702,7 +727,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
/* return the packet to the stack */
skb_queue_tail(&wl->deferred_tx_queue, skb);
ieee80211_queue_work(wl->hw, &wl->netstack_work);
queue_work(wl->freezable_wq, &wl->netstack_work);
wl1271_free_tx_id(wl, result->id);
}
......@@ -757,7 +782,7 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
info = IEEE80211_SKB_CB(skb);
info->status.rates[0].idx = -1;
info->status.rates[0].count = 0;
ieee80211_tx_status(wl->hw, skb);
ieee80211_tx_status_ni(wl->hw, skb);
total++;
}
}
......@@ -795,7 +820,7 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
info = IEEE80211_SKB_CB(skb);
info->status.rates[0].idx = -1;
info->status.rates[0].count = 0;
ieee80211_tx_status(wl->hw, skb);
ieee80211_tx_status_ni(wl->hw, skb);
}
}
}
......@@ -838,7 +863,7 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
info->status.rates[0].idx = -1;
info->status.rates[0].count = 0;
ieee80211_tx_status(wl->hw, skb);
ieee80211_tx_status_ni(wl->hw, skb);
}
}
}
......
......@@ -226,6 +226,8 @@ enum {
#define FW_VER_MINOR_1_SPARE_STA_MIN 58
#define FW_VER_MINOR_1_SPARE_AP_MIN 47
#define FW_VER_MINOR_FWLOG_STA_MIN 70
struct wl1271_chip {
u32 id;
char fw_ver_str[ETHTOOL_BUSINFO_LEN];
......@@ -284,8 +286,7 @@ struct wl1271_fw_sta_status {
u8 tx_total;
u8 reserved1;
__le16 reserved2;
/* Total structure size is 68 bytes */
u32 padding;
__le32 log_start_addr;
} __packed;
struct wl1271_fw_full_status {
......@@ -359,6 +360,9 @@ enum wl12xx_flags {
WL1271_FLAG_DUMMY_PACKET_PENDING,
WL1271_FLAG_SUSPENDED,
WL1271_FLAG_PENDING_WORK,
WL1271_FLAG_SOFT_GEMINI,
WL1271_FLAG_RX_STREAMING_STARTED,
WL1271_FLAG_RECOVERY_IN_PROGRESS,
};
struct wl1271_link {
......@@ -443,6 +447,7 @@ struct wl1271 {
struct sk_buff_head deferred_tx_queue;
struct work_struct tx_work;
struct workqueue_struct *freezable_wq;
/* Pending TX frames */
unsigned long tx_frames_map[BITS_TO_LONGS(ACX_TX_DESCRIPTORS)];
......@@ -468,6 +473,15 @@ struct wl1271 {
/* Network stack work */
struct work_struct netstack_work;
/* FW log buffer */
u8 *fwlog;
/* Number of valid bytes in the FW log buffer */
ssize_t fwlog_size;
/* Sysfs FW log entry readers wait queue */
wait_queue_head_t fwlog_waitq;
/* Hardware recovery work */
struct work_struct recovery_work;
......@@ -508,6 +522,11 @@ struct wl1271 {
/* Default key (for WEP) */
u32 default_key;
/* Rx Streaming */
struct work_struct rx_streaming_enable_work;
struct work_struct rx_streaming_disable_work;
struct timer_list rx_streaming_timer;
unsigned int filters;
unsigned int rx_config;
unsigned int rx_filter;
......@@ -573,6 +592,7 @@ struct wl1271 {
* (currently, only "ANY" trigger is supported)
*/
bool wow_enabled;
bool irq_wake_enabled;
/*
* AP-mode - links indexed by HLID. The global and broadcast links
......@@ -602,6 +622,9 @@ struct wl1271_station {
int wl1271_plt_start(struct wl1271 *wl);
int wl1271_plt_stop(struct wl1271 *wl);
int wl1271_recalc_rx_streaming(struct wl1271 *wl);
void wl12xx_queue_recovery_work(struct wl1271 *wl);
size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
......@@ -637,4 +660,15 @@ int wl1271_plt_stop(struct wl1271 *wl);
/* WL128X requires aggregated packets to be aligned to the SDIO block size */
#define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2)
/*
* WL127X AP mode requires Low Power DRPw (LPD) enable to reduce power
* consumption
*/
#define WL12XX_QUIRK_LPD_MODE BIT(3)
/* Older firmwares did not implement the FW logger over bus feature */
#define WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4)
#define WL12XX_HW_BLOCK_SIZE 256
#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