LinuxKPI: 802.11: basic implementation of *queue(s)/*txq*
Very basic implementations of ieee80211_{wake,stop}_queue[s], as well as ieee80211_txq_schedule_start(), ieee80211_next_txq(), and ieee80211_schedule_txq(). Various combinations of these are used by different wireless drivers, incl. iwlwifi. Sponsored by: The FreeBSD Foundation (parts of this work) MFC after: 3 days
This commit is contained in:
parent
a839757109
commit
5a9a0d7803
@ -1030,6 +1030,14 @@ struct sk_buff *linuxkpi_ieee80211_probereq_get(struct ieee80211_hw *,
|
||||
void linuxkpi_ieee80211_tx_status(struct ieee80211_hw *, struct sk_buff *);
|
||||
void linuxkpi_ieee80211_tx_status_ext(struct ieee80211_hw *,
|
||||
struct ieee80211_tx_status *);
|
||||
void linuxkpi_ieee80211_stop_queues(struct ieee80211_hw *);
|
||||
void linuxkpi_ieee80211_wake_queues(struct ieee80211_hw *);
|
||||
void linuxkpi_ieee80211_stop_queue(struct ieee80211_hw *, int);
|
||||
void linuxkpi_ieee80211_wake_queue(struct ieee80211_hw *, int);
|
||||
void linuxkpi_ieee80211_txq_schedule_start(struct ieee80211_hw *, uint8_t);
|
||||
struct ieee80211_txq *linuxkpi_ieee80211_next_txq(struct ieee80211_hw *, uint8_t);
|
||||
void linuxkpi_ieee80211_schedule_txq(struct ieee80211_hw *,
|
||||
struct ieee80211_txq *, bool);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
@ -1504,6 +1512,63 @@ ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static inline void
|
||||
ieee80211_stop_queues(struct ieee80211_hw *hw)
|
||||
{
|
||||
linuxkpi_ieee80211_stop_queues(hw);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ieee80211_wake_queues(struct ieee80211_hw *hw)
|
||||
{
|
||||
linuxkpi_ieee80211_wake_queues(hw);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ieee80211_stop_queue(struct ieee80211_hw *hw, int qnum)
|
||||
{
|
||||
linuxkpi_ieee80211_stop_queue(hw, qnum);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ieee80211_wake_queue(struct ieee80211_hw *hw, int qnum)
|
||||
{
|
||||
linuxkpi_ieee80211_wake_queue(hw, qnum);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
|
||||
{
|
||||
linuxkpi_ieee80211_schedule_txq(hw, txq, true);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq,
|
||||
bool withoutpkts)
|
||||
{
|
||||
linuxkpi_ieee80211_schedule_txq(hw, txq, true);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ieee80211_txq_schedule_start(struct ieee80211_hw *hw, uint8_t ac)
|
||||
{
|
||||
linuxkpi_ieee80211_txq_schedule_start(hw, ac);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ieee80211_txq_schedule_end(struct ieee80211_hw *hw, uint8_t ac)
|
||||
{
|
||||
/* DO_NADA; */
|
||||
}
|
||||
|
||||
static inline struct ieee80211_txq *
|
||||
ieee80211_next_txq(struct ieee80211_hw *hw, uint8_t ac)
|
||||
{
|
||||
return (linuxkpi_ieee80211_next_txq(hw, ac));
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static __inline uint8_t
|
||||
ieee80211_get_tid(struct ieee80211_hdr *hdr)
|
||||
{
|
||||
@ -1815,18 +1880,6 @@ ieee80211_tdls_oper_request(struct ieee80211_vif *vif, uint8_t *addr,
|
||||
TODO();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ieee80211_stop_queues(struct ieee80211_hw *hw)
|
||||
{
|
||||
TODO();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ieee80211_wake_queues(struct ieee80211_hw *hw)
|
||||
{
|
||||
TODO();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool state)
|
||||
{
|
||||
@ -2113,18 +2166,6 @@ ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *w)
|
||||
linuxkpi_ieee80211_queue_work(hw, w);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ieee80211_stop_queue(struct ieee80211_hw *hw, uint16_t q)
|
||||
{
|
||||
TODO();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ieee80211_wake_queue(struct ieee80211_hw *hw, uint16_t q)
|
||||
{
|
||||
TODO();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
@ -2255,41 +2296,6 @@ ieee80211_sta_register_airtime(struct ieee80211_sta *sta,
|
||||
TODO();
|
||||
}
|
||||
|
||||
|
||||
static __inline void
|
||||
ieee80211_txq_schedule_start(struct ieee80211_hw *hw, uint8_t ac)
|
||||
{
|
||||
TODO();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ieee80211_txq_schedule_end(struct ieee80211_hw *hw, uint8_t ac)
|
||||
{
|
||||
/* DO_NADA; */
|
||||
}
|
||||
|
||||
static __inline struct ieee80211_txq *
|
||||
ieee80211_next_txq(struct ieee80211_hw *hw, uint8_t ac)
|
||||
{
|
||||
|
||||
TODO();
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
|
||||
{
|
||||
TODO();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq,
|
||||
bool withoutpkts)
|
||||
{
|
||||
TODO();
|
||||
}
|
||||
|
||||
|
||||
static __inline void
|
||||
ieee80211_beacon_set_cntdwn(struct ieee80211_vif *vif, u8 counter)
|
||||
{
|
||||
|
@ -76,6 +76,12 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
static MALLOC_DEFINE(M_LKPI80211, "lkpi80211", "LinuxKPI 80211 compat");
|
||||
|
||||
/* XXX-BZ really want this and others in queue.h */
|
||||
#define TAILQ_ELEM_INIT(elm, field) do { \
|
||||
(elm)->field.tqe_next = NULL; \
|
||||
(elm)->field.tqe_prev = NULL; \
|
||||
} while (0)
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* Keep public for as long as header files are using it too. */
|
||||
@ -4620,6 +4626,220 @@ linuxkpi_ieee80211_beacon_loss(struct ieee80211_vif *vif)
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void
|
||||
linuxkpi_ieee80211_stop_queue(struct ieee80211_hw *hw, int qnum)
|
||||
{
|
||||
struct lkpi_hw *lhw;
|
||||
struct lkpi_vif *lvif;
|
||||
struct ieee80211_vif *vif;
|
||||
int ac_count, ac;
|
||||
|
||||
KASSERT(qnum < hw->queues, ("%s: qnum %d >= hw->queues %d, hw %p\n",
|
||||
__func__, qnum, hw->queues, hw));
|
||||
|
||||
lhw = wiphy_priv(hw->wiphy);
|
||||
|
||||
/* See lkpi_ic_vap_create(). */
|
||||
if (hw->queues >= IEEE80211_NUM_ACS)
|
||||
ac_count = IEEE80211_NUM_ACS;
|
||||
else
|
||||
ac_count = 1;
|
||||
|
||||
LKPI_80211_LHW_LVIF_LOCK(lhw);
|
||||
TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {
|
||||
|
||||
vif = LVIF_TO_VIF(lvif);
|
||||
for (ac = 0; ac < ac_count; ac++) {
|
||||
IMPROVE_TXQ("LOCKING");
|
||||
if (qnum == vif->hw_queue[ac]) {
|
||||
/*
|
||||
* For now log this to better understand
|
||||
* how this is supposed to work.
|
||||
*/
|
||||
if (lvif->hw_queue_stopped[ac])
|
||||
ic_printf(lhw->ic, "%s:%d: lhw %p hw %p "
|
||||
"lvif %p vif %p ac %d qnum %d already "
|
||||
"stopped\n", __func__, __LINE__,
|
||||
lhw, hw, lvif, vif, ac, qnum);
|
||||
lvif->hw_queue_stopped[ac] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
LKPI_80211_LHW_LVIF_UNLOCK(lhw);
|
||||
}
|
||||
|
||||
void
|
||||
linuxkpi_ieee80211_stop_queues(struct ieee80211_hw *hw)
|
||||
{
|
||||
int i;
|
||||
|
||||
IMPROVE_TXQ("Locking; do we need further info?");
|
||||
for (i = 0; i < hw->queues; i++)
|
||||
linuxkpi_ieee80211_stop_queue(hw, i);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
lkpi_ieee80211_wake_queues(struct ieee80211_hw *hw, int hwq)
|
||||
{
|
||||
struct lkpi_hw *lhw;
|
||||
struct lkpi_vif *lvif;
|
||||
struct lkpi_sta *lsta;
|
||||
int ac_count, ac, tid;
|
||||
|
||||
/* See lkpi_ic_vap_create(). */
|
||||
if (hw->queues >= IEEE80211_NUM_ACS)
|
||||
ac_count = IEEE80211_NUM_ACS;
|
||||
else
|
||||
ac_count = 1;
|
||||
|
||||
lhw = wiphy_priv(hw->wiphy);
|
||||
|
||||
IMPROVE_TXQ("Locking");
|
||||
LKPI_80211_LHW_LVIF_LOCK(lhw);
|
||||
TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
vif = LVIF_TO_VIF(lvif);
|
||||
for (ac = 0; ac < ac_count; ac++) {
|
||||
|
||||
if (hwq == vif->hw_queue[ac]) {
|
||||
|
||||
/* XXX-BZ what about software scan? */
|
||||
|
||||
/*
|
||||
* For now log this to better understand
|
||||
* how this is supposed to work.
|
||||
*/
|
||||
if (!lvif->hw_queue_stopped[ac])
|
||||
ic_printf(lhw->ic, "%s:%d: lhw %p hw %p "
|
||||
"lvif %p vif %p ac %d hw_q not stopped\n",
|
||||
__func__, __LINE__,
|
||||
lhw, hw, lvif, vif, ac);
|
||||
lvif->hw_queue_stopped[ac] = false;
|
||||
|
||||
LKPI_80211_LVIF_LOCK(lvif);
|
||||
TAILQ_FOREACH(lsta, &lvif->lsta_head, lsta_entry) {
|
||||
struct ieee80211_sta *sta;
|
||||
|
||||
sta = LSTA_TO_STA(lsta);
|
||||
for (tid = 0; tid < nitems(sta->txq); tid++) {
|
||||
struct lkpi_txq *ltxq;
|
||||
|
||||
if (sta->txq[tid] == NULL)
|
||||
continue;
|
||||
|
||||
if (sta->txq[tid]->ac != ac)
|
||||
continue;
|
||||
|
||||
ltxq = TXQ_TO_LTXQ(sta->txq[tid]);
|
||||
if (!ltxq->stopped)
|
||||
continue;
|
||||
|
||||
ltxq->stopped = false;
|
||||
|
||||
/* XXX-BZ see when this explodes with all the locking. taskq? */
|
||||
lkpi_80211_mo_wake_tx_queue(hw, sta->txq[tid]);
|
||||
}
|
||||
}
|
||||
LKPI_80211_LVIF_UNLOCK(lvif);
|
||||
}
|
||||
}
|
||||
}
|
||||
LKPI_80211_LHW_LVIF_UNLOCK(lhw);
|
||||
}
|
||||
|
||||
void
|
||||
linuxkpi_ieee80211_wake_queues(struct ieee80211_hw *hw)
|
||||
{
|
||||
int i;
|
||||
|
||||
IMPROVE_TXQ("Is this all/enough here?");
|
||||
for (i = 0; i < hw->queues; i++)
|
||||
lkpi_ieee80211_wake_queues(hw, i);
|
||||
}
|
||||
|
||||
void
|
||||
linuxkpi_ieee80211_wake_queue(struct ieee80211_hw *hw, int qnum)
|
||||
{
|
||||
|
||||
KASSERT(qnum < hw->queues, ("%s: qnum %d >= hw->queues %d, hw %p\n",
|
||||
__func__, qnum, hw->queues, hw));
|
||||
|
||||
lkpi_ieee80211_wake_queues(hw, qnum);
|
||||
}
|
||||
|
||||
/* This is just hardware queues. */
|
||||
void
|
||||
linuxkpi_ieee80211_txq_schedule_start(struct ieee80211_hw *hw, uint8_t ac)
|
||||
{
|
||||
struct lkpi_hw *lhw;
|
||||
|
||||
lhw = HW_TO_LHW(hw);
|
||||
|
||||
IMPROVE_TXQ("Are there reasons why we wouldn't schedule?");
|
||||
IMPROVE_TXQ("LOCKING");
|
||||
if (++lhw->txq_generation[ac] == 0)
|
||||
lhw->txq_generation[ac]++;
|
||||
}
|
||||
|
||||
struct ieee80211_txq *
|
||||
linuxkpi_ieee80211_next_txq(struct ieee80211_hw *hw, uint8_t ac)
|
||||
{
|
||||
struct lkpi_hw *lhw;
|
||||
struct ieee80211_txq *txq;
|
||||
struct lkpi_txq *ltxq;
|
||||
|
||||
lhw = HW_TO_LHW(hw);
|
||||
txq = NULL;
|
||||
|
||||
IMPROVE_TXQ("LOCKING");
|
||||
|
||||
/* Check that we are scheduled. */
|
||||
if (lhw->txq_generation[ac] == 0)
|
||||
goto out;
|
||||
|
||||
ltxq = TAILQ_FIRST(&lhw->scheduled_txqs[ac]);
|
||||
if (ltxq == NULL)
|
||||
goto out;
|
||||
if (ltxq->txq_generation == lhw->txq_generation[ac])
|
||||
goto out;
|
||||
|
||||
ltxq->txq_generation = lhw->txq_generation[ac];
|
||||
TAILQ_REMOVE(&lhw->scheduled_txqs[ac], ltxq, txq_entry);
|
||||
txq = <xq->txq;
|
||||
TAILQ_ELEM_INIT(ltxq, txq_entry);
|
||||
|
||||
out:
|
||||
return (txq);
|
||||
}
|
||||
|
||||
void linuxkpi_ieee80211_schedule_txq(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq, bool withoutpkts)
|
||||
{
|
||||
struct lkpi_hw *lhw;
|
||||
struct lkpi_txq *ltxq;
|
||||
|
||||
ltxq = TXQ_TO_LTXQ(txq);
|
||||
|
||||
IMPROVE_TXQ("LOCKING");
|
||||
|
||||
/* Only schedule if work to do or asked to anyway. */
|
||||
if (!withoutpkts && skb_queue_empty(<xq->skbq))
|
||||
goto out;
|
||||
|
||||
/* Make sure we do not double-schedule. */
|
||||
if (ltxq->txq_entry.tqe_next != NULL)
|
||||
goto out;
|
||||
|
||||
lhw = HW_TO_LHW(hw);
|
||||
TAILQ_INSERT_TAIL(&lhw->scheduled_txqs[txq->ac], ltxq, txq_entry);
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
struct lkpi_cfg80211_bss {
|
||||
u_int refcnt;
|
||||
struct cfg80211_bss bss;
|
||||
|
@ -50,6 +50,7 @@
|
||||
#ifndef D80211_IMPROVE
|
||||
#define D80211_IMPROVE 0x2
|
||||
#endif
|
||||
#define D80211_IMPROVE_TXQ 0x4
|
||||
#define D80211_TRACE 0x10
|
||||
#define D80211_TRACEOK 0x20
|
||||
#define D80211_TRACE_TX 0x100
|
||||
@ -62,6 +63,10 @@
|
||||
#define D80211_TRACE_STA 0x10000
|
||||
#define D80211_TRACE_MO 0x100000
|
||||
|
||||
#define IMPROVE_TXQ(...) \
|
||||
if (linuxkpi_debug_80211 & D80211_IMPROVE_TXQ) \
|
||||
printf("%s:%d: XXX LKPI80211 IMPROVE_TXQ\n", __func__, __LINE__)
|
||||
|
||||
struct lkpi_radiotap_tx_hdr {
|
||||
struct ieee80211_radiotap_header wt_ihdr;
|
||||
uint8_t wt_flags;
|
||||
@ -93,7 +98,11 @@ struct lkpi_radiotap_rx_hdr {
|
||||
(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE))
|
||||
|
||||
struct lkpi_txq {
|
||||
TAILQ_ENTRY(lkpi_txq) txq_entry;
|
||||
|
||||
bool seen_dequeue;
|
||||
bool stopped;
|
||||
uint32_t txq_generation;
|
||||
struct sk_buff_head skbq;
|
||||
|
||||
/* Must be last! */
|
||||
@ -139,6 +148,8 @@ struct lkpi_vif {
|
||||
TAILQ_HEAD(, lkpi_sta) lsta_head;
|
||||
bool added_to_drv; /* Driver knows; i.e. we called add_interface(). */
|
||||
|
||||
bool hw_queue_stopped[IEEE80211_NUM_ACS];
|
||||
|
||||
/* Must be last! */
|
||||
struct ieee80211_vif vif __aligned(CACHE_LINE_SIZE);
|
||||
};
|
||||
@ -164,6 +175,9 @@ struct lkpi_hw { /* name it mac80211_sc? */
|
||||
|
||||
struct mtx mtx;
|
||||
|
||||
uint32_t txq_generation[IEEE80211_NUM_ACS];
|
||||
TAILQ_HEAD(, lkpi_txq) scheduled_txqs[IEEE80211_NUM_ACS];
|
||||
|
||||
/* Scan functions we overload to handle depending on scan mode. */
|
||||
void (*ic_scan_curchan)(struct ieee80211_scan_state *,
|
||||
unsigned long);
|
||||
|
Loading…
Reference in New Issue
Block a user