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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * dcam_ring_buff.c 29 * 30 * dcam1394 driver. Video frame ring buffer support. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/kmem.h> 35 #include <sys/ddidmareq.h> 36 #include <sys/types.h> 37 #include <sys/inttypes.h> 38 #include <sys/cmn_err.h> 39 40 #include <sys/1394/targets/dcam1394/dcam.h> 41 42 /* 43 * ring_buff_create 44 * 45 * - alloc ring_buff_t structure 46 * - init ring_buff's num_buffs, buff_num_bytes, num_read_ptrs, 47 * read_ptr_pos 48 * - alloc (num buffs) entries in ring_buff's buff_info_array_p 49 * 50 * - for each buff 51 * - alloc DMA handle; store DMA handle in buff's buff_info_array_p 52 * - alloc mem for DMA transfer; store base addr, data access handle 53 * in buff's buff_info_array_p entry 54 * - bind alloc'ed mem to DMA handle; store assoc info in buff's 55 * buff_info_array_p entry 56 */ 57 ring_buff_t * 58 ring_buff_create(dcam_state_t *softc_p, size_t num_buffs, 59 size_t buff_num_bytes) 60 { 61 buff_info_t *buff_info_p; 62 size_t buff; 63 int i, rc; 64 ring_buff_t *ring_buff_p; 65 size_t num_bytes; 66 67 num_bytes = sizeof (ring_buff_t); 68 69 ring_buff_p = (ring_buff_t *)kmem_alloc(num_bytes, KM_SLEEP); 70 71 ring_buff_p->num_buffs = num_buffs; 72 ring_buff_p->buff_num_bytes = buff_num_bytes; 73 ring_buff_p->write_ptr_pos = 0; 74 ring_buff_p->num_read_ptrs = 0; 75 ring_buff_p->read_ptr_incr_val = 1; 76 77 for (i = 0; i < MAX_NUM_READ_PTRS; i++) { 78 ring_buff_p->read_ptr_pos[i] = (size_t)-1; 79 } 80 81 num_bytes = num_buffs * sizeof (buff_info_t); 82 83 ring_buff_p->buff_info_array_p = 84 (buff_info_t *)kmem_alloc(num_bytes, KM_SLEEP); 85 86 for (buff = 0; buff < num_buffs; buff++) { 87 88 buff_info_p = &(ring_buff_p->buff_info_array_p[buff]); 89 90 if ((ddi_dma_alloc_handle( 91 softc_p->dip, 92 &softc_p->attachinfo.dma_attr, 93 DDI_DMA_DONTWAIT, 94 NULL, 95 &(buff_info_p->dma_handle))) != DDI_SUCCESS) { 96 ring_buff_free(softc_p, ring_buff_p); 97 return (NULL); 98 } 99 100 if (ddi_dma_mem_alloc( 101 buff_info_p->dma_handle, 102 buff_num_bytes, 103 &softc_p->attachinfo.acc_attr, 104 DDI_DMA_STREAMING, 105 DDI_DMA_DONTWAIT, 106 (caddr_t)NULL, 107 &(buff_info_p->kaddr_p), 108 &(buff_info_p->real_len), 109 &(buff_info_p->data_acc_handle)) != DDI_SUCCESS) { 110 ring_buff_free(softc_p, ring_buff_p); 111 112 /* 113 * Print a warning, this triggered the bug 114 * report #4423667. This call can fail if 115 * the memory tests are being run in sunvts. 116 * The fact is, this code is doing the right 117 * thing. I added an error message, so that 118 * future occurrences can be dealt with directly. 119 * This is not a bug... The vmem test in sunvts 120 * can eat up all swap/virtual memory. 121 */ 122 cmn_err(CE_WARN, 123 "ddi_dma_mem_alloc() failed in ring_buff_create(),"\ 124 " insufficient memory resources.\n"); 125 return (NULL); 126 } 127 128 rc = ddi_dma_addr_bind_handle( 129 buff_info_p->dma_handle, 130 (struct as *)NULL, 131 (caddr_t)buff_info_p->kaddr_p, 132 buff_info_p->real_len, 133 DDI_DMA_RDWR | DDI_DMA_STREAMING, 134 DDI_DMA_DONTWAIT, 135 NULL, 136 &buff_info_p->dma_cookie, 137 &buff_info_p->dma_cookie_count); 138 139 if (rc != DDI_DMA_MAPPED) { 140 ring_buff_free(softc_p, ring_buff_p); 141 return (NULL); 142 } 143 } 144 145 return (ring_buff_p); 146 } 147 148 149 /* 150 * ring_buff_free 151 */ 152 void 153 ring_buff_free(dcam_state_t *softc_p, ring_buff_t *ring_buff_p) 154 { 155 buff_info_t *buff_info_p; 156 int i; 157 158 if (ring_buff_p == NULL) { 159 softc_p->ring_buff_p = NULL; 160 return; 161 } 162 163 if (ring_buff_p->buff_info_array_p != NULL) { 164 for (i = 0; i < ring_buff_p->num_buffs; i++) { 165 166 buff_info_p = &(ring_buff_p->buff_info_array_p[i]); 167 168 (void) ddi_dma_unbind_handle(buff_info_p->dma_handle); 169 ddi_dma_mem_free(&buff_info_p->data_acc_handle); 170 ddi_dma_free_handle(&buff_info_p->dma_handle); 171 } 172 173 kmem_free(ring_buff_p->buff_info_array_p, 174 ring_buff_p->num_buffs * sizeof (buff_info_t)); 175 } 176 177 kmem_free(ring_buff_p, sizeof (ring_buff_t)); 178 179 softc_p->ring_buff_p = NULL; 180 } 181 182 183 /* 184 * ring_buff_read_ptr_add 185 */ 186 int 187 ring_buff_read_ptr_add(ring_buff_t *ring_buff_p) 188 { 189 int i; 190 int read_ptr_id; 191 192 read_ptr_id = -1; 193 194 for (i = 0; i < MAX_NUM_READ_PTRS; i++) { 195 196 if (ring_buff_p->read_ptr_pos[i] == -1) { 197 ring_buff_p->read_ptr_pos[i] = 0; 198 read_ptr_id = i; 199 break; 200 } 201 } 202 203 return (read_ptr_id); 204 } 205 206 207 /* 208 * ring_buff_read_ptr_remove 209 */ 210 int 211 ring_buff_read_ptr_remove(ring_buff_t *ring_buff_p, int read_ptr_id) 212 { 213 ring_buff_p->read_ptr_pos[read_ptr_id] = (size_t)-1; 214 215 return (0); 216 } 217 218 219 /* 220 * ring_buff_read_ptr_buff_get 221 * 222 * Return pointer to buffer that a read pointer associated with the 223 * ring buffer is pointing to. 224 */ 225 buff_info_t * 226 ring_buff_read_ptr_buff_get(ring_buff_t *ring_buff_p, int read_ptr_id) 227 { 228 size_t read_ptr_pos; 229 buff_info_t *buff_info_p; 230 231 read_ptr_pos = ring_buff_p->read_ptr_pos[read_ptr_id]; 232 buff_info_p = &(ring_buff_p->buff_info_array_p[read_ptr_pos]); 233 234 return (buff_info_p); 235 } 236 237 238 /* 239 * ring_buff_read_ptr_pos_get 240 */ 241 size_t 242 ring_buff_read_ptr_pos_get(ring_buff_t *ring_buff_p, int read_ptr_id) 243 { 244 return (ring_buff_p->read_ptr_pos[read_ptr_id]); 245 } 246 247 248 /* 249 * ring_buff_read_ptr_incr 250 */ 251 void 252 ring_buff_read_ptr_incr(ring_buff_t *ring_buff_p, int read_ptr_id) 253 { 254 size_t read_ptr_pos; 255 #if defined(_ADDL_RING_BUFF_CHECK) 256 size_t lrp, lwp; /* linear read, write positions */ 257 #endif /* _ADDL_RING_BUFFER_CHECK */ 258 259 /* 260 * increment the read pointer based on read_ptr_incr_val 261 * which can vary from 1 to 10 262 */ 263 264 /* get current read pointer pos */ 265 read_ptr_pos = ring_buff_p->read_ptr_pos[read_ptr_id]; 266 267 ring_buff_p->read_ptr_pos[read_ptr_id] = 268 (read_ptr_pos + 1) % ring_buff_p->num_buffs; 269 270 #if defined(_ADDL_RING_BUFF_CHECK) 271 if ((read_ptr_pos == 0) && (ring_buff_p->write_ptr_pos == 0)) { 272 return; 273 } 274 275 if (read_ptr_pos < ring_buff_p->write_ptr_pos) { 276 277 /* calculate new read pointer position */ 278 if ((read_ptr_pos + ring_buff_p->read_ptr_incr_val) < 279 ring_buff_p->write_ptr_pos) { 280 281 /* there is still some valid frame data */ 282 ring_buff_p->read_ptr_pos[read_ptr_id] = 283 (read_ptr_pos + 284 ring_buff_p->read_ptr_incr_val) % 285 ring_buff_p->num_buffs; 286 } else { 287 /* 288 * we have skipped beyond available frame 289 * data, so the buffer is empty 290 */ 291 ring_buff_p->read_ptr_pos[read_ptr_id] = 292 ring_buff_p->write_ptr_pos; 293 } 294 } else { 295 /* 296 * since read pointer is ahead of write pointer, 297 * it becomes easier to check for new read 298 * pointer position if we pretend that our data 299 * buffer is linear instead of circular 300 */ 301 302 lrp = read_ptr_pos + ring_buff_p->read_ptr_incr_val; 303 lwp = ring_buff_p->num_buffs + 304 ring_buff_p->write_ptr_pos; 305 306 if (lrp < lwp) { 307 /* there is still some valid frame data */ 308 ring_buff_p->read_ptr_pos[read_ptr_id] = 309 (read_ptr_pos + 310 ring_buff_p->read_ptr_incr_val) % 311 ring_buff_p->num_buffs; 312 } else { 313 /* 314 * we have skipped beyond available 315 * frame data, so the buffer is empty 316 */ 317 ring_buff_p->read_ptr_pos[read_ptr_id] = 318 ring_buff_p->write_ptr_pos; 319 } 320 } 321 #endif /* _ADDL_RING_BUFF_CHECK */ 322 } 323 324 325 /* 326 * ring_buff_write_ptr_pos_get 327 */ 328 size_t 329 ring_buff_write_ptr_pos_get(ring_buff_t *ring_buff_p) 330 { 331 return (ring_buff_p->write_ptr_pos); 332 } 333 334 335 /* 336 * ring_buff_write_ptr_incr 337 */ 338 void 339 ring_buff_write_ptr_incr(ring_buff_t *ring_buff_p) 340 { 341 size_t write_ptr_pos; 342 343 write_ptr_pos = ring_buff_p->write_ptr_pos; 344 345 ring_buff_p->write_ptr_pos = 346 ((write_ptr_pos + 1) % ring_buff_p->num_buffs); 347 } 348