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"
53 #define A_UNCACHED_ADDR(addr) addr
54 //#define A_MEMZERO(v, size)
56 /*** statics vars ****/
57 //HTC_CONTEXT g_htcCtx;
58 //HTC_CONTEXT *g_pHTC = NULL;
61 LOCAL void HTCControlSvcProcessMsg(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t hdr_buf, adf_nbuf_t pBuffers, void *arg);
62 LOCAL void HTCControlSvcProcessSendComplete(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers, void *arg);
63 LOCAL void HTCMsgRecvHandler(adf_nbuf_t hdr_buf, adf_nbuf_t buf, void *context);
64 LOCAL void HTCSendDoneHandler(adf_nbuf_t buf, void *context);
65 LOCAL void HTCFreeMsgBuffer(HTC_CONTEXT *pHTC, adf_nbuf_t pBuffer);
66 LOCAL adf_nbuf_t HTCAllocMsgBuffer(HTC_CONTEXT *pHTC);
67 //LOCAL void HTC_EnqueuePausedRecv(HTC_ENDPOINT *pEndpoint,
70 //LOCAL VBUF* HTC_DequeuePausedRecv(HTC_ENDPOINT *pEndpoint);
71 LOCAL void HTCCheckAndSendCreditReport(HTC_CONTEXT *pHTC, A_UINT32 EpMask, HTC_ENDPOINT *pEndpoint, HTC_ENDPOINT_ID Id);
72 LOCAL void AdjustCreditThreshold(HTC_ENDPOINT *pEndpoint);
73 //LOCAL void _HTC_AddBufferResources(int buffers);
74 LOCAL void HTC_AssembleBuffers(HTC_CONTEXT *pHTC, int Count, int Size);
75 LOCAL htc_handle_t _HTC_Init(/*A_UINT32 dataAddr,*/
76 HTC_SETUP_COMPLETE_CB SetupComplete,
78 LOCAL void _HTC_RegisterService(htc_handle_t handle, HTC_SERVICE *pService);
79 LOCAL void _HTC_Ready(htc_handle_t handle);
80 LOCAL void ReturnBuffers(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers, A_BOOL sendCreditFlag);
81 LOCAL void _HTC_ReturnBuffers(htc_handle_t handle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers);
82 LOCAL void _HTC_ReturnBuffersList(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_queue_t bufHead);
83 LOCAL void _HTC_SendMsg(htc_handle_t handle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers);
84 void _HTC_PauseRecv(HTC_ENDPOINT_ID EndpointID);
85 void _HTC_ResumeRecv(HTC_ENDPOINT_ID EndpointID);
86 LOCAL void HTCProcessConnectMsg(HTC_CONTEXT *pHTC, HTC_CONNECT_SERVICE_MSG *pMsg);
87 LOCAL void HTCProcessConfigPipeMsg(HTC_CONTEXT *pHTC, HTC_CONFIG_PIPE_MSG *pMsg);
88 LOCAL void RedistributeCredit(adf_nbuf_t buf, int toPipeId);
89 LOCAL void _HTC_Shutdown(htc_handle_t htcHandle);
91 /* macro to check if the service wants to prevent credit dribbling by using
92 a dynamic threshold */
93 #define CHECK_AND_ADJUST_CREDIT_THRESHOLD(pEndpoint) \
94 if ((pEndpoint)->ConnectionFlags & HTC_CONNECT_FLAGS_REDUCE_CREDIT_DRIBBLE) { \
95 AdjustCreditThreshold((pEndpoint)); \
98 /***********************************************************************************************/
99 /************************ MODULE API implementation *******************************************/
101 LOCAL void _HTC_AddBufferResources(int buffers)
104 //MboxHW_AddDMAResources(buffers);
108 LOCAL void HTC_AssembleBuffers(HTC_CONTEXT *pHTC, int Count, int Size)
110 BUF_Pool_create_pool(pHTC->PoolHandle, POOL_ID_HTC_CONTROL, Count, Size);
114 LOCAL htc_handle_t _HTC_Init(HTC_SETUP_COMPLETE_CB SetupComplete,
117 HIF_CALLBACK hifCBConfig;
120 //if (NULL == g_pHTC)
122 pHTC = (HTC_CONTEXT *)adf_os_mem_alloc(sizeof(HTC_CONTEXT));
123 //g_pHTC = &g_htcCtx;
126 adf_os_mem_zero(pHTC, sizeof(HTC_CONTEXT));
128 pHTC->OSHandle = pConfig->OSHandle;
129 pHTC->PoolHandle = pConfig->PoolHandle;
130 pHTC->hifHandle = pConfig->HIFHandle;
132 //A_MEMZERO(&hwConfig,sizeof(hwConfig));
133 hifCBConfig.send_buf_done = A_INDIR(htc._HTC_SendDoneHandler);
134 hifCBConfig.recv_buf = A_INDIR(htc._HTC_MsgRecvHandler);
135 hifCBConfig.context = pHTC;
137 /* initialize hardware layer */
138 HIF_register_callback(pConfig->HIFHandle, &hifCBConfig);
140 /* see if the host wants us to override the number of ctrl buffers */
141 //g_pHTC->NumBuffersForCreditRpts = (HOST_INTEREST->hi_mbox_io_block_sz >> 16) & 0xF;
142 pHTC->NumBuffersForCreditRpts = 0;
144 if (0 == pHTC->NumBuffersForCreditRpts) {
145 /* nothing to override, simply set default */
146 pHTC->NumBuffersForCreditRpts = HTC_DEFAULT_NUM_CTRL_BUFFERS;
149 //g_pHTC->MaxEpPendingCreditRpts = (HOST_INTEREST->hi_mbox_io_block_sz >> 20) & 0xF;
150 pHTC->MaxEpPendingCreditRpts = 0;
152 if (0 == pHTC->MaxEpPendingCreditRpts) {
153 pHTC->MaxEpPendingCreditRpts = HTC_DEFAULT_MAX_EP_PENDING_CREDIT_REPORTS;
155 /* calculate the total allocation size based on the number of credit report buffers */
156 pHTC->CtrlBufferAllocSize = MIN_CREDIT_BUFFER_ALLOC_SIZE * pHTC->NumBuffersForCreditRpts;
157 /* we need at least enough buffer space for 1 ctrl message */
158 pHTC->CtrlBufferAllocSize = A_MAX(pHTC->CtrlBufferAllocSize,MAX_HTC_SETUP_MSG_SIZE);
160 //A_PRINTF("%d, %d, (%d, %d) %s-%s \n",g_pHTC->NumBuffersForCreditRpts,g_pHTC->CtrlBufferAllocSize,
161 // MIN_BUF_SIZE_FOR_RPTS, MIN_CREDIT_BUFFER_ALLOC_SIZE,__DATE__, __TIME__);
163 /* save the size of each buffer/credit we will receive */
164 pHTC->RecvBufferSize = pConfig->CreditSize; //RecvBufferSize;
165 pHTC->TotalCredits = pConfig->CreditNumber;
166 //g_pHTC->FreeCreditList = pConfig->CreditList;
167 pHTC->TotalCreditsAssigned = 0;
169 /* setup the pseudo service that handles HTC control messages */
170 pHTC->HTCControlService.ProcessRecvMsg = A_INDIR(htc._HTC_ControlSvcProcessMsg);
171 pHTC->HTCControlService.ProcessSendBufferComplete = A_INDIR(htc._HTC_ControlSvcProcessSendComplete);
172 pHTC->HTCControlService.TrailerSpcCheckLimit = HTC_CTRL_BUFFER_CHECK_SIZE;
173 pHTC->HTCControlService.MaxSvcMsgSize = MAX_HTC_SETUP_MSG_SIZE;
174 pHTC->HTCControlService.ServiceCtx = pHTC;
176 /* automatically register this pseudo service to endpoint 1 */
177 pHTC->Endpoints[ENDPOINT0].pService = &pHTC->HTCControlService;
178 HIF_get_default_pipe(pHTC->hifHandle, &pHTC->Endpoints[ENDPOINT0].UpLinkPipeID,
179 &pHTC->Endpoints[ENDPOINT0].DownLinkPipeID);
181 /* Initialize control pipe so we could receive the HTC control packets */
183 HIF_config_pipe(pHTC->hifHandle, pHTC->Endpoints[ENDPOINT0].UpLinkPipeID, 1);
185 /* set the first free endpoint */
186 pHTC->CurrentEpIndex = ENDPOINT1;
187 pHTC->SetupCompleteCb = SetupComplete;
189 /* setup buffers for just the setup phase, we only need 1 buffer to handle
191 HTC_AssembleBuffers(pHTC, 4, MAX_HTC_SETUP_MSG_SIZE);
193 /* start hardware layer so that we can queue buffers */
194 HIF_start(pHTC->hifHandle);
199 LOCAL void _HTC_Shutdown(htc_handle_t htcHandle)
201 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
203 adf_os_mem_free(pHTC);
206 LOCAL void _HTC_RegisterService(htc_handle_t htcHandle, HTC_SERVICE *pService)
208 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
210 /* add it to the list */
211 pService->pNext = pHTC->pServiceList;
212 pHTC->pServiceList = pService;
215 LOCAL void _HTC_Ready(htc_handle_t htcHandle)
218 HTC_READY_MSG *pReady;
220 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
222 pBuffer = HTCAllocMsgBuffer(pHTC);
223 //A_ASSERT(pBuffer != NULL);
225 /* an optimization... the header length is chosen to
226 * be aligned on a 16 bit bounday, the fields in the message are designed to
228 addr = adf_nbuf_put_tail(pBuffer, sizeof(HTC_READY_MSG));
229 pReady = (HTC_READY_MSG *)addr;
230 A_MEMZERO(pReady,sizeof(HTC_READY_MSG));
231 pReady->MessageID = adf_os_htons(HTC_MSG_READY_ID);
232 pReady->CreditSize = adf_os_htons((A_UINT16)pHTC->RecvBufferSize);
233 //A_ASSERT(g_pHTC->TotalCredits <= MAX_HTC_CREDITS);
234 pReady->CreditCount = adf_os_htons((A_UINT16)pHTC->TotalCredits);
235 pReady->MaxEndpoints = ENDPOINT_MAX;
237 /* send out the message */
238 //A_DATA_CACHE_FLUSH(pBuffer->buffer, pBuffer->actual_length);
239 HTC_SendMsg(pHTC, ENDPOINT0, pBuffer);
240 /* now we need to wait for service connection requests */
243 LOCAL void ReturnBuffers(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers, A_BOOL sendCreditFlag)
246 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
248 //A_ASSERT(EndpointID < ENDPOINT_MAX);
250 /* supply some head-room again */
251 adf_nbuf_push_head(pBuffers, HTC_HDR_LENGTH);
252 //A_DATA_CACHE_INVAL(pBuffers->buffer, pBuffers->actual_length + HTC_HDR_SZ);
254 /* enqueue all buffers to the single mailbox */
255 HIF_return_recv_buf(pHTC->hifHandle, pHTC->Endpoints[EndpointID].UpLinkPipeID, pBuffers);
256 //A_ASSERT(nbufs != 0);
258 if (pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE) {
259 A_UINT32 epCreditMask = (1 << EndpointID);
260 /* we are running normally */
261 /* update pending credit counts with the number of buffers that were added */
262 pHTC->Endpoints[EndpointID].CreditsToReturn += (A_INT16)nbufs;
263 pHTC->Endpoints[EndpointID].CreditsConsumed -= (A_INT16)nbufs;
264 //A_ASSERT(g_pHTC->Endpoints[EndpointID].CreditsConsumed >= 0);
265 /* update bit map that this endpoint has non-zero credits */
266 pHTC->EpCreditPendingMap |= epCreditMask;
268 if (sendCreditFlag) {
269 HTCCheckAndSendCreditReport(pHTC, epCreditMask,&pHTC->Endpoints[EndpointID],EndpointID);
273 /* we have not started yet so all return operations are simply adding buffers
274 * to the interface at startup, so we can keep track of how many total
276 /* update global count that will be returned to the host */
277 pHTC->TotalCredits += nbufs;
281 LOCAL void _HTC_ReturnBuffersList(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_queue_t bufHead)
283 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
284 adf_nbuf_t netbuf, tmpNbuf;
286 /* retrieve each nbuf in the queue */
287 netbuf = adf_nbuf_queue_first(&bufHead);
292 netbuf = adf_nbuf_queue_next(netbuf);
294 ReturnBuffers(htcHandle, EndpointID, tmpNbuf, FALSE);
297 HTCCheckAndSendCreditReport(pHTC, (1 << EndpointID),&pHTC->Endpoints[EndpointID],EndpointID);
300 LOCAL void _HTC_ReturnBuffers(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers)
302 ReturnBuffers(htcHandle, EndpointID, pBuffers, TRUE);
305 LOCAL void _HTC_SendMsg(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers)
307 HTC_FRAME_HDR *pHTCHdr;
309 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
310 HTC_BUF_CONTEXT *ctx;
312 ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(pBuffers);
314 /* init total size (this does not include the space we will put in for the HTC header) */
315 totsz = adf_nbuf_len(pBuffers);
317 /* the first buffer stores the header */
318 /* back up buffer by a header size when we pass it down, by agreed upon convention the caller
319 * points the buffer to it's payload and leaves head room for the HTC header
320 * Note: in HTCSendDoneHandler(), we undo this so that the caller get's it's buffer
322 pHTCHdr = (HTC_FRAME_HDR *)adf_nbuf_push_head(pBuffers, HTC_HDR_LENGTH);
324 /* flag that this is the header buffer that was modified */
325 ctx->htc_flags |= HTC_FLAGS_BUF_HDR;
326 /* mark where this buffer came from */
327 ctx->end_point = EndpointID;
328 /* the header start is ALWAYS aligned since we DMA it directly */
329 //pHTCHdr = (HTC_FRAME_HDR *)A_UNCACHED_ADDR(VBUF_GET_DATA_ADDR(pBuffers));
330 /* set some fields, the rest of them will be filled below when we check for
333 pHTCHdr->EndpointID = EndpointID;
335 //A_ASSERT(totsz <= g_pHTC->Endpoints[EndpointID].pService->MaxSvcMsgSize);
336 /* check opportunistically if we can return any reports via a trailer */
338 int room,i,totalReportBytes;
339 A_UINT32 creditsPendingMap, compareMask;
340 HTC_CREDIT_REPORT *pCreditRpt;
341 HTC_RECORD_HDR *pRecHdr;
343 A_UINT32 roomForPipeMaxLen;
345 /* figure out how much room the last buffer can spare */
346 pipeMaxLen = HIF_get_max_msg_len(pHTC->hifHandle, pHTC->Endpoints[EndpointID].DownLinkPipeID);
347 roomForPipeMaxLen = pipeMaxLen - adf_nbuf_headroom(pBuffers) - adf_nbuf_len(pBuffers);
348 if ( roomForPipeMaxLen < 0 ) {
349 roomForPipeMaxLen = 0;
352 room = adf_os_min( adf_nbuf_tailroom(pBuffers), roomForPipeMaxLen);
353 if (room < (int)(sizeof(HTC_CREDIT_REPORT) + sizeof(HTC_RECORD_HDR))) {
354 /* no room for any reports */
357 /* note, a record header only has 8 bit fields, so this is safe.
358 * we need an uncached pointer here too */
359 totalReportBytes = 0;
362 creditsPendingMap = pHTC->EpCreditPendingMap;
364 /* test pending map to see if we can send a report , if any
365 * credits are available, we might as well send them on the
366 * unused space in the buffer */
367 if (creditsPendingMap) {
369 pRecHdr = (HTC_RECORD_HDR *)adf_nbuf_put_tail(pBuffers, sizeof(HTC_RECORD_HDR));
371 /* set the ID, the length will be updated with the number of credit reports we
372 * can fit (see below) */
373 pRecHdr->RecordID = HTC_RECORD_CREDITS;
375 /* the credit report follows the record header */
376 totalReportBytes += sizeof(HTC_RECORD_HDR);
377 room -= sizeof(HTC_RECORD_HDR);
379 /* walkthrough pending credits map and build the records */
381 (creditsPendingMap != 0) && (room >= (int)sizeof(HTC_CREDIT_REPORT));
383 compareMask = (1 << i);
384 if (compareMask & creditsPendingMap) {
386 pCreditRpt = (HTC_CREDIT_REPORT *)adf_nbuf_put_tail(pBuffers, sizeof(HTC_CREDIT_REPORT));
388 /* clear pending mask, we are going to return all these credits */
389 creditsPendingMap &= ~(compareMask);
390 /* add this record */
391 pCreditRpt->EndpointID = i;
392 pCreditRpt->Credits = (A_UINT8)pHTC->Endpoints[i].CreditsToReturn;
393 /* remove pending credits, we always send deltas */
394 pHTC->Endpoints[i].CreditsToReturn = 0;
395 /* adjust new threshold for this endpoint if needed */
396 CHECK_AND_ADJUST_CREDIT_THRESHOLD(&pHTC->Endpoints[i]);
397 /* update this record length */
398 pRecHdr->Length += sizeof(HTC_CREDIT_REPORT);
399 room -= sizeof(HTC_CREDIT_REPORT);
400 totalReportBytes += sizeof(HTC_CREDIT_REPORT);
402 if ( room < sizeof(HTC_CREDIT_REPORT) ) {
408 /* update new pending credits map */
409 pHTC->EpCreditPendingMap = creditsPendingMap;
412 if (totalReportBytes <= 0) {
416 /* must fit into a byte, this should never actually happen since
417 * the maximum possible number of endpoints is 32.
418 * The trailer can have at most 1 credit record with up to 32 reports in the record.
419 * The trailer can have at most 1 lookahead record with only 1 lookahead report in the record.
422 //A_ASSERT(totalReportBytes <= 255);
424 /* set header option bytes */
425 pHTCHdr->ControlBytes[0] = totalReportBytes;
426 /* HTC frame contains a trailer */
427 pHTCHdr->Flags |= HTC_FLAGS_RECV_TRAILER;
428 /* increment total size by the reports we added */
429 totsz += totalReportBytes;
430 /* adjust the last buffer we used for adding on the trailer */
437 /* set length for message (this includes any reports that were added above) */
438 pHTCHdr->PayloadLen = adf_os_htons(totsz);
439 HIF_send_buffer(pHTC->hifHandle, pHTC->Endpoints[EndpointID].DownLinkPipeID, pBuffers);
442 void _HTC_PauseRecv(HTC_ENDPOINT_ID EndpointID)
444 #if 0 // Disable first. Ray
445 #ifdef HTC_PAUSE_RESUME_REF_COUNTING
446 g_pHTC->Endpoints[EndpointID].PauseRefCount++;
448 /* we are now paused */
449 g_pHTC->EpRecvPausedMap |= (1 << EndpointID);
453 void _HTC_ResumeRecv(HTC_ENDPOINT_ID EndpointID)
455 #if 0 // Disable first. Ray
457 HTC_ENDPOINT *pEndpoint;
459 pEndpoint = &g_pHTC->Endpoints[EndpointID];
461 /* TODO: we can't quite use referencing counting yet until we clean up the WLAN
462 * app, there are some un-matched pause/resume cases that need to be fixed */
463 #ifdef HTC_PAUSE_RESUME_REF_COUNTING
464 pEndpoint->PauseRefCount--;
465 //A_ASSERT(pEndpoint->PauseRefCount >= 0);
467 /* check reference count and unpause if it is zero */
468 if (pEndpoint->PauseRefCount > 0) {
473 g_pHTC->EpRecvPausedMap &= ~(1 << EndpointID);
474 /* unload the paused receive queue */
475 while ((buffer = HTC_DequeuePausedRecv(pEndpoint)) != NULL) {
476 /* note that the paused messages have already been processed at the HTC layer,
477 * we can simply indicate the buffers to the service */
478 pEndpoint->pService->ProcessRecvMsg(EndpointID,buffer);
483 int _HTC_GetReservedHeadroom(htc_handle_t htcHandle)
485 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
487 return HTC_HDR_LENGTH + HIF_get_reserved_headroom(pHTC->hifHandle);
490 void htc_module_install(struct htc_apis *pAPIs)
492 pAPIs->_HTC_Init = _HTC_Init;
493 pAPIs->_HTC_ReturnBuffers = _HTC_ReturnBuffers;
494 pAPIs->_HTC_ReturnBuffersList = _HTC_ReturnBuffersList;
495 pAPIs->_HTC_Ready = _HTC_Ready;
496 pAPIs->_HTC_RegisterService = _HTC_RegisterService;
497 pAPIs->_HTC_SendMsg = _HTC_SendMsg;
498 pAPIs->_HTC_Shutdown = _HTC_Shutdown;
499 pAPIs->_HTC_GetReservedHeadroom = _HTC_GetReservedHeadroom;
500 pAPIs->_HTC_MsgRecvHandler = HTCMsgRecvHandler;
501 pAPIs->_HTC_SendDoneHandler = HTCSendDoneHandler;
502 pAPIs->_HTC_ControlSvcProcessMsg = HTCControlSvcProcessMsg;
503 pAPIs->_HTC_ControlSvcProcessSendComplete = HTCControlSvcProcessSendComplete;
505 //pAPIs->_HTC_PauseRecv = _HTC_PauseRecv;
506 //pAPIs->_HTC_ResumeRecv = _HTC_ResumeRecv;
507 //pAPIs->_HTC_AddBufferResources = _HTC_AddBufferResources;
508 /* save ptr to the ptr to the context for external code to inspect/modify internal module state */
509 //pAPIs->pReserved = &g_pHTC;
512 /*******************************************************************************************/
513 /**************** INTERNAL ROUTINES to this MODULE ***************************************/
515 /* free message to the free list */
516 //LOCAL void HTCFreeMsgBuffer(HTC_BUFFER *pBuffer)
517 LOCAL void HTCFreeMsgBuffer(HTC_CONTEXT *pHTC, adf_nbuf_t buf)
519 BUF_Pool_free_buf(pHTC->PoolHandle, POOL_ID_HTC_CONTROL, buf);
522 /* HTC control message allocator (also used for empty frames to send trailer options) */
523 //LOCAL HTC_BUFFER *HTCAllocMsgBuffer(void)
524 LOCAL adf_nbuf_t HTCAllocMsgBuffer(HTC_CONTEXT *pHTC)
526 return BUF_Pool_alloc_buf(pHTC->PoolHandle, POOL_ID_HTC_CONTROL, HTC_GetReservedHeadroom(pHTC));
529 LOCAL void HTCCheckAndSendCreditReport(HTC_CONTEXT *pHTC, A_UINT32 EpMask, HTC_ENDPOINT *pEndpoint, HTC_ENDPOINT_ID Eid)
531 adf_nbuf_t pCredBuffer;
532 HTC_BUF_CONTEXT *ctx;
535 /* check if host needs credits */
536 if (!(pHTC->EpHostNeedsCreditMap & EpMask)) {
537 /* host does not need any credits for this set */
540 /* check if any are pending */
541 if (!(pHTC->EpCreditPendingMap & EpMask)) {
542 /* nothing to send up */
545 /* was an endpoint specified? */
546 if (pEndpoint != NULL) {
547 /* see if a threshold is in effect for this endpoint */
548 if (pEndpoint->CreditReturnThreshhold != 0) {
549 if (pEndpoint->CreditsToReturn < pEndpoint->CreditReturnThreshhold) {
550 /* this endpoint is using a threshold to prevent credits from dribbling
551 * back to the host */
556 if (pEndpoint->PendingCreditReports >= pHTC->MaxEpPendingCreditRpts) {
557 /* this endpoint already has some reports outstanding */
558 /* flag that as soon as a buffer is reaped, we issue a credit update to
559 * pick up this credit that is being held up because the endpoint has already
560 * exceeded the max outstanding credit report limit */
561 pHTC->StateFlags |= HTC_SEND_CREDIT_UPDATE_SOON;
566 /* if we get here we have some credits to send up */
568 /* allocate a message buffer for the trailer */
569 pCredBuffer = HTCAllocMsgBuffer(pHTC);
570 if (NULL == pCredBuffer) {
571 /* no buffers left to send an empty message with trailers, host will just
572 * have to wait until we get our endpoint 0 messages back.. */
573 /* mark that we need to send an update as soon as we can get a buffer back */
574 pHTC->StateFlags |= HTC_SEND_CREDIT_UPDATE_SOON;
578 ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(pCredBuffer);
579 if (pEndpoint != NULL) {
580 /* keep track of pending reports */
581 pEndpoint->PendingCreditReports++;
582 /* save the endpoint in order to decrement the count when the send completes */
583 ctx->htc_flags = Eid | HTC_FLAGS_CREDIT_RPT;
586 /* this is an empty message, the HTC_SendMsg will tack on a trailer in the remaining
587 * space, NOTE: no need to flush the cache, the header and trailers are assembled
588 * using uncached addresses */
589 HTC_SendMsg(pHTC, ENDPOINT0, pCredBuffer);
594 /* called in response to the arrival of a service connection message */
595 LOCAL void HTCProcessConnectMsg(HTC_CONTEXT *pHTC, HTC_CONNECT_SERVICE_MSG *pMsg)
597 HTC_SERVICE *pService = pHTC->pServiceList;
598 A_UINT8 connectStatus = HTC_SERVICE_NOT_FOUND;
599 //HTC_BUFFER *pBuffer;
601 HTC_CONNECT_SERVICE_RESPONSE_MSG *pRspMsg;
602 int metaDataOutLen = 0;
603 A_UINT16 serviceId = adf_os_ntohs(pMsg->ServiceID);
605 pBuffer = HTCAllocMsgBuffer(pHTC);
606 //A_ASSERT(pBuffer != NULL);
607 /* note : this will be aligned */
608 pRspMsg = (HTC_CONNECT_SERVICE_RESPONSE_MSG *)
609 adf_nbuf_put_tail(pBuffer, sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG));
611 A_MEMZERO(pRspMsg,sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG));
612 pRspMsg->MessageID = adf_os_htons(HTC_MSG_CONNECT_SERVICE_RESPONSE_ID);
613 /* reflect the service ID for this connect attempt */
614 pRspMsg->ServiceID = adf_os_htons(serviceId);
618 if (pHTC->CurrentEpIndex >= ENDPOINT_MAX) {
619 /* no more endpoints */
620 connectStatus = HTC_SERVICE_NO_RESOURCES;
624 if (serviceId == pService->ServiceID) {
625 /* we found a match */
626 A_UINT8 *pMetaDataIN = NULL;
627 A_UINT8 *pMetaDataOut;
629 /* outgoing meta data resides in the space after the response message */
630 pMetaDataOut = ((A_UINT8 *)pRspMsg) + sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG);
632 if (pMsg->ServiceMetaLength != 0) {
633 //A_ASSERT(pMsg->ServiceMetaLength <= HTC_SERVICE_META_DATA_MAX_LENGTH);
634 /* the meta data follows the connect service message */
635 pMetaDataIN = ((A_UINT8 *)pMsg) + sizeof(HTC_CONNECT_SERVICE_MSG);
638 //A_ASSERT(pService->ProcessConnect != NULL);
639 /* call the connect callback with the endpoint to use and pointers to meta data */
640 connectStatus = pService->ProcessConnect(pService,
641 pHTC->CurrentEpIndex,
643 pMsg->ServiceMetaLength,
647 /* check if the service accepted this connection request */
648 if (HTC_SERVICE_SUCCESS == connectStatus) {
649 //A_ASSERT(metaDataOutLen <= HTC_SERVICE_META_DATA_MAX_LENGTH);
650 /* set the length of the response meta data going back to the host */
651 pRspMsg->ServiceMetaLength = (A_UINT8)metaDataOutLen;
652 /* set the endpoint ID the host will now communicate over */
653 pRspMsg->EndpointID = pHTC->CurrentEpIndex;
654 /* return the maximum message size for this service */
655 pRspMsg->MaxMsgSize = adf_os_htons((A_UINT16)pService->MaxSvcMsgSize);
656 /* assign this endpoint to this service, this will be used in routing messages */
657 pHTC->Endpoints[pHTC->CurrentEpIndex].pService = pService;
658 /* set connection flags */
659 pHTC->Endpoints[pHTC->CurrentEpIndex].ConnectionFlags = pMsg->ConnectionFlags;
661 pHTC->Endpoints[pHTC->CurrentEpIndex].DownLinkPipeID = pMsg->DownLinkPipeID;
662 pHTC->Endpoints[pHTC->CurrentEpIndex].UpLinkPipeID = pMsg->UpLinkPipeID;
664 /* mark that we are now connected */
665 pService->ServiceFlags |= HTC_SERVICE_FLAGS_CONNECTED;
666 /* bump up our index, this EP is now in use */
667 pHTC->CurrentEpIndex++;
673 pService = pService->pNext;
676 pRspMsg->Status = connectStatus;
678 /* send out the response message */
679 //A_DATA_CACHE_FLUSH(pBuffer->buffer, pBuffer->actual_length);
680 HTC_SendMsg(pHTC, ENDPOINT0, pBuffer);
683 LOCAL void HTCProcessConfigPipeMsg(HTC_CONTEXT *pHTC, HTC_CONFIG_PIPE_MSG *pMsg)
685 //HTC_SERVICE *pService = g_pHTC->pServiceList;
686 //A_UINT8 connectStatus = HTC_SERVICE_NOT_FOUND;
688 HTC_CONFIG_PIPE_RESPONSE_MSG *pRspMsg;
690 pBuffer = HTCAllocMsgBuffer(pHTC);
692 //A_ASSERT(pBuffer != NULL);
693 /* note : this will be aligned */
694 pRspMsg = (HTC_CONFIG_PIPE_RESPONSE_MSG *)
695 adf_nbuf_put_tail(pBuffer, sizeof(HTC_CONFIG_PIPE_RESPONSE_MSG));
697 A_MEMZERO(pRspMsg,sizeof(HTC_CONFIG_PIPE_RESPONSE_MSG));
699 pRspMsg->MessageID = adf_os_htons(HTC_MSG_CONFIG_PIPE_RESPONSE_ID);
700 /* reflect the service ID for this connect attempt */
701 pRspMsg->PipeID = pMsg->PipeID;
703 if ( HIF_is_pipe_supported(pHTC->hifHandle, pMsg->PipeID) ) {
710 if ( (pHTC->TotalCreditsAssigned + pMsg->CreditCount) <= pHTC->TotalCredits ) {
711 pHTC->TotalCreditsAssigned += pMsg->CreditCount;
717 HIF_config_pipe(pHTC->hifHandle, pMsg->PipeID, pMsg->CreditCount);
720 /* send out the response message */
721 //A_DATA_CACHE_FLUSH(pBuffer->buffer, pBuffer->actual_length);
722 HTC_SendMsg(pHTC, ENDPOINT0, pBuffer);
725 /* process an incomming control message from the host */
726 LOCAL void HTCControlSvcProcessMsg(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t hdr_buf, adf_nbuf_t pBuffers, void *arg)
728 A_BOOL setupComplete = FALSE;
731 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)arg;
732 HTC_UNKNOWN_MSG *pMsg;
734 adf_os_assert(hdr_buf == ADF_NBUF_NULL);
736 /* we assume buffers are aligned such that we can access the message
737 * parameters directly*/
738 adf_nbuf_peek_header(pBuffers, &anbdata, &anblen);
739 pMsg = (HTC_UNKNOWN_MSG *)anbdata;
741 /* we cannot handle fragmented messages across buffers */
742 //A_ASSERT(pBuffers->next == NULL);
744 switch ( adf_os_ntohs(pMsg->MessageID) ) {
745 case HTC_MSG_CONNECT_SERVICE_ID:
746 //A_ASSERT(pBuffers->actual_length >= sizeof(HTC_CONNECT_SERVICE_MSG));
747 HTCProcessConnectMsg(pHTC, (HTC_CONNECT_SERVICE_MSG *)pMsg);
749 case HTC_MSG_CONFIG_PIPE_ID:
750 HTCProcessConfigPipeMsg(pHTC, (HTC_CONFIG_PIPE_MSG *)pMsg);
752 case HTC_MSG_SETUP_COMPLETE_ID:
753 /* the host has indicated that it has completed all
754 setup tasks and we can now let the services take over to
755 run the rest of the application */
756 setupComplete = TRUE;
757 /* can't get this more than once */
758 //A_ASSERT(!(g_pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE));
765 if (pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE) {
766 /* recycle buffer only if we are fully running */
767 HTC_ReturnBuffers(pHTC, ENDPOINT0,pBuffers);
769 /* supply some head-room again */
770 //A_DATA_CACHE_INVAL(pBuffers->buffer, pBuffers->actual_length + HTC_HDR_SZ);
771 adf_nbuf_push_head(pBuffers, HTC_HDR_LENGTH);
773 /* otherwise return the packet back to mbox */
774 HIF_return_recv_buf(pHTC->hifHandle, pHTC->Endpoints[EndpointID].UpLinkPipeID, pBuffers);
778 /* mark that setup has completed */
779 pHTC->StateFlags |= HTC_STATE_SETUP_COMPLETE;
780 if (pHTC->SetupCompleteCb != NULL) {
781 pHTC->SetupCompleteCb();
786 /* callback when endpoint 0 send buffers are completed */
787 LOCAL void HTCControlSvcProcessSendComplete(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers, void *arg)
789 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)arg;
790 HTC_BUF_CONTEXT *ctx;
791 HTC_ENDPOINT_ID creditRptEndpoint;
793 ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(pBuffers);
795 //A_ASSERT(EndpointID == ENDPOINT0);
797 /* put them back into the pool */
799 while (pBuffers != NULL) {
800 pNext = pBuffers->next_buf;
801 pBuffers->next_buf = NULL;
802 /* note: HTC does not send fragmented control messages, so each buffer
803 * represents 1 full HTC control message */
804 if (pBuffers->desc_list->control & HTC_FLAGS_CREDIT_RPT) {
805 /* extract the endpoint number that requested this credit report */
806 creditRptEndpoint = pBuffers->desc_list->control & HTC_FLAGS_CRPT_EP_MASK;
807 pBuffers->desc_list->control = 0;
808 g_pHTC->Endpoints[creditRptEndpoint].PendingCreditReports--;
809 //A_ASSERT(g_pHTC->Endpoints[creditRptEndpoint].PendingCreditReports >= 0);
812 HTCFreeMsgBuffer(pBuffers);
816 if ( ctx->htc_flags & HTC_FLAGS_CREDIT_RPT ) {
817 /* extract the endpoint number that requested this credit report */
818 creditRptEndpoint = ctx->htc_flags & HTC_FLAGS_CRPT_EP_MASK;
819 pHTC->Endpoints[creditRptEndpoint].PendingCreditReports--;
820 //A_ASSERT(g_pHTC->Endpoints[creditRptEndpoint].PendingCreditReports >= 0);
823 HTCFreeMsgBuffer(pHTC, pBuffers);
826 if (pHTC->StateFlags & HTC_SEND_CREDIT_UPDATE_SOON) {
827 /* this flag is set when the host could not send a credit report
828 * because we ran out of HTC control buffers */
829 pHTC->StateFlags &= ~HTC_SEND_CREDIT_UPDATE_SOON;
830 /* send out a report if anything is pending */
831 HTCCheckAndSendCreditReport(pHTC, HTC_ANY_ENDPOINT_MASK,NULL,ENDPOINT_MAX);
835 LOCAL void HTCSendDoneHandler(adf_nbuf_t buf, void *context)
838 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)context;
839 HTC_BUF_CONTEXT *ctx;
841 ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(buf);
842 current_eid = ctx->end_point;
844 /* Walk through the buffers and fixup the ones we used for HTC headers.
845 * The buffer list may contain more than one string of HTC buffers comprising of an
846 * HTC message so we need to check every buffer */
847 adf_nbuf_pull_head(buf, HTC_HDR_LENGTH);
849 pHTC->Endpoints[current_eid].pService->
850 ProcessSendBufferComplete(current_eid,
852 pHTC->Endpoints[current_eid].pService->ServiceCtx);
856 LOCAL void HTC_EnqueuePausedRecv(HTC_ENDPOINT *pEndpoint,
857 HTC_BUFFER *pFirstBuf,
858 HTC_BUFFER *pLastBuf)
860 //A_ASSERT(pLastBuf->next == NULL);
862 if (NULL == pEndpoint->pRcvPausedQueueTail) {
863 pEndpoint->pRcvPausedQueueTail = pLastBuf;
864 pEndpoint->pRcvPausedQueueHead = pFirstBuf;
866 /* queue to the tail */
867 pEndpoint->pRcvPausedQueueTail->next = pFirstBuf;
868 pEndpoint->pRcvPausedQueueTail = pLastBuf;
875 LOCAL HTC_BUFFER *HTC_DequeuePausedRecv(HTC_ENDPOINT *pEndpoint)
880 if (pEndpoint->pRcvPausedQueueHead != NULL) {
881 /* there is a message in the queue */
882 pHead = pEndpoint->pRcvPausedQueueHead;
885 while (pCur != NULL) {
886 /* check for end marker on this buffer */
887 if (pCur->htc_flags & HTC_FLAGS_RECV_END_MSG) {
888 pCur->htc_flags &= ~HTC_FLAGS_RECV_END_MSG;
889 /* advance the head */
890 pEndpoint->pRcvPausedQueueHead = pCur->next;
892 if (NULL == pEndpoint->pRcvPausedQueueHead) {
893 /* list is now empty */
894 pEndpoint->pRcvPausedQueueTail = NULL;
896 /* cut this message out */
902 /* we should always find complete messages with the marker present */
903 //A_ASSERT(pCur != NULL);
906 //A_ASSERT(pEndpoint->pRcvPausedQueueTail == NULL);
912 LOCAL void AdjustCreditThreshold(HTC_ENDPOINT *pEndpoint)
915 A_INT16 creditsOutstanding = pEndpoint->CreditsToReturn + pEndpoint->CreditsConsumed;
916 /* set the new threshold based on the number of credits that have been consumed
917 * and which have not been returned by the app.
918 * Note: it is okay for this threshold to be zero which indicates no threshold
920 switch (pEndpoint->ConnectionFlags & HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_MASK) {
921 case HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_FOURTH :
922 creditsOutstanding >>= 2;
924 case HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_HALF :
925 creditsOutstanding >>= 1;
927 case HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_THREE_FOURTHS :
928 creditsOutstanding = (creditsOutstanding * 3) >> 2;
930 /* default case is unity */
933 pEndpoint->CreditReturnThreshhold = creditsOutstanding;
937 LOCAL void RedistributeCredit(adf_nbuf_t buf, int toPipeId)
942 /* callback from the mailbox hardware layer when a full message arrives */
943 LOCAL void HTCMsgRecvHandler(adf_nbuf_t hdr_buf, adf_nbuf_t buffer, void *context)
946 HTC_ENDPOINT *pEndpoint;
951 HTC_FRAME_HDR *pHTCHdr;
952 HTC_CONTEXT *pHTC = (HTC_CONTEXT *)context;
955 if (hdr_buf == ADF_NBUF_NULL) {
956 /* HTC hdr is not in the hdr_buf */
963 adf_nbuf_peek_header(tmp_nbuf, &anbdata, &anblen);
964 pHTCHdr = (HTC_FRAME_HDR *)anbdata;
966 totsz = adf_os_ntohs(pHTCHdr->PayloadLen);
968 //A_ASSERT(pHTCHdr->EndpointID < ENDPOINT_MAX);
969 eid = pHTCHdr->EndpointID;
971 pEndpoint = &pHTC->Endpoints[eid];
974 if (pHTCHdr->Flags & HTC_FLAGS_CREDIT_REDISTRIBUTION) {
975 /* The pipe id where the credit is redistributed to is carried in Control
977 RedistributeCredit(tmp_nbuf, pHTCHdr->ControlBytes[0]);
981 if (pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE) {
982 /* after setup we keep track of credit consumption to allow us to
983 * adjust thresholds to reduce credit dribbling */
984 pEndpoint->CreditsConsumed ++;
987 /* from the design document, we put the endpoint into a "host-needs-credit" state
988 * when we receive a frame with the NEED_CREDIT_UPDATE flag set .
989 * if the host received credits through an opportunistic path, then it can
990 * issue a another frame with this bit cleared, this signals the target to clear
991 * the "host-needs-credit" state */
992 if (pHTCHdr->Flags & HTC_FLAGS_NEED_CREDIT_UPDATE) {
993 /* the host is running low (or is out) of credits on this
994 * endpoint, update mask */
995 pHTC->EpHostNeedsCreditMap |= eidMask;
996 /* check and set new threshold since host has reached a low credit situation */
997 CHECK_AND_ADJUST_CREDIT_THRESHOLD(pEndpoint);
1000 pHTC->EpHostNeedsCreditMap &= ~(eidMask);
1001 pEndpoint->CreditReturnThreshhold = 0;
1004 /* Adjust the first buffer to point to the start of the actual
1005 payload, the first buffer contains the header */
1006 adf_nbuf_pull_head(tmp_nbuf, HTC_HDR_LENGTH);
1008 /* NOTE : This callback could re-queue the recv buffers within this calling context.
1009 * The callback could also send a response message within the context of this callback
1010 * as the result of parsing this message. In either case, if there are
1011 * pending credits and the host needs them, a credit report will be sent either through
1012 * the response message trailer or a NULL message through HTC_ReturnBuffers().
1015 //A_ASSERT(totsz <= pEndpoint->pService->MaxSvcMsgSize);
1018 /* is this endpoint paused? */
1019 if (g_pHTC->EpRecvPausedMap & eidMask) {
1020 /* note that curr_buf is the last buffer */
1021 /* mark the last buffer so that it indicates the end of this message */
1022 //curr_buf->htc_flags |= HTC_FLAGS_RECV_END_MSG;
1023 /* enqueue this message to our pause queues */
1024 //HTC_EnqueuePausedRecv(pEndpoint,bufinfo,curr_buf);
1026 /* pass the message to the service */
1027 pEndpoint->pService->ProcessRecvMsg(eid, buffer, pEndpoint->pService->ServiceCtx);
1030 pEndpoint->pService->ProcessRecvMsg(eid, hdr_buf, buffer, pEndpoint->pService->ServiceCtx);
1033 /* Calls to HTC_ReturnBuffers drives the endpoint credit reporting state machine.
1034 * We do not want to delay credits for too long in the event that the application is
1035 * holding onto buffers for excessive periods of time. This gives us "some" better
1036 * opportunities to send up credits. */
1037 HTCCheckAndSendCreditReport(pHTC, eidMask, pEndpoint, eid);