summaryrefslogtreecommitdiff
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.h9
-rw-r--r--drivers/net/wireless/ath/ath5k/ahb.c28
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h31
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c7
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c71
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h7
-rw-r--r--drivers/net/wireless/ath/ath5k/caps.c3
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c65
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.h17
-rw-r--r--drivers/net/wireless/ath/ath5k/desc.c158
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.c158
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c9
-rw-r--r--drivers/net/wireless/ath/ath5k/pci.c32
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c35
-rw-r--r--drivers/net/wireless/ath/ath5k/qcu.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig21
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile6
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c14
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_mac.c12
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_phy.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h178
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.c12
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c17
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9485_initvals.h10
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h12
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c44
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c40
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h7
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c26
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c25
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c334
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.h7
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h211
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_beacon.c318
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_debug.c505
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_gpio.c12
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c91
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c322
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c780
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.c50
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.h14
-rw-r--r--drivers/net/wireless/ath/ath9k/hw-ops.h5
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c45
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h9
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c63
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h35
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.c122
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.h80
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c111
-rw-r--r--drivers/net/wireless/ath/key.c6
-rw-r--r--drivers/net/wireless/ath/regd.c8
-rw-r--r--drivers/net/wireless/ath/regd_common.h2
57 files changed, 2962 insertions, 1249 deletions
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index 6d7105b7e8f1..7cf4317a2a84 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -123,14 +123,7 @@ struct ath_ops {
};
struct ath_common;
-
-struct ath_bus_ops {
- enum ath_bus_type ath_bus_type;
- void (*read_cachesize)(struct ath_common *common, int *csz);
- bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
- void (*bt_coex_prep)(struct ath_common *common);
- void (*extn_synch_en)(struct ath_common *common);
-};
+struct ath_bus_ops;
struct ath_common {
void *ah;
diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c
index 82324e98efef..ea9982781559 100644
--- a/drivers/net/wireless/ath/ath5k/ahb.c
+++ b/drivers/net/wireless/ath/ath5k/ahb.c
@@ -18,6 +18,7 @@
#include <linux/nl80211.h>
#include <linux/platform_device.h>
+#include <linux/etherdevice.h>
#include <ar231x_platform.h>
#include "ath5k.h"
#include "debug.h"
@@ -62,10 +63,27 @@ int ath5k_hw_read_srev(struct ath5k_hw *ah)
return 0;
}
+static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
+{
+ struct ath5k_softc *sc = ah->ah_sc;
+ struct platform_device *pdev = to_platform_device(sc->dev);
+ struct ar231x_board_config *bcfg = pdev->dev.platform_data;
+ u8 *cfg_mac;
+
+ if (to_platform_device(sc->dev)->id == 0)
+ cfg_mac = bcfg->config->wlan0_mac;
+ else
+ cfg_mac = bcfg->config->wlan1_mac;
+
+ memcpy(mac, cfg_mac, ETH_ALEN);
+ return 0;
+}
+
static const struct ath_bus_ops ath_ahb_bus_ops = {
.ath_bus_type = ATH_AHB,
.read_cachesize = ath5k_ahb_read_cachesize,
.eeprom_read = ath5k_ahb_eeprom_read,
+ .eeprom_read_mac = ath5k_ahb_eeprom_read_mac,
};
/*Initialization*/
@@ -142,6 +160,16 @@ static int ath_ahb_probe(struct platform_device *pdev)
else
reg |= AR5K_AR5312_ENABLE_WLAN1;
__raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
+
+ /*
+ * On a dual-band AR5312, the multiband radio is only
+ * used as pass-through. Disable 2 GHz support in the
+ * driver for it
+ */
+ if (to_platform_device(sc->dev)->id == 0 &&
+ (bcfg->config->flags & (BD_WLAN0|BD_WLAN1)) ==
+ (BD_WLAN1|BD_WLAN0))
+ __set_bit(ATH_STAT_2G_DISABLED, sc->status);
}
ret = ath5k_init_softc(sc, &ath_ahb_bus_ops);
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 8a06dbd39629..bb50700436fe 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -224,8 +224,7 @@
/* SIFS */
#define AR5K_INIT_SIFS_TURBO 6
-/* XXX: 8 from initvals 10 from standard */
-#define AR5K_INIT_SIFS_DEFAULT_BG 8
+#define AR5K_INIT_SIFS_DEFAULT_BG 10
#define AR5K_INIT_SIFS_DEFAULT_A 16
#define AR5K_INIT_SIFS_HALF_RATE 32
#define AR5K_INIT_SIFS_QUARTER_RATE 64
@@ -453,12 +452,10 @@ struct ath5k_tx_status {
u16 ts_seqnum;
u16 ts_tstamp;
u8 ts_status;
- u8 ts_rate[4];
- u8 ts_retry[4];
u8 ts_final_idx;
+ u8 ts_final_retry;
s8 ts_rssi;
u8 ts_shortretry;
- u8 ts_longretry;
u8 ts_virtcol;
u8 ts_antenna;
};
@@ -875,6 +872,19 @@ enum ath5k_int {
AR5K_INT_QTRIG = 0x40000000, /* Non common */
AR5K_INT_GLOBAL = 0x80000000,
+ AR5K_INT_TX_ALL = AR5K_INT_TXOK
+ | AR5K_INT_TXDESC
+ | AR5K_INT_TXERR
+ | AR5K_INT_TXEOL
+ | AR5K_INT_TXURN,
+
+ AR5K_INT_RX_ALL = AR5K_INT_RXOK
+ | AR5K_INT_RXDESC
+ | AR5K_INT_RXERR
+ | AR5K_INT_RXNOFRM
+ | AR5K_INT_RXEOL
+ | AR5K_INT_RXORN,
+
AR5K_INT_COMMON = AR5K_INT_RXOK
| AR5K_INT_RXDESC
| AR5K_INT_RXERR
@@ -1058,6 +1068,7 @@ struct ath5k_hw {
u8 ah_coverage_class;
bool ah_ack_bitrate_high;
u8 ah_bwmode;
+ bool ah_short_slot;
/* Antenna Control */
u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
@@ -1144,6 +1155,13 @@ struct ath5k_hw {
struct ath5k_rx_status *);
};
+struct ath_bus_ops {
+ enum ath_bus_type ath_bus_type;
+ void (*read_cachesize)(struct ath_common *common, int *csz);
+ bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
+ int (*eeprom_read_mac)(struct ath5k_hw *ah, u8 *mac);
+};
+
/*
* Prototypes
*/
@@ -1227,13 +1245,12 @@ int ath5k_hw_dma_stop(struct ath5k_hw *ah);
/* EEPROM access functions */
int ath5k_eeprom_init(struct ath5k_hw *ah);
void ath5k_eeprom_detach(struct ath5k_hw *ah);
-int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
/* Protocol Control Unit Functions */
/* Helpers */
int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
- int len, struct ieee80211_rate *rate);
+ int len, struct ieee80211_rate *rate, bool shortpre);
unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah);
unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah);
extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode);
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index bc8240560488..1588401de3c4 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -313,12 +313,17 @@ int ath5k_hw_init(struct ath5k_softc *sc)
goto err;
}
+ if (test_bit(ATH_STAT_2G_DISABLED, sc->status)) {
+ __clear_bit(AR5K_MODE_11B, ah->ah_capabilities.cap_mode);
+ __clear_bit(AR5K_MODE_11G, ah->ah_capabilities.cap_mode);
+ }
+
/* Crypto settings */
common->keymax = (sc->ah->ah_version == AR5K_AR5210 ?
AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211);
if (srev >= AR5K_SREV_AR5212_V4 &&
- (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 &&
+ (ee->ee_version < AR5K_EEPROM_VERSION_5_0 ||
!AR5K_EEPROM_AES_DIS(ee->ee_misc5)))
common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 349a5963931b..203243bacc89 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -1444,6 +1444,21 @@ ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs)
}
static void
+ath5k_set_current_imask(struct ath5k_softc *sc)
+{
+ enum ath5k_int imask = sc->imask;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sc->irqlock, flags);
+ if (sc->rx_pending)
+ imask &= ~AR5K_INT_RX_ALL;
+ if (sc->tx_pending)
+ imask &= ~AR5K_INT_TX_ALL;
+ ath5k_hw_set_imr(sc->ah, imask);
+ spin_unlock_irqrestore(&sc->irqlock, flags);
+}
+
+static void
ath5k_tasklet_rx(unsigned long data)
{
struct ath5k_rx_status rs = {};
@@ -1506,6 +1521,8 @@ next:
} while (ath5k_rxbuf_setup(sc, bf) == 0);
unlock:
spin_unlock(&sc->rxbuflock);
+ sc->rx_pending = false;
+ ath5k_set_current_imask(sc);
}
@@ -1573,28 +1590,28 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb,
struct ath5k_txq *txq, struct ath5k_tx_status *ts)
{
struct ieee80211_tx_info *info;
+ u8 tries[3];
int i;
sc->stats.tx_all_count++;
sc->stats.tx_bytes_count += skb->len;
info = IEEE80211_SKB_CB(skb);
+ tries[0] = info->status.rates[0].count;
+ tries[1] = info->status.rates[1].count;
+ tries[2] = info->status.rates[2].count;
+
ieee80211_tx_info_clear_status(info);
- for (i = 0; i < 4; i++) {
+
+ for (i = 0; i < ts->ts_final_idx; i++) {
struct ieee80211_tx_rate *r =
&info->status.rates[i];
- if (ts->ts_rate[i]) {
- r->idx = ath5k_hw_to_driver_rix(sc, ts->ts_rate[i]);
- r->count = ts->ts_retry[i];
- } else {
- r->idx = -1;
- r->count = 0;
- }
+ r->count = tries[i];
}
- /* count the successful attempt as well */
- info->status.rates[ts->ts_final_idx].count++;
+ info->status.rates[ts->ts_final_idx].count = ts->ts_final_retry;
+ info->status.rates[ts->ts_final_idx + 1].idx = -1;
if (unlikely(ts->ts_status)) {
sc->stats.ack_fail++;
@@ -1609,6 +1626,9 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb,
} else {
info->flags |= IEEE80211_TX_STAT_ACK;
info->status.ack_signal = ts->ts_rssi;
+
+ /* count the successful attempt as well */
+ info->status.rates[ts->ts_final_idx].count++;
}
/*
@@ -1690,6 +1710,9 @@ ath5k_tasklet_tx(unsigned long data)
for (i=0; i < AR5K_NUM_TX_QUEUES; i++)
if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i)))
ath5k_tx_processq(sc, &sc->txqs[i]);
+
+ sc->tx_pending = false;
+ ath5k_set_current_imask(sc);
}
@@ -2119,6 +2142,20 @@ ath5k_intr_calibration_poll(struct ath5k_hw *ah)
* AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */
}
+static void
+ath5k_schedule_rx(struct ath5k_softc *sc)
+{
+ sc->rx_pending = true;
+ tasklet_schedule(&sc->rxtq);
+}
+
+static void
+ath5k_schedule_tx(struct ath5k_softc *sc)
+{
+ sc->tx_pending = true;
+ tasklet_schedule(&sc->txtq);
+}
+
irqreturn_t
ath5k_intr(int irq, void *dev_id)
{
@@ -2161,7 +2198,7 @@ ath5k_intr(int irq, void *dev_id)
ieee80211_queue_work(sc->hw, &sc->reset_work);
}
else
- tasklet_schedule(&sc->rxtq);
+ ath5k_schedule_rx(sc);
} else {
if (status & AR5K_INT_SWBA) {
tasklet_hi_schedule(&sc->beacontq);
@@ -2179,10 +2216,10 @@ ath5k_intr(int irq, void *dev_id)
ath5k_hw_update_tx_triglevel(ah, true);
}
if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
- tasklet_schedule(&sc->rxtq);
+ ath5k_schedule_rx(sc);
if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
| AR5K_INT_TXERR | AR5K_INT_TXEOL))
- tasklet_schedule(&sc->txtq);
+ ath5k_schedule_tx(sc);
if (status & AR5K_INT_BMISS) {
/* TODO */
}
@@ -2201,6 +2238,9 @@ ath5k_intr(int irq, void *dev_id)
} while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
+ if (sc->rx_pending || sc->tx_pending)
+ ath5k_set_current_imask(sc);
+
if (unlikely(!counter))
ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
@@ -2572,6 +2612,8 @@ done:
static void stop_tasklets(struct ath5k_softc *sc)
{
+ sc->rx_pending = false;
+ sc->tx_pending = false;
tasklet_kill(&sc->rxtq);
tasklet_kill(&sc->txtq);
tasklet_kill(&sc->calib);
@@ -2838,7 +2880,7 @@ ath5k_init(struct ieee80211_hw *hw)
INIT_WORK(&sc->reset_work, ath5k_reset_work);
INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work);
- ret = ath5k_eeprom_read_mac(ah, mac);
+ ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac);
if (ret) {
ATH5K_ERR(sc, "unable to read address from EEPROM\n");
goto err_queues;
@@ -2898,7 +2940,6 @@ ath5k_deinit_softc(struct ath5k_softc *sc)
* XXX: ??? detach ath5k_hw ???
* Other than that, it's straightforward...
*/
- ath5k_debug_finish_device(sc);
ieee80211_unregister_hw(hw);
ath5k_desc_free(sc);
ath5k_txq_release(sc);
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index 978f1f4ac2f3..b294f3305011 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -193,12 +193,13 @@ struct ath5k_softc {
dma_addr_t desc_daddr; /* DMA (physical) address */
size_t desc_len; /* size of TX/RX descriptors */
- DECLARE_BITMAP(status, 5);
+ DECLARE_BITMAP(status, 6);
#define ATH_STAT_INVALID 0 /* disable hardware accesses */
#define ATH_STAT_MRRETRY 1 /* multi-rate retry support */
#define ATH_STAT_PROMISC 2
#define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */
#define ATH_STAT_STARTED 4 /* opened & irqs enabled */
+#define ATH_STAT_2G_DISABLED 5 /* multiband radio without 2G */
unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */
struct ieee80211_channel *curchan; /* current h/w channel */
@@ -207,6 +208,10 @@ struct ath5k_softc {
enum ath5k_int imask; /* interrupt mask copy */
+ spinlock_t irqlock;
+ bool rx_pending; /* rx tasklet pending */
+ bool tx_pending; /* tx tasklet pending */
+
u8 lladdr[ETH_ALEN];
u8 bssidmask[ETH_ALEN];
diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c
index f77e8a703c5c..7dd88e1c3ff8 100644
--- a/drivers/net/wireless/ath/ath5k/caps.c
+++ b/drivers/net/wireless/ath/ath5k/caps.c
@@ -94,6 +94,9 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
}
}
+ if ((ah->ah_radio_5ghz_revision & 0xf0) == AR5K_SREV_RAD_2112)
+ __clear_bit(AR5K_MODE_11A, caps->cap_mode);
+
/* Set number of supported TX queues */
if (ah->ah_version == AR5K_AR5210)
caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES_NOQCU;
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 0230f30e9e9a..0bf7313b8a17 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -888,65 +888,38 @@ static const struct file_operations fops_queue = {
void
ath5k_debug_init_device(struct ath5k_softc *sc)
{
- sc->debug.level = ath5k_debug;
+ struct dentry *phydir;
- sc->debug.debugfs_phydir = debugfs_create_dir("ath5k",
- sc->hw->wiphy->debugfsdir);
+ sc->debug.level = ath5k_debug;
- sc->debug.debugfs_debug = debugfs_create_file("debug",
- S_IWUSR | S_IRUSR,
- sc->debug.debugfs_phydir, sc, &fops_debug);
+ phydir = debugfs_create_dir("ath5k", sc->hw->wiphy->debugfsdir);
+ if (!phydir)
+ return;
- sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUSR,
- sc->debug.debugfs_phydir, sc, &fops_registers);
+ debugfs_create_file("debug", S_IWUSR | S_IRUSR, phydir, sc,
+ &fops_debug);
- sc->debug.debugfs_beacon = debugfs_create_file("beacon",
- S_IWUSR | S_IRUSR,
- sc->debug.debugfs_phydir, sc, &fops_beacon);
+ debugfs_create_file("registers", S_IRUSR, phydir, sc, &fops_registers);
- sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR,
- sc->debug.debugfs_phydir, sc, &fops_reset);
+ debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, sc,
+ &fops_beacon);
- sc->debug.debugfs_antenna = debugfs_create_file("antenna",
- S_IWUSR | S_IRUSR,
- sc->debug.debugfs_phydir, sc, &fops_antenna);
+ debugfs_create_file("reset", S_IWUSR, phydir, sc, &fops_reset);
- sc->debug.debugfs_misc = debugfs_create_file("misc",
- S_IRUSR,
- sc->debug.debugfs_phydir, sc, &fops_misc);
+ debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, sc,
+ &fops_antenna);
- sc->debug.debugfs_frameerrors = debugfs_create_file("frameerrors",
- S_IWUSR | S_IRUSR,
- sc->debug.debugfs_phydir, sc,
- &fops_frameerrors);
+ debugfs_create_file("misc", S_IRUSR, phydir, sc, &fops_misc);
- sc->debug.debugfs_ani = debugfs_create_file("ani",
- S_IWUSR | S_IRUSR,
- sc->debug.debugfs_phydir, sc,
- &fops_ani);
+ debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, phydir, sc,
+ &fops_frameerrors);
- sc->debug.debugfs_queue = debugfs_create_file("queue",
- S_IWUSR | S_IRUSR,
- sc->debug.debugfs_phydir, sc,
- &fops_queue);
-}
+ debugfs_create_file("ani", S_IWUSR | S_IRUSR, phydir, sc, &fops_ani);
-void
-ath5k_debug_finish_device(struct ath5k_softc *sc)
-{
- debugfs_remove(sc->debug.debugfs_debug);
- debugfs_remove(sc->debug.debugfs_registers);
- debugfs_remove(sc->debug.debugfs_beacon);
- debugfs_remove(sc->debug.debugfs_reset);
- debugfs_remove(sc->debug.debugfs_antenna);
- debugfs_remove(sc->debug.debugfs_misc);
- debugfs_remove(sc->debug.debugfs_frameerrors);
- debugfs_remove(sc->debug.debugfs_ani);
- debugfs_remove(sc->debug.debugfs_queue);
- debugfs_remove(sc->debug.debugfs_phydir);
+ debugfs_create_file("queue", S_IWUSR | S_IRUSR, phydir, sc,
+ &fops_queue);
}
-
/* functions used in other places */
void
diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h
index b0355aef68d3..193dd2d4ea3c 100644
--- a/drivers/net/wireless/ath/ath5k/debug.h
+++ b/drivers/net/wireless/ath/ath5k/debug.h
@@ -68,17 +68,6 @@ struct ath5k_buf;
struct ath5k_dbg_info {
unsigned int level; /* debug level */
- /* debugfs entries */
- struct dentry *debugfs_phydir;
- struct dentry *debugfs_debug;
- struct dentry *debugfs_registers;
- struct dentry *debugfs_beacon;
- struct dentry *debugfs_reset;
- struct dentry *debugfs_antenna;
- struct dentry *debugfs_misc;
- struct dentry *debugfs_frameerrors;
- struct dentry *debugfs_ani;
- struct dentry *debugfs_queue;
};
/**
@@ -141,9 +130,6 @@ void
ath5k_debug_init_device(struct ath5k_softc *sc);
void
-ath5k_debug_finish_device(struct ath5k_softc *sc);
-
-void
ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah);
void
@@ -167,9 +153,6 @@ static inline void
ath5k_debug_init_device(struct ath5k_softc *sc) {}
static inline void
-ath5k_debug_finish_device(struct ath5k_softc *sc) {}
-
-static inline void
ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {}
static inline void
diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c
index a8fcc94269f7..62172d585723 100644
--- a/drivers/net/wireless/ath/ath5k/desc.c
+++ b/drivers/net/wireless/ath/ath5k/desc.c
@@ -185,6 +185,12 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
struct ath5k_hw_4w_tx_ctl *tx_ctl;
unsigned int frame_len;
+ /*
+ * Use local variables for these to reduce load/store access on
+ * uncached memory
+ */
+ u32 txctl0 = 0, txctl1 = 0, txctl2 = 0, txctl3 = 0;
+
tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
/*
@@ -208,8 +214,9 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
if (tx_power > AR5K_TUNE_MAX_TXPOWER)
tx_power = AR5K_TUNE_MAX_TXPOWER;
- /* Clear descriptor */
- memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc));
+ /* Clear descriptor status area */
+ memset(&desc->ud.ds_tx5212.tx_stat, 0,
+ sizeof(desc->ud.ds_tx5212.tx_stat));
/* Setup control descriptor */
@@ -221,7 +228,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
return -EINVAL;
- tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
+ txctl0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
/* Verify and set buffer length */
@@ -232,21 +239,17 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
return -EINVAL;
- tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
+ txctl1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
- tx_ctl->tx_control_0 |=
- AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
- AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
- tx_ctl->tx_control_1 |= AR5K_REG_SM(type,
- AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
- tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0,
- AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
- tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+ txctl0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
+ AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
+ txctl1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
+ txctl2 = AR5K_REG_SM(tx_tries0, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
+ txctl3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
#define _TX_FLAGS(_c, _flag) \
if (flags & AR5K_TXDESC_##_flag) { \
- tx_ctl->tx_control_##_c |= \
- AR5K_4W_TX_DESC_CTL##_c##_##_flag; \
+ txctl##_c |= AR5K_4W_TX_DESC_CTL##_c##_##_flag; \
}
_TX_FLAGS(0, CLRDMASK);
@@ -262,8 +265,8 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
* WEP crap
*/
if (key_index != AR5K_TXKEYIX_INVALID) {
- tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
- tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index,
+ txctl0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
+ txctl1 |= AR5K_REG_SM(key_index,
AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX);
}
@@ -274,12 +277,16 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
if ((flags & AR5K_TXDESC_RTSENA) &&
(flags & AR5K_TXDESC_CTSENA))
return -EINVAL;
- tx_ctl->tx_control_2 |= rtscts_duration &
- AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
- tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
+ txctl2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
+ txctl3 |= AR5K_REG_SM(rtscts_rate,
AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
}
+ tx_ctl->tx_control_0 = txctl0;
+ tx_ctl->tx_control_1 = txctl1;
+ tx_ctl->tx_control_2 = txctl2;
+ tx_ctl->tx_control_3 = txctl3;
+
return 0;
}
@@ -364,7 +371,7 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
- ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+ ts->ts_final_retry = AR5K_REG_MS(tx_status->tx_status_0,
AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
/*TODO: ts->ts_virtcol + test*/
ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
@@ -373,9 +380,6 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
ts->ts_antenna = 1;
ts->ts_status = 0;
- ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0,
- AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
- ts->ts_retry[0] = ts->ts_longretry;
ts->ts_final_idx = 0;
if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
@@ -401,81 +405,48 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
{
struct ath5k_hw_4w_tx_ctl *tx_ctl;
struct ath5k_hw_tx_status *tx_status;
+ u32 txstat0, txstat1;
tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
tx_status = &desc->ud.ds_tx5212.tx_stat;
+ txstat1 = ACCESS_ONCE(tx_status->tx_status_1);
+
/* No frame has been send or error */
- if (unlikely(!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE)))
+ if (unlikely(!(txstat1 & AR5K_DESC_TX_STATUS1_DONE)))
return -EINPROGRESS;
+ txstat0 = ACCESS_ONCE(tx_status->tx_status_0);
+
/*
* Get descriptor status
*/
- ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
+ ts->ts_tstamp = AR5K_REG_MS(txstat0,
AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
- ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
+ ts->ts_shortretry = AR5K_REG_MS(txstat0,
AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
- ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+ ts->ts_final_retry = AR5K_REG_MS(txstat0,
AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
- ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
+ ts->ts_seqnum = AR5K_REG_MS(txstat1,
AR5K_DESC_TX_STATUS1_SEQ_NUM);
- ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
+ ts->ts_rssi = AR5K_REG_MS(txstat1,
AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
- ts->ts_antenna = (tx_status->tx_status_1 &
+ ts->ts_antenna = (txstat1 &
AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212) ? 2 : 1;
ts->ts_status = 0;
- ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1,
+ ts->ts_final_idx = AR5K_REG_MS(txstat1,
AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212);
- /* The longretry counter has the number of un-acked retries
- * for the final rate. To get the total number of retries
- * we have to add the retry counters for the other rates
- * as well
- */
- ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry;
- switch (ts->ts_final_idx) {
- case 3:
- ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3,
- AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
-
- ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2,
- AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
- ts->ts_longretry += ts->ts_retry[2];
- /* fall through */
- case 2:
- ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3,
- AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
-
- ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2,
- AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
- ts->ts_longretry += ts->ts_retry[1];
- /* fall through */
- case 1:
- ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3,
- AR5K_4W_TX_DESC_CTL3_XMIT_RATE1);
-
- ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2,
- AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
- ts->ts_longretry += ts->ts_retry[0];
- /* fall through */
- case 0:
- ts->ts_rate[0] = tx_ctl->tx_control_3 &
- AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
- break;
- }
-
/* TX error */
- if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
- if (tx_status->tx_status_0 &
- AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
+ if (!(txstat0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
+ if (txstat0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
ts->ts_status |= AR5K_TXERR_XRETRY;
- if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
+ if (txstat0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
ts->ts_status |= AR5K_TXERR_FIFO;
- if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
+ if (txstat0 & AR5K_DESC_TX_STATUS0_FILTERED)
ts->ts_status |= AR5K_TXERR_FILT;
}
@@ -609,37 +580,37 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
struct ath5k_rx_status *rs)
{
struct ath5k_hw_rx_status *rx_status;
+ u32 rxstat0, rxstat1;
rx_status = &desc->ud.ds_rx.rx_stat;
+ rxstat1 = ACCESS_ONCE(rx_status->rx_status_1);
/* No frame received / not ready */
- if (unlikely(!(rx_status->rx_status_1 &
- AR5K_5212_RX_DESC_STATUS1_DONE)))
+ if (unlikely(!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_DONE)))
return -EINPROGRESS;
memset(rs, 0, sizeof(struct ath5k_rx_status));
+ rxstat0 = ACCESS_ONCE(rx_status->rx_status_0);
/*
* Frame receive status
*/
- rs->rs_datalen = rx_status->rx_status_0 &
- AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
- rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
+ rs->rs_datalen = rxstat0 & AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
+ rs->rs_rssi = AR5K_REG_MS(rxstat0,
AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL);
- rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
+ rs->rs_rate = AR5K_REG_MS(rxstat0,
AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE);
- rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0,
+ rs->rs_antenna = AR5K_REG_MS(rxstat0,
AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA);
- rs->rs_more = !!(rx_status->rx_status_0 &
- AR5K_5212_RX_DESC_STATUS0_MORE);
- rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
+ rs->rs_more = !!(rxstat0 & AR5K_5212_RX_DESC_STATUS0_MORE);
+ rs->rs_tstamp = AR5K_REG_MS(rxstat1,
AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
/*
* Key table status
*/
- if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
- rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
+ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
+ rs->rs_keyix = AR5K_REG_MS(rxstat1,
AR5K_5212_RX_DESC_STATUS1_KEY_INDEX);
else
rs->rs_keyix = AR5K_RXKEYIX_INVALID;
@@ -647,27 +618,22 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
/*
* Receive/descriptor errors
*/
- if (!(rx_status->rx_status_1 &
- AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
- if (rx_status->rx_status_1 &
- AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
+ if (!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
+ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
rs->rs_status |= AR5K_RXERR_CRC;
- if (rx_status->rx_status_1 &
- AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
+ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
rs->rs_status |= AR5K_RXERR_PHY;
- rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1,
+ rs->rs_phyerr = AR5K_REG_MS(rxstat1,
AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE);
if (!ah->ah_capabilities.cap_has_phyerr_counters)
ath5k_ani_phy_error_report(ah, rs->rs_phyerr);
}
- if (rx_status->rx_status_1 &
- AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
+ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
rs->rs_status |= AR5K_RXERR_DECRYPT;
- if (rx_status->rx_status_1 &
- AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
+ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
rs->rs_status |= AR5K_RXERR_MIC;
}
return 0;
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index efb672cb31e4..1fef84f87c78 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -660,6 +660,53 @@ ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100;
}
+static int
+ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ struct ath5k_chan_pcal_info *chinfo;
+ u8 pier, pdg;
+
+ switch (mode) {
+ case AR5K_EEPROM_MODE_11A:
+ if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+ return 0;
+ chinfo = ee->ee_pwr_cal_a;
+ break;
+ case AR5K_EEPROM_MODE_11B:
+ if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
+ return 0;
+ chinfo = ee->ee_pwr_cal_b;
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+ return 0;
+ chinfo = ee->ee_pwr_cal_g;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
+ if (!chinfo[pier].pd_curves)
+ continue;
+
+ for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
+ struct ath5k_pdgain_info *pd =
+ &chinfo[pier].pd_curves[pdg];
+
+ if (pd != NULL) {
+ kfree(pd->pd_step);
+ kfree(pd->pd_pwr);
+ }
+ }
+
+ kfree(chinfo[pier].pd_curves);
+ }
+
+ return 0;
+}
+
/* Convert RF5111 specific data to generic raw data
* used by interpolation code */
static int
@@ -684,7 +731,7 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
GFP_KERNEL);
if (!chinfo[pier].pd_curves)
- return -ENOMEM;
+ goto err_out;
/* Only one curve for RF5111
* find out which one and place
@@ -708,12 +755,12 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111,
sizeof(u8), GFP_KERNEL);
if (!pd->pd_step)
- return -ENOMEM;
+ goto err_out;
pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111,
sizeof(s16), GFP_KERNEL);
if (!pd->pd_pwr)
- return -ENOMEM;
+ goto err_out;
/* Fill raw dataset
* (convert power to 0.25dB units
@@ -734,6 +781,10 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
}
return 0;
+
+err_out:
+ ath5k_eeprom_free_pcal_info(ah, mode);
+ return -ENOMEM;
}
/* Parse EEPROM data */
@@ -867,7 +918,7 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
GFP_KERNEL);
if (!chinfo[pier].pd_curves)
- return -ENOMEM;
+ goto err_out;
/* Fill pd_curves */
for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
@@ -886,14 +937,13 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
sizeof(u8), GFP_KERNEL);
if (!pd->pd_step)
- return -ENOMEM;
+ goto err_out;
pd->pd_pwr = kcalloc(pd->pd_points,
sizeof(s16), GFP_KERNEL);
if (!pd->pd_pwr)
- return -ENOMEM;
-
+ goto err_out;
/* Fill raw dataset
* (all power levels are in 0.25dB units) */
@@ -925,13 +975,13 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
sizeof(u8), GFP_KERNEL);
if (!pd->pd_step)
- return -ENOMEM;
+ goto err_out;
pd->pd_pwr = kcalloc(pd->pd_points,
sizeof(s16), GFP_KERNEL);
if (!pd->pd_pwr)
- return -ENOMEM;
+ goto err_out;
/* Fill raw dataset
* (all power levels are in 0.25dB units) */
@@ -954,6 +1004,10 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
}
return 0;
+
+err_out:
+ ath5k_eeprom_free_pcal_info(ah, mode);
+ return -ENOMEM;
}
/* Parse EEPROM data */
@@ -1156,7 +1210,7 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
GFP_KERNEL);
if (!chinfo[pier].pd_curves)
- return -ENOMEM;
+ goto err_out;
/* Fill pd_curves */
for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
@@ -1177,13 +1231,13 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
sizeof(u8), GFP_KERNEL);
if (!pd->pd_step)
- return -ENOMEM;
+ goto err_out;
pd->pd_pwr = kcalloc(pd->pd_points,
sizeof(s16), GFP_KERNEL);
if (!pd->pd_pwr)
- return -ENOMEM;
+ goto err_out;
/* Fill raw dataset
* convert all pwr levels to
@@ -1213,6 +1267,10 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
}
return 0;
+
+err_out:
+ ath5k_eeprom_free_pcal_info(ah, mode);
+ return -ENOMEM;
}
/* Parse EEPROM data */
@@ -1534,53 +1592,6 @@ ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)
return 0;
}
-static int
-ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
-{
- struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
- struct ath5k_chan_pcal_info *chinfo;
- u8 pier, pdg;
-
- switch (mode) {
- case AR5K_EEPROM_MODE_11A:
- if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
- return 0;
- chinfo = ee->ee_pwr_cal_a;
- break;
- case AR5K_EEPROM_MODE_11B:
- if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
- return 0;
- chinfo = ee->ee_pwr_cal_b;
- break;
- case AR5K_EEPROM_MODE_11G:
- if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
- return 0;
- chinfo = ee->ee_pwr_cal_g;
- break;
- default:
- return -EINVAL;
- }
-
- for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
- if (!chinfo[pier].pd_curves)
- continue;
-
- for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
- struct ath5k_pdgain_info *pd =
- &chinfo[pier].pd_curves[pdg];
-
- if (pd != NULL) {
- kfree(pd->pd_step);
- kfree(pd->pd_pwr);
- }
- }
-
- kfree(chinfo[pier].pd_curves);
- }
-
- return 0;
-}
-
/* Read conformance test limits used for regulatory control */
static int
ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
@@ -1721,35 +1732,6 @@ ath5k_eeprom_read_spur_chans(struct ath5k_hw *ah)
return ret;
}
-/*
- * Read the MAC address from eeprom
- */
-int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
-{
- u8 mac_d[ETH_ALEN] = {};
- u32 total, offset;
- u16 data;
- int octet;
-
- AR5K_EEPROM_READ(0x20, data);
-
- for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
- AR5K_EEPROM_READ(offset, data);
-
- total += data;
- mac_d[octet + 1] = data & 0xff;
- mac_d[octet] = data >> 8;
- octet += 2;
- }
-
- if (!total || total == 3 * 0xffff)
- return -EINVAL;
-
- memcpy(mac, mac_d, ETH_ALEN);
-
- return 0;
-}
-
/***********************\
* Init/Detach functions *
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index 9be29b728b1c..807bd6440169 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -282,6 +282,15 @@ ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (changes & BSS_CHANGED_BEACON_INT)
sc->bintval = bss_conf->beacon_int;
+ if (changes & BSS_CHANGED_ERP_SLOT) {
+ int slot_time;
+
+ ah->ah_short_slot = bss_conf->use_short_slot;
+ slot_time = ath5k_hw_get_default_slottime(ah) +
+ 3 * ah->ah_coverage_class;
+ ath5k_hw_set_ifs_intervals(ah, slot_time);
+ }
+
if (changes & BSS_CHANGED_ASSOC) {
avf->assoc = bss_conf->assoc;
if (bss_conf->assoc)
diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c
index 3c44689a700b..296c316a8341 100644
--- a/drivers/net/wireless/ath/ath5k/pci.c
+++ b/drivers/net/wireless/ath/ath5k/pci.c
@@ -17,6 +17,7 @@
#include <linux/nl80211.h>
#include <linux/pci.h>
#include <linux/pci-aspm.h>
+#include <linux/etherdevice.h>
#include "../ath.h"
#include "ath5k.h"
#include "debug.h"
@@ -108,11 +109,42 @@ int ath5k_hw_read_srev(struct ath5k_hw *ah)
return 0;
}
+/*
+ * Read the MAC address from eeprom or platform_data
+ */
+static int ath5k_pci_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
+{
+ u8 mac_d[ETH_ALEN] = {};
+ u32 total, offset;
+ u16 data;
+ int octet;
+
+ AR5K_EEPROM_READ(0x20, data);
+
+ for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
+ AR5K_EEPROM_READ(offset, data);
+
+ total += data;
+ mac_d[octet + 1] = data & 0xff;
+ mac_d[octet] = data >> 8;
+ octet += 2;
+ }
+
+ if (!total || total == 3 * 0xffff)
+ return -EINVAL;
+
+ memcpy(mac, mac_d, ETH_ALEN);
+
+ return 0;
+}
+
+
/* Common ath_bus_opts structure */
static const struct ath_bus_ops ath_pci_bus_ops = {
.ath_bus_type = ATH_PCI,
.read_cachesize = ath5k_pci_read_cachesize,
.eeprom_read = ath5k_pci_eeprom_read,
+ .eeprom_read_mac = ath5k_pci_eeprom_read_mac,
};
/********************\
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index d9b3f828455a..712a9ac4000e 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -75,7 +75,7 @@ static const unsigned int ack_rates_high[] =
* bwmodes.
*/
int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
- int len, struct ieee80211_rate *rate)
+ int len, struct ieee80211_rate *rate, bool shortpre)
{
struct ath5k_softc *sc = ah->ah_sc;
int sifs, preamble, plcp_bits, sym_time;
@@ -84,9 +84,15 @@ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
/* Fallback */
if (!ah->ah_bwmode) {
- dur = ieee80211_generic_frame_duration(sc->hw,
- NULL, len, rate);
- return le16_to_cpu(dur);
+ __le16 raw_dur = ieee80211_generic_frame_duration(sc->hw,
+ NULL, len, rate);
+
+ /* subtract difference between long and short preamble */
+ dur = le16_to_cpu(raw_dur);
+ if (shortpre)
+ dur -= 96;
+
+ return dur;
}
bitrate = rate->bitrate;
@@ -145,9 +151,9 @@ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
slot_time = AR5K_INIT_SLOT_TIME_QUARTER_RATE;
break;
case AR5K_BWMODE_DEFAULT:
- slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
default:
- if (channel->hw_value & CHANNEL_CCK)
+ slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
+ if ((channel->hw_value & CHANNEL_CCK) && !ah->ah_short_slot)
slot_time = AR5K_INIT_SLOT_TIME_B;
break;
}
@@ -263,27 +269,14 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
* actual rate for this rate. See mac80211 tx.c
* ieee80211_duration() for a brief description of
* what rate we should choose to TX ACKs. */
- tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
+ tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false);
ath5k_hw_reg_write(ah, tx_time, reg);
if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
continue;
- /*
- * We're not distinguishing short preamble here,
- * This is true, all we'll get is a longer value here
- * which is not necessarilly bad. We could use
- * export ieee80211_frame_duration() but that needs to be
- * fixed first to be properly used by mac802111 drivers:
- *
- * - remove erp stuff and let the routine figure ofdm
- * erp rates
- * - remove passing argument ieee80211_local as
- * drivers don't have access to it
- * - move drivers using ieee80211_generic_frame_duration()
- * to this
- */
+ tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, true);
ath5k_hw_reg_write(ah, tx_time,
reg + (AR5K_SET_SHORT_PREAMBLE << 2));
}
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index 3343fb9e4940..b18c5021aac3 100644
--- a/drivers/net/wireless/ath/ath5k/qcu.c
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
@@ -519,7 +519,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
return -EINVAL;
sifs = ath5k_hw_get_default_sifs(ah);
- sifs_clock = ath5k_hw_htoclock(ah, sifs);
+ sifs_clock = ath5k_hw_htoclock(ah, sifs - 2);
/* EIFS
* Txtime of ack at lowest rate + SIFS + DIFS
@@ -550,7 +550,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
else
rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[0];
- ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
+ ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false);
/* ack_tx_time includes an SIFS already */
eifs = ack_tx_time + sifs + 2 * slot_time;
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index ad57a6d23110..d9ff8413ab9a 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -5,7 +5,7 @@ config ATH9K_COMMON
config ATH9K
tristate "Atheros 802.11n wireless cards support"
- depends on PCI && MAC80211
+ depends on MAC80211
select ATH9K_HW
select MAC80211_LEDS
select LEDS_CLASS
@@ -23,6 +23,25 @@ config ATH9K
If you choose to build a module, it'll be called ath9k.
+config ATH9K_PCI
+ bool "Atheros ath9k PCI/PCIe bus support"
+ depends on ATH9K && PCI
+ default PCI
+ ---help---
+ This option enables the PCI bus support in ath9k.
+
+ Say Y, if you have a compatible PCI/PCIe wireless card.
+
+config ATH9K_AHB
+ bool "Atheros ath9k AHB bus support"
+ depends on ATH9K
+ default n
+ ---help---
+ This option enables the AHB bus support in ath9k.
+
+ Say Y, if you have a SoC with a compatible built-in
+ wireless MAC. Say N if unsure.
+
config ATH9K_DEBUGFS
bool "Atheros ath9k debugging"
depends on ATH9K && DEBUG_FS
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 4d66ca8042eb..05a6fade7b1c 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -6,8 +6,8 @@ ath9k-y += beacon.o \
xmit.o \
ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
-ath9k-$(CONFIG_PCI) += pci.o
-ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o
+ath9k-$(CONFIG_ATH9K_PCI) += pci.o
+ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
obj-$(CONFIG_ATH9K) += ath9k.o
@@ -48,4 +48,6 @@ ath9k_htc-y += htc_hst.o \
htc_drv_init.o \
htc_drv_gpio.o
+ath9k_htc-$(CONFIG_ATH9K_HTC_DEBUGFS) += htc_drv_debug.o
+
obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 9cb0efa9b4c0..5193ed58a17b 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -21,6 +21,14 @@
#include <linux/ath9k_platform.h>
#include "ath9k.h"
+const struct platform_device_id ath9k_platform_id_table[] = {
+ {
+ .name = "ath9k",
+ .driver_data = AR5416_AR9100_DEVID,
+ },
+ {},
+};
+
/* return bus cachesize in 4B word units */
static void ath_ahb_read_cachesize(struct ath_common *common, int *csz)
{
@@ -57,6 +65,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
struct ath_softc *sc;
struct ieee80211_hw *hw;
struct resource *res;
+ const struct platform_device_id *id = platform_get_device_id(pdev);
int irq;
int ret = 0;
struct ath_hw *ah;
@@ -116,7 +125,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
goto err_free_hw;
}
- ret = ath9k_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops);
+ ret = ath9k_init_device(id->driver_data, sc, 0x0, &ath_ahb_bus_ops);
if (ret) {
dev_err(&pdev->dev, "failed to initialize device\n");
goto err_irq;
@@ -165,8 +174,11 @@ static struct platform_driver ath_ahb_driver = {
.name = "ath9k",
.owner = THIS_MODULE,
},
+ .id_table = ath9k_platform_id_table,
};
+MODULE_DEVICE_TABLE(platform, ath9k_platform_id_table);
+
int ath_ahb_init(void)
{
return platform_driver_register(&ath_ahb_driver);
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
index 8dd8f6308502..c338efbccf40 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
@@ -290,7 +290,6 @@ static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
| SM(txPower, AR_XmitPower)
| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
- | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
| (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
@@ -311,6 +310,16 @@ static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
}
}
+static void ar9002_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ if (val)
+ ads->ds_ctl0 |= AR_ClrDestMask;
+ else
+ ads->ds_ctl0 &= ~AR_ClrDestMask;
+}
+
static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
void *lastds,
u32 durUpdateEn, u32 rtsctsRate,
@@ -448,4 +457,5 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah)
ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last;
ops->clr11n_aggr = ar9002_hw_clr11n_aggr;
ops->set11n_burstduration = ar9002_hw_set11n_burstduration;
+ ops->set_clrdmask = ar9002_hw_set_clrdmask;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.h b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
index 37663dbbcf57..47780ef1c892 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
@@ -483,7 +483,11 @@
#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN 0x01F80000
#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S 19
+#define AR_PHY_TX_PWRCTRL8 0xa278
+
#define AR_PHY_TX_PWRCTRL9 0xa27C
+
+#define AR_PHY_TX_PWRCTRL10 0xa394
#define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00
#define AR_PHY_TX_DESIRED_SCALE_CCK_S 10
#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL 0x80000000
@@ -495,6 +499,8 @@
#define AR_PHY_CH0_TX_PWRCTRL11 0xa398
#define AR_PHY_CH1_TX_PWRCTRL11 0xb398
+#define AR_PHY_CH0_TX_PWRCTRL12 0xa3dc
+#define AR_PHY_CH0_TX_PWRCTRL13 0xa3e0
#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP 0x0000FC00
#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index 9ecca93392e8..f915a3dbfcad 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -34,10 +34,10 @@ static const u32 ar9300_2p2_radio_postamble[][5] = {
static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800},
- {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000},
- {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000},
- {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+ {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+ {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
@@ -119,14 +119,14 @@ static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
{0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
- {0x0000b2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800},
- {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000},
- {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000},
- {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000c2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800},
- {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000},
- {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000},
- {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+ {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+ {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
@@ -835,10 +835,10 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+ {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+ {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
@@ -920,14 +920,14 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
- {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+ {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+ {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
{0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
{0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
@@ -941,10 +941,10 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800},
- {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000},
- {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+ {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+ {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
@@ -1026,14 +1026,14 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
- {0x0000b2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800},
- {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000},
- {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000c2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800},
- {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000},
- {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+ {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+ {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x0000c2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
{0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
@@ -1307,10 +1307,10 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+ {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+ {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
@@ -1329,21 +1329,21 @@ static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = {
{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
- {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
- {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
- {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
- {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
- {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
- {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
- {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
- {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
- {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861},
+ {0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81},
+ {0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
@@ -1361,45 +1361,45 @@ static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = {
{0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
- {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
- {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
- {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
- {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
- {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
- {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
- {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
- {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
- {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861},
+ {0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81},
+ {0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83},
+ {0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84},
+ {0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3},
+ {0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5},
+ {0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9},
+ {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb},
+ {0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
- {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
- {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
- {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
- {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
- {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
- {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
- {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
- {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
- {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
- {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
- {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000},
+ {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501},
+ {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501},
+ {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03},
+ {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04},
+ {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04},
+ {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+ {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+ {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 724ac2464ad5..c1264d60c499 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -329,7 +329,6 @@ static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
| SM(txpower, AR_XmitPower)
| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
- | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
| (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0);
@@ -350,6 +349,16 @@ static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
ads->ctl22 = 0;
}
+static void ar9003_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
+{
+ struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+
+ if (val)
+ ads->ctl11 |= AR_ClrDestMask;
+ else
+ ads->ctl11 &= ~AR_ClrDestMask;
+}
+
static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
void *lastds,
u32 durUpdateEn, u32 rtsctsRate,
@@ -510,6 +519,7 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw)
ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last;
ops->clr11n_aggr = ar9003_hw_clr11n_aggr;
ops->set11n_burstduration = ar9003_hw_set11n_burstduration;
+ ops->set_clrdmask = ar9003_hw_set_clrdmask;
}
void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size)
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index eb250d6b8038..1bc33f51e466 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -75,9 +75,18 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
freq = centers.synth_center;
if (freq < 4800) { /* 2 GHz, fractional mode */
- if (AR_SREV_9485(ah))
- channelSel = CHANSEL_2G_9485(freq);
- else
+ if (AR_SREV_9485(ah)) {
+ u32 chan_frac;
+
+ /*
+ * freq_ref = 40 / (refdiva >> amoderefsel); where refdiva=1 and amoderefsel=0
+ * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
+ * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000
+ */
+ channelSel = (freq * 4) / 120;
+ chan_frac = (((freq * 4) % 120) * 0x20000) / 120;
+ channelSel = (channelSel << 17) | chan_frac;
+ } else
channelSel = CHANSEL_2G(freq);
/* Set to 2G mode */
bMode = 1;
@@ -401,7 +410,7 @@ static void ar9003_hw_spur_mitigate_ofdm(struct ath_hw *ah,
ar9003_hw_spur_ofdm_clear(ah);
- for (i = 0; spurChansPtr[i] && i < 5; i++) {
+ for (i = 0; i < AR_EEPROM_MODAL_SPURS && spurChansPtr[i]; i++) {
freq_offset = FBIN2FREQ(spurChansPtr[i], mode) - synth_freq;
if (abs(freq_offset) < range) {
ar9003_hw_spur_ofdm_work(ah, chan, freq_offset);
diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
index f91f73e50d00..fbdde29f0ab8 100644
--- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
@@ -396,7 +396,7 @@ static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = {
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb},
+ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
@@ -469,7 +469,7 @@ static const u32 ar9485_modes_lowest_ob_db_tx_gain_1_1[][5] = {
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb},
+ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
@@ -635,7 +635,7 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb},
+ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
@@ -728,7 +728,7 @@ static const u32 ar9485_modes_green_ob_db_tx_gain_1_1[][5] = {
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb},
+ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
@@ -827,7 +827,7 @@ static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = {
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb},
+ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 38835bc324b2..a6b538802251 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -200,6 +200,7 @@ struct ath_atx_ac {
int sched;
struct list_head list;
struct list_head tid_q;
+ bool clear_ps_filter;
};
struct ath_frame_info {
@@ -255,8 +256,12 @@ struct ath_node {
#endif
struct ath_atx_tid tid[WME_NUM_TID];
struct ath_atx_ac ac[WME_NUM_AC];
+ int ps_key;
+
u16 maxampdu;
u8 mpdudensity;
+
+ bool sleeping;
};
#define AGGR_CLEANUP BIT(1)
@@ -338,6 +343,9 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
+bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an);
+
/********/
/* VIFs */
/********/
@@ -665,7 +673,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw);
bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode);
bool ath9k_uses_beacons(int type);
-#ifdef CONFIG_PCI
+#ifdef CONFIG_ATH9K_PCI
int ath_pci_init(void);
void ath_pci_exit(void);
#else
@@ -673,7 +681,7 @@ static inline int ath_pci_init(void) { return 0; };
static inline void ath_pci_exit(void) {};
#endif
-#ifdef CONFIG_ATHEROS_AR71XX
+#ifdef CONFIG_ATH9K_AHB
int ath_ahb_init(void);
void ath_ahb_exit(void);
#else
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index eccb0ec87adb..24f565ba9988 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -320,6 +320,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
if (avp->av_bcbuf != NULL) {
struct ath_buf *bf;
+ avp->is_bslot_active = false;
if (avp->av_bslot != -1) {
sc->beacon.bslot[avp->av_bslot] = NULL;
sc->nbcnvifs--;
@@ -743,9 +744,27 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
cur_conf->dtim_period = 1;
ath_set_beacon(sc);
- sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
}
+static bool ath_has_valid_bslot(struct ath_softc *sc)
+{
+ struct ath_vif *avp;
+ int slot;
+ bool found = false;
+
+ for (slot = 0; slot < ATH_BCBUF; slot++) {
+ if (sc->beacon.bslot[slot]) {
+ avp = (void *)sc->beacon.bslot[slot]->drv_priv;
+ if (avp->is_bslot_active) {
+ found = true;
+ break;
+ }
+ }
+ }
+ return found;
+}
+
+
void ath_set_beacon(struct ath_softc *sc)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -753,7 +772,8 @@ void ath_set_beacon(struct ath_softc *sc)
switch (sc->sc_ah->opmode) {
case NL80211_IFTYPE_AP:
- ath_beacon_config_ap(sc, cur_conf);
+ if (ath_has_valid_bslot(sc))
+ ath_beacon_config_ap(sc, cur_conf);
break;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
@@ -761,6 +781,12 @@ void ath_set_beacon(struct ath_softc *sc)
break;
case NL80211_IFTYPE_STATION:
ath_beacon_config_sta(sc, cur_conf);
+ /*
+ * Request a re-configuration of Beacon related timers
+ * on the receipt of the first Beacon frame (i.e.,
+ * after time sync with the AP).
+ */
+ sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
break;
default:
ath_dbg(common, ATH_DBG_CONFIG,
@@ -774,20 +800,8 @@ void ath_set_beacon(struct ath_softc *sc)
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
{
struct ath_hw *ah = sc->sc_ah;
- struct ath_vif *avp;
- int slot;
- bool found = false;
- for (slot = 0; slot < ATH_BCBUF; slot++) {
- if (sc->beacon.bslot[slot]) {
- avp = (void *)sc->beacon.bslot[slot]->drv_priv;
- if (avp->is_bslot_active) {
- found = true;
- break;
- }
- }
- }
- if (!found)
+ if (!ath_has_valid_bslot(sc))
return;
ath9k_ps_wakeup(sc);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index a762cadb3ab7..34f191ec8e8c 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -845,7 +845,7 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
struct ath_softc *sc = file->private_data;
char *buf;
- unsigned int len = 0, size = 1152;
+ unsigned int len = 0, size = 1400;
ssize_t retval = 0;
buf = kzalloc(size, GFP_KERNEL);
@@ -874,6 +874,34 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
"%18s : %10u\n", "DECRYPT BUSY ERR",
sc->debug.stats.rxstats.decrypt_busy_err);
+ len += snprintf(buf + len, size - len,
+ "%18s : %10d\n", "RSSI-CTL0",
+ sc->debug.stats.rxstats.rs_rssi_ctl0);
+
+ len += snprintf(buf + len, size - len,
+ "%18s : %10d\n", "RSSI-CTL1",
+ sc->debug.stats.rxstats.rs_rssi_ctl1);
+
+ len += snprintf(buf + len, size - len,
+ "%18s : %10d\n", "RSSI-CTL2",
+ sc->debug.stats.rxstats.rs_rssi_ctl2);
+
+ len += snprintf(buf + len, size - len,
+ "%18s : %10d\n", "RSSI-EXT0",
+ sc->debug.stats.rxstats.rs_rssi_ext0);
+
+ len += snprintf(buf + len, size - len,
+ "%18s : %10d\n", "RSSI-EXT1",
+ sc->debug.stats.rxstats.rs_rssi_ext1);
+
+ len += snprintf(buf + len, size - len,
+ "%18s : %10d\n", "RSSI-EXT2",
+ sc->debug.stats.rxstats.rs_rssi_ext2);
+
+ len += snprintf(buf + len, size - len,
+ "%18s : %10d\n", "Rx Antenna",
+ sc->debug.stats.rxstats.rs_antenna);
+
PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN);
PHY_ERR("TIMING", ATH9K_PHYERR_TIMING);
PHY_ERR("PARITY", ATH9K_PHYERR_PARITY);
@@ -948,6 +976,16 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
RX_PHY_ERR_INC(phyerr);
}
+ sc->debug.stats.rxstats.rs_rssi_ctl0 = rs->rs_rssi_ctl0;
+ sc->debug.stats.rxstats.rs_rssi_ctl1 = rs->rs_rssi_ctl1;
+ sc->debug.stats.rxstats.rs_rssi_ctl2 = rs->rs_rssi_ctl2;
+
+ sc->debug.stats.rxstats.rs_rssi_ext0 = rs->rs_rssi_ext0;
+ sc->debug.stats.rxstats.rs_rssi_ext1 = rs->rs_rssi_ext1;
+ sc->debug.stats.rxstats.rs_rssi_ext2 = rs->rs_rssi_ext2;
+
+ sc->debug.stats.rxstats.rs_antenna = rs->rs_antenna;
+
#undef RX_STAT_INC
#undef RX_PHY_ERR_INC
}
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 59338de0ce19..1f9f8eada465 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -157,6 +157,13 @@ struct ath_rx_stats {
u32 post_delim_crc_err;
u32 decrypt_busy_err;
u32 phy_err_stats[ATH9K_PHYERR_MAX];
+ int8_t rs_rssi_ctl0;
+ int8_t rs_rssi_ctl1;
+ int8_t rs_rssi_ctl2;
+ int8_t rs_rssi_ext0;
+ int8_t rs_rssi_ext1;
+ int8_t rs_rssi_ext2;
+ u8 rs_antenna;
};
struct ath_stats {
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index bd82447f5b78..3e316133f114 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -436,7 +436,11 @@ struct modal_eep_4k_header {
u8 db2_2:4, db2_3:4;
u8 db2_4:4, reserved:4;
#endif
- u8 futureModal[4];
+ u8 tx_diversity;
+ u8 flc_pwr_thresh;
+ u8 bb_scale_smrt_antenna;
+#define EEP_4K_BB_DESIRED_SCALE_MASK 0x1f
+ u8 futureModal[1];
struct spur_chan spurChans[AR_EEPROM_MODAL_SPURS];
} __packed;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index bc77a308c901..6f714dd72365 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -781,6 +781,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
{
struct modal_eep_4k_header *pModal;
struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+ struct base_eep_header_4k *pBase = &eep->baseEepHeader;
u8 txRxAttenLocal;
u8 ob[5], db1[5], db2[5];
u8 ant_div_control1, ant_div_control2;
@@ -1003,6 +1004,31 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
AR_PHY_SETTLING_SWITCH,
pModal->swSettleHt40);
}
+ if (AR_SREV_9271(ah) || AR_SREV_9285(ah)) {
+ u8 bb_desired_scale = (pModal->bb_scale_smrt_antenna &
+ EEP_4K_BB_DESIRED_SCALE_MASK);
+ if ((pBase->txGainType == 0) && (bb_desired_scale != 0)) {
+ u32 pwrctrl, mask, clr;
+
+ mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25);
+ pwrctrl = mask * bb_desired_scale;
+ clr = mask * 0x1f;
+ REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr);
+ REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr);
+ REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr);
+
+ mask = BIT(0)|BIT(5)|BIT(15);
+ pwrctrl = mask * bb_desired_scale;
+ clr = mask * 0x1f;
+ REG_RMW(ah, AR_PHY_TX_PWRCTRL9, pwrctrl, clr);
+
+ mask = BIT(0)|BIT(5);
+ pwrctrl = mask * bb_desired_scale;
+ clr = mask * 0x1f;
+ REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr);
+ REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr);
+ }
+ }
}
static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index 2f0712ea49a6..13579752a300 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -858,35 +858,12 @@ static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
{
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
- u16 antWrites[AR9287_ANT_16S];
u32 regChainOffset, regval;
u8 txRxAttenLocal;
- int i, j, offset_num;
+ int i;
pModal = &eep->modalHeader;
- antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF);
- antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF);
- antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF);
- antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF);
- antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF);
- antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF);
- antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF);
- antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF);
-
- offset_num = 8;
-
- for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) {
- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf);
- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3);
- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3);
- antWrites[j++] = 0;
- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3);
- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3);
- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3);
- antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3);
- }
-
REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon);
for (i = 0; i < AR9287_MAX_CHAINS; i++) {
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 2d10239ce829..2e3a33a53406 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -17,11 +17,9 @@
#include "htc.h"
/* identify firmware images */
-#define FIRMWARE_AR7010 "ar7010.fw"
-#define FIRMWARE_AR7010_1_1 "ar7010_1_1.fw"
-#define FIRMWARE_AR9271 "ar9271.fw"
+#define FIRMWARE_AR7010_1_1 "htc_7010.fw"
+#define FIRMWARE_AR9271 "htc_9271.fw"
-MODULE_FIRMWARE(FIRMWARE_AR7010);
MODULE_FIRMWARE(FIRMWARE_AR7010_1_1);
MODULE_FIRMWARE(FIRMWARE_AR9271);
@@ -80,7 +78,7 @@ static void hif_usb_regout_cb(struct urb *urb)
if (cmd) {
ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle,
- cmd->skb, 1);
+ cmd->skb, true);
kfree(cmd);
}
@@ -126,6 +124,90 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev,
return ret;
}
+static void hif_usb_mgmt_cb(struct urb *urb)
+{
+ struct cmd_buf *cmd = (struct cmd_buf *)urb->context;
+ struct hif_device_usb *hif_dev = cmd->hif_dev;
+ bool txok = true;
+
+ if (!cmd || !cmd->skb || !cmd->hif_dev)
+ return;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ENODEV:
+ case -ESHUTDOWN:
+ txok = false;
+
+ /*
+ * If the URBs are being flushed, no need to complete
+ * this packet.
+ */
+ spin_lock(&hif_dev->tx.tx_lock);
+ if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
+ spin_unlock(&hif_dev->tx.tx_lock);
+ dev_kfree_skb_any(cmd->skb);
+ kfree(cmd);
+ return;
+ }
+ spin_unlock(&hif_dev->tx.tx_lock);
+
+ break;
+ default:
+ txok = false;
+ break;
+ }
+
+ skb_pull(cmd->skb, 4);
+ ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle,
+ cmd->skb, txok);
+ kfree(cmd);
+}
+
+static int hif_usb_send_mgmt(struct hif_device_usb *hif_dev,
+ struct sk_buff *skb)
+{
+ struct urb *urb;
+ struct cmd_buf *cmd;
+ int ret = 0;
+ __le16 *hdr;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (urb == NULL)
+ return -ENOMEM;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+ if (cmd == NULL) {
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+
+ cmd->skb = skb;
+ cmd->hif_dev = hif_dev;
+
+ hdr = (__le16 *) skb_push(skb, 4);
+ *hdr++ = cpu_to_le16(skb->len - 4);
+ *hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG);
+
+ usb_fill_bulk_urb(urb, hif_dev->udev,
+ usb_sndbulkpipe(hif_dev->udev, USB_WLAN_TX_PIPE),
+ skb->data, skb->len,
+ hif_usb_mgmt_cb, cmd);
+
+ usb_anchor_urb(urb, &hif_dev->mgmt_submitted);
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret) {
+ usb_unanchor_urb(urb);
+ kfree(cmd);
+ }
+ usb_free_urb(urb);
+
+ return ret;
+}
+
static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
struct sk_buff_head *list)
{
@@ -133,7 +215,22 @@ static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
while ((skb = __skb_dequeue(list)) != NULL) {
dev_kfree_skb_any(skb);
- TX_STAT_INC(skb_dropped);
+ }
+}
+
+static inline void ath9k_skb_queue_complete(struct hif_device_usb *hif_dev,
+ struct sk_buff_head *queue,
+ bool txok)
+{
+ struct sk_buff *skb;
+
+ while ((skb = __skb_dequeue(queue)) != NULL) {
+ ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
+ skb, txok);
+ if (txok)
+ TX_STAT_INC(skb_success);
+ else
+ TX_STAT_INC(skb_failed);
}
}
@@ -141,7 +238,7 @@ static void hif_usb_tx_cb(struct urb *urb)
{
struct tx_buf *tx_buf = (struct tx_buf *) urb->context;
struct hif_device_usb *hif_dev;
- struct sk_buff *skb;
+ bool txok = true;
if (!tx_buf || !tx_buf->hif_dev)
return;
@@ -155,10 +252,7 @@ static void hif_usb_tx_cb(struct urb *urb)
case -ECONNRESET:
case -ENODEV:
case -ESHUTDOWN:
- /*
- * The URB has been killed, free the SKBs.
- */
- ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
+ txok = false;
/*
* If the URBs are being flushed, no need to add this
@@ -167,41 +261,19 @@ static void hif_usb_tx_cb(struct urb *urb)
spin_lock(&hif_dev->tx.tx_lock);
if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
spin_unlock(&hif_dev->tx.tx_lock);
+ ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
return;
}
spin_unlock(&hif_dev->tx.tx_lock);
- /*
- * In the stop() case, this URB has to be added to
- * the free list.
- */
- goto add_free;
+ break;
default:
+ txok = false;
break;
}
- /*
- * Check if TX has been stopped, this is needed because
- * this CB could have been invoked just after the TX lock
- * was released in hif_stop() and kill_urb() hasn't been
- * called yet.
- */
- spin_lock(&hif_dev->tx.tx_lock);
- if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
- spin_unlock(&hif_dev->tx.tx_lock);
- ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
- goto add_free;
- }
- spin_unlock(&hif_dev->tx.tx_lock);
-
- /* Complete the queued SKBs. */
- while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) {
- ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
- skb, 1);
- TX_STAT_INC(skb_completed);
- }
+ ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, txok);
-add_free:
/* Re-initialize the SKB queue */
tx_buf->len = tx_buf->offset = 0;
__skb_queue_head_init(&tx_buf->skb_queue);
@@ -274,7 +346,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev)
ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC);
if (ret) {
tx_buf->len = tx_buf->offset = 0;
- ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
+ ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, false);
__skb_queue_head_init(&tx_buf->skb_queue);
list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
hif_dev->tx.tx_buf_cnt++;
@@ -286,10 +358,11 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev)
return ret;
}
-static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb,
- struct ath9k_htc_tx_ctl *tx_ctl)
+static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb)
{
+ struct ath9k_htc_tx_ctl *tx_ctl;
unsigned long flags;
+ int ret = 0;
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
@@ -304,26 +377,36 @@ static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb,
return -ENOMEM;
}
- __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb);
- hif_dev->tx.tx_skb_cnt++;
+ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
- /* Send normal frames immediately */
- if (!tx_ctl || (tx_ctl && (tx_ctl->type == ATH9K_HTC_NORMAL)))
- __hif_usb_tx(hif_dev);
+ tx_ctl = HTC_SKB_CB(skb);
+
+ /* Mgmt/Beacon frames don't use the TX buffer pool */
+ if ((tx_ctl->type == ATH9K_HTC_MGMT) ||
+ (tx_ctl->type == ATH9K_HTC_BEACON)) {
+ ret = hif_usb_send_mgmt(hif_dev, skb);
+ }
+
+ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
+
+ if ((tx_ctl->type == ATH9K_HTC_NORMAL) ||
+ (tx_ctl->type == ATH9K_HTC_AMPDU)) {
+ __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb);
+ hif_dev->tx.tx_skb_cnt++;
+ }
/* Check if AMPDUs have to be sent immediately */
- if (tx_ctl && (tx_ctl->type == ATH9K_HTC_AMPDU) &&
- (hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) &&
+ if ((hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) &&
(hif_dev->tx.tx_skb_cnt < 2)) {
__hif_usb_tx(hif_dev);
}
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
- return 0;
+ return ret;
}
-static void hif_usb_start(void *hif_handle, u8 pipe_id)
+static void hif_usb_start(void *hif_handle)
{
struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
unsigned long flags;
@@ -335,14 +418,14 @@ static void hif_usb_start(void *hif_handle, u8 pipe_id)
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
}
-static void hif_usb_stop(void *hif_handle, u8 pipe_id)
+static void hif_usb_stop(void *hif_handle)
{
struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
unsigned long flags;
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
- ath9k_skb_queue_purge(hif_dev, &hif_dev->tx.tx_skb_queue);
+ ath9k_skb_queue_complete(hif_dev, &hif_dev->tx.tx_skb_queue, false);
hif_dev->tx.tx_skb_cnt = 0;
hif_dev->tx.flags |= HIF_USB_TX_STOP;
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
@@ -352,17 +435,18 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id)
&hif_dev->tx.tx_pending, list) {
usb_kill_urb(tx_buf->urb);
}
+
+ usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
}
-static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb,
- struct ath9k_htc_tx_ctl *tx_ctl)
+static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb)
{
struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
int ret = 0;
switch (pipe_id) {
case USB_WLAN_TX_PIPE:
- ret = hif_usb_send_tx(hif_dev, skb, tx_ctl);
+ ret = hif_usb_send_tx(hif_dev, skb);
break;
case USB_REG_OUT_PIPE:
ret = hif_usb_send_regout(hif_dev, skb);
@@ -377,6 +461,40 @@ static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb,
return ret;
}
+static inline bool check_index(struct sk_buff *skb, u8 idx)
+{
+ struct ath9k_htc_tx_ctl *tx_ctl;
+
+ tx_ctl = HTC_SKB_CB(skb);
+
+ if ((tx_ctl->type == ATH9K_HTC_AMPDU) &&
+ (tx_ctl->sta_idx == idx))
+ return true;
+
+ return false;
+}
+
+static void hif_usb_sta_drain(void *hif_handle, u8 idx)
+{
+ struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
+ struct sk_buff *skb, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
+
+ skb_queue_walk_safe(&hif_dev->tx.tx_skb_queue, skb, tmp) {
+ if (check_index(skb, idx)) {
+ __skb_unlink(skb, &hif_dev->tx.tx_skb_queue);
+ ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
+ skb, false);
+ hif_dev->tx.tx_skb_cnt--;
+ TX_STAT_INC(skb_failed);
+ }
+ }
+
+ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
+}
+
static struct ath9k_htc_hif hif_usb = {
.transport = ATH9K_HIF_USB,
.name = "ath9k_hif_usb",
@@ -386,6 +504,7 @@ static struct ath9k_htc_hif hif_usb = {
.start = hif_usb_start,
.stop = hif_usb_stop,
+ .sta_drain = hif_usb_sta_drain,
.send = hif_usb_send,
};
@@ -567,6 +686,9 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
case -ESHUTDOWN:
goto free;
default:
+ skb_reset_tail_pointer(skb);
+ skb_trim(skb, 0);
+
goto resubmit;
}
@@ -591,23 +713,15 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
USB_REG_IN_PIPE),
nskb->data, MAX_REG_IN_BUF_SIZE,
ath9k_hif_usb_reg_in_cb, nskb);
-
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret) {
- kfree_skb(nskb);
- urb->context = NULL;
- }
-
- return;
}
resubmit:
- skb_reset_tail_pointer(skb);
- skb_trim(skb, 0);
-
+ usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret)
+ if (ret) {
+ usb_unanchor_urb(urb);
goto free;
+ }
return;
free:
@@ -641,6 +755,8 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
kfree(tx_buf->buf);
kfree(tx_buf);
}
+
+ usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
}
static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
@@ -652,6 +768,7 @@ static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
INIT_LIST_HEAD(&hif_dev->tx.tx_pending);
spin_lock_init(&hif_dev->tx.tx_lock);
__skb_queue_head_init(&hif_dev->tx.tx_skb_queue);
+ init_usb_anchor(&hif_dev->mgmt_submitted);
for (i = 0; i < MAX_TX_URB_NUM; i++) {
tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL);
@@ -748,43 +865,67 @@ err_urb:
return ret;
}
-static void ath9k_hif_usb_dealloc_reg_in_urb(struct hif_device_usb *hif_dev)
+static void ath9k_hif_usb_dealloc_reg_in_urbs(struct hif_device_usb *hif_dev)
{
- if (hif_dev->reg_in_urb) {
- usb_kill_urb(hif_dev->reg_in_urb);
- if (hif_dev->reg_in_urb->context)
- kfree_skb((void *)hif_dev->reg_in_urb->context);
- usb_free_urb(hif_dev->reg_in_urb);
- hif_dev->reg_in_urb = NULL;
- }
+ usb_kill_anchored_urbs(&hif_dev->reg_in_submitted);
}
-static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev)
+static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev)
{
- struct sk_buff *skb;
+ struct urb *urb = NULL;
+ struct sk_buff *skb = NULL;
+ int i, ret;
- hif_dev->reg_in_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (hif_dev->reg_in_urb == NULL)
- return -ENOMEM;
+ init_usb_anchor(&hif_dev->reg_in_submitted);
- skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL);
- if (!skb)
- goto err;
+ for (i = 0; i < MAX_REG_IN_URB_NUM; i++) {
- usb_fill_bulk_urb(hif_dev->reg_in_urb, hif_dev->udev,
- usb_rcvbulkpipe(hif_dev->udev,
- USB_REG_IN_PIPE),
- skb->data, MAX_REG_IN_BUF_SIZE,
- ath9k_hif_usb_reg_in_cb, skb);
+ /* Allocate URB */
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (urb == NULL) {
+ ret = -ENOMEM;
+ goto err_urb;
+ }
- if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0)
- goto err;
+ /* Allocate buffer */
+ skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL);
+ if (!skb) {
+ ret = -ENOMEM;
+ goto err_skb;
+ }
+
+ usb_fill_bulk_urb(urb, hif_dev->udev,
+ usb_rcvbulkpipe(hif_dev->udev,
+ USB_REG_IN_PIPE),
+ skb->data, MAX_REG_IN_BUF_SIZE,
+ ath9k_hif_usb_reg_in_cb, skb);
+
+ /* Anchor URB */
+ usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
+
+ /* Submit URB */
+ ret = usb_submit_urb(urb, GFP_KERNEL);
+ if (ret) {
+ usb_unanchor_urb(urb);
+ goto err_submit;
+ }
+
+ /*
+ * Drop reference count.
+ * This ensures that the URB is freed when killing them.
+ */
+ usb_free_urb(urb);
+ }
return 0;
-err:
- ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
- return -ENOMEM;
+err_submit:
+ kfree_skb(skb);
+err_skb:
+ usb_free_urb(urb);
+err_urb:
+ ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev);
+ return ret;
}
static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev)
@@ -801,7 +942,7 @@ static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev)
goto err_rx;
/* Register Read */
- if (ath9k_hif_usb_alloc_reg_in_urb(hif_dev) < 0)
+ if (ath9k_hif_usb_alloc_reg_in_urbs(hif_dev) < 0)
goto err_reg;
return 0;
@@ -816,7 +957,7 @@ err:
static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
{
usb_kill_anchored_urbs(&hif_dev->regout_submitted);
- ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
+ ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev);
ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
}
@@ -1026,10 +1167,7 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
/* Find out which firmware to load */
if (IS_AR7010_DEVICE(id->driver_info))
- if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202)
- hif_dev->fw_name = FIRMWARE_AR7010_1_1;
- else
- hif_dev->fw_name = FIRMWARE_AR7010;
+ hif_dev->fw_name = FIRMWARE_AR7010_1_1;
else
hif_dev->fw_name = FIRMWARE_AR9271;
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index 7b9d863d4035..f59df48a86e2 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -31,7 +31,7 @@
/* FIXME: Verify these numbers (with Windows) */
#define MAX_TX_URB_NUM 8
-#define MAX_TX_BUF_NUM 1024
+#define MAX_TX_BUF_NUM 256
#define MAX_TX_BUF_SIZE 32768
#define MAX_TX_AGGR_NUM 20
@@ -40,7 +40,7 @@
#define MAX_PKT_NUM_IN_TRANSFER 10
#define MAX_REG_OUT_URB_NUM 1
-#define MAX_REG_OUT_BUF_NUM 8
+#define MAX_REG_IN_URB_NUM 64
#define MAX_REG_IN_BUF_SIZE 64
@@ -90,9 +90,10 @@ struct hif_device_usb {
const struct firmware *firmware;
struct htc_target *htc_handle;
struct hif_usb_tx tx;
- struct urb *reg_in_urb;
struct usb_anchor regout_submitted;
struct usb_anchor rx_submitted;
+ struct usb_anchor reg_in_submitted;
+ struct usb_anchor mgmt_submitted;
struct sk_buff *remain_skb;
const char *fw_name;
int rx_remain_len;
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index ec47be94b74f..48a885575085 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -67,8 +67,11 @@ enum htc_opmode {
};
#define ATH9K_HTC_HDRSPACE sizeof(struct htc_frame_hdr)
-#define ATH9K_HTC_AMPDU 1
+
+#define ATH9K_HTC_AMPDU 1
#define ATH9K_HTC_NORMAL 2
+#define ATH9K_HTC_BEACON 3
+#define ATH9K_HTC_MGMT 4
#define ATH9K_HTC_TX_CTSONLY 0x1
#define ATH9K_HTC_TX_RTSCTS 0x2
@@ -82,7 +85,8 @@ struct tx_frame_hdr {
__be32 flags; /* ATH9K_HTC_TX_* */
u8 key_type;
u8 keyix;
- u8 reserved[26];
+ u8 cookie;
+ u8 pad;
} __packed;
struct tx_mgmt_hdr {
@@ -92,26 +96,16 @@ struct tx_mgmt_hdr {
u8 flags;
u8 key_type;
u8 keyix;
- u16 reserved;
+ u8 cookie;
+ u8 pad;
} __packed;
struct tx_beacon_header {
- u8 len_changed;
u8 vif_index;
+ u8 len_changed;
u16 rev;
} __packed;
-struct ath9k_htc_target_hw {
- u32 flags;
- u32 flags_ext;
- u32 ampdu_limit;
- u8 ampdu_subframes;
- u8 tx_chainmask;
- u8 tx_chainmask_legacy;
- u8 rtscts_ratecode;
- u8 protmode;
-} __packed;
-
struct ath9k_htc_cap_target {
u32 flags;
u32 flags_ext;
@@ -121,21 +115,16 @@ struct ath9k_htc_cap_target {
u8 tx_chainmask_legacy;
u8 rtscts_ratecode;
u8 protmode;
+ u8 pad;
} __packed;
struct ath9k_htc_target_vif {
u8 index;
- u8 des_bssid[ETH_ALEN];
- __be32 opmode;
+ u8 opmode;
u8 myaddr[ETH_ALEN];
- u8 bssid[ETH_ALEN];
- u32 flags;
- u32 flags_ext;
- u16 ps_sta;
- __be16 rtsthreshold;
u8 ath_cap;
- u8 node;
- s8 mcast_rate;
+ __be16 rtsthreshold;
+ u8 pad;
} __packed;
#define ATH_HTC_STA_AUTH 0x0001
@@ -143,27 +132,16 @@ struct ath9k_htc_target_vif {
#define ATH_HTC_STA_ERP 0x0004
#define ATH_HTC_STA_HT 0x0008
-/* FIXME: UAPSD variables */
struct ath9k_htc_target_sta {
- u16 associd;
- u16 txpower;
- u32 ucastkey;
u8 macaddr[ETH_ALEN];
u8 bssid[ETH_ALEN];
u8 sta_index;
u8 vif_index;
- u8 vif_sta;
- __be16 flags; /* ATH_HTC_STA_* */
- u16 htcap;
- u8 valid;
- u16 capinfo;
- struct ath9k_htc_target_hw *hw;
- struct ath9k_htc_target_vif *vif;
- u16 txseqmgmt;
u8 is_vif_sta;
- u16 maxampdu;
- u16 iv16;
- u32 iv32;
+ __be16 flags; /* ATH_HTC_STA_* */
+ __be16 htcap;
+ __be16 maxampdu;
+ u8 pad;
} __packed;
struct ath9k_htc_target_aggr {
@@ -197,12 +175,31 @@ struct ath9k_htc_target_rate {
struct ath9k_htc_rate rates;
};
-struct ath9k_htc_target_stats {
- __be32 tx_shortretry;
- __be32 tx_longretry;
- __be32 tx_xretries;
- __be32 ht_txunaggr_xretry;
- __be32 ht_tx_xretries;
+struct ath9k_htc_target_int_stats {
+ __be32 rx;
+ __be32 rxorn;
+ __be32 rxeol;
+ __be32 txurn;
+ __be32 txto;
+ __be32 cst;
+} __packed;
+
+struct ath9k_htc_target_tx_stats {
+ __be32 xretries;
+ __be32 fifoerr;
+ __be32 filtered;
+ __be32 timer_exp;
+ __be32 shortretries;
+ __be32 longretries;
+ __be32 qnull;
+ __be32 encap_fail;
+ __be32 nobuf;
+} __packed;
+
+struct ath9k_htc_target_rx_stats {
+ __be32 nobuf;
+ __be32 host_send;
+ __be32 host_done;
} __packed;
#define ATH9K_HTC_MAX_VIF 2
@@ -244,6 +241,8 @@ struct ath9k_htc_vif {
u8 index;
u16 seq_no;
bool beacon_configured;
+ int bslot;
+ __le64 tsfadjust;
};
struct ath9k_vif_iter_data {
@@ -282,23 +281,65 @@ struct ath9k_htc_rx {
spinlock_t rxbuflock;
};
+#define ATH9K_HTC_TX_CLEANUP_INTERVAL 50 /* ms */
+#define ATH9K_HTC_TX_TIMEOUT_INTERVAL 2500 /* ms */
+#define ATH9K_HTC_TX_RESERVE 10
+#define ATH9K_HTC_TX_TIMEOUT_COUNT 20
+#define ATH9K_HTC_TX_THRESHOLD (MAX_TX_BUF_NUM - ATH9K_HTC_TX_RESERVE)
+
+#define ATH9K_HTC_OP_TX_QUEUES_STOP BIT(0)
+#define ATH9K_HTC_OP_TX_DRAIN BIT(1)
+
+struct ath9k_htc_tx {
+ u8 flags;
+ int queued_cnt;
+ struct sk_buff_head mgmt_ep_queue;
+ struct sk_buff_head cab_ep_queue;
+ struct sk_buff_head data_be_queue;
+ struct sk_buff_head data_bk_queue;
+ struct sk_buff_head data_vi_queue;
+ struct sk_buff_head data_vo_queue;
+ struct sk_buff_head tx_failed;
+ DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM);
+ struct timer_list cleanup_timer;
+ spinlock_t tx_lock;
+};
+
struct ath9k_htc_tx_ctl {
u8 type; /* ATH9K_HTC_* */
+ u8 epid;
+ u8 txok;
+ u8 sta_idx;
+ unsigned long timestamp;
};
+static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+
+ BUILD_BUG_ON(sizeof(struct ath9k_htc_tx_ctl) >
+ IEEE80211_TX_INFO_DRIVER_DATA_SIZE);
+ return (struct ath9k_htc_tx_ctl *) &tx_info->driver_data;
+}
+
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
#define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++)
#define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++)
+#define CAB_STAT_INC priv->debug.tx_stats.cab_queued++
#define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++)
+void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
+ struct ath_htc_rx_status *rxs);
+
struct ath_tx_stats {
u32 buf_queued;
u32 buf_completed;
u32 skb_queued;
- u32 skb_completed;
- u32 skb_dropped;
+ u32 skb_success;
+ u32 skb_failed;
+ u32 cab_queued;
u32 queue_stats[WME_NUM_AC];
};
@@ -306,25 +347,35 @@ struct ath_rx_stats {
u32 skb_allocated;
u32 skb_completed;
u32 skb_dropped;
+ u32 err_crc;
+ u32 err_decrypt_crc;
+ u32 err_mic;
+ u32 err_pre_delim;
+ u32 err_post_delim;
+ u32 err_decrypt_busy;
+ u32 err_phy;
+ u32 err_phy_stats[ATH9K_PHYERR_MAX];
};
struct ath9k_debug {
struct dentry *debugfs_phy;
- struct dentry *debugfs_tgt_stats;
- struct dentry *debugfs_xmit;
- struct dentry *debugfs_recv;
struct ath_tx_stats tx_stats;
struct ath_rx_stats rx_stats;
- u32 txrate;
};
#else
#define TX_STAT_INC(c) do { } while (0)
#define RX_STAT_INC(c) do { } while (0)
+#define CAB_STAT_INC do { } while (0)
#define TX_QSTAT_INC(c) do { } while (0)
+static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
+ struct ath_htc_rx_status *rxs)
+{
+}
+
#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
#define ATH_LED_PIN_DEF 1
@@ -351,10 +402,21 @@ struct ath_led {
int brightness;
};
+#define BSTUCK_THRESHOLD 10
+
+/*
+ * Adjust these when the max. no of beaconing interfaces is
+ * increased.
+ */
+#define DEFAULT_SWBA_RESPONSE 40 /* in TUs */
+#define MIN_SWBA_RESPONSE 10 /* in TUs */
+
struct htc_beacon_config {
+ struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF];
u16 beacon_interval;
u16 dtim_period;
u16 bmiss_timeout;
+ u32 bmiss_cnt;
};
struct ath_btcoex {
@@ -388,6 +450,9 @@ struct ath9k_htc_priv {
struct htc_target *htc;
struct wmi *wmi;
+ u16 fw_version_major;
+ u16 fw_version_minor;
+
enum htc_endpoint_id wmi_cmd_ep;
enum htc_endpoint_id beacon_ep;
enum htc_endpoint_id cab_ep;
@@ -411,27 +476,23 @@ struct ath9k_htc_priv {
u16 txpowlimit;
u16 nvifs;
u16 nstations;
- u32 bmiss_cnt;
bool rearm_ani;
bool reconfig_beacon;
+ unsigned int rxfilter;
struct ath9k_hw_cal_data caldata;
+ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
spinlock_t beacon_lock;
+ struct htc_beacon_config cur_beacon_conf;
- bool tx_queues_stop;
- spinlock_t tx_lock;
+ struct ath9k_htc_rx rx;
+ struct ath9k_htc_tx tx;
- struct ieee80211_vif *vif;
- struct htc_beacon_config cur_beacon_conf;
- unsigned int rxfilter;
struct tasklet_struct swba_tasklet;
struct tasklet_struct rx_tasklet;
- struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
- struct ath9k_htc_rx rx;
- struct tasklet_struct tx_tasklet;
- struct sk_buff_head tx_queue;
struct delayed_work ani_work;
+ struct tasklet_struct tx_failed_tasklet;
struct work_struct ps_work;
struct work_struct fatal_work;
@@ -470,11 +531,18 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
void ath9k_htc_reset(struct ath9k_htc_priv *priv);
+void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif);
+void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif);
+void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif);
void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv);
void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif);
void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv);
-void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending);
+void ath9k_htc_swba(struct ath9k_htc_priv *priv,
+ struct wmi_event_swba *swba);
void ath9k_htc_rxep(void *priv, struct sk_buff *skb,
enum htc_endpoint_id ep_id);
@@ -491,14 +559,23 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv);
void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv);
int ath9k_tx_init(struct ath9k_htc_priv *priv);
-void ath9k_tx_tasklet(unsigned long data);
-int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb);
+int ath9k_htc_tx_start(struct ath9k_htc_priv *priv,
+ struct sk_buff *skb, u8 slot, bool is_cab);
void ath9k_tx_cleanup(struct ath9k_htc_priv *priv);
bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype);
int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv);
int get_hw_qnum(u16 queue, int *hwq_map);
int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
struct ath9k_tx_queue_info *qinfo);
+void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv);
+void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv);
+int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv);
+void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot);
+void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv);
+void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event);
+void ath9k_htc_tx_failed(struct ath9k_htc_priv *priv);
+void ath9k_tx_failed_tasklet(unsigned long data);
+void ath9k_htc_tx_cleanup_timer(unsigned long data);
int ath9k_rx_init(struct ath9k_htc_priv *priv);
void ath9k_rx_cleanup(struct ath9k_htc_priv *priv);
@@ -528,15 +605,9 @@ void ath9k_htc_suspend(struct htc_target *htc_handle);
int ath9k_htc_resume(struct htc_target *htc_handle);
#endif
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
-int ath9k_htc_debug_create_root(void);
-void ath9k_htc_debug_remove_root(void);
int ath9k_htc_init_debug(struct ath_hw *ah);
-void ath9k_htc_exit_debug(struct ath_hw *ah);
#else
-static inline int ath9k_htc_debug_create_root(void) { return 0; };
-static inline void ath9k_htc_debug_remove_root(void) {};
static inline int ath9k_htc_init_debug(struct ath_hw *ah) { return 0; };
-static inline void ath9k_htc_exit_debug(struct ath_hw *ah) {};
#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
#endif /* HTC_H */
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index 8f56158e5887..a157107b3f3b 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -18,6 +18,50 @@
#define FUDGE 2
+void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
+{
+ struct ath_hw *ah = priv->ah;
+ struct ath9k_tx_queue_info qi, qi_be;
+
+ memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
+ memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info));
+
+ ath9k_hw_get_txq_props(ah, priv->beaconq, &qi);
+
+ if (priv->ah->opmode == NL80211_IFTYPE_AP) {
+ qi.tqi_aifs = 1;
+ qi.tqi_cwmin = 0;
+ qi.tqi_cwmax = 0;
+ } else if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) {
+ int qnum = priv->hwq_map[WME_AC_BE];
+
+ ath9k_hw_get_txq_props(ah, qnum, &qi_be);
+
+ qi.tqi_aifs = qi_be.tqi_aifs;
+
+ /*
+ * For WIFI Beacon Distribution
+ * Long slot time : 2x cwmin
+ * Short slot time : 4x cwmin
+ */
+ if (ah->slottime == ATH9K_SLOT_TIME_20)
+ qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
+ else
+ qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
+
+ qi.tqi_cwmax = qi_be.tqi_cwmax;
+
+ }
+
+ if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) {
+ ath_err(ath9k_hw_common(ah),
+ "Unable to update beacon queue %u!\n", priv->beaconq);
+ } else {
+ ath9k_hw_resettxqueue(ah, priv->beaconq);
+ }
+}
+
+
static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
struct htc_beacon_config *bss_conf)
{
@@ -154,6 +198,15 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
intval /= ATH9K_HTC_MAX_BCN_VIF;
nexttbtt = intval;
+ /*
+ * To reduce beacon misses under heavy TX load,
+ * set the beacon response time to a larger value.
+ */
+ if (intval > DEFAULT_SWBA_RESPONSE)
+ priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
+ else
+ priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
+
if (priv->op_flags & OP_TSF_RESET) {
ath9k_hw_reset_tsf(priv->ah);
priv->op_flags &= ~OP_TSF_RESET;
@@ -172,12 +225,16 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
imask |= ATH9K_INT_SWBA;
ath_dbg(common, ATH_DBG_CONFIG,
- "AP Beacon config, intval: %d, nexttbtt: %u imask: 0x%x\n",
- bss_conf->beacon_interval, nexttbtt, imask);
+ "AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d "
+ "imask: 0x%x\n",
+ bss_conf->beacon_interval, nexttbtt,
+ priv->ah->config.sw_beacon_response_time, imask);
+
+ ath9k_htc_beaconq_config(priv);
WMI_CMD(WMI_DISABLE_INTR_CMDID);
ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
- priv->bmiss_cnt = 0;
+ priv->cur_beacon_conf.bmiss_cnt = 0;
htc_imask = cpu_to_be32(imask);
WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
}
@@ -205,16 +262,26 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
nexttbtt += intval;
} while (nexttbtt < tsftu);
+ /*
+ * Only one IBSS interfce is allowed.
+ */
+ if (intval > DEFAULT_SWBA_RESPONSE)
+ priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
+ else
+ priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
+
if (priv->op_flags & OP_ENABLE_BEACON)
imask |= ATH9K_INT_SWBA;
ath_dbg(common, ATH_DBG_CONFIG,
- "IBSS Beacon config, intval: %d, nexttbtt: %u, imask: 0x%x\n",
- bss_conf->beacon_interval, nexttbtt, imask);
+ "IBSS Beacon config, intval: %d, nexttbtt: %u, "
+ "resp_time: %d, imask: 0x%x\n",
+ bss_conf->beacon_interval, nexttbtt,
+ priv->ah->config.sw_beacon_response_time, imask);
WMI_CMD(WMI_DISABLE_INTR_CMDID);
ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
- priv->bmiss_cnt = 0;
+ priv->cur_beacon_conf.bmiss_cnt = 0;
htc_imask = cpu_to_be32(imask);
WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
}
@@ -225,38 +292,101 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
dev_kfree_skb_any(skb);
}
-void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
+static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv,
+ int slot)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ieee80211_vif *vif;
+ struct sk_buff *skb;
+ struct ieee80211_hdr *hdr;
+ int padpos, padsize, ret, tx_slot;
+
+ spin_lock_bh(&priv->beacon_lock);
+
+ vif = priv->cur_beacon_conf.bslot[slot];
+
+ skb = ieee80211_get_buffered_bc(priv->hw, vif);
+
+ while(skb) {
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ padpos = ath9k_cmn_padpos(hdr->frame_control);
+ padsize = padpos & 3;
+ if (padsize && skb->len > padpos) {
+ if (skb_headroom(skb) < padsize) {
+ dev_kfree_skb_any(skb);
+ goto next;
+ }
+ skb_push(skb, padsize);
+ memmove(skb->data, skb->data + padsize, padpos);
+ }
+
+ tx_slot = ath9k_htc_tx_get_slot(priv);
+ if (tx_slot < 0) {
+ ath_dbg(common, ATH_DBG_XMIT, "No free CAB slot\n");
+ dev_kfree_skb_any(skb);
+ goto next;
+ }
+
+ ret = ath9k_htc_tx_start(priv, skb, tx_slot, true);
+ if (ret != 0) {
+ ath9k_htc_tx_clear_slot(priv, tx_slot);
+ dev_kfree_skb_any(skb);
+
+ ath_dbg(common, ATH_DBG_XMIT,
+ "Failed to send CAB frame\n");
+ } else {
+ spin_lock_bh(&priv->tx.tx_lock);
+ priv->tx.queued_cnt++;
+ spin_unlock_bh(&priv->tx.tx_lock);
+ }
+ next:
+ skb = ieee80211_get_buffered_bc(priv->hw, vif);
+ }
+
+ spin_unlock_bh(&priv->beacon_lock);
+}
+
+static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
+ int slot)
{
- struct ath9k_htc_vif *avp = (void *)priv->vif->drv_priv;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ieee80211_vif *vif;
+ struct ath9k_htc_vif *avp;
struct tx_beacon_header beacon_hdr;
- struct ath9k_htc_tx_ctl tx_ctl;
+ struct ath9k_htc_tx_ctl *tx_ctl;
struct ieee80211_tx_info *info;
+ struct ieee80211_mgmt *mgmt;
struct sk_buff *beacon;
u8 *tx_fhdr;
+ int ret;
memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header));
- memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl));
-
- /* FIXME: Handle BMISS */
- if (beacon_pending != 0) {
- priv->bmiss_cnt++;
- return;
- }
spin_lock_bh(&priv->beacon_lock);
+ vif = priv->cur_beacon_conf.bslot[slot];
+ avp = (struct ath9k_htc_vif *)vif->drv_priv;
+
if (unlikely(priv->op_flags & OP_SCANNING)) {
spin_unlock_bh(&priv->beacon_lock);
return;
}
/* Get a new beacon */
- beacon = ieee80211_beacon_get(priv->hw, priv->vif);
+ beacon = ieee80211_beacon_get(priv->hw, vif);
if (!beacon) {
spin_unlock_bh(&priv->beacon_lock);
return;
}
+ /*
+ * Update the TSF adjust value here, the HW will
+ * add this value for every beacon.
+ */
+ mgmt = (struct ieee80211_mgmt *)beacon->data;
+ mgmt->u.beacon.timestamp = avp->tsfadjust;
+
info = IEEE80211_SKB_CB(beacon);
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
struct ieee80211_hdr *hdr =
@@ -266,45 +396,149 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
}
- tx_ctl.type = ATH9K_HTC_NORMAL;
+ tx_ctl = HTC_SKB_CB(beacon);
+ memset(tx_ctl, 0, sizeof(*tx_ctl));
+
+ tx_ctl->type = ATH9K_HTC_BEACON;
+ tx_ctl->epid = priv->beacon_ep;
+
beacon_hdr.vif_index = avp->index;
tx_fhdr = skb_push(beacon, sizeof(beacon_hdr));
memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr));
- htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl);
+ ret = htc_send(priv->htc, beacon);
+ if (ret != 0) {
+ if (ret == -ENOMEM) {
+ ath_dbg(common, ATH_DBG_BSTUCK,
+ "Failed to send beacon, no free TX buffer\n");
+ }
+ dev_kfree_skb_any(beacon);
+ }
+
+ spin_unlock_bh(&priv->beacon_lock);
+}
+
+static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv,
+ struct wmi_event_swba *swba)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ u64 tsf;
+ u32 tsftu;
+ u16 intval;
+ int slot;
+
+ intval = priv->cur_beacon_conf.beacon_interval & ATH9K_BEACON_PERIOD;
+ tsf = be64_to_cpu(swba->tsf);
+ tsftu = TSF_TO_TU(tsf >> 32, tsf);
+ slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval;
+ slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1;
+
+ ath_dbg(common, ATH_DBG_BEACON,
+ "Choose slot: %d, tsf: %llu, tsftu: %u, intval: %u\n",
+ slot, tsf, tsftu, intval);
+
+ return slot;
+}
+
+void ath9k_htc_swba(struct ath9k_htc_priv *priv,
+ struct wmi_event_swba *swba)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ int slot;
+
+ if (swba->beacon_pending != 0) {
+ priv->cur_beacon_conf.bmiss_cnt++;
+ if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) {
+ ath_dbg(common, ATH_DBG_BSTUCK,
+ "Beacon stuck, HW reset\n");
+ ieee80211_queue_work(priv->hw,
+ &priv->fatal_work);
+ }
+ return;
+ }
+
+ if (priv->cur_beacon_conf.bmiss_cnt) {
+ ath_dbg(common, ATH_DBG_BSTUCK,
+ "Resuming beacon xmit after %u misses\n",
+ priv->cur_beacon_conf.bmiss_cnt);
+ priv->cur_beacon_conf.bmiss_cnt = 0;
+ }
+
+ slot = ath9k_htc_choose_bslot(priv, swba);
+ spin_lock_bh(&priv->beacon_lock);
+ if (priv->cur_beacon_conf.bslot[slot] == NULL) {
+ spin_unlock_bh(&priv->beacon_lock);
+ return;
+ }
spin_unlock_bh(&priv->beacon_lock);
+
+ ath9k_htc_send_buffered(priv, slot);
+ ath9k_htc_send_beacon(priv, slot);
}
-/* Currently, only for IBSS */
-void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
+void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif)
{
- struct ath_hw *ah = priv->ah;
- struct ath9k_tx_queue_info qi, qi_be;
- int qnum = priv->hwq_map[WME_AC_BE];
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
+ int i = 0;
- memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
- memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info));
+ spin_lock_bh(&priv->beacon_lock);
+ for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) {
+ if (priv->cur_beacon_conf.bslot[i] == NULL) {
+ avp->bslot = i;
+ break;
+ }
+ }
+
+ priv->cur_beacon_conf.bslot[avp->bslot] = vif;
+ spin_unlock_bh(&priv->beacon_lock);
+
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Added interface at beacon slot: %d\n", avp->bslot);
+}
+
+void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
+
+ spin_lock_bh(&priv->beacon_lock);
+ priv->cur_beacon_conf.bslot[avp->bslot] = NULL;
+ spin_unlock_bh(&priv->beacon_lock);
+
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Removed interface at beacon slot: %d\n", avp->bslot);
+}
- ath9k_hw_get_txq_props(ah, qnum, &qi_be);
+/*
+ * Calculate the TSF adjustment value for all slots
+ * other than zero.
+ */
+void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
+ struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
+ u64 tsfadjust;
+
+ if (avp->bslot == 0)
+ return;
- qi.tqi_aifs = qi_be.tqi_aifs;
- /* For WIFI Beacon Distribution
- * Long slot time : 2x cwmin
- * Short slot time : 4x cwmin
+ /*
+ * The beacon interval cannot be different for multi-AP mode,
+ * and we reach here only for VIF slots greater than zero,
+ * so beacon_interval is guaranteed to be set in cur_conf.
*/
- if (ah->slottime == ATH9K_SLOT_TIME_20)
- qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
- else
- qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
- qi.tqi_cwmax = qi_be.tqi_cwmax;
+ tsfadjust = cur_conf->beacon_interval * avp->bslot / ATH9K_HTC_MAX_BCN_VIF;
+ avp->tsfadjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
- if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) {
- ath_err(ath9k_hw_common(ah),
- "Unable to update beacon queue %u!\n", qnum);
- } else {
- ath9k_hw_resettxqueue(ah, priv->beaconq);
- }
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "tsfadjust is: %llu for bslot: %d\n",
+ (unsigned long long)tsfadjust, avp->bslot);
}
static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
new file mode 100644
index 000000000000..eca777497fe5
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright (c) 2010-2011 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 "htc.h"
+
+static int ath9k_debugfs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct ath9k_htc_target_int_stats cmd_rsp;
+ char buf[512];
+ unsigned int len = 0;
+ int ret = 0;
+
+ memset(&cmd_rsp, 0, sizeof(cmd_rsp));
+
+ WMI_CMD(WMI_INT_STATS_CMDID);
+ if (ret)
+ return -EINVAL;
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "RX",
+ be32_to_cpu(cmd_rsp.rx));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "RXORN",
+ be32_to_cpu(cmd_rsp.rxorn));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "RXEOL",
+ be32_to_cpu(cmd_rsp.rxeol));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "TXURN",
+ be32_to_cpu(cmd_rsp.txurn));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "TXTO",
+ be32_to_cpu(cmd_rsp.txto));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "CST",
+ be32_to_cpu(cmd_rsp.cst));
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_tgt_int_stats = {
+ .read = read_file_tgt_int_stats,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct ath9k_htc_target_tx_stats cmd_rsp;
+ char buf[512];
+ unsigned int len = 0;
+ int ret = 0;
+
+ memset(&cmd_rsp, 0, sizeof(cmd_rsp));
+
+ WMI_CMD(WMI_TX_STATS_CMDID);
+ if (ret)
+ return -EINVAL;
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "Xretries",
+ be32_to_cpu(cmd_rsp.xretries));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "FifoErr",
+ be32_to_cpu(cmd_rsp.fifoerr));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "Filtered",
+ be32_to_cpu(cmd_rsp.filtered));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "TimerExp",
+ be32_to_cpu(cmd_rsp.timer_exp));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "ShortRetries",
+ be32_to_cpu(cmd_rsp.shortretries));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "LongRetries",
+ be32_to_cpu(cmd_rsp.longretries));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "QueueNull",
+ be32_to_cpu(cmd_rsp.qnull));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "EncapFail",
+ be32_to_cpu(cmd_rsp.encap_fail));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "NoBuf",
+ be32_to_cpu(cmd_rsp.nobuf));
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_tgt_tx_stats = {
+ .read = read_file_tgt_tx_stats,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct ath9k_htc_target_rx_stats cmd_rsp;
+ char buf[512];
+ unsigned int len = 0;
+ int ret = 0;
+
+ memset(&cmd_rsp, 0, sizeof(cmd_rsp));
+
+ WMI_CMD(WMI_RX_STATS_CMDID);
+ if (ret)
+ return -EINVAL;
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "NoBuf",
+ be32_to_cpu(cmd_rsp.nobuf));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "HostSend",
+ be32_to_cpu(cmd_rsp.host_send));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "HostDone",
+ be32_to_cpu(cmd_rsp.host_done));
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_tgt_rx_stats = {
+ .read = read_file_tgt_rx_stats,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ char buf[512];
+ unsigned int len = 0;
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "Buffers queued",
+ priv->debug.tx_stats.buf_queued);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "Buffers completed",
+ priv->debug.tx_stats.buf_completed);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "SKBs queued",
+ priv->debug.tx_stats.skb_queued);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "SKBs success",
+ priv->debug.tx_stats.skb_success);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "SKBs failed",
+ priv->debug.tx_stats.skb_failed);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "CAB queued",
+ priv->debug.tx_stats.cab_queued);
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "BE queued",
+ priv->debug.tx_stats.queue_stats[WME_AC_BE]);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "BK queued",
+ priv->debug.tx_stats.queue_stats[WME_AC_BK]);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "VI queued",
+ priv->debug.tx_stats.queue_stats[WME_AC_VI]);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "VO queued",
+ priv->debug.tx_stats.queue_stats[WME_AC_VO]);
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_xmit = {
+ .read = read_file_xmit,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
+ struct ath_htc_rx_status *rxs)
+{
+#define RX_PHY_ERR_INC(c) priv->debug.rx_stats.err_phy_stats[c]++
+
+ if (rxs->rs_status & ATH9K_RXERR_CRC)
+ priv->debug.rx_stats.err_crc++;
+ if (rxs->rs_status & ATH9K_RXERR_DECRYPT)
+ priv->debug.rx_stats.err_decrypt_crc++;
+ if (rxs->rs_status & ATH9K_RXERR_MIC)
+ priv->debug.rx_stats.err_mic++;
+ if (rxs->rs_status & ATH9K_RX_DELIM_CRC_PRE)
+ priv->debug.rx_stats.err_pre_delim++;
+ if (rxs->rs_status & ATH9K_RX_DELIM_CRC_POST)
+ priv->debug.rx_stats.err_post_delim++;
+ if (rxs->rs_status & ATH9K_RX_DECRYPT_BUSY)
+ priv->debug.rx_stats.err_decrypt_busy++;
+
+ if (rxs->rs_status & ATH9K_RXERR_PHY) {
+ priv->debug.rx_stats.err_phy++;
+ if (rxs->rs_phyerr < ATH9K_PHYERR_MAX)
+ RX_PHY_ERR_INC(rxs->rs_phyerr);
+ }
+
+#undef RX_PHY_ERR_INC
+}
+
+static ssize_t read_file_recv(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+#define PHY_ERR(s, p) \
+ len += snprintf(buf + len, size - len, "%20s : %10u\n", s, \
+ priv->debug.rx_stats.err_phy_stats[p]);
+
+ struct ath9k_htc_priv *priv = file->private_data;
+ char *buf;
+ unsigned int len = 0, size = 1500;
+ ssize_t retval = 0;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "SKBs allocated",
+ priv->debug.rx_stats.skb_allocated);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "SKBs completed",
+ priv->debug.rx_stats.skb_completed);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "SKBs Dropped",
+ priv->debug.rx_stats.skb_dropped);
+
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "CRC ERR",
+ priv->debug.rx_stats.err_crc);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "DECRYPT CRC ERR",
+ priv->debug.rx_stats.err_decrypt_crc);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "MIC ERR",
+ priv->debug.rx_stats.err_mic);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "PRE-DELIM CRC ERR",
+ priv->debug.rx_stats.err_pre_delim);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "POST-DELIM CRC ERR",
+ priv->debug.rx_stats.err_post_delim);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "DECRYPT BUSY ERR",
+ priv->debug.rx_stats.err_decrypt_busy);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "TOTAL PHY ERR",
+ priv->debug.rx_stats.err_phy);
+
+
+ PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN);
+ PHY_ERR("TIMING", ATH9K_PHYERR_TIMING);
+ PHY_ERR("PARITY", ATH9K_PHYERR_PARITY);
+ PHY_ERR("RATE", ATH9K_PHYERR_RATE);
+ PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH);
+ PHY_ERR("RADAR", ATH9K_PHYERR_RADAR);
+ PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE);
+ PHY_ERR("TOR", ATH9K_PHYERR_TOR);
+ PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING);
+ PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY);
+ PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL);
+ PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL);
+ PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP);
+ PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE);
+ PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART);
+ PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT);
+ PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING);
+ PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC);
+ PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL);
+ PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE);
+ PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART);
+ PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL);
+ PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP);
+ PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR);
+ PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
+ PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL);
+
+ if (len > size)
+ len = size;
+
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return retval;
+
+#undef PHY_ERR
+}
+
+static const struct file_operations fops_recv = {
+ .read = read_file_recv,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_slot(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ char buf[512];
+ unsigned int len = 0;
+
+ spin_lock_bh(&priv->tx.tx_lock);
+
+ len += snprintf(buf + len, sizeof(buf) - len, "TX slot bitmap : ");
+
+ len += bitmap_scnprintf(buf + len, sizeof(buf) - len,
+ priv->tx.tx_slot, MAX_TX_BUF_NUM);
+
+ len += snprintf(buf + len, sizeof(buf) - len, "\n");
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "Used slots : %d\n",
+ bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM));
+
+ spin_unlock_bh(&priv->tx.tx_lock);
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_slot = {
+ .read = read_file_slot,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_queue(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ char buf[512];
+ unsigned int len = 0;
+
+ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+ "Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue));
+
+ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+ "Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue));
+
+ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+ "Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue));
+
+ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+ "Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue));
+
+ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+ "Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue));
+
+ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+ "Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue));
+
+ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+ "Failed queue", skb_queue_len(&priv->tx.tx_failed));
+
+ spin_lock_bh(&priv->tx.tx_lock);
+ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+ "Queued count", priv->tx.queued_cnt);
+ spin_unlock_bh(&priv->tx.tx_lock);
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+}
+
+static const struct file_operations fops_queue = {
+ .read = read_file_queue,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_debug(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ char buf[32];
+ unsigned int len;
+
+ len = sprintf(buf, "0x%08x\n", common->debug_mask);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ unsigned long mask;
+ char buf[32];
+ ssize_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ if (strict_strtoul(buf, 0, &mask))
+ return -EINVAL;
+
+ common->debug_mask = mask;
+ return count;
+}
+
+static const struct file_operations fops_debug = {
+ .read = read_file_debug,
+ .write = write_file_debug,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+int ath9k_htc_init_debug(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+
+ priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME,
+ priv->hw->wiphy->debugfsdir);
+ if (!priv->debug.debugfs_phy)
+ return -ENOMEM;
+
+ debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_tgt_int_stats);
+ debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_tgt_tx_stats);
+ debugfs_create_file("tgt_rx_stats", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_tgt_rx_stats);
+ debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_xmit);
+ debugfs_create_file("recv", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_recv);
+ debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_slot);
+ debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_queue);
+ debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy,
+ priv, &fops_debug);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
index 7e630a81b453..dc0b33d01210 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
@@ -398,9 +398,9 @@ void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
/* Start TX */
htc_start(priv->htc);
- spin_lock_bh(&priv->tx_lock);
- priv->tx_queues_stop = false;
- spin_unlock_bh(&priv->tx_lock);
+ spin_lock_bh(&priv->tx.tx_lock);
+ priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
+ spin_unlock_bh(&priv->tx.tx_lock);
ieee80211_wake_queues(hw);
WMI_CMD(WMI_ENABLE_INTR_CMDID);
@@ -429,13 +429,15 @@ void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
/* Stop TX */
ieee80211_stop_queues(hw);
- htc_stop(priv->htc);
+ ath9k_htc_tx_drain(priv);
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
- skb_queue_purge(&priv->tx_queue);
/* Stop RX */
WMI_CMD(WMI_STOP_RECV_CMDID);
+ /* Clear the WMI event queue */
+ ath9k_wmi_event_drain(priv);
+
/*
* The MIB counters have to be disabled here,
* since the target doesn't do it.
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 8303b34bdc90..06e043bffaf4 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -140,7 +140,6 @@ static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
static void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
{
- ath9k_htc_exit_debug(priv->ah);
ath9k_hw_deinit(priv->ah);
kfree(priv->ah);
priv->ah = NULL;
@@ -643,7 +642,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
{
struct ath_hw *ah = NULL;
struct ath_common *common;
- int ret = 0, csz = 0;
+ int i, ret = 0, csz = 0;
priv->op_flags |= OP_INVALID;
@@ -671,20 +670,19 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
common->priv = priv;
common->debug_mask = ath9k_debug;
- spin_lock_init(&priv->wmi->wmi_lock);
spin_lock_init(&priv->beacon_lock);
- spin_lock_init(&priv->tx_lock);
+ spin_lock_init(&priv->tx.tx_lock);
mutex_init(&priv->mutex);
mutex_init(&priv->htc_pm_lock);
- tasklet_init(&priv->swba_tasklet, ath9k_swba_tasklet,
- (unsigned long)priv);
tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
(unsigned long)priv);
- tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet,
+ tasklet_init(&priv->tx_failed_tasklet, ath9k_tx_failed_tasklet,
(unsigned long)priv);
INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work);
INIT_WORK(&priv->ps_work, ath9k_ps_work);
INIT_WORK(&priv->fatal_work, ath9k_fatal_work);
+ setup_timer(&priv->tx.cleanup_timer, ath9k_htc_tx_cleanup_timer,
+ (unsigned long)priv);
/*
* Cache line size is used to size and align various
@@ -701,16 +699,13 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
goto err_hw;
}
- ret = ath9k_htc_init_debug(ah);
- if (ret) {
- ath_err(common, "Unable to create debugfs files\n");
- goto err_debug;
- }
-
ret = ath9k_init_queues(priv);
if (ret)
goto err_queues;
+ for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
+ priv->cur_beacon_conf.bslot[i] = NULL;
+
ath9k_init_crypto(priv);
ath9k_init_channels_rates(priv);
ath9k_init_misc(priv);
@@ -723,8 +718,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
return 0;
err_queues:
- ath9k_htc_exit_debug(ah);
-err_debug:
ath9k_hw_deinit(ah);
err_hw:
@@ -745,11 +738,15 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
IEEE80211_HW_HAS_RATE_CONTROL |
IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK;
+ IEEE80211_HW_PS_NULLFUNC_STACK |
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC);
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT);
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -782,6 +779,32 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
}
+static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)
+{
+ struct ieee80211_hw *hw = priv->hw;
+ struct wmi_fw_version cmd_rsp;
+ int ret;
+
+ memset(&cmd_rsp, 0, sizeof(cmd_rsp));
+
+ WMI_CMD(WMI_GET_FW_VERSION);
+ if (ret)
+ return -EINVAL;
+
+ priv->fw_version_major = be16_to_cpu(cmd_rsp.major);
+ priv->fw_version_minor = be16_to_cpu(cmd_rsp.minor);
+
+ snprintf(hw->wiphy->fw_version, ETHTOOL_BUSINFO_LEN, "%d.%d",
+ priv->fw_version_major,
+ priv->fw_version_minor);
+
+ dev_info(priv->dev, "ath9k_htc: FW Version: %d.%d\n",
+ priv->fw_version_major,
+ priv->fw_version_minor);
+
+ return 0;
+}
+
static int ath9k_init_device(struct ath9k_htc_priv *priv,
u16 devid, char *product, u32 drv_info)
{
@@ -801,6 +824,10 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
common = ath9k_hw_common(ah);
ath9k_set_hw_capab(priv, hw);
+ error = ath9k_init_firmware_version(priv);
+ if (error != 0)
+ goto err_fw;
+
/* Initialize regulatory */
error = ath_regd_init(&common->regulatory, priv->hw->wiphy,
ath9k_reg_notifier);
@@ -831,6 +858,12 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
goto err_world;
}
+ error = ath9k_htc_init_debug(priv->ah);
+ if (error) {
+ ath_err(common, "Unable to create debugfs files\n");
+ goto err_world;
+ }
+
ath_dbg(common, ATH_DBG_CONFIG,
"WMI:%d, BCN:%d, CAB:%d, UAPSD:%d, MGMT:%d, "
"BE:%d, BK:%d, VI:%d, VO:%d\n",
@@ -861,6 +894,8 @@ err_rx:
err_tx:
/* Nothing */
err_regd:
+ /* Nothing */
+err_fw:
ath9k_deinit_priv(priv);
err_init:
return error;
@@ -949,38 +984,20 @@ int ath9k_htc_resume(struct htc_target *htc_handle)
static int __init ath9k_htc_init(void)
{
- int error;
-
- error = ath9k_htc_debug_create_root();
- if (error < 0) {
- printk(KERN_ERR
- "ath9k_htc: Unable to create debugfs root: %d\n",
- error);
- goto err_dbg;
- }
-
- error = ath9k_hif_usb_init();
- if (error < 0) {
+ if (ath9k_hif_usb_init() < 0) {
printk(KERN_ERR
"ath9k_htc: No USB devices found,"
" driver not installed.\n");
- error = -ENODEV;
- goto err_usb;
+ return -ENODEV;
}
return 0;
-
-err_usb:
- ath9k_htc_debug_remove_root();
-err_dbg:
- return error;
}
module_init(ath9k_htc_init);
static void __exit ath9k_htc_exit(void)
{
ath9k_hif_usb_exit();
- ath9k_htc_debug_remove_root();
printk(KERN_INFO "ath9k_htc: Driver unloaded\n");
}
module_exit(ath9k_htc_exit);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index db8c0c044e9e..4de38643cb53 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -16,10 +16,6 @@
#include "htc.h"
-#ifdef CONFIG_ATH9K_HTC_DEBUGFS
-static struct dentry *ath9k_debugfs_root;
-#endif
-
/*************/
/* Utilities */
/*************/
@@ -197,11 +193,16 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv)
ath9k_htc_stop_ani(priv);
ieee80211_stop_queues(priv->hw);
- htc_stop(priv->htc);
+
+ del_timer_sync(&priv->tx.cleanup_timer);
+ ath9k_htc_tx_drain(priv);
+
WMI_CMD(WMI_DISABLE_INTR_CMDID);
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
WMI_CMD(WMI_STOP_RECV_CMDID);
+ ath9k_wmi_event_drain(priv);
+
caldata = &priv->caldata;
ret = ath9k_hw_reset(ah, ah->curchan, caldata, false);
if (ret) {
@@ -225,6 +226,9 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv)
ath9k_htc_vif_reconfig(priv);
ieee80211_wake_queues(priv->hw);
+ mod_timer(&priv->tx.cleanup_timer,
+ jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
+
ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
}
@@ -250,11 +254,16 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);
ath9k_htc_ps_wakeup(priv);
- htc_stop(priv->htc);
+
+ del_timer_sync(&priv->tx.cleanup_timer);
+ ath9k_htc_tx_drain(priv);
+
WMI_CMD(WMI_DISABLE_INTR_CMDID);
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
WMI_CMD(WMI_STOP_RECV_CMDID);
+ ath9k_wmi_event_drain(priv);
+
ath_dbg(common, ATH_DBG_CONFIG,
"(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n",
priv->ah->curchan->channel,
@@ -263,6 +272,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
if (!fastcc)
caldata = &priv->caldata;
+
ret = ath9k_hw_reset(ah, hchan, caldata, fastcc);
if (ret) {
ath_err(common,
@@ -296,6 +306,9 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
ath9k_htc_vif_reconfig(priv);
+ mod_timer(&priv->tx.cleanup_timer,
+ jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
+
err:
ath9k_htc_ps_restore(priv);
return ret;
@@ -349,7 +362,7 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
- hvif.opmode = cpu_to_be32(HTC_M_MONITOR);
+ hvif.opmode = HTC_M_MONITOR;
hvif.index = ffz(priv->vif_slot);
WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
@@ -382,7 +395,7 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
tsta.is_vif_sta = 1;
tsta.sta_index = sta_idx;
tsta.vif_index = hvif.index;
- tsta.maxampdu = 0xffff;
+ tsta.maxampdu = cpu_to_be16(0xffff);
WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
if (ret) {
@@ -463,9 +476,7 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
ista = (struct ath9k_htc_sta *) sta->drv_priv;
memcpy(&tsta.macaddr, sta->addr, ETH_ALEN);
memcpy(&tsta.bssid, common->curbssid, ETH_ALEN);
- tsta.associd = common->curaid;
tsta.is_vif_sta = 0;
- tsta.valid = true;
ista->index = sta_idx;
} else {
memcpy(&tsta.macaddr, vif->addr, ETH_ALEN);
@@ -474,7 +485,7 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
tsta.sta_index = sta_idx;
tsta.vif_index = avp->index;
- tsta.maxampdu = 0xffff;
+ tsta.maxampdu = cpu_to_be16(0xffff);
if (sta && sta->ht_cap.ht_supported)
tsta.flags = cpu_to_be16(ATH_HTC_STA_HT);
@@ -709,218 +720,13 @@ static int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv,
(aggr.aggr_enable) ? "Starting" : "Stopping",
sta->addr, tid);
- spin_lock_bh(&priv->tx_lock);
+ spin_lock_bh(&priv->tx.tx_lock);
ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP;
- spin_unlock_bh(&priv->tx_lock);
+ spin_unlock_bh(&priv->tx.tx_lock);
return ret;
}
-/*********/
-/* DEBUG */
-/*********/
-
-#ifdef CONFIG_ATH9K_HTC_DEBUGFS
-
-static int ath9k_debugfs_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ath9k_htc_priv *priv = file->private_data;
- struct ath9k_htc_target_stats cmd_rsp;
- char buf[512];
- unsigned int len = 0;
- int ret = 0;
-
- memset(&cmd_rsp, 0, sizeof(cmd_rsp));
-
- WMI_CMD(WMI_TGT_STATS_CMDID);
- if (ret)
- return -EINVAL;
-
-
- len += snprintf(buf + len, sizeof(buf) - len,
- "%19s : %10u\n", "TX Short Retries",
- be32_to_cpu(cmd_rsp.tx_shortretry));
- len += snprintf(buf + len, sizeof(buf) - len,
- "%19s : %10u\n", "TX Long Retries",
- be32_to_cpu(cmd_rsp.tx_longretry));
- len += snprintf(buf + len, sizeof(buf) - len,
- "%19s : %10u\n", "TX Xretries",
- be32_to_cpu(cmd_rsp.tx_xretries));
- len += snprintf(buf + len, sizeof(buf) - len,
- "%19s : %10u\n", "TX Unaggr. Xretries",
- be32_to_cpu(cmd_rsp.ht_txunaggr_xretry));
- len += snprintf(buf + len, sizeof(buf) - len,
- "%19s : %10u\n", "TX Xretries (HT)",
- be32_to_cpu(cmd_rsp.ht_tx_xretries));
- len += snprintf(buf + len, sizeof(buf) - len,
- "%19s : %10u\n", "TX Rate", priv->debug.txrate);
-
- if (len > sizeof(buf))
- len = sizeof(buf);
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static const struct file_operations fops_tgt_stats = {
- .read = read_file_tgt_stats,
- .open = ath9k_debugfs_open,
- .owner = THIS_MODULE,
- .llseek = default_llseek,
-};
-
-static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ath9k_htc_priv *priv = file->private_data;
- char buf[512];
- unsigned int len = 0;
-
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "Buffers queued",
- priv->debug.tx_stats.buf_queued);
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "Buffers completed",
- priv->debug.tx_stats.buf_completed);
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "SKBs queued",
- priv->debug.tx_stats.skb_queued);
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "SKBs completed",
- priv->debug.tx_stats.skb_completed);
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "SKBs dropped",
- priv->debug.tx_stats.skb_dropped);
-
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "BE queued",
- priv->debug.tx_stats.queue_stats[WME_AC_BE]);
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "BK queued",
- priv->debug.tx_stats.queue_stats[WME_AC_BK]);
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "VI queued",
- priv->debug.tx_stats.queue_stats[WME_AC_VI]);
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "VO queued",
- priv->debug.tx_stats.queue_stats[WME_AC_VO]);
-
- if (len > sizeof(buf))
- len = sizeof(buf);
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static const struct file_operations fops_xmit = {
- .read = read_file_xmit,
- .open = ath9k_debugfs_open,
- .owner = THIS_MODULE,
- .llseek = default_llseek,
-};
-
-static ssize_t read_file_recv(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ath9k_htc_priv *priv = file->private_data;
- char buf[512];
- unsigned int len = 0;
-
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "SKBs allocated",
- priv->debug.rx_stats.skb_allocated);
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "SKBs completed",
- priv->debug.rx_stats.skb_completed);
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "SKBs Dropped",
- priv->debug.rx_stats.skb_dropped);
-
- if (len > sizeof(buf))
- len = sizeof(buf);
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static const struct file_operations fops_recv = {
- .read = read_file_recv,
- .open = ath9k_debugfs_open,
- .owner = THIS_MODULE,
- .llseek = default_llseek,
-};
-
-int ath9k_htc_init_debug(struct ath_hw *ah)
-{
- struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
-
- if (!ath9k_debugfs_root)
- return -ENOENT;
-
- priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy),
- ath9k_debugfs_root);
- if (!priv->debug.debugfs_phy)
- goto err;
-
- priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR,
- priv->debug.debugfs_phy,
- priv, &fops_tgt_stats);
- if (!priv->debug.debugfs_tgt_stats)
- goto err;
-
-
- priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR,
- priv->debug.debugfs_phy,
- priv, &fops_xmit);
- if (!priv->debug.debugfs_xmit)
- goto err;
-
- priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR,
- priv->debug.debugfs_phy,
- priv, &fops_recv);
- if (!priv->debug.debugfs_recv)
- goto err;
-
- return 0;
-
-err:
- ath9k_htc_exit_debug(ah);
- return -ENOMEM;
-}
-
-void ath9k_htc_exit_debug(struct ath_hw *ah)
-{
- struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
-
- debugfs_remove(priv->debug.debugfs_recv);
- debugfs_remove(priv->debug.debugfs_xmit);
- debugfs_remove(priv->debug.debugfs_tgt_stats);
- debugfs_remove(priv->debug.debugfs_phy);
-}
-
-int ath9k_htc_debug_create_root(void)
-{
- ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
- if (!ath9k_debugfs_root)
- return -ENOENT;
-
- return 0;
-}
-
-void ath9k_htc_debug_remove_root(void)
-{
- debugfs_remove(ath9k_debugfs_root);
- ath9k_debugfs_root = NULL;
-}
-
-#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
-
/*******/
/* ANI */
/*******/
@@ -1040,7 +846,8 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
struct ath9k_htc_priv *priv = hw->priv;
- int padpos, padsize, ret;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ int padpos, padsize, ret, slot;
hdr = (struct ieee80211_hdr *) skb->data;
@@ -1048,30 +855,32 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
padpos = ath9k_cmn_padpos(hdr->frame_control);
padsize = padpos & 3;
if (padsize && skb->len > padpos) {
- if (skb_headroom(skb) < padsize)
+ if (skb_headroom(skb) < padsize) {
+ ath_dbg(common, ATH_DBG_XMIT, "No room for padding\n");
goto fail_tx;
+ }
skb_push(skb, padsize);
memmove(skb->data, skb->data + padsize, padpos);
}
- ret = ath9k_htc_tx_start(priv, skb);
- if (ret != 0) {
- if (ret == -ENOMEM) {
- ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
- "Stopping TX queues\n");
- ieee80211_stop_queues(hw);
- spin_lock_bh(&priv->tx_lock);
- priv->tx_queues_stop = true;
- spin_unlock_bh(&priv->tx_lock);
- } else {
- ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
- "Tx failed\n");
- }
+ slot = ath9k_htc_tx_get_slot(priv);
+ if (slot < 0) {
+ ath_dbg(common, ATH_DBG_XMIT, "No free TX slot\n");
goto fail_tx;
}
+ ret = ath9k_htc_tx_start(priv, skb, slot, false);
+ if (ret != 0) {
+ ath_dbg(common, ATH_DBG_XMIT, "Tx failed\n");
+ goto clear_slot;
+ }
+
+ ath9k_htc_check_stop_queues(priv);
+
return;
+clear_slot:
+ ath9k_htc_tx_clear_slot(priv, slot);
fail_tx:
dev_kfree_skb_any(skb);
}
@@ -1130,12 +939,15 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
priv->op_flags &= ~OP_INVALID;
htc_start(priv->htc);
- spin_lock_bh(&priv->tx_lock);
- priv->tx_queues_stop = false;
- spin_unlock_bh(&priv->tx_lock);
+ spin_lock_bh(&priv->tx.tx_lock);
+ priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
+ spin_unlock_bh(&priv->tx.tx_lock);
ieee80211_wake_queues(hw);
+ mod_timer(&priv->tx.cleanup_timer,
+ jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
+
if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) {
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
AR_STOMP_LOW_WLAN_WGHT);
@@ -1164,16 +976,16 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
}
ath9k_htc_ps_wakeup(priv);
- htc_stop(priv->htc);
+
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);
+ del_timer_sync(&priv->tx.cleanup_timer);
+ ath9k_htc_tx_drain(priv);
+ ath9k_wmi_event_drain(priv);
mutex_unlock(&priv->mutex);
@@ -1245,13 +1057,13 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
switch (vif->type) {
case NL80211_IFTYPE_STATION:
- hvif.opmode = cpu_to_be32(HTC_M_STA);
+ hvif.opmode = HTC_M_STA;
break;
case NL80211_IFTYPE_ADHOC:
- hvif.opmode = cpu_to_be32(HTC_M_IBSS);
+ hvif.opmode = HTC_M_IBSS;
break;
case NL80211_IFTYPE_AP:
- hvif.opmode = cpu_to_be32(HTC_M_HOSTAP);
+ hvif.opmode = HTC_M_HOSTAP;
break;
default:
ath_err(common,
@@ -1281,14 +1093,20 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
priv->vif_slot |= (1 << avp->index);
priv->nvifs++;
- priv->vif = vif;
INC_VIF(priv, vif->type);
+
+ if ((vif->type == NL80211_IFTYPE_AP) ||
+ (vif->type == NL80211_IFTYPE_ADHOC))
+ ath9k_htc_assign_bslot(priv, vif);
+
ath9k_htc_set_opmode(priv);
if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
- !(priv->op_flags & OP_ANI_RUNNING))
+ !(priv->op_flags & OP_ANI_RUNNING)) {
+ ath9k_hw_set_tsfadjust(priv->ah, 1);
ath9k_htc_start_ani(priv);
+ }
ath_dbg(common, ATH_DBG_CONFIG,
"Attach a VIF of type: %d at idx: %d\n", vif->type, avp->index);
@@ -1321,9 +1139,13 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
priv->vif_slot &= ~(1 << avp->index);
ath9k_htc_remove_station(priv, vif, NULL);
- priv->vif = NULL;
DEC_VIF(priv, vif->type);
+
+ if ((vif->type == NL80211_IFTYPE_AP) ||
+ (vif->type == NL80211_IFTYPE_ADHOC))
+ ath9k_htc_remove_bslot(priv, vif);
+
ath9k_htc_set_opmode(priv);
/*
@@ -1493,10 +1315,13 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_sta *sta)
{
struct ath9k_htc_priv *priv = hw->priv;
+ struct ath9k_htc_sta *ista;
int ret;
mutex_lock(&priv->mutex);
ath9k_htc_ps_wakeup(priv);
+ ista = (struct ath9k_htc_sta *) sta->drv_priv;
+ htc_sta_drain(priv->htc, ista->index);
ret = ath9k_htc_remove_station(priv, vif, sta);
ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
@@ -1644,6 +1469,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) {
ath_dbg(common, ATH_DBG_CONFIG,
"Beacon enabled for BSS: %pM\n", bss_conf->bssid);
+ ath9k_htc_set_tsfadjust(priv, vif);
priv->op_flags |= OP_ENABLE_BEACON;
ath9k_htc_beacon_config(priv, vif);
}
@@ -1758,9 +1584,9 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
ista = (struct ath9k_htc_sta *) sta->drv_priv;
- spin_lock_bh(&priv->tx_lock);
+ spin_lock_bh(&priv->tx.tx_lock);
ista->tid_state[tid] = AGGR_OPERATIONAL;
- spin_unlock_bh(&priv->tx_lock);
+ spin_unlock_bh(&priv->tx.tx_lock);
break;
default:
ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n");
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 4a4f27ba96af..723a3a9c5cd9 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -53,6 +53,138 @@ int get_hw_qnum(u16 queue, int *hwq_map)
}
}
+void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv)
+{
+ spin_lock_bh(&priv->tx.tx_lock);
+ priv->tx.queued_cnt++;
+ if ((priv->tx.queued_cnt >= ATH9K_HTC_TX_THRESHOLD) &&
+ !(priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) {
+ priv->tx.flags |= ATH9K_HTC_OP_TX_QUEUES_STOP;
+ ieee80211_stop_queues(priv->hw);
+ }
+ spin_unlock_bh(&priv->tx.tx_lock);
+}
+
+void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv)
+{
+ spin_lock_bh(&priv->tx.tx_lock);
+ if ((priv->tx.queued_cnt < ATH9K_HTC_TX_THRESHOLD) &&
+ (priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) {
+ priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
+ ieee80211_wake_queues(priv->hw);
+ }
+ spin_unlock_bh(&priv->tx.tx_lock);
+}
+
+int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv)
+{
+ int slot;
+
+ spin_lock_bh(&priv->tx.tx_lock);
+ slot = find_first_zero_bit(priv->tx.tx_slot, MAX_TX_BUF_NUM);
+ if (slot >= MAX_TX_BUF_NUM) {
+ spin_unlock_bh(&priv->tx.tx_lock);
+ return -ENOBUFS;
+ }
+ __set_bit(slot, priv->tx.tx_slot);
+ spin_unlock_bh(&priv->tx.tx_lock);
+
+ return slot;
+}
+
+void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot)
+{
+ spin_lock_bh(&priv->tx.tx_lock);
+ __clear_bit(slot, priv->tx.tx_slot);
+ spin_unlock_bh(&priv->tx.tx_lock);
+}
+
+static inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv,
+ u16 qnum)
+{
+ enum htc_endpoint_id epid;
+
+ switch (qnum) {
+ case 0:
+ TX_QSTAT_INC(WME_AC_VO);
+ epid = priv->data_vo_ep;
+ break;
+ case 1:
+ TX_QSTAT_INC(WME_AC_VI);
+ epid = priv->data_vi_ep;
+ break;
+ case 2:
+ TX_QSTAT_INC(WME_AC_BE);
+ epid = priv->data_be_ep;
+ break;
+ case 3:
+ default:
+ TX_QSTAT_INC(WME_AC_BK);
+ epid = priv->data_bk_ep;
+ break;
+ }
+
+ return epid;
+}
+
+static inline struct sk_buff_head*
+get_htc_epid_queue(struct ath9k_htc_priv *priv, u8 epid)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct sk_buff_head *epid_queue = NULL;
+
+ if (epid == priv->mgmt_ep)
+ epid_queue = &priv->tx.mgmt_ep_queue;
+ else if (epid == priv->cab_ep)
+ epid_queue = &priv->tx.cab_ep_queue;
+ else if (epid == priv->data_be_ep)
+ epid_queue = &priv->tx.data_be_queue;
+ else if (epid == priv->data_bk_ep)
+ epid_queue = &priv->tx.data_bk_queue;
+ else if (epid == priv->data_vi_ep)
+ epid_queue = &priv->tx.data_vi_queue;
+ else if (epid == priv->data_vo_ep)
+ epid_queue = &priv->tx.data_vo_queue;
+ else
+ ath_err(common, "Invalid EPID: %d\n", epid);
+
+ return epid_queue;
+}
+
+/*
+ * Removes the driver header and returns the TX slot number
+ */
+static inline int strip_drv_header(struct ath9k_htc_priv *priv,
+ struct sk_buff *skb)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_tx_ctl *tx_ctl;
+ int slot;
+
+ tx_ctl = HTC_SKB_CB(skb);
+
+ if (tx_ctl->epid == priv->mgmt_ep) {
+ struct tx_mgmt_hdr *tx_mhdr =
+ (struct tx_mgmt_hdr *)skb->data;
+ slot = tx_mhdr->cookie;
+ skb_pull(skb, sizeof(struct tx_mgmt_hdr));
+ } else if ((tx_ctl->epid == priv->data_bk_ep) ||
+ (tx_ctl->epid == priv->data_be_ep) ||
+ (tx_ctl->epid == priv->data_vi_ep) ||
+ (tx_ctl->epid == priv->data_vo_ep) ||
+ (tx_ctl->epid == priv->cab_ep)) {
+ struct tx_frame_hdr *tx_fhdr =
+ (struct tx_frame_hdr *)skb->data;
+ slot = tx_fhdr->cookie;
+ skb_pull(skb, sizeof(struct tx_frame_hdr));
+ } else {
+ ath_err(common, "Unsupported EPID: %d\n", tx_ctl->epid);
+ slot = -EINVAL;
+ }
+
+ return slot;
+}
+
int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
struct ath9k_tx_queue_info *qinfo)
{
@@ -79,23 +211,140 @@ int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
return error;
}
-int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
+static void ath9k_htc_tx_mgmt(struct ath9k_htc_priv *priv,
+ struct ath9k_htc_vif *avp,
+ struct sk_buff *skb,
+ u8 sta_idx, u8 vif_idx, u8 slot)
+{
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_mgmt *mgmt;
+ struct ieee80211_hdr *hdr;
+ struct tx_mgmt_hdr mgmt_hdr;
+ struct ath9k_htc_tx_ctl *tx_ctl;
+ u8 *tx_fhdr;
+
+ tx_ctl = HTC_SKB_CB(skb);
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ memset(tx_ctl, 0, sizeof(*tx_ctl));
+ memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr));
+
+ /*
+ * Set the TSF adjust value for probe response
+ * frame also.
+ */
+ if (avp && unlikely(ieee80211_is_probe_resp(hdr->frame_control))) {
+ mgmt = (struct ieee80211_mgmt *)skb->data;
+ mgmt->u.probe_resp.timestamp = avp->tsfadjust;
+ }
+
+ tx_ctl->type = ATH9K_HTC_MGMT;
+
+ mgmt_hdr.node_idx = sta_idx;
+ mgmt_hdr.vif_idx = vif_idx;
+ mgmt_hdr.tidno = 0;
+ mgmt_hdr.flags = 0;
+ mgmt_hdr.cookie = slot;
+
+ mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
+ if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
+ mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
+ else
+ mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
+
+ tx_fhdr = skb_push(skb, sizeof(mgmt_hdr));
+ memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr));
+ tx_ctl->epid = priv->mgmt_ep;
+}
+
+static void ath9k_htc_tx_data(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif,
+ struct sk_buff *skb,
+ u8 sta_idx, u8 vif_idx, u8 slot,
+ bool is_cab)
+{
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr;
+ struct ath9k_htc_tx_ctl *tx_ctl;
+ struct tx_frame_hdr tx_hdr;
+ u32 flags = 0;
+ u8 *qc, *tx_fhdr;
+ u16 qnum;
+
+ tx_ctl = HTC_SKB_CB(skb);
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ memset(tx_ctl, 0, sizeof(*tx_ctl));
+ memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr));
+
+ tx_hdr.node_idx = sta_idx;
+ tx_hdr.vif_idx = vif_idx;
+ tx_hdr.cookie = slot;
+
+ /*
+ * This is a bit redundant but it helps to get
+ * the per-packet index quickly when draining the
+ * TX queue in the HIF layer. Otherwise we would
+ * have to parse the packet contents ...
+ */
+ tx_ctl->sta_idx = sta_idx;
+
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ tx_ctl->type = ATH9K_HTC_AMPDU;
+ tx_hdr.data_type = ATH9K_HTC_AMPDU;
+ } else {
+ tx_ctl->type = ATH9K_HTC_NORMAL;
+ tx_hdr.data_type = ATH9K_HTC_NORMAL;
+ }
+
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
+ qc = ieee80211_get_qos_ctl(hdr);
+ tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+ }
+
+ /* Check for RTS protection */
+ if (priv->hw->wiphy->rts_threshold != (u32) -1)
+ if (skb->len > priv->hw->wiphy->rts_threshold)
+ flags |= ATH9K_HTC_TX_RTSCTS;
+
+ /* CTS-to-self */
+ if (!(flags & ATH9K_HTC_TX_RTSCTS) &&
+ (vif && vif->bss_conf.use_cts_prot))
+ flags |= ATH9K_HTC_TX_CTSONLY;
+
+ tx_hdr.flags = cpu_to_be32(flags);
+ tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
+ if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
+ tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
+ else
+ tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
+
+ tx_fhdr = skb_push(skb, sizeof(tx_hdr));
+ memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
+
+ if (is_cab) {
+ CAB_STAT_INC;
+ tx_ctl->epid = priv->cab_ep;
+ return;
+ }
+
+ qnum = skb_get_queue_mapping(skb);
+ tx_ctl->epid = get_htc_epid(priv, qnum);
+}
+
+int ath9k_htc_tx_start(struct ath9k_htc_priv *priv,
+ struct sk_buff *skb,
+ u8 slot, bool is_cab)
{
struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *sta = tx_info->control.sta;
struct ieee80211_vif *vif = tx_info->control.vif;
struct ath9k_htc_sta *ista;
- struct ath9k_htc_vif *avp;
- struct ath9k_htc_tx_ctl tx_ctl;
- enum htc_endpoint_id epid;
- u16 qnum;
- __le16 fc;
- u8 *tx_fhdr;
+ struct ath9k_htc_vif *avp = NULL;
u8 sta_idx, vif_idx;
hdr = (struct ieee80211_hdr *) skb->data;
- fc = hdr->frame_control;
/*
* Find out on which interface this packet has to be
@@ -124,218 +373,432 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
sta_idx = priv->vif_sta_pos[vif_idx];
}
- memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl));
+ if (ieee80211_is_data(hdr->frame_control))
+ ath9k_htc_tx_data(priv, vif, skb,
+ sta_idx, vif_idx, slot, is_cab);
+ else
+ ath9k_htc_tx_mgmt(priv, avp, skb,
+ sta_idx, vif_idx, slot);
- if (ieee80211_is_data(fc)) {
- struct tx_frame_hdr tx_hdr;
- u32 flags = 0;
- u8 *qc;
- memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr));
+ return htc_send(priv->htc, skb);
+}
- tx_hdr.node_idx = sta_idx;
- tx_hdr.vif_idx = vif_idx;
+static inline bool __ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
+ struct ath9k_htc_sta *ista, u8 tid)
+{
+ bool ret = false;
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
- tx_ctl.type = ATH9K_HTC_AMPDU;
- tx_hdr.data_type = ATH9K_HTC_AMPDU;
- } else {
- tx_ctl.type = ATH9K_HTC_NORMAL;
- tx_hdr.data_type = ATH9K_HTC_NORMAL;
- }
+ spin_lock_bh(&priv->tx.tx_lock);
+ if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP))
+ ret = true;
+ spin_unlock_bh(&priv->tx.tx_lock);
+
+ return ret;
+}
+
+static void ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif,
+ struct sk_buff *skb)
+{
+ struct ieee80211_sta *sta;
+ struct ieee80211_hdr *hdr;
+ __le16 fc;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = hdr->frame_control;
+
+ rcu_read_lock();
+
+ sta = ieee80211_find_sta(vif, hdr->addr1);
+ if (!sta) {
+ rcu_read_unlock();
+ return;
+ }
+ if (sta && conf_is_ht(&priv->hw->conf) &&
+ !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
if (ieee80211_is_data_qos(fc)) {
+ u8 *qc, tid;
+ struct ath9k_htc_sta *ista;
+
qc = ieee80211_get_qos_ctl(hdr);
- tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+ tid = qc[0] & 0xf;
+ ista = (struct ath9k_htc_sta *)sta->drv_priv;
+ if (__ath9k_htc_check_tx_aggr(priv, ista, tid)) {
+ ieee80211_start_tx_ba_session(sta, tid, 0);
+ spin_lock_bh(&priv->tx.tx_lock);
+ ista->tid_state[tid] = AGGR_PROGRESS;
+ spin_unlock_bh(&priv->tx.tx_lock);
+ }
}
+ }
- /* Check for RTS protection */
- if (priv->hw->wiphy->rts_threshold != (u32) -1)
- if (skb->len > priv->hw->wiphy->rts_threshold)
- flags |= ATH9K_HTC_TX_RTSCTS;
+ rcu_read_unlock();
+}
- /* CTS-to-self */
- if (!(flags & ATH9K_HTC_TX_RTSCTS) &&
- (vif && vif->bss_conf.use_cts_prot))
- flags |= ATH9K_HTC_TX_CTSONLY;
+static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv,
+ struct sk_buff *skb,
+ struct __wmi_event_txstatus *txs)
+{
+ struct ieee80211_vif *vif;
+ struct ath9k_htc_tx_ctl *tx_ctl;
+ struct ieee80211_tx_info *tx_info;
+ struct ieee80211_tx_rate *rate;
+ struct ieee80211_conf *cur_conf = &priv->hw->conf;
+ struct ieee80211_supported_band *sband;
+ bool txok;
+ int slot;
- tx_hdr.flags = cpu_to_be32(flags);
- tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
- if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
- tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
- else
- tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
+ slot = strip_drv_header(priv, skb);
+ if (slot < 0) {
+ dev_kfree_skb_any(skb);
+ return;
+ }
- tx_fhdr = skb_push(skb, sizeof(tx_hdr));
- memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
+ tx_ctl = HTC_SKB_CB(skb);
+ txok = tx_ctl->txok;
+ tx_info = IEEE80211_SKB_CB(skb);
+ vif = tx_info->control.vif;
+ rate = &tx_info->status.rates[0];
+ sband = priv->hw->wiphy->bands[cur_conf->channel->band];
- qnum = skb_get_queue_mapping(skb);
+ memset(&tx_info->status, 0, sizeof(tx_info->status));
- switch (qnum) {
- case 0:
- TX_QSTAT_INC(WME_AC_VO);
- epid = priv->data_vo_ep;
- break;
- case 1:
- TX_QSTAT_INC(WME_AC_VI);
- epid = priv->data_vi_ep;
- break;
- case 2:
- TX_QSTAT_INC(WME_AC_BE);
- epid = priv->data_be_ep;
- break;
- case 3:
- default:
- TX_QSTAT_INC(WME_AC_BK);
- epid = priv->data_bk_ep;
- break;
- }
- } else {
- struct tx_mgmt_hdr mgmt_hdr;
+ /*
+ * URB submission failed for this frame, it never reached
+ * the target.
+ */
+ if (!txok || !vif || !txs)
+ goto send_mac80211;
- memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr));
+ if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK)
+ tx_info->flags |= IEEE80211_TX_STAT_ACK;
+
+ if (txs->ts_flags & ATH9K_HTC_TXSTAT_FILT)
+ tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
- tx_ctl.type = ATH9K_HTC_NORMAL;
+ if (txs->ts_flags & ATH9K_HTC_TXSTAT_RTC_CTS)
+ rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
- mgmt_hdr.node_idx = sta_idx;
- mgmt_hdr.vif_idx = vif_idx;
- mgmt_hdr.tidno = 0;
- mgmt_hdr.flags = 0;
+ rate->count = 1;
+ rate->idx = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_RATE);
- mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
- if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
- mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
- else
- mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
+ if (txs->ts_flags & ATH9K_HTC_TXSTAT_MCS) {
+ rate->flags |= IEEE80211_TX_RC_MCS;
- tx_fhdr = skb_push(skb, sizeof(mgmt_hdr));
- memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr));
- epid = priv->mgmt_ep;
+ if (txs->ts_flags & ATH9K_HTC_TXSTAT_CW40)
+ rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+ if (txs->ts_flags & ATH9K_HTC_TXSTAT_SGI)
+ rate->flags |= IEEE80211_TX_RC_SHORT_GI;
+ } else {
+ if (cur_conf->channel->band == IEEE80211_BAND_5GHZ)
+ rate->idx += 4; /* No CCK rates */
}
- return htc_send(priv->htc, skb, epid, &tx_ctl);
+ ath9k_htc_check_tx_aggr(priv, vif, skb);
+
+send_mac80211:
+ spin_lock_bh(&priv->tx.tx_lock);
+ if (WARN_ON(--priv->tx.queued_cnt < 0))
+ priv->tx.queued_cnt = 0;
+ spin_unlock_bh(&priv->tx.tx_lock);
+
+ ath9k_htc_tx_clear_slot(priv, slot);
+
+ /* Send status to mac80211 */
+ ieee80211_tx_status(priv->hw, skb);
}
-static bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
- struct ath9k_htc_sta *ista, u8 tid)
+static inline void ath9k_htc_tx_drainq(struct ath9k_htc_priv *priv,
+ struct sk_buff_head *queue)
{
- bool ret = false;
+ struct sk_buff *skb;
- spin_lock_bh(&priv->tx_lock);
- if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP))
- ret = true;
- spin_unlock_bh(&priv->tx_lock);
+ while ((skb = skb_dequeue(queue)) != NULL) {
+ ath9k_htc_tx_process(priv, skb, NULL);
+ }
+}
- return ret;
+void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv)
+{
+ struct ath9k_htc_tx_event *event, *tmp;
+
+ spin_lock_bh(&priv->tx.tx_lock);
+ priv->tx.flags |= ATH9K_HTC_OP_TX_DRAIN;
+ spin_unlock_bh(&priv->tx.tx_lock);
+
+ /*
+ * Ensure that all pending TX frames are flushed,
+ * and that the TX completion/failed tasklets is killed.
+ */
+ htc_stop(priv->htc);
+ tasklet_kill(&priv->wmi->wmi_event_tasklet);
+ tasklet_kill(&priv->tx_failed_tasklet);
+
+ ath9k_htc_tx_drainq(priv, &priv->tx.mgmt_ep_queue);
+ ath9k_htc_tx_drainq(priv, &priv->tx.cab_ep_queue);
+ ath9k_htc_tx_drainq(priv, &priv->tx.data_be_queue);
+ ath9k_htc_tx_drainq(priv, &priv->tx.data_bk_queue);
+ ath9k_htc_tx_drainq(priv, &priv->tx.data_vi_queue);
+ ath9k_htc_tx_drainq(priv, &priv->tx.data_vo_queue);
+ ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed);
+
+ /*
+ * The TX cleanup timer has already been killed.
+ */
+ spin_lock_bh(&priv->wmi->event_lock);
+ list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) {
+ list_del(&event->list);
+ kfree(event);
+ }
+ spin_unlock_bh(&priv->wmi->event_lock);
+
+ spin_lock_bh(&priv->tx.tx_lock);
+ priv->tx.flags &= ~ATH9K_HTC_OP_TX_DRAIN;
+ spin_unlock_bh(&priv->tx.tx_lock);
}
-void ath9k_tx_tasklet(unsigned long data)
+void ath9k_tx_failed_tasklet(unsigned long data)
{
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
- struct ieee80211_vif *vif;
- struct ieee80211_sta *sta;
- struct ieee80211_hdr *hdr;
- struct ieee80211_tx_info *tx_info;
- struct sk_buff *skb = NULL;
- __le16 fc;
- while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) {
+ spin_lock_bh(&priv->tx.tx_lock);
+ if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) {
+ spin_unlock_bh(&priv->tx.tx_lock);
+ return;
+ }
+ spin_unlock_bh(&priv->tx.tx_lock);
- hdr = (struct ieee80211_hdr *) skb->data;
- fc = hdr->frame_control;
- tx_info = IEEE80211_SKB_CB(skb);
- vif = tx_info->control.vif;
+ ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed);
+}
- memset(&tx_info->status, 0, sizeof(tx_info->status));
+static inline bool check_cookie(struct ath9k_htc_priv *priv,
+ struct sk_buff *skb,
+ u8 cookie, u8 epid)
+{
+ u8 fcookie = 0;
+
+ if (epid == priv->mgmt_ep) {
+ struct tx_mgmt_hdr *hdr;
+ hdr = (struct tx_mgmt_hdr *) skb->data;
+ fcookie = hdr->cookie;
+ } else if ((epid == priv->data_bk_ep) ||
+ (epid == priv->data_be_ep) ||
+ (epid == priv->data_vi_ep) ||
+ (epid == priv->data_vo_ep) ||
+ (epid == priv->cab_ep)) {
+ struct tx_frame_hdr *hdr;
+ hdr = (struct tx_frame_hdr *) skb->data;
+ fcookie = hdr->cookie;
+ }
- if (!vif)
- goto send_mac80211;
+ if (fcookie == cookie)
+ return true;
- rcu_read_lock();
+ return false;
+}
- sta = ieee80211_find_sta(vif, hdr->addr1);
- if (!sta) {
- rcu_read_unlock();
- ieee80211_tx_status(priv->hw, skb);
- continue;
+static struct sk_buff* ath9k_htc_tx_get_packet(struct ath9k_htc_priv *priv,
+ struct __wmi_event_txstatus *txs)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct sk_buff_head *epid_queue;
+ struct sk_buff *skb, *tmp;
+ unsigned long flags;
+ u8 epid = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_EPID);
+
+ epid_queue = get_htc_epid_queue(priv, epid);
+ if (!epid_queue)
+ return NULL;
+
+ spin_lock_irqsave(&epid_queue->lock, flags);
+ skb_queue_walk_safe(epid_queue, skb, tmp) {
+ if (check_cookie(priv, skb, txs->cookie, epid)) {
+ __skb_unlink(skb, epid_queue);
+ spin_unlock_irqrestore(&epid_queue->lock, flags);
+ return skb;
}
+ }
+ spin_unlock_irqrestore(&epid_queue->lock, flags);
- /* Check if we need to start aggregation */
+ ath_dbg(common, ATH_DBG_XMIT,
+ "No matching packet for cookie: %d, epid: %d\n",
+ txs->cookie, epid);
- if (sta && conf_is_ht(&priv->hw->conf) &&
- !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
- if (ieee80211_is_data_qos(fc)) {
- u8 *qc, tid;
- struct ath9k_htc_sta *ista;
+ return NULL;
+}
- qc = ieee80211_get_qos_ctl(hdr);
- tid = qc[0] & 0xf;
- ista = (struct ath9k_htc_sta *)sta->drv_priv;
+void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event)
+{
+ struct wmi_event_txstatus *txs = (struct wmi_event_txstatus *)wmi_event;
+ struct __wmi_event_txstatus *__txs;
+ struct sk_buff *skb;
+ struct ath9k_htc_tx_event *tx_pend;
+ int i;
- if (ath9k_htc_check_tx_aggr(priv, ista, tid)) {
- ieee80211_start_tx_ba_session(sta, tid, 0);
- spin_lock_bh(&priv->tx_lock);
- ista->tid_state[tid] = AGGR_PROGRESS;
- spin_unlock_bh(&priv->tx_lock);
- }
- }
- }
+ for (i = 0; i < txs->cnt; i++) {
+ WARN_ON(txs->cnt > HTC_MAX_TX_STATUS);
- rcu_read_unlock();
+ __txs = &txs->txstatus[i];
+
+ skb = ath9k_htc_tx_get_packet(priv, __txs);
+ if (!skb) {
+ /*
+ * Store this event, so that the TX cleanup
+ * routine can check later for the needed packet.
+ */
+ tx_pend = kzalloc(sizeof(struct ath9k_htc_tx_event),
+ GFP_ATOMIC);
+ if (!tx_pend)
+ continue;
+
+ memcpy(&tx_pend->txs, __txs,
+ sizeof(struct __wmi_event_txstatus));
+
+ spin_lock(&priv->wmi->event_lock);
+ list_add_tail(&tx_pend->list,
+ &priv->wmi->pending_tx_events);
+ spin_unlock(&priv->wmi->event_lock);
- send_mac80211:
- /* Send status to mac80211 */
- ieee80211_tx_status(priv->hw, skb);
+ continue;
+ }
+
+ ath9k_htc_tx_process(priv, skb, __txs);
}
/* Wake TX queues if needed */
- spin_lock_bh(&priv->tx_lock);
- if (priv->tx_queues_stop) {
- priv->tx_queues_stop = false;
- spin_unlock_bh(&priv->tx_lock);
- ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
- "Waking up TX queues\n");
- ieee80211_wake_queues(priv->hw);
- return;
- }
- spin_unlock_bh(&priv->tx_lock);
+ ath9k_htc_check_wake_queues(priv);
}
void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb,
enum htc_endpoint_id ep_id, bool txok)
{
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv;
- struct ath_common *common = ath9k_hw_common(priv->ah);
- struct ieee80211_tx_info *tx_info;
+ struct ath9k_htc_tx_ctl *tx_ctl;
+ struct sk_buff_head *epid_queue;
- if (!skb)
+ tx_ctl = HTC_SKB_CB(skb);
+ tx_ctl->txok = txok;
+ tx_ctl->timestamp = jiffies;
+
+ if (!txok) {
+ skb_queue_tail(&priv->tx.tx_failed, skb);
+ tasklet_schedule(&priv->tx_failed_tasklet);
return;
+ }
- if (ep_id == priv->mgmt_ep) {
- skb_pull(skb, sizeof(struct tx_mgmt_hdr));
- } else if ((ep_id == priv->data_bk_ep) ||
- (ep_id == priv->data_be_ep) ||
- (ep_id == priv->data_vi_ep) ||
- (ep_id == priv->data_vo_ep)) {
- skb_pull(skb, sizeof(struct tx_frame_hdr));
- } else {
- ath_err(common, "Unsupported TX EPID: %d\n", ep_id);
+ epid_queue = get_htc_epid_queue(priv, ep_id);
+ if (!epid_queue) {
dev_kfree_skb_any(skb);
return;
}
- tx_info = IEEE80211_SKB_CB(skb);
+ skb_queue_tail(epid_queue, skb);
+}
- if (txok)
- tx_info->flags |= IEEE80211_TX_STAT_ACK;
+static inline bool check_packet(struct ath9k_htc_priv *priv, struct sk_buff *skb)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_tx_ctl *tx_ctl;
- skb_queue_tail(&priv->tx_queue, skb);
- tasklet_schedule(&priv->tx_tasklet);
+ tx_ctl = HTC_SKB_CB(skb);
+
+ if (time_after(jiffies,
+ tx_ctl->timestamp +
+ msecs_to_jiffies(ATH9K_HTC_TX_TIMEOUT_INTERVAL))) {
+ ath_dbg(common, ATH_DBG_XMIT,
+ "Dropping a packet due to TX timeout\n");
+ return true;
+ }
+
+ return false;
+}
+
+static void ath9k_htc_tx_cleanup_queue(struct ath9k_htc_priv *priv,
+ struct sk_buff_head *epid_queue)
+{
+ bool process = false;
+ unsigned long flags;
+ struct sk_buff *skb, *tmp;
+ struct sk_buff_head queue;
+
+ skb_queue_head_init(&queue);
+
+ spin_lock_irqsave(&epid_queue->lock, flags);
+ skb_queue_walk_safe(epid_queue, skb, tmp) {
+ if (check_packet(priv, skb)) {
+ __skb_unlink(skb, epid_queue);
+ __skb_queue_tail(&queue, skb);
+ process = true;
+ }
+ }
+ spin_unlock_irqrestore(&epid_queue->lock, flags);
+
+ if (process) {
+ skb_queue_walk_safe(&queue, skb, tmp) {
+ __skb_unlink(skb, &queue);
+ ath9k_htc_tx_process(priv, skb, NULL);
+ }
+ }
+}
+
+void ath9k_htc_tx_cleanup_timer(unsigned long data)
+{
+ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) data;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_tx_event *event, *tmp;
+ struct sk_buff *skb;
+
+ spin_lock(&priv->wmi->event_lock);
+ list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) {
+
+ skb = ath9k_htc_tx_get_packet(priv, &event->txs);
+ if (skb) {
+ ath_dbg(common, ATH_DBG_XMIT,
+ "Found packet for cookie: %d, epid: %d\n",
+ event->txs.cookie,
+ MS(event->txs.ts_rate, ATH9K_HTC_TXSTAT_EPID));
+
+ ath9k_htc_tx_process(priv, skb, &event->txs);
+ list_del(&event->list);
+ kfree(event);
+ continue;
+ }
+
+ if (++event->count >= ATH9K_HTC_TX_TIMEOUT_COUNT) {
+ list_del(&event->list);
+ kfree(event);
+ }
+ }
+ spin_unlock(&priv->wmi->event_lock);
+
+ /*
+ * Check if status-pending packets have to be cleaned up.
+ */
+ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.mgmt_ep_queue);
+ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.cab_ep_queue);
+ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_be_queue);
+ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_bk_queue);
+ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vi_queue);
+ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vo_queue);
+
+ /* Wake TX queues if needed */
+ ath9k_htc_check_wake_queues(priv);
+
+ mod_timer(&priv->tx.cleanup_timer,
+ jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
}
int ath9k_tx_init(struct ath9k_htc_priv *priv)
{
- skb_queue_head_init(&priv->tx_queue);
+ skb_queue_head_init(&priv->tx.mgmt_ep_queue);
+ skb_queue_head_init(&priv->tx.cab_ep_queue);
+ skb_queue_head_init(&priv->tx.data_be_queue);
+ skb_queue_head_init(&priv->tx.data_bk_queue);
+ skb_queue_head_init(&priv->tx.data_vi_queue);
+ skb_queue_head_init(&priv->tx.data_vo_queue);
+ skb_queue_head_init(&priv->tx.tx_failed);
return 0;
}
@@ -507,8 +970,9 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
int last_rssi = ATH_RSSI_DUMMY_MARKER;
__le16 fc;
- if (skb->len <= HTC_RX_FRAME_HEADER_SIZE) {
- ath_err(common, "Corrupted RX frame, dropping\n");
+ if (skb->len < HTC_RX_FRAME_HEADER_SIZE) {
+ ath_err(common, "Corrupted RX frame, dropping (len: %d)\n",
+ skb->len);
goto rx_next;
}
@@ -522,6 +986,8 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
goto rx_next;
}
+ ath9k_htc_err_stat_rx(priv, rxstatus);
+
/* Get the RX status information */
memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE);
skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE);
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index 62e139a30a74..cee970fdf652 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -17,8 +17,8 @@
#include "htc.h"
static int htc_issue_send(struct htc_target *target, struct sk_buff* skb,
- u16 len, u8 flags, u8 epid,
- struct ath9k_htc_tx_ctl *tx_ctl)
+ u16 len, u8 flags, u8 epid)
+
{
struct htc_frame_hdr *hdr;
struct htc_endpoint *endpoint = &target->endpoint[epid];
@@ -30,8 +30,8 @@ static int htc_issue_send(struct htc_target *target, struct sk_buff* skb,
hdr->flags = flags;
hdr->payload_len = cpu_to_be16(len);
- status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb,
- tx_ctl);
+ status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb);
+
return status;
}
@@ -162,7 +162,7 @@ static int htc_config_pipe_credits(struct htc_target *target)
target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS;
- ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL);
+ ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
if (ret)
goto err;
@@ -197,7 +197,7 @@ static int htc_setup_complete(struct htc_target *target)
target->htc_flags |= HTC_OP_START_WAIT;
- ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL);
+ ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
if (ret)
goto err;
@@ -268,7 +268,7 @@ int htc_connect_service(struct htc_target *target,
conn_msg->dl_pipeid = endpoint->dl_pipeid;
conn_msg->ul_pipeid = endpoint->ul_pipeid;
- ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL);
+ ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
if (ret)
goto err;
@@ -286,35 +286,33 @@ err:
return ret;
}
-int htc_send(struct htc_target *target, struct sk_buff *skb,
- enum htc_endpoint_id epid, struct ath9k_htc_tx_ctl *tx_ctl)
+int htc_send(struct htc_target *target, struct sk_buff *skb)
{
- return htc_issue_send(target, skb, skb->len, 0, epid, tx_ctl);
+ struct ath9k_htc_tx_ctl *tx_ctl;
+
+ tx_ctl = HTC_SKB_CB(skb);
+ return htc_issue_send(target, skb, skb->len, 0, tx_ctl->epid);
}
-void htc_stop(struct htc_target *target)
+int htc_send_epid(struct htc_target *target, struct sk_buff *skb,
+ enum htc_endpoint_id epid)
{
- enum htc_endpoint_id epid;
- struct htc_endpoint *endpoint;
+ return htc_issue_send(target, skb, skb->len, 0, epid);
+}
- for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) {
- endpoint = &target->endpoint[epid];
- if (endpoint->service_id != 0)
- target->hif->stop(target->hif_dev, endpoint->ul_pipeid);
- }
+void htc_stop(struct htc_target *target)
+{
+ target->hif->stop(target->hif_dev);
}
void htc_start(struct htc_target *target)
{
- enum htc_endpoint_id epid;
- struct htc_endpoint *endpoint;
+ target->hif->start(target->hif_dev);
+}
- for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) {
- endpoint = &target->endpoint[epid];
- if (endpoint->service_id != 0)
- target->hif->start(target->hif_dev,
- endpoint->ul_pipeid);
- }
+void htc_sta_drain(struct htc_target *target, u8 idx)
+{
+ target->hif->sta_drain(target->hif_dev, idx);
}
void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h
index ecd018798c47..cb9174ade53e 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.h
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.h
@@ -33,10 +33,10 @@ struct ath9k_htc_hif {
u8 control_dl_pipe;
u8 control_ul_pipe;
- void (*start) (void *hif_handle, u8 pipe);
- void (*stop) (void *hif_handle, u8 pipe);
- int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf,
- struct ath9k_htc_tx_ctl *tx_ctl);
+ void (*start) (void *hif_handle);
+ void (*stop) (void *hif_handle);
+ void (*sta_drain) (void *hif_handle, u8 idx);
+ int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf);
};
enum htc_endpoint_id {
@@ -205,10 +205,12 @@ int htc_init(struct htc_target *target);
int htc_connect_service(struct htc_target *target,
struct htc_service_connreq *service_connreq,
enum htc_endpoint_id *conn_rsp_eid);
-int htc_send(struct htc_target *target, struct sk_buff *skb,
- enum htc_endpoint_id eid, struct ath9k_htc_tx_ctl *tx_ctl);
+int htc_send(struct htc_target *target, struct sk_buff *skb);
+int htc_send_epid(struct htc_target *target, struct sk_buff *skb,
+ enum htc_endpoint_id epid);
void htc_stop(struct htc_target *target);
void htc_start(struct htc_target *target);
+void htc_sta_drain(struct htc_target *target, u8 idx);
void ath9k_htc_rx_msg(struct htc_target *htc_handle,
struct sk_buff *skb, u32 len, u8 pipe_id);
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index 22ee888b0baf..9dd90a85ad63 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -122,6 +122,11 @@ static inline void ath9k_hw_set11n_burstduration(struct ath_hw *ah, void *ds,
ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration);
}
+static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
+{
+ ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val);
+}
+
/* Private hardware call ops */
/* PHY ops */
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index c8a2d0dae796..045abd557840 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -676,42 +676,55 @@ unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah)
}
EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc);
-#define DPLL2_KD_VAL 0x3D
-#define DPLL2_KI_VAL 0x06
-#define DPLL3_PHASE_SHIFT_VAL 0x1
-
+#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)) {
- 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(1000);
+ /* program BB PLL ki and kd value, ki=0x4, kd=0x40 */
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+ AR_CH0_BB_DPLL2_PLL_PWD, 0x1);
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+ AR_CH0_DPLL2_KD, 0x40);
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+ AR_CH0_DPLL2_KI, 0x4);
- REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666);
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
+ AR_CH0_BB_DPLL1_REFDIV, 0x5);
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
+ AR_CH0_BB_DPLL1_NINI, 0x58);
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
+ AR_CH0_BB_DPLL1_NFRAC, 0x0);
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
- AR_CH0_DPLL2_KD, DPLL2_KD_VAL);
+ AR_CH0_BB_DPLL2_OUTDIV, 0x1);
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+ AR_CH0_BB_DPLL2_LOCAL_PLL, 0x1);
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
- AR_CH0_DPLL2_KI, DPLL2_KI_VAL);
+ AR_CH0_BB_DPLL2_EN_NEGTRIG, 0x1);
+ /* program BB PLL phase_shift to 0x6 */
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);
+ AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x6);
+
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+ AR_CH0_BB_DPLL2_PLL_PWD, 0x0);
udelay(1000);
+
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3,
+ AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);
}
pll = ath9k_hw_compute_pll_control(ah, chan);
REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
+ if (AR_SREV_9485(ah))
+ udelay(1000);
+
/* Switch the core clock for ar9271 to 117Mhz */
if (AR_SREV_9271(ah)) {
udelay(500);
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index a778b66f4438..1018d6cbd530 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -626,6 +626,7 @@ struct ath_hw_ops {
void (*clr11n_aggr)(struct ath_hw *ah, void *ds);
void (*set11n_burstduration)(struct ath_hw *ah, void *ds,
u32 burstDuration);
+ void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val);
};
struct ath_nf_limits {
@@ -846,6 +847,14 @@ struct ath_hw {
u32 ent_mode;
};
+struct ath_bus_ops {
+ enum ath_bus_type ath_bus_type;
+ void (*read_cachesize)(struct ath_common *common, int *csz);
+ bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
+ void (*bt_coex_prep)(struct ath_common *common);
+ void (*extn_synch_en)(struct ath_common *common);
+};
+
static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
{
return &ah->common;
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index c2a59386fb9c..b60c130917f7 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -239,7 +239,6 @@ struct ath_desc {
void *ds_vdata;
} __packed __aligned(4);
-#define ATH9K_TXDESC_CLRDMASK 0x0001
#define ATH9K_TXDESC_NOACK 0x0002
#define ATH9K_TXDESC_RTSENA 0x0004
#define ATH9K_TXDESC_CTSENA 0x0008
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 4c5c9997dac6..a8d9009a76d5 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1373,6 +1373,9 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
if ((iter_data.naps + iter_data.nadhocs) > 0) {
sc->sc_flags |= SC_OP_ANI_RUN;
ath_start_ani(common);
+ } else {
+ sc->sc_flags &= ~SC_OP_ANI_RUN;
+ del_timer_sync(&common->ani.timer);
}
}
@@ -1733,23 +1736,63 @@ static int ath9k_sta_add(struct ieee80211_hw *hw,
struct ieee80211_sta *sta)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_node *an = (struct ath_node *) sta->drv_priv;
+ struct ieee80211_key_conf ps_key = { };
ath_node_attach(sc, sta);
+ an->ps_key = ath_key_config(common, vif, sta, &ps_key);
return 0;
}
+static void ath9k_del_ps_key(struct ath_softc *sc,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_node *an = (struct ath_node *) sta->drv_priv;
+ struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key };
+
+ if (!an->ps_key)
+ return;
+
+ ath_key_delete(common, &ps_key);
+}
+
static int ath9k_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct ath_softc *sc = hw->priv;
+ ath9k_del_ps_key(sc, vif, sta);
ath_node_detach(sc, sta);
return 0;
}
+static void ath9k_sta_notify(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum sta_notify_cmd cmd,
+ struct ieee80211_sta *sta)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_node *an = (struct ath_node *) sta->drv_priv;
+
+ switch (cmd) {
+ case STA_NOTIFY_SLEEP:
+ an->sleeping = true;
+ if (ath_tx_aggr_sleep(sc, an))
+ ieee80211_sta_set_tim(sta);
+ break;
+ case STA_NOTIFY_AWAKE:
+ an->sleeping = false;
+ ath_tx_aggr_wakeup(sc, an);
+ break;
+ }
+}
+
static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
@@ -1826,6 +1869,9 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
switch (cmd) {
case SET_KEY:
+ if (sta)
+ ath9k_del_ps_key(sc, vif, sta);
+
ret = ath_key_config(common, vif, sta, key);
if (ret >= 0) {
key->hw_key_idx = ret;
@@ -2209,6 +2255,21 @@ out:
ath9k_ps_restore(sc);
}
+static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
+{
+ struct ath_softc *sc = hw->priv;
+ int i;
+
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+ if (!ATH_TXQ_SETUP(sc, i))
+ continue;
+
+ if (ath9k_has_pending_frames(sc, &sc->tx.txq[i]))
+ return true;
+ }
+ return false;
+}
+
struct ieee80211_ops ath9k_ops = {
.tx = ath9k_tx,
.start = ath9k_start,
@@ -2220,6 +2281,7 @@ struct ieee80211_ops ath9k_ops = {
.configure_filter = ath9k_configure_filter,
.sta_add = ath9k_sta_add,
.sta_remove = ath9k_sta_remove,
+ .sta_notify = ath9k_sta_notify,
.conf_tx = ath9k_conf_tx,
.bss_info_changed = ath9k_bss_info_changed,
.set_key = ath9k_set_key,
@@ -2231,4 +2293,5 @@ struct ieee80211_ops ath9k_ops = {
.rfkill_poll = ath9k_rfkill_poll_state,
.set_coverage_class = ath9k_set_coverage_class,
.flush = ath9k_flush,
+ .tx_frames_pending = ath9k_tx_frames_pending,
};
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h
index f50e2c29f71e..8e5fe9d7f174 100644
--- a/drivers/net/wireless/ath/ath9k/phy.h
+++ b/drivers/net/wireless/ath/ath9k/phy.h
@@ -19,7 +19,6 @@
#define CHANSEL_DIV 15
#define CHANSEL_2G(_freq) (((_freq) * 0x10000) / CHANSEL_DIV)
-#define CHANSEL_2G_9485(_freq) ((((_freq) * 0x10000) - 215) / CHANSEL_DIV)
#define CHANSEL_5G(_freq) (((_freq) * 0x8000) / CHANSEL_DIV)
#define AR_PHY_BASE 0x9800
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 4c0d36a6980f..18094094b298 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -1092,8 +1092,7 @@ static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
if (!(rate->flags & IEEE80211_TX_RC_MCS))
return rate->idx;
- while (rate->idx > mcs_rix_off[i] &&
- i < ARRAY_SIZE(mcs_rix_off)) {
+ while (i < ARRAY_SIZE(mcs_rix_off) && rate->idx > mcs_rix_off[i]) {
rix++; i++;
}
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index cfaf0a48b939..642504f9638c 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -75,7 +75,6 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
*sc->rx.rxlink = bf->bf_daddr;
sc->rx.rxlink = &ds->ds_link;
- ath9k_hw_rxena(ah);
}
static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
@@ -426,9 +425,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
else
rfilt |= ATH9K_RX_FILTER_BEACON;
- if ((AR_SREV_9280_20_OR_LATER(sc->sc_ah) ||
- AR_SREV_9285_12_OR_LATER(sc->sc_ah)) &&
- (sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
+ if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
(sc->rx.rxfilter & FIF_PSPOLL))
rfilt |= ATH9K_RX_FILTER_PSPOLL;
@@ -1767,6 +1764,7 @@ requeue:
} else {
list_move_tail(&bf->list, &sc->rx.rxbuf);
ath_rx_buf_link(sc, bf);
+ ath9k_hw_rxena(ah);
}
} while (1);
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 693d543937b5..6acbf0e2240b 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -858,9 +858,7 @@
#define AR_SREV_9300(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300))
#define AR_SREV_9300_20_OR_LATER(_ah) \
- (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9300) || \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300) && \
- ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9300_20)))
+ ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9300)
#define AR_SREV_9485(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485))
@@ -1088,14 +1086,35 @@ 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_DPLL1 0x16180
+#define AR_CH0_BB_DPLL1_REFDIV 0xF8000000
+#define AR_CH0_BB_DPLL1_REFDIV_S 27
+#define AR_CH0_BB_DPLL1_NINI 0x07FC0000
+#define AR_CH0_BB_DPLL1_NINI_S 18
+#define AR_CH0_BB_DPLL1_NFRAC 0x0003FFFF
+#define AR_CH0_BB_DPLL1_NFRAC_S 0
+
+#define AR_CH0_BB_DPLL2 0x16184
+#define AR_CH0_BB_DPLL2_LOCAL_PLL 0x40000000
+#define AR_CH0_BB_DPLL2_LOCAL_PLL_S 30
+#define AR_CH0_DPLL2_KI 0x3C000000
+#define AR_CH0_DPLL2_KI_S 26
+#define AR_CH0_DPLL2_KD 0x03F80000
+#define AR_CH0_DPLL2_KD_S 19
+#define AR_CH0_BB_DPLL2_EN_NEGTRIG 0x00040000
+#define AR_CH0_BB_DPLL2_EN_NEGTRIG_S 18
+#define AR_CH0_BB_DPLL2_PLL_PWD 0x00010000
+#define AR_CH0_BB_DPLL2_PLL_PWD_S 16
+#define AR_CH0_BB_DPLL2_OUTDIV 0x0000E000
+#define AR_CH0_BB_DPLL2_OUTDIV_S 13
+
#define AR_CH0_BB_DPLL3 0x16188
+#define AR_CH0_BB_DPLL3_PHASE_SHIFT 0x3F800000
+#define AR_CH0_BB_DPLL3_PHASE_SHIFT_S 23
+
#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
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index d3d24904f62f..8f095ad0a3db 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -23,20 +23,18 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
return "WMI_ECHO_CMDID";
case WMI_ACCESS_MEMORY_CMDID:
return "WMI_ACCESS_MEMORY_CMDID";
+ case WMI_GET_FW_VERSION:
+ return "WMI_GET_FW_VERSION";
case WMI_DISABLE_INTR_CMDID:
return "WMI_DISABLE_INTR_CMDID";
case WMI_ENABLE_INTR_CMDID:
return "WMI_ENABLE_INTR_CMDID";
- case WMI_RX_LINK_CMDID:
- return "WMI_RX_LINK_CMDID";
case WMI_ATH_INIT_CMDID:
return "WMI_ATH_INIT_CMDID";
case WMI_ABORT_TXQ_CMDID:
return "WMI_ABORT_TXQ_CMDID";
case WMI_STOP_TX_DMA_CMDID:
return "WMI_STOP_TX_DMA_CMDID";
- case WMI_STOP_DMA_RECV_CMDID:
- return "WMI_STOP_DMA_RECV_CMDID";
case WMI_ABORT_TX_DMA_CMDID:
return "WMI_ABORT_TX_DMA_CMDID";
case WMI_DRAIN_TXQ_CMDID:
@@ -51,8 +49,6 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
return "WMI_FLUSH_RECV_CMDID";
case WMI_SET_MODE_CMDID:
return "WMI_SET_MODE_CMDID";
- case WMI_RESET_CMDID:
- return "WMI_RESET_CMDID";
case WMI_NODE_CREATE_CMDID:
return "WMI_NODE_CREATE_CMDID";
case WMI_NODE_REMOVE_CMDID:
@@ -61,8 +57,6 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
return "WMI_VAP_REMOVE_CMDID";
case WMI_VAP_CREATE_CMDID:
return "WMI_VAP_CREATE_CMDID";
- case WMI_BEACON_UPDATE_CMDID:
- return "WMI_BEACON_UPDATE_CMDID";
case WMI_REG_READ_CMDID:
return "WMI_REG_READ_CMDID";
case WMI_REG_WRITE_CMDID:
@@ -71,20 +65,20 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
return "WMI_RC_STATE_CHANGE_CMDID";
case WMI_RC_RATE_UPDATE_CMDID:
return "WMI_RC_RATE_UPDATE_CMDID";
- case WMI_DEBUG_INFO_CMDID:
- return "WMI_DEBUG_INFO_CMDID";
- case WMI_HOST_ATTACH:
- return "WMI_HOST_ATTACH";
case WMI_TARGET_IC_UPDATE_CMDID:
return "WMI_TARGET_IC_UPDATE_CMDID";
- case WMI_TGT_STATS_CMDID:
- return "WMI_TGT_STATS_CMDID";
case WMI_TX_AGGR_ENABLE_CMDID:
return "WMI_TX_AGGR_ENABLE_CMDID";
case WMI_TGT_DETACH_CMDID:
return "WMI_TGT_DETACH_CMDID";
- case WMI_TGT_TXQ_ENABLE_CMDID:
- return "WMI_TGT_TXQ_ENABLE_CMDID";
+ case WMI_NODE_UPDATE_CMDID:
+ return "WMI_NODE_UPDATE_CMDID";
+ case WMI_INT_STATS_CMDID:
+ return "WMI_INT_STATS_CMDID";
+ case WMI_TX_STATS_CMDID:
+ return "WMI_TX_STATS_CMDID";
+ case WMI_RX_STATS_CMDID:
+ return "WMI_RX_STATS_CMDID";
case WMI_AGGR_LIMIT_CMD:
return "WMI_AGGR_LIMIT_CMD";
}
@@ -102,9 +96,15 @@ struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv)
wmi->drv_priv = priv;
wmi->stopped = false;
+ skb_queue_head_init(&wmi->wmi_event_queue);
+ spin_lock_init(&wmi->wmi_lock);
+ spin_lock_init(&wmi->event_lock);
mutex_init(&wmi->op_mutex);
mutex_init(&wmi->multi_write_mutex);
init_completion(&wmi->cmd_wait);
+ INIT_LIST_HEAD(&wmi->pending_tx_events);
+ tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet,
+ (unsigned long)wmi);
return wmi;
}
@@ -120,11 +120,65 @@ void ath9k_deinit_wmi(struct ath9k_htc_priv *priv)
kfree(priv->wmi);
}
-void ath9k_swba_tasklet(unsigned long data)
+void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv)
{
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
+ unsigned long flags;
- ath9k_htc_swba(priv, priv->wmi->beacon_pending);
+ tasklet_kill(&priv->wmi->wmi_event_tasklet);
+ spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
+ __skb_queue_purge(&priv->wmi->wmi_event_queue);
+ spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);
+}
+
+void ath9k_wmi_event_tasklet(unsigned long data)
+{
+ struct wmi *wmi = (struct wmi *)data;
+ struct ath9k_htc_priv *priv = wmi->drv_priv;
+ struct wmi_cmd_hdr *hdr;
+ void *wmi_event;
+ struct wmi_event_swba *swba;
+ struct sk_buff *skb = NULL;
+ unsigned long flags;
+ u16 cmd_id;
+
+ do {
+ spin_lock_irqsave(&wmi->wmi_lock, flags);
+ skb = __skb_dequeue(&wmi->wmi_event_queue);
+ if (!skb) {
+ spin_unlock_irqrestore(&wmi->wmi_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&wmi->wmi_lock, flags);
+
+ hdr = (struct wmi_cmd_hdr *) skb->data;
+ cmd_id = be16_to_cpu(hdr->command_id);
+ wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
+
+ switch (cmd_id) {
+ case WMI_SWBA_EVENTID:
+ swba = (struct wmi_event_swba *) wmi_event;
+ ath9k_htc_swba(priv, swba);
+ break;
+ case WMI_FATAL_EVENTID:
+ ieee80211_queue_work(wmi->drv_priv->hw,
+ &wmi->drv_priv->fatal_work);
+ break;
+ case WMI_TXSTATUS_EVENTID:
+ spin_lock_bh(&priv->tx.tx_lock);
+ if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) {
+ spin_unlock_bh(&priv->tx.tx_lock);
+ break;
+ }
+ spin_unlock_bh(&priv->tx.tx_lock);
+
+ ath9k_htc_txstatus(priv, wmi_event);
+ break;
+ default:
+ break;
+ }
+
+ kfree_skb(skb);
+ } while (1);
}
void ath9k_fatal_work(struct work_struct *work)
@@ -153,10 +207,6 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
struct wmi *wmi = (struct wmi *) priv;
struct wmi_cmd_hdr *hdr;
u16 cmd_id;
- void *wmi_event;
-#ifdef CONFIG_ATH9K_HTC_DEBUGFS
- __be32 txrate;
-#endif
if (unlikely(wmi->stopped))
goto free_skb;
@@ -165,26 +215,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
cmd_id = be16_to_cpu(hdr->command_id);
if (cmd_id & 0x1000) {
- wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
- switch (cmd_id) {
- case WMI_SWBA_EVENTID:
- wmi->beacon_pending = *(u8 *)wmi_event;
- tasklet_schedule(&wmi->drv_priv->swba_tasklet);
- break;
- case WMI_FATAL_EVENTID:
- ieee80211_queue_work(wmi->drv_priv->hw,
- &wmi->drv_priv->fatal_work);
- break;
- case WMI_TXRATE_EVENTID:
-#ifdef CONFIG_ATH9K_HTC_DEBUGFS
- txrate = ((struct wmi_event_txrate *)wmi_event)->txrate;
- wmi->drv_priv->debug.txrate = be32_to_cpu(txrate);
-#endif
- break;
- default:
- break;
- }
- kfree_skb(skb);
+ spin_lock(&wmi->wmi_lock);
+ __skb_queue_tail(&wmi->wmi_event_queue, skb);
+ spin_unlock(&wmi->wmi_lock);
+ tasklet_schedule(&wmi->wmi_event_tasklet);
return;
}
@@ -243,7 +277,7 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi,
hdr->command_id = cpu_to_be16(cmd);
hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id);
- return htc_send(wmi->htc, skb, wmi->ctrl_epid, NULL);
+ return htc_send_epid(wmi->htc, skb, wmi->ctrl_epid);
}
int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index 42084277522d..02ecb9f06db0 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -17,7 +17,6 @@
#ifndef WMI_H
#define WMI_H
-
struct wmi_event_txrate {
__be32 txrate;
struct {
@@ -31,18 +30,65 @@ struct wmi_cmd_hdr {
__be16 seq_no;
} __packed;
+struct wmi_fw_version {
+ __be16 major;
+ __be16 minor;
+
+} __packed;
+
+struct wmi_event_swba {
+ __be64 tsf;
+ u8 beacon_pending;
+};
+
+/*
+ * 64 - HTC header - WMI header - 1 / txstatus
+ * And some other hdr. space is also accounted for.
+ * 12 seems to be the magic number.
+ */
+#define HTC_MAX_TX_STATUS 12
+
+#define ATH9K_HTC_TXSTAT_ACK BIT(0)
+#define ATH9K_HTC_TXSTAT_FILT BIT(1)
+#define ATH9K_HTC_TXSTAT_RTC_CTS BIT(2)
+#define ATH9K_HTC_TXSTAT_MCS BIT(3)
+#define ATH9K_HTC_TXSTAT_CW40 BIT(4)
+#define ATH9K_HTC_TXSTAT_SGI BIT(5)
+
+/*
+ * Legacy rates are indicated as indices.
+ * HT rates are indicated as dot11 numbers.
+ * This allows us to resrict the rate field
+ * to 4 bits.
+ */
+#define ATH9K_HTC_TXSTAT_RATE 0x0f
+#define ATH9K_HTC_TXSTAT_RATE_S 0
+
+#define ATH9K_HTC_TXSTAT_EPID 0xf0
+#define ATH9K_HTC_TXSTAT_EPID_S 4
+
+struct __wmi_event_txstatus {
+ u8 cookie;
+ u8 ts_rate; /* Also holds EP ID */
+ u8 ts_flags;
+};
+
+struct wmi_event_txstatus {
+ u8 cnt;
+ struct __wmi_event_txstatus txstatus[HTC_MAX_TX_STATUS];
+} __packed;
+
enum wmi_cmd_id {
WMI_ECHO_CMDID = 0x0001,
WMI_ACCESS_MEMORY_CMDID,
/* Commands to Target */
+ WMI_GET_FW_VERSION,
WMI_DISABLE_INTR_CMDID,
WMI_ENABLE_INTR_CMDID,
- WMI_RX_LINK_CMDID,
WMI_ATH_INIT_CMDID,
WMI_ABORT_TXQ_CMDID,
WMI_STOP_TX_DMA_CMDID,
- WMI_STOP_DMA_RECV_CMDID,
WMI_ABORT_TX_DMA_CMDID,
WMI_DRAIN_TXQ_CMDID,
WMI_DRAIN_TXQ_ALL_CMDID,
@@ -50,23 +96,21 @@ enum wmi_cmd_id {
WMI_STOP_RECV_CMDID,
WMI_FLUSH_RECV_CMDID,
WMI_SET_MODE_CMDID,
- WMI_RESET_CMDID,
WMI_NODE_CREATE_CMDID,
WMI_NODE_REMOVE_CMDID,
WMI_VAP_REMOVE_CMDID,
WMI_VAP_CREATE_CMDID,
- WMI_BEACON_UPDATE_CMDID,
WMI_REG_READ_CMDID,
WMI_REG_WRITE_CMDID,
WMI_RC_STATE_CHANGE_CMDID,
WMI_RC_RATE_UPDATE_CMDID,
- WMI_DEBUG_INFO_CMDID,
- WMI_HOST_ATTACH,
WMI_TARGET_IC_UPDATE_CMDID,
- WMI_TGT_STATS_CMDID,
WMI_TX_AGGR_ENABLE_CMDID,
WMI_TGT_DETACH_CMDID,
- WMI_TGT_TXQ_ENABLE_CMDID,
+ WMI_NODE_UPDATE_CMDID,
+ WMI_INT_STATS_CMDID,
+ WMI_TX_STATS_CMDID,
+ WMI_RX_STATS_CMDID,
WMI_AGGR_LIMIT_CMD = 0x0026,
};
@@ -76,9 +120,8 @@ enum wmi_event_id {
WMI_FATAL_EVENTID,
WMI_TXTO_EVENTID,
WMI_BMISS_EVENTID,
- WMI_WLAN_TXCOMP_EVENTID,
WMI_DELBA_EVENTID,
- WMI_TXRATE_EVENTID,
+ WMI_TXSTATUS_EVENTID,
};
#define MAX_CMD_NUMBER 62
@@ -88,6 +131,12 @@ struct register_write {
__be32 val;
};
+struct ath9k_htc_tx_event {
+ int count;
+ struct __wmi_event_txstatus txs;
+ struct list_head list;
+};
+
struct wmi {
struct ath9k_htc_priv *drv_priv;
struct htc_target *htc;
@@ -95,12 +144,16 @@ struct wmi {
struct mutex op_mutex;
struct completion cmd_wait;
enum wmi_cmd_id last_cmd_id;
+ struct sk_buff_head wmi_event_queue;
+ struct tasklet_struct wmi_event_tasklet;
u16 tx_seq_id;
u8 *cmd_rsp_buf;
u32 cmd_rsp_len;
bool stopped;
- u8 beacon_pending;
+ struct list_head pending_tx_events;
+ spinlock_t event_lock;
+
spinlock_t wmi_lock;
atomic_t mwrite_cnt;
@@ -117,8 +170,9 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
u8 *cmd_buf, u32 cmd_len,
u8 *rsp_buf, u32 rsp_len,
u32 timeout);
-void ath9k_swba_tasklet(unsigned long data);
+void ath9k_wmi_event_tasklet(unsigned long data);
void ath9k_fatal_work(struct work_struct *work);
+void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv);
#define WMI_CMD(_wmi_cmd) \
do { \
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 3cea3f76e373..e9e99f730ca8 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -357,6 +357,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_frame_info *fi;
int nframes;
u8 tidno;
+ bool clear_filter;
skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data;
@@ -441,22 +442,24 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
/* transmit completion */
acked_cnt++;
} else {
- if (!(tid->state & AGGR_CLEANUP) && retry) {
- if (fi->retries < ATH_MAX_SW_RETRIES) {
- ath_tx_set_retry(sc, txq, bf->bf_mpdu);
- txpending = 1;
- } else {
- bf->bf_state.bf_type |= BUF_XRETRY;
- txfail = 1;
- sendbar = 1;
- txfail_cnt++;
- }
- } else {
+ if ((tid->state & AGGR_CLEANUP) || !retry) {
/*
* cleanup in progress, just fail
* the un-acked sub-frames
*/
txfail = 1;
+ } else if (fi->retries < ATH_MAX_SW_RETRIES) {
+ if (!(ts->ts_status & ATH9K_TXERR_FILT) ||
+ !an->sleeping)
+ ath_tx_set_retry(sc, txq, bf->bf_mpdu);
+
+ clear_filter = true;
+ txpending = 1;
+ } else {
+ bf->bf_state.bf_type |= BUF_XRETRY;
+ txfail = 1;
+ sendbar = 1;
+ txfail_cnt++;
}
}
@@ -496,6 +499,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
!txfail, sendbar);
} else {
/* retry the un-acked ones */
+ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false);
if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
if (bf->bf_next == NULL && bf_last->bf_stale) {
struct ath_buf *tbf;
@@ -546,7 +550,12 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
/* prepend un-acked frames to the beginning of the pending frame queue */
if (!list_empty(&bf_pending)) {
+ if (an->sleeping)
+ ieee80211_sta_set_tim(sta);
+
spin_lock_bh(&txq->axq_lock);
+ if (clear_filter)
+ tid->ac->clear_ps_filter = true;
list_splice(&bf_pending, &tid->buf_q);
ath_tx_queue_tid(txq, tid);
spin_unlock_bh(&txq->axq_lock);
@@ -816,6 +825,11 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
bf = list_first_entry(&bf_q, struct ath_buf, list);
bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
+ if (tid->ac->clear_ps_filter) {
+ tid->ac->clear_ps_filter = false;
+ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
+ }
+
/* if only one frame, send as non-aggregate */
if (bf == bf->bf_lastbf) {
fi = get_frame_info(bf->bf_mpdu);
@@ -896,6 +910,67 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
ath_tx_flush_tid(sc, txtid);
}
+bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
+{
+ struct ath_atx_tid *tid;
+ struct ath_atx_ac *ac;
+ struct ath_txq *txq;
+ bool buffered = false;
+ int tidno;
+
+ for (tidno = 0, tid = &an->tid[tidno];
+ tidno < WME_NUM_TID; tidno++, tid++) {
+
+ if (!tid->sched)
+ continue;
+
+ ac = tid->ac;
+ txq = ac->txq;
+
+ spin_lock_bh(&txq->axq_lock);
+
+ if (!list_empty(&tid->buf_q))
+ buffered = true;
+
+ tid->sched = false;
+ list_del(&tid->list);
+
+ if (ac->sched) {
+ ac->sched = false;
+ list_del(&ac->list);
+ }
+
+ spin_unlock_bh(&txq->axq_lock);
+ }
+
+ return buffered;
+}
+
+void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
+{
+ struct ath_atx_tid *tid;
+ struct ath_atx_ac *ac;
+ struct ath_txq *txq;
+ int tidno;
+
+ for (tidno = 0, tid = &an->tid[tidno];
+ tidno < WME_NUM_TID; tidno++, tid++) {
+
+ ac = tid->ac;
+ txq = ac->txq;
+
+ spin_lock_bh(&txq->axq_lock);
+ ac->clear_ps_filter = true;
+
+ if (!list_empty(&tid->buf_q) && !tid->paused) {
+ ath_tx_queue_tid(txq, tid);
+ ath_txq_schedule(sc, txq);
+ }
+
+ spin_unlock_bh(&txq->axq_lock);
+ }
+}
+
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
{
struct ath_atx_tid *txtid;
@@ -1451,7 +1526,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
struct ieee80211_hdr *hdr;
struct ath_frame_info *fi = get_frame_info(skb);
- struct ath_node *an;
+ struct ath_node *an = NULL;
struct ath_atx_tid *tid;
enum ath9k_key_type keytype;
u16 seqno = 0;
@@ -1459,11 +1534,13 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
+ if (sta)
+ an = (struct ath_node *) sta->drv_priv;
+
hdr = (struct ieee80211_hdr *)skb->data;
- if (sta && ieee80211_is_data_qos(hdr->frame_control) &&
+ if (an && ieee80211_is_data_qos(hdr->frame_control) &&
conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) {
- an = (struct ath_node *) sta->drv_priv;
tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
/*
@@ -1479,6 +1556,8 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
memset(fi, 0, sizeof(*fi));
if (hw_key)
fi->keyix = hw_key->hw_key_idx;
+ else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0)
+ fi->keyix = an->ps_key;
else
fi->keyix = ATH9K_TXKEYIX_INVALID;
fi->keytype = keytype;
@@ -1491,7 +1570,6 @@ static int setup_tx_flags(struct sk_buff *skb)
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
int flags = 0;
- flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
flags |= ATH9K_TXDESC_INTREQ;
if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
@@ -1754,6 +1832,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
if (txctl->paprd)
bf->bf_state.bfs_paprd_timestamp = jiffies;
+ if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
+ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
+
ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
}
diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c
index 0d4f39cbdcab..a61ef3d6d89c 100644
--- a/drivers/net/wireless/ath/key.c
+++ b/drivers/net/wireless/ath/key.c
@@ -483,6 +483,9 @@ int ath_key_config(struct ath_common *common,
memset(&hk, 0, sizeof(hk));
switch (key->cipher) {
+ case 0:
+ hk.kv_type = ATH_CIPHER_CLR;
+ break;
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
hk.kv_type = ATH_CIPHER_WEP;
@@ -498,7 +501,8 @@ int ath_key_config(struct ath_common *common,
}
hk.kv_len = key->keylen;
- memcpy(hk.kv_val, key->key, key->keylen);
+ if (key->keylen)
+ memcpy(hk.kv_val, key->key, key->keylen);
if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
switch (vif->type) {
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index 0e1b8793c864..028310f263c8 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -97,8 +97,8 @@ static const struct ieee80211_regdomain ath_world_regdom_66_69 = {
}
};
-/* Can be used by 0x67, 0x6A and 0x68 */
-static const struct ieee80211_regdomain ath_world_regdom_67_68_6A = {
+/* Can be used by 0x67, 0x68, 0x6A and 0x6C */
+static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = {
.n_reg_rules = 4,
.alpha2 = "99",
.reg_rules = {
@@ -151,7 +151,8 @@ ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
case 0x67:
case 0x68:
case 0x6A:
- return &ath_world_regdom_67_68_6A;
+ case 0x6C:
+ return &ath_world_regdom_67_68_6A_6C;
default:
WARN_ON(1);
return ath_default_world_regdomain();
@@ -333,6 +334,7 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy,
case 0x63:
case 0x66:
case 0x67:
+ case 0x6C:
ath_reg_apply_beaconing_flags(wiphy, initiator);
break;
case 0x68:
diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h
index 5c2cfe694152..24b53839fc3a 100644
--- a/drivers/net/wireless/ath/regd_common.h
+++ b/drivers/net/wireless/ath/regd_common.h
@@ -86,6 +86,7 @@ enum EnumRd {
WOR9_WORLD = 0x69,
WORA_WORLD = 0x6A,
WORB_WORLD = 0x6B,
+ WORC_WORLD = 0x6C,
MKK3_MKKB = 0x80,
MKK3_MKKA2 = 0x81,
@@ -282,6 +283,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = {
{WOR9_WORLD, NO_CTL, NO_CTL},
{WORA_WORLD, NO_CTL, NO_CTL},
{WORB_WORLD, NO_CTL, NO_CTL},
+ {WORC_WORLD, NO_CTL, NO_CTL},
};
static struct country_code_to_enum_rd allCountries[] = {