]>
Commit | Line | Data |
---|---|---|
f0553ca9 | 1 | // SPDX-License-Identifier: ISC |
5e3dd157 KV |
2 | /* |
3 | * Copyright (c) 2005-2011 Atheros Communications Inc. | |
8b1083d6 | 4 | * Copyright (c) 2011-2016 Qualcomm Atheros, Inc. |
235b9c42 | 5 | * Copyright (c) 2018, The Linux Foundation. All rights reserved. |
5e3dd157 KV |
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 | { | |
e0813d34 MK |
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)) | |
5e3dd157 KV |
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 | |
d6dfe25c MR |
27 | * offchan_tx_skb. |
28 | */ | |
5e3dd157 KV |
29 | spin_lock_bh(&ar->data_lock); |
30 | if (ar->offchan_tx_skb != skb) { | |
7aa7a72a | 31 | ath10k_warn(ar, "completed old offchannel frame\n"); |
5e3dd157 KV |
32 | goto out; |
33 | } | |
34 | ||
35 | complete(&ar->offchan_tx_completed); | |
36 | ar->offchan_tx_skb = NULL; /* just for sanity */ | |
37 | ||
75b34800 | 38 | ath10k_dbg(ar, ATH10K_DBG_HTT, "completed offchannel skb %pK\n", skb); |
5e3dd157 KV |
39 | out: |
40 | spin_unlock_bh(&ar->data_lock); | |
41 | } | |
42 | ||
cac08552 RM |
43 | int ath10k_txrx_tx_unref(struct ath10k_htt *htt, |
44 | const struct htt_tx_done *tx_done) | |
5e3dd157 | 45 | { |
7aa7a72a MK |
46 | struct ath10k *ar = htt->ar; |
47 | struct device *dev = ar->dev; | |
5e3dd157 | 48 | struct ieee80211_tx_info *info; |
3cc0fef6 | 49 | struct ieee80211_txq *txq; |
1f8bb151 | 50 | struct ath10k_skb_cb *skb_cb; |
3cc0fef6 | 51 | struct ath10k_txq *artxq; |
1f8bb151 | 52 | struct sk_buff *msdu; |
5e3dd157 | 53 | |
55314fc2 | 54 | ath10k_dbg(ar, ATH10K_DBG_HTT, |
59465fe4 RM |
55 | "htt tx completion msdu_id %u status %d\n", |
56 | tx_done->msdu_id, tx_done->status); | |
5e3dd157 | 57 | |
0a89f8a0 | 58 | if (tx_done->msdu_id >= htt->max_num_pending_tx) { |
7aa7a72a | 59 | ath10k_warn(ar, "warning: msdu_id %d too big, ignoring\n", |
0a89f8a0 | 60 | tx_done->msdu_id); |
cac08552 | 61 | return -EINVAL; |
0a89f8a0 MK |
62 | } |
63 | ||
005fb161 | 64 | spin_lock_bh(&htt->tx_lock); |
89d6d835 MK |
65 | msdu = idr_find(&htt->pending_tx, tx_done->msdu_id); |
66 | if (!msdu) { | |
67 | ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n", | |
68 | tx_done->msdu_id); | |
005fb161 | 69 | spin_unlock_bh(&htt->tx_lock); |
cac08552 | 70 | return -ENOENT; |
89d6d835 | 71 | } |
7b7da0a0 | 72 | |
d668dbae | 73 | skb_cb = ATH10K_SKB_CB(msdu); |
3cc0fef6 | 74 | txq = skb_cb->txq; |
7b7da0a0 | 75 | |
a66cd733 BC |
76 | if (txq) { |
77 | artxq = (void *)txq->drv_priv; | |
3cc0fef6 | 78 | artxq->num_fw_queued--; |
a66cd733 | 79 | } |
3cc0fef6 | 80 | |
005fb161 | 81 | ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); |
cac08552 | 82 | ath10k_htt_tx_dec_pending(htt); |
005fb161 QZ |
83 | if (htt->num_pending_tx == 0) |
84 | wake_up(&htt->empty_tx_wq); | |
85 | spin_unlock_bh(&htt->tx_lock); | |
89d6d835 | 86 | |
bb31b7cb | 87 | if (txq && txq->sta && skb_cb->airtime_est) |
d1ce37b7 KY |
88 | ieee80211_sta_register_airtime(txq->sta, txq->tid, |
89 | skb_cb->airtime_est, 0); | |
90 | ||
de8781d7 | 91 | if (ar->bus_param.dev_type != ATH10K_DEV_TYPE_HL) |
e66d5361 | 92 | dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); |
5e3dd157 KV |
93 | |
94 | ath10k_report_offchan_tx(htt->ar, msdu); | |
95 | ||
96 | info = IEEE80211_SKB_CB(msdu); | |
6d33a9a6 | 97 | memset(&info->status, 0, sizeof(info->status)); |
05a11003 MP |
98 | info->status.rates[0].idx = -1; |
99 | ||
d1e50f47 | 100 | trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id); |
5e3dd157 | 101 | |
5e3dd157 KV |
102 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) |
103 | info->flags |= IEEE80211_TX_STAT_ACK; | |
104 | ||
59465fe4 | 105 | if (tx_done->status == HTT_TX_COMPL_STATE_NOACK) |
5e3dd157 KV |
106 | info->flags &= ~IEEE80211_TX_STAT_ACK; |
107 | ||
59465fe4 RM |
108 | if ((tx_done->status == HTT_TX_COMPL_STATE_ACK) && |
109 | (info->flags & IEEE80211_TX_CTL_NO_ACK)) | |
55314fc2 SM |
110 | info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; |
111 | ||
abb374fe INH |
112 | if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) { |
113 | if (info->flags & IEEE80211_TX_CTL_NO_ACK) | |
114 | info->flags &= ~IEEE80211_TX_STAT_NOACK_TRANSMITTED; | |
115 | else | |
116 | info->flags &= ~IEEE80211_TX_STAT_ACK; | |
117 | } | |
118 | ||
235b9c42 VN |
119 | if (tx_done->status == HTT_TX_COMPL_STATE_ACK && |
120 | tx_done->ack_rssi != ATH10K_INVALID_RSSI) { | |
121 | info->status.ack_signal = ATH10K_DEFAULT_NOISE_FLOOR + | |
122 | tx_done->ack_rssi; | |
123 | info->status.is_valid_ack_signal = true; | |
124 | } | |
125 | ||
5e3dd157 KV |
126 | ieee80211_tx_status(htt->ar->hw, msdu); |
127 | /* we do not own the msdu anymore */ | |
7a0adc83 | 128 | |
cac08552 | 129 | return 0; |
5e3dd157 KV |
130 | } |
131 | ||
5e3dd157 KV |
132 | struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, |
133 | const u8 *addr) | |
134 | { | |
135 | struct ath10k_peer *peer; | |
136 | ||
137 | lockdep_assert_held(&ar->data_lock); | |
138 | ||
139 | list_for_each_entry(peer, &ar->peers, list) { | |
140 | if (peer->vdev_id != vdev_id) | |
141 | continue; | |
c178da58 | 142 | if (!ether_addr_equal(peer->addr, addr)) |
5e3dd157 KV |
143 | continue; |
144 | ||
145 | return peer; | |
146 | } | |
147 | ||
148 | return NULL; | |
149 | } | |
150 | ||
aa5b4fbc | 151 | struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id) |
5e3dd157 KV |
152 | { |
153 | struct ath10k_peer *peer; | |
154 | ||
49ed34b8 WG |
155 | if (peer_id >= BITS_PER_TYPE(peer->peer_ids)) |
156 | return NULL; | |
157 | ||
5e3dd157 KV |
158 | lockdep_assert_held(&ar->data_lock); |
159 | ||
160 | list_for_each_entry(peer, &ar->peers, list) | |
161 | if (test_bit(peer_id, peer->peer_ids)) | |
162 | return peer; | |
163 | ||
164 | return NULL; | |
165 | } | |
166 | ||
167 | static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id, | |
168 | const u8 *addr, bool expect_mapped) | |
169 | { | |
71c47df4 | 170 | long time_left; |
5e3dd157 | 171 | |
71c47df4 | 172 | time_left = wait_event_timeout(ar->peer_mapping_wq, ({ |
5e3dd157 KV |
173 | bool mapped; |
174 | ||
175 | spin_lock_bh(&ar->data_lock); | |
176 | mapped = !!ath10k_peer_find(ar, vdev_id, addr); | |
177 | spin_unlock_bh(&ar->data_lock); | |
178 | ||
7962b0d8 MK |
179 | (mapped == expect_mapped || |
180 | test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)); | |
14e105cd | 181 | }), 3 * HZ); |
5e3dd157 | 182 | |
71c47df4 | 183 | if (time_left == 0) |
5e3dd157 KV |
184 | return -ETIMEDOUT; |
185 | ||
186 | return 0; | |
187 | } | |
188 | ||
189 | int ath10k_wait_for_peer_created(struct ath10k *ar, int vdev_id, const u8 *addr) | |
190 | { | |
191 | return ath10k_wait_for_peer_common(ar, vdev_id, addr, true); | |
192 | } | |
193 | ||
194 | int ath10k_wait_for_peer_deleted(struct ath10k *ar, int vdev_id, const u8 *addr) | |
195 | { | |
196 | return ath10k_wait_for_peer_common(ar, vdev_id, addr, false); | |
197 | } | |
198 | ||
199 | void ath10k_peer_map_event(struct ath10k_htt *htt, | |
200 | struct htt_peer_map_event *ev) | |
201 | { | |
202 | struct ath10k *ar = htt->ar; | |
203 | struct ath10k_peer *peer; | |
204 | ||
de72a20d DC |
205 | if (ev->peer_id >= ATH10K_MAX_NUM_PEER_IDS) { |
206 | ath10k_warn(ar, | |
207 | "received htt peer map event with idx out of bounds: %hu\n", | |
208 | ev->peer_id); | |
209 | return; | |
210 | } | |
211 | ||
5e3dd157 KV |
212 | spin_lock_bh(&ar->data_lock); |
213 | peer = ath10k_peer_find(ar, ev->vdev_id, ev->addr); | |
214 | if (!peer) { | |
215 | peer = kzalloc(sizeof(*peer), GFP_ATOMIC); | |
216 | if (!peer) | |
217 | goto exit; | |
218 | ||
219 | peer->vdev_id = ev->vdev_id; | |
b25f32cb | 220 | ether_addr_copy(peer->addr, ev->addr); |
5e3dd157 KV |
221 | list_add(&peer->list, &ar->peers); |
222 | wake_up(&ar->peer_mapping_wq); | |
223 | } | |
224 | ||
7aa7a72a | 225 | ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n", |
5e3dd157 KV |
226 | ev->vdev_id, ev->addr, ev->peer_id); |
227 | ||
c5ace87a | 228 | WARN_ON(ar->peer_map[ev->peer_id] && (ar->peer_map[ev->peer_id] != peer)); |
6942726f | 229 | ar->peer_map[ev->peer_id] = peer; |
5e3dd157 KV |
230 | set_bit(ev->peer_id, peer->peer_ids); |
231 | exit: | |
232 | spin_unlock_bh(&ar->data_lock); | |
233 | } | |
234 | ||
235 | void ath10k_peer_unmap_event(struct ath10k_htt *htt, | |
236 | struct htt_peer_unmap_event *ev) | |
237 | { | |
238 | struct ath10k *ar = htt->ar; | |
239 | struct ath10k_peer *peer; | |
240 | ||
de72a20d DC |
241 | if (ev->peer_id >= ATH10K_MAX_NUM_PEER_IDS) { |
242 | ath10k_warn(ar, | |
243 | "received htt peer unmap event with idx out of bounds: %hu\n", | |
244 | ev->peer_id); | |
245 | return; | |
246 | } | |
247 | ||
5e3dd157 KV |
248 | spin_lock_bh(&ar->data_lock); |
249 | peer = ath10k_peer_find_by_id(ar, ev->peer_id); | |
250 | if (!peer) { | |
7aa7a72a | 251 | ath10k_warn(ar, "peer-unmap-event: unknown peer id %d\n", |
9ba4c787 | 252 | ev->peer_id); |
5e3dd157 KV |
253 | goto exit; |
254 | } | |
255 | ||
7aa7a72a | 256 | ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n", |
5e3dd157 KV |
257 | peer->vdev_id, peer->addr, ev->peer_id); |
258 | ||
6942726f | 259 | ar->peer_map[ev->peer_id] = NULL; |
5e3dd157 KV |
260 | clear_bit(ev->peer_id, peer->peer_ids); |
261 | ||
262 | if (bitmap_empty(peer->peer_ids, ATH10K_MAX_NUM_PEER_IDS)) { | |
263 | list_del(&peer->list); | |
264 | kfree(peer); | |
265 | wake_up(&ar->peer_mapping_wq); | |
266 | } | |
267 | ||
268 | exit: | |
269 | spin_unlock_bh(&ar->data_lock); | |
270 | } |