4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1999-2000 by Sun Microsystems, Inc.
24 * All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
31 * These routines track the tlabel usage for a 1394 adapter.
35 #include <sys/types.h>
38 #include <sys/sunddi.h>
40 #include <sys/1394/ieee1394.h>
41 #include <sys/1394/adapters/hci1394.h>
45 * hci1394_tlabel_init()
46 * Initialize the tlabel structures. These structures will be protected
47 * by a mutex at the iblock_cookie passed in. Bad tlabels will be usable
48 * when > reclaim_time_nS has gone by. init() returns a handle to be used
49 * for the rest of the tlabel functions.
52 hci1394_tlabel_init(hci1394_drvinfo_t
*drvinfo
, hrtime_t reclaim_time_nS
,
53 hci1394_tlabel_handle_t
*tlabel_handle
)
55 hci1394_tlabel_t
*tstruct
;
58 ASSERT(tlabel_handle
!= NULL
);
60 /* alloc space for tlabel data */
61 tstruct
= kmem_alloc(sizeof (hci1394_tlabel_t
), KM_SLEEP
);
63 /* setup handle which is returned from this function */
64 *tlabel_handle
= tstruct
;
67 * Initialize tlabel structure. We start with max node set to the
68 * maxiumum node we could have so that we make sure the arrays are
69 * initialized correctly in hci1394_tlabel_reset().
71 tstruct
->tb_drvinfo
= drvinfo
;
72 tstruct
->tb_reclaim_time
= reclaim_time_nS
;
73 tstruct
->tb_max_node
= TLABEL_RANGE
- 1;
74 tstruct
->tb_bcast_sent
= B_FALSE
;
76 mutex_init(&tstruct
->tb_mutex
, NULL
, MUTEX_DRIVER
,
77 drvinfo
->di_iblock_cookie
);
80 * The mutex must be initialized before tlabel_reset()
81 * is called. This is because tlabel_reset is also
82 * used in normal tlabel processing (i.e. not just during
85 hci1394_tlabel_reset(tstruct
);
90 * hci1394_tlabel_fini()
91 * Frees up the space allocated in init(). Notice that a pointer to the
92 * handle is used for the parameter. fini() will set your handle to NULL
96 hci1394_tlabel_fini(hci1394_tlabel_handle_t
*tlabel_handle
)
98 hci1394_tlabel_t
*tstruct
;
101 ASSERT(tlabel_handle
!= NULL
);
103 tstruct
= (hci1394_tlabel_t
*)*tlabel_handle
;
105 mutex_destroy(&tstruct
->tb_mutex
);
106 kmem_free(tstruct
, sizeof (hci1394_tlabel_t
));
108 /* set handle to null. This helps catch bugs. */
109 *tlabel_handle
= NULL
;
114 * hci1394_tlabel_alloc()
115 * alloc a tlabel based on the node id. If alloc fails, we are out of
116 * tlabels for that node. See comments before set_reclaim_time() on when
117 * bad tlabel's are free to be used again.
120 hci1394_tlabel_alloc(hci1394_tlabel_handle_t tlabel_handle
, uint_t destination
,
121 hci1394_tlabel_info_t
*tlabel_info
)
131 ASSERT(tlabel_handle
!= NULL
);
132 ASSERT(tlabel_info
!= NULL
);
134 /* copy destination into tlabel_info */
135 tlabel_info
->tbi_destination
= destination
;
137 /* figure out what node we are going to */
138 node_number
= IEEE1394_NODE_NUM(destination
);
140 mutex_enter(&tlabel_handle
->tb_mutex
);
143 * Keep track of if we have sent out a broadcast request and what the
144 * maximum # node we have sent to for reset processing optimization
146 if (node_number
== IEEE1394_BROADCAST_NODEID
) {
147 tlabel_handle
->tb_bcast_sent
= B_TRUE
;
148 } else if (node_number
> tlabel_handle
->tb_max_node
) {
149 tlabel_handle
->tb_max_node
= node_number
;
152 /* setup copies so we don't take up so much space :-) */
153 bad
= tlabel_handle
->tb_bad
[node_number
];
154 free
= tlabel_handle
->tb_free
[node_number
];
155 time
= tlabel_handle
->tb_bad_timestamp
[node_number
];
156 last
= tlabel_handle
->tb_last
[node_number
];
159 * If there are any bad tlabels, see if the last bad tlabel recorded for
160 * this nodeid is now good to use. If so, add all bad tlabels for that
161 * node id back into the free list
163 * NOTE: This assumes that bad tlabels are infrequent.
166 if (gethrtime() > time
) {
168 /* add the bad tlabels back into the free list */
171 /* clear the bad list */
177 * Find a free tlabel. This will break out of the loop once it finds a
178 * tlabel. There are a total of TLABEL_RANGE tlabels. The alloc
179 * rotates the check so that we don't always use the same tlabel. It
180 * stores the last tlabel used in last.
182 for (index
= 0; index
< TLABEL_RANGE
; index
++) {
184 /* if the next tlabel to check is free */
185 if ((free
& ((uint64_t)1 << last
)) != 0) {
186 /* we are using this tlabel */
187 tlabel_info
->tbi_tlabel
= last
;
189 /* take it out of the free list */
190 free
= free
& ~((uint64_t)1 << last
);
193 * increment the last count so we start checking on the
194 * next tlabel next alloc(). Note the rollover at
195 * TLABEL_RANGE since we only have TLABEL_RANGE tlabels.
198 if (last
>= TLABEL_RANGE
) {
202 /* Copy the copies back */
203 tlabel_handle
->tb_bad
[node_number
] = bad
;
204 tlabel_handle
->tb_free
[node_number
] = free
;
205 tlabel_handle
->tb_bad_timestamp
[node_number
] = time
;
206 tlabel_handle
->tb_last
[node_number
] = last
;
208 /* unlock the tlabel structure */
209 mutex_exit(&tlabel_handle
->tb_mutex
);
211 return (DDI_SUCCESS
);
215 * This tlabel is not free, lets go to the next one. Note the
216 * rollover at TLABEL_RANGE since we only have TLABEL_RANGE
220 if (last
>= TLABEL_RANGE
) {
225 /* Copy the copies back */
226 tlabel_handle
->tb_bad
[node_number
] = bad
;
227 tlabel_handle
->tb_free
[node_number
] = free
;
228 tlabel_handle
->tb_bad_timestamp
[node_number
] = time
;
229 tlabel_handle
->tb_last
[node_number
] = last
;
231 mutex_exit(&tlabel_handle
->tb_mutex
);
233 return (DDI_FAILURE
);
238 * hci1394_tlabel_free()
239 * free the previously alloc()'d tlabel. Once a tlabel has been free'd, it
240 * can be used again when alloc() is called.
243 hci1394_tlabel_free(hci1394_tlabel_handle_t tlabel_handle
,
244 hci1394_tlabel_info_t
*tlabel_info
)
250 ASSERT(tlabel_handle
!= NULL
);
251 ASSERT(tlabel_info
!= NULL
);
252 ASSERT(tlabel_info
->tbi_tlabel
<= TLABEL_MASK
);
254 /* figure out what node and tlabel we are using */
255 node_number
= IEEE1394_NODE_NUM(tlabel_info
->tbi_destination
);
256 tlabel
= tlabel_info
->tbi_tlabel
;
258 mutex_enter(&tlabel_handle
->tb_mutex
);
261 * Put the tlabel back in the free list and NULL out the (void *) in the
262 * lookup structure. You wouldn't expect to have to null out the lookup
263 * structure, but we know first hand that bad HW will send invalid
264 * tlabels which could really mess things up if you didn't :-)
266 tlabel_handle
->tb_lookup
[node_number
][tlabel
] = NULL
;
267 tlabel_handle
->tb_free
[node_number
] |= ((uint64_t)1 << tlabel
);
269 mutex_exit(&tlabel_handle
->tb_mutex
);
274 * hci1394_tlabel_register()
275 * Register an opaque command with an alloc()'d tlabel. Each nodeID has it's
279 hci1394_tlabel_register(hci1394_tlabel_handle_t tlabel_handle
,
280 hci1394_tlabel_info_t
*tlabel_info
, void *cmd
)
286 ASSERT(tlabel_handle
!= NULL
);
287 ASSERT(tlabel_info
!= NULL
);
288 ASSERT(tlabel_info
->tbi_tlabel
<= TLABEL_MASK
);
290 /* figure out what node and tlabel we are using */
291 node_number
= IEEE1394_NODE_NUM(tlabel_info
->tbi_destination
);
292 tlabel
= tlabel_info
->tbi_tlabel
;
294 mutex_enter(&tlabel_handle
->tb_mutex
);
296 /* enter the (void *) into the lookup table */
297 tlabel_handle
->tb_lookup
[node_number
][tlabel
] = cmd
;
299 mutex_exit(&tlabel_handle
->tb_mutex
);
304 * hci1394_tlabel_lookup()
305 * returns (in cmd) the opaque command which was registered with the
306 * specified tlabel from alloc(). If a tlabel was not registered, cmd ='s
310 hci1394_tlabel_lookup(hci1394_tlabel_handle_t tlabel_handle
,
311 hci1394_tlabel_info_t
*tlabel_info
, void **cmd
)
317 ASSERT(tlabel_handle
!= NULL
);
318 ASSERT(tlabel_info
!= NULL
);
320 ASSERT(tlabel_info
->tbi_tlabel
<= TLABEL_MASK
);
322 /* figure out what node and tlabel we are using */
323 node_number
= IEEE1394_NODE_NUM(tlabel_info
->tbi_destination
);
324 tlabel
= tlabel_info
->tbi_tlabel
;
326 mutex_enter(&tlabel_handle
->tb_mutex
);
329 * fetch the (void *) from the lookup table. The case where the pointer
330 * equals NULL will be handled by the layer above.
332 *cmd
= tlabel_handle
->tb_lookup
[node_number
][tlabel
];
334 mutex_exit(&tlabel_handle
->tb_mutex
);
339 * hci1394_tlabel_bad()
340 * Register the specified tlabel as bad. tlabel_lookup() will no longer
341 * return a registered opaque command and this tlabel will not be returned
342 * from alloc() until > reclaim_time has passed. See set_reclaim_time() for
346 hci1394_tlabel_bad(hci1394_tlabel_handle_t tlabel_handle
,
347 hci1394_tlabel_info_t
*tlabel_info
)
353 ASSERT(tlabel_handle
!= NULL
);
354 ASSERT(tlabel_info
!= NULL
);
356 /* figure out what node and tlabel we are using */
357 node_number
= IEEE1394_NODE_NUM(tlabel_info
->tbi_destination
);
358 tlabel
= tlabel_info
->tbi_tlabel
& TLABEL_MASK
;
360 mutex_enter(&tlabel_handle
->tb_mutex
);
363 * Put the tlabel in the bad list and NULL out the (void *) in the
364 * lookup structure. We may see this tlabel shortly if the device is
365 * late in responding. We want to make sure to drop the message if we
366 * do. Set the bad timestamp to the current time plus the reclaim time.
367 * This is the "new" time when all of the bad tlabels for this node will
370 tlabel_handle
->tb_bad_timestamp
[node_number
] = gethrtime() +
371 tlabel_handle
->tb_reclaim_time
;
372 tlabel_handle
->tb_bad
[node_number
] |= ((uint64_t)1 << tlabel
);
373 tlabel_handle
->tb_lookup
[node_number
][tlabel
] = NULL
;
375 mutex_exit(&tlabel_handle
->tb_mutex
);
380 * hci1394_tlabel_reset()
381 * resets the tlabel tracking structures to an initial state where no
382 * tlabels are outstanding and all tlabels are registered as good. This
383 * routine should be called every bus reset.
386 hci1394_tlabel_reset(hci1394_tlabel_handle_t tlabel_handle
)
392 ASSERT(tlabel_handle
!= NULL
);
394 mutex_enter(&tlabel_handle
->tb_mutex
);
396 /* Bus reset optimization. handle broadcast writes separately */
397 if (tlabel_handle
->tb_bcast_sent
== B_TRUE
) {
398 tlabel_handle
->tb_free
[IEEE1394_BROADCAST_NODEID
] =
399 (uint64_t)0xFFFFFFFFFFFFFFFF;
400 tlabel_handle
->tb_bad
[IEEE1394_BROADCAST_NODEID
] =
402 tlabel_handle
->tb_bad_timestamp
[IEEE1394_BROADCAST_NODEID
] =
404 tlabel_handle
->tb_last
[IEEE1394_BROADCAST_NODEID
] = 0;
405 for (index2
= 0; index2
< TLABEL_RANGE
; index2
++) {
406 tlabel_handle
->tb_lookup
[IEEE1394_BROADCAST_NODEID
412 * Mark all tlabels as free. No bad tlabels. Start the first tlabel
413 * alloc at 0. Cleanout the lookup table. An optimization to only do
414 * this up to the max node we have seen on the bus has been added.
416 for (index
= 0; index
<= tlabel_handle
->tb_max_node
; index
++) {
417 tlabel_handle
->tb_free
[index
] = (uint64_t)0xFFFFFFFFFFFFFFFF;
418 tlabel_handle
->tb_bad
[index
] = (uint64_t)0;
419 tlabel_handle
->tb_bad_timestamp
[index
] = (hrtime_t
)0;
420 tlabel_handle
->tb_last
[index
] = 0;
421 for (index2
= 0; index2
< TLABEL_RANGE
; index2
++) {
422 tlabel_handle
->tb_lookup
[index
][index2
] = NULL
;
426 tlabel_handle
->tb_max_node
= 0;
427 tlabel_handle
->tb_bcast_sent
= B_FALSE
;
429 mutex_exit(&tlabel_handle
->tb_mutex
);
434 * hci1394_tlabel_set_reclaim_time()
435 * This function should be called if a change to the reclaim_time is
436 * required after the initial call to init(). It is not necessary to call
437 * this function if the reclaim time never changes.
439 * Currently, bad tlabels are reclaimed in tlabel_alloc().
440 * It looks like the following for a given node:
442 * if bad tlabels exist
443 * if ((current time + reclaim time) >= last bad tlabel time)
444 * free all bad tlabels.
447 hci1394_tlabel_set_reclaim_time(hci1394_tlabel_handle_t tlabel_handle
,
448 hrtime_t reclaim_time_nS
)
450 ASSERT(tlabel_handle
!= NULL
);
453 * We do not need to lock the tlabel structure in this because we are
454 * doing a single write to reclaim_time. If this changes in the future,
455 * we may need to add calls to lock() and unlock().
457 tlabel_handle
->tb_reclaim_time
= reclaim_time_nS
;