1 /*
2 * Copyright (C) 2007 VMware, Inc. All rights reserved.
3 *
4 * The contents of this file are subject to the terms of the Common
5 * Development and Distribution License (the "License") version 1.0
6 * and no later version. You may not use this file except in
7 * compliance with the License.
8 *
9 * You can obtain a copy of the License at
10 * http://www.opensource.org/licenses/cddl1.php
11 *
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
14 */
15 /*
16 * Copyright (c) 2016 by Delphix. All rights reserved.
17 */
18
19 #include <vmxnet3.h>
20
21 /* Used by ddi_regs_map_setup() and ddi_dma_mem_alloc() */
22 ddi_device_acc_attr_t vmxnet3_dev_attr = {
23 DDI_DEVICE_ATTR_V0,
24 DDI_STRUCTURE_LE_ACC,
25 DDI_STRICTORDER_ACC
26 };
27
28 /* Buffers with no alignment constraint DMA description */
29 static ddi_dma_attr_t vmxnet3_dma_attrs_1 = {
30 .dma_attr_version = DMA_ATTR_V0,
31 .dma_attr_addr_lo = 0x0000000000000000ull,
32 .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull,
33 .dma_attr_count_max = 0xFFFFFFFFFFFFFFFFull,
34 .dma_attr_align = 0x0000000000000001ull,
35 .dma_attr_burstsizes = 0x0000000000000001ull,
36 .dma_attr_minxfer = 0x00000001,
37 .dma_attr_maxxfer = 0xFFFFFFFFFFFFFFFFull,
38 .dma_attr_seg = 0xFFFFFFFFFFFFFFFFull,
39 .dma_attr_sgllen = 1,
40 .dma_attr_granular = 0x00000001,
41 .dma_attr_flags = 0
42 };
43
44 /* Buffers with a 128-bytes alignment constraint DMA description */
45 static ddi_dma_attr_t vmxnet3_dma_attrs_128 = {
46 .dma_attr_version = DMA_ATTR_V0,
47 .dma_attr_addr_lo = 0x0000000000000000ull,
48 .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull,
49 .dma_attr_count_max = 0xFFFFFFFFFFFFFFFFull,
50 .dma_attr_align = 0x0000000000000080ull,
51 .dma_attr_burstsizes = 0x0000000000000001ull,
52 .dma_attr_minxfer = 0x00000001,
53 .dma_attr_maxxfer = 0xFFFFFFFFFFFFFFFFull,
54 .dma_attr_seg = 0xFFFFFFFFFFFFFFFFull,
55 .dma_attr_sgllen = 1,
56 .dma_attr_granular = 0x00000001,
57 .dma_attr_flags = 0
58 };
59
60 /* Buffers with a 512-bytes alignment constraint DMA description */
61 static ddi_dma_attr_t vmxnet3_dma_attrs_512 = {
62 .dma_attr_version = DMA_ATTR_V0,
63 .dma_attr_addr_lo = 0x0000000000000000ull,
64 .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull,
65 .dma_attr_count_max = 0xFFFFFFFFFFFFFFFFull,
66 .dma_attr_align = 0x0000000000000200ull,
67 .dma_attr_burstsizes = 0x0000000000000001ull,
68 .dma_attr_minxfer = 0x00000001,
69 .dma_attr_maxxfer = 0xFFFFFFFFFFFFFFFFull,
70 .dma_attr_seg = 0xFFFFFFFFFFFFFFFFull,
71 .dma_attr_sgllen = 1,
72 .dma_attr_granular = 0x00000001,
73 .dma_attr_flags = 0
74 };
75
76 int
vmxnet3_dmaerr2errno(int dmaerr)77 vmxnet3_dmaerr2errno(int dmaerr)
78 {
79 int err;
80
81 switch (dmaerr) {
82 case DDI_DMA_NORESOURCES:
83 case DDI_DMA_TOOBIG:
84 err = ENOMEM;
85 break;
86 case DDI_DMA_INUSE:
87 err = EBUSY;
88 break;
89 case DDI_DMA_BADATTR:
90 case DDI_DMA_NOMAPPING:
91 default:
92 err = EINVAL;
93 }
94
95 return (err);
96 }
97
98 /*
99 * Allocate /size/ bytes of contiguous DMA-ble memory.
100 *
101 * Returns:
102 * 0 on success, non-zero on failure.
103 */
104 static int
vmxnet3_alloc_dma_mem(vmxnet3_softc_t * dp,vmxnet3_dmabuf_t * dma,size_t size,boolean_t canSleep,ddi_dma_attr_t * dma_attrs)105 vmxnet3_alloc_dma_mem(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma, size_t size,
106 boolean_t canSleep, ddi_dma_attr_t *dma_attrs)
107 {
108 ddi_dma_cookie_t cookie;
109 uint_t cookieCount;
110 int dmaerr, err = 0;
111 int (*cb) (caddr_t) = canSleep ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
112
113 ASSERT(size != 0);
114
115 /*
116 * Allocate a DMA handle
117 */
118 if ((dmaerr = ddi_dma_alloc_handle(dp->dip, dma_attrs, cb, NULL,
119 &dma->dmaHandle)) != DDI_SUCCESS) {
120 VMXNET3_WARN(dp, "ddi_dma_alloc_handle() failed: %d", dmaerr);
121 err = vmxnet3_dmaerr2errno(dmaerr);
122 goto error;
123 }
124
125 /*
126 * Allocate memory
127 */
128 if (ddi_dma_mem_alloc(dma->dmaHandle, size, &vmxnet3_dev_attr,
129 DDI_DMA_CONSISTENT, cb, NULL, &dma->buf, &dma->bufLen,
130 &dma->dataHandle) != DDI_SUCCESS) {
131 VMXNET3_WARN(dp, "ddi_dma_mem_alloc() failed");
132 err = ENOMEM;
133 goto error_dma_handle;
134 }
135
136 /*
137 * Map the memory
138 */
139 if ((dmaerr = ddi_dma_addr_bind_handle(dma->dmaHandle, NULL, dma->buf,
140 dma->bufLen, DDI_DMA_RDWR | DDI_DMA_STREAMING, cb, NULL, &cookie,
141 &cookieCount)) != DDI_DMA_MAPPED) {
142 VMXNET3_WARN(dp, "ddi_dma_addr_bind_handle() failed: %d",
143 dmaerr);
144 err = vmxnet3_dmaerr2errno(dmaerr);
145 goto error_dma_mem;
146 }
147
148 ASSERT(cookieCount == 1);
149 dma->bufPA = cookie.dmac_laddress;
150
151 return (0);
152
153 error_dma_mem:
154 ddi_dma_mem_free(&dma->dataHandle);
155 error_dma_handle:
156 ddi_dma_free_handle(&dma->dmaHandle);
157 error:
158 dma->buf = NULL;
159 dma->bufPA = 0;
160 dma->bufLen = 0;
161 return (err);
162 }
163
164 int
vmxnet3_alloc_dma_mem_1(vmxnet3_softc_t * dp,vmxnet3_dmabuf_t * dma,size_t size,boolean_t canSleep)165 vmxnet3_alloc_dma_mem_1(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma, size_t size,
166 boolean_t canSleep)
167 {
168 return (vmxnet3_alloc_dma_mem(dp, dma, size, canSleep,
169 &vmxnet3_dma_attrs_1));
170 }
171
172 int
vmxnet3_alloc_dma_mem_512(vmxnet3_softc_t * dp,vmxnet3_dmabuf_t * dma,size_t size,boolean_t canSleep)173 vmxnet3_alloc_dma_mem_512(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma,
174 size_t size, boolean_t canSleep)
175 {
176 return (vmxnet3_alloc_dma_mem(dp, dma, size, canSleep,
177 &vmxnet3_dma_attrs_512));
178 }
179
180 int
vmxnet3_alloc_dma_mem_128(vmxnet3_softc_t * dp,vmxnet3_dmabuf_t * dma,size_t size,boolean_t canSleep)181 vmxnet3_alloc_dma_mem_128(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma,
182 size_t size, boolean_t canSleep)
183 {
184 return (vmxnet3_alloc_dma_mem(dp, dma, size, canSleep,
185 &vmxnet3_dma_attrs_128));
186 }
187
188 /*
189 * Free DMA-ble memory.
190 */
191 void
vmxnet3_free_dma_mem(vmxnet3_dmabuf_t * dma)192 vmxnet3_free_dma_mem(vmxnet3_dmabuf_t *dma)
193 {
194 (void) ddi_dma_unbind_handle(dma->dmaHandle);
195 ddi_dma_mem_free(&dma->dataHandle);
196 ddi_dma_free_handle(&dma->dmaHandle);
197
198 dma->buf = NULL;
199 dma->bufPA = 0;
200 dma->bufLen = 0;
201 }
202
203 /*
204 * Get the numeric value of the property "name" in vmxnet3s.conf for
205 * the corresponding device instance.
206 * If the property isn't found or if it doesn't satisfy the conditions,
207 * "def" is returned.
208 *
209 * Returns:
210 * The value of the property or "def".
211 */
212 int
vmxnet3_getprop(vmxnet3_softc_t * dp,char * name,int min,int max,int def)213 vmxnet3_getprop(vmxnet3_softc_t *dp, char *name, int min, int max, int def)
214 {
215 int ret = def;
216 int *props;
217 uint_t nprops;
218
219 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dp->dip, DDI_PROP_DONTPASS,
220 name, &props, &nprops) == DDI_PROP_SUCCESS) {
221 if (dp->instance < nprops) {
222 ret = props[dp->instance];
223 } else {
224 VMXNET3_WARN(dp, "property %s not available for this "
225 "device\n", name);
226 }
227 ddi_prop_free(props);
228 }
229
230 if (ret < min || ret > max) {
231 ASSERT(def >= min && def <= max);
232 VMXNET3_WARN(dp, "property %s invalid (%d <= %d <= %d)\n",
233 name, min, ret, max);
234 ret = def;
235 }
236
237 VMXNET3_DEBUG(dp, 2, "getprop(%s) -> %d\n", name, ret);
238
239 return (ret);
240 }
241