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
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]
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"
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
37 #include <sys/types.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"
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.
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
;
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
,
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
,
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
);
124 * hci1394_isoch_fini()
125 * Cleanup after hci1394_isoch_init. This should be called during detach.
128 hci1394_isoch_fini(hci1394_isoch_handle_t
*isoch_hdl
)
130 hci1394_isoch_t
*isochp
;
133 ASSERT(isoch_hdl
!= NULL
);
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
));
151 * hci1394_isoch_resume()
152 * There is currently nothing to do for resume. This is a placeholder.
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
)
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) {
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) {
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
];
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) {
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
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
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
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.
380 if (ctxtp
->default_tag
== 0x0)
382 else if (ctxtp
->default_tag
== 0x1)
384 else if (ctxtp
->default_tag
== 0x2)
386 else if (ctxtp
->default_tag
== 0x3)
389 /* set match register as desired */
390 HCI1394_IRCTXT_MATCH_WRITE(soft_statep
, ctxtp
->ctxt_index
, tag3
,
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
));
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.
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
;
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
);
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
;
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
;
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().
514 hci1394_stop_isoch_dma(void *hal_private
, void *hal_isoch_dma_handle
,
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
);
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
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.
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
)
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
);
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
) {
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 */);
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
,
605 mutex_exit(&ctxtp
->intrprocmutex
);
607 /* Wait until "active" bit is cleared before continuing */
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)
615 * The context did not stop yet. Wait 1us, increment the
616 * count and try again.
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
);
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.
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
;
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
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
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
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).
746 hci1394_isoch_error_ints_enable(hci1394_state_t
*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
);