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