Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / 1394 / adapters / hci1394_isoch.c
blob5122d9d2debfd91702ce858c79492c65f0a69a1d
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
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.
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>
43 #include <sys/1394/h1394.h>
44 #include <sys/1394/adapters/hci1394.h>
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
51 uint_t hci1394_iso_ctxt_stop_delay_uS = 1000;
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.
59 uint_t hci1394_iso_ctxt_stop_intr_timeout_uS = 5 * 1000000;
62 * hci1394_isoch_init()
63 * Initialize the isochronous dma soft state.
65 void
66 hci1394_isoch_init(hci1394_drvinfo_t *drvinfo, hci1394_ohci_handle_t ohci,
67 hci1394_isoch_handle_t *isoch_hdl)
69 hci1394_isoch_t *isochp;
70 int i;
72 ASSERT(drvinfo != NULL);
73 ASSERT(isoch_hdl != NULL);
75 isochp = kmem_alloc(sizeof (hci1394_isoch_t), KM_SLEEP);
77 /* initialize contexts */
78 for (i = 0; i < HCI1394_MAX_ISOCH_CONTEXTS; i++) {
79 isochp->ctxt_xmit[i].ctxt_index = i;
81 /* init context flags to 0 */
82 isochp->ctxt_xmit[i].ctxt_flags = 0;
84 mutex_init(&isochp->ctxt_xmit[i].intrprocmutex, NULL,
85 MUTEX_DRIVER, drvinfo->di_iblock_cookie);
86 cv_init(&isochp->ctxt_xmit[i].intr_cv, NULL,
87 CV_DRIVER, NULL);
89 isochp->ctxt_recv[i].ctxt_index = i;
90 isochp->ctxt_recv[i].ctxt_flags = HCI1394_ISO_CTXT_RECV;
91 mutex_init(&isochp->ctxt_recv[i].intrprocmutex, NULL,
92 MUTEX_DRIVER, drvinfo->di_iblock_cookie);
93 cv_init(&isochp->ctxt_recv[i].intr_cv, NULL,
94 CV_DRIVER, NULL);
97 /* initialize the count for allocated isoch dma */
98 isochp->isoch_dma_alloc_cnt = 0;
100 /* initialize the cycle_lost_thresh struct */
101 isochp->cycle_lost_thresh.last_intr_time = 0;
102 isochp->cycle_lost_thresh.delta_t_counter = 0;
103 isochp->cycle_lost_thresh.delta_t_thresh = HCI1394_CYC_LOST_DELTA;
104 isochp->cycle_lost_thresh.counter_thresh = HCI1394_CYC_LOST_COUNT;
106 /* initialize the cycle_incon_thresh struct */
107 isochp->cycle_incon_thresh.last_intr_time = 0;
108 isochp->cycle_incon_thresh.delta_t_counter = 0;
109 isochp->cycle_incon_thresh.delta_t_thresh = HCI1394_CYC_INCON_DELTA;
110 isochp->cycle_incon_thresh.counter_thresh = HCI1394_CYC_INCON_COUNT;
112 /* determine number of contexts supported */
113 isochp->ctxt_xmit_count = hci1394_ohci_it_ctxt_count_get(ohci);
114 isochp->ctxt_recv_count = hci1394_ohci_ir_ctxt_count_get(ohci);
116 /* the isochronous context mutex is used during some error interrupts */
117 mutex_init(&isochp->ctxt_list_mutex, NULL, MUTEX_DRIVER,
118 drvinfo->di_iblock_cookie);
120 *isoch_hdl = isochp;
124 * hci1394_isoch_fini()
125 * Cleanup after hci1394_isoch_init. This should be called during detach.
127 void
128 hci1394_isoch_fini(hci1394_isoch_handle_t *isoch_hdl)
130 hci1394_isoch_t *isochp;
131 int i;
133 ASSERT(isoch_hdl != NULL);
135 isochp = *isoch_hdl;
137 for (i = 0; i < HCI1394_MAX_ISOCH_CONTEXTS; i++) {
138 mutex_destroy(&isochp->ctxt_xmit[i].intrprocmutex);
139 mutex_destroy(&isochp->ctxt_recv[i].intrprocmutex);
140 cv_destroy(&isochp->ctxt_xmit[i].intr_cv);
141 cv_destroy(&isochp->ctxt_recv[i].intr_cv);
144 mutex_destroy(&isochp->ctxt_list_mutex);
145 kmem_free(isochp, sizeof (hci1394_isoch_t));
146 *isoch_hdl = NULL;
151 * hci1394_isoch_resume()
152 * There is currently nothing to do for resume. This is a placeholder.
154 /* ARGSUSED */
156 hci1394_isoch_resume(hci1394_state_t *soft_state)
158 return (DDI_SUCCESS);
162 * hci1394_alloc_isoch_dma ()
163 * Called by the Services Layer. Used to allocate a local Isoch DMA context.
164 * Goes through appropriate context list (either transmit or receive)
165 * looking for an unused context. Fails if none found.
166 * Then compiles the provided IXL program.
169 hci1394_alloc_isoch_dma(void *hal_private, id1394_isoch_dmainfo_t *idi,
170 void **hal_idma_handlep, int *resultp)
172 int i;
173 int err;
174 hci1394_state_t *soft_statep = (hci1394_state_t *)hal_private;
175 hci1394_isoch_t *isochp;
176 hci1394_iso_ctxt_t *ctxtp;
179 ASSERT(soft_statep != NULL);
180 ASSERT(hal_idma_handlep != NULL);
182 isochp = soft_statep->isoch;
183 *hal_idma_handlep = NULL;
186 * find context to use based on whether talking(send) or listening(recv)
188 mutex_enter(&isochp->ctxt_list_mutex);
189 if ((idi->idma_options & ID1394_TALK) != 0) {
190 /* TRANSMIT */
193 * search through list of hardware supported contexts for
194 * one that's not inuse
196 for (i = 0; i < isochp->ctxt_xmit_count; i++) {
197 if ((isochp->ctxt_xmit[i].ctxt_flags &
198 HCI1394_ISO_CTXT_INUSE) == 0) {
199 break;
203 /* if there aren't any left, return an error */
204 if (i >= isochp->ctxt_xmit_count) {
205 mutex_exit(&isochp->ctxt_list_mutex);
206 *resultp = IXL1394_ENO_DMA_RESRCS;
207 return (DDI_FAILURE);
210 /* mark inuse and set up handle to context */
211 isochp->ctxt_xmit[i].ctxt_flags |= HCI1394_ISO_CTXT_INUSE;
212 ctxtp = &isochp->ctxt_xmit[i];
213 isochp->ctxt_xmit[i].ctxt_regsp =
214 &soft_statep->ohci->ohci_regs->it[i];
215 } else {
216 /* RECEIVE */
218 /* search thru implemented contexts for one that's available */
219 for (i = 0; i < isochp->ctxt_recv_count; i++) {
220 if ((isochp->ctxt_recv[i].ctxt_flags &
221 HCI1394_ISO_CTXT_INUSE) == 0) {
222 break;
226 /* if there aren't any left, return an error */
227 /* XXX support for multi-chan could go here */
228 if (i >= isochp->ctxt_recv_count) {
230 mutex_exit(&isochp->ctxt_list_mutex);
231 *resultp = IXL1394_ENO_DMA_RESRCS;
232 return (DDI_FAILURE);
235 /* set up receive mode flags */
236 if ((idi->idma_options & ID1394_LISTEN_BUF_MODE) != 0) {
237 isochp->ctxt_recv[i].ctxt_flags |=
238 HCI1394_ISO_CTXT_BFFILL;
240 if ((idi->idma_options & ID1394_RECV_HEADERS) != 0) {
241 isochp->ctxt_recv[i].ctxt_flags |=
242 HCI1394_ISO_CTXT_RHDRS;
245 /* mark inuse and set up handle to context */
246 isochp->ctxt_recv[i].ctxt_flags |= HCI1394_ISO_CTXT_INUSE;
247 ctxtp = &isochp->ctxt_recv[i];
249 isochp->ctxt_recv[i].ctxt_regsp = (hci1394_ctxt_regs_t *)
250 &soft_statep->ohci->ohci_regs->ir[i];
252 mutex_exit(&isochp->ctxt_list_mutex);
254 /* before compiling, set up some default context values */
255 ctxtp->isochan = idi->channel_num;
256 ctxtp->default_tag = idi->default_tag;
257 ctxtp->default_sync = idi->default_sync;
258 ctxtp->global_callback_arg = idi->global_callback_arg;
259 ctxtp->isoch_dma_stopped = idi->isoch_dma_stopped;
260 ctxtp->idma_evt_arg = idi->idma_evt_arg;
261 ctxtp->isospd = idi->it_speed;
262 ctxtp->default_skipmode = idi->it_default_skip;
263 ctxtp->default_skiplabelp = idi->it_default_skiplabel;
265 err = hci1394_compile_ixl(soft_statep, ctxtp, idi->ixlp, resultp);
269 * if the compile failed, clear the appropriate flags.
270 * Note that the context mutex is needed to eliminate race condition
271 * with cycle_inconsistent and other error intrs.
273 if (err != DDI_SUCCESS) {
275 mutex_enter(&isochp->ctxt_list_mutex);
276 if ((ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RECV) != 0) {
277 /* undo the set up of receive mode flags */
278 isochp->ctxt_recv[i].ctxt_flags &=
279 ~HCI1394_ISO_CTXT_BFFILL;
280 isochp->ctxt_recv[i].ctxt_flags &=
281 ~HCI1394_ISO_CTXT_RHDRS;
283 ctxtp->ctxt_flags &= ~HCI1394_ISO_CTXT_INUSE;
284 mutex_exit(&isochp->ctxt_list_mutex);
286 return (DDI_FAILURE);
290 * Update count of allocated isoch dma (and enable interrupts
291 * if necessary)
293 mutex_enter(&isochp->ctxt_list_mutex);
294 if (isochp->isoch_dma_alloc_cnt == 0) {
295 hci1394_ohci_intr_clear(soft_statep->ohci,
296 OHCI_INTR_CYC_LOST | OHCI_INTR_CYC_INCONSISTENT);
297 hci1394_ohci_intr_enable(soft_statep->ohci,
298 OHCI_INTR_CYC_LOST | OHCI_INTR_CYC_INCONSISTENT);
300 isochp->isoch_dma_alloc_cnt++;
301 mutex_exit(&isochp->ctxt_list_mutex);
303 /* No errors, so all set to go. initialize interrupt/execution flags */
304 ctxtp->intr_flags = 0;
306 *hal_idma_handlep = ctxtp;
307 return (DDI_SUCCESS);
312 * hci1394_start_isoch_dma()
313 * Used to start an allocated isochronous dma resource.
314 * Sets the context's command ptr to start at the first IXL,
315 * sets up IR match register (if IR), and enables the context_control
316 * register RUN bit.
318 /* ARGSUSED */
320 hci1394_start_isoch_dma(void *hal_private, void *hal_isoch_dma_handle,
321 id1394_isoch_dma_ctrlinfo_t *idma_ctrlinfop, uint_t flags, int *result)
323 hci1394_state_t *soft_statep = (hci1394_state_t *)hal_private;
324 hci1394_iso_ctxt_t *ctxtp;
325 int tag0, tag1, tag2, tag3;
327 /* pick up the context pointer from the private idma data */
328 ctxtp = (hci1394_iso_ctxt_t *)hal_isoch_dma_handle;
330 ASSERT(hal_private != NULL);
331 ASSERT(ctxtp != NULL);
332 ASSERT(idma_ctrlinfop != NULL);
335 /* if the context is already running, just exit. else set running */
336 mutex_enter(&soft_statep->isoch->ctxt_list_mutex);
337 if ((ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RUNNING) != 0) {
339 mutex_exit(&soft_statep->isoch->ctxt_list_mutex);
341 return (DDI_SUCCESS);
343 ctxtp->ctxt_flags |= HCI1394_ISO_CTXT_RUNNING;
344 mutex_exit(&soft_statep->isoch->ctxt_list_mutex);
346 ctxtp->intr_flags &= ~HCI1394_ISO_CTXT_STOP;
348 /* initialize context values */
349 ctxtp->ixl_execp = ctxtp->ixl_firstp; /* start of ixl chain */
350 ctxtp->ixl_exec_depth = 0;
351 ctxtp->dma_last_time = 0;
352 ctxtp->rem_noadv_intrs = ctxtp->max_noadv_intrs;
355 * clear out hci DMA descriptor status to start with clean slate.
356 * note that statuses could be set if context was previously started
357 * then stopped.
359 hci1394_ixl_reset_status(ctxtp);
361 /* set up registers, and start isoch */
362 if (ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RECV) {
364 /* set context's command ptr to the first descriptor */
365 hci1394_ohci_ir_cmd_ptr_set(soft_statep->ohci,
366 ctxtp->ctxt_index, ctxtp->dma_mem_execp);
369 * determine correct tag values. map target's requested 2-bit
370 * tag into one of the 4 openHCI tag bits.
371 * XXX for now the t1394 api only supports a single tag setting,
372 * whereas openhci supports a set of (non-mutually exclusive)
373 * valid tags. if the api changes to support multiple
374 * simultaneous tags, then this code must be changed.
376 tag0 = 0;
377 tag1 = 1;
378 tag2 = 2;
379 tag3 = 3;
380 if (ctxtp->default_tag == 0x0)
381 tag0 = 1;
382 else if (ctxtp->default_tag == 0x1)
383 tag1 = 1;
384 else if (ctxtp->default_tag == 0x2)
385 tag2 = 1;
386 else if (ctxtp->default_tag == 0x3)
387 tag3 = 1;
389 /* set match register as desired */
390 HCI1394_IRCTXT_MATCH_WRITE(soft_statep, ctxtp->ctxt_index, tag3,
391 tag2, tag1, tag0,
392 idma_ctrlinfop->start_cycle /* cycleMatch */,
393 ctxtp->default_sync /* sync */, 0 /* tag1sync */,
394 ctxtp->isochan /* chan */);
396 /* clear all bits in context ctrl reg to init to known state */
397 HCI1394_IRCTXT_CTRL_CLR(soft_statep, ctxtp->ctxt_index,
398 (uint32_t)1, 1, 1, 1, 1);
400 /* set desired values in context control register */
401 HCI1394_IRCTXT_CTRL_SET(soft_statep, ctxtp->ctxt_index,
402 (ctxtp->ctxt_flags & HCI1394_ISO_CTXT_BFFILL) != 0 /* bf */,
403 (ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RHDRS) != 0 /* hdr */,
404 (flags & ID1394_START_ON_CYCLE) != 0 /* match enbl */,
405 0 /* multi-chan mode */, 1 /* run */, 0 /* wake */);
408 * before enabling interrupts, make sure any vestige interrupt
409 * event (from a previous use) is cleared.
411 hci1394_ohci_ir_intr_clear(soft_statep->ohci,
412 (uint32_t)(0x1 << ctxtp->ctxt_index));
414 /* enable interrupts for this IR context */
415 hci1394_ohci_ir_intr_enable(soft_statep->ohci,
416 (uint32_t)(0x1 << ctxtp->ctxt_index));
418 } else {
419 /* TRANSMIT */
421 /* set context's command ptr to the first descriptor */
422 hci1394_ohci_it_cmd_ptr_set(soft_statep->ohci,
423 ctxtp->ctxt_index, ctxtp->dma_mem_execp);
425 /* set desired values in context control register */
426 HCI1394_ITCTXT_CTRL_SET(soft_statep, ctxtp->ctxt_index,
427 ((flags & ID1394_START_ON_CYCLE) != 0) /* match enable */,
428 idma_ctrlinfop->start_cycle /* cycle Match */,
429 1 /* run */, 0 /* wake */);
432 * before enabling interrupts, make sure any vestige interrupt
433 * event (from a previous use) is cleared.
435 hci1394_ohci_it_intr_clear(soft_statep->ohci,
436 (uint32_t)(0x1 << ctxtp->ctxt_index));
438 /* enable interrupts for this IT context */
439 hci1394_ohci_it_intr_enable(soft_statep->ohci,
440 (uint32_t)(0x1 << ctxtp->ctxt_index));
443 return (DDI_SUCCESS);
447 * hci1394_update_isoch_dma()
449 * Returns DDI_SUCCESS, or DDI_FAILURE. If DDI_FAILURE, then resultp
450 * contains the error code.
452 /* ARGSUSED */
454 hci1394_update_isoch_dma(void *hal_private, void *hal_isoch_dma_handle,
455 id1394_isoch_dma_updateinfo_t *idma_updateinfop, uint_t flags, int *resultp)
457 hci1394_state_t *soft_statep = (hci1394_state_t *)hal_private;
458 hci1394_iso_ctxt_t *ctxtp;
459 ixl1394_command_t *cur_new_ixlp;
460 ixl1394_command_t *cur_orig_ixlp;
461 int ii;
462 int err = DDI_SUCCESS;
464 /* pick up the context pointer from the private idma data */
465 ctxtp = (hci1394_iso_ctxt_t *)hal_isoch_dma_handle;
467 ASSERT(hal_private != NULL);
468 ASSERT(ctxtp != NULL);
469 ASSERT(idma_updateinfop != NULL);
472 * regardless of the type of context (IR or IT), loop through each
473 * command pair (one from new, one from orig), updating the relevant
474 * fields of orig with those from new.
476 cur_new_ixlp = idma_updateinfop->temp_ixlp;
477 cur_orig_ixlp = idma_updateinfop->orig_ixlp;
479 ASSERT(cur_new_ixlp != NULL);
480 ASSERT(cur_orig_ixlp != NULL);
482 for (ii = 0; (ii < idma_updateinfop->ixl_count) && (err == DDI_SUCCESS);
483 ii++) {
485 /* error if hit a null ixl command too soon */
486 if ((cur_new_ixlp == NULL) || (cur_orig_ixlp == NULL)) {
487 *resultp = IXL1394_ECOUNT_MISMATCH;
488 err = DDI_FAILURE;
490 break;
493 /* proceed with the update */
494 err = hci1394_ixl_update(soft_statep, ctxtp, cur_new_ixlp,
495 cur_orig_ixlp, 0, resultp);
497 /* advance new and orig chains */
498 cur_new_ixlp = cur_new_ixlp->next_ixlp;
499 cur_orig_ixlp = cur_orig_ixlp->next_ixlp;
502 return (err);
507 * hci1394_stop_isoch_dma()
508 * Used to stop a "running" isochronous dma resource.
509 * This is a wrapper which calls the hci1394_do_stop to do the actual work,
510 * but NOT to invoke the target's isoch_dma_stopped().
512 /* ARGSUSED */
513 void
514 hci1394_stop_isoch_dma(void *hal_private, void *hal_isoch_dma_handle,
515 int *result)
517 hci1394_state_t *soft_statep = (hci1394_state_t *)hal_private;
518 hci1394_iso_ctxt_t *ctxtp;
520 /* pick up the context pointer from the private idma data */
521 ctxtp = (hci1394_iso_ctxt_t *)hal_isoch_dma_handle;
523 ASSERT(hal_private != NULL);
524 ASSERT(ctxtp != NULL);
526 /* stop the context, do not invoke target's stop callback */
527 hci1394_do_stop(soft_statep, ctxtp, B_FALSE, 0);
530 * call interrupt processing functions to bring callbacks and
531 * store_timestamps upto date. Don't care about errors.
533 hci1394_ixl_interrupt(soft_statep, ctxtp, B_TRUE);
537 * hci1394_do_stop()
538 * Used to stop a "running" isochronous dma resource.
539 * Disables interrupts for the context, clears the context_control register's
540 * RUN bit, and makes sure the ixl is up-to-date with where the hardware is
541 * in the DMA chain.
542 * If do_callback is B_TRUE, the target's isoch_dma_stopped() callback is
543 * invoked. Caller must not hold mutex(es) if calling with
544 * do_callback==B_TRUE, otherwise mutex(es) will be held during callback.
545 * If do_callback is B_FALSE, the isoch_dma_stopped() callback is NOT
546 * invoked and stop_args is ignored.
548 void
549 hci1394_do_stop(hci1394_state_t *soft_statep, hci1394_iso_ctxt_t *ctxtp,
550 boolean_t do_callback, id1394_isoch_dma_stopped_t stop_args)
552 int count;
553 clock_t upto;
555 /* already stopped? if yes, done, else set state to not-running */
556 mutex_enter(&soft_statep->isoch->ctxt_list_mutex);
557 if ((ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RUNNING) == 0) {
558 mutex_exit(&soft_statep->isoch->ctxt_list_mutex);
560 return;
562 ctxtp->ctxt_flags &= ~HCI1394_ISO_CTXT_RUNNING;
563 mutex_exit(&soft_statep->isoch->ctxt_list_mutex);
565 /* turn off context control register's run bit */
566 if (ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RECV) {
567 /* RECEIVE */
569 /* disable interrupts for this IR context */
570 hci1394_ohci_ir_intr_disable(soft_statep->ohci,
571 (uint32_t)(0x1 << ctxtp->ctxt_index));
573 /* turn off run bit */
574 HCI1394_IRCTXT_CTRL_CLR(soft_statep, ctxtp->ctxt_index,
575 0 /* bffill */, 0 /* iso hdrs */, 0 /* match enbl */,
576 0 /* multi-chan mode (not implemented) */, 1 /* run */);
577 } else {
578 /* TRANSMIT */
580 /* disable interrupts for this IT context */
581 hci1394_ohci_it_intr_disable(soft_statep->ohci,
582 (uint32_t)(0x1 << ctxtp->ctxt_index));
584 /* turn of run bit */
585 HCI1394_ITCTXT_CTRL_CLR(soft_statep, ctxtp->ctxt_index,
586 0 /* match enbl */, 0 /* match */, 1 /* run */);
590 * If interrupt is already in progress, wait until it's over.
591 * Otherwise, set flag to prevent the new interrupt.
593 mutex_enter(&ctxtp->intrprocmutex);
594 ctxtp->intr_flags |= HCI1394_ISO_CTXT_STOP;
595 if (ctxtp->intr_flags & HCI1394_ISO_CTXT_ININTR) {
596 upto = ddi_get_lbolt() +
597 drv_usectohz(hci1394_iso_ctxt_stop_intr_timeout_uS);
598 while (ctxtp->intr_flags & HCI1394_ISO_CTXT_ININTR) {
599 if (cv_timedwait(&ctxtp->intr_cv, &ctxtp->intrprocmutex,
600 upto) <= 0) {
601 break;
605 mutex_exit(&ctxtp->intrprocmutex);
607 /* Wait until "active" bit is cleared before continuing */
608 count = 0;
609 while (count < hci1394_iso_ctxt_stop_delay_uS) {
610 /* Has the "active" bit gone low yet? */
611 if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) == 0)
612 break;
615 * The context did not stop yet. Wait 1us, increment the
616 * count and try again.
618 drv_usecwait(1);
619 count++;
622 /* Check to see if we timed out or not */
623 if (count >= hci1394_iso_ctxt_stop_delay_uS) {
624 h1394_error_detected(soft_statep->drvinfo.di_sl_private,
625 H1394_SELF_INITIATED_SHUTDOWN, NULL);
626 cmn_err(CE_WARN, "hci1394(%d): driver shutdown: "
627 "unable to stop isoch context",
628 soft_statep->drvinfo.di_instance);
629 hci1394_shutdown(soft_statep->drvinfo.di_dip);
631 return;
635 * invoke callback as directed. Note that the CTXT_INCALL flag is NOT
636 * needed here. That flag is only used when we have to drop a mutex
637 * that we want to grab back again. We're not doing that here.
639 if (do_callback == B_TRUE) {
640 if (ctxtp->isoch_dma_stopped != NULL) {
641 ctxtp->isoch_dma_stopped(
642 (struct isoch_dma_handle *)ctxtp,
643 ctxtp->idma_evt_arg, stop_args);
649 * hci1394_free_isoch_dma()
650 * Used to free up usage of an isochronous context and any other
651 * system resources acquired during IXL compilation.
652 * This does NOT free up the IXL and it's data buffers which is
653 * the target driver's responsibility.
655 void
656 hci1394_free_isoch_dma(void *hal_private, void *hal_isoch_dma_handle)
658 hci1394_state_t *soft_statep = (hci1394_state_t *)hal_private;
659 hci1394_iso_ctxt_t *ctxtp;
660 hci1394_isoch_t *isochp;
662 /* pick up the context pointer from the private idma data */
663 ctxtp = (hci1394_iso_ctxt_t *)hal_isoch_dma_handle;
665 ASSERT(soft_statep);
666 ASSERT(ctxtp);
668 isochp = soft_statep->isoch;
670 mutex_enter(&soft_statep->isoch->ctxt_list_mutex);
672 /* delete xfer_ctl structs and pages of allocated hci_desc memory */
673 hci1394_ixl_cleanup(soft_statep, ctxtp);
676 * free context. no need to determine if xmit or recv. clearing of recv
677 * flags is harmless for xmit.
679 ctxtp->ctxt_flags &= ~(HCI1394_ISO_CTXT_INUSE |
680 HCI1394_ISO_CTXT_BFFILL | HCI1394_ISO_CTXT_RHDRS);
683 * Update count of allocated isoch dma (and disable interrupts
684 * if necessary)
686 ASSERT(isochp->isoch_dma_alloc_cnt > 0);
687 isochp->isoch_dma_alloc_cnt--;
688 if (isochp->isoch_dma_alloc_cnt == 0) {
689 hci1394_ohci_intr_disable(soft_statep->ohci,
690 OHCI_INTR_CYC_LOST | OHCI_INTR_CYC_INCONSISTENT);
693 mutex_exit(&soft_statep->isoch->ctxt_list_mutex);
697 * hci1394_isoch_recv_count_get()
698 * returns the number of supported isoch receive contexts.
701 hci1394_isoch_recv_count_get(hci1394_isoch_handle_t isoch_hdl)
703 ASSERT(isoch_hdl != NULL);
704 return (isoch_hdl->ctxt_recv_count);
708 * hci1394_isoch_recv_ctxt_get()
709 * given a context index, returns its isoch receive context struct
711 hci1394_iso_ctxt_t *
712 hci1394_isoch_recv_ctxt_get(hci1394_isoch_handle_t isoch_hdl, int num)
714 ASSERT(isoch_hdl != NULL);
715 return (&isoch_hdl->ctxt_recv[num]);
719 * hci1394_isoch_xmit_count_get()
720 * returns the number of supported isoch transmit contexts.
723 hci1394_isoch_xmit_count_get(hci1394_isoch_handle_t isoch_hdl)
725 ASSERT(isoch_hdl != NULL);
726 return (isoch_hdl->ctxt_xmit_count);
730 * hci1394_isoch_xmit_ctxt_get()
731 * given a context index, returns its isoch transmit context struct
733 hci1394_iso_ctxt_t *
734 hci1394_isoch_xmit_ctxt_get(hci1394_isoch_handle_t isoch_hdl, int num)
736 ASSERT(isoch_hdl != NULL);
737 return (&isoch_hdl->ctxt_xmit[num]);
741 * hci1394_isoch_error_ints_enable()
742 * after bus reset, reenable CYCLE_LOST and CYCLE_INCONSISTENT
743 * interrupts (if necessary).
745 void
746 hci1394_isoch_error_ints_enable(hci1394_state_t *soft_statep)
748 ASSERT(soft_statep);
750 mutex_enter(&soft_statep->isoch->ctxt_list_mutex);
752 if (soft_statep->isoch->isoch_dma_alloc_cnt != 0) {
753 soft_statep->isoch->cycle_lost_thresh.delta_t_counter = 0;
754 soft_statep->isoch->cycle_incon_thresh.delta_t_counter = 0;
755 hci1394_ohci_intr_clear(soft_statep->ohci,
756 OHCI_INTR_CYC_LOST | OHCI_INTR_CYC_INCONSISTENT);
757 hci1394_ohci_intr_enable(soft_statep->ohci,
758 OHCI_INTR_CYC_LOST | OHCI_INTR_CYC_INCONSISTENT);
760 mutex_exit(&soft_statep->isoch->ctxt_list_mutex);