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