--- /dev/null
+/*
+ * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted (subject to the limitations in the
+ * disclaimer below) provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Qualcomm Atheros nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+ * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+ * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * @File: dma_engine.c
+ *
+ * @Abstract: DMA engine for Magpie
+ *
+ * @Notes:
+ */
+#include "sys_cfg.h"
+#include "dt_defs.h"
+#include "reg_defs.h"
+#include "desc.h"
+
+#include <osapi.h>
+//#include <HIF_api.h>
+#include <dma_engine_api.h>
+#include <Magpie_api.h>
+#include <vdesc_api.h>
+#include <adf_os_mem.h>
+#include <adf_os_io.h>
+
+//#include "HIF_usb.h"
+
+//HIF_USB_CONTEXT g_hifUSBCtx;
+
+#define VDESC_TO_USBDESC(vdesc) (struct zsDmaDesc *)((vdesc)->hw_desc_buf)
+
+static void relinkUSBDescToVdesc(VBUF *buf, struct zsDmaDesc* desc);
+static void config_queue(struct zsDmaQueue *q, VDESC *desc_list);
+
+#if ENABLE_SW_SWAP_DATA_MODE
+static void swapData(struct zsDmaDesc* usbDesc);
+#endif
+
+static void init_usb_desc(struct zsDmaDesc *usbDesc)
+{
+ usbDesc->status = ZM_OWN_BITS_SW;
+ usbDesc->ctrl = 0;
+ usbDesc->dataSize = 0;
+ usbDesc->totalLen = 0;
+ usbDesc->lastAddr = 0;
+ usbDesc->dataAddr = 0;
+ usbDesc->nextAddr = 0;
+}
+
+void _DMAengine_init()
+{
+
+}
+
+void _DMAengine_init_rx_queue(struct zsDmaQueue *q)
+{
+ VDESC *desc;
+ struct zsDmaDesc *usbDesc;
+
+ desc = VDESC_alloc_vdesc();
+ if ( desc != NULL ) {
+ usbDesc = VDESC_TO_USBDESC(desc);
+ init_usb_desc(usbDesc);
+
+ q->head = q->terminator = usbDesc;
+ }
+}
+
+void _DMAengine_init_tx_queue(struct zsTxDmaQueue *q)
+{
+ _DMAengine_init_rx_queue((struct zsDmaQueue *)q);
+ q->xmited_buf_head = NULL;
+ q->xmited_buf_tail = NULL;
+}
+
+#if ENABLE_SW_SWAP_DATA_MODE
+
+static void swapData(struct zsDmaDesc* usbDesc)
+{
+ int len = (usbDesc->dataSize & 0xfffffffc) >> 2;
+ int i;
+ A_UINT32 *dataAddr = (A_UINT32 *)usbDesc->dataAddr;
+ A_UINT32 data;
+
+ if ( ( usbDesc->dataSize & 3 ) != 0 ) {
+ len += 1;
+ }
+
+ for ( i = 0; i < len; i++ ) {
+ data = dataAddr[i];
+
+ dataAddr[i] = __bswap32(data);
+ }
+}
+
+#endif
+
+void _DMAengine_return_recv_buf(struct zsDmaQueue *q, VBUF *buf)
+{
+ /* Re-link the VDESC of buf into USB descriptor list & queue the descriptors
+ into downQ
+ */
+ config_queue(q, buf->desc_list);
+ VBUF_free_vbuf(buf);
+}
+
+static void config_queue(struct zsDmaQueue *q, VDESC *desc_list)
+{
+ VDESC *theDesc;
+ struct zsDmaDesc *usbDesc;
+ struct zsDmaDesc* prevUsbDesc = NULL;
+ struct zsDmaDesc* headUsbDesc;
+
+ theDesc = desc_list;
+ while ( theDesc != NULL ) {
+ usbDesc = (struct zsDmaDesc *)VDESC_get_hw_desc(theDesc);
+ init_usb_desc(usbDesc);
+
+ theDesc->data_offset = 0; //RAY 0723
+ usbDesc->dataAddr = (volatile u32_t)(theDesc->buf_addr + theDesc->data_offset);
+ usbDesc->dataSize = theDesc->buf_size;
+
+ if ( prevUsbDesc == NULL ) {
+ headUsbDesc = usbDesc;
+ prevUsbDesc = usbDesc;
+ } else {
+ prevUsbDesc->nextAddr = usbDesc;
+ prevUsbDesc = usbDesc;
+ }
+
+ theDesc = theDesc->next_desc;
+ }
+
+ headUsbDesc->lastAddr = prevUsbDesc;
+ DMA_Engine_reclaim_packet(q, headUsbDesc);
+
+ return;
+}
+
+//#define MAX_TX_BUF_SIZE ZM_BLOCK_SIZE
+//#define MAX_TX_BUF_SIZE 1600
+
+void _DMAengine_config_rx_queue(struct zsDmaQueue *q, int num_desc, int buf_size)
+{
+ int i;
+ VDESC *desc;
+ VDESC *head = NULL;
+
+ for(i=0; i < num_desc; i++)
+ {
+ desc = VDESC_alloc_vdesc();
+
+ adf_os_assert(desc != NULL);
+
+ desc->buf_addr = (A_UINT8 *)adf_os_mem_alloc(buf_size);
+ desc->buf_size = buf_size;
+ desc->next_desc = NULL;
+ desc->data_offset = 0;
+ desc->data_size = 0;
+ desc->control = 0;
+
+ if ( head == NULL )
+ {
+ head = desc;
+ }
+ else
+ {
+ desc->next_desc = head;
+ head = desc;
+ }
+ }
+
+ config_queue(q, head);
+}
+
+void _DMAengine_xmit_buf(struct zsTxDmaQueue *q, VBUF *buf)
+{
+ VDESC *currVdesc;
+ struct zsDmaDesc* usbDesc;
+ struct zsDmaDesc* prevUsbDesc = NULL;
+ struct zsDmaDesc* headUsbDesc;
+
+ /* Re-link the VDESC of buf into USB descriptor list & queue the descriptors
+ into upQ
+ */
+ currVdesc = (VDESC *)buf->desc_list;
+ while(currVdesc != NULL) {
+
+ usbDesc = (struct zsDmaDesc *)currVdesc->hw_desc_buf;
+
+ init_usb_desc(usbDesc);
+ usbDesc->dataSize = currVdesc->data_size;
+ usbDesc->dataAddr = (volatile u32_t)(currVdesc->buf_addr + currVdesc->data_offset);
+ usbDesc->ctrl = 0;
+ usbDesc->status = 0;
+
+#if ENABLE_SW_SWAP_DATA_MODE && ENABLE_SWAP_DATA_MODE == 0
+ swapData(usbDesc);
+#endif
+
+ if ( prevUsbDesc == NULL ) {
+ headUsbDesc = usbDesc;
+
+ usbDesc->ctrl |= ZM_FS_BIT;
+
+ // how to get the total len???
+ usbDesc->totalLen = buf->buf_length;
+ prevUsbDesc = usbDesc;
+ }
+ else {
+ prevUsbDesc->nextAddr = usbDesc;
+ prevUsbDesc = usbDesc;
+ }
+
+ currVdesc = currVdesc->next_desc;
+ }
+
+ usbDesc->ctrl |= ZM_LS_BIT;
+ headUsbDesc->lastAddr = usbDesc;
+
+ if ( q->xmited_buf_head == NULL && q->xmited_buf_tail == NULL ) {
+ q->xmited_buf_head = buf;
+ q->xmited_buf_tail = buf;
+ q->xmited_buf_head->next_buf = q->xmited_buf_tail;
+ }
+ else {
+ q->xmited_buf_tail->next_buf = buf;
+ q->xmited_buf_tail = buf;
+ }
+
+ DMA_Engine_put_packet((struct zsDmaQueue *)q, headUsbDesc);
+}
+
+void _DMAengine_flush_xmit(struct zsDmaQueue *q)
+{
+}
+
+int _DMAengine_has_compl_packets(struct zsDmaQueue *q)
+{
+ int has_compl_pkts = 0;
+
+ if ((q->head != q->terminator) &&
+ ((q->head->status & ZM_OWN_BITS_MASK) != ZM_OWN_BITS_HW)) {
+ has_compl_pkts = 1;
+ }
+
+ return has_compl_pkts;
+}
+
+VBUF* _DMAengine_reap_recv_buf(struct zsDmaQueue *q)
+{
+ struct zsDmaDesc* desc;
+ VBUF *buf;
+ //int i;
+ //u8_t *tbuf = (u8_t *)desc->dataAddr;
+
+ desc = DMA_Engine_get_packet(q);
+
+ if(!desc)
+ return NULL;
+
+#if ENABLE_SW_SWAP_DATA_MODE && ENABLE_SWAP_DATA_MODE == 0
+ swapData(desc);
+#endif
+
+ buf = VBUF_alloc_vbuf();
+ adf_os_assert(buf != NULL);
+
+ relinkUSBDescToVdesc(buf, desc);
+ return buf;
+}
+
+VBUF* _DMAengine_reap_xmited_buf(struct zsTxDmaQueue *q)
+{
+ struct zsDmaDesc* desc;
+ VBUF *sentBuf;
+
+ desc = DMA_Engine_get_packet((struct zsDmaQueue *)q);
+
+ if(!desc)
+ return NULL;
+
+ // assert g_hifUSBCtx.upVbufQ.head is not null
+ // assert g_hifUSBCtx.upVbufQ.tail is not null
+ sentBuf = q->xmited_buf_head;
+ if ( q->xmited_buf_head == q->xmited_buf_tail ) {
+ q->xmited_buf_head = NULL;
+ q->xmited_buf_tail = NULL;
+ } else {
+ q->xmited_buf_head = q->xmited_buf_head->next_buf;
+ }
+
+ sentBuf->next_buf = NULL;
+ relinkUSBDescToVdesc(sentBuf, desc);
+ return sentBuf;
+}
+
+void _DMAengine_desc_dump(struct zsDmaQueue *q)
+{
+ u32_t i=0;
+ struct zsDmaDesc* tmpDesc;
+
+ tmpDesc = q->head;
+
+ do {
+ if( tmpDesc == q->terminator )
+ {
+#ifdef DESC_DUMP_BOTH_DESCnDATA
+ A_PRINTF("0x%08x(0x%08x,T)]", tmpDesc, tmpDesc->dataAddr);
+#else
+ A_PRINTF("0x%08x(T)]", tmpDesc);
+#endif
+ break;
+ }
+ else
+#ifdef DESC_DUMP_BOTH_DESCnDATA
+ A_PRINTF("0x%08x(0x%08x,%c)->", tmpDesc, tmpDesc->dataAddr, (tmpDesc->status&ZM_OWN_BITS_HW)?'H':'S');
+#else
+ A_PRINTF("0x%08x(%c)->", tmpDesc, (tmpDesc->status&ZM_OWN_BITS_HW)?'H':'S');
+#endif
+
+ if( (++i%5)==0 )
+ {
+ A_PRINTF("\n\r ");
+ }
+
+ tmpDesc = tmpDesc->nextAddr;
+ }while(1);
+ A_PRINTF("\n\r");
+}
+
+/* the exported entry point into this module. All apis are accessed through
+ * function pointers */
+void dma_engine_module_install(struct dma_engine_api *apis)
+{
+ /* hook in APIs */
+ apis->_init = _DMAengine_init;
+ apis->_config_rx_queue = _DMAengine_config_rx_queue;
+ apis->_xmit_buf = _DMAengine_xmit_buf;
+ apis->_flush_xmit = _DMAengine_flush_xmit;
+ apis->_reap_recv_buf = _DMAengine_reap_recv_buf;
+ apis->_return_recv_buf = _DMAengine_return_recv_buf;
+ apis->_reap_xmited_buf = _DMAengine_reap_xmited_buf;
+ apis->_swap_data = swapData;
+ apis->_has_compl_packets = _DMAengine_has_compl_packets;
+ apis->_init_rx_queue = _DMAengine_init_rx_queue;
+ apis->_init_tx_queue = _DMAengine_init_tx_queue;
+ apis->_desc_dump = _DMAengine_desc_dump;
+ apis->_get_packet = zfDmaGetPacket;
+ apis->_reclaim_packet = zfDmaReclaimPacket;
+ apis->_put_packet = zfDmaPutPacket;
+
+ /* save ptr to the ptr to the context for external code to inspect/modify internal module state */
+ //apis->pReserved = &g_pMboxHWContext;
+}
+
+static void relinkUSBDescToVdesc(VBUF *buf, struct zsDmaDesc* desc)
+{
+ VDESC *vdesc;
+ VDESC *prevVdesc = NULL;
+ struct zsDmaDesc *currDesc = desc;
+
+ vdesc = VDESC_HW_TO_VDESC(currDesc);
+ buf->desc_list = vdesc;
+ buf->buf_length = currDesc->totalLen;
+
+ while(currDesc != NULL) {
+ vdesc->data_size = currDesc->dataSize;
+ //vdesc->data_offset = 0; // TODO: bad!!
+
+ if ( prevVdesc == NULL ) {
+ prevVdesc = vdesc;
+ } else {
+ prevVdesc->next_desc = vdesc;
+ prevVdesc = vdesc;
+ }
+
+ if ( currDesc->ctrl & ZM_LS_BIT ) {
+ vdesc->next_desc = NULL;
+ currDesc = NULL;
+ break;
+ } else {
+ currDesc = currDesc->nextAddr;
+ vdesc = VDESC_HW_TO_VDESC(currDesc);
+ }
+ }
+}