]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/mips/nlm/intr_machdep.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / mips / nlm / intr_machdep.c
1 /*-
2  * Copyright 2003-2011 Netlogic Microsystems (Netlogic). All rights
3  * reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
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
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY Netlogic Microsystems ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE 
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * NETLOGIC_BSD */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36 #include <sys/interrupt.h>
37 #include <sys/kernel.h>
38
39 #include <machine/cpu.h>
40 #include <machine/cpufunc.h>
41 #include <machine/cpuinfo.h>
42 #include <machine/cpuregs.h>
43 #include <machine/frame.h>
44 #include <machine/intr_machdep.h>
45 #include <machine/md_var.h>
46 #include <machine/trap.h>
47 #include <machine/hwfunc.h>
48
49 #include <mips/nlm/hal/haldefs.h>
50 #include <mips/nlm/hal/iomap.h>
51 #include <mips/nlm/hal/mips-extns.h>
52 #include <mips/nlm/interrupt.h>
53 #include <mips/nlm/hal/pic.h>
54 #include <mips/nlm/xlp.h>
55
56 struct xlp_intrsrc {
57         void (*busack)(int);            /* Additional ack */
58         struct intr_event *ie;          /* event corresponding to intr */
59         int irq;
60 };
61         
62 static struct xlp_intrsrc xlp_interrupts[XLR_MAX_INTR];
63 static mips_intrcnt_t mips_intr_counters[XLR_MAX_INTR];
64 static int intrcnt_index;
65
66 void
67 xlp_enable_irq(int irq)
68 {
69         uint64_t eimr;
70
71         eimr = nlm_read_c0_eimr();
72         nlm_write_c0_eimr(eimr | (1ULL << irq));
73 }
74
75 void
76 cpu_establish_softintr(const char *name, driver_filter_t * filt,
77     void (*handler) (void *), void *arg, int irq, int flags,
78     void **cookiep)
79 {
80
81         panic("Soft interrupts unsupported!\n");
82 }
83
84 void
85 cpu_establish_hardintr(const char *name, driver_filter_t * filt,
86     void (*handler) (void *), void *arg, int irq, int flags,
87     void **cookiep)
88 {
89
90         xlp_establish_intr(name, filt, handler, arg, irq, flags,
91             cookiep, NULL);
92 }
93
94 static void
95 xlp_post_filter(void *source)
96 {
97         struct xlp_intrsrc *src = source;
98         
99         if (src->busack)
100                 src->busack(src->irq);
101         nlm_pic_ack(xlp_pic_base, xlp_irq_to_irt(src->irq));
102 }
103
104 static void
105 xlp_pre_ithread(void *source)
106 {
107         struct xlp_intrsrc *src = source;
108
109         if (src->busack)
110                 src->busack(src->irq);
111 }
112
113 static void
114 xlp_post_ithread(void *source)
115 {
116         struct xlp_intrsrc *src = source;
117
118         nlm_pic_ack(xlp_pic_base, xlp_irq_to_irt(src->irq));
119 }
120
121 void
122 xlp_establish_intr(const char *name, driver_filter_t filt,
123     driver_intr_t handler, void *arg, int irq, int flags,
124     void **cookiep, void (*busack)(int))
125 {
126         struct intr_event *ie;  /* descriptor for the IRQ */
127         struct xlp_intrsrc *src = NULL;
128         int errcode;
129
130         if (irq < 0 || irq > XLR_MAX_INTR)
131                 panic("%s called for unknown hard intr %d", __func__, irq);
132
133         /*
134          * FIXME locking - not needed now, because we do this only on
135          * startup from CPU0
136          */
137         src = &xlp_interrupts[irq];
138         ie = src->ie;
139         if (ie == NULL) {
140                 /*
141                  * PIC based interrupts need ack in PIC, and some SoC
142                  * components need additional acks (e.g. PCI)
143                  */
144                 if (xlp_irq_is_picintr(irq))
145                         errcode = intr_event_create(&ie, src, 0, irq,
146                             xlp_pre_ithread, xlp_post_ithread, xlp_post_filter,
147                             NULL, "hard intr%d:", irq);
148                 else {
149                         if (filt == NULL)
150                                 panic("Not supported - non filter percpu intr");
151                         errcode = intr_event_create(&ie, src, 0, irq,
152                             NULL, NULL, NULL, NULL, "hard intr%d:", irq);
153                 }
154                 if (errcode) {
155                         printf("Could not create event for intr %d\n", irq);
156                         return;
157                 }
158                 src->irq = irq;
159                 src->busack = busack;
160                 src->ie = ie;
161         }
162         intr_event_add_handler(ie, name, filt, handler, arg,
163             intr_priority(flags), flags, cookiep);
164         xlp_enable_irq(irq);
165 }
166
167 void
168 cpu_intr(struct trapframe *tf)
169 {
170         struct intr_event *ie;
171         uint64_t eirr, eimr;
172         int i;
173
174         critical_enter();
175
176         /* find a list of enabled interrupts */
177         eirr = nlm_read_c0_eirr();
178         eimr = nlm_read_c0_eimr();
179         eirr &= eimr;
180         
181         if (eirr == 0) { 
182                 critical_exit();
183                 return;
184         }
185         /*
186          * No need to clear the EIRR here as the handler writes to
187          * compare which ACKs the interrupt.
188          */
189         if (eirr & (1 << IRQ_TIMER)) {
190                 intr_event_handle(xlp_interrupts[IRQ_TIMER].ie, tf);
191                 critical_exit();
192                 return;
193         }
194         
195         /* FIXME sched pin >? LOCK>? */
196         for (i = sizeof(eirr) * 8 - 1; i >= 0; i--) {
197                 if ((eirr & (1ULL << i)) == 0)
198                         continue;
199
200                 ie = xlp_interrupts[i].ie;
201                 /* Don't account special IRQs */
202                 switch (i) {
203                 case IRQ_IPI:
204                 case IRQ_MSGRING:
205                         break;
206                 default:
207                         mips_intrcnt_inc(mips_intr_counters[i]);
208                 }
209
210                 /* Ack the IRQ on the CPU */
211                 nlm_write_c0_eirr(1ULL << i);
212                 if (intr_event_handle(ie, tf) != 0) {
213                         printf("stray interrupt %d\n", i);
214                 }
215         }
216         critical_exit();
217 }
218
219 void
220 mips_intrcnt_setname(mips_intrcnt_t counter, const char *name)
221 {
222         int idx = counter - intrcnt;
223
224         KASSERT(counter != NULL, ("mips_intrcnt_setname: NULL counter"));
225
226         snprintf(intrnames + (MAXCOMLEN + 1) * idx,
227             MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name);
228 }
229
230 mips_intrcnt_t
231 mips_intrcnt_create(const char* name)
232 {
233         mips_intrcnt_t counter = &intrcnt[intrcnt_index++];
234
235         mips_intrcnt_setname(counter, name);
236         return counter;
237 }
238
239 void
240 cpu_init_interrupts()
241 {
242         int i;
243         char name[MAXCOMLEN + 1];
244
245         /*
246          * Initialize all available vectors so spare IRQ
247          * would show up in systat output 
248          */
249         for (i = 0; i < XLR_MAX_INTR; i++) {
250                 snprintf(name, MAXCOMLEN + 1, "int%d:", i);
251                 mips_intr_counters[i] = mips_intrcnt_create(name);
252         }
253 }