1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2009-2012 Emulex. All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 
  28 /*
  29  * Source file containing the implementation of Driver buffer management
  30  * and related helper functions
  31  */
  32 #include <oce_impl.h>
  33 
  34 static ddi_dma_attr_t oce_dma_buf_attr = {
  35         DMA_ATTR_V0,            /* version number */
  36         0x0000000000000000ull,  /* low address */
  37         0xFFFFFFFFFFFFFFFFull,  /* high address */
  38         0x00000000FFFFFFFFull,  /* dma counter max */
  39         OCE_DMA_ALIGNMENT,      /* alignment */
  40         0x00000FFF,             /* burst sizes */
  41         0x00000001,             /* minimum transfer size */
  42         0x00000000FFFFFFFFull,  /* maximum transfer size */
  43         0xFFFFFFFFFFFFFFFFull,  /* maximum segment size */
  44         1,                      /* scatter/gather list length */
  45         0x00000001,             /* granularity */
  46         0                       /* DMA flags */
  47 };
  48 
  49 static ddi_device_acc_attr_t oce_dma_buf_accattr = {
  50         DDI_DEVICE_ATTR_V0,
  51         DDI_NEVERSWAP_ACC,
  52         DDI_STRICTORDER_ACC,
  53 };
  54 
  55 
  56 /*
  57  * function to allocate a dma buffer for mapping memory va-pa
  58  *
  59  * dev - software handle to device
  60  * size - size of the memory to map
  61  * flags - DDI_DMA_CONSISTENT/DDI_DMA_STREAMING
  62  *
  63  * return pointer to a oce_dma_buf_t structure handling the map
  64  *      NULL => failure
  65  */
  66 int
  67 oce_alloc_dma_buffer(struct oce_dev *dev, oce_dma_buf_t *dbuf,
  68     uint32_t size, ddi_dma_attr_t *dma_attr, uint32_t flags)
  69 {
  70         size_t actual_len;
  71         int ret = 0;
  72 
  73         ASSERT(size > 0);
  74         /* if NULL use default */
  75         if (dma_attr == NULL) {
  76                 dma_attr = &oce_dma_buf_attr;
  77         }
  78 
  79         /* allocate dma handle */
  80         ret = ddi_dma_alloc_handle(dev->dip, dma_attr,
  81             DDI_DMA_DONTWAIT, NULL, &dbuf->dma_handle);
  82         if (ret != DDI_SUCCESS) {
  83                 oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
  84                     "Failed to allocate DMA handle");
  85                 goto handle_fail;
  86         }
  87         /* allocate the DMA-able memory */
  88         ret = ddi_dma_mem_alloc(dbuf->dma_handle, size, &oce_dma_buf_accattr,
  89             (flags & DDI_DMA_STREAMING) ?
  90             DDI_DMA_STREAMING : DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
  91             &dbuf->base, &actual_len, &dbuf->acc_handle);
  92         if (ret != DDI_SUCCESS) {
  93                 oce_log(dev, CE_NOTE, MOD_CONFIG,
  94                     "Failed to allocate DMA memory: 0x%x bytes", size);
  95                 goto alloc_fail;
  96         }
  97 
  98         /* bind handle */
  99         ret = ddi_dma_addr_bind_handle(dbuf->dma_handle,
 100             (struct as *)0, dbuf->base, actual_len,
 101             flags,
 102             DDI_DMA_DONTWAIT, NULL, &dbuf->cookie, &dbuf->ncookies);
 103         if (ret != DDI_DMA_MAPPED) {
 104                 oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
 105                     "Failed to bind dma handle");
 106                 goto bind_fail;
 107         }
 108         bzero(dbuf->base, actual_len);
 109         dbuf->addr = dbuf->cookie.dmac_laddress;
 110         dbuf->size = actual_len;
 111         /* usable length */
 112         dbuf->len  = size;
 113         dbuf->num_pages = OCE_NUM_PAGES(size);
 114         return (DDI_SUCCESS);
 115 
 116 bind_fail:
 117         ddi_dma_mem_free(&dbuf->acc_handle);
 118 alloc_fail:
 119         ddi_dma_free_handle(&dbuf->dma_handle);
 120 handle_fail:
 121         return (ret);
 122 } /* oce_dma_alloc_buffer */
 123 
 124 /*
 125  * function to delete a dma buffer
 126  *
 127  * dev - software handle to device
 128  * dbuf - dma obj  to delete
 129  *
 130  * return none
 131  */
 132 void
 133 oce_free_dma_buffer(struct oce_dev *dev, oce_dma_buf_t *dbuf)
 134 {
 135         _NOTE(ARGUNUSED(dev));
 136 
 137         if (dbuf == NULL) {
 138                 return;
 139         }
 140         if (dbuf->dma_handle != NULL) {
 141                 (void) ddi_dma_unbind_handle(dbuf->dma_handle);
 142         }
 143         if (dbuf->acc_handle != NULL) {
 144                 ddi_dma_mem_free(&dbuf->acc_handle);
 145                 dbuf->acc_handle = NULL;
 146         }
 147         if (dbuf->dma_handle != NULL) {
 148                 ddi_dma_free_handle(&dbuf->dma_handle);
 149                 dbuf->dma_handle = NULL;
 150         }
 151 } /* oce_free_dma_buffer */
 152 
 153 /*
 154  * function to create a ring buffer
 155  *
 156  * dev - software handle to the device
 157  * num_items - number of items in the ring
 158  * item_size - size of an individual item in the ring
 159  * flags - DDI_DMA_CONSISTENT/DDI_DMA_STREAMING for ring memory
 160  *
 161  * return pointer to a ring_buffer structure, NULL on failure
 162  */
 163 oce_ring_buffer_t *
 164 oce_create_ring_buffer(struct oce_dev *dev,
 165     uint32_t num_items, uint32_t item_size, uint32_t flags)
 166 {
 167         oce_ring_buffer_t *ring;
 168         int ret;
 169 
 170         /* allocate the ring buffer */
 171         ring = kmem_zalloc(sizeof (oce_ring_buffer_t), KM_NOSLEEP);
 172         if (ring == NULL) {
 173                 return (NULL);
 174         }
 175 
 176         /* get the dbuf defining the ring */
 177         ret = oce_alloc_dma_buffer(dev, &ring->dbuf, num_items *item_size,
 178             NULL, flags);
 179         if (ret != DDI_SUCCESS) {
 180                 oce_log(dev, CE_WARN, MOD_CONFIG,
 181                     "Ring buffer allocation failed 0x%x", ret);
 182                 goto dbuf_fail;
 183         }
 184 
 185         /* fill the rest of the ring */
 186         ring->num_items = num_items;
 187         ring->item_size = item_size;
 188         ring->num_used  = 0;
 189         return (ring);
 190 
 191 dbuf_fail:
 192         kmem_free(ring, sizeof (oce_ring_buffer_t));
 193         return (NULL);
 194 } /* create_ring_buffer */
 195 
 196 /*
 197  * function to destroy a ring buffer
 198  *
 199  * dev - software handle to teh device
 200  * ring - the ring buffer to delete
 201  *
 202  * return none
 203  */
 204 void
 205 destroy_ring_buffer(struct oce_dev *dev, oce_ring_buffer_t *ring)
 206 {
 207         ASSERT(dev != NULL);
 208         ASSERT(ring !=  NULL);
 209 
 210         /* free the dbuf associated with the ring */
 211         oce_free_dma_buffer(dev, &ring->dbuf);
 212 
 213         /* free the ring itself */
 214         kmem_free(ring, sizeof (oce_ring_buffer_t));
 215 } /* destroy_ring_buffer */
 216 
 217 
 218 /*
 219  * function to enable the fma flags
 220  * fm_caps - FM capability flags
 221  *
 222  * return none
 223  */
 224 
 225 void
 226 oce_set_dma_fma_flags(int fm_caps)
 227 {
 228         if (fm_caps == DDI_FM_NOT_CAPABLE) {
 229                 return;
 230         }
 231 
 232         oce_dma_buf_accattr.devacc_attr_access = DDI_DEFAULT_ACC;
 233 
 234         if (DDI_FM_DMA_ERR_CAP(fm_caps)) {
 235                 oce_dma_buf_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
 236 
 237         } else {
 238                 oce_dma_buf_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
 239 
 240         }
 241 } /* oce_set_dma_fma_flags */