Cleanup last commit. Remove local ncp, it shadows the parameter, add
[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.8 2004/03/01 06:33:16 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 #include <sys/thread2.h>
37
38 #include <i386/isa/intr_machdep.h>      /* Xspuriousint() */
39
40 /* EISA Edge/Level trigger control registers */
41 #define ELCR0   0x4d0                   /* eisa irq 0-7 */
42 #define ELCR1   0x4d1                   /* eisa irq 8-15 */
43
44 /*
45  * pointers to pmapped apic hardware.
46  */
47
48 #if defined(APIC_IO)
49 volatile ioapic_t       **ioapic;
50 #endif  /* APIC_IO */
51
52 /*
53  * Enable APIC, configure interrupts.
54  */
55 void
56 apic_initialize(void)
57 {
58         u_int   temp;
59
60         /* setup LVT1 as ExtINT */
61         temp = lapic.lvt_lint0;
62         temp &= ~(APIC_LVT_M | APIC_LVT_TM | APIC_LVT_IIPP | APIC_LVT_DM);
63         if (mycpu->gd_cpuid == 0)
64                 temp |= 0x00000700;     /* process ExtInts */
65         else
66                 temp |= 0x00010700;     /* mask ExtInts */
67         lapic.lvt_lint0 = temp;
68
69         /* setup LVT2 as NMI, masked till later... */
70         temp = lapic.lvt_lint1;
71         temp &= ~(APIC_LVT_M | APIC_LVT_TM | APIC_LVT_IIPP | APIC_LVT_DM);
72         temp |= 0x00010400;             /* masked, edge trigger, active hi */
73         lapic.lvt_lint1 = temp;
74
75         /*
76          * Set the Task Priority Register as needed.   At the moment allow
77          * interrupts on all cpus (the APs will remain CLId until they are
78          * ready to deal).  We could disable all but IPIs by setting
79          * temp |= TPR_IPI_ONLY for cpu != 0.
80          */
81         temp = lapic.tpr;
82         temp &= ~APIC_TPR_PRIO;         /* clear priority field */
83
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 (int apic, int pin, u_int32_t * flags);
133 static void polarity (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  * A backlog of requests can create a deadlock between cpus.  To avoid this
489  * we have to be able to accept IPIs at the same time we are trying to send
490  * them.  The critical section prevents us from attempting to send additional
491  * IPIs reentrantly, but also prevents IPIQ processing so we have to call
492  * lwkt_process_ipiq() manually.  It's rather messy and expensive for this
493  * to occur but fortunately it does not happen too often.
494  */
495 int
496 apic_ipi(int dest_type, int vector, int delivery_mode)
497 {
498         u_long  icr_lo;
499
500         crit_enter();
501         if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
502             unsigned int eflags = read_eflags();
503             cpu_enable_intr();
504             while ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
505                 lwkt_process_ipiq();
506             }
507             write_eflags(eflags);
508         }
509
510         icr_lo = (lapic.icr_lo & APIC_RESV2_MASK) | dest_type | 
511                 delivery_mode | vector;
512         lapic.icr_lo = icr_lo;
513         crit_exit();
514         return 0;
515 }
516
517 void
518 single_apic_ipi(int cpu, int vector, int delivery_mode)
519 {
520         u_long  icr_lo;
521         u_long  icr_hi;
522
523         crit_enter();
524         if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
525             unsigned int eflags = read_eflags();
526             cpu_enable_intr();
527             while ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
528                 lwkt_process_ipiq();
529             }
530             write_eflags(eflags);
531         }
532         icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
533         icr_hi |= (CPU_TO_ID(cpu) << 24);
534         lapic.icr_hi = icr_hi;
535
536         /* build IRC_LOW */
537         icr_lo = (lapic.icr_lo & APIC_RESV2_MASK)
538             | APIC_DEST_DESTFLD | delivery_mode | vector;
539
540         /* write APIC ICR */
541         lapic.icr_lo = icr_lo;
542         crit_exit();
543 }
544
545 #if 0   
546
547 /*
548  * Returns 0 if the apic is busy, 1 if we were able to queue the request.
549  *
550  * NOT WORKING YET!  The code as-is may end up not queueing an IPI at all
551  * to the target, and the scheduler does not 'poll' for IPI messages.
552  */
553 int
554 single_apic_ipi_passive(int cpu, int vector, int delivery_mode)
555 {
556         u_long  icr_lo;
557         u_long  icr_hi;
558
559         crit_enter();
560         if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
561             crit_exit();
562             return(0);
563         }
564         icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
565         icr_hi |= (CPU_TO_ID(cpu) << 24);
566         lapic.icr_hi = icr_hi;
567
568         /* build IRC_LOW */
569         icr_lo = (lapic.icr_lo & APIC_RESV2_MASK)
570             | APIC_DEST_DESTFLD | delivery_mode | vector;
571
572         /* write APIC ICR */
573         lapic.icr_lo = icr_lo;
574         crit_exit();
575         return(1);
576 }
577
578 #endif
579
580 /*
581  * Send APIC IPI 'vector' to 'target's via 'delivery_mode'.
582  *
583  * target is a bitmask of destination cpus.  Vector is any
584  * valid system INT vector.  Delivery mode may be either
585  * APIC_DELMODE_FIXED or APIC_DELMODE_LOWPRIO.
586  */
587 void
588 selected_apic_ipi(u_int target, int vector, int delivery_mode)
589 {
590         crit_enter();
591         while (target) {
592                 int n = bsfl(target);
593                 target &= ~(1 << n);
594                 single_apic_ipi(n, vector, delivery_mode);
595         }
596         crit_exit();
597 }
598
599 #endif  /* APIC_IO */
600
601 /*
602  * Timer code, in development...
603  *  - suggested by rgrimes@gndrsh.aac.dev.com
604  */
605
606 /** XXX FIXME: temp hack till we can determin bus clock */
607 #ifndef BUS_CLOCK
608 #define BUS_CLOCK       66000000
609 #define bus_clock()     66000000
610 #endif
611
612 #if defined(READY)
613 int acquire_apic_timer (void);
614 int release_apic_timer (void);
615
616 /*
617  * Acquire the APIC timer for exclusive use.
618  */
619 int
620 acquire_apic_timer(void)
621 {
622 #if 1
623         return 0;
624 #else
625         /** XXX FIXME: make this really do something */
626         panic("APIC timer in use when attempting to aquire");
627 #endif
628 }
629
630
631 /*
632  * Return the APIC timer.
633  */
634 int
635 release_apic_timer(void)
636 {
637 #if 1
638         return 0;
639 #else
640         /** XXX FIXME: make this really do something */
641         panic("APIC timer was already released");
642 #endif
643 }
644 #endif  /* READY */
645
646
647 /*
648  * Load a 'downcount time' in uSeconds.
649  */
650 void
651 set_apic_timer(int value)
652 {
653         u_long  lvtt;
654         long    ticks_per_microsec;
655
656         /*
657          * Calculate divisor and count from value:
658          * 
659          *  timeBase == CPU bus clock divisor == [1,2,4,8,16,32,64,128]
660          *  value == time in uS
661          */
662         lapic.dcr_timer = APIC_TDCR_1;
663         ticks_per_microsec = bus_clock() / 1000000;
664
665         /* configure timer as one-shot */
666         lvtt = lapic.lvt_timer;
667         lvtt &= ~(APIC_LVTT_VECTOR | APIC_LVTT_DS | APIC_LVTT_M | APIC_LVTT_TM);
668         lvtt |= APIC_LVTT_M;                    /* no INT, one-shot */
669         lapic.lvt_timer = lvtt;
670
671         /* */
672         lapic.icr_timer = value * ticks_per_microsec;
673 }
674
675
676 /*
677  * Read remaining time in timer.
678  */
679 int
680 read_apic_timer(void)
681 {
682 #if 0
683         /** XXX FIXME: we need to return the actual remaining time,
684          *         for now we just return the remaining count.
685          */
686 #else
687         return lapic.ccr_timer;
688 #endif
689 }
690
691
692 /*
693  * Spin-style delay, set delay time in uS, spin till it drains.
694  */
695 void
696 u_sleep(int count)
697 {
698         set_apic_timer(count);
699         while (read_apic_timer())
700                  /* spin */ ;
701 }