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