hci1394_isoch.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* HCI HAL isochronous interface routines. Contains routines used
* internally within the HAL to manage isochronous contexts, and
* also routines called from the Services Layer to manage an isochronous
* DMA resource.
*/
/*
* Patchable variable used to indicate the number of microseconds to wait
* for an isoch ctxt to stop ("active" goes low) after clearing the "run"
* bit
*/
/*
* Number of microseconds to wait in hci1394_do_stop() for an isoch ctxt
* interrupt handler to complete. Experiments showed that in some cases
* the timeout needed was as long as 2 seconds. This is probably due to
* significant interrupt processing overhead for certain IXL chains.
*/
/*
* hci1394_isoch_init()
* Initialize the isochronous dma soft state.
*/
void
{
int i;
"");
/* initialize contexts */
for (i = 0; i < HCI1394_MAX_ISOCH_CONTEXTS; i++) {
/* init context flags to 0 */
}
/* initialize the count for allocated isoch dma */
isochp->isoch_dma_alloc_cnt = 0;
/* initialize the cycle_lost_thresh struct */
/* initialize the cycle_incon_thresh struct */
/* determine number of contexts supported */
/* the isochronous context mutex is used during some error interrupts */
"");
}
/*
* hci1394_isoch_fini()
* Cleanup after hci1394_isoch_init. This should be called during detach.
*/
void
{
int i;
"");
for (i = 0; i < HCI1394_MAX_ISOCH_CONTEXTS; i++) {
}
"");
}
/*
* hci1394_isoch_resume()
* There is currently nothing to do for resume. This is a placeholder.
*/
/* ARGSUSED */
int
{
return (DDI_SUCCESS);
}
/*
* hci1394_alloc_isoch_dma ()
* Called by the Services Layer. Used to allocate a local Isoch DMA context.
* Goes through appropriate context list (either transmit or receive)
* looking for an unused context. Fails if none found.
* Then compiles the provided IXL program.
*/
int
void **hal_idma_handlep, int *resultp)
{
int i;
int err;
*hal_idma_handlep = NULL;
/*
* find context to use based on whether talking(send) or listening(recv)
*/
/* TRANSMIT */
"Allocating isoch transmit context");
/*
* search through list of hardware supported contexts for
* one that's not inuse
*/
for (i = 0; i < isochp->ctxt_xmit_count; i++) {
HCI1394_ISO_CTXT_INUSE) == 0) {
break;
}
}
/* if there aren't any left, return an error */
if (i >= isochp->ctxt_xmit_count) {
"Out of isoch transmit resources");
return (DDI_FAILURE);
}
/* mark inuse and set up handle to context */
} else {
/* RECEIVE */
"Allocating isoch receive context");
/* search thru implemented contexts for one that's available */
for (i = 0; i < isochp->ctxt_recv_count; i++) {
HCI1394_ISO_CTXT_INUSE) == 0) {
break;
}
}
/* if there aren't any left, return an error */
/* XXX support for multi-chan could go here */
if (i >= isochp->ctxt_recv_count) {
"Out of isoch receive resources");
return (DDI_FAILURE);
}
/* set up receive mode flags */
}
}
/* mark inuse and set up handle to context */
}
/* before compiling, set up some default context values */
/*
* if the compile failed, clear the appropriate flags.
* Note that the context mutex is needed to eliminate race condition
* with cycle_inconsistent and other error intrs.
*/
if (err != DDI_SUCCESS) {
/* undo the set up of receive mode flags */
}
return (DDI_FAILURE);
}
/*
* Update count of allocated isoch dma (and enable interrupts
* if necessary)
*/
if (isochp->isoch_dma_alloc_cnt == 0) {
}
ctxtp->intr_flags = 0;
return (DDI_SUCCESS);
}
/*
* hci1394_start_isoch_dma()
* Used to start an allocated isochronous dma resource.
* Sets the context's command ptr to start at the first IXL,
* sets up IR match register (if IR), and enables the context_control
* register RUN bit.
*/
/* ARGSUSED */
int
{
/* pick up the context pointer from the private idma data */
/* if the context is already running, just exit. else set running */
"context already running");
return (DDI_SUCCESS);
}
/* initialize context values */
ctxtp->ixl_exec_depth = 0;
ctxtp->dma_last_time = 0;
/*
* clear out hci DMA descriptor status to start with clean slate.
* note that statuses could be set if context was previously started
* then stopped.
*/
/* set up registers, and start isoch */
/* set context's command ptr to the first descriptor */
/*
* determine correct tag values. map target's requested 2-bit
* tag into one of the 4 openHCI tag bits.
* XXX for now the t1394 api only supports a single tag setting,
* whereas openhci supports a set of (non-mutually exclusive)
* valid tags. if the api changes to support multiple
* simultaneous tags, then this code must be changed.
*/
tag0 = 0;
tag1 = 1;
tag2 = 2;
tag3 = 3;
tag0 = 1;
tag1 = 1;
tag2 = 1;
tag3 = 1;
/* set match register as desired */
/* clear all bits in context ctrl reg to init to known state */
/* set desired values in context control register */
0 /* multi-chan mode */, 1 /* run */, 0 /* wake */);
/*
* before enabling interrupts, make sure any vestige interrupt
* event (from a previous use) is cleared.
*/
/* enable interrupts for this IR context */
} else {
/* TRANSMIT */
/* set context's command ptr to the first descriptor */
/* set desired values in context control register */
1 /* run */, 0 /* wake */);
/*
* before enabling interrupts, make sure any vestige interrupt
* event (from a previous use) is cleared.
*/
/* enable interrupts for this IT context */
}
return (DDI_SUCCESS);
}
/*
* hci1394_update_isoch_dma()
*
* Returns DDI_SUCCESS, or DDI_FAILURE. If DDI_FAILURE, then resultp
* contains the error code.
*/
/* ARGSUSED */
int
{
int ii;
int err = DDI_SUCCESS;
/* pick up the context pointer from the private idma data */
/*
* regardless of the type of context (IR or IT), loop through each
* command pair (one from new, one from orig), updating the relevant
* fields of orig with those from new.
*/
/* lots of debug trace info */
ii++) {
/* error if hit a null ixl command too soon */
err = DDI_FAILURE;
break;
}
/* proceed with the update */
cur_orig_ixlp, 0, resultp);
/* advance new and orig chains */
}
return (err);
}
/*
* hci1394_stop_isoch_dma()
* Used to stop a "running" isochronous dma resource.
* This is a wrapper which calls the hci1394_do_stop to do the actual work,
* but NOT to invoke the target's isoch_dma_stopped().
*/
/* ARGSUSED */
void
int *result)
{
/* pick up the context pointer from the private idma data */
/* stop the context, do not invoke target's stop callback */
/*
* call interrupt processing functions to bring callbacks and
* store_timestamps upto date. Don't care about errors.
*/
}
/*
* hci1394_do_stop()
* Used to stop a "running" isochronous dma resource.
* Disables interrupts for the context, clears the context_control register's
* RUN bit, and makes sure the ixl is up-to-date with where the hardware is
* in the DMA chain.
* If do_callback is B_TRUE, the target's isoch_dma_stopped() callback is
* invoked. Caller must not hold mutex(es) if calling with
* do_callback==B_TRUE, otherwise mutex(es) will be held during callback.
* If do_callback is B_FALSE, the isoch_dma_stopped() callback is NOT
* invoked and stop_args is ignored.
*/
void
{
int count;
"");
/* already stopped? if yes, done, else set state to not-running */
"context already stopped");
return;
}
/* turn off context control register's run bit */
/* RECEIVE */
/* disable interrupts for this IR context */
/* turn off run bit */
0 /* bffill */, 0 /* iso hdrs */, 0 /* match enbl */,
0 /* multi-chan mode (not implemented) */, 1 /* run */);
} else {
/* TRANSMIT */
/* disable interrupts for this IT context */
/* turn of run bit */
0 /* match enbl */, 0 /* match */, 1 /* run */);
}
/*
* If interrupt is already in progress, wait until it's over.
* Otherwise, set flag to prevent the new interrupt.
*/
upto = ddi_get_lbolt() +
upto) <= 0) {
break;
}
}
}
}
/* Wait until "active" bit is cleared before continuing */
count = 0;
while (count < hci1394_iso_ctxt_stop_delay_uS) {
/* Has the "active" bit gone low yet? */
break;
/*
* The context did not stop yet. Wait 1us, increment the
* count and try again.
*/
drv_usecwait(1);
count++;
}
/* Check to see if we timed out or not */
if (count >= hci1394_iso_ctxt_stop_delay_uS) {
"unable to stop isoch context",
"context timed out trying to stop");
return;
}
/*
* invoke callback as directed. Note that the CTXT_INCALL flag is NOT
* needed here. That flag is only used when we have to drop a mutex
* that we want to grab back again. We're not doing that here.
*/
if (do_callback == B_TRUE) {
(struct isoch_dma_handle *)ctxtp,
}
}
"");
}
/*
* hci1394_free_isoch_dma()
* Used to free up usage of an isochronous context and any other
* system resources acquired during IXL compilation.
* This does NOT free up the IXL and it's data buffers which is
* the target driver's responsibility.
*/
void
{
/* pick up the context pointer from the private idma data */
/* lots of debug trace info */
/* delete xfer_ctl structs and pages of allocated hci_desc memory */
/*
* free context. no need to determine if xmit or recv. clearing of recv
* flags is harmless for xmit.
*/
/*
* Update count of allocated isoch dma (and disable interrupts
* if necessary)
*/
if (isochp->isoch_dma_alloc_cnt == 0) {
}
}
/*
* hci1394_isoch_recv_count_get()
* returns the number of supported isoch receive contexts.
*/
int
{
return (isoch_hdl->ctxt_recv_count);
}
/*
* hci1394_isoch_recv_ctxt_get()
* given a context index, returns its isoch receive context struct
*/
{
}
/*
* hci1394_isoch_xmit_count_get()
* returns the number of supported isoch transmit contexts.
*/
int
{
return (isoch_hdl->ctxt_xmit_count);
}
/*
* hci1394_isoch_xmit_ctxt_get()
* given a context index, returns its isoch transmit context struct
*/
{
}
/*
* hci1394_isoch_error_ints_enable()
* after bus reset, reenable CYCLE_LOST and CYCLE_INCONSISTENT
* interrupts (if necessary).
*/
void
{
}
}