1 /* $NetBSD: interrupt.c,v 1.2 2002/04/28 17:10:38 uch Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 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 #include <sys/param.h> 40 #include <sys/malloc.h> 41 42 #include <uvm/uvm_extern.h> /* uvmexp.intrs */ 43 44 #include <net/netisr.h> 45 46 #include <sh3/exception.h> 47 #include <sh3/clock.h> 48 #include <sh3/intcreg.h> 49 #include <sh3/tmureg.h> 50 #include <machine/intr.h> 51 52 void intc_intr_priority(int, int); 53 struct intc_intrhand *intc_alloc_ih(void); 54 void intc_free_ih(struct intc_intrhand *); 55 int intc_unknown_intr(void *); 56 void netintr(void); 57 void tmu1_oneshot(void); 58 int tmu1_intr(void *); 59 void tmu2_oneshot(void); 60 int tmu2_intr(void *); 61 /* 62 * EVTCODE to intc_intrhand mapper. 63 * max #60 is SH7709_INTEVT2_ADC_ADI (0x980) 64 */ 65 int8_t __intc_evtcode_to_ih[64]; 66 67 struct intc_intrhand __intc_intrhand[_INTR_N + 1] = { 68 /* Place holder interrupt handler for unregistered interrupt. */ 69 [0] = { .ih_func = intc_unknown_intr, .ih_level = 0xf0 } 70 }; 71 72 struct sh_soft_intr sh_soft_intrs[_IPL_NSOFT]; 73 struct sh_soft_intrhand *softnet_intrhand; 74 75 /* 76 * SH INTC support. 77 */ 78 void 79 intc_init() 80 { 81 82 switch (cpu_product) { 83 case CPU_PRODUCT_7709: 84 case CPU_PRODUCT_7709A: 85 _reg_write_2(SH7709_IPRC, 0); 86 _reg_write_2(SH7709_IPRD, 0); 87 _reg_write_2(SH7709_IPRE, 0); 88 /* FALLTHROUGH */ 89 case CPU_PRODUCT_7708: 90 case CPU_PRODUCT_7708S: 91 case CPU_PRODUCT_7708R: 92 _reg_write_2(SH3_IPRA, 0); 93 _reg_write_2(SH3_IPRB, 0); 94 break; 95 case CPU_PRODUCT_7750S: 96 _reg_write_2(SH4_IPRD, 0); 97 /* FALLTHROUGH */ 98 case CPU_PRODUCT_7750: 99 _reg_write_2(SH4_IPRA, 0); 100 _reg_write_2(SH4_IPRB, 0); 101 _reg_write_2(SH4_IPRC, 0); 102 break; 103 } 104 } 105 106 void * 107 intc_intr_establish(int evtcode, int trigger, int level, 108 int (*ih_func)(void *), void *ih_arg) 109 { 110 struct intc_intrhand *ih; 111 112 KDASSERT(evtcode >= 0x200 && level > 0); 113 114 ih = intc_alloc_ih(); 115 ih->ih_func = ih_func; 116 ih->ih_arg = ih_arg; 117 ih->ih_level = level << 4; /* convert to SR.IMASK format. */ 118 ih->ih_evtcode = evtcode; 119 120 /* Map interrupt handler */ 121 EVTCODE_TO_IH_INDEX(evtcode) = ih->ih_idx; 122 123 /* Priority */ 124 intc_intr_priority(evtcode, level); 125 126 /* Sense select (SH7709, SH7709A only) XXX notyet */ 127 128 return (ih); 129 } 130 131 void 132 intc_intr_disestablish(void *arg) 133 { 134 struct intc_intrhand *ih = arg; 135 int evtcode = ih->ih_evtcode; 136 137 /* Mask interrupt if IPR can manage it. if not, cascated ICU will do */ 138 intc_intr_priority(evtcode, 0); 139 140 /* Unmap interrupt handler */ 141 EVTCODE_TO_IH_INDEX(evtcode) = 0; 142 143 intc_free_ih(ih); 144 } 145 146 /* 147 * void intc_intr_priority(int evtcode, int level) 148 * Setup interrupt priority register. 149 * SH7708, SH7708S, SH7708R, SH7750, SH7750S ... evtcode is INTEVT 150 * SH7709, SH7709A ... evtcode is INTEVT2 151 */ 152 void 153 intc_intr_priority(int evtcode, int level) 154 { 155 #define SET_LEVEL(r, pos, level) \ 156 r = (r & ~(0xf << (pos))) | (level << (pos)) 157 #define __SH_IPR(sh, x, pos, level) \ 158 do { \ 159 r = _reg_read_2(SH ## sh ## _IPR ## x); \ 160 SET_LEVEL(r, pos, level); \ 161 _reg_write_2(SH ## sh ## _IPR ## x, r); \ 162 } while (/*CONSTCOND*/0) 163 #define SH3_IPR(x, pos, level) __SH_IPR(3, x, pos, level) 164 #define SH4_IPR(x, pos, level) __SH_IPR(4, x, pos, level) 165 #define SH7709_IPR(x, pos, level) __SH_IPR(7709, x, pos, level) 166 #define SH_IPR(x, pos, level) \ 167 do { \ 168 if (CPU_IS_SH3) \ 169 SH3_IPR(x, pos, level); \ 170 else \ 171 SH4_IPR(x, pos, level); \ 172 } while (/*CONSTCOND*/0) 173 174 u_int16_t r; 175 176 switch (evtcode) { 177 case SH_INTEVT_TMU0_TUNI0: 178 SH_IPR(A, 12, level); 179 break; 180 case SH_INTEVT_TMU1_TUNI1: 181 SH_IPR(A, 8, level); 182 break; 183 case SH_INTEVT_TMU2_TUNI2: 184 SH_IPR(A, 4, level); 185 break; 186 case SH_INTEVT_SCI_ERI: 187 case SH_INTEVT_SCI_RXI: 188 case SH_INTEVT_SCI_TXI: 189 case SH_INTEVT_SCI_TEI: 190 SH_IPR(B, 4, level); 191 break; 192 case SH7709_INTEVT2_SCIF_ERI: 193 case SH7709_INTEVT2_SCIF_RXI: 194 case SH7709_INTEVT2_SCIF_BRI: 195 case SH7709_INTEVT2_SCIF_TXI: 196 SH7709_IPR(E, 4, level); 197 break; 198 case SH7709_INTEVT2_IRQ4: 199 SH7709_IPR(D, 0, level); 200 break; 201 case SH4_INTEVT_SCIF_ERI: 202 case SH4_INTEVT_SCIF_RXI: 203 case SH4_INTEVT_SCIF_BRI: 204 case SH4_INTEVT_SCIF_TXI: 205 SH4_IPR(C, 4, level); 206 break; 207 } 208 } 209 210 /* 211 * Interrupt handler holder allocater. 212 */ 213 struct intc_intrhand * 214 intc_alloc_ih() 215 { 216 /* #0 is reserved for unregistered interrupt. */ 217 struct intc_intrhand *ih = &__intc_intrhand[1]; 218 int i; 219 220 for (i = 1; i <= _INTR_N; i++, ih++) 221 if (ih->ih_idx == 0) { /* no driver use this. */ 222 ih->ih_idx = i; /* register myself */ 223 return (ih); 224 } 225 226 panic("increase _INTR_N greater than %d\n", _INTR_N); 227 return (NULL); 228 } 229 230 void 231 intc_free_ih(struct intc_intrhand *ih) 232 { 233 234 memset(ih, 0, sizeof(*ih)); 235 } 236 237 /* Place-holder for debugging */ 238 int 239 intc_unknown_intr(void *arg) 240 { 241 242 printf("INTEVT=0x%x", _reg_read_4(SH_(INTEVT))); 243 if (cpu_product == CPU_PRODUCT_7709 || cpu_product == CPU_PRODUCT_7709A) 244 printf(" INTEVT2=0x%x", _reg_read_4(SH7709_INTEVT2)); 245 printf("\n"); 246 247 panic("unknown interrupt"); 248 /* NOTREACHED */ 249 return (0); 250 } 251 252 /* 253 * Software interrupt support 254 */ 255 void 256 softintr_init() 257 { 258 static const char *softintr_names[] = IPL_SOFTNAMES; 259 struct sh_soft_intr *asi; 260 int i; 261 262 for (i = 0; i < _IPL_NSOFT; i++) { 263 asi = &sh_soft_intrs[i]; 264 TAILQ_INIT(&asi->softintr_q); 265 266 asi->softintr_ipl = IPL_SOFT + i; 267 simple_lock_init(&asi->softintr_slock); 268 evcnt_attach_dynamic(&asi->softintr_evcnt, EVCNT_TYPE_INTR, 269 NULL, "soft", softintr_names[i]); 270 } 271 272 /* XXX Establish legacy soft interrupt handlers. */ 273 softnet_intrhand = softintr_establish(IPL_SOFTNET, 274 (void (*)(void *))netintr, NULL); 275 KDASSERT(softnet_intrhand != NULL); 276 277 intc_intr_establish(SH_INTEVT_TMU1_TUNI1, IST_LEVEL, IPL_SOFT, 278 tmu1_intr, NULL); 279 intc_intr_establish(SH_INTEVT_TMU2_TUNI2, IST_LEVEL, IPL_SOFTNET, 280 tmu2_intr, NULL); 281 } 282 283 void 284 softintr_dispatch(int ipl) 285 { 286 struct sh_soft_intr *asi; 287 struct sh_soft_intrhand *sih; 288 int s; 289 290 s = _cpu_intr_suspend(); 291 292 asi = &sh_soft_intrs[ipl - IPL_SOFT]; 293 294 if (TAILQ_FIRST(&asi->softintr_q) != NULL) 295 asi->softintr_evcnt.ev_count++; 296 297 while ((sih = TAILQ_FIRST(&asi->softintr_q)) != NULL) { 298 TAILQ_REMOVE(&asi->softintr_q, sih, sih_q); 299 sih->sih_pending = 0; 300 301 uvmexp.softs++; 302 303 _cpu_intr_resume(s); 304 (*sih->sih_fn)(sih->sih_arg); 305 s = _cpu_intr_suspend(); 306 } 307 308 _cpu_intr_resume(s); 309 } 310 311 void 312 setsoft(int ipl) 313 { 314 315 if (ipl < IPL_SOFTNET) 316 tmu1_oneshot(); 317 else 318 tmu2_oneshot(); 319 } 320 321 /* Register a software interrupt handler. */ 322 void * 323 softintr_establish(int ipl, void (*func)(void *), void *arg) 324 { 325 struct sh_soft_intr *asi; 326 struct sh_soft_intrhand *sih; 327 int s; 328 329 if (__predict_false(ipl >= (IPL_SOFT + _IPL_NSOFT) || 330 ipl < IPL_SOFT)) 331 panic("softintr_establish"); 332 333 sih = malloc(sizeof(*sih), M_DEVBUF, M_NOWAIT); 334 335 s = _cpu_intr_suspend(); 336 asi = &sh_soft_intrs[ipl - IPL_SOFT]; 337 if (__predict_true(sih != NULL)) { 338 sih->sih_intrhead = asi; 339 sih->sih_fn = func; 340 sih->sih_arg = arg; 341 sih->sih_pending = 0; 342 } 343 _cpu_intr_resume(s); 344 345 return (sih); 346 } 347 348 /* Unregister a software interrupt handler. */ 349 void 350 softintr_disestablish(void *arg) 351 { 352 struct sh_soft_intrhand *sih = arg; 353 struct sh_soft_intr *asi = sih->sih_intrhead; 354 int s; 355 356 s = _cpu_intr_suspend(); 357 if (sih->sih_pending) { 358 TAILQ_REMOVE(&asi->softintr_q, sih, sih_q); 359 sih->sih_pending = 0; 360 } 361 _cpu_intr_resume(s); 362 363 free(sih, M_DEVBUF); 364 } 365 366 /* 367 * Software (low priority) network interrupt. i.e. softnet(). 368 */ 369 void 370 netintr() 371 { 372 #define DONETISR(bit, fn) \ 373 do { \ 374 if (n & (1 << bit)) \ 375 fn(); \ 376 } while (/*CONSTCOND*/0) 377 378 int s, n; 379 380 s = splnet(); 381 n = netisr; 382 netisr = 0; 383 splx(s); 384 #include <net/netisr_dispatch.h> 385 386 #undef DONETISR 387 } 388 389 /* 390 * Software interrupt is simulated with TMU one-shot timer. 391 */ 392 void 393 tmu1_oneshot() 394 { 395 396 _reg_write_4(SH_(TCNT1), 0); 397 _reg_write_1(SH_(TSTR), _reg_read_1(SH_(TSTR)) | TSTR_STR1); 398 } 399 400 int 401 tmu1_intr(void *arg) 402 { 403 404 _reg_write_1(SH_(TSTR), _reg_read_1(SH_(TSTR)) & ~TSTR_STR1); 405 _reg_write_2(SH_(TCR1), _reg_read_2(SH_(TCR1)) & ~TCR_UNF); 406 407 softintr_dispatch(IPL_SOFTCLOCK); 408 softintr_dispatch(IPL_SOFT); 409 410 return (0); 411 } 412 413 void 414 tmu2_oneshot() 415 { 416 417 _reg_write_4(SH_(TCNT2), 0); 418 _reg_write_1(SH_(TSTR), _reg_read_1(SH_(TSTR)) | TSTR_STR2); 419 } 420 421 int 422 tmu2_intr(void *arg) 423 { 424 425 _reg_write_1(SH_(TSTR), _reg_read_1(SH_(TSTR)) & ~TSTR_STR2); 426 _reg_write_2(SH_(TCR2), _reg_read_2(SH_(TCR2)) & ~TCR_UNF); 427 428 softintr_dispatch(IPL_SOFTSERIAL); 429 softintr_dispatch(IPL_SOFTNET); 430 431 return (0); 432 } 433