1 /* 2 * Copyright (c) 2011, 2014-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /** 21 * @file htt_tx.c 22 * @brief Implement transmit aspects of HTT. 23 * @details 24 * This file contains three categories of HTT tx code: 25 * 1. An abstraction of the tx descriptor, to hide the 26 * differences between the HL vs. LL tx descriptor. 27 * 2. Functions for allocating and freeing HTT tx descriptors. 28 * 3. The function that accepts a tx frame from txrx and sends the 29 * tx frame to HTC. 30 */ 31 #include <osdep.h> /* uint32_t, offsetof, etc. */ 32 #include <qdf_types.h> /* qdf_dma_addr_t */ 33 #include <qdf_mem.h> /* qdf_mem_alloc_consistent et al */ 34 #include <qdf_nbuf.h> /* qdf_nbuf_t, etc. */ 35 #include <qdf_time.h> /* qdf_mdelay */ 36 37 #include <htt.h> /* htt_tx_msdu_desc_t */ 38 #include <htc.h> /* HTC_HDR_LENGTH */ 39 #include <htc_api.h> /* htc_flush_surprise_remove */ 40 #include <ol_cfg.h> /* ol_cfg_netbuf_frags_max, etc. */ 41 #include <ol_htt_tx_api.h> /* HTT_TX_DESC_VADDR_OFFSET */ 42 #include <ol_txrx_htt_api.h> /* ol_tx_msdu_id_storage */ 43 #include <ol_txrx_internal.h> 44 #include <htt_internal.h> 45 46 #include <cds_utils.h> 47 #include <ce_api.h> 48 #include <ce_internal.h> 49 50 /* IPA Micro controller TX data packet HTT Header Preset 51 * 31 | 30 29 | 28 | 27 | 26 22 | 21 16 | 15 13 | 12 8 | 7 0 52 ***---------------------------------------------------------------------------- 53 * R | CS OL | R | PP | ext TID | vdev ID | pkt type | pkt subtyp | msg type 54 * 0 | 0 | 0 | | 0x1F | 0 | 2 | 0 | 0x01 55 ***---------------------------------------------------------------------------- 56 * pkt ID | pkt length 57 ***---------------------------------------------------------------------------- 58 * frag_desc_ptr 59 ***---------------------------------------------------------------------------- 60 * peer_id 61 ***---------------------------------------------------------------------------- 62 */ 63 #define HTT_IPA_UC_OFFLOAD_TX_HEADER_DEFAULT 0x07C04001 64 65 #ifdef QCA_WIFI_3_0 66 #define IPA_UC_TX_BUF_FRAG_DESC_OFFSET 20 67 #define IPA_UC_TX_BUF_FRAG_HDR_OFFSET 64 68 #define IPA_UC_TX_BUF_TSO_HDR_SIZE 6 69 #define IPA_UC_TX_BUF_PADDR_HI_MASK 0x0000001F 70 #else 71 #define IPA_UC_TX_BUF_FRAG_DESC_OFFSET 16 72 #define IPA_UC_TX_BUF_FRAG_HDR_OFFSET 32 73 #endif /* QCA_WIFI_3_0 */ 74 75 #if HTT_PADDR64 76 #define HTT_TX_DESC_FRAG_FIELD_UPDATE(frag_filed_ptr, frag_desc_addr) \ 77 do { \ 78 *frag_filed_ptr = qdf_get_lower_32_bits(frag_desc_addr); \ 79 frag_filed_ptr++; \ 80 /* frags_desc_ptr.hi */ \ 81 *frag_filed_ptr = qdf_get_upper_32_bits(frag_desc_addr) & 0x1F; \ 82 } while (0) 83 #else 84 #define HTT_TX_DESC_FRAG_FIELD_UPDATE(frag_filed_ptr, frag_desc_addr) \ 85 do { \ 86 *frag_filed_ptr = qdf_get_lower_32_bits(frag_desc_addr); \ 87 } while (0) 88 #endif 89 90 /*--- setup / tear-down functions -------------------------------------------*/ 91 92 static qdf_dma_addr_t htt_tx_get_paddr(htt_pdev_handle pdev, 93 char *target_vaddr); 94 95 #ifdef HELIUMPLUS 96 /** 97 * htt_tx_desc_get_size() - get tx descripotrs size 98 * @pdev: htt device instance pointer 99 * 100 * This function will get HTT TX descriptor size and fragment descriptor size 101 * 102 * Return: None 103 */ htt_tx_desc_get_size(struct htt_pdev_t * pdev)104 static void htt_tx_desc_get_size(struct htt_pdev_t *pdev) 105 { 106 pdev->tx_descs.size = sizeof(struct htt_host_tx_desc_t); 107 if (HTT_WIFI_IP_VERSION(pdev->wifi_ip_ver.major, 0x2)) { 108 /* 109 * sizeof MSDU_EXT/Fragmentation descriptor. 110 */ 111 pdev->frag_descs.size = sizeof(struct msdu_ext_desc_t); 112 } else { 113 /* 114 * Add the fragmentation descriptor elements. 115 * Add the most that the OS may deliver, plus one more 116 * in case the txrx code adds a prefix fragment (for 117 * TSO or audio interworking SNAP header) 118 */ 119 pdev->frag_descs.size = 120 (ol_cfg_netbuf_frags_max(pdev->ctrl_pdev)+1) * 8 121 + 4; 122 } 123 } 124 125 /** 126 * htt_tx_frag_desc_field_update() - Update fragment descriptor field 127 * @pdev: htt device instance pointer 128 * @fptr: Fragment descriptor field pointer 129 * @index: Descriptor index to find page and offset 130 * @desc_v_ptr: descriptor virtual pointot to find offset 131 * 132 * This function will update fragment descriptor field with actual fragment 133 * descriptor stating physical pointer 134 * 135 * Return: None 136 */ htt_tx_frag_desc_field_update(struct htt_pdev_t * pdev,uint32_t * fptr,unsigned int index,struct htt_tx_msdu_desc_t * desc_v_ptr)137 static void htt_tx_frag_desc_field_update(struct htt_pdev_t *pdev, 138 uint32_t *fptr, unsigned int index, 139 struct htt_tx_msdu_desc_t *desc_v_ptr) 140 { 141 unsigned int target_page; 142 unsigned int offset; 143 struct qdf_mem_dma_page_t *dma_page; 144 qdf_dma_addr_t frag_desc_addr; 145 146 target_page = index / pdev->frag_descs.desc_pages.num_element_per_page; 147 offset = index % pdev->frag_descs.desc_pages.num_element_per_page; 148 dma_page = &pdev->frag_descs.desc_pages.dma_pages[target_page]; 149 frag_desc_addr = (dma_page->page_p_addr + 150 offset * pdev->frag_descs.size); 151 HTT_TX_DESC_FRAG_FIELD_UPDATE(fptr, frag_desc_addr); 152 } 153 154 /** 155 * htt_tx_frag_desc_attach() - Attach fragment descriptor 156 * @pdev: htt device instance pointer 157 * @desc_pool_elems: Number of fragment descriptor 158 * 159 * This function will allocate fragment descriptor 160 * 161 * Return: 0 success 162 */ htt_tx_frag_desc_attach(struct htt_pdev_t * pdev,uint16_t desc_pool_elems)163 static int htt_tx_frag_desc_attach(struct htt_pdev_t *pdev, 164 uint16_t desc_pool_elems) 165 { 166 pdev->frag_descs.pool_elems = desc_pool_elems; 167 qdf_mem_multi_pages_alloc(pdev->osdev, &pdev->frag_descs.desc_pages, 168 pdev->frag_descs.size, desc_pool_elems, 169 qdf_get_dma_mem_context((&pdev->frag_descs), memctx), false); 170 if ((0 == pdev->frag_descs.desc_pages.num_pages) || 171 (!pdev->frag_descs.desc_pages.dma_pages)) { 172 ol_txrx_err("FRAG descriptor alloc fail"); 173 return -ENOBUFS; 174 } 175 return 0; 176 } 177 178 /** 179 * htt_tx_frag_desc_detach() - Detach fragment descriptor 180 * @pdev: htt device instance pointer 181 * 182 * This function will free fragment descriptor 183 * 184 * Return: None 185 */ htt_tx_frag_desc_detach(struct htt_pdev_t * pdev)186 static void htt_tx_frag_desc_detach(struct htt_pdev_t *pdev) 187 { 188 qdf_mem_multi_pages_free(pdev->osdev, &pdev->frag_descs.desc_pages, 189 qdf_get_dma_mem_context((&pdev->frag_descs), memctx), false); 190 } 191 192 /** 193 * htt_tx_frag_alloc() - Allocate single fragment descriptor from the pool 194 * @pdev: htt device instance pointer 195 * @index: Descriptor index 196 * @frag_paddr: Fragment descriptor physical address 197 * @frag_ptr: Fragment descriptor virtual address 198 * 199 * This function will free fragment descriptor 200 * 201 * Return: None 202 */ htt_tx_frag_alloc(htt_pdev_handle pdev,u_int16_t index,qdf_dma_addr_t * frag_paddr,void ** frag_ptr)203 int htt_tx_frag_alloc(htt_pdev_handle pdev, 204 u_int16_t index, qdf_dma_addr_t *frag_paddr, void **frag_ptr) 205 { 206 uint16_t frag_page_index; 207 uint16_t frag_elem_index; 208 struct qdf_mem_dma_page_t *dma_page; 209 210 /* 211 * Index should never be 0, since its used by the hardware 212 * to terminate the link. 213 */ 214 if (index >= pdev->tx_descs.pool_elems) { 215 *frag_ptr = NULL; 216 return 1; 217 } 218 219 frag_page_index = index / 220 pdev->frag_descs.desc_pages.num_element_per_page; 221 frag_elem_index = index % 222 pdev->frag_descs.desc_pages.num_element_per_page; 223 dma_page = &pdev->frag_descs.desc_pages.dma_pages[frag_page_index]; 224 225 *frag_ptr = dma_page->page_v_addr_start + 226 frag_elem_index * pdev->frag_descs.size; 227 if (((char *)(*frag_ptr) < dma_page->page_v_addr_start) || 228 ((char *)(*frag_ptr) > dma_page->page_v_addr_end)) { 229 *frag_ptr = NULL; 230 return 1; 231 } 232 233 *frag_paddr = dma_page->page_p_addr + 234 frag_elem_index * pdev->frag_descs.size; 235 return 0; 236 } 237 #else 238 239 /** 240 * htt_tx_desc_get_size() - get tx descripotrs size 241 * @pdev: htt device instance pointer 242 * 243 * This function will get HTT TX descriptor size and fragment descriptor size 244 * 245 * Return: None 246 */ htt_tx_desc_get_size(struct htt_pdev_t * pdev)247 static inline void htt_tx_desc_get_size(struct htt_pdev_t *pdev) 248 { 249 if (pdev->cfg.is_high_latency) { 250 pdev->tx_descs.size = sizeof(struct htt_host_tx_desc_t); 251 } else { 252 /* 253 * Start with the size of the base struct 254 * that actually gets downloaded. 255 * 256 * Add the fragmentation descriptor elements. 257 * Add the most that the OS may deliver, plus one more 258 * in case the txrx code adds a prefix fragment (for 259 * TSO or audio interworking SNAP header) 260 */ 261 pdev->tx_descs.size = 262 sizeof(struct htt_host_tx_desc_t) 263 + (ol_cfg_netbuf_frags_max(pdev->ctrl_pdev) + 1) * 8 264 /* 2x uint32_t */ 265 + 4; /* uint32_t fragmentation list terminator */ 266 } 267 } 268 269 #ifndef CONFIG_HL_SUPPORT 270 271 /** 272 * htt_tx_frag_desc_field_update() - Update fragment descriptor field 273 * @pdev: htt device instance pointer 274 * @fptr: Fragment descriptor field pointer 275 * @index: Descriptor index to find page and offset 276 * @desc_v_ptr: descriptor virtual pointot to find offset 277 * 278 * This function will update fragment descriptor field with actual fragment 279 * descriptor stating physical pointer 280 * 281 * Return: None 282 */ htt_tx_frag_desc_field_update(struct htt_pdev_t * pdev,uint32_t * fptr,unsigned int index,struct htt_tx_msdu_desc_t * desc_v_ptr)283 static void htt_tx_frag_desc_field_update(struct htt_pdev_t *pdev, 284 uint32_t *fptr, unsigned int index, 285 struct htt_tx_msdu_desc_t *desc_v_ptr) 286 { 287 *fptr = (uint32_t)htt_tx_get_paddr(pdev, (char *)desc_v_ptr) + 288 HTT_TX_DESC_LEN; 289 } 290 #endif 291 292 /** 293 * htt_tx_frag_desc_attach() - Attach fragment descriptor 294 * @pdev: htt device instance pointer 295 * @desc_pool_elems: Number of fragment descriptor 296 * 297 * This function will allocate fragment descriptor 298 * 299 * Return: 0 success 300 */ htt_tx_frag_desc_attach(struct htt_pdev_t * pdev,int desc_pool_elems)301 static inline int htt_tx_frag_desc_attach(struct htt_pdev_t *pdev, 302 int desc_pool_elems) 303 { 304 return 0; 305 } 306 307 /** 308 * htt_tx_frag_desc_detach() - Detach fragment descriptor 309 * @pdev: htt device instance pointer 310 * 311 * This function will free fragment descriptor 312 * 313 * Return: None 314 */ htt_tx_frag_desc_detach(struct htt_pdev_t * pdev)315 static void htt_tx_frag_desc_detach(struct htt_pdev_t *pdev) {} 316 #endif /* HELIUMPLUS */ 317 318 #ifdef CONFIG_HL_SUPPORT 319 320 /** 321 * htt_tx_attach() - Attach HTT device instance 322 * @pdev: htt device instance pointer 323 * @desc_pool_elems: Number of TX descriptors 324 * 325 * This function will allocate HTT TX resources 326 * 327 * Return: 0 Success 328 */ htt_tx_attach(struct htt_pdev_t * pdev,int desc_pool_elems)329 int htt_tx_attach(struct htt_pdev_t *pdev, int desc_pool_elems) 330 { 331 int i, i_int, pool_size; 332 uint32_t **p; 333 uint32_t num_link = 0; 334 uint16_t num_page, num_desc_per_page; 335 void **cacheable_pages = NULL; 336 337 htt_tx_desc_get_size(pdev); 338 339 /* 340 * Make sure tx_descs.size is a multiple of 4-bytes. 341 * It should be, but round up just to be sure. 342 */ 343 pdev->tx_descs.size = (pdev->tx_descs.size + 3) & (~0x3); 344 345 pdev->tx_descs.pool_elems = desc_pool_elems; 346 pdev->tx_descs.alloc_cnt = 0; 347 pool_size = pdev->tx_descs.pool_elems * pdev->tx_descs.size; 348 qdf_mem_multi_pages_alloc(pdev->osdev, &pdev->tx_descs.desc_pages, 349 pdev->tx_descs.size, 350 pdev->tx_descs.pool_elems, 351 qdf_get_dma_mem_context((&pdev->tx_descs), 352 memctx), true); 353 if ((0 == pdev->tx_descs.desc_pages.num_pages) || 354 (!pdev->tx_descs.desc_pages.cacheable_pages)) { 355 ol_txrx_err("HTT desc alloc fail"); 356 goto out_fail; 357 } 358 num_page = pdev->tx_descs.desc_pages.num_pages; 359 num_desc_per_page = pdev->tx_descs.desc_pages.num_element_per_page; 360 361 /* link tx descriptors into a freelist */ 362 cacheable_pages = pdev->tx_descs.desc_pages.cacheable_pages; 363 364 pdev->tx_descs.freelist = (uint32_t *)cacheable_pages[0]; 365 p = (uint32_t **)pdev->tx_descs.freelist; 366 for (i = 0; i < num_page; i++) { 367 for (i_int = 0; i_int < num_desc_per_page; i_int++) { 368 if (i_int == (num_desc_per_page - 1)) { 369 /* 370 * Last element on this page, 371 * should point next page 372 */ 373 if (!cacheable_pages[i + 1]) { 374 ol_txrx_err("over flow num link %d", 375 num_link); 376 goto free_htt_desc; 377 } 378 *p = (uint32_t *)cacheable_pages[i + 1]; 379 } else { 380 *p = (uint32_t *) 381 (((char *)p) + pdev->tx_descs.size); 382 } 383 num_link++; 384 p = (uint32_t **) *p; 385 /* Last link established exit */ 386 if (num_link == (pdev->tx_descs.pool_elems - 1)) 387 break; 388 } 389 } 390 *p = NULL; 391 392 if (htt_tx_frag_desc_attach(pdev, desc_pool_elems)) { 393 ol_txrx_err("HTT Frag descriptor alloc fail"); 394 goto free_htt_desc; 395 } 396 397 /* success */ 398 return 0; 399 400 free_htt_desc: 401 qdf_mem_multi_pages_free(pdev->osdev, &pdev->tx_descs.desc_pages, 402 qdf_get_dma_mem_context((&pdev->tx_descs), 403 memctx), true); 404 out_fail: 405 return -ENOBUFS; 406 } 407 htt_tx_detach(struct htt_pdev_t * pdev)408 void htt_tx_detach(struct htt_pdev_t *pdev) 409 { 410 if (!pdev) { 411 qdf_print("htt tx detach invalid instance"); 412 return; 413 } 414 415 htt_tx_frag_desc_detach(pdev); 416 qdf_mem_multi_pages_free(pdev->osdev, &pdev->tx_descs.desc_pages, 417 qdf_get_dma_mem_context((&pdev->tx_descs), 418 memctx), true); 419 } 420 421 /** 422 * htt_tx_set_frag_desc_addr() - set up the fragmentation descriptor address 423 * @pdev: pointer to the HTT instance making the allocation 424 * @htt_tx_desc: Host tx descriptor that does not include HTC hdr 425 * @index: index to alloc htt tx desc 426 * 427 * 428 * Return: None 429 */ 430 static inline void htt_tx_set_frag_desc_addr(struct htt_pdev_t * pdev,struct htt_tx_msdu_desc_t * htt_tx_desc,uint16_t index)431 htt_tx_set_frag_desc_addr(struct htt_pdev_t *pdev, 432 struct htt_tx_msdu_desc_t *htt_tx_desc, 433 uint16_t index) 434 { 435 } 436 437 /** 438 * htt_tx_desc_frags_table_set() - set up the descriptor and payload 439 * to correspondinf fragments 440 * @pdev: pointer to the HTT instance making the allocation 441 * @htt_tx_desc: Host tx descriptor that does not include HTC hdr 442 * @paddr: fragment physical address 443 * @frag_desc_paddr_lo: frag descriptor address 444 * @reset: reset 445 * 446 * Return: None 447 */ htt_tx_desc_frags_table_set(htt_pdev_handle pdev,void * desc,qdf_dma_addr_t paddr,qdf_dma_addr_t frag_desc_paddr,int reset)448 void htt_tx_desc_frags_table_set(htt_pdev_handle pdev, 449 void *desc, 450 qdf_dma_addr_t paddr, 451 qdf_dma_addr_t frag_desc_paddr, 452 int reset) 453 { 454 /* fragments table only applies to LL systems */ 455 } 456 457 /** 458 * htt_tx_credit_update() - get the number of credits by which the amount of 459 * target credits needs to be updated 460 * @pdev: htt context 461 * 462 * Return: number of credits 463 */ htt_tx_credit_update(struct htt_pdev_t * pdev)464 int htt_tx_credit_update(struct htt_pdev_t *pdev) 465 { 466 int credit_delta; 467 468 credit_delta = QDF_MIN(qdf_atomic_read( 469 &pdev->htt_tx_credit.target_delta), 470 qdf_atomic_read(&pdev->htt_tx_credit.bus_delta)); 471 if (credit_delta) { 472 qdf_atomic_add(-credit_delta, 473 &pdev->htt_tx_credit.target_delta); 474 qdf_atomic_add(-credit_delta, 475 &pdev->htt_tx_credit.bus_delta); 476 } 477 return credit_delta; 478 } 479 480 /** 481 * htt_tx_get_paddr() - get physical address for htt desc 482 * 483 * Get HTT descriptor physical address from virtual address 484 * Find page first and find offset 485 * Not required for HL systems 486 * 487 * Return: Physical address of descriptor 488 */ 489 static inline htt_tx_get_paddr(htt_pdev_handle pdev,char * target_vaddr)490 qdf_dma_addr_t htt_tx_get_paddr(htt_pdev_handle pdev, 491 char *target_vaddr) 492 { 493 return 0; 494 } 495 496 497 #else 498 htt_tx_attach(struct htt_pdev_t * pdev,int desc_pool_elems)499 int htt_tx_attach(struct htt_pdev_t *pdev, int desc_pool_elems) 500 { 501 int i, i_int, pool_size; 502 uint32_t **p; 503 struct qdf_mem_dma_page_t *page_info; 504 uint32_t num_link = 0; 505 uint16_t num_page, num_desc_per_page; 506 507 htt_tx_desc_get_size(pdev); 508 509 /* 510 * Make sure tx_descs.size is a multiple of 4-bytes. 511 * It should be, but round up just to be sure. 512 */ 513 pdev->tx_descs.size = (pdev->tx_descs.size + 3) & (~0x3); 514 515 pdev->tx_descs.pool_elems = desc_pool_elems; 516 pdev->tx_descs.alloc_cnt = 0; 517 pool_size = pdev->tx_descs.pool_elems * pdev->tx_descs.size; 518 qdf_mem_multi_pages_alloc(pdev->osdev, &pdev->tx_descs.desc_pages, 519 pdev->tx_descs.size, pdev->tx_descs.pool_elems, 520 qdf_get_dma_mem_context((&pdev->tx_descs), memctx), false); 521 if ((0 == pdev->tx_descs.desc_pages.num_pages) || 522 (!pdev->tx_descs.desc_pages.dma_pages)) { 523 ol_txrx_err("HTT desc alloc fail"); 524 goto out_fail; 525 } 526 num_page = pdev->tx_descs.desc_pages.num_pages; 527 num_desc_per_page = pdev->tx_descs.desc_pages.num_element_per_page; 528 529 /* link tx descriptors into a freelist */ 530 page_info = pdev->tx_descs.desc_pages.dma_pages; 531 pdev->tx_descs.freelist = (uint32_t *)page_info->page_v_addr_start; 532 p = (uint32_t **) pdev->tx_descs.freelist; 533 for (i = 0; i < num_page; i++) { 534 for (i_int = 0; i_int < num_desc_per_page; i_int++) { 535 if (i_int == (num_desc_per_page - 1)) { 536 /* 537 * Last element on this page, 538 * should pint next page 539 */ 540 if (!page_info->page_v_addr_start) { 541 ol_txrx_err("over flow num link %d", 542 num_link); 543 goto free_htt_desc; 544 } 545 page_info++; 546 *p = (uint32_t *)page_info->page_v_addr_start; 547 } else { 548 *p = (uint32_t *) 549 (((char *) p) + pdev->tx_descs.size); 550 } 551 num_link++; 552 p = (uint32_t **) *p; 553 /* Last link established exit */ 554 if (num_link == (pdev->tx_descs.pool_elems - 1)) 555 break; 556 } 557 } 558 *p = NULL; 559 560 if (htt_tx_frag_desc_attach(pdev, desc_pool_elems)) { 561 ol_txrx_err("HTT Frag descriptor alloc fail"); 562 goto free_htt_desc; 563 } 564 565 /* success */ 566 return 0; 567 568 free_htt_desc: 569 qdf_mem_multi_pages_free(pdev->osdev, &pdev->tx_descs.desc_pages, 570 qdf_get_dma_mem_context((&pdev->tx_descs), memctx), false); 571 out_fail: 572 return -ENOBUFS; 573 } 574 htt_tx_detach(struct htt_pdev_t * pdev)575 void htt_tx_detach(struct htt_pdev_t *pdev) 576 { 577 if (!pdev) { 578 qdf_print("htt tx detach invalid instance"); 579 return; 580 } 581 582 htt_tx_frag_desc_detach(pdev); 583 qdf_mem_multi_pages_free(pdev->osdev, &pdev->tx_descs.desc_pages, 584 qdf_get_dma_mem_context((&pdev->tx_descs), memctx), false); 585 } 586 587 static void htt_tx_set_frag_desc_addr(struct htt_pdev_t * pdev,struct htt_tx_msdu_desc_t * htt_tx_desc,uint16_t index)588 htt_tx_set_frag_desc_addr(struct htt_pdev_t *pdev, 589 struct htt_tx_msdu_desc_t *htt_tx_desc, 590 uint16_t index) 591 { 592 uint32_t *fragmentation_descr_field_ptr; 593 594 fragmentation_descr_field_ptr = (uint32_t *) 595 ((uint32_t *)htt_tx_desc) + 596 HTT_TX_DESC_FRAGS_DESC_PADDR_OFFSET_DWORD; 597 /* 598 * The fragmentation descriptor is allocated from consistent 599 * memory. Therefore, we can use the address directly rather 600 * than having to map it from a virtual/CPU address to a 601 * physical/bus address. 602 */ 603 htt_tx_frag_desc_field_update(pdev, fragmentation_descr_field_ptr, 604 index, htt_tx_desc); 605 606 return; 607 } 608 htt_tx_desc_frags_table_set(htt_pdev_handle pdev,void * htt_tx_desc,qdf_dma_addr_t paddr,qdf_dma_addr_t frag_desc_paddr,int reset)609 void htt_tx_desc_frags_table_set(htt_pdev_handle pdev, 610 void *htt_tx_desc, 611 qdf_dma_addr_t paddr, 612 qdf_dma_addr_t frag_desc_paddr, 613 int reset) 614 { 615 uint32_t *fragmentation_descr_field_ptr; 616 617 fragmentation_descr_field_ptr = (uint32_t *) 618 ((uint32_t *) htt_tx_desc) + 619 HTT_TX_DESC_FRAGS_DESC_PADDR_OFFSET_DWORD; 620 if (reset) { 621 #if defined(HELIUMPLUS) 622 *fragmentation_descr_field_ptr = frag_desc_paddr; 623 #else 624 *fragmentation_descr_field_ptr = 625 htt_tx_get_paddr(pdev, htt_tx_desc) + HTT_TX_DESC_LEN; 626 #endif 627 } else { 628 *fragmentation_descr_field_ptr = paddr; 629 } 630 } 631 htt_tx_pending_discard(htt_pdev_handle pdev)632 void htt_tx_pending_discard(htt_pdev_handle pdev) 633 { 634 htc_flush_surprise_remove(pdev->htc_pdev); 635 } 636 htt_tx_get_paddr(htt_pdev_handle pdev,char * target_vaddr)637 static qdf_dma_addr_t htt_tx_get_paddr(htt_pdev_handle pdev, 638 char *target_vaddr) 639 { 640 uint16_t i; 641 struct qdf_mem_dma_page_t *page_info = NULL; 642 uint64_t offset; 643 644 for (i = 0; i < pdev->tx_descs.desc_pages.num_pages; i++) { 645 page_info = pdev->tx_descs.desc_pages.dma_pages + i; 646 if (!page_info->page_v_addr_start) { 647 qdf_assert(0); 648 return 0; 649 } 650 if ((target_vaddr >= page_info->page_v_addr_start) && 651 (target_vaddr <= page_info->page_v_addr_end)) 652 break; 653 } 654 655 if (!page_info) { 656 ol_txrx_err("invalid page_info"); 657 return 0; 658 } 659 660 offset = (uint64_t)(target_vaddr - page_info->page_v_addr_start); 661 return page_info->page_p_addr + offset; 662 } 663 664 #endif 665 666 /*--- descriptor allocation functions ---------------------------------------*/ 667 htt_tx_desc_alloc(htt_pdev_handle pdev,qdf_dma_addr_t * paddr,uint16_t index)668 void *htt_tx_desc_alloc(htt_pdev_handle pdev, qdf_dma_addr_t *paddr, 669 uint16_t index) 670 { 671 struct htt_host_tx_desc_t *htt_host_tx_desc; /* includes HTC hdr */ 672 struct htt_tx_msdu_desc_t *htt_tx_desc; /* doesn't include HTC hdr */ 673 674 htt_host_tx_desc = (struct htt_host_tx_desc_t *)pdev->tx_descs.freelist; 675 if (!htt_host_tx_desc) 676 return NULL; /* pool is exhausted */ 677 678 htt_tx_desc = &htt_host_tx_desc->align32.tx_desc; 679 680 if (pdev->tx_descs.freelist) { 681 pdev->tx_descs.freelist = 682 *((uint32_t **) pdev->tx_descs.freelist); 683 pdev->tx_descs.alloc_cnt++; 684 } 685 /* 686 * For LL, set up the fragmentation descriptor address. 687 * Currently, this HTT tx desc allocation is performed once up front. 688 * If this is changed to have the allocation done during tx, then it 689 * would be helpful to have separate htt_tx_desc_alloc functions for 690 * HL vs. LL, to remove the below conditional branch. 691 */ 692 htt_tx_set_frag_desc_addr(pdev, htt_tx_desc, index); 693 694 /* 695 * Include the headroom for the HTC frame header when specifying the 696 * physical address for the HTT tx descriptor. 697 */ 698 *paddr = (qdf_dma_addr_t)htt_tx_get_paddr(pdev, 699 (char *)htt_host_tx_desc); 700 /* 701 * The allocated tx descriptor space includes headroom for a 702 * HTC frame header. Hide this headroom, so that we don't have 703 * to jump past the headroom each time we program a field within 704 * the tx desc, but only once when we download the tx desc (and 705 * the headroom) to the target via HTC. 706 * Skip past the headroom and return the address of the HTT tx desc. 707 */ 708 return (void *)htt_tx_desc; 709 } 710 htt_tx_desc_free(htt_pdev_handle pdev,void * tx_desc)711 void htt_tx_desc_free(htt_pdev_handle pdev, void *tx_desc) 712 { 713 char *htt_host_tx_desc = tx_desc; 714 /* rewind over the HTC frame header space */ 715 htt_host_tx_desc -= 716 offsetof(struct htt_host_tx_desc_t, align32.tx_desc); 717 *((uint32_t **) htt_host_tx_desc) = pdev->tx_descs.freelist; 718 pdev->tx_descs.freelist = (uint32_t *) htt_host_tx_desc; 719 pdev->tx_descs.alloc_cnt--; 720 } 721 722 /*--- descriptor field access methods ---------------------------------------*/ 723 724 /* PUT THESE AS inline IN ol_htt_tx_api.h */ 725 htt_tx_desc_flag_postponed(htt_pdev_handle pdev,void * desc)726 void htt_tx_desc_flag_postponed(htt_pdev_handle pdev, void *desc) 727 { 728 } 729 htt_tx_desc_flag_batch_more(htt_pdev_handle pdev,void * desc)730 void htt_tx_desc_flag_batch_more(htt_pdev_handle pdev, void *desc) 731 { 732 } 733 734 /*--- tx send function ------------------------------------------------------*/ 735 736 #ifdef ATH_11AC_TXCOMPACT 737 738 /* 739 * Scheduling the Queued packets in HTT which could not be sent out 740 * because of No CE desc 741 */ htt_tx_sched(htt_pdev_handle pdev)742 void htt_tx_sched(htt_pdev_handle pdev) 743 { 744 qdf_nbuf_t msdu; 745 int download_len = pdev->download_len; 746 int packet_len; 747 748 HTT_TX_NBUF_QUEUE_REMOVE(pdev, msdu); 749 while (msdu) { 750 int not_accepted; 751 /* packet length includes HTT tx desc frag added above */ 752 packet_len = qdf_nbuf_len(msdu); 753 if (packet_len < download_len) { 754 /* 755 * This case of packet length being less than the 756 * nominal download length can happen for a couple 757 * of reasons: 758 * In HL, the nominal download length is a large 759 * artificial value. 760 * In LL, the frame may not have the optional header 761 * fields accounted for in the nominal download size 762 * (LLC/SNAP header, IPv4 or IPv6 header). 763 */ 764 download_len = packet_len; 765 } 766 767 not_accepted = 768 htc_send_data_pkt(pdev->htc_pdev, msdu, 769 pdev->htc_tx_endpoint, 770 download_len); 771 if (not_accepted) { 772 HTT_TX_NBUF_QUEUE_INSERT_HEAD(pdev, msdu); 773 return; 774 } 775 HTT_TX_NBUF_QUEUE_REMOVE(pdev, msdu); 776 } 777 } 778 htt_tx_send_std(htt_pdev_handle pdev,qdf_nbuf_t msdu,uint16_t msdu_id)779 int htt_tx_send_std(htt_pdev_handle pdev, qdf_nbuf_t msdu, uint16_t msdu_id) 780 { 781 782 int download_len = pdev->download_len; 783 784 int packet_len; 785 786 /* packet length includes HTT tx desc frag added above */ 787 packet_len = qdf_nbuf_len(msdu); 788 if (packet_len < download_len) { 789 /* 790 * This case of packet length being less than the nominal 791 * download length can happen for a couple of reasons: 792 * In HL, the nominal download length is a large artificial 793 * value. 794 * In LL, the frame may not have the optional header fields 795 * accounted for in the nominal download size (LLC/SNAP header, 796 * IPv4 or IPv6 header). 797 */ 798 download_len = packet_len; 799 } 800 801 if (QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_EXT_HEADER(msdu)) 802 download_len += sizeof(struct htt_tx_msdu_desc_ext_t); 803 804 805 QDF_NBUF_UPDATE_TX_PKT_COUNT(msdu, QDF_NBUF_TX_PKT_HTT); 806 DPTRACE(qdf_dp_trace(msdu, QDF_DP_TRACE_HTT_PACKET_PTR_RECORD, 807 QDF_TRACE_DEFAULT_PDEV_ID, 808 qdf_nbuf_data_addr(msdu), 809 sizeof(qdf_nbuf_data(msdu)), QDF_TX)); 810 if (qdf_nbuf_queue_len(&pdev->txnbufq) > 0) { 811 HTT_TX_NBUF_QUEUE_ADD(pdev, msdu); 812 htt_tx_sched(pdev); 813 return 0; 814 } 815 816 if (htc_send_data_pkt(pdev->htc_pdev, msdu, 817 pdev->htc_tx_endpoint, download_len)) { 818 HTT_TX_NBUF_QUEUE_ADD(pdev, msdu); 819 } 820 821 return 0; /* success */ 822 823 } 824 825 #ifndef CONFIG_HL_SUPPORT 826 #ifdef FEATURE_RUNTIME_PM 827 /** 828 * htt_tx_resume_handler() - resume callback for the htt endpoint 829 * @context: a pointer to the htt context 830 * 831 * runs htt_tx_sched. 832 */ htt_tx_resume_handler(void * context)833 void htt_tx_resume_handler(void *context) 834 { 835 struct htt_pdev_t *pdev = (struct htt_pdev_t *) context; 836 837 htt_tx_sched(pdev); 838 } 839 #else 840 void htt_tx_resume_handler(void * context)841 htt_tx_resume_handler(void *context) { } 842 #endif 843 #endif 844 845 qdf_nbuf_t htt_tx_send_batch(htt_pdev_handle pdev,qdf_nbuf_t head_msdu,int num_msdus)846 htt_tx_send_batch(htt_pdev_handle pdev, qdf_nbuf_t head_msdu, int num_msdus) 847 { 848 qdf_print("Not apply to LL"); 849 qdf_assert(0); 850 return head_msdu; 851 852 } 853 854 int htt_tx_send_nonstd(htt_pdev_handle pdev,qdf_nbuf_t msdu,uint16_t msdu_id,enum htt_pkt_type pkt_type)855 htt_tx_send_nonstd(htt_pdev_handle pdev, 856 qdf_nbuf_t msdu, 857 uint16_t msdu_id, enum htt_pkt_type pkt_type) 858 { 859 int download_len; 860 861 /* 862 * The pkt_type could be checked to see what L2 header type is present, 863 * and then the L2 header could be examined to determine its length. 864 * But for simplicity, just use the maximum possible header size, 865 * rather than computing the actual header size. 866 */ 867 download_len = sizeof(struct htt_host_tx_desc_t) 868 + HTT_TX_HDR_SIZE_OUTER_HDR_MAX /* worst case */ 869 + HTT_TX_HDR_SIZE_802_1Q 870 + HTT_TX_HDR_SIZE_LLC_SNAP 871 + ol_cfg_tx_download_size(pdev->ctrl_pdev); 872 qdf_assert(download_len <= pdev->download_len); 873 return htt_tx_send_std(pdev, msdu, msdu_id); 874 } 875 876 #ifndef QCA_TX_PADDING_CREDIT_SUPPORT htt_tx_padding_credit_update_handler(void * context,int pad_credit)877 int htt_tx_padding_credit_update_handler(void *context, int pad_credit) 878 { 879 return 1; 880 } 881 #endif 882 883 #else /*ATH_11AC_TXCOMPACT */ 884 885 #ifdef QCA_TX_PADDING_CREDIT_SUPPORT htt_tx_padding_credit_update(htt_pdev_handle htt_pdev,int pad_credit)886 static int htt_tx_padding_credit_update(htt_pdev_handle htt_pdev, 887 int pad_credit) 888 { 889 int ret = 0; 890 891 if (pad_credit) 892 qdf_atomic_add(pad_credit, 893 &htt_pdev->txrx_pdev->pad_reserve_tx_credit); 894 895 ret = qdf_atomic_read(&htt_pdev->txrx_pdev->pad_reserve_tx_credit); 896 897 return ret; 898 } 899 htt_tx_padding_credit_update_handler(void * context,int pad_credit)900 int htt_tx_padding_credit_update_handler(void *context, int pad_credit) 901 { 902 struct htt_pdev_t *htt_pdev = (struct htt_pdev_t *)context; 903 904 return htt_tx_padding_credit_update(htt_pdev, pad_credit); 905 } 906 #else htt_tx_padding_credit_update_handler(void * context,int pad_credit)907 int htt_tx_padding_credit_update_handler(void *context, int pad_credit) 908 { 909 return 1; 910 } 911 #endif 912 913 #ifdef QCA_TX_HTT2_SUPPORT 914 static inline HTC_ENDPOINT_ID htt_tx_htt2_get_ep_id(htt_pdev_handle pdev,qdf_nbuf_t msdu)915 htt_tx_htt2_get_ep_id(htt_pdev_handle pdev, qdf_nbuf_t msdu) 916 { 917 /* 918 * TX HTT2 service mainly for small sized frame and check if 919 * this candidate frame allow or not. 920 */ 921 if ((pdev->htc_tx_htt2_endpoint != ENDPOINT_UNUSED) && 922 qdf_nbuf_get_tx_parallel_dnload_frm(msdu) && 923 (qdf_nbuf_len(msdu) < pdev->htc_tx_htt2_max_size)) 924 return pdev->htc_tx_htt2_endpoint; 925 else 926 return pdev->htc_tx_endpoint; 927 } 928 #else 929 #define htt_tx_htt2_get_ep_id(pdev, msdu) (pdev->htc_tx_endpoint) 930 #endif /* QCA_TX_HTT2_SUPPORT */ 931 932 static inline int htt_tx_send_base(htt_pdev_handle pdev,qdf_nbuf_t msdu,uint16_t msdu_id,int download_len,uint8_t more_data)933 htt_tx_send_base(htt_pdev_handle pdev, 934 qdf_nbuf_t msdu, 935 uint16_t msdu_id, int download_len, uint8_t more_data) 936 { 937 struct htt_host_tx_desc_t *htt_host_tx_desc; 938 struct htt_htc_pkt *pkt; 939 int packet_len; 940 HTC_ENDPOINT_ID ep_id; 941 942 /* 943 * The HTT tx descriptor was attached as the prefix fragment to the 944 * msdu netbuf during the call to htt_tx_desc_init. 945 * Retrieve it so we can provide its HTC header space to HTC. 946 */ 947 htt_host_tx_desc = (struct htt_host_tx_desc_t *) 948 qdf_nbuf_get_frag_vaddr(msdu, 0); 949 950 pkt = htt_htc_pkt_alloc(pdev); 951 if (!pkt) 952 return -ENOBUFS; /* failure */ 953 954 pkt->msdu_id = msdu_id; 955 pkt->pdev_ctxt = pdev->txrx_pdev; 956 957 /* packet length includes HTT tx desc frag added above */ 958 packet_len = qdf_nbuf_len(msdu); 959 if (packet_len < download_len) { 960 /* 961 * This case of packet length being less than the nominal 962 * download length can happen for a couple reasons: 963 * In HL, the nominal download length is a large artificial 964 * value. 965 * In LL, the frame may not have the optional header fields 966 * accounted for in the nominal download size (LLC/SNAP header, 967 * IPv4 or IPv6 header). 968 */ 969 download_len = packet_len; 970 } 971 972 ep_id = htt_tx_htt2_get_ep_id(pdev, msdu); 973 974 SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, 975 pdev->tx_send_complete_part2, 976 (unsigned char *)htt_host_tx_desc, 977 download_len - HTC_HDR_LENGTH, 978 ep_id, 979 1); /* tag - not relevant here */ 980 981 SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msdu); 982 983 QDF_NBUF_UPDATE_TX_PKT_COUNT(msdu, QDF_NBUF_TX_PKT_HTT); 984 DPTRACE(qdf_dp_trace(msdu, QDF_DP_TRACE_HTT_PACKET_PTR_RECORD, 985 QDF_TRACE_DEFAULT_PDEV_ID, 986 qdf_nbuf_data_addr(msdu), 987 sizeof(qdf_nbuf_data(msdu)), QDF_TX)); 988 htc_send_data_pkt(pdev->htc_pdev, &pkt->htc_pkt, more_data); 989 990 return 0; /* success */ 991 } 992 993 qdf_nbuf_t htt_tx_send_batch(htt_pdev_handle pdev,qdf_nbuf_t head_msdu,int num_msdus)994 htt_tx_send_batch(htt_pdev_handle pdev, qdf_nbuf_t head_msdu, int num_msdus) 995 { 996 qdf_nbuf_t rejected = NULL; 997 uint16_t *msdu_id_storage; 998 uint16_t msdu_id; 999 qdf_nbuf_t msdu; 1000 1001 /* 1002 * FOR NOW, iterate through the batch, sending the frames singly. 1003 * Eventually HTC and HIF should be able to accept a batch of 1004 * data frames rather than singles. 1005 */ 1006 msdu = head_msdu; 1007 while (num_msdus--) { 1008 qdf_nbuf_t next_msdu = qdf_nbuf_next(msdu); 1009 1010 msdu_id_storage = ol_tx_msdu_id_storage(msdu); 1011 msdu_id = *msdu_id_storage; 1012 1013 /* htt_tx_send_base returns 0 as success and 1 as failure */ 1014 if (htt_tx_send_base(pdev, msdu, msdu_id, pdev->download_len, 1015 num_msdus)) { 1016 qdf_nbuf_set_next(msdu, rejected); 1017 rejected = msdu; 1018 } 1019 msdu = next_msdu; 1020 } 1021 return rejected; 1022 } 1023 1024 int htt_tx_send_nonstd(htt_pdev_handle pdev,qdf_nbuf_t msdu,uint16_t msdu_id,enum htt_pkt_type pkt_type)1025 htt_tx_send_nonstd(htt_pdev_handle pdev, 1026 qdf_nbuf_t msdu, 1027 uint16_t msdu_id, enum htt_pkt_type pkt_type) 1028 { 1029 int download_len; 1030 1031 /* 1032 * The pkt_type could be checked to see what L2 header type is present, 1033 * and then the L2 header could be examined to determine its length. 1034 * But for simplicity, just use the maximum possible header size, 1035 * rather than computing the actual header size. 1036 */ 1037 download_len = sizeof(struct htt_host_tx_desc_t) 1038 + HTT_TX_HDR_SIZE_OUTER_HDR_MAX /* worst case */ 1039 + HTT_TX_HDR_SIZE_802_1Q 1040 + HTT_TX_HDR_SIZE_LLC_SNAP 1041 + ol_cfg_tx_download_size(pdev->ctrl_pdev); 1042 return htt_tx_send_base(pdev, msdu, msdu_id, download_len, 0); 1043 } 1044 htt_tx_send_std(htt_pdev_handle pdev,qdf_nbuf_t msdu,uint16_t msdu_id)1045 int htt_tx_send_std(htt_pdev_handle pdev, qdf_nbuf_t msdu, uint16_t msdu_id) 1046 { 1047 return htt_tx_send_base(pdev, msdu, msdu_id, pdev->download_len, 0); 1048 } 1049 1050 #endif /*ATH_11AC_TXCOMPACT */ 1051 1052 #if defined(HTT_DBG) htt_tx_desc_display(void * tx_desc)1053 void htt_tx_desc_display(void *tx_desc) 1054 { 1055 struct htt_tx_msdu_desc_t *htt_tx_desc; 1056 1057 htt_tx_desc = (struct htt_tx_msdu_desc_t *)tx_desc; 1058 1059 /* only works for little-endian */ 1060 qdf_debug("HTT tx desc (@ %pK):", htt_tx_desc); 1061 qdf_debug(" msg type = %d", htt_tx_desc->msg_type); 1062 qdf_debug(" pkt subtype = %d", htt_tx_desc->pkt_subtype); 1063 qdf_debug(" pkt type = %d", htt_tx_desc->pkt_type); 1064 qdf_debug(" vdev ID = %d", htt_tx_desc->vdev_id); 1065 qdf_debug(" ext TID = %d", htt_tx_desc->ext_tid); 1066 qdf_debug(" postponed = %d", htt_tx_desc->postponed); 1067 qdf_debug(" extension = %d", htt_tx_desc->extension); 1068 qdf_debug(" cksum_offload = %d", htt_tx_desc->cksum_offload); 1069 qdf_debug(" tx_compl_req= %d", htt_tx_desc->tx_compl_req); 1070 qdf_debug(" length = %d", htt_tx_desc->len); 1071 qdf_debug(" id = %d", htt_tx_desc->id); 1072 #if HTT_PADDR64 1073 qdf_debug(" frag desc addr.lo = %#x", 1074 htt_tx_desc->frags_desc_ptr.lo); 1075 qdf_debug(" frag desc addr.hi = %#x", 1076 htt_tx_desc->frags_desc_ptr.hi); 1077 #else /* ! HTT_PADDR64 */ 1078 qdf_debug(" frag desc addr = %#x", htt_tx_desc->frags_desc_ptr); 1079 #endif /* HTT_PADDR64 */ 1080 qdf_debug(" peerid = %d", htt_tx_desc->peerid); 1081 qdf_debug(" chanfreq = %d", htt_tx_desc->chanfreq); 1082 } 1083 #endif 1084 1085 #ifdef IPA_OFFLOAD 1086 #ifdef QCA_WIFI_3_0 1087 1088 #ifndef LIMIT_IPA_TX_BUFFER 1089 #define LIMIT_IPA_TX_BUFFER 2048 1090 #endif 1091 1092 /** 1093 * htt_tx_ipa_get_tx_buf_count() - Update WDI TX buffers count 1094 * @uc_tx_buf_cnt: TX Buffer count 1095 * 1096 * Return: new uc tx buffer count 1097 */ htt_tx_ipa_get_limit_tx_buf_count(unsigned int uc_tx_buf_cnt)1098 static int htt_tx_ipa_get_limit_tx_buf_count(unsigned int uc_tx_buf_cnt) 1099 { 1100 /* In order to improve the Genoa IPA DBS KPI, need to set 1101 * IpaUcTxBufCount=2048, so tx complete ring size=2048, and 1102 * total tx buffer count = 2047. 1103 * But in fact, wlan fw just only have 5G 1100 tx desc + 1104 * 2.4G 400 desc, it can cover about 1500 packets from 1105 * IPA side. 1106 * So the remaining 2047-1500 packet are not used, 1107 * in order to save some memory, so we can use 1108 * LIMIT_IPA_TX_BUFFER to limit the max tx buffer 1109 * count, which varied from platform. 1110 * And then the tx buffer count always equal to tx complete 1111 * ring size -1 is not mandatory now. 1112 * From the trying, it has the same KPI achievement while 1113 * set LIMIT_IPA_TX_BUFFER=1500 or 2048. 1114 */ 1115 if (uc_tx_buf_cnt > LIMIT_IPA_TX_BUFFER) 1116 return LIMIT_IPA_TX_BUFFER; 1117 else 1118 return uc_tx_buf_cnt; 1119 } 1120 1121 /** 1122 * htt_tx_ipa_uc_wdi_tx_buf_alloc() - Alloc WDI TX buffers 1123 * @pdev: htt context 1124 * @uc_tx_buf_sz: TX buffer size 1125 * @uc_tx_buf_cnt: TX Buffer count 1126 * @uc_tx_partition_base: IPA UC TX partition base value 1127 * 1128 * Allocate WDI TX buffers. Also note Rome supports only WDI 1.0. 1129 * 1130 * Return: 0 success 1131 */ 1132 htt_tx_ipa_uc_wdi_tx_buf_alloc(struct htt_pdev_t * pdev,unsigned int uc_tx_buf_sz,unsigned int uc_tx_buf_cnt,unsigned int uc_tx_partition_base)1133 static int htt_tx_ipa_uc_wdi_tx_buf_alloc(struct htt_pdev_t *pdev, 1134 unsigned int uc_tx_buf_sz, 1135 unsigned int uc_tx_buf_cnt, 1136 unsigned int uc_tx_partition_base) 1137 { 1138 unsigned int tx_buffer_count; 1139 qdf_dma_addr_t buffer_paddr; 1140 uint32_t *header_ptr; 1141 target_paddr_t *ring_vaddr; 1142 qdf_shared_mem_t *shared_tx_buffer; 1143 1144 ring_vaddr = (target_paddr_t *)pdev->ipa_uc_tx_rsc.tx_comp_ring->vaddr; 1145 1146 /* Allocate TX buffers as many as possible */ 1147 for (tx_buffer_count = 0; 1148 tx_buffer_count < (uc_tx_buf_cnt - 1); tx_buffer_count++) { 1149 1150 shared_tx_buffer = qdf_mem_shared_mem_alloc(pdev->osdev, 1151 uc_tx_buf_sz); 1152 if (!shared_tx_buffer || !shared_tx_buffer->vaddr) { 1153 qdf_print("IPA WDI TX buffer alloc fail %d allocated", 1154 tx_buffer_count); 1155 goto out; 1156 } 1157 1158 header_ptr = shared_tx_buffer->vaddr; 1159 buffer_paddr = qdf_mem_get_dma_addr(pdev->osdev, 1160 &shared_tx_buffer->mem_info); 1161 1162 /* HTT control header */ 1163 *header_ptr = HTT_IPA_UC_OFFLOAD_TX_HEADER_DEFAULT; 1164 header_ptr++; 1165 1166 /* PKT ID */ 1167 *header_ptr |= ((uint16_t) uc_tx_partition_base + 1168 tx_buffer_count) << 16; 1169 1170 header_ptr++; 1171 1172 /* Frag Desc Pointer */ 1173 /* 64bits descriptor, Low 32bits */ 1174 *header_ptr = qdf_get_lower_32_bits(buffer_paddr + 1175 IPA_UC_TX_BUF_FRAG_DESC_OFFSET); 1176 header_ptr++; 1177 1178 /* 64bits descriptor, high 32bits */ 1179 *header_ptr = qdf_get_upper_32_bits(buffer_paddr) & 1180 IPA_UC_TX_BUF_PADDR_HI_MASK; 1181 header_ptr++; 1182 1183 /* chanreq, peerid */ 1184 *header_ptr = 0xFFFFFFFF; 1185 header_ptr++; 1186 1187 /* FRAG Header */ 1188 /* 6 words TSO header */ 1189 header_ptr += IPA_UC_TX_BUF_TSO_HDR_SIZE; 1190 *header_ptr = buffer_paddr + IPA_UC_TX_BUF_FRAG_HDR_OFFSET; 1191 1192 *ring_vaddr = buffer_paddr; 1193 pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[tx_buffer_count] = 1194 shared_tx_buffer; 1195 1196 /* Memory barrier to ensure actual value updated */ 1197 1198 ring_vaddr++; 1199 } 1200 1201 out: 1202 1203 return tx_buffer_count; 1204 } 1205 1206 /** 1207 * htt_tx_buf_pool_free() - Free tx buffer pool 1208 * @pdev: htt context 1209 * 1210 * Free memory in tx buffer pool 1211 * 1212 * Return: 0 success 1213 */ htt_tx_buf_pool_free(struct htt_pdev_t * pdev)1214 static void htt_tx_buf_pool_free(struct htt_pdev_t *pdev) 1215 { 1216 uint16_t idx; 1217 1218 for (idx = 0; idx < pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt; idx++) { 1219 if (pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[idx]) { 1220 qdf_mem_shared_mem_free(pdev->osdev, 1221 pdev->ipa_uc_tx_rsc. 1222 tx_buf_pool_strg[idx]); 1223 pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[idx] = NULL; 1224 } 1225 } 1226 } 1227 #else htt_tx_ipa_get_limit_tx_buf_count(unsigned int uc_tx_buf_cnt)1228 static int htt_tx_ipa_get_limit_tx_buf_count(unsigned int uc_tx_buf_cnt) 1229 { 1230 return uc_tx_buf_cnt; 1231 } 1232 htt_tx_ipa_uc_wdi_tx_buf_alloc(struct htt_pdev_t * pdev,unsigned int uc_tx_buf_sz,unsigned int uc_tx_buf_cnt,unsigned int uc_tx_partition_base)1233 static int htt_tx_ipa_uc_wdi_tx_buf_alloc(struct htt_pdev_t *pdev, 1234 unsigned int uc_tx_buf_sz, 1235 unsigned int uc_tx_buf_cnt, 1236 unsigned int uc_tx_partition_base) 1237 { 1238 unsigned int tx_buffer_count; 1239 unsigned int tx_buffer_count_pwr2; 1240 qdf_dma_addr_t buffer_paddr; 1241 uint32_t *header_ptr; 1242 uint32_t *ring_vaddr; 1243 uint16_t idx; 1244 qdf_shared_mem_t *shared_tx_buffer; 1245 1246 ring_vaddr = pdev->ipa_uc_tx_rsc.tx_comp_ring->vaddr; 1247 1248 /* Allocate TX buffers as many as possible */ 1249 for (tx_buffer_count = 0; 1250 tx_buffer_count < (uc_tx_buf_cnt - 1); tx_buffer_count++) { 1251 shared_tx_buffer = qdf_mem_shared_mem_alloc(pdev->osdev, 1252 uc_tx_buf_sz); 1253 if (!shared_tx_buffer || !shared_tx_buffer->vaddr) { 1254 qdf_print("TX BUF alloc fail, loop index: %d", 1255 tx_buffer_count); 1256 goto pwr2; 1257 } 1258 1259 /* Init buffer */ 1260 qdf_mem_zero(shared_tx_buffer->vaddr, uc_tx_buf_sz); 1261 header_ptr = (uint32_t *)shared_tx_buffer->vaddr; 1262 buffer_paddr = qdf_mem_get_dma_addr(pdev->osdev, 1263 &shared_tx_buffer->mem_info); 1264 1265 /* HTT control header */ 1266 *header_ptr = HTT_IPA_UC_OFFLOAD_TX_HEADER_DEFAULT; 1267 header_ptr++; 1268 1269 /* PKT ID */ 1270 *header_ptr |= ((uint16_t) uc_tx_partition_base + 1271 tx_buffer_count) << 16; 1272 header_ptr++; 1273 1274 /*FRAG Desc Pointer */ 1275 *header_ptr = (uint32_t) (buffer_paddr + 1276 IPA_UC_TX_BUF_FRAG_DESC_OFFSET); 1277 header_ptr++; 1278 *header_ptr = 0xFFFFFFFF; 1279 1280 /* FRAG Header */ 1281 header_ptr++; 1282 *header_ptr = buffer_paddr + IPA_UC_TX_BUF_FRAG_HDR_OFFSET; 1283 1284 *ring_vaddr = buffer_paddr; 1285 pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[tx_buffer_count] = 1286 shared_tx_buffer; 1287 /* Memory barrier to ensure actual value updated */ 1288 1289 ring_vaddr++; 1290 } 1291 1292 pwr2: 1293 /* 1294 * Tx complete ring buffer count should be power of 2. 1295 * So, allocated Tx buffer count should be one less than ring buffer 1296 * size. 1297 */ 1298 tx_buffer_count_pwr2 = qdf_rounddown_pow_of_two(tx_buffer_count + 1) 1299 - 1; 1300 if (tx_buffer_count > tx_buffer_count_pwr2) { 1301 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO, 1302 "%s: Allocated Tx buffer count %d is rounded down to %d", 1303 __func__, tx_buffer_count, tx_buffer_count_pwr2); 1304 1305 /* Free over allocated buffers below power of 2 */ 1306 for (idx = tx_buffer_count_pwr2; idx < tx_buffer_count; idx++) { 1307 if (pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[idx]) { 1308 qdf_mem_shared_mem_free(pdev->osdev, 1309 pdev->ipa_uc_tx_rsc. 1310 tx_buf_pool_strg[idx]); 1311 pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[idx] = 1312 NULL; 1313 } 1314 } 1315 } 1316 1317 return tx_buffer_count_pwr2; 1318 } 1319 htt_tx_buf_pool_free(struct htt_pdev_t * pdev)1320 static void htt_tx_buf_pool_free(struct htt_pdev_t *pdev) 1321 { 1322 uint16_t idx; 1323 1324 for (idx = 0; idx < pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt; idx++) { 1325 if (pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[idx]) { 1326 qdf_mem_shared_mem_free(pdev->osdev, 1327 pdev->ipa_uc_tx_rsc. 1328 tx_buf_pool_strg[idx]); 1329 pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[idx] = NULL; 1330 } 1331 } 1332 } 1333 #endif 1334 1335 /** 1336 * htt_tx_ipa_uc_attach() - attach htt ipa uc tx resource 1337 * @pdev: htt context 1338 * @uc_tx_buf_sz: single tx buffer size 1339 * @uc_tx_buf_cnt: total tx buffer count 1340 * @uc_tx_partition_base: tx buffer partition start 1341 * 1342 * Return: 0 success 1343 * ENOBUFS No memory fail 1344 */ htt_tx_ipa_uc_attach(struct htt_pdev_t * pdev,unsigned int uc_tx_buf_sz,unsigned int uc_tx_buf_cnt,unsigned int uc_tx_partition_base)1345 int htt_tx_ipa_uc_attach(struct htt_pdev_t *pdev, 1346 unsigned int uc_tx_buf_sz, 1347 unsigned int uc_tx_buf_cnt, 1348 unsigned int uc_tx_partition_base) 1349 { 1350 int return_code = 0; 1351 unsigned int tx_comp_ring_size; 1352 1353 /* Allocate CE Write Index WORD */ 1354 pdev->ipa_uc_tx_rsc.tx_ce_idx = 1355 qdf_mem_shared_mem_alloc(pdev->osdev, 4); 1356 if (!pdev->ipa_uc_tx_rsc.tx_ce_idx) { 1357 qdf_print("Unable to allocate memory for IPA tx ce idx"); 1358 return -ENOBUFS; 1359 } 1360 1361 /* Allocate TX COMP Ring */ 1362 tx_comp_ring_size = qdf_get_pwr2(uc_tx_buf_cnt) 1363 * sizeof(target_paddr_t); 1364 pdev->ipa_uc_tx_rsc.tx_comp_ring = 1365 qdf_mem_shared_mem_alloc(pdev->osdev, 1366 tx_comp_ring_size); 1367 if (!pdev->ipa_uc_tx_rsc.tx_comp_ring || 1368 !pdev->ipa_uc_tx_rsc.tx_comp_ring->vaddr) { 1369 qdf_print("TX COMP ring alloc fail"); 1370 return_code = -ENOBUFS; 1371 goto free_tx_ce_idx; 1372 } 1373 1374 uc_tx_buf_cnt = htt_tx_ipa_get_limit_tx_buf_count(uc_tx_buf_cnt); 1375 /* Allocate TX BUF vAddress Storage */ 1376 pdev->ipa_uc_tx_rsc.tx_buf_pool_strg = 1377 qdf_mem_malloc(uc_tx_buf_cnt * 1378 sizeof(*pdev->ipa_uc_tx_rsc.tx_buf_pool_strg)); 1379 if (!pdev->ipa_uc_tx_rsc.tx_buf_pool_strg) { 1380 return_code = -ENOBUFS; 1381 goto free_tx_comp_base; 1382 } 1383 1384 qdf_mem_zero(pdev->ipa_uc_tx_rsc.tx_buf_pool_strg, 1385 uc_tx_buf_cnt * 1386 sizeof(*pdev->ipa_uc_tx_rsc.tx_buf_pool_strg)); 1387 1388 pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt = htt_tx_ipa_uc_wdi_tx_buf_alloc( 1389 pdev, uc_tx_buf_sz, uc_tx_buf_cnt, uc_tx_partition_base); 1390 1391 pdev->ipa_uc_tx_rsc.ipa_smmu_mapped = false; 1392 1393 1394 return 0; 1395 1396 free_tx_comp_base: 1397 qdf_mem_shared_mem_free(pdev->osdev, 1398 pdev->ipa_uc_tx_rsc.tx_comp_ring); 1399 free_tx_ce_idx: 1400 qdf_mem_shared_mem_free(pdev->osdev, 1401 pdev->ipa_uc_tx_rsc.tx_ce_idx); 1402 1403 return return_code; 1404 } 1405 1406 /** 1407 * htt_tx_ipa_uc_detach() - Free WDI TX resources 1408 * @pdev: htt context 1409 * 1410 * Remove IPA WDI TX resources during device detach 1411 * Free all of allocated resources 1412 * 1413 * Return: 0 success 1414 */ htt_tx_ipa_uc_detach(struct htt_pdev_t * pdev)1415 int htt_tx_ipa_uc_detach(struct htt_pdev_t *pdev) 1416 { 1417 qdf_mem_shared_mem_free(pdev->osdev, 1418 pdev->ipa_uc_tx_rsc.tx_ce_idx); 1419 qdf_mem_shared_mem_free(pdev->osdev, 1420 pdev->ipa_uc_tx_rsc.tx_comp_ring); 1421 1422 /* Free each single buffer */ 1423 htt_tx_buf_pool_free(pdev); 1424 1425 /* Free storage */ 1426 qdf_mem_free(pdev->ipa_uc_tx_rsc.tx_buf_pool_strg); 1427 1428 return 0; 1429 } 1430 #endif /* IPA_OFFLOAD */ 1431 1432 #if defined(FEATURE_TSO) && defined(HELIUMPLUS) 1433 void htt_tx_desc_fill_tso_info(htt_pdev_handle pdev,void * desc,struct qdf_tso_info_t * tso_info)1434 htt_tx_desc_fill_tso_info(htt_pdev_handle pdev, void *desc, 1435 struct qdf_tso_info_t *tso_info) 1436 { 1437 u_int32_t *word; 1438 int i; 1439 struct qdf_tso_seg_elem_t *tso_seg = tso_info->curr_seg; 1440 struct msdu_ext_desc_t *msdu_ext_desc = (struct msdu_ext_desc_t *)desc; 1441 1442 word = (u_int32_t *)(desc); 1443 1444 /* Initialize the TSO flags per MSDU */ 1445 msdu_ext_desc->tso_flags = 1446 tso_seg->seg.tso_flags; 1447 1448 /* First 24 bytes (6*4) contain the TSO flags */ 1449 TSO_DEBUG("%s seq# %u l2 len %d, ip len %d", 1450 __func__, 1451 tso_seg->seg.tso_flags.tcp_seq_num, 1452 tso_seg->seg.tso_flags.l2_len, 1453 tso_seg->seg.tso_flags.ip_len); 1454 TSO_DEBUG("%s flags 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", 1455 __func__, 1456 *word, 1457 *(word + 1), 1458 *(word + 2), 1459 *(word + 3), 1460 *(word + 4), 1461 *(word + 5)); 1462 1463 word += 6; 1464 1465 for (i = 0; i < tso_seg->seg.num_frags; i++) { 1466 uint32_t lo = 0; 1467 uint32_t hi = 0; 1468 1469 qdf_dmaaddr_to_32s(tso_seg->seg.tso_frags[i].paddr, 1470 &lo, &hi); 1471 /* [31:0] first 32 bits of the buffer pointer */ 1472 *word = lo; 1473 word++; 1474 /* [15:0] the upper 16 bits of the first buffer pointer */ 1475 /* [31:16] length of the first buffer */ 1476 *word = (tso_seg->seg.tso_frags[i].length << 16) | hi; 1477 word++; 1478 TSO_DEBUG("%s frag[%d] ptr_low 0x%x ptr_hi 0x%x len %u", 1479 __func__, i, 1480 msdu_ext_desc->frags[i].u.frag32.ptr_low, 1481 msdu_ext_desc->frags[i].u.frag32.ptr_hi, 1482 msdu_ext_desc->frags[i].u.frag32.len); 1483 } 1484 1485 if (tso_seg->seg.num_frags < FRAG_NUM_MAX) 1486 *word = 0; 1487 qdf_tso_seg_dbg_record(tso_seg, TSOSEG_LOC_FILLHTTSEG); 1488 } 1489 #endif /* FEATURE_TSO */ 1490 1491 /** 1492 * htt_get_ext_tid() - get ext_tid value 1493 * @type: extension header type 1494 * @ext_header_data: header data 1495 * @msdu_info: msdu info 1496 * 1497 * Return: ext_tid value 1498 */ 1499 static inline htt_get_ext_tid(enum extension_header_type type,void * ext_header_data,struct htt_msdu_info_t * msdu_info)1500 int htt_get_ext_tid(enum extension_header_type type, 1501 void *ext_header_data, struct htt_msdu_info_t *msdu_info) 1502 { 1503 if (type == OCB_MODE_EXT_HEADER && ext_header_data) 1504 return ((struct ocb_tx_ctrl_hdr_t *)ext_header_data)->ext_tid; 1505 else 1506 return msdu_info->info.ext_tid; 1507 } 1508 1509 /** 1510 * htt_get_channel_freq() - get channel frequency 1511 * @type: extension header type 1512 * @ext_header_data: header data 1513 * 1514 * Return: channel frequency number 1515 */ 1516 static inline htt_get_channel_freq(enum extension_header_type type,void * ext_header_data)1517 int htt_get_channel_freq(enum extension_header_type type, 1518 void *ext_header_data) 1519 { 1520 if (type == OCB_MODE_EXT_HEADER && ext_header_data) 1521 return ((struct ocb_tx_ctrl_hdr_t *)ext_header_data) 1522 ->channel_freq; 1523 else 1524 return HTT_INVALID_CHANNEL; 1525 } 1526 1527 /** 1528 * htt_fill_ocb_ext_header() - fill OCB extension header 1529 * @msdu: network buffer 1530 * @local_desc_ext: extension descriptor 1531 * @type: extension header type 1532 * @ext_header_data: header data 1533 * @is_dsrc: is dsrc is eenabled or not 1534 * 1535 * Return: none 1536 */ 1537 #ifdef WLAN_FEATURE_DSRC 1538 static htt_fill_ocb_ext_header(qdf_nbuf_t msdu,struct htt_tx_msdu_desc_ext_t * local_desc_ext,enum extension_header_type type,void * ext_header_data)1539 void htt_fill_ocb_ext_header(qdf_nbuf_t msdu, 1540 struct htt_tx_msdu_desc_ext_t *local_desc_ext, 1541 enum extension_header_type type, 1542 void *ext_header_data) 1543 { 1544 struct ocb_tx_ctrl_hdr_t *tx_ctrl = 1545 (struct ocb_tx_ctrl_hdr_t *)ext_header_data; 1546 1547 if (tx_ctrl->all_flags == 0) 1548 return; 1549 /* 1550 * Copy the info that was read from TX control header from the 1551 * user application to the extended HTT header. 1552 * First copy everything 1553 * to a local temp structure, and then copy everything to the 1554 * actual uncached structure in one go to save memory writes. 1555 */ 1556 local_desc_ext->valid_pwr = tx_ctrl->valid_pwr; 1557 local_desc_ext->valid_mcs_mask = tx_ctrl->valid_datarate; 1558 local_desc_ext->valid_retries = tx_ctrl->valid_retries; 1559 local_desc_ext->valid_expire_tsf = tx_ctrl->valid_expire_tsf; 1560 local_desc_ext->valid_chainmask = tx_ctrl->valid_chain_mask; 1561 1562 local_desc_ext->pwr = tx_ctrl->pwr; 1563 if (tx_ctrl->valid_datarate && 1564 tx_ctrl->datarate <= htt_ofdm_datarate_max) 1565 local_desc_ext->mcs_mask = 1566 (1 << (tx_ctrl->datarate + 4)); 1567 local_desc_ext->retry_limit = tx_ctrl->retry_limit; 1568 local_desc_ext->expire_tsf_lo = tx_ctrl->expire_tsf_lo; 1569 local_desc_ext->expire_tsf_hi = tx_ctrl->expire_tsf_hi; 1570 local_desc_ext->chain_mask = tx_ctrl->chain_mask; 1571 local_desc_ext->is_dsrc = 1; 1572 qdf_nbuf_push_head(msdu, sizeof(struct htt_tx_msdu_desc_ext_t)); 1573 qdf_mem_copy(qdf_nbuf_data(msdu), local_desc_ext, 1574 sizeof(struct htt_tx_msdu_desc_ext_t)); 1575 QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_EXT_HEADER(msdu) = 1; 1576 } 1577 #else 1578 static htt_fill_ocb_ext_header(qdf_nbuf_t msdu,struct htt_tx_msdu_desc_ext_t * local_desc_ext,enum extension_header_type type,void * ext_header_data)1579 void htt_fill_ocb_ext_header(qdf_nbuf_t msdu, 1580 struct htt_tx_msdu_desc_ext_t *local_desc_ext, 1581 enum extension_header_type type, 1582 void *ext_header_data) 1583 { 1584 } 1585 #endif 1586 1587 /** 1588 * htt_fill_wisa_ext_header() - fill WiSA extension header 1589 * @msdu: network buffer 1590 * @local_desc_ext: extension descriptor 1591 * @type: extension header type 1592 * @ext_header_data: header data 1593 * 1594 * Return: none 1595 */ 1596 static htt_fill_wisa_ext_header(qdf_nbuf_t msdu,struct htt_tx_msdu_desc_ext_t * local_desc_ext,enum extension_header_type type,void * ext_header_data)1597 void htt_fill_wisa_ext_header(qdf_nbuf_t msdu, 1598 struct htt_tx_msdu_desc_ext_t *local_desc_ext, 1599 enum extension_header_type type, void *ext_header_data) 1600 { 1601 void *qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); 1602 QDF_STATUS status; 1603 1604 if (!qdf_ctx) 1605 return; 1606 1607 local_desc_ext->valid_mcs_mask = 1; 1608 if (WISA_MODE_EXT_HEADER_6MBPS == type) 1609 local_desc_ext->mcs_mask = htt_ofdm_datarate_6_mbps; 1610 else 1611 local_desc_ext->mcs_mask = htt_ofdm_datarate_24_mbps; 1612 local_desc_ext->valid_nss_mask = 1; 1613 local_desc_ext->nss_mask = 1; 1614 local_desc_ext->valid_bandwidth = 1; 1615 local_desc_ext->bandwidth_mask = htt_tx_bandwidth_20MHz; 1616 local_desc_ext->valid_guard_interval = 1; 1617 local_desc_ext->guard_interval = htt_tx_guard_interval_regular; 1618 1619 /* 1620 * Do dma_unmap and dma_map again if already mapped 1621 * as adding extra bytes in skb 1622 */ 1623 if (QDF_NBUF_CB_PADDR(msdu) != 0) 1624 qdf_nbuf_unmap_single(qdf_ctx, msdu, QDF_DMA_TO_DEVICE); 1625 1626 qdf_nbuf_push_head(msdu, sizeof(struct htt_tx_msdu_desc_ext_t)); 1627 qdf_mem_copy(qdf_nbuf_data(msdu), local_desc_ext, 1628 sizeof(struct htt_tx_msdu_desc_ext_t)); 1629 1630 if (QDF_NBUF_CB_PADDR(msdu) != 0) { 1631 status = qdf_nbuf_map_single(qdf_ctx, msdu, QDF_DMA_TO_DEVICE); 1632 if (qdf_unlikely(status != QDF_STATUS_SUCCESS)) { 1633 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_WARN, 1634 "%s: nbuf map failed", __func__); 1635 return; 1636 } 1637 } 1638 QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_EXT_HEADER(msdu) = 1; 1639 } 1640 1641 /** 1642 * htt_push_ext_header() - fill extension header 1643 * @msdu: network buffer 1644 * @local_desc_ext: extension descriptor 1645 * @type: extension header type 1646 * @ext_header_data: header data 1647 * @is_dsrc: is dsrc is eenabled or not 1648 * 1649 * Return: none 1650 */ 1651 static htt_push_ext_header(qdf_nbuf_t msdu,struct htt_tx_msdu_desc_ext_t * local_desc_ext,enum extension_header_type type,void * ext_header_data)1652 void htt_push_ext_header(qdf_nbuf_t msdu, 1653 struct htt_tx_msdu_desc_ext_t *local_desc_ext, 1654 enum extension_header_type type, void *ext_header_data) 1655 { 1656 switch (type) { 1657 case OCB_MODE_EXT_HEADER: 1658 htt_fill_ocb_ext_header(msdu, local_desc_ext, 1659 type, ext_header_data); 1660 break; 1661 case WISA_MODE_EXT_HEADER_6MBPS: 1662 case WISA_MODE_EXT_HEADER_24MBPS: 1663 htt_fill_wisa_ext_header(msdu, local_desc_ext, 1664 type, ext_header_data); 1665 break; 1666 default: 1667 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO, 1668 "Invalid EXT header type %d\n", type); 1669 break; 1670 } 1671 } 1672 1673 QDF_STATUS htt_tx_desc_init(htt_pdev_handle pdev,void * htt_tx_desc,qdf_dma_addr_t htt_tx_desc_paddr,uint16_t msdu_id,qdf_nbuf_t msdu,struct htt_msdu_info_t * msdu_info,struct qdf_tso_info_t * tso_info,void * ext_header_data,enum extension_header_type type)1674 htt_tx_desc_init(htt_pdev_handle pdev, 1675 void *htt_tx_desc, 1676 qdf_dma_addr_t htt_tx_desc_paddr, 1677 uint16_t msdu_id, 1678 qdf_nbuf_t msdu, struct htt_msdu_info_t *msdu_info, 1679 struct qdf_tso_info_t *tso_info, 1680 void *ext_header_data, 1681 enum extension_header_type type) 1682 { 1683 uint8_t pkt_type, pkt_subtype = 0, ce_pkt_type = 0; 1684 uint32_t hw_classify = 0, data_attr = 0; 1685 uint32_t *word0, *word1, local_word3; 1686 #if HTT_PADDR64 1687 uint32_t *word4; 1688 #else /* ! HTT_PADDR64 */ 1689 uint32_t *word3; 1690 #endif /* HTT_PADDR64 */ 1691 uint32_t local_word0, local_word1; 1692 struct htt_host_tx_desc_t *htt_host_tx_desc = 1693 (struct htt_host_tx_desc_t *) 1694 (((char *)htt_tx_desc) - HTT_TX_DESC_VADDR_OFFSET); 1695 bool desc_ext_required = (type != EXT_HEADER_NOT_PRESENT); 1696 int channel_freq; 1697 void *qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); 1698 qdf_dma_dir_t dir; 1699 QDF_STATUS status; 1700 1701 if (qdf_unlikely(!qdf_ctx)) 1702 return QDF_STATUS_E_FAILURE; 1703 1704 if (qdf_unlikely(!msdu_info)) { 1705 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 1706 "%s: bad arg: msdu_info is NULL", __func__); 1707 return QDF_STATUS_E_FAILURE; 1708 } 1709 if (qdf_unlikely(!tso_info)) { 1710 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 1711 "%s: bad arg: tso_info is NULL", __func__); 1712 return QDF_STATUS_E_FAILURE; 1713 } 1714 1715 word0 = (uint32_t *) htt_tx_desc; 1716 word1 = word0 + 1; 1717 /* 1718 * word2 is frag desc pointer 1719 * word3 or 4 is peer_id 1720 */ 1721 #if HTT_PADDR64 1722 word4 = word0 + 4; /* Dword 3 */ 1723 #else /* ! HTT_PADDR64 */ 1724 word3 = word0 + 3; /* Dword 3 */ 1725 #endif /* HTT_PADDR64 */ 1726 1727 pkt_type = msdu_info->info.l2_hdr_type; 1728 1729 if (qdf_likely(pdev->cfg.ce_classify_enabled)) { 1730 if (qdf_likely(pkt_type == htt_pkt_type_eth2 || 1731 pkt_type == htt_pkt_type_ethernet)) 1732 qdf_nbuf_tx_info_get(msdu, pkt_type, pkt_subtype, 1733 hw_classify); 1734 1735 ce_pkt_type = htt_to_ce_pkt_type[pkt_type]; 1736 if (0xffffffff == ce_pkt_type) { 1737 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, 1738 "Invalid HTT pkt type %d\n", pkt_type); 1739 return QDF_STATUS_E_INVAL; 1740 } 1741 } 1742 1743 /* 1744 * HTT Tx Desc is in uncached memory. Used cached writes per word, to 1745 * reduce unnecessary memory access. 1746 */ 1747 1748 local_word0 = 0; 1749 1750 HTT_H2T_MSG_TYPE_SET(local_word0, HTT_H2T_MSG_TYPE_TX_FRM); 1751 HTT_TX_DESC_PKT_TYPE_SET(local_word0, pkt_type); 1752 HTT_TX_DESC_PKT_SUBTYPE_SET(local_word0, pkt_subtype); 1753 HTT_TX_DESC_VDEV_ID_SET(local_word0, msdu_info->info.vdev_id); 1754 HTT_TX_DESC_EXT_TID_SET(local_word0, htt_get_ext_tid(type, 1755 ext_header_data, msdu_info)); 1756 HTT_TX_DESC_EXTENSION_SET(local_word0, desc_ext_required); 1757 HTT_TX_DESC_EXT_TID_SET(local_word0, msdu_info->info.ext_tid); 1758 HTT_TX_DESC_CKSUM_OFFLOAD_SET(local_word0, 1759 msdu_info->action.cksum_offload); 1760 if (pdev->cfg.is_high_latency) 1761 HTT_TX_DESC_TX_COMP_SET(local_word0, msdu_info->action. 1762 tx_comp_req); 1763 HTT_TX_DESC_NO_ENCRYPT_SET(local_word0, 1764 msdu_info->action.do_encrypt ? 1765 0 : 1); 1766 1767 *word0 = local_word0; 1768 1769 local_word1 = 0; 1770 1771 if (tso_info->is_tso) { 1772 uint32_t total_len = tso_info->curr_seg->seg.total_len; 1773 1774 HTT_TX_DESC_FRM_LEN_SET(local_word1, total_len); 1775 TSO_DEBUG("%s setting HTT TX DESC Len = %d", 1776 __func__, total_len); 1777 } else { 1778 HTT_TX_DESC_FRM_LEN_SET(local_word1, qdf_nbuf_len(msdu)); 1779 } 1780 1781 QDF_BUG(HTT_TX_DESC_FRM_LEN_GET(local_word1) != 0); 1782 1783 HTT_TX_DESC_FRM_ID_SET(local_word1, msdu_id); 1784 *word1 = local_word1; 1785 1786 /* 1787 * Initialize peer_id to INVALID_PEER because 1788 * this is NOT Reinjection path 1789 */ 1790 local_word3 = HTT_INVALID_PEER; 1791 channel_freq = htt_get_channel_freq(type, ext_header_data); 1792 if (channel_freq != HTT_INVALID_CHANNEL && channel_freq > 0) 1793 HTT_TX_DESC_CHAN_FREQ_SET(local_word3, channel_freq); 1794 #if HTT_PADDR64 1795 *word4 = local_word3; 1796 #else /* ! HTT_PADDR64 */ 1797 *word3 = local_word3; 1798 #endif /* HTT_PADDR64 */ 1799 1800 /* 1801 * If any of the tx control flags are set, then we need the extended 1802 * HTT header. 1803 */ 1804 if (desc_ext_required) { 1805 struct htt_tx_msdu_desc_ext_t local_desc_ext = {0}; 1806 1807 htt_push_ext_header(msdu, &local_desc_ext, 1808 type, ext_header_data); 1809 } 1810 1811 /* 1812 * Specify that the data provided by the OS is a bytestream, 1813 * and thus should not be byte-swapped during the HIF download 1814 * even if the host is big-endian. 1815 * There could be extra fragments added before the OS's fragments, 1816 * e.g. for TSO, so it's incorrect to clear the frag 0 wordstream flag. 1817 * Instead, clear the wordstream flag for the final fragment, which 1818 * is certain to be (one of the) fragment(s) provided by the OS. 1819 * Setting the flag for this final fragment suffices for specifying 1820 * all fragments provided by the OS rather than added by the driver. 1821 */ 1822 qdf_nbuf_set_frag_is_wordstream(msdu, qdf_nbuf_get_num_frags(msdu) - 1, 1823 0); 1824 1825 if (QDF_NBUF_CB_PADDR(msdu) == 0) { 1826 dir = QDF_NBUF_CB_TX_DMA_BI_MAP(msdu) ? 1827 QDF_DMA_BIDIRECTIONAL : QDF_DMA_TO_DEVICE; 1828 status = qdf_nbuf_map_single(qdf_ctx, msdu, dir); 1829 if (qdf_unlikely(status != QDF_STATUS_SUCCESS)) { 1830 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, 1831 "%s: nbuf map failed", __func__); 1832 return QDF_STATUS_E_NOMEM; 1833 } 1834 } 1835 1836 /* store a link to the HTT tx descriptor within the netbuf */ 1837 qdf_nbuf_frag_push_head(msdu, sizeof(struct htt_host_tx_desc_t), 1838 (char *)htt_host_tx_desc, /* virtual addr */ 1839 htt_tx_desc_paddr); 1840 1841 /* 1842 * Indicate that the HTT header (and HTC header) is a meta-data 1843 * "wordstream", i.e. series of uint32_t, rather than a data 1844 * bytestream. 1845 * This allows the HIF download to byteswap the HTT + HTC headers if 1846 * the host is big-endian, to convert to the target's little-endian 1847 * format. 1848 */ 1849 qdf_nbuf_set_frag_is_wordstream(msdu, 0, 1); 1850 1851 if (qdf_likely(pdev->cfg.ce_classify_enabled && 1852 (msdu_info->info.l2_hdr_type != htt_pkt_type_mgmt))) { 1853 uint32_t pkt_offset = qdf_nbuf_get_frag_len(msdu, 0); 1854 1855 data_attr = hw_classify << CE_DESC_TX_CLASSIFY_BIT_S; 1856 data_attr |= ce_pkt_type << CE_DESC_PKT_TYPE_BIT_S; 1857 data_attr |= pkt_offset << CE_DESC_PKT_OFFSET_BIT_S; 1858 } 1859 1860 qdf_nbuf_data_attr_set(msdu, data_attr); 1861 return QDF_STATUS_SUCCESS; 1862 } 1863 1864 #ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL 1865 1866 /** 1867 * htt_tx_group_credit_process() - process group data for 1868 * credit update indication 1869 * @pdev: pointer to htt device. 1870 * @msg_word: htt msg 1871 * 1872 * Return: None 1873 */ htt_tx_group_credit_process(struct htt_pdev_t * pdev,u_int32_t * msg_word)1874 void htt_tx_group_credit_process(struct htt_pdev_t *pdev, u_int32_t *msg_word) 1875 { 1876 int group_credit_sign; 1877 int32_t group_credit; 1878 u_int32_t group_credit_abs, vdev_id_mask, ac_mask; 1879 u_int8_t group_abs, group_id; 1880 u_int8_t group_offset = 0, more_group_present = 0; 1881 1882 more_group_present = HTT_TX_CREDIT_TXQ_GRP_GET(*msg_word); 1883 1884 while (more_group_present) { 1885 /* Parse the Group Data */ 1886 group_id = HTT_TXQ_GROUP_ID_GET(*(msg_word+1 1887 +group_offset)); 1888 group_credit_abs = 1889 HTT_TXQ_GROUP_CREDIT_COUNT_GET(*(msg_word+1 1890 +group_offset)); 1891 group_credit_sign = 1892 HTT_TXQ_GROUP_SIGN_GET(*(msg_word+1 1893 +group_offset)) ? -1 : 1; 1894 group_credit = group_credit_sign * group_credit_abs; 1895 group_abs = HTT_TXQ_GROUP_ABS_GET(*(msg_word+1 1896 +group_offset)); 1897 1898 vdev_id_mask = 1899 HTT_TXQ_GROUP_VDEV_ID_MASK_GET(*(msg_word+2 1900 +group_offset)); 1901 ac_mask = HTT_TXQ_GROUP_AC_MASK_GET(*(msg_word+2 1902 +group_offset)); 1903 1904 ol_txrx_update_tx_queue_groups(pdev->txrx_pdev, group_id, 1905 group_credit, group_abs, 1906 vdev_id_mask, ac_mask); 1907 more_group_present = HTT_TXQ_GROUP_EXT_GET(*(msg_word+1 1908 +group_offset)); 1909 group_offset += HTT_TX_GROUP_INDEX_OFFSET; 1910 } 1911 ol_tx_update_group_credit_stats(pdev->txrx_pdev); 1912 } 1913 #endif 1914 1915