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