mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-27 08:05:27 +08:00
Merge branch 'wl12xx-next' into for-linville
This commit is contained in:
commit
bf34e68352
@ -8,6 +8,7 @@ menuconfig WL_TI
|
||||
if WL_TI
|
||||
source "drivers/net/wireless/ti/wl1251/Kconfig"
|
||||
source "drivers/net/wireless/ti/wl12xx/Kconfig"
|
||||
source "drivers/net/wireless/ti/wl18xx/Kconfig"
|
||||
|
||||
# keep last for automatic dependencies
|
||||
source "drivers/net/wireless/ti/wlcore/Kconfig"
|
||||
|
@ -2,3 +2,4 @@ obj-$(CONFIG_WLCORE) += wlcore/
|
||||
obj-$(CONFIG_WL12XX) += wl12xx/
|
||||
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wlcore/
|
||||
obj-$(CONFIG_WL1251) += wl1251/
|
||||
obj-$(CONFIG_WL18XX) += wl18xx/
|
||||
|
@ -1,3 +1,3 @@
|
||||
wl12xx-objs = main.o cmd.o acx.o
|
||||
wl12xx-objs = main.o cmd.o acx.o debugfs.o
|
||||
|
||||
obj-$(CONFIG_WL12XX) += wl12xx.o
|
||||
|
@ -24,6 +24,21 @@
|
||||
#define __WL12XX_ACX_H__
|
||||
|
||||
#include "../wlcore/wlcore.h"
|
||||
#include "../wlcore/acx.h"
|
||||
|
||||
#define WL12XX_ACX_ALL_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \
|
||||
WL1271_ACX_INTR_INIT_COMPLETE | \
|
||||
WL1271_ACX_INTR_EVENT_A | \
|
||||
WL1271_ACX_INTR_EVENT_B | \
|
||||
WL1271_ACX_INTR_CMD_COMPLETE | \
|
||||
WL1271_ACX_INTR_HW_AVAILABLE | \
|
||||
WL1271_ACX_INTR_DATA)
|
||||
|
||||
#define WL12XX_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \
|
||||
WL1271_ACX_INTR_EVENT_A | \
|
||||
WL1271_ACX_INTR_EVENT_B | \
|
||||
WL1271_ACX_INTR_HW_AVAILABLE | \
|
||||
WL1271_ACX_INTR_DATA)
|
||||
|
||||
struct wl1271_acx_host_config_bitmap {
|
||||
struct acx_header header;
|
||||
@ -31,6 +46,228 @@ struct wl1271_acx_host_config_bitmap {
|
||||
__le32 host_cfg_bitmap;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_tx_statistics {
|
||||
__le32 internal_desc_overflow;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_rx_statistics {
|
||||
__le32 out_of_mem;
|
||||
__le32 hdr_overflow;
|
||||
__le32 hw_stuck;
|
||||
__le32 dropped;
|
||||
__le32 fcs_err;
|
||||
__le32 xfr_hint_trig;
|
||||
__le32 path_reset;
|
||||
__le32 reset_counter;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_dma_statistics {
|
||||
__le32 rx_requested;
|
||||
__le32 rx_errors;
|
||||
__le32 tx_requested;
|
||||
__le32 tx_errors;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_isr_statistics {
|
||||
/* host command complete */
|
||||
__le32 cmd_cmplt;
|
||||
|
||||
/* fiqisr() */
|
||||
__le32 fiqs;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_RX_HEADER) */
|
||||
__le32 rx_headers;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_RX_CMPLT) */
|
||||
__le32 rx_completes;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */
|
||||
__le32 rx_mem_overflow;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_S_RX_RDY) */
|
||||
__le32 rx_rdys;
|
||||
|
||||
/* irqisr() */
|
||||
__le32 irqs;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_TX_PROC) */
|
||||
__le32 tx_procs;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */
|
||||
__le32 decrypt_done;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_DMA0) */
|
||||
__le32 dma0_done;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_DMA1) */
|
||||
__le32 dma1_done;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */
|
||||
__le32 tx_exch_complete;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_COMMAND) */
|
||||
__le32 commands;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_RX_PROC) */
|
||||
__le32 rx_procs;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_PM_802) */
|
||||
__le32 hw_pm_mode_changes;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */
|
||||
__le32 host_acknowledges;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_PM_PCI) */
|
||||
__le32 pci_pm;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */
|
||||
__le32 wakeups;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
|
||||
__le32 low_rssi;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_wep_statistics {
|
||||
/* WEP address keys configured */
|
||||
__le32 addr_key_count;
|
||||
|
||||
/* default keys configured */
|
||||
__le32 default_key_count;
|
||||
|
||||
__le32 reserved;
|
||||
|
||||
/* number of times that WEP key not found on lookup */
|
||||
__le32 key_not_found;
|
||||
|
||||
/* number of times that WEP key decryption failed */
|
||||
__le32 decrypt_fail;
|
||||
|
||||
/* WEP packets decrypted */
|
||||
__le32 packets;
|
||||
|
||||
/* WEP decrypt interrupts */
|
||||
__le32 interrupt;
|
||||
} __packed;
|
||||
|
||||
#define ACX_MISSED_BEACONS_SPREAD 10
|
||||
|
||||
struct wl12xx_acx_pwr_statistics {
|
||||
/* the amount of enters into power save mode (both PD & ELP) */
|
||||
__le32 ps_enter;
|
||||
|
||||
/* the amount of enters into ELP mode */
|
||||
__le32 elp_enter;
|
||||
|
||||
/* the amount of missing beacon interrupts to the host */
|
||||
__le32 missing_bcns;
|
||||
|
||||
/* the amount of wake on host-access times */
|
||||
__le32 wake_on_host;
|
||||
|
||||
/* the amount of wake on timer-expire */
|
||||
__le32 wake_on_timer_exp;
|
||||
|
||||
/* the number of packets that were transmitted with PS bit set */
|
||||
__le32 tx_with_ps;
|
||||
|
||||
/* the number of packets that were transmitted with PS bit clear */
|
||||
__le32 tx_without_ps;
|
||||
|
||||
/* the number of received beacons */
|
||||
__le32 rcvd_beacons;
|
||||
|
||||
/* the number of entering into PowerOn (power save off) */
|
||||
__le32 power_save_off;
|
||||
|
||||
/* the number of entries into power save mode */
|
||||
__le16 enable_ps;
|
||||
|
||||
/*
|
||||
* the number of exits from power save, not including failed PS
|
||||
* transitions
|
||||
*/
|
||||
__le16 disable_ps;
|
||||
|
||||
/*
|
||||
* the number of times the TSF counter was adjusted because
|
||||
* of drift
|
||||
*/
|
||||
__le32 fix_tsf_ps;
|
||||
|
||||
/* Gives statistics about the spread continuous missed beacons.
|
||||
* The 16 LSB are dedicated for the PS mode.
|
||||
* The 16 MSB are dedicated for the PS mode.
|
||||
* cont_miss_bcns_spread[0] - single missed beacon.
|
||||
* cont_miss_bcns_spread[1] - two continuous missed beacons.
|
||||
* cont_miss_bcns_spread[2] - three continuous missed beacons.
|
||||
* ...
|
||||
* cont_miss_bcns_spread[9] - ten and more continuous missed beacons.
|
||||
*/
|
||||
__le32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD];
|
||||
|
||||
/* the number of beacons in awake mode */
|
||||
__le32 rcvd_awake_beacons;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_mic_statistics {
|
||||
__le32 rx_pkts;
|
||||
__le32 calc_failure;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_aes_statistics {
|
||||
__le32 encrypt_fail;
|
||||
__le32 decrypt_fail;
|
||||
__le32 encrypt_packets;
|
||||
__le32 decrypt_packets;
|
||||
__le32 encrypt_interrupt;
|
||||
__le32 decrypt_interrupt;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_event_statistics {
|
||||
__le32 heart_beat;
|
||||
__le32 calibration;
|
||||
__le32 rx_mismatch;
|
||||
__le32 rx_mem_empty;
|
||||
__le32 rx_pool;
|
||||
__le32 oom_late;
|
||||
__le32 phy_transmit_error;
|
||||
__le32 tx_stuck;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_ps_statistics {
|
||||
__le32 pspoll_timeouts;
|
||||
__le32 upsd_timeouts;
|
||||
__le32 upsd_max_sptime;
|
||||
__le32 upsd_max_apturn;
|
||||
__le32 pspoll_max_apturn;
|
||||
__le32 pspoll_utilization;
|
||||
__le32 upsd_utilization;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_rxpipe_statistics {
|
||||
__le32 rx_prep_beacon_drop;
|
||||
__le32 descr_host_int_trig_rx_data;
|
||||
__le32 beacon_buffer_thres_host_int_trig_rx_data;
|
||||
__le32 missed_beacon_host_int_trig_rx_data;
|
||||
__le32 tx_xfr_host_int_trig_rx_data;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_statistics {
|
||||
struct acx_header header;
|
||||
|
||||
struct wl12xx_acx_tx_statistics tx;
|
||||
struct wl12xx_acx_rx_statistics rx;
|
||||
struct wl12xx_acx_dma_statistics dma;
|
||||
struct wl12xx_acx_isr_statistics isr;
|
||||
struct wl12xx_acx_wep_statistics wep;
|
||||
struct wl12xx_acx_pwr_statistics pwr;
|
||||
struct wl12xx_acx_aes_statistics aes;
|
||||
struct wl12xx_acx_mic_statistics mic;
|
||||
struct wl12xx_acx_event_statistics event;
|
||||
struct wl12xx_acx_ps_statistics ps;
|
||||
struct wl12xx_acx_rxpipe_statistics rxpipe;
|
||||
} __packed;
|
||||
|
||||
int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap);
|
||||
|
||||
#endif /* __WL12XX_ACX_H__ */
|
||||
|
@ -65,6 +65,7 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
|
||||
struct wl1271_general_parms_cmd *gen_parms;
|
||||
struct wl1271_ini_general_params *gp =
|
||||
&((struct wl1271_nvs_file *)wl->nvs)->general_params;
|
||||
struct wl12xx_priv *priv = wl->priv;
|
||||
bool answer = false;
|
||||
int ret;
|
||||
|
||||
@ -88,7 +89,7 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
|
||||
answer = true;
|
||||
|
||||
/* Override the REF CLK from the NVS with the one from platform data */
|
||||
gen_parms->general_params.ref_clock = wl->ref_clock;
|
||||
gen_parms->general_params.ref_clock = priv->ref_clock;
|
||||
|
||||
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
|
||||
if (ret < 0) {
|
||||
@ -118,6 +119,7 @@ int wl128x_cmd_general_parms(struct wl1271 *wl)
|
||||
struct wl128x_general_parms_cmd *gen_parms;
|
||||
struct wl128x_ini_general_params *gp =
|
||||
&((struct wl128x_nvs_file *)wl->nvs)->general_params;
|
||||
struct wl12xx_priv *priv = wl->priv;
|
||||
bool answer = false;
|
||||
int ret;
|
||||
|
||||
@ -141,8 +143,8 @@ int wl128x_cmd_general_parms(struct wl1271 *wl)
|
||||
answer = true;
|
||||
|
||||
/* Replace REF and TCXO CLKs with the ones from platform data */
|
||||
gen_parms->general_params.ref_clock = wl->ref_clock;
|
||||
gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock;
|
||||
gen_parms->general_params.ref_clock = priv->ref_clock;
|
||||
gen_parms->general_params.tcxo_ref_clock = priv->tcxo_clock;
|
||||
|
||||
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
|
||||
if (ret < 0) {
|
||||
|
243
drivers/net/wireless/ti/wl12xx/debugfs.c
Normal file
243
drivers/net/wireless/ti/wl12xx/debugfs.c
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* This file is part of wl12xx
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Copyright (C) 2011-2012 Texas Instruments
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../wlcore/debugfs.h"
|
||||
#include "../wlcore/wlcore.h"
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "acx.h"
|
||||
#include "debugfs.h"
|
||||
|
||||
#define WL12XX_DEBUGFS_FWSTATS_FILE(a, b, c) \
|
||||
DEBUGFS_FWSTATS_FILE(a, b, c, wl12xx_acx_statistics)
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rx, out_of_mem, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rx, hw_stuck, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rx, dropped, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rx, fcs_err, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rx, path_reset, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rx, reset_counter, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(dma, rx_requested, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(dma, rx_errors, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(dma, tx_requested, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(dma, tx_errors, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, fiqs, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, rx_headers, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, rx_rdys, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, irqs, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, tx_procs, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, decrypt_done, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, dma0_done, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, dma1_done, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, commands, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, rx_procs, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, pci_pm, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, wakeups, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, low_rssi, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(wep, addr_key_count, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(wep, default_key_count, "%u");
|
||||
/* skipping wep.reserved */
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(wep, key_not_found, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(wep, packets, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(wep, interrupt, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, ps_enter, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, elp_enter, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, power_save_off, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, enable_ps, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, disable_ps, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, "%u");
|
||||
/* skipping cont_miss_bcns_spread for now */
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(mic, rx_pkts, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(mic, calc_failure, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(event, heart_beat, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(event, calibration, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(event, rx_mismatch, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(event, rx_pool, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(event, oom_late, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(event, tx_stuck, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data,
|
||||
"%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, "%u");
|
||||
|
||||
int wl12xx_debugfs_add_files(struct wl1271 *wl,
|
||||
struct dentry *rootdir)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dentry *entry, *stats, *moddir;
|
||||
|
||||
moddir = debugfs_create_dir(KBUILD_MODNAME, rootdir);
|
||||
if (!moddir || IS_ERR(moddir)) {
|
||||
entry = moddir;
|
||||
goto err;
|
||||
}
|
||||
|
||||
stats = debugfs_create_dir("fw_stats", moddir);
|
||||
if (!stats || IS_ERR(stats)) {
|
||||
entry = stats;
|
||||
goto err;
|
||||
}
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(rx, out_of_mem);
|
||||
DEBUGFS_FWSTATS_ADD(rx, hdr_overflow);
|
||||
DEBUGFS_FWSTATS_ADD(rx, hw_stuck);
|
||||
DEBUGFS_FWSTATS_ADD(rx, dropped);
|
||||
DEBUGFS_FWSTATS_ADD(rx, fcs_err);
|
||||
DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig);
|
||||
DEBUGFS_FWSTATS_ADD(rx, path_reset);
|
||||
DEBUGFS_FWSTATS_ADD(rx, reset_counter);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(dma, rx_requested);
|
||||
DEBUGFS_FWSTATS_ADD(dma, rx_errors);
|
||||
DEBUGFS_FWSTATS_ADD(dma, tx_requested);
|
||||
DEBUGFS_FWSTATS_ADD(dma, tx_errors);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt);
|
||||
DEBUGFS_FWSTATS_ADD(isr, fiqs);
|
||||
DEBUGFS_FWSTATS_ADD(isr, rx_headers);
|
||||
DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow);
|
||||
DEBUGFS_FWSTATS_ADD(isr, rx_rdys);
|
||||
DEBUGFS_FWSTATS_ADD(isr, irqs);
|
||||
DEBUGFS_FWSTATS_ADD(isr, tx_procs);
|
||||
DEBUGFS_FWSTATS_ADD(isr, decrypt_done);
|
||||
DEBUGFS_FWSTATS_ADD(isr, dma0_done);
|
||||
DEBUGFS_FWSTATS_ADD(isr, dma1_done);
|
||||
DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete);
|
||||
DEBUGFS_FWSTATS_ADD(isr, commands);
|
||||
DEBUGFS_FWSTATS_ADD(isr, rx_procs);
|
||||
DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes);
|
||||
DEBUGFS_FWSTATS_ADD(isr, host_acknowledges);
|
||||
DEBUGFS_FWSTATS_ADD(isr, pci_pm);
|
||||
DEBUGFS_FWSTATS_ADD(isr, wakeups);
|
||||
DEBUGFS_FWSTATS_ADD(isr, low_rssi);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(wep, addr_key_count);
|
||||
DEBUGFS_FWSTATS_ADD(wep, default_key_count);
|
||||
/* skipping wep.reserved */
|
||||
DEBUGFS_FWSTATS_ADD(wep, key_not_found);
|
||||
DEBUGFS_FWSTATS_ADD(wep, decrypt_fail);
|
||||
DEBUGFS_FWSTATS_ADD(wep, packets);
|
||||
DEBUGFS_FWSTATS_ADD(wep, interrupt);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(pwr, ps_enter);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, elp_enter);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, missing_bcns);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, wake_on_host);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, power_save_off);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, enable_ps);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, disable_ps);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps);
|
||||
/* skipping cont_miss_bcns_spread for now */
|
||||
DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(mic, rx_pkts);
|
||||
DEBUGFS_FWSTATS_ADD(mic, calc_failure);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(aes, encrypt_fail);
|
||||
DEBUGFS_FWSTATS_ADD(aes, decrypt_fail);
|
||||
DEBUGFS_FWSTATS_ADD(aes, encrypt_packets);
|
||||
DEBUGFS_FWSTATS_ADD(aes, decrypt_packets);
|
||||
DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt);
|
||||
DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(event, heart_beat);
|
||||
DEBUGFS_FWSTATS_ADD(event, calibration);
|
||||
DEBUGFS_FWSTATS_ADD(event, rx_mismatch);
|
||||
DEBUGFS_FWSTATS_ADD(event, rx_mem_empty);
|
||||
DEBUGFS_FWSTATS_ADD(event, rx_pool);
|
||||
DEBUGFS_FWSTATS_ADD(event, oom_late);
|
||||
DEBUGFS_FWSTATS_ADD(event, phy_transmit_error);
|
||||
DEBUGFS_FWSTATS_ADD(event, tx_stuck);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts);
|
||||
DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts);
|
||||
DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime);
|
||||
DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn);
|
||||
DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn);
|
||||
DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization);
|
||||
DEBUGFS_FWSTATS_ADD(ps, upsd_utilization);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (IS_ERR(entry))
|
||||
ret = PTR_ERR(entry);
|
||||
else
|
||||
ret = -ENOMEM;
|
||||
|
||||
return ret;
|
||||
}
|
28
drivers/net/wireless/ti/wl12xx/debugfs.h
Normal file
28
drivers/net/wireless/ti/wl12xx/debugfs.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of wl12xx
|
||||
*
|
||||
* Copyright (C) 2012 Texas Instruments. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WL12XX_DEBUGFS_H__
|
||||
#define __WL12XX_DEBUGFS_H__
|
||||
|
||||
int wl12xx_debugfs_add_files(struct wl1271 *wl,
|
||||
struct dentry *rootdir);
|
||||
|
||||
#endif /* __WL12XX_DEBUGFS_H__ */
|
@ -39,6 +39,10 @@
|
||||
#include "reg.h"
|
||||
#include "cmd.h"
|
||||
#include "acx.h"
|
||||
#include "debugfs.h"
|
||||
|
||||
static char *fref_param;
|
||||
static char *tcxo_param;
|
||||
|
||||
static struct wlcore_conf wl12xx_conf = {
|
||||
.sg = {
|
||||
@ -212,7 +216,7 @@ static struct wlcore_conf wl12xx_conf = {
|
||||
.suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM,
|
||||
.suspend_listen_interval = 3,
|
||||
.bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
|
||||
.bcn_filt_ie_count = 2,
|
||||
.bcn_filt_ie_count = 3,
|
||||
.bcn_filt_ie = {
|
||||
[0] = {
|
||||
.ie = WLAN_EID_CHANNEL_SWITCH,
|
||||
@ -222,9 +226,13 @@ static struct wlcore_conf wl12xx_conf = {
|
||||
.ie = WLAN_EID_HT_OPERATION,
|
||||
.rule = CONF_BCN_RULE_PASS_ON_CHANGE,
|
||||
},
|
||||
[2] = {
|
||||
.ie = WLAN_EID_ERP_INFO,
|
||||
.rule = CONF_BCN_RULE_PASS_ON_CHANGE,
|
||||
},
|
||||
},
|
||||
.synch_fail_thold = 10,
|
||||
.bss_lose_timeout = 100,
|
||||
.synch_fail_thold = 12,
|
||||
.bss_lose_timeout = 400,
|
||||
.beacon_rx_timeout = 10000,
|
||||
.broadcast_timeout = 20000,
|
||||
.rx_broadcast_in_ps = 1,
|
||||
@ -234,7 +242,7 @@ static struct wlcore_conf wl12xx_conf = {
|
||||
.psm_entry_retries = 8,
|
||||
.psm_exit_retries = 16,
|
||||
.psm_entry_nullfunc_retries = 3,
|
||||
.dynamic_ps_timeout = 40,
|
||||
.dynamic_ps_timeout = 200,
|
||||
.forced_ps = false,
|
||||
.keep_alive_interval = 55000,
|
||||
.max_listen_interval = 20,
|
||||
@ -245,7 +253,7 @@ static struct wlcore_conf wl12xx_conf = {
|
||||
},
|
||||
.pm_config = {
|
||||
.host_clk_settling_time = 5000,
|
||||
.host_fast_wakeup_support = false
|
||||
.host_fast_wakeup_support = CONF_FAST_WAKEUP_DISABLE,
|
||||
},
|
||||
.roam_trigger = {
|
||||
.trigger_pacing = 1,
|
||||
@ -305,8 +313,8 @@ static struct wlcore_conf wl12xx_conf = {
|
||||
.swallow_period = 5,
|
||||
.n_divider_fref_set_1 = 0xff, /* default */
|
||||
.n_divider_fref_set_2 = 12,
|
||||
.m_divider_fref_set_1 = 148,
|
||||
.m_divider_fref_set_2 = 0xffff, /* default */
|
||||
.m_divider_fref_set_1 = 0xffff,
|
||||
.m_divider_fref_set_2 = 148, /* default */
|
||||
.coex_pll_stabilization_time = 0xffffffff, /* default */
|
||||
.ldo_stabilization_time = 0xffff, /* default */
|
||||
.fm_disturbed_band_margin = 0xff, /* default */
|
||||
@ -593,7 +601,7 @@ static void wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
|
||||
{
|
||||
if (wl->chip.id != CHIP_ID_1283_PG20) {
|
||||
struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
|
||||
struct wl1271_rx_mem_pool_addr rx_mem_addr;
|
||||
struct wl127x_rx_mem_pool_addr rx_mem_addr;
|
||||
|
||||
/*
|
||||
* Choose the block we want to read
|
||||
@ -621,10 +629,8 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
|
||||
wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
|
||||
wl->chip.id);
|
||||
|
||||
/* clear the alignment quirk, since we don't support it */
|
||||
wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
|
||||
|
||||
wl->quirks |= WLCORE_QUIRK_LEGACY_NVS;
|
||||
wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
|
||||
WLCORE_QUIRK_TKIP_HEADER_SPACE;
|
||||
wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
|
||||
wl->mr_fw_name = WL127X_FW_NAME_MULTI;
|
||||
memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x,
|
||||
@ -639,10 +645,8 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
|
||||
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
|
||||
wl->chip.id);
|
||||
|
||||
/* clear the alignment quirk, since we don't support it */
|
||||
wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
|
||||
|
||||
wl->quirks |= WLCORE_QUIRK_LEGACY_NVS;
|
||||
wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
|
||||
WLCORE_QUIRK_TKIP_HEADER_SPACE;
|
||||
wl->plt_fw_name = WL127X_PLT_FW_NAME;
|
||||
wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
|
||||
wl->mr_fw_name = WL127X_FW_NAME_MULTI;
|
||||
@ -660,6 +664,11 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
|
||||
wl->plt_fw_name = WL128X_PLT_FW_NAME;
|
||||
wl->sr_fw_name = WL128X_FW_NAME_SINGLE;
|
||||
wl->mr_fw_name = WL128X_FW_NAME_MULTI;
|
||||
|
||||
/* wl128x requires TX blocksize alignment */
|
||||
wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
|
||||
WLCORE_QUIRK_TKIP_HEADER_SPACE;
|
||||
|
||||
break;
|
||||
case CHIP_ID_1283_PG10:
|
||||
default:
|
||||
@ -773,6 +782,7 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
|
||||
u16 spare_reg;
|
||||
u16 pll_config;
|
||||
u8 input_freq;
|
||||
struct wl12xx_priv *priv = wl->priv;
|
||||
|
||||
/* Mask bits [3:1] in the sys_clk_cfg register */
|
||||
spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG);
|
||||
@ -782,8 +792,8 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
|
||||
wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg);
|
||||
|
||||
/* Handle special cases of the TCXO clock */
|
||||
if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 ||
|
||||
wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6)
|
||||
if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_8 ||
|
||||
priv->tcxo_clock == WL12XX_TCXOCLOCK_33_6)
|
||||
return wl128x_manually_configure_mcs_pll(wl);
|
||||
|
||||
/* Set the input frequency according to the selected clock source */
|
||||
@ -808,11 +818,12 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
|
||||
*/
|
||||
static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
|
||||
{
|
||||
struct wl12xx_priv *priv = wl->priv;
|
||||
u16 sys_clk_cfg;
|
||||
|
||||
/* For XTAL-only modes, FREF will be used after switching from TCXO */
|
||||
if (wl->ref_clock == WL12XX_REFCLOCK_26_XTAL ||
|
||||
wl->ref_clock == WL12XX_REFCLOCK_38_XTAL) {
|
||||
if (priv->ref_clock == WL12XX_REFCLOCK_26_XTAL ||
|
||||
priv->ref_clock == WL12XX_REFCLOCK_38_XTAL) {
|
||||
if (!wl128x_switch_tcxo_to_fref(wl))
|
||||
return -EINVAL;
|
||||
goto fref_clk;
|
||||
@ -826,8 +837,8 @@ static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
|
||||
goto fref_clk;
|
||||
|
||||
/* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */
|
||||
if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_368 ||
|
||||
wl->tcxo_clock == WL12XX_TCXOCLOCK_32_736) {
|
||||
if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_368 ||
|
||||
priv->tcxo_clock == WL12XX_TCXOCLOCK_32_736) {
|
||||
if (!wl128x_switch_tcxo_to_fref(wl))
|
||||
return -EINVAL;
|
||||
goto fref_clk;
|
||||
@ -836,14 +847,14 @@ static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
|
||||
/* TCXO clock is selected */
|
||||
if (!wl128x_is_tcxo_valid(wl))
|
||||
return -EINVAL;
|
||||
*selected_clock = wl->tcxo_clock;
|
||||
*selected_clock = priv->tcxo_clock;
|
||||
goto config_mcs_pll;
|
||||
|
||||
fref_clk:
|
||||
/* FREF clock is selected */
|
||||
if (!wl128x_is_fref_valid(wl))
|
||||
return -EINVAL;
|
||||
*selected_clock = wl->ref_clock;
|
||||
*selected_clock = priv->ref_clock;
|
||||
|
||||
config_mcs_pll:
|
||||
return wl128x_configure_mcs_pll(wl, *selected_clock);
|
||||
@ -851,25 +862,27 @@ config_mcs_pll:
|
||||
|
||||
static int wl127x_boot_clk(struct wl1271 *wl)
|
||||
{
|
||||
struct wl12xx_priv *priv = wl->priv;
|
||||
u32 pause;
|
||||
u32 clk;
|
||||
|
||||
if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3)
|
||||
wl->quirks |= WLCORE_QUIRK_END_OF_TRANSACTION;
|
||||
|
||||
if (wl->ref_clock == CONF_REF_CLK_19_2_E ||
|
||||
wl->ref_clock == CONF_REF_CLK_38_4_E ||
|
||||
wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL)
|
||||
if (priv->ref_clock == CONF_REF_CLK_19_2_E ||
|
||||
priv->ref_clock == CONF_REF_CLK_38_4_E ||
|
||||
priv->ref_clock == CONF_REF_CLK_38_4_M_XTAL)
|
||||
/* ref clk: 19.2/38.4/38.4-XTAL */
|
||||
clk = 0x3;
|
||||
else if (wl->ref_clock == CONF_REF_CLK_26_E ||
|
||||
wl->ref_clock == CONF_REF_CLK_52_E)
|
||||
else if (priv->ref_clock == CONF_REF_CLK_26_E ||
|
||||
priv->ref_clock == CONF_REF_CLK_26_M_XTAL ||
|
||||
priv->ref_clock == CONF_REF_CLK_52_E)
|
||||
/* ref clk: 26/52 */
|
||||
clk = 0x5;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (wl->ref_clock != CONF_REF_CLK_19_2_E) {
|
||||
if (priv->ref_clock != CONF_REF_CLK_19_2_E) {
|
||||
u16 val;
|
||||
/* Set clock type (open drain) */
|
||||
val = wl12xx_top_reg_read(wl, OCP_REG_CLK_TYPE);
|
||||
@ -939,6 +952,7 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
|
||||
|
||||
static int wl12xx_pre_boot(struct wl1271 *wl)
|
||||
{
|
||||
struct wl12xx_priv *priv = wl->priv;
|
||||
int ret = 0;
|
||||
u32 clk;
|
||||
int selected_clock = -1;
|
||||
@ -970,7 +984,7 @@ static int wl12xx_pre_boot(struct wl1271 *wl)
|
||||
if (wl->chip.id == CHIP_ID_1283_PG20)
|
||||
clk |= ((selected_clock & 0x3) << 1) << 4;
|
||||
else
|
||||
clk |= (wl->ref_clock << 1) << 4;
|
||||
clk |= (priv->ref_clock << 1) << 4;
|
||||
|
||||
wl1271_write32(wl, WL12XX_DRPW_SCRATCH_START, clk);
|
||||
|
||||
@ -989,7 +1003,7 @@ out:
|
||||
|
||||
static void wl12xx_pre_upload(struct wl1271 *wl)
|
||||
{
|
||||
u32 tmp;
|
||||
u32 tmp, polarity;
|
||||
|
||||
/* write firmware's last address (ie. it's length) to
|
||||
* ACX_EEPROMLESS_IND_REG */
|
||||
@ -1009,23 +1023,23 @@ static void wl12xx_pre_upload(struct wl1271 *wl)
|
||||
|
||||
if (wl->chip.id == CHIP_ID_1283_PG20)
|
||||
wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA);
|
||||
}
|
||||
|
||||
static void wl12xx_enable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
u32 polarity;
|
||||
|
||||
/* polarity must be set before the firmware is loaded */
|
||||
polarity = wl12xx_top_reg_read(wl, OCP_REG_POLARITY);
|
||||
|
||||
/* We use HIGH polarity, so unset the LOW bit */
|
||||
polarity &= ~POLARITY_LOW;
|
||||
wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity);
|
||||
|
||||
wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_ALL_EVENTS_VECTOR);
|
||||
}
|
||||
|
||||
static void wl12xx_enable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL12XX_ACX_ALL_EVENTS_VECTOR);
|
||||
|
||||
wlcore_enable_interrupts(wl);
|
||||
wlcore_write_reg(wl, REG_INTERRUPT_MASK,
|
||||
WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
|
||||
WL1271_ACX_INTR_ALL & ~(WL12XX_INTR_MASK));
|
||||
|
||||
wl1271_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL);
|
||||
}
|
||||
@ -1149,7 +1163,8 @@ static u32 wl12xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data,
|
||||
|
||||
static void wl12xx_tx_delayed_compl(struct wl1271 *wl)
|
||||
{
|
||||
if (wl->fw_status->tx_results_counter == (wl->tx_results_count & 0xff))
|
||||
if (wl->fw_status_1->tx_results_counter ==
|
||||
(wl->tx_results_count & 0xff))
|
||||
return;
|
||||
|
||||
wl1271_tx_complete(wl);
|
||||
@ -1288,10 +1303,90 @@ static void wl12xx_get_mac(struct wl1271 *wl)
|
||||
wl12xx_get_fuse_mac(wl);
|
||||
}
|
||||
|
||||
static void wl12xx_set_tx_desc_csum(struct wl1271 *wl,
|
||||
struct wl1271_tx_hw_descr *desc,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
desc->wl12xx_reserved = 0;
|
||||
}
|
||||
|
||||
static int wl12xx_plt_init(struct wl1271 *wl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl->ops->boot(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl->ops->hw_init(wl);
|
||||
if (ret < 0)
|
||||
goto out_irq_disable;
|
||||
|
||||
ret = wl1271_acx_init_mem_config(wl);
|
||||
if (ret < 0)
|
||||
goto out_irq_disable;
|
||||
|
||||
ret = wl12xx_acx_mem_cfg(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Enable data path */
|
||||
ret = wl1271_cmd_data_path(wl, 1);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Configure for CAM power saving (ie. always active) */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* configure PM */
|
||||
ret = wl1271_acx_pm_config(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
goto out;
|
||||
|
||||
out_free_memmap:
|
||||
kfree(wl->target_mem_map);
|
||||
wl->target_mem_map = NULL;
|
||||
|
||||
out_irq_disable:
|
||||
mutex_unlock(&wl->mutex);
|
||||
/* Unlocking the mutex in the middle of handling is
|
||||
inherently unsafe. In this case we deem it safe to do,
|
||||
because we need to let any possibly pending IRQ out of
|
||||
the system (and while we are WL1271_STATE_OFF the IRQ
|
||||
work function will not do anything.) Also, any other
|
||||
possible concurrent operations will fail due to the
|
||||
current state, hence the wl1271 struct should be safe. */
|
||||
wlcore_disable_interrupts(wl);
|
||||
mutex_lock(&wl->mutex);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl12xx_get_spare_blocks(struct wl1271 *wl, bool is_gem)
|
||||
{
|
||||
if (is_gem)
|
||||
return WL12XX_TX_HW_BLOCK_GEM_SPARE;
|
||||
|
||||
return WL12XX_TX_HW_BLOCK_SPARE_DEFAULT;
|
||||
}
|
||||
|
||||
static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key_conf)
|
||||
{
|
||||
return wlcore_set_key(wl, cmd, vif, sta, key_conf);
|
||||
}
|
||||
|
||||
static struct wlcore_ops wl12xx_ops = {
|
||||
.identify_chip = wl12xx_identify_chip,
|
||||
.identify_fw = wl12xx_identify_fw,
|
||||
.boot = wl12xx_boot,
|
||||
.plt_init = wl12xx_plt_init,
|
||||
.trigger_cmd = wl12xx_trigger_cmd,
|
||||
.ack_event = wl12xx_ack_event,
|
||||
.calc_tx_blocks = wl12xx_calc_tx_blocks,
|
||||
@ -1306,6 +1401,13 @@ static struct wlcore_ops wl12xx_ops = {
|
||||
.sta_get_ap_rate_mask = wl12xx_sta_get_ap_rate_mask,
|
||||
.get_pg_ver = wl12xx_get_pg_ver,
|
||||
.get_mac = wl12xx_get_mac,
|
||||
.set_tx_desc_csum = wl12xx_set_tx_desc_csum,
|
||||
.set_rx_csum = NULL,
|
||||
.ap_get_mimo_wide_rate_mask = NULL,
|
||||
.debugfs_init = wl12xx_debugfs_add_files,
|
||||
.get_spare_blocks = wl12xx_get_spare_blocks,
|
||||
.set_key = wl12xx_set_key,
|
||||
.pre_pkt_send = NULL,
|
||||
};
|
||||
|
||||
static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
|
||||
@ -1323,6 +1425,7 @@ static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
|
||||
|
||||
static int __devinit wl12xx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct wl1271 *wl;
|
||||
struct ieee80211_hw *hw;
|
||||
struct wl12xx_priv *priv;
|
||||
@ -1334,19 +1437,65 @@ static int __devinit wl12xx_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
wl = hw->priv;
|
||||
priv = wl->priv;
|
||||
wl->ops = &wl12xx_ops;
|
||||
wl->ptable = wl12xx_ptable;
|
||||
wl->rtable = wl12xx_rtable;
|
||||
wl->num_tx_desc = 16;
|
||||
wl->normal_tx_spare = WL12XX_TX_HW_BLOCK_SPARE_DEFAULT;
|
||||
wl->gem_tx_spare = WL12XX_TX_HW_BLOCK_GEM_SPARE;
|
||||
wl->num_rx_desc = 8;
|
||||
wl->band_rate_to_idx = wl12xx_band_rate_to_idx;
|
||||
wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX;
|
||||
wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0;
|
||||
wl->fw_status_priv_len = 0;
|
||||
memcpy(&wl->ht_cap, &wl12xx_ht_cap, sizeof(wl12xx_ht_cap));
|
||||
wl->stats.fw_stats_len = sizeof(struct wl12xx_acx_statistics);
|
||||
memcpy(&wl->ht_cap[IEEE80211_BAND_2GHZ], &wl12xx_ht_cap,
|
||||
sizeof(wl12xx_ht_cap));
|
||||
memcpy(&wl->ht_cap[IEEE80211_BAND_5GHZ], &wl12xx_ht_cap,
|
||||
sizeof(wl12xx_ht_cap));
|
||||
wl12xx_conf_init(wl);
|
||||
|
||||
if (!fref_param) {
|
||||
priv->ref_clock = pdata->board_ref_clock;
|
||||
} else {
|
||||
if (!strcmp(fref_param, "19.2"))
|
||||
priv->ref_clock = WL12XX_REFCLOCK_19;
|
||||
else if (!strcmp(fref_param, "26"))
|
||||
priv->ref_clock = WL12XX_REFCLOCK_26;
|
||||
else if (!strcmp(fref_param, "26x"))
|
||||
priv->ref_clock = WL12XX_REFCLOCK_26_XTAL;
|
||||
else if (!strcmp(fref_param, "38.4"))
|
||||
priv->ref_clock = WL12XX_REFCLOCK_38;
|
||||
else if (!strcmp(fref_param, "38.4x"))
|
||||
priv->ref_clock = WL12XX_REFCLOCK_38_XTAL;
|
||||
else if (!strcmp(fref_param, "52"))
|
||||
priv->ref_clock = WL12XX_REFCLOCK_52;
|
||||
else
|
||||
wl1271_error("Invalid fref parameter %s", fref_param);
|
||||
}
|
||||
|
||||
if (!tcxo_param) {
|
||||
priv->tcxo_clock = pdata->board_tcxo_clock;
|
||||
} else {
|
||||
if (!strcmp(tcxo_param, "19.2"))
|
||||
priv->tcxo_clock = WL12XX_TCXOCLOCK_19_2;
|
||||
else if (!strcmp(tcxo_param, "26"))
|
||||
priv->tcxo_clock = WL12XX_TCXOCLOCK_26;
|
||||
else if (!strcmp(tcxo_param, "38.4"))
|
||||
priv->tcxo_clock = WL12XX_TCXOCLOCK_38_4;
|
||||
else if (!strcmp(tcxo_param, "52"))
|
||||
priv->tcxo_clock = WL12XX_TCXOCLOCK_52;
|
||||
else if (!strcmp(tcxo_param, "16.368"))
|
||||
priv->tcxo_clock = WL12XX_TCXOCLOCK_16_368;
|
||||
else if (!strcmp(tcxo_param, "32.736"))
|
||||
priv->tcxo_clock = WL12XX_TCXOCLOCK_32_736;
|
||||
else if (!strcmp(tcxo_param, "16.8"))
|
||||
priv->tcxo_clock = WL12XX_TCXOCLOCK_16_8;
|
||||
else if (!strcmp(tcxo_param, "33.6"))
|
||||
priv->tcxo_clock = WL12XX_TCXOCLOCK_33_6;
|
||||
else
|
||||
wl1271_error("Invalid tcxo parameter %s", tcxo_param);
|
||||
}
|
||||
|
||||
return wlcore_probe(wl, pdev);
|
||||
}
|
||||
|
||||
@ -1378,6 +1527,13 @@ static void __exit wl12xx_exit(void)
|
||||
}
|
||||
module_exit(wl12xx_exit);
|
||||
|
||||
module_param_named(fref, fref_param, charp, 0);
|
||||
MODULE_PARM_DESC(fref, "FREF clock: 19.2, 26, 26x, 38.4, 38.4x, 52");
|
||||
|
||||
module_param_named(tcxo, tcxo_param, charp, 0);
|
||||
MODULE_PARM_DESC(tcxo,
|
||||
"TCXO clock: 19.2, 26, 38.4, 52, 16.368, 32.736, 16.8, 33.6");
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
|
||||
MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
|
||||
|
@ -24,8 +24,16 @@
|
||||
|
||||
#include "conf.h"
|
||||
|
||||
struct wl127x_rx_mem_pool_addr {
|
||||
u32 addr;
|
||||
u32 addr_extra;
|
||||
};
|
||||
|
||||
struct wl12xx_priv {
|
||||
struct wl12xx_priv_conf conf;
|
||||
|
||||
int ref_clock;
|
||||
int tcxo_clock;
|
||||
};
|
||||
|
||||
#endif /* __WL12XX_PRIV_H__ */
|
||||
|
7
drivers/net/wireless/ti/wl18xx/Kconfig
Normal file
7
drivers/net/wireless/ti/wl18xx/Kconfig
Normal file
@ -0,0 +1,7 @@
|
||||
config WL18XX
|
||||
tristate "TI wl18xx support"
|
||||
depends on MAC80211
|
||||
select WLCORE
|
||||
---help---
|
||||
This module adds support for wireless adapters based on TI
|
||||
WiLink 8 chipsets.
|
3
drivers/net/wireless/ti/wl18xx/Makefile
Normal file
3
drivers/net/wireless/ti/wl18xx/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
wl18xx-objs = main.o acx.o tx.o io.o debugfs.o
|
||||
|
||||
obj-$(CONFIG_WL18XX) += wl18xx.o
|
111
drivers/net/wireless/ti/wl18xx/acx.c
Normal file
111
drivers/net/wireless/ti/wl18xx/acx.c
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../wlcore/cmd.h"
|
||||
#include "../wlcore/debug.h"
|
||||
#include "../wlcore/acx.h"
|
||||
|
||||
#include "acx.h"
|
||||
|
||||
int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
|
||||
u32 sdio_blk_size, u32 extra_mem_blks,
|
||||
u32 len_field_size)
|
||||
{
|
||||
struct wl18xx_acx_host_config_bitmap *bitmap_conf;
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "acx cfg bitmap %d blk %d spare %d field %d",
|
||||
host_cfg_bitmap, sdio_blk_size, extra_mem_blks,
|
||||
len_field_size);
|
||||
|
||||
bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL);
|
||||
if (!bitmap_conf) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap);
|
||||
bitmap_conf->host_sdio_block_size = cpu_to_le32(sdio_blk_size);
|
||||
bitmap_conf->extra_mem_blocks = cpu_to_le32(extra_mem_blks);
|
||||
bitmap_conf->length_field_size = cpu_to_le32(len_field_size);
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP,
|
||||
bitmap_conf, sizeof(*bitmap_conf));
|
||||
if (ret < 0) {
|
||||
wl1271_warning("wl1271 bitmap config opt failed: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(bitmap_conf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl18xx_acx_set_checksum_state(struct wl1271 *wl)
|
||||
{
|
||||
struct wl18xx_acx_checksum_state *acx;
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "acx checksum state");
|
||||
|
||||
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
|
||||
if (!acx) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->checksum_state = CHECKSUM_OFFLOAD_ENABLED;
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_CHECKSUM_CONFIG, acx, sizeof(*acx));
|
||||
if (ret < 0) {
|
||||
wl1271_warning("failed to set Tx checksum state: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl18xx_acx_clear_statistics(struct wl1271 *wl)
|
||||
{
|
||||
struct wl18xx_acx_clear_statistics *acx;
|
||||
int ret = 0;
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "acx clear statistics");
|
||||
|
||||
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
|
||||
if (!acx) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_CLEAR_STATISTICS, acx, sizeof(*acx));
|
||||
if (ret < 0) {
|
||||
wl1271_warning("failed to clear firmware statistics: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
291
drivers/net/wireless/ti/wl18xx/acx.h
Normal file
291
drivers/net/wireless/ti/wl18xx/acx.h
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WL18XX_ACX_H__
|
||||
#define __WL18XX_ACX_H__
|
||||
|
||||
#include "../wlcore/wlcore.h"
|
||||
#include "../wlcore/acx.h"
|
||||
|
||||
enum {
|
||||
ACX_CLEAR_STATISTICS = 0x0047,
|
||||
};
|
||||
|
||||
/* numbers of bits the length field takes (add 1 for the actual number) */
|
||||
#define WL18XX_HOST_IF_LEN_SIZE_FIELD 15
|
||||
|
||||
#define WL18XX_ACX_EVENTS_VECTOR_PG1 (WL1271_ACX_INTR_WATCHDOG | \
|
||||
WL1271_ACX_INTR_INIT_COMPLETE | \
|
||||
WL1271_ACX_INTR_EVENT_A | \
|
||||
WL1271_ACX_INTR_EVENT_B | \
|
||||
WL1271_ACX_INTR_CMD_COMPLETE | \
|
||||
WL1271_ACX_INTR_HW_AVAILABLE | \
|
||||
WL1271_ACX_INTR_DATA)
|
||||
|
||||
#define WL18XX_ACX_EVENTS_VECTOR_PG2 (WL18XX_ACX_EVENTS_VECTOR_PG1 | \
|
||||
WL1271_ACX_SW_INTR_WATCHDOG)
|
||||
|
||||
#define WL18XX_INTR_MASK_PG1 (WL1271_ACX_INTR_WATCHDOG | \
|
||||
WL1271_ACX_INTR_EVENT_A | \
|
||||
WL1271_ACX_INTR_EVENT_B | \
|
||||
WL1271_ACX_INTR_HW_AVAILABLE | \
|
||||
WL1271_ACX_INTR_DATA)
|
||||
|
||||
#define WL18XX_INTR_MASK_PG2 (WL18XX_INTR_MASK_PG1 | \
|
||||
WL1271_ACX_SW_INTR_WATCHDOG)
|
||||
|
||||
struct wl18xx_acx_host_config_bitmap {
|
||||
struct acx_header header;
|
||||
|
||||
__le32 host_cfg_bitmap;
|
||||
|
||||
__le32 host_sdio_block_size;
|
||||
|
||||
/* extra mem blocks per frame in TX. */
|
||||
__le32 extra_mem_blocks;
|
||||
|
||||
/*
|
||||
* number of bits of the length field in the first TX word
|
||||
* (up to 15 - for using the entire 16 bits).
|
||||
*/
|
||||
__le32 length_field_size;
|
||||
|
||||
} __packed;
|
||||
|
||||
enum {
|
||||
CHECKSUM_OFFLOAD_DISABLED = 0,
|
||||
CHECKSUM_OFFLOAD_ENABLED = 1,
|
||||
CHECKSUM_OFFLOAD_FAKE_RX = 2,
|
||||
CHECKSUM_OFFLOAD_INVALID = 0xFF
|
||||
};
|
||||
|
||||
struct wl18xx_acx_checksum_state {
|
||||
struct acx_header header;
|
||||
|
||||
/* enum acx_checksum_state */
|
||||
u8 checksum_state;
|
||||
u8 pad[3];
|
||||
} __packed;
|
||||
|
||||
|
||||
struct wl18xx_acx_error_stats {
|
||||
u32 error_frame;
|
||||
u32 error_null_Frame_tx_start;
|
||||
u32 error_numll_frame_cts_start;
|
||||
u32 error_bar_retry;
|
||||
u32 error_frame_cts_nul_flid;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_debug_stats {
|
||||
u32 debug1;
|
||||
u32 debug2;
|
||||
u32 debug3;
|
||||
u32 debug4;
|
||||
u32 debug5;
|
||||
u32 debug6;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_ring_stats {
|
||||
u32 prepared_descs;
|
||||
u32 tx_cmplt;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_tx_stats {
|
||||
u32 tx_prepared_descs;
|
||||
u32 tx_cmplt;
|
||||
u32 tx_template_prepared;
|
||||
u32 tx_data_prepared;
|
||||
u32 tx_template_programmed;
|
||||
u32 tx_data_programmed;
|
||||
u32 tx_burst_programmed;
|
||||
u32 tx_starts;
|
||||
u32 tx_imm_resp;
|
||||
u32 tx_start_templates;
|
||||
u32 tx_start_int_templates;
|
||||
u32 tx_start_fw_gen;
|
||||
u32 tx_start_data;
|
||||
u32 tx_start_null_frame;
|
||||
u32 tx_exch;
|
||||
u32 tx_retry_template;
|
||||
u32 tx_retry_data;
|
||||
u32 tx_exch_pending;
|
||||
u32 tx_exch_expiry;
|
||||
u32 tx_done_template;
|
||||
u32 tx_done_data;
|
||||
u32 tx_done_int_template;
|
||||
u32 tx_frame_checksum;
|
||||
u32 tx_checksum_result;
|
||||
u32 frag_called;
|
||||
u32 frag_mpdu_alloc_failed;
|
||||
u32 frag_init_called;
|
||||
u32 frag_in_process_called;
|
||||
u32 frag_tkip_called;
|
||||
u32 frag_key_not_found;
|
||||
u32 frag_need_fragmentation;
|
||||
u32 frag_bad_mblk_num;
|
||||
u32 frag_failed;
|
||||
u32 frag_cache_hit;
|
||||
u32 frag_cache_miss;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_rx_stats {
|
||||
u32 rx_beacon_early_term;
|
||||
u32 rx_out_of_mpdu_nodes;
|
||||
u32 rx_hdr_overflow;
|
||||
u32 rx_dropped_frame;
|
||||
u32 rx_done_stage;
|
||||
u32 rx_done;
|
||||
u32 rx_defrag;
|
||||
u32 rx_defrag_end;
|
||||
u32 rx_cmplt;
|
||||
u32 rx_pre_complt;
|
||||
u32 rx_cmplt_task;
|
||||
u32 rx_phy_hdr;
|
||||
u32 rx_timeout;
|
||||
u32 rx_timeout_wa;
|
||||
u32 rx_wa_density_dropped_frame;
|
||||
u32 rx_wa_ba_not_expected;
|
||||
u32 rx_frame_checksum;
|
||||
u32 rx_checksum_result;
|
||||
u32 defrag_called;
|
||||
u32 defrag_init_called;
|
||||
u32 defrag_in_process_called;
|
||||
u32 defrag_tkip_called;
|
||||
u32 defrag_need_defrag;
|
||||
u32 defrag_decrypt_failed;
|
||||
u32 decrypt_key_not_found;
|
||||
u32 defrag_need_decrypt;
|
||||
u32 rx_tkip_replays;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_isr_stats {
|
||||
u32 irqs;
|
||||
} __packed;
|
||||
|
||||
#define PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD 10
|
||||
|
||||
struct wl18xx_acx_pwr_stats {
|
||||
u32 missing_bcns_cnt;
|
||||
u32 rcvd_bcns_cnt;
|
||||
u32 connection_out_of_sync;
|
||||
u32 cont_miss_bcns_spread[PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD];
|
||||
u32 rcvd_awake_bcns_cnt;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_event_stats {
|
||||
u32 calibration;
|
||||
u32 rx_mismatch;
|
||||
u32 rx_mem_empty;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_ps_poll_stats {
|
||||
u32 ps_poll_timeouts;
|
||||
u32 upsd_timeouts;
|
||||
u32 upsd_max_ap_turn;
|
||||
u32 ps_poll_max_ap_turn;
|
||||
u32 ps_poll_utilization;
|
||||
u32 upsd_utilization;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_rx_filter_stats {
|
||||
u32 beacon_filter;
|
||||
u32 arp_filter;
|
||||
u32 mc_filter;
|
||||
u32 dup_filter;
|
||||
u32 data_filter;
|
||||
u32 ibss_filter;
|
||||
u32 protection_filter;
|
||||
u32 accum_arp_pend_requests;
|
||||
u32 max_arp_queue_dep;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_rx_rate_stats {
|
||||
u32 rx_frames_per_rates[50];
|
||||
} __packed;
|
||||
|
||||
#define AGGR_STATS_TX_AGG 16
|
||||
#define AGGR_STATS_TX_RATE 16
|
||||
#define AGGR_STATS_RX_SIZE_LEN 16
|
||||
|
||||
struct wl18xx_acx_aggr_stats {
|
||||
u32 tx_agg_vs_rate[AGGR_STATS_TX_AGG * AGGR_STATS_TX_RATE];
|
||||
u32 rx_size[AGGR_STATS_RX_SIZE_LEN];
|
||||
} __packed;
|
||||
|
||||
#define PIPE_STATS_HW_FIFO 11
|
||||
|
||||
struct wl18xx_acx_pipeline_stats {
|
||||
u32 hs_tx_stat_fifo_int;
|
||||
u32 hs_rx_stat_fifo_int;
|
||||
u32 tcp_tx_stat_fifo_int;
|
||||
u32 tcp_rx_stat_fifo_int;
|
||||
u32 enc_tx_stat_fifo_int;
|
||||
u32 enc_rx_stat_fifo_int;
|
||||
u32 rx_complete_stat_fifo_int;
|
||||
u32 pre_proc_swi;
|
||||
u32 post_proc_swi;
|
||||
u32 sec_frag_swi;
|
||||
u32 pre_to_defrag_swi;
|
||||
u32 defrag_to_csum_swi;
|
||||
u32 csum_to_rx_xfer_swi;
|
||||
u32 dec_packet_in;
|
||||
u32 dec_packet_in_fifo_full;
|
||||
u32 dec_packet_out;
|
||||
u32 cs_rx_packet_in;
|
||||
u32 cs_rx_packet_out;
|
||||
u16 pipeline_fifo_full[PIPE_STATS_HW_FIFO];
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_mem_stats {
|
||||
u32 rx_free_mem_blks;
|
||||
u32 tx_free_mem_blks;
|
||||
u32 fwlog_free_mem_blks;
|
||||
u32 fw_gen_free_mem_blks;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_statistics {
|
||||
struct acx_header header;
|
||||
|
||||
struct wl18xx_acx_error_stats error;
|
||||
struct wl18xx_acx_debug_stats debug;
|
||||
struct wl18xx_acx_tx_stats tx;
|
||||
struct wl18xx_acx_rx_stats rx;
|
||||
struct wl18xx_acx_isr_stats isr;
|
||||
struct wl18xx_acx_pwr_stats pwr;
|
||||
struct wl18xx_acx_ps_poll_stats ps_poll;
|
||||
struct wl18xx_acx_rx_filter_stats rx_filter;
|
||||
struct wl18xx_acx_rx_rate_stats rx_rate;
|
||||
struct wl18xx_acx_aggr_stats aggr_size;
|
||||
struct wl18xx_acx_pipeline_stats pipeline;
|
||||
struct wl18xx_acx_mem_stats mem;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_clear_statistics {
|
||||
struct acx_header header;
|
||||
};
|
||||
|
||||
int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
|
||||
u32 sdio_blk_size, u32 extra_mem_blks,
|
||||
u32 len_field_size);
|
||||
int wl18xx_acx_set_checksum_state(struct wl1271 *wl);
|
||||
int wl18xx_acx_clear_statistics(struct wl1271 *wl);
|
||||
|
||||
#endif /* __WL18XX_ACX_H__ */
|
92
drivers/net/wireless/ti/wl18xx/conf.h
Normal file
92
drivers/net/wireless/ti/wl18xx/conf.h
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WL18XX_CONF_H__
|
||||
#define __WL18XX_CONF_H__
|
||||
|
||||
#define WL18XX_CONF_MAGIC 0x10e100ca
|
||||
#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0002)
|
||||
#define WL18XX_CONF_MASK 0x0000ffff
|
||||
#define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \
|
||||
sizeof(struct wl18xx_priv_conf))
|
||||
|
||||
#define NUM_OF_CHANNELS_11_ABG 150
|
||||
#define NUM_OF_CHANNELS_11_P 7
|
||||
#define WL18XX_NUM_OF_SUB_BANDS 9
|
||||
#define SRF_TABLE_LEN 16
|
||||
#define PIN_MUXING_SIZE 2
|
||||
|
||||
struct wl18xx_mac_and_phy_params {
|
||||
u8 phy_standalone;
|
||||
u8 rdl;
|
||||
u8 enable_clpc;
|
||||
u8 enable_tx_low_pwr_on_siso_rdl;
|
||||
u8 auto_detect;
|
||||
u8 dedicated_fem;
|
||||
|
||||
u8 low_band_component;
|
||||
|
||||
/* Bit 0: One Hot, Bit 1: Control Enable, Bit 2: 1.8V, Bit 3: 3V */
|
||||
u8 low_band_component_type;
|
||||
|
||||
u8 high_band_component;
|
||||
|
||||
/* Bit 0: One Hot, Bit 1: Control Enable, Bit 2: 1.8V, Bit 3: 3V */
|
||||
u8 high_band_component_type;
|
||||
u8 number_of_assembled_ant2_4;
|
||||
u8 number_of_assembled_ant5;
|
||||
u8 pin_muxing_platform_options[PIN_MUXING_SIZE];
|
||||
u8 external_pa_dc2dc;
|
||||
u8 tcxo_ldo_voltage;
|
||||
u8 xtal_itrim_val;
|
||||
u8 srf_state;
|
||||
u8 srf1[SRF_TABLE_LEN];
|
||||
u8 srf2[SRF_TABLE_LEN];
|
||||
u8 srf3[SRF_TABLE_LEN];
|
||||
u8 io_configuration;
|
||||
u8 sdio_configuration;
|
||||
u8 settings;
|
||||
u8 rx_profile;
|
||||
u8 per_chan_pwr_limit_arr_11abg[NUM_OF_CHANNELS_11_ABG];
|
||||
u8 pwr_limit_reference_11_abg;
|
||||
u8 per_chan_pwr_limit_arr_11p[NUM_OF_CHANNELS_11_P];
|
||||
u8 pwr_limit_reference_11p;
|
||||
u8 per_sub_band_tx_trace_loss[WL18XX_NUM_OF_SUB_BANDS];
|
||||
u8 per_sub_band_rx_trace_loss[WL18XX_NUM_OF_SUB_BANDS];
|
||||
u8 primary_clock_setting_time;
|
||||
u8 clock_valid_on_wake_up;
|
||||
u8 secondary_clock_setting_time;
|
||||
u8 board_type;
|
||||
/* enable point saturation */
|
||||
u8 psat;
|
||||
/* low/medium/high Tx power in dBm */
|
||||
s8 low_power_val;
|
||||
s8 med_power_val;
|
||||
s8 high_power_val;
|
||||
u8 padding[1];
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_priv_conf {
|
||||
/* this structure is copied wholesale to FW */
|
||||
struct wl18xx_mac_and_phy_params phy;
|
||||
} __packed;
|
||||
|
||||
#endif /* __WL18XX_CONF_H__ */
|
403
drivers/net/wireless/ti/wl18xx/debugfs.c
Normal file
403
drivers/net/wireless/ti/wl18xx/debugfs.c
Normal file
@ -0,0 +1,403 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Copyright (C) 2011-2012 Texas Instruments
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../wlcore/debugfs.h"
|
||||
#include "../wlcore/wlcore.h"
|
||||
|
||||
#include "wl18xx.h"
|
||||
#include "acx.h"
|
||||
#include "debugfs.h"
|
||||
|
||||
#define WL18XX_DEBUGFS_FWSTATS_FILE(a, b, c) \
|
||||
DEBUGFS_FWSTATS_FILE(a, b, c, wl18xx_acx_statistics)
|
||||
#define WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(a, b, c) \
|
||||
DEBUGFS_FWSTATS_FILE_ARRAY(a, b, c, wl18xx_acx_statistics)
|
||||
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug1, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug2, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug3, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug4, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug5, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug6, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(error, error_null_Frame_tx_start, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(error, error_numll_frame_cts_start, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(error, error_bar_retry, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame_cts_nul_flid, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_prepared_descs, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_cmplt, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_template_prepared, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_data_prepared, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_template_programmed, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_data_programmed, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_burst_programmed, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_starts, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_imm_resp, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_templates, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_int_templates, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_fw_gen, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_data, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_null_frame, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_retry_template, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_retry_data, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch_pending, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch_expiry, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_template, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_data, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_int_template, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_frame_checksum, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_checksum_result, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_called, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_mpdu_alloc_failed, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_init_called, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_in_process_called, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_tkip_called, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_key_not_found, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_need_fragmentation, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_bad_mblk_num, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_failed, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_cache_hit, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_cache_miss, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_beacon_early_term, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_out_of_mpdu_nodes, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_hdr_overflow, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_dropped_frame, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_done, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_defrag, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_defrag_end, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_cmplt, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_pre_complt, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_cmplt_task, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_phy_hdr, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_timeout, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_timeout_wa, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_wa_density_dropped_frame, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_wa_ba_not_expected, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_frame_checksum, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_checksum_result, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_called, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_init_called, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_in_process_called, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_tkip_called, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_need_defrag, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_decrypt_failed, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, decrypt_key_not_found, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_need_decrypt, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_tkip_replays, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(isr, irqs, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pwr, missing_bcns_cnt, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_bcns_cnt, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pwr, connection_out_of_sync, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(pwr, cont_miss_bcns_spread,
|
||||
PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD);
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_bcns_cnt, "%u");
|
||||
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_timeouts, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_timeouts, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_max_ap_turn, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_max_ap_turn, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_utilization, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_utilization, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, beacon_filter, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, arp_filter, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, mc_filter, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, dup_filter, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, data_filter, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, ibss_filter, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, protection_filter, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, accum_arp_pend_requests, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, max_arp_queue_dep, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_rate, rx_frames_per_rates, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, tx_agg_vs_rate,
|
||||
AGGR_STATS_TX_AGG*AGGR_STATS_TX_RATE);
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, rx_size,
|
||||
AGGR_STATS_RX_SIZE_LEN);
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, hs_tx_stat_fifo_int, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, tcp_tx_stat_fifo_int, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, tcp_rx_stat_fifo_int, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, enc_tx_stat_fifo_int, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, enc_rx_stat_fifo_int, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, rx_complete_stat_fifo_int, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, pre_proc_swi, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, post_proc_swi, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, sec_frag_swi, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, pre_to_defrag_swi, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, defrag_to_csum_swi, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, csum_to_rx_xfer_swi, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_in, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_in_fifo_full, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_out, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, cs_rx_packet_in, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, cs_rx_packet_out, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(pipeline, pipeline_fifo_full,
|
||||
PIPE_STATS_HW_FIFO);
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(mem, rx_free_mem_blks, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(mem, tx_free_mem_blks, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(mem, fwlog_free_mem_blks, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(mem, fw_gen_free_mem_blks, "%u");
|
||||
|
||||
static ssize_t conf_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wl1271 *wl = file->private_data;
|
||||
struct wl18xx_priv *priv = wl->priv;
|
||||
struct wlcore_conf_header header;
|
||||
char *buf, *pos;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
len = WL18XX_CONF_SIZE;
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
header.magic = cpu_to_le32(WL18XX_CONF_MAGIC);
|
||||
header.version = cpu_to_le32(WL18XX_CONF_VERSION);
|
||||
header.checksum = 0;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
pos = buf;
|
||||
memcpy(pos, &header, sizeof(header));
|
||||
pos += sizeof(header);
|
||||
memcpy(pos, &wl->conf, sizeof(wl->conf));
|
||||
pos += sizeof(wl->conf);
|
||||
memcpy(pos, &priv->conf, sizeof(priv->conf));
|
||||
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations conf_ops = {
|
||||
.read = conf_read,
|
||||
.open = simple_open,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t clear_fw_stats_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wl1271 *wl = file->private_data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF)
|
||||
goto out;
|
||||
|
||||
ret = wl18xx_acx_clear_statistics(wl);
|
||||
if (ret < 0) {
|
||||
count = ret;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&wl->mutex);
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations clear_fw_stats_ops = {
|
||||
.write = clear_fw_stats_write,
|
||||
.open = simple_open,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
int wl18xx_debugfs_add_files(struct wl1271 *wl,
|
||||
struct dentry *rootdir)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dentry *entry, *stats, *moddir;
|
||||
|
||||
moddir = debugfs_create_dir(KBUILD_MODNAME, rootdir);
|
||||
if (!moddir || IS_ERR(moddir)) {
|
||||
entry = moddir;
|
||||
goto err;
|
||||
}
|
||||
|
||||
stats = debugfs_create_dir("fw_stats", moddir);
|
||||
if (!stats || IS_ERR(stats)) {
|
||||
entry = stats;
|
||||
goto err;
|
||||
}
|
||||
|
||||
DEBUGFS_ADD(clear_fw_stats, stats);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(debug, debug1);
|
||||
DEBUGFS_FWSTATS_ADD(debug, debug2);
|
||||
DEBUGFS_FWSTATS_ADD(debug, debug3);
|
||||
DEBUGFS_FWSTATS_ADD(debug, debug4);
|
||||
DEBUGFS_FWSTATS_ADD(debug, debug5);
|
||||
DEBUGFS_FWSTATS_ADD(debug, debug6);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(error, error_frame);
|
||||
DEBUGFS_FWSTATS_ADD(error, error_null_Frame_tx_start);
|
||||
DEBUGFS_FWSTATS_ADD(error, error_numll_frame_cts_start);
|
||||
DEBUGFS_FWSTATS_ADD(error, error_bar_retry);
|
||||
DEBUGFS_FWSTATS_ADD(error, error_frame_cts_nul_flid);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_prepared_descs);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_cmplt);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_template_prepared);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_data_prepared);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_template_programmed);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_data_programmed);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_burst_programmed);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_starts);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_imm_resp);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_start_templates);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_start_int_templates);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_start_fw_gen);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_start_data);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_start_null_frame);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_exch);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_retry_template);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_retry_data);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_exch_pending);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_exch_expiry);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_done_template);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_done_data);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_done_int_template);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_frame_checksum);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_checksum_result);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_called);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_mpdu_alloc_failed);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_init_called);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_in_process_called);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_tkip_called);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_key_not_found);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_need_fragmentation);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_bad_mblk_num);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_failed);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_cache_hit);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_cache_miss);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_beacon_early_term);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_out_of_mpdu_nodes);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_hdr_overflow);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_dropped_frame);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_done);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_defrag);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_defrag_end);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_cmplt);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_pre_complt);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_cmplt_task);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_phy_hdr);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_timeout);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_timeout_wa);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_wa_density_dropped_frame);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_wa_ba_not_expected);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_frame_checksum);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_checksum_result);
|
||||
DEBUGFS_FWSTATS_ADD(rx, defrag_called);
|
||||
DEBUGFS_FWSTATS_ADD(rx, defrag_init_called);
|
||||
DEBUGFS_FWSTATS_ADD(rx, defrag_in_process_called);
|
||||
DEBUGFS_FWSTATS_ADD(rx, defrag_tkip_called);
|
||||
DEBUGFS_FWSTATS_ADD(rx, defrag_need_defrag);
|
||||
DEBUGFS_FWSTATS_ADD(rx, defrag_decrypt_failed);
|
||||
DEBUGFS_FWSTATS_ADD(rx, decrypt_key_not_found);
|
||||
DEBUGFS_FWSTATS_ADD(rx, defrag_need_decrypt);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_tkip_replays);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(isr, irqs);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(pwr, missing_bcns_cnt);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, rcvd_bcns_cnt);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, connection_out_of_sync);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, cont_miss_bcns_spread);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_bcns_cnt);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_timeouts);
|
||||
DEBUGFS_FWSTATS_ADD(ps_poll, upsd_timeouts);
|
||||
DEBUGFS_FWSTATS_ADD(ps_poll, upsd_max_ap_turn);
|
||||
DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_max_ap_turn);
|
||||
DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_utilization);
|
||||
DEBUGFS_FWSTATS_ADD(ps_poll, upsd_utilization);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, beacon_filter);
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, arp_filter);
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, mc_filter);
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, dup_filter);
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, data_filter);
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, ibss_filter);
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, protection_filter);
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, accum_arp_pend_requests);
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, max_arp_queue_dep);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(rx_rate, rx_frames_per_rates);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(aggr_size, tx_agg_vs_rate);
|
||||
DEBUGFS_FWSTATS_ADD(aggr_size, rx_size);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, hs_tx_stat_fifo_int);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, tcp_tx_stat_fifo_int);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, tcp_rx_stat_fifo_int);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, enc_tx_stat_fifo_int);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, enc_rx_stat_fifo_int);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, rx_complete_stat_fifo_int);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, pre_proc_swi);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, post_proc_swi);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, sec_frag_swi);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, pre_to_defrag_swi);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, defrag_to_csum_swi);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, csum_to_rx_xfer_swi);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_in);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_in_fifo_full);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_out);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, cs_rx_packet_in);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, cs_rx_packet_out);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, pipeline_fifo_full);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(mem, rx_free_mem_blks);
|
||||
DEBUGFS_FWSTATS_ADD(mem, tx_free_mem_blks);
|
||||
DEBUGFS_FWSTATS_ADD(mem, fwlog_free_mem_blks);
|
||||
DEBUGFS_FWSTATS_ADD(mem, fw_gen_free_mem_blks);
|
||||
|
||||
DEBUGFS_ADD(conf, moddir);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (IS_ERR(entry))
|
||||
ret = PTR_ERR(entry);
|
||||
else
|
||||
ret = -ENOMEM;
|
||||
|
||||
return ret;
|
||||
}
|
28
drivers/net/wireless/ti/wl18xx/debugfs.h
Normal file
28
drivers/net/wireless/ti/wl18xx/debugfs.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2012 Texas Instruments. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WL18XX_DEBUGFS_H__
|
||||
#define __WL18XX_DEBUGFS_H__
|
||||
|
||||
int wl18xx_debugfs_add_files(struct wl1271 *wl,
|
||||
struct dentry *rootdir);
|
||||
|
||||
#endif /* __WL18XX_DEBUGFS_H__ */
|
60
drivers/net/wireless/ti/wl18xx/io.c
Normal file
60
drivers/net/wireless/ti/wl18xx/io.c
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../wlcore/wlcore.h"
|
||||
#include "../wlcore/io.h"
|
||||
|
||||
#include "io.h"
|
||||
|
||||
void wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
if (WARN_ON(addr % 2))
|
||||
return;
|
||||
|
||||
if ((addr % 4) == 0) {
|
||||
tmp = wl1271_read32(wl, addr);
|
||||
tmp = (tmp & 0xffff0000) | val;
|
||||
wl1271_write32(wl, addr, tmp);
|
||||
} else {
|
||||
tmp = wl1271_read32(wl, addr - 2);
|
||||
tmp = (tmp & 0xffff) | (val << 16);
|
||||
wl1271_write32(wl, addr - 2, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
u16 wl18xx_top_reg_read(struct wl1271 *wl, int addr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (WARN_ON(addr % 2))
|
||||
return 0;
|
||||
|
||||
if ((addr % 4) == 0) {
|
||||
/* address is 4-bytes aligned */
|
||||
val = wl1271_read32(wl, addr);
|
||||
return val & 0xffff;
|
||||
} else {
|
||||
val = wl1271_read32(wl, addr - 2);
|
||||
return (val & 0xffff0000) >> 16;
|
||||
}
|
||||
}
|
28
drivers/net/wireless/ti/wl18xx/io.h
Normal file
28
drivers/net/wireless/ti/wl18xx/io.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WL18XX_IO_H__
|
||||
#define __WL18XX_IO_H__
|
||||
|
||||
void wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val);
|
||||
u16 wl18xx_top_reg_read(struct wl1271 *wl, int addr);
|
||||
|
||||
#endif /* __WL18XX_IO_H__ */
|
1462
drivers/net/wireless/ti/wl18xx/main.c
Normal file
1462
drivers/net/wireless/ti/wl18xx/main.c
Normal file
File diff suppressed because it is too large
Load Diff
191
drivers/net/wireless/ti/wl18xx/reg.h
Normal file
191
drivers/net/wireless/ti/wl18xx/reg.h
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* This file is part of wlcore
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __REG_H__
|
||||
#define __REG_H__
|
||||
|
||||
#define WL18XX_REGISTERS_BASE 0x00800000
|
||||
#define WL18XX_CODE_BASE 0x00000000
|
||||
#define WL18XX_DATA_BASE 0x00400000
|
||||
#define WL18XX_DOUBLE_BUFFER_BASE 0x00600000
|
||||
#define WL18XX_MCU_KEY_SEARCH_BASE 0x00700000
|
||||
#define WL18XX_PHY_BASE 0x00900000
|
||||
#define WL18XX_TOP_OCP_BASE 0x00A00000
|
||||
#define WL18XX_PACKET_RAM_BASE 0x00B00000
|
||||
#define WL18XX_HOST_BASE 0x00C00000
|
||||
|
||||
#define WL18XX_REGISTERS_DOWN_SIZE 0x0000B000
|
||||
|
||||
#define WL18XX_REG_BOOT_PART_START 0x00802000
|
||||
#define WL18XX_REG_BOOT_PART_SIZE 0x00014578
|
||||
|
||||
#define WL18XX_PHY_INIT_MEM_ADDR 0x80926000
|
||||
|
||||
#define WL18XX_SDIO_WSPI_BASE (WL18XX_REGISTERS_BASE)
|
||||
#define WL18XX_REG_CONFIG_BASE (WL18XX_REGISTERS_BASE + 0x02000)
|
||||
#define WL18XX_WGCM_REGS_BASE (WL18XX_REGISTERS_BASE + 0x03000)
|
||||
#define WL18XX_ENC_BASE (WL18XX_REGISTERS_BASE + 0x04000)
|
||||
#define WL18XX_INTERRUPT_BASE (WL18XX_REGISTERS_BASE + 0x05000)
|
||||
#define WL18XX_UART_BASE (WL18XX_REGISTERS_BASE + 0x06000)
|
||||
#define WL18XX_WELP_BASE (WL18XX_REGISTERS_BASE + 0x07000)
|
||||
#define WL18XX_TCP_CKSM_BASE (WL18XX_REGISTERS_BASE + 0x08000)
|
||||
#define WL18XX_FIFO_BASE (WL18XX_REGISTERS_BASE + 0x09000)
|
||||
#define WL18XX_OCP_BRIDGE_BASE (WL18XX_REGISTERS_BASE + 0x0A000)
|
||||
#define WL18XX_PMAC_RX_BASE (WL18XX_REGISTERS_BASE + 0x14800)
|
||||
#define WL18XX_PMAC_ACM_BASE (WL18XX_REGISTERS_BASE + 0x14C00)
|
||||
#define WL18XX_PMAC_TX_BASE (WL18XX_REGISTERS_BASE + 0x15000)
|
||||
#define WL18XX_PMAC_CSR_BASE (WL18XX_REGISTERS_BASE + 0x15400)
|
||||
|
||||
#define WL18XX_REG_ECPU_CONTROL (WL18XX_REGISTERS_BASE + 0x02004)
|
||||
#define WL18XX_REG_INTERRUPT_NO_CLEAR (WL18XX_REGISTERS_BASE + 0x050E8)
|
||||
#define WL18XX_REG_INTERRUPT_ACK (WL18XX_REGISTERS_BASE + 0x050F0)
|
||||
#define WL18XX_REG_INTERRUPT_TRIG (WL18XX_REGISTERS_BASE + 0x5074)
|
||||
#define WL18XX_REG_INTERRUPT_TRIG_H (WL18XX_REGISTERS_BASE + 0x5078)
|
||||
#define WL18XX_REG_INTERRUPT_MASK (WL18XX_REGISTERS_BASE + 0x0050DC)
|
||||
|
||||
#define WL18XX_REG_CHIP_ID_B (WL18XX_REGISTERS_BASE + 0x01542C)
|
||||
|
||||
#define WL18XX_SLV_MEM_DATA (WL18XX_HOST_BASE + 0x0018)
|
||||
#define WL18XX_SLV_REG_DATA (WL18XX_HOST_BASE + 0x0008)
|
||||
|
||||
/* Scratch Pad registers*/
|
||||
#define WL18XX_SCR_PAD0 (WL18XX_REGISTERS_BASE + 0x0154EC)
|
||||
#define WL18XX_SCR_PAD1 (WL18XX_REGISTERS_BASE + 0x0154F0)
|
||||
#define WL18XX_SCR_PAD2 (WL18XX_REGISTERS_BASE + 0x0154F4)
|
||||
#define WL18XX_SCR_PAD3 (WL18XX_REGISTERS_BASE + 0x0154F8)
|
||||
#define WL18XX_SCR_PAD4 (WL18XX_REGISTERS_BASE + 0x0154FC)
|
||||
#define WL18XX_SCR_PAD4_SET (WL18XX_REGISTERS_BASE + 0x015504)
|
||||
#define WL18XX_SCR_PAD4_CLR (WL18XX_REGISTERS_BASE + 0x015500)
|
||||
#define WL18XX_SCR_PAD5 (WL18XX_REGISTERS_BASE + 0x015508)
|
||||
#define WL18XX_SCR_PAD5_SET (WL18XX_REGISTERS_BASE + 0x015510)
|
||||
#define WL18XX_SCR_PAD5_CLR (WL18XX_REGISTERS_BASE + 0x01550C)
|
||||
#define WL18XX_SCR_PAD6 (WL18XX_REGISTERS_BASE + 0x015514)
|
||||
#define WL18XX_SCR_PAD7 (WL18XX_REGISTERS_BASE + 0x015518)
|
||||
#define WL18XX_SCR_PAD8 (WL18XX_REGISTERS_BASE + 0x01551C)
|
||||
#define WL18XX_SCR_PAD9 (WL18XX_REGISTERS_BASE + 0x015520)
|
||||
|
||||
/* Spare registers*/
|
||||
#define WL18XX_SPARE_A1 (WL18XX_REGISTERS_BASE + 0x002194)
|
||||
#define WL18XX_SPARE_A2 (WL18XX_REGISTERS_BASE + 0x002198)
|
||||
#define WL18XX_SPARE_A3 (WL18XX_REGISTERS_BASE + 0x00219C)
|
||||
#define WL18XX_SPARE_A4 (WL18XX_REGISTERS_BASE + 0x0021A0)
|
||||
#define WL18XX_SPARE_A5 (WL18XX_REGISTERS_BASE + 0x0021A4)
|
||||
#define WL18XX_SPARE_A6 (WL18XX_REGISTERS_BASE + 0x0021A8)
|
||||
#define WL18XX_SPARE_A7 (WL18XX_REGISTERS_BASE + 0x0021AC)
|
||||
#define WL18XX_SPARE_A8 (WL18XX_REGISTERS_BASE + 0x0021B0)
|
||||
#define WL18XX_SPARE_B1 (WL18XX_REGISTERS_BASE + 0x015524)
|
||||
#define WL18XX_SPARE_B2 (WL18XX_REGISTERS_BASE + 0x015528)
|
||||
#define WL18XX_SPARE_B3 (WL18XX_REGISTERS_BASE + 0x01552C)
|
||||
#define WL18XX_SPARE_B4 (WL18XX_REGISTERS_BASE + 0x015530)
|
||||
#define WL18XX_SPARE_B5 (WL18XX_REGISTERS_BASE + 0x015534)
|
||||
#define WL18XX_SPARE_B6 (WL18XX_REGISTERS_BASE + 0x015538)
|
||||
#define WL18XX_SPARE_B7 (WL18XX_REGISTERS_BASE + 0x01553C)
|
||||
#define WL18XX_SPARE_B8 (WL18XX_REGISTERS_BASE + 0x015540)
|
||||
|
||||
#define WL18XX_REG_COMMAND_MAILBOX_PTR (WL18XX_SCR_PAD0)
|
||||
#define WL18XX_REG_EVENT_MAILBOX_PTR (WL18XX_SCR_PAD1)
|
||||
#define WL18XX_EEPROMLESS_IND (WL18XX_SCR_PAD4)
|
||||
|
||||
#define WL18XX_WELP_ARM_COMMAND (WL18XX_REGISTERS_BASE + 0x7100)
|
||||
#define WL18XX_ENABLE (WL18XX_REGISTERS_BASE + 0x01543C)
|
||||
|
||||
/* PRCM registers */
|
||||
#define PLATFORM_DETECTION 0xA0E3E0
|
||||
#define OCS_EN 0xA02080
|
||||
#define PRIMARY_CLK_DETECT 0xA020A6
|
||||
#define PLLSH_WCS_PLL_N 0xA02362
|
||||
#define PLLSH_WCS_PLL_M 0xA02360
|
||||
#define PLLSH_WCS_PLL_Q_FACTOR_CFG_1 0xA02364
|
||||
#define PLLSH_WCS_PLL_Q_FACTOR_CFG_2 0xA02366
|
||||
#define PLLSH_WCS_PLL_P_FACTOR_CFG_1 0xA02368
|
||||
#define PLLSH_WCS_PLL_P_FACTOR_CFG_2 0xA0236A
|
||||
#define PLLSH_WCS_PLL_SWALLOW_EN 0xA0236C
|
||||
#define PLLSH_WL_PLL_EN 0xA02392
|
||||
|
||||
#define PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK 0xFFFF
|
||||
#define PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK 0x007F
|
||||
#define PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK 0xFFFF
|
||||
#define PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK 0x000F
|
||||
|
||||
#define PLLSH_WCS_PLL_SWALLOW_EN_VAL1 0x1
|
||||
#define PLLSH_WCS_PLL_SWALLOW_EN_VAL2 0x12
|
||||
|
||||
#define WL18XX_REG_FUSE_DATA_1_3 0xA0260C
|
||||
#define WL18XX_PG_VER_MASK 0x70
|
||||
#define WL18XX_PG_VER_OFFSET 4
|
||||
|
||||
#define WL18XX_REG_FUSE_BD_ADDR_1 0xA02602
|
||||
#define WL18XX_REG_FUSE_BD_ADDR_2 0xA02606
|
||||
|
||||
#define WL18XX_CMD_MBOX_ADDRESS 0xB007B4
|
||||
|
||||
#define WL18XX_FW_STATUS_ADDR 0x50F8
|
||||
|
||||
#define CHIP_ID_185x_PG10 (0x06030101)
|
||||
#define CHIP_ID_185x_PG20 (0x06030111)
|
||||
|
||||
/*
|
||||
* Host Command Interrupt. Setting this bit masks
|
||||
* the interrupt that the host issues to inform
|
||||
* the FW that it has sent a command
|
||||
* to the Wlan hardware Command Mailbox.
|
||||
*/
|
||||
#define WL18XX_INTR_TRIG_CMD BIT(28)
|
||||
|
||||
/*
|
||||
* Host Event Acknowlegde Interrupt. The host
|
||||
* sets this bit to acknowledge that it received
|
||||
* the unsolicited information from the event
|
||||
* mailbox.
|
||||
*/
|
||||
#define WL18XX_INTR_TRIG_EVENT_ACK BIT(29)
|
||||
|
||||
/*
|
||||
* To boot the firmware in PLT mode we need to write this value in
|
||||
* SCR_PAD8 before starting.
|
||||
*/
|
||||
#define WL18XX_SCR_PAD8_PLT 0xBABABEBE
|
||||
|
||||
enum {
|
||||
COMPONENT_NO_SWITCH = 0x0,
|
||||
COMPONENT_2_WAY_SWITCH = 0x1,
|
||||
COMPONENT_3_WAY_SWITCH = 0x2,
|
||||
COMPONENT_MATCHING = 0x3,
|
||||
};
|
||||
|
||||
enum {
|
||||
FEM_NONE = 0x0,
|
||||
FEM_VENDOR_1 = 0x1,
|
||||
FEM_VENDOR_2 = 0x2,
|
||||
FEM_VENDOR_3 = 0x3,
|
||||
};
|
||||
|
||||
enum {
|
||||
BOARD_TYPE_EVB_18XX = 0,
|
||||
BOARD_TYPE_DVP_18XX = 1,
|
||||
BOARD_TYPE_HDK_18XX = 2,
|
||||
BOARD_TYPE_FPGA_18XX = 3,
|
||||
BOARD_TYPE_COM8_18XX = 4,
|
||||
|
||||
NUM_BOARD_TYPES,
|
||||
};
|
||||
|
||||
#endif /* __REG_H__ */
|
127
drivers/net/wireless/ti/wl18xx/tx.c
Normal file
127
drivers/net/wireless/ti/wl18xx/tx.c
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../wlcore/wlcore.h"
|
||||
#include "../wlcore/cmd.h"
|
||||
#include "../wlcore/debug.h"
|
||||
#include "../wlcore/acx.h"
|
||||
#include "../wlcore/tx.h"
|
||||
|
||||
#include "wl18xx.h"
|
||||
#include "tx.h"
|
||||
|
||||
static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
|
||||
{
|
||||
struct ieee80211_tx_info *info;
|
||||
struct sk_buff *skb;
|
||||
int id = tx_stat_byte & WL18XX_TX_STATUS_DESC_ID_MASK;
|
||||
bool tx_success;
|
||||
|
||||
/* check for id legality */
|
||||
if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) {
|
||||
wl1271_warning("illegal id in tx completion: %d", id);
|
||||
return;
|
||||
}
|
||||
|
||||
/* a zero bit indicates Tx success */
|
||||
tx_success = !(tx_stat_byte & BIT(WL18XX_TX_STATUS_STAT_BIT_IDX));
|
||||
|
||||
|
||||
skb = wl->tx_frames[id];
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
if (wl12xx_is_dummy_packet(wl, skb)) {
|
||||
wl1271_free_tx_id(wl, id);
|
||||
return;
|
||||
}
|
||||
|
||||
/* update the TX status info */
|
||||
if (tx_success && !(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
|
||||
/* no real data about Tx completion */
|
||||
info->status.rates[0].idx = -1;
|
||||
info->status.rates[0].count = 0;
|
||||
info->status.rates[0].flags = 0;
|
||||
info->status.ack_signal = -1;
|
||||
|
||||
if (!tx_success)
|
||||
wl->stats.retry_count++;
|
||||
|
||||
/*
|
||||
* TODO: update sequence number for encryption? seems to be
|
||||
* unsupported for now. needed for recovery with encryption.
|
||||
*/
|
||||
|
||||
/* remove private header from packet */
|
||||
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
|
||||
|
||||
/* remove TKIP header space if present */
|
||||
if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
|
||||
info->control.hw_key &&
|
||||
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
|
||||
int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
|
||||
memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data, hdrlen);
|
||||
skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p success %d",
|
||||
id, skb, tx_success);
|
||||
|
||||
/* return the packet to the stack */
|
||||
skb_queue_tail(&wl->deferred_tx_queue, skb);
|
||||
queue_work(wl->freezable_wq, &wl->netstack_work);
|
||||
wl1271_free_tx_id(wl, id);
|
||||
}
|
||||
|
||||
void wl18xx_tx_immediate_complete(struct wl1271 *wl)
|
||||
{
|
||||
struct wl18xx_fw_status_priv *status_priv =
|
||||
(struct wl18xx_fw_status_priv *)wl->fw_status_2->priv;
|
||||
struct wl18xx_priv *priv = wl->priv;
|
||||
u8 i;
|
||||
|
||||
/* nothing to do here */
|
||||
if (priv->last_fw_rls_idx == status_priv->fw_release_idx)
|
||||
return;
|
||||
|
||||
/* freed Tx descriptors */
|
||||
wl1271_debug(DEBUG_TX, "last released desc = %d, current idx = %d",
|
||||
priv->last_fw_rls_idx, status_priv->fw_release_idx);
|
||||
|
||||
if (status_priv->fw_release_idx >= WL18XX_FW_MAX_TX_STATUS_DESC) {
|
||||
wl1271_error("invalid desc release index %d",
|
||||
status_priv->fw_release_idx);
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = priv->last_fw_rls_idx;
|
||||
i != status_priv->fw_release_idx;
|
||||
i = (i + 1) % WL18XX_FW_MAX_TX_STATUS_DESC) {
|
||||
wl18xx_tx_complete_packet(wl,
|
||||
status_priv->released_tx_desc[i]);
|
||||
|
||||
wl->tx_results_count++;
|
||||
}
|
||||
|
||||
priv->last_fw_rls_idx = status_priv->fw_release_idx;
|
||||
}
|
46
drivers/net/wireless/ti/wl18xx/tx.h
Normal file
46
drivers/net/wireless/ti/wl18xx/tx.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WL18XX_TX_H__
|
||||
#define __WL18XX_TX_H__
|
||||
|
||||
#include "../wlcore/wlcore.h"
|
||||
|
||||
#define WL18XX_TX_HW_BLOCK_SPARE 1
|
||||
/* for special cases - namely, TKIP and GEM */
|
||||
#define WL18XX_TX_HW_EXTRA_BLOCK_SPARE 2
|
||||
#define WL18XX_TX_HW_BLOCK_SIZE 268
|
||||
|
||||
#define WL18XX_TX_STATUS_DESC_ID_MASK 0x7F
|
||||
#define WL18XX_TX_STATUS_STAT_BIT_IDX 7
|
||||
|
||||
/* Indicates this TX HW frame is not padded to SDIO block size */
|
||||
#define WL18XX_TX_CTRL_NOT_PADDED BIT(7)
|
||||
|
||||
/*
|
||||
* The FW uses a special bit to indicate a wide channel should be used in
|
||||
* the rate policy.
|
||||
*/
|
||||
#define CONF_TX_RATE_USE_WIDE_CHAN BIT(31)
|
||||
|
||||
void wl18xx_tx_immediate_complete(struct wl1271 *wl);
|
||||
|
||||
#endif /* __WL12XX_TX_H__ */
|
88
drivers/net/wireless/ti/wl18xx/wl18xx.h
Normal file
88
drivers/net/wireless/ti/wl18xx/wl18xx.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WL18XX_PRIV_H__
|
||||
#define __WL18XX_PRIV_H__
|
||||
|
||||
#include "conf.h"
|
||||
|
||||
#define WL18XX_CMD_MAX_SIZE 740
|
||||
|
||||
struct wl18xx_priv {
|
||||
/* buffer for sending commands to FW */
|
||||
u8 cmd_buf[WL18XX_CMD_MAX_SIZE];
|
||||
|
||||
struct wl18xx_priv_conf conf;
|
||||
|
||||
/* Index of last released Tx desc in FW */
|
||||
u8 last_fw_rls_idx;
|
||||
|
||||
/* number of VIFs requiring extra spare mem-blocks */
|
||||
int extra_spare_vif_count;
|
||||
};
|
||||
|
||||
#define WL18XX_FW_MAX_TX_STATUS_DESC 33
|
||||
|
||||
struct wl18xx_fw_status_priv {
|
||||
/*
|
||||
* Index in released_tx_desc for first byte that holds
|
||||
* released tx host desc
|
||||
*/
|
||||
u8 fw_release_idx;
|
||||
|
||||
/*
|
||||
* Array of host Tx descriptors, where fw_release_idx
|
||||
* indicated the first released idx.
|
||||
*/
|
||||
u8 released_tx_desc[WL18XX_FW_MAX_TX_STATUS_DESC];
|
||||
|
||||
u8 padding[2];
|
||||
};
|
||||
|
||||
#define WL18XX_PHY_VERSION_MAX_LEN 20
|
||||
|
||||
struct wl18xx_static_data_priv {
|
||||
char phy_version[WL18XX_PHY_VERSION_MAX_LEN];
|
||||
};
|
||||
|
||||
struct wl18xx_clk_cfg {
|
||||
u32 n;
|
||||
u32 m;
|
||||
u32 p;
|
||||
u32 q;
|
||||
bool swallow;
|
||||
};
|
||||
|
||||
enum {
|
||||
CLOCK_CONFIG_16_2_M = 1,
|
||||
CLOCK_CONFIG_16_368_M,
|
||||
CLOCK_CONFIG_16_8_M,
|
||||
CLOCK_CONFIG_19_2_M,
|
||||
CLOCK_CONFIG_26_M,
|
||||
CLOCK_CONFIG_32_736_M,
|
||||
CLOCK_CONFIG_33_6_M,
|
||||
CLOCK_CONFIG_38_468_M,
|
||||
CLOCK_CONFIG_52_M,
|
||||
|
||||
NUM_CLOCK_CONFIGS,
|
||||
};
|
||||
|
||||
#endif /* __WL18XX_PRIV_H__ */
|
@ -86,6 +86,7 @@ out:
|
||||
kfree(auth);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wl1271_acx_sleep_auth);
|
||||
|
||||
int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
int power)
|
||||
@ -708,14 +709,14 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
|
||||
int wl1271_acx_statistics(struct wl1271 *wl, void *stats)
|
||||
{
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "acx statistics");
|
||||
|
||||
ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats,
|
||||
sizeof(*stats));
|
||||
wl->stats.fw_stats_len);
|
||||
if (ret < 0) {
|
||||
wl1271_warning("acx statistics failed: %d", ret);
|
||||
return -ENOMEM;
|
||||
@ -997,6 +998,7 @@ out:
|
||||
kfree(mem_conf);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wl12xx_acx_mem_cfg);
|
||||
|
||||
int wl1271_acx_init_mem_config(struct wl1271 *wl)
|
||||
{
|
||||
@ -1027,6 +1029,7 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wl1271_acx_init_mem_config);
|
||||
|
||||
int wl1271_acx_init_rx_interrupt(struct wl1271 *wl)
|
||||
{
|
||||
@ -1150,6 +1153,7 @@ out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wl1271_acx_pm_config);
|
||||
|
||||
int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable)
|
||||
|
@ -51,21 +51,18 @@
|
||||
#define WL1271_ACX_INTR_TRACE_A BIT(7)
|
||||
/* Trace message on MBOX #B */
|
||||
#define WL1271_ACX_INTR_TRACE_B BIT(8)
|
||||
/* SW FW Initiated interrupt Watchdog timer expiration */
|
||||
#define WL1271_ACX_SW_INTR_WATCHDOG BIT(9)
|
||||
|
||||
#define WL1271_ACX_INTR_ALL 0xFFFFFFFF
|
||||
#define WL1271_ACX_ALL_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \
|
||||
WL1271_ACX_INTR_INIT_COMPLETE | \
|
||||
WL1271_ACX_INTR_EVENT_A | \
|
||||
WL1271_ACX_INTR_EVENT_B | \
|
||||
WL1271_ACX_INTR_CMD_COMPLETE | \
|
||||
WL1271_ACX_INTR_HW_AVAILABLE | \
|
||||
WL1271_ACX_INTR_DATA)
|
||||
#define WL1271_ACX_INTR_ALL 0xFFFFFFFF
|
||||
|
||||
#define WL1271_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \
|
||||
WL1271_ACX_INTR_EVENT_A | \
|
||||
WL1271_ACX_INTR_EVENT_B | \
|
||||
WL1271_ACX_INTR_HW_AVAILABLE | \
|
||||
WL1271_ACX_INTR_DATA)
|
||||
/* all possible interrupts - only appropriate ones will be masked in */
|
||||
#define WLCORE_ALL_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \
|
||||
WL1271_ACX_INTR_EVENT_A | \
|
||||
WL1271_ACX_INTR_EVENT_B | \
|
||||
WL1271_ACX_INTR_HW_AVAILABLE | \
|
||||
WL1271_ACX_INTR_DATA | \
|
||||
WL1271_ACX_SW_INTR_WATCHDOG)
|
||||
|
||||
/* Target's information element */
|
||||
struct acx_header {
|
||||
@ -417,228 +414,6 @@ struct acx_ctsprotect {
|
||||
u8 padding[2];
|
||||
} __packed;
|
||||
|
||||
struct acx_tx_statistics {
|
||||
__le32 internal_desc_overflow;
|
||||
} __packed;
|
||||
|
||||
struct acx_rx_statistics {
|
||||
__le32 out_of_mem;
|
||||
__le32 hdr_overflow;
|
||||
__le32 hw_stuck;
|
||||
__le32 dropped;
|
||||
__le32 fcs_err;
|
||||
__le32 xfr_hint_trig;
|
||||
__le32 path_reset;
|
||||
__le32 reset_counter;
|
||||
} __packed;
|
||||
|
||||
struct acx_dma_statistics {
|
||||
__le32 rx_requested;
|
||||
__le32 rx_errors;
|
||||
__le32 tx_requested;
|
||||
__le32 tx_errors;
|
||||
} __packed;
|
||||
|
||||
struct acx_isr_statistics {
|
||||
/* host command complete */
|
||||
__le32 cmd_cmplt;
|
||||
|
||||
/* fiqisr() */
|
||||
__le32 fiqs;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_RX_HEADER) */
|
||||
__le32 rx_headers;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_RX_CMPLT) */
|
||||
__le32 rx_completes;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */
|
||||
__le32 rx_mem_overflow;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_S_RX_RDY) */
|
||||
__le32 rx_rdys;
|
||||
|
||||
/* irqisr() */
|
||||
__le32 irqs;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_TX_PROC) */
|
||||
__le32 tx_procs;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */
|
||||
__le32 decrypt_done;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_DMA0) */
|
||||
__le32 dma0_done;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_DMA1) */
|
||||
__le32 dma1_done;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */
|
||||
__le32 tx_exch_complete;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_COMMAND) */
|
||||
__le32 commands;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_RX_PROC) */
|
||||
__le32 rx_procs;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_PM_802) */
|
||||
__le32 hw_pm_mode_changes;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */
|
||||
__le32 host_acknowledges;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_PM_PCI) */
|
||||
__le32 pci_pm;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */
|
||||
__le32 wakeups;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
|
||||
__le32 low_rssi;
|
||||
} __packed;
|
||||
|
||||
struct acx_wep_statistics {
|
||||
/* WEP address keys configured */
|
||||
__le32 addr_key_count;
|
||||
|
||||
/* default keys configured */
|
||||
__le32 default_key_count;
|
||||
|
||||
__le32 reserved;
|
||||
|
||||
/* number of times that WEP key not found on lookup */
|
||||
__le32 key_not_found;
|
||||
|
||||
/* number of times that WEP key decryption failed */
|
||||
__le32 decrypt_fail;
|
||||
|
||||
/* WEP packets decrypted */
|
||||
__le32 packets;
|
||||
|
||||
/* WEP decrypt interrupts */
|
||||
__le32 interrupt;
|
||||
} __packed;
|
||||
|
||||
#define ACX_MISSED_BEACONS_SPREAD 10
|
||||
|
||||
struct acx_pwr_statistics {
|
||||
/* the amount of enters into power save mode (both PD & ELP) */
|
||||
__le32 ps_enter;
|
||||
|
||||
/* the amount of enters into ELP mode */
|
||||
__le32 elp_enter;
|
||||
|
||||
/* the amount of missing beacon interrupts to the host */
|
||||
__le32 missing_bcns;
|
||||
|
||||
/* the amount of wake on host-access times */
|
||||
__le32 wake_on_host;
|
||||
|
||||
/* the amount of wake on timer-expire */
|
||||
__le32 wake_on_timer_exp;
|
||||
|
||||
/* the number of packets that were transmitted with PS bit set */
|
||||
__le32 tx_with_ps;
|
||||
|
||||
/* the number of packets that were transmitted with PS bit clear */
|
||||
__le32 tx_without_ps;
|
||||
|
||||
/* the number of received beacons */
|
||||
__le32 rcvd_beacons;
|
||||
|
||||
/* the number of entering into PowerOn (power save off) */
|
||||
__le32 power_save_off;
|
||||
|
||||
/* the number of entries into power save mode */
|
||||
__le16 enable_ps;
|
||||
|
||||
/*
|
||||
* the number of exits from power save, not including failed PS
|
||||
* transitions
|
||||
*/
|
||||
__le16 disable_ps;
|
||||
|
||||
/*
|
||||
* the number of times the TSF counter was adjusted because
|
||||
* of drift
|
||||
*/
|
||||
__le32 fix_tsf_ps;
|
||||
|
||||
/* Gives statistics about the spread continuous missed beacons.
|
||||
* The 16 LSB are dedicated for the PS mode.
|
||||
* The 16 MSB are dedicated for the PS mode.
|
||||
* cont_miss_bcns_spread[0] - single missed beacon.
|
||||
* cont_miss_bcns_spread[1] - two continuous missed beacons.
|
||||
* cont_miss_bcns_spread[2] - three continuous missed beacons.
|
||||
* ...
|
||||
* cont_miss_bcns_spread[9] - ten and more continuous missed beacons.
|
||||
*/
|
||||
__le32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD];
|
||||
|
||||
/* the number of beacons in awake mode */
|
||||
__le32 rcvd_awake_beacons;
|
||||
} __packed;
|
||||
|
||||
struct acx_mic_statistics {
|
||||
__le32 rx_pkts;
|
||||
__le32 calc_failure;
|
||||
} __packed;
|
||||
|
||||
struct acx_aes_statistics {
|
||||
__le32 encrypt_fail;
|
||||
__le32 decrypt_fail;
|
||||
__le32 encrypt_packets;
|
||||
__le32 decrypt_packets;
|
||||
__le32 encrypt_interrupt;
|
||||
__le32 decrypt_interrupt;
|
||||
} __packed;
|
||||
|
||||
struct acx_event_statistics {
|
||||
__le32 heart_beat;
|
||||
__le32 calibration;
|
||||
__le32 rx_mismatch;
|
||||
__le32 rx_mem_empty;
|
||||
__le32 rx_pool;
|
||||
__le32 oom_late;
|
||||
__le32 phy_transmit_error;
|
||||
__le32 tx_stuck;
|
||||
} __packed;
|
||||
|
||||
struct acx_ps_statistics {
|
||||
__le32 pspoll_timeouts;
|
||||
__le32 upsd_timeouts;
|
||||
__le32 upsd_max_sptime;
|
||||
__le32 upsd_max_apturn;
|
||||
__le32 pspoll_max_apturn;
|
||||
__le32 pspoll_utilization;
|
||||
__le32 upsd_utilization;
|
||||
} __packed;
|
||||
|
||||
struct acx_rxpipe_statistics {
|
||||
__le32 rx_prep_beacon_drop;
|
||||
__le32 descr_host_int_trig_rx_data;
|
||||
__le32 beacon_buffer_thres_host_int_trig_rx_data;
|
||||
__le32 missed_beacon_host_int_trig_rx_data;
|
||||
__le32 tx_xfr_host_int_trig_rx_data;
|
||||
} __packed;
|
||||
|
||||
struct acx_statistics {
|
||||
struct acx_header header;
|
||||
|
||||
struct acx_tx_statistics tx;
|
||||
struct acx_rx_statistics rx;
|
||||
struct acx_dma_statistics dma;
|
||||
struct acx_isr_statistics isr;
|
||||
struct acx_wep_statistics wep;
|
||||
struct acx_pwr_statistics pwr;
|
||||
struct acx_aes_statistics aes;
|
||||
struct acx_mic_statistics mic;
|
||||
struct acx_event_statistics event;
|
||||
struct acx_ps_statistics ps;
|
||||
struct acx_rxpipe_statistics rxpipe;
|
||||
} __packed;
|
||||
|
||||
struct acx_rate_class {
|
||||
__le32 enabled_rates;
|
||||
u8 short_retry_limit;
|
||||
@ -828,6 +603,8 @@ struct wl1271_acx_keep_alive_config {
|
||||
#define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0)
|
||||
#define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1)
|
||||
#define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3)
|
||||
#define HOST_IF_CFG_RX_PAD_TO_SDIO_BLK BIT(4)
|
||||
#define HOST_IF_CFG_ADD_RX_ALIGNMENT BIT(6)
|
||||
|
||||
enum {
|
||||
WL1271_ACX_TRIG_TYPE_LEVEL = 0,
|
||||
@ -946,7 +723,7 @@ struct wl1271_acx_ht_information {
|
||||
u8 padding[2];
|
||||
} __packed;
|
||||
|
||||
#define RX_BA_MAX_SESSIONS 2
|
||||
#define RX_BA_MAX_SESSIONS 3
|
||||
|
||||
struct wl1271_acx_ba_initiator_policy {
|
||||
struct acx_header header;
|
||||
@ -1243,6 +1020,7 @@ enum {
|
||||
ACX_CONFIG_HANGOVER = 0x0042,
|
||||
ACX_FEATURE_CFG = 0x0043,
|
||||
ACX_PROTECTION_CFG = 0x0044,
|
||||
ACX_CHECKSUM_CONFIG = 0x0045,
|
||||
};
|
||||
|
||||
|
||||
@ -1281,7 +1059,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum acx_preamble_type preamble);
|
||||
int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum acx_ctsprotect_type ctsprotect);
|
||||
int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
|
||||
int wl1271_acx_statistics(struct wl1271 *wl, void *stats);
|
||||
int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
|
||||
u8 idx);
|
||||
|
@ -45,10 +45,17 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
|
||||
wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl);
|
||||
}
|
||||
|
||||
static int wlcore_parse_fw_ver(struct wl1271 *wl)
|
||||
static int wlcore_boot_parse_fw_ver(struct wl1271 *wl,
|
||||
struct wl1271_static_data *static_data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
strncpy(wl->chip.fw_ver_str, static_data->fw_version,
|
||||
sizeof(wl->chip.fw_ver_str));
|
||||
|
||||
/* make sure the string is NULL-terminated */
|
||||
wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0';
|
||||
|
||||
ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u",
|
||||
&wl->chip.fw_ver[0], &wl->chip.fw_ver[1],
|
||||
&wl->chip.fw_ver[2], &wl->chip.fw_ver[3],
|
||||
@ -57,43 +64,43 @@ static int wlcore_parse_fw_ver(struct wl1271 *wl)
|
||||
if (ret != 5) {
|
||||
wl1271_warning("fw version incorrect value");
|
||||
memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver));
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wlcore_identify_fw(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
goto out;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wlcore_boot_fw_version(struct wl1271 *wl)
|
||||
static int wlcore_boot_static_data(struct wl1271 *wl)
|
||||
{
|
||||
struct wl1271_static_data *static_data;
|
||||
size_t len = sizeof(*static_data) + wl->static_data_priv_len;
|
||||
int ret;
|
||||
|
||||
static_data = kmalloc(sizeof(*static_data), GFP_KERNEL | GFP_DMA);
|
||||
static_data = kmalloc(len, GFP_KERNEL);
|
||||
if (!static_data) {
|
||||
wl1271_error("Couldn't allocate memory for static data!");
|
||||
return -ENOMEM;
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_read(wl, wl->cmd_box_addr, static_data, sizeof(*static_data),
|
||||
false);
|
||||
wl1271_read(wl, wl->cmd_box_addr, static_data, len, false);
|
||||
|
||||
strncpy(wl->chip.fw_ver_str, static_data->fw_version,
|
||||
sizeof(wl->chip.fw_ver_str));
|
||||
|
||||
kfree(static_data);
|
||||
|
||||
/* make sure the string is NULL-terminated */
|
||||
wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0';
|
||||
|
||||
ret = wlcore_parse_fw_ver(wl);
|
||||
ret = wlcore_boot_parse_fw_ver(wl, static_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto out_free;
|
||||
|
||||
return 0;
|
||||
ret = wlcore_handle_static_data(wl, static_data);
|
||||
if (ret < 0)
|
||||
goto out_free;
|
||||
|
||||
out_free:
|
||||
kfree(static_data);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
|
||||
@ -204,8 +211,10 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
|
||||
u32 dest_addr, val;
|
||||
u8 *nvs_ptr, *nvs_aligned;
|
||||
|
||||
if (wl->nvs == NULL)
|
||||
if (wl->nvs == NULL) {
|
||||
wl1271_error("NVS file is needed during boot");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (wl->quirks & WLCORE_QUIRK_LEGACY_NVS) {
|
||||
struct wl1271_nvs_file *nvs =
|
||||
@ -400,9 +409,9 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
|
||||
wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x",
|
||||
wl->mbox_ptr[0], wl->mbox_ptr[1]);
|
||||
|
||||
ret = wlcore_boot_fw_version(wl);
|
||||
ret = wlcore_boot_static_data(wl);
|
||||
if (ret < 0) {
|
||||
wl1271_error("couldn't boot firmware");
|
||||
wl1271_error("error getting static data");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@ struct wl1271_static_data {
|
||||
u8 fw_version[WL1271_FW_VERSION_MAX_LEN];
|
||||
u32 hw_version;
|
||||
u8 tx_power_table[WL1271_NO_SUBBANDS][WL1271_NO_POWER_LEVELS];
|
||||
u8 priv[0];
|
||||
};
|
||||
|
||||
/* number of times we try to read the INIT interrupt */
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "cmd.h"
|
||||
#include "event.h"
|
||||
#include "tx.h"
|
||||
#include "hw_ops.h"
|
||||
|
||||
#define WL1271_CMD_FAST_POLL_COUNT 50
|
||||
|
||||
@ -291,6 +292,23 @@ static int wl12xx_get_new_session_id(struct wl1271 *wl,
|
||||
return wlvif->session_counter;
|
||||
}
|
||||
|
||||
static u8 wlcore_get_native_channel_type(u8 nl_channel_type)
|
||||
{
|
||||
switch (nl_channel_type) {
|
||||
case NL80211_CHAN_NO_HT:
|
||||
return WLCORE_CHAN_NO_HT;
|
||||
case NL80211_CHAN_HT20:
|
||||
return WLCORE_CHAN_HT20;
|
||||
case NL80211_CHAN_HT40MINUS:
|
||||
return WLCORE_CHAN_HT40MINUS;
|
||||
case NL80211_CHAN_HT40PLUS:
|
||||
return WLCORE_CHAN_HT40PLUS;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return WLCORE_CHAN_NO_HT;
|
||||
}
|
||||
}
|
||||
|
||||
static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
@ -407,6 +425,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len);
|
||||
memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN);
|
||||
cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set);
|
||||
cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type);
|
||||
|
||||
if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) {
|
||||
ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid);
|
||||
@ -482,6 +501,7 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
struct wl12xx_cmd_role_start *cmd;
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
u32 supported_rates;
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id);
|
||||
@ -519,6 +539,7 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
/* FIXME: Change when adding DFS */
|
||||
cmd->ap.reset_tsf = 1; /* By default reset AP TSF */
|
||||
cmd->channel = wlvif->channel;
|
||||
cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type);
|
||||
|
||||
if (!bss_conf->hidden_ssid) {
|
||||
/* take the SSID from the beacon for backward compatibility */
|
||||
@ -531,7 +552,13 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len);
|
||||
}
|
||||
|
||||
cmd->ap.local_rates = cpu_to_le32(0xffffffff);
|
||||
supported_rates = CONF_TX_AP_ENABLED_RATES | CONF_TX_MCS_RATES |
|
||||
wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start ap with supported_rates 0x%08x",
|
||||
supported_rates);
|
||||
|
||||
cmd->ap.local_rates = cpu_to_le32(supported_rates);
|
||||
|
||||
switch (wlvif->band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
@ -797,6 +824,7 @@ out:
|
||||
kfree(cmd);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wl1271_cmd_data_path);
|
||||
|
||||
int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 ps_mode, u16 auto_ps_timeout)
|
||||
@ -1018,7 +1046,7 @@ out:
|
||||
|
||||
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret, extra;
|
||||
int ret, extra = 0;
|
||||
u16 fc;
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct sk_buff *skb;
|
||||
@ -1057,7 +1085,8 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
/* encryption space */
|
||||
switch (wlvif->encryption_type) {
|
||||
case KEY_TKIP:
|
||||
extra = WL1271_EXTRA_SPACE_TKIP;
|
||||
if (wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE)
|
||||
extra = WL1271_EXTRA_SPACE_TKIP;
|
||||
break;
|
||||
case KEY_AES:
|
||||
extra = WL1271_EXTRA_SPACE_AES;
|
||||
@ -1346,13 +1375,18 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
|
||||
for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++)
|
||||
if (sta->wme && (sta->uapsd_queues & BIT(i)))
|
||||
cmd->psd_type[i] = WL1271_PSD_UPSD_TRIGGER;
|
||||
cmd->psd_type[NUM_ACCESS_CATEGORIES_COPY-1-i] =
|
||||
WL1271_PSD_UPSD_TRIGGER;
|
||||
else
|
||||
cmd->psd_type[i] = WL1271_PSD_LEGACY;
|
||||
cmd->psd_type[NUM_ACCESS_CATEGORIES_COPY-1-i] =
|
||||
WL1271_PSD_LEGACY;
|
||||
|
||||
|
||||
sta_rates = sta->supp_rates[wlvif->band];
|
||||
if (sta->ht_cap.ht_supported)
|
||||
sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET;
|
||||
sta_rates |=
|
||||
(sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET) |
|
||||
(sta->ht_cap.mcs.rx_mask[1] << HW_MIMO_RATES_OFFSET);
|
||||
|
||||
cmd->supported_rates =
|
||||
cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates,
|
||||
@ -1573,19 +1607,25 @@ out:
|
||||
int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id)
|
||||
{
|
||||
int ret = 0;
|
||||
bool is_first_roc;
|
||||
|
||||
if (WARN_ON(test_bit(role_id, wl->roc_map)))
|
||||
return 0;
|
||||
|
||||
is_first_roc = (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) >=
|
||||
WL12XX_MAX_ROLES);
|
||||
|
||||
ret = wl12xx_cmd_roc(wl, wlvif, role_id);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl1271_cmd_wait_for_event(wl,
|
||||
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID);
|
||||
if (ret < 0) {
|
||||
wl1271_error("cmd roc event completion error");
|
||||
goto out;
|
||||
if (is_first_roc) {
|
||||
ret = wl1271_cmd_wait_for_event(wl,
|
||||
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID);
|
||||
if (ret < 0) {
|
||||
wl1271_error("cmd roc event completion error");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
__set_bit(role_id, wl->roc_map);
|
||||
|
@ -192,7 +192,7 @@ enum cmd_templ {
|
||||
#define WL1271_COMMAND_TIMEOUT 2000
|
||||
#define WL1271_CMD_TEMPL_DFLT_SIZE 252
|
||||
#define WL1271_CMD_TEMPL_MAX_SIZE 512
|
||||
#define WL1271_EVENT_TIMEOUT 750
|
||||
#define WL1271_EVENT_TIMEOUT 1000
|
||||
|
||||
struct wl1271_cmd_header {
|
||||
__le16 id;
|
||||
@ -266,13 +266,22 @@ enum wlcore_band {
|
||||
WLCORE_BAND_MAX_RADIO = 0x7F,
|
||||
};
|
||||
|
||||
enum wlcore_channel_type {
|
||||
WLCORE_CHAN_NO_HT,
|
||||
WLCORE_CHAN_HT20,
|
||||
WLCORE_CHAN_HT40MINUS,
|
||||
WLCORE_CHAN_HT40PLUS
|
||||
};
|
||||
|
||||
struct wl12xx_cmd_role_start {
|
||||
struct wl1271_cmd_header header;
|
||||
|
||||
u8 role_id;
|
||||
u8 band;
|
||||
u8 channel;
|
||||
u8 padding;
|
||||
|
||||
/* enum wlcore_channel_type */
|
||||
u8 channel_type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
|
@ -45,7 +45,15 @@ enum {
|
||||
CONF_HW_BIT_RATE_MCS_4 = BIT(17),
|
||||
CONF_HW_BIT_RATE_MCS_5 = BIT(18),
|
||||
CONF_HW_BIT_RATE_MCS_6 = BIT(19),
|
||||
CONF_HW_BIT_RATE_MCS_7 = BIT(20)
|
||||
CONF_HW_BIT_RATE_MCS_7 = BIT(20),
|
||||
CONF_HW_BIT_RATE_MCS_8 = BIT(21),
|
||||
CONF_HW_BIT_RATE_MCS_9 = BIT(22),
|
||||
CONF_HW_BIT_RATE_MCS_10 = BIT(23),
|
||||
CONF_HW_BIT_RATE_MCS_11 = BIT(24),
|
||||
CONF_HW_BIT_RATE_MCS_12 = BIT(25),
|
||||
CONF_HW_BIT_RATE_MCS_13 = BIT(26),
|
||||
CONF_HW_BIT_RATE_MCS_14 = BIT(27),
|
||||
CONF_HW_BIT_RATE_MCS_15 = BIT(28),
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -310,7 +318,7 @@ enum {
|
||||
struct conf_sg_settings {
|
||||
u32 params[CONF_SG_PARAMS_MAX];
|
||||
u8 state;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
enum conf_rx_queue_type {
|
||||
CONF_RX_QUEUE_TYPE_LOW_PRIORITY, /* All except the high priority */
|
||||
@ -394,7 +402,7 @@ struct conf_rx_settings {
|
||||
* Range: RX_QUEUE_TYPE_RX_LOW_PRIORITY, RX_QUEUE_TYPE_RX_HIGH_PRIORITY,
|
||||
*/
|
||||
u8 queue_type;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#define CONF_TX_MAX_RATE_CLASSES 10
|
||||
|
||||
@ -435,6 +443,12 @@ struct conf_rx_settings {
|
||||
CONF_HW_BIT_RATE_MCS_5 | CONF_HW_BIT_RATE_MCS_6 | \
|
||||
CONF_HW_BIT_RATE_MCS_7)
|
||||
|
||||
#define CONF_TX_MIMO_RATES (CONF_HW_BIT_RATE_MCS_8 | \
|
||||
CONF_HW_BIT_RATE_MCS_9 | CONF_HW_BIT_RATE_MCS_10 | \
|
||||
CONF_HW_BIT_RATE_MCS_11 | CONF_HW_BIT_RATE_MCS_12 | \
|
||||
CONF_HW_BIT_RATE_MCS_13 | CONF_HW_BIT_RATE_MCS_14 | \
|
||||
CONF_HW_BIT_RATE_MCS_15)
|
||||
|
||||
/*
|
||||
* Default rates for management traffic when operating in AP mode. This
|
||||
* should be configured according to the basic rate set of the AP
|
||||
@ -487,7 +501,7 @@ struct conf_tx_rate_class {
|
||||
* the policy (0 - long preamble, 1 - short preamble.
|
||||
*/
|
||||
u8 aflags;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#define CONF_TX_MAX_AC_COUNT 4
|
||||
|
||||
@ -504,7 +518,7 @@ enum conf_tx_ac {
|
||||
CONF_TX_AC_VI = 2, /* video */
|
||||
CONF_TX_AC_VO = 3, /* voice */
|
||||
CONF_TX_AC_CTS2SELF = 4, /* fictitious AC, follows AC_VO */
|
||||
CONF_TX_AC_ANY_TID = 0x1f
|
||||
CONF_TX_AC_ANY_TID = 0xff
|
||||
};
|
||||
|
||||
struct conf_tx_ac_category {
|
||||
@ -544,7 +558,7 @@ struct conf_tx_ac_category {
|
||||
* Range: u16
|
||||
*/
|
||||
u16 tx_op_limit;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#define CONF_TX_MAX_TID_COUNT 8
|
||||
|
||||
@ -578,7 +592,7 @@ struct conf_tx_tid {
|
||||
u8 ps_scheme;
|
||||
u8 ack_policy;
|
||||
u32 apsd_conf[2];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_tx_settings {
|
||||
/*
|
||||
@ -664,7 +678,7 @@ struct conf_tx_settings {
|
||||
|
||||
/* Time in ms for Tx watchdog timer to expire */
|
||||
u32 tx_watchdog_timeout;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
enum {
|
||||
CONF_WAKE_UP_EVENT_BEACON = 0x01, /* Wake on every Beacon*/
|
||||
@ -711,7 +725,7 @@ struct conf_bcn_filt_rule {
|
||||
* Version for the vendor specifie IE (221)
|
||||
*/
|
||||
u8 version[CONF_BCN_IE_VER_LEN];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#define CONF_MAX_RSSI_SNR_TRIGGERS 8
|
||||
|
||||
@ -762,7 +776,7 @@ struct conf_sig_weights {
|
||||
* Range: u8
|
||||
*/
|
||||
u8 snr_pkt_avg_weight;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
enum conf_bcn_filt_mode {
|
||||
CONF_BCN_FILT_MODE_DISABLED = 0,
|
||||
@ -810,7 +824,7 @@ struct conf_conn_settings {
|
||||
*
|
||||
* Range: CONF_BCN_FILT_MODE_*
|
||||
*/
|
||||
enum conf_bcn_filt_mode bcn_filt_mode;
|
||||
u8 bcn_filt_mode;
|
||||
|
||||
/*
|
||||
* Configure Beacon filter pass-thru rules.
|
||||
@ -937,7 +951,7 @@ struct conf_conn_settings {
|
||||
* Range: u16
|
||||
*/
|
||||
u8 max_listen_interval;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
enum {
|
||||
CONF_REF_CLK_19_2_E,
|
||||
@ -965,6 +979,11 @@ struct conf_itrim_settings {
|
||||
|
||||
/* moderation timeout in microsecs from the last TX */
|
||||
u32 timeout;
|
||||
} __packed;
|
||||
|
||||
enum conf_fast_wakeup {
|
||||
CONF_FAST_WAKEUP_ENABLE,
|
||||
CONF_FAST_WAKEUP_DISABLE,
|
||||
};
|
||||
|
||||
struct conf_pm_config_settings {
|
||||
@ -978,10 +997,10 @@ struct conf_pm_config_settings {
|
||||
/*
|
||||
* Host fast wakeup support
|
||||
*
|
||||
* Range: true, false
|
||||
* Range: enum conf_fast_wakeup
|
||||
*/
|
||||
bool host_fast_wakeup_support;
|
||||
};
|
||||
u8 host_fast_wakeup_support;
|
||||
} __packed;
|
||||
|
||||
struct conf_roam_trigger_settings {
|
||||
/*
|
||||
@ -1018,7 +1037,7 @@ struct conf_roam_trigger_settings {
|
||||
* Range: 0 - 255
|
||||
*/
|
||||
u8 avg_weight_snr_data;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_scan_settings {
|
||||
/*
|
||||
@ -1064,7 +1083,7 @@ struct conf_scan_settings {
|
||||
* Range: u32 Microsecs
|
||||
*/
|
||||
u32 split_scan_timeout;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_sched_scan_settings {
|
||||
/*
|
||||
@ -1102,7 +1121,7 @@ struct conf_sched_scan_settings {
|
||||
|
||||
/* SNR threshold to be used for filtering */
|
||||
s8 snr_threshold;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_ht_setting {
|
||||
u8 rx_ba_win_size;
|
||||
@ -1111,7 +1130,7 @@ struct conf_ht_setting {
|
||||
|
||||
/* bitmap of enabled TIDs for TX BA sessions */
|
||||
u8 tx_ba_tid_bitmap;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_memory_settings {
|
||||
/* Number of stations supported in IBSS mode */
|
||||
@ -1151,7 +1170,7 @@ struct conf_memory_settings {
|
||||
* Range: 0-120
|
||||
*/
|
||||
u8 tx_min;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_fm_coex {
|
||||
u8 enable;
|
||||
@ -1164,7 +1183,7 @@ struct conf_fm_coex {
|
||||
u16 ldo_stabilization_time;
|
||||
u8 fm_disturbed_band_margin;
|
||||
u8 swallow_clk_diff;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_rx_streaming_settings {
|
||||
/*
|
||||
@ -1193,7 +1212,7 @@ struct conf_rx_streaming_settings {
|
||||
* enable rx streaming also when there is no coex activity
|
||||
*/
|
||||
u8 always;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_fwlog {
|
||||
/* Continuous or on-demand */
|
||||
@ -1217,7 +1236,7 @@ struct conf_fwlog {
|
||||
|
||||
/* Regulates the frequency of log messages */
|
||||
u8 threshold;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#define ACX_RATE_MGMT_NUM_OF_RATES 13
|
||||
struct conf_rate_policy_settings {
|
||||
@ -1236,7 +1255,7 @@ struct conf_rate_policy_settings {
|
||||
u8 rate_check_up;
|
||||
u8 rate_check_down;
|
||||
u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_hangover_settings {
|
||||
u32 recover_time;
|
||||
@ -1250,7 +1269,23 @@ struct conf_hangover_settings {
|
||||
u8 quiet_time;
|
||||
u8 increase_time;
|
||||
u8 window_size;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* The conf version consists of 4 bytes. The two MSB are the wlcore
|
||||
* version, the two LSB are the lower driver's private conf
|
||||
* version.
|
||||
*/
|
||||
#define WLCORE_CONF_VERSION (0x0001 << 16)
|
||||
#define WLCORE_CONF_MASK 0xffff0000
|
||||
#define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \
|
||||
sizeof(struct wlcore_conf))
|
||||
|
||||
struct wlcore_conf_header {
|
||||
__le32 magic;
|
||||
__le32 version;
|
||||
__le32 checksum;
|
||||
} __packed;
|
||||
|
||||
struct wlcore_conf {
|
||||
struct conf_sg_settings sg;
|
||||
@ -1269,6 +1304,12 @@ struct wlcore_conf {
|
||||
struct conf_fwlog fwlog;
|
||||
struct conf_rate_policy_settings rate;
|
||||
struct conf_hangover_settings hangover;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct wlcore_conf_file {
|
||||
struct wlcore_conf_header header;
|
||||
struct wlcore_conf core;
|
||||
u8 priv[0];
|
||||
} __packed;
|
||||
|
||||
#endif
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "wlcore.h"
|
||||
#include "debug.h"
|
||||
@ -32,14 +33,14 @@
|
||||
#include "ps.h"
|
||||
#include "io.h"
|
||||
#include "tx.h"
|
||||
#include "hw_ops.h"
|
||||
|
||||
/* ms */
|
||||
#define WL1271_DEBUGFS_STATS_LIFETIME 1000
|
||||
|
||||
/* debugfs macros idea from mac80211 */
|
||||
#define DEBUGFS_FORMAT_BUFFER_SIZE 100
|
||||
static int wl1271_format_buffer(char __user *userbuf, size_t count,
|
||||
loff_t *ppos, char *fmt, ...)
|
||||
int wl1271_format_buffer(char __user *userbuf, size_t count,
|
||||
loff_t *ppos, char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buf[DEBUGFS_FORMAT_BUFFER_SIZE];
|
||||
@ -51,59 +52,9 @@ static int wl1271_format_buffer(char __user *userbuf, size_t count,
|
||||
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, res);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wl1271_format_buffer);
|
||||
|
||||
#define DEBUGFS_READONLY_FILE(name, fmt, value...) \
|
||||
static ssize_t name## _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, \
|
||||
fmt "\n", ##value); \
|
||||
} \
|
||||
\
|
||||
static const struct file_operations name## _ops = { \
|
||||
.read = name## _read, \
|
||||
.open = simple_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
};
|
||||
|
||||
#define DEBUGFS_ADD(name, parent) \
|
||||
entry = debugfs_create_file(#name, 0400, parent, \
|
||||
wl, &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, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct wl1271 *wl = file->private_data; \
|
||||
\
|
||||
wl1271_debugfs_update_stats(wl); \
|
||||
\
|
||||
return wl1271_format_buffer(userbuf, count, ppos, fmt "\n", \
|
||||
wl->stats.fw_stats->sub.name); \
|
||||
} \
|
||||
\
|
||||
static const struct file_operations sub## _ ##name## _ops = { \
|
||||
.read = sub## _ ##name## _read, \
|
||||
.open = simple_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
};
|
||||
|
||||
#define DEBUGFS_FWSTATS_ADD(sub, name) \
|
||||
DEBUGFS_ADD(sub## _ ##name, stats)
|
||||
|
||||
static void wl1271_debugfs_update_stats(struct wl1271 *wl)
|
||||
void wl1271_debugfs_update_stats(struct wl1271 *wl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -125,97 +76,7 @@ static void wl1271_debugfs_update_stats(struct wl1271 *wl)
|
||||
out:
|
||||
mutex_unlock(&wl->mutex);
|
||||
}
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(rx, out_of_mem, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rx, hw_stuck, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rx, dropped, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rx, fcs_err, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rx, path_reset, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rx, reset_counter, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(dma, rx_requested, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(dma, rx_errors, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(dma, tx_requested, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(dma, tx_errors, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, fiqs, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, rx_headers, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, rx_rdys, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, irqs, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, tx_procs, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, decrypt_done, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, dma0_done, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, dma1_done, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, commands, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, rx_procs, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, pci_pm, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, wakeups, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, low_rssi, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(wep, addr_key_count, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(wep, default_key_count, "%u");
|
||||
/* skipping wep.reserved */
|
||||
DEBUGFS_FWSTATS_FILE(wep, key_not_found, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(wep, packets, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(wep, interrupt, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(pwr, ps_enter, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, elp_enter, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, power_save_off, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, enable_ps, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, disable_ps, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, "%u");
|
||||
/* skipping cont_miss_bcns_spread for now */
|
||||
DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(mic, rx_pkts, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(mic, calc_failure, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(event, heart_beat, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(event, calibration, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(event, rx_mismatch, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(event, rx_pool, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(event, oom_late, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(event, tx_stuck, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, "%u");
|
||||
EXPORT_SYMBOL_GPL(wl1271_debugfs_update_stats);
|
||||
|
||||
DEBUGFS_READONLY_FILE(retry_count, "%u", wl->stats.retry_count);
|
||||
DEBUGFS_READONLY_FILE(excessive_retries, "%u",
|
||||
@ -241,6 +102,89 @@ static const struct file_operations tx_queue_len_ops = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static void chip_op_handler(struct wl1271 *wl, unsigned long value,
|
||||
void *arg)
|
||||
{
|
||||
int ret;
|
||||
int (*chip_op) (struct wl1271 *wl);
|
||||
|
||||
if (!arg) {
|
||||
wl1271_warning("debugfs chip_op_handler with no callback");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
chip_op = arg;
|
||||
chip_op(wl);
|
||||
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
}
|
||||
|
||||
|
||||
static inline void no_write_handler(struct wl1271 *wl,
|
||||
unsigned long value,
|
||||
unsigned long param)
|
||||
{
|
||||
}
|
||||
|
||||
#define WL12XX_CONF_DEBUGFS(param, conf_sub_struct, \
|
||||
min_val, max_val, write_handler_locked, \
|
||||
write_handler_arg) \
|
||||
static ssize_t param##_read(struct file *file, \
|
||||
char __user *user_buf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct wl1271 *wl = file->private_data; \
|
||||
return wl1271_format_buffer(user_buf, count, \
|
||||
ppos, "%d\n", \
|
||||
wl->conf.conf_sub_struct.param); \
|
||||
} \
|
||||
\
|
||||
static ssize_t param##_write(struct file *file, \
|
||||
const char __user *user_buf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct wl1271 *wl = file->private_data; \
|
||||
unsigned long value; \
|
||||
int ret; \
|
||||
\
|
||||
ret = kstrtoul_from_user(user_buf, count, 10, &value); \
|
||||
if (ret < 0) { \
|
||||
wl1271_warning("illegal value for " #param); \
|
||||
return -EINVAL; \
|
||||
} \
|
||||
\
|
||||
if (value < min_val || value > max_val) { \
|
||||
wl1271_warning(#param " is not in valid range"); \
|
||||
return -ERANGE; \
|
||||
} \
|
||||
\
|
||||
mutex_lock(&wl->mutex); \
|
||||
wl->conf.conf_sub_struct.param = value; \
|
||||
\
|
||||
write_handler_locked(wl, value, write_handler_arg); \
|
||||
\
|
||||
mutex_unlock(&wl->mutex); \
|
||||
return count; \
|
||||
} \
|
||||
\
|
||||
static const struct file_operations param##_ops = { \
|
||||
.read = param##_read, \
|
||||
.write = param##_write, \
|
||||
.open = simple_open, \
|
||||
.llseek = default_llseek, \
|
||||
};
|
||||
|
||||
WL12XX_CONF_DEBUGFS(irq_pkt_threshold, rx, 0, 65535,
|
||||
chip_op_handler, wl1271_acx_init_rx_interrupt)
|
||||
WL12XX_CONF_DEBUGFS(irq_blk_threshold, rx, 0, 65535,
|
||||
chip_op_handler, wl1271_acx_init_rx_interrupt)
|
||||
WL12XX_CONF_DEBUGFS(irq_timeout, rx, 0, 100,
|
||||
chip_op_handler, wl1271_acx_init_rx_interrupt)
|
||||
|
||||
static ssize_t gpio_power_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
@ -535,8 +479,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
|
||||
DRIVER_STATE_PRINT_LHEX(ap_ps_map);
|
||||
DRIVER_STATE_PRINT_HEX(quirks);
|
||||
DRIVER_STATE_PRINT_HEX(irq);
|
||||
DRIVER_STATE_PRINT_HEX(ref_clock);
|
||||
DRIVER_STATE_PRINT_HEX(tcxo_clock);
|
||||
/* TODO: ref_clock and tcxo_clock were moved to wl12xx priv */
|
||||
DRIVER_STATE_PRINT_HEX(hw_pg_ver);
|
||||
DRIVER_STATE_PRINT_HEX(platform_quirks);
|
||||
DRIVER_STATE_PRINT_HEX(chip.id);
|
||||
@ -647,7 +590,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
|
||||
VIF_STATE_PRINT_INT(last_rssi_event);
|
||||
VIF_STATE_PRINT_INT(ba_support);
|
||||
VIF_STATE_PRINT_INT(ba_allowed);
|
||||
VIF_STATE_PRINT_INT(is_gem);
|
||||
VIF_STATE_PRINT_LLHEX(tx_security_seq);
|
||||
VIF_STATE_PRINT_INT(tx_security_last_seq_lsb);
|
||||
}
|
||||
@ -1002,108 +944,30 @@ static const struct file_operations beacon_filtering_ops = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t fw_stats_raw_read(struct file *file,
|
||||
char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wl1271 *wl = file->private_data;
|
||||
|
||||
wl1271_debugfs_update_stats(wl);
|
||||
|
||||
return simple_read_from_buffer(userbuf, count, ppos,
|
||||
wl->stats.fw_stats,
|
||||
wl->stats.fw_stats_len);
|
||||
}
|
||||
|
||||
static const struct file_operations fw_stats_raw_ops = {
|
||||
.read = fw_stats_raw_read,
|
||||
.open = simple_open,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static int wl1271_debugfs_add_files(struct wl1271 *wl,
|
||||
struct dentry *rootdir)
|
||||
struct dentry *rootdir)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dentry *entry, *stats, *streaming;
|
||||
|
||||
stats = debugfs_create_dir("fw-statistics", rootdir);
|
||||
if (!stats || IS_ERR(stats)) {
|
||||
entry = stats;
|
||||
goto err;
|
||||
}
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(rx, out_of_mem);
|
||||
DEBUGFS_FWSTATS_ADD(rx, hdr_overflow);
|
||||
DEBUGFS_FWSTATS_ADD(rx, hw_stuck);
|
||||
DEBUGFS_FWSTATS_ADD(rx, dropped);
|
||||
DEBUGFS_FWSTATS_ADD(rx, fcs_err);
|
||||
DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig);
|
||||
DEBUGFS_FWSTATS_ADD(rx, path_reset);
|
||||
DEBUGFS_FWSTATS_ADD(rx, reset_counter);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(dma, rx_requested);
|
||||
DEBUGFS_FWSTATS_ADD(dma, rx_errors);
|
||||
DEBUGFS_FWSTATS_ADD(dma, tx_requested);
|
||||
DEBUGFS_FWSTATS_ADD(dma, tx_errors);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt);
|
||||
DEBUGFS_FWSTATS_ADD(isr, fiqs);
|
||||
DEBUGFS_FWSTATS_ADD(isr, rx_headers);
|
||||
DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow);
|
||||
DEBUGFS_FWSTATS_ADD(isr, rx_rdys);
|
||||
DEBUGFS_FWSTATS_ADD(isr, irqs);
|
||||
DEBUGFS_FWSTATS_ADD(isr, tx_procs);
|
||||
DEBUGFS_FWSTATS_ADD(isr, decrypt_done);
|
||||
DEBUGFS_FWSTATS_ADD(isr, dma0_done);
|
||||
DEBUGFS_FWSTATS_ADD(isr, dma1_done);
|
||||
DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete);
|
||||
DEBUGFS_FWSTATS_ADD(isr, commands);
|
||||
DEBUGFS_FWSTATS_ADD(isr, rx_procs);
|
||||
DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes);
|
||||
DEBUGFS_FWSTATS_ADD(isr, host_acknowledges);
|
||||
DEBUGFS_FWSTATS_ADD(isr, pci_pm);
|
||||
DEBUGFS_FWSTATS_ADD(isr, wakeups);
|
||||
DEBUGFS_FWSTATS_ADD(isr, low_rssi);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(wep, addr_key_count);
|
||||
DEBUGFS_FWSTATS_ADD(wep, default_key_count);
|
||||
/* skipping wep.reserved */
|
||||
DEBUGFS_FWSTATS_ADD(wep, key_not_found);
|
||||
DEBUGFS_FWSTATS_ADD(wep, decrypt_fail);
|
||||
DEBUGFS_FWSTATS_ADD(wep, packets);
|
||||
DEBUGFS_FWSTATS_ADD(wep, interrupt);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(pwr, ps_enter);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, elp_enter);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, missing_bcns);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, wake_on_host);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, power_save_off);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, enable_ps);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, disable_ps);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps);
|
||||
/* skipping cont_miss_bcns_spread for now */
|
||||
DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(mic, rx_pkts);
|
||||
DEBUGFS_FWSTATS_ADD(mic, calc_failure);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(aes, encrypt_fail);
|
||||
DEBUGFS_FWSTATS_ADD(aes, decrypt_fail);
|
||||
DEBUGFS_FWSTATS_ADD(aes, encrypt_packets);
|
||||
DEBUGFS_FWSTATS_ADD(aes, decrypt_packets);
|
||||
DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt);
|
||||
DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(event, heart_beat);
|
||||
DEBUGFS_FWSTATS_ADD(event, calibration);
|
||||
DEBUGFS_FWSTATS_ADD(event, rx_mismatch);
|
||||
DEBUGFS_FWSTATS_ADD(event, rx_mem_empty);
|
||||
DEBUGFS_FWSTATS_ADD(event, rx_pool);
|
||||
DEBUGFS_FWSTATS_ADD(event, oom_late);
|
||||
DEBUGFS_FWSTATS_ADD(event, phy_transmit_error);
|
||||
DEBUGFS_FWSTATS_ADD(event, tx_stuck);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts);
|
||||
DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts);
|
||||
DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime);
|
||||
DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn);
|
||||
DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn);
|
||||
DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization);
|
||||
DEBUGFS_FWSTATS_ADD(ps, upsd_utilization);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
|
||||
struct dentry *entry, *streaming;
|
||||
|
||||
DEBUGFS_ADD(tx_queue_len, rootdir);
|
||||
DEBUGFS_ADD(retry_count, rootdir);
|
||||
@ -1120,6 +984,10 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
|
||||
DEBUGFS_ADD(dynamic_ps_timeout, rootdir);
|
||||
DEBUGFS_ADD(forced_ps, rootdir);
|
||||
DEBUGFS_ADD(split_scan_timeout, rootdir);
|
||||
DEBUGFS_ADD(irq_pkt_threshold, rootdir);
|
||||
DEBUGFS_ADD(irq_blk_threshold, rootdir);
|
||||
DEBUGFS_ADD(irq_timeout, rootdir);
|
||||
DEBUGFS_ADD(fw_stats_raw, rootdir);
|
||||
|
||||
streaming = debugfs_create_dir("rx_streaming", rootdir);
|
||||
if (!streaming || IS_ERR(streaming))
|
||||
@ -1145,7 +1013,7 @@ void wl1271_debugfs_reset(struct wl1271 *wl)
|
||||
if (!wl->stats.fw_stats)
|
||||
return;
|
||||
|
||||
memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats));
|
||||
memset(wl->stats.fw_stats, 0, wl->stats.fw_stats_len);
|
||||
wl->stats.retry_count = 0;
|
||||
wl->stats.excessive_retries = 0;
|
||||
}
|
||||
@ -1160,34 +1028,34 @@ int wl1271_debugfs_init(struct wl1271 *wl)
|
||||
|
||||
if (IS_ERR(rootdir)) {
|
||||
ret = PTR_ERR(rootdir);
|
||||
goto err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats),
|
||||
GFP_KERNEL);
|
||||
|
||||
wl->stats.fw_stats = kzalloc(wl->stats.fw_stats_len, GFP_KERNEL);
|
||||
if (!wl->stats.fw_stats) {
|
||||
ret = -ENOMEM;
|
||||
goto err_fw;
|
||||
goto out_remove;
|
||||
}
|
||||
|
||||
wl->stats.fw_stats_update = jiffies;
|
||||
|
||||
ret = wl1271_debugfs_add_files(wl, rootdir);
|
||||
|
||||
if (ret < 0)
|
||||
goto err_file;
|
||||
goto out_exit;
|
||||
|
||||
return 0;
|
||||
ret = wlcore_debugfs_init(wl, rootdir);
|
||||
if (ret < 0)
|
||||
goto out_exit;
|
||||
|
||||
err_file:
|
||||
kfree(wl->stats.fw_stats);
|
||||
wl->stats.fw_stats = NULL;
|
||||
goto out;
|
||||
|
||||
err_fw:
|
||||
out_exit:
|
||||
wl1271_debugfs_exit(wl);
|
||||
|
||||
out_remove:
|
||||
debugfs_remove_recursive(rootdir);
|
||||
|
||||
err:
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,95 @@
|
||||
|
||||
#include "wlcore.h"
|
||||
|
||||
int wl1271_format_buffer(char __user *userbuf, size_t count,
|
||||
loff_t *ppos, char *fmt, ...);
|
||||
|
||||
int wl1271_debugfs_init(struct wl1271 *wl);
|
||||
void wl1271_debugfs_exit(struct wl1271 *wl);
|
||||
void wl1271_debugfs_reset(struct wl1271 *wl);
|
||||
void wl1271_debugfs_update_stats(struct wl1271 *wl);
|
||||
|
||||
#define DEBUGFS_FORMAT_BUFFER_SIZE 256
|
||||
|
||||
#define DEBUGFS_READONLY_FILE(name, fmt, value...) \
|
||||
static ssize_t name## _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, \
|
||||
fmt "\n", ##value); \
|
||||
} \
|
||||
\
|
||||
static const struct file_operations name## _ops = { \
|
||||
.read = name## _read, \
|
||||
.open = simple_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
};
|
||||
|
||||
#define DEBUGFS_ADD(name, parent) \
|
||||
do { \
|
||||
entry = debugfs_create_file(#name, 0400, parent, \
|
||||
wl, &name## _ops); \
|
||||
if (!entry || IS_ERR(entry)) \
|
||||
goto err; \
|
||||
} while (0);
|
||||
|
||||
|
||||
#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, struct_type) \
|
||||
static ssize_t sub## _ ##name## _read(struct file *file, \
|
||||
char __user *userbuf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct wl1271 *wl = file->private_data; \
|
||||
struct struct_type *stats = wl->stats.fw_stats; \
|
||||
\
|
||||
wl1271_debugfs_update_stats(wl); \
|
||||
\
|
||||
return wl1271_format_buffer(userbuf, count, ppos, fmt "\n", \
|
||||
stats->sub.name); \
|
||||
} \
|
||||
\
|
||||
static const struct file_operations sub## _ ##name## _ops = { \
|
||||
.read = sub## _ ##name## _read, \
|
||||
.open = simple_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
};
|
||||
|
||||
#define DEBUGFS_FWSTATS_FILE_ARRAY(sub, name, len, struct_type) \
|
||||
static ssize_t sub## _ ##name## _read(struct file *file, \
|
||||
char __user *userbuf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct wl1271 *wl = file->private_data; \
|
||||
struct struct_type *stats = wl->stats.fw_stats; \
|
||||
char buf[DEBUGFS_FORMAT_BUFFER_SIZE] = ""; \
|
||||
int res, i; \
|
||||
\
|
||||
wl1271_debugfs_update_stats(wl); \
|
||||
\
|
||||
for (i = 0; i < len; i++) \
|
||||
res = snprintf(buf, sizeof(buf), "%s[%d] = %d\n", \
|
||||
buf, i, stats->sub.name[i]); \
|
||||
\
|
||||
return wl1271_format_buffer(userbuf, count, ppos, "%s", buf); \
|
||||
} \
|
||||
\
|
||||
static const struct file_operations sub## _ ##name## _ops = { \
|
||||
.read = sub## _ ##name## _read, \
|
||||
.open = simple_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
};
|
||||
|
||||
#define DEBUGFS_FWSTATS_ADD(sub, name) \
|
||||
DEBUGFS_ADD(sub## _ ##name, stats)
|
||||
|
||||
|
||||
#endif /* WL1271_DEBUGFS_H */
|
||||
|
@ -148,15 +148,33 @@ static int wl1271_event_process(struct wl1271 *wl)
|
||||
int delay = wl->conf.conn.synch_fail_thold *
|
||||
wl->conf.conn.bss_lose_timeout;
|
||||
wl1271_info("Beacon loss detected.");
|
||||
cancel_delayed_work_sync(&wl->connection_loss_work);
|
||||
|
||||
/*
|
||||
* if the work is already queued, it should take place. We
|
||||
* don't want to delay the connection loss indication
|
||||
* any more.
|
||||
*/
|
||||
ieee80211_queue_delayed_work(wl->hw, &wl->connection_loss_work,
|
||||
msecs_to_jiffies(delay));
|
||||
msecs_to_jiffies(delay));
|
||||
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
|
||||
ieee80211_cqm_rssi_notify(
|
||||
vif,
|
||||
NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
|
||||
GFP_KERNEL);
|
||||
}
|
||||
}
|
||||
|
||||
if (vector & REGAINED_BSS_EVENT_ID) {
|
||||
/* TODO: check for multi-role */
|
||||
wl1271_info("Beacon regained.");
|
||||
cancel_delayed_work_sync(&wl->connection_loss_work);
|
||||
cancel_delayed_work(&wl->connection_loss_work);
|
||||
|
||||
/* sanity check - we can't lose and gain the beacon together */
|
||||
WARN(vector & BSS_LOSE_EVENT_ID,
|
||||
"Concurrent beacon loss and gain from FW");
|
||||
}
|
||||
|
||||
if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
|
||||
|
@ -119,4 +119,82 @@ static inline int wlcore_identify_fw(struct wl1271 *wl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
wlcore_hw_set_tx_desc_csum(struct wl1271 *wl,
|
||||
struct wl1271_tx_hw_descr *desc,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
if (!wl->ops->set_tx_desc_csum)
|
||||
BUG_ON(1);
|
||||
|
||||
wl->ops->set_tx_desc_csum(wl, desc, skb);
|
||||
}
|
||||
|
||||
static inline void
|
||||
wlcore_hw_set_rx_csum(struct wl1271 *wl,
|
||||
struct wl1271_rx_descriptor *desc,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
if (wl->ops->set_rx_csum)
|
||||
wl->ops->set_rx_csum(wl, desc, skb);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
wlcore_hw_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
if (wl->ops->ap_get_mimo_wide_rate_mask)
|
||||
return wl->ops->ap_get_mimo_wide_rate_mask(wl, wlvif);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
wlcore_debugfs_init(struct wl1271 *wl, struct dentry *rootdir)
|
||||
{
|
||||
if (wl->ops->debugfs_init)
|
||||
return wl->ops->debugfs_init(wl, rootdir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
wlcore_handle_static_data(struct wl1271 *wl, void *static_data)
|
||||
{
|
||||
if (wl->ops->handle_static_data)
|
||||
return wl->ops->handle_static_data(wl, static_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
wlcore_hw_get_spare_blocks(struct wl1271 *wl, bool is_gem)
|
||||
{
|
||||
if (!wl->ops->get_spare_blocks)
|
||||
BUG_ON(1);
|
||||
|
||||
return wl->ops->get_spare_blocks(wl, is_gem);
|
||||
}
|
||||
|
||||
static inline int
|
||||
wlcore_hw_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key_conf)
|
||||
{
|
||||
if (!wl->ops->set_key)
|
||||
BUG_ON(1);
|
||||
|
||||
return wl->ops->set_key(wl, cmd, vif, sta, key_conf);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
wlcore_hw_pre_pkt_send(struct wl1271 *wl, u32 buf_offset, u32 last_len)
|
||||
{
|
||||
if (wl->ops->pre_pkt_send)
|
||||
return wl->ops->pre_pkt_send(wl, buf_offset, last_len);
|
||||
|
||||
return buf_offset;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -460,6 +460,9 @@ int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
/* unconditionally enable HT rates */
|
||||
supported_rates |= CONF_TX_MCS_RATES;
|
||||
|
||||
/* get extra MIMO or wide-chan rates where the HW supports it */
|
||||
supported_rates |= wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
|
||||
|
||||
/* configure unicast TX rate classes */
|
||||
for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
|
||||
rc.enabled_rates = supported_rates;
|
||||
|
@ -320,46 +320,6 @@ static void wlcore_adjust_conf(struct wl1271 *wl)
|
||||
}
|
||||
}
|
||||
|
||||
static int wl1271_plt_init(struct wl1271 *wl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl->ops->hw_init(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_init_mem_config(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl12xx_acx_mem_cfg(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Enable data path */
|
||||
ret = wl1271_cmd_data_path(wl, 1);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Configure for CAM power saving (ie. always active) */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* configure PM */
|
||||
ret = wl1271_acx_pm_config(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_memmap:
|
||||
kfree(wl->target_mem_map);
|
||||
wl->target_mem_map = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
u8 hlid, u8 tx_pkts)
|
||||
@ -387,7 +347,7 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
|
||||
|
||||
static void wl12xx_irq_update_links_status(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct wl_fw_status *status)
|
||||
struct wl_fw_status_2 *status)
|
||||
{
|
||||
struct wl1271_link *lnk;
|
||||
u32 cur_fw_ps_map;
|
||||
@ -419,7 +379,8 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl,
|
||||
}
|
||||
|
||||
static void wl12xx_fw_status(struct wl1271 *wl,
|
||||
struct wl_fw_status *status)
|
||||
struct wl_fw_status_1 *status_1,
|
||||
struct wl_fw_status_2 *status_2)
|
||||
{
|
||||
struct wl12xx_vif *wlvif;
|
||||
struct timespec ts;
|
||||
@ -428,37 +389,38 @@ static void wl12xx_fw_status(struct wl1271 *wl,
|
||||
int i;
|
||||
size_t status_len;
|
||||
|
||||
status_len = sizeof(*status) + wl->fw_status_priv_len;
|
||||
status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
|
||||
sizeof(*status_2) + wl->fw_status_priv_len;
|
||||
|
||||
wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status,
|
||||
wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1,
|
||||
status_len, false);
|
||||
|
||||
wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
|
||||
"drv_rx_counter = %d, tx_results_counter = %d)",
|
||||
status->intr,
|
||||
status->fw_rx_counter,
|
||||
status->drv_rx_counter,
|
||||
status->tx_results_counter);
|
||||
status_1->intr,
|
||||
status_1->fw_rx_counter,
|
||||
status_1->drv_rx_counter,
|
||||
status_1->tx_results_counter);
|
||||
|
||||
for (i = 0; i < NUM_TX_QUEUES; i++) {
|
||||
/* prevent wrap-around in freed-packets counter */
|
||||
wl->tx_allocated_pkts[i] -=
|
||||
(status->counters.tx_released_pkts[i] -
|
||||
(status_2->counters.tx_released_pkts[i] -
|
||||
wl->tx_pkts_freed[i]) & 0xff;
|
||||
|
||||
wl->tx_pkts_freed[i] = status->counters.tx_released_pkts[i];
|
||||
wl->tx_pkts_freed[i] = status_2->counters.tx_released_pkts[i];
|
||||
}
|
||||
|
||||
/* prevent wrap-around in total blocks counter */
|
||||
if (likely(wl->tx_blocks_freed <=
|
||||
le32_to_cpu(status->total_released_blks)))
|
||||
freed_blocks = le32_to_cpu(status->total_released_blks) -
|
||||
le32_to_cpu(status_2->total_released_blks)))
|
||||
freed_blocks = le32_to_cpu(status_2->total_released_blks) -
|
||||
wl->tx_blocks_freed;
|
||||
else
|
||||
freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
|
||||
le32_to_cpu(status->total_released_blks);
|
||||
le32_to_cpu(status_2->total_released_blks);
|
||||
|
||||
wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
|
||||
wl->tx_blocks_freed = le32_to_cpu(status_2->total_released_blks);
|
||||
|
||||
wl->tx_allocated_blocks -= freed_blocks;
|
||||
|
||||
@ -474,7 +436,7 @@ static void wl12xx_fw_status(struct wl1271 *wl,
|
||||
cancel_delayed_work(&wl->tx_watchdog_work);
|
||||
}
|
||||
|
||||
avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
|
||||
avail = le32_to_cpu(status_2->tx_total) - wl->tx_allocated_blocks;
|
||||
|
||||
/*
|
||||
* The FW might change the total number of TX memblocks before
|
||||
@ -493,13 +455,13 @@ static void wl12xx_fw_status(struct wl1271 *wl,
|
||||
|
||||
/* for AP update num of allocated TX blocks per link and ps status */
|
||||
wl12xx_for_each_wlvif_ap(wl, wlvif) {
|
||||
wl12xx_irq_update_links_status(wl, wlvif, status);
|
||||
wl12xx_irq_update_links_status(wl, wlvif, status_2);
|
||||
}
|
||||
|
||||
/* update the host-chipset time offset */
|
||||
getnstimeofday(&ts);
|
||||
wl->time_offset = (timespec_to_ns(&ts) >> 10) -
|
||||
(s64)le32_to_cpu(status->fw_localtime);
|
||||
(s64)le32_to_cpu(status_2->fw_localtime);
|
||||
}
|
||||
|
||||
static void wl1271_flush_deferred_work(struct wl1271 *wl)
|
||||
@ -568,20 +530,30 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
|
||||
clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
|
||||
smp_mb__after_clear_bit();
|
||||
|
||||
wl12xx_fw_status(wl, wl->fw_status);
|
||||
wl12xx_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
|
||||
|
||||
wlcore_hw_tx_immediate_compl(wl);
|
||||
|
||||
intr = le32_to_cpu(wl->fw_status->intr);
|
||||
intr &= WL1271_INTR_MASK;
|
||||
intr = le32_to_cpu(wl->fw_status_1->intr);
|
||||
intr &= WLCORE_ALL_INTR_MASK;
|
||||
if (!intr) {
|
||||
done = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
|
||||
wl1271_error("watchdog interrupt received! "
|
||||
wl1271_error("HW watchdog interrupt received! starting recovery.");
|
||||
wl->watchdog_recovery = true;
|
||||
wl12xx_queue_recovery_work(wl);
|
||||
|
||||
/* restarting the chip. ignore any other interrupt. */
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(intr & WL1271_ACX_SW_INTR_WATCHDOG)) {
|
||||
wl1271_error("SW watchdog interrupt received! "
|
||||
"starting recovery.");
|
||||
wl->watchdog_recovery = true;
|
||||
wl12xx_queue_recovery_work(wl);
|
||||
|
||||
/* restarting the chip. ignore any other interrupt. */
|
||||
@ -591,7 +563,7 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
|
||||
if (likely(intr & WL1271_ACX_INTR_DATA)) {
|
||||
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
|
||||
|
||||
wl12xx_rx(wl, wl->fw_status);
|
||||
wl12xx_rx(wl, wl->fw_status_1);
|
||||
|
||||
/* Check if any tx blocks were freed */
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
@ -743,7 +715,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_fetch_nvs(struct wl1271 *wl)
|
||||
static void wl1271_fetch_nvs(struct wl1271 *wl)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
int ret;
|
||||
@ -751,16 +723,15 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
|
||||
ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
|
||||
|
||||
if (ret < 0) {
|
||||
wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
|
||||
ret);
|
||||
return ret;
|
||||
wl1271_debug(DEBUG_BOOT, "could not get nvs file %s: %d",
|
||||
WL12XX_NVS_NAME, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
|
||||
|
||||
if (!wl->nvs) {
|
||||
wl1271_error("could not allocate memory for the nvs file");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -768,8 +739,6 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
|
||||
|
||||
out:
|
||||
release_firmware(fw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void wl12xx_queue_recovery_work(struct wl1271 *wl)
|
||||
@ -820,14 +789,16 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
|
||||
|
||||
/*
|
||||
* Make sure the chip is awake and the logger isn't active.
|
||||
* This might fail if the firmware hanged.
|
||||
* Do not send a stop fwlog command if the fw is hanged.
|
||||
*/
|
||||
if (!wl1271_ps_elp_wakeup(wl))
|
||||
if (!wl1271_ps_elp_wakeup(wl) && !wl->watchdog_recovery)
|
||||
wl12xx_cmd_stop_fwlog(wl);
|
||||
else
|
||||
goto out;
|
||||
|
||||
/* Read the first memory block address */
|
||||
wl12xx_fw_status(wl, wl->fw_status);
|
||||
first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
|
||||
wl12xx_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
|
||||
first_addr = le32_to_cpu(wl->fw_status_2->log_start_addr);
|
||||
if (!first_addr)
|
||||
goto out;
|
||||
|
||||
@ -872,9 +843,14 @@ static void wl1271_recovery_work(struct work_struct *work)
|
||||
|
||||
wl12xx_read_fwlog_panic(wl);
|
||||
|
||||
wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
|
||||
/* change partitions momentarily so we can read the FW pc */
|
||||
wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
|
||||
wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x "
|
||||
"hint_sts: 0x%08x",
|
||||
wl->chip.fw_ver_str,
|
||||
wlcore_read_reg(wl, REG_PC_ON_RECOVERY));
|
||||
wlcore_read_reg(wl, REG_PC_ON_RECOVERY),
|
||||
wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR));
|
||||
wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
|
||||
|
||||
BUG_ON(bug_on_recovery &&
|
||||
!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
|
||||
@ -885,8 +861,6 @@ static void wl1271_recovery_work(struct work_struct *work)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
BUG_ON(bug_on_recovery);
|
||||
|
||||
/*
|
||||
* Advance security sequence number to overcome potential progress
|
||||
* in the firmware during recovery. This doens't hurt if the network is
|
||||
@ -900,7 +874,7 @@ static void wl1271_recovery_work(struct work_struct *work)
|
||||
}
|
||||
|
||||
/* Prevent spurious TX during FW restart */
|
||||
ieee80211_stop_queues(wl->hw);
|
||||
wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
|
||||
|
||||
if (wl->sched_scanning) {
|
||||
ieee80211_sched_scan_stopped(wl->hw);
|
||||
@ -914,6 +888,7 @@ static void wl1271_recovery_work(struct work_struct *work)
|
||||
vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
__wl1271_op_remove_interface(wl, vif, false);
|
||||
}
|
||||
wl->watchdog_recovery = false;
|
||||
mutex_unlock(&wl->mutex);
|
||||
wl1271_op_stop(wl->hw);
|
||||
|
||||
@ -925,9 +900,10 @@ static void wl1271_recovery_work(struct work_struct *work)
|
||||
* Its safe to enable TX now - the queues are stopped after a request
|
||||
* to restart the HW.
|
||||
*/
|
||||
ieee80211_wake_queues(wl->hw);
|
||||
wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
|
||||
return;
|
||||
out_unlock:
|
||||
wl->watchdog_recovery = false;
|
||||
mutex_unlock(&wl->mutex);
|
||||
}
|
||||
|
||||
@ -938,13 +914,19 @@ static void wl1271_fw_wakeup(struct wl1271 *wl)
|
||||
|
||||
static int wl1271_setup(struct wl1271 *wl)
|
||||
{
|
||||
wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
|
||||
if (!wl->fw_status)
|
||||
wl->fw_status_1 = kmalloc(WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
|
||||
sizeof(*wl->fw_status_2) +
|
||||
wl->fw_status_priv_len, GFP_KERNEL);
|
||||
if (!wl->fw_status_1)
|
||||
return -ENOMEM;
|
||||
|
||||
wl->fw_status_2 = (struct wl_fw_status_2 *)
|
||||
(((u8 *) wl->fw_status_1) +
|
||||
WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc));
|
||||
|
||||
wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
|
||||
if (!wl->tx_res_if) {
|
||||
kfree(wl->fw_status);
|
||||
kfree(wl->fw_status_1);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -987,13 +969,12 @@ static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
|
||||
* simplify the code and since the performance impact is
|
||||
* negligible, we use the same block size for all different
|
||||
* chip types.
|
||||
*
|
||||
* Check if the bus supports blocksize alignment and, if it
|
||||
* doesn't, make sure we don't have the quirk.
|
||||
*/
|
||||
if (wl1271_set_block_size(wl))
|
||||
wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
|
||||
|
||||
ret = wl->ops->identify_chip(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (!wl1271_set_block_size(wl))
|
||||
wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
|
||||
|
||||
/* TODO: make sure the lower driver has set things up correctly */
|
||||
|
||||
@ -1005,13 +986,6 @@ static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* No NVS from netlink, try to get it from the filesystem */
|
||||
if (wl->nvs == NULL) {
|
||||
ret = wl1271_fetch_nvs(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@ -1039,14 +1013,10 @@ int wl1271_plt_start(struct wl1271 *wl)
|
||||
if (ret < 0)
|
||||
goto power_off;
|
||||
|
||||
ret = wl->ops->boot(wl);
|
||||
ret = wl->ops->plt_init(wl);
|
||||
if (ret < 0)
|
||||
goto power_off;
|
||||
|
||||
ret = wl1271_plt_init(wl);
|
||||
if (ret < 0)
|
||||
goto irq_disable;
|
||||
|
||||
wl->plt = true;
|
||||
wl->state = WL1271_STATE_ON;
|
||||
wl1271_notice("firmware booted in PLT mode (%s)",
|
||||
@ -1059,19 +1029,6 @@ int wl1271_plt_start(struct wl1271 *wl)
|
||||
|
||||
goto out;
|
||||
|
||||
irq_disable:
|
||||
mutex_unlock(&wl->mutex);
|
||||
/* Unlocking the mutex in the middle of handling is
|
||||
inherently unsafe. In this case we deem it safe to do,
|
||||
because we need to let any possibly pending IRQ out of
|
||||
the system (and while we are WL1271_STATE_OFF the IRQ
|
||||
work function will not do anything.) Also, any other
|
||||
possible concurrent operations will fail due to the
|
||||
current state, hence the wl1271 struct should be safe. */
|
||||
wlcore_disable_interrupts(wl);
|
||||
wl1271_flush_deferred_work(wl);
|
||||
cancel_work_sync(&wl->netstack_work);
|
||||
mutex_lock(&wl->mutex);
|
||||
power_off:
|
||||
wl1271_power_off(wl);
|
||||
}
|
||||
@ -1154,9 +1111,16 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
|
||||
/* queue the packet */
|
||||
/*
|
||||
* drop the packet if the link is invalid or the queue is stopped
|
||||
* for any reason but watermark. Watermark is a "soft"-stop so we
|
||||
* allow these packets through.
|
||||
*/
|
||||
if (hlid == WL12XX_INVALID_LINK_ID ||
|
||||
(wlvif && !test_bit(hlid, wlvif->links_map))) {
|
||||
(wlvif && !test_bit(hlid, wlvif->links_map)) ||
|
||||
(wlcore_is_queue_stopped(wl, q) &&
|
||||
!wlcore_is_queue_stopped_by_reason(wl, q,
|
||||
WLCORE_QUEUE_STOP_REASON_WATERMARK))) {
|
||||
wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
|
||||
ieee80211_free_txskb(hw, skb);
|
||||
goto out;
|
||||
@ -1174,8 +1138,8 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
*/
|
||||
if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
|
||||
wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
|
||||
ieee80211_stop_queue(wl->hw, mapping);
|
||||
set_bit(q, &wl->stopped_queues_map);
|
||||
wlcore_stop_queue_locked(wl, q,
|
||||
WLCORE_QUEUE_STOP_REASON_WATERMARK);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1758,7 +1722,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
|
||||
cancel_delayed_work_sync(&wl->connection_loss_work);
|
||||
|
||||
/* let's notify MAC80211 about the remaining pending TX frames */
|
||||
wl12xx_tx_reset(wl, true);
|
||||
wl12xx_tx_reset(wl);
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
wl1271_power_off(wl);
|
||||
@ -1767,6 +1731,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
|
||||
|
||||
wl->rx_counter = 0;
|
||||
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
|
||||
wl->channel_type = NL80211_CHAN_NO_HT;
|
||||
wl->tx_blocks_available = 0;
|
||||
wl->tx_allocated_blocks = 0;
|
||||
wl->tx_results_count = 0;
|
||||
@ -1799,8 +1764,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
|
||||
|
||||
wl1271_debugfs_reset(wl);
|
||||
|
||||
kfree(wl->fw_status);
|
||||
wl->fw_status = NULL;
|
||||
kfree(wl->fw_status_1);
|
||||
wl->fw_status_1 = NULL;
|
||||
wl->fw_status_2 = NULL;
|
||||
kfree(wl->tx_res_if);
|
||||
wl->tx_res_if = NULL;
|
||||
kfree(wl->target_mem_map);
|
||||
@ -1894,6 +1860,9 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||
wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
|
||||
wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
|
||||
wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
|
||||
wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
|
||||
wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
|
||||
wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
|
||||
} else {
|
||||
/* init ap data */
|
||||
wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
|
||||
@ -1903,13 +1872,19 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||
for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
|
||||
wl12xx_allocate_rate_policy(wl,
|
||||
&wlvif->ap.ucast_rate_idx[i]);
|
||||
wlvif->basic_rate_set = CONF_TX_AP_ENABLED_RATES;
|
||||
/*
|
||||
* TODO: check if basic_rate shouldn't be
|
||||
* wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
* instead (the same thing for STA above).
|
||||
*/
|
||||
wlvif->basic_rate = CONF_TX_AP_ENABLED_RATES;
|
||||
/* TODO: this seems to be used only for STA, check it */
|
||||
wlvif->rate_set = CONF_TX_AP_ENABLED_RATES;
|
||||
}
|
||||
|
||||
wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
|
||||
wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
|
||||
wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
|
||||
wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
|
||||
wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
|
||||
wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
|
||||
|
||||
/*
|
||||
@ -1919,6 +1894,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||
wlvif->band = wl->band;
|
||||
wlvif->channel = wl->channel;
|
||||
wlvif->power_level = wl->power_level;
|
||||
wlvif->channel_type = wl->channel_type;
|
||||
|
||||
INIT_WORK(&wlvif->rx_streaming_enable_work,
|
||||
wl1271_rx_streaming_enable_work);
|
||||
@ -2444,7 +2420,7 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
} else {
|
||||
/* The current firmware only supports sched_scan in idle */
|
||||
if (wl->sched_scanning) {
|
||||
wl1271_scan_sched_scan_stop(wl);
|
||||
wl1271_scan_sched_scan_stop(wl, wlvif);
|
||||
ieee80211_sched_scan_stopped(wl->hw);
|
||||
}
|
||||
|
||||
@ -2469,13 +2445,20 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
/* if the channel changes while joined, join again */
|
||||
if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
|
||||
((wlvif->band != conf->channel->band) ||
|
||||
(wlvif->channel != channel))) {
|
||||
(wlvif->channel != channel) ||
|
||||
(wlvif->channel_type != conf->channel_type))) {
|
||||
/* send all pending packets */
|
||||
wl1271_tx_work_locked(wl);
|
||||
wlvif->band = conf->channel->band;
|
||||
wlvif->channel = channel;
|
||||
wlvif->channel_type = conf->channel_type;
|
||||
|
||||
if (!is_ap) {
|
||||
if (is_ap) {
|
||||
ret = wl1271_init_ap_rates(wl, wlvif);
|
||||
if (ret < 0)
|
||||
wl1271_error("AP rate policy change failed %d",
|
||||
ret);
|
||||
} else {
|
||||
/*
|
||||
* FIXME: the mac80211 should really provide a fixed
|
||||
* rate to use here. for now, just use the smallest
|
||||
@ -2583,8 +2566,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
|
||||
* frames, such as the deauth. To make sure those frames reach the air,
|
||||
* wait here until the TX queue is fully flushed.
|
||||
*/
|
||||
if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
|
||||
(conf->flags & IEEE80211_CONF_IDLE))
|
||||
if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) ||
|
||||
((changed & IEEE80211_CONF_CHANGE_IDLE) &&
|
||||
(conf->flags & IEEE80211_CONF_IDLE)))
|
||||
wl1271_tx_flush(wl);
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
@ -2593,6 +2577,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
|
||||
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
|
||||
wl->band = conf->channel->band;
|
||||
wl->channel = channel;
|
||||
wl->channel_type = conf->channel_type;
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_POWER)
|
||||
@ -2825,17 +2810,6 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
int ret;
|
||||
bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
|
||||
|
||||
/*
|
||||
* A role set to GEM cipher requires different Tx settings (namely
|
||||
* spare blocks). Note when we are in this mode so the HW can adjust.
|
||||
*/
|
||||
if (key_type == KEY_GEM) {
|
||||
if (action == KEY_ADD_OR_REPLACE)
|
||||
wlvif->is_gem = true;
|
||||
else if (action == KEY_REMOVE)
|
||||
wlvif->is_gem = false;
|
||||
}
|
||||
|
||||
if (is_ap) {
|
||||
struct wl1271_station *wl_sta;
|
||||
u8 hlid;
|
||||
@ -2913,12 +2887,21 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key_conf)
|
||||
{
|
||||
struct wl1271 *wl = hw->priv;
|
||||
|
||||
return wlcore_hw_set_key(wl, cmd, vif, sta, key_conf);
|
||||
}
|
||||
|
||||
int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key_conf)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
int ret;
|
||||
u32 tx_seq_32 = 0;
|
||||
@ -3029,6 +3012,7 @@ out_unlock:
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wlcore_set_key);
|
||||
|
||||
static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
@ -3167,6 +3151,7 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct wl1271 *wl = hw->priv;
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
|
||||
@ -3180,7 +3165,7 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
wl1271_scan_sched_scan_stop(wl);
|
||||
wl1271_scan_sched_scan_stop(wl, wlvif);
|
||||
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
out:
|
||||
@ -3316,8 +3301,15 @@ static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
|
||||
skb->data,
|
||||
skb->len, 0,
|
||||
rates);
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
wl1271_debug(DEBUG_AP, "probe response updated");
|
||||
set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -3422,6 +3414,87 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wlcore_set_beacon_template(struct wl1271 *wl,
|
||||
struct ieee80211_vif *vif,
|
||||
bool is_ap)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
struct ieee80211_hdr *hdr;
|
||||
u32 min_rate;
|
||||
int ret;
|
||||
int ieoffset = offsetof(struct ieee80211_mgmt,
|
||||
u.beacon.variable);
|
||||
struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
|
||||
u16 tmpl_id;
|
||||
|
||||
if (!beacon) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_MASTER, "beacon updated");
|
||||
|
||||
ret = wl1271_ssid_set(vif, beacon, ieoffset);
|
||||
if (ret < 0) {
|
||||
dev_kfree_skb(beacon);
|
||||
goto out;
|
||||
}
|
||||
min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
|
||||
CMD_TEMPL_BEACON;
|
||||
ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
|
||||
beacon->data,
|
||||
beacon->len, 0,
|
||||
min_rate);
|
||||
if (ret < 0) {
|
||||
dev_kfree_skb(beacon);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case we already have a probe-resp beacon set explicitly
|
||||
* by usermode, don't use the beacon data.
|
||||
*/
|
||||
if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
|
||||
goto end_bcn;
|
||||
|
||||
/* remove TIM ie from probe response */
|
||||
wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
|
||||
|
||||
/*
|
||||
* remove p2p ie from probe response.
|
||||
* the fw reponds to probe requests that don't include
|
||||
* the p2p ie. probe requests with p2p ie will be passed,
|
||||
* and will be responded by the supplicant (the spec
|
||||
* forbids including the p2p ie when responding to probe
|
||||
* requests that didn't include it).
|
||||
*/
|
||||
wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
|
||||
WLAN_OUI_TYPE_WFA_P2P, ieoffset);
|
||||
|
||||
hdr = (struct ieee80211_hdr *) beacon->data;
|
||||
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_PROBE_RESP);
|
||||
if (is_ap)
|
||||
ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
|
||||
beacon->data,
|
||||
beacon->len,
|
||||
min_rate);
|
||||
else
|
||||
ret = wl1271_cmd_template_set(wl, wlvif->role_id,
|
||||
CMD_TEMPL_PROBE_RESPONSE,
|
||||
beacon->data,
|
||||
beacon->len, 0,
|
||||
min_rate);
|
||||
end_bcn:
|
||||
dev_kfree_skb(beacon);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *bss_conf,
|
||||
@ -3440,81 +3513,12 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
|
||||
|
||||
if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
|
||||
u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
|
||||
wl1271_debug(DEBUG_AP, "probe response updated");
|
||||
set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
|
||||
}
|
||||
|
||||
wl1271_ap_set_probe_resp_tmpl(wl, rate, vif);
|
||||
}
|
||||
|
||||
if ((changed & BSS_CHANGED_BEACON)) {
|
||||
struct ieee80211_hdr *hdr;
|
||||
u32 min_rate;
|
||||
int ieoffset = offsetof(struct ieee80211_mgmt,
|
||||
u.beacon.variable);
|
||||
struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
|
||||
u16 tmpl_id;
|
||||
|
||||
if (!beacon) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_MASTER, "beacon updated");
|
||||
|
||||
ret = wl1271_ssid_set(vif, beacon, ieoffset);
|
||||
if (ret < 0) {
|
||||
dev_kfree_skb(beacon);
|
||||
goto out;
|
||||
}
|
||||
min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
|
||||
CMD_TEMPL_BEACON;
|
||||
ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
|
||||
beacon->data,
|
||||
beacon->len, 0,
|
||||
min_rate);
|
||||
if (ret < 0) {
|
||||
dev_kfree_skb(beacon);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case we already have a probe-resp beacon set explicitly
|
||||
* by usermode, don't use the beacon data.
|
||||
*/
|
||||
if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
|
||||
goto end_bcn;
|
||||
|
||||
/* remove TIM ie from probe response */
|
||||
wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
|
||||
|
||||
/*
|
||||
* remove p2p ie from probe response.
|
||||
* the fw reponds to probe requests that don't include
|
||||
* the p2p ie. probe requests with p2p ie will be passed,
|
||||
* and will be responded by the supplicant (the spec
|
||||
* forbids including the p2p ie when responding to probe
|
||||
* requests that didn't include it).
|
||||
*/
|
||||
wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
|
||||
WLAN_OUI_TYPE_WFA_P2P, ieoffset);
|
||||
|
||||
hdr = (struct ieee80211_hdr *) beacon->data;
|
||||
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_PROBE_RESP);
|
||||
if (is_ap)
|
||||
ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
|
||||
beacon->data,
|
||||
beacon->len,
|
||||
min_rate);
|
||||
else
|
||||
ret = wl1271_cmd_template_set(wl, wlvif->role_id,
|
||||
CMD_TEMPL_PROBE_RESPONSE,
|
||||
beacon->data,
|
||||
beacon->len, 0,
|
||||
min_rate);
|
||||
end_bcn:
|
||||
dev_kfree_skb(beacon);
|
||||
ret = wlcore_set_beacon_template(wl, vif, is_ap);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
@ -3551,6 +3555,14 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
|
||||
ret = wl1271_ap_init_templates(wl, vif);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl1271_ap_set_probe_resp_tmpl(wl, wlvif->basic_rate, vif);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wlcore_set_beacon_template(wl, vif, true);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
|
||||
@ -3691,7 +3703,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
|
||||
sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
|
||||
if (sta->ht_cap.ht_supported)
|
||||
sta_rate_set |=
|
||||
(sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
|
||||
(sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET) |
|
||||
(sta->ht_cap.mcs.rx_mask[1] << HW_MIMO_RATES_OFFSET);
|
||||
sta_ht_cap = sta->ht_cap;
|
||||
sta_exists = true;
|
||||
|
||||
@ -3704,13 +3717,11 @@ sta_not_found:
|
||||
u32 rates;
|
||||
int ieoffset;
|
||||
wlvif->aid = bss_conf->aid;
|
||||
wlvif->channel_type = bss_conf->channel_type;
|
||||
wlvif->beacon_int = bss_conf->beacon_int;
|
||||
do_join = true;
|
||||
set_assoc = true;
|
||||
|
||||
/* Cancel connection_loss_work */
|
||||
cancel_delayed_work_sync(&wl->connection_loss_work);
|
||||
|
||||
/*
|
||||
* use basic rates from AP, and determine lowest rate
|
||||
* to use with control frames.
|
||||
@ -3960,6 +3971,17 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
|
||||
wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
|
||||
(int)changed);
|
||||
|
||||
/*
|
||||
* make sure to cancel pending disconnections if our association
|
||||
* state changed
|
||||
*/
|
||||
if (!is_ap && (changed & BSS_CHANGED_ASSOC))
|
||||
cancel_delayed_work_sync(&wl->connection_loss_work);
|
||||
|
||||
if (is_ap && (changed & BSS_CHANGED_BEACON_ENABLED) &&
|
||||
!bss_conf->enable_beacon)
|
||||
wl1271_tx_flush(wl);
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
@ -4636,7 +4658,7 @@ static const struct ieee80211_ops wl1271_ops = {
|
||||
.prepare_multicast = wl1271_op_prepare_multicast,
|
||||
.configure_filter = wl1271_op_configure_filter,
|
||||
.tx = wl1271_op_tx,
|
||||
.set_key = wl1271_op_set_key,
|
||||
.set_key = wlcore_op_set_key,
|
||||
.hw_scan = wl1271_op_hw_scan,
|
||||
.cancel_hw_scan = wl1271_op_cancel_hw_scan,
|
||||
.sched_scan_start = wl1271_op_sched_scan_start,
|
||||
@ -4905,14 +4927,8 @@ static int wl1271_register_hw(struct wl1271 *wl)
|
||||
if (wl->mac80211_registered)
|
||||
return 0;
|
||||
|
||||
ret = wl12xx_get_hw_info(wl);
|
||||
if (ret < 0) {
|
||||
wl1271_error("couldn't get hw info");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl1271_fetch_nvs(wl);
|
||||
if (ret == 0) {
|
||||
wl1271_fetch_nvs(wl);
|
||||
if (wl->nvs != NULL) {
|
||||
/* NOTE: The wl->nvs->nvs element must be first, in
|
||||
* order to simplify the casting, we assume it is at
|
||||
* the beginning of the wl->nvs structure.
|
||||
@ -4970,9 +4986,11 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
|
||||
WL1271_CIPHER_SUITE_GEM,
|
||||
};
|
||||
|
||||
/* The tx descriptor buffer and the TKIP space. */
|
||||
wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +
|
||||
sizeof(struct wl1271_tx_hw_descr);
|
||||
/* The tx descriptor buffer */
|
||||
wl->hw->extra_tx_headroom = sizeof(struct wl1271_tx_hw_descr);
|
||||
|
||||
if (wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE)
|
||||
wl->hw->extra_tx_headroom += WL1271_EXTRA_SPACE_TKIP;
|
||||
|
||||
/* unit us */
|
||||
/* FIXME: find a proper value */
|
||||
@ -5025,12 +5043,14 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
|
||||
*/
|
||||
memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
|
||||
sizeof(wl1271_band_2ghz));
|
||||
memcpy(&wl->bands[IEEE80211_BAND_2GHZ].ht_cap, &wl->ht_cap,
|
||||
sizeof(wl->ht_cap));
|
||||
memcpy(&wl->bands[IEEE80211_BAND_2GHZ].ht_cap,
|
||||
&wl->ht_cap[IEEE80211_BAND_2GHZ],
|
||||
sizeof(*wl->ht_cap));
|
||||
memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
|
||||
sizeof(wl1271_band_5ghz));
|
||||
memcpy(&wl->bands[IEEE80211_BAND_5GHZ].ht_cap, &wl->ht_cap,
|
||||
sizeof(wl->ht_cap));
|
||||
memcpy(&wl->bands[IEEE80211_BAND_5GHZ].ht_cap,
|
||||
&wl->ht_cap[IEEE80211_BAND_5GHZ],
|
||||
sizeof(*wl->ht_cap));
|
||||
|
||||
wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
|
||||
&wl->bands[IEEE80211_BAND_2GHZ];
|
||||
@ -5117,6 +5137,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
|
||||
wl->rx_counter = 0;
|
||||
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
|
||||
wl->band = IEEE80211_BAND_2GHZ;
|
||||
wl->channel_type = NL80211_CHAN_NO_HT;
|
||||
wl->flags = 0;
|
||||
wl->sg_enabled = true;
|
||||
wl->hw_pg_ver = -1;
|
||||
@ -5142,6 +5163,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
|
||||
wl->state = WL1271_STATE_OFF;
|
||||
wl->fw_type = WL12XX_FW_TYPE_NONE;
|
||||
mutex_init(&wl->mutex);
|
||||
mutex_init(&wl->flush_mutex);
|
||||
|
||||
order = get_order(WL1271_AGGR_BUFFER_SIZE);
|
||||
wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
|
||||
@ -5222,7 +5244,7 @@ int wlcore_free_hw(struct wl1271 *wl)
|
||||
kfree(wl->nvs);
|
||||
wl->nvs = NULL;
|
||||
|
||||
kfree(wl->fw_status);
|
||||
kfree(wl->fw_status_1);
|
||||
kfree(wl->tx_res_if);
|
||||
destroy_workqueue(wl->freezable_wq);
|
||||
|
||||
@ -5279,8 +5301,6 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
|
||||
wlcore_adjust_conf(wl);
|
||||
|
||||
wl->irq = platform_get_irq(pdev, 0);
|
||||
wl->ref_clock = pdata->board_ref_clock;
|
||||
wl->tcxo_clock = pdata->board_tcxo_clock;
|
||||
wl->platform_quirks = pdata->platform_quirks;
|
||||
wl->set_power = pdata->set_power;
|
||||
wl->dev = &pdev->dev;
|
||||
@ -5316,6 +5336,16 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
|
||||
}
|
||||
disable_irq(wl->irq);
|
||||
|
||||
ret = wl12xx_get_hw_info(wl);
|
||||
if (ret < 0) {
|
||||
wl1271_error("couldn't get hw info");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl->ops->identify_chip(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl1271_init_ieee80211(wl);
|
||||
if (ret)
|
||||
goto out_irq;
|
||||
|
@ -28,6 +28,8 @@
|
||||
|
||||
#define WL1271_WAKEUP_TIMEOUT 500
|
||||
|
||||
#define ELP_ENTRY_DELAY 5
|
||||
|
||||
void wl1271_elp_work(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *dwork;
|
||||
@ -72,6 +74,7 @@ out:
|
||||
void wl1271_ps_elp_sleep(struct wl1271 *wl)
|
||||
{
|
||||
struct wl12xx_vif *wlvif;
|
||||
u32 timeout;
|
||||
|
||||
if (wl->quirks & WLCORE_QUIRK_NO_ELP)
|
||||
return;
|
||||
@ -89,8 +92,13 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
|
||||
return;
|
||||
}
|
||||
|
||||
if (wl->conf.conn.forced_ps)
|
||||
timeout = ELP_ENTRY_DELAY;
|
||||
else
|
||||
timeout = wl->conf.conn.dynamic_ps_timeout;
|
||||
|
||||
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
|
||||
msecs_to_jiffies(wl->conf.conn.dynamic_ps_timeout));
|
||||
msecs_to_jiffies(timeout));
|
||||
}
|
||||
|
||||
int wl1271_ps_elp_wakeup(struct wl1271 *wl)
|
||||
@ -185,8 +193,12 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
|
||||
set_bit(WLVIF_FLAG_IN_PS, &wlvif->flags);
|
||||
|
||||
/* enable beacon early termination. Not relevant for 5GHz */
|
||||
if (wlvif->band == IEEE80211_BAND_2GHZ) {
|
||||
/*
|
||||
* enable beacon early termination.
|
||||
* Not relevant for 5GHz and for high rates.
|
||||
*/
|
||||
if ((wlvif->band == IEEE80211_BAND_2GHZ) &&
|
||||
(wlvif->basic_rate < CONF_HW_BIT_RATE_9MBPS)) {
|
||||
ret = wl1271_acx_bet_enable(wl, wlvif, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -196,7 +208,8 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
wl1271_debug(DEBUG_PSM, "leaving psm");
|
||||
|
||||
/* disable beacon early termination */
|
||||
if (wlvif->band == IEEE80211_BAND_2GHZ) {
|
||||
if ((wlvif->band == IEEE80211_BAND_2GHZ) &&
|
||||
(wlvif->basic_rate < CONF_HW_BIT_RATE_9MBPS)) {
|
||||
ret = wl1271_acx_bet_enable(wl, wlvif, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -186,6 +186,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||
is_data = 1;
|
||||
|
||||
wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
|
||||
wlcore_hw_set_rx_csum(wl, desc, skb);
|
||||
|
||||
seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
|
||||
wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb,
|
||||
@ -199,12 +200,12 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||
return is_data;
|
||||
}
|
||||
|
||||
void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
|
||||
void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
|
||||
{
|
||||
unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
|
||||
u32 buf_size;
|
||||
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 fw_rx_counter = status->fw_rx_counter % wl->num_rx_desc;
|
||||
u32 drv_rx_counter = wl->rx_counter % wl->num_rx_desc;
|
||||
u32 rx_counter;
|
||||
u32 pkt_len, align_pkt_len;
|
||||
u32 pkt_offset, des;
|
||||
@ -223,7 +224,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
|
||||
break;
|
||||
buf_size += align_pkt_len;
|
||||
rx_counter++;
|
||||
rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
|
||||
rx_counter %= wl->num_rx_desc;
|
||||
}
|
||||
|
||||
if (buf_size == 0) {
|
||||
@ -263,7 +264,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
|
||||
|
||||
wl->rx_counter++;
|
||||
drv_rx_counter++;
|
||||
drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
|
||||
drv_rx_counter %= wl->num_rx_desc;
|
||||
pkt_offset += wlcore_rx_get_align_buf_size(wl, pkt_len);
|
||||
}
|
||||
}
|
||||
|
@ -38,8 +38,6 @@
|
||||
#define RX_DESC_PACKETID_SHIFT 11
|
||||
#define RX_MAX_PACKET_ID 3
|
||||
|
||||
#define NUM_RX_PKT_DESC_MOD_MASK 7
|
||||
|
||||
#define RX_DESC_VALID_FCS 0x0001
|
||||
#define RX_DESC_MATCH_RXADDR1 0x0002
|
||||
#define RX_DESC_MCAST 0x0004
|
||||
@ -102,6 +100,9 @@
|
||||
/* If set, the start of IP payload is not 4 bytes aligned */
|
||||
#define RX_BUF_UNALIGNED_PAYLOAD BIT(20)
|
||||
|
||||
/* If set, the buffer was padded by the FW to be 4 bytes aligned */
|
||||
#define RX_BUF_PADDED_PAYLOAD BIT(30)
|
||||
|
||||
/* Describes the alignment state of a Rx buffer */
|
||||
enum wl_rx_buf_align {
|
||||
WLCORE_RX_BUF_ALIGNED,
|
||||
@ -136,7 +137,7 @@ struct wl1271_rx_descriptor {
|
||||
u8 reserved;
|
||||
} __packed;
|
||||
|
||||
void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status);
|
||||
void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status);
|
||||
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
|
||||
int wl1271_rx_filter_enable(struct wl1271 *wl,
|
||||
int index, bool enable,
|
||||
|
@ -411,7 +411,8 @@ 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 max_channels)
|
||||
int start, int max_channels,
|
||||
u8 *n_pactive_ch)
|
||||
{
|
||||
struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
|
||||
int i, j;
|
||||
@ -479,6 +480,23 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
|
||||
channels[j].tx_power_att = req->channels[i]->max_power;
|
||||
channels[j].channel = req->channels[i]->hw_value;
|
||||
|
||||
if ((band == IEEE80211_BAND_2GHZ) &&
|
||||
(channels[j].channel >= 12) &&
|
||||
(channels[j].channel <= 14) &&
|
||||
(flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
|
||||
!force_passive) {
|
||||
/* pactive channels treated as DFS */
|
||||
channels[j].flags = SCAN_CHANNEL_FLAGS_DFS;
|
||||
|
||||
/*
|
||||
* n_pactive_ch is counted down from the end of
|
||||
* the passive channel list
|
||||
*/
|
||||
(*n_pactive_ch)++;
|
||||
wl1271_debug(DEBUG_SCAN, "n_pactive_ch = %d",
|
||||
*n_pactive_ch);
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
@ -491,38 +509,47 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
|
||||
struct cfg80211_sched_scan_request *req,
|
||||
struct wl1271_cmd_sched_scan_config *cfg)
|
||||
{
|
||||
u8 n_pactive_ch = 0;
|
||||
|
||||
cfg->passive[0] =
|
||||
wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2,
|
||||
IEEE80211_BAND_2GHZ,
|
||||
false, true, 0,
|
||||
MAX_CHANNELS_2GHZ);
|
||||
MAX_CHANNELS_2GHZ,
|
||||
&n_pactive_ch);
|
||||
cfg->active[0] =
|
||||
wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2,
|
||||
IEEE80211_BAND_2GHZ,
|
||||
false, false,
|
||||
cfg->passive[0],
|
||||
MAX_CHANNELS_2GHZ);
|
||||
MAX_CHANNELS_2GHZ,
|
||||
&n_pactive_ch);
|
||||
cfg->passive[1] =
|
||||
wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
|
||||
IEEE80211_BAND_5GHZ,
|
||||
false, true, 0,
|
||||
MAX_CHANNELS_5GHZ);
|
||||
MAX_CHANNELS_5GHZ,
|
||||
&n_pactive_ch);
|
||||
cfg->dfs =
|
||||
wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
|
||||
IEEE80211_BAND_5GHZ,
|
||||
true, true,
|
||||
cfg->passive[1],
|
||||
MAX_CHANNELS_5GHZ);
|
||||
MAX_CHANNELS_5GHZ,
|
||||
&n_pactive_ch);
|
||||
cfg->active[1] =
|
||||
wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
|
||||
IEEE80211_BAND_5GHZ,
|
||||
false, false,
|
||||
cfg->passive[1] + cfg->dfs,
|
||||
MAX_CHANNELS_5GHZ);
|
||||
MAX_CHANNELS_5GHZ,
|
||||
&n_pactive_ch);
|
||||
/* 802.11j channels are not supported yet */
|
||||
cfg->passive[2] = 0;
|
||||
cfg->active[2] = 0;
|
||||
|
||||
cfg->n_pactive_ch = n_pactive_ch;
|
||||
|
||||
wl1271_debug(DEBUG_SCAN, " 2.4GHz: active %d passive %d",
|
||||
cfg->active[0], cfg->passive[0]);
|
||||
wl1271_debug(DEBUG_SCAN, " 5GHz: active %d passive %d",
|
||||
@ -537,6 +564,7 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
|
||||
/* Returns the scan type to be used or a negative value on error */
|
||||
static int
|
||||
wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct cfg80211_sched_scan_request *req)
|
||||
{
|
||||
struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL;
|
||||
@ -565,6 +593,7 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmd->role_id = wlvif->dev_role_id;
|
||||
if (!n_match_ssids) {
|
||||
/* No filter, with ssids */
|
||||
type = SCAN_SSID_FILTER_DISABLED;
|
||||
@ -603,7 +632,9 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
|
||||
continue;
|
||||
|
||||
for (j = 0; j < cmd->n_ssids; j++)
|
||||
if (!memcmp(req->ssids[i].ssid,
|
||||
if ((req->ssids[i].ssid_len ==
|
||||
req->ssids[j].ssid_len) &&
|
||||
!memcmp(req->ssids[i].ssid,
|
||||
cmd->ssids[j].ssid,
|
||||
req->ssids[i].ssid_len)) {
|
||||
cmd->ssids[j].type =
|
||||
@ -652,6 +683,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
|
||||
if (!cfg)
|
||||
return -ENOMEM;
|
||||
|
||||
cfg->role_id = wlvif->dev_role_id;
|
||||
cfg->rssi_threshold = c->rssi_threshold;
|
||||
cfg->snr_threshold = c->snr_threshold;
|
||||
cfg->n_probe_reqs = c->num_probe_reqs;
|
||||
@ -669,7 +701,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
|
||||
cfg->intervals[i] = cpu_to_le32(req->interval);
|
||||
|
||||
cfg->ssid_len = 0;
|
||||
ret = wl12xx_scan_sched_scan_ssid_list(wl, req);
|
||||
ret = wl12xx_scan_sched_scan_ssid_list(wl, wlvif, req);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
@ -741,6 +773,7 @@ int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
if (!start)
|
||||
return -ENOMEM;
|
||||
|
||||
start->role_id = wlvif->dev_role_id;
|
||||
start->tag = WL1271_SCAN_DEFAULT_TAG;
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start,
|
||||
@ -762,7 +795,7 @@ void wl1271_scan_sched_scan_results(struct wl1271 *wl)
|
||||
ieee80211_sched_scan_results(wl->hw);
|
||||
}
|
||||
|
||||
void wl1271_scan_sched_scan_stop(struct wl1271 *wl)
|
||||
void wl1271_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl1271_cmd_sched_scan_stop *stop;
|
||||
int ret = 0;
|
||||
@ -776,6 +809,7 @@ void wl1271_scan_sched_scan_stop(struct wl1271 *wl)
|
||||
return;
|
||||
}
|
||||
|
||||
stop->role_id = wlvif->dev_role_id;
|
||||
stop->tag = WL1271_SCAN_DEFAULT_TAG;
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop,
|
||||
|
@ -40,7 +40,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
|
||||
struct cfg80211_sched_scan_request *req,
|
||||
struct ieee80211_sched_scan_ies *ies);
|
||||
int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
void wl1271_scan_sched_scan_stop(struct wl1271 *wl);
|
||||
void wl1271_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
void wl1271_scan_sched_scan_results(struct wl1271 *wl);
|
||||
|
||||
#define WL1271_SCAN_MAX_CHANNELS 24
|
||||
@ -142,7 +142,8 @@ enum {
|
||||
SCAN_BSS_TYPE_ANY,
|
||||
};
|
||||
|
||||
#define SCAN_CHANNEL_FLAGS_DFS BIT(0)
|
||||
#define SCAN_CHANNEL_FLAGS_DFS BIT(0) /* channel is passive until an
|
||||
activity is detected on it */
|
||||
#define SCAN_CHANNEL_FLAGS_DFS_ENABLED BIT(1)
|
||||
|
||||
struct conn_scan_ch_params {
|
||||
@ -185,7 +186,10 @@ struct wl1271_cmd_sched_scan_config {
|
||||
|
||||
u8 dfs;
|
||||
|
||||
u8 padding[3];
|
||||
u8 n_pactive_ch; /* number of pactive (passive until fw detects energy)
|
||||
channels in BG band */
|
||||
u8 role_id;
|
||||
u8 padding[1];
|
||||
|
||||
struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
|
||||
struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ];
|
||||
@ -212,21 +216,24 @@ struct wl1271_cmd_sched_scan_ssid_list {
|
||||
|
||||
u8 n_ssids;
|
||||
struct wl1271_ssid ssids[SCHED_SCAN_MAX_SSIDS];
|
||||
u8 padding[3];
|
||||
u8 role_id;
|
||||
u8 padding[2];
|
||||
} __packed;
|
||||
|
||||
struct wl1271_cmd_sched_scan_start {
|
||||
struct wl1271_cmd_header header;
|
||||
|
||||
u8 tag;
|
||||
u8 padding[3];
|
||||
u8 role_id;
|
||||
u8 padding[2];
|
||||
} __packed;
|
||||
|
||||
struct wl1271_cmd_sched_scan_stop {
|
||||
struct wl1271_cmd_header header;
|
||||
|
||||
u8 tag;
|
||||
u8 padding[3];
|
||||
u8 role_id;
|
||||
u8 padding[2];
|
||||
} __packed;
|
||||
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mmc/sdio.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
#include <linux/mmc/sdio_ids.h>
|
||||
#include <linux/mmc/card.h>
|
||||
@ -32,6 +33,7 @@
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/wl12xx.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
#include "wlcore.h"
|
||||
#include "wl12xx_80211.h"
|
||||
@ -45,6 +47,8 @@
|
||||
#define SDIO_DEVICE_ID_TI_WL1271 0x4076
|
||||
#endif
|
||||
|
||||
static bool dump = false;
|
||||
|
||||
struct wl12xx_sdio_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *core;
|
||||
@ -76,6 +80,13 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
|
||||
|
||||
sdio_claim_host(func);
|
||||
|
||||
if (unlikely(dump)) {
|
||||
printk(KERN_DEBUG "wlcore_sdio: READ from 0x%04x\n", addr);
|
||||
print_hex_dump(KERN_DEBUG, "wlcore_sdio: READ ",
|
||||
DUMP_PREFIX_OFFSET, 16, 1,
|
||||
buf, len, false);
|
||||
}
|
||||
|
||||
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) {
|
||||
((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
|
||||
dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n",
|
||||
@ -105,6 +116,13 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
|
||||
|
||||
sdio_claim_host(func);
|
||||
|
||||
if (unlikely(dump)) {
|
||||
printk(KERN_DEBUG "wlcore_sdio: WRITE to 0x%04x\n", addr);
|
||||
print_hex_dump(KERN_DEBUG, "wlcore_sdio: WRITE ",
|
||||
DUMP_PREFIX_OFFSET, 16, 1,
|
||||
buf, len, false);
|
||||
}
|
||||
|
||||
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) {
|
||||
sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
|
||||
dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n",
|
||||
@ -196,6 +214,7 @@ static int __devinit wl1271_probe(struct sdio_func *func,
|
||||
struct resource res[1];
|
||||
mmc_pm_flag_t mmcflags;
|
||||
int ret = -ENOMEM;
|
||||
const char *chip_family;
|
||||
|
||||
/* We are only able to handle the wlan function */
|
||||
if (func->num != 0x02)
|
||||
@ -236,7 +255,18 @@ 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);
|
||||
|
||||
glue->core = platform_device_alloc("wl12xx", -1);
|
||||
/*
|
||||
* Due to a hardware bug, we can't differentiate wl18xx from
|
||||
* wl12xx, because both report the same device ID. The only
|
||||
* way to differentiate is by checking the SDIO revision,
|
||||
* which is 3.00 on the wl18xx chips.
|
||||
*/
|
||||
if (func->card->cccr.sdio_vsn == SDIO_SDIO_REV_3_00)
|
||||
chip_family = "wl18xx";
|
||||
else
|
||||
chip_family = "wl12xx";
|
||||
|
||||
glue->core = platform_device_alloc(chip_family, -1);
|
||||
if (!glue->core) {
|
||||
dev_err(glue->dev, "can't allocate platform_device");
|
||||
ret = -ENOMEM;
|
||||
@ -367,6 +397,9 @@ static void __exit wl1271_exit(void)
|
||||
module_init(wl1271_init);
|
||||
module_exit(wl1271_exit);
|
||||
|
||||
module_param(dump, bool, S_IRUSR | S_IWUSR);
|
||||
MODULE_PARM_DESC(dump, "Enable sdio read/write dumps.");
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
|
||||
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
|
||||
|
@ -72,7 +72,7 @@ static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb)
|
||||
return id;
|
||||
}
|
||||
|
||||
static void wl1271_free_tx_id(struct wl1271 *wl, int id)
|
||||
void wl1271_free_tx_id(struct wl1271 *wl, int id)
|
||||
{
|
||||
if (__test_and_clear_bit(id, wl->tx_frames_map)) {
|
||||
if (unlikely(wl->tx_frames_cnt == wl->num_tx_desc))
|
||||
@ -82,6 +82,7 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id)
|
||||
wl->tx_frames_cnt--;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(wl1271_free_tx_id);
|
||||
|
||||
static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
|
||||
struct sk_buff *skb)
|
||||
@ -127,6 +128,7 @@ bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
|
||||
{
|
||||
return wl->dummy_packet == skb;
|
||||
}
|
||||
EXPORT_SYMBOL(wl12xx_is_dummy_packet);
|
||||
|
||||
u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb)
|
||||
@ -146,10 +148,10 @@ u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
return wl->system_hlid;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
if (ieee80211_is_mgmt(hdr->frame_control))
|
||||
return wlvif->ap.global_hlid;
|
||||
else
|
||||
if (is_multicast_ether_addr(ieee80211_get_DA(hdr)))
|
||||
return wlvif->ap.bcast_hlid;
|
||||
else
|
||||
return wlvif->ap.global_hlid;
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,37 +178,34 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
|
||||
unsigned int packet_length)
|
||||
{
|
||||
if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN)
|
||||
return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
|
||||
else
|
||||
if ((wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME) ||
|
||||
!(wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN))
|
||||
return ALIGN(packet_length, WL1271_TX_ALIGN_TO);
|
||||
else
|
||||
return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
|
||||
}
|
||||
EXPORT_SYMBOL(wlcore_calc_packet_alignment);
|
||||
|
||||
static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb, u32 extra, u32 buf_offset,
|
||||
u8 hlid)
|
||||
u8 hlid, bool is_gem)
|
||||
{
|
||||
struct wl1271_tx_hw_descr *desc;
|
||||
u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
|
||||
u32 total_blocks;
|
||||
int id, ret = -EBUSY, ac;
|
||||
u32 spare_blocks = wl->normal_tx_spare;
|
||||
bool is_dummy = false;
|
||||
u32 spare_blocks;
|
||||
|
||||
if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
|
||||
return -EAGAIN;
|
||||
|
||||
spare_blocks = wlcore_hw_get_spare_blocks(wl, is_gem);
|
||||
|
||||
/* allocate free identifier for the packet */
|
||||
id = wl1271_alloc_tx_id(wl, skb);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
if (unlikely(wl12xx_is_dummy_packet(wl, skb)))
|
||||
is_dummy = true;
|
||||
else if (wlvif->is_gem)
|
||||
spare_blocks = wl->gem_tx_spare;
|
||||
|
||||
total_blocks = wlcore_hw_calc_tx_blocks(wl, total_len, spare_blocks);
|
||||
|
||||
if (total_blocks <= wl->tx_blocks_available) {
|
||||
@ -228,7 +227,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
|
||||
wl->tx_allocated_pkts[ac]++;
|
||||
|
||||
if (!is_dummy && wlvif &&
|
||||
if (!wl12xx_is_dummy_packet(wl, skb) && wlvif &&
|
||||
wlvif->bss_type == BSS_TYPE_AP_BSS &&
|
||||
test_bit(hlid, wlvif->ap.sta_hlid_map))
|
||||
wl->links[hlid].allocated_pkts++;
|
||||
@ -268,6 +267,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
if (extra) {
|
||||
int hdrlen = ieee80211_hdrlen(frame_control);
|
||||
memmove(frame_start, hdr, hdrlen);
|
||||
skb_set_network_header(skb, skb_network_offset(skb) + extra);
|
||||
}
|
||||
|
||||
/* configure packet life time */
|
||||
@ -330,9 +330,9 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
ieee80211_has_protected(frame_control))
|
||||
tx_attr |= TX_HW_ATTR_HOST_ENCRYPT;
|
||||
|
||||
desc->reserved = 0;
|
||||
desc->tx_attr = cpu_to_le16(tx_attr);
|
||||
|
||||
wlcore_hw_set_tx_desc_csum(wl, desc, skb);
|
||||
wlcore_hw_set_tx_desc_data_len(wl, desc, skb);
|
||||
}
|
||||
|
||||
@ -346,6 +346,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u32 total_len;
|
||||
u8 hlid;
|
||||
bool is_dummy;
|
||||
bool is_gem = false;
|
||||
|
||||
if (!skb)
|
||||
return -EINVAL;
|
||||
@ -355,7 +356,8 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
/* TODO: handle dummy packets on multi-vifs */
|
||||
is_dummy = wl12xx_is_dummy_packet(wl, skb);
|
||||
|
||||
if (info->control.hw_key &&
|
||||
if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
|
||||
info->control.hw_key &&
|
||||
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP)
|
||||
extra = WL1271_EXTRA_SPACE_TKIP;
|
||||
|
||||
@ -373,6 +375,8 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
return ret;
|
||||
wlvif->default_key = idx;
|
||||
}
|
||||
|
||||
is_gem = (cipher == WL1271_CIPHER_SUITE_GEM);
|
||||
}
|
||||
hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
|
||||
if (hlid == WL12XX_INVALID_LINK_ID) {
|
||||
@ -380,7 +384,8 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid);
|
||||
ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid,
|
||||
is_gem);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -425,10 +430,10 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
|
||||
rate_set >>= 1;
|
||||
}
|
||||
|
||||
/* MCS rates indication are on bits 16 - 23 */
|
||||
/* MCS rates indication are on bits 16 - 31 */
|
||||
rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates;
|
||||
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
for (bit = 0; bit < 16; bit++) {
|
||||
if (rate_set & 0x1)
|
||||
enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit);
|
||||
rate_set >>= 1;
|
||||
@ -439,18 +444,15 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
|
||||
|
||||
void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_TX_QUEUES; i++) {
|
||||
if (test_bit(i, &wl->stopped_queues_map) &&
|
||||
if (wlcore_is_queue_stopped_by_reason(wl, i,
|
||||
WLCORE_QUEUE_STOP_REASON_WATERMARK) &&
|
||||
wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) {
|
||||
/* firmware buffer has space, restart queues */
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
ieee80211_wake_queue(wl->hw,
|
||||
wl1271_tx_get_mac80211_queue(i));
|
||||
clear_bit(i, &wl->stopped_queues_map);
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
wlcore_wake_queue(wl, i,
|
||||
WLCORE_QUEUE_STOP_REASON_WATERMARK);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -661,7 +663,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
|
||||
struct wl12xx_vif *wlvif;
|
||||
struct sk_buff *skb;
|
||||
struct wl1271_tx_hw_descr *desc;
|
||||
u32 buf_offset = 0;
|
||||
u32 buf_offset = 0, last_len = 0;
|
||||
bool sent_packets = false;
|
||||
unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
|
||||
int ret;
|
||||
@ -685,6 +687,9 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
|
||||
* Flush buffer and try again.
|
||||
*/
|
||||
wl1271_skb_queue_head(wl, wlvif, skb);
|
||||
|
||||
buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset,
|
||||
last_len);
|
||||
wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
|
||||
buf_offset, true);
|
||||
sent_packets = true;
|
||||
@ -710,7 +715,8 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
|
||||
ieee80211_free_txskb(wl->hw, skb);
|
||||
goto out_ack;
|
||||
}
|
||||
buf_offset += ret;
|
||||
last_len = ret;
|
||||
buf_offset += last_len;
|
||||
wl->tx_packets_count++;
|
||||
if (has_data) {
|
||||
desc = (struct wl1271_tx_hw_descr *) skb->data;
|
||||
@ -720,6 +726,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
|
||||
|
||||
out_ack:
|
||||
if (buf_offset) {
|
||||
buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, last_len);
|
||||
wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
|
||||
buf_offset, true);
|
||||
sent_packets = true;
|
||||
@ -849,7 +856,8 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
|
||||
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
|
||||
|
||||
/* remove TKIP header space if present */
|
||||
if (info->control.hw_key &&
|
||||
if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
|
||||
info->control.hw_key &&
|
||||
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
|
||||
int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
|
||||
memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data,
|
||||
@ -958,7 +966,7 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
|
||||
}
|
||||
/* caller must hold wl->mutex and TX must be stopped */
|
||||
void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
|
||||
void wl12xx_tx_reset(struct wl1271 *wl)
|
||||
{
|
||||
int i;
|
||||
struct sk_buff *skb;
|
||||
@ -973,15 +981,12 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
|
||||
wl->tx_queue_count[i] = 0;
|
||||
}
|
||||
|
||||
wl->stopped_queues_map = 0;
|
||||
|
||||
/*
|
||||
* Make sure the driver is at a consistent state, in case this
|
||||
* function is called from a context other than interface removal.
|
||||
* This call will always wake the TX queues.
|
||||
*/
|
||||
if (reset_tx_queues)
|
||||
wl1271_handle_tx_low_watermark(wl);
|
||||
wl1271_handle_tx_low_watermark(wl);
|
||||
|
||||
for (i = 0; i < wl->num_tx_desc; i++) {
|
||||
if (wl->tx_frames[i] == NULL)
|
||||
@ -998,7 +1003,8 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
|
||||
*/
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
|
||||
if (info->control.hw_key &&
|
||||
if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
|
||||
info->control.hw_key &&
|
||||
info->control.hw_key->cipher ==
|
||||
WLAN_CIPHER_SUITE_TKIP) {
|
||||
int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
|
||||
@ -1024,6 +1030,11 @@ void wl1271_tx_flush(struct wl1271 *wl)
|
||||
int i;
|
||||
timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT);
|
||||
|
||||
/* only one flush should be in progress, for consistent queue state */
|
||||
mutex_lock(&wl->flush_mutex);
|
||||
|
||||
wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH);
|
||||
|
||||
while (!time_after(jiffies, timeout)) {
|
||||
mutex_lock(&wl->mutex);
|
||||
wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d",
|
||||
@ -1032,7 +1043,7 @@ void wl1271_tx_flush(struct wl1271 *wl)
|
||||
if ((wl->tx_frames_cnt == 0) &&
|
||||
(wl1271_tx_total_queue_count(wl) == 0)) {
|
||||
mutex_unlock(&wl->mutex);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
mutex_unlock(&wl->mutex);
|
||||
msleep(1);
|
||||
@ -1045,7 +1056,12 @@ void wl1271_tx_flush(struct wl1271 *wl)
|
||||
for (i = 0; i < WL12XX_MAX_LINKS; i++)
|
||||
wl1271_tx_reset_link_queues(wl, i);
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
out:
|
||||
wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH);
|
||||
mutex_unlock(&wl->flush_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wl1271_tx_flush);
|
||||
|
||||
u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
|
||||
{
|
||||
@ -1054,3 +1070,96 @@ u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
|
||||
|
||||
return BIT(__ffs(rate_set));
|
||||
}
|
||||
|
||||
void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue,
|
||||
enum wlcore_queue_stop_reason reason)
|
||||
{
|
||||
bool stopped = !!wl->queue_stop_reasons[queue];
|
||||
|
||||
/* queue should not be stopped for this reason */
|
||||
WARN_ON(test_and_set_bit(reason, &wl->queue_stop_reasons[queue]));
|
||||
|
||||
if (stopped)
|
||||
return;
|
||||
|
||||
ieee80211_stop_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue));
|
||||
}
|
||||
|
||||
void wlcore_stop_queue(struct wl1271 *wl, u8 queue,
|
||||
enum wlcore_queue_stop_reason reason)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
wlcore_stop_queue_locked(wl, queue, reason);
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
}
|
||||
|
||||
void wlcore_wake_queue(struct wl1271 *wl, u8 queue,
|
||||
enum wlcore_queue_stop_reason reason)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
|
||||
/* queue should not be clear for this reason */
|
||||
WARN_ON(!test_and_clear_bit(reason, &wl->queue_stop_reasons[queue]));
|
||||
|
||||
if (wl->queue_stop_reasons[queue])
|
||||
goto out;
|
||||
|
||||
ieee80211_wake_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue));
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
}
|
||||
|
||||
void wlcore_stop_queues(struct wl1271 *wl,
|
||||
enum wlcore_queue_stop_reason reason)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_TX_QUEUES; i++)
|
||||
wlcore_stop_queue(wl, i, reason);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wlcore_stop_queues);
|
||||
|
||||
void wlcore_wake_queues(struct wl1271 *wl,
|
||||
enum wlcore_queue_stop_reason reason)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_TX_QUEUES; i++)
|
||||
wlcore_wake_queue(wl, i, reason);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wlcore_wake_queues);
|
||||
|
||||
void wlcore_reset_stopped_queues(struct wl1271 *wl)
|
||||
{
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
|
||||
for (i = 0; i < NUM_TX_QUEUES; i++) {
|
||||
if (!wl->queue_stop_reasons[i])
|
||||
continue;
|
||||
|
||||
wl->queue_stop_reasons[i] = 0;
|
||||
ieee80211_wake_queue(wl->hw,
|
||||
wl1271_tx_get_mac80211_queue(i));
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
}
|
||||
|
||||
bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue,
|
||||
enum wlcore_queue_stop_reason reason)
|
||||
{
|
||||
return test_bit(reason, &wl->queue_stop_reasons[queue]);
|
||||
}
|
||||
|
||||
bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue)
|
||||
{
|
||||
return !!wl->queue_stop_reasons[queue];
|
||||
}
|
||||
|
@ -85,6 +85,19 @@ struct wl128x_tx_mem {
|
||||
u8 extra_bytes;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_tx_mem {
|
||||
/*
|
||||
* Total number of memory blocks allocated by the host for
|
||||
* this packet.
|
||||
*/
|
||||
u8 total_mem_blocks;
|
||||
|
||||
/*
|
||||
* control bits
|
||||
*/
|
||||
u8 ctrl;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* On wl128x based devices, when TX packets are aggregated, each packet
|
||||
* size must be aligned to the SDIO block size. The maximum block size
|
||||
@ -100,6 +113,7 @@ struct wl1271_tx_hw_descr {
|
||||
union {
|
||||
struct wl127x_tx_mem wl127x_mem;
|
||||
struct wl128x_tx_mem wl128x_mem;
|
||||
struct wl18xx_tx_mem wl18xx_mem;
|
||||
} __packed;
|
||||
/* Device time (in us) when the packet arrived to the driver */
|
||||
__le32 start_time;
|
||||
@ -116,7 +130,16 @@ struct wl1271_tx_hw_descr {
|
||||
u8 tid;
|
||||
/* host link ID (HLID) */
|
||||
u8 hlid;
|
||||
u8 reserved;
|
||||
|
||||
union {
|
||||
u8 wl12xx_reserved;
|
||||
|
||||
/*
|
||||
* bit 0 -> 0 = udp, 1 = tcp
|
||||
* bit 1:7 -> IP header offset
|
||||
*/
|
||||
u8 wl18xx_checksum_data;
|
||||
} __packed;
|
||||
} __packed;
|
||||
|
||||
enum wl1271_tx_hw_res_status {
|
||||
@ -161,6 +184,13 @@ struct wl1271_tx_hw_res_if {
|
||||
struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN];
|
||||
} __packed;
|
||||
|
||||
enum wlcore_queue_stop_reason {
|
||||
WLCORE_QUEUE_STOP_REASON_WATERMARK,
|
||||
WLCORE_QUEUE_STOP_REASON_FW_RESTART,
|
||||
WLCORE_QUEUE_STOP_REASON_FLUSH,
|
||||
WLCORE_QUEUE_STOP_REASON_SPARE_BLK, /* 18xx specific */
|
||||
};
|
||||
|
||||
static inline int wl1271_tx_get_queue(int queue)
|
||||
{
|
||||
switch (queue) {
|
||||
@ -207,7 +237,7 @@ void wl1271_tx_work(struct work_struct *work);
|
||||
void wl1271_tx_work_locked(struct wl1271 *wl);
|
||||
void wl1271_tx_complete(struct wl1271 *wl);
|
||||
void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
|
||||
void wl12xx_tx_reset(struct wl1271 *wl);
|
||||
void wl1271_tx_flush(struct wl1271 *wl);
|
||||
u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band);
|
||||
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
|
||||
@ -223,6 +253,21 @@ bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb);
|
||||
void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids);
|
||||
unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
|
||||
unsigned int packet_length);
|
||||
void wl1271_free_tx_id(struct wl1271 *wl, int id);
|
||||
void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue,
|
||||
enum wlcore_queue_stop_reason reason);
|
||||
void wlcore_stop_queue(struct wl1271 *wl, u8 queue,
|
||||
enum wlcore_queue_stop_reason reason);
|
||||
void wlcore_wake_queue(struct wl1271 *wl, u8 queue,
|
||||
enum wlcore_queue_stop_reason reason);
|
||||
void wlcore_stop_queues(struct wl1271 *wl,
|
||||
enum wlcore_queue_stop_reason reason);
|
||||
void wlcore_wake_queues(struct wl1271 *wl,
|
||||
enum wlcore_queue_stop_reason reason);
|
||||
void wlcore_reset_stopped_queues(struct wl1271 *wl);
|
||||
bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue,
|
||||
enum wlcore_queue_stop_reason reason);
|
||||
bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue);
|
||||
|
||||
/* from main.c */
|
||||
void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
|
||||
|
@ -24,8 +24,9 @@
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "wlcore_i.h"
|
||||
#include "event.h"
|
||||
#include "boot.h"
|
||||
|
||||
/* The maximum number of Tx descriptors in all chip families */
|
||||
#define WLCORE_MAX_TX_DESCRIPTORS 32
|
||||
@ -33,11 +34,13 @@
|
||||
/* forward declaration */
|
||||
struct wl1271_tx_hw_descr;
|
||||
enum wl_rx_buf_align;
|
||||
struct wl1271_rx_descriptor;
|
||||
|
||||
struct wlcore_ops {
|
||||
int (*identify_chip)(struct wl1271 *wl);
|
||||
int (*identify_fw)(struct wl1271 *wl);
|
||||
int (*boot)(struct wl1271 *wl);
|
||||
int (*plt_init)(struct wl1271 *wl);
|
||||
void (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr,
|
||||
void *buf, size_t len);
|
||||
void (*ack_event)(struct wl1271 *wl);
|
||||
@ -61,6 +64,23 @@ struct wlcore_ops {
|
||||
struct wl12xx_vif *wlvif);
|
||||
s8 (*get_pg_ver)(struct wl1271 *wl);
|
||||
void (*get_mac)(struct wl1271 *wl);
|
||||
void (*set_tx_desc_csum)(struct wl1271 *wl,
|
||||
struct wl1271_tx_hw_descr *desc,
|
||||
struct sk_buff *skb);
|
||||
void (*set_rx_csum)(struct wl1271 *wl,
|
||||
struct wl1271_rx_descriptor *desc,
|
||||
struct sk_buff *skb);
|
||||
u32 (*ap_get_mimo_wide_rate_mask)(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif);
|
||||
int (*debugfs_init)(struct wl1271 *wl, struct dentry *rootdir);
|
||||
int (*handle_static_data)(struct wl1271 *wl,
|
||||
struct wl1271_static_data *static_data);
|
||||
int (*get_spare_blocks)(struct wl1271 *wl, bool is_gem);
|
||||
int (*set_key)(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key_conf);
|
||||
u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len);
|
||||
};
|
||||
|
||||
enum wlcore_partitions {
|
||||
@ -109,6 +129,15 @@ enum wlcore_registers {
|
||||
REG_TABLE_LEN,
|
||||
};
|
||||
|
||||
struct wl1271_stats {
|
||||
void *fw_stats;
|
||||
unsigned long fw_stats_update;
|
||||
size_t fw_stats_len;
|
||||
|
||||
unsigned int retry_count;
|
||||
unsigned int excessive_retries;
|
||||
};
|
||||
|
||||
struct wl1271 {
|
||||
struct ieee80211_hw *hw;
|
||||
bool mac80211_registered;
|
||||
@ -121,7 +150,6 @@ struct wl1271 {
|
||||
|
||||
void (*set_power)(bool enable);
|
||||
int irq;
|
||||
int ref_clock;
|
||||
|
||||
spinlock_t wl_lock;
|
||||
|
||||
@ -186,7 +214,7 @@ struct wl1271 {
|
||||
|
||||
/* Frames scheduled for transmission, not handled yet */
|
||||
int tx_queue_count[NUM_TX_QUEUES];
|
||||
long stopped_queues_map;
|
||||
unsigned long queue_stop_reasons[NUM_TX_QUEUES];
|
||||
|
||||
/* Frames received, not handled yet by mac80211 */
|
||||
struct sk_buff_head deferred_rx_queue;
|
||||
@ -205,9 +233,6 @@ struct wl1271 {
|
||||
/* FW Rx counter */
|
||||
u32 rx_counter;
|
||||
|
||||
/* Rx memory pool address */
|
||||
struct wl1271_rx_mem_pool_addr rx_mem_pool_addr;
|
||||
|
||||
/* Intermediate buffer, used for packet aggregation */
|
||||
u8 *aggr_buf;
|
||||
|
||||
@ -228,6 +253,7 @@ struct wl1271 {
|
||||
|
||||
/* Hardware recovery work */
|
||||
struct work_struct recovery_work;
|
||||
bool watchdog_recovery;
|
||||
|
||||
/* Pointer that holds DMA-friendly block for the mailbox */
|
||||
struct event_mailbox *mbox;
|
||||
@ -263,7 +289,8 @@ struct wl1271 {
|
||||
u32 buffer_cmd;
|
||||
u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
|
||||
|
||||
struct wl_fw_status *fw_status;
|
||||
struct wl_fw_status_1 *fw_status_1;
|
||||
struct wl_fw_status_2 *fw_status_2;
|
||||
struct wl1271_tx_hw_res_if *tx_res_if;
|
||||
|
||||
/* Current chipset configuration */
|
||||
@ -279,8 +306,6 @@ struct wl1271 {
|
||||
/* bands supported by this instance of wl12xx */
|
||||
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
|
||||
|
||||
int tcxo_clock;
|
||||
|
||||
/*
|
||||
* wowlan trigger was configured during suspend.
|
||||
* (currently, only "ANY" trigger is supported)
|
||||
@ -333,10 +358,8 @@ struct wl1271 {
|
||||
|
||||
/* number of TX descriptors the HW supports. */
|
||||
u32 num_tx_desc;
|
||||
|
||||
/* spare Tx blocks for normal/GEM operating modes */
|
||||
u32 normal_tx_spare;
|
||||
u32 gem_tx_spare;
|
||||
/* number of RX descriptors the HW supports. */
|
||||
u32 num_rx_desc;
|
||||
|
||||
/* translate HW Tx rates to standard rate-indices */
|
||||
const u8 **band_rate_to_idx;
|
||||
@ -348,19 +371,32 @@ struct wl1271 {
|
||||
u8 hw_min_ht_rate;
|
||||
|
||||
/* HW HT (11n) capabilities */
|
||||
struct ieee80211_sta_ht_cap ht_cap;
|
||||
struct ieee80211_sta_ht_cap ht_cap[IEEE80211_NUM_BANDS];
|
||||
|
||||
/* size of the private FW status data */
|
||||
size_t fw_status_priv_len;
|
||||
|
||||
/* RX Data filter rule state - enabled/disabled */
|
||||
bool rx_filter_enabled[WL1271_MAX_RX_FILTERS];
|
||||
|
||||
/* size of the private static data */
|
||||
size_t static_data_priv_len;
|
||||
|
||||
/* the current channel type */
|
||||
enum nl80211_channel_type channel_type;
|
||||
|
||||
/* mutex for protecting the tx_flush function */
|
||||
struct mutex flush_mutex;
|
||||
};
|
||||
|
||||
int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev);
|
||||
int __devexit wlcore_remove(struct platform_device *pdev);
|
||||
struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size);
|
||||
int wlcore_free_hw(struct wl1271 *wl);
|
||||
int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key_conf);
|
||||
|
||||
/* Firmware image load chunk size */
|
||||
#define CHUNK_SIZE 16384
|
||||
@ -385,6 +421,12 @@ int wlcore_free_hw(struct wl1271 *wl);
|
||||
/* Some firmwares may not support ELP */
|
||||
#define WLCORE_QUIRK_NO_ELP BIT(6)
|
||||
|
||||
/* pad only the last frame in the aggregate buffer */
|
||||
#define WLCORE_QUIRK_TX_PAD_LAST_FRAME BIT(7)
|
||||
|
||||
/* extra header space is required for TKIP */
|
||||
#define WLCORE_QUIRK_TKIP_HEADER_SPACE BIT(8)
|
||||
|
||||
/* TODO: move to the lower drivers when all usages are abstracted */
|
||||
#define CHIP_ID_1271_PG10 (0x4030101)
|
||||
#define CHIP_ID_1271_PG20 (0x4030111)
|
||||
|
@ -22,8 +22,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WL12XX_H__
|
||||
#define __WL12XX_H__
|
||||
#ifndef __WLCORE_I_H__
|
||||
#define __WLCORE_I_H__
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/completion.h>
|
||||
@ -89,7 +89,7 @@
|
||||
#define WL1271_AP_BSS_INDEX 0
|
||||
#define WL1271_AP_DEF_BEACON_EXP 20
|
||||
|
||||
#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
|
||||
#define WL1271_AGGR_BUFFER_SIZE (5 * PAGE_SIZE)
|
||||
|
||||
enum wl1271_state {
|
||||
WL1271_STATE_OFF,
|
||||
@ -132,16 +132,7 @@ struct wl1271_chip {
|
||||
unsigned int fw_ver[NUM_FW_VER];
|
||||
};
|
||||
|
||||
struct wl1271_stats {
|
||||
struct acx_statistics *fw_stats;
|
||||
unsigned long fw_stats_update;
|
||||
|
||||
unsigned int retry_count;
|
||||
unsigned int excessive_retries;
|
||||
};
|
||||
|
||||
#define NUM_TX_QUEUES 4
|
||||
#define NUM_RX_PKT_DESC 8
|
||||
|
||||
#define AP_MAX_STATIONS 8
|
||||
|
||||
@ -159,13 +150,26 @@ struct wl_fw_packet_counters {
|
||||
} __packed;
|
||||
|
||||
/* FW status registers */
|
||||
struct wl_fw_status {
|
||||
struct wl_fw_status_1 {
|
||||
__le32 intr;
|
||||
u8 fw_rx_counter;
|
||||
u8 drv_rx_counter;
|
||||
u8 reserved;
|
||||
u8 tx_results_counter;
|
||||
__le32 rx_pkt_descs[NUM_RX_PKT_DESC];
|
||||
__le32 rx_pkt_descs[0];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Each HW arch has a different number of Rx descriptors.
|
||||
* The length of the status depends on it, since it holds an array
|
||||
* of descriptors.
|
||||
*/
|
||||
#define WLCORE_FW_STATUS_1_LEN(num_rx_desc) \
|
||||
(sizeof(struct wl_fw_status_1) + \
|
||||
(sizeof(((struct wl_fw_status_1 *)0)->rx_pkt_descs[0])) * \
|
||||
num_rx_desc)
|
||||
|
||||
struct wl_fw_status_2 {
|
||||
__le32 fw_localtime;
|
||||
|
||||
/*
|
||||
@ -194,11 +198,6 @@ struct wl_fw_status {
|
||||
u8 priv[0];
|
||||
} __packed;
|
||||
|
||||
struct wl1271_rx_mem_pool_addr {
|
||||
u32 addr;
|
||||
u32 addr_extra;
|
||||
};
|
||||
|
||||
#define WL1271_MAX_CHANNELS 64
|
||||
struct wl1271_scan {
|
||||
struct cfg80211_scan_request *req;
|
||||
@ -367,6 +366,7 @@ struct wl12xx_vif {
|
||||
/* The current band */
|
||||
enum ieee80211_band band;
|
||||
int channel;
|
||||
enum nl80211_channel_type channel_type;
|
||||
|
||||
u32 bitrate_masks[IEEE80211_NUM_BANDS];
|
||||
u32 basic_rate_set;
|
||||
@ -417,9 +417,6 @@ struct wl12xx_vif {
|
||||
struct work_struct rx_streaming_disable_work;
|
||||
struct timer_list rx_streaming_timer;
|
||||
|
||||
/* does the current role use GEM for encryption (AP or STA) */
|
||||
bool is_gem;
|
||||
|
||||
/*
|
||||
* This struct must be last!
|
||||
* data that has to be saved acrossed reconfigs (e.g. recovery)
|
||||
@ -501,7 +498,8 @@ void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
|
||||
/* Macros to handle wl1271.sta_rate_set */
|
||||
#define HW_BG_RATES_MASK 0xffff
|
||||
#define HW_HT_RATES_OFFSET 16
|
||||
#define HW_MIMO_RATES_OFFSET 24
|
||||
|
||||
#define WL12XX_HW_BLOCK_SIZE 256
|
||||
|
||||
#endif
|
||||
#endif /* __WLCORE_I_H__ */
|
Loading…
Reference in New Issue
Block a user