blob: b4ccb7c1f3a703ed7dcc2d08b7c228c702cc11ec [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
39A_STATUS htc_connect_service(HTC_HANDLE HTCHandle,
40 HTC_SERVICE_CONNECT_REQ *pConnectReq,
41 HTC_SERVICE_CONNECT_RESP *pConnectResp)
42{
43 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
44 A_STATUS status = A_OK;
45 HTC_PACKET *pSendPacket = NULL;
46 HTC_CONNECT_SERVICE_RESPONSE_MSG *pResponseMsg;
47 HTC_CONNECT_SERVICE_MSG *pConnectMsg;
48 HTC_ENDPOINT_ID assignedEndpoint = ENDPOINT_MAX;
49 HTC_ENDPOINT *pEndpoint;
50 unsigned int maxMsgSize = 0;
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +053051 qdf_nbuf_t netbuf;
Yue Mab16cf302016-03-08 18:30:25 -080052 uint8_t txAlloc;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080053 int length;
Yue Mab16cf302016-03-08 18:30:25 -080054 bool disableCreditFlowCtrl = false;
55 uint16_t conn_flags;
56 uint16_t rsp_msg_id, rsp_msg_serv_id, rsp_msg_max_msg_size;
57 uint8_t rsp_msg_status, rsp_msg_end_id, rsp_msg_serv_meta_len;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080058
59 AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
Houston Hoffman4f2f4592015-10-20 18:00:29 -070060 ("+htc_connect_service, target:%p SvcID:0x%X\n", target,
61 pConnectReq->service_id));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080062
63 do {
64
Houston Hoffman4f2f4592015-10-20 18:00:29 -070065 AR_DEBUG_ASSERT(pConnectReq->service_id != 0);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080066
Houston Hoffman4f2f4592015-10-20 18:00:29 -070067 if (HTC_CTRL_RSVD_SVC == pConnectReq->service_id) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080068 /* special case for pseudo control service */
69 assignedEndpoint = ENDPOINT_0;
70 maxMsgSize = HTC_MAX_CONTROL_MESSAGE_LENGTH;
71 txAlloc = 0;
72
73 } else {
74
Houston Hoffman4f2f4592015-10-20 18:00:29 -070075 txAlloc = htc_get_credit_allocation(target,
76 pConnectReq->service_id);
77
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080078 if (!txAlloc) {
79 AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
80 ("Service %d does not allocate target credits!\n",
Houston Hoffman4f2f4592015-10-20 18:00:29 -070081 pConnectReq->service_id));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080082 }
83
84 /* allocate a packet to send to the target */
85 pSendPacket = htc_alloc_control_tx_packet(target);
86
87 if (NULL == pSendPacket) {
88 AR_DEBUG_ASSERT(false);
89 status = A_NO_MEMORY;
90 break;
91 }
92
93 netbuf =
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +053094 (qdf_nbuf_t)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080095 GET_HTC_PACKET_NET_BUF_CONTEXT(pSendPacket);
96 length =
97 sizeof(HTC_CONNECT_SERVICE_MSG) +
98 pConnectReq->MetaDataLength;
99
100 /* assemble connect service message */
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530101 qdf_nbuf_put_tail(netbuf, length);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800102 pConnectMsg =
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530103 (HTC_CONNECT_SERVICE_MSG *) qdf_nbuf_data(netbuf);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800104
105 if (NULL == pConnectMsg) {
106 AR_DEBUG_ASSERT(0);
107 status = A_EFAULT;
108 break;
109 }
110
Yue Mab16cf302016-03-08 18:30:25 -0800111 qdf_mem_zero(pConnectMsg,
112 sizeof(HTC_CONNECT_SERVICE_MSG));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800113
114 conn_flags =
115 (pConnectReq->
116 ConnectionFlags & ~HTC_SET_RECV_ALLOC_MASK) |
117 HTC_CONNECT_FLAGS_SET_RECV_ALLOCATION(txAlloc);
118 HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
119 MESSAGEID, HTC_MSG_CONNECT_SERVICE_ID);
120 HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700121 SERVICE_ID, pConnectReq->service_id);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800122 HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
123 CONNECTIONFLAGS, conn_flags);
124
125 if (pConnectReq->
126 ConnectionFlags &
127 HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL) {
128 disableCreditFlowCtrl = true;
129 }
Yue Ma9be730f2016-03-08 17:40:42 -0800130
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800131 if (!htc_credit_flow) {
132 disableCreditFlowCtrl = true;
133 }
Yue Ma9be730f2016-03-08 17:40:42 -0800134
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800135 /* check caller if it wants to transfer meta data */
136 if ((pConnectReq->pMetaData != NULL) &&
137 (pConnectReq->MetaDataLength <=
138 HTC_SERVICE_META_DATA_MAX_LENGTH)) {
139 /* copy meta data into message buffer (after header ) */
Yue Mab16cf302016-03-08 18:30:25 -0800140 qdf_mem_copy((uint8_t *) pConnectMsg +
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800141 sizeof(HTC_CONNECT_SERVICE_MSG),
142 pConnectReq->pMetaData,
143 pConnectReq->MetaDataLength);
144
145 HTC_SET_FIELD(pConnectMsg,
146 HTC_CONNECT_SERVICE_MSG,
147 SERVICEMETALENGTH,
148 pConnectReq->MetaDataLength);
149 }
150
151 SET_HTC_PACKET_INFO_TX(pSendPacket,
152 NULL,
Yue Mab16cf302016-03-08 18:30:25 -0800153 (uint8_t *) pConnectMsg,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800154 length,
155 ENDPOINT_0,
156 HTC_SERVICE_TX_PACKET_TAG);
157
158 status = htc_send_pkt((HTC_HANDLE) target, pSendPacket);
159 /* we don't own it anymore */
160 pSendPacket = NULL;
161 if (A_FAILED(status)) {
162 break;
163 }
164
165 /* wait for response */
166 status = htc_wait_recv_ctrl_message(target);
167 if (A_FAILED(status)) {
168 break;
169 }
170 /* we controlled the buffer creation so it has to be properly aligned */
171 pResponseMsg =
172 (HTC_CONNECT_SERVICE_RESPONSE_MSG *) target->
173 CtrlResponseBuffer;
174
175 rsp_msg_id = HTC_GET_FIELD(pResponseMsg,
176 HTC_CONNECT_SERVICE_RESPONSE_MSG,
177 MESSAGEID);
178 rsp_msg_serv_id =
179 HTC_GET_FIELD(pResponseMsg,
180 HTC_CONNECT_SERVICE_RESPONSE_MSG,
181 SERVICEID);
182 rsp_msg_status =
183 HTC_GET_FIELD(pResponseMsg,
184 HTC_CONNECT_SERVICE_RESPONSE_MSG,
185 STATUS);
186 rsp_msg_end_id =
187 HTC_GET_FIELD(pResponseMsg,
188 HTC_CONNECT_SERVICE_RESPONSE_MSG,
189 ENDPOINTID);
190 rsp_msg_max_msg_size =
191 HTC_GET_FIELD(pResponseMsg,
192 HTC_CONNECT_SERVICE_RESPONSE_MSG,
193 MAXMSGSIZE);
194 rsp_msg_serv_meta_len =
195 HTC_GET_FIELD(pResponseMsg,
196 HTC_CONNECT_SERVICE_RESPONSE_MSG,
197 SERVICEMETALENGTH);
198
199 if ((rsp_msg_id != HTC_MSG_CONNECT_SERVICE_RESPONSE_ID)
200 || (target->CtrlResponseLength <
201 sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG))) {
202 /* this message is not valid */
203 AR_DEBUG_ASSERT(false);
204 status = A_EPROTO;
205 break;
206 }
207
208 AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
209 ("htc_connect_service, service 0x%X connect response from target status:%d, assigned ep: %d\n",
210 rsp_msg_serv_id, rsp_msg_status,
211 rsp_msg_end_id));
212
213 pConnectResp->ConnectRespCode = rsp_msg_status;
214
215 /* check response status */
216 if (rsp_msg_status != HTC_SERVICE_SUCCESS) {
217 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
218 (" Target failed service 0x%X connect request (status:%d)\n",
219 rsp_msg_serv_id,
220 rsp_msg_status));
221 status = A_EPROTO;
222#ifdef QCA_TX_HTT2_SUPPORT
223 /* Keep work and not to block the control message. */
224 target->CtrlResponseProcessing = false;
225#endif /* QCA_TX_HTT2_SUPPORT */
226 break;
227 }
228
229 assignedEndpoint = (HTC_ENDPOINT_ID) rsp_msg_end_id;
230 maxMsgSize = rsp_msg_max_msg_size;
231
232 if ((pConnectResp->pMetaData != NULL) &&
233 (rsp_msg_serv_meta_len > 0) &&
234 (rsp_msg_serv_meta_len <=
235 HTC_SERVICE_META_DATA_MAX_LENGTH)) {
236 /* caller supplied a buffer and the target responded with data */
237 int copyLength =
238 min((int)pConnectResp->BufferLength,
239 (int)rsp_msg_serv_meta_len);
240 /* copy the meta data */
Yue Mab16cf302016-03-08 18:30:25 -0800241 qdf_mem_copy(pConnectResp->pMetaData,
242 ((uint8_t *) pResponseMsg) +
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800243 sizeof
244 (HTC_CONNECT_SERVICE_RESPONSE_MSG),
245 copyLength);
246 pConnectResp->ActualLength = copyLength;
247 }
248 /* done processing response buffer */
249 target->CtrlResponseProcessing = false;
250 }
251
252 /* the rest of these are parameter checks so set the error status */
253 status = A_EPROTO;
254
255 if (assignedEndpoint >= ENDPOINT_MAX) {
256 AR_DEBUG_ASSERT(false);
257 break;
258 }
259
260 if (0 == maxMsgSize) {
261 AR_DEBUG_ASSERT(false);
262 break;
263 }
264
Houston Hoffman29573d92015-10-20 17:49:44 -0700265 pEndpoint = &target->endpoint[assignedEndpoint];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800266 pEndpoint->Id = assignedEndpoint;
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700267 if (pEndpoint->service_id != 0) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800268 /* endpoint already in use! */
269 AR_DEBUG_ASSERT(false);
270 break;
271 }
272
273 /* return assigned endpoint to caller */
274 pConnectResp->Endpoint = assignedEndpoint;
275 pConnectResp->MaxMsgLength = maxMsgSize;
276
277 /* setup the endpoint */
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700278 /* service_id marks the endpoint in use */
279 pEndpoint->service_id = pConnectReq->service_id;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800280 pEndpoint->MaxTxQueueDepth = pConnectReq->MaxSendQueueDepth;
281 pEndpoint->MaxMsgLength = maxMsgSize;
282 pEndpoint->TxCredits = txAlloc;
283 pEndpoint->TxCreditSize = target->TargetCreditSize;
284 pEndpoint->TxCreditsPerMaxMsg =
285 maxMsgSize / target->TargetCreditSize;
286 if (maxMsgSize % target->TargetCreditSize) {
287 pEndpoint->TxCreditsPerMaxMsg++;
288 }
289#if DEBUG_CREDIT
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530290 qdf_print(" Endpoint%d initial credit:%d, size:%d.\n",
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800291 pEndpoint->Id, pEndpoint->TxCredits,
292 pEndpoint->TxCreditSize);
293#endif
294
295 /* copy all the callbacks */
296 pEndpoint->EpCallBacks = pConnectReq->EpCallbacks;
297
298 status = hif_map_service_to_pipe(target->hif_dev,
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700299 pEndpoint->service_id,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800300 &pEndpoint->UL_PipeID,
301 &pEndpoint->DL_PipeID,
302 &pEndpoint->ul_is_polled,
303 &pEndpoint->dl_is_polled);
304 if (A_FAILED(status)) {
305 break;
306 }
307
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530308 qdf_assert(!pEndpoint->dl_is_polled); /* not currently supported */
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800309
310 if (pEndpoint->ul_is_polled) {
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530311 qdf_timer_init(target->osdev,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800312 &pEndpoint->ul_poll_timer,
313 htc_send_complete_check_cleanup,
314 pEndpoint,
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530315 QDF_TIMER_TYPE_SW);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800316 }
317
318 AR_DEBUG_PRINTF(ATH_DEBUG_SETUP,
319 ("HTC Service:0x%4.4X, ULpipe:%d DLpipe:%d id:%d Ready\n",
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700320 pEndpoint->service_id, pEndpoint->UL_PipeID,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800321 pEndpoint->DL_PipeID, pEndpoint->Id));
322
323 if (disableCreditFlowCtrl && pEndpoint->TxCreditFlowEnabled) {
324 pEndpoint->TxCreditFlowEnabled = false;
325 AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
326 ("HTC Service:0x%4.4X ep:%d TX flow control disabled\n",
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700327 pEndpoint->service_id,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800328 assignedEndpoint));
329 }
330
331 } while (false);
332
Komal Seelamf8600682016-02-02 18:17:13 +0530333 if (HTT_SERVICE_GROUP == (pConnectReq->service_id >> 8))
Houston Hoffmand2ac86c2016-03-14 21:11:41 -0700334 hif_save_htc_htt_config_endpoint(target->hif_dev,
335 assignedEndpoint);
Komal Seelamf8600682016-02-02 18:17:13 +0530336
337 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_connect_service\n"));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800338
339 return status;
340}
341
342void htc_set_credit_distribution(HTC_HANDLE HTCHandle,
343 void *pCreditDistContext,
344 HTC_CREDIT_DIST_CALLBACK CreditDistFunc,
345 HTC_CREDIT_INIT_CALLBACK CreditInitFunc,
346 HTC_SERVICE_ID ServicePriorityOrder[],
347 int ListLength)
348{
349 /* NOT Supported, this transport does not use a credit based flow control mechanism */
350
351}
352
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530353void htc_fw_event_handler(void *context, QDF_STATUS status)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800354{
355 HTC_TARGET *target = (HTC_TARGET *) context;
356 HTC_INIT_INFO *initInfo = &target->HTCInitInfo;
357
358 /* check if target failure handler exists and pass error code to it. */
359 if (target->HTCInitInfo.TargetFailure != NULL) {
360 initInfo->TargetFailure(initInfo->pContext, status);
361 }
362}