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 }