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