/*
* 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 (c) 1999-2000 by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* 1394 Services Layer Isochronous Communication Routines
* This file contains routines for managing isochronous bandwidth
* and channel needs for registered targets (through the target
* isoch interfaces).
*/
#include <sys/tnf_probe.h>
/*
* s1394_isoch_rsrc_realloc()
* is called during bus reset processing to reallocate any isochronous
* resources that were previously allocated.
*/
void
{
int err;
int ret;
S1394_TNF_SL_ISOCH_STACK, "");
/*
* Get the current generation number - don't need the
* topology tree mutex here because it is read-only, and
* there is a race condition with or without it.
*/
/* Lock the Isoch CEC list */
/* Lock the Isoch CEC member list */
/* Are we supposed to reallocate resources? */
/* Reallocate some bandwidth */
/* Check that the generation has not changed */
/* Try the next Isoch CEC */
goto next_isoch_cec;
}
/* Unlock the Isoch CEC member list */
/*
* We can unlock the Isoch CEC list here
* because we know this Isoch CEC can not
* go away (we are trying to realloc its
* resources so it can't be in a state that
* will allow a free).
*/
/* Try to reallocate bandwidth */
generation, &err);
/* Lock the Isoch CEC list */
/* Lock the Isoch CEC member list */
/* If we failed because we couldn't get bandwidth */
if (ret == DDI_FAILURE) {
}
}
/* Are we supposed to reallocate resources? */
/* Reallocate the channel */
/* Unlock the Isoch CEC member list */
/*
* We can unlock the Isoch CEC list here
* because we know this Isoch CEC can not
* go away (we are trying to realloc its
* resources so it can't be in a state that
* will allow a free).
*/
if (chnl_num < 32) {
&old_chnl_mask, &err);
} else {
&old_chnl_mask, &err);
}
/* Lock the Isoch CEC list */
/* Lock the Isoch CEC member list */
if (ret == DDI_FAILURE) {
if (err != CMD1394_EBUSRESET) {
/*
* If we successfully reallocate
* bandwidth, and then fail getting
* the channel, we need to free up
* the bandwidth
*/
/* Try to free up the bandwidth */
if ((ret == DDI_FAILURE) &&
(err != CMD1394_EBUSRESET)) {
"Unable to free bandwidth");
}
/* Try the next Isoch CEC */
goto next_isoch_cec;
}
}
}
/* Unlock the Isoch CEC member list */
}
/* Unlock the Isoch CEC list */
S1394_TNF_SL_ISOCH_STACK, "");
}
/*
* s1394_isoch_rsrc_realloc_notify()
* is called during bus reset processing to notify all targets for
* which isochronous resources were not able to be reallocated.
*/
void
{
S1394_TNF_SL_ISOCH_STACK, "");
/* Lock the Isoch CEC list */
/* Notify all targets that failed realloc */
/* Lock the Isoch CEC member list */
/* Do we notify of realloc failure? */
/* Reason for realloc failure */
/* Now we are going into the callbacks */
/* Unlock the Isoch CEC member list */
/*
* We can unlock the Isoch CEC list here
* because we have the in_fail_callbacks
* field set to B_TRUE. And free will fail
* if we are in fail callbacks.
*/
/* Call all of the rsrc_fail_target() callbacks */
/* Start at the head (talker first) and */
/* go toward the tail (listeners last) */
while (member_curr != NULL) {
if (rsrc_fail_callback != NULL) {
if (type == S1394_PEER_TO_PEER) {
fail_arg);
} else {
fail_arg);
}
}
}
/* Lock the Isoch CEC list */
/* Lock the Isoch CEC member list */
/* We are finished with the callbacks */
}
/* Set flags back to original state */
}
/* Unlock the Isoch CEC member list */
}
/* Unlock the Isoch CEC list */
S1394_TNF_SL_ISOCH_STACK, "");
}
/*
* s1394_channel_alloc()
* is used to allocate an isochronous channel. A channel mask and
* generation are passed. A request is sent to whichever node is the
* IRM for the appropriate channels. If it fails because of a bus
* reset it can be retried. If it fails for another reason the
* channel(s) may not be availble or there may be no IRM.
*/
int
{
int ret;
int i;
S1394_TNF_SL_ISOCH_STACK, "");
/* Lock the topology tree */
/* Unlock the topology tree */
/* Make sure there is a valid IRM on the bus */
if (IRM_node == -1) {
"No IRM on the 1394 bus");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
if (flags & S1394_CHANNEL_ALLOC_HI) {
offset =
} else {
offset =
}
/* Send compare-swap to CHANNELS_AVAILABLE */
/* register on the Isoch Rsrc Mgr */
if (IRM_node == hal_node_num) {
/* Local */
i = num_retries;
do {
/* Check that the generation has not changed */
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
if (ret != DDI_SUCCESS) {
msg, "Error in cswap32");
"stacktrace 1394 s1394", "");
return (DDI_FAILURE);
}
if ((~old_value & channel_mask) != 0) {
msg, "Channels already taken");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_SUCCESS);
}
} while (i--);
"Retries exceeded");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
} else {
/* Remote */
"Unable to allocate command");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
if (flags & S1394_CHANNEL_ALLOC_HI) {
} else {
}
if (ret == DDI_SUCCESS) {
if ((~(*old_channels) & channel_mask) != 0) {
"Channels already taken");
S1394_TNF_SL_ISOCH_STACK, "");
ret = DDI_FAILURE;
} else {
}
/* Need to free the command */
S1394_TNF_SL_ISOCH_STACK, "");
return (ret);
} else {
/* Need to free the command */
msg, "Error allocating isoch channel");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
} else {
/* Need to free the command */
"Error allocating isoch channel");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
}
}
/*
* s1394_channel_free()
* is used to free up an isochronous channel. A channel mask and
* generation are passed. A request is sent to whichever node is the
* IRM for the appropriate channels. If it fails because of a bus
* reset it can be retried. If it fails for another reason the
* channel(s) may already be free or there may be no IRM.
*/
int
{
int ret;
int i;
S1394_TNF_SL_ISOCH_STACK, "");
/* Lock the topology tree */
/* Unlock the topology tree */
/* Make sure there is a valid IRM on the bus */
if (IRM_node == -1) {
"No IRM on the 1394 bus");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
if (flags & S1394_CHANNEL_ALLOC_HI) {
offset =
} else {
offset =
}
/* Send compare-swap to CHANNELS_AVAILABLE */
/* register on the Isoch Rsrc Mgr */
/* Local */
i = num_retries;
do {
/* Check that the generation has not changed */
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
if (ret != DDI_SUCCESS) {
msg, "Error in cswap32");
"stacktrace 1394 s1394", "");
return (DDI_FAILURE);
}
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_SUCCESS);
}
} while (i--);
"Retries exceeded");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
} else {
/* Remote */
"Unable to allocate command");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
if (flags & S1394_CHANNEL_ALLOC_HI) {
} else {
}
if (ret == DDI_SUCCESS) {
/* Need to free the command */
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_SUCCESS);
} else {
/* Need to free the command */
msg, "Error freeing isoch channel");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
} else {
/* Need to free the command */
"Error freeing isoch channel");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
}
}
/*
* s1394_bandwidth_alloc()
* is used to allocate isochronous bandwidth. A number of bandwidth
* allocation units and a generation are passed. The request is sent
* to whichever node is the IRM for this amount of bandwidth. If it
* fails because of a bus reset it can be retried. If it fails for
* another reason the bandwidth may not be available or there may be
* no IRM.
*/
int
{
int temp_value;
int ret;
int i;
S1394_TNF_SL_ISOCH_STACK, "");
/* Lock the topology tree */
/* Unlock the topology tree */
/* Make sure there is a valid IRM on the bus */
if (IRM_node == -1) {
"No IRM on the 1394 bus");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
/* Send compare-swap to BANDWIDTH_AVAILABLE */
/* register on the Isoch Rsrc Mgr */
if (IRM_node == hal_node_num) {
/* Local */
i = num_retries;
do {
/*
* Check that the generation has not changed -
* don't need the lock (read-only)
*/
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
if ((old_value >= bw_alloc_units) &&
(temp_value >= IEEE1394_BANDWIDTH_MIN)) {
} else {
msg, "Retries exceeded");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
&old_value);
if (ret != DDI_SUCCESS) {
msg, "Error in cswap32");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_SUCCESS);
}
} while (i--);
"Too many retries");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
} else {
/* Remote */
"Unable to allocate command");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
if (ret == DDI_SUCCESS) {
/* Need to free the command */
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_SUCCESS);
} else {
/* Need to free the command */
msg, "Error allocating isoch bandwidth");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
} else {
/* Need to free the command */
"Error allocating isoch bandwidth");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
}
}
/*
* s1394_compute_bw_alloc_units()
* is used to compute the number of "bandwidth allocation units" that
* are necessary for a given bit rate. It calculates the overhead
* necessary for isoch packet headers, bus arbitration, etc. (See
* IEEE 1394-1995 Section 8.3.2.3.7 for an explanation of what a
* "bandwidth allocation unit" is.
*/
{
int max_hops;
/* Lock the topology tree */
/* Calculate the 1394 bus diameter */
/* Unlock the topology tree */
/* Calculate the total bandwidth (including overhead) */
switch (speed) {
case IEEE1394_S400:
break;
case IEEE1394_S200:
break;
case IEEE1394_S100:
break;
}
/* See IEC 61883-1 pp. 26-29 for this formula */
return (bau);
}
/*
* s1394_bandwidth_free()
* is used to free up isochronous bandwidth. A number of bandwidth
* allocation units and a generation are passed. The request is sent
* to whichever node is the IRM for this amount of bandwidth. If it
* fails because of a bus reset it can be retried. If it fails for
* another reason the bandwidth may already be freed or there may
* be no IRM.
*/
int
{
int ret;
int i;
S1394_TNF_SL_ISOCH_STACK, "");
/* Lock the topology tree */
/* Unlock the topology tree */
/* Make sure there is a valid IRM on the bus */
if (IRM_node == -1) {
"No IRM on the 1394 bus");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
/* Send compare-swap to BANDWIDTH_AVAILABLE */
/* register on the Isoch Rsrc Mgr */
if (IRM_node == hal_node_num) {
i = num_retries;
do {
/* Check that the generation has not changed */
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
if ((temp_value >= old_value) &&
(temp_value <= IEEE1394_BANDWIDTH_MAX)) {
swap = temp_value;
} else {
msg, "Too many retries");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
&old_value);
if (ret != DDI_SUCCESS) {
msg, "Error in cswap32");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_SUCCESS);
}
} while (i--);
"Retries exceeded");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
} else {
/* Remote */
"Unable to allocate command");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
if (ret == DDI_SUCCESS) {
/* Need to free the command */
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_SUCCESS);
} else {
/* Need to free the command */
msg, "Error freeing isoch bandwidth");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
} else {
/* Need to free the command */
"Error freeing isoch bandwidth");
S1394_TNF_SL_ISOCH_STACK, "");
return (DDI_FAILURE);
}
}
}
/*
* s1394_isoch_cec_list_insert()
* is used to insert an Isoch CEC into a given HAL's list of Isoch CECs.
*/
void
{
S1394_TNF_SL_ISOCH_STACK, "");
/* Is the Isoch CEC list empty? */
} else {
}
S1394_TNF_SL_ISOCH_STACK, "");
}
/*
* s1394_isoch_cec_list_remove()
* is used to remove an Isoch CEC from a given HAL's list of Isoch CECs.
*/
void
{
S1394_TNF_SL_ISOCH_STACK, "");
} else {
}
} else {
}
S1394_TNF_SL_ISOCH_STACK, "");
}
/*
* s1394_isoch_cec_member_list_insert()
* is used to insert a new member (target) into the list of members for
* a given Isoch CEC.
*/
/* ARGSUSED */
void
{
S1394_TNF_SL_ISOCH_STACK, "");
/* Is the Isoch CEC member list empty? */
/* Put talker at the head of the list */
} else {
/* Put listeners at the tail of the list */
}
S1394_TNF_SL_ISOCH_STACK, "");
}
/*
* s1394_isoch_cec_member_list_remove()
* is used to remove a member (target) from the list of members for
* a given Isoch CEC.
*/
/* ARGSUSED */
void
{
S1394_TNF_SL_ISOCH_STACK, "");
if (prev_member != NULL) {
} else {
}
if (next_member != NULL) {
} else {
}
S1394_TNF_SL_ISOCH_STACK, "");
}