1 /*
   2  * Copyright (c) 2008-2016 Solarflare Communications Inc.
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions are met:
   7  *
   8  * 1. Redistributions of source code must retain the above copyright notice,
   9  *    this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright notice,
  11  *    this list of conditions and the following disclaimer in the documentation
  12  *    and/or other materials provided with the distribution.
  13  *
  14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25  *
  26  * The views and conclusions contained in the software and documentation are
  27  * those of the authors and should not be interpreted as representing official
  28  * policies, either expressed or implied, of the FreeBSD Project.
  29  */
  30 
  31 #include <sys/ddi.h>
  32 
  33 #include "sfxge.h"
  34 #include "efx.h"
  35 
  36 static int
  37 sfxge_dma_buffer_unbind_handle(efsys_mem_t *esmp)
  38 {
  39         int rc;
  40 
  41         esmp->esm_addr = 0;
  42         rc = ddi_dma_unbind_handle(esmp->esm_dma_handle);
  43         if (rc != DDI_SUCCESS)
  44                 goto fail1;
  45 
  46         return (0);
  47 
  48 fail1:
  49         DTRACE_PROBE1(fail1, int, rc);
  50 
  51         return (rc);
  52 }
  53 
  54 static void
  55 sfxge_dma_buffer_mem_free(efsys_mem_t *esmp)
  56 {
  57         esmp->esm_base = NULL;
  58         ddi_dma_mem_free(&(esmp->esm_acc_handle));
  59         esmp->esm_acc_handle = NULL;
  60 }
  61 
  62 static void
  63 sfxge_dma_buffer_handle_free(ddi_dma_handle_t *dhandlep)
  64 {
  65         ddi_dma_free_handle(dhandlep);
  66         *dhandlep = NULL;
  67 }
  68 
  69 int
  70 sfxge_dma_buffer_create(efsys_mem_t *esmp, const sfxge_dma_buffer_attr_t *sdbap)
  71 {
  72         int err;
  73         int rc;
  74         size_t unit;
  75         ddi_dma_cookie_t dmac;
  76         unsigned int ncookies;
  77 
  78         /* Allocate a DMA handle */
  79         err = ddi_dma_alloc_handle(sdbap->sdba_dip, sdbap->sdba_dattrp,
  80             sdbap->sdba_callback, NULL, &(esmp->esm_dma_handle));
  81         switch (err) {
  82         case DDI_SUCCESS:
  83                 break;
  84 
  85         case DDI_DMA_BADATTR:
  86                 rc = EINVAL;
  87                 goto fail1;
  88 
  89         case DDI_DMA_NORESOURCES:
  90                 rc = ENOMEM;
  91                 goto fail1;
  92 
  93         default:
  94                 rc = EFAULT;
  95                 goto fail1;
  96         }
  97 
  98         /* Allocate some DMA memory */
  99         err = ddi_dma_mem_alloc(esmp->esm_dma_handle, sdbap->sdba_length,
 100             sdbap->sdba_devaccp, sdbap->sdba_memflags,
 101             sdbap->sdba_callback, NULL,
 102             &(esmp->esm_base), &unit, &(esmp->esm_acc_handle));
 103         switch (err) {
 104         case DDI_SUCCESS:
 105                 break;
 106 
 107         case DDI_FAILURE:
 108                 /*FALLTHRU*/
 109         default:
 110                 rc = EFAULT;
 111                 goto fail2;
 112         }
 113 
 114         if (sdbap->sdba_zeroinit)
 115                 bzero(esmp->esm_base, sdbap->sdba_length);
 116 
 117         /* Bind the DMA memory to the DMA handle */
 118         /* We aren't handling partial mappings */
 119         ASSERT3U(sdbap->sdba_bindflags & DDI_DMA_PARTIAL, !=, DDI_DMA_PARTIAL);
 120         err = ddi_dma_addr_bind_handle(esmp->esm_dma_handle, NULL,
 121             esmp->esm_base, sdbap->sdba_length, sdbap->sdba_bindflags,
 122             sdbap->sdba_callback, NULL, &dmac, &ncookies);
 123         switch (err) {
 124         case DDI_DMA_MAPPED:
 125                 break;
 126 
 127         case DDI_DMA_INUSE:
 128                 rc = EEXIST;
 129                 goto fail3;
 130 
 131         case DDI_DMA_NORESOURCES:
 132                 rc = ENOMEM;
 133                 goto fail3;
 134 
 135         case DDI_DMA_NOMAPPING:
 136                 rc = ENOTSUP;
 137                 goto fail3;
 138 
 139         case DDI_DMA_TOOBIG:
 140                 rc = EFBIG;
 141                 goto fail3;
 142 
 143         default:
 144                 rc = EFAULT;
 145                 goto fail3;
 146         }
 147         ASSERT3U(ncookies, >=, 1);
 148         ASSERT3U(ncookies, <=, sdbap->sdba_maxcookies);
 149 
 150         esmp->esm_addr = dmac.dmac_laddress;
 151         esmp->esm_size = dmac.dmac_size;
 152         DTRACE_PROBE1(addr, efsys_dma_addr_t, esmp->esm_addr);
 153 
 154         return (0);
 155 
 156 fail3:
 157         DTRACE_PROBE(fail3);
 158 
 159         sfxge_dma_buffer_mem_free(esmp);
 160 
 161 fail2:
 162         DTRACE_PROBE(fail2);
 163 
 164         sfxge_dma_buffer_handle_free(&(esmp->esm_dma_handle));
 165         esmp->esm_dma_handle = NULL;
 166 
 167 fail1:
 168         DTRACE_PROBE1(fail1, int, rc);
 169 
 170         return (-1);
 171 }
 172 
 173 void
 174 sfxge_dma_buffer_destroy(efsys_mem_t *esmp)
 175 {
 176         int rc;
 177 
 178         rc = sfxge_dma_buffer_unbind_handle(esmp);
 179         if (rc != 0) {
 180                 cmn_err(CE_WARN, SFXGE_CMN_ERR "DMA Unbind failed rc=%d", rc);
 181         }
 182         sfxge_dma_buffer_mem_free(esmp);
 183         sfxge_dma_buffer_handle_free(&(esmp->esm_dma_handle));
 184 }