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