xref: /wlan-dirver/qca-wifi-host-cmn/htc/htc_services.c (revision 4865edfd190c086bbe2c69aae12a8226f877b91e)
1 /*
2  * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include "htc_debug.h"
20 #include "htc_internal.h"
21 #include <hif.h>
22 #include <qdf_nbuf.h>           /* qdf_nbuf_t */
23 #include "qdf_module.h"
24 
25 /* use credit flow control over HTC */
26 unsigned int htc_credit_flow = 1;
27 #ifndef DEBUG_CREDIT
28 #define DEBUG_CREDIT 0
29 #endif
30 
31 /* HTC credit flow global disable */
32 void htc_global_credit_flow_disable(void)
33 {
34 	htc_credit_flow = 0;
35 }
36 
37 /* HTC credit flow global enable */
38 void htc_global_credit_flow_enable(void)
39 {
40 	htc_credit_flow = 1;
41 }
42 
43 #ifdef HIF_SDIO
44 
45 /**
46  * htc_alt_data_credit_size_update() - update tx credit size info
47  *				on max bundle size
48  * @target: hif context
49  * @ul_pipe: endpoint ul pipe id
50  * @dl_pipe: endpoint dl pipe id
51  * @txCreditSize: endpoint tx credit size
52  *
53  *
54  * When AltDataCreditSize is non zero, it indicates the credit size for
55  * HTT and all other services on Mbox0. Mbox1 has WMI_CONTROL_SVC which
56  * uses the default credit size. Use AltDataCreditSize only when
57  * mailbox is swapped. Mailbox swap bit is set by bmi_target_ready at
58  * the end of BMI phase.
59  *
60  * The Credit Size is a parameter associated with the mbox rather than
61  * a service. Multiple services can run on this mbox.
62  *
63  * If AltDataCreditSize is 0, that means the firmware doesn't support
64  * this feature. Default to the TargetCreditSize
65  *
66  * Return: None
67  */
68 static inline void
69 htc_alt_data_credit_size_update(HTC_TARGET *target,
70 				uint8_t *ul_pipe,
71 				uint8_t *dl_pipe,
72 				int *txCreditSize)
73 {
74 	if ((target->AltDataCreditSize) &&
75 	    (*ul_pipe == 1) && (*dl_pipe == 0))
76 		*txCreditSize = target->AltDataCreditSize;
77 
78 }
79 #else
80 
81 static inline void
82 htc_alt_data_credit_size_update(HTC_TARGET *target,
83 				uint8_t *ul_pipe,
84 				uint8_t *dl_pipe,
85 				int *txCreditSize)
86 {
87 }
88 #endif
89 
90 QDF_STATUS htc_connect_service(HTC_HANDLE HTCHandle,
91 			     struct htc_service_connect_req *pConnectReq,
92 			     struct htc_service_connect_resp *pConnectResp)
93 {
94 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
95 	QDF_STATUS status = QDF_STATUS_SUCCESS;
96 	HTC_PACKET *pSendPacket = NULL;
97 	HTC_CONNECT_SERVICE_RESPONSE_MSG *pResponseMsg;
98 	HTC_CONNECT_SERVICE_MSG *pConnectMsg;
99 	HTC_ENDPOINT_ID assignedEndpoint = ENDPOINT_MAX;
100 	HTC_ENDPOINT *pEndpoint;
101 	unsigned int maxMsgSize = 0;
102 	qdf_nbuf_t netbuf;
103 	uint8_t txAlloc;
104 	int length;
105 	bool disableCreditFlowCtrl = false;
106 	uint16_t conn_flags;
107 	uint16_t rsp_msg_id, rsp_msg_serv_id, rsp_msg_max_msg_size;
108 	uint8_t rsp_msg_status, rsp_msg_end_id, rsp_msg_serv_meta_len;
109 
110 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
111 			("+htc_connect_service, target:%pK SvcID:0x%X\n", target,
112 			 pConnectReq->service_id));
113 
114 	do {
115 
116 		AR_DEBUG_ASSERT(pConnectReq->service_id != 0);
117 
118 		if (HTC_CTRL_RSVD_SVC == pConnectReq->service_id) {
119 			/* special case for pseudo control service */
120 			assignedEndpoint = ENDPOINT_0;
121 			maxMsgSize = HTC_MAX_CONTROL_MESSAGE_LENGTH;
122 			txAlloc = 0;
123 
124 		} else {
125 
126 			txAlloc = htc_get_credit_allocation(target,
127 					pConnectReq->service_id);
128 
129 			if (!txAlloc) {
130 				AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
131 						("Service %d does not allocate target credits!\n",
132 						 pConnectReq->service_id));
133 			}
134 
135 			/* allocate a packet to send to the target */
136 			pSendPacket = htc_alloc_control_tx_packet(target);
137 
138 			if (NULL == pSendPacket) {
139 				AR_DEBUG_ASSERT(false);
140 				status = QDF_STATUS_E_NOMEM;
141 				break;
142 			}
143 
144 			netbuf =
145 				(qdf_nbuf_t)
146 				GET_HTC_PACKET_NET_BUF_CONTEXT(pSendPacket);
147 			length =
148 				sizeof(HTC_CONNECT_SERVICE_MSG) +
149 				pConnectReq->MetaDataLength;
150 
151 			/* assemble connect service message */
152 			qdf_nbuf_put_tail(netbuf, length);
153 			pConnectMsg =
154 			    (HTC_CONNECT_SERVICE_MSG *) qdf_nbuf_data(netbuf);
155 
156 			if (NULL == pConnectMsg) {
157 				AR_DEBUG_ASSERT(0);
158 				status = QDF_STATUS_E_FAULT;
159 				break;
160 			}
161 
162 			qdf_mem_zero(pConnectMsg,
163 				     sizeof(HTC_CONNECT_SERVICE_MSG));
164 
165 			conn_flags =
166 				(pConnectReq->
167 				 ConnectionFlags & ~HTC_SET_RECV_ALLOC_MASK) |
168 				HTC_CONNECT_FLAGS_SET_RECV_ALLOCATION(txAlloc);
169 			HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
170 				      MESSAGEID, HTC_MSG_CONNECT_SERVICE_ID);
171 			HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
172 				      SERVICE_ID, pConnectReq->service_id);
173 			HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
174 				      CONNECTIONFLAGS, conn_flags);
175 
176 			if (pConnectReq->
177 			    ConnectionFlags &
178 			    HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL) {
179 				disableCreditFlowCtrl = true;
180 			}
181 
182 			if (!htc_credit_flow)
183 				disableCreditFlowCtrl = true;
184 
185 			/* check caller if it wants to transfer meta data */
186 			if ((pConnectReq->pMetaData != NULL) &&
187 			    (pConnectReq->MetaDataLength <=
188 			     HTC_SERVICE_META_DATA_MAX_LENGTH)) {
189 				/* copy meta data into msg buffer (after hdr) */
190 				qdf_mem_copy((uint8_t *) pConnectMsg +
191 					 sizeof(HTC_CONNECT_SERVICE_MSG),
192 					 pConnectReq->pMetaData,
193 					 pConnectReq->MetaDataLength);
194 
195 				HTC_SET_FIELD(pConnectMsg,
196 					      HTC_CONNECT_SERVICE_MSG,
197 					      SERVICEMETALENGTH,
198 					      pConnectReq->MetaDataLength);
199 			}
200 
201 			SET_HTC_PACKET_INFO_TX(pSendPacket,
202 					       NULL,
203 					       (uint8_t *) pConnectMsg,
204 					       length,
205 					       ENDPOINT_0,
206 					       HTC_SERVICE_TX_PACKET_TAG);
207 
208 			status = htc_send_pkt((HTC_HANDLE) target, pSendPacket);
209 			/* we don't own it anymore */
210 			pSendPacket = NULL;
211 			if (QDF_IS_STATUS_ERROR(status))
212 				break;
213 
214 			/* wait for response */
215 			status = htc_wait_recv_ctrl_message(target);
216 			if (QDF_IS_STATUS_ERROR(status))
217 				break;
218 			/* we controlled the buffer creation so it has to be
219 			 * properly aligned
220 			 */
221 			pResponseMsg =
222 				(HTC_CONNECT_SERVICE_RESPONSE_MSG *) target->
223 				CtrlResponseBuffer;
224 
225 			rsp_msg_id = HTC_GET_FIELD(pResponseMsg,
226 					   HTC_CONNECT_SERVICE_RESPONSE_MSG,
227 					   MESSAGEID);
228 			rsp_msg_serv_id =
229 				HTC_GET_FIELD(pResponseMsg,
230 					      HTC_CONNECT_SERVICE_RESPONSE_MSG,
231 					      SERVICEID);
232 			rsp_msg_status =
233 				HTC_GET_FIELD(pResponseMsg,
234 					      HTC_CONNECT_SERVICE_RESPONSE_MSG,
235 					      STATUS);
236 			rsp_msg_end_id =
237 				HTC_GET_FIELD(pResponseMsg,
238 					      HTC_CONNECT_SERVICE_RESPONSE_MSG,
239 					      ENDPOINTID);
240 			rsp_msg_max_msg_size =
241 				HTC_GET_FIELD(pResponseMsg,
242 					      HTC_CONNECT_SERVICE_RESPONSE_MSG,
243 					      MAXMSGSIZE);
244 			rsp_msg_serv_meta_len =
245 				HTC_GET_FIELD(pResponseMsg,
246 					      HTC_CONNECT_SERVICE_RESPONSE_MSG,
247 					      SERVICEMETALENGTH);
248 
249 			if ((rsp_msg_id != HTC_MSG_CONNECT_SERVICE_RESPONSE_ID)
250 			    || (target->CtrlResponseLength <
251 				sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG))) {
252 				/* this message is not valid */
253 				AR_DEBUG_ASSERT(false);
254 				status = QDF_STATUS_E_PROTO;
255 				break;
256 			}
257 
258 			AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
259 					("htc_connect_service, service 0x%X connect response from target status:%d, assigned ep: %d\n",
260 					 rsp_msg_serv_id, rsp_msg_status,
261 					 rsp_msg_end_id));
262 
263 			pConnectResp->ConnectRespCode = rsp_msg_status;
264 
265 			/* check response status */
266 			if (rsp_msg_status != HTC_SERVICE_SUCCESS) {
267 				AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
268 						(" Target failed service 0x%X connect request (status:%d)\n",
269 						 rsp_msg_serv_id,
270 						 rsp_msg_status));
271 				status = QDF_STATUS_E_PROTO;
272 /* TODO: restore the ifdef when FW supports services 301 and 302
273  * (HTT_MSG_DATA[23]_MSG_SVC)
274  */
275 /* #ifdef QCA_TX_HTT2_SUPPORT */
276 				/* Keep work and not to block the control msg */
277 				target->CtrlResponseProcessing = false;
278 /* #endif */ /* QCA_TX_HTT2_SUPPORT */
279 				break;
280 			}
281 
282 			assignedEndpoint = (HTC_ENDPOINT_ID) rsp_msg_end_id;
283 			maxMsgSize = rsp_msg_max_msg_size;
284 
285 			if ((pConnectResp->pMetaData != NULL) &&
286 			    (rsp_msg_serv_meta_len > 0) &&
287 			    (rsp_msg_serv_meta_len <=
288 			     HTC_SERVICE_META_DATA_MAX_LENGTH)) {
289 				/* caller supplied a buffer and the target
290 				 * responded with data
291 				 */
292 				int copyLength =
293 					min((int)pConnectResp->BufferLength,
294 					    (int)rsp_msg_serv_meta_len);
295 				/* copy the meta data */
296 				qdf_mem_copy(pConnectResp->pMetaData,
297 					 ((uint8_t *) pResponseMsg) +
298 					 sizeof
299 					 (HTC_CONNECT_SERVICE_RESPONSE_MSG),
300 					 copyLength);
301 				pConnectResp->ActualLength = copyLength;
302 			}
303 			/* done processing response buffer */
304 			target->CtrlResponseProcessing = false;
305 		}
306 
307 		/* rest of these are parameter checks so set the error status */
308 		status = QDF_STATUS_E_PROTO;
309 
310 		if (assignedEndpoint >= ENDPOINT_MAX) {
311 			AR_DEBUG_ASSERT(false);
312 			break;
313 		}
314 
315 		if (0 == maxMsgSize) {
316 			AR_DEBUG_ASSERT(false);
317 			break;
318 		}
319 
320 		pEndpoint = &target->endpoint[assignedEndpoint];
321 		pEndpoint->Id = assignedEndpoint;
322 		if (pEndpoint->service_id != 0) {
323 			/* endpoint already in use! */
324 			AR_DEBUG_ASSERT(false);
325 			break;
326 		}
327 
328 		/* return assigned endpoint to caller */
329 		pConnectResp->Endpoint = assignedEndpoint;
330 		pConnectResp->MaxMsgLength = maxMsgSize;
331 
332 		/* setup the endpoint */
333 		/* service_id marks the endpoint in use */
334 		pEndpoint->service_id = pConnectReq->service_id;
335 		pEndpoint->MaxTxQueueDepth = pConnectReq->MaxSendQueueDepth;
336 		pEndpoint->MaxMsgLength = maxMsgSize;
337 		pEndpoint->TxCredits = txAlloc;
338 		pEndpoint->TxCreditSize = target->TargetCreditSize;
339 		pEndpoint->TxCreditsPerMaxMsg =
340 			maxMsgSize / target->TargetCreditSize;
341 		if (maxMsgSize % target->TargetCreditSize)
342 			pEndpoint->TxCreditsPerMaxMsg++;
343 #if DEBUG_CREDIT
344 		qdf_print(" Endpoint%d initial credit:%d, size:%d.\n",
345 			  pEndpoint->Id, pEndpoint->TxCredits,
346 			  pEndpoint->TxCreditSize);
347 #endif
348 
349 		/* copy all the callbacks */
350 		pEndpoint->EpCallBacks = pConnectReq->EpCallbacks;
351 		pEndpoint->async_update = 0;
352 
353 		status = hif_map_service_to_pipe(target->hif_dev,
354 						 pEndpoint->service_id,
355 						 &pEndpoint->UL_PipeID,
356 						 &pEndpoint->DL_PipeID,
357 						 &pEndpoint->ul_is_polled,
358 						 &pEndpoint->dl_is_polled);
359 		if (QDF_IS_STATUS_ERROR(status))
360 			break;
361 
362 		htc_alt_data_credit_size_update(target,
363 						&pEndpoint->UL_PipeID,
364 						&pEndpoint->DL_PipeID,
365 						&pEndpoint->TxCreditSize);
366 
367 		/* not currently supported */
368 		qdf_assert(!pEndpoint->dl_is_polled);
369 
370 		if (pEndpoint->ul_is_polled) {
371 			qdf_timer_init(target->osdev,
372 				&pEndpoint->ul_poll_timer,
373 				htc_send_complete_check_cleanup,
374 				pEndpoint,
375 				QDF_TIMER_TYPE_SW);
376 		}
377 
378 		AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
379 				("SVC:0x%4.4X, ULpipe:%d DLpipe:%d id:%d Ready",
380 				 pEndpoint->service_id, pEndpoint->UL_PipeID,
381 				 pEndpoint->DL_PipeID, pEndpoint->Id));
382 
383 		if (disableCreditFlowCtrl && pEndpoint->TxCreditFlowEnabled) {
384 			pEndpoint->TxCreditFlowEnabled = false;
385 			AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
386 					("SVC:0x%4.4X ep:%d TX flow control disabled",
387 					 pEndpoint->service_id,
388 					 assignedEndpoint));
389 		}
390 
391 	} while (false);
392 
393 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_connect_service\n"));
394 
395 	return status;
396 }
397 qdf_export_symbol(htc_connect_service);
398 
399 void htc_set_credit_distribution(HTC_HANDLE HTCHandle,
400 				 void *pCreditDistContext,
401 				 HTC_CREDIT_DIST_CALLBACK CreditDistFunc,
402 				 HTC_CREDIT_INIT_CALLBACK CreditInitFunc,
403 				 HTC_SERVICE_ID ServicePriorityOrder[],
404 				 int ListLength)
405 {
406 	/* NOT Supported, this transport does not use a credit based flow
407 	 * control mechanism
408 	 */
409 
410 }
411 
412 void htc_fw_event_handler(void *context, QDF_STATUS status)
413 {
414 	HTC_TARGET *target = (HTC_TARGET *) context;
415 	struct htc_init_info *initInfo = &target->HTCInitInfo;
416 
417 	/* check if target failure handler exists and pass error code to it. */
418 	if (target->HTCInitInfo.TargetFailure != NULL)
419 		initInfo->TargetFailure(initInfo->pContext, status);
420 }
421 
422 
423 void htc_set_async_ep(HTC_HANDLE HTCHandle,
424 			HTC_ENDPOINT_ID htc_ep_id, bool value)
425 {
426 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
427 	HTC_ENDPOINT *pEndpoint = &target->endpoint[htc_ep_id];
428 
429 	pEndpoint->async_update = value;
430 	qdf_print("%s: htc_handle %pK, ep %d, value %d\n", __func__,
431 					HTCHandle, htc_ep_id, value);
432 }
433 
434