Module Name:    src
Committed By:   mjf
Date:           Sat May 16 16:06:06 UTC 2009

Modified Files:
        src/sys/arch/hp700/hp700: machdep.c pim.h

Log Message:
Add PA-RISC 2.0 PIM support.

Fix the HPMC exception handler so that, if we're running on a PA-RISC
2.0 machine, we use the 64-bit PIM data structures.

There was also a bug in the HPMC exception handler that stopped output
being written to the console after we'd taken the exception. We need
to make a PDC_IO pdc call to reset I/O.


To generate a diff of this commit:
cvs rdiff -u -r1.63 -r1.64 src/sys/arch/hp700/hp700/machdep.c
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/hp700/hp700/pim.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/hp700/hp700/machdep.c
diff -u src/sys/arch/hp700/hp700/machdep.c:1.63 src/sys/arch/hp700/hp700/machdep.c:1.64
--- src/sys/arch/hp700/hp700/machdep.c:1.63	Wed May 13 14:33:42 2009
+++ src/sys/arch/hp700/hp700/machdep.c	Sat May 16 16:06:06 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: machdep.c,v 1.63 2009/05/13 14:33:42 skrll Exp $	*/
+/*	$NetBSD: machdep.c,v 1.64 2009/05/16 16:06:06 mjf Exp $	*/
 
 /*-
  * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
@@ -58,7 +58,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.63 2009/05/13 14:33:42 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.64 2009/05/16 16:06:06 mjf Exp $");
 
 #include "opt_cputype.h"
 #include "opt_ddb.h"
@@ -1455,12 +1455,20 @@
  * an LPMC, or a TOC.  The check type is passed in as a trap
  * type, one of T_HPMC, T_LPMC, or T_INTERRUPT (for TOC).
  */
-static char pim_data_buffer[4096];	/* XXX assumed to be big enough */
+static char pim_data_buffer[896] __attribute__((__aligned__(8)));
 static char in_check = 0;
