2021-04-18 16:46:17

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 00/19] mt76: improve runtime-pm support

Rework runtime-pm support introduce pm refcounting in order
to fix some leftover races between fw_own and tx/rx path.
Introduce awake/doze time accounting.
This is a preliminary series to enable 'deep sleep' support in
mt7921 firmware.

Lorenzo Bianconi (19):
mt76: mt7921: fix a race between mt7921_mcu_drv_pmctrl and
mt7921_mcu_fw_pmctrl
mt76: mt7663: fix a race between mt7615_mcu_drv_pmctrl and
mt7615_mcu_fw_pmctrl
mt76: connac: introduce wake counter for fw_pmctrl synchronization
mt76: mt7921: rely on mt76_connac_pm_ref/mt76_connac_pm_unref in tx
path
mt76: mt7663: rely on mt76_connac_pm_ref/mt76_connac_pm_unref in tx
path
mt76: dma: add the capability to define a custom rx napi poll routine
mt76: mt7921: rely on mt76_connac_pm_ref/mt76_connac_pm_unref in tx/rx
napi
mt76: mt7663: rely on mt76_connac_pm_ref/mt76_connac_pm_unref in tx/rx
napi
mt76: connac: unschedule ps_work in mt76_connac_pm_wake
mt76: connac: check wake refcount in mcu_fw_pmctrl
mt76: connac: remove MT76_STATE_PM in mac_tx_free
mt76: mt7921: get rid of useless MT76_STATE_PM in mt7921_mac_work
mt76: connac: alaways wake the device before scanning
mt76: mt7615: rely on pm refcounting in mt7615_led_set_config
mt76: connac: do not run mt76_txq_schedule_all directly
mt76: connac: use waitqueue for runtime-pm
mt76: remove MT76_STATE_PM in tx path
mt76: mt7921: add awake and doze time accounting
mt76: mt7921: enable sw interrupts

drivers/net/wireless/mediatek/mt76/dma.c | 10 ++--
drivers/net/wireless/mediatek/mt76/dma.h | 1 +
drivers/net/wireless/mediatek/mt76/mt76.h | 6 ++-
.../net/wireless/mediatek/mt76/mt7603/dma.c | 2 +-
.../net/wireless/mediatek/mt76/mt7615/dma.c | 30 +++++++++--
.../net/wireless/mediatek/mt76/mt7615/init.c | 5 +-
.../net/wireless/mediatek/mt76/mt7615/mac.c | 20 ++++---
.../net/wireless/mediatek/mt76/mt7615/main.c | 30 +++++------
.../net/wireless/mediatek/mt76/mt7615/mcu.c | 23 +++++---
.../wireless/mediatek/mt76/mt7615/mt7615.h | 1 +
.../wireless/mediatek/mt76/mt7615/pci_init.c | 4 +-
.../net/wireless/mediatek/mt76/mt76_connac.h | 52 ++++++++++++++++++-
.../wireless/mediatek/mt76/mt76_connac_mac.c | 17 ++----
.../net/wireless/mediatek/mt76/mt76x02_mmio.c | 2 +-
.../net/wireless/mediatek/mt76/mt7915/dma.c | 2 +-
.../wireless/mediatek/mt76/mt7921/debugfs.c | 32 +++++++++++-
.../net/wireless/mediatek/mt76/mt7921/dma.c | 34 ++++++++++--
.../net/wireless/mediatek/mt76/mt7921/init.c | 10 +++-
.../net/wireless/mediatek/mt76/mt7921/mac.c | 29 +++++------
.../net/wireless/mediatek/mt76/mt7921/main.c | 26 ++++------
.../net/wireless/mediatek/mt76/mt7921/mcu.c | 46 +++++++++++-----
.../wireless/mediatek/mt76/mt7921/mt7921.h | 3 ++
.../net/wireless/mediatek/mt76/mt7921/pci.c | 13 +++++
.../net/wireless/mediatek/mt76/mt7921/regs.h | 17 +++---
drivers/net/wireless/mediatek/mt76/tx.c | 18 ++++---
25 files changed, 307 insertions(+), 126 deletions(-)

--
2.30.2


2021-04-18 16:46:20

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 02/19] mt76: mt7663: fix a race between mt7615_mcu_drv_pmctrl and mt7615_mcu_fw_pmctrl

Introduce a mutex in order to avoid a race between mt7615_mcu_lp_drv_pmctrl and
mt7615_mcu_fw_pmctrl routines since they are run two independent works

Fixes: 1f549009b5b2 ("mt76: mt7615: do not request {driver,fw}_own if already granted")
Signed-off-by: Lorenzo Bianconi <[email protected]>
---
.../net/wireless/mediatek/mt76/mt7615/init.c | 1 +
.../net/wireless/mediatek/mt76/mt7615/mcu.c | 20 +++++++++++++------
2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
index d84662fb0304..5429536e8d43 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
@@ -505,6 +505,7 @@ void mt7615_init_device(struct mt7615_dev *dev)

INIT_DELAYED_WORK(&dev->pm.ps_work, mt7615_pm_power_save_work);
INIT_WORK(&dev->pm.wake_work, mt7615_pm_wake_work);
+ mutex_init(&dev->pm.mutex);
init_completion(&dev->pm.wake_cmpl);
spin_lock_init(&dev->pm.txq_lock);
set_bit(MT76_STATE_PM, &dev->mphy.state);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index 364daef4b0be..7081bb4a28bd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -323,9 +323,11 @@ static int mt7615_mcu_drv_pmctrl(struct mt7615_dev *dev)
static int mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
- int i;
+ int i, err = 0;
+
+ mutex_lock(&dev->pm.mutex);

- if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state))
+ if (!test_bit(MT76_STATE_PM, &mphy->state))
goto out;

for (i = 0; i < MT7615_DRV_OWN_RETRY_COUNT; i++) {
@@ -337,14 +339,16 @@ static int mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev *dev)

if (i == MT7615_DRV_OWN_RETRY_COUNT) {
dev_err(dev->mt76.dev, "driver own failed\n");
- set_bit(MT76_STATE_PM, &mphy->state);
- return -EIO;
+ err = -EIO;
+ goto out;
}
+ clear_bit(MT76_STATE_PM, &mphy->state);

out:
dev->pm.last_activity = jiffies;
+ mutex_unlock(&dev->pm.mutex);

- return 0;
+ return err;
}

static int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev)
@@ -353,8 +357,10 @@ static int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev)
int err = 0;
u32 addr;

+ mutex_lock(&dev->pm.mutex);
+
if (test_and_set_bit(MT76_STATE_PM, &mphy->state))
- return 0;
+ goto out;

mt7622_trigger_hif_int(dev, true);

@@ -370,6 +376,8 @@ static int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev)
}

mt7622_trigger_hif_int(dev, false);
+out:
+ mutex_unlock(&dev->pm.mutex);

return err;
}
--
2.30.2

2021-04-18 16:46:22

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 03/19] mt76: connac: introduce wake counter for fw_pmctrl synchronization

