/* * Copyright (C) 2007 VMware, Inc. All rights reserved. * * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. */ /* * Copyright (c) 2016 by Delphix. All rights reserved. */ #include /* Used by ddi_regs_map_setup() and ddi_dma_mem_alloc() */ ddi_device_acc_attr_t vmxnet3_dev_attr = { DDI_DEVICE_ATTR_V0, DDI_STRUCTURE_LE_ACC, DDI_STRICTORDER_ACC }; /* Buffers with no alignment constraint DMA description */ static ddi_dma_attr_t vmxnet3_dma_attrs_1 = { .dma_attr_version = DMA_ATTR_V0, .dma_attr_addr_lo = 0x0000000000000000ull, .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull, .dma_attr_count_max = 0xFFFFFFFFFFFFFFFFull, .dma_attr_align = 0x0000000000000001ull, .dma_attr_burstsizes = 0x0000000000000001ull, .dma_attr_minxfer = 0x00000001, .dma_attr_maxxfer = 0xFFFFFFFFFFFFFFFFull, .dma_attr_seg = 0xFFFFFFFFFFFFFFFFull, .dma_attr_sgllen = 1, .dma_attr_granular = 0x00000001, .dma_attr_flags = 0 }; /* Buffers with a 128-bytes alignment constraint DMA description */ static ddi_dma_attr_t vmxnet3_dma_attrs_128 = { .dma_attr_version = DMA_ATTR_V0, .dma_attr_addr_lo = 0x0000000000000000ull, .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull, .dma_attr_count_max = 0xFFFFFFFFFFFFFFFFull, .dma_attr_align = 0x0000000000000080ull, .dma_attr_burstsizes = 0x0000000000000001ull, .dma_attr_minxfer = 0x00000001, .dma_attr_maxxfer = 0xFFFFFFFFFFFFFFFFull, .dma_attr_seg = 0xFFFFFFFFFFFFFFFFull, .dma_attr_sgllen = 1, .dma_attr_granular = 0x00000001, .dma_attr_flags = 0 }; /* Buffers with a 512-bytes alignment constraint DMA description */ static ddi_dma_attr_t vmxnet3_dma_attrs_512 = { .dma_attr_version = DMA_ATTR_V0, .dma_attr_addr_lo = 0x0000000000000000ull, .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull, .dma_attr_count_max = 0xFFFFFFFFFFFFFFFFull, .dma_attr_align = 0x0000000000000200ull, .dma_attr_burstsizes = 0x0000000000000001ull, .dma_attr_minxfer = 0x00000001, .dma_attr_maxxfer = 0xFFFFFFFFFFFFFFFFull, .dma_attr_seg = 0xFFFFFFFFFFFFFFFFull, .dma_attr_sgllen = 1, .dma_attr_granular = 0x00000001, .dma_attr_flags = 0 }; int vmxnet3_dmaerr2errno(int dmaerr) { int err; switch (dmaerr) { case DDI_DMA_NORESOURCES: case DDI_DMA_TOOBIG: err = ENOMEM; break; case DDI_DMA_INUSE: err = EBUSY; break; case DDI_DMA_BADATTR: case DDI_DMA_NOMAPPING: default: err = EINVAL; } return (err); } /* * Allocate /size/ bytes of contiguous DMA-ble memory. * * Returns: * 0 on success, non-zero on failure. */ 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) { ddi_dma_cookie_t cookie; uint_t cookieCount; int dmaerr, err = 0; int (*cb) (caddr_t) = canSleep ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT; ASSERT(size != 0); /* * Allocate a DMA handle */ if ((dmaerr = ddi_dma_alloc_handle(dp->dip, dma_attrs, cb, NULL, &dma->dmaHandle)) != DDI_SUCCESS) { VMXNET3_WARN(dp, "ddi_dma_alloc_handle() failed: %d", dmaerr); err = vmxnet3_dmaerr2errno(dmaerr); goto error; } /* * Allocate memory */ if (ddi_dma_mem_alloc(dma->dmaHandle, size, &vmxnet3_dev_attr, DDI_DMA_CONSISTENT, cb, NULL, &dma->buf, &dma->bufLen, &dma->dataHandle) != DDI_SUCCESS) { VMXNET3_WARN(dp, "ddi_dma_mem_alloc() failed"); err = ENOMEM; goto error_dma_handle; } /* * Map the memory */ if ((dmaerr = ddi_dma_addr_bind_handle(dma->dmaHandle, NULL, dma->buf, dma->bufLen, DDI_DMA_RDWR | DDI_DMA_STREAMING, cb, NULL, &cookie, &cookieCount)) != DDI_DMA_MAPPED) { VMXNET3_WARN(dp, "ddi_dma_addr_bind_handle() failed: %d", dmaerr); err = vmxnet3_dmaerr2errno(dmaerr); goto error_dma_mem; } ASSERT(cookieCount == 1); dma->bufPA = cookie.dmac_laddress; return (0); error_dma_mem: ddi_dma_mem_free(&dma->dataHandle); error_dma_handle: ddi_dma_free_handle(&dma->dmaHandle); error: dma->buf = NULL; dma->bufPA = 0; dma->bufLen = 0; return (err); } int vmxnet3_alloc_dma_mem_1(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma, size_t size, boolean_t canSleep) { return (vmxnet3_alloc_dma_mem(dp, dma, size, canSleep, &vmxnet3_dma_attrs_1)); } int vmxnet3_alloc_dma_mem_512(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma, size_t size, boolean_t canSleep) { return (vmxnet3_alloc_dma_mem(dp, dma, size, canSleep, &vmxnet3_dma_attrs_512)); } int vmxnet3_alloc_dma_mem_128(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma, size_t size, boolean_t canSleep) { return (vmxnet3_alloc_dma_mem(dp, dma, size, canSleep, &vmxnet3_dma_attrs_128)); } /* * Free DMA-ble memory. */ void vmxnet3_free_dma_mem(vmxnet3_dmabuf_t *dma) { (void) ddi_dma_unbind_handle(dma->dmaHandle); ddi_dma_mem_free(&dma->dataHandle); ddi_dma_free_handle(&dma->dmaHandle); dma->buf = NULL; dma->bufPA = 0; dma->bufLen = 0; } /* * Get the numeric value of the property "name" in vmxnet3s.conf for * the corresponding device instance. * If the property isn't found or if it doesn't satisfy the conditions, * "def" is returned. * * Returns: * The value of the property or "def". */ int vmxnet3_getprop(vmxnet3_softc_t *dp, char *name, int min, int max, int def) { int ret = def; int *props; uint_t nprops; if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dp->dip, DDI_PROP_DONTPASS, name, &props, &nprops) == DDI_PROP_SUCCESS) { if (dp->instance < nprops) { ret = props[dp->instance]; } else { VMXNET3_WARN(dp, "property %s not available for this " "device\n", name); } ddi_prop_free(props); } if (ret < min || ret > max) { ASSERT(def >= min && def <= max); VMXNET3_WARN(dp, "property %s invalid (%d <= %d <= %d)\n", name, min, ret, max); ret = def; } VMXNET3_DEBUG(dp, 2, "getprop(%s) -> %d\n", name, ret); return (ret); }