xref: /plan9/sys/src/9/ppc/m8260.c (revision 5d9de2d38d2503efca29e12e0e32036368a7a75f)
1 /*
2  *	8260 specific stuff:
3  *		Interrupt handling
4  */
5 #include	"u.h"
6 #include	"../port/lib.h"
7 #include	"mem.h"
8 #include	"dat.h"
9 #include	"io.h"
10 #include	"fns.h"
11 #include	"m8260.h"
12 
13 enum {
14 	Pin4 = BIT(4),
15 };
16 
17 static union {
18 	struct {
19 		ulong	hi;
20 		ulong	lo;
21 	};
22 	uvlong		val;
23 } ticks;
24 
25 struct {
26 	ulong	hi;
27 	ulong	lo;
28 } vec2mask[64]	= {
29 [0]	= {0,		0	},	/* Error, No interrupt */
30 [1]	= {0,		BIT(16)	},	/* I2C */
31 [2]	= {0,		BIT(17)	},	/* SPI */
32 [3]	= {0,		BIT(18)	},	/* Risc Timers */
33 [4]	= {0,		BIT(19)	},	/* SMC1 */
34 [5]	= {0,		BIT(20)	},	/* SMC2 */
35 [6]	= {0,		BIT(21)	},	/* IDMA1 */
36 [7]	= {0,		BIT(22)	},	/* IDMA2 */
37 [8]	= {0,		BIT(23)	},	/* IDMA3 */
38 [9]	= {0,		BIT(24)	},	/* IDMA4 */
39 [10]	= {0,		BIT(25)	},	/* SDMA */
40 [11]	= {0,		0	},	/* Reserved */
41 [12]	= {0,		BIT(27)	},	/* Timer1 */
42 [13]	= {0,		BIT(28)	},	/* Timer2 */
43 [14]	= {0,		BIT(29)	},	/* Timer3 */
44 [15]	= {0,		BIT(30)	},	/* Timer4 */
45 
46 [16]	= {BIT(29),	0	},	/* TMCNT */
47 [17]	= {BIT(30),	0	},	/* PIT */
48 [18]	= {0,		0	},	/* Reserved */
49 [19]	= {BIT(17),	0	},	/* IRQ1 */
50 [20]	= {BIT(18),	0	},	/* IRQ2 */
51 [21]	= {BIT(19),	0	},	/* IRQ3 */
52 [22]	= {BIT(20),	0	},	/* IRQ4 */
53 [23]	= {BIT(21),	0	},	/* IRQ5 */
54 [24]	= {BIT(22),	0	},	/* IRQ6 */
55 [25]	= {BIT(23),	0	},	/* IRQ7 */
56 [26]	= {0,		0	},	/* Reserved */
57 [27]	= {0,		0	},	/* Reserved */
58 [28]	= {0,		0	},	/* Reserved */
59 [29]	= {0,		0	},	/* Reserved */
60 [30]	= {0,		0	},	/* Reserved */
61 [31]	= {0,		0	},	/* Reserved */
62 
63 [32]	= {0,		BIT(0)	},	/* FCC1 */
64 [33]	= {0,		BIT(1)	},	/* FCC2 */
65 [34]	= {0,		BIT(2)	},	/* FCC3 */
66 [35]	= {0,		0	},	/* Reserved */
67 [36]	= {0,		BIT(4)	},	/* MCC1 */
68 [37]	= {0,		BIT(5)	},	/* MCC2 */
69 [38]	= {0,		0	},	/* Reserved */
70 [39]	= {0,		0	},	/* Reserved */
71 [40]	= {0,		BIT(8)	},	/* SCC1 */
72 [41]	= {0,		BIT(9)	},	/* SCC2 */
73 [42]	= {0,		BIT(10)	},	/* SCC3 */
74 [43]	= {0,		BIT(11)	},	/* SCC4 */
75 [44]	= {0,		0	},	/* Reserved */
76 [45]	= {0,		0	},	/* Reserved */
77 [46]	= {0,		0	},	/* Reserved */
78 [47]	= {0,		0	},	/* Reserved */
79 
80 [48]	= {BIT(15),	0	},	/* PC15 */
81 [49]	= {BIT(14),	0	},	/* PC14 */
82 [50]	= {BIT(13),	0	},	/* PC13 */
83 [51]	= {BIT(12),	0	},	/* PC12 */
84 [52]	= {BIT(11),	0	},	/* PC11 */
85 [53]	= {BIT(10),	0	},	/* PC10 */
86 [54]	= {BIT(9),	0	},	/* PC9 */
87 [55]	= {BIT(8),	0	},	/* PC8 */
88 [56]	= {BIT(7),	0	},	/* PC7 */
89 [57]	= {BIT(6),	0	},	/* PC6 */
90 [58]	= {BIT(5),	0	},	/* PC5 */
91 [59]	= {BIT(4),	0	},	/* PC4 */
92 [60]	= {BIT(3),	0	},	/* PC3 */
93 [61]	= {BIT(2),	0	},	/* PC2 */
94 [62]	= {BIT(1),	0	},	/* PC1 */
95 [63]	= {BIT(0),	0	},	/* PC0 */
96 };
97 
98 /* Blast memory layout:
99  *	CS0: FE000000 -> FFFFFFFF (Flash)
100  *	CS1: FC000000 -> FCFFFFFF (DSP hpi)
101  *	CS2: 00000000 -> 03FFFFFF (60x sdram)
102  *	CS3: 04000000 -> 04FFFFFF (FPGA)
103  *	CS4: 05000000 -> 06FFFFFF (local bus sdram)
104  *	CS5: 07000000 -> 0700FFFF (eeprom - not populated)
105  *	CS6: E0000000 -> E0FFFFFF (FPGA - 64bits)
106  *
107  * Main Board memory layout:
108  *	CS0: FE000000 -> FEFFFFFF (16 M FLASH)
109  *	CS1: FC000000 -> FCFFFFFF (16 M DSP1)
110  *	CS2: 00000000 -> 03FFFFFF (64 M SDRAM)
111  *	CS3: 04000000 -> 04FFFFFF (16M DSP2)
112  *	CS4: 05000000 -> 06FFFFFF (32 M Local SDRAM)
113  *	CS5: 07000000 -> 0700FFFF (eeprom - not populated)
114  *	CS6: unused
115  *	CS7: E0000000 -> E0FFFFFF (16 M FPGA)
116  */
117 
118 IMM* iomem = (IMM*)IOMEM;
119 uchar etheraddr[6] = { 0x90, 0x85, 0x82, 0x32, 0x83, 0x00};
120 
121 static Lock cpmlock;
122 
123 void
machinit(void)124 machinit(void)
125 {
126 	ulong scmr;
127 	int pllmf;
128 	extern char* plan9inistr;
129 
130 	memset(m, 0, sizeof(*m));
131 	m->cputype = getpvr()>>16;	/* pvr = 0x00810101 for the 8260 */
132 	m->imap = (Imap*)INTMEM;
133 
134 	m->loopconst = 1096;
135 
136 	/* Make sure Ethernet is disabled (boot code may have buffers allocated anywhere in memory) */
137 	iomem->fcc[0].gfmr &= ~(BIT(27)|BIT(26));
138 	iomem->fcc[1].gfmr &= ~(BIT(27)|BIT(26));
139 	iomem->fcc[2].gfmr &= ~(BIT(27)|BIT(26));
140 
141 	/* Flashed CS configuration is wrong for DSP2.  It's set to 64 bits, should be 16 */
142 	iomem->bank[3].br = 0x04001001;	/* Set 16-bit port */
143 
144 	/*
145 	 * FPGA is capable of doing 64-bit transfers.  To use these, set br to 0xe0000001.
146 	 * Currently we use 32-bit transfers, because the 8260 does not easily do 64-bit operations.
147 	 */
148 	iomem->bank[6].br = 0xe0001801;
149 	iomem->bank[6].or = 0xff000830;	/* Was 0xff000816 */
150 
151 /*
152  * All systems with rev. A.1 (0K26N) silicon had serious problems when doing
153  * DMA transfers with data cache enabled (usually this shows when  using
154  * one of the FCC's with some traffic on the ethernet).  Allocating FCC buffer
155  * descriptors in main memory instead of DP ram solves this problem.
156  */
157 
158 	/* Guess at clocks based upon the PLL configuration from the
159 	 * power-on reset.
160 	 */
161 	scmr = iomem->scmr;
162 
163 	/* The EST8260 is typically run using either 33 or 66 MHz
164 	 * external clock.  The configuration byte in the Flash will
165 	 * tell us which is configured.  The blast appears to be slightly
166 	 * overclocked at 72 MHz (if set to 66 MHz, the uart runs too fast)
167 	 */
168 
169 	m->clkin = CLKIN;
170 
171 	pllmf = scmr & 0xfff;
172 
173 	/* This is arithmetic from the 8260 manual, section 9.4.1. */
174 
175 	/* Collect the bits from the scmr.
176 	*/
177 	m->vco_out = m->clkin * (pllmf + 1);
178 	if (scmr & BIT(19))	/* plldf (division factor is 1 or 2) */
179 		m->vco_out >>= 1;
180 
181 	m->cpmhz = m->vco_out >> 1;	/* cpm hz is half of vco_out */
182 	m->brghz = m->vco_out >> (2 * ((iomem->sccr & 0x3) + 1));
183 	m->bushz = m->vco_out / (((scmr & 0x00f00000) >> 20) + 1);
184 
185 	/* Serial init sets BRG clock....I don't know how to compute
186 	 * core clock from core configuration, but I think I know the
187 	 * mapping....
188 	 */
189 	switch(scmr >> (31-7)){
190 	case 0x0a:
191 		m->cpuhz = m->clkin * 2;
192 		break;
193 	case 0x0b:
194 		m->cpuhz = (m->clkin >> 1) * 5;
195 		break;
196 	default:
197 	case 0x0d:
198 		m->cpuhz = m->clkin * 3;
199 		break;
200 	case 0x14:
201 		m->cpuhz = (m->clkin >> 1) * 7;
202 		break;
203 	case 0x1c:
204 		m->cpuhz = m->clkin * 4;
205 		break;
206 	}
207 
208 	m->cyclefreq = m->bushz / 4;
209 
210 /*	Expect:
211 	intfreq	133		m->cpuhz
212 	busfreq	33		m->bushz
213 	cpmfreq	99		m->cpmhz
214 	brgfreq	49.5		m->brghz
215 	vco		198
216 */
217 
218 	active.machs = 1;
219 	active.exiting = 0;
220 
221 	putmsr(getmsr() | MSR_ME);
222 
223 	/*
224 	 * turn on data cache before instruction cache;
225 	 * for some reason which I don't understand,
226 	 * you can't turn on both caches at once
227 	 */
228 	icacheenb();
229 	dcacheenb();
230 
231 	kfpinit();
232 
233 	/* Plan9.ini location in flash is FLASHMEM+PLAN9INI
234 	 * if PLAN9INI == ~0, it's not stored in flash or there is no flash
235 	 * if *cp == 0xff, flash memory is not initialized
236 	 */
237 	if (PLAN9INI == ~0 ||
238 	    (uchar)*(plan9inistr = (char*)(FLASHMEM+PLAN9INI)) == 0xff){
239 		/* No plan9.ini in flash */
240 		plan9inistr =
241 			"console=0\n"
242 			"ether0=type=fcc port=0 ea=00601d051dd8\n"
243 			"flash0=mem=0xfe000000\n"
244 			"fs=135.104.9.42\n"
245 			"auth=135.104.9.7\n"
246 			"authdom=cs.bell-labs.com\n"
247 			"sys=blast\n"
248 			"ntp=135.104.9.52\n";
249 	}
250 }
251 
252 void
fpgareset(void)253 fpgareset(void)
254 {
255 	print("fpga reset\n");
256 
257 	ioplock();
258 
259 	iomem->port[1].pdat &= ~Pin4;	/* force reset signal to 0 */
260 	delay(100);
261 	iomem->port[1].pdat |= Pin4;		/* force reset signal back to one */
262 
263 	iopunlock();
264 }
265 
266 void
hwintrinit(void)267 hwintrinit(void)
268 {
269 	iomem->sicr = 2 << 8;
270 	/* Write ones into most bits of the interrupt pending registers to clear interrupts */
271 	iomem->sipnr_h = ~7;
272 	iomem->sipnr_h = ~1;
273 	/* Clear the interrupt masks, thereby disabling all interrupts */
274 	iomem->simr_h = 0;
275 	iomem->simr_l = 0;
276 
277 	iomem->sypcr &= ~2;	/* cause a machine check interrupt on memory timeout */
278 
279 	/* Initialize fpga reset pin */
280 	iomem->port[1].pdir |= Pin4;		/* 1 is an output */
281 	iomem->port[1].ppar &= ~Pin4;
282 	iomem->port[1].pdat |= Pin4;		/* force reset signal back to one */
283 }
284 
285 int
vectorenable(Vctl * v)286 vectorenable(Vctl *v)
287 {
288 	ulong hi, lo;
289 
290 	if (v->irq & ~0x3f){
291 		print("m8260enable: interrupt vector %d out of range\n", v->irq);
292 		return -1;
293 	}
294 	hi = vec2mask[v->irq].hi;
295 	lo = vec2mask[v->irq].lo;
296 	if (hi == 0 && lo == 0){
297 		print("m8260enable: nonexistent vector %d\n", v->irq);
298 		return -1;
299 	}
300 	ioplock();
301 	/* Clear the interrupt before enabling */
302 	iomem->sipnr_h |= hi;
303 	iomem->sipnr_l |= lo;
304 	/* Enable */
305 	iomem->simr_h |= hi;
306 	iomem->simr_l |= lo;
307 	iopunlock();
308 	return v->irq;
309 }
310 
311 void
vectordisable(Vctl * v)312 vectordisable(Vctl *v)
313 {
314 	ulong hi, lo;
315 
316 	if (v->irq & ~0x3f){
317 		print("m8260disable: interrupt vector %d out of range\n", v->irq);
318 		return;
319 	}
320 	hi = vec2mask[v->irq].hi;
321 	lo = vec2mask[v->irq].lo;
322 	if (hi == 0 && lo == 0){
323 		print("m8260disable: nonexistent vector %d\n", v->irq);
324 		return;
325 	}
326 	ioplock();
327 	iomem->simr_h &= ~hi;
328 	iomem->simr_l &= ~lo;
329 	iopunlock();
330 }
331 
332 int
intvec(void)333 intvec(void)
334 {
335 	return iomem->sivec >> 26;
336 }
337 
338 void
intend(int vno)339 intend(int vno)
340 {
341 	/* Clear interrupt */
342 	ioplock();
343 	iomem->sipnr_h |= vec2mask[vno].hi;
344 	iomem->sipnr_l |= vec2mask[vno].lo;
345 	iopunlock();
346 }
347 
348 int
m8260eoi(int)349 m8260eoi(int)
350 {
351 	return 0;
352 }
353 
354 int
m8260isr(int)355 m8260isr(int)
356 {
357 	return 0;
358 }
359 
360 void
flashprogpower(int)361 flashprogpower(int)
362 {
363 }
364 
365 enum {
366 	TgcrCas 			= 0x80,
367 	TgcrGm 			= 0x08,
368 	TgcrStp 			= 0x2,	/* There are two of these, timer-2 bits are bits << 4 */
369 	TgcrRst 			= 0x1,
370 
371 	TmrIclkCasc		= 0x00<<1,
372 	TmrIclkIntclock	= 0x01<<1,
373 	TmrIclkIntclock16	= 0x02<<1,
374 	TmrIclkTin		= 0x03<<1,
375 	TmrCERising		= 0x1 << 6,
376 	TmrCEFalling		= 0x2 << 6,
377 	TmrCEAny		= 0x3 << 6,
378 	TmrFrr			= SBIT(12),
379 	TmrOri			= SBIT(11),
380 
381 	TerRef			= SBIT(14),
382 	TerCap			= SBIT(15),
383 };
384 
385 uvlong
fastticks(uvlong * hz)386 fastticks(uvlong *hz)
387 {
388 	ulong count;
389 	static Lock fasttickslock;
390 
391 	if (hz)
392 		*hz = m->clkin>>1;
393 	ilock(&fasttickslock);
394 	count = iomem->tcnl1;
395 	if (count < ticks.lo)
396 		ticks.hi += 1;
397 	ticks.lo = count;
398 	iunlock(&fasttickslock);
399 	return ticks.val;
400 }
401 
402 ulong multiplier;
403 
404 ulong
s(void)405 µs(void)
406 {
407 	uvlong x;
408 
409 	if(multiplier == 0){
410 		multiplier = (uvlong)(1000000LL << 16) / m->cyclefreq;
411 		print("µs: multiplier %ld, cyclefreq %lld, shifter %d\n", multiplier, m->cyclefreq, 16);
412 	}
413 	cycles(&x);
414 	return (x*multiplier) >> 16;
415 }
416 
417 void
timerset(Tval next)418 timerset(Tval next)
419 {
420 	long offset;
421 	uvlong now;
422 	static int cnt;
423 
424 	now = fastticks(nil);
425 	offset = next - now;
426 	if (offset < 2500)
427 		next = now + 2500;	/* 10000 instructions */
428 	else if (offset > m->clkin / HZ){
429 		print("too far in the future: offset %llux, now %llux\n", next, now);
430 		next = now + m->clkin / HZ;
431 	}
432 	iomem->trrl1 = next;
433 }
434 
435 void
m8260timerintr(Ureg * u,void *)436 m8260timerintr(Ureg *u, void*)
437 {
438 	iomem->ter2 |= TerRef | TerCap;		/* Clear interrupt */
439 	timerintr(u, 0);
440 }
441 
442 void
timerinit(void)443 timerinit(void)
444 {
445 
446 	iomem->tgcr1 = TgcrCas | TgcrGm;		/* cascade timers 1 & 2, normal gate mode */
447 	iomem->tcnl1 = 0;
448 	iomem->trrl1 = m->clkin / HZ;		/* first capture in 1/HZ seconds */
449 	iomem->tmr1 = TmrIclkCasc;
450 	iomem->tmr2 = TmrIclkIntclock | TmrOri;
451 	intrenable(13, m8260timerintr, nil, "timer");	/* Timer 2 interrupt is on 13 */
452 	iomem->tgcr1 |= TgcrRst << 4;
453 }
454 
455 static void
addseg(char * name,ulong start,ulong length)456 addseg(char *name, ulong start, ulong length)
457 {
458 	Physseg segbuf;
459 
460 	memset(&segbuf, 0, sizeof(segbuf));
461 	segbuf.attr = SG_PHYSICAL;
462 	kstrdup(&segbuf.name, name);
463 	segbuf.pa = start;
464 	segbuf.size = length;
465 	if (addphysseg(&segbuf) == -1) {
466 		print("addphysseg: %s\n", name);
467 		return;
468 	}
469 }
470 
471 void
sharedseginit(void)472 sharedseginit(void)
473 {
474 	int i, j;
475 	ulong base, size;
476 	char name[16], *a, *b, *s;
477 	static char *segnames[] = {
478 		"fpga",
479 		"dsp",
480 	};
481 
482 	for (j = 0; j < nelem(segnames); j++){
483 		for (i = 0; i < 8; i++){
484 			snprint(name, sizeof name, "%s%d", segnames[j], i);
485 			if ((a = getconf(name)) == nil)
486 				continue;
487 			if ((b = strstr(a, "mem=")) == nil){
488 				print("blastseginit: %s: no base\n", name);
489 				continue;
490 			}
491 			b += 4;
492 			base = strtoul(b, nil, 0);
493 			if (base == 0){
494 				print("blastseginit: %s: bad base: %s\n", name, b);
495 				continue;
496 			}
497 			if ((s = strstr(a, "size=")) == nil){
498 				print("blastseginit: %s: no size\n", name);
499 				continue;
500 			}
501 			s += 5;
502 			size = strtoul(s, nil, 0);
503 			if (size == 0){
504 				print("blastseginit: %s: bad size: %s\n", name, s);
505 				continue;
506 			}
507 			addseg(name, base, size);
508 		}
509 	}
510 }
511 
512 void
cpmop(int op,int dev,int mcn)513 cpmop(int op, int dev, int mcn)
514 {
515 	ioplock();
516 	eieio();
517 	while(iomem->cpcr & 0x10000)
518 		eieio();
519 	iomem->cpcr = dev<<(31-10) | mcn<<(31-25) | op | 0x10000;
520 	eieio();
521 	while(iomem->cpcr & 0x10000)
522 		eieio();
523 	iopunlock();
524 }
525 
526 /*
527  * connect SCCx clocks in NSMI mode (x=1 for USB)
528  */
529 void
sccnmsi(int x,int rcs,int tcs)530 sccnmsi(int x, int rcs, int tcs)
531 {
532 	ulong v;
533 	int sh;
534 
535 	sh = (x-1)*8;	/* each SCCx field in sicr is 8 bits */
536 	v = (((rcs&7)<<3) | (tcs&7)) << sh;
537 	iomem->sicr = (iomem->sicr & ~(0xFF<<sh)) | v;
538 }
539 
540 /*
541  * lock the shared IO memory and return a reference to it
542  */
543 void
ioplock(void)544 ioplock(void)
545 {
546 	ilock(&cpmlock);
547 }
548 
549 /*
550  * release the lock on the shared IO memory
551  */
552 void
iopunlock(void)553 iopunlock(void)
554 {
555 	eieio();
556 	iunlock(&cpmlock);
557 }
558 
559 BD*
bdalloc(int n)560 bdalloc(int n)
561 {
562 	static BD *palloc = ((Imap*)INTMEM)->bd;
563 	BD *p;
564 
565 	p = palloc;
566 	if (palloc > ((Imap*)INTMEM)->bd + nelem(((Imap*)INTMEM)->bd)){
567 		print("bdalloc: out of BDs\n");
568 		return nil;
569 	}
570 	palloc += n;
571 	return p;
572 }
573 
574 /*
575  * Initialise receive and transmit buffer rings.  Only used for FCC
576  * Ethernet now.
577  *
578  * Ioringinit will allocate the buffer descriptors in normal memory
579  * and NOT in Dual-Ported Ram, as prescribed by the MPC8260
580  * PowerQUICC II manual (Section 28.6).  When they are allocated
581  * in DPram and the Dcache is enabled, the processor will hang.
582  * This has been observed for the FCCs, it may or may not be true
583  * for SCCs or DMA.
584  * The SMC Uart buffer descriptors are not allocated here; (1) they
585  * can ONLY be in DPram and (2) they are not configured as a ring.
586  */
587 int
ioringinit(Ring * r,int nrdre,int ntdre,int bufsize)588 ioringinit(Ring* r, int nrdre, int ntdre, int bufsize)
589 {
590 	int i, x;
591 	static uchar *dpmallocaddr;
592 	static uchar *dpmallocend;
593 
594 	if (dpmallocaddr == nil){
595 		dpmallocaddr = m->imap->dpram1;
596 		dpmallocend = dpmallocaddr + sizeof(m->imap->dpram1);
597 	}
598 	/* the ring entries must be aligned on sizeof(BD) boundaries */
599 	r->nrdre = nrdre;
600 	if(r->rdr == nil)
601 		r->rdr = xspanalloc(nrdre*sizeof(BD), 0, 8);
602 	if(r->rdr == nil)
603 		return -1;
604 	if(r->rrb == nil && bufsize){
605 		r->rrb = xspanalloc(nrdre*bufsize, 0, CACHELINESZ);
606 		if(r->rrb == nil)
607 			return -1;
608 	}
609 	x = bufsize ? PADDR(r->rrb) : 0;
610 	for(i = 0; i < nrdre; i++){
611 		r->rdr[i].length = 0;
612 		r->rdr[i].addr = x;
613 		r->rdr[i].status = BDEmpty|BDInt;
614 		x += bufsize;
615 	}
616 	r->rdr[i-1].status |= BDWrap;
617 	r->rdrx = 0;
618 
619 	r->ntdre = ntdre;
620 	if(r->tdr == nil)
621 		r->tdr = xspanalloc(ntdre*sizeof(BD), 0, 8);
622 	if(r->txb == nil)
623 		r->txb = xspanalloc(ntdre*sizeof(Block*), 0, CACHELINESZ);
624 	if(r->tdr == nil || r->txb == nil)
625 		return -1;
626 	for(i = 0; i < ntdre; i++){
627 		r->txb[i] = nil;
628 		r->tdr[i].addr = 0;
629 		r->tdr[i].length = 0;
630 		r->tdr[i].status = 0;
631 	}
632 	r->tdr[i-1].status |= BDWrap;
633 	r->tdrh = 0;
634 	r->tdri = 0;
635 	r->ntq = 0;
636 	return 0;
637 }
638 
639 void
trapinit(void)640 trapinit(void)
641 {
642 	int i;
643 
644 	/*
645 	 * set all exceptions to trap
646 	 */
647 	for(i = 0x0; i < 0x2000; i += 0x100)
648 		sethvec(i, trapvec);
649 
650 	setmvec(0x1000, imiss, tlbvec);
651 	setmvec(0x1100, dmiss, tlbvec);
652 	setmvec(0x1200, dmiss, tlbvec);
653 
654 /*	Useful for avoiding assembler miss handling:
655 	sethvec(0x1000, tlbvec);
656 	sethvec(0x1100, tlbvec);
657 	sethvec(0x1200, tlbvec);
658 /* */
659 	dcflush(KADDR(0), 0x2000);
660 	icflush(KADDR(0), 0x2000);
661 
662 	putmsr(getmsr() & ~MSR_IP);
663 }
664 
665 void
reboot(void *,void *,ulong)666 reboot(void*, void*, ulong)
667 {
668 	ulong *p;
669 	int x;
670 
671 	p = (ulong*)0x90000000;
672 	x = splhi();
673 	iomem->sypcr |= 0xc0;
674 	print("iomem->sypcr = 0x%lux\n", iomem->sypcr);
675 	*p = 0;
676 	print("still alive\n");
677 	splx(x);
678 }
679