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_usb(dev)) 14 return 0; 15 16 cancel_delayed_work_sync(&pm->ps_work); 17 if (!test_bit(MT76_STATE_PM, &phy->state)) 18 return 0; 19 20 if (pm->suspended) 21 return 0; 22 23 queue_work(dev->wq, &pm->wake_work); 24 if (!wait_event_timeout(pm->wait, 25 !test_bit(MT76_STATE_PM, &phy->state), 26 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_usb(dev)) 41 return; 42 43 if (!pm->enable) 44 return; 45 46 if (pm->suspended) 47 return; 48 49 pm->last_activity = jiffies; 50 51 if (!test_bit(MT76_STATE_PM, &phy->state)) { 52 cancel_delayed_work(&phy->mac_work); 53 queue_delayed_work(dev->wq, &pm->ps_work, pm->idle_timeout); 54 } 55 } 56 EXPORT_SYMBOL_GPL(mt76_connac_power_save_sched); 57 58 void mt76_connac_free_pending_tx_skbs(struct mt76_connac_pm *pm, 59 struct mt76_wcid *wcid) 60 { 61 int i; 62 63 spin_lock_bh(&pm->txq_lock); 64 for (i = 0; i < IEEE80211_NUM_ACS; i++) { 65 if (wcid && pm->tx_q[i].wcid != wcid) 66 continue; 67 68 dev_kfree_skb(pm->tx_q[i].skb); 69 pm->tx_q[i].skb = NULL; 70 } 71 spin_unlock_bh(&pm->txq_lock); 72 } 73 EXPORT_SYMBOL_GPL(mt76_connac_free_pending_tx_skbs); 74 75 void mt76_connac_pm_queue_skb(struct ieee80211_hw *hw, 76 struct mt76_connac_pm *pm, 77 struct mt76_wcid *wcid, 78 struct sk_buff *skb) 79 { 80 int qid = skb_get_queue_mapping(skb); 81 struct mt76_phy *phy = hw->priv; 82 83 spin_lock_bh(&pm->txq_lock); 84 if (!pm->tx_q[qid].skb) { 85 ieee80211_stop_queues(hw); 86 pm->tx_q[qid].wcid = wcid; 87 pm->tx_q[qid].skb = skb; 88 queue_work(phy->dev->wq, &pm->wake_work); 89 } else { 90 dev_kfree_skb(skb); 91 } 92 spin_unlock_bh(&pm->txq_lock); 93 } 94 EXPORT_SYMBOL_GPL(mt76_connac_pm_queue_skb); 95 96 void mt76_connac_pm_dequeue_skbs(struct mt76_phy *phy, 97 struct mt76_connac_pm *pm) 98 { 99 int i; 100 101 spin_lock_bh(&pm->txq_lock); 102 for (i = 0; i < IEEE80211_NUM_ACS; i++) { 103 struct mt76_wcid *wcid = pm->tx_q[i].wcid; 104 struct ieee80211_sta *sta = NULL; 105 106 if (!pm->tx_q[i].skb) 107 continue; 108 109 if (wcid && wcid->sta) 110 sta = container_of((void *)wcid, struct ieee80211_sta, 111 drv_priv); 112 113 mt76_tx(phy, sta, wcid, pm->tx_q[i].skb); 114 pm->tx_q[i].skb = NULL; 115 } 116 spin_unlock_bh(&pm->txq_lock); 117 118 mt76_worker_schedule(&phy->dev->tx_worker); 119 } 120 EXPORT_SYMBOL_GPL(mt76_connac_pm_dequeue_skbs); 121