1 /*
2 * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2024 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 #include "htc_debug.h"
21 #include "htc_internal.h"
22 #include "htc_credit_history.h"
23 #include <qdf_mem.h> /* qdf_mem_malloc */
24 #include <qdf_nbuf.h> /* qdf_nbuf_t */
25 #include "qdf_module.h"
26
27 /* #define USB_HIF_SINGLE_PIPE_DATA_SCHED */
28 /* #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED */
29 #define DATA_EP_SIZE 4
30 /* #endif */
31 #define HTC_DATA_RESOURCE_THRS 256
32 #define HTC_DATA_MINDESC_PERPACKET 2
33
34 /* maximum number of requeue attempts before print */
35 #define MAX_REQUEUE_WARN 5
36
37 enum HTC_SEND_QUEUE_RESULT {
38 HTC_SEND_QUEUE_OK = 0, /* packet was queued */
39 HTC_SEND_QUEUE_DROP = 1, /* this packet should be dropped */
40 };
41
42 #ifndef DEBUG_CREDIT
43 #define DEBUG_CREDIT 0
44 #endif
45
46 #if DEBUG_CREDIT
47 /* bit mask to enable debug certain endpoint */
48 static unsigned int ep_debug_mask =
49 (1 << ENDPOINT_0) | (1 << ENDPOINT_1) | (1 << ENDPOINT_2);
50 #endif
51
52 #ifdef QCA_WIFI_EMULATION
53 #define HTC_EMULATION_DELAY_IN_MS 20
54 /**
55 * htc_add_emulation_delay() - Adds a delay in before proceeding, only for
56 * emulation
57 *
58 * Return: None
59 */
htc_add_emulation_delay(void)60 static inline void htc_add_emulation_delay(void)
61 {
62 qdf_mdelay(HTC_EMULATION_DELAY_IN_MS);
63 }
64 #else
htc_add_emulation_delay(void)65 static inline void htc_add_emulation_delay(void)
66 {
67 }
68 #endif
69
htc_dump_counter_info(HTC_HANDLE HTCHandle)70 void htc_dump_counter_info(HTC_HANDLE HTCHandle)
71 {
72 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
73
74 if (!target)
75 return;
76
77 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
78 ("\n%s: ce_send_cnt = %d, TX_comp_cnt = %d\n",
79 __func__, target->ce_send_cnt, target->TX_comp_cnt));
80 }
81
htc_get_tx_queue_depth(HTC_HANDLE htc_handle,HTC_ENDPOINT_ID endpoint_id)82 int htc_get_tx_queue_depth(HTC_HANDLE htc_handle, HTC_ENDPOINT_ID endpoint_id)
83 {
84 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
85 HTC_ENDPOINT *endpoint = &target->endpoint[endpoint_id];
86
87 return HTC_PACKET_QUEUE_DEPTH(&endpoint->TxQueue);
88 }
89 qdf_export_symbol(htc_get_tx_queue_depth);
90
htc_get_control_endpoint_tx_host_credits(HTC_HANDLE HTCHandle,int * credits)91 void htc_get_control_endpoint_tx_host_credits(HTC_HANDLE HTCHandle,
92 int *credits)
93 {
94 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
95 HTC_ENDPOINT *pEndpoint;
96 int i;
97
98 if (!credits || !target) {
99 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: invalid args", __func__));
100 return;
101 }
102
103 *credits = 0;
104 LOCK_HTC_TX(target);
105 for (i = 0; i < ENDPOINT_MAX; i++) {
106 pEndpoint = &target->endpoint[i];
107 if (pEndpoint->service_id == WMI_CONTROL_SVC) {
108 *credits = pEndpoint->TxCredits;
109 break;
110 }
111 }
112 UNLOCK_HTC_TX(target);
113 }
114
restore_tx_packet(HTC_TARGET * target,HTC_PACKET * pPacket)115 static inline void restore_tx_packet(HTC_TARGET *target, HTC_PACKET *pPacket)
116 {
117 qdf_nbuf_t netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
118
119 if (pPacket->PktInfo.AsTx.Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) {
120 qdf_nbuf_unmap(target->osdev, netbuf, QDF_DMA_TO_DEVICE);
121 pPacket->PktInfo.AsTx.Flags &= ~HTC_TX_PACKET_FLAG_FIXUP_NETBUF;
122 }
123 if (pPacket->PktInfo.AsTx.Flags &
124 HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA) {
125 qdf_nbuf_pull_head(netbuf, sizeof(HTC_FRAME_HDR));
126 pPacket->PktInfo.AsTx.Flags &=
127 ~HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA;
128 }
129 }
130
send_packet_completion(HTC_TARGET * target,HTC_PACKET * pPacket)131 static void send_packet_completion(HTC_TARGET *target, HTC_PACKET *pPacket)
132 {
133 HTC_ENDPOINT *pEndpoint = &target->endpoint[pPacket->Endpoint];
134 HTC_EP_SEND_PKT_COMPLETE EpTxComplete;
135
136 if ((pPacket->PktInfo.AsTx.Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) &&
137 (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)))
138 target->nbuf_nfc_unmap_count++;
139
140 restore_tx_packet(target, pPacket);
141
142 /*
143 * In case of SSR, we cannot call the upper layer completion
144 * callbacks, hence just free the nbuf and HTC packet here.
145 */
146 if (target->hif_dev && hif_get_target_status(target->hif_dev)) {
147 htc_free_control_tx_packet(target, pPacket);
148 return;
149 }
150
151 /* do completion */
152 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
153 ("HTC calling ep %d send complete callback on packet %pK\n",
154 pEndpoint->Id, pPacket));
155
156 EpTxComplete = pEndpoint->EpCallBacks.EpTxComplete;
157 if (EpTxComplete)
158 EpTxComplete(pEndpoint->EpCallBacks.pContext, pPacket);
159 else
160 qdf_nbuf_free(pPacket->pPktContext);
161
162
163 }
164
165 #ifdef FEATURE_RUNTIME_PM
166 /**
167 * log_packet_info() - Log HTC packet information
168 *
169 * @target: handle of HTC context
170 * @pPacket: handle of HTC packet
171 *
172 * Return: None
173 */
log_packet_info(HTC_TARGET * target,HTC_PACKET * pPacket)174 static void log_packet_info(HTC_TARGET *target, HTC_PACKET *pPacket)
175 {
176 HTC_ENDPOINT *pEndpoint = &target->endpoint[pPacket->Endpoint];
177 HTC_EP_LOG_PKT ep_log_pkt;
178 qdf_nbuf_t netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
179
180 ep_log_pkt = pEndpoint->EpCallBacks.ep_log_pkt;
181 if (ep_log_pkt) {
182 qdf_nbuf_pull_head(netbuf, sizeof(HTC_FRAME_HDR));
183 ep_log_pkt(pEndpoint->EpCallBacks.pContext, pPacket);
184 qdf_nbuf_push_head(netbuf, sizeof(HTC_FRAME_HDR));
185 }
186 }
187
188 /**
189 * htc_inc_htt_runtime_cnt() - Increment htc htt runtime count
190 * @target: handle of HTC context
191 *
192 * Return: None
193 */
194 static inline
htc_inc_htt_runtime_cnt(HTC_TARGET * target)195 void htc_inc_htt_runtime_cnt(HTC_TARGET *target)
196 {
197 qdf_atomic_inc(&target->htc_htt_runtime_cnt);
198 }
199 #else
log_packet_info(HTC_TARGET * target,HTC_PACKET * pPacket)200 static void log_packet_info(HTC_TARGET *target, HTC_PACKET *pPacket)
201 {
202 }
203
204 static inline
htc_inc_htt_runtime_cnt(HTC_TARGET * target)205 void htc_inc_htt_runtime_cnt(HTC_TARGET *target)
206 {
207 }
208 #endif
209
htc_send_complete_check_cleanup(void * context)210 void htc_send_complete_check_cleanup(void *context)
211 {
212 HTC_ENDPOINT *pEndpoint = (HTC_ENDPOINT *) context;
213
214 htc_send_complete_check(pEndpoint, 1);
215 }
216
allocate_htc_bundle_packet(HTC_TARGET * target)217 HTC_PACKET *allocate_htc_bundle_packet(HTC_TARGET *target)
218 {
219 HTC_PACKET *pPacket;
220 HTC_PACKET_QUEUE *pQueueSave;
221 qdf_nbuf_t netbuf;
222
223 LOCK_HTC_TX(target);
224 if (!target->pBundleFreeList) {
225 UNLOCK_HTC_TX(target);
226 netbuf = qdf_nbuf_alloc(NULL,
227 target->MaxMsgsPerHTCBundle *
228 target->TargetCreditSize, 0, 4, false);
229 AR_DEBUG_ASSERT(netbuf);
230 if (!netbuf)
231 return NULL;
232 pPacket = qdf_mem_malloc(sizeof(HTC_PACKET));
233 AR_DEBUG_ASSERT(pPacket);
234 if (!pPacket) {
235 qdf_nbuf_free(netbuf);
236 return NULL;
237 }
238 pQueueSave = qdf_mem_malloc(sizeof(HTC_PACKET_QUEUE));
239 AR_DEBUG_ASSERT(pQueueSave);
240 if (!pQueueSave) {
241 qdf_nbuf_free(netbuf);
242 qdf_mem_free(pPacket);
243 return NULL;
244 }
245 INIT_HTC_PACKET_QUEUE(pQueueSave);
246 pPacket->pContext = pQueueSave;
247 SET_HTC_PACKET_NET_BUF_CONTEXT(pPacket, netbuf);
248 pPacket->pBuffer = qdf_nbuf_data(netbuf);
249 pPacket->BufferLength = qdf_nbuf_len(netbuf);
250
251 /* store the original head room so that we can restore this
252 * when we "free" the packet.
253 * free packet puts the packet back on the free list
254 */
255 pPacket->netbufOrigHeadRoom = qdf_nbuf_headroom(netbuf);
256 return pPacket;
257 }
258 /* already done malloc - restore from free list */
259 pPacket = target->pBundleFreeList;
260 AR_DEBUG_ASSERT(pPacket);
261 if (!pPacket) {
262 UNLOCK_HTC_TX(target);
263 return NULL;
264 }
265 target->pBundleFreeList = (HTC_PACKET *) pPacket->ListLink.pNext;
266 UNLOCK_HTC_TX(target);
267 pPacket->ListLink.pNext = NULL;
268
269 return pPacket;
270 }
271
free_htc_bundle_packet(HTC_TARGET * target,HTC_PACKET * pPacket)272 void free_htc_bundle_packet(HTC_TARGET *target, HTC_PACKET *pPacket)
273 {
274 uint32_t curentHeadRoom;
275 qdf_nbuf_t netbuf;
276 HTC_PACKET_QUEUE *pQueueSave;
277
278 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
279 AR_DEBUG_ASSERT(netbuf);
280 if (!netbuf) {
281 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
282 ("\n%s: Invalid netbuf in HTC Packet\n",
283 __func__));
284 return;
285 }
286 /* HIF adds data to the headroom section of the nbuf, restore their
287 * original size. If this is not done, headroom keeps shrinking with
288 * every HIF send and eventually HIF ends up doing another malloc big
289 * enough to store the data + its header
290 */
291
292 curentHeadRoom = qdf_nbuf_headroom(netbuf);
293 qdf_nbuf_pull_head(netbuf,
294 pPacket->netbufOrigHeadRoom - curentHeadRoom);
295 qdf_nbuf_trim_tail(netbuf, qdf_nbuf_len(netbuf));
296
297 /* restore the pBuffer pointer. HIF changes this */
298 pPacket->pBuffer = qdf_nbuf_data(netbuf);
299 pPacket->BufferLength = qdf_nbuf_len(netbuf);
300
301 /* restore queue */
302 pQueueSave = (HTC_PACKET_QUEUE *) pPacket->pContext;
303 if (qdf_unlikely(!pQueueSave)) {
304 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
305 ("\n%s: Invalid pQueueSave in HTC Packet\n",
306 __func__));
307 AR_DEBUG_ASSERT(pQueueSave);
308 } else
309 INIT_HTC_PACKET_QUEUE(pQueueSave);
310
311 LOCK_HTC_TX(target);
312 if (!target->pBundleFreeList) {
313 target->pBundleFreeList = pPacket;
314 pPacket->ListLink.pNext = NULL;
315 } else {
316 pPacket->ListLink.pNext = (DL_LIST *) target->pBundleFreeList;
317 target->pBundleFreeList = pPacket;
318 }
319 UNLOCK_HTC_TX(target);
320 }
321
322 #if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT)
323
324 /**
325 * htc_send_update_tx_bundle_stats() - update tx bundle stats depends
326 * on max bundle size
327 * @target: hif context
328 * @data_len: tx data len
329 * @TxCreditSize: endpoint tx credit size
330 *
331 * Return: None
332 */
333 static inline void
htc_send_update_tx_bundle_stats(HTC_TARGET * target,qdf_size_t data_len,int TxCreditSize)334 htc_send_update_tx_bundle_stats(HTC_TARGET *target,
335 qdf_size_t data_len,
336 int TxCreditSize)
337 {
338 int index = ((data_len + TxCreditSize - 1) / TxCreditSize) - 1;
339
340 if (index < HTC_MAX_MSG_PER_BUNDLE_TX)
341 target->tx_bundle_stats[index]++;
342 }
343
344 /**
345 * htc_issue_tx_bundle_stats_inc() - increment in tx bundle stats
346 * on max bundle size
347 * @target: hif context
348 *
349 * Return: None
350 */
351 static inline void
htc_issue_tx_bundle_stats_inc(HTC_TARGET * target)352 htc_issue_tx_bundle_stats_inc(HTC_TARGET *target)
353 {
354 target->tx_bundle_stats[0]++;
355 }
356 #else
357
358 static inline void
htc_send_update_tx_bundle_stats(HTC_TARGET * target,qdf_size_t data_len,int TxCreditSize)359 htc_send_update_tx_bundle_stats(HTC_TARGET *target,
360 qdf_size_t data_len,
361 int TxCreditSize)
362 {
363 }
364
365 static inline void
htc_issue_tx_bundle_stats_inc(HTC_TARGET * target)366 htc_issue_tx_bundle_stats_inc(HTC_TARGET *target)
367 {
368 }
369 #endif
370
371 #if defined(HIF_USB) || defined(HIF_SDIO)
372 #ifdef ENABLE_BUNDLE_TX
htc_send_bundled_netbuf(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,unsigned char * pBundleBuffer,HTC_PACKET * pPacketTx)373 static QDF_STATUS htc_send_bundled_netbuf(HTC_TARGET *target,
374 HTC_ENDPOINT *pEndpoint,
375 unsigned char *pBundleBuffer,
376 HTC_PACKET *pPacketTx)
377 {
378 qdf_size_t data_len;
379 QDF_STATUS status;
380 qdf_nbuf_t bundleBuf;
381 uint32_t data_attr = 0;
382
383 bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx);
384 data_len = pBundleBuffer - qdf_nbuf_data(bundleBuf);
385 qdf_nbuf_put_tail(bundleBuf, data_len);
386 SET_HTC_PACKET_INFO_TX(pPacketTx,
387 target,
388 pBundleBuffer,
389 data_len,
390 pEndpoint->Id, HTC_TX_PACKET_TAG_BUNDLED);
391 LOCK_HTC_TX(target);
392 HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacketTx);
393 pEndpoint->ul_outstanding_cnt++;
394 UNLOCK_HTC_TX(target);
395 #if DEBUG_BUNDLE
396 qdf_print(" Send bundle EP%d buffer size:0x%x, total:0x%x, count:%d.",
397 pEndpoint->Id,
398 pEndpoint->TxCreditSize,
399 data_len, data_len / pEndpoint->TxCreditSize);
400 #endif
401
402 htc_send_update_tx_bundle_stats(target, data_len,
403 pEndpoint->TxCreditSize);
404
405 status = hif_send_head(target->hif_dev,
406 pEndpoint->UL_PipeID,
407 pEndpoint->Id, data_len,
408 bundleBuf, data_attr);
409 if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) {
410 HTC_PACKET_QUEUE requeue;
411
412 qdf_print("hif_send_head failed(len=%zu).", data_len);
413 INIT_HTC_PACKET_QUEUE(&requeue);
414 LOCK_HTC_TX(target);
415 pEndpoint->ul_outstanding_cnt--;
416 HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacketTx);
417
418 if (pPacketTx->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_BUNDLED) {
419 HTC_PACKET *temp_packet;
420 HTC_PACKET_QUEUE *packet_queue =
421 (HTC_PACKET_QUEUE *)pPacketTx->pContext;
422
423 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(packet_queue,
424 temp_packet) {
425 HTC_PACKET_ENQUEUE(&requeue, temp_packet);
426 } HTC_PACKET_QUEUE_ITERATE_END;
427
428 UNLOCK_HTC_TX(target);
429 free_htc_bundle_packet(target, pPacketTx);
430 LOCK_HTC_TX(target);
431
432 } else {
433 HTC_PACKET_ENQUEUE(&requeue, pPacketTx);
434 }
435
436 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue,
437 &requeue);
438 UNLOCK_HTC_TX(target);
439 }
440 return status;
441 }
442
443 #ifdef QCA_TX_PADDING_CREDIT_SUPPORT
444 #define SDIO_BLOCK_SIZE 512
htc_tx_pad_credit_avail(HTC_ENDPOINT * ep)445 static int htc_tx_pad_credit_avail(HTC_ENDPOINT *ep)
446 {
447 int ret = 0;
448
449 if (!ep || !ep->EpCallBacks.pContext ||
450 !ep->EpCallBacks.ep_padding_credit_update)
451 return 1;
452
453 ret = ep->EpCallBacks.ep_padding_credit_update(ep->EpCallBacks.pContext,
454 0);
455
456 if (ret < 2)
457 AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s ret %d\n", __func__, ret));
458
459 return ret;
460 }
461
htc_handle_extra_tx_credit(HTC_ENDPOINT * ep,HTC_PACKET * p_last_htc_pkt,unsigned char * p_last_pkt_bundle_buffer,unsigned char ** p_bundle_buffer,int tot_data_len)462 static bool htc_handle_extra_tx_credit(HTC_ENDPOINT *ep,
463 HTC_PACKET *p_last_htc_pkt,
464 unsigned char *p_last_pkt_bundle_buffer,
465 unsigned char **p_bundle_buffer,
466 int tot_data_len)
467 {
468 bool extra_tx_credit = FALSE;
469 HTC_FRAME_HDR *p_htc_hdr;
470 int first_buf_bundled_len = 0, last_buf_len = 0;
471 int sdio_pad = 0, free_space = 0;
472 int (*update_ep_padding_credit)(void *, int);
473
474 update_ep_padding_credit = ep->EpCallBacks.ep_padding_credit_update;
475
476 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
477 ("%s Tot data_len = %d\n", __func__, tot_data_len));
478
479 if (!p_last_htc_pkt)
480 return extra_tx_credit;
481
482 last_buf_len = (p_last_htc_pkt->ActualLength + HTC_HDR_LENGTH);
483 if (tot_data_len != last_buf_len) {
484 first_buf_bundled_len = tot_data_len - ep->TxCreditSize;
485 free_space = tot_data_len -
486 (first_buf_bundled_len + last_buf_len);
487 } else {
488 free_space = ep->TxCreditSize - tot_data_len;
489 }
490
491 sdio_pad = SDIO_BLOCK_SIZE - ((first_buf_bundled_len + last_buf_len) %
492 SDIO_BLOCK_SIZE);
493
494 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
495 ("%s first_buf_bundled_len = %d last_buf_len = %d\n",
496 __func__, first_buf_bundled_len, last_buf_len));
497
498 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
499 ("%s sdio_pad = %d free_space = %d\n", __func__,
500 sdio_pad, free_space));
501
502 if (sdio_pad <= free_space) {
503 if (p_bundle_buffer && *p_bundle_buffer) {
504 /* Align Tx bundled buf to avoid a extra Padding buf */
505 *p_bundle_buffer -= (free_space - sdio_pad);
506 }
507 } else {
508 /* Extra Padding Buffer needed, consume extra tx credit */
509 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
510 ("%s Used a Tx credit for Padding Buffer\n",
511 __func__));
512 p_htc_hdr = (HTC_FRAME_HDR *)(p_last_pkt_bundle_buffer);
513 p_htc_hdr->Flags |= HTC_FLAGS_PADDING_CHECK;
514 extra_tx_credit = TRUE;
515 if (ep->EpCallBacks.ep_padding_credit_update) {
516 /* Decrement 1 credit at host,
517 * due to extra tx credit consumed by padding buffer
518 */
519 update_ep_padding_credit(ep->EpCallBacks.pContext, -1);
520 }
521 }
522 return extra_tx_credit;
523 }
524 #else
htc_tx_pad_credit_avail(HTC_ENDPOINT * ep)525 static int htc_tx_pad_credit_avail(HTC_ENDPOINT *ep)
526 {
527 return 1;
528 }
529
htc_handle_extra_tx_credit(HTC_ENDPOINT * ep,HTC_PACKET * p_last_htc_pkt,unsigned char * p_last_pkt_bundle_buffer,unsigned char ** p_bundle_buffer,int tot_data_len)530 static bool htc_handle_extra_tx_credit(HTC_ENDPOINT *ep,
531 HTC_PACKET *p_last_htc_pkt,
532 unsigned char *p_last_pkt_bundle_buffer,
533 unsigned char **p_bundle_buffer,
534 int tot_data_len)
535 {
536 return FALSE;
537 }
538 #endif
539
540 /**
541 * htc_issue_packets_bundle() - HTC function to send bundle packets from a queue
542 * @target: HTC target on which packets need to be sent
543 * @pEndpoint: logical endpoint on which packets needs to be sent
544 * @pPktQueue: HTC packet queue containing the list of packets to be sent
545 *
546 * Return: void
547 */
htc_issue_packets_bundle(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,HTC_PACKET_QUEUE * pPktQueue)548 static void htc_issue_packets_bundle(HTC_TARGET *target,
549 HTC_ENDPOINT *pEndpoint,
550 HTC_PACKET_QUEUE *pPktQueue)
551 {
552 int i, frag_count, nbytes;
553 qdf_nbuf_t netbuf, bundleBuf;
554 unsigned char *pBundleBuffer = NULL;
555 HTC_PACKET *pPacket = NULL, *pPacketTx = NULL;
556 HTC_FRAME_HDR *pHtcHdr;
557 int last_credit_pad = 0;
558 int creditPad, creditRemainder, transferLength, bundlesSpaceRemaining =
559 0;
560 HTC_PACKET_QUEUE *pQueueSave = NULL;
561 HTC_PACKET *p_last_htc_pkt = NULL;
562 unsigned char *p_last_pkt_bundle_buffer = NULL;
563
564 bundlesSpaceRemaining =
565 target->MaxMsgsPerHTCBundle * pEndpoint->TxCreditSize;
566 pPacketTx = allocate_htc_bundle_packet(target);
567 if (!pPacketTx) {
568 /* good time to panic */
569 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
570 ("allocate_htc_bundle_packet failed\n"));
571 AR_DEBUG_ASSERT(false);
572 return;
573 }
574 bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx);
575 pBundleBuffer = qdf_nbuf_data(bundleBuf);
576 pQueueSave = (HTC_PACKET_QUEUE *) pPacketTx->pContext;
577 while (1) {
578 if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
579 if (htc_tx_pad_credit_avail(pEndpoint) < 1)
580 break;
581 }
582 pPacket = htc_packet_dequeue(pPktQueue);
583 if (!pPacket)
584 break;
585 creditPad = 0;
586 transferLength = pPacket->ActualLength + HTC_HDR_LENGTH;
587 creditRemainder = transferLength % pEndpoint->TxCreditSize;
588 if (creditRemainder != 0) {
589 if (transferLength < pEndpoint->TxCreditSize) {
590 creditPad = pEndpoint->TxCreditSize -
591 transferLength;
592 } else {
593 creditPad = creditRemainder;
594 }
595 transferLength += creditPad;
596 }
597
598 if (bundlesSpaceRemaining < transferLength) {
599 htc_handle_extra_tx_credit(pEndpoint, p_last_htc_pkt,
600 p_last_pkt_bundle_buffer,
601 &pBundleBuffer,
602 pBundleBuffer -
603 qdf_nbuf_data(bundleBuf));
604
605 /* send out previous buffer */
606 htc_send_bundled_netbuf(target, pEndpoint,
607 pBundleBuffer - last_credit_pad,
608 pPacketTx);
609 /* One packet has been dequeued from sending queue when enter
610 * this loop, so need to add 1 back for this checking.
611 */
612 if ((HTC_PACKET_QUEUE_DEPTH(pPktQueue) + 1) <
613 HTC_MIN_MSG_PER_BUNDLE) {
614 HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket);
615 return;
616 }
617 bundlesSpaceRemaining =
618 target->MaxMsgsPerHTCBundle *
619 pEndpoint->TxCreditSize;
620 pPacketTx = allocate_htc_bundle_packet(target);
621 if (!pPacketTx) {
622 HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket);
623 /* good time to panic */
624 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
625 ("allocate_htc_bundle_packet failed\n"));
626 AR_DEBUG_ASSERT(false);
627 return;
628 }
629 bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx);
630 pBundleBuffer = qdf_nbuf_data(bundleBuf);
631 pQueueSave = (HTC_PACKET_QUEUE *) pPacketTx->pContext;
632 }
633
634 p_last_htc_pkt = pPacket;
635 p_last_pkt_bundle_buffer = pBundleBuffer;
636
637 bundlesSpaceRemaining -= transferLength;
638 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
639
640 if (hif_get_bus_type(target->hif_dev) != QDF_BUS_TYPE_USB) {
641 pHtcHdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr(
642 netbuf, 0);
643 HTC_WRITE32(pHtcHdr,
644 SM(pPacket->ActualLength,
645 HTC_FRAME_HDR_PAYLOADLEN) |
646 SM(pPacket->PktInfo.AsTx.SendFlags |
647 HTC_FLAGS_SEND_BUNDLE,
648 HTC_FRAME_HDR_FLAGS) |
649 SM(pPacket->Endpoint,
650 HTC_FRAME_HDR_ENDPOINTID));
651 HTC_WRITE32((uint32_t *) pHtcHdr + 1,
652 SM(pPacket->PktInfo.AsTx.SeqNo,
653 HTC_FRAME_HDR_CONTROLBYTES1) | SM(creditPad,
654 HTC_FRAME_HDR_RESERVED));
655 pHtcHdr->reserved = creditPad;
656 }
657 frag_count = qdf_nbuf_get_num_frags(netbuf);
658 nbytes = pPacket->ActualLength + HTC_HDR_LENGTH;
659 for (i = 0; i < frag_count && nbytes > 0; i++) {
660 int frag_len = qdf_nbuf_get_frag_len(netbuf, i);
661 unsigned char *frag_addr =
662 qdf_nbuf_get_frag_vaddr(netbuf, i);
663 if (frag_len > nbytes)
664 frag_len = nbytes;
665 qdf_mem_copy(pBundleBuffer, frag_addr, frag_len);
666 nbytes -= frag_len;
667 pBundleBuffer += frag_len;
668 }
669 HTC_PACKET_ENQUEUE(pQueueSave, pPacket);
670 pBundleBuffer += creditPad;
671
672 /* last one can't be packed. */
673 if (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB)
674 last_credit_pad = creditPad;
675 }
676 /* send out remaining buffer */
677 if (pBundleBuffer != qdf_nbuf_data(bundleBuf)) {
678 htc_handle_extra_tx_credit(pEndpoint, p_last_htc_pkt,
679 p_last_pkt_bundle_buffer,
680 &pBundleBuffer,
681 pBundleBuffer -
682 qdf_nbuf_data(bundleBuf));
683
684 htc_send_bundled_netbuf(target, pEndpoint,
685 pBundleBuffer - last_credit_pad,
686 pPacketTx);
687 } else {
688 free_htc_bundle_packet(target, pPacketTx);
689 }
690 }
691 #endif /* ENABLE_BUNDLE_TX */
692 #else
htc_tx_pad_credit_avail(HTC_ENDPOINT * ep)693 static int htc_tx_pad_credit_avail(HTC_ENDPOINT *ep)
694 {
695 return 1;
696 }
697
698 bool htc_handle_extra_tx_credit(HTC_ENDPOINT *ep,
699 HTC_PACKET *p_last_htc_pkt,
700 unsigned char *p_last_pkt_bundle_buffer,
701 unsigned char **p_bundle_buffer,
702 int tot_data_len);
htc_handle_extra_tx_credit(HTC_ENDPOINT * ep,HTC_PACKET * p_last_htc_pkt,unsigned char * p_last_pkt_bundle_buffer,unsigned char ** p_bundle_buffer,int tot_data_len)703 bool htc_handle_extra_tx_credit(HTC_ENDPOINT *ep,
704 HTC_PACKET *p_last_htc_pkt,
705 unsigned char *p_last_pkt_bundle_buffer,
706 unsigned char **p_bundle_buffer,
707 int tot_data_len)
708 {
709 return FALSE;
710 }
711
htc_issue_packets_bundle(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,HTC_PACKET_QUEUE * pPktQueue)712 static void htc_issue_packets_bundle(HTC_TARGET *target,
713 HTC_ENDPOINT *pEndpoint,
714 HTC_PACKET_QUEUE *pPktQueue)
715 {
716 }
717 #endif
718
719 /**
720 * htc_issue_packets() - HTC function to send packets from a queue
721 * @target: HTC target on which packets need to be sent
722 * @pEndpoint: logical endpoint on which packets needs to be sent
723 * @pPktQueue: HTC packet queue containing the list of packets to be sent
724 *
725 * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure
726 */
htc_issue_packets(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,HTC_PACKET_QUEUE * pPktQueue)727 static QDF_STATUS htc_issue_packets(HTC_TARGET *target,
728 HTC_ENDPOINT *pEndpoint,
729 HTC_PACKET_QUEUE *pPktQueue)
730 {
731 QDF_STATUS status = QDF_STATUS_SUCCESS;
732 qdf_nbuf_t netbuf;
733 HTC_PACKET *pPacket = NULL;
734 uint16_t payloadLen;
735 HTC_FRAME_HDR *pHtcHdr;
736 uint32_t data_attr = 0;
737 enum qdf_bus_type bus_type;
738 QDF_STATUS ret;
739 bool rt_put = false;
740 bool used_extra_tx_credit = false;
741 uint8_t *buf = NULL;
742 int (*update_ep_padding_credit)(void *, int);
743 void *ctx = NULL;
744 bool rt_put_in_resp;
745 int32_t sys_state = HIF_SYSTEM_PM_STATE_ON;
746
747 update_ep_padding_credit =
748 pEndpoint->EpCallBacks.ep_padding_credit_update;
749
750 bus_type = hif_get_bus_type(target->hif_dev);
751
752 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
753 ("+htc_issue_packets: Queue: %pK, Pkts %d\n", pPktQueue,
754 HTC_PACKET_QUEUE_DEPTH(pPktQueue)));
755 while (true) {
756 rt_put_in_resp = false;
757 if (HTC_TX_BUNDLE_ENABLED(target) &&
758 HTC_PACKET_QUEUE_DEPTH(pPktQueue) >=
759 HTC_MIN_MSG_PER_BUNDLE) {
760 switch (bus_type) {
761 case QDF_BUS_TYPE_SDIO:
762 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint))
763 break;
764 if (update_ep_padding_credit) {
765 if (htc_tx_pad_credit_avail
766 (pEndpoint) < 1)
767 break;
768 }
769 fallthrough;
770 case QDF_BUS_TYPE_USB:
771 htc_issue_packets_bundle(target,
772 pEndpoint,
773 pPktQueue);
774 break;
775 default:
776 break;
777 }
778 }
779 /* if not bundling or there was a packet that could not be
780 * placed in a bundle, and send it by normal way
781 */
782 if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
783 if (htc_tx_pad_credit_avail(pEndpoint) < 1) {
784 status = QDF_STATUS_E_FAILURE;
785 break;
786 }
787 }
788
789 pPacket = htc_packet_dequeue(pPktQueue);
790 if (!pPacket) {
791 /* local queue is fully drained */
792 break;
793 }
794
795 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
796 AR_DEBUG_ASSERT(netbuf);
797 /* Non-credit enabled endpoints have been mapped and setup by
798 * now, so no need to revisit the HTC headers
799 */
800 if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
801
802 payloadLen = pPacket->ActualLength;
803 /* setup HTC frame header */
804
805 pHtcHdr = (HTC_FRAME_HDR *)
806 qdf_nbuf_get_frag_vaddr(netbuf, 0);
807 if (qdf_unlikely(!pHtcHdr)) {
808 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
809 ("%s Invalid pHtcHdr\n",
810 __func__));
811 AR_DEBUG_ASSERT(pHtcHdr);
812 status = QDF_STATUS_E_FAILURE;
813 break;
814 }
815
816 HTC_WRITE32(pHtcHdr,
817 SM(payloadLen,
818 HTC_FRAME_HDR_PAYLOADLEN) |
819 SM(pPacket->PktInfo.AsTx.SendFlags,
820 HTC_FRAME_HDR_FLAGS) |
821 SM(pPacket->Endpoint,
822 HTC_FRAME_HDR_ENDPOINTID));
823 HTC_WRITE32(((uint32_t *) pHtcHdr) + 1,
824 SM(pPacket->PktInfo.AsTx.SeqNo,
825 HTC_FRAME_HDR_CONTROLBYTES1));
826
827 /*
828 * Now that the HTC frame header has been added, the
829 * netbuf can be mapped. This only applies to non-data
830 * frames, since data frames were already mapped as they
831 * entered into the driver.
832 */
833 ret = qdf_nbuf_map(target->osdev,
834 GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket),
835 QDF_DMA_TO_DEVICE);
836 if (ret != QDF_STATUS_SUCCESS) {
837 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
838 ("%s nbuf Map Fail Endpnt %pK\n",
839 __func__, pEndpoint));
840 HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket);
841 status = QDF_STATUS_E_FAILURE;
842 break;
843 }
844 pPacket->PktInfo.AsTx.Flags |=
845 HTC_TX_PACKET_FLAG_FIXUP_NETBUF;
846 }
847
848 if (!pEndpoint->async_update) {
849 LOCK_HTC_TX(target);
850 }
851 /* store in look up queue to match completions */
852 HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacket);
853 INC_HTC_EP_STAT(pEndpoint, TxIssued, 1);
854 pEndpoint->ul_outstanding_cnt++;
855 if (!pEndpoint->async_update) {
856 UNLOCK_HTC_TX(target);
857 hif_send_complete_check(target->hif_dev,
858 pEndpoint->UL_PipeID, false);
859 }
860
861 if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_SYSTEM_SUSPEND) {
862 sys_state = hif_system_pm_get_state(target->hif_dev);
863 hif_system_pm_set_state_suspending(target->hif_dev);
864 }
865
866 htc_packet_set_magic_cookie(pPacket, HTC_PACKET_MAGIC_COOKIE);
867 /*
868 * For HTT messages without a response from fw,
869 * do the runtime put here.
870 * otherwise runtime put will be done when the fw response comes
871 */
872 if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_RUNTIME_PUT) {
873 rt_put = true;
874 } else if (pPacket->PktInfo.AsTx.Tag ==
875 HTC_TX_PACKET_TAG_RTPM_PUT_RC) {
876 rt_put_in_resp = true;
877 htc_inc_htt_runtime_cnt(target);
878 }
879
880 #if DEBUG_BUNDLE
881 qdf_print(" Send single EP%d buffer size:0x%x, total:0x%x.",
882 pEndpoint->Id,
883 pEndpoint->TxCreditSize,
884 HTC_HDR_LENGTH + pPacket->ActualLength);
885 #endif
886 buf = (uint8_t *)qdf_nbuf_get_frag_vaddr(netbuf, 0);
887 used_extra_tx_credit =
888 htc_handle_extra_tx_credit(pEndpoint, pPacket, buf,
889 NULL, pPacket->ActualLength +
890 HTC_HDR_LENGTH);
891
892 status = hif_send_head(target->hif_dev,
893 pEndpoint->UL_PipeID, pEndpoint->Id,
894 HTC_HDR_LENGTH + pPacket->ActualLength,
895 netbuf, data_attr);
896
897 if (status != QDF_STATUS_SUCCESS) {
898 if (rt_put_in_resp)
899 htc_dec_return_htt_runtime_cnt((void *)target);
900
901 if (pPacket->PktInfo.AsTx.Tag ==
902 HTC_TX_PACKET_SYSTEM_SUSPEND)
903 __hif_system_pm_set_state(target->hif_dev,
904 sys_state);
905
906 if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
907 if (used_extra_tx_credit) {
908 ctx = pEndpoint->EpCallBacks.pContext;
909 update_ep_padding_credit(ctx, 1);
910 }
911 }
912 }
913
914 htc_issue_tx_bundle_stats_inc(target);
915
916 target->ce_send_cnt++;
917 pEndpoint->htc_send_cnt++;
918
919 if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) {
920 if (status != QDF_STATUS_E_RESOURCES) {
921 /* TODO : if more than 1 endpoint maps to the
922 * same PipeID it is possible to run out of
923 * resources in the HIF layer. Don't emit the
924 * error
925 */
926 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
927 ("hif_send Failed status:%d\n",
928 status));
929 } else {
930 if (target->htc_pkt_dbg) {
931 if (pEndpoint->num_requeues_warn >
932 MAX_REQUEUE_WARN) {
933 hif_print_napi_stats(target->hif_dev);
934 }
935 }
936 }
937
938 /* only unmap if we mapped in this function */
939 if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
940 qdf_nbuf_unmap(target->osdev,
941 GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket),
942 QDF_DMA_TO_DEVICE);
943 pPacket->PktInfo.AsTx.Flags &=
944 ~HTC_TX_PACKET_FLAG_FIXUP_NETBUF;
945 }
946
947 if (!pEndpoint->async_update) {
948 LOCK_HTC_TX(target);
949 }
950 target->ce_send_cnt--;
951 pEndpoint->htc_send_cnt--;
952 pEndpoint->ul_outstanding_cnt--;
953 HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacket);
954 htc_packet_set_magic_cookie(pPacket, 0);
955 /* put it back into the callers queue */
956 HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket);
957 /* reclaim credits */
958 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue,
959 pPacket) {
960 pEndpoint->TxCredits +=
961 pPacket->PktInfo.AsTx.CreditsUsed;
962 } HTC_PACKET_QUEUE_ITERATE_END;
963 if (!pEndpoint->async_update) {
964 UNLOCK_HTC_TX(target);
965 }
966 break;
967 }
968 if (rt_put) {
969 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_HTT);
970 rt_put = false;
971 }
972 }
973
974 if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) {
975 if (((status == QDF_STATUS_E_RESOURCES) &&
976 (pEndpoint->num_requeues_warn > MAX_REQUEUE_WARN)) ||
977 (status != QDF_STATUS_E_RESOURCES)) {
978 QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO,
979 "failed pkt:0x%pK status:%d endpoint:%d",
980 pPacket, status, pEndpoint->Id);
981 }
982
983 }
984
985 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_issue_packets\n"));
986
987 return status;
988 }
989
990 #ifdef FEATURE_RUNTIME_PM
991 /**
992 * extract_htc_pm_packets() - move pm packets from endpoint into queue
993 * @endpoint: which endpoint to extract packets from
994 * @queue: a queue to store extracted packets in.
995 *
996 * remove pm packets from the endpoint's tx queue.
997 * queue them into a queue
998 */
extract_htc_pm_packets(HTC_ENDPOINT * endpoint,HTC_PACKET_QUEUE * queue)999 static void extract_htc_pm_packets(HTC_ENDPOINT *endpoint,
1000 HTC_PACKET_QUEUE *queue)
1001 {
1002 HTC_PACKET *packet;
1003
1004 /* only WMI endpoint has power management packets */
1005 if (endpoint->service_id != WMI_CONTROL_SVC)
1006 return;
1007
1008 ITERATE_OVER_LIST_ALLOW_REMOVE(&endpoint->TxQueue.QueueHead, packet,
1009 HTC_PACKET, ListLink) {
1010 if (packet->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_AUTO_PM) {
1011 HTC_PACKET_REMOVE(&endpoint->TxQueue, packet);
1012 HTC_PACKET_ENQUEUE(queue, packet);
1013 }
1014 } ITERATE_END
1015 }
1016
1017 /**
1018 * queue_htc_pm_packets() - queue pm packets with priority
1019 * @endpoint: endpoint to queue packets to
1020 * @queue: queue of pm packets to enqueue
1021 *
1022 * suspend resume packets get special treatment & priority.
1023 * need to queue them at the front of the queue.
1024 */
queue_htc_pm_packets(HTC_ENDPOINT * endpoint,HTC_PACKET_QUEUE * queue)1025 static void queue_htc_pm_packets(HTC_ENDPOINT *endpoint,
1026 HTC_PACKET_QUEUE *queue)
1027 {
1028 if (endpoint->service_id != WMI_CONTROL_SVC)
1029 return;
1030
1031 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&endpoint->TxQueue, queue);
1032 }
1033
1034 /**
1035 * htc_dec_wmi_runtime_cnt: Decrement htc wmi runtime count
1036 * @target: HTC target
1037 * @rtpm_code: RTPM code
1038 *
1039 * Return: None
1040 */
1041 static inline
htc_dec_wmi_runtime_cnt(HTC_TARGET * target,uint8_t rtpm_code)1042 void htc_dec_wmi_runtime_cnt(HTC_TARGET *target, uint8_t rtpm_code)
1043 {
1044 if (rtpm_code == HIF_RTPM_ID_WMI)
1045 qdf_atomic_dec(&target->htc_wmi_runtime_cnt);
1046 }
1047
1048 /**
1049 * htc_inc_wmi_runtime_cnt: Increment htc wmi runtime count
1050 * @target: HTC target
1051 * @rtpm_code: RTPM code
1052 *
1053 * Return: None
1054 */
1055 static inline
htc_inc_wmi_runtime_cnt(HTC_TARGET * target,uint8_t rtpm_code)1056 void htc_inc_wmi_runtime_cnt(HTC_TARGET *target, uint8_t rtpm_code)
1057 {
1058 if (rtpm_code == HIF_RTPM_ID_WMI)
1059 qdf_atomic_inc(&target->htc_wmi_runtime_cnt);
1060 }
1061 #else
extract_htc_pm_packets(HTC_ENDPOINT * endpoint,HTC_PACKET_QUEUE * queue)1062 static void extract_htc_pm_packets(HTC_ENDPOINT *endpoint,
1063 HTC_PACKET_QUEUE *queue)
1064 {}
1065
queue_htc_pm_packets(HTC_ENDPOINT * endpoint,HTC_PACKET_QUEUE * queue)1066 static void queue_htc_pm_packets(HTC_ENDPOINT *endpoint,
1067 HTC_PACKET_QUEUE *queue)
1068 {}
1069
1070 static inline
htc_dec_wmi_runtime_cnt(HTC_TARGET * target,uint8_t rtpm_code)1071 void htc_dec_wmi_runtime_cnt(HTC_TARGET *target, uint8_t rtpm_code)
1072 {
1073 }
1074
1075 static inline
htc_inc_wmi_runtime_cnt(HTC_TARGET * target,uint8_t rtpm_code)1076 void htc_inc_wmi_runtime_cnt(HTC_TARGET *target, uint8_t rtpm_code)
1077 {
1078 }
1079 #endif
1080
1081 /**
1082 * htc_send_pkts_get_rtpm_id() - get runtime pm dbgid by service_id
1083 * @service_id: service for endpoint
1084 *
1085 * For service_id HTT_DATA_MSG_SVC, HTT message donot have a tx complete
1086 * from CE level, so they need runtime put which only can happen in fw
1087 * response. runtime put will happens at 2 ways.
1088 * 1 if packet tag HTC_TX_PACKET_TAG_RUNTIME_PUT, runtime put
1089 * will be just in htc_issue_packets. as such pkt doesn't have
1090 * a response from fw.
1091 * 2 other pkt must have a response from fw, it will be handled
1092 * by fw response using htc_pm_runtime_put.
1093 *
1094 * For other service_id, they have tx_completion from CE, so they will be
1095 * handled in htc_tx_completion_handler, except packet tag as
1096 * HTC_TX_PACKET_TAG_AUTO_PM, pm related wmi cmd don't need a runtime
1097 * put/get.
1098 *
1099 *
1100 * Return: rtpm id to trace who used it
1101 */
1102 static unsigned int
htc_send_pkts_get_rtpm_id(HTC_SERVICE_ID service_id)1103 htc_send_pkts_get_rtpm_id(HTC_SERVICE_ID service_id)
1104 {
1105 if (service_id == HTT_DATA_MSG_SVC)
1106 return HIF_RTPM_ID_HTT;
1107 else
1108 return HIF_RTPM_ID_WMI;
1109 }
1110
1111 #ifdef SYSTEM_PM_CHECK
1112 /**
1113 * extract_htc_system_resume_pkts() - Move system pm resume packets from
1114 * endpoint into queue
1115 * @endpoint: which endpoint to extract packets from
1116 * @queue: a queue to store extracted packets in.
1117 *
1118 * Remove pm packets from the endpoint's tx queue and enqueue
1119 * them into a queue
1120 */
extract_htc_system_resume_pkts(HTC_ENDPOINT * endpoint,HTC_PACKET_QUEUE * queue)1121 static void extract_htc_system_resume_pkts(HTC_ENDPOINT *endpoint,
1122 HTC_PACKET_QUEUE *queue)
1123 {
1124 HTC_PACKET *packet;
1125
1126 /* only WMI endpoint has power management packets */
1127 if (endpoint->service_id != WMI_CONTROL_SVC)
1128 return;
1129
1130 ITERATE_OVER_LIST_ALLOW_REMOVE(&endpoint->TxQueue.QueueHead, packet,
1131 HTC_PACKET, ListLink) {
1132 if (packet->PktInfo.AsTx.Tag == HTC_TX_PACKET_SYSTEM_RESUME) {
1133 HTC_PACKET_REMOVE(&endpoint->TxQueue, packet);
1134 HTC_PACKET_ENQUEUE(queue, packet);
1135 }
1136 } ITERATE_END
1137 }
1138 #else
1139 static inline
extract_htc_system_resume_pkts(HTC_ENDPOINT * endpoint,HTC_PACKET_QUEUE * queue)1140 void extract_htc_system_resume_pkts(HTC_ENDPOINT *endpoint,
1141 HTC_PACKET_QUEUE *queue)
1142 {
1143 }
1144 #endif
1145
1146 /**
1147 * get_htc_send_packets_credit_based() - get packets based on available credits
1148 * @target: HTC target on which packets need to be sent
1149 * @pEndpoint: logical endpoint on which packets needs to be sent
1150 * @pQueue: HTC packet queue containing the list of packets to be sent
1151 *
1152 * Get HTC send packets from TX queue on an endpoint based on available credits.
1153 * The function moves the packets from TX queue of the endpoint to pQueue.
1154 *
1155 * Return: None
1156 */
get_htc_send_packets_credit_based(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,HTC_PACKET_QUEUE * pQueue)1157 static void get_htc_send_packets_credit_based(HTC_TARGET *target,
1158 HTC_ENDPOINT *pEndpoint,
1159 HTC_PACKET_QUEUE *pQueue)
1160 {
1161 int creditsRequired;
1162 int remainder;
1163 uint8_t sendFlags;
1164 HTC_PACKET *pPacket;
1165 unsigned int transferLength;
1166 HTC_PACKET_QUEUE *tx_queue;
1167 HTC_PACKET_QUEUE pm_queue;
1168 bool do_pm_get = false;
1169 unsigned int rtpm_code = 0;
1170 int ret;
1171 HTC_PACKET_QUEUE sys_pm_queue;
1172 bool sys_pm_check = false;
1173
1174 /*** NOTE : the TX lock is held when this function is called ***/
1175 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1176 ("+get_htc_send_packets_credit_based\n"));
1177
1178 INIT_HTC_PACKET_QUEUE(&pm_queue);
1179 extract_htc_pm_packets(pEndpoint, &pm_queue);
1180 if (HTC_QUEUE_EMPTY(&pm_queue)) {
1181 do_pm_get = true;
1182
1183 INIT_HTC_PACKET_QUEUE(&sys_pm_queue);
1184 extract_htc_system_resume_pkts(pEndpoint, &sys_pm_queue);
1185 if (HTC_QUEUE_EMPTY(&sys_pm_queue)) {
1186 tx_queue = &pEndpoint->TxQueue;
1187 sys_pm_check = true;
1188 } else {
1189 tx_queue = &sys_pm_queue;
1190 }
1191 } else {
1192 tx_queue = &pm_queue;
1193 }
1194
1195 /* loop until we can grab as many packets out of the queue as we can */
1196 while (true) {
1197 if (do_pm_get) {
1198 rtpm_code = htc_send_pkts_get_rtpm_id(
1199 pEndpoint->service_id);
1200 ret = hif_rtpm_get(HIF_RTPM_GET_ASYNC, rtpm_code);
1201 if (ret) {
1202 /* bus suspended, runtime resume issued */
1203 if (HTC_PACKET_QUEUE_DEPTH(pQueue) > 0)
1204 AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
1205 (" pQueue depth: %d\n",
1206 HTC_PACKET_QUEUE_DEPTH(pQueue)));
1207
1208 pPacket = htc_get_pkt_at_head(tx_queue);
1209 if (!pPacket ||
1210 (pPacket->Endpoint >= ENDPOINT_MAX) ||
1211 (pPacket->Endpoint <= ENDPOINT_UNUSED))
1212 break;
1213 log_packet_info(target, pPacket);
1214 break;
1215 }
1216 htc_inc_wmi_runtime_cnt(target, rtpm_code);
1217 }
1218
1219 sendFlags = 0;
1220 /* get packet at head, but don't remove it */
1221 pPacket = htc_get_pkt_at_head(tx_queue);
1222 if (!pPacket) {
1223 if (do_pm_get) {
1224 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code);
1225 htc_dec_wmi_runtime_cnt(target, rtpm_code);
1226 }
1227 break;
1228 }
1229
1230 if (sys_pm_check &&
1231 hif_system_pm_state_check(target->hif_dev)) {
1232 if (do_pm_get) {
1233 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code);
1234 htc_dec_wmi_runtime_cnt(target, rtpm_code);
1235 }
1236 break;
1237 }
1238
1239 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1240 (" Got head packet:%pK , Queue Depth: %d\n",
1241 pPacket,
1242 HTC_PACKET_QUEUE_DEPTH(tx_queue)));
1243
1244 transferLength = pPacket->ActualLength + HTC_HDR_LENGTH;
1245
1246 if (transferLength <= pEndpoint->TxCreditSize) {
1247 creditsRequired = 1;
1248 } else {
1249 /* figure out how many credits this message requires */
1250 creditsRequired =
1251 transferLength / pEndpoint->TxCreditSize;
1252 remainder = transferLength % pEndpoint->TxCreditSize;
1253
1254 if (remainder)
1255 creditsRequired++;
1256 }
1257
1258 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1259 (" Credits Required:%d Got:%d\n",
1260 creditsRequired, pEndpoint->TxCredits));
1261
1262 if (pEndpoint->Id == ENDPOINT_0) {
1263 /*
1264 * endpoint 0 is special, it always has a credit and
1265 * does not require credit based flow control
1266 */
1267 creditsRequired = 0;
1268 } else {
1269
1270 if (pEndpoint->TxCredits < creditsRequired) {
1271 #if DEBUG_CREDIT
1272 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
1273 ("EP%d,No Credit now.%d < %d\n",
1274 pEndpoint->Id,
1275 pEndpoint->TxCredits,
1276 creditsRequired));
1277 #endif
1278 if (do_pm_get) {
1279 hif_rtpm_put(HIF_RTPM_PUT_ASYNC,
1280 rtpm_code);
1281 htc_dec_wmi_runtime_cnt(target,
1282 rtpm_code);
1283 }
1284
1285 break;
1286 }
1287
1288 pEndpoint->TxCredits -= creditsRequired;
1289 INC_HTC_EP_STAT(pEndpoint, TxCreditsConsummed,
1290 creditsRequired);
1291
1292 /* check if we need credits back from the target */
1293 if (pEndpoint->TxCredits <=
1294 pEndpoint->TxCreditsPerMaxMsg) {
1295 /* tell the target we need credits ASAP! */
1296 sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
1297 if (pEndpoint->service_id == WMI_CONTROL_SVC) {
1298 htc_credit_record(HTC_REQUEST_CREDIT,
1299 pEndpoint->TxCredits,
1300 HTC_PACKET_QUEUE_DEPTH
1301 (tx_queue));
1302 hif_latency_detect_credit_record_time(
1303 HIF_REQUEST_CREDIT,
1304 target->hif_dev);
1305 }
1306 INC_HTC_EP_STAT(pEndpoint,
1307 TxCreditLowIndications, 1);
1308 #if DEBUG_CREDIT
1309 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
1310 (" EP%d Needs Credits\n",
1311 pEndpoint->Id));
1312 #endif
1313 }
1314 }
1315
1316 /* now we can fully dequeue */
1317 pPacket = htc_packet_dequeue(tx_queue);
1318 if (pPacket) {
1319 /* save the number of credits this packet consumed */
1320 pPacket->PktInfo.AsTx.CreditsUsed = creditsRequired;
1321 /* save send flags */
1322 pPacket->PktInfo.AsTx.SendFlags = sendFlags;
1323
1324 /* queue this packet into the caller's queue */
1325 HTC_PACKET_ENQUEUE(pQueue, pPacket);
1326 }
1327 }
1328
1329 if (!HTC_QUEUE_EMPTY(&pm_queue))
1330 queue_htc_pm_packets(pEndpoint, &pm_queue);
1331
1332 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1333 ("-get_htc_send_packets_credit_based\n"));
1334
1335 }
1336
get_htc_send_packets(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,HTC_PACKET_QUEUE * pQueue,int Resources)1337 static void get_htc_send_packets(HTC_TARGET *target,
1338 HTC_ENDPOINT *pEndpoint,
1339 HTC_PACKET_QUEUE *pQueue, int Resources)
1340 {
1341
1342 HTC_PACKET *pPacket;
1343 HTC_PACKET_QUEUE *tx_queue;
1344 HTC_PACKET_QUEUE pm_queue;
1345 bool do_pm_get = false;
1346 unsigned int rtpm_code = 0;
1347 int ret;
1348
1349 /*** NOTE : the TX lock is held when this function is called ***/
1350 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1351 ("+get_htc_send_packets %d resources\n", Resources));
1352
1353 INIT_HTC_PACKET_QUEUE(&pm_queue);
1354 extract_htc_pm_packets(pEndpoint, &pm_queue);
1355 if (HTC_QUEUE_EMPTY(&pm_queue)) {
1356 tx_queue = &pEndpoint->TxQueue;
1357 do_pm_get = true;
1358 } else {
1359 tx_queue = &pm_queue;
1360 }
1361
1362 /* loop until we can grab as many packets out of the queue as we can */
1363 while (Resources > 0) {
1364 int num_frags;
1365
1366 if (do_pm_get) {
1367 rtpm_code =
1368 htc_send_pkts_get_rtpm_id(
1369 pEndpoint->service_id);
1370 ret = hif_rtpm_get(HIF_RTPM_GET_ASYNC, rtpm_code);
1371 if (ret) {
1372 /* bus suspended, runtime resume issued */
1373 QDF_ASSERT(HTC_PACKET_QUEUE_DEPTH(pQueue) == 0);
1374 pPacket = htc_get_pkt_at_head(tx_queue);
1375 if (!pPacket ||
1376 (pPacket->Endpoint >= ENDPOINT_MAX) ||
1377 (pPacket->Endpoint <= ENDPOINT_UNUSED))
1378 break;
1379 log_packet_info(target, pPacket);
1380 break;
1381 }
1382 htc_inc_wmi_runtime_cnt(target, rtpm_code);
1383
1384 }
1385
1386 ret = hif_system_pm_state_check(target->hif_dev);
1387 if (ret) {
1388 if (do_pm_get) {
1389 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code);
1390 htc_dec_wmi_runtime_cnt(target, rtpm_code);
1391 }
1392 break;
1393 }
1394
1395 pPacket = htc_packet_dequeue(tx_queue);
1396 if (!pPacket) {
1397 if (do_pm_get) {
1398 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code);
1399 htc_dec_wmi_runtime_cnt(target, rtpm_code);
1400 }
1401 break;
1402 }
1403
1404 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1405 (" Got packet:%pK , New Queue Depth: %d\n",
1406 pPacket,
1407 HTC_PACKET_QUEUE_DEPTH(tx_queue)));
1408 /* For non-credit path the sequence number is already embedded
1409 * in the constructed HTC header
1410 */
1411 pPacket->PktInfo.AsTx.SendFlags = 0;
1412 pPacket->PktInfo.AsTx.CreditsUsed = 0;
1413 /* queue this packet into the caller's queue */
1414 HTC_PACKET_ENQUEUE(pQueue, pPacket);
1415
1416 /*
1417 * FIX THIS:
1418 * For now, avoid calling qdf_nbuf_get_num_frags before calling
1419 * qdf_nbuf_map, because the MacOS version of qdf_nbuf_t doesn't
1420 * support qdf_nbuf_get_num_frags until after qdf_nbuf_map has
1421 * been done.
1422 * Assume that the non-data netbufs, i.e. WMI message netbufs,
1423 * consist of a single fragment.
1424 */
1425 /* WMI messages are in a single-fragment network buf */
1426 num_frags =
1427 (pPacket->PktInfo.AsTx.
1428 Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) ? 1 :
1429 qdf_nbuf_get_num_frags(GET_HTC_PACKET_NET_BUF_CONTEXT
1430 (pPacket));
1431 Resources -= num_frags;
1432 }
1433
1434 if (!HTC_QUEUE_EMPTY(&pm_queue))
1435 queue_htc_pm_packets(pEndpoint, &pm_queue);
1436
1437 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-get_htc_send_packets\n"));
1438
1439 }
1440
1441 /**
1442 * htc_try_send() - Send packets in a queue on an endpoint
1443 * @target: HTC target on which packets need to be sent
1444 * @pEndpoint: logical endpoint on which packets needs to be sent
1445 * @pCallersSendQueue: packet queue containing the list of packets to be sent
1446 *
1447 * Return: enum HTC_SEND_QUEUE_RESULT indicates whether the packet was queued to
1448 * be sent or the packet should be dropped by the upper layer
1449 */
htc_try_send(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,HTC_PACKET_QUEUE * pCallersSendQueue)1450 static enum HTC_SEND_QUEUE_RESULT htc_try_send(HTC_TARGET *target,
1451 HTC_ENDPOINT *pEndpoint,
1452 HTC_PACKET_QUEUE *pCallersSendQueue)
1453 {
1454 /* temp queue to hold packets at various stages */
1455 HTC_PACKET_QUEUE sendQueue;
1456 HTC_PACKET *pPacket;
1457 int tx_resources;
1458 int overflow;
1459 enum HTC_SEND_QUEUE_RESULT result = HTC_SEND_QUEUE_OK;
1460 QDF_STATUS status;
1461
1462 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+htc_try_send (Queue:%pK Depth:%d)\n",
1463 pCallersSendQueue,
1464 (pCallersSendQueue ==
1465 NULL) ? 0 :
1466 HTC_PACKET_QUEUE_DEPTH
1467 (pCallersSendQueue)));
1468
1469 /* init the local send queue */
1470 INIT_HTC_PACKET_QUEUE(&sendQueue);
1471
1472 do {
1473
1474 /* caller didn't provide a queue, just wants us to check
1475 * queues and send
1476 */
1477 if (!pCallersSendQueue)
1478 break;
1479
1480 if (HTC_QUEUE_EMPTY(pCallersSendQueue)) {
1481 /* empty queue */
1482 OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target,
1483 HTC_PKT_Q_EMPTY);
1484 result = HTC_SEND_QUEUE_DROP;
1485 break;
1486 }
1487
1488 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) >=
1489 pEndpoint->MaxTxQueueDepth) {
1490 /* we've already overflowed */
1491 overflow = HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue);
1492 } else {
1493 /* figure out how much we will overflow by */
1494 overflow = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
1495 overflow += HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue);
1496 /* get how much we will overflow the TX queue by */
1497 overflow -= pEndpoint->MaxTxQueueDepth;
1498 }
1499
1500 /* if overflow is negative or zero, we are okay */
1501 if (overflow > 0) {
1502 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1503 ("Endpoint %d, TX queue will overflow :%d , Tx Depth:%d, Max:%d\n",
1504 pEndpoint->Id, overflow,
1505 HTC_PACKET_QUEUE_DEPTH(&pEndpoint->
1506 TxQueue),
1507 pEndpoint->MaxTxQueueDepth));
1508 }
1509 if ((overflow <= 0)
1510 || (!pEndpoint->EpCallBacks.EpSendFull)) {
1511 /* all packets will fit or caller did not provide send
1512 * full indication handler
1513 * just move all of them to local sendQueue object
1514 */
1515 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&sendQueue,
1516 pCallersSendQueue);
1517 } else {
1518 int i;
1519 int goodPkts =
1520 HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue) -
1521 overflow;
1522
1523 A_ASSERT(goodPkts >= 0);
1524 /* we have overflowed and callback is provided. Dequeue
1525 * all non-overflow packets into the sendqueue
1526 */
1527 for (i = 0; i < goodPkts; i++) {
1528 /* pop off caller's queue */
1529 pPacket = htc_packet_dequeue(pCallersSendQueue);
1530 A_ASSERT(pPacket);
1531 if (pPacket)
1532 /* insert into local queue */
1533 HTC_PACKET_ENQUEUE(&sendQueue,
1534 pPacket);
1535 }
1536
1537 /* the caller's queue has all the packets that won't fit
1538 * walk through the caller's queue and indicate each one
1539 * to the send full handler
1540 */
1541 ITERATE_OVER_LIST_ALLOW_REMOVE(&pCallersSendQueue->
1542 QueueHead, pPacket,
1543 HTC_PACKET, ListLink) {
1544
1545 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1546 ("Indicating overflowed TX packet: %pK\n",
1547 pPacket));
1548 /*
1549 * Remove headroom reserved for HTC_FRAME_HDR
1550 * before giving the packet back to the user via
1551 * the EpSendFull callback.
1552 */
1553 qdf_nbuf_pull_head
1554 (GET_HTC_PACKET_NET_BUF_CONTEXT
1555 (pPacket),
1556 sizeof(HTC_FRAME_HDR));
1557 pPacket->PktInfo.AsTx.Flags &=
1558 ~HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA;
1559
1560 if (pEndpoint->EpCallBacks.
1561 EpSendFull(pEndpoint->EpCallBacks.pContext,
1562 pPacket) == HTC_SEND_FULL_DROP) {
1563 /* callback wants the packet dropped */
1564 INC_HTC_EP_STAT(pEndpoint, TxDropped,
1565 1);
1566 /* leave this one in the caller's queue
1567 * for cleanup
1568 */
1569 } else {
1570 /* callback wants to keep this packet,
1571 * remove from caller's queue
1572 */
1573 HTC_PACKET_REMOVE(pCallersSendQueue,
1574 pPacket);
1575 /* put it in the send queue
1576 * add HTC_FRAME_HDR space reservation
1577 * again
1578 */
1579 qdf_nbuf_push_head
1580 (GET_HTC_PACKET_NET_BUF_CONTEXT
1581 (pPacket),
1582 sizeof(HTC_FRAME_HDR));
1583 pPacket->PktInfo.AsTx.Flags |=
1584 HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA;
1585
1586 HTC_PACKET_ENQUEUE(&sendQueue, pPacket);
1587 }
1588
1589 }
1590 ITERATE_END;
1591
1592 if (HTC_QUEUE_EMPTY(&sendQueue)) {
1593 /* no packets made it in, caller will cleanup */
1594 OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target,
1595 HTC_SEND_Q_EMPTY);
1596 result = HTC_SEND_QUEUE_DROP;
1597 break;
1598 }
1599 }
1600
1601 } while (false);
1602
1603 if (result != HTC_SEND_QUEUE_OK) {
1604 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send: %d\n",
1605 result));
1606 return result;
1607 }
1608
1609 LOCK_HTC_TX(target);
1610
1611 if (!HTC_QUEUE_EMPTY(&sendQueue)) {
1612 if (target->is_nodrop_pkt) {
1613 /*
1614 * nodrop pkts have higher priority than normal pkts,
1615 * insert nodrop pkt to head for proper
1616 * start/termination of test.
1617 */
1618 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue,
1619 &sendQueue);
1620 target->is_nodrop_pkt = false;
1621 } else {
1622 /* transfer packets to tail */
1623 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->TxQueue,
1624 &sendQueue);
1625 A_ASSERT(HTC_QUEUE_EMPTY(&sendQueue));
1626 INIT_HTC_PACKET_QUEUE(&sendQueue);
1627 }
1628 }
1629
1630 /* increment tx processing count on entry */
1631 if (qdf_atomic_inc_return(&pEndpoint->TxProcessCount) > 1) {
1632 /* another thread or task is draining the TX queues on this
1633 * endpoint that thread will reset the tx processing count when
1634 * the queue is drained
1635 */
1636 qdf_atomic_dec(&pEndpoint->TxProcessCount);
1637 UNLOCK_HTC_TX(target);
1638 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send (busy)\n"));
1639 return HTC_SEND_QUEUE_OK;
1640 }
1641
1642 /***** beyond this point only 1 thread may enter ******/
1643
1644 /* now drain the endpoint TX queue for transmission as long as we have
1645 * enough transmit resources
1646 */
1647 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
1648 tx_resources =
1649 hif_get_free_queue_number(target->hif_dev,
1650 pEndpoint->UL_PipeID);
1651 } else {
1652 tx_resources = 0;
1653 }
1654
1655 while (true) {
1656
1657 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) == 0)
1658 break;
1659
1660 if (pEndpoint->async_update &&
1661 (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) &&
1662 (!tx_resources)) {
1663 hif_schedule_ce_tasklet(target->hif_dev,
1664 pEndpoint->UL_PipeID);
1665 break;
1666 }
1667
1668 if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
1669 #if DEBUG_CREDIT
1670 int cred = pEndpoint->TxCredits;
1671 #endif
1672 /* credit based mechanism provides flow control based on
1673 * target transmit resource availability, we assume that
1674 * the HIF layer will always have bus resources greater
1675 * than target transmit resources
1676 */
1677 get_htc_send_packets_credit_based(target, pEndpoint,
1678 &sendQueue);
1679 #if DEBUG_CREDIT
1680 if (ep_debug_mask & (1 << pEndpoint->Id)) {
1681 if (cred - pEndpoint->TxCredits > 0) {
1682 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
1683 (" <HTC> Decrease EP%d %d - %d = %d credits.\n",
1684 pEndpoint->Id, cred,
1685 cred -
1686 pEndpoint->TxCredits,
1687 pEndpoint->TxCredits));
1688 }
1689 }
1690 #endif
1691 } else {
1692
1693 /*
1694 * Header and payload belongs to the different fragments and
1695 * consume 2 resource for one HTC package but USB combine into
1696 * one transfer.And one WMI message only consumes one single
1697 * resource.
1698 */
1699 if (HTC_TX_BUNDLE_ENABLED(target) && tx_resources &&
1700 hif_get_bus_type(target->hif_dev) ==
1701 QDF_BUS_TYPE_USB) {
1702 if (pEndpoint->service_id ==
1703 WMI_CONTROL_SVC)
1704 tx_resources =
1705 HTC_MAX_MSG_PER_BUNDLE_TX;
1706 else
1707 tx_resources =
1708 (HTC_MAX_MSG_PER_BUNDLE_TX * 2);
1709 }
1710 /* get all the packets for this endpoint that we can for
1711 * this pass
1712 */
1713 get_htc_send_packets(target, pEndpoint, &sendQueue,
1714 tx_resources);
1715 }
1716
1717 if (HTC_PACKET_QUEUE_DEPTH(&sendQueue) == 0) {
1718 /* didn't get any packets due to a lack of resources or
1719 * TX queue was drained
1720 */
1721 break;
1722 }
1723
1724 if (!pEndpoint->async_update)
1725 UNLOCK_HTC_TX(target);
1726
1727 /* send what we can */
1728 status = htc_issue_packets(target, pEndpoint, &sendQueue);
1729 if (status) {
1730 int i;
1731 unsigned int rtpm_code;
1732
1733 result = HTC_SEND_QUEUE_DROP;
1734
1735 switch (status) {
1736 case QDF_STATUS_E_RESOURCES:
1737 if (pEndpoint->num_requeues_warn <= MAX_REQUEUE_WARN) {
1738 pEndpoint->num_requeues_warn++;
1739 pEndpoint->total_num_requeues++;
1740 break;
1741 } else {
1742 pEndpoint->total_num_requeues++;
1743 pEndpoint->num_requeues_warn = 0;
1744 }
1745 fallthrough;
1746 default:
1747 QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO,
1748 "htc_issue_packets, failed status:%d"
1749 "endpoint:%d, put it back to head of"
1750 "callersSendQueue", result, pEndpoint->Id);
1751 break;
1752 }
1753
1754 rtpm_code = htc_send_pkts_get_rtpm_id(
1755 pEndpoint->service_id);
1756 for (i = HTC_PACKET_QUEUE_DEPTH(&sendQueue); i > 0; i--) {
1757 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code);
1758 htc_dec_wmi_runtime_cnt(target, rtpm_code);
1759 }
1760
1761 if (!pEndpoint->async_update) {
1762 LOCK_HTC_TX(target);
1763 }
1764 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue,
1765 &sendQueue);
1766 break;
1767 } else {
1768 if (pEndpoint->num_requeues_warn)
1769 pEndpoint->num_requeues_warn = 0;
1770 }
1771
1772 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
1773 tx_resources =
1774 hif_get_free_queue_number(target->hif_dev,
1775 pEndpoint->UL_PipeID);
1776 }
1777
1778 if (!pEndpoint->async_update) {
1779 LOCK_HTC_TX(target);
1780 }
1781
1782 }
1783
1784 /* done with this endpoint, we can clear the count */
1785 qdf_atomic_init(&pEndpoint->TxProcessCount);
1786
1787 UNLOCK_HTC_TX(target);
1788
1789 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send:\n"));
1790
1791 return HTC_SEND_QUEUE_OK;
1792 }
1793
1794 #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED
htc_send_pkts_sched_check(HTC_HANDLE HTCHandle,HTC_ENDPOINT_ID id)1795 static uint16_t htc_send_pkts_sched_check(HTC_HANDLE HTCHandle,
1796 HTC_ENDPOINT_ID id)
1797 {
1798 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1799 HTC_ENDPOINT *pEndpoint;
1800 HTC_ENDPOINT_ID eid;
1801 HTC_PACKET_QUEUE *pTxQueue;
1802 uint16_t resources;
1803 uint16_t acQueueStatus[DATA_EP_SIZE] = { 0, 0, 0, 0 };
1804
1805 if (id < ENDPOINT_2 || id > ENDPOINT_5)
1806 return 1;
1807
1808 for (eid = ENDPOINT_2; eid <= ENDPOINT_5; eid++) {
1809 pEndpoint = &target->endpoint[eid];
1810 pTxQueue = &pEndpoint->TxQueue;
1811
1812 if (HTC_QUEUE_EMPTY(pTxQueue))
1813 acQueueStatus[eid - 2] = 1;
1814 }
1815
1816 switch (id) {
1817 case ENDPOINT_2: /* BE */
1818 return acQueueStatus[0] && acQueueStatus[2]
1819 && acQueueStatus[3];
1820 case ENDPOINT_3: /* BK */
1821 return acQueueStatus[0] && acQueueStatus[1] && acQueueStatus[2]
1822 && acQueueStatus[3];
1823 case ENDPOINT_4: /* VI */
1824 return acQueueStatus[2] && acQueueStatus[3];
1825 case ENDPOINT_5: /* VO */
1826 return acQueueStatus[3];
1827 default:
1828 return 0;
1829 }
1830
1831 }
1832
htc_send_pkts_sched_queue(HTC_TARGET * target,HTC_PACKET_QUEUE * pPktQueue,HTC_ENDPOINT_ID eid)1833 static A_STATUS htc_send_pkts_sched_queue(HTC_TARGET *target,
1834 HTC_PACKET_QUEUE *pPktQueue,
1835 HTC_ENDPOINT_ID eid)
1836 {
1837 HTC_ENDPOINT *pEndpoint;
1838 HTC_PACKET_QUEUE *pTxQueue;
1839 HTC_PACKET *pPacket;
1840 int goodPkts;
1841
1842 pEndpoint = &target->endpoint[eid];
1843 pTxQueue = &pEndpoint->TxQueue;
1844
1845 LOCK_HTC_TX(target);
1846
1847 goodPkts =
1848 pEndpoint->MaxTxQueueDepth -
1849 HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
1850
1851 if (goodPkts > 0) {
1852 while (!HTC_QUEUE_EMPTY(pPktQueue)) {
1853 pPacket = htc_packet_dequeue(pPktQueue);
1854 HTC_PACKET_ENQUEUE(pTxQueue, pPacket);
1855 goodPkts--;
1856
1857 if (goodPkts <= 0)
1858 break;
1859 }
1860 }
1861
1862 if (HTC_PACKET_QUEUE_DEPTH(pPktQueue)) {
1863 ITERATE_OVER_LIST_ALLOW_REMOVE(&pPktQueue->QueueHead, pPacket,
1864 HTC_PACKET, ListLink) {
1865
1866 if (pEndpoint->EpCallBacks.
1867 EpSendFull(pEndpoint->EpCallBacks.pContext,
1868 pPacket) == HTC_SEND_FULL_DROP) {
1869 INC_HTC_EP_STAT(pEndpoint, TxDropped, 1);
1870 } else {
1871 HTC_PACKET_REMOVE(pPktQueue, pPacket);
1872 HTC_PACKET_ENQUEUE(pTxQueue, pPacket);
1873 }
1874 }
1875 ITERATE_END;
1876 }
1877
1878 UNLOCK_HTC_TX(target);
1879
1880 return A_OK;
1881 }
1882
1883 #endif
1884
__htc_send_pkt(HTC_HANDLE HTCHandle,HTC_PACKET * pPacket)1885 static inline QDF_STATUS __htc_send_pkt(HTC_HANDLE HTCHandle,
1886 HTC_PACKET *pPacket)
1887 {
1888 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1889 HTC_ENDPOINT *pEndpoint;
1890 HTC_PACKET_QUEUE pPktQueue;
1891 qdf_nbuf_t netbuf;
1892 HTC_FRAME_HDR *htc_hdr;
1893 QDF_STATUS status;
1894
1895 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1896 ("+__htc_send_pkt\n"));
1897
1898 /* get packet at head to figure out which endpoint these packets will
1899 * go into
1900 */
1901 if (!pPacket) {
1902 OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, GET_HTC_PKT_Q_FAIL);
1903 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-__htc_send_pkt\n"));
1904 return QDF_STATUS_E_INVAL;
1905 }
1906
1907 if ((pPacket->Endpoint >= ENDPOINT_MAX) ||
1908 (pPacket->Endpoint <= ENDPOINT_UNUSED)) {
1909 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1910 ("%s endpoint is invalid\n", __func__));
1911 AR_DEBUG_ASSERT(0);
1912 return QDF_STATUS_E_INVAL;
1913 }
1914 pEndpoint = &target->endpoint[pPacket->Endpoint];
1915
1916 if (!pEndpoint->service_id) {
1917 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s service_id is invalid\n",
1918 __func__));
1919 return QDF_STATUS_E_INVAL;
1920 }
1921
1922 #ifdef HTC_EP_STAT_PROFILING
1923 LOCK_HTC_TX(target);
1924 INC_HTC_EP_STAT(pEndpoint, TxPosted, 1);
1925 UNLOCK_HTC_TX(target);
1926 #endif
1927
1928 /* provide room in each packet's netbuf for the HTC frame header */
1929 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
1930 AR_DEBUG_ASSERT(netbuf);
1931 if (!netbuf)
1932 return QDF_STATUS_E_INVAL;
1933
1934 qdf_nbuf_push_head(netbuf, sizeof(HTC_FRAME_HDR));
1935 pPacket->PktInfo.AsTx.Flags |=
1936 HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA;
1937 /* setup HTC frame header */
1938 htc_hdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr(netbuf, 0);
1939 AR_DEBUG_ASSERT(htc_hdr);
1940 if (!htc_hdr)
1941 return QDF_STATUS_E_INVAL;
1942
1943 HTC_WRITE32(htc_hdr,
1944 SM(pPacket->ActualLength,
1945 HTC_FRAME_HDR_PAYLOADLEN) |
1946 SM(pPacket->Endpoint,
1947 HTC_FRAME_HDR_ENDPOINTID));
1948 LOCK_HTC_TX(target);
1949
1950 pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo;
1951 pEndpoint->SeqNo++;
1952
1953 HTC_WRITE32(((uint32_t *)htc_hdr) + 1,
1954 SM(pPacket->PktInfo.AsTx.SeqNo,
1955 HTC_FRAME_HDR_CONTROLBYTES1));
1956
1957 UNLOCK_HTC_TX(target);
1958
1959 /*
1960 * For flow control enabled endpoints mapping is done in
1961 * htc_issue_packets and for non flow control enabled endpoints
1962 * its done here.
1963 */
1964 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
1965 pPacket->PktInfo.AsTx.Flags |= HTC_TX_PACKET_FLAG_FIXUP_NETBUF;
1966 status = qdf_nbuf_map(target->osdev,
1967 GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket),
1968 QDF_DMA_TO_DEVICE);
1969 if (status == QDF_STATUS_SUCCESS) {
1970 target->nbuf_nfc_map_count++;
1971 } else {
1972 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
1973 ("%s: nbuf map failed, endpoint %pK, seq_no. %d\n",
1974 __func__, pEndpoint, pEndpoint->SeqNo));
1975 return status;
1976 }
1977 }
1978
1979 INIT_HTC_PACKET_QUEUE_AND_ADD(&pPktQueue, pPacket);
1980 #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED
1981 if (!htc_send_pkts_sched_check(HTCHandle, pEndpoint->Id))
1982 htc_send_pkts_sched_queue(HTCHandle, &pPktQueue, pEndpoint->Id);
1983 else
1984 htc_try_send(target, pEndpoint, &pPktQueue);
1985 #else
1986 htc_try_send(target, pEndpoint, &pPktQueue);
1987 #endif
1988
1989 /* do completion on any packets that couldn't get in */
1990 while (!HTC_QUEUE_EMPTY(&pPktQueue)) {
1991 pPacket = htc_packet_dequeue(&pPktQueue);
1992
1993 if (HTC_STOPPING(target))
1994 pPacket->Status = QDF_STATUS_E_CANCELED;
1995 else
1996 pPacket->Status = QDF_STATUS_E_RESOURCES;
1997
1998 send_packet_completion(target, pPacket);
1999 }
2000
2001 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-__htc_send_pkt\n"));
2002
2003 return QDF_STATUS_SUCCESS;
2004 }
2005
2006 #ifdef CUSTOM_CB_SCHEDULER_SUPPORT
2007 /**
2008 * htc_get_endpoint_ul_pipeid() - Helper API to get uplink pipe ID
2009 * @htc_handle: HTC handle
2010 * @endpoint_id: Endpoint ID
2011 * @ul_pipeid: Pointer to uplink pipe ID
2012 *
2013 * return: QDF_STATUS
2014 */
2015 static QDF_STATUS
htc_get_endpoint_ul_pipeid(HTC_HANDLE htc_handle,HTC_ENDPOINT_ID endpoint_id,uint8_t * ul_pipeid)2016 htc_get_endpoint_ul_pipeid(HTC_HANDLE htc_handle, HTC_ENDPOINT_ID endpoint_id,
2017 uint8_t *ul_pipeid)
2018 {
2019 HTC_TARGET *target;
2020 HTC_ENDPOINT *end_point;
2021
2022 if (!htc_handle) {
2023 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
2024 ("%s: HTCHandle is NULL\n", __func__));
2025 return QDF_STATUS_E_NULL_VALUE;
2026 }
2027 target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
2028
2029 if (endpoint_id >= ENDPOINT_MAX || endpoint_id <= ENDPOINT_UNUSED) {
2030 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
2031 ("%s endpoint is invalid\n", __func__));
2032 AR_DEBUG_ASSERT(0);
2033 return QDF_STATUS_E_INVAL;
2034 }
2035 end_point = &target->endpoint[endpoint_id];
2036
2037 if (!end_point->service_id) {
2038 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s service_id is invalid\n",
2039 __func__));
2040 return QDF_STATUS_E_INVAL;
2041 }
2042
2043 *ul_pipeid = end_point->UL_PipeID;
2044
2045 return QDF_STATUS_SUCCESS;
2046 }
2047
2048 QDF_STATUS
htc_register_custom_cb(HTC_HANDLE htc_handle,HTC_ENDPOINT_ID endpoint_id,void (* custom_cb)(void *),void * custom_cb_context)2049 htc_register_custom_cb(HTC_HANDLE htc_handle, HTC_ENDPOINT_ID endpoint_id,
2050 void (*custom_cb)(void *), void *custom_cb_context)
2051 {
2052 QDF_STATUS status = QDF_STATUS_SUCCESS;
2053 uint8_t ul_pipeid;
2054
2055 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+%s\n", __func__));
2056
2057 status = htc_get_endpoint_ul_pipeid(htc_handle, endpoint_id,
2058 &ul_pipeid);
2059 if (QDF_IS_STATUS_ERROR(status)) {
2060 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s Failed to get ul pipeid\n",
2061 __func__));
2062 goto exit;
2063 }
2064
2065 status = hif_register_ce_custom_cb(htc_get_hif_device(htc_handle),
2066 ul_pipeid, custom_cb,
2067 custom_cb_context);
2068 if (QDF_IS_STATUS_ERROR(status)) {
2069 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s Failed to register cb\n",
2070 __func__));
2071 goto exit;
2072 }
2073
2074 exit:
2075 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-%s\n", __func__));
2076
2077 return status;
2078 }
2079
2080 QDF_STATUS
htc_unregister_custom_cb(HTC_HANDLE htc_handle,HTC_ENDPOINT_ID endpoint_id)2081 htc_unregister_custom_cb(HTC_HANDLE htc_handle, HTC_ENDPOINT_ID endpoint_id)
2082 {
2083 QDF_STATUS status = QDF_STATUS_SUCCESS;
2084 uint8_t ul_pipeid;
2085
2086 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+%s\n", __func__));
2087
2088 status = htc_get_endpoint_ul_pipeid(htc_handle, endpoint_id,
2089 &ul_pipeid);
2090 if (QDF_IS_STATUS_ERROR(status)) {
2091 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s Failed to get ul pipeid\n",
2092 __func__));
2093 goto exit;
2094 }
2095
2096 status = hif_unregister_ce_custom_cb(htc_get_hif_device(htc_handle),
2097 ul_pipeid);
2098 if (QDF_IS_STATUS_ERROR(status)) {
2099 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s Failed to unregister cb\n",
2100 __func__));
2101 status = QDF_STATUS_E_INVAL;
2102 goto exit;
2103 }
2104
2105 exit:
2106 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-%s\n", __func__));
2107
2108 return status;
2109 }
2110
2111 QDF_STATUS
htc_enable_custom_cb(HTC_HANDLE htc_handle,HTC_ENDPOINT_ID endpoint_id)2112 htc_enable_custom_cb(HTC_HANDLE htc_handle, HTC_ENDPOINT_ID endpoint_id)
2113 {
2114 QDF_STATUS status = QDF_STATUS_SUCCESS;
2115 uint8_t ul_pipeid;
2116
2117 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+%s\n", __func__));
2118
2119 status = htc_get_endpoint_ul_pipeid(htc_handle, endpoint_id,
2120 &ul_pipeid);
2121 if (QDF_IS_STATUS_ERROR(status)) {
2122 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s Failed to get ul pipeid\n",
2123 __func__));
2124 goto exit;
2125 }
2126
2127 status = hif_enable_ce_custom_cb(htc_get_hif_device(htc_handle),
2128 ul_pipeid);
2129 if (QDF_IS_STATUS_ERROR(status)) {
2130 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s Failed to enable cb\n",
2131 __func__));
2132 status = QDF_STATUS_E_INVAL;
2133 goto exit;
2134 }
2135
2136 exit:
2137 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-%s\n", __func__));
2138
2139 return status;
2140 }
2141
2142 QDF_STATUS
htc_disable_custom_cb(HTC_HANDLE htc_handle,HTC_ENDPOINT_ID endpoint_id)2143 htc_disable_custom_cb(HTC_HANDLE htc_handle, HTC_ENDPOINT_ID endpoint_id)
2144 {
2145 QDF_STATUS status = QDF_STATUS_SUCCESS;
2146 uint8_t ul_pipeid;
2147
2148 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+%s\n", __func__));
2149
2150 status = htc_get_endpoint_ul_pipeid(htc_handle, endpoint_id,
2151 &ul_pipeid);
2152 if (QDF_IS_STATUS_ERROR(status)) {
2153 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s Failed to get ul pipeid\n",
2154 __func__));
2155 goto exit;
2156 }
2157
2158 status = hif_disable_ce_custom_cb(htc_get_hif_device(htc_handle),
2159 ul_pipeid);
2160 if (QDF_IS_STATUS_ERROR(status)) {
2161 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s Failed to disable cb\n",
2162 __func__));
2163 status = QDF_STATUS_E_INVAL;
2164 goto exit;
2165 }
2166
2167 exit:
2168 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-%s\n", __func__));
2169
2170 return status;
2171 }
2172 #endif /* CUSTOM_CB_SCHEDULER_SUPPORT */
2173
2174 /* HTC API - htc_send_pkt */
htc_send_pkt(HTC_HANDLE htc_handle,HTC_PACKET * htc_packet)2175 QDF_STATUS htc_send_pkt(HTC_HANDLE htc_handle, HTC_PACKET *htc_packet)
2176 {
2177 if (!htc_handle) {
2178 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
2179 ("%s: HTCHandle is NULL \n", __func__));
2180 return QDF_STATUS_E_FAILURE;
2181 }
2182
2183 if (!htc_packet) {
2184 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
2185 ("%s: pPacket is NULL \n", __func__));
2186 return QDF_STATUS_E_FAILURE;
2187 }
2188
2189 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
2190 ("+-htc_send_pkt: Enter endPointId: %d, buffer: %pK, length: %d\n",
2191 htc_packet->Endpoint, htc_packet->pBuffer,
2192 htc_packet->ActualLength));
2193 return __htc_send_pkt(htc_handle, htc_packet);
2194 }
2195 qdf_export_symbol(htc_send_pkt);
2196
2197 #ifdef ATH_11AC_TXCOMPACT
2198 /**
2199 * htc_send_data_pkt() - send single data packet on an endpoint
2200 * @htc_hdl: pointer to HTC handle
2201 * @netbuf: network buffer containing the data to be sent
2202 * @ep_id: endpoint identifier
2203 * @actual_length: length of data that needs to be transmitted
2204 *
2205 * Return: QDF_STATUS_SUCCESS for success or an appropriate QDF_STATUS error
2206 */
htc_send_data_pkt(HTC_HANDLE htc_hdl,qdf_nbuf_t netbuf,int ep_id,int actual_length)2207 QDF_STATUS htc_send_data_pkt(HTC_HANDLE htc_hdl, qdf_nbuf_t netbuf, int ep_id,
2208 int actual_length)
2209 {
2210 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_hdl);
2211 HTC_ENDPOINT *pEndpoint;
2212 HTC_FRAME_HDR *p_htc_hdr;
2213 QDF_STATUS status = QDF_STATUS_SUCCESS;
2214 int tx_resources;
2215 uint32_t data_attr = 0;
2216 int htc_payload_len = actual_length;
2217 unsigned int rtpm_code;
2218
2219 pEndpoint = &target->endpoint[ep_id];
2220
2221 tx_resources = hif_get_free_queue_number(target->hif_dev,
2222 pEndpoint->UL_PipeID);
2223
2224 if (tx_resources < HTC_DATA_RESOURCE_THRS) {
2225 if (pEndpoint->ul_is_polled) {
2226 hif_send_complete_check(pEndpoint->target->hif_dev,
2227 pEndpoint->UL_PipeID, 1);
2228 tx_resources =
2229 hif_get_free_queue_number(target->hif_dev,
2230 pEndpoint->UL_PipeID);
2231 }
2232 if (tx_resources < HTC_DATA_MINDESC_PERPACKET)
2233 return QDF_STATUS_E_FAILURE;
2234 }
2235
2236 rtpm_code = htc_send_pkts_get_rtpm_id(
2237 pEndpoint->service_id);
2238 if (hif_rtpm_get(HIF_RTPM_GET_ASYNC, rtpm_code))
2239 return QDF_STATUS_E_FAILURE;
2240
2241 p_htc_hdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr(netbuf, 0);
2242 AR_DEBUG_ASSERT(p_htc_hdr);
2243
2244 data_attr = qdf_nbuf_data_attr_get(netbuf);
2245
2246 if (target->htc_hdr_length_check)
2247 htc_payload_len = actual_length - HTC_HEADER_LEN;
2248
2249 HTC_WRITE32(p_htc_hdr, SM(htc_payload_len, HTC_FRAME_HDR_PAYLOADLEN)
2250 | SM(ep_id, HTC_FRAME_HDR_ENDPOINTID));
2251 /*
2252 * If the HIF pipe for the data endpoint is polled rather than
2253 * interrupt-driven, this is a good point to check whether any
2254 * data previously sent through the HIF pipe have finished being
2255 * sent.
2256 * Since this may result in callbacks to htc_tx_completion_handler,
2257 * which can take the HTC tx lock, make the hif_send_complete_check
2258 * call before acquiring the HTC tx lock.
2259 * Call hif_send_complete_check directly, rather than calling
2260 * htc_send_complete_check, and call the PollTimerStart separately
2261 * after calling hif_send_head, so the timer will be started to
2262 * check for completion of the new outstanding download (in the
2263 * unexpected event that other polling calls don't catch it).
2264 */
2265
2266 LOCK_HTC_TX(target);
2267
2268 HTC_WRITE32(((uint32_t *)p_htc_hdr) + 1,
2269 SM(pEndpoint->SeqNo, HTC_FRAME_HDR_CONTROLBYTES1));
2270
2271 pEndpoint->SeqNo++;
2272
2273 QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_HTC);
2274 DPTRACE(qdf_dp_trace(netbuf, QDF_DP_TRACE_HTC_PACKET_PTR_RECORD,
2275 QDF_TRACE_DEFAULT_PDEV_ID, qdf_nbuf_data_addr(netbuf),
2276 sizeof(qdf_nbuf_data(netbuf)), QDF_TX));
2277 status = hif_send_head(target->hif_dev,
2278 pEndpoint->UL_PipeID,
2279 pEndpoint->Id, actual_length, netbuf, data_attr);
2280
2281 UNLOCK_HTC_TX(target);
2282 return status;
2283 }
2284 #else /*ATH_11AC_TXCOMPACT */
2285
2286 /**
2287 * htc_send_data_pkt() - htc_send_data_pkt
2288 * @HTCHandle: pointer to HTC handle
2289 * @pPacket: pointer to HTC_PACKET
2290 * @more_data: indicates whether more data is to follow
2291 *
2292 * Return: QDF_STATUS_SUCCESS for success or an appropriate QDF_STATUS error
2293 */
htc_send_data_pkt(HTC_HANDLE HTCHandle,HTC_PACKET * pPacket,uint8_t more_data)2294 QDF_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket,
2295 uint8_t more_data)
2296 {
2297 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
2298 HTC_ENDPOINT *pEndpoint;
2299 HTC_FRAME_HDR *pHtcHdr;
2300 HTC_PACKET_QUEUE sendQueue;
2301 qdf_nbuf_t netbuf = NULL;
2302 int tx_resources;
2303 QDF_STATUS status = QDF_STATUS_SUCCESS;
2304 uint32_t data_attr = 0;
2305 bool used_extra_tx_credit = false;
2306
2307 if (pPacket) {
2308 if ((pPacket->Endpoint >= ENDPOINT_MAX) ||
2309 (pPacket->Endpoint <= ENDPOINT_UNUSED)) {
2310 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
2311 ("%s endpoint is invalid\n", __func__));
2312 AR_DEBUG_ASSERT(0);
2313 return QDF_STATUS_E_INVAL;
2314 }
2315 pEndpoint = &target->endpoint[pPacket->Endpoint];
2316
2317 /* add HTC_FRAME_HDR in the initial fragment */
2318 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
2319 pHtcHdr = (HTC_FRAME_HDR *) qdf_nbuf_get_frag_vaddr(netbuf, 0);
2320 AR_DEBUG_ASSERT(pHtcHdr);
2321
2322 HTC_WRITE32(pHtcHdr,
2323 SM(pPacket->ActualLength,
2324 HTC_FRAME_HDR_PAYLOADLEN) |
2325 SM(pPacket->PktInfo.AsTx.SendFlags,
2326 HTC_FRAME_HDR_FLAGS) |
2327 SM(pPacket->Endpoint,
2328 HTC_FRAME_HDR_ENDPOINTID));
2329 /*
2330 * If the HIF pipe for the data endpoint is polled rather than
2331 * interrupt-driven, this is a good point to check whether any
2332 * data previously sent through the HIF pipe have finished being
2333 * sent. Since this may result in callbacks to
2334 * htc_tx_completion_handler, which can take the HTC tx lock,
2335 * make the hif_send_complete_check call before acquiring the
2336 * HTC tx lock.
2337 * Call hif_send_complete_check directly, rather than calling
2338 * htc_send_complete_check, and call the PollTimerStart
2339 * separately after calling hif_send_head, so the timer will be
2340 * started to check for completion of the new outstanding
2341 * download (in the unexpected event that other polling calls
2342 * don't catch it).
2343 */
2344 if (pEndpoint->ul_is_polled) {
2345 htc_send_complete_poll_timer_stop(pEndpoint);
2346 hif_send_complete_check(pEndpoint->target->hif_dev,
2347 pEndpoint->UL_PipeID, 0);
2348 }
2349
2350 LOCK_HTC_TX(target);
2351
2352 pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo;
2353 pEndpoint->SeqNo++;
2354
2355 HTC_WRITE32(((uint32_t *) pHtcHdr) + 1,
2356 SM(pPacket->PktInfo.AsTx.SeqNo,
2357 HTC_FRAME_HDR_CONTROLBYTES1));
2358
2359 /* append new packet to pEndpoint->TxQueue */
2360 HTC_PACKET_ENQUEUE(&pEndpoint->TxQueue, pPacket);
2361 if (HTC_TX_BUNDLE_ENABLED(target) && (more_data)) {
2362 UNLOCK_HTC_TX(target);
2363 return QDF_STATUS_SUCCESS;
2364 }
2365
2366 QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_HTC);
2367 DPTRACE(qdf_dp_trace(netbuf, QDF_DP_TRACE_HTC_PACKET_PTR_RECORD,
2368 QDF_TRACE_DEFAULT_PDEV_ID, qdf_nbuf_data_addr(netbuf),
2369 sizeof(qdf_nbuf_data(netbuf)), QDF_TX));
2370 } else {
2371 LOCK_HTC_TX(target);
2372 pEndpoint = &target->endpoint[1];
2373 }
2374
2375 /* increment tx processing count on entry */
2376 qdf_atomic_inc(&pEndpoint->TxProcessCount);
2377 if (qdf_atomic_read(&pEndpoint->TxProcessCount) > 1) {
2378 /*
2379 * Another thread or task is draining the TX queues on this
2380 * endpoint. That thread will reset the tx processing count when
2381 * the queue is drained.
2382 */
2383 qdf_atomic_dec(&pEndpoint->TxProcessCount);
2384 UNLOCK_HTC_TX(target);
2385 return QDF_STATUS_SUCCESS;
2386 }
2387
2388 /***** beyond this point only 1 thread may enter ******/
2389
2390 INIT_HTC_PACKET_QUEUE(&sendQueue);
2391 if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
2392 #if DEBUG_CREDIT
2393 int cred = pEndpoint->TxCredits;
2394 #endif
2395 get_htc_send_packets_credit_based(target, pEndpoint,
2396 &sendQueue);
2397 #if DEBUG_CREDIT
2398 if (ep_debug_mask & (1 << pEndpoint->Id)) {
2399 if (cred - pEndpoint->TxCredits > 0) {
2400 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
2401 (" <HTC> Decrease EP%d %d - %d = %d credits.\n",
2402 pEndpoint->Id, cred,
2403 cred - pEndpoint->TxCredits,
2404 pEndpoint->TxCredits));
2405 }
2406 }
2407 #endif
2408 UNLOCK_HTC_TX(target);
2409 }
2410
2411 else if (HTC_TX_BUNDLE_ENABLED(target)) {
2412 if (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB) {
2413 if (hif_get_free_queue_number(target->hif_dev,
2414 pEndpoint->UL_PipeID))
2415 /*
2416 * Header and payload belongs to the different
2417 * fragments and consume 2 resource for one HTC
2418 * package but USB combine into one transfer.
2419 */
2420 get_htc_send_packets(target, pEndpoint,
2421 &sendQueue,
2422 HTC_MAX_MSG_PER_BUNDLE_TX
2423 * 2);
2424 } else {
2425 /* Dequeue max packets from endpoint tx queue */
2426 get_htc_send_packets(target, pEndpoint, &sendQueue,
2427 HTC_MAX_TX_BUNDLE_SEND_LIMIT);
2428 }
2429 UNLOCK_HTC_TX(target);
2430 } else {
2431 /*
2432 * Now drain the endpoint TX queue for transmission as long as
2433 * we have enough transmit resources
2434 */
2435 tx_resources =
2436 hif_get_free_queue_number(target->hif_dev,
2437 pEndpoint->UL_PipeID);
2438 get_htc_send_packets(target, pEndpoint, &sendQueue,
2439 tx_resources);
2440 UNLOCK_HTC_TX(target);
2441 }
2442
2443 /* send what we can */
2444 while (true) {
2445 if (HTC_TX_BUNDLE_ENABLED(target) &&
2446 (HTC_PACKET_QUEUE_DEPTH(&sendQueue) >=
2447 HTC_MIN_MSG_PER_BUNDLE) &&
2448 (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_SDIO ||
2449 hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB)) {
2450 if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
2451 if (htc_tx_pad_credit_avail(pEndpoint) < 1) {
2452 status = QDF_STATUS_E_RESOURCES;
2453 /* put the sendQueue back at the front
2454 * of pEndpoint->TxQueue
2455 */
2456 LOCK_HTC_TX(target);
2457 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(
2458 &pEndpoint->TxQueue,
2459 &sendQueue);
2460 UNLOCK_HTC_TX(target);
2461 break;
2462 }
2463 }
2464 htc_issue_packets_bundle(target, pEndpoint, &sendQueue);
2465 }
2466 if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
2467 if (htc_tx_pad_credit_avail(pEndpoint) < 1) {
2468 status = QDF_STATUS_E_RESOURCES;
2469 /* put the sendQueue back at the front
2470 * of pEndpoint->TxQueue
2471 */
2472 LOCK_HTC_TX(target);
2473 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(
2474 &pEndpoint->TxQueue,
2475 &sendQueue);
2476 UNLOCK_HTC_TX(target);
2477 break;
2478 }
2479 }
2480 pPacket = htc_packet_dequeue(&sendQueue);
2481 if (!pPacket)
2482 break;
2483 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
2484 pHtcHdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr(netbuf, 0);
2485
2486 LOCK_HTC_TX(target);
2487 /* store in look up queue to match completions */
2488 HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacket);
2489 INC_HTC_EP_STAT(pEndpoint, TxIssued, 1);
2490 pEndpoint->ul_outstanding_cnt++;
2491 UNLOCK_HTC_TX(target);
2492
2493 used_extra_tx_credit =
2494 htc_handle_extra_tx_credit(pEndpoint, pPacket,
2495 (uint8_t *)pHtcHdr,
2496 NULL,
2497 pPacket->ActualLength
2498 + HTC_HDR_LENGTH);
2499
2500 status = hif_send_head(target->hif_dev,
2501 pEndpoint->UL_PipeID,
2502 pEndpoint->Id,
2503 HTC_HDR_LENGTH + pPacket->ActualLength,
2504 netbuf, data_attr);
2505 if (status != QDF_STATUS_SUCCESS) {
2506 if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
2507 if (used_extra_tx_credit) {
2508 pEndpoint->EpCallBacks.
2509 ep_padding_credit_update
2510 (pEndpoint->EpCallBacks.pContext, 1);
2511 }
2512 }
2513 }
2514 #if DEBUG_BUNDLE
2515 qdf_print(" Send single EP%d buffer size:0x%x, total:0x%x.",
2516 pEndpoint->Id,
2517 pEndpoint->TxCreditSize,
2518 HTC_HDR_LENGTH + pPacket->ActualLength);
2519 #endif
2520
2521 htc_issue_tx_bundle_stats_inc(target);
2522
2523 if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) {
2524 LOCK_HTC_TX(target);
2525 pEndpoint->ul_outstanding_cnt--;
2526 /* remove this packet from the tx completion queue */
2527 HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacket);
2528
2529 /*
2530 * Don't bother reclaiming credits - HTC flow control
2531 * is not applicable to tx data.
2532 * In LL systems, there is no download flow control,
2533 * since there's virtually no download delay.
2534 * In HL systems, the txrx SW explicitly performs the
2535 * tx flow control.
2536 */
2537 /* pEndpoint->TxCredits +=
2538 * pPacket->PktInfo.AsTx.CreditsUsed;
2539 */
2540
2541 /* put this frame back at the front of the sendQueue */
2542 HTC_PACKET_ENQUEUE_TO_HEAD(&sendQueue, pPacket);
2543
2544 /* put the sendQueue back at the front of
2545 * pEndpoint->TxQueue
2546 */
2547 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue,
2548 &sendQueue);
2549 UNLOCK_HTC_TX(target);
2550 break; /* still need to reset TxProcessCount */
2551 }
2552 }
2553 /* done with this endpoint, we can clear the count */
2554 qdf_atomic_init(&pEndpoint->TxProcessCount);
2555
2556 if (pEndpoint->ul_is_polled) {
2557 /*
2558 * Start a cleanup timer to poll for download completion.
2559 * The download completion should be noticed promptly from
2560 * other polling calls, but the timer provides a safety net
2561 * in case other polling calls don't occur as expected.
2562 */
2563 htc_send_complete_poll_timer_start(pEndpoint);
2564 }
2565
2566 return status;
2567 }
2568 #endif /*ATH_11AC_TXCOMPACT */
2569 qdf_export_symbol(htc_send_data_pkt);
2570
2571 /*
2572 * In the adapted HIF layer, qdf_nbuf_t are passed between HIF and HTC,
2573 * since upper layers expects HTC_PACKET containers we use the completed netbuf
2574 * and lookup its corresponding HTC packet buffer from a lookup list.
2575 * This is extra overhead that can be fixed by re-aligning HIF interfaces
2576 * with HTC.
2577 *
2578 */
htc_lookup_tx_packet(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,qdf_nbuf_t netbuf)2579 static HTC_PACKET *htc_lookup_tx_packet(HTC_TARGET *target,
2580 HTC_ENDPOINT *pEndpoint,
2581 qdf_nbuf_t netbuf)
2582 {
2583 HTC_PACKET *pPacket = NULL;
2584 HTC_PACKET *pFoundPacket = NULL;
2585 HTC_PACKET_QUEUE lookupQueue;
2586
2587 INIT_HTC_PACKET_QUEUE(&lookupQueue);
2588 LOCK_HTC_EP_TX_LOOKUP(pEndpoint);
2589
2590 LOCK_HTC_TX(target);
2591 /* mark that HIF has indicated the send complete for another packet */
2592 pEndpoint->ul_outstanding_cnt--;
2593
2594 /* Dequeue first packet directly because of in-order completion */
2595 pPacket = htc_packet_dequeue(&pEndpoint->TxLookupQueue);
2596 if (qdf_unlikely(!pPacket)) {
2597 UNLOCK_HTC_TX(target);
2598 UNLOCK_HTC_EP_TX_LOOKUP(pEndpoint);
2599 return NULL;
2600 }
2601 if (netbuf == (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket)) {
2602 UNLOCK_HTC_TX(target);
2603 UNLOCK_HTC_EP_TX_LOOKUP(pEndpoint);
2604 return pPacket;
2605 }
2606 HTC_PACKET_ENQUEUE(&lookupQueue, pPacket);
2607
2608 /*
2609 * Move TX lookup queue to temp queue because most of packets that are
2610 * not index 0 are not top 10 packets.
2611 */
2612 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&lookupQueue,
2613 &pEndpoint->TxLookupQueue);
2614
2615 ITERATE_OVER_LIST_ALLOW_REMOVE(&lookupQueue.QueueHead, pPacket,
2616 HTC_PACKET, ListLink) {
2617
2618 if (!pPacket) {
2619 pFoundPacket = pPacket;
2620 break;
2621 }
2622 /* check for removal */
2623 if (netbuf ==
2624 (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket)) {
2625 /* found it */
2626 HTC_PACKET_REMOVE(&lookupQueue, pPacket);
2627 pFoundPacket = pPacket;
2628 break;
2629 }
2630
2631 }
2632 ITERATE_END;
2633
2634 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxLookupQueue,
2635 &lookupQueue);
2636 UNLOCK_HTC_TX(target);
2637 UNLOCK_HTC_EP_TX_LOOKUP(pEndpoint);
2638
2639 return pFoundPacket;
2640 }
2641
2642 /**
2643 * htc_tx_completion_handler() - htc tx completion handler
2644 * @Context: pointer to HTC_TARGET structure
2645 * @netbuf: pointer to netbuf for which completion handler is being called
2646 * @EpID: end point Id on which the packet was sent
2647 * @toeplitz_hash_result: toeplitz hash result
2648 *
2649 * Return: QDF_STATUS_SUCCESS for success or an appropriate QDF_STATUS error
2650 */
htc_tx_completion_handler(void * Context,qdf_nbuf_t netbuf,unsigned int EpID,uint32_t toeplitz_hash_result)2651 QDF_STATUS htc_tx_completion_handler(void *Context,
2652 qdf_nbuf_t netbuf, unsigned int EpID,
2653 uint32_t toeplitz_hash_result)
2654 {
2655 HTC_TARGET *target = (HTC_TARGET *) Context;
2656 HTC_ENDPOINT *pEndpoint;
2657 HTC_PACKET *pPacket;
2658 #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED
2659 HTC_ENDPOINT_ID eid[DATA_EP_SIZE] = { ENDPOINT_5, ENDPOINT_4,
2660 ENDPOINT_2, ENDPOINT_3 };
2661 int epidIdx;
2662 uint16_t resourcesThresh[DATA_EP_SIZE]; /* urb resources */
2663 uint16_t resources;
2664 uint16_t resourcesMax;
2665 #endif
2666
2667 pEndpoint = &target->endpoint[EpID];
2668 target->TX_comp_cnt++;
2669 pEndpoint->htc_comp_cnt++;
2670
2671 do {
2672 pPacket = htc_lookup_tx_packet(target, pEndpoint, netbuf);
2673 if (!pPacket) {
2674 qdf_rl_err("HTC TX lookup failed!");
2675 /* may have already been flushed and freed */
2676 netbuf = NULL;
2677 break;
2678 }
2679 if (pPacket->PktInfo.AsTx.Tag != HTC_TX_PACKET_TAG_AUTO_PM &&
2680 pPacket->PktInfo.AsTx.Tag != HTC_TX_PACKET_TAG_RUNTIME_PUT &&
2681 pPacket->PktInfo.AsTx.Tag != HTC_TX_PACKET_TAG_RTPM_PUT_RC) {
2682 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_WMI);
2683 htc_dec_wmi_runtime_cnt(target, HIF_RTPM_ID_WMI);
2684 }
2685
2686
2687 if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_BUNDLED) {
2688 HTC_PACKET *pPacketTemp;
2689 HTC_PACKET_QUEUE *pQueueSave =
2690 (HTC_PACKET_QUEUE *) pPacket->pContext;
2691 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pQueueSave,
2692 pPacketTemp) {
2693 pPacket->Status = QDF_STATUS_SUCCESS;
2694 send_packet_completion(target, pPacketTemp);
2695 }
2696 HTC_PACKET_QUEUE_ITERATE_END;
2697 free_htc_bundle_packet(target, pPacket);
2698
2699 if (hif_get_bus_type(target->hif_dev) ==
2700 QDF_BUS_TYPE_USB) {
2701 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint))
2702 htc_try_send(target, pEndpoint, NULL);
2703 }
2704
2705 return QDF_STATUS_SUCCESS;
2706 }
2707 /* will be giving this buffer back to upper layers */
2708 netbuf = NULL;
2709 pPacket->Status = QDF_STATUS_SUCCESS;
2710 send_packet_completion(target, pPacket);
2711
2712 } while (false);
2713
2714 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
2715 /* note: when using TX credit flow, the re-checking of queues
2716 * happens when credits flow back from the target. In the non-TX
2717 * credit case, we recheck after the packet completes
2718 */
2719 if ((qdf_atomic_read(&pEndpoint->TxProcessCount) == 0) ||
2720 (!pEndpoint->async_update)) {
2721 htc_try_send(target, pEndpoint, NULL);
2722 }
2723 }
2724
2725 return QDF_STATUS_SUCCESS;
2726 }
2727
2728 #ifdef WLAN_FEATURE_FASTPATH
2729 /**
2730 * htc_ctrl_msg_cmpl() - checks for tx completion for the endpoint specified
2731 * @htc_pdev: pointer to the htc context
2732 * @htc_ep_id: end point id
2733 *
2734 * checks HTC tx completion
2735 *
2736 * Return: none
2737 */
htc_ctrl_msg_cmpl(HTC_HANDLE htc_pdev,HTC_ENDPOINT_ID htc_ep_id)2738 void htc_ctrl_msg_cmpl(HTC_HANDLE htc_pdev, HTC_ENDPOINT_ID htc_ep_id)
2739 {
2740 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_pdev);
2741 HTC_ENDPOINT *pendpoint = &target->endpoint[htc_ep_id];
2742
2743 htc_send_complete_check(pendpoint, 1);
2744 }
2745 qdf_export_symbol(htc_ctrl_msg_cmpl);
2746 #endif
2747
2748 /* callback when TX resources become available */
htc_tx_resource_avail_handler(void * context,uint8_t pipeID)2749 void htc_tx_resource_avail_handler(void *context, uint8_t pipeID)
2750 {
2751 int i;
2752 HTC_TARGET *target = (HTC_TARGET *) context;
2753 HTC_ENDPOINT *pEndpoint = NULL;
2754
2755 for (i = 0; i < ENDPOINT_MAX; i++) {
2756 pEndpoint = &target->endpoint[i];
2757 if (pEndpoint->service_id != 0) {
2758 if (pEndpoint->UL_PipeID == pipeID)
2759 break;
2760 }
2761 }
2762
2763 if (i >= ENDPOINT_MAX) {
2764 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
2765 ("Invalid pipe indicated for TX resource avail : %d!\n",
2766 pipeID));
2767 return;
2768 }
2769
2770 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
2771 ("HIF indicated more resources for pipe:%d\n",
2772 pipeID));
2773
2774 htc_try_send(target, pEndpoint, NULL);
2775 }
2776
2777 #ifdef FEATURE_RUNTIME_PM
2778 /**
2779 * htc_kick_queues() - resumes tx transactions of suspended endpoints
2780 * @context: pointer to the htc target context
2781 *
2782 * Iterates through the endpoints and provides a context to empty queues
2783 * int the hif layer when they are stalled due to runtime suspend.
2784 *
2785 * Return: none
2786 */
htc_kick_queues(void * context)2787 void htc_kick_queues(void *context)
2788 {
2789 int i;
2790 HTC_TARGET *target = (HTC_TARGET *)context;
2791 HTC_ENDPOINT *endpoint = NULL;
2792
2793 if (hif_rtpm_get(HIF_RTPM_GET_SYNC, HIF_RTPM_ID_HTT))
2794 return;
2795
2796 for (i = 0; i < ENDPOINT_MAX; i++) {
2797 endpoint = &target->endpoint[i];
2798
2799 if (endpoint->service_id == 0)
2800 continue;
2801
2802 if (endpoint->EpCallBacks.ep_resume_tx_queue)
2803 endpoint->EpCallBacks.ep_resume_tx_queue(
2804 endpoint->EpCallBacks.pContext);
2805
2806 htc_try_send(target, endpoint, NULL);
2807 }
2808
2809 hif_fastpath_resume(target->hif_dev);
2810
2811 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_HTT);
2812 }
2813 #endif
2814
2815 /* flush endpoint TX queue */
htc_flush_endpoint_tx(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,HTC_TX_TAG Tag)2816 void htc_flush_endpoint_tx(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint,
2817 HTC_TX_TAG Tag)
2818 {
2819 HTC_PACKET *pPacket;
2820
2821 LOCK_HTC_TX(target);
2822 while (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) {
2823 pPacket = htc_packet_dequeue(&pEndpoint->TxQueue);
2824
2825 if (pPacket) {
2826 /* let the sender know the packet was not delivered */
2827 pPacket->Status = QDF_STATUS_E_CANCELED;
2828 send_packet_completion(target, pPacket);
2829 }
2830 }
2831 UNLOCK_HTC_TX(target);
2832 }
2833
2834 /* flush pending entries in endpoint TX Lookup queue */
htc_flush_endpoint_txlookupQ(HTC_TARGET * target,HTC_ENDPOINT_ID endpoint_id,bool call_ep_callback)2835 void htc_flush_endpoint_txlookupQ(HTC_TARGET *target,
2836 HTC_ENDPOINT_ID endpoint_id,
2837 bool call_ep_callback)
2838 {
2839 HTC_PACKET *packet;
2840 HTC_ENDPOINT *endpoint;
2841
2842 endpoint = &target->endpoint[endpoint_id];
2843
2844 if (!endpoint && endpoint->service_id == 0)
2845 return;
2846
2847 LOCK_HTC_TX(target);
2848 while (HTC_PACKET_QUEUE_DEPTH(&endpoint->TxLookupQueue)) {
2849 packet = htc_packet_dequeue(&endpoint->TxLookupQueue);
2850
2851 if (packet) {
2852 if (call_ep_callback == true) {
2853 packet->Status = QDF_STATUS_E_CANCELED;
2854 send_packet_completion(target, packet);
2855 } else {
2856 qdf_mem_free(packet);
2857 }
2858 }
2859 }
2860 UNLOCK_HTC_TX(target);
2861 }
2862
2863 /* HTC API to flush an endpoint's TX queue*/
htc_flush_endpoint(HTC_HANDLE HTCHandle,HTC_ENDPOINT_ID Endpoint,HTC_TX_TAG Tag)2864 void htc_flush_endpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint,
2865 HTC_TX_TAG Tag)
2866 {
2867 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
2868 HTC_ENDPOINT *pEndpoint = &target->endpoint[Endpoint];
2869
2870 if (pEndpoint->service_id == 0) {
2871 AR_DEBUG_ASSERT(false);
2872 /* not in use.. */
2873 return;
2874 }
2875
2876 htc_flush_endpoint_tx(target, pEndpoint, Tag);
2877 }
2878
2879 /* HTC API to indicate activity to the credit distribution function */
htc_indicate_activity_change(HTC_HANDLE HTCHandle,HTC_ENDPOINT_ID Endpoint,bool Active)2880 void htc_indicate_activity_change(HTC_HANDLE HTCHandle,
2881 HTC_ENDPOINT_ID Endpoint, bool Active)
2882 {
2883 /* TODO */
2884 }
2885
htc_is_endpoint_active(HTC_HANDLE HTCHandle,HTC_ENDPOINT_ID Endpoint)2886 bool htc_is_endpoint_active(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint)
2887 {
2888 return true;
2889 }
2890
htc_set_pkt_dbg(HTC_HANDLE handle,A_BOOL dbg_flag)2891 void htc_set_pkt_dbg(HTC_HANDLE handle, A_BOOL dbg_flag)
2892 {
2893 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(handle);
2894
2895 target->htc_pkt_dbg = dbg_flag;
2896 }
2897
htc_set_nodrop_pkt(HTC_HANDLE HTCHandle,A_BOOL isNodropPkt)2898 void htc_set_nodrop_pkt(HTC_HANDLE HTCHandle, A_BOOL isNodropPkt)
2899 {
2900 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
2901
2902 target->is_nodrop_pkt = isNodropPkt;
2903 }
2904
htc_enable_hdr_length_check(HTC_HANDLE htc_hdl,bool htc_hdr_length_check)2905 void htc_enable_hdr_length_check(HTC_HANDLE htc_hdl, bool htc_hdr_length_check)
2906 {
2907 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_hdl);
2908
2909 target->htc_hdr_length_check = htc_hdr_length_check;
2910 }
2911
2912 /**
2913 * htc_process_credit_rpt() - process credit report, call distribution function
2914 * @target: pointer to HTC_TARGET
2915 * @pRpt: pointer to HTC_CREDIT_REPORT
2916 * @NumEntries: number of entries in credit report
2917 * @FromEndpoint: endpoint for which credit report is received
2918 *
2919 * Return: A_OK for success or an appropriate A_STATUS error
2920 */
htc_process_credit_rpt(HTC_TARGET * target,HTC_CREDIT_REPORT * pRpt,int NumEntries,HTC_ENDPOINT_ID FromEndpoint)2921 void htc_process_credit_rpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt,
2922 int NumEntries, HTC_ENDPOINT_ID FromEndpoint)
2923 {
2924 int i;
2925 HTC_ENDPOINT *pEndpoint;
2926 int totalCredits = 0;
2927 uint8_t rpt_credits, rpt_ep_id;
2928
2929 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
2930 ("+htc_process_credit_rpt, Credit Report Entries:%d\n",
2931 NumEntries));
2932
2933 /* lock out TX while we update credits */
2934 LOCK_HTC_TX(target);
2935
2936 for (i = 0; i < NumEntries; i++, pRpt++) {
2937
2938 rpt_ep_id = HTC_GET_FIELD(pRpt, HTC_CREDIT_REPORT, ENDPOINTID);
2939
2940 if (rpt_ep_id >= ENDPOINT_MAX) {
2941 AR_DEBUG_ASSERT(false);
2942 break;
2943 }
2944
2945 rpt_credits = HTC_GET_FIELD(pRpt, HTC_CREDIT_REPORT, CREDITS);
2946
2947 pEndpoint = &target->endpoint[rpt_ep_id];
2948 #if DEBUG_CREDIT
2949 if (ep_debug_mask & (1 << pEndpoint->Id)) {
2950 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
2951 (" <HTC> Increase EP%d %d + %d = %d credits\n",
2952 rpt_ep_id, pEndpoint->TxCredits,
2953 rpt_credits,
2954 pEndpoint->TxCredits + rpt_credits));
2955 }
2956 #endif
2957
2958 #ifdef HTC_EP_STAT_PROFILING
2959
2960 INC_HTC_EP_STAT(pEndpoint, TxCreditRpts, 1);
2961 INC_HTC_EP_STAT(pEndpoint, TxCreditsReturned, rpt_credits);
2962
2963 if (FromEndpoint == rpt_ep_id) {
2964 /* this credit report arrived on the same endpoint
2965 * indicating it arrived in an RX packet
2966 */
2967 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromRx,
2968 rpt_credits);
2969 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromRx, 1);
2970 } else if (FromEndpoint == ENDPOINT_0) {
2971 /* this credit arrived on endpoint 0 as a NULL msg */
2972 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromEp0,
2973 rpt_credits);
2974 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromEp0, 1);
2975 } else {
2976 /* arrived on another endpoint */
2977 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromOther,
2978 rpt_credits);
2979 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromOther, 1);
2980 }
2981
2982 #endif
2983
2984 if (pEndpoint->service_id == WMI_CONTROL_SVC) {
2985 htc_credit_record(HTC_PROCESS_CREDIT_REPORT,
2986 pEndpoint->TxCredits + rpt_credits,
2987 HTC_PACKET_QUEUE_DEPTH(&pEndpoint->
2988 TxQueue));
2989 hif_latency_detect_credit_record_time(
2990 HIF_PROCESS_CREDIT_REPORT,
2991 target->hif_dev);
2992 }
2993
2994 pEndpoint->TxCredits += rpt_credits;
2995
2996 if (pEndpoint->TxCredits
2997 && HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) {
2998 UNLOCK_HTC_TX(target);
2999 #ifdef ATH_11AC_TXCOMPACT
3000 htc_try_send(target, pEndpoint, NULL);
3001 #else
3002 if (pEndpoint->service_id == HTT_DATA_MSG_SVC)
3003 htc_send_data_pkt((HTC_HANDLE)target, NULL, 0);
3004 else
3005 htc_try_send(target, pEndpoint, NULL);
3006 #endif
3007 LOCK_HTC_TX(target);
3008 }
3009 totalCredits += rpt_credits;
3010 }
3011
3012 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
3013 (" Report indicated %d credits to distribute\n",
3014 totalCredits));
3015
3016 UNLOCK_HTC_TX(target);
3017
3018 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_process_credit_rpt\n"));
3019 }
3020
3021 /* function to fetch stats from htc layer*/
ieee80211_ioctl_get_htc_stats(HTC_HANDLE HTCHandle)3022 struct ol_ath_htc_stats *ieee80211_ioctl_get_htc_stats(HTC_HANDLE HTCHandle)
3023 {
3024 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
3025
3026 return &(target->htc_pkt_stats);
3027 }
3028
3029 #ifdef SYSTEM_PM_CHECK
htc_system_resume(HTC_HANDLE htc)3030 void htc_system_resume(HTC_HANDLE htc)
3031 {
3032 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc);
3033 HTC_ENDPOINT *endpoint = NULL;
3034 int i;
3035
3036 if (!target)
3037 return;
3038
3039 for (i = 0; i < ENDPOINT_MAX; i++) {
3040 endpoint = &target->endpoint[i];
3041
3042 if (endpoint->service_id == 0)
3043 continue;
3044
3045 htc_try_send(target, endpoint, NULL);
3046 }
3047 }
3048 #endif
3049