xref: /netbsd-src/sys/arch/powerpc/marvell/marvell_intr.h (revision 500db002748d9818288e46e10f026a2b09548086)
1 /*	$NetBSD: marvell_intr.h,v 1.16 2009/03/14 14:46:05 dsl 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