xref: /illumos-gate/usr/src/uts/common/io/1394/targets/dcam1394/dcam_ring_buff.c (revision 2570281cf351044b6936651ce26dbe1f801dcbd8)
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