1 /*
2 * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /**
21 * @file htt_rx.c
22 * @brief Implement receive aspects of HTT.
23 * @details
24 * This file contains three categories of HTT rx code:
25 * 1. An abstraction of the rx descriptor, to hide the
26 * differences between the HL vs. LL rx descriptor.
27 * 2. Functions for providing access to the (series of)
28 * rx descriptor(s) and rx frame(s) associated with
29 * an rx indication message.
30 * 3. Functions for setting up and using the MAC DMA
31 * rx ring (applies to LL only).
32 */
33
34 #include <qdf_mem.h> /* qdf_mem_malloc,free, etc. */
35 #include <qdf_types.h> /* qdf_print, bool */
36 #include <qdf_nbuf.h> /* qdf_nbuf_t, etc. */
37 #include <qdf_timer.h> /* qdf_timer_free */
38
39 #include <htt.h> /* HTT_HL_RX_DESC_SIZE */
40 #include <ol_cfg.h>
41 #include <ol_rx.h>
42 #include <ol_htt_rx_api.h>
43 #include <htt_internal.h> /* HTT_ASSERT, htt_pdev_t, HTT_RX_BUF_SIZE */
44 #include "regtable.h"
45
46 #include <cds_ieee80211_common.h> /* ieee80211_frame, ieee80211_qoscntl */
47 #include <cds_utils.h>
48 #include <wlan_policy_mgr_api.h>
49 #include "ol_txrx_types.h"
50 #ifdef DEBUG_DMA_DONE
51 #include <asm/barrier.h>
52 #include <wma_api.h>
53 #endif
54 #include <pktlog_ac_fmt.h>
55
56 /**
57 * htt_rx_mpdu_wifi_hdr_retrieve() - retrieve 802.11 header
58 * @pdev - pdev handle
59 * @mpdu_desc - mpdu descriptor
60 *
61 * Return : pointer to 802.11 header
62 */
htt_rx_mpdu_wifi_hdr_retrieve(htt_pdev_handle pdev,void * mpdu_desc)63 char *htt_rx_mpdu_wifi_hdr_retrieve(htt_pdev_handle pdev, void *mpdu_desc)
64 {
65 struct htt_host_rx_desc_base *rx_desc =
66 (struct htt_host_rx_desc_base *)mpdu_desc;
67
68 if (!rx_desc)
69 return NULL;
70 else
71 return rx_desc->rx_hdr_status;
72 }
73
74 /**
75 * htt_rx_mpdu_desc_tsf32() - Return the TSF timestamp indicating when
76 * a MPDU was received.
77 * @pdev - the HTT instance the rx data was received on
78 * @mpdu_desc - the abstract descriptor for the MPDU in question
79 *
80 * return : 32 LSBs of TSF time at which the MPDU's PPDU was received
81 */
htt_rx_mpdu_desc_tsf32(htt_pdev_handle pdev,void * mpdu_desc)82 uint32_t htt_rx_mpdu_desc_tsf32(htt_pdev_handle pdev, void *mpdu_desc)
83 {
84 return 0;
85 }
86
87 static inline
htt_rx_msdu_fw_desc_get(htt_pdev_handle pdev,void * msdu_desc)88 uint8_t htt_rx_msdu_fw_desc_get(htt_pdev_handle pdev, void *msdu_desc)
89 {
90 /*
91 * HL and LL use the same format for FW rx desc, but have the FW rx desc
92 * in different locations.
93 * In LL, the FW rx descriptor has been copied into the same
94 * htt_host_rx_desc_base struct that holds the HW rx desc.
95 * In HL, the FW rx descriptor, along with the MSDU payload,
96 * is in the same buffer as the rx indication message.
97 *
98 * Use the FW rx desc offset configured during startup to account for
99 * this difference between HL vs. LL.
100 *
101 * An optimization would be to define the LL and HL msdu_desc pointer
102 * in such a way that they both use the same offset to the FW rx desc.
103 * Then the following functions could be converted to macros, without
104 * needing to expose the htt_pdev_t definition outside HTT.
105 */
106 return *(((uint8_t *)msdu_desc) + pdev->rx_fw_desc_offset);
107 }
108
htt_rx_msdu_discard(htt_pdev_handle pdev,void * msdu_desc)109 int htt_rx_msdu_discard(htt_pdev_handle pdev, void *msdu_desc)
110 {
111 return htt_rx_msdu_fw_desc_get(pdev, msdu_desc) & FW_RX_DESC_DISCARD_M;
112 }
113
htt_rx_msdu_forward(htt_pdev_handle pdev,void * msdu_desc)114 int htt_rx_msdu_forward(htt_pdev_handle pdev, void *msdu_desc)
115 {
116 return htt_rx_msdu_fw_desc_get(pdev, msdu_desc) & FW_RX_DESC_FORWARD_M;
117 }
118
htt_rx_msdu_inspect(htt_pdev_handle pdev,void * msdu_desc)119 int htt_rx_msdu_inspect(htt_pdev_handle pdev, void *msdu_desc)
120 {
121 return htt_rx_msdu_fw_desc_get(pdev, msdu_desc) & FW_RX_DESC_INSPECT_M;
122 }
123
124 void
htt_rx_msdu_actions(htt_pdev_handle pdev,void * msdu_desc,int * discard,int * forward,int * inspect)125 htt_rx_msdu_actions(htt_pdev_handle pdev,
126 void *msdu_desc, int *discard, int *forward, int *inspect)
127 {
128 uint8_t rx_msdu_fw_desc = htt_rx_msdu_fw_desc_get(pdev, msdu_desc);
129 #ifdef HTT_DEBUG_DATA
130 HTT_PRINT("act:0x%x ", rx_msdu_fw_desc);
131 #endif
132 *discard = rx_msdu_fw_desc & FW_RX_DESC_DISCARD_M;
133 *forward = rx_msdu_fw_desc & FW_RX_DESC_FORWARD_M;
134 *inspect = rx_msdu_fw_desc & FW_RX_DESC_INSPECT_M;
135 }
136
htt_rx_amsdu_rx_in_order_get_pktlog(qdf_nbuf_t rx_ind_msg)137 uint32_t htt_rx_amsdu_rx_in_order_get_pktlog(qdf_nbuf_t rx_ind_msg)
138 {
139 uint32_t *msg_word;
140
141 msg_word = (uint32_t *)qdf_nbuf_data(rx_ind_msg);
142 return HTT_RX_IN_ORD_PADDR_IND_PKTLOG_GET(*msg_word);
143 }
144
htt_rx_mpdu_desc_rssi_dbm(htt_pdev_handle pdev,void * mpdu_desc)145 int16_t htt_rx_mpdu_desc_rssi_dbm(htt_pdev_handle pdev, void *mpdu_desc)
146 {
147 /*
148 * Currently the RSSI is provided only as a field in the
149 * HTT_T2H_RX_IND message, rather than in each rx descriptor.
150 */
151 return HTT_RSSI_INVALID;
152 }
153
154 /*
155 * htt_rx_amsdu_pop -
156 * global function pointer that is programmed during attach to point
157 * to either htt_rx_amsdu_pop_ll or htt_rx_amsdu_rx_in_order_pop_ll.
158 */
159 int (*htt_rx_amsdu_pop)(htt_pdev_handle pdev,
160 qdf_nbuf_t rx_ind_msg,
161 qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu,
162 uint32_t *msdu_count);
163
164 /*
165 * htt_rx_frag_pop -
166 * global function pointer that is programmed during attach to point
167 * to either htt_rx_amsdu_pop_ll
168 */
169 int (*htt_rx_frag_pop)(htt_pdev_handle pdev,
170 qdf_nbuf_t rx_ind_msg,
171 qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu,
172 uint32_t *msdu_count);
173
174 int (*htt_rx_offload_msdu_cnt)(htt_pdev_handle pdev);
175
176 int
177 (*htt_rx_offload_msdu_pop)(htt_pdev_handle pdev,
178 qdf_nbuf_t offload_deliver_msg,
179 int *vdev_id,
180 int *peer_id,
181 int *tid,
182 uint8_t *fw_desc,
183 qdf_nbuf_t *head_buf, qdf_nbuf_t *tail_buf);
184
185 void * (*htt_rx_mpdu_desc_list_next)(htt_pdev_handle pdev,
186 qdf_nbuf_t rx_ind_msg);
187
188 bool (*htt_rx_mpdu_desc_retry)(htt_pdev_handle pdev, void *mpdu_desc);
189
190 uint16_t (*htt_rx_mpdu_desc_seq_num)(htt_pdev_handle pdev, void *mpdu_desc,
191 bool update_seq_num);
192
193 void (*htt_rx_mpdu_desc_pn)(htt_pdev_handle pdev,
194 void *mpdu_desc,
195 union htt_rx_pn_t *pn, int pn_len_bits);
196
197 uint8_t (*htt_rx_mpdu_desc_tid)(htt_pdev_handle pdev, void *mpdu_desc);
198
199 bool (*htt_rx_msdu_desc_completes_mpdu)(htt_pdev_handle pdev, void *msdu_desc);
200
201 bool (*htt_rx_msdu_first_msdu_flag)(htt_pdev_handle pdev, void *msdu_desc);
202
203 int (*htt_rx_msdu_has_wlan_mcast_flag)(htt_pdev_handle pdev, void *msdu_desc);
204
205 bool (*htt_rx_msdu_is_wlan_mcast)(htt_pdev_handle pdev, void *msdu_desc);
206
207 int (*htt_rx_msdu_is_frag)(htt_pdev_handle pdev, void *msdu_desc);
208
209 void * (*htt_rx_msdu_desc_retrieve)(htt_pdev_handle pdev, qdf_nbuf_t msdu);
210
211 bool (*htt_rx_mpdu_is_encrypted)(htt_pdev_handle pdev, void *mpdu_desc);
212
213 bool (*htt_rx_msdu_desc_key_id)(htt_pdev_handle pdev,
214 void *mpdu_desc, uint8_t *key_id);
215
216 bool (*htt_rx_msdu_chan_info_present)(
217 htt_pdev_handle pdev,
218 void *mpdu_desc);
219
220 bool (*htt_rx_msdu_center_freq)(
221 htt_pdev_handle pdev,
222 struct ol_txrx_peer_t *peer,
223 void *mpdu_desc,
224 uint16_t *primary_chan_center_freq_mhz,
225 uint16_t *contig_chan1_center_freq_mhz,
226 uint16_t *contig_chan2_center_freq_mhz,
227 uint8_t *phy_mode);
228
htt_rx_desc_frame_free(htt_pdev_handle htt_pdev,qdf_nbuf_t msdu)229 void htt_rx_desc_frame_free(htt_pdev_handle htt_pdev, qdf_nbuf_t msdu)
230 {
231 qdf_nbuf_free(msdu);
232 }
233
htt_rx_msdu_desc_free(htt_pdev_handle htt_pdev,qdf_nbuf_t msdu)234 void htt_rx_msdu_desc_free(htt_pdev_handle htt_pdev, qdf_nbuf_t msdu)
235 {
236 /*
237 * The rx descriptor is in the same buffer as the rx MSDU payload,
238 * and does not need to be freed separately.
239 */
240 }
241
htt_rx_msdu_buff_replenish(htt_pdev_handle pdev)242 void htt_rx_msdu_buff_replenish(htt_pdev_handle pdev)
243 {
244 if (qdf_atomic_dec_and_test(&pdev->rx_ring.refill_ref_cnt))
245 htt_rx_fill_ring_count(pdev);
246
247 qdf_atomic_inc(&pdev->rx_ring.refill_ref_cnt);
248 }
249
250 #ifdef IPA_OFFLOAD
251 #ifdef QCA_WIFI_3_0
252 /**
253 * htt_rx_ipa_uc_alloc_wdi2_rsc() - Allocate WDI2.0 resources
254 * @pdev: htt context
255 * @rx_ind_ring_elements: rx ring elements
256 *
257 * Return: 0 success
258 */
htt_rx_ipa_uc_alloc_wdi2_rsc(struct htt_pdev_t * pdev,unsigned int rx_ind_ring_elements)259 static int htt_rx_ipa_uc_alloc_wdi2_rsc(struct htt_pdev_t *pdev,
260 unsigned int rx_ind_ring_elements)
261 {
262 /*
263 * Allocate RX2 indication ring
264 * RX2 IND ring element
265 * 4bytes: pointer
266 * 2bytes: VDEV ID
267 * 2bytes: length
268 *
269 * RX indication ring size, by bytes
270 */
271 pdev->ipa_uc_rx_rsc.rx2_ind_ring =
272 qdf_mem_shared_mem_alloc(pdev->osdev,
273 rx_ind_ring_elements *
274 sizeof(target_paddr_t));
275 if (!pdev->ipa_uc_rx_rsc.rx2_ind_ring) {
276 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR,
277 "%s: Unable to allocate memory for IPA rx2 ind ring",
278 __func__);
279 return 1;
280 }
281
282 pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx =
283 qdf_mem_shared_mem_alloc(pdev->osdev, 4);
284 if (!pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx) {
285 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR,
286 "%s: Unable to allocate memory for IPA rx proc done index",
287 __func__);
288 qdf_mem_shared_mem_free(pdev->osdev,
289 pdev->ipa_uc_rx_rsc.rx2_ind_ring);
290 return 1;
291 }
292
293 return 0;
294 }
295
296 /**
297 * htt_rx_ipa_uc_free_wdi2_rsc() - Free WDI2.0 resources
298 * @pdev: htt context
299 *
300 * Return: None
301 */
htt_rx_ipa_uc_free_wdi2_rsc(struct htt_pdev_t * pdev)302 static void htt_rx_ipa_uc_free_wdi2_rsc(struct htt_pdev_t *pdev)
303 {
304 qdf_mem_shared_mem_free(pdev->osdev, pdev->ipa_uc_rx_rsc.rx2_ind_ring);
305 qdf_mem_shared_mem_free(pdev->osdev,
306 pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx);
307 }
308 #else
htt_rx_ipa_uc_alloc_wdi2_rsc(struct htt_pdev_t * pdev,unsigned int rx_ind_ring_elements)309 static int htt_rx_ipa_uc_alloc_wdi2_rsc(struct htt_pdev_t *pdev,
310 unsigned int rx_ind_ring_elements)
311 {
312 return 0;
313 }
314
htt_rx_ipa_uc_free_wdi2_rsc(struct htt_pdev_t * pdev)315 static void htt_rx_ipa_uc_free_wdi2_rsc(struct htt_pdev_t *pdev)
316 {
317 }
318 #endif
319
320 /**
321 * htt_rx_ipa_uc_attach() - attach htt ipa uc rx resource
322 * @pdev: htt context
323 * @rx_ind_ring_size: rx ring size
324 *
325 * Return: 0 success
326 */
htt_rx_ipa_uc_attach(struct htt_pdev_t * pdev,unsigned int rx_ind_ring_elements)327 int htt_rx_ipa_uc_attach(struct htt_pdev_t *pdev,
328 unsigned int rx_ind_ring_elements)
329 {
330 int ret = 0;
331
332 /*
333 * Allocate RX indication ring
334 * RX IND ring element
335 * 4bytes: pointer
336 * 2bytes: VDEV ID
337 * 2bytes: length
338 */
339 pdev->ipa_uc_rx_rsc.rx_ind_ring =
340 qdf_mem_shared_mem_alloc(pdev->osdev,
341 rx_ind_ring_elements *
342 sizeof(struct ipa_uc_rx_ring_elem_t));
343 if (!pdev->ipa_uc_rx_rsc.rx_ind_ring) {
344 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR,
345 "%s: Unable to allocate memory for IPA rx ind ring",
346 __func__);
347 return 1;
348 }
349
350 pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx =
351 qdf_mem_shared_mem_alloc(pdev->osdev, 4);
352 if (!pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx) {
353 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR,
354 "%s: Unable to allocate memory for IPA rx proc done index",
355 __func__);
356 qdf_mem_shared_mem_free(pdev->osdev,
357 pdev->ipa_uc_rx_rsc.rx_ind_ring);
358 return 1;
359 }
360
361 ret = htt_rx_ipa_uc_alloc_wdi2_rsc(pdev, rx_ind_ring_elements);
362 if (ret) {
363 qdf_mem_shared_mem_free(pdev->osdev, pdev->ipa_uc_rx_rsc.rx_ind_ring);
364 qdf_mem_shared_mem_free(pdev->osdev,
365 pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx);
366 }
367 return ret;
368 }
369
htt_rx_ipa_uc_detach(struct htt_pdev_t * pdev)370 int htt_rx_ipa_uc_detach(struct htt_pdev_t *pdev)
371 {
372 qdf_mem_shared_mem_free(pdev->osdev, pdev->ipa_uc_rx_rsc.rx_ind_ring);
373 qdf_mem_shared_mem_free(pdev->osdev,
374 pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx);
375
376 htt_rx_ipa_uc_free_wdi2_rsc(pdev);
377 return 0;
378 }
379 #endif /* IPA_OFFLOAD */
380
381 #ifdef CONNECTIVITY_PKTLOG
382 /**
383 * htt_register_rx_pkt_dump_callback() - registers callback to
384 * get rx pkt status and call callback to do rx packet dump
385 *
386 * @pdev: htt pdev handle
387 * @callback: callback to get rx pkt status and
388 * call callback to do rx packet dump
389 *
390 * This function is used to register the callback to get
391 * rx pkt status and call callback to do rx packet dump
392 *
393 * Return: None
394 *
395 */
htt_register_rx_pkt_dump_callback(struct htt_pdev_t * pdev,tp_rx_pkt_dump_cb callback)396 void htt_register_rx_pkt_dump_callback(struct htt_pdev_t *pdev,
397 tp_rx_pkt_dump_cb callback)
398 {
399 if (!pdev) {
400 qdf_print("pdev is NULL");
401 return;
402 }
403 pdev->rx_pkt_dump_cb = callback;
404 }
405
406 /**
407 * htt_deregister_rx_pkt_dump_callback() - deregisters callback to
408 * get rx pkt status and call callback to do rx packet dump
409 *
410 * @pdev: htt pdev handle
411 *
412 * This function is used to deregister the callback to get
413 * rx pkt status and call callback to do rx packet dump
414 *
415 * Return: None
416 *
417 */
htt_deregister_rx_pkt_dump_callback(struct htt_pdev_t * pdev)418 void htt_deregister_rx_pkt_dump_callback(struct htt_pdev_t *pdev)
419 {
420 if (!pdev) {
421 qdf_print("pdev is NULL");
422 return;
423 }
424 pdev->rx_pkt_dump_cb = NULL;
425 }
426 #endif
427
428 #ifdef WLAN_FEATURE_TSF_PLUS
htt_rx_enable_ppdu_end(int * enable_ppdu_end)429 void htt_rx_enable_ppdu_end(int *enable_ppdu_end)
430 {
431 *enable_ppdu_end = 1;
432 }
433 #endif
434