|
@@ -370,3 +370,146 @@ ioc_error(__u32 stat0, __u32 stat1)
|
|
|
"target abort", "bad address parity", "page table read error",
|
|
|
"invalid page", "data error"
|
|
|
};
|
|
|
+ unsigned code = (stat0 & IOC_CODE) >> IOC_CODE_SHIFT;
|
|
|
+ unsigned cmd = (stat0 & IOC_CMD) >> IOC_CMD_SHIFT;
|
|
|
+
|
|
|
+ printk(" %s initiated PCI %s cycle to address %x"
|
|
|
+ " failed due to %s.\n",
|
|
|
+ code > 3 ? "PCI" : "CPU", pci_cmd[cmd], stat1, err_name[code]);
|
|
|
+
|
|
|
+ if (code == 5 || code == 6) {
|
|
|
+ printk(" (Error occurred at PCI memory address %x.)\n",
|
|
|
+ (stat0 & ~IOC_P_NBR));
|
|
|
+ }
|
|
|
+ if (stat0 & IOC_LOST) {
|
|
|
+ printk(" Other PCI errors occurred simultaneously.\n");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+lca_machine_check(unsigned long vector, unsigned long la_ptr)
|
|
|
+{
|
|
|
+ const char * reason;
|
|
|
+ union el_lca el;
|
|
|
+
|
|
|
+ el.c = (struct el_common *) la_ptr;
|
|
|
+
|
|
|
+ wrmces(rdmces()); /* reset machine check pending flag */
|
|
|
+
|
|
|
+ printk(KERN_CRIT "LCA machine check: vector=%#lx pc=%#lx code=%#x\n",
|
|
|
+ vector, get_irq_regs()->pc, (unsigned int) el.c->code);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The first quadword after the common header always seems to
|
|
|
+ * be the machine check reason---don't know why this isn't
|
|
|
+ * part of the common header instead. In the case of a long
|
|
|
+ * logout frame, the upper 32 bits is the machine check
|
|
|
+ * revision level, which we ignore for now.
|
|
|
+ */
|
|
|
+ switch ((unsigned int) el.c->code) {
|
|
|
+ case MCHK_K_TPERR: reason = "tag parity error"; break;
|
|
|
+ case MCHK_K_TCPERR: reason = "tag control parity error"; break;
|
|
|
+ case MCHK_K_HERR: reason = "access to non-existent memory"; break;
|
|
|
+ case MCHK_K_ECC_C: reason = "correctable ECC error"; break;
|
|
|
+ case MCHK_K_ECC_NC: reason = "non-correctable ECC error"; break;
|
|
|
+ case MCHK_K_CACKSOFT: reason = "MCHK_K_CACKSOFT"; break;
|
|
|
+ case MCHK_K_BUGCHECK: reason = "illegal exception in PAL mode"; break;
|
|
|
+ case MCHK_K_OS_BUGCHECK: reason = "callsys in kernel mode"; break;
|
|
|
+ case MCHK_K_DCPERR: reason = "d-cache parity error"; break;
|
|
|
+ case MCHK_K_ICPERR: reason = "i-cache parity error"; break;
|
|
|
+ case MCHK_K_SIO_SERR: reason = "SIO SERR occurred on PCI bus"; break;
|
|
|
+ case MCHK_K_SIO_IOCHK: reason = "SIO IOCHK occurred on ISA bus"; break;
|
|
|
+ case MCHK_K_DCSR: reason = "MCHK_K_DCSR"; break;
|
|
|
+ case MCHK_K_UNKNOWN:
|
|
|
+ default: reason = "unknown"; break;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (el.c->size) {
|
|
|
+ case sizeof(struct el_lca_mcheck_short):
|
|
|
+ printk(KERN_CRIT
|
|
|
+ " Reason: %s (short frame%s, dc_stat=%#lx):\n",
|
|
|
+ reason, el.c->retry ? ", retryable" : "",
|
|
|
+ el.s->dc_stat);
|
|
|
+ if (el.s->esr & ESR_EAV) {
|
|
|
+ mem_error(el.s->esr, el.s->ear);
|
|
|
+ }
|
|
|
+ if (el.s->ioc_stat0 & IOC_ERR) {
|
|
|
+ ioc_error(el.s->ioc_stat0, el.s->ioc_stat1);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case sizeof(struct el_lca_mcheck_long):
|
|
|
+ printk(KERN_CRIT " Reason: %s (long frame%s):\n",
|
|
|
+ reason, el.c->retry ? ", retryable" : "");
|
|
|
+ printk(KERN_CRIT
|
|
|
+ " reason: %#lx exc_addr: %#lx dc_stat: %#lx\n",
|
|
|
+ el.l->pt[0], el.l->exc_addr, el.l->dc_stat);
|
|
|
+ printk(KERN_CRIT " car: %#lx\n", el.l->car);
|
|
|
+ if (el.l->esr & ESR_EAV) {
|
|
|
+ mem_error(el.l->esr, el.l->ear);
|
|
|
+ }
|
|
|
+ if (el.l->ioc_stat0 & IOC_ERR) {
|
|
|
+ ioc_error(el.l->ioc_stat0, el.l->ioc_stat1);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ printk(KERN_CRIT " Unknown errorlog size %d\n", el.c->size);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Dump the logout area to give all info. */
|
|
|
+#ifdef CONFIG_VERBOSE_MCHECK
|
|
|
+ if (alpha_verbose_mcheck > 1) {
|
|
|
+ unsigned long * ptr = (unsigned long *) la_ptr;
|
|
|
+ long i;
|
|
|
+ for (i = 0; i < el.c->size / sizeof(long); i += 2) {
|
|
|
+ printk(KERN_CRIT " +%8lx %016lx %016lx\n",
|
|
|
+ i*sizeof(long), ptr[i], ptr[i+1]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif /* CONFIG_VERBOSE_MCHECK */
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * The following routines are needed to support the SPEED changing
|
|
|
+ * necessary to successfully manage the thermal problem on the AlphaBook1.
|
|
|
+ */
|
|
|
+
|
|
|
+void
|
|
|
+lca_clock_print(void)
|
|
|
+{
|
|
|
+ long pmr_reg;
|
|
|
+
|
|
|
+ pmr_reg = LCA_READ_PMR;
|
|
|
+
|
|
|
+ printk("Status of clock control:\n");
|
|
|
+ printk("\tPrimary clock divisor\t0x%lx\n", LCA_GET_PRIMARY(pmr_reg));
|
|
|
+ printk("\tOverride clock divisor\t0x%lx\n", LCA_GET_OVERRIDE(pmr_reg));
|
|
|
+ printk("\tInterrupt override is %s\n",
|
|
|
+ (pmr_reg & LCA_PMR_INTO) ? "on" : "off");
|
|
|
+ printk("\tDMA override is %s\n",
|
|
|
+ (pmr_reg & LCA_PMR_DMAO) ? "on" : "off");
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+int
|
|
|
+lca_get_clock(void)
|
|
|
+{
|
|
|
+ long pmr_reg;
|
|
|
+
|
|
|
+ pmr_reg = LCA_READ_PMR;
|
|
|
+ return(LCA_GET_PRIMARY(pmr_reg));
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+lca_clock_fiddle(int divisor)
|
|
|
+{
|
|
|
+ long pmr_reg;
|
|
|
+
|
|
|
+ pmr_reg = LCA_READ_PMR;
|
|
|
+ LCA_SET_PRIMARY_CLOCK(pmr_reg, divisor);
|
|
|
+ /* lca_norm_clock = divisor; */
|
|
|
+ LCA_WRITE_PMR(pmr_reg);
|
|
|
+ mb();
|
|
|
+}
|