blob: 053bd851b6a210181631dbe15582fe6f2ccf9731 [file] [log] [blame]
/*
* Copyright (c) 2013 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <adf_nbuf.h>
#include <adf_os_mem.h>
#include <adf_os_dma.h>
#include "hif_pcie_dma.h"
/**************************** Globals ****************************/
a_status_t
pci_dma_recv_refill(adf_os_device_t osdev, zdma_swdesc_t *swdesc,
a_uint32_t size)
{
adf_nbuf_t buf;
buf = adf_nbuf_alloc(osdev, size, 0, PCI_NBUF_ALIGNMENT);
if (!buf)
adf_os_assert(0);
pci_dma_link_buf(osdev, swdesc, buf);
pci_zdma_mark_rdy(swdesc, (ZM_FS_BIT | ZM_LS_BIT));
return A_STATUS_OK;
}
a_status_t
pci_dma_recv_init(adf_os_device_t osdev, pci_dma_softc_t *dma_q,
adf_nbuf_t buf, a_uint32_t pos)
{
zdma_swdesc_t *swdesc;
swdesc = &dma_q->sw_ring[pos];
pci_dma_link_buf(osdev, swdesc, buf);
pci_zdma_mark_rdy(swdesc, (ZM_FS_BIT | ZM_LS_BIT));
return A_STATUS_OK;
}
/**
* @brief Initialize the H/W ring
* Note: This joins all the H/W descriptor together
*
* @param swdesc
* @param num_desc
*/
static void
pci_dma_init_ring(zdma_swdesc_t *swdesc , a_uint32_t num_desc)
{
a_uint32_t i = 0, j = 0;
for (i = 0; i < num_desc; i++) {
j = (i + 1) % num_desc;
swdesc[i].descp->nextAddr = (struct zsDmaDesc *)swdesc[j].hwaddr;
}
}
/**
* @brief Allocate & initialize the S/W descriptor & H/W
* Descriptor
*
* @param osdev
* @param sc
* @param num_desc
*/
static void
pci_dma_alloc_swdesc(adf_os_device_t osdev, pci_dma_softc_t *sc,
a_uint32_t num_desc)
{
a_uint32_t size_sw, size_hw, i = 0;
adf_os_dma_addr_t paddr;
zdma_swdesc_t *swdesc;
struct zsDmaDesc *hwdesc;
// struct zsDmaDesc *tmpdesc;
size_sw = sizeof(struct zdma_swdesc) * num_desc;
size_hw = sizeof(struct zsDmaDesc) * num_desc;
sc->sw_ring = adf_os_mem_alloc(osdev, size_sw);
adf_os_assert(sc->sw_ring);
sc->hw_ring = adf_os_dmamem_alloc(osdev, size_hw, PCI_DMA_MAPPING,
&sc->dmap);
// printk("sc->hw_ring %x paddr is %x \n",(unsigned int )sc->hw_ring, (unsigned int) sc->dmap->seg[0].daddr);
adf_os_assert(sc->hw_ring);
swdesc = sc->sw_ring;
hwdesc = sc->hw_ring;
paddr = adf_os_dmamem_map2addr(sc->dmap);
// printk("sc->hw_ring paddr %x \n",paddr );
for (i = 0; i < num_desc; i++) {
swdesc[i].descp = &hwdesc[i];
swdesc[i].hwaddr = paddr;
paddr = (adf_os_dma_addr_t)((struct zsDmaDesc *)paddr + 1);
}
sc->num_desc = num_desc;
pci_dma_init_ring(swdesc, num_desc);
}
/**
* @brief Free the S/W & H/W descriptor ring
*
* @param osdev
* @param dma_q
* @param num_desc
*/
static void
pci_dma_free_swdesc(adf_os_device_t osdev, pci_dma_softc_t *dma_q,
a_uint32_t num_desc)
{
a_uint32_t size_hw;
size_hw = sizeof(struct zsDmaDesc) * num_desc;
adf_os_dmamem_free(osdev, size_hw, PCI_DMA_MAPPING, dma_q->hw_ring,
dma_q->dmap);
adf_os_mem_free(dma_q->sw_ring);
}
/**
* @brief Mark the H/W descriptor not ready
*
* @param swdesc
* @param ctrl
*/
static inline void
pci_zdma_mark_notrdy(zdma_swdesc_t *swdesc)
{
struct zsDmaDesc *hwdesc = swdesc->descp;
hwdesc->status = ZM_OWN_BITS_SW;
}
/**
* @brief Initialize the RX ring
*
* @param osdev
* @param dma_q
* @param num_desc
* @param buf_size
*/
void
pci_dma_init_rx(adf_os_device_t osdev, pci_dma_softc_t *dma_q,
a_uint32_t num_desc, adf_os_size_t buf_size)
{
a_uint32_t i;
zdma_swdesc_t *swdesc;
adf_nbuf_t buf;
pci_dma_alloc_swdesc(osdev, dma_q, num_desc);
swdesc = dma_q->sw_ring;
for (i = 0; i < num_desc ; i++) {
adf_nbuf_dmamap_create(osdev, &swdesc[i].nbuf_map);
buf = adf_nbuf_alloc(osdev, buf_size, 0, PCI_NBUF_ALIGNMENT);
adf_os_assert(buf);
pci_dma_recv_init(osdev, dma_q, buf, i);
}
swdesc = &dma_q->sw_ring[dma_q->tail];
}
/**
* @brief Free the RX Ring ( S/W & H/W), dequeue all the SKB's
* and free them starting from the head
* NOTE: The NULL terminator doesn't have a SKB
*
* @param osdev
* @param dma_q
*/
void
pci_dma_deinit_rx(adf_os_device_t osdev, pci_dma_softc_t *dma_q)
{
a_uint32_t i, num_desc;
zdma_swdesc_t *swdesc;
adf_nbuf_t buf;
num_desc = dma_q->num_desc;
swdesc = dma_q->sw_ring;
for (i = 0; i < num_desc; i++, swdesc++) {
pci_zdma_mark_notrdy(swdesc);
adf_nbuf_unmap(osdev, swdesc->nbuf_map, ADF_OS_DMA_TO_DEVICE);
buf = pci_dma_unlink_buf(osdev, swdesc);
adf_os_assert(buf);
adf_nbuf_free(buf);
adf_nbuf_dmamap_destroy(osdev, swdesc->nbuf_map);
}
pci_dma_free_swdesc(osdev, dma_q, num_desc);
}
/**
* @brief Initialize the TX ring
*
* @param osdev
* @param dma_q
* @param num_desc
*/
void
pci_dma_init_tx(adf_os_device_t osdev, pci_dma_softc_t *dma_q,
a_uint32_t num_desc)
{
zdma_swdesc_t *swdesc;
a_uint32_t i = 0;
pci_dma_alloc_swdesc(osdev, dma_q, num_desc);
swdesc = dma_q->sw_ring;
for (i = 0; i < num_desc; i++)
adf_nbuf_dmamap_create(osdev, &swdesc[i].nbuf_map);
swdesc = &dma_q->sw_ring[dma_q->tail];
}
/**
* @brief Free the TX Ring
*
* @param osdev
* @param dma_q
*/
void
pci_dma_deinit_tx(adf_os_device_t osdev, pci_dma_softc_t *dma_q)
{
a_uint32_t i, num_desc;
zdma_swdesc_t *swdesc;
swdesc = dma_q->sw_ring;
num_desc = dma_q->num_desc;
for (i = 0; i < num_desc; i++, swdesc++)
adf_nbuf_dmamap_destroy(osdev, swdesc->nbuf_map);
pci_dma_free_swdesc(osdev, dma_q, num_desc);
}
/* pci_dma_softc_t *dma_q0 = NULL; */
/* void */
/* pci_prn_uncached(zdma_swdesc_t *swdesc) */
/* { */
/* adf_os_dma_addr_t hwaddr = swdesc->hwaddr; */
/* */
/* printk("hwu = %#x ",hwaddr); */
/* printk("swu = %#x ",swdesc->descp); */
/* */
/* hwaddr &= ~0x80000000; */
/* hwaddr |= 0xa0000000; */
/* */
/* printk("hwc = %#x ",hwaddr); */
/* printk("s_addr = %#x ",swdesc->buf_addr); */
/* printk("h_addr = %#x ", ((struct zsDmaDesc *)hwaddr)->dataAddr); */
/* printk("n_addr = %#x ", ((struct zsDmaDesc *)hwaddr)->nextAddr); */
/* printk("l_addr = %#x\n", ((struct zsDmaDesc *)hwaddr)->lastAddr); */
/* } */
/* */
/* void */
/* pci_prn_uncached0(pci_dma_softc_t *dma_q) */
/* { */
/* adf_os_dma_addr_t hwaddr = dma_q->sw_ring[0].hwaddr; */
/* */
/* printk("hwu = %#x ",hwaddr); */
/* */
/* hwaddr &= ~0x80000000; */
/* hwaddr |= 0xa0000000; */
/* */
/* printk("hwc = %#x ",hwaddr); */
/* printk("s_addr = %#x ",dma_q->sw_ring[0].buf_addr); */
/* printk("h_addr = %#x ", ((struct zsDmaDesc *)hwaddr)->dataAddr); */
/* printk("n_addr = %#x ", ((struct zsDmaDesc *)hwaddr)->nextAddr); */
/* printk("l_addr = %#x\n", ((struct zsDmaDesc *)hwaddr)->lastAddr); */
/* } */
/* */