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