Print this page
8626 make pcplusmp and apix warning-free
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>


   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.

  23  */
  24 /*
  25  * Copyright (c) 2010, Intel Corporation.
  26  * All rights reserved.
  27  */
  28 
  29 /*
  30  * PSMI 1.1 extensions are supported only in 2.6 and later versions.
  31  * PSMI 1.2 extensions are supported only in 2.7 and later versions.
  32  * PSMI 1.3 and 1.4 extensions are supported in Solaris 10.
  33  * PSMI 1.5 extensions are supported in Solaris Nevada.
  34  * PSMI 1.6 extensions are supported in Solaris Nevada.
  35  * PSMI 1.7 extensions are supported in Solaris Nevada.
  36  */
  37 #define PSMI_1_7
  38 
  39 #include <sys/processor.h>
  40 #include <sys/time.h>
  41 #include <sys/psm.h>
  42 #include <sys/smp_impldefs.h>


 627                         /*
 628                          * If the desired IPL's hardware priority is lower
 629                          * than that of the vector, use the hardware priority
 630                          * of the vector to determine the new IPL.
 631                          */
 632                         hwpri = (vect_desired_hwpri < vect_inherent_hwpri) ?
 633                             vect_inherent_hwpri : vect_desired_hwpri;
 634 
 635                         /*
 636                          * Now, to get the right index for apic_vectortoipl,
 637                          * we need to subtract APIC_BASE_VECT from the
 638                          * hardware-vector-equivalent (in hwpri).  Since hwpri
 639                          * is already shifted, we shift APIC_BASE_VECT before
 640                          * doing the subtraction.
 641                          */
 642                         hwpri -= (APIC_BASE_VECT >> APIC_IPL_SHIFT);
 643 
 644                         ASSERT(hwpri >= 0);
 645                         ASSERT(hwpri < MAXIPL);
 646                         max_ipl = apic_vectortoipl[hwpri];
 647                         apic_ipls[apic_ipls_index] = max_ipl;
 648 
 649                         irqp = irqheadptr;
 650                         while (irqp) {
 651                                 irqp->airq_ipl = (uchar_t)max_ipl;
 652                                 irqp = irqp->airq_next;
 653                         }
 654                 } else {
 655                         /*
 656                          * No more devices on this IRQ, so reset this vector's
 657                          * element in apic_ipls to the original IPL for this
 658                          * vector
 659                          */
 660                         apic_ipls[apic_ipls_index] =
 661                             apic_vectortoipl[vect_inherent_hwpri];
 662                 }
 663         }
 664 
 665         /*
 666          * If there are still active interrupts, we are done.
 667          */


