| /* |
| * 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. |
| */ |
| |
| #ifndef __HIF_PCI_ZDMA_H |
| #define __HIF_PCI_ZDMA_H |
| |
| #include <adf_os_types.h> |
| //#include <adf_net.h> |
| |
| #define PCI_NBUF_ALIGNMENT 4 |
| /** |
| * Change this for the mapping 0 is streaming & 1 is coherent |
| */ |
| #define PCI_DMA_MAPPING 1 |
| |
| //#define ADF_BIG_ENDIAN_MACHINE 1 |
| |
| struct zsDmaDesc{ |
| #if defined (ADF_BIG_ENDIAN_MACHINE) |
| a_uint16_t ctrl; // Descriptor control |
| a_uint16_t status; // Descriptor status |
| a_uint16_t totalLen; // Total length |
| a_uint16_t dataSize; // Data size |
| #elif defined (ADF_LITTLE_ENDIAN_MACHINE) |
| a_uint16_t status; // Descriptor status |
| a_uint16_t ctrl; // Descriptor control |
| a_uint16_t dataSize; // Data size |
| a_uint16_t totalLen; // Total length |
| #else |
| #error "Endianess unknown, Fix me" |
| #endif |
| struct zsDmaDesc* lastAddr; // Last address of this chain |
| a_uint32_t dataAddr; // Data buffer address |
| struct zsDmaDesc* nextAddr; // Next TD address |
| a_uint8_t pad[12]; /* Pad for 32 byte Cache Alignment*/ |
| }; |
| |
| |
| typedef struct zdma_swdesc { |
| a_uint8_t *buf_addr; |
| a_uint32_t buf_size; |
| adf_nbuf_t nbuf; |
| adf_os_dma_map_t nbuf_map; |
| adf_os_dma_addr_t hwaddr; |
| struct zsDmaDesc *descp; |
| }zdma_swdesc_t; |
| |
| |
| typedef struct pci_dma_softc{ |
| adf_os_dma_map_t dmap; |
| zdma_swdesc_t *sw_ring; |
| struct zsDmaDesc *hw_ring; |
| /** |
| * For ring mgmt |
| */ |
| a_uint32_t tail;/* dequeue*/ |
| a_uint32_t head;/* enqueue*/ |
| a_uint32_t num_desc; |
| }pci_dma_softc_t; |
| |
| /* Status bits definitions */ |
| /* Own bits definitions */ |
| /* This is common between host and target */ |
| #define ZM_OWN_BITS_MASK 0x3 |
| #define ZM_OWN_BITS_SW 0x0 |
| #define ZM_OWN_BITS_HW 0x1 |
| #define ZM_OWN_BITS_SE 0x2 |
| /* Control bits definitions */ |
| /* First segament bit */ |
| #define ZM_LS_BIT 0x100 |
| /* Last segament bit */ |
| #define ZM_FS_BIT 0x200 |
| |
| |
| #define ring_incr(_val, _lim) ((_val) + 1)&((_lim) - 1) |
| #define ring_tx_incr(_val) ring_incr((_val), HIF_PCI_MAX_TX_DESC) |
| #define ring_rx_incr(_val) ring_incr((_val), HIF_PCI_MAX_RX_DESC) |
| |
| #define RING_MAX HIF_PCI_MAX_TX_DESC |
| |
| #define ring_full(head, tail) (((head + 1) % RING_MAX) == tail ) |
| |
| #define ring_empty(head, tail) (head == tail) |
| |
| #define ring_free(_h, _t, _num) \ |
| ((_h >= _t) ? (_num - _h + _t) : (_t - _h)) |
| |
| #define ring_tx_free(_h, _t) ring_free(_h, _t, HIF_PCI_MAX_TX_DESC) |
| |
| #define hw_desc_own(hwdesc_p) ((hwdesc_p)->status == ZM_OWN_BITS_HW) |
| #define hw_desc_len(hwdesc_p) (hwdesc_p)->totalLen |
| |
| /** |
| * |
| * @param dma_q |
| * |
| * @return a_uint32_t |
| */ |
| static inline a_uint32_t |
| pci_dma_tail_addr(pci_dma_softc_t *dma_q) |
| { |
| a_uint32_t tail = dma_q->tail; |
| zdma_swdesc_t *swdesc = &dma_q->sw_ring[tail]; |
| // printk("Tail value is %d\n", dma_q->tail); |
| // printk("Tail hwaddr returned for user is %x\n", swdesc->hwaddr); |
| |
| return (swdesc->hwaddr); |
| } |
| |
| /** |
| * |
| * @param dma_q |
| * |
| * @return a_uint32_t |
| */ |
| static inline zdma_swdesc_t * |
| pci_dma_tail_vaddr(pci_dma_softc_t *dma_q) |
| { |
| a_uint32_t tail = dma_q->tail; |
| zdma_swdesc_t *swdesc = &dma_q->sw_ring[tail]; |
| |
| return (swdesc); |
| } |
| |
| /** |
| * |
| * @param dma_q |
| * |
| * @return a_uint32_t |
| */ |
| static inline zdma_swdesc_t * |
| pci_dma_head_vaddr(pci_dma_softc_t *dma_q) |
| { |
| a_uint32_t head = dma_q->head; |
| zdma_swdesc_t *swdesc = &dma_q->sw_ring[head]; |
| |
| return (swdesc); |
| } |
| |
| /** |
| * @brief Mark the H/W descriptor ready |
| * |
| * @param swdesc |
| * @param ctrl |
| */ |
| static inline void |
| pci_zdma_mark_rdy(zdma_swdesc_t *swdesc, a_uint16_t ctrl) |
| { |
| struct zsDmaDesc *hwdesc = swdesc->descp; |
| |
| hwdesc->dataAddr = (a_uint32_t)swdesc->buf_addr; |
| hwdesc->dataSize = swdesc->buf_size; |
| hwdesc->lastAddr = (struct zsDmaDesc *)swdesc->hwaddr; |
| hwdesc->status = ZM_OWN_BITS_HW; |
| hwdesc->ctrl = ctrl; |
| } |
| |
| /** |
| * @brief Add SKB into the S/W descriptor |
| * |
| * @param osdev |
| * @param swdesc |
| * @param buf |
| */ |
| static inline void |
| pci_dma_link_buf(adf_os_device_t osdev, zdma_swdesc_t *swdesc, |
| adf_nbuf_t buf) |
| { |
| adf_os_dmamap_info_t sg = {0}; |
| |
| adf_nbuf_map(osdev, swdesc->nbuf_map, buf, ADF_OS_DMA_TO_DEVICE); |
| |
| /** |
| * XXX: for TX gather we need to use multiple swdesc |
| */ |
| adf_nbuf_dmamap_info(swdesc->nbuf_map, &sg); |
| adf_os_assert(sg.nsegs == 1); |
| |
| swdesc->nbuf = buf; |
| swdesc->buf_addr = (a_uint8_t *)sg.dma_segs[0].paddr; |
| swdesc->buf_size = sg.dma_segs[0].len; |
| } |
| |
| /** |
| * @brief remove the SKB references in S/W descriptor |
| * |
| * @param osdev |
| * @param swdesc |
| * |
| * @return adf_nbuf_t |
| */ |
| static inline adf_nbuf_t |
| pci_dma_unlink_buf(adf_os_device_t osdev, zdma_swdesc_t *swdesc) |
| { |
| adf_nbuf_t buf = swdesc->nbuf; |
| |
| adf_nbuf_unmap(osdev, swdesc->nbuf_map, ADF_OS_DMA_TO_DEVICE); |
| |
| swdesc->buf_addr = NULL; |
| swdesc->buf_size = 0; |
| swdesc->nbuf = ADF_NBUF_NULL; |
| |
| return buf; |
| } |
| |
| void pci_prn_uncached(zdma_swdesc_t *swdesc); |
| |
| 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); |
| |
| void pci_dma_deinit_rx(adf_os_device_t , pci_dma_softc_t *); |
| void pci_dma_init_tx(adf_os_device_t , pci_dma_softc_t *, |
| a_uint32_t num_desc); |
| void pci_dma_deinit_tx(adf_os_device_t , pci_dma_softc_t *); |
| |
| a_status_t pci_dma_recv_refill(adf_os_device_t , zdma_swdesc_t *, |
| a_uint32_t ); |
| |
| #endif |