mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 02:39:48 +00:00
ath9k: Switch to mac80211 TXQ scheduling and airtime APIs
This moves the ath9k driver to use the mac80211 TXQ scheduling and airtime accounting APIs, removing the corresponding state tracking inside the driver. Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk> [rmanohar@codeaurora.org: fixed checkpatch error and warnings] Signed-off-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
parent
acc65103c1
commit
89cea7493a
7 changed files with 75 additions and 276 deletions
|
@ -112,8 +112,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
|
|||
#define ATH_TXFIFO_DEPTH 8
|
||||
#define ATH_TX_ERROR 0x01
|
||||
|
||||
#define ATH_AIRTIME_QUANTUM 300 /* usec */
|
||||
|
||||
/* Stop tx traffic 1ms before the GO goes away */
|
||||
#define ATH_P2P_PS_STOP_TIME 1000
|
||||
|
||||
|
@ -246,10 +244,8 @@ struct ath_atx_tid {
|
|||
s8 bar_index;
|
||||
bool active;
|
||||
bool clear_ps_filter;
|
||||
bool has_queued;
|
||||
};
|
||||
|
||||
void __ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid);
|
||||
void ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid);
|
||||
|
||||
struct ath_node {
|
||||
|
@ -263,12 +259,9 @@ struct ath_node {
|
|||
|
||||
bool sleeping;
|
||||
bool no_ps_filter;
|
||||
s64 airtime_deficit[IEEE80211_NUM_ACS];
|
||||
u32 airtime_rx_start;
|
||||
|
||||
#ifdef CONFIG_ATH9K_STATION_STATISTICS
|
||||
struct ath_rx_rate_stats rx_rate_stats;
|
||||
struct ath_airtime_stats airtime_stats;
|
||||
#endif
|
||||
u8 key_idx[4];
|
||||
|
||||
|
@ -986,11 +979,6 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
|
|||
|
||||
#define ATH9K_NUM_CHANCTX 2 /* supports 2 operating channels */
|
||||
|
||||
#define AIRTIME_USE_TX BIT(0)
|
||||
#define AIRTIME_USE_RX BIT(1)
|
||||
#define AIRTIME_USE_NEW_QUEUES BIT(2)
|
||||
#define AIRTIME_ACTIVE(flags) (!!(flags & (AIRTIME_USE_TX|AIRTIME_USE_RX)))
|
||||
|
||||
struct ath_softc {
|
||||
struct ieee80211_hw *hw;
|
||||
struct device *dev;
|
||||
|
@ -1034,8 +1022,6 @@ struct ath_softc {
|
|||
short nbcnvifs;
|
||||
unsigned long ps_usecount;
|
||||
|
||||
u16 airtime_flags; /* AIRTIME_* */
|
||||
|
||||
struct ath_rx rx;
|
||||
struct ath_tx tx;
|
||||
struct ath_beacon beacon;
|
||||
|
|
|
@ -1443,9 +1443,6 @@ int ath9k_init_debug(struct ath_hw *ah)
|
|||
#endif
|
||||
debugfs_create_file("tpc", 0600, sc->debug.debugfs_phy, sc, &fops_tpc);
|
||||
|
||||
debugfs_create_u16("airtime_flags", 0600,
|
||||
sc->debug.debugfs_phy, &sc->airtime_flags);
|
||||
|
||||
debugfs_create_file("nf_override", 0600,
|
||||
sc->debug.debugfs_phy, sc, &fops_nf_override);
|
||||
|
||||
|
|
|
@ -319,20 +319,12 @@ ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause)
|
|||
void ath_debug_rate_stats(struct ath_softc *sc,
|
||||
struct ath_rx_status *rs,
|
||||
struct sk_buff *skb);
|
||||
void ath_debug_airtime(struct ath_softc *sc,
|
||||
struct ath_node *an,
|
||||
u32 rx, u32 tx);
|
||||
#else
|
||||
static inline void ath_debug_rate_stats(struct ath_softc *sc,
|
||||
struct ath_rx_status *rs,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
}
|
||||
static inline void ath_debug_airtime(struct ath_softc *sc,
|
||||
struct ath_node *an,
|
||||
u32 rx, u32 tx)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_ATH9K_STATION_STATISTICS */
|
||||
|
||||
#endif /* DEBUG_H */
|
||||
|
|
|
@ -242,75 +242,6 @@ static const struct file_operations fops_node_recv = {
|
|||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
void ath_debug_airtime(struct ath_softc *sc,
|
||||
struct ath_node *an,
|
||||
u32 rx,
|
||||
u32 tx)
|
||||
{
|
||||
struct ath_airtime_stats *astats = &an->airtime_stats;
|
||||
|
||||
astats->rx_airtime += rx;
|
||||
astats->tx_airtime += tx;
|
||||
}
|
||||
|
||||
static ssize_t read_airtime(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_node *an = file->private_data;
|
||||
struct ath_airtime_stats *astats;
|
||||
static const char *qname[4] = {
|
||||
"VO", "VI", "BE", "BK"
|
||||
};
|
||||
u32 len = 0, size = 256;
|
||||
char *buf;
|
||||
size_t retval;
|
||||
int i;
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
astats = &an->airtime_stats;
|
||||
|
||||
len += scnprintf(buf + len, size - len, "RX: %u us\n", astats->rx_airtime);
|
||||
len += scnprintf(buf + len, size - len, "TX: %u us\n", astats->tx_airtime);
|
||||
len += scnprintf(buf + len, size - len, "Deficit: ");
|
||||
for (i = 0; i < 4; i++)
|
||||
len += scnprintf(buf+len, size - len, "%s: %lld us ", qname[i], an->airtime_deficit[i]);
|
||||
if (len < size)
|
||||
buf[len++] = '\n';
|
||||
|
||||
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
kfree(buf);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
write_airtime_reset_stub(struct file *file, const char __user *ubuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_node *an = file->private_data;
|
||||
struct ath_airtime_stats *astats;
|
||||
int i;
|
||||
|
||||
astats = &an->airtime_stats;
|
||||
astats->rx_airtime = 0;
|
||||
astats->tx_airtime = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
an->airtime_deficit[i] = ATH_AIRTIME_QUANTUM;
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_airtime = {
|
||||
.read = read_airtime,
|
||||
.write = write_airtime_reset_stub,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
|
||||
void ath9k_sta_add_debugfs(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
|
@ -320,5 +251,4 @@ void ath9k_sta_add_debugfs(struct ieee80211_hw *hw,
|
|||
|
||||
debugfs_create_file("node_aggr", 0444, dir, an, &fops_node_aggr);
|
||||
debugfs_create_file("node_recv", 0444, dir, an, &fops_node_recv);
|
||||
debugfs_create_file("airtime", 0644, dir, an, &fops_airtime);
|
||||
}
|
||||
|
|
|
@ -676,8 +676,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
|
|||
|
||||
/* Will be cleared in ath9k_start() */
|
||||
set_bit(ATH_OP_INVALID, &common->op_flags);
|
||||
sc->airtime_flags = (AIRTIME_USE_TX | AIRTIME_USE_RX |
|
||||
AIRTIME_USE_NEW_QUEUES);
|
||||
|
||||
sc->sc_ah = ah;
|
||||
sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET);
|
||||
|
@ -1013,6 +1011,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
|
||||
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
|
||||
}
|
||||
|
||||
int ath9k_init_device(u16 devid, struct ath_softc *sc,
|
||||
|
|
|
@ -1054,14 +1054,7 @@ static void ath_rx_count_airtime(struct ath_softc *sc,
|
|||
len, rxs->rate_idx, is_sp);
|
||||
}
|
||||
|
||||
if (!!(sc->airtime_flags & AIRTIME_USE_RX)) {
|
||||
spin_lock_bh(&acq->lock);
|
||||
an->airtime_deficit[acno] -= airtime;
|
||||
if (an->airtime_deficit[acno] <= 0)
|
||||
__ath_tx_queue_tid(sc, ATH_AN_2_TID(an, tidno));
|
||||
spin_unlock_bh(&acq->lock);
|
||||
}
|
||||
ath_debug_airtime(sc, an, airtime, 0);
|
||||
ieee80211_sta_register_airtime(sta, tidno, 0, airtime);
|
||||
exit:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
|
|
@ -113,44 +113,14 @@ void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
|
|||
ath_tx_status(hw, skb);
|
||||
}
|
||||
|
||||
void __ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
|
||||
{
|
||||
struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv;
|
||||
struct ath_chanctx *ctx = avp->chanctx;
|
||||
struct ath_acq *acq;
|
||||
struct list_head *tid_list;
|
||||
u8 acno = TID_TO_WME_AC(tid->tidno);
|
||||
|
||||
if (!ctx || !list_empty(&tid->list))
|
||||
return;
|
||||
|
||||
|
||||
acq = &ctx->acq[acno];
|
||||
if ((sc->airtime_flags & AIRTIME_USE_NEW_QUEUES) &&
|
||||
tid->an->airtime_deficit[acno] > 0)
|
||||
tid_list = &acq->acq_new;
|
||||
else
|
||||
tid_list = &acq->acq_old;
|
||||
|
||||
list_add_tail(&tid->list, tid_list);
|
||||
}
|
||||
|
||||
void ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
|
||||
{
|
||||
struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv;
|
||||
struct ath_chanctx *ctx = avp->chanctx;
|
||||
struct ath_acq *acq;
|
||||
struct ieee80211_txq *queue =
|
||||
container_of((void *)tid, struct ieee80211_txq, drv_priv);
|
||||
|
||||
if (!ctx || !list_empty(&tid->list))
|
||||
return;
|
||||
|
||||
acq = &ctx->acq[TID_TO_WME_AC(tid->tidno)];
|
||||
spin_lock_bh(&acq->lock);
|
||||
__ath_tx_queue_tid(sc, tid);
|
||||
spin_unlock_bh(&acq->lock);
|
||||
ieee80211_schedule_txq(sc->hw, queue);
|
||||
}
|
||||
|
||||
|
||||
void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
|
||||
{
|
||||
struct ath_softc *sc = hw->priv;
|
||||
|
@ -163,11 +133,7 @@ void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
|
|||
tid->tidno);
|
||||
|
||||
ath_txq_lock(sc, txq);
|
||||
|
||||
tid->has_queued = true;
|
||||
ath_tx_queue_tid(sc, tid);
|
||||
ath_txq_schedule(sc, txq);
|
||||
|
||||
ath_txq_unlock(sc, txq);
|
||||
}
|
||||
|
||||
|
@ -217,8 +183,8 @@ ath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb)
|
|||
return ATH_AN_2_TID(an, tidno);
|
||||
}
|
||||
|
||||
static struct sk_buff *
|
||||
ath_tid_pull(struct ath_atx_tid *tid)
|
||||
static int
|
||||
ath_tid_pull(struct ath_atx_tid *tid, struct sk_buff **skbuf)
|
||||
{
|
||||
struct ieee80211_txq *txq = container_of((void*)tid, struct ieee80211_txq, drv_priv);
|
||||
struct ath_softc *sc = tid->an->sc;
|
||||
|
@ -229,20 +195,16 @@ ath_tid_pull(struct ath_atx_tid *tid)
|
|||
};
|
||||
struct sk_buff *skb;
|
||||
struct ath_frame_info *fi;
|
||||
int q;
|
||||
|
||||
if (!tid->has_queued)
|
||||
return NULL;
|
||||
int q, ret;
|
||||
|
||||
skb = ieee80211_tx_dequeue(hw, txq);
|
||||
if (!skb) {
|
||||
tid->has_queued = false;
|
||||
return NULL;
|
||||
}
|
||||
if (!skb)
|
||||
return -ENOENT;
|
||||
|
||||
if (ath_tx_prepare(hw, skb, &txctl)) {
|
||||
ret = ath_tx_prepare(hw, skb, &txctl);
|
||||
if (ret) {
|
||||
ieee80211_free_txskb(hw, skb);
|
||||
return NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
q = skb_get_queue_mapping(skb);
|
||||
|
@ -252,24 +214,19 @@ ath_tid_pull(struct ath_atx_tid *tid)
|
|||
++tid->txq->pending_frames;
|
||||
}
|
||||
|
||||
return skb;
|
||||
*skbuf = skb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static bool ath_tid_has_buffered(struct ath_atx_tid *tid)
|
||||
static int ath_tid_dequeue(struct ath_atx_tid *tid,
|
||||
struct sk_buff **skb)
|
||||
{
|
||||
return !skb_queue_empty(&tid->retry_q) || tid->has_queued;
|
||||
}
|
||||
int ret = 0;
|
||||
*skb = __skb_dequeue(&tid->retry_q);
|
||||
if (!*skb)
|
||||
ret = ath_tid_pull(tid, skb);
|
||||
|
||||
static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = __skb_dequeue(&tid->retry_q);
|
||||
if (!skb)
|
||||
skb = ath_tid_pull(tid);
|
||||
|
||||
return skb;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
|
||||
|
@ -365,11 +322,12 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
|
|||
struct list_head bf_head;
|
||||
struct ath_tx_status ts;
|
||||
struct ath_frame_info *fi;
|
||||
int ret;
|
||||
|
||||
memset(&ts, 0, sizeof(ts));
|
||||
INIT_LIST_HEAD(&bf_head);
|
||||
|
||||
while ((skb = ath_tid_dequeue(tid))) {
|
||||
while ((ret = ath_tid_dequeue(tid, &skb)) == 0) {
|
||||
fi = get_frame_info(skb);
|
||||
bf = fi->bf;
|
||||
|
||||
|
@ -681,7 +639,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|||
skb_queue_splice_tail(&bf_pending, &tid->retry_q);
|
||||
if (!an->sleeping) {
|
||||
ath_tx_queue_tid(sc, tid);
|
||||
|
||||
if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY))
|
||||
tid->clear_ps_filter = true;
|
||||
}
|
||||
|
@ -708,11 +665,11 @@ static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
|
|||
return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
|
||||
}
|
||||
|
||||
static void ath_tx_count_airtime(struct ath_softc *sc, struct ath_node *an,
|
||||
struct ath_atx_tid *tid, struct ath_buf *bf,
|
||||
static void ath_tx_count_airtime(struct ath_softc *sc,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ath_buf *bf,
|
||||
struct ath_tx_status *ts)
|
||||
{
|
||||
struct ath_txq *txq = tid->txq;
|
||||
u32 airtime = 0;
|
||||
int i;
|
||||
|
||||
|
@ -722,17 +679,7 @@ static void ath_tx_count_airtime(struct ath_softc *sc, struct ath_node *an,
|
|||
airtime += rate_dur * bf->rates[i].count;
|
||||
}
|
||||
|
||||
if (sc->airtime_flags & AIRTIME_USE_TX) {
|
||||
int q = txq->mac80211_qnum;
|
||||
struct ath_acq *acq = &sc->cur_chan->acq[q];
|
||||
|
||||
spin_lock_bh(&acq->lock);
|
||||
an->airtime_deficit[q] -= airtime;
|
||||
if (an->airtime_deficit[q] <= 0)
|
||||
__ath_tx_queue_tid(sc, tid);
|
||||
spin_unlock_bh(&acq->lock);
|
||||
}
|
||||
ath_debug_airtime(sc, an, 0, airtime);
|
||||
ieee80211_sta_register_airtime(sta, ts->tid, airtime, 0);
|
||||
}
|
||||
|
||||
static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
|
||||
|
@ -762,7 +709,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
|
|||
if (sta) {
|
||||
struct ath_node *an = (struct ath_node *)sta->drv_priv;
|
||||
tid = ath_get_skb_tid(sc, an, bf->bf_mpdu);
|
||||
ath_tx_count_airtime(sc, an, tid, bf, ts);
|
||||
ath_tx_count_airtime(sc, sta, bf, ts);
|
||||
if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY))
|
||||
tid->clear_ps_filter = true;
|
||||
}
|
||||
|
@ -947,20 +894,21 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
|
|||
return ndelim;
|
||||
}
|
||||
|
||||
static struct ath_buf *
|
||||
static int
|
||||
ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
|
||||
struct ath_atx_tid *tid)
|
||||
struct ath_atx_tid *tid, struct ath_buf **buf)
|
||||
{
|
||||
struct ieee80211_tx_info *tx_info;
|
||||
struct ath_frame_info *fi;
|
||||
struct sk_buff *skb, *first_skb = NULL;
|
||||
struct ath_buf *bf;
|
||||
struct sk_buff *skb, *first_skb = NULL;
|
||||
u16 seqno;
|
||||
int ret;
|
||||
|
||||
while (1) {
|
||||
skb = ath_tid_dequeue(tid);
|
||||
if (!skb)
|
||||
break;
|
||||
ret = ath_tid_dequeue(tid, &skb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
fi = get_frame_info(skb);
|
||||
bf = fi->bf;
|
||||
|
@ -992,7 +940,7 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
|
|||
|
||||
if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) {
|
||||
bf->bf_state.bf_type = 0;
|
||||
return bf;
|
||||
break;
|
||||
}
|
||||
|
||||
bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR;
|
||||
|
@ -1011,7 +959,7 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
|
|||
first_skb = skb;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
|
||||
|
@ -1028,10 +976,11 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
|
|||
if (bf_isampdu(bf))
|
||||
ath_tx_addto_baw(sc, tid, bf);
|
||||
|
||||
return bf;
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
*buf = bf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1041,7 +990,7 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|||
{
|
||||
#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
|
||||
struct ath_buf *bf = bf_first, *bf_prev = NULL;
|
||||
int nframes = 0, ndelim;
|
||||
int nframes = 0, ndelim, ret;
|
||||
u16 aggr_limit = 0, al = 0, bpad = 0,
|
||||
al_delta, h_baw = tid->baw_size / 2;
|
||||
struct ieee80211_tx_info *tx_info;
|
||||
|
@ -1093,7 +1042,9 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|||
|
||||
bf_prev = bf;
|
||||
|
||||
bf = ath_tx_get_tid_subframe(sc, txq, tid);
|
||||
ret = ath_tx_get_tid_subframe(sc, txq, tid, &bf);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
goto finish;
|
||||
stop:
|
||||
|
@ -1490,7 +1441,7 @@ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
|
|||
struct ath_buf *bf_first)
|
||||
{
|
||||
struct ath_buf *bf = bf_first, *bf_prev = NULL;
|
||||
int nframes = 0;
|
||||
int nframes = 0, ret;
|
||||
|
||||
do {
|
||||
struct ieee80211_tx_info *tx_info;
|
||||
|
@ -1504,8 +1455,8 @@ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
|
|||
if (nframes >= 2)
|
||||
break;
|
||||
|
||||
bf = ath_tx_get_tid_subframe(sc, txq, tid);
|
||||
if (!bf)
|
||||
ret = ath_tx_get_tid_subframe(sc, txq, tid, &bf);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
|
||||
|
@ -1518,30 +1469,27 @@ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
|
|||
} while (1);
|
||||
}
|
||||
|
||||
static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||||
struct ath_atx_tid *tid)
|
||||
static int ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||||
struct ath_atx_tid *tid)
|
||||
{
|
||||
struct ath_buf *bf;
|
||||
struct ath_buf *bf = NULL;
|
||||
struct ieee80211_tx_info *tx_info;
|
||||
struct list_head bf_q;
|
||||
int aggr_len = 0;
|
||||
int aggr_len = 0, ret;
|
||||
bool aggr;
|
||||
|
||||
if (!ath_tid_has_buffered(tid))
|
||||
return false;
|
||||
|
||||
INIT_LIST_HEAD(&bf_q);
|
||||
|
||||
bf = ath_tx_get_tid_subframe(sc, txq, tid);
|
||||
if (!bf)
|
||||
return false;
|
||||
ret = ath_tx_get_tid_subframe(sc, txq, tid, &bf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
|
||||
aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
|
||||
if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) ||
|
||||
(!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
|
||||
__skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
|
||||
return false;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ath_set_rates(tid->an->vif, tid->an->sta, bf);
|
||||
|
@ -1551,7 +1499,7 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|||
ath_tx_form_burst(sc, txq, tid, &bf_q, bf);
|
||||
|
||||
if (list_empty(&bf_q))
|
||||
return false;
|
||||
return -EAGAIN;
|
||||
|
||||
if (tid->clear_ps_filter || tid->an->no_ps_filter) {
|
||||
tid->clear_ps_filter = false;
|
||||
|
@ -1560,7 +1508,7 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|||
|
||||
ath_tx_fill_desc(sc, bf, txq, aggr_len);
|
||||
ath_tx_txqaddbuf(sc, txq, &bf_q, false);
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
|
||||
|
@ -1623,28 +1571,16 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
|
|||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_atx_tid *tid;
|
||||
struct ath_txq *txq;
|
||||
int tidno;
|
||||
|
||||
ath_dbg(common, XMIT, "%s called\n", __func__);
|
||||
|
||||
for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
|
||||
tid = ath_node_to_tid(an, tidno);
|
||||
txq = tid->txq;
|
||||
|
||||
ath_txq_lock(sc, txq);
|
||||
|
||||
if (list_empty(&tid->list)) {
|
||||
ath_txq_unlock(sc, txq);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!skb_queue_empty(&tid->retry_q))
|
||||
ieee80211_sta_set_buffered(sta, tid->tidno, true);
|
||||
|
||||
list_del_init(&tid->list);
|
||||
|
||||
ath_txq_unlock(sc, txq);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1663,11 +1599,12 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
|
|||
|
||||
ath_txq_lock(sc, txq);
|
||||
tid->clear_ps_filter = true;
|
||||
if (ath_tid_has_buffered(tid)) {
|
||||
if (!skb_queue_empty(&tid->retry_q)) {
|
||||
ath_tx_queue_tid(sc, tid);
|
||||
ath_txq_schedule(sc, txq);
|
||||
}
|
||||
ath_txq_unlock_complete(sc, txq);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1698,9 +1635,9 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
|
|||
struct ath_txq *txq = sc->tx.uapsdq;
|
||||
struct ieee80211_tx_info *info;
|
||||
struct list_head bf_q;
|
||||
struct ath_buf *bf_tail = NULL, *bf;
|
||||
struct ath_buf *bf_tail = NULL, *bf = NULL;
|
||||
int sent = 0;
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
INIT_LIST_HEAD(&bf_q);
|
||||
for (i = 0; tids && nframes; i++, tids >>= 1) {
|
||||
|
@ -1713,8 +1650,9 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
|
|||
|
||||
ath_txq_lock(sc, tid->txq);
|
||||
while (nframes > 0) {
|
||||
bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid);
|
||||
if (!bf)
|
||||
ret = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq,
|
||||
tid, &bf);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
ath9k_set_moredata(sc, bf, true);
|
||||
|
@ -1980,11 +1918,11 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
|
|||
*/
|
||||
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ieee80211_txq *queue;
|
||||
struct ath_atx_tid *tid;
|
||||
struct list_head *tid_list;
|
||||
struct ath_acq *acq;
|
||||
bool active = AIRTIME_ACTIVE(sc->airtime_flags);
|
||||
int ret;
|
||||
|
||||
if (txq->mac80211_qnum < 0)
|
||||
return;
|
||||
|
@ -1992,58 +1930,26 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
|
|||
if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
|
||||
return;
|
||||
|
||||
ieee80211_txq_schedule_start(hw, txq->mac80211_qnum);
|
||||
spin_lock_bh(&sc->chan_lock);
|
||||
rcu_read_lock();
|
||||
acq = &sc->cur_chan->acq[txq->mac80211_qnum];
|
||||
|
||||
if (sc->cur_chan->stopped)
|
||||
goto out;
|
||||
|
||||
begin:
|
||||
tid_list = &acq->acq_new;
|
||||
if (list_empty(tid_list)) {
|
||||
tid_list = &acq->acq_old;
|
||||
if (list_empty(tid_list))
|
||||
goto out;
|
||||
}
|
||||
tid = list_first_entry(tid_list, struct ath_atx_tid, list);
|
||||
while ((queue = ieee80211_next_txq(hw, txq->mac80211_qnum))) {
|
||||
tid = (struct ath_atx_tid *)queue->drv_priv;
|
||||
|
||||
if (active && tid->an->airtime_deficit[txq->mac80211_qnum] <= 0) {
|
||||
spin_lock_bh(&acq->lock);
|
||||
tid->an->airtime_deficit[txq->mac80211_qnum] += ATH_AIRTIME_QUANTUM;
|
||||
list_move_tail(&tid->list, &acq->acq_old);
|
||||
spin_unlock_bh(&acq->lock);
|
||||
goto begin;
|
||||
}
|
||||
ret = ath_tx_sched_aggr(sc, txq, tid);
|
||||
ath_dbg(common, QUEUE, "ath_tx_sched_aggr returned %d\n", ret);
|
||||
|
||||
if (!ath_tid_has_buffered(tid)) {
|
||||
spin_lock_bh(&acq->lock);
|
||||
if ((tid_list == &acq->acq_new) && !list_empty(&acq->acq_old))
|
||||
list_move_tail(&tid->list, &acq->acq_old);
|
||||
else {
|
||||
list_del_init(&tid->list);
|
||||
}
|
||||
spin_unlock_bh(&acq->lock);
|
||||
goto begin;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If we succeed in scheduling something, immediately restart to make
|
||||
* sure we keep the HW busy.
|
||||
*/
|
||||
if(ath_tx_sched_aggr(sc, txq, tid)) {
|
||||
if (!active) {
|
||||
spin_lock_bh(&acq->lock);
|
||||
list_move_tail(&tid->list, &acq->acq_old);
|
||||
spin_unlock_bh(&acq->lock);
|
||||
}
|
||||
goto begin;
|
||||
ieee80211_return_txq(hw, queue);
|
||||
}
|
||||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
spin_unlock_bh(&sc->chan_lock);
|
||||
ieee80211_txq_schedule_end(hw, txq->mac80211_qnum);
|
||||
}
|
||||
|
||||
void ath_txq_schedule_all(struct ath_softc *sc)
|
||||
|
@ -2887,9 +2793,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
|
|||
struct ath_atx_tid *tid;
|
||||
int tidno, acno;
|
||||
|
||||
for (acno = 0; acno < IEEE80211_NUM_ACS; acno++)
|
||||
an->airtime_deficit[acno] = ATH_AIRTIME_QUANTUM;
|
||||
|
||||
for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
|
||||
tid = ath_node_to_tid(an, tidno);
|
||||
tid->an = an;
|
||||
|
@ -2899,7 +2802,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
|
|||
tid->baw_head = tid->baw_tail = 0;
|
||||
tid->active = false;
|
||||
tid->clear_ps_filter = true;
|
||||
tid->has_queued = false;
|
||||
__skb_queue_head_init(&tid->retry_q);
|
||||
INIT_LIST_HEAD(&tid->list);
|
||||
acno = TID_TO_WME_AC(tidno);
|
||||
|
|
Loading…
Reference in a new issue