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