htc.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. /*
  2. * Copyright (c) 2013 Qualcomm Atheros, Inc.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted (subject to the limitations in the
  7. * disclaimer below) provided that the following conditions are met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. *
  12. * * Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the
  15. * distribution.
  16. *
  17. * * Neither the name of Qualcomm Atheros nor the names of its
  18. * contributors may be used to endorse or promote products derived
  19. * from this software without specific prior written permission.
  20. *
  21. * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
  22. * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
  23. * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
  24. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  25. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  26. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  27. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  28. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  29. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  30. * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  31. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  32. * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  33. * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  34. */
  35. /*
  36. * @File:
  37. *
  38. * @Abstract: host target communications
  39. *
  40. * @Notes:
  41. */
  42. #include <osapi.h>
  43. #include <Magpie_api.h>
  44. #include <htc.h>
  45. #include <htc_api.h>
  46. #include <hif_api.h>
  47. #include <adf_os_mem.h>
  48. #include <adf_os_io.h>
  49. #include "htc_internal.h"
  50. #define A_UNCACHED_ADDR(addr) addr
  51. /* prototypes */
  52. LOCAL void HTCControlSvcProcessMsg(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t hdr_buf, adf_nbuf_t pBuffers, void *arg);
  53. LOCAL void HTCControlSvcProcessSendComplete(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers, void *arg);
  54. LOCAL void HTCMsgRecvHandler(adf_nbuf_t hdr_buf, adf_nbuf_t buf, void *context);
  55. LOCAL void HTCSendDoneHandler(adf_nbuf_t buf, void *context);
  56. LOCAL void HTCFreeMsgBuffer(HTC_CONTEXT *pHTC, adf_nbuf_t pBuffer);
  57. LOCAL adf_nbuf_t HTCAllocMsgBuffer(HTC_CONTEXT *pHTC);
  58. LOCAL void HTCCheckAndSendCreditReport(HTC_CONTEXT *pHTC, A_UINT32 EpMask, HTC_ENDPOINT *pEndpoint, HTC_ENDPOINT_ID Id);
  59. LOCAL void AdjustCreditThreshold(HTC_ENDPOINT *pEndpoint);
  60. LOCAL void HTC_AssembleBuffers(HTC_CONTEXT *pHTC, int Count, int Size);
  61. LOCAL htc_handle_t _HTC_Init(/*A_UINT32 dataAddr,*/
  62. HTC_SETUP_COMPLETE_CB SetupComplete,
  63. HTC_CONFIG *pConfig);
  64. LOCAL void _HTC_RegisterService(htc_handle_t handle, HTC_SERVICE *pService);
  65. LOCAL void _HTC_Ready(htc_handle_t handle);
  66. LOCAL void ReturnBuffers(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers, A_BOOL sendCreditFlag);
  67. LOCAL void _HTC_ReturnBuffers(htc_handle_t handle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers);
  68. LOCAL void _HTC_ReturnBuffersList(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_queue_t bufHead);
  69. LOCAL void _HTC_SendMsg(htc_handle_t handle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers);
  70. void _HTC_PauseRecv(HTC_ENDPOINT_ID EndpointID);
  71. void _HTC_ResumeRecv(HTC_ENDPOINT_ID EndpointID);
  72. LOCAL void HTCProcessConnectMsg(HTC_CONTEXT *pHTC, HTC_CONNECT_SERVICE_MSG *pMsg);
  73. LOCAL void HTCProcessConfigPipeMsg(HTC_CONTEXT *pHTC, HTC_CONFIG_PIPE_MSG *pMsg);
  74. LOCAL void RedistributeCredit(adf_nbuf_t buf, int toPipeId);
  75. LOCAL void _HTC_Shutdown(htc_handle_t htcHandle);
  76. /* macro to check if the service wants to prevent credit dribbling by using
  77. a dynamic threshold */
  78. #define CHECK_AND_ADJUST_CREDIT_THRESHOLD(pEndpoint) \
  79. if ((pEndpoint)->ConnectionFlags & HTC_CONNECT_FLAGS_REDUCE_CREDIT_DRIBBLE) { \
  80. AdjustCreditThreshold((pEndpoint)); \
  81. }
  82. LOCAL void HTC_AssembleBuffers(HTC_CONTEXT *pHTC, int Count, int Size)
  83. {
  84. BUF_Pool_create_pool(pHTC->PoolHandle, POOL_ID_HTC_CONTROL, Count, Size);
  85. }
  86. LOCAL htc_handle_t _HTC_Init(HTC_SETUP_COMPLETE_CB SetupComplete,
  87. HTC_CONFIG *pConfig)
  88. {
  89. HIF_CALLBACK hifCBConfig;
  90. HTC_CONTEXT *pHTC;
  91. pHTC = (HTC_CONTEXT *)adf_os_mem_alloc(sizeof(HTC_CONTEXT));
  92. adf_os_mem_zero(pHTC, sizeof(HTC_CONTEXT));
  93. pHTC->OSHandle = pConfig->OSHandle;
  94. pHTC->PoolHandle = pConfig->PoolHandle;
  95. pHTC->hifHandle = pConfig->HIFHandle;
  96. hifCBConfig.send_buf_done = A_INDIR(htc._HTC_SendDoneHandler);
  97. hifCBConfig.recv_buf = A_INDIR(htc._HTC_MsgRecvHandler);
  98. hifCBConfig.context = pHTC;
  99. /* initialize hardware layer */
  100. HIF_register_callback(pConfig->HIFHandle, &hifCBConfig);
  101. /* see if the host wants us to override the number of ctrl buffers */
  102. pHTC->NumBuffersForCreditRpts = 0;
  103. if (0 == pHTC->NumBuffersForCreditRpts) {
  104. /* nothing to override, simply set default */
  105. pHTC->NumBuffersForCreditRpts = HTC_DEFAULT_NUM_CTRL_BUFFERS;
  106. }
  107. pHTC->MaxEpPendingCreditRpts = 0;
  108. if (0 == pHTC->MaxEpPendingCreditRpts) {
  109. pHTC->MaxEpPendingCreditRpts = HTC_DEFAULT_MAX_EP_PENDING_CREDIT_REPORTS;
  110. }
  111. /* calculate the total allocation size based on the number of credit report buffers */
  112. pHTC->CtrlBufferAllocSize = MIN_CREDIT_BUFFER_ALLOC_SIZE * pHTC->NumBuffersForCreditRpts;
  113. /* we need at least enough buffer space for 1 ctrl message */
  114. pHTC->CtrlBufferAllocSize = A_MAX(pHTC->CtrlBufferAllocSize,MAX_HTC_SETUP_MSG_SIZE);
  115. /* save the size of each buffer/credit we will receive */
  116. pHTC->RecvBufferSize = pConfig->CreditSize; //RecvBufferSize;
  117. pHTC->TotalCredits = pConfig->CreditNumber;
  118. pHTC->TotalCreditsAssigned = 0;
  119. /* setup the pseudo service that handles HTC control messages */
  120. pHTC->HTCControlService.ProcessRecvMsg = A_INDIR(htc._HTC_ControlSvcProcessMsg);
  121. pHTC->HTCControlService.ProcessSendBufferComplete = A_INDIR(htc._HTC_ControlSvcProcessSendComplete);
  122. pHTC->HTCControlService.TrailerSpcCheckLimit = HTC_CTRL_BUFFER_CHECK_SIZE;
  123. pHTC->HTCControlService.MaxSvcMsgSize = MAX_HTC_SETUP_MSG_SIZE;
  124. pHTC->HTCControlService.ServiceCtx = pHTC;
  125. /* automatically register this pseudo service to endpoint 1 */
  126. pHTC->Endpoints[ENDPOINT0].pService = &pHTC->HTCControlService;
  127. HIF_get_default_pipe(pHTC->hifHandle, &pHTC->Endpoints[ENDPOINT0].UpLinkPipeID,
  128. &pHTC->Endpoints[ENDPOINT0].DownLinkPipeID);
  129. /* Initialize control pipe so we could receive the HTC control packets */
  130. // @TODO: msg size!
  131. HIF_config_pipe(pHTC->hifHandle, pHTC->Endpoints[ENDPOINT0].UpLinkPipeID, 1);
  132. /* set the first free endpoint */
  133. pHTC->CurrentEpIndex = ENDPOINT1;
  134. pHTC->SetupCompleteCb = SetupComplete;
  135. /* setup buffers for just the setup phase, we only need 1 buffer to handle
  136. * setup */
  137. HTC_AssembleBuffers(pHTC, 4, MAX_HTC_SETUP_MSG_SIZE);
  138. /* start hardware layer so that we can queue buffers */
  139. HIF_start(pHTC->hifHandle);
  140. return pHTC;
  141. }
  142. LOCAL void _HTC_Shutdown(htc_handle_t htcHandle)
  143. {
  144. HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
  145. adf_os_mem_free(pHTC);
  146. }
  147. LOCAL void _HTC_RegisterService(htc_handle_t htcHandle, HTC_SERVICE *pService)
  148. {
  149. HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
  150. /* add it to the list */
  151. pService->pNext = pHTC->pServiceList;
  152. pHTC->pServiceList = pService;
  153. }
  154. LOCAL void _HTC_Ready(htc_handle_t htcHandle)
  155. {
  156. adf_nbuf_t pBuffer;
  157. HTC_READY_MSG *pReady;
  158. a_uint8_t *addr;
  159. HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
  160. pBuffer = HTCAllocMsgBuffer(pHTC);
  161. /* an optimization... the header length is chosen to
  162. * be aligned on a 16 bit bounday, the fields in the message are designed to
  163. * be aligned */
  164. addr = adf_nbuf_put_tail(pBuffer, sizeof(HTC_READY_MSG));
  165. pReady = (HTC_READY_MSG *)addr;
  166. A_MEMZERO(pReady,sizeof(HTC_READY_MSG));
  167. pReady->MessageID = adf_os_htons(HTC_MSG_READY_ID);
  168. pReady->CreditSize = adf_os_htons((A_UINT16)pHTC->RecvBufferSize);
  169. pReady->CreditCount = adf_os_htons((A_UINT16)pHTC->TotalCredits);
  170. pReady->MaxEndpoints = ENDPOINT_MAX;
  171. /* send out the message */
  172. HTC_SendMsg(pHTC, ENDPOINT0, pBuffer);
  173. /* now we need to wait for service connection requests */
  174. }
  175. LOCAL void ReturnBuffers(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID,
  176. adf_nbuf_t pBuffers, A_BOOL sendCreditFlag)
  177. {
  178. int nbufs = 1;
  179. HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
  180. /* supply some head-room again */
  181. adf_nbuf_push_head(pBuffers, HTC_HDR_LENGTH);
  182. /* enqueue all buffers to the single mailbox */
  183. HIF_return_recv_buf(pHTC->hifHandle, pHTC->Endpoints[EndpointID].UpLinkPipeID, pBuffers);
  184. if (pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE) {
  185. A_UINT32 epCreditMask = (1 << EndpointID);
  186. /* we are running normally */
  187. /* update pending credit counts with the number of buffers that were added */
  188. pHTC->Endpoints[EndpointID].CreditsToReturn += (A_INT16)nbufs;
  189. pHTC->Endpoints[EndpointID].CreditsConsumed -= (A_INT16)nbufs;
  190. /* update bit map that this endpoint has non-zero credits */
  191. pHTC->EpCreditPendingMap |= epCreditMask;
  192. if (sendCreditFlag) {
  193. HTCCheckAndSendCreditReport(pHTC, epCreditMask,&pHTC->Endpoints[EndpointID],EndpointID);
  194. }
  195. } else {
  196. /* we have not started yet so all return operations are simply adding buffers
  197. * to the interface at startup, so we can keep track of how many total
  198. * credits we get */
  199. /* update global count that will be returned to the host */
  200. pHTC->TotalCredits += nbufs;
  201. }
  202. }
  203. LOCAL void _HTC_ReturnBuffersList(htc_handle_t htcHandle,
  204. HTC_ENDPOINT_ID EndpointID,
  205. adf_nbuf_queue_t bufHead)
  206. {
  207. HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
  208. adf_nbuf_t netbuf, tmpNbuf;
  209. /* retrieve each nbuf in the queue */
  210. netbuf = adf_nbuf_queue_first(&bufHead);
  211. while (netbuf) {
  212. tmpNbuf = netbuf;
  213. netbuf = adf_nbuf_queue_next(netbuf);
  214. ReturnBuffers(htcHandle, EndpointID, tmpNbuf, FALSE);
  215. }
  216. HTCCheckAndSendCreditReport(pHTC, (1 << EndpointID),&pHTC->Endpoints[EndpointID],EndpointID);
  217. }
  218. LOCAL void _HTC_ReturnBuffers(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID,
  219. adf_nbuf_t pBuffers)
  220. {
  221. ReturnBuffers(htcHandle, EndpointID, pBuffers, TRUE);
  222. }
  223. LOCAL void _HTC_SendMsg(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID,
  224. adf_nbuf_t pBuffers)
  225. {
  226. HTC_FRAME_HDR *pHTCHdr;
  227. int totsz;
  228. HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
  229. HTC_BUF_CONTEXT *ctx;
  230. ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(pBuffers);
  231. /* init total size (this does not include the space we will put in for the HTC header) */
  232. totsz = adf_nbuf_len(pBuffers);
  233. /* the first buffer stores the header */
  234. /* back up buffer by a header size when we pass it down, by agreed upon convention the caller
  235. * points the buffer to it's payload and leaves head room for the HTC header
  236. * Note: in HTCSendDoneHandler(), we undo this so that the caller get's it's buffer
  237. * back untainted */
  238. pHTCHdr = (HTC_FRAME_HDR *)adf_nbuf_push_head(pBuffers, HTC_HDR_LENGTH);
  239. /* flag that this is the header buffer that was modified */
  240. ctx->htc_flags |= HTC_FLAGS_BUF_HDR;
  241. /* mark where this buffer came from */
  242. ctx->end_point = EndpointID;
  243. /* the header start is ALWAYS aligned since we DMA it directly */
  244. /* set some fields, the rest of them will be filled below when we check for
  245. * trailer space */
  246. pHTCHdr->Flags = 0;
  247. pHTCHdr->EndpointID = EndpointID;
  248. /* check opportunistically if we can return any reports via a trailer */
  249. do {
  250. int room,i,totalReportBytes;
  251. A_UINT32 creditsPendingMap, compareMask;
  252. HTC_CREDIT_REPORT *pCreditRpt;
  253. HTC_RECORD_HDR *pRecHdr;
  254. int pipeMaxLen;
  255. A_UINT32 roomForPipeMaxLen;
  256. /* figure out how much room the last buffer can spare */
  257. pipeMaxLen = HIF_get_max_msg_len(pHTC->hifHandle,
  258. pHTC->Endpoints[EndpointID].DownLinkPipeID);
  259. roomForPipeMaxLen = pipeMaxLen - adf_nbuf_headroom(pBuffers) - adf_nbuf_len(pBuffers);
  260. if ( roomForPipeMaxLen < 0 ) {
  261. roomForPipeMaxLen = 0;
  262. }
  263. room = adf_os_min( adf_nbuf_tailroom(pBuffers), roomForPipeMaxLen);
  264. if (room < (int)(sizeof(HTC_CREDIT_REPORT) + sizeof(HTC_RECORD_HDR))) {
  265. /* no room for any reports */
  266. break;
  267. }
  268. /* note, a record header only has 8 bit fields, so this is safe.
  269. * we need an uncached pointer here too */
  270. totalReportBytes = 0;
  271. /* get a copy */
  272. creditsPendingMap = pHTC->EpCreditPendingMap;
  273. /* test pending map to see if we can send a report , if any
  274. * credits are available, we might as well send them on the
  275. * unused space in the buffer */
  276. if (creditsPendingMap) {
  277. pRecHdr = (HTC_RECORD_HDR *)adf_nbuf_put_tail(pBuffers,
  278. sizeof(HTC_RECORD_HDR));
  279. /* set the ID, the length will be updated with the number of credit reports we
  280. * can fit (see below) */
  281. pRecHdr->RecordID = HTC_RECORD_CREDITS;
  282. pRecHdr->Length = 0;
  283. /* the credit report follows the record header */
  284. totalReportBytes += sizeof(HTC_RECORD_HDR);
  285. room -= sizeof(HTC_RECORD_HDR);
  286. /* walkthrough pending credits map and build the records */
  287. for (i = 0;
  288. (creditsPendingMap != 0) && (room >= (int)sizeof(HTC_CREDIT_REPORT));
  289. i++) {
  290. compareMask = (1 << i);
  291. if (compareMask & creditsPendingMap) {
  292. pCreditRpt = (HTC_CREDIT_REPORT *)adf_nbuf_put_tail(pBuffers,
  293. sizeof(HTC_CREDIT_REPORT));
  294. /* clear pending mask, we are going to return all these credits */
  295. creditsPendingMap &= ~(compareMask);
  296. /* add this record */
  297. pCreditRpt->EndpointID = i;
  298. pCreditRpt->Credits = (A_UINT8)pHTC->Endpoints[i].CreditsToReturn;
  299. /* remove pending credits, we always send deltas */
  300. pHTC->Endpoints[i].CreditsToReturn = 0;
  301. /* adjust new threshold for this endpoint if needed */
  302. CHECK_AND_ADJUST_CREDIT_THRESHOLD(&pHTC->Endpoints[i]);
  303. /* update this record length */
  304. pRecHdr->Length += sizeof(HTC_CREDIT_REPORT);
  305. room -= sizeof(HTC_CREDIT_REPORT);
  306. totalReportBytes += sizeof(HTC_CREDIT_REPORT);
  307. if ( room < sizeof(HTC_CREDIT_REPORT) ) {
  308. break;
  309. }
  310. }
  311. }
  312. /* update new pending credits map */
  313. pHTC->EpCreditPendingMap = creditsPendingMap;
  314. }
  315. if (totalReportBytes <= 0) {
  316. break;
  317. }
  318. /* must fit into a byte, this should never actually happen since
  319. * the maximum possible number of endpoints is 32.
  320. * The trailer can have at most 1 credit record with up to 32 reports in the record.
  321. * The trailer can have at most 1 lookahead record with only 1 lookahead report in the record.
  322. */
  323. /* set header option bytes */
  324. pHTCHdr->ControlBytes[0] = totalReportBytes;
  325. /* HTC frame contains a trailer */
  326. pHTCHdr->Flags |= HTC_FLAGS_RECV_TRAILER;
  327. /* increment total size by the reports we added */
  328. totsz += totalReportBytes;
  329. /* adjust the last buffer we used for adding on the trailer */
  330. } while (FALSE);
  331. if (totsz == 0) {
  332. }
  333. /* set length for message (this includes any reports that were added above) */
  334. pHTCHdr->PayloadLen = adf_os_htons(totsz);
  335. HIF_send_buffer(pHTC->hifHandle, pHTC->Endpoints[EndpointID].DownLinkPipeID, pBuffers);
  336. }
  337. void _HTC_PauseRecv(HTC_ENDPOINT_ID EndpointID)
  338. {
  339. }
  340. void _HTC_ResumeRecv(HTC_ENDPOINT_ID EndpointID)
  341. {
  342. }
  343. int _HTC_GetReservedHeadroom(htc_handle_t htcHandle)
  344. {
  345. HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
  346. return HTC_HDR_LENGTH + HIF_get_reserved_headroom(pHTC->hifHandle);
  347. }
  348. void htc_module_install(struct htc_apis *pAPIs)
  349. {
  350. pAPIs->_HTC_Init = _HTC_Init;
  351. pAPIs->_HTC_ReturnBuffers = _HTC_ReturnBuffers;
  352. pAPIs->_HTC_ReturnBuffersList = _HTC_ReturnBuffersList;
  353. pAPIs->_HTC_Ready = _HTC_Ready;
  354. pAPIs->_HTC_RegisterService = _HTC_RegisterService;
  355. pAPIs->_HTC_SendMsg = _HTC_SendMsg;
  356. pAPIs->_HTC_Shutdown = _HTC_Shutdown;
  357. pAPIs->_HTC_GetReservedHeadroom = _HTC_GetReservedHeadroom;
  358. pAPIs->_HTC_MsgRecvHandler = HTCMsgRecvHandler;
  359. pAPIs->_HTC_SendDoneHandler = HTCSendDoneHandler;
  360. pAPIs->_HTC_ControlSvcProcessMsg = HTCControlSvcProcessMsg;
  361. pAPIs->_HTC_ControlSvcProcessSendComplete = HTCControlSvcProcessSendComplete;
  362. }
  363. /* free message to the free list */
  364. LOCAL void HTCFreeMsgBuffer(HTC_CONTEXT *pHTC, adf_nbuf_t buf)
  365. {
  366. BUF_Pool_free_buf(pHTC->PoolHandle, POOL_ID_HTC_CONTROL, buf);
  367. }
  368. /* HTC control message allocator (also used for empty frames to send trailer options) */
  369. LOCAL adf_nbuf_t HTCAllocMsgBuffer(HTC_CONTEXT *pHTC)
  370. {
  371. return BUF_Pool_alloc_buf(pHTC->PoolHandle,
  372. POOL_ID_HTC_CONTROL,
  373. HTC_GetReservedHeadroom(pHTC));
  374. }
  375. LOCAL void HTCCheckAndSendCreditReport(HTC_CONTEXT *pHTC, A_UINT32 EpMask,
  376. HTC_ENDPOINT *pEndpoint, HTC_ENDPOINT_ID Eid)
  377. {
  378. adf_nbuf_t pCredBuffer;
  379. HTC_BUF_CONTEXT *ctx;
  380. do {
  381. /* check if host needs credits */
  382. if (!(pHTC->EpHostNeedsCreditMap & EpMask)) {
  383. /* host does not need any credits for this set */
  384. break;
  385. }
  386. /* check if any are pending */
  387. if (!(pHTC->EpCreditPendingMap & EpMask)) {
  388. /* nothing to send up */
  389. break;
  390. }
  391. /* was an endpoint specified? */
  392. if (pEndpoint != NULL) {
  393. /* see if a threshold is in effect for this endpoint */
  394. if (pEndpoint->CreditReturnThreshhold != 0) {
  395. if (pEndpoint->CreditsToReturn < pEndpoint->CreditReturnThreshhold) {
  396. /* this endpoint is using a threshold to prevent credits from dribbling
  397. * back to the host */
  398. break;
  399. }
  400. }
  401. if (pEndpoint->PendingCreditReports >= pHTC->MaxEpPendingCreditRpts) {
  402. /* this endpoint already has some reports outstanding */
  403. /* flag that as soon as a buffer is reaped, we issue a credit update to
  404. * pick up this credit that is being held up because the endpoint has already
  405. * exceeded the max outstanding credit report limit */
  406. pHTC->StateFlags |= HTC_SEND_CREDIT_UPDATE_SOON;
  407. break;
  408. }
  409. }
  410. /* if we get here we have some credits to send up */
  411. /* allocate a message buffer for the trailer */
  412. pCredBuffer = HTCAllocMsgBuffer(pHTC);
  413. if (NULL == pCredBuffer) {
  414. /* no buffers left to send an empty message with trailers, host will just
  415. * have to wait until we get our endpoint 0 messages back.. */
  416. /* mark that we need to send an update as soon as we can get a buffer back */
  417. pHTC->StateFlags |= HTC_SEND_CREDIT_UPDATE_SOON;
  418. break;
  419. }
  420. ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(pCredBuffer);
  421. if (pEndpoint != NULL) {
  422. /* keep track of pending reports */
  423. pEndpoint->PendingCreditReports++;
  424. /* save the endpoint in order to decrement the count when the send completes */
  425. ctx->htc_flags = Eid | HTC_FLAGS_CREDIT_RPT;
  426. }
  427. /* this is an empty message, the HTC_SendMsg will tack on a trailer in the remaining
  428. * space, NOTE: no need to flush the cache, the header and trailers are assembled
  429. * using uncached addresses */
  430. HTC_SendMsg(pHTC, ENDPOINT0, pCredBuffer);
  431. } while (FALSE);
  432. }
  433. /* called in response to the arrival of a service connection message */
  434. LOCAL void HTCProcessConnectMsg(HTC_CONTEXT *pHTC, HTC_CONNECT_SERVICE_MSG *pMsg)
  435. {
  436. HTC_SERVICE *pService = pHTC->pServiceList;
  437. A_UINT8 connectStatus = HTC_SERVICE_NOT_FOUND;
  438. adf_nbuf_t pBuffer;
  439. HTC_CONNECT_SERVICE_RESPONSE_MSG *pRspMsg;
  440. int metaDataOutLen = 0;
  441. A_UINT16 serviceId = adf_os_ntohs(pMsg->ServiceID);
  442. pBuffer = HTCAllocMsgBuffer(pHTC);
  443. /* note : this will be aligned */
  444. pRspMsg = (HTC_CONNECT_SERVICE_RESPONSE_MSG *)
  445. adf_nbuf_put_tail(pBuffer, sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG));
  446. A_MEMZERO(pRspMsg,sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG));
  447. pRspMsg->MessageID = adf_os_htons(HTC_MSG_CONNECT_SERVICE_RESPONSE_ID);
  448. /* reflect the service ID for this connect attempt */
  449. pRspMsg->ServiceID = adf_os_htons(serviceId);
  450. while (pService) {
  451. if (pHTC->CurrentEpIndex >= ENDPOINT_MAX) {
  452. /* no more endpoints */
  453. connectStatus = HTC_SERVICE_NO_RESOURCES;
  454. break;
  455. }
  456. if (serviceId == pService->ServiceID) {
  457. /* we found a match */
  458. A_UINT8 *pMetaDataIN = NULL;
  459. A_UINT8 *pMetaDataOut;
  460. /* outgoing meta data resides in the space after the response message */
  461. pMetaDataOut = ((A_UINT8 *)pRspMsg) + sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG);
  462. if (pMsg->ServiceMetaLength != 0) {
  463. /* the meta data follows the connect service message */
  464. pMetaDataIN = ((A_UINT8 *)pMsg) + sizeof(HTC_CONNECT_SERVICE_MSG);
  465. }
  466. /* call the connect callback with the endpoint to use and pointers to meta data */
  467. connectStatus = pService->ProcessConnect(pService,
  468. pHTC->CurrentEpIndex,
  469. pMetaDataIN,
  470. pMsg->ServiceMetaLength,
  471. pMetaDataOut,
  472. &metaDataOutLen);
  473. /* check if the service accepted this connection request */
  474. if (HTC_SERVICE_SUCCESS == connectStatus) {
  475. /* set the length of the response meta data going back to the host */
  476. pRspMsg->ServiceMetaLength = (A_UINT8)metaDataOutLen;
  477. /* set the endpoint ID the host will now communicate over */
  478. pRspMsg->EndpointID = pHTC->CurrentEpIndex;
  479. /* return the maximum message size for this service */
  480. pRspMsg->MaxMsgSize = adf_os_htons((A_UINT16)pService->MaxSvcMsgSize);
  481. /* assign this endpoint to this service, this will be used in routing messages */
  482. pHTC->Endpoints[pHTC->CurrentEpIndex].pService = pService;
  483. /* set connection flags */
  484. pHTC->Endpoints[pHTC->CurrentEpIndex].ConnectionFlags = pMsg->ConnectionFlags;
  485. pHTC->Endpoints[pHTC->CurrentEpIndex].DownLinkPipeID = pMsg->DownLinkPipeID;
  486. pHTC->Endpoints[pHTC->CurrentEpIndex].UpLinkPipeID = pMsg->UpLinkPipeID;
  487. /* mark that we are now connected */
  488. pService->ServiceFlags |= HTC_SERVICE_FLAGS_CONNECTED;
  489. /* bump up our index, this EP is now in use */
  490. pHTC->CurrentEpIndex++;
  491. }
  492. break;
  493. }
  494. pService = pService->pNext;
  495. }
  496. pRspMsg->Status = connectStatus;
  497. /* send out the response message */
  498. HTC_SendMsg(pHTC, ENDPOINT0, pBuffer);
  499. }
  500. LOCAL void HTCProcessConfigPipeMsg(HTC_CONTEXT *pHTC, HTC_CONFIG_PIPE_MSG *pMsg)
  501. {
  502. adf_nbuf_t pBuffer;
  503. HTC_CONFIG_PIPE_RESPONSE_MSG *pRspMsg;
  504. pBuffer = HTCAllocMsgBuffer(pHTC);
  505. /* note : this will be aligned */
  506. pRspMsg = (HTC_CONFIG_PIPE_RESPONSE_MSG *)
  507. adf_nbuf_put_tail(pBuffer, sizeof(HTC_CONFIG_PIPE_RESPONSE_MSG));
  508. A_MEMZERO(pRspMsg,sizeof(HTC_CONFIG_PIPE_RESPONSE_MSG));
  509. pRspMsg->MessageID = adf_os_htons(HTC_MSG_CONFIG_PIPE_RESPONSE_ID);
  510. /* reflect the service ID for this connect attempt */
  511. pRspMsg->PipeID = pMsg->PipeID;
  512. if ( HIF_is_pipe_supported(pHTC->hifHandle, pMsg->PipeID) ) {
  513. pRspMsg->Status = 0;
  514. } else {
  515. pRspMsg->Status = 1;
  516. goto config_done;
  517. }
  518. if ( (pHTC->TotalCreditsAssigned + pMsg->CreditCount) <= pHTC->TotalCredits ) {
  519. pHTC->TotalCreditsAssigned += pMsg->CreditCount;
  520. } else {
  521. pRspMsg->Status = 2;
  522. goto config_done;
  523. }
  524. HIF_config_pipe(pHTC->hifHandle, pMsg->PipeID, pMsg->CreditCount);
  525. config_done:
  526. /* send out the response message */
  527. HTC_SendMsg(pHTC, ENDPOINT0, pBuffer);
  528. }
  529. /* process an incomming control message from the host */
  530. LOCAL void HTCControlSvcProcessMsg(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t hdr_buf,
  531. adf_nbuf_t pBuffers, void *arg)
  532. {
  533. A_BOOL setupComplete = FALSE;
  534. a_uint8_t *anbdata;
  535. a_uint32_t anblen;
  536. HTC_CONTEXT *pHTC = (HTC_CONTEXT *)arg;
  537. HTC_UNKNOWN_MSG *pMsg;
  538. adf_os_assert(hdr_buf == ADF_NBUF_NULL);
  539. /* we assume buffers are aligned such that we can access the message
  540. * parameters directly*/
  541. adf_nbuf_peek_header(pBuffers, &anbdata, &anblen);
  542. pMsg = (HTC_UNKNOWN_MSG *)anbdata;
  543. /* we cannot handle fragmented messages across buffers */
  544. switch ( adf_os_ntohs(pMsg->MessageID) ) {
  545. case HTC_MSG_CONNECT_SERVICE_ID:
  546. HTCProcessConnectMsg(pHTC, (HTC_CONNECT_SERVICE_MSG *)pMsg);
  547. break;
  548. case HTC_MSG_CONFIG_PIPE_ID:
  549. HTCProcessConfigPipeMsg(pHTC, (HTC_CONFIG_PIPE_MSG *)pMsg);
  550. break;
  551. case HTC_MSG_SETUP_COMPLETE_ID:
  552. /* the host has indicated that it has completed all
  553. setup tasks and we can now let the services take over to
  554. run the rest of the application */
  555. setupComplete = TRUE;
  556. /* can't get this more than once */
  557. break;
  558. default:
  559. ;
  560. }
  561. if (pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE) {
  562. /* recycle buffer only if we are fully running */
  563. HTC_ReturnBuffers(pHTC, ENDPOINT0,pBuffers);
  564. } else {
  565. /* supply some head-room again */
  566. adf_nbuf_push_head(pBuffers, HTC_HDR_LENGTH);
  567. /* otherwise return the packet back to mbox */
  568. HIF_return_recv_buf(pHTC->hifHandle, pHTC->Endpoints[EndpointID].UpLinkPipeID, pBuffers);
  569. }
  570. if (setupComplete) {
  571. /* mark that setup has completed */
  572. pHTC->StateFlags |= HTC_STATE_SETUP_COMPLETE;
  573. if (pHTC->SetupCompleteCb != NULL) {
  574. pHTC->SetupCompleteCb();
  575. }
  576. }
  577. }
  578. /* callback when endpoint 0 send buffers are completed */
  579. LOCAL void HTCControlSvcProcessSendComplete(HTC_ENDPOINT_ID EndpointID,
  580. adf_nbuf_t pBuffers, void *arg)
  581. {
  582. HTC_CONTEXT *pHTC = (HTC_CONTEXT *)arg;
  583. HTC_BUF_CONTEXT *ctx;
  584. HTC_ENDPOINT_ID creditRptEndpoint;
  585. ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(pBuffers);
  586. /* put them back into the pool */
  587. if ( ctx->htc_flags & HTC_FLAGS_CREDIT_RPT ) {
  588. /* extract the endpoint number that requested this credit report */
  589. creditRptEndpoint = ctx->htc_flags & HTC_FLAGS_CRPT_EP_MASK;
  590. pHTC->Endpoints[creditRptEndpoint].PendingCreditReports--;
  591. }
  592. HTCFreeMsgBuffer(pHTC, pBuffers);
  593. if (pHTC->StateFlags & HTC_SEND_CREDIT_UPDATE_SOON) {
  594. /* this flag is set when the host could not send a credit report
  595. * because we ran out of HTC control buffers */
  596. pHTC->StateFlags &= ~HTC_SEND_CREDIT_UPDATE_SOON;
  597. /* send out a report if anything is pending */
  598. HTCCheckAndSendCreditReport(pHTC, HTC_ANY_ENDPOINT_MASK,NULL,ENDPOINT_MAX);
  599. }
  600. }
  601. LOCAL void HTCSendDoneHandler(adf_nbuf_t buf, void *context)
  602. {
  603. A_UINT8 current_eid;
  604. HTC_CONTEXT *pHTC = (HTC_CONTEXT *)context;
  605. HTC_BUF_CONTEXT *ctx;
  606. ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(buf);
  607. current_eid = ctx->end_point;
  608. /* Walk through the buffers and fixup the ones we used for HTC headers.
  609. * The buffer list may contain more than one string of HTC buffers comprising of an
  610. * HTC message so we need to check every buffer */
  611. adf_nbuf_pull_head(buf, HTC_HDR_LENGTH);
  612. pHTC->Endpoints[current_eid].pService->
  613. ProcessSendBufferComplete(current_eid,
  614. buf,
  615. pHTC->Endpoints[current_eid].pService->ServiceCtx);
  616. }
  617. LOCAL void AdjustCreditThreshold(HTC_ENDPOINT *pEndpoint)
  618. {
  619. A_INT16 creditsOutstanding = pEndpoint->CreditsToReturn + pEndpoint->CreditsConsumed;
  620. /* set the new threshold based on the number of credits that have been consumed
  621. * and which have not been returned by the app.
  622. * Note: it is okay for this threshold to be zero which indicates no threshold
  623. * is in use */
  624. switch (pEndpoint->ConnectionFlags & HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_MASK) {
  625. case HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_FOURTH :
  626. creditsOutstanding >>= 2;
  627. break;
  628. case HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_HALF :
  629. creditsOutstanding >>= 1;
  630. break;
  631. case HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_THREE_FOURTHS :
  632. creditsOutstanding = (creditsOutstanding * 3) >> 2;
  633. break;
  634. /* default case is unity */
  635. }
  636. pEndpoint->CreditReturnThreshhold = creditsOutstanding;
  637. }
  638. LOCAL void RedistributeCredit(adf_nbuf_t buf, int toPipeId)
  639. {
  640. }
  641. /* callback from the mailbox hardware layer when a full message arrives */
  642. LOCAL void HTCMsgRecvHandler(adf_nbuf_t hdr_buf, adf_nbuf_t buffer, void *context)
  643. {
  644. HTC_ENDPOINT *pEndpoint;
  645. A_UINT32 eidMask;
  646. int eid;
  647. a_uint8_t *anbdata;
  648. a_uint32_t anblen;
  649. HTC_FRAME_HDR *pHTCHdr;
  650. HTC_CONTEXT *pHTC = (HTC_CONTEXT *)context;
  651. adf_nbuf_t tmp_nbuf;
  652. if (hdr_buf == ADF_NBUF_NULL) {
  653. /* HTC hdr is not in the hdr_buf */
  654. tmp_nbuf = buffer;
  655. }
  656. else {
  657. tmp_nbuf = hdr_buf;
  658. }
  659. adf_nbuf_peek_header(tmp_nbuf, &anbdata, &anblen);
  660. pHTCHdr = (HTC_FRAME_HDR *)anbdata;
  661. eid = pHTCHdr->EndpointID;
  662. pEndpoint = &pHTC->Endpoints[eid];
  663. eidMask = 1 << eid;
  664. if (pHTCHdr->Flags & HTC_FLAGS_CREDIT_REDISTRIBUTION) {
  665. /* The pipe id where the credit is redistributed to is carried in Control
  666. * Byte 0 */
  667. RedistributeCredit(tmp_nbuf, pHTCHdr->ControlBytes[0]);
  668. return;
  669. }
  670. if (pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE) {
  671. /* after setup we keep track of credit consumption to allow us to
  672. * adjust thresholds to reduce credit dribbling */
  673. pEndpoint->CreditsConsumed ++;
  674. }
  675. /* from the design document, we put the endpoint into a "host-needs-credit" state
  676. * when we receive a frame with the NEED_CREDIT_UPDATE flag set .
  677. * if the host received credits through an opportunistic path, then it can
  678. * issue a another frame with this bit cleared, this signals the target to clear
  679. * the "host-needs-credit" state */
  680. if (pHTCHdr->Flags & HTC_FLAGS_NEED_CREDIT_UPDATE) {
  681. /* the host is running low (or is out) of credits on this
  682. * endpoint, update mask */
  683. pHTC->EpHostNeedsCreditMap |= eidMask;
  684. /* check and set new threshold since host has reached a low credit situation */
  685. CHECK_AND_ADJUST_CREDIT_THRESHOLD(pEndpoint);
  686. } else {
  687. /* clear the flag */
  688. pHTC->EpHostNeedsCreditMap &= ~(eidMask);
  689. pEndpoint->CreditReturnThreshhold = 0;
  690. }
  691. /* Adjust the first buffer to point to the start of the actual
  692. payload, the first buffer contains the header */
  693. adf_nbuf_pull_head(tmp_nbuf, HTC_HDR_LENGTH);
  694. /* NOTE : This callback could re-queue the recv buffers within this calling context.
  695. * The callback could also send a response message within the context of this callback
  696. * as the result of parsing this message. In either case, if there are
  697. * pending credits and the host needs them, a credit report will be sent either through
  698. * the response message trailer or a NULL message through HTC_ReturnBuffers().
  699. */
  700. pEndpoint->pService->ProcessRecvMsg(eid, hdr_buf, buffer, pEndpoint->pService->ServiceCtx);
  701. /* Calls to HTC_ReturnBuffers drives the endpoint credit reporting state machine.
  702. * We do not want to delay credits for too long in the event that the application is
  703. * holding onto buffers for excessive periods of time. This gives us "some" better
  704. * opportunities to send up credits. */
  705. HTCCheckAndSendCreditReport(pHTC, eidMask, pEndpoint, eid);
  706. }