--- /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.
+ */
+#include <hif_api.h>
+#include <Magpie_api.h>
+#include <cmnos_api.h>
+
+#include <dma_lib.h>
+#include "hif_pci.h"
+
+
+/**************************Constants******************************/
+
+/*************************Data types*******************************/
+enum pci_regs{
+ MAG_REG_AHB_RESET = 0x00050010,
+ MAG_REG_AHB_ARB = 0x00050018
+};
+
+#define PCI_AHB_ARB_ENB (1 << 3)
+#define PCI_AHB_RESET_DMA (1 << 13)
+#define PCI_AHB_RESET_DMA_HST_RAW (1 << 14)
+#define PCI_AHB_RESET_DMA_HST (1 << 15)
+
+/*********************************softC************************/
+typedef struct __pci_softc{
+ HIF_CALLBACK sw;
+}__pci_softc_t;
+
+
+#define ret_pkt sw.send_buf_done
+#define indicate_pkt sw.recv_buf
+#define htc_ctx sw.context
+/*********************************DEFINES**********************************/
+#define hdl_to_softc(_hdl) (__pci_softc_t *)(_hdl)
+
+#define PCI_ENG_NUM(_eng) HIF_PCI_PIPE_##_eng
+
+#define PCI_INIT_PIPE { \
+ PCI_ENG_NUM(RX0), \
+ PCI_ENG_NUM(RX1), \
+ PCI_ENG_NUM(RX2), \
+ PCI_ENG_NUM(RX3), \
+ PCI_ENG_NUM(TX0), \
+ PCI_ENG_NUM(TX1), \
+}
+
+#define rx_pipe0 DMA_ENGINE_RX0
+#define rx_pipe1 DMA_ENGINE_RX1
+#define tx_pipe0 DMA_ENGINE_TX0
+#define tx_pipe1 DMA_ENGINE_TX1
+#define dbg_pci 0
+#define dbg_pci_loopback 0
+
+#define PCI_DBG_MODE 0
+
+void __pci_cfg_pipe(hif_handle_t hdl, int pipe, int num_desc);
+int __pci_get_max_msg_len(hif_handle_t hdl, int pipe);
+void __pci_return_recv(hif_handle_t hdl, int pipe, VBUF *buf);
+void __pci_reset(void);
+void __pci_enable(void);
+
+
+/***********************************Globals********************************/
+/**
+ * @brief Engines are fixed
+ */
+__pci_softc_t pci_sc = {0};
+
+
+/**************************************APIs********************************/
+
+A_UINT32
+__pci_reg_read(A_UINT32 addr)
+{
+ return *((volatile A_UINT32 *)addr);
+}
+
+void
+__pci_reg_write(A_UINT32 addr, A_UINT32 val)
+{
+ *((volatile A_UINT32 *)addr) = val;
+}
+
+A_UINT8
+__pci_get_pipe(dma_engine_t eng)
+{
+ switch (eng) {
+ case DMA_ENGINE_RX0:
+ return HIF_PCI_PIPE_RX0;
+ case DMA_ENGINE_RX1:
+ return HIF_PCI_PIPE_RX1;
+ case DMA_ENGINE_RX2:
+ return HIF_PCI_PIPE_RX2;
+ case DMA_ENGINE_RX3:
+ return HIF_PCI_PIPE_RX3;
+ case DMA_ENGINE_TX0:
+ return HIF_PCI_PIPE_TX0;
+ case DMA_ENGINE_TX1:
+ return HIF_PCI_PIPE_TX1;
+ default:
+ adf_os_assert(0);
+ }
+}
+
+dma_engine_t
+__pci_get_tx_eng(hif_pci_pipe_tx_t pipe)
+{
+ switch (pipe) {
+ case HIF_PCI_PIPE_TX0:
+ return DMA_ENGINE_TX0;
+
+ case HIF_PCI_PIPE_TX1:
+ return DMA_ENGINE_TX1;
+
+ default:
+ return DMA_ENGINE_MAX;
+ }
+}
+dma_engine_t
+__pci_get_rx_eng(hif_pci_pipe_rx_t pipe)
+{
+ switch (pipe) {
+ case HIF_PCI_PIPE_RX0:
+ return DMA_ENGINE_RX0;
+
+ case HIF_PCI_PIPE_RX1:
+ return DMA_ENGINE_RX1;
+
+ case HIF_PCI_PIPE_RX2:
+ return DMA_ENGINE_RX2;
+
+ case HIF_PCI_PIPE_RX3:
+ return DMA_ENGINE_RX3;
+
+ default:
+ return DMA_ENGINE_MAX;
+ }
+}
+
+
+
+void
+__pci_enable(void)
+{
+ A_UINT32 r_data;
+ /**
+ * Grant access to the internal memory for PCI DMA
+ */
+
+ r_data = __pci_reg_read(MAG_REG_AHB_ARB);
+ r_data |= PCI_AHB_ARB_ENB;
+ __pci_reg_write(MAG_REG_AHB_ARB, r_data);
+}
+
+/**
+ * @brief PCI reset
+ * XXX: Move this to RAM
+ */
+void
+__pci_reset(void)
+{
+ volatile A_UINT32 r_data;
+
+ /**
+ * Poll until the Host has reset
+ */
+ A_PRINTF("Waiting for host reset..");
+ for (;;) {
+ r_data = __pci_reg_read(MAG_REG_AHB_RESET);
+
+ if ( r_data & PCI_AHB_RESET_DMA_HST_RAW)
+ break;
+ }
+ A_PRINTF("received.\n");
+
+ /**
+ * Pull the AHB out of reset
+ */
+
+ r_data = __pci_reg_read(MAG_REG_AHB_RESET);
+ r_data &= ~PCI_AHB_RESET_DMA;
+ __pci_reg_write(MAG_REG_AHB_RESET, r_data);
+
+ A_DELAY_USECS(10);
+
+ /**
+ * Put the AHB into reset
+ */
+
+ r_data = __pci_reg_read(MAG_REG_AHB_RESET);
+ r_data |= PCI_AHB_RESET_DMA;
+ __pci_reg_write(MAG_REG_AHB_RESET, r_data);
+
+ A_DELAY_USECS(10);
+
+ /**
+ * Pull the AHB out of reset
+ */
+
+ r_data = __pci_reg_read(MAG_REG_AHB_RESET);
+ r_data &= ~PCI_AHB_RESET_DMA;
+ __pci_reg_write(MAG_REG_AHB_RESET, r_data);
+
+ A_DELAY_USECS(10);
+}
+/**
+ * @brief Boot init
+ */
+void
+__pci_boot_init(void)
+{
+ __pci_reset();
+ __pci_enable();
+
+ dma_lib_tx_init(DMA_ENGINE_TX0, DMA_IF_PCI);
+ dma_lib_rx_init(DMA_ENGINE_RX0, DMA_IF_PCI);
+
+ dma_lib_rx_config(DMA_ENGINE_RX0, PCI_MAX_BOOT_DESC,
+ PCI_MAX_DATA_PKT_LEN);
+
+}
+/**
+ * @brief
+ *
+ * @param pConfig
+ *
+ * @return hif_handle_t
+ */
+hif_handle_t
+__pci_init(HIF_CONFIG *pConfig)
+{
+ __pci_reset();
+ __pci_enable();
+
+ /**
+ * Initializing the other TX engines
+ */
+ dma_lib_tx_init(DMA_ENGINE_TX0, DMA_IF_PCI);
+ dma_lib_tx_init(DMA_ENGINE_TX1, DMA_IF_PCI);
+
+ /**
+ * Initializing the other RX engines
+ */
+ dma_lib_rx_init(DMA_ENGINE_RX0, DMA_IF_PCI);
+ dma_lib_rx_init(DMA_ENGINE_RX1, DMA_IF_PCI);
+ dma_lib_rx_init(DMA_ENGINE_RX2, DMA_IF_PCI);
+ dma_lib_rx_init(DMA_ENGINE_RX3, DMA_IF_PCI);
+
+ return &pci_sc;
+}
+/**
+ * @brief Configure the receive pipe
+ *
+ * @param hdl
+ * @param pipe
+ * @param num_desc
+ */
+void
+__pci_cfg_pipe(hif_handle_t hdl, int pipe, int num_desc)
+{
+ dma_engine_t eng;
+ A_UINT16 desc_len;
+
+ eng = __pci_get_rx_eng(pipe);
+
+ if (eng == DMA_ENGINE_MAX) {
+ A_PRINTF("Bad Engine number\n");
+ return;
+ }
+
+ desc_len = __pci_get_max_msg_len(hdl, pipe);
+
+ dma_lib_rx_config(eng, num_desc, desc_len);
+}
+/**
+ * @brief Start the interface
+ *
+ * @param hdl
+ */
+void
+__pci_start(hif_handle_t hdl)
+{
+ return;
+}
+/**
+ * @brief Register callback of thre HTC
+ *
+ * @param hdl
+ * @param sw
+ */
+void
+__pci_reg_callback(hif_handle_t hdl, HIF_CALLBACK *sw)
+{
+ __pci_softc_t *sc = &pci_sc;
+
+ sc->htc_ctx = sw->context;
+ sc->indicate_pkt = sw->recv_buf;
+ sc->ret_pkt = sw->send_buf_done;
+}
+
+/**
+ * @brief reap the transmit queue for trasnmitted packets
+ *
+ * @param sc
+ * @param eng_no
+ */
+void
+__pci_reap_xmitted(__pci_softc_t *sc, dma_engine_t eng_no)
+{
+ VBUF *vbuf = NULL;
+ A_UINT8 pipe;
+
+ pipe = __pci_get_pipe(eng_no);
+
+ vbuf = dma_lib_reap_xmitted(eng_no);
+
+ if ( vbuf )
+ sc->ret_pkt(vbuf, sc->htc_ctx);
+ else
+ A_PRINTF("Empty RX Reap\n");
+
+
+}
+
+/**
+ * @brief reap the receive queue for vbuf's on the specified
+ * engine number
+ *
+ * @param sc
+ * @param eng_no
+ */
+void
+__pci_reap_recv(__pci_softc_t *sc, dma_engine_t eng_no)
+{
+ VBUF *vbuf = NULL;
+
+ vbuf = dma_lib_reap_recv(eng_no);
+
+ if(vbuf)
+ sc->indicate_pkt(NULL, vbuf, sc->htc_ctx);
+ else
+ A_PRINTF("Empty TX Reap \n");
+}
+/**
+ * @brief The interrupt handler
+ *
+ * @param hdl
+ */
+void
+__pci_isr_handler(hif_handle_t hdl)
+{
+ __pci_softc_t *sc = &pci_sc;
+ A_UINT16 more = 0;
+
+ do {
+
+ more = 0;
+
+ if( dma_lib_xmit_done(DMA_ENGINE_TX1) ) {
+ __pci_reap_xmitted(sc,DMA_ENGINE_TX1);
+ more = 1;
+ }
+ if( dma_lib_recv_pkt(DMA_ENGINE_RX3) ) {
+ __pci_reap_recv(sc, DMA_ENGINE_RX3);
+ more = 1;
+ }
+
+ } while( more );
+
+ do {
+
+ more = 0;
+
+ if( dma_lib_xmit_done(DMA_ENGINE_TX1) ) {
+ __pci_reap_xmitted(sc,DMA_ENGINE_TX1);
+ more = 1;
+ }
+ if( dma_lib_recv_pkt(DMA_ENGINE_RX2) ) {
+ __pci_reap_recv(sc, DMA_ENGINE_RX2);
+ more = 1;
+ }
+
+ } while( more );
+
+ do {
+
+ more = 0;
+
+ if( dma_lib_xmit_done(DMA_ENGINE_TX1) ) {
+ __pci_reap_xmitted(sc,DMA_ENGINE_TX1);
+ more = 1;
+ }
+ if( dma_lib_recv_pkt(DMA_ENGINE_RX1) ) {
+ __pci_reap_recv(sc, DMA_ENGINE_RX1);
+ more = 1;
+ }
+
+ } while( more );
+
+ do {
+
+ more = 0;
+
+ if( dma_lib_xmit_done(DMA_ENGINE_TX0) ) {
+ __pci_reap_xmitted(sc,DMA_ENGINE_TX0);
+ more = 1;
+ }
+
+ if( dma_lib_recv_pkt(DMA_ENGINE_RX0) ) {
+ __pci_reap_recv(sc, DMA_ENGINE_RX0);
+ more = 1;
+ }
+
+ } while( more );
+
+}
+/**
+ * @brief transmit the vbuf from the specified pipe
+ *
+ * @param hdl
+ * @param pipe
+ * @param buf
+ *
+ * @return int
+ */
+int
+__pci_xmit_buf(hif_handle_t hdl, int pipe, VBUF *vbuf)
+{
+ dma_engine_t eng;
+
+ eng = __pci_get_tx_eng(pipe);
+
+ if (eng == DMA_ENGINE_MAX) {
+ A_PRINTF("Invalid Pipe number\n");
+ return -1;
+ }
+
+ return dma_lib_hard_xmit(eng, vbuf);
+}
+/**
+ * @brief Submit the receive vbuf into the receive queue
+ *
+ * @param handle
+ * @param pipe
+ * @param buf
+ */
+void
+__pci_return_recv(hif_handle_t hdl, int pipe, VBUF *buf)
+{
+ dma_engine_t eng;
+
+ eng = __pci_get_rx_eng(pipe);
+
+ if (eng == DMA_ENGINE_MAX)
+ return;
+
+ dma_lib_return_recv(eng, buf);
+}
+/**
+ * @brief Is this pipe number supported
+ *
+ * @param handle
+ * @param pipe
+ *
+ * @return int
+ */
+int
+__pci_is_pipe_supported(hif_handle_t hdl, int pipe)
+{
+ if (pipe >= 0 && pipe <= 4)
+ return 1;
+ else
+ return 0;
+}
+/**
+ * @brief maximum message length this pipe can support
+ *
+ * @param handle
+ * @param pipe
+ *
+ * @return int
+ */
+int
+__pci_get_max_msg_len(hif_handle_t hdl, int pipe)
+{
+ if( pipe == HIF_PCI_PIPE_TX0 || pipe == HIF_PCI_PIPE_RX0)
+ return PCI_MAX_CMD_PKT_LEN;
+
+ return PCI_MAX_DATA_PKT_LEN;
+}
+/**
+ * @brief return the header room required by this HIF
+ *
+ * @param hdl
+ *
+ * @return int
+ */
+int
+__pci_get_reserved_headroom(hif_handle_t hdl)
+{
+ return 0;
+}
+/**
+ * @brief Device shutdown, HIF reset required
+ *
+ * @param hdl
+ */
+void
+__pci_shutdown(hif_handle_t hdl)
+{
+ return;
+}
+
+void
+__pci_get_def_pipe(hif_handle_t handle, A_UINT8 *pipe_rx, A_UINT8 *pipe_tx)
+{
+ *pipe_rx = HIF_PCI_PIPE_RX0;
+ *pipe_tx = HIF_PCI_PIPE_TX0;
+}
+/**
+ * @brief This install the API's of the HIF
+ *
+ * @param apis
+ */
+void
+hif_pci_module_install(struct hif_api *apis)
+{
+ /* hook in APIs */
+ apis->_init = __pci_init;
+ apis->_start = __pci_start;
+ apis->_config_pipe = __pci_cfg_pipe;
+ apis->_isr_handler = __pci_isr_handler;
+ apis->_send_buffer = __pci_xmit_buf;
+ apis->_return_recv_buf = __pci_return_recv;
+ apis->_is_pipe_supported = __pci_is_pipe_supported;
+ apis->_get_max_msg_len = __pci_get_max_msg_len;
+ apis->_register_callback = __pci_reg_callback;
+ apis->_shutdown = __pci_shutdown;
+ apis->_get_reserved_headroom = __pci_get_reserved_headroom;
+ apis->_get_default_pipe = __pci_get_def_pipe;
+}
+
+void
+cmnos_pci_module_install(struct pci_api *apis)
+{
+ apis->pci_boot_init = __pci_boot_init;
+}