Introduce wake counter and related spinlock in order to synchronize
tx/rx path and fw_pmctrl request.

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
.../net/wireless/mediatek/mt76/mt76_connac.h | 31 +++++++++++++++++++
1 file changed, 31 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
index 2b31c9794e92..85846eab8d7d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
@@ -54,6 +54,11 @@ struct mt76_connac_pm {

struct work_struct wake_work;
struct completion wake_cmpl;
+
+ struct {
+ spinlock_t lock;
+ u32 count;
+ } wake;
struct mutex mutex;

struct delayed_work ps_work;
@@ -85,6 +90,32 @@ void mt76_connac_power_save_sched(struct mt76_phy *phy,
void mt76_connac_free_pending_tx_skbs(struct mt76_connac_pm *pm,
struct mt76_wcid *wcid);

+static inline bool
+mt76_connac_pm_ref(struct mt76_phy *phy, struct mt76_connac_pm *pm)
+{
+ bool ret = false;
+
+ spin_lock_bh(&pm->wake.lock);
+ if (test_bit(MT76_STATE_PM, &phy->state))
+ goto out;
+
+ pm->wake.count++;
+ ret = true;
+out:
+ spin_unlock_bh(&pm->wake.lock);
+
+ return ret;
+}
+
+static inline void
+mt76_connac_pm_unref(struct mt76_connac_pm *pm)
+{
+ spin_lock_bh(&pm->wake.lock);
+ pm->wake.count--;
+ pm->last_activity = jiffies;
+ spin_unlock_bh(&pm->wake.lock);
+}
+
static inline void
mt76_connac_mutex_acquire(struct mt76_dev *dev, struct mt76_connac_pm *pm)
__acquires(&dev->mutex)
--
2.30.2

2021-04-18 16:46:25

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 04/19] mt76: mt7921: rely on mt76_connac_pm_ref/mt76_connac_pm_unref in tx path

Introduce mt7921_tx_worker routine as mt76 tx worker callback for
mt7921.
Rely on mt76_connac_pm_ref/mt76_connac_pm_unref to check PM state and
increment/decrement wake counter

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
.../net/wireless/mediatek/mt76/mt7921/init.c | 2 ++
.../net/wireless/mediatek/mt76/mt7921/main.c | 23 ++++++++-----------
.../wireless/mediatek/mt76/mt7921/mt7921.h | 2 ++
3 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index 0b8a5a7f4362..ce0e231ab772 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -219,9 +219,11 @@ int mt7921_register_device(struct mt7921_dev *dev)
dev->phy.dev = dev;
dev->phy.mt76 = &dev->mt76.phy;
dev->mt76.phy.priv = &dev->phy;
+ dev->mt76.tx_worker.fn = mt7921_tx_worker;

INIT_DELAYED_WORK(&dev->pm.ps_work, mt7921_pm_power_save_work);
INIT_WORK(&dev->pm.wake_work, mt7921_pm_wake_work);
+ spin_lock_init(&dev->pm.wake.lock);
mutex_init(&dev->pm.mutex);
init_completion(&dev->pm.wake_cmpl);
spin_lock_init(&dev->pm.txq_lock);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 25591e2c510c..95e1775c5c00 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -725,23 +725,18 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
}

-static void
-mt7921_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
+void mt7921_tx_worker(struct mt76_worker *w)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
- struct mt76_phy *mphy = phy->mt76;
-
- if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
- return;
+ struct mt7921_dev *dev = container_of(w, struct mt7921_dev,
+ mt76.tx_worker);

- if (test_bit(MT76_STATE_PM, &mphy->state)) {
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
queue_work(dev->mt76.wq, &dev->pm.wake_work);
return;
}

- dev->pm.last_activity = jiffies;
- mt76_worker_schedule(&dev->mt76.tx_worker);
+ mt76_txq_schedule_all(&dev->mphy);
+ mt76_connac_pm_unref(&dev->pm);
}

static void mt7921_tx(struct ieee80211_hw *hw,
@@ -769,9 +764,9 @@ static void mt7921_tx(struct ieee80211_hw *hw,
wcid = &mvif->sta.wcid;
}

- if (!test_bit(MT76_STATE_PM, &mphy->state)) {
- dev->pm.last_activity = jiffies;
+ if (mt76_connac_pm_ref(mphy, &dev->pm)) {
mt76_tx(mphy, control->sta, wcid, skb);
+ mt76_connac_pm_unref(&dev->pm);
return;
}

@@ -1200,7 +1195,7 @@ const struct ieee80211_ops mt7921_ops = {
.set_key = mt7921_set_key,
.ampdu_action = mt7921_ampdu_action,
.set_rts_threshold = mt7921_set_rts_threshold,
- .wake_tx_queue = mt7921_wake_tx_queue,
+ .wake_tx_queue = mt76_wake_tx_queue,
.release_buffered_frames = mt76_release_buffered_frames,
.get_txpower = mt76_get_txpower,
.get_stats = mt7921_get_stats,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index 3780a7f4cb16..a794c074867e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -336,6 +336,8 @@ int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
+
+void mt7921_tx_worker(struct mt76_worker *w);
void mt7921_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
int mt7921_init_tx_queues(struct mt7921_phy *phy, int idx, int n_desc);
void mt7921_tx_token_put(struct mt7921_dev *dev);
--
2.30.2

2021-04-18 16:46:28

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 05/19] mt76: mt7663: rely on mt76_connac_pm_ref/mt76_connac_pm_unref in tx path

Introduce mt7615_tx_worker routine as mt76 tx worker callback for
mt7663.
Rely on mt76_connac_pm_ref/mt76_connac_pm_unref to check PM state and
increment/decrement wake counter

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76.h | 1 +
.../net/wireless/mediatek/mt76/mt7615/init.c | 2 ++
.../net/wireless/mediatek/mt76/mt7615/main.c | 27 +++++++++----------
.../wireless/mediatek/mt76/mt7615/mt7615.h | 1 +
drivers/net/wireless/mediatek/mt76/tx.c | 12 ++++++---
5 files changed, 25 insertions(+), 18 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 289f195a7951..0660b708156d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -1015,6 +1015,7 @@ void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta,
void mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb);
void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid);
void mt76_txq_schedule_all(struct mt76_phy *phy);
+void mt76_tx_worker_run(struct mt76_dev *dev);
void mt76_tx_worker(struct mt76_worker *w);
void mt76_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
index 5429536e8d43..3ef6bcdf38c4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
@@ -502,9 +502,11 @@ void mt7615_init_device(struct mt7615_dev *dev)
dev->phy.dev = dev;
dev->phy.mt76 = &dev->mt76.phy;
dev->mt76.phy.priv = &dev->phy;
+ dev->mt76.tx_worker.fn = mt7615_tx_worker;

INIT_DELAYED_WORK(&dev->pm.ps_work, mt7615_pm_power_save_work);
INIT_WORK(&dev->pm.wake_work, mt7615_pm_wake_work);
+ spin_lock_init(&dev->pm.wake.lock);
mutex_init(&dev->pm.mutex);
init_completion(&dev->pm.wake_cmpl);
spin_lock_init(&dev->pm.txq_lock);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index 8313bf468db2..a3e53d3aec02 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -694,28 +694,25 @@ static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw,
break;
}
msta->n_rates = i;
- if (!test_bit(MT76_STATE_PM, &phy->mt76->state))
+ if (mt76_connac_pm_ref(phy->mt76, &dev->pm)) {
mt7615_mac_set_rates(phy, msta, NULL, msta->rates);
+ mt76_connac_pm_unref(&dev->pm);
+ }
spin_unlock_bh(&dev->mt76.lock);
}

