linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/5] mt76: only stop tx queues on offchannel, not during the entire scan
@ 2018-05-20  5:43 Felix Fietkau
  2018-05-20  5:43 ` [PATCH 2/5] mt76: prevent tx scheduling during channel change Felix Fietkau
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Felix Fietkau @ 2018-05-20  5:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo

During scans, mac80211 frequently switches back to the home channel to
minimize interruption of ongoing traffic. Keep regular tx queues active
during that time.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/mac80211.c | 5 +++++
 drivers/net/wireless/mediatek/mt76/mt76.h     | 1 +
 drivers/net/wireless/mediatek/mt76/tx.c       | 4 ++--
 3 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 915e61733131..d862e5efd094 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -366,6 +366,11 @@ void mt76_set_channel(struct mt76_dev *dev)
 	struct mt76_channel_state *state;
 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
 
+	if (offchannel)
+		set_bit(MT76_OFFCHANNEL, &dev->state);
+	else
+		clear_bit(MT76_OFFCHANNEL, &dev->state);
+
 	if (dev->drv->update_survey)
 		dev->drv->update_survey(dev);
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index a74e6eef51e9..2d098fac6147 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -189,6 +189,7 @@ enum {
 	MT76_STATE_RUNNING,
 	MT76_SCANNING,
 	MT76_RESET,
+	MT76_OFFCHANNEL,
 };
 
 struct mt76_hw_cap {
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 7ecd2d7c5db4..e96956710fb2 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -332,7 +332,7 @@ mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_queue *hwq,
 		if (probe)
 			break;
 
-		if (test_bit(MT76_SCANNING, &dev->state) ||
+		if (test_bit(MT76_OFFCHANNEL, &dev->state) ||
 		    test_bit(MT76_RESET, &dev->state))
 			return -EBUSY;
 
@@ -385,7 +385,7 @@ mt76_txq_schedule_list(struct mt76_dev *dev, struct mt76_queue *hwq)
 		bool empty = false;
 		int cur;
 
-		if (test_bit(MT76_SCANNING, &dev->state) ||
+		if (test_bit(MT76_OFFCHANNEL, &dev->state) ||
 		    test_bit(MT76_RESET, &dev->state))
 			return -EBUSY;
 
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/5] mt76: prevent tx scheduling during channel change
  2018-05-20  5:43 [PATCH 1/5] mt76: only stop tx queues on offchannel, not during the entire scan Felix Fietkau
@ 2018-05-20  5:43 ` Felix Fietkau
  2018-05-20  5:43 ` [PATCH 3/5] mt76: move ieee80211_hw allocation to common core Felix Fietkau
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Felix Fietkau @ 2018-05-20  5:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo

Re-schedule tx afterwards

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/mt76x2_main.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c
index 5c0d1e1260fa..48388f51915a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c
@@ -124,11 +124,14 @@ mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef)
 {
 	int ret;
 
+	cancel_delayed_work_sync(&dev->cal_work);
+
+	set_bit(MT76_RESET, &dev->mt76.state);
+
 	mt76_set_channel(&dev->mt76);
 
 	tasklet_disable(&dev->pre_tbtt_tasklet);
 	tasklet_disable(&dev->dfs_pd.dfs_tasklet);
-	cancel_delayed_work_sync(&dev->cal_work);
 
 	mt76x2_mac_stop(dev, true);
 	ret = mt76x2_phy_set_channel(dev, chandef);
@@ -143,6 +146,10 @@ mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef)
 	tasklet_enable(&dev->dfs_pd.dfs_tasklet);
 	tasklet_enable(&dev->pre_tbtt_tasklet);
 
+	clear_bit(MT76_RESET, &dev->mt76.state);
+
+	mt76_txq_schedule_all(&dev->mt76);
+
 	return ret;
 }
 
@@ -453,7 +460,6 @@ mt76x2_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 
 	clear_bit(MT76_SCANNING, &dev->mt76.state);
 	tasklet_enable(&dev->pre_tbtt_tasklet);
-	mt76_txq_schedule_all(&dev->mt76);
 }
 
 static void
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/5] mt76: move ieee80211_hw allocation to common core
  2018-05-20  5:43 [PATCH 1/5] mt76: only stop tx queues on offchannel, not during the entire scan Felix Fietkau
  2018-05-20  5:43 ` [PATCH 2/5] mt76: prevent tx scheduling during channel change Felix Fietkau
@ 2018-05-20  5:43 ` Felix Fietkau
  2018-05-20  5:43 ` [PATCH 4/5] mt76: wait for pending tx to complete before switching channel Felix Fietkau
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Felix Fietkau @ 2018-05-20  5:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo

