1 /* 2 * CDDL HEADER START 3 * 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. 8 * 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. 13 * 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] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1999-2000 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * hci1394_tlabel.h 31 * These routines track the tlabel usage for a 1394 adapter. 32 */ 33 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> 39 40 #include <sys/1394/ieee1394.h> 41 #include <sys/1394/adapters/hci1394.h> 42 43 44 /* 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. 50 */ 51 void 52 hci1394_tlabel_init(hci1394_drvinfo_t *drvinfo, hrtime_t reclaim_time_nS, 53 hci1394_tlabel_handle_t *tlabel_handle) 54 { 55 hci1394_tlabel_t *tstruct; 56 57 58 ASSERT(tlabel_handle != NULL); 59 TNF_PROBE_0_DEBUG(hci1394_tlabel_init_enter, HCI1394_TNF_HAL_STACK, ""); 60 61 /* alloc space for tlabel data */ 62 tstruct = kmem_alloc(sizeof (hci1394_tlabel_t), KM_SLEEP); 63 64 /* setup handle which is returned from this function */ 65 *tlabel_handle = tstruct; 66 67 /* 68 * Initialize tlabel structure. We start with max node set to the 69 * maxiumum node we could have so that we make sure the arrays are 70 * initialized correctly in hci1394_tlabel_reset(). 71 */ 72 tstruct->tb_drvinfo = drvinfo; 73 tstruct->tb_reclaim_time = reclaim_time_nS; 74 tstruct->tb_max_node = TLABEL_RANGE - 1; 75 tstruct->tb_bcast_sent = B_FALSE; 76 77 mutex_init(&tstruct->tb_mutex, NULL, MUTEX_DRIVER, 78 drvinfo->di_iblock_cookie); 79 80 /* 81 * The mutex must be initialized before tlabel_reset() 82 * is called. This is because tlabel_reset is also 83 * used in normal tlabel processing (i.e. not just during 84 * initialization) 85 */ 86 hci1394_tlabel_reset(tstruct); 87 88 TNF_PROBE_0_DEBUG(hci1394_tlabel_init_exit, HCI1394_TNF_HAL_STACK, ""); 89 } 90 91 92 /* 93 * hci1394_tlabel_fini() 94 * Frees up the space allocated in init(). Notice that a pointer to the 95 * handle is used for the parameter. fini() will set your handle to NULL 96 * before returning. 97 */ 98 void 99 hci1394_tlabel_fini(hci1394_tlabel_handle_t *tlabel_handle) 100 { 101 hci1394_tlabel_t *tstruct; 102 103 104 ASSERT(tlabel_handle != NULL); 105 TNF_PROBE_0_DEBUG(hci1394_tlabel_fini_enter, HCI1394_TNF_HAL_STACK, ""); 106 107 tstruct = (hci1394_tlabel_t *)*tlabel_handle; 108 109 mutex_destroy(&tstruct->tb_mutex); 110 kmem_free(tstruct, sizeof (hci1394_tlabel_t)); 111 112 /* set handle to null. This helps catch bugs. */ 113 *tlabel_handle = NULL; 114 115 TNF_PROBE_0_DEBUG(hci1394_tlabel_fini_exit, HCI1394_TNF_HAL_STACK, ""); 116 } 117 118 119 /* 120 * hci1394_tlabel_alloc() 121 * alloc a tlabel based on the node id. If alloc fails, we are out of 122 * tlabels for that node. See comments before set_reclaim_time() on when 123 * bad tlabel's are free to be used again. 124 */ 125 int 126 hci1394_tlabel_alloc(hci1394_tlabel_handle_t tlabel_handle, uint_t destination, 127 hci1394_tlabel_info_t *tlabel_info) 128 { 129 uint_t node_number; 130 uint_t index; 131 uint64_t bad; 132 uint64_t free; 133 hrtime_t time; 134 uint8_t last; 135 136 137 ASSERT(tlabel_handle != NULL); 138 ASSERT(tlabel_info != NULL); 139 TNF_PROBE_0_DEBUG(hci1394_tlabel_alloc_enter, 140 HCI1394_TNF_HAL_STACK, ""); 141 142 /* copy destination into tlabel_info */ 143 tlabel_info->tbi_destination = destination; 144 145 /* figure out what node we are going to */ 146 node_number = IEEE1394_NODE_NUM(destination); 147 148 mutex_enter(&tlabel_handle->tb_mutex); 149 150 /* 151 * Keep track of if we have sent out a broadcast request and what the 152 * maximum # node we have sent to for reset processing optimization 153 */ 154 if (node_number == IEEE1394_BROADCAST_NODEID) { 155 tlabel_handle->tb_bcast_sent = B_TRUE; 156 } else if (node_number > tlabel_handle->tb_max_node) { 157 tlabel_handle->tb_max_node = node_number; 158 } 159 160 /* setup copies so we don't take up so much space :-) */ 161 bad = tlabel_handle->tb_bad[node_number]; 162 free = tlabel_handle->tb_free[node_number]; 163 time = tlabel_handle->tb_bad_timestamp[node_number]; 164 last = tlabel_handle->tb_last[node_number]; 165 166 /* 167 * If there are any bad tlabels, see if the last bad tlabel recorded for 168 * this nodeid is now good to use. If so, add all bad tlabels for that 169 * node id back into the free list 170 * 171 * NOTE: This assumes that bad tlabels are infrequent. 172 */ 173 if (bad != 0) { 174 if (gethrtime() > time) { 175 176 /* add the bad tlabels back into the free list */ 177 free |= bad; 178 179 /* clear the bad list */ 180 bad = 0; 181 182 TNF_PROBE_1(hci1394_tlabel_free_bad, 183 HCI1394_TNF_HAL_ERROR, "", tnf_uint, nodeid, 184 node_number); 185 } 186 } 187 188 /* 189 * Find a free tlabel. This will break out of the loop once it finds a 190 * tlabel. There are a total of TLABEL_RANGE tlabels. The alloc 191 * rotates the check so that we don't always use the same tlabel. It 192 * stores the last tlabel used in last. 193 */ 194 for (index = 0; index < TLABEL_RANGE; index++) { 195 196 /* if the next tlabel to check is free */ 197 if ((free & ((uint64_t)1 << last)) != 0) { 198 /* we are using this tlabel */ 199 tlabel_info->tbi_tlabel = last; 200 201 TNF_PROBE_2_DEBUG(hci1394_tlabel_alloc, 202 HCI1394_TNF_HAL_TLABEL, "", tnf_uint, nodeid, 203 node_number, tnf_uint, alloced_tlabel, 204 tlabel_info->tbi_tlabel); 205 206 /* take it out of the free list */ 207 free = free & ~((uint64_t)1 << last); 208 209 /* 210 * increment the last count so we start checking on the 211 * next tlabel next alloc(). Note the rollover at 212 * TLABEL_RANGE since we only have TLABEL_RANGE tlabels. 213 */ 214 (last)++; 215 if (last >= TLABEL_RANGE) { 216 last = 0; 217 } 218 219 /* Copy the copies back */ 220 tlabel_handle->tb_bad[node_number] = bad; 221 tlabel_handle->tb_free[node_number] = free; 222 tlabel_handle->tb_bad_timestamp[node_number] = time; 223 tlabel_handle->tb_last[node_number] = last; 224 225 /* unlock the tlabel structure */ 226 mutex_exit(&tlabel_handle->tb_mutex); 227 228 TNF_PROBE_0_DEBUG(hci1394_tlabel_alloc_exit, 229 HCI1394_TNF_HAL_STACK, ""); 230 return (DDI_SUCCESS); 231 } 232 233 /* 234 * This tlabel is not free, lets go to the next one. Note the 235 * rollover at TLABEL_RANGE since we only have TLABEL_RANGE 236 * tlabels. 237 */ 238 (last)++; 239 if (last >= TLABEL_RANGE) { 240 last = 0; 241 } 242 } 243 244 /* Copy the copies back */ 245 tlabel_handle->tb_bad[node_number] = bad; 246 tlabel_handle->tb_free[node_number] = free; 247 tlabel_handle->tb_bad_timestamp[node_number] = time; 248 tlabel_handle->tb_last[node_number] = last; 249 250 mutex_exit(&tlabel_handle->tb_mutex); 251 252 TNF_PROBE_1(hci1394_tlabel_alloc_empty, HCI1394_TNF_HAL_ERROR, "", 253 tnf_string, errmsg, "No more tlabels left to alloc"); 254 TNF_PROBE_0_DEBUG(hci1394_tlabel_alloc_exit, HCI1394_TNF_HAL_STACK, ""); 255 256 return (DDI_FAILURE); 257 } 258 259 260 /* 261 * hci1394_tlabel_free() 262 * free the previously alloc()'d tlabel. Once a tlabel has been free'd, it 263 * can be used again when alloc() is called. 264 */ 265 void 266 hci1394_tlabel_free(hci1394_tlabel_handle_t tlabel_handle, 267 hci1394_tlabel_info_t *tlabel_info) 268 { 269 uint_t node_number; 270 uint_t tlabel; 271 272 273 ASSERT(tlabel_handle != NULL); 274 ASSERT(tlabel_info != NULL); 275 ASSERT(tlabel_info->tbi_tlabel <= TLABEL_MASK); 276 TNF_PROBE_0_DEBUG(hci1394_tlabel_free_enter, HCI1394_TNF_HAL_STACK, ""); 277 278 /* figure out what node and tlabel we are using */ 279 node_number = IEEE1394_NODE_NUM(tlabel_info->tbi_destination); 280 tlabel = tlabel_info->tbi_tlabel; 281 282 TNF_PROBE_2_DEBUG(hci1394_tlabel_free, 283 HCI1394_TNF_HAL_TLABEL, "", tnf_uint, nodeid, node_number, 284 tnf_uint, freed_tlabel, tlabel_info->tbi_tlabel); 285 286 mutex_enter(&tlabel_handle->tb_mutex); 287 288 /* 289 * Put the tlabel back in the free list and NULL out the (void *) in the 290 * lookup structure. You wouldn't expect to have to null out the lookup 291 * structure, but we know first hand that bad HW will send invalid 292 * tlabels which could really mess things up if you didn't :-) 293 */ 294 tlabel_handle->tb_lookup[node_number][tlabel] = NULL; 295 tlabel_handle->tb_free[node_number] |= ((uint64_t)1 << tlabel); 296 297 mutex_exit(&tlabel_handle->tb_mutex); 298 299 TNF_PROBE_0_DEBUG(hci1394_tlabel_free_exit, HCI1394_TNF_HAL_STACK, ""); 300 } 301 302 303 /* 304 * hci1394_tlabel_register() 305 * Register an opaque command with an alloc()'d tlabel. Each nodeID has it's 306 * own tlabel list. 307 */ 308 void 309 hci1394_tlabel_register(hci1394_tlabel_handle_t tlabel_handle, 310 hci1394_tlabel_info_t *tlabel_info, void *cmd) 311 { 312 uint_t node_number; 313 uint_t tlabel; 314 315 316 ASSERT(tlabel_handle != NULL); 317 ASSERT(tlabel_info != NULL); 318 ASSERT(tlabel_info->tbi_tlabel <= TLABEL_MASK); 319 TNF_PROBE_0_DEBUG(hci1394_tlabel_register_enter, 320 HCI1394_TNF_HAL_STACK, ""); 321 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; 325 326 mutex_enter(&tlabel_handle->tb_mutex); 327 328 /* enter the (void *) into the lookup table */ 329 tlabel_handle->tb_lookup[node_number][tlabel] = cmd; 330 331 mutex_exit(&tlabel_handle->tb_mutex); 332 333 TNF_PROBE_0_DEBUG(hci1394_tlabel_register_exit, 334 HCI1394_TNF_HAL_STACK, ""); 335 } 336 337 338 /* 339 * hci1394_tlabel_lookup() 340 * returns (in cmd) the opaque command which was registered with the 341 * specified tlabel from alloc(). If a tlabel was not registered, cmd ='s 342 * NULL. 343 */ 344 void 345 hci1394_tlabel_lookup(hci1394_tlabel_handle_t tlabel_handle, 346 hci1394_tlabel_info_t *tlabel_info, void **cmd) 347 { 348 uint_t node_number; 349 uint_t tlabel; 350 351 352 ASSERT(tlabel_handle != NULL); 353 ASSERT(tlabel_info != NULL); 354 ASSERT(cmd != NULL); 355 ASSERT(tlabel_info->tbi_tlabel <= TLABEL_MASK); 356 TNF_PROBE_0_DEBUG(hci1394_tlabel_lookup_enter, 357 HCI1394_TNF_HAL_STACK, ""); 358 359 /* figure out what node and tlabel we are using */ 360 node_number = IEEE1394_NODE_NUM(tlabel_info->tbi_destination); 361 tlabel = tlabel_info->tbi_tlabel; 362 363 mutex_enter(&tlabel_handle->tb_mutex); 364 365 /* 366 * fetch the (void *) from the lookup table. The case where the pointer 367 * equals NULL will be handled by the layer above. 368 */ 369 *cmd = tlabel_handle->tb_lookup[node_number][tlabel]; 370 371 mutex_exit(&tlabel_handle->tb_mutex); 372 373 TNF_PROBE_2_DEBUG(hci1394_tlabel_lookup, 374 HCI1394_TNF_HAL_TLABEL, "", tnf_uint, nodeid, node_number, 375 tnf_uint, lookup_tlabel, tlabel_info->tbi_tlabel); 376 377 TNF_PROBE_0_DEBUG(hci1394_tlabel_lookup_exit, 378 HCI1394_TNF_HAL_STACK, ""); 379 } 380 381 382 /* 383 * hci1394_tlabel_bad() 384 * Register the specified tlabel as bad. tlabel_lookup() will no longer 385 * return a registered opaque command and this tlabel will not be returned 386 * from alloc() until > reclaim_time has passed. See set_reclaim_time() for 387 * more info. 388 */ 389 void 390 hci1394_tlabel_bad(hci1394_tlabel_handle_t tlabel_handle, 391 hci1394_tlabel_info_t *tlabel_info) 392 { 393 uint_t node_number; 394 uint_t tlabel; 395 396 397 ASSERT(tlabel_handle != NULL); 398 ASSERT(tlabel_info != NULL); 399 TNF_PROBE_0_DEBUG(hci1394_tlabel_bad_enter, HCI1394_TNF_HAL_STACK, ""); 400 401 /* figure out what node and tlabel we are using */ 402 node_number = IEEE1394_NODE_NUM(tlabel_info->tbi_destination); 403 tlabel = tlabel_info->tbi_tlabel & TLABEL_MASK; 404 405 mutex_enter(&tlabel_handle->tb_mutex); 406 407 TNF_PROBE_2(hci1394_tlabel_timeout, HCI1394_TNF_HAL_ERROR, "", tnf_uint, 408 nodeid, node_number, tnf_uint, bad_tlabel, tlabel_info->tbi_tlabel); 409 410 /* 411 * Put the tlabel in the bad list and NULL out the (void *) in the 412 * lookup structure. We may see this tlabel shortly if the device is 413 * late in responding. We want to make sure to drop the message if we 414 * do. Set the bad timestamp to the current time plus the reclaim time. 415 * This is the "new" time when all of the bad tlabels for this node will 416 * be free'd. 417 */ 418 tlabel_handle->tb_bad_timestamp[node_number] = gethrtime() + 419 tlabel_handle->tb_reclaim_time; 420 tlabel_handle->tb_bad[node_number] |= ((uint64_t)1 << tlabel); 421 tlabel_handle->tb_lookup[node_number][tlabel] = NULL; 422 423 mutex_exit(&tlabel_handle->tb_mutex); 424 425 TNF_PROBE_0_DEBUG(hci1394_tlabel_bad_exit, HCI1394_TNF_HAL_STACK, ""); 426 } 427 428 429 /* 430 * hci1394_tlabel_reset() 431 * resets the tlabel tracking structures to an initial state where no 432 * tlabels are outstanding and all tlabels are registered as good. This 433 * routine should be called every bus reset. 434 */ 435 void 436 hci1394_tlabel_reset(hci1394_tlabel_handle_t tlabel_handle) 437 { 438 int index; 439 int index2; 440 441 442 ASSERT(tlabel_handle != NULL); 443 TNF_PROBE_0_DEBUG(hci1394_tlabel_reset_enter, 444 HCI1394_TNF_HAL_STACK, ""); 445 446 mutex_enter(&tlabel_handle->tb_mutex); 447 448 TNF_PROBE_0_DEBUG(hci1394_tlabel_reset, HCI1394_TNF_HAL_TLABEL, ""); 449 450 /* Bus reset optimization. handle broadcast writes separately */ 451 if (tlabel_handle->tb_bcast_sent == B_TRUE) { 452 tlabel_handle->tb_free[IEEE1394_BROADCAST_NODEID] = 453 (uint64_t)0xFFFFFFFFFFFFFFFF; 454 tlabel_handle->tb_bad[IEEE1394_BROADCAST_NODEID] = 455 (uint64_t)0; 456 tlabel_handle->tb_bad_timestamp[IEEE1394_BROADCAST_NODEID] = 457 (hrtime_t)0; 458 tlabel_handle->tb_last[IEEE1394_BROADCAST_NODEID] = 0; 459 for (index2 = 0; index2 < TLABEL_RANGE; index2++) { 460 tlabel_handle->tb_lookup[IEEE1394_BROADCAST_NODEID 461 ][index2] = NULL; 462 } 463 } 464 465 /* 466 * Mark all tlabels as free. No bad tlabels. Start the first tlabel 467 * alloc at 0. Cleanout the lookup table. An optimization to only do 468 * this up to the max node we have seen on the bus has been added. 469 */ 470 for (index = 0; index <= tlabel_handle->tb_max_node; index++) { 471 tlabel_handle->tb_free[index] = (uint64_t)0xFFFFFFFFFFFFFFFF; 472 tlabel_handle->tb_bad[index] = (uint64_t)0; 473 tlabel_handle->tb_bad_timestamp[index] = (hrtime_t)0; 474 tlabel_handle->tb_last[index] = 0; 475 for (index2 = 0; index2 < TLABEL_RANGE; index2++) { 476 tlabel_handle->tb_lookup[index][index2] = NULL; 477 } 478 } 479 480 tlabel_handle->tb_max_node = 0; 481 tlabel_handle->tb_bcast_sent = B_FALSE; 482 483 mutex_exit(&tlabel_handle->tb_mutex); 484 485 TNF_PROBE_0_DEBUG(hci1394_tlabel_reset_exit, HCI1394_TNF_HAL_STACK, ""); 486 } 487 488 489 /* 490 * hci1394_tlabel_set_reclaim_time() 491 * This function should be called if a change to the reclaim_time is 492 * required after the initial call to init(). It is not necessary to call 493 * this function if the reclaim time never changes. 494 * 495 * Currently, bad tlabels are reclaimed in tlabel_alloc(). 496 * It looks like the following for a given node: 497 * 498 * if bad tlabels exist 499 * if ((current time + reclaim time) >= last bad tlabel time) 500 * free all bad tlabels. 501 */ 502 void 503 hci1394_tlabel_set_reclaim_time(hci1394_tlabel_handle_t tlabel_handle, 504 hrtime_t reclaim_time_nS) 505 { 506 ASSERT(tlabel_handle != NULL); 507 TNF_PROBE_0_DEBUG(hci1394_tlabel_set_reclaim_time_enter, 508 HCI1394_TNF_HAL_STACK, ""); 509 510 /* 511 * We do not need to lock the tlabel structure in this because we are 512 * doing a single write to reclaim_time. If this changes in the future, 513 * we may need to add calls to lock() and unlock(). 514 */ 515 tlabel_handle->tb_reclaim_time = reclaim_time_nS; 516 517 TNF_PROBE_0_DEBUG(hci1394_tlabel_set_reclaim_time_exit, 518 HCI1394_TNF_HAL_STACK, ""); 519 } 520