htc_services.c 12 KB

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