-static void
-mt7615_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
+void mt7615_tx_worker(struct mt76_worker *w)
{
- struct mt7615_dev *dev = mt7615_hw_dev(hw);
- struct mt7615_phy *phy = mt7615_hw_phy(hw);
- struct mt76_phy *mphy = phy->mt76;
-
- if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
- return;
+ struct mt7615_dev *dev = container_of(w, struct mt7615_dev,
+ mt76.tx_worker);

- if (test_bit(MT76_STATE_PM, &mphy->state)) {
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
queue_work(dev->mt76.wq, &dev->pm.wake_work);
return;
}

- dev->pm.last_activity = jiffies;
- mt76_worker_schedule(&dev->mt76.tx_worker);
+ mt76_tx_worker_run(&dev->mt76);
+ mt76_connac_pm_unref(&dev->pm);
}

static void mt7615_tx(struct ieee80211_hw *hw,
@@ -743,9 +740,9 @@ static void mt7615_tx(struct ieee80211_hw *hw,
wcid = &msta->wcid;
}

- if (!test_bit(MT76_STATE_PM, &mphy->state)) {
- dev->pm.last_activity = jiffies;
+ if (mt76_connac_pm_ref(mphy, &dev->pm)) {
mt76_tx(mphy, control->sta, wcid, skb);
+ mt76_connac_pm_unref(&dev->pm);
return;
}

@@ -1272,7 +1269,7 @@ const struct ieee80211_ops mt7615_ops = {
.sta_set_decap_offload = mt7615_sta_set_decap_offload,
.ampdu_action = mt7615_ampdu_action,
.set_rts_threshold = mt7615_set_rts_threshold,
- .wake_tx_queue = mt7615_wake_tx_queue,
+ .wake_tx_queue = mt76_wake_tx_queue,
.sta_rate_tbl_update = mt7615_sta_rate_tbl_update,
.sw_scan_start = mt76_sw_scan,
.sw_scan_complete = mt76_sw_scan_complete,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index 5262b84a28c7..4c533b8ffa47 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -508,6 +508,7 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);

+void mt7615_tx_worker(struct mt76_worker *w);
void mt7615_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
void mt7615_tx_token_put(struct mt7615_dev *dev);
void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 04e47259ea5f..cfc7229aa7b0 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -540,10 +540,8 @@ void mt76_txq_schedule_all(struct mt76_phy *phy)
}
EXPORT_SYMBOL_GPL(mt76_txq_schedule_all);

-void mt76_tx_worker(struct mt76_worker *w)
+void mt76_tx_worker_run(struct mt76_dev *dev)
{
- struct mt76_dev *dev = container_of(w, struct mt76_dev, tx_worker);
-
mt76_txq_schedule_all(&dev->phy);
if (dev->phy2)
mt76_txq_schedule_all(dev->phy2);
@@ -555,6 +553,14 @@ void mt76_tx_worker(struct mt76_worker *w)
mt76_testmode_tx_pending(dev->phy2);
#endif
}
+EXPORT_SYMBOL_GPL(mt76_tx_worker_run);
+
+void mt76_tx_worker(struct mt76_worker *w)
+{
+ struct mt76_dev *dev = container_of(w, struct mt76_dev, tx_worker);
+
+ mt76_tx_worker_run(dev);
+}

void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta,
bool send_bar)
--
2.30.2

2021-04-18 16:46:31

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 06/19] mt76: dma: add the capability to define a custom rx napi poll routine

Add the capability to define a custom rx napi callback for each driver.
This is a preliminary patch to properly support runtime-pm on rx side

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
drivers/net/wireless/mediatek/mt76/dma.c | 10 +++++-----
drivers/net/wireless/mediatek/mt76/dma.h | 1 +
drivers/net/wireless/mediatek/mt76/mt76.h | 5 +++--
drivers/net/wireless/mediatek/mt76/mt7603/dma.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt7615/dma.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt7915/dma.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt7921/dma.c | 2 +-
8 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 6ea58aecca41..72b1cc0ecfda 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -602,8 +602,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
return done;
}

-static int
-mt76_dma_rx_poll(struct napi_struct *napi, int budget)
+int mt76_dma_rx_poll(struct napi_struct *napi, int budget)
{
struct mt76_dev *dev;
int qid, done = 0, cur;
@@ -626,9 +625,11 @@ mt76_dma_rx_poll(struct napi_struct *napi, int budget)

return done;
}
+EXPORT_SYMBOL_GPL(mt76_dma_rx_poll);

