blob: d2cb0dd27851c6dd1968723e01f560da35b930f1 [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"
30#include <cdf_nbuf.h> /* cdf_nbuf_t */
31#include "hif.h"
32
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
Komal Seelamf8600682016-02-02 18:17:13 +053039/**
40 * htc_update_htc_htt_config - API to update HIF with the HTT endpoint info
41 * @target: HTC handle
42 * @endpoint: Endpoint on which HTT messages flow
43 *
44 * Return: void
45 */
46#ifdef HIF_PCI
47void htc_update_htc_htt_config(HTC_TARGET *target, int endpoint)
48{
49 hif_save_htc_htt_config_endpoint(target->hif_dev, endpoint);
50}
51#else
52void htc_update_htc_htt_config(HTC_TARGET *target, int endpoint)
53{
54}
55#endif
56
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080057A_STATUS htc_connect_service(HTC_HANDLE HTCHandle,
58 HTC_SERVICE_CONNECT_REQ *pConnectReq,
59 HTC_SERVICE_CONNECT_RESP *pConnectResp)
60{
61 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
62 A_STATUS status = A_OK;
63 HTC_PACKET *pSendPacket = NULL;
64 HTC_CONNECT_SERVICE_RESPONSE_MSG *pResponseMsg;
65 HTC_CONNECT_SERVICE_MSG *pConnectMsg;
66 HTC_ENDPOINT_ID assignedEndpoint = ENDPOINT_MAX;
67 HTC_ENDPOINT *pEndpoint;
68 unsigned int maxMsgSize = 0;
69 cdf_nbuf_t netbuf;
70 A_UINT8 txAlloc;
71 int length;
72 A_BOOL disableCreditFlowCtrl = false;
73 A_UINT16 conn_flags;
74 A_UINT16 rsp_msg_id, rsp_msg_serv_id, rsp_msg_max_msg_size;
75 A_UINT8 rsp_msg_status, rsp_msg_end_id, rsp_msg_serv_meta_len;
76
77 AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
Houston Hoffman4f2f4592015-10-20 18:00:29 -070078 ("+htc_connect_service, target:%p SvcID:0x%X\n", target,
79 pConnectReq->service_id));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080080
81 do {
82
Houston Hoffman4f2f4592015-10-20 18:00:29 -070083 AR_DEBUG_ASSERT(pConnectReq->service_id != 0);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080084
Houston Hoffman4f2f4592015-10-20 18:00:29 -070085 if (HTC_CTRL_RSVD_SVC == pConnectReq->service_id) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080086 /* special case for pseudo control service */
87 assignedEndpoint = ENDPOINT_0;
88 maxMsgSize = HTC_MAX_CONTROL_MESSAGE_LENGTH;
89 txAlloc = 0;
90
91 } else {
92
Houston Hoffman4f2f4592015-10-20 18:00:29 -070093 txAlloc = htc_get_credit_allocation(target,
94 pConnectReq->service_id);
95
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080096 if (!txAlloc) {
97 AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
98 ("Service %d does not allocate target credits!\n",
Houston Hoffman4f2f4592015-10-20 18:00:29 -070099 pConnectReq->service_id));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800100 }
101
102 /* allocate a packet to send to the target */
103 pSendPacket = htc_alloc_control_tx_packet(target);
104
105 if (NULL == pSendPacket) {
106 AR_DEBUG_ASSERT(false);
107 status = A_NO_MEMORY;
108 break;
109 }
110
111 netbuf =
112 (cdf_nbuf_t)
113 GET_HTC_PACKET_NET_BUF_CONTEXT(pSendPacket);
114 length =
115 sizeof(HTC_CONNECT_SERVICE_MSG) +
116 pConnectReq->MetaDataLength;
117
118 /* assemble connect service message */
119 cdf_nbuf_put_tail(netbuf, length);
120 pConnectMsg =
121 (HTC_CONNECT_SERVICE_MSG *) cdf_nbuf_data(netbuf);
122
123 if (NULL == pConnectMsg) {
124 AR_DEBUG_ASSERT(0);
125 status = A_EFAULT;
126 break;
127 }
128
129 A_MEMZERO(pConnectMsg, sizeof(HTC_CONNECT_SERVICE_MSG));
130
131 conn_flags =
132 (pConnectReq->
133 ConnectionFlags & ~HTC_SET_RECV_ALLOC_MASK) |
134 HTC_CONNECT_FLAGS_SET_RECV_ALLOCATION(txAlloc);
135 HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
136 MESSAGEID, HTC_MSG_CONNECT_SERVICE_ID);
137 HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700138 SERVICE_ID, pConnectReq->service_id);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800139 HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
140 CONNECTIONFLAGS, conn_flags);
141
142 if (pConnectReq->
143 ConnectionFlags &
144 HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL) {
145 disableCreditFlowCtrl = true;
146 }
147#if defined(HIF_USB)
148 if (!htc_credit_flow) {
149 disableCreditFlowCtrl = true;
150 }
151#else
152 /* Only enable credit for WMI service */
153 if (!htc_credit_flow
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700154 && pConnectReq->service_id != WMI_CONTROL_SVC) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800155 disableCreditFlowCtrl = true;
156 }
157#endif
158 /* check caller if it wants to transfer meta data */
159 if ((pConnectReq->pMetaData != NULL) &&
160 (pConnectReq->MetaDataLength <=
161 HTC_SERVICE_META_DATA_MAX_LENGTH)) {
162 /* copy meta data into message buffer (after header ) */
163 A_MEMCPY((A_UINT8 *) pConnectMsg +
164 sizeof(HTC_CONNECT_SERVICE_MSG),
165 pConnectReq->pMetaData,
166 pConnectReq->MetaDataLength);
167
168 HTC_SET_FIELD(pConnectMsg,
169 HTC_CONNECT_SERVICE_MSG,
170 SERVICEMETALENGTH,
171 pConnectReq->MetaDataLength);
172 }
173
174 SET_HTC_PACKET_INFO_TX(pSendPacket,
175 NULL,
176 (A_UINT8 *) pConnectMsg,
177 length,
178 ENDPOINT_0,
179 HTC_SERVICE_TX_PACKET_TAG);
180
181 status = htc_send_pkt((HTC_HANDLE) target, pSendPacket);
182 /* we don't own it anymore */
183 pSendPacket = NULL;
184 if (A_FAILED(status)) {
185 break;
186 }
187
188 /* wait for response */
189 status = htc_wait_recv_ctrl_message(target);
190 if (A_FAILED(status)) {
191 break;
192 }
193 /* we controlled the buffer creation so it has to be properly aligned */
194 pResponseMsg =
195 (HTC_CONNECT_SERVICE_RESPONSE_MSG *) target->
196 CtrlResponseBuffer;
197
198 rsp_msg_id = HTC_GET_FIELD(pResponseMsg,
199 HTC_CONNECT_SERVICE_RESPONSE_MSG,
200 MESSAGEID);
201 rsp_msg_serv_id =
202 HTC_GET_FIELD(pResponseMsg,
203 HTC_CONNECT_SERVICE_RESPONSE_MSG,
204 SERVICEID);
205 rsp_msg_status =
206 HTC_GET_FIELD(pResponseMsg,
207 HTC_CONNECT_SERVICE_RESPONSE_MSG,
208 STATUS);
209 rsp_msg_end_id =
210 HTC_GET_FIELD(pResponseMsg,
211 HTC_CONNECT_SERVICE_RESPONSE_MSG,
212 ENDPOINTID);
213 rsp_msg_max_msg_size =
214 HTC_GET_FIELD(pResponseMsg,
215 HTC_CONNECT_SERVICE_RESPONSE_MSG,
216 MAXMSGSIZE);
217 rsp_msg_serv_meta_len =
218 HTC_GET_FIELD(pResponseMsg,
219 HTC_CONNECT_SERVICE_RESPONSE_MSG,
220 SERVICEMETALENGTH);
221
222 if ((rsp_msg_id != HTC_MSG_CONNECT_SERVICE_RESPONSE_ID)
223 || (target->CtrlResponseLength <
224 sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG))) {
225 /* this message is not valid */
226 AR_DEBUG_ASSERT(false);
227 status = A_EPROTO;
228 break;
229 }
230
231 AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
232 ("htc_connect_service, service 0x%X connect response from target status:%d, assigned ep: %d\n",
233 rsp_msg_serv_id, rsp_msg_status,
234 rsp_msg_end_id));
235
236 pConnectResp->ConnectRespCode = rsp_msg_status;
237
238 /* check response status */
239 if (rsp_msg_status != HTC_SERVICE_SUCCESS) {
240 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
241 (" Target failed service 0x%X connect request (status:%d)\n",
242 rsp_msg_serv_id,
243 rsp_msg_status));
244 status = A_EPROTO;
245#ifdef QCA_TX_HTT2_SUPPORT
246 /* Keep work and not to block the control message. */
247 target->CtrlResponseProcessing = false;
248#endif /* QCA_TX_HTT2_SUPPORT */
249 break;
250 }
251
252 assignedEndpoint = (HTC_ENDPOINT_ID) rsp_msg_end_id;
253 maxMsgSize = rsp_msg_max_msg_size;
254
255 if ((pConnectResp->pMetaData != NULL) &&
256 (rsp_msg_serv_meta_len > 0) &&
257 (rsp_msg_serv_meta_len <=
258 HTC_SERVICE_META_DATA_MAX_LENGTH)) {
259 /* caller supplied a buffer and the target responded with data */
260 int copyLength =
261 min((int)pConnectResp->BufferLength,
262 (int)rsp_msg_serv_meta_len);
263 /* copy the meta data */
264 A_MEMCPY(pConnectResp->pMetaData,
265 ((A_UINT8 *) pResponseMsg) +
266 sizeof
267 (HTC_CONNECT_SERVICE_RESPONSE_MSG),
268 copyLength);
269 pConnectResp->ActualLength = copyLength;
270 }
271 /* done processing response buffer */
272 target->CtrlResponseProcessing = false;
273 }
274
275 /* the rest of these are parameter checks so set the error status */
276 status = A_EPROTO;
277
278 if (assignedEndpoint >= ENDPOINT_MAX) {
279 AR_DEBUG_ASSERT(false);
280 break;
281 }
282
283 if (0 == maxMsgSize) {
284 AR_DEBUG_ASSERT(false);
285 break;
286 }
287
Houston Hoffman29573d92015-10-20 17:49:44 -0700288 pEndpoint = &target->endpoint[assignedEndpoint];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800289 pEndpoint->Id = assignedEndpoint;
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700290 if (pEndpoint->service_id != 0) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800291 /* endpoint already in use! */
292 AR_DEBUG_ASSERT(false);
293 break;
294 }
295
296 /* return assigned endpoint to caller */
297 pConnectResp->Endpoint = assignedEndpoint;
298 pConnectResp->MaxMsgLength = maxMsgSize;
299
300 /* setup the endpoint */
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700301 /* service_id marks the endpoint in use */
302 pEndpoint->service_id = pConnectReq->service_id;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800303 pEndpoint->MaxTxQueueDepth = pConnectReq->MaxSendQueueDepth;
304 pEndpoint->MaxMsgLength = maxMsgSize;
305 pEndpoint->TxCredits = txAlloc;
306 pEndpoint->TxCreditSize = target->TargetCreditSize;
307 pEndpoint->TxCreditsPerMaxMsg =
308 maxMsgSize / target->TargetCreditSize;
309 if (maxMsgSize % target->TargetCreditSize) {
310 pEndpoint->TxCreditsPerMaxMsg++;
311 }
312#if DEBUG_CREDIT
313 cdf_print(" Endpoint%d initial credit:%d, size:%d.\n",
314 pEndpoint->Id, pEndpoint->TxCredits,
315 pEndpoint->TxCreditSize);
316#endif
317
318 /* copy all the callbacks */
319 pEndpoint->EpCallBacks = pConnectReq->EpCallbacks;
320
321 status = hif_map_service_to_pipe(target->hif_dev,
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700322 pEndpoint->service_id,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800323 &pEndpoint->UL_PipeID,
324 &pEndpoint->DL_PipeID,
325 &pEndpoint->ul_is_polled,
326 &pEndpoint->dl_is_polled);
327 if (A_FAILED(status)) {
328 break;
329 }
330
331 cdf_assert(!pEndpoint->dl_is_polled); /* not currently supported */
332
333 if (pEndpoint->ul_is_polled) {
334 cdf_softirq_timer_init(target->osdev,
335 &pEndpoint->ul_poll_timer,
336 htc_send_complete_check_cleanup,
337 pEndpoint,
338 CDF_TIMER_TYPE_SW);
339 }
340
341 AR_DEBUG_PRINTF(ATH_DEBUG_SETUP,
342 ("HTC Service:0x%4.4X, ULpipe:%d DLpipe:%d id:%d Ready\n",
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700343 pEndpoint->service_id, pEndpoint->UL_PipeID,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800344 pEndpoint->DL_PipeID, pEndpoint->Id));
345
346 if (disableCreditFlowCtrl && pEndpoint->TxCreditFlowEnabled) {
347 pEndpoint->TxCreditFlowEnabled = false;
348 AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
349 ("HTC Service:0x%4.4X ep:%d TX flow control disabled\n",
Houston Hoffman4f2f4592015-10-20 18:00:29 -0700350 pEndpoint->service_id,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800351 assignedEndpoint));
352 }
353
354 } while (false);
355
Komal Seelamf8600682016-02-02 18:17:13 +0530356 if (HTT_SERVICE_GROUP == (pConnectReq->service_id >> 8))
357 htc_update_htc_htt_config(target, assignedEndpoint);
358
359 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_connect_service\n"));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800360
361 return status;
362}
363
364void htc_set_credit_distribution(HTC_HANDLE HTCHandle,
365 void *pCreditDistContext,
366 HTC_CREDIT_DIST_CALLBACK CreditDistFunc,
367 HTC_CREDIT_INIT_CALLBACK CreditInitFunc,
368 HTC_SERVICE_ID ServicePriorityOrder[],
369 int ListLength)
370{
371 /* NOT Supported, this transport does not use a credit based flow control mechanism */
372
373}
374
375void htc_fw_event_handler(void *context, CDF_STATUS status)
376{
377 HTC_TARGET *target = (HTC_TARGET *) context;
378 HTC_INIT_INFO *initInfo = &target->HTCInitInfo;
379
380 /* check if target failure handler exists and pass error code to it. */
381 if (target->HTCInitInfo.TargetFailure != NULL) {
382 initInfo->TargetFailure(initInfo->pContext, status);
383 }
384}
385
386/* Disable ASPM : disable PCIe low power */
Komal Seelamf8600682016-02-02 18:17:13 +0530387void htc_disable_aspm(HTC_HANDLE HTCHandle)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800388{
Komal Seelamf8600682016-02-02 18:17:13 +0530389 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
390
391 if (!target->hif_dev)
392 return;
393
394 hif_disable_aspm(target->hif_dev);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800395}