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
sfxge_dma_buffer_unbind_handle(efsys_mem_t * esmp)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
sfxge_dma_buffer_mem_free(efsys_mem_t * esmp)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
sfxge_dma_buffer_handle_free(ddi_dma_handle_t * dhandlep)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
sfxge_dma_buffer_create(efsys_mem_t * esmp,const sfxge_dma_buffer_attr_t * sdbap)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
sfxge_dma_buffer_destroy(efsys_mem_t * esmp)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 }
185