static int
-mt76_dma_init(struct mt76_dev *dev)
+mt76_dma_init(struct mt76_dev *dev,
+ int (*poll)(struct napi_struct *napi, int budget))
{
int i;

@@ -639,8 +640,7 @@ mt76_dma_init(struct mt76_dev *dev)
dev->napi_dev.threaded = 1;

mt76_for_each_q_rx(dev, i) {
- netif_napi_add(&dev->napi_dev, &dev->napi[i], mt76_dma_rx_poll,
- 64);
+ netif_napi_add(&dev->napi_dev, &dev->napi[i], poll, 64);
mt76_dma_rx_fill(dev, &dev->q_rx[i]);
napi_enable(&dev->napi[i]);
}
diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h
index e7c27697ef04..fdf786f975ea 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.h
+++ b/drivers/net/wireless/mediatek/mt76/dma.h
@@ -45,6 +45,7 @@ enum mt76_mcu_evt_type {
EVT_EVENT_DFS_DETECT_RSP,
};

+int mt76_dma_rx_poll(struct napi_struct *napi, int budget);
void mt76_dma_attach(struct mt76_dev *dev);
void mt76_dma_cleanup(struct mt76_dev *dev);

diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 0660b708156d..49f3e5985422 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -170,7 +170,8 @@ struct mt76_mcu_ops {
};

struct mt76_queue_ops {
- int (*init)(struct mt76_dev *dev);
+ int (*init)(struct mt76_dev *dev,
+ int (*poll)(struct napi_struct *napi, int budget));

int (*alloc)(struct mt76_dev *dev, struct mt76_queue *q,
int idx, int n_desc, int bufsize,
@@ -802,7 +803,7 @@ static inline u16 mt76_rev(struct mt76_dev *dev)
#define mt76xx_chip(dev) mt76_chip(&((dev)->mt76))
#define mt76xx_rev(dev) mt76_rev(&((dev)->mt76))

-#define mt76_init_queues(dev) (dev)->mt76.queue_ops->init(&((dev)->mt76))
+#define mt76_init_queues(dev, ...) (dev)->mt76.queue_ops->init(&((dev)->mt76), __VA_ARGS__)
#define mt76_queue_alloc(dev, ...) (dev)->mt76.queue_ops->alloc(&((dev)->mt76), __VA_ARGS__)
#define mt76_tx_queue_skb_raw(dev, ...) (dev)->mt76.queue_ops->tx_queue_skb_raw(&((dev)->mt76), __VA_ARGS__)
#define mt76_tx_queue_skb(dev, ...) (dev)->mt76.queue_ops->tx_queue_skb(&((dev)->mt76), __VA_ARGS__)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
index 2b6244116842..415ea17b9be6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
@@ -219,7 +219,7 @@ int mt7603_dma_init(struct mt7603_dev *dev)
return ret;

mt76_wr(dev, MT_DELAY_INT_CFG, 0);
- ret = mt76_init_queues(dev);
+ ret = mt76_init_queues(dev, mt76_dma_rx_poll);
if (ret)
return ret;

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
index 642b4eab0d8b..d658555f5965 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
@@ -261,7 +261,7 @@ int mt7615_dma_init(struct mt7615_dev *dev)

mt76_wr(dev, MT_DELAY_INT_CFG, 0);

- ret = mt76_init_queues(dev);
+ ret = mt76_init_queues(dev, mt76_dma_rx_poll);
if (ret < 0)
return ret;

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
index ce1e9ad23fec..b50084bbe83d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -226,7 +226,7 @@ int mt76x02_dma_init(struct mt76x02_dev *dev)
if (ret)
return ret;

- ret = mt76_init_queues(dev);
+ ret = mt76_init_queues(dev, mt76_dma_rx_poll);
if (ret)
return ret;

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
index 9fe09870f8f0..11d0b760abd7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
@@ -213,7 +213,7 @@ int mt7915_dma_init(struct mt7915_dev *dev)
return ret;
}

- ret = mt76_init_queues(dev);
+ ret = mt76_init_queues(dev, mt76_dma_rx_poll);
if (ret < 0)
return ret;

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
index 992faf82ad09..b056ac15f09a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
@@ -295,7 +295,7 @@ int mt7921_dma_init(struct mt7921_dev *dev)
if (ret)
return ret;

- ret = mt76_init_queues(dev);
+ ret = mt76_init_queues(dev, mt76_dma_rx_poll);
if (ret < 0)
return ret;

--
2.30.2

2021-04-18 16:46:32

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 07/19] mt76: mt7921: rely on mt76_connac_pm_ref/mt76_connac_pm_unref in tx/rx napi

Introduce mt7921_poll_rx rx napi callback for mt7921.
Do not access device registers in tx/rx napi if the device is not awake.

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
.../net/wireless/mediatek/mt76/mt7921/dma.c | 33 ++++++++++++++++---
.../net/wireless/mediatek/mt76/mt7921/mac.c | 11 +++++--
.../wireless/mediatek/mt76/mt7921/mt7921.h | 1 +
3 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
index b056ac15f09a..c26979614113 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
@@ -53,8 +53,7 @@ void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
}
}

-static void
-mt7921_tx_cleanup(struct mt7921_dev *dev)
+void mt7921_tx_cleanup(struct mt7921_dev *dev)
{
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], false);
@@ -66,14 +65,38 @@ static int mt7921_poll_tx(struct napi_struct *napi, int budget)

dev = container_of(napi, struct mt7921_dev, mt76.tx_napi);

- mt7921_tx_cleanup(dev);
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
+ napi_complete(napi);
+ queue_work(dev->mt76.wq, &dev->pm.wake_work);
+ return 0;
+ }

- if (napi_complete_done(napi, 0))
+ mt7921_tx_cleanup(dev);
+ if (napi_complete(napi))
mt7921_irq_enable(dev, MT_INT_TX_DONE_ALL);
+ mt76_connac_pm_unref(&dev->pm);

return 0;
}

+static int mt7921_poll_rx(struct napi_struct *napi, int budget)
+{
+ struct mt7921_dev *dev;
+ int done;
+
+ dev = container_of(napi->dev, struct mt7921_dev, mt76.napi_dev);
+
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
+ napi_complete(napi);
+ queue_work(dev->mt76.wq, &dev->pm.wake_work);
+ return 0;
+ }
+ done = mt76_dma_rx_poll(napi, budget);
+ mt76_connac_pm_unref(&dev->pm);
+
+ return done;
+}
+
void mt7921_dma_prefetch(struct mt7921_dev *dev)
{
#define PREFETCH(base, depth) ((base) << 16 | (depth))
@@ -295,7 +318,7 @@ int mt7921_dma_init(struct mt7921_dev *dev)
if (ret)
return ret;

- ret = mt76_init_queues(dev, mt76_dma_rx_poll);
+ ret = mt76_init_queues(dev, mt7921_poll_rx);
if (ret < 0)
return ret;

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index c8819e78cea3..def00b255495 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -1367,6 +1367,7 @@ mt7921_mac_reset(struct mt7921_dev *dev)
mt76_worker_enable(&dev->mt76.tx_worker);

clear_bit(MT76_MCU_RESET, &dev->mphy.state);
+ clear_bit(MT76_STATE_PM, &dev->mphy.state);

mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
@@ -1530,10 +1531,14 @@ void mt7921_pm_wake_work(struct work_struct *work)
pm.wake_work);
mphy = dev->phy.mt76;

- if (!mt7921_mcu_drv_pmctrl(dev))
+ if (!mt7921_mcu_drv_pmctrl(dev)) {
+ int i;
+
+ mt76_for_each_q_rx(&dev->mt76, i)
+ napi_schedule(&dev->mt76.napi[i]);
mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
- else
- dev_err(mphy->dev->dev, "failed to wake device\n");
+ mt7921_tx_cleanup(dev);
+ }

ieee80211_wake_queues(mphy->hw);
complete_all(&dev->pm.wake_cmpl);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index a794c074867e..c9687c57cbe7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -332,6 +332,7 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
void mt7921_mac_work(struct work_struct *work);
void mt7921_mac_reset_work(struct work_struct *work);
void mt7921_reset(struct mt76_dev *mdev);
+void mt7921_tx_cleanup(struct mt7921_dev *dev);
int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
--
2.30.2

2021-04-18 16:46:37

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 08/19] mt76: mt7663: rely on mt76_connac_pm_ref/mt76_connac_pm_unref in tx/rx napi

Introduce mt7615_poll_rx rx napi callback for mt7663.
Do not access device registers in tx/rx napi if the device is not awake.

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
.../net/wireless/mediatek/mt76/mt7615/dma.c | 30 +++++++++++++++++--
.../net/wireless/mediatek/mt76/mt7615/mac.c | 10 +++++--
2 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
index d658555f5965..8004ae5c16a9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
@@ -71,15 +71,39 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget)
struct mt7615_dev *dev;

dev = container_of(napi, struct mt7615_dev, mt76.tx_napi);
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
+ napi_complete(napi);
+ queue_work(dev->mt76.wq, &dev->pm.wake_work);
+ return 0;
+ }

mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
-
- if (napi_complete_done(napi, 0))
+ if (napi_complete(napi))
mt7615_irq_enable(dev, mt7615_tx_mcu_int_mask(dev));

+ mt76_connac_pm_unref(&dev->pm);
+
return 0;
}

