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 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 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 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 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 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 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 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