htc_services.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. //------------------------------------------------------------------------------
  2. // <copyright file="htc_services.c" company="Atheros">
  3. // Copyright (c) 2007-2008 Atheros Corporation. All rights reserved.
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License version 2 as
  7. // published by the Free Software Foundation;
  8. //
  9. // Software distributed under the License is distributed on an "AS
  10. // IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  11. // implied. See the License for the specific language governing
  12. // rights and limitations under the License.
  13. //
  14. //
  15. //------------------------------------------------------------------------------
  16. //==============================================================================
  17. // Author(s): ="Atheros"
  18. //==============================================================================
  19. #include "htc_internal.h"
  20. void HTCControlTxComplete(void *Context, HTC_PACKET *pPacket)
  21. {
  22. /* not implemented
  23. * we do not send control TX frames during normal runtime, only during setup */
  24. AR_DEBUG_ASSERT(FALSE);
  25. }
  26. /* callback when a control message arrives on this endpoint */
  27. void HTCControlRecv(void *Context, HTC_PACKET *pPacket)
  28. {
  29. AR_DEBUG_ASSERT(pPacket->Endpoint == ENDPOINT_0);
  30. if (pPacket->Status == A_ECANCELED) {
  31. /* this is a flush operation, return the control packet back to the pool */
  32. HTC_FREE_CONTROL_RX((HTC_TARGET*)Context,pPacket);
  33. return;
  34. }
  35. /* the only control messages we are expecting are NULL messages (credit resports), which should
  36. * never get here */
  37. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
  38. ("HTCControlRecv, got message with length:%d \n",
  39. pPacket->ActualLength + HTC_HDR_LENGTH));
  40. /* dump header and message */
  41. DebugDumpBytes(pPacket->pBuffer - HTC_HDR_LENGTH,
  42. pPacket->ActualLength + HTC_HDR_LENGTH,
  43. "Unexpected ENDPOINT 0 Message");
  44. HTC_RECYCLE_RX_PKT((HTC_TARGET*)Context,pPacket,&((HTC_TARGET*)Context)->EndPoint[0]);
  45. }
  46. A_STATUS HTCSendSetupComplete(HTC_TARGET *target)
  47. {
  48. HTC_PACKET *pSendPacket = NULL;
  49. A_STATUS status;
  50. HTC_SETUP_COMPLETE_MSG *pSetupComplete;
  51. do {
  52. /* allocate a packet to send to the target */
  53. pSendPacket = HTC_ALLOC_CONTROL_TX(target);
  54. if (NULL == pSendPacket) {
  55. status = A_NO_MEMORY;
  56. break;
  57. }
  58. /* assemble setup complete message */
  59. pSetupComplete = (HTC_SETUP_COMPLETE_MSG *)pSendPacket->pBuffer;
  60. A_MEMZERO(pSetupComplete,sizeof(HTC_SETUP_COMPLETE_MSG));
  61. pSetupComplete->MessageID = HTC_MSG_SETUP_COMPLETE_ID;
  62. SET_HTC_PACKET_INFO_TX(pSendPacket,
  63. NULL,
  64. (A_UINT8 *)pSetupComplete,
  65. sizeof(HTC_SETUP_COMPLETE_MSG),
  66. ENDPOINT_0,
  67. HTC_SERVICE_TX_PACKET_TAG);
  68. /* we want synchronous operation */
  69. pSendPacket->Completion = NULL;
  70. /* send the message */
  71. status = HTCIssueSend(target,pSendPacket,0);
  72. } while (FALSE);
  73. if (pSendPacket != NULL) {
  74. HTC_FREE_CONTROL_TX(target,pSendPacket);
  75. }
  76. return status;
  77. }
  78. A_STATUS HTCConnectService(HTC_HANDLE HTCHandle,
  79. HTC_SERVICE_CONNECT_REQ *pConnectReq,
  80. HTC_SERVICE_CONNECT_RESP *pConnectResp)
  81. {
  82. HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
  83. A_STATUS status = A_OK;
  84. HTC_PACKET *pRecvPacket = NULL;
  85. HTC_PACKET *pSendPacket = NULL;
  86. HTC_CONNECT_SERVICE_RESPONSE_MSG *pResponseMsg;
  87. HTC_CONNECT_SERVICE_MSG *pConnectMsg;
  88. HTC_ENDPOINT_ID assignedEndpoint = ENDPOINT_MAX;
  89. HTC_ENDPOINT *pEndpoint;
  90. int maxMsgSize = 0;
  91. AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCConnectService, target:0x%X SvcID:0x%X \n",
  92. (A_UINT32)target, pConnectReq->ServiceID));
  93. do {
  94. AR_DEBUG_ASSERT(pConnectReq->ServiceID != 0);
  95. if (HTC_CTRL_RSVD_SVC == pConnectReq->ServiceID) {
  96. /* special case for pseudo control service */
  97. assignedEndpoint = ENDPOINT_0;
  98. maxMsgSize = HTC_MAX_CONTROL_MESSAGE_LENGTH;
  99. } else {
  100. /* allocate a packet to send to the target */
  101. pSendPacket = HTC_ALLOC_CONTROL_TX(target);
  102. if (NULL == pSendPacket) {
  103. AR_DEBUG_ASSERT(FALSE);
  104. status = A_NO_MEMORY;
  105. break;
  106. }
  107. /* assemble connect service message */
  108. pConnectMsg = (HTC_CONNECT_SERVICE_MSG *)pSendPacket->pBuffer;
  109. AR_DEBUG_ASSERT(pConnectMsg != NULL);
  110. A_MEMZERO(pConnectMsg,sizeof(HTC_CONNECT_SERVICE_MSG));
  111. pConnectMsg->MessageID = HTC_MSG_CONNECT_SERVICE_ID;
  112. pConnectMsg->ServiceID = pConnectReq->ServiceID;
  113. pConnectMsg->ConnectionFlags = pConnectReq->ConnectionFlags;
  114. /* check caller if it wants to transfer meta data */
  115. if ((pConnectReq->pMetaData != NULL) &&
  116. (pConnectReq->MetaDataLength <= HTC_SERVICE_META_DATA_MAX_LENGTH)) {
  117. /* copy meta data into message buffer (after header ) */
  118. A_MEMCPY((A_UINT8 *)pConnectMsg + sizeof(HTC_CONNECT_SERVICE_MSG),
  119. pConnectReq->pMetaData,
  120. pConnectReq->MetaDataLength);
  121. pConnectMsg->ServiceMetaLength = pConnectReq->MetaDataLength;
  122. }
  123. SET_HTC_PACKET_INFO_TX(pSendPacket,
  124. NULL,
  125. (A_UINT8 *)pConnectMsg,
  126. sizeof(HTC_CONNECT_SERVICE_MSG) + pConnectMsg->ServiceMetaLength,
  127. ENDPOINT_0,
  128. HTC_SERVICE_TX_PACKET_TAG);
  129. /* we want synchronous operation */
  130. pSendPacket->Completion = NULL;
  131. status = HTCIssueSend(target,pSendPacket,0);
  132. if (A_FAILED(status)) {
  133. break;
  134. }
  135. /* wait for response */
  136. status = HTCWaitforControlMessage(target, &pRecvPacket);
  137. if (A_FAILED(status)) {
  138. break;
  139. }
  140. /* we controlled the buffer creation so it has to be properly aligned */
  141. pResponseMsg = (HTC_CONNECT_SERVICE_RESPONSE_MSG *)pRecvPacket->pBuffer;
  142. if ((pResponseMsg->MessageID != HTC_MSG_CONNECT_SERVICE_RESPONSE_ID) ||
  143. (pRecvPacket->ActualLength < sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG))) {
  144. /* this message is not valid */
  145. AR_DEBUG_ASSERT(FALSE);
  146. status = A_EPROTO;
  147. break;
  148. }
  149. pConnectResp->ConnectRespCode = pResponseMsg->Status;
  150. /* check response status */
  151. if (pResponseMsg->Status != HTC_SERVICE_SUCCESS) {
  152. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
  153. (" Target failed service 0x%X connect request (status:%d)\n",
  154. pResponseMsg->ServiceID, pResponseMsg->Status));
  155. status = A_EPROTO;
  156. break;
  157. }
  158. assignedEndpoint = (HTC_ENDPOINT_ID) pResponseMsg->EndpointID;
  159. maxMsgSize = pResponseMsg->MaxMsgSize;
  160. if ((pConnectResp->pMetaData != NULL) &&
  161. (pResponseMsg->ServiceMetaLength > 0) &&
  162. (pResponseMsg->ServiceMetaLength <= HTC_SERVICE_META_DATA_MAX_LENGTH)) {
  163. /* caller supplied a buffer and the target responded with data */
  164. int copyLength = min((int)pConnectResp->BufferLength, (int)pResponseMsg->ServiceMetaLength);
  165. /* copy the meta data */
  166. A_MEMCPY(pConnectResp->pMetaData,
  167. ((A_UINT8 *)pResponseMsg) + sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG),
  168. copyLength);
  169. pConnectResp->ActualLength = copyLength;
  170. }
  171. }
  172. /* the rest of these are parameter checks so set the error status */
  173. status = A_EPROTO;
  174. if (assignedEndpoint >= ENDPOINT_MAX) {
  175. AR_DEBUG_ASSERT(FALSE);
  176. break;
  177. }
  178. if (0 == maxMsgSize) {
  179. AR_DEBUG_ASSERT(FALSE);
  180. break;
  181. }
  182. pEndpoint = &target->EndPoint[assignedEndpoint];
  183. if (pEndpoint->ServiceID != 0) {
  184. /* endpoint already in use! */
  185. AR_DEBUG_ASSERT(FALSE);
  186. break;
  187. }
  188. /* return assigned endpoint to caller */
  189. pConnectResp->Endpoint = assignedEndpoint;
  190. pConnectResp->MaxMsgLength = maxMsgSize;
  191. /* setup the endpoint */
  192. pEndpoint->ServiceID = pConnectReq->ServiceID; /* this marks the endpoint in use */
  193. pEndpoint->MaxTxQueueDepth = pConnectReq->MaxSendQueueDepth;
  194. pEndpoint->MaxMsgLength = maxMsgSize;
  195. /* copy all the callbacks */
  196. pEndpoint->EpCallBacks = pConnectReq->EpCallbacks;
  197. INIT_HTC_PACKET_QUEUE(&pEndpoint->RxBuffers);
  198. INIT_HTC_PACKET_QUEUE(&pEndpoint->TxQueue);
  199. /* set the credit distribution info for this endpoint, this information is
  200. * passed back to the credit distribution callback function */
  201. pEndpoint->CreditDist.ServiceID = pConnectReq->ServiceID;
  202. pEndpoint->CreditDist.pHTCReserved = pEndpoint;
  203. pEndpoint->CreditDist.Endpoint = assignedEndpoint;
  204. pEndpoint->CreditDist.TxCreditSize = target->TargetCreditSize;
  205. pEndpoint->CreditDist.TxCreditsPerMaxMsg = maxMsgSize / target->TargetCreditSize;
  206. if (0 == pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
  207. pEndpoint->CreditDist.TxCreditsPerMaxMsg = 1;
  208. }
  209. status = A_OK;
  210. } while (FALSE);
  211. if (pSendPacket != NULL) {
  212. HTC_FREE_CONTROL_TX(target,pSendPacket);
  213. }
  214. if (pRecvPacket != NULL) {
  215. HTC_FREE_CONTROL_RX(target,pRecvPacket);
  216. }
  217. AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCConnectService \n"));
  218. return status;
  219. }
  220. static void AddToEndpointDistList(HTC_TARGET *target, HTC_ENDPOINT_CREDIT_DIST *pEpDist)
  221. {
  222. HTC_ENDPOINT_CREDIT_DIST *pCurEntry,*pLastEntry;
  223. if (NULL == target->EpCreditDistributionListHead) {
  224. target->EpCreditDistributionListHead = pEpDist;
  225. pEpDist->pNext = NULL;
  226. pEpDist->pPrev = NULL;
  227. return;
  228. }
  229. /* queue to the end of the list, this does not have to be very
  230. * fast since this list is built at startup time */
  231. pCurEntry = target->EpCreditDistributionListHead;
  232. while (pCurEntry) {
  233. pLastEntry = pCurEntry;
  234. pCurEntry = pCurEntry->pNext;
  235. }
  236. pLastEntry->pNext = pEpDist;
  237. pEpDist->pPrev = pLastEntry;
  238. pEpDist->pNext = NULL;
  239. }
  240. /* default credit init callback */
  241. static void HTCDefaultCreditInit(void *Context,
  242. HTC_ENDPOINT_CREDIT_DIST *pEPList,
  243. int TotalCredits)
  244. {
  245. HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
  246. int totalEps = 0;
  247. int creditsPerEndpoint;
  248. pCurEpDist = pEPList;
  249. /* first run through the list and figure out how many endpoints we are dealing with */
  250. while (pCurEpDist != NULL) {
  251. pCurEpDist = pCurEpDist->pNext;
  252. totalEps++;
  253. }
  254. /* even distribution */
  255. creditsPerEndpoint = TotalCredits/totalEps;
  256. pCurEpDist = pEPList;
  257. /* run through the list and set minimum and normal credits and
  258. * provide the endpoint with some credits to start */
  259. while (pCurEpDist != NULL) {
  260. if (creditsPerEndpoint < pCurEpDist->TxCreditsPerMaxMsg) {
  261. /* too many endpoints and not enough credits */
  262. AR_DEBUG_ASSERT(FALSE);
  263. break;
  264. }
  265. /* our minimum is set for at least 1 max message */
  266. pCurEpDist->TxCreditsMin = pCurEpDist->TxCreditsPerMaxMsg;
  267. /* this value is ignored by our credit alg, since we do
  268. * not dynamically adjust credits, this is the policy of
  269. * the "default" credit distribution, something simple and easy */
  270. pCurEpDist->TxCreditsNorm = 0xFFFF;
  271. /* give the endpoint minimum credits */
  272. pCurEpDist->TxCredits = creditsPerEndpoint;
  273. pCurEpDist->TxCreditsAssigned = creditsPerEndpoint;
  274. pCurEpDist = pCurEpDist->pNext;
  275. }
  276. }
  277. /* default credit distribution callback, NOTE, this callback holds the TX lock */
  278. void HTCDefaultCreditDist(void *Context,
  279. HTC_ENDPOINT_CREDIT_DIST *pEPDistList,
  280. HTC_CREDIT_DIST_REASON Reason)
  281. {
  282. HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
  283. if (Reason == HTC_CREDIT_DIST_SEND_COMPLETE) {
  284. pCurEpDist = pEPDistList;
  285. /* simple distribution */
  286. while (pCurEpDist != NULL) {
  287. if (pCurEpDist->TxCreditsToDist > 0) {
  288. /* just give the endpoint back the credits */
  289. pCurEpDist->TxCredits += pCurEpDist->TxCreditsToDist;
  290. pCurEpDist->TxCreditsToDist = 0;
  291. }
  292. pCurEpDist = pCurEpDist->pNext;
  293. }
  294. }
  295. /* note we do not need to handle the other reason codes as this is a very
  296. * simple distribution scheme, no need to seek for more credits or handle inactivity */
  297. }
  298. void HTCSetCreditDistribution(HTC_HANDLE HTCHandle,
  299. void *pCreditDistContext,
  300. HTC_CREDIT_DIST_CALLBACK CreditDistFunc,
  301. HTC_CREDIT_INIT_CALLBACK CreditInitFunc,
  302. HTC_SERVICE_ID ServicePriorityOrder[],
  303. int ListLength)
  304. {
  305. HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
  306. int i;
  307. int ep;
  308. if (CreditInitFunc != NULL) {
  309. /* caller has supplied their own distribution functions */
  310. target->InitCredits = CreditInitFunc;
  311. AR_DEBUG_ASSERT(CreditDistFunc != NULL);
  312. target->DistributeCredits = CreditDistFunc;
  313. target->pCredDistContext = pCreditDistContext;
  314. } else {
  315. /* caller wants HTC to do distribution */
  316. /* if caller wants service to handle distributions then
  317. * it must set both of these to NULL! */
  318. AR_DEBUG_ASSERT(CreditDistFunc == NULL);
  319. target->InitCredits = HTCDefaultCreditInit;
  320. target->DistributeCredits = HTCDefaultCreditDist;
  321. target->pCredDistContext = target;
  322. }
  323. /* always add HTC control endpoint first, we only expose the list after the
  324. * first one, this is added for TX queue checking */
  325. AddToEndpointDistList(target, &target->EndPoint[ENDPOINT_0].CreditDist);
  326. /* build the list of credit distribution structures in priority order
  327. * supplied by the caller, these will follow endpoint 0 */
  328. for (i = 0; i < ListLength; i++) {
  329. /* match services with endpoints and add the endpoints to the distribution list
  330. * in FIFO order */
  331. for (ep = ENDPOINT_1; ep < ENDPOINT_MAX; ep++) {
  332. if (target->EndPoint[ep].ServiceID == ServicePriorityOrder[i]) {
  333. /* queue this one to the list */
  334. AddToEndpointDistList(target, &target->EndPoint[ep].CreditDist);
  335. break;
  336. }
  337. }
  338. AR_DEBUG_ASSERT(ep < ENDPOINT_MAX);
  339. }
  340. }