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 = ®s->pim_regs_r0;
+ reg_j = 32;
+ } else if (reg_i == 1) {
+ name = "Control";
+ regarray = ®s->pim_regs_cr0;
+ reg_j = 32;
+ } else {
+ name = "Space";
+ regarray = ®s->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;
+};