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