aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath.h28
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c32
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h2
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig3
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile3
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h130
-rw-r--r--drivers/net/wireless/ath/ath9k/common.c286
-rw-r--r--drivers/net/wireless/ath/ath9k/common.h123
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c243
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c313
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/virtual.c79
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c21
17 files changed, 771 insertions, 518 deletions
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index 5e19a7330d39..9e05648356fe 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -21,8 +21,28 @@
#include <linux/if_ether.h>
#include <net/mac80211.h>
+/*
+ * The key cache is used for h/w cipher state and also for
+ * tracking station state such as the current tx antenna.
+ * We also setup a mapping table between key cache slot indices
+ * and station state to short-circuit node lookups on rx.
+ * Different parts have different size key caches. We handle
+ * up to ATH_KEYMAX entries (could dynamically allocate state).
+ */
+#define ATH_KEYMAX 128 /* max key cache size we handle */
+
static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+struct ath_ani {
+ bool caldone;
+ int16_t noise_floor;
+ unsigned int longcal_timer;
+ unsigned int shortcal_timer;
+ unsigned int resetcal_timer;
+ unsigned int checkani_timer;
+ struct timer_list timer;
+};
+
enum ath_device_state {
ATH_HW_UNAVAILABLE,
ATH_HW_INITIALIZED,
@@ -66,6 +86,8 @@ struct ath_common {
int debug_mask;
enum ath_device_state state;
+ struct ath_ani ani;
+
u16 cachelsz;
u16 curaid;
u8 macaddr[ETH_ALEN];
@@ -75,6 +97,12 @@ struct ath_common {
u8 tx_chainmask;
u8 rx_chainmask;
+ u32 rx_bufsize;
+
+ u32 keymax;
+ DECLARE_BITMAP(keymap, ATH_KEYMAX);
+ u8 splitmic;
+
struct ath_regulatory regulatory;
const struct ath_ops *ops;
const struct ath_bus_ops *bus_ops;
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index cb3dc892d697..a4c086f069b1 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -323,10 +323,13 @@ static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
static inline void ath5k_rxbuf_free(struct ath5k_softc *sc,
struct ath5k_buf *bf)
{
+ struct ath5k_hw *ah = sc->ah;
+ struct ath_common *common = ath5k_hw_common(ah);
+
BUG_ON(!bf);
if (!bf->skb)
return;
- pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize,
+ pci_unmap_single(sc->pdev, bf->skbaddr, common->rx_bufsize,
PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(bf->skb);
bf->skb = NULL;
@@ -1181,17 +1184,18 @@ struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr)
* fake physical layer header at the start.
*/
skb = ath_rxbuf_alloc(common,
- sc->rxbufsize + common->cachelsz - 1,
+ common->rx_bufsize,
GFP_ATOMIC);
if (!skb) {
ATH5K_ERR(sc, "can't alloc skbuff of size %u\n",
- sc->rxbufsize + common->cachelsz - 1);
+ common->rx_bufsize);
return NULL;
}
*skb_addr = pci_map_single(sc->pdev,
- skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE);
+ skb->data, common->rx_bufsize,
+ PCI_DMA_FROMDEVICE);
if (unlikely(pci_dma_mapping_error(sc->pdev, *skb_addr))) {
ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__);
dev_kfree_skb(skb);
@@ -1631,10 +1635,10 @@ ath5k_rx_start(struct ath5k_softc *sc)
struct ath5k_buf *bf;
int ret;
- sc->rxbufsize = roundup(IEEE80211_MAX_LEN, common->cachelsz);
+ common->rx_bufsize = roundup(IEEE80211_MAX_LEN, common->cachelsz);
- ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n",
- common->cachelsz, sc->rxbufsize);
+ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rx_bufsize %u\n",
+ common->cachelsz, common->rx_bufsize);
spin_lock_bh(&sc->rxbuflock);
sc->rxlink = NULL;
@@ -1679,6 +1683,8 @@ static unsigned int
ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds,
struct sk_buff *skb, struct ath5k_rx_status *rs)
{
+ struct ath5k_hw *ah = sc->ah;
+ struct ath_common *common = ath5k_hw_common(ah);
struct ieee80211_hdr *hdr = (void *)skb->data;
unsigned int keyix, hlen;
@@ -1695,7 +1701,7 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds,
skb->len >= hlen + 4) {
keyix = skb->data[hlen + 3] >> 6;
- if (test_bit(keyix, sc->keymap))
+ if (test_bit(keyix, common->keymap))
return RX_FLAG_DECRYPTED;
}
@@ -1769,6 +1775,8 @@ ath5k_tasklet_rx(unsigned long data)
struct sk_buff *skb, *next_skb;
dma_addr_t next_skb_addr;
struct ath5k_softc *sc = (void *)data;
+ struct ath5k_hw *ah = sc->ah;
+ struct ath_common *common = ath5k_hw_common(ah);
struct ath5k_buf *bf;
struct ath5k_desc *ds;
int ret;
@@ -1846,7 +1854,7 @@ accept:
if (!next_skb)
goto next;
- pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize,
+ pci_unmap_single(sc->pdev, bf->skbaddr, common->rx_bufsize,
PCI_DMA_FROMDEVICE);
skb_put(skb, rs.rs_datalen);
@@ -3032,6 +3040,8 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_key_conf *key)
{
struct ath5k_softc *sc = hw->priv;
+ struct ath5k_hw *ah = sc->ah;
+ struct ath_common *common = ath5k_hw_common(ah);
int ret = 0;
if (modparam_nohwcrypt)
@@ -3064,14 +3074,14 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ATH5K_ERR(sc, "can't set the key\n");
goto unlock;
}
- __set_bit(key->keyidx, sc->keymap);
+ __set_bit(key->keyidx, common->keymap);
key->hw_key_idx = key->keyidx;
key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV |
IEEE80211_KEY_FLAG_GENERATE_MMIC);
break;
case DISABLE_KEY:
ath5k_hw_reset_key(sc->ah, key->keyidx);
- __clear_bit(key->keyidx, sc->keymap);
+ __clear_bit(key->keyidx, common->keymap);
break;
default:
ret = -EINVAL;
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index b14ba07e9157..b72338c9bde7 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -153,8 +153,6 @@ struct ath5k_softc {
enum ath5k_int imask; /* interrupt mask copy */
- DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */
-
u8 bssidmask[ETH_ALEN];
unsigned int led_pin, /* GPIO pin for driving LED */
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 895990751d36..721ec5ee381d 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -3025,8 +3025,6 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower);
return -EINVAL;
}
- if (txpower == 0)
- txpower = AR5K_TUNE_DEFAULT_TXPOWER;
/* Reset TX power values */
memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index b735fb399fb1..006364f76bb4 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -1,5 +1,7 @@
config ATH9K_HW
tristate
+config ATH9K_COMMON
+ tristate
config ATH9K
tristate "Atheros 802.11n wireless cards support"
@@ -8,6 +10,7 @@ config ATH9K
select MAC80211_LEDS
select LEDS_CLASS
select NEW_LEDS
+ select ATH9K_COMMON
---help---
This module adds support for wireless adapters based on
Atheros IEEE 802.11n AR5008, AR9001 and AR9002 family
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 8caf2a8f8953..e53f9680a385 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -23,3 +23,6 @@ ath9k_hw-y:= hw.o \
mac.o \
obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
+
+obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o
+ath9k_common-y:= common.o
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 13dd0202d6b5..d9bcc3abb425 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -19,14 +19,16 @@
#include <linux/etherdevice.h>
#include <linux/device.h>
-#include <net/mac80211.h>
#include <linux/leds.h>
-#include "hw.h"
#include "rc.h"
#include "debug.h"
-#include "../ath.h"
-#include "../debug.h"
+#include "common.h"
+
+/*
+ * Header for the ath9k.ko driver core *only* -- hw code nor any other driver
+ * should rely on this file or its contents.
+ */
struct ath_node;
@@ -99,18 +101,6 @@ enum buffer_type {
BUF_XRETRY = BIT(5),
};
-struct ath_buf_state {
- int bfs_nframes;
- u16 bfs_al;
- u16 bfs_frmlen;
- int bfs_seqno;
- int bfs_tidno;
- int bfs_retries;
- u8 bf_type;
- u32 bfs_keyix;
- enum ath9k_key_type bfs_keytype;
-};
-
#define bf_nframes bf_state.bfs_nframes
#define bf_al bf_state.bfs_al
#define bf_frmlen bf_state.bfs_frmlen
@@ -125,21 +115,6 @@ struct ath_buf_state {
#define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY)
#define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY)
-struct ath_buf {
- struct list_head list;
- struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or
- an aggregate) */
- struct ath_buf *bf_next; /* next subframe in the aggregate */
- struct sk_buff *bf_mpdu; /* enclosing frame structure */
- struct ath_desc *bf_desc; /* virtual addr of desc */
- dma_addr_t bf_daddr; /* physical addr of desc */
- dma_addr_t bf_buf_addr; /* physical addr of data buffer */
- bool bf_stale;
- u16 bf_flags;
- struct ath_buf_state bf_state;
- dma_addr_t bf_dmacontext;
-};
-
struct ath_descdma {
struct ath_desc *dd_desc;
dma_addr_t dd_desc_paddr;
@@ -159,13 +134,9 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_MAX_ANTENNA 3
#define ATH_RXBUF 512
-#define WME_NUM_TID 16
#define ATH_TXBUF 512
#define ATH_TXMAXTRY 13
#define ATH_MGT_TXMAXTRY 4
-#define WME_BA_BMP_SIZE 64
-#define WME_MAX_BA WME_BA_BMP_SIZE
-#define ATH_TID_MAX_BUFS (2 * WME_MAX_BA)
#define TID_TO_WME_AC(_tid) \
((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
@@ -173,12 +144,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
(((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
WME_AC_VO)
-#define WME_AC_BE 0
-#define WME_AC_BK 1
-#define WME_AC_VI 2
-#define WME_AC_VO 3
-#define WME_NUM_AC 4
-
#define ADDBA_EXCHANGE_ATTEMPTS 10
#define ATH_AGGR_DELIM_SZ 4
#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */
@@ -252,30 +217,6 @@ struct ath_txq {
#define AGGR_ADDBA_COMPLETE BIT(2)
#define AGGR_ADDBA_PROGRESS BIT(3)
-struct ath_atx_tid {
- struct list_head list;
- struct list_head buf_q;
- struct ath_node *an;
- struct ath_atx_ac *ac;
- struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];
- u16 seq_start;
- u16 seq_next;
- u16 baw_size;
- int tidno;
- int baw_head; /* first un-acked tx buffer */
- int baw_tail; /* next unused tx buffer slot */
- int sched;
- int paused;
- u8 state;
-};
-
-struct ath_atx_ac {
- int sched;
- int qnum;
- struct list_head list;
- struct list_head tid_q;
-};
-
struct ath_tx_control {
struct ath_txq *txq;
int if_id;
@@ -286,29 +227,6 @@ struct ath_tx_control {
#define ATH_TX_XRETRY 0x02
#define ATH_TX_BAR 0x04
-#define ATH_RSSI_LPF_LEN 10
-#define RSSI_LPF_THRESHOLD -20
-#define ATH_RSSI_EP_MULTIPLIER (1<<7)
-#define ATH_EP_MUL(x, mul) ((x) * (mul))
-#define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
-#define ATH_LPF_RSSI(x, y, len) \
- ((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y))
-#define ATH_RSSI_LPF(x, y) do { \
- if ((y) >= RSSI_LPF_THRESHOLD) \
- x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
-} while (0)
-#define ATH_EP_RND(x, mul) \
- ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
-
-struct ath_node {
- struct ath_softc *an_sc;
- struct ath_atx_tid tid[WME_NUM_TID];
- struct ath_atx_ac ac[WME_NUM_AC];
- u16 maxampdu;
- u8 mpdudensity;
- int last_rssi;
-};
-
struct ath_tx {
u16 seq_no;
u32 txqsetup;
@@ -323,7 +241,6 @@ struct ath_rx {
u8 defant;
u8 rxotherant;
u32 *rxlink;
- int bufsize;
unsigned int rxfilter;
spinlock_t rxflushlock;
spinlock_t rxbuflock;
@@ -434,16 +351,6 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
-struct ath_ani {
- bool caldone;
- int16_t noise_floor;
- unsigned int longcal_timer;
- unsigned int shortcal_timer;
- unsigned int resetcal_timer;
- unsigned int checkani_timer;
- struct timer_list timer;
-};
-
/* Defines the BT AR_BT_COEX_WGHT used */
enum ath_stomp_type {
ATH_BTCOEX_NO_STOMP,
@@ -503,18 +410,7 @@ struct ath_led {
#define ATH_CHAN_MAX 255
#define IEEE80211_WEP_NKID 4 /* number of key ids */
-/*
- * The key cache is used for h/w cipher state and also for
- * tracking station state such as the current tx antenna.
- * We also setup a mapping table between key cache slot indices
- * and station state to short-circuit node lookups on rx.
- * Different parts have different size key caches. We handle
- * up to ATH_KEYMAX entries (could dynamically allocate state).
- */
-#define ATH_KEYMAX 128 /* max key cache size we handle */
-
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
-#define ATH_RSSI_DUMMY_MARKER 0x127
#define ATH_RATE_DUMMY_MARKER 0
#define SC_OP_INVALID BIT(0)
@@ -573,9 +469,6 @@ struct ath_softc {
u16 curtxpow;
u8 nbcnvifs;
u16 nvifs;
- u32 keymax;
- DECLARE_BITMAP(keymap, ATH_KEYMAX);
- u8 splitmic;
bool ps_enabled;
unsigned long ps_usecount;
enum ath9k_int imask;
@@ -601,7 +494,6 @@ struct ath_softc {
int beacon_interval;
- struct ath_ani ani;
#ifdef CONFIG_ATH9K_DEBUG
struct ath9k_debug debug;
#endif
@@ -620,6 +512,7 @@ struct ath_wiphy {
ATH_WIPHY_PAUSED,
ATH_WIPHY_SCAN,
} state;
+ bool idle;
int chan_idx;
int chan_is_ht;
};
@@ -654,8 +547,9 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
void ath_update_chainmask(struct ath_softc *sc, int is_ht);
int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
struct ath9k_channel *hchan);
-void ath_radio_enable(struct ath_softc *sc);
-void ath_radio_disable(struct ath_softc *sc);
+
+void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw);
+void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw);
#ifdef CONFIG_PCI
int ath_pci_init(void);
@@ -691,6 +585,10 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
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);
+void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue);
int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
#endif /* ATH9K_H */
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
new file mode 100644
index 000000000000..2f1e1612e2ad
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/*
+ * Module for common driver code between ath9k and ath9k_htc
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "common.h"
+
+MODULE_AUTHOR("Atheros Communications");
+MODULE_DESCRIPTION("Shared library for Atheros wireless 802.11n LAN cards.");
+MODULE_LICENSE("Dual BSD/GPL");
+
+/* Common RX processing */
+
+/* Assumes you've already done the endian to CPU conversion */
+static bool ath9k_rx_accept(struct ath_common *common,
+ struct sk_buff *skb,
+ struct ieee80211_rx_status *rxs,
+ struct ath_rx_status *rx_stats,
+ bool *decrypt_error)
+{
+ struct ath_hw *ah = common->ah;
+ struct ieee80211_hdr *hdr;
+ __le16 fc;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = hdr->frame_control;
+
+ if (!rx_stats->rs_datalen)
+ return false;
+ /*
+ * rs_status follows rs_datalen so if rs_datalen is too large
+ * we can take a hint that hardware corrupted it, so ignore
+ * those frames.
+ */
+ if (rx_stats->rs_datalen > common->rx_bufsize)
+ return false;
+
+ /*
+ * rs_more indicates chained descriptors which can be used
+ * to link buffers together for a sort of scatter-gather
+ * operation.
+ *
+ * The rx_stats->rs_status will not be set until the end of the
+ * chained descriptors so it can be ignored if rs_more is set. The
+ * rs_more will be false at the last element of the chained
+ * descriptors.
+ */
+ if (!rx_stats->rs_more && rx_stats->rs_status != 0) {
+ if (rx_stats->rs_status & ATH9K_RXERR_CRC)
+ rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
+ if (rx_stats->rs_status & ATH9K_RXERR_PHY)
+ return false;
+
+ if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
+ *decrypt_error = true;
+ } else if (rx_stats->rs_status & ATH9K_RXERR_MIC) {
+ if (ieee80211_is_ctl(fc))
+ /*
+ * Sometimes, we get invalid
+ * MIC failures on valid control frames.
+ * Remove these mic errors.
+ */
+ rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
+ else
+ rxs->flag |= RX_FLAG_MMIC_ERROR;
+ }
+ /*
+ * Reject error frames with the exception of
+ * decryption and MIC failures. For monitor mode,
+ * we also ignore the CRC error.
+ */
+ if (ah->opmode == NL80211_IFTYPE_MONITOR) {
+ if (rx_stats->rs_status &
+ ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
+ ATH9K_RXERR_CRC))
+ return false;
+ } else {
+ if (rx_stats->rs_status &
+ ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static u8 ath9k_process_rate(struct ath_common *common,
+ struct ieee80211_hw *hw,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rxs,
+ struct sk_buff *skb)
+{
+ struct ieee80211_supported_band *sband;
+ enum ieee80211_band band;
+ unsigned int i = 0;
+
+ band = hw->conf.channel->band;
+ sband = hw->wiphy->bands[band];
+
+ if (rx_stats->rs_rate & 0x80) {
+ /* HT rate */
+ rxs->flag |= RX_FLAG_HT;
+ if (rx_stats->rs_flags & ATH9K_RX_2040)
+ rxs->flag |= RX_FLAG_40MHZ;
+ if (rx_stats->rs_flags & ATH9K_RX_GI)
+ rxs->flag |= RX_FLAG_SHORT_GI;
+ return rx_stats->rs_rate & 0x7f;
+ }
+
+ for (i = 0; i < sband->n_bitrates; i++) {
+ if (sband->bitrates[i].hw_value == rx_stats->rs_rate)
+ return i;
+ if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) {
+ rxs->flag |= RX_FLAG_SHORTPRE;
+ return i;
+ }
+ }
+
+ /* No valid hardware bitrate found -- we should not get here */
+ ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected "
+ "0x%02x using 1 Mbit\n", rx_stats->rs_rate);
+ if ((common->debug_mask & ATH_DBG_XMIT))
+ print_hex_dump_bytes("", DUMP_PREFIX_NONE, skb->data, skb->len);
+
+ return 0;
+}
+
+static void ath9k_process_rssi(struct ath_common *common,
+ struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct ath_rx_status *rx_stats)
+{
+ struct ath_hw *ah = common->ah;
+ struct ieee80211_sta *sta;
+ struct ieee80211_hdr *hdr;
+ struct ath_node *an;
+ int last_rssi = ATH_RSSI_DUMMY_MARKER;
+ __le16 fc;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = hdr->frame_control;
+
+ rcu_read_lock();
+ /*
+ * XXX: use ieee80211_find_sta! This requires quite a bit of work
+ * under the current ath9k virtual wiphy implementation as we have
+ * no way of tying a vif to wiphy. Typically vifs are attached to
+ * at least one sdata of a wiphy on mac80211 but with ath9k virtual
+ * wiphy you'd have to iterate over every wiphy and each sdata.
+ */
+ sta = ieee80211_find_sta_by_hw(hw, hdr->addr2);
+ if (sta) {
+ an = (struct ath_node *) sta->drv_priv;
+ if (rx_stats->rs_rssi != ATH9K_RSSI_BAD &&
+ !rx_stats->rs_moreaggr)
+ ATH_RSSI_LPF(an->last_rssi, rx_stats->rs_rssi);
+ last_rssi = an->last_rssi;
+ }
+ rcu_read_unlock();
+
+ if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
+ rx_stats->rs_rssi = ATH_EP_RND(last_rssi,
+ ATH_RSSI_EP_MULTIPLIER);
+ if (rx_stats->rs_rssi < 0)
+ rx_stats->rs_rssi = 0;
+ else if (rx_stats->rs_rssi > 127)
+ rx_stats->rs_rssi = 127;
+
+ /* Update Beacon RSSI, this is used by ANI. */
+ if (ieee80211_is_beacon(fc))
+ ah->stats.avgbrssi = rx_stats->rs_rssi;
+}
+
+/*
+ * For Decrypt or Demic errors, we only mark packet status here and always push
+ * up the frame up to let mac80211 handle the actual error case, be it no
+ * decryption key or real decryption error. This let us keep statistics there.
+ */
+int ath9k_cmn_rx_skb_preprocess(struct ath_common *common,
+ struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rx_status,
+ bool *decrypt_error)
+{
+ struct ath_hw *ah = common->ah;
+
+ memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
+ if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error))
+ return -EINVAL;
+
+ ath9k_process_rssi(common, hw, skb, rx_stats);
+
+ rx_status->rate_idx = ath9k_process_rate(common, hw,
+ rx_stats, rx_status, skb);
+ rx_status->mactime = ath9k_hw_extend_tsf(ah, rx_stats->rs_tstamp);
+ rx_status->band = hw->conf.channel->band;
+ rx_status->freq = hw->conf.channel->center_freq;
+ rx_status->noise = common->ani.noise_floor;
+ rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi;
+ rx_status->antenna = rx_stats->rs_antenna;
+ rx_status->flag |= RX_FLAG_TSFT;
+
+ return 0;
+}
+EXPORT_SYMBOL(ath9k_cmn_rx_skb_preprocess);
+
+void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
+ struct sk_buff *skb,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rxs,
+ bool decrypt_error)
+{
+ struct ath_hw *ah = common->ah;
+ struct ieee80211_hdr *hdr;
+ int hdrlen, padsize;
+ u8 keyix;
+ __le16 fc;
+
+ /* see if any padding is done by the hw and remove it */
+ hdr = (struct ieee80211_hdr *) skb->data;
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ fc = hdr->frame_control;
+
+ /* The MAC header is padded to have 32-bit boundary if the
+ * packet payload is non-zero. The general calculation for
+ * padsize would take into account odd header lengths:
+ * padsize = (4 - hdrlen % 4) % 4; However, since only
+ * even-length headers are used, padding can only be 0 or 2
+ * bytes and we can optimize this a bit. In addition, we must
+ * not try to remove padding from short control frames that do
+ * not have payload. */
+ padsize = hdrlen & 3;
+ if (padsize && hdrlen >= 24) {
+ memmove(skb->data + padsize, skb->data, hdrlen);
+ skb_pull(skb, padsize);
+ }
+
+ keyix = rx_stats->rs_keyix;
+
+ if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) {
+ rxs->flag |= RX_FLAG_DECRYPTED;
+ } else if (ieee80211_has_protected(fc)
+ && !decrypt_error && skb->len >= hdrlen + 4) {
+ keyix = skb->data[hdrlen + 3] >> 6;
+
+ if (test_bit(keyix, common->keymap))
+ rxs->flag |= RX_FLAG_DECRYPTED;
+ }
+ if (ah->sw_mgmt_crypto &&
+ (rxs->flag & RX_FLAG_DECRYPTED) &&
+ ieee80211_is_mgmt(fc))
+ /* Use software decrypt for management frames. */
+ rxs->flag &= ~RX_FLAG_DECRYPTED;
+}
+EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess);
+
+static int __init ath9k_cmn_init(void)
+{
+ return 0;
+}
+module_init(ath9k_cmn_init);
+
+static void __exit ath9k_cmn_exit(void)
+{
+ return;
+}
+module_exit(ath9k_cmn_exit);
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h
new file mode 100644
index 000000000000..292e3d860c0e
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/common.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 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 <net/mac80211.h>
+
+#include "../ath.h"
+#include "../debug.h"
+
+#include "hw.h"
+
+/* Common header for Atheros 802.11n base driver cores */
+
+#define WME_NUM_TID 16
+#define WME_BA_BMP_SIZE 64
+#define WME_MAX_BA WME_BA_BMP_SIZE
+#define ATH_TID_MAX_BUFS (2 * WME_MAX_BA)
+
+#define WME_AC_BE 0
+#define WME_AC_BK 1
+#define WME_AC_VI 2
+#define WME_AC_VO 3
+#define WME_NUM_AC 4
+
+#define ATH_RSSI_DUMMY_MARKER 0x127
+#define ATH_RSSI_LPF_LEN 10
+#define RSSI_LPF_THRESHOLD -20
+#define ATH_RSSI_EP_MULTIPLIER (1<<7)
+#define ATH_EP_MUL(x, mul) ((x) * (mul))
+#define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
+#define ATH_LPF_RSSI(x, y, len) \
+ ((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y))
+#define ATH_RSSI_LPF(x, y) do { \
+ if ((y) >= RSSI_LPF_THRESHOLD) \
+ x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
+} while (0)
+#define ATH_EP_RND(x, mul) \
+ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+
+struct ath_atx_ac {
+ int sched;
+ int qnum;
+ struct list_head list;
+ struct list_head tid_q;
+};
+
+struct ath_buf_state {
+ int bfs_nframes;
+ u16 bfs_al;
+ u16 bfs_frmlen;
+ int bfs_seqno;
+ int bfs_tidno;
+ int bfs_retries;
+ u8 bf_type;
+ u32 bfs_keyix;
+ enum ath9k_key_type bfs_keytype;
+};
+
+struct ath_buf {
+ struct list_head list;
+ struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or
+ an aggregate) */
+ struct ath_buf *bf_next; /* next subframe in the aggregate */
+ struct sk_buff *bf_mpdu; /* enclosing frame structure */
+ struct ath_desc *bf_desc; /* virtual addr of desc */
+ dma_addr_t bf_daddr; /* physical addr of desc */
+ dma_addr_t bf_buf_addr; /* physical addr of data buffer */
+ bool bf_stale;
+ u16 bf_flags;
+ struct ath_buf_state bf_state;
+ dma_addr_t bf_dmacontext;
+};
+
+struct ath_atx_tid {
+ struct list_head list;
+ struct list_head buf_q;
+ struct ath_node *an;
+ struct ath_atx_ac *ac;
+ struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];
+ u16 seq_start;
+ u16 seq_next;
+ u16 baw_size;
+ int tidno;
+ int baw_head; /* first un-acked tx buffer */
+ int baw_tail; /* next unused tx buffer slot */
+ int sched;
+ int paused;
+ u8 state;
+};
+
+struct ath_node {
+ struct ath_common *common;
+ struct ath_atx_tid tid[WME_NUM_TID];
+ struct ath_atx_ac ac[WME_NUM_AC];
+ u16 maxampdu;
+ u8 mpdudensity;
+ int last_rssi;
+};
+
+int ath9k_cmn_rx_skb_preprocess(struct ath_common *common,
+ struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rx_status,
+ bool *decrypt_error);
+
+void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
+ struct sk_buff *skb,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rxs,
+ bool decrypt_error);
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 111ff049f75d..b25eedf67e0b 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -3710,6 +3710,21 @@ void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
}
EXPORT_SYMBOL(ath9k_hw_set_tsfadjust);
+/*
+ * Extend 15-bit time stamp from rx descriptor to
+ * a full 64-bit TSF using the current h/w TSF.
+*/
+u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp)
+{
+ u64 tsf;
+
+ tsf = ath9k_hw_gettsf64(ah);
+ if ((tsf & 0x7fff) < rstamp)
+ tsf -= 0x8000;
+ return (tsf & ~0x7fff) | rstamp;
+}
+EXPORT_SYMBOL(ath9k_hw_extend_tsf);
+
bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
{
if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) {
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index c7b0c4d5f75a..abaa2f09a3bc 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -432,7 +432,7 @@ struct ath9k_hw_version {
* Using de Bruijin sequence to to look up 1's index in a 32 bit number
* debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001
*/
-#define debruijn32 0x077CB531UL
+#define debruijn32 0x077CB531U
struct ath_gen_timer_configuration {
u32 next_addr;
@@ -689,6 +689,7 @@ u64 ath9k_hw_gettsf64(struct ath_hw *ah);
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);
+u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp);
bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us);
void ath9k_hw_set11nmac2040(struct ath_hw *ah);
void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 9fefc51aec17..3c02b977a613 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -405,34 +405,34 @@ static void ath_ani_calibrate(unsigned long data)
ath9k_ps_wakeup(sc);
/* Long calibration runs independently of short calibration. */
- if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
+ if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
longcal = true;
ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
- sc->ani.longcal_timer = timestamp;
+ common->ani.longcal_timer = timestamp;
}
/* Short calibration applies only while caldone is false */
- if (!sc->ani.caldone) {
- if ((timestamp - sc->ani.shortcal_timer) >= short_cal_interval) {
+ if (!common->ani.caldone) {
+ if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
shortcal = true;
ath_print(common, ATH_DBG_ANI,
"shortcal @%lu\n", jiffies);
- sc->ani.shortcal_timer = timestamp;
- sc->ani.resetcal_timer = timestamp;
+ common->ani.shortcal_timer = timestamp;
+ common->ani.resetcal_timer = timestamp;
}
} else {
- if ((timestamp - sc->ani.resetcal_timer) >=
+ if ((timestamp - common->ani.resetcal_timer) >=
ATH_RESTART_CALINTERVAL) {
- sc->ani.caldone = ath9k_hw_reset_calvalid(ah);
- if (sc->ani.caldone)
- sc->ani.resetcal_timer = timestamp;
+ common->ani.caldone = ath9k_hw_reset_calvalid(ah);
+ if (common->ani.caldone)
+ common->ani.resetcal_timer = timestamp;
}
}
/* Verify whether we must check ANI */
- if ((timestamp - sc->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
+ if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
aniflag = true;
- sc->ani.checkani_timer = timestamp;
+ common->ani.checkani_timer = timestamp;
}
/* Skip all processing if there's nothing to do. */
@@ -443,21 +443,21 @@ static void ath_ani_calibrate(unsigned long data)
/* Perform calibration if necessary */
if (longcal || shortcal) {
- sc->ani.caldone =
+ common->ani.caldone =
ath9k_hw_calibrate(ah,
ah->curchan,
common->rx_chainmask,
longcal);
if (longcal)
- sc->ani.noise_floor = ath9k_hw_getchan_noise(ah,
+ common->ani.noise_floor = ath9k_hw_getchan_noise(ah,
ah->curchan);
ath_print(common, ATH_DBG_ANI,
" calibrate chan %u/%x nf: %d\n",
ah->curchan->channel,
ah->curchan->channelFlags,
- sc->ani.noise_floor);
+ common->ani.noise_floor);
}
}
@@ -473,21 +473,21 @@ set_timer:
cal_interval = ATH_LONG_CALINTERVAL;
if (sc->sc_ah->config.enable_ani)
cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
- if (!sc->ani.caldone)
+ if (!common->ani.caldone)
cal_interval = min(cal_interval, (u32)short_cal_interval);
- mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
+ mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
}
-static void ath_start_ani(struct ath_softc *sc)
+static void ath_start_ani(struct ath_common *common)
{
unsigned long timestamp = jiffies_to_msecs(jiffies);
- sc->ani.longcal_timer = timestamp;
- sc->ani.shortcal_timer = timestamp;
- sc->ani.checkani_timer = timestamp;
+ common->ani.longcal_timer = timestamp;
+ common->ani.shortcal_timer = timestamp;
+ common->ani.checkani_timer = timestamp;
- mod_timer(&sc->ani.timer,
+ mod_timer(&common->ani.timer,
jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
}
@@ -733,10 +733,11 @@ static u32 ath_get_extchanmode(struct ath_softc *sc,
return chanmode;
}
-static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
+static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key,
struct ath9k_keyval *hk, const u8 *addr,
bool authenticator)
{
+ struct ath_hw *ah = common->ah;
const u8 *key_rxmic;
const u8 *key_txmic;
@@ -756,42 +757,42 @@ static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic));
}
- return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr);
+ return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
}
- if (!sc->splitmic) {
+ if (!common->splitmic) {
/* TX and RX keys share the same key cache entry. */
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
- return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr);
+ return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
}
/* Separate key cache entries for TX and RX */
/* TX key goes at first index, RX key at +32. */
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
- if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) {
+ if (!ath9k_hw_set_keycache_entry(ah, keyix, hk, NULL)) {
/* TX MIC entry failed. No need to proceed further */
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ ath_print(common, ATH_DBG_FATAL,
"Setting TX MIC Key Failed\n");
return 0;
}
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
/* XXX delete tx key on failure? */
- return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix + 32, hk, addr);
+ return ath9k_hw_set_keycache_entry(ah, keyix + 32, hk, addr);
}
-static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc)
+static int ath_reserve_key_cache_slot_tkip(struct ath_common *common)
{
int i;
- for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) {
- if (test_bit(i, sc->keymap) ||
- test_bit(i + 64, sc->keymap))
+ for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
+ if (test_bit(i, common->keymap) ||
+ test_bit(i + 64, common->keymap))
continue; /* At least one part of TKIP key allocated */
- if (sc->splitmic &&
- (test_bit(i + 32, sc->keymap) ||
- test_bit(i + 64 + 32, sc->keymap)))
+ if (common->splitmic &&
+ (test_bit(i + 32, common->keymap) ||
+ test_bit(i + 64 + 32, common->keymap)))
continue; /* At least one part of TKIP key allocated */
/* Found a free slot for a TKIP key */
@@ -800,60 +801,60 @@ static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc)
return -1;
}
-static int ath_reserve_key_cache_slot(struct ath_softc *sc)
+static int ath_reserve_key_cache_slot(struct ath_common *common)
{
int i;
/* First, try to find slots that would not be available for TKIP. */
- if (sc->splitmic) {
- for (i = IEEE80211_WEP_NKID; i < sc->keymax / 4; i++) {
- if (!test_bit(i, sc->keymap) &&
- (test_bit(i + 32, sc->keymap) ||
- test_bit(i + 64, sc->keymap) ||
- test_bit(i + 64 + 32, sc->keymap)))
+ if (common->splitmic) {
+ for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) {
+ if (!test_bit(i, common->keymap) &&
+ (test_bit(i + 32, common->keymap) ||
+ test_bit(i + 64, common->keymap) ||
+ test_bit(i + 64 + 32, common->keymap)))
return i;
- if (!test_bit(i + 32, sc->keymap) &&
- (test_bit(i, sc->keymap) ||
- test_bit(i + 64, sc->keymap) ||
- test_bit(i + 64 + 32, sc->keymap)))
+ if (!test_bit(i + 32, common->keymap) &&
+ (test_bit(i, common->keymap) ||
+ test_bit(i + 64, common->keymap) ||
+ test_bit(i + 64 + 32, common->keymap)))
return i + 32;
- if (!test_bit(i + 64, sc->keymap) &&
- (test_bit(i , sc->keymap) ||
- test_bit(i + 32, sc->keymap) ||
- test_bit(i + 64 + 32, sc->keymap)))
+ if (!test_bit(i + 64, common->keymap) &&
+ (test_bit(i , common->keymap) ||
+ test_bit(i + 32, common->keymap) ||
+ test_bit(i + 64 + 32, common->keymap)))
return i + 64;
- if (!test_bit(i + 64 + 32, sc->keymap) &&
- (test_bit(i, sc->keymap) ||
- test_bit(i + 32, sc->keymap) ||
- test_bit(i + 64, sc->keymap)))
+ if (!test_bit(i + 64 + 32, common->keymap) &&
+ (test_bit(i, common->keymap) ||
+ test_bit(i + 32, common->keymap) ||
+ test_bit(i + 64, common->keymap)))
return i + 64 + 32;
}
} else {
- for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) {
- if (!test_bit(i, sc->keymap) &&
- test_bit(i + 64, sc->keymap))
+ for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
+ if (!test_bit(i, common->keymap) &&
+ test_bit(i + 64, common->keymap))
return i;
- if (test_bit(i, sc->keymap) &&
- !test_bit(i + 64, sc->keymap))
+ if (test_bit(i, common->keymap) &&
+ !test_bit(i + 64, common->keymap))
return i + 64;
}
}
/* No partially used TKIP slots, pick any available slot */
- for (i = IEEE80211_WEP_NKID; i < sc->keymax; i++) {
+ for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) {
/* Do not allow slots that could be needed for TKIP group keys
* to be used. This limitation could be removed if we know that
* TKIP will not be used. */
if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
continue;
- if (sc->splitmic) {
+ if (common->splitmic) {
if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
continue;
if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
continue;
}
- if (!test_bit(i, sc->keymap))
+ if (!test_bit(i, common->keymap))
return i; /* Found a free slot for a key */
}
@@ -861,11 +862,12 @@ static int ath_reserve_key_cache_slot(struct ath_softc *sc)
return -1;
}
-static int ath_key_config(struct ath_softc *sc,
+static int ath_key_config(struct ath_common *common,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
+ struct ath_hw *ah = common->ah;
struct ath9k_keyval hk;
const u8 *mac = NULL;
int ret = 0;
@@ -911,48 +913,50 @@ static int ath_key_config(struct ath_softc *sc,
mac = sta->addr;
if (key->alg == ALG_TKIP)
- idx = ath_reserve_key_cache_slot_tkip(sc);
+ idx = ath_reserve_key_cache_slot_tkip(common);
else
- idx = ath_reserve_key_cache_slot(sc);
+ idx = ath_reserve_key_cache_slot(common);
if (idx < 0)
return -ENOSPC; /* no free key cache entries */
}
if (key->alg == ALG_TKIP)
- ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac,
+ ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
vif->type == NL80211_IFTYPE_AP);
else
- ret = ath9k_hw_set_keycache_entry(sc->sc_ah, idx, &hk, mac);
+ ret = ath9k_hw_set_keycache_entry(ah, idx, &hk, mac);
if (!ret)
return -EIO;
- set_bit(idx, sc->keymap);
+ set_bit(idx, common->keymap);
if (key->alg == ALG_TKIP) {
- set_bit(idx + 64, sc->keymap);
- if (sc->splitmic) {
- set_bit(idx + 32, sc->keymap);
- set_bit(idx + 64 + 32, sc->keymap);
+ set_bit(idx + 64, common->keymap);
+ if (common->splitmic) {
+ set_bit(idx + 32, common->keymap);
+ set_bit(idx + 64 + 32, common->keymap);
}
}
return idx;
}
-static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
+static void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key)
{
- ath9k_hw_keyreset(sc->sc_ah, key->hw_key_idx);
+ struct ath_hw *ah = common->ah;
+
+ ath9k_hw_keyreset(ah, key->hw_key_idx);
if (key->hw_key_idx < IEEE80211_WEP_NKID)
return;
- clear_bit(key->hw_key_idx, sc->keymap);
+ clear_bit(key->hw_key_idx, common->keymap);
if (key->alg != ALG_TKIP)
return;
- clear_bit(key->hw_key_idx + 64, sc->keymap);
- if (sc->splitmic) {
- clear_bit(key->hw_key_idx + 32, sc->keymap);
- clear_bit(key->hw_key_idx + 64 + 32, sc->keymap);
+ clear_bit(key->hw_key_idx + 64, common->keymap);
+ if (common->splitmic) {
+ clear_bit(key->hw_key_idx + 32, common->keymap);
+ clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
}
}
@@ -1023,12 +1027,12 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
/* Reset rssi stats */
sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
- ath_start_ani(sc);
+ ath_start_ani(common);
} else {
ath_print(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
common->curaid = 0;
/* Stop ANI */
- del_timer_sync(&sc->ani.timer);
+ del_timer_sync(&common->ani.timer);
}
}
@@ -1200,11 +1204,11 @@ fail:
ath_deinit_leds(sc);
}
-void ath_radio_enable(struct ath_softc *sc)
+void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
- struct ieee80211_channel *channel = sc->hw->conf.channel;
+ struct ieee80211_channel *channel = hw->conf.channel;
int r;
ath9k_ps_wakeup(sc);
@@ -1241,18 +1245,18 @@ void ath_radio_enable(struct ath_softc *sc)
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
ath9k_hw_set_gpio(ah, ah->led_pin, 0);
- ieee80211_wake_queues(sc->hw);
+ ieee80211_wake_queues(hw);
ath9k_ps_restore(sc);
}
-void ath_radio_disable(struct ath_softc *sc)
+void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
{
struct ath_hw *ah = sc->sc_ah;
- struct ieee80211_channel *channel = sc->hw->conf.channel;
+ struct ieee80211_channel *channel = hw->conf.channel;
int r;
ath9k_ps_wakeup(sc);
- ieee80211_stop_queues(sc->hw);
+ ieee80211_stop_queues(hw);
/* Disable LED */
ath9k_hw_set_gpio(ah, ah->led_pin, 1);
@@ -1266,7 +1270,7 @@ void ath_radio_disable(struct ath_softc *sc)
ath_flushrecv(sc); /* flush recv queue */
if (!ah->curchan)
- ah->curchan = ath_get_curchannel(sc, sc->hw);
+ ah->curchan = ath_get_curchannel(sc, hw);
spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, ah->curchan, false);
@@ -1679,19 +1683,19 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
}
/* Get the hardware key cache size. */
- sc->keymax = ah->caps.keycache_size;
- if (sc->keymax > ATH_KEYMAX) {
+ common->keymax = ah->caps.keycache_size;
+ if (common->keymax > ATH_KEYMAX) {
ath_print(common, ATH_DBG_ANY,
"Warning, using only %u entries in %u key cache\n",
- ATH_KEYMAX, sc->keymax);
- sc->keymax = ATH_KEYMAX;
+ ATH_KEYMAX, common->keymax);
+ common->keymax = ATH_KEYMAX;
}
/*
* Reset the key cache since some parts do not
* reset the contents on initial power up.
*/
- for (i = 0; i < sc->keymax; i++)
+ for (i = 0; i < common->keymax; i++)
ath9k_hw_keyreset(ah, (u16) i);
/* default to MONITOR mode */
@@ -1761,8 +1765,8 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
/* Initializes the noise floor to a reasonable default value.
* Later on this will be updated during ANI processing. */
- sc->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR;
- setup_timer(&sc->ani.timer, ath_ani_calibrate, (unsigned long)sc);
+ common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR;
+ setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
ATH9K_CIPHER_TKIP, NULL)) {
@@ -1788,7 +1792,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
ATH9K_CIPHER_MIC, NULL)
&& ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT,
0, NULL))
- sc->splitmic = 1;
+ common->splitmic = 1;
/* turn on mcast key search if possible */
if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
@@ -2634,7 +2638,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
if (conf->type == NL80211_IFTYPE_AP ||
conf->type == NL80211_IFTYPE_ADHOC ||
conf->type == NL80211_IFTYPE_MONITOR)
- ath_start_ani(sc);
+ ath_start_ani(common);
out:
mutex_unlock(&sc->mutex);
@@ -2655,7 +2659,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
mutex_lock(&sc->mutex);
/* Stop ANI */
- del_timer_sync(&sc->ani.timer);
+ del_timer_sync(&common->ani.timer);
/* Reclaim beacon resources */
if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
@@ -2688,23 +2692,38 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_conf *conf = &hw->conf;
struct ath_hw *ah = sc->sc_ah;
- bool all_wiphys_idle = false, disable_radio = false;
+ bool disable_radio;
mutex_lock(&sc->mutex);
- /* Leave this as the first check */
+ /*
+ * Leave this as the first check because we need to turn on the
+ * radio if it was disabled before prior to processing the rest
+ * of the changes. Likewise we must only disable the radio towards
+ * 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);
+
+ if (!idle && all_wiphys_idle)
+ enable_radio = true;
+
+ /*
+ * 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 (conf->flags & IEEE80211_CONF_IDLE){
- if (all_wiphys_idle)
- disable_radio = true;
- }
- else if (all_wiphys_idle) {
- ath_radio_enable(sc);
+ if (enable_radio) {
+ ath_radio_enable(sc, hw);
ath_print(common, ATH_DBG_CONFIG,
"not-idle: enabling radio\n");
}
@@ -2779,9 +2798,13 @@ skip_chan_change:
if (changed & IEEE80211_CONF_CHANGE_POWER)
sc->config.txpowlimit = 2 * conf->power_level;
+ spin_lock_bh(&sc->wiphy_lock);
+ disable_radio = ath9k_all_wiphys_idle(sc);
+ spin_unlock_bh(&sc->wiphy_lock);
+
if (disable_radio) {
ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
- ath_radio_disable(sc);
+ ath_radio_disable(sc, hw);
}
mutex_unlock(&sc->mutex);
@@ -2898,7 +2921,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
switch (cmd) {
case SET_KEY:
- ret = ath_key_config(sc, vif, sta, key);
+ ret = ath_key_config(common, vif, sta, key);
if (ret >= 0) {
key->hw_key_idx = ret;
/* push IV and Michael MIC generation to stack */
@@ -2911,7 +2934,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
}
break;
case DISABLE_KEY:
- ath_key_delete(sc, key);
+ ath_key_delete(common, key);
break;
default:
ret = -EINVAL;
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
index fa21a628ddd0..94cb9f8d2446 100644
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -19,6 +19,8 @@
#ifndef RC_H
#define RC_H
+#include "hw.h"
+
struct ath_softc;
#define ATH_RATE_MAX 30
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 355dd1834e1d..477365e5ae69 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -48,6 +48,7 @@ static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc,
static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_desc *ds;
struct sk_buff *skb;
@@ -62,11 +63,13 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
BUG_ON(skb == NULL);
ds->ds_vdata = skb->data;
- /* setup rx descriptors. The rx.bufsize here tells the harware
+ /*
+ * setup rx descriptors. The rx_bufsize here tells the hardware
* how much data it can DMA to us and that we are prepared
- * to process */
+ * to process
+ */
ath9k_hw_setuprxdesc(ah, ds,
- sc->rx.bufsize,
+ common->rx_bufsize,
0);
if (sc->rx.rxlink == NULL)
@@ -86,190 +89,6 @@ static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
sc->rx.rxotherant = 0;
}
-/*
- * Extend 15-bit time stamp from rx descriptor to
- * a full 64-bit TSF using the current h/w TSF.
-*/
-static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
-{
- u64 tsf;
-
- tsf = ath9k_hw_gettsf64(sc->sc_ah);
- if ((tsf & 0x7fff) < rstamp)
- tsf -= 0x8000;
- return (tsf & ~0x7fff) | rstamp;
-}
-
-/*
- * For Decrypt or Demic errors, we only mark packet status here and always push
- * up the frame up to let mac80211 handle the actual error case, be it no
- * decryption key or real decryption error. This let us keep statistics there.
- */
-static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
- struct ieee80211_rx_status *rx_status, bool *decrypt_error,
- struct ath_softc *sc)
-{
- struct ieee80211_hdr *hdr;
- u8 ratecode;
- __le16 fc;
- struct ieee80211_hw *hw;
- struct ieee80211_sta *sta;
- struct ath_node *an;
- int last_rssi = ATH_RSSI_DUMMY_MARKER;
-
-
- hdr = (struct ieee80211_hdr *)skb->data;
- fc = hdr->frame_control;
- memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
- hw = ath_get_virt_hw(sc, hdr);
-
- if (ds->ds_rxstat.rs_more) {
- /*
- * Frame spans multiple descriptors; this cannot happen yet
- * as we don't support jumbograms. If not in monitor mode,
- * discard the frame. Enable this if you want to see
- * error frames in Monitor mode.
- */
- if (sc->sc_ah->opmode != NL80211_IFTYPE_MONITOR)
- goto rx_next;
- } else if (ds->ds_rxstat.rs_status != 0) {
- if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
- rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
- if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY)
- goto rx_next;
-
- if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) {
- *decrypt_error = true;
- } else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) {
- if (ieee80211_is_ctl(fc))
- /*
- * Sometimes, we get invalid
- * MIC failures on valid control frames.
- * Remove these mic errors.
- */
- ds->ds_rxstat.rs_status &= ~ATH9K_RXERR_MIC;
- else
- rx_status->flag |= RX_FLAG_MMIC_ERROR;
- }
- /*
- * Reject error frames with the exception of
- * decryption and MIC failures. For monitor mode,
- * we also ignore the CRC error.
- */
- if (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR) {
- if (ds->ds_rxstat.rs_status &
- ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
- ATH9K_RXERR_CRC))
- goto rx_next;
- } else {
- if (ds->ds_rxstat.rs_status &
- ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
- goto rx_next;
- }
- }
- }
-
- ratecode = ds->ds_rxstat.rs_rate;
-
- if (ratecode & 0x80) {
- /* HT rate */
- rx_status->flag |= RX_FLAG_HT;
- if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040)
- rx_status->flag |= RX_FLAG_40MHZ;
- if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI)
- rx_status->flag |= RX_FLAG_SHORT_GI;
- rx_status->rate_idx = ratecode & 0x7f;
- } else {
- int i = 0, cur_band, n_rates;
-
- cur_band = hw->conf.channel->band;
- n_rates = sc->sbands[cur_band].n_bitrates;
-
- for (i = 0; i < n_rates; i++) {
- if (sc->sbands[cur_band].bitrates[i].hw_value ==
- ratecode) {
- rx_status->rate_idx = i;
- break;
- }
-
- if (sc->sbands[cur_band].bitrates[i].hw_value_short ==
- ratecode) {
- rx_status->rate_idx = i;
- rx_status->flag |= RX_FLAG_SHORTPRE;
- break;
- }
- }
- }
-
- rcu_read_lock();
- /* XXX: use ieee80211_find_sta! */
- sta = ieee80211_find_sta_by_hw(sc->hw, hdr->addr2);
- if (sta) {
- an = (struct ath_node *) sta->drv_priv;
- if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD &&
- !ds->ds_rxstat.rs_moreaggr)
- ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi);
- last_rssi = an->last_rssi;
- }
- rcu_read_unlock();
-
- if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
- ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi,
- ATH_RSSI_EP_MULTIPLIER);
- if (ds->ds_rxstat.rs_rssi < 0)
- ds->ds_rxstat.rs_rssi = 0;
- else if (ds->ds_rxstat.rs_rssi > 127)
- ds->ds_rxstat.rs_rssi = 127;
-
- /* Update Beacon RSSI, this is used by ANI. */
- if (ieee80211_is_beacon(fc))
- sc->sc_ah->stats.avgbrssi = ds->ds_rxstat.rs_rssi;
-
- rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
- rx_status->band = hw->conf.channel->band;
- rx_status->freq = hw->conf.channel->center_freq;
- rx_status->noise = sc->ani.noise_floor;
- rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + ds->ds_rxstat.rs_rssi;
- rx_status->antenna = ds->ds_rxstat.rs_antenna;
-
- /*
- * Theory for reporting quality:
- *
- * At a hardware RSSI of 45 you will be able to use MCS 7 reliably.
- * At a hardware RSSI of 45 you will be able to use MCS 15 reliably.
- * At a hardware RSSI of 35 you should be able use 54 Mbps reliably.
- *
- * MCS 7 is the highets MCS index usable by a 1-stream device.
- * MCS 15 is the highest MCS index usable by a 2-stream device.
- *
- * All ath9k devices are either 1-stream or 2-stream.
- *
- * How many bars you see is derived from the qual reporting.
- *
- * A more elaborate scheme can be used here but it requires tables
- * of SNR/throughput for each possible mode used. For the MCS table
- * you can refer to the wireless wiki:
- *
- * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n
- *
- */
- if (conf_is_ht(&hw->conf))
- rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45;
- else
- rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 35;
-
- /* rssi can be more than 45 though, anything above that
- * should be considered at 100% */
- if (rx_status->qual > 100)
- rx_status->qual = 100;
-
- rx_status->flag |= RX_FLAG_TSFT;
-
- return 1;
-rx_next:
- return 0;
-}
-
static void ath_opmode_init(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
@@ -307,11 +126,11 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
sc->sc_flags &= ~SC_OP_RXFLUSH;
spin_lock_init(&sc->rx.rxbuflock);
- sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
- min(common->cachelsz, (u16)64));
+ common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
+ min(common->cachelsz, (u16)64));
ath_print(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
- common->cachelsz, sc->rx.bufsize);
+ common->cachelsz, common->rx_bufsize);
/* Initialize rx descriptors */
@@ -324,7 +143,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
}
list_for_each_entry(bf, &sc->rx.rxbuf, list) {
- skb = ath_rxbuf_alloc(common, sc->rx.bufsize, GFP_KERNEL);
+ skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_KERNEL);
if (skb == NULL) {
error = -ENOMEM;
goto err;
@@ -332,7 +151,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
bf->bf_mpdu = skb;
bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
- sc->rx.bufsize,
+ common->rx_bufsize,
DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(sc->dev,
bf->bf_buf_addr))) {
@@ -356,6 +175,8 @@ err:
void ath_rx_cleanup(struct ath_softc *sc)
{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct sk_buff *skb;
struct ath_buf *bf;
@@ -363,7 +184,7 @@ void ath_rx_cleanup(struct ath_softc *sc)
skb = bf->bf_mpdu;
if (skb) {
dma_unmap_single(sc->dev, bf->bf_buf_addr,
- sc->rx.bufsize, DMA_FROM_DEVICE);
+ common->rx_bufsize, DMA_FROM_DEVICE);
dev_kfree_skb(skb);
}
}
@@ -616,8 +437,9 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
}
}
-static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb,
- struct ieee80211_rx_status *rx_status)
+static void ath_rx_send_to_mac80211(struct ieee80211_hw *hw,
+ struct ath_softc *sc, struct sk_buff *skb,
+ struct ieee80211_rx_status *rxs)
{
struct ieee80211_hdr *hdr;
@@ -637,19 +459,14 @@ static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb,
if (aphy == NULL)
continue;
nskb = skb_copy(skb, GFP_ATOMIC);
- if (nskb) {
- memcpy(IEEE80211_SKB_RXCB(nskb), rx_status,
- sizeof(*rx_status));
- ieee80211_rx(aphy->hw, nskb);
- }
+ if (!nskb)
+ continue;
+ ieee80211_rx(aphy->hw, nskb);
}
- memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
ieee80211_rx(sc->hw, skb);
- } else {
+ } else
/* Deliver unicast frames based on receiver address */
- memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
- ieee80211_rx(ath_get_virt_hw(sc, hdr), skb);
- }
+ ieee80211_rx(hw, skb);
}
int ath_rx_tasklet(struct ath_softc *sc, int flush)
@@ -660,15 +477,20 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
struct ath_buf *bf;
struct ath_desc *ds;
+ struct ath_rx_status *rx_stats;
struct sk_buff *skb = NULL, *requeue_skb;
- struct ieee80211_rx_status rx_status;
+ struct ieee80211_rx_status *rxs;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
+ /*
+ * The hw can techncically differ from common->hw when using ath9k
+ * 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_hdr *hdr;
- int hdrlen, padsize, retval;
+ int retval;
bool decrypt_error = false;
- u8 keyix;
- __le16 fc;
spin_lock_bh(&sc->rx.rxbuflock);
@@ -740,9 +562,15 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
* 2. requeueing the same buffer to h/w
*/
dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
- sc->rx.bufsize,
+ common->rx_bufsize,
DMA_FROM_DEVICE);
+ hdr = (struct ieee80211_hdr *) skb->data;
+ rxs = IEEE80211_SKB_RXCB(skb);
+
+ hw = ath_get_virt_hw(sc, hdr);
+ rx_stats = &ds->ds_rxstat;
+
/*
* If we're asked to flush receive queue, directly
* chain it back at the queue without processing it.
@@ -750,19 +578,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
if (flush)
goto requeue;
- if (!ds->ds_rxstat.rs_datalen)
- goto requeue;
-
- /* The status portion of the descriptor could get corrupted. */
- if (sc->rx.bufsize < ds->ds_rxstat.rs_datalen)
- goto requeue;
-
- if (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc))
+ retval = ath9k_cmn_rx_skb_preprocess(common, hw, skb, rx_stats,
+ rxs, &decrypt_error);
+ if (retval)
goto requeue;
/* Ensure we always have an skb to requeue once we are done
* processing the current buffer's skb */
- requeue_skb = ath_rxbuf_alloc(common, sc->rx.bufsize, GFP_ATOMIC);
+ requeue_skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_ATOMIC);
/* If there is no memory we ignore the current RX'd frame,
* tell hardware it can give us a new frame using the old
@@ -773,60 +596,26 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
/* Unmap the frame */
dma_unmap_single(sc->dev, bf->bf_buf_addr,
- sc->rx.bufsize,
+ common->rx_bufsize,
DMA_FROM_DEVICE);
- skb_put(skb, ds->ds_rxstat.rs_datalen);
-
- /* see if any padding is done by the hw and remove it */
- hdr = (struct ieee80211_hdr *)skb->data;
- hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- fc = hdr->frame_control;
-
- /* The MAC header is padded to have 32-bit boundary if the
- * packet payload is non-zero. The general calculation for
- * padsize would take into account odd header lengths:
- * padsize = (4 - hdrlen % 4) % 4; However, since only
- * even-length headers are used, padding can only be 0 or 2
- * bytes and we can optimize this a bit. In addition, we must
- * not try to remove padding from short control frames that do
- * not have payload. */
- padsize = hdrlen & 3;
- if (padsize && hdrlen >= 24) {
- memmove(skb->data + padsize, skb->data, hdrlen);
- skb_pull(skb, padsize);
- }
-
- keyix = ds->ds_rxstat.rs_keyix;
+ skb_put(skb, rx_stats->rs_datalen);
- if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) {
- rx_status.flag |= RX_FLAG_DECRYPTED;
- } else if (ieee80211_has_protected(fc)
- && !decrypt_error && skb->len >= hdrlen + 4) {
- keyix = skb->data[hdrlen + 3] >> 6;
-
- if (test_bit(keyix, sc->keymap))
- rx_status.flag |= RX_FLAG_DECRYPTED;
- }
- if (ah->sw_mgmt_crypto &&
- (rx_status.flag & RX_FLAG_DECRYPTED) &&
- ieee80211_is_mgmt(fc)) {
- /* Use software decrypt for management frames. */
- rx_status.flag &= ~RX_FLAG_DECRYPTED;
- }
+ ath9k_cmn_rx_skb_postprocess(common, skb, rx_stats,
+ rxs, decrypt_error);
/* We will now give hardware our shiny new allocated skb */
bf->bf_mpdu = requeue_skb;
bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data,
- sc->rx.bufsize,
- DMA_FROM_DEVICE);
+ common->rx_bufsize,
+ DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(sc->dev,
bf->bf_buf_addr))) {
dev_kfree_skb_any(requeue_skb);
bf->bf_mpdu = NULL;
ath_print(common, ATH_DBG_FATAL,
"dma_mapping_error() on RX\n");
- ath_rx_send_to_mac80211(sc, skb, &rx_status);
+ ath_rx_send_to_mac80211(hw, sc, skb, rxs);
break;
}
bf->bf_dmacontext = bf->bf_buf_addr;
@@ -837,7 +626,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
*/
if (sc->rx.defant != ds->ds_rxstat.rs_antenna) {
if (++sc->rx.rxotherant >= 3)
- ath_setdefantenna(sc, ds->ds_rxstat.rs_antenna);
+ ath_setdefantenna(sc, rx_stats->rs_antenna);
} else {
sc->rx.rxotherant = 0;
}
@@ -847,7 +636,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
SC_OP_WAIT_FOR_PSPOLL_DATA)))
ath_rx_ps(sc, skb);
- ath_rx_send_to_mac80211(sc, skb, &rx_status);
+ ath_rx_send_to_mac80211(hw, sc, skb, rxs);
requeue:
list_move_tail(&bf->list, &sc->rx.rxbuf);
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 061e12ce0b24..49ec25f020f0 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -971,10 +971,10 @@ enum {
#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_S 4
#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF 0x00000080
#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7
+#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00000400
+#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 10
#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB 0x00001000
#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S 12
-#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00001000
-#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 1
#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB 0x00008000
#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S 15
#define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index bc7d173b6fae..0a36b572294c 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -298,6 +298,7 @@ static void ath9k_wiphy_unpause_channel(struct ath_softc *sc)
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)
@@ -313,6 +314,10 @@ void ath9k_wiphy_chan_work(struct work_struct *work)
/* 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;
+
ath_update_chainmask(sc, sc->chan_is_ht);
if (ath_set_channel(sc, aphy->hw,
&sc->sc_ah->channels[sc->chan_idx]) < 0) {
@@ -521,8 +526,9 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy)
* frame being completed)
*/
spin_unlock_bh(&sc->wiphy_lock);
- ath_radio_disable(sc);
- ath_radio_enable(sc);
+ 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 */
@@ -668,15 +674,78 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
bool ath9k_all_wiphys_idle(struct ath_softc *sc)
{
unsigned int i;
- if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) {
+ 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->state != ATH_WIPHY_INACTIVE)
+ 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_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
+ "Marking %s as %s\n",
+ wiphy_name(aphy->hw->wiphy),
+ idle ? "idle" : "not-idle");
+}
+/* Only bother starting a queue on an active virtual wiphy */
+void ath_mac80211_start_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);
+
+ /* Start the primary wiphy */
+ if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) {
+ ieee80211_wake_queue(hw, skb_queue);
+ 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);
+ break;
+ }
+
+unlock:
+ spin_unlock_bh(&sc->wiphy_lock);
+}
+
+/* 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);
+}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 8e052f406c35..86b54ddd01cb 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -267,7 +267,10 @@ 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_hdr *hdr;
+ struct ieee80211_tx_info *tx_info;
+ struct ath_tx_info_priv *tx_info_priv;
struct ath_atx_tid *tid = NULL;
struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
struct ath_desc *ds = bf_last->bf_desc;
@@ -280,10 +283,14 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data;
+ tx_info = IEEE80211_SKB_CB(skb);
+ tx_info_priv = (struct ath_tx_info_priv *) tx_info->rate_driver_data[0];
+ hw = tx_info_priv->aphy->hw;
+
rcu_read_lock();
/* XXX: use ieee80211_find_sta! */
- sta = ieee80211_find_sta_by_hw(sc->hw, hdr->addr1);
+ sta = ieee80211_find_sta_by_hw(hw, hdr->addr1);
if (!sta) {
rcu_read_unlock();
return;
@@ -908,9 +915,10 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
{
struct ath_txq *txq = NULL;
+ u16 skb_queue = skb_get_queue_mapping(skb);
int qnum;
- qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
+ qnum = ath_get_hal_qnum(skb_queue, sc);
txq = &sc->tx.txq[qnum];
spin_lock_bh(&txq->axq_lock);
@@ -919,7 +927,7 @@ struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT,
"TX queue: %d is full, depth: %d\n",
qnum, txq->axq_depth);
- ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb));
+ ath_mac80211_stop_queue(sc, skb_queue);
txq->stopped = 1;
spin_unlock_bh(&txq->axq_lock);
return NULL;
@@ -1569,7 +1577,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
- if (conf_is_ht(&sc->hw->conf) && !is_pae(skb))
+ if (conf_is_ht(&hw->conf) && !is_pae(skb))
bf->bf_state.bf_type |= BUF_HT;
bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq);
@@ -1698,8 +1706,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
* on the queue */
spin_lock_bh(&txq->axq_lock);
if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) {
- ieee80211_stop_queue(sc->hw,
- skb_get_queue_mapping(skb));
+ ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
txq->stopped = 1;
}
spin_unlock_bh(&txq->axq_lock);
@@ -1939,7 +1946,7 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) {
qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc);
if (qnum != -1) {
- ieee80211_wake_queue(sc->hw, qnum);
+ ath_mac80211_start_queue(sc, qnum);
txq->stopped = 0;
}
}