Print this page
PANKOVs restructure
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/i86xpv/io/psm/mp_platform_xpv.c
+++ new/usr/src/uts/i86xpv/io/psm/mp_platform_xpv.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24 /*
25 25 * Copyright (c) 2010, Intel Corporation.
26 26 * All rights reserved.
27 27 */
28 28
29 29 /*
30 30 * PSMI 1.1 extensions are supported only in 2.6 and later versions.
31 31 * PSMI 1.2 extensions are supported only in 2.7 and later versions.
32 32 * PSMI 1.3 and 1.4 extensions are supported in Solaris 10.
33 33 * PSMI 1.5 extensions are supported in Solaris Nevada.
↓ open down ↓ |
33 lines elided |
↑ open up ↑ |
34 34 * PSMI 1.6 extensions are supported in Solaris Nevada.
35 35 * PSMI 1.7 extensions are supported in Solaris Nevada.
36 36 */
37 37 #define PSMI_1_7
38 38
39 39 #include <sys/processor.h>
40 40 #include <sys/time.h>
41 41 #include <sys/psm.h>
42 42 #include <sys/smp_impldefs.h>
43 43 #include <sys/cram.h>
44 -#include <sys/acpi/acpi.h>
44 +#include <acpica/include/acpi.h>
45 45 #include <sys/acpica.h>
46 46 #include <sys/psm_common.h>
47 47 #include <sys/apic.h>
48 48 #include <sys/apic_common.h>
49 49 #include <sys/pit.h>
50 50 #include <sys/ddi.h>
51 51 #include <sys/sunddi.h>
52 52 #include <sys/ddi_impldefs.h>
53 53 #include <sys/pci.h>
54 54 #include <sys/promif.h>
55 55 #include <sys/x86_archext.h>
56 56 #include <sys/cpc_impl.h>
57 57 #include <sys/uadmin.h>
58 58 #include <sys/panic.h>
59 59 #include <sys/debug.h>
60 60 #include <sys/archsystm.h>
61 61 #include <sys/trap.h>
62 62 #include <sys/machsystm.h>
63 63 #include <sys/cpuvar.h>
64 64 #include <sys/rm_platter.h>
65 65 #include <sys/privregs.h>
66 66 #include <sys/cyclic.h>
67 67 #include <sys/note.h>
68 68 #include <sys/pci_intr_lib.h>
69 69 #include <sys/sunndi.h>
70 70
71 71
72 72 /*
73 73 * Local Function Prototypes
74 74 */
75 75 static void apic_mark_vector(uchar_t oldvector, uchar_t newvector);
76 76 static void apic_xlate_vector_free_timeout_handler(void *arg);
77 77 static int apic_check_stuck_interrupt(apic_irq_t *irq_ptr, int old_bind_cpu,
78 78 int new_bind_cpu, int apicindex, int intin_no, int which_irq,
79 79 struct ioapic_reprogram_data *drep);
80 80 static int apic_setup_irq_table(dev_info_t *dip, int irqno,
81 81 struct apic_io_intr *intrp, struct intrspec *ispec, iflag_t *intr_flagp,
82 82 int type);
83 83 static void apic_try_deferred_reprogram(int ipl, int vect);
84 84 static void delete_defer_repro_ent(int which_irq);
85 85 static void apic_ioapic_wait_pending_clear(int ioapicindex,
86 86 int intin_no);
87 87
88 88 extern int apic_acpi_translate_pci_irq(dev_info_t *dip, int busid, int devid,
89 89 int ipin, int *pci_irqp, iflag_t *intr_flagp);
90 90 extern int apic_handle_pci_pci_bridge(dev_info_t *idip, int child_devno,
91 91 int child_ipin, struct apic_io_intr **intrp);
92 92 extern uchar_t acpi_find_ioapic(int irq);
93 93 extern struct apic_io_intr *apic_find_io_intr_w_busid(int irqno, int busid);
94 94 extern int apic_find_bus_id(int bustype);
95 95 extern int apic_find_intin(uchar_t ioapic, uchar_t intin);
96 96 extern void apic_record_rdt_entry(apic_irq_t *irqptr, int irq);
97 97
98 98 extern int apic_sci_vect;
99 99 extern iflag_t apic_sci_flags;
100 100 extern int apic_intr_policy;
101 101 extern char *psm_name;
102 102
103 103 /*
104 104 * number of bits per byte, from <sys/param.h>
105 105 */
106 106 #define UCHAR_MAX ((1 << NBBY) - 1)
107 107
108 108 /* Max wait time (in repetitions) for flags to clear in an RDT entry. */
109 109 extern int apic_max_reps_clear_pending;
110 110
111 111 /* The irq # is implicit in the array index: */
112 112 struct ioapic_reprogram_data apic_reprogram_info[APIC_MAX_VECTOR+1];
113 113 /*
114 114 * APIC_MAX_VECTOR + 1 is the maximum # of IRQs as well. ioapic_reprogram_info
115 115 * is indexed by IRQ number, NOT by vector number.
116 116 */
117 117
118 118 extern int apic_int_busy_mark;
119 119 extern int apic_int_free_mark;
120 120 extern int apic_diff_for_redistribution;
121 121 extern int apic_sample_factor_redistribution;
122 122 extern int apic_redist_cpu_skip;
123 123 extern int apic_num_imbalance;
124 124 extern int apic_num_rebind;
125 125
126 126 /* timeout for xlate_vector, mark_vector */
127 127 int apic_revector_timeout = 16 * 10000; /* 160 millisec */
128 128
129 129 extern int apic_defconf;
130 130 extern int apic_irq_translate;
131 131
132 132 extern int apic_use_acpi_madt_only; /* 1=ONLY use MADT from ACPI */
133 133
134 134 extern uchar_t apic_io_vectbase[MAX_IO_APIC];
135 135
136 136 extern boolean_t ioapic_mask_workaround[MAX_IO_APIC];
137 137
138 138 /*
139 139 * First available slot to be used as IRQ index into the apic_irq_table
140 140 * for those interrupts (like MSI/X) that don't have a physical IRQ.
141 141 */
142 142 extern int apic_first_avail_irq;
143 143
144 144 /*
145 145 * apic_defer_reprogram_lock ensures that only one processor is handling
146 146 * deferred interrupt programming at *_intr_exit time.
147 147 */
148 148 static lock_t apic_defer_reprogram_lock;
149 149
150 150 /*
151 151 * The current number of deferred reprogrammings outstanding
152 152 */
153 153 uint_t apic_reprogram_outstanding = 0;
154 154
155 155 #ifdef DEBUG
156 156 /*
157 157 * Counters that keep track of deferred reprogramming stats
158 158 */
159 159 uint_t apic_intr_deferrals = 0;
160 160 uint_t apic_intr_deliver_timeouts = 0;
161 161 uint_t apic_last_ditch_reprogram_failures = 0;
162 162 uint_t apic_deferred_setup_failures = 0;
163 163 uint_t apic_defer_repro_total_retries = 0;
164 164 uint_t apic_defer_repro_successes = 0;
165 165 uint_t apic_deferred_spurious_enters = 0;
166 166 #endif
167 167
168 168 extern int apic_io_max;
169 169 extern struct apic_io_intr *apic_io_intrp;
170 170
171 171 uchar_t apic_vector_to_irq[APIC_MAX_VECTOR+1];
172 172
173 173 extern uint32_t eisa_level_intr_mask;
174 174 /* At least MSB will be set if EISA bus */
175 175
176 176 extern int apic_pci_bus_total;
177 177 extern uchar_t apic_single_pci_busid;
178 178
179 179 /*
180 180 * Following declarations are for revectoring; used when ISRs at different
181 181 * IPLs share an irq.
182 182 */
183 183 static lock_t apic_revector_lock;
184 184 int apic_revector_pending = 0;
185 185 static uchar_t *apic_oldvec_to_newvec;
186 186 static uchar_t *apic_newvec_to_oldvec;
187 187
188 188 /* ACPI Interrupt Source Override Structure ptr */
189 189 ACPI_MADT_INTERRUPT_OVERRIDE *acpi_isop;
190 190 extern int acpi_iso_cnt;
191 191
192 192 /*
193 193 * Auto-configuration routines
194 194 */
195 195
196 196 /*
197 197 * Initialise vector->ipl and ipl->pri arrays. level_intr and irqtable
198 198 * are also set to NULL. vector->irq is set to a value which cannot map
199 199 * to a real irq to show that it is free.
200 200 */
201 201 void
202 202 apic_init_common(void)
203 203 {
204 204 int i, j, indx;
205 205 int *iptr;
206 206
207 207 /*
208 208 * Initialize apic_ipls from apic_vectortoipl. This array is
209 209 * used in apic_intr_enter to determine the IPL to use for the
210 210 * corresponding vector. On some systems, due to hardware errata
211 211 * and interrupt sharing, the IPL may not correspond to the IPL listed
212 212 * in apic_vectortoipl (see apic_addspl and apic_delspl).
213 213 */
214 214 for (i = 0; i < (APIC_AVAIL_VECTOR / APIC_VECTOR_PER_IPL); i++) {
215 215 indx = i * APIC_VECTOR_PER_IPL;
216 216
217 217 for (j = 0; j < APIC_VECTOR_PER_IPL; j++, indx++)
218 218 apic_ipls[indx] = apic_vectortoipl[i];
219 219 }
220 220
221 221 /* cpu 0 is always up (for now) */
222 222 apic_cpus[0].aci_status = APIC_CPU_ONLINE | APIC_CPU_INTR_ENABLE;
223 223
224 224 iptr = (int *)&apic_irq_table[0];
225 225 for (i = 0; i <= APIC_MAX_VECTOR; i++) {
226 226 apic_level_intr[i] = 0;
227 227 *iptr++ = NULL;
228 228 apic_vector_to_irq[i] = APIC_RESV_IRQ;
229 229
230 230 /* These *must* be initted to B_TRUE! */
231 231 apic_reprogram_info[i].done = B_TRUE;
232 232 apic_reprogram_info[i].irqp = NULL;
233 233 apic_reprogram_info[i].tries = 0;
234 234 apic_reprogram_info[i].bindcpu = 0;
235 235 }
236 236
237 237 /*
238 238 * Allocate a dummy irq table entry for the reserved entry.
239 239 * This takes care of the race between removing an irq and
240 240 * clock detecting a CPU in that irq during interrupt load
241 241 * sampling.
242 242 */
243 243 apic_irq_table[APIC_RESV_IRQ] =
244 244 kmem_zalloc(sizeof (apic_irq_t), KM_SLEEP);
245 245
246 246 mutex_init(&airq_mutex, NULL, MUTEX_DEFAULT, NULL);
247 247 }
248 248
249 249 void
250 250 ioapic_init_intr(int mask_apic)
251 251 {
252 252 int ioapic_ix;
253 253 struct intrspec ispec;
254 254 apic_irq_t *irqptr;
255 255 int i, j;
256 256 ulong_t iflag;
257 257
258 258 LOCK_INIT_CLEAR(&apic_revector_lock);
259 259 LOCK_INIT_CLEAR(&apic_defer_reprogram_lock);
260 260
261 261 /* mask interrupt vectors */
262 262 for (j = 0; j < apic_io_max && mask_apic; j++) {
263 263 int intin_max;
264 264
265 265 ioapic_ix = j;
266 266 /* Bits 23-16 define the maximum redirection entries */
267 267 intin_max = (ioapic_read(ioapic_ix, APIC_VERS_CMD) >> 16)
268 268 & 0xff;
269 269 for (i = 0; i <= intin_max; i++)
270 270 ioapic_write(ioapic_ix, APIC_RDT_CMD + 2 * i, AV_MASK);
271 271 }
272 272
273 273 /*
274 274 * Hack alert: deal with ACPI SCI interrupt chicken/egg here
275 275 */
276 276 if (apic_sci_vect > 0) {
277 277 /*
278 278 * acpica has already done add_avintr(); we just
279 279 * to finish the job by mimicing translate_irq()
280 280 *
281 281 * Fake up an intrspec and setup the tables
282 282 */
283 283 ispec.intrspec_vec = apic_sci_vect;
284 284 ispec.intrspec_pri = SCI_IPL;
285 285
286 286 if (apic_setup_irq_table(NULL, apic_sci_vect, NULL,
287 287 &ispec, &apic_sci_flags, DDI_INTR_TYPE_FIXED) < 0) {
288 288 cmn_err(CE_WARN, "!apic: SCI setup failed");
289 289 return;
290 290 }
291 291 irqptr = apic_irq_table[apic_sci_vect];
292 292
293 293 iflag = intr_clear();
294 294 lock_set(&apic_ioapic_lock);
295 295
296 296 /* Program I/O APIC */
297 297 (void) apic_setup_io_intr(irqptr, apic_sci_vect, B_FALSE);
298 298
299 299 lock_clear(&apic_ioapic_lock);
300 300 intr_restore(iflag);
301 301
302 302 irqptr->airq_share++;
303 303 }
304 304 }
305 305
306 306 /*
307 307 * Add mask bits to disable interrupt vector from happening
308 308 * at or above IPL. In addition, it should remove mask bits
309 309 * to enable interrupt vectors below the given IPL.
310 310 *
311 311 * Both add and delspl are complicated by the fact that different interrupts
312 312 * may share IRQs. This can happen in two ways.
313 313 * 1. The same H/W line is shared by more than 1 device
314 314 * 1a. with interrupts at different IPLs
315 315 * 1b. with interrupts at same IPL
316 316 * 2. We ran out of vectors at a given IPL and started sharing vectors.
317 317 * 1b and 2 should be handled gracefully, except for the fact some ISRs
318 318 * will get called often when no interrupt is pending for the device.
319 319 * For 1a, we handle it at the higher IPL.
320 320 */
321 321 /*ARGSUSED*/
322 322 int
323 323 apic_addspl_common(int irqno, int ipl, int min_ipl, int max_ipl)
324 324 {
325 325 uchar_t vector;
326 326 ulong_t iflag;
327 327 apic_irq_t *irqptr, *irqheadptr;
328 328 int irqindex;
329 329
330 330 ASSERT(max_ipl <= UCHAR_MAX);
331 331 irqindex = IRQINDEX(irqno);
332 332
333 333 if ((irqindex == -1) || (!apic_irq_table[irqindex]))
334 334 return (PSM_FAILURE);
335 335
336 336 mutex_enter(&airq_mutex);
337 337 irqptr = irqheadptr = apic_irq_table[irqindex];
338 338
339 339 DDI_INTR_IMPLDBG((CE_CONT, "apic_addspl: dip=0x%p type=%d irqno=0x%x "
340 340 "vector=0x%x\n", (void *)irqptr->airq_dip,
341 341 irqptr->airq_mps_intr_index, irqno, irqptr->airq_vector));
342 342
343 343 while (irqptr) {
344 344 if (VIRTIRQ(irqindex, irqptr->airq_share_id) == irqno)
345 345 break;
346 346 irqptr = irqptr->airq_next;
347 347 }
348 348 irqptr->airq_share++;
349 349
350 350 mutex_exit(&airq_mutex);
351 351
352 352 /* return if it is not hardware interrupt */
353 353 if (irqptr->airq_mps_intr_index == RESERVE_INDEX)
354 354 return (PSM_SUCCESS);
355 355
356 356 /* Or if there are more interupts at a higher IPL */
357 357 if (ipl != max_ipl)
358 358 return (PSM_SUCCESS);
359 359
360 360 /*
361 361 * if apic_picinit() has not been called yet, just return.
362 362 * At the end of apic_picinit(), we will call setup_io_intr().
363 363 */
364 364
365 365 if (!apic_picinit_called)
366 366 return (PSM_SUCCESS);
367 367
368 368 /*
369 369 * Upgrade vector if max_ipl is not earlier ipl. If we cannot allocate,
370 370 * return failure.
371 371 */
372 372 if (irqptr->airq_ipl != max_ipl &&
373 373 !ioapic_mask_workaround[irqptr->airq_ioapicindex]) {
374 374
375 375 vector = apic_allocate_vector(max_ipl, irqindex, 1);
376 376 if (vector == 0) {
377 377 irqptr->airq_share--;
378 378 return (PSM_FAILURE);
379 379 }
380 380 irqptr = irqheadptr;
381 381 apic_mark_vector(irqptr->airq_vector, vector);
382 382 while (irqptr) {
383 383 irqptr->airq_vector = vector;
384 384 irqptr->airq_ipl = (uchar_t)max_ipl;
385 385 /*
386 386 * reprogram irq being added and every one else
387 387 * who is not in the UNINIT state
388 388 */
389 389 if ((VIRTIRQ(irqindex, irqptr->airq_share_id) ==
390 390 irqno) || (irqptr->airq_temp_cpu != IRQ_UNINIT)) {
391 391 apic_record_rdt_entry(irqptr, irqindex);
392 392
393 393 iflag = intr_clear();
394 394 lock_set(&apic_ioapic_lock);
395 395
396 396 (void) apic_setup_io_intr(irqptr, irqindex,
397 397 B_FALSE);
398 398
399 399 lock_clear(&apic_ioapic_lock);
400 400 intr_restore(iflag);
401 401 }
402 402 irqptr = irqptr->airq_next;
403 403 }
404 404 return (PSM_SUCCESS);
405 405
406 406 } else if (irqptr->airq_ipl != max_ipl &&
407 407 ioapic_mask_workaround[irqptr->airq_ioapicindex]) {
408 408 /*
409 409 * We cannot upgrade the vector, but we can change
410 410 * the IPL that this vector induces.
411 411 *
412 412 * Note that we subtract APIC_BASE_VECT from the vector
413 413 * here because this array is used in apic_intr_enter
414 414 * (no need to add APIC_BASE_VECT in that hot code
415 415 * path since we can do it in the rarely-executed path
416 416 * here).
417 417 */
418 418 apic_ipls[irqptr->airq_vector - APIC_BASE_VECT] =
419 419 (uchar_t)max_ipl;
420 420
421 421 irqptr = irqheadptr;
422 422 while (irqptr) {
423 423 irqptr->airq_ipl = (uchar_t)max_ipl;
424 424 irqptr = irqptr->airq_next;
425 425 }
426 426
427 427 return (PSM_SUCCESS);
428 428 }
429 429
430 430 ASSERT(irqptr);
431 431
432 432 iflag = intr_clear();
433 433 lock_set(&apic_ioapic_lock);
434 434
435 435 (void) apic_setup_io_intr(irqptr, irqindex, B_FALSE);
436 436
437 437 lock_clear(&apic_ioapic_lock);
438 438 intr_restore(iflag);
439 439
440 440 return (PSM_SUCCESS);
441 441 }
442 442
443 443 /*
444 444 * Recompute mask bits for the given interrupt vector.
445 445 * If there is no interrupt servicing routine for this
446 446 * vector, this function should disable interrupt vector
447 447 * from happening at all IPLs. If there are still
448 448 * handlers using the given vector, this function should
449 449 * disable the given vector from happening below the lowest
450 450 * IPL of the remaining hadlers.
451 451 */
452 452 /*ARGSUSED*/
453 453 int
454 454 apic_delspl_common(int irqno, int ipl, int min_ipl, int max_ipl)
455 455 {
456 456 uchar_t vector;
457 457 uint32_t bind_cpu;
458 458 int intin, irqindex;
459 459 int ioapic_ix;
460 460 apic_irq_t *irqptr, *preirqptr, *irqheadptr, *irqp;
461 461 ulong_t iflag;
462 462
463 463 mutex_enter(&airq_mutex);
464 464 irqindex = IRQINDEX(irqno);
465 465 irqptr = preirqptr = irqheadptr = apic_irq_table[irqindex];
466 466
467 467 DDI_INTR_IMPLDBG((CE_CONT, "apic_delspl: dip=0x%p type=%d irqno=0x%x "
468 468 "vector=0x%x\n", (void *)irqptr->airq_dip,
469 469 irqptr->airq_mps_intr_index, irqno, irqptr->airq_vector));
470 470
471 471 while (irqptr) {
472 472 if (VIRTIRQ(irqindex, irqptr->airq_share_id) == irqno)
473 473 break;
474 474 preirqptr = irqptr;
475 475 irqptr = irqptr->airq_next;
476 476 }
477 477 ASSERT(irqptr);
478 478
479 479 irqptr->airq_share--;
480 480
481 481 mutex_exit(&airq_mutex);
482 482
483 483 /*
484 484 * If there are more interrupts at a higher IPL, we don't need
485 485 * to disable anything.
486 486 */
487 487 if (ipl < max_ipl)
488 488 return (PSM_SUCCESS);
489 489
490 490 /* return if it is not hardware interrupt */
491 491 if (irqptr->airq_mps_intr_index == RESERVE_INDEX)
492 492 return (PSM_SUCCESS);
493 493
494 494 if (!apic_picinit_called) {
495 495 /*
496 496 * Clear irq_struct. If two devices shared an intpt
497 497 * line & 1 unloaded before picinit, we are hosed. But, then
498 498 * we hope the machine survive.
499 499 */
500 500 irqptr->airq_mps_intr_index = FREE_INDEX;
501 501 irqptr->airq_temp_cpu = IRQ_UNINIT;
502 502 apic_free_vector(irqptr->airq_vector);
503 503 return (PSM_SUCCESS);
504 504 }
505 505 /*
506 506 * Downgrade vector to new max_ipl if needed. If we cannot allocate,
507 507 * use old IPL. Not very elegant, but it should work.
508 508 */
509 509 if ((irqptr->airq_ipl != max_ipl) && (max_ipl != PSM_INVALID_IPL) &&
510 510 !ioapic_mask_workaround[irqptr->airq_ioapicindex]) {
511 511 apic_irq_t *irqp;
512 512 if (vector = apic_allocate_vector(max_ipl, irqno, 1)) {
513 513 apic_mark_vector(irqheadptr->airq_vector, vector);
514 514 irqp = irqheadptr;
515 515 while (irqp) {
516 516 irqp->airq_vector = vector;
517 517 irqp->airq_ipl = (uchar_t)max_ipl;
518 518 if (irqp->airq_temp_cpu != IRQ_UNINIT) {
519 519 apic_record_rdt_entry(irqp, irqindex);
520 520
521 521 iflag = intr_clear();
522 522 lock_set(&apic_ioapic_lock);
523 523
524 524 (void) apic_setup_io_intr(irqp,
525 525 irqindex, B_FALSE);
526 526
527 527 lock_clear(&apic_ioapic_lock);
528 528 intr_restore(iflag);
529 529 }
530 530 irqp = irqp->airq_next;
531 531 }
532 532 }
533 533
534 534 } else if (irqptr->airq_ipl != max_ipl &&
535 535 max_ipl != PSM_INVALID_IPL &&
536 536 ioapic_mask_workaround[irqptr->airq_ioapicindex]) {
537 537
538 538 /*
539 539 * We cannot downgrade the IPL of the vector below the vector's
540 540 * hardware priority. If we did, it would be possible for a
541 541 * higher-priority hardware vector to interrupt a CPU running at an IPL
542 542 * lower than the hardware priority of the interrupting vector (but
543 543 * higher than the soft IPL of this IRQ). When this happens, we would
544 544 * then try to drop the IPL BELOW what it was (effectively dropping
545 545 * below base_spl) which would be potentially catastrophic.
546 546 *
547 547 * (e.g. Suppose the hardware vector associated with this IRQ is 0x40
548 548 * (hardware IPL of 4). Further assume that the old IPL of this IRQ
549 549 * was 4, but the new IPL is 1. If we forced vector 0x40 to result in
550 550 * an IPL of 1, it would be possible for the processor to be executing
551 551 * at IPL 3 and for an interrupt to come in on vector 0x40, interrupting
552 552 * the currently-executing ISR. When apic_intr_enter consults
553 553 * apic_irqs[], it will return 1, bringing the IPL of the CPU down to 1
554 554 * so even though the processor was running at IPL 4, an IPL 1
555 555 * interrupt will have interrupted it, which must not happen)).
556 556 *
557 557 * Effectively, this means that the hardware priority corresponding to
558 558 * the IRQ's IPL (in apic_ipls[]) cannot be lower than the vector's
559 559 * hardware priority.
560 560 *
561 561 * (In the above example, then, after removal of the IPL 4 device's
562 562 * interrupt handler, the new IPL will continue to be 4 because the
563 563 * hardware priority that IPL 1 implies is lower than the hardware
564 564 * priority of the vector used.)
565 565 */
566 566 /* apic_ipls is indexed by vector, starting at APIC_BASE_VECT */
567 567 const int apic_ipls_index = irqptr->airq_vector -
568 568 APIC_BASE_VECT;
569 569 const int vect_inherent_hwpri = irqptr->airq_vector >>
570 570 APIC_IPL_SHIFT;
571 571
572 572 /*
573 573 * If there are still devices using this IRQ, determine the
574 574 * new ipl to use.
575 575 */
576 576 if (irqptr->airq_share) {
577 577 int vect_desired_hwpri, hwpri;
578 578
579 579 ASSERT(max_ipl < MAXIPL);
580 580 vect_desired_hwpri = apic_ipltopri[max_ipl] >>
581 581 APIC_IPL_SHIFT;
582 582
583 583 /*
584 584 * If the desired IPL's hardware priority is lower
585 585 * than that of the vector, use the hardware priority
586 586 * of the vector to determine the new IPL.
587 587 */
588 588 hwpri = (vect_desired_hwpri < vect_inherent_hwpri) ?
589 589 vect_inherent_hwpri : vect_desired_hwpri;
590 590
591 591 /*
592 592 * Now, to get the right index for apic_vectortoipl,
593 593 * we need to subtract APIC_BASE_VECT from the
594 594 * hardware-vector-equivalent (in hwpri). Since hwpri
595 595 * is already shifted, we shift APIC_BASE_VECT before
596 596 * doing the subtraction.
597 597 */
598 598 hwpri -= (APIC_BASE_VECT >> APIC_IPL_SHIFT);
599 599
600 600 ASSERT(hwpri >= 0);
601 601 ASSERT(hwpri < MAXIPL);
602 602 max_ipl = apic_vectortoipl[hwpri];
603 603 apic_ipls[apic_ipls_index] = max_ipl;
604 604
605 605 irqp = irqheadptr;
606 606 while (irqp) {
607 607 irqp->airq_ipl = (uchar_t)max_ipl;
608 608 irqp = irqp->airq_next;
609 609 }
610 610 } else {
611 611 /*
612 612 * No more devices on this IRQ, so reset this vector's
613 613 * element in apic_ipls to the original IPL for this
614 614 * vector
615 615 */
616 616 apic_ipls[apic_ipls_index] =
617 617 apic_vectortoipl[vect_inherent_hwpri];
618 618 }
619 619 }
620 620
621 621 /*
622 622 * If there are still active interrupts, we are done.
623 623 */
624 624 if (irqptr->airq_share)
625 625 return (PSM_SUCCESS);
626 626
627 627 iflag = intr_clear();
628 628 lock_set(&apic_ioapic_lock);
629 629
630 630 if (irqptr->airq_mps_intr_index == MSI_INDEX) {
631 631 /*
632 632 * Disable the MSI vector
633 633 * Make sure we only disable on the last
634 634 * of the multi-MSI support
635 635 */
636 636 if (i_ddi_intr_get_current_nenables(irqptr->airq_dip) == 1) {
637 637 apic_pci_msi_disable_mode(irqptr->airq_dip,
638 638 DDI_INTR_TYPE_MSI);
639 639 }
640 640 } else if (irqptr->airq_mps_intr_index == MSIX_INDEX) {
641 641 /*
642 642 * Disable the MSI-X vector
643 643 * needs to clear its mask and addr/data for each MSI-X
644 644 */
645 645 apic_pci_msi_unconfigure(irqptr->airq_dip, DDI_INTR_TYPE_MSIX,
646 646 irqptr->airq_origirq);
647 647 /*
648 648 * Make sure we only disable on the last MSI-X
649 649 */
650 650 if (i_ddi_intr_get_current_nenables(irqptr->airq_dip) == 1) {
651 651 apic_pci_msi_disable_mode(irqptr->airq_dip,
652 652 DDI_INTR_TYPE_MSIX);
653 653 }
654 654 } else {
655 655 /*
656 656 * The assumption here is that this is safe, even for
657 657 * systems with IOAPICs that suffer from the hardware
658 658 * erratum because all devices have been quiesced before
659 659 * they unregister their interrupt handlers. If that
660 660 * assumption turns out to be false, this mask operation
661 661 * can induce the same erratum result we're trying to
662 662 * avoid.
663 663 */
664 664 ioapic_ix = irqptr->airq_ioapicindex;
665 665 intin = irqptr->airq_intin_no;
666 666 ioapic_write(ioapic_ix, APIC_RDT_CMD + 2 * intin, AV_MASK);
667 667 }
668 668
669 669 /*
670 670 * This irq entry is the only one in the chain.
671 671 */
672 672 if (irqheadptr->airq_next == NULL) {
673 673 ASSERT(irqheadptr == irqptr);
674 674 bind_cpu = irqptr->airq_temp_cpu;
675 675 if (((uint32_t)bind_cpu != IRQ_UNBOUND) &&
676 676 ((uint32_t)bind_cpu != IRQ_UNINIT)) {
677 677 ASSERT(apic_cpu_in_range(bind_cpu));
678 678 if (bind_cpu & IRQ_USER_BOUND) {
679 679 /* If hardbound, temp_cpu == cpu */
680 680 bind_cpu &= ~IRQ_USER_BOUND;
681 681 apic_cpus[bind_cpu].aci_bound--;
682 682 } else
683 683 apic_cpus[bind_cpu].aci_temp_bound--;
684 684 }
685 685 irqptr->airq_temp_cpu = IRQ_UNINIT;
686 686 irqptr->airq_mps_intr_index = FREE_INDEX;
687 687 lock_clear(&apic_ioapic_lock);
688 688 intr_restore(iflag);
689 689 apic_free_vector(irqptr->airq_vector);
690 690 return (PSM_SUCCESS);
691 691 }
692 692
693 693 /*
694 694 * If we get here, we are sharing the vector and there are more than
695 695 * one active irq entries in the chain.
696 696 */
697 697 lock_clear(&apic_ioapic_lock);
698 698 intr_restore(iflag);
699 699
700 700 mutex_enter(&airq_mutex);
701 701 /* Remove the irq entry from the chain */
702 702 if (irqptr == irqheadptr) { /* The irq entry is at the head */
703 703 apic_irq_table[irqindex] = irqptr->airq_next;
704 704 } else {
705 705 preirqptr->airq_next = irqptr->airq_next;
706 706 }
707 707 /* Free the irq entry */
708 708 kmem_free(irqptr, sizeof (apic_irq_t));
709 709 mutex_exit(&airq_mutex);
710 710
711 711 return (PSM_SUCCESS);
712 712 }
713 713
714 714 /*
715 715 * apic_introp_xlate() replaces apic_translate_irq() and is
716 716 * called only from apic_intr_ops(). With the new ADII framework,
717 717 * the priority can no longer be retrieved through i_ddi_get_intrspec().
718 718 * It has to be passed in from the caller.
719 719 *
720 720 * Return value:
721 721 * Success: irqno for the given device
722 722 * Failure: -1
723 723 */
724 724 int
725 725 apic_introp_xlate(dev_info_t *dip, struct intrspec *ispec, int type)
726 726 {
727 727 char dev_type[16];
728 728 int dev_len, pci_irq, newirq, bustype, devid, busid, i;
729 729 int irqno = ispec->intrspec_vec;
730 730 ddi_acc_handle_t cfg_handle;
731 731 uchar_t ipin;
732 732 struct apic_io_intr *intrp;
733 733 iflag_t intr_flag;
734 734 ACPI_SUBTABLE_HEADER *hp;
735 735 ACPI_MADT_INTERRUPT_OVERRIDE *isop;
736 736 apic_irq_t *airqp;
737 737 int parent_is_pci_or_pciex = 0;
738 738 int child_is_pciex = 0;
739 739
740 740 DDI_INTR_IMPLDBG((CE_CONT, "apic_introp_xlate: dip=0x%p name=%s "
741 741 "type=%d irqno=0x%x\n", (void *)dip, ddi_get_name(dip), type,
742 742 irqno));
743 743
744 744 dev_len = sizeof (dev_type);
745 745 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ddi_get_parent(dip),
746 746 DDI_PROP_DONTPASS, "device_type", (caddr_t)dev_type,
747 747 &dev_len) == DDI_PROP_SUCCESS) {
748 748 if ((strcmp(dev_type, "pci") == 0) ||
749 749 (strcmp(dev_type, "pciex") == 0))
750 750 parent_is_pci_or_pciex = 1;
751 751 }
752 752
753 753 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
754 754 DDI_PROP_DONTPASS, "compatible", (caddr_t)dev_type,
755 755 &dev_len) == DDI_PROP_SUCCESS) {
756 756 if (strstr(dev_type, "pciex"))
757 757 child_is_pciex = 1;
758 758 }
759 759
760 760 if (DDI_INTR_IS_MSI_OR_MSIX(type)) {
761 761 if ((airqp = apic_find_irq(dip, ispec, type)) != NULL) {
762 762 airqp->airq_iflag.bustype =
763 763 child_is_pciex ? BUS_PCIE : BUS_PCI;
764 764 return (apic_vector_to_irq[airqp->airq_vector]);
765 765 }
766 766 return (apic_setup_irq_table(dip, irqno, NULL, ispec,
767 767 NULL, type));
768 768 }
769 769
770 770 bustype = 0;
771 771
772 772 /* check if we have already translated this irq */
773 773 mutex_enter(&airq_mutex);
774 774 newirq = apic_min_device_irq;
775 775 for (; newirq <= apic_max_device_irq; newirq++) {
776 776 airqp = apic_irq_table[newirq];
777 777 while (airqp) {
778 778 if ((airqp->airq_dip == dip) &&
779 779 (airqp->airq_origirq == irqno) &&
780 780 (airqp->airq_mps_intr_index != FREE_INDEX)) {
781 781
782 782 mutex_exit(&airq_mutex);
783 783 return (VIRTIRQ(newirq, airqp->airq_share_id));
784 784 }
785 785 airqp = airqp->airq_next;
786 786 }
787 787 }
788 788 mutex_exit(&airq_mutex);
789 789
790 790 if (apic_defconf)
791 791 goto defconf;
792 792
793 793 if ((dip == NULL) || (!apic_irq_translate && !apic_enable_acpi))
794 794 goto nonpci;
795 795
796 796 if (parent_is_pci_or_pciex) {
797 797 /* pci device */
798 798 if (acpica_get_bdf(dip, &busid, &devid, NULL) != 0)
799 799 goto nonpci;
800 800 if (busid == 0 && apic_pci_bus_total == 1)
801 801 busid = (int)apic_single_pci_busid;
802 802
803 803 if (pci_config_setup(dip, &cfg_handle) != DDI_SUCCESS)
804 804 return (-1);
805 805 ipin = pci_config_get8(cfg_handle, PCI_CONF_IPIN) - PCI_INTA;
806 806 pci_config_teardown(&cfg_handle);
807 807 if (apic_enable_acpi && !apic_use_acpi_madt_only) {
808 808 if (apic_acpi_translate_pci_irq(dip, busid, devid,
809 809 ipin, &pci_irq, &intr_flag) != ACPI_PSM_SUCCESS)
810 810 return (-1);
811 811
812 812 intr_flag.bustype = child_is_pciex ? BUS_PCIE : BUS_PCI;
813 813 return (apic_setup_irq_table(dip, pci_irq, NULL, ispec,
814 814 &intr_flag, type));
815 815 } else {
816 816 pci_irq = ((devid & 0x1f) << 2) | (ipin & 0x3);
817 817 if ((intrp = apic_find_io_intr_w_busid(pci_irq, busid))
818 818 == NULL) {
819 819 if ((pci_irq = apic_handle_pci_pci_bridge(dip,
820 820 devid, ipin, &intrp)) == -1)
821 821 return (-1);
822 822 }
823 823 return (apic_setup_irq_table(dip, pci_irq, intrp, ispec,
824 824 NULL, type));
825 825 }
826 826 } else if (strcmp(dev_type, "isa") == 0)
827 827 bustype = BUS_ISA;
828 828 else if (strcmp(dev_type, "eisa") == 0)
829 829 bustype = BUS_EISA;
830 830
831 831 nonpci:
832 832 if (apic_enable_acpi && !apic_use_acpi_madt_only) {
833 833 /* search iso entries first */
834 834 if (acpi_iso_cnt != 0) {
835 835 hp = (ACPI_SUBTABLE_HEADER *)acpi_isop;
836 836 i = 0;
837 837 while (i < acpi_iso_cnt) {
838 838 if (hp->Type ==
839 839 ACPI_MADT_TYPE_INTERRUPT_OVERRIDE) {
840 840 isop =
841 841 (ACPI_MADT_INTERRUPT_OVERRIDE *) hp;
842 842 if (isop->Bus == 0 &&
843 843 isop->SourceIrq == irqno) {
844 844 newirq = isop->GlobalIrq;
845 845 intr_flag.intr_po =
846 846 isop->IntiFlags &
847 847 ACPI_MADT_POLARITY_MASK;
848 848 intr_flag.intr_el =
849 849 (isop->IntiFlags &
850 850 ACPI_MADT_TRIGGER_MASK)
851 851 >> 2;
852 852 intr_flag.bustype = BUS_ISA;
853 853
854 854 return (apic_setup_irq_table(
855 855 dip, newirq, NULL, ispec,
856 856 &intr_flag, type));
857 857
858 858 }
859 859 i++;
860 860 }
861 861 hp = (ACPI_SUBTABLE_HEADER *)(((char *)hp) +
862 862 hp->Length);
863 863 }
864 864 }
865 865 intr_flag.intr_po = INTR_PO_ACTIVE_HIGH;
866 866 intr_flag.intr_el = INTR_EL_EDGE;
867 867 intr_flag.bustype = BUS_ISA;
868 868 return (apic_setup_irq_table(dip, irqno, NULL, ispec,
869 869 &intr_flag, type));
870 870 } else {
871 871 if (bustype == 0) /* not initialized */
872 872 bustype = eisa_level_intr_mask ? BUS_EISA : BUS_ISA;
873 873 for (i = 0; i < 2; i++) {
874 874 if (((busid = apic_find_bus_id(bustype)) != -1) &&
875 875 ((intrp = apic_find_io_intr_w_busid(irqno, busid))
876 876 != NULL)) {
877 877 if ((newirq = apic_setup_irq_table(dip, irqno,
878 878 intrp, ispec, NULL, type)) != -1) {
879 879 return (newirq);
880 880 }
881 881 goto defconf;
882 882 }
883 883 bustype = (bustype == BUS_EISA) ? BUS_ISA : BUS_EISA;
884 884 }
885 885 }
886 886
887 887 /* MPS default configuration */
888 888 defconf:
889 889 newirq = apic_setup_irq_table(dip, irqno, NULL, ispec, NULL, type);
890 890 if (newirq == -1)
891 891 return (-1);
892 892 ASSERT(IRQINDEX(newirq) == irqno);
893 893 ASSERT(apic_irq_table[irqno]);
894 894 return (newirq);
895 895 }
896 896
897 897 /*
898 898 * Attempt to share vector with someone else
899 899 */
900 900 static int
901 901 apic_share_vector(int irqno, iflag_t *intr_flagp, short intr_index, int ipl,
902 902 uchar_t ioapicindex, uchar_t ipin, apic_irq_t **irqptrp)
903 903 {
904 904 #ifdef DEBUG
905 905 apic_irq_t *tmpirqp = NULL;
906 906 #endif /* DEBUG */
907 907 apic_irq_t *irqptr, dummyirq;
908 908 int newirq, chosen_irq = -1, share = 127;
909 909 int lowest, highest, i;
910 910 uchar_t share_id;
911 911
912 912 DDI_INTR_IMPLDBG((CE_CONT, "apic_share_vector: irqno=0x%x "
913 913 "intr_index=0x%x ipl=0x%x\n", irqno, intr_index, ipl));
914 914
915 915 highest = apic_ipltopri[ipl] + APIC_VECTOR_MASK;
916 916 lowest = apic_ipltopri[ipl-1] + APIC_VECTOR_PER_IPL;
917 917
918 918 if (highest < lowest) /* Both ipl and ipl-1 map to same pri */
919 919 lowest -= APIC_VECTOR_PER_IPL;
920 920 dummyirq.airq_mps_intr_index = intr_index;
921 921 dummyirq.airq_ioapicindex = ioapicindex;
922 922 dummyirq.airq_intin_no = ipin;
923 923 if (intr_flagp)
924 924 dummyirq.airq_iflag = *intr_flagp;
925 925 apic_record_rdt_entry(&dummyirq, irqno);
926 926 for (i = lowest; i <= highest; i++) {
927 927 newirq = apic_vector_to_irq[i];
928 928 if (newirq == APIC_RESV_IRQ)
929 929 continue;
930 930 irqptr = apic_irq_table[newirq];
931 931
932 932 if ((dummyirq.airq_rdt_entry & 0xFF00) !=
933 933 (irqptr->airq_rdt_entry & 0xFF00))
934 934 /* not compatible */
935 935 continue;
936 936
937 937 if (irqptr->airq_share < share) {
938 938 share = irqptr->airq_share;
939 939 chosen_irq = newirq;
940 940 }
941 941 }
942 942 if (chosen_irq != -1) {
943 943 /*
944 944 * Assign a share id which is free or which is larger
945 945 * than the largest one.
946 946 */
947 947 share_id = 1;
948 948 mutex_enter(&airq_mutex);
949 949 irqptr = apic_irq_table[chosen_irq];
950 950 while (irqptr) {
951 951 if (irqptr->airq_mps_intr_index == FREE_INDEX) {
952 952 share_id = irqptr->airq_share_id;
953 953 break;
954 954 }
955 955 if (share_id <= irqptr->airq_share_id)
956 956 share_id = irqptr->airq_share_id + 1;
957 957 #ifdef DEBUG
958 958 tmpirqp = irqptr;
959 959 #endif /* DEBUG */
960 960 irqptr = irqptr->airq_next;
961 961 }
962 962 if (!irqptr) {
963 963 irqptr = kmem_zalloc(sizeof (apic_irq_t), KM_SLEEP);
964 964 irqptr->airq_temp_cpu = IRQ_UNINIT;
965 965 irqptr->airq_next =
966 966 apic_irq_table[chosen_irq]->airq_next;
967 967 apic_irq_table[chosen_irq]->airq_next = irqptr;
968 968 #ifdef DEBUG
969 969 tmpirqp = apic_irq_table[chosen_irq];
970 970 #endif /* DEBUG */
971 971 }
972 972 irqptr->airq_mps_intr_index = intr_index;
973 973 irqptr->airq_ioapicindex = ioapicindex;
974 974 irqptr->airq_intin_no = ipin;
975 975 if (intr_flagp)
976 976 irqptr->airq_iflag = *intr_flagp;
977 977 irqptr->airq_vector = apic_irq_table[chosen_irq]->airq_vector;
978 978 irqptr->airq_share_id = share_id;
979 979 apic_record_rdt_entry(irqptr, irqno);
980 980 *irqptrp = irqptr;
981 981 #ifdef DEBUG
982 982 /* shuffle the pointers to test apic_delspl path */
983 983 if (tmpirqp) {
984 984 tmpirqp->airq_next = irqptr->airq_next;
985 985 irqptr->airq_next = apic_irq_table[chosen_irq];
986 986 apic_irq_table[chosen_irq] = irqptr;
987 987 }
988 988 #endif /* DEBUG */
989 989 mutex_exit(&airq_mutex);
990 990 return (VIRTIRQ(chosen_irq, share_id));
991 991 }
992 992 return (-1);
993 993 }
994 994
995 995 /*
996 996 * Allocate/Initialize the apic_irq_table[] entry for given irqno. If the entry
997 997 * is used already, we will try to allocate a new irqno.
998 998 *
999 999 * Return value:
1000 1000 * Success: irqno
1001 1001 * Failure: -1
1002 1002 */
1003 1003 static int
1004 1004 apic_setup_irq_table(dev_info_t *dip, int irqno, struct apic_io_intr *intrp,
1005 1005 struct intrspec *ispec, iflag_t *intr_flagp, int type)
1006 1006 {
1007 1007 int origirq = ispec->intrspec_vec;
1008 1008 uchar_t ipl = ispec->intrspec_pri;
1009 1009 int newirq, intr_index;
1010 1010 uchar_t ipin, ioapic, ioapicindex, vector;
1011 1011 apic_irq_t *irqptr;
1012 1012 major_t major;
1013 1013 dev_info_t *sdip;
1014 1014
1015 1015 DDI_INTR_IMPLDBG((CE_CONT, "apic_setup_irq_table: dip=0x%p type=%d "
1016 1016 "irqno=0x%x origirq=0x%x\n", (void *)dip, type, irqno, origirq));
1017 1017
1018 1018 ASSERT(ispec != NULL);
1019 1019
1020 1020 major = (dip != NULL) ? ddi_driver_major(dip) : 0;
1021 1021
1022 1022 if (DDI_INTR_IS_MSI_OR_MSIX(type)) {
1023 1023 /* MSI/X doesn't need to setup ioapic stuffs */
1024 1024 ioapicindex = 0xff;
1025 1025 ioapic = 0xff;
1026 1026 ipin = (uchar_t)0xff;
1027 1027 intr_index = (type == DDI_INTR_TYPE_MSI) ? MSI_INDEX :
1028 1028 MSIX_INDEX;
1029 1029 mutex_enter(&airq_mutex);
1030 1030 if ((irqno = apic_allocate_irq(apic_first_avail_irq)) == -1) {
1031 1031 mutex_exit(&airq_mutex);
1032 1032 /* need an irq for MSI/X to index into autovect[] */
1033 1033 cmn_err(CE_WARN, "No interrupt irq: %s instance %d",
1034 1034 ddi_get_name(dip), ddi_get_instance(dip));
1035 1035 return (-1);
1036 1036 }
1037 1037 mutex_exit(&airq_mutex);
1038 1038
1039 1039 } else if (intrp != NULL) {
1040 1040 intr_index = (int)(intrp - apic_io_intrp);
1041 1041 ioapic = intrp->intr_destid;
1042 1042 ipin = intrp->intr_destintin;
1043 1043 /* Find ioapicindex. If destid was ALL, we will exit with 0. */
1044 1044 for (ioapicindex = apic_io_max - 1; ioapicindex; ioapicindex--)
1045 1045 if (apic_io_id[ioapicindex] == ioapic)
1046 1046 break;
1047 1047 ASSERT((ioapic == apic_io_id[ioapicindex]) ||
1048 1048 (ioapic == INTR_ALL_APIC));
1049 1049
1050 1050 /* check whether this intin# has been used by another irqno */
1051 1051 if ((newirq = apic_find_intin(ioapicindex, ipin)) != -1) {
1052 1052 return (newirq);
1053 1053 }
1054 1054
1055 1055 } else if (intr_flagp != NULL) {
1056 1056 /* ACPI case */
1057 1057 intr_index = ACPI_INDEX;
1058 1058 ioapicindex = acpi_find_ioapic(irqno);
1059 1059 ASSERT(ioapicindex != 0xFF);
1060 1060 ioapic = apic_io_id[ioapicindex];
1061 1061 ipin = irqno - apic_io_vectbase[ioapicindex];
1062 1062 if (apic_irq_table[irqno] &&
1063 1063 apic_irq_table[irqno]->airq_mps_intr_index == ACPI_INDEX) {
1064 1064 ASSERT(apic_irq_table[irqno]->airq_intin_no == ipin &&
1065 1065 apic_irq_table[irqno]->airq_ioapicindex ==
1066 1066 ioapicindex);
1067 1067 return (irqno);
1068 1068 }
1069 1069
1070 1070 } else {
1071 1071 /* default configuration */
1072 1072 ioapicindex = 0;
1073 1073 ioapic = apic_io_id[ioapicindex];
1074 1074 ipin = (uchar_t)irqno;
1075 1075 intr_index = DEFAULT_INDEX;
1076 1076 }
1077 1077
1078 1078 if (ispec == NULL) {
1079 1079 APIC_VERBOSE_IOAPIC((CE_WARN, "No intrspec for irqno = %x\n",
1080 1080 irqno));
1081 1081 } else if ((vector = apic_allocate_vector(ipl, irqno, 0)) == 0) {
1082 1082 if ((newirq = apic_share_vector(irqno, intr_flagp, intr_index,
1083 1083 ipl, ioapicindex, ipin, &irqptr)) != -1) {
1084 1084 irqptr->airq_ipl = ipl;
1085 1085 irqptr->airq_origirq = (uchar_t)origirq;
1086 1086 irqptr->airq_dip = dip;
1087 1087 irqptr->airq_major = major;
1088 1088 sdip = apic_irq_table[IRQINDEX(newirq)]->airq_dip;
1089 1089 /* This is OK to do really */
1090 1090 if (sdip == NULL) {
1091 1091 cmn_err(CE_WARN, "Sharing vectors: %s"
1092 1092 " instance %d and SCI",
1093 1093 ddi_get_name(dip), ddi_get_instance(dip));
1094 1094 } else {
1095 1095 cmn_err(CE_WARN, "Sharing vectors: %s"
1096 1096 " instance %d and %s instance %d",
1097 1097 ddi_get_name(sdip), ddi_get_instance(sdip),
1098 1098 ddi_get_name(dip), ddi_get_instance(dip));
1099 1099 }
1100 1100 return (newirq);
1101 1101 }
1102 1102 /* try high priority allocation now that share has failed */
1103 1103 if ((vector = apic_allocate_vector(ipl, irqno, 1)) == 0) {
1104 1104 cmn_err(CE_WARN, "No interrupt vector: %s instance %d",
1105 1105 ddi_get_name(dip), ddi_get_instance(dip));
1106 1106 return (-1);
1107 1107 }
1108 1108 }
1109 1109
1110 1110 mutex_enter(&airq_mutex);
1111 1111 if (apic_irq_table[irqno] == NULL) {
1112 1112 irqptr = kmem_zalloc(sizeof (apic_irq_t), KM_SLEEP);
1113 1113 irqptr->airq_temp_cpu = IRQ_UNINIT;
1114 1114 apic_irq_table[irqno] = irqptr;
1115 1115 } else {
1116 1116 irqptr = apic_irq_table[irqno];
1117 1117 if (irqptr->airq_mps_intr_index != FREE_INDEX) {
1118 1118 /*
1119 1119 * The slot is used by another irqno, so allocate
1120 1120 * a free irqno for this interrupt
1121 1121 */
1122 1122 newirq = apic_allocate_irq(apic_first_avail_irq);
1123 1123 if (newirq == -1) {
1124 1124 mutex_exit(&airq_mutex);
1125 1125 return (-1);
1126 1126 }
1127 1127 irqno = newirq;
1128 1128 irqptr = apic_irq_table[irqno];
1129 1129 if (irqptr == NULL) {
1130 1130 irqptr = kmem_zalloc(sizeof (apic_irq_t),
1131 1131 KM_SLEEP);
1132 1132 irqptr->airq_temp_cpu = IRQ_UNINIT;
1133 1133 apic_irq_table[irqno] = irqptr;
1134 1134 }
1135 1135 vector = apic_modify_vector(vector, newirq);
1136 1136 }
1137 1137 }
1138 1138 apic_max_device_irq = max(irqno, apic_max_device_irq);
1139 1139 apic_min_device_irq = min(irqno, apic_min_device_irq);
1140 1140 mutex_exit(&airq_mutex);
1141 1141 irqptr->airq_ioapicindex = ioapicindex;
1142 1142 irqptr->airq_intin_no = ipin;
1143 1143 irqptr->airq_ipl = ipl;
1144 1144 irqptr->airq_vector = vector;
1145 1145 irqptr->airq_origirq = (uchar_t)origirq;
1146 1146 irqptr->airq_share_id = 0;
1147 1147 irqptr->airq_mps_intr_index = (short)intr_index;
1148 1148 irqptr->airq_dip = dip;
1149 1149 irqptr->airq_major = major;
1150 1150 irqptr->airq_cpu = apic_bind_intr(dip, irqno, ioapic, ipin);
1151 1151 if (intr_flagp)
1152 1152 irqptr->airq_iflag = *intr_flagp;
1153 1153
1154 1154 if (!DDI_INTR_IS_MSI_OR_MSIX(type)) {
1155 1155 /* setup I/O APIC entry for non-MSI/X interrupts */
1156 1156 apic_record_rdt_entry(irqptr, irqno);
1157 1157 }
1158 1158 return (irqno);
1159 1159 }
1160 1160
1161 1161 /*
1162 1162 * return the cpu to which this intr should be bound.
1163 1163 * Check properties or any other mechanism to see if user wants it
1164 1164 * bound to a specific CPU. If so, return the cpu id with high bit set.
1165 1165 * If not, use the policy to choose a cpu and return the id.
1166 1166 */
1167 1167 uint32_t
1168 1168 apic_bind_intr(dev_info_t *dip, int irq, uchar_t ioapicid, uchar_t intin)
1169 1169 {
1170 1170 int instance, instno, prop_len, bind_cpu, count;
1171 1171 uint_t i, rc;
1172 1172 uint32_t cpu;
1173 1173 major_t major;
1174 1174 char *name, *drv_name, *prop_val, *cptr;
1175 1175 char prop_name[32];
1176 1176 ulong_t iflag;
1177 1177
1178 1178
1179 1179 if (apic_intr_policy == INTR_LOWEST_PRIORITY)
1180 1180 return (IRQ_UNBOUND);
1181 1181
1182 1182 if (apic_nproc == 1)
1183 1183 return (0);
1184 1184
1185 1185 drv_name = NULL;
1186 1186 rc = DDI_PROP_NOT_FOUND;
1187 1187 major = (major_t)-1;
1188 1188 if (dip != NULL) {
1189 1189 name = ddi_get_name(dip);
1190 1190 major = ddi_name_to_major(name);
1191 1191 drv_name = ddi_major_to_name(major);
1192 1192 instance = ddi_get_instance(dip);
1193 1193 if (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) {
1194 1194 i = apic_min_device_irq;
1195 1195 for (; i <= apic_max_device_irq; i++) {
1196 1196
1197 1197 if ((i == irq) || (apic_irq_table[i] == NULL) ||
1198 1198 (apic_irq_table[i]->airq_mps_intr_index
1199 1199 == FREE_INDEX))
1200 1200 continue;
1201 1201
1202 1202 if ((apic_irq_table[i]->airq_major == major) &&
1203 1203 (!(apic_irq_table[i]->airq_cpu &
1204 1204 IRQ_USER_BOUND))) {
1205 1205
1206 1206 cpu = apic_irq_table[i]->airq_cpu;
1207 1207
1208 1208 cmn_err(CE_CONT,
1209 1209 "!%s: %s (%s) instance #%d "
1210 1210 "irq 0x%x vector 0x%x ioapic 0x%x "
1211 1211 "intin 0x%x is bound to cpu %d\n",
1212 1212 psm_name,
1213 1213 name, drv_name, instance, irq,
1214 1214 apic_irq_table[irq]->airq_vector,
1215 1215 ioapicid, intin, cpu);
1216 1216 return (cpu);
1217 1217 }
1218 1218 }
1219 1219 }
1220 1220 /*
1221 1221 * search for "drvname"_intpt_bind_cpus property first, the
1222 1222 * syntax of the property should be "a[,b,c,...]" where
1223 1223 * instance 0 binds to cpu a, instance 1 binds to cpu b,
1224 1224 * instance 3 binds to cpu c...
1225 1225 * ddi_getlongprop() will search /option first, then /
1226 1226 * if "drvname"_intpt_bind_cpus doesn't exist, then find
1227 1227 * intpt_bind_cpus property. The syntax is the same, and
1228 1228 * it applies to all the devices if its "drvname" specific
1229 1229 * property doesn't exist
1230 1230 */
1231 1231 (void) strcpy(prop_name, drv_name);
1232 1232 (void) strcat(prop_name, "_intpt_bind_cpus");
1233 1233 rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, prop_name,
1234 1234 (caddr_t)&prop_val, &prop_len);
1235 1235 if (rc != DDI_PROP_SUCCESS) {
1236 1236 rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0,
1237 1237 "intpt_bind_cpus", (caddr_t)&prop_val, &prop_len);
1238 1238 }
1239 1239 }
1240 1240 if (rc == DDI_PROP_SUCCESS) {
1241 1241 for (i = count = 0; i < (prop_len - 1); i++)
1242 1242 if (prop_val[i] == ',')
1243 1243 count++;
1244 1244 if (prop_val[i-1] != ',')
1245 1245 count++;
1246 1246 /*
1247 1247 * if somehow the binding instances defined in the
1248 1248 * property are not enough for this instno., then
1249 1249 * reuse the pattern for the next instance until
1250 1250 * it reaches the requested instno
1251 1251 */
1252 1252 instno = instance % count;
1253 1253 i = 0;
1254 1254 cptr = prop_val;
1255 1255 while (i < instno)
1256 1256 if (*cptr++ == ',')
1257 1257 i++;
1258 1258 bind_cpu = stoi(&cptr);
1259 1259 kmem_free(prop_val, prop_len);
1260 1260 /* if specific CPU is bogus, then default to next cpu */
1261 1261 if (!apic_cpu_in_range(bind_cpu)) {
1262 1262 cmn_err(CE_WARN, "%s: %s=%s: CPU %d not present",
1263 1263 psm_name, prop_name, prop_val, bind_cpu);
1264 1264 rc = DDI_PROP_NOT_FOUND;
1265 1265 } else {
1266 1266 /* indicate that we are bound at user request */
1267 1267 bind_cpu |= IRQ_USER_BOUND;
1268 1268 }
1269 1269 /*
1270 1270 * no need to check apic_cpus[].aci_status, if specific CPU is
1271 1271 * not up, then post_cpu_start will handle it.
1272 1272 */
1273 1273 }
1274 1274 if (rc != DDI_PROP_SUCCESS) {
1275 1275 iflag = intr_clear();
1276 1276 lock_set(&apic_ioapic_lock);
1277 1277 bind_cpu = apic_get_next_bind_cpu();
1278 1278 lock_clear(&apic_ioapic_lock);
1279 1279 intr_restore(iflag);
1280 1280 }
1281 1281
1282 1282 if (drv_name != NULL)
1283 1283 cmn_err(CE_CONT, "!%s: %s (%s) instance %d irq 0x%x "
1284 1284 "vector 0x%x ioapic 0x%x intin 0x%x is bound to cpu %d\n",
1285 1285 psm_name, name, drv_name, instance, irq,
1286 1286 apic_irq_table[irq]->airq_vector, ioapicid, intin,
1287 1287 bind_cpu & ~IRQ_USER_BOUND);
1288 1288 else
1289 1289 cmn_err(CE_CONT, "!%s: irq 0x%x "
1290 1290 "vector 0x%x ioapic 0x%x intin 0x%x is bound to cpu %d\n",
1291 1291 psm_name, irq, apic_irq_table[irq]->airq_vector, ioapicid,
1292 1292 intin, bind_cpu & ~IRQ_USER_BOUND);
1293 1293
1294 1294 return ((uint32_t)bind_cpu);
1295 1295 }
1296 1296
1297 1297 /*
1298 1298 * Mark vector as being in the process of being deleted. Interrupts
1299 1299 * may still come in on some CPU. The moment an interrupt comes with
1300 1300 * the new vector, we know we can free the old one. Called only from
1301 1301 * addspl and delspl with interrupts disabled. Because an interrupt
1302 1302 * can be shared, but no interrupt from either device may come in,
1303 1303 * we also use a timeout mechanism, which we arbitrarily set to
1304 1304 * apic_revector_timeout microseconds.
1305 1305 */
1306 1306 static void
1307 1307 apic_mark_vector(uchar_t oldvector, uchar_t newvector)
1308 1308 {
1309 1309 ulong_t iflag;
1310 1310
1311 1311 iflag = intr_clear();
1312 1312 lock_set(&apic_revector_lock);
1313 1313 if (!apic_oldvec_to_newvec) {
1314 1314 apic_oldvec_to_newvec =
1315 1315 kmem_zalloc(sizeof (newvector) * APIC_MAX_VECTOR * 2,
1316 1316 KM_NOSLEEP);
1317 1317
1318 1318 if (!apic_oldvec_to_newvec) {
1319 1319 /*
1320 1320 * This failure is not catastrophic.
1321 1321 * But, the oldvec will never be freed.
1322 1322 */
1323 1323 apic_error |= APIC_ERR_MARK_VECTOR_FAIL;
1324 1324 lock_clear(&apic_revector_lock);
1325 1325 intr_restore(iflag);
1326 1326 return;
1327 1327 }
1328 1328 apic_newvec_to_oldvec = &apic_oldvec_to_newvec[APIC_MAX_VECTOR];
1329 1329 }
1330 1330
1331 1331 /* See if we already did this for drivers which do double addintrs */
1332 1332 if (apic_oldvec_to_newvec[oldvector] != newvector) {
1333 1333 apic_oldvec_to_newvec[oldvector] = newvector;
1334 1334 apic_newvec_to_oldvec[newvector] = oldvector;
1335 1335 apic_revector_pending++;
1336 1336 }
1337 1337 lock_clear(&apic_revector_lock);
1338 1338 intr_restore(iflag);
1339 1339 (void) timeout(apic_xlate_vector_free_timeout_handler,
1340 1340 (void *)(uintptr_t)oldvector, drv_usectohz(apic_revector_timeout));
1341 1341 }
1342 1342
1343 1343 /*
1344 1344 * xlate_vector is called from intr_enter if revector_pending is set.
1345 1345 * It will xlate it if needed and mark the old vector as free.
1346 1346 */
1347 1347 uchar_t
1348 1348 apic_xlate_vector(uchar_t vector)
1349 1349 {
1350 1350 uchar_t newvector, oldvector = 0;
1351 1351
1352 1352 lock_set(&apic_revector_lock);
1353 1353 /* Do we really need to do this ? */
1354 1354 if (!apic_revector_pending) {
1355 1355 lock_clear(&apic_revector_lock);
1356 1356 return (vector);
1357 1357 }
1358 1358 if ((newvector = apic_oldvec_to_newvec[vector]) != 0)
1359 1359 oldvector = vector;
1360 1360 else {
1361 1361 /*
1362 1362 * The incoming vector is new . See if a stale entry is
1363 1363 * remaining
1364 1364 */
1365 1365 if ((oldvector = apic_newvec_to_oldvec[vector]) != 0)
1366 1366 newvector = vector;
1367 1367 }
1368 1368
1369 1369 if (oldvector) {
1370 1370 apic_revector_pending--;
1371 1371 apic_oldvec_to_newvec[oldvector] = 0;
1372 1372 apic_newvec_to_oldvec[newvector] = 0;
1373 1373 apic_free_vector(oldvector);
1374 1374 lock_clear(&apic_revector_lock);
1375 1375 /* There could have been more than one reprogramming! */
1376 1376 return (apic_xlate_vector(newvector));
1377 1377 }
1378 1378 lock_clear(&apic_revector_lock);
1379 1379 return (vector);
1380 1380 }
1381 1381
1382 1382 void
1383 1383 apic_xlate_vector_free_timeout_handler(void *arg)
1384 1384 {
1385 1385 ulong_t iflag;
1386 1386 uchar_t oldvector, newvector;
1387 1387
1388 1388 oldvector = (uchar_t)(uintptr_t)arg;
1389 1389 iflag = intr_clear();
1390 1390 lock_set(&apic_revector_lock);
1391 1391 if ((newvector = apic_oldvec_to_newvec[oldvector]) != 0) {
1392 1392 apic_free_vector(oldvector);
1393 1393 apic_oldvec_to_newvec[oldvector] = 0;
1394 1394 apic_newvec_to_oldvec[newvector] = 0;
1395 1395 apic_revector_pending--;
1396 1396 }
1397 1397
1398 1398 lock_clear(&apic_revector_lock);
1399 1399 intr_restore(iflag);
1400 1400 }
1401 1401
1402 1402 /*
1403 1403 * Bind interrupt corresponding to irq_ptr to bind_cpu.
1404 1404 * Must be called with interrupts disabled and apic_ioapic_lock held
1405 1405 */
1406 1406 int
1407 1407 apic_rebind(apic_irq_t *irq_ptr, int bind_cpu,
1408 1408 struct ioapic_reprogram_data *drep)
1409 1409 {
1410 1410 int ioapicindex, intin_no;
1411 1411 uint32_t airq_temp_cpu;
1412 1412 apic_cpus_info_t *cpu_infop;
1413 1413 uint32_t rdt_entry;
1414 1414 int which_irq;
1415 1415 ioapic_rdt_t irdt;
1416 1416
1417 1417 which_irq = apic_vector_to_irq[irq_ptr->airq_vector];
1418 1418
1419 1419 intin_no = irq_ptr->airq_intin_no;
1420 1420 ioapicindex = irq_ptr->airq_ioapicindex;
1421 1421 airq_temp_cpu = irq_ptr->airq_temp_cpu;
1422 1422 if (airq_temp_cpu != IRQ_UNINIT && airq_temp_cpu != IRQ_UNBOUND) {
1423 1423 if (airq_temp_cpu & IRQ_USER_BOUND)
1424 1424 /* Mask off high bit so it can be used as array index */
1425 1425 airq_temp_cpu &= ~IRQ_USER_BOUND;
1426 1426
1427 1427 ASSERT(apic_cpu_in_range(airq_temp_cpu));
1428 1428 }
1429 1429
1430 1430 /*
1431 1431 * Can't bind to a CPU that's not accepting interrupts:
1432 1432 */
1433 1433 cpu_infop = &apic_cpus[bind_cpu & ~IRQ_USER_BOUND];
1434 1434 if (!(cpu_infop->aci_status & APIC_CPU_INTR_ENABLE))
1435 1435 return (1);
1436 1436
1437 1437 /*
1438 1438 * If we are about to change the interrupt vector for this interrupt,
1439 1439 * and this interrupt is level-triggered, attached to an IOAPIC,
1440 1440 * has been delivered to a CPU and that CPU has not handled it
1441 1441 * yet, we cannot reprogram the IOAPIC now.
1442 1442 */
1443 1443 if (!APIC_IS_MSI_OR_MSIX_INDEX(irq_ptr->airq_mps_intr_index)) {
1444 1444
1445 1445 rdt_entry = READ_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapicindex,
1446 1446 intin_no);
1447 1447
1448 1448 if ((irq_ptr->airq_vector != RDT_VECTOR(rdt_entry)) &&
1449 1449 apic_check_stuck_interrupt(irq_ptr, airq_temp_cpu,
1450 1450 bind_cpu, ioapicindex, intin_no, which_irq, drep) != 0) {
1451 1451
1452 1452 return (0);
1453 1453 }
1454 1454
1455 1455 /*
1456 1456 * NOTE: We do not unmask the RDT here, as an interrupt MAY
1457 1457 * still come in before we have a chance to reprogram it below.
1458 1458 * The reprogramming below will simultaneously change and
1459 1459 * unmask the RDT entry.
1460 1460 */
1461 1461
1462 1462 if ((uint32_t)bind_cpu == IRQ_UNBOUND) {
1463 1463 irdt.ir_lo = AV_LDEST | AV_LOPRI |
1464 1464 irq_ptr->airq_rdt_entry;
1465 1465
1466 1466 WRITE_IOAPIC_RDT_ENTRY_HIGH_DWORD(ioapicindex, intin_no,
1467 1467 AV_TOALL);
1468 1468
1469 1469 if (airq_temp_cpu != IRQ_UNINIT && airq_temp_cpu !=
1470 1470 IRQ_UNBOUND)
1471 1471 apic_cpus[airq_temp_cpu].aci_temp_bound--;
1472 1472
1473 1473 /*
1474 1474 * Write the vector, trigger, and polarity portion of
1475 1475 * the RDT
1476 1476 */
1477 1477 WRITE_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapicindex, intin_no,
1478 1478 irdt.ir_lo);
1479 1479
1480 1480 irq_ptr->airq_temp_cpu = IRQ_UNBOUND;
1481 1481 return (0);
1482 1482 }
1483 1483 }
1484 1484
1485 1485 if (bind_cpu & IRQ_USER_BOUND) {
1486 1486 cpu_infop->aci_bound++;
1487 1487 } else {
1488 1488 cpu_infop->aci_temp_bound++;
1489 1489 }
1490 1490 ASSERT(apic_cpu_in_range(bind_cpu));
1491 1491
1492 1492 if ((airq_temp_cpu != IRQ_UNBOUND) && (airq_temp_cpu != IRQ_UNINIT)) {
1493 1493 apic_cpus[airq_temp_cpu].aci_temp_bound--;
1494 1494 }
1495 1495 if (!APIC_IS_MSI_OR_MSIX_INDEX(irq_ptr->airq_mps_intr_index)) {
1496 1496
1497 1497 irdt.ir_lo = AV_PDEST | AV_FIXED | irq_ptr->airq_rdt_entry;
1498 1498 irdt.ir_hi = cpu_infop->aci_local_id;
1499 1499
1500 1500 /* Write the RDT entry -- bind to a specific CPU: */
1501 1501 WRITE_IOAPIC_RDT_ENTRY_HIGH_DWORD(ioapicindex, intin_no,
1502 1502 irdt.ir_hi << APIC_ID_BIT_OFFSET);
1503 1503
1504 1504 /* Write the vector, trigger, and polarity portion of the RDT */
1505 1505 WRITE_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapicindex, intin_no,
1506 1506 irdt.ir_lo);
1507 1507
1508 1508 } else {
1509 1509 int type = (irq_ptr->airq_mps_intr_index == MSI_INDEX) ?
1510 1510 DDI_INTR_TYPE_MSI : DDI_INTR_TYPE_MSIX;
1511 1511 if (type == DDI_INTR_TYPE_MSI) {
1512 1512 if (irq_ptr->airq_ioapicindex ==
1513 1513 irq_ptr->airq_origirq) {
1514 1514 /* first one */
1515 1515 DDI_INTR_IMPLDBG((CE_CONT, "apic_rebind: call "
1516 1516 "apic_pci_msi_enable_vector\n"));
1517 1517 apic_pci_msi_enable_vector(irq_ptr,
1518 1518 type, which_irq, irq_ptr->airq_vector,
1519 1519 irq_ptr->airq_intin_no,
1520 1520 cpu_infop->aci_local_id);
1521 1521 }
1522 1522 if ((irq_ptr->airq_ioapicindex +
1523 1523 irq_ptr->airq_intin_no - 1) ==
1524 1524 irq_ptr->airq_origirq) { /* last one */
1525 1525 DDI_INTR_IMPLDBG((CE_CONT, "apic_rebind: call "
1526 1526 "apic_pci_msi_enable_mode\n"));
1527 1527 apic_pci_msi_enable_mode(irq_ptr->airq_dip,
1528 1528 type, which_irq);
1529 1529 }
1530 1530 } else { /* MSI-X */
1531 1531 apic_pci_msi_enable_vector(irq_ptr, type,
1532 1532 irq_ptr->airq_origirq, irq_ptr->airq_vector, 1,
1533 1533 cpu_infop->aci_local_id);
1534 1534 apic_pci_msi_enable_mode(irq_ptr->airq_dip, type,
1535 1535 irq_ptr->airq_origirq);
1536 1536 }
1537 1537 }
1538 1538 irq_ptr->airq_temp_cpu = (uint32_t)bind_cpu;
1539 1539 apic_redist_cpu_skip &= ~(1 << (bind_cpu & ~IRQ_USER_BOUND));
1540 1540 return (0);
1541 1541 }
1542 1542
1543 1543 static void
1544 1544 apic_last_ditch_clear_remote_irr(int ioapic_ix, int intin_no)
1545 1545 {
1546 1546 if ((READ_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapic_ix, intin_no)
1547 1547 & AV_REMOTE_IRR) != 0) {
1548 1548 /*
1549 1549 * Trying to clear the bit through normal
1550 1550 * channels has failed. So as a last-ditch
1551 1551 * effort, try to set the trigger mode to
1552 1552 * edge, then to level. This has been
1553 1553 * observed to work on many systems.
1554 1554 */
1555 1555 WRITE_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapic_ix,
1556 1556 intin_no,
1557 1557 READ_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapic_ix,
1558 1558 intin_no) & ~AV_LEVEL);
1559 1559
1560 1560 WRITE_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapic_ix,
1561 1561 intin_no,
1562 1562 READ_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapic_ix,
1563 1563 intin_no) | AV_LEVEL);
1564 1564
1565 1565 /*
1566 1566 * If the bit's STILL set, this interrupt may
1567 1567 * be hosed.
1568 1568 */
1569 1569 if ((READ_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapic_ix,
1570 1570 intin_no) & AV_REMOTE_IRR) != 0) {
1571 1571
1572 1572 prom_printf("%s: Remote IRR still "
1573 1573 "not clear for IOAPIC %d intin %d.\n"
1574 1574 "\tInterrupts to this pin may cease "
1575 1575 "functioning.\n", psm_name, ioapic_ix,
1576 1576 intin_no);
1577 1577 #ifdef DEBUG
1578 1578 apic_last_ditch_reprogram_failures++;
1579 1579 #endif
1580 1580 }
1581 1581 }
1582 1582 }
1583 1583
1584 1584 /*
1585 1585 * This function is protected by apic_ioapic_lock coupled with the
1586 1586 * fact that interrupts are disabled.
1587 1587 */
1588 1588 static void
1589 1589 delete_defer_repro_ent(int which_irq)
1590 1590 {
1591 1591 ASSERT(which_irq >= 0);
1592 1592 ASSERT(which_irq <= 255);
1593 1593 ASSERT(LOCK_HELD(&apic_ioapic_lock));
1594 1594
1595 1595 if (apic_reprogram_info[which_irq].done)
1596 1596 return;
1597 1597
1598 1598 apic_reprogram_info[which_irq].done = B_TRUE;
1599 1599
1600 1600 #ifdef DEBUG
1601 1601 apic_defer_repro_total_retries +=
1602 1602 apic_reprogram_info[which_irq].tries;
1603 1603
1604 1604 apic_defer_repro_successes++;
1605 1605 #endif
1606 1606
1607 1607 if (--apic_reprogram_outstanding == 0) {
1608 1608
1609 1609 setlvlx = psm_intr_exit_fn();
1610 1610 }
1611 1611 }
1612 1612
1613 1613
1614 1614 /*
1615 1615 * Interrupts must be disabled during this function to prevent
1616 1616 * self-deadlock. Interrupts are disabled because this function
1617 1617 * is called from apic_check_stuck_interrupt(), which is called
1618 1618 * from apic_rebind(), which requires its caller to disable interrupts.
1619 1619 */
1620 1620 static void
1621 1621 add_defer_repro_ent(apic_irq_t *irq_ptr, int which_irq, int new_bind_cpu)
1622 1622 {
1623 1623 ASSERT(which_irq >= 0);
1624 1624 ASSERT(which_irq <= 255);
1625 1625 ASSERT(!interrupts_enabled());
1626 1626
1627 1627 /*
1628 1628 * On the off-chance that there's already a deferred
1629 1629 * reprogramming on this irq, check, and if so, just update the
1630 1630 * CPU and irq pointer to which the interrupt is targeted, then return.
1631 1631 */
1632 1632 if (!apic_reprogram_info[which_irq].done) {
1633 1633 apic_reprogram_info[which_irq].bindcpu = new_bind_cpu;
1634 1634 apic_reprogram_info[which_irq].irqp = irq_ptr;
1635 1635 return;
1636 1636 }
1637 1637
1638 1638 apic_reprogram_info[which_irq].irqp = irq_ptr;
1639 1639 apic_reprogram_info[which_irq].bindcpu = new_bind_cpu;
1640 1640 apic_reprogram_info[which_irq].tries = 0;
1641 1641 /*
1642 1642 * This must be the last thing set, since we're not
1643 1643 * grabbing any locks, apic_try_deferred_reprogram() will
1644 1644 * make its decision about using this entry iff done
1645 1645 * is false.
1646 1646 */
1647 1647 apic_reprogram_info[which_irq].done = B_FALSE;
1648 1648
1649 1649 /*
1650 1650 * If there were previously no deferred reprogrammings, change
1651 1651 * setlvlx to call apic_try_deferred_reprogram()
1652 1652 */
1653 1653 if (++apic_reprogram_outstanding == 1) {
1654 1654
1655 1655 setlvlx = apic_try_deferred_reprogram;
1656 1656 }
1657 1657 }
1658 1658
1659 1659 static void
1660 1660 apic_try_deferred_reprogram(int prev_ipl, int irq)
1661 1661 {
1662 1662 int reproirq;
1663 1663 ulong_t iflag;
1664 1664 struct ioapic_reprogram_data *drep;
1665 1665
1666 1666 (*psm_intr_exit_fn())(prev_ipl, irq);
1667 1667
1668 1668 if (!lock_try(&apic_defer_reprogram_lock)) {
1669 1669 return;
1670 1670 }
1671 1671
1672 1672 /*
1673 1673 * Acquire the apic_ioapic_lock so that any other operations that
1674 1674 * may affect the apic_reprogram_info state are serialized.
1675 1675 * It's still possible for the last deferred reprogramming to clear
1676 1676 * between the time we entered this function and the time we get to
1677 1677 * the for loop below. In that case, *setlvlx will have been set
1678 1678 * back to *_intr_exit and drep will be NULL. (There's no way to
1679 1679 * stop that from happening -- we would need to grab a lock before
1680 1680 * calling *setlvlx, which is neither realistic nor prudent).
1681 1681 */
1682 1682 iflag = intr_clear();
1683 1683 lock_set(&apic_ioapic_lock);
1684 1684
1685 1685 /*
1686 1686 * For each deferred RDT entry, try to reprogram it now. Note that
1687 1687 * there is no lock acquisition to read apic_reprogram_info because
1688 1688 * '.done' is set only after the other fields in the structure are set.
1689 1689 */
1690 1690
1691 1691 drep = NULL;
1692 1692 for (reproirq = 0; reproirq <= APIC_MAX_VECTOR; reproirq++) {
1693 1693 if (apic_reprogram_info[reproirq].done == B_FALSE) {
1694 1694 drep = &apic_reprogram_info[reproirq];
1695 1695 break;
1696 1696 }
1697 1697 }
1698 1698
1699 1699 /*
1700 1700 * Either we found a deferred action to perform, or
1701 1701 * we entered this function spuriously, after *setlvlx
1702 1702 * was restored to point to *_intr_exit. Any other
1703 1703 * permutation is invalid.
1704 1704 */
1705 1705 ASSERT(drep != NULL || *setlvlx == psm_intr_exit_fn());
1706 1706
1707 1707 /*
1708 1708 * Though we can't really do anything about errors
1709 1709 * at this point, keep track of them for reporting.
1710 1710 * Note that it is very possible for apic_setup_io_intr
1711 1711 * to re-register this very timeout if the Remote IRR bit
1712 1712 * has not yet cleared.
1713 1713 */
1714 1714
1715 1715 #ifdef DEBUG
1716 1716 if (drep != NULL) {
1717 1717 if (apic_setup_io_intr(drep, reproirq, B_TRUE) != 0) {
1718 1718 apic_deferred_setup_failures++;
1719 1719 }
1720 1720 } else {
1721 1721 apic_deferred_spurious_enters++;
1722 1722 }
1723 1723 #else
1724 1724 if (drep != NULL)
1725 1725 (void) apic_setup_io_intr(drep, reproirq, B_TRUE);
1726 1726 #endif
1727 1727
1728 1728 lock_clear(&apic_ioapic_lock);
1729 1729 intr_restore(iflag);
1730 1730
1731 1731 lock_clear(&apic_defer_reprogram_lock);
1732 1732 }
1733 1733
1734 1734 static void
1735 1735 apic_ioapic_wait_pending_clear(int ioapic_ix, int intin_no)
1736 1736 {
1737 1737 int waited;
1738 1738
1739 1739 /*
1740 1740 * Wait for the delivery pending bit to clear.
1741 1741 */
1742 1742 if ((READ_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapic_ix, intin_no) &
1743 1743 (AV_LEVEL|AV_PENDING)) == (AV_LEVEL|AV_PENDING)) {
1744 1744
1745 1745 /*
1746 1746 * If we're still waiting on the delivery of this interrupt,
1747 1747 * continue to wait here until it is delivered (this should be
1748 1748 * a very small amount of time, but include a timeout just in
1749 1749 * case).
1750 1750 */
1751 1751 for (waited = 0; waited < apic_max_reps_clear_pending;
1752 1752 waited++) {
1753 1753 if ((READ_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapic_ix,
1754 1754 intin_no) & AV_PENDING) == 0) {
1755 1755 break;
1756 1756 }
1757 1757 }
1758 1758 }
1759 1759 }
1760 1760
1761 1761
1762 1762 /*
1763 1763 * Checks to see if the IOAPIC interrupt entry specified has its Remote IRR
1764 1764 * bit set. Calls functions that modify the function that setlvlx points to,
1765 1765 * so that the reprogramming can be retried very shortly.
1766 1766 *
1767 1767 * This function will mask the RDT entry if the interrupt is level-triggered.
1768 1768 * (The caller is responsible for unmasking the RDT entry.)
1769 1769 *
1770 1770 * Returns non-zero if the caller should defer IOAPIC reprogramming.
1771 1771 */
1772 1772 static int
1773 1773 apic_check_stuck_interrupt(apic_irq_t *irq_ptr, int old_bind_cpu,
1774 1774 int new_bind_cpu, int ioapic_ix, int intin_no, int which_irq,
1775 1775 struct ioapic_reprogram_data *drep)
1776 1776 {
1777 1777 int32_t rdt_entry;
1778 1778 int waited;
1779 1779 int reps = 0;
1780 1780
1781 1781 /*
1782 1782 * Wait for the delivery pending bit to clear.
1783 1783 */
1784 1784 do {
1785 1785 ++reps;
1786 1786
1787 1787 apic_ioapic_wait_pending_clear(ioapic_ix, intin_no);
1788 1788
1789 1789 /*
1790 1790 * Mask the RDT entry, but only if it's a level-triggered
1791 1791 * interrupt
1792 1792 */
1793 1793 rdt_entry = READ_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapic_ix,
1794 1794 intin_no);
1795 1795 if ((rdt_entry & (AV_LEVEL|AV_MASK)) == AV_LEVEL) {
1796 1796
1797 1797 /* Mask it */
1798 1798 WRITE_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapic_ix, intin_no,
1799 1799 AV_MASK | rdt_entry);
1800 1800 }
1801 1801
1802 1802 if ((rdt_entry & AV_LEVEL) == AV_LEVEL) {
1803 1803 /*
1804 1804 * If there was a race and an interrupt was injected
1805 1805 * just before we masked, check for that case here.
1806 1806 * Then, unmask the RDT entry and try again. If we're
1807 1807 * on our last try, don't unmask (because we want the
1808 1808 * RDT entry to remain masked for the rest of the
1809 1809 * function).
1810 1810 */
1811 1811 rdt_entry = READ_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapic_ix,
1812 1812 intin_no);
1813 1813 if ((rdt_entry & AV_PENDING) &&
1814 1814 (reps < apic_max_reps_clear_pending)) {
1815 1815 /* Unmask it */
1816 1816 WRITE_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapic_ix,
1817 1817 intin_no, rdt_entry & ~AV_MASK);
1818 1818 }
1819 1819 }
1820 1820
1821 1821 } while ((rdt_entry & AV_PENDING) &&
1822 1822 (reps < apic_max_reps_clear_pending));
1823 1823
1824 1824 #ifdef DEBUG
1825 1825 if (rdt_entry & AV_PENDING)
1826 1826 apic_intr_deliver_timeouts++;
1827 1827 #endif
1828 1828
1829 1829 /*
1830 1830 * If the remote IRR bit is set, then the interrupt has been sent
1831 1831 * to a CPU for processing. We have no choice but to wait for
1832 1832 * that CPU to process the interrupt, at which point the remote IRR
1833 1833 * bit will be cleared.
1834 1834 */
1835 1835 if ((READ_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapic_ix, intin_no) &
1836 1836 (AV_LEVEL|AV_REMOTE_IRR)) == (AV_LEVEL|AV_REMOTE_IRR)) {
1837 1837
1838 1838 /*
1839 1839 * If the CPU that this RDT is bound to is NOT the current
1840 1840 * CPU, wait until that CPU handles the interrupt and ACKs
1841 1841 * it. If this interrupt is not bound to any CPU (that is,
1842 1842 * if it's bound to the logical destination of "anyone"), it
1843 1843 * may have been delivered to the current CPU so handle that
1844 1844 * case by deferring the reprogramming (below).
1845 1845 */
1846 1846 if ((old_bind_cpu != IRQ_UNBOUND) &&
1847 1847 (old_bind_cpu != IRQ_UNINIT) &&
1848 1848 (old_bind_cpu != psm_get_cpu_id())) {
1849 1849 for (waited = 0; waited < apic_max_reps_clear_pending;
1850 1850 waited++) {
1851 1851 if ((READ_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapic_ix,
1852 1852 intin_no) & AV_REMOTE_IRR) == 0) {
1853 1853
1854 1854 delete_defer_repro_ent(which_irq);
1855 1855
1856 1856 /* Remote IRR has cleared! */
1857 1857 return (0);
1858 1858 }
1859 1859 }
1860 1860 }
1861 1861
1862 1862 /*
1863 1863 * If we waited and the Remote IRR bit is still not cleared,
1864 1864 * AND if we've invoked the timeout APIC_REPROGRAM_MAX_TIMEOUTS
1865 1865 * times for this interrupt, try the last-ditch workaround:
1866 1866 */
1867 1867 if (drep && drep->tries >= APIC_REPROGRAM_MAX_TRIES) {
1868 1868
1869 1869 apic_last_ditch_clear_remote_irr(ioapic_ix, intin_no);
1870 1870
1871 1871 /* Mark this one as reprogrammed: */
1872 1872 delete_defer_repro_ent(which_irq);
1873 1873
1874 1874 return (0);
1875 1875 } else {
1876 1876 #ifdef DEBUG
1877 1877 apic_intr_deferrals++;
1878 1878 #endif
1879 1879
1880 1880 /*
1881 1881 * If waiting for the Remote IRR bit (above) didn't
1882 1882 * allow it to clear, defer the reprogramming.
1883 1883 * Add a new deferred-programming entry if the
1884 1884 * caller passed a NULL one (and update the existing one
1885 1885 * in case anything changed).
1886 1886 */
1887 1887 add_defer_repro_ent(irq_ptr, which_irq, new_bind_cpu);
1888 1888 if (drep)
1889 1889 drep->tries++;
1890 1890
1891 1891 /* Inform caller to defer IOAPIC programming: */
1892 1892 return (1);
1893 1893 }
1894 1894
1895 1895 }
1896 1896
1897 1897 /* Remote IRR is clear */
1898 1898 delete_defer_repro_ent(which_irq);
1899 1899
1900 1900 return (0);
1901 1901 }
1902 1902
1903 1903 /*
1904 1904 * Called to migrate all interrupts at an irq to another cpu.
1905 1905 * Must be called with interrupts disabled and apic_ioapic_lock held
1906 1906 */
1907 1907 int
1908 1908 apic_rebind_all(apic_irq_t *irq_ptr, int bind_cpu)
1909 1909 {
1910 1910 apic_irq_t *irqptr = irq_ptr;
1911 1911 int retval = 0;
1912 1912
1913 1913 while (irqptr) {
1914 1914 if (irqptr->airq_temp_cpu != IRQ_UNINIT)
1915 1915 retval |= apic_rebind(irqptr, bind_cpu, NULL);
1916 1916 irqptr = irqptr->airq_next;
1917 1917 }
1918 1918
1919 1919 return (retval);
1920 1920 }
1921 1921
1922 1922 /*
1923 1923 * apic_intr_redistribute does all the messy computations for identifying
1924 1924 * which interrupt to move to which CPU. Currently we do just one interrupt
1925 1925 * at a time. This reduces the time we spent doing all this within clock
1926 1926 * interrupt. When it is done in idle, we could do more than 1.
1927 1927 * First we find the most busy and the most free CPU (time in ISR only)
1928 1928 * skipping those CPUs that has been identified as being ineligible (cpu_skip)
1929 1929 * Then we look for IRQs which are closest to the difference between the
1930 1930 * most busy CPU and the average ISR load. We try to find one whose load
1931 1931 * is less than difference.If none exists, then we chose one larger than the
1932 1932 * difference, provided it does not make the most idle CPU worse than the
1933 1933 * most busy one. In the end, we clear all the busy fields for CPUs. For
1934 1934 * IRQs, they are cleared as they are scanned.
1935 1935 */
1936 1936 void
1937 1937 apic_intr_redistribute(void)
1938 1938 {
1939 1939 int busiest_cpu, most_free_cpu;
1940 1940 int cpu_free, cpu_busy, max_busy, min_busy;
1941 1941 int min_free, diff;
1942 1942 int average_busy, cpus_online;
1943 1943 int i, busy;
1944 1944 ulong_t iflag;
1945 1945 apic_cpus_info_t *cpu_infop;
1946 1946 apic_irq_t *min_busy_irq = NULL;
1947 1947 apic_irq_t *max_busy_irq = NULL;
1948 1948
1949 1949 busiest_cpu = most_free_cpu = -1;
1950 1950 cpu_free = cpu_busy = max_busy = average_busy = 0;
1951 1951 min_free = apic_sample_factor_redistribution;
1952 1952 cpus_online = 0;
1953 1953 /*
1954 1954 * Below we will check for CPU_INTR_ENABLE, bound, temp_bound, temp_cpu
1955 1955 * without ioapic_lock. That is OK as we are just doing statistical
1956 1956 * sampling anyway and any inaccuracy now will get corrected next time
1957 1957 * The call to rebind which actually changes things will make sure
1958 1958 * we are consistent.
1959 1959 */
1960 1960 for (i = 0; i < apic_nproc; i++) {
1961 1961 if (apic_cpu_in_range(i) &&
1962 1962 !(apic_redist_cpu_skip & (1 << i)) &&
1963 1963 (apic_cpus[i].aci_status & APIC_CPU_INTR_ENABLE)) {
1964 1964
1965 1965 cpu_infop = &apic_cpus[i];
1966 1966 /*
1967 1967 * If no unbound interrupts or only 1 total on this
1968 1968 * CPU, skip
1969 1969 */
1970 1970 if (!cpu_infop->aci_temp_bound ||
1971 1971 (cpu_infop->aci_bound + cpu_infop->aci_temp_bound)
1972 1972 == 1) {
1973 1973 apic_redist_cpu_skip |= 1 << i;
1974 1974 continue;
1975 1975 }
1976 1976
1977 1977 busy = cpu_infop->aci_busy;
1978 1978 average_busy += busy;
1979 1979 cpus_online++;
1980 1980 if (max_busy < busy) {
1981 1981 max_busy = busy;
1982 1982 busiest_cpu = i;
1983 1983 }
1984 1984 if (min_free > busy) {
1985 1985 min_free = busy;
1986 1986 most_free_cpu = i;
1987 1987 }
1988 1988 if (busy > apic_int_busy_mark) {
1989 1989 cpu_busy |= 1 << i;
1990 1990 } else {
1991 1991 if (busy < apic_int_free_mark)
1992 1992 cpu_free |= 1 << i;
1993 1993 }
1994 1994 }
1995 1995 }
1996 1996 if ((cpu_busy && cpu_free) ||
1997 1997 (max_busy >= (min_free + apic_diff_for_redistribution))) {
1998 1998
1999 1999 apic_num_imbalance++;
2000 2000 #ifdef DEBUG
2001 2001 if (apic_verbose & APIC_VERBOSE_IOAPIC_FLAG) {
2002 2002 prom_printf(
2003 2003 "redistribute busy=%x free=%x max=%x min=%x",
2004 2004 cpu_busy, cpu_free, max_busy, min_free);
2005 2005 }
2006 2006 #endif /* DEBUG */
2007 2007
2008 2008
2009 2009 average_busy /= cpus_online;
2010 2010
2011 2011 diff = max_busy - average_busy;
2012 2012 min_busy = max_busy; /* start with the max possible value */
2013 2013 max_busy = 0;
2014 2014 min_busy_irq = max_busy_irq = NULL;
2015 2015 i = apic_min_device_irq;
2016 2016 for (; i <= apic_max_device_irq; i++) {
2017 2017 apic_irq_t *irq_ptr;
2018 2018 /* Change to linked list per CPU ? */
2019 2019 if ((irq_ptr = apic_irq_table[i]) == NULL)
2020 2020 continue;
2021 2021 /* Check for irq_busy & decide which one to move */
2022 2022 /* Also zero them for next round */
2023 2023 if ((irq_ptr->airq_temp_cpu == busiest_cpu) &&
2024 2024 irq_ptr->airq_busy) {
2025 2025 if (irq_ptr->airq_busy < diff) {
2026 2026 /*
2027 2027 * Check for least busy CPU,
2028 2028 * best fit or what ?
2029 2029 */
2030 2030 if (max_busy < irq_ptr->airq_busy) {
2031 2031 /*
2032 2032 * Most busy within the
2033 2033 * required differential
2034 2034 */
2035 2035 max_busy = irq_ptr->airq_busy;
2036 2036 max_busy_irq = irq_ptr;
2037 2037 }
2038 2038 } else {
2039 2039 if (min_busy > irq_ptr->airq_busy) {
2040 2040 /*
2041 2041 * least busy, but more than
2042 2042 * the reqd diff
2043 2043 */
2044 2044 if (min_busy <
2045 2045 (diff + average_busy -
2046 2046 min_free)) {
2047 2047 /*
2048 2048 * Making sure new cpu
2049 2049 * will not end up
2050 2050 * worse
2051 2051 */
2052 2052 min_busy =
2053 2053 irq_ptr->airq_busy;
2054 2054
2055 2055 min_busy_irq = irq_ptr;
2056 2056 }
2057 2057 }
2058 2058 }
2059 2059 }
2060 2060 irq_ptr->airq_busy = 0;
2061 2061 }
2062 2062
2063 2063 if (max_busy_irq != NULL) {
2064 2064 #ifdef DEBUG
2065 2065 if (apic_verbose & APIC_VERBOSE_IOAPIC_FLAG) {
2066 2066 prom_printf("rebinding %x to %x",
2067 2067 max_busy_irq->airq_vector, most_free_cpu);
2068 2068 }
2069 2069 #endif /* DEBUG */
2070 2070 iflag = intr_clear();
2071 2071 if (lock_try(&apic_ioapic_lock)) {
2072 2072 if (apic_rebind_all(max_busy_irq,
2073 2073 most_free_cpu) == 0) {
2074 2074 /* Make change permenant */
2075 2075 max_busy_irq->airq_cpu =
2076 2076 (uint32_t)most_free_cpu;
2077 2077 }
2078 2078 lock_clear(&apic_ioapic_lock);
2079 2079 }
2080 2080 intr_restore(iflag);
2081 2081
2082 2082 } else if (min_busy_irq != NULL) {
2083 2083 #ifdef DEBUG
2084 2084 if (apic_verbose & APIC_VERBOSE_IOAPIC_FLAG) {
2085 2085 prom_printf("rebinding %x to %x",
2086 2086 min_busy_irq->airq_vector, most_free_cpu);
2087 2087 }
2088 2088 #endif /* DEBUG */
2089 2089
2090 2090 iflag = intr_clear();
2091 2091 if (lock_try(&apic_ioapic_lock)) {
2092 2092 if (apic_rebind_all(min_busy_irq,
2093 2093 most_free_cpu) == 0) {
2094 2094 /* Make change permenant */
2095 2095 min_busy_irq->airq_cpu =
2096 2096 (uint32_t)most_free_cpu;
2097 2097 }
2098 2098 lock_clear(&apic_ioapic_lock);
2099 2099 }
2100 2100 intr_restore(iflag);
2101 2101
2102 2102 } else {
2103 2103 if (cpu_busy != (1 << busiest_cpu)) {
2104 2104 apic_redist_cpu_skip |= 1 << busiest_cpu;
2105 2105 /*
2106 2106 * We leave cpu_skip set so that next time we
2107 2107 * can choose another cpu
2108 2108 */
2109 2109 }
2110 2110 }
2111 2111 apic_num_rebind++;
2112 2112 } else {
2113 2113 /*
2114 2114 * found nothing. Could be that we skipped over valid CPUs
2115 2115 * or we have balanced everything. If we had a variable
2116 2116 * ticks_for_redistribution, it could be increased here.
2117 2117 * apic_int_busy, int_free etc would also need to be
2118 2118 * changed.
2119 2119 */
2120 2120 if (apic_redist_cpu_skip)
2121 2121 apic_redist_cpu_skip = 0;
2122 2122 }
2123 2123 for (i = 0; i < apic_nproc; i++) {
2124 2124 if (apic_cpu_in_range(i)) {
2125 2125 apic_cpus[i].aci_busy = 0;
2126 2126 }
2127 2127 }
2128 2128 }
2129 2129
2130 2130 void
2131 2131 apic_cleanup_busy(void)
2132 2132 {
2133 2133 int i;
2134 2134 apic_irq_t *irq_ptr;
2135 2135
2136 2136 for (i = 0; i < apic_nproc; i++) {
2137 2137 if (apic_cpu_in_range(i)) {
2138 2138 apic_cpus[i].aci_busy = 0;
2139 2139 }
2140 2140 }
2141 2141
2142 2142 for (i = apic_min_device_irq; i <= apic_max_device_irq; i++) {
2143 2143 if ((irq_ptr = apic_irq_table[i]) != NULL)
2144 2144 irq_ptr->airq_busy = 0;
2145 2145 }
2146 2146 }
2147 2147
2148 2148 int
2149 2149 apic_ioapic_method_probe()
2150 2150 {
2151 2151 return (PSM_SUCCESS);
2152 2152 }
↓ open down ↓ |
2098 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX