Commit | Line | Data |
---|---|---|
5e3dd157 KV |
1 | /* |
2 | * Copyright (c) 2005-2011 Atheros Communications Inc. | |
3 | * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. | |
4 | * | |
5 | * Permission to use, copy, modify, and/or distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
18 | #include "core.h" | |
19 | #include "txrx.h" | |
20 | #include "htt.h" | |
21 | #include "mac.h" | |
22 | #include "debug.h" | |
23 | ||
24 | static void ath10k_report_offchan_tx(struct ath10k *ar, struct sk_buff *skb) | |
25 | { | |
26 | if (!ATH10K_SKB_CB(skb)->htt.is_offchan) | |
27 | return; | |
28 | ||
29 | /* If the original wait_for_completion() timed out before | |
30 | * {data,mgmt}_tx_completed() was called then we could complete | |
31 | * offchan_tx_completed for a different skb. Prevent this by using | |
32 | * offchan_tx_skb. */ | |
33 | spin_lock_bh(&ar->data_lock); | |
34 | if (ar->offchan_tx_skb != skb) { | |
7aa7a72a | 35 | ath10k_warn(ar, "completed old offchannel frame\n"); |
5e3dd157 KV |
36 | goto out; |
37 | } | |
38 | ||
39 | complete(&ar->offchan_tx_completed); | |
40 | ar->offchan_tx_skb = NULL; /* just for sanity */ | |
41 | ||
7aa7a72a | 42 | ath10k_dbg(ar, ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb); |
5e3dd157 KV |
43 | out: |
44 | spin_unlock_bh(&ar->data_lock); | |
45 | } | |
46 | ||
0a89f8a0 MK |
47 | void ath10k_txrx_tx_unref(struct ath10k_htt *htt, |
48 | const struct htt_tx_done *tx_done) | |
5e3dd157 | 49 | { |
7aa7a72a MK |
50 | struct ath10k *ar = htt->ar; |
51 | struct device *dev = ar->dev; | |
5e3dd157 | 52 | struct ieee80211_tx_info *info; |
1f8bb151 MK |
53 | struct ath10k_skb_cb *skb_cb; |
54 | struct sk_buff *msdu; | |
7b7da0a0 VN |
55 | struct ieee80211_hdr *hdr; |
56 | __le16 fc; | |
57 | bool limit_mgmt_desc = false; | |
5e3dd157 | 58 | |
55314fc2 SM |
59 | ath10k_dbg(ar, ATH10K_DBG_HTT, |
60 | "htt tx completion msdu_id %u discard %d no_ack %d success %d\n", | |
61 | tx_done->msdu_id, !!tx_done->discard, | |
62 | !!tx_done->no_ack, !!tx_done->success); | |
5e3dd157 | 63 | |
0a89f8a0 | 64 | if (tx_done->msdu_id >= htt->max_num_pending_tx) { |
7aa7a72a | 65 | ath10k_warn(ar, "warning: msdu_id %d too big, ignoring\n", |
0a89f8a0 | 66 | tx_done->msdu_id); |
5e3dd157 | 67 | return; |
0a89f8a0 MK |
68 | } |
69 | ||
005fb161 | 70 | spin_lock_bh(&htt->tx_lock); |
89d6d835 MK |
71 | msdu = idr_find(&htt->pending_tx, tx_done->msdu_id); |
72 | if (!msdu) { | |
73 | ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n", | |
74 | tx_done->msdu_id); | |
005fb161 | 75 | spin_unlock_bh(&htt->tx_lock); |
89d6d835 MK |
76 | return; |
77 | } | |
7b7da0a0 VN |
78 | |
79 | hdr = (struct ieee80211_hdr *)msdu->data; | |
80 | fc = hdr->frame_control; | |
81 | ||
82 | if (unlikely(ieee80211_is_mgmt(fc)) && | |
83 | ar->hw_params.max_probe_resp_desc_thres) | |
84 | limit_mgmt_desc = true; | |
85 | ||
005fb161 | 86 | ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); |
7b7da0a0 | 87 | __ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc); |
005fb161 QZ |
88 | if (htt->num_pending_tx == 0) |
89 | wake_up(&htt->empty_tx_wq); | |
90 | spin_unlock_bh(&htt->tx_lock); | |
89d6d835 | 91 | |
1f8bb151 | 92 | skb_cb = ATH10K_SKB_CB(msdu); |
767d34fc | 93 | dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); |
5e3dd157 | 94 | |
a16942e6 MK |
95 | if (skb_cb->htt.txbuf) |
96 | dma_pool_free(htt->tx_pool, | |
97 | skb_cb->htt.txbuf, | |
98 | skb_cb->htt.txbuf_paddr); | |
1f8bb151 | 99 | |
5e3dd157 KV |
100 | ath10k_report_offchan_tx(htt->ar, msdu); |
101 | ||
102 | info = IEEE80211_SKB_CB(msdu); | |
6d33a9a6 | 103 | memset(&info->status, 0, sizeof(info->status)); |
d1e50f47 | 104 | trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id); |
5e3dd157 | 105 | |
0a89f8a0 | 106 | if (tx_done->discard) { |
5e3dd157 | 107 | ieee80211_free_txskb(htt->ar->hw, msdu); |
005fb161 | 108 | return; |
5e3dd157 KV |
109 | } |
110 | ||
111 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) | |
112 | info->flags |= IEEE80211_TX_STAT_ACK; | |
113 | ||
0a89f8a0 | 114 | if (tx_done->no_ack) |
5e3dd157 KV |
115 | info->flags &= ~IEEE80211_TX_STAT_ACK; |
116 | ||
55314fc2 SM |
117 | if (tx_done->success && (info->flags & IEEE80211_TX_CTL_NO_ACK)) |
118 | info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; | |
119 | ||
5e3dd157 KV |
120 | ieee80211_tx_status(htt->ar->hw, msdu); |
121 | /* we do not own the msdu anymore */ | |
5e3dd157 KV |
122 | } |
123 | ||
5e3dd157 KV |
124 | struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, |
125 | const u8 *addr) | |
126 | { | |
127 | struct ath10k_peer *peer; | |
128 | ||
129 | lockdep_assert_held(&ar->data_lock); | |
130 | ||
131 | list_for_each_entry(peer, &ar->peers, list) { | |
132 | if (peer->vdev_id != vdev_id) | |
133 | continue; | |
134 | if (memcmp(peer->addr, addr, ETH_ALEN)) | |
135 | continue; | |
136 | ||
137 | return peer; | |
138 | } | |
139 | ||
140 | return NULL; | |
141 | } | |
142 | ||
aa5b4fbc | 143 | struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id) |
5e3dd157 KV |
144 | { |
145 | struct ath10k_peer *peer; | |
146 | ||
147 | lockdep_assert_held(&ar->data_lock); | |
148 | ||
149 | list_for_each_entry(peer, &ar->peers, list) | |
150 | if (test_bit(peer_id, peer->peer_ids)) | |
151 | return peer; | |
152 | ||
153 | return NULL; | |
154 | } | |
155 | ||
156 | static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id, | |
157 | const u8 *addr, bool expect_mapped) | |
158 | { | |
71c47df4 | 159 | long time_left; |
5e3dd157 | 160 | |
71c47df4 | 161 | time_left = wait_event_timeout(ar->peer_mapping_wq, ({ |
5e3dd157 KV |
162 | bool mapped; |
163 | ||
164 | spin_lock_bh(&ar->data_lock); | |
165 | mapped = !!ath10k_peer_find(ar, vdev_id, addr); | |
166 | spin_unlock_bh(&ar->data_lock); | |
167 | ||
7962b0d8 MK |
168 | (mapped == expect_mapped || |
169 | test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)); | |
5e3dd157 KV |
170 | }), 3*HZ); |
171 | ||
71c47df4 | 172 | if (time_left == 0) |
5e3dd157 KV |
173 | return -ETIMEDOUT; |
174 | ||
175 | return 0; | |
176 | } | |
177 | ||
178 | int ath10k_wait_for_peer_created(struct ath10k *ar, int vdev_id, const u8 *addr) | |
179 | { | |
180 | return ath10k_wait_for_peer_common(ar, vdev_id, addr, true); | |
181 | } | |
182 | ||
183 | int ath10k_wait_for_peer_deleted(struct ath10k *ar, int vdev_id, const u8 *addr) | |
184 | { | |
185 | return ath10k_wait_for_peer_common(ar, vdev_id, addr, false); | |
186 | } | |
187 | ||
188 | void ath10k_peer_map_event(struct ath10k_htt *htt, | |
189 | struct htt_peer_map_event *ev) | |
190 | { | |
191 | struct ath10k *ar = htt->ar; | |
192 | struct ath10k_peer *peer; | |
193 | ||
194 | spin_lock_bh(&ar->data_lock); | |
195 | peer = ath10k_peer_find(ar, ev->vdev_id, ev->addr); | |
196 | if (!peer) { | |
197 | peer = kzalloc(sizeof(*peer), GFP_ATOMIC); | |
198 | if (!peer) | |
199 | goto exit; | |
200 | ||
201 | peer->vdev_id = ev->vdev_id; | |
b25f32cb | 202 | ether_addr_copy(peer->addr, ev->addr); |
5e3dd157 KV |
203 | list_add(&peer->list, &ar->peers); |
204 | wake_up(&ar->peer_mapping_wq); | |
205 | } | |
206 | ||
7aa7a72a | 207 | ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n", |
5e3dd157 KV |
208 | ev->vdev_id, ev->addr, ev->peer_id); |
209 | ||
210 | set_bit(ev->peer_id, peer->peer_ids); | |
211 | exit: | |
212 | spin_unlock_bh(&ar->data_lock); | |
213 | } | |
214 | ||
215 | void ath10k_peer_unmap_event(struct ath10k_htt *htt, | |
216 | struct htt_peer_unmap_event *ev) | |
217 | { | |
218 | struct ath10k *ar = htt->ar; | |
219 | struct ath10k_peer *peer; | |
220 | ||
221 | spin_lock_bh(&ar->data_lock); | |
222 | peer = ath10k_peer_find_by_id(ar, ev->peer_id); | |
223 | if (!peer) { | |
7aa7a72a | 224 | ath10k_warn(ar, "peer-unmap-event: unknown peer id %d\n", |
9ba4c787 | 225 | ev->peer_id); |
5e3dd157 KV |
226 | goto exit; |
227 | } | |
228 | ||
7aa7a72a | 229 | ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n", |
5e3dd157 KV |
230 | peer->vdev_id, peer->addr, ev->peer_id); |
231 | ||
232 | clear_bit(ev->peer_id, peer->peer_ids); | |
233 | ||
234 | if (bitmap_empty(peer->peer_ids, ATH10K_MAX_NUM_PEER_IDS)) { | |
235 | list_del(&peer->list); | |
236 | kfree(peer); | |
237 | wake_up(&ar->peer_mapping_wq); | |
238 | } | |
239 | ||
240 | exit: | |
241 | spin_unlock_bh(&ar->data_lock); | |
242 | } |