lapic timer: Improve lapic timer testing
[dragonfly.git] / sys / platform / pc32 / apic / mpapic.c
blob773b14c61d97a30d4299761b7b10e10f690a16a3
1 /*
2 * Copyright (c) 1996, by Steve Passe
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. The name of the developer may NOT be used to endorse or promote products
11 * derived from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
25 * $FreeBSD: src/sys/i386/i386/mpapic.c,v 1.37.2.7 2003/01/25 02:31:47 peter Exp $
26 * $DragonFly: src/sys/platform/pc32/apic/mpapic.c,v 1.22 2008/04/20 13:44:26 swildner Exp $
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <machine/globaldata.h>
33 #include <machine/smp.h>
34 #include <machine/md_var.h>
35 #include <machine_base/apic/mpapic.h>
36 #include <machine/segments.h>
37 #include <sys/thread2.h>
39 #include <machine_base/isa/intr_machdep.h> /* Xspuriousint() */
41 /* EISA Edge/Level trigger control registers */
42 #define ELCR0 0x4d0 /* eisa irq 0-7 */
43 #define ELCR1 0x4d1 /* eisa irq 8-15 */
45 static void lapic_timer_calibrate(void);
46 static void lapic_timer_set_divisor(int);
47 void lapic_timer_process(void);
48 void lapic_timer_process_frame(struct intrframe *);
49 void lapic_timer_intr_test(void);
50 void lapic_timer_oneshot_intr_enable(void);
52 int lapic_timer_test;
53 TUNABLE_INT("hw.lapic_timer_test", &lapic_timer_test);
56 * pointers to pmapped apic hardware.
59 volatile ioapic_t **ioapic;
61 static sysclock_t lapic_timer_freq;
62 static int lapic_timer_divisor_idx = -1;
63 static const uint32_t lapic_timer_divisors[] = {
64 APIC_TDCR_2, APIC_TDCR_4, APIC_TDCR_8, APIC_TDCR_16,
65 APIC_TDCR_32, APIC_TDCR_64, APIC_TDCR_128, APIC_TDCR_1
67 #define APIC_TIMER_NDIVISORS \
68 (int)(sizeof(lapic_timer_divisors) / sizeof(lapic_timer_divisors[0]))
72 * Enable APIC, configure interrupts.
74 void
75 apic_initialize(boolean_t bsp)
77 uint32_t timer;
78 u_int temp;
81 * setup LVT1 as ExtINT on the BSP. This is theoretically an
82 * aggregate interrupt input from the 8259. The INTA cycle
83 * will be routed to the external controller (the 8259) which
84 * is expected to supply the vector.
86 * Must be setup edge triggered, active high.
88 * Disable LVT1 on the APs. It doesn't matter what delivery
89 * mode we use because we leave it masked.
91 temp = lapic.lvt_lint0;
92 temp &= ~(APIC_LVT_MASKED | APIC_LVT_TRIG_MASK |
93 APIC_LVT_POLARITY_MASK | APIC_LVT_DM_MASK);
94 if (mycpu->gd_cpuid == 0)
95 temp |= APIC_LVT_DM_EXTINT;
96 else
97 temp |= APIC_LVT_DM_FIXED | APIC_LVT_MASKED;
98 lapic.lvt_lint0 = temp;
101 * setup LVT2 as NMI, masked till later. Edge trigger, active high.
103 temp = lapic.lvt_lint1;
104 temp &= ~(APIC_LVT_MASKED | APIC_LVT_TRIG_MASK |
105 APIC_LVT_POLARITY_MASK | APIC_LVT_DM_MASK);
106 temp |= APIC_LVT_MASKED | APIC_LVT_DM_NMI;
107 lapic.lvt_lint1 = temp;
110 * Mask the apic error interrupt, apic performance counter
111 * interrupt.
113 lapic.lvt_error = lapic.lvt_error | APIC_LVT_MASKED;
114 lapic.lvt_pcint = lapic.lvt_pcint | APIC_LVT_MASKED;
116 /* Set apic timer vector and mask the apic timer interrupt. */
117 timer = lapic.lvt_timer;
118 timer &= ~APIC_LVTT_VECTOR;
119 timer |= XTIMER_OFFSET;
120 timer |= APIC_LVTT_MASKED;
121 lapic.lvt_timer = timer;
124 * Set the Task Priority Register as needed. At the moment allow
125 * interrupts on all cpus (the APs will remain CLId until they are
126 * ready to deal). We could disable all but IPIs by setting
127 * temp |= TPR_IPI_ONLY for cpu != 0.
129 temp = lapic.tpr;
130 temp &= ~APIC_TPR_PRIO; /* clear priority field */
131 #ifndef APIC_IO
133 * If we are NOT running the IO APICs, the LAPIC will only be used
134 * for IPIs. Set the TPR to prevent any unintentional interrupts.
136 temp |= TPR_IPI_ONLY;
137 #endif
139 lapic.tpr = temp;
142 * enable the local APIC
144 temp = lapic.svr;
145 temp |= APIC_SVR_ENABLE; /* enable the APIC */
146 temp &= ~APIC_SVR_FOCUS_DISABLE; /* enable lopri focus processor */
149 * Set the spurious interrupt vector. The low 4 bits of the vector
150 * must be 1111.
152 if ((XSPURIOUSINT_OFFSET & 0x0F) != 0x0F)
153 panic("bad XSPURIOUSINT_OFFSET: 0x%08x", XSPURIOUSINT_OFFSET);
154 temp &= ~APIC_SVR_VECTOR;
155 temp |= XSPURIOUSINT_OFFSET;
157 lapic.svr = temp;
160 * Pump out a few EOIs to clean out interrupts that got through
161 * before we were able to set the TPR.
163 lapic.eoi = 0;
164 lapic.eoi = 0;
165 lapic.eoi = 0;
167 if (strcmp(cpu_vendor, "AuthenticAMD") == 0) {
169 * Detect the presence of C1E capability mostly on latest
170 * dual-cores (or future) k8 family. This feature renders
171 * the local APIC timer dead, so we disable it by reading
172 * the Interrupt Pending Message register and clearing both
173 * C1eOnCmpHalt (bit 28) and SmiOnCmpHalt (bit 27).
175 * Reference:
176 * "BIOS and Kernel Developer's Guide for AMD NPT
177 * Family 0Fh Processors"
178 * #32559 revision 3.00
180 if ((cpu_id & 0x00000f00) == 0x00000f00 &&
181 (cpu_id & 0x0fff0000) >= 0x00040000) {
182 uint64_t msr;
184 msr = rdmsr(0xc0010055);
185 if (msr & 0x18000000)
186 wrmsr(0xc0010055, msr & ~0x18000000ULL);
190 if (bsp)
191 lapic_timer_calibrate();
192 else
193 lapic_timer_set_divisor(lapic_timer_divisor_idx);
195 if (bootverbose)
196 apic_dump("apic_initialize()");
200 static void
201 lapic_timer_set_divisor(int divisor_idx)
203 KKASSERT(divisor_idx >= 0 && divisor_idx < APIC_TIMER_NDIVISORS);
204 lapic.dcr_timer = lapic_timer_divisors[divisor_idx];
207 static void
208 lapic_timer_oneshot(u_int count)
210 uint32_t value;
212 value = lapic.lvt_timer;
213 value &= ~APIC_LVTT_PERIODIC;
214 lapic.lvt_timer = value;
215 lapic.icr_timer = count;
218 static void
219 lapic_timer_oneshot_quick(u_int count)
221 lapic.icr_timer = count;
224 static void
225 lapic_timer_calibrate(void)
227 sysclock_t value;
229 /* Try to calibrate the local APIC timer. */
230 for (lapic_timer_divisor_idx = 0;
231 lapic_timer_divisor_idx < APIC_TIMER_NDIVISORS;
232 lapic_timer_divisor_idx++) {
233 lapic_timer_set_divisor(lapic_timer_divisor_idx);
234 lapic_timer_oneshot(APIC_TIMER_MAX_COUNT);
235 DELAY(2000000);
236 value = APIC_TIMER_MAX_COUNT - lapic.ccr_timer;
237 if (value != APIC_TIMER_MAX_COUNT)
238 break;
240 if (lapic_timer_divisor_idx >= APIC_TIMER_NDIVISORS)
241 panic("lapic: no proper timer divisor?!\n");
242 lapic_timer_freq = value / 2;
244 kprintf("lapic: divisor index %d, frequency %u Hz\n",
245 lapic_timer_divisor_idx, lapic_timer_freq);
248 void
249 lapic_timer_process(void)
251 struct globaldata *gd = mycpu;
253 gd->gd_timer_running = 0;
255 if (lapic_timer_test)
256 kprintf("%d proc\n", gd->gd_cpuid);
259 void
260 lapic_timer_process_frame(struct intrframe *frame)
262 struct globaldata *gd = mycpu;
264 gd->gd_timer_running = 0;
266 if (lapic_timer_test)
267 kprintf("%d proc frame\n", gd->gd_cpuid);
270 void
271 lapic_timer_intr_test(void)
273 struct globaldata *gd = mycpu;
275 if (!gd->gd_timer_running) {
276 gd->gd_timer_running = 1;
277 KKASSERT(lapic_timer_freq != 0);
278 lapic_timer_oneshot_quick(lapic_timer_freq);
282 void
283 lapic_timer_oneshot_intr_enable(void)
285 uint32_t timer;
287 timer = lapic.lvt_timer;
288 timer &= ~(APIC_LVTT_MASKED | APIC_LVTT_PERIODIC);
289 lapic.lvt_timer = timer;
294 * dump contents of local APIC registers
296 void
297 apic_dump(char* str)
299 kprintf("SMP: CPU%d %s:\n", mycpu->gd_cpuid, str);
300 kprintf(" lint0: 0x%08x lint1: 0x%08x TPR: 0x%08x SVR: 0x%08x\n",
301 lapic.lvt_lint0, lapic.lvt_lint1, lapic.tpr, lapic.svr);
305 #if defined(APIC_IO)
308 * IO APIC code,
311 #define IOAPIC_ISA_INTS 16
312 #define REDIRCNT_IOAPIC(A) \
313 ((int)((io_apic_versions[(A)] & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1)
315 static int trigger (int apic, int pin, u_int32_t * flags);
316 static void polarity (int apic, int pin, u_int32_t * flags, int level);
318 #define DEFAULT_FLAGS \
319 ((u_int32_t) \
320 (IOART_INTMSET | \
321 IOART_DESTPHY | \
322 IOART_DELLOPRI))
324 #define DEFAULT_ISA_FLAGS \
325 ((u_int32_t) \
326 (IOART_INTMSET | \
327 IOART_TRGREDG | \
328 IOART_INTAHI | \
329 IOART_DESTPHY | \
330 IOART_DELLOPRI))
332 void
333 io_apic_set_id(int apic, int id)
335 u_int32_t ux;
337 ux = io_apic_read(apic, IOAPIC_ID); /* get current contents */
338 if (((ux & APIC_ID_MASK) >> 24) != id) {
339 kprintf("Changing APIC ID for IO APIC #%d"
340 " from %d to %d on chip\n",
341 apic, ((ux & APIC_ID_MASK) >> 24), id);
342 ux &= ~APIC_ID_MASK; /* clear the ID field */
343 ux |= (id << 24);
344 io_apic_write(apic, IOAPIC_ID, ux); /* write new value */
345 ux = io_apic_read(apic, IOAPIC_ID); /* re-read && test */
346 if (((ux & APIC_ID_MASK) >> 24) != id)
347 panic("can't control IO APIC #%d ID, reg: 0x%08x",
348 apic, ux);
354 io_apic_get_id(int apic)
356 return (io_apic_read(apic, IOAPIC_ID) & APIC_ID_MASK) >> 24;
362 * Setup the IO APIC.
365 extern int apic_pin_trigger; /* 'opaque' */
367 void
368 io_apic_setup_intpin(int apic, int pin)
370 int bus, bustype, irq;
371 u_char select; /* the select register is 8 bits */
372 u_int32_t flags; /* the window register is 32 bits */
373 u_int32_t target; /* the window register is 32 bits */
374 u_int32_t vector; /* the window register is 32 bits */
375 int level;
377 select = pin * 2 + IOAPIC_REDTBL0; /* register */
380 * Always clear an IO APIC pin before [re]programming it. This is
381 * particularly important if the pin is set up for a level interrupt
382 * as the IOART_REM_IRR bit might be set. When we reprogram the
383 * vector any EOI from pending ints on this pin could be lost and
384 * IRR might never get reset.
386 * To fix this problem, clear the vector and make sure it is
387 * programmed as an edge interrupt. This should theoretically
388 * clear IRR so we can later, safely program it as a level
389 * interrupt.
391 imen_lock();
393 flags = io_apic_read(apic, select) & IOART_RESV;
394 flags |= IOART_INTMSET | IOART_TRGREDG | IOART_INTAHI;
395 flags |= IOART_DESTPHY | IOART_DELFIXED;
397 target = io_apic_read(apic, select + 1) & IOART_HI_DEST_RESV;
398 target |= 0; /* fixed mode cpu mask of 0 - don't deliver anywhere */
400 vector = 0;
402 io_apic_write(apic, select, flags | vector);
403 io_apic_write(apic, select + 1, target);
405 imen_unlock();
408 * We only deal with vectored interrupts here. ? documentation is
409 * lacking, I'm guessing an interrupt type of 0 is the 'INT' type,
410 * vs ExTINT, etc.
412 * This test also catches unconfigured pins.
414 if (apic_int_type(apic, pin) != 0)
415 return;
418 * Leave the pin unprogrammed if it does not correspond to
419 * an IRQ.
421 irq = apic_irq(apic, pin);
422 if (irq < 0)
423 return;
425 /* determine the bus type for this pin */
426 bus = apic_src_bus_id(apic, pin);
427 if (bus < 0)
428 return;
429 bustype = apic_bus_type(bus);
431 if ((bustype == ISA) &&
432 (pin < IOAPIC_ISA_INTS) &&
433 (irq == pin) &&
434 (apic_polarity(apic, pin) == 0x1) &&
435 (apic_trigger(apic, pin) == 0x3)) {
437 * A broken BIOS might describe some ISA
438 * interrupts as active-high level-triggered.
439 * Use default ISA flags for those interrupts.
441 flags = DEFAULT_ISA_FLAGS;
442 } else {
444 * Program polarity and trigger mode according to
445 * interrupt entry.
447 flags = DEFAULT_FLAGS;
448 level = trigger(apic, pin, &flags);
449 if (level == 1)
450 apic_pin_trigger |= (1 << irq);
451 polarity(apic, pin, &flags, level);
454 if (bootverbose) {
455 kprintf("IOAPIC #%d intpin %d -> irq %d\n",
456 apic, pin, irq);
460 * Program the appropriate registers. This routing may be
461 * overridden when an interrupt handler for a device is
462 * actually added (see register_int(), which calls through
463 * the MACHINTR ABI to set up an interrupt handler/vector).
465 * The order in which we must program the two registers for
466 * safety is unclear! XXX
468 imen_lock();
470 vector = IDT_OFFSET + irq; /* IDT vec */
471 target = io_apic_read(apic, select + 1) & IOART_HI_DEST_RESV;
472 target |= IOART_HI_DEST_BROADCAST;
473 flags |= io_apic_read(apic, select) & IOART_RESV;
474 io_apic_write(apic, select, flags | vector);
475 io_apic_write(apic, select + 1, target);
477 imen_unlock();
481 io_apic_setup(int apic)
483 int maxpin;
484 int pin;
486 if (apic == 0)
487 apic_pin_trigger = 0; /* default to edge-triggered */
489 maxpin = REDIRCNT_IOAPIC(apic); /* pins in APIC */
490 kprintf("Programming %d pins in IOAPIC #%d\n", maxpin, apic);
492 for (pin = 0; pin < maxpin; ++pin) {
493 io_apic_setup_intpin(apic, pin);
495 while (pin < 32) {
496 if (apic_int_type(apic, pin) >= 0) {
497 kprintf("Warning: IOAPIC #%d pin %d does not exist,"
498 " cannot program!\n", apic, pin);
500 ++pin;
503 /* return GOOD status */
504 return 0;
506 #undef DEFAULT_ISA_FLAGS
507 #undef DEFAULT_FLAGS
510 #define DEFAULT_EXTINT_FLAGS \
511 ((u_int32_t) \
512 (IOART_INTMSET | \
513 IOART_TRGREDG | \
514 IOART_INTAHI | \
515 IOART_DESTPHY | \
516 IOART_DELLOPRI))
519 * Setup the source of External INTerrupts.
522 ext_int_setup(int apic, int intr)
524 u_char select; /* the select register is 8 bits */
525 u_int32_t flags; /* the window register is 32 bits */
526 u_int32_t target; /* the window register is 32 bits */
527 u_int32_t vector; /* the window register is 32 bits */
529 if (apic_int_type(apic, intr) != 3)
530 return -1;
532 target = IOART_HI_DEST_BROADCAST;
533 select = IOAPIC_REDTBL0 + (2 * intr);
534 vector = IDT_OFFSET + intr;
535 flags = DEFAULT_EXTINT_FLAGS;
537 io_apic_write(apic, select, flags | vector);
538 io_apic_write(apic, select + 1, target);
540 return 0;
542 #undef DEFAULT_EXTINT_FLAGS
546 * Set the trigger level for an IO APIC pin.
548 static int
549 trigger(int apic, int pin, u_int32_t * flags)
551 int id;
552 int eirq;
553 int level;
554 static int intcontrol = -1;
556 switch (apic_trigger(apic, pin)) {
558 case 0x00:
559 break;
561 case 0x01:
562 *flags &= ~IOART_TRGRLVL; /* *flags |= IOART_TRGREDG */
563 return 0;
565 case 0x03:
566 *flags |= IOART_TRGRLVL;
567 return 1;
569 case -1:
570 default:
571 goto bad;
574 if ((id = apic_src_bus_id(apic, pin)) == -1)
575 goto bad;
577 switch (apic_bus_type(id)) {
578 case ISA:
579 *flags &= ~IOART_TRGRLVL; /* *flags |= IOART_TRGREDG; */
580 return 0;
582 case EISA:
583 eirq = apic_src_bus_irq(apic, pin);
585 if (eirq < 0 || eirq > 15) {
586 kprintf("EISA IRQ %d?!?!\n", eirq);
587 goto bad;
590 if (intcontrol == -1) {
591 intcontrol = inb(ELCR1) << 8;
592 intcontrol |= inb(ELCR0);
593 kprintf("EISA INTCONTROL = %08x\n", intcontrol);
596 /* Use ELCR settings to determine level or edge mode */
597 level = (intcontrol >> eirq) & 1;
600 * Note that on older Neptune chipset based systems, any
601 * pci interrupts often show up here and in the ELCR as well
602 * as level sensitive interrupts attributed to the EISA bus.
605 if (level)
606 *flags |= IOART_TRGRLVL;
607 else
608 *flags &= ~IOART_TRGRLVL;
610 return level;
612 case PCI:
613 *flags |= IOART_TRGRLVL;
614 return 1;
616 case -1:
617 default:
618 goto bad;
621 bad:
622 panic("bad APIC IO INT flags");
627 * Set the polarity value for an IO APIC pin.
629 static void
630 polarity(int apic, int pin, u_int32_t * flags, int level)
632 int id;
634 switch (apic_polarity(apic, pin)) {
636 case 0x00:
637 break;
639 case 0x01:
640 *flags &= ~IOART_INTALO; /* *flags |= IOART_INTAHI */
641 return;
643 case 0x03:
644 *flags |= IOART_INTALO;
645 return;
647 case -1:
648 default:
649 goto bad;
652 if ((id = apic_src_bus_id(apic, pin)) == -1)
653 goto bad;
655 switch (apic_bus_type(id)) {
656 case ISA:
657 *flags &= ~IOART_INTALO; /* *flags |= IOART_INTAHI */
658 return;
660 case EISA:
661 /* polarity converter always gives active high */
662 *flags &= ~IOART_INTALO;
663 return;
665 case PCI:
666 *flags |= IOART_INTALO;
667 return;
669 case -1:
670 default:
671 goto bad;
674 bad:
675 panic("bad APIC IO INT flags");
680 * Print contents of apic_imen.
682 extern u_int apic_imen; /* keep apic_imen 'opaque' */
683 void
684 imen_dump(void)
686 int x;
688 kprintf("SMP: enabled INTs: ");
689 for (x = 0; x < 24; ++x)
690 if ((apic_imen & (1 << x)) == 0)
691 kprintf("%d, ", x);
692 kprintf("apic_imen: 0x%08x\n", apic_imen);
697 * Inter Processor Interrupt functions.
700 #endif /* APIC_IO */
703 * Send APIC IPI 'vector' to 'destType' via 'deliveryMode'.
705 * destType is 1 of: APIC_DEST_SELF, APIC_DEST_ALLISELF, APIC_DEST_ALLESELF
706 * vector is any valid SYSTEM INT vector
707 * delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
709 * A backlog of requests can create a deadlock between cpus. To avoid this
710 * we have to be able to accept IPIs at the same time we are trying to send
711 * them. The critical section prevents us from attempting to send additional
712 * IPIs reentrantly, but also prevents IPIQ processing so we have to call
713 * lwkt_process_ipiq() manually. It's rather messy and expensive for this
714 * to occur but fortunately it does not happen too often.
717 apic_ipi(int dest_type, int vector, int delivery_mode)
719 u_long icr_lo;
721 crit_enter();
722 if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
723 unsigned int eflags = read_eflags();
724 cpu_enable_intr();
725 while ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
726 lwkt_process_ipiq();
728 write_eflags(eflags);
731 icr_lo = (lapic.icr_lo & APIC_ICRLO_RESV_MASK) | dest_type |
732 delivery_mode | vector;
733 lapic.icr_lo = icr_lo;
734 crit_exit();
735 return 0;
738 void
739 single_apic_ipi(int cpu, int vector, int delivery_mode)
741 u_long icr_lo;
742 u_long icr_hi;
744 crit_enter();
745 if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
746 unsigned int eflags = read_eflags();
747 cpu_enable_intr();
748 while ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
749 lwkt_process_ipiq();
751 write_eflags(eflags);
753 icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
754 icr_hi |= (CPU_TO_ID(cpu) << 24);
755 lapic.icr_hi = icr_hi;
757 /* build ICR_LOW */
758 icr_lo = (lapic.icr_lo & APIC_ICRLO_RESV_MASK)
759 | APIC_DEST_DESTFLD | delivery_mode | vector;
761 /* write APIC ICR */
762 lapic.icr_lo = icr_lo;
763 crit_exit();
766 #if 0
769 * Returns 0 if the apic is busy, 1 if we were able to queue the request.
771 * NOT WORKING YET! The code as-is may end up not queueing an IPI at all
772 * to the target, and the scheduler does not 'poll' for IPI messages.
775 single_apic_ipi_passive(int cpu, int vector, int delivery_mode)
777 u_long icr_lo;
778 u_long icr_hi;
780 crit_enter();
781 if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
782 crit_exit();
783 return(0);
785 icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
786 icr_hi |= (CPU_TO_ID(cpu) << 24);
787 lapic.icr_hi = icr_hi;
789 /* build IRC_LOW */
790 icr_lo = (lapic.icr_lo & APIC_RESV2_MASK)
791 | APIC_DEST_DESTFLD | delivery_mode | vector;
793 /* write APIC ICR */
794 lapic.icr_lo = icr_lo;
795 crit_exit();
796 return(1);
799 #endif
802 * Send APIC IPI 'vector' to 'target's via 'delivery_mode'.
804 * target is a bitmask of destination cpus. Vector is any
805 * valid system INT vector. Delivery mode may be either
806 * APIC_DELMODE_FIXED or APIC_DELMODE_LOWPRIO.
808 void
809 selected_apic_ipi(u_int target, int vector, int delivery_mode)
811 crit_enter();
812 while (target) {
813 int n = bsfl(target);
814 target &= ~(1 << n);
815 single_apic_ipi(n, vector, delivery_mode);
817 crit_exit();
821 * Timer code, in development...
822 * - suggested by rgrimes@gndrsh.aac.dev.com
826 * Load a 'downcount time' in uSeconds.
828 void
829 set_apic_timer(int us)
831 u_int count;
834 * When we reach here, lapic timer's frequency
835 * must have been calculated as well as the
836 * divisor (lapic.dcr_timer is setup during the
837 * divisor calculation).
839 KKASSERT(lapic_timer_freq != 0 &&
840 lapic_timer_divisor_idx >= 0);
842 count = ((us * (int64_t)lapic_timer_freq) + 999999) / 1000000;
843 lapic_timer_oneshot(count);
848 * Read remaining time in timer.
851 read_apic_timer(void)
853 #if 0
854 /** XXX FIXME: we need to return the actual remaining time,
855 * for now we just return the remaining count.
857 #else
858 return lapic.ccr_timer;
859 #endif
864 * Spin-style delay, set delay time in uS, spin till it drains.
866 void
867 u_sleep(int count)
869 set_apic_timer(count);
870 while (read_apic_timer())
871 /* spin */ ;