+static int mt7615_poll_rx(struct napi_struct *napi, int budget)
+{
+ struct mt7615_dev *dev;
+ int done;
+
+ dev = container_of(napi->dev, struct mt7615_dev, mt76.napi_dev);
+
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
+ napi_complete(napi);
+ queue_work(dev->mt76.wq, &dev->pm.wake_work);
+ return 0;
+ }
+ done = mt76_dma_rx_poll(napi, budget);
+ mt76_connac_pm_unref(&dev->pm);
+
+ return done;
+}
+
int mt7615_wait_pdma_busy(struct mt7615_dev *dev)
{
struct mt76_dev *mdev = &dev->mt76;
@@ -261,7 +285,7 @@ int mt7615_dma_init(struct mt7615_dev *dev)

mt76_wr(dev, MT_DELAY_INT_CFG, 0);

- ret = mt76_init_queues(dev, mt76_dma_rx_poll);
+ ret = mt76_init_queues(dev, mt7615_poll_rx);
if (ret < 0)
return ret;

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index 0b386030dbd8..e81c7d322811 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -1913,10 +1913,14 @@ void mt7615_pm_wake_work(struct work_struct *work)
pm.wake_work);
mphy = dev->phy.mt76;

- if (!mt7615_mcu_set_drv_ctrl(dev))
+ if (!mt7615_mcu_set_drv_ctrl(dev)) {
+ int i;
+
+ mt76_for_each_q_rx(&dev->mt76, i)
+ napi_schedule(&dev->mt76.napi[i]);
mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
- else
- dev_err(mphy->dev->dev, "failed to wake device\n");
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
+ }

ieee80211_wake_queues(mphy->hw);
complete_all(&dev->pm.wake_cmpl);
--
2.30.2

2021-04-18 16:46:37

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 09/19] mt76: connac: unschedule ps_work in mt76_connac_pm_wake

In order to avoid synchronization issues between wake and ps works,
cancel ps_work in mt76_connac_pm_wake routine

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 1 -
drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c | 1 +
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 1 -
3 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index 7081bb4a28bd..5890fee98d97 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -345,7 +345,6 @@ static int mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev *dev)
clear_bit(MT76_STATE_PM, &mphy->state);

out:
- dev->pm.last_activity = jiffies;
mutex_unlock(&dev->pm.mutex);

return err;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
index c5f5037f5757..32d664ac1e35 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
@@ -13,6 +13,7 @@ int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm)
if (!mt76_is_mmio(dev))
return 0;

+ cancel_delayed_work_sync(&pm->ps_work);
if (!test_bit(MT76_STATE_PM, &phy->state))
return 0;

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index ea00f6b6af56..44f02cbf9cc7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -1289,7 +1289,6 @@ int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
clear_bit(MT76_STATE_PM, &mphy->state);

out:
- dev->pm.last_activity = jiffies;
mutex_unlock(&dev->pm.mutex);

if (err)
--
2.30.2

2021-04-18 16:46:41

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 11/19] mt76: connac: remove MT76_STATE_PM in mac_tx_free

Get rid of MT76_STATE_PM chec in mt7615_mac_tx_free and
mt7921_mac_tx_free since we already rely on mt76_connac_pm_unref in the
NAPI callback.
Remove mt76_connac_power_save_sched calls in mt7615_mac_tx_free and
mt7921_mac_tx_free

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 4 ----
drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 6 ------
2 files changed, 10 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index e81c7d322811..ad1e236727cb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -1514,14 +1514,10 @@ static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb)

dev_kfree_skb(skb);

- if (test_bit(MT76_STATE_PM, &dev->phy.mt76->state))
- return;
-
rcu_read_lock();
mt7615_mac_sta_poll(dev);
rcu_read_unlock();

- mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
mt76_worker_schedule(&dev->mt76.tx_worker);
}

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index def00b255495..a8247a6d5bc7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -1043,13 +1043,7 @@ void mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb)
napi_consume_skb(skb, 1);
}

- if (test_bit(MT76_STATE_PM, &dev->phy.mt76->state))
- return;
-
mt7921_mac_sta_poll(dev);
-
- mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
-
mt76_worker_schedule(&dev->mt76.tx_worker);
}

--
2.30.2

2021-04-18 16:46:43

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 12/19] mt76: mt7921: get rid of useless MT76_STATE_PM in mt7921_mac_work

Remove useless MT76_STATE_PM check in mt7921_mac_work since
mt7921_mutex_acquire will wake up the device if necessary

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 5 -----
1 file changed, 5 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index a8247a6d5bc7..5dcb574a2768 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -1493,9 +1493,6 @@ void mt7921_mac_work(struct work_struct *work)
mac_work.work);
phy = mphy->priv;

- if (test_bit(MT76_STATE_PM, &mphy->state))
- goto out;
-
mt7921_mutex_acquire(phy->dev);

mt76_update_survey(mphy->dev);
@@ -1510,8 +1507,6 @@ void mt7921_mac_work(struct work_struct *work)
}

mt7921_mutex_release(phy->dev);
-
-out:
ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work,
MT7921_WATCHDOG_TIME);
}
--
2.30.2

2021-04-18 16:46:43

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 10/19] mt76: connac: check wake refcount in mcu_fw_pmctrl

In order to avoid synchronization races between tx and rx path, rely on
mt76_connac_skip_fw_pmctrl putting the chip in sleep mode for mt7921 and
mt7663 devices

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt76_connac.h | 12 ++++++++++++
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +-
3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index 5890fee98d97..45c6fb5832b8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -358,7 +358,7 @@ static int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev)

mutex_lock(&dev->pm.mutex);

- if (test_and_set_bit(MT76_STATE_PM, &mphy->state))
+ if (mt76_connac_skip_fw_pmctrl(mphy, &dev->pm))
goto out;

mt7622_trigger_hif_int(dev, true);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
index 85846eab8d7d..116d800c9f9d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
@@ -116,6 +116,18 @@ mt76_connac_pm_unref(struct mt76_connac_pm *pm)
spin_unlock_bh(&pm->wake.lock);
}

+static inline bool
+mt76_connac_skip_fw_pmctrl(struct mt76_phy *phy, struct mt76_connac_pm *pm)
+{
+ bool ret;
+
+ spin_lock_bh(&pm->wake.lock);
+ ret = pm->wake.count || test_and_set_bit(MT76_STATE_PM, &phy->state);
+ spin_unlock_bh(&pm->wake.lock);
+
+ return ret;
+}
+
static inline void
mt76_connac_mutex_acquire(struct mt76_dev *dev, struct mt76_connac_pm *pm)
__acquires(&dev->mutex)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 44f02cbf9cc7..1204f5d324f8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -1304,7 +1304,7 @@ int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev)

mutex_lock(&dev->pm.mutex);

- if (test_and_set_bit(MT76_STATE_PM, &mphy->state))
+ if (mt76_connac_skip_fw_pmctrl(mphy, &dev->pm))
goto out;

for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
--
2.30.2

2021-04-18 16:46:45

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 13/19] mt76: connac: alaways wake the device before scanning

move scanning check from mt76_connac_power_save_sched routine
to mt7921_pm_power_save_work/mt7615_pm_power_save_work ones

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 4 ++++
drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c | 8 --------
drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 4 ++++
3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index ad1e236727cb..adbc726149a9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -1931,6 +1931,10 @@ void mt7615_pm_power_save_work(struct work_struct *work)
pm.ps_work.work);

