diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ani.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ani.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9002_mac.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9003_mac.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/debug.c | 312 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/debug.h | 47 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_main.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.c | 13 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/init.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/mac.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 24 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/reg.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 234 |
17 files changed, 528 insertions, 133 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index bfb6481f01f9..d969a11e3425 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -643,7 +643,7 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) listenTime = ath_hw_get_listen_time(common); if (listenTime <= 0) { - ah->stats.ast_ani_lneg++; + ah->stats.ast_ani_lneg_or_lzero++; ath9k_ani_restart(ah); return false; } diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index dbab5b9ce494..a547005572e7 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -148,8 +148,7 @@ struct ar5416Stats { u32 ast_ani_ofdmerrs; u32 ast_ani_cckerrs; u32 ast_ani_reset; - u32 ast_ani_lzero; - u32 ast_ani_lneg; + u32 ast_ani_lneg_or_lzero; u32 avgbrssi; struct ath9k_mib_stats ast_mibstats; }; @@ -159,7 +158,5 @@ void ath9k_enable_mib_counters(struct ath_hw *ah); void ath9k_hw_disable_mib_counters(struct ath_hw *ah); void ath9k_hw_ani_setup(struct ath_hw *ah); void ath9k_hw_ani_init(struct ath_hw *ah); -int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, - struct ath9k_channel *chan); #endif /* ANI_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 45b262fe2c25..33deb0d574b0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -273,7 +273,7 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds, u32 pktLen, enum ath9k_pkt_type type, - u32 txPower, u32 keyIx, + u32 txPower, u8 keyIx, enum ath9k_key_type keyType, u32 flags) { struct ar5416_desc *ads = AR5416DESC(ds); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index cb8bcc4e6091..5f3ac251b486 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3318,7 +3318,7 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, word = kzalloc(2048, GFP_KERNEL); if (!word) - return -1; + return -ENOMEM; memcpy(mptr, &ar9300_default, mdata_size); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 8ace36e77399..d08ab930e430 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -312,7 +312,7 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds, u32 pktlen, enum ath9k_pkt_type type, u32 txpower, - u32 keyIx, enum ath9k_key_type keyType, u32 flags) + u8 keyIx, enum ath9k_key_type keyType, u32 flags) { struct ar9003_txc *ads = (struct ar9003_txc *) ds; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 3a893e19d6c3..5d9a9aabe476 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -206,16 +206,17 @@ struct ath_atx_ac { }; struct ath_frame_info { + struct ath_buf *bf; int framelen; - u32 keyix; enum ath9k_key_type keytype; + u8 keyix; u8 retries; - u16 seqno; }; struct ath_buf_state { u8 bf_type; u8 bfs_paprd; + u16 seqno; unsigned long bfs_paprd_timestamp; }; @@ -235,7 +236,7 @@ struct ath_buf { struct ath_atx_tid { struct list_head list; - struct list_head buf_q; + struct sk_buff_head buf_q; struct ath_node *an; struct ath_atx_ac *ac; unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)]; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index da45f325be7d..727e8de22fda 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -711,7 +711,7 @@ static ssize_t read_file_stations(struct file *file, char __user *user_buf, " tid: %p %s %s %i %p %p\n", tid, tid->sched ? "sched" : "idle", tid->paused ? "paused" : "running", - list_empty(&tid->buf_q), + skb_queue_empty(&tid->buf_q), tid->an, tid->ac); if (len >= size) goto done; @@ -828,6 +828,8 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, struct ath_txq *txq) { +#define TX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].ts\ + [sc->debug.tsidx].c) int qnum = txq->axq_qnum; TX_STAT_INC(qnum, tx_pkts_all); @@ -857,6 +859,26 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, TX_STAT_INC(qnum, data_underrun); if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN) TX_STAT_INC(qnum, delim_underrun); + + spin_lock(&sc->debug.samp_lock); + TX_SAMP_DBG(jiffies) = jiffies; + TX_SAMP_DBG(rssi_ctl0) = ts->ts_rssi_ctl0; + TX_SAMP_DBG(rssi_ctl1) = ts->ts_rssi_ctl1; + TX_SAMP_DBG(rssi_ctl2) = ts->ts_rssi_ctl2; + TX_SAMP_DBG(rssi_ext0) = ts->ts_rssi_ext0; + TX_SAMP_DBG(rssi_ext1) = ts->ts_rssi_ext1; + TX_SAMP_DBG(rssi_ext2) = ts->ts_rssi_ext2; + TX_SAMP_DBG(rateindex) = ts->ts_rateindex; + TX_SAMP_DBG(isok) = !!(ts->ts_status & ATH9K_TXERR_MASK); + TX_SAMP_DBG(rts_fail_cnt) = ts->ts_shortretry; + TX_SAMP_DBG(data_fail_cnt) = ts->ts_longretry; + TX_SAMP_DBG(rssi) = ts->ts_rssi; + TX_SAMP_DBG(tid) = ts->tid; + TX_SAMP_DBG(qid) = ts->qid; + sc->debug.tsidx = (sc->debug.tsidx + 1) % ATH_DBG_MAX_SAMPLES; + spin_unlock(&sc->debug.samp_lock); + +#undef TX_SAMP_DBG } static const struct file_operations fops_xmit = { @@ -995,6 +1017,8 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) { #define RX_STAT_INC(c) sc->debug.stats.rxstats.c++ #define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++ +#define RX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].rs\ + [sc->debug.rsidx].c) u32 phyerr; @@ -1030,8 +1054,25 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) sc->debug.stats.rxstats.rs_antenna = rs->rs_antenna; + spin_lock(&sc->debug.samp_lock); + RX_SAMP_DBG(jiffies) = jiffies; + RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl0; + RX_SAMP_DBG(rssi_ctl1) = rs->rs_rssi_ctl1; + RX_SAMP_DBG(rssi_ctl2) = rs->rs_rssi_ctl2; + RX_SAMP_DBG(rssi_ext0) = rs->rs_rssi_ext0; + RX_SAMP_DBG(rssi_ext1) = rs->rs_rssi_ext1; + RX_SAMP_DBG(rssi_ext2) = rs->rs_rssi_ext2; + RX_SAMP_DBG(antenna) = rs->rs_antenna; + RX_SAMP_DBG(rssi) = rs->rs_rssi; + RX_SAMP_DBG(rate) = rs->rs_rate; + RX_SAMP_DBG(is_mybeacon) = rs->is_mybeacon; + + sc->debug.rsidx = (sc->debug.rsidx + 1) % ATH_DBG_MAX_SAMPLES; + spin_unlock(&sc->debug.samp_lock); + #undef RX_STAT_INC #undef RX_PHY_ERR_INC +#undef RX_SAMP_DBG } static const struct file_operations fops_recv = { @@ -1272,6 +1313,269 @@ static const struct file_operations fops_modal_eeprom = { .llseek = default_llseek, }; +void ath9k_debug_samp_bb_mac(struct ath_softc *sc) +{ +#define ATH_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].c) + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + unsigned long flags; + int i; + + ath9k_ps_wakeup(sc); + + spin_lock_irqsave(&common->cc_lock, flags); + ath_hw_cycle_counters_update(common); + spin_unlock_irqrestore(&common->cc_lock, flags); + + spin_lock_bh(&sc->debug.samp_lock); + + ATH_SAMP_DBG(cc.cycles) = common->cc_ani.cycles; + ATH_SAMP_DBG(cc.rx_busy) = common->cc_ani.rx_busy; + ATH_SAMP_DBG(cc.rx_frame) = common->cc_ani.rx_frame; + ATH_SAMP_DBG(cc.tx_frame) = common->cc_ani.tx_frame; + ATH_SAMP_DBG(noise) = ah->noise; + + REG_WRITE_D(ah, AR_MACMISC, + ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | + (AR_MACMISC_MISC_OBS_BUS_1 << + AR_MACMISC_MISC_OBS_BUS_MSB_S))); + + for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) + ATH_SAMP_DBG(dma_dbg_reg_vals[i]) = REG_READ_D(ah, + AR_DMADBG_0 + (i * sizeof(u32))); + + ATH_SAMP_DBG(pcu_obs) = REG_READ_D(ah, AR_OBS_BUS_1); + ATH_SAMP_DBG(pcu_cr) = REG_READ_D(ah, AR_CR); + + memcpy(ATH_SAMP_DBG(nfCalHist), sc->caldata.nfCalHist, + sizeof(ATH_SAMP_DBG(nfCalHist))); + + sc->debug.sampidx = (sc->debug.sampidx + 1) % ATH_DBG_MAX_SAMPLES; + spin_unlock_bh(&sc->debug.samp_lock); + ath9k_ps_restore(sc); + +#undef ATH_SAMP_DBG +} + +static int open_file_bb_mac_samps(struct inode *inode, struct file *file) +{ +#define ATH_SAMP_DBG(c) bb_mac_samp[sampidx].c + struct ath_softc *sc = inode->i_private; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_conf *conf = &common->hw->conf; + struct ath_dbg_bb_mac_samp *bb_mac_samp; + struct ath9k_nfcal_hist *h; + int i, j, qcuOffset = 0, dcuOffset = 0; + u32 *qcuBase, *dcuBase, size = 30000, len = 0; + u32 sampidx = 0; + u8 *buf; + u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; + u8 nread; + + buf = vmalloc(size); + if (!buf) + return -ENOMEM; + bb_mac_samp = vmalloc(sizeof(*bb_mac_samp) * ATH_DBG_MAX_SAMPLES); + if (!bb_mac_samp) { + vfree(buf); + return -ENOMEM; + } + + spin_lock_bh(&sc->debug.samp_lock); + memcpy(bb_mac_samp, sc->debug.bb_mac_samp, + sizeof(*bb_mac_samp) * ATH_DBG_MAX_SAMPLES); + spin_unlock_bh(&sc->debug.samp_lock); + + len += snprintf(buf + len, size - len, + "Raw DMA Debug Dump:\n"); + len += snprintf(buf + len, size - len, "Sample |\t"); + for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) + len += snprintf(buf + len, size - len, " DMA Reg%d |\t", i); + len += snprintf(buf + len, size - len, "\n"); + + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + len += snprintf(buf + len, size - len, "%d\t", sampidx); + + for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) + len += snprintf(buf + len, size - len, " %08x\t", + ATH_SAMP_DBG(dma_dbg_reg_vals[i])); + len += snprintf(buf + len, size - len, "\n"); + } + len += snprintf(buf + len, size - len, "\n"); + + len += snprintf(buf + len, size - len, + "Sample Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + qcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[0]); + dcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[4]); + + for (i = 0; i < ATH9K_NUM_QUEUES; i++, + qcuOffset += 4, dcuOffset += 5) { + if (i == 8) { + qcuOffset = 0; + qcuBase++; + } + + if (i == 6) { + dcuOffset = 0; + dcuBase++; + } + if (!sc->debug.stats.txstats[i].queued) + continue; + + len += snprintf(buf + len, size - len, + "%4d %7d %2x %1x %2x %2x\n", + sampidx, i, + (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, + (*qcuBase & (0x8 << qcuOffset)) >> + (qcuOffset + 3), + ATH_SAMP_DBG(dma_dbg_reg_vals[2]) & + (0x7 << (i * 3)) >> (i * 3), + (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); + } + len += snprintf(buf + len, size - len, "\n"); + } + len += snprintf(buf + len, size - len, + "samp qcu_sh qcu_fh qcu_comp dcu_comp dcu_arb dcu_fp " + "ch_idle_dur ch_idle_dur_val txfifo_val0 txfifo_val1 " + "txfifo_dcu0 txfifo_dcu1 pcu_obs AR_CR\n"); + + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + qcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[0]); + dcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[4]); + + len += snprintf(buf + len, size - len, "%4d %5x %5x ", sampidx, + (ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x003c0000) >> 18, + (ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x03c00000) >> 22); + len += snprintf(buf + len, size - len, "%7x %8x ", + (ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x1c000000) >> 26, + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x3)); + len += snprintf(buf + len, size - len, "%7x %7x ", + (ATH_SAMP_DBG(dma_dbg_reg_vals[5]) & 0x06000000) >> 25, + (ATH_SAMP_DBG(dma_dbg_reg_vals[5]) & 0x38000000) >> 27); + len += snprintf(buf + len, size - len, "%7d %12d ", + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x000003fc) >> 2, + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00000400) >> 10); + len += snprintf(buf + len, size - len, "%12d %12d ", + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00000800) >> 11, + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00001000) >> 12); + len += snprintf(buf + len, size - len, "%12d %12d ", + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x0001e000) >> 13, + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x001e0000) >> 17); + len += snprintf(buf + len, size - len, "0x%07x 0x%07x\n", + ATH_SAMP_DBG(pcu_obs), ATH_SAMP_DBG(pcu_cr)); + } + + len += snprintf(buf + len, size - len, + "Sample ChNoise Chain privNF #Reading Readings\n"); + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + h = ATH_SAMP_DBG(nfCalHist); + if (!ATH_SAMP_DBG(noise)) + continue; + + for (i = 0; i < NUM_NF_READINGS; i++) { + if (!(chainmask & (1 << i)) || + ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))) + continue; + + nread = AR_PHY_CCA_FILTERWINDOW_LENGTH - + h[i].invalidNFcount; + len += snprintf(buf + len, size - len, + "%4d %5d %4d\t %d\t %d\t", + sampidx, ATH_SAMP_DBG(noise), + i, h[i].privNF, nread); + for (j = 0; j < nread; j++) + len += snprintf(buf + len, size - len, + " %d", h[i].nfCalBuffer[j]); + len += snprintf(buf + len, size - len, "\n"); + } + } + len += snprintf(buf + len, size - len, "\nCycle counters:\n" + "Sample Total Rxbusy Rxframes Txframes\n"); + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + if (!ATH_SAMP_DBG(cc.cycles)) + continue; + len += snprintf(buf + len, size - len, + "%4d %08x %08x %08x %08x\n", + sampidx, ATH_SAMP_DBG(cc.cycles), + ATH_SAMP_DBG(cc.rx_busy), + ATH_SAMP_DBG(cc.rx_frame), + ATH_SAMP_DBG(cc.tx_frame)); + } + + len += snprintf(buf + len, size - len, "Tx status Dump :\n"); + len += snprintf(buf + len, size - len, + "Sample rssi:- ctl0 ctl1 ctl2 ext0 ext1 ext2 comb " + "isok rts_fail data_fail rate tid qid tx_before(ms)\n"); + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + for (i = 0; i < ATH_DBG_MAX_SAMPLES; i++) { + if (!ATH_SAMP_DBG(ts[i].jiffies)) + continue; + len += snprintf(buf + len, size - len, "%4d \t" + "%8d %4d %4d %4d %4d %4d %4d %4d %4d " + "%4d %4d %2d %2d %d\n", + sampidx, + ATH_SAMP_DBG(ts[i].rssi_ctl0), + ATH_SAMP_DBG(ts[i].rssi_ctl1), + ATH_SAMP_DBG(ts[i].rssi_ctl2), + ATH_SAMP_DBG(ts[i].rssi_ext0), + ATH_SAMP_DBG(ts[i].rssi_ext1), + ATH_SAMP_DBG(ts[i].rssi_ext2), + ATH_SAMP_DBG(ts[i].rssi), + ATH_SAMP_DBG(ts[i].isok), + ATH_SAMP_DBG(ts[i].rts_fail_cnt), + ATH_SAMP_DBG(ts[i].data_fail_cnt), + ATH_SAMP_DBG(ts[i].rateindex), + ATH_SAMP_DBG(ts[i].tid), + ATH_SAMP_DBG(ts[i].qid), + jiffies_to_msecs(jiffies - + ATH_SAMP_DBG(ts[i].jiffies))); + } + } + + len += snprintf(buf + len, size - len, "Rx status Dump :\n"); + len += snprintf(buf + len, size - len, "Sample rssi:- ctl0 ctl1 ctl2 " + "ext0 ext1 ext2 comb beacon ant rate rx_before(ms)\n"); + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + for (i = 0; i < ATH_DBG_MAX_SAMPLES; i++) { + if (!ATH_SAMP_DBG(rs[i].jiffies)) + continue; + len += snprintf(buf + len, size - len, "%4d \t" + "%8d %4d %4d %4d %4d %4d %4d %s %4d %02x %d\n", + sampidx, + ATH_SAMP_DBG(rs[i].rssi_ctl0), + ATH_SAMP_DBG(rs[i].rssi_ctl1), + ATH_SAMP_DBG(rs[i].rssi_ctl2), + ATH_SAMP_DBG(rs[i].rssi_ext0), + ATH_SAMP_DBG(rs[i].rssi_ext1), + ATH_SAMP_DBG(rs[i].rssi_ext2), + ATH_SAMP_DBG(rs[i].rssi), + ATH_SAMP_DBG(rs[i].is_mybeacon) ? + "True" : "False", + ATH_SAMP_DBG(rs[i].antenna), + ATH_SAMP_DBG(rs[i].rate), + jiffies_to_msecs(jiffies - + ATH_SAMP_DBG(rs[i].jiffies))); + } + } + + vfree(bb_mac_samp); + file->private_data = buf; + + return 0; +#undef ATH_SAMP_DBG +} + +static const struct file_operations fops_samps = { + .open = open_file_bb_mac_samps, + .read = ath9k_debugfs_read_buf, + .release = ath9k_debugfs_release_buf, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + + int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -1321,6 +1625,8 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_base_eeprom); debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_modal_eeprom); + debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_samps); debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); @@ -1329,5 +1635,9 @@ int ath9k_init_debug(struct ath_hw *ah) sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); sc->debug.regidx = 0; + memset(&sc->debug.bb_mac_samp, 0, sizeof(sc->debug.bb_mac_samp)); + sc->debug.sampidx = 0; + sc->debug.tsidx = 0; + sc->debug.rsidx = 0; return 0; } diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 4a04510e1111..95f85bdc8db7 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -177,14 +177,57 @@ struct ath_stats { struct ath_rx_stats rxstats; }; +#define ATH_DBG_MAX_SAMPLES 10 +struct ath_dbg_bb_mac_samp { + u32 dma_dbg_reg_vals[ATH9K_NUM_DMA_DEBUG_REGS]; + u32 pcu_obs, pcu_cr, noise; + struct { + u64 jiffies; + int8_t rssi_ctl0; + int8_t rssi_ctl1; + int8_t rssi_ctl2; + int8_t rssi_ext0; + int8_t rssi_ext1; + int8_t rssi_ext2; + int8_t rssi; + bool isok; + u8 rts_fail_cnt; + u8 data_fail_cnt; + u8 rateindex; + u8 qid; + u8 tid; + } ts[ATH_DBG_MAX_SAMPLES]; + struct { + u64 jiffies; + int8_t rssi_ctl0; + int8_t rssi_ctl1; + int8_t rssi_ctl2; + int8_t rssi_ext0; + int8_t rssi_ext1; + int8_t rssi_ext2; + int8_t rssi; + bool is_mybeacon; + u8 antenna; + u8 rate; + } rs[ATH_DBG_MAX_SAMPLES]; + struct ath_cycle_counters cc; + struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; +}; + struct ath9k_debug { struct dentry *debugfs_phy; u32 regidx; struct ath_stats stats; + spinlock_t samp_lock; + struct ath_dbg_bb_mac_samp bb_mac_samp[ATH_DBG_MAX_SAMPLES]; + u8 sampidx; + u8 tsidx; + u8 rsidx; }; int ath9k_init_debug(struct ath_hw *ah); +void ath9k_debug_samp_bb_mac(struct ath_softc *sc); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, struct ath_txq *txq); @@ -197,6 +240,10 @@ static inline int ath9k_init_debug(struct ath_hw *ah) return 0; } +static inline void ath9k_debug_samp_bb_mac(struct ath_softc *sc) +{ +} + static inline void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) { diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 0248024da56a..b9de1511add9 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1300,6 +1300,7 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, if (priv->op_flags & OP_INVALID) { ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_ANY, "Unable to configure filter on invalid state\n"); + mutex_unlock(&priv->mutex); return; } ath9k_htc_ps_wakeup(priv); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index a0d1147844fb..3a16ba256ef9 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -440,7 +440,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) if (AR_SREV_9100(ah)) ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX; ah->enable_32kHz_clock = DONT_USE_32KHZ; - ah->slottime = 20; + ah->slottime = ATH9K_SLOT_TIME_9; ah->globaltxtimeout = (u32) -1; ah->power_mode = ATH9K_PM_UNDEFINED; } @@ -997,8 +997,14 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) slottime = 21; sifstime = 64; } else { - eifs = REG_READ(ah, AR_D_GBL_IFS_EIFS)/common->clockrate; - reg = REG_READ(ah, AR_USEC); + if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) { + eifs = AR_D_GBL_IFS_EIFS_ASYNC_FIFO; + reg = AR_USEC_ASYNC_FIFO; + } else { + eifs = REG_READ(ah, AR_D_GBL_IFS_EIFS)/ + common->clockrate; + reg = REG_READ(ah, AR_USEC); + } rx_lat = MS(reg, AR_USEC_RX_LAT); tx_lat = MS(reg, AR_USEC_TX_LAT); @@ -2754,6 +2760,7 @@ static struct { { AR_SREV_VERSION_9271, "9271" }, { AR_SREV_VERSION_9300, "9300" }, { AR_SREV_VERSION_9330, "9330" }, + { AR_SREV_VERSION_9340, "9340" }, { AR_SREV_VERSION_9485, "9485" }, }; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 3aa3fb191775..c8af86c795e5 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -623,7 +623,7 @@ struct ath_hw_ops { struct ath_tx_status *ts); void (*set11n_txdesc)(struct ath_hw *ah, void *ds, u32 pktLen, enum ath9k_pkt_type type, - u32 txPower, u32 keyIx, + u32 txPower, u8 keyIx, enum ath9k_key_type keyType, u32 flags); void (*set11n_ratescenario)(struct ath_hw *ah, void *ds, diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index d7761d1fc5ba..dd71a5f77516 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -572,6 +572,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, mutex_init(&sc->mutex); #ifdef CONFIG_ATH9K_DEBUGFS spin_lock_init(&sc->nodes_lock); + spin_lock_init(&sc->debug.samp_lock); INIT_LIST_HEAD(&sc->nodes); #endif tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 153859ccc2a1..acb83bfd05a0 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -146,6 +146,7 @@ struct ath_rx_status { u8 rs_moreaggr; u8 rs_num_delims; u8 rs_flags; + bool is_mybeacon; u32 evm0; u32 evm1; u32 evm2; @@ -194,7 +195,7 @@ struct ath_htc_rx_status { #define ATH9K_RX_DECRYPT_BUSY 0x40 #define ATH9K_RXKEYIX_INVALID ((u8)-1) -#define ATH9K_TXKEYIX_INVALID ((u32)-1) +#define ATH9K_TXKEYIX_INVALID ((u8)-1) enum ath9k_phyerr { ATH9K_PHYERR_UNDERRUN = 0, /* Transmit underrun */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 5ac4f3f2ad60..7b7864dfab75 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -546,6 +546,7 @@ set_timer: * The interval must be the shortest necessary to satisfy ANI, * short calibration and long calibration. */ + ath9k_debug_samp_bb_mac(sc); cal_interval = ATH_LONG_CALINTERVAL; if (sc->sc_ah->config.enable_ani) cal_interval = min(cal_interval, @@ -978,6 +979,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) sc->hw_busy_count = 0; + ath9k_debug_samp_bb_mac(sc); /* Stop ANI */ del_timer_sync(&common->ani.timer); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index ad5f9bd2f0b9..9c7f905f3871 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -937,7 +937,7 @@ static int ath9k_process_rate(struct ath_common *common, * No valid hardware bitrate found -- we should not get here * because hardware has already validated this frame as OK. */ - ath_dbg(common, ATH_DBG_XMIT, + ath_dbg(common, ATH_DBG_ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n", rx_stats->rs_rate); @@ -952,23 +952,12 @@ static void ath9k_process_rssi(struct ath_common *common, struct ath_softc *sc = hw->priv; struct ath_hw *ah = common->ah; int last_rssi; - __le16 fc; - if ((ah->opmode != NL80211_IFTYPE_STATION) && - (ah->opmode != NL80211_IFTYPE_ADHOC)) + if (!rx_stats->is_mybeacon || + ((ah->opmode != NL80211_IFTYPE_STATION) && + (ah->opmode != NL80211_IFTYPE_ADHOC))) return; - fc = hdr->frame_control; - if (!ieee80211_is_beacon(fc) || - compare_ether_addr(hdr->addr3, common->curbssid)) { - /* TODO: This doesn't work well if you have stations - * associated to two different APs because curbssid - * is just the last AP that any of the stations associated - * with. - */ - return; - } - if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && !rx_stats->rs_moreaggr) ATH_RSSI_LPF(sc->last_rssi, rx_stats->rs_rssi); @@ -1838,6 +1827,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len); rxs = IEEE80211_SKB_RXCB(hdr_skb); + if (ieee80211_is_beacon(hdr->frame_control) && + !compare_ether_addr(hdr->addr3, common->curbssid)) + rs.is_mybeacon = true; + else + rs.is_mybeacon = false; ath_debug_stat_rx(sc, &rs); diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index a3b8bbc6c063..17a272f4d8d6 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -619,6 +619,7 @@ #define AR_D_GBL_IFS_EIFS 0x10b0 #define AR_D_GBL_IFS_EIFS_M 0x0000FFFF #define AR_D_GBL_IFS_EIFS_RESV0 0xFFFF0000 +#define AR_D_GBL_IFS_EIFS_ASYNC_FIFO 363 #define AR_D_GBL_IFS_MISC 0x10f0 #define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007 @@ -1503,6 +1504,7 @@ enum { #define AR_USEC_TX_LAT_S 14 #define AR_USEC_RX_LAT 0x1F800000 #define AR_USEC_RX_LAT_S 23 +#define AR_USEC_ASYNC_FIFO 0x12E00074 #define AR_RESET_TSF 0x8020 #define AR_RESET_TSF_ONCE 0x01000000 diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 5e2982938ffc..68066c56e4e5 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -48,8 +48,9 @@ static u16 bits_per_symbol[][2] = { #define IS_HT_RATE(_rate) ((_rate) & 0x80) static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid, - struct list_head *bf_head); + struct ath_atx_tid *tid, struct sk_buff *skb); +static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, + int tx_flags, struct ath_txq *txq); static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, struct ath_txq *txq, struct list_head *bf_q, struct ath_tx_status *ts, int txok, int sendbar); @@ -61,6 +62,10 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, int txok, bool update_rc); static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, int seqno); +static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, + struct ath_txq *txq, + struct ath_atx_tid *tid, + struct sk_buff *skb); enum { MCS_HT20, @@ -129,7 +134,7 @@ static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) spin_lock_bh(&txq->axq_lock); tid->paused = false; - if (list_empty(&tid->buf_q)) + if (skb_queue_empty(&tid->buf_q)) goto unlock; ath_tx_queue_tid(txq, tid); @@ -149,6 +154,7 @@ static struct ath_frame_info *get_frame_info(struct sk_buff *skb) static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { struct ath_txq *txq = tid->ac->txq; + struct sk_buff *skb; struct ath_buf *bf; struct list_head bf_head; struct ath_tx_status ts; @@ -159,17 +165,17 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) memset(&ts, 0, sizeof(ts)); spin_lock_bh(&txq->axq_lock); - while (!list_empty(&tid->buf_q)) { - bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - list_move_tail(&bf->list, &bf_head); + while ((skb = __skb_dequeue(&tid->buf_q))) { + fi = get_frame_info(skb); + bf = fi->bf; spin_unlock_bh(&txq->axq_lock); - fi = get_frame_info(bf->bf_mpdu); - if (fi->retries) { - ath_tx_update_baw(sc, tid, fi->seqno); + if (bf && fi->retries) { + list_add_tail(&bf->list, &bf_head); + ath_tx_update_baw(sc, tid, bf->bf_state.seqno); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 1); } else { - ath_tx_send_normal(sc, txq, NULL, &bf_head); + ath_tx_send_normal(sc, txq, NULL, skb); } spin_lock_bh(&txq->axq_lock); } @@ -219,6 +225,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid) { + struct sk_buff *skb; struct ath_buf *bf; struct list_head bf_head; struct ath_tx_status ts; @@ -227,16 +234,21 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, memset(&ts, 0, sizeof(ts)); INIT_LIST_HEAD(&bf_head); - for (;;) { - if (list_empty(&tid->buf_q)) - break; + while ((skb = __skb_dequeue(&tid->buf_q))) { + fi = get_frame_info(skb); + bf = fi->bf; + + if (!bf) { + spin_unlock(&txq->axq_lock); + ath_tx_complete(sc, skb, ATH_TX_ERROR, txq); + spin_lock(&txq->axq_lock); + continue; + } - bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - list_move_tail(&bf->list, &bf_head); + list_add_tail(&bf->list, &bf_head); - fi = get_frame_info(bf->bf_mpdu); if (fi->retries) - ath_tx_update_baw(sc, tid, fi->seqno); + ath_tx_update_baw(sc, tid, bf->bf_state.seqno); spin_unlock(&txq->axq_lock); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); @@ -326,7 +338,7 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, while (bf) { fi = get_frame_info(bf->bf_mpdu); - ba_index = ATH_BA_INDEX(seq_st, fi->seqno); + ba_index = ATH_BA_INDEX(seq_st, bf->bf_state.seqno); (*nframes)++; if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index))) @@ -349,7 +361,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ieee80211_tx_info *tx_info; struct ath_atx_tid *tid = NULL; struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; - struct list_head bf_head, bf_pending; + struct list_head bf_head; + struct sk_buff_head bf_pending; u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0; u32 ba[WME_BA_BMP_SIZE >> 5]; int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; @@ -422,11 +435,12 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, } } - INIT_LIST_HEAD(&bf_pending); - INIT_LIST_HEAD(&bf_head); + __skb_queue_head_init(&bf_pending); ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad); while (bf) { + u16 seqno = bf->bf_state.seqno; + txfail = txpending = sendbar = 0; bf_next = bf->bf_next; @@ -434,7 +448,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, tx_info = IEEE80211_SKB_CB(skb); fi = get_frame_info(skb); - if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, fi->seqno))) { + if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, seqno))) { /* transmit completion, subframe is * acked by block ack */ acked_cnt++; @@ -467,10 +481,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * Make sure the last desc is reclaimed if it * not a holding desc. */ - if (!bf_last->bf_stale || bf_next != NULL) + INIT_LIST_HEAD(&bf_head); + if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) || + bf_next != NULL || !bf_last->bf_stale) list_move_tail(&bf->list, &bf_head); - else - INIT_LIST_HEAD(&bf_head); if (!txpending || (tid->state & AGGR_CLEANUP)) { /* @@ -478,7 +492,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * block-ack window */ spin_lock_bh(&txq->axq_lock); - ath_tx_update_baw(sc, tid, fi->seqno); + ath_tx_update_baw(sc, tid, seqno); spin_unlock_bh(&txq->axq_lock); if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { @@ -506,7 +520,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, */ if (!tbf) { spin_lock_bh(&txq->axq_lock); - ath_tx_update_baw(sc, tid, fi->seqno); + ath_tx_update_baw(sc, tid, seqno); spin_unlock_bh(&txq->axq_lock); bf->bf_state.bf_type |= @@ -521,7 +535,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc); - list_add_tail(&tbf->list, &bf_head); + fi->bf = tbf; } else { /* * Clear descriptor status words for @@ -536,21 +550,21 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * Put this buffer to the temporary pending * queue to retain ordering */ - list_splice_tail_init(&bf_head, &bf_pending); + __skb_queue_tail(&bf_pending, skb); } bf = bf_next; } /* prepend un-acked frames to the beginning of the pending frame queue */ - if (!list_empty(&bf_pending)) { + if (!skb_queue_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); + skb_queue_splice(&bf_pending, &tid->buf_q); if (!an->sleeping) ath_tx_queue_tid(txq, tid); spin_unlock_bh(&txq->axq_lock); @@ -582,7 +596,10 @@ static bool ath_lookup_legacy(struct ath_buf *bf) tx_info = IEEE80211_SKB_CB(skb); rates = tx_info->control.rates; - for (i = 3; i >= 0; i--) { + for (i = 0; i < 4; i++) { + if (!rates[i].count || rates[i].idx < 0) + break; + if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) return true; } @@ -740,22 +757,33 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, int *aggr_len) { #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) - struct ath_buf *bf, *bf_first, *bf_prev = NULL; + struct ath_buf *bf, *bf_first = NULL, *bf_prev = NULL; int rl = 0, nframes = 0, ndelim, prev_al = 0; u16 aggr_limit = 0, al = 0, bpad = 0, al_delta, h_baw = tid->baw_size / 2; enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; struct ieee80211_tx_info *tx_info; struct ath_frame_info *fi; - - bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list); + struct sk_buff *skb; + u16 seqno; do { - bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - fi = get_frame_info(bf->bf_mpdu); + skb = skb_peek(&tid->buf_q); + fi = get_frame_info(skb); + bf = fi->bf; + if (!fi->bf) + bf = ath_tx_setup_buffer(sc, txq, tid, skb); + + if (!bf) + continue; + + bf->bf_state.bf_type |= BUF_AMPDU; + seqno = bf->bf_state.seqno; + if (!bf_first) + bf_first = bf; /* do not step over block-ack window */ - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno)) { + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) { status = ATH_AGGR_BAW_CLOSED; break; } @@ -803,9 +831,11 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, /* link buffers of this frame to the aggregate */ if (!fi->retries) - ath_tx_addto_baw(sc, tid, fi->seqno); + ath_tx_addto_baw(sc, tid, seqno); ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim); - list_move_tail(&bf->list, bf_q); + + __skb_unlink(skb, &tid->buf_q); + list_add_tail(&bf->list, bf_q); if (bf_prev) { bf_prev->bf_next = bf; ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc, @@ -813,7 +843,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, } bf_prev = bf; - } while (!list_empty(&tid->buf_q)); + } while (!skb_queue_empty(&tid->buf_q)); *aggr_len = al; @@ -831,7 +861,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, int aggr_len; do { - if (list_empty(&tid->buf_q)) + if (skb_queue_empty(&tid->buf_q)) return; INIT_LIST_HEAD(&bf_q); @@ -952,7 +982,7 @@ bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) spin_lock_bh(&txq->axq_lock); - if (!list_empty(&tid->buf_q)) + if (!skb_queue_empty(&tid->buf_q)) buffered = true; tid->sched = false; @@ -985,7 +1015,7 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) spin_lock_bh(&txq->axq_lock); ac->clear_ps_filter = true; - if (!list_empty(&tid->buf_q) && !tid->paused) { + if (!skb_queue_empty(&tid->buf_q) && !tid->paused) { ath_tx_queue_tid(txq, tid); ath_txq_schedule(sc, txq); } @@ -1329,7 +1359,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) * add tid to round-robin queue if more frames * are pending for the tid */ - if (!list_empty(&tid->buf_q)) + if (!skb_queue_empty(&tid->buf_q)) ath_tx_queue_tid(txq, tid); if (tid == last_tid || @@ -1421,12 +1451,11 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, } static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, - struct ath_buf *bf, struct ath_tx_control *txctl) + struct sk_buff *skb, struct ath_tx_control *txctl) { - struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); + struct ath_frame_info *fi = get_frame_info(skb); struct list_head bf_head; - - bf->bf_state.bf_type |= BUF_AMPDU; + struct ath_buf *bf; /* * Do not queue to h/w when any of the following conditions is true: @@ -1435,26 +1464,30 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, * - seqno is not within block-ack window * - h/w queue depth exceeds low water mark */ - if (!list_empty(&tid->buf_q) || tid->paused || - !BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno) || + if (!skb_queue_empty(&tid->buf_q) || tid->paused || + !BAW_WITHIN(tid->seq_start, tid->baw_size, tid->seq_next) || txctl->txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) { /* * Add this frame to software queue for scheduling later * for aggregation. */ TX_STAT_INC(txctl->txq->axq_qnum, a_queued_sw); - list_add_tail(&bf->list, &tid->buf_q); + __skb_queue_tail(&tid->buf_q, skb); if (!txctl->an || !txctl->an->sleeping) ath_tx_queue_tid(txctl->txq, tid); return; } + bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); + if (!bf) + return; + + bf->bf_state.bf_type |= BUF_AMPDU; INIT_LIST_HEAD(&bf_head); list_add(&bf->list, &bf_head); /* Add sub-frame to BAW */ - if (!fi->retries) - ath_tx_addto_baw(sc, tid, fi->seqno); + ath_tx_addto_baw(sc, tid, bf->bf_state.seqno); /* Queue to h/w without aggregation */ TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw); @@ -1464,13 +1497,21 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, } static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid, - struct list_head *bf_head) + struct ath_atx_tid *tid, struct sk_buff *skb) { - struct ath_frame_info *fi; + struct ath_frame_info *fi = get_frame_info(skb); + struct list_head bf_head; struct ath_buf *bf; - bf = list_first_entry(bf_head, struct ath_buf, list); + bf = fi->bf; + if (!bf) + bf = ath_tx_setup_buffer(sc, txq, tid, skb); + + if (!bf) + return; + + INIT_LIST_HEAD(&bf_head); + list_add_tail(&bf->list, &bf_head); bf->bf_state.bf_type &= ~BUF_AMPDU; /* update starting sequence number for subsequent ADDBA request */ @@ -1478,9 +1519,8 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, INCR(tid->seq_start, IEEE80211_SEQ_MAX); bf->bf_lastbf = bf; - fi = get_frame_info(bf->bf_mpdu); ath_buf_set_rate(sc, bf, fi->framelen); - ath_tx_txqaddbuf(sc, txq, bf_head, false); + ath_tx_txqaddbuf(sc, txq, &bf_head, false); TX_STAT_INC(txq->axq_qnum, queued); } @@ -1510,39 +1550,19 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, int framelen) { - struct ath_softc *sc = hw->priv; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = tx_info->control.sta; struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ath_frame_info *fi = get_frame_info(skb); struct ath_node *an = NULL; - struct ath_atx_tid *tid; enum ath9k_key_type keytype; - u16 seqno = 0; - u8 tidno; keytype = ath9k_cmn_get_hw_crypto_keytype(skb); if (sta) an = (struct ath_node *) sta->drv_priv; - hdr = (struct ieee80211_hdr *)skb->data; - if (an && ieee80211_is_data_qos(hdr->frame_control) && - conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) { - - tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; - - /* - * Override seqno set by upper layer with the one - * in tx aggregation state. - */ - tid = ATH_AN_2_TID(an, tidno); - seqno = tid->seq_next; - hdr->seq_ctrl = cpu_to_le16(seqno << IEEE80211_SEQ_SEQ_SHIFT); - INCR(tid->seq_next, IEEE80211_SEQ_MAX); - } - memset(fi, 0, sizeof(*fi)); if (hw_key) fi->keyix = hw_key->hw_key_idx; @@ -1552,7 +1572,6 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, fi->keyix = ATH9K_TXKEYIX_INVALID; fi->keytype = keytype; fi->framelen = framelen; - fi->seqno = seqno; } static int setup_tx_flags(struct sk_buff *skb) @@ -1724,26 +1743,39 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len) } -static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, +/* + * Assign a descriptor (and sequence number if necessary, + * and map buffer for DMA. Frees skb on error + */ +static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid, struct sk_buff *skb) { - struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_frame_info *fi = get_frame_info(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ath_buf *bf; struct ath_desc *ds; int frm_type; + u16 seqno; bf = ath_tx_get_buffer(sc); if (!bf) { ath_dbg(common, ATH_DBG_XMIT, "TX buffers are full\n"); - return NULL; + goto error; } ATH_TXBUF_RESET(bf); + if (tid) { + seqno = tid->seq_next; + hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT); + INCR(tid->seq_next, IEEE80211_SEQ_MAX); + bf->bf_state.seqno = seqno; + } + bf->bf_flags = setup_tx_flags(skb); bf->bf_mpdu = skb; @@ -1755,7 +1787,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, ath_err(ath9k_hw_common(sc->sc_ah), "dma_mapping_error() on TX\n"); ath_tx_return_buffer(sc, bf); - return NULL; + goto error; } frm_type = get_hw_packet_type(skb); @@ -1774,19 +1806,23 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, bf->bf_buf_addr, txq->axq_qnum); + fi->bf = bf; return bf; + +error: + dev_kfree_skb_any(skb); + return NULL; } /* FIXME: tx power */ -static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, +static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, struct ath_tx_control *txctl) { - struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct list_head bf_head; struct ath_atx_tid *tid = NULL; + struct ath_buf *bf; u8 tidno; spin_lock_bh(&txctl->txq->axq_lock); @@ -1804,10 +1840,11 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, * Try aggregation if it's a unicast data frame * and the destination is HT capable. */ - ath_tx_send_ampdu(sc, tid, bf, txctl); + ath_tx_send_ampdu(sc, tid, skb, txctl); } else { - INIT_LIST_HEAD(&bf_head); - list_add_tail(&bf->list, &bf_head); + bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); + if (!bf) + goto out; bf->bf_state.bfs_paprd = txctl->paprd; @@ -1821,9 +1858,10 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, 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); + ath_tx_send_normal(sc, txctl->txq, tid, skb); } +out: spin_unlock_bh(&txctl->txq->axq_lock); } @@ -1837,7 +1875,6 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_vif *vif = info->control.vif; struct ath_softc *sc = hw->priv; struct ath_txq *txq = txctl->txq; - struct ath_buf *bf; int padpos, padsize; int frmlen = skb->len + FCS_LEN; int q; @@ -1884,10 +1921,6 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, * info are no longer valid (overwritten by the ath_frame_info data. */ - bf = ath_tx_setup_buffer(hw, txctl->txq, skb); - if (unlikely(!bf)) - return -ENOMEM; - q = skb_get_queue_mapping(skb); spin_lock_bh(&txq->axq_lock); if (txq == sc->tx.txq_map[q] && @@ -1897,8 +1930,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, } spin_unlock_bh(&txq->axq_lock); - ath_tx_start_dma(sc, bf, txctl); - + ath_tx_start_dma(sc, skb, txctl); return 0; } @@ -2391,7 +2423,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) tid->sched = false; tid->paused = false; tid->state &= ~AGGR_CLEANUP; - INIT_LIST_HEAD(&tid->buf_q); + __skb_queue_head_init(&tid->buf_q); acno = TID_TO_WME_AC(tidno); tid->ac = &an->ac[acno]; tid->state &= ~AGGR_ADDBA_COMPLETE; |