mac80211: Add TXQ scheduling API

This adds an API to mac80211 to handle scheduling of TXQs and changes the
interface between driver and mac80211 for TXQ handling as follows:

- The wake_tx_queue callback interface no longer includes the TXQ. Instead,
  the driver is expected to retrieve that from ieee80211_next_txq()

- Two new mac80211 functions are added: ieee80211_next_txq() and
  ieee80211_schedule_txq(). The former returns the next TXQ that should be
  scheduled, and is how the driver gets a queue to pull packets from. The
  latter is called internally by mac80211 to start scheduling a queue, and
  the driver is supposed to call it to re-schedule the TXQ after it is
  finished pulling packets from it (unless the queue emptied).

The ath9k and ath10k drivers are changed to use the new API.

Signed-off-by: Toke Høiland-Jørgensen <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
This commit is contained in:
Toke Høiland-Jørgensen 2017-10-31 12:27:45 +01:00 • committed by Johannes Berg
commit e937b8da5a
15 changed files with 173 additions and 262 deletions

View file

@ -226,9 +226,13 @@ ieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable)
clear_bit(IEEE80211_TXQ_AMPDU, &txqi->flags);
clear_bit(IEEE80211_TXQ_STOP, &txqi->flags);
if (!ieee80211_schedule_txq(&sta->sdata->local->hw, txq))
return;
local_bh_disable();
rcu_read_lock();
drv_wake_tx_queue(sta->sdata->local, txqi);
drv_wake_tx_queue(sta->sdata->local);
rcu_read_unlock();
local_bh_enable();
}

View file

@ -1158,16 +1158,10 @@ drv_tdls_recv_channel_switch(struct ieee80211_local *local,
trace_drv_return_void(local);
}
static inline void drv_wake_tx_queue(struct ieee80211_local *local,
struct txq_info *txq)
static inline void drv_wake_tx_queue(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->txq.vif);
if (!check_sdata_in_driver(sdata))
return;
trace_drv_wake_tx_queue(local, sdata, txq);
local->ops->wake_tx_queue(&local->hw, &txq->txq);
trace_drv_wake_tx_queue(local);
local->ops->wake_tx_queue(&local->hw);
}
static inline int drv_start_nan(struct ieee80211_local *local,

View file

@ -832,6 +832,7 @@ struct txq_info {
struct codel_vars def_cvars;
struct codel_stats cstats;
struct sk_buff_head frags;
struct list_head schedule_order;
unsigned long flags;
/* keep last! */
@ -1122,6 +1123,10 @@ struct ieee80211_local {
struct codel_vars *cvars;
struct codel_params cparams;
/* protects active_txqs and txqi->schedule_order */
spinlock_t active_txq_lock;
struct list_head active_txqs;
const struct ieee80211_ops *ops;
/*

View file

@ -619,6 +619,9 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
spin_lock_init(&local->rx_path_lock);
spin_lock_init(&local->queue_stop_reason_lock);
INIT_LIST_HEAD(&local->active_txqs);
spin_lock_init(&local->active_txq_lock);
INIT_LIST_HEAD(&local->chanctx_list);
mutex_init(&local->chanctx_mtx);

View file

@ -1237,12 +1237,17 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
if (sta->sta.txq[0]) {
bool wake = false;
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
if (!txq_has_queue(sta->sta.txq[i]))
continue;
drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i]));
if (ieee80211_schedule_txq(&local->hw, sta->sta.txq[i]))
wake = true;
}
if (wake)
drv_wake_tx_queue(local);
}
skb_queue_head_init(&pending);

View file

@ -2550,35 +2550,9 @@ TRACE_EVENT(drv_tdls_recv_channel_switch,
)
);
TRACE_EVENT(drv_wake_tx_queue,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct txq_info *txq),
TP_ARGS(local, sdata, txq),
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
STA_ENTRY
__field(u8, ac)
__field(u8, tid)
),
TP_fast_assign(
struct ieee80211_sta *sta = txq->txq.sta;
LOCAL_ASSIGN;
VIF_ASSIGN;
STA_ASSIGN;
__entry->ac = txq->txq.ac;
__entry->tid = txq->txq.tid;
),
TP_printk(
LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " ac:%d tid:%d",
LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ac, __entry->tid
)
DEFINE_EVENT(local_only_evt, drv_wake_tx_queue,
TP_PROTO(struct ieee80211_local *local),
TP_ARGS(local)
);
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */

View file

@ -1439,6 +1439,7 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
codel_vars_init(&txqi->def_cvars);
codel_stats_init(&txqi->cstats);
__skb_queue_head_init(&txqi->frags);
INIT_LIST_HEAD(&txqi->schedule_order);
txqi->txq.vif = &sdata->vif;
@ -1462,6 +1463,7 @@ void ieee80211_txq_purge(struct ieee80211_local *local,
fq_tin_reset(fq, tin, fq_skb_free_func);
ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
list_del_init(&txqi->schedule_order);
}
int ieee80211_txq_setup_flows(struct ieee80211_local *local)
@ -1558,7 +1560,8 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
ieee80211_txq_enqueue(local, txqi, skb);
spin_unlock_bh(&fq->lock);
drv_wake_tx_queue(local, txqi);
if (ieee80211_schedule_txq(&local->hw, &txqi->txq))
drv_wake_tx_queue(local);
return true;
}
@ -3553,6 +3556,50 @@ out:
}
EXPORT_SYMBOL(ieee80211_tx_dequeue);
bool ieee80211_schedule_txq(struct ieee80211_hw *hw,
struct ieee80211_txq *txq)
{
struct ieee80211_local *local = hw_to_local(hw);
struct txq_info *txqi = to_txq_info(txq);
bool ret = false;
spin_lock_bh(&local->active_txq_lock);
if (list_empty(&txqi->schedule_order)) {
list_add_tail(&txqi->schedule_order, &local->active_txqs);
ret = true;
}
spin_unlock_bh(&local->active_txq_lock);
return ret;
}
EXPORT_SYMBOL(ieee80211_schedule_txq);
struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
struct txq_info *txqi = NULL;
spin_lock_bh(&local->active_txq_lock);
if (list_empty(&local->active_txqs))
goto out;
txqi = list_first_entry(&local->active_txqs,
struct txq_info, schedule_order);
list_del_init(&txqi->schedule_order);
out:
spin_unlock_bh(&local->active_txq_lock);
if (!txqi)
return NULL;
return &txqi->txq;
}
EXPORT_SYMBOL(ieee80211_next_txq);
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev,
u32 info_flags)