12f345d8eSLuigi Rizzo /*- 2*291a1934SXin LI * Copyright (C) 2013 Emulex 32f345d8eSLuigi Rizzo * All rights reserved. 42f345d8eSLuigi Rizzo * 52f345d8eSLuigi Rizzo * Redistribution and use in source and binary forms, with or without 62f345d8eSLuigi Rizzo * modification, are permitted provided that the following conditions are met: 72f345d8eSLuigi Rizzo * 82f345d8eSLuigi Rizzo * 1. Redistributions of source code must retain the above copyright notice, 92f345d8eSLuigi Rizzo * this list of conditions and the following disclaimer. 102f345d8eSLuigi Rizzo * 112f345d8eSLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 122f345d8eSLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 132f345d8eSLuigi Rizzo * documentation and/or other materials provided with the distribution. 142f345d8eSLuigi Rizzo * 152f345d8eSLuigi Rizzo * 3. Neither the name of the Emulex Corporation nor the names of its 162f345d8eSLuigi Rizzo * contributors may be used to endorse or promote products derived from 172f345d8eSLuigi Rizzo * this software without specific prior written permission. 182f345d8eSLuigi Rizzo * 192f345d8eSLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 202f345d8eSLuigi Rizzo * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 212f345d8eSLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 222f345d8eSLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 232f345d8eSLuigi Rizzo * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 242f345d8eSLuigi Rizzo * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 252f345d8eSLuigi Rizzo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 262f345d8eSLuigi Rizzo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 272f345d8eSLuigi Rizzo * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 282f345d8eSLuigi Rizzo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 292f345d8eSLuigi Rizzo * POSSIBILITY OF SUCH DAMAGE. 302f345d8eSLuigi Rizzo * 312f345d8eSLuigi Rizzo * Contact Information: 322f345d8eSLuigi Rizzo * freebsd-drivers@emulex.com 332f345d8eSLuigi Rizzo * 342f345d8eSLuigi Rizzo * Emulex 352f345d8eSLuigi Rizzo * 3333 Susan Street 362f345d8eSLuigi Rizzo * Costa Mesa, CA 92626 372f345d8eSLuigi Rizzo */ 382f345d8eSLuigi Rizzo 39cdaba892SXin LI 402f345d8eSLuigi Rizzo /* $FreeBSD$ */ 412f345d8eSLuigi Rizzo 42cdaba892SXin LI 432f345d8eSLuigi Rizzo #include "oce_if.h" 442f345d8eSLuigi Rizzo 452f345d8eSLuigi Rizzo static void oce_dma_map_ring(void *arg, 462f345d8eSLuigi Rizzo bus_dma_segment_t *segs, 472f345d8eSLuigi Rizzo int nseg, 482f345d8eSLuigi Rizzo int error); 492f345d8eSLuigi Rizzo 502f345d8eSLuigi Rizzo /** 512f345d8eSLuigi Rizzo * @brief Allocate DMA memory 522f345d8eSLuigi Rizzo * @param sc software handle to the device 532f345d8eSLuigi Rizzo * @param size bus size 542f345d8eSLuigi Rizzo * @param dma dma memory area 552f345d8eSLuigi Rizzo * @param flags creation flags 562f345d8eSLuigi Rizzo * @returns 0 on success, error otherwize 572f345d8eSLuigi Rizzo */ 582f345d8eSLuigi Rizzo int 592f345d8eSLuigi Rizzo oce_dma_alloc(POCE_SOFTC sc, bus_size_t size, POCE_DMA_MEM dma, int flags) 602f345d8eSLuigi Rizzo { 612f345d8eSLuigi Rizzo int rc; 622f345d8eSLuigi Rizzo 632f345d8eSLuigi Rizzo 642f345d8eSLuigi Rizzo memset(dma, 0, sizeof(OCE_DMA_MEM)); 652f345d8eSLuigi Rizzo 662f345d8eSLuigi Rizzo rc = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 672f345d8eSLuigi Rizzo 8, 0, 682f345d8eSLuigi Rizzo BUS_SPACE_MAXADDR, 692f345d8eSLuigi Rizzo BUS_SPACE_MAXADDR, 702f345d8eSLuigi Rizzo NULL, NULL, 712f345d8eSLuigi Rizzo size, 1, size, 0, NULL, NULL, &dma->tag); 722f345d8eSLuigi Rizzo 732f345d8eSLuigi Rizzo if (rc == 0) { 742f345d8eSLuigi Rizzo rc = bus_dmamem_alloc(dma->tag, 752f345d8eSLuigi Rizzo &dma->ptr, 76cdaba892SXin LI BUS_DMA_NOWAIT | BUS_DMA_COHERENT | 77cdaba892SXin LI BUS_DMA_ZERO, 782f345d8eSLuigi Rizzo &dma->map); 792f345d8eSLuigi Rizzo } 802f345d8eSLuigi Rizzo 812f345d8eSLuigi Rizzo dma->paddr = 0; 822f345d8eSLuigi Rizzo if (rc == 0) { 832f345d8eSLuigi Rizzo rc = bus_dmamap_load(dma->tag, 842f345d8eSLuigi Rizzo dma->map, 852f345d8eSLuigi Rizzo dma->ptr, 862f345d8eSLuigi Rizzo size, 872f345d8eSLuigi Rizzo oce_dma_map_addr, 882f345d8eSLuigi Rizzo &dma->paddr, flags | BUS_DMA_NOWAIT); 892f345d8eSLuigi Rizzo if (dma->paddr == 0) 902f345d8eSLuigi Rizzo rc = ENXIO; 912f345d8eSLuigi Rizzo } 922f345d8eSLuigi Rizzo 932f345d8eSLuigi Rizzo if (rc != 0) 942f345d8eSLuigi Rizzo oce_dma_free(sc, dma); 952f345d8eSLuigi Rizzo 962f345d8eSLuigi Rizzo return rc; 972f345d8eSLuigi Rizzo } 982f345d8eSLuigi Rizzo 992f345d8eSLuigi Rizzo /** 1002f345d8eSLuigi Rizzo * @brief Free DMA memory 1012f345d8eSLuigi Rizzo * @param sc software handle to the device 1022f345d8eSLuigi Rizzo * @param dma dma area to free 1032f345d8eSLuigi Rizzo */ 1042f345d8eSLuigi Rizzo void 1052f345d8eSLuigi Rizzo oce_dma_free(POCE_SOFTC sc, POCE_DMA_MEM dma) 1062f345d8eSLuigi Rizzo { 1072f345d8eSLuigi Rizzo if (dma->tag == NULL) 1082f345d8eSLuigi Rizzo return; 1092f345d8eSLuigi Rizzo 1102f345d8eSLuigi Rizzo if (dma->map != NULL) { 1112f345d8eSLuigi Rizzo bus_dmamap_sync(dma->tag, dma->map, 1122f345d8eSLuigi Rizzo BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1132f345d8eSLuigi Rizzo bus_dmamap_unload(dma->tag, dma->map); 1142f345d8eSLuigi Rizzo } 1152f345d8eSLuigi Rizzo 1162f345d8eSLuigi Rizzo if (dma->ptr != NULL) { 1172f345d8eSLuigi Rizzo bus_dmamem_free(dma->tag, dma->ptr, dma->map); 1182f345d8eSLuigi Rizzo dma->map = NULL; 1192f345d8eSLuigi Rizzo dma->ptr = NULL; 1202f345d8eSLuigi Rizzo } 1212f345d8eSLuigi Rizzo 1222f345d8eSLuigi Rizzo bus_dma_tag_destroy(dma->tag); 1232f345d8eSLuigi Rizzo dma->tag = NULL; 1242f345d8eSLuigi Rizzo 1252f345d8eSLuigi Rizzo return; 1262f345d8eSLuigi Rizzo } 1272f345d8eSLuigi Rizzo 1282f345d8eSLuigi Rizzo 1292f345d8eSLuigi Rizzo 1302f345d8eSLuigi Rizzo /** 1312f345d8eSLuigi Rizzo * @brief Map DMA memory segment addresses 1322f345d8eSLuigi Rizzo * @param arg physical address pointer 1332f345d8eSLuigi Rizzo * @param segs dma memory segments 1342f345d8eSLuigi Rizzo * @param nseg number of dma memory segments 1352f345d8eSLuigi Rizzo * @param error if error, zeroes the physical address 1362f345d8eSLuigi Rizzo */ 1372f345d8eSLuigi Rizzo void 1382f345d8eSLuigi Rizzo oce_dma_map_addr(void *arg, bus_dma_segment_t * segs, int nseg, int error) 1392f345d8eSLuigi Rizzo { 1402f345d8eSLuigi Rizzo bus_addr_t *paddr = arg; 1412f345d8eSLuigi Rizzo 1422f345d8eSLuigi Rizzo if (error) 1432f345d8eSLuigi Rizzo *paddr = 0; 1442f345d8eSLuigi Rizzo else 1452f345d8eSLuigi Rizzo *paddr = segs->ds_addr; 1462f345d8eSLuigi Rizzo } 1472f345d8eSLuigi Rizzo 1482f345d8eSLuigi Rizzo 1492f345d8eSLuigi Rizzo 1502f345d8eSLuigi Rizzo /** 1512f345d8eSLuigi Rizzo * @brief Destroy a ring buffer 1522f345d8eSLuigi Rizzo * @param sc software handle to the device 1532f345d8eSLuigi Rizzo * @param ring ring buffer 1542f345d8eSLuigi Rizzo */ 1552f345d8eSLuigi Rizzo 1562f345d8eSLuigi Rizzo void 1572f345d8eSLuigi Rizzo oce_destroy_ring_buffer(POCE_SOFTC sc, oce_ring_buffer_t *ring) 1582f345d8eSLuigi Rizzo { 1592f345d8eSLuigi Rizzo oce_dma_free(sc, &ring->dma); 1602f345d8eSLuigi Rizzo free(ring, M_DEVBUF); 1612f345d8eSLuigi Rizzo } 1622f345d8eSLuigi Rizzo 1632f345d8eSLuigi Rizzo 1642f345d8eSLuigi Rizzo 1652f345d8eSLuigi Rizzo oce_ring_buffer_t * 1662f345d8eSLuigi Rizzo oce_create_ring_buffer(POCE_SOFTC sc, 1672f345d8eSLuigi Rizzo uint32_t q_len, uint32_t item_size) 1682f345d8eSLuigi Rizzo { 1692f345d8eSLuigi Rizzo uint32_t size = q_len * item_size; 1702f345d8eSLuigi Rizzo int rc; 1712f345d8eSLuigi Rizzo oce_ring_buffer_t *ring; 1722f345d8eSLuigi Rizzo 1732f345d8eSLuigi Rizzo 1742f345d8eSLuigi Rizzo ring = malloc(sizeof(oce_ring_buffer_t), M_DEVBUF, M_NOWAIT | M_ZERO); 1752f345d8eSLuigi Rizzo if (ring == NULL) 1762f345d8eSLuigi Rizzo return NULL; 1772f345d8eSLuigi Rizzo 1782f345d8eSLuigi Rizzo ring->item_size = item_size; 1792f345d8eSLuigi Rizzo ring->num_items = q_len; 1802f345d8eSLuigi Rizzo 1812f345d8eSLuigi Rizzo rc = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1822f345d8eSLuigi Rizzo 4096, 0, 1832f345d8eSLuigi Rizzo BUS_SPACE_MAXADDR, 1842f345d8eSLuigi Rizzo BUS_SPACE_MAXADDR, 1852f345d8eSLuigi Rizzo NULL, NULL, 1862f345d8eSLuigi Rizzo size, 8, 4096, 0, NULL, NULL, &ring->dma.tag); 1872f345d8eSLuigi Rizzo if (rc) 1882f345d8eSLuigi Rizzo goto fail; 1892f345d8eSLuigi Rizzo 1902f345d8eSLuigi Rizzo 1912f345d8eSLuigi Rizzo rc = bus_dmamem_alloc(ring->dma.tag, 1922f345d8eSLuigi Rizzo &ring->dma.ptr, 1932f345d8eSLuigi Rizzo BUS_DMA_NOWAIT | BUS_DMA_COHERENT, 1942f345d8eSLuigi Rizzo &ring->dma.map); 1952f345d8eSLuigi Rizzo if (rc) 1962f345d8eSLuigi Rizzo goto fail; 1972f345d8eSLuigi Rizzo 1982f345d8eSLuigi Rizzo bzero(ring->dma.ptr, size); 1992f345d8eSLuigi Rizzo bus_dmamap_sync(ring->dma.tag, ring->dma.map, 2002f345d8eSLuigi Rizzo BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2012f345d8eSLuigi Rizzo ring->dma.paddr = 0; 2022f345d8eSLuigi Rizzo 2032f345d8eSLuigi Rizzo return ring; 2042f345d8eSLuigi Rizzo 2052f345d8eSLuigi Rizzo fail: 2062f345d8eSLuigi Rizzo oce_dma_free(sc, &ring->dma); 2072f345d8eSLuigi Rizzo free(ring, M_DEVBUF); 2082f345d8eSLuigi Rizzo ring = NULL; 2092f345d8eSLuigi Rizzo return NULL; 2102f345d8eSLuigi Rizzo } 2112f345d8eSLuigi Rizzo 2122f345d8eSLuigi Rizzo 2132f345d8eSLuigi Rizzo 2142f345d8eSLuigi Rizzo struct _oce_dmamap_paddr_table { 2152f345d8eSLuigi Rizzo uint32_t max_entries; 2162f345d8eSLuigi Rizzo uint32_t num_entries; 2172f345d8eSLuigi Rizzo struct phys_addr *paddrs; 2182f345d8eSLuigi Rizzo }; 2192f345d8eSLuigi Rizzo 2202f345d8eSLuigi Rizzo 2212f345d8eSLuigi Rizzo 2222f345d8eSLuigi Rizzo /** 2232f345d8eSLuigi Rizzo * @brief Map ring buffer 2242f345d8eSLuigi Rizzo * @param arg dma map phyical address table pointer 2252f345d8eSLuigi Rizzo * @param segs dma memory segments 2262f345d8eSLuigi Rizzo * @param nseg number of dma memory segments 2272f345d8eSLuigi Rizzo * @param error maps only if error is 0 2282f345d8eSLuigi Rizzo */ 2292f345d8eSLuigi Rizzo static void 2302f345d8eSLuigi Rizzo oce_dma_map_ring(void *arg, bus_dma_segment_t * segs, int nseg, int error) 2312f345d8eSLuigi Rizzo { 2322f345d8eSLuigi Rizzo int i; 2332f345d8eSLuigi Rizzo struct _oce_dmamap_paddr_table *dpt = 2342f345d8eSLuigi Rizzo (struct _oce_dmamap_paddr_table *)arg; 2352f345d8eSLuigi Rizzo 2362f345d8eSLuigi Rizzo if (error == 0) { 2372f345d8eSLuigi Rizzo if (nseg <= dpt->max_entries) { 2382f345d8eSLuigi Rizzo for (i = 0; i < nseg; i++) { 2392f345d8eSLuigi Rizzo dpt->paddrs[i].lo = ADDR_LO(segs[i].ds_addr); 2402f345d8eSLuigi Rizzo dpt->paddrs[i].hi = ADDR_HI(segs[i].ds_addr); 2412f345d8eSLuigi Rizzo } 2422f345d8eSLuigi Rizzo dpt->num_entries = nseg; 2432f345d8eSLuigi Rizzo } 2442f345d8eSLuigi Rizzo } 2452f345d8eSLuigi Rizzo } 2462f345d8eSLuigi Rizzo 2472f345d8eSLuigi Rizzo 2482f345d8eSLuigi Rizzo 2492f345d8eSLuigi Rizzo /** 2502f345d8eSLuigi Rizzo * @brief Load bus dma map for a ring buffer 2512f345d8eSLuigi Rizzo * @param ring ring buffer pointer 2522f345d8eSLuigi Rizzo * @param pa_list physical address list 2532f345d8eSLuigi Rizzo * @returns number entries 2542f345d8eSLuigi Rizzo */ 2552f345d8eSLuigi Rizzo uint32_t 2562f345d8eSLuigi Rizzo oce_page_list(oce_ring_buffer_t *ring, struct phys_addr *pa_list) 2572f345d8eSLuigi Rizzo { 2582f345d8eSLuigi Rizzo struct _oce_dmamap_paddr_table dpt; 2592f345d8eSLuigi Rizzo 2602f345d8eSLuigi Rizzo dpt.max_entries = 8; 2612f345d8eSLuigi Rizzo dpt.num_entries = 0; 2622f345d8eSLuigi Rizzo dpt.paddrs = pa_list; 2632f345d8eSLuigi Rizzo 2642f345d8eSLuigi Rizzo bus_dmamap_load(ring->dma.tag, 2652f345d8eSLuigi Rizzo ring->dma.map, 2662f345d8eSLuigi Rizzo ring->dma.ptr, 2672f345d8eSLuigi Rizzo ring->item_size * ring->num_items, 2682f345d8eSLuigi Rizzo oce_dma_map_ring, &dpt, BUS_DMA_NOWAIT); 2692f345d8eSLuigi Rizzo 2702f345d8eSLuigi Rizzo return dpt.num_entries; 2712f345d8eSLuigi Rizzo } 272