GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / net / wireless / mediatek / mt76 / mt76_connac_mac.c
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);