Allows it to be shared between different drivers and locks to be
initialized earlier

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/mac80211.c | 22 +++++++++++++++++--
 drivers/net/wireless/mediatek/mt76/mt76.h     |  2 ++
 .../net/wireless/mediatek/mt76/mt76x2_init.c  | 14 +++++-------
 3 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index d862e5efd094..d1044e5b25db 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -268,6 +268,26 @@ mt76_check_sband(struct mt76_dev *dev, int band)
 	dev->hw->wiphy->bands[band] = NULL;
 }
 
+struct mt76_dev *
+mt76_alloc_device(unsigned int size, const struct ieee80211_ops *ops)
+{
+	struct ieee80211_hw *hw;
+	struct mt76_dev *dev;
+
+	hw = ieee80211_alloc_hw(size, ops);
+	if (!hw)
+		return NULL;
+
+	dev = hw->priv;
+	dev->hw = hw;
+	spin_lock_init(&dev->rx_lock);
+	spin_lock_init(&dev->lock);
+	spin_lock_init(&dev->cc_lock);
+
+	return dev;
+}
+EXPORT_SYMBOL_GPL(mt76_alloc_device);
+
 int mt76_register_device(struct mt76_dev *dev, bool vht,
 			 struct ieee80211_rate *rates, int n_rates)
 {
@@ -277,8 +297,6 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
 
 	dev_set_drvdata(dev->dev, dev);
 
-	spin_lock_init(&dev->lock);
-	spin_lock_init(&dev->cc_lock);
 	INIT_LIST_HEAD(&dev->txwi_cache);
 
 	SET_IEEE80211_DEV(hw, dev->dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 2d098fac6147..bb158f867d7c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -377,6 +377,8 @@ mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c)
 	return &msband->chan[idx];
 }
 
+struct mt76_dev *mt76_alloc_device(unsigned int size,
+				   const struct ieee80211_ops *ops);
 int mt76_register_device(struct mt76_dev *dev, bool vht,
 			 struct ieee80211_rate *rates, int n_rates);
 void mt76_unregister_device(struct mt76_dev *dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c
index aeee0b3de136..7096256c7f50 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c
@@ -635,20 +635,18 @@ struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev)
 		.rx_poll_complete = mt76x2_rx_poll_complete,
 		.sta_ps = mt76x2_sta_ps,
 	};
-	struct ieee80211_hw *hw;
 	struct mt76x2_dev *dev;
+	struct mt76_dev *mdev;
 
-	hw = ieee80211_alloc_hw(sizeof(*dev), &mt76x2_ops);
-	if (!hw)
+	mdev = mt76_alloc_device(sizeof(*dev), &mt76x2_ops);
+	if (!mdev)
 		return NULL;
 
-	dev = hw->priv;
-	dev->mt76.dev = pdev;
-	dev->mt76.hw = hw;
-	dev->mt76.drv = &drv_ops;
+	dev = container_of(mdev, struct mt76x2_dev, mt76);
+	mdev->dev = pdev;
+	mdev->drv = &drv_ops;
 	mutex_init(&dev->mutex);
 	spin_lock_init(&dev->irq_lock);
-	spin_lock_init(&dev->mt76.rx_lock);
 
 	return dev;
 }
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/5] mt76: wait for pending tx to complete before switching channel
  2018-05-20  5:43 [PATCH 1/5] mt76: only stop tx queues on offchannel, not during the entire scan Felix Fietkau
  2018-05-20  5:43 ` [PATCH 2/5] mt76: prevent tx scheduling during channel change Felix Fietkau
  2018-05-20  5:43 ` [PATCH 3/5] mt76: move ieee80211_hw allocation to common core Felix Fietkau
