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 * 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 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 * 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 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 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