1*229aec1cSSascha Wildner /*- 2*229aec1cSSascha Wildner * Copyright (C) 2012 Emulex 3*229aec1cSSascha Wildner * All rights reserved. 4*229aec1cSSascha Wildner * 5*229aec1cSSascha Wildner * Redistribution and use in source and binary forms, with or without 6*229aec1cSSascha Wildner * modification, are permitted provided that the following conditions are met: 7*229aec1cSSascha Wildner * 8*229aec1cSSascha Wildner * 1. Redistributions of source code must retain the above copyright notice, 9*229aec1cSSascha Wildner * this list of conditions and the following disclaimer. 10*229aec1cSSascha Wildner * 11*229aec1cSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright 12*229aec1cSSascha Wildner * notice, this list of conditions and the following disclaimer in the 13*229aec1cSSascha Wildner * documentation and/or other materials provided with the distribution. 14*229aec1cSSascha Wildner * 15*229aec1cSSascha Wildner * 3. Neither the name of the Emulex Corporation nor the names of its 16*229aec1cSSascha Wildner * contributors may be used to endorse or promote products derived from 17*229aec1cSSascha Wildner * this software without specific prior written permission. 18*229aec1cSSascha Wildner * 19*229aec1cSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20*229aec1cSSascha Wildner * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21*229aec1cSSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22*229aec1cSSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23*229aec1cSSascha Wildner * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24*229aec1cSSascha Wildner * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25*229aec1cSSascha Wildner * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26*229aec1cSSascha Wildner * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27*229aec1cSSascha Wildner * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28*229aec1cSSascha Wildner * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29*229aec1cSSascha Wildner * POSSIBILITY OF SUCH DAMAGE. 30*229aec1cSSascha Wildner * 31*229aec1cSSascha Wildner * Contact Information: 32*229aec1cSSascha Wildner * freebsd-drivers@emulex.com 33*229aec1cSSascha Wildner * 34*229aec1cSSascha Wildner * Emulex 35*229aec1cSSascha Wildner * 3333 Susan Street 36*229aec1cSSascha Wildner * Costa Mesa, CA 92626 37*229aec1cSSascha Wildner */ 38*229aec1cSSascha Wildner 39*229aec1cSSascha Wildner 40*229aec1cSSascha Wildner /* $FreeBSD: src/sys/dev/oce/oce_util.c,v 1.4 2013/03/07 00:29:47 svnexp Exp $ */ 41*229aec1cSSascha Wildner 42*229aec1cSSascha Wildner 43*229aec1cSSascha Wildner #include "oce_if.h" 44*229aec1cSSascha Wildner 45*229aec1cSSascha Wildner static void oce_dma_map_ring(void *arg, 46*229aec1cSSascha Wildner bus_dma_segment_t *segs, 47*229aec1cSSascha Wildner int nseg, 48*229aec1cSSascha Wildner int error); 49*229aec1cSSascha Wildner 50*229aec1cSSascha Wildner /** 51*229aec1cSSascha Wildner * @brief Allocate DMA memory 52*229aec1cSSascha Wildner * @param sc software handle to the device 53*229aec1cSSascha Wildner * @param size bus size 54*229aec1cSSascha Wildner * @param dma dma memory area 55*229aec1cSSascha Wildner * @param flags creation flags 56*229aec1cSSascha Wildner * @returns 0 on success, error otherwize 57*229aec1cSSascha Wildner */ 58*229aec1cSSascha Wildner int 59*229aec1cSSascha Wildner oce_dma_alloc(POCE_SOFTC sc, bus_size_t size, POCE_DMA_MEM dma, int flags) 60*229aec1cSSascha Wildner { 61*229aec1cSSascha Wildner int rc; 62*229aec1cSSascha Wildner 63*229aec1cSSascha Wildner 64*229aec1cSSascha Wildner memset(dma, 0, sizeof(OCE_DMA_MEM)); 65*229aec1cSSascha Wildner 66*229aec1cSSascha Wildner rc = bus_dma_tag_create(NULL, 67*229aec1cSSascha Wildner 8, 0, 68*229aec1cSSascha Wildner BUS_SPACE_MAXADDR, 69*229aec1cSSascha Wildner BUS_SPACE_MAXADDR, 70*229aec1cSSascha Wildner NULL, NULL, 71*229aec1cSSascha Wildner size, 1, size, 0, &dma->tag); 72*229aec1cSSascha Wildner 73*229aec1cSSascha Wildner if (rc == 0) { 74*229aec1cSSascha Wildner rc = bus_dmamem_alloc(dma->tag, 75*229aec1cSSascha Wildner &dma->ptr, 76*229aec1cSSascha Wildner BUS_DMA_NOWAIT | BUS_DMA_COHERENT | 77*229aec1cSSascha Wildner BUS_DMA_ZERO, 78*229aec1cSSascha Wildner &dma->map); 79*229aec1cSSascha Wildner } 80*229aec1cSSascha Wildner 81*229aec1cSSascha Wildner dma->paddr = 0; 82*229aec1cSSascha Wildner if (rc == 0) { 83*229aec1cSSascha Wildner rc = bus_dmamap_load(dma->tag, 84*229aec1cSSascha Wildner dma->map, 85*229aec1cSSascha Wildner dma->ptr, 86*229aec1cSSascha Wildner size, 87*229aec1cSSascha Wildner oce_dma_map_addr, 88*229aec1cSSascha Wildner &dma->paddr, flags | BUS_DMA_NOWAIT); 89*229aec1cSSascha Wildner if (dma->paddr == 0) 90*229aec1cSSascha Wildner rc = ENXIO; 91*229aec1cSSascha Wildner } 92*229aec1cSSascha Wildner 93*229aec1cSSascha Wildner if (rc != 0) 94*229aec1cSSascha Wildner oce_dma_free(sc, dma); 95*229aec1cSSascha Wildner 96*229aec1cSSascha Wildner return rc; 97*229aec1cSSascha Wildner } 98*229aec1cSSascha Wildner 99*229aec1cSSascha Wildner /** 100*229aec1cSSascha Wildner * @brief Free DMA memory 101*229aec1cSSascha Wildner * @param sc software handle to the device 102*229aec1cSSascha Wildner * @param dma dma area to free 103*229aec1cSSascha Wildner */ 104*229aec1cSSascha Wildner void 105*229aec1cSSascha Wildner oce_dma_free(POCE_SOFTC sc, POCE_DMA_MEM dma) 106*229aec1cSSascha Wildner { 107*229aec1cSSascha Wildner if (dma->tag == NULL) 108*229aec1cSSascha Wildner return; 109*229aec1cSSascha Wildner 110*229aec1cSSascha Wildner if (dma->map != NULL) { 111*229aec1cSSascha Wildner bus_dmamap_sync(dma->tag, dma->map, 112*229aec1cSSascha Wildner BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 113*229aec1cSSascha Wildner bus_dmamap_unload(dma->tag, dma->map); 114*229aec1cSSascha Wildner } 115*229aec1cSSascha Wildner 116*229aec1cSSascha Wildner if (dma->ptr != NULL) { 117*229aec1cSSascha Wildner bus_dmamem_free(dma->tag, dma->ptr, dma->map); 118*229aec1cSSascha Wildner dma->map = NULL; 119*229aec1cSSascha Wildner dma->ptr = NULL; 120*229aec1cSSascha Wildner } 121*229aec1cSSascha Wildner 122*229aec1cSSascha Wildner bus_dma_tag_destroy(dma->tag); 123*229aec1cSSascha Wildner dma->tag = NULL; 124*229aec1cSSascha Wildner 125*229aec1cSSascha Wildner return; 126*229aec1cSSascha Wildner } 127*229aec1cSSascha Wildner 128*229aec1cSSascha Wildner 129*229aec1cSSascha Wildner 130*229aec1cSSascha Wildner /** 131*229aec1cSSascha Wildner * @brief Map DMA memory segment addresses 132*229aec1cSSascha Wildner * @param arg physical address pointer 133*229aec1cSSascha Wildner * @param segs dma memory segments 134*229aec1cSSascha Wildner * @param nseg number of dma memory segments 135*229aec1cSSascha Wildner * @param error if error, zeroes the physical address 136*229aec1cSSascha Wildner */ 137*229aec1cSSascha Wildner void 138*229aec1cSSascha Wildner oce_dma_map_addr(void *arg, bus_dma_segment_t * segs, int nseg, int error) 139*229aec1cSSascha Wildner { 140*229aec1cSSascha Wildner bus_addr_t *paddr = arg; 141*229aec1cSSascha Wildner 142*229aec1cSSascha Wildner if (error) 143*229aec1cSSascha Wildner *paddr = 0; 144*229aec1cSSascha Wildner else 145*229aec1cSSascha Wildner *paddr = segs->ds_addr; 146*229aec1cSSascha Wildner } 147*229aec1cSSascha Wildner 148*229aec1cSSascha Wildner 149*229aec1cSSascha Wildner 150*229aec1cSSascha Wildner /** 151*229aec1cSSascha Wildner * @brief Destroy a ring buffer 152*229aec1cSSascha Wildner * @param sc software handle to the device 153*229aec1cSSascha Wildner * @param ring ring buffer 154*229aec1cSSascha Wildner */ 155*229aec1cSSascha Wildner 156*229aec1cSSascha Wildner void 157*229aec1cSSascha Wildner oce_destroy_ring_buffer(POCE_SOFTC sc, oce_ring_buffer_t *ring) 158*229aec1cSSascha Wildner { 159*229aec1cSSascha Wildner oce_dma_free(sc, &ring->dma); 160*229aec1cSSascha Wildner kfree(ring, M_DEVBUF); 161*229aec1cSSascha Wildner } 162*229aec1cSSascha Wildner 163*229aec1cSSascha Wildner 164*229aec1cSSascha Wildner 165*229aec1cSSascha Wildner oce_ring_buffer_t * 166*229aec1cSSascha Wildner oce_create_ring_buffer(POCE_SOFTC sc, 167*229aec1cSSascha Wildner uint32_t q_len, uint32_t item_size) 168*229aec1cSSascha Wildner { 169*229aec1cSSascha Wildner uint32_t size = q_len * item_size; 170*229aec1cSSascha Wildner int rc; 171*229aec1cSSascha Wildner oce_ring_buffer_t *ring; 172*229aec1cSSascha Wildner 173*229aec1cSSascha Wildner 174*229aec1cSSascha Wildner ring = kmalloc(sizeof(oce_ring_buffer_t), M_DEVBUF, M_NOWAIT | M_ZERO); 175*229aec1cSSascha Wildner if (ring == NULL) 176*229aec1cSSascha Wildner return NULL; 177*229aec1cSSascha Wildner 178*229aec1cSSascha Wildner ring->item_size = item_size; 179*229aec1cSSascha Wildner ring->num_items = q_len; 180*229aec1cSSascha Wildner 181*229aec1cSSascha Wildner rc = bus_dma_tag_create(NULL, 182*229aec1cSSascha Wildner 4096, 0, 183*229aec1cSSascha Wildner BUS_SPACE_MAXADDR, 184*229aec1cSSascha Wildner BUS_SPACE_MAXADDR, 185*229aec1cSSascha Wildner NULL, NULL, 186*229aec1cSSascha Wildner size, 8, 4096, 0, &ring->dma.tag); 187*229aec1cSSascha Wildner if (rc) 188*229aec1cSSascha Wildner goto fail; 189*229aec1cSSascha Wildner 190*229aec1cSSascha Wildner 191*229aec1cSSascha Wildner rc = bus_dmamem_alloc(ring->dma.tag, 192*229aec1cSSascha Wildner &ring->dma.ptr, 193*229aec1cSSascha Wildner BUS_DMA_NOWAIT | BUS_DMA_COHERENT, 194*229aec1cSSascha Wildner &ring->dma.map); 195*229aec1cSSascha Wildner if (rc) 196*229aec1cSSascha Wildner goto fail; 197*229aec1cSSascha Wildner 198*229aec1cSSascha Wildner bzero(ring->dma.ptr, size); 199*229aec1cSSascha Wildner bus_dmamap_sync(ring->dma.tag, ring->dma.map, 200*229aec1cSSascha Wildner BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 201*229aec1cSSascha Wildner ring->dma.paddr = 0; 202*229aec1cSSascha Wildner 203*229aec1cSSascha Wildner return ring; 204*229aec1cSSascha Wildner 205*229aec1cSSascha Wildner fail: 206*229aec1cSSascha Wildner oce_dma_free(sc, &ring->dma); 207*229aec1cSSascha Wildner kfree(ring, M_DEVBUF); 208*229aec1cSSascha Wildner ring = NULL; 209*229aec1cSSascha Wildner return NULL; 210*229aec1cSSascha Wildner } 211*229aec1cSSascha Wildner 212*229aec1cSSascha Wildner 213*229aec1cSSascha Wildner 214*229aec1cSSascha Wildner struct _oce_dmamap_paddr_table { 215*229aec1cSSascha Wildner uint32_t max_entries; 216*229aec1cSSascha Wildner uint32_t num_entries; 217*229aec1cSSascha Wildner struct phys_addr *paddrs; 218*229aec1cSSascha Wildner }; 219*229aec1cSSascha Wildner 220*229aec1cSSascha Wildner 221*229aec1cSSascha Wildner 222*229aec1cSSascha Wildner /** 223*229aec1cSSascha Wildner * @brief Map ring buffer 224*229aec1cSSascha Wildner * @param arg dma map phyical address table pointer 225*229aec1cSSascha Wildner * @param segs dma memory segments 226*229aec1cSSascha Wildner * @param nseg number of dma memory segments 227*229aec1cSSascha Wildner * @param error maps only if error is 0 228*229aec1cSSascha Wildner */ 229*229aec1cSSascha Wildner static void 230*229aec1cSSascha Wildner oce_dma_map_ring(void *arg, bus_dma_segment_t * segs, int nseg, int error) 231*229aec1cSSascha Wildner { 232*229aec1cSSascha Wildner int i; 233*229aec1cSSascha Wildner struct _oce_dmamap_paddr_table *dpt = 234*229aec1cSSascha Wildner (struct _oce_dmamap_paddr_table *)arg; 235*229aec1cSSascha Wildner 236*229aec1cSSascha Wildner if (error == 0) { 237*229aec1cSSascha Wildner if (nseg <= dpt->max_entries) { 238*229aec1cSSascha Wildner for (i = 0; i < nseg; i++) { 239*229aec1cSSascha Wildner dpt->paddrs[i].lo = ADDR_LO(segs[i].ds_addr); 240*229aec1cSSascha Wildner dpt->paddrs[i].hi = ADDR_HI(segs[i].ds_addr); 241*229aec1cSSascha Wildner } 242*229aec1cSSascha Wildner dpt->num_entries = nseg; 243*229aec1cSSascha Wildner } 244*229aec1cSSascha Wildner } 245*229aec1cSSascha Wildner } 246*229aec1cSSascha Wildner 247*229aec1cSSascha Wildner 248*229aec1cSSascha Wildner 249*229aec1cSSascha Wildner /** 250*229aec1cSSascha Wildner * @brief Load bus dma map for a ring buffer 251*229aec1cSSascha Wildner * @param ring ring buffer pointer 252*229aec1cSSascha Wildner * @param pa_list physical address list 253*229aec1cSSascha Wildner * @returns number entries 254*229aec1cSSascha Wildner */ 255*229aec1cSSascha Wildner uint32_t 256*229aec1cSSascha Wildner oce_page_list(oce_ring_buffer_t *ring, struct phys_addr *pa_list) 257*229aec1cSSascha Wildner { 258*229aec1cSSascha Wildner struct _oce_dmamap_paddr_table dpt; 259*229aec1cSSascha Wildner 260*229aec1cSSascha Wildner dpt.max_entries = 8; 261*229aec1cSSascha Wildner dpt.num_entries = 0; 262*229aec1cSSascha Wildner dpt.paddrs = pa_list; 263*229aec1cSSascha Wildner 264*229aec1cSSascha Wildner bus_dmamap_load(ring->dma.tag, 265*229aec1cSSascha Wildner ring->dma.map, 266*229aec1cSSascha Wildner ring->dma.ptr, 267*229aec1cSSascha Wildner ring->item_size * ring->num_items, 268*229aec1cSSascha Wildner oce_dma_map_ring, &dpt, BUS_DMA_NOWAIT); 269*229aec1cSSascha Wildner 270*229aec1cSSascha Wildner return dpt.num_entries; 271*229aec1cSSascha Wildner } 272