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