mt76: avoid queue/status spinlocks while passing tx status to mac80211
Subsystems (2)
Felix Fietkau
maintainerPATCH v2 1/7 mt76: avoid queue/status spinlocks while passing tx status to mac80211
There is some code in the mac80211 tx status processing code that could potentially call back into the tx codepath.
To avoid deadlocks, make sure that no tx related spinlocks are taken during the ieee80211_tx_status call.
--- drivers/net/wireless/mediatek/mt76/dma.c | 11 ++-- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76.h | 30 ++++------ .../net/wireless/mediatek/mt76/mt76x02_mac.c | 11 ++-- .../net/wireless/mediatek/mt76/mt76x02_util.c | 2 +- drivers/net/wireless/mediatek/mt76/tx.c | 58 ++++++++++++++++--- 6 files changed, 76 insertions(+), 38 deletions(-)
drivers/net/wireless/mediatek/mt76/dma.c +7 -4
@@ -157,17 +157,20 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)if (entry.schedule) q->swq_queued--; -if (entry.skb) + q->tail = (q->tail +1 ) % q->ndesc; + q->queued--; + +if (entry.skb) { +spin_unlock_bh (&q->lock); dev->drv->tx_complete_skb (dev, q, &entry, flush); +spin_lock_bh (&q->lock); + }if (entry.txwi) {mt76_put_txwi (dev, entry.txwi); wake = true; } - q->tail = (q->tail +1 ) % q->ndesc; - q->queued--; -if (!flush && q->tail == last) last =ioread32 (&q->regs->dma_idx); }
drivers/net/wireless/mediatek/mt76/mac80211.c +1 -1
@@ -359,7 +359,7 @@ void mt76_unregister_device(struct mt76_dev *dev) {struct ieee80211_hw *hw = dev->hw; -mt76_tx_status_flush (dev,NULL ); +mt76_tx_status_check (dev,NULL , true);ieee80211_unregister_hw (hw);mt76_tx_free (dev); }
drivers/net/wireless/mediatek/mt76/mt76.h +12 -18
@@ -648,28 +648,22 @@ void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid);void mt76_wcid_key_setup (struct mt76_dev *dev,struct mt76_wcid *wcid,struct ieee80211_key_conf *key); + +void mt76_tx_status_lock(struct mt76_dev *dev, struct sk_buff_head *list) + __acquires(&dev->status_list.lock); +void mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list) + __releases(&dev->status_list.lock); +int mt76_tx_status_skb_add (struct mt76_dev *dev,struct mt76_wcid *wcid,struct sk_buff *skb);struct sk_buff *mt76_tx_status_skb_get (struct mt76_dev *dev, -struct mt76_wcid *wcid,int pktid); -void mt76_tx_status_skb_done (struct mt76_dev *dev,struct sk_buff *skb); +struct mt76_wcid *wcid,int pktid, +struct sk_buff_head *list); +void mt76_tx_status_skb_done (struct mt76_dev *dev,struct sk_buff *skb, +struct sk_buff_head *list);void mt76_tx_complete_skb (struct mt76_dev *dev,struct sk_buff *skb); - -static inline void -mt76_tx_status_check (struct mt76_dev *dev) -{ -spin_lock_bh (&dev->status_list.lock); -mt76_tx_status_skb_get (dev,NULL ,0 ); -spin_unlock_bh (&dev->status_list.lock); -} - -static inline void -mt76_tx_status_flush (struct mt76_dev *dev,struct mt76_wcid *wcid) -{ -spin_lock_bh (&dev->status_list.lock); -mt76_tx_status_skb_get (dev, wcid,-1 ); -spin_unlock_bh (&dev->status_list.lock); -} +void mt76_tx_status_check (struct mt76_dev *dev,struct mt76_wcid *wcid, +bool flush);struct ieee80211_sta *mt76_rx_convert (struct sk_buff *skb);
drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +6 -5
@@ -438,12 +438,13 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,struct mt76_wcid *wcid =NULL ;struct mt76x02_sta *msta =NULL ;struct mt76_dev *mdev = &dev->mt76; +struct sk_buff_head list;if (stat->pktid ==MT_PACKET_ID_NO_ACK )return ;rcu_read_lock (); -spin_lock_bh (&mdev->status_list.lock); +mt76_tx_status_lock (mdev, &list);if (stat->wcid <ARRAY_SIZE (dev->mt76.wcid)) wcid =rcu_dereference (dev->mt76.wcid[stat->wcid]);
@@ -459,7 +460,7 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,if (wcid) {if (stat->pktid) status.skb =mt76_tx_status_skb_get (mdev, wcid, - stat->pktid); + stat->pktid, &list);if (status.skb) status.info =IEEE80211_SKB_CB (status.skb); }
@@ -490,12 +491,12 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev, }if (status.skb) -mt76_tx_status_skb_done (mdev, status.skb); +mt76_tx_status_skb_done (mdev, status.skb, &list);else ieee80211_tx_status_ext (mt76_hw (dev), &status); out: -spin_unlock_bh (&mdev->status_list.lock); +mt76_tx_status_unlock (mdev, &list);rcu_read_unlock (); }
@@ -818,7 +819,7 @@ void mt76x02_mac_work(struct work_struct *work)if (!dev->beacon_mask)mt76x02_check_mac_err (dev); -mt76_tx_status_check (&dev->mt76); +mt76_tx_status_check (&dev->mt76,NULL , false);ieee80211_queue_delayed_work (mt76_hw (dev), &dev->mac_work,MT_CALIBRATE_INTERVAL );
drivers/net/wireless/mediatek/mt76/mt76x02_util.c +1 -1
@@ -217,7 +217,7 @@ int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,int i;mutex_lock (&dev->mt76.mutex); -mt76_tx_status_flush (&dev->mt76, &msta->wcid); +mt76_tx_status_check (&dev->mt76, &msta->wcid, true);rcu_assign_pointer (dev->mt76.wcid[idx],NULL );for (i =0 ; i <ARRAY_SIZE (sta->txq); i++)mt76_txq_remove (&dev->mt76, sta->txq[i]);
drivers/net/wireless/mediatek/mt76/tx.c +49 -9
100 lines not on this page · raw message
Signature · 1 line
2.17.0
Felix Fietkau
maintainerPATCH v2 2/7 mt76: do not wake tx queues during flush
While the queue is being cleaned up, the stack must not attempt to add any extra packets
--- drivers/net/wireless/mediatek/mt76/dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/dma.c +1 -1
@@ -168,7 +168,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)if (entry.txwi) {mt76_put_txwi (dev, entry.txwi); - wake = true; + wake = !flush; }if (!flush && q->tail == last)
Signature · 1 line
2.17.0
Felix Fietkau
maintainerPATCH v2 3/7 mt76: fix race condition in station removal
In reply to Felix FietkauIf there are still pending packets in the tx queue when removing a station, it could possibly lead to a call to further attempts to pull packets from the mac80211 tx queue after it has already been removed from the scheduling list.
Prevent this from happening by calling synchronize_rcu after deleting the wcid pointer before further cleaning up the tx queues.
To be extra careful, ensure that mtxq->list is always initialized properly.
---
v2: keep the call to mt76x02_mac_wcid_setup in place
drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 4 +++- drivers/net/wireless/mediatek/mt76/tx.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-)
drivers/net/wireless/mediatek/mt76/mt76x02_util.c +3 -1
@@ -216,9 +216,11 @@ int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,int idx = msta->wcid.idx;int i; +rcu_assign_pointer (dev->mt76.wcid[idx],NULL ); +synchronize_rcu (); +mutex_lock (&dev->mt76.mutex);mt76_tx_status_check (&dev->mt76, &msta->wcid, true); -rcu_assign_pointer (dev->mt76.wcid[idx],NULL );for (i =0 ; i <ARRAY_SIZE (sta->txq); i++)mt76_txq_remove (&dev->mt76, sta->txq[i]);mt76x02_mac_wcid_set_drop (dev, idx, true);
drivers/net/wireless/mediatek/mt76/tx.c +1 -1
@@ -590,7 +590,7 @@ void mt76_txq_remove(struct mt76_dev *dev, struct ieee80211_txq *txq)spin_lock_bh (&hwq->lock);if (!list_empty (&mtxq->list)) -list_del (&mtxq->list); +list_del_init (&mtxq->list);spin_unlock_bh (&hwq->lock);while ((skb =skb_dequeue (&mtxq->retry_q)) !=NULL )
Signature · 1 line
2.17.0
Felix Fietkau
maintainerPATCH v2 4/7 mt76: add mt76_sta_remove helper
In reply to Felix FietkauThis allows station removal code to be used by mt7603 later
--- drivers/net/wireless/mediatek/mt76/mac80211.c | 19 +++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++ .../net/wireless/mediatek/mt76/mt76x02_util.c | 12 +++--------- 3 files changed, 24 insertions(+), 9 deletions(-)
drivers/net/wireless/mediatek/mt76/mac80211.c +19 -0
@@ -630,3 +630,22 @@ void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,mt76_rx_complete (dev, &frames, napi); }EXPORT_SYMBOL_GPL (mt76_rx_poll_complete); + +void mt76_sta_remove (struct mt76_dev *dev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta) +{ +struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; +int idx = wcid->idx; +int i; + +rcu_assign_pointer (dev->wcid[idx],NULL ); +synchronize_rcu (); + +mutex_lock (&dev->mutex); +mt76_tx_status_check (dev, wcid, true); +for (i =0 ; i <ARRAY_SIZE (sta->txq); i++) +mt76_txq_remove (dev, sta->txq[i]); +mt76_wcid_free (dev->wcid_mask, idx); +mutex_unlock (&dev->mutex); +} +EXPORT_SYMBOL_GPL (mt76_sta_remove);
drivers/net/wireless/mediatek/mt76/mt76.h +2 -0
@@ -664,6 +664,8 @@ void mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb,void mt76_tx_complete_skb (struct mt76_dev *dev,struct sk_buff *skb);void mt76_tx_status_check (struct mt76_dev *dev,struct mt76_wcid *wcid,bool flush); +void mt76_sta_remove (struct mt76_dev *dev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta);struct ieee80211_sta *mt76_rx_convert (struct sk_buff *skb);
drivers/net/wireless/mediatek/mt76/mt76x02_util.c +3 -9
@@ -212,19 +212,13 @@ int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) {struct mt76x02_dev *dev = hw->priv; -struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; -int idx = msta->wcid.idx; -int i; +struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; +int idx = wcid->idx; -rcu_assign_pointer (dev->mt76.wcid[idx],NULL ); -synchronize_rcu (); +mt76_sta_remove (&dev->mt76, vif, sta);mutex_lock (&dev->mt76.mutex); -mt76_tx_status_check (&dev->mt76, &msta->wcid, true); -for (i =0 ; i <ARRAY_SIZE (sta->txq); i++) -mt76_txq_remove (&dev->mt76, sta->txq[i]);mt76x02_mac_wcid_set_drop (dev, idx, true); -mt76_wcid_free (dev->mt76.wcid_mask, idx);mt76x02_mac_wcid_setup (dev, idx,0 ,NULL );mutex_unlock (&dev->mt76.mutex);
Signature · 1 line
2.17.0
Felix Fietkau
maintainerPATCH v2 5/7 mt76: mt76x02: make group_wcid the first member in struct mt76x02_vif
In reply to Felix FietkauAllows mt76 core to cast vif->drv_priv to struct mt76_wcid
--- drivers/net/wireless/mediatek/mt76/mt76x02_mac.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +1 -2
@@ -37,9 +37,8 @@ struct mt76x02_tx_status {#define MT_MAX_VIFS 8struct mt76x02_vif { +struct mt76_wcid group_wcid;/* must be first */ u8 idx; - -struct mt76_wcid group_wcid; };DECLARE_EWMA (signal,10 ,8 );
Signature · 1 line
2.17.0
Felix Fietkau
maintainerPATCH v2 6/7 mt76: mt76x02: remove mt76x02_txq_init
In reply to Felix FietkauOpen-coding it simplifies the code
--- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 23 ------------------- .../net/wireless/mediatek/mt76/mt76x02_mac.h | 2 -- .../net/wireless/mediatek/mt76/mt76x02_util.c | 15 +++++++++--- 3 files changed, 12 insertions(+), 28 deletions(-)
drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +0 -23
@@ -126,29 +126,6 @@ void mt76x02_mac_wcid_set_drop(struct mt76x02_dev *dev, u8 idx, bool drop)mt76_wr (dev,MT_WCID_DROP (idx), (val & ~bit) | (bit * drop)); } -void mt76x02_txq_init (struct mt76x02_dev *dev,struct ieee80211_txq *txq) -{ -struct mt76_txq *mtxq; - -if (!txq) -return ; - - mtxq = (struct mt76_txq *) txq->drv_priv; -if (txq->sta) { -struct mt76x02_sta *sta; - - sta = (struct mt76x02_sta *) txq->sta->drv_priv; - mtxq->wcid = &sta->wcid; - }else { -struct mt76x02_vif *mvif; - - mvif = (struct mt76x02_vif *) txq->vif->drv_priv; - mtxq->wcid = &mvif->group_wcid; - } - -mt76_txq_init (&dev->mt76, txq); -} -static __le16 mt76x02_mac_tx_rate_val (struct mt76x02_dev *dev,const struct ieee80211_tx_rate *rate,u8 *nss_val)
drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +0 -2
@@ -178,8 +178,6 @@ static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev)return false; } -void mt76x02_txq_init (struct mt76x02_dev *dev,struct ieee80211_txq *txq); -void mt76x02_mac_set_short_preamble (struct mt76x02_dev *dev,bool enable);int mt76x02_mac_shared_key_setup (struct mt76x02_dev *dev,u8 vif_idx,u8 key_idx,struct ieee80211_key_conf *key);
drivers/net/wireless/mediatek/mt76/mt76x02_util.c +12 -3
@@ -191,8 +191,13 @@ int mt76x02_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, msta->wcid.hw_key_idx =-1 ;mt76x02_mac_wcid_setup (dev, idx, mvif->idx, sta->addr);mt76x02_mac_wcid_set_drop (dev, idx, false); -for (i =0 ; i <ARRAY_SIZE (sta->txq); i++) -mt76x02_txq_init (dev, sta->txq[i]); +for (i =0 ; i <ARRAY_SIZE (sta->txq); i++) { +struct mt76_txq *mtxq; + + mtxq = (struct mt76_txq *) sta->txq[i]->drv_priv; + mtxq->wcid = &msta->wcid; +mt76_txq_init (&dev->mt76, sta->txq[i]); + }if (vif->type ==NL80211_IFTYPE_AP )set_bit (MT_WCID_FLAG_CHECK_PS , &msta->wcid.flags);
@@ -230,11 +235,15 @@ void mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif, unsigned int idx) {struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; +struct mt76_txq *mtxq; mvif->idx = idx; mvif->group_wcid.idx =MT_VIF_WCID (idx); mvif->group_wcid.hw_key_idx =-1 ; -mt76x02_txq_init (dev, vif->txq); + mtxq = (struct mt76_txq *) vif->txq->drv_priv; + mtxq->wcid = &mvif->group_wcid; + +mt76_txq_init (&dev->mt76, vif->txq); }EXPORT_SYMBOL_GPL (mt76x02_vif_init);
Signature · 1 line
2.17.0
Re: [PATCH v2 6/7] mt76: mt76x02: remove mt76x02_txq_init
Quoted 9 lines
Open-coding it simplifies the code
Signed-off-by Felix Fietkau <[email protected]>--- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 23 ------------------- .../net/wireless/mediatek/mt76/mt76x02_mac.h | 2 -- .../net/wireless/mediatek/mt76/mt76x02_util.c | 15 +++++++++--- 3 files changed, 12 insertions(+), 28 deletions(-)
[...]
drivers/net/wireless/mediatek/mt76/mt76x02_util.c int mt76x02_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · line 197
Quoted 10 lines
drivers/net/wireless/mediatek/mt76/mt76x02_util.c +4
-2@@ -191,8 +191,13 @@ int mt76x02_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, msta->wcid.hw_key_idx =-1 ;mt76x02_mac_wcid_setup (dev, idx, mvif->idx, sta->addr);mt76x02_mac_wcid_set_drop (dev, idx, false); -for (i =0 ; i <ARRAY_SIZE (sta->txq); i++) -mt76x02_txq_init (dev, sta->txq[i]); +for (i =0 ; i <ARRAY_SIZE (sta->txq); i++) { +struct mt76_txq *mtxq; + + mtxq = (struct mt76_txq *) sta->txq[i]->drv_priv;
I think sta->txq[i] can be NULL here
Quoted 26 lines
drivers/net/wireless/mediatek/mt76/mt76x02_util.c +8
-2+ mtxq->wcid = &msta->wcid; +mt76_txq_init (&dev->mt76, sta->txq[i]); + }if (vif->type ==NL80211_IFTYPE_AP )set_bit (MT_WCID_FLAG_CHECK_PS , &msta->wcid.flags);@@ -230,11 +235,15 @@ void mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif, unsigned int idx) {struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; +struct mt76_txq *mtxq; mvif->idx = idx; mvif->group_wcid.idx =MT_VIF_WCID (idx); mvif->group_wcid.hw_key_idx =-1 ; -mt76x02_txq_init (dev, vif->txq); + mtxq = (struct mt76_txq *) vif->txq->drv_priv; + mtxq->wcid = &mvif->group_wcid; + +mt76_txq_init (&dev->mt76, vif->txq); }EXPORT_SYMBOL_GPL (mt76x02_vif_init); --2.17.0
Signature · 3 lines
UNIX is Sexy: who | grep -i blonde | talk; cd ~; wine; talk; touch; unzip; touch; strip; gasp; finger; gasp; mount; fsck; more; yes; gasp; umount; make clean; sleep
Felix Fietkau
maintainerPATCH v2 7/7 mt76: replace sta_add/remove ops with common sta_state function
In reply to Felix FietkauAllows adding unassociated stations from mac80211
--- drivers/net/wireless/mediatek/mt76/mac80211.c | 61 ++++++++++++++++++- drivers/net/wireless/mediatek/mt76/mt76.h | 12 +++- .../net/wireless/mediatek/mt76/mt76x0/pci.c | 5 +- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 5 +- drivers/net/wireless/mediatek/mt76/mt76x02.h | 8 +-- .../net/wireless/mediatek/mt76/mt76x02_util.c | 40 +++--------- .../wireless/mediatek/mt76/mt76x2/pci_init.c | 2 + .../wireless/mediatek/mt76/mt76x2/pci_main.c | 3 +- .../wireless/mediatek/mt76/mt76x2/usb_init.c | 2 + .../wireless/mediatek/mt76/mt76x2/usb_main.c | 3 +- 10 files changed, 92 insertions(+), 49 deletions(-)
drivers/net/wireless/mediatek/mt76/mac80211.c +58 -3
@@ -631,8 +631,40 @@ void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, }EXPORT_SYMBOL_GPL (mt76_rx_poll_complete); -void mt76_sta_remove (struct mt76_dev *dev,struct ieee80211_vif *vif, -struct ieee80211_sta *sta) +static int +mt76_sta_add (struct mt76_dev *dev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta) +{ +struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; +int ret; +int i; + +mutex_lock (&dev->mutex); + + ret = dev->drv->sta_add (dev, vif, sta); +if (ret) + goto out; + +for (i =0 ; i <ARRAY_SIZE (sta->txq); i++) { +struct mt76_txq *mtxq; + + mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; + mtxq->wcid = wcid; + +mt76_txq_init (dev, sta->txq[i]); + } + +rcu_assign_pointer (dev->wcid[wcid->idx], wcid); + +out: +mutex_unlock (&dev->mutex); + +return ret; +} + +static void +mt76_sta_remove (struct mt76_dev *dev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta) {struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;int idx = wcid->idx;
@@ -642,10 +674,33 @@ void mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,synchronize_rcu ();mutex_lock (&dev->mutex); + +if (dev->drv->sta_remove) + dev->drv->sta_remove (dev, vif, sta); +mt76_tx_status_check (dev, wcid, true);for (i =0 ; i <ARRAY_SIZE (sta->txq); i++)mt76_txq_remove (dev, sta->txq[i]);mt76_wcid_free (dev->wcid_mask, idx); +mutex_unlock (&dev->mutex); } -EXPORT_SYMBOL_GPL (mt76_sta_remove); + +int mt76_sta_state (struct ieee80211_hw *hw,struct ieee80211_vif *vif, +struct ieee80211_sta *sta, +enum ieee80211_sta_state old_state, +enum ieee80211_sta_state new_state) +{ +struct mt76_dev *dev = hw->priv; + +if (old_state ==IEEE80211_STA_NOTEXIST && + new_state ==IEEE80211_STA_NONE ) +return mt76_sta_add (dev, vif, sta); + +if (old_state ==IEEE80211_STA_NONE && + new_state ==IEEE80211_STA_NOTEXIST ) +mt76_sta_remove (dev, vif, sta); + +return 0 ; +} +EXPORT_SYMBOL_GPL (mt76_sta_state);
drivers/net/wireless/mediatek/mt76/mt76.h +10 -2
@@ -288,6 +288,12 @@ struct mt76_driver_ops {void (*sta_ps)(struct mt76_dev *dev,struct ieee80211_sta *sta,bool ps); + +int (*sta_add)(struct mt76_dev *dev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta); + +void (*sta_remove)(struct mt76_dev *dev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta); };struct mt76_channel_state {
@@ -664,8 +670,10 @@ void mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb,void mt76_tx_complete_skb (struct mt76_dev *dev,struct sk_buff *skb);void mt76_tx_status_check (struct mt76_dev *dev,struct mt76_wcid *wcid,bool flush); -void mt76_sta_remove (struct mt76_dev *dev,struct ieee80211_vif *vif, -struct ieee80211_sta *sta); +int mt76_sta_state (struct ieee80211_hw *hw,struct ieee80211_vif *vif, +struct ieee80211_sta *sta, +enum ieee80211_sta_state old_state, +enum ieee80211_sta_state new_state);struct ieee80211_sta *mt76_rx_convert (struct sk_buff *skb);
drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +3 -2
@@ -90,8 +90,7 @@ static const struct ieee80211_ops mt76x0e_ops = { .config = mt76x0_config, .configure_filter = mt76x02_configure_filter, .bss_info_changed = mt76x02_bss_info_changed, - .sta_add = mt76x02_sta_add, - .sta_remove = mt76x02_sta_remove, + .sta_state = mt76_sta_state, .set_key = mt76x02_set_key, .conf_tx = mt76x02_conf_tx, .sw_scan_start = mt76x02_sw_scan,
@@ -162,6 +161,8 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) .rx_skb = mt76x02_queue_rx_skb, .rx_poll_complete = mt76x02_rx_poll_complete, .sta_ps = mt76x02_sta_ps, + .sta_add = mt76x02_sta_add, + .sta_remove = mt76x02_sta_remove, };struct mt76x02_dev *dev;int ret;
drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +3 -2
@@ -146,8 +146,7 @@ static const struct ieee80211_ops mt76x0u_ops = { .config = mt76x0_config, .configure_filter = mt76x02_configure_filter, .bss_info_changed = mt76x02_bss_info_changed, - .sta_add = mt76x02_sta_add, - .sta_remove = mt76x02_sta_remove, + .sta_state = mt76_sta_state, .set_key = mt76x02_set_key, .conf_tx = mt76x02_conf_tx, .sw_scan_start = mt76x02_sw_scan,
@@ -219,6 +218,8 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, .tx_complete_skb = mt76x02u_tx_complete_skb, .tx_status_data = mt76x02_tx_status_data, .rx_skb = mt76x02_queue_rx_skb, + .sta_add = mt76x02_sta_add, + .sta_remove = mt76x02_sta_remove, };struct usb_device *usb_dev =interface_to_usbdev (usb_intf);struct mt76x02_dev *dev;
drivers/net/wireless/mediatek/mt76/mt76x02.h +4 -4
@@ -110,10 +110,10 @@ void mt76x02_init_device(struct mt76x02_dev *dev);void mt76x02_configure_filter (struct ieee80211_hw *hw,unsigned int changed_flags,unsigned int *total_flags,u64 multicast); -int mt76x02_sta_add (struct ieee80211_hw *hw,struct ieee80211_vif *vif, -struct ieee80211_sta *sta); -int mt76x02_sta_remove (struct ieee80211_hw *hw,struct ieee80211_vif *vif, -struct ieee80211_sta *sta); +int mt76x02_sta_add (struct mt76_dev *mdev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta); +void mt76x02_sta_remove (struct mt76_dev *mdev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta);void mt76x02_config_mac_addr_list (struct mt76x02_dev *dev); void mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif,
drivers/net/wireless/mediatek/mt76/mt76x02_util.c +8 -32
@@ -167,23 +167,17 @@ void mt76x02_configure_filter(struct ieee80211_hw *hw, }EXPORT_SYMBOL_GPL (mt76x02_configure_filter); -int mt76x02_sta_add (struct ieee80211_hw *hw,struct ieee80211_vif *vif, +int mt76x02_sta_add (struct mt76_dev *mdev,struct ieee80211_vif *vif,struct ieee80211_sta *sta) { -struct mt76x02_dev *dev = hw->priv; + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; -int ret =0 ;int idx =0 ; -int i; - -mutex_lock (&dev->mt76.mutex); idx =mt76_wcid_alloc (dev->mt76.wcid_mask,ARRAY_SIZE (dev->mt76.wcid)); -if (idx <0 ) { - ret = -ENOSPC ; - goto out; - } +if (idx <0 ) +return -ENOSPC ; msta->vif = mvif; msta->wcid.sta =1 ;
@@ -191,43 +185,25 @@ int mt76x02_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, msta->wcid.hw_key_idx =-1 ;mt76x02_mac_wcid_setup (dev, idx, mvif->idx, sta->addr);mt76x02_mac_wcid_set_drop (dev, idx, false); -for (i =0 ; i <ARRAY_SIZE (sta->txq); i++) { -struct mt76_txq *mtxq; - - mtxq = (struct mt76_txq *) sta->txq[i]->drv_priv; - mtxq->wcid = &msta->wcid; -mt76_txq_init (&dev->mt76, sta->txq[i]); - }if (vif->type ==NL80211_IFTYPE_AP )set_bit (MT_WCID_FLAG_CHECK_PS , &msta->wcid.flags);ewma_signal_init (&msta->rssi); -rcu_assign_pointer (dev->mt76.wcid[idx], &msta->wcid); - -out: -mutex_unlock (&dev->mt76.mutex); - -return ret; +return 0 ; }EXPORT_SYMBOL_GPL (mt76x02_sta_add); -int mt76x02_sta_remove (struct ieee80211_hw *hw,struct ieee80211_vif *vif, -struct ieee80211_sta *sta) +void mt76x02_sta_remove (struct mt76_dev *mdev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta) { -struct mt76x02_dev *dev = hw->priv; + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;int idx = wcid->idx; -mt76_sta_remove (&dev->mt76, vif, sta); - -mutex_lock (&dev->mt76.mutex);mt76x02_mac_wcid_set_drop (dev, idx, true);mt76x02_mac_wcid_setup (dev, idx,0 ,NULL ); -mutex_unlock (&dev->mt76.mutex); - -return 0 ; }EXPORT_SYMBOL_GPL (mt76x02_sta_remove);
drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +2 -0
@@ -323,6 +323,8 @@ struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev) .rx_skb = mt76x02_queue_rx_skb, .rx_poll_complete = mt76x02_rx_poll_complete, .sta_ps = mt76x02_sta_ps, + .sta_add = mt76x02_sta_add, + .sta_remove = mt76x02_sta_remove, };struct mt76x02_dev *dev;struct mt76_dev *mdev;
drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +1 -2
@@ -182,8 +182,7 @@ const struct ieee80211_ops mt76x2_ops = { .config = mt76x2_config, .configure_filter = mt76x02_configure_filter, .bss_info_changed = mt76x02_bss_info_changed, - .sta_add = mt76x02_sta_add, - .sta_remove = mt76x02_sta_remove, + .sta_state = mt76_sta_state, .set_key = mt76x02_set_key, .conf_tx = mt76x02_conf_tx, .sw_scan_start = mt76x02_sw_scan,
drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +2 -0
@@ -141,6 +141,8 @@ struct mt76x02_dev *mt76x2u_alloc_device(struct device *pdev) .tx_complete_skb = mt76x02u_tx_complete_skb, .tx_status_data = mt76x02_tx_status_data, .rx_skb = mt76x02_queue_rx_skb, + .sta_add = mt76x02_sta_add, + .sta_remove = mt76x02_sta_remove, };struct mt76x02_dev *dev;struct mt76_dev *mdev;
drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +1 -2
@@ -127,8 +127,7 @@ const struct ieee80211_ops mt76x2u_ops = { .stop = mt76x2u_stop, .add_interface = mt76x2u_add_interface, .remove_interface = mt76x02_remove_interface, - .sta_add = mt76x02_sta_add, - .sta_remove = mt76x02_sta_remove, + .sta_state = mt76x02_sta_state, .set_key = mt76x02_set_key, .ampdu_action = mt76x02_ampdu_action, .config = mt76x2u_config,
Signature · 1 line
2.17.0
Felix Fietkau
maintainerPATCH v3 7/7 mt76: replace sta_add/remove ops with common sta_state function
Allows adding unassociated stations from mac80211
---
v3: fix typo in mt76x2u
drivers/net/wireless/mediatek/mt76/mac80211.c | 61 ++++++++++++++++++- drivers/net/wireless/mediatek/mt76/mt76.h | 12 +++- .../net/wireless/mediatek/mt76/mt76x0/pci.c | 5 +- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 5 +- drivers/net/wireless/mediatek/mt76/mt76x02.h | 8 +-- .../net/wireless/mediatek/mt76/mt76x02_util.c | 40 +++--------- .../wireless/mediatek/mt76/mt76x2/pci_init.c | 2 + .../wireless/mediatek/mt76/mt76x2/pci_main.c | 3 +- .../wireless/mediatek/mt76/mt76x2/usb_init.c | 2 + .../wireless/mediatek/mt76/mt76x2/usb_main.c | 3 +- 10 files changed, 92 insertions(+), 49 deletions(-)
drivers/net/wireless/mediatek/mt76/mac80211.c +58 -3
@@ -631,8 +631,40 @@ void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, }EXPORT_SYMBOL_GPL (mt76_rx_poll_complete); -void mt76_sta_remove (struct mt76_dev *dev,struct ieee80211_vif *vif, -struct ieee80211_sta *sta) +static int +mt76_sta_add (struct mt76_dev *dev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta) +{ +struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; +int ret; +int i; + +mutex_lock (&dev->mutex); + + ret = dev->drv->sta_add (dev, vif, sta); +if (ret) + goto out; + +for (i =0 ; i <ARRAY_SIZE (sta->txq); i++) { +struct mt76_txq *mtxq; + + mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; + mtxq->wcid = wcid; + +mt76_txq_init (dev, sta->txq[i]); + } + +rcu_assign_pointer (dev->wcid[wcid->idx], wcid); + +out: +mutex_unlock (&dev->mutex); + +return ret; +} + +static void +mt76_sta_remove (struct mt76_dev *dev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta) {struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;int idx = wcid->idx;
@@ -642,10 +674,33 @@ void mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,synchronize_rcu ();mutex_lock (&dev->mutex); + +if (dev->drv->sta_remove) + dev->drv->sta_remove (dev, vif, sta); +mt76_tx_status_check (dev, wcid, true);for (i =0 ; i <ARRAY_SIZE (sta->txq); i++)mt76_txq_remove (dev, sta->txq[i]);mt76_wcid_free (dev->wcid_mask, idx); +mutex_unlock (&dev->mutex); } -EXPORT_SYMBOL_GPL (mt76_sta_remove); + +int mt76_sta_state (struct ieee80211_hw *hw,struct ieee80211_vif *vif, +struct ieee80211_sta *sta, +enum ieee80211_sta_state old_state, +enum ieee80211_sta_state new_state) +{ +struct mt76_dev *dev = hw->priv; + +if (old_state ==IEEE80211_STA_NOTEXIST && + new_state ==IEEE80211_STA_NONE ) +return mt76_sta_add (dev, vif, sta); + +if (old_state ==IEEE80211_STA_NONE && + new_state ==IEEE80211_STA_NOTEXIST ) +mt76_sta_remove (dev, vif, sta); + +return 0 ; +} +EXPORT_SYMBOL_GPL (mt76_sta_state);
drivers/net/wireless/mediatek/mt76/mt76.h +10 -2
@@ -288,6 +288,12 @@ struct mt76_driver_ops {void (*sta_ps)(struct mt76_dev *dev,struct ieee80211_sta *sta,bool ps); + +int (*sta_add)(struct mt76_dev *dev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta); + +void (*sta_remove)(struct mt76_dev *dev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta); };struct mt76_channel_state {
@@ -664,8 +670,10 @@ void mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb,void mt76_tx_complete_skb (struct mt76_dev *dev,struct sk_buff *skb);void mt76_tx_status_check (struct mt76_dev *dev,struct mt76_wcid *wcid,bool flush); -void mt76_sta_remove (struct mt76_dev *dev,struct ieee80211_vif *vif, -struct ieee80211_sta *sta); +int mt76_sta_state (struct ieee80211_hw *hw,struct ieee80211_vif *vif, +struct ieee80211_sta *sta, +enum ieee80211_sta_state old_state, +enum ieee80211_sta_state new_state);struct ieee80211_sta *mt76_rx_convert (struct sk_buff *skb);
drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +3 -2
@@ -90,8 +90,7 @@ static const struct ieee80211_ops mt76x0e_ops = { .config = mt76x0_config, .configure_filter = mt76x02_configure_filter, .bss_info_changed = mt76x02_bss_info_changed, - .sta_add = mt76x02_sta_add, - .sta_remove = mt76x02_sta_remove, + .sta_state = mt76_sta_state, .set_key = mt76x02_set_key, .conf_tx = mt76x02_conf_tx, .sw_scan_start = mt76x02_sw_scan,
@@ -162,6 +161,8 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) .rx_skb = mt76x02_queue_rx_skb, .rx_poll_complete = mt76x02_rx_poll_complete, .sta_ps = mt76x02_sta_ps, + .sta_add = mt76x02_sta_add, + .sta_remove = mt76x02_sta_remove, };struct mt76x02_dev *dev;int ret;
drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +3 -2
@@ -146,8 +146,7 @@ static const struct ieee80211_ops mt76x0u_ops = { .config = mt76x0_config, .configure_filter = mt76x02_configure_filter, .bss_info_changed = mt76x02_bss_info_changed, - .sta_add = mt76x02_sta_add, - .sta_remove = mt76x02_sta_remove, + .sta_state = mt76_sta_state, .set_key = mt76x02_set_key, .conf_tx = mt76x02_conf_tx, .sw_scan_start = mt76x02_sw_scan,
@@ -219,6 +218,8 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, .tx_complete_skb = mt76x02u_tx_complete_skb, .tx_status_data = mt76x02_tx_status_data, .rx_skb = mt76x02_queue_rx_skb, + .sta_add = mt76x02_sta_add, + .sta_remove = mt76x02_sta_remove, };struct usb_device *usb_dev =interface_to_usbdev (usb_intf);struct mt76x02_dev *dev;
drivers/net/wireless/mediatek/mt76/mt76x02.h +4 -4
@@ -110,10 +110,10 @@ void mt76x02_init_device(struct mt76x02_dev *dev);void mt76x02_configure_filter (struct ieee80211_hw *hw,unsigned int changed_flags,unsigned int *total_flags,u64 multicast); -int mt76x02_sta_add (struct ieee80211_hw *hw,struct ieee80211_vif *vif, -struct ieee80211_sta *sta); -int mt76x02_sta_remove (struct ieee80211_hw *hw,struct ieee80211_vif *vif, -struct ieee80211_sta *sta); +int mt76x02_sta_add (struct mt76_dev *mdev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta); +void mt76x02_sta_remove (struct mt76_dev *mdev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta);void mt76x02_config_mac_addr_list (struct mt76x02_dev *dev); void mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif,
drivers/net/wireless/mediatek/mt76/mt76x02_util.c +8 -32
@@ -167,23 +167,17 @@ void mt76x02_configure_filter(struct ieee80211_hw *hw, }EXPORT_SYMBOL_GPL (mt76x02_configure_filter); -int mt76x02_sta_add (struct ieee80211_hw *hw,struct ieee80211_vif *vif, +int mt76x02_sta_add (struct mt76_dev *mdev,struct ieee80211_vif *vif,struct ieee80211_sta *sta) { -struct mt76x02_dev *dev = hw->priv; + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; -int ret =0 ;int idx =0 ; -int i; - -mutex_lock (&dev->mt76.mutex); idx =mt76_wcid_alloc (dev->mt76.wcid_mask,ARRAY_SIZE (dev->mt76.wcid)); -if (idx <0 ) { - ret = -ENOSPC ; - goto out; - } +if (idx <0 ) +return -ENOSPC ; msta->vif = mvif; msta->wcid.sta =1 ;
@@ -191,43 +185,25 @@ int mt76x02_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, msta->wcid.hw_key_idx =-1 ;mt76x02_mac_wcid_setup (dev, idx, mvif->idx, sta->addr);mt76x02_mac_wcid_set_drop (dev, idx, false); -for (i =0 ; i <ARRAY_SIZE (sta->txq); i++) { -struct mt76_txq *mtxq; - - mtxq = (struct mt76_txq *) sta->txq[i]->drv_priv; - mtxq->wcid = &msta->wcid; -mt76_txq_init (&dev->mt76, sta->txq[i]); - }if (vif->type ==NL80211_IFTYPE_AP )set_bit (MT_WCID_FLAG_CHECK_PS , &msta->wcid.flags);ewma_signal_init (&msta->rssi); -rcu_assign_pointer (dev->mt76.wcid[idx], &msta->wcid); - -out: -mutex_unlock (&dev->mt76.mutex); - -return ret; +return 0 ; }EXPORT_SYMBOL_GPL (mt76x02_sta_add); -int mt76x02_sta_remove (struct ieee80211_hw *hw,struct ieee80211_vif *vif, -struct ieee80211_sta *sta) +void mt76x02_sta_remove (struct mt76_dev *mdev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta) { -struct mt76x02_dev *dev = hw->priv; + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;int idx = wcid->idx; -mt76_sta_remove (&dev->mt76, vif, sta); - -mutex_lock (&dev->mt76.mutex);mt76x02_mac_wcid_set_drop (dev, idx, true);mt76x02_mac_wcid_setup (dev, idx,0 ,NULL ); -mutex_unlock (&dev->mt76.mutex); - -return 0 ; }EXPORT_SYMBOL_GPL (mt76x02_sta_remove);
drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +2 -0
@@ -323,6 +323,8 @@ struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev) .rx_skb = mt76x02_queue_rx_skb, .rx_poll_complete = mt76x02_rx_poll_complete, .sta_ps = mt76x02_sta_ps, + .sta_add = mt76x02_sta_add, + .sta_remove = mt76x02_sta_remove, };struct mt76x02_dev *dev;struct mt76_dev *mdev;
drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +1 -2
@@ -182,8 +182,7 @@ const struct ieee80211_ops mt76x2_ops = { .config = mt76x2_config, .configure_filter = mt76x02_configure_filter, .bss_info_changed = mt76x02_bss_info_changed, - .sta_add = mt76x02_sta_add, - .sta_remove = mt76x02_sta_remove, + .sta_state = mt76_sta_state, .set_key = mt76x02_set_key, .conf_tx = mt76x02_conf_tx, .sw_scan_start = mt76x02_sw_scan,
drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +2 -0
@@ -141,6 +141,8 @@ struct mt76x02_dev *mt76x2u_alloc_device(struct device *pdev) .tx_complete_skb = mt76x02u_tx_complete_skb, .tx_status_data = mt76x02_tx_status_data, .rx_skb = mt76x02_queue_rx_skb, + .sta_add = mt76x02_sta_add, + .sta_remove = mt76x02_sta_remove, };struct mt76x02_dev *dev;struct mt76_dev *mdev;
drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +1 -2
@@ -127,8 +127,7 @@ const struct ieee80211_ops mt76x2u_ops = { .stop = mt76x2u_stop, .add_interface = mt76x2u_add_interface, .remove_interface = mt76x02_remove_interface, - .sta_add = mt76x02_sta_add, - .sta_remove = mt76x02_sta_remove, + .sta_state = mt76_sta_state, .set_key = mt76x02_set_key, .ampdu_action = mt76x02_ampdu_action, .config = mt76x2u_config,
Signature · 1 line
2.17.0