@ 2018-05-20  5:43 ` Felix Fietkau
  2018-05-20  5:43 ` [PATCH 5/5] mt76: use udelay instead of usleep_range in mt76x2_mac_stop Felix Fietkau
  2018-05-23  7:59 ` [1/5] mt76: only stop tx queues on offchannel, not during the entire scan Kalle Valo
  4 siblings, 0 replies; 6+ messages in thread
From: Felix Fietkau @ 2018-05-20  5:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo

Reduces interruption caused by scanning

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/dma.c      |  4 ++++
 drivers/net/wireless/mediatek/mt76/mac80211.c | 16 ++++++++++++++++
 drivers/net/wireless/mediatek/mt76/mt76.h     |  2 ++
 3 files changed, 22 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 3518703524e7..3dbedcedc2c4 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -178,6 +178,10 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
 		mt76_dma_sync_idx(dev, q);
 
 	wake = wake && qid < IEEE80211_NUM_ACS && q->queued < q->ndesc - 8;
+
+	if (!q->queued)
+		wake_up(&dev->tx_wait);
+
 	spin_unlock_bh(&q->lock);
 
 	if (wake)
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index d1044e5b25db..fcd079a96782 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -283,6 +283,7 @@ mt76_alloc_device(unsigned int size, const struct ieee80211_ops *ops)
 	spin_lock_init(&dev->rx_lock);
 	spin_lock_init(&dev->lock);
 	spin_lock_init(&dev->cc_lock);
+	init_waitqueue_head(&dev->tx_wait);
 
 	return dev;
 }
@@ -377,18 +378,33 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(mt76_rx);
 
+static bool mt76_has_tx_pending(struct mt76_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++) {
+		if (dev->q_tx[i].queued)
+			return true;
+	}
+
+	return false;
+}
+
 void mt76_set_channel(struct mt76_dev *dev)
 {
 	struct ieee80211_hw *hw = dev->hw;
 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
 	struct mt76_channel_state *state;
 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
+	int timeout = HZ / 5;
 
 	if (offchannel)
 		set_bit(MT76_OFFCHANNEL, &dev->state);
 	else
 		clear_bit(MT76_OFFCHANNEL, &dev->state);
 
+	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout);
+
 	if (dev->drv->update_survey)
 		dev->drv->update_survey(dev);
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index bb158f867d7c..d2166fbf50ff 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -251,6 +251,8 @@ struct mt76_dev {
 	struct mt76_queue q_rx[__MT_RXQ_MAX];
 	const struct mt76_queue_ops *queue_ops;
 
+	wait_queue_head_t tx_wait;
+
 	u8 macaddr[ETH_ALEN];
 	u32 rev;
 	unsigned long state;
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 5/5] mt76: use udelay instead of usleep_range in mt76x2_mac_stop
  2018-05-20  5:43 [PATCH 1/5] mt76: only stop tx queues on offchannel, not during the entire scan Felix Fietkau
                   ` (2 preceding siblings ...)
  2018-05-20  5:43 ` [PATCH 4/5] mt76: wait for pending tx to complete before switching channel Felix Fietkau
@ 2018-05-20  5:43 ` Felix Fietkau
  2018-05-23  7:59 ` [1/5] mt76: only stop tx queues on offchannel, not during the entire scan Kalle Valo
  4 siblings, 0 replies; 6+ messages in thread
From: Felix Fietkau @ 2018-05-20  5:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo

usleep_range can cause excessive latency on channel change if waiting
for the MAC to stop fails. It will be forced to stop by the code
following that loop anyway.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/mt76x2_init.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c
index 7096256c7f50..4e5f360d0655 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c
@@ -376,7 +376,7 @@ void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force)
 		if ((mt76_rr(dev, MT_MAC_STATUS) &
 		     (MT_MAC_STATUS_RX | MT_MAC_STATUS_TX)) ||
 		    mt76_rr(dev, MT_BBP(IBI, 12))) {
-			usleep_range(10, 20);
+			udelay(1);
 			continue;
 		}
 
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [1/5] mt76: only stop tx queues on offchannel, not during the entire scan
  2018-05-20  5:43 [PATCH 1/5] mt76: only stop tx queues on offchannel, not during the entire scan Felix Fietkau
                   ` (3 preceding siblings ...)
  2018-05-20  5:43 ` [PATCH 5/5] mt76: use udelay instead of usleep_range in mt76x2_mac_stop Felix Fietkau
@ 2018-05-23  7:59 ` Kalle Valo
  4 siblings, 0 replies; 6+ messages in thread
From: Kalle Valo @ 2018-05-23  7:59 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linux-wireless

Felix Fietkau <nbd@nbd.name> wrote:

> During scans, mac80211 frequently switches back to the home channel to
> minimize interruption of ongoing traffic. Keep regular tx queues active
> during that time.
> 
> Signed-off-by: Felix Fietkau <nbd@nbd.name>

5 patches applied to wireless-drivers-next.git, thanks.

89bc67e3a93a mt76: only stop tx queues on offchannel, not during the entire scan
a164a94212ce mt76: prevent tx scheduling during channel change
a85b590cf55f mt76: move ieee80211_hw allocation to common core
26e40d4c0b52 mt76: wait for pending tx to complete before switching channel
cbec83d40cc7 mt76: use udelay instead of usleep_range in mt76x2_mac_stop

-- 
https://patchwork.kernel.org/patch/10413117/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-05-23  7:59 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-05-20  5:43 [PATCH 1/5] mt76: only stop tx queues on offchannel, not during the entire scan Felix Fietkau
2018-05-20  5:43 ` [PATCH 2/5] mt76: prevent tx scheduling during channel change Felix Fietkau
2018-05-20  5:43 ` [PATCH 3/5] mt76: move ieee80211_hw allocation to common core Felix Fietkau
2018-05-20  5:43 ` [PATCH 4/5] mt76: wait for pending tx to complete before switching channel Felix Fietkau
2018-05-20  5:43 ` [PATCH 5/5] mt76: use udelay instead of usleep_range in mt76x2_mac_stop Felix Fietkau
2018-05-23  7:59 ` [1/5] mt76: only stop tx queues on offchannel, not during the entire scan Kalle Valo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).