* [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