1 // SPDX-License-Identifier: ISC 2 /* Copyright (C) 2020 MediaTek Inc. */ 3 4 #include "mt76_connac.h" 5 6 int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm) 7 { 8 struct mt76_dev *dev = phy->dev; 9 10 if (!pm->enable) 11 return 0; 12 13 if (!mt76_is_mmio(dev)) 14 return 0; 15 16 if (!test_bit(MT76_STATE_PM, &phy->state)) 17 return 0; 18 19 if (test_bit(MT76_HW_SCANNING, &phy->state) || 20 test_bit(MT76_HW_SCHED_SCANNING, &phy->state)) 21 return 0; 22 23 if (queue_work(dev->wq, &pm->wake_work)) 24 reinit_completion(&pm->wake_cmpl); 25 26 if (!wait_for_completion_timeout(&pm->wake_cmpl, 3 * HZ)) { 27 ieee80211_wake_queues(phy->hw); 28 return -ETIMEDOUT; 29 } 30 31 return 0; 32 } 33 EXPORT_SYMBOL_GPL(mt76_connac_pm_wake); 34 35 void mt76_connac_power_save_sched(struct mt76_phy *phy, 36 struct mt76_connac_pm *pm) 37 { 38 struct mt76_dev *dev = phy->dev; 39 40 if (!mt76_is_mmio(dev)) 41 return; 42 43 if (!pm->enable || !test_bit(MT76_STATE_RUNNING, &phy->state)) 44 return; 45 46 pm->last_activity = jiffies; 47 48 if (test_bit(MT76_HW_SCANNING, &phy->state) || 49 test_bit(MT76_HW_SCHED_SCANNING, &phy->state)) 50 return; 51 52 if (!test_bit(MT76_STATE_PM, &phy->state)) 53 queue_delayed_work(dev->wq, &pm->ps_work, pm->idle_timeout); 54 } 55 EXPORT_SYMBOL_GPL(mt76_connac_power_save_sched); 56 57 void mt76_connac_free_pending_tx_skbs(struct mt76_connac_pm *pm, 58 struct mt76_wcid *wcid) 59 { 60 int i; 61 62 spin_lock_bh(&pm->txq_lock); 63 for (i = 0; i < IEEE80211_NUM_ACS; i++) { 64 if (wcid && pm->tx_q[i].wcid != wcid) 65 continue; 66 67 dev_kfree_skb(pm->tx_q[i].skb); 68 pm->tx_q[i].skb = NULL; 69 } 70 spin_unlock_bh(&pm->txq_lock); 71 } 72 EXPORT_SYMBOL_GPL(mt76_connac_free_pending_tx_skbs); 73 74 void mt76_connac_pm_queue_skb(struct ieee80211_hw *hw, 75 struct mt76_connac_pm *pm, 76 struct mt76_wcid *wcid, 77 struct sk_buff *skb) 78 { 79 int qid = skb_get_queue_mapping(skb); 80 struct mt76_phy *phy = hw->priv; 81 82 spin_lock_bh(&pm->txq_lock); 83 if (!pm->tx_q[qid].skb) { 84 ieee80211_stop_queues(hw); 85 pm->tx_q[qid].wcid = wcid; 86 pm->tx_q[qid].skb = skb; 87 queue_work(phy->dev->wq, &pm->wake_work); 88 } else { 89 dev_kfree_skb(skb); 90 } 91 spin_unlock_bh(&pm->txq_lock); 92 } 93 EXPORT_SYMBOL_GPL(mt76_connac_pm_queue_skb); 94 95 void mt76_connac_pm_dequeue_skbs(struct mt76_phy *phy, 96 struct mt76_connac_pm *pm) 97 { 98 int i; 99 100 spin_lock_bh(&pm->txq_lock); 101 for (i = 0; i < IEEE80211_NUM_ACS; i++) { 102 struct mt76_wcid *wcid = pm->tx_q[i].wcid; 103 struct ieee80211_sta *sta = NULL; 104 105 if (!pm->tx_q[i].skb) 106 continue; 107 108 if (wcid && wcid->sta) 109 sta = container_of((void *)wcid, struct ieee80211_sta, 110 drv_priv); 111 112 mt76_tx(phy, sta, wcid, pm->tx_q[i].skb); 113 pm->tx_q[i].skb = NULL; 114 } 115 spin_unlock_bh(&pm->txq_lock); 116 117 mt76_worker_schedule(&phy->dev->tx_worker); 118 } 119 EXPORT_SYMBOL_GPL(mt76_connac_pm_dequeue_skbs); 120