blob: a71c04f774c8609ef4aa13521d2629714d6c6e6f [file] [log] [blame]
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001/*
Rajeev Kumar926baab2016-01-06 18:11:55 -08002 * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28#include "htc_debug.h"
29#include "htc_internal.h"
Yue Mab16cf302016-03-08 18:30:25 -080030#include <qdf_mem.h> /* qdf_mem_malloc */
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +053031#include <qdf_nbuf.h> /* qdf_nbuf_t */
Yue Mab16cf302016-03-08 18:30:25 -080032
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080033
34/* #define USB_HIF_SINGLE_PIPE_DATA_SCHED */
35/* #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED */
36#define DATA_EP_SIZE 4
37/* #endif */
38#define HTC_DATA_RESOURCE_THRS 256
39#define HTC_DATA_MINDESC_PERPACKET 2
40
41typedef enum _HTC_SEND_QUEUE_RESULT {
42 HTC_SEND_QUEUE_OK = 0, /* packet was queued */
43 HTC_SEND_QUEUE_DROP = 1, /* this packet should be dropped */
44} HTC_SEND_QUEUE_RESULT;
45
46#ifndef DEBUG_CREDIT
47#define DEBUG_CREDIT 0
48#endif
49
50#if DEBUG_CREDIT
51/* bit mask to enable debug certain endpoint */
52static unsigned ep_debug_mask =
53 (1 << ENDPOINT_0) | (1 << ENDPOINT_1) | (1 << ENDPOINT_2);
54#endif
55
56/* HTC Control Path Credit History */
Yue Mab16cf302016-03-08 18:30:25 -080057uint32_t g_htc_credit_history_idx = 0;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080058HTC_CREDIT_HISTORY htc_credit_history_buffer[HTC_CREDIT_HISTORY_MAX];
59
60/**
61 * htc_credit_record() - records tx que state & credit transactions
62 * @type: type of echange can be HTC_REQUEST_CREDIT
63 * or HTC_PROCESS_CREDIT_REPORT
64 * @tx_credits: current number of tx_credits
65 * @htc_tx_queue_depth: current hct tx queue depth
66 *
67 * This function records the credits and pending commands whenever a command is
68 * sent or credits are returned. Call this after the credits have been updated
69 * according to the transaction. Call this before dequeing commands.
70 *
71 * Consider making this function accept an HTC_ENDPOINT and find the current
72 * credits and queue depth itself.
73 *
74 * Consider moving the LOCK_HTC_CREDIT(target); logic into this function as well.
75 */
76void htc_credit_record(htc_credit_exchange_type type, uint32_t tx_credit,
77 uint32_t htc_tx_queue_depth) {
78 if (HTC_CREDIT_HISTORY_MAX <= g_htc_credit_history_idx)
79 g_htc_credit_history_idx = 0;
80
81 htc_credit_history_buffer[g_htc_credit_history_idx].type = type;
82 htc_credit_history_buffer[g_htc_credit_history_idx].time =
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +053083 qdf_get_log_timestamp();
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080084 htc_credit_history_buffer[g_htc_credit_history_idx].tx_credit =
85 tx_credit;
86 htc_credit_history_buffer[g_htc_credit_history_idx].htc_tx_queue_depth =
87 htc_tx_queue_depth;
88 g_htc_credit_history_idx++;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080089}
90
91void htc_dump_counter_info(HTC_HANDLE HTCHandle)
92{
93 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
94
95 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
96 ("\n%s: ce_send_cnt = %d, TX_comp_cnt = %d\n",
97 __func__, target->ce_send_cnt, target->TX_comp_cnt));
98}
99
100void htc_get_control_endpoint_tx_host_credits(HTC_HANDLE HTCHandle, int *credits)
101{
102 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
103 HTC_ENDPOINT *pEndpoint;
104 int i;
105
106 if (!credits || !target) {
107 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: invalid args", __func__));
108 return;
109 }
110
111 *credits = 0;
112 LOCK_HTC_TX(target);
113 for (i = 0; i < ENDPOINT_MAX; i++) {
Houston Hoffman29573d92015-10-20 17:49:44 -0700114 pEndpoint = &target->endpoint[i];
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700115 if (pEndpoint->service_id == WMI_CONTROL_SVC) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800116 *credits = pEndpoint->TxCredits;
117 break;
118 }
119 }
120 UNLOCK_HTC_TX(target);
121}
122
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530123static inline void restore_tx_packet(HTC_TARGET *target, HTC_PACKET *pPacket)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800124{
125 if (pPacket->PktInfo.AsTx.Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) {
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530126 qdf_nbuf_t netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
127 qdf_nbuf_unmap(target->osdev, netbuf, QDF_DMA_TO_DEVICE);
128 qdf_nbuf_pull_head(netbuf, sizeof(HTC_FRAME_HDR));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800129 pPacket->PktInfo.AsTx.Flags &= ~HTC_TX_PACKET_FLAG_FIXUP_NETBUF;
130 }
131
132}
133
134static void do_send_completion(HTC_ENDPOINT *pEndpoint,
135 HTC_PACKET_QUEUE *pQueueToIndicate)
136{
137 do {
138
139 if (HTC_QUEUE_EMPTY(pQueueToIndicate)) {
140 /* nothing to indicate */
141 break;
142 }
143
144 if (pEndpoint->EpCallBacks.EpTxCompleteMultiple != NULL) {
145 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
146 (" HTC calling ep %d, send complete multiple callback (%d pkts) \n",
147 pEndpoint->Id,
148 HTC_PACKET_QUEUE_DEPTH
149 (pQueueToIndicate)));
150 /* a multiple send complete handler is being used, pass the queue to the handler */
151 pEndpoint->EpCallBacks.EpTxCompleteMultiple(pEndpoint->
152 EpCallBacks.
153 pContext,
154 pQueueToIndicate);
155 /* all packets are now owned by the callback, reset queue to be safe */
156 INIT_HTC_PACKET_QUEUE(pQueueToIndicate);
157 } else {
158 HTC_PACKET *pPacket;
159 /* using legacy EpTxComplete */
160 do {
161 pPacket = htc_packet_dequeue(pQueueToIndicate);
162 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
163 (" HTC calling ep %d send complete callback on packet %p \n",
164 pEndpoint->Id, pPacket));
165 pEndpoint->EpCallBacks.EpTxComplete(pEndpoint->
166 EpCallBacks.
167 pContext,
168 pPacket);
169 } while (!HTC_QUEUE_EMPTY(pQueueToIndicate));
170 }
171
172 } while (false);
173
174}
175
176static void send_packet_completion(HTC_TARGET *target, HTC_PACKET *pPacket)
177{
Houston Hoffman29573d92015-10-20 17:49:44 -0700178 HTC_ENDPOINT *pEndpoint = &target->endpoint[pPacket->Endpoint];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800179 HTC_PACKET_QUEUE container;
180
181 restore_tx_packet(target, pPacket);
182 INIT_HTC_PACKET_QUEUE_AND_ADD(&container, pPacket);
183
184 /* do completion */
185 do_send_completion(pEndpoint, &container);
186}
187
188void htc_send_complete_check_cleanup(void *context)
189{
190 HTC_ENDPOINT *pEndpoint = (HTC_ENDPOINT *) context;
191 htc_send_complete_check(pEndpoint, 1);
192}
193
194HTC_PACKET *allocate_htc_bundle_packet(HTC_TARGET *target)
195{
196 HTC_PACKET *pPacket;
197 HTC_PACKET_QUEUE *pQueueSave;
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530198 qdf_nbuf_t netbuf;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800199 LOCK_HTC_TX(target);
200 if (NULL == target->pBundleFreeList) {
201 UNLOCK_HTC_TX(target);
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530202 netbuf = qdf_nbuf_alloc(NULL,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800203 target->MaxMsgsPerHTCBundle *
204 target->TargetCreditSize, 0, 4, false);
205 AR_DEBUG_ASSERT(netbuf);
206 if (!netbuf) {
207 return NULL;
208 }
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530209 pPacket = qdf_mem_malloc(sizeof(HTC_PACKET));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800210 AR_DEBUG_ASSERT(pPacket);
211 if (!pPacket) {
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530212 qdf_nbuf_free(netbuf);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800213 return NULL;
214 }
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530215 pQueueSave = qdf_mem_malloc(sizeof(HTC_PACKET_QUEUE));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800216 AR_DEBUG_ASSERT(pQueueSave);
217 if (!pQueueSave) {
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530218 qdf_nbuf_free(netbuf);
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530219 qdf_mem_free(pPacket);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800220 return NULL;
221 }
222 INIT_HTC_PACKET_QUEUE(pQueueSave);
223 pPacket->pContext = pQueueSave;
224 SET_HTC_PACKET_NET_BUF_CONTEXT(pPacket, netbuf);
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530225 pPacket->pBuffer = qdf_nbuf_data(netbuf);
226 pPacket->BufferLength = qdf_nbuf_len(netbuf);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800227
228 /* store the original head room so that we can restore this when we "free" the packet */
229 /* free packet puts the packet back on the free list */
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530230 pPacket->netbufOrigHeadRoom = qdf_nbuf_headroom(netbuf);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800231 return pPacket;
232 }
233 /* already done malloc - restore from free list */
234 pPacket = target->pBundleFreeList;
235 AR_DEBUG_ASSERT(pPacket);
236 if (!pPacket) {
237 UNLOCK_HTC_TX(target);
238 return NULL;
239 }
240 target->pBundleFreeList = (HTC_PACKET *) pPacket->ListLink.pNext;
241 UNLOCK_HTC_TX(target);
242 pPacket->ListLink.pNext = NULL;
243
244 return pPacket;
245}
246
247void free_htc_bundle_packet(HTC_TARGET *target, HTC_PACKET *pPacket)
248{
Yue Mab16cf302016-03-08 18:30:25 -0800249 uint32_t curentHeadRoom;
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530250 qdf_nbuf_t netbuf;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800251 HTC_PACKET_QUEUE *pQueueSave;
252
253 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
254 AR_DEBUG_ASSERT(netbuf);
255 if (!netbuf) {
256 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("\n%s: Invalid netbuf in HTC "
257 "Packet\n", __func__));
258 return;
259 }
260 /* HIF adds data to the headroom section of the nbuf, restore the original */
261 /* size. If this is not done, headroom keeps shrinking with every HIF send */
262 /* and eventually HIF ends up doing another malloc big enough to store the */
263 /* data + its header */
264
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530265 curentHeadRoom = qdf_nbuf_headroom(netbuf);
266 qdf_nbuf_pull_head(netbuf,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800267 pPacket->netbufOrigHeadRoom - curentHeadRoom);
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530268 qdf_nbuf_trim_tail(netbuf, qdf_nbuf_len(netbuf));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800269
270 /* restore the pBuffer pointer. HIF changes this */
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530271 pPacket->pBuffer = qdf_nbuf_data(netbuf);
272 pPacket->BufferLength = qdf_nbuf_len(netbuf);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800273
274 /* restore queue */
275 pQueueSave = (HTC_PACKET_QUEUE *) pPacket->pContext;
276 AR_DEBUG_ASSERT(pQueueSave);
277
278 INIT_HTC_PACKET_QUEUE(pQueueSave);
279
280 LOCK_HTC_TX(target);
281 if (target->pBundleFreeList == NULL) {
282 target->pBundleFreeList = pPacket;
283 pPacket->ListLink.pNext = NULL;
284 } else {
285 pPacket->ListLink.pNext = (DL_LIST *) target->pBundleFreeList;
286 target->pBundleFreeList = pPacket;
287 }
288 UNLOCK_HTC_TX(target);
289}
290
Poddar, Siddarthdf030092016-04-28 11:41:57 +0530291#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT)
292
293/**
294 * htc_send_update_tx_bundle_stats() - update tx bundle stats depends
295 * on max bundle size
296 * @target: hif context
297 * @data_len: tx data len
298 * @TxCreditSize: endpoint tx credit size
299 *
300 * Return: None
301 */
302static inline void
303htc_send_update_tx_bundle_stats(HTC_TARGET *target,
304 qdf_size_t data_len,
305 int TxCreditSize)
306{
307 if ((data_len / TxCreditSize) <= HTC_MAX_MSG_PER_BUNDLE_TX)
308 target->tx_bundle_stats[(data_len / TxCreditSize) - 1]++;
309
310 return;
311}
312
313/**
314 * htc_issue_tx_bundle_stats_inc() - increment in tx bundle stats
315 * on max bundle size
316 * @target: hif context
317 *
318 * Return: None
319 */
320static inline void
321htc_issue_tx_bundle_stats_inc(HTC_TARGET *target)
322{
323 target->tx_bundle_stats[0]++;
324}
325#else
326
327static inline void
328htc_send_update_tx_bundle_stats(HTC_TARGET *target,
329 qdf_size_t data_len,
330 int TxCreditSize)
331{
332 return;
333}
334
335static inline void
336htc_issue_tx_bundle_stats_inc(HTC_TARGET *target)
337{
338 return;
339}
340#endif
341
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800342#if defined(HIF_USB) || defined(HIF_SDIO)
343#ifdef ENABLE_BUNDLE_TX
344static A_STATUS htc_send_bundled_netbuf(HTC_TARGET *target,
345 HTC_ENDPOINT *pEndpoint,
346 unsigned char *pBundleBuffer,
347 HTC_PACKET *pPacketTx)
348{
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530349 qdf_size_t data_len;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800350 A_STATUS status;
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530351 qdf_nbuf_t bundleBuf;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800352 uint32_t data_attr = 0;
353
354 bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx);
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530355 data_len = pBundleBuffer - qdf_nbuf_data(bundleBuf);
356 qdf_nbuf_put_tail(bundleBuf, data_len);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800357 SET_HTC_PACKET_INFO_TX(pPacketTx,
358 target,
359 pBundleBuffer,
360 data_len,
361 pEndpoint->Id, HTC_TX_PACKET_TAG_BUNDLED);
362 LOCK_HTC_TX(target);
363 HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacketTx);
364 UNLOCK_HTC_TX(target);
365#if DEBUG_BUNDLE
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530366 qdf_print(" Send bundle EP%d buffer size:0x%x, total:0x%x, count:%d.\n",
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800367 pEndpoint->Id,
368 pEndpoint->TxCreditSize,
369 data_len, data_len / pEndpoint->TxCreditSize);
370#endif
Poddar, Siddarthdf030092016-04-28 11:41:57 +0530371
372 htc_send_update_tx_bundle_stats(target, data_len,
373 pEndpoint->TxCreditSize);
374
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800375 status = hif_send_head(target->hif_dev,
376 pEndpoint->UL_PipeID,
Poddar, Siddarth416b7062016-04-29 11:02:13 +0530377 pEndpoint->Id, data_len,
378 bundleBuf, data_attr);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800379 if (status != A_OK) {
Poddar, Siddarth416b7062016-04-29 11:02:13 +0530380 qdf_print("%s:hif_send_head failed(len=%zu).\n", __func__,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800381 data_len);
382 }
383 return status;
384}
385
Mohit Khanna0f6194e2016-05-17 15:30:44 -0700386/**
387 * htc_issue_packets_bundle() - HTC function to send bundle packets from a queue
388 * @target: HTC target on which packets need to be sent
389 * @pEndpoint: logical endpoint on which packets needs to be sent
390 * @pPktQueue: HTC packet queue containing the list of packets to be sent
391 *
392 * Return: void
393 */
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800394static void htc_issue_packets_bundle(HTC_TARGET *target,
395 HTC_ENDPOINT *pEndpoint,
396 HTC_PACKET_QUEUE *pPktQueue)
397{
398 int i, frag_count, nbytes;
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530399 qdf_nbuf_t netbuf, bundleBuf;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800400 unsigned char *pBundleBuffer = NULL;
401 HTC_PACKET *pPacket = NULL, *pPacketTx = NULL;
402 HTC_FRAME_HDR *pHtcHdr;
Mohit Khanna0f6194e2016-05-17 15:30:44 -0700403 int last_credit_pad = 0;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800404 int creditPad, creditRemainder, transferLength, bundlesSpaceRemaining =
405 0;
406 HTC_PACKET_QUEUE *pQueueSave = NULL;
407
408 bundlesSpaceRemaining =
409 target->MaxMsgsPerHTCBundle * pEndpoint->TxCreditSize;
410 pPacketTx = allocate_htc_bundle_packet(target);
411 if (!pPacketTx) {
412 /* good time to panic */
413 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
414 ("allocate_htc_bundle_packet failed \n"));
415 AR_DEBUG_ASSERT(false);
416 return;
417 }
418 bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx);
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530419 pBundleBuffer = qdf_nbuf_data(bundleBuf);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800420 pQueueSave = (HTC_PACKET_QUEUE *) pPacketTx->pContext;
421 while (1) {
422 pPacket = htc_packet_dequeue(pPktQueue);
423 if (pPacket == NULL) {
424 break;
425 }
426 creditPad = 0;
427 transferLength = pPacket->ActualLength + HTC_HDR_LENGTH;
428 creditRemainder = transferLength % pEndpoint->TxCreditSize;
429 if (creditRemainder != 0) {
430 if (transferLength < pEndpoint->TxCreditSize) {
431 creditPad =
432 pEndpoint->TxCreditSize - transferLength;
433 } else {
434 creditPad = creditRemainder;
435 }
436 transferLength += creditPad;
437 }
438
439 if (bundlesSpaceRemaining < transferLength) {
440 /* send out previous buffer */
Mohit Khanna0f6194e2016-05-17 15:30:44 -0700441 htc_send_bundled_netbuf(target, pEndpoint,
442 pBundleBuffer - last_credit_pad,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800443 pPacketTx);
444 if (HTC_PACKET_QUEUE_DEPTH(pPktQueue) <
445 HTC_MIN_MSG_PER_BUNDLE) {
446 return;
447 }
448 bundlesSpaceRemaining =
449 target->MaxMsgsPerHTCBundle *
450 pEndpoint->TxCreditSize;
451 pPacketTx = allocate_htc_bundle_packet(target);
452 if (!pPacketTx) {
453 /* good time to panic */
454 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
455 ("allocate_htc_bundle_packet failed \n"));
456 AR_DEBUG_ASSERT(false);
457 return;
458 }
459 bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx);
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530460 pBundleBuffer = qdf_nbuf_data(bundleBuf);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800461 pQueueSave = (HTC_PACKET_QUEUE *) pPacketTx->pContext;
462 }
463
464 bundlesSpaceRemaining -= transferLength;
465 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
Mohit Khanna0f6194e2016-05-17 15:30:44 -0700466
467 if (hif_get_bus_type(target->hif_dev) != QDF_BUS_TYPE_USB) {
468 pHtcHdr =
469 (HTC_FRAME_HDR *)
470 qdf_nbuf_get_frag_vaddr(netbuf, 0);
471 HTC_WRITE32(pHtcHdr,
472 SM(pPacket->ActualLength,
473 HTC_FRAME_HDR_PAYLOADLEN) |
474 SM(pPacket->PktInfo.AsTx.SendFlags |
475 HTC_FLAGS_SEND_BUNDLE,
476 HTC_FRAME_HDR_FLAGS) |
477 SM(pPacket->Endpoint,
478 HTC_FRAME_HDR_ENDPOINTID));
479 HTC_WRITE32((uint32_t *) pHtcHdr + 1,
480 SM(pPacket->PktInfo.AsTx.SeqNo,
481 HTC_FRAME_HDR_CONTROLBYTES1) | SM(creditPad,
482 HTC_FRAME_HDR_RESERVED));
483 pHtcHdr->reserved = creditPad;
484 }
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530485 frag_count = qdf_nbuf_get_num_frags(netbuf);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800486 nbytes = pPacket->ActualLength + HTC_HDR_LENGTH;
487 for (i = 0; i < frag_count && nbytes > 0; i++) {
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530488 int frag_len = qdf_nbuf_get_frag_len(netbuf, i);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800489 unsigned char *frag_addr =
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530490 qdf_nbuf_get_frag_vaddr(netbuf, i);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800491 if (frag_len > nbytes) {
492 frag_len = nbytes;
493 }
Yue Mab16cf302016-03-08 18:30:25 -0800494 qdf_mem_copy(pBundleBuffer, frag_addr, frag_len);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800495 nbytes -= frag_len;
496 pBundleBuffer += frag_len;
497 }
498 HTC_PACKET_ENQUEUE(pQueueSave, pPacket);
499 pBundleBuffer += creditPad;
Mohit Khanna0f6194e2016-05-17 15:30:44 -0700500
501 if (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB) {
502 /* last one can't be packed. */
503 last_credit_pad = creditPad;
504 }
505
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800506 }
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530507 if (pBundleBuffer != qdf_nbuf_data(bundleBuf)) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800508 /* send out remaining buffer */
Mohit Khanna0f6194e2016-05-17 15:30:44 -0700509 htc_send_bundled_netbuf(target, pEndpoint,
510 pBundleBuffer - last_credit_pad,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800511 pPacketTx);
512 } else {
513 free_htc_bundle_packet(target, pPacketTx);
514 }
515}
516#endif /* ENABLE_BUNDLE_TX */
Mohit Khanna0f6194e2016-05-17 15:30:44 -0700517#else
518static void htc_issue_packets_bundle(HTC_TARGET *target,
519 HTC_ENDPOINT *pEndpoint,
520 HTC_PACKET_QUEUE *pPktQueue)
521{
522}
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800523#endif
524
Mohit Khanna0f6194e2016-05-17 15:30:44 -0700525/**
526 * htc_issue_packets() - HTC function to send packets from a queue
527 * @target: HTC target on which packets need to be sent
528 * @pEndpoint: logical endpoint on which packets needs to be sent
529 * @pPktQueue: HTC packet queue containing the list of packets to be sent
530 *
531 * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure
532 */
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800533static A_STATUS htc_issue_packets(HTC_TARGET *target,
534 HTC_ENDPOINT *pEndpoint,
535 HTC_PACKET_QUEUE *pPktQueue)
536{
537 A_STATUS status = A_OK;
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530538 qdf_nbuf_t netbuf;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800539 HTC_PACKET *pPacket = NULL;
540 uint16_t payloadLen;
541 HTC_FRAME_HDR *pHtcHdr;
542 uint32_t data_attr = 0;
Mohit Khanna0f6194e2016-05-17 15:30:44 -0700543 enum qdf_bus_type bus_type;
544
545 bus_type = hif_get_bus_type(target->hif_dev);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800546
547 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
548 ("+htc_issue_packets: Queue: %p, Pkts %d \n", pPktQueue,
549 HTC_PACKET_QUEUE_DEPTH(pPktQueue)));
550 while (true) {
Mohit Khanna0f6194e2016-05-17 15:30:44 -0700551 if (HTC_TX_BUNDLE_ENABLED(target) &&
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800552 HTC_PACKET_QUEUE_DEPTH(pPktQueue) >=
553 HTC_MIN_MSG_PER_BUNDLE) {
Mohit Khanna0f6194e2016-05-17 15:30:44 -0700554 switch (bus_type) {
555 case QDF_BUS_TYPE_SDIO:
556 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint))
557 break;
558 case QDF_BUS_TYPE_USB:
559 htc_issue_packets_bundle(target,
560 pEndpoint,
561 pPktQueue);
562 break;
563 default:
564 break;
565 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800566 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800567 /* if not bundling or there was a packet that could not be placed in a bundle,
568 * and send it by normal way
569 */
570 pPacket = htc_packet_dequeue(pPktQueue);
571 if (NULL == pPacket) {
572 /* local queue is fully drained */
573 break;
574 }
575
576 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
577 AR_DEBUG_ASSERT(netbuf);
578 /* Non-credit enabled endpoints have been mapped and setup by now,
579 * so no need to revisit the HTC headers
580 */
581 if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
582
583 payloadLen = pPacket->ActualLength;
584 /* setup HTC frame header */
585
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530586 pHtcHdr = (HTC_FRAME_HDR *)
587 qdf_nbuf_get_frag_vaddr(netbuf, 0);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800588 AR_DEBUG_ASSERT(pHtcHdr);
589
590 HTC_WRITE32(pHtcHdr,
591 SM(payloadLen,
592 HTC_FRAME_HDR_PAYLOADLEN) | SM(pPacket->
593 PktInfo.
594 AsTx.
595 SendFlags,
596 HTC_FRAME_HDR_FLAGS)
597 | SM(pPacket->Endpoint,
598 HTC_FRAME_HDR_ENDPOINTID));
Yue Mab16cf302016-03-08 18:30:25 -0800599 HTC_WRITE32(((uint32_t *) pHtcHdr) + 1,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800600 SM(pPacket->PktInfo.AsTx.SeqNo,
601 HTC_FRAME_HDR_CONTROLBYTES1));
602
603 /*
604 * Now that the HTC frame header has been added, the netbuf can be
605 * mapped. This only applies to non-data frames, since data frames
606 * were already mapped as they entered into the driver.
607 * Check the "FIXUP_NETBUF" flag to see whether this is a data netbuf
608 * that is already mapped, or a non-data netbuf that needs to be
609 * mapped.
610 */
611 if (pPacket->PktInfo.AsTx.
612 Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) {
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530613 qdf_nbuf_map(target->osdev,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800614 GET_HTC_PACKET_NET_BUF_CONTEXT
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530615 (pPacket), QDF_DMA_TO_DEVICE);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800616 }
617 }
Venkateswara Swamy Bandaru9e66f4f2016-10-29 17:13:52 +0530618
619 if (pEndpoint->service_id != WMI_CONTROL_SVC) {
620 LOCK_HTC_TX(target);
621 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800622 /* store in look up queue to match completions */
623 HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacket);
624 INC_HTC_EP_STAT(pEndpoint, TxIssued, 1);
625 pEndpoint->ul_outstanding_cnt++;
Venkateswara Swamy Bandaru9e66f4f2016-10-29 17:13:52 +0530626 if (pEndpoint->service_id != WMI_CONTROL_SVC) {
627 UNLOCK_HTC_TX(target);
628 hif_send_complete_check(target->hif_dev,
629 pEndpoint->UL_PipeID, false);
630 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800631
632 status = hif_send_head(target->hif_dev,
633 pEndpoint->UL_PipeID, pEndpoint->Id,
634 HTC_HDR_LENGTH + pPacket->ActualLength,
635 netbuf, data_attr);
636#if DEBUG_BUNDLE
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530637 qdf_print(" Send single EP%d buffer size:0x%x, total:0x%x.\n",
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800638 pEndpoint->Id,
639 pEndpoint->TxCreditSize,
640 HTC_HDR_LENGTH + pPacket->ActualLength);
641#endif
Poddar, Siddarthdf030092016-04-28 11:41:57 +0530642 htc_issue_tx_bundle_stats_inc(target);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800643
644 target->ce_send_cnt++;
645
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530646 if (qdf_unlikely(A_FAILED(status))) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800647 if (status != A_NO_RESOURCE) {
648 /* TODO : if more than 1 endpoint maps to the same PipeID it is possible
649 * to run out of resources in the HIF layer. Don't emit the error */
650 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
651 ("hif_send Failed status:%d \n",
652 status));
653 }
Venkateswara Swamy Bandaru9e66f4f2016-10-29 17:13:52 +0530654 if (pEndpoint->service_id != WMI_CONTROL_SVC) {
655 LOCK_HTC_TX(target);
656 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800657 target->ce_send_cnt--;
658 pEndpoint->ul_outstanding_cnt--;
659 HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacket);
660 /* reclaim credits */
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800661 pEndpoint->TxCredits +=
662 pPacket->PktInfo.AsTx.CreditsUsed;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800663 /* put it back into the callers queue */
664 HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket);
Venkateswara Swamy Bandaru9e66f4f2016-10-29 17:13:52 +0530665 if (pEndpoint->service_id != WMI_CONTROL_SVC) {
666 UNLOCK_HTC_TX(target);
667 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800668 break;
669 }
670
Houston Hoffman1dd22762015-11-10 11:35:49 -0800671 /*
672 * For HTT messages without a response from fw,
673 * do the runtime put here.
674 * otherwise runtime put will be done when the fw response comes
675 */
676 if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_RUNTIME_PUT)
677 hif_pm_runtime_put(target->hif_dev);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800678 }
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530679 if (qdf_unlikely(A_FAILED(status))) {
Manjunathappa Prakash3044c6e2015-12-04 00:08:58 -0800680 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
681 ("htc_issue_packets, failed pkt:0x%p status:%d",
682 pPacket, status));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800683 }
684
685 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_issue_packets \n"));
686
687 return status;
688}
689
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800690#ifdef FEATURE_RUNTIME_PM
691/**
692 * extract_htc_pm_packtes(): move pm packets from endpoint into queue
693 * @endpoint: which enpoint to extract packets from
694 * @queue: a queue to store extracted packets in.
695 *
696 * remove pm packets from the endpoint's tx queue.
697 * queue them into a queue
698 */
699static void extract_htc_pm_packets(HTC_ENDPOINT *endpoint,
700 HTC_PACKET_QUEUE *queue)
701{
702 HTC_PACKET *packet;
703
704 /* only WMI endpoint has power management packets */
705 if (endpoint->service_id != WMI_CONTROL_SVC)
706 return;
707
708 ITERATE_OVER_LIST_ALLOW_REMOVE(&endpoint->TxQueue.QueueHead, packet,
709 HTC_PACKET, ListLink) {
710 if (packet->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_AUTO_PM) {
711 HTC_PACKET_REMOVE(&endpoint->TxQueue, packet);
712 HTC_PACKET_ENQUEUE(queue, packet);
713 }
714 } ITERATE_END
715}
716
717/**
718 * queue_htc_pm_packets(): queue pm packets with priority
719 * @endpoint: enpoint to queue packets to
720 * @queue: queue of pm packets to enque
721 *
722 * suspend resume packets get special treatment & priority.
723 * need to queue them at the front of the queue.
724 */
725static void queue_htc_pm_packets(HTC_ENDPOINT *endpoint,
726 HTC_PACKET_QUEUE *queue)
727{
728 if (endpoint->service_id != WMI_CONTROL_SVC)
729 return;
730
731 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&endpoint->TxQueue, queue);
732}
733#else
734static void extract_htc_pm_packets(HTC_ENDPOINT *endpoint,
735 HTC_PACKET_QUEUE *queue)
736{}
737
738static void queue_htc_pm_packets(HTC_ENDPOINT *endpoint,
739 HTC_PACKET_QUEUE *queue)
740{}
741#endif
742
Mohit Khanna0f6194e2016-05-17 15:30:44 -0700743/**
744 * get_htc_send_packets_credit_based() - get packets based on available credits
745 * @target: HTC target on which packets need to be sent
746 * @pEndpoint: logical endpoint on which packets needs to be sent
747 * @pQueue: HTC packet queue containing the list of packets to be sent
748 *
749 * Get HTC send packets from TX queue on an endpoint based on available credits.
750 * The function moves the packets from TX queue of the endpoint to pQueue.
751 *
752 * Return: None
753 */
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800754void get_htc_send_packets_credit_based(HTC_TARGET *target,
755 HTC_ENDPOINT *pEndpoint,
756 HTC_PACKET_QUEUE *pQueue)
757{
758 int creditsRequired;
759 int remainder;
Yue Mab16cf302016-03-08 18:30:25 -0800760 uint8_t sendFlags;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800761 HTC_PACKET *pPacket;
762 unsigned int transferLength;
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800763 HTC_PACKET_QUEUE *tx_queue;
764 HTC_PACKET_QUEUE pm_queue;
765 bool do_pm_get = false;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800766
767 /****** NOTE : the TX lock is held when this function is called *****************/
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800768 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+get_htc_send_packets_credit_based\n"));
769
770 INIT_HTC_PACKET_QUEUE(&pm_queue);
771 extract_htc_pm_packets(pEndpoint, &pm_queue);
772 if (HTC_QUEUE_EMPTY(&pm_queue)) {
773 tx_queue = &pEndpoint->TxQueue;
774 do_pm_get = true;
775 } else {
776 tx_queue = &pm_queue;
777 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800778
779 /* loop until we can grab as many packets out of the queue as we can */
780 while (true) {
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800781 if (do_pm_get && hif_pm_runtime_get(target->hif_dev)) {
782 /* bus suspended, runtime resume issued */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530783 QDF_ASSERT(HTC_PACKET_QUEUE_DEPTH(pQueue) == 0);
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800784 break;
785 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800786
787 sendFlags = 0;
788 /* get packet at head, but don't remove it */
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800789 pPacket = htc_get_pkt_at_head(tx_queue);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800790 if (pPacket == NULL) {
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800791 if (do_pm_get)
792 hif_pm_runtime_put(target->hif_dev);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800793 break;
794 }
795
796 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
797 (" Got head packet:%p , Queue Depth: %d\n",
798 pPacket,
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800799 HTC_PACKET_QUEUE_DEPTH(tx_queue)));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800800
801 transferLength = pPacket->ActualLength + HTC_HDR_LENGTH;
802
803 if (transferLength <= pEndpoint->TxCreditSize) {
804 creditsRequired = 1;
805 } else {
806 /* figure out how many credits this message requires */
807 creditsRequired =
808 transferLength / pEndpoint->TxCreditSize;
809 remainder = transferLength % pEndpoint->TxCreditSize;
810
811 if (remainder) {
812 creditsRequired++;
813 }
814 }
815
816 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
817 (" Credits Required:%d Got:%d\n",
818 creditsRequired, pEndpoint->TxCredits));
819
820 if (pEndpoint->Id == ENDPOINT_0) {
Mohit Khanna0f6194e2016-05-17 15:30:44 -0700821 /*
822 * endpoint 0 is special, it always has a credit and
823 * does not require credit based flow control
824 */
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800825 creditsRequired = 0;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800826 } else {
827
828 if (pEndpoint->TxCredits < creditsRequired) {
829#if DEBUG_CREDIT
830 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
831 (" EP%d, No Credit now. %d < %d\n",
832 pEndpoint->Id,
833 pEndpoint->TxCredits,
834 creditsRequired));
835#endif
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800836 if (do_pm_get)
837 hif_pm_runtime_put(target->hif_dev);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800838 break;
839 }
840
841 pEndpoint->TxCredits -= creditsRequired;
842 INC_HTC_EP_STAT(pEndpoint, TxCreditsConsummed,
843 creditsRequired);
844
845 /* check if we need credits back from the target */
846 if (pEndpoint->TxCredits <=
847 pEndpoint->TxCreditsPerMaxMsg) {
848 /* tell the target we need credits ASAP! */
849 sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
850
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700851 if (pEndpoint->service_id == WMI_CONTROL_SVC) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800852 LOCK_HTC_CREDIT(target);
853 htc_credit_record(HTC_REQUEST_CREDIT,
854 pEndpoint->TxCredits,
855 HTC_PACKET_QUEUE_DEPTH
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800856 (tx_queue));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800857 UNLOCK_HTC_CREDIT(target);
858 }
859
860 INC_HTC_EP_STAT(pEndpoint,
861 TxCreditLowIndications, 1);
862#if DEBUG_CREDIT
863 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
864 (" EP%d Needs Credits\n",
865 pEndpoint->Id));
866#endif
867 }
868 }
869
870 /* now we can fully dequeue */
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800871 pPacket = htc_packet_dequeue(tx_queue);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800872 if (pPacket) {
873 /* save the number of credits this packet consumed */
874 pPacket->PktInfo.AsTx.CreditsUsed = creditsRequired;
875 /* save send flags */
876 pPacket->PktInfo.AsTx.SendFlags = sendFlags;
877
878 /* queue this packet into the caller's queue */
879 HTC_PACKET_ENQUEUE(pQueue, pPacket);
880 }
881 }
882
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800883 if (!HTC_QUEUE_EMPTY(&pm_queue))
884 queue_htc_pm_packets(pEndpoint, &pm_queue);
885
886 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
887 ("-get_htc_send_packets_credit_based\n"));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800888
889}
890
891void get_htc_send_packets(HTC_TARGET *target,
892 HTC_ENDPOINT *pEndpoint,
893 HTC_PACKET_QUEUE *pQueue, int Resources)
894{
895
896 HTC_PACKET *pPacket;
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800897 HTC_PACKET_QUEUE *tx_queue;
898 HTC_PACKET_QUEUE pm_queue;
899 bool do_pm_get;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800900
901 /****** NOTE : the TX lock is held when this function is called *****************/
902 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
903 ("+get_htc_send_packets %d resources\n", Resources));
904
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800905 INIT_HTC_PACKET_QUEUE(&pm_queue);
906 extract_htc_pm_packets(pEndpoint, &pm_queue);
907 if (HTC_QUEUE_EMPTY(&pm_queue)) {
908 tx_queue = &pEndpoint->TxQueue;
909 do_pm_get = true;
910 } else {
911 tx_queue = &pm_queue;
912 }
913
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800914 /* loop until we can grab as many packets out of the queue as we can */
915 while (Resources > 0) {
916 int num_frags;
917
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800918 if (do_pm_get && hif_pm_runtime_get(target->hif_dev)) {
919 /* bus suspended, runtime resume issued */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530920 QDF_ASSERT(HTC_PACKET_QUEUE_DEPTH(pQueue) == 0);
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800921 break;
922 }
923
924 pPacket = htc_packet_dequeue(tx_queue);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800925 if (pPacket == NULL) {
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800926 if (do_pm_get)
927 hif_pm_runtime_put(target->hif_dev);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800928 break;
929 }
930 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
931 (" Got packet:%p , New Queue Depth: %d\n",
932 pPacket,
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800933 HTC_PACKET_QUEUE_DEPTH(tx_queue)));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800934 /* For non-credit path the sequence number is already embedded
935 * in the constructed HTC header
936 */
937#if 0
938 pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo;
939 pEndpoint->SeqNo++;
940#endif
941 pPacket->PktInfo.AsTx.SendFlags = 0;
942 pPacket->PktInfo.AsTx.CreditsUsed = 0;
943 /* queue this packet into the caller's queue */
944 HTC_PACKET_ENQUEUE(pQueue, pPacket);
945
946 /*
947 * FIX THIS:
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530948 * For now, avoid calling qdf_nbuf_get_num_frags before calling
949 * qdf_nbuf_map, because the MacOS version of qdf_nbuf_t doesn't
950 * support qdf_nbuf_get_num_frags until after qdf_nbuf_map has
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800951 * been done.
952 * Assume that the non-data netbufs, i.e. the WMI message netbufs,
953 * consist of a single fragment.
954 */
955 num_frags =
956 (pPacket->PktInfo.AsTx.
957 Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) ? 1
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530958 /* WMI messages are in a single-fragment network buffer */ :
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530959 qdf_nbuf_get_num_frags(GET_HTC_PACKET_NET_BUF_CONTEXT
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800960 (pPacket));
961 Resources -= num_frags;
962 }
963
Houston Hoffmanc5141b02015-11-18 02:36:30 -0800964 if (!HTC_QUEUE_EMPTY(&pm_queue))
965 queue_htc_pm_packets(pEndpoint, &pm_queue);
966
967 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-get_htc_send_packets\n"));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800968
969}
970
Mohit Khanna0f6194e2016-05-17 15:30:44 -0700971/**
972 * htc_try_send() - Send packets in a queue on an endpoint
973 * @target: HTC target on which packets need to be sent
974 * @pEndpoint: logical endpoint on which packets needs to be sent
975 * @pCallersSendQueue: packet queue containing the list of packets to be sent
976 *
977 * Return: HTC_SEND_QUEUE_RESULT indicates whether the packet was queued to be
978 * sent or the packet should be dropped by the upper layer
979 */
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800980static HTC_SEND_QUEUE_RESULT htc_try_send(HTC_TARGET *target,
981 HTC_ENDPOINT *pEndpoint,
982 HTC_PACKET_QUEUE *pCallersSendQueue)
983{
984 HTC_PACKET_QUEUE sendQueue; /* temp queue to hold packets at various stages */
985 HTC_PACKET *pPacket;
986 int tx_resources;
987 int overflow;
988 HTC_SEND_QUEUE_RESULT result = HTC_SEND_QUEUE_OK;
989
990 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+htc_try_send (Queue:%p Depth:%d)\n",
991 pCallersSendQueue,
992 (pCallersSendQueue ==
993 NULL) ? 0 :
994 HTC_PACKET_QUEUE_DEPTH
995 (pCallersSendQueue)));
996
997 /* init the local send queue */
998 INIT_HTC_PACKET_QUEUE(&sendQueue);
999
1000 do {
1001
1002 if (NULL == pCallersSendQueue) {
1003 /* caller didn't provide a queue, just wants us to check queues and send */
1004 break;
1005 }
1006
1007 if (HTC_QUEUE_EMPTY(pCallersSendQueue)) {
1008 /* empty queue */
1009 OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target,
1010 HTC_PKT_Q_EMPTY);
1011 result = HTC_SEND_QUEUE_DROP;
1012 break;
1013 }
1014
1015 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) >=
1016 pEndpoint->MaxTxQueueDepth) {
1017 /* we've already overflowed */
1018 overflow = HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue);
1019 } else {
1020 /* figure out how much we will overflow by */
1021 overflow = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
1022 overflow += HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue);
1023 /* figure out how much we will overflow the TX queue by */
1024 overflow -= pEndpoint->MaxTxQueueDepth;
1025 }
1026
1027 /* if overflow is negative or zero, we are okay */
1028 if (overflow > 0) {
1029 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1030 (" Endpoint %d, TX queue will overflow :%d , Tx Depth:%d, Max:%d \n",
1031 pEndpoint->Id, overflow,
1032 HTC_PACKET_QUEUE_DEPTH(&pEndpoint->
1033 TxQueue),
1034 pEndpoint->MaxTxQueueDepth));
1035 }
1036 if ((overflow <= 0)
1037 || (pEndpoint->EpCallBacks.EpSendFull == NULL)) {
1038 /* all packets will fit or caller did not provide send full indication handler
1039 * -- just move all of them to the local sendQueue object */
1040 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&sendQueue,
1041 pCallersSendQueue);
1042 } else {
1043 int i;
1044 int goodPkts =
1045 HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue) -
1046 overflow;
1047
1048 A_ASSERT(goodPkts >= 0);
1049 /* we have overflowed, and a callback is provided */
1050 /* dequeue all non-overflow packets into the sendqueue */
1051 for (i = 0; i < goodPkts; i++) {
1052 /* pop off caller's queue */
1053 pPacket = htc_packet_dequeue(pCallersSendQueue);
1054 A_ASSERT(pPacket != NULL);
1055 /* insert into local queue */
1056 HTC_PACKET_ENQUEUE(&sendQueue, pPacket);
1057 }
1058
1059 /* the caller's queue has all the packets that won't fit */
1060 /* walk through the caller's queue and indicate each one to the send full handler */
1061 ITERATE_OVER_LIST_ALLOW_REMOVE(&pCallersSendQueue->
1062 QueueHead, pPacket,
1063 HTC_PACKET, ListLink) {
1064
1065 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1066 (" Indicating overflowed TX packet: %p \n",
1067 pPacket));
1068 /*
1069 * Remove headroom reserved for HTC_FRAME_HDR before giving
1070 * the packet back to the user via the EpSendFull callback.
1071 */
1072 restore_tx_packet(target, pPacket);
1073
1074 if (pEndpoint->EpCallBacks.
1075 EpSendFull(pEndpoint->EpCallBacks.pContext,
1076 pPacket) == HTC_SEND_FULL_DROP) {
1077 /* callback wants the packet dropped */
1078 INC_HTC_EP_STAT(pEndpoint, TxDropped,
1079 1);
1080 /* leave this one in the caller's queue for cleanup */
1081 } else {
1082 /* callback wants to keep this packet, remove from caller's queue */
1083 HTC_PACKET_REMOVE(pCallersSendQueue,
1084 pPacket);
1085 /* put it in the send queue */
1086 /* add HTC_FRAME_HDR space reservation again */
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301087 qdf_nbuf_push_head
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001088 (GET_HTC_PACKET_NET_BUF_CONTEXT
1089 (pPacket), sizeof(HTC_FRAME_HDR));
1090
1091 HTC_PACKET_ENQUEUE(&sendQueue, pPacket);
1092 }
1093
1094 }
1095 ITERATE_END;
1096
1097 if (HTC_QUEUE_EMPTY(&sendQueue)) {
1098 /* no packets made it in, caller will cleanup */
1099 OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target,
1100 HTC_SEND_Q_EMPTY);
1101 result = HTC_SEND_QUEUE_DROP;
1102 break;
1103 }
1104 }
1105
1106 } while (false);
1107
1108 if (result != HTC_SEND_QUEUE_OK) {
Mohit Khanna0f6194e2016-05-17 15:30:44 -07001109 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send: %d\n",
1110 result));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001111 return result;
1112 }
1113
1114 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
1115 tx_resources =
1116 hif_get_free_queue_number(target->hif_dev,
1117 pEndpoint->UL_PipeID);
1118 } else {
1119 tx_resources = 0;
1120 }
1121
1122 LOCK_HTC_TX(target);
1123
1124 if (!HTC_QUEUE_EMPTY(&sendQueue)) {
gbianb417db22016-09-30 17:01:07 +08001125 if (target->is_nodrop_pkt) {
1126 /*
1127 * nodrop pkts have higher priority than normal pkts,
1128 * insert nodrop pkt to head for proper
1129 * start/termination of test.
1130 */
1131 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue,
1132 &sendQueue);
1133 target->is_nodrop_pkt = false;
1134 } else {
1135 /* transfer packets to tail */
1136 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->TxQueue,
1137 &sendQueue);
1138 A_ASSERT(HTC_QUEUE_EMPTY(&sendQueue));
1139 INIT_HTC_PACKET_QUEUE(&sendQueue);
1140 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001141 }
1142
1143 /* increment tx processing count on entry */
Rajeev Kumare37820e2016-04-14 17:30:56 -07001144 if (qdf_atomic_inc_return(&pEndpoint->TxProcessCount) > 1) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001145 /* another thread or task is draining the TX queues on this endpoint
1146 * that thread will reset the tx processing count when the queue is drained */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301147 qdf_atomic_dec(&pEndpoint->TxProcessCount);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001148 UNLOCK_HTC_TX(target);
1149 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send (busy) \n"));
1150 return HTC_SEND_QUEUE_OK;
1151 }
1152
1153 /***** beyond this point only 1 thread may enter ******/
1154
1155 /* now drain the endpoint TX queue for transmission as long as we have enough
1156 * transmit resources */
1157 while (true) {
1158
Venkateswara Swamy Bandaru9e66f4f2016-10-29 17:13:52 +05301159 if ((HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) == 0) ||
1160 ((!tx_resources) &&
1161 (pEndpoint->service_id == WMI_CONTROL_SVC))) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001162 break;
1163 }
1164
1165 if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
1166#if DEBUG_CREDIT
1167 int cred = pEndpoint->TxCredits;
1168#endif
1169 /* credit based mechanism provides flow control based on target transmit resource availability, we
1170 * assume that the HIF layer will always have bus resources greater than target transmit resources */
1171 get_htc_send_packets_credit_based(target, pEndpoint,
1172 &sendQueue);
1173#if DEBUG_CREDIT
1174 if (ep_debug_mask & (1 << pEndpoint->Id)) {
1175 if (cred - pEndpoint->TxCredits > 0) {
1176 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
1177 (" <HTC> Decrease EP%d %d - %d = %d credits.\n",
1178 pEndpoint->Id, cred,
1179 cred -
1180 pEndpoint->TxCredits,
1181 pEndpoint->TxCredits));
1182 }
1183 }
1184#endif
1185 } else {
Mohit Khanna0f6194e2016-05-17 15:30:44 -07001186
1187 /*
1188 * Header and payload belongs to the different fragments and
1189 * consume 2 resource for one HTC package but USB combine into
1190 * one transfer.
1191 */
1192 if (HTC_TX_BUNDLE_ENABLED(target) && tx_resources &&
1193 hif_get_bus_type(target->hif_dev) ==
1194 QDF_BUS_TYPE_USB)
1195 tx_resources = (HTC_MAX_MSG_PER_BUNDLE_TX * 2);
1196
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001197 /* get all the packets for this endpoint that we can for this pass */
1198 get_htc_send_packets(target, pEndpoint, &sendQueue,
1199 tx_resources);
1200 }
1201
1202 if (HTC_PACKET_QUEUE_DEPTH(&sendQueue) == 0) {
1203 /* didn't get any packets due to a lack of resources or TX queue was drained */
1204 break;
1205 }
1206
Venkateswara Swamy Bandaru9e66f4f2016-10-29 17:13:52 +05301207 if (pEndpoint->service_id != WMI_CONTROL_SVC) {
1208 UNLOCK_HTC_TX(target);
1209 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001210
1211 /* send what we can */
Manjunathappa Prakash3044c6e2015-12-04 00:08:58 -08001212 result = htc_issue_packets(target, pEndpoint, &sendQueue);
1213 if (result) {
Houston Hoffmanc5141b02015-11-18 02:36:30 -08001214 int i;
Manjunathappa Prakash3044c6e2015-12-04 00:08:58 -08001215 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
1216 ("htc_issue_packets, failed status:%d put it back to head of callersSendQueue",
1217 result));
Houston Hoffmanc5141b02015-11-18 02:36:30 -08001218
1219 for (i = HTC_PACKET_QUEUE_DEPTH(&sendQueue); i > 0; i--)
1220 hif_pm_runtime_put(target->hif_dev);
1221
Manjunathappa Prakash3044c6e2015-12-04 00:08:58 -08001222 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue,
1223 &sendQueue);
1224 LOCK_HTC_TX(target);
1225 break;
1226 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001227
1228 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
1229 tx_resources =
1230 hif_get_free_queue_number(target->hif_dev,
1231 pEndpoint->UL_PipeID);
1232 }
1233
Venkateswara Swamy Bandaru9e66f4f2016-10-29 17:13:52 +05301234 if (pEndpoint->service_id != WMI_CONTROL_SVC) {
1235 LOCK_HTC_TX(target);
1236 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001237
1238 }
1239
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001240 /* done with this endpoint, we can clear the count */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301241 qdf_atomic_init(&pEndpoint->TxProcessCount);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001242
Rajeev Kumare37820e2016-04-14 17:30:56 -07001243 UNLOCK_HTC_TX(target);
1244
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001245 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send: \n"));
1246
1247 return HTC_SEND_QUEUE_OK;
1248}
1249
1250#ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED
Yue Mab16cf302016-03-08 18:30:25 -08001251static uint16_t htc_send_pkts_sched_check(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID id)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001252{
1253 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1254 HTC_ENDPOINT *pEndpoint;
1255 HTC_ENDPOINT_ID eid;
1256 HTC_PACKET_QUEUE *pTxQueue;
Yue Mab16cf302016-03-08 18:30:25 -08001257 uint16_t resources;
1258 uint16_t acQueueStatus[DATA_EP_SIZE] = { 0, 0, 0, 0 };
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001259
1260 if (id < ENDPOINT_2 || id > ENDPOINT_5) {
1261 return 1;
1262 }
1263
1264 for (eid = ENDPOINT_2; eid <= ENDPOINT_5; eid++) {
Houston Hoffman29573d92015-10-20 17:49:44 -07001265 pEndpoint = &target->endpoint[eid];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001266 pTxQueue = &pEndpoint->TxQueue;
1267
1268 if (HTC_QUEUE_EMPTY(pTxQueue)) {
1269 acQueueStatus[eid - 2] = 1;
1270 }
1271 }
1272
1273 switch (id) {
1274 case ENDPOINT_2: /* BE */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301275 return acQueueStatus[0] && acQueueStatus[2]
1276 && acQueueStatus[3];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001277 case ENDPOINT_3: /* BK */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301278 return acQueueStatus[0] && acQueueStatus[1] && acQueueStatus[2]
1279 && acQueueStatus[3];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001280 case ENDPOINT_4: /* VI */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301281 return acQueueStatus[2] && acQueueStatus[3];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001282 case ENDPOINT_5: /* VO */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301283 return acQueueStatus[3];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001284 default:
1285 return 0;
1286 }
1287
1288}
1289
1290static A_STATUS htc_send_pkts_sched_queue(HTC_TARGET *target,
1291 HTC_PACKET_QUEUE *pPktQueue,
1292 HTC_ENDPOINT_ID eid)
1293{
1294 HTC_ENDPOINT *pEndpoint;
1295 HTC_PACKET_QUEUE *pTxQueue;
1296 HTC_PACKET *pPacket;
1297 int goodPkts;
1298
Houston Hoffman29573d92015-10-20 17:49:44 -07001299 pEndpoint = &target->endpoint[eid];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001300 pTxQueue = &pEndpoint->TxQueue;
1301
1302 LOCK_HTC_TX(target);
1303
1304 goodPkts =
1305 pEndpoint->MaxTxQueueDepth -
1306 HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
1307
1308 if (goodPkts > 0) {
1309 while (!HTC_QUEUE_EMPTY(pPktQueue)) {
1310 pPacket = htc_packet_dequeue(pPktQueue);
1311 HTC_PACKET_ENQUEUE(pTxQueue, pPacket);
1312 goodPkts--;
1313
1314 if (goodPkts <= 0) {
1315 break;
1316 }
1317 }
1318 }
1319
1320 if (HTC_PACKET_QUEUE_DEPTH(pPktQueue)) {
1321 ITERATE_OVER_LIST_ALLOW_REMOVE(&pPktQueue->QueueHead, pPacket,
1322 HTC_PACKET, ListLink) {
1323
1324 if (pEndpoint->EpCallBacks.
1325 EpSendFull(pEndpoint->EpCallBacks.pContext,
1326 pPacket) == HTC_SEND_FULL_DROP) {
1327 INC_HTC_EP_STAT(pEndpoint, TxDropped, 1);
1328 } else {
1329 HTC_PACKET_REMOVE(pPktQueue, pPacket);
1330 HTC_PACKET_ENQUEUE(pTxQueue, pPacket);
1331 }
1332 }
1333 ITERATE_END;
1334 }
1335
1336 UNLOCK_HTC_TX(target);
1337
1338 return A_OK;
1339}
1340
1341#endif
1342
1343A_STATUS htc_send_pkts_multiple(HTC_HANDLE HTCHandle, HTC_PACKET_QUEUE *pPktQueue)
1344{
1345 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1346 HTC_ENDPOINT *pEndpoint;
1347 HTC_PACKET *pPacket;
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301348 qdf_nbuf_t netbuf;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001349 HTC_FRAME_HDR *pHtcHdr;
1350
1351 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1352 ("+htc_send_pkts_multiple: Queue: %p, Pkts %d \n",
1353 pPktQueue, HTC_PACKET_QUEUE_DEPTH(pPktQueue)));
1354
1355 /* get packet at head to figure out which endpoint these packets will go into */
1356 pPacket = htc_get_pkt_at_head(pPktQueue);
1357 if (NULL == pPacket) {
1358 OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, GET_HTC_PKT_Q_FAIL);
1359 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_send_pkts_multiple \n"));
1360 return A_EINVAL;
1361 }
1362
1363 AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX);
Houston Hoffman29573d92015-10-20 17:49:44 -07001364 pEndpoint = &target->endpoint[pPacket->Endpoint];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001365
Houston Hoffman4f2f4592015-10-20 18:00:29 -07001366 if (!pEndpoint->service_id) {
1367 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s service_id is invalid\n",
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001368 __func__));
1369 return A_EINVAL;
1370 }
1371
1372#ifdef HTC_EP_STAT_PROFILING
1373 LOCK_HTC_TX(target);
1374 INC_HTC_EP_STAT(pEndpoint, TxPosted, HTC_PACKET_QUEUE_DEPTH(pPktQueue));
1375 UNLOCK_HTC_TX(target);
1376#endif
1377
1378 /* provide room in each packet's netbuf for the HTC frame header */
1379 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue, pPacket) {
1380 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
1381 AR_DEBUG_ASSERT(netbuf);
1382
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301383 qdf_nbuf_push_head(netbuf, sizeof(HTC_FRAME_HDR));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001384 /* setup HTC frame header */
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301385 pHtcHdr = (HTC_FRAME_HDR *) qdf_nbuf_get_frag_vaddr(netbuf, 0);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001386 AR_DEBUG_ASSERT(pHtcHdr);
1387 HTC_WRITE32(pHtcHdr,
1388 SM(pPacket->ActualLength,
1389 HTC_FRAME_HDR_PAYLOADLEN) | SM(pPacket->Endpoint,
1390 HTC_FRAME_HDR_ENDPOINTID));
1391
1392 LOCK_HTC_TX(target);
1393
1394 pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo;
1395 pEndpoint->SeqNo++;
1396
Yue Mab16cf302016-03-08 18:30:25 -08001397 HTC_WRITE32(((uint32_t *) pHtcHdr) + 1,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001398 SM(pPacket->PktInfo.AsTx.SeqNo,
1399 HTC_FRAME_HDR_CONTROLBYTES1));
1400
1401 UNLOCK_HTC_TX(target);
1402 /*
1403 * Now that the HTC frame header has been added, the netbuf can be
1404 * mapped. This only applies to non-data frames, since data frames
1405 * were already mapped as they entered into the driver.
1406 */
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301407 qdf_nbuf_map(target->osdev,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001408 GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket),
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301409 QDF_DMA_TO_DEVICE);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001410
1411 pPacket->PktInfo.AsTx.Flags |= HTC_TX_PACKET_FLAG_FIXUP_NETBUF;
1412 }
1413 HTC_PACKET_QUEUE_ITERATE_END;
1414
1415#ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED
1416 if (!htc_send_pkts_sched_check(HTCHandle, pEndpoint->Id)) {
1417 htc_send_pkts_sched_queue(HTCHandle, pPktQueue, pEndpoint->Id);
1418 } else {
1419 htc_try_send(target, pEndpoint, pPktQueue);
1420 }
1421#else
1422 htc_try_send(target, pEndpoint, pPktQueue);
1423#endif
1424
1425 /* do completion on any packets that couldn't get in */
1426 if (!HTC_QUEUE_EMPTY(pPktQueue)) {
1427
1428 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue, pPacket) {
1429 /* remove the headroom reserved for HTC_FRAME_HDR */
1430 restore_tx_packet(target, pPacket);
1431
1432 if (HTC_STOPPING(target)) {
1433 pPacket->Status = A_ECANCELED;
1434 } else {
1435 pPacket->Status = A_NO_RESOURCE;
1436 }
1437 }
1438 HTC_PACKET_QUEUE_ITERATE_END;
1439
1440 do_send_completion(pEndpoint, pPktQueue);
1441 }
1442
1443 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_send_pkts_multiple \n"));
1444
1445 return A_OK;
1446}
1447
1448/* HTC API - htc_send_pkt */
1449A_STATUS htc_send_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket)
1450{
1451 HTC_PACKET_QUEUE queue;
1452
Karthick Sdc40a352015-10-14 18:14:15 +05301453 if (HTCHandle == NULL || pPacket == NULL) {
1454 return A_ERROR;
1455 }
1456
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001457 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1458 ("+-htc_send_pkt: Enter endPointId: %d, buffer: %p, length: %d \n",
1459 pPacket->Endpoint, pPacket->pBuffer,
1460 pPacket->ActualLength));
1461 INIT_HTC_PACKET_QUEUE_AND_ADD(&queue, pPacket);
1462 return htc_send_pkts_multiple(HTCHandle, &queue);
1463}
1464
1465#ifdef ATH_11AC_TXCOMPACT
Mohit Khanna0f6194e2016-05-17 15:30:44 -07001466/**
1467 * htc_send_data_pkt() - send single data packet on an endpoint
1468 * @HTCHandle: pointer to HTC handle
1469 * @netbuf: network buffer containing the data to be sent
1470 * @ActualLength: length of data that needs to be transmitted
1471 *
1472 * Return: A_OK for success or an appropriate A_STATUS error
1473 */
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301474A_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, qdf_nbuf_t netbuf, int Epid,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001475 int ActualLength)
1476{
1477 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1478 HTC_ENDPOINT *pEndpoint;
1479 HTC_FRAME_HDR *pHtcHdr;
1480 A_STATUS status = A_OK;
1481 int tx_resources;
1482 uint32_t data_attr = 0;
1483
Houston Hoffman29573d92015-10-20 17:49:44 -07001484 pEndpoint = &target->endpoint[Epid];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001485
1486 tx_resources =
1487 hif_get_free_queue_number(target->hif_dev, pEndpoint->UL_PipeID);
1488
1489 if (tx_resources < HTC_DATA_RESOURCE_THRS) {
1490 if (pEndpoint->ul_is_polled) {
1491 hif_send_complete_check(pEndpoint->target->hif_dev,
1492 pEndpoint->UL_PipeID, 1);
1493 tx_resources =
1494 hif_get_free_queue_number(target->hif_dev,
1495 pEndpoint->UL_PipeID);
1496 }
1497 if (tx_resources < HTC_DATA_MINDESC_PERPACKET) {
1498 return A_ERROR;
1499 }
1500 }
1501
Houston Hoffmanc5141b02015-11-18 02:36:30 -08001502 if (hif_pm_runtime_get(target->hif_dev))
1503 return A_ERROR;
1504
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301505 pHtcHdr = (HTC_FRAME_HDR *) qdf_nbuf_get_frag_vaddr(netbuf, 0);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001506 AR_DEBUG_ASSERT(pHtcHdr);
1507
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301508 data_attr = qdf_nbuf_data_attr_get(netbuf);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001509
1510 HTC_WRITE32(pHtcHdr, SM(ActualLength, HTC_FRAME_HDR_PAYLOADLEN) |
1511 SM(Epid, HTC_FRAME_HDR_ENDPOINTID));
1512 /*
1513 * If the HIF pipe for the data endpoint is polled rather than
1514 * interrupt-driven, this is a good point to check whether any
1515 * data previously sent through the HIF pipe have finished being
1516 * sent.
1517 * Since this may result in callbacks to htc_tx_completion_handler,
1518 * which can take the HTC tx lock, make the hif_send_complete_check
1519 * call before acquiring the HTC tx lock.
1520 * Call hif_send_complete_check directly, rather than calling
1521 * htc_send_complete_check, and call the PollTimerStart separately
1522 * after calling hif_send_head, so the timer will be started to
1523 * check for completion of the new outstanding download (in the
1524 * unexpected event that other polling calls don't catch it).
1525 */
1526
1527 LOCK_HTC_TX(target);
1528
Yue Mab16cf302016-03-08 18:30:25 -08001529 HTC_WRITE32(((uint32_t *) pHtcHdr) + 1,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001530 SM(pEndpoint->SeqNo, HTC_FRAME_HDR_CONTROLBYTES1));
1531
1532 pEndpoint->SeqNo++;
1533
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301534 QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_HTC);
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301535 DPTRACE(qdf_dp_trace(netbuf, QDF_DP_TRACE_HTC_PACKET_PTR_RECORD,
Nirav Shaheaa20d82016-04-25 18:01:05 +05301536 qdf_nbuf_data_addr(netbuf),
Nirav Shah29beae02016-04-26 22:58:54 +05301537 sizeof(qdf_nbuf_data(netbuf)), QDF_TX));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001538 status = hif_send_head(target->hif_dev,
1539 pEndpoint->UL_PipeID,
1540 pEndpoint->Id, ActualLength, netbuf, data_attr);
1541
1542 UNLOCK_HTC_TX(target);
1543 return status;
1544}
1545#else /*ATH_11AC_TXCOMPACT */
1546
Mohit Khanna0f6194e2016-05-17 15:30:44 -07001547/**
1548 * htc_send_data_pkt() - htc_send_data_pkt
1549 * @HTCHandle: pointer to HTC handle
1550 * @pPacket: pointer to HTC_PACKET
1551 * @more_data: indicates whether more data is to follow
1552 *
1553 * Return: A_OK for success or an appropriate A_STATUS error
1554 */
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001555A_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket,
Yue Mab16cf302016-03-08 18:30:25 -08001556 uint8_t more_data)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001557{
1558 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1559 HTC_ENDPOINT *pEndpoint;
1560 HTC_FRAME_HDR *pHtcHdr;
1561 HTC_PACKET_QUEUE sendQueue;
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301562 qdf_nbuf_t netbuf = NULL;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001563 int tx_resources;
1564 A_STATUS status = A_OK;
1565 uint32_t data_attr = 0;
1566
1567 if (pPacket) {
1568 AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX);
Houston Hoffman29573d92015-10-20 17:49:44 -07001569 pEndpoint = &target->endpoint[pPacket->Endpoint];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001570
1571 /* add HTC_FRAME_HDR in the initial fragment */
1572 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301573 pHtcHdr = (HTC_FRAME_HDR *) qdf_nbuf_get_frag_vaddr(netbuf, 0);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001574 AR_DEBUG_ASSERT(pHtcHdr);
1575
1576 HTC_WRITE32(pHtcHdr,
1577 SM(pPacket->ActualLength,
1578 HTC_FRAME_HDR_PAYLOADLEN) | SM(pPacket->PktInfo.
1579 AsTx.SendFlags,
1580 HTC_FRAME_HDR_FLAGS)
1581 | SM(pPacket->Endpoint, HTC_FRAME_HDR_ENDPOINTID));
1582 /*
1583 * If the HIF pipe for the data endpoint is polled rather than
1584 * interrupt-driven, this is a good point to check whether any
1585 * data previously sent through the HIF pipe have finished being
1586 * sent.
1587 * Since this may result in callbacks to htc_tx_completion_handler,
1588 * which can take the HTC tx lock, make the hif_send_complete_check
1589 * call before acquiring the HTC tx lock.
1590 * Call hif_send_complete_check directly, rather than calling
1591 * htc_send_complete_check, and call the PollTimerStart separately
1592 * after calling hif_send_head, so the timer will be started to
1593 * check for completion of the new outstanding download (in the
1594 * unexpected event that other polling calls don't catch it).
1595 */
1596 if (pEndpoint->ul_is_polled) {
1597 htc_send_complete_poll_timer_stop(pEndpoint);
1598 hif_send_complete_check(pEndpoint->target->hif_dev,
1599 pEndpoint->UL_PipeID, 0);
1600 }
1601
1602 LOCK_HTC_TX(target);
1603
1604 pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo;
1605 pEndpoint->SeqNo++;
1606
Yue Mab16cf302016-03-08 18:30:25 -08001607 HTC_WRITE32(((uint32_t *) pHtcHdr) + 1,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001608 SM(pPacket->PktInfo.AsTx.SeqNo,
1609 HTC_FRAME_HDR_CONTROLBYTES1));
1610
1611 /* append new packet to pEndpoint->TxQueue */
1612 HTC_PACKET_ENQUEUE(&pEndpoint->TxQueue, pPacket);
Mohit Khanna0f6194e2016-05-17 15:30:44 -07001613 if (HTC_TX_BUNDLE_ENABLED(target) && (more_data)) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001614 UNLOCK_HTC_TX(target);
1615 return A_OK;
1616 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001617 } else {
1618 LOCK_HTC_TX(target);
Houston Hoffman29573d92015-10-20 17:49:44 -07001619 pEndpoint = &target->endpoint[1];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001620 }
1621
1622 /* increment tx processing count on entry */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301623 qdf_atomic_inc(&pEndpoint->TxProcessCount);
1624 if (qdf_atomic_read(&pEndpoint->TxProcessCount) > 1) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001625 /*
1626 * Another thread or task is draining the TX queues on this endpoint.
1627 * That thread will reset the tx processing count when the queue is
1628 * drained.
1629 */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301630 qdf_atomic_dec(&pEndpoint->TxProcessCount);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001631 UNLOCK_HTC_TX(target);
1632 return A_OK;
1633 }
1634
1635 /***** beyond this point only 1 thread may enter ******/
1636
1637 INIT_HTC_PACKET_QUEUE(&sendQueue);
1638 if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
1639#if DEBUG_CREDIT
1640 int cred = pEndpoint->TxCredits;
1641#endif
1642 get_htc_send_packets_credit_based(target, pEndpoint, &sendQueue);
1643#if DEBUG_CREDIT
1644 if (ep_debug_mask & (1 << pEndpoint->Id)) {
1645 if (cred - pEndpoint->TxCredits > 0) {
1646 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
1647 (" <HTC> Decrease EP%d %d - %d = %d credits.\n",
1648 pEndpoint->Id, cred,
1649 cred - pEndpoint->TxCredits,
1650 pEndpoint->TxCredits));
1651 }
1652 }
1653#endif
1654 UNLOCK_HTC_TX(target);
1655 }
Mohit Khanna0f6194e2016-05-17 15:30:44 -07001656
1657 else if (HTC_TX_BUNDLE_ENABLED(target)) {
1658
1659 if ((hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB) &&
1660 hif_get_free_queue_number(target->hif_dev,
1661 pEndpoint->UL_PipeID)) {
1662 /*
1663 * Header and payload belongs to the different fragments
1664 * and consume 2 resource for one HTC package but USB
1665 * combine into one transfer.
1666 */
1667 get_htc_send_packets(target, pEndpoint, &sendQueue,
1668 (HTC_MAX_MSG_PER_BUNDLE_TX * 2));
1669 } else {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001670 /* Dequeue max packets from endpoint tx queue */
1671 get_htc_send_packets(target, pEndpoint, &sendQueue,
1672 HTC_MAX_TX_BUNDLE_SEND_LIMIT);
Mohit Khanna0f6194e2016-05-17 15:30:44 -07001673 }
1674
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001675 UNLOCK_HTC_TX(target);
1676 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001677 else {
1678 /*
1679 * Now drain the endpoint TX queue for transmission as long as we have
1680 * enough transmit resources
1681 */
1682 tx_resources =
1683 hif_get_free_queue_number(target->hif_dev,
1684 pEndpoint->UL_PipeID);
1685 get_htc_send_packets(target, pEndpoint, &sendQueue, tx_resources);
1686 UNLOCK_HTC_TX(target);
1687 }
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301688 QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_HTC);
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301689 DPTRACE(qdf_dp_trace(netbuf, QDF_DP_TRACE_HTC_PACKET_PTR_RECORD,
Nirav Shaheaa20d82016-04-25 18:01:05 +05301690 qdf_nbuf_data_addr(netbuf),
Nirav Shah29beae02016-04-26 22:58:54 +05301691 sizeof(qdf_nbuf_data(netbuf)), QDF_TX));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001692
1693 /* send what we can */
1694 while (true) {
Mohit Khanna0f6194e2016-05-17 15:30:44 -07001695 if (HTC_TX_BUNDLE_ENABLED(target) &&
1696 (HTC_PACKET_QUEUE_DEPTH(&sendQueue) >=
1697 HTC_MIN_MSG_PER_BUNDLE) &&
1698 (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_SDIO ||
1699 hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB)) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001700 htc_issue_packets_bundle(target, pEndpoint, &sendQueue);
1701 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001702 pPacket = htc_packet_dequeue(&sendQueue);
1703 if (pPacket == NULL) {
1704 break;
1705 }
1706 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
1707
1708 LOCK_HTC_TX(target);
1709 /* store in look up queue to match completions */
1710 HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacket);
1711 INC_HTC_EP_STAT(pEndpoint, TxIssued, 1);
1712 pEndpoint->ul_outstanding_cnt++;
1713 UNLOCK_HTC_TX(target);
1714
1715 status = hif_send_head(target->hif_dev,
1716 pEndpoint->UL_PipeID,
1717 pEndpoint->Id,
1718 HTC_HDR_LENGTH + pPacket->ActualLength,
1719 netbuf, data_attr);
1720#if DEBUG_BUNDLE
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301721 qdf_print(" Send single EP%d buffer size:0x%x, total:0x%x.\n",
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001722 pEndpoint->Id,
1723 pEndpoint->TxCreditSize,
1724 HTC_HDR_LENGTH + pPacket->ActualLength);
1725#endif
1726
Poddar, Siddarthdf030092016-04-28 11:41:57 +05301727 htc_issue_tx_bundle_stats_inc(target);
1728
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301729 if (qdf_unlikely(A_FAILED(status))) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001730 LOCK_HTC_TX(target);
1731 pEndpoint->ul_outstanding_cnt--;
1732 /* remove this packet from the tx completion queue */
1733 HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacket);
1734
1735 /*
1736 * Don't bother reclaiming credits - HTC flow control
1737 * is not applicable to tx data.
1738 * In LL systems, there is no download flow control,
1739 * since there's virtually no download delay.
1740 * In HL systems, the txrx SW explicitly performs the
1741 * tx flow control.
1742 */
1743 /* pEndpoint->TxCredits += pPacket->PktInfo.AsTx.CreditsUsed; */
1744
1745 /* put this frame back at the front of the sendQueue */
1746 HTC_PACKET_ENQUEUE_TO_HEAD(&sendQueue, pPacket);
1747
1748 /* put the sendQueue back at the front of pEndpoint->TxQueue */
1749 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue,
1750 &sendQueue);
1751 UNLOCK_HTC_TX(target);
1752 break; /* still need to reset TxProcessCount */
1753 }
1754 }
1755 /* done with this endpoint, we can clear the count */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301756 qdf_atomic_init(&pEndpoint->TxProcessCount);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001757
1758 if (pEndpoint->ul_is_polled) {
1759 /*
1760 * Start a cleanup timer to poll for download completion.
1761 * The download completion should be noticed promptly from
1762 * other polling calls, but the timer provides a safety net
1763 * in case other polling calls don't occur as expected.
1764 */
1765 htc_send_complete_poll_timer_start(pEndpoint);
1766 }
1767
1768 return status;
1769}
1770#endif /*ATH_11AC_TXCOMPACT */
1771
1772/*
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301773 * In the adapted HIF layer, qdf_nbuf_t are passed between HIF and HTC,
1774 * since upper layers expects HTC_PACKET containers we use the completed netbuf
1775 * and lookup its corresponding HTC packet buffer from a lookup list.
1776 * This is extra overhead that can be fixed by re-aligning HIF interfaces
1777 * with HTC.
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001778 *
1779 */
1780static HTC_PACKET *htc_lookup_tx_packet(HTC_TARGET *target,
1781 HTC_ENDPOINT *pEndpoint,
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301782 qdf_nbuf_t netbuf)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001783{
1784 HTC_PACKET *pPacket = NULL;
1785 HTC_PACKET *pFoundPacket = NULL;
1786 HTC_PACKET_QUEUE lookupQueue;
1787
1788 INIT_HTC_PACKET_QUEUE(&lookupQueue);
1789 LOCK_HTC_TX(target);
1790
1791 /* mark that HIF has indicated the send complete for another packet */
1792 pEndpoint->ul_outstanding_cnt--;
1793
1794 /* Dequeue first packet directly because of in-order completion */
1795 pPacket = htc_packet_dequeue(&pEndpoint->TxLookupQueue);
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301796 if (qdf_unlikely(!pPacket)) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001797 UNLOCK_HTC_TX(target);
1798 return NULL;
1799 }
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301800 if (netbuf == (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket)) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001801 UNLOCK_HTC_TX(target);
1802 return pPacket;
1803 } else {
1804 HTC_PACKET_ENQUEUE(&lookupQueue, pPacket);
1805 }
1806
1807 /*
1808 * Move TX lookup queue to temp queue because most of packets that are not index 0
1809 * are not top 10 packets.
1810 */
1811 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&lookupQueue,
1812 &pEndpoint->TxLookupQueue);
1813 UNLOCK_HTC_TX(target);
1814
1815 ITERATE_OVER_LIST_ALLOW_REMOVE(&lookupQueue.QueueHead, pPacket,
1816 HTC_PACKET, ListLink) {
1817
1818 if (NULL == pPacket) {
1819 pFoundPacket = pPacket;
1820 break;
1821 }
1822 /* check for removal */
1823 if (netbuf ==
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301824 (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket)) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001825 /* found it */
1826 HTC_PACKET_REMOVE(&lookupQueue, pPacket);
1827 pFoundPacket = pPacket;
1828 break;
1829 }
1830
1831 }
1832 ITERATE_END;
1833
1834 LOCK_HTC_TX(target);
1835 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxLookupQueue,
1836 &lookupQueue);
1837 UNLOCK_HTC_TX(target);
1838
1839 return pFoundPacket;
1840}
1841
Mohit Khanna0f6194e2016-05-17 15:30:44 -07001842/**
1843 * htc_tx_completion_handler() - htc tx completion handler
1844 * @Context: pointer to HTC_TARGET structure
1845 * @netbuf: pointer to netbuf for which completion handler is being called
1846 * @EpID: end point Id on which the packet was sent
1847 * @toeplitz_hash_result: toeplitz hash result
1848 *
1849 * Return: QDF_STATUS_SUCCESS for success or an appropriate QDF_STATUS error
1850 */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301851QDF_STATUS htc_tx_completion_handler(void *Context,
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +05301852 qdf_nbuf_t netbuf, unsigned int EpID,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001853 uint32_t toeplitz_hash_result)
1854{
1855 HTC_TARGET *target = (HTC_TARGET *) Context;
1856 HTC_ENDPOINT *pEndpoint;
1857 HTC_PACKET *pPacket;
1858#ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301859 HTC_ENDPOINT_ID eid[DATA_EP_SIZE] = { ENDPOINT_5, ENDPOINT_4,
1860 ENDPOINT_2, ENDPOINT_3 };
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001861 int epidIdx;
Yue Mab16cf302016-03-08 18:30:25 -08001862 uint16_t resourcesThresh[DATA_EP_SIZE]; /* urb resources */
1863 uint16_t resources;
1864 uint16_t resourcesMax;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001865#endif
1866
Houston Hoffman29573d92015-10-20 17:49:44 -07001867 pEndpoint = &target->endpoint[EpID];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001868 target->TX_comp_cnt++;
1869
1870 do {
1871 pPacket = htc_lookup_tx_packet(target, pEndpoint, netbuf);
1872 if (NULL == pPacket) {
1873 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
1874 ("HTC TX lookup failed!\n"));
1875 /* may have already been flushed and freed */
1876 netbuf = NULL;
1877 break;
1878 }
Houston Hoffmanc5141b02015-11-18 02:36:30 -08001879 if (pPacket->PktInfo.AsTx.Tag != HTC_TX_PACKET_TAG_AUTO_PM)
1880 hif_pm_runtime_put(target->hif_dev);
1881
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001882 if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_BUNDLED) {
1883 HTC_PACKET *pPacketTemp;
1884 HTC_PACKET_QUEUE *pQueueSave =
1885 (HTC_PACKET_QUEUE *) pPacket->pContext;
1886 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pQueueSave,
1887 pPacketTemp) {
1888 pPacket->Status = A_OK;
1889 send_packet_completion(target, pPacketTemp);
1890 }
1891 HTC_PACKET_QUEUE_ITERATE_END;
1892 free_htc_bundle_packet(target, pPacket);
Mohit Khanna0f6194e2016-05-17 15:30:44 -07001893
1894 if (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB) {
1895 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint))
1896 htc_try_send(target, pEndpoint, NULL);
1897 }
1898
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301899 return QDF_STATUS_SUCCESS;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001900 }
1901 /* will be giving this buffer back to upper layers */
1902 netbuf = NULL;
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301903 pPacket->Status = QDF_STATUS_SUCCESS;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001904 send_packet_completion(target, pPacket);
1905
1906 } while (false);
1907
1908 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
1909 /* note: when using TX credit flow, the re-checking of queues happens
1910 * when credits flow back from the target.
1911 * in the non-TX credit case, we recheck after the packet completes */
Venkateswara Swamy Bandaru9e66f4f2016-10-29 17:13:52 +05301912 if ((qdf_atomic_read(&pEndpoint->TxProcessCount) == 0) ||
1913 (pEndpoint->service_id != WMI_CONTROL_SVC)) {
1914 htc_try_send(target, pEndpoint, NULL);
1915 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001916 }
1917
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05301918 return QDF_STATUS_SUCCESS;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001919}
1920
Poddar, Siddarthdf030092016-04-28 11:41:57 +05301921#ifdef WLAN_FEATURE_FASTPATH
Houston Hoffman93481862016-05-05 18:49:59 -07001922/**
1923 * htc_ctrl_msg_cmpl(): checks for tx completion for the endpoint specified
1924 * @HTC_HANDLE : pointer to the htc target context
1925 * @htc_ep_id : end point id
1926 *
1927 * checks HTC tx completion
1928 *
1929 * Return: none
1930 */
1931void htc_ctrl_msg_cmpl(HTC_HANDLE htc_pdev, HTC_ENDPOINT_ID htc_ep_id)
1932{
1933 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_pdev);
1934 HTC_ENDPOINT *pendpoint = &target->endpoint[htc_ep_id];
1935
1936 htc_send_complete_check(pendpoint, 1);
1937}
1938#endif
1939
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001940/* callback when TX resources become available */
Yue Mab16cf302016-03-08 18:30:25 -08001941void htc_tx_resource_avail_handler(void *context, uint8_t pipeID)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001942{
1943 int i;
1944 HTC_TARGET *target = (HTC_TARGET *) context;
1945 HTC_ENDPOINT *pEndpoint = NULL;
1946
1947 for (i = 0; i < ENDPOINT_MAX; i++) {
Houston Hoffman29573d92015-10-20 17:49:44 -07001948 pEndpoint = &target->endpoint[i];
Houston Hoffman4f2f4592015-10-20 18:00:29 -07001949 if (pEndpoint->service_id != 0) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001950 if (pEndpoint->UL_PipeID == pipeID) {
1951 break;
1952 }
1953 }
1954 }
1955
1956 if (i >= ENDPOINT_MAX) {
1957 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
1958 ("Invalid pipe indicated for TX resource avail : %d!\n",
1959 pipeID));
1960 return;
1961 }
1962
1963 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1964 ("HIF indicated more resources for pipe:%d \n",
1965 pipeID));
1966
1967 htc_try_send(target, pEndpoint, NULL);
1968}
1969
Yue Maec9e71c2016-02-26 18:52:20 -08001970#ifdef FEATURE_RUNTIME_PM
Houston Hoffman47e387b2015-10-20 17:04:42 -07001971/**
1972 * htc_kick_queues(): resumes tx transactions of suspended endpoints
1973 * @context: pointer to the htc target context
1974 *
1975 * Iterates throught the enpoints and provides a context to empty queues
1976 * int the hif layer when they are stalled due to runtime suspend.
1977 *
1978 * Return: none
1979 */
1980void htc_kick_queues(void *context)
1981{
1982 int i;
1983 HTC_TARGET *target = (HTC_TARGET *)context;
1984 HTC_ENDPOINT *endpoint = NULL;
1985
1986 for (i = 0; i < ENDPOINT_MAX; i++) {
1987 endpoint = &target->endpoint[i];
1988
1989 if (endpoint->service_id == 0)
1990 continue;
1991
1992 if (endpoint->EpCallBacks.ep_resume_tx_queue)
1993 endpoint->EpCallBacks.ep_resume_tx_queue(
1994 endpoint->EpCallBacks.pContext);
1995
1996 htc_try_send(target, endpoint, NULL);
1997 }
1998}
Yue Maec9e71c2016-02-26 18:52:20 -08001999#endif
Houston Hoffman47e387b2015-10-20 17:04:42 -07002000
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08002001/* flush endpoint TX queue */
2002void htc_flush_endpoint_tx(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint,
2003 HTC_TX_TAG Tag)
2004{
2005 HTC_PACKET *pPacket;
2006
2007 LOCK_HTC_TX(target);
2008 while (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) {
2009 pPacket = htc_packet_dequeue(&pEndpoint->TxQueue);
2010
2011 if (pPacket) {
2012 /* let the sender know the packet was not delivered */
2013 pPacket->Status = A_ECANCELED;
2014 send_packet_completion(target, pPacket);
2015 }
2016 }
2017 UNLOCK_HTC_TX(target);
2018}
2019
2020/* HTC API to flush an endpoint's TX queue*/
2021void htc_flush_endpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint,
2022 HTC_TX_TAG Tag)
2023{
2024 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
Houston Hoffman29573d92015-10-20 17:49:44 -07002025 HTC_ENDPOINT *pEndpoint = &target->endpoint[Endpoint];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08002026
Houston Hoffman4f2f4592015-10-20 18:00:29 -07002027 if (pEndpoint->service_id == 0) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08002028 AR_DEBUG_ASSERT(false);
2029 /* not in use.. */
2030 return;
2031 }
2032
2033 htc_flush_endpoint_tx(target, pEndpoint, Tag);
2034}
2035
2036/* HTC API to indicate activity to the credit distribution function */
2037void htc_indicate_activity_change(HTC_HANDLE HTCHandle,
Yue Mab16cf302016-03-08 18:30:25 -08002038 HTC_ENDPOINT_ID Endpoint, bool Active)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08002039{
2040 /* TODO */
2041}
2042
Yue Mab16cf302016-03-08 18:30:25 -08002043bool htc_is_endpoint_active(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08002044{
2045 return true;
2046}
2047
gbianb417db22016-09-30 17:01:07 +08002048void htc_set_nodrop_pkt(HTC_HANDLE HTCHandle, A_BOOL isNodropPkt)
2049{
2050 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
2051 target->is_nodrop_pkt = isNodropPkt;
2052}
2053
Mohit Khanna0f6194e2016-05-17 15:30:44 -07002054/**
2055 * htc_process_credit_rpt() - process credit report, call distribution function
2056 * @target: pointer to HTC_TARGET
2057 * @pRpt: pointer to HTC_CREDIT_REPORT
2058 * @NumEntries: number of entries in credit report
2059 * @FromEndpoint: endpoint for which credit report is received
2060 *
2061 * Return: A_OK for success or an appropriate A_STATUS error
2062 */
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08002063void htc_process_credit_rpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt,
2064 int NumEntries, HTC_ENDPOINT_ID FromEndpoint)
2065{
2066 int i;
2067 HTC_ENDPOINT *pEndpoint;
2068 int totalCredits = 0;
Yue Mab16cf302016-03-08 18:30:25 -08002069 uint8_t rpt_credits, rpt_ep_id;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08002070
2071 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
2072 ("+htc_process_credit_rpt, Credit Report Entries:%d \n",
2073 NumEntries));
2074
2075 /* lock out TX while we update credits */
2076 LOCK_HTC_TX(target);
2077
2078 for (i = 0; i < NumEntries; i++, pRpt++) {
2079
2080 rpt_ep_id = HTC_GET_FIELD(pRpt, HTC_CREDIT_REPORT, ENDPOINTID);
2081
2082 if (rpt_ep_id >= ENDPOINT_MAX) {
2083 AR_DEBUG_ASSERT(false);
2084 break;
2085 }
2086
2087 rpt_credits = HTC_GET_FIELD(pRpt, HTC_CREDIT_REPORT, CREDITS);
2088
Houston Hoffman29573d92015-10-20 17:49:44 -07002089 pEndpoint = &target->endpoint[rpt_ep_id];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08002090#if DEBUG_CREDIT
2091 if (ep_debug_mask & (1 << pEndpoint->Id)) {
2092 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
2093 (" <HTC> Increase EP%d %d + %d = %d credits\n",
2094 rpt_ep_id, pEndpoint->TxCredits,
2095 rpt_credits,
2096 pEndpoint->TxCredits + rpt_credits));
2097 }
2098#endif
2099
2100#ifdef HTC_EP_STAT_PROFILING
2101
2102 INC_HTC_EP_STAT(pEndpoint, TxCreditRpts, 1);
2103 INC_HTC_EP_STAT(pEndpoint, TxCreditsReturned, rpt_credits);
2104
2105 if (FromEndpoint == rpt_ep_id) {
2106 /* this credit report arrived on the same endpoint indicating it arrived in an RX
2107 * packet */
2108 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromRx,
2109 rpt_credits);
2110 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromRx, 1);
2111 } else if (FromEndpoint == ENDPOINT_0) {
2112 /* this credit arrived on endpoint 0 as a NULL message */
2113 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromEp0,
2114 rpt_credits);
2115 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromEp0, 1);
2116 } else {
2117 /* arrived on another endpoint */
2118 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromOther,
2119 rpt_credits);
2120 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromOther, 1);
2121 }
2122
2123#endif
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08002124
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08002125 pEndpoint->TxCredits += rpt_credits;
2126
Houston Hoffman4f2f4592015-10-20 18:00:29 -07002127 if (pEndpoint->service_id == WMI_CONTROL_SVC) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08002128 LOCK_HTC_CREDIT(target);
2129 htc_credit_record(HTC_PROCESS_CREDIT_REPORT,
2130 pEndpoint->TxCredits,
2131 HTC_PACKET_QUEUE_DEPTH(&pEndpoint->
2132 TxQueue));
2133 UNLOCK_HTC_CREDIT(target);
2134 }
2135
2136 if (pEndpoint->TxCredits
2137 && HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) {
2138 UNLOCK_HTC_TX(target);
2139#ifdef ATH_11AC_TXCOMPACT
2140 htc_try_send(target, pEndpoint, NULL);
2141#else
Houston Hoffman4f2f4592015-10-20 18:00:29 -07002142 if (pEndpoint->service_id == HTT_DATA_MSG_SVC) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08002143 htc_send_data_pkt(target, NULL, 0);
2144 } else {
2145 htc_try_send(target, pEndpoint, NULL);
2146 }
2147#endif
2148 LOCK_HTC_TX(target);
2149 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08002150 totalCredits += rpt_credits;
2151 }
2152
2153 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
2154 (" Report indicated %d credits to distribute \n",
2155 totalCredits));
2156
2157 UNLOCK_HTC_TX(target);
2158
2159 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_process_credit_rpt \n"));
2160}
2161
2162/* function to fetch stats from htc layer*/
2163struct ol_ath_htc_stats *ieee80211_ioctl_get_htc_stats(HTC_HANDLE HTCHandle)
2164{
2165 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
2166
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +05302167 return &(target->htc_pkt_stats);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08002168}