delta = dev->pm.idle_timeout;
+ if (test_bit(MT76_HW_SCANNING, &dev->mphy.state) ||
+ test_bit(MT76_HW_SCHED_SCANNING, &dev->mphy.state))
+ goto out;
+
if (time_is_after_jiffies(dev->pm.last_activity + delta)) {
delta = dev->pm.last_activity + delta - jiffies;
goto out;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
index 32d664ac1e35..a263921d9f42 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
@@ -17,10 +17,6 @@ int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm)
if (!test_bit(MT76_STATE_PM, &phy->state))
return 0;

- if (test_bit(MT76_HW_SCANNING, &phy->state) ||
- test_bit(MT76_HW_SCHED_SCANNING, &phy->state))
- return 0;
-
if (queue_work(dev->wq, &pm->wake_work))
reinit_completion(&pm->wake_cmpl);

@@ -46,10 +42,6 @@ void mt76_connac_power_save_sched(struct mt76_phy *phy,

pm->last_activity = jiffies;

- if (test_bit(MT76_HW_SCANNING, &phy->state) ||
- test_bit(MT76_HW_SCHED_SCANNING, &phy->state))
- return;
-
if (!test_bit(MT76_STATE_PM, &phy->state))
queue_delayed_work(dev->wq, &pm->ps_work, pm->idle_timeout);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index 5dcb574a2768..90ede75cfba8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -1542,6 +1542,10 @@ void mt7921_pm_power_save_work(struct work_struct *work)
pm.ps_work.work);

delta = dev->pm.idle_timeout;
+ if (test_bit(MT76_HW_SCANNING, &dev->mphy.state) ||
+ test_bit(MT76_HW_SCHED_SCANNING, &dev->mphy.state))
+ goto out;
+
if (time_is_after_jiffies(dev->pm.last_activity + delta)) {
delta = dev->pm.last_activity + delta - jiffies;
goto out;
--
2.30.2

2021-04-18 16:46:47

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 14/19] mt76: mt7615: rely on pm refcounting in mt7615_led_set_config

Rely on mt76_connac_pm_ref/mt76_connac_pm_unref utility routines in
mt7615_led_set_config

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c
index 49540b00519d..736d19699a03 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c
@@ -82,7 +82,7 @@ mt7615_led_set_config(struct led_classdev *led_cdev,
mt76 = container_of(led_cdev, struct mt76_dev, led_cdev);
dev = container_of(mt76, struct mt7615_dev, mt76);

- if (test_bit(MT76_STATE_PM, &mt76->phy.state))
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm))
return;

val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xffff) |
@@ -100,6 +100,8 @@ mt7615_led_set_config(struct led_classdev *led_cdev,
val |= MT_LED_CTRL_POLARITY(mt76->led_pin);
addr = mt7615_reg_map(dev, MT_LED_CTRL);
mt76_wr(dev, addr, val);
+
+ mt76_connac_pm_unref(&dev->pm);
}

static int
--
2.30.2

2021-04-18 16:46:50

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 15/19] mt76: connac: do not run mt76_txq_schedule_all directly

In order to not break runtime-pm, do run mt76_txq_schedule_all in
mt7615_set_channel/mt7921_set_channel but rely on mt76_worker_schedule

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7615/main.c | 3 +--
drivers/net/wireless/mediatek/mt76/mt7921/main.c | 3 +--
2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index a3e53d3aec02..39733b351ac4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -351,8 +351,7 @@ int mt7615_set_channel(struct mt7615_phy *phy)

mt7615_mutex_release(dev);

- mt76_txq_schedule_all(phy->mt76);
-
+ mt76_worker_schedule(&dev->mt76.tx_worker);
if (!mt76_testmode_enabled(phy->mt76))
ieee80211_queue_delayed_work(phy->mt76->hw,
&phy->mt76->mac_work,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 95e1775c5c00..255a931675bb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -395,8 +395,7 @@ int mt7921_set_channel(struct mt7921_phy *phy)
clear_bit(MT76_RESET, &phy->mt76->state);
mt7921_mutex_release(dev);

- mt76_txq_schedule_all(phy->mt76);
-
+ mt76_worker_schedule(&dev->mt76.tx_worker);
ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mt76->mac_work,
MT7921_WATCHDOG_TIME);

--
2.30.2

2021-04-18 16:46:54

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 16/19] mt76: connac: use waitqueue for runtime-pm

Simplify the code using a wait_queue_head_t instead of a completion to
wait the chip is fully awake in mt76_connac_pm_wake routine

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7615/init.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt76_connac.h | 2 +-
drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c | 8 ++++----
drivers/net/wireless/mediatek/mt76/mt7921/init.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 2 +-
6 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
index 3ef6bcdf38c4..894b2588e075 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
@@ -508,7 +508,7 @@ void mt7615_init_device(struct mt7615_dev *dev)
INIT_WORK(&dev->pm.wake_work, mt7615_pm_wake_work);
spin_lock_init(&dev->pm.wake.lock);
mutex_init(&dev->pm.mutex);
- init_completion(&dev->pm.wake_cmpl);
+ init_waitqueue_head(&dev->pm.wait);
spin_lock_init(&dev->pm.txq_lock);
set_bit(MT76_STATE_PM, &dev->mphy.state);
INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7615_mac_work);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index adbc726149a9..747bf90f9d8a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -1919,7 +1919,7 @@ void mt7615_pm_wake_work(struct work_struct *work)
}

ieee80211_wake_queues(mphy->hw);
- complete_all(&dev->pm.wake_cmpl);
+ wake_up(&dev->pm.wait);
}

void mt7615_pm_power_save_work(struct work_struct *work)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
index 116d800c9f9d..e3937f6d3640 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
@@ -53,7 +53,7 @@ struct mt76_connac_pm {
} tx_q[IEEE80211_NUM_ACS];

struct work_struct wake_work;
- struct completion wake_cmpl;
+ wait_queue_head_t wait;

struct {
spinlock_t lock;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
index a263921d9f42..66f1667481e6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
@@ -17,10 +17,10 @@ int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm)
if (!test_bit(MT76_STATE_PM, &phy->state))
return 0;

- if (queue_work(dev->wq, &pm->wake_work))
- reinit_completion(&pm->wake_cmpl);
-
- if (!wait_for_completion_timeout(&pm->wake_cmpl, 3 * HZ)) {
+ queue_work(dev->wq, &pm->wake_work);
+ if (!wait_event_timeout(pm->wait,
+ !test_bit(MT76_STATE_PM, &phy->state),
+ 3 * HZ)) {
ieee80211_wake_queues(phy->hw);
return -ETIMEDOUT;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index ce0e231ab772..2d8dba000d0b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -225,7 +225,7 @@ int mt7921_register_device(struct mt7921_dev *dev)
INIT_WORK(&dev->pm.wake_work, mt7921_pm_wake_work);
spin_lock_init(&dev->pm.wake.lock);
mutex_init(&dev->pm.mutex);
- init_completion(&dev->pm.wake_cmpl);
+ init_waitqueue_head(&dev->pm.wait);
spin_lock_init(&dev->pm.txq_lock);
set_bit(MT76_STATE_PM, &dev->mphy.state);
INIT_LIST_HEAD(&dev->phy.stats_list);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index 90ede75cfba8..7b5323181fac 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -1530,7 +1530,7 @@ void mt7921_pm_wake_work(struct work_struct *work)
}

ieee80211_wake_queues(mphy->hw);
- complete_all(&dev->pm.wake_cmpl);
+ wake_up(&dev->pm.wait);
}

