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