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 }