blob: 6d5d30868a4676ee852d8922860a7b6e2d690e7e [file] [log] [blame]
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001/*
2 * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved.
3 *
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
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;
51 cdf_nbuf_t netbuf;
52 A_UINT8 txAlloc;
53 int length;
54 A_BOOL disableCreditFlowCtrl = false;
55 A_UINT16 conn_flags;
56 A_UINT16 rsp_msg_id, rsp_msg_serv_id, rsp_msg_max_msg_size;
57 A_UINT8 rsp_msg_status, rsp_msg_end_id, rsp_msg_serv_meta_len;
58
59 AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
60 ("+htc_connect_service, target:%p SvcID:0x%X \n", target,
61 pConnectReq->ServiceID));
62
63 do {
64
65 AR_DEBUG_ASSERT(pConnectReq->ServiceID != 0);
66
67 if (HTC_CTRL_RSVD_SVC == pConnectReq->ServiceID) {
68 /* special case for pseudo control service */
69 assignedEndpoint = ENDPOINT_0;
70 maxMsgSize = HTC_MAX_CONTROL_MESSAGE_LENGTH;
71 txAlloc = 0;
72
73 } else {
74
75 txAlloc =
76 htc_get_credit_allocation(target,
77 pConnectReq->ServiceID);
78 if (!txAlloc) {
79 AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
80 ("Service %d does not allocate target credits!\n",
81 pConnectReq->ServiceID));
82 }
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 =
94 (cdf_nbuf_t)
95 GET_HTC_PACKET_NET_BUF_CONTEXT(pSendPacket);
96 length =
97 sizeof(HTC_CONNECT_SERVICE_MSG) +
98 pConnectReq->MetaDataLength;
99
100 /* assemble connect service message */
101 cdf_nbuf_put_tail(netbuf, length);
102 pConnectMsg =
103 (HTC_CONNECT_SERVICE_MSG *) cdf_nbuf_data(netbuf);
104
105 if (NULL == pConnectMsg) {
106 AR_DEBUG_ASSERT(0);
107 status = A_EFAULT;
108 break;
109 }
110
111 A_MEMZERO(pConnectMsg, sizeof(HTC_CONNECT_SERVICE_MSG));
112
113 conn_flags =
114 (pConnectReq->
115 ConnectionFlags & ~HTC_SET_RECV_ALLOC_MASK) |
116 HTC_CONNECT_FLAGS_SET_RECV_ALLOCATION(txAlloc);
117 HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
118 MESSAGEID, HTC_MSG_CONNECT_SERVICE_ID);
119 HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
120 SERVICE_ID, pConnectReq->ServiceID);
121 HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
122 CONNECTIONFLAGS, conn_flags);
123
124 if (pConnectReq->
125 ConnectionFlags &
126 HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL) {
127 disableCreditFlowCtrl = true;
128 }
129#if defined(HIF_USB)
130 if (!htc_credit_flow) {
131 disableCreditFlowCtrl = true;
132 }
133#else
134 /* Only enable credit for WMI service */
135 if (!htc_credit_flow
136 && pConnectReq->ServiceID != WMI_CONTROL_SVC) {
137 disableCreditFlowCtrl = true;
138 }
139#endif
140 /* check caller if it wants to transfer meta data */
141 if ((pConnectReq->pMetaData != NULL) &&
142 (pConnectReq->MetaDataLength <=
143 HTC_SERVICE_META_DATA_MAX_LENGTH)) {
144 /* copy meta data into message buffer (after header ) */
145 A_MEMCPY((A_UINT8 *) pConnectMsg +
146 sizeof(HTC_CONNECT_SERVICE_MSG),
147 pConnectReq->pMetaData,
148 pConnectReq->MetaDataLength);
149
150 HTC_SET_FIELD(pConnectMsg,
151 HTC_CONNECT_SERVICE_MSG,
152 SERVICEMETALENGTH,
153 pConnectReq->MetaDataLength);
154 }
155
156 SET_HTC_PACKET_INFO_TX(pSendPacket,
157 NULL,
158 (A_UINT8 *) pConnectMsg,
159 length,
160 ENDPOINT_0,
161 HTC_SERVICE_TX_PACKET_TAG);
162
163 status = htc_send_pkt((HTC_HANDLE) target, pSendPacket);
164 /* we don't own it anymore */
165 pSendPacket = NULL;
166 if (A_FAILED(status)) {
167 break;
168 }
169
170 /* wait for response */
171 status = htc_wait_recv_ctrl_message(target);
172 if (A_FAILED(status)) {
173 break;
174 }
175 /* we controlled the buffer creation so it has to be properly aligned */
176 pResponseMsg =
177 (HTC_CONNECT_SERVICE_RESPONSE_MSG *) target->
178 CtrlResponseBuffer;
179
180 rsp_msg_id = HTC_GET_FIELD(pResponseMsg,
181 HTC_CONNECT_SERVICE_RESPONSE_MSG,
182 MESSAGEID);
183 rsp_msg_serv_id =
184 HTC_GET_FIELD(pResponseMsg,
185 HTC_CONNECT_SERVICE_RESPONSE_MSG,
186 SERVICEID);
187 rsp_msg_status =
188 HTC_GET_FIELD(pResponseMsg,
189 HTC_CONNECT_SERVICE_RESPONSE_MSG,
190 STATUS);
191 rsp_msg_end_id =
192 HTC_GET_FIELD(pResponseMsg,
193 HTC_CONNECT_SERVICE_RESPONSE_MSG,
194 ENDPOINTID);
195 rsp_msg_max_msg_size =
196 HTC_GET_FIELD(pResponseMsg,
197 HTC_CONNECT_SERVICE_RESPONSE_MSG,
198 MAXMSGSIZE);
199 rsp_msg_serv_meta_len =
200 HTC_GET_FIELD(pResponseMsg,
201 HTC_CONNECT_SERVICE_RESPONSE_MSG,
202 SERVICEMETALENGTH);
203
204 if ((rsp_msg_id != HTC_MSG_CONNECT_SERVICE_RESPONSE_ID)
205 || (target->CtrlResponseLength <
206 sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG))) {
207 /* this message is not valid */
208 AR_DEBUG_ASSERT(false);
209 status = A_EPROTO;
210 break;
211 }
212
213 AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
214 ("htc_connect_service, service 0x%X connect response from target status:%d, assigned ep: %d\n",
215 rsp_msg_serv_id, rsp_msg_status,
216 rsp_msg_end_id));
217
218 pConnectResp->ConnectRespCode = rsp_msg_status;
219
220 /* check response status */
221 if (rsp_msg_status != HTC_SERVICE_SUCCESS) {
222 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
223 (" Target failed service 0x%X connect request (status:%d)\n",
224 rsp_msg_serv_id,
225 rsp_msg_status));
226 status = A_EPROTO;
227#ifdef QCA_TX_HTT2_SUPPORT
228 /* Keep work and not to block the control message. */
229 target->CtrlResponseProcessing = false;
230#endif /* QCA_TX_HTT2_SUPPORT */
231 break;
232 }
233
234 assignedEndpoint = (HTC_ENDPOINT_ID) rsp_msg_end_id;
235 maxMsgSize = rsp_msg_max_msg_size;
236
237 if ((pConnectResp->pMetaData != NULL) &&
238 (rsp_msg_serv_meta_len > 0) &&
239 (rsp_msg_serv_meta_len <=
240 HTC_SERVICE_META_DATA_MAX_LENGTH)) {
241 /* caller supplied a buffer and the target responded with data */
242 int copyLength =
243 min((int)pConnectResp->BufferLength,
244 (int)rsp_msg_serv_meta_len);
245 /* copy the meta data */
246 A_MEMCPY(pConnectResp->pMetaData,
247 ((A_UINT8 *) pResponseMsg) +
248 sizeof
249 (HTC_CONNECT_SERVICE_RESPONSE_MSG),
250 copyLength);
251 pConnectResp->ActualLength = copyLength;
252 }
253 /* done processing response buffer */
254 target->CtrlResponseProcessing = false;
255 }
256
257 /* the rest of these are parameter checks so set the error status */
258 status = A_EPROTO;
259
260 if (assignedEndpoint >= ENDPOINT_MAX) {
261 AR_DEBUG_ASSERT(false);
262 break;
263 }
264
265 if (0 == maxMsgSize) {
266 AR_DEBUG_ASSERT(false);
267 break;
268 }
269
Houston Hoffman29573d92015-10-20 17:49:44 -0700270 pEndpoint = &target->endpoint[assignedEndpoint];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800271 pEndpoint->Id = assignedEndpoint;
272 if (pEndpoint->ServiceID != 0) {
273 /* endpoint already in use! */
274 AR_DEBUG_ASSERT(false);
275 break;
276 }
277
278 /* return assigned endpoint to caller */
279 pConnectResp->Endpoint = assignedEndpoint;
280 pConnectResp->MaxMsgLength = maxMsgSize;
281
282 /* setup the endpoint */
283 pEndpoint->ServiceID = pConnectReq->ServiceID; /* this marks the endpoint in use */
284 pEndpoint->MaxTxQueueDepth = pConnectReq->MaxSendQueueDepth;
285 pEndpoint->MaxMsgLength = maxMsgSize;
286 pEndpoint->TxCredits = txAlloc;
287 pEndpoint->TxCreditSize = target->TargetCreditSize;
288 pEndpoint->TxCreditsPerMaxMsg =
289 maxMsgSize / target->TargetCreditSize;
290 if (maxMsgSize % target->TargetCreditSize) {
291 pEndpoint->TxCreditsPerMaxMsg++;
292 }
293#if DEBUG_CREDIT
294 cdf_print(" Endpoint%d initial credit:%d, size:%d.\n",
295 pEndpoint->Id, pEndpoint->TxCredits,
296 pEndpoint->TxCreditSize);
297#endif
298
299 /* copy all the callbacks */
300 pEndpoint->EpCallBacks = pConnectReq->EpCallbacks;
301
302 status = hif_map_service_to_pipe(target->hif_dev,
303 pEndpoint->ServiceID,
304 &pEndpoint->UL_PipeID,
305 &pEndpoint->DL_PipeID,
306 &pEndpoint->ul_is_polled,
307 &pEndpoint->dl_is_polled);
308 if (A_FAILED(status)) {
309 break;
310 }
311
312 cdf_assert(!pEndpoint->dl_is_polled); /* not currently supported */
313
314 if (pEndpoint->ul_is_polled) {
315 cdf_softirq_timer_init(target->osdev,
316 &pEndpoint->ul_poll_timer,
317 htc_send_complete_check_cleanup,
318 pEndpoint,
319 CDF_TIMER_TYPE_SW);
320 }
321
322 AR_DEBUG_PRINTF(ATH_DEBUG_SETUP,
323 ("HTC Service:0x%4.4X, ULpipe:%d DLpipe:%d id:%d Ready\n",
324 pEndpoint->ServiceID, pEndpoint->UL_PipeID,
325 pEndpoint->DL_PipeID, pEndpoint->Id));
326
327 if (disableCreditFlowCtrl && pEndpoint->TxCreditFlowEnabled) {
328 pEndpoint->TxCreditFlowEnabled = false;
329 AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
330 ("HTC Service:0x%4.4X ep:%d TX flow control disabled\n",
331 pEndpoint->ServiceID,
332 assignedEndpoint));
333 }
334
335 } while (false);
336
337 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_connect_service \n"));
338
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
353void htc_fw_event_handler(void *context, CDF_STATUS status)
354{
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}
363
364/* Disable ASPM : disable PCIe low power */
365void htc_disable_aspm(void)
366{
367 hif_disable_aspm();
368}