1033                 }
1034 #endif /* DEBUG */
1035                 mutex_exit(&airq_mutex);
1036                 return (VIRTIRQ(chosen_irq, share_id));
1037         }
1038         return (-1);
1039 }
1040 
1041 /*
1042  * Allocate/Initialize the apic_irq_table[] entry for given irqno. If the entry
1043  * is used already, we will try to allocate a new irqno.
1044  *
1045  * Return value:
1046  *      Success: irqno
1047  *      Failure: -1
1048  */
1049 static int
1050 apic_setup_irq_table(dev_info_t *dip, int irqno, struct apic_io_intr *intrp,
1051     struct intrspec *ispec, iflag_t *intr_flagp, int type)
1052 {
1053         int origirq = ispec->intrspec_vec;
1054         uchar_t ipl = ispec->intrspec_pri;
1055         int     newirq, intr_index;
1056         uchar_t ipin, ioapic, ioapicindex, vector;
1057         apic_irq_t *irqptr;
1058         major_t major;
1059         dev_info_t      *sdip;
1060 





1061         DDI_INTR_IMPLDBG((CE_CONT, "apic_setup_irq_table: dip=0x%p type=%d "
1062             "irqno=0x%x origirq=0x%x\n", (void *)dip, type, irqno, origirq));
1063 
1064         ASSERT(ispec != NULL);
1065 
1066         major =  (dip != NULL) ? ddi_driver_major(dip) : 0;
1067 
1068         if (DDI_INTR_IS_MSI_OR_MSIX(type)) {
1069                 /* MSI/X doesn't need to setup ioapic stuffs */
1070                 ioapicindex = 0xff;
1071                 ioapic = 0xff;
1072                 ipin = (uchar_t)0xff;
1073                 intr_index = (type == DDI_INTR_TYPE_MSI) ? MSI_INDEX :
1074                     MSIX_INDEX;
1075                 mutex_enter(&airq_mutex);
1076                 if ((irqno = apic_allocate_irq(apic_first_avail_irq)) == -1) {
1077                         mutex_exit(&airq_mutex);
1078                         /* need an irq for MSI/X to index into autovect[] */
1079                         cmn_err(CE_WARN, "No interrupt irq: %s instance %d",
1080                             ddi_get_name(dip), ddi_get_instance(dip));
1081                         return (-1);
1082                 }
1083                 mutex_exit(&airq_mutex);
1084 
1085         } else if (intrp != NULL) {


1104                 ioapicindex = acpi_find_ioapic(irqno);
1105                 ASSERT(ioapicindex != 0xFF);
1106                 ioapic = apic_io_id[ioapicindex];
1107                 ipin = irqno - apic_io_vectbase[ioapicindex];
1108                 if (apic_irq_table[irqno] &&
1109                     apic_irq_table[irqno]->airq_mps_intr_index == ACPI_INDEX) {
1110                         ASSERT(apic_irq_table[irqno]->airq_intin_no == ipin &&
1111                             apic_irq_table[irqno]->airq_ioapicindex ==
1112                             ioapicindex);
1113                         return (irqno);
1114                 }
1115 
1116         } else {
1117                 /* default configuration */
1118                 ioapicindex = 0;
1119                 ioapic = apic_io_id[ioapicindex];
1120                 ipin = (uchar_t)irqno;
1121                 intr_index = DEFAULT_INDEX;
1122         }
1123 
1124         if (ispec == NULL) {
1125                 APIC_VERBOSE_IOAPIC((CE_WARN, "No intrspec for irqno = %x\n",
1126                     irqno));
1127         } else if ((vector = apic_allocate_vector(ipl, irqno, 0)) == 0) {
1128                 if ((newirq = apic_share_vector(irqno, intr_flagp, intr_index,
1129                     ipl, ioapicindex, ipin, &irqptr)) != -1) {
1130                         irqptr->airq_ipl = ipl;
1131                         irqptr->airq_origirq = (uchar_t)origirq;
1132                         irqptr->airq_dip = dip;
1133                         irqptr->airq_major = major;
1134                         sdip = apic_irq_table[IRQINDEX(newirq)]->airq_dip;
1135                         /* This is OK to do really */
1136                         if (sdip == NULL) {
1137                                 cmn_err(CE_WARN, "Sharing vectors: %s"
1138                                     " instance %d and SCI",
1139                                     ddi_get_name(dip), ddi_get_instance(dip));
1140                         } else {
1141                                 cmn_err(CE_WARN, "Sharing vectors: %s"
1142                                     " instance %d and %s instance %d",
1143                                     ddi_get_name(sdip), ddi_get_instance(sdip),
1144                                     ddi_get_name(dip), ddi_get_instance(dip));
1145                         }
1146                         return (newirq);
1147                 }


1211  * If not, use the policy to choose a cpu and return the id.
1212  */
1213 uint32_t
1214 apic_bind_intr(dev_info_t *dip, int irq, uchar_t ioapicid, uchar_t intin)
1215 {
1216         int     instance, instno, prop_len, bind_cpu, count;
1217         uint_t  i, rc;
1218         uint32_t cpu;
1219         major_t major;
1220         char    *name, *drv_name, *prop_val, *cptr;
1221         char    prop_name[32];
1222         ulong_t iflag;
1223 
1224 
1225         if (apic_intr_policy == INTR_LOWEST_PRIORITY)
1226                 return (IRQ_UNBOUND);
1227 
1228         if (apic_nproc == 1)
1229                 return (0);
1230 
1231         drv_name = NULL;
1232         rc = DDI_PROP_NOT_FOUND;
1233         major = (major_t)-1;
1234         if (dip != NULL) {











1235                 name = ddi_get_name(dip);
1236                 major = ddi_name_to_major(name);
1237                 drv_name = ddi_major_to_name(major);
1238                 instance = ddi_get_instance(dip);
1239                 if (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) {
1240                         i = apic_min_device_irq;
1241                         for (; i <= apic_max_device_irq; i++) {
1242 
1243                                 if ((i == irq) || (apic_irq_table[i] == NULL) ||
1244                                     (apic_irq_table[i]->airq_mps_intr_index
1245                                     == FREE_INDEX))
1246                                         continue;
1247 
1248                                 if ((apic_irq_table[i]->airq_major == major) &&
1249                                     (!(apic_irq_table[i]->airq_cpu &
1250                                     IRQ_USER_BOUND))) {
1251 
1252                                         cpu = apic_irq_table[i]->airq_cpu;
1253 
1254                                         cmn_err(CE_CONT,
1255                                             "!%s: %s (%s) instance #%d "
1256                                             "irq 0x%x vector 0x%x ioapic 0x%x "
1257                                             "intin 0x%x is bound to cpu %d\n",
1258                                             psm_name,
1259                                             name, drv_name, instance, irq,
1260                                             apic_irq_table[irq]->airq_vector,
1261                                             ioapicid, intin, cpu);
1262                                         return (cpu);
1263                                 }
1264                         }
1265                 }
1266                 /*
1267                  * search for "drvname"_intpt_bind_cpus property first, the
1268                  * syntax of the property should be "a[,b,c,...]" where
1269                  * instance 0 binds to cpu a, instance 1 binds to cpu b,
1270                  * instance 3 binds to cpu c...
1271                  * ddi_getlongprop() will search /option first, then /
1272                  * if "drvname"_intpt_bind_cpus doesn't exist, then find
1273                  * intpt_bind_cpus property.  The syntax is the same, and
1274                  * it applies to all the devices if its "drvname" specific
1275                  * property doesn't exist
1276                  */
1277                 (void) strcpy(prop_name, drv_name);
1278                 (void) strcat(prop_name, "_intpt_bind_cpus");
1279                 rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, prop_name,
1280                     (caddr_t)&prop_val, &prop_len);
1281                 if (rc != DDI_PROP_SUCCESS) {
1282                         rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0,
1283                             "intpt_bind_cpus", (caddr_t)&prop_val, &prop_len);
1284                 }
1285         }
1286         if (rc == DDI_PROP_SUCCESS) {
1287                 for (i = count = 0; i < (prop_len - 1); i++)
1288                         if (prop_val[i] == ',')
1289                                 count++;
1290                 if (prop_val[i-1] != ',')
1291                         count++;
1292                 /*
1293                  * if somehow the binding instances defined in the
1294                  * property are not enough for this instno., then
1295                  * reuse the pattern for the next instance until
1296                  * it reaches the requested instno
1297                  */
1298                 instno = instance % count;
1299                 i = 0;
1300                 cptr = prop_val;
1301                 while (i < instno)
1302                         if (*cptr++ == ',')
1303                                 i++;
1304                 bind_cpu = stoi(&cptr);
1305                 kmem_free(prop_val, prop_len);
1306                 /* if specific CPU is bogus, then default to next cpu */
1307                 if (!apic_cpu_in_range(bind_cpu)) {
1308                         cmn_err(CE_WARN, "%s: %s=%s: CPU %d not present",
1309                             psm_name, prop_name, prop_val, bind_cpu);
1310                         rc = DDI_PROP_NOT_FOUND;
1311                 } else {
1312                         /* indicate that we are bound at user request */
1313                         bind_cpu |= IRQ_USER_BOUND;
1314                 }
1315                 /*
1316                  * no need to check apic_cpus[].aci_status, if specific CPU is
1317                  * not up, then post_cpu_start will handle it.
1318                  */
1319         }

1320         if (rc != DDI_PROP_SUCCESS) {
1321                 iflag = intr_clear();
1322                 lock_set(&apic_ioapic_lock);
1323                 bind_cpu = apic_get_next_bind_cpu();
1324                 lock_clear(&apic_ioapic_lock);
1325                 intr_restore(iflag);
1326         }
1327 
1328         if (drv_name != NULL)
1329                 cmn_err(CE_CONT, "!%s: %s (%s) instance %d irq 0x%x "
1330                     "vector 0x%x ioapic 0x%x intin 0x%x is bound to cpu %d\n",
1331                     psm_name, name, drv_name, instance, irq,
1332                     apic_irq_table[irq]->airq_vector, ioapicid, intin,
1333                     bind_cpu & ~IRQ_USER_BOUND);
1334         else
1335                 cmn_err(CE_CONT, "!%s: irq 0x%x "
1336                     "vector 0x%x ioapic 0x%x intin 0x%x is bound to cpu %d\n",
1337                     psm_name, irq, apic_irq_table[irq]->airq_vector, ioapicid,
1338                     intin, bind_cpu & ~IRQ_USER_BOUND);
1339 
1340         return ((uint32_t)bind_cpu);
1341 }
1342 
1343 /*
1344  * Mark vector as being in the process of being deleted. Interrupts
1345  * may still come in on some CPU. The moment an interrupt comes with
1346  * the new vector, we know we can free the old one. Called only from
1347  * addspl and delspl with interrupts disabled. Because an interrupt
1348  * can be shared, but no interrupt from either device may come in,
1349  * we also use a timeout mechanism, which we arbitrarily set to
1350  * apic_revector_timeout microseconds.
1351  */
1352 static void
1353 apic_mark_vector(uchar_t oldvector, uchar_t newvector)
1354 {
1355         ulong_t iflag;
1356 
1357         iflag = intr_clear();
1358         lock_set(&apic_revector_lock);




   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2017 Joyent, Inc.
  24  */
  25 /*
  26  * Copyright (c) 2010, Intel Corporation.
  27  * All rights reserved.
  28  */
  29 
  30 /*
  31  * PSMI 1.1 extensions are supported only in 2.6 and later versions.
  32  * PSMI 1.2 extensions are supported only in 2.7 and later versions.
  33  * PSMI 1.3 and 1.4 extensions are supported in Solaris 10.
  34  * PSMI 1.5 extensions are supported in Solaris Nevada.
  35  * PSMI 1.6 extensions are supported in Solaris Nevada.
  36  * PSMI 1.7 extensions are supported in Solaris Nevada.
  37  */
  38 #define PSMI_1_7
  39 
  40 #include <sys/processor.h>
  41 #include <sys/time.h>
  42 #include <sys/psm.h>
  43 #include <sys/smp_impldefs.h>


 628                         /*
 629                          * If the desired IPL's hardware priority is lower
 630                          * than that of the vector, use the hardware priority
 631                          * of the vector to determine the new IPL.
 632                          */
 633                         hwpri = (vect_desired_hwpri < vect_inherent_hwpri) ?
 634                             vect_inherent_hwpri : vect_desired_hwpri;
 635 
 636                         /*
 637                          * Now, to get the right index for apic_vectortoipl,
 638                          * we need to subtract APIC_BASE_VECT from the
 639                          * hardware-vector-equivalent (in hwpri).  Since hwpri
 640                          * is already shifted, we shift APIC_BASE_VECT before
 641                          * doing the subtraction.
 642                          */
 643                         hwpri -= (APIC_BASE_VECT >> APIC_IPL_SHIFT);
 644 
 645                         ASSERT(hwpri >= 0);
 646                         ASSERT(hwpri < MAXIPL);
 647                         max_ipl = apic_vectortoipl[hwpri];
 648                         apic_ipls[apic_ipls_index] = (uchar_t)max_ipl;
 649 
 650                         irqp = irqheadptr;
 651                         while (irqp) {
 652                                 irqp->airq_ipl = (uchar_t)max_ipl;
 653                                 irqp = irqp->airq_next;
 654                         }
 655                 } else {
 656                         /*
 657                          * No more devices on this IRQ, so reset this vector's
 658                          * element in apic_ipls to the original IPL for this
 659                          * vector
 660                          */
 661                         apic_ipls[apic_ipls_index] =
 662                             apic_vectortoipl[vect_inherent_hwpri];
 663                 }
 664         }
 665 
 666         /*
 667          * If there are still active interrupts, we are done.
 668          */


