Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / 1394 / adapters / hci1394_tlabel.c
blobf4caebd2ab1ad1fb23572ee24e2126b8121c5fc3
1 /*
2 * CDDL HEADER START
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
7 * with the License.
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]
20 * CDDL HEADER END
23 * Copyright (c) 1999-2000 by Sun Microsystems, Inc.
24 * All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * hci1394_tlabel.h
31 * These routines track the tlabel usage for a 1394 adapter.
34 #include <sys/kmem.h>
35 #include <sys/types.h>
36 #include <sys/conf.h>
37 #include <sys/ddi.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.
51 void
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
83 * initialization)
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
93 * before returning.
95 void
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)
123 uint_t node_number;
124 uint_t index;
125 uint64_t bad;
126 uint64_t free;
127 hrtime_t time;
128 uint8_t last;
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.
165 if (bad != 0) {
166 if (gethrtime() > time) {
168 /* add the bad tlabels back into the free list */
169 free |= bad;
171 /* clear the bad list */
172 bad = 0;
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.
197 (last)++;
198 if (last >= TLABEL_RANGE) {
199 last = 0;
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
217 * tlabels.
219 (last)++;
220 if (last >= TLABEL_RANGE) {
221 last = 0;
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.
242 void
243 hci1394_tlabel_free(hci1394_tlabel_handle_t tlabel_handle,
244 hci1394_tlabel_info_t *tlabel_info)
246 uint_t node_number;
247 uint_t tlabel;
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
276 * own tlabel list.
278 void
279 hci1394_tlabel_register(hci1394_tlabel_handle_t tlabel_handle,
280 hci1394_tlabel_info_t *tlabel_info, void *cmd)
282 uint_t node_number;
283 uint_t tlabel;
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
307 * NULL.
309 void
310 hci1394_tlabel_lookup(hci1394_tlabel_handle_t tlabel_handle,
311 hci1394_tlabel_info_t *tlabel_info, void **cmd)
313 uint_t node_number;
314 uint_t tlabel;
317 ASSERT(tlabel_handle != NULL);
318 ASSERT(tlabel_info != NULL);
319 ASSERT(cmd != 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
343 * more info.
345 void
346 hci1394_tlabel_bad(hci1394_tlabel_handle_t tlabel_handle,
347 hci1394_tlabel_info_t *tlabel_info)
349 uint_t node_number;
350 uint_t tlabel;
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
368 * be free'd.
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.
385 void
386 hci1394_tlabel_reset(hci1394_tlabel_handle_t tlabel_handle)
388 int index;
389 int index2;
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] =
401 (uint64_t)0;
402 tlabel_handle->tb_bad_timestamp[IEEE1394_BROADCAST_NODEID] =
403 (hrtime_t)0;
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
407 ][index2] = NULL;
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.
446 void
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;