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