162dadd65SYuri Pankov /* 262dadd65SYuri Pankov * Copyright (C) 2007 VMware, Inc. All rights reserved. 362dadd65SYuri Pankov * 462dadd65SYuri Pankov * The contents of this file are subject to the terms of the Common 562dadd65SYuri Pankov * Development and Distribution License (the "License") version 1.0 662dadd65SYuri Pankov * and no later version. You may not use this file except in 762dadd65SYuri Pankov * compliance with the License. 862dadd65SYuri Pankov * 962dadd65SYuri Pankov * You can obtain a copy of the License at 1062dadd65SYuri Pankov * http://www.opensource.org/licenses/cddl1.php 1162dadd65SYuri Pankov * 1262dadd65SYuri Pankov * See the License for the specific language governing permissions 1362dadd65SYuri Pankov * and limitations under the License. 1462dadd65SYuri Pankov */ 15*6849994eSSebastien Roy /* 16*6849994eSSebastien Roy * Copyright (c) 2016 by Delphix. All rights reserved. 17*6849994eSSebastien Roy */ 1862dadd65SYuri Pankov 1962dadd65SYuri Pankov #include <vmxnet3.h> 2062dadd65SYuri Pankov 2162dadd65SYuri Pankov /* Used by ddi_regs_map_setup() and ddi_dma_mem_alloc() */ 2262dadd65SYuri Pankov ddi_device_acc_attr_t vmxnet3_dev_attr = { 2362dadd65SYuri Pankov DDI_DEVICE_ATTR_V0, 2462dadd65SYuri Pankov DDI_STRUCTURE_LE_ACC, 2562dadd65SYuri Pankov DDI_STRICTORDER_ACC 2662dadd65SYuri Pankov }; 2762dadd65SYuri Pankov 2862dadd65SYuri Pankov /* Buffers with no alignment constraint DMA description */ 2962dadd65SYuri Pankov static ddi_dma_attr_t vmxnet3_dma_attrs_1 = { 3062dadd65SYuri Pankov .dma_attr_version = DMA_ATTR_V0, 3162dadd65SYuri Pankov .dma_attr_addr_lo = 0x0000000000000000ull, 3262dadd65SYuri Pankov .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull, 3362dadd65SYuri Pankov .dma_attr_count_max = 0xFFFFFFFFFFFFFFFFull, 3462dadd65SYuri Pankov .dma_attr_align = 0x0000000000000001ull, 3562dadd65SYuri Pankov .dma_attr_burstsizes = 0x0000000000000001ull, 3662dadd65SYuri Pankov .dma_attr_minxfer = 0x00000001, 3762dadd65SYuri Pankov .dma_attr_maxxfer = 0xFFFFFFFFFFFFFFFFull, 3862dadd65SYuri Pankov .dma_attr_seg = 0xFFFFFFFFFFFFFFFFull, 3962dadd65SYuri Pankov .dma_attr_sgllen = 1, 4062dadd65SYuri Pankov .dma_attr_granular = 0x00000001, 4162dadd65SYuri Pankov .dma_attr_flags = 0 4262dadd65SYuri Pankov }; 4362dadd65SYuri Pankov 4462dadd65SYuri Pankov /* Buffers with a 128-bytes alignment constraint DMA description */ 4562dadd65SYuri Pankov static ddi_dma_attr_t vmxnet3_dma_attrs_128 = { 4662dadd65SYuri Pankov .dma_attr_version = DMA_ATTR_V0, 4762dadd65SYuri Pankov .dma_attr_addr_lo = 0x0000000000000000ull, 4862dadd65SYuri Pankov .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull, 4962dadd65SYuri Pankov .dma_attr_count_max = 0xFFFFFFFFFFFFFFFFull, 5062dadd65SYuri Pankov .dma_attr_align = 0x0000000000000080ull, 5162dadd65SYuri Pankov .dma_attr_burstsizes = 0x0000000000000001ull, 5262dadd65SYuri Pankov .dma_attr_minxfer = 0x00000001, 5362dadd65SYuri Pankov .dma_attr_maxxfer = 0xFFFFFFFFFFFFFFFFull, 5462dadd65SYuri Pankov .dma_attr_seg = 0xFFFFFFFFFFFFFFFFull, 5562dadd65SYuri Pankov .dma_attr_sgllen = 1, 5662dadd65SYuri Pankov .dma_attr_granular = 0x00000001, 5762dadd65SYuri Pankov .dma_attr_flags = 0 5862dadd65SYuri Pankov }; 5962dadd65SYuri Pankov 6062dadd65SYuri Pankov /* Buffers with a 512-bytes alignment constraint DMA description */ 6162dadd65SYuri Pankov static ddi_dma_attr_t vmxnet3_dma_attrs_512 = { 6262dadd65SYuri Pankov .dma_attr_version = DMA_ATTR_V0, 6362dadd65SYuri Pankov .dma_attr_addr_lo = 0x0000000000000000ull, 6462dadd65SYuri Pankov .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull, 6562dadd65SYuri Pankov .dma_attr_count_max = 0xFFFFFFFFFFFFFFFFull, 6662dadd65SYuri Pankov .dma_attr_align = 0x0000000000000200ull, 6762dadd65SYuri Pankov .dma_attr_burstsizes = 0x0000000000000001ull, 6862dadd65SYuri Pankov .dma_attr_minxfer = 0x00000001, 6962dadd65SYuri Pankov .dma_attr_maxxfer = 0xFFFFFFFFFFFFFFFFull, 7062dadd65SYuri Pankov .dma_attr_seg = 0xFFFFFFFFFFFFFFFFull, 7162dadd65SYuri Pankov .dma_attr_sgllen = 1, 7262dadd65SYuri Pankov .dma_attr_granular = 0x00000001, 7362dadd65SYuri Pankov .dma_attr_flags = 0 7462dadd65SYuri Pankov }; 7562dadd65SYuri Pankov 76*6849994eSSebastien Roy int 77*6849994eSSebastien Roy vmxnet3_dmaerr2errno(int dmaerr) 78*6849994eSSebastien Roy { 79*6849994eSSebastien Roy int err; 80*6849994eSSebastien Roy 81*6849994eSSebastien Roy switch (dmaerr) { 82*6849994eSSebastien Roy case DDI_DMA_NORESOURCES: 83*6849994eSSebastien Roy case DDI_DMA_TOOBIG: 84*6849994eSSebastien Roy err = ENOMEM; 85*6849994eSSebastien Roy break; 86*6849994eSSebastien Roy case DDI_DMA_INUSE: 87*6849994eSSebastien Roy err = EBUSY; 88*6849994eSSebastien Roy break; 89*6849994eSSebastien Roy case DDI_DMA_BADATTR: 90*6849994eSSebastien Roy case DDI_DMA_NOMAPPING: 91*6849994eSSebastien Roy default: 92*6849994eSSebastien Roy err = EINVAL; 93*6849994eSSebastien Roy } 94*6849994eSSebastien Roy 95*6849994eSSebastien Roy return (err); 96*6849994eSSebastien Roy } 97*6849994eSSebastien Roy 9862dadd65SYuri Pankov /* 99ca5345b6SSebastien Roy * Allocate /size/ bytes of contiguous DMA-ble memory. 10062dadd65SYuri Pankov * 101ca5345b6SSebastien Roy * Returns: 102*6849994eSSebastien Roy * 0 on success, non-zero on failure. 10362dadd65SYuri Pankov */ 10462dadd65SYuri Pankov static int 10562dadd65SYuri Pankov vmxnet3_alloc_dma_mem(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma, size_t size, 10662dadd65SYuri Pankov boolean_t canSleep, ddi_dma_attr_t *dma_attrs) 10762dadd65SYuri Pankov { 10862dadd65SYuri Pankov ddi_dma_cookie_t cookie; 10962dadd65SYuri Pankov uint_t cookieCount; 110*6849994eSSebastien Roy int dmaerr, err = 0; 11162dadd65SYuri Pankov int (*cb) (caddr_t) = canSleep ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT; 11262dadd65SYuri Pankov 11362dadd65SYuri Pankov ASSERT(size != 0); 11462dadd65SYuri Pankov 11562dadd65SYuri Pankov /* 11662dadd65SYuri Pankov * Allocate a DMA handle 11762dadd65SYuri Pankov */ 118*6849994eSSebastien Roy if ((dmaerr = ddi_dma_alloc_handle(dp->dip, dma_attrs, cb, NULL, 119*6849994eSSebastien Roy &dma->dmaHandle)) != DDI_SUCCESS) { 120*6849994eSSebastien Roy VMXNET3_WARN(dp, "ddi_dma_alloc_handle() failed: %d", dmaerr); 121*6849994eSSebastien Roy err = vmxnet3_dmaerr2errno(dmaerr); 12262dadd65SYuri Pankov goto error; 12362dadd65SYuri Pankov } 12462dadd65SYuri Pankov 12562dadd65SYuri Pankov /* 12662dadd65SYuri Pankov * Allocate memory 12762dadd65SYuri Pankov */ 12862dadd65SYuri Pankov if (ddi_dma_mem_alloc(dma->dmaHandle, size, &vmxnet3_dev_attr, 12962dadd65SYuri Pankov DDI_DMA_CONSISTENT, cb, NULL, &dma->buf, &dma->bufLen, 13062dadd65SYuri Pankov &dma->dataHandle) != DDI_SUCCESS) { 131*6849994eSSebastien Roy VMXNET3_WARN(dp, "ddi_dma_mem_alloc() failed"); 132*6849994eSSebastien Roy err = ENOMEM; 13362dadd65SYuri Pankov goto error_dma_handle; 13462dadd65SYuri Pankov } 13562dadd65SYuri Pankov 13662dadd65SYuri Pankov /* 13762dadd65SYuri Pankov * Map the memory 13862dadd65SYuri Pankov */ 139*6849994eSSebastien Roy if ((dmaerr = ddi_dma_addr_bind_handle(dma->dmaHandle, NULL, dma->buf, 14062dadd65SYuri Pankov dma->bufLen, DDI_DMA_RDWR | DDI_DMA_STREAMING, cb, NULL, &cookie, 141*6849994eSSebastien Roy &cookieCount)) != DDI_DMA_MAPPED) { 142*6849994eSSebastien Roy VMXNET3_WARN(dp, "ddi_dma_addr_bind_handle() failed: %d", 143*6849994eSSebastien Roy dmaerr); 144*6849994eSSebastien Roy err = vmxnet3_dmaerr2errno(dmaerr); 14562dadd65SYuri Pankov goto error_dma_mem; 14662dadd65SYuri Pankov } 14762dadd65SYuri Pankov 14862dadd65SYuri Pankov ASSERT(cookieCount == 1); 14962dadd65SYuri Pankov dma->bufPA = cookie.dmac_laddress; 15062dadd65SYuri Pankov 151*6849994eSSebastien Roy return (0); 15262dadd65SYuri Pankov 15362dadd65SYuri Pankov error_dma_mem: 15462dadd65SYuri Pankov ddi_dma_mem_free(&dma->dataHandle); 15562dadd65SYuri Pankov error_dma_handle: 15662dadd65SYuri Pankov ddi_dma_free_handle(&dma->dmaHandle); 15762dadd65SYuri Pankov error: 15862dadd65SYuri Pankov dma->buf = NULL; 15962dadd65SYuri Pankov dma->bufPA = NULL; 16062dadd65SYuri Pankov dma->bufLen = 0; 161*6849994eSSebastien Roy return (err); 16262dadd65SYuri Pankov } 16362dadd65SYuri Pankov 16462dadd65SYuri Pankov int 16562dadd65SYuri Pankov vmxnet3_alloc_dma_mem_1(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma, size_t size, 16662dadd65SYuri Pankov boolean_t canSleep) 16762dadd65SYuri Pankov { 16862dadd65SYuri Pankov return (vmxnet3_alloc_dma_mem(dp, dma, size, canSleep, 16962dadd65SYuri Pankov &vmxnet3_dma_attrs_1)); 17062dadd65SYuri Pankov } 17162dadd65SYuri Pankov 17262dadd65SYuri Pankov int 17362dadd65SYuri Pankov vmxnet3_alloc_dma_mem_512(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma, 17462dadd65SYuri Pankov size_t size, boolean_t canSleep) 17562dadd65SYuri Pankov { 17662dadd65SYuri Pankov return (vmxnet3_alloc_dma_mem(dp, dma, size, canSleep, 17762dadd65SYuri Pankov &vmxnet3_dma_attrs_512)); 17862dadd65SYuri Pankov } 17962dadd65SYuri Pankov 18062dadd65SYuri Pankov int 18162dadd65SYuri Pankov vmxnet3_alloc_dma_mem_128(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma, 18262dadd65SYuri Pankov size_t size, boolean_t canSleep) 18362dadd65SYuri Pankov { 18462dadd65SYuri Pankov return (vmxnet3_alloc_dma_mem(dp, dma, size, canSleep, 18562dadd65SYuri Pankov &vmxnet3_dma_attrs_128)); 18662dadd65SYuri Pankov } 18762dadd65SYuri Pankov 18862dadd65SYuri Pankov /* 189ca5345b6SSebastien Roy * Free DMA-ble memory. 19062dadd65SYuri Pankov */ 19162dadd65SYuri Pankov void 19262dadd65SYuri Pankov vmxnet3_free_dma_mem(vmxnet3_dmabuf_t *dma) 19362dadd65SYuri Pankov { 19462dadd65SYuri Pankov (void) ddi_dma_unbind_handle(dma->dmaHandle); 19562dadd65SYuri Pankov ddi_dma_mem_free(&dma->dataHandle); 19662dadd65SYuri Pankov ddi_dma_free_handle(&dma->dmaHandle); 19762dadd65SYuri Pankov 19862dadd65SYuri Pankov dma->buf = NULL; 19962dadd65SYuri Pankov dma->bufPA = NULL; 20062dadd65SYuri Pankov dma->bufLen = 0; 20162dadd65SYuri Pankov } 20262dadd65SYuri Pankov 20362dadd65SYuri Pankov /* 204ca5345b6SSebastien Roy * Get the numeric value of the property "name" in vmxnet3s.conf for 205ca5345b6SSebastien Roy * the corresponding device instance. 206ca5345b6SSebastien Roy * If the property isn't found or if it doesn't satisfy the conditions, 207ca5345b6SSebastien Roy * "def" is returned. 20862dadd65SYuri Pankov * 209ca5345b6SSebastien Roy * Returns: 210ca5345b6SSebastien Roy * The value of the property or "def". 21162dadd65SYuri Pankov */ 21262dadd65SYuri Pankov int 21362dadd65SYuri Pankov vmxnet3_getprop(vmxnet3_softc_t *dp, char *name, int min, int max, int def) 21462dadd65SYuri Pankov { 21562dadd65SYuri Pankov int ret = def; 21662dadd65SYuri Pankov int *props; 21762dadd65SYuri Pankov uint_t nprops; 21862dadd65SYuri Pankov 21962dadd65SYuri Pankov if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dp->dip, DDI_PROP_DONTPASS, 22062dadd65SYuri Pankov name, &props, &nprops) == DDI_PROP_SUCCESS) { 22162dadd65SYuri Pankov if (dp->instance < nprops) { 22262dadd65SYuri Pankov ret = props[dp->instance]; 22362dadd65SYuri Pankov } else { 22462dadd65SYuri Pankov VMXNET3_WARN(dp, "property %s not available for this " 22562dadd65SYuri Pankov "device\n", name); 22662dadd65SYuri Pankov } 22762dadd65SYuri Pankov ddi_prop_free(props); 22862dadd65SYuri Pankov } 22962dadd65SYuri Pankov 23062dadd65SYuri Pankov if (ret < min || ret > max) { 23162dadd65SYuri Pankov ASSERT(def >= min && def <= max); 23262dadd65SYuri Pankov VMXNET3_WARN(dp, "property %s invalid (%d <= %d <= %d)\n", 23362dadd65SYuri Pankov name, min, ret, max); 23462dadd65SYuri Pankov ret = def; 23562dadd65SYuri Pankov } 23662dadd65SYuri Pankov 23762dadd65SYuri Pankov VMXNET3_DEBUG(dp, 2, "getprop(%s) -> %d\n", name, ret); 23862dadd65SYuri Pankov 23962dadd65SYuri Pankov return (ret); 24062dadd65SYuri Pankov } 241