void mt7921_pm_power_save_work(struct work_struct *work)
--
2.30.2

2021-04-18 16:46:54

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 17/19] mt76: remove MT76_STATE_PM in tx path

since tx/rx path is now relying pm ref counting, get rid of MT76_STATE_PM
check in the tx path

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
drivers/net/wireless/mediatek/mt76/tx.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index cfc7229aa7b0..236eaa351f53 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -422,8 +422,7 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
return idx;

do {
- if (test_bit(MT76_STATE_PM, &phy->state) ||
- test_bit(MT76_RESET, &phy->state))
+ if (test_bit(MT76_RESET, &phy->state))
return -EBUSY;

if (stop || mt76_txq_stopped(q))
@@ -463,8 +462,7 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
while (1) {
int n_frames = 0;

- if (test_bit(MT76_STATE_PM, &phy->state) ||
- test_bit(MT76_RESET, &phy->state))
+ if (test_bit(MT76_RESET, &phy->state))
return -EBUSY;

if (dev->queue_ops->tx_cleanup &&
--
2.30.2

2021-04-18 16:46:59

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 19/19] mt76: mt7921: enable sw interrupts

Enable sw interrupts in order to wake the device from deep sleep
receiving packets

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7921/dma.c | 1 +
drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 1 +
drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 13 +++++++++++++
.../net/wireless/mediatek/mt76/mt7921/regs.h | 17 ++++++++++-------
4 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
index c26979614113..7ada8339b74f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
@@ -351,6 +351,7 @@ int mt7921_dma_init(struct mt7921_dev *dev)
/* enable interrupts for TX/RX rings */
mt7921_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
MT_INT_MCU_CMD);
+ mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE);

return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index 7b5323181fac..8770e0d93f45 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -1276,6 +1276,7 @@ mt7921_dma_reset(struct mt7921_dev *dev)
mt7921_irq_enable(dev,
MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
MT_INT_MCU_CMD);
+ mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE);
}

void mt7921_tx_token_put(struct mt7921_dev *dev)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
index 40e2086d075c..d5da98d36f63 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -61,6 +61,18 @@ static void mt7921_irq_tasklet(unsigned long data)
if (intr & MT_INT_TX_DONE_MCU)
mask |= MT_INT_TX_DONE_MCU;

+ if (intr & MT_INT_MCU_CMD) {
+ u32 intr_sw;
+
+ intr_sw = mt76_rr(dev, MT_MCU_CMD);
+ /* ack MCU2HOST_SW_INT_STA */
+ mt76_wr(dev, MT_MCU_CMD, intr_sw);
+ if (intr_sw & MT_MCU_CMD_WAKE_RX_PCIE) {
+ mask |= MT_INT_RX_DONE_DATA;
+ intr |= MT_INT_RX_DONE_DATA;
+ }
+ }
+
mt76_set_irq_mask(&dev->mt76, MT_WFDMA0_HOST_INT_ENA, mask, 0);

if (intr & MT_INT_TX_DONE_ALL)
@@ -253,6 +265,7 @@ static int mt7921_pci_resume(struct pci_dev *pdev)
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
mt7921_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
MT_INT_MCU_CMD);
+ mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE);

/* put dma enabled */
mt76_set(dev, MT_WFDMA0_GLO_CFG,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
index 76ecfea21dce..b6944c867a57 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
@@ -251,13 +251,16 @@
#define MT_WFDMA0_BUSY_ENA_TX_FIFO1 BIT(1)
#define MT_WFDMA0_BUSY_ENA_RX_FIFO BIT(2)

-#define MT_MCU_CMD MT_WFDMA0(0x1f0)
-#define MT_MCU_CMD_STOP_DMA_FW_RELOAD BIT(1)
-#define MT_MCU_CMD_STOP_DMA BIT(2)
-#define MT_MCU_CMD_RESET_DONE BIT(3)
-#define MT_MCU_CMD_RECOVERY_DONE BIT(4)
-#define MT_MCU_CMD_NORMAL_STATE BIT(5)
-#define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1)
+#define MT_MCU_CMD MT_WFDMA0(0x1f0)
+#define MT_MCU_CMD_WAKE_RX_PCIE BIT(0)
+#define MT_MCU_CMD_STOP_DMA_FW_RELOAD BIT(1)
+#define MT_MCU_CMD_STOP_DMA BIT(2)
+#define MT_MCU_CMD_RESET_DONE BIT(3)
+#define MT_MCU_CMD_RECOVERY_DONE BIT(4)
+#define MT_MCU_CMD_NORMAL_STATE BIT(5)
+#define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1)
+
+#define MT_MCU2HOST_SW_INT_ENA MT_WFDMA0(0x1f4)

#define MT_WFDMA0_HOST_INT_STA MT_WFDMA0(0x200)
#define HOST_RX_DONE_INT_STS0 BIT(0) /* Rx mcu */
--
2.30.2

2021-04-18 16:47:05

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 18/19] mt76: mt7921: add awake and doze time accounting

Introduce awake and doze time accounting for runtime pm.

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
.../net/wireless/mediatek/mt76/mt76_connac.h | 6 ++++
.../wireless/mediatek/mt76/mt7921/debugfs.c | 32 ++++++++++++++++++-
.../net/wireless/mediatek/mt76/mt7921/init.c | 5 ++-
.../net/wireless/mediatek/mt76/mt7921/mcu.c | 19 ++++++++---
4 files changed, 55 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
index e3937f6d3640..9e61c107c640 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
@@ -64,6 +64,12 @@ struct mt76_connac_pm {
struct delayed_work ps_work;
unsigned long last_activity;
unsigned long idle_timeout;
+ struct {
+ unsigned long last_wake_event;
+ unsigned long awake_time;
+ unsigned long last_doze_event;
+ unsigned long doze_time;
+ } stats;
};

