void HTCFlushRxHoldQueue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint) { HTC_PACKET *pPacket; HTC_PACKET_QUEUE container; LOCK_HTC_RX(target); while (1) { pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBufferHoldQueue); if (NULL == pPacket) { break; } UNLOCK_HTC_RX(target); pPacket->Status = A_ECANCELED; pPacket->ActualLength = 0; AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" Flushing RX packet:%p, length:%d, ep:%d \n", pPacket, pPacket->BufferLength, pPacket->Endpoint)); INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket); /* give the packet back */ DoRecvCompletion(pEndpoint,&container); LOCK_HTC_RX(target); } UNLOCK_HTC_RX(target); }
static void DoRecvCompletion(HTC_ENDPOINT *pEndpoint, HTC_PACKET_QUEUE *pQueueToIndicate) { do { if (HTC_QUEUE_EMPTY(pQueueToIndicate)) { /* nothing to indicate */ break; } if (pEndpoint->EpCallBacks.EpRecvPktMultiple != NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" HTC calling ep %d, recv multiple callback (%d pkts) \n", pEndpoint->Id, HTC_PACKET_QUEUE_DEPTH(pQueueToIndicate))); /* a recv multiple handler is being used, pass the queue to the handler */ pEndpoint->EpCallBacks.EpRecvPktMultiple(pEndpoint->EpCallBacks.pContext, pQueueToIndicate); INIT_HTC_PACKET_QUEUE(pQueueToIndicate); } else { HTC_PACKET *pPacket; /* using legacy EpRecv */ while (!HTC_QUEUE_EMPTY(pQueueToIndicate)) { pPacket = HTC_PACKET_DEQUEUE(pQueueToIndicate); AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" HTC calling ep %d recv callback on packet %p \n", pEndpoint->Id, pPacket)); pEndpoint->EpCallBacks.EpRecv(pEndpoint->EpCallBacks.pContext, pPacket); } } } while (FALSE); }
static void HTCFlushEndpointRX(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint) { HTC_PACKET *pPacket; LOCK_HTC_RX(target); while (1) { pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers); if (NULL == pPacket) { break; } UNLOCK_HTC_RX(target); pPacket->Status = A_ECANCELED; pPacket->ActualLength = 0; AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" Flushing RX packet:0x%X, length:%d, ep:%d \n", (A_UINT32)pPacket, pPacket->BufferLength, pPacket->Endpoint)); /* give the packet back */ pEndpoint->EpCallBacks.EpRecv(pEndpoint->EpCallBacks.pContext, pPacket); LOCK_HTC_RX(target); } UNLOCK_HTC_RX(target); }
static struct htc_packet * AllocHTCStruct(struct ar6k_hci_bridge_info *pHcidevInfo) { struct htc_packet *pPacket = NULL; LOCK_BRIDGE(pHcidevInfo); pPacket = HTC_PACKET_DEQUEUE(&pHcidevInfo->HTCPacketStructHead); UNLOCK_BRIDGE(pHcidevInfo); return pPacket; }
static HTC_PACKET * AllocHTCStruct(AR6K_HCI_BRIDGE_INFO *pHcidevInfo) { HTC_PACKET *pPacket = NULL; LOCK_BRIDGE(pHcidevInfo); pPacket = HTC_PACKET_DEQUEUE(&pHcidevInfo->HTCPacketStructHead); UNLOCK_BRIDGE(pHcidevInfo); return pPacket; }
HTC_PACKET *AR6KAllocIOPacket(AR6K_DEVICE *pDev) { HTC_PACKET *pPacket; LOCK_AR6K(pDev); pPacket = HTC_PACKET_DEQUEUE(&pDev->RegisterIOList); UNLOCK_AR6K(pDev); return pPacket; }
HTC_PACKET *HTCAllocControlBuffer(HTC_TARGET *target, HTC_PACKET_QUEUE *pList) { HTC_PACKET *pPacket; LOCK_HTC(target); pPacket = HTC_PACKET_DEQUEUE(pList); UNLOCK_HTC(target); return pPacket; }
struct htc_packet *AR6KAllocIOPacket(struct ar6k_device *pDev) { struct htc_packet *pPacket; LOCK_AR6K(pDev); pPacket = HTC_PACKET_DEQUEUE(&pDev->RegisterIOList); UNLOCK_AR6K(pDev); return pPacket; }
HTC_PACKET *HTCAllocControlTxPacket(HTC_TARGET *target) { #ifdef TODO_FIXME HTC_PACKET *pPacket; LOCK_HTC(target); pPacket = HTC_PACKET_DEQUEUE(&target->ControlBufferTXFreeList); UNLOCK_HTC(target); return pPacket; #else return BuildHTCTxCtrlPacket(target->osdev); #endif }
/* * Call netif_stop_queue frequently will impact the mboxping tx t-put. * Return HTC_SEND_FULL_KEEP directly in epping_tx_queue_full to avoid. */ return HTC_SEND_FULL_KEEP; } #endif /* HIF_SDIO */ void epping_tx_complete_multiple(void *ctx, HTC_PACKET_QUEUE *pPacketQueue) { epping_context_t *pEpping_ctx = (epping_context_t *)ctx; epping_adapter_t *pAdapter = pEpping_ctx->epping_adapter; struct net_device* dev = pAdapter->dev; A_STATUS status; HTC_ENDPOINT_ID eid; adf_nbuf_t pktSkb; struct epping_cookie *cookie; A_BOOL flushing = FALSE; adf_nbuf_queue_t skb_queue; HTC_PACKET *htc_pkt; adf_nbuf_queue_init(&skb_queue); adf_os_spin_lock_bh(&pAdapter->data_lock); while (!HTC_QUEUE_EMPTY(pPacketQueue)) { htc_pkt = HTC_PACKET_DEQUEUE(pPacketQueue); if (htc_pkt == NULL) break; status=htc_pkt->Status; eid=htc_pkt->Endpoint; pktSkb=GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt); cookie = htc_pkt->pPktContext; if (!pktSkb) { EPPING_LOG(VOS_TRACE_LEVEL_ERROR, "%s: pktSkb is NULL", __func__); ASSERT(0); } else { if (htc_pkt->pBuffer != adf_nbuf_data(pktSkb)) { EPPING_LOG(VOS_TRACE_LEVEL_ERROR, "%s: htc_pkt buffer not equal to skb->data", __func__); ASSERT(0); } /* add this to the list, use faster non-lock API */ adf_nbuf_queue_add(&skb_queue,pktSkb); if (A_SUCCESS(status)) if (htc_pkt->ActualLength != adf_nbuf_len(pktSkb)) { EPPING_LOG(VOS_TRACE_LEVEL_ERROR, "%s: htc_pkt length not equal to skb->len", __func__); ASSERT(0); } } EPPING_LOG(VOS_TRACE_LEVEL_INFO, "%s skb=%p data=%p len=0x%x eid=%d ", __func__, pktSkb, htc_pkt->pBuffer, htc_pkt->ActualLength, eid); if (A_FAILED(status)) { if (status == A_ECANCELED) { /* a packet was flushed */ flushing = TRUE; } if (status != A_NO_RESOURCE) { printk("%s() -TX ERROR, status: 0x%x\n", __func__, status); } } else { EPPING_LOG(VOS_TRACE_LEVEL_INFO, "%s: OK\n", __func__); flushing = FALSE; } epping_free_cookie(pAdapter->pEpping_ctx, cookie); } adf_os_spin_unlock_bh(&pAdapter->data_lock); /* free all skbs in our local list */ while (adf_nbuf_queue_len(&skb_queue)) { /* use non-lock version */ pktSkb = adf_nbuf_queue_remove(&skb_queue); if (pktSkb == NULL) break; adf_nbuf_tx_free(pktSkb, ADF_NBUF_PKT_ERROR); pEpping_ctx->total_tx_acks++; } if (!flushing) { netif_wake_queue(dev); } }
/* callback when device layer or lookahead report parsing detects a pending message */ A_STATUS HTCRecvMessagePendingHandler(void *Context, A_UINT32 *LookAhead, A_BOOL *pAsyncProc) { HTC_TARGET *target = (HTC_TARGET *)Context; A_STATUS status = A_OK; HTC_PACKET *pPacket = NULL; HTC_FRAME_HDR *pHdr = NULL; HTC_ENDPOINT *pEndpoint = NULL; A_BOOL asyncProc = FALSE; AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCRecvMessagePendingHandler LookAhead:0x%X \n", *LookAhead)); if (IS_DEV_IRQ_PROCESSING_ASYNC_ALLOWED(&target->Device)) { /* We use async mode to get the packets if the device layer supports it. * The device layer interfaces with HIF in which HIF may have restrictions on * how interrupts are processed */ asyncProc = TRUE; } if (pAsyncProc != NULL) { /* indicate to caller how we decided to process this */ *pAsyncProc = asyncProc; } while (TRUE) { pHdr = (HTC_FRAME_HDR *)LookAhead; if (pHdr->EndpointID >= ENDPOINT_MAX) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Invalid Endpoint in look-ahead: %d \n",pHdr->EndpointID)); /* invalid endpoint */ status = A_EPROTO; break; } if (pHdr->PayloadLen > HTC_MAX_PAYLOAD_LENGTH) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Payload length %d exceeds max HTC : %d !\n", pHdr->PayloadLen, HTC_MAX_PAYLOAD_LENGTH)); status = A_EPROTO; break; } pEndpoint = &target->EndPoint[pHdr->EndpointID]; if (0 == pEndpoint->ServiceID) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Endpoint %d is not connected !\n",pHdr->EndpointID)); /* endpoint isn't even connected */ status = A_EPROTO; break; } if (pEndpoint->EpCallBacks.EpRecvAlloc != NULL) { /* user is using a per-packet allocation callback */ pPacket = pEndpoint->EpCallBacks.EpRecvAlloc(pEndpoint->EpCallBacks.pContext, (HTC_ENDPOINT_ID) pHdr->EndpointID, pHdr->PayloadLen + sizeof(HTC_FRAME_HDR)); /* lock RX, in case this allocation fails, we need to update internal state below */ LOCK_HTC_RX(target); } else { /* user is using a refill handler that can refill multiple HTC buffers */ /* lock RX to get a buffer */ LOCK_HTC_RX(target); /* get a packet from the endpoint recv queue */ pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers); if (NULL == pPacket) { /* check for refill handler */ if (pEndpoint->EpCallBacks.EpRecvRefill != NULL) { UNLOCK_HTC_RX(target); /* call the re-fill handler */ pEndpoint->EpCallBacks.EpRecvRefill(pEndpoint->EpCallBacks.pContext, (HTC_ENDPOINT_ID) pHdr->EndpointID); LOCK_HTC_RX(target); /* check if we have more buffers */ pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers); /* fall through */ } } } if (NULL == pPacket) { /* this is not an error, we simply need to mark that we are waiting for buffers.*/ target->HTCStateFlags |= HTC_STATE_WAIT_BUFFERS; target->EpWaitingForBuffers = (HTC_ENDPOINT_ID) pHdr->EndpointID; status = A_NO_MEMORY; } if (HTC_STOPPING(target)) { status = A_ECANCELED; } UNLOCK_HTC_RX(target); if (A_FAILED(status)) { /* no buffers or stopping */ break; } pPacket->PktInfo.AsRx.IndicationFlags = 0; AR_DEBUG_ASSERT(pPacket->Endpoint == pHdr->EndpointID); /* make sure this message can fit in the endpoint buffer */ if ((pHdr->PayloadLen + HTC_HDR_LENGTH) > pPacket->BufferLength) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Payload Length Error : header reports payload of: %d, endpoint buffer size: %d \n", pHdr->PayloadLen, pPacket->BufferLength)); status = A_EPROTO; break; } pPacket->HTCReserved = *LookAhead; /* set expected look ahead */ /* set the amount of data to fetch */ pPacket->ActualLength = pHdr->PayloadLen + HTC_HDR_LENGTH; if (asyncProc) { /* we use async mode to get the packet if the device layer supports it * set our callback and context */ pPacket->Completion = HTCRecvCompleteHandler; pPacket->pContext = target; } else { /* fully synchronous */ pPacket->Completion = NULL; } /* go fetch the packet */ status = HTCIssueRecv(target, pPacket); if (A_FAILED(status)) { break; } if (asyncProc) { /* we did this asynchronously so we can get out of the loop, the asynch processing * creates a chain of requests to continue processing pending messages in the * context of callbacks */ break; } /* in the sync case, we process the packet, check lookaheads and then repeat */ *LookAhead = 0; status = HTCProcessRecvHeader(target,pPacket,LookAhead); if (A_FAILED(status)) { break; } HTC_RX_STAT_PROFILE(target,pEndpoint,*LookAhead); /* check lookahead to see if we can indicate next packet hint to recv callback */ if (LookAhead != 0) { pHdr = (HTC_FRAME_HDR *)&LookAhead; /* check to see if the "next" packet is from the same endpoint of the completing packet */ if (pHdr->EndpointID == pPacket->Endpoint) { /* check that there is a buffer available to actually fetch it * NOTE: no need to lock RX here , since we are synchronously processing RX * and we are only looking at the queue (not modifying it) */ if (!HTC_QUEUE_EMPTY(&pEndpoint->RxBuffers)) { /* provide a hint that there are more RX packets to fetch */ pPacket->PktInfo.AsRx.IndicationFlags |= HTC_RX_FLAGS_INDICATE_MORE_PKTS; } } } DO_RCV_COMPLETION(target,pPacket,pEndpoint); pPacket = NULL; if (0 == *LookAhead) { break; } /* check whether other OS contexts have queued any WMI command/data for WLAN. * This check is needed only if WLAN Tx and Rx happens in same thread context */ A_CHECK_DRV_TX(); } if (A_NO_MEMORY == status) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Endpoint :%d has no buffers, blocking receiver to prevent overrun.. \n", (pHdr != NULL) ? pHdr->EndpointID : 0xFFFF)); /* try to stop receive at the device layer */ DevStopRecv(&target->Device, asyncProc ? DEV_STOP_RECV_ASYNC : DEV_STOP_RECV_SYNC); status = A_OK; } else if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to get pending message : LookAhead Value: 0x%X (status = %d) \n", *LookAhead, status)); if (pPacket != NULL) { /* clean up packet on error */ HTC_RECYCLE_RX_PKT(target, pPacket, pEndpoint); } } AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCRecvMessagePendingHandler \n")); return status; }