/* callback when endpoint 0 send buffers are completed */ LOCAL void HTCControlSvcProcessSendComplete(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers, void *arg) { HTC_CONTEXT *pHTC = (HTC_CONTEXT *)arg; HTC_BUF_CONTEXT *ctx; HTC_ENDPOINT_ID creditRptEndpoint; ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(pBuffers); /* put them back into the pool */ if ( ctx->htc_flags & HTC_FLAGS_CREDIT_RPT ) { /* extract the endpoint number that requested this credit report */ creditRptEndpoint = ctx->htc_flags & HTC_FLAGS_CRPT_EP_MASK; pHTC->Endpoints[creditRptEndpoint].PendingCreditReports--; } HTCFreeMsgBuffer(pHTC, pBuffers); if (pHTC->StateFlags & HTC_SEND_CREDIT_UPDATE_SOON) { /* this flag is set when the host could not send a credit report * because we ran out of HTC control buffers */ pHTC->StateFlags &= ~HTC_SEND_CREDIT_UPDATE_SOON; /* send out a report if anything is pending */ HTCCheckAndSendCreditReport(pHTC, HTC_ANY_ENDPOINT_MASK,NULL,ENDPOINT_MAX); } }
void ieee80211_recv_mgmt_defer(void *arg) { struct ieee80211com *ic = (struct ieee80211com *)arg; struct ieee80211_recv_mgt_args *entry = NULL; wbuf_t wbuf = ADF_NBUF_NULL; struct ieee80211_rx_status rs; struct ieee80211vap *vap ; /* Dequeue and process */ do { OS_MGMT_LOCKBH(&ic->ic_mgmt_lock); wbuf = adf_nbuf_queue_remove(&ic->ic_mgmt_nbufqueue); OS_MGMT_UNLOCKBH(&ic->ic_mgmt_lock); if(!wbuf) break; entry = (struct ieee80211_recv_mgt_args *)adf_nbuf_get_priv(wbuf); ieee80211_recv_mgmt( entry->ni, wbuf, entry->subtype, &rs); vap = entry->ni->ni_vap; if (vap->iv_evtable) { vap->iv_evtable->wlan_receive(vap->iv_ifp,wbuf,IEEE80211_FC0_TYPE_MGT,entry->subtype, &rs); } }while(1); atomic_set(&ic->ic_mgmt_deferflags, DEFER_DONE); return; }
/* send completion handler when any HTC buffers are returned */ static void _WMI_SendCompleteHandler(HTC_ENDPOINT_ID Endpt, adf_nbuf_t pHTCBuf, void *arg) { WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)arg; WMI_BUF_CONTEXT *ctx; BUF_POOL_ID poolId; ctx = (WMI_BUF_CONTEXT *)adf_nbuf_get_priv(pHTCBuf); if ( ctx->EventClass == WMI_EVT_CLASS_CMD_EVENT ) { poolId = POOL_ID_WMI_SVC_EVENT; } else { poolId = POOL_ID_WMI_SVC_CMD_REPLY; } BUF_Pool_free_buf(pWMI->PoolHandle, poolId, pHTCBuf); }
LOCAL void HTCSendDoneHandler(adf_nbuf_t buf, void *context) { A_UINT8 current_eid; HTC_CONTEXT *pHTC = (HTC_CONTEXT *)context; HTC_BUF_CONTEXT *ctx; ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(buf); current_eid = ctx->end_point; /* Walk through the buffers and fixup the ones we used for HTC headers. * The buffer list may contain more than one string of HTC buffers comprising of an * HTC message so we need to check every buffer */ adf_nbuf_pull_head(buf, HTC_HDR_LENGTH); pHTC->Endpoints[current_eid].pService-> ProcessSendBufferComplete(current_eid, buf, pHTC->Endpoints[current_eid].pService->ServiceCtx); }
static adf_nbuf_t _WMI_AllocEvent(wmi_handle_t handle, WMI_EVT_CLASS EventClass, int Length) { BUF_POOL_ID poolId; WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)handle; adf_nbuf_t buf; WMI_BUF_CONTEXT *ctx; if ( EventClass == WMI_EVT_CLASS_CMD_EVENT ) { poolId = POOL_ID_WMI_SVC_EVENT; } else { poolId = POOL_ID_WMI_SVC_CMD_REPLY; } buf = BUF_Pool_alloc_buf(pWMI->PoolHandle, poolId, sizeof(WMI_CMD_HDR) + HTC_GetReservedHeadroom(pWMI->HtcHandle)); if ( buf != NULL ) { ctx = (WMI_BUF_CONTEXT *)adf_nbuf_get_priv(buf); ctx->EventClass = EventClass; } return buf; }
LOCAL void HTCCheckAndSendCreditReport(HTC_CONTEXT *pHTC, A_UINT32 EpMask, HTC_ENDPOINT *pEndpoint, HTC_ENDPOINT_ID Eid) { adf_nbuf_t pCredBuffer; HTC_BUF_CONTEXT *ctx; do { /* check if host needs credits */ if (!(pHTC->EpHostNeedsCreditMap & EpMask)) { /* host does not need any credits for this set */ break; } /* check if any are pending */ if (!(pHTC->EpCreditPendingMap & EpMask)) { /* nothing to send up */ break; } /* was an endpoint specified? */ if (pEndpoint != NULL) { /* see if a threshold is in effect for this endpoint */ if (pEndpoint->CreditReturnThreshhold != 0) { if (pEndpoint->CreditsToReturn < pEndpoint->CreditReturnThreshhold) { /* this endpoint is using a threshold to prevent credits from dribbling * back to the host */ break; } } if (pEndpoint->PendingCreditReports >= pHTC->MaxEpPendingCreditRpts) { /* this endpoint already has some reports outstanding */ /* flag that as soon as a buffer is reaped, we issue a credit update to * pick up this credit that is being held up because the endpoint has already * exceeded the max outstanding credit report limit */ pHTC->StateFlags |= HTC_SEND_CREDIT_UPDATE_SOON; break; } } /* if we get here we have some credits to send up */ /* allocate a message buffer for the trailer */ pCredBuffer = HTCAllocMsgBuffer(pHTC); if (NULL == pCredBuffer) { /* no buffers left to send an empty message with trailers, host will just * have to wait until we get our endpoint 0 messages back.. */ /* mark that we need to send an update as soon as we can get a buffer back */ pHTC->StateFlags |= HTC_SEND_CREDIT_UPDATE_SOON; break; } ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(pCredBuffer); if (pEndpoint != NULL) { /* keep track of pending reports */ pEndpoint->PendingCreditReports++; /* save the endpoint in order to decrement the count when the send completes */ ctx->htc_flags = Eid | HTC_FLAGS_CREDIT_RPT; } /* this is an empty message, the HTC_SendMsg will tack on a trailer in the remaining * space, NOTE: no need to flush the cache, the header and trailers are assembled * using uncached addresses */ HTC_SendMsg(pHTC, ENDPOINT0, pCredBuffer); } while (FALSE); }
LOCAL void _HTC_SendMsg(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers) { HTC_FRAME_HDR *pHTCHdr; int totsz; HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle; HTC_BUF_CONTEXT *ctx; ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(pBuffers); /* init total size (this does not include the space we will put in for the HTC header) */ totsz = adf_nbuf_len(pBuffers); /* the first buffer stores the header */ /* back up buffer by a header size when we pass it down, by agreed upon convention the caller * points the buffer to it's payload and leaves head room for the HTC header * Note: in HTCSendDoneHandler(), we undo this so that the caller get's it's buffer * back untainted */ pHTCHdr = (HTC_FRAME_HDR *)adf_nbuf_push_head(pBuffers, HTC_HDR_LENGTH); /* flag that this is the header buffer that was modified */ ctx->htc_flags |= HTC_FLAGS_BUF_HDR; /* mark where this buffer came from */ ctx->end_point = EndpointID; /* the header start is ALWAYS aligned since we DMA it directly */ /* set some fields, the rest of them will be filled below when we check for * trailer space */ pHTCHdr->Flags = 0; pHTCHdr->EndpointID = EndpointID; /* check opportunistically if we can return any reports via a trailer */ do { int room,i,totalReportBytes; A_UINT32 creditsPendingMap, compareMask; HTC_CREDIT_REPORT *pCreditRpt; HTC_RECORD_HDR *pRecHdr; int pipeMaxLen; A_UINT32 roomForPipeMaxLen; /* figure out how much room the last buffer can spare */ pipeMaxLen = HIF_get_max_msg_len(pHTC->hifHandle, pHTC->Endpoints[EndpointID].DownLinkPipeID); roomForPipeMaxLen = pipeMaxLen - adf_nbuf_headroom(pBuffers) - adf_nbuf_len(pBuffers); if ( roomForPipeMaxLen < 0 ) { roomForPipeMaxLen = 0; } room = adf_os_min( adf_nbuf_tailroom(pBuffers), roomForPipeMaxLen); if (room < (int)(sizeof(HTC_CREDIT_REPORT) + sizeof(HTC_RECORD_HDR))) { /* no room for any reports */ break; } /* note, a record header only has 8 bit fields, so this is safe. * we need an uncached pointer here too */ totalReportBytes = 0; /* get a copy */ creditsPendingMap = pHTC->EpCreditPendingMap; /* test pending map to see if we can send a report , if any * credits are available, we might as well send them on the * unused space in the buffer */ if (creditsPendingMap) { pRecHdr = (HTC_RECORD_HDR *)adf_nbuf_put_tail(pBuffers, sizeof(HTC_RECORD_HDR)); /* set the ID, the length will be updated with the number of credit reports we * can fit (see below) */ pRecHdr->RecordID = HTC_RECORD_CREDITS; pRecHdr->Length = 0; /* the credit report follows the record header */ totalReportBytes += sizeof(HTC_RECORD_HDR); room -= sizeof(HTC_RECORD_HDR); /* walkthrough pending credits map and build the records */ for (i = 0; (creditsPendingMap != 0) && (room >= (int)sizeof(HTC_CREDIT_REPORT)); i++) { compareMask = (1 << i); if (compareMask & creditsPendingMap) { pCreditRpt = (HTC_CREDIT_REPORT *)adf_nbuf_put_tail(pBuffers, sizeof(HTC_CREDIT_REPORT)); /* clear pending mask, we are going to return all these credits */ creditsPendingMap &= ~(compareMask); /* add this record */ pCreditRpt->EndpointID = i; pCreditRpt->Credits = (A_UINT8)pHTC->Endpoints[i].CreditsToReturn; /* remove pending credits, we always send deltas */ pHTC->Endpoints[i].CreditsToReturn = 0; /* adjust new threshold for this endpoint if needed */ CHECK_AND_ADJUST_CREDIT_THRESHOLD(&pHTC->Endpoints[i]); /* update this record length */ pRecHdr->Length += sizeof(HTC_CREDIT_REPORT); room -= sizeof(HTC_CREDIT_REPORT); totalReportBytes += sizeof(HTC_CREDIT_REPORT); if ( room < sizeof(HTC_CREDIT_REPORT) ) { break; } } } /* update new pending credits map */ pHTC->EpCreditPendingMap = creditsPendingMap; } if (totalReportBytes <= 0) { break; } /* must fit into a byte, this should never actually happen since * the maximum possible number of endpoints is 32. * The trailer can have at most 1 credit record with up to 32 reports in the record. * The trailer can have at most 1 lookahead record with only 1 lookahead report in the record. */ /* set header option bytes */ pHTCHdr->ControlBytes[0] = totalReportBytes; /* HTC frame contains a trailer */ pHTCHdr->Flags |= HTC_FLAGS_RECV_TRAILER; /* increment total size by the reports we added */ totsz += totalReportBytes; /* adjust the last buffer we used for adding on the trailer */ } while (FALSE); if (totsz == 0) { } /* set length for message (this includes any reports that were added above) */ pHTCHdr->PayloadLen = adf_os_htons(totsz); HIF_send_buffer(pHTC->hifHandle, pHTC->Endpoints[EndpointID].DownLinkPipeID, pBuffers); }