htc_services.c 11 KB

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