Remove pre-ELF underscore prefix and asnames macro hacks.
[dragonfly.git] / sys / i386 / apic / apic_ipl.s
1 /*-
2  * Copyright (c) 1997, 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/isa/apic_ipl.s,v 1.27.2.2 2000/09/30 02:49:35 ps Exp $
26  * $DragonFly: src/sys/i386/apic/Attic/apic_ipl.s,v 1.6 2003/07/01 20:31:38 dillon Exp $
27  */
28
29 #if 0
30
31         .data
32         ALIGN_DATA
33
34 /*
35  * Routines used by splz_unpend to build an interrupt frame from a
36  * trap frame.  The _vec[] routines build the proper frame on the stack,
37  * then call one of _Xintr0 thru _XintrNN.
38  *
39  * used by:
40  *   i386/isa/apic_ipl.s (this file):   splz_unpend JUMPs to HWIs.
41  *   i386/isa/clock.c:                  setup _vec[clock] to point at _vec8254.
42  */
43         .globl _vec
44 _vec:
45         .long    vec0,  vec1,  vec2,  vec3,  vec4,  vec5,  vec6,  vec7
46         .long    vec8,  vec9, vec10, vec11, vec12, vec13, vec14, vec15
47         .long   vec16, vec17, vec18, vec19, vec20, vec21, vec22, vec23
48
49 /*
50  * Note:
51  *      This is the UP equivilant of _imen.
52  *      It is OPAQUE, and must NOT be accessed directly.
53  *      It MUST be accessed along with the IO APIC as a 'critical region'.
54  *      Accessed by:
55  *              INTREN()
56  *              INTRDIS()
57  *              MAYBE_MASK_IRQ
58  *              MAYBE_UNMASK_IRQ
59  *              imen_dump()
60  */
61         .p2align 2                              /* MUST be 32bit aligned */
62         .globl _apic_imen
63 _apic_imen:
64         .long   HWI_MASK
65
66
67 /*
68  * 
69  */
70         .text
71         SUPERALIGN_TEXT
72
73 /*
74  * splz() -     dispatch pending interrupts after cpl reduced
75  *
76  * Interrupt priority mechanism
77  *      -- soft splXX masks with group mechanism (cpl)
78  *      -- h/w masks for currently active or unused interrupts (imen)
79  *      -- ipending = active interrupts currently masked by cpl
80  */
81
82 ENTRY(splz)
83         /*
84          * The caller has restored cpl and checked that (ipending & ~cpl)
85          * is nonzero.  However, since ipending can change at any time
86          * (by an interrupt or, with SMP, by another cpu), we have to
87          * repeat the check.  At the moment we must own the MP lock in
88          * the SMP case because the interruput handlers require it.  We
89          * loop until no unmasked pending interrupts remain.  
90          *
91          * No new unmaksed pending interrupts will be added during the
92          * loop because, being unmasked, the interrupt code will be able
93          * to execute the interrupts.
94          *
95          * Interrupts come in two flavors:  Hardware interrupts and software
96          * interrupts.  We have to detect the type of interrupt (based on the
97          * position of the interrupt bit) and call the appropriate dispatch
98          * routine.
99          * 
100          * NOTE: "bsfl %ecx,%ecx" is undefined when %ecx is 0 so we can't
101          * rely on the secondary btrl tests.
102          */
103         pushl   %ebx
104         movl    _curthread,%ebx
105         movl    TD_CPL(%ebx),%eax
106 splz_next:
107         /*
108          * We don't need any locking here.  (ipending & ~cpl) cannot grow 
109          * while we're looking at it - any interrupt will shrink it to 0.
110          */
111         movl    $0,_reqpri
112         movl    %eax,%ecx
113         notl    %ecx                    /* set bit = unmasked level */
114         andl    _ipending,%ecx          /* set bit = unmasked pending INT */
115         jne     splz_unpend
116         popl    %ebx
117         ret
118
119         ALIGN_TEXT
120 splz_unpend:
121         bsfl    %ecx,%ecx
122         lock
123         btrl    %ecx,_ipending
124         jnc     splz_next
125         cmpl    $NHWI,%ecx
126         jae     splz_swi
127         /*
128          * We would prefer to call the intr handler directly here but that
129          * doesn't work for badly behaved handlers that want the interrupt
130          * frame.  Also, there's a problem determining the unit number.
131          * We should change the interface so that the unit number is not
132          * determined at config time.
133          *
134          * The vec[] routines build the proper frame on the stack so
135          * the interrupt will eventually return to the caller or splz,
136          * then calls one of _Xintr0 thru _XintrNN.
137          */
138         popl    %ebx
139         jmp     *_vec(,%ecx,4)
140
141         ALIGN_TEXT
142 splz_swi:
143         pushl   %eax                    /* save cpl across call */
144         orl     imasks(,%ecx,4),%eax
145         movl    %eax,TD_CPL(%ebx) /* set cpl for SWI */
146         call    *_ihandlers(,%ecx,4)
147         popl    %eax
148         movl    %eax,TD_CPL(%ebx) /* restore cpl and loop */
149         jmp     splz_next
150
151 /*
152  * Fake clock interrupt(s) so that they appear to come from our caller instead
153  * of from here, so that system profiling works.
154  * XXX do this more generally (for all vectors; look up the C entry point).
155  * XXX frame bogusness stops us from just jumping to the C entry point.
156  * We have to clear iactive since this is an unpend call, and it will be
157  * set from the time of the original INT.
158  */
159
160 /*
161  * The 'generic' vector stubs.
162  */
163
164 #define BUILD_VEC(irq_num)                                              \
165         ALIGN_TEXT ;                                                    \
166 __CONCAT(vec,irq_num): ;                                                \
167         popl    %eax ;                                                  \
168         pushfl ;                                                        \
169         pushl   $KCSEL ;                                                \
170         pushl   %eax ;                                                  \
171         cli ;                                                           \
172         lock ;                                  /* MP-safe */           \
173         andl    $~IRQ_BIT(irq_num), iactive ;   /* lazy masking */      \
174         MEXITCOUNT ;                                                    \
175         APIC_ITRACE(apic_itrace_splz, irq_num, APIC_ITRACE_SPLZ) ;      \
176         jmp     __CONCAT(_Xintr,irq_num)
177
178
179         BUILD_VEC(0)
180         BUILD_VEC(1)
181         BUILD_VEC(2)
182         BUILD_VEC(3)
183         BUILD_VEC(4)
184         BUILD_VEC(5)
185         BUILD_VEC(6)
186         BUILD_VEC(7)
187         BUILD_VEC(8)
188         BUILD_VEC(9)
189         BUILD_VEC(10)
190         BUILD_VEC(11)
191         BUILD_VEC(12)
192         BUILD_VEC(13)
193         BUILD_VEC(14)
194         BUILD_VEC(15)
195         BUILD_VEC(16)                   /* 8 additional INTs in IO APIC */
196         BUILD_VEC(17)
197         BUILD_VEC(18)
198         BUILD_VEC(19)
199         BUILD_VEC(20)
200         BUILD_VEC(21)
201         BUILD_VEC(22)
202         BUILD_VEC(23)
203
204
205 /******************************************************************************
206  * XXX FIXME: figure out where these belong.
207  */
208
209 /* this nonsense is to verify that masks ALWAYS have 1 and only 1 bit set */
210 #define QUALIFY_MASKS_NOT
211
212 #ifdef QUALIFY_MASKS
213 #define QUALIFY_MASK            \
214         btrl    %ecx, %eax ;    \
215         andl    %eax, %eax ;    \
216         jz      1f ;            \
217         pushl   $bad_mask ;     \
218         call    _panic ;        \
219 1:
220
221 bad_mask:       .asciz  "bad mask"
222 #else
223 #define QUALIFY_MASK
224 #endif
225
226 /*
227  * (soon to be) MP-safe function to clear ONE INT mask bit.
228  * The passed arg is a 32bit u_int MASK.
229  * It sets the associated bit in _apic_imen.
230  * It sets the mask bit of the associated IO APIC register.
231  */
232 ENTRY(INTREN)
233         pushfl                          /* save state of EI flag */
234         cli                             /* prevent recursion */
235         IMASK_LOCK                      /* enter critical reg */
236
237         movl    8(%esp), %eax           /* mask into %eax */
238         bsfl    %eax, %ecx              /* get pin index */
239         btrl    %ecx, apic_imen         /* update apic_imen */
240
241         QUALIFY_MASK
242
243         shll    $4, %ecx
244         movl    CNAME(int_to_apicintpin) + 8(%ecx), %edx
245         movl    CNAME(int_to_apicintpin) + 12(%ecx), %ecx
246         testl   %edx, %edx
247         jz      1f
248
249         movl    %ecx, (%edx)            /* write the target register index */
250         movl    16(%edx), %eax          /* read the target register data */
251         andl    $~IOART_INTMASK, %eax   /* clear mask bit */
252         movl    %eax, 16(%edx)          /* write the APIC register data */
253 1:      
254         IMASK_UNLOCK                    /* exit critical reg */
255         popfl                           /* restore old state of EI flag */
256         ret
257
258 /*
259  * (soon to be) MP-safe function to set ONE INT mask bit.
260  * The passed arg is a 32bit u_int MASK.
261  * It clears the associated bit in apic_imen.
262  * It clears the mask bit of the associated IO APIC register.
263  */
264 ENTRY(INTRDIS)
265         pushfl                          /* save state of EI flag */
266         cli                             /* prevent recursion */
267         IMASK_LOCK                      /* enter critical reg */
268
269         movl    8(%esp), %eax           /* mask into %eax */
270         bsfl    %eax, %ecx              /* get pin index */
271         btsl    %ecx, apic_imen         /* update _apic_imen */
272
273         QUALIFY_MASK
274
275         shll    $4, %ecx
276         movl    CNAME(int_to_apicintpin) + 8(%ecx), %edx
277         movl    CNAME(int_to_apicintpin) + 12(%ecx), %ecx
278         testl   %edx, %edx
279         jz      1f
280
281         movl    %ecx, (%edx)            /* write the target register index */
282         movl    16(%edx), %eax          /* read the target register data */
283         orl     $IOART_INTMASK, %eax    /* set mask bit */
284         movl    %eax, 16(%edx)          /* write the APIC register data */
285 1:      
286         IMASK_UNLOCK                    /* exit critical reg */
287         popfl                           /* restore old state of EI flag */
288         ret
289
290
291 /******************************************************************************
292  *
293  */
294
295
296 /*
297  * void write_ioapic_mask(int apic, u_int mask); 
298  */
299
300 #define _INT_MASK       0x00010000
301 #define _PIN_MASK       0x00ffffff
302
303 #define _OLD_ESI          0(%esp)
304 #define _OLD_EBX          4(%esp)
305 #define _RETADDR          8(%esp)
306 #define _APIC            12(%esp)
307 #define _MASK            16(%esp)
308
309         ALIGN_TEXT
310 write_ioapic_mask:
311         pushl %ebx                      /* scratch */
312         pushl %esi                      /* scratch */
313
314         movl    apic_imen, %ebx
315         xorl    _MASK, %ebx             /* %ebx = _apic_imen ^ mask */
316         andl    $_PIN_MASK, %ebx        /* %ebx = _apic_imen & 0x00ffffff */
317         jz      all_done                /* no change, return */
318
319         movl    _APIC, %esi             /* APIC # */
320         movl    ioapic, %ecx
321         movl    (%ecx,%esi,4), %esi     /* %esi holds APIC base address */
322
323 next_loop:                              /* %ebx = diffs, %esi = APIC base */
324         bsfl    %ebx, %ecx              /* %ecx = index if 1st/next set bit */
325         jz      all_done
326
327         btrl    %ecx, %ebx              /* clear this bit in diffs */
328         leal    16(,%ecx,2), %edx       /* calculate register index */
329
330         movl    %edx, (%esi)            /* write the target register index */
331         movl    16(%esi), %eax          /* read the target register data */
332
333         btl     %ecx, _MASK             /* test for mask or unmask */
334         jnc     clear                   /* bit is clear */
335         orl     $_INT_MASK, %eax        /* set mask bit */
336         jmp     write
337 clear:  andl    $~_INT_MASK, %eax       /* clear mask bit */
338
339 write:  movl    %eax, 16(%esi)          /* write the APIC register data */
340
341         jmp     next_loop               /* try another pass */
342
343 all_done:
344         popl    %esi
345         popl    %ebx
346         ret
347
348 #undef _OLD_ESI
349 #undef _OLD_EBX
350 #undef _RETADDR
351 #undef _APIC
352 #undef _MASK
353
354 #undef _PIN_MASK
355 #undef _INT_MASK
356
357 #ifdef oldcode
358
359 _INTREN:
360         movl apic_imen, %eax
361         notl %eax                       /* mask = ~mask */
362         andl apic_imen, %eax            /* %eax = _apic_imen & ~mask */
363
364         pushl %eax                      /* new (future) _apic_imen value */
365         pushl $0                        /* APIC# arg */
366         call write_ioapic_mask          /* modify the APIC registers */
367
368         addl $4, %esp                   /* remove APIC# arg from stack */
369         popl apic_imen                  /* _apic_imen |= mask */
370         ret
371
372 _INTRDIS:
373         movl _apic_imen, %eax
374         orl 4(%esp), %eax               /* %eax = _apic_imen | mask */
375
376         pushl %eax                      /* new (future) _apic_imen value */
377         pushl $0                        /* APIC# arg */
378         call write_ioapic_mask          /* modify the APIC registers */
379
380         addl $4, %esp                   /* remove APIC# arg from stack */
381         popl apic_imen                  /* _apic_imen |= mask */
382         ret
383
384 #endif /* oldcode */
385
386
387 #ifdef ready
388
389 /*
390  * u_int read_io_apic_mask(int apic); 
391  */
392         ALIGN_TEXT
393 read_io_apic_mask:
394         ret
395
396 /*
397  * Set INT mask bit for each bit set in 'mask'.
398  * Ignore INT mask bit for all others.
399  *
400  * void set_io_apic_mask(apic, u_int32_t bits); 
401  */
402         ALIGN_TEXT
403 set_io_apic_mask:
404         ret
405
406 /*
407  * void set_ioapic_maskbit(int apic, int bit); 
408  */
409         ALIGN_TEXT
410 set_ioapic_maskbit:
411         ret
412
413 /*
414  * Clear INT mask bit for each bit set in 'mask'.
415  * Ignore INT mask bit for all others.
416  *
417  * void clr_io_apic_mask(int apic, u_int32_t bits); 
418  */
419         ALIGN_TEXT
420 clr_io_apic_mask:
421         ret
422
423 /*
424  * void clr_ioapic_maskbit(int apic, int bit); 
425  */
426         ALIGN_TEXT
427 clr_ioapic_maskbit:
428         ret
429
430 #endif /** ready */
431
432 /******************************************************************************
433  * 
434  */
435
436 /*
437  * u_int io_apic_write(int apic, int select);
438  */
439 ENTRY(io_apic_read)
440         movl    4(%esp), %ecx           /* APIC # */
441         movl    ioapic, %eax
442         movl    (%eax,%ecx,4), %edx     /* APIC base register address */
443         movl    8(%esp), %eax           /* target register index */
444         movl    %eax, (%edx)            /* write the target register index */
445         movl    16(%edx), %eax          /* read the APIC register data */
446         ret                             /* %eax = register value */
447
448 /*
449  * void io_apic_write(int apic, int select, int value);
450  */
451 ENTRY(io_apic_write)
452         movl    4(%esp), %ecx           /* APIC # */
453         movl    ioapic, %eax
454         movl    (%eax,%ecx,4), %edx     /* APIC base register address */
455         movl    8(%esp), %eax           /* target register index */
456         movl    %eax, (%edx)            /* write the target register index */
457         movl    12(%esp), %eax          /* target register value */
458         movl    %eax, 16(%edx)          /* write the APIC register data */
459         ret                             /* %eax = void */
460
461 /*
462  * Send an EOI to the local APIC.
463  */
464 ENTRY(apic_eoi)
465         movl    $0, lapic+0xb0
466         ret
467
468 #endif