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 /* 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 /* 26 * Copyright (c) 2010, Intel Corporation. 27 * All rights reserved. 28 */ 29 30 #include <sys/processor.h> 31 #include <sys/time.h> 32 #include <sys/psm.h> 33 #include <sys/smp_impldefs.h> 34 #include <sys/cram.h> 35 #include <sys/acpi/acpi.h> 36 #include <sys/acpica.h> 37 #include <sys/psm_common.h> 38 #include <sys/pit.h> 39 #include <sys/ddi.h> 40 #include <sys/sunddi.h> 41 #include <sys/ddi_impldefs.h> 42 #include <sys/pci.h> 43 #include <sys/promif.h> 44 #include <sys/x86_archext.h> 45 #include <sys/cpc_impl.h> 46 #include <sys/uadmin.h> 47 #include <sys/panic.h> 48 #include <sys/debug.h> 49 #include <sys/archsystm.h> 50 #include <sys/trap.h> 51 #include <sys/machsystm.h> 52 #include <sys/sysmacros.h> 53 #include <sys/cpuvar.h> 54 #include <sys/rm_platter.h> 55 #include <sys/privregs.h> 56 #include <sys/note.h> 57 #include <sys/pci_intr_lib.h> 58 #include <sys/spl.h> 59 #include <sys/clock.h> 60 #include <sys/dditypes.h> 61 #include <sys/sunddi.h> 62 #include <sys/x_call.h> 63 #include <sys/reboot.h> 64 #include <sys/apix.h> 65 66 static int apix_get_avail_vector_oncpu(uint32_t, int, int); 67 static apix_vector_t *apix_init_vector(processorid_t, uchar_t); 68 static void apix_cleanup_vector(apix_vector_t *); 69 static void apix_insert_av(apix_vector_t *, void *, avfunc, caddr_t, caddr_t, 70 uint64_t *, int, dev_info_t *); 71 static void apix_remove_av(apix_vector_t *, struct autovec *); 72 static void apix_clear_dev_map(dev_info_t *, int, int); 73 static boolean_t apix_is_cpu_enabled(processorid_t); 74 static void apix_wait_till_seen(processorid_t, int); 75 76 #define GET_INTR_INUM(ihdlp) \ 77 (((ihdlp) != NULL) ? ((ddi_intr_handle_impl_t *)(ihdlp))->ih_inum : 0) 78 79 apix_rebind_info_t apix_rebindinfo = {0, 0, 0, NULL, 0, NULL}; 80 81 /* 82 * Allocate IPI 83 * 84 * Return vector number or 0 on error 85 */ 86 uchar_t 87 apix_alloc_ipi(int ipl) 88 { 89 apix_vector_t *vecp; 90 uchar_t vector; 91 int cpun; 92 int nproc; 93 94 APIX_ENTER_CPU_LOCK(0); 95 96 vector = apix_get_avail_vector_oncpu(0, APIX_IPI_MIN, APIX_IPI_MAX); 97 if (vector == 0) { 98 APIX_LEAVE_CPU_LOCK(0); 99 cmn_err(CE_WARN, "apix: no available IPI\n"); 100 apic_error |= APIC_ERR_GET_IPIVECT_FAIL; 101 return (0); 102 } 103 104 nproc = max(apic_nproc, apic_max_nproc); 105 for (cpun = 0; cpun < nproc; cpun++) { 106 vecp = xv_vector(cpun, vector); 107 if (vecp == NULL) { 108 vecp = kmem_zalloc(sizeof (apix_vector_t), KM_NOSLEEP); 109 if (vecp == NULL) { 110 cmn_err(CE_WARN, "apix: No memory for ipi"); 111 goto fail; 112 } 113 xv_vector(cpun, vector) = vecp; 114 } 115 vecp->v_state = APIX_STATE_ALLOCED; 116 vecp->v_type = APIX_TYPE_IPI; 117 vecp->v_cpuid = vecp->v_bound_cpuid = cpun; 118 vecp->v_vector = vector; 119 vecp->v_pri = ipl; 120 } 121 APIX_LEAVE_CPU_LOCK(0); 122 return (vector); 123 124 fail: 125 while (--cpun >= 0) 126 apix_cleanup_vector(xv_vector(cpun, vector)); 127 APIX_LEAVE_CPU_LOCK(0); 128 return (0); 129 } 130 131 /* 132 * Add IPI service routine 133 */ 134 static int 135 apix_add_ipi(int ipl, avfunc xxintr, char *name, int vector, 136 caddr_t arg1, caddr_t arg2) 137 { 138 int cpun; 139 apix_vector_t *vecp; 140 int nproc; 141 142 ASSERT(vector >= APIX_IPI_MIN && vector <= APIX_IPI_MAX); 143 144 nproc = max(apic_nproc, apic_max_nproc); 145 for (cpun = 0; cpun < nproc; cpun++) { 146 APIX_ENTER_CPU_LOCK(cpun); 147 vecp = xv_vector(cpun, vector); 148 apix_insert_av(vecp, NULL, xxintr, arg1, arg2, NULL, ipl, NULL); 149 vecp->v_state = APIX_STATE_ENABLED; 150 APIX_LEAVE_CPU_LOCK(cpun); 151 } 152 153 APIC_VERBOSE(IPI, (CE_CONT, "apix: add ipi for %s, vector %x " 154 "ipl %x\n", name, vector, ipl)); 155 156 return (1); 157 } 158 159 /* 160 * Find and return first free vector in range (start, end) 161 */ 162 static int 163 apix_get_avail_vector_oncpu(uint32_t cpuid, int start, int end) 164 { 165 int i; 166 apix_impl_t *apixp = apixs[cpuid]; 167 168 for (i = start; i <= end; i++) { 169 if (APIC_CHECK_RESERVE_VECTORS(i)) 170 continue; 171 if (IS_VECT_FREE(apixp->x_vectbl[i])) 172 return (i); 173 } 174 175 return (0); 176 } 177 178 /* 179 * Allocate a vector on specified cpu 180 * 181 * Return NULL on error 182 */ 183 static apix_vector_t * 184 apix_alloc_vector_oncpu(uint32_t cpuid, dev_info_t *dip, int inum, int type) 185 { 186 processorid_t tocpu = cpuid & ~IRQ_USER_BOUND; 187 apix_vector_t *vecp; 188 int vector; 189 190 ASSERT(APIX_CPU_LOCK_HELD(tocpu)); 191 192 /* find free vector */ 193 vector = apix_get_avail_vector_oncpu(tocpu, APIX_AVINTR_MIN, 194 APIX_AVINTR_MAX); 195 if (vector == 0) 196 return (NULL); 197 198 vecp = apix_init_vector(tocpu, vector); 199 vecp->v_type = (ushort_t)type; 200 vecp->v_inum = inum; 201 vecp->v_flags = (cpuid & IRQ_USER_BOUND) ? APIX_VECT_USER_BOUND : 0; 202 203 if (dip != NULL) 204 apix_set_dev_map(vecp, dip, inum); 205 206 return (vecp); 207 } 208 209 /* 210 * Allocates "count" contiguous MSI vectors starting at the proper alignment. 211 * Caller needs to make sure that count has to be power of 2 and should not 212 * be < 1. 213 * 214 * Return first vector number 215 */ 216 apix_vector_t * 217 apix_alloc_nvectors_oncpu(uint32_t cpuid, dev_info_t *dip, int inum, 218 int count, int type) 219 { 220 int i, msibits, start = 0, navail = 0; 221 apix_vector_t *vecp, *startp = NULL; 222 processorid_t tocpu = cpuid & ~IRQ_USER_BOUND; 223 uint_t flags; 224 225 ASSERT(APIX_CPU_LOCK_HELD(tocpu)); 226 227 /* 228 * msibits is the no. of lower order message data bits for the 229 * allocated MSI vectors and is used to calculate the aligned 230 * starting vector 231 */ 232 msibits = count - 1; 233 234 /* It has to be contiguous */ 235 for (i = APIX_AVINTR_MIN; i <= APIX_AVINTR_MAX; i++) { 236 if (!IS_VECT_FREE(xv_vector(tocpu, i))) 237 continue; 238 239 /* 240 * starting vector has to be aligned accordingly for 241 * multiple MSIs 242 */ 243 if (msibits) 244 i = (i + msibits) & ~msibits; 245 246 for (navail = 0, start = i; i <= APIX_AVINTR_MAX; i++) { 247 if (!IS_VECT_FREE(xv_vector(tocpu, i))) 248 break; 249 if (APIC_CHECK_RESERVE_VECTORS(i)) 250 break; 251 if (++navail == count) 252 goto done; 253 } 254 } 255 256 return (NULL); 257 258 done: 259 flags = (cpuid & IRQ_USER_BOUND) ? APIX_VECT_USER_BOUND : 0; 260 261 for (i = 0; i < count; i++) { 262 if ((vecp = apix_init_vector(tocpu, start + i)) == NULL) 263 goto fail; 264 265 vecp->v_type = (ushort_t)type; 266 vecp->v_inum = inum + i; 267 vecp->v_flags = flags; 268 269 if (dip != NULL) 270 apix_set_dev_map(vecp, dip, inum + i); 271 272 if (i == 0) 273 startp = vecp; 274 } 275 276 return (startp); 277 278 fail: 279 while (i-- > 0) { /* Free allocated vectors */ 280 vecp = xv_vector(tocpu, start + i); 281 apix_clear_dev_map(dip, inum + i, type); 282 apix_cleanup_vector(vecp); 283 } 284 return (NULL); 285 } 286 287 #define APIX_WRITE_MSI_DATA(_hdl, _cap, _ctrl, _v)\ 288 do {\ 289 if ((_ctrl) & PCI_MSI_64BIT_MASK)\ 290 pci_config_put16((_hdl), (_cap) + PCI_MSI_64BIT_DATA, (_v));\ 291 else\ 292 pci_config_put16((_hdl), (_cap) + PCI_MSI_32BIT_DATA, (_v));\ 293 _NOTE(CONSTCOND)} while (0) 294 295 static void 296 apix_pci_msi_enable_vector(apix_vector_t *vecp, dev_info_t *dip, int type, 297 int inum, int count, uchar_t vector, int target_apic_id) 298 { 299 uint64_t msi_addr, msi_data; 300 ushort_t msi_ctrl; 301 int i, cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip); 302 ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(dip); 303 msi_regs_t msi_regs; 304 void *intrmap_tbl[PCI_MSI_MAX_INTRS]; 305 306 DDI_INTR_IMPLDBG((CE_CONT, "apix_pci_msi_enable_vector: dip=0x%p\n" 307 "\tdriver = %s, inum=0x%x vector=0x%x apicid=0x%x\n", (void *)dip, 308 ddi_driver_name(dip), inum, vector, target_apic_id)); 309 310 ASSERT((handle != NULL) && (cap_ptr != 0)); 311 312 msi_regs.mr_data = vector; 313 msi_regs.mr_addr = target_apic_id; 314 315 intrmap_tbl[0] = vecp->v_intrmap_private; 316 apic_vt_ops->apic_intrmap_alloc_entry(intrmap_tbl, dip, type, 317 count, 0xff); 318 for (i = 0; i < count; i++) 319 xv_intrmap_private(vecp->v_cpuid, vector + i) = intrmap_tbl[i]; 320 321 apic_vt_ops->apic_intrmap_map_entry(vecp->v_intrmap_private, 322 (void *)&msi_regs, type, count); 323 apic_vt_ops->apic_intrmap_record_msi(vecp->v_intrmap_private, 324 &msi_regs); 325 326 /* MSI Address */ 327 msi_addr = msi_regs.mr_addr; 328 329 /* MSI Data: MSI is edge triggered according to spec */ 330 msi_data = msi_regs.mr_data; 331 332 DDI_INTR_IMPLDBG((CE_CONT, "apix_pci_msi_enable_vector: addr=0x%lx " 333 "data=0x%lx\n", (long)msi_addr, (long)msi_data)); 334 335 if (type == APIX_TYPE_MSI) { 336 msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL); 337 338 /* Set the bits to inform how many MSIs are enabled */ 339 msi_ctrl |= ((highbit(count) - 1) << PCI_MSI_MME_SHIFT); 340 pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl); 341 342 if ((vecp->v_flags & APIX_VECT_MASKABLE) == 0) 343 APIX_WRITE_MSI_DATA(handle, cap_ptr, msi_ctrl, 344 APIX_RESV_VECTOR); 345 346 pci_config_put32(handle, 347 cap_ptr + PCI_MSI_ADDR_OFFSET, msi_addr); 348 if (msi_ctrl & PCI_MSI_64BIT_MASK) 349 pci_config_put32(handle, 350 cap_ptr + PCI_MSI_ADDR_OFFSET + 4, msi_addr >> 32); 351 352 APIX_WRITE_MSI_DATA(handle, cap_ptr, msi_ctrl, msi_data); 353 } else if (type == APIX_TYPE_MSIX) { 354 uintptr_t off; 355 ddi_intr_msix_t *msix_p = i_ddi_get_msix(dip); 356 357 /* Offset into the "inum"th entry in the MSI-X table */ 358 off = (uintptr_t)msix_p->msix_tbl_addr + 359 (inum * PCI_MSIX_VECTOR_SIZE); 360 361 ddi_put32(msix_p->msix_tbl_hdl, 362 (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), msi_data); 363 ddi_put64(msix_p->msix_tbl_hdl, 364 (uint64_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET), msi_addr); 365 } 366 } 367 368 static void 369 apix_pci_msi_enable_mode(dev_info_t *dip, int type, int inum) 370 { 371 ushort_t msi_ctrl; 372 int cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip); 373 ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(dip); 374 375 ASSERT((handle != NULL) && (cap_ptr != 0)); 376 377 if (type == APIX_TYPE_MSI) { 378 msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL); 379 if ((msi_ctrl & PCI_MSI_ENABLE_BIT)) 380 return; 381 382 msi_ctrl |= PCI_MSI_ENABLE_BIT; 383 pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl); 384 385 } else if (type == DDI_INTR_TYPE_MSIX) { 386 uintptr_t off; 387 uint32_t mask; 388 ddi_intr_msix_t *msix_p; 389 390 msix_p = i_ddi_get_msix(dip); 391 392 /* Offset into "inum"th entry in the MSI-X table & clear mask */ 393 off = (uintptr_t)msix_p->msix_tbl_addr + (inum * 394 PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET; 395 396 mask = ddi_get32(msix_p->msix_tbl_hdl, (uint32_t *)off); 397 398 ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, (mask & ~1)); 399 400 msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSIX_CTRL); 401 402 if (!(msi_ctrl & PCI_MSIX_ENABLE_BIT)) { 403 msi_ctrl |= PCI_MSIX_ENABLE_BIT; 404 pci_config_put16(handle, cap_ptr + PCI_MSIX_CTRL, 405 msi_ctrl); 406 } 407 } 408 } 409 410 /* 411 * Setup interrupt, pogramming IO-APIC or MSI/X address/data. 412 */ 413 void 414 apix_enable_vector(apix_vector_t *vecp) 415 { 416 int tocpu = vecp->v_cpuid, type = vecp->v_type; 417 apic_cpus_info_t *cpu_infop; 418 ulong_t iflag; 419 420 ASSERT(tocpu < apic_nproc); 421 422 cpu_infop = &apic_cpus[tocpu]; 423 if (vecp->v_flags & APIX_VECT_USER_BOUND) 424 cpu_infop->aci_bound++; 425 else 426 cpu_infop->aci_temp_bound++; 427 428 iflag = intr_clear(); 429 lock_set(&apic_ioapic_lock); 430 431 if (!DDI_INTR_IS_MSI_OR_MSIX(type)) { /* fixed */ 432 apix_intx_enable(vecp->v_inum); 433 } else { 434 int inum = vecp->v_inum; 435 dev_info_t *dip = APIX_GET_DIP(vecp); 436 int count = i_ddi_intr_get_current_nintrs(dip); 437 438 if (type == APIX_TYPE_MSI) { /* MSI */ 439 if (inum == apix_get_max_dev_inum(dip, type)) { 440 /* last one */ 441 uchar_t start_inum = inum + 1 - count; 442 uchar_t start_vect = vecp->v_vector + 1 - count; 443 apix_vector_t *start_vecp = 444 xv_vector(vecp->v_cpuid, start_vect); 445 446 APIC_VERBOSE(INTR, (CE_CONT, "apix: call " 447 "apix_pci_msi_enable_vector\n")); 448 apix_pci_msi_enable_vector(start_vecp, dip, 449 type, start_inum, count, start_vect, 450 cpu_infop->aci_local_id); 451 452 APIC_VERBOSE(INTR, (CE_CONT, "apix: call " 453 "apix_pci_msi_enable_mode\n")); 454 apix_pci_msi_enable_mode(dip, type, inum); 455 } 456 } else { /* MSI-X */ 457 apix_pci_msi_enable_vector(vecp, dip, 458 type, inum, 1, vecp->v_vector, 459 cpu_infop->aci_local_id); 460 apix_pci_msi_enable_mode(dip, type, inum); 461 } 462 } 463 vecp->v_state = APIX_STATE_ENABLED; 464 apic_redist_cpu_skip &= ~(1 << tocpu); 465 466 lock_clear(&apic_ioapic_lock); 467 intr_restore(iflag); 468 } 469 470 /* 471 * Disable the interrupt 472 */ 473 void 474 apix_disable_vector(apix_vector_t *vecp) 475 { 476 struct autovec *avp = vecp->v_autovect; 477 ulong_t iflag; 478 479 ASSERT(avp != NULL); 480 481 iflag = intr_clear(); 482 lock_set(&apic_ioapic_lock); 483 484 switch (vecp->v_type) { 485 case APIX_TYPE_MSI: 486 ASSERT(avp->av_vector != NULL && avp->av_dip != NULL); 487 /* 488 * Disable the MSI vector 489 * Make sure we only disable on the last 490 * of the multi-MSI support 491 */ 492 if (i_ddi_intr_get_current_nenables(avp->av_dip) == 1) { 493 apic_pci_msi_disable_mode(avp->av_dip, 494 DDI_INTR_TYPE_MSI); 495 } 496 break; 497 case APIX_TYPE_MSIX: 498 ASSERT(avp->av_vector != NULL && avp->av_dip != NULL); 499 /* 500 * Disable the MSI-X vector 501 * needs to clear its mask and addr/data for each MSI-X 502 */ 503 apic_pci_msi_unconfigure(avp->av_dip, DDI_INTR_TYPE_MSIX, 504 vecp->v_inum); 505 /* 506 * Make sure we only disable on the last MSI-X 507 */ 508 if (i_ddi_intr_get_current_nenables(avp->av_dip) == 1) { 509 apic_pci_msi_disable_mode(avp->av_dip, 510 DDI_INTR_TYPE_MSIX); 511 } 512 break; 513 default: 514 apix_intx_disable(vecp->v_inum); 515 break; 516 } 517 518 if (!(apic_cpus[vecp->v_cpuid].aci_status & APIC_CPU_SUSPEND)) 519 vecp->v_state = APIX_STATE_DISABLED; 520 apic_vt_ops->apic_intrmap_free_entry(&vecp->v_intrmap_private); 521 vecp->v_intrmap_private = NULL; 522 523 lock_clear(&apic_ioapic_lock); 524 intr_restore(iflag); 525 } 526 527 /* 528 * Mark vector as obsoleted or freed. The vector is marked 529 * obsoleted if there are pending requests on it. Otherwise, 530 * free the vector. The obsoleted vectors get freed after 531 * being serviced. 532 * 533 * Return 1 on being obosoleted and 0 on being freed. 534 */ 535 #define INTR_BUSY(_avp)\ 536 ((((volatile ushort_t)(_avp)->av_flags) &\ 537 (AV_PENTRY_PEND | AV_PENTRY_ONPROC)) != 0) 538 #define LOCAL_WITH_INTR_DISABLED(_cpuid)\ 539 ((_cpuid) == psm_get_cpu_id() && !interrupts_enabled()) 540 static uint64_t dummy_tick; 541 542 int 543 apix_obsolete_vector(apix_vector_t *vecp) 544 { 545 struct autovec *avp = vecp->v_autovect; 546 int repeats, tries, ipl, busy = 0, cpuid = vecp->v_cpuid; 547 apix_impl_t *apixp = apixs[cpuid]; 548 549 ASSERT(APIX_CPU_LOCK_HELD(cpuid)); 550 551 for (avp = vecp->v_autovect; avp != NULL; avp = avp->av_link) { 552 if (avp->av_vector == NULL) 553 continue; 554 555 if (LOCAL_WITH_INTR_DISABLED(cpuid)) { 556 int bit, index, irr; 557 558 if (INTR_BUSY(avp)) { 559 busy++; 560 continue; 561 } 562 563 /* check IRR for pending interrupts */ 564 index = vecp->v_vector / 32; 565 bit = vecp->v_vector % 32; 566 irr = apic_reg_ops->apic_read(APIC_IRR_REG + index); 567 if ((irr & (1 << bit)) != 0) 568 busy++; 569 570 if (!busy) 571 apix_remove_av(vecp, avp); 572 573 continue; 574 } 575 576 repeats = 0; 577 do { 578 repeats++; 579 for (tries = 0; tries < apic_max_reps_clear_pending; 580 tries++) 581 if (!INTR_BUSY(avp)) 582 break; 583 } while (INTR_BUSY(avp) && 584 (repeats < apic_max_reps_clear_pending)); 585 586 if (INTR_BUSY(avp)) 587 busy++; 588 else { 589 /* 590 * Interrupt is not in pending list or being serviced. 591 * However it might be cached in Local APIC's IRR 592 * register. It's impossible to check another CPU's 593 * IRR register. Then wait till lower levels finish 594 * running. 595 */ 596 for (ipl = 1; ipl < MIN(LOCK_LEVEL, vecp->v_pri); ipl++) 597 apix_wait_till_seen(cpuid, ipl); 598 if (INTR_BUSY(avp)) 599 busy++; 600 } 601 602 if (!busy) 603 apix_remove_av(vecp, avp); 604 } 605 606 if (busy) { 607 apix_vector_t *tp = apixp->x_obsoletes; 608 609 if (vecp->v_state == APIX_STATE_OBSOLETED) 610 return (1); 611 612 vecp->v_state = APIX_STATE_OBSOLETED; 613 vecp->v_next = NULL; 614 if (tp == NULL) 615 apixp->x_obsoletes = vecp; 616 else { 617 while (tp->v_next != NULL) 618 tp = tp->v_next; 619 tp->v_next = vecp; 620 } 621 return (1); 622 } 623 624 /* interrupt is not busy */ 625 if (vecp->v_state == APIX_STATE_OBSOLETED) { 626 /* remove from obsoleted list */ 627 apixp->x_obsoletes = vecp->v_next; 628 vecp->v_next = NULL; 629 } 630 apix_cleanup_vector(vecp); 631 return (0); 632 } 633 634 /* 635 * Duplicate number of continuous vectors to specified target vectors. 636 */ 637 static void 638 apix_dup_vectors(apix_vector_t *oldp, apix_vector_t *newp, int count) 639 { 640 struct autovec *avp; 641 apix_vector_t *fromp, *top; 642 processorid_t oldcpu = oldp->v_cpuid, newcpu = newp->v_cpuid; 643 uchar_t oldvec = oldp->v_vector, newvec = newp->v_vector; 644 int i, inum; 645 646 ASSERT(oldp->v_type != APIX_TYPE_IPI); 647 648 for (i = 0; i < count; i++) { 649 fromp = xv_vector(oldcpu, oldvec + i); 650 top = xv_vector(newcpu, newvec + i); 651 ASSERT(fromp != NULL && top != NULL); 652 653 /* copy over original one */ 654 top->v_state = fromp->v_state; 655 top->v_type = fromp->v_type; 656 top->v_bound_cpuid = fromp->v_bound_cpuid; 657 top->v_inum = fromp->v_inum; 658 top->v_flags = fromp->v_flags; 659 top->v_intrmap_private = fromp->v_intrmap_private; 660 661 for (avp = fromp->v_autovect; avp != NULL; avp = avp->av_link) { 662 if (avp->av_vector == NULL) 663 continue; 664 665 apix_insert_av(top, avp->av_intr_id, avp->av_vector, 666 avp->av_intarg1, avp->av_intarg2, avp->av_ticksp, 667 avp->av_prilevel, avp->av_dip); 668 669 if (fromp->v_type == APIX_TYPE_FIXED && 670 avp->av_dip != NULL) { 671 inum = GET_INTR_INUM(avp->av_intr_id); 672 apix_set_dev_map(top, avp->av_dip, inum); 673 } 674 } 675 676 if (DDI_INTR_IS_MSI_OR_MSIX(fromp->v_type) && 677 fromp->v_devp != NULL) 678 apix_set_dev_map(top, fromp->v_devp->dv_dip, 679 fromp->v_devp->dv_inum); 680 } 681 } 682 683 static apix_vector_t * 684 apix_init_vector(processorid_t cpuid, uchar_t vector) 685 { 686 apix_impl_t *apixp = apixs[cpuid]; 687 apix_vector_t *vecp = apixp->x_vectbl[vector]; 688 689 ASSERT(IS_VECT_FREE(vecp)); 690 691 if (vecp == NULL) { 692 vecp = kmem_zalloc(sizeof (apix_vector_t), KM_NOSLEEP); 693 if (vecp == NULL) { 694 cmn_err(CE_WARN, "apix: no memory to allocate vector"); 695 return (NULL); 696 } 697 apixp->x_vectbl[vector] = vecp; 698 } 699 vecp->v_state = APIX_STATE_ALLOCED; 700 vecp->v_cpuid = vecp->v_bound_cpuid = cpuid; 701 vecp->v_vector = vector; 702 703 return (vecp); 704 } 705 706 static void 707 apix_cleanup_vector(apix_vector_t *vecp) 708 { 709 ASSERT(vecp->v_share == 0); 710 vecp->v_bound_cpuid = IRQ_UNINIT; 711 vecp->v_state = APIX_STATE_FREED; 712 vecp->v_type = 0; 713 vecp->v_flags = 0; 714 vecp->v_busy = 0; 715 vecp->v_intrmap_private = NULL; 716 } 717 718 static void 719 apix_dprint_vector(apix_vector_t *vecp, dev_info_t *dip, int count) 720 { 721 #ifdef DEBUG 722 major_t major; 723 char *name, *drv_name; 724 int instance, len, t_len; 725 char mesg[1024] = "apix: "; 726 727 t_len = sizeof (mesg); 728 len = strlen(mesg); 729 if (dip != NULL) { 730 name = ddi_get_name(dip); 731 major = ddi_name_to_major(name); 732 drv_name = ddi_major_to_name(major); 733 instance = ddi_get_instance(dip); 734 (void) snprintf(mesg + len, t_len - len, "%s (%s) instance %d ", 735 name, drv_name, instance); 736 } 737 len = strlen(mesg); 738 739 switch (vecp->v_type) { 740 case APIX_TYPE_FIXED: 741 (void) snprintf(mesg + len, t_len - len, "irqno %d", 742 vecp->v_inum); 743 break; 744 case APIX_TYPE_MSI: 745 (void) snprintf(mesg + len, t_len - len, 746 "msi inum %d (count %d)", vecp->v_inum, count); 747 break; 748 case APIX_TYPE_MSIX: 749 (void) snprintf(mesg + len, t_len - len, "msi-x inum %d", 750 vecp->v_inum); 751 break; 752 default: 753 break; 754 755 } 756 757 APIC_VERBOSE(ALLOC, (CE_CONT, "%s allocated with vector 0x%x on " 758 "cpu %d\n", mesg, vecp->v_vector, vecp->v_cpuid)); 759 #endif /* DEBUG */ 760 } 761 762 /* 763 * Operations on avintr 764 */ 765 766 #define INIT_AUTOVEC(p, intr_id, f, arg1, arg2, ticksp, ipl, dip) \ 767 do { \ 768 (p)->av_intr_id = intr_id; \ 769 (p)->av_vector = f; \ 770 (p)->av_intarg1 = arg1; \ 771 (p)->av_intarg2 = arg2; \ 772 (p)->av_ticksp = ticksp; \ 773 (p)->av_prilevel = ipl; \ 774 (p)->av_dip = dip; \ 775 (p)->av_flags = 0; \ 776 _NOTE(CONSTCOND)} while (0) 777 778 /* 779 * Insert an interrupt service routine into chain by its priority from 780 * high to low 781 */ 782 static void 783 apix_insert_av(apix_vector_t *vecp, void *intr_id, avfunc f, caddr_t arg1, 784 caddr_t arg2, uint64_t *ticksp, int ipl, dev_info_t *dip) 785 { 786 struct autovec *p, *prep, *mem; 787 788 APIC_VERBOSE(INTR, (CE_CONT, "apix_insert_av: dip %p, vector 0x%x, " 789 "cpu %d\n", (void *)dip, vecp->v_vector, vecp->v_cpuid)); 790 791 mem = kmem_zalloc(sizeof (struct autovec), KM_SLEEP); 792 INIT_AUTOVEC(mem, intr_id, f, arg1, arg2, ticksp, ipl, dip); 793 if (vecp->v_type == APIX_TYPE_FIXED && apic_level_intr[vecp->v_inum]) 794 mem->av_flags |= AV_PENTRY_LEVEL; 795 796 vecp->v_share++; 797 vecp->v_pri = (ipl > vecp->v_pri) ? ipl : vecp->v_pri; 798 if (vecp->v_autovect == NULL) { /* Nothing on list - put it at head */ 799 vecp->v_autovect = mem; 800 return; 801 } 802 803 if (DDI_INTR_IS_MSI_OR_MSIX(vecp->v_type)) { /* MSI/X */ 804 ASSERT(vecp->v_share == 1); /* No sharing for MSI/X */ 805 806 INIT_AUTOVEC(vecp->v_autovect, intr_id, f, arg1, arg2, ticksp, 807 ipl, dip); 808 prep = vecp->v_autovect->av_link; 809 vecp->v_autovect->av_link = NULL; 810 811 /* Free the following autovect chain */ 812 while (prep != NULL) { 813 ASSERT(prep->av_vector == NULL); 814 815 p = prep; 816 prep = prep->av_link; 817 kmem_free(p, sizeof (struct autovec)); 818 } 819 820 kmem_free(mem, sizeof (struct autovec)); 821 return; 822 } 823 824 /* find where it goes in list */ 825 prep = NULL; 826 for (p = vecp->v_autovect; p != NULL; p = p->av_link) { 827 if (p->av_vector && p->av_prilevel <= ipl) 828 break; 829 prep = p; 830 } 831 if (prep != NULL) { 832 if (prep->av_vector == NULL) { /* freed struct available */ 833 INIT_AUTOVEC(prep, intr_id, f, arg1, arg2, 834 ticksp, ipl, dip); 835 prep->av_flags = mem->av_flags; 836 kmem_free(mem, sizeof (struct autovec)); 837 return; 838 } 839 840 mem->av_link = prep->av_link; 841 prep->av_link = mem; 842 } else { 843 /* insert new intpt at beginning of chain */ 844 mem->av_link = vecp->v_autovect; 845 vecp->v_autovect = mem; 846 } 847 } 848 849 /* 850 * After having made a change to an autovector list, wait until we have 851 * seen specified cpu not executing an interrupt at that level--so we 852 * know our change has taken effect completely (no old state in registers, 853 * etc). 854 */ 855 #define APIX_CPU_ENABLED(_cp) \ 856 (quiesce_active == 0 && \ 857 (((_cp)->cpu_flags & (CPU_QUIESCED|CPU_OFFLINE)) == 0)) 858 859 static void 860 apix_wait_till_seen(processorid_t cpuid, int ipl) 861 { 862 struct cpu *cp = cpu[cpuid]; 863 864 if (cp == NULL || LOCAL_WITH_INTR_DISABLED(cpuid)) 865 return; 866 867 /* 868 * Don't wait if the CPU is quiesced or offlined. This can happen 869 * when a CPU is running pause thread but hardware triggered an 870 * interrupt and the interrupt gets queued. 871 */ 872 for (;;) { 873 if (!INTR_ACTIVE((volatile struct cpu *)cpu[cpuid], ipl) && 874 (!APIX_CPU_ENABLED(cp) || 875 !INTR_PENDING((volatile apix_impl_t *)apixs[cpuid], ipl))) 876 return; 877 } 878 } 879 880 static void 881 apix_remove_av(apix_vector_t *vecp, struct autovec *target) 882 { 883 int hi_pri = 0; 884 struct autovec *p; 885 886 if (target == NULL) 887 return; 888 889 APIC_VERBOSE(INTR, (CE_CONT, "apix_remove_av: dip %p, vector 0x%x, " 890 "cpu %d\n", (void *)target->av_dip, vecp->v_vector, vecp->v_cpuid)); 891 892 for (p = vecp->v_autovect; p; p = p->av_link) { 893 if (p == target || p->av_vector == NULL) 894 continue; 895 hi_pri = (p->av_prilevel > hi_pri) ? p->av_prilevel : hi_pri; 896 } 897 898 vecp->v_share--; 899 vecp->v_pri = hi_pri; 900 901 /* 902 * This drops the handler from the chain, it can no longer be called. 903 * However, there is no guarantee that the handler is not currently 904 * still executing. 905 */ 906 target->av_vector = NULL; 907 /* 908 * There is a race where we could be just about to pick up the ticksp 909 * pointer to increment it after returning from the service routine 910 * in av_dispatch_autovect. Rather than NULL it out let's just point 911 * it off to something safe so that any final tick update attempt 912 * won't fault. 913 */ 914 target->av_ticksp = &dummy_tick; 915 apix_wait_till_seen(vecp->v_cpuid, target->av_prilevel); 916 } 917 918 static struct autovec * 919 apix_find_av(apix_vector_t *vecp, void *intr_id, avfunc f) 920 { 921 struct autovec *p; 922 923 for (p = vecp->v_autovect; p; p = p->av_link) { 924 if ((p->av_vector == f) && (p->av_intr_id == intr_id)) { 925 /* found the handler */ 926 return (p); 927 } 928 } 929 930 return (NULL); 931 } 932 933 static apix_vector_t * 934 apix_find_vector_by_avintr(void *intr_id, avfunc f) 935 { 936 apix_vector_t *vecp; 937 processorid_t n; 938 uchar_t v; 939 940 for (n = 0; n < apic_nproc; n++) { 941 if (!apix_is_cpu_enabled(n)) 942 continue; 943 944 for (v = APIX_AVINTR_MIN; v <= APIX_AVINTR_MIN; v++) { 945 vecp = xv_vector(n, v); 946 if (vecp == NULL || 947 vecp->v_state <= APIX_STATE_OBSOLETED) 948 continue; 949 950 if (apix_find_av(vecp, intr_id, f) != NULL) 951 return (vecp); 952 } 953 } 954 955 return (NULL); 956 } 957 958 /* 959 * Add interrupt service routine. 960 * 961 * For legacy interrupts (HPET timer, ACPI SCI), the vector is actually 962 * IRQ no. A vector is then allocated. Otherwise, the vector is already 963 * allocated. The input argument virt_vect is virtual vector of format 964 * APIX_VIRTVEC_VECTOR(cpuid, vector). 965 * 966 * Return 1 on success, 0 on failure. 967 */ 968 int 969 apix_add_avintr(void *intr_id, int ipl, avfunc xxintr, char *name, 970 int virt_vect, caddr_t arg1, caddr_t arg2, uint64_t *ticksp, 971 dev_info_t *dip) 972 { 973 int cpuid; 974 uchar_t v = (uchar_t)APIX_VIRTVEC_VECTOR(virt_vect); 975 apix_vector_t *vecp; 976 977 if (xxintr == NULL) { 978 cmn_err(CE_WARN, "Attempt to add null for %s " 979 "on vector 0x%x,0x%x", name, 980 APIX_VIRTVEC_CPU(virt_vect), 981 APIX_VIRTVEC_VECTOR(virt_vect)); 982 return (0); 983 } 984 985 if (v >= APIX_IPI_MIN) /* IPIs */ 986 return (apix_add_ipi(ipl, xxintr, name, v, arg1, arg2)); 987 988 if (!APIX_IS_VIRTVEC(virt_vect)) { /* got irq */ 989 int irqno = virt_vect; 990 int inum = GET_INTR_INUM(intr_id); 991 992 /* 993 * Senarios include: 994 * a. add_avintr() is called before irqp initialized (legacy) 995 * b. irqp is initialized, vector is not allocated (fixed) 996 * c. irqp is initialized, vector is allocated (fixed & shared) 997 */ 998 if ((vecp = apix_alloc_intx(dip, inum, irqno)) == NULL) 999 return (0); 1000 1001 cpuid = vecp->v_cpuid; 1002 v = vecp->v_vector; 1003 virt_vect = APIX_VIRTVECTOR(cpuid, v); 1004 } else { /* got virtual vector */ 1005 cpuid = APIX_VIRTVEC_CPU(virt_vect); 1006 vecp = xv_vector(cpuid, v); 1007 ASSERT(vecp != NULL); 1008 } 1009 1010 lock_set(&apix_lock); 1011 if (vecp->v_state <= APIX_STATE_OBSOLETED) { 1012 vecp = NULL; 1013 1014 /* 1015 * Basically the allocated but not enabled interrupts 1016 * will not get re-targeted. But MSIs in allocated state 1017 * could be re-targeted due to group re-targeting. 1018 */ 1019 if (intr_id != NULL && dip != NULL) { 1020 ddi_intr_handle_impl_t *hdlp = intr_id; 1021 vecp = apix_get_dev_map(dip, hdlp->ih_inum, 1022 hdlp->ih_type); 1023 ASSERT(vecp->v_state == APIX_STATE_ALLOCED); 1024 } 1025 if (vecp == NULL) { 1026 lock_clear(&apix_lock); 1027 cmn_err(CE_WARN, "Invalid interrupt 0x%x,0x%x " 1028 " for %p to add", cpuid, v, intr_id); 1029 return (0); 1030 } 1031 cpuid = vecp->v_cpuid; 1032 virt_vect = APIX_VIRTVECTOR(cpuid, vecp->v_vector); 1033 } 1034 1035 APIX_ENTER_CPU_LOCK(cpuid); 1036 apix_insert_av(vecp, intr_id, xxintr, arg1, arg2, ticksp, ipl, dip); 1037 APIX_LEAVE_CPU_LOCK(cpuid); 1038 1039 (void) apix_addspl(virt_vect, ipl, 0, 0); 1040 1041 lock_clear(&apix_lock); 1042 1043 return (1); 1044 } 1045 1046 /* 1047 * Remove avintr 1048 * 1049 * For fixed, if it's the last one of shared interrupts, free the vector. 1050 * For msi/x, only disable the interrupt but not free the vector, which 1051 * is freed by PSM_XXX_FREE_XXX. 1052 */ 1053 void 1054 apix_rem_avintr(void *intr_id, int ipl, avfunc xxintr, int virt_vect) 1055 { 1056 avfunc f; 1057 apix_vector_t *vecp; 1058 struct autovec *avp; 1059 processorid_t cpuid; 1060 1061 if ((f = xxintr) == NULL) 1062 return; 1063 1064 lock_set(&apix_lock); 1065 1066 if (!APIX_IS_VIRTVEC(virt_vect)) { /* got irq */ 1067 vecp = apix_intx_get_vector(virt_vect); 1068 virt_vect = APIX_VIRTVECTOR(vecp->v_cpuid, vecp->v_vector); 1069 } else /* got virtual vector */ 1070 vecp = xv_vector(APIX_VIRTVEC_CPU(virt_vect), 1071 APIX_VIRTVEC_VECTOR(virt_vect)); 1072 1073 if (vecp == NULL) { 1074 lock_clear(&apix_lock); 1075 cmn_err(CE_CONT, "Invalid interrupt 0x%x,0x%x to remove", 1076 APIX_VIRTVEC_CPU(virt_vect), 1077 APIX_VIRTVEC_VECTOR(virt_vect)); 1078 return; 1079 } 1080 1081 if (vecp->v_state <= APIX_STATE_OBSOLETED || 1082 ((avp = apix_find_av(vecp, intr_id, f)) == NULL)) { 1083 /* 1084 * It's possible that the interrupt is rebound to a 1085 * different cpu before rem_avintr() is called. Search 1086 * through all vectors once it happens. 1087 */ 1088 if ((vecp = apix_find_vector_by_avintr(intr_id, f)) 1089 == NULL) { 1090 lock_clear(&apix_lock); 1091 cmn_err(CE_CONT, "Unknown interrupt 0x%x,0x%x " 1092 "for %p to remove", APIX_VIRTVEC_CPU(virt_vect), 1093 APIX_VIRTVEC_VECTOR(virt_vect), intr_id); 1094 return; 1095 } 1096 virt_vect = APIX_VIRTVECTOR(vecp->v_cpuid, vecp->v_vector); 1097 avp = apix_find_av(vecp, intr_id, f); 1098 } 1099 cpuid = vecp->v_cpuid; 1100 1101 /* disable interrupt */ 1102 (void) apix_delspl(virt_vect, ipl, 0, 0); 1103 1104 /* remove ISR entry */ 1105 APIX_ENTER_CPU_LOCK(cpuid); 1106 apix_remove_av(vecp, avp); 1107 APIX_LEAVE_CPU_LOCK(cpuid); 1108 1109 lock_clear(&apix_lock); 1110 } 1111 1112 /* 1113 * Device to vector mapping table 1114 */ 1115 1116 static void 1117 apix_clear_dev_map(dev_info_t *dip, int inum, int type) 1118 { 1119 char *name; 1120 major_t major; 1121 apix_dev_vector_t *dvp, *prev = NULL; 1122 int found = 0; 1123 1124 name = ddi_get_name(dip); 1125 major = ddi_name_to_major(name); 1126 1127 mutex_enter(&apix_mutex); 1128 1129 for (dvp = apix_dev_vector[major]; dvp != NULL; 1130 prev = dvp, dvp = dvp->dv_next) { 1131 if (dvp->dv_dip == dip && dvp->dv_inum == inum && 1132 dvp->dv_type == type) { 1133 found++; 1134 break; 1135 } 1136 } 1137 1138 if (!found) { 1139 mutex_exit(&apix_mutex); 1140 return; 1141 } 1142 1143 if (prev != NULL) 1144 prev->dv_next = dvp->dv_next; 1145 1146 if (apix_dev_vector[major] == dvp) 1147 apix_dev_vector[major] = dvp->dv_next; 1148 1149 dvp->dv_vector->v_devp = NULL; 1150 1151 mutex_exit(&apix_mutex); 1152 1153 kmem_free(dvp, sizeof (apix_dev_vector_t)); 1154 } 1155 1156 void 1157 apix_set_dev_map(apix_vector_t *vecp, dev_info_t *dip, int inum) 1158 { 1159 apix_dev_vector_t *dvp; 1160 char *name; 1161 major_t major; 1162 uint32_t found = 0; 1163 1164 ASSERT(dip != NULL); 1165 name = ddi_get_name(dip); 1166 major = ddi_name_to_major(name); 1167 1168 mutex_enter(&apix_mutex); 1169 1170 for (dvp = apix_dev_vector[major]; dvp != NULL; 1171 dvp = dvp->dv_next) { 1172 if (dvp->dv_dip == dip && dvp->dv_inum == inum && 1173 dvp->dv_type == vecp->v_type) { 1174 found++; 1175 break; 1176 } 1177 } 1178 1179 if (found == 0) { /* not found */ 1180 dvp = kmem_zalloc(sizeof (apix_dev_vector_t), KM_SLEEP); 1181 dvp->dv_dip = dip; 1182 dvp->dv_inum = inum; 1183 dvp->dv_type = vecp->v_type; 1184 1185 dvp->dv_next = apix_dev_vector[major]; 1186 apix_dev_vector[major] = dvp; 1187 } 1188 dvp->dv_vector = vecp; 1189 vecp->v_devp = dvp; 1190 1191 mutex_exit(&apix_mutex); 1192 1193 DDI_INTR_IMPLDBG((CE_CONT, "apix_set_dev_map: dip=0x%p " 1194 "inum=0x%x vector=0x%x/0x%x\n", 1195 (void *)dip, inum, vecp->v_cpuid, vecp->v_vector)); 1196 } 1197 1198 apix_vector_t * 1199 apix_get_dev_map(dev_info_t *dip, int inum, int type) 1200 { 1201 char *name; 1202 major_t major; 1203 apix_dev_vector_t *dvp; 1204 apix_vector_t *vecp; 1205 1206 name = ddi_get_name(dip); 1207 if ((major = ddi_name_to_major(name)) == DDI_MAJOR_T_NONE) 1208 return (NULL); 1209 1210 mutex_enter(&apix_mutex); 1211 for (dvp = apix_dev_vector[major]; dvp != NULL; 1212 dvp = dvp->dv_next) { 1213 if (dvp->dv_dip == dip && dvp->dv_inum == inum && 1214 dvp->dv_type == type) { 1215 vecp = dvp->dv_vector; 1216 mutex_exit(&apix_mutex); 1217 return (vecp); 1218 } 1219 } 1220 mutex_exit(&apix_mutex); 1221 1222 return (NULL); 1223 } 1224 1225 /* 1226 * Get minimum inum for specified device, used for MSI 1227 */ 1228 int 1229 apix_get_min_dev_inum(dev_info_t *dip, int type) 1230 { 1231 char *name; 1232 major_t major; 1233 apix_dev_vector_t *dvp; 1234 int inum = -1; 1235 1236 name = ddi_get_name(dip); 1237 major = ddi_name_to_major(name); 1238 1239 mutex_enter(&apix_mutex); 1240 for (dvp = apix_dev_vector[major]; dvp != NULL; 1241 dvp = dvp->dv_next) { 1242 if (dvp->dv_dip == dip && dvp->dv_type == type) { 1243 if (inum == -1) 1244 inum = dvp->dv_inum; 1245 else 1246 inum = (dvp->dv_inum < inum) ? 1247 dvp->dv_inum : inum; 1248 } 1249 } 1250 mutex_exit(&apix_mutex); 1251 1252 return (inum); 1253 } 1254 1255 int 1256 apix_get_max_dev_inum(dev_info_t *dip, int type) 1257 { 1258 char *name; 1259 major_t major; 1260 apix_dev_vector_t *dvp; 1261 int inum = -1; 1262 1263 name = ddi_get_name(dip); 1264 major = ddi_name_to_major(name); 1265 1266 mutex_enter(&apix_mutex); 1267 for (dvp = apix_dev_vector[major]; dvp != NULL; 1268 dvp = dvp->dv_next) { 1269 if (dvp->dv_dip == dip && dvp->dv_type == type) { 1270 if (inum == -1) 1271 inum = dvp->dv_inum; 1272 else 1273 inum = (dvp->dv_inum > inum) ? 1274 dvp->dv_inum : inum; 1275 } 1276 } 1277 mutex_exit(&apix_mutex); 1278 1279 return (inum); 1280 } 1281 1282 /* 1283 * Major to cpu binding, for INTR_ROUND_ROBIN_WITH_AFFINITY cpu 1284 * binding policy 1285 */ 1286 1287 static uint32_t 1288 apix_get_dev_binding(dev_info_t *dip) 1289 { 1290 major_t major; 1291 char *name; 1292 uint32_t cpu = IRQ_UNINIT; 1293 1294 name = ddi_get_name(dip); 1295 major = ddi_name_to_major(name); 1296 if (major < devcnt) { 1297 mutex_enter(&apix_mutex); 1298 cpu = apix_major_to_cpu[major]; 1299 mutex_exit(&apix_mutex); 1300 } 1301 1302 return (cpu); 1303 } 1304 1305 static void 1306 apix_set_dev_binding(dev_info_t *dip, uint32_t cpu) 1307 { 1308 major_t major; 1309 char *name; 1310 1311 /* setup major to cpu mapping */ 1312 name = ddi_get_name(dip); 1313 major = ddi_name_to_major(name); 1314 if (apix_major_to_cpu[major] == IRQ_UNINIT) { 1315 mutex_enter(&apix_mutex); 1316 apix_major_to_cpu[major] = cpu; 1317 mutex_exit(&apix_mutex); 1318 } 1319 } 1320 1321 /* 1322 * return the cpu to which this intr should be bound. 1323 * Check properties or any other mechanism to see if user wants it 1324 * bound to a specific CPU. If so, return the cpu id with high bit set. 1325 * If not, use the policy to choose a cpu and return the id. 1326 */ 1327 uint32_t 1328 apix_bind_cpu(dev_info_t *dip) 1329 { 1330 int instance, instno, prop_len, bind_cpu, count; 1331 uint_t i, rc; 1332 major_t major; 1333 char *name, *drv_name, *prop_val, *cptr; 1334 char prop_name[32]; 1335 1336 lock_set(&apix_lock); 1337 1338 if (apic_intr_policy == INTR_LOWEST_PRIORITY) { 1339 cmn_err(CE_WARN, "apix: unsupported interrupt binding policy " 1340 "LOWEST PRIORITY, use ROUND ROBIN instead"); 1341 apic_intr_policy = INTR_ROUND_ROBIN; 1342 } 1343 1344 if (apic_nproc == 1) { 1345 lock_clear(&apix_lock); 1346 return (0); 1347 } 1348 1349 drv_name = NULL; 1350 rc = DDI_PROP_NOT_FOUND; 1351 major = (major_t)-1; 1352 if (dip != NULL) { 1353 name = ddi_get_name(dip); 1354 major = ddi_name_to_major(name); 1355 drv_name = ddi_major_to_name(major); 1356 instance = ddi_get_instance(dip); 1357 if (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) { 1358 bind_cpu = apix_get_dev_binding(dip); 1359 if (bind_cpu != IRQ_UNINIT) { 1360 lock_clear(&apix_lock); 1361 return (bind_cpu); 1362 } 1363 } 1364 /* 1365 * search for "drvname"_intpt_bind_cpus property first, the 1366 * syntax of the property should be "a[,b,c,...]" where 1367 * instance 0 binds to cpu a, instance 1 binds to cpu b, 1368 * instance 3 binds to cpu c... 1369 * ddi_getlongprop() will search /option first, then / 1370 * if "drvname"_intpt_bind_cpus doesn't exist, then find 1371 * intpt_bind_cpus property. The syntax is the same, and 1372 * it applies to all the devices if its "drvname" specific 1373 * property doesn't exist 1374 */ 1375 (void) strcpy(prop_name, drv_name); 1376 (void) strcat(prop_name, "_intpt_bind_cpus"); 1377 rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, prop_name, 1378 (caddr_t)&prop_val, &prop_len); 1379 if (rc != DDI_PROP_SUCCESS) { 1380 rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, 1381 "intpt_bind_cpus", (caddr_t)&prop_val, &prop_len); 1382 } 1383 } 1384 if (rc == DDI_PROP_SUCCESS) { 1385 for (i = count = 0; i < (prop_len - 1); i++) 1386 if (prop_val[i] == ',') 1387 count++; 1388 if (prop_val[i-1] != ',') 1389 count++; 1390 /* 1391 * if somehow the binding instances defined in the 1392 * property are not enough for this instno., then 1393 * reuse the pattern for the next instance until 1394 * it reaches the requested instno 1395 */ 1396 instno = instance % count; 1397 i = 0; 1398 cptr = prop_val; 1399 while (i < instno) 1400 if (*cptr++ == ',') 1401 i++; 1402 bind_cpu = stoi(&cptr); 1403 kmem_free(prop_val, prop_len); 1404 /* if specific cpu is bogus, then default to cpu 0 */ 1405 if (bind_cpu >= apic_nproc) { 1406 cmn_err(CE_WARN, "apix: %s=%s: CPU %d not present", 1407 prop_name, prop_val, bind_cpu); 1408 bind_cpu = 0; 1409 } else { 1410 /* indicate that we are bound at user request */ 1411 bind_cpu |= IRQ_USER_BOUND; 1412 } 1413 /* 1414 * no need to check apic_cpus[].aci_status, if specific cpu is 1415 * not up, then post_cpu_start will handle it. 1416 */ 1417 } else { 1418 bind_cpu = apic_get_next_bind_cpu(); 1419 } 1420 1421 lock_clear(&apix_lock); 1422 1423 return ((uint32_t)bind_cpu); 1424 } 1425 1426 static boolean_t 1427 apix_is_cpu_enabled(processorid_t cpuid) 1428 { 1429 apic_cpus_info_t *cpu_infop; 1430 1431 cpu_infop = &apic_cpus[cpuid]; 1432 1433 if ((cpu_infop->aci_status & APIC_CPU_INTR_ENABLE) == 0) 1434 return (B_FALSE); 1435 1436 return (B_TRUE); 1437 } 1438 1439 /* 1440 * Must be called with apix_lock held. This function can be 1441 * called from above lock level by apix_intr_redistribute(). 1442 * 1443 * Arguments: 1444 * vecp : Vector to be rebound 1445 * tocpu : Target cpu. IRQ_UNINIT means target is vecp->v_cpuid. 1446 * count : Number of continuous vectors 1447 * 1448 * Return new vector being bound to 1449 */ 1450 apix_vector_t * 1451 apix_rebind(apix_vector_t *vecp, processorid_t newcpu, int count) 1452 { 1453 apix_vector_t *newp, *oldp; 1454 processorid_t oldcpu = vecp->v_cpuid; 1455 uchar_t newvec, oldvec = vecp->v_vector; 1456 int i; 1457 1458 ASSERT(LOCK_HELD(&apix_lock) && count > 0); 1459 1460 if (!apix_is_cpu_enabled(newcpu)) 1461 return (NULL); 1462 1463 if (vecp->v_cpuid == newcpu) /* rebind to the same cpu */ 1464 return (vecp); 1465 1466 APIX_ENTER_CPU_LOCK(oldcpu); 1467 APIX_ENTER_CPU_LOCK(newcpu); 1468 1469 /* allocate vector */ 1470 if (count == 1) 1471 newp = apix_alloc_vector_oncpu(newcpu, NULL, 0, vecp->v_type); 1472 else { 1473 ASSERT(vecp->v_type == APIX_TYPE_MSI); 1474 newp = apix_alloc_nvectors_oncpu(newcpu, NULL, 0, count, 1475 vecp->v_type); 1476 } 1477 if (newp == NULL) { 1478 APIX_LEAVE_CPU_LOCK(newcpu); 1479 APIX_LEAVE_CPU_LOCK(oldcpu); 1480 return (NULL); 1481 } 1482 1483 newvec = newp->v_vector; 1484 apix_dup_vectors(vecp, newp, count); 1485 1486 APIX_LEAVE_CPU_LOCK(newcpu); 1487 APIX_LEAVE_CPU_LOCK(oldcpu); 1488 1489 if (!DDI_INTR_IS_MSI_OR_MSIX(vecp->v_type)) { 1490 ASSERT(count == 1); 1491 if (apix_intx_rebind(vecp->v_inum, newcpu, newvec) != 0) { 1492 struct autovec *avp; 1493 int inum; 1494 1495 /* undo duplication */ 1496 APIX_ENTER_CPU_LOCK(oldcpu); 1497 APIX_ENTER_CPU_LOCK(newcpu); 1498 for (avp = newp->v_autovect; avp != NULL; 1499 avp = avp->av_link) { 1500 if (avp->av_dip != NULL) { 1501 inum = GET_INTR_INUM(avp->av_intr_id); 1502 apix_set_dev_map(vecp, avp->av_dip, 1503 inum); 1504 } 1505 apix_remove_av(newp, avp); 1506 } 1507 apix_cleanup_vector(newp); 1508 APIX_LEAVE_CPU_LOCK(newcpu); 1509 APIX_LEAVE_CPU_LOCK(oldcpu); 1510 APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind fixed " 1511 "interrupt 0x%x to cpu %d failed\n", 1512 vecp->v_inum, newcpu)); 1513 return (NULL); 1514 } 1515 1516 APIX_ENTER_CPU_LOCK(oldcpu); 1517 (void) apix_obsolete_vector(vecp); 1518 APIX_LEAVE_CPU_LOCK(oldcpu); 1519 APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind fixed interrupt" 1520 " 0x%x/0x%x to 0x%x/0x%x\n", 1521 oldcpu, oldvec, newcpu, newvec)); 1522 return (newp); 1523 } 1524 1525 for (i = 0; i < count; i++) { 1526 oldp = xv_vector(oldcpu, oldvec + i); 1527 newp = xv_vector(newcpu, newvec + i); 1528 1529 if (newp->v_share > 0) { 1530 APIX_SET_REBIND_INFO(oldp, newp); 1531 1532 apix_enable_vector(newp); 1533 1534 APIX_CLR_REBIND_INFO(); 1535 } 1536 1537 APIX_ENTER_CPU_LOCK(oldcpu); 1538 (void) apix_obsolete_vector(oldp); 1539 APIX_LEAVE_CPU_LOCK(oldcpu); 1540 } 1541 APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind vector 0x%x/0x%x " 1542 "to 0x%x/0x%x, count=%d\n", 1543 oldcpu, oldvec, newcpu, newvec, count)); 1544 1545 return (xv_vector(newcpu, newvec)); 1546 } 1547 1548 /* 1549 * Senarios include: 1550 * a. add_avintr() is called before irqp initialized (legacy) 1551 * b. irqp is initialized, vector is not allocated (fixed interrupts) 1552 * c. irqp is initialized, vector is allocated (shared interrupts) 1553 */ 1554 apix_vector_t * 1555 apix_alloc_intx(dev_info_t *dip, int inum, int irqno) 1556 { 1557 apic_irq_t *irqp; 1558 apix_vector_t *vecp; 1559 1560 /* 1561 * Allocate IRQ. Caller is later responsible for the 1562 * initialization 1563 */ 1564 mutex_enter(&airq_mutex); 1565 if ((irqp = apic_irq_table[irqno]) == NULL) { 1566 /* allocate irq */ 1567 irqp = kmem_zalloc(sizeof (apic_irq_t), KM_SLEEP); 1568 irqp->airq_mps_intr_index = FREE_INDEX; 1569 apic_irq_table[irqno] = irqp; 1570 } 1571 if (irqp->airq_mps_intr_index == FREE_INDEX) { 1572 irqp->airq_mps_intr_index = DEFAULT_INDEX; 1573 irqp->airq_cpu = IRQ_UNINIT; 1574 irqp->airq_origirq = (uchar_t)irqno; 1575 } 1576 1577 mutex_exit(&airq_mutex); 1578 1579 /* 1580 * allocate vector 1581 */ 1582 if (irqp->airq_cpu == IRQ_UNINIT) { 1583 uint32_t bindcpu, cpuid; 1584 1585 /* select cpu by system policy */ 1586 bindcpu = apix_bind_cpu(dip); 1587 cpuid = bindcpu & ~IRQ_USER_BOUND; 1588 1589 /* allocate vector */ 1590 APIX_ENTER_CPU_LOCK(cpuid); 1591 1592 if ((vecp = apix_alloc_vector_oncpu(bindcpu, dip, inum, 1593 APIX_TYPE_FIXED)) == NULL) { 1594 cmn_err(CE_WARN, "No interrupt vector for irq %x", 1595 irqno); 1596 APIX_LEAVE_CPU_LOCK(cpuid); 1597 return (NULL); 1598 } 1599 vecp->v_inum = irqno; 1600 vecp->v_flags |= APIX_VECT_MASKABLE; 1601 1602 apix_intx_set_vector(irqno, vecp->v_cpuid, vecp->v_vector); 1603 1604 APIX_LEAVE_CPU_LOCK(cpuid); 1605 } else { 1606 vecp = xv_vector(irqp->airq_cpu, irqp->airq_vector); 1607 ASSERT(!IS_VECT_FREE(vecp)); 1608 1609 if (dip != NULL) 1610 apix_set_dev_map(vecp, dip, inum); 1611 } 1612 1613 if ((dip != NULL) && 1614 (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) && 1615 ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0)) 1616 apix_set_dev_binding(dip, vecp->v_cpuid); 1617 1618 apix_dprint_vector(vecp, dip, 1); 1619 1620 return (vecp); 1621 } 1622 1623 int 1624 apix_alloc_msi(dev_info_t *dip, int inum, int count, int behavior) 1625 { 1626 int i, cap_ptr, rcount = count; 1627 apix_vector_t *vecp; 1628 processorid_t bindcpu, cpuid; 1629 ushort_t msi_ctrl; 1630 ddi_acc_handle_t handle; 1631 1632 DDI_INTR_IMPLDBG((CE_CONT, "apix_alloc_msi_vectors: dip=0x%p " 1633 "inum=0x%x count=0x%x behavior=%d\n", 1634 (void *)dip, inum, count, behavior)); 1635 1636 if (count > 1) { 1637 if (behavior == DDI_INTR_ALLOC_STRICT && 1638 apic_multi_msi_enable == 0) 1639 return (0); 1640 if (apic_multi_msi_enable == 0) 1641 count = 1; 1642 } 1643 1644 /* Check whether it supports per-vector masking */ 1645 cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip); 1646 handle = i_ddi_get_pci_config_handle(dip); 1647 msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL); 1648 1649 /* bind to cpu */ 1650 bindcpu = apix_bind_cpu(dip); 1651 cpuid = bindcpu & ~IRQ_USER_BOUND; 1652 1653 /* if not ISP2, then round it down */ 1654 if (!ISP2(rcount)) 1655 rcount = 1 << (highbit(rcount) - 1); 1656 1657 APIX_ENTER_CPU_LOCK(cpuid); 1658 for (vecp = NULL; rcount > 0; rcount >>= 1) { 1659 vecp = apix_alloc_nvectors_oncpu(bindcpu, dip, inum, rcount, 1660 APIX_TYPE_MSI); 1661 if (vecp != NULL || behavior == DDI_INTR_ALLOC_STRICT) 1662 break; 1663 } 1664 for (i = 0; vecp && i < rcount; i++) 1665 xv_vector(vecp->v_cpuid, vecp->v_vector + i)->v_flags |= 1666 (msi_ctrl & PCI_MSI_PVM_MASK) ? APIX_VECT_MASKABLE : 0; 1667 APIX_LEAVE_CPU_LOCK(cpuid); 1668 if (vecp == NULL) { 1669 APIC_VERBOSE(INTR, (CE_CONT, 1670 "apix_alloc_msi: no %d cont vectors found on cpu 0x%x\n", 1671 count, bindcpu)); 1672 return (0); 1673 } 1674 1675 /* major to cpu binding */ 1676 if ((apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) && 1677 ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0)) 1678 apix_set_dev_binding(dip, vecp->v_cpuid); 1679 1680 apix_dprint_vector(vecp, dip, rcount); 1681 1682 return (rcount); 1683 } 1684 1685 int 1686 apix_alloc_msix(dev_info_t *dip, int inum, int count, int behavior) 1687 { 1688 apix_vector_t *vecp; 1689 processorid_t bindcpu, cpuid; 1690 int i; 1691 1692 for (i = 0; i < count; i++) { 1693 /* select cpu by system policy */ 1694 bindcpu = apix_bind_cpu(dip); 1695 cpuid = bindcpu & ~IRQ_USER_BOUND; 1696 1697 /* allocate vector */ 1698 APIX_ENTER_CPU_LOCK(cpuid); 1699 if ((vecp = apix_alloc_vector_oncpu(bindcpu, dip, inum + i, 1700 APIX_TYPE_MSIX)) == NULL) { 1701 APIX_LEAVE_CPU_LOCK(cpuid); 1702 APIC_VERBOSE(INTR, (CE_CONT, "apix_alloc_msix: " 1703 "allocate msix for device dip=%p, inum=%d on" 1704 " cpu %d failed", (void *)dip, inum + i, bindcpu)); 1705 break; 1706 } 1707 vecp->v_flags |= APIX_VECT_MASKABLE; 1708 APIX_LEAVE_CPU_LOCK(cpuid); 1709 1710 /* major to cpu mapping */ 1711 if ((i == 0) && 1712 (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) && 1713 ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0)) 1714 apix_set_dev_binding(dip, vecp->v_cpuid); 1715 1716 apix_dprint_vector(vecp, dip, 1); 1717 } 1718 1719 if (i < count && behavior == DDI_INTR_ALLOC_STRICT) { 1720 APIC_VERBOSE(INTR, (CE_WARN, "apix_alloc_msix: " 1721 "strictly allocate %d vectors failed, got %d\n", 1722 count, i)); 1723 apix_free_vectors(dip, inum, i, APIX_TYPE_MSIX); 1724 i = 0; 1725 } 1726 1727 return (i); 1728 } 1729 1730 /* 1731 * A rollback free for vectors allocated by apix_alloc_xxx(). 1732 */ 1733 void 1734 apix_free_vectors(dev_info_t *dip, int inum, int count, int type) 1735 { 1736 int i, cpuid; 1737 apix_vector_t *vecp; 1738 1739 DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: dip: %p inum: %x " 1740 "count: %x type: %x\n", 1741 (void *)dip, inum, count, type)); 1742 1743 lock_set(&apix_lock); 1744 1745 for (i = 0; i < count; i++, inum++) { 1746 if ((vecp = apix_get_dev_map(dip, inum, type)) == NULL) { 1747 lock_clear(&apix_lock); 1748 DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: " 1749 "dip=0x%p inum=0x%x type=0x%x apix_find_intr() " 1750 "failed\n", (void *)dip, inum, type)); 1751 continue; 1752 } 1753 1754 APIX_ENTER_CPU_LOCK(vecp->v_cpuid); 1755 cpuid = vecp->v_cpuid; 1756 1757 DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: " 1758 "dip=0x%p inum=0x%x type=0x%x vector 0x%x (share %d)\n", 1759 (void *)dip, inum, type, vecp->v_vector, vecp->v_share)); 1760 1761 /* tear down device interrupt to vector mapping */ 1762 apix_clear_dev_map(dip, inum, type); 1763 1764 if (vecp->v_type == APIX_TYPE_FIXED) { 1765 if (vecp->v_share > 0) { /* share IRQ line */ 1766 APIX_LEAVE_CPU_LOCK(cpuid); 1767 continue; 1768 } 1769 1770 /* Free apic_irq_table entry */ 1771 apix_intx_free(vecp->v_inum); 1772 } 1773 1774 /* free vector */ 1775 apix_cleanup_vector(vecp); 1776 1777 APIX_LEAVE_CPU_LOCK(cpuid); 1778 } 1779 1780 lock_clear(&apix_lock); 1781 } 1782 1783 /* 1784 * Must be called with apix_lock held 1785 */ 1786 apix_vector_t * 1787 apix_setup_io_intr(apix_vector_t *vecp) 1788 { 1789 processorid_t bindcpu; 1790 int ret; 1791 1792 ASSERT(LOCK_HELD(&apix_lock)); 1793 1794 /* 1795 * Interrupts are enabled on the CPU, programme IOAPIC RDT 1796 * entry or MSI/X address/data to enable the interrupt. 1797 */ 1798 if (apix_is_cpu_enabled(vecp->v_cpuid)) { 1799 apix_enable_vector(vecp); 1800 return (vecp); 1801 } 1802 1803 /* 1804 * CPU is not up or interrupts are disabled. Fall back to the 1805 * first avialable CPU. 1806 */ 1807 bindcpu = apic_find_cpu(APIC_CPU_INTR_ENABLE); 1808 1809 if (vecp->v_type == APIX_TYPE_MSI) 1810 return (apix_grp_set_cpu(vecp, bindcpu, &ret)); 1811 1812 return (apix_set_cpu(vecp, bindcpu, &ret)); 1813 } 1814 1815 /* 1816 * For interrupts which call add_avintr() before apic is initialized. 1817 * ioapix_setup_intr() will 1818 * - allocate vector 1819 * - copy over ISR 1820 */ 1821 static void 1822 ioapix_setup_intr(int irqno, iflag_t *flagp) 1823 { 1824 extern struct av_head autovect[]; 1825 apix_vector_t *vecp; 1826 apic_irq_t *irqp; 1827 uchar_t ioapicindex, ipin; 1828 ulong_t iflag; 1829 struct autovec *avp; 1830 1831 irqp = apic_irq_table[irqno]; 1832 ioapicindex = acpi_find_ioapic(irqno); 1833 ASSERT(ioapicindex != 0xFF); 1834 ipin = irqno - apic_io_vectbase[ioapicindex]; 1835 1836 if ((irqp != NULL) && (irqp->airq_mps_intr_index == ACPI_INDEX)) { 1837 ASSERT(irqp->airq_intin_no == ipin && 1838 irqp->airq_ioapicindex == ioapicindex); 1839 vecp = xv_vector(irqp->airq_cpu, irqp->airq_vector); 1840 ASSERT(!IS_VECT_FREE(vecp)); 1841 } else { 1842 vecp = apix_alloc_intx(NULL, 0, irqno); 1843 1844 irqp = apic_irq_table[irqno]; 1845 irqp->airq_mps_intr_index = ACPI_INDEX; 1846 irqp->airq_ioapicindex = ioapicindex; 1847 irqp->airq_intin_no = ipin; 1848 irqp->airq_iflag = *flagp; 1849 irqp->airq_share++; 1850 apic_record_rdt_entry(irqp, irqno); 1851 } 1852 1853 /* copy over autovect */ 1854 for (avp = autovect[irqno].avh_link; avp; avp = avp->av_link) 1855 apix_insert_av(vecp, avp->av_intr_id, avp->av_vector, 1856 avp->av_intarg1, avp->av_intarg2, avp->av_ticksp, 1857 avp->av_prilevel, avp->av_dip); 1858 1859 /* Program I/O APIC */ 1860 iflag = intr_clear(); 1861 lock_set(&apix_lock); 1862 1863 (void) apix_setup_io_intr(vecp); 1864 1865 lock_clear(&apix_lock); 1866 intr_restore(iflag); 1867 1868 APIC_VERBOSE_IOAPIC((CE_CONT, "apix: setup ioapic, irqno %x " 1869 "(ioapic %x, ipin %x) is bound to cpu %x, vector %x\n", 1870 irqno, ioapicindex, ipin, irqp->airq_cpu, irqp->airq_vector)); 1871 } 1872 1873 void 1874 ioapix_init_intr(int mask_apic) 1875 { 1876 int ioapicindex; 1877 int i, j; 1878 1879 /* mask interrupt vectors */ 1880 for (j = 0; j < apic_io_max && mask_apic; j++) { 1881 int intin_max; 1882 1883 ioapicindex = j; 1884 /* Bits 23-16 define the maximum redirection entries */ 1885 intin_max = (ioapic_read(ioapicindex, APIC_VERS_CMD) >> 16) 1886 & 0xff; 1887 for (i = 0; i <= intin_max; i++) 1888 ioapic_write(ioapicindex, APIC_RDT_CMD + 2 * i, 1889 AV_MASK); 1890 } 1891 1892 /* 1893 * Hack alert: deal with ACPI SCI interrupt chicken/egg here 1894 */ 1895 if (apic_sci_vect > 0) 1896 ioapix_setup_intr(apic_sci_vect, &apic_sci_flags); 1897 1898 /* 1899 * Hack alert: deal with ACPI HPET interrupt chicken/egg here. 1900 */ 1901 if (apic_hpet_vect > 0) 1902 ioapix_setup_intr(apic_hpet_vect, &apic_hpet_flags); 1903 } 1904