Annotation of sys/arch/landisk/landisk/intr.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: intr.c,v 1.5 2007/04/09 13:23:25 miod Exp $ */
! 2: /* $NetBSD: intr.c,v 1.1 2006/09/01 21:26:18 uwe Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2005 NONAKA Kimihiro
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 20: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 27: * SUCH DAMAGE.
! 28: */
! 29:
! 30: #include <sys/param.h>
! 31: #include <sys/systm.h>
! 32: #include <sys/kernel.h>
! 33: #include <sys/malloc.h>
! 34: #include <sys/device.h>
! 35: #include <sys/evcount.h>
! 36:
! 37: #include <sh/trap.h>
! 38:
! 39: #include <machine/intr.h>
! 40:
! 41: #define _N_EXTINTR 8
! 42:
! 43: #define LANDISK_INTEN 0xb0000005
! 44: #define INTEN_ALL_MASK 0x00
! 45:
! 46: struct intrhand {
! 47: int (*ih_fun)(void *);
! 48: void *ih_arg;
! 49: struct intrhand *ih_next;
! 50: int ih_enable;
! 51: int ih_level;
! 52: int ih_irq;
! 53: struct evcount ih_count;
! 54: const char *ih_name;
! 55: };
! 56:
! 57: struct extintr_handler {
! 58: int (*eih_func)(void *eih_arg);
! 59: void *eih_arg;
! 60: struct intrhand *eih_ih;
! 61: int eih_nih;
! 62: };
! 63:
! 64: static struct extintr_handler extintr_handler[_N_EXTINTR];
! 65:
! 66: static int fakeintr(void *arg);
! 67: static int extintr_intr_handler(void *arg);
! 68:
! 69: void
! 70: intc_intr(int ssr, int spc, int ssp)
! 71: {
! 72: struct intc_intrhand *ih;
! 73: struct clockframe cf;
! 74: int evtcode;
! 75:
! 76: evtcode = _reg_read_4(SH4_INTEVT);
! 77: ih = EVTCODE_IH(evtcode);
! 78: KDASSERT(ih->ih_func);
! 79:
! 80: switch (evtcode) {
! 81: #if 0
! 82: #define IRL(irq) (0x200 + ((irq) << 5))
! 83: case IRL(5): case IRL(6): case IRL(7): case IRL(8):
! 84: case IRL(9): case IRL(10): case IRL(11): case IRL(12):
! 85: {
! 86: int level;
! 87: uint8_t inten, bit;
! 88:
! 89: bit = 1 << (EVTCODE_TO_MAP_INDEX(evtcode) - 5);
! 90: inten = _reg_read_1(LANDISK_INTEN);
! 91: _reg_write_1(LANDISK_INTEN, inten & ~bit);
! 92: level = (_IPL_NSOFT + 1) << 4; /* disable softintr */
! 93: ssr &= 0xf0;
! 94: if (level < ssr)
! 95: level = ssr;
! 96: (void)_cpu_intr_resume(level);
! 97: if ((*ih->ih_func)(ih->ih_arg) != 0)
! 98: ih->ih_count.ec_count++;
! 99: _reg_write_1(LANDISK_INTEN, inten);
! 100: break;
! 101: }
! 102: #endif
! 103: default:
! 104: (void)_cpu_intr_resume(ih->ih_level);
! 105: if ((*ih->ih_func)(ih->ih_arg) != 0)
! 106: ih->ih_count.ec_count++;
! 107: break;
! 108:
! 109: case SH_INTEVT_TMU0_TUNI0:
! 110: (void)_cpu_intr_resume(ih->ih_level);
! 111: cf.spc = spc;
! 112: cf.ssr = ssr;
! 113: cf.ssp = ssp;
! 114: if ((*ih->ih_func)(&cf) != 0)
! 115: ih->ih_count.ec_count++;
! 116: break;
! 117:
! 118: case SH_INTEVT_NMI:
! 119: printf("NMI ignored.\n");
! 120: break;
! 121: }
! 122: }
! 123:
! 124: void
! 125: intr_init(void)
! 126: {
! 127: _reg_write_1(LANDISK_INTEN, INTEN_ALL_MASK);
! 128: }
! 129:
! 130: void *
! 131: extintr_establish(int irq, int level, int (*ih_fun)(void *), void *ih_arg,
! 132: const char *ih_name)
! 133: {
! 134: static struct intrhand fakehand = {fakeintr};
! 135: struct extintr_handler *eih;
! 136: struct intrhand **p, *q, *ih;
! 137: int evtcode;
! 138: int s;
! 139:
! 140: KDASSERT(irq >= 5 && irq < 13);
! 141:
! 142: ih = malloc(sizeof(*ih), M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
! 143: if (ih == NULL)
! 144: panic("intr_establish: can't malloc handler info");
! 145:
! 146: s = _cpu_intr_suspend();
! 147:
! 148: switch (level) {
! 149: default:
! 150: #if defined(DEBUG)
! 151: panic("extintr_establish: unknown level %d", level);
! 152: /*NOTREACHED*/
! 153: #endif
! 154: case IPL_BIO:
! 155: case IPL_NET:
! 156: case IPL_TTY:
! 157: break;
! 158: }
! 159:
! 160: eih = &extintr_handler[irq - 5];
! 161: if (eih->eih_func == NULL) {
! 162: evtcode = 0x200 + (irq << 5);
! 163: eih->eih_func = intc_intr_establish(evtcode, IST_LEVEL, level,
! 164: extintr_intr_handler, eih, NULL);
! 165: }
! 166:
! 167: /*
! 168: * Figure out where to put the handler.
! 169: * This is O(N^2), but we want to preserve the order, and N is
! 170: * generally small.
! 171: */
! 172: for (p = &eih->eih_ih; (q = *p) != NULL; p = &q->ih_next)
! 173: continue;
! 174:
! 175: /*
! 176: * Actually install a fake handler momentarily, since we might be doing
! 177: * this with interrupts enabled and don't want the real routine called
! 178: * until masking is set up.
! 179: */
! 180: fakehand.ih_level = level;
! 181: *p = &fakehand;
! 182:
! 183: /*
! 184: * Poke the real handler in now.
! 185: */
! 186: memset(ih, 0, sizeof(*ih));
! 187: ih->ih_fun = ih_fun;
! 188: ih->ih_arg = ih_arg;
! 189: ih->ih_next = NULL;
! 190: ih->ih_enable = 1;
! 191: ih->ih_level = level;
! 192: ih->ih_irq = irq;
! 193: ih->ih_name = ih_name;
! 194:
! 195: if (ih_name != NULL)
! 196: evcount_attach(&ih->ih_count, ih_name, (void *)&ih->ih_irq,
! 197: &evcount_intr);
! 198: *p = ih;
! 199:
! 200: if (++eih->eih_nih == 1) {
! 201: /* Unmask interrupt */
! 202: _reg_bset_1(LANDISK_INTEN, (1 << (irq - 5)));
! 203: }
! 204:
! 205: _cpu_intr_resume(s);
! 206:
! 207: return (ih);
! 208: }
! 209:
! 210: void
! 211: extintr_disestablish(void *aux)
! 212: {
! 213: struct intrhand *ih = aux;
! 214: struct intrhand **p, *q;
! 215: struct extintr_handler *eih;
! 216: int irq;
! 217: int s;
! 218:
! 219: KDASSERT(ih != NULL);
! 220:
! 221: s = _cpu_intr_suspend();
! 222:
! 223: irq = ih->ih_irq - 5;
! 224: eih = &extintr_handler[irq];
! 225: /*
! 226: * Remove the handler from the chain.
! 227: * This is O(n^2), too.
! 228: */
! 229: for (p = &eih->eih_ih; (q = *p) != NULL && q != ih; p = &q->ih_next)
! 230: continue;
! 231: if (q == NULL)
! 232: panic("extintr_disestablish: handler not registered");
! 233:
! 234: *p = q->ih_next;
! 235:
! 236: #if 0
! 237: if (ih->ih_name != NULL)
! 238: evcount_detach(&ih->ih_count);
! 239: #endif
! 240:
! 241: free((void *)ih, M_DEVBUF);
! 242:
! 243: if (--eih->eih_nih == 0) {
! 244: intc_intr_disestablish(eih->eih_func);
! 245:
! 246: /* Mask interrupt */
! 247: _reg_bclr_1(LANDISK_INTEN, (1 << irq));
! 248: }
! 249:
! 250: _cpu_intr_resume(s);
! 251: }
! 252:
! 253: void
! 254: extintr_enable(void *aux)
! 255: {
! 256: struct intrhand *ih = aux;
! 257: struct intrhand *p, *q;
! 258: struct extintr_handler *eih;
! 259: int irq;
! 260: int cnt;
! 261: int s;
! 262:
! 263: KDASSERT(ih != NULL);
! 264:
! 265: s = _cpu_intr_suspend();
! 266:
! 267: irq = ih->ih_irq - 5;
! 268: KDASSERT(irq >= 0 && irq < 8);
! 269: eih = &extintr_handler[irq];
! 270: for (cnt = 0, p = eih->eih_ih, q = NULL; p != NULL; p = p->ih_next) {
! 271: if (p->ih_enable) {
! 272: cnt++;
! 273: }
! 274: if (p == ih) {
! 275: q = p;
! 276: p->ih_enable = 1;
! 277: }
! 278: }
! 279: KDASSERT(q != NULL);
! 280:
! 281: if (cnt == 0) {
! 282: /* Unmask interrupt */
! 283: _reg_bset_1(LANDISK_INTEN, (1 << irq));
! 284: }
! 285:
! 286: _cpu_intr_resume(s);
! 287: }
! 288:
! 289: void
! 290: extintr_disable(void *aux)
! 291: {
! 292: struct intrhand *ih = aux;
! 293: struct intrhand *p, *q;
! 294: struct extintr_handler *eih;
! 295: int irq;
! 296: int cnt;
! 297: int s;
! 298:
! 299: KDASSERT(ih != NULL);
! 300:
! 301: s = _cpu_intr_suspend();
! 302:
! 303: irq = ih->ih_irq - 5;
! 304: KDASSERT(irq >= 0 && irq < 8);
! 305: eih = &extintr_handler[irq];
! 306: for (cnt = 0, p = eih->eih_ih, q = NULL; p != NULL; p = p->ih_next) {
! 307: if (p == ih) {
! 308: q = p;
! 309: p->ih_enable = 0;
! 310: }
! 311: if (!ih->ih_enable) {
! 312: cnt++;
! 313: }
! 314: }
! 315: KDASSERT(q != NULL);
! 316:
! 317: if (cnt == 0) {
! 318: /* Mask interrupt */
! 319: _reg_bclr_1(LANDISK_INTEN, (1 << irq));
! 320: }
! 321:
! 322: _cpu_intr_resume(s);
! 323: }
! 324:
! 325: void
! 326: extintr_disable_by_num(int irq)
! 327: {
! 328: struct extintr_handler *eih;
! 329: struct intrhand *ih;
! 330: int s;
! 331:
! 332: irq -= 5;
! 333: KDASSERT(irq >= 0 && irq < 8);
! 334:
! 335: s = _cpu_intr_suspend();
! 336: eih = &extintr_handler[irq];
! 337: for (ih = eih->eih_ih; ih != NULL; ih = ih->ih_next) {
! 338: ih->ih_enable = 0;
! 339: }
! 340: /* Mask interrupt */
! 341: _reg_bclr_1(LANDISK_INTEN, (1 << irq));
! 342: _cpu_intr_resume(s);
! 343: }
! 344:
! 345: static int
! 346: fakeintr(void *arg)
! 347: {
! 348: return 0;
! 349: }
! 350:
! 351: static int
! 352: extintr_intr_handler(void *arg)
! 353: {
! 354: struct extintr_handler *eih = arg;
! 355: struct intrhand *ih;
! 356: int r;
! 357:
! 358: if (__predict_true(eih != NULL)) {
! 359: for (ih = eih->eih_ih; ih != NULL; ih = ih->ih_next) {
! 360: if (__predict_true(ih->ih_enable)) {
! 361: r = (*ih->ih_fun)(ih->ih_arg);
! 362: if (__predict_true(r != 0)) {
! 363: ih->ih_count.ec_count++;
! 364: }
! 365: }
! 366: }
! 367: return 1;
! 368: }
! 369: return 0;
! 370: }
! 371:
! 372: #ifdef DIAGNOSTIC
! 373: void
! 374: splassert_check(int wantipl, const char *func)
! 375: {
! 376: register_t sr;
! 377: int oldipl;
! 378:
! 379: __asm__ __volatile__ ("stc sr,%0" : "=r" (sr));
! 380:
! 381: oldipl = (sr & 0xf0) >> 4;
! 382: if (oldipl < wantipl) {
! 383: splassert_fail(wantipl, oldipl, func);
! 384: /*
! 385: * If the splassert_ctl is set to not panic, raise the ipl
! 386: * in a feeble attempt to reduce damage.
! 387: */
! 388: _cpu_intr_raise(wantipl << 4);
! 389: }
! 390: }
! 391: #endif
CVSweb