marvell_intr.h revision 1.15.14.1 1 /* $NetBSD: marvell_intr.h,v 1.15.14.1 2009/05/13 17:18:15 jym Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #ifndef _MVPPPC_INTR_H_
33 #define _MVPPPC_INTR_H_
34
35 #include <powerpc/psl.h>
36 #include <powerpc/frame.h>
37
38 /*
39 * Interrupt Priority Levels
40 */
41 #define IPL_NONE 0 /* nothing */
42 #define IPL_SOFTCLOCK 1 /* timeouts */
43 #define IPL_SOFTBIO 2 /* block I/O */
44 #define IPL_SOFTNET 3 /* protocol stacks */
45 #define IPL_SOFTSERIAL 4 /* serial */
46 #define IPL_VM 12 /* memory allocation */
47 #define IPL_SCHED 14 /* clock */
48 #define IPL_HIGH 15 /* everything */
49 #define NIPL 16
50 #define IPL_PRIMASK 0xf
51 #define IPL_EE 0x10 /* enable external interrupts on splx */
52
53 /* Interrupt sharing types. */
54 #define IST_NONE 0 /* none */
55 #define IST_PULSE 1 /* pulsed */
56 #define IST_EDGE 2 /* edge-triggered */
57 #define IST_LEVEL 3 /* level-triggered */
58 #define IST_SOFT 4 /* software-triggered */
59 #define IST_CLOCK 5 /* exclusive for clock */
60 #define NIST 6
61
62 #if !defined(_LOCORE) && defined(_KERNEL)
63
64 #define CLKF_BASEPRI(frame) ((frame)->pri == IPL_NONE)
65
66 /*
67 * we support 128 IRQs:
68 * 96 (ICU_LEN) hard interrupt IRQs:
69 * - 64 Main Cause IRQs,
70 * - 32 GPP IRQs,
71 * and 32 softint IRQs
72 */
73 #define ICU_LEN 96 /* number of HW IRQs */
74 #define IRQ_GPP_BASE 64 /* base of GPP IRQs */
75 #define IRQ_GPP_SUM (32+24) /* GPP[7..0] interrupt */ /* XXX */
76 #define NIRQ 128 /* total # of HW IRQs */
77
78 #define IMASK_ICU_LO 0
79 #define IMASK_ICU_HI 1
80 #define IMASK_ICU_GPP 2
81 #define IMASK_SOFTINT 3
82 #define IMASK_WORDSHIFT 5 /* log2(32) */
83 #define IMASK_BITMASK ~((~0) << IMASK_WORDSHIFT)
84
85 #define IRQ_IS_GPP(irq) ((irq >= IRQ_GPP_BASE) && (irq < ICU_LEN))
86
87 /*
88 * interrupt mask bit vector
89 */
90 typedef struct {
91 u_int32_t bits[4];
92 } imask_t __attribute__ ((aligned(16)));
93
94 static inline void imask_zero(imask_t *);
95 static inline void imask_zero_v(volatile imask_t *);
96 static inline void imask_dup_v(imask_t *, const volatile imask_t *);
97 static inline void imask_and(imask_t *, const imask_t *);
98 static inline void imask_andnot_v(volatile imask_t *, const imask_t *);
99 static inline void imask_andnot_icu_vv(volatile imask_t *, const volatile imask_t *);
100 static inline int imask_empty(const imask_t *);
101 static inline void imask_orbit(imask_t *, int);
102 static inline void imask_orbit_v(volatile imask_t *, int);
103 static inline void imask_clrbit(imask_t *, int);
104 static inline void imask_clrbit_v(volatile imask_t *, int);
105 static inline u_int32_t imask_andbit_v(const volatile imask_t *, int);
106 static inline int imask_test_v(const volatile imask_t *, const imask_t *);
107
108 static inline void
109 imask_zero(imask_t *idp)
110 {
111 idp->bits[IMASK_ICU_LO] = 0;
112 idp->bits[IMASK_ICU_HI] = 0;
113 idp->bits[IMASK_ICU_GPP] = 0;
114 idp->bits[IMASK_SOFTINT] = 0;
115 }
116
117 static inline void
118 imask_zero_v(volatile imask_t *idp)
119 {
120 idp->bits[IMASK_ICU_LO] = 0;
121 idp->bits[IMASK_ICU_HI] = 0;
122 idp->bits[IMASK_ICU_GPP] = 0;
123 idp->bits[IMASK_SOFTINT] = 0;
124 }
125
126 static inline void
127 imask_dup_v(imask_t *idp, const volatile imask_t *isp)
128 {
129 *idp = *isp;
130 }
131
132 static inline void
133 imask_and(imask_t *idp, const imask_t *isp)
134 {
135 idp->bits[IMASK_ICU_LO] &= isp->bits[IMASK_ICU_LO];
136 idp->bits[IMASK_ICU_HI] &= isp->bits[IMASK_ICU_HI];
137 idp->bits[IMASK_ICU_GPP] &= isp->bits[IMASK_ICU_GPP];
138 idp->bits[IMASK_SOFTINT] &= isp->bits[IMASK_SOFTINT];
139 }
140
141 static inline void
142 imask_andnot_v(volatile imask_t *idp, const imask_t *isp)
143 {
144 idp->bits[IMASK_ICU_LO] &= ~isp->bits[IMASK_ICU_LO];
145 idp->bits[IMASK_ICU_HI] &= ~isp->bits[IMASK_ICU_HI];
146 idp->bits[IMASK_ICU_GPP] &= ~isp->bits[IMASK_ICU_GPP];
147 idp->bits[IMASK_SOFTINT] &= ~isp->bits[IMASK_SOFTINT];
148 }
149
150 static inline void
151 imask_andnot_icu_vv(volatile imask_t *idp, const volatile imask_t *isp)
152 {
153 idp->bits[IMASK_ICU_LO] &= ~isp->bits[IMASK_ICU_LO];
154 idp->bits[IMASK_ICU_HI] &= ~isp->bits[IMASK_ICU_HI];
155 idp->bits[IMASK_ICU_GPP] &= ~isp->bits[IMASK_ICU_GPP];
156 }
157
158 static inline int
159 imask_empty(const imask_t *isp)
160 {
161 return (! (isp->bits[IMASK_ICU_LO] | isp->bits[IMASK_ICU_HI] |
162 isp->bits[IMASK_ICU_GPP]| isp->bits[IMASK_SOFTINT]));
163 }
164
165 static inline void
166 imask_orbit(imask_t *idp, int bitno)
167 {
168 idp->bits[bitno>>IMASK_WORDSHIFT] |= (1 << (bitno&IMASK_BITMASK));
169 }
170
171 static inline void
172 imask_orbit_v(volatile imask_t *idp, int bitno)
173 {
174 idp->bits[bitno>>IMASK_WORDSHIFT] |= (1 << (bitno&IMASK_BITMASK));
175 }
176
177 static inline void
178 imask_clrbit(imask_t *idp, int bitno)
179 {
180 idp->bits[bitno>>IMASK_WORDSHIFT] &= ~(1 << (bitno&IMASK_BITMASK));
181 }
182
183 static inline void
184 imask_clrbit_v(volatile imask_t *idp, int bitno)
185 {
186 idp->bits[bitno>>IMASK_WORDSHIFT] &= ~(1 << (bitno&IMASK_BITMASK));
187 }
188
189 static inline u_int32_t
190 imask_andbit_v(const volatile imask_t *idp, int bitno)
191 {
192 return idp->bits[bitno>>IMASK_WORDSHIFT] & (1 << (bitno&IMASK_BITMASK));
193 }
194
195 static inline int
196 imask_test_v(const volatile imask_t *idp, const imask_t *isp)
197 {
198 return ((idp->bits[IMASK_ICU_LO] & isp->bits[IMASK_ICU_LO]) ||
199 (idp->bits[IMASK_ICU_HI] & isp->bits[IMASK_ICU_HI]) ||
200 (idp->bits[IMASK_ICU_GPP] & isp->bits[IMASK_ICU_GPP])||
201 (idp->bits[IMASK_SOFTINT] & isp->bits[IMASK_SOFTINT]));
202 }
203
204 #ifdef EXT_INTR_STATS
205 /*
206 * ISR timing stats
207 */
208
209 typedef struct ext_intr_hist {
210 u_int64_t tcause;
211 u_int64_t tcommit;
212 u_int64_t tstart;
213 u_int64_t tfin;
214 } ext_intr_hist_t __attribute__ ((aligned(32)));
215
216 typedef struct ext_intr_stat {
217 struct ext_intr_hist *histp;
218 unsigned int histix;
219 u_int64_t cnt;
220 u_int64_t sum;
221 u_int64_t min;
222 u_int64_t max;
223 u_int64_t pnd;
224 u_int64_t borrowed;
225 struct ext_intr_stat *save;
226 unsigned long preempted[NIRQ]; /* XXX */
227 } ext_intr_stat_t __attribute__ ((aligned(32)));
228
229 extern int intr_depth_max;
230 extern int ext_intr_stats_enb;
231 extern ext_intr_stat_t ext_intr_stats[];
232 extern ext_intr_stat_t *ext_intr_statp;
233
234 extern void ext_intr_stats_init(void);
235 extern void ext_intr_stats_cause
236 (u_int32_t, u_int32_t, u_int32_t, u_int32_t);
237 extern void ext_intr_stats_pend
238 (u_int32_t, u_int32_t, u_int32_t, u_int32_t);
239 extern void ext_intr_stats_commit(imask_t *);
240 extern void ext_intr_stats_commit_m(imask_t *);
241 extern void ext_intr_stats_commit_irq(u_int);
242 extern u_int64_t ext_intr_stats_pre(int);
243 extern void ext_intr_stats_post(int, u_int64_t);
244
245 #define EXT_INTR_STATS_INIT() ext_intr_stats_init()
246 #define EXT_INTR_STATS_CAUSE(l, h, g, s) ext_intr_stats_cause(l, h, g, s)
247 #define EXT_INTR_STATS_COMMIT_M(m) ext_intr_stats_commit_m(m)
248 #define EXT_INTR_STATS_COMMIT_IRQ(i) ext_intr_stats_commit_irq(i)
249 #define EXT_INTR_STATS_DECL(t) u_int64_t t
250 #define EXT_INTR_STATS_PRE(i, t) t = ext_intr_stats_pre(i)
251 #define EXT_INTR_STATS_POST(i, t) ext_intr_stats_post(i, t)
252 #define EXT_INTR_STATS_PEND(l, h, g, s) ext_intr_stats_pend(l, h, g, s)
253 #define EXT_INTR_STATS_PEND_IRQ(i) ext_intr_stats[i].pnd++
254 #define EXT_INTR_STATS_DEPTH() \
255 intr_depth_max = (intr_depth > intr_depth_max) ? \
256 intr_depth : intr_depth_max
257
258 #else /* EXT_INTR_STATS */
259
260 #define EXT_INTR_STATS_INIT()
261 #define EXT_INTR_STATS_CAUSE(l, h, g, s)
262 #define EXT_INTR_STATS_COMMIT_M(m)
263 #define EXT_INTR_STATS_COMMIT_IRQ(i)
264 #define EXT_INTR_STATS_DECL(t)
265 #define EXT_INTR_STATS_PRE(irq, t)
266 #define EXT_INTR_STATS_POST(i, t)
267 #define EXT_INTR_STATS_PEND(l, h, g, s)
268 #define EXT_INTR_STATS_PEND_IRQ(i)
269 #define EXT_INTR_STATS_DEPTH()
270
271 #endif /* EXT_INTR_STATS */
272
273
274 #ifdef SPL_STATS
275 typedef struct spl_hist {
276 int level;
277 void *addr;
278 u_int64_t time;
279 } spl_hist_t;
280
281 extern void spl_stats_init();
282 extern void spl_stats_log();
283 extern unsigned int spl_stats_enb;
284
285 #define SPL_STATS_INIT() spl_stats_init()
286 #define SPL_STATS_LOG(ipl, cc) spl_stats_log((ipl), (cc))
287
288 #else
289
290 #define SPL_STATS_INIT()
291 #define SPL_STATS_LOG(ipl, cc)
292
293 #endif /* SPL_STATS */
294
295
296 void intr_dispatch(void);
297 #ifdef SPL_INLINE
298 static inline int splraise(int);
299 static inline int spllower(int);
300 static inline void splx(int);
301 #else
302 extern int splraise(int);
303 extern int spllower(int);
304 extern void splx(int);
305 #endif
306
307 extern volatile int tickspending;
308
309 extern volatile imask_t ipending;
310 extern imask_t imask[];
311
312 /*
313 * inlines for manipulating PSL_EE
314 */
315 static inline void
316 extintr_restore(register_t omsr)
317 {
318 __asm volatile ("sync; mtmsr %0;" :: "r"(omsr));
319 }
320
321 static inline register_t
322 extintr_enable(void)
323 {
324 register_t omsr;
325
326 __asm volatile("sync;");
327 __asm volatile("mfmsr %0;" : "=r"(omsr));
328 __asm volatile("mtmsr %0;" :: "r"(omsr | PSL_EE));
329
330 return omsr;
331 }
332
333 static inline register_t
334 extintr_disable(void)
335 {
336 register_t omsr;
337
338 __asm volatile("mfmsr %0;" : "=r"(omsr));
339 __asm volatile("mtmsr %0;" :: "r"(omsr & ~PSL_EE));
340 __asm volatile("isync;");
341
342 return omsr;
343 }
344
345 #ifdef SPL_INLINE
346 static inline int
347 splraise(int ncpl)
348 {
349 int ocpl;
350 register_t omsr;
351
352 omsr = extintr_disable();
353 ocpl = cpl;
354 if (ncpl > cpl) {
355 SPL_STATS_LOG(ncpl, 0);
356 cpl = ncpl;
357 if ((ncpl == IPL_HIGH) && ((omsr & PSL_EE) != 0)) {
358 /* leave external interrupts disabled */
359 return (ocpl | IPL_EE);
360 }
361 }
362 extintr_restore(omsr);
363 return (ocpl);
364 }
365
366 static inline void
367 splx(int xcpl)
368 {
369 imask_t *ncplp;
370 register_t omsr;
371 int ncpl = xcpl & IPL_PRIMASK;
372
373 ncplp = &imask[ncpl];
374
375 omsr = extintr_disable();
376 if (ncpl < cpl) {
377 cpl = ncpl;
378 SPL_STATS_LOG(ncpl, 0);
379 if (imask_test_v(&ipending, ncplp))
380 intr_dispatch();
381 }
382 if (xcpl & IPL_EE)
383 omsr |= PSL_EE;
384 extintr_restore(omsr);
385 }
386
387 static inline int
388 spllower(int ncpl)
389 {
390 int ocpl;
391 imask_t *ncplp;
392 register_t omsr;
393
394 ncpl &= IPL_PRIMASK;
395 ncplp = &imask[ncpl];
396
397 omsr = extintr_disable();
398 ocpl = cpl;
399 cpl = ncpl;
400 SPL_STATS_LOG(ncpl, 0);
401 #ifdef EXT_INTR_STATS
402 ext_intr_statp = 0;
403 #endif
404 if (imask_test_v(&ipending, ncplp))
405 intr_dispatch();
406
407 if (ncpl < IPL_HIGH)
408 omsr |= PSL_EE;
409 extintr_restore(omsr);
410
411 return (ocpl);
412 }
413 #endif /* SPL_INLINE */
414
415
416 /*
417 * Soft interrupt IRQs
418 * see also intrnames[] in locore.S
419 */
420 #define SIR_BASE (NIRQ-32)
421 #define SIXBIT(ipl) ((ipl) - SIR_BASE) /* XXX rennovate later */
422 #define SIR_SOFTCLOCK (NIRQ-5)
423 #define SIR_CLOCK SIXBIT(SIR_SOFTCLOCK) /* XXX rennovate later */
424 #define SIR_SOFTNET (NIRQ-4)
425 #define SIR_SOFTBIO (NIRQ-3)
426 #define SIR_SOFTSERIAL (NIRQ-2)
427 #define SIR_HWCLOCK (NIRQ-1)
428 #define SPL_CLOCK SIXBIT(SIR_HWCLOCK) /* XXX rennovate later */
429 #define SIR_RES ~(SIBIT(SIR_SOFTCLOCK)|\
430 SIBIT(SIR_SOFTNET)|\
431 SIBIT(SIR_SOFTBIO)|\
432 SIBIT(SIR_SOFTSERIAL)|\
433 SIBIT(SIR_HWCLOCK))
434
435 struct intrhand;
436
437 /*
438 * Miscellaneous
439 */
440 #define spl0() spllower(IPL_NONE)
441
442 typedef int ipl_t;
443 typedef struct {
444 ipl_t _ipl;
445 } ipl_cookie_t;
446
447 static inline ipl_cookie_t
448 makeiplcookie(ipl_t ipl)
449 {
450
451 return (ipl_cookie_t){._ipl = ipl};
452 }
453
454 static inline int
455 splraiseipl(ipl_cookie_t icookie)
456 {
457
458 return splraise(icookie._ipl);
459 }
460
461 #include <sys/spl.h>
462
463 #define SIBIT(ipl) (1 << ((ipl) - SIR_BASE))
464
465 void *intr_establish(int, int, int, int (*)(void *), void *);
466 void intr_disestablish(void *);
467 void init_interrupt(void);
468 const char * intr_typename(int);
469 const char * intr_string(int);
470 const struct evcnt * intr_evcnt(int);
471 void ext_intr(struct intrframe *);
472
473 /* the following are needed to compile until this port is properly
474 * converted to ppcoea-rennovation.
475 */
476 void genppc_cpu_configure(void);
477
478 void strayintr(int);
479
480 /*
481 * defines for indexing intrcnt
482 */
483 #define CNT_IRQ0 0
484 #define CNT_CLOCK SIR_HWCLOCK
485 #define CNT_SOFTCLOCK SIR_SOFTCLOCK
486 #define CNT_SOFTNET SIR_NET
487 #define CNT_SOFTSERIAL SIR_SOFTSERIAL
488 #define CNT_SOFTBIO SIR_BIO
489
490 #endif /* !_LOCORE */
491
492 #endif /* _MVPPPC_INTR_H_ */
493