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