1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /* Copyright © 2003-2011 Emulex. All rights reserved. */
23
24 /*
25 * Source file containing the implementation of Driver buffer management
26 * and related helper functions
27 */
28 #include <oce_impl.h>
29
30 static ddi_dma_attr_t oce_dma_buf_attr = {
31 DMA_ATTR_V0, /* version number */
32 0x0000000000000000ull, /* low address */
33 0xFFFFFFFFFFFFFFFFull, /* high address */
34 0x00000000FFFFFFFFull, /* dma counter max */
35 OCE_DMA_ALIGNMENT, /* alignment */
36 0x00000FFF, /* burst sizes */
37 0x00000001, /* minimum transfer size */
38 0x00000000FFFFFFFFull, /* maximum transfer size */
39 0xFFFFFFFFFFFFFFFFull, /* maximum segment size */
40 1, /* scatter/gather list length */
41 0x00000001, /* granularity */
42 0 /* DMA flags */
43 };
44
45 static ddi_device_acc_attr_t oce_dma_buf_accattr = {
46 DDI_DEVICE_ATTR_V0,
47 DDI_NEVERSWAP_ACC,
48 DDI_STRICTORDER_ACC,
49 };
50
51
52 /*
53 * function to allocate a dma buffer for mapping memory va-pa
54 *
55 * dev - software handle to device
56 * size - size of the memory to map
57 * flags - DDI_DMA_CONSISTENT/DDI_DMA_STREAMING
58 *
59 * return pointer to a oce_dma_buf_t structure handling the map
60 * NULL => failure
61 */
62 oce_dma_buf_t *
oce_alloc_dma_buffer(struct oce_dev * dev,uint32_t size,ddi_dma_attr_t * dma_attr,uint32_t flags)63 oce_alloc_dma_buffer(struct oce_dev *dev,
64 uint32_t size, ddi_dma_attr_t *dma_attr, uint32_t flags)
65 {
66 oce_dma_buf_t *dbuf;
67 ddi_dma_cookie_t cookie;
68 uint32_t count;
69 size_t actual_len;
70 int ret = 0;
71
72 ASSERT(size > 0);
73 /* if NULL use default */
74 if (dma_attr == NULL) {
75 dma_attr = &oce_dma_buf_attr;
76 }
77
78 dbuf = kmem_zalloc(sizeof (oce_dma_buf_t), KM_NOSLEEP);
79 if (dbuf == NULL) {
80 return (NULL);
81 }
82
83 /* allocate dma handle */
84 ret = ddi_dma_alloc_handle(dev->dip, dma_attr,
85 DDI_DMA_DONTWAIT, NULL, &dbuf->dma_handle);
86 if (ret != DDI_SUCCESS) {
87 oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
88 "Failed to allocate DMA handle");
89 goto handle_fail;
90 }
91 /* allocate the DMA-able memory */
92 ret = ddi_dma_mem_alloc(dbuf->dma_handle, size, &oce_dma_buf_accattr,
93 flags, DDI_DMA_DONTWAIT, NULL, &dbuf->base,
94 &actual_len, &dbuf->acc_handle);
95 if (ret != DDI_SUCCESS) {
96 oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
97 "Failed to allocate DMA memory");
98 goto alloc_fail;
99 }
100
101 /* bind handle */
102 ret = ddi_dma_addr_bind_handle(dbuf->dma_handle,
103 (struct as *)0, dbuf->base, actual_len,
104 DDI_DMA_RDWR | flags,
105 DDI_DMA_DONTWAIT, NULL, &cookie, &count);
106 if (ret != DDI_DMA_MAPPED) {
107 oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
108 "Failed to bind dma handle");
109 goto bind_fail;
110 }
111 bzero(dbuf->base, actual_len);
112 dbuf->addr = cookie.dmac_laddress;
113 dbuf->size = actual_len;
114 /* usable length */
115 dbuf->len = size;
116 dbuf->num_pages = OCE_NUM_PAGES(size);
117 return (dbuf);
118
119 bind_fail:
120 ddi_dma_mem_free(&dbuf->acc_handle);
121 alloc_fail:
122 ddi_dma_free_handle(&dbuf->dma_handle);
123 handle_fail:
124 kmem_free(dbuf, sizeof (oce_dma_buf_t));
125 return (NULL);
126 } /* oce_dma_alloc_buffer */
127
128 /*
129 * function to delete a dma buffer
130 *
131 * dev - software handle to device
132 * dbuf - dma obj to delete
133 *
134 * return none
135 */
136 void
oce_free_dma_buffer(struct oce_dev * dev,oce_dma_buf_t * dbuf)137 oce_free_dma_buffer(struct oce_dev *dev, oce_dma_buf_t *dbuf)
138 {
139 _NOTE(ARGUNUSED(dev));
140
141 if (dbuf == NULL) {
142 return;
143 }
144 if (dbuf->dma_handle != NULL) {
145 (void) ddi_dma_unbind_handle(dbuf->dma_handle);
146 }
147 if (dbuf->acc_handle != NULL) {
148 ddi_dma_mem_free(&dbuf->acc_handle);
149 }
150 if (dbuf->dma_handle != NULL) {
151 ddi_dma_free_handle(&dbuf->dma_handle);
152 }
153 kmem_free(dbuf, sizeof (oce_dma_buf_t));
154 } /* oce_free_dma_buffer */
155
156 /*
157 * function to create a ring buffer
158 *
159 * dev - software handle to the device
160 * num_items - number of items in the ring
161 * item_size - size of an individual item in the ring
162 * flags - DDI_DMA_CONSISTENT/DDI_DMA_STREAMING for ring memory
163 *
164 * return pointer to a ring_buffer structure, NULL on failure
165 */
166 oce_ring_buffer_t *
create_ring_buffer(struct oce_dev * dev,uint32_t num_items,uint32_t item_size,uint32_t flags)167 create_ring_buffer(struct oce_dev *dev,
168 uint32_t num_items, uint32_t item_size, uint32_t flags)
169 {
170 oce_ring_buffer_t *ring;
171 uint32_t size;
172
173 /* allocate the ring buffer */
174 ring = kmem_zalloc(sizeof (oce_ring_buffer_t), KM_NOSLEEP);
175 if (ring == NULL) {
176 return (NULL);
177 }
178
179 /* get the dbuf defining the ring */
180 size = num_items * item_size;
181 ring->dbuf = oce_alloc_dma_buffer(dev, size, NULL, flags);
182 if (ring->dbuf == NULL) {
183 oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
184 "Ring buffer allocation failed");
185 goto dbuf_fail;
186 }
187
188 /* fill the rest of the ring */
189 ring->num_items = num_items;
190 ring->item_size = item_size;
191 ring->num_used = 0;
192 return (ring);
193
194 dbuf_fail:
195 kmem_free(ring, sizeof (oce_ring_buffer_t));
196 return (NULL);
197 } /* create_ring_buffer */
198
199 /*
200 * function to destroy a ring buffer
201 *
202 * dev - software handle to teh device
203 * ring - the ring buffer to delete
204 *
205 * return none
206 */
207 void
destroy_ring_buffer(struct oce_dev * dev,oce_ring_buffer_t * ring)208 destroy_ring_buffer(struct oce_dev *dev, oce_ring_buffer_t *ring)
209 {
210 ASSERT(dev != NULL);
211 ASSERT(ring != NULL);
212
213 /* free the dbuf associated with the ring */
214 oce_free_dma_buffer(dev, ring->dbuf);
215 ring->dbuf = NULL;
216
217 /* free the ring itself */
218 kmem_free(ring, sizeof (oce_ring_buffer_t));
219 } /* destroy_ring_buffer */
220
221
222 /*
223 * function to enable the fma flags
224 * fm_caps - FM capability flags
225 *
226 * return none
227 */
228
229 void
oce_set_dma_fma_flags(int fm_caps)230 oce_set_dma_fma_flags(int fm_caps)
231 {
232 if (fm_caps == DDI_FM_NOT_CAPABLE) {
233 return;
234 }
235
236 oce_dma_buf_accattr.devacc_attr_access = DDI_DEFAULT_ACC;
237
238 if (DDI_FM_DMA_ERR_CAP(fm_caps)) {
239 oce_dma_buf_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
240
241 } else {
242 oce_dma_buf_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
243
244 }
245 } /* oce_set_dma_fma_flags */
246