Skip to content

Commit

Permalink
Merge branch 'for-linville' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/luca/wl12xx
  • Loading branch information
John W. Linville committed Jul 6, 2011
2 parents 115f945 + 95dac04 commit 333c0db
Show file tree
Hide file tree
Showing 24 changed files with 1,176 additions and 244 deletions.
2 changes: 1 addition & 1 deletion drivers/net/wireless/wl12xx/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
49 changes: 48 additions & 1 deletion drivers/net/wireless/wl12xx/acx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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;
Expand Down
16 changes: 16 additions & 0 deletions drivers/net/wireless/wl12xx/acx.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down
33 changes: 33 additions & 0 deletions drivers/net/wireless/wl12xx/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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]);
Expand Down
94 changes: 91 additions & 3 deletions drivers/net/wireless/wl12xx/cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
62 changes: 62 additions & 0 deletions drivers/net/wireless/wl12xx/cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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*/
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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__ */
Loading

0 comments on commit 333c0db

Please sign in to comment.