/* process an incomming control message from the host */ LOCAL void HTCControlSvcProcessMsg(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t hdr_buf, adf_nbuf_t pBuffers, void *arg) { A_BOOL setupComplete = FALSE; a_uint8_t *anbdata; a_uint32_t anblen; HTC_CONTEXT *pHTC = (HTC_CONTEXT *)arg; HTC_UNKNOWN_MSG *pMsg; adf_os_assert(hdr_buf == ADF_NBUF_NULL); /* we assume buffers are aligned such that we can access the message * parameters directly*/ adf_nbuf_peek_header(pBuffers, &anbdata, &anblen); pMsg = (HTC_UNKNOWN_MSG *)anbdata; /* we cannot handle fragmented messages across buffers */ switch ( adf_os_ntohs(pMsg->MessageID) ) { case HTC_MSG_CONNECT_SERVICE_ID: HTCProcessConnectMsg(pHTC, (HTC_CONNECT_SERVICE_MSG *)pMsg); break; case HTC_MSG_CONFIG_PIPE_ID: HTCProcessConfigPipeMsg(pHTC, (HTC_CONFIG_PIPE_MSG *)pMsg); break; case HTC_MSG_SETUP_COMPLETE_ID: /* the host has indicated that it has completed all setup tasks and we can now let the services take over to run the rest of the application */ setupComplete = TRUE; /* can't get this more than once */ break; default: ; } if (pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE) { /* recycle buffer only if we are fully running */ HTC_ReturnBuffers(pHTC, ENDPOINT0,pBuffers); } else { /* supply some head-room again */ adf_nbuf_push_head(pBuffers, HTC_HDR_LENGTH); /* otherwise return the packet back to mbox */ HIF_return_recv_buf(pHTC->hifHandle, pHTC->Endpoints[EndpointID].UpLinkPipeID, pBuffers); } if (setupComplete) { /* mark that setup has completed */ pHTC->StateFlags |= HTC_STATE_SETUP_COMPLETE; if (pHTC->SetupCompleteCb != NULL) { pHTC->SetupCompleteCb(); } } }
/* callback from the mailbox hardware layer when a full message arrives */ LOCAL void HTCMsgRecvHandler(adf_nbuf_t hdr_buf, adf_nbuf_t buffer, void *context) { A_UINT16 totsz; HTC_ENDPOINT *pEndpoint; A_UINT32 eidMask; int eid; a_uint8_t *anbdata; a_uint32_t anblen; HTC_FRAME_HDR *pHTCHdr; HTC_CONTEXT *pHTC = (HTC_CONTEXT *)context; adf_nbuf_t tmp_nbuf; if (hdr_buf == ADF_NBUF_NULL) { /* HTC hdr is not in the hdr_buf */ tmp_nbuf = buffer; } else { tmp_nbuf = hdr_buf; } adf_nbuf_peek_header(tmp_nbuf, &anbdata, &anblen); pHTCHdr = (HTC_FRAME_HDR *)anbdata; totsz = adf_os_ntohs(pHTCHdr->PayloadLen); eid = pHTCHdr->EndpointID; pEndpoint = &pHTC->Endpoints[eid]; eidMask = 1 << eid; if (pHTCHdr->Flags & HTC_FLAGS_CREDIT_REDISTRIBUTION) { /* The pipe id where the credit is redistributed to is carried in Control * Byte 0 */ RedistributeCredit(tmp_nbuf, pHTCHdr->ControlBytes[0]); return; } if (pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE) { /* after setup we keep track of credit consumption to allow us to * adjust thresholds to reduce credit dribbling */ pEndpoint->CreditsConsumed ++; } /* from the design document, we put the endpoint into a "host-needs-credit" state * when we receive a frame with the NEED_CREDIT_UPDATE flag set . * if the host received credits through an opportunistic path, then it can * issue a another frame with this bit cleared, this signals the target to clear * the "host-needs-credit" state */ if (pHTCHdr->Flags & HTC_FLAGS_NEED_CREDIT_UPDATE) { /* the host is running low (or is out) of credits on this * endpoint, update mask */ pHTC->EpHostNeedsCreditMap |= eidMask; /* check and set new threshold since host has reached a low credit situation */ CHECK_AND_ADJUST_CREDIT_THRESHOLD(pEndpoint); } else { /* clear the flag */ pHTC->EpHostNeedsCreditMap &= ~(eidMask); pEndpoint->CreditReturnThreshhold = 0; } /* Adjust the first buffer to point to the start of the actual payload, the first buffer contains the header */ adf_nbuf_pull_head(tmp_nbuf, HTC_HDR_LENGTH); /* NOTE : This callback could re-queue the recv buffers within this calling context. * The callback could also send a response message within the context of this callback * as the result of parsing this message. In either case, if there are * pending credits and the host needs them, a credit report will be sent either through * the response message trailer or a NULL message through HTC_ReturnBuffers(). */ pEndpoint->pService->ProcessRecvMsg(eid, hdr_buf, buffer, pEndpoint->pService->ServiceCtx); /* Calls to HTC_ReturnBuffers drives the endpoint credit reporting state machine. * We do not want to delay credits for too long in the event that the application is * holding onto buffers for excessive periods of time. This gives us "some" better * opportunities to send up credits. */ HTCCheckAndSendCreditReport(pHTC, eidMask, pEndpoint, eid); }
static void WMIRecvMessageHandler(HTC_ENDPOINT_ID EndPt, adf_nbuf_t hdr_buf, adf_nbuf_t pHTCBuf, void *arg) { void *pContext; WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)arg; WMI_DISPATCH_TABLE *pCurrentTable; WMI_DISPATCH_ENTRY*pCurrentEntry; WMI_CMD_HANDLER pCmdHandler; A_UINT8* pCmdBuffer; int i; A_UINT16 cmd; A_UINT16 seq; int length; a_uint8_t *anbdata; a_uint32_t anblen; WMI_CMD_HDR *cmdHdr; adf_os_assert(hdr_buf == ADF_NBUF_NULL); do { length = adf_nbuf_len(pHTCBuf); if (length < sizeof(WMI_CMD_HDR)) { break; } adf_nbuf_peek_header(pHTCBuf, &anbdata, &anblen); pCurrentTable = pWMI->pDispatchHead; length = length - sizeof(WMI_CMD_HDR); cmdHdr = (WMI_CMD_HDR *)anbdata; cmd = adf_os_ntohs(cmdHdr->commandId); seq = adf_os_ntohs(cmdHdr->seqNo); pCmdBuffer = anbdata + sizeof(WMI_CMD_HDR); pCmdHandler = NULL; while (pCurrentTable != NULL) { pContext = pCurrentTable->pContext; pCurrentEntry = pCurrentTable->pTable; /* scan table entries */ for (i = 0; i < pCurrentTable->NumberOfEntries; i++, pCurrentEntry++) { if (pCurrentEntry->CmdID == cmd) { /* found a match */ pCmdHandler = pCurrentEntry->pCmdHandler; /* optionally check length */ if ((pCurrentEntry->CheckLength != 0) && (length < pCurrentEntry->CheckLength)) { /* do not process command */ pCmdHandler = NULL; } /* end search */ break; } } if (pCmdHandler != NULL) { /* found a handler */ break; } /* scan next table */ pCurrentTable = pCurrentTable->pNext; } if (NULL == pCmdHandler) { break; } /* if we get here, we have a command handler to dispatch */ /* call dispatch function */ pCmdHandler(pContext, cmd, seq, pCmdBuffer, length); } while (FALSE); /* Invalidate the buffer (including HTC header). Note : we only need to invalidate up to the portion * that was used (cache invalidate will also round up to the nearest cache line). * The rest of the buffer should still be coherent. * */ HTC_ReturnBuffers(pWMI->HtcHandle, EndPt, pHTCBuf); }
/* called in response to the arrival of a service connection message */ LOCAL void HTCProcessConnectMsg(HTC_CONTEXT *pHTC, HTC_CONNECT_SERVICE_MSG *pMsg) { HTC_SERVICE *pService = pHTC->pServiceList; A_UINT8 connectStatus = HTC_SERVICE_NOT_FOUND; adf_nbuf_t pBuffer; HTC_CONNECT_SERVICE_RESPONSE_MSG *pRspMsg; int metaDataOutLen = 0; A_UINT16 serviceId = adf_os_ntohs(pMsg->ServiceID); pBuffer = HTCAllocMsgBuffer(pHTC); /* note : this will be aligned */ pRspMsg = (HTC_CONNECT_SERVICE_RESPONSE_MSG *) adf_nbuf_put_tail(pBuffer, sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG)); A_MEMZERO(pRspMsg,sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG)); pRspMsg->MessageID = adf_os_htons(HTC_MSG_CONNECT_SERVICE_RESPONSE_ID); /* reflect the service ID for this connect attempt */ pRspMsg->ServiceID = adf_os_htons(serviceId); while (pService) { if (pHTC->CurrentEpIndex >= ENDPOINT_MAX) { /* no more endpoints */ connectStatus = HTC_SERVICE_NO_RESOURCES; break; } if (serviceId == pService->ServiceID) { /* we found a match */ A_UINT8 *pMetaDataIN = NULL; A_UINT8 *pMetaDataOut; /* outgoing meta data resides in the space after the response message */ pMetaDataOut = ((A_UINT8 *)pRspMsg) + sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG); if (pMsg->ServiceMetaLength != 0) { /* the meta data follows the connect service message */ pMetaDataIN = ((A_UINT8 *)pMsg) + sizeof(HTC_CONNECT_SERVICE_MSG); } /* call the connect callback with the endpoint to use and pointers to meta data */ connectStatus = pService->ProcessConnect(pService, pHTC->CurrentEpIndex, pMetaDataIN, pMsg->ServiceMetaLength, pMetaDataOut, &metaDataOutLen); /* check if the service accepted this connection request */ if (HTC_SERVICE_SUCCESS == connectStatus) { /* set the length of the response meta data going back to the host */ pRspMsg->ServiceMetaLength = (A_UINT8)metaDataOutLen; /* set the endpoint ID the host will now communicate over */ pRspMsg->EndpointID = pHTC->CurrentEpIndex; /* return the maximum message size for this service */ pRspMsg->MaxMsgSize = adf_os_htons((A_UINT16)pService->MaxSvcMsgSize); /* assign this endpoint to this service, this will be used in routing messages */ pHTC->Endpoints[pHTC->CurrentEpIndex].pService = pService; /* set connection flags */ pHTC->Endpoints[pHTC->CurrentEpIndex].ConnectionFlags = pMsg->ConnectionFlags; pHTC->Endpoints[pHTC->CurrentEpIndex].DownLinkPipeID = pMsg->DownLinkPipeID; pHTC->Endpoints[pHTC->CurrentEpIndex].UpLinkPipeID = pMsg->UpLinkPipeID; /* mark that we are now connected */ pService->ServiceFlags |= HTC_SERVICE_FLAGS_CONNECTED; /* bump up our index, this EP is now in use */ pHTC->CurrentEpIndex++; } break; } pService = pService->pNext; } pRspMsg->Status = connectStatus; /* send out the response message */ HTC_SendMsg(pHTC, ENDPOINT0, pBuffer); }
/* process credit reports and call distribution function */ void HTCProcessCreditRpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt0, a_uint32_t RecLen, HTC_ENDPOINT_ID FromEndpoint) { a_uint32_t i; a_uint32_t NumEntries; #ifdef HTC_HOST_CREDIT_DIST a_uint32_t totalCredits = 0; a_uint8_t doDist = FALSE; HTC_ENDPOINT *pEndpoint; a_uint16_t seq_diff; a_uint16_t tgt_seq; #endif HTC_CREDIT_REPORT_1_1 *pRpt = (HTC_CREDIT_REPORT_1_1 *)pRpt0 ; NumEntries = RecLen / (sizeof(HTC_CREDIT_REPORT_1_1)) ; /* lock out TX while we update credits */ LOCK_HTC_TX(target); for (i = 0; i < NumEntries; i++, pRpt++) { if (pRpt->EndpointID >= ENDPOINT_MAX) { adf_os_assert(0); break; } #ifdef HTC_HOST_CREDIT_DIST pEndpoint = &target->EndPoint[pRpt->EndpointID]; tgt_seq = adf_os_ntohs(pRpt->TgtCreditSeqNo); if (ENDPOINT0 == pRpt->EndpointID) { /* always give endpoint 0 credits back */ seq_diff = (tgt_seq - pEndpoint->LastCreditSeq) & (HTC_SEQ_MAX -1); pEndpoint->CreditDist.TxCredits += seq_diff; pEndpoint->LastCreditSeq = tgt_seq; } else { /* for all other endpoints, update credits to distribute, the distribution function * will handle giving out credits back to the endpoints */ #ifdef MAGPIE_HIF_GMAC if ( pRpt->EndpointID == 6 ) OS_SET_TIMER(&host_seek_credit_timer, 1000); #endif seq_diff = (tgt_seq - pEndpoint->LastCreditSeq) & (HTC_SEQ_MAX -1); pEndpoint->CreditDist.TxCreditsToDist += seq_diff; pEndpoint->LastCreditSeq = tgt_seq; /* flag that we have to do the distribution */ doDist = TRUE; } totalCredits += seq_diff; #endif } #ifdef HTC_HOST_CREDIT_DIST if (doDist) { /* this was a credit return based on a completed send operations * note, this is done with the lock held */ DO_DISTRIBUTION(target, HTC_CREDIT_DIST_SEND_COMPLETE, "Send Complete", target->EpCreditDistributionListHead->pNext); } #endif UNLOCK_HTC_TX(target); }