1 | // SPDX-License-Identifier: ISC |
2 | /* |
3 | * Copyright (c) 2005-2011 Atheros Communications Inc. |
4 | * Copyright (c) 2011-2016 Qualcomm Atheros, Inc. |
5 | * Copyright (c) 2018, The Linux Foundation. All rights reserved. |
6 | */ |
7 | |
8 | #include "core.h" |
9 | #include "txrx.h" |
10 | #include "htt.h" |
11 | #include "mac.h" |
12 | #include "debug.h" |
13 | |
14 | static void ath10k_report_offchan_tx(struct ath10k *ar, struct sk_buff *skb) |
15 | { |
16 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
17 | |
18 | if (likely(!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN))) |
19 | return; |
20 | |
21 | if (ath10k_mac_tx_frm_has_freq(ar)) |
22 | return; |
23 | |
24 | /* If the original wait_for_completion() timed out before |
25 | * {data,mgmt}_tx_completed() was called then we could complete |
26 | * offchan_tx_completed for a different skb. Prevent this by using |
27 | * offchan_tx_skb. |
28 | */ |
29 | spin_lock_bh(lock: &ar->data_lock); |
30 | if (ar->offchan_tx_skb != skb) { |
31 | ath10k_warn(ar, fmt: "completed old offchannel frame\n" ); |
32 | goto out; |
33 | } |
34 | |
35 | complete(&ar->offchan_tx_completed); |
36 | ar->offchan_tx_skb = NULL; /* just for sanity */ |
37 | |
38 | ath10k_dbg(ar, ATH10K_DBG_HTT, "completed offchannel skb %pK\n" , skb); |
39 | out: |
40 | spin_unlock_bh(lock: &ar->data_lock); |
41 | } |
42 | |
43 | int ath10k_txrx_tx_unref(struct ath10k_htt *htt, |
44 | const struct htt_tx_done *tx_done) |
45 | { |
46 | struct ieee80211_tx_status status; |
47 | struct ath10k *ar = htt->ar; |
48 | struct device *dev = ar->dev; |
49 | struct ieee80211_tx_info *info; |
50 | struct ieee80211_txq *txq; |
51 | struct ath10k_skb_cb *skb_cb; |
52 | struct ath10k_txq *artxq; |
53 | struct sk_buff *msdu; |
54 | u8 flags; |
55 | |
56 | ath10k_dbg(ar, ATH10K_DBG_HTT, |
57 | "htt tx completion msdu_id %u status %d\n" , |
58 | tx_done->msdu_id, tx_done->status); |
59 | |
60 | if (tx_done->msdu_id >= htt->max_num_pending_tx) { |
61 | ath10k_warn(ar, fmt: "warning: msdu_id %d too big, ignoring\n" , |
62 | tx_done->msdu_id); |
63 | return -EINVAL; |
64 | } |
65 | |
66 | spin_lock_bh(lock: &htt->tx_lock); |
67 | msdu = idr_find(&htt->pending_tx, id: tx_done->msdu_id); |
68 | if (!msdu) { |
69 | ath10k_warn(ar, fmt: "received tx completion for invalid msdu_id: %d\n" , |
70 | tx_done->msdu_id); |
71 | spin_unlock_bh(lock: &htt->tx_lock); |
72 | return -ENOENT; |
73 | } |
74 | |
75 | skb_cb = ATH10K_SKB_CB(skb: msdu); |
76 | txq = skb_cb->txq; |
77 | |
78 | if (txq) { |
79 | artxq = (void *)txq->drv_priv; |
80 | artxq->num_fw_queued--; |
81 | } |
82 | |
83 | flags = skb_cb->flags; |
84 | ath10k_htt_tx_free_msdu_id(htt, msdu_id: tx_done->msdu_id); |
85 | ath10k_htt_tx_dec_pending(htt); |
86 | spin_unlock_bh(lock: &htt->tx_lock); |
87 | |
88 | rcu_read_lock(); |
89 | if (txq && txq->sta && skb_cb->airtime_est) |
90 | ieee80211_sta_register_airtime(pubsta: txq->sta, tid: txq->tid, |
91 | tx_airtime: skb_cb->airtime_est, rx_airtime: 0); |
92 | rcu_read_unlock(); |
93 | |
94 | if (ar->bus_param.dev_type != ATH10K_DEV_TYPE_HL) |
95 | dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); |
96 | |
97 | ath10k_report_offchan_tx(ar: htt->ar, skb: msdu); |
98 | |
99 | info = IEEE80211_SKB_CB(skb: msdu); |
100 | memset(&info->status, 0, sizeof(info->status)); |
101 | info->status.rates[0].idx = -1; |
102 | |
103 | trace_ath10k_txrx_tx_unref(ar, msdu_id: tx_done->msdu_id); |
104 | |
105 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && |
106 | !(flags & ATH10K_SKB_F_NOACK_TID)) |
107 | info->flags |= IEEE80211_TX_STAT_ACK; |
108 | |
109 | if (tx_done->status == HTT_TX_COMPL_STATE_NOACK) |
110 | info->flags &= ~IEEE80211_TX_STAT_ACK; |
111 | |
112 | if ((tx_done->status == HTT_TX_COMPL_STATE_ACK) && |
113 | ((info->flags & IEEE80211_TX_CTL_NO_ACK) || |
114 | (flags & ATH10K_SKB_F_NOACK_TID))) |
115 | info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; |
116 | |
117 | if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) { |
118 | if ((info->flags & IEEE80211_TX_CTL_NO_ACK) || |
119 | (flags & ATH10K_SKB_F_NOACK_TID)) |
120 | info->flags &= ~IEEE80211_TX_STAT_NOACK_TRANSMITTED; |
121 | else |
122 | info->flags &= ~IEEE80211_TX_STAT_ACK; |
123 | } |
124 | |
125 | if (tx_done->status == HTT_TX_COMPL_STATE_ACK && |
126 | tx_done->ack_rssi != ATH10K_INVALID_RSSI) { |
127 | info->status.ack_signal = ATH10K_DEFAULT_NOISE_FLOOR + |
128 | tx_done->ack_rssi; |
129 | info->status.flags |= IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; |
130 | } |
131 | |
132 | memset(&status, 0, sizeof(status)); |
133 | status.skb = msdu; |
134 | status.info = info; |
135 | |
136 | rcu_read_lock(); |
137 | |
138 | if (txq) |
139 | status.sta = txq->sta; |
140 | |
141 | ieee80211_tx_status_ext(hw: htt->ar->hw, status: &status); |
142 | |
143 | rcu_read_unlock(); |
144 | |
145 | /* we do not own the msdu anymore */ |
146 | |
147 | return 0; |
148 | } |
149 | |
150 | struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, |
151 | const u8 *addr) |
152 | { |
153 | struct ath10k_peer *peer; |
154 | |
155 | lockdep_assert_held(&ar->data_lock); |
156 | |
157 | list_for_each_entry(peer, &ar->peers, list) { |
158 | if (peer->vdev_id != vdev_id) |
159 | continue; |
160 | if (!ether_addr_equal(addr1: peer->addr, addr2: addr)) |
161 | continue; |
162 | |
163 | return peer; |
164 | } |
165 | |
166 | return NULL; |
167 | } |
168 | |
169 | struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id) |
170 | { |
171 | struct ath10k_peer *peer; |
172 | |
173 | if (peer_id >= BITS_PER_TYPE(peer->peer_ids)) |
174 | return NULL; |
175 | |
176 | lockdep_assert_held(&ar->data_lock); |
177 | |
178 | list_for_each_entry(peer, &ar->peers, list) |
179 | if (test_bit(peer_id, peer->peer_ids)) |
180 | return peer; |
181 | |
182 | return NULL; |
183 | } |
184 | |
185 | static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id, |
186 | const u8 *addr, bool expect_mapped) |
187 | { |
188 | long time_left; |
189 | |
190 | time_left = wait_event_timeout(ar->peer_mapping_wq, ({ |
191 | bool mapped; |
192 | |
193 | spin_lock_bh(&ar->data_lock); |
194 | mapped = !!ath10k_peer_find(ar, vdev_id, addr); |
195 | spin_unlock_bh(&ar->data_lock); |
196 | |
197 | (mapped == expect_mapped || |
198 | test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)); |
199 | }), 3 * HZ); |
200 | |
201 | if (time_left == 0) |
202 | return -ETIMEDOUT; |
203 | |
204 | return 0; |
205 | } |
206 | |
207 | int ath10k_wait_for_peer_created(struct ath10k *ar, int vdev_id, const u8 *addr) |
208 | { |
209 | return ath10k_wait_for_peer_common(ar, vdev_id, addr, expect_mapped: true); |
210 | } |
211 | |
212 | int ath10k_wait_for_peer_deleted(struct ath10k *ar, int vdev_id, const u8 *addr) |
213 | { |
214 | return ath10k_wait_for_peer_common(ar, vdev_id, addr, expect_mapped: false); |
215 | } |
216 | |
217 | void ath10k_peer_map_event(struct ath10k_htt *htt, |
218 | struct htt_peer_map_event *ev) |
219 | { |
220 | struct ath10k *ar = htt->ar; |
221 | struct ath10k_peer *peer; |
222 | |
223 | if (ev->peer_id >= ATH10K_MAX_NUM_PEER_IDS) { |
224 | ath10k_warn(ar, |
225 | fmt: "received htt peer map event with idx out of bounds: %u\n" , |
226 | ev->peer_id); |
227 | return; |
228 | } |
229 | |
230 | spin_lock_bh(lock: &ar->data_lock); |
231 | peer = ath10k_peer_find(ar, vdev_id: ev->vdev_id, addr: ev->addr); |
232 | if (!peer) { |
233 | peer = kzalloc(size: sizeof(*peer), GFP_ATOMIC); |
234 | if (!peer) |
235 | goto exit; |
236 | |
237 | peer->vdev_id = ev->vdev_id; |
238 | ether_addr_copy(dst: peer->addr, src: ev->addr); |
239 | list_add(new: &peer->list, head: &ar->peers); |
240 | wake_up(&ar->peer_mapping_wq); |
241 | } |
242 | |
243 | ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n" , |
244 | ev->vdev_id, ev->addr, ev->peer_id); |
245 | |
246 | WARN_ON(ar->peer_map[ev->peer_id] && (ar->peer_map[ev->peer_id] != peer)); |
247 | ar->peer_map[ev->peer_id] = peer; |
248 | set_bit(nr: ev->peer_id, addr: peer->peer_ids); |
249 | exit: |
250 | spin_unlock_bh(lock: &ar->data_lock); |
251 | } |
252 | |
253 | void ath10k_peer_unmap_event(struct ath10k_htt *htt, |
254 | struct htt_peer_unmap_event *ev) |
255 | { |
256 | struct ath10k *ar = htt->ar; |
257 | struct ath10k_peer *peer; |
258 | |
259 | if (ev->peer_id >= ATH10K_MAX_NUM_PEER_IDS) { |
260 | ath10k_warn(ar, |
261 | fmt: "received htt peer unmap event with idx out of bounds: %u\n" , |
262 | ev->peer_id); |
263 | return; |
264 | } |
265 | |
266 | spin_lock_bh(lock: &ar->data_lock); |
267 | peer = ath10k_peer_find_by_id(ar, peer_id: ev->peer_id); |
268 | if (!peer) { |
269 | ath10k_warn(ar, fmt: "peer-unmap-event: unknown peer id %d\n" , |
270 | ev->peer_id); |
271 | goto exit; |
272 | } |
273 | |
274 | ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n" , |
275 | peer->vdev_id, peer->addr, ev->peer_id); |
276 | |
277 | ar->peer_map[ev->peer_id] = NULL; |
278 | clear_bit(nr: ev->peer_id, addr: peer->peer_ids); |
279 | |
280 | if (bitmap_empty(src: peer->peer_ids, ATH10K_MAX_NUM_PEER_IDS)) { |
281 | list_del(entry: &peer->list); |
282 | kfree(objp: peer); |
283 | wake_up(&ar->peer_mapping_wq); |
284 | } |
285 | |
286 | exit: |
287 | spin_unlock_bh(lock: &ar->data_lock); |
288 | } |
289 | |