struct mt76_connac_coredump {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
index 5a54cd8d2ce4..f3982578cc56 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
@@ -230,11 +230,19 @@ static int
mt7921_pm_set(void *data, u64 val)
{
struct mt7921_dev *dev = data;
+ struct mt76_connac_pm *pm = &dev->pm;
struct mt76_phy *mphy = dev->phy.mt76;

+ if (val == pm->enable)
+ return 0;
+
mt7921_mutex_acquire(dev);

- dev->pm.enable = val;
+ if (!pm->enable) {
+ pm->stats.last_wake_event = jiffies;
+ pm->stats.last_doze_event = jiffies;
+ }
+ pm->enable = val;

ieee80211_iterate_active_interfaces(mphy->hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
@@ -256,6 +264,26 @@ mt7921_pm_get(void *data, u64 *val)

DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7921_pm_get, mt7921_pm_set, "%lld\n");

+static int
+mt7921_pm_stats(struct seq_file *s, void *data)
+{
+ struct mt7921_dev *dev = dev_get_drvdata(s->private);
+ struct mt76_connac_pm *pm = &dev->pm;
+ unsigned long awake_time = pm->stats.awake_time;
+ unsigned long doze_time = pm->stats.doze_time;
+
+ if (!test_bit(MT76_STATE_PM, &dev->mphy.state))
+ awake_time += jiffies - pm->stats.last_wake_event;
+ else
+ doze_time += jiffies - pm->stats.last_doze_event;
+
+ seq_printf(s, "awake time: %14u\ndoze time: %15u\n",
+ jiffies_to_msecs(awake_time),
+ jiffies_to_msecs(doze_time));
+
+ return 0;
+}
+
static int
mt7921_pm_idle_timeout_set(void *data, u64 val)
{
@@ -322,6 +350,8 @@ int mt7921_init_debugfs(struct mt7921_dev *dev)
debugfs_create_file("idle-timeout", 0600, dir, dev,
&fops_pm_idle_timeout);
debugfs_create_file("chip_reset", 0600, dir, dev, &fops_reset);
+ debugfs_create_devm_seqfile(dev->mt76.dev, "runtime_pm_stats", dir,
+ mt7921_pm_stats);

return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index 2d8dba000d0b..cec17a249a8c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -239,12 +239,15 @@ int mt7921_register_device(struct mt7921_dev *dev)

INIT_WORK(&dev->reset_work, mt7921_mac_reset_work);

+ dev->pm.idle_timeout = MT7921_PM_TIMEOUT;
+ dev->pm.stats.last_wake_event = jiffies;
+ dev->pm.stats.last_doze_event = jiffies;
+
ret = mt7921_init_hardware(dev);
if (ret)
return ret;

mt7921_init_wiphy(hw);
- dev->pm.idle_timeout = MT7921_PM_TIMEOUT;
dev->mphy.sband_2g.sband.ht_cap.cap |=
IEEE80211_HT_CAP_LDPC_CODING |
IEEE80211_HT_CAP_MAX_AMSDU;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 1204f5d324f8..c00295b63ba8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -1267,9 +1267,10 @@ int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_connac_pm *pm = &dev->pm;
int i, err = 0;

- mutex_lock(&dev->pm.mutex);
+ mutex_lock(&pm->mutex);

if (!test_bit(MT76_STATE_PM, &mphy->state))
goto out;
@@ -1288,8 +1289,11 @@ int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
}
clear_bit(MT76_STATE_PM, &mphy->state);

+ pm->stats.last_wake_event = jiffies;
+ pm->stats.doze_time += pm->stats.last_wake_event -
+ pm->stats.last_doze_event;
out:
- mutex_unlock(&dev->pm.mutex);
+ mutex_unlock(&pm->mutex);

if (err)
mt7921_reset(&dev->mt76);
@@ -1300,11 +1304,12 @@ int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_connac_pm *pm = &dev->pm;
int i, err = 0;

- mutex_lock(&dev->pm.mutex);
+ mutex_lock(&pm->mutex);

- if (mt76_connac_skip_fw_pmctrl(mphy, &dev->pm))
+ if (mt76_connac_skip_fw_pmctrl(mphy, pm))
goto out;

for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
@@ -1319,8 +1324,12 @@ int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev)
clear_bit(MT76_STATE_PM, &mphy->state);
err = -EIO;
}
+
+ pm->stats.last_doze_event = jiffies;
+ pm->stats.awake_time += pm->stats.last_doze_event -
+ pm->stats.last_wake_event;
out:
- mutex_unlock(&dev->pm.mutex);
+ mutex_unlock(&pm->mutex);

if (err)
mt7921_reset(&dev->mt76);
--
2.30.2

2021-04-18 16:47:17

by Lorenzo Bianconi

[permalink] [raw]
Subject: [PATCH 01/19] mt76: mt7921: fix a race between mt7921_mcu_drv_pmctrl and mt7921_mcu_fw_pmctrl

Introduce a mutex in order to avoid a race between mt7921_mcu_drv_pmctrl and
mt7921_mcu_fw_pmctrl routines since they are run two independent works

Fixes: 1d8efc741df8 ("mt76: mt7921: introduce Runtime PM support")
Signed-off-by: Lorenzo Bianconi <[email protected]>
---
.../net/wireless/mediatek/mt76/mt76_connac.h | 1 +
.../net/wireless/mediatek/mt76/mt7921/init.c | 1 +
.../net/wireless/mediatek/mt76/mt7921/mcu.c | 34 +++++++++++++------
3 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
index b811f3c410a1..2b31c9794e92 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
@@ -54,6 +54,7 @@ struct mt76_connac_pm {

struct work_struct wake_work;
struct completion wake_cmpl;
+ struct mutex mutex;

struct delayed_work ps_work;
unsigned long last_activity;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index eab6e2dcdb96..0b8a5a7f4362 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -222,6 +222,7 @@ int mt7921_register_device(struct mt7921_dev *dev)

INIT_DELAYED_WORK(&dev->pm.ps_work, mt7921_pm_power_save_work);
INIT_WORK(&dev->pm.wake_work, mt7921_pm_wake_work);
+ mutex_init(&dev->pm.mutex);
init_completion(&dev->pm.wake_cmpl);
spin_lock_init(&dev->pm.txq_lock);
set_bit(MT76_STATE_PM, &dev->mphy.state);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 14ba856de0b6..ea00f6b6af56 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -1267,9 +1267,11 @@ int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
- int i;
+ int i, err = 0;

- if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state))
+ mutex_lock(&dev->pm.mutex);
+
+ if (!test_bit(MT76_STATE_PM, &mphy->state))
goto out;

for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
@@ -1281,23 +1283,30 @@ int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)

if (i == MT7921_DRV_OWN_RETRY_COUNT) {
dev_err(dev->mt76.dev, "driver own failed\n");
- mt7921_reset(&dev->mt76);
- return -EIO;
+ err = -EIO;
+ goto out;
}
+ clear_bit(MT76_STATE_PM, &mphy->state);

out:
dev->pm.last_activity = jiffies;
+ mutex_unlock(&dev->pm.mutex);

- return 0;
+ if (err)
+ mt7921_reset(&dev->mt76);
+
+ return err;
}

int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
- int i;
+ int i, err = 0;
+
+ mutex_lock(&dev->pm.mutex);

if (test_and_set_bit(MT76_STATE_PM, &mphy->state))
- return 0;
+ goto out;

for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN);
@@ -1308,11 +1317,16 @@ int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev)

if (i == MT7921_DRV_OWN_RETRY_COUNT) {
dev_err(dev->mt76.dev, "firmware own failed\n");
- mt7921_reset(&dev->mt76);
- return -EIO;
+ clear_bit(MT76_STATE_PM, &mphy->state);
+ err = -EIO;
}
+out:
+ mutex_unlock(&dev->pm.mutex);

- return 0;
+ if (err)
+ mt7921_reset(&dev->mt76);
+
+ return err;
}

void
--
2.30.2