1034                 }
1035 #endif /* DEBUG */
1036                 mutex_exit(&airq_mutex);
1037                 return (VIRTIRQ(chosen_irq, share_id));
1038         }
1039         return (-1);
1040 }
1041 
1042 /*
1043  * Allocate/Initialize the apic_irq_table[] entry for given irqno. If the entry
1044  * is used already, we will try to allocate a new irqno.
1045  *
1046  * Return value:
1047  *      Success: irqno
1048  *      Failure: -1
1049  */
1050 static int
1051 apic_setup_irq_table(dev_info_t *dip, int irqno, struct apic_io_intr *intrp,
1052     struct intrspec *ispec, iflag_t *intr_flagp, int type)
1053 {
1054         int origirq;
1055         uchar_t ipl;
1056         int     newirq, intr_index;
1057         uchar_t ipin, ioapic, ioapicindex, vector;
1058         apic_irq_t *irqptr;
1059         major_t major;
1060         dev_info_t      *sdip;
1061 
1062         ASSERT(ispec != NULL);
1063 
1064         origirq = ispec->intrspec_vec;
1065         ipl = ispec->intrspec_pri;
1066 
1067         DDI_INTR_IMPLDBG((CE_CONT, "apic_setup_irq_table: dip=0x%p type=%d "
1068             "irqno=0x%x origirq=0x%x\n", (void *)dip, type, irqno, origirq));
1069 


1070         major =  (dip != NULL) ? ddi_driver_major(dip) : 0;
1071 
1072         if (DDI_INTR_IS_MSI_OR_MSIX(type)) {
1073                 /* MSI/X doesn't need to setup ioapic stuffs */
1074                 ioapicindex = 0xff;
1075                 ioapic = 0xff;
1076                 ipin = (uchar_t)0xff;
1077                 intr_index = (type == DDI_INTR_TYPE_MSI) ? MSI_INDEX :
1078                     MSIX_INDEX;
1079                 mutex_enter(&airq_mutex);
1080                 if ((irqno = apic_allocate_irq(apic_first_avail_irq)) == -1) {
1081                         mutex_exit(&airq_mutex);
1082                         /* need an irq for MSI/X to index into autovect[] */
1083                         cmn_err(CE_WARN, "No interrupt irq: %s instance %d",
1084                             ddi_get_name(dip), ddi_get_instance(dip));
1085                         return (-1);
1086                 }
1087                 mutex_exit(&airq_mutex);
1088 
1089         } else if (intrp != NULL) {


1108                 ioapicindex = acpi_find_ioapic(irqno);
1109                 ASSERT(ioapicindex != 0xFF);
1110                 ioapic = apic_io_id[ioapicindex];
1111                 ipin = irqno - apic_io_vectbase[ioapicindex];
1112                 if (apic_irq_table[irqno] &&
1113                     apic_irq_table[irqno]->airq_mps_intr_index == ACPI_INDEX) {
1114                         ASSERT(apic_irq_table[irqno]->airq_intin_no == ipin &&
1115                             apic_irq_table[irqno]->airq_ioapicindex ==
1116                             ioapicindex);
1117                         return (irqno);
1118                 }
1119 
1120         } else {
1121                 /* default configuration */
1122                 ioapicindex = 0;
1123                 ioapic = apic_io_id[ioapicindex];
1124                 ipin = (uchar_t)irqno;
1125                 intr_index = DEFAULT_INDEX;
1126         }
1127 
1128         if ((vector = apic_allocate_vector(ipl, irqno, 0)) == 0) {



1129                 if ((newirq = apic_share_vector(irqno, intr_flagp, intr_index,
1130                     ipl, ioapicindex, ipin, &irqptr)) != -1) {
1131                         irqptr->airq_ipl = ipl;
1132                         irqptr->airq_origirq = (uchar_t)origirq;
1133                         irqptr->airq_dip = dip;
1134                         irqptr->airq_major = major;
1135                         sdip = apic_irq_table[IRQINDEX(newirq)]->airq_dip;
1136                         /* This is OK to do really */
1137                         if (sdip == NULL) {
1138                                 cmn_err(CE_WARN, "Sharing vectors: %s"
1139                                     " instance %d and SCI",
1140                                     ddi_get_name(dip), ddi_get_instance(dip));
1141                         } else {
1142                                 cmn_err(CE_WARN, "Sharing vectors: %s"
1143                                     " instance %d and %s instance %d",
1144                                     ddi_get_name(sdip), ddi_get_instance(sdip),
1145                                     ddi_get_name(dip), ddi_get_instance(dip));
1146                         }
1147                         return (newirq);
1148                 }


1212  * If not, use the policy to choose a cpu and return the id.
1213  */
1214 uint32_t
1215 apic_bind_intr(dev_info_t *dip, int irq, uchar_t ioapicid, uchar_t intin)
1216 {
1217         int     instance, instno, prop_len, bind_cpu, count;
1218         uint_t  i, rc;
1219         uint32_t cpu;
1220         major_t major;
1221         char    *name, *drv_name, *prop_val, *cptr;
1222         char    prop_name[32];
1223         ulong_t iflag;
1224 
1225 
1226         if (apic_intr_policy == INTR_LOWEST_PRIORITY)
1227                 return (IRQ_UNBOUND);
1228 
1229         if (apic_nproc == 1)
1230                 return (0);
1231 
1232         if (dip == NULL) {
1233                 iflag = intr_clear();
1234                 lock_set(&apic_ioapic_lock);
1235                 bind_cpu = apic_get_next_bind_cpu();
1236                 lock_clear(&apic_ioapic_lock);
1237                 intr_restore(iflag);
1238 
1239                 cmn_err(CE_CONT, "!%s: irq 0x%x "
1240                     "vector 0x%x ioapic 0x%x intin 0x%x is bound to cpu %d\n",
1241                     psm_name, irq, apic_irq_table[irq]->airq_vector, ioapicid,
1242                     intin, bind_cpu & ~IRQ_USER_BOUND);
1243 
1244                 return ((uint32_t)bind_cpu);
1245         }
1246 
1247         name = ddi_get_name(dip);
1248         major = ddi_name_to_major(name);
1249         drv_name = ddi_major_to_name(major);
1250         instance = ddi_get_instance(dip);
1251         if (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) {
1252                 i = apic_min_device_irq;
1253                 for (; i <= apic_max_device_irq; i++) {

1254                         if ((i == irq) || (apic_irq_table[i] == NULL) ||
1255                             (apic_irq_table[i]->airq_mps_intr_index
1256                             == FREE_INDEX))
1257                                 continue;
1258 
1259                         if ((apic_irq_table[i]->airq_major == major) &&
1260                             (!(apic_irq_table[i]->airq_cpu & IRQ_USER_BOUND))) {


1261                                 cpu = apic_irq_table[i]->airq_cpu;
1262 
1263                                 cmn_err(CE_CONT,
1264                                     "!%s: %s (%s) instance #%d "
1265                                     "irq 0x%x vector 0x%x ioapic 0x%x "
1266                                     "intin 0x%x is bound to cpu %d\n",
1267                                     psm_name,
1268                                     name, drv_name, instance, irq,
1269                                     apic_irq_table[irq]->airq_vector,
1270                                     ioapicid, intin, cpu);
1271                                 return (cpu);
1272                         }
1273                 }
1274         }
1275         /*
1276          * search for "drvname"_intpt_bind_cpus property first, the
1277          * syntax of the property should be "a[,b,c,...]" where
1278          * instance 0 binds to cpu a, instance 1 binds to cpu b,
1279          * instance 3 binds to cpu c...
1280          * ddi_getlongprop() will search /option first, then /
1281          * if "drvname"_intpt_bind_cpus doesn't exist, then find
1282          * intpt_bind_cpus property.  The syntax is the same, and
1283          * it applies to all the devices if its "drvname" specific
1284          * property doesn't exist
1285          */
1286         (void) strcpy(prop_name, drv_name);
1287         (void) strcat(prop_name, "_intpt_bind_cpus");
1288         rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, prop_name,
1289             (caddr_t)&prop_val, &prop_len);
1290         if (rc != DDI_PROP_SUCCESS) {
1291                 rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0,
1292                     "intpt_bind_cpus", (caddr_t)&prop_val, &prop_len);
1293         }

1294         if (rc == DDI_PROP_SUCCESS) {
1295                 for (i = count = 0; i < (prop_len - 1); i++)
1296                         if (prop_val[i] == ',')
1297                                 count++;
1298                 if (prop_val[i-1] != ',')
1299                         count++;
1300                 /*
1301                  * if somehow the binding instances defined in the
1302                  * property are not enough for this instno., then
1303                  * reuse the pattern for the next instance until
1304                  * it reaches the requested instno
1305                  */
1306                 instno = instance % count;
1307                 i = 0;
1308                 cptr = prop_val;
1309                 while (i < instno)
1310                         if (*cptr++ == ',')
1311                                 i++;
1312                 bind_cpu = stoi(&cptr);
1313                 kmem_free(prop_val, prop_len);
1314                 /* if specific CPU is bogus, then default to next cpu */
1315                 if (!apic_cpu_in_range(bind_cpu)) {
1316                         cmn_err(CE_WARN, "%s: %s=%s: CPU %d not present",
1317                             psm_name, prop_name, prop_val, bind_cpu);
1318                         rc = DDI_PROP_NOT_FOUND;
1319                 } else {
1320                         /* indicate that we are bound at user request */
1321                         bind_cpu |= IRQ_USER_BOUND;
1322                 }
1323                 /*
1324                  * no need to check apic_cpus[].aci_status, if specific CPU is
1325                  * not up, then post_cpu_start will handle it.
1326                  */
1327         }
1328 
1329         if (rc != DDI_PROP_SUCCESS) {
1330                 iflag = intr_clear();
1331                 lock_set(&apic_ioapic_lock);
1332                 bind_cpu = apic_get_next_bind_cpu();
1333                 lock_clear(&apic_ioapic_lock);
1334                 intr_restore(iflag);
1335         }
1336 

1337         cmn_err(CE_CONT, "!%s: %s (%s) instance %d irq 0x%x "
1338             "vector 0x%x ioapic 0x%x intin 0x%x is bound to cpu %d\n",
1339             psm_name, name, drv_name, instance, irq,
1340             apic_irq_table[irq]->airq_vector, ioapicid, intin,
1341             bind_cpu & ~IRQ_USER_BOUND);





1342 
1343         return ((uint32_t)bind_cpu);
1344 }
1345 
1346 /*
1347  * Mark vector as being in the process of being deleted. Interrupts
1348  * may still come in on some CPU. The moment an interrupt comes with
1349  * the new vector, we know we can free the old one. Called only from
1350  * addspl and delspl with interrupts disabled. Because an interrupt
1351  * can be shared, but no interrupt from either device may come in,
1352  * we also use a timeout mechanism, which we arbitrarily set to
1353  * apic_revector_timeout microseconds.
1354  */
1355 static void
1356 apic_mark_vector(uchar_t oldvector, uchar_t newvector)
1357 {
1358         ulong_t iflag;
1359 
1360         iflag = intr_clear();
1361         lock_set(&apic_revector_lock);