1 /* $NetBSD: marvell_intr.h,v 1.15 2008/04/28 20:23:32 martin Exp $ */
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
32 #ifndef _MVPPPC_INTR_H_
33 #define _MVPPPC_INTR_H_
35 #include <powerpc/psl.h>
36 #include <powerpc/frame.h>
39 * Interrupt Priority Levels
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 */
50 #define IPL_PRIMASK 0xf
51 #define IPL_EE 0x10 /* enable external interrupts on splx */
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 */
62 #if !defined(_LOCORE) && defined(_KERNEL)
64 #define CLKF_BASEPRI(frame) ((frame)->pri == IPL_NONE)
67 * we support 128 IRQs:
68 * 96 (ICU_LEN) hard interrupt IRQs:
69 * - 64 Main Cause IRQs,
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 */
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)
85 #define IRQ_IS_GPP(irq) ((irq >= IRQ_GPP_BASE) && (irq < ICU_LEN))
88 * interrupt mask bit vector
92 } imask_t
__attribute__ ((aligned(16)));
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
*);
109 imask_zero(imask_t
*idp
)
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;
118 imask_zero_v(volatile imask_t
*idp
)
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;
127 imask_dup_v(imask_t
*idp
, const volatile imask_t
*isp
)
133 imask_and(imask_t
*idp
, const imask_t
*isp
)
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
];
142 imask_andnot_v(volatile imask_t
*idp
, const imask_t
*isp
)
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
];
151 imask_andnot_icu_vv(volatile imask_t
*idp
, const volatile imask_t
*isp
)
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
];
159 imask_empty(const imask_t
*isp
)
161 return (! (isp
->bits
[IMASK_ICU_LO
] | isp
->bits
[IMASK_ICU_HI
] |
162 isp
->bits
[IMASK_ICU_GPP
]| isp
->bits
[IMASK_SOFTINT
]));
166 imask_orbit(imask_t
*idp
, int bitno
)
168 idp
->bits
[bitno
>>IMASK_WORDSHIFT
] |= (1 << (bitno
&IMASK_BITMASK
));
172 imask_orbit_v(volatile imask_t
*idp
, int bitno
)
174 idp
->bits
[bitno
>>IMASK_WORDSHIFT
] |= (1 << (bitno
&IMASK_BITMASK
));
178 imask_clrbit(imask_t
*idp
, int bitno
)
180 idp
->bits
[bitno
>>IMASK_WORDSHIFT
] &= ~(1 << (bitno
&IMASK_BITMASK
));
184 imask_clrbit_v(volatile imask_t
*idp
, int bitno
)
186 idp
->bits
[bitno
>>IMASK_WORDSHIFT
] &= ~(1 << (bitno
&IMASK_BITMASK
));
189 static inline u_int32_t
190 imask_andbit_v(const volatile imask_t
*idp
, int bitno
)
192 return idp
->bits
[bitno
>>IMASK_WORDSHIFT
] & (1 << (bitno
&IMASK_BITMASK
));
196 imask_test_v(const volatile imask_t
*idp
, const imask_t
*isp
)
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
]));
204 #ifdef EXT_INTR_STATS
209 typedef struct ext_intr_hist
{
214 } ext_intr_hist_t
__attribute__ ((aligned(32)));
216 typedef struct ext_intr_stat
{
217 struct ext_intr_hist
*histp
;
225 struct ext_intr_stat
*save
;
226 unsigned long preempted
[NIRQ
]; /* XXX */
227 } ext_intr_stat_t
__attribute__ ((aligned(32)));
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
;
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
);
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
258 #else /* EXT_INTR_STATS */
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()
271 #endif /* EXT_INTR_STATS */
275 typedef struct spl_hist
{
281 extern void spl_stats_init();
282 extern void spl_stats_log();
283 extern unsigned int spl_stats_enb
;
285 #define SPL_STATS_INIT() spl_stats_init()
286 #define SPL_STATS_LOG(ipl, cc) spl_stats_log((ipl), (cc))
290 #define SPL_STATS_INIT()
291 #define SPL_STATS_LOG(ipl, cc)
293 #endif /* SPL_STATS */
296 void intr_dispatch(void);
298 static inline int splraise(int);
299 static inline int spllower(int);
300 static inline void splx(int);
302 extern int splraise(int);
303 extern int spllower(int);
304 extern void splx(int);
307 extern volatile int tickspending
;
309 extern volatile imask_t ipending
;
310 extern imask_t imask
[];
313 * inlines for manipulating PSL_EE
316 extintr_restore(register_t omsr
)
318 __asm
volatile ("sync; mtmsr %0;" :: "r"(omsr
));
321 static inline register_t
326 __asm
volatile("sync;");
327 __asm
volatile("mfmsr %0;" : "=r"(omsr
));
328 __asm
volatile("mtmsr %0;" :: "r"(omsr
| PSL_EE
));
333 static inline register_t
334 extintr_disable(void)
338 __asm
volatile("mfmsr %0;" : "=r"(omsr
));
339 __asm
volatile("mtmsr %0;" :: "r"(omsr
& ~PSL_EE
));
340 __asm
volatile("isync;");
352 omsr
= extintr_disable();
355 SPL_STATS_LOG(ncpl
, 0);
357 if ((ncpl
== IPL_HIGH
) && ((omsr
& PSL_EE
) != 0)) {
358 /* leave external interrupts disabled */
359 return (ocpl
| IPL_EE
);
362 extintr_restore(omsr
);
371 int ncpl
= xcpl
& IPL_PRIMASK
;
373 ncplp
= &imask
[ncpl
];
375 omsr
= extintr_disable();
378 SPL_STATS_LOG(ncpl
, 0);
379 if (imask_test_v(&ipending
, ncplp
))
384 extintr_restore(omsr
);
395 ncplp
= &imask
[ncpl
];
397 omsr
= extintr_disable();
400 SPL_STATS_LOG(ncpl
, 0);
401 #ifdef EXT_INTR_STATS
404 if (imask_test_v(&ipending
, ncplp
))
409 extintr_restore(omsr
);
413 #endif /* SPL_INLINE */
417 * Soft interrupt IRQs
418 * see also intrnames[] in locore.S
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)|\
432 SIBIT(SIR_SOFTSERIAL)|\
440 #define spl0() spllower(IPL_NONE)
447 static inline ipl_cookie_t
448 makeiplcookie(ipl_t ipl
)
451 return (ipl_cookie_t
){._ipl
= ipl
};
455 splraiseipl(ipl_cookie_t icookie
)
458 return splraise(icookie
._ipl
);
463 #define SIBIT(ipl) (1 << ((ipl) - SIR_BASE))
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
*);
473 /* the following are needed to compile until this port is properly
474 * converted to ppcoea-rennovation.
476 void genppc_cpu_configure(void);
481 * defines for indexing intrcnt
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
490 #endif /* !_LOCORE */
492 #endif /* _MVPPPC_INTR_H_ */