Home | History | Annotate | Line # | Download | only in amigappc
      1 /* $NetBSD: machdep.c,v 1.55 2024/09/08 10:17:54 andvar Exp $ */
      2 
      3 /*
      4  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
      5  * Copyright (C) 1995, 1996 TooLs GmbH.
      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  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *      This product includes software developed by TooLs GmbH.
     19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
     20  *    derived from this software without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
     23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 #include <sys/cdefs.h>
     35 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.55 2024/09/08 10:17:54 andvar Exp $");
     36 
     37 #include <sys/param.h>
     38 #include <sys/device.h>
     39 #include <sys/mount.h>
     40 #include <sys/msgbuf.h>
     41 #include <sys/kernel.h>
     42 #include <sys/reboot.h>
     43 #include <sys/ksyms.h>
     44 
     45 #include <uvm/uvm_extern.h>
     46 
     47 #include <dev/cons.h>
     48 
     49 #include <machine/autoconf.h>
     50 #include <machine/powerpc.h>
     51 
     52 #include <powerpc/oea/bat.h>
     53 #include <powerpc/pic/picvar.h>
     54 
     55 #include <amiga/amiga/cc.h>
     56 #include <amiga/amiga/cia.h>
     57 #include <amiga/amiga/custom.h>
     58 #include <amiga/amiga/device.h>
     59 #include <amiga/amiga/isr.h>
     60 #include <amiga/amiga/memlist.h>
     61 #include <amigappc/amigappc/p5reg.h>
     62 
     63 #include "opt_ddb.h"
     64 
     65 #include "fd.h"
     66 #include "ser.h"
     67 
     68 extern void setup_amiga_intr(void);
     69 #if NSER > 0
     70 extern void ser_outintr(void);
     71 extern void ser_fastint(void);
     72 #endif
     73 #if NFD > 0
     74 extern void fdintr(int);
     75 #endif
     76 
     77 #define AMIGAMEMREGIONS 8
     78 static struct mem_region physmemr[AMIGAMEMREGIONS], availmemr[AMIGAMEMREGIONS];
     79 static char model[80];
     80 
     81 /*
     82  * patched by some devices at attach time (currently, only the coms)
     83  */
     84 int amiga_serialspl = 4;
     85 
     86 /*
     87  * current open serial device speed;  used by some SCSI drivers to reduce
     88  * DMA transfer lengths.
     89  */
     90 int ser_open_speed;
     91 
     92 /* interrupt handler chains for level2 and level6 interrupt */
     93 struct isr *isr_ports;
     94 struct isr *isr_exter;
     95 
     96 extern void *startsym, *endsym;
     97 
     98 void
     99 add_isr(struct isr *isr)
    100 {
    101 	struct isr **p, *q;
    102 
    103 	p = isr->isr_ipl == 2 ? &isr_ports : &isr_exter;
    104 
    105 	while ((q = *p) != NULL)
    106 		p = &q->isr_forw;
    107 	isr->isr_forw = NULL;
    108 	*p = isr;
    109 
    110 	/* enable interrupt */
    111 	custom.intena = isr->isr_ipl == 2 ?
    112 	    INTF_SETCLR | INTF_PORTS :
    113 	    INTF_SETCLR | INTF_EXTER;
    114 }
    115 
    116 void
    117 remove_isr(struct isr *isr)
    118 {
    119 	struct isr **p, *q;
    120 
    121 	p = isr->isr_ipl == 6 ? &isr_exter : &isr_ports;
    122 
    123 	while ((q = *p) != NULL && q != isr)
    124 		p = &q->isr_forw;
    125 	if (q)
    126 		*p = q->isr_forw;
    127 	else
    128 		panic("remove_isr: handler not registered");
    129 
    130 	/* disable interrupt if no more handlers */
    131 	p = isr->isr_ipl == 6 ? &isr_exter : &isr_ports;
    132 	if (*p == NULL) {
    133 		custom.intena = isr->isr_ipl == 6 ?
    134 		    INTF_EXTER : INTF_PORTS;
    135 	}
    136 }
    137 
    138 static int
    139 ports_intr(void *arg)
    140 {
    141 	struct isr **p;
    142 	struct isr *q;
    143 
    144 	p = (struct isr **)arg;
    145 	while ((q = *p) != NULL) {
    146 		if ((q->isr_intr)(q->isr_arg))
    147 			break;
    148 		p = &q->isr_forw;
    149 	}
    150 	if (q == NULL)
    151 		ciaa_intr();  /* ciaa handles keyboard and parallel port */
    152 
    153 	custom.intreq = INTF_PORTS;
    154 	return 0;
    155 }
    156 
    157 static int
    158 exter_intr(void *arg)
    159 {
    160 	struct isr **p;
    161 	struct isr *q;
    162 
    163 	p = (struct isr **)arg;
    164 	while ((q = *p) != NULL) {
    165 		if ((q->isr_intr)(q->isr_arg))
    166 			break;
    167 		p = &q->isr_forw;
    168 	}
    169 	if (q == NULL)
    170 		ciab_intr();  /* clear ciab icr */
    171 
    172 	custom.intreq = INTF_EXTER;
    173 	return 0;
    174 }
    175 
    176 static int
    177 lev1_intr(void *arg)
    178 {
    179 	unsigned short ireq;
    180 
    181 	ireq = custom.intreqr;
    182 	if (ireq & INTF_TBE) {
    183 #if NSER > 0
    184 		ser_outintr();
    185 #else
    186 		custom.intreq = INTF_TBE;
    187 #endif
    188 	}
    189 	if (ireq & INTF_DSKBLK) {
    190 #if NFD > 0
    191 		fdintr(0);
    192 #endif
    193 		custom.intreq = INTF_DSKBLK;
    194 	}
    195 	if (ireq & INTF_SOFTINT) {
    196 #ifdef DEBUG
    197 		printf("intrhand: SOFTINT ignored\n");
    198 #endif
    199 		custom.intreq = INTF_SOFTINT;
    200 	}
    201 	return 0;
    202 }
    203 
    204 static int
    205 lev3_intr(void *arg)
    206 {
    207 	unsigned short ireq;
    208 
    209 	ireq = custom.intreqr;
    210 	if (ireq & INTF_BLIT)
    211 		blitter_handler();
    212 	if (ireq & INTF_COPER)
    213 		copper_handler();
    214 	if (ireq & INTF_VERTB)
    215 		vbl_handler();
    216 	return 0;
    217 }
    218 
    219 static int
    220 lev4_intr(void *arg)
    221 {
    222 
    223 	audio_handler();
    224 	return 0;
    225 }
    226 
    227 static int
    228 lev5_intr(void *arg)
    229 {
    230 
    231 	ser_fastint();
    232 	if (custom.intreqr & INTF_DSKSYNC)
    233 		custom.intreq = INTF_DSKSYNC;
    234 	return 0;
    235 }
    236 
    237 static void
    238 amigappc_install_handlers(void)
    239 {
    240 
    241 	/* handlers for all 6 Amiga interrupt levels */
    242 	intr_establish(1, IST_LEVEL, IPL_BIO, lev1_intr, NULL);
    243 	intr_establish(2, IST_LEVEL, IPL_BIO, ports_intr, &isr_ports);
    244 	intr_establish(3, IST_LEVEL, IPL_TTY, lev3_intr, NULL);
    245 	intr_establish(4, IST_LEVEL, IPL_AUDIO, lev4_intr, NULL);
    246 	intr_establish(5, IST_LEVEL, IPL_SERIAL, lev5_intr, NULL);
    247 	intr_establish(6, IST_LEVEL, IPL_SERIAL, exter_intr, &isr_exter);
    248 }
    249 
    250 static void
    251 amigappc_identify(void)
    252 {
    253 	extern u_long ns_per_tick, ticks_per_sec;
    254 	static const unsigned char pll[] = {
    255 		10, 10, 70, 10, 20, 65, 25, 45,
    256 		30, 55, 40, 50, 15, 60, 35, 00
    257 	};
    258 	const char *cpuname, *mach, *p5type_p, *pup;
    259 	u_long busclock, cpuclock;
    260 	register int pvr, hid1;
    261 
    262 	/* PowerUp ROM id location */
    263 	p5type_p = (const char *)0xf00010;
    264 
    265 	/*
    266 	 * PVR holds the CPU-type and version while
    267          * HID1 holds the PLL configuration
    268 	 */
    269 	__asm ("mfpvr %0; mfspr %1,1009" : "=r"(pvr), "=r"(hid1));
    270 
    271 	/* Amiga types which can run a PPC board */
    272 	if (is_a4000())
    273 		mach = "Amiga 4000";
    274 	else if (is_a3000())
    275 		mach = "Amiga 3000";
    276 	else
    277 		mach = "Amiga 1200";
    278 
    279 	/* find CPU type - BlizzardPPC has 603e/603ev, CyberstormPPC has 604e */
    280 	switch (pvr >> 16) {
    281 	case 3:
    282 		cpuname = "603";
    283 		break;
    284 	case 4:
    285 		cpuname = "604";
    286 		break;
    287 	case 6:
    288 		cpuname = "603e";
    289 		break;
    290 	case 7:
    291 		cpuname = "603ev";
    292 		break;
    293 	case 9:
    294 	case 10:
    295 		cpuname = "604e";
    296 		break;
    297 	default:
    298 		cpuname = "unknown";
    299 		break;
    300 	}
    301 
    302 	switch (p5type_p[0]) {
    303 	case 'D':
    304 		pup = "[PowerUP]";
    305 		break;
    306 	case 'E':
    307 		pup = "[CSPPC]";
    308 		break;
    309 	case 'F':
    310 		pup = "[CS Mk.III]";
    311 		break;
    312 	case 'H':
    313 	case 'I':
    314 		pup = "[BlizzardPPC]";
    315 		break;
    316 	default:
    317 		pup = "";
    318 		break;
    319 	}
    320 
    321 	/* XXX busclock can be measured with CIA-timers */
    322 	switch (p5type_p[1]) {
    323 	case 'A':
    324 		busclock = 60000000;
    325 		break;
    326 	/* case B, C, D */
    327 	default:
    328 		busclock = 66666667;
    329 		break;
    330 	}
    331 
    332 	/* compute cpuclock based on PLL configuration */
    333 	cpuclock = busclock * pll[hid1>>28 & 0xf] / 10;
    334 
    335 	snprintf(model, sizeof(model),
    336 	    "%s %s (%s v%d.%d %lu MHz, busclk %lu MHz)",
    337 	    mach, pup, cpuname, (pvr>>8) & 0xf, (pvr >> 0) & 0xf,
    338 	    cpuclock / 1000000, busclock / 1000000);
    339 
    340 	/* set timebase */
    341 	ticks_per_sec = busclock / 4;
    342 	ns_per_tick = 1000000000 / ticks_per_sec;
    343 }
    344 
    345 static void
    346 amigappc_reboot(void)
    347 {
    348 
    349 	/* reboot CSPPC/BPPC */
    350 	if (!is_a1200()) {
    351 		P5write(P5_REG_LOCK,0x60);
    352 		P5write(P5_REG_LOCK,0x50);
    353 		P5write(P5_REG_LOCK,0x30);
    354 		P5write(P5_REG_SHADOW,P5_SET_CLEAR|P5_SHADOW);
    355 		P5write(P5_REG_LOCK,0x00);
    356 	} else
    357 		P5write(P5_BPPC_MAGIC,0x00);
    358 
    359 	P5write(P5_REG_LOCK,0x60);
    360 	P5write(P5_REG_LOCK,0x50);
    361 	P5write(P5_REG_LOCK,0x30);
    362 	P5write(P5_REG_SHADOW,P5_SELF_RESET);
    363 	P5write(P5_REG_RESET,P5_AMIGA_RESET);
    364 }
    365 
    366 static void
    367 amigappc_bat_add(paddr_t pa, register_t len, register_t prot)
    368 {
    369 	static int nd = 0, ni = 0;
    370 	const uint32_t i = pa >> 28;
    371 
    372 	battable[i].batl = BATL(pa, prot, BAT_PP_RW);
    373 	battable[i].batu = BATU(pa, len, BAT_Vs);
    374 
    375 	/*
    376 	 * Let's start loading the BAT registers.
    377 	 */
    378 	if (!(prot & (BAT_I | BAT_G))) {
    379 		switch (ni) {
    380 		case 0:
    381 			__asm volatile ("isync");
    382 			__asm volatile ("mtibatl 0,%0; mtibatu 0,%1;"
    383 			    ::	"r"(battable[i].batl),
    384 				"r"(battable[i].batu));
    385 			__asm volatile ("isync");
    386 			ni = 1;
    387 			break;
    388 		case 1:
    389 			__asm volatile ("isync");
    390 			__asm volatile ("mtibatl 1,%0; mtibatu 1,%1;"
    391 			    ::	"r"(battable[i].batl),
    392 				"r"(battable[i].batu));
    393 			__asm volatile ("isync");
    394 			ni = 2;
    395 			break;
    396 		case 2:
    397 			__asm volatile ("isync");
    398 			__asm volatile ("mtibatl 2,%0; mtibatu 2,%1;"
    399 			    ::	"r"(battable[i].batl),
    400 				"r"(battable[i].batu));
    401 			__asm volatile ("isync");
    402 			ni = 3;
    403 			break;
    404 		case 3:
    405 			__asm volatile ("isync");
    406 			__asm volatile ("mtibatl 3,%0; mtibatu 3,%1;"
    407 			    ::	"r"(battable[i].batl),
    408 				"r"(battable[i].batu));
    409 			__asm volatile ("isync");
    410 			ni = 4;
    411 			break;
    412 		default:
    413 			break;
    414 		}
    415 	}
    416 	switch (nd) {
    417 	case 0:
    418 		__asm volatile ("isync");
    419 		__asm volatile ("mtdbatl 0,%0; mtdbatu 0,%1;"
    420 		    ::	"r"(battable[i].batl),
    421 			"r"(battable[i].batu));
    422 		__asm volatile ("isync");
    423 		nd = 1;
    424 		break;
    425 	case 1:
    426 		__asm volatile ("isync");
    427 		__asm volatile ("mtdbatl 1,%0; mtdbatu 1,%1;"
    428 		    ::	"r"(battable[i].batl),
    429 			"r"(battable[i].batu));
    430 		__asm volatile ("isync");
    431 		nd = 2;
    432 		break;
    433 	case 2:
    434 		__asm volatile ("isync");
    435 		__asm volatile ("mtdbatl 2,%0; mtdbatu 2,%1;"
    436 		    ::	"r"(battable[i].batl),
    437 			"r"(battable[i].batu));
    438 		__asm volatile ("isync");
    439 		nd = 3;
    440 		break;
    441 	case 3:
    442 		__asm volatile ("isync");
    443 		__asm volatile ("mtdbatl 3,%0; mtdbatu 3,%1;"
    444 		    ::	"r"(battable[i].batl),
    445 			"r"(battable[i].batu));
    446 		__asm volatile ("isync");
    447 		nd = 4;
    448 		break;
    449 	default:
    450 		break;
    451 	}
    452 }
    453 
    454 static void
    455 amigappc_batinit(paddr_t pa, ...)
    456 {
    457 	va_list ap;
    458 	register_t msr;
    459 
    460 	msr = mfmsr();
    461 
    462 	/*
    463 	 * Set BAT registers to unmapped to avoid overlapping mappings below.
    464 	 */
    465 	if ((msr & (PSL_IR|PSL_DR)) == 0) {
    466 		__asm volatile ("isync");
    467 		__asm volatile ("mtibatu 0,%0" :: "r"(0));
    468 		__asm volatile ("mtibatu 1,%0" :: "r"(0));
    469 		__asm volatile ("mtibatu 2,%0" :: "r"(0));
    470 		__asm volatile ("mtibatu 3,%0" :: "r"(0));
    471 		__asm volatile ("mtdbatu 0,%0" :: "r"(0));
    472 		__asm volatile ("mtdbatu 1,%0" :: "r"(0));
    473 		__asm volatile ("mtdbatu 2,%0" :: "r"(0));
    474 		__asm volatile ("mtdbatu 3,%0" :: "r"(0));
    475 		__asm volatile ("isync");
    476 	}
    477 
    478 	/*
    479 	 * Setup BATs
    480 	 */
    481 	va_start(ap, pa);
    482 	while (pa != ~0) {
    483 		register_t len, prot;
    484 
    485 		len = va_arg(ap, register_t);
    486 		prot = va_arg(ap, register_t);
    487 		amigappc_bat_add(pa, len, prot);
    488 		pa = va_arg(ap, paddr_t);
    489 	}
    490 	va_end(ap);
    491 }
    492 
    493 void
    494 initppc(u_int startkernel, u_int endkernel)
    495 {
    496 	struct boot_memseg *ms;
    497 	u_int i, r;
    498 
    499 	/*
    500 	 * amigappc memory region set
    501 	 */
    502 	ms = &memlist->m_seg[0];
    503 	for (i = 0, r = 0; i < memlist->m_nseg; i++, ms++) {
    504 		if (ms->ms_attrib & MEMF_FAST) {
    505 			/*
    506 			 * XXX Only recognize the memory segment in which
    507 			 * the kernel resides, for now
    508 			 */
    509 			if (ms->ms_start <= startkernel &&
    510 			    ms->ms_start + ms->ms_size > endkernel) {
    511 				physmemr[r].start = (paddr_t)ms->ms_start;
    512 				physmemr[r].size = (psize_t)ms->ms_size & ~PGOFSET;
    513 				availmemr[r].start = (endkernel + PGOFSET) & ~PGOFSET;
    514 				availmemr[r].size  = (physmemr[0].start +
    515 						      physmemr[0].size)
    516 						     - availmemr[0].start;
    517 			}
    518 			r++;
    519 		}
    520 	}
    521 	physmemr[r].start = 0;
    522 	physmemr[r].size = 0;
    523 	availmemr[r].start = 0;
    524 	availmemr[r].size = 0;
    525 	if (r == 0)
    526 		panic("initppc: no suitable memory segment found");
    527 
    528 	/*
    529 	 * Initialize BAT tables.
    530 	 * The CSPPC RAM (A3000/A4000) always starts at 0x08000000 and is
    531 	 * up to 128MB big.
    532 	 * The BPPC RAM (A1200) can be up to 256MB and may start at nearly
    533 	 * any address between 0x40000000 and 0x80000000 depending on which
    534 	 * RAM module of which size was inserted into which bank:
    535 	 * The RAM module in bank 1 is located from 0x?8000000 downwards.
    536 	 * The RAM module in bank 2 is located from 0x?8000000 upwards.
    537 	 * Whether '?' is 4, 5, 6 or 7 probably depends on the size.
    538 	 * So we have to use the 'startkernel' symbol for BAT-mapping
    539 	 * our RAM.
    540 	 */
    541 	if (is_a1200()) {
    542 		amigappc_batinit(0x00000000, BAT_BL_16M, BAT_I|BAT_G,
    543 		    (startkernel & 0xf0000000), BAT_BL_256M, 0,
    544 		    0xfff00000, BAT_BL_512K, 0,
    545 		    ~0);
    546 	} else {
    547 		/* A3000 or A4000 */
    548 		amigappc_batinit(0x00000000, BAT_BL_16M, BAT_I|BAT_G,
    549 		    (startkernel & 0xf8000000), BAT_BL_128M, 0,
    550 		    0xfff00000, BAT_BL_512K, 0,
    551 		    0x40000000, BAT_BL_256M, BAT_I|BAT_G,
    552 		    ~0);
    553 	}
    554 
    555 	/*
    556 	 * Set up trap vectors and interrupt handler
    557 	 */
    558 	oea_init(NULL);
    559 
    560 	/* XXX bus_space_init() not needed here */
    561 
    562 	uvm_md_init();
    563 
    564 	/*
    565 	 * Initialize pmap module
    566 	 */
    567 	pmap_bootstrap(startkernel, endkernel);
    568 
    569 #if NKSYMS || defined(DDB) || defined(MODULAR)
    570 	ksyms_addsyms_elf((int)((u_int)endsym - (u_int)startsym), startsym, endsym);
    571 #endif
    572 
    573 	/*
    574 	 * CPU model, bus clock, timebase
    575 	 */
    576 	amigappc_identify();
    577 
    578 #ifdef DDB
    579 	if (boothowto & RB_KDB)
    580 		Debugger();
    581 #endif
    582 }
    583 
    584 /*
    585  * This is called during initppc, before the system is really initialized.
    586  * It shall provide the total and the available regions of RAM.
    587  * Both lists must have a zero-size entry as terminator.
    588  * The available regions need not take the kernel into account, but needs
    589  * to provide space for two additional entry beyond the terminating one.
    590  */
    591 void
    592 mem_regions(struct mem_region **memp, struct mem_region **availp)
    593 {
    594 
    595 	*memp = physmemr;
    596 	*availp = availmemr;
    597 }
    598 
    599 /*
    600  * Machine dependent startup code
    601  */
    602 void
    603 cpu_startup(void)
    604 {
    605 	int msr;
    606 
    607 	/*
    608 	 * hello world
    609 	 */
    610 	oea_startup(model);
    611 
    612 	/* Setup interrupts */
    613 	pic_init();
    614 	setup_amiga_intr();
    615 	amigappc_install_handlers();
    616 
    617 	oea_install_extint(pic_ext_intr);
    618 
    619 	/*
    620 	 * Now allow hardware interrupts.
    621 	 */
    622 	splhigh();
    623 	__asm volatile ("mfmsr %0; ori %0,%0,%1; mtmsr %0"
    624 	    :	"=r"(msr)
    625 	    :	"K"(PSL_EE));
    626 
    627 #if 0 /* XXX Not in amiga bus.h - fix it? */
    628 	/*
    629 	 * Now that we have VM, malloc's are OK in bus_space.
    630 	 */
    631 	bus_space_mallocok();
    632 #endif
    633 }
    634 
    635 /*
    636  * consinit
    637  * Initialize system console.
    638  */
    639 void
    640 consinit(void)
    641 {
    642 
    643 	/* preconfigure graphics cards */
    644 	custom_chips_init();
    645 	config_console();
    646 
    647 	/* Initialize the console before we print anything out. */
    648 	cninit();
    649 }
    650 
    651 /*
    652  * Halt or reboot the machine after syncing/dumping according to howto
    653  */
    654 void
    655 cpu_reboot(int howto, char *what)
    656 {
    657 	static int syncing;
    658 
    659 	if (cold) {
    660 		howto |= RB_HALT;
    661 		goto halt_sys;
    662 	}
    663 
    664 	boothowto = howto;
    665 	if ((howto & RB_NOSYNC) == 0 && syncing == 0) {
    666 		syncing = 1;
    667 		vfs_shutdown();		/* sync */
    668 	}
    669 
    670 	/* Disable intr */
    671 	splhigh();
    672 
    673 	/* Do dump if requested */
    674 	if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP) {
    675 		oea_dumpsys();
    676 #ifdef DDB
    677 		/* XXX dumpsys doesn't work, so give a chance to debug */
    678 		Debugger();
    679 #endif
    680 	}
    681 
    682 halt_sys:
    683 	doshutdownhooks();
    684 
    685 	if (howto & RB_HALT) {
    686 		printf("\n");
    687 		printf("The operating system has halted.\n");
    688 		printf("Please press any key to reboot.\n\n");
    689 		cnpollc(1);	/* for proper keyboard command handling */
    690 		cngetc();
    691 		cnpollc(0);
    692 	}
    693 
    694 	printf("rebooting...\n\n");
    695 	delay(1000000);
    696 	amigappc_reboot();
    697 
    698 	for (;;);
    699 	/* NOTREACHED */
    700 }
    701 
    702 /*
    703  * Try to emulate the functionality from m68k/m68k/sys_machdep.c
    704  * used by several amiga scsi drivers.
    705  */
    706 int
    707 dma_cachectl(void *addr, int len)
    708 {
    709 	paddr_t pa, end;
    710 	int inc;
    711 
    712 	if (addr == NULL || len == 0)
    713 		return 0;
    714 
    715 	pa = kvtop(addr);
    716 	inc = curcpu()->ci_ci.dcache_line_size;
    717 
    718 	for (end = pa + len; pa < end; pa += inc)
    719 		__asm volatile("dcbf 0,%0" :: "r"(pa));
    720 	__asm volatile("sync");
    721 
    722 #if 0 /* XXX not needed, we don't have instructions in DMA buffers */
    723 	pa = kvtop(addr);
    724 	for (end = pa + len; pa < end; pa += inc)
    725 		__asm volatile("icbi 0,%0" :: "r"(pa));
    726 	__asm volatile("isync");
    727 #endif
    728 
    729 	return 0;
    730 }
    731