-void
-hppa_machine_check(int check_type)
+
+#define	PIM_WORD(name, word, bits)			\
+do {							\
+	snprintb(bitmask_buffer, sizeof(bitmask_buffer),\
+	    bits, word);				\
+	printf("%s %s", name, bitmask_buffer);		\
+} while (/* CONSTCOND */ 0)
+
+
+static inline void
+hppa_pim_dump(int check_type)
 {
-	int pdc_pim_type;
 	struct hp700_pim_hpmc *hpmc;
 	struct hp700_pim_lpmc *lpmc;
 	struct hp700_pim_toc *toc;
@@ -1470,37 +1478,20 @@
 	int reg_i, reg_j, reg_k;
 	char bitmask_buffer[64];
 	const char *name;
-	int error;
-#define	PIM_WORD(name, word, bits)			\
-do {							\
-	snprintb(bitmask_buffer, sizeof(bitmask_buffer),\
-	    bits, word);				\
-	printf("%s %s", name, bitmask_buffer);		\
-} while (/* CONSTCOND */ 0)
 
-	/* Do an fcacheall(). */
-	fcacheall();
-
-	/* Dispatch on the check type. */
 	regs = NULL;
 	checks = NULL;
 	switch (check_type) {
 	case T_HPMC:
-		name = "HPMC";
-		pdc_pim_type = PDC_PIM_HPMC;
 		hpmc = (struct hp700_pim_hpmc *) pim_data_buffer;
 		regs = &hpmc->pim_hpmc_regs;
 		checks = &hpmc->pim_hpmc_checks;
 		break;
 	case T_LPMC:
-		name = "LPMC";
-		pdc_pim_type = PDC_PIM_LPMC;
 		lpmc = (struct hp700_pim_lpmc *) pim_data_buffer;
 		checks = &lpmc->pim_lpmc_checks;
 		break;
 	case T_INTERRUPT:
-		name = "TOC";
-		pdc_pim_type = PDC_PIM_TOC;
 		toc = (struct hp700_pim_toc *) pim_data_buffer;
 		regs = &toc->pim_toc_regs;
 		break;
@@ -1508,11 +1499,6 @@
 		panic("unknown machine check type");
 		/* NOTREACHED */
 	}
-	printf("\nmachine check: %s", name);
-	error = pdc_call((iodcio_t)pdc, 0, PDC_PIM, pdc_pim_type,
-		&pdc_pim, pim_data_buffer, sizeof(pim_data_buffer));
-	if (error < 0)
-		printf(" - WARNING: could not transfer PIM info (%d)", error);
 
 	/* If we have register arrays, display them. */
 	if (regs != NULL) {
@@ -1538,7 +1524,8 @@
 		}
 
 		/* Print out some interesting registers. */
-		printf("\n\n\tIIA 0x%x:0x%08x 0x%x:0x%08x",
+		printf("\n\n\tIIA head 0x%x:0x%08x\n"
+			"\tIIA tail 0x%x:0x%08x",
 			regs->pim_regs_cr17, regs->pim_regs_cr18,
 			regs->pim_regs_iisq_tail, regs->pim_regs_iioq_tail);
 		PIM_WORD("\n\tIPSW", regs->pim_regs_cr22, PSW_BITS);
@@ -1569,6 +1556,164 @@
 		printf("\n\tPath Info 0x%08x",
 			checks->pim_check_path_info);
 	}
+}
+
+static inline void
+hppa_pim64_dump(int check_type)
+{
+	struct hp700_pim64_hpmc *hpmc;
+	struct hp700_pim64_lpmc *lpmc;
+	struct hp700_pim64_toc *toc;
+	struct hp700_pim64_regs *regs;
+	struct hp700_pim64_checks *checks;
+	int reg_i, reg_j, reg_k;
+	uint64_t *regarray;
+	char bitmask_buffer[64];
+	const char *name;
+
+	regs = NULL;
+	checks = NULL;
+	switch (check_type) {
+	case T_HPMC:
+		hpmc = (struct hp700_pim64_hpmc *) pim_data_buffer;
+		regs = &hpmc->pim_hpmc_regs;
+		checks = &hpmc->pim_hpmc_checks;
+		break;
+	case T_LPMC:
+		lpmc = (struct hp700_pim64_lpmc *) pim_data_buffer;
+		checks = &lpmc->pim_lpmc_checks;
+		break;
+	case T_INTERRUPT:
+		toc = (struct hp700_pim64_toc *) pim_data_buffer;
+		regs = &toc->pim_toc_regs;
+		break;
+	default:
+		panic("unknown machine check type");
+		/* NOTREACHED */
+	}
+
+	/* If we have register arrays, display them. */
+	if (regs != NULL) {
+		for (reg_i = 0; reg_i < 3; reg_i++) {
+			if (reg_i == 0) {
+				name = "General";
+				regarray = &regs->pim_regs_r0;
+				reg_j = 32;
+			} else if (reg_i == 1) {
+				name = "Control";
+				regarray = &regs->pim_regs_cr0;
+				reg_j = 32;
+			} else {
+				name = "Space";
+				regarray = &regs->pim_regs_sr0;
+				reg_j = 8;
+			}
+			printf("\n\n\t%s Registers:", name);
+			for (reg_k = 0; reg_k < reg_j; reg_k++) {
+				printf("%s",
+					(reg_k & 1) ? " " : "\n\t");
+				if (!(reg_k & 1))
+					printf("%2d: ", reg_k);
+				printf("0x%016lx",
+					(unsigned long)regarray[reg_k]);
+			}
+
+		}
+
+		/* Print out some interesting registers. */
+		printf("\n\n\tIIA head 0x%lx:0x%016lx\n"
+		    "\tIIA tail 0x%lx:0x%016lx",
+		    (unsigned long)regs->pim_regs_cr17,
+		    (unsigned long)regs->pim_regs_cr18,
+		    (unsigned long)regs->pim_regs_iisq_tail,
+		    (unsigned long)regs->pim_regs_iioq_tail);
+		PIM_WORD("\n\tIPSW", regs->pim_regs_cr22, PSW_BITS);
+		printf("\n\tSP 0x%lx:0x%016lx\n\tFP 0x%lx:0x%016lx",
+		    (unsigned long)regs->pim_regs_sr0,
+		    (unsigned long)regs->pim_regs_r30,
+		    (unsigned long)regs->pim_regs_sr0,
+		    (unsigned long)regs->pim_regs_r3);
+	}
+
+	/* If we have check words, display them. */
+	if (checks != NULL) {
+		PIM_WORD("\n\n\tCheck Type", checks->pim_check_type,
+			PIM_CHECK_BITS);
+		PIM_WORD("\n\tCPU State", checks->pim_check_cpu_state,
+			PIM_CPU_BITS PIM_CPU_HPMC_BITS);
+		PIM_WORD("\n\tCache Check", checks->pim_check_cache,
+			PIM_CACHE_BITS);
+		PIM_WORD("\n\tTLB Check", checks->pim_check_tlb,
+			PIM_TLB_BITS);
+		PIM_WORD("\n\tBus Check", checks->pim_check_bus,
+			PIM_BUS_BITS);
+		PIM_WORD("\n\tAssist Check", checks->pim_check_assist,
+			PIM_ASSIST_BITS);
+		printf("\tAssist State %u", checks->pim_check_assist_state);
+		printf("\n\tSystem Responder 0x%016lx",
+		    (unsigned long)checks->pim_check_responder);
+		printf("\n\tSystem Requestor 0x%016lx",
+		    (unsigned long)checks->pim_check_requestor);
+		printf("\n\tPath Info 0x%08x",
+		    checks->pim_check_path_info);
+	}
+}
+
+void
+hppa_machine_check(int check_type)
+{
+	int pdc_pim_type;
+	const char *name;
+	int error;
+
+	/* Do an fcacheall(). */
+	fcacheall();
+
+	/* Dispatch on the check type. */
+	switch (check_type) {
+	case T_HPMC:
+		name = "HPMC";
+		pdc_pim_type = PDC_PIM_HPMC;
+		break;
+	case T_LPMC:
+		name = "LPMC";
+		pdc_pim_type = PDC_PIM_LPMC;
+		break;
+	case T_INTERRUPT:
+		name = "TOC";
+		pdc_pim_type = PDC_PIM_TOC;
+		break;
+	default:
+		panic("unknown machine check type");
+		/* NOTREACHED */
+	}
+
+	error = pdc_call((iodcio_t)pdc, 0, PDC_PIM, pdc_pim_type,
+		&pdc_pim, pim_data_buffer, sizeof(pim_data_buffer));
+	if (error < 0)
+		printf(" - WARNING: could not transfer PIM info (%d)", error);
+
+	CTASSERT(pdc_pim.count <= sizeof(pim_data_buffer));
+
+	/*
+	 * Reset IO and log errors.
+	 *
+	 * This seems to be needed in order to output to the console
+	 * if we take a HPMC interrupt. This PDC procedure may not be
+	 * implemented by some machines.
+	 */
+	error = pdc_call((iodcio_t)pdc, 0, PDC_IO, 0, 0, 0, 0);
+	if (error  != PDC_ERR_OK && error != PDC_ERR_NOPROC)
+		/* This seems futile if we can't print to the console. */
+		panic("PDC_IO failed");
+
+	printf("\nmachine check: %s", name);
+
+	if (hppa_cpu_info->hci_features & HPPA_FTRS_W32B)
+		hppa_pim64_dump(check_type);
+	else
+		hppa_pim_dump(check_type);
+
 	printf("\n");
 
 	/* If this is our first check, panic. */

Index: src/sys/arch/hp700/hp700/pim.h
diff -u src/sys/arch/hp700/hp700/pim.h:1.2 src/sys/arch/hp700/hp700/pim.h:1.3
--- src/sys/arch/hp700/hp700/pim.h:1.2	Mon Apr 28 20:23:19 2008
+++ src/sys/arch/hp700/hp700/pim.h	Sat May 16 16:06:06 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: pim.h,v 1.2 2008/04/28 20:23:19 martin Exp $	*/
+/*	$NetBSD: pim.h,v 1.3 2009/05/16 16:06:06 mjf Exp $	*/
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -36,6 +36,9 @@
  *
  * "PA/RISC 1.1 I/O Firmware Architecture Reference Specification",
  * Version 1.0, August 22, 2001.
+ *
+ * "PA/RISC 2.0 I/O Firmware Architecture Reference Specification",
+ * Version 1.0, August 22, 2001.
  */
 
 /* The PIM data for HPMC and TOC contains these register arrays. */
@@ -262,3 +265,138 @@
 	u_int	pim_toc_hversion_dep;
 	u_int	pim_toc_cpu_state;
 };
