xref: /openbsd/sys/arch/alpha/alpha/dec_6600.c (revision cca36db2)
1 /* $OpenBSD: dec_6600.c,v 1.13 2010/11/23 04:07:55 shadchin 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", ctb->ctb_term_type, ctbslot,
177 		    CTB_TURBOSLOT_HOSE(ctbslot));
178 
179 		panic("consinit: unknown console type %ld",
180 		    ctb->ctb_term_type);
181 	}
182 }
183 
184 static void
185 dec_6600_device_register(dev, aux)
186 	struct device *dev;
187 	void *aux;
188 {
189 	static int found, initted, diskboot, netboot;
190 	static struct device *primarydev, *pcidev, *ctrlrdev;
191 	struct bootdev_data *b = bootdev_data;
192 	struct device *parent = dev->dv_parent;
193 	struct cfdata *cf = dev->dv_cfdata;
194 	struct cfdriver *cd = cf->cf_driver;
195 
196 	if (found)
197 		return;
198 
199 	if (!initted) {
200 		diskboot = (strncasecmp(b->protocol, "SCSI", 4) == 0) ||
201 		    (strncasecmp(b->protocol, "IDE", 3) == 0);
202 		netboot = (strncasecmp(b->protocol, "BOOTP", 5) == 0) ||
203 		    (strncasecmp(b->protocol, "MOP", 3) == 0);
204 		DR_VERBOSE(printf("diskboot = %d, netboot = %d\n", diskboot,
205 		    netboot));
206 		initted = 1;
207 	}
208 
209 	if (primarydev == NULL) {
210 		if (strcmp(cd->cd_name, "tsp"))
211 			return;
212 		else {
213 			struct tsp_attach_args *tsp = aux;
214 
215 			if (b->bus != tsp->tsp_slot)
216 				return;
217 			primarydev = dev;
218 			DR_VERBOSE(printf("\nprimarydev = %s\n",
219 			    dev->dv_xname));
220 			return;
221 		}
222 	}
223 
224 	if (pcidev == NULL) {
225 		if (strcmp(cd->cd_name, "pci"))
226 			return;
227 		/*
228 		 * Try to find primarydev anywhere in the ancestry.  This is
229 		 * necessary if the PCI bus is hidden behind a bridge.
230 		 */
231 		while (parent) {
232 			if (parent == primarydev)
233 				break;
234 			parent = parent->dv_parent;
235 		}
236 		if (!parent)
237 			return;
238 		else {
239 			struct pcibus_attach_args *pba = aux;
240 
241 			if ((b->slot / 1000) != pba->pba_bus)
242 				return;
243 
244 			pcidev = dev;
245 			DR_VERBOSE(printf("\npcidev = %s\n", dev->dv_xname));
246 			return;
247 		}
248 	}
249 
250 	if (ctrlrdev == NULL) {
251 		if (parent != pcidev)
252 			return;
253 		else {
254 			struct pci_attach_args *pa = aux;
255 			int slot;
256 
257 			slot = pa->pa_bus * 1000 + pa->pa_function * 100 +
258 			    pa->pa_device;
259 			if (b->slot != slot)
260 				return;
261 
262 			if (netboot) {
263 				booted_device = dev;
264 				DR_VERBOSE(printf("\nbooted_device = %s\n",
265 				    dev->dv_xname));
266 				found = 1;
267 			} else {
268 				ctrlrdev = dev;
269 				DR_VERBOSE(printf("\nctrlrdev = %s\n",
270 				    dev->dv_xname));
271 			}
272 			return;
273 		}
274 	}
275 
276 	if (!diskboot)
277 		return;
278 
279 	if (!strcmp(cd->cd_name, "sd") || !strcmp(cd->cd_name, "st") ||
280 	    !strcmp(cd->cd_name, "cd")) {
281 		struct scsi_attach_args *sa = aux;
282 		struct scsi_link *periph = sa->sa_sc_link;
283 		int unit;
284 
285 		if (parent->dv_parent != ctrlrdev)
286 			return;
287 
288 		unit = periph->target * 100 + periph->lun;
289 		if (b->unit != unit)
290                         return;
291 
292 		/* we've found it! */
293 		booted_device = dev;
294 		DR_VERBOSE(printf("\nbooted_device = %s\n", dev->dv_xname));
295 		found = 1;
296 	}
297 
298 	/*
299 	 * Support to boot from IDE drives.
300 	 */
301 	if (!strcmp(cd->cd_name, "wd")) {
302 		struct ata_atapi_attach *aa_link = aux;
303 
304 		if ((strcmp("pciide", parent->dv_cfdata->cf_driver->cd_name) != 0))
305 			return;
306 		if (parent != ctrlrdev)
307 			return;
308 
309 		DR_VERBOSE(printf("\nAtapi info: drive: %d, channel %d\n",
310 		    aa_link->aa_drv_data->drive, aa_link->aa_channel));
311 		DR_VERBOSE(printf("Bootdev info: unit: %d, channel: %d\n",
312 		    b->unit, b->channel));
313 		if (b->unit != aa_link->aa_drv_data->drive ||
314 		    b->channel != aa_link->aa_channel)
315 			return;
316 
317 		/* we've found it! */
318 		booted_device = dev;
319 		DR_VERBOSE(printf("booted_device = %s\n", dev->dv_xname));
320 		found = 1;
321 	}
322 }
323 
324 #ifndef SMALL_KERNEL
325 static void
326 dec_6600_environmental_mcheck(unsigned long mces, struct trapframe *framep,
327     unsigned long vector, unsigned long logout)
328 {
329 	mc_hdr_ev6 *hdr = (mc_hdr_ev6 *)logout;
330 	mc_env_ev6 *env = (mc_env_ev6 *)(logout + hdr->la_system_offset);
331 	int silent = 0;
332 	int itemno;
333 
334 	/*
335 	 * Note that we do not check for an expected machine check,
336 	 * since software is not supposed to trigger an environmental
337 	 * machine check, and there might be an environmental change
338 	 * just before our expected machine check occurs.
339 	 */
340 
341 	/*
342 	 * Most environmental changes are handled at the RMC level,
343 	 * and we are either not notified (e.g. PCI door open) or
344 	 * drastic action is taken (e.g. the RMC will power down the
345 	 * system immediately if the CPU door is open).
346 	 *
347 	 * The only events we seem to be notified of are power supply
348 	 * failures.
349 	 */
350 
351 	/* display CPU failures */
352 	for (itemno = 0; itemno < 4; itemno++) {
353 		if ((env->cpuir & EV6_ENV_CPUIR_CPU_ENABLE(itemno)) != 0 &&
354 		    (env->cpuir & EV6_ENV_CPUIR_CPU_FAIL(itemno)) != 0) {
355 			printf("CPU%d FAILURE\n", itemno);
356 			silent = 1;
357 		}
358 	}
359 
360 	/* display PSU failures */
361 	if (env->smir & EV6_ENV_SMIR_PSU_FAILURE) {
362 		for (itemno = 0; itemno < 3; itemno++) {
363 			if ((env->psir & EV6_ENV_PSIR_PSU_FAIL(itemno)) != 0) {
364 				if ((env->psir &
365 				    EV6_ENV_PSIR_PSU_ENABLE(itemno)) != 0)
366 					printf("PSU%d FAILURE\n", itemno);
367 				else
368 					printf("PSU%d DISABLED\n", itemno);
369 			} else {
370 				if ((env->psir &
371 				    EV6_ENV_PSIR_PSU_ENABLE(itemno)) != 0)
372 					printf("PSU%d ENABLED\n", itemno);
373 			}
374 		}
375 		silent = 1;
376 	}
377 
378 	/* if we could not print a summary, display everything */
379 	if (silent == 0) {
380 		printf("      Processor Environmental Machine Check, "
381 		    "Code 0x%x\n", hdr->mcheck_code);
382 
383 		printf("Flags\t%016x\n", env->flags);
384 		printf("DIR\t%016x\n", env->c_dir);
385 		printf("SMIR\t%016x\n", env->smir);
386 		printf("CPUIR\t%016x\n", env->cpuir);
387 		printf("PSIR\t%016x\n", env->psir);
388 		printf("LM78_ISR\t%016x\n", env->lm78_isr);
389 		printf("Doors\t%016x\n", env->doors);
390 		printf("Temp Warning\t%016x\n", env->temp_warning);
391 		printf("Fan Control\t%016x\n", env->fan_control);
392 		printf("Fatal Power Down\t%016x\n", env->fatal_power_down);
393 	}
394 
395 	/*
396 	 * Apparently, these checks occur with MCES == 0, which
397 	 * is supposed to be an uncorrectable machine check.
398 	 *
399 	 * Until I know of a better way to tell recoverable and
400 	 * unrecoverable environmental checks apart, I'll use
401 	 * the fatal power down code to discriminate.
402 	 */
403 	if (mces == 0 && env->fatal_power_down == 0)
404 		return;
405 	else
406 		machine_check(mces, framep, vector, logout);
407 }
408 
409 /*
410  * Expected syndrome values per faulting bit
411  */
412 static const uint8_t ev6_syndrome[64 + 8] = {
413 	0xce, 0xcb, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc,
414 	0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34,
415 	0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c,
416 	0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xf1, 0xf4,
417 	0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d,
418 	0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xb0, 0xb5,
419 	0x8f, 0x8a, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d,
420 	0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75,
421 	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
422 };
423 
424 static void
425 dec_6600_print_syndrome(int sno, unsigned long syndrome)
426 {
427 	unsigned int bitno;
428 
429 	syndrome &= 0xff;
430 	printf("Syndrome bits %d\t%02x ", sno, syndrome);
431 	for (bitno = 0; bitno < nitems(ev6_syndrome); bitno++)
432 		if (syndrome == ev6_syndrome[bitno])
433 			break;
434 
435 	if (bitno < 64)
436 		printf("(%d)\n", bitno);
437 	else if (bitno < nitems(ev6_syndrome))
438 		printf("(CB%d)\n", bitno - 64);
439 	else
440 		printf("(unknown)\n");
441 }
442 
443 static void
444 dec_6600_mcheck(unsigned long mces, struct trapframe *framep,
445     unsigned long vector, unsigned long logout)
446 {
447 	mc_hdr_ev6 *hdr = (mc_hdr_ev6 *)logout;
448 	struct mchkinfo *mcp;
449 
450 	/*
451 	 * If we expected a machine check, don't decode it.
452 	 */
453 	mcp = &curcpu()->ci_mcinfo;
454 	if (mcp->mc_expected) {
455 		machine_check(mces, framep, vector, logout);
456 		return;
457 	}
458 
459 	printf("      Processor Machine Check (%lx), Code 0x%x\n",
460 	    vector, hdr->mcheck_code);
461 
462 	if (vector == ALPHA_SYS_MCHECK) {
463 #ifdef notyet
464 		mc_sys_ev6 *sys = (mc_sys_ev6 *)(logout + hdr->la_system_offset);
465 #endif
466 		/* XXX Decode and report P-Chip errors */
467 	} else /* ALPHA_PROC_MCHECK */ {
468 		mc_cpu_ev6 *cpu = (mc_cpu_ev6 *)(logout + hdr->la_cpu_offset);
469 		size_t cpu_size = hdr->la_system_offset - hdr->la_cpu_offset;
470 
471 		printf("Dcache status\t0x%05x\n",
472 		    cpu->dc_stat & EV6_DC_STAT_MASK);
473 		dec_6600_print_syndrome(0, cpu->c_syndrome_0);
474 		dec_6600_print_syndrome(1, cpu->c_syndrome_1);
475 		/* C_STAT */
476 		printf("C_STAT\t");
477 		switch (cpu->c_stat & EV6_C_STAT_MASK) {
478 		case EV6_C_STAT_DBL_ISTREAM_BC_ECC_ERR:
479 			printf("Bcache instruction stream double ECC error\n");
480 			break;
481 		case EV6_C_STAT_DBL_ISTREAM_MEM_ECC_ERR:
482 			printf("Memory instruction stream double ECC error\n");
483 			break;
484 		case EV6_C_STAT_DBL_DSTREAM_BC_ECC_ERR:
485 			printf("Bcache data stream double ECC error\n");
486 			break;
487 		case EV6_C_STAT_DBL_DSTREAM_MEM_ECC_ERR:
488 			printf("Memory data stream double ECC error\n");
489 			break;
490 		case EV6_C_STAT_SNGL_ISTREAM_BC_ECC_ERR:
491 			printf("Bcache instruction stream single ECC error\n");
492 			break;
493 		case EV6_C_STAT_SNGL_ISTREAM_MEM_ECC_ERR:
494 			printf("Memory instruction stream single ECC error\n");
495 			break;
496 		case EV6_C_STAT_SNGL_BC_PROBE_HIT_ERR:
497 		case EV6_C_STAT_SNGL_BC_PROBE_HIT_ERR2:
498 			printf("Bcache probe hit error\n");
499 			break;
500 		case EV6_C_STAT_SNGL_DSTREAM_DC_ECC_ERR:
501 			printf("Dcache data stream single ECC error\n");
502 			break;
503 		case EV6_C_STAT_SNGL_DSTREAM_BC_ECC_ERR:
504 			printf("Bcache data stream single ECC error\n");
505 			break;
506 		case EV6_C_STAT_SNGL_DSTREAM_MEM_ECC_ERR:
507 			printf("Memory data stream single ECC error\n");
508 			break;
509 		case EV6_C_STAT_SNGL_DC_DUPLICATE_TAG_PERR:
510 			printf("Dcache duplicate tag error\n");
511 			break;
512 		case EV6_C_STAT_SNGL_BC_TAG_PERR:
513 			printf("Bcache tag error\n");
514 			break;
515 		case EV6_C_STAT_NO_ERROR:
516 			if (cpu->dc_stat & EV6_DC_STAT_STORE_DATA_ECC_ERROR) {
517 				printf("Bcache/Dcache victim read ECC error\n");
518 				break;
519 			}
520 			/* FALLTHROUGH */
521 		default:
522 			printf("%02x\n", cpu->c_stat);
523 			break;
524 		}
525 		/* C_ADDR */
526 		printf("Error address\t");
527 		if ((cpu->c_stat & EV6_C_STAT_MASK) ==
528 		    EV6_C_STAT_SNGL_DSTREAM_DC_ECC_ERR)
529 			printf("0xXXXXXXXXXXX%05x\n", cpu->c_addr & 0xfffc0);
530 		else
531 			printf("0x%016x\n", cpu->c_addr & 0xffffffffffffffc0);
532 
533 		if (cpu_size > offsetof(mc_cpu_ev6, exc_addr)) {
534 			printf("Exception address\t0x%016x%s\n",
535 			    cpu->exc_addr & 0xfffffffffffffffc,
536 			    cpu->exc_addr & 1 ? " in PAL mode" : "");
537 			/* other fields are not really informative */
538 		}
539 	}
540 
541 	machine_check(mces, framep, vector, logout);
542 }
543 #endif
544 
545 static void
546 dec_6600_mcheck_handler(unsigned long mces, struct trapframe *framep,
547     unsigned long vector, unsigned long param)
548 {
549 #ifdef SMALL_KERNEL
550 	/*
551 	 * Even though we can not afford the machine check
552 	 * analysis code, we need to ignore environmental
553 	 * changes.
554 	 */
555 	if (vector == ALPHA_ENV_MCHECK)
556 		return;
557 
558 	machine_check(mces, framep, vector, param);
559 #else
560 	switch (vector) {
561 	case ALPHA_ENV_MCHECK:
562 		dec_6600_environmental_mcheck(mces, framep, vector, param);
563 		break;
564 	case ALPHA_PROC_MCHECK:
565 	case ALPHA_SYS_MCHECK:
566 		dec_6600_mcheck(mces, framep, vector, param);
567 		break;
568 	default:
569 		machine_check(mces, framep, vector, param);
570 		break;
571 	}
572 #endif
573 }
574