xref: /netbsd/sys/arch/macppc/macppc/machdep.c (revision c4a72b64)
1 /*	$NetBSD: machdep.c,v 1.121 2002/09/25 22:21:12 thorpej 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 "opt_compat_netbsd.h"
35 #include "opt_ddb.h"
36 #include "opt_kgdb.h"
37 #include "opt_ipkdb.h"
38 #include "opt_altivec.h"
39 #include "opt_multiprocessor.h"
40 #include "adb.h"
41 #include "zsc.h"
42 
43 #include <sys/param.h>
44 #include <sys/buf.h>
45 #include <sys/exec.h>
46 #include <sys/malloc.h>
47 #include <sys/mbuf.h>
48 #include <sys/mount.h>
49 #include <sys/msgbuf.h>
50 #include <sys/proc.h>
51 #include <sys/reboot.h>
52 #include <sys/syscallargs.h>
53 #include <sys/syslog.h>
54 #include <sys/systm.h>
55 #include <sys/kernel.h>
56 #include <sys/user.h>
57 #include <sys/boot_flag.h>
58 
59 #include <uvm/uvm_extern.h>
60 
61 #include <net/netisr.h>
62 
63 #ifdef DDB
64 #include <machine/db_machdep.h>
65 #include <ddb/db_extern.h>
66 #endif
67 
68 #ifdef KGDB
69 #include <sys/kgdb.h>
70 #endif
71 
72 #ifdef IPKDB
73 #include <ipkdb/ipkdb.h>
74 #endif
75 
76 #include <machine/autoconf.h>
77 #include <machine/bat.h>
78 #include <machine/powerpc.h>
79 #include <machine/trap.h>
80 #include <machine/bus.h>
81 #include <machine/fpu.h>
82 #ifdef ALTIVEC
83 #include <powerpc/altivec.h>
84 #endif
85 
86 #include <dev/cons.h>
87 #include <dev/ofw/openfirm.h>
88 
89 #include <dev/wscons/wsksymvar.h>
90 #include <dev/wscons/wscons_callbacks.h>
91 
92 #include <dev/usb/ukbdvar.h>
93 
94 #include <macppc/dev/adbvar.h>
95 
96 #if NZSC > 0
97 #include <machine/z8530var.h>
98 #endif
99 
100 extern int ofmsr;
101 
102 char bootpath[256];
103 static int chosen;
104 struct pmap ofw_pmap;
105 int ofkbd_ihandle;
106 
107 #ifdef DDB
108 void *startsym, *endsym;
109 #endif
110 
111 struct ofw_translations {
112 	vaddr_t va;
113 	int len;
114 	paddr_t pa;
115 	int mode;
116 };
117 
118 int ofkbd_cngetc(dev_t);
119 void cninit_kd(void);
120 int lcsplx(int);
121 int save_ofmap(struct ofw_translations *, int);
122 void restore_ofmap(struct ofw_translations *, int);
123 static void dumpsys(void);
124 
125 void
126 initppc(startkernel, endkernel, args)
127 	u_int startkernel, endkernel;
128 	char *args;
129 {
130 	struct ofw_translations *ofmap;
131 	int ofmaplen;
132 
133 	mpc6xx_batinit(0x80000000, BAT_BL_256M, 0xf0000000, BAT_BL_256M,
134 	    0x90000000, BAT_BL_256M, 0xa0000000, BAT_BL_256M,
135 	    0xb0000000, BAT_BL_256M, 0);
136 	mpc6xx_init(ext_intr);
137 
138 	chosen = OF_finddevice("/chosen");
139 
140 	ofmaplen = save_ofmap(NULL, 0);
141 	ofmap = alloca(ofmaplen);
142 	save_ofmap(ofmap, ofmaplen);
143 
144 #ifdef	__notyet__		/* Needs some rethinking regarding real/virtual OFW */
145 	OF_set_callback(callback);
146 #endif
147 
148 	ofmsr &= ~PSL_IP;
149 
150 	/*
151 	 * Parse arg string.
152 	 */
153 #ifdef DDB
154 	memcpy(&startsym, args + strlen(args) + 1, sizeof(startsym));
155 	memcpy(&endsym, args + strlen(args) + 5, sizeof(endsym));
156 	if (startsym == NULL || endsym == NULL)
157 		startsym = endsym = NULL;
158 #endif
159 
160 	strcpy(bootpath, args);
161 	args = bootpath;
162 	while (*++args && *args != ' ');
163 	if (*args) {
164 		*args++ = 0;
165 		while (*args)
166 			BOOT_FLAG(*args++, boothowto);
167 	}
168 
169 	/*
170 	 * i386 port says, that this shouldn't be here,
171 	 * but I really think the console should be initialized
172 	 * as early as possible.
173 	 */
174 	consinit();
175 
176 	/*
177 	 * Set the page size.
178 	 */
179 	uvm_setpagesize();
180 
181 	/*
182 	 * Initialize pmap module.
183 	 */
184 	pmap_bootstrap(startkernel, endkernel, NULL);
185 
186 	restore_ofmap(ofmap, ofmaplen);
187 }
188 
189 int
190 save_ofmap(ofmap, maxlen)
191 	struct ofw_translations *ofmap;
192 	int maxlen;
193 {
194 	int mmui, mmu, len;
195 
196 	OF_getprop(chosen, "mmu", &mmui, sizeof mmui);
197 	mmu = OF_instance_to_package(mmui);
198 
199 	if (ofmap) {
200 		memset(ofmap, 0, maxlen);	/* to be safe */
201 		len = OF_getprop(mmu, "translations", ofmap, maxlen);
202 	} else
203 		len = OF_getproplen(mmu, "translations");
204 
205 	return len;
206 }
207 
208 void
209 restore_ofmap(ofmap, len)
210 	struct ofw_translations *ofmap;
211 	int len;
212 {
213 	int n = len / sizeof(struct ofw_translations);
214 	int i;
215 
216 	pmap_pinit(&ofw_pmap);
217 
218 	ofw_pmap.pm_sr[KERNEL_SR] = KERNEL_SEGMENT;
219 #ifdef KERNEL2_SR
220 	ofw_pmap.pm_sr[KERNEL2_SR] = KERNEL2_SEGMENT;
221 #endif
222 
223 	for (i = 0; i < n; i++) {
224 		paddr_t pa = ofmap[i].pa;
225 		vaddr_t va = ofmap[i].va;
226 		int len = ofmap[i].len;
227 
228 		if (va < 0xf0000000)			/* XXX */
229 			continue;
230 
231 		while (len > 0) {
232 			pmap_enter(&ofw_pmap, va, pa, VM_PROT_ALL,
233 			    VM_PROT_ALL|PMAP_WIRED);
234 			pa += NBPG;
235 			va += NBPG;
236 			len -= NBPG;
237 		}
238 	}
239 	pmap_update(&ofw_pmap);
240 }
241 
242 /*
243  * Machine dependent startup code.
244  */
245 void
246 cpu_startup()
247 {
248 	mpc6xx_startup(NULL);
249 }
250 
251 /*
252  * consinit
253  * Initialize system console.
254  */
255 void
256 consinit()
257 {
258 	static int initted;
259 
260 	if (initted)
261 		return;
262 	initted = 1;
263 	cninit();
264 
265 #ifdef DDB
266 	ddb_init((int)((u_int)endsym - (u_int)startsym), startsym, endsym);
267 	if (boothowto & RB_KDB)
268 		Debugger();
269 #endif
270 
271 #ifdef IPKDB
272 	ipkdb_init();
273 	if (boothowto & RB_KDB)
274 		ipkdb_connect(0);
275 #endif
276 
277 #ifdef KGDB
278 #if NZSC > 0
279 	zs_kgdb_init();
280 #endif
281 	if (boothowto & RB_KDB)
282 		kgdb_connect(1);
283 #endif
284 }
285 
286 /*
287  * Crash dump handling.
288  */
289 
290 void
291 dumpsys()
292 {
293 	printf("dumpsys: TBD\n");
294 }
295 
296 #include "zsc.h"
297 #include "com.h"
298 /*
299  * Soft tty interrupts.
300  */
301 void
302 softserial()
303 {
304 #if NZSC > 0
305 	zssoft(NULL);
306 #endif
307 #if NCOM > 0
308 	comsoft();
309 #endif
310 }
311 
312 #if 0
313 /*
314  * Stray interrupts.
315  */
316 void
317 strayintr(irq)
318 	int irq;
319 {
320 	log(LOG_ERR, "stray interrupt %d\n", irq);
321 }
322 #endif
323 
324 /*
325  * Halt or reboot the machine after syncing/dumping according to howto.
326  */
327 void
328 cpu_reboot(howto, what)
329 	int howto;
330 	char *what;
331 {
332 	static int syncing;
333 	static char str[256];
334 	char *ap = str, *ap1 = ap;
335 
336 	boothowto = howto;
337 	if (!cold && !(howto & RB_NOSYNC) && !syncing) {
338 		syncing = 1;
339 		vfs_shutdown();		/* sync */
340 		resettodr();		/* set wall clock */
341 	}
342 
343 #ifdef MULTIPROCESSOR
344 	/* Halt other CPU.  XXX for now... */
345 	macppc_send_ipi(&cpu_info[1 - cpu_number()], MACPPC_IPI_HALT);
346 	delay(100000);	/* XXX */
347 #endif
348 
349 	splhigh();
350 
351 	if (!cold && (howto & RB_DUMP))
352 		dumpsys();
353 
354 	doshutdownhooks();
355 
356 	if ((howto & RB_POWERDOWN) == RB_POWERDOWN) {
357 #if NADB > 0
358 		delay(1000000);
359 		adb_poweroff();
360 		printf("WARNING: powerdown failed!\n");
361 #endif
362 	}
363 
364 	if (howto & RB_HALT) {
365 		printf("halted\n\n");
366 
367 		/* flush cache for msgbuf */
368 		__syncicache((void *)msgbuf_paddr, round_page(MSGBUFSIZE));
369 
370 		ppc_exit();
371 	}
372 
373 	printf("rebooting\n\n");
374 	if (what && *what) {
375 		if (strlen(what) > sizeof str - 5)
376 			printf("boot string too large, ignored\n");
377 		else {
378 			strcpy(str, what);
379 			ap1 = ap = str + strlen(str);
380 			*ap++ = ' ';
381 		}
382 	}
383 	*ap++ = '-';
384 	if (howto & RB_SINGLE)
385 		*ap++ = 's';
386 	if (howto & RB_KDB)
387 		*ap++ = 'd';
388 	*ap++ = 0;
389 	if (ap[-2] == '-')
390 		*ap1 = 0;
391 
392 	/* flush cache for msgbuf */
393 	__syncicache((void *)msgbuf_paddr, round_page(MSGBUFSIZE));
394 
395 #if NADB > 0
396 	adb_restart();	/* not return */
397 #endif
398 	ppc_exit();
399 }
400 
401 #if 0
402 /*
403  * OpenFirmware callback routine
404  */
405 void
406 callback(p)
407 	void *p;
408 {
409 	panic("callback");	/* for now			XXX */
410 }
411 #endif
412 
413 int
414 lcsplx(ipl)
415 	int ipl;
416 {
417 	return spllower(ipl); 	/* XXX */
418 }
419 
420 #include "akbd.h"
421 #include "ukbd.h"
422 #include "ofb.h"
423 #include "ite.h"
424 #include "zstty.h"
425 
426 void
427 cninit()
428 {
429 #if (NITE > 0 || NZSTTY > 0)
430 	struct consdev *cp;
431 #endif /* (NITE > 0 || NZSTTY > 0) */
432 	int stdout, node;
433 	char type[16];
434 
435 	if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout))
436 	    != sizeof(stdout))
437 		goto nocons;
438 
439 	node = OF_instance_to_package(stdout);
440 	memset(type, 0, sizeof(type));
441 	if (OF_getprop(node, "device_type", type, sizeof(type)) == -1)
442 		goto nocons;
443 
444 #if NOFB > 0
445 	if (strcmp(type, "display") == 0) {
446 		cninit_kd();
447 		return;
448 	}
449 #endif /* NOFB > 0 */
450 
451 #if NITE > 0
452 	if (strcmp(type, "display") == 0) {
453 		extern struct consdev consdev_ite;
454 
455 		cp = &consdev_ite;
456 		(*cp->cn_probe)(cp);
457 		(*cp->cn_init)(cp);
458 		cn_tab = cp;
459 
460 		return;
461 	}
462 #endif
463 
464 #if NZSTTY > 0
465 	if (strcmp(type, "serial") == 0) {
466 		extern struct consdev consdev_zs;
467 
468 		cp = &consdev_zs;
469 		(*cp->cn_probe)(cp);
470 		(*cp->cn_init)(cp);
471 		cn_tab = cp;
472 
473 		return;
474 	}
475 #endif
476 
477 nocons:
478 	return;
479 }
480 
481 #if NOFB > 0
482 struct usb_kbd_ihandles {
483 	struct usb_kbd_ihandles *next;
484 	int ihandle;
485 };
486 
487 void
488 cninit_kd()
489 {
490 	int stdin, node;
491 	char name[16];
492 #if NAKBD > 0
493 	int akbd;
494 #endif
495 #if NUKBD > 0
496 	struct usb_kbd_ihandles *ukbds;
497 	int ukbd;
498 #endif
499 
500 	/*
501 	 * Attach the console output now (so we can see debugging messages,
502 	 * if any).
503 	 */
504 	ofb_cnattach();
505 
506 	/*
507 	 * We must determine which keyboard type we have.
508 	 */
509 	if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin))
510 	    != sizeof(stdin)) {
511 		printf("WARNING: no `stdin' property in /chosen\n");
512 		return;
513 	}
514 
515 	node = OF_instance_to_package(stdin);
516 	memset(name, 0, sizeof(name));
517 	OF_getprop(node, "name", name, sizeof(name));
518 	if (strcmp(name, "keyboard") != 0) {
519 		printf("WARNING: stdin is not a keyboard: %s\n", name);
520 		return;
521 	}
522 
523 #if NAKBD > 0
524 	memset(name, 0, sizeof(name));
525 	OF_getprop(OF_parent(node), "name", name, sizeof(name));
526 	if (strcmp(name, "adb") == 0) {
527 		printf("console keyboard type: ADB\n");
528 		akbd_cnattach();
529 		goto kbd_found;
530 	}
531 #endif
532 
533 	/*
534 	 * We're not an ADB keyboard; must be USB.  Unfortunately,
535 	 * we have a few problems:
536 	 *
537 	 *	(1) The stupid Macintosh firmware uses a
538 	 *	    `psuedo-hid' (yes, they even spell it
539 	 *	    incorrectly!) which apparently merges
540 	 *	    all USB keyboard input into a single
541 	 *	    input stream.  Because of this, we can't
542 	 *	    actually determine which USB controller
543 	 *	    or keyboard is really the console keyboard!
544 	 *
545 	 *	(2) Even if we could, USB requires a lot of
546 	 *	    the kernel to be running in order for it
547 	 *	    to work.
548 	 *
549 	 * So, what we do is this:
550 	 *
551 	 *	(1) Tell the ukbd driver that it is the console.
552 	 *	    At autoconfiguration time, it will attach the
553 	 *	    first USB keyboard instance as the console
554 	 *	    keyboard.
555 	 *
556 	 *	(2) Until then, so that we have _something_, we
557 	 *	    use the OpenFirmware I/O facilities to read
558 	 *	    the keyboard.
559 	 */
560 
561 	/*
562 	 * stdin is /psuedo-hid/keyboard.  Test `adb-kbd-ihandle and
563 	 * `usb-kbd-ihandles to figure out the real keyboard(s).
564 	 *
565 	 * XXX This must be called before pmap_bootstrap().
566 	 */
567 
568 #if NUKBD > 0
569 	if (OF_call_method("`usb-kbd-ihandles", stdin, 0, 1, &ukbds) >= 0 &&
570 	    ukbds != NULL && ukbds->ihandle != 0 &&
571 	    OF_instance_to_package(ukbds->ihandle) != -1) {
572 		printf("console keyboard type: USB\n");
573 		ukbd_cnattach();
574 		goto kbd_found;
575 	}
576 	/* Try old method name. */
577 	if (OF_call_method("`usb-kbd-ihandle", stdin, 0, 1, &ukbd) >= 0 &&
578 	    ukbd != 0 &&
579 	    OF_instance_to_package(ukbd) != -1) {
580 		printf("console keyboard type: USB\n");
581 		stdin = ukbd;
582 		ukbd_cnattach();
583 		goto kbd_found;
584 	}
585 #endif
586 
587 #if NAKBD > 0
588 	if (OF_call_method("`adb-kbd-ihandle", stdin, 0, 1, &akbd) >= 0 &&
589 	    akbd != 0 &&
590 	    OF_instance_to_package(akbd) != -1) {
591 		printf("console keyboard type: ADB\n");
592 		stdin = akbd;
593 		akbd_cnattach();
594 		goto kbd_found;
595 	}
596 #endif
597 
598 #if NUKBD > 0
599 	/*
600 	 * XXX Old firmware does not have `usb-kbd-ihandles method.  Assume
601 	 * XXX USB keyboard anyway.
602 	 */
603 	printf("console keyboard type: USB\n");
604 	ukbd_cnattach();
605 	goto kbd_found;
606 #endif
607 
608 	/*
609 	 * No keyboard is found.  Just return.
610 	 */
611 	printf("no console keyboard\n");
612 	return;
613 
614 #if NAKBD + NUKBD > 0
615 kbd_found:
616 	/*
617 	 * XXX This is a little gross, but we don't get to call
618 	 * XXX wskbd_cnattach() twice.
619 	 */
620 	ofkbd_ihandle = stdin;
621 	wsdisplay_set_cons_kbd(ofkbd_cngetc, NULL, NULL);
622 #endif
623 }
624 #endif
625 
626 /*
627  * Bootstrap console keyboard routines, using OpenFirmware I/O.
628  */
629 int
630 ofkbd_cngetc(dev)
631 	dev_t dev;
632 {
633 	u_char c = '\0';
634 	int len;
635 
636 	do {
637 		len = OF_read(ofkbd_ihandle, &c, 1);
638 	} while (len != 1);
639 
640 	return c;
641 }
642 
643 #ifdef MULTIPROCESSOR
644 /*
645  * Save a process's FPU state to its PCB.  The state is in another CPU
646  * (though by the time our IPI is processed, it may have been flushed already).
647  */
648 void
649 mp_save_fpu_proc(p)
650 	struct proc *p;
651 {
652 	struct pcb *pcb = &p->p_addr->u_pcb;
653 	struct cpu_info *fpcpu;
654 	int i;
655 
656 	/*
657 	 * Send an IPI to the other CPU with the data and wait for that CPU
658 	 * to flush the data.  Note that the other CPU might have switched
659 	 * to a different proc's FPU state by the time it receives the IPI,
660 	 * but that will only result in an unnecessary reload.
661 	 */
662 
663 	fpcpu = pcb->pcb_fpcpu;
664 	if (fpcpu == NULL) {
665 		return;
666 	}
667 	macppc_send_ipi(fpcpu, MACPPC_IPI_FLUSH_FPU);
668 
669 	/* Wait for flush. */
670 #if 0
671 	while (pcb->pcb_fpcpu)
672 		;
673 #else
674 	for (i = 0; i < 0x3fffffff; i++) {
675 		if (pcb->pcb_fpcpu == NULL)
676 			return;
677 	}
678 	printf("mp_save_fpu_proc{%d} pid = %d, fpcpu->ci_cpuid = %d\n",
679 	    cpu_number(), p->p_pid, fpcpu->ci_cpuid);
680 	panic("mp_save_fpu_proc");
681 #endif
682 }
683 
684 #ifdef ALTIVEC
685 /*
686  * Save a process's AltiVEC state to its PCB.  The state may be in any CPU.
687  * The process must either be curproc or traced by curproc (and stopped).
688  * (The point being that the process must not run on another CPU during
689  * this function).
690  */
691 void
692 mp_save_vec_proc(p)
693 	struct proc *p;
694 {
695 	struct pcb *pcb = &p->p_addr->u_pcb;
696 	struct cpu_info *veccpu;
697 	int i;
698 
699 	/*
700 	 * Send an IPI to the other CPU with the data and wait for that CPU
701 	 * to flush the data.  Note that the other CPU might have switched
702 	 * to a different proc's AltiVEC state by the time it receives the IPI,
703 	 * but that will only result in an unnecessary reload.
704 	 */
705 
706 	veccpu = pcb->pcb_veccpu;
707 	if (veccpu == NULL) {
708 		return;
709 	}
710 	macppc_send_ipi(veccpu, MACPPC_IPI_FLUSH_VEC);
711 
712 	/* Wait for flush. */
713 #if 0
714 	while (pcb->pcb_veccpu)
715 		;
716 #else
717 	for (i = 0; i < 0x3fffffff; i++) {
718 		if (pcb->pcb_veccpu == NULL)
719 			return;
720 	}
721 	printf("mp_save_vec_proc{%d} pid = %d, veccpu->ci_cpuid = %d\n",
722 	    cpu_number(), p->p_pid, veccpu->ci_cpuid);
723 	panic("mp_save_vec_proc");
724 #endif
725 }
726 #endif /* ALTIVEC */
727 #endif /* MULTIPROCESSOR */
728