1 /* 2 * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <htt.h> 20 #include <hal_api.h> 21 #include "dp_htt.h" 22 #include "dp_peer.h" 23 #include "dp_types.h" 24 #include "dp_internal.h" 25 #include "dp_rx_mon.h" 26 #include "htt_stats.h" 27 #include "htt_ppdu_stats.h" 28 #include "qdf_mem.h" /* qdf_mem_malloc,free */ 29 #include "cdp_txrx_cmn_struct.h" 30 31 #define HTT_TLV_HDR_LEN HTT_T2H_EXT_STATS_CONF_TLV_HDR_SIZE 32 33 #define HTT_HTC_PKT_POOL_INIT_SIZE 64 34 #define HTT_T2H_MAX_MSG_SIZE 2048 35 36 #define HTT_MSG_BUF_SIZE(msg_bytes) \ 37 ((msg_bytes) + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING) 38 39 #define HTT_PID_BIT_MASK 0x3 40 41 #define DP_EXT_MSG_LENGTH 2048 42 #define DP_HTT_SEND_HTC_PKT(soc, pkt) \ 43 do { \ 44 if (htc_send_pkt(soc->htc_soc, &pkt->htc_pkt) == \ 45 QDF_STATUS_SUCCESS) \ 46 htt_htc_misc_pkt_list_add(soc, pkt); \ 47 } while (0) 48 49 #define HTT_MGMT_CTRL_TLV_RESERVERD_LEN 12 50 /** 51 * Bitmap of HTT PPDU TLV types for Default mode 52 */ 53 #define HTT_PPDU_DEFAULT_TLV_BITMAP \ 54 (1 << HTT_PPDU_STATS_COMMON_TLV) | \ 55 (1 << HTT_PPDU_STATS_USR_COMMON_TLV) | \ 56 (1 << HTT_PPDU_STATS_USR_RATE_TLV) | \ 57 (1 << HTT_PPDU_STATS_SCH_CMD_STATUS_TLV) | \ 58 (1 << HTT_PPDU_STATS_USR_COMPLTN_COMMON_TLV) | \ 59 (1 << HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV) 60 61 /** 62 * Bitmap of HTT PPDU TLV types for Sniffer mode 63 */ 64 #define HTT_PPDU_SNIFFER_AMPDU_TLV_BITMAP \ 65 (1 << HTT_PPDU_STATS_COMMON_TLV) | \ 66 (1 << HTT_PPDU_STATS_USR_COMMON_TLV) | \ 67 (1 << HTT_PPDU_STATS_USR_RATE_TLV) | \ 68 (1 << HTT_PPDU_STATS_SCH_CMD_STATUS_TLV) | \ 69 (1 << HTT_PPDU_STATS_USR_COMPLTN_COMMON_TLV) | \ 70 (1 << HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV) | \ 71 (1 << HTT_PPDU_STATS_USR_COMPLTN_BA_BITMAP_64_TLV) | \ 72 (1 << HTT_PPDU_STATS_USR_MPDU_ENQ_BITMAP_64_TLV) | \ 73 (1 << HTT_PPDU_STATS_USR_COMPLTN_BA_BITMAP_256_TLV) 74 75 #define HTT_FRAMECTRL_DATATYPE 0x08 76 #define HTT_PPDU_DESC_MAX_DEPTH 16 77 78 /* 79 * dp_tx_stats_update() - Update per-peer statistics 80 * @soc: Datapath soc handle 81 * @peer: Datapath peer handle 82 * @ppdu: PPDU Descriptor 83 * @ack_rssi: RSSI of last ack received 84 * 85 * Return: None 86 */ 87 #ifdef FEATURE_PERPKT_INFO 88 static void dp_tx_stats_update(struct dp_soc *soc, struct dp_peer *peer, 89 struct cdp_tx_completion_ppdu_user *ppdu, uint32_t ack_rssi) 90 { 91 struct dp_pdev *pdev = peer->vdev->pdev; 92 uint8_t preamble, mcs; 93 uint16_t num_msdu; 94 95 preamble = ppdu->preamble; 96 mcs = ppdu->mcs; 97 num_msdu = ppdu->num_msdu; 98 99 /* If the peer statistics are already processed as part of 100 * per-MSDU completion handler, do not process these again in per-PPDU 101 * indications */ 102 if (soc->process_tx_status) 103 return; 104 105 DP_STATS_INC_PKT(peer, tx.comp_pkt, 106 num_msdu, (ppdu->success_bytes + 107 ppdu->retry_bytes + ppdu->failed_bytes)); 108 DP_STATS_INC(peer, tx.tx_failed, ppdu->failed_msdus); 109 DP_STATS_UPD(peer, tx.tx_rate, ppdu->tx_rate); 110 DP_STATS_INC(peer, tx.sgi_count[ppdu->gi], num_msdu); 111 DP_STATS_INC(peer, tx.bw[ppdu->bw], num_msdu); 112 DP_STATS_INC(peer, tx.nss[ppdu->nss], num_msdu); 113 DP_STATS_INC(peer, tx.wme_ac_type[TID_TO_WME_AC(ppdu->tid)], num_msdu); 114 DP_STATS_INCC(peer, tx.stbc, num_msdu, ppdu->stbc); 115 DP_STATS_INCC(peer, tx.ldpc, num_msdu, ppdu->ldpc); 116 if (!(ppdu->is_mcast)) 117 DP_STATS_UPD(peer, tx.last_ack_rssi, ack_rssi); 118 119 DP_STATS_INC(peer, tx.retries, 120 (ppdu->long_retries + ppdu->short_retries)); 121 DP_STATS_INCC(peer, 122 tx.pkt_type[preamble].mcs_count[MAX_MCS-1], num_msdu, 123 ((mcs >= MAX_MCS_11A) && (preamble == DOT11_A))); 124 DP_STATS_INCC(peer, 125 tx.pkt_type[preamble].mcs_count[mcs], num_msdu, 126 ((mcs < MAX_MCS_11A) && (preamble == DOT11_A))); 127 DP_STATS_INCC(peer, 128 tx.pkt_type[preamble].mcs_count[MAX_MCS-1], num_msdu, 129 ((mcs >= MAX_MCS_11B) && (preamble == DOT11_B))); 130 DP_STATS_INCC(peer, 131 tx.pkt_type[preamble].mcs_count[mcs], num_msdu, 132 ((mcs < (MAX_MCS_11B)) && (preamble == DOT11_B))); 133 DP_STATS_INCC(peer, 134 tx.pkt_type[preamble].mcs_count[MAX_MCS-1], num_msdu, 135 ((mcs >= MAX_MCS_11A) && (preamble == DOT11_N))); 136 DP_STATS_INCC(peer, 137 tx.pkt_type[preamble].mcs_count[mcs], num_msdu, 138 ((mcs < MAX_MCS_11A) && (preamble == DOT11_N))); 139 DP_STATS_INCC(peer, 140 tx.pkt_type[preamble].mcs_count[MAX_MCS-1], num_msdu, 141 ((mcs >= MAX_MCS_11AC) && (preamble == DOT11_AC))); 142 DP_STATS_INCC(peer, 143 tx.pkt_type[preamble].mcs_count[mcs], num_msdu, 144 ((mcs < MAX_MCS_11AC) && (preamble == DOT11_AC))); 145 DP_STATS_INCC(peer, 146 tx.pkt_type[preamble].mcs_count[MAX_MCS-1], num_msdu, 147 ((mcs >= (MAX_MCS - 1)) && (preamble == DOT11_AX))); 148 DP_STATS_INCC(peer, 149 tx.pkt_type[preamble].mcs_count[mcs], num_msdu, 150 ((mcs < (MAX_MCS - 1)) && (preamble == DOT11_AX))); 151 152 if (soc->cdp_soc.ol_ops->update_dp_stats) { 153 soc->cdp_soc.ol_ops->update_dp_stats(pdev->osif_pdev, 154 &peer->stats, ppdu->peer_id, 155 UPDATE_PEER_STATS); 156 157 dp_aggregate_vdev_stats(peer->vdev); 158 } 159 } 160 #endif 161 162 /* 163 * htt_htc_pkt_alloc() - Allocate HTC packet buffer 164 * @htt_soc: HTT SOC handle 165 * 166 * Return: Pointer to htc packet buffer 167 */ 168 static struct dp_htt_htc_pkt * 169 htt_htc_pkt_alloc(struct htt_soc *soc) 170 { 171 struct dp_htt_htc_pkt_union *pkt = NULL; 172 173 HTT_TX_MUTEX_ACQUIRE(&soc->htt_tx_mutex); 174 if (soc->htt_htc_pkt_freelist) { 175 pkt = soc->htt_htc_pkt_freelist; 176 soc->htt_htc_pkt_freelist = soc->htt_htc_pkt_freelist->u.next; 177 } 178 HTT_TX_MUTEX_RELEASE(&soc->htt_tx_mutex); 179 180 if (pkt == NULL) 181 pkt = qdf_mem_malloc(sizeof(*pkt)); 182 return &pkt->u.pkt; /* not actually a dereference */ 183 } 184 185 /* 186 * htt_htc_pkt_free() - Free HTC packet buffer 187 * @htt_soc: HTT SOC handle 188 */ 189 static void 190 htt_htc_pkt_free(struct htt_soc *soc, struct dp_htt_htc_pkt *pkt) 191 { 192 struct dp_htt_htc_pkt_union *u_pkt = 193 (struct dp_htt_htc_pkt_union *)pkt; 194 195 HTT_TX_MUTEX_ACQUIRE(&soc->htt_tx_mutex); 196 u_pkt->u.next = soc->htt_htc_pkt_freelist; 197 soc->htt_htc_pkt_freelist = u_pkt; 198 HTT_TX_MUTEX_RELEASE(&soc->htt_tx_mutex); 199 } 200 201 /* 202 * htt_htc_pkt_pool_free() - Free HTC packet pool 203 * @htt_soc: HTT SOC handle 204 */ 205 static void 206 htt_htc_pkt_pool_free(struct htt_soc *soc) 207 { 208 struct dp_htt_htc_pkt_union *pkt, *next; 209 pkt = soc->htt_htc_pkt_freelist; 210 while (pkt) { 211 next = pkt->u.next; 212 qdf_mem_free(pkt); 213 pkt = next; 214 } 215 soc->htt_htc_pkt_freelist = NULL; 216 } 217 218 /* 219 * htt_htc_misc_pkt_list_trim() - trim misc list 220 * @htt_soc: HTT SOC handle 221 * @level: max no. of pkts in list 222 */ 223 static void 224 htt_htc_misc_pkt_list_trim(struct htt_soc *soc, int level) 225 { 226 struct dp_htt_htc_pkt_union *pkt, *next, *prev = NULL; 227 int i = 0; 228 qdf_nbuf_t netbuf; 229 230 HTT_TX_MUTEX_ACQUIRE(&soc->htt_tx_mutex); 231 pkt = soc->htt_htc_pkt_misclist; 232 while (pkt) { 233 next = pkt->u.next; 234 /* trim the out grown list*/ 235 if (++i > level) { 236 netbuf = 237 (qdf_nbuf_t)(pkt->u.pkt.htc_pkt.pNetBufContext); 238 qdf_nbuf_unmap(soc->osdev, netbuf, QDF_DMA_TO_DEVICE); 239 qdf_nbuf_free(netbuf); 240 qdf_mem_free(pkt); 241 pkt = NULL; 242 if (prev) 243 prev->u.next = NULL; 244 } 245 prev = pkt; 246 pkt = next; 247 } 248 HTT_TX_MUTEX_RELEASE(&soc->htt_tx_mutex); 249 } 250 251 /* 252 * htt_htc_misc_pkt_list_add() - Add pkt to misc list 253 * @htt_soc: HTT SOC handle 254 * @dp_htt_htc_pkt: pkt to be added to list 255 */ 256 static void 257 htt_htc_misc_pkt_list_add(struct htt_soc *soc, struct dp_htt_htc_pkt *pkt) 258 { 259 struct dp_htt_htc_pkt_union *u_pkt = 260 (struct dp_htt_htc_pkt_union *)pkt; 261 int misclist_trim_level = htc_get_tx_queue_depth(soc->htc_soc, 262 pkt->htc_pkt.Endpoint) 263 + DP_HTT_HTC_PKT_MISCLIST_SIZE; 264 265 HTT_TX_MUTEX_ACQUIRE(&soc->htt_tx_mutex); 266 if (soc->htt_htc_pkt_misclist) { 267 u_pkt->u.next = soc->htt_htc_pkt_misclist; 268 soc->htt_htc_pkt_misclist = u_pkt; 269 } else { 270 soc->htt_htc_pkt_misclist = u_pkt; 271 } 272 HTT_TX_MUTEX_RELEASE(&soc->htt_tx_mutex); 273 274 /* only ce pipe size + tx_queue_depth could possibly be in use 275 * free older packets in the misclist 276 */ 277 htt_htc_misc_pkt_list_trim(soc, misclist_trim_level); 278 } 279 280 /* 281 * htt_htc_misc_pkt_pool_free() - free pkts in misc list 282 * @htt_soc: HTT SOC handle 283 */ 284 static void 285 htt_htc_misc_pkt_pool_free(struct htt_soc *soc) 286 { 287 struct dp_htt_htc_pkt_union *pkt, *next; 288 qdf_nbuf_t netbuf; 289 290 pkt = soc->htt_htc_pkt_misclist; 291 292 while (pkt) { 293 next = pkt->u.next; 294 netbuf = (qdf_nbuf_t) (pkt->u.pkt.htc_pkt.pNetBufContext); 295 qdf_nbuf_unmap(soc->osdev, netbuf, QDF_DMA_TO_DEVICE); 296 297 soc->stats.htc_pkt_free++; 298 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_LOW, 299 "%s: Pkt free count %d\n", 300 __func__, soc->stats.htc_pkt_free); 301 302 qdf_nbuf_free(netbuf); 303 qdf_mem_free(pkt); 304 pkt = next; 305 } 306 soc->htt_htc_pkt_misclist = NULL; 307 } 308 309 /* 310 * htt_t2h_mac_addr_deswizzle() - Swap MAC addr bytes if FW endianess differ 311 * @tgt_mac_addr: Target MAC 312 * @buffer: Output buffer 313 */ 314 static u_int8_t * 315 htt_t2h_mac_addr_deswizzle(u_int8_t *tgt_mac_addr, u_int8_t *buffer) 316 { 317 #ifdef BIG_ENDIAN_HOST 318 /* 319 * The host endianness is opposite of the target endianness. 320 * To make u_int32_t elements come out correctly, the target->host 321 * upload has swizzled the bytes in each u_int32_t element of the 322 * message. 323 * For byte-array message fields like the MAC address, this 324 * upload swizzling puts the bytes in the wrong order, and needs 325 * to be undone. 326 */ 327 buffer[0] = tgt_mac_addr[3]; 328 buffer[1] = tgt_mac_addr[2]; 329 buffer[2] = tgt_mac_addr[1]; 330 buffer[3] = tgt_mac_addr[0]; 331 buffer[4] = tgt_mac_addr[7]; 332 buffer[5] = tgt_mac_addr[6]; 333 return buffer; 334 #else 335 /* 336 * The host endianness matches the target endianness - 337 * we can use the mac addr directly from the message buffer. 338 */ 339 return tgt_mac_addr; 340 #endif 341 } 342 343 /* 344 * dp_htt_h2t_send_complete_free_netbuf() - Free completed buffer 345 * @soc: SOC handle 346 * @status: Completion status 347 * @netbuf: HTT buffer 348 */ 349 static void 350 dp_htt_h2t_send_complete_free_netbuf( 351 void *soc, A_STATUS status, qdf_nbuf_t netbuf) 352 { 353 qdf_nbuf_free(netbuf); 354 } 355 356 /* 357 * dp_htt_h2t_send_complete() - H2T completion handler 358 * @context: Opaque context (HTT SOC handle) 359 * @htc_pkt: HTC packet 360 */ 361 static void 362 dp_htt_h2t_send_complete(void *context, HTC_PACKET *htc_pkt) 363 { 364 void (*send_complete_part2)( 365 void *soc, A_STATUS status, qdf_nbuf_t msdu); 366 struct htt_soc *soc = (struct htt_soc *) context; 367 struct dp_htt_htc_pkt *htt_pkt; 368 qdf_nbuf_t netbuf; 369 370 send_complete_part2 = htc_pkt->pPktContext; 371 372 htt_pkt = container_of(htc_pkt, struct dp_htt_htc_pkt, htc_pkt); 373 374 /* process (free or keep) the netbuf that held the message */ 375 netbuf = (qdf_nbuf_t) htc_pkt->pNetBufContext; 376 /* 377 * adf sendcomplete is required for windows only 378 */ 379 /* qdf_nbuf_set_sendcompleteflag(netbuf, TRUE); */ 380 if (send_complete_part2 != NULL) { 381 send_complete_part2( 382 htt_pkt->soc_ctxt, htc_pkt->Status, netbuf); 383 } 384 /* free the htt_htc_pkt / HTC_PACKET object */ 385 htt_htc_pkt_free(soc, htt_pkt); 386 } 387 388 /* 389 * htt_h2t_ver_req_msg() - Send HTT version request message to target 390 * @htt_soc: HTT SOC handle 391 * 392 * Return: 0 on success; error code on failure 393 */ 394 static int htt_h2t_ver_req_msg(struct htt_soc *soc) 395 { 396 struct dp_htt_htc_pkt *pkt; 397 qdf_nbuf_t msg; 398 uint32_t *msg_word; 399 400 msg = qdf_nbuf_alloc( 401 soc->osdev, 402 HTT_MSG_BUF_SIZE(HTT_VER_REQ_BYTES), 403 /* reserve room for the HTC header */ 404 HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, TRUE); 405 if (!msg) 406 return QDF_STATUS_E_NOMEM; 407 408 /* 409 * Set the length of the message. 410 * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added 411 * separately during the below call to qdf_nbuf_push_head. 412 * The contribution from the HTC header is added separately inside HTC. 413 */ 414 if (qdf_nbuf_put_tail(msg, HTT_VER_REQ_BYTES) == NULL) { 415 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 416 "%s: Failed to expand head for HTT_H2T_MSG_TYPE_VERSION_REQ msg\n", 417 __func__); 418 return QDF_STATUS_E_FAILURE; 419 } 420 421 /* fill in the message contents */ 422 msg_word = (u_int32_t *) qdf_nbuf_data(msg); 423 424 /* rewind beyond alignment pad to get to the HTC header reserved area */ 425 qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); 426 427 *msg_word = 0; 428 HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_VERSION_REQ); 429 430 pkt = htt_htc_pkt_alloc(soc); 431 if (!pkt) { 432 qdf_nbuf_free(msg); 433 return QDF_STATUS_E_FAILURE; 434 } 435 pkt->soc_ctxt = NULL; /* not used during send-done callback */ 436 437 SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, 438 dp_htt_h2t_send_complete_free_netbuf, qdf_nbuf_data(msg), 439 qdf_nbuf_len(msg), soc->htc_endpoint, 440 1); /* tag - not relevant here */ 441 442 SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); 443 DP_HTT_SEND_HTC_PKT(soc, pkt); 444 return 0; 445 } 446 447 /* 448 * htt_srng_setup() - Send SRNG setup message to target 449 * @htt_soc: HTT SOC handle 450 * @mac_id: MAC Id 451 * @hal_srng: Opaque HAL SRNG pointer 452 * @hal_ring_type: SRNG ring type 453 * 454 * Return: 0 on success; error code on failure 455 */ 456 int htt_srng_setup(void *htt_soc, int mac_id, void *hal_srng, 457 int hal_ring_type) 458 { 459 struct htt_soc *soc = (struct htt_soc *)htt_soc; 460 struct dp_htt_htc_pkt *pkt; 461 qdf_nbuf_t htt_msg; 462 uint32_t *msg_word; 463 struct hal_srng_params srng_params; 464 qdf_dma_addr_t hp_addr, tp_addr; 465 uint32_t ring_entry_size = 466 hal_srng_get_entrysize(soc->hal_soc, hal_ring_type); 467 int htt_ring_type, htt_ring_id; 468 469 /* Sizes should be set in 4-byte words */ 470 ring_entry_size = ring_entry_size >> 2; 471 472 htt_msg = qdf_nbuf_alloc(soc->osdev, 473 HTT_MSG_BUF_SIZE(HTT_SRING_SETUP_SZ), 474 /* reserve room for the HTC header */ 475 HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, TRUE); 476 if (!htt_msg) 477 goto fail0; 478 479 hal_get_srng_params(soc->hal_soc, hal_srng, &srng_params); 480 hp_addr = hal_srng_get_hp_addr(soc->hal_soc, hal_srng); 481 tp_addr = hal_srng_get_tp_addr(soc->hal_soc, hal_srng); 482 483 switch (hal_ring_type) { 484 case RXDMA_BUF: 485 #ifdef QCA_HOST2FW_RXBUF_RING 486 if (srng_params.ring_id == 487 (HAL_SRNG_WMAC1_SW2RXDMA0_BUF0)) { 488 htt_ring_id = HTT_HOST1_TO_FW_RXBUF_RING; 489 htt_ring_type = HTT_SW_TO_SW_RING; 490 #ifdef IPA_OFFLOAD 491 } else if (srng_params.ring_id == 492 (HAL_SRNG_WMAC1_SW2RXDMA0_BUF2)) { 493 htt_ring_id = HTT_HOST2_TO_FW_RXBUF_RING; 494 htt_ring_type = HTT_SW_TO_SW_RING; 495 #endif 496 #else 497 if (srng_params.ring_id == 498 (HAL_SRNG_WMAC1_SW2RXDMA0_BUF0 + 499 (mac_id * HAL_MAX_RINGS_PER_LMAC))) { 500 htt_ring_id = HTT_RXDMA_HOST_BUF_RING; 501 htt_ring_type = HTT_SW_TO_HW_RING; 502 #endif 503 } else if (srng_params.ring_id == 504 #ifdef IPA_OFFLOAD 505 (HAL_SRNG_WMAC1_SW2RXDMA0_BUF1 + 506 #else 507 (HAL_SRNG_WMAC1_SW2RXDMA1_BUF + 508 #endif 509 (mac_id * HAL_MAX_RINGS_PER_LMAC))) { 510 htt_ring_id = HTT_RXDMA_HOST_BUF_RING; 511 htt_ring_type = HTT_SW_TO_HW_RING; 512 } else { 513 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 514 "%s: Ring %d currently not supported\n", 515 __func__, srng_params.ring_id); 516 goto fail1; 517 } 518 519 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 520 "%s: ring_type %d ring_id %d\n", 521 __func__, hal_ring_type, srng_params.ring_id); 522 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 523 "%s: hp_addr 0x%llx tp_addr 0x%llx\n", 524 __func__, (uint64_t)hp_addr, (uint64_t)tp_addr); 525 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 526 "%s: htt_ring_id %d\n", __func__, htt_ring_id); 527 break; 528 case RXDMA_MONITOR_BUF: 529 htt_ring_id = HTT_RXDMA_MONITOR_BUF_RING; 530 htt_ring_type = HTT_SW_TO_HW_RING; 531 break; 532 case RXDMA_MONITOR_STATUS: 533 htt_ring_id = HTT_RXDMA_MONITOR_STATUS_RING; 534 htt_ring_type = HTT_SW_TO_HW_RING; 535 break; 536 case RXDMA_MONITOR_DST: 537 htt_ring_id = HTT_RXDMA_MONITOR_DEST_RING; 538 htt_ring_type = HTT_HW_TO_SW_RING; 539 break; 540 case RXDMA_MONITOR_DESC: 541 htt_ring_id = HTT_RXDMA_MONITOR_DESC_RING; 542 htt_ring_type = HTT_SW_TO_HW_RING; 543 break; 544 case RXDMA_DST: 545 htt_ring_id = HTT_RXDMA_NON_MONITOR_DEST_RING; 546 htt_ring_type = HTT_HW_TO_SW_RING; 547 break; 548 549 default: 550 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 551 "%s: Ring currently not supported\n", __func__); 552 goto fail1; 553 } 554 555 /* 556 * Set the length of the message. 557 * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added 558 * separately during the below call to qdf_nbuf_push_head. 559 * The contribution from the HTC header is added separately inside HTC. 560 */ 561 if (qdf_nbuf_put_tail(htt_msg, HTT_SRING_SETUP_SZ) == NULL) { 562 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 563 "%s: Failed to expand head for SRING_SETUP msg\n", 564 __func__); 565 return QDF_STATUS_E_FAILURE; 566 } 567 568 msg_word = (uint32_t *)qdf_nbuf_data(htt_msg); 569 570 /* rewind beyond alignment pad to get to the HTC header reserved area */ 571 qdf_nbuf_push_head(htt_msg, HTC_HDR_ALIGNMENT_PADDING); 572 573 /* word 0 */ 574 *msg_word = 0; 575 HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_SRING_SETUP); 576 577 if ((htt_ring_type == HTT_SW_TO_HW_RING) || 578 (htt_ring_type == HTT_HW_TO_SW_RING)) 579 HTT_SRING_SETUP_PDEV_ID_SET(*msg_word, 580 DP_SW2HW_MACID(mac_id)); 581 else 582 HTT_SRING_SETUP_PDEV_ID_SET(*msg_word, mac_id); 583 584 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 585 "%s: mac_id %d\n", __func__, mac_id); 586 HTT_SRING_SETUP_RING_TYPE_SET(*msg_word, htt_ring_type); 587 /* TODO: Discuss with FW on changing this to unique ID and using 588 * htt_ring_type to send the type of ring 589 */ 590 HTT_SRING_SETUP_RING_ID_SET(*msg_word, htt_ring_id); 591 592 /* word 1 */ 593 msg_word++; 594 *msg_word = 0; 595 HTT_SRING_SETUP_RING_BASE_ADDR_LO_SET(*msg_word, 596 srng_params.ring_base_paddr & 0xffffffff); 597 598 /* word 2 */ 599 msg_word++; 600 *msg_word = 0; 601 HTT_SRING_SETUP_RING_BASE_ADDR_HI_SET(*msg_word, 602 (uint64_t)srng_params.ring_base_paddr >> 32); 603 604 /* word 3 */ 605 msg_word++; 606 *msg_word = 0; 607 HTT_SRING_SETUP_ENTRY_SIZE_SET(*msg_word, ring_entry_size); 608 HTT_SRING_SETUP_RING_SIZE_SET(*msg_word, 609 (ring_entry_size * srng_params.num_entries)); 610 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 611 "%s: entry_size %d\n", __func__, 612 ring_entry_size); 613 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 614 "%s: num_entries %d\n", __func__, 615 srng_params.num_entries); 616 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 617 "%s: ring_size %d\n", __func__, 618 (ring_entry_size * srng_params.num_entries)); 619 if (htt_ring_type == HTT_SW_TO_HW_RING) 620 HTT_SRING_SETUP_RING_MISC_CFG_FLAG_LOOPCOUNT_DISABLE_SET( 621 *msg_word, 1); 622 HTT_SRING_SETUP_RING_MISC_CFG_FLAG_MSI_SWAP_SET(*msg_word, 623 !!(srng_params.flags & HAL_SRNG_MSI_SWAP)); 624 HTT_SRING_SETUP_RING_MISC_CFG_FLAG_TLV_SWAP_SET(*msg_word, 625 !!(srng_params.flags & HAL_SRNG_DATA_TLV_SWAP)); 626 HTT_SRING_SETUP_RING_MISC_CFG_FLAG_HOST_FW_SWAP_SET(*msg_word, 627 !!(srng_params.flags & HAL_SRNG_RING_PTR_SWAP)); 628 629 /* word 4 */ 630 msg_word++; 631 *msg_word = 0; 632 HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_LO_SET(*msg_word, 633 hp_addr & 0xffffffff); 634 635 /* word 5 */ 636 msg_word++; 637 *msg_word = 0; 638 HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_HI_SET(*msg_word, 639 (uint64_t)hp_addr >> 32); 640 641 /* word 6 */ 642 msg_word++; 643 *msg_word = 0; 644 HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_LO_SET(*msg_word, 645 tp_addr & 0xffffffff); 646 647 /* word 7 */ 648 msg_word++; 649 *msg_word = 0; 650 HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_HI_SET(*msg_word, 651 (uint64_t)tp_addr >> 32); 652 653 /* word 8 */ 654 msg_word++; 655 *msg_word = 0; 656 HTT_SRING_SETUP_RING_MSI_ADDR_LO_SET(*msg_word, 657 srng_params.msi_addr & 0xffffffff); 658 659 /* word 9 */ 660 msg_word++; 661 *msg_word = 0; 662 HTT_SRING_SETUP_RING_MSI_ADDR_HI_SET(*msg_word, 663 (uint64_t)(srng_params.msi_addr) >> 32); 664 665 /* word 10 */ 666 msg_word++; 667 *msg_word = 0; 668 HTT_SRING_SETUP_RING_MSI_DATA_SET(*msg_word, 669 srng_params.msi_data); 670 671 /* word 11 */ 672 msg_word++; 673 *msg_word = 0; 674 HTT_SRING_SETUP_INTR_BATCH_COUNTER_TH_SET(*msg_word, 675 srng_params.intr_batch_cntr_thres_entries * 676 ring_entry_size); 677 HTT_SRING_SETUP_INTR_TIMER_TH_SET(*msg_word, 678 srng_params.intr_timer_thres_us >> 3); 679 680 /* word 12 */ 681 msg_word++; 682 *msg_word = 0; 683 if (srng_params.flags & HAL_SRNG_LOW_THRES_INTR_ENABLE) { 684 /* TODO: Setting low threshold to 1/8th of ring size - see 685 * if this needs to be configurable 686 */ 687 HTT_SRING_SETUP_INTR_LOW_TH_SET(*msg_word, 688 srng_params.low_threshold); 689 } 690 /* "response_required" field should be set if a HTT response message is 691 * required after setting up the ring. 692 */ 693 pkt = htt_htc_pkt_alloc(soc); 694 if (!pkt) 695 goto fail1; 696 697 pkt->soc_ctxt = NULL; /* not used during send-done callback */ 698 699 SET_HTC_PACKET_INFO_TX( 700 &pkt->htc_pkt, 701 dp_htt_h2t_send_complete_free_netbuf, 702 qdf_nbuf_data(htt_msg), 703 qdf_nbuf_len(htt_msg), 704 soc->htc_endpoint, 705 HTC_TX_PACKET_TAG_RUNTIME_PUT); /* tag for no FW response msg */ 706 707 SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, htt_msg); 708 DP_HTT_SEND_HTC_PKT(soc, pkt); 709 710 return QDF_STATUS_SUCCESS; 711 712 fail1: 713 qdf_nbuf_free(htt_msg); 714 fail0: 715 return QDF_STATUS_E_FAILURE; 716 } 717 718 /* 719 * htt_h2t_rx_ring_cfg() - Send SRNG packet and TLV filter 720 * config message to target 721 * @htt_soc: HTT SOC handle 722 * @pdev_id: PDEV Id 723 * @hal_srng: Opaque HAL SRNG pointer 724 * @hal_ring_type: SRNG ring type 725 * @ring_buf_size: SRNG buffer size 726 * @htt_tlv_filter: Rx SRNG TLV and filter setting 727 * Return: 0 on success; error code on failure 728 */ 729 int htt_h2t_rx_ring_cfg(void *htt_soc, int pdev_id, void *hal_srng, 730 int hal_ring_type, int ring_buf_size, 731 struct htt_rx_ring_tlv_filter *htt_tlv_filter) 732 { 733 struct htt_soc *soc = (struct htt_soc *)htt_soc; 734 struct dp_htt_htc_pkt *pkt; 735 qdf_nbuf_t htt_msg; 736 uint32_t *msg_word; 737 struct hal_srng_params srng_params; 738 uint32_t htt_ring_type, htt_ring_id; 739 uint32_t tlv_filter; 740 741 htt_msg = qdf_nbuf_alloc(soc->osdev, 742 HTT_MSG_BUF_SIZE(HTT_RX_RING_SELECTION_CFG_SZ), 743 /* reserve room for the HTC header */ 744 HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, TRUE); 745 if (!htt_msg) 746 goto fail0; 747 748 hal_get_srng_params(soc->hal_soc, hal_srng, &srng_params); 749 750 switch (hal_ring_type) { 751 case RXDMA_BUF: 752 #if QCA_HOST2FW_RXBUF_RING 753 htt_ring_id = HTT_HOST1_TO_FW_RXBUF_RING; 754 htt_ring_type = HTT_SW_TO_SW_RING; 755 #else 756 htt_ring_id = HTT_RXDMA_HOST_BUF_RING; 757 htt_ring_type = HTT_SW_TO_HW_RING; 758 #endif 759 break; 760 case RXDMA_MONITOR_BUF: 761 htt_ring_id = HTT_RXDMA_MONITOR_BUF_RING; 762 htt_ring_type = HTT_SW_TO_HW_RING; 763 break; 764 case RXDMA_MONITOR_STATUS: 765 htt_ring_id = HTT_RXDMA_MONITOR_STATUS_RING; 766 htt_ring_type = HTT_SW_TO_HW_RING; 767 break; 768 case RXDMA_MONITOR_DST: 769 htt_ring_id = HTT_RXDMA_MONITOR_DEST_RING; 770 htt_ring_type = HTT_HW_TO_SW_RING; 771 break; 772 case RXDMA_MONITOR_DESC: 773 htt_ring_id = HTT_RXDMA_MONITOR_DESC_RING; 774 htt_ring_type = HTT_SW_TO_HW_RING; 775 break; 776 case RXDMA_DST: 777 htt_ring_id = HTT_RXDMA_NON_MONITOR_DEST_RING; 778 htt_ring_type = HTT_HW_TO_SW_RING; 779 break; 780 781 default: 782 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 783 "%s: Ring currently not supported\n", __func__); 784 goto fail1; 785 } 786 787 /* 788 * Set the length of the message. 789 * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added 790 * separately during the below call to qdf_nbuf_push_head. 791 * The contribution from the HTC header is added separately inside HTC. 792 */ 793 if (qdf_nbuf_put_tail(htt_msg, HTT_RX_RING_SELECTION_CFG_SZ) == NULL) { 794 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 795 "%s: Failed to expand head for RX Ring Cfg msg\n", 796 __func__); 797 goto fail1; /* failure */ 798 } 799 800 msg_word = (uint32_t *)qdf_nbuf_data(htt_msg); 801 802 /* rewind beyond alignment pad to get to the HTC header reserved area */ 803 qdf_nbuf_push_head(htt_msg, HTC_HDR_ALIGNMENT_PADDING); 804 805 /* word 0 */ 806 *msg_word = 0; 807 HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG); 808 809 /* 810 * pdev_id is indexed from 0 whereas mac_id is indexed from 1 811 * SW_TO_SW and SW_TO_HW rings are unaffected by this 812 */ 813 if (htt_ring_type == HTT_SW_TO_SW_RING || 814 htt_ring_type == HTT_SW_TO_HW_RING) 815 HTT_RX_RING_SELECTION_CFG_PDEV_ID_SET(*msg_word, 816 DP_SW2HW_MACID(pdev_id)); 817 818 /* TODO: Discuss with FW on changing this to unique ID and using 819 * htt_ring_type to send the type of ring 820 */ 821 HTT_RX_RING_SELECTION_CFG_RING_ID_SET(*msg_word, htt_ring_id); 822 823 HTT_RX_RING_SELECTION_CFG_STATUS_TLV_SET(*msg_word, 824 !!(srng_params.flags & HAL_SRNG_MSI_SWAP)); 825 826 HTT_RX_RING_SELECTION_CFG_PKT_TLV_SET(*msg_word, 827 !!(srng_params.flags & HAL_SRNG_DATA_TLV_SWAP)); 828 829 /* word 1 */ 830 msg_word++; 831 *msg_word = 0; 832 HTT_RX_RING_SELECTION_CFG_RING_BUFFER_SIZE_SET(*msg_word, 833 ring_buf_size); 834 835 /* word 2 */ 836 msg_word++; 837 *msg_word = 0; 838 839 if (htt_tlv_filter->enable_fp) { 840 /* TYPE: MGMT */ 841 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 842 FP, MGMT, 0000, 843 (htt_tlv_filter->fp_mgmt_filter & 844 FILTER_MGMT_ASSOC_REQ) ? 1 : 0); 845 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 846 FP, MGMT, 0001, 847 (htt_tlv_filter->fp_mgmt_filter & 848 FILTER_MGMT_ASSOC_RES) ? 1 : 0); 849 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 850 FP, MGMT, 0010, 851 (htt_tlv_filter->fp_mgmt_filter & 852 FILTER_MGMT_REASSOC_REQ) ? 1 : 0); 853 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 854 FP, MGMT, 0011, 855 (htt_tlv_filter->fp_mgmt_filter & 856 FILTER_MGMT_REASSOC_RES) ? 1 : 0); 857 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 858 FP, MGMT, 0100, 859 (htt_tlv_filter->fp_mgmt_filter & 860 FILTER_MGMT_PROBE_REQ) ? 1 : 0); 861 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 862 FP, MGMT, 0101, 863 (htt_tlv_filter->fp_mgmt_filter & 864 FILTER_MGMT_PROBE_RES) ? 1 : 0); 865 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 866 FP, MGMT, 0110, 867 (htt_tlv_filter->fp_mgmt_filter & 868 FILTER_MGMT_TIM_ADVT) ? 1 : 0); 869 /* reserved */ 870 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, FP, 871 MGMT, 0111, 872 (htt_tlv_filter->fp_mgmt_filter & 873 FILTER_MGMT_RESERVED_7) ? 1 : 0); 874 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 875 FP, MGMT, 1000, 876 (htt_tlv_filter->fp_mgmt_filter & 877 FILTER_MGMT_BEACON) ? 1 : 0); 878 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 879 FP, MGMT, 1001, 880 (htt_tlv_filter->fp_mgmt_filter & 881 FILTER_MGMT_ATIM) ? 1 : 0); 882 } 883 884 if (htt_tlv_filter->enable_md) { 885 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, MD, 886 MGMT, 0000, 1); 887 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, MD, 888 MGMT, 0001, 1); 889 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, MD, 890 MGMT, 0010, 1); 891 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, MD, 892 MGMT, 0011, 1); 893 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, MD, 894 MGMT, 0100, 1); 895 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, MD, 896 MGMT, 0101, 1); 897 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, MD, 898 MGMT, 0110, 1); 899 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, MD, 900 MGMT, 0111, 1); 901 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, MD, 902 MGMT, 1000, 1); 903 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, MD, 904 MGMT, 1001, 1); 905 } 906 907 if (htt_tlv_filter->enable_mo) { 908 /* TYPE: MGMT */ 909 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 910 MO, MGMT, 0000, 911 (htt_tlv_filter->mo_mgmt_filter & 912 FILTER_MGMT_ASSOC_REQ) ? 1 : 0); 913 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 914 MO, MGMT, 0001, 915 (htt_tlv_filter->mo_mgmt_filter & 916 FILTER_MGMT_ASSOC_RES) ? 1 : 0); 917 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 918 MO, MGMT, 0010, 919 (htt_tlv_filter->mo_mgmt_filter & 920 FILTER_MGMT_REASSOC_REQ) ? 1 : 0); 921 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 922 MO, MGMT, 0011, 923 (htt_tlv_filter->mo_mgmt_filter & 924 FILTER_MGMT_REASSOC_RES) ? 1 : 0); 925 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 926 MO, MGMT, 0100, 927 (htt_tlv_filter->mo_mgmt_filter & 928 FILTER_MGMT_PROBE_REQ) ? 1 : 0); 929 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 930 MO, MGMT, 0101, 931 (htt_tlv_filter->mo_mgmt_filter & 932 FILTER_MGMT_PROBE_RES) ? 1 : 0); 933 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 934 MO, MGMT, 0110, 935 (htt_tlv_filter->mo_mgmt_filter & 936 FILTER_MGMT_TIM_ADVT) ? 1 : 0); 937 /* reserved */ 938 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, MO, 939 MGMT, 0111, 940 (htt_tlv_filter->mo_mgmt_filter & 941 FILTER_MGMT_RESERVED_7) ? 1 : 0); 942 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 943 MO, MGMT, 1000, 944 (htt_tlv_filter->mo_mgmt_filter & 945 FILTER_MGMT_BEACON) ? 1 : 0); 946 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG0, 947 MO, MGMT, 1001, 948 (htt_tlv_filter->mo_mgmt_filter & 949 FILTER_MGMT_ATIM) ? 1 : 0); 950 } 951 952 /* word 3 */ 953 msg_word++; 954 *msg_word = 0; 955 956 if (htt_tlv_filter->enable_fp) { 957 /* TYPE: MGMT */ 958 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, 959 FP, MGMT, 1010, 960 (htt_tlv_filter->fp_mgmt_filter & 961 FILTER_MGMT_DISASSOC) ? 1 : 0); 962 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, 963 FP, MGMT, 1011, 964 (htt_tlv_filter->fp_mgmt_filter & 965 FILTER_MGMT_AUTH) ? 1 : 0); 966 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, 967 FP, MGMT, 1100, 968 (htt_tlv_filter->fp_mgmt_filter & 969 FILTER_MGMT_DEAUTH) ? 1 : 0); 970 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, 971 FP, MGMT, 1101, 972 (htt_tlv_filter->fp_mgmt_filter & 973 FILTER_MGMT_ACTION) ? 1 : 0); 974 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, 975 FP, MGMT, 1110, 976 (htt_tlv_filter->fp_mgmt_filter & 977 FILTER_MGMT_ACT_NO_ACK) ? 1 : 0); 978 /* reserved*/ 979 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, FP, 980 MGMT, 1111, 981 (htt_tlv_filter->fp_mgmt_filter & 982 FILTER_MGMT_RESERVED_15) ? 1 : 0); 983 } 984 985 if (htt_tlv_filter->enable_md) { 986 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, MD, 987 MGMT, 1010, 1); 988 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, MD, 989 MGMT, 1011, 1); 990 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, MD, 991 MGMT, 1100, 1); 992 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, MD, 993 MGMT, 1101, 1); 994 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, MD, 995 MGMT, 1110, 1); 996 } 997 998 if (htt_tlv_filter->enable_mo) { 999 /* TYPE: MGMT */ 1000 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, 1001 MO, MGMT, 1010, 1002 (htt_tlv_filter->mo_mgmt_filter & 1003 FILTER_MGMT_DISASSOC) ? 1 : 0); 1004 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, 1005 MO, MGMT, 1011, 1006 (htt_tlv_filter->mo_mgmt_filter & 1007 FILTER_MGMT_AUTH) ? 1 : 0); 1008 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, 1009 MO, MGMT, 1100, 1010 (htt_tlv_filter->mo_mgmt_filter & 1011 FILTER_MGMT_DEAUTH) ? 1 : 0); 1012 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, 1013 MO, MGMT, 1101, 1014 (htt_tlv_filter->mo_mgmt_filter & 1015 FILTER_MGMT_ACTION) ? 1 : 0); 1016 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, 1017 MO, MGMT, 1110, 1018 (htt_tlv_filter->mo_mgmt_filter & 1019 FILTER_MGMT_ACT_NO_ACK) ? 1 : 0); 1020 /* reserved*/ 1021 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG1, MO, 1022 MGMT, 1111, 1023 (htt_tlv_filter->mo_mgmt_filter & 1024 FILTER_MGMT_RESERVED_15) ? 1 : 0); 1025 } 1026 1027 /* word 4 */ 1028 msg_word++; 1029 *msg_word = 0; 1030 1031 if (htt_tlv_filter->enable_fp) { 1032 /* TYPE: CTRL */ 1033 /* reserved */ 1034 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, FP, 1035 CTRL, 0000, 1036 (htt_tlv_filter->fp_ctrl_filter & 1037 FILTER_CTRL_RESERVED_1) ? 1 : 0); 1038 /* reserved */ 1039 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, FP, 1040 CTRL, 0001, 1041 (htt_tlv_filter->fp_ctrl_filter & 1042 FILTER_CTRL_RESERVED_2) ? 1 : 0); 1043 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, FP, 1044 CTRL, 0010, 1045 (htt_tlv_filter->fp_ctrl_filter & 1046 FILTER_CTRL_TRIGGER) ? 1 : 0); 1047 /* reserved */ 1048 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, FP, 1049 CTRL, 0011, 1050 (htt_tlv_filter->fp_ctrl_filter & 1051 FILTER_CTRL_RESERVED_4) ? 1 : 0); 1052 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, FP, 1053 CTRL, 0100, 1054 (htt_tlv_filter->fp_ctrl_filter & 1055 FILTER_CTRL_BF_REP_POLL) ? 1 : 0); 1056 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, FP, 1057 CTRL, 0101, 1058 (htt_tlv_filter->fp_ctrl_filter & 1059 FILTER_CTRL_VHT_NDP) ? 1 : 0); 1060 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, FP, 1061 CTRL, 0110, 1062 (htt_tlv_filter->fp_ctrl_filter & 1063 FILTER_CTRL_FRAME_EXT) ? 1 : 0); 1064 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, FP, 1065 CTRL, 0111, 1066 (htt_tlv_filter->fp_ctrl_filter & 1067 FILTER_CTRL_CTRLWRAP) ? 1 : 0); 1068 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, FP, 1069 CTRL, 1000, 1070 (htt_tlv_filter->fp_ctrl_filter & 1071 FILTER_CTRL_BA_REQ) ? 1 : 0); 1072 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, FP, 1073 CTRL, 1001, 1074 (htt_tlv_filter->fp_ctrl_filter & 1075 FILTER_CTRL_BA) ? 1 : 0); 1076 } 1077 1078 if (htt_tlv_filter->enable_md) { 1079 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1080 CTRL, 0000, 1); 1081 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1082 CTRL, 0001, 1); 1083 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1084 CTRL, 0010, 1); 1085 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1086 CTRL, 0011, 1); 1087 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1088 CTRL, 0100, 1); 1089 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1090 CTRL, 0101, 1); 1091 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1092 CTRL, 0110, 1); 1093 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MD, 1094 CTRL, 0111, 1); 1095 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MD, 1096 CTRL, 1000, 1); 1097 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MD, 1098 CTRL, 1001, 1); 1099 } 1100 1101 if (htt_tlv_filter->enable_mo) { 1102 /* TYPE: CTRL */ 1103 /* reserved */ 1104 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1105 CTRL, 0000, 1106 (htt_tlv_filter->mo_ctrl_filter & 1107 FILTER_CTRL_RESERVED_1) ? 1 : 0); 1108 /* reserved */ 1109 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1110 CTRL, 0001, 1111 (htt_tlv_filter->mo_ctrl_filter & 1112 FILTER_CTRL_RESERVED_2) ? 1 : 0); 1113 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1114 CTRL, 0010, 1115 (htt_tlv_filter->mo_ctrl_filter & 1116 FILTER_CTRL_TRIGGER) ? 1 : 0); 1117 /* reserved */ 1118 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1119 CTRL, 0011, 1120 (htt_tlv_filter->mo_ctrl_filter & 1121 FILTER_CTRL_RESERVED_4) ? 1 : 0); 1122 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1123 CTRL, 0100, 1124 (htt_tlv_filter->mo_ctrl_filter & 1125 FILTER_CTRL_BF_REP_POLL) ? 1 : 0); 1126 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1127 CTRL, 0101, 1128 (htt_tlv_filter->mo_ctrl_filter & 1129 FILTER_CTRL_VHT_NDP) ? 1 : 0); 1130 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1131 CTRL, 0110, 1132 (htt_tlv_filter->mo_ctrl_filter & 1133 FILTER_CTRL_FRAME_EXT) ? 1 : 0); 1134 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1135 CTRL, 0111, 1136 (htt_tlv_filter->mo_ctrl_filter & 1137 FILTER_CTRL_CTRLWRAP) ? 1 : 0); 1138 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1139 CTRL, 1000, 1140 (htt_tlv_filter->mo_ctrl_filter & 1141 FILTER_CTRL_BA_REQ) ? 1 : 0); 1142 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG2, MO, 1143 CTRL, 1001, 1144 (htt_tlv_filter->mo_ctrl_filter & 1145 FILTER_CTRL_BA) ? 1 : 0); 1146 } 1147 1148 /* word 5 */ 1149 msg_word++; 1150 *msg_word = 0; 1151 if (htt_tlv_filter->enable_fp) { 1152 /* TYPE: CTRL */ 1153 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, FP, 1154 CTRL, 1010, 1155 (htt_tlv_filter->fp_ctrl_filter & 1156 FILTER_CTRL_PSPOLL) ? 1 : 0); 1157 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, FP, 1158 CTRL, 1011, 1159 (htt_tlv_filter->fp_ctrl_filter & 1160 FILTER_CTRL_RTS) ? 1 : 0); 1161 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, FP, 1162 CTRL, 1100, 1163 (htt_tlv_filter->fp_ctrl_filter & 1164 FILTER_CTRL_CTS) ? 1 : 0); 1165 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, FP, 1166 CTRL, 1101, 1167 (htt_tlv_filter->fp_ctrl_filter & 1168 FILTER_CTRL_ACK) ? 1 : 0); 1169 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, FP, 1170 CTRL, 1110, 1171 (htt_tlv_filter->fp_ctrl_filter & 1172 FILTER_CTRL_CFEND) ? 1 : 0); 1173 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, FP, 1174 CTRL, 1111, 1175 (htt_tlv_filter->fp_ctrl_filter & 1176 FILTER_CTRL_CFEND_CFACK) ? 1 : 0); 1177 /* TYPE: DATA */ 1178 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, FP, 1179 DATA, MCAST, 1180 (htt_tlv_filter->fp_data_filter & 1181 FILTER_DATA_MCAST) ? 1 : 0); 1182 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, FP, 1183 DATA, UCAST, 1184 (htt_tlv_filter->fp_data_filter & 1185 FILTER_DATA_UCAST) ? 1 : 0); 1186 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, FP, 1187 DATA, NULL, 1188 (htt_tlv_filter->fp_data_filter & 1189 FILTER_DATA_NULL) ? 1 : 0); 1190 } 1191 1192 if (htt_tlv_filter->enable_md) { 1193 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MD, 1194 CTRL, 1010, 1); 1195 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MD, 1196 CTRL, 1011, 1); 1197 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MD, 1198 CTRL, 1100, 1); 1199 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MD, 1200 CTRL, 1101, 1); 1201 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MD, 1202 CTRL, 1110, 1); 1203 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MD, 1204 CTRL, 1111, 1); 1205 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MD, 1206 DATA, MCAST, 1); 1207 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MD, 1208 DATA, UCAST, 1); 1209 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MD, 1210 DATA, NULL, 1); 1211 } 1212 1213 if (htt_tlv_filter->enable_mo) { 1214 /* TYPE: CTRL */ 1215 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MO, 1216 CTRL, 1010, 1217 (htt_tlv_filter->mo_ctrl_filter & 1218 FILTER_CTRL_PSPOLL) ? 1 : 0); 1219 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MO, 1220 CTRL, 1011, 1221 (htt_tlv_filter->mo_ctrl_filter & 1222 FILTER_CTRL_RTS) ? 1 : 0); 1223 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MO, 1224 CTRL, 1100, 1225 (htt_tlv_filter->mo_ctrl_filter & 1226 FILTER_CTRL_CTS) ? 1 : 0); 1227 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MO, 1228 CTRL, 1101, 1229 (htt_tlv_filter->mo_ctrl_filter & 1230 FILTER_CTRL_ACK) ? 1 : 0); 1231 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MO, 1232 CTRL, 1110, 1233 (htt_tlv_filter->mo_ctrl_filter & 1234 FILTER_CTRL_CFEND) ? 1 : 0); 1235 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MO, 1236 CTRL, 1111, 1237 (htt_tlv_filter->mo_ctrl_filter & 1238 FILTER_CTRL_CFEND_CFACK) ? 1 : 0); 1239 /* TYPE: DATA */ 1240 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MO, 1241 DATA, MCAST, 1242 (htt_tlv_filter->mo_data_filter & 1243 FILTER_DATA_MCAST) ? 1 : 0); 1244 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MO, 1245 DATA, UCAST, 1246 (htt_tlv_filter->mo_data_filter & 1247 FILTER_DATA_UCAST) ? 1 : 0); 1248 htt_rx_ring_pkt_enable_subtype_set(*msg_word, FLAG3, MO, 1249 DATA, NULL, 1250 (htt_tlv_filter->mo_data_filter & 1251 FILTER_DATA_NULL) ? 1 : 0); 1252 } 1253 1254 /* word 6 */ 1255 msg_word++; 1256 *msg_word = 0; 1257 tlv_filter = 0; 1258 htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, MPDU_START, 1259 htt_tlv_filter->mpdu_start); 1260 htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, MSDU_START, 1261 htt_tlv_filter->msdu_start); 1262 htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, PACKET, 1263 htt_tlv_filter->packet); 1264 htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, MSDU_END, 1265 htt_tlv_filter->msdu_end); 1266 htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, MPDU_END, 1267 htt_tlv_filter->mpdu_end); 1268 htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, PACKET_HEADER, 1269 htt_tlv_filter->packet_header); 1270 htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, ATTENTION, 1271 htt_tlv_filter->attention); 1272 htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, PPDU_START, 1273 htt_tlv_filter->ppdu_start); 1274 htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, PPDU_END, 1275 htt_tlv_filter->ppdu_end); 1276 htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, PPDU_END_USER_STATS, 1277 htt_tlv_filter->ppdu_end_user_stats); 1278 htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, 1279 PPDU_END_USER_STATS_EXT, 1280 htt_tlv_filter->ppdu_end_user_stats_ext); 1281 htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, PPDU_END_STATUS_DONE, 1282 htt_tlv_filter->ppdu_end_status_done); 1283 /* RESERVED bit maps to header_per_msdu in htt_tlv_filter*/ 1284 htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, RESERVED, 1285 htt_tlv_filter->header_per_msdu); 1286 1287 HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_SET(*msg_word, tlv_filter); 1288 1289 /* "response_required" field should be set if a HTT response message is 1290 * required after setting up the ring. 1291 */ 1292 pkt = htt_htc_pkt_alloc(soc); 1293 if (!pkt) 1294 goto fail1; 1295 1296 pkt->soc_ctxt = NULL; /* not used during send-done callback */ 1297 1298 SET_HTC_PACKET_INFO_TX( 1299 &pkt->htc_pkt, 1300 dp_htt_h2t_send_complete_free_netbuf, 1301 qdf_nbuf_data(htt_msg), 1302 qdf_nbuf_len(htt_msg), 1303 soc->htc_endpoint, 1304 1); /* tag - not relevant here */ 1305 1306 SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, htt_msg); 1307 DP_HTT_SEND_HTC_PKT(soc, pkt); 1308 return QDF_STATUS_SUCCESS; 1309 1310 fail1: 1311 qdf_nbuf_free(htt_msg); 1312 fail0: 1313 return QDF_STATUS_E_FAILURE; 1314 } 1315 1316 #if defined(CONFIG_WIN) && WDI_EVENT_ENABLE 1317 static inline QDF_STATUS dp_send_htt_stat_resp(struct htt_stats_context *htt_stats, 1318 struct dp_soc *soc, qdf_nbuf_t htt_msg) 1319 1320 { 1321 uint32_t pdev_id; 1322 uint32_t *msg_word = NULL; 1323 uint32_t msg_remain_len = 0; 1324 1325 msg_word = (uint32_t *) qdf_nbuf_data(htt_msg); 1326 1327 /*COOKIE MSB*/ 1328 pdev_id = *(msg_word + 2) & HTT_PID_BIT_MASK; 1329 1330 /* stats message length + 16 size of HTT header*/ 1331 msg_remain_len = qdf_min(htt_stats->msg_len + 16, 1332 (uint32_t)DP_EXT_MSG_LENGTH); 1333 1334 dp_wdi_event_handler(WDI_EVENT_HTT_STATS, soc, 1335 msg_word, msg_remain_len, 1336 WDI_NO_VAL, pdev_id); 1337 1338 if (htt_stats->msg_len >= DP_EXT_MSG_LENGTH) { 1339 htt_stats->msg_len -= DP_EXT_MSG_LENGTH; 1340 } 1341 /* Need to be freed here as WDI handler will 1342 * make a copy of pkt to send data to application 1343 */ 1344 qdf_nbuf_free(htt_msg); 1345 return QDF_STATUS_SUCCESS; 1346 } 1347 #else 1348 static inline QDF_STATUS dp_send_htt_stat_resp(struct htt_stats_context *htt_stats, 1349 struct dp_soc *soc, qdf_nbuf_t htt_msg) 1350 { 1351 return QDF_STATUS_E_NOSUPPORT; 1352 } 1353 #endif 1354 1355 /** 1356 * dp_process_htt_stat_msg(): Process the list of buffers of HTT EXT stats 1357 * @htt_stats: htt stats info 1358 * 1359 * The FW sends the HTT EXT STATS as a stream of T2H messages. Each T2H message 1360 * contains sub messages which are identified by a TLV header. 1361 * In this function we will process the stream of T2H messages and read all the 1362 * TLV contained in the message. 1363 * 1364 * THe following cases have been taken care of 1365 * Case 1: When the tlv_remain_length <= msg_remain_length of HTT MSG buffer 1366 * In this case the buffer will contain multiple tlvs. 1367 * Case 2: When the tlv_remain_length > msg_remain_length of HTT MSG buffer. 1368 * Only one tlv will be contained in the HTT message and this tag 1369 * will extend onto the next buffer. 1370 * Case 3: When the buffer is the continuation of the previous message 1371 * Case 4: tlv length is 0. which will indicate the end of message 1372 * 1373 * return: void 1374 */ 1375 static inline void dp_process_htt_stat_msg(struct htt_stats_context *htt_stats, 1376 struct dp_soc *soc) 1377 { 1378 htt_tlv_tag_t tlv_type = 0xff; 1379 qdf_nbuf_t htt_msg = NULL; 1380 uint32_t *msg_word; 1381 uint8_t *tlv_buf_head = NULL; 1382 uint8_t *tlv_buf_tail = NULL; 1383 uint32_t msg_remain_len = 0; 1384 uint32_t tlv_remain_len = 0; 1385 uint32_t *tlv_start; 1386 int cookie_val; 1387 int cookie_msb; 1388 int pdev_id; 1389 bool copy_stats = false; 1390 struct dp_pdev *pdev; 1391 1392 /* Process node in the HTT message queue */ 1393 while ((htt_msg = qdf_nbuf_queue_remove(&htt_stats->msg)) 1394 != NULL) { 1395 msg_word = (uint32_t *) qdf_nbuf_data(htt_msg); 1396 cookie_val = *(msg_word + 1); 1397 if (cookie_val) { 1398 if (dp_send_htt_stat_resp(htt_stats, soc, htt_msg) 1399 == QDF_STATUS_SUCCESS) { 1400 continue; 1401 } 1402 } 1403 1404 cookie_msb = *(msg_word + 2); 1405 pdev_id = *(msg_word + 2) & HTT_PID_BIT_MASK; 1406 pdev = soc->pdev_list[pdev_id]; 1407 1408 if (cookie_msb >> 2) { 1409 copy_stats = true; 1410 } 1411 1412 htt_stats->msg_len = HTT_T2H_EXT_STATS_CONF_TLV_LENGTH_GET( 1413 *(msg_word + 1414 HTT_T2H_EXT_STATS_TLV_START_OFFSET)); 1415 1416 /* read 5th word */ 1417 msg_word = msg_word + 4; 1418 msg_remain_len = qdf_min(htt_stats->msg_len, 1419 (uint32_t) DP_EXT_MSG_LENGTH); 1420 /* Keep processing the node till node length is 0 */ 1421 while (msg_remain_len) { 1422 /* 1423 * if message is not a continuation of previous message 1424 * read the tlv type and tlv length 1425 */ 1426 if (!tlv_buf_head) { 1427 tlv_type = HTT_STATS_TLV_TAG_GET( 1428 *msg_word); 1429 tlv_remain_len = HTT_STATS_TLV_LENGTH_GET( 1430 *msg_word); 1431 } 1432 1433 if (tlv_remain_len == 0) { 1434 msg_remain_len = 0; 1435 1436 if (tlv_buf_head) { 1437 qdf_mem_free(tlv_buf_head); 1438 tlv_buf_head = NULL; 1439 tlv_buf_tail = NULL; 1440 } 1441 1442 goto error; 1443 } 1444 1445 if (!tlv_buf_head) 1446 tlv_remain_len += HTT_TLV_HDR_LEN; 1447 1448 if ((tlv_remain_len <= msg_remain_len)) { 1449 /* Case 3 */ 1450 if (tlv_buf_head) { 1451 qdf_mem_copy(tlv_buf_tail, 1452 (uint8_t *)msg_word, 1453 tlv_remain_len); 1454 tlv_start = (uint32_t *)tlv_buf_head; 1455 } else { 1456 /* Case 1 */ 1457 tlv_start = msg_word; 1458 } 1459 1460 if (copy_stats) 1461 dp_htt_stats_copy_tag(pdev, tlv_type, tlv_start); 1462 else 1463 dp_htt_stats_print_tag(tlv_type, tlv_start); 1464 1465 msg_remain_len -= tlv_remain_len; 1466 1467 msg_word = (uint32_t *) 1468 (((uint8_t *)msg_word) + 1469 tlv_remain_len); 1470 1471 tlv_remain_len = 0; 1472 1473 if (tlv_buf_head) { 1474 qdf_mem_free(tlv_buf_head); 1475 tlv_buf_head = NULL; 1476 tlv_buf_tail = NULL; 1477 } 1478 1479 } else { /* tlv_remain_len > msg_remain_len */ 1480 /* Case 2 & 3 */ 1481 if (!tlv_buf_head) { 1482 tlv_buf_head = qdf_mem_malloc( 1483 tlv_remain_len); 1484 1485 if (!tlv_buf_head) { 1486 QDF_TRACE(QDF_MODULE_ID_TXRX, 1487 QDF_TRACE_LEVEL_ERROR, 1488 "Alloc failed"); 1489 goto error; 1490 } 1491 1492 tlv_buf_tail = tlv_buf_head; 1493 } 1494 1495 qdf_mem_copy(tlv_buf_tail, (uint8_t *)msg_word, 1496 msg_remain_len); 1497 tlv_remain_len -= msg_remain_len; 1498 tlv_buf_tail += msg_remain_len; 1499 } 1500 } 1501 1502 if (htt_stats->msg_len >= DP_EXT_MSG_LENGTH) { 1503 htt_stats->msg_len -= DP_EXT_MSG_LENGTH; 1504 } 1505 1506 qdf_nbuf_free(htt_msg); 1507 } 1508 return; 1509 1510 error: 1511 qdf_nbuf_free(htt_msg); 1512 while ((htt_msg = qdf_nbuf_queue_remove(&htt_stats->msg)) 1513 != NULL) 1514 qdf_nbuf_free(htt_msg); 1515 } 1516 1517 void htt_t2h_stats_handler(void *context) 1518 { 1519 struct dp_soc *soc = (struct dp_soc *)context; 1520 struct htt_stats_context htt_stats; 1521 uint32_t *msg_word; 1522 qdf_nbuf_t htt_msg = NULL; 1523 uint8_t done; 1524 uint8_t rem_stats; 1525 1526 if (!soc || !qdf_atomic_read(&soc->cmn_init_done)) { 1527 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 1528 "soc: 0x%pK, init_done: %d", soc, 1529 qdf_atomic_read(&soc->cmn_init_done)); 1530 return; 1531 } 1532 1533 qdf_mem_zero(&htt_stats, sizeof(htt_stats)); 1534 qdf_nbuf_queue_init(&htt_stats.msg); 1535 1536 /* pull one completed stats from soc->htt_stats_msg and process */ 1537 qdf_spin_lock_bh(&soc->htt_stats.lock); 1538 if (!soc->htt_stats.num_stats) { 1539 qdf_spin_unlock_bh(&soc->htt_stats.lock); 1540 return; 1541 } 1542 while ((htt_msg = qdf_nbuf_queue_remove(&soc->htt_stats.msg)) != NULL) { 1543 msg_word = (uint32_t *) qdf_nbuf_data(htt_msg); 1544 msg_word = msg_word + HTT_T2H_EXT_STATS_TLV_START_OFFSET; 1545 done = HTT_T2H_EXT_STATS_CONF_TLV_DONE_GET(*msg_word); 1546 qdf_nbuf_queue_add(&htt_stats.msg, htt_msg); 1547 /* 1548 * Done bit signifies that this is the last T2H buffer in the 1549 * stream of HTT EXT STATS message 1550 */ 1551 if (done) 1552 break; 1553 } 1554 rem_stats = --soc->htt_stats.num_stats; 1555 qdf_spin_unlock_bh(&soc->htt_stats.lock); 1556 1557 dp_process_htt_stat_msg(&htt_stats, soc); 1558 /* If there are more stats to process, schedule stats work again */ 1559 if (rem_stats) 1560 qdf_sched_work(0, &soc->htt_stats.work); 1561 } 1562 1563 /* 1564 * dp_get_ppdu_info_user_index: Find and allocate a per-user descriptor for a PPDU, 1565 * if a new peer id arrives in a PPDU 1566 * pdev: DP pdev handle 1567 * @peer_id : peer unique identifier 1568 * @ppdu_info: per ppdu tlv structure 1569 * 1570 * return:user index to be populated 1571 */ 1572 #ifdef FEATURE_PERPKT_INFO 1573 static uint8_t dp_get_ppdu_info_user_index(struct dp_pdev *pdev, 1574 uint16_t peer_id, 1575 struct ppdu_info *ppdu_info) 1576 { 1577 uint8_t user_index = 0; 1578 struct cdp_tx_completion_ppdu *ppdu_desc; 1579 struct cdp_tx_completion_ppdu_user *ppdu_user_desc; 1580 1581 ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); 1582 1583 while ((user_index + 1) <= ppdu_info->last_user) { 1584 ppdu_user_desc = &ppdu_desc->user[user_index]; 1585 if (ppdu_user_desc->peer_id != peer_id) { 1586 user_index++; 1587 continue; 1588 } else { 1589 /* Max users possible is 8 so user array index should 1590 * not exceed 7 1591 */ 1592 qdf_assert_always(user_index <= CDP_MU_MAX_USER_INDEX); 1593 return user_index; 1594 } 1595 } 1596 1597 ppdu_info->last_user++; 1598 /* Max users possible is 8 so last user should not exceed 8 */ 1599 qdf_assert_always(ppdu_info->last_user <= CDP_MU_MAX_USERS); 1600 return ppdu_info->last_user - 1; 1601 } 1602 1603 /* 1604 * dp_process_ppdu_stats_common_tlv: Process htt_ppdu_stats_common_tlv 1605 * pdev: DP pdev handle 1606 * @tag_buf: buffer containing the tlv htt_ppdu_stats_common_tlv 1607 * @ppdu_info: per ppdu tlv structure 1608 * 1609 * return:void 1610 */ 1611 static void dp_process_ppdu_stats_common_tlv(struct dp_pdev *pdev, 1612 uint32_t *tag_buf, struct ppdu_info *ppdu_info) 1613 { 1614 uint16_t frame_type; 1615 uint16_t freq; 1616 struct dp_soc *soc = NULL; 1617 struct cdp_tx_completion_ppdu *ppdu_desc = NULL; 1618 1619 ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); 1620 1621 tag_buf += 2; 1622 ppdu_desc->num_users = 1623 HTT_PPDU_STATS_COMMON_TLV_NUM_USERS_GET(*tag_buf); 1624 tag_buf++; 1625 frame_type = HTT_PPDU_STATS_COMMON_TLV_FRM_TYPE_GET(*tag_buf); 1626 1627 if ((frame_type == HTT_STATS_FTYPE_TIDQ_DATA_SU) || 1628 (frame_type == HTT_STATS_FTYPE_TIDQ_DATA_MU)) 1629 ppdu_desc->frame_type = CDP_PPDU_FTYPE_DATA; 1630 else 1631 ppdu_desc->frame_type = CDP_PPDU_FTYPE_CTRL; 1632 1633 tag_buf += 2; 1634 ppdu_desc->tx_duration = *tag_buf; 1635 tag_buf += 3; 1636 ppdu_desc->ppdu_start_timestamp = *tag_buf; 1637 1638 ppdu_desc->ppdu_end_timestamp = ppdu_desc->ppdu_start_timestamp + 1639 ppdu_desc->tx_duration; 1640 /* Ack time stamp is same as end time stamp*/ 1641 ppdu_desc->ack_timestamp = ppdu_desc->ppdu_end_timestamp; 1642 1643 tag_buf++; 1644 1645 freq = HTT_PPDU_STATS_COMMON_TLV_CHAN_MHZ_GET(*tag_buf); 1646 if (freq != ppdu_desc->channel) { 1647 soc = pdev->soc; 1648 ppdu_desc->channel = freq; 1649 if (soc && soc->cdp_soc.ol_ops->freq_to_channel) 1650 pdev->operating_channel = 1651 soc->cdp_soc.ol_ops->freq_to_channel(pdev->osif_pdev, freq); 1652 } 1653 1654 ppdu_desc->phy_mode = HTT_PPDU_STATS_COMMON_TLV_PHY_MODE_GET(*tag_buf); 1655 } 1656 1657 /* 1658 * dp_process_ppdu_stats_user_common_tlv: Process ppdu_stats_user_common 1659 * @tag_buf: buffer containing the tlv htt_ppdu_stats_user_common_tlv 1660 * @ppdu_info: per ppdu tlv structure 1661 * 1662 * return:void 1663 */ 1664 static void dp_process_ppdu_stats_user_common_tlv( 1665 struct dp_pdev *pdev, uint32_t *tag_buf, 1666 struct ppdu_info *ppdu_info) 1667 { 1668 uint16_t peer_id; 1669 struct dp_peer *peer; 1670 struct cdp_tx_completion_ppdu *ppdu_desc; 1671 struct cdp_tx_completion_ppdu_user *ppdu_user_desc; 1672 uint8_t curr_user_index = 0; 1673 1674 ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); 1675 1676 tag_buf++; 1677 peer_id = HTT_PPDU_STATS_USER_COMMON_TLV_SW_PEER_ID_GET(*tag_buf); 1678 peer = dp_peer_find_by_id(pdev->soc, peer_id); 1679 1680 if (!peer) 1681 return; 1682 1683 curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); 1684 ppdu_user_desc = &ppdu_desc->user[curr_user_index]; 1685 1686 ppdu_user_desc->peer_id = peer_id; 1687 1688 tag_buf++; 1689 1690 if (HTT_PPDU_STATS_USER_COMMON_TLV_MCAST_GET(*tag_buf)) { 1691 ppdu_user_desc->is_mcast = true; 1692 ppdu_user_desc->mpdu_tried_mcast = 1693 HTT_PPDU_STATS_USER_COMMON_TLV_MPDUS_TRIED_GET(*tag_buf); 1694 ppdu_user_desc->num_mpdu = ppdu_user_desc->mpdu_tried_mcast; 1695 } else { 1696 ppdu_user_desc->mpdu_tried_ucast = 1697 HTT_PPDU_STATS_USER_COMMON_TLV_MPDUS_TRIED_GET(*tag_buf); 1698 } 1699 1700 tag_buf++; 1701 1702 ppdu_user_desc->qos_ctrl = 1703 HTT_PPDU_STATS_USER_COMMON_TLV_QOS_CTRL_GET(*tag_buf); 1704 ppdu_user_desc->frame_ctrl = 1705 HTT_PPDU_STATS_USER_COMMON_TLV_FRAME_CTRL_GET(*tag_buf); 1706 ppdu_desc->frame_ctrl = ppdu_user_desc->frame_ctrl; 1707 } 1708 1709 1710 /** 1711 * dp_process_ppdu_stats_user_rate_tlv() - Process htt_ppdu_stats_user_rate_tlv 1712 * @pdev: DP pdev handle 1713 * @tag_buf: T2H message buffer carrying the user rate TLV 1714 * @ppdu_info: per ppdu tlv structure 1715 * 1716 * return:void 1717 */ 1718 static void dp_process_ppdu_stats_user_rate_tlv(struct dp_pdev *pdev, 1719 uint32_t *tag_buf, 1720 struct ppdu_info *ppdu_info) 1721 { 1722 uint16_t peer_id; 1723 struct dp_peer *peer; 1724 struct cdp_tx_completion_ppdu *ppdu_desc; 1725 struct cdp_tx_completion_ppdu_user *ppdu_user_desc; 1726 uint8_t curr_user_index = 0; 1727 1728 ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); 1729 1730 tag_buf++; 1731 peer_id = HTT_PPDU_STATS_USER_RATE_TLV_SW_PEER_ID_GET(*tag_buf); 1732 peer = dp_peer_find_by_id(pdev->soc, peer_id); 1733 1734 if (!peer) 1735 return; 1736 1737 curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); 1738 1739 ppdu_user_desc = &ppdu_desc->user[curr_user_index]; 1740 ppdu_user_desc->peer_id = peer_id; 1741 1742 ppdu_user_desc->tid = 1743 HTT_PPDU_STATS_USER_RATE_TLV_TID_NUM_GET(*tag_buf); 1744 1745 qdf_mem_copy(ppdu_user_desc->mac_addr, peer->mac_addr.raw, 1746 DP_MAC_ADDR_LEN); 1747 1748 tag_buf += 2; 1749 1750 ppdu_user_desc->ru_tones = (HTT_PPDU_STATS_USER_RATE_TLV_RU_END_GET(*tag_buf) - 1751 HTT_PPDU_STATS_USER_RATE_TLV_RU_START_GET(*tag_buf)) + 1; 1752 1753 tag_buf += 2; 1754 1755 ppdu_user_desc->ppdu_type = 1756 HTT_PPDU_STATS_USER_RATE_TLV_PPDU_TYPE_GET(*tag_buf); 1757 1758 tag_buf++; 1759 ppdu_user_desc->tx_rate = *tag_buf; 1760 1761 ppdu_user_desc->ltf_size = 1762 HTT_PPDU_STATS_USER_RATE_TLV_LTF_SIZE_GET(*tag_buf); 1763 ppdu_user_desc->stbc = 1764 HTT_PPDU_STATS_USER_RATE_TLV_STBC_GET(*tag_buf); 1765 ppdu_user_desc->he_re = 1766 HTT_PPDU_STATS_USER_RATE_TLV_HE_RE_GET(*tag_buf); 1767 ppdu_user_desc->txbf = 1768 HTT_PPDU_STATS_USER_RATE_TLV_TXBF_GET(*tag_buf); 1769 ppdu_user_desc->bw = 1770 HTT_PPDU_STATS_USER_RATE_TLV_BW_GET(*tag_buf); 1771 ppdu_user_desc->nss = HTT_PPDU_STATS_USER_RATE_TLV_NSS_GET(*tag_buf); 1772 ppdu_user_desc->mcs = HTT_PPDU_STATS_USER_RATE_TLV_MCS_GET(*tag_buf); 1773 ppdu_user_desc->preamble = 1774 HTT_PPDU_STATS_USER_RATE_TLV_PREAMBLE_GET(*tag_buf); 1775 ppdu_user_desc->gi = HTT_PPDU_STATS_USER_RATE_TLV_GI_GET(*tag_buf); 1776 ppdu_user_desc->dcm = HTT_PPDU_STATS_USER_RATE_TLV_DCM_GET(*tag_buf); 1777 ppdu_user_desc->ldpc = HTT_PPDU_STATS_USER_RATE_TLV_LDPC_GET(*tag_buf); 1778 } 1779 1780 /* 1781 * dp_process_ppdu_stats_enq_mpdu_bitmap_64_tlv: Process 1782 * htt_ppdu_stats_enq_mpdu_bitmap_64_tlv 1783 * pdev: DP PDEV handle 1784 * @tag_buf: buffer containing the tlv htt_ppdu_stats_enq_mpdu_bitmap_64_tlv 1785 * @ppdu_info: per ppdu tlv structure 1786 * 1787 * return:void 1788 */ 1789 static void dp_process_ppdu_stats_enq_mpdu_bitmap_64_tlv( 1790 struct dp_pdev *pdev, uint32_t *tag_buf, 1791 struct ppdu_info *ppdu_info) 1792 { 1793 htt_ppdu_stats_enq_mpdu_bitmap_64_tlv *dp_stats_buf = 1794 (htt_ppdu_stats_enq_mpdu_bitmap_64_tlv *)tag_buf; 1795 1796 struct cdp_tx_completion_ppdu *ppdu_desc; 1797 struct cdp_tx_completion_ppdu_user *ppdu_user_desc; 1798 uint8_t curr_user_index = 0; 1799 uint16_t peer_id; 1800 struct dp_peer *peer; 1801 1802 ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); 1803 1804 tag_buf++; 1805 1806 peer_id = 1807 HTT_PPDU_STATS_ENQ_MPDU_BITMAP_TLV_SW_PEER_ID_GET(*tag_buf); 1808 1809 peer = dp_peer_find_by_id(pdev->soc, peer_id); 1810 1811 if (!peer) 1812 return; 1813 1814 curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); 1815 1816 ppdu_user_desc = &ppdu_desc->user[curr_user_index]; 1817 ppdu_user_desc->peer_id = peer_id; 1818 1819 ppdu_user_desc->start_seq = dp_stats_buf->start_seq; 1820 qdf_mem_copy(&ppdu_user_desc->enq_bitmap, &dp_stats_buf->enq_bitmap, 1821 CDP_BA_64_BIT_MAP_SIZE_DWORDS); 1822 } 1823 1824 /* 1825 * dp_process_ppdu_stats_enq_mpdu_bitmap_256_tlv: Process 1826 * htt_ppdu_stats_enq_mpdu_bitmap_256_tlv 1827 * soc: DP SOC handle 1828 * @tag_buf: buffer containing the tlv htt_ppdu_stats_enq_mpdu_bitmap_256_tlv 1829 * @ppdu_info: per ppdu tlv structure 1830 * 1831 * return:void 1832 */ 1833 static void dp_process_ppdu_stats_enq_mpdu_bitmap_256_tlv( 1834 struct dp_pdev *pdev, uint32_t *tag_buf, 1835 struct ppdu_info *ppdu_info) 1836 { 1837 htt_ppdu_stats_enq_mpdu_bitmap_256_tlv *dp_stats_buf = 1838 (htt_ppdu_stats_enq_mpdu_bitmap_256_tlv *)tag_buf; 1839 1840 struct cdp_tx_completion_ppdu *ppdu_desc; 1841 struct cdp_tx_completion_ppdu_user *ppdu_user_desc; 1842 uint8_t curr_user_index = 0; 1843 uint16_t peer_id; 1844 struct dp_peer *peer; 1845 1846 ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); 1847 1848 tag_buf++; 1849 1850 peer_id = 1851 HTT_PPDU_STATS_ENQ_MPDU_BITMAP_TLV_SW_PEER_ID_GET(*tag_buf); 1852 1853 peer = dp_peer_find_by_id(pdev->soc, peer_id); 1854 1855 if (!peer) 1856 return; 1857 1858 curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); 1859 1860 ppdu_user_desc = &ppdu_desc->user[curr_user_index]; 1861 ppdu_user_desc->peer_id = peer_id; 1862 1863 ppdu_user_desc->start_seq = dp_stats_buf->start_seq; 1864 qdf_mem_copy(&ppdu_user_desc->enq_bitmap, &dp_stats_buf->enq_bitmap, 1865 CDP_BA_256_BIT_MAP_SIZE_DWORDS); 1866 } 1867 1868 /* 1869 * dp_process_ppdu_stats_user_cmpltn_common_tlv: Process 1870 * htt_ppdu_stats_user_cmpltn_common_tlv 1871 * soc: DP SOC handle 1872 * @tag_buf: buffer containing the tlv htt_ppdu_stats_user_cmpltn_common_tlv 1873 * @ppdu_info: per ppdu tlv structure 1874 * 1875 * return:void 1876 */ 1877 static void dp_process_ppdu_stats_user_cmpltn_common_tlv( 1878 struct dp_pdev *pdev, uint32_t *tag_buf, 1879 struct ppdu_info *ppdu_info) 1880 { 1881 uint16_t peer_id; 1882 struct dp_peer *peer; 1883 struct cdp_tx_completion_ppdu *ppdu_desc; 1884 struct cdp_tx_completion_ppdu_user *ppdu_user_desc; 1885 uint8_t curr_user_index = 0; 1886 htt_ppdu_stats_user_cmpltn_common_tlv *dp_stats_buf = 1887 (htt_ppdu_stats_user_cmpltn_common_tlv *)tag_buf; 1888 1889 ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); 1890 1891 tag_buf++; 1892 peer_id = 1893 HTT_PPDU_STATS_USER_CMPLTN_COMMON_TLV_SW_PEER_ID_GET(*tag_buf); 1894 peer = dp_peer_find_by_id(pdev->soc, peer_id); 1895 1896 if (!peer) 1897 return; 1898 1899 curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); 1900 ppdu_user_desc = &ppdu_desc->user[curr_user_index]; 1901 ppdu_user_desc->peer_id = peer_id; 1902 1903 ppdu_user_desc->completion_status = 1904 HTT_PPDU_STATS_USER_CMPLTN_COMMON_TLV_COMPLETION_STATUS_GET( 1905 *tag_buf); 1906 1907 ppdu_user_desc->tid = 1908 HTT_PPDU_STATS_USER_CMPLTN_COMMON_TLV_TID_NUM_GET(*tag_buf); 1909 1910 1911 tag_buf++; 1912 ppdu_desc->ack_rssi = dp_stats_buf->ack_rssi; 1913 1914 tag_buf++; 1915 1916 ppdu_user_desc->mpdu_success = 1917 HTT_PPDU_STATS_USER_CMPLTN_COMMON_TLV_MPDU_SUCCESS_GET(*tag_buf); 1918 1919 tag_buf++; 1920 1921 ppdu_user_desc->long_retries = 1922 HTT_PPDU_STATS_USER_CMPLTN_COMMON_TLV_LONG_RETRY_GET(*tag_buf); 1923 1924 ppdu_user_desc->short_retries = 1925 HTT_PPDU_STATS_USER_CMPLTN_COMMON_TLV_SHORT_RETRY_GET(*tag_buf); 1926 ppdu_user_desc->retry_msdus = 1927 ppdu_user_desc->long_retries + ppdu_user_desc->short_retries; 1928 1929 ppdu_user_desc->is_ampdu = 1930 HTT_PPDU_STATS_USER_CMPLTN_COMMON_TLV_IS_AMPDU_GET(*tag_buf); 1931 ppdu_info->is_ampdu = ppdu_user_desc->is_ampdu; 1932 1933 } 1934 1935 /* 1936 * dp_process_ppdu_stats_user_compltn_ba_bitmap_64_tlv: Process 1937 * htt_ppdu_stats_user_compltn_ba_bitmap_64_tlv 1938 * pdev: DP PDEV handle 1939 * @tag_buf: buffer containing the htt_ppdu_stats_user_compltn_ba_bitmap_64_tlv 1940 * @ppdu_info: per ppdu tlv structure 1941 * 1942 * return:void 1943 */ 1944 static void dp_process_ppdu_stats_user_compltn_ba_bitmap_64_tlv( 1945 struct dp_pdev *pdev, uint32_t *tag_buf, 1946 struct ppdu_info *ppdu_info) 1947 { 1948 htt_ppdu_stats_user_compltn_ba_bitmap_64_tlv *dp_stats_buf = 1949 (htt_ppdu_stats_user_compltn_ba_bitmap_64_tlv *)tag_buf; 1950 struct cdp_tx_completion_ppdu_user *ppdu_user_desc; 1951 struct cdp_tx_completion_ppdu *ppdu_desc; 1952 uint8_t curr_user_index = 0; 1953 uint16_t peer_id; 1954 struct dp_peer *peer; 1955 1956 ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); 1957 1958 tag_buf++; 1959 1960 peer_id = 1961 HTT_PPDU_STATS_USER_CMPLTN_BA_BITMAP_TLV_SW_PEER_ID_GET(*tag_buf); 1962 1963 peer = dp_peer_find_by_id(pdev->soc, peer_id); 1964 1965 if (!peer) 1966 return; 1967 1968 curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); 1969 1970 ppdu_user_desc = &ppdu_desc->user[curr_user_index]; 1971 ppdu_user_desc->peer_id = peer_id; 1972 1973 ppdu_user_desc->ba_seq_no = dp_stats_buf->ba_seq_no; 1974 qdf_mem_copy(&ppdu_user_desc->ba_bitmap, &dp_stats_buf->ba_bitmap, 1975 CDP_BA_64_BIT_MAP_SIZE_DWORDS); 1976 } 1977 1978 /* 1979 * dp_process_ppdu_stats_user_compltn_ba_bitmap_256_tlv: Process 1980 * htt_ppdu_stats_user_compltn_ba_bitmap_256_tlv 1981 * pdev: DP PDEV handle 1982 * @tag_buf: buffer containing the htt_ppdu_stats_user_compltn_ba_bitmap_256_tlv 1983 * @ppdu_info: per ppdu tlv structure 1984 * 1985 * return:void 1986 */ 1987 static void dp_process_ppdu_stats_user_compltn_ba_bitmap_256_tlv( 1988 struct dp_pdev *pdev, uint32_t *tag_buf, 1989 struct ppdu_info *ppdu_info) 1990 { 1991 htt_ppdu_stats_user_compltn_ba_bitmap_256_tlv *dp_stats_buf = 1992 (htt_ppdu_stats_user_compltn_ba_bitmap_256_tlv *)tag_buf; 1993 struct cdp_tx_completion_ppdu_user *ppdu_user_desc; 1994 struct cdp_tx_completion_ppdu *ppdu_desc; 1995 uint8_t curr_user_index = 0; 1996 uint16_t peer_id; 1997 struct dp_peer *peer; 1998 1999 ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); 2000 2001 tag_buf++; 2002 2003 peer_id = 2004 HTT_PPDU_STATS_USER_CMPLTN_BA_BITMAP_TLV_SW_PEER_ID_GET(*tag_buf); 2005 2006 peer = dp_peer_find_by_id(pdev->soc, peer_id); 2007 2008 if (!peer) 2009 return; 2010 2011 curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); 2012 2013 ppdu_user_desc = &ppdu_desc->user[curr_user_index]; 2014 ppdu_user_desc->peer_id = peer_id; 2015 2016 ppdu_user_desc->ba_seq_no = dp_stats_buf->ba_seq_no; 2017 qdf_mem_copy(&ppdu_user_desc->ba_bitmap, &dp_stats_buf->ba_bitmap, 2018 CDP_BA_256_BIT_MAP_SIZE_DWORDS); 2019 } 2020 2021 /* 2022 * dp_process_ppdu_stats_user_compltn_ack_ba_status_tlv: Process 2023 * htt_ppdu_stats_user_compltn_ack_ba_status_tlv 2024 * pdev: DP PDE handle 2025 * @tag_buf: buffer containing the htt_ppdu_stats_user_compltn_ack_ba_status_tlv 2026 * @ppdu_info: per ppdu tlv structure 2027 * 2028 * return:void 2029 */ 2030 static void dp_process_ppdu_stats_user_compltn_ack_ba_status_tlv( 2031 struct dp_pdev *pdev, uint32_t *tag_buf, 2032 struct ppdu_info *ppdu_info) 2033 { 2034 uint16_t peer_id; 2035 struct dp_peer *peer; 2036 struct cdp_tx_completion_ppdu *ppdu_desc; 2037 struct cdp_tx_completion_ppdu_user *ppdu_user_desc; 2038 uint8_t curr_user_index = 0; 2039 2040 ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); 2041 2042 tag_buf += 2; 2043 peer_id = 2044 HTT_PPDU_STATS_USER_CMPLTN_ACK_BA_STATUS_TLV_SW_PEER_ID_GET(*tag_buf); 2045 2046 2047 peer = dp_peer_find_by_id(pdev->soc, peer_id); 2048 2049 if (!peer) 2050 return; 2051 2052 curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); 2053 2054 ppdu_user_desc = &ppdu_desc->user[curr_user_index]; 2055 ppdu_user_desc->peer_id = peer_id; 2056 2057 tag_buf++; 2058 ppdu_user_desc->tid = 2059 HTT_PPDU_STATS_USER_CMPLTN_ACK_BA_STATUS_TLV_TID_NUM_GET(*tag_buf); 2060 ppdu_user_desc->num_mpdu = 2061 HTT_PPDU_STATS_USER_CMPLTN_ACK_BA_STATUS_TLV_NUM_MPDU_GET(*tag_buf); 2062 2063 ppdu_user_desc->num_msdu = 2064 HTT_PPDU_STATS_USER_CMPLTN_ACK_BA_STATUS_TLV_NUM_MSDU_GET(*tag_buf); 2065 2066 ppdu_user_desc->success_msdus = ppdu_user_desc->num_msdu; 2067 2068 tag_buf += 2; 2069 ppdu_user_desc->success_bytes = *tag_buf; 2070 2071 } 2072 2073 /* 2074 * dp_process_ppdu_stats_user_common_array_tlv: Process 2075 * htt_ppdu_stats_user_common_array_tlv 2076 * pdev: DP PDEV handle 2077 * @tag_buf: buffer containing the htt_ppdu_stats_user_compltn_ack_ba_status_tlv 2078 * @ppdu_info: per ppdu tlv structure 2079 * 2080 * return:void 2081 */ 2082 static void dp_process_ppdu_stats_user_common_array_tlv( 2083 struct dp_pdev *pdev, uint32_t *tag_buf, 2084 struct ppdu_info *ppdu_info) 2085 { 2086 uint32_t peer_id; 2087 struct dp_peer *peer; 2088 struct cdp_tx_completion_ppdu *ppdu_desc; 2089 struct cdp_tx_completion_ppdu_user *ppdu_user_desc; 2090 uint8_t curr_user_index = 0; 2091 struct htt_tx_ppdu_stats_info *dp_stats_buf; 2092 2093 ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); 2094 2095 tag_buf++; 2096 dp_stats_buf = (struct htt_tx_ppdu_stats_info *)tag_buf; 2097 tag_buf += 3; 2098 peer_id = 2099 HTT_PPDU_STATS_ARRAY_ITEM_TLV_PEERID_GET(*tag_buf); 2100 2101 peer = dp_peer_find_by_id(pdev->soc, peer_id); 2102 2103 if (!peer) { 2104 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 2105 "Invalid peer"); 2106 return; 2107 } 2108 2109 curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); 2110 2111 ppdu_user_desc = &ppdu_desc->user[curr_user_index]; 2112 2113 ppdu_user_desc->retry_bytes = dp_stats_buf->tx_retry_bytes; 2114 ppdu_user_desc->failed_bytes = dp_stats_buf->tx_failed_bytes; 2115 2116 tag_buf++; 2117 2118 ppdu_user_desc->success_msdus = 2119 HTT_PPDU_STATS_ARRAY_ITEM_TLV_TX_SUCC_MSDUS_GET(*tag_buf); 2120 ppdu_user_desc->retry_bytes = 2121 HTT_PPDU_STATS_ARRAY_ITEM_TLV_TX_RETRY_MSDUS_GET(*tag_buf); 2122 tag_buf++; 2123 ppdu_user_desc->failed_msdus = 2124 HTT_PPDU_STATS_ARRAY_ITEM_TLV_TX_FAILED_MSDUS_GET(*tag_buf); 2125 } 2126 2127 /* 2128 * dp_process_ppdu_stats_flush_tlv: Process 2129 * htt_ppdu_stats_flush_tlv 2130 * @pdev: DP PDEV handle 2131 * @tag_buf: buffer containing the htt_ppdu_stats_flush_tlv 2132 * 2133 * return:void 2134 */ 2135 static void dp_process_ppdu_stats_user_compltn_flush_tlv(struct dp_pdev *pdev, 2136 uint32_t *tag_buf) 2137 { 2138 uint32_t peer_id; 2139 uint32_t drop_reason; 2140 uint8_t tid; 2141 uint32_t num_msdu; 2142 struct dp_peer *peer; 2143 2144 tag_buf++; 2145 drop_reason = *tag_buf; 2146 2147 tag_buf++; 2148 num_msdu = HTT_PPDU_STATS_FLUSH_TLV_NUM_MSDU_GET(*tag_buf); 2149 2150 tag_buf++; 2151 peer_id = 2152 HTT_PPDU_STATS_FLUSH_TLV_SW_PEER_ID_GET(*tag_buf); 2153 2154 peer = dp_peer_find_by_id(pdev->soc, peer_id); 2155 if (!peer) 2156 return; 2157 2158 tid = HTT_PPDU_STATS_FLUSH_TLV_TID_NUM_GET(*tag_buf); 2159 2160 if (drop_reason == HTT_FLUSH_EXCESS_RETRIES) { 2161 DP_STATS_INC(peer, tx.excess_retries_per_ac[TID_TO_WME_AC(tid)], 2162 num_msdu); 2163 } 2164 } 2165 2166 /* 2167 * dp_process_ppdu_stats_tx_mgmtctrl_payload_tlv: Process 2168 * htt_ppdu_stats_tx_mgmtctrl_payload_tlv 2169 * @pdev: DP PDEV handle 2170 * @tag_buf: buffer containing the htt_ppdu_stats_tx_mgmtctrl_payload_tlv 2171 * @length: tlv_length 2172 * 2173 * return:void 2174 */ 2175 static void 2176 dp_process_ppdu_stats_tx_mgmtctrl_payload_tlv(struct dp_pdev *pdev, 2177 qdf_nbuf_t tag_buf, 2178 uint32_t length, 2179 uint32_t ppdu_id) 2180 { 2181 uint32_t *nbuf_ptr; 2182 2183 if ((!pdev->tx_sniffer_enable) && (!pdev->mcopy_mode)) 2184 return; 2185 2186 if (qdf_nbuf_pull_head(tag_buf, HTT_MGMT_CTRL_TLV_RESERVERD_LEN + 4) 2187 == NULL) 2188 return; 2189 2190 nbuf_ptr = (uint32_t *)qdf_nbuf_push_head( 2191 tag_buf, sizeof(ppdu_id)); 2192 *nbuf_ptr = ppdu_id; 2193 2194 dp_wdi_event_handler(WDI_EVENT_TX_MGMT_CTRL, pdev->soc, 2195 tag_buf, HTT_INVALID_PEER, 2196 WDI_NO_VAL, pdev->pdev_id); 2197 } 2198 2199 /** 2200 * dp_process_ppdu_tag(): Function to process the PPDU TLVs 2201 * @pdev: DP pdev handle 2202 * @tag_buf: TLV buffer 2203 * @tlv_len: length of tlv 2204 * @ppdu_info: per ppdu tlv structure 2205 * 2206 * return: void 2207 */ 2208 static void dp_process_ppdu_tag(struct dp_pdev *pdev, uint32_t *tag_buf, 2209 uint32_t tlv_len, struct ppdu_info *ppdu_info) 2210 { 2211 uint32_t tlv_type = HTT_STATS_TLV_TAG_GET(*tag_buf); 2212 2213 switch (tlv_type) { 2214 case HTT_PPDU_STATS_COMMON_TLV: 2215 qdf_assert_always(tlv_len == 2216 sizeof(htt_ppdu_stats_common_tlv)); 2217 dp_process_ppdu_stats_common_tlv(pdev, tag_buf, ppdu_info); 2218 break; 2219 case HTT_PPDU_STATS_USR_COMMON_TLV: 2220 qdf_assert_always(tlv_len == 2221 sizeof(htt_ppdu_stats_user_common_tlv)); 2222 dp_process_ppdu_stats_user_common_tlv( 2223 pdev, tag_buf, ppdu_info); 2224 break; 2225 case HTT_PPDU_STATS_USR_RATE_TLV: 2226 qdf_assert_always(tlv_len == 2227 sizeof(htt_ppdu_stats_user_rate_tlv)); 2228 dp_process_ppdu_stats_user_rate_tlv(pdev, tag_buf, ppdu_info); 2229 break; 2230 case HTT_PPDU_STATS_USR_MPDU_ENQ_BITMAP_64_TLV: 2231 qdf_assert_always(tlv_len == 2232 sizeof(htt_ppdu_stats_enq_mpdu_bitmap_64_tlv)); 2233 dp_process_ppdu_stats_enq_mpdu_bitmap_64_tlv( 2234 pdev, tag_buf, ppdu_info); 2235 break; 2236 case HTT_PPDU_STATS_USR_MPDU_ENQ_BITMAP_256_TLV: 2237 qdf_assert_always(tlv_len == 2238 sizeof(htt_ppdu_stats_enq_mpdu_bitmap_256_tlv)); 2239 dp_process_ppdu_stats_enq_mpdu_bitmap_256_tlv( 2240 pdev, tag_buf, ppdu_info); 2241 break; 2242 case HTT_PPDU_STATS_USR_COMPLTN_COMMON_TLV: 2243 qdf_assert_always(tlv_len == 2244 sizeof(htt_ppdu_stats_user_cmpltn_common_tlv)); 2245 dp_process_ppdu_stats_user_cmpltn_common_tlv( 2246 pdev, tag_buf, ppdu_info); 2247 break; 2248 case HTT_PPDU_STATS_USR_COMPLTN_BA_BITMAP_64_TLV: 2249 qdf_assert_always(tlv_len == 2250 sizeof(htt_ppdu_stats_user_compltn_ba_bitmap_64_tlv)); 2251 dp_process_ppdu_stats_user_compltn_ba_bitmap_64_tlv( 2252 pdev, tag_buf, ppdu_info); 2253 break; 2254 case HTT_PPDU_STATS_USR_COMPLTN_BA_BITMAP_256_TLV: 2255 qdf_assert_always(tlv_len == 2256 sizeof(htt_ppdu_stats_user_compltn_ba_bitmap_256_tlv)); 2257 dp_process_ppdu_stats_user_compltn_ba_bitmap_256_tlv( 2258 pdev, tag_buf, ppdu_info); 2259 break; 2260 case HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV: 2261 qdf_assert_always(tlv_len == 2262 sizeof(htt_ppdu_stats_user_compltn_ack_ba_status_tlv)); 2263 dp_process_ppdu_stats_user_compltn_ack_ba_status_tlv( 2264 pdev, tag_buf, ppdu_info); 2265 break; 2266 case HTT_PPDU_STATS_USR_COMMON_ARRAY_TLV: 2267 qdf_assert_always(tlv_len == 2268 sizeof(htt_ppdu_stats_usr_common_array_tlv_v)); 2269 dp_process_ppdu_stats_user_common_array_tlv( 2270 pdev, tag_buf, ppdu_info); 2271 break; 2272 case HTT_PPDU_STATS_USR_COMPLTN_FLUSH_TLV: 2273 qdf_assert_always(tlv_len == 2274 sizeof(htt_ppdu_stats_flush_tlv)); 2275 dp_process_ppdu_stats_user_compltn_flush_tlv( 2276 pdev, tag_buf); 2277 break; 2278 default: 2279 break; 2280 } 2281 } 2282 2283 /** 2284 * dp_ppdu_desc_deliver(): Function to deliver Tx PPDU status descriptor 2285 * to upper layer 2286 * @pdev: DP pdev handle 2287 * @ppdu_info: per PPDU TLV descriptor 2288 * 2289 * return: void 2290 */ 2291 static 2292 void dp_ppdu_desc_deliver(struct dp_pdev *pdev, 2293 struct ppdu_info *ppdu_info) 2294 { 2295 struct cdp_tx_completion_ppdu *ppdu_desc = NULL; 2296 struct dp_peer *peer = NULL; 2297 qdf_nbuf_t nbuf; 2298 uint16_t i; 2299 2300 ppdu_desc = (struct cdp_tx_completion_ppdu *) 2301 qdf_nbuf_data(ppdu_info->nbuf); 2302 2303 ppdu_desc->num_users = ppdu_info->last_user; 2304 ppdu_desc->ppdu_id = ppdu_info->ppdu_id; 2305 2306 for (i = 0; i < ppdu_desc->num_users; i++) { 2307 2308 2309 ppdu_desc->num_mpdu += ppdu_desc->user[i].num_mpdu; 2310 ppdu_desc->num_msdu += ppdu_desc->user[i].num_msdu; 2311 2312 if (ppdu_desc->user[i].tid < CDP_DATA_TID_MAX) { 2313 peer = dp_peer_find_by_id(pdev->soc, 2314 ppdu_desc->user[i].peer_id); 2315 /** 2316 * This check is to make sure peer is not deleted 2317 * after processing the TLVs. 2318 */ 2319 if (!peer) 2320 continue; 2321 2322 dp_tx_stats_update(pdev->soc, peer, 2323 &ppdu_desc->user[i], 2324 ppdu_desc->ack_rssi); 2325 } 2326 } 2327 2328 /* 2329 * Remove from the list 2330 */ 2331 TAILQ_REMOVE(&pdev->ppdu_info_list, ppdu_info, ppdu_info_list_elem); 2332 nbuf = ppdu_info->nbuf; 2333 pdev->list_depth--; 2334 qdf_mem_free(ppdu_info); 2335 2336 qdf_assert_always(nbuf); 2337 2338 ppdu_desc = (struct cdp_tx_completion_ppdu *) 2339 qdf_nbuf_data(nbuf); 2340 2341 /** 2342 * Deliver PPDU stats only for valid (acked) data frames if 2343 * sniffer mode is not enabled. 2344 * If sniffer mode is enabled, PPDU stats for all frames 2345 * including mgmt/control frames should be delivered to upper layer 2346 */ 2347 if (pdev->tx_sniffer_enable || pdev->mcopy_mode) { 2348 dp_wdi_event_handler(WDI_EVENT_TX_PPDU_DESC, pdev->soc, 2349 nbuf, HTT_INVALID_PEER, 2350 WDI_NO_VAL, pdev->pdev_id); 2351 } else { 2352 if (ppdu_desc->num_mpdu != 0 && ppdu_desc->num_users != 0 && 2353 ppdu_desc->frame_ctrl & HTT_FRAMECTRL_DATATYPE) { 2354 2355 dp_wdi_event_handler(WDI_EVENT_TX_PPDU_DESC, 2356 pdev->soc, nbuf, HTT_INVALID_PEER, 2357 WDI_NO_VAL, pdev->pdev_id); 2358 } else 2359 qdf_nbuf_free(nbuf); 2360 } 2361 return; 2362 } 2363 2364 /** 2365 * dp_get_ppdu_desc(): Function to allocate new PPDU status 2366 * desc for new ppdu id 2367 * @pdev: DP pdev handle 2368 * @ppdu_id: PPDU unique identifier 2369 * @tlv_type: TLV type received 2370 * 2371 * return: ppdu_info per ppdu tlv structure 2372 */ 2373 static 2374 struct ppdu_info *dp_get_ppdu_desc(struct dp_pdev *pdev, uint32_t ppdu_id, 2375 uint8_t tlv_type) 2376 { 2377 struct ppdu_info *ppdu_info = NULL; 2378 2379 /* 2380 * Find ppdu_id node exists or not 2381 */ 2382 TAILQ_FOREACH(ppdu_info, &pdev->ppdu_info_list, ppdu_info_list_elem) { 2383 2384 if (ppdu_info && (ppdu_info->ppdu_id == ppdu_id)) { 2385 break; 2386 } 2387 } 2388 2389 if (ppdu_info) { 2390 /** 2391 * if we get tlv_type that is already been processed for ppdu, 2392 * that means we got a new ppdu with same ppdu id. 2393 * Hence Flush the older ppdu 2394 */ 2395 if (ppdu_info->tlv_bitmap & (1 << tlv_type)) 2396 dp_ppdu_desc_deliver(pdev, ppdu_info); 2397 else 2398 return ppdu_info; 2399 } 2400 2401 /** 2402 * Flush the head ppdu descriptor if ppdu desc list reaches max 2403 * threshold 2404 */ 2405 if (pdev->list_depth > HTT_PPDU_DESC_MAX_DEPTH) { 2406 ppdu_info = TAILQ_FIRST(&pdev->ppdu_info_list); 2407 dp_ppdu_desc_deliver(pdev, ppdu_info); 2408 } 2409 2410 /* 2411 * Allocate new ppdu_info node 2412 */ 2413 ppdu_info = qdf_mem_malloc(sizeof(struct ppdu_info)); 2414 if (!ppdu_info) 2415 return NULL; 2416 2417 ppdu_info->nbuf = qdf_nbuf_alloc(pdev->soc->osdev, 2418 sizeof(struct cdp_tx_completion_ppdu), 0, 4, 2419 TRUE); 2420 if (!ppdu_info->nbuf) { 2421 qdf_mem_free(ppdu_info); 2422 return NULL; 2423 } 2424 2425 qdf_mem_zero(qdf_nbuf_data(ppdu_info->nbuf), 2426 sizeof(struct cdp_tx_completion_ppdu)); 2427 2428 if (qdf_nbuf_put_tail(ppdu_info->nbuf, 2429 sizeof(struct cdp_tx_completion_ppdu)) == NULL) { 2430 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 2431 "No tailroom for HTT PPDU"); 2432 qdf_nbuf_free(ppdu_info->nbuf); 2433 ppdu_info->nbuf = NULL; 2434 ppdu_info->last_user = 0; 2435 qdf_mem_free(ppdu_info); 2436 return NULL; 2437 } 2438 2439 /** 2440 * No lock is needed because all PPDU TLVs are processed in 2441 * same context and this list is updated in same context 2442 */ 2443 TAILQ_INSERT_TAIL(&pdev->ppdu_info_list, ppdu_info, 2444 ppdu_info_list_elem); 2445 pdev->list_depth++; 2446 return ppdu_info; 2447 } 2448 2449 /** 2450 * dp_htt_process_tlv(): Function to process each PPDU TLVs 2451 * @pdev: DP pdev handle 2452 * @htt_t2h_msg: HTT target to host message 2453 * 2454 * return: ppdu_info per ppdu tlv structure 2455 */ 2456 2457 static struct ppdu_info *dp_htt_process_tlv(struct dp_pdev *pdev, 2458 qdf_nbuf_t htt_t2h_msg, bool *free_buf) 2459 { 2460 uint32_t length; 2461 uint32_t ppdu_id; 2462 uint8_t tlv_type; 2463 uint32_t tlv_length, tlv_bitmap_expected; 2464 uint8_t *tlv_buf; 2465 struct ppdu_info *ppdu_info = NULL; 2466 2467 uint32_t *msg_word = (uint32_t *) qdf_nbuf_data(htt_t2h_msg); 2468 2469 length = HTT_T2H_PPDU_STATS_PAYLOAD_SIZE_GET(*msg_word); 2470 2471 msg_word = msg_word + 1; 2472 ppdu_id = HTT_T2H_PPDU_STATS_PPDU_ID_GET(*msg_word); 2473 2474 2475 msg_word = msg_word + 3; 2476 while (length > 0) { 2477 tlv_buf = (uint8_t *)msg_word; 2478 tlv_type = HTT_STATS_TLV_TAG_GET(*msg_word); 2479 tlv_length = HTT_STATS_TLV_LENGTH_GET(*msg_word); 2480 if (qdf_likely(tlv_type < CDP_PPDU_STATS_MAX_TAG)) 2481 pdev->stats.ppdu_stats_counter[tlv_type]++; 2482 2483 if (tlv_length == 0) 2484 break; 2485 2486 tlv_length += HTT_TLV_HDR_LEN; 2487 2488 /** 2489 * Not allocating separate ppdu descriptor for MGMT Payload 2490 * TLV as this is sent as separate WDI indication and it 2491 * doesn't contain any ppdu information 2492 */ 2493 if (tlv_type == HTT_PPDU_STATS_TX_MGMTCTRL_PAYLOAD_TLV) { 2494 dp_process_ppdu_stats_tx_mgmtctrl_payload_tlv(pdev, 2495 htt_t2h_msg, tlv_length, ppdu_id); 2496 msg_word = 2497 (uint32_t *)((uint8_t *)tlv_buf + tlv_length); 2498 length -= (tlv_length); 2499 *free_buf = false; 2500 return NULL; 2501 } 2502 2503 ppdu_info = dp_get_ppdu_desc(pdev, ppdu_id, tlv_type); 2504 if (!ppdu_info) 2505 return NULL; 2506 ppdu_info->ppdu_id = ppdu_id; 2507 ppdu_info->tlv_bitmap |= (1 << tlv_type); 2508 2509 dp_process_ppdu_tag(pdev, msg_word, tlv_length, ppdu_info); 2510 2511 /** 2512 * Increment pdev level tlv count to monitor 2513 * missing TLVs 2514 */ 2515 pdev->tlv_count++; 2516 ppdu_info->last_tlv_cnt = pdev->tlv_count; 2517 2518 msg_word = (uint32_t *)((uint8_t *)tlv_buf + tlv_length); 2519 length -= (tlv_length); 2520 } 2521 2522 if (!ppdu_info) 2523 return NULL; 2524 2525 pdev->last_ppdu_id = ppdu_id; 2526 2527 tlv_bitmap_expected = HTT_PPDU_DEFAULT_TLV_BITMAP; 2528 2529 if (pdev->tx_sniffer_enable || pdev->mcopy_mode) { 2530 if (ppdu_info->is_ampdu) 2531 tlv_bitmap_expected = HTT_PPDU_SNIFFER_AMPDU_TLV_BITMAP; 2532 } 2533 2534 /** 2535 * Once all the TLVs for a given PPDU has been processed, 2536 * return PPDU status to be delivered to higher layer 2537 */ 2538 if (ppdu_info->tlv_bitmap == tlv_bitmap_expected) 2539 return ppdu_info; 2540 2541 return NULL; 2542 } 2543 #endif /* FEATURE_PERPKT_INFO */ 2544 2545 /** 2546 * dp_txrx_ppdu_stats_handler() - Function to process HTT PPDU stats from FW 2547 * @soc: DP SOC handle 2548 * @pdev_id: pdev id 2549 * @htt_t2h_msg: HTT message nbuf 2550 * 2551 * return:void 2552 */ 2553 #if defined(WDI_EVENT_ENABLE) 2554 #ifdef FEATURE_PERPKT_INFO 2555 static bool dp_txrx_ppdu_stats_handler(struct dp_soc *soc, 2556 uint8_t pdev_id, qdf_nbuf_t htt_t2h_msg) 2557 { 2558 struct dp_pdev *pdev = soc->pdev_list[pdev_id]; 2559 struct ppdu_info *ppdu_info = NULL; 2560 bool free_buf = true; 2561 2562 if (!pdev->enhanced_stats_en && !pdev->tx_sniffer_enable && 2563 !pdev->mcopy_mode) 2564 return free_buf; 2565 2566 ppdu_info = dp_htt_process_tlv(pdev, htt_t2h_msg, &free_buf); 2567 if (ppdu_info) 2568 dp_ppdu_desc_deliver(pdev, ppdu_info); 2569 2570 return free_buf; 2571 } 2572 #else 2573 static bool dp_txrx_ppdu_stats_handler(struct dp_soc *soc, 2574 uint8_t pdev_id, qdf_nbuf_t htt_t2h_msg) 2575 { 2576 return true; 2577 } 2578 #endif 2579 #endif 2580 2581 /** 2582 * dp_txrx_fw_stats_handler() - Function to process HTT EXT stats 2583 * @soc: DP SOC handle 2584 * @htt_t2h_msg: HTT message nbuf 2585 * 2586 * return:void 2587 */ 2588 static inline void dp_txrx_fw_stats_handler(struct dp_soc *soc, 2589 qdf_nbuf_t htt_t2h_msg) 2590 { 2591 uint8_t done; 2592 qdf_nbuf_t msg_copy; 2593 uint32_t *msg_word; 2594 2595 msg_word = (uint32_t *) qdf_nbuf_data(htt_t2h_msg); 2596 msg_word = msg_word + 3; 2597 done = HTT_T2H_EXT_STATS_CONF_TLV_DONE_GET(*msg_word); 2598 2599 /* 2600 * HTT EXT stats response comes as stream of TLVs which span over 2601 * multiple T2H messages. 2602 * The first message will carry length of the response. 2603 * For rest of the messages length will be zero. 2604 * 2605 * Clone the T2H message buffer and store it in a list to process 2606 * it later. 2607 * 2608 * The original T2H message buffers gets freed in the T2H HTT event 2609 * handler 2610 */ 2611 msg_copy = qdf_nbuf_clone(htt_t2h_msg); 2612 2613 if (!msg_copy) { 2614 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, 2615 "T2H messge clone failed for HTT EXT STATS"); 2616 goto error; 2617 } 2618 2619 qdf_spin_lock_bh(&soc->htt_stats.lock); 2620 qdf_nbuf_queue_add(&soc->htt_stats.msg, msg_copy); 2621 /* 2622 * Done bit signifies that this is the last T2H buffer in the stream of 2623 * HTT EXT STATS message 2624 */ 2625 if (done) { 2626 soc->htt_stats.num_stats++; 2627 qdf_sched_work(0, &soc->htt_stats.work); 2628 } 2629 qdf_spin_unlock_bh(&soc->htt_stats.lock); 2630 2631 return; 2632 2633 error: 2634 qdf_spin_lock_bh(&soc->htt_stats.lock); 2635 while ((msg_copy = qdf_nbuf_queue_remove(&soc->htt_stats.msg)) 2636 != NULL) { 2637 qdf_nbuf_free(msg_copy); 2638 } 2639 soc->htt_stats.num_stats = 0; 2640 qdf_spin_unlock_bh(&soc->htt_stats.lock); 2641 return; 2642 2643 } 2644 2645 /* 2646 * htt_soc_attach_target() - SOC level HTT setup 2647 * @htt_soc: HTT SOC handle 2648 * 2649 * Return: 0 on success; error code on failure 2650 */ 2651 int htt_soc_attach_target(void *htt_soc) 2652 { 2653 struct htt_soc *soc = (struct htt_soc *)htt_soc; 2654 2655 return htt_h2t_ver_req_msg(soc); 2656 } 2657 2658 2659 #if defined(WDI_EVENT_ENABLE) && !defined(REMOVE_PKT_LOG) 2660 /* 2661 * dp_ppdu_stats_ind_handler() - PPDU stats msg handler 2662 * @htt_soc: HTT SOC handle 2663 * @msg_word: Pointer to payload 2664 * @htt_t2h_msg: HTT msg nbuf 2665 * 2666 * Return: None 2667 */ 2668 static bool 2669 dp_ppdu_stats_ind_handler(struct htt_soc *soc, 2670 uint32_t *msg_word, 2671 qdf_nbuf_t htt_t2h_msg) 2672 { 2673 u_int8_t pdev_id; 2674 bool free_buf; 2675 qdf_nbuf_set_pktlen(htt_t2h_msg, HTT_T2H_MAX_MSG_SIZE); 2676 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, 2677 "received HTT_T2H_MSG_TYPE_PPDU_STATS_IND\n"); 2678 pdev_id = HTT_T2H_PPDU_STATS_PDEV_ID_GET(*msg_word); 2679 pdev_id = DP_HW2SW_MACID(pdev_id); 2680 free_buf = dp_txrx_ppdu_stats_handler(soc->dp_soc, pdev_id, 2681 htt_t2h_msg); 2682 dp_wdi_event_handler(WDI_EVENT_LITE_T2H, soc->dp_soc, 2683 htt_t2h_msg, HTT_INVALID_PEER, WDI_NO_VAL, 2684 pdev_id); 2685 return free_buf; 2686 } 2687 #else 2688 dp_ppdu_stats_ind_handler(struct htt_soc *soc, 2689 qdf_nbuf_t htt_t2h_msg) 2690 { 2691 } 2692 #endif 2693 2694 #if defined(WDI_EVENT_ENABLE) && \ 2695 !defined(REMOVE_PKT_LOG) && defined(CONFIG_WIN) 2696 /* 2697 * dp_pktlog_msg_handler() - Pktlog msg handler 2698 * @htt_soc: HTT SOC handle 2699 * @msg_word: Pointer to payload 2700 * 2701 * Return: None 2702 */ 2703 static void 2704 dp_pktlog_msg_handler(struct htt_soc *soc, 2705 uint32_t *msg_word) 2706 { 2707 uint8_t pdev_id; 2708 uint32_t *pl_hdr; 2709 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, 2710 "received HTT_T2H_MSG_TYPE_PKTLOG\n"); 2711 pdev_id = HTT_T2H_PKTLOG_PDEV_ID_GET(*msg_word); 2712 pdev_id = DP_HW2SW_MACID(pdev_id); 2713 pl_hdr = (msg_word + 1); 2714 dp_wdi_event_handler(WDI_EVENT_OFFLOAD_ALL, soc->dp_soc, 2715 pl_hdr, HTT_INVALID_PEER, WDI_NO_VAL, 2716 pdev_id); 2717 } 2718 #else 2719 static void 2720 dp_pktlog_msg_handler(struct htt_soc *soc, 2721 uint32_t *msg_word) 2722 { 2723 } 2724 #endif 2725 2726 /* 2727 * dp_htt_t2h_msg_handler() - Generic Target to host Msg/event handler 2728 * @context: Opaque context (HTT SOC handle) 2729 * @pkt: HTC packet 2730 */ 2731 static void dp_htt_t2h_msg_handler(void *context, HTC_PACKET *pkt) 2732 { 2733 struct htt_soc *soc = (struct htt_soc *) context; 2734 qdf_nbuf_t htt_t2h_msg = (qdf_nbuf_t) pkt->pPktContext; 2735 u_int32_t *msg_word; 2736 enum htt_t2h_msg_type msg_type; 2737 bool free_buf = true; 2738 2739 /* check for successful message reception */ 2740 if (pkt->Status != QDF_STATUS_SUCCESS) { 2741 if (pkt->Status != QDF_STATUS_E_CANCELED) 2742 soc->stats.htc_err_cnt++; 2743 2744 qdf_nbuf_free(htt_t2h_msg); 2745 return; 2746 } 2747 2748 /* TODO: Check if we should pop the HTC/HTT header alignment padding */ 2749 2750 msg_word = (u_int32_t *) qdf_nbuf_data(htt_t2h_msg); 2751 msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word); 2752 switch (msg_type) { 2753 case HTT_T2H_MSG_TYPE_PEER_MAP: 2754 { 2755 u_int8_t mac_addr_deswizzle_buf[HTT_MAC_ADDR_LEN]; 2756 u_int8_t *peer_mac_addr; 2757 u_int16_t peer_id; 2758 u_int16_t hw_peer_id; 2759 u_int8_t vdev_id; 2760 2761 peer_id = HTT_RX_PEER_MAP_PEER_ID_GET(*msg_word); 2762 hw_peer_id = 2763 HTT_RX_PEER_MAP_HW_PEER_ID_GET(*(msg_word+2)); 2764 vdev_id = HTT_RX_PEER_MAP_VDEV_ID_GET(*msg_word); 2765 peer_mac_addr = htt_t2h_mac_addr_deswizzle( 2766 (u_int8_t *) (msg_word+1), 2767 &mac_addr_deswizzle_buf[0]); 2768 QDF_TRACE(QDF_MODULE_ID_TXRX, 2769 QDF_TRACE_LEVEL_INFO, 2770 "HTT_T2H_MSG_TYPE_PEER_MAP msg for peer id %d vdev id %d n", 2771 peer_id, vdev_id); 2772 2773 dp_rx_peer_map_handler(soc->dp_soc, peer_id, hw_peer_id, 2774 vdev_id, peer_mac_addr); 2775 break; 2776 } 2777 case HTT_T2H_MSG_TYPE_PEER_UNMAP: 2778 { 2779 u_int16_t peer_id; 2780 peer_id = HTT_RX_PEER_UNMAP_PEER_ID_GET(*msg_word); 2781 2782 dp_rx_peer_unmap_handler(soc->dp_soc, peer_id); 2783 break; 2784 } 2785 case HTT_T2H_MSG_TYPE_SEC_IND: 2786 { 2787 u_int16_t peer_id; 2788 enum htt_sec_type sec_type; 2789 int is_unicast; 2790 2791 peer_id = HTT_SEC_IND_PEER_ID_GET(*msg_word); 2792 sec_type = HTT_SEC_IND_SEC_TYPE_GET(*msg_word); 2793 is_unicast = HTT_SEC_IND_UNICAST_GET(*msg_word); 2794 /* point to the first part of the Michael key */ 2795 msg_word++; 2796 dp_rx_sec_ind_handler( 2797 soc->dp_soc, peer_id, sec_type, is_unicast, 2798 msg_word, msg_word + 2); 2799 break; 2800 } 2801 2802 case HTT_T2H_MSG_TYPE_PPDU_STATS_IND: 2803 { 2804 free_buf = dp_ppdu_stats_ind_handler(soc, msg_word, 2805 htt_t2h_msg); 2806 break; 2807 } 2808 2809 case HTT_T2H_MSG_TYPE_PKTLOG: 2810 { 2811 dp_pktlog_msg_handler(soc, msg_word); 2812 break; 2813 } 2814 2815 case HTT_T2H_MSG_TYPE_VERSION_CONF: 2816 { 2817 htc_pm_runtime_put(soc->htc_soc); 2818 soc->tgt_ver.major = HTT_VER_CONF_MAJOR_GET(*msg_word); 2819 soc->tgt_ver.minor = HTT_VER_CONF_MINOR_GET(*msg_word); 2820 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, 2821 "target uses HTT version %d.%d; host uses %d.%d\n", 2822 soc->tgt_ver.major, soc->tgt_ver.minor, 2823 HTT_CURRENT_VERSION_MAJOR, 2824 HTT_CURRENT_VERSION_MINOR); 2825 if (soc->tgt_ver.major != HTT_CURRENT_VERSION_MAJOR) { 2826 QDF_TRACE(QDF_MODULE_ID_TXRX, 2827 QDF_TRACE_LEVEL_ERROR, 2828 "*** Incompatible host/target HTT versions!\n"); 2829 } 2830 /* abort if the target is incompatible with the host */ 2831 qdf_assert(soc->tgt_ver.major == 2832 HTT_CURRENT_VERSION_MAJOR); 2833 if (soc->tgt_ver.minor != HTT_CURRENT_VERSION_MINOR) { 2834 QDF_TRACE(QDF_MODULE_ID_TXRX, 2835 QDF_TRACE_LEVEL_WARN, 2836 "*** Warning: host/target HTT versions" 2837 " are different, though compatible!\n"); 2838 } 2839 break; 2840 } 2841 case HTT_T2H_MSG_TYPE_RX_ADDBA: 2842 { 2843 uint16_t peer_id; 2844 uint8_t tid; 2845 uint8_t win_sz; 2846 uint16_t status; 2847 struct dp_peer *peer; 2848 2849 /* 2850 * Update REO Queue Desc with new values 2851 */ 2852 peer_id = HTT_RX_ADDBA_PEER_ID_GET(*msg_word); 2853 tid = HTT_RX_ADDBA_TID_GET(*msg_word); 2854 win_sz = HTT_RX_ADDBA_WIN_SIZE_GET(*msg_word); 2855 peer = dp_peer_find_by_id(soc->dp_soc, peer_id); 2856 2857 /* 2858 * Window size needs to be incremented by 1 2859 * since fw needs to represent a value of 256 2860 * using just 8 bits 2861 */ 2862 if (peer) { 2863 status = dp_addba_requestprocess_wifi3(peer, 2864 0, tid, 0, win_sz + 1, 0xffff); 2865 QDF_TRACE(QDF_MODULE_ID_TXRX, 2866 QDF_TRACE_LEVEL_INFO, 2867 FL("PeerID %d BAW %d TID %d stat %d\n"), 2868 peer_id, win_sz, tid, status); 2869 2870 } else { 2871 QDF_TRACE(QDF_MODULE_ID_TXRX, 2872 QDF_TRACE_LEVEL_ERROR, 2873 FL("Peer not found peer id %d\n"), 2874 peer_id); 2875 } 2876 break; 2877 } 2878 case HTT_T2H_MSG_TYPE_EXT_STATS_CONF: 2879 { 2880 dp_txrx_fw_stats_handler(soc->dp_soc, htt_t2h_msg); 2881 break; 2882 } 2883 default: 2884 break; 2885 }; 2886 2887 /* Free the indication buffer */ 2888 if (free_buf) 2889 qdf_nbuf_free(htt_t2h_msg); 2890 } 2891 2892 /* 2893 * dp_htt_h2t_full() - Send full handler (called from HTC) 2894 * @context: Opaque context (HTT SOC handle) 2895 * @pkt: HTC packet 2896 * 2897 * Return: enum htc_send_full_action 2898 */ 2899 static enum htc_send_full_action 2900 dp_htt_h2t_full(void *context, HTC_PACKET *pkt) 2901 { 2902 return HTC_SEND_FULL_KEEP; 2903 } 2904 2905 /* 2906 * dp_htt_hif_t2h_hp_callback() - HIF callback for high priority T2H messages 2907 * @context: Opaque context (HTT SOC handle) 2908 * @nbuf: nbuf containing T2H message 2909 * @pipe_id: HIF pipe ID 2910 * 2911 * Return: QDF_STATUS 2912 * 2913 * TODO: Temporary change to bypass HTC connection for this new HIF pipe, which 2914 * will be used for packet log and other high-priority HTT messsages. Proper 2915 * HTC connection to be added later once required FW changes are available 2916 */ 2917 static QDF_STATUS 2918 dp_htt_hif_t2h_hp_callback (void *context, qdf_nbuf_t nbuf, uint8_t pipe_id) 2919 { 2920 A_STATUS rc = QDF_STATUS_SUCCESS; 2921 HTC_PACKET htc_pkt; 2922 2923 qdf_assert_always(pipe_id == DP_HTT_T2H_HP_PIPE); 2924 qdf_mem_zero(&htc_pkt, sizeof(htc_pkt)); 2925 htc_pkt.Status = QDF_STATUS_SUCCESS; 2926 htc_pkt.pPktContext = (void *)nbuf; 2927 dp_htt_t2h_msg_handler(context, &htc_pkt); 2928 2929 return rc; 2930 } 2931 2932 /* 2933 * htt_htc_soc_attach() - Register SOC level HTT instance with HTC 2934 * @htt_soc: HTT SOC handle 2935 * 2936 * Return: 0 on success; error code on failure 2937 */ 2938 static int 2939 htt_htc_soc_attach(struct htt_soc *soc) 2940 { 2941 struct htc_service_connect_req connect; 2942 struct htc_service_connect_resp response; 2943 A_STATUS status; 2944 struct dp_soc *dpsoc = soc->dp_soc; 2945 2946 qdf_mem_set(&connect, sizeof(connect), 0); 2947 qdf_mem_set(&response, sizeof(response), 0); 2948 2949 connect.pMetaData = NULL; 2950 connect.MetaDataLength = 0; 2951 connect.EpCallbacks.pContext = soc; 2952 connect.EpCallbacks.EpTxComplete = dp_htt_h2t_send_complete; 2953 connect.EpCallbacks.EpTxCompleteMultiple = NULL; 2954 connect.EpCallbacks.EpRecv = dp_htt_t2h_msg_handler; 2955 2956 /* rx buffers currently are provided by HIF, not by EpRecvRefill */ 2957 connect.EpCallbacks.EpRecvRefill = NULL; 2958 2959 /* N/A, fill is done by HIF */ 2960 connect.EpCallbacks.RecvRefillWaterMark = 1; 2961 2962 connect.EpCallbacks.EpSendFull = dp_htt_h2t_full; 2963 /* 2964 * Specify how deep to let a queue get before htc_send_pkt will 2965 * call the EpSendFull function due to excessive send queue depth. 2966 */ 2967 connect.MaxSendQueueDepth = DP_HTT_MAX_SEND_QUEUE_DEPTH; 2968 2969 /* disable flow control for HTT data message service */ 2970 connect.ConnectionFlags |= HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; 2971 2972 /* connect to control service */ 2973 connect.service_id = HTT_DATA_MSG_SVC; 2974 2975 status = htc_connect_service(soc->htc_soc, &connect, &response); 2976 2977 if (status != A_OK) 2978 return QDF_STATUS_E_FAILURE; 2979 2980 soc->htc_endpoint = response.Endpoint; 2981 2982 hif_save_htc_htt_config_endpoint(dpsoc->hif_handle, soc->htc_endpoint); 2983 dp_hif_update_pipe_callback(soc->dp_soc, (void *)soc, 2984 dp_htt_hif_t2h_hp_callback, DP_HTT_T2H_HP_PIPE); 2985 2986 return 0; /* success */ 2987 } 2988 2989 /* 2990 * htt_soc_attach() - SOC level HTT initialization 2991 * @dp_soc: Opaque Data path SOC handle 2992 * @ctrl_psoc: Opaque ctrl SOC handle 2993 * @htc_soc: SOC level HTC handle 2994 * @hal_soc: Opaque HAL SOC handle 2995 * @osdev: QDF device 2996 * 2997 * Return: HTT handle on success; NULL on failure 2998 */ 2999 void * 3000 htt_soc_attach(void *dp_soc, void *ctrl_psoc, HTC_HANDLE htc_soc, 3001 void *hal_soc, qdf_device_t osdev) 3002 { 3003 struct htt_soc *soc; 3004 int i; 3005 3006 soc = qdf_mem_malloc(sizeof(*soc)); 3007 3008 if (!soc) 3009 goto fail1; 3010 3011 soc->osdev = osdev; 3012 soc->ctrl_psoc = ctrl_psoc; 3013 soc->dp_soc = dp_soc; 3014 soc->htc_soc = htc_soc; 3015 soc->hal_soc = hal_soc; 3016 3017 /* TODO: See if any NSS related context is requred in htt_soc */ 3018 3019 soc->htt_htc_pkt_freelist = NULL; 3020 3021 if (htt_htc_soc_attach(soc)) 3022 goto fail2; 3023 3024 /* TODO: See if any Rx data specific intialization is required. For 3025 * MCL use cases, the data will be received as single packet and 3026 * should not required any descriptor or reorder handling 3027 */ 3028 3029 HTT_TX_MUTEX_INIT(&soc->htt_tx_mutex); 3030 3031 /* pre-allocate some HTC_PACKET objects */ 3032 for (i = 0; i < HTT_HTC_PKT_POOL_INIT_SIZE; i++) { 3033 struct dp_htt_htc_pkt_union *pkt; 3034 pkt = qdf_mem_malloc(sizeof(*pkt)); 3035 if (!pkt) 3036 break; 3037 3038 htt_htc_pkt_free(soc, &pkt->u.pkt); 3039 } 3040 3041 return soc; 3042 3043 fail2: 3044 qdf_mem_free(soc); 3045 3046 fail1: 3047 return NULL; 3048 } 3049 3050 3051 /* 3052 * htt_soc_detach() - Detach SOC level HTT 3053 * @htt_soc: HTT SOC handle 3054 */ 3055 void 3056 htt_soc_detach(void *htt_soc) 3057 { 3058 struct htt_soc *soc = (struct htt_soc *)htt_soc; 3059 3060 htt_htc_misc_pkt_pool_free(soc); 3061 htt_htc_pkt_pool_free(soc); 3062 HTT_TX_MUTEX_DESTROY(&soc->htt_tx_mutex); 3063 qdf_mem_free(soc); 3064 } 3065 3066 /* 3067 * dp_get_pdev_mask_for_channel_id() - Retrieve pdev_id mask based on channel 3068 * information 3069 * @pdev - DP PDEV Handle 3070 * @channel - frequency 3071 * 3072 * Return - Pdev_id mask 3073 */ 3074 static inline 3075 uint8_t dp_get_pdev_mask_for_channel_id(struct dp_pdev *pdev, uint8_t channel) 3076 { 3077 uint8_t pdev_mask = 0; 3078 3079 if (!channel) 3080 return 1 << (pdev->pdev_id + 1); 3081 3082 else if (channel && WLAN_CHAN_IS_5GHZ(channel)) 3083 pdev_mask = 0; 3084 3085 else if (channel && WLAN_CHAN_IS_2GHZ(channel)) 3086 pdev_mask = 1; 3087 3088 return 1 << (pdev_mask + 1); 3089 } 3090 3091 /** 3092 * dp_h2t_ext_stats_msg_send(): function to contruct HTT message to pass to FW 3093 * @pdev: DP PDEV handle 3094 * @stats_type_upload_mask: stats type requested by user 3095 * @config_param_0: extra configuration parameters 3096 * @config_param_1: extra configuration parameters 3097 * @config_param_2: extra configuration parameters 3098 * @config_param_3: extra configuration parameters 3099 * 3100 * return: QDF STATUS 3101 */ 3102 QDF_STATUS dp_h2t_ext_stats_msg_send(struct dp_pdev *pdev, 3103 uint32_t stats_type_upload_mask, uint32_t config_param_0, 3104 uint32_t config_param_1, uint32_t config_param_2, 3105 uint32_t config_param_3, int cookie_val, int cookie_msb, 3106 uint8_t channel) 3107 { 3108 struct htt_soc *soc = pdev->soc->htt_handle; 3109 struct dp_htt_htc_pkt *pkt; 3110 qdf_nbuf_t msg; 3111 uint32_t *msg_word; 3112 uint8_t pdev_mask = 0; 3113 3114 msg = qdf_nbuf_alloc( 3115 soc->osdev, 3116 HTT_MSG_BUF_SIZE(HTT_H2T_EXT_STATS_REQ_MSG_SZ), 3117 HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, TRUE); 3118 3119 if (!msg) 3120 return QDF_STATUS_E_NOMEM; 3121 3122 /*TODO:Add support for SOC stats 3123 * Bit 0: SOC Stats 3124 * Bit 1: Pdev stats for pdev id 0 3125 * Bit 2: Pdev stats for pdev id 1 3126 * Bit 3: Pdev stats for pdev id 2 3127 */ 3128 pdev_mask = dp_get_pdev_mask_for_channel_id(pdev, channel); 3129 3130 /* 3131 * Set the length of the message. 3132 * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added 3133 * separately during the below call to qdf_nbuf_push_head. 3134 * The contribution from the HTC header is added separately inside HTC. 3135 */ 3136 if (qdf_nbuf_put_tail(msg, HTT_H2T_EXT_STATS_REQ_MSG_SZ) == NULL) { 3137 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 3138 "Failed to expand head for HTT_EXT_STATS"); 3139 qdf_nbuf_free(msg); 3140 return QDF_STATUS_E_FAILURE; 3141 } 3142 3143 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO, 3144 "-----%s:%d----\n cookie <-> %d\n config_param_0 %u\n" 3145 "config_param_1 %u\n config_param_2 %u\n" 3146 "config_param_4 %u\n -------------\n", 3147 __func__, __LINE__, cookie_val, config_param_0, 3148 config_param_1, config_param_2, config_param_3); 3149 3150 msg_word = (uint32_t *) qdf_nbuf_data(msg); 3151 3152 qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); 3153 *msg_word = 0; 3154 HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_EXT_STATS_REQ); 3155 HTT_H2T_EXT_STATS_REQ_PDEV_MASK_SET(*msg_word, pdev_mask); 3156 HTT_H2T_EXT_STATS_REQ_STATS_TYPE_SET(*msg_word, stats_type_upload_mask); 3157 3158 /* word 1 */ 3159 msg_word++; 3160 *msg_word = 0; 3161 HTT_H2T_EXT_STATS_REQ_CONFIG_PARAM_SET(*msg_word, config_param_0); 3162 3163 /* word 2 */ 3164 msg_word++; 3165 *msg_word = 0; 3166 HTT_H2T_EXT_STATS_REQ_CONFIG_PARAM_SET(*msg_word, config_param_1); 3167 3168 /* word 3 */ 3169 msg_word++; 3170 *msg_word = 0; 3171 HTT_H2T_EXT_STATS_REQ_CONFIG_PARAM_SET(*msg_word, config_param_2); 3172 3173 /* word 4 */ 3174 msg_word++; 3175 *msg_word = 0; 3176 HTT_H2T_EXT_STATS_REQ_CONFIG_PARAM_SET(*msg_word, config_param_3); 3177 3178 HTT_H2T_EXT_STATS_REQ_CONFIG_PARAM_SET(*msg_word, 0); 3179 3180 /* word 5 */ 3181 msg_word++; 3182 3183 /* word 6 */ 3184 msg_word++; 3185 *msg_word = 0; 3186 HTT_H2T_EXT_STATS_REQ_CONFIG_PARAM_SET(*msg_word, cookie_val); 3187 3188 /* word 7 */ 3189 msg_word++; 3190 *msg_word = 0; 3191 /*Using last 2 bits for pdev_id */ 3192 cookie_msb = ((cookie_msb << 2) | pdev->pdev_id); 3193 HTT_H2T_EXT_STATS_REQ_CONFIG_PARAM_SET(*msg_word, cookie_msb); 3194 3195 pkt = htt_htc_pkt_alloc(soc); 3196 if (!pkt) { 3197 qdf_nbuf_free(msg); 3198 return QDF_STATUS_E_NOMEM; 3199 } 3200 3201 pkt->soc_ctxt = NULL; /* not used during send-done callback */ 3202 3203 SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, 3204 dp_htt_h2t_send_complete_free_netbuf, 3205 qdf_nbuf_data(msg), qdf_nbuf_len(msg), 3206 soc->htc_endpoint, 3207 1); /* tag - not relevant here */ 3208 3209 SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); 3210 DP_HTT_SEND_HTC_PKT(soc, pkt); 3211 return 0; 3212 } 3213 3214 /* This macro will revert once proper HTT header will define for 3215 * HTT_H2T_MSG_TYPE_PPDU_STATS_CFG in htt.h file 3216 * */ 3217 #if defined(WDI_EVENT_ENABLE) 3218 /** 3219 * dp_h2t_cfg_stats_msg_send(): function to construct HTT message to pass to FW 3220 * @pdev: DP PDEV handle 3221 * @stats_type_upload_mask: stats type requested by user 3222 * @mac_id: Mac id number 3223 * 3224 * return: QDF STATUS 3225 */ 3226 QDF_STATUS dp_h2t_cfg_stats_msg_send(struct dp_pdev *pdev, 3227 uint32_t stats_type_upload_mask, uint8_t mac_id) 3228 { 3229 struct htt_soc *soc = pdev->soc->htt_handle; 3230 struct dp_htt_htc_pkt *pkt; 3231 qdf_nbuf_t msg; 3232 uint32_t *msg_word; 3233 uint8_t pdev_mask; 3234 3235 msg = qdf_nbuf_alloc( 3236 soc->osdev, 3237 HTT_MSG_BUF_SIZE(HTT_H2T_PPDU_STATS_CFG_MSG_SZ), 3238 HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, true); 3239 3240 if (!msg) { 3241 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, 3242 "Fail to allocate HTT_H2T_PPDU_STATS_CFG_MSG_SZ msg buffer\n"); 3243 qdf_assert(0); 3244 return QDF_STATUS_E_NOMEM; 3245 } 3246 3247 /*TODO:Add support for SOC stats 3248 * Bit 0: SOC Stats 3249 * Bit 1: Pdev stats for pdev id 0 3250 * Bit 2: Pdev stats for pdev id 1 3251 * Bit 3: Pdev stats for pdev id 2 3252 */ 3253 pdev_mask = 1 << DP_SW2HW_MACID(mac_id); 3254 3255 /* 3256 * Set the length of the message. 3257 * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added 3258 * separately during the below call to qdf_nbuf_push_head. 3259 * The contribution from the HTC header is added separately inside HTC. 3260 */ 3261 if (qdf_nbuf_put_tail(msg, HTT_H2T_PPDU_STATS_CFG_MSG_SZ) == NULL) { 3262 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, 3263 "Failed to expand head for HTT_CFG_STATS\n"); 3264 qdf_nbuf_free(msg); 3265 return QDF_STATUS_E_FAILURE; 3266 } 3267 3268 msg_word = (uint32_t *) qdf_nbuf_data(msg); 3269 3270 qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); 3271 *msg_word = 0; 3272 HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_PPDU_STATS_CFG); 3273 HTT_H2T_PPDU_STATS_CFG_PDEV_MASK_SET(*msg_word, pdev_mask); 3274 HTT_H2T_PPDU_STATS_CFG_TLV_BITMASK_SET(*msg_word, 3275 stats_type_upload_mask); 3276 3277 pkt = htt_htc_pkt_alloc(soc); 3278 if (!pkt) { 3279 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, 3280 "Fail to allocate dp_htt_htc_pkt buffer\n"); 3281 qdf_assert(0); 3282 qdf_nbuf_free(msg); 3283 return QDF_STATUS_E_NOMEM; 3284 } 3285 3286 pkt->soc_ctxt = NULL; /* not used during send-done callback */ 3287 3288 SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, 3289 dp_htt_h2t_send_complete_free_netbuf, 3290 qdf_nbuf_data(msg), qdf_nbuf_len(msg), 3291 soc->htc_endpoint, 3292 1); /* tag - not relevant here */ 3293 3294 SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); 3295 DP_HTT_SEND_HTC_PKT(soc, pkt); 3296 return 0; 3297 } 3298 #endif 3299