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);
|