htc_services.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  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. A_STATUS htc_connect_service(HTC_HANDLE HTCHandle,
  46. HTC_SERVICE_CONNECT_REQ *pConnectReq,
  47. HTC_SERVICE_CONNECT_RESP *pConnectResp)
  48. {
  49. HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
  50. A_STATUS status = A_OK;
  51. HTC_PACKET *pSendPacket = NULL;
  52. HTC_CONNECT_SERVICE_RESPONSE_MSG *pResponseMsg;
  53. HTC_CONNECT_SERVICE_MSG *pConnectMsg;
  54. HTC_ENDPOINT_ID assignedEndpoint = ENDPOINT_MAX;
  55. HTC_ENDPOINT *pEndpoint;
  56. unsigned int maxMsgSize = 0;
  57. qdf_nbuf_t netbuf;
  58. uint8_t txAlloc;
  59. int length;
  60. bool disableCreditFlowCtrl = false;
  61. uint16_t conn_flags;
  62. uint16_t rsp_msg_id, rsp_msg_serv_id, rsp_msg_max_msg_size;
  63. uint8_t rsp_msg_status, rsp_msg_end_id, rsp_msg_serv_meta_len;
  64. AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
  65. ("+htc_connect_service, target:%p SvcID:0x%X\n", target,
  66. pConnectReq->service_id));
  67. do {
  68. AR_DEBUG_ASSERT(pConnectReq->service_id != 0);
  69. if (HTC_CTRL_RSVD_SVC == pConnectReq->service_id) {
  70. /* special case for pseudo control service */
  71. assignedEndpoint = ENDPOINT_0;
  72. maxMsgSize = HTC_MAX_CONTROL_MESSAGE_LENGTH;
  73. txAlloc = 0;
  74. } else {
  75. txAlloc = htc_get_credit_allocation(target,
  76. pConnectReq->service_id);
  77. if (!txAlloc) {
  78. AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
  79. ("Service %d does not allocate target credits!\n",
  80. pConnectReq->service_id));
  81. }
  82. /* allocate a packet to send to the target */
  83. pSendPacket = htc_alloc_control_tx_packet(target);
  84. if (NULL == pSendPacket) {
  85. AR_DEBUG_ASSERT(false);
  86. status = A_NO_MEMORY;
  87. break;
  88. }
  89. netbuf =
  90. (qdf_nbuf_t)
  91. GET_HTC_PACKET_NET_BUF_CONTEXT(pSendPacket);
  92. length =
  93. sizeof(HTC_CONNECT_SERVICE_MSG) +
  94. pConnectReq->MetaDataLength;
  95. /* assemble connect service message */
  96. qdf_nbuf_put_tail(netbuf, length);
  97. pConnectMsg =
  98. (HTC_CONNECT_SERVICE_MSG *) qdf_nbuf_data(netbuf);
  99. if (NULL == pConnectMsg) {
  100. AR_DEBUG_ASSERT(0);
  101. status = A_EFAULT;
  102. break;
  103. }
  104. qdf_mem_zero(pConnectMsg,
  105. sizeof(HTC_CONNECT_SERVICE_MSG));
  106. conn_flags =
  107. (pConnectReq->
  108. ConnectionFlags & ~HTC_SET_RECV_ALLOC_MASK) |
  109. HTC_CONNECT_FLAGS_SET_RECV_ALLOCATION(txAlloc);
  110. HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
  111. MESSAGEID, HTC_MSG_CONNECT_SERVICE_ID);
  112. HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
  113. SERVICE_ID, pConnectReq->service_id);
  114. HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
  115. CONNECTIONFLAGS, conn_flags);
  116. if (pConnectReq->
  117. ConnectionFlags &
  118. HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL) {
  119. disableCreditFlowCtrl = true;
  120. }
  121. if (!htc_credit_flow) {
  122. disableCreditFlowCtrl = true;
  123. }
  124. /* check caller if it wants to transfer meta data */
  125. if ((pConnectReq->pMetaData != NULL) &&
  126. (pConnectReq->MetaDataLength <=
  127. HTC_SERVICE_META_DATA_MAX_LENGTH)) {
  128. /* copy meta data into message buffer (after header ) */
  129. qdf_mem_copy((uint8_t *) pConnectMsg +
  130. sizeof(HTC_CONNECT_SERVICE_MSG),
  131. pConnectReq->pMetaData,
  132. pConnectReq->MetaDataLength);
  133. HTC_SET_FIELD(pConnectMsg,
  134. HTC_CONNECT_SERVICE_MSG,
  135. SERVICEMETALENGTH,
  136. pConnectReq->MetaDataLength);
  137. }
  138. SET_HTC_PACKET_INFO_TX(pSendPacket,
  139. NULL,
  140. (uint8_t *) pConnectMsg,
  141. length,
  142. ENDPOINT_0,
  143. HTC_SERVICE_TX_PACKET_TAG);
  144. status = htc_send_pkt((HTC_HANDLE) target, pSendPacket);
  145. /* we don't own it anymore */
  146. pSendPacket = NULL;
  147. if (A_FAILED(status)) {
  148. break;
  149. }
  150. /* wait for response */
  151. status = htc_wait_recv_ctrl_message(target);
  152. if (A_FAILED(status)) {
  153. break;
  154. }
  155. /* we controlled the buffer creation so it has to be properly aligned */
  156. pResponseMsg =
  157. (HTC_CONNECT_SERVICE_RESPONSE_MSG *) target->
  158. CtrlResponseBuffer;
  159. rsp_msg_id = HTC_GET_FIELD(pResponseMsg,
  160. HTC_CONNECT_SERVICE_RESPONSE_MSG,
  161. MESSAGEID);
  162. rsp_msg_serv_id =
  163. HTC_GET_FIELD(pResponseMsg,
  164. HTC_CONNECT_SERVICE_RESPONSE_MSG,
  165. SERVICEID);
  166. rsp_msg_status =
  167. HTC_GET_FIELD(pResponseMsg,
  168. HTC_CONNECT_SERVICE_RESPONSE_MSG,
  169. STATUS);
  170. rsp_msg_end_id =
  171. HTC_GET_FIELD(pResponseMsg,
  172. HTC_CONNECT_SERVICE_RESPONSE_MSG,
  173. ENDPOINTID);
  174. rsp_msg_max_msg_size =
  175. HTC_GET_FIELD(pResponseMsg,
  176. HTC_CONNECT_SERVICE_RESPONSE_MSG,
  177. MAXMSGSIZE);
  178. rsp_msg_serv_meta_len =
  179. HTC_GET_FIELD(pResponseMsg,
  180. HTC_CONNECT_SERVICE_RESPONSE_MSG,
  181. SERVICEMETALENGTH);
  182. if ((rsp_msg_id != HTC_MSG_CONNECT_SERVICE_RESPONSE_ID)
  183. || (target->CtrlResponseLength <
  184. sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG))) {
  185. /* this message is not valid */
  186. AR_DEBUG_ASSERT(false);
  187. status = A_EPROTO;
  188. break;
  189. }
  190. AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
  191. ("htc_connect_service, service 0x%X connect response from target status:%d, assigned ep: %d\n",
  192. rsp_msg_serv_id, rsp_msg_status,
  193. rsp_msg_end_id));
  194. pConnectResp->ConnectRespCode = rsp_msg_status;
  195. /* check response status */
  196. if (rsp_msg_status != HTC_SERVICE_SUCCESS) {
  197. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
  198. (" Target failed service 0x%X connect request (status:%d)\n",
  199. rsp_msg_serv_id,
  200. rsp_msg_status));
  201. status = A_EPROTO;
  202. /* TODO: restore the ifdef when FW supports services 301 and 302 (HTT_MSG_DATA[23]_MSG_SVC)
  203. #ifdef QCA_TX_HTT2_SUPPORT
  204. */
  205. /* Keep work and not to block the control message. */
  206. target->CtrlResponseProcessing = false;
  207. /*#endif */ /* QCA_TX_HTT2_SUPPORT */
  208. break;
  209. }
  210. assignedEndpoint = (HTC_ENDPOINT_ID) rsp_msg_end_id;
  211. maxMsgSize = rsp_msg_max_msg_size;
  212. if ((pConnectResp->pMetaData != NULL) &&
  213. (rsp_msg_serv_meta_len > 0) &&
  214. (rsp_msg_serv_meta_len <=
  215. HTC_SERVICE_META_DATA_MAX_LENGTH)) {
  216. /* caller supplied a buffer and the target responded with data */
  217. int copyLength =
  218. min((int)pConnectResp->BufferLength,
  219. (int)rsp_msg_serv_meta_len);
  220. /* copy the meta data */
  221. qdf_mem_copy(pConnectResp->pMetaData,
  222. ((uint8_t *) pResponseMsg) +
  223. sizeof
  224. (HTC_CONNECT_SERVICE_RESPONSE_MSG),
  225. copyLength);
  226. pConnectResp->ActualLength = copyLength;
  227. }
  228. /* done processing response buffer */
  229. target->CtrlResponseProcessing = false;
  230. }
  231. /* the rest of these are parameter checks so set the error status */
  232. status = A_EPROTO;
  233. if (assignedEndpoint >= ENDPOINT_MAX) {
  234. AR_DEBUG_ASSERT(false);
  235. break;
  236. }
  237. if (0 == maxMsgSize) {
  238. AR_DEBUG_ASSERT(false);
  239. break;
  240. }
  241. pEndpoint = &target->endpoint[assignedEndpoint];
  242. pEndpoint->Id = assignedEndpoint;
  243. if (pEndpoint->service_id != 0) {
  244. /* endpoint already in use! */
  245. AR_DEBUG_ASSERT(false);
  246. break;
  247. }
  248. /* return assigned endpoint to caller */
  249. pConnectResp->Endpoint = assignedEndpoint;
  250. pConnectResp->MaxMsgLength = maxMsgSize;
  251. /* setup the endpoint */
  252. /* service_id marks the endpoint in use */
  253. pEndpoint->service_id = pConnectReq->service_id;
  254. pEndpoint->MaxTxQueueDepth = pConnectReq->MaxSendQueueDepth;
  255. pEndpoint->MaxMsgLength = maxMsgSize;
  256. pEndpoint->TxCredits = txAlloc;
  257. pEndpoint->TxCreditSize = target->TargetCreditSize;
  258. pEndpoint->TxCreditsPerMaxMsg =
  259. maxMsgSize / target->TargetCreditSize;
  260. if (maxMsgSize % target->TargetCreditSize) {
  261. pEndpoint->TxCreditsPerMaxMsg++;
  262. }
  263. #if DEBUG_CREDIT
  264. qdf_print(" Endpoint%d initial credit:%d, size:%d.\n",
  265. pEndpoint->Id, pEndpoint->TxCredits,
  266. pEndpoint->TxCreditSize);
  267. #endif
  268. /* copy all the callbacks */
  269. pEndpoint->EpCallBacks = pConnectReq->EpCallbacks;
  270. status = hif_map_service_to_pipe(target->hif_dev,
  271. pEndpoint->service_id,
  272. &pEndpoint->UL_PipeID,
  273. &pEndpoint->DL_PipeID,
  274. &pEndpoint->ul_is_polled,
  275. &pEndpoint->dl_is_polled);
  276. if (A_FAILED(status)) {
  277. break;
  278. }
  279. qdf_assert(!pEndpoint->dl_is_polled); /* not currently supported */
  280. if (pEndpoint->ul_is_polled) {
  281. qdf_timer_init(target->osdev,
  282. &pEndpoint->ul_poll_timer,
  283. htc_send_complete_check_cleanup,
  284. pEndpoint,
  285. QDF_TIMER_TYPE_SW);
  286. }
  287. AR_DEBUG_PRINTF(ATH_DEBUG_SETUP,
  288. ("HTC Service:0x%4.4X, ULpipe:%d DLpipe:%d id:%d Ready\n",
  289. pEndpoint->service_id, pEndpoint->UL_PipeID,
  290. pEndpoint->DL_PipeID, pEndpoint->Id));
  291. if (disableCreditFlowCtrl && pEndpoint->TxCreditFlowEnabled) {
  292. pEndpoint->TxCreditFlowEnabled = false;
  293. AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
  294. ("HTC Service:0x%4.4X ep:%d TX flow control disabled\n",
  295. pEndpoint->service_id,
  296. assignedEndpoint));
  297. }
  298. } while (false);
  299. AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_connect_service\n"));
  300. return status;
  301. }
  302. void htc_set_credit_distribution(HTC_HANDLE HTCHandle,
  303. void *pCreditDistContext,
  304. HTC_CREDIT_DIST_CALLBACK CreditDistFunc,
  305. HTC_CREDIT_INIT_CALLBACK CreditInitFunc,
  306. HTC_SERVICE_ID ServicePriorityOrder[],
  307. int ListLength)
  308. {
  309. /* NOT Supported, this transport does not use a credit based flow control mechanism */
  310. }
  311. void htc_fw_event_handler(void *context, QDF_STATUS status)
  312. {
  313. HTC_TARGET *target = (HTC_TARGET *) context;
  314. HTC_INIT_INFO *initInfo = &target->HTCInitInfo;
  315. /* check if target failure handler exists and pass error code to it. */
  316. if (target->HTCInitInfo.TargetFailure != NULL) {
  317. initInfo->TargetFailure(initInfo->pContext, status);
  318. }
  319. }