1 /* $OpenBSD: intr.c,v 1.29 2024/08/04 12:01:18 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2011 Dale Rahn <drahn@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/timetc.h> 21 #include <sys/malloc.h> 22 23 #include <dev/clock_subr.h> 24 #include <machine/cpu.h> 25 #include <machine/intr.h> 26 27 #include <dev/ofw/openfirm.h> 28 29 int arm_intr_get_parent(int); 30 uint32_t arm_intr_map_msi(int, uint64_t *); 31 32 void *arm_intr_prereg_establish_fdt(void *, int *, int, struct cpu_info *, 33 int (*)(void *), void *, char *); 34 void arm_intr_prereg_disestablish_fdt(void *); 35 void arm_intr_prereg_barrier_fdt(void *); 36 37 int arm_dflt_splraise(int); 38 int arm_dflt_spllower(int); 39 void arm_dflt_splx(int); 40 void arm_dflt_setipl(int); 41 42 void arm_dflt_irq(void *); 43 void arm_dflt_fiq(void *); 44 45 void arm_cpu_irq(void *); 46 void arm_cpu_fiq(void *); 47 48 #define SI_TO_IRQBIT(x) (1 << (x)) 49 uint32_t arm_smask[NIPL]; 50 51 struct arm_intr_func arm_intr_func = { 52 arm_dflt_splraise, 53 arm_dflt_spllower, 54 arm_dflt_splx, 55 arm_dflt_setipl 56 }; 57 58 void 59 arm_dflt_irq(void *frame) 60 { 61 panic("%s", __func__); 62 } 63 64 void 65 arm_dflt_fiq(void *frame) 66 { 67 panic("%s", __func__); 68 } 69 70 void (*arm_irq_dispatch)(void *) = arm_dflt_irq; 71 72 void 73 arm_cpu_irq(void *frame) 74 { 75 struct cpu_info *ci = curcpu(); 76 77 ci->ci_idepth++; 78 (*arm_irq_dispatch)(frame); 79 ci->ci_idepth--; 80 } 81 82 void (*arm_fiq_dispatch)(void *) = arm_dflt_fiq; 83 84 void 85 arm_cpu_fiq(void *frame) 86 { 87 struct cpu_info *ci = curcpu(); 88 89 ci->ci_idepth++; 90 (*arm_fiq_dispatch)(frame); 91 ci->ci_idepth--; 92 } 93 94 /* 95 * Find the interrupt parent by walking up the tree. 96 */ 97 int 98 arm_intr_get_parent(int node) 99 { 100 uint32_t phandle; 101 102 while (node) { 103 phandle = OF_getpropint(node, "interrupt-parent", 0); 104 if (phandle) 105 return OF_getnodebyphandle(phandle); 106 node = OF_parent(node); 107 if (OF_getpropbool(node, "interrupt-controller")) 108 return node; 109 } 110 111 return 0; 112 } 113 114 uint32_t 115 arm_intr_map_msi(int node, uint64_t *data) 116 { 117 uint64_t msi_base; 118 uint32_t phandle = 0; 119 uint32_t *cell; 120 uint32_t *map; 121 uint32_t mask, rid_base, rid; 122 int i, len, length, mcells, ncells; 123 124 len = OF_getproplen(node, "msi-map"); 125 if (len <= 0) { 126 while (node && !phandle) { 127 phandle = OF_getpropint(node, "msi-parent", 0); 128 node = OF_parent(node); 129 } 130 131 return phandle; 132 } 133 134 map = malloc(len, M_TEMP, M_WAITOK); 135 OF_getpropintarray(node, "msi-map", map, len); 136 137 mask = OF_getpropint(node, "msi-map-mask", 0xffff); 138 rid = *data & mask; 139 140 cell = map; 141 ncells = len / sizeof(uint32_t); 142 while (ncells > 1) { 143 node = OF_getnodebyphandle(cell[1]); 144 if (node == 0) 145 goto out; 146 147 /* 148 * Some device trees (e.g. those for the Rockchip 149 * RK3399 boards) are missing a #msi-cells property. 150 * Assume the msi-specifier uses a single cell in that 151 * case. 152 */ 153 mcells = OF_getpropint(node, "#msi-cells", 1); 154 if (ncells < mcells + 3) 155 goto out; 156 157 rid_base = cell[0]; 158 length = cell[2 + mcells]; 159 msi_base = cell[2]; 160 for (i = 1; i < mcells; i++) { 161 msi_base <<= 32; 162 msi_base |= cell[2 + i]; 163 } 164 if (rid >= rid_base && rid < rid_base + length) { 165 *data = msi_base + (rid - rid_base); 166 phandle = cell[1]; 167 break; 168 } 169 170 cell += (3 + mcells); 171 ncells -= (3 + mcells); 172 } 173 174 out: 175 free(map, M_TEMP, len); 176 return phandle; 177 } 178 179 /* 180 * Interrupt pre-registration. 181 * 182 * To allow device drivers to establish interrupt handlers before all 183 * relevant interrupt controllers have been attached, we support 184 * pre-registration of interrupt handlers. For each node in the 185 * device tree that has an "interrupt-controller" property, we 186 * register a dummy interrupt controller that simply stashes away all 187 * relevant details of the interrupt handler being established. 188 * Later, when the real interrupt controller registers itself, we 189 * establish those interrupt handlers based on that information. 190 */ 191 192 #define MAX_INTERRUPT_CELLS 4 193 194 struct intr_prereg { 195 LIST_ENTRY(intr_prereg) ip_list; 196 uint32_t ip_phandle; 197 uint32_t ip_cell[MAX_INTERRUPT_CELLS]; 198 199 int ip_level; 200 struct cpu_info *ip_ci; 201 int (*ip_func)(void *); 202 void *ip_arg; 203 char *ip_name; 204 205 struct interrupt_controller *ip_ic; 206 void *ip_ih; 207 }; 208 209 LIST_HEAD(, intr_prereg) prereg_interrupts = 210 LIST_HEAD_INITIALIZER(prereg_interrupts); 211 212 void * 213 arm_intr_prereg_establish_fdt(void *cookie, int *cell, int level, 214 struct cpu_info *ci, int (*func)(void *), void *arg, char *name) 215 { 216 struct interrupt_controller *ic = cookie; 217 struct intr_prereg *ip; 218 int i; 219 220 ip = malloc(sizeof(struct intr_prereg), M_DEVBUF, M_ZERO | M_WAITOK); 221 ip->ip_phandle = ic->ic_phandle; 222 for (i = 0; i < ic->ic_cells; i++) 223 ip->ip_cell[i] = cell[i]; 224 ip->ip_level = level; 225 ip->ip_ci = ci; 226 ip->ip_func = func; 227 ip->ip_arg = arg; 228 ip->ip_name = name; 229 LIST_INSERT_HEAD(&prereg_interrupts, ip, ip_list); 230 231 return ip; 232 } 233 234 void 235 arm_intr_prereg_disestablish_fdt(void *cookie) 236 { 237 struct intr_prereg *ip = cookie; 238 struct interrupt_controller *ic = ip->ip_ic; 239 240 if (ip->ip_ic != NULL && ip->ip_ih != NULL) 241 ic->ic_disestablish(ip->ip_ih); 242 243 if (ip->ip_ic != NULL) 244 LIST_REMOVE(ip, ip_list); 245 246 free(ip, M_DEVBUF, sizeof(*ip)); 247 } 248 249 void 250 arm_intr_prereg_barrier_fdt(void *cookie) 251 { 252 struct intr_prereg *ip = cookie; 253 struct interrupt_controller *ic = ip->ip_ic; 254 255 if (ip->ip_ic != NULL && ip->ip_ih != NULL) 256 ic->ic_barrier(ip->ip_ih); 257 } 258 259 void 260 arm_intr_init_fdt_recurse(int node) 261 { 262 struct interrupt_controller *ic; 263 264 if (OF_getproplen(node, "interrupt-controller") >= 0) { 265 ic = malloc(sizeof(struct interrupt_controller), 266 M_DEVBUF, M_ZERO | M_WAITOK); 267 ic->ic_node = node; 268 ic->ic_cookie = ic; 269 ic->ic_establish = arm_intr_prereg_establish_fdt; 270 ic->ic_disestablish = arm_intr_prereg_disestablish_fdt; 271 ic->ic_barrier = arm_intr_prereg_barrier_fdt; 272 arm_intr_register_fdt(ic); 273 } 274 275 for (node = OF_child(node); node; node = OF_peer(node)) 276 arm_intr_init_fdt_recurse(node); 277 } 278 279 void 280 arm_intr_init_fdt(void) 281 { 282 int node = OF_peer(0); 283 284 if (node) 285 arm_intr_init_fdt_recurse(node); 286 } 287 288 LIST_HEAD(, interrupt_controller) interrupt_controllers = 289 LIST_HEAD_INITIALIZER(interrupt_controllers); 290 291 void 292 arm_intr_register_fdt(struct interrupt_controller *ic) 293 { 294 struct intr_prereg *ip, *tip; 295 296 ic->ic_cells = OF_getpropint(ic->ic_node, "#interrupt-cells", 0); 297 ic->ic_phandle = OF_getpropint(ic->ic_node, "phandle", 0); 298 KASSERT(ic->ic_cells <= MAX_INTERRUPT_CELLS); 299 300 LIST_INSERT_HEAD(&interrupt_controllers, ic, ic_list); 301 302 /* Establish pre-registered interrupt handlers. */ 303 LIST_FOREACH_SAFE(ip, &prereg_interrupts, ip_list, tip) { 304 if (ip->ip_phandle != ic->ic_phandle) 305 continue; 306 307 ip->ip_ic = ic; 308 ip->ip_ih = ic->ic_establish(ic->ic_cookie, ip->ip_cell, 309 ip->ip_level, ip->ip_ci, ip->ip_func, ip->ip_arg, 310 ip->ip_name); 311 if (ip->ip_ih == NULL) 312 printf("can't establish interrupt %s\n", ip->ip_name); 313 314 LIST_REMOVE(ip, ip_list); 315 } 316 } 317 318 void * 319 arm_intr_establish_fdt(int node, int level, int (*func)(void *), 320 void *cookie, char *name) 321 { 322 return arm_intr_establish_fdt_idx(node, 0, level, func, cookie, name); 323 } 324 325 void * 326 arm_intr_establish_fdt_cpu(int node, int level, struct cpu_info *ci, 327 int (*func)(void *), void *cookie, char *name) 328 { 329 return arm_intr_establish_fdt_idx_cpu(node, 0, level, ci, func, 330 cookie, name); 331 } 332 333 void * 334 arm_intr_establish_fdt_idx(int node, int idx, int level, int (*func)(void *), 335 void *cookie, char *name) 336 { 337 return arm_intr_establish_fdt_idx_cpu(node, idx, level, NULL, func, 338 cookie, name); 339 } 340 341 void * 342 arm_intr_establish_fdt_idx_cpu(int node, int idx, int level, struct cpu_info *ci, 343 int (*func)(void *), void *cookie, char *name) 344 { 345 struct interrupt_controller *ic; 346 int i, len, ncells, parent; 347 int extended = 1; 348 uint32_t *cell, *cells, phandle; 349 struct machine_intr_handle *ih; 350 void *val = NULL; 351 352 len = OF_getproplen(node, "interrupts-extended"); 353 if (len <= 0) { 354 len = OF_getproplen(node, "interrupts"); 355 extended = 0; 356 } 357 if (len <= 0 || (len % sizeof(uint32_t) != 0)) 358 return NULL; 359 360 /* Old style. */ 361 if (!extended) { 362 parent = arm_intr_get_parent(node); 363 LIST_FOREACH(ic, &interrupt_controllers, ic_list) { 364 if (ic->ic_node == parent) 365 break; 366 } 367 368 if (ic == NULL) 369 return NULL; 370 } 371 372 cell = cells = malloc(len, M_TEMP, M_WAITOK); 373 if (extended) 374 OF_getpropintarray(node, "interrupts-extended", cells, len); 375 else 376 OF_getpropintarray(node, "interrupts", cells, len); 377 ncells = len / sizeof(uint32_t); 378 379 for (i = 0; i <= idx && ncells > 0; i++) { 380 if (extended) { 381 phandle = cell[0]; 382 383 /* Handle "empty" phandle reference. */ 384 if (phandle == 0) { 385 cell++; 386 ncells--; 387 continue; 388 } 389 390 LIST_FOREACH(ic, &interrupt_controllers, ic_list) { 391 if (ic->ic_phandle == phandle) 392 break; 393 } 394 395 if (ic == NULL) 396 break; 397 398 cell++; 399 ncells--; 400 } 401 402 if (i == idx && ncells >= ic->ic_cells && ic->ic_establish) { 403 val = ic->ic_establish(ic->ic_cookie, cell, level, 404 ci, func, cookie, name); 405 break; 406 } 407 408 cell += ic->ic_cells; 409 ncells -= ic->ic_cells; 410 } 411 412 free(cells, M_TEMP, len); 413 414 if (val == NULL) 415 return NULL; 416 417 ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK); 418 ih->ih_ic = ic; 419 ih->ih_ih = val; 420 421 return ih; 422 } 423 424 void * 425 arm_intr_establish_fdt_imap(int node, int *reg, int nreg, int level, 426 int (*func)(void *), void *cookie, char *name) 427 { 428 return arm_intr_establish_fdt_imap_cpu(node, reg, nreg, level, NULL, 429 func, cookie, name); 430 } 431 432 void * 433 arm_intr_establish_fdt_imap_cpu(int node, int *reg, int nreg, int level, 434 struct cpu_info *ci, int (*func)(void *), void *cookie, char *name) 435 { 436 struct interrupt_controller *ic; 437 struct machine_intr_handle *ih; 438 uint32_t *cell; 439 uint32_t map_mask[4], *map; 440 int len, acells, ncells; 441 void *val = NULL; 442 443 if (nreg != sizeof(map_mask)) 444 return NULL; 445 446 if (OF_getpropintarray(node, "interrupt-map-mask", map_mask, 447 sizeof(map_mask)) != sizeof(map_mask)) 448 return NULL; 449 450 len = OF_getproplen(node, "interrupt-map"); 451 if (len <= 0) 452 return NULL; 453 454 map = malloc(len, M_DEVBUF, M_WAITOK); 455 OF_getpropintarray(node, "interrupt-map", map, len); 456 457 cell = map; 458 ncells = len / sizeof(uint32_t); 459 while (ncells > 5) { 460 LIST_FOREACH(ic, &interrupt_controllers, ic_list) { 461 if (ic->ic_phandle == cell[4]) 462 break; 463 } 464 465 if (ic == NULL) 466 break; 467 468 acells = OF_getpropint(ic->ic_node, "#address-cells", 0); 469 if (ncells >= (5 + acells + ic->ic_cells) && 470 (reg[0] & map_mask[0]) == cell[0] && 471 (reg[1] & map_mask[1]) == cell[1] && 472 (reg[2] & map_mask[2]) == cell[2] && 473 (reg[3] & map_mask[3]) == cell[3] && 474 ic->ic_establish) { 475 val = ic->ic_establish(ic->ic_cookie, &cell[5 + acells], 476 level, ci, func, cookie, name); 477 break; 478 } 479 480 cell += (5 + acells + ic->ic_cells); 481 ncells -= (5 + acells + ic->ic_cells); 482 } 483 484 if (val == NULL) { 485 free(map, M_DEVBUF, len); 486 return NULL; 487 } 488 489 ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK); 490 ih->ih_ic = ic; 491 ih->ih_ih = val; 492 493 free(map, M_DEVBUF, len); 494 return ih; 495 } 496 497 void * 498 arm_intr_establish_fdt_msi(int node, uint64_t *addr, uint64_t *data, 499 int level, int (*func)(void *), void *cookie, char *name) 500 { 501 return arm_intr_establish_fdt_msi_cpu(node, addr, data, level, NULL, 502 func, cookie, name); 503 } 504 505 void * 506 arm_intr_establish_fdt_msi_cpu(int node, uint64_t *addr, uint64_t *data, 507 int level, struct cpu_info *ci, int (*func)(void *), void *cookie, 508 char *name) 509 { 510 struct interrupt_controller *ic; 511 struct machine_intr_handle *ih; 512 uint32_t phandle; 513 void *val = NULL; 514 515 phandle = arm_intr_map_msi(node, data); 516 LIST_FOREACH(ic, &interrupt_controllers, ic_list) { 517 if (ic->ic_phandle == phandle) 518 break; 519 } 520 521 if (ic == NULL || ic->ic_establish_msi == NULL) 522 return NULL; 523 524 val = ic->ic_establish_msi(ic->ic_cookie, addr, data, 525 level, ci, func, cookie, name); 526 527 ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK); 528 ih->ih_ic = ic; 529 ih->ih_ih = val; 530 531 return ih; 532 } 533 534 void 535 arm_intr_disestablish_fdt(void *cookie) 536 { 537 struct machine_intr_handle *ih = cookie; 538 struct interrupt_controller *ic = ih->ih_ic; 539 540 ic->ic_disestablish(ih->ih_ih); 541 free(ih, M_DEVBUF, sizeof(*ih)); 542 } 543 544 void 545 arm_intr_enable(void *cookie) 546 { 547 struct machine_intr_handle *ih = cookie; 548 struct interrupt_controller *ic = ih->ih_ic; 549 550 KASSERT(ic->ic_enable != NULL); 551 ic->ic_enable(ih->ih_ih); 552 } 553 554 void 555 arm_intr_disable(void *cookie) 556 { 557 struct machine_intr_handle *ih = cookie; 558 struct interrupt_controller *ic = ih->ih_ic; 559 560 KASSERT(ic->ic_disable != NULL); 561 ic->ic_disable(ih->ih_ih); 562 } 563 564 /* 565 * Some interrupt controllers transparently forward interrupts to 566 * their parent. Such interrupt controllers can use this function to 567 * delegate the interrupt handler to their parent. 568 */ 569 void * 570 arm_intr_parent_establish_fdt(void *cookie, int *cell, int level, 571 struct cpu_info *ci, int (*func)(void *), void *arg, char *name) 572 { 573 struct interrupt_controller *ic = cookie; 574 struct machine_intr_handle *ih; 575 int parent; 576 void *val; 577 578 parent = arm_intr_get_parent(ic->ic_node); 579 LIST_FOREACH(ic, &interrupt_controllers, ic_list) { 580 if (ic->ic_node == parent) 581 break; 582 } 583 if (ic == NULL) 584 return NULL; 585 586 val = ic->ic_establish(ic->ic_cookie, cell, level, ci, func, arg, name); 587 if (val == NULL) 588 return NULL; 589 590 ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK); 591 ih->ih_ic = ic; 592 ih->ih_ih = val; 593 594 return ih; 595 } 596 597 void 598 arm_intr_parent_disestablish_fdt(void *cookie) 599 { 600 struct machine_intr_handle *ih = cookie; 601 struct interrupt_controller *ic = ih->ih_ic; 602 603 ic->ic_disestablish(ih->ih_ih); 604 free(ih, M_DEVBUF, sizeof(*ih)); 605 } 606 607 void 608 arm_intr_route(void *cookie, int enable, struct cpu_info *ci) 609 { 610 struct machine_intr_handle *ih = cookie; 611 struct interrupt_controller *ic = ih->ih_ic; 612 613 if (ic->ic_route) 614 ic->ic_route(ih->ih_ih, enable, ci); 615 } 616 617 void 618 arm_intr_cpu_enable(void) 619 { 620 struct interrupt_controller *ic; 621 622 LIST_FOREACH(ic, &interrupt_controllers, ic_list) 623 if (ic->ic_cpu_enable) 624 ic->ic_cpu_enable(); 625 } 626 627 int 628 arm_dflt_splraise(int newcpl) 629 { 630 struct cpu_info *ci = curcpu(); 631 int oldcpl; 632 633 oldcpl = ci->ci_cpl; 634 635 if (newcpl < oldcpl) 636 newcpl = oldcpl; 637 638 ci->ci_cpl = newcpl; 639 640 return oldcpl; 641 } 642 643 int 644 arm_dflt_spllower(int newcpl) 645 { 646 struct cpu_info *ci = curcpu(); 647 int oldcpl; 648 649 oldcpl = ci->ci_cpl; 650 651 splx(newcpl); 652 653 return oldcpl; 654 } 655 656 void 657 arm_dflt_splx(int newcpl) 658 { 659 struct cpu_info *ci = curcpu(); 660 661 if (ci->ci_ipending & arm_smask[newcpl]) 662 arm_do_pending_intr(newcpl); 663 ci->ci_cpl = newcpl; 664 } 665 666 void 667 arm_dflt_setipl(int newcpl) 668 { 669 struct cpu_info *ci = curcpu(); 670 671 ci->ci_cpl = newcpl; 672 } 673 674 void 675 arm_do_pending_intr(int pcpl) 676 { 677 struct cpu_info *ci = curcpu(); 678 u_long oldirqstate; 679 680 oldirqstate = intr_disable(); 681 682 #define DO_SOFTINT(si, ipl) \ 683 if ((ci->ci_ipending & arm_smask[pcpl]) & \ 684 SI_TO_IRQBIT(si)) { \ 685 ci->ci_ipending &= ~SI_TO_IRQBIT(si); \ 686 arm_intr_func.setipl(ipl); \ 687 intr_restore(oldirqstate); \ 688 softintr_dispatch(si); \ 689 oldirqstate = intr_disable(); \ 690 } 691 692 do { 693 DO_SOFTINT(SIR_TTY, IPL_SOFTTTY); 694 DO_SOFTINT(SIR_NET, IPL_SOFTNET); 695 DO_SOFTINT(SIR_CLOCK, IPL_SOFTCLOCK); 696 DO_SOFTINT(SIR_SOFT, IPL_SOFT); 697 } while (ci->ci_ipending & arm_smask[pcpl]); 698 699 /* Don't use splx... we are here already! */ 700 arm_intr_func.setipl(pcpl); 701 intr_restore(oldirqstate); 702 } 703 704 void 705 arm_set_intr_handler(int (*raise)(int), int (*lower)(int), 706 void (*x)(int), void (*setipl)(int), void (*irq_dispatch)(void *), 707 void (*fiq_dispatch)(void *), void (*enable_wakeup)(void), 708 void (*disable_wakeup)(void)) 709 { 710 arm_intr_func.raise = raise; 711 arm_intr_func.lower = lower; 712 arm_intr_func.x = x; 713 arm_intr_func.setipl = setipl; 714 arm_intr_func.enable_wakeup = enable_wakeup; 715 arm_intr_func.disable_wakeup = disable_wakeup; 716 717 if (irq_dispatch) 718 arm_irq_dispatch = irq_dispatch; 719 if (fiq_dispatch) 720 arm_fiq_dispatch = fiq_dispatch; 721 } 722 723 void 724 arm_init_smask(void) 725 { 726 static int inited = 0; 727 int i; 728 729 if (inited) 730 return; 731 inited = 1; 732 733 for (i = IPL_NONE; i <= IPL_HIGH; i++) { 734 arm_smask[i] = 0; 735 if (i < IPL_SOFT) 736 arm_smask[i] |= SI_TO_IRQBIT(SIR_SOFT); 737 if (i < IPL_SOFTCLOCK) 738 arm_smask[i] |= SI_TO_IRQBIT(SIR_CLOCK); 739 if (i < IPL_SOFTNET) 740 arm_smask[i] |= SI_TO_IRQBIT(SIR_NET); 741 if (i < IPL_SOFTTTY) 742 arm_smask[i] |= SI_TO_IRQBIT(SIR_TTY); 743 } 744 } 745 746 /* provide functions for asm */ 747 #undef splraise 748 #undef spllower 749 #undef splx 750 751 int 752 splraise(int ipl) 753 { 754 return arm_intr_func.raise(ipl); 755 } 756 757 int _spllower(int ipl); /* XXX - called from asm? */ 758 int 759 _spllower(int ipl) 760 { 761 return arm_intr_func.lower(ipl); 762 } 763 int 764 spllower(int ipl) 765 { 766 return arm_intr_func.lower(ipl); 767 } 768 769 void 770 splx(int ipl) 771 { 772 arm_intr_func.x(ipl); 773 } 774 775 776 #ifdef DIAGNOSTIC 777 void 778 arm_splassert_check(int wantipl, const char *func) 779 { 780 int oldipl = curcpu()->ci_cpl; 781 782 if (oldipl < wantipl) { 783 splassert_fail(wantipl, oldipl, func); 784 /* 785 * If the splassert_ctl is set to not panic, raise the ipl 786 * in a feeble attempt to reduce damage. 787 */ 788 arm_intr_func.setipl(wantipl); 789 } 790 791 if (wantipl == IPL_NONE && curcpu()->ci_idepth != 0) { 792 splassert_fail(-1, curcpu()->ci_idepth, func); 793 } 794 } 795 #endif 796 797 void arm_dflt_delay(u_int usecs); 798 799 struct { 800 void (*delay)(u_int); 801 void (*initclocks)(void); 802 void (*setstatclockrate)(int); 803 void (*mpstartclock)(void); 804 } arm_clock_func = { 805 arm_dflt_delay, 806 NULL, 807 NULL, 808 NULL 809 }; 810 811 void 812 arm_clock_register(void (*initclock)(void), void (*delay)(u_int), 813 void (*statclock)(int), void(*mpstartclock)(void)) 814 { 815 if (arm_clock_func.initclocks) 816 return; 817 818 arm_clock_func.initclocks = initclock; 819 arm_clock_func.delay = delay; 820 arm_clock_func.setstatclockrate = statclock; 821 arm_clock_func.mpstartclock = mpstartclock; 822 } 823 824 825 void 826 delay(u_int usec) 827 { 828 arm_clock_func.delay(usec); 829 } 830 831 void 832 cpu_initclocks(void) 833 { 834 if (arm_clock_func.initclocks == NULL) 835 panic("initclocks function not initialized yet"); 836 837 arm_clock_func.initclocks(); 838 } 839 840 void 841 cpu_startclock(void) 842 { 843 if (arm_clock_func.mpstartclock == NULL) 844 panic("startclock function not initialized yet"); 845 846 arm_clock_func.mpstartclock(); 847 } 848 849 void 850 arm_dflt_delay(u_int usecs) 851 { 852 int j; 853 /* BAH - there is no good way to make this close */ 854 /* but this isn't supposed to be used after the real clock attaches */ 855 for (; usecs > 0; usecs--) 856 for (j = 100; j > 0; j--) 857 ; 858 859 } 860 861 void 862 setstatclockrate(int new) 863 { 864 if (arm_clock_func.setstatclockrate == NULL) { 865 panic("arm_clock_func.setstatclockrate not initialized"); 866 } 867 arm_clock_func.setstatclockrate(new); 868 } 869 870 void 871 intr_barrier(void *cookie) 872 { 873 struct machine_intr_handle *ih = cookie; 874 struct interrupt_controller *ic = ih->ih_ic; 875 876 ic->ic_barrier(ih->ih_ih); 877 } 878 879 void 880 intr_set_wakeup(void *cookie) 881 { 882 struct machine_intr_handle *ih = cookie; 883 struct interrupt_controller *ic = ih->ih_ic; 884 885 if (ic->ic_set_wakeup) 886 ic->ic_set_wakeup(ih->ih_ih); 887 } 888 889 void 890 intr_enable_wakeup(void) 891 { 892 if (arm_intr_func.enable_wakeup) 893 arm_intr_func.enable_wakeup(); 894 } 895 896 void 897 intr_disable_wakeup(void) 898 { 899 if (arm_intr_func.disable_wakeup) 900 arm_intr_func.disable_wakeup(); 901 } 902 903 /* 904 * IPI implementation 905 */ 906 907 void arm_no_send_ipi(struct cpu_info *ci, int id); 908 void (*intr_send_ipi_func)(struct cpu_info *, int) = arm_no_send_ipi; 909 910 void 911 arm_send_ipi(struct cpu_info *ci, int id) 912 { 913 (*intr_send_ipi_func)(ci, id); 914 } 915 916 void 917 arm_no_send_ipi(struct cpu_info *ci, int id) 918 { 919 panic("arm_send_ipi() called: no ipi function"); 920 } 921