xref: /freebsd/sys/dev/oce/oce_util.c (revision 2f345d8ed55d5dd29023c1f0e6b6a396e1bf2770)
1*2f345d8eSLuigi Rizzo /*-
2*2f345d8eSLuigi Rizzo  * Copyright (C) 2012 Emulex
3*2f345d8eSLuigi Rizzo  * All rights reserved.
4*2f345d8eSLuigi Rizzo  *
5*2f345d8eSLuigi Rizzo  * Redistribution and use in source and binary forms, with or without
6*2f345d8eSLuigi Rizzo  * modification, are permitted provided that the following conditions are met:
7*2f345d8eSLuigi Rizzo  *
8*2f345d8eSLuigi Rizzo  * 1. Redistributions of source code must retain the above copyright notice,
9*2f345d8eSLuigi Rizzo  *    this list of conditions and the following disclaimer.
10*2f345d8eSLuigi Rizzo  *
11*2f345d8eSLuigi Rizzo  * 2. Redistributions in binary form must reproduce the above copyright
12*2f345d8eSLuigi Rizzo  *    notice, this list of conditions and the following disclaimer in the
13*2f345d8eSLuigi Rizzo  *    documentation and/or other materials provided with the distribution.
14*2f345d8eSLuigi Rizzo  *
15*2f345d8eSLuigi Rizzo  * 3. Neither the name of the Emulex Corporation nor the names of its
16*2f345d8eSLuigi Rizzo  *    contributors may be used to endorse or promote products derived from
17*2f345d8eSLuigi Rizzo  *    this software without specific prior written permission.
18*2f345d8eSLuigi Rizzo  *
19*2f345d8eSLuigi Rizzo  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20*2f345d8eSLuigi Rizzo  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*2f345d8eSLuigi Rizzo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*2f345d8eSLuigi Rizzo  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23*2f345d8eSLuigi Rizzo  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*2f345d8eSLuigi Rizzo  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*2f345d8eSLuigi Rizzo  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*2f345d8eSLuigi Rizzo  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*2f345d8eSLuigi Rizzo  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*2f345d8eSLuigi Rizzo  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*2f345d8eSLuigi Rizzo  * POSSIBILITY OF SUCH DAMAGE.
30*2f345d8eSLuigi Rizzo  *
31*2f345d8eSLuigi Rizzo  * Contact Information:
32*2f345d8eSLuigi Rizzo  * freebsd-drivers@emulex.com
33*2f345d8eSLuigi Rizzo  *
34*2f345d8eSLuigi Rizzo  * Emulex
35*2f345d8eSLuigi Rizzo  * 3333 Susan Street
36*2f345d8eSLuigi Rizzo  * Costa Mesa, CA 92626
37*2f345d8eSLuigi Rizzo  */
38*2f345d8eSLuigi Rizzo 
39*2f345d8eSLuigi Rizzo 
40*2f345d8eSLuigi Rizzo /* $FreeBSD$ */
41*2f345d8eSLuigi Rizzo 
42*2f345d8eSLuigi Rizzo 
43*2f345d8eSLuigi Rizzo #include "oce_if.h"
44*2f345d8eSLuigi Rizzo 
45*2f345d8eSLuigi Rizzo static void oce_dma_map_ring(void *arg,
46*2f345d8eSLuigi Rizzo 			     bus_dma_segment_t *segs,
47*2f345d8eSLuigi Rizzo 			     int nseg,
48*2f345d8eSLuigi Rizzo 			     int error);
49*2f345d8eSLuigi Rizzo 
50*2f345d8eSLuigi Rizzo /**
51*2f345d8eSLuigi Rizzo  * @brief		Allocate DMA memory
52*2f345d8eSLuigi Rizzo  * @param sc		software handle to the device
53*2f345d8eSLuigi Rizzo  * @param size		bus size
54*2f345d8eSLuigi Rizzo  * @param dma		dma memory area
55*2f345d8eSLuigi Rizzo  * @param flags		creation flags
56*2f345d8eSLuigi Rizzo  * @returns		0 on success, error otherwize
57*2f345d8eSLuigi Rizzo  */
58*2f345d8eSLuigi Rizzo int
59*2f345d8eSLuigi Rizzo oce_dma_alloc(POCE_SOFTC sc, bus_size_t size, POCE_DMA_MEM dma, int flags)
60*2f345d8eSLuigi Rizzo {
61*2f345d8eSLuigi Rizzo 	int rc;
62*2f345d8eSLuigi Rizzo 
63*2f345d8eSLuigi Rizzo 
64*2f345d8eSLuigi Rizzo 	memset(dma, 0, sizeof(OCE_DMA_MEM));
65*2f345d8eSLuigi Rizzo 
66*2f345d8eSLuigi Rizzo 	rc = bus_dma_tag_create(bus_get_dma_tag(sc->dev),
67*2f345d8eSLuigi Rizzo 				8, 0,
68*2f345d8eSLuigi Rizzo 				BUS_SPACE_MAXADDR,
69*2f345d8eSLuigi Rizzo 				BUS_SPACE_MAXADDR,
70*2f345d8eSLuigi Rizzo 				NULL, NULL,
71*2f345d8eSLuigi Rizzo 				size, 1, size, 0, NULL, NULL, &dma->tag);
72*2f345d8eSLuigi Rizzo 
73*2f345d8eSLuigi Rizzo 	if (rc == 0) {
74*2f345d8eSLuigi Rizzo 		rc = bus_dmamem_alloc(dma->tag,
75*2f345d8eSLuigi Rizzo 				      &dma->ptr,
76*2f345d8eSLuigi Rizzo 				      BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
77*2f345d8eSLuigi Rizzo 				      &dma->map);
78*2f345d8eSLuigi Rizzo 	}
79*2f345d8eSLuigi Rizzo 
80*2f345d8eSLuigi Rizzo 	dma->paddr = 0;
81*2f345d8eSLuigi Rizzo 	if (rc == 0) {
82*2f345d8eSLuigi Rizzo 		rc = bus_dmamap_load(dma->tag,
83*2f345d8eSLuigi Rizzo 				     dma->map,
84*2f345d8eSLuigi Rizzo 				     dma->ptr,
85*2f345d8eSLuigi Rizzo 				     size,
86*2f345d8eSLuigi Rizzo 				     oce_dma_map_addr,
87*2f345d8eSLuigi Rizzo 				     &dma->paddr, flags | BUS_DMA_NOWAIT);
88*2f345d8eSLuigi Rizzo 		if (dma->paddr == 0)
89*2f345d8eSLuigi Rizzo 			rc = ENXIO;
90*2f345d8eSLuigi Rizzo 	}
91*2f345d8eSLuigi Rizzo 
92*2f345d8eSLuigi Rizzo 	if (rc != 0)
93*2f345d8eSLuigi Rizzo 		oce_dma_free(sc, dma);
94*2f345d8eSLuigi Rizzo 
95*2f345d8eSLuigi Rizzo 	return rc;
96*2f345d8eSLuigi Rizzo }
97*2f345d8eSLuigi Rizzo 
98*2f345d8eSLuigi Rizzo /**
99*2f345d8eSLuigi Rizzo  * @brief		Free DMA memory
100*2f345d8eSLuigi Rizzo  * @param sc		software handle to the device
101*2f345d8eSLuigi Rizzo  * @param dma		dma area to free
102*2f345d8eSLuigi Rizzo  */
103*2f345d8eSLuigi Rizzo void
104*2f345d8eSLuigi Rizzo oce_dma_free(POCE_SOFTC sc, POCE_DMA_MEM dma)
105*2f345d8eSLuigi Rizzo {
106*2f345d8eSLuigi Rizzo 	if (dma->tag == NULL)
107*2f345d8eSLuigi Rizzo 		return;
108*2f345d8eSLuigi Rizzo 
109*2f345d8eSLuigi Rizzo 	if (dma->map != NULL) {
110*2f345d8eSLuigi Rizzo 		bus_dmamap_sync(dma->tag, dma->map,
111*2f345d8eSLuigi Rizzo 				BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
112*2f345d8eSLuigi Rizzo 		bus_dmamap_unload(dma->tag, dma->map);
113*2f345d8eSLuigi Rizzo 	}
114*2f345d8eSLuigi Rizzo 
115*2f345d8eSLuigi Rizzo 	if (dma->ptr != NULL) {
116*2f345d8eSLuigi Rizzo 		bus_dmamem_free(dma->tag, dma->ptr, dma->map);
117*2f345d8eSLuigi Rizzo 		dma->map = NULL;
118*2f345d8eSLuigi Rizzo 		dma->ptr = NULL;
119*2f345d8eSLuigi Rizzo 	}
120*2f345d8eSLuigi Rizzo 
121*2f345d8eSLuigi Rizzo 	bus_dma_tag_destroy(dma->tag);
122*2f345d8eSLuigi Rizzo 	dma->tag = NULL;
123*2f345d8eSLuigi Rizzo 
124*2f345d8eSLuigi Rizzo 	return;
125*2f345d8eSLuigi Rizzo }
126*2f345d8eSLuigi Rizzo 
127*2f345d8eSLuigi Rizzo 
128*2f345d8eSLuigi Rizzo 
129*2f345d8eSLuigi Rizzo /**
130*2f345d8eSLuigi Rizzo  * @brief		Map DMA memory segment addresses
131*2f345d8eSLuigi Rizzo  * @param arg		physical address pointer
132*2f345d8eSLuigi Rizzo  * @param segs		dma memory segments
133*2f345d8eSLuigi Rizzo  * @param nseg		number of dma memory segments
134*2f345d8eSLuigi Rizzo  * @param error		if error, zeroes the physical address
135*2f345d8eSLuigi Rizzo  */
136*2f345d8eSLuigi Rizzo void
137*2f345d8eSLuigi Rizzo oce_dma_map_addr(void *arg, bus_dma_segment_t * segs, int nseg, int error)
138*2f345d8eSLuigi Rizzo {
139*2f345d8eSLuigi Rizzo 	bus_addr_t *paddr = arg;
140*2f345d8eSLuigi Rizzo 
141*2f345d8eSLuigi Rizzo 	if (error)
142*2f345d8eSLuigi Rizzo 		*paddr = 0;
143*2f345d8eSLuigi Rizzo 	else
144*2f345d8eSLuigi Rizzo 		*paddr = segs->ds_addr;
145*2f345d8eSLuigi Rizzo }
146*2f345d8eSLuigi Rizzo 
147*2f345d8eSLuigi Rizzo 
148*2f345d8eSLuigi Rizzo 
149*2f345d8eSLuigi Rizzo /**
150*2f345d8eSLuigi Rizzo  * @brief		Destroy a ring buffer
151*2f345d8eSLuigi Rizzo  * @param sc		software handle to the device
152*2f345d8eSLuigi Rizzo  * @param ring		ring buffer
153*2f345d8eSLuigi Rizzo  */
154*2f345d8eSLuigi Rizzo 
155*2f345d8eSLuigi Rizzo void
156*2f345d8eSLuigi Rizzo oce_destroy_ring_buffer(POCE_SOFTC sc, oce_ring_buffer_t *ring)
157*2f345d8eSLuigi Rizzo {
158*2f345d8eSLuigi Rizzo 	oce_dma_free(sc, &ring->dma);
159*2f345d8eSLuigi Rizzo 	free(ring, M_DEVBUF);
160*2f345d8eSLuigi Rizzo }
161*2f345d8eSLuigi Rizzo 
162*2f345d8eSLuigi Rizzo 
163*2f345d8eSLuigi Rizzo 
164*2f345d8eSLuigi Rizzo oce_ring_buffer_t *
165*2f345d8eSLuigi Rizzo oce_create_ring_buffer(POCE_SOFTC sc,
166*2f345d8eSLuigi Rizzo 		uint32_t q_len, uint32_t item_size)
167*2f345d8eSLuigi Rizzo {
168*2f345d8eSLuigi Rizzo 	uint32_t size = q_len * item_size;
169*2f345d8eSLuigi Rizzo 	int rc;
170*2f345d8eSLuigi Rizzo 	oce_ring_buffer_t *ring;
171*2f345d8eSLuigi Rizzo 
172*2f345d8eSLuigi Rizzo 
173*2f345d8eSLuigi Rizzo 	ring = malloc(sizeof(oce_ring_buffer_t), M_DEVBUF, M_NOWAIT | M_ZERO);
174*2f345d8eSLuigi Rizzo 	if (ring == NULL)
175*2f345d8eSLuigi Rizzo 		return NULL;
176*2f345d8eSLuigi Rizzo 
177*2f345d8eSLuigi Rizzo 	ring->item_size = item_size;
178*2f345d8eSLuigi Rizzo 	ring->num_items = q_len;
179*2f345d8eSLuigi Rizzo 
180*2f345d8eSLuigi Rizzo 	rc = bus_dma_tag_create(bus_get_dma_tag(sc->dev),
181*2f345d8eSLuigi Rizzo 				4096, 0,
182*2f345d8eSLuigi Rizzo 				BUS_SPACE_MAXADDR,
183*2f345d8eSLuigi Rizzo 				BUS_SPACE_MAXADDR,
184*2f345d8eSLuigi Rizzo 				NULL, NULL,
185*2f345d8eSLuigi Rizzo 				size, 8, 4096, 0, NULL, NULL, &ring->dma.tag);
186*2f345d8eSLuigi Rizzo 	if (rc)
187*2f345d8eSLuigi Rizzo 		goto fail;
188*2f345d8eSLuigi Rizzo 
189*2f345d8eSLuigi Rizzo 
190*2f345d8eSLuigi Rizzo 	rc = bus_dmamem_alloc(ring->dma.tag,
191*2f345d8eSLuigi Rizzo 				&ring->dma.ptr,
192*2f345d8eSLuigi Rizzo 				BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
193*2f345d8eSLuigi Rizzo 				&ring->dma.map);
194*2f345d8eSLuigi Rizzo 	if (rc)
195*2f345d8eSLuigi Rizzo 		goto fail;
196*2f345d8eSLuigi Rizzo 
197*2f345d8eSLuigi Rizzo 	bzero(ring->dma.ptr, size);
198*2f345d8eSLuigi Rizzo 	bus_dmamap_sync(ring->dma.tag, ring->dma.map,
199*2f345d8eSLuigi Rizzo 			BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
200*2f345d8eSLuigi Rizzo 	ring->dma.paddr = 0;
201*2f345d8eSLuigi Rizzo 
202*2f345d8eSLuigi Rizzo 	return ring;
203*2f345d8eSLuigi Rizzo 
204*2f345d8eSLuigi Rizzo fail:
205*2f345d8eSLuigi Rizzo 	oce_dma_free(sc, &ring->dma);
206*2f345d8eSLuigi Rizzo 	free(ring, M_DEVBUF);
207*2f345d8eSLuigi Rizzo 	ring = NULL;
208*2f345d8eSLuigi Rizzo 	return NULL;
209*2f345d8eSLuigi Rizzo }
210*2f345d8eSLuigi Rizzo 
211*2f345d8eSLuigi Rizzo 
212*2f345d8eSLuigi Rizzo 
213*2f345d8eSLuigi Rizzo struct _oce_dmamap_paddr_table {
214*2f345d8eSLuigi Rizzo 	uint32_t max_entries;
215*2f345d8eSLuigi Rizzo 	uint32_t num_entries;
216*2f345d8eSLuigi Rizzo 	struct phys_addr *paddrs;
217*2f345d8eSLuigi Rizzo };
218*2f345d8eSLuigi Rizzo 
219*2f345d8eSLuigi Rizzo 
220*2f345d8eSLuigi Rizzo 
221*2f345d8eSLuigi Rizzo /**
222*2f345d8eSLuigi Rizzo  * @brief		Map ring buffer
223*2f345d8eSLuigi Rizzo  * @param arg		dma map phyical address table pointer
224*2f345d8eSLuigi Rizzo  * @param segs		dma memory segments
225*2f345d8eSLuigi Rizzo  * @param nseg		number of dma memory segments
226*2f345d8eSLuigi Rizzo  * @param error		maps only if error is 0
227*2f345d8eSLuigi Rizzo  */
228*2f345d8eSLuigi Rizzo static void
229*2f345d8eSLuigi Rizzo oce_dma_map_ring(void *arg, bus_dma_segment_t * segs, int nseg, int error)
230*2f345d8eSLuigi Rizzo {
231*2f345d8eSLuigi Rizzo 	int i;
232*2f345d8eSLuigi Rizzo 	struct _oce_dmamap_paddr_table *dpt =
233*2f345d8eSLuigi Rizzo 	    (struct _oce_dmamap_paddr_table *)arg;
234*2f345d8eSLuigi Rizzo 
235*2f345d8eSLuigi Rizzo 	if (error == 0) {
236*2f345d8eSLuigi Rizzo 		if (nseg <= dpt->max_entries) {
237*2f345d8eSLuigi Rizzo 			for (i = 0; i < nseg; i++) {
238*2f345d8eSLuigi Rizzo 				dpt->paddrs[i].lo = ADDR_LO(segs[i].ds_addr);
239*2f345d8eSLuigi Rizzo 				dpt->paddrs[i].hi = ADDR_HI(segs[i].ds_addr);
240*2f345d8eSLuigi Rizzo 			}
241*2f345d8eSLuigi Rizzo 			dpt->num_entries = nseg;
242*2f345d8eSLuigi Rizzo 		}
243*2f345d8eSLuigi Rizzo 	}
244*2f345d8eSLuigi Rizzo }
245*2f345d8eSLuigi Rizzo 
246*2f345d8eSLuigi Rizzo 
247*2f345d8eSLuigi Rizzo 
248*2f345d8eSLuigi Rizzo /**
249*2f345d8eSLuigi Rizzo  * @brief		Load bus dma map for a ring buffer
250*2f345d8eSLuigi Rizzo  * @param ring		ring buffer pointer
251*2f345d8eSLuigi Rizzo  * @param pa_list	physical address list
252*2f345d8eSLuigi Rizzo  * @returns		number entries
253*2f345d8eSLuigi Rizzo  */
254*2f345d8eSLuigi Rizzo uint32_t
255*2f345d8eSLuigi Rizzo oce_page_list(oce_ring_buffer_t *ring, struct phys_addr *pa_list)
256*2f345d8eSLuigi Rizzo {
257*2f345d8eSLuigi Rizzo 	struct _oce_dmamap_paddr_table dpt;
258*2f345d8eSLuigi Rizzo 
259*2f345d8eSLuigi Rizzo 	dpt.max_entries = 8;
260*2f345d8eSLuigi Rizzo 	dpt.num_entries = 0;
261*2f345d8eSLuigi Rizzo 	dpt.paddrs = pa_list;
262*2f345d8eSLuigi Rizzo 
263*2f345d8eSLuigi Rizzo 	bus_dmamap_load(ring->dma.tag,
264*2f345d8eSLuigi Rizzo 			ring->dma.map,
265*2f345d8eSLuigi Rizzo 			ring->dma.ptr,
266*2f345d8eSLuigi Rizzo 			ring->item_size * ring->num_items,
267*2f345d8eSLuigi Rizzo 			oce_dma_map_ring, &dpt, BUS_DMA_NOWAIT);
268*2f345d8eSLuigi Rizzo 
269*2f345d8eSLuigi Rizzo 	return dpt.num_entries;
270*2f345d8eSLuigi Rizzo }
271