]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/oce/oce_util.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / dev / oce / oce_util.c
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$ */
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
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(bus_get_dma_tag(sc->dev),
67                                 8, 0,
68                                 BUS_SPACE_MAXADDR,
69                                 BUS_SPACE_MAXADDR,
70                                 NULL, NULL,
71                                 size, 1, size, 0, NULL, NULL, &dma->tag);
72
73         if (rc == 0) {
74                 rc = bus_dmamem_alloc(dma->tag,
75                                       &dma->ptr,
76                                       BUS_DMA_NOWAIT | BUS_DMA_COHERENT |
77                                         BUS_DMA_ZERO,
78                                       &dma->map);
79         }
80
81         dma->paddr = 0;
82         if (rc == 0) {
83                 rc = bus_dmamap_load(dma->tag,
84                                      dma->map,
85                                      dma->ptr,
86                                      size,
87                                      oce_dma_map_addr,
88                                      &dma->paddr, flags | BUS_DMA_NOWAIT);
89                 if (dma->paddr == 0)
90                         rc = ENXIO;
91         }
92
93         if (rc != 0)
94                 oce_dma_free(sc, dma);
95
96         return rc;
97 }
98
99 /**
100  * @brief               Free DMA memory
101  * @param sc            software handle to the device
102  * @param dma           dma area to free
103  */
104 void
105 oce_dma_free(POCE_SOFTC sc, POCE_DMA_MEM dma)
106 {
107         if (dma->tag == NULL)
108                 return;
109
110         if (dma->map != NULL) {
111                 bus_dmamap_sync(dma->tag, dma->map,
112                                 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
113                 bus_dmamap_unload(dma->tag, dma->map);
114         }
115
116         if (dma->ptr != NULL) {
117                 bus_dmamem_free(dma->tag, dma->ptr, dma->map);
118                 dma->map = NULL;
119                 dma->ptr = NULL;
120         }
121
122         bus_dma_tag_destroy(dma->tag);
123         dma->tag = NULL;
124         
125         return;
126 }
127
128
129
130 /**
131  * @brief               Map DMA memory segment addresses
132  * @param arg           physical address pointer
133  * @param segs          dma memory segments
134  * @param nseg          number of dma memory segments
135  * @param error         if error, zeroes the physical address
136  */
137 void
138 oce_dma_map_addr(void *arg, bus_dma_segment_t * segs, int nseg, int error)
139 {
140         bus_addr_t *paddr = arg;
141
142         if (error)
143                 *paddr = 0;
144         else
145                 *paddr = segs->ds_addr;
146 }
147
148
149
150 /**
151  * @brief               Destroy a ring buffer
152  * @param sc            software handle to the device
153  * @param ring          ring buffer
154  */
155
156 void
157 oce_destroy_ring_buffer(POCE_SOFTC sc, oce_ring_buffer_t *ring)
158 {
159         oce_dma_free(sc, &ring->dma);
160         free(ring, M_DEVBUF);
161 }
162
163
164
165 oce_ring_buffer_t *
166 oce_create_ring_buffer(POCE_SOFTC sc,
167                 uint32_t q_len, uint32_t item_size)
168 {
169         uint32_t size = q_len * item_size;
170         int rc;
171         oce_ring_buffer_t *ring;
172
173
174         ring = malloc(sizeof(oce_ring_buffer_t), M_DEVBUF, M_NOWAIT | M_ZERO);
175         if (ring == NULL) 
176                 return NULL;
177
178         ring->item_size = item_size;
179         ring->num_items = q_len;
180
181         rc = bus_dma_tag_create(bus_get_dma_tag(sc->dev),
182                                 4096, 0,
183                                 BUS_SPACE_MAXADDR,
184                                 BUS_SPACE_MAXADDR,
185                                 NULL, NULL,
186                                 size, 8, 4096, 0, NULL, NULL, &ring->dma.tag);
187         if (rc)
188                 goto fail;
189
190
191         rc = bus_dmamem_alloc(ring->dma.tag,
192                                 &ring->dma.ptr,
193                                 BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
194                                 &ring->dma.map);
195         if (rc)
196                 goto fail;
197
198         bzero(ring->dma.ptr, size);
199         bus_dmamap_sync(ring->dma.tag, ring->dma.map,
200                         BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
201         ring->dma.paddr = 0;
202         
203         return ring;
204         
205 fail:
206         oce_dma_free(sc, &ring->dma);
207         free(ring, M_DEVBUF);
208         ring = NULL;
209         return NULL;
210 }
211
212
213
214 struct _oce_dmamap_paddr_table {
215         uint32_t max_entries;
216         uint32_t num_entries;
217         struct phys_addr *paddrs;
218 };
219
220
221
222 /**
223  * @brief               Map ring buffer
224  * @param arg           dma map phyical address table pointer
225  * @param segs          dma memory segments
226  * @param nseg          number of dma memory segments
227  * @param error         maps only if error is 0
228  */
229 static void
230 oce_dma_map_ring(void *arg, bus_dma_segment_t * segs, int nseg, int error)
231 {
232         int i;
233         struct _oce_dmamap_paddr_table *dpt =
234             (struct _oce_dmamap_paddr_table *)arg;
235
236         if (error == 0) {
237                 if (nseg <= dpt->max_entries) {
238                         for (i = 0; i < nseg; i++) {
239                                 dpt->paddrs[i].lo = ADDR_LO(segs[i].ds_addr);
240                                 dpt->paddrs[i].hi = ADDR_HI(segs[i].ds_addr);
241                         }
242                         dpt->num_entries = nseg;
243                 }
244         }
245 }
246
247
248
249 /**
250  * @brief               Load bus dma map for a ring buffer
251  * @param ring          ring buffer pointer
252  * @param pa_list       physical address list
253  * @returns             number entries
254  */
255 uint32_t
256 oce_page_list(oce_ring_buffer_t *ring, struct phys_addr *pa_list)
257 {
258         struct _oce_dmamap_paddr_table dpt;
259
260         dpt.max_entries = 8;
261         dpt.num_entries = 0;
262         dpt.paddrs = pa_list;
263
264         bus_dmamap_load(ring->dma.tag,
265                         ring->dma.map,
266                         ring->dma.ptr,
267                         ring->item_size * ring->num_items,
268                         oce_dma_map_ring, &dpt, BUS_DMA_NOWAIT);
269
270         return dpt.num_entries;
271 }