htc_services.c 12 KB

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