blob: 0ddf398af5ddaa78bed7b8f1708ab98f230d6614 [file] [log] [blame]
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001/*
Komal Seelamf8600682016-02-02 18:17:13 +05302 * 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 <hif.h>
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +053031#include <qdf_nbuf.h> /* qdf_nbuf_t */
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080032
33/* use credit flow control over HTC */
34unsigned int htc_credit_flow = 1;
35#ifndef DEBUG_CREDIT
36#define DEBUG_CREDIT 0
37#endif
38
Houston Hoffmanfb698ef2016-05-05 19:50:44 -070039/* HTC credit flow global disable */
40void htc_global_credit_flow_disable(void)
41{
42 htc_credit_flow = 0;
43}
44
45/* HTC credit flow global enable */
46void htc_global_credit_flow_enable(void)
47{
48 htc_credit_flow = 1;
49}
50
Poddar, Siddarthdf030092016-04-28 11:41:57 +053051#ifdef HIF_SDIO
52
53/**
54 * htc_alt_data_credit_size_update() - update tx credit size info
55 * on max bundle size
56 * @target: hif context
57 * @ul_pipe: endpoint ul pipe id
58 * @dl_pipe: endpoint dl pipe id
59 * @txCreditSize: endpoint tx credit size
60 *
61 *
62 * When AltDataCreditSize is non zero, it indicates the credit size for
63 * HTT and all other services on Mbox0. Mbox1 has WMI_CONTROL_SVC which
64 * uses the default credit size. Use AltDataCreditSize only when
65 * mailbox is swapped. Mailbox swap bit is set by bmi_target_ready at
66 * the end of BMI phase.
67 *
68 * The Credit Size is a parameter associated with the mbox rather than
69 * a service. Multiple services can run on this mbox.
70 *
71 * If AltDataCreditSize is 0, that means the firmware doesn't support
72 * this feature. Default to the TargetCreditSize
73 *
74 * Return: None
75 */
76static inline void
77htc_alt_data_credit_size_update(HTC_TARGET *target,
78 uint8_t *ul_pipe,
79 uint8_t *dl_pipe,
80 int *txCreditSize)
81{
82 if ((target->AltDataCreditSize) &&
83 (*ul_pipe == 1) && (*dl_pipe == 0))
84 *txCreditSize = target->AltDataCreditSize;
85
86 return;
87}
88#else
89
90static inline void
91htc_alt_data_credit_size_update(HTC_TARGET *target,
92 uint8_t *ul_pipe,
93 uint8_t *dl_pipe,
94 int *txCreditSize)
95{
96 return;
97}
98#endif
99
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800100A_STATUS htc_connect_service(HTC_HANDLE HTCHandle,
101 HTC_SERVICE_CONNECT_REQ *pConnectReq,
102 HTC_SERVICE_CONNECT_RESP *pConnectResp)
103{
104 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
105 A_STATUS status = A_OK;
106 HTC_PACKET *pSendPacket = NULL;
107 HTC_CONNECT_SERVICE_RESPONSE_MSG *pResponseMsg;
108 HTC_CONNECT_SERVICE_MSG *pConnectMsg;
109 HTC_ENDPOINT_ID assignedEndpoint = ENDPOINT_MAX;
110 HTC_ENDPOINT *pEndpoint;
111 unsigned int maxMsgSize = 0;
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530112 qdf_nbuf_t netbuf;
Yue Mab16cf302016-03-08 18:30:25 -0800113 uint8_t txAlloc;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800114 int length;
Yue Mab16cf302016-03-08 18:30:25 -0800115 bool disableCreditFlowCtrl = false;
116 uint16_t conn_flags;
117 uint16_t rsp_msg_id, rsp_msg_serv_id, rsp_msg_max_msg_size;
118 uint8_t rsp_msg_status, rsp_msg_end_id, rsp_msg_serv_meta_len;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800119
120 AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700121 ("+htc_connect_service, target:%p SvcID:0x%X\n", target,
122 pConnectReq->service_id));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800123
124 do {
125
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700126 AR_DEBUG_ASSERT(pConnectReq->service_id != 0);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800127
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700128 if (HTC_CTRL_RSVD_SVC == pConnectReq->service_id) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800129 /* special case for pseudo control service */
130 assignedEndpoint = ENDPOINT_0;
131 maxMsgSize = HTC_MAX_CONTROL_MESSAGE_LENGTH;
132 txAlloc = 0;
133
134 } else {
135
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700136 txAlloc = htc_get_credit_allocation(target,
137 pConnectReq->service_id);
138
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800139 if (!txAlloc) {
140 AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
141 ("Service %d does not allocate target credits!\n",
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700142 pConnectReq->service_id));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800143 }
144
145 /* allocate a packet to send to the target */
146 pSendPacket = htc_alloc_control_tx_packet(target);
147
148 if (NULL == pSendPacket) {
149 AR_DEBUG_ASSERT(false);
150 status = A_NO_MEMORY;
151 break;
152 }
153
154 netbuf =
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530155 (qdf_nbuf_t)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800156 GET_HTC_PACKET_NET_BUF_CONTEXT(pSendPacket);
157 length =
158 sizeof(HTC_CONNECT_SERVICE_MSG) +
159 pConnectReq->MetaDataLength;
160
161 /* assemble connect service message */
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530162 qdf_nbuf_put_tail(netbuf, length);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800163 pConnectMsg =
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530164 (HTC_CONNECT_SERVICE_MSG *) qdf_nbuf_data(netbuf);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800165
166 if (NULL == pConnectMsg) {
167 AR_DEBUG_ASSERT(0);
168 status = A_EFAULT;
169 break;
170 }
171
Yue Mab16cf302016-03-08 18:30:25 -0800172 qdf_mem_zero(pConnectMsg,
173 sizeof(HTC_CONNECT_SERVICE_MSG));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800174
175 conn_flags =
176 (pConnectReq->
177 ConnectionFlags & ~HTC_SET_RECV_ALLOC_MASK) |
178 HTC_CONNECT_FLAGS_SET_RECV_ALLOCATION(txAlloc);
179 HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
180 MESSAGEID, HTC_MSG_CONNECT_SERVICE_ID);
181 HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700182 SERVICE_ID, pConnectReq->service_id);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800183 HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
184 CONNECTIONFLAGS, conn_flags);
185
186 if (pConnectReq->
187 ConnectionFlags &
188 HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL) {
189 disableCreditFlowCtrl = true;
190 }
Yue Ma9be730f2016-03-08 17:40:42 -0800191
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800192 if (!htc_credit_flow) {
193 disableCreditFlowCtrl = true;
194 }
Yue Ma9be730f2016-03-08 17:40:42 -0800195
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800196 /* check caller if it wants to transfer meta data */
197 if ((pConnectReq->pMetaData != NULL) &&
198 (pConnectReq->MetaDataLength <=
199 HTC_SERVICE_META_DATA_MAX_LENGTH)) {
200 /* copy meta data into message buffer (after header ) */
Yue Mab16cf302016-03-08 18:30:25 -0800201 qdf_mem_copy((uint8_t *) pConnectMsg +
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800202 sizeof(HTC_CONNECT_SERVICE_MSG),
203 pConnectReq->pMetaData,
204 pConnectReq->MetaDataLength);
205
206 HTC_SET_FIELD(pConnectMsg,
207 HTC_CONNECT_SERVICE_MSG,
208 SERVICEMETALENGTH,
209 pConnectReq->MetaDataLength);
210 }
211
212 SET_HTC_PACKET_INFO_TX(pSendPacket,
213 NULL,
Yue Mab16cf302016-03-08 18:30:25 -0800214 (uint8_t *) pConnectMsg,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800215 length,
216 ENDPOINT_0,
217 HTC_SERVICE_TX_PACKET_TAG);
218
219 status = htc_send_pkt((HTC_HANDLE) target, pSendPacket);
220 /* we don't own it anymore */
221 pSendPacket = NULL;
222 if (A_FAILED(status)) {
223 break;
224 }
225
226 /* wait for response */
227 status = htc_wait_recv_ctrl_message(target);
228 if (A_FAILED(status)) {
229 break;
230 }
231 /* we controlled the buffer creation so it has to be properly aligned */
232 pResponseMsg =
233 (HTC_CONNECT_SERVICE_RESPONSE_MSG *) target->
234 CtrlResponseBuffer;
235
236 rsp_msg_id = HTC_GET_FIELD(pResponseMsg,
237 HTC_CONNECT_SERVICE_RESPONSE_MSG,
238 MESSAGEID);
239 rsp_msg_serv_id =
240 HTC_GET_FIELD(pResponseMsg,
241 HTC_CONNECT_SERVICE_RESPONSE_MSG,
242 SERVICEID);
243 rsp_msg_status =
244 HTC_GET_FIELD(pResponseMsg,
245 HTC_CONNECT_SERVICE_RESPONSE_MSG,
246 STATUS);
247 rsp_msg_end_id =
248 HTC_GET_FIELD(pResponseMsg,
249 HTC_CONNECT_SERVICE_RESPONSE_MSG,
250 ENDPOINTID);
251 rsp_msg_max_msg_size =
252 HTC_GET_FIELD(pResponseMsg,
253 HTC_CONNECT_SERVICE_RESPONSE_MSG,
254 MAXMSGSIZE);
255 rsp_msg_serv_meta_len =
256 HTC_GET_FIELD(pResponseMsg,
257 HTC_CONNECT_SERVICE_RESPONSE_MSG,
258 SERVICEMETALENGTH);
259
260 if ((rsp_msg_id != HTC_MSG_CONNECT_SERVICE_RESPONSE_ID)
261 || (target->CtrlResponseLength <
262 sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG))) {
263 /* this message is not valid */
264 AR_DEBUG_ASSERT(false);
265 status = A_EPROTO;
266 break;
267 }
268
269 AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
270 ("htc_connect_service, service 0x%X connect response from target status:%d, assigned ep: %d\n",
271 rsp_msg_serv_id, rsp_msg_status,
272 rsp_msg_end_id));
273
274 pConnectResp->ConnectRespCode = rsp_msg_status;
275
276 /* check response status */
277 if (rsp_msg_status != HTC_SERVICE_SUCCESS) {
278 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
279 (" Target failed service 0x%X connect request (status:%d)\n",
280 rsp_msg_serv_id,
281 rsp_msg_status));
282 status = A_EPROTO;
Houston Hoffmane6330442016-02-26 12:19:11 -0800283/* TODO: restore the ifdef when FW supports services 301 and 302 (HTT_MSG_DATA[23]_MSG_SVC)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800284#ifdef QCA_TX_HTT2_SUPPORT
Houston Hoffmane6330442016-02-26 12:19:11 -0800285*/
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800286 /* Keep work and not to block the control message. */
287 target->CtrlResponseProcessing = false;
Houston Hoffmane6330442016-02-26 12:19:11 -0800288/*#endif */ /* QCA_TX_HTT2_SUPPORT */
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800289 break;
290 }
291
292 assignedEndpoint = (HTC_ENDPOINT_ID) rsp_msg_end_id;
293 maxMsgSize = rsp_msg_max_msg_size;
294
295 if ((pConnectResp->pMetaData != NULL) &&
296 (rsp_msg_serv_meta_len > 0) &&
297 (rsp_msg_serv_meta_len <=
298 HTC_SERVICE_META_DATA_MAX_LENGTH)) {
299 /* caller supplied a buffer and the target responded with data */
300 int copyLength =
301 min((int)pConnectResp->BufferLength,
302 (int)rsp_msg_serv_meta_len);
303 /* copy the meta data */
Yue Mab16cf302016-03-08 18:30:25 -0800304 qdf_mem_copy(pConnectResp->pMetaData,
305 ((uint8_t *) pResponseMsg) +
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800306 sizeof
307 (HTC_CONNECT_SERVICE_RESPONSE_MSG),
308 copyLength);
309 pConnectResp->ActualLength = copyLength;
310 }
311 /* done processing response buffer */
312 target->CtrlResponseProcessing = false;
313 }
314
315 /* the rest of these are parameter checks so set the error status */
316 status = A_EPROTO;
317
318 if (assignedEndpoint >= ENDPOINT_MAX) {
319 AR_DEBUG_ASSERT(false);
320 break;
321 }
322
323 if (0 == maxMsgSize) {
324 AR_DEBUG_ASSERT(false);
325 break;
326 }
327
Houston Hoffman29573d92015-10-20 17:49:44 -0700328 pEndpoint = &target->endpoint[assignedEndpoint];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800329 pEndpoint->Id = assignedEndpoint;
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700330 if (pEndpoint->service_id != 0) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800331 /* endpoint already in use! */
332 AR_DEBUG_ASSERT(false);
333 break;
334 }
335
336 /* return assigned endpoint to caller */
337 pConnectResp->Endpoint = assignedEndpoint;
338 pConnectResp->MaxMsgLength = maxMsgSize;
339
340 /* setup the endpoint */
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700341 /* service_id marks the endpoint in use */
342 pEndpoint->service_id = pConnectReq->service_id;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800343 pEndpoint->MaxTxQueueDepth = pConnectReq->MaxSendQueueDepth;
344 pEndpoint->MaxMsgLength = maxMsgSize;
345 pEndpoint->TxCredits = txAlloc;
346 pEndpoint->TxCreditSize = target->TargetCreditSize;
347 pEndpoint->TxCreditsPerMaxMsg =
348 maxMsgSize / target->TargetCreditSize;
349 if (maxMsgSize % target->TargetCreditSize) {
350 pEndpoint->TxCreditsPerMaxMsg++;
351 }
352#if DEBUG_CREDIT
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530353 qdf_print(" Endpoint%d initial credit:%d, size:%d.\n",
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800354 pEndpoint->Id, pEndpoint->TxCredits,
355 pEndpoint->TxCreditSize);
356#endif
357
358 /* copy all the callbacks */
359 pEndpoint->EpCallBacks = pConnectReq->EpCallbacks;
Venkateswara Swamy Bandaruae41b9e2016-11-21 15:06:24 +0530360 pEndpoint->async_update = 0;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800361
362 status = hif_map_service_to_pipe(target->hif_dev,
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700363 pEndpoint->service_id,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800364 &pEndpoint->UL_PipeID,
365 &pEndpoint->DL_PipeID,
366 &pEndpoint->ul_is_polled,
367 &pEndpoint->dl_is_polled);
368 if (A_FAILED(status)) {
369 break;
370 }
371
Poddar, Siddarthdf030092016-04-28 11:41:57 +0530372 htc_alt_data_credit_size_update(target,
373 &pEndpoint->UL_PipeID,
374 &pEndpoint->DL_PipeID,
375 &pEndpoint->TxCreditSize);
376
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530377 qdf_assert(!pEndpoint->dl_is_polled); /* not currently supported */
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800378
379 if (pEndpoint->ul_is_polled) {
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530380 qdf_timer_init(target->osdev,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800381 &pEndpoint->ul_poll_timer,
382 htc_send_complete_check_cleanup,
383 pEndpoint,
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530384 QDF_TIMER_TYPE_SW);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800385 }
386
387 AR_DEBUG_PRINTF(ATH_DEBUG_SETUP,
388 ("HTC Service:0x%4.4X, ULpipe:%d DLpipe:%d id:%d Ready\n",
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700389 pEndpoint->service_id, pEndpoint->UL_PipeID,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800390 pEndpoint->DL_PipeID, pEndpoint->Id));
391
392 if (disableCreditFlowCtrl && pEndpoint->TxCreditFlowEnabled) {
393 pEndpoint->TxCreditFlowEnabled = false;
394 AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
395 ("HTC Service:0x%4.4X ep:%d TX flow control disabled\n",
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700396 pEndpoint->service_id,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800397 assignedEndpoint));
398 }
399
400 } while (false);
401
Komal Seelamf8600682016-02-02 18:17:13 +0530402 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_connect_service\n"));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800403
404 return status;
405}
406
407void htc_set_credit_distribution(HTC_HANDLE HTCHandle,
408 void *pCreditDistContext,
409 HTC_CREDIT_DIST_CALLBACK CreditDistFunc,
410 HTC_CREDIT_INIT_CALLBACK CreditInitFunc,
411 HTC_SERVICE_ID ServicePriorityOrder[],
412 int ListLength)
413{
414 /* NOT Supported, this transport does not use a credit based flow control mechanism */
415
416}
417
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530418void htc_fw_event_handler(void *context, QDF_STATUS status)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800419{
420 HTC_TARGET *target = (HTC_TARGET *) context;
421 HTC_INIT_INFO *initInfo = &target->HTCInitInfo;
422
423 /* check if target failure handler exists and pass error code to it. */
424 if (target->HTCInitInfo.TargetFailure != NULL) {
425 initInfo->TargetFailure(initInfo->pContext, status);
426 }
427}
Venkateswara Swamy Bandaruae41b9e2016-11-21 15:06:24 +0530428
429
430void htc_set_async_ep(HTC_HANDLE HTCHandle,
431 HTC_ENDPOINT_ID htc_ep_id, bool value)
432{
433 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
434 HTC_ENDPOINT *pEndpoint = &target->endpoint[htc_ep_id];
435
436 pEndpoint->async_update = value;
437 qdf_print("%s: htc_handle %p, ep %d, value %d\n", __func__,
438 HTCHandle, htc_ep_id, value);
439}
440