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  */
156849994eSSebastien Roy /*
166849994eSSebastien Roy  * Copyright (c) 2016 by Delphix. All rights reserved.
176849994eSSebastien 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 
766849994eSSebastien Roy int
vmxnet3_dmaerr2errno(int dmaerr)776849994eSSebastien Roy vmxnet3_dmaerr2errno(int dmaerr)
786849994eSSebastien Roy {
796849994eSSebastien Roy 	int err;
806849994eSSebastien Roy 
816849994eSSebastien Roy 	switch (dmaerr) {
826849994eSSebastien Roy 	case DDI_DMA_NORESOURCES:
836849994eSSebastien Roy 	case DDI_DMA_TOOBIG:
846849994eSSebastien Roy 		err = ENOMEM;
856849994eSSebastien Roy 		break;
866849994eSSebastien Roy 	case DDI_DMA_INUSE:
876849994eSSebastien Roy 		err = EBUSY;
886849994eSSebastien Roy 		break;
896849994eSSebastien Roy 	case DDI_DMA_BADATTR:
906849994eSSebastien Roy 	case DDI_DMA_NOMAPPING:
916849994eSSebastien Roy 	default:
926849994eSSebastien Roy 		err = EINVAL;
936849994eSSebastien Roy 	}
946849994eSSebastien Roy 
956849994eSSebastien Roy 	return (err);
966849994eSSebastien Roy }
976849994eSSebastien Roy 
9862dadd65SYuri Pankov /*
99ca5345b6SSebastien Roy  * Allocate /size/ bytes of contiguous DMA-ble memory.
10062dadd65SYuri Pankov  *
101ca5345b6SSebastien Roy  * Returns:
1026849994eSSebastien Roy  *    0 on success, non-zero on failure.
10362dadd65SYuri Pankov  */
10462dadd65SYuri Pankov 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)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;
1106849994eSSebastien 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 	 */
1186849994eSSebastien Roy 	if ((dmaerr = ddi_dma_alloc_handle(dp->dip, dma_attrs, cb, NULL,
1196849994eSSebastien Roy 	    &dma->dmaHandle)) != DDI_SUCCESS) {
1206849994eSSebastien Roy 		VMXNET3_WARN(dp, "ddi_dma_alloc_handle() failed: %d", dmaerr);
1216849994eSSebastien 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) {
1316849994eSSebastien Roy 		VMXNET3_WARN(dp, "ddi_dma_mem_alloc() failed");
1326849994eSSebastien Roy 		err = ENOMEM;
13362dadd65SYuri Pankov 		goto error_dma_handle;
13462dadd65SYuri Pankov 	}
13562dadd65SYuri Pankov 
13662dadd65SYuri Pankov 	/*
13762dadd65SYuri Pankov 	 * Map the memory
13862dadd65SYuri Pankov 	 */
1396849994eSSebastien 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,
1416849994eSSebastien Roy 	    &cookieCount)) != DDI_DMA_MAPPED) {
1426849994eSSebastien Roy 		VMXNET3_WARN(dp, "ddi_dma_addr_bind_handle() failed: %d",
1436849994eSSebastien Roy 		    dmaerr);
1446849994eSSebastien 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 
1516849994eSSebastien 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;
159*40a73301SToomas Soome 	dma->bufPA = 0;
16062dadd65SYuri Pankov 	dma->bufLen = 0;
1616849994eSSebastien Roy 	return (err);
16262dadd65SYuri Pankov }
16362dadd65SYuri Pankov 
16462dadd65SYuri Pankov int
vmxnet3_alloc_dma_mem_1(vmxnet3_softc_t * dp,vmxnet3_dmabuf_t * dma,size_t size,boolean_t canSleep)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
vmxnet3_alloc_dma_mem_512(vmxnet3_softc_t * dp,vmxnet3_dmabuf_t * dma,size_t size,boolean_t canSleep)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
vmxnet3_alloc_dma_mem_128(vmxnet3_softc_t * dp,vmxnet3_dmabuf_t * dma,size_t size,boolean_t canSleep)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
vmxnet3_free_dma_mem(vmxnet3_dmabuf_t * dma)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;
199*40a73301SToomas Soome 	dma->bufPA = 0;
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
vmxnet3_getprop(vmxnet3_softc_t * dp,char * name,int min,int max,int def)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 }