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 2001-2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * hci1394_isoch.c
31 * HCI HAL isochronous interface routines. Contains routines used
32 * internally within the HAL to manage isochronous contexts, and
33 * also routines called from the Services Layer to manage an isochronous
34 * DMA resource.
35 */
36
37 #include <sys/types.h>
38 #include <sys/kmem.h>
39 #include <sys/conf.h>
40 #include <sys/ddi.h>
41 #include <sys/sunddi.h>
42
43 #include <sys/1394/h1394.h>
44 #include <sys/1394/adapters/hci1394.h>
45
46 /*
47 * Patchable variable used to indicate the number of microseconds to wait
48 * for an isoch ctxt to stop ("active" goes low) after clearing the "run"
49 * bit
50 */
51 uint_t hci1394_iso_ctxt_stop_delay_uS = 1000;
52
53 /*
54 * Number of microseconds to wait in hci1394_do_stop() for an isoch ctxt
55 * interrupt handler to complete. Experiments showed that in some cases
56 * the timeout needed was as long as 2 seconds. This is probably due to
57 * significant interrupt processing overhead for certain IXL chains.
58 */
59 uint_t hci1394_iso_ctxt_stop_intr_timeout_uS = 5 * 1000000;
60
61 /*
62 * hci1394_isoch_init()
63 * Initialize the isochronous dma soft state.
64 */
65 void
hci1394_isoch_init(hci1394_drvinfo_t * drvinfo,hci1394_ohci_handle_t ohci,hci1394_isoch_handle_t * isoch_hdl)66 hci1394_isoch_init(hci1394_drvinfo_t *drvinfo, hci1394_ohci_handle_t ohci,
67 hci1394_isoch_handle_t *isoch_hdl)
68 {
69 hci1394_isoch_t *isochp;
70 int i;
71
72 ASSERT(drvinfo != NULL);
73 ASSERT(isoch_hdl != NULL);
74 TNF_PROBE_0_DEBUG(hci1394_isoch_init_enter, HCI1394_TNF_HAL_STACK_ISOCH,
75 "");
76
77 isochp = kmem_alloc(sizeof (hci1394_isoch_t), KM_SLEEP);
78
79 /* initialize contexts */
80 for (i = 0; i < HCI1394_MAX_ISOCH_CONTEXTS; i++) {
81 isochp->ctxt_xmit[i].ctxt_index = i;
82
83 /* init context flags to 0 */
84 isochp->ctxt_xmit[i].ctxt_flags = 0;
85
86 mutex_init(&isochp->ctxt_xmit[i].intrprocmutex, NULL,
87 MUTEX_DRIVER, drvinfo->di_iblock_cookie);
88 cv_init(&isochp->ctxt_xmit[i].intr_cv, NULL,
89 CV_DRIVER, NULL);
90
91 isochp->ctxt_recv[i].ctxt_index = i;
92 isochp->ctxt_recv[i].ctxt_flags = HCI1394_ISO_CTXT_RECV;
93 mutex_init(&isochp->ctxt_recv[i].intrprocmutex, NULL,
94 MUTEX_DRIVER, drvinfo->di_iblock_cookie);
95 cv_init(&isochp->ctxt_recv[i].intr_cv, NULL,
96 CV_DRIVER, NULL);
97 }
98
99 /* initialize the count for allocated isoch dma */
100 isochp->isoch_dma_alloc_cnt = 0;
101
102 /* initialize the cycle_lost_thresh struct */
103 isochp->cycle_lost_thresh.last_intr_time = 0;
104 isochp->cycle_lost_thresh.delta_t_counter = 0;
105 isochp->cycle_lost_thresh.delta_t_thresh = HCI1394_CYC_LOST_DELTA;
106 isochp->cycle_lost_thresh.counter_thresh = HCI1394_CYC_LOST_COUNT;
107
108 /* initialize the cycle_incon_thresh struct */
109 isochp->cycle_incon_thresh.last_intr_time = 0;
110 isochp->cycle_incon_thresh.delta_t_counter = 0;
111 isochp->cycle_incon_thresh.delta_t_thresh = HCI1394_CYC_INCON_DELTA;
112 isochp->cycle_incon_thresh.counter_thresh = HCI1394_CYC_INCON_COUNT;
113
114 /* determine number of contexts supported */
115 isochp->ctxt_xmit_count = hci1394_ohci_it_ctxt_count_get(ohci);
116 isochp->ctxt_recv_count = hci1394_ohci_ir_ctxt_count_get(ohci);
117
118 /* the isochronous context mutex is used during some error interrupts */
119 mutex_init(&isochp->ctxt_list_mutex, NULL, MUTEX_DRIVER,
120 drvinfo->di_iblock_cookie);
121
122 *isoch_hdl = isochp;
123
124 TNF_PROBE_0_DEBUG(hci1394_isoch_init_exit, HCI1394_TNF_HAL_STACK_ISOCH,
125 "");
126 }
127
128 /*
129 * hci1394_isoch_fini()
130 * Cleanup after hci1394_isoch_init. This should be called during detach.
131 */
132 void
hci1394_isoch_fini(hci1394_isoch_handle_t * isoch_hdl)133 hci1394_isoch_fini(hci1394_isoch_handle_t *isoch_hdl)
134 {
135 hci1394_isoch_t *isochp;
136 int i;
137
138 ASSERT(isoch_hdl != NULL);
139 TNF_PROBE_0_DEBUG(hci1394_isoch_fini_enter, HCI1394_TNF_HAL_STACK_ISOCH,
140 "");
141
142 isochp = *isoch_hdl;
143
144 for (i = 0; i < HCI1394_MAX_ISOCH_CONTEXTS; i++) {
145 mutex_destroy(&isochp->ctxt_xmit[i].intrprocmutex);
146 mutex_destroy(&isochp->ctxt_recv[i].intrprocmutex);
147 cv_destroy(&isochp->ctxt_xmit[i].intr_cv);
148 cv_destroy(&isochp->ctxt_recv[i].intr_cv);
149 }
150
151 mutex_destroy(&isochp->ctxt_list_mutex);
152 kmem_free(isochp, sizeof (hci1394_isoch_t));
153 *isoch_hdl = NULL;
154
155 TNF_PROBE_0_DEBUG(hci1394_isoch_fini_exit, HCI1394_TNF_HAL_STACK_ISOCH,
156 "");
157 }
158
159
160 /*
161 * hci1394_isoch_resume()
162 * There is currently nothing to do for resume. This is a placeholder.
163 */
164 /* ARGSUSED */
165 int
hci1394_isoch_resume(hci1394_state_t * soft_state)166 hci1394_isoch_resume(hci1394_state_t *soft_state)
167 {
168 TNF_PROBE_0_DEBUG(hci1394_isoch_resume_enter,
169 HCI1394_TNF_HAL_STACK_ISOCH, "");
170 TNF_PROBE_0_DEBUG(hci1394_isoch_resume_exit,
171 HCI1394_TNF_HAL_STACK_ISOCH, "");
172 return (DDI_SUCCESS);
173 }
174
175 /*
176 * hci1394_alloc_isoch_dma ()
177 * Called by the Services Layer. Used to allocate a local Isoch DMA context.
178 * Goes through appropriate context list (either transmit or receive)
179 * looking for an unused context. Fails if none found.
180 * Then compiles the provided IXL program.
181 */
182 int
hci1394_alloc_isoch_dma(void * hal_private,id1394_isoch_dmainfo_t * idi,void ** hal_idma_handlep,int * resultp)183 hci1394_alloc_isoch_dma(void *hal_private, id1394_isoch_dmainfo_t *idi,
184 void **hal_idma_handlep, int *resultp)
185 {
186 int i;
187 int err;
188 hci1394_state_t *soft_statep = (hci1394_state_t *)hal_private;
189 hci1394_isoch_t *isochp;
190 hci1394_iso_ctxt_t *ctxtp;
191
192
193 ASSERT(soft_statep != NULL);
194 ASSERT(hal_idma_handlep != NULL);
195 TNF_PROBE_0_DEBUG(hci1394_alloc_isoch_dma_enter,
196 HCI1394_TNF_HAL_STACK_ISOCH, "");
197
198 isochp = soft_statep->isoch;
199 *hal_idma_handlep = NULL;
200
201 /*
202 * find context to use based on whether talking(send) or listening(recv)
203 */
204 mutex_enter(&isochp->ctxt_list_mutex);
205 if ((idi->idma_options & ID1394_TALK) != 0) {
206 /* TRANSMIT */
207
208 TNF_PROBE_1_DEBUG(hci1394_alloc_isoch_dma_transmit,
209 HCI1394_TNF_HAL_INFO_ISOCH, "", tnf_string, msg,
210 "Allocating isoch transmit context");
211
212 /*
213 * search through list of hardware supported contexts for
214 * one that's not inuse
215 */
216 for (i = 0; i < isochp->ctxt_xmit_count; i++) {
217 if ((isochp->ctxt_xmit[i].ctxt_flags &
218 HCI1394_ISO_CTXT_INUSE) == 0) {
219 break;
220 }
221 }
222
223 /* if there aren't any left, return an error */
224 if (i >= isochp->ctxt_xmit_count) {
225 TNF_PROBE_1(hci1394_alloc_isoch_dma_xmit_rsrc_error,
226 HCI1394_TNF_HAL_ERROR_ISOCH, "", tnf_string, errmsg,
227 "Out of isoch transmit resources");
228 TNF_PROBE_0_DEBUG(hci1394_alloc_isoch_dma_exit,
229 HCI1394_TNF_HAL_STACK_ISOCH, "");
230
231 mutex_exit(&isochp->ctxt_list_mutex);
232 *resultp = IXL1394_ENO_DMA_RESRCS;
233 return (DDI_FAILURE);
234 }
235
236 TNF_PROBE_1_DEBUG(t1394_alloc_isoch_dma_it_ctxtnum,
237 HCI1394_TNF_HAL_INFO_ISOCH, "", tnf_int, it_ctxt_num, i);
238
239 /* mark inuse and set up handle to context */
240 isochp->ctxt_xmit[i].ctxt_flags |= HCI1394_ISO_CTXT_INUSE;
241 ctxtp = &isochp->ctxt_xmit[i];
242 isochp->ctxt_xmit[i].ctxt_regsp =
243 &soft_statep->ohci->ohci_regs->it[i];
244 } else {
245 /* RECEIVE */
246
247 TNF_PROBE_1_DEBUG(hci1394_alloc_isoch_dma_receive,
248 HCI1394_TNF_HAL_INFO_ISOCH, "", tnf_string, msg,
249 "Allocating isoch receive context");
250
251 /* search thru implemented contexts for one that's available */
252 for (i = 0; i < isochp->ctxt_recv_count; i++) {
253 if ((isochp->ctxt_recv[i].ctxt_flags &
254 HCI1394_ISO_CTXT_INUSE) == 0) {
255 break;
256 }
257 }
258
259 /* if there aren't any left, return an error */
260 /* XXX support for multi-chan could go here */
261 if (i >= isochp->ctxt_recv_count) {
262
263 TNF_PROBE_1(t1394_alloc_isoch_dma_ir_rsrc_error,
264 HCI1394_TNF_HAL_ERROR_ISOCH, "", tnf_string, errmsg,
265 "Out of isoch receive resources");
266 TNF_PROBE_0_DEBUG(hci1394_alloc_isoch_dma_exit,
267 HCI1394_TNF_HAL_STACK_ISOCH, "");
268
269 mutex_exit(&isochp->ctxt_list_mutex);
270 *resultp = IXL1394_ENO_DMA_RESRCS;
271 return (DDI_FAILURE);
272 }
273
274 /* set up receive mode flags */
275 if ((idi->idma_options & ID1394_LISTEN_BUF_MODE) != 0) {
276 isochp->ctxt_recv[i].ctxt_flags |=
277 HCI1394_ISO_CTXT_BFFILL;
278 }
279 if ((idi->idma_options & ID1394_RECV_HEADERS) != 0) {
280 isochp->ctxt_recv[i].ctxt_flags |=
281 HCI1394_ISO_CTXT_RHDRS;
282 }
283
284 TNF_PROBE_1_DEBUG(hci1394_alloc_isoch_dma_recv_ctxtnum,
285 HCI1394_TNF_HAL_INFO_ISOCH, "", tnf_int, recv_ctxt_num, i);
286
287 /* mark inuse and set up handle to context */
288 isochp->ctxt_recv[i].ctxt_flags |= HCI1394_ISO_CTXT_INUSE;
289 ctxtp = &isochp->ctxt_recv[i];
290
291 isochp->ctxt_recv[i].ctxt_regsp = (hci1394_ctxt_regs_t *)
292 &soft_statep->ohci->ohci_regs->ir[i];
293 }
294 mutex_exit(&isochp->ctxt_list_mutex);
295
296 /* before compiling, set up some default context values */
297 ctxtp->isochan = idi->channel_num;
298 ctxtp->default_tag = idi->default_tag;
299 ctxtp->default_sync = idi->default_sync;
300 ctxtp->global_callback_arg = idi->global_callback_arg;
301 ctxtp->isoch_dma_stopped = idi->isoch_dma_stopped;
302 ctxtp->idma_evt_arg = idi->idma_evt_arg;
303 ctxtp->isospd = idi->it_speed;
304 ctxtp->default_skipmode = idi->it_default_skip;
305 ctxtp->default_skiplabelp = idi->it_default_skiplabel;
306
307 err = hci1394_compile_ixl(soft_statep, ctxtp, idi->ixlp, resultp);
308
309
310 /*
311 * if the compile failed, clear the appropriate flags.
312 * Note that the context mutex is needed to eliminate race condition
313 * with cycle_inconsistent and other error intrs.
314 */
315 if (err != DDI_SUCCESS) {
316
317 mutex_enter(&isochp->ctxt_list_mutex);
318 if ((ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RECV) != 0) {
319 /* undo the set up of receive mode flags */
320 isochp->ctxt_recv[i].ctxt_flags &=
321 ~HCI1394_ISO_CTXT_BFFILL;
322 isochp->ctxt_recv[i].ctxt_flags &=
323 ~HCI1394_ISO_CTXT_RHDRS;
324 }
325 ctxtp->ctxt_flags &= ~HCI1394_ISO_CTXT_INUSE;
326 mutex_exit(&isochp->ctxt_list_mutex);
327
328 TNF_PROBE_2(t1394_alloc_isoch_dma_compile_fail,
329 HCI1394_TNF_HAL_ERROR_ISOCH, "", tnf_string, errmsg,
330 "IXL compilation error", tnf_int, ixl_error, *resultp);
331 TNF_PROBE_0_DEBUG(hci1394_alloc_isoch_dma_exit,
332 HCI1394_TNF_HAL_STACK_ISOCH, "");
333 return (DDI_FAILURE);
334 }
335
336 /*
337 * Update count of allocated isoch dma (and enable interrupts
338 * if necessary)
339 */
340 mutex_enter(&isochp->ctxt_list_mutex);
341 if (isochp->isoch_dma_alloc_cnt == 0) {
342 hci1394_ohci_intr_clear(soft_statep->ohci,
343 OHCI_INTR_CYC_LOST | OHCI_INTR_CYC_INCONSISTENT);
344 hci1394_ohci_intr_enable(soft_statep->ohci,
345 OHCI_INTR_CYC_LOST | OHCI_INTR_CYC_INCONSISTENT);
346 }
347 isochp->isoch_dma_alloc_cnt++;
348 mutex_exit(&isochp->ctxt_list_mutex);
349
350 /* No errors, so all set to go. initialize interrupt/execution flags */
351 ctxtp->intr_flags = 0;
352
353 TNF_PROBE_0_DEBUG(hci1394_alloc_isoch_dma_exit,
354 HCI1394_TNF_HAL_STACK_ISOCH, "");
355
356 *hal_idma_handlep = ctxtp;
357 return (DDI_SUCCESS);
358 }
359
360
361 /*
362 * hci1394_start_isoch_dma()
363 * Used to start an allocated isochronous dma resource.
364 * Sets the context's command ptr to start at the first IXL,
365 * sets up IR match register (if IR), and enables the context_control
366 * register RUN bit.
367 */
368 /* ARGSUSED */
369 int
hci1394_start_isoch_dma(void * hal_private,void * hal_isoch_dma_handle,id1394_isoch_dma_ctrlinfo_t * idma_ctrlinfop,uint_t flags,int * result)370 hci1394_start_isoch_dma(void *hal_private, void *hal_isoch_dma_handle,
371 id1394_isoch_dma_ctrlinfo_t *idma_ctrlinfop, uint_t flags, int *result)
372 {
373 hci1394_state_t *soft_statep = (hci1394_state_t *)hal_private;
374 hci1394_iso_ctxt_t *ctxtp;
375 int tag0, tag1, tag2, tag3;
376
377 TNF_PROBE_0_DEBUG(hci1394_start_isoch_dma_enter,
378 HCI1394_TNF_HAL_STACK_ISOCH, "");
379
380 /* pick up the context pointer from the private idma data */
381 ctxtp = (hci1394_iso_ctxt_t *)hal_isoch_dma_handle;
382
383 ASSERT(hal_private != NULL);
384 ASSERT(ctxtp != NULL);
385 ASSERT(idma_ctrlinfop != NULL);
386 TNF_PROBE_4_DEBUG(hci1394_start_isoch_dma_ctxt_info,
387 HCI1394_TNF_HAL_INFO_ISOCH, "", tnf_opaque, ctxt_ptr, ctxtp,
388 tnf_int, ctxt_index, ctxtp->ctxt_index, tnf_opaque, ctxt_flags,
389 ctxtp->ctxt_flags, tnf_opaque, first_ixl, ctxtp->ixl_firstp);
390
391
392 /* if the context is already running, just exit. else set running */
393 mutex_enter(&soft_statep->isoch->ctxt_list_mutex);
394 if ((ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RUNNING) != 0) {
395
396 mutex_exit(&soft_statep->isoch->ctxt_list_mutex);
397
398 TNF_PROBE_1_DEBUG(hci1394_start_isoch_dma_exit,
399 HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
400 "context already running");
401 return (DDI_SUCCESS);
402 }
403 ctxtp->ctxt_flags |= HCI1394_ISO_CTXT_RUNNING;
404 mutex_exit(&soft_statep->isoch->ctxt_list_mutex);
405
406 ctxtp->intr_flags &= ~HCI1394_ISO_CTXT_STOP;
407
408 /* initialize context values */
409 ctxtp->ixl_execp = ctxtp->ixl_firstp; /* start of ixl chain */
410 ctxtp->ixl_exec_depth = 0;
411 ctxtp->dma_last_time = 0;
412 ctxtp->rem_noadv_intrs = ctxtp->max_noadv_intrs;
413
414 /*
415 * clear out hci DMA descriptor status to start with clean slate.
416 * note that statuses could be set if context was previously started
417 * then stopped.
418 */
419 hci1394_ixl_reset_status(ctxtp);
420
421 /* set up registers, and start isoch */
422 if (ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RECV) {
423
424 /* set context's command ptr to the first descriptor */
425 hci1394_ohci_ir_cmd_ptr_set(soft_statep->ohci,
426 ctxtp->ctxt_index, ctxtp->dma_mem_execp);
427
428 TNF_PROBE_2_DEBUG(hci1394_start_isoch_dma_index_info,
429 HCI1394_TNF_HAL_INFO_ISOCH, "", tnf_string, msg,
430 "starting IR ctxt", tnf_int, ctxt_num, ctxtp->ctxt_index);
431
432 /*
433 * determine correct tag values. map target's requested 2-bit
434 * tag into one of the 4 openHCI tag bits.
435 * XXX for now the t1394 api only supports a single tag setting,
436 * whereas openhci supports a set of (non-mutually exclusive)
437 * valid tags. if the api changes to support multiple
438 * simultaneous tags, then this code must be changed.
439 */
440 tag0 = 0;
441 tag1 = 1;
442 tag2 = 2;
443 tag3 = 3;
444 if (ctxtp->default_tag == 0x0)
445 tag0 = 1;
446 else if (ctxtp->default_tag == 0x1)
447 tag1 = 1;
448 else if (ctxtp->default_tag == 0x2)
449 tag2 = 1;
450 else if (ctxtp->default_tag == 0x3)
451 tag3 = 1;
452
453 /* set match register as desired */
454 HCI1394_IRCTXT_MATCH_WRITE(soft_statep, ctxtp->ctxt_index, tag3,
455 tag2, tag1, tag0,
456 idma_ctrlinfop->start_cycle /* cycleMatch */,
457 ctxtp->default_sync /* sync */, 0 /* tag1sync */,
458 ctxtp->isochan /* chan */);
459
460 /* clear all bits in context ctrl reg to init to known state */
461 HCI1394_IRCTXT_CTRL_CLR(soft_statep, ctxtp->ctxt_index,
462 (uint32_t)1, 1, 1, 1, 1);
463
464 /* set desired values in context control register */
465 HCI1394_IRCTXT_CTRL_SET(soft_statep, ctxtp->ctxt_index,
466 (ctxtp->ctxt_flags & HCI1394_ISO_CTXT_BFFILL) != 0 /* bf */,
467 (ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RHDRS) != 0 /* hdr */,
468 (flags & ID1394_START_ON_CYCLE) != 0 /* match enbl */,
469 0 /* multi-chan mode */, 1 /* run */, 0 /* wake */);
470
471 /*
472 * before enabling interrupts, make sure any vestige interrupt
473 * event (from a previous use) is cleared.
474 */
475 hci1394_ohci_ir_intr_clear(soft_statep->ohci,
476 (uint32_t)(0x1 << ctxtp->ctxt_index));
477
478 /* enable interrupts for this IR context */
479 hci1394_ohci_ir_intr_enable(soft_statep->ohci,
480 (uint32_t)(0x1 << ctxtp->ctxt_index));
481
482 } else {
483 /* TRANSMIT */
484
485 /* set context's command ptr to the first descriptor */
486 hci1394_ohci_it_cmd_ptr_set(soft_statep->ohci,
487 ctxtp->ctxt_index, ctxtp->dma_mem_execp);
488
489 TNF_PROBE_2_DEBUG(hci1394_start_isoch_dma_index_info,
490 HCI1394_TNF_HAL_INFO_ISOCH, "", tnf_string, msg,
491 "starting IT ctxt", tnf_int, ctxt_num, ctxtp->ctxt_index);
492
493 /* set desired values in context control register */
494 HCI1394_ITCTXT_CTRL_SET(soft_statep, ctxtp->ctxt_index,
495 ((flags & ID1394_START_ON_CYCLE) != 0) /* match enable */,
496 idma_ctrlinfop->start_cycle /* cycle Match */,
497 1 /* run */, 0 /* wake */);
498
499 /*
500 * before enabling interrupts, make sure any vestige interrupt
501 * event (from a previous use) is cleared.
502 */
503 hci1394_ohci_it_intr_clear(soft_statep->ohci,
504 (uint32_t)(0x1 << ctxtp->ctxt_index));
505
506 /* enable interrupts for this IT context */
507 hci1394_ohci_it_intr_enable(soft_statep->ohci,
508 (uint32_t)(0x1 << ctxtp->ctxt_index));
509 }
510
511 TNF_PROBE_0_DEBUG(hci1394_start_isoch_dma_exit,
512 HCI1394_TNF_HAL_STACK_ISOCH, "");
513 return (DDI_SUCCESS);
514 }
515
516 /*
517 * hci1394_update_isoch_dma()
518 *
519 * Returns DDI_SUCCESS, or DDI_FAILURE. If DDI_FAILURE, then resultp
520 * contains the error code.
521 */
522 /* ARGSUSED */
523 int
hci1394_update_isoch_dma(void * hal_private,void * hal_isoch_dma_handle,id1394_isoch_dma_updateinfo_t * idma_updateinfop,uint_t flags,int * resultp)524 hci1394_update_isoch_dma(void *hal_private, void *hal_isoch_dma_handle,
525 id1394_isoch_dma_updateinfo_t *idma_updateinfop, uint_t flags, int *resultp)
526 {
527 hci1394_state_t *soft_statep = (hci1394_state_t *)hal_private;
528 hci1394_iso_ctxt_t *ctxtp;
529 ixl1394_command_t *cur_new_ixlp;
530 ixl1394_command_t *cur_orig_ixlp;
531 int ii;
532 int err = DDI_SUCCESS;
533
534
535 TNF_PROBE_0_DEBUG(hci1394_update_isoch_dma_enter,
536 HCI1394_TNF_HAL_STACK_ISOCH, "");
537
538 /* pick up the context pointer from the private idma data */
539 ctxtp = (hci1394_iso_ctxt_t *)hal_isoch_dma_handle;
540
541 ASSERT(hal_private != NULL);
542 ASSERT(ctxtp != NULL);
543 ASSERT(idma_updateinfop != NULL);
544
545 /*
546 * regardless of the type of context (IR or IT), loop through each
547 * command pair (one from new, one from orig), updating the relevant
548 * fields of orig with those from new.
549 */
550 cur_new_ixlp = idma_updateinfop->temp_ixlp;
551 cur_orig_ixlp = idma_updateinfop->orig_ixlp;
552
553 ASSERT(cur_new_ixlp != NULL);
554 ASSERT(cur_orig_ixlp != NULL);
555
556 /* lots of debug trace info */
557 TNF_PROBE_4_DEBUG(hci1394_update_isoch_dma_ctxt_info,
558 HCI1394_TNF_HAL_INFO_ISOCH, "", tnf_opaque, ctxt_ptr, ctxtp,
559 tnf_int, ixlcount, idma_updateinfop->ixl_count,
560 tnf_opaque, new_ixl, cur_new_ixlp, tnf_opaque, orig_ixl,
561 cur_orig_ixlp);
562
563 for (ii = 0; (ii < idma_updateinfop->ixl_count) && (err == DDI_SUCCESS);
564 ii++) {
565
566 /* error if hit a null ixl command too soon */
567 if ((cur_new_ixlp == NULL) || (cur_orig_ixlp == NULL)) {
568 *resultp = IXL1394_ECOUNT_MISMATCH;
569 err = DDI_FAILURE;
570
571 TNF_PROBE_3_DEBUG(hci1394_update_isoch_dma_mismatch,
572 HCI1394_TNF_HAL_ERROR_ISOCH, "", tnf_opaque, new,
573 cur_new_ixlp, tnf_opaque, orig, cur_orig_ixlp,
574 tnf_int, iteration, ii);
575 break;
576 }
577
578 /* proceed with the update */
579 err = hci1394_ixl_update(soft_statep, ctxtp, cur_new_ixlp,
580 cur_orig_ixlp, 0, resultp);
581
582 /* advance new and orig chains */
583 cur_new_ixlp = cur_new_ixlp->next_ixlp;
584 cur_orig_ixlp = cur_orig_ixlp->next_ixlp;
585 }
586
587 TNF_PROBE_0_DEBUG(hci1394_update_isoch_dma_exit,
588 HCI1394_TNF_HAL_STACK_ISOCH, "");
589 return (err);
590 }
591
592
593 /*
594 * hci1394_stop_isoch_dma()
595 * Used to stop a "running" isochronous dma resource.
596 * This is a wrapper which calls the hci1394_do_stop to do the actual work,
597 * but NOT to invoke the target's isoch_dma_stopped().
598 */
599 /* ARGSUSED */
600 void
hci1394_stop_isoch_dma(void * hal_private,void * hal_isoch_dma_handle,int * result)601 hci1394_stop_isoch_dma(void *hal_private, void *hal_isoch_dma_handle,
602 int *result)
603 {
604 hci1394_state_t *soft_statep = (hci1394_state_t *)hal_private;
605 hci1394_iso_ctxt_t *ctxtp;
606
607 TNF_PROBE_0_DEBUG(hci1394_stop_isoch_dma_enter,
608 HCI1394_TNF_HAL_STACK_ISOCH, "");
609
610 /* pick up the context pointer from the private idma data */
611 ctxtp = (hci1394_iso_ctxt_t *)hal_isoch_dma_handle;
612
613 ASSERT(hal_private != NULL);
614 ASSERT(ctxtp != NULL);
615
616 /* stop the context, do not invoke target's stop callback */
617 hci1394_do_stop(soft_statep, ctxtp, B_FALSE, 0);
618
619 /*
620 * call interrupt processing functions to bring callbacks and
621 * store_timestamps upto date. Don't care about errors.
622 */
623 hci1394_ixl_interrupt(soft_statep, ctxtp, B_TRUE);
624
625 TNF_PROBE_0_DEBUG(hci1394_stop_isoch_dma_exit,
626 HCI1394_TNF_HAL_STACK_ISOCH, "");
627 }
628
629 /*
630 * hci1394_do_stop()
631 * Used to stop a "running" isochronous dma resource.
632 * Disables interrupts for the context, clears the context_control register's
633 * RUN bit, and makes sure the ixl is up-to-date with where the hardware is
634 * in the DMA chain.
635 * If do_callback is B_TRUE, the target's isoch_dma_stopped() callback is
636 * invoked. Caller must not hold mutex(es) if calling with
637 * do_callback==B_TRUE, otherwise mutex(es) will be held during callback.
638 * If do_callback is B_FALSE, the isoch_dma_stopped() callback is NOT
639 * invoked and stop_args is ignored.
640 */
641 void
hci1394_do_stop(hci1394_state_t * soft_statep,hci1394_iso_ctxt_t * ctxtp,boolean_t do_callback,id1394_isoch_dma_stopped_t stop_args)642 hci1394_do_stop(hci1394_state_t *soft_statep, hci1394_iso_ctxt_t *ctxtp,
643 boolean_t do_callback, id1394_isoch_dma_stopped_t stop_args)
644 {
645 int count;
646 clock_t upto;
647
648 TNF_PROBE_0_DEBUG(hci1394_do_stop_enter, HCI1394_TNF_HAL_STACK_ISOCH,
649 "");
650
651 TNF_PROBE_4_DEBUG(hci1394_do_stop_info,
652 HCI1394_TNF_HAL_INFO_ISOCH, "", tnf_opaque, ctxt_ptr, ctxtp,
653 tnf_int, ctxt_index, ctxtp->ctxt_index, tnf_opaque, ctxt_flags,
654 ctxtp->ctxt_flags, tnf_string, reason,
655 (stop_args == ID1394_DONE) ? "DONE":"FAIL");
656
657 /* already stopped? if yes, done, else set state to not-running */
658 mutex_enter(&soft_statep->isoch->ctxt_list_mutex);
659 if ((ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RUNNING) == 0) {
660 mutex_exit(&soft_statep->isoch->ctxt_list_mutex);
661
662 TNF_PROBE_1_DEBUG(hci1394_do_stop_exit,
663 HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
664 "context already stopped");
665 return;
666 }
667 ctxtp->ctxt_flags &= ~HCI1394_ISO_CTXT_RUNNING;
668 mutex_exit(&soft_statep->isoch->ctxt_list_mutex);
669
670 /* turn off context control register's run bit */
671 if (ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RECV) {
672 /* RECEIVE */
673
674 /* disable interrupts for this IR context */
675 hci1394_ohci_ir_intr_disable(soft_statep->ohci,
676 (uint32_t)(0x1 << ctxtp->ctxt_index));
677
678 /* turn off run bit */
679 HCI1394_IRCTXT_CTRL_CLR(soft_statep, ctxtp->ctxt_index,
680 0 /* bffill */, 0 /* iso hdrs */, 0 /* match enbl */,
681 0 /* multi-chan mode (not implemented) */, 1 /* run */);
682 } else {
683 /* TRANSMIT */
684
685 /* disable interrupts for this IT context */
686 hci1394_ohci_it_intr_disable(soft_statep->ohci,
687 (uint32_t)(0x1 << ctxtp->ctxt_index));
688
689 /* turn of run bit */
690 HCI1394_ITCTXT_CTRL_CLR(soft_statep, ctxtp->ctxt_index,
691 0 /* match enbl */, 0 /* match */, 1 /* run */);
692 }
693
694 /*
695 * If interrupt is already in progress, wait until it's over.
696 * Otherwise, set flag to prevent the new interrupt.
697 */
698 mutex_enter(&ctxtp->intrprocmutex);
699 ctxtp->intr_flags |= HCI1394_ISO_CTXT_STOP;
700 if (ctxtp->intr_flags & HCI1394_ISO_CTXT_ININTR) {
701 upto = ddi_get_lbolt() +
702 drv_usectohz(hci1394_iso_ctxt_stop_intr_timeout_uS);
703 while (ctxtp->intr_flags & HCI1394_ISO_CTXT_ININTR) {
704 if (cv_timedwait(&ctxtp->intr_cv, &ctxtp->intrprocmutex,
705 upto) <= 0) {
706 break;
707 }
708 }
709
710 if (ctxtp->intr_flags & HCI1394_ISO_CTXT_ININTR) {
711 TNF_PROBE_1(hci1394_do_stop_error,
712 HCI1394_TNF_HAL_ERROR_ISOCH, "",
713 tnf_string, msg, "intr completion timeout");
714 }
715 }
716 mutex_exit(&ctxtp->intrprocmutex);
717
718 /* Wait until "active" bit is cleared before continuing */
719 count = 0;
720 while (count < hci1394_iso_ctxt_stop_delay_uS) {
721 /* Has the "active" bit gone low yet? */
722 if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) == 0)
723 break;
724
725 /*
726 * The context did not stop yet. Wait 1us, increment the
727 * count and try again.
728 */
729 drv_usecwait(1);
730 count++;
731 }
732
733 /* Check to see if we timed out or not */
734 if (count >= hci1394_iso_ctxt_stop_delay_uS) {
735 h1394_error_detected(soft_statep->drvinfo.di_sl_private,
736 H1394_SELF_INITIATED_SHUTDOWN, NULL);
737 cmn_err(CE_WARN, "hci1394(%d): driver shutdown: "
738 "unable to stop isoch context",
739 soft_statep->drvinfo.di_instance);
740 hci1394_shutdown(soft_statep->drvinfo.di_dip);
741
742 TNF_PROBE_1_DEBUG(hci1394_do_stop_exit,
743 HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
744 "context timed out trying to stop");
745 return;
746 }
747
748 /*
749 * invoke callback as directed. Note that the CTXT_INCALL flag is NOT
750 * needed here. That flag is only used when we have to drop a mutex
751 * that we want to grab back again. We're not doing that here.
752 */
753 if (do_callback == B_TRUE) {
754 if (ctxtp->isoch_dma_stopped != NULL) {
755 ctxtp->isoch_dma_stopped(
756 (struct isoch_dma_handle *)ctxtp,
757 ctxtp->idma_evt_arg, stop_args);
758 }
759 }
760 TNF_PROBE_0_DEBUG(hci1394_do_stop_exit, HCI1394_TNF_HAL_STACK_ISOCH,
761 "");
762 }
763
764 /*
765 * hci1394_free_isoch_dma()
766 * Used to free up usage of an isochronous context and any other
767 * system resources acquired during IXL compilation.
768 * This does NOT free up the IXL and it's data buffers which is
769 * the target driver's responsibility.
770 */
771 void
hci1394_free_isoch_dma(void * hal_private,void * hal_isoch_dma_handle)772 hci1394_free_isoch_dma(void *hal_private, void *hal_isoch_dma_handle)
773 {
774 hci1394_state_t *soft_statep = (hci1394_state_t *)hal_private;
775 hci1394_iso_ctxt_t *ctxtp;
776 hci1394_isoch_t *isochp;
777
778 TNF_PROBE_0_DEBUG(hci1394_free_isoch_dma_enter,
779 HCI1394_TNF_HAL_STACK_ISOCH, "");
780
781 /* pick up the context pointer from the private idma data */
782 ctxtp = (hci1394_iso_ctxt_t *)hal_isoch_dma_handle;
783
784 ASSERT(soft_statep);
785 ASSERT(ctxtp);
786
787 isochp = soft_statep->isoch;
788
789 /* lots of debug trace info */
790 TNF_PROBE_4_DEBUG(hci1394_free_isoch_dma_ctxt_info,
791 HCI1394_TNF_HAL_INFO_ISOCH, "", tnf_opaque, ctxt_ptr, ctxtp,
792 tnf_int, ctxt_index, ctxtp->ctxt_index, tnf_opaque, ctxt_flags,
793 ctxtp->ctxt_flags, tnf_opaque, first_ixl, ctxtp->ixl_firstp);
794
795 mutex_enter(&soft_statep->isoch->ctxt_list_mutex);
796
797 /* delete xfer_ctl structs and pages of allocated hci_desc memory */
798 hci1394_ixl_cleanup(soft_statep, ctxtp);
799
800 /*
801 * free context. no need to determine if xmit or recv. clearing of recv
802 * flags is harmless for xmit.
803 */
804 ctxtp->ctxt_flags &= ~(HCI1394_ISO_CTXT_INUSE |
805 HCI1394_ISO_CTXT_BFFILL | HCI1394_ISO_CTXT_RHDRS);
806
807 /*
808 * Update count of allocated isoch dma (and disable interrupts
809 * if necessary)
810 */
811 ASSERT(isochp->isoch_dma_alloc_cnt > 0);
812 isochp->isoch_dma_alloc_cnt--;
813 if (isochp->isoch_dma_alloc_cnt == 0) {
814 hci1394_ohci_intr_disable(soft_statep->ohci,
815 OHCI_INTR_CYC_LOST | OHCI_INTR_CYC_INCONSISTENT);
816 }
817
818 mutex_exit(&soft_statep->isoch->ctxt_list_mutex);
819
820 TNF_PROBE_0_DEBUG(hci1394_free_isoch_dma_exit,
821 HCI1394_TNF_HAL_STACK_ISOCH, "");
822 }
823
824 /*
825 * hci1394_isoch_recv_count_get()
826 * returns the number of supported isoch receive contexts.
827 */
828 int
hci1394_isoch_recv_count_get(hci1394_isoch_handle_t isoch_hdl)829 hci1394_isoch_recv_count_get(hci1394_isoch_handle_t isoch_hdl)
830 {
831 ASSERT(isoch_hdl != NULL);
832 return (isoch_hdl->ctxt_recv_count);
833 }
834
835 /*
836 * hci1394_isoch_recv_ctxt_get()
837 * given a context index, returns its isoch receive context struct
838 */
839 hci1394_iso_ctxt_t *
hci1394_isoch_recv_ctxt_get(hci1394_isoch_handle_t isoch_hdl,int num)840 hci1394_isoch_recv_ctxt_get(hci1394_isoch_handle_t isoch_hdl, int num)
841 {
842 ASSERT(isoch_hdl != NULL);
843 return (&isoch_hdl->ctxt_recv[num]);
844 }
845
846 /*
847 * hci1394_isoch_xmit_count_get()
848 * returns the number of supported isoch transmit contexts.
849 */
850 int
hci1394_isoch_xmit_count_get(hci1394_isoch_handle_t isoch_hdl)851 hci1394_isoch_xmit_count_get(hci1394_isoch_handle_t isoch_hdl)
852 {
853 ASSERT(isoch_hdl != NULL);
854 return (isoch_hdl->ctxt_xmit_count);
855 }
856
857 /*
858 * hci1394_isoch_xmit_ctxt_get()
859 * given a context index, returns its isoch transmit context struct
860 */
861 hci1394_iso_ctxt_t *
hci1394_isoch_xmit_ctxt_get(hci1394_isoch_handle_t isoch_hdl,int num)862 hci1394_isoch_xmit_ctxt_get(hci1394_isoch_handle_t isoch_hdl, int num)
863 {
864 ASSERT(isoch_hdl != NULL);
865 return (&isoch_hdl->ctxt_xmit[num]);
866 }
867
868 /*
869 * hci1394_isoch_error_ints_enable()
870 * after bus reset, reenable CYCLE_LOST and CYCLE_INCONSISTENT
871 * interrupts (if necessary).
872 */
873 void
hci1394_isoch_error_ints_enable(hci1394_state_t * soft_statep)874 hci1394_isoch_error_ints_enable(hci1394_state_t *soft_statep)
875 {
876 ASSERT(soft_statep);
877
878 TNF_PROBE_0_DEBUG(hci1394_isoch_error_ints_enable_enter,
879 HCI1394_TNF_HAL_STACK_ISOCH, "");
880
881 mutex_enter(&soft_statep->isoch->ctxt_list_mutex);
882
883 if (soft_statep->isoch->isoch_dma_alloc_cnt != 0) {
884 soft_statep->isoch->cycle_lost_thresh.delta_t_counter = 0;
885 soft_statep->isoch->cycle_incon_thresh.delta_t_counter = 0;
886 hci1394_ohci_intr_clear(soft_statep->ohci,
887 OHCI_INTR_CYC_LOST | OHCI_INTR_CYC_INCONSISTENT);
888 hci1394_ohci_intr_enable(soft_statep->ohci,
889 OHCI_INTR_CYC_LOST | OHCI_INTR_CYC_INCONSISTENT);
890 }
891 mutex_exit(&soft_statep->isoch->ctxt_list_mutex);
892
893 TNF_PROBE_0_DEBUG(hci1394_isoch_error_ints_enable_exit,
894 HCI1394_TNF_HAL_STACK_ISOCH, "");
895 }
896