Home | History | Annotate | Line # | Download | only in hpcsh
      1 /*	$NetBSD: machdep.c,v 1.81 2026/04/08 04:06:40 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2001, 2002, 2004 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.81 2026/04/08 04:06:40 thorpej Exp $");
     31 
     32 #include "opt_md.h"
     33 #include "opt_ddb.h"
     34 #include "opt_kgdb.h"
     35 #include "opt_modular.h"
     36 #include "biconsdev.h"
     37 #include "debug_hpc.h"
     38 #include "hd64465if.h"
     39 
     40 #include "opt_kloader.h"
     41 #include "opt_kloader_kernel_path.h"
     42 
     43 #include <sys/param.h>
     44 #include <sys/systm.h>
     45 #include <sys/kernel.h>
     46 #include <sys/device.h>
     47 #include <sys/lwp.h>
     48 
     49 #include <sys/reboot.h>
     50 #include <sys/mount.h>
     51 #include <sys/sysctl.h>
     52 #include <sys/kcore.h>
     53 #include <sys/boot_flag.h>
     54 #include <sys/ksyms.h>
     55 #include <sys/module.h>
     56 #include <sys/cpu.h>
     57 
     58 #include <uvm/uvm_extern.h>
     59 
     60 #include <ufs/mfs/mfs_extern.h>		/* mfs_initminiroot() */
     61 
     62 #include <sh3/cpu.h>
     63 #include <sh3/exception.h>
     64 #include <sh3/cache.h>
     65 #include <sh3/clock.h>
     66 #include <sh3/intcreg.h>
     67 #include <sh3/proc.h>
     68 
     69 #ifdef KGDB
     70 #include <sys/kgdb.h>
     71 #endif
     72 
     73 #include "ksyms.h"
     74 
     75 #if NKSYMS || defined(MODULAR) || defined(DDB) || defined(KGDB)
     76 #include <machine/db_machdep.h>
     77 #include <ddb/db_sym.h>
     78 #include <ddb/db_extern.h>
     79 #include <sys/exec_elf.h>
     80 #endif /* NKSYMS || MODULAR || DDB || KGDB */
     81 
     82 #include <dev/cons.h> /* consdev */
     83 #include <dev/md.h>
     84 
     85 #include <machine/bootinfo.h>
     86 #include <machine/platid.h>
     87 #include <machine/platid_mask.h>
     88 #ifdef KLOADER
     89 #include <machine/kloader.h>
     90 #endif
     91 #include <machine/autoconf.h>		/* makebootdev() */
     92 #include <machine/intr.h>
     93 #include <machine/pcb.h>
     94 
     95 #include <nfs/rpcv2.h>
     96 #include <nfs/nfsproto.h>
     97 #include <nfs/nfs.h>
     98 #include <nfs/nfsmount.h>
     99 
    100 #include <dev/hpc/apm/apmvar.h>
    101 
    102 #include <hpcsh/dev/hd6446x/hd6446xintcvar.h>
    103 #include <hpcsh/dev/hd6446x/hd6446xintcreg.h>
    104 #include <hpcsh/dev/hd64465/hd64465var.h>
    105 
    106 #ifdef DEBUG
    107 #define	DPRINTF_ENABLE
    108 #define	DPRINTF_DEBUG	machdep_debug
    109 #endif /* DEBUG */
    110 #include <machine/debug.h>
    111 
    112 /*
    113  * D-RAM location (Windows CE machine specific)
    114  *
    115  * Jornada 690 (32MB model) SH7709A
    116  *  + SH7709A split CS3 to 2 banks.
    117  *
    118  * CS3 (0x0c000000-0x0fffffff
    119  * 0x0c000000 --- onboard   16MByte
    120  * 0x0d000000 --- onboard   16MByte (shadow)
    121  * 0x0e000000 --- extension 16MByte
    122  * 0x0f000000 --- extension 16MByte (shadow)
    123  *
    124  * PERSONA HPW-650PA (16MB model) SH7750
    125  * SH7750
    126  *
    127  * CS3 (0x0c000000-0x0fffffff
    128  * 0x0c000000 --- onboard   16MByte
    129  * 0x0d000000 --- onboard   16MByte (shadow)
    130  * 0x0e000000 --- onboard   16MByte (shadow)
    131  * 0x0f000000 --- onboard   16MByte (shadow)
    132  */
    133 
    134 #define	SH_CS3_START			0x0c000000
    135 #define	SH_CS3_END			(SH_CS3_START + 0x04000000)
    136 
    137 #define	SH7709_CS3_BANK0_START		0x0c000000
    138 #define	SH7709_CS3_BANK0_END		(SH7709_CS3_BANK0_START + 0x02000000)
    139 #define	SH7709_CS3_BANK1_START		0x0e000000
    140 #define	SH7709_CS3_BANK1_END		(SH7709_CS3_BANK1_START + 0x02000000)
    141 
    142 /* Machine */
    143 char machine[]		= MACHINE;
    144 char machine_arch[]	= MACHINE_ARCH;
    145 
    146 /* Physical memory */
    147 static int	mem_cluster_init(paddr_t);
    148 static void	mem_cluster_load(void);
    149 static void	__find_dram_shadow(paddr_t, paddr_t);
    150 #ifdef NARLY_MEMORY_PROBE
    151 static int	__check_dram(paddr_t, paddr_t);
    152 #endif
    153 int		mem_cluster_cnt;
    154 phys_ram_seg_t	mem_clusters[VM_PHYSSEG_MAX];
    155 
    156 /* bootinfo */
    157 static struct bootinfo bootinfo_storage;
    158 struct bootinfo *bootinfo = &bootinfo_storage;
    159 
    160 /* hpcapm: machine_sleep() */
    161 void (*__sleep_func)(void *);	/* model dependent sleep function holder */
    162 void *__sleep_ctx;
    163 
    164 extern void main(void) __attribute__((__noreturn__));
    165 void machine_startup(int, char *[], struct bootinfo *)
    166 	__attribute__((__noreturn__));
    167 
    168 #ifdef KLOADER
    169 #if !defined(KLOADER_KERNEL_PATH)
    170 #define KLOADER_KERNEL_PATH	"/netbsd"
    171 #endif /* !KLOADER_KERNEL_PATH */
    172 static const char kernel_path[] = KLOADER_KERNEL_PATH;
    173 #endif /* KLOADER */
    174 
    175 void
    176 machine_startup(int argc, char *argv[], struct bootinfo *bi)
    177 {
    178 	extern char edata[], end[];
    179 	vaddr_t kernend;
    180 	size_t symbolsize;
    181 	int i;
    182 	char *p;
    183 
    184 #ifdef KLOADER
    185 	/*
    186 	 * this routines stack is never polluted since stack pointer
    187 	 * is lower than kernel text segment, and at exiting, stack pointer
    188 	 * is changed to proc0.
    189 	 */
    190 	struct kloader_bootinfo kbi;
    191 #endif
    192 
    193 	/* Symbol table size */
    194 	symbolsize = 0;
    195 #if NKSYMS || defined(MODULAR) || defined(DDB) || defined(KGDB)
    196 	if (memcmp(&end, ELFMAG, SELFMAG) == 0) {
    197 		Elf_Ehdr *eh = (void *)end;
    198 		Elf_Shdr *sh = (void *)(end + eh->e_shoff);
    199 		for(i = 0; i < eh->e_shnum; i++, sh++)
    200 			if (sh->sh_offset > 0 &&
    201 			    (sh->sh_offset + sh->sh_size) > symbolsize)
    202 				symbolsize = sh->sh_offset + sh->sh_size;
    203 	}
    204 #endif
    205 
    206 	/* Clear BSS */
    207 	memset(edata, 0, end - edata);
    208 
    209 	/* Setup bootinfo */
    210 	memcpy(&bootinfo_storage, bi, sizeof(struct bootinfo));
    211 	if (bootinfo->magic == BOOTINFO_MAGIC) {
    212 		platid.dw.dw0 = bootinfo->platid_cpu;
    213 		platid.dw.dw1 = bootinfo->platid_machine;
    214 	}
    215 
    216 	/* CPU initialize */
    217 	if (platid_match(&platid, &platid_mask_CPU_SH_3))
    218 		sh_cpu_init(CPU_ARCH_SH3, CPU_PRODUCT_7709A);
    219 	else if (platid_match(&platid, &platid_mask_CPU_SH_4))
    220 		sh_cpu_init(CPU_ARCH_SH4, CPU_PRODUCT_7750);
    221 
    222 #ifndef RTC_OFFSET
    223 	/*
    224 	 * rtc_offset from bootinfo.timezone set by hpcboot.exe
    225 	 */
    226 	if (rtc_offset == 0
    227 	    && bootinfo->timezone > (-12*60)
    228 	    && bootinfo->timezone <= (12*60))
    229 		rtc_offset = bootinfo->timezone;
    230 #endif
    231 
    232 	/* Start to determine heap area */
    233 	kernend = (vaddr_t)sh3_round_page(end + symbolsize);
    234 
    235 	/* Setup bootstrap options */
    236 	makebootdev("wd0"); /* default boot device */
    237 	boothowto = 0;
    238 	for (i = 1; i < argc; i++) { /* skip 1st arg (kernel name). */
    239 		char *cp = argv[i];
    240 		switch (*cp) {
    241 		case 'b':
    242 			/* boot device: -b=sd0 etc. */
    243 			p = cp + 2;
    244 			if (strcmp(p, "nfs") == 0)
    245 				rootfstype = MOUNT_NFS;
    246 			else
    247 				makebootdev(p);
    248 			break;
    249 		default:
    250 			BOOT_FLAG(*cp, boothowto);
    251 			break;
    252 		}
    253 	}
    254 
    255 	/*
    256 	 * Check to see if a mini-root was loaded into memory. It resides
    257 	 * at the start of the next page just after the end of BSS.
    258 	 */
    259 	if (boothowto & RB_MINIROOT) {
    260 		size_t fssz;
    261 		fssz = sh3_round_page(mfs_initminiroot((void *)kernend));
    262 #ifdef MEMORY_DISK_DYNAMIC
    263 		md_root_setconf((void *)kernend, fssz);
    264 #endif
    265 		kernend += fssz;
    266 	}
    267 
    268 	/* Console */
    269 	consinit();
    270 #ifdef HPC_DEBUG_LCD
    271 	dbg_lcd_test();
    272 #endif
    273 
    274 #ifdef KLOADER
    275 	/* copy boot parameter for kloader */
    276 	kloader_bootinfo_set(&kbi, argc, argv, bootinfo, true);
    277 #endif
    278 
    279 	/* Find memory cluster. and load to UVM */
    280 	physmem = mem_cluster_init(SH3_P1SEG_TO_PHYS(kernend));
    281 	_DPRINTF("total memory = %dMbyte\n", (int)(sh3_ptob(physmem) >> 20));
    282 	mem_cluster_load();
    283 
    284 	/* Initialize proc0 u-area */
    285 	sh_proc0_init();
    286 
    287 	/* Initialize pmap and start to address translation */
    288 	pmap_bootstrap();
    289 
    290 #if NKSYMS || defined(MODULAR) || defined(DDB) || defined(KGDB)
    291 	if (symbolsize) {
    292 		ksyms_addsyms_elf(symbolsize, &end, end + symbolsize);
    293 		_DPRINTF("symbol size = %d byte\n", symbolsize);
    294 	}
    295 #endif
    296 #ifdef DDB
    297 	/* Debugger. */
    298 	if (boothowto & RB_KDB)
    299 		Debugger();
    300 #endif /* DDB */
    301 #ifdef KGDB
    302 	if (boothowto & RB_KDB) {
    303 		if (kgdb_dev == NODEV) {
    304 			printf("no kgdb console.\n");
    305 		} else {
    306 			kgdb_debug_init = 1;
    307 			kgdb_connect(1);
    308 		}
    309 	}
    310 #endif /* KGDB */
    311 
    312 	/* Jump to main */
    313 	__asm volatile(
    314 		"jmp	@%0;"
    315 		"mov	%1, sp"
    316 		:: "r"(main),"r"(lwp0.l_md.md_pcb->pcb_sf.sf_r7_bank));
    317 
    318 	/* NOTREACHED */
    319 	for (;;)
    320 		continue;
    321 }
    322 
    323 void
    324 cpu_startup(void)
    325 {
    326 
    327 	cpu_setmodel("%s", platid_name(&platid));
    328 
    329 	sh_startup();
    330 }
    331 
    332 SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup")
    333 {
    334 
    335 	sysctl_createv(clog, 0, NULL, NULL,
    336 		       CTLFLAG_PERMANENT,
    337 		       CTLTYPE_NODE, "machdep", NULL,
    338 		       NULL, 0, NULL, 0,
    339 		       CTL_MACHDEP, CTL_EOL);
    340 
    341 	sysctl_createv(clog, 0, NULL, NULL,
    342 		       CTLFLAG_PERMANENT,
    343 		       CTLTYPE_STRUCT, "console_device", NULL,
    344 		       sysctl_consdev, 0, NULL, sizeof(dev_t),
    345 		       CTL_MACHDEP, CPU_CONSDEV, CTL_EOL);
    346 }
    347 
    348 /* hpcapm */
    349 void
    350 machine_sleep(void)
    351 {
    352 
    353 	if (__sleep_func != NULL)
    354 		__sleep_func(__sleep_ctx);
    355 }
    356 
    357 /* hpcapm */
    358 void
    359 machine_standby(void)
    360 {
    361 	/* notyet */
    362 }
    363 
    364 void
    365 cpu_reboot(int howto, char *bootstr)
    366 {
    367 
    368 	/* take a snap shot before clobbering any registers */
    369 	if (curlwp)
    370 		savectx(curpcb);
    371 
    372 	/* If system is cold, just halt. */
    373 	if (cold) {
    374 		howto |= RB_HALT;
    375 		goto haltsys;
    376 	}
    377 
    378 	/* If "always halt" was specified as a boot flag, obey. */
    379 	if ((boothowto & RB_HALT) != 0) {
    380 		howto |= RB_HALT;
    381 	}
    382 
    383 #ifdef KLOADER
    384 	if ((howto & RB_HALT) == 0) {
    385 		if ((howto & RB_STRING) != 0)
    386 			kloader_reboot_setup(bootstr);
    387 		else
    388 			kloader_reboot_setup(kernel_path);
    389 	}
    390 #endif
    391 
    392 	boothowto = howto;
    393 	if ((howto & RB_NOSYNC) == 0) {
    394 		/*
    395 		 * Synchronize the disks....
    396 		 */
    397 		vfs_shutdown();
    398 	}
    399 
    400 	/* Disable interrupts. */
    401 	splhigh();
    402 
    403 	/* If rebooting and a dump is requested do it. */
    404 #if notyet
    405 	if (howto & RB_DUMP)
    406 		dumpsys();
    407 #endif
    408 
    409  haltsys:
    410 	/* run any shutdown hooks */
    411 	doshutdownhooks();
    412 
    413 	pmf_system_shutdown(boothowto);
    414 
    415 	/* Finally, halt/reboot the system. */
    416 	if ((howto & RB_HALT) != 0) {
    417 		printf("halted.\n");
    418 	} else {
    419 #ifdef KLOADER
    420 		kloader_reboot();
    421 		/* NOTREACHED */
    422 #endif
    423 	}
    424 
    425 #if NHD64465IF > 0
    426 	hd64465_shutdown();
    427 #endif
    428 
    429 	cpu_reset();
    430 
    431 	/* NOTREACHED */
    432 	for (;;)
    433 		continue;
    434 }
    435 
    436 /* return # of physical pages. */
    437 static int
    438 mem_cluster_init(paddr_t addr)
    439 {
    440 	phys_ram_seg_t *seg;
    441 	int npages, i;
    442 
    443 	/* cluster 0 is always the kernel itself. */
    444 	mem_clusters[0].start = SH_CS3_START;
    445 	mem_clusters[0].size = addr - SH_CS3_START;
    446 	mem_cluster_cnt = 1;
    447 
    448 	/* search CS3 */
    449 #ifdef SH3
    450 	/* SH7709A's CS3 is split to 2 banks. */
    451 	if (CPU_IS_SH3) {
    452 		__find_dram_shadow(addr, SH7709_CS3_BANK0_END);
    453 		__find_dram_shadow(SH7709_CS3_BANK1_START,
    454 		    SH7709_CS3_BANK1_END);
    455 	}
    456 #endif
    457 #ifdef SH4
    458 	/* contiguous CS3 */
    459 	if (CPU_IS_SH4) {
    460 		__find_dram_shadow(addr, SH_CS3_END);
    461 	}
    462 #endif
    463 	_DPRINTF("mem_cluster_cnt = %d\n", mem_cluster_cnt);
    464 	npages = 0;
    465 	for (i = 0, seg = mem_clusters; i < mem_cluster_cnt; i++, seg++) {
    466 		_DPRINTF("mem_clusters[%d] = {0x%lx+0x%lx <0x%lx}", i,
    467 		    (paddr_t)seg->start, (paddr_t)seg->size,
    468 		    (paddr_t)seg->start + (paddr_t)seg->size);
    469 		npages += sh3_btop(seg->size);
    470 #ifdef NARLY_MEMORY_PROBE
    471 		if (i == 0) {
    472 			_DPRINTF(" don't check.\n");
    473 			continue;
    474 		}
    475 		if (__check_dram((paddr_t)seg->start, (paddr_t)seg->start +
    476 		    (paddr_t)seg->size) != 0)
    477 			panic("D-RAM check failed.");
    478 #else
    479 		_DPRINTF("\n");
    480 #endif /* NARLY_MEMORY_PROBE */
    481 	}
    482 
    483 	return (npages);
    484 }
    485 
    486 static void
    487 mem_cluster_load(void)
    488 {
    489 	paddr_t start, end;
    490 	psize_t size;
    491 	int i;
    492 
    493 	/* Cluster 0 is always the kernel, which doesn't get loaded. */
    494 	sh_dcache_wbinv_all();
    495 	for (i = 1; i < mem_cluster_cnt; i++) {
    496 		start = (paddr_t)mem_clusters[i].start;
    497 		size = (psize_t)mem_clusters[i].size;
    498 
    499 		_DPRINTF("loading 0x%lx,0x%lx\n", start, size);
    500 		memset((void *)SH3_PHYS_TO_P1SEG(start), 0, size);
    501 		end = atop(start + size);
    502 		start = atop(start);
    503 		uvm_page_physload(start, end, start, end, VM_FREELIST_DEFAULT);
    504 	}
    505 	sh_dcache_wbinv_all();
    506 }
    507 
    508 static void
    509 __find_dram_shadow(paddr_t start, paddr_t end)
    510 {
    511 	vaddr_t page, startaddr, endaddr;
    512 	int x;
    513 
    514 	_DPRINTF("search D-RAM from 0x%08lx for 0x%08lx\n", start, end);
    515 	startaddr = SH3_PHYS_TO_P2SEG(start);
    516 	endaddr = SH3_PHYS_TO_P2SEG(end);
    517 
    518 	page = startaddr;
    519 
    520 	x = random();
    521 	*(volatile int *)(page + 0) = x;
    522 	*(volatile int *)(page + 4) = ~x;
    523 
    524 	if (*(volatile int *)(page + 0) != x ||
    525 	    *(volatile int *)(page + 4) != ~x)
    526 		return;
    527 
    528 	for (page += PAGE_SIZE; page < endaddr; page += PAGE_SIZE) {
    529 		if (*(volatile int *)(page + 0) == x &&
    530 		    *(volatile int *)(page + 4) == ~x) {
    531 			goto memend_found;
    532 		}
    533 	}
    534 
    535 	page -= PAGE_SIZE;
    536 	*(volatile int *)(page + 0) = x;
    537 	*(volatile int *)(page + 4) = ~x;
    538 
    539 	if (*(volatile int *)(page + 0) != x ||
    540 	    *(volatile int *)(page + 4) != ~x)
    541 		return; /* no memory in this bank */
    542 
    543  memend_found:
    544 	KASSERT(mem_cluster_cnt < VM_PHYSSEG_MAX);
    545 
    546 	mem_clusters[mem_cluster_cnt].start = start;
    547 	mem_clusters[mem_cluster_cnt].size = page - startaddr;
    548 
    549 	/* skip kernel area */
    550 	if (mem_cluster_cnt == 1)
    551 		mem_clusters[1].size -= mem_clusters[0].size;
    552 
    553 	mem_cluster_cnt++;
    554 }
    555 
    556 #ifdef NARLY_MEMORY_PROBE
    557 static int
    558 __check_dram(paddr_t start, paddr_t end)
    559 {
    560 	uint8_t *page;
    561 	int i, x;
    562 
    563 	_DPRINTF(" checking...");
    564 	for (; start < end; start += PAGE_SIZE) {
    565 		page = (uint8_t *)SH3_PHYS_TO_P2SEG (start);
    566 		x = random();
    567 		for (i = 0; i < PAGE_SIZE; i += 4)
    568 			*(volatile int *)(page + i) = (x ^ i);
    569 		for (i = 0; i < PAGE_SIZE; i += 4)
    570 			if (*(volatile int *)(page + i) != (x ^ i))
    571 				goto bad;
    572 		x = random();
    573 		for (i = 0; i < PAGE_SIZE; i += 4)
    574 			*(volatile int *)(page + i) = (x ^ i);
    575 		for (i = 0; i < PAGE_SIZE; i += 4)
    576 			if (*(volatile int *)(page + i) != (x ^ i))
    577 				goto bad;
    578 	}
    579 	_DPRINTF("success.\n");
    580 	return (0);
    581  bad:
    582 	_DPRINTF("failed.\n");
    583 	return (1);
    584 }
    585 #endif /* NARLY_MEMORY_PROBE */
    586 
    587 void
    588 intc_intr(int ssr, int spc, int ssp)
    589 {
    590 	struct intc_intrhand *ih;
    591 	int evtcode;
    592 	uint16_t r;
    593 
    594 	curcpu()->ci_data.cpu_nintr++;
    595 
    596 	evtcode = _reg_read_4(CPU_IS_SH3 ? SH7709_INTEVT2 : SH4_INTEVT);
    597 
    598 	ih = EVTCODE_IH(evtcode);
    599 	KDASSERT(ih->ih_func);
    600 	/*
    601 	 * On entry, all interrupts are disabled,
    602 	 * and exception is enabled for P3 access. (kernel stack is P3,
    603 	 * SH3 may or may not cause TLB miss when access stack.)
    604 	 * Enable higher level interrupt here.
    605 	 */
    606 	r = _reg_read_2(HD6446X_NIRR);
    607 
    608 	splx(ih->ih_level);
    609 
    610 	if (evtcode == SH_INTEVT_TMU0_TUNI0) {
    611 		struct clockframe cf;
    612 		cf.spc = spc;
    613 		cf.ssr = ssr;
    614 		cf.ssp = ssp;
    615 		(*ih->ih_func)(&cf);
    616 		__dbg_heart_beat(HEART_BEAT_RED);
    617 	} else if (evtcode ==
    618 	    (CPU_IS_SH3 ? SH7709_INTEVT2_IRQ4 : SH_INTEVT_IRL11)) {
    619 		struct hd6446x_intrhand *hh;
    620 		int cause;
    621 
    622 		cause = r & hd6446x_ienable;
    623 		if (cause == 0) {
    624 			printf("masked HD6446x interrupt 0x%04x\n",
    625 			       r & ~hd6446x_ienable);
    626 			_reg_write_2(HD6446X_NIRR, 0x0000);
    627 			return;
    628 		}
    629 		/* Enable higher level interrupt*/
    630 		hh = &hd6446x_intrhand[ffs(cause) - 1];
    631 		hd6446x_intr_resume(hh->hh_ipl);
    632 		KDASSERT(hh->hh_func != NULL);
    633 		(*hh->hh_func)(hh->hh_arg);
    634 		__dbg_heart_beat(HEART_BEAT_GREEN);
    635 	} else {
    636 		(*ih->ih_func)(ih->ih_arg);
    637 		__dbg_heart_beat(HEART_BEAT_BLUE);
    638 	}
    639 }
    640