static inline int htt_tx_send_base( htt_pdev_handle pdev, adf_nbuf_t msdu, u_int16_t msdu_id, int download_len, u_int8_t more_data) { struct htt_host_tx_desc_t *htt_host_tx_desc; struct htt_htc_pkt *pkt; int packet_len; HTC_ENDPOINT_ID ep_id; /* * The HTT tx descriptor was attached as the prefix fragment to the * msdu netbuf during the call to htt_tx_desc_init. * Retrieve it so we can provide its HTC header space to HTC. */ htt_host_tx_desc = (struct htt_host_tx_desc_t *) adf_nbuf_get_frag_vaddr(msdu, 0); pkt = htt_htc_pkt_alloc(pdev); if (!pkt) { return 1; /* failure */ } pkt->msdu_id = msdu_id; pkt->pdev_ctxt = pdev->txrx_pdev; /* packet length includes HTT tx desc frag added above */ packet_len = adf_nbuf_len(msdu); if (packet_len < download_len) { /* * This case of packet length being less than the nominal download * length can happen for a couple reasons: * In HL, the nominal download length is a large artificial value. * In LL, the frame may not have the optional header fields * accounted for in the nominal download size (LLC/SNAP header, * IPv4 or IPv6 header). */ download_len = packet_len; } ep_id = htt_tx_htt2_get_ep_id(pdev, msdu); SET_HTC_PACKET_INFO_TX( &pkt->htc_pkt, pdev->tx_send_complete_part2, (unsigned char *) htt_host_tx_desc, download_len - HTC_HDR_LENGTH, ep_id, 1); /* tag - not relevant here */ SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msdu); adf_nbuf_trace_update(msdu, "HT:T:"); HTCSendDataPkt(pdev->htc_pdev, &pkt->htc_pkt, more_data); return 0; /* success */ }
void usb_hif_io_comp_work(struct work_struct *work) { HIF_USB_PIPE *pipe = container_of(work, HIF_USB_PIPE, io_complete_work); adf_nbuf_t buf; HIF_DEVICE_USB *device; HTC_FRAME_HDR *HtcHdr; struct hif_usb_softc *sc; A_UINT8 *data; A_UINT32 len; AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+%s\n", __func__)); device = pipe->device; sc = device->sc; while ((buf = skb_dequeue(&pipe->io_comp_queue))) { a_mem_trace(buf); if (pipe->flags & HIF_USB_PIPE_FLAG_TX) { AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_OUT, ("+athusb xmit callback " "buf:0x%p\n", buf)); HtcHdr = (HTC_FRAME_HDR *) adf_nbuf_get_frag_vaddr(buf, 0); #ifdef ATH_11AC_TXCOMPACT #error ATH_11AC_TXCOMPACT only support for High Latency mode #else device->htcCallbacks.txCompletionHandler(device-> htcCallbacks. Context, buf, HtcHdr-> EndpointID); #endif AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_OUT, ("-athusb xmit callback\n")); } else { AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, ("+athusb recv callback buf:" "0x%p\n", buf)); adf_nbuf_peek_header(buf, &data, &len); if (IS_FW_CRASH_DUMP(*((A_UINT32 *) data))) { sc->fw_data = data; sc->fw_data_len = len; device->htcCallbacks.fwEventHandler( device->htcCallbacks.Context, A_USB_ERROR); dev_kfree_skb(buf); } else { device->htcCallbacks.rxCompletionHandler( device->htcCallbacks.Context, buf, pipe->logical_pipe_num); AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, ("-athusb recv callback\n")); } } } AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-%s\n", __func__)); }
A_STATUS HIFDevSendBuffer(HIF_SDIO_DEVICE *pDev, unsigned int transferID, a_uint8_t pipe, unsigned int nbytes, adf_nbuf_t buf) { A_STATUS status; A_UINT32 paddedLength; int frag_count = 0, i, head_data_len; struct HIFSendContext *pSendContext; unsigned char *pData; A_UINT32 request = HIF_WR_ASYNC_BLOCK_INC; A_UINT8 mboxIndex = HIFDevMapPipeToMailBox(pDev, pipe); paddedLength = DEV_CALC_SEND_PADDED_LEN(pDev, nbytes); #ifdef ENABLE_MBOX_DUMMY_SPACE_FEATURE A_ASSERT(paddedLength - nbytes < HIF_DUMMY_SPACE_MASK + 1); /* * two most significant bytes to save dummy data count * data written into the dummy space will not put into the final mbox FIFO * */ request |= ((paddedLength - nbytes) << 16); #endif frag_count = adf_nbuf_get_num_frags(buf); if (frag_count > 1){ /* header data length should be total sending length substract internal data length of netbuf */ /* * | HIFSendContext | fragments except internal buffer | netbuf->data */ head_data_len = sizeof(struct HIFSendContext) + (nbytes - adf_nbuf_get_frag_len(buf, frag_count - 1)); } else { /* * | HIFSendContext | netbuf->data */ head_data_len = sizeof(struct HIFSendContext); } /* Check whether head room is enough to save extra head data */ if ((head_data_len <= adf_nbuf_headroom(buf)) && (adf_nbuf_tailroom(buf) >= (paddedLength - nbytes))){ pSendContext = (struct HIFSendContext*)adf_nbuf_push_head(buf, head_data_len); pSendContext->bNewAlloc = FALSE; } else { pSendContext = (struct HIFSendContext*)adf_os_mem_alloc(NULL, sizeof(struct HIFSendContext) + paddedLength); pSendContext->bNewAlloc = TRUE; } pSendContext->netbuf = buf; pSendContext->pDev = pDev; pSendContext->transferID = transferID; pSendContext->head_data_len = head_data_len; /* * Copy data to head part of netbuf or head of allocated buffer. * if buffer is new allocated, the last buffer should be copied also. * It assume last fragment is internal buffer of netbuf * sometime total length of fragments larger than nbytes */ pData = (unsigned char *)pSendContext + sizeof(struct HIFSendContext); for (i = 0; i < (pSendContext->bNewAlloc ? frag_count : frag_count - 1); i ++){ int frag_len = adf_nbuf_get_frag_len(buf, i); unsigned char *frag_addr = adf_nbuf_get_frag_vaddr(buf, i); if (frag_len > nbytes){ frag_len = nbytes; } memcpy(pData, frag_addr, frag_len); pData += frag_len; nbytes -= frag_len; if (nbytes <= 0) { break; } } /* Reset pData pointer and send out */ pData = (unsigned char *)pSendContext + sizeof(struct HIFSendContext); status = HIFReadWrite(pDev->HIFDevice, pDev->MailBoxInfo.MboxProp[mboxIndex].ExtendedAddress, (char*) pData, paddedLength, request, (void*)pSendContext); if (status == A_PENDING){ /* * it will return A_PENDING in native HIF implementation, * which should be treated as successful result here. */ status = A_OK; } /* release buffer or move back data pointer when failed */ if (status != A_OK){ if (pSendContext->bNewAlloc){ adf_os_mem_free(pSendContext); } else { adf_nbuf_pull_head(buf, head_data_len); } } return status; }