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