mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 14:41:39 +00:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
fd95240568
@ -5127,6 +5127,7 @@ RALINK RT2X00 WIRELESS LAN DRIVER
|
||||
P: rt2x00 project
|
||||
M: Ivo van Doorn <IvDoorn@gmail.com>
|
||||
M: Gertjan van Wingerde <gwingerde@gmail.com>
|
||||
M: Helmut Schaa <helmut.schaa@googlemail.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
L: users@rt2x00.serialmonkey.com (moderated for non-subscribers)
|
||||
W: http://rt2x00.serialmonkey.com/
|
||||
@ -6767,12 +6768,12 @@ S: Maintained
|
||||
F: drivers/net/wireless/wl1251/*
|
||||
|
||||
WL1271 WIRELESS DRIVER
|
||||
M: Luciano Coelho <luciano.coelho@nokia.com>
|
||||
M: Luciano Coelho <coelho@ti.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://wireless.kernel.org
|
||||
W: http://wireless.kernel.org/en/users/Drivers/wl12xx
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/wl12xx/wl1271*
|
||||
F: drivers/net/wireless/wl12xx/
|
||||
F: include/linux/wl12xx.h
|
||||
|
||||
WL3501 WIRELESS PCMCIA CARD DRIVER
|
||||
|
@ -40,6 +40,17 @@ config ATH5K_DEBUG
|
||||
|
||||
modprobe ath5k debug=0x00000400
|
||||
|
||||
config ATH5K_TRACER
|
||||
bool "Atheros 5xxx tracer"
|
||||
depends on ATH5K
|
||||
depends on EVENT_TRACING
|
||||
---help---
|
||||
Say Y here to enable tracepoints for the ath5k driver
|
||||
using the kernel tracing infrastructure. Select this
|
||||
option if you are interested in debugging the driver.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config ATH5K_AHB
|
||||
bool "Atheros 5xxx AHB bus support"
|
||||
depends on (ATHEROS_AR231X && !PCI)
|
||||
|
@ -210,14 +210,9 @@
|
||||
/* Initial values */
|
||||
#define AR5K_INIT_CYCRSSI_THR1 2
|
||||
|
||||
/* Tx retry limits */
|
||||
#define AR5K_INIT_SH_RETRY 10
|
||||
#define AR5K_INIT_LG_RETRY AR5K_INIT_SH_RETRY
|
||||
/* For station mode */
|
||||
#define AR5K_INIT_SSH_RETRY 32
|
||||
#define AR5K_INIT_SLG_RETRY AR5K_INIT_SSH_RETRY
|
||||
#define AR5K_INIT_TX_RETRY 10
|
||||
|
||||
/* Tx retry limit defaults from standard */
|
||||
#define AR5K_INIT_RETRY_SHORT 7
|
||||
#define AR5K_INIT_RETRY_LONG 4
|
||||
|
||||
/* Slot time */
|
||||
#define AR5K_INIT_SLOT_TIME_TURBO 6
|
||||
@ -1057,7 +1052,9 @@ struct ath5k_hw {
|
||||
#define ah_modes ah_capabilities.cap_mode
|
||||
#define ah_ee_version ah_capabilities.cap_eeprom.ee_version
|
||||
|
||||
u32 ah_limit_tx_retries;
|
||||
u8 ah_retry_long;
|
||||
u8 ah_retry_short;
|
||||
|
||||
u8 ah_coverage_class;
|
||||
bool ah_ack_bitrate_high;
|
||||
u8 ah_bwmode;
|
||||
@ -1067,7 +1064,6 @@ struct ath5k_hw {
|
||||
u8 ah_ant_mode;
|
||||
u8 ah_tx_ant;
|
||||
u8 ah_def_ant;
|
||||
bool ah_software_retry;
|
||||
|
||||
struct ath5k_capabilities ah_capabilities;
|
||||
|
||||
@ -1250,6 +1246,8 @@ int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
|
||||
int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah,
|
||||
enum ath5k_tx_queue queue_type,
|
||||
struct ath5k_txq_info *queue_info);
|
||||
void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah,
|
||||
unsigned int queue);
|
||||
u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue);
|
||||
void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue);
|
||||
int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue);
|
||||
|
@ -118,8 +118,8 @@ int ath5k_hw_init(struct ath5k_softc *sc)
|
||||
ah->ah_bwmode = AR5K_BWMODE_DEFAULT;
|
||||
ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
|
||||
ah->ah_imr = 0;
|
||||
ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
|
||||
ah->ah_software_retry = false;
|
||||
ah->ah_retry_short = AR5K_INIT_RETRY_SHORT;
|
||||
ah->ah_retry_long = AR5K_INIT_RETRY_LONG;
|
||||
ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT;
|
||||
ah->ah_noise_floor = -95; /* until first NF calibration is run */
|
||||
sc->ani_state.ani_mode = ATH5K_ANI_MODE_AUTO;
|
||||
|
@ -61,6 +61,9 @@
|
||||
#include "debug.h"
|
||||
#include "ani.h"
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "trace.h"
|
||||
|
||||
int ath5k_modparam_nohwcrypt;
|
||||
module_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
|
||||
@ -1379,7 +1382,7 @@ ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb,
|
||||
sc->sbands[sc->curchan->band].bitrates[rxs->rate_idx].hw_value_short)
|
||||
rxs->flag |= RX_FLAG_SHORTPRE;
|
||||
|
||||
ath5k_debug_dump_skb(sc, skb, "RX ", 0);
|
||||
trace_ath5k_rx(sc, skb);
|
||||
|
||||
ath5k_update_beacon_rssi(sc, skb, rs->rs_rssi);
|
||||
|
||||
@ -1524,7 +1527,7 @@ ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
|
||||
unsigned long flags;
|
||||
int padsize;
|
||||
|
||||
ath5k_debug_dump_skb(sc, skb, "TX ", 1);
|
||||
trace_ath5k_tx(sc, skb, txq);
|
||||
|
||||
/*
|
||||
* The hardware expects the header padded to 4 byte boundaries.
|
||||
@ -1573,7 +1576,7 @@ drop_packet:
|
||||
|
||||
static void
|
||||
ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb,
|
||||
struct ath5k_tx_status *ts)
|
||||
struct ath5k_txq *txq, struct ath5k_tx_status *ts)
|
||||
{
|
||||
struct ieee80211_tx_info *info;
|
||||
int i;
|
||||
@ -1625,6 +1628,7 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb,
|
||||
else
|
||||
sc->stats.antenna_tx[0]++; /* invalid */
|
||||
|
||||
trace_ath5k_tx_complete(sc, skb, txq, ts);
|
||||
ieee80211_tx_status(sc->hw, skb);
|
||||
}
|
||||
|
||||
@ -1661,7 +1665,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
|
||||
|
||||
dma_unmap_single(sc->dev, bf->skbaddr, skb->len,
|
||||
DMA_TO_DEVICE);
|
||||
ath5k_tx_frame_completed(sc, skb, &ts);
|
||||
ath5k_tx_frame_completed(sc, skb, txq, &ts);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1803,8 +1807,6 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ath5k_debug_dump_skb(sc, skb, "BC ", 1);
|
||||
|
||||
ath5k_txbuf_free_skb(sc, avf->bbuf);
|
||||
avf->bbuf->skb = skb;
|
||||
ret = ath5k_beacon_setup(sc, avf->bbuf);
|
||||
@ -1899,6 +1901,8 @@ ath5k_beacon_send(struct ath5k_softc *sc)
|
||||
sc->opmode == NL80211_IFTYPE_MESH_POINT)
|
||||
ath5k_beacon_update(sc->hw, vif);
|
||||
|
||||
trace_ath5k_tx(sc, bf->skb, &sc->txqs[sc->bhalq]);
|
||||
|
||||
ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr);
|
||||
ath5k_hw_start_tx_dma(ah, sc->bhalq);
|
||||
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
|
||||
@ -2399,7 +2403,8 @@ ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops)
|
||||
/* set up multi-rate retry capabilities */
|
||||
if (sc->ah->ah_version == AR5K_AR5212) {
|
||||
hw->max_rates = 4;
|
||||
hw->max_rate_tries = 11;
|
||||
hw->max_rate_tries = max(AR5K_INIT_RETRY_SHORT,
|
||||
AR5K_INIT_RETRY_LONG);
|
||||
}
|
||||
|
||||
hw->vif_data_size = sizeof(struct ath5k_vif);
|
||||
|
@ -32,23 +32,24 @@
|
||||
*/
|
||||
int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
|
||||
{
|
||||
struct ath5k_capabilities *caps = &ah->ah_capabilities;
|
||||
u16 ee_header;
|
||||
|
||||
/* Capabilities stored in the EEPROM */
|
||||
ee_header = ah->ah_capabilities.cap_eeprom.ee_header;
|
||||
ee_header = caps->cap_eeprom.ee_header;
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
/*
|
||||
* Set radio capabilities
|
||||
* (The AR5110 only supports the middle 5GHz band)
|
||||
*/
|
||||
ah->ah_capabilities.cap_range.range_5ghz_min = 5120;
|
||||
ah->ah_capabilities.cap_range.range_5ghz_max = 5430;
|
||||
ah->ah_capabilities.cap_range.range_2ghz_min = 0;
|
||||
ah->ah_capabilities.cap_range.range_2ghz_max = 0;
|
||||
caps->cap_range.range_5ghz_min = 5120;
|
||||
caps->cap_range.range_5ghz_max = 5430;
|
||||
caps->cap_range.range_2ghz_min = 0;
|
||||
caps->cap_range.range_2ghz_max = 0;
|
||||
|
||||
/* Set supported modes */
|
||||
__set_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode);
|
||||
__set_bit(AR5K_MODE_11A, caps->cap_mode);
|
||||
} else {
|
||||
/*
|
||||
* XXX The tranceiver supports frequencies from 4920 to 6100GHz
|
||||
@ -56,9 +57,8 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
|
||||
* XXX current ieee80211 implementation because the IEEE
|
||||
* XXX channel mapping does not support negative channel
|
||||
* XXX numbers (2312MHz is channel -19). Of course, this
|
||||
* XXX doesn't matter because these channels are out of range
|
||||
* XXX but some regulation domains like MKK (Japan) will
|
||||
* XXX support frequencies somewhere around 4.8GHz.
|
||||
* XXX doesn't matter because these channels are out of the
|
||||
* XXX legal range.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -66,13 +66,14 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
|
||||
*/
|
||||
|
||||
if (AR5K_EEPROM_HDR_11A(ee_header)) {
|
||||
/* 4920 */
|
||||
ah->ah_capabilities.cap_range.range_5ghz_min = 5005;
|
||||
ah->ah_capabilities.cap_range.range_5ghz_max = 6100;
|
||||
if (ath_is_49ghz_allowed(caps->cap_eeprom.ee_regdomain))
|
||||
caps->cap_range.range_5ghz_min = 4920;
|
||||
else
|
||||
caps->cap_range.range_5ghz_min = 5005;
|
||||
caps->cap_range.range_5ghz_max = 6100;
|
||||
|
||||
/* Set supported modes */
|
||||
__set_bit(AR5K_MODE_11A,
|
||||
ah->ah_capabilities.cap_mode);
|
||||
__set_bit(AR5K_MODE_11A, caps->cap_mode);
|
||||
}
|
||||
|
||||
/* Enable 802.11b if a 2GHz capable radio (2111/5112) is
|
||||
@ -81,32 +82,29 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
|
||||
(AR5K_EEPROM_HDR_11G(ee_header) &&
|
||||
ah->ah_version != AR5K_AR5211)) {
|
||||
/* 2312 */
|
||||
ah->ah_capabilities.cap_range.range_2ghz_min = 2412;
|
||||
ah->ah_capabilities.cap_range.range_2ghz_max = 2732;
|
||||
caps->cap_range.range_2ghz_min = 2412;
|
||||
caps->cap_range.range_2ghz_max = 2732;
|
||||
|
||||
if (AR5K_EEPROM_HDR_11B(ee_header))
|
||||
__set_bit(AR5K_MODE_11B,
|
||||
ah->ah_capabilities.cap_mode);
|
||||
__set_bit(AR5K_MODE_11B, caps->cap_mode);
|
||||
|
||||
if (AR5K_EEPROM_HDR_11G(ee_header) &&
|
||||
ah->ah_version != AR5K_AR5211)
|
||||
__set_bit(AR5K_MODE_11G,
|
||||
ah->ah_capabilities.cap_mode);
|
||||
__set_bit(AR5K_MODE_11G, caps->cap_mode);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set number of supported TX queues */
|
||||
if (ah->ah_version == AR5K_AR5210)
|
||||
ah->ah_capabilities.cap_queues.q_tx_num =
|
||||
AR5K_NUM_TX_QUEUES_NOQCU;
|
||||
caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES_NOQCU;
|
||||
else
|
||||
ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES;
|
||||
caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES;
|
||||
|
||||
/* newer hardware has PHY error counters */
|
||||
if (ah->ah_mac_srev >= AR5K_SREV_AR5213A)
|
||||
ah->ah_capabilities.cap_has_phyerr_counters = true;
|
||||
caps->cap_has_phyerr_counters = true;
|
||||
else
|
||||
ah->ah_capabilities.cap_has_phyerr_counters = false;
|
||||
caps->cap_has_phyerr_counters = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -308,8 +308,6 @@ static const struct {
|
||||
{ ATH5K_DEBUG_CALIBRATE, "calib", "periodic calibration" },
|
||||
{ ATH5K_DEBUG_TXPOWER, "txpower", "transmit power setting" },
|
||||
{ ATH5K_DEBUG_LED, "led", "LED management" },
|
||||
{ ATH5K_DEBUG_DUMP_RX, "dumprx", "print received skb content" },
|
||||
{ ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" },
|
||||
{ ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" },
|
||||
{ ATH5K_DEBUG_DMA, "dma", "dma start/stop" },
|
||||
{ ATH5K_DEBUG_ANI, "ani", "adaptive noise immunity" },
|
||||
@ -1035,24 +1033,6 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah)
|
||||
spin_unlock_bh(&sc->rxbuflock);
|
||||
}
|
||||
|
||||
void
|
||||
ath5k_debug_dump_skb(struct ath5k_softc *sc,
|
||||
struct sk_buff *skb, const char *prefix, int tx)
|
||||
{
|
||||
char buf[16];
|
||||
|
||||
if (likely(!((tx && (sc->debug.level & ATH5K_DEBUG_DUMP_TX)) ||
|
||||
(!tx && (sc->debug.level & ATH5K_DEBUG_DUMP_RX)))))
|
||||
return;
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s %s", wiphy_name(sc->hw->wiphy), prefix);
|
||||
|
||||
print_hex_dump_bytes(buf, DUMP_PREFIX_NONE, skb->data,
|
||||
min(200U, skb->len));
|
||||
|
||||
printk(KERN_DEBUG "\n");
|
||||
}
|
||||
|
||||
void
|
||||
ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf)
|
||||
{
|
||||
|
@ -116,8 +116,6 @@ enum ath5k_debug_level {
|
||||
ATH5K_DEBUG_CALIBRATE = 0x00000020,
|
||||
ATH5K_DEBUG_TXPOWER = 0x00000040,
|
||||
ATH5K_DEBUG_LED = 0x00000080,
|
||||
ATH5K_DEBUG_DUMP_RX = 0x00000100,
|
||||
ATH5K_DEBUG_DUMP_TX = 0x00000200,
|
||||
ATH5K_DEBUG_DUMPBANDS = 0x00000400,
|
||||
ATH5K_DEBUG_DMA = 0x00000800,
|
||||
ATH5K_DEBUG_ANI = 0x00002000,
|
||||
@ -151,10 +149,6 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah);
|
||||
void
|
||||
ath5k_debug_dump_bands(struct ath5k_softc *sc);
|
||||
|
||||
void
|
||||
ath5k_debug_dump_skb(struct ath5k_softc *sc,
|
||||
struct sk_buff *skb, const char *prefix, int tx);
|
||||
|
||||
void
|
||||
ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf);
|
||||
|
||||
@ -181,10 +175,6 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {}
|
||||
static inline void
|
||||
ath5k_debug_dump_bands(struct ath5k_softc *sc) {}
|
||||
|
||||
static inline void
|
||||
ath5k_debug_dump_skb(struct ath5k_softc *sc,
|
||||
struct sk_buff *skb, const char *prefix, int tx) {}
|
||||
|
||||
static inline void
|
||||
ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) {}
|
||||
|
||||
|
@ -838,9 +838,9 @@ int ath5k_hw_dma_stop(struct ath5k_hw *ah)
|
||||
for (i = 0; i < qmax; i++) {
|
||||
err = ath5k_hw_stop_tx_dma(ah, i);
|
||||
/* -EINVAL -> queue inactive */
|
||||
if (err != -EINVAL)
|
||||
if (err && err != -EINVAL)
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
@ -226,6 +226,7 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
struct ath5k_hw *ah = sc->ah;
|
||||
struct ieee80211_conf *conf = &hw->conf;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
mutex_lock(&sc->lock);
|
||||
|
||||
@ -243,6 +244,14 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2));
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
|
||||
ah->ah_retry_long = conf->long_frame_max_tx_count;
|
||||
ah->ah_retry_short = conf->short_frame_max_tx_count;
|
||||
|
||||
for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++)
|
||||
ath5k_hw_set_tx_retry_limits(ah, i);
|
||||
}
|
||||
|
||||
/* TODO:
|
||||
* 1) Move this on config_interface and handle each case
|
||||
* separately eg. when we have only one STA vif, use
|
||||
|
@ -86,7 +86,7 @@ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
|
||||
if (!ah->ah_bwmode) {
|
||||
dur = ieee80211_generic_frame_duration(sc->hw,
|
||||
NULL, len, rate);
|
||||
return dur;
|
||||
return le16_to_cpu(dur);
|
||||
}
|
||||
|
||||
bitrate = rate->bitrate;
|
||||
@ -265,8 +265,6 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
|
||||
* what rate we should choose to TX ACKs. */
|
||||
tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
|
||||
|
||||
tx_time = le16_to_cpu(tx_time);
|
||||
|
||||
ath5k_hw_reg_write(ah, tx_time, reg);
|
||||
|
||||
if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
|
||||
|
@ -228,24 +228,9 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
|
||||
/*
|
||||
* Set tx retry limits on DCU
|
||||
*/
|
||||
static void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah,
|
||||
unsigned int queue)
|
||||
void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah,
|
||||
unsigned int queue)
|
||||
{
|
||||
u32 retry_lg, retry_sh;
|
||||
|
||||
/*
|
||||
* Calculate and set retry limits
|
||||
*/
|
||||
if (ah->ah_software_retry) {
|
||||
/* XXX Need to test this */
|
||||
retry_lg = ah->ah_limit_tx_retries;
|
||||
retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ?
|
||||
AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg;
|
||||
} else {
|
||||
retry_lg = AR5K_INIT_LG_RETRY;
|
||||
retry_sh = AR5K_INIT_SH_RETRY;
|
||||
}
|
||||
|
||||
/* Single data queue on AR5210 */
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
struct ath5k_txq_info *tq = &ah->ah_txq[queue];
|
||||
@ -255,25 +240,26 @@ static void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah,
|
||||
|
||||
ath5k_hw_reg_write(ah,
|
||||
(tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
|
||||
| AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
|
||||
AR5K_NODCU_RETRY_LMT_SLG_RETRY)
|
||||
| AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
|
||||
AR5K_NODCU_RETRY_LMT_SSH_RETRY)
|
||||
| AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY)
|
||||
| AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY),
|
||||
| AR5K_REG_SM(ah->ah_retry_long,
|
||||
AR5K_NODCU_RETRY_LMT_SLG_RETRY)
|
||||
| AR5K_REG_SM(ah->ah_retry_short,
|
||||
AR5K_NODCU_RETRY_LMT_SSH_RETRY)
|
||||
| AR5K_REG_SM(ah->ah_retry_long,
|
||||
AR5K_NODCU_RETRY_LMT_LG_RETRY)
|
||||
| AR5K_REG_SM(ah->ah_retry_short,
|
||||
AR5K_NODCU_RETRY_LMT_SH_RETRY),
|
||||
AR5K_NODCU_RETRY_LMT);
|
||||
/* DCU on AR5211+ */
|
||||
} else {
|
||||
ath5k_hw_reg_write(ah,
|
||||
AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
|
||||
AR5K_DCU_RETRY_LMT_SLG_RETRY) |
|
||||
AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
|
||||
AR5K_DCU_RETRY_LMT_SSH_RETRY) |
|
||||
AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) |
|
||||
AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY),
|
||||
AR5K_REG_SM(ah->ah_retry_long,
|
||||
AR5K_DCU_RETRY_LMT_RTS)
|
||||
| AR5K_REG_SM(ah->ah_retry_long,
|
||||
AR5K_DCU_RETRY_LMT_STA_RTS)
|
||||
| AR5K_REG_SM(max(ah->ah_retry_long, ah->ah_retry_short),
|
||||
AR5K_DCU_RETRY_LMT_STA_DATA),
|
||||
AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -686,16 +686,15 @@
|
||||
|
||||
/*
|
||||
* DCU retry limit registers
|
||||
* all these fields don't allow zero values
|
||||
*/
|
||||
#define AR5K_DCU_RETRY_LMT_BASE 0x1080 /* Register Address -Queue0 DCU_RETRY_LMT */
|
||||
#define AR5K_DCU_RETRY_LMT_SH_RETRY 0x0000000f /* Short retry limit mask */
|
||||
#define AR5K_DCU_RETRY_LMT_SH_RETRY_S 0
|
||||
#define AR5K_DCU_RETRY_LMT_LG_RETRY 0x000000f0 /* Long retry limit mask */
|
||||
#define AR5K_DCU_RETRY_LMT_LG_RETRY_S 4
|
||||
#define AR5K_DCU_RETRY_LMT_SSH_RETRY 0x00003f00 /* Station short retry limit mask (?) */
|
||||
#define AR5K_DCU_RETRY_LMT_SSH_RETRY_S 8
|
||||
#define AR5K_DCU_RETRY_LMT_SLG_RETRY 0x000fc000 /* Station long retry limit mask (?) */
|
||||
#define AR5K_DCU_RETRY_LMT_SLG_RETRY_S 14
|
||||
#define AR5K_DCU_RETRY_LMT_RTS 0x0000000f /* RTS failure limit. Transmission fails if no CTS is received for this number of times */
|
||||
#define AR5K_DCU_RETRY_LMT_RTS_S 0
|
||||
#define AR5K_DCU_RETRY_LMT_STA_RTS 0x00003f00 /* STA RTS failure limit. If exceeded CW reset */
|
||||
#define AR5K_DCU_RETRY_LMT_STA_RTS_S 8
|
||||
#define AR5K_DCU_RETRY_LMT_STA_DATA 0x000fc000 /* STA data failure limit. If exceeded CW reset. */
|
||||
#define AR5K_DCU_RETRY_LMT_STA_DATA_S 14
|
||||
#define AR5K_QUEUE_DFS_RETRY_LIMIT(_q) AR5K_QUEUE_REG(AR5K_DCU_RETRY_LMT_BASE, _q)
|
||||
|
||||
/*
|
||||
|
107
drivers/net/wireless/ath/ath5k/trace.h
Normal file
107
drivers/net/wireless/ath/ath5k/trace.h
Normal file
@ -0,0 +1,107 @@
|
||||
#if !defined(__TRACE_ATH5K_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define __TRACE_ATH5K_H
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
#include "base.h"
|
||||
|
||||
#ifndef CONFIG_ATH5K_TRACER
|
||||
#undef TRACE_EVENT
|
||||
#define TRACE_EVENT(name, proto, ...) \
|
||||
static inline void trace_ ## name(proto) {}
|
||||
#endif
|
||||
|
||||
struct sk_buff;
|
||||
|
||||
#define PRIV_ENTRY __field(struct ath5k_softc *, priv)
|
||||
#define PRIV_ASSIGN __entry->priv = priv
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM ath5k
|
||||
|
||||
TRACE_EVENT(ath5k_rx,
|
||||
TP_PROTO(struct ath5k_softc *priv, struct sk_buff *skb),
|
||||
TP_ARGS(priv, skb),
|
||||
TP_STRUCT__entry(
|
||||
PRIV_ENTRY
|
||||
__field(unsigned long, skbaddr)
|
||||
__dynamic_array(u8, frame, skb->len)
|
||||
),
|
||||
TP_fast_assign(
|
||||
PRIV_ASSIGN;
|
||||
__entry->skbaddr = (unsigned long) skb;
|
||||
memcpy(__get_dynamic_array(frame), skb->data, skb->len);
|
||||
),
|
||||
TP_printk(
|
||||
"[%p] RX skb=%lx", __entry->priv, __entry->skbaddr
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath5k_tx,
|
||||
TP_PROTO(struct ath5k_softc *priv, struct sk_buff *skb,
|
||||
struct ath5k_txq *q),
|
||||
|
||||
TP_ARGS(priv, skb, q),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
PRIV_ENTRY
|
||||
__field(unsigned long, skbaddr)
|
||||
__field(u8, qnum)
|
||||
__dynamic_array(u8, frame, skb->len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
PRIV_ASSIGN;
|
||||
__entry->skbaddr = (unsigned long) skb;
|
||||
__entry->qnum = (u8) q->qnum;
|
||||
memcpy(__get_dynamic_array(frame), skb->data, skb->len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"[%p] TX skb=%lx q=%d", __entry->priv, __entry->skbaddr,
|
||||
__entry->qnum
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath5k_tx_complete,
|
||||
TP_PROTO(struct ath5k_softc *priv, struct sk_buff *skb,
|
||||
struct ath5k_txq *q, struct ath5k_tx_status *ts),
|
||||
|
||||
TP_ARGS(priv, skb, q, ts),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
PRIV_ENTRY
|
||||
__field(unsigned long, skbaddr)
|
||||
__field(u8, qnum)
|
||||
__field(u8, ts_status)
|
||||
__field(s8, ts_rssi)
|
||||
__field(u8, ts_antenna)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
PRIV_ASSIGN;
|
||||
__entry->skbaddr = (unsigned long) skb;
|
||||
__entry->qnum = (u8) q->qnum;
|
||||
__entry->ts_status = ts->ts_status;
|
||||
__entry->ts_rssi = ts->ts_rssi;
|
||||
__entry->ts_antenna = ts->ts_antenna;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"[%p] TX end skb=%lx q=%d stat=%x rssi=%d ant=%x",
|
||||
__entry->priv, __entry->skbaddr, __entry->qnum,
|
||||
__entry->ts_status, __entry->ts_rssi, __entry->ts_antenna
|
||||
)
|
||||
);
|
||||
|
||||
#endif /* __TRACE_ATH5K_H */
|
||||
|
||||
#ifdef CONFIG_ATH5K_TRACER
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH ../../drivers/net/wireless/ath/ath5k
|
||||
#undef TRACE_INCLUDE_FILE
|
||||
#define TRACE_INCLUDE_FILE trace
|
||||
|
||||
#include <trace/define_trace.h>
|
||||
|
||||
#endif
|
@ -4,7 +4,6 @@ ath9k-y += beacon.o \
|
||||
main.o \
|
||||
recv.o \
|
||||
xmit.o \
|
||||
virtual.o \
|
||||
|
||||
ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
|
||||
ath9k-$(CONFIG_PCI) += pci.o
|
||||
|
@ -54,7 +54,6 @@ static struct ath_bus_ops ath_ahb_bus_ops = {
|
||||
static int ath_ahb_probe(struct platform_device *pdev)
|
||||
{
|
||||
void __iomem *mem;
|
||||
struct ath_wiphy *aphy;
|
||||
struct ath_softc *sc;
|
||||
struct ieee80211_hw *hw;
|
||||
struct resource *res;
|
||||
@ -92,8 +91,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
|
||||
|
||||
irq = res->start;
|
||||
|
||||
hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) +
|
||||
sizeof(struct ath_softc), &ath9k_ops);
|
||||
hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
|
||||
if (hw == NULL) {
|
||||
dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
|
||||
ret = -ENOMEM;
|
||||
@ -103,11 +101,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
|
||||
SET_IEEE80211_DEV(hw, &pdev->dev);
|
||||
platform_set_drvdata(pdev, hw);
|
||||
|
||||
aphy = hw->priv;
|
||||
sc = (struct ath_softc *) (aphy + 1);
|
||||
aphy->sc = sc;
|
||||
aphy->hw = hw;
|
||||
sc->pri_wiphy = aphy;
|
||||
sc = hw->priv;
|
||||
sc->hw = hw;
|
||||
sc->dev = &pdev->dev;
|
||||
sc->mem = mem;
|
||||
@ -151,8 +145,7 @@ static int ath_ahb_remove(struct platform_device *pdev)
|
||||
struct ieee80211_hw *hw = platform_get_drvdata(pdev);
|
||||
|
||||
if (hw) {
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
void __iomem *mem = sc->mem;
|
||||
|
||||
ath9k_deinit_device(sc);
|
||||
|
@ -426,9 +426,8 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
|
||||
}
|
||||
|
||||
/* WAR for ASPM system hang */
|
||||
if (AR_SREV_9280(ah) || AR_SREV_9285(ah) || AR_SREV_9287(ah)) {
|
||||
if (AR_SREV_9285(ah) || AR_SREV_9287(ah))
|
||||
val |= (AR_WA_BIT6 | AR_WA_BIT7);
|
||||
}
|
||||
|
||||
if (AR_SREV_9285E_20(ah))
|
||||
val |= AR_WA_BIT23;
|
||||
|
@ -3673,7 +3673,7 @@ static void ar9003_hw_internal_regulator_apply(struct ath_hw *ah)
|
||||
return;
|
||||
|
||||
reg_pmu_set = (5 << 1) | (7 << 4) | (1 << 8) |
|
||||
(7 << 14) | (6 << 17) | (1 << 20) |
|
||||
(2 << 14) | (6 << 17) | (1 << 20) |
|
||||
(3 << 24) | (1 << 28);
|
||||
|
||||
REG_WRITE(ah, AR_PHY_PMU1, reg_pmu_set);
|
||||
|
@ -233,7 +233,6 @@ struct ath_buf {
|
||||
bool bf_stale;
|
||||
u16 bf_flags;
|
||||
struct ath_buf_state bf_state;
|
||||
struct ath_wiphy *aphy;
|
||||
};
|
||||
|
||||
struct ath_atx_tid {
|
||||
@ -311,6 +310,8 @@ struct ath_rx {
|
||||
struct ath_descdma rxdma;
|
||||
struct ath_buf *rx_bufptr;
|
||||
struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
|
||||
|
||||
struct sk_buff *frag;
|
||||
};
|
||||
|
||||
int ath_startrecv(struct ath_softc *sc);
|
||||
@ -388,7 +389,6 @@ struct ath_beacon {
|
||||
u32 ast_be_xmit;
|
||||
u64 bc_tstamp;
|
||||
struct ieee80211_vif *bslot[ATH_BCBUF];
|
||||
struct ath_wiphy *bslot_aphy[ATH_BCBUF];
|
||||
int slottime;
|
||||
int slotupdate;
|
||||
struct ath9k_tx_queue_info beacon_qi;
|
||||
@ -399,7 +399,7 @@ struct ath_beacon {
|
||||
|
||||
void ath_beacon_tasklet(unsigned long data);
|
||||
void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
|
||||
int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif);
|
||||
int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif);
|
||||
void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
|
||||
int ath_beaconq_config(struct ath_softc *sc);
|
||||
|
||||
@ -536,7 +536,6 @@ struct ath_ant_comb {
|
||||
#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */
|
||||
#define ATH_MAX_SW_RETRIES 10
|
||||
#define ATH_CHAN_MAX 255
|
||||
#define IEEE80211_WEP_NKID 4 /* number of key ids */
|
||||
|
||||
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
|
||||
#define ATH_RATE_DUMMY_MARKER 0
|
||||
@ -564,7 +563,6 @@ struct ath_ant_comb {
|
||||
#define PS_WAIT_FOR_TX_ACK BIT(3)
|
||||
#define PS_BEACON_SYNC BIT(4)
|
||||
|
||||
struct ath_wiphy;
|
||||
struct ath_rate_table;
|
||||
|
||||
struct ath9k_vif_iter_data {
|
||||
@ -585,20 +583,8 @@ struct ath_softc {
|
||||
struct ieee80211_hw *hw;
|
||||
struct device *dev;
|
||||
|
||||
spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */
|
||||
struct ath_wiphy *pri_wiphy;
|
||||
struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may
|
||||
* have NULL entries */
|
||||
int num_sec_wiphy; /* number of sec_wiphy pointers in the array */
|
||||
int chan_idx;
|
||||
int chan_is_ht;
|
||||
struct ath_wiphy *next_wiphy;
|
||||
struct work_struct chan_work;
|
||||
int wiphy_select_failures;
|
||||
unsigned long wiphy_select_first_fail;
|
||||
struct delayed_work wiphy_work;
|
||||
unsigned long wiphy_scheduler_int;
|
||||
int wiphy_scheduler_index;
|
||||
struct survey_info *cur_survey;
|
||||
struct survey_info survey[ATH9K_NUM_CHANNELS];
|
||||
|
||||
@ -642,6 +628,9 @@ struct ath_softc {
|
||||
int led_on_cnt;
|
||||
int led_off_cnt;
|
||||
|
||||
struct ath9k_hw_cal_data caldata;
|
||||
int last_rssi;
|
||||
|
||||
int beacon_interval;
|
||||
|
||||
#ifdef CONFIG_ATH9K_DEBUGFS
|
||||
@ -652,6 +641,7 @@ struct ath_softc {
|
||||
#endif
|
||||
struct ath_beacon_config cur_beacon_conf;
|
||||
struct delayed_work tx_complete_work;
|
||||
struct delayed_work hw_pll_work;
|
||||
struct ath_btcoex btcoex;
|
||||
|
||||
struct ath_descdma txsdma;
|
||||
@ -661,23 +651,6 @@ struct ath_softc {
|
||||
struct pm_qos_request_list pm_qos_req;
|
||||
};
|
||||
|
||||
struct ath_wiphy {
|
||||
struct ath_softc *sc; /* shared for all virtual wiphys */
|
||||
struct ieee80211_hw *hw;
|
||||
struct ath9k_hw_cal_data caldata;
|
||||
enum ath_wiphy_state {
|
||||
ATH_WIPHY_INACTIVE,
|
||||
ATH_WIPHY_ACTIVE,
|
||||
ATH_WIPHY_PAUSING,
|
||||
ATH_WIPHY_PAUSED,
|
||||
ATH_WIPHY_SCAN,
|
||||
} state;
|
||||
bool idle;
|
||||
int chan_idx;
|
||||
int chan_is_ht;
|
||||
int last_rssi;
|
||||
};
|
||||
|
||||
void ath9k_tasklet(unsigned long data);
|
||||
int ath_reset(struct ath_softc *sc, bool retry_tx);
|
||||
int ath_cabq_update(struct ath_softc *);
|
||||
@ -699,8 +672,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
|
||||
const struct ath_bus_ops *bus_ops);
|
||||
void ath9k_deinit_device(struct ath_softc *sc);
|
||||
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
|
||||
void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
||||
struct ath9k_channel *ichan);
|
||||
int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
||||
struct ath9k_channel *hchan);
|
||||
|
||||
@ -731,24 +702,6 @@ void ath9k_ps_restore(struct ath_softc *sc);
|
||||
u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate);
|
||||
|
||||
void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
|
||||
int ath9k_wiphy_add(struct ath_softc *sc);
|
||||
int ath9k_wiphy_del(struct ath_wiphy *aphy);
|
||||
void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, int ftype);
|
||||
int ath9k_wiphy_pause(struct ath_wiphy *aphy);
|
||||
int ath9k_wiphy_unpause(struct ath_wiphy *aphy);
|
||||
int ath9k_wiphy_select(struct ath_wiphy *aphy);
|
||||
void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int);
|
||||
void ath9k_wiphy_chan_work(struct work_struct *work);
|
||||
bool ath9k_wiphy_started(struct ath_softc *sc);
|
||||
void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
|
||||
struct ath_wiphy *selected);
|
||||
bool ath9k_wiphy_scanning(struct ath_softc *sc);
|
||||
void ath9k_wiphy_work(struct work_struct *work);
|
||||
bool ath9k_all_wiphys_idle(struct ath_softc *sc);
|
||||
void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle);
|
||||
|
||||
void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue);
|
||||
bool ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue);
|
||||
|
||||
void ath_start_rfkill_poll(struct ath_softc *sc);
|
||||
extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw);
|
||||
|
@ -112,8 +112,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
|
||||
|
||||
static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_tx_control txctl;
|
||||
|
||||
@ -132,8 +131,7 @@ static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_buf *bf;
|
||||
struct ath_vif *avp;
|
||||
@ -142,9 +140,6 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
|
||||
struct ieee80211_tx_info *info;
|
||||
int cabq_depth;
|
||||
|
||||
if (aphy->state != ATH_WIPHY_ACTIVE)
|
||||
return NULL;
|
||||
|
||||
avp = (void *)vif->drv_priv;
|
||||
cabq = sc->beacon.cabq;
|
||||
|
||||
@ -225,9 +220,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
|
||||
return bf;
|
||||
}
|
||||
|
||||
int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
|
||||
int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_vif *avp;
|
||||
struct ath_buf *bf;
|
||||
@ -261,7 +255,6 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
|
||||
}
|
||||
BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL);
|
||||
sc->beacon.bslot[avp->av_bslot] = vif;
|
||||
sc->beacon.bslot_aphy[avp->av_bslot] = aphy;
|
||||
sc->nbcnvifs++;
|
||||
}
|
||||
}
|
||||
@ -332,7 +325,6 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
|
||||
|
||||
if (avp->av_bslot != -1) {
|
||||
sc->beacon.bslot[avp->av_bslot] = NULL;
|
||||
sc->beacon.bslot_aphy[avp->av_bslot] = NULL;
|
||||
sc->nbcnvifs--;
|
||||
}
|
||||
|
||||
@ -358,7 +350,6 @@ void ath_beacon_tasklet(unsigned long data)
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_buf *bf = NULL;
|
||||
struct ieee80211_vif *vif;
|
||||
struct ath_wiphy *aphy;
|
||||
int slot;
|
||||
u32 bfaddr, bc = 0, tsftu;
|
||||
u64 tsf;
|
||||
@ -416,7 +407,6 @@ void ath_beacon_tasklet(unsigned long data)
|
||||
*/
|
||||
slot = ATH_BCBUF - slot - 1;
|
||||
vif = sc->beacon.bslot[slot];
|
||||
aphy = sc->beacon.bslot_aphy[slot];
|
||||
|
||||
ath_dbg(common, ATH_DBG_BEACON,
|
||||
"slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
|
||||
@ -424,7 +414,7 @@ void ath_beacon_tasklet(unsigned long data)
|
||||
|
||||
bfaddr = 0;
|
||||
if (vif) {
|
||||
bf = ath_beacon_generate(aphy->hw, vif);
|
||||
bf = ath_beacon_generate(sc->hw, vif);
|
||||
if (bf != NULL) {
|
||||
bfaddr = bf->bf_daddr;
|
||||
bc = 1;
|
||||
|
@ -23,8 +23,6 @@
|
||||
|
||||
/* Common header for Atheros 802.11n base driver cores */
|
||||
|
||||
#define IEEE80211_WEP_NKID 4
|
||||
|
||||
#define WME_NUM_TID 16
|
||||
#define WME_BA_BMP_SIZE 64
|
||||
#define WME_MAX_BA WME_BA_BMP_SIZE
|
||||
|
@ -381,41 +381,21 @@ static const struct file_operations fops_interrupt = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static const char * ath_wiphy_state_str(enum ath_wiphy_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case ATH_WIPHY_INACTIVE:
|
||||
return "INACTIVE";
|
||||
case ATH_WIPHY_ACTIVE:
|
||||
return "ACTIVE";
|
||||
case ATH_WIPHY_PAUSING:
|
||||
return "PAUSING";
|
||||
case ATH_WIPHY_PAUSED:
|
||||
return "PAUSED";
|
||||
case ATH_WIPHY_SCAN:
|
||||
return "SCAN";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_softc *sc = file->private_data;
|
||||
struct ath_wiphy *aphy = sc->pri_wiphy;
|
||||
struct ieee80211_channel *chan = aphy->hw->conf.channel;
|
||||
struct ieee80211_channel *chan = sc->hw->conf.channel;
|
||||
char buf[512];
|
||||
unsigned int len = 0;
|
||||
int i;
|
||||
u8 addr[ETH_ALEN];
|
||||
u32 tmp;
|
||||
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"primary: %s (%s chan=%d ht=%d)\n",
|
||||
wiphy_name(sc->pri_wiphy->hw->wiphy),
|
||||
ath_wiphy_state_str(sc->pri_wiphy->state),
|
||||
"%s (chan=%d ht=%d)\n",
|
||||
wiphy_name(sc->hw->wiphy),
|
||||
ieee80211_frequency_to_channel(chan->center_freq),
|
||||
aphy->chan_is_ht);
|
||||
conf_is_ht(&sc->hw->conf));
|
||||
|
||||
put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr);
|
||||
put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
|
||||
@ -457,136 +437,28 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
|
||||
else
|
||||
len += snprintf(buf + len, sizeof(buf) - len, "\n");
|
||||
|
||||
/* Put variable-length stuff down here, and check for overflows. */
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
struct ath_wiphy *aphy_tmp = sc->sec_wiphy[i];
|
||||
if (aphy_tmp == NULL)
|
||||
continue;
|
||||
chan = aphy_tmp->hw->conf.channel;
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"secondary: %s (%s chan=%d ht=%d)\n",
|
||||
wiphy_name(aphy_tmp->hw->wiphy),
|
||||
ath_wiphy_state_str(aphy_tmp->state),
|
||||
ieee80211_frequency_to_channel(chan->center_freq),
|
||||
aphy_tmp->chan_is_ht);
|
||||
}
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static struct ath_wiphy * get_wiphy(struct ath_softc *sc, const char *name)
|
||||
{
|
||||
int i;
|
||||
if (strcmp(name, wiphy_name(sc->pri_wiphy->hw->wiphy)) == 0)
|
||||
return sc->pri_wiphy;
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
struct ath_wiphy *aphy = sc->sec_wiphy[i];
|
||||
if (aphy && strcmp(name, wiphy_name(aphy->hw->wiphy)) == 0)
|
||||
return aphy;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int del_wiphy(struct ath_softc *sc, const char *name)
|
||||
{
|
||||
struct ath_wiphy *aphy = get_wiphy(sc, name);
|
||||
if (!aphy)
|
||||
return -ENOENT;
|
||||
return ath9k_wiphy_del(aphy);
|
||||
}
|
||||
|
||||
static int pause_wiphy(struct ath_softc *sc, const char *name)
|
||||
{
|
||||
struct ath_wiphy *aphy = get_wiphy(sc, name);
|
||||
if (!aphy)
|
||||
return -ENOENT;
|
||||
return ath9k_wiphy_pause(aphy);
|
||||
}
|
||||
|
||||
static int unpause_wiphy(struct ath_softc *sc, const char *name)
|
||||
{
|
||||
struct ath_wiphy *aphy = get_wiphy(sc, name);
|
||||
if (!aphy)
|
||||
return -ENOENT;
|
||||
return ath9k_wiphy_unpause(aphy);
|
||||
}
|
||||
|
||||
static int select_wiphy(struct ath_softc *sc, const char *name)
|
||||
{
|
||||
struct ath_wiphy *aphy = get_wiphy(sc, name);
|
||||
if (!aphy)
|
||||
return -ENOENT;
|
||||
return ath9k_wiphy_select(aphy);
|
||||
}
|
||||
|
||||
static int schedule_wiphy(struct ath_softc *sc, const char *msec)
|
||||
{
|
||||
ath9k_wiphy_set_scheduler(sc, simple_strtoul(msec, NULL, 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t write_file_wiphy(struct file *file, const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_softc *sc = file->private_data;
|
||||
char buf[50];
|
||||
size_t len;
|
||||
|
||||
len = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, len))
|
||||
return -EFAULT;
|
||||
buf[len] = '\0';
|
||||
if (len > 0 && buf[len - 1] == '\n')
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
if (strncmp(buf, "add", 3) == 0) {
|
||||
int res = ath9k_wiphy_add(sc);
|
||||
if (res < 0)
|
||||
return res;
|
||||
} else if (strncmp(buf, "del=", 4) == 0) {
|
||||
int res = del_wiphy(sc, buf + 4);
|
||||
if (res < 0)
|
||||
return res;
|
||||
} else if (strncmp(buf, "pause=", 6) == 0) {
|
||||
int res = pause_wiphy(sc, buf + 6);
|
||||
if (res < 0)
|
||||
return res;
|
||||
} else if (strncmp(buf, "unpause=", 8) == 0) {
|
||||
int res = unpause_wiphy(sc, buf + 8);
|
||||
if (res < 0)
|
||||
return res;
|
||||
} else if (strncmp(buf, "select=", 7) == 0) {
|
||||
int res = select_wiphy(sc, buf + 7);
|
||||
if (res < 0)
|
||||
return res;
|
||||
} else if (strncmp(buf, "schedule=", 9) == 0) {
|
||||
int res = schedule_wiphy(sc, buf + 9);
|
||||
if (res < 0)
|
||||
return res;
|
||||
} else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_wiphy = {
|
||||
.read = read_file_wiphy,
|
||||
.write = write_file_wiphy,
|
||||
.open = ath9k_debugfs_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
#define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum
|
||||
#define PR(str, elem) \
|
||||
do { \
|
||||
len += snprintf(buf + len, size - len, \
|
||||
"%s%13u%11u%10u%10u\n", str, \
|
||||
sc->debug.stats.txstats[WME_AC_BE].elem, \
|
||||
sc->debug.stats.txstats[WME_AC_BK].elem, \
|
||||
sc->debug.stats.txstats[WME_AC_VI].elem, \
|
||||
sc->debug.stats.txstats[WME_AC_VO].elem); \
|
||||
sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem, \
|
||||
sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem, \
|
||||
sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem, \
|
||||
sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem); \
|
||||
if (len >= size) \
|
||||
goto done; \
|
||||
} while(0)
|
||||
@ -595,10 +467,10 @@ static const struct file_operations fops_wiphy = {
|
||||
do { \
|
||||
len += snprintf(buf + len, size - len, \
|
||||
"%s%13u%11u%10u%10u\n", str, \
|
||||
(unsigned int)(sc->tx.txq[ATH_TXQ_AC_BE].elem), \
|
||||
(unsigned int)(sc->tx.txq[ATH_TXQ_AC_BK].elem), \
|
||||
(unsigned int)(sc->tx.txq[ATH_TXQ_AC_VI].elem), \
|
||||
(unsigned int)(sc->tx.txq[ATH_TXQ_AC_VO].elem)); \
|
||||
(unsigned int)(sc->tx.txq_map[WME_AC_BE]->elem), \
|
||||
(unsigned int)(sc->tx.txq_map[WME_AC_BK]->elem), \
|
||||
(unsigned int)(sc->tx.txq_map[WME_AC_VI]->elem), \
|
||||
(unsigned int)(sc->tx.txq_map[WME_AC_VO]->elem)); \
|
||||
if (len >= size) \
|
||||
goto done; \
|
||||
} while(0)
|
||||
@ -607,10 +479,10 @@ do { \
|
||||
do { \
|
||||
len += snprintf(buf + len, size - len, \
|
||||
"%s%13i%11i%10i%10i\n", str, \
|
||||
list_empty(&sc->tx.txq[ATH_TXQ_AC_BE].elem), \
|
||||
list_empty(&sc->tx.txq[ATH_TXQ_AC_BK].elem), \
|
||||
list_empty(&sc->tx.txq[ATH_TXQ_AC_VI].elem), \
|
||||
list_empty(&sc->tx.txq[ATH_TXQ_AC_VO].elem)); \
|
||||
list_empty(&sc->tx.txq_map[WME_AC_BE]->elem), \
|
||||
list_empty(&sc->tx.txq_map[WME_AC_BK]->elem), \
|
||||
list_empty(&sc->tx.txq_map[WME_AC_VI]->elem), \
|
||||
list_empty(&sc->tx.txq_map[WME_AC_VO]->elem)); \
|
||||
if (len >= size) \
|
||||
goto done; \
|
||||
} while (0)
|
||||
@ -657,10 +529,10 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
|
||||
PR("hw-tx-proc-desc: ", txprocdesc);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%s%11p%11p%10p%10p\n", "txq-memory-address:",
|
||||
&(sc->tx.txq[ATH_TXQ_AC_BE]),
|
||||
&(sc->tx.txq[ATH_TXQ_AC_BK]),
|
||||
&(sc->tx.txq[ATH_TXQ_AC_VI]),
|
||||
&(sc->tx.txq[ATH_TXQ_AC_VO]));
|
||||
&(sc->tx.txq_map[WME_AC_BE]),
|
||||
&(sc->tx.txq_map[WME_AC_BK]),
|
||||
&(sc->tx.txq_map[WME_AC_VI]),
|
||||
&(sc->tx.txq_map[WME_AC_VO]));
|
||||
if (len >= size)
|
||||
goto done;
|
||||
|
||||
@ -880,9 +752,9 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
|
||||
}
|
||||
|
||||
void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
|
||||
struct ath_tx_status *ts)
|
||||
struct ath_tx_status *ts, struct ath_txq *txq)
|
||||
{
|
||||
int qnum = skb_get_queue_mapping(bf->bf_mpdu);
|
||||
int qnum = txq->axq_qnum;
|
||||
|
||||
TX_STAT_INC(qnum, tx_pkts_all);
|
||||
sc->debug.stats.txstats[qnum].tx_bytes_all += bf->bf_mpdu->len;
|
||||
|
@ -175,7 +175,7 @@ int ath9k_init_debug(struct ath_hw *ah);
|
||||
|
||||
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
|
||||
void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
|
||||
struct ath_tx_status *ts);
|
||||
struct ath_tx_status *ts, struct ath_txq *txq);
|
||||
void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs);
|
||||
|
||||
#else
|
||||
@ -192,7 +192,8 @@ static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
|
||||
|
||||
static inline void ath_debug_stat_tx(struct ath_softc *sc,
|
||||
struct ath_buf *bf,
|
||||
struct ath_tx_status *ts)
|
||||
struct ath_tx_status *ts,
|
||||
struct ath_txq *txq)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -247,9 +247,9 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
|
||||
}
|
||||
|
||||
/* Enable fixup for AR_AN_TOP2 if necessary */
|
||||
if (AR_SREV_9280_20_OR_LATER(ah) &&
|
||||
(eep->baseEepHeader.version & 0xff) > 0x0a &&
|
||||
eep->baseEepHeader.pwdclkind == 0)
|
||||
if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
|
||||
((eep->baseEepHeader.version & 0xff) > 0x0a) &&
|
||||
(eep->baseEepHeader.pwdclkind == 0))
|
||||
ah->need_an_top2_fixup = 1;
|
||||
|
||||
if ((common->bus_ops->ath_bus_type == ATH_USB) &&
|
||||
|
@ -201,8 +201,7 @@ static bool ath_is_rfkill_set(struct ath_softc *sc)
|
||||
|
||||
void ath9k_rfkill_poll_state(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
bool blocked = !!ath_is_rfkill_set(sc);
|
||||
|
||||
wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
|
||||
|
@ -142,9 +142,6 @@ static void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
|
||||
{
|
||||
ath9k_htc_exit_debug(priv->ah);
|
||||
ath9k_hw_deinit(priv->ah);
|
||||
tasklet_kill(&priv->swba_tasklet);
|
||||
tasklet_kill(&priv->rx_tasklet);
|
||||
tasklet_kill(&priv->tx_tasklet);
|
||||
kfree(priv->ah);
|
||||
priv->ah = NULL;
|
||||
}
|
||||
|
@ -1026,12 +1026,6 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
|
||||
int ret = 0;
|
||||
u8 cmd_rsp;
|
||||
|
||||
/* Cancel all the running timers/work .. */
|
||||
cancel_work_sync(&priv->fatal_work);
|
||||
cancel_work_sync(&priv->ps_work);
|
||||
cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
|
||||
ath9k_led_stop_brightness(priv);
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
if (priv->op_flags & OP_INVALID) {
|
||||
@ -1045,8 +1039,23 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
|
||||
WMI_CMD(WMI_DISABLE_INTR_CMDID);
|
||||
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
|
||||
WMI_CMD(WMI_STOP_RECV_CMDID);
|
||||
|
||||
tasklet_kill(&priv->swba_tasklet);
|
||||
tasklet_kill(&priv->rx_tasklet);
|
||||
tasklet_kill(&priv->tx_tasklet);
|
||||
|
||||
skb_queue_purge(&priv->tx_queue);
|
||||
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
/* Cancel all the running timers/work .. */
|
||||
cancel_work_sync(&priv->fatal_work);
|
||||
cancel_work_sync(&priv->ps_work);
|
||||
cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
|
||||
ath9k_led_stop_brightness(priv);
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
/* Remove monitor interface here */
|
||||
if (ah->opmode == NL80211_IFTYPE_MONITOR) {
|
||||
if (ath9k_htc_remove_monitor_interface(priv))
|
||||
|
@ -671,13 +671,50 @@ static void ath9k_hw_init_qos(struct ath_hw *ah)
|
||||
REGWRITE_BUFFER_FLUSH(ah);
|
||||
}
|
||||
|
||||
unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah)
|
||||
{
|
||||
REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) & ~(PLL3_DO_MEAS_MASK)));
|
||||
udelay(100);
|
||||
REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) | PLL3_DO_MEAS_MASK));
|
||||
|
||||
while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0)
|
||||
udelay(100);
|
||||
|
||||
return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3;
|
||||
}
|
||||
EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc);
|
||||
|
||||
#define DPLL2_KD_VAL 0x3D
|
||||
#define DPLL2_KI_VAL 0x06
|
||||
#define DPLL3_PHASE_SHIFT_VAL 0x1
|
||||
|
||||
static void ath9k_hw_init_pll(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan)
|
||||
{
|
||||
u32 pll;
|
||||
|
||||
if (AR_SREV_9485(ah))
|
||||
if (AR_SREV_9485(ah)) {
|
||||
REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666);
|
||||
REG_WRITE(ah, AR_CH0_DDR_DPLL2, 0x19e82f01);
|
||||
|
||||
REG_RMW_FIELD(ah, AR_CH0_DDR_DPLL3,
|
||||
AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);
|
||||
|
||||
REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
|
||||
udelay(100);
|
||||
|
||||
REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666);
|
||||
|
||||
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
|
||||
AR_CH0_DPLL2_KD, DPLL2_KD_VAL);
|
||||
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
|
||||
AR_CH0_DPLL2_KI, DPLL2_KI_VAL);
|
||||
|
||||
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3,
|
||||
AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);
|
||||
REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c);
|
||||
udelay(110);
|
||||
}
|
||||
|
||||
pll = ath9k_hw_compute_pll_control(ah, chan);
|
||||
|
||||
@ -1349,8 +1386,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
ath9k_hw_spur_mitigate_freq(ah, chan);
|
||||
ah->eep_ops->set_board_values(ah, chan);
|
||||
|
||||
ath9k_hw_set_operating_mode(ah, ah->opmode);
|
||||
|
||||
ENABLE_REGWRITE_BUFFER(ah);
|
||||
|
||||
REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
|
||||
@ -1368,6 +1403,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
|
||||
REGWRITE_BUFFER_FLUSH(ah);
|
||||
|
||||
ath9k_hw_set_operating_mode(ah, ah->opmode);
|
||||
|
||||
r = ath9k_hw_rf_set_freq(ah, chan);
|
||||
if (r)
|
||||
return r;
|
||||
|
@ -929,6 +929,7 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
|
||||
void ath9k_hw_reset_tsf(struct ath_hw *ah);
|
||||
void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
|
||||
void ath9k_hw_init_global_settings(struct ath_hw *ah);
|
||||
unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah);
|
||||
void ath9k_hw_set11nmac2040(struct ath_hw *ah);
|
||||
void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);
|
||||
void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
|
||||
|
@ -254,8 +254,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
|
||||
struct regulatory_request *request)
|
||||
{
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah);
|
||||
|
||||
return ath_reg_notifier_apply(wiphy, request, reg);
|
||||
@ -517,10 +516,8 @@ static void ath9k_init_misc(struct ath_softc *sc)
|
||||
|
||||
sc->beacon.slottime = ATH9K_SLOT_TIME_9;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++)
|
||||
sc->beacon.bslot[i] = NULL;
|
||||
sc->beacon.bslot_aphy[i] = NULL;
|
||||
}
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
|
||||
sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT;
|
||||
@ -556,7 +553,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
|
||||
common->btcoex_enabled = ath9k_btcoex_enable == 1;
|
||||
spin_lock_init(&common->cc_lock);
|
||||
|
||||
spin_lock_init(&sc->wiphy_lock);
|
||||
spin_lock_init(&sc->sc_serial_rw);
|
||||
spin_lock_init(&sc->sc_pm_lock);
|
||||
mutex_init(&sc->mutex);
|
||||
@ -604,8 +600,6 @@ err_btcoex:
|
||||
err_queues:
|
||||
ath9k_hw_deinit(ah);
|
||||
err_hw:
|
||||
tasklet_kill(&sc->intr_tq);
|
||||
tasklet_kill(&sc->bcon_tasklet);
|
||||
|
||||
kfree(ah);
|
||||
sc->sc_ah = NULL;
|
||||
@ -707,7 +701,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
|
||||
const struct ath_bus_ops *bus_ops)
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_common *common;
|
||||
struct ath_hw *ah;
|
||||
int error = 0;
|
||||
@ -762,10 +755,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
|
||||
|
||||
INIT_WORK(&sc->hw_check_work, ath_hw_check);
|
||||
INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
|
||||
INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
|
||||
INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
|
||||
sc->wiphy_scheduler_int = msecs_to_jiffies(500);
|
||||
aphy->last_rssi = ATH_RSSI_DUMMY_MARKER;
|
||||
sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
|
||||
|
||||
ath_init_leds(sc);
|
||||
ath_start_rfkill_poll(sc);
|
||||
@ -813,9 +803,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
|
||||
|
||||
ath9k_hw_deinit(sc->sc_ah);
|
||||
|
||||
tasklet_kill(&sc->intr_tq);
|
||||
tasklet_kill(&sc->bcon_tasklet);
|
||||
|
||||
kfree(sc->sc_ah);
|
||||
sc->sc_ah = NULL;
|
||||
}
|
||||
@ -823,28 +810,19 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
|
||||
void ath9k_deinit_device(struct ath_softc *sc)
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
int i = 0;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
|
||||
wiphy_rfkill_stop_polling(sc->hw->wiphy);
|
||||
ath_deinit_leds(sc);
|
||||
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
struct ath_wiphy *aphy = sc->sec_wiphy[i];
|
||||
if (aphy == NULL)
|
||||
continue;
|
||||
sc->sec_wiphy[i] = NULL;
|
||||
ieee80211_unregister_hw(aphy->hw);
|
||||
ieee80211_free_hw(aphy->hw);
|
||||
}
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
ieee80211_unregister_hw(hw);
|
||||
pm_qos_remove_request(&sc->pm_qos_req);
|
||||
ath_rx_cleanup(sc);
|
||||
ath_tx_cleanup(sc);
|
||||
ath9k_deinit_softc(sc);
|
||||
kfree(sc->sec_wiphy);
|
||||
}
|
||||
|
||||
void ath_descdma_cleanup(struct ath_softc *sc,
|
||||
|
@ -639,6 +639,8 @@ enum ath9k_rx_filter {
|
||||
ATH9K_RX_FILTER_PHYERR = 0x00000100,
|
||||
ATH9K_RX_FILTER_MYBEACON = 0x00000200,
|
||||
ATH9K_RX_FILTER_COMP_BAR = 0x00000400,
|
||||
ATH9K_RX_FILTER_COMP_BA = 0x00000800,
|
||||
ATH9K_RX_FILTER_UNCOMP_BA_BAR = 0x00001000,
|
||||
ATH9K_RX_FILTER_PSPOLL = 0x00004000,
|
||||
ATH9K_RX_FILTER_PHYRADAR = 0x00002000,
|
||||
ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000,
|
||||
|
@ -73,7 +73,7 @@ static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc,
|
||||
|
||||
chan_idx = curchan->hw_value;
|
||||
channel = &sc->sc_ah->channels[chan_idx];
|
||||
ath9k_update_ichannel(sc, hw, channel);
|
||||
ath9k_cmn_update_ichannel(channel, curchan, hw->conf.channel_type);
|
||||
return channel;
|
||||
}
|
||||
|
||||
@ -215,7 +215,6 @@ static void ath_update_survey_stats(struct ath_softc *sc)
|
||||
int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
||||
struct ath9k_channel *hchan)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ieee80211_conf *conf = &common->hw->conf;
|
||||
@ -231,6 +230,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
||||
cancel_work_sync(&sc->paprd_work);
|
||||
cancel_work_sync(&sc->hw_check_work);
|
||||
cancel_delayed_work_sync(&sc->tx_complete_work);
|
||||
cancel_delayed_work_sync(&sc->hw_pll_work);
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
|
||||
@ -262,7 +262,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
||||
fastcc = false;
|
||||
|
||||
if (!(sc->sc_flags & SC_OP_OFFCHANNEL))
|
||||
caldata = &aphy->caldata;
|
||||
caldata = &sc->caldata;
|
||||
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"(%u MHz) -> (%u MHz), conf_is_ht40: %d fastcc: %d\n",
|
||||
@ -291,10 +291,13 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
||||
if (sc->sc_flags & SC_OP_BEACONS)
|
||||
ath_beacon_config(sc, NULL);
|
||||
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
|
||||
ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
|
||||
ath_start_ani(common);
|
||||
}
|
||||
|
||||
ps_restore:
|
||||
ieee80211_wake_queues(hw);
|
||||
|
||||
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||
|
||||
ath9k_ps_restore(sc);
|
||||
@ -328,6 +331,8 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_tx_control txctl;
|
||||
int time_left;
|
||||
|
||||
@ -345,8 +350,12 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int
|
||||
init_completion(&sc->paprd_complete);
|
||||
sc->paprd_pending = true;
|
||||
txctl.paprd = BIT(chain);
|
||||
if (ath_tx_start(hw, skb, &txctl) != 0)
|
||||
|
||||
if (ath_tx_start(hw, skb, &txctl) != 0) {
|
||||
ath_dbg(common, ATH_DBG_XMIT, "PAPRD TX failed\n");
|
||||
dev_kfree_skb_any(skb);
|
||||
return false;
|
||||
}
|
||||
|
||||
time_left = wait_for_completion_timeout(&sc->paprd_complete,
|
||||
msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
|
||||
@ -803,54 +812,11 @@ chip_reset:
|
||||
#undef SCHED_INTR
|
||||
}
|
||||
|
||||
static u32 ath_get_extchanmode(struct ath_softc *sc,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type)
|
||||
{
|
||||
u32 chanmode = 0;
|
||||
|
||||
switch (chan->band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
switch(channel_type) {
|
||||
case NL80211_CHAN_NO_HT:
|
||||
case NL80211_CHAN_HT20:
|
||||
chanmode = CHANNEL_G_HT20;
|
||||
break;
|
||||
case NL80211_CHAN_HT40PLUS:
|
||||
chanmode = CHANNEL_G_HT40PLUS;
|
||||
break;
|
||||
case NL80211_CHAN_HT40MINUS:
|
||||
chanmode = CHANNEL_G_HT40MINUS;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
switch(channel_type) {
|
||||
case NL80211_CHAN_NO_HT:
|
||||
case NL80211_CHAN_HT20:
|
||||
chanmode = CHANNEL_A_HT20;
|
||||
break;
|
||||
case NL80211_CHAN_HT40PLUS:
|
||||
chanmode = CHANNEL_A_HT40PLUS;
|
||||
break;
|
||||
case NL80211_CHAN_HT40MINUS:
|
||||
chanmode = CHANNEL_A_HT40MINUS;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return chanmode;
|
||||
}
|
||||
|
||||
static void ath9k_bss_assoc_info(struct ath_softc *sc,
|
||||
struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *bss_conf)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
@ -874,7 +840,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
|
||||
ath_beacon_config(sc, vif);
|
||||
|
||||
/* Reset rssi stats */
|
||||
aphy->last_rssi = ATH_RSSI_DUMMY_MARKER;
|
||||
sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
|
||||
sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
|
||||
|
||||
sc->sc_flags |= SC_OP_ANI_RUN;
|
||||
@ -977,8 +943,6 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
|
||||
|
||||
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
|
||||
}
|
||||
|
||||
int ath_reset(struct ath_softc *sc, bool retry_tx)
|
||||
@ -1043,38 +1007,13 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* XXX: Remove me once we don't depend on ath9k_channel for all
|
||||
* this redundant data */
|
||||
void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
||||
struct ath9k_channel *ichan)
|
||||
{
|
||||
struct ieee80211_channel *chan = hw->conf.channel;
|
||||
struct ieee80211_conf *conf = &hw->conf;
|
||||
|
||||
ichan->channel = chan->center_freq;
|
||||
ichan->chan = chan;
|
||||
|
||||
if (chan->band == IEEE80211_BAND_2GHZ) {
|
||||
ichan->chanmode = CHANNEL_G;
|
||||
ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G;
|
||||
} else {
|
||||
ichan->chanmode = CHANNEL_A;
|
||||
ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM;
|
||||
}
|
||||
|
||||
if (conf_is_ht(conf))
|
||||
ichan->chanmode = ath_get_extchanmode(sc, chan,
|
||||
conf->channel_type);
|
||||
}
|
||||
|
||||
/**********************/
|
||||
/* mac80211 callbacks */
|
||||
/**********************/
|
||||
|
||||
static int ath9k_start(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ieee80211_channel *curchan = hw->conf.channel;
|
||||
@ -1087,29 +1026,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
if (ath9k_wiphy_started(sc)) {
|
||||
if (sc->chan_idx == curchan->hw_value) {
|
||||
/*
|
||||
* Already on the operational channel, the new wiphy
|
||||
* can be marked active.
|
||||
*/
|
||||
aphy->state = ATH_WIPHY_ACTIVE;
|
||||
ieee80211_wake_queues(hw);
|
||||
} else {
|
||||
/*
|
||||
* Another wiphy is on another channel, start the new
|
||||
* wiphy in paused state.
|
||||
*/
|
||||
aphy->state = ATH_WIPHY_PAUSED;
|
||||
ieee80211_stop_queues(hw);
|
||||
}
|
||||
mutex_unlock(&sc->mutex);
|
||||
return 0;
|
||||
}
|
||||
aphy->state = ATH_WIPHY_ACTIVE;
|
||||
|
||||
/* setup initial channel */
|
||||
|
||||
sc->chan_idx = curchan->hw_value;
|
||||
|
||||
init_channel = ath_get_curchannel(sc, hw);
|
||||
@ -1213,19 +1130,11 @@ mutex_unlock:
|
||||
static int ath9k_tx(struct ieee80211_hw *hw,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_tx_control txctl;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
|
||||
if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) {
|
||||
ath_dbg(common, ATH_DBG_XMIT,
|
||||
"ath9k: %s: TX in unexpected wiphy state %d\n",
|
||||
wiphy_name(hw->wiphy), aphy->state);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (sc->ps_enabled) {
|
||||
/*
|
||||
* mac80211 does not set PM field for normal data frames, so we
|
||||
@ -1284,44 +1193,26 @@ exit:
|
||||
|
||||
static void ath9k_stop(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
int i;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
aphy->state = ATH_WIPHY_INACTIVE;
|
||||
|
||||
if (led_blink)
|
||||
cancel_delayed_work_sync(&sc->ath_led_blink_work);
|
||||
|
||||
cancel_delayed_work_sync(&sc->tx_complete_work);
|
||||
cancel_delayed_work_sync(&sc->hw_pll_work);
|
||||
cancel_work_sync(&sc->paprd_work);
|
||||
cancel_work_sync(&sc->hw_check_work);
|
||||
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
if (sc->sec_wiphy[i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == sc->num_sec_wiphy) {
|
||||
cancel_delayed_work_sync(&sc->wiphy_work);
|
||||
cancel_work_sync(&sc->chan_work);
|
||||
}
|
||||
|
||||
if (sc->sc_flags & SC_OP_INVALID) {
|
||||
ath_dbg(common, ATH_DBG_ANY, "Device not present\n");
|
||||
mutex_unlock(&sc->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ath9k_wiphy_started(sc)) {
|
||||
mutex_unlock(&sc->mutex);
|
||||
return; /* another wiphy still in use */
|
||||
}
|
||||
|
||||
/* Ensure HW is awake when we try to shut it down. */
|
||||
ath9k_ps_wakeup(sc);
|
||||
|
||||
@ -1333,6 +1224,9 @@ static void ath9k_stop(struct ieee80211_hw *hw)
|
||||
|
||||
spin_lock_bh(&sc->sc_pcu_lock);
|
||||
|
||||
/* prevent tasklets to enable interrupts once we disable them */
|
||||
ah->imask &= ~ATH9K_INT_GLOBAL;
|
||||
|
||||
/* make sure h/w will not generate any interrupt
|
||||
* before setting the invalid flag. */
|
||||
ath9k_hw_disable_interrupts(ah);
|
||||
@ -1344,16 +1238,26 @@ static void ath9k_stop(struct ieee80211_hw *hw)
|
||||
} else
|
||||
sc->rx.rxlink = NULL;
|
||||
|
||||
if (sc->rx.frag) {
|
||||
dev_kfree_skb_any(sc->rx.frag);
|
||||
sc->rx.frag = NULL;
|
||||
}
|
||||
|
||||
/* disable HAL and put h/w to sleep */
|
||||
ath9k_hw_disable(ah);
|
||||
ath9k_hw_configpcipowersave(ah, 1, 1);
|
||||
|
||||
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||
|
||||
/* we can now sync irq and kill any running tasklets, since we already
|
||||
* disabled interrupts and not holding a spin lock */
|
||||
synchronize_irq(sc->irq);
|
||||
tasklet_kill(&sc->intr_tq);
|
||||
tasklet_kill(&sc->bcon_tasklet);
|
||||
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
sc->ps_idle = true;
|
||||
ath9k_set_wiphy_idle(aphy, true);
|
||||
ath_radio_disable(sc, hw);
|
||||
|
||||
sc->sc_flags |= SC_OP_INVALID;
|
||||
@ -1439,11 +1343,9 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ath9k_vif_iter_data *iter_data)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Use the hardware MAC address as reference, the hardware uses it
|
||||
@ -1457,24 +1359,15 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
|
||||
ath9k_vif_iter(iter_data, vif->addr, vif);
|
||||
|
||||
/* Get list of all active MAC addresses */
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter,
|
||||
iter_data);
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
if (sc->sec_wiphy[i] == NULL)
|
||||
continue;
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
sc->sec_wiphy[i]->hw, ath9k_vif_iter, iter_data);
|
||||
}
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
}
|
||||
|
||||
/* Called with sc->mutex held. */
|
||||
static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath9k_vif_iter_data iter_data;
|
||||
@ -1530,8 +1423,7 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
|
||||
static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
|
||||
ath9k_calculate_summary_state(hw, vif);
|
||||
|
||||
@ -1544,7 +1436,7 @@ static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
|
||||
* in the info_changed method and set up beacons properly
|
||||
* there.
|
||||
*/
|
||||
error = ath_beacon_alloc(aphy, vif);
|
||||
error = ath_beacon_alloc(sc, vif);
|
||||
if (error)
|
||||
ath9k_reclaim_beacon(sc, vif);
|
||||
else
|
||||
@ -1556,8 +1448,7 @@ static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
|
||||
static int ath9k_add_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
@ -1617,8 +1508,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
|
||||
enum nl80211_iftype new_type,
|
||||
bool p2p)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
int ret = 0;
|
||||
|
||||
@ -1660,8 +1550,7 @@ out:
|
||||
static void ath9k_remove_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
|
||||
ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n");
|
||||
@ -1715,12 +1604,11 @@ static void ath9k_disable_ps(struct ath_softc *sc)
|
||||
|
||||
static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ieee80211_conf *conf = &hw->conf;
|
||||
bool disable_radio;
|
||||
bool disable_radio = false;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
@ -1731,29 +1619,13 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
* the end.
|
||||
*/
|
||||
if (changed & IEEE80211_CONF_CHANGE_IDLE) {
|
||||
bool enable_radio;
|
||||
bool all_wiphys_idle;
|
||||
bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
|
||||
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
all_wiphys_idle = ath9k_all_wiphys_idle(sc);
|
||||
ath9k_set_wiphy_idle(aphy, idle);
|
||||
|
||||
enable_radio = (!idle && all_wiphys_idle);
|
||||
|
||||
/*
|
||||
* After we unlock here its possible another wiphy
|
||||
* can be re-renabled so to account for that we will
|
||||
* only disable the radio toward the end of this routine
|
||||
* if by then all wiphys are still idle.
|
||||
*/
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
|
||||
if (enable_radio) {
|
||||
sc->ps_idle = false;
|
||||
sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
|
||||
if (!sc->ps_idle) {
|
||||
ath_radio_enable(sc, hw);
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"not-idle: enabling radio\n");
|
||||
} else {
|
||||
disable_radio = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1794,29 +1666,16 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
if (ah->curchan)
|
||||
old_pos = ah->curchan - &ah->channels[0];
|
||||
|
||||
aphy->chan_idx = pos;
|
||||
aphy->chan_is_ht = conf_is_ht(conf);
|
||||
if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
|
||||
sc->sc_flags |= SC_OP_OFFCHANNEL;
|
||||
else
|
||||
sc->sc_flags &= ~SC_OP_OFFCHANNEL;
|
||||
|
||||
if (aphy->state == ATH_WIPHY_SCAN ||
|
||||
aphy->state == ATH_WIPHY_ACTIVE)
|
||||
ath9k_wiphy_pause_all_forced(sc, aphy);
|
||||
else {
|
||||
/*
|
||||
* Do not change operational channel based on a paused
|
||||
* wiphy changes.
|
||||
*/
|
||||
goto skip_chan_change;
|
||||
}
|
||||
|
||||
ath_dbg(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
|
||||
curchan->center_freq);
|
||||
|
||||
/* XXX: remove me eventualy */
|
||||
ath9k_update_ichannel(sc, hw, &sc->sc_ah->channels[pos]);
|
||||
ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
|
||||
curchan, conf->channel_type);
|
||||
|
||||
/* update survey stats for the old channel before switching */
|
||||
spin_lock_irqsave(&common->cc_lock, flags);
|
||||
@ -1858,7 +1717,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
ath_update_survey_nf(sc, old_pos);
|
||||
}
|
||||
|
||||
skip_chan_change:
|
||||
if (changed & IEEE80211_CONF_CHANGE_POWER) {
|
||||
sc->config.txpowlimit = 2 * conf->power_level;
|
||||
ath9k_ps_wakeup(sc);
|
||||
@ -1866,13 +1724,8 @@ skip_chan_change:
|
||||
ath9k_ps_restore(sc);
|
||||
}
|
||||
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
disable_radio = ath9k_all_wiphys_idle(sc);
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
|
||||
if (disable_radio) {
|
||||
ath_dbg(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
|
||||
sc->ps_idle = true;
|
||||
ath_radio_disable(sc, hw);
|
||||
}
|
||||
|
||||
@ -1897,8 +1750,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
|
||||
unsigned int *total_flags,
|
||||
u64 multicast)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
u32 rfilt;
|
||||
|
||||
changed_flags &= SUPPORTED_FILTERS;
|
||||
@ -1918,8 +1770,7 @@ static int ath9k_sta_add(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
|
||||
ath_node_attach(sc, sta);
|
||||
|
||||
@ -1930,8 +1781,7 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
|
||||
ath_node_detach(sc, sta);
|
||||
|
||||
@ -1941,8 +1791,7 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw,
|
||||
static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
||||
const struct ieee80211_tx_queue_params *params)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_txq *txq;
|
||||
struct ath9k_tx_queue_info qi;
|
||||
@ -1986,8 +1835,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
int ret = 0;
|
||||
|
||||
@ -2031,8 +1879,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
struct ieee80211_bss_conf *bss_conf,
|
||||
u32 changed)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
@ -2062,7 +1909,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
if ((changed & BSS_CHANGED_BEACON) ||
|
||||
((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) {
|
||||
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
|
||||
error = ath_beacon_alloc(aphy, vif);
|
||||
error = ath_beacon_alloc(sc, vif);
|
||||
if (!error)
|
||||
ath_beacon_config(sc, vif);
|
||||
}
|
||||
@ -2099,7 +1946,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
sc->sc_flags |= SC_OP_TSF_RESET;
|
||||
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
|
||||
error = ath_beacon_alloc(aphy, vif);
|
||||
error = ath_beacon_alloc(sc, vif);
|
||||
if (!error)
|
||||
ath_beacon_config(sc, vif);
|
||||
} else {
|
||||
@ -2137,9 +1984,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
|
||||
static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath_softc *sc = hw->priv;
|
||||
u64 tsf;
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
ath9k_ps_wakeup(sc);
|
||||
@ -2152,8 +1998,7 @@ static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
|
||||
|
||||
static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
ath9k_ps_wakeup(sc);
|
||||
@ -2164,8 +2009,7 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
|
||||
|
||||
static void ath9k_reset_tsf(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
@ -2182,8 +2026,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn, u8 buf_size)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
int ret = 0;
|
||||
|
||||
local_bh_disable();
|
||||
@ -2228,8 +2071,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
|
||||
static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
|
||||
struct survey_info *survey)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_channel *chan;
|
||||
@ -2263,47 +2105,9 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
if (ath9k_wiphy_scanning(sc)) {
|
||||
/*
|
||||
* There is a race here in mac80211 but fixing it requires
|
||||
* we revisit how we handle the scan complete callback.
|
||||
* After mac80211 fixes we will not have configured hardware
|
||||
* to the home channel nor would we have configured the RX
|
||||
* filter yet.
|
||||
*/
|
||||
mutex_unlock(&sc->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
aphy->state = ATH_WIPHY_SCAN;
|
||||
ath9k_wiphy_pause_all_forced(sc, aphy);
|
||||
mutex_unlock(&sc->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: this requires a revisit after the driver
|
||||
* scan_complete gets moved to another place/removed in mac80211.
|
||||
*/
|
||||
static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
aphy->state = ATH_WIPHY_ACTIVE;
|
||||
mutex_unlock(&sc->mutex);
|
||||
}
|
||||
|
||||
static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
@ -2331,8 +2135,6 @@ struct ieee80211_ops ath9k_ops = {
|
||||
.reset_tsf = ath9k_reset_tsf,
|
||||
.ampdu_action = ath9k_ampdu_action,
|
||||
.get_survey = ath9k_get_survey,
|
||||
.sw_scan_start = ath9k_sw_scan_start,
|
||||
.sw_scan_complete = ath9k_sw_scan_complete,
|
||||
.rfkill_poll = ath9k_rfkill_poll_state,
|
||||
.set_coverage_class = ath9k_set_coverage_class,
|
||||
};
|
||||
|
@ -126,7 +126,6 @@ static const struct ath_bus_ops ath_pci_bus_ops = {
|
||||
static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
void __iomem *mem;
|
||||
struct ath_wiphy *aphy;
|
||||
struct ath_softc *sc;
|
||||
struct ieee80211_hw *hw;
|
||||
u8 csz;
|
||||
@ -198,8 +197,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
goto err_iomap;
|
||||
}
|
||||
|
||||
hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) +
|
||||
sizeof(struct ath_softc), &ath9k_ops);
|
||||
hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
|
||||
if (!hw) {
|
||||
dev_err(&pdev->dev, "No memory for ieee80211_hw\n");
|
||||
ret = -ENOMEM;
|
||||
@ -209,11 +207,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
SET_IEEE80211_DEV(hw, &pdev->dev);
|
||||
pci_set_drvdata(pdev, hw);
|
||||
|
||||
aphy = hw->priv;
|
||||
sc = (struct ath_softc *) (aphy + 1);
|
||||
aphy->sc = sc;
|
||||
aphy->hw = hw;
|
||||
sc->pri_wiphy = aphy;
|
||||
sc = hw->priv;
|
||||
sc->hw = hw;
|
||||
sc->dev = &pdev->dev;
|
||||
sc->mem = mem;
|
||||
@ -260,8 +254,7 @@ err_dma:
|
||||
static void ath_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
void __iomem *mem = sc->mem;
|
||||
|
||||
if (!is_ath9k_unloaded)
|
||||
@ -281,8 +274,7 @@ static int ath_pci_suspend(struct device *device)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(device);
|
||||
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
|
||||
|
||||
@ -293,8 +285,7 @@ static int ath_pci_resume(struct device *device)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(device);
|
||||
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
@ -320,7 +311,6 @@ static int ath_pci_resume(struct device *device)
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
sc->ps_idle = true;
|
||||
ath9k_set_wiphy_idle(aphy, true);
|
||||
ath_radio_disable(sc, hw);
|
||||
|
||||
return 0;
|
||||
|
@ -1560,8 +1560,7 @@ static void ath_rate_add_sta_debugfs(void *priv, void *priv_sta,
|
||||
|
||||
static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
return aphy->sc;
|
||||
return hw->priv;
|
||||
}
|
||||
|
||||
static void ath_rate_free(void *priv)
|
||||
|
@ -34,27 +34,6 @@ static inline bool ath9k_check_auto_sleep(struct ath_softc *sc)
|
||||
(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP);
|
||||
}
|
||||
|
||||
static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc,
|
||||
struct ieee80211_hdr *hdr)
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->pri_wiphy->hw;
|
||||
int i;
|
||||
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
struct ath_wiphy *aphy = sc->sec_wiphy[i];
|
||||
if (aphy == NULL)
|
||||
continue;
|
||||
if (compare_ether_addr(hdr->addr1, aphy->hw->wiphy->perm_addr)
|
||||
== 0) {
|
||||
hw = aphy->hw;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
return hw;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup and link descriptors.
|
||||
*
|
||||
@ -230,11 +209,6 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs)
|
||||
int error = 0, i;
|
||||
u32 size;
|
||||
|
||||
|
||||
common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN +
|
||||
ah->caps.rx_status_len,
|
||||
min(common->cachelsz, (u16)64));
|
||||
|
||||
ath9k_hw_set_rx_bufsize(ah, common->rx_bufsize -
|
||||
ah->caps.rx_status_len);
|
||||
|
||||
@ -321,12 +295,12 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
|
||||
sc->sc_flags &= ~SC_OP_RXFLUSH;
|
||||
spin_lock_init(&sc->rx.rxbuflock);
|
||||
|
||||
common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
|
||||
sc->sc_ah->caps.rx_status_len;
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
|
||||
return ath_rx_edma_init(sc, nbufs);
|
||||
} else {
|
||||
common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
|
||||
min(common->cachelsz, (u16)64));
|
||||
|
||||
ath_dbg(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
|
||||
common->cachelsz, common->rx_bufsize);
|
||||
|
||||
@ -463,8 +437,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
|
||||
if (conf_is_ht(&sc->hw->conf))
|
||||
rfilt |= ATH9K_RX_FILTER_COMP_BAR;
|
||||
|
||||
if (sc->sec_wiphy || (sc->nvifs > 1) ||
|
||||
(sc->rx.rxfilter & FIF_OTHER_BSS)) {
|
||||
if (sc->nvifs > 1 || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
|
||||
/* The following may also be needed for other older chips */
|
||||
if (sc->sc_ah->hw_version.macVersion == AR_SREV_VERSION_9160)
|
||||
rfilt |= ATH9K_RX_FILTER_PROM;
|
||||
@ -668,37 +641,6 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
|
||||
}
|
||||
}
|
||||
|
||||
static void ath_rx_send_to_mac80211(struct ieee80211_hw *hw,
|
||||
struct ath_softc *sc, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
/* Send the frame to mac80211 */
|
||||
if (is_multicast_ether_addr(hdr->addr1)) {
|
||||
int i;
|
||||
/*
|
||||
* Deliver broadcast/multicast frames to all suitable
|
||||
* virtual wiphys.
|
||||
*/
|
||||
/* TODO: filter based on channel configuration */
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
struct ath_wiphy *aphy = sc->sec_wiphy[i];
|
||||
struct sk_buff *nskb;
|
||||
if (aphy == NULL)
|
||||
continue;
|
||||
nskb = skb_copy(skb, GFP_ATOMIC);
|
||||
if (!nskb)
|
||||
continue;
|
||||
ieee80211_rx(aphy->hw, nskb);
|
||||
}
|
||||
ieee80211_rx(sc->hw, skb);
|
||||
} else
|
||||
/* Deliver unicast frames based on receiver address */
|
||||
ieee80211_rx(hw, skb);
|
||||
}
|
||||
|
||||
static bool ath_edma_get_buffers(struct ath_softc *sc,
|
||||
enum ath9k_rx_qtype qtype)
|
||||
{
|
||||
@ -868,15 +810,9 @@ static bool ath9k_rx_accept(struct ath_common *common,
|
||||
if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* rs_more indicates chained descriptors which can be used
|
||||
* to link buffers together for a sort of scatter-gather
|
||||
* operation.
|
||||
* reject the frame, we don't support scatter-gather yet and
|
||||
* the frame is probably corrupt anyway
|
||||
*/
|
||||
/* Only use error bits from the last fragment */
|
||||
if (rx_stats->rs_more)
|
||||
return false;
|
||||
return true;
|
||||
|
||||
/*
|
||||
* The rx_stats->rs_status will not be set until the end of the
|
||||
@ -980,7 +916,7 @@ static void ath9k_process_rssi(struct ath_common *common,
|
||||
struct ieee80211_hdr *hdr,
|
||||
struct ath_rx_status *rx_stats)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_hw *ah = common->ah;
|
||||
int last_rssi;
|
||||
__le16 fc;
|
||||
@ -1000,9 +936,9 @@ static void ath9k_process_rssi(struct ath_common *common,
|
||||
}
|
||||
|
||||
if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && !rx_stats->rs_moreaggr)
|
||||
ATH_RSSI_LPF(aphy->last_rssi, rx_stats->rs_rssi);
|
||||
ATH_RSSI_LPF(sc->last_rssi, rx_stats->rs_rssi);
|
||||
|
||||
last_rssi = aphy->last_rssi;
|
||||
last_rssi = sc->last_rssi;
|
||||
if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
|
||||
rx_stats->rs_rssi = ATH_EP_RND(last_rssi,
|
||||
ATH_RSSI_EP_MULTIPLIER);
|
||||
@ -1034,6 +970,10 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,
|
||||
if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error))
|
||||
return -EINVAL;
|
||||
|
||||
/* Only use status info from the last fragment */
|
||||
if (rx_stats->rs_more)
|
||||
return 0;
|
||||
|
||||
ath9k_process_rssi(common, hw, hdr, rx_stats);
|
||||
|
||||
if (ath9k_process_rate(common, hw, rx_stats, rx_status))
|
||||
@ -1635,7 +1575,7 @@ div_comb_done:
|
||||
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
||||
{
|
||||
struct ath_buf *bf;
|
||||
struct sk_buff *skb = NULL, *requeue_skb;
|
||||
struct sk_buff *skb = NULL, *requeue_skb, *hdr_skb;
|
||||
struct ieee80211_rx_status *rxs;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
@ -1644,7 +1584,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
||||
* virtual wiphy so to account for that we iterate over the active
|
||||
* wiphys and find the appropriate wiphy and therefore hw.
|
||||
*/
|
||||
struct ieee80211_hw *hw = NULL;
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ieee80211_hdr *hdr;
|
||||
int retval;
|
||||
bool decrypt_error = false;
|
||||
@ -1686,10 +1626,17 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
||||
if (!skb)
|
||||
continue;
|
||||
|
||||
hdr = (struct ieee80211_hdr *) (skb->data + rx_status_len);
|
||||
rxs = IEEE80211_SKB_RXCB(skb);
|
||||
/*
|
||||
* Take frame header from the first fragment and RX status from
|
||||
* the last one.
|
||||
*/
|
||||
if (sc->rx.frag)
|
||||
hdr_skb = sc->rx.frag;
|
||||
else
|
||||
hdr_skb = skb;
|
||||
|
||||
hw = ath_get_virt_hw(sc, hdr);
|
||||
hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len);
|
||||
rxs = IEEE80211_SKB_RXCB(hdr_skb);
|
||||
|
||||
ath_debug_stat_rx(sc, &rs);
|
||||
|
||||
@ -1698,12 +1645,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
||||
* chain it back at the queue without processing it.
|
||||
*/
|
||||
if (flush)
|
||||
goto requeue;
|
||||
goto requeue_drop_frag;
|
||||
|
||||
retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
|
||||
rxs, &decrypt_error);
|
||||
if (retval)
|
||||
goto requeue;
|
||||
goto requeue_drop_frag;
|
||||
|
||||
rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp;
|
||||
if (rs.rs_tstamp > tsf_lower &&
|
||||
@ -1723,7 +1670,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
||||
* skb and put it at the tail of the sc->rx.rxbuf list for
|
||||
* processing. */
|
||||
if (!requeue_skb)
|
||||
goto requeue;
|
||||
goto requeue_drop_frag;
|
||||
|
||||
/* Unmap the frame */
|
||||
dma_unmap_single(sc->dev, bf->bf_buf_addr,
|
||||
@ -1734,8 +1681,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
||||
if (ah->caps.rx_status_len)
|
||||
skb_pull(skb, ah->caps.rx_status_len);
|
||||
|
||||
ath9k_rx_skb_postprocess(common, skb, &rs,
|
||||
rxs, decrypt_error);
|
||||
if (!rs.rs_more)
|
||||
ath9k_rx_skb_postprocess(common, hdr_skb, &rs,
|
||||
rxs, decrypt_error);
|
||||
|
||||
/* We will now give hardware our shiny new allocated skb */
|
||||
bf->bf_mpdu = requeue_skb;
|
||||
@ -1748,10 +1696,42 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
||||
bf->bf_mpdu = NULL;
|
||||
bf->bf_buf_addr = 0;
|
||||
ath_err(common, "dma_mapping_error() on RX\n");
|
||||
ath_rx_send_to_mac80211(hw, sc, skb);
|
||||
ieee80211_rx(hw, skb);
|
||||
break;
|
||||
}
|
||||
|
||||
if (rs.rs_more) {
|
||||
/*
|
||||
* rs_more indicates chained descriptors which can be
|
||||
* used to link buffers together for a sort of
|
||||
* scatter-gather operation.
|
||||
*/
|
||||
if (sc->rx.frag) {
|
||||
/* too many fragments - cannot handle frame */
|
||||
dev_kfree_skb_any(sc->rx.frag);
|
||||
dev_kfree_skb_any(skb);
|
||||
skb = NULL;
|
||||
}
|
||||
sc->rx.frag = skb;
|
||||
goto requeue;
|
||||
}
|
||||
|
||||
if (sc->rx.frag) {
|
||||
int space = skb->len - skb_tailroom(hdr_skb);
|
||||
|
||||
sc->rx.frag = NULL;
|
||||
|
||||
if (pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) {
|
||||
dev_kfree_skb(skb);
|
||||
goto requeue_drop_frag;
|
||||
}
|
||||
|
||||
skb_copy_from_linear_data(skb, skb_put(hdr_skb, skb->len),
|
||||
skb->len);
|
||||
dev_kfree_skb_any(skb);
|
||||
skb = hdr_skb;
|
||||
}
|
||||
|
||||
/*
|
||||
* change the default rx antenna if rx diversity chooses the
|
||||
* other antenna 3 times in a row.
|
||||
@ -1775,8 +1755,13 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
|
||||
ath_ant_comb_scan(sc, &rs);
|
||||
|
||||
ath_rx_send_to_mac80211(hw, sc, skb);
|
||||
ieee80211_rx(hw, skb);
|
||||
|
||||
requeue_drop_frag:
|
||||
if (sc->rx.frag) {
|
||||
dev_kfree_skb_any(sc->rx.frag);
|
||||
sc->rx.frag = NULL;
|
||||
}
|
||||
requeue:
|
||||
if (edma) {
|
||||
list_add_tail(&bf->list, &sc->rx.rxbuf);
|
||||
|
@ -1083,6 +1083,17 @@ enum {
|
||||
#define AR_ENT_OTP 0x40d8
|
||||
#define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000
|
||||
#define AR_ENT_OTP_MPSD 0x00800000
|
||||
#define AR_CH0_BB_DPLL2 0x16184
|
||||
#define AR_CH0_BB_DPLL3 0x16188
|
||||
#define AR_CH0_DDR_DPLL2 0x16244
|
||||
#define AR_CH0_DDR_DPLL3 0x16248
|
||||
#define AR_CH0_DPLL2_KD 0x03F80000
|
||||
#define AR_CH0_DPLL2_KD_S 19
|
||||
#define AR_CH0_DPLL2_KI 0x3C000000
|
||||
#define AR_CH0_DPLL2_KI_S 26
|
||||
#define AR_CH0_DPLL3_PHASE_SHIFT 0x3F800000
|
||||
#define AR_CH0_DPLL3_PHASE_SHIFT_S 23
|
||||
#define AR_PHY_CCA_NOM_VAL_2GHZ -118
|
||||
|
||||
#define AR_RTC_9300_PLL_DIV 0x000003ff
|
||||
#define AR_RTC_9300_PLL_DIV_S 0
|
||||
@ -1129,6 +1140,12 @@ enum {
|
||||
#define AR_RTC_PLL_CLKSEL 0x00000300
|
||||
#define AR_RTC_PLL_CLKSEL_S 8
|
||||
|
||||
#define PLL3 0x16188
|
||||
#define PLL3_DO_MEAS_MASK 0x40000000
|
||||
#define PLL4 0x1618c
|
||||
#define PLL4_MEAS_DONE 0x8
|
||||
#define SQSUM_DVC_MASK 0x007ffff8
|
||||
|
||||
#define AR_RTC_RESET \
|
||||
((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0040) : 0x7040)
|
||||
#define AR_RTC_RESET_EN (0x00000001)
|
||||
|
@ -1,669 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2009 Atheros Communications Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "ath9k.h"
|
||||
|
||||
int ath9k_wiphy_add(struct ath_softc *sc)
|
||||
{
|
||||
int i, error;
|
||||
struct ath_wiphy *aphy;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ieee80211_hw *hw;
|
||||
u8 addr[ETH_ALEN];
|
||||
|
||||
hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy), &ath9k_ops);
|
||||
if (hw == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
if (sc->sec_wiphy[i] == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == sc->num_sec_wiphy) {
|
||||
/* No empty slot available; increase array length */
|
||||
struct ath_wiphy **n;
|
||||
n = krealloc(sc->sec_wiphy,
|
||||
(sc->num_sec_wiphy + 1) *
|
||||
sizeof(struct ath_wiphy *),
|
||||
GFP_ATOMIC);
|
||||
if (n == NULL) {
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
ieee80211_free_hw(hw);
|
||||
return -ENOMEM;
|
||||
}
|
||||
n[i] = NULL;
|
||||
sc->sec_wiphy = n;
|
||||
sc->num_sec_wiphy++;
|
||||
}
|
||||
|
||||
SET_IEEE80211_DEV(hw, sc->dev);
|
||||
|
||||
aphy = hw->priv;
|
||||
aphy->sc = sc;
|
||||
aphy->hw = hw;
|
||||
sc->sec_wiphy[i] = aphy;
|
||||
aphy->last_rssi = ATH_RSSI_DUMMY_MARKER;
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
|
||||
memcpy(addr, common->macaddr, ETH_ALEN);
|
||||
addr[0] |= 0x02; /* Locally managed address */
|
||||
/*
|
||||
* XOR virtual wiphy index into the least significant bits to generate
|
||||
* a different MAC address for each virtual wiphy.
|
||||
*/
|
||||
addr[5] ^= i & 0xff;
|
||||
addr[4] ^= (i & 0xff00) >> 8;
|
||||
addr[3] ^= (i & 0xff0000) >> 16;
|
||||
|
||||
SET_IEEE80211_PERM_ADDR(hw, addr);
|
||||
|
||||
ath9k_set_hw_capab(sc, hw);
|
||||
|
||||
error = ieee80211_register_hw(hw);
|
||||
|
||||
if (error == 0) {
|
||||
/* Make sure wiphy scheduler is started (if enabled) */
|
||||
ath9k_wiphy_set_scheduler(sc, sc->wiphy_scheduler_int);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int ath9k_wiphy_del(struct ath_wiphy *aphy)
|
||||
{
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
int i;
|
||||
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
if (aphy == sc->sec_wiphy[i]) {
|
||||
sc->sec_wiphy[i] = NULL;
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
ieee80211_unregister_hw(aphy->hw);
|
||||
ieee80211_free_hw(aphy->hw);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int ath9k_send_nullfunc(struct ath_wiphy *aphy,
|
||||
struct ieee80211_vif *vif, const u8 *bssid,
|
||||
int ps)
|
||||
{
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_tx_control txctl;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_hdr *hdr;
|
||||
__le16 fc;
|
||||
struct ieee80211_tx_info *info;
|
||||
|
||||
skb = dev_alloc_skb(24);
|
||||
if (skb == NULL)
|
||||
return -ENOMEM;
|
||||
hdr = (struct ieee80211_hdr *) skb_put(skb, 24);
|
||||
memset(hdr, 0, 24);
|
||||
fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
|
||||
IEEE80211_FCTL_TODS);
|
||||
if (ps)
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_PM);
|
||||
hdr->frame_control = fc;
|
||||
memcpy(hdr->addr1, bssid, ETH_ALEN);
|
||||
memcpy(hdr->addr2, aphy->hw->wiphy->perm_addr, ETH_ALEN);
|
||||
memcpy(hdr->addr3, bssid, ETH_ALEN);
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
info->control.vif = vif;
|
||||
info->control.rates[0].idx = 0;
|
||||
info->control.rates[0].count = 4;
|
||||
info->control.rates[1].idx = -1;
|
||||
|
||||
memset(&txctl, 0, sizeof(struct ath_tx_control));
|
||||
txctl.txq = sc->tx.txq_map[WME_AC_VO];
|
||||
txctl.frame_type = ps ? ATH9K_IFT_PAUSE : ATH9K_IFT_UNPAUSE;
|
||||
|
||||
if (ath_tx_start(aphy->hw, skb, &txctl) != 0)
|
||||
goto exit;
|
||||
|
||||
return 0;
|
||||
exit:
|
||||
dev_kfree_skb_any(skb);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool __ath9k_wiphy_pausing(struct ath_softc *sc)
|
||||
{
|
||||
int i;
|
||||
if (sc->pri_wiphy->state == ATH_WIPHY_PAUSING)
|
||||
return true;
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
if (sc->sec_wiphy[i] &&
|
||||
sc->sec_wiphy[i]->state == ATH_WIPHY_PAUSING)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ath9k_wiphy_pausing(struct ath_softc *sc)
|
||||
{
|
||||
bool ret;
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
ret = __ath9k_wiphy_pausing(sc);
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool __ath9k_wiphy_scanning(struct ath_softc *sc)
|
||||
{
|
||||
int i;
|
||||
if (sc->pri_wiphy->state == ATH_WIPHY_SCAN)
|
||||
return true;
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
if (sc->sec_wiphy[i] &&
|
||||
sc->sec_wiphy[i]->state == ATH_WIPHY_SCAN)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ath9k_wiphy_scanning(struct ath_softc *sc)
|
||||
{
|
||||
bool ret;
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
ret = __ath9k_wiphy_scanning(sc);
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy);
|
||||
|
||||
/* caller must hold wiphy_lock */
|
||||
static void __ath9k_wiphy_unpause_ch(struct ath_wiphy *aphy)
|
||||
{
|
||||
if (aphy == NULL)
|
||||
return;
|
||||
if (aphy->chan_idx != aphy->sc->chan_idx)
|
||||
return; /* wiphy not on the selected channel */
|
||||
__ath9k_wiphy_unpause(aphy);
|
||||
}
|
||||
|
||||
static void ath9k_wiphy_unpause_channel(struct ath_softc *sc)
|
||||
{
|
||||
int i;
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
__ath9k_wiphy_unpause_ch(sc->pri_wiphy);
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++)
|
||||
__ath9k_wiphy_unpause_ch(sc->sec_wiphy[i]);
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
}
|
||||
|
||||
void ath9k_wiphy_chan_work(struct work_struct *work)
|
||||
{
|
||||
struct ath_softc *sc = container_of(work, struct ath_softc, chan_work);
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_wiphy *aphy = sc->next_wiphy;
|
||||
|
||||
if (aphy == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* All pending interfaces paused; ready to change
|
||||
* channels.
|
||||
*/
|
||||
|
||||
/* Change channels */
|
||||
mutex_lock(&sc->mutex);
|
||||
/* XXX: remove me eventually */
|
||||
ath9k_update_ichannel(sc, aphy->hw,
|
||||
&sc->sc_ah->channels[sc->chan_idx]);
|
||||
|
||||
/* sync hw configuration for hw code */
|
||||
common->hw = aphy->hw;
|
||||
|
||||
if (ath_set_channel(sc, aphy->hw,
|
||||
&sc->sc_ah->channels[sc->chan_idx]) < 0) {
|
||||
printk(KERN_DEBUG "ath9k: Failed to set channel for new "
|
||||
"virtual wiphy\n");
|
||||
mutex_unlock(&sc->mutex);
|
||||
return;
|
||||
}
|
||||
mutex_unlock(&sc->mutex);
|
||||
|
||||
ath9k_wiphy_unpause_channel(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
* ath9k version of ieee80211_tx_status() for TX frames that are generated
|
||||
* internally in the driver.
|
||||
*/
|
||||
void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, int ftype)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
if (ftype == ATH9K_IFT_PAUSE && aphy->state == ATH_WIPHY_PAUSING) {
|
||||
if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) {
|
||||
printk(KERN_DEBUG "ath9k: %s: no ACK for pause "
|
||||
"frame\n", wiphy_name(hw->wiphy));
|
||||
/*
|
||||
* The AP did not reply; ignore this to allow us to
|
||||
* continue.
|
||||
*/
|
||||
}
|
||||
aphy->state = ATH_WIPHY_PAUSED;
|
||||
if (!ath9k_wiphy_pausing(aphy->sc)) {
|
||||
/*
|
||||
* Drop from tasklet to work to allow mutex for channel
|
||||
* change.
|
||||
*/
|
||||
ieee80211_queue_work(aphy->sc->hw,
|
||||
&aphy->sc->chan_work);
|
||||
}
|
||||
}
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
static void ath9k_mark_paused(struct ath_wiphy *aphy)
|
||||
{
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
aphy->state = ATH_WIPHY_PAUSED;
|
||||
if (!__ath9k_wiphy_pausing(sc))
|
||||
ieee80211_queue_work(sc->hw, &sc->chan_work);
|
||||
}
|
||||
|
||||
static void ath9k_pause_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_wiphy *aphy = data;
|
||||
struct ath_vif *avp = (void *) vif->drv_priv;
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (!vif->bss_conf.assoc) {
|
||||
ath9k_mark_paused(aphy);
|
||||
break;
|
||||
}
|
||||
/* TODO: could avoid this if already in PS mode */
|
||||
if (ath9k_send_nullfunc(aphy, vif, avp->bssid, 1)) {
|
||||
printk(KERN_DEBUG "%s: failed to send PS nullfunc\n",
|
||||
__func__);
|
||||
ath9k_mark_paused(aphy);
|
||||
}
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
/* Beacon transmission is paused by aphy->state change */
|
||||
ath9k_mark_paused(aphy);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* caller must hold wiphy_lock */
|
||||
static int __ath9k_wiphy_pause(struct ath_wiphy *aphy)
|
||||
{
|
||||
ieee80211_stop_queues(aphy->hw);
|
||||
aphy->state = ATH_WIPHY_PAUSING;
|
||||
/*
|
||||
* TODO: handle PAUSING->PAUSED for the case where there are multiple
|
||||
* active vifs (now we do it on the first vif getting ready; should be
|
||||
* on the last)
|
||||
*/
|
||||
ieee80211_iterate_active_interfaces_atomic(aphy->hw, ath9k_pause_iter,
|
||||
aphy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath9k_wiphy_pause(struct ath_wiphy *aphy)
|
||||
{
|
||||
int ret;
|
||||
spin_lock_bh(&aphy->sc->wiphy_lock);
|
||||
ret = __ath9k_wiphy_pause(aphy);
|
||||
spin_unlock_bh(&aphy->sc->wiphy_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath9k_unpause_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_wiphy *aphy = data;
|
||||
struct ath_vif *avp = (void *) vif->drv_priv;
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (!vif->bss_conf.assoc)
|
||||
break;
|
||||
ath9k_send_nullfunc(aphy, vif, avp->bssid, 0);
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
/* Beacon transmission is re-enabled by aphy->state change */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* caller must hold wiphy_lock */
|
||||
static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy)
|
||||
{
|
||||
ieee80211_iterate_active_interfaces_atomic(aphy->hw,
|
||||
ath9k_unpause_iter, aphy);
|
||||
aphy->state = ATH_WIPHY_ACTIVE;
|
||||
ieee80211_wake_queues(aphy->hw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath9k_wiphy_unpause(struct ath_wiphy *aphy)
|
||||
{
|
||||
int ret;
|
||||
spin_lock_bh(&aphy->sc->wiphy_lock);
|
||||
ret = __ath9k_wiphy_unpause(aphy);
|
||||
spin_unlock_bh(&aphy->sc->wiphy_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __ath9k_wiphy_mark_all_paused(struct ath_softc *sc)
|
||||
{
|
||||
int i;
|
||||
if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE)
|
||||
sc->pri_wiphy->state = ATH_WIPHY_PAUSED;
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
if (sc->sec_wiphy[i] &&
|
||||
sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE)
|
||||
sc->sec_wiphy[i]->state = ATH_WIPHY_PAUSED;
|
||||
}
|
||||
}
|
||||
|
||||
/* caller must hold wiphy_lock */
|
||||
static void __ath9k_wiphy_pause_all(struct ath_softc *sc)
|
||||
{
|
||||
int i;
|
||||
if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE)
|
||||
__ath9k_wiphy_pause(sc->pri_wiphy);
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
if (sc->sec_wiphy[i] &&
|
||||
sc->sec_wiphy[i]->state == ATH_WIPHY_ACTIVE)
|
||||
__ath9k_wiphy_pause(sc->sec_wiphy[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int ath9k_wiphy_select(struct ath_wiphy *aphy)
|
||||
{
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
bool now;
|
||||
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
if (__ath9k_wiphy_scanning(sc)) {
|
||||
/*
|
||||
* For now, we are using mac80211 sw scan and it expects to
|
||||
* have full control over channel changes, so avoid wiphy
|
||||
* scheduling during a scan. This could be optimized if the
|
||||
* scanning control were moved into the driver.
|
||||
*/
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
if (__ath9k_wiphy_pausing(sc)) {
|
||||
if (sc->wiphy_select_failures == 0)
|
||||
sc->wiphy_select_first_fail = jiffies;
|
||||
sc->wiphy_select_failures++;
|
||||
if (time_after(jiffies, sc->wiphy_select_first_fail + HZ / 2))
|
||||
{
|
||||
printk(KERN_DEBUG "ath9k: Previous wiphy select timed "
|
||||
"out; disable/enable hw to recover\n");
|
||||
__ath9k_wiphy_mark_all_paused(sc);
|
||||
/*
|
||||
* TODO: this workaround to fix hardware is unlikely to
|
||||
* be specific to virtual wiphy changes. It can happen
|
||||
* on normal channel change, too, and as such, this
|
||||
* should really be made more generic. For example,
|
||||
* tricker radio disable/enable on GTT interrupt burst
|
||||
* (say, 10 GTT interrupts received without any TX
|
||||
* frame being completed)
|
||||
*/
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
ath_radio_disable(sc, aphy->hw);
|
||||
ath_radio_enable(sc, aphy->hw);
|
||||
/* Only the primary wiphy hw is used for queuing work */
|
||||
ieee80211_queue_work(aphy->sc->hw,
|
||||
&aphy->sc->chan_work);
|
||||
return -EBUSY; /* previous select still in progress */
|
||||
}
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
return -EBUSY; /* previous select still in progress */
|
||||
}
|
||||
sc->wiphy_select_failures = 0;
|
||||
|
||||
/* Store the new channel */
|
||||
sc->chan_idx = aphy->chan_idx;
|
||||
sc->chan_is_ht = aphy->chan_is_ht;
|
||||
sc->next_wiphy = aphy;
|
||||
|
||||
__ath9k_wiphy_pause_all(sc);
|
||||
now = !__ath9k_wiphy_pausing(aphy->sc);
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
|
||||
if (now) {
|
||||
/* Ready to request channel change immediately */
|
||||
ieee80211_queue_work(aphy->sc->hw, &aphy->sc->chan_work);
|
||||
}
|
||||
|
||||
/*
|
||||
* wiphys will be unpaused in ath9k_tx_status() once channel has been
|
||||
* changed if any wiphy needs time to become paused.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ath9k_wiphy_started(struct ath_softc *sc)
|
||||
{
|
||||
int i;
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) {
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
return true;
|
||||
}
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
if (sc->sec_wiphy[i] &&
|
||||
sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE) {
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ath9k_wiphy_pause_chan(struct ath_wiphy *aphy,
|
||||
struct ath_wiphy *selected)
|
||||
{
|
||||
if (selected->state == ATH_WIPHY_SCAN) {
|
||||
if (aphy == selected)
|
||||
return;
|
||||
/*
|
||||
* Pause all other wiphys for the duration of the scan even if
|
||||
* they are on the current channel now.
|
||||
*/
|
||||
} else if (aphy->chan_idx == selected->chan_idx)
|
||||
return;
|
||||
aphy->state = ATH_WIPHY_PAUSED;
|
||||
ieee80211_stop_queues(aphy->hw);
|
||||
}
|
||||
|
||||
void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
|
||||
struct ath_wiphy *selected)
|
||||
{
|
||||
int i;
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE)
|
||||
ath9k_wiphy_pause_chan(sc->pri_wiphy, selected);
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
if (sc->sec_wiphy[i] &&
|
||||
sc->sec_wiphy[i]->state == ATH_WIPHY_ACTIVE)
|
||||
ath9k_wiphy_pause_chan(sc->sec_wiphy[i], selected);
|
||||
}
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
}
|
||||
|
||||
void ath9k_wiphy_work(struct work_struct *work)
|
||||
{
|
||||
struct ath_softc *sc = container_of(work, struct ath_softc,
|
||||
wiphy_work.work);
|
||||
struct ath_wiphy *aphy = NULL;
|
||||
bool first = true;
|
||||
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
|
||||
if (sc->wiphy_scheduler_int == 0) {
|
||||
/* wiphy scheduler is disabled */
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
try_again:
|
||||
sc->wiphy_scheduler_index++;
|
||||
while (sc->wiphy_scheduler_index <= sc->num_sec_wiphy) {
|
||||
aphy = sc->sec_wiphy[sc->wiphy_scheduler_index - 1];
|
||||
if (aphy && aphy->state != ATH_WIPHY_INACTIVE)
|
||||
break;
|
||||
|
||||
sc->wiphy_scheduler_index++;
|
||||
aphy = NULL;
|
||||
}
|
||||
if (aphy == NULL) {
|
||||
sc->wiphy_scheduler_index = 0;
|
||||
if (sc->pri_wiphy->state == ATH_WIPHY_INACTIVE) {
|
||||
if (first) {
|
||||
first = false;
|
||||
goto try_again;
|
||||
}
|
||||
/* No wiphy is ready to be scheduled */
|
||||
} else
|
||||
aphy = sc->pri_wiphy;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
|
||||
if (aphy &&
|
||||
aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN &&
|
||||
ath9k_wiphy_select(aphy)) {
|
||||
printk(KERN_DEBUG "ath9k: Failed to schedule virtual wiphy "
|
||||
"change\n");
|
||||
}
|
||||
|
||||
ieee80211_queue_delayed_work(sc->hw,
|
||||
&sc->wiphy_work,
|
||||
sc->wiphy_scheduler_int);
|
||||
}
|
||||
|
||||
void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
|
||||
{
|
||||
cancel_delayed_work_sync(&sc->wiphy_work);
|
||||
sc->wiphy_scheduler_int = msecs_to_jiffies(msec_int);
|
||||
if (sc->wiphy_scheduler_int)
|
||||
ieee80211_queue_delayed_work(sc->hw, &sc->wiphy_work,
|
||||
sc->wiphy_scheduler_int);
|
||||
}
|
||||
|
||||
/* caller must hold wiphy_lock */
|
||||
bool ath9k_all_wiphys_idle(struct ath_softc *sc)
|
||||
{
|
||||
unsigned int i;
|
||||
if (!sc->pri_wiphy->idle)
|
||||
return false;
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
struct ath_wiphy *aphy = sc->sec_wiphy[i];
|
||||
if (!aphy)
|
||||
continue;
|
||||
if (!aphy->idle)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* caller must hold wiphy_lock */
|
||||
void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle)
|
||||
{
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
|
||||
aphy->idle = idle;
|
||||
ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
|
||||
"Marking %s as %sidle\n",
|
||||
wiphy_name(aphy->hw->wiphy), idle ? "" : "not-");
|
||||
}
|
||||
/* Only bother starting a queue on an active virtual wiphy */
|
||||
bool ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue)
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->pri_wiphy->hw;
|
||||
unsigned int i;
|
||||
bool txq_started = false;
|
||||
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
|
||||
/* Start the primary wiphy */
|
||||
if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) {
|
||||
ieee80211_wake_queue(hw, skb_queue);
|
||||
txq_started = true;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* Now start the secondary wiphy queues */
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
struct ath_wiphy *aphy = sc->sec_wiphy[i];
|
||||
if (!aphy)
|
||||
continue;
|
||||
if (aphy->state != ATH_WIPHY_ACTIVE)
|
||||
continue;
|
||||
|
||||
hw = aphy->hw;
|
||||
ieee80211_wake_queue(hw, skb_queue);
|
||||
txq_started = true;
|
||||
break;
|
||||
}
|
||||
|
||||
unlock:
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
return txq_started;
|
||||
}
|
||||
|
||||
/* Go ahead and propagate information to all virtual wiphys, it won't hurt */
|
||||
void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue)
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->pri_wiphy->hw;
|
||||
unsigned int i;
|
||||
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
|
||||
/* Stop the primary wiphy */
|
||||
ieee80211_stop_queue(hw, skb_queue);
|
||||
|
||||
/* Now stop the secondary wiphy queues */
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
struct ath_wiphy *aphy = sc->sec_wiphy[i];
|
||||
if (!aphy)
|
||||
continue;
|
||||
hw = aphy->hw;
|
||||
ieee80211_stop_queue(hw, skb_queue);
|
||||
}
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
}
|
@ -55,8 +55,9 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
|
||||
static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
|
||||
struct list_head *head);
|
||||
static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
|
||||
static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
|
||||
int nframes, int nbad, int txok, bool update_rc);
|
||||
static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
|
||||
struct ath_tx_status *ts, int nframes, int nbad,
|
||||
int txok, bool update_rc);
|
||||
static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
|
||||
int seqno);
|
||||
|
||||
@ -295,7 +296,6 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
|
||||
|
||||
ATH_TXBUF_RESET(tbf);
|
||||
|
||||
tbf->aphy = bf->aphy;
|
||||
tbf->bf_mpdu = bf->bf_mpdu;
|
||||
tbf->bf_buf_addr = bf->bf_buf_addr;
|
||||
memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
|
||||
@ -343,7 +343,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||||
struct ath_node *an = NULL;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ieee80211_hw *hw;
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ieee80211_tx_info *tx_info;
|
||||
struct ath_atx_tid *tid = NULL;
|
||||
@ -362,7 +362,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
tx_info = IEEE80211_SKB_CB(skb);
|
||||
hw = bf->aphy->hw;
|
||||
|
||||
memcpy(rates, tx_info->control.rates, sizeof(rates));
|
||||
|
||||
@ -381,7 +380,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||||
!bf->bf_stale || bf_next != NULL)
|
||||
list_move_tail(&bf->list, &bf_head);
|
||||
|
||||
ath_tx_rc_status(bf, ts, 1, 1, 0, false);
|
||||
ath_tx_rc_status(sc, bf, ts, 1, 1, 0, false);
|
||||
ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
|
||||
0, 0);
|
||||
|
||||
@ -487,10 +486,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||||
|
||||
if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
|
||||
memcpy(tx_info->control.rates, rates, sizeof(rates));
|
||||
ath_tx_rc_status(bf, ts, nframes, nbad, txok, true);
|
||||
ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok, true);
|
||||
rc_update = false;
|
||||
} else {
|
||||
ath_tx_rc_status(bf, ts, nframes, nbad, txok, false);
|
||||
ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok, false);
|
||||
}
|
||||
|
||||
ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
|
||||
@ -514,7 +513,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||||
|
||||
bf->bf_state.bf_type |=
|
||||
BUF_XRETRY;
|
||||
ath_tx_rc_status(bf, ts, nframes,
|
||||
ath_tx_rc_status(sc, bf, ts, nframes,
|
||||
nbad, 0, false);
|
||||
ath_tx_complete_buf(sc, bf, txq,
|
||||
&bf_head,
|
||||
@ -564,8 +563,11 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (needreset)
|
||||
if (needreset) {
|
||||
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||
ath_reset(sc, false);
|
||||
spin_lock_bh(&sc->sc_pcu_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
|
||||
@ -1207,8 +1209,17 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
|
||||
ath_err(common, "Failed to stop TX DMA!\n");
|
||||
|
||||
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
|
||||
if (ATH_TXQ_SETUP(sc, i))
|
||||
ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
|
||||
if (!ATH_TXQ_SETUP(sc, i))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* The caller will resume queues with ieee80211_wake_queues.
|
||||
* Mark the queue as not stopped to prevent ath_tx_complete
|
||||
* from waking the queue too early.
|
||||
*/
|
||||
txq = &sc->tx.txq[i];
|
||||
txq->stopped = false;
|
||||
ath_draintxq(sc, txq, retry_tx);
|
||||
}
|
||||
|
||||
return !npend;
|
||||
@ -1435,8 +1446,7 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
|
||||
static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
|
||||
int framelen)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_sta *sta = tx_info->control.sta;
|
||||
struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
|
||||
@ -1654,8 +1664,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
|
||||
struct ath_txq *txq,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_frame_info *fi = get_frame_info(skb);
|
||||
@ -1671,7 +1680,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
|
||||
|
||||
ATH_TXBUF_RESET(bf);
|
||||
|
||||
bf->aphy = aphy;
|
||||
bf->bf_flags = setup_tx_flags(skb);
|
||||
bf->bf_mpdu = skb;
|
||||
|
||||
@ -1757,8 +1765,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_sta *sta = info->control.sta;
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_txq *txq = txctl->txq;
|
||||
struct ath_buf *bf;
|
||||
int padpos, padsize;
|
||||
@ -1810,7 +1817,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
if (txq == sc->tx.txq_map[q] &&
|
||||
++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
|
||||
ath_mac80211_stop_queue(sc, q);
|
||||
ieee80211_stop_queue(sc->hw, q);
|
||||
txq->stopped = 1;
|
||||
}
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
@ -1825,8 +1832,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
|
||||
/*****************/
|
||||
|
||||
static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
||||
struct ath_wiphy *aphy, int tx_flags, int ftype,
|
||||
struct ath_txq *txq)
|
||||
int tx_flags, int ftype, struct ath_txq *txq)
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
@ -1836,9 +1842,6 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
||||
|
||||
ath_dbg(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
|
||||
|
||||
if (aphy)
|
||||
hw = aphy->hw;
|
||||
|
||||
if (tx_flags & ATH_TX_BAR)
|
||||
tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
|
||||
|
||||
@ -1868,19 +1871,20 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
||||
PS_WAIT_FOR_TX_ACK));
|
||||
}
|
||||
|
||||
if (unlikely(ftype))
|
||||
ath9k_tx_status(hw, skb, ftype);
|
||||
else {
|
||||
q = skb_get_queue_mapping(skb);
|
||||
if (txq == sc->tx.txq_map[q]) {
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
if (WARN_ON(--txq->pending_frames < 0))
|
||||
txq->pending_frames = 0;
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
}
|
||||
q = skb_get_queue_mapping(skb);
|
||||
if (txq == sc->tx.txq_map[q]) {
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
if (WARN_ON(--txq->pending_frames < 0))
|
||||
txq->pending_frames = 0;
|
||||
|
||||
ieee80211_tx_status(hw, skb);
|
||||
if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
|
||||
ieee80211_wake_queue(sc->hw, q);
|
||||
txq->stopped = 0;
|
||||
}
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
}
|
||||
|
||||
ieee80211_tx_status(hw, skb);
|
||||
}
|
||||
|
||||
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
|
||||
@ -1910,8 +1914,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
|
||||
else
|
||||
complete(&sc->paprd_complete);
|
||||
} else {
|
||||
ath_debug_stat_tx(sc, bf, ts);
|
||||
ath_tx_complete(sc, skb, bf->aphy, tx_flags,
|
||||
ath_debug_stat_tx(sc, bf, ts, txq);
|
||||
ath_tx_complete(sc, skb, tx_flags,
|
||||
bf->bf_state.bfs_ftype, txq);
|
||||
}
|
||||
/* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
|
||||
@ -1927,14 +1931,14 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
|
||||
spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
|
||||
}
|
||||
|
||||
static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
|
||||
int nframes, int nbad, int txok, bool update_rc)
|
||||
static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
|
||||
struct ath_tx_status *ts, int nframes, int nbad,
|
||||
int txok, bool update_rc)
|
||||
{
|
||||
struct sk_buff *skb = bf->bf_mpdu;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hw *hw = bf->aphy->hw;
|
||||
struct ath_softc *sc = bf->aphy->sc;
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
u8 i, tx_rateindex;
|
||||
|
||||
@ -1985,18 +1989,6 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
|
||||
tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
|
||||
}
|
||||
|
||||
/* Has no locking. Must hold spin_lock_bh(&txq->axq_lock)
|
||||
* before calling this.
|
||||
*/
|
||||
static void __ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
|
||||
{
|
||||
if (txq->mac80211_qnum >= 0 &&
|
||||
txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
|
||||
if (ath_mac80211_start_queue(sc, txq->mac80211_qnum))
|
||||
txq->stopped = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
@ -2007,7 +1999,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
||||
struct ath_tx_status ts;
|
||||
int txok;
|
||||
int status;
|
||||
int qnum;
|
||||
|
||||
ath_dbg(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
|
||||
txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
|
||||
@ -2086,11 +2077,9 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
||||
*/
|
||||
if (ts.ts_status & ATH9K_TXERR_XRETRY)
|
||||
bf->bf_state.bf_type |= BUF_XRETRY;
|
||||
ath_tx_rc_status(bf, &ts, 1, txok ? 0 : 1, txok, true);
|
||||
ath_tx_rc_status(sc, bf, &ts, 1, txok ? 0 : 1, txok, true);
|
||||
}
|
||||
|
||||
qnum = skb_get_queue_mapping(bf->bf_mpdu);
|
||||
|
||||
if (bf_isampdu(bf))
|
||||
ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok,
|
||||
true);
|
||||
@ -2098,7 +2087,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
||||
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
|
||||
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
__ath_wake_mac80211_queue(sc, txq);
|
||||
|
||||
if (sc->sc_flags & SC_OP_TXAGGR)
|
||||
ath_txq_schedule(sc, txq);
|
||||
@ -2106,6 +2094,28 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
||||
}
|
||||
}
|
||||
|
||||
static void ath_hw_pll_work(struct work_struct *work)
|
||||
{
|
||||
struct ath_softc *sc = container_of(work, struct ath_softc,
|
||||
hw_pll_work.work);
|
||||
static int count;
|
||||
|
||||
if (AR_SREV_9485(sc->sc_ah)) {
|
||||
if (ar9003_get_pll_sqsum_dvc(sc->sc_ah) >= 0x40000) {
|
||||
count++;
|
||||
|
||||
if (count == 3) {
|
||||
/* Rx is hung for more than 500ms. Reset it */
|
||||
ath_reset(sc, true);
|
||||
count = 0;
|
||||
}
|
||||
} else
|
||||
count = 0;
|
||||
|
||||
ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath_tx_complete_poll_work(struct work_struct *work)
|
||||
{
|
||||
struct ath_softc *sc = container_of(work, struct ath_softc,
|
||||
@ -2154,7 +2164,6 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
|
||||
txq->pending_frames,
|
||||
list_empty(&txq->axq_acq),
|
||||
txq->stopped);
|
||||
__ath_wake_mac80211_queue(sc, txq);
|
||||
ath_txq_schedule(sc, txq);
|
||||
}
|
||||
}
|
||||
@ -2196,7 +2205,6 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
|
||||
struct list_head bf_head;
|
||||
int status;
|
||||
int txok;
|
||||
int qnum;
|
||||
|
||||
for (;;) {
|
||||
status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
|
||||
@ -2239,11 +2247,9 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
|
||||
if (!bf_isampdu(bf)) {
|
||||
if (txs.ts_status & ATH9K_TXERR_XRETRY)
|
||||
bf->bf_state.bf_type |= BUF_XRETRY;
|
||||
ath_tx_rc_status(bf, &txs, 1, txok ? 0 : 1, txok, true);
|
||||
ath_tx_rc_status(sc, bf, &txs, 1, txok ? 0 : 1, txok, true);
|
||||
}
|
||||
|
||||
qnum = skb_get_queue_mapping(bf->bf_mpdu);
|
||||
|
||||
if (bf_isampdu(bf))
|
||||
ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs,
|
||||
txok, true);
|
||||
@ -2252,7 +2258,6 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
|
||||
&txs, txok, 0);
|
||||
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
__ath_wake_mac80211_queue(sc, txq);
|
||||
|
||||
if (!list_empty(&txq->txq_fifo_pending)) {
|
||||
INIT_LIST_HEAD(&bf_head);
|
||||
@ -2330,6 +2335,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
|
||||
INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
|
||||
error = ath_tx_edma_init(sc);
|
||||
|
@ -158,6 +158,13 @@ ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
|
||||
}
|
||||
}
|
||||
|
||||
bool ath_is_49ghz_allowed(u16 regdomain)
|
||||
{
|
||||
/* possibly more */
|
||||
return regdomain == MKK9_MKKC;
|
||||
}
|
||||
EXPORT_SYMBOL(ath_is_49ghz_allowed);
|
||||
|
||||
/* Frequency is one where radar detection is required */
|
||||
static bool ath_is_radar_freq(u16 center_freq)
|
||||
{
|
||||
|
@ -250,6 +250,7 @@ enum CountryCode {
|
||||
};
|
||||
|
||||
bool ath_is_world_regd(struct ath_regulatory *reg);
|
||||
bool ath_is_49ghz_allowed(u16 redomain);
|
||||
int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy,
|
||||
int (*reg_notifier)(struct wiphy *wiphy,
|
||||
struct regulatory_request *request));
|
||||
|
@ -762,8 +762,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
|
||||
|
||||
/* We need to figure out how to get the sta->supp_rates while
|
||||
* in this running context */
|
||||
rate_mask = IWL_RATES_MASK;
|
||||
|
||||
rate_mask = IWL_RATES_MASK_3945;
|
||||
|
||||
/* Set retry limit on DATA packets and Probe Responses*/
|
||||
if (ieee80211_is_probe_resp(fc))
|
||||
@ -1650,7 +1649,7 @@ static int iwl3945_hw_reg_comp_txpower_temp(struct iwl_priv *priv)
|
||||
ref_temp);
|
||||
|
||||
/* set tx power value for all rates, OFDM and CCK */
|
||||
for (rate_index = 0; rate_index < IWL_RATE_COUNT;
|
||||
for (rate_index = 0; rate_index < IWL_RATE_COUNT_3945;
|
||||
rate_index++) {
|
||||
int power_idx =
|
||||
ch_info->power_info[rate_index].base_power_index;
|
||||
@ -1890,7 +1889,7 @@ int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
||||
|
||||
/* If we issue a new RXON command which required a tune then we must
|
||||
* send a new TXPOWER command or we won't be able to Tx any frames */
|
||||
rc = priv->cfg->ops->lib->send_tx_power(priv);
|
||||
rc = iwl_set_tx_power(priv, priv->tx_power_next, true);
|
||||
if (rc) {
|
||||
IWL_ERR(priv, "Error setting Tx power (%d).\n", rc);
|
||||
return rc;
|
||||
|
@ -1571,7 +1571,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *c
|
||||
|
||||
/* If we issue a new RXON command which required a tune then we must
|
||||
* send a new TXPOWER command or we won't be able to Tx any frames */
|
||||
ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
|
||||
ret = iwl_set_tx_power(priv, priv->tx_power_next, true);
|
||||
if (ret) {
|
||||
IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
|
||||
return ret;
|
||||
|
@ -631,8 +631,7 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp)
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->bt_statistics) {
|
||||
if (iwl_bt_statistics(priv)) {
|
||||
rx_info = &(((struct iwl_bt_notif_statistics *)resp)->
|
||||
rx.general.common);
|
||||
ofdm = &(((struct iwl_bt_notif_statistics *)resp)->rx.ofdm);
|
||||
@ -897,8 +896,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->bt_statistics) {
|
||||
if (iwl_bt_statistics(priv)) {
|
||||
rx_info = &(((struct iwl_bt_notif_statistics *)stat_resp)->
|
||||
rx.general.common);
|
||||
} else {
|
||||
@ -913,8 +911,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
|
||||
|
||||
rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK);
|
||||
rxon_chnum = le16_to_cpu(ctx->staging.channel);
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->bt_statistics) {
|
||||
if (iwl_bt_statistics(priv)) {
|
||||
stat_band24 = !!(((struct iwl_bt_notif_statistics *)
|
||||
stat_resp)->flag &
|
||||
STATISTICS_REPLY_FLG_BAND_24G_MSK);
|
||||
|
@ -39,8 +39,7 @@ static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
|
||||
int p = 0;
|
||||
u32 flag;
|
||||
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->bt_statistics)
|
||||
if (iwl_bt_statistics(priv))
|
||||
flag = le32_to_cpu(priv->_agn.statistics_bt.flag);
|
||||
else
|
||||
flag = le32_to_cpu(priv->_agn.statistics.flag);
|
||||
@ -89,8 +88,7 @@ ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
|
||||
* the last statistics notification from uCode
|
||||
* might not reflect the current uCode activity
|
||||
*/
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->bt_statistics) {
|
||||
if (iwl_bt_statistics(priv)) {
|
||||
ofdm = &priv->_agn.statistics_bt.rx.ofdm;
|
||||
cck = &priv->_agn.statistics_bt.rx.cck;
|
||||
general = &priv->_agn.statistics_bt.rx.general.common;
|
||||
@ -536,8 +534,7 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file,
|
||||
* the last statistics notification from uCode
|
||||
* might not reflect the current uCode activity
|
||||
*/
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->bt_statistics) {
|
||||
if (iwl_bt_statistics(priv)) {
|
||||
tx = &priv->_agn.statistics_bt.tx;
|
||||
accum_tx = &priv->_agn.accum_statistics_bt.tx;
|
||||
delta_tx = &priv->_agn.delta_statistics_bt.tx;
|
||||
@ -737,8 +734,7 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
|
||||
* the last statistics notification from uCode
|
||||
* might not reflect the current uCode activity
|
||||
*/
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->bt_statistics) {
|
||||
if (iwl_bt_statistics(priv)) {
|
||||
general = &priv->_agn.statistics_bt.general.common;
|
||||
dbg = &priv->_agn.statistics_bt.general.common.dbg;
|
||||
div = &priv->_agn.statistics_bt.general.common.div;
|
||||
|
@ -213,6 +213,7 @@ enum {
|
||||
IWL_CCK_BASIC_RATES_MASK)
|
||||
|
||||
#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
|
||||
#define IWL_RATES_MASK_3945 ((1 << IWL_RATE_COUNT_3945) - 1)
|
||||
|
||||
#define IWL_INVALID_VALUE -1
|
||||
|
||||
|
@ -73,8 +73,7 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
|
||||
int bcn_silence_a, bcn_silence_b, bcn_silence_c;
|
||||
int last_rx_noise;
|
||||
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->bt_statistics)
|
||||
if (iwl_bt_statistics(priv))
|
||||
rx_info = &(priv->_agn.statistics_bt.rx.general.common);
|
||||
else
|
||||
rx_info = &(priv->_agn.statistics.rx.general);
|
||||
@ -125,8 +124,7 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv,
|
||||
struct statistics_general_common *general, *accum_general;
|
||||
struct statistics_tx *tx, *accum_tx;
|
||||
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->bt_statistics) {
|
||||
if (iwl_bt_statistics(priv)) {
|
||||
prev_stats = (__le32 *)&priv->_agn.statistics_bt;
|
||||
accum_stats = (u32 *)&priv->_agn.accum_statistics_bt;
|
||||
size = sizeof(struct iwl_bt_notif_statistics);
|
||||
@ -207,8 +205,7 @@ bool iwl_good_plcp_health(struct iwl_priv *priv,
|
||||
struct statistics_rx_phy *ofdm;
|
||||
struct statistics_rx_ht_phy *ofdm_ht;
|
||||
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->bt_statistics) {
|
||||
if (iwl_bt_statistics(priv)) {
|
||||
ofdm = &pkt->u.stats_bt.rx.ofdm;
|
||||
ofdm_ht = &pkt->u.stats_bt.rx.ofdm_ht;
|
||||
combined_plcp_delta =
|
||||
@ -265,8 +262,7 @@ void iwl_rx_statistics(struct iwl_priv *priv,
|
||||
int change;
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->bt_statistics) {
|
||||
if (iwl_bt_statistics(priv)) {
|
||||
IWL_DEBUG_RX(priv,
|
||||
"Statistics notification received (%d vs %d).\n",
|
||||
(int)sizeof(struct iwl_bt_notif_statistics),
|
||||
@ -304,8 +300,7 @@ void iwl_rx_statistics(struct iwl_priv *priv,
|
||||
|
||||
iwl_recover_from_statistics(priv, pkt);
|
||||
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->bt_statistics)
|
||||
if (iwl_bt_statistics(priv))
|
||||
memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt,
|
||||
sizeof(priv->_agn.statistics_bt));
|
||||
else
|
||||
|
@ -316,10 +316,9 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
||||
* If we issue a new RXON command which required a tune then we must
|
||||
* send a new TXPOWER command or we won't be able to Tx any frames.
|
||||
*
|
||||
* FIXME: which RXON requires a tune? Can we optimise this out in
|
||||
* some cases?
|
||||
* It's expected we set power here if channel is changing.
|
||||
*/
|
||||
ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
|
||||
ret = iwl_set_tx_power(priv, priv->tx_power_next, true);
|
||||
if (ret) {
|
||||
IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
|
||||
return ret;
|
||||
|
@ -3077,8 +3077,7 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
|
||||
}
|
||||
|
||||
if (priv->start_calib) {
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->bt_statistics) {
|
||||
if (iwl_bt_statistics(priv)) {
|
||||
iwl_chain_noise_calibration(priv,
|
||||
(void *)&priv->_agn.statistics_bt);
|
||||
iwl_sensitivity_calibration(priv,
|
||||
|
@ -219,16 +219,12 @@ int iwlcore_init_geos(struct iwl_priv *priv)
|
||||
if (!is_channel_valid(ch))
|
||||
continue;
|
||||
|
||||
if (is_channel_a_band(ch))
|
||||
sband = &priv->bands[IEEE80211_BAND_5GHZ];
|
||||
else
|
||||
sband = &priv->bands[IEEE80211_BAND_2GHZ];
|
||||
sband = &priv->bands[ch->band];
|
||||
|
||||
geo_ch = &sband->channels[sband->n_channels++];
|
||||
|
||||
geo_ch->center_freq =
|
||||
ieee80211_channel_to_frequency(ch->channel,
|
||||
sband->band);
|
||||
ieee80211_channel_to_frequency(ch->channel, ch->band);
|
||||
geo_ch->max_power = ch->max_power_avg;
|
||||
geo_ch->max_antenna_gain = 0xff;
|
||||
geo_ch->hw_value = ch->channel;
|
||||
@ -1162,6 +1158,8 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
|
||||
{
|
||||
int ret;
|
||||
s8 prev_tx_power;
|
||||
bool defer;
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
@ -1189,10 +1187,15 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
|
||||
if (!iwl_is_ready_rf(priv))
|
||||
return -EIO;
|
||||
|
||||
/* scan complete use tx_power_next, need to be updated */
|
||||
/* scan complete and commit_rxon use tx_power_next value,
|
||||
* it always need to be updated for newest request */
|
||||
priv->tx_power_next = tx_power;
|
||||
if (test_bit(STATUS_SCANNING, &priv->status) && !force) {
|
||||
IWL_DEBUG_INFO(priv, "Deferring tx power set while scanning\n");
|
||||
|
||||
/* do not set tx power when scanning or channel changing */
|
||||
defer = test_bit(STATUS_SCANNING, &priv->status) ||
|
||||
memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging));
|
||||
if (defer && !force) {
|
||||
IWL_DEBUG_INFO(priv, "Deferring tx power set\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -741,6 +741,17 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
|
||||
return priv->hw->wiphy->bands[band];
|
||||
}
|
||||
|
||||
static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv)
|
||||
{
|
||||
return priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->advanced_bt_coexist;
|
||||
}
|
||||
|
||||
static inline bool iwl_bt_statistics(struct iwl_priv *priv)
|
||||
{
|
||||
return priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics;
|
||||
}
|
||||
|
||||
extern bool bt_coex_active;
|
||||
extern bool bt_siso_mode;
|
||||
|
||||
|
@ -1765,13 +1765,13 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
|
||||
DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
|
||||
if (priv->cfg->base_params->ucode_tracing)
|
||||
DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
|
||||
if (priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics)
|
||||
if (iwl_bt_statistics(priv))
|
||||
DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
|
||||
if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist)
|
||||
if (iwl_advanced_bt_coexist(priv))
|
||||
DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
|
||||
if (priv->cfg->base_params->sensitivity_calib_by_driver)
|
||||
DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
|
||||
|
@ -138,7 +138,7 @@ struct iwl_queue {
|
||||
* space more than this */
|
||||
int high_mark; /* high watermark, stop queue if free
|
||||
* space less than this */
|
||||
} __packed;
|
||||
};
|
||||
|
||||
/* One for each TFD */
|
||||
struct iwl_tx_info {
|
||||
|
@ -85,10 +85,9 @@ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed)
|
||||
IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n",
|
||||
channel->hw_value, changed);
|
||||
|
||||
if (unlikely(!priv->cfg->mod_params->disable_hw_scan &&
|
||||
test_bit(STATUS_SCANNING, &priv->status))) {
|
||||
if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
|
||||
scan_active = 1;
|
||||
IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
|
||||
IWL_DEBUG_MAC80211(priv, "scan active\n");
|
||||
}
|
||||
|
||||
if (changed & (IEEE80211_CONF_CHANGE_SMPS |
|
||||
|
@ -226,8 +226,7 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
|
||||
else
|
||||
cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA;
|
||||
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->advanced_bt_coexist) {
|
||||
if (iwl_advanced_bt_coexist(priv)) {
|
||||
if (!priv->cfg->bt_params->bt_sco_disable)
|
||||
cmd->flags |= IWL_POWER_BT_SCO_ENA;
|
||||
else
|
||||
@ -313,8 +312,7 @@ static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv,
|
||||
else
|
||||
cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA;
|
||||
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->advanced_bt_coexist) {
|
||||
if (iwl_advanced_bt_coexist(priv)) {
|
||||
if (!priv->cfg->bt_params->bt_sco_disable)
|
||||
cmd->flags |= IWL_POWER_BT_SCO_ENA;
|
||||
else
|
||||
|
@ -257,8 +257,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
|
||||
queue_work(priv->workqueue, &priv->scan_completed);
|
||||
|
||||
if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
|
||||
priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->advanced_bt_coexist &&
|
||||
iwl_advanced_bt_coexist(priv) &&
|
||||
priv->bt_status != scan_notif->bt_status) {
|
||||
if (scan_notif->bt_status) {
|
||||
/* BT on */
|
||||
|
@ -2517,7 +2517,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
|
||||
|
||||
ieee80211_wake_queues(priv->hw);
|
||||
|
||||
priv->active_rate = IWL_RATES_MASK;
|
||||
priv->active_rate = IWL_RATES_MASK_3945;
|
||||
|
||||
iwl_power_update_mode(priv, true);
|
||||
|
||||
@ -2535,13 +2535,14 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
|
||||
/* Configure Bluetooth device coexistence support */
|
||||
priv->cfg->ops->hcmd->send_bt_config(priv);
|
||||
|
||||
set_bit(STATUS_READY, &priv->status);
|
||||
|
||||
/* Configure the adapter for unassociated operation */
|
||||
iwl3945_commit_rxon(priv, ctx);
|
||||
|
||||
iwl3945_reg_txpower_periodic(priv);
|
||||
|
||||
IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
|
||||
set_bit(STATUS_READY, &priv->status);
|
||||
wake_up_interruptible(&priv->wait_command_queue);
|
||||
|
||||
return;
|
||||
|
@ -46,7 +46,7 @@
|
||||
* These indirect registers work with busy bits,
|
||||
* and we will try maximal REGISTER_BUSY_COUNT times to access
|
||||
* the register while taking a REGISTER_BUSY_DELAY us delay
|
||||
* between each attampt. When the busy bit is still set at that time,
|
||||
* between each attempt. When the busy bit is still set at that time,
|
||||
* the access attempt is considered to have failed,
|
||||
* and we will print an error.
|
||||
*/
|
||||
@ -305,9 +305,7 @@ static void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev,
|
||||
* Enable synchronisation.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, CSR14, ®);
|
||||
rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
|
||||
rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync);
|
||||
rt2x00_set_field32(®, CSR14_TBCN, 1);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
|
||||
}
|
||||
|
||||
@ -647,6 +645,11 @@ static void rt2400pci_start_queue(struct data_queue *queue)
|
||||
rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
|
||||
break;
|
||||
case QID_BEACON:
|
||||
/*
|
||||
* Allow the tbtt tasklet to be scheduled.
|
||||
*/
|
||||
tasklet_enable(&rt2x00dev->tbtt_tasklet);
|
||||
|
||||
rt2x00pci_register_read(rt2x00dev, CSR14, ®);
|
||||
rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
|
||||
rt2x00_set_field32(®, CSR14_TBCN, 1);
|
||||
@ -708,6 +711,11 @@ static void rt2400pci_stop_queue(struct data_queue *queue)
|
||||
rt2x00_set_field32(®, CSR14_TBCN, 0);
|
||||
rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
|
||||
|
||||
/*
|
||||
* Wait for possibly running tbtt tasklets.
|
||||
*/
|
||||
tasklet_disable(&rt2x00dev->tbtt_tasklet);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -963,9 +971,9 @@ static int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev)
|
||||
static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
|
||||
enum dev_state state)
|
||||
{
|
||||
int mask = (state == STATE_RADIO_IRQ_OFF) ||
|
||||
(state == STATE_RADIO_IRQ_OFF_ISR);
|
||||
int mask = (state == STATE_RADIO_IRQ_OFF);
|
||||
u32 reg;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* When interrupts are being enabled, the interrupt registers
|
||||
@ -974,12 +982,20 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
|
||||
if (state == STATE_RADIO_IRQ_ON) {
|
||||
rt2x00pci_register_read(rt2x00dev, CSR7, ®);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR7, reg);
|
||||
|
||||
/*
|
||||
* Enable tasklets.
|
||||
*/
|
||||
tasklet_enable(&rt2x00dev->txstatus_tasklet);
|
||||
tasklet_enable(&rt2x00dev->rxdone_tasklet);
|
||||
}
|
||||
|
||||
/*
|
||||
* Only toggle the interrupts bits we are going to use.
|
||||
* Non-checked interrupt bits are disabled by default.
|
||||
*/
|
||||
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
rt2x00pci_register_read(rt2x00dev, CSR8, ®);
|
||||
rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask);
|
||||
rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask);
|
||||
@ -987,6 +1003,17 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
|
||||
rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, mask);
|
||||
rt2x00_set_field32(®, CSR8_RXDONE, mask);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR8, reg);
|
||||
|
||||
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
if (state == STATE_RADIO_IRQ_OFF) {
|
||||
/*
|
||||
* Ensure that all tasklets are finished before
|
||||
* disabling the interrupts.
|
||||
*/
|
||||
tasklet_disable(&rt2x00dev->txstatus_tasklet);
|
||||
tasklet_disable(&rt2x00dev->rxdone_tasklet);
|
||||
}
|
||||
}
|
||||
|
||||
static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev)
|
||||
@ -1059,9 +1086,7 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
|
||||
rt2400pci_disable_radio(rt2x00dev);
|
||||
break;
|
||||
case STATE_RADIO_IRQ_ON:
|
||||
case STATE_RADIO_IRQ_ON_ISR:
|
||||
case STATE_RADIO_IRQ_OFF:
|
||||
case STATE_RADIO_IRQ_OFF_ISR:
|
||||
rt2400pci_toggle_irq(rt2x00dev, state);
|
||||
break;
|
||||
case STATE_DEEP_SLEEP:
|
||||
@ -1183,8 +1208,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
|
||||
/*
|
||||
* Enable beaconing again.
|
||||
*/
|
||||
rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
|
||||
rt2x00_set_field32(®, CSR14_TBCN, 1);
|
||||
rt2x00_set_field32(®, CSR14_BEACON_GEN, 1);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
|
||||
}
|
||||
@ -1289,57 +1312,71 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t rt2400pci_interrupt_thread(int irq, void *dev_instance)
|
||||
static void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
|
||||
struct rt2x00_field32 irq_field)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = dev_instance;
|
||||
u32 reg = rt2x00dev->irqvalue[0];
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Handle interrupts, walk through all bits
|
||||
* and run the tasks, the bits are checked in order of
|
||||
* priority.
|
||||
* Enable a single interrupt. The interrupt mask register
|
||||
* access needs locking.
|
||||
*/
|
||||
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
rt2x00pci_register_read(rt2x00dev, CSR8, ®);
|
||||
rt2x00_set_field32(®, irq_field, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR8, reg);
|
||||
|
||||
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
|
||||
}
|
||||
|
||||
static void rt2400pci_txstatus_tasklet(unsigned long data)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
|
||||
u32 reg;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* 1 - Beacon timer expired interrupt.
|
||||
* Handle all tx queues.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE))
|
||||
rt2x00lib_beacondone(rt2x00dev);
|
||||
rt2400pci_txdone(rt2x00dev, QID_ATIM);
|
||||
rt2400pci_txdone(rt2x00dev, QID_AC_VO);
|
||||
rt2400pci_txdone(rt2x00dev, QID_AC_VI);
|
||||
|
||||
/*
|
||||
* 2 - Rx ring done interrupt.
|
||||
* Enable all TXDONE interrupts again.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, CSR7_RXDONE))
|
||||
rt2x00pci_rxdone(rt2x00dev);
|
||||
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
/*
|
||||
* 3 - Atim ring transmit done interrupt.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING))
|
||||
rt2400pci_txdone(rt2x00dev, QID_ATIM);
|
||||
rt2x00pci_register_read(rt2x00dev, CSR8, ®);
|
||||
rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0);
|
||||
rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0);
|
||||
rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR8, reg);
|
||||
|
||||
/*
|
||||
* 4 - Priority ring transmit done interrupt.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
|
||||
rt2400pci_txdone(rt2x00dev, QID_AC_VO);
|
||||
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* 5 - Tx ring transmit done interrupt.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
|
||||
rt2400pci_txdone(rt2x00dev, QID_AC_VI);
|
||||
static void rt2400pci_tbtt_tasklet(unsigned long data)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
|
||||
rt2x00lib_beacondone(rt2x00dev);
|
||||
rt2400pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE);
|
||||
}
|
||||
|
||||
/* Enable interrupts again. */
|
||||
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
|
||||
STATE_RADIO_IRQ_ON_ISR);
|
||||
return IRQ_HANDLED;
|
||||
static void rt2400pci_rxdone_tasklet(unsigned long data)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
|
||||
rt2x00pci_rxdone(rt2x00dev);
|
||||
rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
|
||||
}
|
||||
|
||||
static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = dev_instance;
|
||||
u32 reg;
|
||||
u32 reg, mask;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Get the interrupt sources & saved to local variable.
|
||||
@ -1354,14 +1391,44 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
|
||||
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/* Store irqvalues for use in the interrupt thread. */
|
||||
rt2x00dev->irqvalue[0] = reg;
|
||||
mask = reg;
|
||||
|
||||
/* Disable interrupts, will be enabled again in the interrupt thread. */
|
||||
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
|
||||
STATE_RADIO_IRQ_OFF_ISR);
|
||||
/*
|
||||
* Schedule tasklets for interrupt handling.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE))
|
||||
tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
if (rt2x00_get_field32(reg, CSR7_RXDONE))
|
||||
tasklet_schedule(&rt2x00dev->rxdone_tasklet);
|
||||
|
||||
if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING) ||
|
||||
rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING) ||
|
||||
rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) {
|
||||
tasklet_schedule(&rt2x00dev->txstatus_tasklet);
|
||||
/*
|
||||
* Mask out all txdone interrupts.
|
||||
*/
|
||||
rt2x00_set_field32(&mask, CSR8_TXDONE_TXRING, 1);
|
||||
rt2x00_set_field32(&mask, CSR8_TXDONE_ATIMRING, 1);
|
||||
rt2x00_set_field32(&mask, CSR8_TXDONE_PRIORING, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable all interrupts for which a tasklet was scheduled right now,
|
||||
* the tasklet will reenable the appropriate interrupts.
|
||||
*/
|
||||
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
rt2x00pci_register_read(rt2x00dev, CSR8, ®);
|
||||
reg |= mask;
|
||||
rt2x00pci_register_write(rt2x00dev, CSR8, reg);
|
||||
|
||||
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1655,7 +1722,9 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
|
||||
|
||||
static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
|
||||
.irq_handler = rt2400pci_interrupt,
|
||||
.irq_handler_thread = rt2400pci_interrupt_thread,
|
||||
.txstatus_tasklet = rt2400pci_txstatus_tasklet,
|
||||
.tbtt_tasklet = rt2400pci_tbtt_tasklet,
|
||||
.rxdone_tasklet = rt2400pci_rxdone_tasklet,
|
||||
.probe_hw = rt2400pci_probe_hw,
|
||||
.initialize = rt2x00pci_initialize,
|
||||
.uninitialize = rt2x00pci_uninitialize,
|
||||
|
@ -311,9 +311,7 @@ static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev,
|
||||
* Enable synchronisation.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, CSR14, ®);
|
||||
rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
|
||||
rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync);
|
||||
rt2x00_set_field32(®, CSR14_TBCN, 1);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
|
||||
}
|
||||
|
||||
@ -737,6 +735,11 @@ static void rt2500pci_start_queue(struct data_queue *queue)
|
||||
rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
|
||||
break;
|
||||
case QID_BEACON:
|
||||
/*
|
||||
* Allow the tbtt tasklet to be scheduled.
|
||||
*/
|
||||
tasklet_enable(&rt2x00dev->tbtt_tasklet);
|
||||
|
||||
rt2x00pci_register_read(rt2x00dev, CSR14, ®);
|
||||
rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
|
||||
rt2x00_set_field32(®, CSR14_TBCN, 1);
|
||||
@ -798,6 +801,11 @@ static void rt2500pci_stop_queue(struct data_queue *queue)
|
||||
rt2x00_set_field32(®, CSR14_TBCN, 0);
|
||||
rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
|
||||
|
||||
/*
|
||||
* Wait for possibly running tbtt tasklets.
|
||||
*/
|
||||
tasklet_disable(&rt2x00dev->tbtt_tasklet);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -1118,9 +1126,9 @@ static int rt2500pci_init_bbp(struct rt2x00_dev *rt2x00dev)
|
||||
static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
|
||||
enum dev_state state)
|
||||
{
|
||||
int mask = (state == STATE_RADIO_IRQ_OFF) ||
|
||||
(state == STATE_RADIO_IRQ_OFF_ISR);
|
||||
int mask = (state == STATE_RADIO_IRQ_OFF);
|
||||
u32 reg;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* When interrupts are being enabled, the interrupt registers
|
||||
@ -1129,12 +1137,20 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
|
||||
if (state == STATE_RADIO_IRQ_ON) {
|
||||
rt2x00pci_register_read(rt2x00dev, CSR7, ®);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR7, reg);
|
||||
|
||||
/*
|
||||
* Enable tasklets.
|
||||
*/
|
||||
tasklet_enable(&rt2x00dev->txstatus_tasklet);
|
||||
tasklet_enable(&rt2x00dev->rxdone_tasklet);
|
||||
}
|
||||
|
||||
/*
|
||||
* Only toggle the interrupts bits we are going to use.
|
||||
* Non-checked interrupt bits are disabled by default.
|
||||
*/
|
||||
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
rt2x00pci_register_read(rt2x00dev, CSR8, ®);
|
||||
rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask);
|
||||
rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask);
|
||||
@ -1142,6 +1158,16 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
|
||||
rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, mask);
|
||||
rt2x00_set_field32(®, CSR8_RXDONE, mask);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR8, reg);
|
||||
|
||||
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
if (state == STATE_RADIO_IRQ_OFF) {
|
||||
/*
|
||||
* Ensure that all tasklets are finished.
|
||||
*/
|
||||
tasklet_disable(&rt2x00dev->txstatus_tasklet);
|
||||
tasklet_disable(&rt2x00dev->rxdone_tasklet);
|
||||
}
|
||||
}
|
||||
|
||||
static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev)
|
||||
@ -1214,9 +1240,7 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
|
||||
rt2500pci_disable_radio(rt2x00dev);
|
||||
break;
|
||||
case STATE_RADIO_IRQ_ON:
|
||||
case STATE_RADIO_IRQ_ON_ISR:
|
||||
case STATE_RADIO_IRQ_OFF:
|
||||
case STATE_RADIO_IRQ_OFF_ISR:
|
||||
rt2500pci_toggle_irq(rt2x00dev, state);
|
||||
break;
|
||||
case STATE_DEEP_SLEEP:
|
||||
@ -1337,8 +1361,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
|
||||
/*
|
||||
* Enable beaconing again.
|
||||
*/
|
||||
rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
|
||||
rt2x00_set_field32(®, CSR14_TBCN, 1);
|
||||
rt2x00_set_field32(®, CSR14_BEACON_GEN, 1);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
|
||||
}
|
||||
@ -1422,58 +1444,71 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t rt2500pci_interrupt_thread(int irq, void *dev_instance)
|
||||
static void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
|
||||
struct rt2x00_field32 irq_field)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = dev_instance;
|
||||
u32 reg = rt2x00dev->irqvalue[0];
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Handle interrupts, walk through all bits
|
||||
* and run the tasks, the bits are checked in order of
|
||||
* priority.
|
||||
* Enable a single interrupt. The interrupt mask register
|
||||
* access needs locking.
|
||||
*/
|
||||
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
rt2x00pci_register_read(rt2x00dev, CSR8, ®);
|
||||
rt2x00_set_field32(®, irq_field, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR8, reg);
|
||||
|
||||
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
|
||||
}
|
||||
|
||||
static void rt2500pci_txstatus_tasklet(unsigned long data)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
|
||||
u32 reg;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* 1 - Beacon timer expired interrupt.
|
||||
* Handle all tx queues.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE))
|
||||
rt2x00lib_beacondone(rt2x00dev);
|
||||
rt2500pci_txdone(rt2x00dev, QID_ATIM);
|
||||
rt2500pci_txdone(rt2x00dev, QID_AC_VO);
|
||||
rt2500pci_txdone(rt2x00dev, QID_AC_VI);
|
||||
|
||||
/*
|
||||
* 2 - Rx ring done interrupt.
|
||||
* Enable all TXDONE interrupts again.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, CSR7_RXDONE))
|
||||
rt2x00pci_rxdone(rt2x00dev);
|
||||
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
/*
|
||||
* 3 - Atim ring transmit done interrupt.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING))
|
||||
rt2500pci_txdone(rt2x00dev, QID_ATIM);
|
||||
rt2x00pci_register_read(rt2x00dev, CSR8, ®);
|
||||
rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0);
|
||||
rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0);
|
||||
rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR8, reg);
|
||||
|
||||
/*
|
||||
* 4 - Priority ring transmit done interrupt.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
|
||||
rt2500pci_txdone(rt2x00dev, QID_AC_VO);
|
||||
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* 5 - Tx ring transmit done interrupt.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
|
||||
rt2500pci_txdone(rt2x00dev, QID_AC_VI);
|
||||
static void rt2500pci_tbtt_tasklet(unsigned long data)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
|
||||
rt2x00lib_beacondone(rt2x00dev);
|
||||
rt2500pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE);
|
||||
}
|
||||
|
||||
/* Enable interrupts again. */
|
||||
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
|
||||
STATE_RADIO_IRQ_ON_ISR);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
static void rt2500pci_rxdone_tasklet(unsigned long data)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
|
||||
rt2x00pci_rxdone(rt2x00dev);
|
||||
rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
|
||||
}
|
||||
|
||||
static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = dev_instance;
|
||||
u32 reg;
|
||||
u32 reg, mask;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Get the interrupt sources & saved to local variable.
|
||||
@ -1488,14 +1523,42 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
|
||||
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/* Store irqvalues for use in the interrupt thread. */
|
||||
rt2x00dev->irqvalue[0] = reg;
|
||||
mask = reg;
|
||||
|
||||
/* Disable interrupts, will be enabled again in the interrupt thread. */
|
||||
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
|
||||
STATE_RADIO_IRQ_OFF_ISR);
|
||||
/*
|
||||
* Schedule tasklets for interrupt handling.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE))
|
||||
tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
if (rt2x00_get_field32(reg, CSR7_RXDONE))
|
||||
tasklet_schedule(&rt2x00dev->rxdone_tasklet);
|
||||
|
||||
if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING) ||
|
||||
rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING) ||
|
||||
rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) {
|
||||
tasklet_schedule(&rt2x00dev->txstatus_tasklet);
|
||||
/*
|
||||
* Mask out all txdone interrupts.
|
||||
*/
|
||||
rt2x00_set_field32(&mask, CSR8_TXDONE_TXRING, 1);
|
||||
rt2x00_set_field32(&mask, CSR8_TXDONE_ATIMRING, 1);
|
||||
rt2x00_set_field32(&mask, CSR8_TXDONE_PRIORING, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable all interrupts for which a tasklet was scheduled right now,
|
||||
* the tasklet will reenable the appropriate interrupts.
|
||||
*/
|
||||
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
rt2x00pci_register_read(rt2x00dev, CSR8, ®);
|
||||
reg |= mask;
|
||||
rt2x00pci_register_write(rt2x00dev, CSR8, reg);
|
||||
|
||||
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1952,7 +2015,9 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
|
||||
|
||||
static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
|
||||
.irq_handler = rt2500pci_interrupt,
|
||||
.irq_handler_thread = rt2500pci_interrupt_thread,
|
||||
.txstatus_tasklet = rt2500pci_txstatus_tasklet,
|
||||
.tbtt_tasklet = rt2500pci_tbtt_tasklet,
|
||||
.rxdone_tasklet = rt2500pci_rxdone_tasklet,
|
||||
.probe_hw = rt2500pci_probe_hw,
|
||||
.initialize = rt2x00pci_initialize,
|
||||
.uninitialize = rt2x00pci_uninitialize,
|
||||
|
@ -478,9 +478,7 @@ static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev,
|
||||
rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
|
||||
|
||||
rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®);
|
||||
rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1);
|
||||
rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, conf->sync);
|
||||
rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1);
|
||||
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
|
||||
}
|
||||
|
||||
@ -1056,9 +1054,7 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
|
||||
rt2500usb_disable_radio(rt2x00dev);
|
||||
break;
|
||||
case STATE_RADIO_IRQ_ON:
|
||||
case STATE_RADIO_IRQ_ON_ISR:
|
||||
case STATE_RADIO_IRQ_OFF:
|
||||
case STATE_RADIO_IRQ_OFF_ISR:
|
||||
/* No support, but no error either */
|
||||
break;
|
||||
case STATE_DEEP_SLEEP:
|
||||
|
@ -372,8 +372,12 @@
|
||||
|
||||
/*
|
||||
* US_CYC_CNT
|
||||
* BT_MODE_EN: Bluetooth mode enable
|
||||
* CLOCK CYCLE: Clock cycle count in 1us.
|
||||
* PCI:0x21, PCIE:0x7d, USB:0x1e
|
||||
*/
|
||||
#define US_CYC_CNT 0x02a4
|
||||
#define US_CYC_CNT_BT_MODE_EN FIELD32(0x00000100)
|
||||
#define US_CYC_CNT_CLOCK_CYCLE FIELD32(0x000000ff)
|
||||
|
||||
/*
|
||||
|
@ -818,8 +818,6 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
|
||||
/*
|
||||
* Enable beaconing again.
|
||||
*/
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1);
|
||||
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
|
||||
|
||||
@ -831,8 +829,8 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2800_write_beacon);
|
||||
|
||||
static inline void rt2800_clear_beacon(struct rt2x00_dev *rt2x00dev,
|
||||
unsigned int beacon_base)
|
||||
static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev,
|
||||
unsigned int beacon_base)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -845,6 +843,33 @@ static inline void rt2800_clear_beacon(struct rt2x00_dev *rt2x00dev,
|
||||
rt2800_register_write(rt2x00dev, beacon_base + i, 0);
|
||||
}
|
||||
|
||||
void rt2800_clear_beacon(struct queue_entry *entry)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Disable beaconing while we are reloading the beacon data,
|
||||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0);
|
||||
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
|
||||
|
||||
/*
|
||||
* Clear beacon.
|
||||
*/
|
||||
rt2800_clear_beacon_register(rt2x00dev,
|
||||
HW_BEACON_OFFSET(entry->entry_idx));
|
||||
|
||||
/*
|
||||
* Enabled beaconing again.
|
||||
*/
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1);
|
||||
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2800_clear_beacon);
|
||||
|
||||
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
|
||||
const struct rt2x00debug rt2800_rt2x00debug = {
|
||||
.owner = THIS_MODULE,
|
||||
@ -1005,7 +1030,7 @@ static void rt2800_config_wcid_attr(struct rt2x00_dev *rt2x00dev,
|
||||
|
||||
memset(&wcid_entry, 0, sizeof(wcid_entry));
|
||||
if (crypto->cmd == SET_KEY)
|
||||
memcpy(&wcid_entry, crypto->address, ETH_ALEN);
|
||||
memcpy(wcid_entry.mac, crypto->address, ETH_ALEN);
|
||||
rt2800_register_multiwrite(rt2x00dev, offset,
|
||||
&wcid_entry, sizeof(wcid_entry));
|
||||
}
|
||||
@ -1154,30 +1179,12 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
|
||||
bool update_bssid = false;
|
||||
|
||||
if (flags & CONFIG_UPDATE_TYPE) {
|
||||
/*
|
||||
* Clear current synchronisation setup.
|
||||
*/
|
||||
rt2800_clear_beacon(rt2x00dev,
|
||||
HW_BEACON_OFFSET(intf->beacon->entry_idx));
|
||||
/*
|
||||
* Enable synchronisation.
|
||||
*/
|
||||
rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE,
|
||||
(conf->sync == TSF_SYNC_ADHOC ||
|
||||
conf->sync == TSF_SYNC_AP_NONE));
|
||||
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
|
||||
|
||||
/*
|
||||
* Enable pre tbtt interrupt for beaconing modes
|
||||
*/
|
||||
rt2800_register_read(rt2x00dev, INT_TIMER_EN, ®);
|
||||
rt2x00_set_field32(®, INT_TIMER_EN_PRE_TBTT_TIMER,
|
||||
(conf->sync == TSF_SYNC_AP_NONE));
|
||||
rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg);
|
||||
|
||||
}
|
||||
|
||||
if (flags & CONFIG_UPDATE_MAC) {
|
||||
@ -2187,19 +2194,23 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
|
||||
/*
|
||||
* Clear all beacons
|
||||
*/
|
||||
rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE0);
|
||||
rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE1);
|
||||
rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE2);
|
||||
rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE3);
|
||||
rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE4);
|
||||
rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE5);
|
||||
rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE6);
|
||||
rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE7);
|
||||
rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE0);
|
||||
rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE1);
|
||||
rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE2);
|
||||
rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE3);
|
||||
rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE4);
|
||||
rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE5);
|
||||
rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE6);
|
||||
rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE7);
|
||||
|
||||
if (rt2x00_is_usb(rt2x00dev)) {
|
||||
rt2800_register_read(rt2x00dev, US_CYC_CNT, ®);
|
||||
rt2x00_set_field32(®, US_CYC_CNT_CLOCK_CYCLE, 30);
|
||||
rt2800_register_write(rt2x00dev, US_CYC_CNT, reg);
|
||||
} else if (rt2x00_is_pcie(rt2x00dev)) {
|
||||
rt2800_register_read(rt2x00dev, US_CYC_CNT, ®);
|
||||
rt2x00_set_field32(®, US_CYC_CNT_CLOCK_CYCLE, 125);
|
||||
rt2800_register_write(rt2x00dev, US_CYC_CNT, reg);
|
||||
}
|
||||
|
||||
rt2800_register_read(rt2x00dev, HT_FBK_CFG0, ®);
|
||||
|
@ -156,6 +156,7 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev);
|
||||
void rt2800_txdone_entry(struct queue_entry *entry, u32 status);
|
||||
|
||||
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
|
||||
void rt2800_clear_beacon(struct queue_entry *entry);
|
||||
|
||||
extern const struct rt2x00debug rt2800_rt2x00debug;
|
||||
|
||||
|
@ -200,11 +200,22 @@ static void rt2800pci_start_queue(struct data_queue *queue)
|
||||
rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
|
||||
break;
|
||||
case QID_BEACON:
|
||||
/*
|
||||
* Allow beacon tasklets to be scheduled for periodic
|
||||
* beacon updates.
|
||||
*/
|
||||
tasklet_enable(&rt2x00dev->tbtt_tasklet);
|
||||
tasklet_enable(&rt2x00dev->pretbtt_tasklet);
|
||||
|
||||
rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1);
|
||||
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
|
||||
|
||||
rt2800_register_read(rt2x00dev, INT_TIMER_EN, ®);
|
||||
rt2x00_set_field32(®, INT_TIMER_EN_PRE_TBTT_TIMER, 1);
|
||||
rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -250,6 +261,16 @@ static void rt2800pci_stop_queue(struct data_queue *queue)
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0);
|
||||
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
|
||||
|
||||
rt2800_register_read(rt2x00dev, INT_TIMER_EN, ®);
|
||||
rt2x00_set_field32(®, INT_TIMER_EN_PRE_TBTT_TIMER, 0);
|
||||
rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg);
|
||||
|
||||
/*
|
||||
* Wait for tbtt tasklets to finish.
|
||||
*/
|
||||
tasklet_disable(&rt2x00dev->tbtt_tasklet);
|
||||
tasklet_disable(&rt2x00dev->pretbtt_tasklet);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -397,9 +418,9 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev)
|
||||
static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
|
||||
enum dev_state state)
|
||||
{
|
||||
int mask = (state == STATE_RADIO_IRQ_ON) ||
|
||||
(state == STATE_RADIO_IRQ_ON_ISR);
|
||||
int mask = (state == STATE_RADIO_IRQ_ON);
|
||||
u32 reg;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* When interrupts are being enabled, the interrupt registers
|
||||
@ -408,8 +429,17 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
|
||||
if (state == STATE_RADIO_IRQ_ON) {
|
||||
rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, ®);
|
||||
rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
|
||||
|
||||
/*
|
||||
* Enable tasklets. The beacon related tasklets are
|
||||
* enabled when the beacon queue is started.
|
||||
*/
|
||||
tasklet_enable(&rt2x00dev->txstatus_tasklet);
|
||||
tasklet_enable(&rt2x00dev->rxdone_tasklet);
|
||||
tasklet_enable(&rt2x00dev->autowake_tasklet);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
|
||||
rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_RXDELAYINT, 0);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_TXDELAYINT, 0);
|
||||
@ -430,6 +460,17 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_RX_COHERENT, 0);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_TX_COHERENT, 0);
|
||||
rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
|
||||
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
if (state == STATE_RADIO_IRQ_OFF) {
|
||||
/*
|
||||
* Ensure that all tasklets are finished before
|
||||
* disabling the interrupts.
|
||||
*/
|
||||
tasklet_disable(&rt2x00dev->txstatus_tasklet);
|
||||
tasklet_disable(&rt2x00dev->rxdone_tasklet);
|
||||
tasklet_disable(&rt2x00dev->autowake_tasklet);
|
||||
}
|
||||
}
|
||||
|
||||
static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
|
||||
@ -522,9 +563,7 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
|
||||
rt2800pci_set_state(rt2x00dev, STATE_SLEEP);
|
||||
break;
|
||||
case STATE_RADIO_IRQ_ON:
|
||||
case STATE_RADIO_IRQ_ON_ISR:
|
||||
case STATE_RADIO_IRQ_OFF:
|
||||
case STATE_RADIO_IRQ_OFF_ISR:
|
||||
rt2800pci_toggle_irq(rt2x00dev, state);
|
||||
break;
|
||||
case STATE_DEEP_SLEEP:
|
||||
@ -636,6 +675,12 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
|
||||
*/
|
||||
rxdesc->flags |= RX_FLAG_IV_STRIPPED;
|
||||
|
||||
/*
|
||||
* The hardware has already checked the Michael Mic and has
|
||||
* stripped it from the frame. Signal this to mac80211.
|
||||
*/
|
||||
rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
|
||||
|
||||
if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
|
||||
rxdesc->flags |= RX_FLAG_DECRYPTED;
|
||||
else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
|
||||
@ -710,45 +755,60 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
|
||||
}
|
||||
}
|
||||
|
||||
static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
|
||||
struct rt2x00_field32 irq_field)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Enable a single interrupt. The interrupt mask register
|
||||
* access needs locking.
|
||||
*/
|
||||
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
|
||||
rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®);
|
||||
rt2x00_set_field32(®, irq_field, 1);
|
||||
rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
|
||||
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
|
||||
}
|
||||
|
||||
static void rt2800pci_txstatus_tasklet(unsigned long data)
|
||||
{
|
||||
rt2800pci_txdone((struct rt2x00_dev *)data);
|
||||
|
||||
/*
|
||||
* No need to enable the tx status interrupt here as we always
|
||||
* leave it enabled to minimize the possibility of a tx status
|
||||
* register overflow. See comment in interrupt handler.
|
||||
*/
|
||||
}
|
||||
|
||||
static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
|
||||
static void rt2800pci_pretbtt_tasklet(unsigned long data)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = dev_instance;
|
||||
u32 reg = rt2x00dev->irqvalue[0];
|
||||
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
|
||||
rt2x00lib_pretbtt(rt2x00dev);
|
||||
rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_PRE_TBTT);
|
||||
}
|
||||
|
||||
/*
|
||||
* 1 - Pre TBTT interrupt.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
|
||||
rt2x00lib_pretbtt(rt2x00dev);
|
||||
static void rt2800pci_tbtt_tasklet(unsigned long data)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
|
||||
rt2x00lib_beacondone(rt2x00dev);
|
||||
rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TBTT);
|
||||
}
|
||||
|
||||
/*
|
||||
* 2 - Beacondone interrupt.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT))
|
||||
rt2x00lib_beacondone(rt2x00dev);
|
||||
static void rt2800pci_rxdone_tasklet(unsigned long data)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
|
||||
rt2x00pci_rxdone(rt2x00dev);
|
||||
rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE);
|
||||
}
|
||||
|
||||
/*
|
||||
* 3 - Rx ring done interrupt.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE))
|
||||
rt2x00pci_rxdone(rt2x00dev);
|
||||
|
||||
/*
|
||||
* 4 - Auto wakeup interrupt.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
|
||||
rt2800pci_wakeup(rt2x00dev);
|
||||
|
||||
/* Enable interrupts again. */
|
||||
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
|
||||
STATE_RADIO_IRQ_ON_ISR);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
static void rt2800pci_autowake_tasklet(unsigned long data)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
|
||||
rt2800pci_wakeup(rt2x00dev);
|
||||
rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_AUTO_WAKEUP);
|
||||
}
|
||||
|
||||
static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
|
||||
@ -794,8 +854,8 @@ static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
|
||||
static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = dev_instance;
|
||||
u32 reg;
|
||||
irqreturn_t ret = IRQ_HANDLED;
|
||||
u32 reg, mask;
|
||||
unsigned long flags;
|
||||
|
||||
/* Read status and ACK all interrupts */
|
||||
rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, ®);
|
||||
@ -807,38 +867,44 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
|
||||
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
|
||||
/*
|
||||
* Since INT_MASK_CSR and INT_SOURCE_CSR use the same bits
|
||||
* for interrupts and interrupt masks we can just use the value of
|
||||
* INT_SOURCE_CSR to create the interrupt mask.
|
||||
*/
|
||||
mask = ~reg;
|
||||
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) {
|
||||
rt2800pci_txstatus_interrupt(rt2x00dev);
|
||||
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT) ||
|
||||
rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT) ||
|
||||
rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE) ||
|
||||
rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) {
|
||||
/*
|
||||
* All other interrupts are handled in the interrupt thread.
|
||||
* Store irqvalue for use in the interrupt thread.
|
||||
* Never disable the TX_FIFO_STATUS interrupt.
|
||||
*/
|
||||
rt2x00dev->irqvalue[0] = reg;
|
||||
|
||||
/*
|
||||
* Disable interrupts, will be enabled again in the
|
||||
* interrupt thread.
|
||||
*/
|
||||
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
|
||||
STATE_RADIO_IRQ_OFF_ISR);
|
||||
|
||||
/*
|
||||
* Leave the TX_FIFO_STATUS interrupt enabled to not lose any
|
||||
* tx status reports.
|
||||
*/
|
||||
rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_TX_FIFO_STATUS, 1);
|
||||
rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
|
||||
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
rt2x00_set_field32(&mask, INT_MASK_CSR_TX_FIFO_STATUS, 1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
|
||||
tasklet_hi_schedule(&rt2x00dev->pretbtt_tasklet);
|
||||
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT))
|
||||
tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet);
|
||||
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE))
|
||||
tasklet_schedule(&rt2x00dev->rxdone_tasklet);
|
||||
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
|
||||
tasklet_schedule(&rt2x00dev->autowake_tasklet);
|
||||
|
||||
/*
|
||||
* Disable all interrupts for which a tasklet was scheduled right now,
|
||||
* the tasklet will reenable the appropriate interrupts.
|
||||
*/
|
||||
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
|
||||
rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®);
|
||||
reg &= mask;
|
||||
rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
|
||||
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -953,8 +1019,11 @@ static const struct rt2800_ops rt2800pci_rt2800_ops = {
|
||||
|
||||
static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
|
||||
.irq_handler = rt2800pci_interrupt,
|
||||
.irq_handler_thread = rt2800pci_interrupt_thread,
|
||||
.txstatus_tasklet = rt2800pci_txstatus_tasklet,
|
||||
.txstatus_tasklet = rt2800pci_txstatus_tasklet,
|
||||
.pretbtt_tasklet = rt2800pci_pretbtt_tasklet,
|
||||
.tbtt_tasklet = rt2800pci_tbtt_tasklet,
|
||||
.rxdone_tasklet = rt2800pci_rxdone_tasklet,
|
||||
.autowake_tasklet = rt2800pci_autowake_tasklet,
|
||||
.probe_hw = rt2800pci_probe_hw,
|
||||
.get_firmware_name = rt2800pci_get_firmware_name,
|
||||
.check_firmware = rt2800_check_firmware,
|
||||
@ -974,6 +1043,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
|
||||
.write_tx_desc = rt2800pci_write_tx_desc,
|
||||
.write_tx_data = rt2800_write_tx_data,
|
||||
.write_beacon = rt2800_write_beacon,
|
||||
.clear_beacon = rt2800_clear_beacon,
|
||||
.fill_rxdone = rt2800pci_fill_rxdone,
|
||||
.config_shared_key = rt2800_config_shared_key,
|
||||
.config_pairwise_key = rt2800_config_pairwise_key,
|
||||
|
@ -253,9 +253,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
|
||||
rt2800usb_set_state(rt2x00dev, STATE_SLEEP);
|
||||
break;
|
||||
case STATE_RADIO_IRQ_ON:
|
||||
case STATE_RADIO_IRQ_ON_ISR:
|
||||
case STATE_RADIO_IRQ_OFF:
|
||||
case STATE_RADIO_IRQ_OFF_ISR:
|
||||
/* No support, but no error either */
|
||||
break;
|
||||
case STATE_DEEP_SLEEP:
|
||||
@ -486,6 +484,12 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
|
||||
*/
|
||||
rxdesc->flags |= RX_FLAG_IV_STRIPPED;
|
||||
|
||||
/*
|
||||
* The hardware has already checked the Michael Mic and has
|
||||
* stripped it from the frame. Signal this to mac80211.
|
||||
*/
|
||||
rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
|
||||
|
||||
if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
|
||||
rxdesc->flags |= RX_FLAG_DECRYPTED;
|
||||
else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
|
||||
@ -633,6 +637,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
|
||||
.write_tx_desc = rt2800usb_write_tx_desc,
|
||||
.write_tx_data = rt2800usb_write_tx_data,
|
||||
.write_beacon = rt2800_write_beacon,
|
||||
.clear_beacon = rt2800_clear_beacon,
|
||||
.get_tx_data_len = rt2800usb_get_tx_data_len,
|
||||
.fill_rxdone = rt2800usb_fill_rxdone,
|
||||
.config_shared_key = rt2800_config_shared_key,
|
||||
|
@ -368,6 +368,7 @@ struct rt2x00_intf {
|
||||
* dedicated beacon entry.
|
||||
*/
|
||||
struct queue_entry *beacon;
|
||||
bool enable_beacon;
|
||||
|
||||
/*
|
||||
* Actions that needed rescheduling.
|
||||
@ -510,15 +511,14 @@ struct rt2x00lib_ops {
|
||||
*/
|
||||
irq_handler_t irq_handler;
|
||||
|
||||
/*
|
||||
* Threaded Interrupt handlers.
|
||||
*/
|
||||
irq_handler_t irq_handler_thread;
|
||||
|
||||
/*
|
||||
* TX status tasklet handler.
|
||||
*/
|
||||
void (*txstatus_tasklet) (unsigned long data);
|
||||
void (*pretbtt_tasklet) (unsigned long data);
|
||||
void (*tbtt_tasklet) (unsigned long data);
|
||||
void (*rxdone_tasklet) (unsigned long data);
|
||||
void (*autowake_tasklet) (unsigned long data);
|
||||
|
||||
/*
|
||||
* Device init handlers.
|
||||
@ -573,6 +573,7 @@ struct rt2x00lib_ops {
|
||||
struct txentry_desc *txdesc);
|
||||
void (*write_beacon) (struct queue_entry *entry,
|
||||
struct txentry_desc *txdesc);
|
||||
void (*clear_beacon) (struct queue_entry *entry);
|
||||
int (*get_tx_data_len) (struct queue_entry *entry);
|
||||
|
||||
/*
|
||||
@ -788,10 +789,12 @@ struct rt2x00_dev {
|
||||
* - Open ap interface count.
|
||||
* - Open sta interface count.
|
||||
* - Association count.
|
||||
* - Beaconing enabled count.
|
||||
*/
|
||||
unsigned int intf_ap_count;
|
||||
unsigned int intf_sta_count;
|
||||
unsigned int intf_associated;
|
||||
unsigned int intf_beaconing;
|
||||
|
||||
/*
|
||||
* Link quality
|
||||
@ -857,6 +860,13 @@ struct rt2x00_dev {
|
||||
*/
|
||||
struct ieee80211_low_level_stats low_level_stats;
|
||||
|
||||
/**
|
||||
* Work queue for all work which should not be placed
|
||||
* on the mac80211 workqueue (because of dependencies
|
||||
* between various work structures).
|
||||
*/
|
||||
struct workqueue_struct *workqueue;
|
||||
|
||||
/*
|
||||
* Scheduled work.
|
||||
* NOTE: intf_work will use ieee80211_iterate_active_interfaces()
|
||||
@ -886,12 +896,6 @@ struct rt2x00_dev {
|
||||
*/
|
||||
const struct firmware *fw;
|
||||
|
||||
/*
|
||||
* Interrupt values, stored between interrupt service routine
|
||||
* and interrupt thread routine.
|
||||
*/
|
||||
u32 irqvalue[2];
|
||||
|
||||
/*
|
||||
* FIFO for storing tx status reports between isr and tasklet.
|
||||
*/
|
||||
@ -901,6 +905,15 @@ struct rt2x00_dev {
|
||||
* Tasklet for processing tx status reports (rt2800pci).
|
||||
*/
|
||||
struct tasklet_struct txstatus_tasklet;
|
||||
struct tasklet_struct pretbtt_tasklet;
|
||||
struct tasklet_struct tbtt_tasklet;
|
||||
struct tasklet_struct rxdone_tasklet;
|
||||
struct tasklet_struct autowake_tasklet;
|
||||
|
||||
/*
|
||||
* Protect the interrupt mask register.
|
||||
*/
|
||||
spinlock_t irqmask_lock;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -121,7 +121,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
|
||||
return;
|
||||
|
||||
if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags))
|
||||
rt2x00queue_update_beacon(rt2x00dev, vif, true);
|
||||
rt2x00queue_update_beacon(rt2x00dev, vif);
|
||||
}
|
||||
|
||||
static void rt2x00lib_intf_scheduled(struct work_struct *work)
|
||||
@ -174,7 +174,13 @@ static void rt2x00lib_beaconupdate_iter(void *data, u8 *mac,
|
||||
vif->type != NL80211_IFTYPE_WDS)
|
||||
return;
|
||||
|
||||
rt2x00queue_update_beacon(rt2x00dev, vif, true);
|
||||
/*
|
||||
* Update the beacon without locking. This is safe on PCI devices
|
||||
* as they only update the beacon periodically here. This should
|
||||
* never be called for USB devices.
|
||||
*/
|
||||
WARN_ON(rt2x00_is_usb(rt2x00dev));
|
||||
rt2x00queue_update_beacon_locked(rt2x00dev, vif);
|
||||
}
|
||||
|
||||
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
|
||||
@ -183,9 +189,9 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
|
||||
return;
|
||||
|
||||
/* send buffered bc/mc frames out for every bssid */
|
||||
ieee80211_iterate_active_interfaces(rt2x00dev->hw,
|
||||
rt2x00lib_bc_buffer_iter,
|
||||
rt2x00dev);
|
||||
ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
|
||||
rt2x00lib_bc_buffer_iter,
|
||||
rt2x00dev);
|
||||
/*
|
||||
* Devices with pre tbtt interrupt don't need to update the beacon
|
||||
* here as they will fetch the next beacon directly prior to
|
||||
@ -195,9 +201,9 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
|
||||
return;
|
||||
|
||||
/* fetch next beacon */
|
||||
ieee80211_iterate_active_interfaces(rt2x00dev->hw,
|
||||
rt2x00lib_beaconupdate_iter,
|
||||
rt2x00dev);
|
||||
ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
|
||||
rt2x00lib_beaconupdate_iter,
|
||||
rt2x00dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
|
||||
|
||||
@ -207,9 +213,9 @@ void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev)
|
||||
return;
|
||||
|
||||
/* fetch next beacon */
|
||||
ieee80211_iterate_active_interfaces(rt2x00dev->hw,
|
||||
rt2x00lib_beaconupdate_iter,
|
||||
rt2x00dev);
|
||||
ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
|
||||
rt2x00lib_beaconupdate_iter,
|
||||
rt2x00dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);
|
||||
|
||||
@ -815,15 +821,29 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
|
||||
GFP_KERNEL);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* tasklet for processing the tx status reports. */
|
||||
if (rt2x00dev->ops->lib->txstatus_tasklet)
|
||||
tasklet_init(&rt2x00dev->txstatus_tasklet,
|
||||
rt2x00dev->ops->lib->txstatus_tasklet,
|
||||
(unsigned long)rt2x00dev);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize tasklets if used by the driver. Tasklets are
|
||||
* disabled until the interrupts are turned on. The driver
|
||||
* has to handle that.
|
||||
*/
|
||||
#define RT2X00_TASKLET_INIT(taskletname) \
|
||||
if (rt2x00dev->ops->lib->taskletname) { \
|
||||
tasklet_init(&rt2x00dev->taskletname, \
|
||||
rt2x00dev->ops->lib->taskletname, \
|
||||
(unsigned long)rt2x00dev); \
|
||||
tasklet_disable(&rt2x00dev->taskletname); \
|
||||
}
|
||||
|
||||
RT2X00_TASKLET_INIT(txstatus_tasklet);
|
||||
RT2X00_TASKLET_INIT(pretbtt_tasklet);
|
||||
RT2X00_TASKLET_INIT(tbtt_tasklet);
|
||||
RT2X00_TASKLET_INIT(rxdone_tasklet);
|
||||
RT2X00_TASKLET_INIT(autowake_tasklet);
|
||||
|
||||
#undef RT2X00_TASKLET_INIT
|
||||
|
||||
/*
|
||||
* Register HW.
|
||||
*/
|
||||
@ -952,6 +972,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
int retval = -ENOMEM;
|
||||
|
||||
spin_lock_init(&rt2x00dev->irqmask_lock);
|
||||
mutex_init(&rt2x00dev->csr_mutex);
|
||||
|
||||
set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
|
||||
@ -976,8 +997,15 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
||||
BIT(NL80211_IFTYPE_WDS);
|
||||
|
||||
/*
|
||||
* Initialize configuration work.
|
||||
* Initialize work.
|
||||
*/
|
||||
rt2x00dev->workqueue =
|
||||
alloc_ordered_workqueue(wiphy_name(rt2x00dev->hw->wiphy), 0);
|
||||
if (!rt2x00dev->workqueue) {
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
|
||||
|
||||
/*
|
||||
@ -1036,6 +1064,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
|
||||
cancel_work_sync(&rt2x00dev->intf_work);
|
||||
cancel_work_sync(&rt2x00dev->rxdone_work);
|
||||
cancel_work_sync(&rt2x00dev->txdone_work);
|
||||
destroy_workqueue(rt2x00dev->workqueue);
|
||||
|
||||
/*
|
||||
* Free the tx status fifo.
|
||||
@ -1046,6 +1075,10 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
|
||||
* Kill the tx status tasklet.
|
||||
*/
|
||||
tasklet_kill(&rt2x00dev->txstatus_tasklet);
|
||||
tasklet_kill(&rt2x00dev->pretbtt_tasklet);
|
||||
tasklet_kill(&rt2x00dev->tbtt_tasklet);
|
||||
tasklet_kill(&rt2x00dev->rxdone_tasklet);
|
||||
tasklet_kill(&rt2x00dev->autowake_tasklet);
|
||||
|
||||
/*
|
||||
* Uninitialize device.
|
||||
|
@ -157,14 +157,30 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
|
||||
bool local);
|
||||
|
||||
/**
|
||||
* rt2x00queue_update_beacon - Send new beacon from mac80211 to hardware
|
||||
* rt2x00queue_update_beacon - Send new beacon from mac80211
|
||||
* to hardware. Handles locking by itself (mutex).
|
||||
* @rt2x00dev: Pointer to &struct rt2x00_dev.
|
||||
* @vif: Interface for which the beacon should be updated.
|
||||
* @enable_beacon: Enable beaconing
|
||||
*/
|
||||
int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
|
||||
struct ieee80211_vif *vif,
|
||||
const bool enable_beacon);
|
||||
struct ieee80211_vif *vif);
|
||||
|
||||
/**
|
||||
* rt2x00queue_update_beacon_locked - Send new beacon from mac80211
|
||||
* to hardware. Caller needs to ensure locking.
|
||||
* @rt2x00dev: Pointer to &struct rt2x00_dev.
|
||||
* @vif: Interface for which the beacon should be updated.
|
||||
*/
|
||||
int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev,
|
||||
struct ieee80211_vif *vif);
|
||||
|
||||
/**
|
||||
* rt2x00queue_clear_beacon - Clear beacon in hardware
|
||||
* @rt2x00dev: Pointer to &struct rt2x00_dev.
|
||||
* @vif: Interface for which the beacon should be updated.
|
||||
*/
|
||||
int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev,
|
||||
struct ieee80211_vif *vif);
|
||||
|
||||
/**
|
||||
* rt2x00queue_index_inc - Index incrementation function
|
||||
|
@ -417,7 +417,8 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev)
|
||||
!test_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags))
|
||||
return;
|
||||
|
||||
schedule_delayed_work(&link->watchdog_work, WATCHDOG_INTERVAL);
|
||||
ieee80211_queue_delayed_work(rt2x00dev->hw,
|
||||
&link->watchdog_work, WATCHDOG_INTERVAL);
|
||||
}
|
||||
|
||||
void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev)
|
||||
@ -441,7 +442,9 @@ static void rt2x00link_watchdog(struct work_struct *work)
|
||||
rt2x00dev->ops->lib->watchdog(rt2x00dev);
|
||||
|
||||
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
|
||||
schedule_delayed_work(&link->watchdog_work, WATCHDOG_INTERVAL);
|
||||
ieee80211_queue_delayed_work(rt2x00dev->hw,
|
||||
&link->watchdog_work,
|
||||
WATCHDOG_INTERVAL);
|
||||
}
|
||||
|
||||
void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
|
||||
|
@ -617,11 +617,47 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
|
||||
bss_conf->bssid);
|
||||
|
||||
/*
|
||||
* Update the beacon.
|
||||
* Update the beacon. This is only required on USB devices. PCI
|
||||
* devices fetch beacons periodically.
|
||||
*/
|
||||
if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED))
|
||||
rt2x00queue_update_beacon(rt2x00dev, vif,
|
||||
bss_conf->enable_beacon);
|
||||
if (changes & BSS_CHANGED_BEACON && rt2x00_is_usb(rt2x00dev))
|
||||
rt2x00queue_update_beacon(rt2x00dev, vif);
|
||||
|
||||
/*
|
||||
* Start/stop beaconing.
|
||||
*/
|
||||
if (changes & BSS_CHANGED_BEACON_ENABLED) {
|
||||
if (!bss_conf->enable_beacon && intf->enable_beacon) {
|
||||
rt2x00queue_clear_beacon(rt2x00dev, vif);
|
||||
rt2x00dev->intf_beaconing--;
|
||||
intf->enable_beacon = false;
|
||||
|
||||
if (rt2x00dev->intf_beaconing == 0) {
|
||||
/*
|
||||
* Last beaconing interface disabled
|
||||
* -> stop beacon queue.
|
||||
*/
|
||||
mutex_lock(&intf->beacon_skb_mutex);
|
||||
rt2x00queue_stop_queue(rt2x00dev->bcn);
|
||||
mutex_unlock(&intf->beacon_skb_mutex);
|
||||
}
|
||||
|
||||
|
||||
} else if (bss_conf->enable_beacon && !intf->enable_beacon) {
|
||||
rt2x00dev->intf_beaconing++;
|
||||
intf->enable_beacon = true;
|
||||
|
||||
if (rt2x00dev->intf_beaconing == 1) {
|
||||
/*
|
||||
* First beaconing interface enabled
|
||||
* -> start beacon queue.
|
||||
*/
|
||||
mutex_lock(&intf->beacon_skb_mutex);
|
||||
rt2x00queue_start_queue(rt2x00dev->bcn);
|
||||
mutex_unlock(&intf->beacon_skb_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When the association status has changed we must reset the link
|
||||
|
@ -160,10 +160,9 @@ int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
|
||||
/*
|
||||
* Register interrupt handler.
|
||||
*/
|
||||
status = request_threaded_irq(rt2x00dev->irq,
|
||||
rt2x00dev->ops->lib->irq_handler,
|
||||
rt2x00dev->ops->lib->irq_handler_thread,
|
||||
IRQF_SHARED, rt2x00dev->name, rt2x00dev);
|
||||
status = request_irq(rt2x00dev->irq,
|
||||
rt2x00dev->ops->lib->irq_handler,
|
||||
IRQF_SHARED, rt2x00dev->name, rt2x00dev);
|
||||
if (status) {
|
||||
ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
|
||||
rt2x00dev->irq, status);
|
||||
|
@ -566,13 +566,10 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
|
||||
struct ieee80211_vif *vif,
|
||||
const bool enable_beacon)
|
||||
int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct rt2x00_intf *intf = vif_to_intf(vif);
|
||||
struct skb_frame_desc *skbdesc;
|
||||
struct txentry_desc txdesc;
|
||||
|
||||
if (unlikely(!intf->beacon))
|
||||
return -ENOBUFS;
|
||||
@ -584,17 +581,36 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
|
||||
*/
|
||||
rt2x00queue_free_skb(intf->beacon);
|
||||
|
||||
if (!enable_beacon) {
|
||||
rt2x00queue_stop_queue(intf->beacon->queue);
|
||||
mutex_unlock(&intf->beacon_skb_mutex);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Clear beacon (single bssid devices don't need to clear the beacon
|
||||
* since the beacon queue will get stopped anyway).
|
||||
*/
|
||||
if (rt2x00dev->ops->lib->clear_beacon)
|
||||
rt2x00dev->ops->lib->clear_beacon(intf->beacon);
|
||||
|
||||
mutex_unlock(&intf->beacon_skb_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct rt2x00_intf *intf = vif_to_intf(vif);
|
||||
struct skb_frame_desc *skbdesc;
|
||||
struct txentry_desc txdesc;
|
||||
|
||||
if (unlikely(!intf->beacon))
|
||||
return -ENOBUFS;
|
||||
|
||||
/*
|
||||
* Clean up the beacon skb.
|
||||
*/
|
||||
rt2x00queue_free_skb(intf->beacon);
|
||||
|
||||
intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
|
||||
if (!intf->beacon->skb) {
|
||||
mutex_unlock(&intf->beacon_skb_mutex);
|
||||
if (!intf->beacon->skb)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy all TX descriptor information into txdesc,
|
||||
@ -611,13 +627,25 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
|
||||
skbdesc->entry = intf->beacon;
|
||||
|
||||
/*
|
||||
* Send beacon to hardware and enable beacon genaration..
|
||||
* Send beacon to hardware.
|
||||
*/
|
||||
rt2x00dev->ops->lib->write_beacon(intf->beacon, &txdesc);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct rt2x00_intf *intf = vif_to_intf(vif);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&intf->beacon_skb_mutex);
|
||||
ret = rt2x00queue_update_beacon_locked(rt2x00dev, vif);
|
||||
mutex_unlock(&intf->beacon_skb_mutex);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rt2x00queue_for_each_entry(struct data_queue *queue,
|
||||
@ -885,7 +913,7 @@ void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
|
||||
* The queue flush has failed...
|
||||
*/
|
||||
if (unlikely(!rt2x00queue_empty(queue)))
|
||||
WARNING(queue->rt2x00dev, "Queue %d failed to flush", queue->qid);
|
||||
WARNING(queue->rt2x00dev, "Queue %d failed to flush\n", queue->qid);
|
||||
|
||||
/*
|
||||
* Restore the queue to the previous status
|
||||
|
@ -85,8 +85,6 @@ enum dev_state {
|
||||
STATE_RADIO_OFF,
|
||||
STATE_RADIO_IRQ_ON,
|
||||
STATE_RADIO_IRQ_OFF,
|
||||
STATE_RADIO_IRQ_ON_ISR,
|
||||
STATE_RADIO_IRQ_OFF_ISR,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -227,7 +227,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
|
||||
* Schedule the delayed work for reading the TX status
|
||||
* from the device.
|
||||
*/
|
||||
ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work);
|
||||
queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
|
||||
}
|
||||
|
||||
static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
|
||||
@ -320,7 +320,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
|
||||
* Schedule the delayed work for reading the RX status
|
||||
* from the device.
|
||||
*/
|
||||
ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work);
|
||||
queue_work(rt2x00dev->workqueue, &rt2x00dev->rxdone_work);
|
||||
}
|
||||
|
||||
static void rt2x00usb_kick_rx_entry(struct queue_entry *entry)
|
||||
@ -429,7 +429,7 @@ void rt2x00usb_flush_queue(struct data_queue *queue)
|
||||
* Schedule the completion handler manually, when this
|
||||
* worker function runs, it should cleanup the queue.
|
||||
*/
|
||||
ieee80211_queue_work(queue->rt2x00dev->hw, completion);
|
||||
queue_work(queue->rt2x00dev->workqueue, completion);
|
||||
|
||||
/*
|
||||
* Wait for a little while to give the driver
|
||||
@ -453,7 +453,7 @@ static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)
|
||||
WARNING(queue->rt2x00dev, "TX queue %d status timed out,"
|
||||
" invoke forced tx handler\n", queue->qid);
|
||||
|
||||
ieee80211_queue_work(queue->rt2x00dev->hw, &queue->rt2x00dev->txdone_work);
|
||||
queue_work(queue->rt2x00dev->workqueue, &queue->rt2x00dev->txdone_work);
|
||||
}
|
||||
|
||||
void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
|
||||
|
@ -551,26 +551,14 @@ static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev,
|
||||
struct rt2x00intf_conf *conf,
|
||||
const unsigned int flags)
|
||||
{
|
||||
unsigned int beacon_base;
|
||||
u32 reg;
|
||||
|
||||
if (flags & CONFIG_UPDATE_TYPE) {
|
||||
/*
|
||||
* Clear current synchronisation setup.
|
||||
* For the Beacon base registers, we only need to clear
|
||||
* the first byte since that byte contains the VALID and OWNER
|
||||
* bits which (when set to 0) will invalidate the entire beacon.
|
||||
*/
|
||||
beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
|
||||
rt2x00pci_register_write(rt2x00dev, beacon_base, 0);
|
||||
|
||||
/*
|
||||
* Enable synchronisation.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1);
|
||||
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
|
||||
}
|
||||
|
||||
@ -1154,6 +1142,11 @@ static void rt61pci_start_queue(struct data_queue *queue)
|
||||
rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
|
||||
break;
|
||||
case QID_BEACON:
|
||||
/*
|
||||
* Allow the tbtt tasklet to be scheduled.
|
||||
*/
|
||||
tasklet_enable(&rt2x00dev->tbtt_tasklet);
|
||||
|
||||
rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1);
|
||||
@ -1233,6 +1226,11 @@ static void rt61pci_stop_queue(struct data_queue *queue)
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
|
||||
|
||||
/*
|
||||
* Wait for possibly running tbtt tasklets.
|
||||
*/
|
||||
tasklet_disable(&rt2x00dev->tbtt_tasklet);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -1719,9 +1717,9 @@ static int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev)
|
||||
static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
|
||||
enum dev_state state)
|
||||
{
|
||||
int mask = (state == STATE_RADIO_IRQ_OFF) ||
|
||||
(state == STATE_RADIO_IRQ_OFF_ISR);
|
||||
int mask = (state == STATE_RADIO_IRQ_OFF);
|
||||
u32 reg;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* When interrupts are being enabled, the interrupt registers
|
||||
@ -1733,12 +1731,21 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
|
||||
|
||||
rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®);
|
||||
rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg);
|
||||
|
||||
/*
|
||||
* Enable tasklets.
|
||||
*/
|
||||
tasklet_enable(&rt2x00dev->txstatus_tasklet);
|
||||
tasklet_enable(&rt2x00dev->rxdone_tasklet);
|
||||
tasklet_enable(&rt2x00dev->autowake_tasklet);
|
||||
}
|
||||
|
||||
/*
|
||||
* Only toggle the interrupts bits we are going to use.
|
||||
* Non-checked interrupt bits are disabled by default.
|
||||
*/
|
||||
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_TXDONE, mask);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_RXDONE, mask);
|
||||
@ -1758,6 +1765,17 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
|
||||
rt2x00_set_field32(®, MCU_INT_MASK_CSR_7, mask);
|
||||
rt2x00_set_field32(®, MCU_INT_MASK_CSR_TWAKEUP, mask);
|
||||
rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
|
||||
|
||||
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
if (state == STATE_RADIO_IRQ_OFF) {
|
||||
/*
|
||||
* Ensure that all tasklets are finished.
|
||||
*/
|
||||
tasklet_disable(&rt2x00dev->txstatus_tasklet);
|
||||
tasklet_disable(&rt2x00dev->rxdone_tasklet);
|
||||
tasklet_disable(&rt2x00dev->autowake_tasklet);
|
||||
}
|
||||
}
|
||||
|
||||
static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev)
|
||||
@ -1833,9 +1851,7 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
|
||||
rt61pci_disable_radio(rt2x00dev);
|
||||
break;
|
||||
case STATE_RADIO_IRQ_ON:
|
||||
case STATE_RADIO_IRQ_ON_ISR:
|
||||
case STATE_RADIO_IRQ_OFF:
|
||||
case STATE_RADIO_IRQ_OFF_ISR:
|
||||
rt61pci_toggle_irq(rt2x00dev, state);
|
||||
break;
|
||||
case STATE_DEEP_SLEEP:
|
||||
@ -2002,8 +2018,6 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
|
||||
*/
|
||||
rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
|
||||
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1);
|
||||
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
|
||||
|
||||
@ -2014,6 +2028,32 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
|
||||
entry->skb = NULL;
|
||||
}
|
||||
|
||||
static void rt61pci_clear_beacon(struct queue_entry *entry)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Disable beaconing while we are reloading the beacon data,
|
||||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
|
||||
|
||||
/*
|
||||
* Clear beacon.
|
||||
*/
|
||||
rt2x00pci_register_write(rt2x00dev,
|
||||
HW_BEACON_OFFSET(entry->entry_idx), 0);
|
||||
|
||||
/*
|
||||
* Enable beaconing again.
|
||||
*/
|
||||
rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1);
|
||||
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* RX control handlers
|
||||
*/
|
||||
@ -2078,9 +2118,8 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry,
|
||||
rxdesc->flags |= RX_FLAG_IV_STRIPPED;
|
||||
|
||||
/*
|
||||
* FIXME: Legacy driver indicates that the frame does
|
||||
* contain the Michael Mic. Unfortunately, in rt2x00
|
||||
* the MIC seems to be missing completely...
|
||||
* The hardware has already checked the Michael Mic and has
|
||||
* stripped it from the frame. Signal this to mac80211.
|
||||
*/
|
||||
rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
|
||||
|
||||
@ -2211,61 +2250,80 @@ static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev)
|
||||
rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
|
||||
}
|
||||
|
||||
static irqreturn_t rt61pci_interrupt_thread(int irq, void *dev_instance)
|
||||
static void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
|
||||
struct rt2x00_field32 irq_field)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = dev_instance;
|
||||
u32 reg = rt2x00dev->irqvalue[0];
|
||||
u32 reg_mcu = rt2x00dev->irqvalue[1];
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Handle interrupts, walk through all bits
|
||||
* and run the tasks, the bits are checked in order of
|
||||
* priority.
|
||||
* Enable a single interrupt. The interrupt mask register
|
||||
* access needs locking.
|
||||
*/
|
||||
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
/*
|
||||
* 1 - Rx ring done interrupt.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE))
|
||||
rt2x00pci_rxdone(rt2x00dev);
|
||||
rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®);
|
||||
rt2x00_set_field32(®, irq_field, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
|
||||
|
||||
/*
|
||||
* 2 - Tx ring done interrupt.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TXDONE))
|
||||
rt61pci_txdone(rt2x00dev);
|
||||
|
||||
/*
|
||||
* 3 - Handle MCU command done.
|
||||
*/
|
||||
if (reg_mcu)
|
||||
rt2x00pci_register_write(rt2x00dev,
|
||||
M2H_CMD_DONE_CSR, 0xffffffff);
|
||||
|
||||
/*
|
||||
* 4 - MCU Autowakeup interrupt.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP))
|
||||
rt61pci_wakeup(rt2x00dev);
|
||||
|
||||
/*
|
||||
* 5 - Beacon done interrupt.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE))
|
||||
rt2x00lib_beacondone(rt2x00dev);
|
||||
|
||||
/* Enable interrupts again. */
|
||||
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
|
||||
STATE_RADIO_IRQ_ON_ISR);
|
||||
return IRQ_HANDLED;
|
||||
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
|
||||
}
|
||||
|
||||
static void rt61pci_enable_mcu_interrupt(struct rt2x00_dev *rt2x00dev,
|
||||
struct rt2x00_field32 irq_field)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Enable a single MCU interrupt. The interrupt mask register
|
||||
* access needs locking.
|
||||
*/
|
||||
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®);
|
||||
rt2x00_set_field32(®, irq_field, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
|
||||
|
||||
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
|
||||
}
|
||||
|
||||
static void rt61pci_txstatus_tasklet(unsigned long data)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
|
||||
rt61pci_txdone(rt2x00dev);
|
||||
rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TXDONE);
|
||||
}
|
||||
|
||||
static void rt61pci_tbtt_tasklet(unsigned long data)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
|
||||
rt2x00lib_beacondone(rt2x00dev);
|
||||
rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_BEACON_DONE);
|
||||
}
|
||||
|
||||
static void rt61pci_rxdone_tasklet(unsigned long data)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
|
||||
rt2x00pci_rxdone(rt2x00dev);
|
||||
rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE);
|
||||
}
|
||||
|
||||
static void rt61pci_autowake_tasklet(unsigned long data)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
|
||||
rt61pci_wakeup(rt2x00dev);
|
||||
rt2x00pci_register_write(rt2x00dev,
|
||||
M2H_CMD_DONE_CSR, 0xffffffff);
|
||||
rt61pci_enable_mcu_interrupt(rt2x00dev, MCU_INT_MASK_CSR_TWAKEUP);
|
||||
}
|
||||
|
||||
static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = dev_instance;
|
||||
u32 reg_mcu;
|
||||
u32 reg;
|
||||
u32 reg_mcu, mask_mcu;
|
||||
u32 reg, mask;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Get the interrupt sources & saved to local variable.
|
||||
@ -2283,14 +2341,46 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
|
||||
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/* Store irqvalues for use in the interrupt thread. */
|
||||
rt2x00dev->irqvalue[0] = reg;
|
||||
rt2x00dev->irqvalue[1] = reg_mcu;
|
||||
/*
|
||||
* Schedule tasklets for interrupt handling.
|
||||
*/
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE))
|
||||
tasklet_schedule(&rt2x00dev->rxdone_tasklet);
|
||||
|
||||
/* Disable interrupts, will be enabled again in the interrupt thread. */
|
||||
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
|
||||
STATE_RADIO_IRQ_OFF_ISR);
|
||||
return IRQ_WAKE_THREAD;
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TXDONE))
|
||||
tasklet_schedule(&rt2x00dev->txstatus_tasklet);
|
||||
|
||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE))
|
||||
tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet);
|
||||
|
||||
if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP))
|
||||
tasklet_schedule(&rt2x00dev->autowake_tasklet);
|
||||
|
||||
/*
|
||||
* Since INT_MASK_CSR and INT_SOURCE_CSR use the same bits
|
||||
* for interrupts and interrupt masks we can just use the value of
|
||||
* INT_SOURCE_CSR to create the interrupt mask.
|
||||
*/
|
||||
mask = reg;
|
||||
mask_mcu = reg_mcu;
|
||||
|
||||
/*
|
||||
* Disable all interrupts for which a tasklet was scheduled right now,
|
||||
* the tasklet will reenable the appropriate interrupts.
|
||||
*/
|
||||
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®);
|
||||
reg |= mask;
|
||||
rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
|
||||
|
||||
rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®);
|
||||
reg |= mask_mcu;
|
||||
rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
|
||||
|
||||
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2884,7 +2974,10 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
|
||||
|
||||
static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
|
||||
.irq_handler = rt61pci_interrupt,
|
||||
.irq_handler_thread = rt61pci_interrupt_thread,
|
||||
.txstatus_tasklet = rt61pci_txstatus_tasklet,
|
||||
.tbtt_tasklet = rt61pci_tbtt_tasklet,
|
||||
.rxdone_tasklet = rt61pci_rxdone_tasklet,
|
||||
.autowake_tasklet = rt61pci_autowake_tasklet,
|
||||
.probe_hw = rt61pci_probe_hw,
|
||||
.get_firmware_name = rt61pci_get_firmware_name,
|
||||
.check_firmware = rt61pci_check_firmware,
|
||||
@ -2903,6 +2996,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
|
||||
.stop_queue = rt61pci_stop_queue,
|
||||
.write_tx_desc = rt61pci_write_tx_desc,
|
||||
.write_beacon = rt61pci_write_beacon,
|
||||
.clear_beacon = rt61pci_clear_beacon,
|
||||
.fill_rxdone = rt61pci_fill_rxdone,
|
||||
.config_shared_key = rt61pci_config_shared_key,
|
||||
.config_pairwise_key = rt61pci_config_pairwise_key,
|
||||
|
@ -502,26 +502,14 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
|
||||
struct rt2x00intf_conf *conf,
|
||||
const unsigned int flags)
|
||||
{
|
||||
unsigned int beacon_base;
|
||||
u32 reg;
|
||||
|
||||
if (flags & CONFIG_UPDATE_TYPE) {
|
||||
/*
|
||||
* Clear current synchronisation setup.
|
||||
* For the Beacon base registers we only need to clear
|
||||
* the first byte since that byte contains the VALID and OWNER
|
||||
* bits which (when set to 0) will invalidate the entire beacon.
|
||||
*/
|
||||
beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
|
||||
rt2x00usb_register_write(rt2x00dev, beacon_base, 0);
|
||||
|
||||
/*
|
||||
* Enable synchronisation.
|
||||
*/
|
||||
rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1);
|
||||
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
|
||||
}
|
||||
|
||||
@ -1440,9 +1428,7 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
|
||||
rt73usb_disable_radio(rt2x00dev);
|
||||
break;
|
||||
case STATE_RADIO_IRQ_ON:
|
||||
case STATE_RADIO_IRQ_ON_ISR:
|
||||
case STATE_RADIO_IRQ_OFF:
|
||||
case STATE_RADIO_IRQ_OFF_ISR:
|
||||
/* No support, but no error either */
|
||||
break;
|
||||
case STATE_DEEP_SLEEP:
|
||||
@ -1590,8 +1576,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
|
||||
*/
|
||||
rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
|
||||
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1);
|
||||
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
|
||||
|
||||
@ -1602,6 +1586,33 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
|
||||
entry->skb = NULL;
|
||||
}
|
||||
|
||||
static void rt73usb_clear_beacon(struct queue_entry *entry)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
unsigned int beacon_base;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Disable beaconing while we are reloading the beacon data,
|
||||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
|
||||
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
|
||||
|
||||
/*
|
||||
* Clear beacon.
|
||||
*/
|
||||
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
|
||||
rt2x00usb_register_write(rt2x00dev, beacon_base, 0);
|
||||
|
||||
/*
|
||||
* Enable beaconing again.
|
||||
*/
|
||||
rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1);
|
||||
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
|
||||
}
|
||||
|
||||
static int rt73usb_get_tx_data_len(struct queue_entry *entry)
|
||||
{
|
||||
int length;
|
||||
@ -1698,9 +1709,8 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
|
||||
rxdesc->flags |= RX_FLAG_IV_STRIPPED;
|
||||
|
||||
/*
|
||||
* FIXME: Legacy driver indicates that the frame does
|
||||
* contain the Michael Mic. Unfortunately, in rt2x00
|
||||
* the MIC seems to be missing completely...
|
||||
* The hardware has already checked the Michael Mic and has
|
||||
* stripped it from the frame. Signal this to mac80211.
|
||||
*/
|
||||
rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
|
||||
|
||||
@ -2313,6 +2323,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
|
||||
.flush_queue = rt2x00usb_flush_queue,
|
||||
.write_tx_desc = rt73usb_write_tx_desc,
|
||||
.write_beacon = rt73usb_write_beacon,
|
||||
.clear_beacon = rt73usb_clear_beacon,
|
||||
.get_tx_data_len = rt73usb_get_tx_data_len,
|
||||
.fill_rxdone = rt73usb_fill_rxdone,
|
||||
.config_shared_key = rt73usb_config_shared_key,
|
||||
|
@ -726,9 +726,9 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data)
|
||||
}
|
||||
|
||||
static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
|
||||
u8 efuse_data, u8 offset, int *bcontinual,
|
||||
u8 *write_state, struct pgpkt_struct target_pkt,
|
||||
int *repeat_times, int *bresult, u8 word_en)
|
||||
u8 efuse_data, u8 offset, int *bcontinual,
|
||||
u8 *write_state, struct pgpkt_struct *target_pkt,
|
||||
int *repeat_times, int *bresult, u8 word_en)
|
||||
{
|
||||
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
||||
struct pgpkt_struct tmp_pkt;
|
||||
@ -744,8 +744,8 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
|
||||
tmp_pkt.word_en = tmp_header & 0x0F;
|
||||
tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en);
|
||||
|
||||
if (tmp_pkt.offset != target_pkt.offset) {
|
||||
efuse_addr = efuse_addr + (tmp_word_cnts * 2) + 1;
|
||||
if (tmp_pkt.offset != target_pkt->offset) {
|
||||
*efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;
|
||||
*write_state = PG_STATE_HEADER;
|
||||
} else {
|
||||
for (tmpindex = 0; tmpindex < (tmp_word_cnts * 2); tmpindex++) {
|
||||
@ -756,23 +756,23 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
|
||||
}
|
||||
|
||||
if (bdataempty == false) {
|
||||
efuse_addr = efuse_addr + (tmp_word_cnts * 2) + 1;
|
||||
*efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;
|
||||
*write_state = PG_STATE_HEADER;
|
||||
} else {
|
||||
match_word_en = 0x0F;
|
||||
if (!((target_pkt.word_en & BIT(0)) |
|
||||
if (!((target_pkt->word_en & BIT(0)) |
|
||||
(tmp_pkt.word_en & BIT(0))))
|
||||
match_word_en &= (~BIT(0));
|
||||
|
||||
if (!((target_pkt.word_en & BIT(1)) |
|
||||
if (!((target_pkt->word_en & BIT(1)) |
|
||||
(tmp_pkt.word_en & BIT(1))))
|
||||
match_word_en &= (~BIT(1));
|
||||
|
||||
if (!((target_pkt.word_en & BIT(2)) |
|
||||
if (!((target_pkt->word_en & BIT(2)) |
|
||||
(tmp_pkt.word_en & BIT(2))))
|
||||
match_word_en &= (~BIT(2));
|
||||
|
||||
if (!((target_pkt.word_en & BIT(3)) |
|
||||
if (!((target_pkt->word_en & BIT(3)) |
|
||||
(tmp_pkt.word_en & BIT(3))))
|
||||
match_word_en &= (~BIT(3));
|
||||
|
||||
@ -780,7 +780,7 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
|
||||
badworden = efuse_word_enable_data_write(
|
||||
hw, *efuse_addr + 1,
|
||||
tmp_pkt.word_en,
|
||||
target_pkt.data);
|
||||
target_pkt->data);
|
||||
|
||||
if (0x0F != (badworden & 0x0F)) {
|
||||
u8 reorg_offset = offset;
|
||||
@ -791,26 +791,26 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
|
||||
}
|
||||
|
||||
tmp_word_en = 0x0F;
|
||||
if ((target_pkt.word_en & BIT(0)) ^
|
||||
if ((target_pkt->word_en & BIT(0)) ^
|
||||
(match_word_en & BIT(0)))
|
||||
tmp_word_en &= (~BIT(0));
|
||||
|
||||
if ((target_pkt.word_en & BIT(1)) ^
|
||||
if ((target_pkt->word_en & BIT(1)) ^
|
||||
(match_word_en & BIT(1)))
|
||||
tmp_word_en &= (~BIT(1));
|
||||
|
||||
if ((target_pkt.word_en & BIT(2)) ^
|
||||
if ((target_pkt->word_en & BIT(2)) ^
|
||||
(match_word_en & BIT(2)))
|
||||
tmp_word_en &= (~BIT(2));
|
||||
|
||||
if ((target_pkt.word_en & BIT(3)) ^
|
||||
if ((target_pkt->word_en & BIT(3)) ^
|
||||
(match_word_en & BIT(3)))
|
||||
tmp_word_en &= (~BIT(3));
|
||||
|
||||
if ((tmp_word_en & 0x0F) != 0x0F) {
|
||||
*efuse_addr = efuse_get_current_size(hw);
|
||||
target_pkt.offset = offset;
|
||||
target_pkt.word_en = tmp_word_en;
|
||||
target_pkt->offset = offset;
|
||||
target_pkt->word_en = tmp_word_en;
|
||||
} else
|
||||
*bcontinual = false;
|
||||
*write_state = PG_STATE_HEADER;
|
||||
@ -821,8 +821,8 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
|
||||
}
|
||||
} else {
|
||||
*efuse_addr += (2 * tmp_word_cnts) + 1;
|
||||
target_pkt.offset = offset;
|
||||
target_pkt.word_en = word_en;
|
||||
target_pkt->offset = offset;
|
||||
target_pkt->word_en = word_en;
|
||||
*write_state = PG_STATE_HEADER;
|
||||
}
|
||||
}
|
||||
@ -938,7 +938,7 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
|
||||
efuse_write_data_case1(hw, &efuse_addr,
|
||||
efuse_data, offset,
|
||||
&bcontinual,
|
||||
&write_state, target_pkt,
|
||||
&write_state, &target_pkt,
|
||||
&repeat_times, &bresult,
|
||||
word_en);
|
||||
else
|
||||
|
@ -751,10 +751,10 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wl1271_acx_rate_policies(struct wl1271 *wl)
|
||||
int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
|
||||
{
|
||||
struct acx_rate_policy *acx;
|
||||
struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf;
|
||||
struct acx_sta_rate_policy *acx;
|
||||
struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf;
|
||||
int idx = 0;
|
||||
int ret = 0;
|
||||
|
||||
@ -794,6 +794,38 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
|
||||
u8 idx)
|
||||
{
|
||||
struct acx_ap_rate_policy *acx;
|
||||
int ret = 0;
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "acx ap rate policy");
|
||||
|
||||
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
|
||||
if (!acx) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->rate_policy.enabled_rates = cpu_to_le32(c->enabled_rates);
|
||||
acx->rate_policy.short_retry_limit = c->short_retry_limit;
|
||||
acx->rate_policy.long_retry_limit = c->long_retry_limit;
|
||||
acx->rate_policy.aflags = c->aflags;
|
||||
|
||||
acx->rate_policy_idx = cpu_to_le32(idx);
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
|
||||
if (ret < 0) {
|
||||
wl1271_warning("Setting of ap rate policy failed: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
|
||||
u8 aifsn, u16 txop)
|
||||
{
|
||||
@ -1233,6 +1265,7 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
|
||||
struct wl1271_acx_ht_capabilities *acx;
|
||||
u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
int ret = 0;
|
||||
u32 ht_capabilites = 0;
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "acx ht capabilities setting");
|
||||
|
||||
@ -1244,16 +1277,16 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
|
||||
|
||||
/* Allow HT Operation ? */
|
||||
if (allow_ht_operation) {
|
||||
acx->ht_capabilites =
|
||||
ht_capabilites =
|
||||
WL1271_ACX_FW_CAP_HT_OPERATION;
|
||||
if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD)
|
||||
acx->ht_capabilites |=
|
||||
ht_capabilites |=
|
||||
WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT;
|
||||
if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
|
||||
acx->ht_capabilites |=
|
||||
ht_capabilites |=
|
||||
WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS;
|
||||
if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT)
|
||||
acx->ht_capabilites |=
|
||||
ht_capabilites |=
|
||||
WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION;
|
||||
|
||||
/* get data from A-MPDU parameters field */
|
||||
@ -1261,10 +1294,10 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
|
||||
acx->ampdu_min_spacing = ht_cap->ampdu_density;
|
||||
|
||||
memcpy(acx->mac_address, mac_address, ETH_ALEN);
|
||||
} else { /* HT operations are not allowed */
|
||||
acx->ht_capabilites = 0;
|
||||
}
|
||||
|
||||
acx->ht_capabilites = cpu_to_le32(ht_capabilites);
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx));
|
||||
if (ret < 0) {
|
||||
wl1271_warning("acx ht capabilities setting failed: %d", ret);
|
||||
@ -1309,6 +1342,91 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configure BA session initiator/receiver parameters setting in the FW. */
|
||||
int wl1271_acx_set_ba_session(struct wl1271 *wl,
|
||||
enum ieee80211_back_parties direction,
|
||||
u8 tid_index, u8 policy)
|
||||
{
|
||||
struct wl1271_acx_ba_session_policy *acx;
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "acx ba session setting");
|
||||
|
||||
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
|
||||
if (!acx) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* ANY role */
|
||||
acx->role_id = 0xff;
|
||||
acx->tid = tid_index;
|
||||
acx->enable = policy;
|
||||
acx->ba_direction = direction;
|
||||
|
||||
switch (direction) {
|
||||
case WLAN_BACK_INITIATOR:
|
||||
acx->win_size = wl->conf.ht.tx_ba_win_size;
|
||||
acx->inactivity_timeout = wl->conf.ht.inactivity_timeout;
|
||||
break;
|
||||
case WLAN_BACK_RECIPIENT:
|
||||
acx->win_size = RX_BA_WIN_SIZE;
|
||||
acx->inactivity_timeout = 0;
|
||||
break;
|
||||
default:
|
||||
wl1271_error("Incorrect acx command id=%x\n", direction);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl1271_cmd_configure(wl,
|
||||
ACX_BA_SESSION_POLICY_CFG,
|
||||
acx,
|
||||
sizeof(*acx));
|
||||
if (ret < 0) {
|
||||
wl1271_warning("acx ba session setting failed: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* setup BA session receiver setting in the FW. */
|
||||
int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
|
||||
bool enable)
|
||||
{
|
||||
struct wl1271_acx_ba_receiver_setup *acx;
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "acx ba receiver session setting");
|
||||
|
||||
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
|
||||
if (!acx) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Single link for now */
|
||||
acx->link_id = 1;
|
||||
acx->tid = tid_index;
|
||||
acx->enable = enable;
|
||||
acx->win_size = 0;
|
||||
acx->ssn = ssn;
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx,
|
||||
sizeof(*acx));
|
||||
if (ret < 0) {
|
||||
wl1271_warning("acx ba receiver session failed: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
|
||||
{
|
||||
struct wl1271_acx_fw_tsf_information *tsf_info;
|
||||
@ -1334,3 +1452,27 @@ out:
|
||||
kfree(tsf_info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_max_tx_retry(struct wl1271 *wl)
|
||||
{
|
||||
struct wl1271_acx_max_tx_retry *acx = NULL;
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "acx max tx retry");
|
||||
|
||||
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
|
||||
if (!acx)
|
||||
return -ENOMEM;
|
||||
|
||||
acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries);
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx));
|
||||
if (ret < 0) {
|
||||
wl1271_warning("acx max tx retry failed: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
||||
|
@ -747,13 +747,23 @@ struct acx_rate_class {
|
||||
#define ACX_TX_BASIC_RATE 0
|
||||
#define ACX_TX_AP_FULL_RATE 1
|
||||
#define ACX_TX_RATE_POLICY_CNT 2
|
||||
struct acx_rate_policy {
|
||||
struct acx_sta_rate_policy {
|
||||
struct acx_header header;
|
||||
|
||||
__le32 rate_class_cnt;
|
||||
struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES];
|
||||
} __packed;
|
||||
|
||||
|
||||
#define ACX_TX_AP_MODE_MGMT_RATE 4
|
||||
#define ACX_TX_AP_MODE_BCST_RATE 5
|
||||
struct acx_ap_rate_policy {
|
||||
struct acx_header header;
|
||||
|
||||
__le32 rate_policy_idx;
|
||||
struct acx_rate_class rate_policy;
|
||||
} __packed;
|
||||
|
||||
struct acx_ac_cfg {
|
||||
struct acx_header header;
|
||||
u8 ac;
|
||||
@ -1051,6 +1061,59 @@ struct wl1271_acx_ht_information {
|
||||
u8 padding[3];
|
||||
} __packed;
|
||||
|
||||
#define RX_BA_WIN_SIZE 8
|
||||
|
||||
struct wl1271_acx_ba_session_policy {
|
||||
struct acx_header header;
|
||||
/*
|
||||
* Specifies role Id, Range 0-7, 0xFF means ANY role.
|
||||
* Future use. For now this field is irrelevant
|
||||
*/
|
||||
u8 role_id;
|
||||
/*
|
||||
* Specifies Link Id, Range 0-31, 0xFF means ANY Link Id.
|
||||
* Not applicable if Role Id is set to ANY.
|
||||
*/
|
||||
u8 link_id;
|
||||
|
||||
u8 tid;
|
||||
|
||||
u8 enable;
|
||||
|
||||
/* Windows size in number of packets */
|
||||
u16 win_size;
|
||||
|
||||
/*
|
||||
* As initiator inactivity timeout in time units(TU) of 1024us.
|
||||
* As receiver reserved
|
||||
*/
|
||||
u16 inactivity_timeout;
|
||||
|
||||
/* Initiator = 1/Receiver = 0 */
|
||||
u8 ba_direction;
|
||||
|
||||
u8 padding[3];
|
||||
} __packed;
|
||||
|
||||
struct wl1271_acx_ba_receiver_setup {
|
||||
struct acx_header header;
|
||||
|
||||
/* Specifies Link Id, Range 0-31, 0xFF means ANY Link Id */
|
||||
u8 link_id;
|
||||
|
||||
u8 tid;
|
||||
|
||||
u8 enable;
|
||||
|
||||
u8 padding[1];
|
||||
|
||||
/* Windows size in number of packets */
|
||||
u16 win_size;
|
||||
|
||||
/* BA session starting sequence number. RANGE 0-FFF */
|
||||
u16 ssn;
|
||||
} __packed;
|
||||
|
||||
struct wl1271_acx_fw_tsf_information {
|
||||
struct acx_header header;
|
||||
|
||||
@ -1062,6 +1125,17 @@ struct wl1271_acx_fw_tsf_information {
|
||||
u8 padding[3];
|
||||
} __packed;
|
||||
|
||||
struct wl1271_acx_max_tx_retry {
|
||||
struct acx_header header;
|
||||
|
||||
/*
|
||||
* the number of frames transmission failures before
|
||||
* issuing the aging event.
|
||||
*/
|
||||
__le16 max_tx_retry;
|
||||
u8 padding_1[2];
|
||||
} __packed;
|
||||
|
||||
enum {
|
||||
ACX_WAKE_UP_CONDITIONS = 0x0002,
|
||||
ACX_MEM_CFG = 0x0003,
|
||||
@ -1113,12 +1187,13 @@ enum {
|
||||
ACX_RSSI_SNR_WEIGHTS = 0x0052,
|
||||
ACX_KEEP_ALIVE_MODE = 0x0053,
|
||||
ACX_SET_KEEP_ALIVE_CONFIG = 0x0054,
|
||||
ACX_BA_SESSION_RESPONDER_POLICY = 0x0055,
|
||||
ACX_BA_SESSION_INITIATOR_POLICY = 0x0056,
|
||||
ACX_BA_SESSION_POLICY_CFG = 0x0055,
|
||||
ACX_BA_SESSION_RX_SETUP = 0x0056,
|
||||
ACX_PEER_HT_CAP = 0x0057,
|
||||
ACX_HT_BSS_OPERATION = 0x0058,
|
||||
ACX_COEX_ACTIVITY = 0x0059,
|
||||
ACX_SET_DCO_ITRIM_PARAMS = 0x0061,
|
||||
ACX_MAX_TX_FAILURE = 0x0072,
|
||||
DOT11_RX_MSDU_LIFE_TIME = 0x1004,
|
||||
DOT11_CUR_TX_PWR = 0x100D,
|
||||
DOT11_RX_DOT11_MODE = 0x1012,
|
||||
@ -1160,7 +1235,9 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble);
|
||||
int wl1271_acx_cts_protect(struct wl1271 *wl,
|
||||
enum acx_ctsprotect_type ctsprotect);
|
||||
int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
|
||||
int wl1271_acx_rate_policies(struct wl1271 *wl);
|
||||
int wl1271_acx_sta_rate_policies(struct wl1271 *wl);
|
||||
int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
|
||||
u8 idx);
|
||||
int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
|
||||
u8 aifsn, u16 txop);
|
||||
int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
|
||||
@ -1185,6 +1262,12 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
|
||||
bool allow_ht_operation);
|
||||
int wl1271_acx_set_ht_information(struct wl1271 *wl,
|
||||
u16 ht_operation_mode);
|
||||
int wl1271_acx_set_ba_session(struct wl1271 *wl,
|
||||
enum ieee80211_back_parties direction,
|
||||
u8 tid_index, u8 policy);
|
||||
int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
|
||||
bool enable);
|
||||
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
|
||||
int wl1271_acx_max_tx_retry(struct wl1271 *wl);
|
||||
|
||||
#endif /* __WL1271_ACX_H__ */
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "boot.h"
|
||||
#include "io.h"
|
||||
#include "event.h"
|
||||
#include "rx.h"
|
||||
|
||||
static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
|
||||
[PART_DOWN] = {
|
||||
@ -100,6 +101,22 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
|
||||
wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
|
||||
}
|
||||
|
||||
static void wl1271_parse_fw_ver(struct wl1271 *wl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u",
|
||||
&wl->chip.fw_ver[0], &wl->chip.fw_ver[1],
|
||||
&wl->chip.fw_ver[2], &wl->chip.fw_ver[3],
|
||||
&wl->chip.fw_ver[4]);
|
||||
|
||||
if (ret != 5) {
|
||||
wl1271_warning("fw version incorrect value");
|
||||
memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void wl1271_boot_fw_version(struct wl1271 *wl)
|
||||
{
|
||||
struct wl1271_static_data static_data;
|
||||
@ -107,11 +124,13 @@ static void wl1271_boot_fw_version(struct wl1271 *wl)
|
||||
wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data),
|
||||
false);
|
||||
|
||||
strncpy(wl->chip.fw_ver, static_data.fw_version,
|
||||
sizeof(wl->chip.fw_ver));
|
||||
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[sizeof(wl->chip.fw_ver) - 1] = '\0';
|
||||
wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0';
|
||||
|
||||
wl1271_parse_fw_ver(wl);
|
||||
}
|
||||
|
||||
static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
|
||||
@ -231,7 +250,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
|
||||
*/
|
||||
if (wl->nvs_len == sizeof(struct wl1271_nvs_file) ||
|
||||
wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) {
|
||||
if (wl->nvs->general_params.dual_mode_select)
|
||||
/* for now 11a is unsupported in AP mode */
|
||||
if (wl->bss_type != BSS_TYPE_AP_BSS &&
|
||||
wl->nvs->general_params.dual_mode_select)
|
||||
wl->enable_11a = true;
|
||||
}
|
||||
|
||||
@ -431,6 +452,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
|
||||
PSPOLL_DELIVERY_FAILURE_EVENT_ID |
|
||||
SOFT_GEMINI_SENSE_EVENT_ID;
|
||||
|
||||
if (wl->bss_type == BSS_TYPE_AP_BSS)
|
||||
wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID;
|
||||
|
||||
ret = wl1271_event_unmask(wl);
|
||||
if (ret < 0) {
|
||||
wl1271_error("EVENT mask setting failed");
|
||||
@ -595,8 +619,7 @@ int wl1271_boot(struct wl1271 *wl)
|
||||
wl1271_boot_enable_interrupts(wl);
|
||||
|
||||
/* set the wl1271 default filters */
|
||||
wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
|
||||
wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
|
||||
wl1271_set_default_filters(wl);
|
||||
|
||||
wl1271_event_mbox_config(wl);
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "wl12xx_80211.h"
|
||||
#include "cmd.h"
|
||||
#include "event.h"
|
||||
#include "tx.h"
|
||||
|
||||
#define WL1271_CMD_FAST_POLL_COUNT 50
|
||||
|
||||
@ -221,7 +222,7 @@ int wl1271_cmd_ext_radio_parms(struct wl1271 *wl)
|
||||
* Poll the mailbox event field until any of the bits in the mask is set or a
|
||||
* timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
|
||||
*/
|
||||
static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
|
||||
static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask)
|
||||
{
|
||||
u32 events_vector, event;
|
||||
unsigned long timeout;
|
||||
@ -230,7 +231,8 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
|
||||
|
||||
do {
|
||||
if (time_after(jiffies, timeout)) {
|
||||
ieee80211_queue_work(wl->hw, &wl->recovery_work);
|
||||
wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
|
||||
(int)mask);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
@ -248,6 +250,19 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask);
|
||||
if (ret != 0) {
|
||||
ieee80211_queue_work(wl->hw, &wl->recovery_work);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
|
||||
{
|
||||
struct wl1271_cmd_join *join;
|
||||
@ -490,8 +505,8 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
|
||||
cmd->len = cpu_to_le16(buf_len);
|
||||
cmd->template_type = template_id;
|
||||
cmd->enabled_rates = cpu_to_le32(rates);
|
||||
cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit;
|
||||
cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit;
|
||||
cmd->short_retry_limit = wl->conf.tx.tmpl_short_retry_limit;
|
||||
cmd->long_retry_limit = wl->conf.tx.tmpl_long_retry_limit;
|
||||
cmd->index = index;
|
||||
|
||||
if (buf)
|
||||
@ -659,15 +674,15 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr)
|
||||
|
||||
/* llc layer */
|
||||
memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header));
|
||||
tmpl.llc_type = htons(ETH_P_ARP);
|
||||
tmpl.llc_type = cpu_to_be16(ETH_P_ARP);
|
||||
|
||||
/* arp header */
|
||||
arp_hdr = &tmpl.arp_hdr;
|
||||
arp_hdr->ar_hrd = htons(ARPHRD_ETHER);
|
||||
arp_hdr->ar_pro = htons(ETH_P_IP);
|
||||
arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER);
|
||||
arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP);
|
||||
arp_hdr->ar_hln = ETH_ALEN;
|
||||
arp_hdr->ar_pln = 4;
|
||||
arp_hdr->ar_op = htons(ARPOP_REPLY);
|
||||
arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY);
|
||||
|
||||
/* arp payload */
|
||||
memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN);
|
||||
@ -702,9 +717,9 @@ int wl1271_build_qos_null_data(struct wl1271 *wl)
|
||||
wl->basic_rate);
|
||||
}
|
||||
|
||||
int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
|
||||
int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id)
|
||||
{
|
||||
struct wl1271_cmd_set_keys *cmd;
|
||||
struct wl1271_cmd_set_sta_keys *cmd;
|
||||
int ret = 0;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id);
|
||||
@ -731,11 +746,42 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
||||
int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id)
|
||||
{
|
||||
struct wl1271_cmd_set_ap_keys *cmd;
|
||||
int ret = 0;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd set_ap_default_wep_key %d", id);
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmd->hlid = WL1271_AP_BROADCAST_HLID;
|
||||
cmd->key_id = id;
|
||||
cmd->lid_key_type = WEP_DEFAULT_LID_TYPE;
|
||||
cmd->key_action = cpu_to_le16(KEY_SET_ID);
|
||||
cmd->key_type = KEY_WEP;
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
|
||||
if (ret < 0) {
|
||||
wl1271_warning("cmd set_ap_default_wep_key failed: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(cmd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
||||
u8 key_size, const u8 *key, const u8 *addr,
|
||||
u32 tx_seq_32, u16 tx_seq_16)
|
||||
{
|
||||
struct wl1271_cmd_set_keys *cmd;
|
||||
struct wl1271_cmd_set_sta_keys *cmd;
|
||||
int ret = 0;
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
@ -788,6 +834,67 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
||||
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
|
||||
u16 tx_seq_16)
|
||||
{
|
||||
struct wl1271_cmd_set_ap_keys *cmd;
|
||||
int ret = 0;
|
||||
u8 lid_type;
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
if (hlid == WL1271_AP_BROADCAST_HLID) {
|
||||
if (key_type == KEY_WEP)
|
||||
lid_type = WEP_DEFAULT_LID_TYPE;
|
||||
else
|
||||
lid_type = BROADCAST_LID_TYPE;
|
||||
} else {
|
||||
lid_type = UNICAST_LID_TYPE;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_CRYPT, "ap key action: %d id: %d lid: %d type: %d"
|
||||
" hlid: %d", (int)action, (int)id, (int)lid_type,
|
||||
(int)key_type, (int)hlid);
|
||||
|
||||
cmd->lid_key_type = lid_type;
|
||||
cmd->hlid = hlid;
|
||||
cmd->key_action = cpu_to_le16(action);
|
||||
cmd->key_size = key_size;
|
||||
cmd->key_type = key_type;
|
||||
cmd->key_id = id;
|
||||
cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
|
||||
cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);
|
||||
|
||||
if (key_type == KEY_TKIP) {
|
||||
/*
|
||||
* We get the key in the following form:
|
||||
* TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
|
||||
* but the target is expecting:
|
||||
* TKIP - RX MIC - TX MIC
|
||||
*/
|
||||
memcpy(cmd->key, key, 16);
|
||||
memcpy(cmd->key + 16, key + 24, 8);
|
||||
memcpy(cmd->key + 24, key + 16, 8);
|
||||
} else {
|
||||
memcpy(cmd->key, key, key_size);
|
||||
}
|
||||
|
||||
wl1271_dump(DEBUG_CRYPT, "TARGET AP KEY: ", cmd, sizeof(*cmd));
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
|
||||
if (ret < 0) {
|
||||
wl1271_warning("could not set ap keys");
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_cmd_disconnect(struct wl1271 *wl)
|
||||
{
|
||||
struct wl1271_cmd_disconnect *cmd;
|
||||
@ -850,3 +957,180 @@ out_free:
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_cmd_start_bss(struct wl1271 *wl)
|
||||
{
|
||||
struct wl1271_cmd_bss_start *cmd;
|
||||
struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd start bss");
|
||||
|
||||
/*
|
||||
* FIXME: We currently do not support hidden SSID. The real SSID
|
||||
* should be fetched from mac80211 first.
|
||||
*/
|
||||
if (wl->ssid_len == 0) {
|
||||
wl1271_warning("Hidden SSID currently not supported for AP");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN);
|
||||
|
||||
cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC);
|
||||
cmd->bss_index = WL1271_AP_BSS_INDEX;
|
||||
cmd->global_hlid = WL1271_AP_GLOBAL_HLID;
|
||||
cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID;
|
||||
cmd->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
|
||||
cmd->beacon_interval = cpu_to_le16(wl->beacon_int);
|
||||
cmd->dtim_interval = bss_conf->dtim_period;
|
||||
cmd->beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
|
||||
cmd->channel = wl->channel;
|
||||
cmd->ssid_len = wl->ssid_len;
|
||||
cmd->ssid_type = SSID_TYPE_PUBLIC;
|
||||
memcpy(cmd->ssid, wl->ssid, wl->ssid_len);
|
||||
|
||||
switch (wl->band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
cmd->band = RADIO_BAND_2_4GHZ;
|
||||
break;
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
cmd->band = RADIO_BAND_5GHZ;
|
||||
break;
|
||||
default:
|
||||
wl1271_warning("bss start - unknown band: %d", (int)wl->band);
|
||||
cmd->band = RADIO_BAND_2_4GHZ;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_BSS_START, cmd, sizeof(*cmd), 0);
|
||||
if (ret < 0) {
|
||||
wl1271_error("failed to initiate cmd start bss");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_cmd_stop_bss(struct wl1271 *wl)
|
||||
{
|
||||
struct wl1271_cmd_bss_start *cmd;
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd stop bss");
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmd->bss_index = WL1271_AP_BSS_INDEX;
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_BSS_STOP, cmd, sizeof(*cmd), 0);
|
||||
if (ret < 0) {
|
||||
wl1271_error("failed to initiate cmd stop bss");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
|
||||
{
|
||||
struct wl1271_cmd_add_sta *cmd;
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd add sta %d", (int)hlid);
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* currently we don't support UAPSD */
|
||||
cmd->sp_len = 0;
|
||||
|
||||
memcpy(cmd->addr, sta->addr, ETH_ALEN);
|
||||
cmd->bss_index = WL1271_AP_BSS_INDEX;
|
||||
cmd->aid = sta->aid;
|
||||
cmd->hlid = hlid;
|
||||
|
||||
/*
|
||||
* FIXME: Does STA support QOS? We need to propagate this info from
|
||||
* hostapd. Currently not that important since this is only used for
|
||||
* sending the correct flavor of null-data packet in response to a
|
||||
* trigger.
|
||||
*/
|
||||
cmd->wmm = 0;
|
||||
|
||||
cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl,
|
||||
sta->supp_rates[wl->band]));
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "new sta rates: 0x%x", cmd->supported_rates);
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_ADD_STA, cmd, sizeof(*cmd), 0);
|
||||
if (ret < 0) {
|
||||
wl1271_error("failed to initiate cmd add sta");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid)
|
||||
{
|
||||
struct wl1271_cmd_remove_sta *cmd;
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd remove sta %d", (int)hlid);
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmd->hlid = hlid;
|
||||
/* We never send a deauth, mac80211 is in charge of this */
|
||||
cmd->reason_opcode = 0;
|
||||
cmd->send_deauth_flag = 0;
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_REMOVE_STA, cmd, sizeof(*cmd), 0);
|
||||
if (ret < 0) {
|
||||
wl1271_error("failed to initiate cmd remove sta");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/*
|
||||
* We are ok with a timeout here. The event is sometimes not sent
|
||||
* due to a firmware bug.
|
||||
*/
|
||||
wl1271_cmd_wait_for_event_or_timeout(wl, STA_REMOVE_COMPLETE_EVENT_ID);
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
@ -54,12 +54,20 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
|
||||
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr);
|
||||
int wl1271_build_qos_null_data(struct wl1271 *wl);
|
||||
int wl1271_cmd_build_klv_null_data(struct wl1271 *wl);
|
||||
int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id);
|
||||
int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
||||
u8 key_size, const u8 *key, const u8 *addr,
|
||||
u32 tx_seq_32, u16 tx_seq_16);
|
||||
int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id);
|
||||
int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id);
|
||||
int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
||||
u8 key_size, const u8 *key, const u8 *addr,
|
||||
u32 tx_seq_32, u16 tx_seq_16);
|
||||
int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
||||
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
|
||||
u16 tx_seq_16);
|
||||
int wl1271_cmd_disconnect(struct wl1271 *wl);
|
||||
int wl1271_cmd_set_sta_state(struct wl1271 *wl);
|
||||
int wl1271_cmd_start_bss(struct wl1271 *wl);
|
||||
int wl1271_cmd_stop_bss(struct wl1271 *wl);
|
||||
int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid);
|
||||
int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid);
|
||||
|
||||
enum wl1271_commands {
|
||||
CMD_INTERROGATE = 1, /*use this to read information elements*/
|
||||
@ -98,6 +106,12 @@ enum wl1271_commands {
|
||||
CMD_STOP_PERIODIC_SCAN = 51,
|
||||
CMD_SET_STA_STATE = 52,
|
||||
|
||||
/* AP mode commands */
|
||||
CMD_BSS_START = 60,
|
||||
CMD_BSS_STOP = 61,
|
||||
CMD_ADD_STA = 62,
|
||||
CMD_REMOVE_STA = 63,
|
||||
|
||||
NUM_COMMANDS,
|
||||
MAX_COMMAND_ID = 0xFFFF,
|
||||
};
|
||||
@ -126,6 +140,13 @@ enum cmd_templ {
|
||||
* For CTS-to-self (FastCTS) mechanism
|
||||
* for BT/WLAN coexistence (SoftGemini). */
|
||||
CMD_TEMPL_ARP_RSP,
|
||||
|
||||
/* AP-mode specific */
|
||||
CMD_TEMPL_AP_BEACON = 13,
|
||||
CMD_TEMPL_AP_PROBE_RESPONSE,
|
||||
CMD_TEMPL_AP_ARP_RSP,
|
||||
CMD_TEMPL_DEAUTH_AP,
|
||||
|
||||
CMD_TEMPL_MAX = 0xff
|
||||
};
|
||||
|
||||
@ -270,7 +291,6 @@ struct wl1271_cmd_ps_params {
|
||||
|
||||
/* HW encryption keys */
|
||||
#define NUM_ACCESS_CATEGORIES_COPY 4
|
||||
#define MAX_KEY_SIZE 32
|
||||
|
||||
enum wl1271_cmd_key_action {
|
||||
KEY_ADD_OR_REPLACE = 1,
|
||||
@ -289,7 +309,7 @@ enum wl1271_cmd_key_type {
|
||||
|
||||
/* FIXME: Add description for key-types */
|
||||
|
||||
struct wl1271_cmd_set_keys {
|
||||
struct wl1271_cmd_set_sta_keys {
|
||||
struct wl1271_cmd_header header;
|
||||
|
||||
/* Ignored for default WEP key */
|
||||
@ -318,6 +338,57 @@ struct wl1271_cmd_set_keys {
|
||||
__le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
|
||||
} __packed;
|
||||
|
||||
enum wl1271_cmd_lid_key_type {
|
||||
UNICAST_LID_TYPE = 0,
|
||||
BROADCAST_LID_TYPE = 1,
|
||||
WEP_DEFAULT_LID_TYPE = 2
|
||||
};
|
||||
|
||||
struct wl1271_cmd_set_ap_keys {
|
||||
struct wl1271_cmd_header header;
|
||||
|
||||
/*
|
||||
* Indicates whether the HLID is a unicast key set
|
||||
* or broadcast key set. A special value 0xFF is
|
||||
* used to indicate that the HLID is on WEP-default
|
||||
* (multi-hlids). of type wl1271_cmd_lid_key_type.
|
||||
*/
|
||||
u8 hlid;
|
||||
|
||||
/*
|
||||
* In WEP-default network (hlid == 0xFF) used to
|
||||
* indicate which network STA/IBSS/AP role should be
|
||||
* changed
|
||||
*/
|
||||
u8 lid_key_type;
|
||||
|
||||
/*
|
||||
* Key ID - For TKIP and AES key types, this field
|
||||
* indicates the value that should be inserted into
|
||||
* the KeyID field of frames transmitted using this
|
||||
* key entry. For broadcast keys the index use as a
|
||||
* marker for TX/RX key.
|
||||
* For WEP default network (HLID=0xFF), this field
|
||||
* indicates the ID of the key to add or remove.
|
||||
*/
|
||||
u8 key_id;
|
||||
u8 reserved_1;
|
||||
|
||||
/* key_action_e */
|
||||
__le16 key_action;
|
||||
|
||||
/* key size in bytes */
|
||||
u8 key_size;
|
||||
|
||||
/* key_type_e */
|
||||
u8 key_type;
|
||||
|
||||
/* This field holds the security key data to add to the STA table */
|
||||
u8 key[MAX_KEY_SIZE];
|
||||
__le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
|
||||
__le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
|
||||
} __packed;
|
||||
|
||||
struct wl1271_cmd_test_header {
|
||||
u8 id;
|
||||
u8 padding[3];
|
||||
@ -412,4 +483,68 @@ struct wl1271_cmd_set_sta_state {
|
||||
u8 padding[3];
|
||||
} __packed;
|
||||
|
||||
enum wl1271_ssid_type {
|
||||
SSID_TYPE_PUBLIC = 0,
|
||||
SSID_TYPE_HIDDEN = 1
|
||||
};
|
||||
|
||||
struct wl1271_cmd_bss_start {
|
||||
struct wl1271_cmd_header header;
|
||||
|
||||
/* wl1271_ssid_type */
|
||||
u8 ssid_type;
|
||||
u8 ssid_len;
|
||||
u8 ssid[IW_ESSID_MAX_SIZE];
|
||||
u8 padding_1[2];
|
||||
|
||||
/* Basic rate set */
|
||||
__le32 basic_rate_set;
|
||||
/* Aging period in seconds*/
|
||||
__le16 aging_period;
|
||||
|
||||
/*
|
||||
* This field specifies the time between target beacon
|
||||
* transmission times (TBTTs), in time units (TUs).
|
||||
* Valid values are 1 to 1024.
|
||||
*/
|
||||
__le16 beacon_interval;
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 bss_index;
|
||||
/* Radio band */
|
||||
u8 band;
|
||||
u8 channel;
|
||||
/* The host link id for the AP's global queue */
|
||||
u8 global_hlid;
|
||||
/* The host link id for the AP's broadcast queue */
|
||||
u8 broadcast_hlid;
|
||||
/* DTIM count */
|
||||
u8 dtim_interval;
|
||||
/* Beacon expiry time in ms */
|
||||
u8 beacon_expiry;
|
||||
u8 padding_2[3];
|
||||
} __packed;
|
||||
|
||||
struct wl1271_cmd_add_sta {
|
||||
struct wl1271_cmd_header header;
|
||||
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 hlid;
|
||||
u8 aid;
|
||||
u8 psd_type[NUM_ACCESS_CATEGORIES_COPY];
|
||||
__le32 supported_rates;
|
||||
u8 bss_index;
|
||||
u8 sp_len;
|
||||
u8 wmm;
|
||||
u8 padding1;
|
||||
} __packed;
|
||||
|
||||
struct wl1271_cmd_remove_sta {
|
||||
struct wl1271_cmd_header header;
|
||||
|
||||
u8 hlid;
|
||||
u8 reason_opcode;
|
||||
u8 send_deauth_flag;
|
||||
u8 padding1;
|
||||
} __packed;
|
||||
|
||||
#endif /* __WL1271_CMD_H__ */
|
||||
|
@ -496,6 +496,26 @@ struct conf_rx_settings {
|
||||
CONF_HW_BIT_RATE_2MBPS)
|
||||
#define CONF_TX_RATE_RETRY_LIMIT 10
|
||||
|
||||
/*
|
||||
* Rates supported for data packets when operating as AP. Note the absense
|
||||
* of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop
|
||||
* one. The rate dropped is not mandatory under any operating mode.
|
||||
*/
|
||||
#define CONF_TX_AP_ENABLED_RATES (CONF_HW_BIT_RATE_1MBPS | \
|
||||
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \
|
||||
CONF_HW_BIT_RATE_6MBPS | CONF_HW_BIT_RATE_9MBPS | \
|
||||
CONF_HW_BIT_RATE_11MBPS | CONF_HW_BIT_RATE_12MBPS | \
|
||||
CONF_HW_BIT_RATE_18MBPS | CONF_HW_BIT_RATE_24MBPS | \
|
||||
CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \
|
||||
CONF_HW_BIT_RATE_54MBPS)
|
||||
|
||||
/*
|
||||
* Default rates for management traffic when operating in AP mode. This
|
||||
* should be configured according to the basic rate set of the AP
|
||||
*/
|
||||
#define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \
|
||||
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS)
|
||||
|
||||
struct conf_tx_rate_class {
|
||||
|
||||
/*
|
||||
@ -636,9 +656,9 @@ struct conf_tx_settings {
|
||||
|
||||
/*
|
||||
* Configuration for rate classes for TX (currently only one
|
||||
* rate class supported.)
|
||||
* rate class supported). Used in non-AP mode.
|
||||
*/
|
||||
struct conf_tx_rate_class rc_conf;
|
||||
struct conf_tx_rate_class sta_rc_conf;
|
||||
|
||||
/*
|
||||
* Configuration for access categories for TX rate control.
|
||||
@ -646,6 +666,28 @@ struct conf_tx_settings {
|
||||
u8 ac_conf_count;
|
||||
struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT];
|
||||
|
||||
/*
|
||||
* Configuration for rate classes in AP-mode. These rate classes
|
||||
* are for the AC TX queues
|
||||
*/
|
||||
struct conf_tx_rate_class ap_rc_conf[CONF_TX_MAX_AC_COUNT];
|
||||
|
||||
/*
|
||||
* Management TX rate class for AP-mode.
|
||||
*/
|
||||
struct conf_tx_rate_class ap_mgmt_conf;
|
||||
|
||||
/*
|
||||
* Broadcast TX rate class for AP-mode.
|
||||
*/
|
||||
struct conf_tx_rate_class ap_bcst_conf;
|
||||
|
||||
/*
|
||||
* AP-mode - allow this number of TX retries to a station before an
|
||||
* event is triggered from FW.
|
||||
*/
|
||||
u16 ap_max_tx_retries;
|
||||
|
||||
/*
|
||||
* Configuration for TID parameters.
|
||||
*/
|
||||
@ -687,6 +729,12 @@ struct conf_tx_settings {
|
||||
* Range: CONF_HW_BIT_RATE_* bit mask
|
||||
*/
|
||||
u32 basic_rate_5;
|
||||
|
||||
/*
|
||||
* TX retry limits for templates
|
||||
*/
|
||||
u8 tmpl_short_retry_limit;
|
||||
u8 tmpl_long_retry_limit;
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -1036,30 +1084,30 @@ struct conf_scan_settings {
|
||||
/*
|
||||
* The minimum time to wait on each channel for active scans
|
||||
*
|
||||
* Range: 0 - 65536 tu
|
||||
* Range: u32 tu/1000
|
||||
*/
|
||||
u16 min_dwell_time_active;
|
||||
u32 min_dwell_time_active;
|
||||
|
||||
/*
|
||||
* The maximum time to wait on each channel for active scans
|
||||
*
|
||||
* Range: 0 - 65536 tu
|
||||
* Range: u32 tu/1000
|
||||
*/
|
||||
u16 max_dwell_time_active;
|
||||
u32 max_dwell_time_active;
|
||||
|
||||
/*
|
||||
* The minimum time to wait on each channel for passive scans
|
||||
*
|
||||
* Range: u32 tu/1000
|
||||
*/
|
||||
u32 min_dwell_time_passive;
|
||||
|
||||
/*
|
||||
* The maximum time to wait on each channel for passive scans
|
||||
*
|
||||
* Range: 0 - 65536 tu
|
||||
* Range: u32 tu/1000
|
||||
*/
|
||||
u16 min_dwell_time_passive;
|
||||
|
||||
/*
|
||||
* The maximum time to wait on each channel for passive scans
|
||||
*
|
||||
* Range: 0 - 65536 tu
|
||||
*/
|
||||
u16 max_dwell_time_passive;
|
||||
u32 max_dwell_time_passive;
|
||||
|
||||
/*
|
||||
* Number of probe requests to transmit on each active scan channel
|
||||
@ -1090,6 +1138,11 @@ struct conf_rf_settings {
|
||||
u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5];
|
||||
};
|
||||
|
||||
struct conf_ht_setting {
|
||||
u16 tx_ba_win_size;
|
||||
u16 inactivity_timeout;
|
||||
};
|
||||
|
||||
struct conf_drv_settings {
|
||||
struct conf_sg_settings sg;
|
||||
struct conf_rx_settings rx;
|
||||
@ -1100,6 +1153,7 @@ struct conf_drv_settings {
|
||||
struct conf_roam_trigger_settings roam_trigger;
|
||||
struct conf_scan_settings scan;
|
||||
struct conf_rf_settings rf;
|
||||
struct conf_ht_setting ht;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -261,27 +261,25 @@ static ssize_t gpio_power_write(struct file *file,
|
||||
unsigned long value;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
len = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, len)) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
return -EFAULT;
|
||||
}
|
||||
buf[len] = '\0';
|
||||
|
||||
ret = strict_strtoul(buf, 0, &value);
|
||||
if (ret < 0) {
|
||||
wl1271_warning("illegal value in gpio_power");
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (value)
|
||||
wl1271_power_on(wl);
|
||||
else
|
||||
wl1271_power_off(wl);
|
||||
|
||||
out:
|
||||
mutex_unlock(&wl->mutex);
|
||||
return count;
|
||||
}
|
||||
@ -293,12 +291,13 @@ static const struct file_operations gpio_power_ops = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static int wl1271_debugfs_add_files(struct wl1271 *wl)
|
||||
static int wl1271_debugfs_add_files(struct wl1271 *wl,
|
||||
struct dentry *rootdir)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dentry *entry, *stats;
|
||||
|
||||
stats = debugfs_create_dir("fw-statistics", wl->rootdir);
|
||||
stats = debugfs_create_dir("fw-statistics", rootdir);
|
||||
if (!stats || IS_ERR(stats)) {
|
||||
entry = stats;
|
||||
goto err;
|
||||
@ -395,16 +394,11 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl)
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
|
||||
|
||||
DEBUGFS_ADD(tx_queue_len, wl->rootdir);
|
||||
DEBUGFS_ADD(retry_count, wl->rootdir);
|
||||
DEBUGFS_ADD(excessive_retries, wl->rootdir);
|
||||
DEBUGFS_ADD(tx_queue_len, rootdir);
|
||||
DEBUGFS_ADD(retry_count, rootdir);
|
||||
DEBUGFS_ADD(excessive_retries, rootdir);
|
||||
|
||||
DEBUGFS_ADD(gpio_power, wl->rootdir);
|
||||
|
||||
entry = debugfs_create_x32("debug_level", 0600, wl->rootdir,
|
||||
&wl12xx_debug_level);
|
||||
if (!entry || IS_ERR(entry))
|
||||
goto err;
|
||||
DEBUGFS_ADD(gpio_power, rootdir);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -419,7 +413,7 @@ err:
|
||||
|
||||
void wl1271_debugfs_reset(struct wl1271 *wl)
|
||||
{
|
||||
if (!wl->rootdir)
|
||||
if (!wl->stats.fw_stats)
|
||||
return;
|
||||
|
||||
memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats));
|
||||
@ -430,13 +424,13 @@ void wl1271_debugfs_reset(struct wl1271 *wl)
|
||||
int wl1271_debugfs_init(struct wl1271 *wl)
|
||||
{
|
||||
int ret;
|
||||
struct dentry *rootdir;
|
||||
|
||||
wl->rootdir = debugfs_create_dir(KBUILD_MODNAME,
|
||||
wl->hw->wiphy->debugfsdir);
|
||||
rootdir = debugfs_create_dir(KBUILD_MODNAME,
|
||||
wl->hw->wiphy->debugfsdir);
|
||||
|
||||
if (IS_ERR(wl->rootdir)) {
|
||||
ret = PTR_ERR(wl->rootdir);
|
||||
wl->rootdir = NULL;
|
||||
if (IS_ERR(rootdir)) {
|
||||
ret = PTR_ERR(rootdir);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -450,7 +444,7 @@ int wl1271_debugfs_init(struct wl1271 *wl)
|
||||
|
||||
wl->stats.fw_stats_update = jiffies;
|
||||
|
||||
ret = wl1271_debugfs_add_files(wl);
|
||||
ret = wl1271_debugfs_add_files(wl, rootdir);
|
||||
|
||||
if (ret < 0)
|
||||
goto err_file;
|
||||
@ -462,8 +456,7 @@ err_file:
|
||||
wl->stats.fw_stats = NULL;
|
||||
|
||||
err_fw:
|
||||
debugfs_remove_recursive(wl->rootdir);
|
||||
wl->rootdir = NULL;
|
||||
debugfs_remove_recursive(rootdir);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
@ -473,8 +466,4 @@ void wl1271_debugfs_exit(struct wl1271 *wl)
|
||||
{
|
||||
kfree(wl->stats.fw_stats);
|
||||
wl->stats.fw_stats = NULL;
|
||||
|
||||
debugfs_remove_recursive(wl->rootdir);
|
||||
wl->rootdir = NULL;
|
||||
|
||||
}
|
||||
|
@ -186,6 +186,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
||||
int ret;
|
||||
u32 vector;
|
||||
bool beacon_loss = false;
|
||||
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
|
||||
|
||||
wl1271_event_mbox_dump(mbox);
|
||||
|
||||
@ -218,21 +219,21 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
||||
* BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
|
||||
*
|
||||
*/
|
||||
if (vector & BSS_LOSE_EVENT_ID) {
|
||||
if ((vector & BSS_LOSE_EVENT_ID) && !is_ap) {
|
||||
wl1271_info("Beacon loss detected.");
|
||||
|
||||
/* indicate to the stack, that beacons have been lost */
|
||||
beacon_loss = true;
|
||||
}
|
||||
|
||||
if (vector & PS_REPORT_EVENT_ID) {
|
||||
if ((vector & PS_REPORT_EVENT_ID) && !is_ap) {
|
||||
wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
|
||||
ret = wl1271_event_ps_report(wl, mbox, &beacon_loss);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID)
|
||||
if ((vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) && !is_ap)
|
||||
wl1271_event_pspoll_delivery_fail(wl);
|
||||
|
||||
if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
|
||||
|
@ -59,6 +59,7 @@ enum {
|
||||
BSS_LOSE_EVENT_ID = BIT(18),
|
||||
REGAINED_BSS_EVENT_ID = BIT(19),
|
||||
ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20),
|
||||
STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), /* AP */
|
||||
SOFT_GEMINI_SENSE_EVENT_ID = BIT(22),
|
||||
SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23),
|
||||
SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24),
|
||||
@ -115,7 +116,12 @@ struct event_mailbox {
|
||||
u8 scheduled_scan_status;
|
||||
u8 ps_status;
|
||||
|
||||
u8 reserved_5[29];
|
||||
/* AP FW only */
|
||||
u8 hlid_removed;
|
||||
__le16 sta_aging_status;
|
||||
__le16 sta_tx_retry_exceeded;
|
||||
|
||||
u8 reserved_5[24];
|
||||
} __packed;
|
||||
|
||||
int wl1271_event_unmask(struct wl1271 *wl);
|
||||
|
@ -30,27 +30,9 @@
|
||||
#include "acx.h"
|
||||
#include "cmd.h"
|
||||
#include "reg.h"
|
||||
#include "tx.h"
|
||||
|
||||
static int wl1271_init_hwenc_config(struct wl1271 *wl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl1271_acx_feature_cfg(wl);
|
||||
if (ret < 0) {
|
||||
wl1271_warning("couldn't set feature config");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wl1271_cmd_set_default_wep_key(wl, wl->default_key);
|
||||
if (ret < 0) {
|
||||
wl1271_warning("couldn't set default key");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wl1271_init_templates_config(struct wl1271 *wl)
|
||||
int wl1271_sta_init_templates_config(struct wl1271 *wl)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
@ -118,6 +100,132 @@ int wl1271_init_templates_config(struct wl1271 *wl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_deauth_template(struct wl1271 *wl)
|
||||
{
|
||||
struct wl12xx_disconn_template *tmpl;
|
||||
int ret;
|
||||
|
||||
tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
|
||||
if (!tmpl) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_DEAUTH);
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP,
|
||||
tmpl, sizeof(*tmpl), 0,
|
||||
wl1271_tx_min_rate_get(wl));
|
||||
|
||||
out:
|
||||
kfree(tmpl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_null_template(struct wl1271 *wl)
|
||||
{
|
||||
struct ieee80211_hdr_3addr *nullfunc;
|
||||
int ret;
|
||||
|
||||
nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL);
|
||||
if (!nullfunc) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_NULLFUNC |
|
||||
IEEE80211_FCTL_FROMDS);
|
||||
|
||||
/* nullfunc->addr1 is filled by FW */
|
||||
|
||||
memcpy(nullfunc->addr2, wl->mac_addr, ETH_ALEN);
|
||||
memcpy(nullfunc->addr3, wl->mac_addr, ETH_ALEN);
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc,
|
||||
sizeof(*nullfunc), 0,
|
||||
wl1271_tx_min_rate_get(wl));
|
||||
|
||||
out:
|
||||
kfree(nullfunc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_qos_null_template(struct wl1271 *wl)
|
||||
{
|
||||
struct ieee80211_qos_hdr *qosnull;
|
||||
int ret;
|
||||
|
||||
qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL);
|
||||
if (!qosnull) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_QOS_NULLFUNC |
|
||||
IEEE80211_FCTL_FROMDS);
|
||||
|
||||
/* qosnull->addr1 is filled by FW */
|
||||
|
||||
memcpy(qosnull->addr2, wl->mac_addr, ETH_ALEN);
|
||||
memcpy(qosnull->addr3, wl->mac_addr, ETH_ALEN);
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull,
|
||||
sizeof(*qosnull), 0,
|
||||
wl1271_tx_min_rate_get(wl));
|
||||
|
||||
out:
|
||||
kfree(qosnull);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_templates_config(struct wl1271 *wl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Put very large empty placeholders for all templates. These
|
||||
* reserve memory for later.
|
||||
*/
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
|
||||
sizeof
|
||||
(struct wl12xx_probe_resp_template),
|
||||
0, WL1271_RATE_AUTOMATIC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL,
|
||||
sizeof
|
||||
(struct wl12xx_beacon_template),
|
||||
0, WL1271_RATE_AUTOMATIC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, NULL,
|
||||
sizeof
|
||||
(struct wl12xx_disconn_template),
|
||||
0, WL1271_RATE_AUTOMATIC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
|
||||
sizeof(struct wl12xx_null_data_template),
|
||||
0, WL1271_RATE_AUTOMATIC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL,
|
||||
sizeof
|
||||
(struct wl12xx_qos_null_data_template),
|
||||
0, WL1271_RATE_AUTOMATIC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter)
|
||||
{
|
||||
int ret;
|
||||
@ -145,10 +253,6 @@ int wl1271_init_phy_config(struct wl1271 *wl)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_group_address_tbl(wl, true, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_service_period_timeout(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -213,11 +317,186 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_sta_hw_init(struct wl1271 *wl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl1271_cmd_ext_radio_parms(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_sta_init_templates_config(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_group_address_tbl(wl, true, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Initialize connection monitoring thresholds */
|
||||
ret = wl1271_acx_conn_monit_params(wl, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Beacon filtering */
|
||||
ret = wl1271_init_beacon_filter(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Bluetooth WLAN coexistence */
|
||||
ret = wl1271_init_pta(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Beacons and broadcast settings */
|
||||
ret = wl1271_init_beacon_broadcast(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure for ELP power saving */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure rssi/snr averaging weights */
|
||||
ret = wl1271_acx_rssi_snr_avg_weights(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_sta_rate_policies(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
ret = wl1271_cmd_set_sta_default_wep_key(wl, wl->default_key);
|
||||
if (ret < 0) {
|
||||
wl1271_warning("couldn't set default key");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* disable all keep-alive templates */
|
||||
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
|
||||
ret = wl1271_acx_keep_alive_config(wl, i,
|
||||
ACX_KEEP_ALIVE_TPL_INVALID);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* disable the keep-alive feature */
|
||||
ret = wl1271_acx_keep_alive_mode(wl, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_ap_hw_init(struct wl1271 *wl)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
ret = wl1271_ap_init_templates_config(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure for power always on */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure initial TX rate classes */
|
||||
for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
|
||||
ret = wl1271_acx_ap_rate_policy(wl,
|
||||
&wl->conf.tx.ap_rc_conf[i], i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wl1271_acx_ap_rate_policy(wl,
|
||||
&wl->conf.tx.ap_mgmt_conf,
|
||||
ACX_TX_AP_MODE_MGMT_RATE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_ap_rate_policy(wl,
|
||||
&wl->conf.tx.ap_bcst_conf,
|
||||
ACX_TX_AP_MODE_BCST_RATE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_max_tx_retry(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl1271_ap_init_deauth_template(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_ap_init_null_template(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_ap_init_qos_null_template(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wl1271_check_ba_support(struct wl1271 *wl)
|
||||
{
|
||||
/* validate FW cose ver x.x.x.50-60.x */
|
||||
if ((wl->chip.fw_ver[3] >= WL12XX_BA_SUPPORT_FW_COST_VER2_START) &&
|
||||
(wl->chip.fw_ver[3] < WL12XX_BA_SUPPORT_FW_COST_VER2_END)) {
|
||||
wl->ba_support = true;
|
||||
return;
|
||||
}
|
||||
|
||||
wl->ba_support = false;
|
||||
}
|
||||
|
||||
static int wl1271_set_ba_policies(struct wl1271 *wl)
|
||||
{
|
||||
u8 tid_index;
|
||||
u8 ret = 0;
|
||||
|
||||
/* Reset the BA RX indicators */
|
||||
wl->ba_rx_bitmap = 0;
|
||||
|
||||
/* validate that FW support BA */
|
||||
wl1271_check_ba_support(wl);
|
||||
|
||||
if (wl->ba_support)
|
||||
/* 802.11n initiator BA session setting */
|
||||
for (tid_index = 0; tid_index < CONF_TX_MAX_TID_COUNT;
|
||||
++tid_index) {
|
||||
ret = wl1271_acx_set_ba_session(wl, WLAN_BACK_INITIATOR,
|
||||
tid_index, true);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_hw_init(struct wl1271 *wl)
|
||||
{
|
||||
struct conf_tx_ac_category *conf_ac;
|
||||
struct conf_tx_tid *conf_tid;
|
||||
int ret, i;
|
||||
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
|
||||
|
||||
ret = wl1271_cmd_general_parms(wl);
|
||||
if (ret < 0)
|
||||
@ -227,12 +506,12 @@ int wl1271_hw_init(struct wl1271 *wl)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_cmd_ext_radio_parms(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* Mode specific init */
|
||||
if (is_ap)
|
||||
ret = wl1271_ap_hw_init(wl);
|
||||
else
|
||||
ret = wl1271_sta_hw_init(wl);
|
||||
|
||||
/* Template settings */
|
||||
ret = wl1271_init_templates_config(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -259,16 +538,6 @@ int wl1271_hw_init(struct wl1271 *wl)
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Initialize connection monitoring thresholds */
|
||||
ret = wl1271_acx_conn_monit_params(wl, false);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Beacon filtering */
|
||||
ret = wl1271_init_beacon_filter(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Configure TX patch complete interrupt behavior */
|
||||
ret = wl1271_acx_tx_config_options(wl);
|
||||
if (ret < 0)
|
||||
@ -279,21 +548,11 @@ int wl1271_hw_init(struct wl1271 *wl)
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Bluetooth WLAN coexistence */
|
||||
ret = wl1271_init_pta(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Energy detection */
|
||||
ret = wl1271_init_energy_detection(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Beacons and boradcast settings */
|
||||
ret = wl1271_init_beacon_broadcast(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Default fragmentation threshold */
|
||||
ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
|
||||
if (ret < 0)
|
||||
@ -321,23 +580,13 @@ int wl1271_hw_init(struct wl1271 *wl)
|
||||
goto out_free_memmap;
|
||||
}
|
||||
|
||||
/* Configure TX rate classes */
|
||||
ret = wl1271_acx_rate_policies(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 ELP power saving */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Configure HW encryption */
|
||||
ret = wl1271_init_hwenc_config(wl);
|
||||
ret = wl1271_acx_feature_cfg(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
@ -346,21 +595,17 @@ int wl1271_hw_init(struct wl1271 *wl)
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* disable all keep-alive templates */
|
||||
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
|
||||
ret = wl1271_acx_keep_alive_config(wl, i,
|
||||
ACX_KEEP_ALIVE_TPL_INVALID);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
}
|
||||
/* Mode specific init - post mem init */
|
||||
if (is_ap)
|
||||
ret = wl1271_ap_hw_init_post_mem(wl);
|
||||
else
|
||||
ret = wl1271_sta_hw_init_post_mem(wl);
|
||||
|
||||
/* disable the keep-alive feature */
|
||||
ret = wl1271_acx_keep_alive_mode(wl, false);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Configure rssi/snr averaging weights */
|
||||
ret = wl1271_acx_rssi_snr_avg_weights(wl);
|
||||
/* Configure initiator BA sessions policies */
|
||||
ret = wl1271_set_ba_policies(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "wl12xx.h"
|
||||
|
||||
int wl1271_hw_init_power_auth(struct wl1271 *wl);
|
||||
int wl1271_init_templates_config(struct wl1271 *wl);
|
||||
int wl1271_sta_init_templates_config(struct wl1271 *wl);
|
||||
int wl1271_init_phy_config(struct wl1271 *wl);
|
||||
int wl1271_init_pta(struct wl1271 *wl);
|
||||
int wl1271_init_energy_detection(struct wl1271 *wl);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -198,6 +198,16 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
|
||||
pkt_offset += pkt_length;
|
||||
}
|
||||
}
|
||||
wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS,
|
||||
cpu_to_le32(wl->rx_counter));
|
||||
wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
|
||||
}
|
||||
|
||||
void wl1271_set_default_filters(struct wl1271 *wl)
|
||||
{
|
||||
if (wl->bss_type == BSS_TYPE_AP_BSS) {
|
||||
wl->rx_config = WL1271_DEFAULT_AP_RX_CONFIG;
|
||||
wl->rx_filter = WL1271_DEFAULT_AP_RX_FILTER;
|
||||
} else {
|
||||
wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
|
||||
wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
|
||||
}
|
||||
}
|
||||
|
@ -86,8 +86,9 @@
|
||||
/*
|
||||
* RX Descriptor status
|
||||
*
|
||||
* Bits 0-2 - status
|
||||
* Bits 3-7 - reserved
|
||||
* Bits 0-2 - error code
|
||||
* Bits 3-5 - process_id tag (AP mode FW)
|
||||
* Bits 6-7 - reserved
|
||||
*/
|
||||
#define WL1271_RX_DESC_STATUS_MASK 0x07
|
||||
|
||||
@ -110,12 +111,16 @@ struct wl1271_rx_descriptor {
|
||||
u8 snr;
|
||||
__le32 timestamp;
|
||||
u8 packet_class;
|
||||
u8 process_id;
|
||||
union {
|
||||
u8 process_id; /* STA FW */
|
||||
u8 hlid; /* AP FW */
|
||||
} __packed;
|
||||
u8 pad_len;
|
||||
u8 reserved;
|
||||
} __packed;
|
||||
|
||||
void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status);
|
||||
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
|
||||
void wl1271_set_default_filters(struct wl1271 *wl);
|
||||
|
||||
#endif
|
||||
|
@ -345,3 +345,4 @@ MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
|
||||
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
|
||||
MODULE_FIRMWARE(WL1271_FW_NAME);
|
||||
MODULE_FIRMWARE(WL1271_AP_FW_NAME);
|
||||
|
@ -110,9 +110,9 @@ static void wl1271_spi_reset(struct wl1271 *wl)
|
||||
spi_message_add_tail(&t, &m);
|
||||
|
||||
spi_sync(wl_to_spi(wl), &m);
|
||||
kfree(cmd);
|
||||
|
||||
wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
|
||||
kfree(cmd);
|
||||
}
|
||||
|
||||
static void wl1271_spi_init(struct wl1271 *wl)
|
||||
@ -495,4 +495,5 @@ MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
|
||||
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
|
||||
MODULE_FIRMWARE(WL1271_FW_NAME);
|
||||
MODULE_FIRMWARE(WL1271_AP_FW_NAME);
|
||||
MODULE_ALIAS("spi:wl1271");
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "io.h"
|
||||
@ -30,6 +31,23 @@
|
||||
#include "ps.h"
|
||||
#include "tx.h"
|
||||
|
||||
static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id)
|
||||
{
|
||||
int ret;
|
||||
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
|
||||
|
||||
if (is_ap)
|
||||
ret = wl1271_cmd_set_ap_default_wep_key(wl, id);
|
||||
else
|
||||
ret = wl1271_cmd_set_sta_default_wep_key(wl, id);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
wl1271_debug(DEBUG_CRYPT, "default wep key idx: %d", (int)id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb)
|
||||
{
|
||||
int id;
|
||||
@ -99,7 +117,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
|
||||
{
|
||||
struct timespec ts;
|
||||
struct wl1271_tx_hw_descr *desc;
|
||||
int pad, ac;
|
||||
int pad, ac, rate_idx;
|
||||
s64 hosttime;
|
||||
u16 tx_attr;
|
||||
|
||||
@ -117,7 +135,11 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
|
||||
getnstimeofday(&ts);
|
||||
hosttime = (timespec_to_ns(&ts) >> 10);
|
||||
desc->start_time = cpu_to_le32(hosttime - wl->time_offset);
|
||||
desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU);
|
||||
|
||||
if (wl->bss_type != BSS_TYPE_AP_BSS)
|
||||
desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU);
|
||||
else
|
||||
desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU);
|
||||
|
||||
/* configure the tx attributes */
|
||||
tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
|
||||
@ -125,7 +147,41 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
|
||||
/* queue (we use same identifiers for tid's and ac's */
|
||||
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
|
||||
desc->tid = ac;
|
||||
desc->aid = TX_HW_DEFAULT_AID;
|
||||
|
||||
if (wl->bss_type != BSS_TYPE_AP_BSS) {
|
||||
desc->aid = TX_HW_DEFAULT_AID;
|
||||
|
||||
/* if the packets are destined for AP (have a STA entry)
|
||||
send them with AP rate policies, otherwise use default
|
||||
basic rates */
|
||||
if (control->control.sta)
|
||||
rate_idx = ACX_TX_AP_FULL_RATE;
|
||||
else
|
||||
rate_idx = ACX_TX_BASIC_RATE;
|
||||
} else {
|
||||
if (control->control.sta) {
|
||||
struct wl1271_station *wl_sta;
|
||||
|
||||
wl_sta = (struct wl1271_station *)
|
||||
control->control.sta->drv_priv;
|
||||
desc->hlid = wl_sta->hlid;
|
||||
rate_idx = ac;
|
||||
} else {
|
||||
struct ieee80211_hdr *hdr;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)
|
||||
(skb->data + sizeof(*desc));
|
||||
if (ieee80211_is_mgmt(hdr->frame_control)) {
|
||||
desc->hlid = WL1271_AP_GLOBAL_HLID;
|
||||
rate_idx = ACX_TX_AP_MODE_MGMT_RATE;
|
||||
} else {
|
||||
desc->hlid = WL1271_AP_BROADCAST_HLID;
|
||||
rate_idx = ACX_TX_AP_MODE_BCST_RATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY;
|
||||
desc->reserved = 0;
|
||||
|
||||
/* align the length (and store in terms of words) */
|
||||
@ -136,14 +192,12 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
|
||||
pad = pad - skb->len;
|
||||
tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
|
||||
|
||||
/* if the packets are destined for AP (have a STA entry) send them
|
||||
with AP rate policies, otherwise use default basic rates */
|
||||
if (control->control.sta)
|
||||
tx_attr |= ACX_TX_AP_FULL_RATE << TX_HW_ATTR_OFST_RATE_POLICY;
|
||||
|
||||
desc->tx_attr = cpu_to_le16(tx_attr);
|
||||
|
||||
wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad);
|
||||
wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d "
|
||||
"tx_attr: 0x%x len: %d life: %d mem: %d", pad, desc->hlid,
|
||||
le16_to_cpu(desc->tx_attr), le16_to_cpu(desc->length),
|
||||
le16_to_cpu(desc->life_time), desc->total_mem_blocks);
|
||||
}
|
||||
|
||||
/* caller must hold wl->mutex */
|
||||
@ -153,7 +207,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
|
||||
struct ieee80211_tx_info *info;
|
||||
u32 extra = 0;
|
||||
int ret = 0;
|
||||
u8 idx;
|
||||
u32 total_len;
|
||||
|
||||
if (!skb)
|
||||
@ -166,11 +219,15 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
|
||||
extra = WL1271_TKIP_IV_SPACE;
|
||||
|
||||
if (info->control.hw_key) {
|
||||
idx = info->control.hw_key->hw_key_idx;
|
||||
bool is_wep;
|
||||
u8 idx = info->control.hw_key->hw_key_idx;
|
||||
u32 cipher = info->control.hw_key->cipher;
|
||||
|
||||
/* FIXME: do we have to do this if we're not using WEP? */
|
||||
if (unlikely(wl->default_key != idx)) {
|
||||
ret = wl1271_cmd_set_default_wep_key(wl, idx);
|
||||
is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) ||
|
||||
(cipher == WLAN_CIPHER_SUITE_WEP104);
|
||||
|
||||
if (unlikely(is_wep && wl->default_key != idx)) {
|
||||
ret = wl1271_set_default_wep_key(wl, idx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
wl->default_key = idx;
|
||||
@ -303,7 +360,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
|
||||
woken_up = true;
|
||||
|
||||
wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates);
|
||||
wl1271_acx_rate_policies(wl);
|
||||
wl1271_acx_sta_rate_policies(wl);
|
||||
}
|
||||
|
||||
while ((skb = wl1271_skb_dequeue(wl))) {
|
||||
@ -521,3 +578,21 @@ void wl1271_tx_flush(struct wl1271 *wl)
|
||||
|
||||
wl1271_warning("Unable to flush all TX buffers, timed out.");
|
||||
}
|
||||
|
||||
u32 wl1271_tx_min_rate_get(struct wl1271 *wl)
|
||||
{
|
||||
int i;
|
||||
u32 rate = 0;
|
||||
|
||||
if (!wl->basic_rate_set) {
|
||||
WARN_ON(1);
|
||||
wl->basic_rate_set = wl->conf.tx.basic_rate;
|
||||
}
|
||||
|
||||
for (i = 0; !rate; i++) {
|
||||
if ((wl->basic_rate_set >> i) & 0x1)
|
||||
rate = 1 << i;
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
#define TX_HW_BLOCK_SIZE 252
|
||||
|
||||
#define TX_HW_MGMT_PKT_LIFETIME_TU 2000
|
||||
#define TX_HW_AP_MODE_PKT_LIFETIME_TU 8000
|
||||
/* The chipset reference driver states, that the "aid" value 1
|
||||
* is for infra-BSS, but is still always used */
|
||||
#define TX_HW_DEFAULT_AID 1
|
||||
@ -77,8 +78,12 @@ struct wl1271_tx_hw_descr {
|
||||
u8 id;
|
||||
/* The packet TID value (as User-Priority) */
|
||||
u8 tid;
|
||||
/* Identifier of the remote STA in IBSS, 1 in infra-BSS */
|
||||
u8 aid;
|
||||
union {
|
||||
/* STA - Identifier of the remote STA in IBSS, 1 in infra-BSS */
|
||||
u8 aid;
|
||||
/* AP - host link ID (HLID) */
|
||||
u8 hlid;
|
||||
} __packed;
|
||||
u8 reserved;
|
||||
} __packed;
|
||||
|
||||
@ -146,5 +151,6 @@ void wl1271_tx_reset(struct wl1271 *wl);
|
||||
void wl1271_tx_flush(struct wl1271 *wl);
|
||||
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
|
||||
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
|
||||
u32 wl1271_tx_min_rate_get(struct wl1271 *wl);
|
||||
|
||||
#endif
|
||||
|
@ -38,6 +38,13 @@
|
||||
#define DRIVER_NAME "wl1271"
|
||||
#define DRIVER_PREFIX DRIVER_NAME ": "
|
||||
|
||||
/*
|
||||
* FW versions support BA 11n
|
||||
* versions marks x.x.x.50-60.x
|
||||
*/
|
||||
#define WL12XX_BA_SUPPORT_FW_COST_VER2_START 50
|
||||
#define WL12XX_BA_SUPPORT_FW_COST_VER2_END 60
|
||||
|
||||
enum {
|
||||
DEBUG_NONE = 0,
|
||||
DEBUG_IRQ = BIT(0),
|
||||
@ -57,6 +64,8 @@ enum {
|
||||
DEBUG_SDIO = BIT(14),
|
||||
DEBUG_FILTERS = BIT(15),
|
||||
DEBUG_ADHOC = BIT(16),
|
||||
DEBUG_AP = BIT(17),
|
||||
DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP),
|
||||
DEBUG_ALL = ~0,
|
||||
};
|
||||
|
||||
@ -103,16 +112,27 @@ extern u32 wl12xx_debug_level;
|
||||
true); \
|
||||
} while (0)
|
||||
|
||||
#define WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \
|
||||
#define WL1271_DEFAULT_STA_RX_CONFIG (CFG_UNI_FILTER_EN | \
|
||||
CFG_BSSID_FILTER_EN | \
|
||||
CFG_MC_FILTER_EN)
|
||||
|
||||
#define WL1271_DEFAULT_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \
|
||||
#define WL1271_DEFAULT_STA_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \
|
||||
CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
|
||||
CFG_RX_CTL_EN | CFG_RX_BCN_EN | \
|
||||
CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
|
||||
|
||||
#define WL1271_DEFAULT_AP_RX_CONFIG 0
|
||||
|
||||
#define WL1271_DEFAULT_AP_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PREQ_EN | \
|
||||
CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
|
||||
CFG_RX_CTL_EN | CFG_RX_AUTH_EN | \
|
||||
CFG_RX_ASSOC_EN)
|
||||
|
||||
|
||||
|
||||
#define WL1271_FW_NAME "wl1271-fw.bin"
|
||||
#define WL1271_AP_FW_NAME "wl1271-fw-ap.bin"
|
||||
|
||||
#define WL1271_NVS_NAME "wl1271-nvs.bin"
|
||||
|
||||
#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
|
||||
@ -129,6 +149,14 @@ extern u32 wl12xx_debug_level;
|
||||
#define WL1271_DEFAULT_BEACON_INT 100
|
||||
#define WL1271_DEFAULT_DTIM_PERIOD 1
|
||||
|
||||
#define WL1271_AP_GLOBAL_HLID 0
|
||||
#define WL1271_AP_BROADCAST_HLID 1
|
||||
#define WL1271_AP_STA_HLID_START 2
|
||||
|
||||
#define WL1271_AP_BSS_INDEX 0
|
||||
#define WL1271_AP_DEF_INACTIV_SEC 300
|
||||
#define WL1271_AP_DEF_BEACON_EXP 20
|
||||
|
||||
#define ACX_TX_DESCRIPTORS 32
|
||||
|
||||
#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
|
||||
@ -161,10 +189,13 @@ struct wl1271_partition_set {
|
||||
|
||||
struct wl1271;
|
||||
|
||||
#define WL12XX_NUM_FW_VER 5
|
||||
|
||||
/* FIXME: I'm not sure about this structure name */
|
||||
struct wl1271_chip {
|
||||
u32 id;
|
||||
char fw_ver[21];
|
||||
char fw_ver_str[ETHTOOL_BUSINFO_LEN];
|
||||
unsigned int fw_ver[WL12XX_NUM_FW_VER];
|
||||
};
|
||||
|
||||
struct wl1271_stats {
|
||||
@ -178,6 +209,11 @@ struct wl1271_stats {
|
||||
#define NUM_TX_QUEUES 4
|
||||
#define NUM_RX_PKT_DESC 8
|
||||
|
||||
#define AP_MAX_STATIONS 5
|
||||
|
||||
/* Broadcast and Global links + links to stations */
|
||||
#define AP_MAX_LINKS (AP_MAX_STATIONS + 2)
|
||||
|
||||
/* FW status registers */
|
||||
struct wl1271_fw_status {
|
||||
__le32 intr;
|
||||
@ -188,7 +224,18 @@ struct wl1271_fw_status {
|
||||
__le32 rx_pkt_descs[NUM_RX_PKT_DESC];
|
||||
__le32 tx_released_blks[NUM_TX_QUEUES];
|
||||
__le32 fw_localtime;
|
||||
__le32 padding[2];
|
||||
|
||||
/* Next fields valid only in AP FW */
|
||||
|
||||
/*
|
||||
* A bitmap (where each bit represents a single HLID)
|
||||
* to indicate if the station is in PS mode.
|
||||
*/
|
||||
__le32 link_ps_bitmap;
|
||||
|
||||
/* Number of freed MBs per HLID */
|
||||
u8 tx_lnk_free_blks[AP_MAX_LINKS];
|
||||
u8 padding_1[1];
|
||||
} __packed;
|
||||
|
||||
struct wl1271_rx_mem_pool_addr {
|
||||
@ -218,6 +265,19 @@ struct wl1271_if_operations {
|
||||
void (*disable_irq)(struct wl1271 *wl);
|
||||
};
|
||||
|
||||
#define MAX_NUM_KEYS 14
|
||||
#define MAX_KEY_SIZE 32
|
||||
|
||||
struct wl1271_ap_key {
|
||||
u8 id;
|
||||
u8 key_type;
|
||||
u8 key_size;
|
||||
u8 key[MAX_KEY_SIZE];
|
||||
u8 hlid;
|
||||
u32 tx_seq_32;
|
||||
u16 tx_seq_16;
|
||||
};
|
||||
|
||||
struct wl1271 {
|
||||
struct platform_device *plat_dev;
|
||||
struct ieee80211_hw *hw;
|
||||
@ -251,6 +311,7 @@ struct wl1271 {
|
||||
#define WL1271_FLAG_PSPOLL_FAILURE (12)
|
||||
#define WL1271_FLAG_STA_STATE_SENT (13)
|
||||
#define WL1271_FLAG_FW_TX_BUSY (14)
|
||||
#define WL1271_FLAG_AP_STARTED (15)
|
||||
unsigned long flags;
|
||||
|
||||
struct wl1271_partition_set part;
|
||||
@ -262,6 +323,7 @@ struct wl1271 {
|
||||
|
||||
u8 *fw;
|
||||
size_t fw_len;
|
||||
u8 fw_bss_type;
|
||||
struct wl1271_nvs_file *nvs;
|
||||
size_t nvs_len;
|
||||
|
||||
@ -378,7 +440,6 @@ struct wl1271 {
|
||||
int last_rssi_event;
|
||||
|
||||
struct wl1271_stats stats;
|
||||
struct dentry *rootdir;
|
||||
|
||||
__le32 buffer_32;
|
||||
u32 buffer_cmd;
|
||||
@ -400,6 +461,23 @@ struct wl1271 {
|
||||
|
||||
/* Most recently reported noise in dBm */
|
||||
s8 noise;
|
||||
|
||||
/* map for HLIDs of associated stations - when operating in AP mode */
|
||||
unsigned long ap_hlid_map[BITS_TO_LONGS(AP_MAX_STATIONS)];
|
||||
|
||||
/* recoreded keys for AP-mode - set here before AP startup */
|
||||
struct wl1271_ap_key *recorded_ap_keys[MAX_NUM_KEYS];
|
||||
|
||||
/* bands supported by this instance of wl12xx */
|
||||
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
|
||||
|
||||
/* RX BA constraint value */
|
||||
bool ba_support;
|
||||
u8 ba_rx_bitmap;
|
||||
};
|
||||
|
||||
struct wl1271_station {
|
||||
u8 hlid;
|
||||
};
|
||||
|
||||
int wl1271_plt_start(struct wl1271 *wl);
|
||||
|
@ -138,13 +138,13 @@ struct wl12xx_arp_rsp_template {
|
||||
struct ieee80211_hdr_3addr hdr;
|
||||
|
||||
u8 llc_hdr[sizeof(rfc1042_header)];
|
||||
u16 llc_type;
|
||||
__be16 llc_type;
|
||||
|
||||
struct arphdr arp_hdr;
|
||||
u8 sender_hw[ETH_ALEN];
|
||||
u32 sender_ip;
|
||||
__be32 sender_ip;
|
||||
u8 target_hw[ETH_ALEN];
|
||||
u32 target_ip;
|
||||
__be32 target_ip;
|
||||
} __packed;
|
||||
|
||||
|
||||
@ -160,4 +160,9 @@ struct wl12xx_probe_resp_template {
|
||||
struct wl12xx_ie_country country;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_disconn_template {
|
||||
struct ieee80211_header header;
|
||||
__le16 disconn_reason;
|
||||
} __packed;
|
||||
|
||||
#endif
|
||||
|
@ -178,6 +178,11 @@ struct ieee80211_radiotap_header {
|
||||
*
|
||||
* Number of unicast retries a transmitted frame used.
|
||||
*
|
||||
* IEEE80211_RADIOTAP_MCS u8, u8, u8 unitless
|
||||
*
|
||||
* Contains a bitmap of known fields/flags, the flags, and
|
||||
* the MCS index.
|
||||
*
|
||||
*/
|
||||
enum ieee80211_radiotap_type {
|
||||
IEEE80211_RADIOTAP_TSFT = 0,
|
||||
@ -199,6 +204,8 @@ enum ieee80211_radiotap_type {
|
||||
IEEE80211_RADIOTAP_RTS_RETRIES = 16,
|
||||
IEEE80211_RADIOTAP_DATA_RETRIES = 17,
|
||||
|
||||
IEEE80211_RADIOTAP_MCS = 19,
|
||||
|
||||
/* valid in every it_present bitmap, even vendor namespaces */
|
||||
IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29,
|
||||
IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30,
|
||||
@ -245,6 +252,24 @@ enum ieee80211_radiotap_type {
|
||||
#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
|
||||
#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
|
||||
|
||||
|
||||
/* For IEEE80211_RADIOTAP_MCS */
|
||||
#define IEEE80211_RADIOTAP_MCS_HAVE_BW 0x01
|
||||
#define IEEE80211_RADIOTAP_MCS_HAVE_MCS 0x02
|
||||
#define IEEE80211_RADIOTAP_MCS_HAVE_GI 0x04
|
||||
#define IEEE80211_RADIOTAP_MCS_HAVE_FMT 0x08
|
||||
#define IEEE80211_RADIOTAP_MCS_HAVE_FEC 0x10
|
||||
|
||||
#define IEEE80211_RADIOTAP_MCS_BW_MASK 0x03
|
||||
#define IEEE80211_RADIOTAP_MCS_BW_20 0
|
||||
#define IEEE80211_RADIOTAP_MCS_BW_40 1
|
||||
#define IEEE80211_RADIOTAP_MCS_BW_20L 2
|
||||
#define IEEE80211_RADIOTAP_MCS_BW_20U 3
|
||||
#define IEEE80211_RADIOTAP_MCS_SGI 0x04
|
||||
#define IEEE80211_RADIOTAP_MCS_FMT_GF 0x08
|
||||
#define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10
|
||||
|
||||
|
||||
/* Ugly macro to convert literal channel numbers into their mhz equivalents
|
||||
* There are certianly some conditions that will break this (like feeding it '30')
|
||||
* but they shouldn't arise since nothing talks on channel 30. */
|
||||
|
@ -81,6 +81,8 @@ static ssize_t ieee80211_if_fmt_##name( \
|
||||
IEEE80211_IF_FMT(name, field, "%d\n")
|
||||
#define IEEE80211_IF_FMT_HEX(name, field) \
|
||||
IEEE80211_IF_FMT(name, field, "%#x\n")
|
||||
#define IEEE80211_IF_FMT_LHEX(name, field) \
|
||||
IEEE80211_IF_FMT(name, field, "%#lx\n")
|
||||
#define IEEE80211_IF_FMT_SIZE(name, field) \
|
||||
IEEE80211_IF_FMT(name, field, "%zd\n")
|
||||
|
||||
@ -145,6 +147,8 @@ IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ],
|
||||
HEX);
|
||||
IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ],
|
||||
HEX);
|
||||
IEEE80211_IF_FILE(flags, flags, HEX);
|
||||
IEEE80211_IF_FILE(state, state, LHEX);
|
||||
|
||||
/* STA attributes */
|
||||
IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
|
||||
@ -283,6 +287,8 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
|
||||
static void add_sta_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_ADD(drop_unencrypted);
|
||||
DEBUGFS_ADD(flags);
|
||||
DEBUGFS_ADD(state);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
|
||||
|
||||
@ -296,6 +302,8 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
|
||||
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_ADD(drop_unencrypted);
|
||||
DEBUGFS_ADD(flags);
|
||||
DEBUGFS_ADD(state);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
|
||||
|
||||
@ -307,6 +315,8 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
|
||||
static void add_wds_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_ADD(drop_unencrypted);
|
||||
DEBUGFS_ADD(flags);
|
||||
DEBUGFS_ADD(state);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
|
||||
|
||||
@ -316,12 +326,16 @@ static void add_wds_files(struct ieee80211_sub_if_data *sdata)
|
||||
static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_ADD(drop_unencrypted);
|
||||
DEBUGFS_ADD(flags);
|
||||
DEBUGFS_ADD(state);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
|
||||
}
|
||||
|
||||
static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_ADD(flags);
|
||||
DEBUGFS_ADD(state);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
|
@ -601,6 +601,14 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP) {
|
||||
/* If an AP vif is found, then disable PS
|
||||
* by setting the count to zero thereby setting
|
||||
* ps_sdata to NULL.
|
||||
*/
|
||||
count = 0;
|
||||
break;
|
||||
}
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
continue;
|
||||
found = sdata;
|
||||
|
@ -85,6 +85,9 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local,
|
||||
if (len & 1) /* padding for RX_FLAGS if necessary */
|
||||
len++;
|
||||
|
||||
if (status->flag & RX_FLAG_HT) /* HT info */
|
||||
len += 3;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -193,6 +196,20 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
|
||||
rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP;
|
||||
put_unaligned_le16(rx_flags, pos);
|
||||
pos += 2;
|
||||
|
||||
if (status->flag & RX_FLAG_HT) {
|
||||
rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS);
|
||||
*pos++ = IEEE80211_RADIOTAP_MCS_HAVE_MCS |
|
||||
IEEE80211_RADIOTAP_MCS_HAVE_GI |
|
||||
IEEE80211_RADIOTAP_MCS_HAVE_BW;
|
||||
*pos = 0;
|
||||
if (status->flag & RX_FLAG_SHORT_GI)
|
||||
*pos |= IEEE80211_RADIOTAP_MCS_SGI;
|
||||
if (status->flag & RX_FLAG_40MHZ)
|
||||
*pos |= IEEE80211_RADIOTAP_MCS_BW_40;
|
||||
pos++;
|
||||
*pos++ = status->rate_idx;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user