1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright (c) 1999-2000 by Sun Microsystems, Inc. 24*7c478bd9Sstevel@tonic-gate * All rights reserved. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * s1394_isoch.c 31*7c478bd9Sstevel@tonic-gate * 1394 Services Layer Isochronous Communication Routines 32*7c478bd9Sstevel@tonic-gate * This file contains routines for managing isochronous bandwidth 33*7c478bd9Sstevel@tonic-gate * and channel needs for registered targets (through the target 34*7c478bd9Sstevel@tonic-gate * isoch interfaces). 35*7c478bd9Sstevel@tonic-gate */ 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/tnf_probe.h> 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate #include <sys/1394/t1394.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/1394/s1394.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/1394/h1394.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/1394/ieee1394.h> 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate /* 49*7c478bd9Sstevel@tonic-gate * s1394_isoch_rsrc_realloc() 50*7c478bd9Sstevel@tonic-gate * is called during bus reset processing to reallocate any isochronous 51*7c478bd9Sstevel@tonic-gate * resources that were previously allocated. 52*7c478bd9Sstevel@tonic-gate */ 53*7c478bd9Sstevel@tonic-gate void 54*7c478bd9Sstevel@tonic-gate s1394_isoch_rsrc_realloc(s1394_hal_t *hal) 55*7c478bd9Sstevel@tonic-gate { 56*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_t *cec_curr; 57*7c478bd9Sstevel@tonic-gate uint32_t chnl_mask; 58*7c478bd9Sstevel@tonic-gate uint32_t old_chnl_mask; 59*7c478bd9Sstevel@tonic-gate uint_t bw_alloc_units; 60*7c478bd9Sstevel@tonic-gate uint_t generation; 61*7c478bd9Sstevel@tonic-gate uint_t chnl_num; 62*7c478bd9Sstevel@tonic-gate int err; 63*7c478bd9Sstevel@tonic-gate int ret; 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_isoch_rsrc_realloc_enter, 66*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate /* 69*7c478bd9Sstevel@tonic-gate * Get the current generation number - don't need the 70*7c478bd9Sstevel@tonic-gate * topology tree mutex here because it is read-only, and 71*7c478bd9Sstevel@tonic-gate * there is a race condition with or without it. 72*7c478bd9Sstevel@tonic-gate */ 73*7c478bd9Sstevel@tonic-gate generation = hal->generation_count; 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate /* Lock the Isoch CEC list */ 76*7c478bd9Sstevel@tonic-gate mutex_enter(&hal->isoch_cec_list_mutex); 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate cec_curr = hal->isoch_cec_list_head; 79*7c478bd9Sstevel@tonic-gate while (cec_curr != NULL) { 80*7c478bd9Sstevel@tonic-gate /* Lock the Isoch CEC member list */ 81*7c478bd9Sstevel@tonic-gate mutex_enter(&cec_curr->isoch_cec_mutex); 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate /* Are we supposed to reallocate resources? */ 84*7c478bd9Sstevel@tonic-gate if (!(cec_curr->cec_options & T1394_NO_IRM_ALLOC) && 85*7c478bd9Sstevel@tonic-gate (cec_curr->realloc_valid == B_TRUE) && 86*7c478bd9Sstevel@tonic-gate (cec_curr->realloc_failed == B_FALSE)) { 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate /* Reallocate some bandwidth */ 89*7c478bd9Sstevel@tonic-gate bw_alloc_units = s1394_compute_bw_alloc_units(hal, 90*7c478bd9Sstevel@tonic-gate cec_curr->bandwidth, cec_curr->realloc_speed); 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate /* Check that the generation has not changed */ 93*7c478bd9Sstevel@tonic-gate if (generation != hal->generation_count) { 94*7c478bd9Sstevel@tonic-gate /* Try the next Isoch CEC */ 95*7c478bd9Sstevel@tonic-gate goto next_isoch_cec; 96*7c478bd9Sstevel@tonic-gate } 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate /* Unlock the Isoch CEC member list */ 99*7c478bd9Sstevel@tonic-gate mutex_exit(&cec_curr->isoch_cec_mutex); 100*7c478bd9Sstevel@tonic-gate /* 101*7c478bd9Sstevel@tonic-gate * We can unlock the Isoch CEC list here 102*7c478bd9Sstevel@tonic-gate * because we know this Isoch CEC can not 103*7c478bd9Sstevel@tonic-gate * go away (we are trying to realloc its 104*7c478bd9Sstevel@tonic-gate * resources so it can't be in a state that 105*7c478bd9Sstevel@tonic-gate * will allow a free). 106*7c478bd9Sstevel@tonic-gate */ 107*7c478bd9Sstevel@tonic-gate mutex_exit(&hal->isoch_cec_list_mutex); 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate /* Try to reallocate bandwidth */ 110*7c478bd9Sstevel@tonic-gate ret = s1394_bandwidth_alloc(hal, bw_alloc_units, 111*7c478bd9Sstevel@tonic-gate generation, &err); 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate /* Lock the Isoch CEC list */ 114*7c478bd9Sstevel@tonic-gate mutex_enter(&hal->isoch_cec_list_mutex); 115*7c478bd9Sstevel@tonic-gate /* Lock the Isoch CEC member list */ 116*7c478bd9Sstevel@tonic-gate mutex_enter(&cec_curr->isoch_cec_mutex); 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate /* If we failed because we couldn't get bandwidth */ 119*7c478bd9Sstevel@tonic-gate if (ret == DDI_FAILURE) { 120*7c478bd9Sstevel@tonic-gate cec_curr->realloc_failed = B_TRUE; 121*7c478bd9Sstevel@tonic-gate cec_curr->realloc_fail_reason = 122*7c478bd9Sstevel@tonic-gate T1394_RSRC_BANDWIDTH; 123*7c478bd9Sstevel@tonic-gate } 124*7c478bd9Sstevel@tonic-gate } 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate /* Are we supposed to reallocate resources? */ 127*7c478bd9Sstevel@tonic-gate if (!(cec_curr->cec_options & T1394_NO_IRM_ALLOC) && 128*7c478bd9Sstevel@tonic-gate (cec_curr->realloc_valid == B_TRUE) && 129*7c478bd9Sstevel@tonic-gate (cec_curr->realloc_failed == B_FALSE)) { 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate /* Reallocate the channel */ 132*7c478bd9Sstevel@tonic-gate chnl_num = cec_curr->realloc_chnl_num; 133*7c478bd9Sstevel@tonic-gate chnl_mask = (1 << ((63 - chnl_num) % 32)); 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate /* Unlock the Isoch CEC member list */ 136*7c478bd9Sstevel@tonic-gate mutex_exit(&cec_curr->isoch_cec_mutex); 137*7c478bd9Sstevel@tonic-gate /* 138*7c478bd9Sstevel@tonic-gate * We can unlock the Isoch CEC list here 139*7c478bd9Sstevel@tonic-gate * because we know this Isoch CEC can not 140*7c478bd9Sstevel@tonic-gate * go away (we are trying to realloc its 141*7c478bd9Sstevel@tonic-gate * resources so it can't be in a state that 142*7c478bd9Sstevel@tonic-gate * will allow a free). 143*7c478bd9Sstevel@tonic-gate */ 144*7c478bd9Sstevel@tonic-gate mutex_exit(&hal->isoch_cec_list_mutex); 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate if (chnl_num < 32) { 147*7c478bd9Sstevel@tonic-gate ret = s1394_channel_alloc(hal, chnl_mask, 148*7c478bd9Sstevel@tonic-gate generation, S1394_CHANNEL_ALLOC_HI, 149*7c478bd9Sstevel@tonic-gate &old_chnl_mask, &err); 150*7c478bd9Sstevel@tonic-gate } else { 151*7c478bd9Sstevel@tonic-gate ret = s1394_channel_alloc(hal, chnl_mask, 152*7c478bd9Sstevel@tonic-gate generation, S1394_CHANNEL_ALLOC_LO, 153*7c478bd9Sstevel@tonic-gate &old_chnl_mask, &err); 154*7c478bd9Sstevel@tonic-gate } 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate /* Lock the Isoch CEC list */ 157*7c478bd9Sstevel@tonic-gate mutex_enter(&hal->isoch_cec_list_mutex); 158*7c478bd9Sstevel@tonic-gate /* Lock the Isoch CEC member list */ 159*7c478bd9Sstevel@tonic-gate mutex_enter(&cec_curr->isoch_cec_mutex); 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate if (ret == DDI_FAILURE) { 162*7c478bd9Sstevel@tonic-gate if (err != CMD1394_EBUSRESET) { 163*7c478bd9Sstevel@tonic-gate /* 164*7c478bd9Sstevel@tonic-gate * If we successfully reallocate 165*7c478bd9Sstevel@tonic-gate * bandwidth, and then fail getting 166*7c478bd9Sstevel@tonic-gate * the channel, we need to free up 167*7c478bd9Sstevel@tonic-gate * the bandwidth 168*7c478bd9Sstevel@tonic-gate */ 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate /* Try to free up the bandwidth */ 171*7c478bd9Sstevel@tonic-gate ret = s1394_bandwidth_free(hal, 172*7c478bd9Sstevel@tonic-gate bw_alloc_units, generation, &err); 173*7c478bd9Sstevel@tonic-gate if ((ret == DDI_FAILURE) && 174*7c478bd9Sstevel@tonic-gate (err != CMD1394_EBUSRESET)) { 175*7c478bd9Sstevel@tonic-gate TNF_PROBE_1( 176*7c478bd9Sstevel@tonic-gate s1394_isoch_rsrc_realloc_error, 177*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, 178*7c478bd9Sstevel@tonic-gate "", tnf_string, msg, 179*7c478bd9Sstevel@tonic-gate "Unable to free bandwidth"); 180*7c478bd9Sstevel@tonic-gate } 181*7c478bd9Sstevel@tonic-gate /* Try the next Isoch CEC */ 182*7c478bd9Sstevel@tonic-gate goto next_isoch_cec; 183*7c478bd9Sstevel@tonic-gate } 184*7c478bd9Sstevel@tonic-gate cec_curr->realloc_failed = B_TRUE; 185*7c478bd9Sstevel@tonic-gate cec_curr->realloc_fail_reason = 186*7c478bd9Sstevel@tonic-gate T1394_RSRC_CHANNEL; 187*7c478bd9Sstevel@tonic-gate } 188*7c478bd9Sstevel@tonic-gate } 189*7c478bd9Sstevel@tonic-gate next_isoch_cec: 190*7c478bd9Sstevel@tonic-gate /* Unlock the Isoch CEC member list */ 191*7c478bd9Sstevel@tonic-gate mutex_exit(&cec_curr->isoch_cec_mutex); 192*7c478bd9Sstevel@tonic-gate cec_curr = cec_curr->cec_next; 193*7c478bd9Sstevel@tonic-gate } 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate /* Unlock the Isoch CEC list */ 196*7c478bd9Sstevel@tonic-gate mutex_exit(&hal->isoch_cec_list_mutex); 197*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_isoch_rsrc_realloc_exit, 198*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 199*7c478bd9Sstevel@tonic-gate } 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate /* 202*7c478bd9Sstevel@tonic-gate * s1394_isoch_rsrc_realloc_notify() 203*7c478bd9Sstevel@tonic-gate * is called during bus reset processing to notify all targets for 204*7c478bd9Sstevel@tonic-gate * which isochronous resources were not able to be reallocated. 205*7c478bd9Sstevel@tonic-gate */ 206*7c478bd9Sstevel@tonic-gate void 207*7c478bd9Sstevel@tonic-gate s1394_isoch_rsrc_realloc_notify(s1394_hal_t *hal) 208*7c478bd9Sstevel@tonic-gate { 209*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_t *cec_curr; 210*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_member_t *member_curr; 211*7c478bd9Sstevel@tonic-gate t1394_isoch_rsrc_error_t fail_arg; 212*7c478bd9Sstevel@tonic-gate opaque_t evts_arg; 213*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_type_t type; 214*7c478bd9Sstevel@tonic-gate void (*rsrc_fail_callback)(t1394_isoch_cec_handle_t, opaque_t, 215*7c478bd9Sstevel@tonic-gate t1394_isoch_rsrc_error_t); 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_isoch_rsrc_realloc_notify_enter, 218*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate /* Lock the Isoch CEC list */ 221*7c478bd9Sstevel@tonic-gate mutex_enter(&hal->isoch_cec_list_mutex); 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate /* Notify all targets that failed realloc */ 224*7c478bd9Sstevel@tonic-gate cec_curr = hal->isoch_cec_list_head; 225*7c478bd9Sstevel@tonic-gate while (cec_curr != NULL) { 226*7c478bd9Sstevel@tonic-gate /* Lock the Isoch CEC member list */ 227*7c478bd9Sstevel@tonic-gate mutex_enter(&cec_curr->isoch_cec_mutex); 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate /* Do we notify of realloc failure? */ 230*7c478bd9Sstevel@tonic-gate if (!(cec_curr->cec_options & T1394_NO_IRM_ALLOC) && 231*7c478bd9Sstevel@tonic-gate (cec_curr->realloc_valid == B_TRUE) && 232*7c478bd9Sstevel@tonic-gate (cec_curr->realloc_failed == B_TRUE)) { 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate /* Reason for realloc failure */ 235*7c478bd9Sstevel@tonic-gate fail_arg = cec_curr->realloc_fail_reason; 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate /* Now we are going into the callbacks */ 238*7c478bd9Sstevel@tonic-gate cec_curr->in_fail_callbacks = B_TRUE; 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate type = cec_curr->cec_type; 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate /* Unlock the Isoch CEC member list */ 243*7c478bd9Sstevel@tonic-gate mutex_exit(&cec_curr->isoch_cec_mutex); 244*7c478bd9Sstevel@tonic-gate /* 245*7c478bd9Sstevel@tonic-gate * We can unlock the Isoch CEC list here 246*7c478bd9Sstevel@tonic-gate * because we have the in_fail_callbacks 247*7c478bd9Sstevel@tonic-gate * field set to B_TRUE. And free will fail 248*7c478bd9Sstevel@tonic-gate * if we are in fail callbacks. 249*7c478bd9Sstevel@tonic-gate */ 250*7c478bd9Sstevel@tonic-gate mutex_exit(&hal->isoch_cec_list_mutex); 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate /* Call all of the rsrc_fail_target() callbacks */ 253*7c478bd9Sstevel@tonic-gate /* Start at the head (talker first) and */ 254*7c478bd9Sstevel@tonic-gate /* go toward the tail (listeners last) */ 255*7c478bd9Sstevel@tonic-gate member_curr = cec_curr->cec_member_list_head; 256*7c478bd9Sstevel@tonic-gate while (member_curr != NULL) { 257*7c478bd9Sstevel@tonic-gate rsrc_fail_callback = member_curr-> 258*7c478bd9Sstevel@tonic-gate isoch_cec_evts.rsrc_fail_target; 259*7c478bd9Sstevel@tonic-gate evts_arg = member_curr->isoch_cec_evts_arg; 260*7c478bd9Sstevel@tonic-gate if (rsrc_fail_callback != NULL) { 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate if (type == S1394_PEER_TO_PEER) { 263*7c478bd9Sstevel@tonic-gate rsrc_fail_callback( 264*7c478bd9Sstevel@tonic-gate (t1394_isoch_cec_handle_t) 265*7c478bd9Sstevel@tonic-gate cec_curr, evts_arg, 266*7c478bd9Sstevel@tonic-gate fail_arg); 267*7c478bd9Sstevel@tonic-gate } else { 268*7c478bd9Sstevel@tonic-gate rsrc_fail_callback( 269*7c478bd9Sstevel@tonic-gate (t1394_isoch_cec_handle_t) 270*7c478bd9Sstevel@tonic-gate cec_curr, evts_arg, 271*7c478bd9Sstevel@tonic-gate fail_arg); 272*7c478bd9Sstevel@tonic-gate } 273*7c478bd9Sstevel@tonic-gate } 274*7c478bd9Sstevel@tonic-gate member_curr = member_curr->cec_mem_next; 275*7c478bd9Sstevel@tonic-gate } 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate /* Lock the Isoch CEC list */ 278*7c478bd9Sstevel@tonic-gate mutex_enter(&hal->isoch_cec_list_mutex); 279*7c478bd9Sstevel@tonic-gate /* Lock the Isoch CEC member list */ 280*7c478bd9Sstevel@tonic-gate mutex_enter(&cec_curr->isoch_cec_mutex); 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate /* We are finished with the callbacks */ 283*7c478bd9Sstevel@tonic-gate cec_curr->in_fail_callbacks = B_FALSE; 284*7c478bd9Sstevel@tonic-gate if (cec_curr->cec_want_wakeup == B_TRUE) { 285*7c478bd9Sstevel@tonic-gate cec_curr->cec_want_wakeup = B_FALSE; 286*7c478bd9Sstevel@tonic-gate cv_broadcast(&cec_curr->in_callbacks_cv); 287*7c478bd9Sstevel@tonic-gate } 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate /* Set flags back to original state */ 290*7c478bd9Sstevel@tonic-gate cec_curr->realloc_valid = B_FALSE; 291*7c478bd9Sstevel@tonic-gate cec_curr->realloc_failed = B_FALSE; 292*7c478bd9Sstevel@tonic-gate } 293*7c478bd9Sstevel@tonic-gate /* Unlock the Isoch CEC member list */ 294*7c478bd9Sstevel@tonic-gate mutex_exit(&cec_curr->isoch_cec_mutex); 295*7c478bd9Sstevel@tonic-gate cec_curr = cec_curr->cec_next; 296*7c478bd9Sstevel@tonic-gate } 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate /* Unlock the Isoch CEC list */ 299*7c478bd9Sstevel@tonic-gate mutex_exit(&hal->isoch_cec_list_mutex); 300*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_isoch_rsrc_realloc_notify_exit, 301*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 302*7c478bd9Sstevel@tonic-gate } 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate /* 305*7c478bd9Sstevel@tonic-gate * s1394_channel_alloc() 306*7c478bd9Sstevel@tonic-gate * is used to allocate an isochronous channel. A channel mask and 307*7c478bd9Sstevel@tonic-gate * generation are passed. A request is sent to whichever node is the 308*7c478bd9Sstevel@tonic-gate * IRM for the appropriate channels. If it fails because of a bus 309*7c478bd9Sstevel@tonic-gate * reset it can be retried. If it fails for another reason the 310*7c478bd9Sstevel@tonic-gate * channel(s) may not be availble or there may be no IRM. 311*7c478bd9Sstevel@tonic-gate */ 312*7c478bd9Sstevel@tonic-gate int 313*7c478bd9Sstevel@tonic-gate s1394_channel_alloc(s1394_hal_t *hal, uint32_t channel_mask, uint_t generation, 314*7c478bd9Sstevel@tonic-gate uint_t flags, uint32_t *old_channels, int *result) 315*7c478bd9Sstevel@tonic-gate { 316*7c478bd9Sstevel@tonic-gate cmd1394_cmd_t *cmd; 317*7c478bd9Sstevel@tonic-gate uint64_t IRM_ID_addr; 318*7c478bd9Sstevel@tonic-gate uint32_t compare; 319*7c478bd9Sstevel@tonic-gate uint32_t swap; 320*7c478bd9Sstevel@tonic-gate uint32_t old_value; 321*7c478bd9Sstevel@tonic-gate uint_t hal_node_num; 322*7c478bd9Sstevel@tonic-gate uint_t IRM_node; 323*7c478bd9Sstevel@tonic-gate uint_t offset; 324*7c478bd9Sstevel@tonic-gate int ret; 325*7c478bd9Sstevel@tonic-gate int i; 326*7c478bd9Sstevel@tonic-gate int num_retries = S1394_ISOCH_ALLOC_RETRIES; 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_alloc_enter, 329*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate /* Lock the topology tree */ 332*7c478bd9Sstevel@tonic-gate mutex_enter(&hal->topology_tree_mutex); 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate hal_node_num = IEEE1394_NODE_NUM(hal->node_id); 335*7c478bd9Sstevel@tonic-gate IRM_node = hal->IRM_node; 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate /* Unlock the topology tree */ 338*7c478bd9Sstevel@tonic-gate mutex_exit(&hal->topology_tree_mutex); 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate /* Make sure there is a valid IRM on the bus */ 341*7c478bd9Sstevel@tonic-gate if (IRM_node == -1) { 342*7c478bd9Sstevel@tonic-gate *result = CMD1394_ERETRIES_EXCEEDED; 343*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_channel_alloc_error, 344*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg, 345*7c478bd9Sstevel@tonic-gate "No IRM on the 1394 bus"); 346*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit, 347*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 348*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate if (flags & S1394_CHANNEL_ALLOC_HI) { 352*7c478bd9Sstevel@tonic-gate offset = 353*7c478bd9Sstevel@tonic-gate (IEEE1394_SCSR_CHANS_AVAIL_HI & IEEE1394_CSR_OFFSET_MASK); 354*7c478bd9Sstevel@tonic-gate } else { 355*7c478bd9Sstevel@tonic-gate offset = 356*7c478bd9Sstevel@tonic-gate (IEEE1394_SCSR_CHANS_AVAIL_LO & IEEE1394_CSR_OFFSET_MASK); 357*7c478bd9Sstevel@tonic-gate } 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate /* Send compare-swap to CHANNELS_AVAILABLE */ 360*7c478bd9Sstevel@tonic-gate /* register on the Isoch Rsrc Mgr */ 361*7c478bd9Sstevel@tonic-gate if (IRM_node == hal_node_num) { 362*7c478bd9Sstevel@tonic-gate /* Local */ 363*7c478bd9Sstevel@tonic-gate i = num_retries; 364*7c478bd9Sstevel@tonic-gate do { 365*7c478bd9Sstevel@tonic-gate (void) HAL_CALL(hal).csr_read(hal->halinfo.hal_private, 366*7c478bd9Sstevel@tonic-gate offset, &old_value); 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate /* Check that the generation has not changed */ 369*7c478bd9Sstevel@tonic-gate if (generation != hal->generation_count) { 370*7c478bd9Sstevel@tonic-gate *result = CMD1394_EBUSRESET; 371*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit, 372*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 373*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate compare = old_value; 377*7c478bd9Sstevel@tonic-gate swap = old_value & (~channel_mask); 378*7c478bd9Sstevel@tonic-gate 379*7c478bd9Sstevel@tonic-gate ret = HAL_CALL(hal).csr_cswap32( 380*7c478bd9Sstevel@tonic-gate hal->halinfo.hal_private, generation, 381*7c478bd9Sstevel@tonic-gate offset, compare, swap, &old_value); 382*7c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 383*7c478bd9Sstevel@tonic-gate *result = CMD1394_EBUSRESET; 384*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_channel_alloc_error, 385*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, 386*7c478bd9Sstevel@tonic-gate msg, "Error in cswap32"); 387*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit, 388*7c478bd9Sstevel@tonic-gate "stacktrace 1394 s1394", ""); 389*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 390*7c478bd9Sstevel@tonic-gate } 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate if ((~old_value & channel_mask) != 0) { 393*7c478bd9Sstevel@tonic-gate *result = CMD1394_ERETRIES_EXCEEDED; 394*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_channel_alloc_error, 395*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, 396*7c478bd9Sstevel@tonic-gate msg, "Channels already taken"); 397*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit, 398*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 399*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate if (old_value == compare) { 403*7c478bd9Sstevel@tonic-gate *result = CMD1394_CMDSUCCESS; 404*7c478bd9Sstevel@tonic-gate *old_channels = old_value; 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit, 407*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 408*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 409*7c478bd9Sstevel@tonic-gate } 410*7c478bd9Sstevel@tonic-gate } while (i--); 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate *result = CMD1394_ERETRIES_EXCEEDED; 413*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_channel_alloc_error, 414*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg, 415*7c478bd9Sstevel@tonic-gate "Retries exceeded"); 416*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit, 417*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 418*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate } else { 421*7c478bd9Sstevel@tonic-gate /* Remote */ 422*7c478bd9Sstevel@tonic-gate if (s1394_alloc_cmd(hal, 0, &cmd) != DDI_SUCCESS) { 423*7c478bd9Sstevel@tonic-gate *result = CMD1394_EUNKNOWN_ERROR; 424*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_channel_alloc_error, 425*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg, 426*7c478bd9Sstevel@tonic-gate "Unable to allocate command"); 427*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit, 428*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 429*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 430*7c478bd9Sstevel@tonic-gate } 431*7c478bd9Sstevel@tonic-gate 432*7c478bd9Sstevel@tonic-gate cmd->cmd_options = (CMD1394_CANCEL_ON_BUS_RESET | 433*7c478bd9Sstevel@tonic-gate CMD1394_OVERRIDE_ADDR | CMD1394_BLOCKING); 434*7c478bd9Sstevel@tonic-gate cmd->cmd_type = CMD1394_ASYNCH_LOCK_32; 435*7c478bd9Sstevel@tonic-gate 436*7c478bd9Sstevel@tonic-gate if (flags & S1394_CHANNEL_ALLOC_HI) { 437*7c478bd9Sstevel@tonic-gate IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK | 438*7c478bd9Sstevel@tonic-gate IEEE1394_SCSR_CHANS_AVAIL_HI) | 439*7c478bd9Sstevel@tonic-gate (((uint64_t)IRM_node) << 440*7c478bd9Sstevel@tonic-gate IEEE1394_ADDR_PHY_ID_SHIFT); 441*7c478bd9Sstevel@tonic-gate } else { 442*7c478bd9Sstevel@tonic-gate IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK | 443*7c478bd9Sstevel@tonic-gate IEEE1394_SCSR_CHANS_AVAIL_LO) | 444*7c478bd9Sstevel@tonic-gate (((uint64_t)IRM_node) << 445*7c478bd9Sstevel@tonic-gate IEEE1394_ADDR_PHY_ID_SHIFT); 446*7c478bd9Sstevel@tonic-gate } 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate cmd->cmd_addr = IRM_ID_addr; 449*7c478bd9Sstevel@tonic-gate cmd->bus_generation = generation; 450*7c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.data_value = T1394_DATA32(~channel_mask); 451*7c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.num_retries = num_retries; 452*7c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.lock_type = CMD1394_LOCK_BIT_AND; 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate ret = s1394_split_lock_req(hal, NULL, cmd); 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 457*7c478bd9Sstevel@tonic-gate if (cmd->cmd_result == CMD1394_CMDSUCCESS) { 458*7c478bd9Sstevel@tonic-gate *old_channels = T1394_DATA32( 459*7c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.old_value); 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate if ((~(*old_channels) & channel_mask) != 0) { 462*7c478bd9Sstevel@tonic-gate *result = CMD1394_ERETRIES_EXCEEDED; 463*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_channel_alloc_error, 464*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", 465*7c478bd9Sstevel@tonic-gate tnf_string, msg, 466*7c478bd9Sstevel@tonic-gate "Channels already taken"); 467*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG( 468*7c478bd9Sstevel@tonic-gate s1394_channel_alloc_exit, 469*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 470*7c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 471*7c478bd9Sstevel@tonic-gate } else { 472*7c478bd9Sstevel@tonic-gate *result = cmd->cmd_result; 473*7c478bd9Sstevel@tonic-gate } 474*7c478bd9Sstevel@tonic-gate 475*7c478bd9Sstevel@tonic-gate /* Need to free the command */ 476*7c478bd9Sstevel@tonic-gate (void) s1394_free_cmd(hal, &cmd); 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit, 479*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 480*7c478bd9Sstevel@tonic-gate return (ret); 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate } else { 483*7c478bd9Sstevel@tonic-gate *result = cmd->cmd_result; 484*7c478bd9Sstevel@tonic-gate /* Need to free the command */ 485*7c478bd9Sstevel@tonic-gate (void) s1394_free_cmd(hal, &cmd); 486*7c478bd9Sstevel@tonic-gate 487*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_channel_alloc_error, 488*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, 489*7c478bd9Sstevel@tonic-gate msg, "Error allocating isoch channel"); 490*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit, 491*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 492*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 493*7c478bd9Sstevel@tonic-gate } 494*7c478bd9Sstevel@tonic-gate } else { 495*7c478bd9Sstevel@tonic-gate *result = cmd->cmd_result; 496*7c478bd9Sstevel@tonic-gate 497*7c478bd9Sstevel@tonic-gate /* Need to free the command */ 498*7c478bd9Sstevel@tonic-gate (void) s1394_free_cmd(hal, &cmd); 499*7c478bd9Sstevel@tonic-gate 500*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_channel_alloc_error, 501*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg, 502*7c478bd9Sstevel@tonic-gate "Error allocating isoch channel"); 503*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit, 504*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 505*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate } 508*7c478bd9Sstevel@tonic-gate } 509*7c478bd9Sstevel@tonic-gate 510*7c478bd9Sstevel@tonic-gate /* 511*7c478bd9Sstevel@tonic-gate * s1394_channel_free() 512*7c478bd9Sstevel@tonic-gate * is used to free up an isochronous channel. A channel mask and 513*7c478bd9Sstevel@tonic-gate * generation are passed. A request is sent to whichever node is the 514*7c478bd9Sstevel@tonic-gate * IRM for the appropriate channels. If it fails because of a bus 515*7c478bd9Sstevel@tonic-gate * reset it can be retried. If it fails for another reason the 516*7c478bd9Sstevel@tonic-gate * channel(s) may already be free or there may be no IRM. 517*7c478bd9Sstevel@tonic-gate */ 518*7c478bd9Sstevel@tonic-gate int 519*7c478bd9Sstevel@tonic-gate s1394_channel_free(s1394_hal_t *hal, uint32_t channel_mask, uint_t generation, 520*7c478bd9Sstevel@tonic-gate uint_t flags, uint32_t *old_channels, int *result) 521*7c478bd9Sstevel@tonic-gate { 522*7c478bd9Sstevel@tonic-gate cmd1394_cmd_t *cmd; 523*7c478bd9Sstevel@tonic-gate uint64_t IRM_ID_addr; 524*7c478bd9Sstevel@tonic-gate uint32_t compare; 525*7c478bd9Sstevel@tonic-gate uint32_t swap; 526*7c478bd9Sstevel@tonic-gate uint32_t old_value; 527*7c478bd9Sstevel@tonic-gate uint_t hal_node_num; 528*7c478bd9Sstevel@tonic-gate uint_t IRM_node; 529*7c478bd9Sstevel@tonic-gate uint_t offset; 530*7c478bd9Sstevel@tonic-gate int ret; 531*7c478bd9Sstevel@tonic-gate int i; 532*7c478bd9Sstevel@tonic-gate int num_retries = S1394_ISOCH_ALLOC_RETRIES; 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_free_enter, 535*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate /* Lock the topology tree */ 538*7c478bd9Sstevel@tonic-gate mutex_enter(&hal->topology_tree_mutex); 539*7c478bd9Sstevel@tonic-gate 540*7c478bd9Sstevel@tonic-gate hal_node_num = IEEE1394_NODE_NUM(hal->node_id); 541*7c478bd9Sstevel@tonic-gate IRM_node = hal->IRM_node; 542*7c478bd9Sstevel@tonic-gate 543*7c478bd9Sstevel@tonic-gate /* Unlock the topology tree */ 544*7c478bd9Sstevel@tonic-gate mutex_exit(&hal->topology_tree_mutex); 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate /* Make sure there is a valid IRM on the bus */ 547*7c478bd9Sstevel@tonic-gate if (IRM_node == -1) { 548*7c478bd9Sstevel@tonic-gate *result = CMD1394_ERETRIES_EXCEEDED; 549*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_channel_free_error, 550*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg, 551*7c478bd9Sstevel@tonic-gate "No IRM on the 1394 bus"); 552*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_free_exit, 553*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 554*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 555*7c478bd9Sstevel@tonic-gate } 556*7c478bd9Sstevel@tonic-gate 557*7c478bd9Sstevel@tonic-gate if (flags & S1394_CHANNEL_ALLOC_HI) { 558*7c478bd9Sstevel@tonic-gate offset = 559*7c478bd9Sstevel@tonic-gate (IEEE1394_SCSR_CHANS_AVAIL_HI & IEEE1394_CSR_OFFSET_MASK); 560*7c478bd9Sstevel@tonic-gate } else { 561*7c478bd9Sstevel@tonic-gate offset = 562*7c478bd9Sstevel@tonic-gate (IEEE1394_SCSR_CHANS_AVAIL_LO & IEEE1394_CSR_OFFSET_MASK); 563*7c478bd9Sstevel@tonic-gate } 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate /* Send compare-swap to CHANNELS_AVAILABLE */ 566*7c478bd9Sstevel@tonic-gate /* register on the Isoch Rsrc Mgr */ 567*7c478bd9Sstevel@tonic-gate if (hal->IRM_node == hal_node_num) { 568*7c478bd9Sstevel@tonic-gate /* Local */ 569*7c478bd9Sstevel@tonic-gate i = num_retries; 570*7c478bd9Sstevel@tonic-gate do { 571*7c478bd9Sstevel@tonic-gate (void) HAL_CALL(hal).csr_read(hal->halinfo.hal_private, 572*7c478bd9Sstevel@tonic-gate offset, &old_value); 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate /* Check that the generation has not changed */ 575*7c478bd9Sstevel@tonic-gate if (generation != hal->generation_count) { 576*7c478bd9Sstevel@tonic-gate *result = CMD1394_EBUSRESET; 577*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_free_exit, 578*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 579*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 580*7c478bd9Sstevel@tonic-gate } 581*7c478bd9Sstevel@tonic-gate 582*7c478bd9Sstevel@tonic-gate compare = old_value; 583*7c478bd9Sstevel@tonic-gate swap = old_value | channel_mask; 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate ret = HAL_CALL(hal).csr_cswap32( 586*7c478bd9Sstevel@tonic-gate hal->halinfo.hal_private, hal->generation_count, 587*7c478bd9Sstevel@tonic-gate offset, compare, swap, &old_value); 588*7c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 589*7c478bd9Sstevel@tonic-gate *result = CMD1394_EBUSRESET; 590*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_channel_free_error, 591*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, 592*7c478bd9Sstevel@tonic-gate msg, "Error in cswap32"); 593*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_free_exit, 594*7c478bd9Sstevel@tonic-gate "stacktrace 1394 s1394", ""); 595*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 596*7c478bd9Sstevel@tonic-gate } 597*7c478bd9Sstevel@tonic-gate 598*7c478bd9Sstevel@tonic-gate if (old_value == compare) { 599*7c478bd9Sstevel@tonic-gate *result = CMD1394_CMDSUCCESS; 600*7c478bd9Sstevel@tonic-gate *old_channels = old_value; 601*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_free_exit, 602*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 603*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 604*7c478bd9Sstevel@tonic-gate } 605*7c478bd9Sstevel@tonic-gate } while (i--); 606*7c478bd9Sstevel@tonic-gate 607*7c478bd9Sstevel@tonic-gate *result = CMD1394_ERETRIES_EXCEEDED; 608*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_channel_free_error, 609*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg, 610*7c478bd9Sstevel@tonic-gate "Retries exceeded"); 611*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_free_exit, 612*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 613*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate } else { 616*7c478bd9Sstevel@tonic-gate /* Remote */ 617*7c478bd9Sstevel@tonic-gate if (s1394_alloc_cmd(hal, 0, &cmd) != DDI_SUCCESS) { 618*7c478bd9Sstevel@tonic-gate *result = CMD1394_EUNKNOWN_ERROR; 619*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_channel_free_error, 620*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg, 621*7c478bd9Sstevel@tonic-gate "Unable to allocate command"); 622*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_free_exit, 623*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 624*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 625*7c478bd9Sstevel@tonic-gate } 626*7c478bd9Sstevel@tonic-gate 627*7c478bd9Sstevel@tonic-gate cmd->cmd_options = (CMD1394_CANCEL_ON_BUS_RESET | 628*7c478bd9Sstevel@tonic-gate CMD1394_OVERRIDE_ADDR | CMD1394_BLOCKING); 629*7c478bd9Sstevel@tonic-gate cmd->cmd_type = CMD1394_ASYNCH_LOCK_32; 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate if (flags & S1394_CHANNEL_ALLOC_HI) { 632*7c478bd9Sstevel@tonic-gate IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK | 633*7c478bd9Sstevel@tonic-gate IEEE1394_SCSR_CHANS_AVAIL_HI) | 634*7c478bd9Sstevel@tonic-gate (((uint64_t)IRM_node) << 635*7c478bd9Sstevel@tonic-gate IEEE1394_ADDR_PHY_ID_SHIFT); 636*7c478bd9Sstevel@tonic-gate } else { 637*7c478bd9Sstevel@tonic-gate IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK | 638*7c478bd9Sstevel@tonic-gate IEEE1394_SCSR_CHANS_AVAIL_LO) | 639*7c478bd9Sstevel@tonic-gate (((uint64_t)IRM_node) << 640*7c478bd9Sstevel@tonic-gate IEEE1394_ADDR_PHY_ID_SHIFT); 641*7c478bd9Sstevel@tonic-gate } 642*7c478bd9Sstevel@tonic-gate 643*7c478bd9Sstevel@tonic-gate cmd->cmd_addr = IRM_ID_addr; 644*7c478bd9Sstevel@tonic-gate cmd->bus_generation = generation; 645*7c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.data_value = T1394_DATA32(channel_mask); 646*7c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.num_retries = num_retries; 647*7c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.lock_type = CMD1394_LOCK_BIT_OR; 648*7c478bd9Sstevel@tonic-gate 649*7c478bd9Sstevel@tonic-gate ret = s1394_split_lock_req(hal, NULL, cmd); 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 652*7c478bd9Sstevel@tonic-gate if (cmd->cmd_result == CMD1394_CMDSUCCESS) { 653*7c478bd9Sstevel@tonic-gate 654*7c478bd9Sstevel@tonic-gate *old_channels = T1394_DATA32( 655*7c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.old_value); 656*7c478bd9Sstevel@tonic-gate *result = cmd->cmd_result; 657*7c478bd9Sstevel@tonic-gate 658*7c478bd9Sstevel@tonic-gate /* Need to free the command */ 659*7c478bd9Sstevel@tonic-gate (void) s1394_free_cmd(hal, &cmd); 660*7c478bd9Sstevel@tonic-gate 661*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_free_exit, 662*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 663*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate } else { 666*7c478bd9Sstevel@tonic-gate *result = cmd->cmd_result; 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate /* Need to free the command */ 669*7c478bd9Sstevel@tonic-gate (void) s1394_free_cmd(hal, &cmd); 670*7c478bd9Sstevel@tonic-gate 671*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_channel_free_error, 672*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, 673*7c478bd9Sstevel@tonic-gate msg, "Error freeing isoch channel"); 674*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_free_exit, 675*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 676*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 677*7c478bd9Sstevel@tonic-gate } 678*7c478bd9Sstevel@tonic-gate } else { 679*7c478bd9Sstevel@tonic-gate *result = cmd->cmd_result; 680*7c478bd9Sstevel@tonic-gate /* Need to free the command */ 681*7c478bd9Sstevel@tonic-gate (void) s1394_free_cmd(hal, &cmd); 682*7c478bd9Sstevel@tonic-gate 683*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_channel_free_error, 684*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg, 685*7c478bd9Sstevel@tonic-gate "Error freeing isoch channel"); 686*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_channel_free_exit, 687*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 688*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 689*7c478bd9Sstevel@tonic-gate } 690*7c478bd9Sstevel@tonic-gate } 691*7c478bd9Sstevel@tonic-gate } 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate /* 694*7c478bd9Sstevel@tonic-gate * s1394_bandwidth_alloc() 695*7c478bd9Sstevel@tonic-gate * is used to allocate isochronous bandwidth. A number of bandwidth 696*7c478bd9Sstevel@tonic-gate * allocation units and a generation are passed. The request is sent 697*7c478bd9Sstevel@tonic-gate * to whichever node is the IRM for this amount of bandwidth. If it 698*7c478bd9Sstevel@tonic-gate * fails because of a bus reset it can be retried. If it fails for 699*7c478bd9Sstevel@tonic-gate * another reason the bandwidth may not be available or there may be 700*7c478bd9Sstevel@tonic-gate * no IRM. 701*7c478bd9Sstevel@tonic-gate */ 702*7c478bd9Sstevel@tonic-gate int 703*7c478bd9Sstevel@tonic-gate s1394_bandwidth_alloc(s1394_hal_t *hal, uint32_t bw_alloc_units, 704*7c478bd9Sstevel@tonic-gate uint_t generation, int *result) 705*7c478bd9Sstevel@tonic-gate { 706*7c478bd9Sstevel@tonic-gate cmd1394_cmd_t *cmd; 707*7c478bd9Sstevel@tonic-gate uint64_t IRM_ID_addr; 708*7c478bd9Sstevel@tonic-gate uint32_t compare; 709*7c478bd9Sstevel@tonic-gate uint32_t swap; 710*7c478bd9Sstevel@tonic-gate uint32_t old_value; 711*7c478bd9Sstevel@tonic-gate uint_t hal_node_num; 712*7c478bd9Sstevel@tonic-gate uint_t IRM_node; 713*7c478bd9Sstevel@tonic-gate int temp_value; 714*7c478bd9Sstevel@tonic-gate int ret; 715*7c478bd9Sstevel@tonic-gate int i; 716*7c478bd9Sstevel@tonic-gate int num_retries = S1394_ISOCH_ALLOC_RETRIES; 717*7c478bd9Sstevel@tonic-gate 718*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_enter, 719*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate /* Lock the topology tree */ 722*7c478bd9Sstevel@tonic-gate mutex_enter(&hal->topology_tree_mutex); 723*7c478bd9Sstevel@tonic-gate 724*7c478bd9Sstevel@tonic-gate hal_node_num = IEEE1394_NODE_NUM(hal->node_id); 725*7c478bd9Sstevel@tonic-gate IRM_node = hal->IRM_node; 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate /* Unlock the topology tree */ 728*7c478bd9Sstevel@tonic-gate mutex_exit(&hal->topology_tree_mutex); 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate /* Make sure there is a valid IRM on the bus */ 731*7c478bd9Sstevel@tonic-gate if (IRM_node == -1) { 732*7c478bd9Sstevel@tonic-gate *result = CMD1394_ERETRIES_EXCEEDED; 733*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_bandwidth_alloc_error, 734*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg, 735*7c478bd9Sstevel@tonic-gate "No IRM on the 1394 bus"); 736*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit, 737*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 738*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 739*7c478bd9Sstevel@tonic-gate } 740*7c478bd9Sstevel@tonic-gate 741*7c478bd9Sstevel@tonic-gate /* Send compare-swap to BANDWIDTH_AVAILABLE */ 742*7c478bd9Sstevel@tonic-gate /* register on the Isoch Rsrc Mgr */ 743*7c478bd9Sstevel@tonic-gate if (IRM_node == hal_node_num) { 744*7c478bd9Sstevel@tonic-gate /* Local */ 745*7c478bd9Sstevel@tonic-gate i = num_retries; 746*7c478bd9Sstevel@tonic-gate do { 747*7c478bd9Sstevel@tonic-gate (void) HAL_CALL(hal).csr_read(hal->halinfo.hal_private, 748*7c478bd9Sstevel@tonic-gate (IEEE1394_SCSR_BANDWIDTH_AVAIL & 749*7c478bd9Sstevel@tonic-gate IEEE1394_CSR_OFFSET_MASK), &old_value); 750*7c478bd9Sstevel@tonic-gate /* 751*7c478bd9Sstevel@tonic-gate * Check that the generation has not changed - 752*7c478bd9Sstevel@tonic-gate * don't need the lock (read-only) 753*7c478bd9Sstevel@tonic-gate */ 754*7c478bd9Sstevel@tonic-gate if (generation != hal->generation_count) { 755*7c478bd9Sstevel@tonic-gate *result = CMD1394_EBUSRESET; 756*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit, 757*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 758*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate temp_value = (old_value - bw_alloc_units); 762*7c478bd9Sstevel@tonic-gate if ((old_value >= bw_alloc_units) && 763*7c478bd9Sstevel@tonic-gate (temp_value >= IEEE1394_BANDWIDTH_MIN)) { 764*7c478bd9Sstevel@tonic-gate compare = old_value; 765*7c478bd9Sstevel@tonic-gate swap = (uint32_t)temp_value; 766*7c478bd9Sstevel@tonic-gate } else { 767*7c478bd9Sstevel@tonic-gate *result = CMD1394_ERETRIES_EXCEEDED; 768*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_bandwidth_alloc_error, 769*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, 770*7c478bd9Sstevel@tonic-gate msg, "Retries exceeded"); 771*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit, 772*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 773*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 774*7c478bd9Sstevel@tonic-gate } 775*7c478bd9Sstevel@tonic-gate 776*7c478bd9Sstevel@tonic-gate ret = HAL_CALL(hal).csr_cswap32( 777*7c478bd9Sstevel@tonic-gate hal->halinfo.hal_private, generation, 778*7c478bd9Sstevel@tonic-gate (IEEE1394_SCSR_BANDWIDTH_AVAIL & 779*7c478bd9Sstevel@tonic-gate IEEE1394_CSR_OFFSET_MASK), compare, swap, 780*7c478bd9Sstevel@tonic-gate &old_value); 781*7c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 782*7c478bd9Sstevel@tonic-gate *result = CMD1394_EBUSRESET; 783*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_bandwidth_alloc_error, 784*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, 785*7c478bd9Sstevel@tonic-gate msg, "Error in cswap32"); 786*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit, 787*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 788*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 789*7c478bd9Sstevel@tonic-gate } 790*7c478bd9Sstevel@tonic-gate 791*7c478bd9Sstevel@tonic-gate if (old_value == compare) { 792*7c478bd9Sstevel@tonic-gate *result = CMD1394_CMDSUCCESS; 793*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit, 794*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 795*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 796*7c478bd9Sstevel@tonic-gate } 797*7c478bd9Sstevel@tonic-gate } while (i--); 798*7c478bd9Sstevel@tonic-gate 799*7c478bd9Sstevel@tonic-gate *result = CMD1394_ERETRIES_EXCEEDED; 800*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_bandwidth_alloc_error, 801*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg, 802*7c478bd9Sstevel@tonic-gate "Too many retries"); 803*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit, 804*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 805*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 806*7c478bd9Sstevel@tonic-gate 807*7c478bd9Sstevel@tonic-gate } else { 808*7c478bd9Sstevel@tonic-gate /* Remote */ 809*7c478bd9Sstevel@tonic-gate if (s1394_alloc_cmd(hal, 0, &cmd) != DDI_SUCCESS) { 810*7c478bd9Sstevel@tonic-gate *result = CMD1394_EUNKNOWN_ERROR; 811*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_bandwidth_alloc_error, 812*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg, 813*7c478bd9Sstevel@tonic-gate "Unable to allocate command"); 814*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit, 815*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 816*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 817*7c478bd9Sstevel@tonic-gate } 818*7c478bd9Sstevel@tonic-gate 819*7c478bd9Sstevel@tonic-gate cmd->cmd_options = (CMD1394_CANCEL_ON_BUS_RESET | 820*7c478bd9Sstevel@tonic-gate CMD1394_OVERRIDE_ADDR | CMD1394_BLOCKING); 821*7c478bd9Sstevel@tonic-gate cmd->cmd_type = CMD1394_ASYNCH_LOCK_32; 822*7c478bd9Sstevel@tonic-gate IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK | 823*7c478bd9Sstevel@tonic-gate IEEE1394_SCSR_BANDWIDTH_AVAIL) | (((uint64_t)IRM_node) << 824*7c478bd9Sstevel@tonic-gate IEEE1394_ADDR_PHY_ID_SHIFT); 825*7c478bd9Sstevel@tonic-gate cmd->cmd_addr = IRM_ID_addr; 826*7c478bd9Sstevel@tonic-gate cmd->bus_generation = generation; 827*7c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.arg_value = 0; 828*7c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.data_value = bw_alloc_units; 829*7c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.num_retries = num_retries; 830*7c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.lock_type = CMD1394_LOCK_THRESH_SUBTRACT; 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate ret = s1394_split_lock_req(hal, NULL, cmd); 833*7c478bd9Sstevel@tonic-gate 834*7c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 835*7c478bd9Sstevel@tonic-gate if (cmd->cmd_result == CMD1394_CMDSUCCESS) { 836*7c478bd9Sstevel@tonic-gate *result = cmd->cmd_result; 837*7c478bd9Sstevel@tonic-gate /* Need to free the command */ 838*7c478bd9Sstevel@tonic-gate (void) s1394_free_cmd(hal, &cmd); 839*7c478bd9Sstevel@tonic-gate 840*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit, 841*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 842*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 843*7c478bd9Sstevel@tonic-gate 844*7c478bd9Sstevel@tonic-gate } else { 845*7c478bd9Sstevel@tonic-gate *result = cmd->cmd_result; 846*7c478bd9Sstevel@tonic-gate /* Need to free the command */ 847*7c478bd9Sstevel@tonic-gate (void) s1394_free_cmd(hal, &cmd); 848*7c478bd9Sstevel@tonic-gate 849*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_bandwidth_alloc_error, 850*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, 851*7c478bd9Sstevel@tonic-gate msg, "Error allocating isoch bandwidth"); 852*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit, 853*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 854*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 855*7c478bd9Sstevel@tonic-gate } 856*7c478bd9Sstevel@tonic-gate } else { 857*7c478bd9Sstevel@tonic-gate *result = cmd->cmd_result; 858*7c478bd9Sstevel@tonic-gate /* Need to free the command */ 859*7c478bd9Sstevel@tonic-gate (void) s1394_free_cmd(hal, &cmd); 860*7c478bd9Sstevel@tonic-gate 861*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_bandwidth_alloc_error, 862*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg, 863*7c478bd9Sstevel@tonic-gate "Error allocating isoch bandwidth"); 864*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit, 865*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 866*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 867*7c478bd9Sstevel@tonic-gate } 868*7c478bd9Sstevel@tonic-gate } 869*7c478bd9Sstevel@tonic-gate } 870*7c478bd9Sstevel@tonic-gate 871*7c478bd9Sstevel@tonic-gate /* 872*7c478bd9Sstevel@tonic-gate * s1394_compute_bw_alloc_units() 873*7c478bd9Sstevel@tonic-gate * is used to compute the number of "bandwidth allocation units" that 874*7c478bd9Sstevel@tonic-gate * are necessary for a given bit rate. It calculates the overhead 875*7c478bd9Sstevel@tonic-gate * necessary for isoch packet headers, bus arbitration, etc. (See 876*7c478bd9Sstevel@tonic-gate * IEEE 1394-1995 Section 8.3.2.3.7 for an explanation of what a 877*7c478bd9Sstevel@tonic-gate * "bandwidth allocation unit" is. 878*7c478bd9Sstevel@tonic-gate */ 879*7c478bd9Sstevel@tonic-gate uint_t 880*7c478bd9Sstevel@tonic-gate s1394_compute_bw_alloc_units(s1394_hal_t *hal, uint_t bandwidth, uint_t speed) 881*7c478bd9Sstevel@tonic-gate { 882*7c478bd9Sstevel@tonic-gate uint_t total_quads; 883*7c478bd9Sstevel@tonic-gate uint_t speed_factor; 884*7c478bd9Sstevel@tonic-gate uint_t bau; 885*7c478bd9Sstevel@tonic-gate int max_hops; 886*7c478bd9Sstevel@tonic-gate 887*7c478bd9Sstevel@tonic-gate /* Lock the topology tree */ 888*7c478bd9Sstevel@tonic-gate mutex_enter(&hal->topology_tree_mutex); 889*7c478bd9Sstevel@tonic-gate 890*7c478bd9Sstevel@tonic-gate /* Calculate the 1394 bus diameter */ 891*7c478bd9Sstevel@tonic-gate max_hops = s1394_topology_tree_calculate_diameter(hal); 892*7c478bd9Sstevel@tonic-gate 893*7c478bd9Sstevel@tonic-gate /* Unlock the topology tree */ 894*7c478bd9Sstevel@tonic-gate mutex_exit(&hal->topology_tree_mutex); 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate /* Calculate the total bandwidth (including overhead) */ 897*7c478bd9Sstevel@tonic-gate total_quads = (bandwidth >> 2) + IEEE1394_ISOCH_HDR_QUAD_SZ; 898*7c478bd9Sstevel@tonic-gate switch (speed) { 899*7c478bd9Sstevel@tonic-gate case IEEE1394_S400: 900*7c478bd9Sstevel@tonic-gate speed_factor = ISOCH_SPEED_FACTOR_S400; 901*7c478bd9Sstevel@tonic-gate break; 902*7c478bd9Sstevel@tonic-gate case IEEE1394_S200: 903*7c478bd9Sstevel@tonic-gate speed_factor = ISOCH_SPEED_FACTOR_S200; 904*7c478bd9Sstevel@tonic-gate break; 905*7c478bd9Sstevel@tonic-gate case IEEE1394_S100: 906*7c478bd9Sstevel@tonic-gate speed_factor = ISOCH_SPEED_FACTOR_S100; 907*7c478bd9Sstevel@tonic-gate break; 908*7c478bd9Sstevel@tonic-gate } 909*7c478bd9Sstevel@tonic-gate /* See IEC 61883-1 pp. 26-29 for this formula */ 910*7c478bd9Sstevel@tonic-gate bau = (32 * max_hops) + (total_quads * speed_factor); 911*7c478bd9Sstevel@tonic-gate 912*7c478bd9Sstevel@tonic-gate return (bau); 913*7c478bd9Sstevel@tonic-gate } 914*7c478bd9Sstevel@tonic-gate 915*7c478bd9Sstevel@tonic-gate /* 916*7c478bd9Sstevel@tonic-gate * s1394_bandwidth_free() 917*7c478bd9Sstevel@tonic-gate * is used to free up isochronous bandwidth. A number of bandwidth 918*7c478bd9Sstevel@tonic-gate * allocation units and a generation are passed. The request is sent 919*7c478bd9Sstevel@tonic-gate * to whichever node is the IRM for this amount of bandwidth. If it 920*7c478bd9Sstevel@tonic-gate * fails because of a bus reset it can be retried. If it fails for 921*7c478bd9Sstevel@tonic-gate * another reason the bandwidth may already be freed or there may 922*7c478bd9Sstevel@tonic-gate * be no IRM. 923*7c478bd9Sstevel@tonic-gate */ 924*7c478bd9Sstevel@tonic-gate int 925*7c478bd9Sstevel@tonic-gate s1394_bandwidth_free(s1394_hal_t *hal, uint32_t bw_alloc_units, 926*7c478bd9Sstevel@tonic-gate uint_t generation, int *result) 927*7c478bd9Sstevel@tonic-gate { 928*7c478bd9Sstevel@tonic-gate cmd1394_cmd_t *cmd; 929*7c478bd9Sstevel@tonic-gate uint64_t IRM_ID_addr; 930*7c478bd9Sstevel@tonic-gate uint32_t compare; 931*7c478bd9Sstevel@tonic-gate uint32_t swap; 932*7c478bd9Sstevel@tonic-gate uint32_t old_value; 933*7c478bd9Sstevel@tonic-gate uint32_t temp_value; 934*7c478bd9Sstevel@tonic-gate uint_t hal_node_num; 935*7c478bd9Sstevel@tonic-gate uint_t IRM_node; 936*7c478bd9Sstevel@tonic-gate int ret; 937*7c478bd9Sstevel@tonic-gate int i; 938*7c478bd9Sstevel@tonic-gate int num_retries = S1394_ISOCH_ALLOC_RETRIES; 939*7c478bd9Sstevel@tonic-gate 940*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_free_enter, 941*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate /* Lock the topology tree */ 944*7c478bd9Sstevel@tonic-gate mutex_enter(&hal->topology_tree_mutex); 945*7c478bd9Sstevel@tonic-gate 946*7c478bd9Sstevel@tonic-gate hal_node_num = IEEE1394_NODE_NUM(hal->node_id); 947*7c478bd9Sstevel@tonic-gate IRM_node = hal->IRM_node; 948*7c478bd9Sstevel@tonic-gate 949*7c478bd9Sstevel@tonic-gate /* Unlock the topology tree */ 950*7c478bd9Sstevel@tonic-gate mutex_exit(&hal->topology_tree_mutex); 951*7c478bd9Sstevel@tonic-gate 952*7c478bd9Sstevel@tonic-gate /* Make sure there is a valid IRM on the bus */ 953*7c478bd9Sstevel@tonic-gate if (IRM_node == -1) { 954*7c478bd9Sstevel@tonic-gate *result = CMD1394_ERETRIES_EXCEEDED; 955*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_bandwidth_free_error, 956*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg, 957*7c478bd9Sstevel@tonic-gate "No IRM on the 1394 bus"); 958*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit, 959*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 960*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 961*7c478bd9Sstevel@tonic-gate } 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate /* Send compare-swap to BANDWIDTH_AVAILABLE */ 964*7c478bd9Sstevel@tonic-gate /* register on the Isoch Rsrc Mgr */ 965*7c478bd9Sstevel@tonic-gate if (IRM_node == hal_node_num) { 966*7c478bd9Sstevel@tonic-gate i = num_retries; 967*7c478bd9Sstevel@tonic-gate do { 968*7c478bd9Sstevel@tonic-gate (void) HAL_CALL(hal).csr_read(hal->halinfo.hal_private, 969*7c478bd9Sstevel@tonic-gate (IEEE1394_SCSR_BANDWIDTH_AVAIL & 970*7c478bd9Sstevel@tonic-gate IEEE1394_CSR_OFFSET_MASK), &old_value); 971*7c478bd9Sstevel@tonic-gate 972*7c478bd9Sstevel@tonic-gate /* Check that the generation has not changed */ 973*7c478bd9Sstevel@tonic-gate if (generation != hal->generation_count) { 974*7c478bd9Sstevel@tonic-gate *result = CMD1394_EBUSRESET; 975*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit, 976*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 977*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 978*7c478bd9Sstevel@tonic-gate } 979*7c478bd9Sstevel@tonic-gate 980*7c478bd9Sstevel@tonic-gate temp_value = (old_value + bw_alloc_units); 981*7c478bd9Sstevel@tonic-gate if ((temp_value >= old_value) && 982*7c478bd9Sstevel@tonic-gate (temp_value <= IEEE1394_BANDWIDTH_MAX)) { 983*7c478bd9Sstevel@tonic-gate compare = old_value; 984*7c478bd9Sstevel@tonic-gate swap = temp_value; 985*7c478bd9Sstevel@tonic-gate } else { 986*7c478bd9Sstevel@tonic-gate *result = CMD1394_ERETRIES_EXCEEDED; 987*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_bandwidth_free_error, 988*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, 989*7c478bd9Sstevel@tonic-gate msg, "Too many retries"); 990*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit, 991*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 992*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 993*7c478bd9Sstevel@tonic-gate } 994*7c478bd9Sstevel@tonic-gate 995*7c478bd9Sstevel@tonic-gate ret = HAL_CALL(hal).csr_cswap32( 996*7c478bd9Sstevel@tonic-gate hal->halinfo.hal_private, generation, 997*7c478bd9Sstevel@tonic-gate (IEEE1394_SCSR_BANDWIDTH_AVAIL & 998*7c478bd9Sstevel@tonic-gate IEEE1394_CSR_OFFSET_MASK), compare, swap, 999*7c478bd9Sstevel@tonic-gate &old_value); 1000*7c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 1001*7c478bd9Sstevel@tonic-gate *result = CMD1394_EBUSRESET; 1002*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_bandwidth_free_error, 1003*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, 1004*7c478bd9Sstevel@tonic-gate msg, "Error in cswap32"); 1005*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit, 1006*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 1007*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1008*7c478bd9Sstevel@tonic-gate } 1009*7c478bd9Sstevel@tonic-gate 1010*7c478bd9Sstevel@tonic-gate if (old_value == compare) { 1011*7c478bd9Sstevel@tonic-gate *result = CMD1394_CMDSUCCESS; 1012*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit, 1013*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 1014*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1015*7c478bd9Sstevel@tonic-gate } 1016*7c478bd9Sstevel@tonic-gate } while (i--); 1017*7c478bd9Sstevel@tonic-gate 1018*7c478bd9Sstevel@tonic-gate *result = CMD1394_ERETRIES_EXCEEDED; 1019*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_bandwidth_free_error, 1020*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg, 1021*7c478bd9Sstevel@tonic-gate "Retries exceeded"); 1022*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit, 1023*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 1024*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1025*7c478bd9Sstevel@tonic-gate 1026*7c478bd9Sstevel@tonic-gate } else { 1027*7c478bd9Sstevel@tonic-gate /* Remote */ 1028*7c478bd9Sstevel@tonic-gate if (s1394_alloc_cmd(hal, 0, &cmd) != DDI_SUCCESS) { 1029*7c478bd9Sstevel@tonic-gate *result = CMD1394_EUNKNOWN_ERROR; 1030*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_bandwidth_free_error, 1031*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg, 1032*7c478bd9Sstevel@tonic-gate "Unable to allocate command"); 1033*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit, 1034*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 1035*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1036*7c478bd9Sstevel@tonic-gate } 1037*7c478bd9Sstevel@tonic-gate 1038*7c478bd9Sstevel@tonic-gate cmd->cmd_options = (CMD1394_CANCEL_ON_BUS_RESET | 1039*7c478bd9Sstevel@tonic-gate CMD1394_OVERRIDE_ADDR | CMD1394_BLOCKING); 1040*7c478bd9Sstevel@tonic-gate cmd->cmd_type = CMD1394_ASYNCH_LOCK_32; 1041*7c478bd9Sstevel@tonic-gate IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK | 1042*7c478bd9Sstevel@tonic-gate IEEE1394_SCSR_BANDWIDTH_AVAIL) | 1043*7c478bd9Sstevel@tonic-gate (((uint64_t)hal->IRM_node) << IEEE1394_ADDR_PHY_ID_SHIFT); 1044*7c478bd9Sstevel@tonic-gate cmd->cmd_addr = IRM_ID_addr; 1045*7c478bd9Sstevel@tonic-gate cmd->bus_generation = generation; 1046*7c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.arg_value = IEEE1394_BANDWIDTH_MAX; 1047*7c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.data_value = bw_alloc_units; 1048*7c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.num_retries = num_retries; 1049*7c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.lock_type = CMD1394_LOCK_THRESH_ADD; 1050*7c478bd9Sstevel@tonic-gate 1051*7c478bd9Sstevel@tonic-gate ret = s1394_split_lock_req(hal, NULL, cmd); 1052*7c478bd9Sstevel@tonic-gate 1053*7c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 1054*7c478bd9Sstevel@tonic-gate if (cmd->cmd_result == CMD1394_CMDSUCCESS) { 1055*7c478bd9Sstevel@tonic-gate *result = cmd->cmd_result; 1056*7c478bd9Sstevel@tonic-gate 1057*7c478bd9Sstevel@tonic-gate /* Need to free the command */ 1058*7c478bd9Sstevel@tonic-gate (void) s1394_free_cmd(hal, &cmd); 1059*7c478bd9Sstevel@tonic-gate 1060*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit, 1061*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 1062*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1063*7c478bd9Sstevel@tonic-gate 1064*7c478bd9Sstevel@tonic-gate } else { 1065*7c478bd9Sstevel@tonic-gate *result = cmd->cmd_result; 1066*7c478bd9Sstevel@tonic-gate /* Need to free the command */ 1067*7c478bd9Sstevel@tonic-gate (void) s1394_free_cmd(hal, &cmd); 1068*7c478bd9Sstevel@tonic-gate 1069*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_bandwidth_free_error, 1070*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, 1071*7c478bd9Sstevel@tonic-gate msg, "Error freeing isoch bandwidth"); 1072*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit, 1073*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 1074*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1075*7c478bd9Sstevel@tonic-gate } 1076*7c478bd9Sstevel@tonic-gate } else { 1077*7c478bd9Sstevel@tonic-gate *result = cmd->cmd_result; 1078*7c478bd9Sstevel@tonic-gate /* Need to free the command */ 1079*7c478bd9Sstevel@tonic-gate (void) s1394_free_cmd(hal, &cmd); 1080*7c478bd9Sstevel@tonic-gate 1081*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(s1394_bandwidth_free_error, 1082*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg, 1083*7c478bd9Sstevel@tonic-gate "Error freeing isoch bandwidth"); 1084*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit, 1085*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 1086*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1087*7c478bd9Sstevel@tonic-gate } 1088*7c478bd9Sstevel@tonic-gate } 1089*7c478bd9Sstevel@tonic-gate } 1090*7c478bd9Sstevel@tonic-gate 1091*7c478bd9Sstevel@tonic-gate /* 1092*7c478bd9Sstevel@tonic-gate * s1394_isoch_cec_list_insert() 1093*7c478bd9Sstevel@tonic-gate * is used to insert an Isoch CEC into a given HAL's list of Isoch CECs. 1094*7c478bd9Sstevel@tonic-gate */ 1095*7c478bd9Sstevel@tonic-gate void 1096*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_list_insert(s1394_hal_t *hal, s1394_isoch_cec_t *cec) 1097*7c478bd9Sstevel@tonic-gate { 1098*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_t *cec_temp; 1099*7c478bd9Sstevel@tonic-gate 1100*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_isoch_cec_list_insert_enter, 1101*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 1102*7c478bd9Sstevel@tonic-gate 1103*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&hal->isoch_cec_list_mutex)); 1104*7c478bd9Sstevel@tonic-gate 1105*7c478bd9Sstevel@tonic-gate /* Is the Isoch CEC list empty? */ 1106*7c478bd9Sstevel@tonic-gate if ((hal->isoch_cec_list_head == NULL) && 1107*7c478bd9Sstevel@tonic-gate (hal->isoch_cec_list_tail == NULL)) { 1108*7c478bd9Sstevel@tonic-gate 1109*7c478bd9Sstevel@tonic-gate hal->isoch_cec_list_head = cec; 1110*7c478bd9Sstevel@tonic-gate hal->isoch_cec_list_tail = cec; 1111*7c478bd9Sstevel@tonic-gate 1112*7c478bd9Sstevel@tonic-gate cec->cec_next = NULL; 1113*7c478bd9Sstevel@tonic-gate cec->cec_prev = NULL; 1114*7c478bd9Sstevel@tonic-gate 1115*7c478bd9Sstevel@tonic-gate } else { 1116*7c478bd9Sstevel@tonic-gate cec->cec_next = hal->isoch_cec_list_head; 1117*7c478bd9Sstevel@tonic-gate cec->cec_prev = NULL; 1118*7c478bd9Sstevel@tonic-gate cec_temp = hal->isoch_cec_list_head; 1119*7c478bd9Sstevel@tonic-gate cec_temp->cec_prev = cec; 1120*7c478bd9Sstevel@tonic-gate 1121*7c478bd9Sstevel@tonic-gate hal->isoch_cec_list_head = cec; 1122*7c478bd9Sstevel@tonic-gate } 1123*7c478bd9Sstevel@tonic-gate 1124*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_isoch_cec_list_insert_exit, 1125*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 1126*7c478bd9Sstevel@tonic-gate } 1127*7c478bd9Sstevel@tonic-gate 1128*7c478bd9Sstevel@tonic-gate /* 1129*7c478bd9Sstevel@tonic-gate * s1394_isoch_cec_list_remove() 1130*7c478bd9Sstevel@tonic-gate * is used to remove an Isoch CEC from a given HAL's list of Isoch CECs. 1131*7c478bd9Sstevel@tonic-gate */ 1132*7c478bd9Sstevel@tonic-gate void 1133*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_list_remove(s1394_hal_t *hal, s1394_isoch_cec_t *cec) 1134*7c478bd9Sstevel@tonic-gate { 1135*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_t *prev_cec; 1136*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_t *next_cec; 1137*7c478bd9Sstevel@tonic-gate 1138*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_isoch_cec_list_remove_enter, 1139*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 1140*7c478bd9Sstevel@tonic-gate 1141*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&hal->isoch_cec_list_mutex)); 1142*7c478bd9Sstevel@tonic-gate 1143*7c478bd9Sstevel@tonic-gate prev_cec = cec->cec_prev; 1144*7c478bd9Sstevel@tonic-gate next_cec = cec->cec_next; 1145*7c478bd9Sstevel@tonic-gate cec->cec_prev = NULL; 1146*7c478bd9Sstevel@tonic-gate cec->cec_next = NULL; 1147*7c478bd9Sstevel@tonic-gate 1148*7c478bd9Sstevel@tonic-gate if (prev_cec != NULL) { 1149*7c478bd9Sstevel@tonic-gate prev_cec->cec_next = next_cec; 1150*7c478bd9Sstevel@tonic-gate 1151*7c478bd9Sstevel@tonic-gate } else { 1152*7c478bd9Sstevel@tonic-gate if (hal->isoch_cec_list_head == cec) 1153*7c478bd9Sstevel@tonic-gate hal->isoch_cec_list_head = next_cec; 1154*7c478bd9Sstevel@tonic-gate } 1155*7c478bd9Sstevel@tonic-gate 1156*7c478bd9Sstevel@tonic-gate if (next_cec != NULL) { 1157*7c478bd9Sstevel@tonic-gate next_cec->cec_prev = prev_cec; 1158*7c478bd9Sstevel@tonic-gate 1159*7c478bd9Sstevel@tonic-gate } else { 1160*7c478bd9Sstevel@tonic-gate if (hal->isoch_cec_list_tail == cec) 1161*7c478bd9Sstevel@tonic-gate hal->isoch_cec_list_tail = prev_cec; 1162*7c478bd9Sstevel@tonic-gate } 1163*7c478bd9Sstevel@tonic-gate 1164*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_isoch_cec_list_remove_exit, 1165*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 1166*7c478bd9Sstevel@tonic-gate } 1167*7c478bd9Sstevel@tonic-gate 1168*7c478bd9Sstevel@tonic-gate /* 1169*7c478bd9Sstevel@tonic-gate * s1394_isoch_cec_member_list_insert() 1170*7c478bd9Sstevel@tonic-gate * is used to insert a new member (target) into the list of members for 1171*7c478bd9Sstevel@tonic-gate * a given Isoch CEC. 1172*7c478bd9Sstevel@tonic-gate */ 1173*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1174*7c478bd9Sstevel@tonic-gate void 1175*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_member_list_insert(s1394_hal_t *hal, s1394_isoch_cec_t *cec, 1176*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_member_t *member) 1177*7c478bd9Sstevel@tonic-gate { 1178*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_member_t *member_temp; 1179*7c478bd9Sstevel@tonic-gate 1180*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_isoch_cec_member_list_insert_enter, 1181*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 1182*7c478bd9Sstevel@tonic-gate 1183*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cec->isoch_cec_mutex)); 1184*7c478bd9Sstevel@tonic-gate 1185*7c478bd9Sstevel@tonic-gate /* Is the Isoch CEC member list empty? */ 1186*7c478bd9Sstevel@tonic-gate if ((cec->cec_member_list_head == NULL) && 1187*7c478bd9Sstevel@tonic-gate (cec->cec_member_list_tail == NULL)) { 1188*7c478bd9Sstevel@tonic-gate 1189*7c478bd9Sstevel@tonic-gate cec->cec_member_list_head = member; 1190*7c478bd9Sstevel@tonic-gate cec->cec_member_list_tail = member; 1191*7c478bd9Sstevel@tonic-gate member->cec_mem_next = NULL; 1192*7c478bd9Sstevel@tonic-gate member->cec_mem_prev = NULL; 1193*7c478bd9Sstevel@tonic-gate 1194*7c478bd9Sstevel@tonic-gate } else if (member->cec_mem_options & T1394_TALKER) { 1195*7c478bd9Sstevel@tonic-gate /* Put talker at the head of the list */ 1196*7c478bd9Sstevel@tonic-gate member->cec_mem_next = cec->cec_member_list_head; 1197*7c478bd9Sstevel@tonic-gate member->cec_mem_prev = NULL; 1198*7c478bd9Sstevel@tonic-gate member_temp = cec->cec_member_list_head; 1199*7c478bd9Sstevel@tonic-gate member_temp->cec_mem_prev = member; 1200*7c478bd9Sstevel@tonic-gate cec->cec_member_list_head = member; 1201*7c478bd9Sstevel@tonic-gate 1202*7c478bd9Sstevel@tonic-gate } else { 1203*7c478bd9Sstevel@tonic-gate /* Put listeners at the tail of the list */ 1204*7c478bd9Sstevel@tonic-gate member->cec_mem_prev = cec->cec_member_list_tail; 1205*7c478bd9Sstevel@tonic-gate member->cec_mem_next = NULL; 1206*7c478bd9Sstevel@tonic-gate member_temp = cec->cec_member_list_tail; 1207*7c478bd9Sstevel@tonic-gate member_temp->cec_mem_next = member; 1208*7c478bd9Sstevel@tonic-gate cec->cec_member_list_tail = member; 1209*7c478bd9Sstevel@tonic-gate } 1210*7c478bd9Sstevel@tonic-gate 1211*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_isoch_cec_member_list_insert_exit, 1212*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 1213*7c478bd9Sstevel@tonic-gate } 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate /* 1216*7c478bd9Sstevel@tonic-gate * s1394_isoch_cec_member_list_remove() 1217*7c478bd9Sstevel@tonic-gate * is used to remove a member (target) from the list of members for 1218*7c478bd9Sstevel@tonic-gate * a given Isoch CEC. 1219*7c478bd9Sstevel@tonic-gate */ 1220*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1221*7c478bd9Sstevel@tonic-gate void 1222*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_member_list_remove(s1394_hal_t *hal, s1394_isoch_cec_t *cec, 1223*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_member_t *member) 1224*7c478bd9Sstevel@tonic-gate { 1225*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_member_t *prev_member; 1226*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_member_t *next_member; 1227*7c478bd9Sstevel@tonic-gate 1228*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_isoch_cec_member_list_remove_enter, 1229*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 1230*7c478bd9Sstevel@tonic-gate 1231*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cec->isoch_cec_mutex)); 1232*7c478bd9Sstevel@tonic-gate 1233*7c478bd9Sstevel@tonic-gate prev_member = member->cec_mem_prev; 1234*7c478bd9Sstevel@tonic-gate next_member = member->cec_mem_next; 1235*7c478bd9Sstevel@tonic-gate 1236*7c478bd9Sstevel@tonic-gate member->cec_mem_prev = NULL; 1237*7c478bd9Sstevel@tonic-gate member->cec_mem_next = NULL; 1238*7c478bd9Sstevel@tonic-gate 1239*7c478bd9Sstevel@tonic-gate if (prev_member != NULL) { 1240*7c478bd9Sstevel@tonic-gate prev_member->cec_mem_next = next_member; 1241*7c478bd9Sstevel@tonic-gate 1242*7c478bd9Sstevel@tonic-gate } else { 1243*7c478bd9Sstevel@tonic-gate if (cec->cec_member_list_head == member) 1244*7c478bd9Sstevel@tonic-gate cec->cec_member_list_head = next_member; 1245*7c478bd9Sstevel@tonic-gate } 1246*7c478bd9Sstevel@tonic-gate 1247*7c478bd9Sstevel@tonic-gate if (next_member != NULL) { 1248*7c478bd9Sstevel@tonic-gate next_member->cec_mem_prev = prev_member; 1249*7c478bd9Sstevel@tonic-gate 1250*7c478bd9Sstevel@tonic-gate } else { 1251*7c478bd9Sstevel@tonic-gate if (cec->cec_member_list_tail == member) 1252*7c478bd9Sstevel@tonic-gate cec->cec_member_list_tail = prev_member; 1253*7c478bd9Sstevel@tonic-gate } 1254*7c478bd9Sstevel@tonic-gate 1255*7c478bd9Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_isoch_cec_member_list_remove_exit, 1256*7c478bd9Sstevel@tonic-gate S1394_TNF_SL_ISOCH_STACK, ""); 1257*7c478bd9Sstevel@tonic-gate } 1258