xref: /dragonfly/sys/dev/netif/oce/oce_util.c (revision 030b0c8c)
1229aec1cSSascha Wildner /*-
2*c976b08eSSascha Wildner  * Copyright (C) 2013 Emulex
3229aec1cSSascha Wildner  * All rights reserved.
4229aec1cSSascha Wildner  *
5229aec1cSSascha Wildner  * Redistribution and use in source and binary forms, with or without
6229aec1cSSascha Wildner  * modification, are permitted provided that the following conditions are met:
7229aec1cSSascha Wildner  *
8229aec1cSSascha Wildner  * 1. Redistributions of source code must retain the above copyright notice,
9229aec1cSSascha Wildner  *    this list of conditions and the following disclaimer.
10229aec1cSSascha Wildner  *
11229aec1cSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
12229aec1cSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
13229aec1cSSascha Wildner  *    documentation and/or other materials provided with the distribution.
14229aec1cSSascha Wildner  *
15229aec1cSSascha Wildner  * 3. Neither the name of the Emulex Corporation nor the names of its
16229aec1cSSascha Wildner  *    contributors may be used to endorse or promote products derived from
17229aec1cSSascha Wildner  *    this software without specific prior written permission.
18229aec1cSSascha Wildner  *
19229aec1cSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20229aec1cSSascha Wildner  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21229aec1cSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22229aec1cSSascha Wildner  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23229aec1cSSascha Wildner  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24229aec1cSSascha Wildner  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25229aec1cSSascha Wildner  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26229aec1cSSascha Wildner  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27229aec1cSSascha Wildner  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28229aec1cSSascha Wildner  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29229aec1cSSascha Wildner  * POSSIBILITY OF SUCH DAMAGE.
30229aec1cSSascha Wildner  *
31229aec1cSSascha Wildner  * Contact Information:
32229aec1cSSascha Wildner  * freebsd-drivers@emulex.com
33229aec1cSSascha Wildner  *
34229aec1cSSascha Wildner  * Emulex
35229aec1cSSascha Wildner  * 3333 Susan Street
36229aec1cSSascha Wildner  * Costa Mesa, CA 92626
37229aec1cSSascha Wildner  */
38229aec1cSSascha Wildner 
39229aec1cSSascha Wildner 
40*c976b08eSSascha Wildner /* $FreeBSD: src/sys/dev/oce/oce_util.c,v 1.5 2013/07/07 00:30:13 svnexp Exp $ */
41229aec1cSSascha Wildner 
42229aec1cSSascha Wildner 
43229aec1cSSascha Wildner #include "oce_if.h"
44229aec1cSSascha Wildner 
45229aec1cSSascha Wildner static void oce_dma_map_ring(void *arg,
46229aec1cSSascha Wildner 			     bus_dma_segment_t *segs,
47229aec1cSSascha Wildner 			     int nseg,
48229aec1cSSascha Wildner 			     int error);
49229aec1cSSascha Wildner 
50229aec1cSSascha Wildner /**
51229aec1cSSascha Wildner  * @brief		Allocate DMA memory
52229aec1cSSascha Wildner  * @param sc		software handle to the device
53229aec1cSSascha Wildner  * @param size		bus size
54229aec1cSSascha Wildner  * @param dma		dma memory area
55229aec1cSSascha Wildner  * @param flags		creation flags
56229aec1cSSascha Wildner  * @returns		0 on success, error otherwize
57229aec1cSSascha Wildner  */
58229aec1cSSascha Wildner int
oce_dma_alloc(POCE_SOFTC sc,bus_size_t size,POCE_DMA_MEM dma,int flags)59229aec1cSSascha Wildner oce_dma_alloc(POCE_SOFTC sc, bus_size_t size, POCE_DMA_MEM dma, int flags)
60229aec1cSSascha Wildner {
61229aec1cSSascha Wildner 	int rc;
62229aec1cSSascha Wildner 
63229aec1cSSascha Wildner 
64229aec1cSSascha Wildner 	memset(dma, 0, sizeof(OCE_DMA_MEM));
65229aec1cSSascha Wildner 
66229aec1cSSascha Wildner 	rc = bus_dma_tag_create(NULL,
67229aec1cSSascha Wildner 				8, 0,
68229aec1cSSascha Wildner 				BUS_SPACE_MAXADDR,
69229aec1cSSascha Wildner 				BUS_SPACE_MAXADDR,
70229aec1cSSascha Wildner 				size, 1, size, 0, &dma->tag);
71229aec1cSSascha Wildner 
72229aec1cSSascha Wildner 	if (rc == 0) {
73229aec1cSSascha Wildner 		rc = bus_dmamem_alloc(dma->tag,
74229aec1cSSascha Wildner 				      &dma->ptr,
75229aec1cSSascha Wildner 				      BUS_DMA_NOWAIT | BUS_DMA_COHERENT |
76229aec1cSSascha Wildner 					BUS_DMA_ZERO,
77229aec1cSSascha Wildner 				      &dma->map);
78229aec1cSSascha Wildner 	}
79229aec1cSSascha Wildner 
80229aec1cSSascha Wildner 	dma->paddr = 0;
81229aec1cSSascha Wildner 	if (rc == 0) {
82229aec1cSSascha Wildner 		rc = bus_dmamap_load(dma->tag,
83229aec1cSSascha Wildner 				     dma->map,
84229aec1cSSascha Wildner 				     dma->ptr,
85229aec1cSSascha Wildner 				     size,
86229aec1cSSascha Wildner 				     oce_dma_map_addr,
87229aec1cSSascha Wildner 				     &dma->paddr, flags | BUS_DMA_NOWAIT);
88229aec1cSSascha Wildner 		if (dma->paddr == 0)
89229aec1cSSascha Wildner 			rc = ENXIO;
90229aec1cSSascha Wildner 	}
91229aec1cSSascha Wildner 
92229aec1cSSascha Wildner 	if (rc != 0)
93229aec1cSSascha Wildner 		oce_dma_free(sc, dma);
94229aec1cSSascha Wildner 
95229aec1cSSascha Wildner 	return rc;
96229aec1cSSascha Wildner }
97229aec1cSSascha Wildner 
98229aec1cSSascha Wildner /**
99229aec1cSSascha Wildner  * @brief		Free DMA memory
100229aec1cSSascha Wildner  * @param sc		software handle to the device
101229aec1cSSascha Wildner  * @param dma		dma area to free
102229aec1cSSascha Wildner  */
103229aec1cSSascha Wildner void
oce_dma_free(POCE_SOFTC sc,POCE_DMA_MEM dma)104229aec1cSSascha Wildner oce_dma_free(POCE_SOFTC sc, POCE_DMA_MEM dma)
105229aec1cSSascha Wildner {
106229aec1cSSascha Wildner 	if (dma->tag == NULL)
107229aec1cSSascha Wildner 		return;
108229aec1cSSascha Wildner 
109229aec1cSSascha Wildner 	if (dma->map != NULL) {
110229aec1cSSascha Wildner 		bus_dmamap_sync(dma->tag, dma->map,
111229aec1cSSascha Wildner 				BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
112229aec1cSSascha Wildner 		bus_dmamap_unload(dma->tag, dma->map);
113229aec1cSSascha Wildner 	}
114229aec1cSSascha Wildner 
115229aec1cSSascha Wildner 	if (dma->ptr != NULL) {
116229aec1cSSascha Wildner 		bus_dmamem_free(dma->tag, dma->ptr, dma->map);
117229aec1cSSascha Wildner 		dma->map = NULL;
118229aec1cSSascha Wildner 		dma->ptr = NULL;
119229aec1cSSascha Wildner 	}
120229aec1cSSascha Wildner 
121229aec1cSSascha Wildner 	bus_dma_tag_destroy(dma->tag);
122229aec1cSSascha Wildner 	dma->tag = NULL;
123229aec1cSSascha Wildner 
124229aec1cSSascha Wildner 	return;
125229aec1cSSascha Wildner }
126229aec1cSSascha Wildner 
127229aec1cSSascha Wildner 
128229aec1cSSascha Wildner 
129229aec1cSSascha Wildner /**
130229aec1cSSascha Wildner  * @brief		Map DMA memory segment addresses
131229aec1cSSascha Wildner  * @param arg		physical address pointer
132229aec1cSSascha Wildner  * @param segs		dma memory segments
133229aec1cSSascha Wildner  * @param nseg		number of dma memory segments
134229aec1cSSascha Wildner  * @param error		if error, zeroes the physical address
135229aec1cSSascha Wildner  */
136229aec1cSSascha Wildner void
oce_dma_map_addr(void * arg,bus_dma_segment_t * segs,int nseg,int error)137229aec1cSSascha Wildner oce_dma_map_addr(void *arg, bus_dma_segment_t * segs, int nseg, int error)
138229aec1cSSascha Wildner {
139229aec1cSSascha Wildner 	bus_addr_t *paddr = arg;
140229aec1cSSascha Wildner 
141229aec1cSSascha Wildner 	if (error)
142229aec1cSSascha Wildner 		*paddr = 0;
143229aec1cSSascha Wildner 	else
144229aec1cSSascha Wildner 		*paddr = segs->ds_addr;
145229aec1cSSascha Wildner }
146229aec1cSSascha Wildner 
147229aec1cSSascha Wildner 
148229aec1cSSascha Wildner 
149229aec1cSSascha Wildner /**
150229aec1cSSascha Wildner  * @brief		Destroy a ring buffer
151229aec1cSSascha Wildner  * @param sc		software handle to the device
152229aec1cSSascha Wildner  * @param ring		ring buffer
153229aec1cSSascha Wildner  */
154229aec1cSSascha Wildner 
155229aec1cSSascha Wildner void
oce_destroy_ring_buffer(POCE_SOFTC sc,oce_ring_buffer_t * ring)156229aec1cSSascha Wildner oce_destroy_ring_buffer(POCE_SOFTC sc, oce_ring_buffer_t *ring)
157229aec1cSSascha Wildner {
158229aec1cSSascha Wildner 	oce_dma_free(sc, &ring->dma);
159229aec1cSSascha Wildner 	kfree(ring, M_DEVBUF);
160229aec1cSSascha Wildner }
161229aec1cSSascha Wildner 
162229aec1cSSascha Wildner 
163229aec1cSSascha Wildner 
164229aec1cSSascha Wildner oce_ring_buffer_t *
oce_create_ring_buffer(POCE_SOFTC sc,uint32_t q_len,uint32_t item_size)165229aec1cSSascha Wildner oce_create_ring_buffer(POCE_SOFTC sc,
166229aec1cSSascha Wildner 		uint32_t q_len, uint32_t item_size)
167229aec1cSSascha Wildner {
168229aec1cSSascha Wildner 	uint32_t size = q_len * item_size;
169229aec1cSSascha Wildner 	int rc;
170229aec1cSSascha Wildner 	oce_ring_buffer_t *ring;
171229aec1cSSascha Wildner 
172229aec1cSSascha Wildner 
173229aec1cSSascha Wildner 	ring = kmalloc(sizeof(oce_ring_buffer_t), M_DEVBUF, M_NOWAIT | M_ZERO);
174229aec1cSSascha Wildner 	if (ring == NULL)
175229aec1cSSascha Wildner 		return NULL;
176229aec1cSSascha Wildner 
177229aec1cSSascha Wildner 	ring->item_size = item_size;
178229aec1cSSascha Wildner 	ring->num_items = q_len;
179229aec1cSSascha Wildner 
180229aec1cSSascha Wildner 	rc = bus_dma_tag_create(NULL,
181229aec1cSSascha Wildner 				4096, 0,
182229aec1cSSascha Wildner 				BUS_SPACE_MAXADDR,
183229aec1cSSascha Wildner 				BUS_SPACE_MAXADDR,
184229aec1cSSascha Wildner 				size, 8, 4096, 0, &ring->dma.tag);
185229aec1cSSascha Wildner 	if (rc)
186229aec1cSSascha Wildner 		goto fail;
187229aec1cSSascha Wildner 
188229aec1cSSascha Wildner 
189229aec1cSSascha Wildner 	rc = bus_dmamem_alloc(ring->dma.tag,
190229aec1cSSascha Wildner 				&ring->dma.ptr,
191229aec1cSSascha Wildner 				BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
192229aec1cSSascha Wildner 				&ring->dma.map);
193229aec1cSSascha Wildner 	if (rc)
194229aec1cSSascha Wildner 		goto fail;
195229aec1cSSascha Wildner 
196229aec1cSSascha Wildner 	bzero(ring->dma.ptr, size);
197229aec1cSSascha Wildner 	bus_dmamap_sync(ring->dma.tag, ring->dma.map,
198229aec1cSSascha Wildner 			BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
199229aec1cSSascha Wildner 	ring->dma.paddr = 0;
200229aec1cSSascha Wildner 
201229aec1cSSascha Wildner 	return ring;
202229aec1cSSascha Wildner 
203229aec1cSSascha Wildner fail:
204229aec1cSSascha Wildner 	oce_dma_free(sc, &ring->dma);
205229aec1cSSascha Wildner 	kfree(ring, M_DEVBUF);
206229aec1cSSascha Wildner 	ring = NULL;
207229aec1cSSascha Wildner 	return NULL;
208229aec1cSSascha Wildner }
209229aec1cSSascha Wildner 
210229aec1cSSascha Wildner 
211229aec1cSSascha Wildner 
212229aec1cSSascha Wildner struct _oce_dmamap_paddr_table {
213229aec1cSSascha Wildner 	uint32_t max_entries;
214229aec1cSSascha Wildner 	uint32_t num_entries;
215229aec1cSSascha Wildner 	struct phys_addr *paddrs;
216229aec1cSSascha Wildner };
217229aec1cSSascha Wildner 
218229aec1cSSascha Wildner 
219229aec1cSSascha Wildner 
220229aec1cSSascha Wildner /**
221229aec1cSSascha Wildner  * @brief		Map ring buffer
222229aec1cSSascha Wildner  * @param arg		dma map phyical address table pointer
223229aec1cSSascha Wildner  * @param segs		dma memory segments
224229aec1cSSascha Wildner  * @param nseg		number of dma memory segments
225229aec1cSSascha Wildner  * @param error		maps only if error is 0
226229aec1cSSascha Wildner  */
227229aec1cSSascha Wildner static void
oce_dma_map_ring(void * arg,bus_dma_segment_t * segs,int nseg,int error)228229aec1cSSascha Wildner oce_dma_map_ring(void *arg, bus_dma_segment_t * segs, int nseg, int error)
229229aec1cSSascha Wildner {
230229aec1cSSascha Wildner 	int i;
231229aec1cSSascha Wildner 	struct _oce_dmamap_paddr_table *dpt =
232229aec1cSSascha Wildner 	    (struct _oce_dmamap_paddr_table *)arg;
233229aec1cSSascha Wildner 
234229aec1cSSascha Wildner 	if (error == 0) {
235229aec1cSSascha Wildner 		if (nseg <= dpt->max_entries) {
236229aec1cSSascha Wildner 			for (i = 0; i < nseg; i++) {
237229aec1cSSascha Wildner 				dpt->paddrs[i].lo = ADDR_LO(segs[i].ds_addr);
238229aec1cSSascha Wildner 				dpt->paddrs[i].hi = ADDR_HI(segs[i].ds_addr);
239229aec1cSSascha Wildner 			}
240229aec1cSSascha Wildner 			dpt->num_entries = nseg;
241229aec1cSSascha Wildner 		}
242229aec1cSSascha Wildner 	}
243229aec1cSSascha Wildner }
244229aec1cSSascha Wildner 
245229aec1cSSascha Wildner 
246229aec1cSSascha Wildner 
247229aec1cSSascha Wildner /**
248229aec1cSSascha Wildner  * @brief		Load bus dma map for a ring buffer
249229aec1cSSascha Wildner  * @param ring		ring buffer pointer
250229aec1cSSascha Wildner  * @param pa_list	physical address list
251229aec1cSSascha Wildner  * @returns		number entries
252229aec1cSSascha Wildner  */
253229aec1cSSascha Wildner uint32_t
oce_page_list(oce_ring_buffer_t * ring,struct phys_addr * pa_list)254229aec1cSSascha Wildner oce_page_list(oce_ring_buffer_t *ring, struct phys_addr *pa_list)
255229aec1cSSascha Wildner {
256229aec1cSSascha Wildner 	struct _oce_dmamap_paddr_table dpt;
257229aec1cSSascha Wildner 
258229aec1cSSascha Wildner 	dpt.max_entries = 8;
259229aec1cSSascha Wildner 	dpt.num_entries = 0;
260229aec1cSSascha Wildner 	dpt.paddrs = pa_list;
261229aec1cSSascha Wildner 
262229aec1cSSascha Wildner 	bus_dmamap_load(ring->dma.tag,
263229aec1cSSascha Wildner 			ring->dma.map,
264229aec1cSSascha Wildner 			ring->dma.ptr,
265229aec1cSSascha Wildner 			ring->item_size * ring->num_items,
266229aec1cSSascha Wildner 			oce_dma_map_ring, &dpt, BUS_DMA_NOWAIT);
267229aec1cSSascha Wildner 
268229aec1cSSascha Wildner 	return dpt.num_entries;
269229aec1cSSascha Wildner }
270