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