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