1 /*
2 * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 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 * DOC: htt_t2h.c
22 *
23 * brief Provide functions to process target->host HTT messages.
24 * details
25 * This file contains functions related to target->host HTT messages.
26 * There are two categories of functions:
27 * 1. A function that receives a HTT message from HTC, and dispatches it
28 * based on the HTT message type.
29 * 2. functions that provide the info elements from specific HTT messages.
30 */
31 #include <wma.h>
32 #include <htc_api.h> /* HTC_PACKET */
33 #include <htt.h> /* HTT_T2H_MSG_TYPE, etc. */
34 #include <qdf_nbuf.h> /* qdf_nbuf_t */
35
36 #include <ol_rx.h>
37 #include <ol_htt_rx_api.h>
38 #include <ol_htt_tx_api.h>
39 #include <ol_txrx_htt_api.h> /* htt_tx_status */
40
41 #include <htt_internal.h> /* HTT_TX_SCHED, etc. */
42 #include <pktlog_ac_fmt.h>
43 #include <wdi_event.h>
44 #include <ol_htt_tx_api.h>
45 #include <ol_txrx_peer_find.h>
46 #include <cdp_txrx_ipa.h>
47 #include "pktlog_ac.h"
48 #include <cdp_txrx_handle.h>
49 #include <wlan_pkt_capture_ucfg_api.h>
50 #include <ol_txrx.h>
51 /*--- target->host HTT message dispatch function ----------------------------*/
52
53 #ifndef DEBUG_CREDIT
54 #define DEBUG_CREDIT 0
55 #endif
56
57 #if defined(CONFIG_HL_SUPPORT)
58
59
60
61 /**
62 * htt_rx_frag_set_last_msdu() - set last msdu bit in rx descriptor
63 * for received frames
64 * @pdev: Handle (pointer) to HTT pdev.
65 * @msg: htt received msg
66 *
67 * Return: None
68 */
69 static inline
htt_rx_frag_set_last_msdu(struct htt_pdev_t * pdev,qdf_nbuf_t msg)70 void htt_rx_frag_set_last_msdu(struct htt_pdev_t *pdev, qdf_nbuf_t msg)
71 {
72 }
73 #else
74
htt_rx_frag_set_last_msdu(struct htt_pdev_t * pdev,qdf_nbuf_t msg)75 static void htt_rx_frag_set_last_msdu(struct htt_pdev_t *pdev, qdf_nbuf_t msg)
76 {
77 uint32_t *msg_word;
78 unsigned int num_msdu_bytes;
79 qdf_nbuf_t msdu;
80 struct htt_host_rx_desc_base *rx_desc;
81 int start_idx;
82 uint8_t *p_fw_msdu_rx_desc = 0;
83
84 msg_word = (uint32_t *) qdf_nbuf_data(msg);
85 num_msdu_bytes = HTT_RX_FRAG_IND_FW_RX_DESC_BYTES_GET(
86 *(msg_word + HTT_RX_FRAG_IND_HDR_PREFIX_SIZE32));
87 /*
88 * 1 word for the message header,
89 * 1 word to specify the number of MSDU bytes,
90 * 1 word for every 4 MSDU bytes (round up),
91 * 1 word for the MPDU range header
92 */
93 pdev->rx_mpdu_range_offset_words = 3 + ((num_msdu_bytes + 3) >> 2);
94 pdev->rx_ind_msdu_byte_idx = 0;
95
96 p_fw_msdu_rx_desc = ((uint8_t *) (msg_word) +
97 HTT_ENDIAN_BYTE_IDX_SWAP
98 (HTT_RX_FRAG_IND_FW_DESC_BYTE_OFFSET));
99
100 /*
101 * Fix for EV126710, in which BSOD occurs due to last_msdu bit
102 * not set while the next pointer is deliberately set to NULL
103 * before calling ol_rx_pn_check_base()
104 *
105 * For fragment frames, the HW may not have set the last_msdu bit
106 * in the rx descriptor, but the SW expects this flag to be set,
107 * since each fragment is in a separate MPDU. Thus, set the flag here,
108 * just in case the HW didn't.
109 */
110 start_idx = pdev->rx_ring.sw_rd_idx.msdu_payld;
111 msdu = pdev->rx_ring.buf.netbufs_ring[start_idx];
112 qdf_nbuf_set_pktlen(msdu, HTT_RX_BUF_SIZE);
113 qdf_nbuf_unmap(pdev->osdev, msdu, QDF_DMA_FROM_DEVICE);
114 rx_desc = htt_rx_desc(msdu);
115 *((uint8_t *) &rx_desc->fw_desc.u.val) = *p_fw_msdu_rx_desc;
116 rx_desc->msdu_end.last_msdu = 1;
117 qdf_nbuf_map(pdev->osdev, msdu, QDF_DMA_FROM_DEVICE);
118 }
119 #endif
120
htt_t2h_mac_addr_deswizzle(uint8_t * tgt_mac_addr,uint8_t * buffer)121 static uint8_t *htt_t2h_mac_addr_deswizzle(uint8_t *tgt_mac_addr,
122 uint8_t *buffer)
123 {
124 #ifdef BIG_ENDIAN_HOST
125 /*
126 * The host endianness is opposite of the target endianness.
127 * To make uint32_t elements come out correctly, the target->host
128 * upload has swizzled the bytes in each uint32_t element of the
129 * message.
130 * For byte-array message fields like the MAC address, this
131 * upload swizzling puts the bytes in the wrong order, and needs
132 * to be undone.
133 */
134 buffer[0] = tgt_mac_addr[3];
135 buffer[1] = tgt_mac_addr[2];
136 buffer[2] = tgt_mac_addr[1];
137 buffer[3] = tgt_mac_addr[0];
138 buffer[4] = tgt_mac_addr[7];
139 buffer[5] = tgt_mac_addr[6];
140 return buffer;
141 #else
142 /*
143 * The host endianness matches the target endianness -
144 * we can use the mac addr directly from the message buffer.
145 */
146 return tgt_mac_addr;
147 #endif
148 }
149
150 /**
151 * htt_ipa_op_response() - invoke an event handler from FW
152 * @pdev: Handle (pointer) to HTT pdev.
153 * @msg_word: htt msg
154 *
155 * Return: None
156 */
157 #ifdef IPA_OFFLOAD
htt_ipa_op_response(struct htt_pdev_t * pdev,uint32_t * msg_word)158 static void htt_ipa_op_response(struct htt_pdev_t *pdev, uint32_t *msg_word)
159 {
160 uint8_t op_code;
161 uint16_t len;
162 uint8_t *op_msg_buffer;
163 uint8_t *msg_start_ptr;
164
165 htc_pm_runtime_put(pdev->htc_pdev);
166 msg_start_ptr = (uint8_t *) msg_word;
167 op_code =
168 HTT_WDI_IPA_OP_RESPONSE_OP_CODE_GET(*msg_word);
169 msg_word++;
170 len = HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_GET(*msg_word);
171
172 op_msg_buffer =
173 qdf_mem_malloc(sizeof
174 (struct htt_wdi_ipa_op_response_t) +
175 len);
176 if (!op_msg_buffer)
177 return;
178
179 qdf_mem_copy(op_msg_buffer,
180 msg_start_ptr,
181 sizeof(struct htt_wdi_ipa_op_response_t) +
182 len);
183 cdp_ipa_op_response(cds_get_context(QDF_MODULE_ID_SOC),
184 OL_TXRX_PDEV_ID, op_msg_buffer);
185 }
186 #else
htt_ipa_op_response(struct htt_pdev_t * pdev,uint32_t * msg_word)187 static void htt_ipa_op_response(struct htt_pdev_t *pdev, uint32_t *msg_word)
188 {
189 }
190 #endif
191
192 #ifndef QCN7605_SUPPORT
htt_t2h_adjust_bus_target_delta(struct htt_pdev_t * pdev,int32_t htt_credit_delta)193 static int htt_t2h_adjust_bus_target_delta(struct htt_pdev_t *pdev,
194 int32_t htt_credit_delta)
195 {
196 if (pdev->cfg.is_high_latency && !pdev->cfg.default_tx_comp_req) {
197 HTT_TX_MUTEX_ACQUIRE(&pdev->credit_mutex);
198 qdf_atomic_add(htt_credit_delta,
199 &pdev->htt_tx_credit.target_delta);
200 htt_credit_delta = htt_tx_credit_update(pdev);
201 HTT_TX_MUTEX_RELEASE(&pdev->credit_mutex);
202 }
203 return htt_credit_delta;
204 }
205 #else
htt_t2h_adjust_bus_target_delta(struct htt_pdev_t * pdev,int32_t htt_credit_delta)206 static int htt_t2h_adjust_bus_target_delta(struct htt_pdev_t *pdev,
207 int32_t htt_credit_delta)
208 {
209 return htt_credit_delta;
210 }
211 #endif
212
213 #define MAX_TARGET_TX_CREDIT 204800
214 #define HTT_CFR_DUMP_COMPL_HEAD_SZ 4
215
216 /* Target to host Msg/event handler for low priority messages*/
htt_t2h_lp_msg_handler(void * context,qdf_nbuf_t htt_t2h_msg,bool free_msg_buf)217 static void htt_t2h_lp_msg_handler(void *context, qdf_nbuf_t htt_t2h_msg,
218 bool free_msg_buf)
219 {
220 struct htt_pdev_t *pdev = (struct htt_pdev_t *)context;
221 uint32_t *msg_word;
222 enum htt_t2h_msg_type msg_type;
223
224 msg_word = (uint32_t *) qdf_nbuf_data(htt_t2h_msg);
225 msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word);
226 switch (msg_type) {
227 case HTT_T2H_MSG_TYPE_VERSION_CONF:
228 {
229 if (htc_dec_return_htt_runtime_cnt(pdev->htc_pdev) >= 0)
230 htc_pm_runtime_put(pdev->htc_pdev);
231
232 pdev->tgt_ver.major = HTT_VER_CONF_MAJOR_GET(*msg_word);
233 pdev->tgt_ver.minor = HTT_VER_CONF_MINOR_GET(*msg_word);
234 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW,
235 "target uses HTT version %d.%d; host uses %d.%d",
236 pdev->tgt_ver.major, pdev->tgt_ver.minor,
237 HTT_CURRENT_VERSION_MAJOR,
238 HTT_CURRENT_VERSION_MINOR);
239 if (pdev->tgt_ver.major != HTT_CURRENT_VERSION_MAJOR)
240 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_WARN,
241 "*** Incompatible host/target HTT versions!");
242 /* abort if the target is incompatible with the host */
243 qdf_assert(pdev->tgt_ver.major ==
244 HTT_CURRENT_VERSION_MAJOR);
245 if (pdev->tgt_ver.minor != HTT_CURRENT_VERSION_MINOR) {
246 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW,
247 "*** Warning: host/target HTT versions are ");
248 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW,
249 "different, though compatible!");
250 }
251 break;
252 }
253 case HTT_T2H_MSG_TYPE_RX_FLUSH:
254 {
255 uint16_t peer_id;
256 uint8_t tid;
257 uint16_t seq_num_start, seq_num_end;
258 enum htt_rx_flush_action action;
259
260 if (qdf_nbuf_len(htt_t2h_msg) < HTT_RX_FLUSH_BYTES) {
261 qdf_print("invalid nbuff len");
262 WARN_ON(1);
263 break;
264 }
265
266 peer_id = HTT_RX_FLUSH_PEER_ID_GET(*msg_word);
267 tid = HTT_RX_FLUSH_TID_GET(*msg_word);
268 seq_num_start =
269 HTT_RX_FLUSH_SEQ_NUM_START_GET(*(msg_word + 1));
270 seq_num_end =
271 HTT_RX_FLUSH_SEQ_NUM_END_GET(*(msg_word + 1));
272 action =
273 HTT_RX_FLUSH_MPDU_STATUS_GET(*(msg_word + 1)) ==
274 1 ? htt_rx_flush_release : htt_rx_flush_discard;
275 ol_rx_flush_handler(pdev->txrx_pdev, peer_id, tid,
276 seq_num_start, seq_num_end, action);
277 break;
278 }
279 case HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND:
280 {
281 uint16_t msdu_cnt;
282
283 if (!pdev->cfg.is_high_latency &&
284 pdev->cfg.is_full_reorder_offload) {
285 qdf_print("HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND not ");
286 qdf_print("supported when full reorder offload is ");
287 qdf_print("enabled in the configuration.\n");
288 break;
289 }
290 msdu_cnt =
291 HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_GET(*msg_word);
292 ol_rx_offload_deliver_ind_handler(pdev->txrx_pdev,
293 htt_t2h_msg,
294 msdu_cnt);
295 if (pdev->cfg.is_high_latency) {
296 /*
297 * return here for HL to avoid double free on
298 * htt_t2h_msg
299 */
300 return;
301 }
302 break;
303 }
304 case HTT_T2H_MSG_TYPE_RX_FRAG_IND:
305 {
306 uint16_t peer_id;
307 uint8_t tid;
308 int msg_len = qdf_nbuf_len(htt_t2h_msg);
309
310 if (msg_len < HTT_RX_FRAG_IND_BYTES) {
311 qdf_print("invalid nbuff len");
312 WARN_ON(1);
313 break;
314 }
315 peer_id = HTT_RX_FRAG_IND_PEER_ID_GET(*msg_word);
316 tid = HTT_RX_FRAG_IND_EXT_TID_GET(*msg_word);
317 htt_rx_frag_set_last_msdu(pdev, htt_t2h_msg);
318
319 /* If packet len is invalid, will discard this frame. */
320 if (pdev->cfg.is_high_latency) {
321 u_int32_t rx_pkt_len = 0;
322
323 rx_pkt_len = qdf_nbuf_len(htt_t2h_msg);
324
325 if (rx_pkt_len < (HTT_RX_FRAG_IND_BYTES +
326 sizeof(struct hl_htt_rx_ind_base)+
327 sizeof(struct ieee80211_frame))) {
328
329 qdf_print("invalid packet len, %u", rx_pkt_len);
330 /*
331 * This buf will be freed before
332 * exiting this function.
333 */
334 break;
335 }
336 }
337
338 ol_rx_frag_indication_handler(pdev->txrx_pdev,
339 htt_t2h_msg,
340 peer_id, tid);
341
342 if (pdev->cfg.is_high_latency) {
343 /*
344 * For high latency solution,
345 * HTT_T2H_MSG_TYPE_RX_FRAG_IND message and RX packet
346 * share the same buffer. All buffer will be freed by
347 * ol_rx_frag_indication_handler or upper layer to
348 * avoid double free issue.
349 *
350 */
351 return;
352 }
353
354 break;
355 }
356 case HTT_T2H_MSG_TYPE_RX_ADDBA:
357 {
358 uint16_t peer_id;
359 uint8_t tid;
360 uint8_t win_sz;
361 uint16_t start_seq_num;
362
363 /*
364 * FOR NOW, the host doesn't need to know the initial
365 * sequence number for rx aggregation.
366 * Thus, any value will do - specify 0.
367 */
368 start_seq_num = 0;
369 peer_id = HTT_RX_ADDBA_PEER_ID_GET(*msg_word);
370 tid = HTT_RX_ADDBA_TID_GET(*msg_word);
371 win_sz = HTT_RX_ADDBA_WIN_SIZE_GET(*msg_word);
372 ol_rx_addba_handler(pdev->txrx_pdev, peer_id, tid,
373 win_sz, start_seq_num,
374 0 /* success */);
375 break;
376 }
377 case HTT_T2H_MSG_TYPE_RX_DELBA:
378 {
379 uint16_t peer_id;
380 uint8_t tid;
381
382 peer_id = HTT_RX_DELBA_PEER_ID_GET(*msg_word);
383 tid = HTT_RX_DELBA_TID_GET(*msg_word);
384 ol_rx_delba_handler(pdev->txrx_pdev, peer_id, tid);
385 break;
386 }
387 case HTT_T2H_MSG_TYPE_PEER_MAP:
388 {
389 uint8_t mac_addr_deswizzle_buf[QDF_MAC_ADDR_SIZE];
390 uint8_t *peer_mac_addr;
391 uint16_t peer_id;
392 uint8_t vdev_id;
393
394 if (qdf_nbuf_len(htt_t2h_msg) < HTT_RX_PEER_MAP_BYTES) {
395 qdf_print("invalid nbuff len");
396 WARN_ON(1);
397 break;
398 }
399
400 peer_id = HTT_RX_PEER_MAP_PEER_ID_GET(*msg_word);
401 vdev_id = HTT_RX_PEER_MAP_VDEV_ID_GET(*msg_word);
402 peer_mac_addr = htt_t2h_mac_addr_deswizzle(
403 (uint8_t *) (msg_word + 1),
404 &mac_addr_deswizzle_buf[0]);
405
406 if (peer_id > ol_cfg_max_peer_id(pdev->ctrl_pdev)) {
407 qdf_print("%s: HTT_T2H_MSG_TYPE_PEER_MAP,"
408 "invalid peer_id, %u\n",
409 __FUNCTION__,
410 peer_id);
411 break;
412 }
413
414 ol_rx_peer_map_handler(pdev->txrx_pdev, peer_id,
415 vdev_id, peer_mac_addr,
416 1 /*can tx */);
417 break;
418 }
419 case HTT_T2H_MSG_TYPE_PEER_UNMAP:
420 {
421 uint16_t peer_id;
422
423 if (qdf_nbuf_len(htt_t2h_msg) < HTT_RX_PEER_UNMAP_BYTES) {
424 qdf_print("invalid nbuff len");
425 WARN_ON(1);
426 break;
427 }
428
429 peer_id = HTT_RX_PEER_UNMAP_PEER_ID_GET(*msg_word);
430 if (peer_id > ol_cfg_max_peer_id(pdev->ctrl_pdev)) {
431 qdf_print("%s: HTT_T2H_MSG_TYPE_PEER_UNMAP,"
432 "invalid peer_id, %u\n",
433 __FUNCTION__,
434 peer_id);
435 break;
436 }
437
438 ol_rx_peer_unmap_handler(pdev->txrx_pdev, peer_id);
439 break;
440 }
441 case HTT_T2H_MSG_TYPE_SEC_IND:
442 {
443 uint16_t peer_id;
444 enum htt_sec_type sec_type;
445 int is_unicast;
446
447 if (qdf_nbuf_len(htt_t2h_msg) < HTT_SEC_IND_BYTES) {
448 qdf_print("invalid nbuff len");
449 WARN_ON(1);
450 break;
451 }
452
453 peer_id = HTT_SEC_IND_PEER_ID_GET(*msg_word);
454 sec_type = HTT_SEC_IND_SEC_TYPE_GET(*msg_word);
455 is_unicast = HTT_SEC_IND_UNICAST_GET(*msg_word);
456 msg_word++; /* point to the first part of the Michael key */
457 ol_rx_sec_ind_handler(pdev->txrx_pdev, peer_id,
458 sec_type, is_unicast, msg_word,
459 msg_word + 2);
460 break;
461 }
462 case HTT_T2H_MSG_TYPE_MGMT_TX_COMPL_IND:
463 {
464 struct htt_mgmt_tx_compl_ind *compl_msg;
465 int32_t credit_delta = 1;
466 int msg_len = qdf_nbuf_len(htt_t2h_msg);
467 if (msg_len < (sizeof(struct htt_mgmt_tx_compl_ind) + sizeof(*msg_word))) {
468 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR,
469 "Invalid msg_word length in HTT_T2H_MSG_TYPE_MGMT_TX_COMPL_IND");
470 WARN_ON(1);
471 break;
472 }
473
474 compl_msg =
475 (struct htt_mgmt_tx_compl_ind *)(msg_word + 1);
476
477 if (pdev->cfg.is_high_latency) {
478 if (!pdev->cfg.default_tx_comp_req) {
479 HTT_TX_MUTEX_ACQUIRE(&pdev->credit_mutex);
480 qdf_atomic_add(credit_delta,
481 &pdev->htt_tx_credit.
482 target_delta);
483 credit_delta = htt_tx_credit_update(pdev);
484 HTT_TX_MUTEX_RELEASE(&pdev->credit_mutex);
485 }
486 if (credit_delta)
487 ol_tx_target_credit_update(
488 pdev->txrx_pdev, credit_delta);
489 }
490 ol_tx_desc_update_group_credit(
491 pdev->txrx_pdev, compl_msg->desc_id, 1,
492 0, compl_msg->status);
493
494 DPTRACE(qdf_dp_trace_credit_record(QDF_TX_COMP, QDF_CREDIT_INC,
495 1, qdf_atomic_read(&pdev->txrx_pdev->target_tx_credit),
496 qdf_atomic_read(&pdev->txrx_pdev->txq_grps[0].credit),
497 qdf_atomic_read(&pdev->txrx_pdev->txq_grps[1].credit)));
498
499 if (!ol_tx_get_is_mgmt_over_wmi_enabled()) {
500 ol_tx_single_completion_handler(pdev->txrx_pdev,
501 compl_msg->status,
502 compl_msg->desc_id);
503 htc_pm_runtime_put(pdev->htc_pdev);
504 HTT_TX_SCHED(pdev);
505 } else {
506 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO,
507 "Ignoring HTT_T2H_MSG_TYPE_MGMT_TX_COMPL_IND indication");
508 }
509 break;
510 }
511 case HTT_T2H_MSG_TYPE_STATS_CONF:
512 {
513 uint8_t cookie;
514 uint8_t *stats_info_list;
515
516 cookie = *(msg_word + 1);
517
518 stats_info_list = (uint8_t *) (msg_word + 3);
519 htc_pm_runtime_put(pdev->htc_pdev);
520 ol_txrx_fw_stats_handler(pdev->txrx_pdev, cookie,
521 stats_info_list);
522 break;
523 }
524 #ifndef REMOVE_PKT_LOG
525 case HTT_T2H_MSG_TYPE_PKTLOG:
526 {
527 uint32_t len = qdf_nbuf_len(htt_t2h_msg);
528
529 if (len < sizeof(*msg_word) + sizeof(uint32_t)) {
530 qdf_print("invalid nbuff len");
531 WARN_ON(1);
532 break;
533 }
534
535 /*len is reduced by sizeof(*msg_word)*/
536 pktlog_process_fw_msg(OL_TXRX_PDEV_ID, msg_word + 1,
537 len - sizeof(*msg_word));
538 break;
539 }
540 #endif
541 case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:
542 {
543 uint32_t htt_credit_delta_abs;
544 int32_t htt_credit_delta;
545 int sign, old_credit;
546 int msg_len = qdf_nbuf_len(htt_t2h_msg);
547
548 if (msg_len < HTT_TX_CREDIT_MSG_BYTES) {
549 qdf_print("invalid nbuff len");
550 WARN_ON(1);
551 break;
552 }
553
554 htt_credit_delta_abs =
555 HTT_TX_CREDIT_DELTA_ABS_GET(*msg_word);
556 sign = HTT_TX_CREDIT_SIGN_BIT_GET(*msg_word) ? -1 : 1;
557 htt_credit_delta = sign * htt_credit_delta_abs;
558
559 old_credit = qdf_atomic_read(&pdev->htt_tx_credit.target_delta);
560 if (((old_credit + htt_credit_delta) > MAX_TARGET_TX_CREDIT) ||
561 ((old_credit + htt_credit_delta) < -MAX_TARGET_TX_CREDIT)) {
562 qdf_err("invalid update,old_credit=%d, htt_credit_delta=%d",
563 old_credit, htt_credit_delta);
564 break;
565 }
566 htt_credit_delta =
567 htt_t2h_adjust_bus_target_delta(pdev, htt_credit_delta);
568 htt_tx_group_credit_process(pdev, msg_word);
569 DPTRACE(qdf_dp_trace_credit_record(QDF_TX_CREDIT_UPDATE,
570 QDF_CREDIT_INC, htt_credit_delta,
571 qdf_atomic_read(&pdev->txrx_pdev->target_tx_credit) +
572 htt_credit_delta,
573 qdf_atomic_read(&pdev->txrx_pdev->txq_grps[0].credit),
574 qdf_atomic_read(&pdev->txrx_pdev->txq_grps[1].credit)));
575
576 ol_tx_credit_completion_handler(pdev->txrx_pdev,
577 htt_credit_delta);
578 break;
579 }
580
581 case HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE:
582 {
583 uint16_t len;
584 int msg_len = qdf_nbuf_len(htt_t2h_msg);
585 len = HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_GET(*(msg_word + 1));
586
587 if (sizeof(struct htt_wdi_ipa_op_response_t) + len > msg_len) {
588 qdf_print("Invalid buf len size %zu len %d, msg_len %d",
589 sizeof(struct htt_wdi_ipa_op_response_t),
590 len, msg_len);
591 WARN_ON(1);
592 break;
593 }
594 htt_ipa_op_response(pdev, msg_word);
595 break;
596 }
597
598 case HTT_T2H_MSG_TYPE_FLOW_POOL_MAP:
599 {
600 uint8_t num_flows;
601 struct htt_flow_pool_map_payload_t *pool_map_payoad;
602 int msg_len = qdf_nbuf_len(htt_t2h_msg);
603
604 num_flows = HTT_FLOW_POOL_MAP_NUM_FLOWS_GET(*msg_word);
605
606 if (((HTT_FLOW_POOL_MAP_PAYLOAD_SZ /
607 HTT_FLOW_POOL_MAP_HEADER_SZ) * num_flows + 1) * sizeof(*msg_word) > msg_len) {
608 qdf_print("Invalid num_flows");
609 WARN_ON(1);
610 break;
611 }
612
613 msg_word++;
614 while (num_flows) {
615 pool_map_payoad = (struct htt_flow_pool_map_payload_t *)
616 msg_word;
617 ol_tx_flow_pool_map_handler(pool_map_payoad->flow_id,
618 pool_map_payoad->flow_type,
619 pool_map_payoad->flow_pool_id,
620 pool_map_payoad->flow_pool_size);
621
622 msg_word += (HTT_FLOW_POOL_MAP_PAYLOAD_SZ /
623 HTT_FLOW_POOL_MAP_HEADER_SZ);
624 num_flows--;
625 }
626 break;
627 }
628
629 case HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP:
630 {
631 struct htt_flow_pool_unmap_t *pool_numap_payload;
632 int msg_len = qdf_nbuf_len(htt_t2h_msg);
633
634 if (msg_len < sizeof(struct htt_flow_pool_unmap_t)) {
635 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR,
636 "Invalid msg_word length in HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP");
637 WARN_ON(1);
638 break;
639 }
640
641 pool_numap_payload = (struct htt_flow_pool_unmap_t *)msg_word;
642 ol_tx_flow_pool_unmap_handler(pool_numap_payload->flow_id,
643 pool_numap_payload->flow_type,
644 pool_numap_payload->flow_pool_id);
645 break;
646 }
647
648 case HTT_T2H_MSG_TYPE_FLOW_POOL_RESIZE:
649 {
650 struct htt_flow_pool_resize_t *msg;
651 int msg_len = qdf_nbuf_len(htt_t2h_msg);
652
653 if (msg_len < sizeof(struct htt_flow_pool_resize_t)) {
654 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR,
655 "Invalid msg_word length in HTT_T2H_MSG_TYPE_FLOW_POOL_RESIZE");
656 WARN_ON(1);
657 break;
658 }
659
660 msg = (struct htt_flow_pool_resize_t *)msg_word;
661 ol_tx_flow_pool_resize_handler(msg->flow_pool_id,
662 msg->flow_pool_new_size);
663
664 break;
665 }
666
667 case HTT_T2H_MSG_TYPE_RX_OFLD_PKT_ERR:
668 {
669 switch (HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_GET(*msg_word)) {
670 case HTT_RX_OFLD_PKT_ERR_TYPE_MIC_ERR:
671 {
672 struct ol_txrx_vdev_t *vdev;
673 struct ol_txrx_peer_t *peer;
674 uint64_t pn;
675 uint32_t key_id;
676 uint16_t peer_id;
677 int msg_len = qdf_nbuf_len(htt_t2h_msg);
678
679 if (msg_len < HTT_RX_OFLD_PKT_ERR_MIC_ERR_BYTES) {
680 qdf_print("invalid nbuff len");
681 WARN_ON(1);
682 break;
683 }
684
685 peer_id = HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_GET
686 (*(msg_word + 1));
687
688 peer = ol_txrx_peer_find_by_id(pdev->txrx_pdev,
689 peer_id);
690 if (!peer) {
691 qdf_print("invalid peer id %d", peer_id);
692 qdf_assert(0);
693 break;
694 }
695 vdev = peer->vdev;
696 key_id = HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_GET
697 (*(msg_word + 1));
698 qdf_mem_copy(&pn, (uint8_t *)(msg_word + 6), 6);
699
700 ol_rx_send_mic_err_ind(vdev->pdev, vdev->vdev_id,
701 peer->mac_addr.raw, 0, 0,
702 OL_RX_ERR_TKIP_MIC, htt_t2h_msg,
703 &pn, key_id);
704 break;
705 }
706 default:
707 {
708 qdf_print("unhandled error type %d",
709 HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_GET(*msg_word));
710 break;
711 }
712 }
713 break;
714 }
715 #ifdef WLAN_CFR_ENABLE
716 case HTT_T2H_MSG_TYPE_CFR_DUMP_COMPL_IND:
717 {
718 int expected_len;
719 int msg_len = qdf_nbuf_len(htt_t2h_msg);
720
721 expected_len = HTT_CFR_DUMP_COMPL_HEAD_SZ +
722 sizeof(struct htt_cfr_dump_compl_ind);
723 if (msg_len < expected_len) {
724 qdf_print("Invalid length of CFR capture event");
725 break;
726 }
727
728 ol_rx_cfr_capture_msg_handler(htt_t2h_msg);
729 break;
730 }
731 #endif
732 default:
733 break;
734 };
735 /* Free the indication buffer */
736 if (free_msg_buf)
737 qdf_nbuf_free(htt_t2h_msg);
738 }
739
740 #define HTT_TX_COMPL_HEAD_SZ 4
741 #define HTT_TX_COMPL_BYTES_PER_MSDU_ID 2
742
743 /*
744 * Generic Target to host Msg/event handler for low priority messages
745 * Low priority message are handler in a different handler called from
746 * this function . So that the most likely success path like Rx and
747 * Tx comp has little code foot print
748 */
htt_t2h_msg_handler(void * context,HTC_PACKET * pkt)749 void htt_t2h_msg_handler(void *context, HTC_PACKET *pkt)
750 {
751 struct htt_pdev_t *pdev = (struct htt_pdev_t *)context;
752 qdf_nbuf_t htt_t2h_msg = (qdf_nbuf_t) pkt->pPktContext;
753 uint32_t *msg_word;
754 enum htt_t2h_msg_type msg_type;
755
756 /* check for successful message reception */
757 if (pkt->Status != QDF_STATUS_SUCCESS) {
758 if (pkt->Status != QDF_STATUS_E_CANCELED)
759 pdev->stats.htc_err_cnt++;
760 qdf_nbuf_free(htt_t2h_msg);
761 return;
762 }
763 #ifdef HTT_RX_RESTORE
764 if (qdf_unlikely(pdev->rx_ring.rx_reset)) {
765 qdf_print("rx restore ..\n");
766 qdf_nbuf_free(htt_t2h_msg);
767 return;
768 }
769 #endif
770
771 /* confirm alignment */
772 HTT_ASSERT3((((unsigned long)qdf_nbuf_data(htt_t2h_msg)) & 0x3) == 0);
773
774 msg_word = (uint32_t *) qdf_nbuf_data(htt_t2h_msg);
775 msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word);
776
777 #if defined(HELIUMPLUS_DEBUG)
778 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO,
779 "%s %d: msg_word 0x%x msg_type %d", __func__, __LINE__,
780 *msg_word, msg_type);
781 #endif
782
783 switch (msg_type) {
784 case HTT_T2H_MSG_TYPE_RX_IND:
785 {
786 unsigned int num_mpdu_ranges;
787 unsigned int num_msdu_bytes;
788 unsigned int calculated_msg_len;
789 unsigned int rx_mpdu_range_offset_bytes;
790 uint16_t peer_id;
791 uint8_t tid;
792 int msg_len = qdf_nbuf_len(htt_t2h_msg);
793
794 if (qdf_unlikely(pdev->cfg.is_full_reorder_offload)) {
795 qdf_print("HTT_T2H_MSG_TYPE_RX_IND not supported ");
796 qdf_print("with full reorder offload\n");
797 break;
798 }
799 peer_id = HTT_RX_IND_PEER_ID_GET(*msg_word);
800 tid = HTT_RX_IND_EXT_TID_GET(*msg_word);
801
802 if (tid >= OL_TXRX_NUM_EXT_TIDS) {
803 qdf_print("HTT_T2H_MSG_TYPE_RX_IND, invalid tid %d\n",
804 tid);
805 break;
806 }
807 if (msg_len < (2 + HTT_RX_PPDU_DESC_SIZE32 + 1) * sizeof(uint32_t)) {
808 qdf_print("HTT_T2H_MSG_TYPE_RX_IND, invalid msg_len\n");
809 break;
810 }
811 num_msdu_bytes =
812 HTT_RX_IND_FW_RX_DESC_BYTES_GET(
813 *(msg_word + 2 + HTT_RX_PPDU_DESC_SIZE32));
814 /*
815 * 1 word for the message header,
816 * HTT_RX_PPDU_DESC_SIZE32 words for the FW rx PPDU desc
817 * 1 word to specify the number of MSDU bytes,
818 * 1 word for every 4 MSDU bytes (round up),
819 * 1 word for the MPDU range header
820 */
821 rx_mpdu_range_offset_bytes =
822 (HTT_RX_IND_HDR_BYTES + num_msdu_bytes + 3);
823 if (qdf_unlikely(num_msdu_bytes >
824 rx_mpdu_range_offset_bytes)) {
825 qdf_print("HTT_T2H_MSG_TYPE_RX_IND, invalid %s %u\n",
826 "num_msdu_bytes",
827 num_msdu_bytes);
828 WARN_ON(1);
829 break;
830 }
831 pdev->rx_mpdu_range_offset_words =
832 rx_mpdu_range_offset_bytes >> 2;
833 num_mpdu_ranges =
834 HTT_RX_IND_NUM_MPDU_RANGES_GET(*(msg_word + 1));
835 pdev->rx_ind_msdu_byte_idx = 0;
836 if (qdf_unlikely(rx_mpdu_range_offset_bytes >
837 msg_len)) {
838 qdf_print("HTT_T2H_MSG_TYPE_RX_IND, invalid %s %d\n",
839 "rx_mpdu_range_offset_words",
840 pdev->rx_mpdu_range_offset_words);
841 WARN_ON(1);
842 break;
843 }
844 calculated_msg_len = rx_mpdu_range_offset_bytes +
845 (num_mpdu_ranges * (int)sizeof(uint32_t));
846 /*
847 * Check that the addition and multiplication
848 * do not cause integer overflow
849 */
850 if (qdf_unlikely(calculated_msg_len <
851 rx_mpdu_range_offset_bytes)) {
852 qdf_print("HTT_T2H_MSG_TYPE_RX_IND, invalid %s %u\n",
853 "num_mpdu_ranges",
854 (num_mpdu_ranges * (int)sizeof(uint32_t)));
855 WARN_ON(1);
856 break;
857 }
858 if (qdf_unlikely(calculated_msg_len > msg_len)) {
859 qdf_print("HTT_T2H_MSG_TYPE_RX_IND, invalid %s %u\n",
860 "offset_words + mpdu_ranges",
861 calculated_msg_len);
862 WARN_ON(1);
863 break;
864 }
865 ol_rx_indication_handler(pdev->txrx_pdev,
866 htt_t2h_msg, peer_id,
867 tid, num_mpdu_ranges);
868
869 if (pdev->cfg.is_high_latency)
870 return;
871
872 break;
873 }
874 case HTT_T2H_MSG_TYPE_TX_COMPL_IND:
875 {
876 int old_credit;
877 int num_msdus;
878 enum htt_tx_status status;
879 int msg_len = qdf_nbuf_len(htt_t2h_msg);
880
881 /* status - no enum translation needed */
882 status = HTT_TX_COMPL_IND_STATUS_GET(*msg_word);
883 num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word);
884
885 /*
886 * each desc id will occupy 2 bytes.
887 * the 4 is for htt msg header
888 */
889 if ((num_msdus * HTT_TX_COMPL_BYTES_PER_MSDU_ID +
890 HTT_TX_COMPL_HEAD_SZ) > msg_len) {
891 qdf_print("%s: num_msdus(%d) is invalid,"
892 "adf_nbuf_len = %d\n",
893 __FUNCTION__,
894 num_msdus,
895 msg_len);
896 break;
897 }
898
899 if (num_msdus & 0x1) {
900 struct htt_tx_compl_ind_base *compl =
901 (void *)msg_word;
902
903 /*
904 * Host CPU endianness can be different from FW CPU.
905 * This can result in even and odd MSDU IDs being
906 * switched. If this happens, copy the switched final
907 * odd MSDU ID from location payload[size], to
908 * location payload[size-1], where the message
909 * handler function expects to find it
910 */
911 if (compl->payload[num_msdus] !=
912 HTT_TX_COMPL_INV_MSDU_ID) {
913 compl->payload[num_msdus - 1] =
914 compl->payload[num_msdus];
915 }
916 }
917
918 if (pdev->cfg.is_high_latency &&
919 !pdev->cfg.credit_update_enabled) {
920 old_credit = qdf_atomic_read(
921 &pdev->htt_tx_credit.target_delta);
922 if (((old_credit + num_msdus) > MAX_TARGET_TX_CREDIT) ||
923 ((old_credit + num_msdus) < -MAX_TARGET_TX_CREDIT)) {
924 qdf_err("invalid update,old_credit=%d, num_msdus=%d",
925 old_credit, num_msdus);
926 } else {
927 if (!pdev->cfg.default_tx_comp_req) {
928 int credit_delta;
929
930 HTT_TX_MUTEX_ACQUIRE(&pdev->credit_mutex);
931 qdf_atomic_add(num_msdus,
932 &pdev->htt_tx_credit.
933 target_delta);
934 credit_delta = htt_tx_credit_update(pdev);
935 HTT_TX_MUTEX_RELEASE(&pdev->credit_mutex);
936
937 if (credit_delta) {
938 ol_tx_target_credit_update(
939 pdev->txrx_pdev,
940 credit_delta);
941 }
942 } else {
943 ol_tx_target_credit_update(pdev->txrx_pdev,
944 num_msdus);
945 }
946 }
947 }
948
949 ol_tx_completion_handler(pdev->txrx_pdev, num_msdus,
950 status, msg_word);
951 HTT_TX_SCHED(pdev);
952 break;
953 }
954 case HTT_T2H_MSG_TYPE_RX_PN_IND:
955 {
956 uint16_t peer_id;
957 uint8_t tid, pn_ie_cnt, *pn_ie = NULL;
958 uint16_t seq_num_start, seq_num_end;
959 int msg_len = qdf_nbuf_len(htt_t2h_msg);
960
961 if (msg_len < HTT_RX_PN_IND_BYTES) {
962 qdf_print("invalid nbuff len");
963 WARN_ON(1);
964 break;
965 }
966
967 /*First dword */
968 peer_id = HTT_RX_PN_IND_PEER_ID_GET(*msg_word);
969 tid = HTT_RX_PN_IND_EXT_TID_GET(*msg_word);
970
971 msg_word++;
972 /*Second dword */
973 seq_num_start =
974 HTT_RX_PN_IND_SEQ_NUM_START_GET(*msg_word);
975 seq_num_end = HTT_RX_PN_IND_SEQ_NUM_END_GET(*msg_word);
976 pn_ie_cnt = HTT_RX_PN_IND_PN_IE_CNT_GET(*msg_word);
977
978 if (msg_len - HTT_RX_PN_IND_BYTES <
979 pn_ie_cnt * sizeof(uint8_t)) {
980 qdf_print("invalid pn_ie count");
981 WARN_ON(1);
982 break;
983 }
984
985 msg_word++;
986 /*Third dword */
987 if (pn_ie_cnt)
988 pn_ie = (uint8_t *) msg_word;
989
990 ol_rx_pn_ind_handler(pdev->txrx_pdev, peer_id, tid,
991 seq_num_start, seq_num_end,
992 pn_ie_cnt, pn_ie);
993
994 break;
995 }
996 case HTT_T2H_MSG_TYPE_TX_INSPECT_IND:
997 {
998 int num_msdus;
999 int msg_len = qdf_nbuf_len(htt_t2h_msg);
1000
1001 num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word);
1002 /*
1003 * each desc id will occupy 2 bytes.
1004 * the 4 is for htt msg header
1005 */
1006 if ((num_msdus * HTT_TX_COMPL_BYTES_PER_MSDU_ID +
1007 HTT_TX_COMPL_HEAD_SZ) > msg_len) {
1008 qdf_print("%s: num_msdus(%d) is invalid,"
1009 "adf_nbuf_len = %d\n",
1010 __FUNCTION__,
1011 num_msdus,
1012 msg_len);
1013 break;
1014 }
1015
1016 if (num_msdus & 0x1) {
1017 struct htt_tx_compl_ind_base *compl =
1018 (void *)msg_word;
1019
1020 /*
1021 * Host CPU endianness can be different from FW CPU.
1022 * This can result in even and odd MSDU IDs being
1023 * switched. If this happens, copy the switched final
1024 * odd MSDU ID from location payload[size], to
1025 * location payload[size-1], where the message handler
1026 * function expects to find it
1027 */
1028 if (compl->payload[num_msdus] !=
1029 HTT_TX_COMPL_INV_MSDU_ID) {
1030 compl->payload[num_msdus - 1] =
1031 compl->payload[num_msdus];
1032 }
1033 }
1034 ol_tx_inspect_handler(pdev->txrx_pdev, num_msdus,
1035 msg_word + 1);
1036 HTT_TX_SCHED(pdev);
1037 break;
1038 }
1039 case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND:
1040 {
1041 uint16_t peer_id;
1042 uint8_t tid;
1043 uint8_t offload_ind, frag_ind;
1044
1045 if (qdf_unlikely(!pdev->cfg.is_full_reorder_offload)) {
1046 qdf_print("full reorder offload is disable");
1047 break;
1048 }
1049
1050 if (qdf_unlikely(pdev->cfg.is_high_latency)) {
1051 qdf_print("full reorder offload not support in HL");
1052 break;
1053 }
1054
1055 peer_id = HTT_RX_IN_ORD_PADDR_IND_PEER_ID_GET(*msg_word);
1056 tid = HTT_RX_IN_ORD_PADDR_IND_EXT_TID_GET(*msg_word);
1057 offload_ind = HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_GET(*msg_word);
1058 frag_ind = HTT_RX_IN_ORD_PADDR_IND_FRAG_GET(*msg_word);
1059
1060 #if defined(HELIUMPLUS_DEBUG)
1061 qdf_print("peerid %d tid %d offloadind %d fragind %d",
1062 peer_id, tid, offload_ind,
1063 frag_ind);
1064 #endif
1065 if (qdf_unlikely(frag_ind)) {
1066 ol_rx_frag_indication_handler(pdev->txrx_pdev,
1067 htt_t2h_msg,
1068 peer_id, tid);
1069 break;
1070 }
1071
1072 ol_rx_in_order_indication_handler(pdev->txrx_pdev,
1073 htt_t2h_msg, peer_id,
1074 tid, offload_ind);
1075 break;
1076 }
1077
1078 default:
1079 htt_t2h_lp_msg_handler(context, htt_t2h_msg, true);
1080 return;
1081
1082 };
1083
1084 /* Free the indication buffer */
1085 qdf_nbuf_free(htt_t2h_msg);
1086 }
1087
1088 #ifdef WLAN_FEATURE_FASTPATH
1089 #define HTT_T2H_MSG_BUF_REINIT(_buf, dev) \
1090 do { \
1091 qdf_nbuf_push_head(_buf, (HTC_HEADER_LEN) + \
1092 HTC_HDR_ALIGNMENT_PADDING); \
1093 qdf_nbuf_init_fast((_buf)); \
1094 qdf_mem_dma_sync_single_for_device(dev, \
1095 (QDF_NBUF_CB_PADDR(_buf)), \
1096 (skb_end_pointer(_buf) - \
1097 (_buf)->data), \
1098 DMA_FROM_DEVICE); \
1099 } while (0)
1100
1101 /**
1102 * htt_t2h_msg_handler_fast() - Fastpath specific message handler
1103 * @context: HTT context
1104 * @cmpl_msdus: netbuf completions
1105 * @num_cmpls: number of completions to be handled
1106 *
1107 * Return: None
1108 */
htt_t2h_msg_handler_fast(void * context,qdf_nbuf_t * cmpl_msdus,uint32_t num_cmpls)1109 void htt_t2h_msg_handler_fast(void *context, qdf_nbuf_t *cmpl_msdus,
1110 uint32_t num_cmpls)
1111 {
1112 struct htt_pdev_t *pdev = (struct htt_pdev_t *)context;
1113 qdf_nbuf_t htt_t2h_msg;
1114 uint32_t *msg_word;
1115 uint32_t i;
1116 enum htt_t2h_msg_type msg_type;
1117 uint32_t msg_len;
1118 struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC);
1119
1120 for (i = 0; i < num_cmpls; i++) {
1121 htt_t2h_msg = cmpl_msdus[i];
1122 msg_len = qdf_nbuf_len(htt_t2h_msg);
1123
1124 /*
1125 * Move the data pointer to point to HTT header
1126 * past the HTC header + HTC header alignment padding
1127 */
1128 qdf_nbuf_pull_head(htt_t2h_msg, HTC_HEADER_LEN +
1129 HTC_HDR_ALIGNMENT_PADDING);
1130
1131 /* confirm alignment */
1132 HTT_ASSERT3((((unsigned long) qdf_nbuf_data(htt_t2h_msg)) & 0x3)
1133 == 0);
1134
1135 msg_word = (u_int32_t *) qdf_nbuf_data(htt_t2h_msg);
1136 msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word);
1137
1138 switch (msg_type) {
1139 case HTT_T2H_MSG_TYPE_RX_IND:
1140 {
1141 unsigned int num_mpdu_ranges;
1142 unsigned int num_msdu_bytes;
1143 unsigned int calculated_msg_len;
1144 unsigned int rx_mpdu_range_offset_bytes;
1145 u_int16_t peer_id;
1146 u_int8_t tid;
1147 msg_len = qdf_nbuf_len(htt_t2h_msg);
1148
1149 peer_id = HTT_RX_IND_PEER_ID_GET(*msg_word);
1150 tid = HTT_RX_IND_EXT_TID_GET(*msg_word);
1151 if (tid >= OL_TXRX_NUM_EXT_TIDS) {
1152 qdf_print("HTT_T2H_MSG_TYPE_RX_IND, invalid tid %d\n",
1153 tid);
1154 WARN_ON(1);
1155 break;
1156 }
1157 num_msdu_bytes =
1158 HTT_RX_IND_FW_RX_DESC_BYTES_GET(
1159 *(msg_word + 2 +
1160 HTT_RX_PPDU_DESC_SIZE32));
1161 /*
1162 * 1 word for the message header,
1163 * HTT_RX_PPDU_DESC_SIZE32 words for the FW
1164 * rx PPDU desc.
1165 * 1 word to specify the number of MSDU bytes,
1166 * 1 word for every 4 MSDU bytes (round up),
1167 * 1 word for the MPDU range header
1168 */
1169 rx_mpdu_range_offset_bytes =
1170 (HTT_RX_IND_HDR_BYTES + num_msdu_bytes + 3);
1171 if (qdf_unlikely(num_msdu_bytes >
1172 rx_mpdu_range_offset_bytes)) {
1173 qdf_print("HTT_T2H_MSG_TYPE_RX_IND, %s %u\n",
1174 "invalid num_msdu_bytes",
1175 num_msdu_bytes);
1176 WARN_ON(1);
1177 break;
1178 }
1179 pdev->rx_mpdu_range_offset_words =
1180 rx_mpdu_range_offset_bytes >> 2;
1181 num_mpdu_ranges =
1182 HTT_RX_IND_NUM_MPDU_RANGES_GET(*(msg_word
1183 + 1));
1184 pdev->rx_ind_msdu_byte_idx = 0;
1185 if (qdf_unlikely(rx_mpdu_range_offset_bytes >
1186 msg_len)) {
1187 qdf_print("HTT_T2H_MSG_TYPE_RX_IND, %s %d\n",
1188 "invalid rx_mpdu_range_offset_words",
1189 pdev->rx_mpdu_range_offset_words);
1190 WARN_ON(1);
1191 break;
1192 }
1193 calculated_msg_len = rx_mpdu_range_offset_bytes +
1194 (num_mpdu_ranges *
1195 (int)sizeof(uint32_t));
1196 /*
1197 * Check that the addition and multiplication
1198 * do not cause integer overflow
1199 */
1200 if (qdf_unlikely(calculated_msg_len <
1201 rx_mpdu_range_offset_bytes)) {
1202 qdf_print("HTT_T2H_MSG_TYPE_RX_IND, %s %u\n",
1203 "invalid num_mpdu_ranges",
1204 (num_mpdu_ranges *
1205 (int)sizeof(uint32_t)));
1206 WARN_ON(1);
1207 break;
1208 }
1209 if (qdf_unlikely(calculated_msg_len > msg_len)) {
1210 qdf_print("HTT_T2H_MSG_TYPE_RX_IND, %s %u\n",
1211 "invalid offset_words + mpdu_ranges",
1212 calculated_msg_len);
1213 WARN_ON(1);
1214 break;
1215 }
1216 ol_rx_indication_handler(pdev->txrx_pdev, htt_t2h_msg,
1217 peer_id, tid, num_mpdu_ranges);
1218 break;
1219 }
1220 case HTT_T2H_MSG_TYPE_TX_COMPL_IND:
1221 {
1222 int num_msdus;
1223 enum htt_tx_status status;
1224
1225 /* status - no enum translation needed */
1226 status = HTT_TX_COMPL_IND_STATUS_GET(*msg_word);
1227 num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word);
1228
1229 /*
1230 * each desc id will occupy 2 bytes.
1231 * the 4 is for htt msg header
1232 */
1233 if ((num_msdus * HTT_TX_COMPL_BYTES_PER_MSDU_ID +
1234 HTT_TX_COMPL_HEAD_SZ) > msg_len) {
1235 qdf_print("%s: num_msdus(%d) is invalid,"
1236 "adf_nbuf_len = %d\n",
1237 __FUNCTION__,
1238 num_msdus,
1239 msg_len);
1240 break;
1241 }
1242
1243 if (num_msdus & 0x1) {
1244 struct htt_tx_compl_ind_base *compl =
1245 (void *)msg_word;
1246
1247 /*
1248 * Host CPU endianness can be different
1249 * from FW CPU. This can result in even
1250 * and odd MSDU IDs being switched. If
1251 * this happens, copy the switched final
1252 * odd MSDU ID from location
1253 * payload[size], to location
1254 * payload[size-1],where the message
1255 * handler function expects to find it
1256 */
1257 if (compl->payload[num_msdus] !=
1258 HTT_TX_COMPL_INV_MSDU_ID) {
1259 compl->payload[num_msdus - 1] =
1260 compl->payload[num_msdus];
1261 }
1262 }
1263 ol_tx_completion_handler(pdev->txrx_pdev, num_msdus,
1264 status, msg_word);
1265
1266 break;
1267 }
1268 case HTT_T2H_MSG_TYPE_TX_OFFLOAD_DELIVER_IND:
1269 {
1270 struct htt_tx_offload_deliver_ind_hdr_t
1271 *offload_deliver_msg;
1272 uint8_t vdev_id;
1273 struct ol_txrx_vdev_t *vdev;
1274 bool is_pkt_during_roam = false;
1275 struct ol_txrx_pdev_t *txrx_pdev = pdev->txrx_pdev;
1276 struct ol_txrx_peer_t *peer;
1277 uint8_t bssid[QDF_MAC_ADDR_SIZE];
1278 uint32_t freq = 0;
1279
1280 if (!(ucfg_pkt_capture_get_pktcap_mode((void *)soc->psoc) &
1281 PKT_CAPTURE_MODE_DATA_ONLY))
1282 break;
1283
1284 offload_deliver_msg =
1285 (struct htt_tx_offload_deliver_ind_hdr_t *)msg_word;
1286 is_pkt_during_roam =
1287 (offload_deliver_msg->reserved_2 ? true : false);
1288
1289 if (qdf_unlikely(
1290 !pdev->cfg.is_full_reorder_offload)) {
1291 break;
1292 }
1293
1294 /* Is FW sends offload data during roaming */
1295 if (is_pkt_during_roam) {
1296 vdev_id = HTT_INVALID_VDEV;
1297 freq =
1298 (uint32_t)offload_deliver_msg->reserved_3;
1299 htt_rx_mon_note_capture_channel(
1300 pdev, cds_freq_to_chan(freq));
1301 } else {
1302 vdev_id = offload_deliver_msg->vdev_id;
1303 vdev = (struct ol_txrx_vdev_t *)
1304 ol_txrx_get_vdev_from_vdev_id(vdev_id);
1305
1306 if (vdev) {
1307 qdf_spin_lock_bh(
1308 &txrx_pdev->peer_ref_mutex);
1309 peer = TAILQ_FIRST(&vdev->peer_list);
1310 qdf_spin_unlock_bh(
1311 &txrx_pdev->peer_ref_mutex);
1312 if (peer) {
1313 qdf_spin_lock_bh(
1314 &peer->peer_info_lock);
1315 qdf_mem_copy(
1316 bssid,
1317 &peer->mac_addr.raw,
1318 QDF_MAC_ADDR_SIZE);
1319 qdf_spin_unlock_bh(
1320 &peer->peer_info_lock);
1321 } else {
1322 break;
1323 }
1324 } else {
1325 break;
1326 }
1327 }
1328 ucfg_pkt_capture_offload_deliver_indication_handler(
1329 msg_word,
1330 vdev_id, bssid, pdev);
1331 break;
1332 }
1333 case HTT_T2H_MSG_TYPE_RX_PN_IND:
1334 {
1335 u_int16_t peer_id;
1336 u_int8_t tid, pn_ie_cnt, *pn_ie = NULL;
1337 int seq_num_start, seq_num_end;
1338 int msg_len = qdf_nbuf_len(htt_t2h_msg);
1339
1340 if (msg_len < HTT_RX_PN_IND_BYTES) {
1341 qdf_print("invalid nbuff len");
1342 WARN_ON(1);
1343 break;
1344 }
1345
1346 /*First dword */
1347 peer_id = HTT_RX_PN_IND_PEER_ID_GET(*msg_word);
1348 tid = HTT_RX_PN_IND_EXT_TID_GET(*msg_word);
1349
1350 msg_word++;
1351 /*Second dword */
1352 seq_num_start =
1353 HTT_RX_PN_IND_SEQ_NUM_START_GET(*msg_word);
1354 seq_num_end =
1355 HTT_RX_PN_IND_SEQ_NUM_END_GET(*msg_word);
1356 pn_ie_cnt =
1357 HTT_RX_PN_IND_PN_IE_CNT_GET(*msg_word);
1358
1359 if (msg_len - HTT_RX_PN_IND_BYTES <
1360 pn_ie_cnt * sizeof(uint8_t)) {
1361 qdf_print("invalid pn_ie len");
1362 WARN_ON(1);
1363 break;
1364 }
1365
1366 msg_word++;
1367 /*Third dword*/
1368 if (pn_ie_cnt)
1369 pn_ie = (u_int8_t *)msg_word;
1370
1371 ol_rx_pn_ind_handler(pdev->txrx_pdev, peer_id, tid,
1372 seq_num_start, seq_num_end, pn_ie_cnt, pn_ie);
1373
1374 break;
1375 }
1376 case HTT_T2H_MSG_TYPE_TX_INSPECT_IND:
1377 {
1378 int num_msdus;
1379
1380 num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word);
1381 /*
1382 * each desc id will occupy 2 bytes.
1383 * the 4 is for htt msg header
1384 */
1385 if ((num_msdus * HTT_TX_COMPL_BYTES_PER_MSDU_ID +
1386 HTT_TX_COMPL_HEAD_SZ) > msg_len) {
1387 qdf_print("%s: num_msdus(%d) is invalid,"
1388 "adf_nbuf_len = %d\n",
1389 __FUNCTION__,
1390 num_msdus,
1391 msg_len);
1392 break;
1393 }
1394
1395 if (num_msdus & 0x1) {
1396 struct htt_tx_compl_ind_base *compl =
1397 (void *)msg_word;
1398
1399 /*
1400 * Host CPU endianness can be different
1401 * from FW CPU. This * can result in
1402 * even and odd MSDU IDs being switched.
1403 * If this happens, copy the switched
1404 * final odd MSDU ID from location
1405 * payload[size], to location
1406 * payload[size-1], where the message
1407 * handler function expects to find it
1408 */
1409 if (compl->payload[num_msdus] !=
1410 HTT_TX_COMPL_INV_MSDU_ID) {
1411 compl->payload[num_msdus - 1] =
1412 compl->payload[num_msdus];
1413 }
1414 }
1415 ol_tx_inspect_handler(pdev->txrx_pdev,
1416 num_msdus, msg_word + 1);
1417 break;
1418 }
1419 case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND:
1420 {
1421 u_int16_t peer_id;
1422 u_int8_t tid;
1423 u_int8_t offload_ind, frag_ind;
1424
1425 if (qdf_unlikely(
1426 !pdev->cfg.is_full_reorder_offload)) {
1427 qdf_print("HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND not supported when full reorder offload is disabled\n");
1428 break;
1429 }
1430
1431 if (qdf_unlikely(
1432 pdev->txrx_pdev->cfg.is_high_latency)) {
1433 qdf_print("HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND not supported on high latency\n");
1434 break;
1435 }
1436
1437 peer_id = HTT_RX_IN_ORD_PADDR_IND_PEER_ID_GET(
1438 *msg_word);
1439 tid = HTT_RX_IN_ORD_PADDR_IND_EXT_TID_GET(
1440 *msg_word);
1441 offload_ind =
1442 HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_GET(
1443 *msg_word);
1444 frag_ind = HTT_RX_IN_ORD_PADDR_IND_FRAG_GET(
1445 *msg_word);
1446
1447 if (qdf_unlikely(frag_ind)) {
1448 ol_rx_frag_indication_handler(
1449 pdev->txrx_pdev, htt_t2h_msg, peer_id,
1450 tid);
1451 break;
1452 }
1453
1454 ol_rx_in_order_indication_handler(
1455 pdev->txrx_pdev, htt_t2h_msg,
1456 peer_id, tid, offload_ind);
1457 break;
1458 }
1459 default:
1460 htt_t2h_lp_msg_handler(context, htt_t2h_msg, false);
1461 break;
1462 };
1463
1464 /* Re-initialize the indication buffer */
1465 HTT_T2H_MSG_BUF_REINIT(htt_t2h_msg, pdev->osdev);
1466 qdf_nbuf_set_pktlen(htt_t2h_msg, 0);
1467 }
1468 }
1469 #endif /* WLAN_FEATURE_FASTPATH */
1470
1471 /*--- target->host HTT message Info Element access methods ------------------*/
1472
1473 /*--- tx completion message ---*/
1474
htt_tx_compl_desc_id(void * iterator,int num)1475 uint16_t htt_tx_compl_desc_id(void *iterator, int num)
1476 {
1477 /*
1478 * The MSDU IDs are packed , 2 per 32-bit word.
1479 * Iterate on them as an array of 16-bit elements.
1480 * This will work fine if the host endianness matches
1481 * the target endianness.
1482 * If the host endianness is opposite of the target's,
1483 * this iterator will produce descriptor IDs in a different
1484 * order than the target inserted them into the message -
1485 * if the target puts in [0, 1, 2, 3, ...] the host will
1486 * put out [1, 0, 3, 2, ...].
1487 * This is fine, except for the last ID if there are an
1488 * odd number of IDs. But the TX_COMPL_IND handling code
1489 * in the htt_t2h_msg_handler already added a duplicate
1490 * of the final ID, if there were an odd number of IDs,
1491 * so this function can safely treat the IDs as an array
1492 * of 16-bit elements.
1493 */
1494 return *(((uint16_t *) iterator) + num);
1495 }
1496
1497 /*--- rx indication message ---*/
1498
htt_rx_ind_flush(htt_pdev_handle pdev,qdf_nbuf_t rx_ind_msg)1499 int htt_rx_ind_flush(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg)
1500 {
1501 uint32_t *msg_word;
1502
1503 msg_word = (uint32_t *) qdf_nbuf_data(rx_ind_msg);
1504 return HTT_RX_IND_FLUSH_VALID_GET(*msg_word);
1505 }
1506
1507 void
htt_rx_ind_flush_seq_num_range(htt_pdev_handle pdev,qdf_nbuf_t rx_ind_msg,unsigned int * seq_num_start,unsigned int * seq_num_end)1508 htt_rx_ind_flush_seq_num_range(htt_pdev_handle pdev,
1509 qdf_nbuf_t rx_ind_msg,
1510 unsigned int *seq_num_start,
1511 unsigned int *seq_num_end)
1512 {
1513 uint32_t *msg_word;
1514
1515 msg_word = (uint32_t *) qdf_nbuf_data(rx_ind_msg);
1516 msg_word++;
1517 *seq_num_start = HTT_RX_IND_FLUSH_SEQ_NUM_START_GET(*msg_word);
1518 *seq_num_end = HTT_RX_IND_FLUSH_SEQ_NUM_END_GET(*msg_word);
1519 }
1520
htt_rx_ind_release(htt_pdev_handle pdev,qdf_nbuf_t rx_ind_msg)1521 int htt_rx_ind_release(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg)
1522 {
1523 uint32_t *msg_word;
1524
1525 msg_word = (uint32_t *) qdf_nbuf_data(rx_ind_msg);
1526 return HTT_RX_IND_REL_VALID_GET(*msg_word);
1527 }
1528
1529 void
htt_rx_ind_release_seq_num_range(htt_pdev_handle pdev,qdf_nbuf_t rx_ind_msg,unsigned int * seq_num_start,unsigned int * seq_num_end)1530 htt_rx_ind_release_seq_num_range(htt_pdev_handle pdev,
1531 qdf_nbuf_t rx_ind_msg,
1532 unsigned int *seq_num_start,
1533 unsigned int *seq_num_end)
1534 {
1535 uint32_t *msg_word;
1536
1537 msg_word = (uint32_t *) qdf_nbuf_data(rx_ind_msg);
1538 msg_word++;
1539 *seq_num_start = HTT_RX_IND_REL_SEQ_NUM_START_GET(*msg_word);
1540 *seq_num_end = HTT_RX_IND_REL_SEQ_NUM_END_GET(*msg_word);
1541 }
1542
1543 void
htt_rx_ind_mpdu_range_info(struct htt_pdev_t * pdev,qdf_nbuf_t rx_ind_msg,int mpdu_range_num,enum htt_rx_status * status,int * mpdu_count)1544 htt_rx_ind_mpdu_range_info(struct htt_pdev_t *pdev,
1545 qdf_nbuf_t rx_ind_msg,
1546 int mpdu_range_num,
1547 enum htt_rx_status *status, int *mpdu_count)
1548 {
1549 uint32_t *msg_word;
1550
1551 msg_word = (uint32_t *) qdf_nbuf_data(rx_ind_msg);
1552 msg_word += pdev->rx_mpdu_range_offset_words + mpdu_range_num;
1553 *status = HTT_RX_IND_MPDU_STATUS_GET(*msg_word);
1554 *mpdu_count = HTT_RX_IND_MPDU_COUNT_GET(*msg_word);
1555 }
1556
1557 /**
1558 * htt_rx_ind_rssi_dbm() - Return the RSSI provided in a rx indication message.
1559 *
1560 * @pdev: the HTT instance the rx data was received on
1561 * @rx_ind_msg: the netbuf containing the rx indication message
1562 *
1563 * Return the RSSI from an rx indication message, in dBm units.
1564 *
1565 * Return: RSSI in dBm, or HTT_INVALID_RSSI
1566 */
htt_rx_ind_rssi_dbm(htt_pdev_handle pdev,qdf_nbuf_t rx_ind_msg)1567 int16_t htt_rx_ind_rssi_dbm(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg)
1568 {
1569 int8_t rssi;
1570 uint32_t *msg_word;
1571
1572 msg_word = (uint32_t *)
1573 (qdf_nbuf_data(rx_ind_msg) +
1574 HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET);
1575
1576 /* check if the RX_IND message contains valid rx PPDU start info */
1577 if (!HTT_RX_IND_START_VALID_GET(*msg_word))
1578 return HTT_RSSI_INVALID;
1579
1580 rssi = HTT_RX_IND_RSSI_CMB_GET(*msg_word);
1581 return (HTT_TGT_RSSI_INVALID == rssi) ?
1582 HTT_RSSI_INVALID : rssi;
1583 }
1584
1585 /**
1586 * htt_rx_ind_rssi_dbm_chain() - Return the RSSI for a chain provided in a rx
1587 * indication message.
1588 * @pdev: the HTT instance the rx data was received on
1589 * @rx_ind_msg: the netbuf containing the rx indication message
1590 * @chain: the index of the chain (0-4)
1591 *
1592 * Return the RSSI for a chain from an rx indication message, in dBm units.
1593 *
1594 * Return: RSSI, or HTT_INVALID_RSSI
1595 */
1596 int16_t
htt_rx_ind_rssi_dbm_chain(htt_pdev_handle pdev,qdf_nbuf_t rx_ind_msg,int8_t chain)1597 htt_rx_ind_rssi_dbm_chain(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg,
1598 int8_t chain)
1599 {
1600 int8_t rssi;
1601 uint32_t *msg_word;
1602
1603 if (chain < 0 || chain > 3)
1604 return HTT_RSSI_INVALID;
1605
1606 msg_word = (uint32_t *)
1607 (qdf_nbuf_data(rx_ind_msg) +
1608 HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET);
1609
1610 /* check if the RX_IND message contains valid rx PPDU start info */
1611 if (!HTT_RX_IND_START_VALID_GET(*msg_word))
1612 return HTT_RSSI_INVALID;
1613
1614 msg_word += 1 + chain;
1615
1616 rssi = HTT_RX_IND_RSSI_PRI20_GET(*msg_word);
1617 return (HTT_TGT_RSSI_INVALID == rssi) ?
1618 HTT_RSSI_INVALID :
1619 rssi;
1620 }
1621
1622 /**
1623 * htt_rx_ind_legacy_rate() - Return the data rate
1624 * @pdev: the HTT instance the rx data was received on
1625 * @rx_ind_msg: the netbuf containing the rx indication message
1626 * @legacy_rate: (output) the data rate
1627 * The legacy_rate parameter's value depends on the
1628 * legacy_rate_sel value.
1629 * If legacy_rate_sel is 0:
1630 * 0x8: OFDM 48 Mbps
1631 * 0x9: OFDM 24 Mbps
1632 * 0xA: OFDM 12 Mbps
1633 * 0xB: OFDM 6 Mbps
1634 * 0xC: OFDM 54 Mbps
1635 * 0xD: OFDM 36 Mbps
1636 * 0xE: OFDM 18 Mbps
1637 * 0xF: OFDM 9 Mbps
1638 * If legacy_rate_sel is 1:
1639 * 0x8: CCK 11 Mbps long preamble
1640 * 0x9: CCK 5.5 Mbps long preamble
1641 * 0xA: CCK 2 Mbps long preamble
1642 * 0xB: CCK 1 Mbps long preamble
1643 * 0xC: CCK 11 Mbps short preamble
1644 * 0xD: CCK 5.5 Mbps short preamble
1645 * 0xE: CCK 2 Mbps short preamble
1646 * -1 on error.
1647 * @legacy_rate_sel: (output) 0 to indicate OFDM, 1 to indicate CCK.
1648 * -1 on error.
1649 *
1650 * Return the data rate provided in a rx indication message.
1651 */
1652 void
htt_rx_ind_legacy_rate(htt_pdev_handle pdev,qdf_nbuf_t rx_ind_msg,uint8_t * legacy_rate,uint8_t * legacy_rate_sel)1653 htt_rx_ind_legacy_rate(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg,
1654 uint8_t *legacy_rate, uint8_t *legacy_rate_sel)
1655 {
1656 uint32_t *msg_word;
1657
1658 msg_word = (uint32_t *)
1659 (qdf_nbuf_data(rx_ind_msg) +
1660 HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET);
1661
1662 /* check if the RX_IND message contains valid rx PPDU start info */
1663 if (!HTT_RX_IND_START_VALID_GET(*msg_word)) {
1664 *legacy_rate = -1;
1665 *legacy_rate_sel = -1;
1666 return;
1667 }
1668
1669 *legacy_rate = HTT_RX_IND_LEGACY_RATE_GET(*msg_word);
1670 *legacy_rate_sel = HTT_RX_IND_LEGACY_RATE_SEL_GET(*msg_word);
1671 }
1672
1673 /**
1674 * htt_rx_ind_timestamp() - Return the timestamp
1675 * @pdev: the HTT instance the rx data was received on
1676 * @rx_ind_msg: the netbuf containing the rx indication message
1677 * @timestamp_microsec: (output) the timestamp to microsecond resolution.
1678 * -1 on error.
1679 * @timestamp_submicrosec: the submicrosecond portion of the
1680 * timestamp. -1 on error.
1681 *
1682 * Return the timestamp provided in a rx indication message.
1683 */
1684 void
htt_rx_ind_timestamp(htt_pdev_handle pdev,qdf_nbuf_t rx_ind_msg,uint32_t * timestamp_microsec,uint8_t * timestamp_submicrosec)1685 htt_rx_ind_timestamp(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg,
1686 uint32_t *timestamp_microsec,
1687 uint8_t *timestamp_submicrosec)
1688 {
1689 uint32_t *msg_word;
1690
1691 msg_word = (uint32_t *)
1692 (qdf_nbuf_data(rx_ind_msg) +
1693 HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET);
1694
1695 /* check if the RX_IND message contains valid rx PPDU start info */
1696 if (!HTT_RX_IND_END_VALID_GET(*msg_word)) {
1697 *timestamp_microsec = -1;
1698 *timestamp_submicrosec = -1;
1699 return;
1700 }
1701
1702 *timestamp_microsec = *(msg_word + 6);
1703 *timestamp_submicrosec =
1704 HTT_RX_IND_TIMESTAMP_SUBMICROSEC_GET(*msg_word);
1705 }
1706
1707 #define INVALID_TSF -1
1708 /**
1709 * htt_rx_ind_tsf32() - Return the TSF timestamp
1710 * @pdev: the HTT instance the rx data was received on
1711 * @rx_ind_msg: the netbuf containing the rx indication message
1712 *
1713 * Return the TSF timestamp provided in a rx indication message.
1714 *
1715 * Return: TSF timestamp
1716 */
1717 uint32_t
htt_rx_ind_tsf32(htt_pdev_handle pdev,qdf_nbuf_t rx_ind_msg)1718 htt_rx_ind_tsf32(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg)
1719 {
1720 uint32_t *msg_word;
1721
1722 msg_word = (uint32_t *)
1723 (qdf_nbuf_data(rx_ind_msg) +
1724 HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET);
1725
1726 /* check if the RX_IND message contains valid rx PPDU start info */
1727 if (!HTT_RX_IND_END_VALID_GET(*msg_word))
1728 return INVALID_TSF;
1729
1730 return *(msg_word + 5);
1731 }
1732
1733 /**
1734 * htt_rx_ind_ext_tid() - Return the extended traffic ID provided in a rx
1735 * indication message.
1736 * @pdev: the HTT instance the rx data was received on
1737 * @rx_ind_msg: the netbuf containing the rx indication message
1738 *
1739 * Return the extended traffic ID in a rx indication message.
1740 *
1741 * Return: Extended TID
1742 */
1743 uint8_t
htt_rx_ind_ext_tid(htt_pdev_handle pdev,qdf_nbuf_t rx_ind_msg)1744 htt_rx_ind_ext_tid(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg)
1745 {
1746 uint32_t *msg_word;
1747
1748 msg_word = (uint32_t *)
1749 (qdf_nbuf_data(rx_ind_msg));
1750
1751 return HTT_RX_IND_EXT_TID_GET(*msg_word);
1752 }
1753
1754 /*--- stats confirmation message ---*/
1755
1756 void
htt_t2h_dbg_stats_hdr_parse(uint8_t * stats_info_list,enum htt_dbg_stats_type * type,enum htt_dbg_stats_status * status,int * length,uint8_t ** stats_data)1757 htt_t2h_dbg_stats_hdr_parse(uint8_t *stats_info_list,
1758 enum htt_dbg_stats_type *type,
1759 enum htt_dbg_stats_status *status,
1760 int *length, uint8_t **stats_data)
1761 {
1762 uint32_t *msg_word = (uint32_t *) stats_info_list;
1763 *type = HTT_T2H_STATS_CONF_TLV_TYPE_GET(*msg_word);
1764 *status = HTT_T2H_STATS_CONF_TLV_STATUS_GET(*msg_word);
1765 *length = HTT_T2H_STATS_CONF_TLV_HDR_SIZE + /* header length */
1766 HTT_T2H_STATS_CONF_TLV_LENGTH_GET(*msg_word); /* data len */
1767 *stats_data = stats_info_list + HTT_T2H_STATS_CONF_TLV_HDR_SIZE;
1768 }
1769
1770 void
htt_rx_frag_ind_flush_seq_num_range(htt_pdev_handle pdev,qdf_nbuf_t rx_frag_ind_msg,uint16_t * seq_num_start,uint16_t * seq_num_end)1771 htt_rx_frag_ind_flush_seq_num_range(htt_pdev_handle pdev,
1772 qdf_nbuf_t rx_frag_ind_msg,
1773 uint16_t *seq_num_start, uint16_t *seq_num_end)
1774 {
1775 uint32_t *msg_word;
1776
1777 msg_word = (uint32_t *) qdf_nbuf_data(rx_frag_ind_msg);
1778 msg_word++;
1779 *seq_num_start = HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_START_GET(*msg_word);
1780 *seq_num_end = HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_END_GET(*msg_word);
1781 }
1782