+
+struct hp700_pim64_regs {
+
+	/* The general registers. */
+	u_int64_t	pim_regs_r0;
+	u_int64_t	pim_regs_r1;
+	u_int64_t	pim_regs_r2;
+	u_int64_t	pim_regs_r3;
+	u_int64_t	pim_regs_r4;
+	u_int64_t	pim_regs_r5;
+	u_int64_t	pim_regs_r6;
+	u_int64_t	pim_regs_r7;
+	u_int64_t	pim_regs_r8;
+	u_int64_t	pim_regs_r9;
+	u_int64_t	pim_regs_r10;
+	u_int64_t	pim_regs_r11;
+	u_int64_t	pim_regs_r12;
+	u_int64_t	pim_regs_r13;
+	u_int64_t	pim_regs_r14;
+	u_int64_t	pim_regs_r15;
+	u_int64_t	pim_regs_r16;
+	u_int64_t	pim_regs_r17;
+	u_int64_t	pim_regs_r18;
+	u_int64_t	pim_regs_r19;
+	u_int64_t	pim_regs_r20;
+	u_int64_t	pim_regs_r21;
+	u_int64_t	pim_regs_r22;
+	u_int64_t	pim_regs_r23;
+	u_int64_t	pim_regs_r24;
+	u_int64_t	pim_regs_r25;
+	u_int64_t	pim_regs_r26;
+	u_int64_t	pim_regs_r27;
+	u_int64_t	pim_regs_r28;
+	u_int64_t	pim_regs_r29;
+	u_int64_t	pim_regs_r30;
+	u_int64_t	pim_regs_r31;
+
+	/* The control registers. */
+	u_int64_t	pim_regs_cr0;
+	u_int64_t	pim_regs_cr1;
+	u_int64_t	pim_regs_cr2;
+	u_int64_t	pim_regs_cr3;
+	u_int64_t	pim_regs_cr4;
+	u_int64_t	pim_regs_cr5;
+	u_int64_t	pim_regs_cr6;
+	u_int64_t	pim_regs_cr7;
+	u_int64_t	pim_regs_cr8;
+	u_int64_t	pim_regs_cr9;
+	u_int64_t	pim_regs_cr10;
+	u_int64_t	pim_regs_cr11;
+	u_int64_t	pim_regs_cr12;
+	u_int64_t	pim_regs_cr13;
+	u_int64_t	pim_regs_cr14;
+	u_int64_t	pim_regs_cr15;
+	u_int64_t	pim_regs_cr16;
+	u_int64_t	pim_regs_cr17;
+	u_int64_t	pim_regs_cr18;
+	u_int64_t	pim_regs_cr19;
+	u_int64_t	pim_regs_cr20;
+	u_int64_t	pim_regs_cr21;
+	u_int64_t	pim_regs_cr22;
+	u_int64_t	pim_regs_cr23;
+	u_int64_t	pim_regs_cr24;
+	u_int64_t	pim_regs_cr25;
+	u_int64_t	pim_regs_cr26;
+	u_int64_t	pim_regs_cr27;
+	u_int64_t	pim_regs_cr28;
+	u_int64_t	pim_regs_cr29;
+	u_int64_t	pim_regs_cr30;
+	u_int64_t	pim_regs_cr31;
+
+	/* The space registers. */
+	u_int64_t	pim_regs_sr0;
+	u_int64_t	pim_regs_sr1;
+	u_int64_t	pim_regs_sr2;
+	u_int64_t	pim_regs_sr3;
+	u_int64_t	pim_regs_sr4;
+	u_int64_t	pim_regs_sr5;
+	u_int64_t	pim_regs_sr6;
+	u_int64_t	pim_regs_sr7;
+
+	/* The back entries of the instruction address queues. */
+	u_int64_t	pim_regs_iisq_tail;
+	u_int64_t	pim_regs_iioq_tail;
+};
+
+struct hp700_pim64_checks {
+	/* The Check Type. */	
+	u_int	pim_check_type;
+
+	/*
+	 * The CPU State.  In addition to the common PIM_CPU_
+	 * bits defined below, some fields are HPMC-specific.
+	 */
+	u_int	pim_check_cpu_state;
+
+	/* The Cache Check word. */
+	u_int	pim_check_cache;
+
+	/* The TLB Check word. */
+	u_int	pim_check_tlb;
+
+	/* The Bus Check word. */
+	u_int	pim_check_bus;
+
+	/* The Assist Check word. */
+	u_int	pim_check_assist;
+
+	/* Additional information about the check. */
+	u_int	pim_check_assist_state;
+	u_int	pim_check_path_info;
+	u_int64_t	pim_check_responder;
+	u_int64_t	pim_check_requestor;
+};
+
+/* The PARISC 2.0 HPMC PIM data. */
+struct hp700_pim64_hpmc {
+	struct hp700_pim64_regs pim_hpmc_regs;
+	struct hp700_pim64_checks pim_hpmc_checks;
+	struct hp700_pim_fpregs pim_hpmc_fpregs;
+};
+
+/* The PARISC 2.0 LPMC PIM data. */
+struct hp700_pim64_lpmc {
+	u_int64_t pim_lmpc_hversion_dep[74];
+	struct hp700_pim64_checks pim_lpmc_checks;
+	struct hp700_pim_fpregs pim_lpmc_fpregs;
+};
+
+/* The PARISC 2.0 TOC PIM data. */
+struct hp700_pim64_toc {
+	struct	hp700_pim64_regs pim_toc_regs;
+	u_int	pim_toc_hversion_dep;
+	u_int	pim_toc_cpu_state;
+};

Reply via email to