1*ebb7c6fdSAlex Wilson /*
2*ebb7c6fdSAlex Wilson  * This file and its contents are supplied under the terms of the
3*ebb7c6fdSAlex Wilson  * Common Development and Distribution License ("CDDL"), version 1.0.
4*ebb7c6fdSAlex Wilson  * You may only use this file in accordance with the terms of version
5*ebb7c6fdSAlex Wilson  * 1.0 of the CDDL.
6*ebb7c6fdSAlex Wilson  *
7*ebb7c6fdSAlex Wilson  * A full copy of the text of the CDDL should have accompanied this
8*ebb7c6fdSAlex Wilson  * source.  A copy of the CDDL is also available via the Internet at
9*ebb7c6fdSAlex Wilson  * http://www.illumos.org/license/CDDL.
10*ebb7c6fdSAlex Wilson  */
11*ebb7c6fdSAlex Wilson 
12*ebb7c6fdSAlex Wilson /*
13*ebb7c6fdSAlex Wilson  * Copyright 2020, The University of Queensland
14*ebb7c6fdSAlex Wilson  * Copyright (c) 2018, Joyent, Inc.
15*ebb7c6fdSAlex Wilson  */
16*ebb7c6fdSAlex Wilson 
17*ebb7c6fdSAlex Wilson /*
18*ebb7c6fdSAlex Wilson  * DMA allocation and tear down routines.
19*ebb7c6fdSAlex Wilson  */
20*ebb7c6fdSAlex Wilson 
21*ebb7c6fdSAlex Wilson #include <mlxcx.h>
22*ebb7c6fdSAlex Wilson 
23*ebb7c6fdSAlex Wilson void
mlxcx_dma_acc_attr(mlxcx_t * mlxp,ddi_device_acc_attr_t * accp)24*ebb7c6fdSAlex Wilson mlxcx_dma_acc_attr(mlxcx_t *mlxp, ddi_device_acc_attr_t *accp)
25*ebb7c6fdSAlex Wilson {
26*ebb7c6fdSAlex Wilson 	bzero(accp, sizeof (*accp));
27*ebb7c6fdSAlex Wilson 	accp->devacc_attr_version = DDI_DEVICE_ATTR_V0;
28*ebb7c6fdSAlex Wilson 	accp->devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
29*ebb7c6fdSAlex Wilson 	accp->devacc_attr_dataorder = DDI_STRICTORDER_ACC;
30*ebb7c6fdSAlex Wilson 
31*ebb7c6fdSAlex Wilson 	if (DDI_FM_DMA_ERR_CAP(mlxp->mlx_fm_caps)) {
32*ebb7c6fdSAlex Wilson 		accp->devacc_attr_access = DDI_FLAGERR_ACC;
33*ebb7c6fdSAlex Wilson 	} else {
34*ebb7c6fdSAlex Wilson 		accp->devacc_attr_access = DDI_DEFAULT_ACC;
35*ebb7c6fdSAlex Wilson 	}
36*ebb7c6fdSAlex Wilson }
37*ebb7c6fdSAlex Wilson 
38*ebb7c6fdSAlex Wilson void
mlxcx_dma_page_attr(mlxcx_t * mlxp,ddi_dma_attr_t * attrp)39*ebb7c6fdSAlex Wilson mlxcx_dma_page_attr(mlxcx_t *mlxp, ddi_dma_attr_t *attrp)
40*ebb7c6fdSAlex Wilson {
41*ebb7c6fdSAlex Wilson 	bzero(attrp, sizeof (*attrp));
42*ebb7c6fdSAlex Wilson 	attrp->dma_attr_version = DMA_ATTR_V0;
43*ebb7c6fdSAlex Wilson 
44*ebb7c6fdSAlex Wilson 	/*
45*ebb7c6fdSAlex Wilson 	 * This is a 64-bit PCIe device. We can use the entire address space.
46*ebb7c6fdSAlex Wilson 	 */
47*ebb7c6fdSAlex Wilson 	attrp->dma_attr_addr_lo = 0x0;
48*ebb7c6fdSAlex Wilson 	attrp->dma_attr_addr_hi = UINT64_MAX;
49*ebb7c6fdSAlex Wilson 
50*ebb7c6fdSAlex Wilson 	/*
51*ebb7c6fdSAlex Wilson 	 * The count max indicates the total amount that can fit into one
52*ebb7c6fdSAlex Wilson 	 * cookie. Because we're creating a single page for tracking purposes,
53*ebb7c6fdSAlex Wilson 	 * this can be a page in size. The alignment and segment are related to
54*ebb7c6fdSAlex Wilson 	 * this same requirement. The alignment needs to be page aligned and the
55*ebb7c6fdSAlex Wilson 	 * segment is the boundary that this can't cross, aka a 4k page.
56*ebb7c6fdSAlex Wilson 	 */
57*ebb7c6fdSAlex Wilson 	attrp->dma_attr_count_max = MLXCX_CMD_DMA_PAGE_SIZE - 1;
58*ebb7c6fdSAlex Wilson 	attrp->dma_attr_align = MLXCX_CMD_DMA_PAGE_SIZE;
59*ebb7c6fdSAlex Wilson 	attrp->dma_attr_seg = MLXCX_CMD_DMA_PAGE_SIZE - 1;
60*ebb7c6fdSAlex Wilson 
61*ebb7c6fdSAlex Wilson 	attrp->dma_attr_burstsizes = 0xfff;
62*ebb7c6fdSAlex Wilson 
63*ebb7c6fdSAlex Wilson 	/*
64*ebb7c6fdSAlex Wilson 	 * The minimum and and maximum sizes that we can send. We cap this based
65*ebb7c6fdSAlex Wilson 	 * on the use of this, which is a page size.
66*ebb7c6fdSAlex Wilson 	 */
67*ebb7c6fdSAlex Wilson 	attrp->dma_attr_minxfer = 0x1;
68*ebb7c6fdSAlex Wilson 	attrp->dma_attr_maxxfer = MLXCX_CMD_DMA_PAGE_SIZE;
69*ebb7c6fdSAlex Wilson 
70*ebb7c6fdSAlex Wilson 	/*
71*ebb7c6fdSAlex Wilson 	 * This is supposed to be used for static data structures, therefore we
72*ebb7c6fdSAlex Wilson 	 * keep this just to a page.
73*ebb7c6fdSAlex Wilson 	 */
74*ebb7c6fdSAlex Wilson 	attrp->dma_attr_sgllen = 1;
75*ebb7c6fdSAlex Wilson 
76*ebb7c6fdSAlex Wilson 	/*
77*ebb7c6fdSAlex Wilson 	 * The granularity describe the addressing graularity. That is, the
78*ebb7c6fdSAlex Wilson 	 * hardware can ask for chunks in this units of bytes.
79*ebb7c6fdSAlex Wilson 	 */
80*ebb7c6fdSAlex Wilson 	attrp->dma_attr_granular = MLXCX_CMD_DMA_PAGE_SIZE;
81*ebb7c6fdSAlex Wilson 
82*ebb7c6fdSAlex Wilson 	if (DDI_FM_DMA_ERR_CAP(mlxp->mlx_fm_caps)) {
83*ebb7c6fdSAlex Wilson 		attrp->dma_attr_flags = DDI_DMA_FLAGERR;
84*ebb7c6fdSAlex Wilson 	} else {
85*ebb7c6fdSAlex Wilson 		attrp->dma_attr_flags = 0;
86*ebb7c6fdSAlex Wilson 	}
87*ebb7c6fdSAlex Wilson }
88*ebb7c6fdSAlex Wilson 
89*ebb7c6fdSAlex Wilson /*
90*ebb7c6fdSAlex Wilson  * DMA attributes for queue memory (EQ, CQ, WQ etc)
91*ebb7c6fdSAlex Wilson  *
92*ebb7c6fdSAlex Wilson  * These have to allocate in units of whole pages, but can be multiple
93*ebb7c6fdSAlex Wilson  * pages and don't have to be physically contiguous.
94*ebb7c6fdSAlex Wilson  */
95*ebb7c6fdSAlex Wilson void
mlxcx_dma_queue_attr(mlxcx_t * mlxp,ddi_dma_attr_t * attrp)96*ebb7c6fdSAlex Wilson mlxcx_dma_queue_attr(mlxcx_t *mlxp, ddi_dma_attr_t *attrp)
97*ebb7c6fdSAlex Wilson {
98*ebb7c6fdSAlex Wilson 	bzero(attrp, sizeof (*attrp));
99*ebb7c6fdSAlex Wilson 	attrp->dma_attr_version = DMA_ATTR_V0;
100*ebb7c6fdSAlex Wilson 
101*ebb7c6fdSAlex Wilson 	/*
102*ebb7c6fdSAlex Wilson 	 * This is a 64-bit PCIe device. We can use the entire address space.
103*ebb7c6fdSAlex Wilson 	 */
104*ebb7c6fdSAlex Wilson 	attrp->dma_attr_addr_lo = 0x0;
105*ebb7c6fdSAlex Wilson 	attrp->dma_attr_addr_hi = UINT64_MAX;
106*ebb7c6fdSAlex Wilson 
107*ebb7c6fdSAlex Wilson 	attrp->dma_attr_count_max = MLXCX_QUEUE_DMA_PAGE_SIZE - 1;
108*ebb7c6fdSAlex Wilson 
109*ebb7c6fdSAlex Wilson 	attrp->dma_attr_align = MLXCX_QUEUE_DMA_PAGE_SIZE;
110*ebb7c6fdSAlex Wilson 
111*ebb7c6fdSAlex Wilson 	attrp->dma_attr_burstsizes = 0xfff;
112*ebb7c6fdSAlex Wilson 
113*ebb7c6fdSAlex Wilson 	/*
114*ebb7c6fdSAlex Wilson 	 * The minimum and and maximum sizes that we can send. We cap this based
115*ebb7c6fdSAlex Wilson 	 * on the use of this, which is a page size.
116*ebb7c6fdSAlex Wilson 	 */
117*ebb7c6fdSAlex Wilson 	attrp->dma_attr_minxfer = MLXCX_QUEUE_DMA_PAGE_SIZE;
118*ebb7c6fdSAlex Wilson 	attrp->dma_attr_maxxfer = UINT32_MAX;
119*ebb7c6fdSAlex Wilson 
120*ebb7c6fdSAlex Wilson 	attrp->dma_attr_seg = UINT64_MAX;
121*ebb7c6fdSAlex Wilson 
122*ebb7c6fdSAlex Wilson 	attrp->dma_attr_granular = MLXCX_QUEUE_DMA_PAGE_SIZE;
123*ebb7c6fdSAlex Wilson 
124*ebb7c6fdSAlex Wilson 	/* But we can have more than one. */
125*ebb7c6fdSAlex Wilson 	attrp->dma_attr_sgllen = MLXCX_CREATE_QUEUE_MAX_PAGES;
126*ebb7c6fdSAlex Wilson 
127*ebb7c6fdSAlex Wilson 	if (DDI_FM_DMA_ERR_CAP(mlxp->mlx_fm_caps)) {
128*ebb7c6fdSAlex Wilson 		attrp->dma_attr_flags = DDI_DMA_FLAGERR;
129*ebb7c6fdSAlex Wilson 	} else {
130*ebb7c6fdSAlex Wilson 		attrp->dma_attr_flags = 0;
131*ebb7c6fdSAlex Wilson 	}
132*ebb7c6fdSAlex Wilson }
133*ebb7c6fdSAlex Wilson 
134*ebb7c6fdSAlex Wilson /*
135*ebb7c6fdSAlex Wilson  * DMA attributes for packet buffers
136*ebb7c6fdSAlex Wilson  */
137*ebb7c6fdSAlex Wilson void
mlxcx_dma_buf_attr(mlxcx_t * mlxp,ddi_dma_attr_t * attrp)138*ebb7c6fdSAlex Wilson mlxcx_dma_buf_attr(mlxcx_t *mlxp, ddi_dma_attr_t *attrp)
139*ebb7c6fdSAlex Wilson {
140*ebb7c6fdSAlex Wilson 	bzero(attrp, sizeof (*attrp));
141*ebb7c6fdSAlex Wilson 	attrp->dma_attr_version = DMA_ATTR_V0;
142*ebb7c6fdSAlex Wilson 
143*ebb7c6fdSAlex Wilson 	/*
144*ebb7c6fdSAlex Wilson 	 * This is a 64-bit PCIe device. We can use the entire address space.
145*ebb7c6fdSAlex Wilson 	 */
146*ebb7c6fdSAlex Wilson 	attrp->dma_attr_addr_lo = 0x0;
147*ebb7c6fdSAlex Wilson 	attrp->dma_attr_addr_hi = UINT64_MAX;
148*ebb7c6fdSAlex Wilson 
149*ebb7c6fdSAlex Wilson 	/*
150*ebb7c6fdSAlex Wilson 	 * Each scatter pointer has a 32-bit length field.
151*ebb7c6fdSAlex Wilson 	 */
152*ebb7c6fdSAlex Wilson 	attrp->dma_attr_count_max = UINT32_MAX;
153*ebb7c6fdSAlex Wilson 
154*ebb7c6fdSAlex Wilson 	/*
155*ebb7c6fdSAlex Wilson 	 * The PRM gives us no alignment requirements for scatter pointers,
156*ebb7c6fdSAlex Wilson 	 * but it implies that units < 16bytes are a bad idea.
157*ebb7c6fdSAlex Wilson 	 */
158*ebb7c6fdSAlex Wilson 	attrp->dma_attr_align = 16;
159*ebb7c6fdSAlex Wilson 	attrp->dma_attr_granular = 1;
160*ebb7c6fdSAlex Wilson 
161*ebb7c6fdSAlex Wilson 	attrp->dma_attr_burstsizes = 0xfff;
162*ebb7c6fdSAlex Wilson 
163*ebb7c6fdSAlex Wilson 	attrp->dma_attr_minxfer = 1;
164*ebb7c6fdSAlex Wilson 	attrp->dma_attr_maxxfer = UINT64_MAX;
165*ebb7c6fdSAlex Wilson 
166*ebb7c6fdSAlex Wilson 	attrp->dma_attr_seg = UINT64_MAX;
167*ebb7c6fdSAlex Wilson 
168*ebb7c6fdSAlex Wilson 	/*
169*ebb7c6fdSAlex Wilson 	 * We choose how many scatter pointers we're allowed per packet when
170*ebb7c6fdSAlex Wilson 	 * we set the recv queue stride. This macro is from mlxcx_reg.h where
171*ebb7c6fdSAlex Wilson 	 * we fix that for all of our receive queues.
172*ebb7c6fdSAlex Wilson 	 */
173*ebb7c6fdSAlex Wilson 	attrp->dma_attr_sgllen = MLXCX_RECVQ_MAX_PTRS;
174*ebb7c6fdSAlex Wilson 
175*ebb7c6fdSAlex Wilson 	if (DDI_FM_DMA_ERR_CAP(mlxp->mlx_fm_caps)) {
176*ebb7c6fdSAlex Wilson 		attrp->dma_attr_flags = DDI_DMA_FLAGERR;
177*ebb7c6fdSAlex Wilson 	} else {
178*ebb7c6fdSAlex Wilson 		attrp->dma_attr_flags = 0;
179*ebb7c6fdSAlex Wilson 	}
180*ebb7c6fdSAlex Wilson }
181*ebb7c6fdSAlex Wilson 
182*ebb7c6fdSAlex Wilson /*
183*ebb7c6fdSAlex Wilson  * DMA attributes for queue doorbells
184*ebb7c6fdSAlex Wilson  */
185*ebb7c6fdSAlex Wilson void
mlxcx_dma_qdbell_attr(mlxcx_t * mlxp,ddi_dma_attr_t * attrp)186*ebb7c6fdSAlex Wilson mlxcx_dma_qdbell_attr(mlxcx_t *mlxp, ddi_dma_attr_t *attrp)
187*ebb7c6fdSAlex Wilson {
188*ebb7c6fdSAlex Wilson 	bzero(attrp, sizeof (*attrp));
189*ebb7c6fdSAlex Wilson 	attrp->dma_attr_version = DMA_ATTR_V0;
190*ebb7c6fdSAlex Wilson 
191*ebb7c6fdSAlex Wilson 	/*
192*ebb7c6fdSAlex Wilson 	 * This is a 64-bit PCIe device. We can use the entire address space.
193*ebb7c6fdSAlex Wilson 	 */
194*ebb7c6fdSAlex Wilson 	attrp->dma_attr_addr_lo = 0x0;
195*ebb7c6fdSAlex Wilson 	attrp->dma_attr_addr_hi = UINT64_MAX;
196*ebb7c6fdSAlex Wilson 
197*ebb7c6fdSAlex Wilson 	/*
198*ebb7c6fdSAlex Wilson 	 * Queue doorbells are always exactly 16 bytes in length, but
199*ebb7c6fdSAlex Wilson 	 * the ddi_dma functions don't like such small values of count_max.
200*ebb7c6fdSAlex Wilson 	 *
201*ebb7c6fdSAlex Wilson 	 * We tell some lies here.
202*ebb7c6fdSAlex Wilson 	 */
203*ebb7c6fdSAlex Wilson 	attrp->dma_attr_count_max = MLXCX_QUEUE_DMA_PAGE_SIZE - 1;
204*ebb7c6fdSAlex Wilson 	attrp->dma_attr_align = 8;
205*ebb7c6fdSAlex Wilson 	attrp->dma_attr_burstsizes = 0x8;
206*ebb7c6fdSAlex Wilson 	attrp->dma_attr_minxfer = 1;
207*ebb7c6fdSAlex Wilson 	attrp->dma_attr_maxxfer = UINT16_MAX;
208*ebb7c6fdSAlex Wilson 	attrp->dma_attr_seg = MLXCX_QUEUE_DMA_PAGE_SIZE - 1;
209*ebb7c6fdSAlex Wilson 	attrp->dma_attr_granular = 1;
210*ebb7c6fdSAlex Wilson 	attrp->dma_attr_sgllen = 1;
211*ebb7c6fdSAlex Wilson 
212*ebb7c6fdSAlex Wilson 	if (DDI_FM_DMA_ERR_CAP(mlxp->mlx_fm_caps)) {
213*ebb7c6fdSAlex Wilson 		attrp->dma_attr_flags = DDI_DMA_FLAGERR;
214*ebb7c6fdSAlex Wilson 	} else {
215*ebb7c6fdSAlex Wilson 		attrp->dma_attr_flags = 0;
216*ebb7c6fdSAlex Wilson 	}
217*ebb7c6fdSAlex Wilson }
218*ebb7c6fdSAlex Wilson 
219*ebb7c6fdSAlex Wilson void
mlxcx_dma_free(mlxcx_dma_buffer_t * mxdb)220*ebb7c6fdSAlex Wilson mlxcx_dma_free(mlxcx_dma_buffer_t *mxdb)
221*ebb7c6fdSAlex Wilson {
222*ebb7c6fdSAlex Wilson 	int ret;
223*ebb7c6fdSAlex Wilson 
224*ebb7c6fdSAlex Wilson 	if (mxdb->mxdb_flags & MLXCX_DMABUF_BOUND) {
225*ebb7c6fdSAlex Wilson 		VERIFY(mxdb->mxdb_dma_handle != NULL);
226*ebb7c6fdSAlex Wilson 		ret = ddi_dma_unbind_handle(mxdb->mxdb_dma_handle);
227*ebb7c6fdSAlex Wilson 		VERIFY3S(ret, ==, DDI_SUCCESS);
228*ebb7c6fdSAlex Wilson 		mxdb->mxdb_flags &= ~MLXCX_DMABUF_BOUND;
229*ebb7c6fdSAlex Wilson 		mxdb->mxdb_ncookies = 0;
230*ebb7c6fdSAlex Wilson 	}
231*ebb7c6fdSAlex Wilson 
232*ebb7c6fdSAlex Wilson 	if (mxdb->mxdb_flags & MLXCX_DMABUF_MEM_ALLOC) {
233*ebb7c6fdSAlex Wilson 		ddi_dma_mem_free(&mxdb->mxdb_acc_handle);
234*ebb7c6fdSAlex Wilson 		mxdb->mxdb_acc_handle = NULL;
235*ebb7c6fdSAlex Wilson 		mxdb->mxdb_va = NULL;
236*ebb7c6fdSAlex Wilson 		mxdb->mxdb_len = 0;
237*ebb7c6fdSAlex Wilson 		mxdb->mxdb_flags &= ~MLXCX_DMABUF_MEM_ALLOC;
238*ebb7c6fdSAlex Wilson 	}
239*ebb7c6fdSAlex Wilson 
240*ebb7c6fdSAlex Wilson 	if (mxdb->mxdb_flags & MLXCX_DMABUF_FOREIGN) {
241*ebb7c6fdSAlex Wilson 		/* The mblk will be freed separately */
242*ebb7c6fdSAlex Wilson 		mxdb->mxdb_va = NULL;
243*ebb7c6fdSAlex Wilson 		mxdb->mxdb_len = 0;
244*ebb7c6fdSAlex Wilson 		mxdb->mxdb_flags &= ~MLXCX_DMABUF_FOREIGN;
245*ebb7c6fdSAlex Wilson 	}
246*ebb7c6fdSAlex Wilson 
247*ebb7c6fdSAlex Wilson 	if (mxdb->mxdb_flags & MLXCX_DMABUF_HDL_ALLOC) {
248*ebb7c6fdSAlex Wilson 		ddi_dma_free_handle(&mxdb->mxdb_dma_handle);
249*ebb7c6fdSAlex Wilson 		mxdb->mxdb_dma_handle = NULL;
250*ebb7c6fdSAlex Wilson 		mxdb->mxdb_flags &= ~MLXCX_DMABUF_HDL_ALLOC;
251*ebb7c6fdSAlex Wilson 	}
252*ebb7c6fdSAlex Wilson 
253*ebb7c6fdSAlex Wilson 	ASSERT3U(mxdb->mxdb_flags, ==, 0);
254*ebb7c6fdSAlex Wilson 	ASSERT3P(mxdb->mxdb_dma_handle, ==, NULL);
255*ebb7c6fdSAlex Wilson 	ASSERT3P(mxdb->mxdb_va, ==, NULL);
256*ebb7c6fdSAlex Wilson 	ASSERT3U(mxdb->mxdb_len, ==, 0);
257*ebb7c6fdSAlex Wilson 	ASSERT3U(mxdb->mxdb_ncookies, ==, 0);
258*ebb7c6fdSAlex Wilson }
259*ebb7c6fdSAlex Wilson 
260*ebb7c6fdSAlex Wilson void
mlxcx_dma_unbind(mlxcx_t * mlxp,mlxcx_dma_buffer_t * mxdb)261*ebb7c6fdSAlex Wilson mlxcx_dma_unbind(mlxcx_t *mlxp, mlxcx_dma_buffer_t *mxdb)
262*ebb7c6fdSAlex Wilson {
263*ebb7c6fdSAlex Wilson 	int ret;
264*ebb7c6fdSAlex Wilson 
265*ebb7c6fdSAlex Wilson 	ASSERT(mxdb->mxdb_flags & MLXCX_DMABUF_HDL_ALLOC);
266*ebb7c6fdSAlex Wilson 	ASSERT(mxdb->mxdb_flags & MLXCX_DMABUF_BOUND);
267*ebb7c6fdSAlex Wilson 
268*ebb7c6fdSAlex Wilson 	if (mxdb->mxdb_flags & MLXCX_DMABUF_FOREIGN) {
269*ebb7c6fdSAlex Wilson 		/* The mblk will be freed separately */
270*ebb7c6fdSAlex Wilson 		mxdb->mxdb_va = NULL;
271*ebb7c6fdSAlex Wilson 		mxdb->mxdb_len = 0;
272*ebb7c6fdSAlex Wilson 		mxdb->mxdb_flags &= ~MLXCX_DMABUF_FOREIGN;
273*ebb7c6fdSAlex Wilson 	}
274*ebb7c6fdSAlex Wilson 
275*ebb7c6fdSAlex Wilson 	ret = ddi_dma_unbind_handle(mxdb->mxdb_dma_handle);
276*ebb7c6fdSAlex Wilson 	VERIFY3S(ret, ==, DDI_SUCCESS);
277*ebb7c6fdSAlex Wilson 	mxdb->mxdb_flags &= ~MLXCX_DMABUF_BOUND;
278*ebb7c6fdSAlex Wilson 	mxdb->mxdb_ncookies = 0;
279*ebb7c6fdSAlex Wilson }
280*ebb7c6fdSAlex Wilson 
281*ebb7c6fdSAlex Wilson boolean_t
mlxcx_dma_init(mlxcx_t * mlxp,mlxcx_dma_buffer_t * mxdb,ddi_dma_attr_t * attrp,boolean_t wait)282*ebb7c6fdSAlex Wilson mlxcx_dma_init(mlxcx_t *mlxp, mlxcx_dma_buffer_t *mxdb,
283*ebb7c6fdSAlex Wilson     ddi_dma_attr_t *attrp, boolean_t wait)
284*ebb7c6fdSAlex Wilson {
285*ebb7c6fdSAlex Wilson 	int ret;
286*ebb7c6fdSAlex Wilson 	int (*memcb)(caddr_t);
287*ebb7c6fdSAlex Wilson 
288*ebb7c6fdSAlex Wilson 	if (wait == B_TRUE) {
289*ebb7c6fdSAlex Wilson 		memcb = DDI_DMA_SLEEP;
290*ebb7c6fdSAlex Wilson 	} else {
291*ebb7c6fdSAlex Wilson 		memcb = DDI_DMA_DONTWAIT;
292*ebb7c6fdSAlex Wilson 	}
293*ebb7c6fdSAlex Wilson 
294*ebb7c6fdSAlex Wilson 	ASSERT3S(mxdb->mxdb_flags, ==, 0);
295*ebb7c6fdSAlex Wilson 
296*ebb7c6fdSAlex Wilson 	ret = ddi_dma_alloc_handle(mlxp->mlx_dip, attrp, memcb, NULL,
297*ebb7c6fdSAlex Wilson 	    &mxdb->mxdb_dma_handle);
298*ebb7c6fdSAlex Wilson 	if (ret != 0) {
299*ebb7c6fdSAlex Wilson 		mlxcx_warn(mlxp, "!failed to allocate DMA handle: %d", ret);
300*ebb7c6fdSAlex Wilson 		mxdb->mxdb_dma_handle = NULL;
301*ebb7c6fdSAlex Wilson 		return (B_FALSE);
302*ebb7c6fdSAlex Wilson 	}
303*ebb7c6fdSAlex Wilson 	mxdb->mxdb_flags |= MLXCX_DMABUF_HDL_ALLOC;
304*ebb7c6fdSAlex Wilson 
305*ebb7c6fdSAlex Wilson 	return (B_TRUE);
306*ebb7c6fdSAlex Wilson }
307*ebb7c6fdSAlex Wilson 
308*ebb7c6fdSAlex Wilson boolean_t
mlxcx_dma_bind_mblk(mlxcx_t * mlxp,mlxcx_dma_buffer_t * mxdb,const mblk_t * mp,size_t off,boolean_t wait)309*ebb7c6fdSAlex Wilson mlxcx_dma_bind_mblk(mlxcx_t *mlxp, mlxcx_dma_buffer_t *mxdb,
310*ebb7c6fdSAlex Wilson     const mblk_t *mp, size_t off, boolean_t wait)
311*ebb7c6fdSAlex Wilson {
312*ebb7c6fdSAlex Wilson 	int ret;
313*ebb7c6fdSAlex Wilson 	uint_t flags = DDI_DMA_STREAMING;
314*ebb7c6fdSAlex Wilson 	int (*memcb)(caddr_t);
315*ebb7c6fdSAlex Wilson 
316*ebb7c6fdSAlex Wilson 	if (wait == B_TRUE) {
317*ebb7c6fdSAlex Wilson 		memcb = DDI_DMA_SLEEP;
318*ebb7c6fdSAlex Wilson 	} else {
319*ebb7c6fdSAlex Wilson 		memcb = DDI_DMA_DONTWAIT;
320*ebb7c6fdSAlex Wilson 	}
321*ebb7c6fdSAlex Wilson 
322*ebb7c6fdSAlex Wilson 	ASSERT(mxdb->mxdb_flags & MLXCX_DMABUF_HDL_ALLOC);
323*ebb7c6fdSAlex Wilson 	ASSERT0(mxdb->mxdb_flags &
324*ebb7c6fdSAlex Wilson 	    (MLXCX_DMABUF_FOREIGN | MLXCX_DMABUF_MEM_ALLOC));
325*ebb7c6fdSAlex Wilson 	ASSERT0(mxdb->mxdb_flags & MLXCX_DMABUF_BOUND);
326*ebb7c6fdSAlex Wilson 
327*ebb7c6fdSAlex Wilson 	ASSERT3U(off, <=, MBLKL(mp));
328*ebb7c6fdSAlex Wilson 	mxdb->mxdb_va = (caddr_t)(mp->b_rptr + off);
329*ebb7c6fdSAlex Wilson 	mxdb->mxdb_len = MBLKL(mp) - off;
330*ebb7c6fdSAlex Wilson 	mxdb->mxdb_flags |= MLXCX_DMABUF_FOREIGN;
331*ebb7c6fdSAlex Wilson 
332*ebb7c6fdSAlex Wilson 	ret = ddi_dma_addr_bind_handle(mxdb->mxdb_dma_handle, NULL,
333*ebb7c6fdSAlex Wilson 	    mxdb->mxdb_va, mxdb->mxdb_len, DDI_DMA_WRITE | flags, memcb, NULL,
334*ebb7c6fdSAlex Wilson 	    NULL, NULL);
335*ebb7c6fdSAlex Wilson 	if (ret != DDI_DMA_MAPPED) {
336*ebb7c6fdSAlex Wilson 		mxdb->mxdb_va = NULL;
337*ebb7c6fdSAlex Wilson 		mxdb->mxdb_len = 0;
338*ebb7c6fdSAlex Wilson 		mxdb->mxdb_flags &= ~MLXCX_DMABUF_FOREIGN;
339*ebb7c6fdSAlex Wilson 		return (B_FALSE);
340*ebb7c6fdSAlex Wilson 	}
341*ebb7c6fdSAlex Wilson 	mxdb->mxdb_flags |= MLXCX_DMABUF_BOUND;
342*ebb7c6fdSAlex Wilson 	mxdb->mxdb_ncookies = ddi_dma_ncookies(mxdb->mxdb_dma_handle);
343*ebb7c6fdSAlex Wilson 
344*ebb7c6fdSAlex Wilson 	return (B_TRUE);
345*ebb7c6fdSAlex Wilson }
346*ebb7c6fdSAlex Wilson 
347*ebb7c6fdSAlex Wilson boolean_t
mlxcx_dma_alloc(mlxcx_t * mlxp,mlxcx_dma_buffer_t * mxdb,ddi_dma_attr_t * attrp,ddi_device_acc_attr_t * accp,boolean_t zero,size_t size,boolean_t wait)348*ebb7c6fdSAlex Wilson mlxcx_dma_alloc(mlxcx_t *mlxp, mlxcx_dma_buffer_t *mxdb,
349*ebb7c6fdSAlex Wilson     ddi_dma_attr_t *attrp, ddi_device_acc_attr_t *accp, boolean_t zero,
350*ebb7c6fdSAlex Wilson     size_t size, boolean_t wait)
351*ebb7c6fdSAlex Wilson {
352*ebb7c6fdSAlex Wilson 	int ret;
353*ebb7c6fdSAlex Wilson 	uint_t flags = DDI_DMA_CONSISTENT;
354*ebb7c6fdSAlex Wilson 	size_t len;
355*ebb7c6fdSAlex Wilson 	int (*memcb)(caddr_t);
356*ebb7c6fdSAlex Wilson 
357*ebb7c6fdSAlex Wilson 	if (wait == B_TRUE) {
358*ebb7c6fdSAlex Wilson 		memcb = DDI_DMA_SLEEP;
359*ebb7c6fdSAlex Wilson 	} else {
360*ebb7c6fdSAlex Wilson 		memcb = DDI_DMA_DONTWAIT;
361*ebb7c6fdSAlex Wilson 	}
362*ebb7c6fdSAlex Wilson 
363*ebb7c6fdSAlex Wilson 	ASSERT3U(mxdb->mxdb_flags, ==, 0);
364*ebb7c6fdSAlex Wilson 
365*ebb7c6fdSAlex Wilson 	ret = ddi_dma_alloc_handle(mlxp->mlx_dip, attrp, memcb, NULL,
366*ebb7c6fdSAlex Wilson 	    &mxdb->mxdb_dma_handle);
367*ebb7c6fdSAlex Wilson 	if (ret != 0) {
368*ebb7c6fdSAlex Wilson 		mlxcx_warn(mlxp, "!failed to allocate DMA handle: %d", ret);
369*ebb7c6fdSAlex Wilson 		mxdb->mxdb_dma_handle = NULL;
370*ebb7c6fdSAlex Wilson 		return (B_FALSE);
371*ebb7c6fdSAlex Wilson 	}
372*ebb7c6fdSAlex Wilson 	mxdb->mxdb_flags |= MLXCX_DMABUF_HDL_ALLOC;
373*ebb7c6fdSAlex Wilson 
374*ebb7c6fdSAlex Wilson 	ret = ddi_dma_mem_alloc(mxdb->mxdb_dma_handle, size, accp, flags, memcb,
375*ebb7c6fdSAlex Wilson 	    NULL, &mxdb->mxdb_va, &len, &mxdb->mxdb_acc_handle);
376*ebb7c6fdSAlex Wilson 	if (ret != DDI_SUCCESS) {
377*ebb7c6fdSAlex Wilson 		mlxcx_warn(mlxp, "!failed to allocate DMA memory: %d", ret);
378*ebb7c6fdSAlex Wilson 		mxdb->mxdb_va = NULL;
379*ebb7c6fdSAlex Wilson 		mxdb->mxdb_acc_handle = NULL;
380*ebb7c6fdSAlex Wilson 		mlxcx_dma_free(mxdb);
381*ebb7c6fdSAlex Wilson 		return (B_FALSE);
382*ebb7c6fdSAlex Wilson 	}
383*ebb7c6fdSAlex Wilson 	mxdb->mxdb_len = size;
384*ebb7c6fdSAlex Wilson 	mxdb->mxdb_flags |= MLXCX_DMABUF_MEM_ALLOC;
385*ebb7c6fdSAlex Wilson 
386*ebb7c6fdSAlex Wilson 	if (zero == B_TRUE)
387*ebb7c6fdSAlex Wilson 		bzero(mxdb->mxdb_va, len);
388*ebb7c6fdSAlex Wilson 
389*ebb7c6fdSAlex Wilson 	ret = ddi_dma_addr_bind_handle(mxdb->mxdb_dma_handle, NULL,
390*ebb7c6fdSAlex Wilson 	    mxdb->mxdb_va, len, DDI_DMA_RDWR | flags, memcb, NULL, NULL,
391*ebb7c6fdSAlex Wilson 	    NULL);
392*ebb7c6fdSAlex Wilson 	if (ret != 0) {
393*ebb7c6fdSAlex Wilson 		mlxcx_warn(mlxp, "!failed to bind DMA memory: %d", ret);
394*ebb7c6fdSAlex Wilson 		mlxcx_dma_free(mxdb);
395*ebb7c6fdSAlex Wilson 		return (B_FALSE);
396*ebb7c6fdSAlex Wilson 	}
397*ebb7c6fdSAlex Wilson 	mxdb->mxdb_flags |= MLXCX_DMABUF_BOUND;
398*ebb7c6fdSAlex Wilson 	mxdb->mxdb_ncookies = ddi_dma_ncookies(mxdb->mxdb_dma_handle);
399*ebb7c6fdSAlex Wilson 
400*ebb7c6fdSAlex Wilson 	return (B_TRUE);
401*ebb7c6fdSAlex Wilson }
402*ebb7c6fdSAlex Wilson 
403*ebb7c6fdSAlex Wilson boolean_t
mlxcx_dma_alloc_offset(mlxcx_t * mlxp,mlxcx_dma_buffer_t * mxdb,ddi_dma_attr_t * attrp,ddi_device_acc_attr_t * accp,boolean_t zero,size_t size,size_t offset,boolean_t wait)404*ebb7c6fdSAlex Wilson mlxcx_dma_alloc_offset(mlxcx_t *mlxp, mlxcx_dma_buffer_t *mxdb,
405*ebb7c6fdSAlex Wilson     ddi_dma_attr_t *attrp, ddi_device_acc_attr_t *accp, boolean_t zero,
406*ebb7c6fdSAlex Wilson     size_t size, size_t offset, boolean_t wait)
407*ebb7c6fdSAlex Wilson {
408*ebb7c6fdSAlex Wilson 	int ret;
409*ebb7c6fdSAlex Wilson 	uint_t flags = DDI_DMA_STREAMING;
410*ebb7c6fdSAlex Wilson 	size_t len;
411*ebb7c6fdSAlex Wilson 	int (*memcb)(caddr_t);
412*ebb7c6fdSAlex Wilson 
413*ebb7c6fdSAlex Wilson 	if (wait == B_TRUE) {
414*ebb7c6fdSAlex Wilson 		memcb = DDI_DMA_SLEEP;
415*ebb7c6fdSAlex Wilson 	} else {
416*ebb7c6fdSAlex Wilson 		memcb = DDI_DMA_DONTWAIT;
417*ebb7c6fdSAlex Wilson 	}
418*ebb7c6fdSAlex Wilson 
419*ebb7c6fdSAlex Wilson 	ASSERT3U(mxdb->mxdb_flags, ==, 0);
420*ebb7c6fdSAlex Wilson 
421*ebb7c6fdSAlex Wilson 	ret = ddi_dma_alloc_handle(mlxp->mlx_dip, attrp, memcb, NULL,
422*ebb7c6fdSAlex Wilson 	    &mxdb->mxdb_dma_handle);
423*ebb7c6fdSAlex Wilson 	if (ret != 0) {
424*ebb7c6fdSAlex Wilson 		mlxcx_warn(mlxp, "!failed to allocate DMA handle: %d", ret);
425*ebb7c6fdSAlex Wilson 		mxdb->mxdb_dma_handle = NULL;
426*ebb7c6fdSAlex Wilson 		return (B_FALSE);
427*ebb7c6fdSAlex Wilson 	}
428*ebb7c6fdSAlex Wilson 	mxdb->mxdb_flags |= MLXCX_DMABUF_HDL_ALLOC;
429*ebb7c6fdSAlex Wilson 
430*ebb7c6fdSAlex Wilson 	ret = ddi_dma_mem_alloc(mxdb->mxdb_dma_handle, size + offset, accp,
431*ebb7c6fdSAlex Wilson 	    flags, memcb, NULL, &mxdb->mxdb_va, &len, &mxdb->mxdb_acc_handle);
432*ebb7c6fdSAlex Wilson 	if (ret != DDI_SUCCESS) {
433*ebb7c6fdSAlex Wilson 		mlxcx_warn(mlxp, "!failed to allocate DMA memory: %d", ret);
434*ebb7c6fdSAlex Wilson 		mxdb->mxdb_va = NULL;
435*ebb7c6fdSAlex Wilson 		mxdb->mxdb_acc_handle = NULL;
436*ebb7c6fdSAlex Wilson 		mlxcx_dma_free(mxdb);
437*ebb7c6fdSAlex Wilson 		return (B_FALSE);
438*ebb7c6fdSAlex Wilson 	}
439*ebb7c6fdSAlex Wilson 
440*ebb7c6fdSAlex Wilson 	if (zero == B_TRUE)
441*ebb7c6fdSAlex Wilson 		bzero(mxdb->mxdb_va, len);
442*ebb7c6fdSAlex Wilson 
443*ebb7c6fdSAlex Wilson 	mxdb->mxdb_va += offset;
444*ebb7c6fdSAlex Wilson 	len -= offset;
445*ebb7c6fdSAlex Wilson 	mxdb->mxdb_len = len;
446*ebb7c6fdSAlex Wilson 	mxdb->mxdb_flags |= MLXCX_DMABUF_MEM_ALLOC;
447*ebb7c6fdSAlex Wilson 
448*ebb7c6fdSAlex Wilson 	ret = ddi_dma_addr_bind_handle(mxdb->mxdb_dma_handle, NULL,
449*ebb7c6fdSAlex Wilson 	    mxdb->mxdb_va, len, DDI_DMA_RDWR | flags, memcb, NULL, NULL,
450*ebb7c6fdSAlex Wilson 	    NULL);
451*ebb7c6fdSAlex Wilson 	if (ret != 0) {
452*ebb7c6fdSAlex Wilson 		mlxcx_warn(mlxp, "!failed to bind DMA memory: %d", ret);
453*ebb7c6fdSAlex Wilson 		mlxcx_dma_free(mxdb);
454*ebb7c6fdSAlex Wilson 		return (B_FALSE);
455*ebb7c6fdSAlex Wilson 	}
456*ebb7c6fdSAlex Wilson 	mxdb->mxdb_flags |= MLXCX_DMABUF_BOUND;
457*ebb7c6fdSAlex Wilson 	mxdb->mxdb_ncookies = ddi_dma_ncookies(mxdb->mxdb_dma_handle);
458*ebb7c6fdSAlex Wilson 
459*ebb7c6fdSAlex Wilson 	return (B_TRUE);
460*ebb7c6fdSAlex Wilson }
461