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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * PX Interrupt Block implementation 27 */ 28 29 #include <sys/types.h> 30 #include <sys/kmem.h> 31 #include <sys/async.h> 32 #include <sys/systm.h> /* panicstr */ 33 #include <sys/spl.h> 34 #include <sys/sunddi.h> 35 #include <sys/machsystm.h> /* intr_dist_add */ 36 #include <sys/ddi_impldefs.h> 37 #include <sys/cpuvar.h> 38 #include <sys/time.h> 39 #include "px_obj.h" 40 41 /*LINTLIBRARY*/ 42 43 static void px_ib_intr_redist(void *arg, int32_t weight_max, int32_t weight); 44 static void px_ib_cpu_ticks_to_ih_nsec(px_ib_t *ib_p, px_ih_t *ih_p, 45 uint32_t cpu_id); 46 static uint_t px_ib_intr_reset(void *arg); 47 static void px_fill_in_intr_devs(pcitool_intr_dev_t *dev, char *driver_name, 48 char *path_name, int instance); 49 50 extern uint64_t xc_tick_jump_limit; 51 52 int 53 px_ib_attach(px_t *px_p) 54 { 55 dev_info_t *dip = px_p->px_dip; 56 px_ib_t *ib_p; 57 sysino_t sysino; 58 px_fault_t *fault_p = &px_p->px_fault; 59 60 DBG(DBG_IB, dip, "px_ib_attach\n"); 61 62 if (px_lib_intr_devino_to_sysino(px_p->px_dip, 63 px_p->px_inos[PX_INTR_PEC], &sysino) != DDI_SUCCESS) 64 return (DDI_FAILURE); 65 66 /* 67 * Allocate interrupt block state structure and link it to 68 * the px state structure. 69 */ 70 ib_p = kmem_zalloc(sizeof (px_ib_t), KM_SLEEP); 71 px_p->px_ib_p = ib_p; 72 ib_p->ib_px_p = px_p; 73 ib_p->ib_ino_lst = (px_ino_t *)NULL; 74 75 mutex_init(&ib_p->ib_intr_lock, NULL, MUTEX_DRIVER, NULL); 76 mutex_init(&ib_p->ib_ino_lst_mutex, NULL, MUTEX_DRIVER, NULL); 77 78 bus_func_register(BF_TYPE_RESINTR, px_ib_intr_reset, ib_p); 79 80 intr_dist_add_weighted(px_ib_intr_redist, ib_p); 81 82 /* 83 * Initialize PEC fault data structure 84 */ 85 fault_p->px_fh_dip = dip; 86 fault_p->px_fh_sysino = sysino; 87 fault_p->px_err_func = px_err_dmc_pec_intr; 88 fault_p->px_intr_ino = px_p->px_inos[PX_INTR_PEC]; 89 90 return (DDI_SUCCESS); 91 } 92 93 void 94 px_ib_detach(px_t *px_p) 95 { 96 px_ib_t *ib_p = px_p->px_ib_p; 97 dev_info_t *dip = px_p->px_dip; 98 99 DBG(DBG_IB, dip, "px_ib_detach\n"); 100 101 bus_func_unregister(BF_TYPE_RESINTR, px_ib_intr_reset, ib_p); 102 intr_dist_rem_weighted(px_ib_intr_redist, ib_p); 103 104 mutex_destroy(&ib_p->ib_ino_lst_mutex); 105 mutex_destroy(&ib_p->ib_intr_lock); 106 107 px_ib_free_ino_all(ib_p); 108 109 px_p->px_ib_p = NULL; 110 kmem_free(ib_p, sizeof (px_ib_t)); 111 } 112 113 void 114 px_ib_intr_enable(px_t *px_p, cpuid_t cpu_id, devino_t ino) 115 { 116 px_ib_t *ib_p = px_p->px_ib_p; 117 sysino_t sysino; 118 119 /* 120 * Determine the cpu for the interrupt 121 */ 122 mutex_enter(&ib_p->ib_intr_lock); 123 124 DBG(DBG_IB, px_p->px_dip, 125 "px_ib_intr_enable: ino=%x cpu_id=%x\n", ino, cpu_id); 126 127 if (px_lib_intr_devino_to_sysino(px_p->px_dip, ino, 128 &sysino) != DDI_SUCCESS) { 129 DBG(DBG_IB, px_p->px_dip, 130 "px_ib_intr_enable: px_intr_devino_to_sysino() failed\n"); 131 132 mutex_exit(&ib_p->ib_intr_lock); 133 return; 134 } 135 136 PX_INTR_ENABLE(px_p->px_dip, sysino, cpu_id); 137 px_lib_intr_setstate(px_p->px_dip, sysino, INTR_IDLE_STATE); 138 139 mutex_exit(&ib_p->ib_intr_lock); 140 } 141 142 /*ARGSUSED*/ 143 void 144 px_ib_intr_disable(px_ib_t *ib_p, devino_t ino, int wait) 145 { 146 sysino_t sysino; 147 148 mutex_enter(&ib_p->ib_intr_lock); 149 150 DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_disable: ino=%x\n", ino); 151 152 /* Disable the interrupt */ 153 if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, ino, 154 &sysino) != DDI_SUCCESS) { 155 DBG(DBG_IB, ib_p->ib_px_p->px_dip, 156 "px_ib_intr_disable: px_intr_devino_to_sysino() failed\n"); 157 158 mutex_exit(&ib_p->ib_intr_lock); 159 return; 160 } 161 162 PX_INTR_DISABLE(ib_p->ib_px_p->px_dip, sysino); 163 164 mutex_exit(&ib_p->ib_intr_lock); 165 } 166 167 int 168 px_ib_intr_pend(dev_info_t *dip, sysino_t sysino) 169 { 170 int ret = DDI_SUCCESS; 171 hrtime_t start_time, prev, curr, interval, jump; 172 hrtime_t intr_timeout; 173 intr_state_t intr_state; 174 175 /* Disable the interrupt */ 176 PX_INTR_DISABLE(dip, sysino); 177 178 intr_timeout = px_intrpend_timeout; 179 jump = TICK_TO_NSEC(xc_tick_jump_limit); 180 181 /* Busy wait on pending interrupt */ 182 for (curr = start_time = gethrtime(); !panicstr && 183 ((ret = px_lib_intr_getstate(dip, sysino, 184 &intr_state)) == DDI_SUCCESS) && 185 (intr_state == INTR_DELIVERED_STATE); /* */) { 186 /* 187 * If we have a really large jump in hrtime, it is most 188 * probably because we entered the debugger (or OBP, 189 * in general). So, we adjust the timeout accordingly 190 * to prevent declaring an interrupt timeout. The 191 * master-interrupt mechanism in OBP should deliver 192 * the interrupts properly. 193 */ 194 prev = curr; 195 curr = gethrtime(); 196 interval = curr - prev; 197 if (interval > jump) 198 intr_timeout += interval; 199 if (curr - start_time > intr_timeout) { 200 ret = DDI_FAILURE; 201 break; 202 } 203 } 204 return (ret); 205 } 206 207 void 208 px_ib_intr_dist_en(dev_info_t *dip, cpuid_t cpu_id, devino_t ino, 209 boolean_t wait_flag) 210 { 211 uint32_t old_cpu_id; 212 sysino_t sysino; 213 intr_valid_state_t enabled = 0; 214 215 DBG(DBG_IB, dip, "px_ib_intr_dist_en: ino=0x%x\n", ino); 216 217 if (px_lib_intr_devino_to_sysino(dip, ino, &sysino) != DDI_SUCCESS) { 218 DBG(DBG_IB, dip, "px_ib_intr_dist_en: " 219 "px_intr_devino_to_sysino() failed, ino 0x%x\n", ino); 220 return; 221 } 222 223 /* Skip enabling disabled interrupts */ 224 if (px_lib_intr_getvalid(dip, sysino, &enabled) != DDI_SUCCESS) { 225 DBG(DBG_IB, dip, "px_ib_intr_dist_en: px_intr_getvalid() " 226 "failed, sysino 0x%x\n", sysino); 227 return; 228 } 229 if (!enabled) 230 return; 231 232 /* Done if redistributed onto the same cpuid */ 233 if (px_lib_intr_gettarget(dip, sysino, &old_cpu_id) != DDI_SUCCESS) { 234 DBG(DBG_IB, dip, "px_ib_intr_dist_en: " 235 "px_intr_gettarget() failed\n"); 236 return; 237 } 238 if (cpu_id == old_cpu_id) 239 return; 240 241 /* Wait on pending interrupts */ 242 if (wait_flag != 0 && px_ib_intr_pend(dip, sysino) != DDI_SUCCESS) { 243 cmn_err(CE_WARN, 244 "%s%d: px_ib_intr_dist_en: sysino 0x%lx(ino 0x%x) " 245 "from cpu id 0x%x to 0x%x timeout", 246 ddi_driver_name(dip), ddi_get_instance(dip), 247 sysino, ino, old_cpu_id, cpu_id); 248 249 DBG(DBG_IB, dip, "px_ib_intr_dist_en: failed, " 250 "ino 0x%x sysino 0x%x\n", ino, sysino); 251 } 252 253 PX_INTR_ENABLE(dip, sysino, cpu_id); 254 } 255 256 static void 257 px_ib_cpu_ticks_to_ih_nsec(px_ib_t *ib_p, px_ih_t *ih_p, uint32_t cpu_id) 258 { 259 extern kmutex_t pxintr_ks_template_lock; 260 hrtime_t ticks; 261 262 /* 263 * Because we are updating two fields in ih_t we must lock 264 * pxintr_ks_template_lock to prevent someone from reading the 265 * kstats after we set ih_ticks to 0 and before we increment 266 * ih_nsec to compensate. 267 * 268 * We must also protect against the interrupt arriving and incrementing 269 * ih_ticks between the time we read it and when we reset it to 0. 270 * To do this we use atomic_swap. 271 */ 272 273 ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 274 275 mutex_enter(&pxintr_ks_template_lock); 276 ticks = atomic_swap_64(&ih_p->ih_ticks, 0); 277 ih_p->ih_nsec += (uint64_t)tick2ns(ticks, cpu_id); 278 mutex_exit(&pxintr_ks_template_lock); 279 } 280 281 282 /* 283 * Redistribute interrupts of the specified weight. The first call has a weight 284 * of weight_max, which can be used to trigger initialization for 285 * redistribution. The inos with weight [weight_max, inf.) should be processed 286 * on the "weight == weight_max" call. This first call is followed by calls 287 * of decreasing weights, inos of that weight should be processed. The final 288 * call specifies a weight of zero, this can be used to trigger processing of 289 * stragglers. 290 */ 291 static void 292 px_ib_intr_redist(void *arg, int32_t weight_max, int32_t weight) 293 { 294 px_ib_t *ib_p = (px_ib_t *)arg; 295 px_t *px_p = ib_p->ib_px_p; 296 dev_info_t *dip = px_p->px_dip; 297 px_ino_t *ino_p; 298 px_ino_pil_t *ipil_p; 299 px_ih_t *ih_lst; 300 int32_t dweight = 0; 301 int i; 302 303 /* Redistribute internal interrupts */ 304 if (weight == 0) { 305 mutex_enter(&ib_p->ib_intr_lock); 306 px_ib_intr_dist_en(dip, intr_dist_cpuid(), 307 px_p->px_inos[PX_INTR_PEC], B_FALSE); 308 mutex_exit(&ib_p->ib_intr_lock); 309 310 px_hp_intr_redist(px_p); 311 } 312 313 /* Redistribute device interrupts */ 314 mutex_enter(&ib_p->ib_ino_lst_mutex); 315 px_msiq_redist(px_p); 316 317 for (ino_p = ib_p->ib_ino_lst; ino_p; ino_p = ino_p->ino_next_p) { 318 /* 319 * Recomputes the sum of interrupt weights of devices that 320 * share the same ino upon first call marked by 321 * (weight == weight_max). 322 */ 323 if (weight == weight_max) { 324 ino_p->ino_intr_weight = 0; 325 326 for (ipil_p = ino_p->ino_ipil_p; ipil_p; 327 ipil_p = ipil_p->ipil_next_p) { 328 for (i = 0, ih_lst = ipil_p->ipil_ih_head; 329 i < ipil_p->ipil_ih_size; i++, 330 ih_lst = ih_lst->ih_next) { 331 dweight = i_ddi_get_intr_weight( 332 ih_lst->ih_dip); 333 if (dweight > 0) 334 ino_p->ino_intr_weight += 335 dweight; 336 } 337 } 338 } 339 340 /* 341 * As part of redistributing weighted interrupts over cpus, 342 * nexus redistributes device interrupts and updates 343 * cpu weight. The purpose is for the most light weighted 344 * cpu to take the next interrupt and gain weight, therefore 345 * attention demanding device gains more cpu attention by 346 * making itself heavy. 347 */ 348 if ((weight == ino_p->ino_intr_weight) || 349 ((weight >= weight_max) && 350 (ino_p->ino_intr_weight >= weight_max))) { 351 uint32_t orig_cpuid = ino_p->ino_cpuid; 352 353 if (cpu[orig_cpuid] == NULL) 354 orig_cpuid = CPU->cpu_id; 355 356 DBG(DBG_IB, dip, "px_ib_intr_redist: sysino 0x%llx " 357 "current cpuid 0x%x current default cpuid 0x%x\n", 358 ino_p->ino_sysino, ino_p->ino_cpuid, 359 ino_p->ino_default_cpuid); 360 361 /* select target cpuid and mark ino established */ 362 if (ino_p->ino_default_cpuid == -1) 363 ino_p->ino_cpuid = ino_p->ino_default_cpuid = 364 intr_dist_cpuid(); 365 else if ((ino_p->ino_cpuid != 366 ino_p->ino_default_cpuid) && 367 cpu[ino_p->ino_default_cpuid] && 368 cpu_intr_on(cpu[ino_p->ino_default_cpuid])) 369 ino_p->ino_cpuid = ino_p->ino_default_cpuid; 370 else if (!cpu_intr_on(cpu[ino_p->ino_cpuid])) 371 ino_p->ino_cpuid = intr_dist_cpuid(); 372 373 DBG(DBG_IB, dip, "px_ib_intr_redist: sysino 0x%llx " 374 "new cpuid 0x%x new default cpuid 0x%x\n", 375 ino_p->ino_sysino, ino_p->ino_cpuid, 376 ino_p->ino_default_cpuid); 377 378 /* Add device weight to targeted cpu. */ 379 for (ipil_p = ino_p->ino_ipil_p; ipil_p; 380 ipil_p = ipil_p->ipil_next_p) { 381 for (i = 0, ih_lst = ipil_p->ipil_ih_head; 382 i < ipil_p->ipil_ih_size; i++, 383 ih_lst = ih_lst->ih_next) { 384 385 dweight = i_ddi_get_intr_weight( 386 ih_lst->ih_dip); 387 intr_dist_cpuid_add_device_weight( 388 ino_p->ino_cpuid, ih_lst->ih_dip, 389 dweight); 390 391 /* 392 * Different cpus may have different 393 * clock speeds. to account for this, 394 * whenever an interrupt is moved to a 395 * new CPU, we convert the accumulated 396 * ticks into nsec, based upon the clock 397 * rate of the prior CPU. 398 * 399 * It is possible that the prior CPU no 400 * longer exists. In this case, fall 401 * back to using this CPU's clock rate. 402 * 403 * Note that the value in ih_ticks has 404 * already been corrected for any power 405 * savings mode which might have been 406 * in effect. 407 */ 408 px_ib_cpu_ticks_to_ih_nsec(ib_p, ih_lst, 409 orig_cpuid); 410 } 411 } 412 413 /* enable interrupt on new targeted cpu */ 414 px_ib_intr_dist_en(dip, ino_p->ino_cpuid, 415 ino_p->ino_ino, B_TRUE); 416 } 417 } 418 mutex_exit(&ib_p->ib_ino_lst_mutex); 419 } 420 421 /* 422 * Reset interrupts to IDLE. This function is called during 423 * panic handling after redistributing interrupts; it's needed to 424 * support dumping to network devices after 'sync' from OBP. 425 * 426 * N.B. This routine runs in a context where all other threads 427 * are permanently suspended. 428 */ 429 static uint_t 430 px_ib_intr_reset(void *arg) 431 { 432 px_ib_t *ib_p = (px_ib_t *)arg; 433 434 DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_reset\n"); 435 436 if (px_lib_intr_reset(ib_p->ib_px_p->px_dip) != DDI_SUCCESS) 437 return (BF_FATAL); 438 439 return (BF_NONE); 440 } 441 442 /* 443 * Locate px_ino_t structure on ib_p->ib_ino_lst according to ino# 444 * returns NULL if not found. 445 */ 446 px_ino_t * 447 px_ib_locate_ino(px_ib_t *ib_p, devino_t ino_num) 448 { 449 px_ino_t *ino_p = ib_p->ib_ino_lst; 450 451 ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 452 453 for (; ino_p && ino_p->ino_ino != ino_num; ino_p = ino_p->ino_next_p) 454 ; 455 456 return (ino_p); 457 } 458 459 px_ino_t * 460 px_ib_alloc_ino(px_ib_t *ib_p, devino_t ino_num) 461 { 462 sysino_t sysino; 463 px_ino_t *ino_p; 464 465 if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, 466 ino_num, &sysino) != DDI_SUCCESS) 467 return (NULL); 468 469 ino_p = kmem_zalloc(sizeof (px_ino_t), KM_SLEEP); 470 471 ino_p->ino_next_p = ib_p->ib_ino_lst; 472 ib_p->ib_ino_lst = ino_p; 473 474 ino_p->ino_ino = ino_num; 475 ino_p->ino_sysino = sysino; 476 ino_p->ino_ib_p = ib_p; 477 ino_p->ino_unclaimed_intrs = 0; 478 ino_p->ino_lopil = 0; 479 ino_p->ino_cpuid = ino_p->ino_default_cpuid = (cpuid_t)-1; 480 481 return (ino_p); 482 } 483 484 px_ino_pil_t * 485 px_ib_new_ino_pil(px_ib_t *ib_p, devino_t ino_num, uint_t pil, px_ih_t *ih_p) 486 { 487 px_ino_pil_t *ipil_p = kmem_zalloc(sizeof (px_ino_pil_t), KM_SLEEP); 488 px_ino_t *ino_p; 489 490 if ((ino_p = px_ib_locate_ino(ib_p, ino_num)) == NULL) 491 ino_p = px_ib_alloc_ino(ib_p, ino_num); 492 493 ASSERT(ino_p != NULL); 494 495 ih_p->ih_next = ih_p; 496 ipil_p->ipil_pil = pil; 497 ipil_p->ipil_ih_head = ih_p; 498 ipil_p->ipil_ih_tail = ih_p; 499 ipil_p->ipil_ih_start = ih_p; 500 ipil_p->ipil_ih_size = 1; 501 ipil_p->ipil_ino_p = ino_p; 502 503 ipil_p->ipil_next_p = ino_p->ino_ipil_p; 504 ino_p->ino_ipil_p = ipil_p; 505 ino_p->ino_ipil_size++; 506 507 if ((ino_p->ino_lopil == 0) || (ino_p->ino_lopil > pil)) 508 ino_p->ino_lopil = pil; 509 510 return (ipil_p); 511 } 512 513 void 514 px_ib_delete_ino_pil(px_ib_t *ib_p, px_ino_pil_t *ipil_p) 515 { 516 px_ino_t *ino_p = ipil_p->ipil_ino_p; 517 ushort_t pil = ipil_p->ipil_pil; 518 px_ino_pil_t *prev, *next; 519 520 ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 521 522 if (ino_p->ino_ipil_p == ipil_p) 523 ino_p->ino_ipil_p = ipil_p->ipil_next_p; 524 else { 525 for (prev = next = ino_p->ino_ipil_p; next != ipil_p; 526 prev = next, next = next->ipil_next_p) 527 ; 528 529 if (prev) 530 prev->ipil_next_p = ipil_p->ipil_next_p; 531 } 532 533 kmem_free(ipil_p, sizeof (px_ino_pil_t)); 534 535 if ((--ino_p->ino_ipil_size) && (ino_p->ino_lopil == pil)) { 536 for (next = ino_p->ino_ipil_p, pil = next->ipil_pil; 537 next; next = next->ipil_next_p) { 538 539 if (pil > next->ipil_pil) 540 pil = next->ipil_pil; 541 } 542 543 /* 544 * Value stored in pil should be the lowest pil. 545 */ 546 ino_p->ino_lopil = pil; 547 } 548 549 if (ino_p->ino_ipil_size) 550 return; 551 552 ino_p->ino_lopil = 0; 553 554 if (ino_p->ino_msiq_p) 555 return; 556 557 if (ib_p->ib_ino_lst == ino_p) 558 ib_p->ib_ino_lst = ino_p->ino_next_p; 559 else { 560 px_ino_t *list = ib_p->ib_ino_lst; 561 562 for (; list->ino_next_p != ino_p; list = list->ino_next_p) 563 ; 564 list->ino_next_p = ino_p->ino_next_p; 565 } 566 } 567 568 /* 569 * Free all ino when we are detaching. 570 */ 571 void 572 px_ib_free_ino_all(px_ib_t *ib_p) 573 { 574 px_ino_t *ino_p = ib_p->ib_ino_lst; 575 px_ino_t *next = NULL; 576 577 while (ino_p) { 578 next = ino_p->ino_next_p; 579 kmem_free(ino_p, sizeof (px_ino_t)); 580 ino_p = next; 581 } 582 } 583 584 /* 585 * Locate px_ino_pil_t structure on ino_p->ino_ipil_p according to ino# 586 * returns NULL if not found. 587 */ 588 px_ino_pil_t * 589 px_ib_ino_locate_ipil(px_ino_t *ino_p, uint_t pil) 590 { 591 px_ino_pil_t *ipil_p = ino_p->ino_ipil_p; 592 593 for (; ipil_p && ipil_p->ipil_pil != pil; ipil_p = ipil_p->ipil_next_p) 594 ; 595 596 return (ipil_p); 597 } 598 599 int 600 px_ib_ino_add_intr(px_t *px_p, px_ino_pil_t *ipil_p, px_ih_t *ih_p) 601 { 602 px_ino_t *ino_p = ipil_p->ipil_ino_p; 603 px_ib_t *ib_p = ino_p->ino_ib_p; 604 devino_t ino = ino_p->ino_ino; 605 sysino_t sysino = ino_p->ino_sysino; 606 dev_info_t *dip = px_p->px_dip; 607 cpuid_t curr_cpu; 608 int ret = DDI_SUCCESS; 609 610 ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 611 ASSERT(ib_p == px_p->px_ib_p); 612 613 DBG(DBG_IB, dip, "px_ib_ino_add_intr ino=%x\n", ino_p->ino_ino); 614 615 /* Disable the interrupt */ 616 if ((ret = px_lib_intr_gettarget(dip, sysino, 617 &curr_cpu)) != DDI_SUCCESS) { 618 DBG(DBG_IB, dip, 619 "px_ib_ino_add_intr px_intr_gettarget() failed\n"); 620 621 return (ret); 622 } 623 624 /* Wait on pending interrupt */ 625 if ((ret = px_ib_intr_pend(dip, sysino)) != DDI_SUCCESS) { 626 cmn_err(CE_WARN, "%s%d: px_ib_ino_add_intr: pending " 627 "sysino 0x%lx(ino 0x%x) timeout", 628 ddi_driver_name(dip), ddi_get_instance(dip), 629 sysino, ino); 630 } 631 632 /* 633 * If the interrupt was previously blocked (left in pending state) 634 * because of jabber we need to clear the pending state in case the 635 * jabber has gone away. 636 */ 637 if (ino_p->ino_unclaimed_intrs > px_unclaimed_intr_max) { 638 cmn_err(CE_WARN, 639 "%s%d: px_ib_ino_add_intr: ino 0x%x has been unblocked", 640 ddi_driver_name(dip), ddi_get_instance(dip), ino); 641 642 ino_p->ino_unclaimed_intrs = 0; 643 ret = px_lib_intr_setstate(dip, sysino, INTR_IDLE_STATE); 644 } 645 646 if (ret != DDI_SUCCESS) { 647 DBG(DBG_IB, dip, "px_ib_ino_add_intr: failed, " 648 "ino 0x%x sysino 0x%x\n", ino, sysino); 649 650 return (ret); 651 } 652 653 /* Link up px_ih_t */ 654 ih_p->ih_next = ipil_p->ipil_ih_head; 655 ipil_p->ipil_ih_tail->ih_next = ih_p; 656 ipil_p->ipil_ih_tail = ih_p; 657 658 ipil_p->ipil_ih_start = ipil_p->ipil_ih_head; 659 ipil_p->ipil_ih_size++; 660 661 /* Re-enable interrupt */ 662 PX_INTR_ENABLE(dip, sysino, curr_cpu); 663 664 return (ret); 665 } 666 667 /* 668 * Removes px_ih_t from the ino's link list. 669 * uses hardware mutex to lock out interrupt threads. 670 * Side effects: interrupt belongs to that ino is turned off on return. 671 * if we are sharing PX slot with other inos, the caller needs 672 * to turn it back on. 673 */ 674 int 675 px_ib_ino_rem_intr(px_t *px_p, px_ino_pil_t *ipil_p, px_ih_t *ih_p) 676 { 677 px_ino_t *ino_p = ipil_p->ipil_ino_p; 678 devino_t ino = ino_p->ino_ino; 679 sysino_t sysino = ino_p->ino_sysino; 680 dev_info_t *dip = px_p->px_dip; 681 px_ih_t *ih_lst = ipil_p->ipil_ih_head; 682 int i, ret = DDI_SUCCESS; 683 684 ASSERT(MUTEX_HELD(&ino_p->ino_ib_p->ib_ino_lst_mutex)); 685 686 DBG(DBG_IB, px_p->px_dip, "px_ib_ino_rem_intr ino=%x\n", 687 ino_p->ino_ino); 688 689 /* Wait on pending interrupt */ 690 if ((ret = px_ib_intr_pend(dip, sysino)) != DDI_SUCCESS) { 691 cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: pending " 692 "sysino 0x%lx(ino 0x%x) timeout", 693 ddi_driver_name(dip), ddi_get_instance(dip), 694 sysino, ino); 695 } 696 697 /* 698 * If the interrupt was previously blocked (left in pending state) 699 * because of jabber we need to clear the pending state in case the 700 * jabber has gone away. 701 */ 702 if (ret == DDI_SUCCESS && 703 ino_p->ino_unclaimed_intrs > px_unclaimed_intr_max) { 704 cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: " 705 "ino 0x%x has been unblocked", 706 ddi_driver_name(dip), ddi_get_instance(dip), ino); 707 708 ino_p->ino_unclaimed_intrs = 0; 709 ret = px_lib_intr_setstate(dip, sysino, INTR_IDLE_STATE); 710 } 711 712 if (ret != DDI_SUCCESS) { 713 DBG(DBG_IB, dip, "px_ib_ino_rem_intr: failed, " 714 "ino 0x%x sysino 0x%x\n", ino, sysino); 715 716 return (ret); 717 } 718 719 if (ipil_p->ipil_ih_size == 1) { 720 if (ih_lst != ih_p) 721 goto not_found; 722 723 /* No need to set head/tail as ino_p will be freed */ 724 goto reset; 725 } 726 727 /* Search the link list for ih_p */ 728 for (i = 0; (i < ipil_p->ipil_ih_size) && 729 (ih_lst->ih_next != ih_p); i++, ih_lst = ih_lst->ih_next) 730 ; 731 732 if (ih_lst->ih_next != ih_p) 733 goto not_found; 734 735 /* Remove ih_p from the link list and maintain the head/tail */ 736 ih_lst->ih_next = ih_p->ih_next; 737 738 if (ipil_p->ipil_ih_head == ih_p) 739 ipil_p->ipil_ih_head = ih_p->ih_next; 740 if (ipil_p->ipil_ih_tail == ih_p) 741 ipil_p->ipil_ih_tail = ih_lst; 742 743 ipil_p->ipil_ih_start = ipil_p->ipil_ih_head; 744 745 reset: 746 if (ih_p->ih_config_handle) 747 pci_config_teardown(&ih_p->ih_config_handle); 748 if (ih_p->ih_ksp != NULL) 749 kstat_delete(ih_p->ih_ksp); 750 751 kmem_free(ih_p, sizeof (px_ih_t)); 752 ipil_p->ipil_ih_size--; 753 754 return (ret); 755 756 not_found: 757 DBG(DBG_R_INTX, ino_p->ino_ib_p->ib_px_p->px_dip, 758 "ino_p=%x does not have ih_p=%x\n", ino_p, ih_p); 759 760 return (DDI_FAILURE); 761 } 762 763 px_ih_t * 764 px_ib_intr_locate_ih(px_ino_pil_t *ipil_p, dev_info_t *rdip, 765 uint32_t inum, msiq_rec_type_t rec_type, msgcode_t msg_code) 766 { 767 px_ih_t *ih_p = ipil_p->ipil_ih_head; 768 int i; 769 770 for (i = 0; i < ipil_p->ipil_ih_size; i++, ih_p = ih_p->ih_next) { 771 if ((ih_p->ih_dip == rdip) && (ih_p->ih_inum == inum) && 772 (ih_p->ih_rec_type == rec_type) && 773 (ih_p->ih_msg_code == msg_code)) 774 return (ih_p); 775 } 776 777 return ((px_ih_t *)NULL); 778 } 779 780 px_ih_t * 781 px_ib_alloc_ih(dev_info_t *rdip, uint32_t inum, 782 uint_t (*int_handler)(caddr_t int_handler_arg1, caddr_t int_handler_arg2), 783 caddr_t int_handler_arg1, caddr_t int_handler_arg2, 784 msiq_rec_type_t rec_type, msgcode_t msg_code) 785 { 786 px_ih_t *ih_p; 787 788 ih_p = kmem_alloc(sizeof (px_ih_t), KM_SLEEP); 789 ih_p->ih_dip = rdip; 790 ih_p->ih_inum = inum; 791 ih_p->ih_intr_state = PX_INTR_STATE_DISABLE; 792 ih_p->ih_intr_flags = PX_INTR_IDLE; 793 ih_p->ih_handler = int_handler; 794 ih_p->ih_handler_arg1 = int_handler_arg1; 795 ih_p->ih_handler_arg2 = int_handler_arg2; 796 ih_p->ih_config_handle = NULL; 797 ih_p->ih_rec_type = rec_type; 798 ih_p->ih_msg_code = msg_code; 799 ih_p->ih_nsec = 0; 800 ih_p->ih_ticks = 0; 801 ih_p->ih_ksp = NULL; 802 803 return (ih_p); 804 } 805 806 int 807 px_ib_update_intr_state(px_t *px_p, dev_info_t *rdip, 808 uint_t inum, devino_t ino, uint_t pil, 809 uint_t new_intr_state, msiq_rec_type_t rec_type, 810 msgcode_t msg_code) 811 { 812 px_ib_t *ib_p = px_p->px_ib_p; 813 px_ino_t *ino_p; 814 px_ino_pil_t *ipil_p; 815 px_ih_t *ih_p; 816 int ret = DDI_FAILURE; 817 818 DBG(DBG_IB, px_p->px_dip, "px_ib_update_intr_state: %s%d " 819 "inum %x devino %x pil %x state %x\n", ddi_driver_name(rdip), 820 ddi_get_instance(rdip), inum, ino, pil, new_intr_state); 821 822 mutex_enter(&ib_p->ib_ino_lst_mutex); 823 824 ino_p = px_ib_locate_ino(ib_p, ino); 825 if (ino_p && (ipil_p = px_ib_ino_locate_ipil(ino_p, pil))) { 826 if (ih_p = px_ib_intr_locate_ih(ipil_p, rdip, inum, rec_type, 827 msg_code)) { 828 ih_p->ih_intr_state = new_intr_state; 829 ret = DDI_SUCCESS; 830 } 831 } 832 833 mutex_exit(&ib_p->ib_ino_lst_mutex); 834 return (ret); 835 } 836 837 838 /* 839 * Get interrupt CPU for a given ino. 840 * Return info only for inos which are already mapped to devices. 841 */ 842 /*ARGSUSED*/ 843 int 844 px_ib_get_intr_target(px_t *px_p, devino_t ino, cpuid_t *cpu_id_p) 845 { 846 dev_info_t *dip = px_p->px_dip; 847 sysino_t sysino; 848 int ret; 849 850 DBG(DBG_IB, px_p->px_dip, "px_ib_get_intr_target: devino %x\n", ino); 851 852 /* Convert leaf-wide intr to system-wide intr */ 853 if (px_lib_intr_devino_to_sysino(dip, ino, &sysino) != DDI_SUCCESS) 854 return (DDI_FAILURE); 855 856 ret = px_lib_intr_gettarget(dip, sysino, cpu_id_p); 857 858 DBG(DBG_IB, px_p->px_dip, "px_ib_get_intr_target: cpu_id %x\n", 859 *cpu_id_p); 860 861 return (ret); 862 } 863 864 865 /* 866 * Associate a new CPU with a given ino. 867 * Operate only on INOs which are already mapped to devices. 868 */ 869 int 870 px_ib_set_intr_target(px_t *px_p, devino_t ino, cpuid_t cpu_id) 871 { 872 dev_info_t *dip = px_p->px_dip; 873 cpuid_t old_cpu_id; 874 sysino_t sysino; 875 int ret = DDI_SUCCESS; 876 extern const int _ncpu; 877 extern cpu_t *cpu[]; 878 879 DBG(DBG_IB, px_p->px_dip, "px_ib_set_intr_target: devino %x " 880 "cpu_id %x\n", ino, cpu_id); 881 882 mutex_enter(&cpu_lock); 883 884 /* Convert leaf-wide intr to system-wide intr */ 885 if (px_lib_intr_devino_to_sysino(dip, ino, &sysino) != DDI_SUCCESS) { 886 ret = DDI_FAILURE; 887 goto done; 888 } 889 890 if (px_lib_intr_gettarget(dip, sysino, &old_cpu_id) != DDI_SUCCESS) { 891 ret = DDI_FAILURE; 892 goto done; 893 } 894 895 /* 896 * Get lock, validate cpu and write it. 897 */ 898 if ((cpu_id < _ncpu) && (cpu[cpu_id] && cpu_is_online(cpu[cpu_id]))) { 899 DBG(DBG_IB, dip, "px_ib_set_intr_target: Enabling CPU %d\n", 900 cpu_id); 901 px_ib_intr_dist_en(dip, cpu_id, ino, B_TRUE); 902 px_ib_log_new_cpu(px_p->px_ib_p, old_cpu_id, cpu_id, ino); 903 } else { /* Invalid cpu */ 904 DBG(DBG_IB, dip, "px_ib_set_intr_target: Invalid cpuid %x\n", 905 cpu_id); 906 ret = DDI_EINVAL; 907 } 908 909 done: 910 mutex_exit(&cpu_lock); 911 return (ret); 912 } 913 914 hrtime_t px_ib_msix_retarget_timeout = 120ll * NANOSEC; /* 120 seconds */ 915 916 /* 917 * Associate a new CPU with a given MSI/X. 918 * Operate only on MSI/Xs which are already mapped to devices. 919 */ 920 int 921 px_ib_set_msix_target(px_t *px_p, ddi_intr_handle_impl_t *hdlp, 922 msinum_t msi_num, cpuid_t cpu_id) 923 { 924 px_ib_t *ib_p = px_p->px_ib_p; 925 px_msi_state_t *msi_state_p = &px_p->px_ib_p->ib_msi_state; 926 dev_info_t *dip = px_p->px_dip; 927 dev_info_t *rdip = hdlp->ih_dip; 928 msiqid_t msiq_id, old_msiq_id; 929 pci_msi_state_t msi_state; 930 msiq_rec_type_t msiq_rec_type; 931 msi_type_t msi_type; 932 px_ino_t *ino_p; 933 px_ih_t *ih_p, *old_ih_p; 934 cpuid_t old_cpu_id; 935 hrtime_t start_time, end_time; 936 int ret = DDI_SUCCESS; 937 extern const int _ncpu; 938 extern cpu_t *cpu[]; 939 940 DBG(DBG_IB, dip, "px_ib_set_msix_target: msi_num %x new cpu_id %x\n", 941 msi_num, cpu_id); 942 943 mutex_enter(&cpu_lock); 944 945 /* Check for MSI64 support */ 946 if ((hdlp->ih_cap & DDI_INTR_FLAG_MSI64) && msi_state_p->msi_addr64) { 947 msiq_rec_type = MSI64_REC; 948 msi_type = MSI64_TYPE; 949 } else { 950 msiq_rec_type = MSI32_REC; 951 msi_type = MSI32_TYPE; 952 } 953 954 if ((ret = px_lib_msi_getmsiq(dip, msi_num, 955 &old_msiq_id)) != DDI_SUCCESS) { 956 957 mutex_exit(&cpu_lock); 958 return (ret); 959 } 960 961 DBG(DBG_IB, dip, "px_ib_set_msix_target: current msiq 0x%x\n", 962 old_msiq_id); 963 964 if ((ret = px_ib_get_intr_target(px_p, 965 px_msiqid_to_devino(px_p, old_msiq_id), 966 &old_cpu_id)) != DDI_SUCCESS) { 967 968 mutex_exit(&cpu_lock); 969 return (ret); 970 } 971 972 DBG(DBG_IB, dip, "px_ib_set_msix_target: current cpuid 0x%x\n", 973 old_cpu_id); 974 975 if (cpu_id == old_cpu_id) { 976 977 mutex_exit(&cpu_lock); 978 return (DDI_SUCCESS); 979 } 980 981 /* 982 * Get lock, validate cpu and write it. 983 */ 984 if (!((cpu_id < _ncpu) && (cpu[cpu_id] && 985 cpu_is_online(cpu[cpu_id])))) { 986 /* Invalid cpu */ 987 DBG(DBG_IB, dip, "px_ib_set_msix_target: Invalid cpuid %x\n", 988 cpu_id); 989 990 mutex_exit(&cpu_lock); 991 return (DDI_EINVAL); 992 } 993 994 DBG(DBG_IB, dip, "px_ib_set_msix_target: Enabling CPU %d\n", cpu_id); 995 996 if ((ret = px_add_msiq_intr(dip, rdip, hdlp, 997 msiq_rec_type, msi_num, cpu_id, &msiq_id)) != DDI_SUCCESS) { 998 DBG(DBG_IB, dip, "px_ib_set_msix_target: Add MSI handler " 999 "failed, rdip 0x%p msi 0x%x\n", rdip, msi_num); 1000 1001 mutex_exit(&cpu_lock); 1002 return (ret); 1003 } 1004 1005 if ((ret = px_lib_msi_setmsiq(dip, msi_num, 1006 msiq_id, msi_type)) != DDI_SUCCESS) { 1007 mutex_exit(&cpu_lock); 1008 1009 (void) px_rem_msiq_intr(dip, rdip, 1010 hdlp, msiq_rec_type, msi_num, msiq_id); 1011 1012 return (ret); 1013 } 1014 1015 if ((ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum, 1016 px_msiqid_to_devino(px_p, msiq_id), hdlp->ih_pri, 1017 PX_INTR_STATE_ENABLE, msiq_rec_type, msi_num)) != DDI_SUCCESS) { 1018 mutex_exit(&cpu_lock); 1019 1020 (void) px_rem_msiq_intr(dip, rdip, 1021 hdlp, msiq_rec_type, msi_num, msiq_id); 1022 1023 return (ret); 1024 } 1025 1026 mutex_exit(&cpu_lock); 1027 1028 /* 1029 * Remove the old handler, but first ensure it is finished. 1030 * 1031 * Each handler sets its PENDING flag before it clears the MSI state. 1032 * Then it clears that flag when finished. If a re-target occurs while 1033 * the MSI state is DELIVERED, then it is not yet known which of the 1034 * two handlers will take the interrupt. So the re-target operation 1035 * sets a RETARGET flag on both handlers in that case. Monitoring both 1036 * flags on both handlers then determines when the old handler can be 1037 * be safely removed. 1038 */ 1039 mutex_enter(&ib_p->ib_ino_lst_mutex); 1040 1041 ino_p = px_ib_locate_ino(ib_p, px_msiqid_to_devino(px_p, old_msiq_id)); 1042 old_ih_p = px_ib_intr_locate_ih(px_ib_ino_locate_ipil(ino_p, 1043 hdlp->ih_pri), rdip, hdlp->ih_inum, msiq_rec_type, msi_num); 1044 1045 ino_p = px_ib_locate_ino(ib_p, px_msiqid_to_devino(px_p, msiq_id)); 1046 ih_p = px_ib_intr_locate_ih(px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri), 1047 rdip, hdlp->ih_inum, msiq_rec_type, msi_num); 1048 1049 if ((ret = px_lib_msi_getstate(dip, msi_num, 1050 &msi_state)) != DDI_SUCCESS) { 1051 (void) px_rem_msiq_intr(dip, rdip, 1052 hdlp, msiq_rec_type, msi_num, msiq_id); 1053 1054 mutex_exit(&ib_p->ib_ino_lst_mutex); 1055 return (ret); 1056 } 1057 1058 if (msi_state == PCI_MSI_STATE_DELIVERED) { 1059 ih_p->ih_intr_flags |= PX_INTR_RETARGET; 1060 old_ih_p->ih_intr_flags |= PX_INTR_RETARGET; 1061 } 1062 1063 start_time = gethrtime(); 1064 while (((ih_p->ih_intr_flags & PX_INTR_RETARGET) && 1065 (old_ih_p->ih_intr_flags & PX_INTR_RETARGET)) || 1066 (old_ih_p->ih_intr_flags & PX_INTR_PENDING)) { 1067 1068 /* Wait for one second */ 1069 delay(drv_usectohz(1000000)); 1070 1071 end_time = gethrtime() - start_time; 1072 if (end_time > px_ib_msix_retarget_timeout) { 1073 cmn_err(CE_WARN, "MSIX retarget %x is not completed, " 1074 "even after waiting %llx ticks\n", 1075 msi_num, end_time); 1076 break; 1077 } 1078 } 1079 1080 ih_p->ih_intr_flags &= ~(PX_INTR_RETARGET); 1081 1082 mutex_exit(&ib_p->ib_ino_lst_mutex); 1083 1084 ret = px_rem_msiq_intr(dip, rdip, 1085 hdlp, msiq_rec_type, msi_num, old_msiq_id); 1086 1087 return (ret); 1088 } 1089 1090 1091 static void 1092 px_fill_in_intr_devs(pcitool_intr_dev_t *dev, char *driver_name, 1093 char *path_name, int instance) 1094 { 1095 (void) strlcpy(dev->driver_name, driver_name, MAXMODCONFNAME); 1096 (void) strlcpy(dev->path, path_name, MAXPATHLEN); 1097 dev->dev_inst = instance; 1098 } 1099 1100 1101 /* 1102 * Return the dips or number of dips associated with a given interrupt block. 1103 * Size of dips array arg is passed in as dips_ret arg. 1104 * Number of dips returned is returned in dips_ret arg. 1105 * Array of dips gets returned in the dips argument. 1106 * Function returns number of dips existing for the given interrupt block. 1107 * 1108 * Note: this function assumes an enabled/valid INO, which is why it returns 1109 * the px node and (Internal) when it finds no other devices (and *devs_ret > 0) 1110 */ 1111 uint8_t 1112 pxtool_ib_get_ino_devs(px_t *px_p, uint32_t ino, uint32_t msi_num, 1113 uint8_t *devs_ret, pcitool_intr_dev_t *devs) 1114 { 1115 px_ib_t *ib_p = px_p->px_ib_p; 1116 px_ino_t *ino_p; 1117 px_ino_pil_t *ipil_p; 1118 px_ih_t *ih_p; 1119 uint32_t num_devs = 0; 1120 char pathname[MAXPATHLEN]; 1121 int i, j; 1122 1123 mutex_enter(&ib_p->ib_ino_lst_mutex); 1124 ino_p = px_ib_locate_ino(ib_p, ino); 1125 if (ino_p != NULL) { 1126 for (j = 0, ipil_p = ino_p->ino_ipil_p; ipil_p; 1127 ipil_p = ipil_p->ipil_next_p) { 1128 num_devs += ipil_p->ipil_ih_size; 1129 1130 for (i = 0, ih_p = ipil_p->ipil_ih_head; 1131 ((i < ipil_p->ipil_ih_size) && (i < *devs_ret)); 1132 i++, j++, ih_p = ih_p->ih_next) { 1133 (void) ddi_pathname(ih_p->ih_dip, pathname); 1134 1135 if (ih_p->ih_msg_code == msi_num) { 1136 num_devs = *devs_ret = 1; 1137 px_fill_in_intr_devs(&devs[0], 1138 (char *)ddi_driver_name( 1139 ih_p->ih_dip), pathname, 1140 ddi_get_instance(ih_p->ih_dip)); 1141 goto done; 1142 } 1143 1144 px_fill_in_intr_devs(&devs[j], 1145 (char *)ddi_driver_name(ih_p->ih_dip), 1146 pathname, ddi_get_instance(ih_p->ih_dip)); 1147 } 1148 } 1149 1150 *devs_ret = j; 1151 } else if (*devs_ret > 0) { 1152 (void) ddi_pathname(px_p->px_dip, pathname); 1153 strcat(pathname, " (Internal)"); 1154 px_fill_in_intr_devs(&devs[0], 1155 (char *)ddi_driver_name(px_p->px_dip), pathname, 1156 ddi_get_instance(px_p->px_dip)); 1157 num_devs = *devs_ret = 1; 1158 } 1159 1160 done: 1161 mutex_exit(&ib_p->ib_ino_lst_mutex); 1162 1163 return (num_devs); 1164 } 1165 1166 1167 int 1168 pxtool_ib_get_msi_info(px_t *px_p, devino_t ino, msinum_t msi_num, 1169 ddi_intr_handle_impl_t *hdlp) 1170 { 1171 px_ib_t *ib_p = px_p->px_ib_p; 1172 px_ino_t *ino_p; 1173 px_ino_pil_t *ipil_p; 1174 px_ih_t *ih_p; 1175 int i; 1176 1177 mutex_enter(&ib_p->ib_ino_lst_mutex); 1178 1179 if ((ino_p = px_ib_locate_ino(ib_p, ino)) == NULL) { 1180 mutex_exit(&ib_p->ib_ino_lst_mutex); 1181 return (DDI_FAILURE); 1182 } 1183 1184 for (ipil_p = ino_p->ino_ipil_p; ipil_p; 1185 ipil_p = ipil_p->ipil_next_p) { 1186 for (i = 0, ih_p = ipil_p->ipil_ih_head; 1187 ((i < ipil_p->ipil_ih_size) && ih_p); 1188 i++, ih_p = ih_p->ih_next) { 1189 1190 if (ih_p->ih_msg_code != msi_num) 1191 continue; 1192 1193 hdlp->ih_dip = ih_p->ih_dip; 1194 hdlp->ih_inum = ih_p->ih_inum; 1195 hdlp->ih_cb_func = ih_p->ih_handler; 1196 hdlp->ih_cb_arg1 = ih_p->ih_handler_arg1; 1197 hdlp->ih_cb_arg2 = ih_p->ih_handler_arg2; 1198 if (ih_p->ih_rec_type == MSI64_REC) 1199 hdlp->ih_cap = DDI_INTR_FLAG_MSI64; 1200 hdlp->ih_pri = ipil_p->ipil_pil; 1201 hdlp->ih_ver = DDI_INTR_VERSION; 1202 1203 mutex_exit(&ib_p->ib_ino_lst_mutex); 1204 return (DDI_SUCCESS); 1205 } 1206 } 1207 1208 mutex_exit(&ib_p->ib_ino_lst_mutex); 1209 return (DDI_FAILURE); 1210 } 1211 1212 void 1213 px_ib_log_new_cpu(px_ib_t *ib_p, cpuid_t old_cpu_id, cpuid_t new_cpu_id, 1214 uint32_t ino) 1215 { 1216 px_ino_t *ino_p; 1217 px_ino_pil_t *ipil_p; 1218 px_ih_t *ih_p; 1219 int i; 1220 1221 mutex_enter(&ib_p->ib_ino_lst_mutex); 1222 1223 /* Log in OS data structures the new CPU. */ 1224 if (ino_p = px_ib_locate_ino(ib_p, ino)) { 1225 1226 /* Log in OS data structures the new CPU. */ 1227 ino_p->ino_cpuid = new_cpu_id; 1228 1229 for (ipil_p = ino_p->ino_ipil_p; ipil_p; 1230 ipil_p = ipil_p->ipil_next_p) { 1231 for (i = 0, ih_p = ipil_p->ipil_ih_head; 1232 (i < ipil_p->ipil_ih_size); 1233 i++, ih_p = ih_p->ih_next) { 1234 /* 1235 * Account for any residual time 1236 * to be logged for old cpu. 1237 */ 1238 px_ib_cpu_ticks_to_ih_nsec(ib_p, 1239 ih_p, old_cpu_id); 1240 } 1241 } 1242 } 1243 1244 mutex_exit(&ib_p->ib_ino_lst_mutex); 1245 } 1246