Skip to content

Commit 1d8efc7

Browse files
moore-brosnbd168
authored andcommitted
mt76: mt7921: introduce Runtime PM support
Introduce runtime PM to mt7921 driver Co-developed-by: Lorenzo Bianconi <[email protected]> Signed-off-by: Lorenzo Bianconi <[email protected]> Signed-off-by: Sean Wang <[email protected]> Signed-off-by: Felix Fietkau <[email protected]>
1 parent 022159b commit 1d8efc7

File tree

8 files changed

+372
-54
lines changed

8 files changed

+372
-54
lines changed

drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,60 @@ mt7921_queues_read(struct seq_file *s, void *data)
159159
return 0;
160160
}
161161

162+
static int
163+
mt7921_pm_set(void *data, u64 val)
164+
{
165+
struct mt7921_dev *dev = data;
166+
struct mt76_phy *mphy = dev->phy.mt76;
167+
int ret = 0;
168+
169+
mt7921_mutex_acquire(dev);
170+
171+
dev->pm.enable = val;
172+
173+
ieee80211_iterate_active_interfaces(mphy->hw,
174+
IEEE80211_IFACE_ITER_RESUME_ALL,
175+
mt7921_pm_interface_iter, mphy->priv);
176+
mt7921_mutex_release(dev);
177+
178+
return ret;
179+
}
180+
181+
static int
182+
mt7921_pm_get(void *data, u64 *val)
183+
{
184+
struct mt7921_dev *dev = data;
185+
186+
*val = dev->pm.enable;
187+
188+
return 0;
189+
}
190+
191+
DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7921_pm_get, mt7921_pm_set, "%lld\n");
192+
193+
static int
194+
mt7921_pm_idle_timeout_set(void *data, u64 val)
195+
{
196+
struct mt7921_dev *dev = data;
197+
198+
dev->pm.idle_timeout = msecs_to_jiffies(val);
199+
200+
return 0;
201+
}
202+
203+
static int
204+
mt7921_pm_idle_timeout_get(void *data, u64 *val)
205+
{
206+
struct mt7921_dev *dev = data;
207+
208+
*val = jiffies_to_msecs(dev->pm.idle_timeout);
209+
210+
return 0;
211+
}
212+
213+
DEFINE_DEBUGFS_ATTRIBUTE(fops_pm_idle_timeout, mt7921_pm_idle_timeout_get,
214+
mt7921_pm_idle_timeout_set, "%lld\n");
215+
162216
int mt7921_init_debugfs(struct mt7921_dev *dev)
163217
{
164218
struct dentry *dir;
@@ -173,6 +227,9 @@ int mt7921_init_debugfs(struct mt7921_dev *dev)
173227
mt7921_queues_acq);
174228
debugfs_create_file("tx_stats", 0400, dir, dev, &fops_tx_stats);
175229
debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug);
230+
debugfs_create_file("runtime-pm", 0600, dir, dev, &fops_pm);
231+
debugfs_create_file("idle-timeout", 0600, dir, dev,
232+
&fops_pm_idle_timeout);
176233

177234
return 0;
178235
}

drivers/net/wireless/mediatek/mt76/mt7921/init.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,12 @@ int mt7921_register_device(struct mt7921_dev *dev)
201201
dev->phy.dev = dev;
202202
dev->phy.mt76 = &dev->mt76.phy;
203203
dev->mt76.phy.priv = &dev->phy;
204+
205+
INIT_DELAYED_WORK(&dev->pm.ps_work, mt7921_pm_power_save_work);
206+
INIT_WORK(&dev->pm.wake_work, mt7921_pm_wake_work);
207+
init_completion(&dev->pm.wake_cmpl);
208+
spin_lock_init(&dev->pm.txq_lock);
209+
set_bit(MT76_STATE_PM, &dev->mphy.state);
204210
INIT_LIST_HEAD(&dev->phy.stats_list);
205211
INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7921_mac_work);
206212
INIT_DELAYED_WORK(&dev->phy.scan_work, mt7921_scan_work);
@@ -216,6 +222,7 @@ int mt7921_register_device(struct mt7921_dev *dev)
216222
return ret;
217223

218224
mt7921_init_wiphy(hw);
225+
dev->pm.idle_timeout = MT7921_PM_TIMEOUT;
219226
dev->mphy.sband_2g.sband.ht_cap.cap |=
220227
IEEE80211_HT_CAP_LDPC_CODING |
221228
IEEE80211_HT_CAP_MAX_AMSDU;

drivers/net/wireless/mediatek/mt76/mt7921/mac.c

Lines changed: 89 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,22 +1001,27 @@ void mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb)
10011001
mt76_put_txwi(mdev, txwi);
10021002
}
10031003

1004-
mt7921_mac_sta_poll(dev);
1005-
10061004
if (wake) {
10071005
spin_lock_bh(&dev->token_lock);
10081006
mt7921_set_tx_blocked(dev, false);
10091007
spin_unlock_bh(&dev->token_lock);
10101008
}
10111009

1012-
mt76_worker_schedule(&dev->mt76.tx_worker);
1013-
10141010
napi_consume_skb(skb, 1);
10151011

