2 * Copyright (c) 2013 Qualcomm Atheros, Inc.
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:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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
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.
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.
38 * @Abstract: host target communications
43 #include <Magpie_api.h>
47 #include <adf_os_mem.h>
48 #include <adf_os_io.h>
50 #include "htc_internal.h"
52 #define A_UNCACHED_ADDR(addr) addr
55 LOCAL void HTCControlSvcProcessMsg(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t hdr_buf, adf_nbuf_t pBuffers, void *arg);
56 LOCAL void HTCControlSvcProcessSendComplete(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers, void *arg);
57 LOCAL void HTCMsgRecvHandler(adf_nbuf_t hdr_buf, adf_nbuf_t buf, void *context);
58 LOCAL void HTCSendDoneHandler(adf_nbuf_t buf, void *context);
59 LOCAL void HTCFreeMsgBuffer(HTC_CONTEXT *pHTC, adf_nbuf_t pBuffer);
60 LOCAL adf_nbuf_t HTCAllocMsgBuffer(HTC_CONTEXT *pHTC);
61 LOCAL void HTCCheckAndSendCreditReport(HTC_CONTEXT *pHTC, A_UINT32 EpMask, HTC_ENDPOINT *pEndpoint, HTC_ENDPOINT_ID Id);
62 LOCAL void AdjustCreditThreshold(HTC_ENDPOINT *pEndpoint);
63 LOCAL void HTC_AssembleBuffers(HTC_CONTEXT *pHTC, int Count, int Size);
64 LOCAL htc_handle_t _HTC_Init(/*A_UINT32 dataAddr,*/
65 HTC_SETUP_COMPLETE_CB SetupComplete,
67 LOCAL void _HTC_RegisterService(htc_handle_t handle, HTC_SERVICE *pService);
68 LOCAL void _HTC_Ready(htc_handle_t handle);
69 LOCAL void ReturnBuffers(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers, A_BOOL sendCreditFlag);
70 LOCAL void _HTC_ReturnBuffers(htc_handle_t handle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers);
71 LOCAL void _HTC_ReturnBuffersList(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_queue_t bufHead);
72 LOCAL void _HTC_SendMsg(htc_handle_t handle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers);
73 void _HTC_PauseRecv(HTC_ENDPOINT_ID EndpointID);
74 void _HTC_ResumeRecv(HTC_ENDPOINT_ID EndpointID);
75 LOCAL void HTCProcessConnectMsg(HTC_CONTEXT *pHTC, HTC_CONNECT_SERVICE_MSG *pMsg);
76 LOCAL void HTCProcessConfigPipeMsg(HTC_CONTEXT *pHTC, HTC_CONFIG_PIPE_MSG *pMsg);
77 LOCAL void RedistributeCredit(adf_nbuf_t buf, int toPipeId);
78 LOCAL void _HTC_Shutdown(htc_handle_t htcHandle);
80 /* macro to check if the service wants to prevent credit dribbling by using
81 a dynamic threshold */
82 #define CHECK_AND_ADJUST_CREDIT_THRESHOLD(pEndpoint) \
83 if ((pEndpoint)->ConnectionFlags & HTC_CONNECT_FLAGS_REDUCE_CREDIT_DRIBBLE) { \
84 AdjustCreditThreshold((pEndpoint)); \
87 LOCAL void HTC_AssembleBuffers(HTC_CONTEXT *pHTC, int Count, int Size)
89 BUF_Pool_create_pool(pHTC->PoolHandle, POOL_ID_HTC_CONTROL, Count, Size);
92 LOCAL htc_handle_t _HTC_Init(HTC_SETUP_COMPLETE_CB SetupComplete,
95 HIF_CALLBACK hifCBConfig;
98 pHTC = (HTC_CONTEXT *)adf_os_mem_alloc(sizeof(HTC_CONTEXT));
100 adf_os_mem_zero(pHTC, sizeof(HTC_CONTEXT));
102 pHTC->OSHandle = pConfig->OSHandle;
103 pHTC->PoolHandle = pConfig->PoolHandle;
104 pHTC->hifHandle = pConfig->HIFHandle;
106 hifCBConfig.send_buf_done = A_INDIR(htc._HTC_SendDoneHandler);
107 hifCBConfig.recv_buf = A_INDIR(htc._HTC_MsgRecvHandler);
108 hifCBConfig.context = pHTC;
110 /* initialize hardware layer */
111 HIF_register_callback(pConfig->HIFHandle, &hifCBConfig);
113 /* see if the host wants us to override the number of ctrl buffers */
114 pHTC->NumBuffersForCreditRpts = 0;
116 if (0 == pHTC->NumBuffersForCreditRpts) {
117 /* nothing to override, simply set default */
118 pHTC->NumBuffersForCreditRpts = HTC_DEFAULT_NUM_CTRL_BUFFERS;
121 pHTC->MaxEpPendingCreditRpts = 0;
123 if (0 == pHTC->MaxEpPendingCreditRpts) {
124 pHTC->MaxEpPendingCreditRpts = HTC_DEFAULT_MAX_EP_PENDING_CREDIT_REPORTS;
126 /* calculate the total allocation size based on the number of credit report buffers */
127 pHTC->CtrlBufferAllocSize = MIN_CREDIT_BUFFER_ALLOC_SIZE * pHTC->NumBuffersForCreditRpts;
128 /* we need at least enough buffer space for 1 ctrl message */
129 pHTC->CtrlBufferAllocSize = A_MAX(pHTC->CtrlBufferAllocSize,MAX_HTC_SETUP_MSG_SIZE);
131 /* save the size of each buffer/credit we will receive */
132 pHTC->RecvBufferSize = pConfig->CreditSize; //RecvBufferSize;
133 pHTC->TotalCredits = pConfig->CreditNumber;
134 pHTC->TotalCreditsAssigned = 0;
136 /* setup the pseudo service that handles HTC control messages */
137 pHTC->HTCControlService.ProcessRecvMsg = A_INDIR(htc._HTC_ControlSvcProcessMsg);
138 pHTC->HTCControlService.ProcessSendBufferComplete = A_INDIR(htc._HTC_ControlSvcProcessSendComplete);
139 pHTC->HTCControlService.TrailerSpcCheckLimit = HTC_CTRL_BUFFER_CHECK_SIZE;
140 pHTC->HTCControlService.MaxSvcMsgSize = MAX_HTC_SETUP_MSG_SIZE;
141 pHTC->HTCControlService.ServiceCtx = pHTC;
143 /* automatically register this pseudo service to endpoint 1 */
144 pHTC->Endpoints[ENDPOINT0].pService = &pHTC->HTCControlService;
145 HIF_get_default_pipe(pHTC->hifHandle, &pHTC->Endpoints[ENDPOINT0].UpLinkPipeID,
146 &pHTC->Endpoints[ENDPOINT0].DownLinkPipeID);
148 /* Initialize control pipe so we could receive the HTC control packets */
150 HIF_config_pipe(pHTC->hifHandle, pHTC->Endpoints[ENDPOINT0].UpLinkPipeID, 1);
152 /* set the first free endpoint */
153 pHTC->CurrentEpIndex = ENDPOINT1;
154 pHTC->SetupCompleteCb = SetupComplete;
156 /* setup buffers for just the setup phase, we only need 1 buffer to handle
158 HTC_AssembleBuffers(pHTC, 4, MAX_HTC_SETUP_MSG_SIZE);
160 /* start hardware layer so that we can queue buffers */
161 HIF_start(pHTC->hifHandle);
166 LOCAL void _HTC_Shutdown(htc_handle_t htcHandle)
168 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
170 adf_os_mem_free(pHTC);
173 LOCAL void _HTC_RegisterService(htc_handle_t htcHandle, HTC_SERVICE *pService)
175 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
177 /* add it to the list */
178 pService->pNext = pHTC->pServiceList;
179 pHTC->pServiceList = pService;
182 LOCAL void _HTC_Ready(htc_handle_t htcHandle)
185 HTC_READY_MSG *pReady;
187 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
189 pBuffer = HTCAllocMsgBuffer(pHTC);
191 /* an optimization... the header length is chosen to
192 * be aligned on a 16 bit bounday, the fields in the message are designed to
194 addr = adf_nbuf_put_tail(pBuffer, sizeof(HTC_READY_MSG));
195 pReady = (HTC_READY_MSG *)addr;
196 A_MEMZERO(pReady,sizeof(HTC_READY_MSG));
197 pReady->MessageID = adf_os_htons(HTC_MSG_READY_ID);
198 pReady->CreditSize = adf_os_htons((A_UINT16)pHTC->RecvBufferSize);
199 pReady->CreditCount = adf_os_htons((A_UINT16)pHTC->TotalCredits);
200 pReady->MaxEndpoints = ENDPOINT_MAX;
202 /* send out the message */
203 HTC_SendMsg(pHTC, ENDPOINT0, pBuffer);
204 /* now we need to wait for service connection requests */
207 LOCAL void ReturnBuffers(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID,
208 adf_nbuf_t pBuffers, A_BOOL sendCreditFlag)
211 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
213 /* supply some head-room again */
214 adf_nbuf_push_head(pBuffers, HTC_HDR_LENGTH);
216 /* enqueue all buffers to the single mailbox */
217 HIF_return_recv_buf(pHTC->hifHandle, pHTC->Endpoints[EndpointID].UpLinkPipeID, pBuffers);
219 if (pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE) {
220 A_UINT32 epCreditMask = (1 << EndpointID);
221 /* we are running normally */
222 /* update pending credit counts with the number of buffers that were added */
223 pHTC->Endpoints[EndpointID].CreditsToReturn += (A_INT16)nbufs;
224 pHTC->Endpoints[EndpointID].CreditsConsumed -= (A_INT16)nbufs;
225 /* update bit map that this endpoint has non-zero credits */
226 pHTC->EpCreditPendingMap |= epCreditMask;
228 if (sendCreditFlag) {
229 HTCCheckAndSendCreditReport(pHTC, epCreditMask,&pHTC->Endpoints[EndpointID],EndpointID);
233 /* we have not started yet so all return operations are simply adding buffers
234 * to the interface at startup, so we can keep track of how many total
236 /* update global count that will be returned to the host */
237 pHTC->TotalCredits += nbufs;
241 LOCAL void _HTC_ReturnBuffersList(htc_handle_t htcHandle,
242 HTC_ENDPOINT_ID EndpointID,
243 adf_nbuf_queue_t bufHead)
245 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
246 adf_nbuf_t netbuf, tmpNbuf;
248 /* retrieve each nbuf in the queue */
249 netbuf = adf_nbuf_queue_first(&bufHead);
254 netbuf = adf_nbuf_queue_next(netbuf);
256 ReturnBuffers(htcHandle, EndpointID, tmpNbuf, FALSE);
259 HTCCheckAndSendCreditReport(pHTC, (1 << EndpointID),&pHTC->Endpoints[EndpointID],EndpointID);
262 LOCAL void _HTC_ReturnBuffers(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID,
265 ReturnBuffers(htcHandle, EndpointID, pBuffers, TRUE);
268 LOCAL void _HTC_SendMsg(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID,
271 HTC_FRAME_HDR *pHTCHdr;
273 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
274 HTC_BUF_CONTEXT *ctx;
276 ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(pBuffers);
278 /* init total size (this does not include the space we will put in for the HTC header) */
279 totsz = adf_nbuf_len(pBuffers);
281 /* the first buffer stores the header */
282 /* back up buffer by a header size when we pass it down, by agreed upon convention the caller
283 * points the buffer to it's payload and leaves head room for the HTC header
284 * Note: in HTCSendDoneHandler(), we undo this so that the caller get's it's buffer
286 pHTCHdr = (HTC_FRAME_HDR *)adf_nbuf_push_head(pBuffers, HTC_HDR_LENGTH);
288 /* flag that this is the header buffer that was modified */
289 ctx->htc_flags |= HTC_FLAGS_BUF_HDR;
290 /* mark where this buffer came from */
291 ctx->end_point = EndpointID;
292 /* the header start is ALWAYS aligned since we DMA it directly */
294 /* set some fields, the rest of them will be filled below when we check for
297 pHTCHdr->EndpointID = EndpointID;
299 /* check opportunistically if we can return any reports via a trailer */
301 int room,i,totalReportBytes;
302 A_UINT32 creditsPendingMap, compareMask;
303 HTC_CREDIT_REPORT *pCreditRpt;
304 HTC_RECORD_HDR *pRecHdr;
306 A_UINT32 roomForPipeMaxLen;
308 /* figure out how much room the last buffer can spare */
309 pipeMaxLen = HIF_get_max_msg_len(pHTC->hifHandle,
310 pHTC->Endpoints[EndpointID].DownLinkPipeID);
311 roomForPipeMaxLen = pipeMaxLen - adf_nbuf_headroom(pBuffers) - adf_nbuf_len(pBuffers);
312 if ( roomForPipeMaxLen < 0 ) {
313 roomForPipeMaxLen = 0;
316 room = adf_os_min( adf_nbuf_tailroom(pBuffers), roomForPipeMaxLen);
317 if (room < (int)(sizeof(HTC_CREDIT_REPORT) + sizeof(HTC_RECORD_HDR))) {
318 /* no room for any reports */
321 /* note, a record header only has 8 bit fields, so this is safe.
322 * we need an uncached pointer here too */
323 totalReportBytes = 0;
326 creditsPendingMap = pHTC->EpCreditPendingMap;
328 /* test pending map to see if we can send a report , if any
329 * credits are available, we might as well send them on the
330 * unused space in the buffer */
331 if (creditsPendingMap) {
333 pRecHdr = (HTC_RECORD_HDR *)adf_nbuf_put_tail(pBuffers,
334 sizeof(HTC_RECORD_HDR));
336 /* set the ID, the length will be updated with the number of credit reports we
337 * can fit (see below) */
338 pRecHdr->RecordID = HTC_RECORD_CREDITS;
340 /* the credit report follows the record header */
341 totalReportBytes += sizeof(HTC_RECORD_HDR);
342 room -= sizeof(HTC_RECORD_HDR);
344 /* walkthrough pending credits map and build the records */
346 (creditsPendingMap != 0) && (room >= (int)sizeof(HTC_CREDIT_REPORT));
348 compareMask = (1 << i);
349 if (compareMask & creditsPendingMap) {
351 pCreditRpt = (HTC_CREDIT_REPORT *)adf_nbuf_put_tail(pBuffers,
352 sizeof(HTC_CREDIT_REPORT));
354 /* clear pending mask, we are going to return all these credits */
355 creditsPendingMap &= ~(compareMask);
356 /* add this record */
357 pCreditRpt->EndpointID = i;
358 pCreditRpt->Credits = (A_UINT8)pHTC->Endpoints[i].CreditsToReturn;
359 /* remove pending credits, we always send deltas */
360 pHTC->Endpoints[i].CreditsToReturn = 0;
361 /* adjust new threshold for this endpoint if needed */
362 CHECK_AND_ADJUST_CREDIT_THRESHOLD(&pHTC->Endpoints[i]);
363 /* update this record length */
364 pRecHdr->Length += sizeof(HTC_CREDIT_REPORT);
365 room -= sizeof(HTC_CREDIT_REPORT);
366 totalReportBytes += sizeof(HTC_CREDIT_REPORT);
368 if ( room < sizeof(HTC_CREDIT_REPORT) ) {
374 /* update new pending credits map */
375 pHTC->EpCreditPendingMap = creditsPendingMap;
378 if (totalReportBytes <= 0) {
382 /* must fit into a byte, this should never actually happen since
383 * the maximum possible number of endpoints is 32.
384 * The trailer can have at most 1 credit record with up to 32 reports in the record.
385 * The trailer can have at most 1 lookahead record with only 1 lookahead report in the record.
388 /* set header option bytes */
389 pHTCHdr->ControlBytes[0] = totalReportBytes;
390 /* HTC frame contains a trailer */
391 pHTCHdr->Flags |= HTC_FLAGS_RECV_TRAILER;
392 /* increment total size by the reports we added */
393 totsz += totalReportBytes;
394 /* adjust the last buffer we used for adding on the trailer */
400 /* set length for message (this includes any reports that were added above) */
401 pHTCHdr->PayloadLen = adf_os_htons(totsz);
402 HIF_send_buffer(pHTC->hifHandle, pHTC->Endpoints[EndpointID].DownLinkPipeID, pBuffers);
405 void _HTC_PauseRecv(HTC_ENDPOINT_ID EndpointID)
409 void _HTC_ResumeRecv(HTC_ENDPOINT_ID EndpointID)
413 int _HTC_GetReservedHeadroom(htc_handle_t htcHandle)
415 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
417 return HTC_HDR_LENGTH + HIF_get_reserved_headroom(pHTC->hifHandle);
420 void htc_module_install(struct htc_apis *pAPIs)
422 pAPIs->_HTC_Init = _HTC_Init;
423 pAPIs->_HTC_ReturnBuffers = _HTC_ReturnBuffers;
424 pAPIs->_HTC_ReturnBuffersList = _HTC_ReturnBuffersList;
425 pAPIs->_HTC_Ready = _HTC_Ready;
426 pAPIs->_HTC_RegisterService = _HTC_RegisterService;
427 pAPIs->_HTC_SendMsg = _HTC_SendMsg;
428 pAPIs->_HTC_Shutdown = _HTC_Shutdown;
429 pAPIs->_HTC_GetReservedHeadroom = _HTC_GetReservedHeadroom;
430 pAPIs->_HTC_MsgRecvHandler = HTCMsgRecvHandler;
431 pAPIs->_HTC_SendDoneHandler = HTCSendDoneHandler;
432 pAPIs->_HTC_ControlSvcProcessMsg = HTCControlSvcProcessMsg;
433 pAPIs->_HTC_ControlSvcProcessSendComplete = HTCControlSvcProcessSendComplete;
436 /* free message to the free list */
437 LOCAL void HTCFreeMsgBuffer(HTC_CONTEXT *pHTC, adf_nbuf_t buf)
439 BUF_Pool_free_buf(pHTC->PoolHandle, POOL_ID_HTC_CONTROL, buf);
442 /* HTC control message allocator (also used for empty frames to send trailer options) */
443 LOCAL adf_nbuf_t HTCAllocMsgBuffer(HTC_CONTEXT *pHTC)
445 return BUF_Pool_alloc_buf(pHTC->PoolHandle,
447 HTC_GetReservedHeadroom(pHTC));
450 LOCAL void HTCCheckAndSendCreditReport(HTC_CONTEXT *pHTC, A_UINT32 EpMask,
451 HTC_ENDPOINT *pEndpoint, HTC_ENDPOINT_ID Eid)
453 adf_nbuf_t pCredBuffer;
454 HTC_BUF_CONTEXT *ctx;
457 /* check if host needs credits */
458 if (!(pHTC->EpHostNeedsCreditMap & EpMask)) {
459 /* host does not need any credits for this set */
462 /* check if any are pending */
463 if (!(pHTC->EpCreditPendingMap & EpMask)) {
464 /* nothing to send up */
467 /* was an endpoint specified? */
468 if (pEndpoint != NULL) {
469 /* see if a threshold is in effect for this endpoint */
470 if (pEndpoint->CreditReturnThreshhold != 0) {
471 if (pEndpoint->CreditsToReturn < pEndpoint->CreditReturnThreshhold) {
472 /* this endpoint is using a threshold to prevent credits from dribbling
473 * back to the host */
478 if (pEndpoint->PendingCreditReports >= pHTC->MaxEpPendingCreditRpts) {
479 /* this endpoint already has some reports outstanding */
480 /* flag that as soon as a buffer is reaped, we issue a credit update to
481 * pick up this credit that is being held up because the endpoint has already
482 * exceeded the max outstanding credit report limit */
483 pHTC->StateFlags |= HTC_SEND_CREDIT_UPDATE_SOON;
488 /* if we get here we have some credits to send up */
490 /* allocate a message buffer for the trailer */
491 pCredBuffer = HTCAllocMsgBuffer(pHTC);
492 if (NULL == pCredBuffer) {
493 /* no buffers left to send an empty message with trailers, host will just
494 * have to wait until we get our endpoint 0 messages back.. */
495 /* mark that we need to send an update as soon as we can get a buffer back */
496 pHTC->StateFlags |= HTC_SEND_CREDIT_UPDATE_SOON;
500 ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(pCredBuffer);
501 if (pEndpoint != NULL) {
502 /* keep track of pending reports */
503 pEndpoint->PendingCreditReports++;
504 /* save the endpoint in order to decrement the count when the send completes */
505 ctx->htc_flags = Eid | HTC_FLAGS_CREDIT_RPT;
508 /* this is an empty message, the HTC_SendMsg will tack on a trailer in the remaining
509 * space, NOTE: no need to flush the cache, the header and trailers are assembled
510 * using uncached addresses */
511 HTC_SendMsg(pHTC, ENDPOINT0, pCredBuffer);
516 /* called in response to the arrival of a service connection message */
517 LOCAL void HTCProcessConnectMsg(HTC_CONTEXT *pHTC, HTC_CONNECT_SERVICE_MSG *pMsg)
519 HTC_SERVICE *pService = pHTC->pServiceList;
520 A_UINT8 connectStatus = HTC_SERVICE_NOT_FOUND;
522 HTC_CONNECT_SERVICE_RESPONSE_MSG *pRspMsg;
523 int metaDataOutLen = 0;
524 A_UINT16 serviceId = adf_os_ntohs(pMsg->ServiceID);
526 pBuffer = HTCAllocMsgBuffer(pHTC);
527 /* note : this will be aligned */
528 pRspMsg = (HTC_CONNECT_SERVICE_RESPONSE_MSG *)
529 adf_nbuf_put_tail(pBuffer, sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG));
531 A_MEMZERO(pRspMsg,sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG));
532 pRspMsg->MessageID = adf_os_htons(HTC_MSG_CONNECT_SERVICE_RESPONSE_ID);
533 /* reflect the service ID for this connect attempt */
534 pRspMsg->ServiceID = adf_os_htons(serviceId);
538 if (pHTC->CurrentEpIndex >= ENDPOINT_MAX) {
539 /* no more endpoints */
540 connectStatus = HTC_SERVICE_NO_RESOURCES;
544 if (serviceId == pService->ServiceID) {
545 /* we found a match */
546 A_UINT8 *pMetaDataIN = NULL;
547 A_UINT8 *pMetaDataOut;
549 /* outgoing meta data resides in the space after the response message */
550 pMetaDataOut = ((A_UINT8 *)pRspMsg) + sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG);
552 if (pMsg->ServiceMetaLength != 0) {
553 /* the meta data follows the connect service message */
554 pMetaDataIN = ((A_UINT8 *)pMsg) + sizeof(HTC_CONNECT_SERVICE_MSG);
557 /* call the connect callback with the endpoint to use and pointers to meta data */
558 connectStatus = pService->ProcessConnect(pService,
559 pHTC->CurrentEpIndex,
561 pMsg->ServiceMetaLength,
565 /* check if the service accepted this connection request */
566 if (HTC_SERVICE_SUCCESS == connectStatus) {
567 /* set the length of the response meta data going back to the host */
568 pRspMsg->ServiceMetaLength = (A_UINT8)metaDataOutLen;
569 /* set the endpoint ID the host will now communicate over */
570 pRspMsg->EndpointID = pHTC->CurrentEpIndex;
571 /* return the maximum message size for this service */
572 pRspMsg->MaxMsgSize = adf_os_htons((A_UINT16)pService->MaxSvcMsgSize);
573 /* assign this endpoint to this service, this will be used in routing messages */
574 pHTC->Endpoints[pHTC->CurrentEpIndex].pService = pService;
575 /* set connection flags */
576 pHTC->Endpoints[pHTC->CurrentEpIndex].ConnectionFlags = pMsg->ConnectionFlags;
578 pHTC->Endpoints[pHTC->CurrentEpIndex].DownLinkPipeID = pMsg->DownLinkPipeID;
579 pHTC->Endpoints[pHTC->CurrentEpIndex].UpLinkPipeID = pMsg->UpLinkPipeID;
581 /* mark that we are now connected */
582 pService->ServiceFlags |= HTC_SERVICE_FLAGS_CONNECTED;
583 /* bump up our index, this EP is now in use */
584 pHTC->CurrentEpIndex++;
590 pService = pService->pNext;
593 pRspMsg->Status = connectStatus;
595 /* send out the response message */
596 HTC_SendMsg(pHTC, ENDPOINT0, pBuffer);
599 LOCAL void HTCProcessConfigPipeMsg(HTC_CONTEXT *pHTC, HTC_CONFIG_PIPE_MSG *pMsg)
602 HTC_CONFIG_PIPE_RESPONSE_MSG *pRspMsg;
604 pBuffer = HTCAllocMsgBuffer(pHTC);
606 /* note : this will be aligned */
607 pRspMsg = (HTC_CONFIG_PIPE_RESPONSE_MSG *)
608 adf_nbuf_put_tail(pBuffer, sizeof(HTC_CONFIG_PIPE_RESPONSE_MSG));
610 A_MEMZERO(pRspMsg,sizeof(HTC_CONFIG_PIPE_RESPONSE_MSG));
612 pRspMsg->MessageID = adf_os_htons(HTC_MSG_CONFIG_PIPE_RESPONSE_ID);
613 /* reflect the service ID for this connect attempt */
614 pRspMsg->PipeID = pMsg->PipeID;
616 if ( HIF_is_pipe_supported(pHTC->hifHandle, pMsg->PipeID) ) {
623 if ( (pHTC->TotalCreditsAssigned + pMsg->CreditCount) <= pHTC->TotalCredits ) {
624 pHTC->TotalCreditsAssigned += pMsg->CreditCount;
630 HIF_config_pipe(pHTC->hifHandle, pMsg->PipeID, pMsg->CreditCount);
633 /* send out the response message */
634 HTC_SendMsg(pHTC, ENDPOINT0, pBuffer);
637 /* process an incomming control message from the host */
638 LOCAL void HTCControlSvcProcessMsg(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t hdr_buf,
639 adf_nbuf_t pBuffers, void *arg)
641 A_BOOL setupComplete = FALSE;
644 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)arg;
645 HTC_UNKNOWN_MSG *pMsg;
647 adf_os_assert(hdr_buf == ADF_NBUF_NULL);
649 /* we assume buffers are aligned such that we can access the message
650 * parameters directly*/
651 adf_nbuf_peek_header(pBuffers, &anbdata, &anblen);
652 pMsg = (HTC_UNKNOWN_MSG *)anbdata;
654 /* we cannot handle fragmented messages across buffers */
656 switch ( adf_os_ntohs(pMsg->MessageID) ) {
657 case HTC_MSG_CONNECT_SERVICE_ID:
658 HTCProcessConnectMsg(pHTC, (HTC_CONNECT_SERVICE_MSG *)pMsg);
660 case HTC_MSG_CONFIG_PIPE_ID:
661 HTCProcessConfigPipeMsg(pHTC, (HTC_CONFIG_PIPE_MSG *)pMsg);
663 case HTC_MSG_SETUP_COMPLETE_ID:
664 /* the host has indicated that it has completed all
665 setup tasks and we can now let the services take over to
666 run the rest of the application */
667 setupComplete = TRUE;
668 /* can't get this more than once */
674 if (pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE) {
675 /* recycle buffer only if we are fully running */
676 HTC_ReturnBuffers(pHTC, ENDPOINT0,pBuffers);
678 /* supply some head-room again */
679 adf_nbuf_push_head(pBuffers, HTC_HDR_LENGTH);
681 /* otherwise return the packet back to mbox */
682 HIF_return_recv_buf(pHTC->hifHandle, pHTC->Endpoints[EndpointID].UpLinkPipeID, pBuffers);
686 /* mark that setup has completed */
687 pHTC->StateFlags |= HTC_STATE_SETUP_COMPLETE;
688 if (pHTC->SetupCompleteCb != NULL) {
689 pHTC->SetupCompleteCb();
694 /* callback when endpoint 0 send buffers are completed */
695 LOCAL void HTCControlSvcProcessSendComplete(HTC_ENDPOINT_ID EndpointID,
696 adf_nbuf_t pBuffers, void *arg)
698 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)arg;
699 HTC_BUF_CONTEXT *ctx;
700 HTC_ENDPOINT_ID creditRptEndpoint;
702 ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(pBuffers);
704 /* put them back into the pool */
705 if ( ctx->htc_flags & HTC_FLAGS_CREDIT_RPT ) {
706 /* extract the endpoint number that requested this credit report */
707 creditRptEndpoint = ctx->htc_flags & HTC_FLAGS_CRPT_EP_MASK;
708 pHTC->Endpoints[creditRptEndpoint].PendingCreditReports--;
711 HTCFreeMsgBuffer(pHTC, pBuffers);
713 if (pHTC->StateFlags & HTC_SEND_CREDIT_UPDATE_SOON) {
714 /* this flag is set when the host could not send a credit report
715 * because we ran out of HTC control buffers */
716 pHTC->StateFlags &= ~HTC_SEND_CREDIT_UPDATE_SOON;
717 /* send out a report if anything is pending */
718 HTCCheckAndSendCreditReport(pHTC, HTC_ANY_ENDPOINT_MASK,NULL,ENDPOINT_MAX);
722 LOCAL void HTCSendDoneHandler(adf_nbuf_t buf, void *context)
725 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)context;
726 HTC_BUF_CONTEXT *ctx;
728 ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(buf);
729 current_eid = ctx->end_point;
731 /* Walk through the buffers and fixup the ones we used for HTC headers.
732 * The buffer list may contain more than one string of HTC buffers comprising of an
733 * HTC message so we need to check every buffer */
734 adf_nbuf_pull_head(buf, HTC_HDR_LENGTH);
736 pHTC->Endpoints[current_eid].pService->
737 ProcessSendBufferComplete(current_eid,
739 pHTC->Endpoints[current_eid].pService->ServiceCtx);
742 LOCAL void AdjustCreditThreshold(HTC_ENDPOINT *pEndpoint)
744 A_INT16 creditsOutstanding = pEndpoint->CreditsToReturn + pEndpoint->CreditsConsumed;
745 /* set the new threshold based on the number of credits that have been consumed
746 * and which have not been returned by the app.
747 * Note: it is okay for this threshold to be zero which indicates no threshold
749 switch (pEndpoint->ConnectionFlags & HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_MASK) {
750 case HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_FOURTH :
751 creditsOutstanding >>= 2;
753 case HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_HALF :
754 creditsOutstanding >>= 1;
756 case HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_THREE_FOURTHS :
757 creditsOutstanding = (creditsOutstanding * 3) >> 2;
759 /* default case is unity */
762 pEndpoint->CreditReturnThreshhold = creditsOutstanding;
766 LOCAL void RedistributeCredit(adf_nbuf_t buf, int toPipeId)
771 /* callback from the mailbox hardware layer when a full message arrives */
772 LOCAL void HTCMsgRecvHandler(adf_nbuf_t hdr_buf, adf_nbuf_t buffer, void *context)
775 HTC_ENDPOINT *pEndpoint;
780 HTC_FRAME_HDR *pHTCHdr;
781 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)context;
784 if (hdr_buf == ADF_NBUF_NULL) {
785 /* HTC hdr is not in the hdr_buf */
792 adf_nbuf_peek_header(tmp_nbuf, &anbdata, &anblen);
793 pHTCHdr = (HTC_FRAME_HDR *)anbdata;
795 totsz = adf_os_ntohs(pHTCHdr->PayloadLen);
797 eid = pHTCHdr->EndpointID;
799 pEndpoint = &pHTC->Endpoints[eid];
802 if (pHTCHdr->Flags & HTC_FLAGS_CREDIT_REDISTRIBUTION) {
803 /* The pipe id where the credit is redistributed to is carried in Control
805 RedistributeCredit(tmp_nbuf, pHTCHdr->ControlBytes[0]);
809 if (pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE) {
810 /* after setup we keep track of credit consumption to allow us to
811 * adjust thresholds to reduce credit dribbling */
812 pEndpoint->CreditsConsumed ++;
815 /* from the design document, we put the endpoint into a "host-needs-credit" state
816 * when we receive a frame with the NEED_CREDIT_UPDATE flag set .
817 * if the host received credits through an opportunistic path, then it can
818 * issue a another frame with this bit cleared, this signals the target to clear
819 * the "host-needs-credit" state */
820 if (pHTCHdr->Flags & HTC_FLAGS_NEED_CREDIT_UPDATE) {
821 /* the host is running low (or is out) of credits on this
822 * endpoint, update mask */
823 pHTC->EpHostNeedsCreditMap |= eidMask;
824 /* check and set new threshold since host has reached a low credit situation */
825 CHECK_AND_ADJUST_CREDIT_THRESHOLD(pEndpoint);
828 pHTC->EpHostNeedsCreditMap &= ~(eidMask);
829 pEndpoint->CreditReturnThreshhold = 0;
832 /* Adjust the first buffer to point to the start of the actual
833 payload, the first buffer contains the header */
834 adf_nbuf_pull_head(tmp_nbuf, HTC_HDR_LENGTH);
836 /* NOTE : This callback could re-queue the recv buffers within this calling context.
837 * The callback could also send a response message within the context of this callback
838 * as the result of parsing this message. In either case, if there are
839 * pending credits and the host needs them, a credit report will be sent either through
840 * the response message trailer or a NULL message through HTC_ReturnBuffers().
843 pEndpoint->pService->ProcessRecvMsg(eid, hdr_buf, buffer, pEndpoint->pService->ServiceCtx);
845 /* Calls to HTC_ReturnBuffers drives the endpoint credit reporting state machine.
846 * We do not want to delay credits for too long in the event that the application is
847 * holding onto buffers for excessive periods of time. This gives us "some" better
848 * opportunities to send up credits. */
849 HTCCheckAndSendCreditReport(pHTC, eidMask, pEndpoint, eid);