d390cffb6ea6cb6a1c190889991b44ab237ce0b8
[dragonfly.git] / sys / platform / pc32 / i386 / mpapic.c
1 /*
2  * Copyright (c) 1996, by Steve Passe
3  * All rights reserved.
4  *
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.
12  *
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.
24  *
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/i386/Attic/mpapic.c,v 1.4 2003/07/06 21:23:48 dillon Exp $
27  */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <machine/smptests.h>   /** TEST_TEST1, GRAB_LOPRIO */
32 #include <machine/globaldata.h>
33 #include <machine/smp.h>
34 #include <machine/mpapic.h>
35 #include <machine/segments.h>
36
37 #include <i386/isa/intr_machdep.h>      /* Xspuriousint() */
38
39 /* EISA Edge/Level trigger control registers */
40 #define ELCR0   0x4d0                   /* eisa irq 0-7 */
41 #define ELCR1   0x4d1                   /* eisa irq 8-15 */
42
43 /*
44  * pointers to pmapped apic hardware.
45  */
46
47 #if defined(APIC_IO)
48 volatile ioapic_t       **ioapic;
49 #endif  /* APIC_IO */
50
51 /*
52  * Enable APIC, configure interrupts.
53  */
54 void
55 apic_initialize(void)
56 {
57         u_int   temp;
58
59         /* setup LVT1 as ExtINT */
60         temp = lapic.lvt_lint0;
61         temp &= ~(APIC_LVT_M | APIC_LVT_TM | APIC_LVT_IIPP | APIC_LVT_DM);
62         if (mycpu->gd_cpuid == 0)
63                 temp |= 0x00000700;     /* process ExtInts */
64         else
65                 temp |= 0x00010700;     /* mask ExtInts */
66         lapic.lvt_lint0 = temp;
67
68         /* setup LVT2 as NMI, masked till later... */
69         temp = lapic.lvt_lint1;
70         temp &= ~(APIC_LVT_M | APIC_LVT_TM | APIC_LVT_IIPP | APIC_LVT_DM);
71         temp |= 0x00010400;             /* masked, edge trigger, active hi */
72         lapic.lvt_lint1 = temp;
73
74         /* set the Task Priority Register as needed */
75         temp = lapic.tpr;
76         temp &= ~APIC_TPR_PRIO;         /* clear priority field */
77
78         /*
79          * Leave the BSP and TPR 0 during boot so it gets all the interrupts,
80          * set APs at TPR 0xF0 at boot so they get no ints.
81          */
82         if (mycpu->gd_cpuid != 0)
83                 temp |= TPR_IPI_ONLY;   /* disable INTs on this cpu */
84         lapic.tpr = temp;
85
86         /* enable the local APIC */
87         temp = lapic.svr;
88         temp |= APIC_SVR_SWEN;          /* software enable APIC */
89         temp &= ~APIC_SVR_FOCUS;        /* enable 'focus processor' */
90
91         /* set the 'spurious INT' vector */
92         if ((XSPURIOUSINT_OFFSET & APIC_SVR_VEC_FIX) != APIC_SVR_VEC_FIX)
93                 panic("bad XSPURIOUSINT_OFFSET: 0x%08x", XSPURIOUSINT_OFFSET);
94         temp &= ~APIC_SVR_VEC_PROG;     /* clear (programmable) vector field */
95         temp |= (XSPURIOUSINT_OFFSET & APIC_SVR_VEC_PROG);
96
97 #if defined(TEST_TEST1)
98         if (cpuid == GUARD_CPU) {
99                 temp &= ~APIC_SVR_SWEN; /* software DISABLE APIC */
100         }
101 #endif  /** TEST_TEST1 */
102
103         lapic.svr = temp;
104
105         if (bootverbose)
106                 apic_dump("apic_initialize()");
107 }
108
109
110 /*
111  * dump contents of local APIC registers
112  */
113 void
114 apic_dump(char* str)
115 {
116         printf("SMP: CPU%d %s:\n", mycpu->gd_cpuid, str);
117         printf("     lint0: 0x%08x lint1: 0x%08x TPR: 0x%08x SVR: 0x%08x\n",
118                 lapic.lvt_lint0, lapic.lvt_lint1, lapic.tpr, lapic.svr);
119 }
120
121
122 #if defined(APIC_IO)
123
124 /*
125  * IO APIC code,
126  */
127
128 #define IOAPIC_ISA_INTS         16
129 #define REDIRCNT_IOAPIC(A) \
130             ((int)((io_apic_versions[(A)] & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1)
131
132 static int trigger __P((int apic, int pin, u_int32_t * flags));
133 static void polarity __P((int apic, int pin, u_int32_t * flags, int level));
134
135 #define DEFAULT_FLAGS           \
136         ((u_int32_t)            \
137          (IOART_INTMSET |       \
138           IOART_DESTPHY |       \
139           IOART_DELLOPRI))
140
141 #define DEFAULT_ISA_FLAGS       \
142         ((u_int32_t)            \
143          (IOART_INTMSET |       \
144           IOART_TRGREDG |       \
145           IOART_INTAHI |        \
146           IOART_DESTPHY |       \
147           IOART_DELLOPRI))
148
149 void
150 io_apic_set_id(int apic, int id)
151 {
152         u_int32_t ux;
153         
154         ux = io_apic_read(apic, IOAPIC_ID);     /* get current contents */
155         if (((ux & APIC_ID_MASK) >> 24) != id) {
156                 printf("Changing APIC ID for IO APIC #%d"
157                        " from %d to %d on chip\n",
158                        apic, ((ux & APIC_ID_MASK) >> 24), id);
159                 ux &= ~APIC_ID_MASK;    /* clear the ID field */
160                 ux |= (id << 24);
161                 io_apic_write(apic, IOAPIC_ID, ux);     /* write new value */
162                 ux = io_apic_read(apic, IOAPIC_ID);     /* re-read && test */
163                 if (((ux & APIC_ID_MASK) >> 24) != id)
164                         panic("can't control IO APIC #%d ID, reg: 0x%08x",
165                               apic, ux);
166         }
167 }
168
169
170 int
171 io_apic_get_id(int apic)
172 {
173   return (io_apic_read(apic, IOAPIC_ID) & APIC_ID_MASK) >> 24;
174 }
175   
176
177
178 /*
179  * Setup the IO APIC.
180  */
181
182 extern int      apic_pin_trigger;       /* 'opaque' */
183
184 void
185 io_apic_setup_intpin(int apic, int pin)
186 {
187         int bus, bustype, irq;
188         u_char          select;         /* the select register is 8 bits */
189         u_int32_t       flags;          /* the window register is 32 bits */
190         u_int32_t       target;         /* the window register is 32 bits */
191         u_int32_t       vector;         /* the window register is 32 bits */
192         int             level;
193
194         target = IOART_DEST;
195
196         select = pin * 2 + IOAPIC_REDTBL0;      /* register */
197         /* 
198          * Always disable interrupts, and by default map
199          * pin X to IRQX because the disable doesn't stick
200          * and the uninitialize vector will get translated 
201          * into a panic.
202          *
203          * This is correct for IRQs 1 and 3-15.  In the other cases, 
204          * any robust driver will handle the spurious interrupt, and 
205          * the effective NOP beats a panic.
206          *
207          * A dedicated "bogus interrupt" entry in the IDT would
208          * be a nicer hack, although some one should find out 
209          * why some systems are generating interrupts when they
210          * shouldn't and stop the carnage.
211          */
212         vector = NRSVIDT + pin;                 /* IDT vec */
213         imen_lock();
214         io_apic_write(apic, select,
215                       (io_apic_read(apic, select) & ~IOART_INTMASK 
216                        & ~0xff)|IOART_INTMSET|vector);
217         imen_unlock();
218         
219         /* we only deal with vectored INTs here */
220         if (apic_int_type(apic, pin) != 0)
221                 return;
222         
223         irq = apic_irq(apic, pin);
224         if (irq < 0)
225                 return;
226         
227         /* determine the bus type for this pin */
228         bus = apic_src_bus_id(apic, pin);
229         if (bus == -1)
230                 return;
231         bustype = apic_bus_type(bus);
232         
233         if ((bustype == ISA) &&
234             (pin < IOAPIC_ISA_INTS) && 
235             (irq == pin) &&
236             (apic_polarity(apic, pin) == 0x1) &&
237             (apic_trigger(apic, pin) == 0x3)) {
238                 /* 
239                  * A broken BIOS might describe some ISA 
240                  * interrupts as active-high level-triggered.
241                  * Use default ISA flags for those interrupts.
242                  */
243                 flags = DEFAULT_ISA_FLAGS;
244         } else {
245                 /* 
246                  * Program polarity and trigger mode according to 
247                  * interrupt entry.
248                  */
249                 flags = DEFAULT_FLAGS;
250                 level = trigger(apic, pin, &flags);
251                 if (level == 1)
252                         apic_pin_trigger |= (1 << irq);
253                 polarity(apic, pin, &flags, level);
254         }
255         
256         /* program the appropriate registers */
257         if (apic != 0 || pin != irq)
258                 printf("IOAPIC #%d intpin %d -> irq %d\n",
259                        apic, pin, irq);
260         vector = NRSVIDT + irq;                 /* IDT vec */
261         imen_lock();
262         io_apic_write(apic, select, flags | vector);
263         io_apic_write(apic, select + 1, target);
264         imen_unlock();
265 }
266
267 int
268 io_apic_setup(int apic)
269 {
270         int             maxpin;
271         int             pin;
272
273         if (apic == 0)
274                 apic_pin_trigger = 0;   /* default to edge-triggered */
275
276         maxpin = REDIRCNT_IOAPIC(apic);         /* pins in APIC */
277         printf("Programming %d pins in IOAPIC #%d\n", maxpin, apic);
278         
279         for (pin = 0; pin < maxpin; ++pin) {
280                 io_apic_setup_intpin(apic, pin);
281         }
282
283         /* return GOOD status */
284         return 0;
285 }
286 #undef DEFAULT_ISA_FLAGS
287 #undef DEFAULT_FLAGS
288
289
290 #define DEFAULT_EXTINT_FLAGS    \
291         ((u_int32_t)            \
292          (IOART_INTMSET |       \
293           IOART_TRGREDG |       \
294           IOART_INTAHI |        \
295           IOART_DESTPHY |       \
296           IOART_DELLOPRI))
297
298 /*
299  * Setup the source of External INTerrupts.
300  */
301 int
302 ext_int_setup(int apic, int intr)
303 {
304         u_char  select;         /* the select register is 8 bits */
305         u_int32_t flags;        /* the window register is 32 bits */
306         u_int32_t target;       /* the window register is 32 bits */
307         u_int32_t vector;       /* the window register is 32 bits */
308
309         if (apic_int_type(apic, intr) != 3)
310                 return -1;
311
312         target = IOART_DEST;
313         select = IOAPIC_REDTBL0 + (2 * intr);
314         vector = NRSVIDT + intr;
315         flags = DEFAULT_EXTINT_FLAGS;
316
317         io_apic_write(apic, select, flags | vector);
318         io_apic_write(apic, select + 1, target);
319
320         return 0;
321 }
322 #undef DEFAULT_EXTINT_FLAGS
323
324
325 /*
326  * Set the trigger level for an IO APIC pin.
327  */
328 static int
329 trigger(int apic, int pin, u_int32_t * flags)
330 {
331         int     id;
332         int     eirq;
333         int     level;
334         static int intcontrol = -1;
335
336         switch (apic_trigger(apic, pin)) {
337
338         case 0x00:
339                 break;
340
341         case 0x01:
342                 *flags &= ~IOART_TRGRLVL;       /* *flags |= IOART_TRGREDG */
343                 return 0;
344
345         case 0x03:
346                 *flags |= IOART_TRGRLVL;
347                 return 1;
348
349         case -1:
350         default:
351                 goto bad;
352         }
353
354         if ((id = apic_src_bus_id(apic, pin)) == -1)
355                 goto bad;
356
357         switch (apic_bus_type(id)) {
358         case ISA:
359                 *flags &= ~IOART_TRGRLVL;       /* *flags |= IOART_TRGREDG; */
360                 return 0;
361
362         case EISA:
363                 eirq = apic_src_bus_irq(apic, pin);
364
365                 if (eirq < 0 || eirq > 15) {
366                         printf("EISA IRQ %d?!?!\n", eirq);
367                         goto bad;
368                 }
369
370                 if (intcontrol == -1) {
371                         intcontrol = inb(ELCR1) << 8;
372                         intcontrol |= inb(ELCR0);
373                         printf("EISA INTCONTROL = %08x\n", intcontrol);
374                 }
375
376                 /* Use ELCR settings to determine level or edge mode */
377                 level = (intcontrol >> eirq) & 1;
378
379                 /*
380                  * Note that on older Neptune chipset based systems, any
381                  * pci interrupts often show up here and in the ELCR as well
382                  * as level sensitive interrupts attributed to the EISA bus.
383                  */
384
385                 if (level)
386                         *flags |= IOART_TRGRLVL;
387                 else
388                         *flags &= ~IOART_TRGRLVL;
389
390                 return level;
391
392         case PCI:
393                 *flags |= IOART_TRGRLVL;
394                 return 1;
395
396         case -1:
397         default:
398                 goto bad;
399         }
400
401 bad:
402         panic("bad APIC IO INT flags");
403 }
404
405
406 /*
407  * Set the polarity value for an IO APIC pin.
408  */
409 static void
410 polarity(int apic, int pin, u_int32_t * flags, int level)
411 {
412         int     id;
413
414         switch (apic_polarity(apic, pin)) {
415
416         case 0x00:
417                 break;
418
419         case 0x01:
420                 *flags &= ~IOART_INTALO;        /* *flags |= IOART_INTAHI */
421                 return;
422
423         case 0x03:
424                 *flags |= IOART_INTALO;
425                 return;
426
427         case -1:
428         default:
429                 goto bad;
430         }
431
432         if ((id = apic_src_bus_id(apic, pin)) == -1)
433                 goto bad;
434
435         switch (apic_bus_type(id)) {
436         case ISA:
437                 *flags &= ~IOART_INTALO;        /* *flags |= IOART_INTAHI */
438                 return;
439
440         case EISA:
441                 /* polarity converter always gives active high */
442                 *flags &= ~IOART_INTALO;
443                 return;
444
445         case PCI:
446                 *flags |= IOART_INTALO;
447                 return;
448
449         case -1:
450         default:
451                 goto bad;
452         }
453
454 bad:
455         panic("bad APIC IO INT flags");
456 }
457
458
459 /*
460  * Print contents of apic_imen.
461  */
462 extern  u_int apic_imen;                /* keep apic_imen 'opaque' */
463 void
464 imen_dump(void)
465 {
466         int x;
467
468         printf("SMP: enabled INTs: ");
469         for (x = 0; x < 24; ++x)
470                 if ((apic_imen & (1 << x)) == 0)
471                         printf("%d, ", x);
472         printf("apic_imen: 0x%08x\n", apic_imen);
473 }
474
475
476 /*
477  * Inter Processor Interrupt functions.
478  */
479
480
481 /*
482  * Send APIC IPI 'vector' to 'destType' via 'deliveryMode'.
483  *
484  *  destType is 1 of: APIC_DEST_SELF, APIC_DEST_ALLISELF, APIC_DEST_ALLESELF
485  *  vector is any valid SYSTEM INT vector
486  *  delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
487  */
488 #define DETECT_DEADLOCK
489 int
490 apic_ipi(int dest_type, int vector, int delivery_mode)
491 {
492         u_long  icr_lo;
493
494 #if defined(DETECT_DEADLOCK)
495 #define MAX_SPIN1       10000000
496 #define MAX_SPIN2       1000
497         int     x;
498
499         /* "lazy delivery", ie we only barf if they stack up on us... */
500         for (x = MAX_SPIN1; x; --x) {
501                 if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
502                         break;
503         }
504         if (x == 0)
505                 panic("apic_ipi was stuck");
506 #endif  /* DETECT_DEADLOCK */
507
508         /* build IRC_LOW */
509         icr_lo = (lapic.icr_lo & APIC_RESV2_MASK)
510             | dest_type | delivery_mode | vector;
511
512         /* write APIC ICR */
513         lapic.icr_lo = icr_lo;
514
515         /* wait for pending status end */
516 #if defined(DETECT_DEADLOCK)
517         for (x = MAX_SPIN2; x; --x) {
518                 if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
519                         break;
520         }
521 #ifdef needsattention
522 /*
523  * XXX FIXME:
524  *      The above loop waits for the message to actually be delivered.
525  *      It breaks out after an arbitrary timout on the theory that it eventually
526  *      will be delivered and we will catch a real failure on the next entry to
527  *      this function, which would panic().
528  *      We could skip this wait entirely, EXCEPT it probably protects us from
529  *      other "less robust" routines that assume the message was delivered and
530  *      acted upon when this function returns.  TLB shootdowns are one such
531  *      "less robust" function.
532  */
533         if (x == 0)
534                 printf("apic_ipi might be stuck\n");
535 #endif
536 #undef MAX_SPIN2
537 #undef MAX_SPIN1
538 #else
539         while (lapic.icr_lo & APIC_DELSTAT_MASK)
540                  /* spin */ ;
541 #endif  /* DETECT_DEADLOCK */
542
543         /** XXX FIXME: return result */
544         return 0;
545 }
546
547 static int
548 apic_ipi_singledest(int cpu, int vector, int delivery_mode)
549 {
550         u_long  icr_lo;
551         u_long  icr_hi;
552         u_long  eflags;
553
554 #if defined(DETECT_DEADLOCK)
555 #define MAX_SPIN1       10000000
556 #define MAX_SPIN2       1000
557         int     x;
558
559         /* "lazy delivery", ie we only barf if they stack up on us... */
560         for (x = MAX_SPIN1; x; --x) {
561                 if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
562                         break;
563         }
564         if (x == 0)
565                 panic("apic_ipi was stuck");
566 #endif  /* DETECT_DEADLOCK */
567
568         eflags = read_eflags();
569         __asm __volatile("cli" : : : "memory");
570         icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
571         icr_hi |= (CPU_TO_ID(cpu) << 24);
572         lapic.icr_hi = icr_hi;
573
574         /* build IRC_LOW */
575         icr_lo = (lapic.icr_lo & APIC_RESV2_MASK)
576             | APIC_DEST_DESTFLD | delivery_mode | vector;
577
578         /* write APIC ICR */
579         lapic.icr_lo = icr_lo;
580         write_eflags(eflags);
581
582         /* wait for pending status end */
583 #if defined(DETECT_DEADLOCK)
584         for (x = MAX_SPIN2; x; --x) {
585                 if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
586                         break;
587         }
588 #ifdef needsattention
589 /*
590  * XXX FIXME:
591  *      The above loop waits for the message to actually be delivered.
592  *      It breaks out after an arbitrary timout on the theory that it eventually
593  *      will be delivered and we will catch a real failure on the next entry to
594  *      this function, which would panic().
595  *      We could skip this wait entirely, EXCEPT it probably protects us from
596  *      other "less robust" routines that assume the message was delivered and
597  *      acted upon when this function returns.  TLB shootdowns are one such
598  *      "less robust" function.
599  */
600         if (x == 0)
601                 printf("apic_ipi might be stuck\n");
602 #endif
603 #undef MAX_SPIN2
604 #undef MAX_SPIN1
605 #else
606         while (lapic.icr_lo & APIC_DELSTAT_MASK)
607                  /* spin */ ;
608 #endif  /* DETECT_DEADLOCK */
609
610         /** XXX FIXME: return result */
611         return 0;
612 }
613
614
615 /*
616  * Send APIC IPI 'vector' to 'target's via 'delivery_mode'.
617  *
618  *  target contains a bitfield with a bit set for selected APICs.
619  *  vector is any valid SYSTEM INT vector
620  *  delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
621  */
622 int
623 selected_apic_ipi(u_int target, int vector, int delivery_mode)
624 {
625         int     x;
626         int     status;
627
628         if (target & ~0x7fff)
629                 return -1;      /* only 15 targets allowed */
630
631         for (status = 0, x = 0; x <= 14; ++x)
632                 if (target & (1 << x)) {
633
634                         /* send the IPI */
635                         if (apic_ipi_singledest(x, vector, 
636                                                 delivery_mode) == -1)
637                                 status |= (1 << x);
638                 }
639         return status;
640 }
641
642
643 #if defined(READY)
644 /*
645  * Send an IPI INTerrupt containing 'vector' to CPU 'target'
646  *   NOTE: target is a LOGICAL APIC ID
647  */
648 int
649 selected_proc_ipi(int target, int vector)
650 {
651         u_long  icr_lo;
652         u_long  icr_hi;
653
654         /* write the destination field for the target AP */
655         icr_hi = (lapic.icr_hi & ~APIC_ID_MASK) |
656             (cpu_num_to_apic_id[target] << 24);
657         lapic.icr_hi = icr_hi;
658
659         /* write command */
660         icr_lo = (lapic.icr_lo & APIC_RESV2_MASK) |
661             APIC_DEST_DESTFLD | APIC_DELMODE_FIXED | vector;
662         lapic.icr_lo = icr_lo;
663
664         /* wait for pending status end */
665         while (lapic.icr_lo & APIC_DELSTAT_MASK)
666                 /* spin */ ;
667
668         return 0;       /** XXX FIXME: return result */
669 }
670 #endif /* READY */
671
672 #endif  /* APIC_IO */
673
674
675 /*
676  * Timer code, in development...
677  *  - suggested by rgrimes@gndrsh.aac.dev.com
678  */
679
680 /** XXX FIXME: temp hack till we can determin bus clock */
681 #ifndef BUS_CLOCK
682 #define BUS_CLOCK       66000000
683 #define bus_clock()     66000000
684 #endif
685
686 #if defined(READY)
687 int acquire_apic_timer __P((void));
688 int release_apic_timer __P((void));
689
690 /*
691  * Acquire the APIC timer for exclusive use.
692  */
693 int
694 acquire_apic_timer(void)
695 {
696 #if 1
697         return 0;
698 #else
699         /** XXX FIXME: make this really do something */
700         panic("APIC timer in use when attempting to aquire");
701 #endif
702 }
703
704
705 /*
706  * Return the APIC timer.
707  */
708 int
709 release_apic_timer(void)
710 {
711 #if 1
712         return 0;
713 #else
714         /** XXX FIXME: make this really do something */
715         panic("APIC timer was already released");
716 #endif
717 }
718 #endif  /* READY */
719
720
721 /*
722  * Load a 'downcount time' in uSeconds.
723  */
724 void
725 set_apic_timer(int value)
726 {
727         u_long  lvtt;
728         long    ticks_per_microsec;
729
730         /*
731          * Calculate divisor and count from value:
732          * 
733          *  timeBase == CPU bus clock divisor == [1,2,4,8,16,32,64,128]
734          *  value == time in uS
735          */
736         lapic.dcr_timer = APIC_TDCR_1;
737         ticks_per_microsec = bus_clock() / 1000000;
738
739         /* configure timer as one-shot */
740         lvtt = lapic.lvt_timer;
741         lvtt &= ~(APIC_LVTT_VECTOR | APIC_LVTT_DS | APIC_LVTT_M | APIC_LVTT_TM);
742         lvtt |= APIC_LVTT_M;                    /* no INT, one-shot */
743         lapic.lvt_timer = lvtt;
744
745         /* */
746         lapic.icr_timer = value * ticks_per_microsec;
747 }
748
749
750 /*
751  * Read remaining time in timer.
752  */
753 int
754 read_apic_timer(void)
755 {
756 #if 0
757         /** XXX FIXME: we need to return the actual remaining time,
758          *         for now we just return the remaining count.
759          */
760 #else
761         return lapic.ccr_timer;
762 #endif
763 }
764
765
766 /*
767  * Spin-style delay, set delay time in uS, spin till it drains.
768  */
769 void
770 u_sleep(int count)
771 {
772         set_apic_timer(count);
773         while (read_apic_timer())
774                  /* spin */ ;
775 }