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