xref: /openbsd/sys/arch/alpha/alpha/dec_6600.c (revision f6aab3d8)
1 /* $OpenBSD: dec_6600.c,v 1.14 2014/05/08 20:46:49 miod Exp $ */
2 /* $NetBSD: dec_6600.c,v 1.7 2000/06/20 03:48:54 matt Exp $ */
3 
4 /*
5  * Copyright (c) 2009 Miodrag Vallat.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 /*
20  * Copyright (c) 1995, 1996, 1997 Carnegie-Mellon University.
21  * All rights reserved.
22  *
23  * Author: Chris G. Demetriou
24  *
25  * Permission to use, copy, modify and distribute this software and
26  * its documentation is hereby granted, provided that both the copyright
27  * notice and this permission notice appear in all copies of the
28  * software, derivative works or modified versions, and any portions
29  * thereof, and that both notices appear in supporting documentation.
30  *
31  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
32  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
33  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
34  *
35  * Carnegie Mellon requests users of this software to return to
36  *
37  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
38  *  School of Computer Science
39  *  Carnegie Mellon University
40  *  Pittsburgh PA 15213-3890
41  *
42  * any improvements or extensions that they make and grant Carnegie the
43  * rights to redistribute these changes.
44  */
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/device.h>
49 #include <sys/termios.h>
50 #include <dev/cons.h>
51 
52 #include <machine/rpb.h>
53 #include <machine/autoconf.h>
54 #include <machine/cpuconf.h>
55 #include <machine/bus.h>
56 #include <machine/logout.h>
57 
58 #include <dev/ic/comreg.h>
59 #include <dev/ic/comvar.h>
60 
61 #include <dev/isa/isareg.h>
62 #include <dev/isa/isavar.h>
63 #include <dev/ic/i8042reg.h>
64 #include <dev/ic/pckbcvar.h>
65 #include <dev/pci/pcireg.h>
66 #include <dev/pci/pcivar.h>
67 
68 #include <alpha/pci/tsreg.h>
69 #include <alpha/pci/tsvar.h>
70 
71 #include <scsi/scsi_all.h>
72 #include <scsi/scsiconf.h>
73 #include <dev/ata/atavar.h>
74 
75 #include "pckbd.h"
76 
77 #ifndef CONSPEED
78 #define CONSPEED TTYDEF_SPEED
79 #endif
80 
81 #define	DR_VERBOSE(f) while (0)
82 
83 static int comcnrate __attribute__((unused)) = CONSPEED;
84 
85 void dec_6600_init(void);
86 static void dec_6600_cons_init(void);
87 static void dec_6600_device_register(struct device *, void *);
88 static void dec_6600_mcheck_handler(unsigned long, struct trapframe *,
89 	    unsigned long, unsigned long);
90 #ifndef SMALL_KERNEL
91 static void dec_6600_environmental_mcheck(unsigned long, struct trapframe *,
92 	    unsigned long, unsigned long);
93 static void dec_6600_mcheck(unsigned long, struct trapframe *, unsigned long,
94 	    unsigned long);
95 static void dec_6600_print_syndrome(int, unsigned long);
96 #endif
97 
98 void
99 dec_6600_init()
100 {
101 
102 	platform.family = "6600";
103 
104 	if ((platform.model = alpha_dsr_sysname()) == NULL) {
105 		/* XXX Don't know the system variations, yet. */
106 		platform.model = alpha_unknown_sysname();
107 	}
108 
109 	platform.iobus = "tsc";
110 	platform.cons_init = dec_6600_cons_init;
111 	platform.device_register = dec_6600_device_register;
112 	platform.mcheck_handler = dec_6600_mcheck_handler;
113 	STQP(TS_C_DIM0) = 0UL;
114 	STQP(TS_C_DIM1) = 0UL;
115 }
116 
117 static void
118 dec_6600_cons_init()
119 {
120 	struct ctb *ctb;
121 	u_int64_t ctbslot;
122 	struct tsp_config *tsp;
123 
124 	ctb = (struct ctb *)(((caddr_t)hwrpb) + hwrpb->rpb_ctb_off);
125 	ctbslot = ctb->ctb_turboslot;
126 
127 	/* Console hose defaults to hose 0. */
128 	tsp_console_hose = 0;
129 
130 	tsp = tsp_init(0, tsp_console_hose);
131 
132 	switch (ctb->ctb_term_type) {
133 	case CTB_PRINTERPORT:
134 		/* serial console ... */
135 		/* XXX */
136 		{
137 			/*
138 			 * Delay to allow PROM putchars to complete.
139 			 * FIFO depth * character time,
140 			 * character time = (1000000 / (defaultrate / 10))
141 			 */
142 			DELAY(160000000 / comcnrate);
143 
144 			if(comcnattach(&tsp->pc_iot, 0x3f8, comcnrate,
145 			    COM_FREQ,
146 			    (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8))
147 				panic("can't init serial console");
148 
149 			break;
150 		}
151 
152 	case CTB_GRAPHICS:
153 #if NPCKBD > 0
154 		/* display console ... */
155 		/* XXX */
156 		(void) pckbc_cnattach(&tsp->pc_iot, IO_KBD, KBCMDP, 0);
157 
158 		if (CTB_TURBOSLOT_TYPE(ctbslot) ==
159 		    CTB_TURBOSLOT_TYPE_ISA)
160 			isa_display_console(&tsp->pc_iot, &tsp->pc_memt);
161 		else {
162 			/* The display PCI might be different */
163 			tsp_console_hose = CTB_TURBOSLOT_HOSE(ctbslot);
164 			tsp = tsp_init(0, tsp_console_hose);
165 			pci_display_console(&tsp->pc_iot, &tsp->pc_memt,
166 			    &tsp->pc_pc, CTB_TURBOSLOT_BUS(ctbslot),
167 			    CTB_TURBOSLOT_SLOT(ctbslot), 0);
168 		}
169 #else
170 		panic("not configured to use display && keyboard console");
171 #endif
172 		break;
173 
174 	default:
175 		printf("ctb_term_type = 0x%lx ctb_turboslot = 0x%lx"
176 		    " hose = %ld\n",
177 		    (unsigned long)ctb->ctb_term_type,
178 		    (unsigned long)ctbslot,
179 		    (unsigned long)CTB_TURBOSLOT_HOSE(ctbslot));
180 
181 		panic("consinit: unknown console type %lu",
182 		    (unsigned long)ctb->ctb_term_type);
183 	}
184 }
185 
186 static void
187 dec_6600_device_register(dev, aux)
188 	struct device *dev;
189 	void *aux;
190 {
191 	static int found, initted, diskboot, netboot;
192 	static struct device *primarydev, *pcidev, *ctrlrdev;
193 	struct bootdev_data *b = bootdev_data;
194 	struct device *parent = dev->dv_parent;
195 	struct cfdata *cf = dev->dv_cfdata;
196 	struct cfdriver *cd = cf->cf_driver;
197 
198 	if (found)
199 		return;
200 
201 	if (!initted) {
202 		diskboot = (strncasecmp(b->protocol, "SCSI", 4) == 0) ||
203 		    (strncasecmp(b->protocol, "IDE", 3) == 0);
204 		netboot = (strncasecmp(b->protocol, "BOOTP", 5) == 0) ||
205 		    (strncasecmp(b->protocol, "MOP", 3) == 0);
206 		DR_VERBOSE(printf("diskboot = %d, netboot = %d\n", diskboot,
207 		    netboot));
208 		initted = 1;
209 	}
210 
211 	if (primarydev == NULL) {
212 		if (strcmp(cd->cd_name, "tsp"))
213 			return;
214 		else {
215 			struct tsp_attach_args *tsp = aux;
216 
217 			if (b->bus != tsp->tsp_slot)
218 				return;
219 			primarydev = dev;
220 			DR_VERBOSE(printf("\nprimarydev = %s\n",
221 			    dev->dv_xname));
222 			return;
223 		}
224 	}
225 
226 	if (pcidev == NULL) {
227 		if (strcmp(cd->cd_name, "pci"))
228 			return;
229 		/*
230 		 * Try to find primarydev anywhere in the ancestry.  This is
231 		 * necessary if the PCI bus is hidden behind a bridge.
232 		 */
233 		while (parent) {
234 			if (parent == primarydev)
235 				break;
236 			parent = parent->dv_parent;
237 		}
238 		if (!parent)
239 			return;
240 		else {
241 			struct pcibus_attach_args *pba = aux;
242 
243 			if ((b->slot / 1000) != pba->pba_bus)
244 				return;
245 
246 			pcidev = dev;
247 			DR_VERBOSE(printf("\npcidev = %s\n", dev->dv_xname));
248 			return;
249 		}
250 	}
251 
252 	if (ctrlrdev == NULL) {
253 		if (parent != pcidev)
254 			return;
255 		else {
256 			struct pci_attach_args *pa = aux;
257 			int slot;
258 
259 			slot = pa->pa_bus * 1000 + pa->pa_function * 100 +
260 			    pa->pa_device;
261 			if (b->slot != slot)
262 				return;
263 
264 			if (netboot) {
265 				booted_device = dev;
266 				DR_VERBOSE(printf("\nbooted_device = %s\n",
267 				    dev->dv_xname));
268 				found = 1;
269 			} else {
270 				ctrlrdev = dev;
271 				DR_VERBOSE(printf("\nctrlrdev = %s\n",
272 				    dev->dv_xname));
273 			}
274 			return;
275 		}
276 	}
277 
278 	if (!diskboot)
279 		return;
280 
281 	if (!strcmp(cd->cd_name, "sd") || !strcmp(cd->cd_name, "st") ||
282 	    !strcmp(cd->cd_name, "cd")) {
283 		struct scsi_attach_args *sa = aux;
284 		struct scsi_link *periph = sa->sa_sc_link;
285 		int unit;
286 
287 		if (parent->dv_parent != ctrlrdev)
288 			return;
289 
290 		unit = periph->target * 100 + periph->lun;
291 		if (b->unit != unit)
292                         return;
293 
294 		/* we've found it! */
295 		booted_device = dev;
296 		DR_VERBOSE(printf("\nbooted_device = %s\n", dev->dv_xname));
297 		found = 1;
298 	}
299 
300 	/*
301 	 * Support to boot from IDE drives.
302 	 */
303 	if (!strcmp(cd->cd_name, "wd")) {
304 		struct ata_atapi_attach *aa_link = aux;
305 
306 		if ((strcmp("pciide", parent->dv_cfdata->cf_driver->cd_name) != 0))
307 			return;
308 		if (parent != ctrlrdev)
309 			return;
310 
311 		DR_VERBOSE(printf("\nAtapi info: drive: %d, channel %d\n",
312 		    aa_link->aa_drv_data->drive, aa_link->aa_channel));
313 		DR_VERBOSE(printf("Bootdev info: unit: %d, channel: %d\n",
314 		    b->unit, b->channel));
315 		if (b->unit != aa_link->aa_drv_data->drive ||
316 		    b->channel != aa_link->aa_channel)
317 			return;
318 
319 		/* we've found it! */
320 		booted_device = dev;
321 		DR_VERBOSE(printf("booted_device = %s\n", dev->dv_xname));
322 		found = 1;
323 	}
324 }
325 
326 #ifndef SMALL_KERNEL
327 static void
328 dec_6600_environmental_mcheck(unsigned long mces, struct trapframe *framep,
329     unsigned long vector, unsigned long logout)
330 {
331 	mc_hdr_ev6 *hdr = (mc_hdr_ev6 *)logout;
332 	mc_env_ev6 *env = (mc_env_ev6 *)(logout + hdr->la_system_offset);
333 	int silent = 0;
334 	int itemno;
335 
336 	/*
337 	 * Note that we do not check for an expected machine check,
338 	 * since software is not supposed to trigger an environmental
339 	 * machine check, and there might be an environmental change
340 	 * just before our expected machine check occurs.
341 	 */
342 
343 	/*
344 	 * Most environmental changes are handled at the RMC level,
345 	 * and we are either not notified (e.g. PCI door open) or
346 	 * drastic action is taken (e.g. the RMC will power down the
347 	 * system immediately if the CPU door is open).
348 	 *
349 	 * The only events we seem to be notified of are power supply
350 	 * failures.
351 	 */
352 
353 	/* display CPU failures */
354 	for (itemno = 0; itemno < 4; itemno++) {
355 		if ((env->cpuir & EV6_ENV_CPUIR_CPU_ENABLE(itemno)) != 0 &&
356 		    (env->cpuir & EV6_ENV_CPUIR_CPU_FAIL(itemno)) != 0) {
357 			printf("CPU%d FAILURE\n", itemno);
358 			silent = 1;
359 		}
360 	}
361 
362 	/* display PSU failures */
363 	if (env->smir & EV6_ENV_SMIR_PSU_FAILURE) {
364 		for (itemno = 0; itemno < 3; itemno++) {
365 			if ((env->psir & EV6_ENV_PSIR_PSU_FAIL(itemno)) != 0) {
366 				if ((env->psir &
367 				    EV6_ENV_PSIR_PSU_ENABLE(itemno)) != 0)
368 					printf("PSU%d FAILURE\n", itemno);
369 				else
370 					printf("PSU%d DISABLED\n", itemno);
371 			} else {
372 				if ((env->psir &
373 				    EV6_ENV_PSIR_PSU_ENABLE(itemno)) != 0)
374 					printf("PSU%d ENABLED\n", itemno);
375 			}
376 		}
377 		silent = 1;
378 	}
379 
380 	/* if we could not print a summary, display everything */
381 	if (silent == 0) {
382 		printf("      Processor Environmental Machine Check, "
383 		    "Code 0x%x\n", hdr->mcheck_code);
384 
385 		printf("Flags\t%016lx\n", (unsigned long)env->flags);
386 		printf("DIR\t%016lx\n", (unsigned long)env->c_dir);
387 		printf("SMIR\t%016lx\n", (unsigned long)env->smir);
388 		printf("CPUIR\t%016lx\n", (unsigned long)env->cpuir);
389 		printf("PSIR\t%016lx\n", (unsigned long)env->psir);
390 		printf("LM78_ISR\t%016lx\n", (unsigned long)env->lm78_isr);
391 		printf("Doors\t%016lx\n", (unsigned long)env->doors);
392 		printf("Temp Warning\t%016lx\n",
393 		    (unsigned long)env->temp_warning);
394 		printf("Fan Control\t%016lx\n",
395 		    (unsigned long)env->fan_control);
396 		printf("Fatal Power Down\t%016lx\n",
397 		    (unsigned long)env->fatal_power_down);
398 	}
399 
400 	/*
401 	 * Apparently, these checks occur with MCES == 0, which
402 	 * is supposed to be an uncorrectable machine check.
403 	 *
404 	 * Until I know of a better way to tell recoverable and
405 	 * unrecoverable environmental checks apart, I'll use
406 	 * the fatal power down code to discriminate.
407 	 */
408 	if (mces == 0 && env->fatal_power_down == 0)
409 		return;
410 	else
411 		machine_check(mces, framep, vector, logout);
412 }
413 
414 /*
415  * Expected syndrome values per faulting bit
416  */
417 static const uint8_t ev6_syndrome[64 + 8] = {
418 	0xce, 0xcb, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc,
419 	0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34,
420 	0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c,
421 	0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xf1, 0xf4,
422 	0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d,
423 	0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xb0, 0xb5,
424 	0x8f, 0x8a, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d,
425 	0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75,
426 	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
427 };
428 
429 static void
430 dec_6600_print_syndrome(int sno, unsigned long syndrome)
431 {
432 	unsigned int bitno;
433 
434 	syndrome &= 0xff;
435 	printf("Syndrome bits %d\t%02lx ", sno, syndrome);
436 	for (bitno = 0; bitno < nitems(ev6_syndrome); bitno++)
437 		if (syndrome == ev6_syndrome[bitno])
438 			break;
439 
440 	if (bitno < 64)
441 		printf("(%d)\n", bitno);
442 	else if (bitno < nitems(ev6_syndrome))
443 		printf("(CB%d)\n", bitno - 64);
444 	else
445 		printf("(unknown)\n");
446 }
447 
448 static void
449 dec_6600_mcheck(unsigned long mces, struct trapframe *framep,
450     unsigned long vector, unsigned long logout)
451 {
452 	mc_hdr_ev6 *hdr = (mc_hdr_ev6 *)logout;
453 	struct mchkinfo *mcp;
454 
455 	/*
456 	 * If we expected a machine check, don't decode it.
457 	 */
458 	mcp = &curcpu()->ci_mcinfo;
459 	if (mcp->mc_expected) {
460 		machine_check(mces, framep, vector, logout);
461 		return;
462 	}
463 
464 	printf("      Processor Machine Check (%lx), Code 0x%x\n",
465 	    vector, hdr->mcheck_code);
466 
467 	if (vector == ALPHA_SYS_MCHECK) {
468 #ifdef notyet
469 		mc_sys_ev6 *sys = (mc_sys_ev6 *)(logout + hdr->la_system_offset);
470 #endif
471 		/* XXX Decode and report P-Chip errors */
472 	} else /* ALPHA_PROC_MCHECK */ {
473 		mc_cpu_ev6 *cpu = (mc_cpu_ev6 *)(logout + hdr->la_cpu_offset);
474 		size_t cpu_size = hdr->la_system_offset - hdr->la_cpu_offset;
475 
476 		printf("Dcache status\t0x%05lx\n",
477 		    (unsigned long)cpu->dc_stat & EV6_DC_STAT_MASK);
478 		dec_6600_print_syndrome(0, cpu->c_syndrome_0);
479 		dec_6600_print_syndrome(1, cpu->c_syndrome_1);
480 		/* C_STAT */
481 		printf("C_STAT\t");
482 		switch (cpu->c_stat & EV6_C_STAT_MASK) {
483 		case EV6_C_STAT_DBL_ISTREAM_BC_ECC_ERR:
484 			printf("Bcache instruction stream double ECC error\n");
485 			break;
486 		case EV6_C_STAT_DBL_ISTREAM_MEM_ECC_ERR:
487 			printf("Memory instruction stream double ECC error\n");
488 			break;
489 		case EV6_C_STAT_DBL_DSTREAM_BC_ECC_ERR:
490 			printf("Bcache data stream double ECC error\n");
491 			break;
492 		case EV6_C_STAT_DBL_DSTREAM_MEM_ECC_ERR:
493 			printf("Memory data stream double ECC error\n");
494 			break;
495 		case EV6_C_STAT_SNGL_ISTREAM_BC_ECC_ERR:
496 			printf("Bcache instruction stream single ECC error\n");
497 			break;
498 		case EV6_C_STAT_SNGL_ISTREAM_MEM_ECC_ERR:
499 			printf("Memory instruction stream single ECC error\n");
500 			break;
501 		case EV6_C_STAT_SNGL_BC_PROBE_HIT_ERR:
502 		case EV6_C_STAT_SNGL_BC_PROBE_HIT_ERR2:
503 			printf("Bcache probe hit error\n");
504 			break;
505 		case EV6_C_STAT_SNGL_DSTREAM_DC_ECC_ERR:
506 			printf("Dcache data stream single ECC error\n");
507 			break;
508 		case EV6_C_STAT_SNGL_DSTREAM_BC_ECC_ERR:
509 			printf("Bcache data stream single ECC error\n");
510 			break;
511 		case EV6_C_STAT_SNGL_DSTREAM_MEM_ECC_ERR:
512 			printf("Memory data stream single ECC error\n");
513 			break;
514 		case EV6_C_STAT_SNGL_DC_DUPLICATE_TAG_PERR:
515 			printf("Dcache duplicate tag error\n");
516 			break;
517 		case EV6_C_STAT_SNGL_BC_TAG_PERR:
518 			printf("Bcache tag error\n");
519 			break;
520 		case EV6_C_STAT_NO_ERROR:
521 			if (cpu->dc_stat & EV6_DC_STAT_STORE_DATA_ECC_ERROR) {
522 				printf("Bcache/Dcache victim read ECC error\n");
523 				break;
524 			}
525 			/* FALLTHROUGH */
526 		default:
527 			printf("%02lx\n", (unsigned long)cpu->c_stat);
528 			break;
529 		}
530 		/* C_ADDR */
531 		printf("Error address\t");
532 		if ((cpu->c_stat & EV6_C_STAT_MASK) ==
533 		    EV6_C_STAT_SNGL_DSTREAM_DC_ECC_ERR)
534 			printf("0xXXXXXXXXXXX%05lx\n",
535 			    (unsigned long)cpu->c_addr & 0xfffc0);
536 		else
537 			printf("0x%016lx\n",
538 			    (unsigned long)cpu->c_addr & 0xffffffffffffffc0);
539 
540 		if (cpu_size > offsetof(mc_cpu_ev6, exc_addr)) {
541 			printf("Exception address\t0x%016lx%s\n",
542 			    (unsigned long)cpu->exc_addr & 0xfffffffffffffffc,
543 			    cpu->exc_addr & 1 ? " in PAL mode" : "");
544 			/* other fields are not really informative */
545 		}
546 	}
547 
548 	machine_check(mces, framep, vector, logout);
549 }
550 #endif
551 
552 static void
553 dec_6600_mcheck_handler(unsigned long mces, struct trapframe *framep,
554     unsigned long vector, unsigned long param)
555 {
556 #ifdef SMALL_KERNEL
557 	/*
558 	 * Even though we can not afford the machine check
559 	 * analysis code, we need to ignore environmental
560 	 * changes.
561 	 */
562 	if (vector == ALPHA_ENV_MCHECK)
563 		return;
564 
565 	machine_check(mces, framep, vector, param);
566 #else
567 	switch (vector) {
568 	case ALPHA_ENV_MCHECK:
569 		dec_6600_environmental_mcheck(mces, framep, vector, param);
570 		break;
571 	case ALPHA_PROC_MCHECK:
572 	case ALPHA_SYS_MCHECK:
573 		dec_6600_mcheck(mces, framep, vector, param);
574 		break;
575 	default:
576 		machine_check(mces, framep, vector, param);
577 		break;
578 	}
579 #endif
580 }
581