xref: /wlan-dirver/qca-wifi-host-cmn/htc/htc_services.c (revision 45a38684b07295822dc8eba39e293408f203eec8)
1 /*
2  * Copyright (c) 2013-2020 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 	int ret;
110 
111 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
112 			("+htc_connect_service, target:%pK SvcID:0x%X\n", target,
113 			 pConnectReq->service_id));
114 
115 	do {
116 
117 		AR_DEBUG_ASSERT(pConnectReq->service_id != 0);
118 
119 		if (HTC_CTRL_RSVD_SVC == pConnectReq->service_id) {
120 			/* special case for pseudo control service */
121 			assignedEndpoint = ENDPOINT_0;
122 			maxMsgSize = HTC_MAX_CONTROL_MESSAGE_LENGTH;
123 			txAlloc = 0;
124 
125 		} else {
126 
127 			txAlloc = htc_get_credit_allocation(target,
128 					pConnectReq->service_id);
129 
130 			if (!txAlloc) {
131 				AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
132 						("Service %d does not allocate target credits!\n",
133 						 pConnectReq->service_id));
134 			}
135 
136 			/* allocate a packet to send to the target */
137 			pSendPacket = htc_alloc_control_tx_packet(target);
138 
139 			if (!pSendPacket) {
140 				AR_DEBUG_ASSERT(false);
141 				status = QDF_STATUS_E_NOMEM;
142 				break;
143 			}
144 
145 			netbuf =
146 				(qdf_nbuf_t)
147 				GET_HTC_PACKET_NET_BUF_CONTEXT(pSendPacket);
148 			length =
149 				sizeof(HTC_CONNECT_SERVICE_MSG) +
150 				pConnectReq->MetaDataLength;
151 
152 			/* assemble connect service message */
153 			qdf_nbuf_put_tail(netbuf, length);
154 			pConnectMsg =
155 			    (HTC_CONNECT_SERVICE_MSG *) qdf_nbuf_data(netbuf);
156 
157 			if (!pConnectMsg) {
158 				AR_DEBUG_ASSERT(0);
159 				status = QDF_STATUS_E_FAULT;
160 				break;
161 			}
162 
163 			qdf_mem_zero(pConnectMsg,
164 				     sizeof(HTC_CONNECT_SERVICE_MSG));
165 
166 			conn_flags =
167 				(pConnectReq->
168 				 ConnectionFlags & ~HTC_SET_RECV_ALLOC_MASK) |
169 				HTC_CONNECT_FLAGS_SET_RECV_ALLOCATION(txAlloc);
170 			HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
171 				      MESSAGEID, HTC_MSG_CONNECT_SERVICE_ID);
172 			HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
173 				      SERVICE_ID, pConnectReq->service_id);
174 			HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
175 				      CONNECTIONFLAGS, conn_flags);
176 
177 			if (pConnectReq->
178 			    ConnectionFlags &
179 			    HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL) {
180 				disableCreditFlowCtrl = true;
181 			}
182 
183 			if (!htc_credit_flow)
184 				disableCreditFlowCtrl = true;
185 
186 			/* check caller if it wants to transfer meta data */
187 			if ((pConnectReq->pMetaData) &&
188 			    (pConnectReq->MetaDataLength <=
189 			     HTC_SERVICE_META_DATA_MAX_LENGTH)) {
190 				/* copy meta data into msg buffer (after hdr) */
191 				qdf_mem_copy((uint8_t *) pConnectMsg +
192 					 sizeof(HTC_CONNECT_SERVICE_MSG),
193 					 pConnectReq->pMetaData,
194 					 pConnectReq->MetaDataLength);
195 
196 				HTC_SET_FIELD(pConnectMsg,
197 					      HTC_CONNECT_SERVICE_MSG,
198 					      SERVICEMETALENGTH,
199 					      pConnectReq->MetaDataLength);
200 			}
201 
202 			SET_HTC_PACKET_INFO_TX(pSendPacket,
203 					       NULL,
204 					       (uint8_t *) pConnectMsg,
205 					       length,
206 					       ENDPOINT_0,
207 					       HTC_SERVICE_TX_PACKET_TAG);
208 
209 			status = htc_send_pkt((HTC_HANDLE) target, pSendPacket);
210 			/* we don't own it anymore */
211 			pSendPacket = NULL;
212 			if (QDF_IS_STATUS_ERROR(status))
213 				break;
214 
215 			/* wait for response */
216 			status = htc_wait_recv_ctrl_message(target);
217 			if (QDF_IS_STATUS_ERROR(status))
218 				break;
219 			/* we controlled the buffer creation so it has to be
220 			 * properly aligned
221 			 */
222 			pResponseMsg =
223 				(HTC_CONNECT_SERVICE_RESPONSE_MSG *) target->
224 				CtrlResponseBuffer;
225 
226 			rsp_msg_id = HTC_GET_FIELD(pResponseMsg,
227 					   HTC_CONNECT_SERVICE_RESPONSE_MSG,
228 					   MESSAGEID);
229 			rsp_msg_serv_id =
230 				HTC_GET_FIELD(pResponseMsg,
231 					      HTC_CONNECT_SERVICE_RESPONSE_MSG,
232 					      SERVICEID);
233 			rsp_msg_status =
234 				HTC_GET_FIELD(pResponseMsg,
235 					      HTC_CONNECT_SERVICE_RESPONSE_MSG,
236 					      STATUS);
237 			rsp_msg_end_id =
238 				HTC_GET_FIELD(pResponseMsg,
239 					      HTC_CONNECT_SERVICE_RESPONSE_MSG,
240 					      ENDPOINTID);
241 			rsp_msg_max_msg_size =
242 				HTC_GET_FIELD(pResponseMsg,
243 					      HTC_CONNECT_SERVICE_RESPONSE_MSG,
244 					      MAXMSGSIZE);
245 			rsp_msg_serv_meta_len =
246 				HTC_GET_FIELD(pResponseMsg,
247 					      HTC_CONNECT_SERVICE_RESPONSE_MSG,
248 					      SERVICEMETALENGTH);
249 
250 			if ((rsp_msg_id != HTC_MSG_CONNECT_SERVICE_RESPONSE_ID)
251 			    || (target->CtrlResponseLength <
252 				sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG))) {
253 				/* this message is not valid */
254 				AR_DEBUG_ASSERT(false);
255 				status = QDF_STATUS_E_PROTO;
256 				break;
257 			}
258 
259 			AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
260 					("htc_connect_service, service 0x%X connect response from target status:%d, assigned ep: %d\n",
261 					 rsp_msg_serv_id, rsp_msg_status,
262 					 rsp_msg_end_id));
263 
264 			pConnectResp->ConnectRespCode = rsp_msg_status;
265 
266 			/* check response status */
267 			if (rsp_msg_status != HTC_SERVICE_SUCCESS) {
268 				AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
269 						(" Target failed service 0x%X connect request (status:%d)\n",
270 						 rsp_msg_serv_id,
271 						 rsp_msg_status));
272 				status = QDF_STATUS_E_PROTO;
273 /* TODO: restore the ifdef when FW supports services 301 and 302
274  * (HTT_MSG_DATA[23]_MSG_SVC)
275  */
276 /* #ifdef QCA_TX_HTT2_SUPPORT */
277 				/* Keep work and not to block the control msg */
278 				target->CtrlResponseProcessing = false;
279 /* #endif */ /* QCA_TX_HTT2_SUPPORT */
280 				break;
281 			}
282 
283 			assignedEndpoint = (HTC_ENDPOINT_ID) rsp_msg_end_id;
284 			maxMsgSize = rsp_msg_max_msg_size;
285 
286 			if ((pConnectResp->pMetaData) &&
287 			    (rsp_msg_serv_meta_len > 0) &&
288 			    (rsp_msg_serv_meta_len <=
289 			     HTC_SERVICE_META_DATA_MAX_LENGTH)) {
290 				/* caller supplied a buffer and the target
291 				 * responded with data
292 				 */
293 				int copyLength =
294 					min((int)pConnectResp->BufferLength,
295 					    (int)rsp_msg_serv_meta_len);
296 				/* copy the meta data */
297 				qdf_mem_copy(pConnectResp->pMetaData,
298 					 ((uint8_t *) pResponseMsg) +
299 					 sizeof
300 					 (HTC_CONNECT_SERVICE_RESPONSE_MSG),
301 					 copyLength);
302 				pConnectResp->ActualLength = copyLength;
303 			}
304 			/* done processing response buffer */
305 			target->CtrlResponseProcessing = false;
306 		}
307 
308 		/* rest of these are parameter checks so set the error status */
309 		status = QDF_STATUS_E_PROTO;
310 
311 		if (assignedEndpoint >= ENDPOINT_MAX) {
312 			AR_DEBUG_ASSERT(false);
313 			break;
314 		}
315 
316 		if (0 == maxMsgSize) {
317 			AR_DEBUG_ASSERT(false);
318 			break;
319 		}
320 
321 		pEndpoint = &target->endpoint[assignedEndpoint];
322 		pEndpoint->Id = assignedEndpoint;
323 		if (pEndpoint->service_id != 0) {
324 			/* endpoint already in use! */
325 			AR_DEBUG_ASSERT(false);
326 			break;
327 		}
328 
329 		/* return assigned endpoint to caller */
330 		pConnectResp->Endpoint = assignedEndpoint;
331 		pConnectResp->MaxMsgLength = maxMsgSize;
332 
333 		/* setup the endpoint */
334 		/* service_id marks the endpoint in use */
335 		pEndpoint->service_id = pConnectReq->service_id;
336 		pEndpoint->MaxTxQueueDepth = pConnectReq->MaxSendQueueDepth;
337 		pEndpoint->MaxMsgLength = maxMsgSize;
338 		pEndpoint->TxCredits = txAlloc;
339 		pEndpoint->TxCreditSize = target->TargetCreditSize;
340 		pEndpoint->TxCreditsPerMaxMsg =
341 			maxMsgSize / target->TargetCreditSize;
342 		if (maxMsgSize % target->TargetCreditSize)
343 			pEndpoint->TxCreditsPerMaxMsg++;
344 #if DEBUG_CREDIT
345 		qdf_print(" Endpoint%d initial credit:%d, size:%d.",
346 			  pEndpoint->Id, pEndpoint->TxCredits,
347 			  pEndpoint->TxCreditSize);
348 #endif
349 
350 		/* copy all the callbacks */
351 		pEndpoint->EpCallBacks = pConnectReq->EpCallbacks;
352 		pEndpoint->async_update = 0;
353 
354 		ret = hif_map_service_to_pipe(target->hif_dev,
355 					      pEndpoint->service_id,
356 					      &pEndpoint->UL_PipeID,
357 					      &pEndpoint->DL_PipeID,
358 					      &pEndpoint->ul_is_polled,
359 					      &pEndpoint->dl_is_polled);
360 		status = qdf_status_from_os_return(ret);
361 		if (QDF_IS_STATUS_ERROR(status))
362 			break;
363 
364 		htc_alt_data_credit_size_update(target,
365 						&pEndpoint->UL_PipeID,
366 						&pEndpoint->DL_PipeID,
367 						&pEndpoint->TxCreditSize);
368 
369 		/* not currently supported */
370 		qdf_assert(!pEndpoint->dl_is_polled);
371 
372 		if (pEndpoint->ul_is_polled) {
373 			qdf_timer_init(target->osdev,
374 				&pEndpoint->ul_poll_timer,
375 				htc_send_complete_check_cleanup,
376 				pEndpoint,
377 				QDF_TIMER_TYPE_SW);
378 		}
379 
380 		HTC_TRACE("SVC:0x%4.4X, ULpipe:%d DLpipe:%d id:%d Ready",
381 			  pEndpoint->service_id, pEndpoint->UL_PipeID,
382 			  pEndpoint->DL_PipeID, pEndpoint->Id);
383 
384 		if (disableCreditFlowCtrl && pEndpoint->TxCreditFlowEnabled) {
385 			pEndpoint->TxCreditFlowEnabled = false;
386 			HTC_TRACE("SVC:0x%4.4X ep:%d TX flow control disabled",
387 				  pEndpoint->service_id, assignedEndpoint);
388 		}
389 
390 	} while (false);
391 
392 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_connect_service\n"));
393 
394 	return status;
395 }
396 qdf_export_symbol(htc_connect_service);
397 
398 void htc_set_credit_distribution(HTC_HANDLE HTCHandle,
399 				 void *pCreditDistContext,
400 				 HTC_CREDIT_DIST_CALLBACK CreditDistFunc,
401 				 HTC_CREDIT_INIT_CALLBACK CreditInitFunc,
402 				 HTC_SERVICE_ID ServicePriorityOrder[],
403 				 int ListLength)
404 {
405 	/* NOT Supported, this transport does not use a credit based flow
406 	 * control mechanism
407 	 */
408 
409 }
410 
411 void htc_fw_event_handler(void *context, QDF_STATUS status)
412 {
413 	HTC_TARGET *target = (HTC_TARGET *) context;
414 	struct htc_init_info *initInfo = &target->HTCInitInfo;
415 
416 	/* check if target failure handler exists and pass error code to it. */
417 	if (target->HTCInitInfo.TargetFailure)
418 		initInfo->TargetFailure(initInfo->pContext, status);
419 }
420 
421 
422 void htc_set_async_ep(HTC_HANDLE HTCHandle,
423 			HTC_ENDPOINT_ID htc_ep_id, bool value)
424 {
425 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
426 	HTC_ENDPOINT *pEndpoint = &target->endpoint[htc_ep_id];
427 
428 	pEndpoint->async_update = value;
429 	qdf_print("%s: htc_handle %pK, ep %d, value %d", __func__,
430 		  HTCHandle, htc_ep_id, value);
431 }
432 
433