Home | History | Annotate | Line # | Download | only in mvme68k
      1 /*	$NetBSD: machdep.c,v 1.194 2026/04/28 03:29:10 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1988 University of Utah.
      5  * Copyright (c) 1982, 1986, 1990, 1993
      6  *	The Regents of the University of California.  All rights reserved.
      7  *
      8  * This code is derived from software contributed to Berkeley by
      9  * the Systems Programming Group of the University of Utah Computer
     10  * Science Department.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  * 3. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  *
     36  * from: Utah $Hdr: machdep.c 1.74 92/12/20$
     37  *
     38  *	@(#)machdep.c	8.10 (Berkeley) 4/20/94
     39  */
     40 
     41 #include <sys/cdefs.h>
     42 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.194 2026/04/28 03:29:10 thorpej Exp $");
     43 
     44 #include "opt_ddb.h"
     45 #include "opt_modular.h"
     46 #include "opt_panicbutton.h"
     47 #include "opt_m68k_arch.h"
     48 #include "opt_mvmeconf.h"
     49 
     50 #include <sys/param.h>
     51 #include <sys/systm.h>
     52 #include <sys/signalvar.h>
     53 #include <sys/kernel.h>
     54 #include <sys/proc.h>
     55 #include <sys/buf.h>
     56 #include <sys/reboot.h>
     57 #include <sys/conf.h>
     58 #include <sys/file.h>
     59 #include <sys/mbuf.h>
     60 #include <sys/msgbuf.h>
     61 #include <sys/ioctl.h>
     62 #include <sys/tty.h>
     63 #include <sys/mount.h>
     64 #include <sys/exec.h>
     65 #include <sys/core.h>
     66 #include <sys/kcore.h>
     67 #include <sys/vnode.h>
     68 #include <sys/syscallargs.h>
     69 #include <sys/ksyms.h>
     70 #include <sys/module.h>
     71 #include <sys/device.h>
     72 #include <sys/cpu.h>
     73 
     74 #include "ksyms.h"
     75 
     76 #if NKSYMS || defined(DDB) || defined(MODULAR)
     77 #include <sys/exec_elf.h>
     78 #endif
     79 
     80 #include <uvm/uvm_extern.h>
     81 
     82 #include <sys/sysctl.h>
     83 
     84 #include <machine/cpu.h>
     85 #define _M68K_BUS_DMA_PRIVATE
     86 #define _M68K_BUS_SPACE_PRIVATE
     87 #include <machine/bus.h>
     88 #undef _M68K_BUS_DMA_PRIVATE
     89 #undef _M68K_BUS_SPACE_PRIVATE
     90 #include <machine/pcb.h>
     91 #include <machine/prom.h>
     92 #include <machine/psl.h>
     93 #include <machine/pte.h>
     94 #include <machine/vmparam.h>
     95 #include <m68k/include/cacheops.h>
     96 #include <dev/cons.h>
     97 #include <dev/mm.h>
     98 
     99 #include <machine/kcore.h>	/* XXX should be pulled in by sys/kcore.h */
    100 
    101 #include <mvme68k/dev/mainbus.h>
    102 #include <m68k/seglist.h>
    103 
    104 #ifdef DDB
    105 #include <machine/db_machdep.h>
    106 #include <ddb/db_extern.h>
    107 #include <ddb/db_output.h>
    108 #endif
    109 
    110 #define	MAXMEM	64*1024	/* XXX - from cmap.h */
    111 
    112 /*
    113  * Model information, filled in by the Bug; see locore.s
    114  */
    115 struct	mvmeprom_brdid  boardid;
    116 
    117 /*
    118  * The driver for the ethernet chip appropriate to the
    119  * platform (lance or i82586) will use this variable
    120  * to size the chip's packet buffer.
    121  */
    122 #ifndef ETHER_DATA_BUFF_PAGES
    123 #define	ETHER_DATA_BUFF_PAGES	4
    124 #endif
    125 u_long	ether_data_buff_size = ETHER_DATA_BUFF_PAGES * PAGE_SIZE;
    126 uint8_t	mvme_ea[6];
    127 
    128 extern	u_int lowram;
    129 
    130 /*
    131  * Default delay_divisor to the "worst case" 60MHz 68060.
    132  */
    133 int	delay_divisor = delay_divisor_est60(60);
    134 
    135 /* Machine-dependent initialization routines. */
    136 void	machine_init(paddr_t);
    137 
    138 #ifdef MVME147
    139 #include <mvme68k/dev/pccreg.h>
    140 void	mvme147_init(void);
    141 #endif
    142 
    143 #if defined(MVME162) || defined(MVME167) || defined(MVME172) || defined(MVME177)
    144 #include <dev/mvme/pcctworeg.h>
    145 void	mvme1xx_init(void);
    146 #endif
    147 
    148 /*
    149  * Early initialization, right before main is called.
    150  */
    151 void
    152 machine_init(paddr_t nextpa)
    153 {
    154 	extern paddr_t msgbufpa;
    155 
    156 	/*
    157 	 * Since mvme68k boards can have anything from 4MB of onboard RAM, we
    158 	 * would rather set the pager_map_size at runtime based on the amount
    159 	 * of onboard RAM.
    160 	 *
    161 	 * Set pager_map_size to half the size of onboard RAM, up to a
    162 	 * maximum of 16MB.
    163 	 * (Note: Just use ps_end here since onboard RAM starts at 0x0)
    164 	 */
    165 	pager_map_size = phys_seg_list[0].ps_end / 2;
    166 	if (pager_map_size > (16 * 1024 * 1024))
    167 		pager_map_size = 16 * 1024 * 1024;
    168 
    169 	/*
    170 	 * Put the kernel message buffer at the end of on-board RAM;
    171 	 * VME memory has to be zero'd to initialize parity.
    172 	 *
    173 	 * (This means we have to fully initialize the first phys seg
    174 	 * entry.)
    175 	 */
    176 	phys_seg_list[0].ps_start = phys_seg_list[0].ps_avail_start =
    177 	    m68k_round_page(phys_seg_list[0].ps_start);
    178 	phys_seg_list[0].ps_end = phys_seg_list[0].ps_avail_end =
    179 	    m68k_trunc_page(phys_seg_list[0].ps_end);
    180 
    181 	phys_seg_list[0].ps_avail_end -= m68k_round_page(MSGBUFSIZE);
    182 	msgbufpa = phys_seg_list[0].ps_avail_end;
    183 
    184 	machine_init_common(nextpa);
    185 
    186 	switch (machineid) {
    187 #ifdef MVME147
    188 	case MVME_147:
    189 		mvme147_init();
    190 		break;
    191 #endif
    192 #ifdef MVME167
    193 	case MVME_167:
    194 #endif
    195 #ifdef MVME162
    196 	case MVME_162:
    197 #endif
    198 #ifdef MVME177
    199 	case MVME_177:
    200 #endif
    201 #ifdef MVME172
    202 	case MVME_172:
    203 #endif
    204 #if defined(MVME162) || defined(MVME167) || defined(MVME172) || defined(MVME177)
    205 		mvme1xx_init();
    206 		break;
    207 #endif
    208 	default:
    209 		panic("%s: impossible machineid", __func__);
    210 	}
    211 }
    212 
    213 #ifdef MVME147
    214 /*
    215  * MVME-147 specific initialization.
    216  */
    217 void
    218 mvme147_init(void)
    219 {
    220 	bus_space_tag_t bt = &m68k_simple_bus_space;
    221 	bus_space_handle_t bh;
    222 
    223 	/*
    224 	 * Set up a temporary mapping to the PCC's registers
    225 	 */
    226 	bus_space_map(bt, intiobase_phys + MAINBUS_PCC_OFFSET, PCCREG_SIZE, 0,
    227 	    &bh);
    228 
    229 	/*
    230 	 * calibrate delay() using the 6.25 usec counter.
    231 	 * we adjust the delay_divisor until we get the result we want.
    232 	 */
    233 	bus_space_write_1(bt, bh, PCCREG_TMR1_CONTROL, PCC_TIMERCLEAR);
    234 	bus_space_write_2(bt, bh, PCCREG_TMR1_PRELOAD, 0);
    235 	bus_space_write_1(bt, bh, PCCREG_TMR1_INTR_CTRL, 0);
    236 
    237 	/*
    238 	 * See delay_divisor_est() definition and recommendation to
    239 	 * assume a bit slower than you'll actually see.
    240 	 */
    241 	for (delay_divisor = delay_divisor_est(delay_calibration_weight(16));
    242 	     delay_divisor > 0; delay_divisor--) {
    243 		bus_space_write_1(bt, bh, PCCREG_TMR1_CONTROL, PCC_TIMERSTART);
    244 		delay(10000);
    245 		bus_space_write_1(bt, bh, PCCREG_TMR1_CONTROL, PCC_TIMERSTOP);
    246 
    247 		/* 1600 * 6.25usec == 10000usec */
    248 		if (bus_space_read_2(bt, bh, PCCREG_TMR1_COUNT) > 1600)
    249 			break;	/* got it! */
    250 
    251 		bus_space_write_1(bt, bh, PCCREG_TMR1_CONTROL, PCC_TIMERCLEAR);
    252 		/* retry! */
    253 	}
    254 	/* just in case */
    255 	if (delay_divisor == 0) {
    256 		delay_divisor = 1;
    257 	}
    258 
    259 	bus_space_unmap(bt, bh, PCCREG_SIZE);
    260 
    261 	/* calculate cpuspeed */
    262 	cpuspeed_khz = delay_divisor_est(delay_divisor) * 1000;
    263 }
    264 #endif /* MVME147 */
    265 
    266 #if defined(MVME162) || defined(MVME167) || defined(MVME172) || defined(MVME177)
    267 int	get_cpuspeed(void);
    268 
    269 /*
    270  * MVME-1[67]x specific initialization.
    271  */
    272 void
    273 mvme1xx_init(void)
    274 {
    275 	bus_space_tag_t bt = &m68k_simple_bus_space;
    276 	bus_space_handle_t bh;
    277 
    278 	/*
    279 	 * Set up a temporary mapping to the PCCChip2's registers
    280 	 */
    281 	bus_space_map(bt,
    282 	    intiobase_phys + MAINBUS_PCCTWO_OFFSET + PCCTWO_REG_OFF,
    283 	    PCC2REG_SIZE, 0, &bh);
    284 
    285 	bus_space_write_1(bt, bh, PCC2REG_TIMER1_ICSR, 0);
    286 
    287 	/*
    288 	 * See delay_divisor_est() definition and recommendation to
    289 	 * assume a bit slower than you'll actually see.
    290 	 */
    291 	if (cputype == CPU_68060) {
    292 		/* MVME-177 came in a 50MHz variant. */
    293 		delay_divisor =
    294 		    delay_divisor_est60(delay_calibration_weight(50));
    295 	} else {
    296 		/* MVME-162 came in 25Hz variant. */
    297 		delay_divisor =
    298 		    delay_divisor_est40(delay_calibration_weight(25));
    299 	}
    300 	for (; delay_divisor > 0; delay_divisor--) {
    301 		bus_space_write_4(bt, bh, PCC2REG_TIMER1_COUNTER, 0);
    302 		bus_space_write_1(bt, bh, PCC2REG_TIMER1_CONTROL,
    303 		    PCCTWO_TT_CTRL_CEN);
    304 		delay(10000);
    305 		bus_space_write_1(bt, bh, PCC2REG_TIMER1_CONTROL, 0);
    306 		if (bus_space_read_4(bt, bh, PCC2REG_TIMER1_COUNTER) > 10000)
    307 			break;	/* got it! */
    308 	}
    309 
    310 	bus_space_unmap(bt, bh, PCC2REG_SIZE);
    311 
    312 	/* calculate cpuspeed */
    313 	cpuspeed_khz = get_cpuspeed();
    314 	if (cpuspeed_khz < 12500 || cpuspeed_khz > 60000) {
    315 		printf("%s: Warning! Firmware has " \
    316 		    "bogus CPU speed: `%s'\n", __func__, boardid.speed);
    317 		cpuspeed_khz = ((cputype == CPU_68060)
    318 		    ? delay_divisor_est60(delay_divisor)
    319 		    : delay_divisor_est40(delay_divisor)) * 1000;
    320 		printf("%s: Approximating speed using delay_divisor\n",
    321 		    __func__);
    322 	}
    323 }
    324 
    325 /*
    326  * Parse the `speed' field of Bug's boardid structure.  Returns
    327  * value in kHz.
    328  */
    329 int
    330 get_cpuspeed(void)
    331 {
    332 	int rv, i;
    333 
    334 	for (i = 0, rv = 0; i < sizeof(boardid.speed); i++) {
    335 		if (boardid.speed[i] < '0' || boardid.speed[i] > '9')
    336 			return 0;
    337 		rv = (rv * 10) + (boardid.speed[i] - '0');
    338 	}
    339 
    340 	return rv * 10;
    341 }
    342 #endif
    343 
    344 /*
    345  * Console initialization: called early on from main,
    346  * before vm init or startup.  Do enough configuration
    347  * to choose and initialize a console.
    348  */
    349 void
    350 consinit(void)
    351 {
    352 
    353 	/*
    354 	 * Initialize the console before we print anything out.
    355 	 */
    356 	cninit();
    357 
    358 #if NKSYMS || defined(DDB) || defined(MODULAR)
    359 	{
    360 		extern char end[];
    361 		extern int *esym;
    362 
    363 		ksyms_addsyms_elf((int)esym - (int)&end - sizeof(Elf32_Ehdr),
    364 		    (void *)&end, esym);
    365 	}
    366 #endif
    367 #ifdef DDB
    368 	if (boothowto & RB_KDB)
    369 		Debugger();
    370 #endif
    371 }
    372 
    373 /*
    374  * We want to print additional detail about on-board vs. VME memory.
    375  */
    376 void
    377 cpu_startup_print_total_memory(void (*pr)(const char *, ...)
    378 			       __printflike(1, 2))
    379 {
    380 	u_quad_t vmememsize;
    381 	char pbuf[9];
    382 	u_int i;
    383 
    384 	format_bytes(pbuf, sizeof(pbuf), ctob(physmem));
    385 	(*pr)("total memory = %s", pbuf);
    386 
    387 	for (vmememsize = 0, i = 1; i < VM_PHYSSEG_MAX; i++) {
    388 		vmememsize +=
    389 		    phys_seg_list[i].ps_end - phys_seg_list[i].ps_start;
    390 	}
    391 	if (vmememsize != 0) {
    392 		format_bytes(pbuf, sizeof(pbuf),
    393 		    phys_seg_list[0].ps_end - phys_seg_list[0].ps_start);
    394 		(*pr)(" (%s on-board", pbuf);
    395 		format_bytes(pbuf, sizeof(pbuf), vmememsize);
    396 		(*pr)(", %s VMEbus)", pbuf);
    397 	}
    398 
    399 	(*pr)("\n");
    400 }
    401 
    402 void
    403 machine_set_model(void)
    404 {
    405 	char board_str[16];
    406 	char *suffix = (char *)&boardid.suffix;
    407 	int len = snprintf(board_str, sizeof(board_str), "%x", machineid);
    408 
    409 	if (suffix[0] != '\0' && len > 0 && len + 3 < sizeof(board_str)) {
    410 		board_str[len++] = suffix[0];
    411 		if (suffix[1] != '\0')
    412 			board_str[len++] = suffix[1];
    413 		board_str[len] = '\0';
    414 	}
    415 	cpu_setmodel("Motorola MVME-%s", board_str);
    416 }
    417 
    418 /*
    419  * machine dependent system variables.
    420  */
    421 SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup")
    422 {
    423 
    424 	sysctl_createv(clog, 0, NULL, NULL,
    425 		       CTLFLAG_PERMANENT,
    426 		       CTLTYPE_NODE, "machdep", NULL,
    427 		       NULL, 0, NULL, 0,
    428 		       CTL_MACHDEP, CTL_EOL);
    429 
    430 	sysctl_createv(clog, 0, NULL, NULL,
    431 		       CTLFLAG_PERMANENT,
    432 		       CTLTYPE_STRUCT, "console_device", NULL,
    433 		       sysctl_consdev, 0, NULL, sizeof(dev_t),
    434 		       CTL_MACHDEP, CPU_CONSDEV, CTL_EOL);
    435 }
    436 
    437 void
    438 cpu_reboot(int howto, char *bootstr)
    439 {
    440 	/* Save the RB_SBOOT flag. */
    441 	howto |= (boothowto & RB_SBOOT);
    442 	cpu_reboot_common(howto, bootstr);
    443 }
    444 
    445 /*
    446  * Level 7 interrupts are caused by e.g. the ABORT switch.
    447  *
    448  * If we have DDB, then break into DDB on ABORT.  In a production
    449  * environment, bumping the ABORT switch would be bad, so we enable
    450  * panic'ing on ABORT with the kernel option "PANICBUTTON".
    451  */
    452 int
    453 nmihand(void *arg)
    454 {
    455 
    456 	mvme68k_abort("ABORT SWITCH");
    457 
    458 	return 1;
    459 }
    460 
    461 /*
    462  * Common code for handling ABORT signals from buttons, switches,
    463  * serial lines, etc.
    464  */
    465 void
    466 mvme68k_abort(const char *cp)
    467 {
    468 
    469 #ifdef DDB
    470 	db_printf("%s\n", cp);
    471 	Debugger();
    472 #else
    473 #ifdef PANICBUTTON
    474 	panic(cp);
    475 #else
    476 	printf("%s ignored\n", cp);
    477 #endif /* PANICBUTTON */
    478 #endif /* DDB */
    479 }
    480