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 2008-2013 Solarflare Communications Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include <sys/ddi.h>
  28 
  29 #include "sfxge.h"
  30 #include "efx.h"
  31 
  32 static int
  33 sfxge_dma_buffer_unbind_handle(efsys_mem_t *esmp)
  34 {
  35         int rc;
  36 
  37         esmp->esm_addr = 0;
  38         rc = ddi_dma_unbind_handle(esmp->esm_dma_handle);
  39         if (rc != DDI_SUCCESS)
  40                 goto fail1;
  41 
  42         return (0);
  43 
  44 fail1:
  45         DTRACE_PROBE1(fail1, int, rc);
  46 
  47         return (rc);
  48 }
  49 
  50 static void
  51 sfxge_dma_buffer_mem_free(efsys_mem_t *esmp)
  52 {
  53         esmp->esm_base = NULL;
  54         ddi_dma_mem_free(&(esmp->esm_acc_handle));
  55         esmp->esm_acc_handle = NULL;
  56 }
  57 
  58 static void
  59 sfxge_dma_buffer_handle_free(ddi_dma_handle_t *dhandlep)
  60 {
  61         ddi_dma_free_handle(dhandlep);
  62         *dhandlep = NULL;
  63 }
  64 
  65 int
  66 sfxge_dma_buffer_create(efsys_mem_t *esmp, const sfxge_dma_buffer_attr_t *sdbap)
  67 {
  68         int err;
  69         int rc;
  70         size_t unit;
  71         ddi_dma_cookie_t dmac;
  72         unsigned int ncookies;
  73 
  74         /* Allocate a DMA handle */
  75         err = ddi_dma_alloc_handle(sdbap->sdba_dip, sdbap->sdba_dattrp,
  76             sdbap->sdba_callback, NULL, &(esmp->esm_dma_handle));
  77         switch (err) {
  78         case DDI_SUCCESS:
  79                 break;
  80 
  81         case DDI_DMA_BADATTR:
  82                 rc = EINVAL;
  83                 goto fail1;
  84 
  85         case DDI_DMA_NORESOURCES:
  86                 rc = ENOMEM;
  87                 goto fail1;
  88 
  89         default:
  90                 rc = EFAULT;
  91                 goto fail1;
  92         }
  93 
  94         /* Allocate some DMA memory */
  95         err = ddi_dma_mem_alloc(esmp->esm_dma_handle, sdbap->sdba_length,
  96             sdbap->sdba_devaccp, sdbap->sdba_memflags,
  97             sdbap->sdba_callback, NULL,
  98             &(esmp->esm_base), &unit, &(esmp->esm_acc_handle));
  99         switch (err) {
 100         case DDI_SUCCESS:
 101                 break;
 102 
 103         case DDI_FAILURE:
 104                 /*FALLTHRU*/
 105         default:
 106                 rc = EFAULT;
 107                 goto fail2;
 108         }
 109 
 110         if (sdbap->sdba_zeroinit)
 111                 bzero(esmp->esm_base, sdbap->sdba_length);
 112 
 113         /* Bind the DMA memory to the DMA handle */
 114         /* We aren't handling partial mappings */
 115         ASSERT3U(sdbap->sdba_bindflags & DDI_DMA_PARTIAL, !=, DDI_DMA_PARTIAL);
 116         err = ddi_dma_addr_bind_handle(esmp->esm_dma_handle, NULL,
 117             esmp->esm_base, sdbap->sdba_length, sdbap->sdba_bindflags,
 118             sdbap->sdba_callback, NULL, &dmac, &ncookies);
 119         switch (err) {
 120         case DDI_DMA_MAPPED:
 121                 break;
 122 
 123         case DDI_DMA_INUSE:
 124                 rc = EEXIST;
 125                 goto fail3;
 126 
 127         case DDI_DMA_NORESOURCES:
 128                 rc = ENOMEM;
 129                 goto fail3;
 130 
 131         case DDI_DMA_NOMAPPING:
 132                 rc = ENOTSUP;
 133                 goto fail3;
 134 
 135         case DDI_DMA_TOOBIG:
 136                 rc = EFBIG;
 137                 goto fail3;
 138 
 139         default:
 140                 rc = EFAULT;
 141                 goto fail3;
 142         }
 143         ASSERT3U(ncookies, >=, 1);
 144         ASSERT3U(ncookies, <=, sdbap->sdba_maxcookies);
 145 
 146         esmp->esm_addr = dmac.dmac_laddress;
 147         DTRACE_PROBE1(addr, efsys_dma_addr_t, esmp->esm_addr);
 148 
 149         return (0);
 150 
 151 fail3:
 152         DTRACE_PROBE(fail3);
 153 
 154         sfxge_dma_buffer_mem_free(esmp);
 155 
 156 fail2:
 157         DTRACE_PROBE(fail2);
 158 
 159         sfxge_dma_buffer_handle_free(&(esmp->esm_dma_handle));
 160         esmp->esm_dma_handle = NULL;
 161 
 162 fail1:
 163         DTRACE_PROBE1(fail1, int, rc);
 164 
 165         return (-1);
 166 }
 167 
 168 void
 169 sfxge_dma_buffer_destroy(efsys_mem_t *esmp)
 170 {
 171         int rc;
 172 
 173         rc = sfxge_dma_buffer_unbind_handle(esmp);
 174         if (rc != 0) {
 175                 cmn_err(CE_WARN, SFXGE_CMN_ERR "ERROR: DMA Unbind failed rc=%d",
 176                     rc);
 177         }
 178         sfxge_dma_buffer_mem_free(esmp);
 179         sfxge_dma_buffer_handle_free(&(esmp->esm_dma_handle));
 180 }