10161012
list_for_each_entry_safe(skb, tmp, &free_list, list) {
10171013
skb_list_del_init(skb);
10181014
napi_consume_skb(skb, 1);
10191015
}
1016+
1017+
if (test_bit(MT76_STATE_PM, &dev->phy.mt76->state))
1018+
return;
1019+
1020+
mt7921_mac_sta_poll(dev);
1021+
1022+
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
1023+
1024+
mt76_worker_schedule(&dev->mt76.tx_worker);
10201025
}
10211026

10221027
void mt7921_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
@@ -1166,9 +1171,14 @@ void mt7921_update_channel(struct mt76_dev *mdev)
11661171
{
11671172
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
11681173

1174+
if (mt76_connac_pm_wake(&dev->mphy, &dev->pm))
1175+
return;
1176+
11691177
mt7921_phy_update_channel(&mdev->phy, 0);
11701178
/* reset obss airtime */
11711179
mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR);
1180+
1181+
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
11721182
}
11731183

11741184
static bool
@@ -1257,7 +1267,7 @@ void mt7921_mac_reset_work(struct work_struct *work)
12571267
napi_disable(&dev->mt76.napi[2]);
12581268
napi_disable(&dev->mt76.tx_napi);
12591269

1260-
mutex_lock(&dev->mt76.mutex);
1270+
mt7921_mutex_acquire(dev);
12611271

12621272
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
12631273

@@ -1292,7 +1302,7 @@ void mt7921_mac_reset_work(struct work_struct *work)
12921302
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
12931303
mt7921_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
12941304

1295-
mutex_unlock(&dev->mt76.mutex);
1305+
mt7921_mutex_release(dev);
12961306

12971307
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
12981308
MT7921_WATCHDOG_TIME);
@@ -1373,7 +1383,10 @@ void mt7921_mac_work(struct work_struct *work)
13731383
mac_work.work);
13741384
phy = mphy->priv;
13751385

1376-
mutex_lock(&mphy->dev->mutex);
1386+
if (test_bit(MT76_STATE_PM, &mphy->state))
1387+
goto out;
1388+
1389+
mt7921_mutex_acquire(phy->dev);
13771390

13781391
mt76_update_survey(mphy->dev);
13791392
if (++mphy->mac_work_count == 5) {
@@ -1386,8 +1399,75 @@ void mt7921_mac_work(struct work_struct *work)
13861399
mt7921_mac_sta_stats_work(phy);
13871400
};
13881401

1389-
mutex_unlock(&mphy->dev->mutex);
1402+
mt7921_mutex_release(phy->dev);
13901403

1391-
ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
1404+
out:
1405+
ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work,
13921406
MT7921_WATCHDOG_TIME);
13931407
}
1408+
1409+
void mt7921_pm_wake_work(struct work_struct *work)
1410+
{
1411+
struct mt7921_dev *dev;
1412+
struct mt76_phy *mphy;
1413+
1414+
dev = (struct mt7921_dev *)container_of(work, struct mt7921_dev,
1415+
pm.wake_work);
1416+
mphy = dev->phy.mt76;
1417+
1418+
if (!mt7921_mcu_drv_pmctrl(dev))
1419+
mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
1420+
else
1421+
dev_err(mphy->dev->dev, "failed to wake device\n");
1422+
1423+
ieee80211_wake_queues(mphy->hw);
1424+
complete_all(&dev->pm.wake_cmpl);
1425+
}
1426+
1427+
void mt7921_pm_power_save_work(struct work_struct *work)
1428+
{
1429+
struct mt7921_dev *dev;
1430+
unsigned long delta;
1431+
1432+
dev = (struct mt7921_dev *)container_of(work, struct mt7921_dev,
1433+
pm.ps_work.work);
1434+
1435+
delta = dev->pm.idle_timeout;
1436+
if (time_is_after_jiffies(dev->pm.last_activity + delta)) {
1437+
delta = dev->pm.last_activity + delta - jiffies;
1438+
goto out;
1439+
}
1440+
1441+
if (!mt7921_mcu_fw_pmctrl(dev))
1442+
return;
1443+
out:
1444+
queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta);
1445+
}
1446+
1447+
int mt7921_mac_set_beacon_filter(struct mt7921_phy *phy,
1448+
struct ieee80211_vif *vif,
1449+
bool enable)
1450+
{
1451+
struct mt7921_dev *dev = phy->dev;
1452+
bool ext_phy = phy != &dev->phy;
1453+
int err;
1454+
1455+
if (!dev->pm.enable)
1456+
return -EOPNOTSUPP;
1457+
1458+
err = mt7921_mcu_set_bss_pm(dev, vif, enable);
1459+
if (err)
1460+
return err;
1461+
1462+
if (enable) {
1463+
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
1464+
mt76_set(dev, MT_WF_RFCR(ext_phy),
1465+
MT_WF_RFCR_DROP_OTHER_BEACON);
1466+
} else {
1467+
vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
1468+
mt76_clear(dev, MT_WF_RFCR(ext_phy),
1469+
MT_WF_RFCR_DROP_OTHER_BEACON);
1470+
}
1471+
1472+
return 0;
1473+
}

0 commit comments

Comments
 (0)