]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/sun4v/sun4v/interrupt.S
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / sun4v / sun4v / interrupt.S
1 /*-
2  * Copyright (c) 2002 Jake Burkholder.
3  * Copyright (c) 2006 Kip Macy <kmacy@FreeBSD.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <machine/asm.h>
29 __FBSDID("$FreeBSD$");
30
31 #include "opt_simulator.h"
32 #include "opt_trap_trace.h"
33
34 #include <machine/asi.h>
35 #include <machine/asmacros.h>
36 #include <machine/frame.h>
37 #include <machine/hypervisorvar.h>
38 #include <machine/intr_machdep.h>
39 #include <machine/ktr.h>
40 #include <machine/pstate.h>
41
42 #include "assym.s"
43
44 #define PUTCHAR(x) \
45 0:      mov     x, %o0          ; \
46         mov     CONS_PUTCHAR, %o5       ; \
47         ta      FAST_TRAP       ; \
48         brnz    %o0, 0b         ; \
49           nop
50                 
51 ENTRY(intr_fast)
52         save    %sp, -CCFSZ, %sp
53 1:      ldx     [PCPU(IRHEAD)], %l0
54         brnz,a,pt %l0, 2f
55          nop
56
57         ret
58          restore
59
60 2:      wrpr    %g0, PSTATE_NORMAL, %pstate
61
62         ldx     [%l0 + IR_NEXT], %l1
63         brnz,pt %l1, 3f
64          stx    %l1, [PCPU(IRHEAD)]
65         PCPU_ADDR(IRHEAD, %l1)
66         stx     %l1, [PCPU(IRTAIL)]
67
68 3:      ldx     [%l0 + IR_FUNC], %o0
69         ldx     [%l0 + IR_ARG], %o1
70         lduw    [%l0 + IR_VEC], %o2
71
72         /* intrcnt[intr_countp[%o2]]++ */
73         SET(intrcnt, %l7, %l2)          /* %l2 = intrcnt */
74         prefetcha [%l2] ASI_N, 1
75         SET(intr_countp, %l7, %l3)      /* %l3 = intr_countp */
76         sllx    %o2, 1, %l4             /* %l4 = vec << 1 */
77         lduh    [%l4 + %l3], %l5        /* %l5 = intr_countp[%o2] */
78         sllx    %l5, 3, %l6             /* %l6 = intr_countp[%o2] << 3 */
79         add     %l6, %l2, %l7           /* %l7 = intrcnt[intr_countp[%o2]] */
80         ldx     [%l7], %l2
81         inc     %l2
82         stx     %l2, [%l7]
83
84         ldx     [PCPU(IRFREE)], %l1
85         stx     %l1, [%l0 + IR_NEXT]
86         stx     %l0, [PCPU(IRFREE)]
87
88         wrpr    %g0, PSTATE_KERNEL, %pstate
89
90         call    %o0
91          mov    %o1, %o0
92
93         ba,a    %xcc, 1b
94          nop
95 END(intr_fast)
96
97 /*
98  * Running tally of invalid CPU mondo interrupts
99  */
100 #if defined(lint)
101 uint64_t cpu_mondo_invalid;
102 #else /* lint */
103         .data
104         .globl cpu_mondo_invalid
105         .align  8
106 cpu_mondo_invalid:
107         .skip   8
108
109         .text
110 #endif  /* lint */
111
112 #if defined(lint)
113 void
114 cpu_mondo(void)
115 {}
116 #else   /* lint */
117
118 /*
119  * (TT 0x7c, TL>0) CPU Mondo Queue Handler
120  *      Globals are the Interrupt Globals.
121  *
122  * Interrupts in sun4v are delivered to privileged code in the form 
123  * of interrupt reports.  Each interrupt report is 64-bytes long, 
124  * consisting of 8 64-bit words.  Each interrupt report is appended 
125  * onto the appropriate interrupt queue of which there are currently two,
126  * one for CPU mondos (formerly referred to as cross trap function
127  * requests) and one for device mondos.  Each queue has its own 
128  * trap vector.
129  *
130  * New reports are appended onto the tail of the queue, and privileged
131  * code reads the report from the queue's head.  The head pointer is stored
132  * in a register and is equal to the current offset from the base address 
133  * of its associated queue.  
134  *
135  * The structure of the cpu mondo report follows sun4u conventions:
136  *
137  * word 0:      address of cross-trap handler
138  * word 1:      first argument to handler
139  * word 2:      second argument to handler
140  * word 3-7:    unused
141  *
142  * Privileged code is responsible for incrementing the head pointer 
143  * to remove each entry.  The pointers are updated using modulo
144  * arithmetic such that the queue is empty when head == tail and is full
145  * when the addition of an entry would make head == tail. 
146  * 
147  * This trap handler is called when the cpu mondo queue becomes non-empty
148  * and will continue to be called while interrupts enabled until the 
149  * queue becomes empty.
150  *
151  */
152 ENTRY(cpu_mondo)
153 #ifdef TRAP_TRACING     
154         GET_PCPU_PHYS_SCRATCH(%g1)
155         rdpr    %tl, %g1
156         dec     %g1     
157         sll     %g1, RW_SHIFT, %g1
158         add     %g1, PC_TSBWBUF, %g1
159         add     PCPU_REG, %g1, %g1
160         wr      %g0, ASI_REAL, %asi
161         TTRACE_ADD_SAFE(%g1, 0, 0, 0, 0, 0)
162 #endif  
163         !
164         !       Register Usage:-
165         !       %g5     PC for fasttrap TL>0 handler
166         !       %g1     arg 1   
167         !       %g2     arg 2
168         !       %g3     queue base RA, ackmask
169         !       %g4     queue size mask
170         !       %g6     head ptr
171         mov     CPU_MONDO_QUEUE_HEAD, %g1     
172         ldxa    [%g1]ASI_QUEUE, %g6     ! %g6 = head ptr 
173         mov     CPU_MONDO_QUEUE_TAIL, %g2     
174         ldxa    [%g2]ASI_QUEUE, %g4     ! %g4 = tail ptr 
175         cmp     %g6, %g4
176         be,pn   %xcc, 0f                ! head == tail
177          nop
178
179         /*
180          * Get the address of the current CPU and index into
181          * the pcpu structure for the Q values.
182          */
183         GET_PCPU_SCRATCH
184         ldx     [PCPU(CPU_Q_RA)], %g3           ! %g3 = queue base PA
185         ldx     [PCPU(CPU_Q_SIZE)], %g4         ! %g4 = queue size
186         sub     %g4, 1, %g4                     ! %g4 = queue size mask 
187
188         ! Load interrupt receive data registers 1 and 2 to fetch
189         ! the arguments for the fast trap handler.
190         !
191         ! Since the data words in the interrupt report are not defined yet 
192         ! we assume that the consective words contain valid data and preserve
193         ! sun4u's xcall mondo arguments. 
194         ! Register usage:
195         !       %g5     PC for fasttrap TL>0 handler
196         !       %g1     arg 1   
197         !       %g2     arg 2   
198
199         ldxa    [%g3 + %g6]ASI_REAL, %g5        ! get PC from q base + head
200         add     %g6, 0x8, %g6                   ! inc head 8 bytes
201         ldxa    [%g3 + %g6]ASI_REAL, %g1        ! read data word 1
202         add     %g6, 0x8, %g6                   ! inc head 8 bytes
203         ldxa    [%g3 + %g6]ASI_REAL, %g2        ! read data word 2
204         add     %g6, 0x8, %g6                   ! inc head 8 bytes
205         ldxa    [%g3 + %g6]ASI_REAL, %g7        ! read data word 3
206         add     %g6, (INTR_REPORT_SIZE - 24) , %g6 ! inc head to next record
207
208         and     %g6, %g4, %g6           ! and size mask for wrap around 
209         mov     CPU_MONDO_QUEUE_HEAD, %g3     
210         stxa    %g6, [%g3]ASI_QUEUE     ! store head pointer 
211         membar  #Sync
212         
213         mov     %g7, %g3                ! ackmask
214         /*
215          * For now catch invalid PC being passed via cpu_mondo queue
216          */
217         set     KERNBASE, %g4
218         cmp     %g5, %g4
219         bl,a,pn %xcc, 1f                ! branch if bad %pc
220           nop
221
222         jmp     %g5                     ! jump to traphandler
223           nop
224 1:
225         ! invalid trap handler, discard it for now
226         set     cpu_mondo_invalid, %g4
227         ldx     [%g4], %g5
228         inc     %g5
229         stx     %g5, [%g4]
230 0:
231         retry
232         /* NOTREACHED */
233 END(cpu_mondo)
234
235 #endif /* lint */
236
237
238 #if defined(lint)
239 void
240 dev_mondo(void)
241 {}
242 #else   /* lint */
243
244 /*
245  * (TT 0x7d, TL>0) Dev Mondo Queue Handler
246  *      Globals are the Interrupt Globals.
247  *
248  * Device interrupt reports take the following form:
249  * Bits:        63              11 10           6 5             0
250  * word 0:      |   zero         | |  bus port  | | device ID   |
251  * word 1-7:                    unused
252  *
253  */
254 ENTRY(dev_mondo)
255 #ifdef TRAP_TRACING     
256         GET_PCPU_PHYS_SCRATCH(%g1)
257         rdpr    %tl, %g1
258         dec     %g1     
259         sll     %g1, RW_SHIFT, %g1
260         add     %g1, PC_TSBWBUF, %g1
261         add     PCPU_REG, %g1, %g1
262         wr      %g0, ASI_REAL, %asi
263         TTRACE_ADD_SAFE(%g1, 0, 0, 0, 0, 0)
264 #endif          
265         /*
266          *       Register Usage:-
267          *       %g5     inum
268          *       %g1     ptr to intrerrupt vector entry for inum
269          *       %g3     queue base PA 
270          *       %g4     queue size mask
271          *       %g6     head ptr
272          */
273 !       mov %o0, %g1
274 !       mov %o5, %g6
275 !       PUTCHAR(0x2b)   
276 !       PUTCHAR(0x2b)   
277 !       mov %g1, %o0
278 !       mov %g6, %o5    
279                 
280         mov     DEV_MONDO_QUEUE_HEAD, %g1     
281         ldxa    [%g1]ASI_QUEUE, %g6             ! %g6 = head ptr 
282         mov     DEV_MONDO_QUEUE_TAIL, %g2     
283         ldxa    [%g2]ASI_QUEUE, %g4             ! %g4 = tail ptr 
284         cmp     %g6, %g4
285         be,pn   %xcc, 0f                        ! head == tail
286         nop
287
288         /*
289          * Get CPU address and index to Q base
290          */
291         GET_PCPU_SCRATCH
292         ldx     [PCPU(DEV_Q_RA)], %g3           ! %g3 = queue base PA
293
294         /*
295          *  Register usage:
296          *       %g5 - inum
297          */
298         ldxa    [%g3 + %g6]ASI_REAL, %g5        ! %g5 = inum from q base + head
299
300         /*
301          * We verify that inum is valid ( < IV_MAX). If it is greater
302          * than IV_MAX, we let the software interrupt handler take care
303          * of it.
304          */
305         set     IV_MAX, %g4
306         cmp     %g5, %g4
307         bgeu,a,pn       %xcc, 1f
308           ldx     [PCPU(DEV_Q_SIZE)], %g4               ! queue size (delay slot)
309
310         /*
311          * Find the function, argument and desired priority from the
312          * intr_vectors table
313          */
314         set     intr_vectors, %g1
315         sll     %g5, IV_SHIFT, %g2
316         add     %g1, %g2, %g1                   ! %g1 = &intr_vectors[inum]
317
318         /*
319          * Get an intr_request from the free list.  There should always be one
320          * unless we are getting an interrupt storm from stray interrupts, in
321          * which case the we will dereference a NULL pointer and panic.
322          */
323         ldx     [PCPU(IRFREE)], %g2             ! %g2 = ptr to tail element
324
325         /*
326          * Sun4v-fixme: It might be better to have the software interrupt
327          * handler deal with this scenario rather than just panic.
328          */
329         !brz,a,pt        %g2, 1f
330         !ldx     [PCPU(DEV_Q_SIZE)], %g4        ! queue size (delay slot)
331
332         ldx     [%g2 + IR_NEXT], %g3            ! %g3 = next element in list
333         stx     %g3, [PCPU(IRFREE)]             ! %g3 is now the tail
334
335         /*
336          * Store the vector number, function, argument, and priority.
337          */
338         stw     %g5, [%g2 + IR_VEC]
339         ldx     [%g1 + IV_FUNC], %g3            ! %g3 = function ptr
340         stx     %g3, [%g2 + IR_FUNC]
341         ldx     [%g1 + IV_ARG], %g3             ! %g3 = argument ptr
342         stx     %g3, [%g2 + IR_ARG]
343         lduw    [%g1 + IV_PRI], %g1             ! %g1 = priority
344         stw     %g1, [%g2 + IR_PRI]
345
346         /*
347          * Link it onto the end of the active list
348          */
349         stx     %g0, [%g2 + IR_NEXT]
350         ldx     [PCPU(IRTAIL)], %g3             ! %g3 = ptr to tail
351         stx     %g2, [%g3]
352         add     %g2, IR_NEXT, %g2
353         stx     %g2, [PCPU(IRTAIL)]
354         
355         /* 
356          * Unlike Solaris, FreeBSD throws away the rest of the 
357          * 64-byte packet.  We may want to revisit this philosophy
358          * at some point since information in the packet is defined by 
359          * the device and MAY be meaningful.
360          *
361          * For now, we retain FreeBSD's sun4u semantics.
362          */
363         ldx     [PCPU(DEV_Q_SIZE)], %g4         ! queue size
364
365 1:      sub     %g4, 1, %g4                     ! %g4 = queue size mask 
366         add     %g6, INTR_REPORT_SIZE, %g6      ! inc head to next record   
367         and     %g6, %g4, %g6                   ! and mask for wrap around      
368         mov     DEV_MONDO_QUEUE_HEAD, %g3     
369         stxa    %g6, [%g3]ASI_QUEUE             ! increment head offset 
370         membar  #Sync
371
372         /*
373          * Trigger a softint at the level indicated by the priority
374          */
375         mov     1, %g6
376         sllx    %g6, %g1, %g6
377         wr      %g6, 0, %set_softint
378 #if 0
379         mov %o0, %g1
380         mov %o5, %g6
381         PUTCHAR(0x2b)   
382         PUTCHAR(0x2b)   
383         mov %g1, %o0
384         mov %g6, %o5    
385 #endif
386         /*
387          * Done, retry the instruction  
388          */
389 0:      retry 
390
391         
392         /* NOTREACHED */
393 END(dev_mondo)
394 #endif /* lint */
395
396 ENTRY(tl_invlctx)
397         mov     %o0, %g2
398         mov     %o1, %g4
399         mov     %o2, %g5
400         mov     %o3, %g6
401         mov     %o5, %g7
402         mov     %g0, %o0
403         mov     %g0, %o1
404         mov     %g1, %o2
405         mov     MAP_ITLB|MAP_DTLB, %o3
406         mov     MMU_DEMAP_CTX, %o5
407         ta      FAST_TRAP
408         brnz,a,pn %o0, interrupt_panic_bad_hcall
409           mov   MMU_DEMAP_CTX, %o1
410         mov     %g2, %o0
411         mov     %g4, %o1
412         mov     %g5, %o2
413         mov     %g6, %o3
414         mov     %g7, %o5
415         ba,pt   %xcc, set_ackmask
416           membar #Sync
417 END(tl_invlctx)
418
419 ENTRY(tl_invltlb)
420         mov     %o0, %g1
421         mov     %o1, %g2
422         mov     %o2, %g4
423         mov     %o5, %g5
424         clr     %o0
425         clr     %o1
426         mov     MAP_ITLB | MAP_DTLB, %o2
427         mov     MMU_DEMAP_ALL, %o5
428         ta      FAST_TRAP
429         brnz,a,pn       %o0, interrupt_panic_bad_hcall
430            mov  MMU_DEMAP_ALL, %o1
431         mov     %g1, %o0
432         mov     %g2, %o1
433         mov     %g4, %o2
434         mov     %g5, %o5
435         ba,pt   %xcc, set_ackmask
436           membar #Sync
437 END(tl_invltlb)
438
439 ENTRY(tl_invlpg)
440         mov     %o0, %g5
441         mov     %o1, %g6
442         mov     %o2, %g7
443         mov     MAP_ITLB|MAP_DTLB, %o2
444         mov     %g1, %o0
445         mov     %g2, %o1
446         ta      MMU_UNMAP_ADDR
447         brnz,a,pn %o0, interrupt_panic_bad_hcall
448            mov  MMU_UNMAP_ADDR, %o1
449         mov     %g5, %o0
450         mov     %g6, %o1
451         mov     %g7, %o2
452         ba,pt   %xcc, set_ackmask
453           membar #Sync
454 END(tl_invlpg)
455
456 ENTRY(tl_invlrng)
457         sethi   %hi(PAGE_SIZE), %g5
458         dec     %g5
459         and     %g1, %g5, %g4
460         andn    %g1, %g5, %g1
461         dec     %g4
462                 
463 1:      mov     %o0, %g5
464         mov     %o1, %g6
465         mov     %o2, %g7
466         mov     MAP_ITLB|MAP_DTLB, %o2
467         mov     %g1, %o0
468         mov     %g2, %o1
469         ta      MMU_UNMAP_ADDR
470         brnz,a,pn %o0, interrupt_panic_bad_hcall
471            mov  MMU_UNMAP_ADDR, %o1
472
473         brnz,pt %g4, 1b
474           dec   %g4
475         
476         mov     %g5, %o0
477         mov     %g6, %o1
478         mov     %g7, %o2
479         ba,pt   %xcc, set_ackmask
480           membar #Sync
481 END(tl_invlrng)
482
483
484
485 ENTRY(tl_tsbupdate)
486 /* compare current context with one to be updated */
487         mov     MMU_CID_S, %g4
488         GET_MMU_CONTEXT(%g4, %g4)
489         
490         cmp     %g1, %g4
491         bne,a,pt %xcc, set_ackmask                      
492           membar #Sync
493 /*  update scratch pointer to tsbscratch */
494         wr      %g0, ASI_REAL, %asi     
495         ldxa    [%g2]%asi, %g4          ! tsbscratch
496         ldxa    [%g2 + 8]%asi, %g2      ! tsb_ra
497         mov     SCRATCH_REG_TSB_USER, %g5
498         SET_SCRATCH(%g5, %g4)
499
500 /* reset tsb context with hypervisor */
501         mov     %o0, %g1
502         mov     %o1, %g2
503         mov     %o5, %g4
504         mov     1, %o0
505         mov     %g2, %o1
506         mov     MMU_TSB_CTXNON0, %o5
507         ta      FAST_TRAP
508         
509         /* XXX test %o0 */
510         mov     %g1, %o0        
511         mov     %g2, %o1
512         mov     %g4, %o5
513         ba,pt   %xcc, set_ackmask
514           membar #Sync
515 END(tl_tsbupdate)
516
517 ENTRY(tl_ttehashupdate)
518 /* compare current context with one to be updated */
519         mov     MMU_CID_S, %g4
520         GET_MMU_CONTEXT(%g4, %g4)
521         cmp     %g1, %g4
522         bne,a,pt %xcc, set_ackmask
523           membar #Sync
524 /*  update scratch pointer to hashscratch */
525         mov     SCRATCH_REG_HASH_USER, %g4
526         SET_SCRATCH(%g4, %g2)
527 END(tl_ttehashupdate)
528                 
529 ENTRY(set_ackmask)
530         GET_PCPU_PHYS_SCRATCH(%g6)
531         wr      %g0, ASI_REAL, %asi
532
533 #ifdef TRAP_TRACING
534         /* pcpu->pad[0] = %pc */
535         rd      %pc, %g4
536         stxa    %g4, [PCPU(PAD)]%asi
537
538         /* pcpu->pad[1] = %tick */
539         rdpr    %tick, %g4
540         stxa    %g4, [PCPU(PAD) + 8]%asi
541
542         /*
543          * Increment a counter which might help us notice if we're
544          * stuck in a loop. pcpu->pad[2] = count
545          */
546         ldxa    [PCPU(PAD) + 16]%asi, %g4
547         add     %g4, 1, %g4
548         stxa    %g4, [PCPU(PAD) + 16]%asi
549 #endif
550
551         lda     [PCPU(CPUMASK)]%asi, %g4
552         lda     [%g3]%asi, %g1
553 1:      or      %g1, %g4, %g2
554         casa    [%g3]%asi, %g1, %g2
555         cmp     %g1, %g2
556         bne,a,pn %xcc, 1b
557           lda   [%g3]%asi, %g1
558         retry
559 END(set_ackmask)
560
561         /*
562          * interrupt_panic_bad_hcall is called when a hcall returns
563          * unexpected error
564          * %o0 error number
565          * %o1 hcall number
566          */
567
568         .text
569 interrupt_bad_hcall_error:
570         .asciz  "hypervisor call 0x%x returned an unexpected error %d"
571
572         
573 ENTRY(interrupt_panic_bad_hcall)
574         PUTCHAR(0x5b)
575         PUTCHAR(0x5b)
576         PUTCHAR(0x5b)
577         PUTCHAR(0x5b)
578         PUTCHAR(0x5b)
579         mov     %o0, %o2
580         sethi   %hi(interrupt_bad_hcall_error), %o0
581         or      %o0, %lo(interrupt_bad_hcall_error), %o0
582         mov     %o7, %o3
583         call    panic
584           mov   %o3, %o7
585 END(interrupt_panic_bad_hcall)