* [PATCH v6 1/6] alpha: move Tsunami machine check handling to err_tsunami.c
2026-10-11 19:12 [PATCH v6 0/6] alpha: improve Tsunami machine check reporting Magnus Lindholm
@ 2026-10-11 19:12 ` Magnus Lindholm
2026-10-11 19:12 ` [PATCH v6 2/6] alpha: describe the Tsunami system machine check frame Magnus Lindholm
` (5 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Magnus Lindholm @ 2026-10-11 19:12 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
Move the existing handler and PCI error clearing helpers without changing
their behavior. Build the error objects for ALPHA_TSUNAMI so that all
Tsunami configurations, including non-generic Shark, can use them.
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
---
arch/alpha/kernel/Makefile | 4 ++-
arch/alpha/kernel/core_tsunami.c | 34 -----------------------
arch/alpha/kernel/err_tsunami.c | 47 ++++++++++++++++++++++++++++++++
3 files changed, 50 insertions(+), 35 deletions(-)
create mode 100644 arch/alpha/kernel/err_tsunami.c
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
index 4ea5c189e60e..a453e487b9d0 100644
--- a/arch/alpha/kernel/Makefile
+++ b/arch/alpha/kernel/Makefile
@@ -39,7 +39,7 @@ obj-y += err_ev7.o err_titan.o err_marvel.o
endif
obj-y += irq_pyxis.o irq_i8259.o irq_srm.o
-obj-y += err_ev6.o
+obj-y += err_ev6.o err_tsunami.o
obj-y += es1888.o smc37c669.o smc37c93x.o pc873xx.o gct.o
obj-y += srmcons.o
@@ -89,4 +89,6 @@ obj-$(CONFIG_ALPHA_MARVEL) += err_ev7.o err_marvel.o
obj-$(CONFIG_ALPHA_NAUTILUS) += err_ev6.o
obj-$(CONFIG_ALPHA_TITAN) += err_ev6.o err_titan.o
+obj-$(CONFIG_ALPHA_TSUNAMI) += err_tsunami.o
+
endif # GENERIC
diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c
index fc1ab73f23de..d435ec9fb828 100644
--- a/arch/alpha/kernel/core_tsunami.c
+++ b/arch/alpha/kernel/core_tsunami.c
@@ -448,37 +448,3 @@ tsunami_kill_arch(int mode)
if (TSUNAMI_cchip->csc.csr & 1L<<14)
tsunami_kill_one_pchip(TSUNAMI_pchip1, 1);
}
-
-static inline void
-tsunami_pci_clr_err_1(tsunami_pchip *pchip)
-{
- pchip->perror.csr;
- pchip->perror.csr = 0x040;
- mb();
- pchip->perror.csr;
-}
-
-static inline void
-tsunami_pci_clr_err(void)
-{
- tsunami_pci_clr_err_1(TSUNAMI_pchip0);
-
- /* TSUNAMI and TYPHOON can have 2, but might only have 1 (DS10) */
- if (TSUNAMI_cchip->csc.csr & 1L<<14)
- tsunami_pci_clr_err_1(TSUNAMI_pchip1);
-}
-
-void
-tsunami_machine_check(unsigned long vector, unsigned long la_ptr)
-{
- /* Clear error before any reporting. */
- mb();
- mb(); /* magic */
- draina();
- tsunami_pci_clr_err();
- wrmces(0x7);
- mb();
-
- process_mcheck_info(vector, la_ptr, "TSUNAMI",
- mcheck_expected(smp_processor_id()));
-}
diff --git a/arch/alpha/kernel/err_tsunami.c b/arch/alpha/kernel/err_tsunami.c
new file mode 100644
index 000000000000..1045b920fa6b
--- /dev/null
+++ b/arch/alpha/kernel/err_tsunami.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Machine check handling for Tsunami/Typhoon systems. */
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <asm/io.h>
+#include <asm/core_tsunami.h>
+#include <asm/smp.h>
+#include <asm/err_common.h>
+#include <asm/irq_regs.h>
+#include "err_impl.h"
+#include "proto.h"
+#include "pci_impl.h"
+
+static inline void
+tsunami_pci_clr_err_1(tsunami_pchip *pchip)
+{
+ pchip->perror.csr;
+ pchip->perror.csr = 0x040;
+ mb();
+ pchip->perror.csr;
+}
+
+static inline void
+tsunami_pci_clr_err(void)
+{
+ tsunami_pci_clr_err_1(TSUNAMI_pchip0);
+
+ /* TSUNAMI and TYPHOON can have 2, but might only have 1 (DS10) */
+ if (TSUNAMI_cchip->csc.csr & 1L<<14)
+ tsunami_pci_clr_err_1(TSUNAMI_pchip1);
+}
+
+void
+tsunami_machine_check(unsigned long vector, unsigned long la_ptr)
+{
+ /* Clear error before any reporting. */
+ mb();
+ mb(); /* magic */
+ draina();
+ tsunami_pci_clr_err();
+ wrmces(0x7);
+ mb();
+
+ process_mcheck_info(vector, la_ptr, "TSUNAMI",
+ mcheck_expected(smp_processor_id()));
+}
--
2.43.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH v6 2/6] alpha: describe the Tsunami system machine check frame
2026-10-11 19:12 [PATCH v6 0/6] alpha: improve Tsunami machine check reporting Magnus Lindholm
2026-10-11 19:12 ` [PATCH v6 1/6] alpha: move Tsunami machine check handling to err_tsunami.c Magnus Lindholm
@ 2026-10-11 19:12 ` Magnus Lindholm
2026-10-11 19:12 ` [PATCH v6 3/6] alpha: bound EV6 logout decoding by the processor area Magnus Lindholm
` (4 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Magnus Lindholm @ 2026-10-11 19:12 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
Define the five system-specific quadwords in the SRM logout frame,
as documented in the AlphaServer ES40 Service Guide, Table D-19.
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
---
arch/alpha/include/asm/core_tsunami.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/alpha/include/asm/core_tsunami.h b/arch/alpha/include/asm/core_tsunami.h
index 3391e95754f2..fe3fd4570fac 100644
--- a/arch/alpha/include/asm/core_tsunami.h
+++ b/arch/alpha/include/asm/core_tsunami.h
@@ -283,6 +283,11 @@ union TPchipPERRMASK {
* Data structure for handling TSUNAMI machine checks:
*/
struct el_TSUNAMI_sysdata_mcheck {
+ u64 sesf;
+ u64 dir;
+ u64 misc;
+ u64 p0_perror;
+ u64 p1_perror;
};
--
2.43.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH v6 3/6] alpha: bound EV6 logout decoding by the processor area
2026-10-11 19:12 [PATCH v6 0/6] alpha: improve Tsunami machine check reporting Magnus Lindholm
2026-10-11 19:12 ` [PATCH v6 1/6] alpha: move Tsunami machine check handling to err_tsunami.c Magnus Lindholm
2026-10-11 19:12 ` [PATCH v6 2/6] alpha: describe the Tsunami system machine check frame Magnus Lindholm
@ 2026-10-11 19:12 ` Magnus Lindholm
2026-10-11 19:59 ` Matt Turner
2026-10-11 19:12 ` [PATCH v6 4/6] alpha: decode and acknowledge Tsunami system machine checks Magnus Lindholm
` (3 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Magnus Lindholm @ 2026-10-11 19:12 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
The ES40 Service Guide, Table D-19, documents a correctable frame with
its system area at 0x58 and total size 0x80. The existing EV6 decoder
interprets system words as extended CPU registers and reads past its end.
This establishes the layout for ES40; whether Titan and Nautilus PALcode
also emits this short frame has not been verified.
Validate the processor area before decoding it and only print extended
registers when present. Preserve rejected frames with a raw dump rather
than trusting their invalid offsets. Cap the dump at 1 KiB and round down
to complete quadwords. This still relies on firmware supplying an
accessible frame of its advertised size; the cap is not pointer validation.
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/kernel/err_common.c | 13 ++++++++++++
arch/alpha/kernel/err_ev6.c | 38 +++++++++++++++++++++++++---------
arch/alpha/kernel/err_impl.h | 1 +
3 files changed, 42 insertions(+), 10 deletions(-)
diff --git a/arch/alpha/kernel/err_common.c b/arch/alpha/kernel/err_common.c
index 94e1b3dcf6d4..9271ea425a7b 100644
--- a/arch/alpha/kernel/err_common.c
+++ b/arch/alpha/kernel/err_common.c
@@ -44,6 +44,19 @@ mchk_dump_mem(void *data, size_t length, char **annotation)
}
}
+/* Preserve rejected frames without trusting their internal offsets. */
+void
+mchk_dump_logout_frame_raw(struct el_common *header)
+{
+ size_t length = header->size;
+
+ /* Bound diagnostic output and never read a partial final quadword. */
+ if (length > 1024)
+ length = 1024;
+ length &= ~7UL;
+ mchk_dump_mem(header, length, NULL);
+}
+
void
mchk_dump_logout_frame(struct el_common *mchk_header)
{
diff --git a/arch/alpha/kernel/err_ev6.c b/arch/alpha/kernel/err_ev6.c
index 8144f2045b5b..f12299ae1f24 100644
--- a/arch/alpha/kernel/err_ev6.c
+++ b/arch/alpha/kernel/err_ev6.c
@@ -190,6 +190,25 @@ ev6_process_logout_frame(struct el_common *mchk_header, int print)
(struct el_common_EV6_mcheck *)mchk_header;
int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+ /*
+ * ES40 correctable frames end the CPU area before EXC_ADDR (Table
+ * D-19). Validate both regions before decoding or dumping any data.
+ */
+ if (mchk_header->proc_offset != offsetof(struct el_common_EV6_mcheck,
+ I_STAT) ||
+ mchk_header->sys_offset < offsetof(struct el_common_EV6_mcheck,
+ EXC_ADDR) ||
+ mchk_header->sys_offset > mchk_header->size ||
+ ((mchk_header->sys_offset | mchk_header->size) & 7)) {
+ if (print) {
+ printk("%s Invalid EV6 logout frame: size %x, CPU %x, system %x\n",
+ err_print_prefix, mchk_header->size,
+ mchk_header->proc_offset, mchk_header->sys_offset);
+ mchk_dump_logout_frame_raw(mchk_header);
+ }
+ return MCHK_DISPOSITION_UNKNOWN_ERROR;
+ }
+
status |= ev6_parse_ibox(ev6mchk->I_STAT, print);
status |= ev6_parse_mbox(ev6mchk->MM_STAT, ev6mchk->DC_STAT,
ev6mchk->C_STAT, print);
@@ -203,16 +222,15 @@ ev6_process_logout_frame(struct el_common *mchk_header, int print)
if (status != MCHK_DISPOSITION_DISMISS) {
char *saved_err_prefix = err_print_prefix;
- /*
- * Dump some additional information from the frame
- */
- printk("%s EXC_ADDR: 0x%016lx IER_CM: 0x%016lx"
- " ISUM: 0x%016lx\n"
- " PAL_BASE: 0x%016lx I_CTL: 0x%016lx"
- " PCTX: 0x%016lx\n",
- err_print_prefix,
- ev6mchk->EXC_ADDR, ev6mchk->IER_CM, ev6mchk->ISUM,
- ev6mchk->PAL_BASE, ev6mchk->I_CTL, ev6mchk->PCTX);
+ /* These registers are absent from short correctable frames. */
+ if (mchk_header->sys_offset >= sizeof(*ev6mchk))
+ printk("%s EXC_ADDR: 0x%016lx IER_CM: 0x%016lx"
+ " ISUM: 0x%016lx\n"
+ " PAL_BASE: 0x%016lx I_CTL: 0x%016lx"
+ " PCTX: 0x%016lx\n",
+ err_print_prefix,
+ ev6mchk->EXC_ADDR, ev6mchk->IER_CM, ev6mchk->ISUM,
+ ev6mchk->PAL_BASE, ev6mchk->I_CTL, ev6mchk->PCTX);
if (status == MCHK_DISPOSITION_UNKNOWN_ERROR) {
printk("%s UNKNOWN error, frame follows:\n",
diff --git a/arch/alpha/kernel/err_impl.h b/arch/alpha/kernel/err_impl.h
index 737b958a586d..5bef23a00942 100644
--- a/arch/alpha/kernel/err_impl.h
+++ b/arch/alpha/kernel/err_impl.h
@@ -47,6 +47,7 @@ struct el_subpacket_handler {
extern char *err_print_prefix;
extern void mchk_dump_mem(void *, size_t, char **);
+extern void mchk_dump_logout_frame_raw(struct el_common *header);
extern void mchk_dump_logout_frame(struct el_common *);
extern void el_print_timestamp(union el_timestamp *);
extern void el_process_subpackets(struct el_subpacket *, int);
--
2.43.0
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v6 3/6] alpha: bound EV6 logout decoding by the processor area
2026-10-11 19:12 ` [PATCH v6 3/6] alpha: bound EV6 logout decoding by the processor area Magnus Lindholm
@ 2026-10-11 19:59 ` Matt Turner
0 siblings, 0 replies; 13+ messages in thread
From: Matt Turner @ 2026-10-11 19:59 UTC (permalink / raw)
To: Magnus Lindholm; +Cc: richard.henderson, linux-kernel, linux-alpha
> + if (mchk_header->proc_offset != offsetof(struct el_common_EV6_mcheck,
> + I_STAT) ||
This is stricter for Titan and Nautilus too, since both reach this
through ev6_machine_check() and Titan also through
privateer_process_logout_frame(). A frame that fails the check now gets
a raw dump where it used to get a decode. I think that is the right
trade, and the changelog says it is unverified there.
Reviewed-by: Matt Turner <mattst88@gmail.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v6 4/6] alpha: decode and acknowledge Tsunami system machine checks
2026-10-11 19:12 [PATCH v6 0/6] alpha: improve Tsunami machine check reporting Magnus Lindholm
` (2 preceding siblings ...)
2026-10-11 19:12 ` [PATCH v6 3/6] alpha: bound EV6 logout decoding by the processor area Magnus Lindholm
@ 2026-10-11 19:12 ` Magnus Lindholm
2026-10-11 20:00 ` Matt Turner
2026-10-11 19:12 ` [PATCH v6 5/6] alpha: decode Clipper environmental events and retain console logs Magnus Lindholm
` (2 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Magnus Lindholm @ 2026-10-11 19:12 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
Decode PCI and ECC transactions separately, honor invalid transaction
information, and select Pchip errors using the logout summary. Report
master aborts without importing Titan-specific dismissal policy.
Delegate processor vectors to the bounded EV6 decoder.
Capture live PERROR and MISC before acknowledging their defined W1C
bits and report live status absent from the saved frame. Leave PERRMASK
unchanged. HRM revision 4.0, Table 10-42 marks bit 9 reserved (MBZ/RAZ);
remove the obsolete RTO definition and reserve its bitfield position.
Use the system vector and frame bounds without restricting the reason
code to the ES40 values. Preserve invalid frames and unknown environmental
layouts in bounded raw dumps. Restore CPU register output for system
errors, including the PC needed to diagnose NXM.
Do not retain expected-probe handling: its only Tsunami writer is under
the undefined NXM_MACHINE_CHECKS_ON_TSUNAMI. Fatal-error policy is left
for a separate patch.
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/include/asm/core_tsunami.h | 3 +-
arch/alpha/kernel/Makefile | 2 +-
arch/alpha/kernel/err_tsunami.c | 241 ++++++++++++++++++++++++--
3 files changed, 225 insertions(+), 21 deletions(-)
diff --git a/arch/alpha/include/asm/core_tsunami.h b/arch/alpha/include/asm/core_tsunami.h
index fe3fd4570fac..5c5d3ff849ed 100644
--- a/arch/alpha/include/asm/core_tsunami.h
+++ b/arch/alpha/include/asm/core_tsunami.h
@@ -105,7 +105,6 @@ extern int TSUNAMI_bootcpu;
#define perror_m_ta 0x40
#define perror_m_rdpe 0x80
#define perror_m_nds 0x100
-#define perror_m_rto 0x200
#define perror_m_uecc 0x400
#define perror_m_cre 0x800
#define perror_m_addrl 0xFFFFFFFF0000UL
@@ -123,7 +122,7 @@ union TPchipPERROR {
unsigned perror_v_ta : 1;
unsigned perror_v_rdpe : 1;
unsigned perror_v_nds : 1;
- unsigned perror_v_rto : 1;
+ unsigned perror_v_reserved : 1; /* PERROR<9>: MBZ, RAZ */
unsigned perror_v_uecc : 1;
unsigned perror_v_cre : 1;
unsigned perror_v_rsvd1 : 4;
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
index a453e487b9d0..0178f6a5bdb8 100644
--- a/arch/alpha/kernel/Makefile
+++ b/arch/alpha/kernel/Makefile
@@ -89,6 +89,6 @@ obj-$(CONFIG_ALPHA_MARVEL) += err_ev7.o err_marvel.o
obj-$(CONFIG_ALPHA_NAUTILUS) += err_ev6.o
obj-$(CONFIG_ALPHA_TITAN) += err_ev6.o err_titan.o
-obj-$(CONFIG_ALPHA_TSUNAMI) += err_tsunami.o
+obj-$(CONFIG_ALPHA_TSUNAMI) += err_ev6.o err_tsunami.o
endif # GENERIC
diff --git a/arch/alpha/kernel/err_tsunami.c b/arch/alpha/kernel/err_tsunami.c
index 1045b920fa6b..91d187cb2a0d 100644
--- a/arch/alpha/kernel/err_tsunami.c
+++ b/arch/alpha/kernel/err_tsunami.c
@@ -1,9 +1,15 @@
// SPDX-License-Identifier: GPL-2.0
-/* Machine check handling for Tsunami/Typhoon systems. */
+/*
+ * Machine check handling for Tsunami/Typhoon systems.
+ * Author: Magnus Lindholm <linmag7@gmail.com>
+ * Based on Titan error handling by Jeff Wiedemeier (Compaq).
+ * Register definitions: 21272 Hardware Reference Manual, revision 4.0.
+ */
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/sched.h>
#include <asm/io.h>
+#include <asm/irq_regs.h>
#include <asm/core_tsunami.h>
#include <asm/smp.h>
#include <asm/err_common.h>
@@ -12,36 +18,235 @@
#include "proto.h"
#include "pci_impl.h"
-static inline void
-tsunami_pci_clr_err_1(tsunami_pchip *pchip)
+#define TSUNAMI_PERROR_ERRMASK 0xdffUL
+#define TSUNAMI_PERROR_ECCMASK (perror_m_uecc | perror_m_cre)
+#define TSUNAMI_PERROR_INV (1UL << 51)
+#define TSUNAMI_MISC_NXM (1UL << 28)
+
+static int
+tsunami_frame_valid(struct el_common *header, size_t size)
{
- pchip->perror.csr;
- pchip->perror.csr = 0x040;
+ return !((header->sys_offset | header->size) & 7) &&
+ header->sys_offset >= sizeof(*header) &&
+ header->sys_offset <= header->size &&
+ size <= header->size - header->sys_offset;
+}
+
+static int
+tsunami_parse_p_perror(int which, u64 perror, int print)
+{
+ static const char * const errors[] = {
+ "Lost error", "SERR asserted", "PERR asserted",
+ "Delayed-completion retry timeout", "Invalid scatter-gather PTE",
+ "Address parity error", "Target abort", "Read data parity error",
+ "No DEVSEL (master abort)", NULL,
+ "Uncorrectable ECC error", "Correctable ECC error"
+ };
+ static const char * const pci_cmd[] = {
+ "Interrupt acknowledge", "Special cycle", "I/O read", "I/O write",
+ "Reserved", "Reserved", "Memory read", "Memory write",
+ "Reserved", "Reserved", "Configuration read", "Configuration write",
+ "Memory read multiple", "Dual address cycle",
+ "Memory read line", "Memory write and invalidate"
+ };
+ unsigned long addr;
+ unsigned int cmd;
+ int i;
+
+ if (!(perror & TSUNAMI_PERROR_ERRMASK))
+ return MCHK_DISPOSITION_UNKNOWN_ERROR;
+ /* Do not import Titan's BIOS master-abort dismissal policy. */
+ if (!print)
+ return MCHK_DISPOSITION_REPORT;
+
+ printk("%s Pchip %d PERROR: %016llx\n", err_print_prefix, which, perror);
+ for (i = 0; i < ARRAY_SIZE(errors); i++)
+ if ((perror & TSUNAMI_PERROR_ERRMASK & (1UL << i)) && errors[i])
+ printk("%s %s\n", err_print_prefix, errors[i]);
+
+ /* INV invalidates SYN, CMD and ADDR; SERR has no command/address. */
+ if (perror & (TSUNAMI_PERROR_INV | perror_m_serr)) {
+ printk("%s Transaction information unavailable\n", err_print_prefix);
+ return MCHK_DISPOSITION_REPORT;
+ }
+ cmd = (perror & perror_m_cmd) >> 52;
+ if (perror & TSUNAMI_PERROR_ECCMASK) {
+ const char *command = "Reserved";
+
+ if (cmd == 0)
+ command = "DMA read";
+ else if (cmd == 1)
+ command = "DMA RMW";
+ else if (cmd == 3)
+ command = "SGTE read";
+ addr = ((perror >> 19) & 0xffffffffUL) << 3;
+ printk("%s Command: %s (%x), syndrome: %02llx\n",
+ err_print_prefix, command, cmd, (perror & perror_m_syn) >> 56);
+ printk("%s System address: %lx\n", err_print_prefix, addr);
+ } else {
+ addr = ((perror >> 18) & 0x3fffffffUL) << 2;
+ /* SGE captures only PCI address bits <31:13> (8KB page). */
+ if (perror & perror_m_sge)
+ addr &= ~0x1fffUL;
+ printk("%s Command: %s (%x), PCI address: %lx%s\n",
+ err_print_prefix, pci_cmd[cmd], cmd, addr,
+ (perror & perror_m_sge) ? " (8KB page)" : "");
+ if (perror & (1UL << 17))
+ printk("%s Monster window\n", err_print_prefix);
+ else if (perror & (1UL << 16))
+ printk("%s DAC scatter-gather window 3\n", err_print_prefix);
+ }
+ return MCHK_DISPOSITION_REPORT;
+}
+
+/* SESF bits 0/1 identify PCI errors, bit 2 covers ECC on either Pchip/CPU. */
+static u64
+tsunami_pchip_error(struct el_TSUNAMI_sysdata_mcheck *frame, int which)
+{
+ u64 perror = which ? frame->p1_perror : frame->p0_perror;
+
+ if (frame->sesf & (1UL << which))
+ return perror;
+ if ((frame->sesf & 4) && (perror & TSUNAMI_PERROR_ECCMASK))
+ return perror;
+ return 0;
+}
+
+static struct el_TSUNAMI_sysdata_mcheck *
+tsunami_system_frame(struct el_common *header)
+{
+ if (!tsunami_frame_valid(header, sizeof(struct el_TSUNAMI_sysdata_mcheck)))
+ return NULL;
+ return (void *)header + header->sys_offset;
+}
+
+static int
+tsunami_process_logout_frame(struct el_common *header, int print)
+{
+ struct el_TSUNAMI_sysdata_mcheck *frame = tsunami_system_frame(header);
+ int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+ int i;
+
+ if (!frame) {
+ if (print) {
+ printk("%s Invalid Tsunami system frame; raw frame follows\n",
+ err_print_prefix);
+ mchk_dump_logout_frame_raw(header);
+ }
+ return MCHK_DISPOSITION_UNKNOWN_ERROR;
+ }
+ if (print)
+ printk("%s SESF: %016llx DIR: %016llx MISC: %016llx\n",
+ err_print_prefix, frame->sesf, frame->dir, frame->misc);
+ if (frame->misc & TSUNAMI_MISC_NXM) {
+ status = MCHK_DISPOSITION_REPORT;
+ if (print)
+ printk("%s Non-existent memory, NXS: %llu\n",
+ err_print_prefix, (frame->misc >> 29) & 7);
+ }
+ for (i = 0; i < 2; i++)
+ status |= tsunami_parse_p_perror(i, tsunami_pchip_error(frame, i), print);
+ return status;
+}
+
+struct tsunami_error_state {
+ u64 perror[2];
+ u64 misc;
+};
+
+static void
+tsunami_ack_pchip(tsunami_pchip *pchip, u64 perror)
+{
+ if (!(perror & TSUNAMI_PERROR_ERRMASK))
+ return;
+ pchip->perror.csr = perror & TSUNAMI_PERROR_ERRMASK;
+ /* Complete the W1C write before releasing the logout frame. */
mb();
pchip->perror.csr;
}
-static inline void
-tsunami_pci_clr_err(void)
+static void
+tsunami_clear_errors(struct tsunami_error_state *state)
{
- tsunami_pci_clr_err_1(TSUNAMI_pchip0);
+ bool pchip1 = TSUNAMI_cchip->csc.csr & (1UL << 14);
- /* TSUNAMI and TYPHOON can have 2, but might only have 1 (DS10) */
- if (TSUNAMI_cchip->csc.csr & 1L<<14)
- tsunami_pci_clr_err_1(TSUNAMI_pchip1);
+ /* Preserve each chip's transaction and the NXM source before clearing. */
+ state->perror[0] = TSUNAMI_pchip0->perror.csr;
+ state->perror[1] = pchip1 ? TSUNAMI_pchip1->perror.csr : 0;
+ state->misc = TSUNAMI_cchip->misc.csr;
+
+ tsunami_ack_pchip(TSUNAMI_pchip0, state->perror[0]);
+ /* Do not access the second Pchip on single-Pchip systems. */
+ if (pchip1)
+ tsunami_ack_pchip(TSUNAMI_pchip1, state->perror[1]);
+ if (state->misc & TSUNAMI_MISC_NXM) {
+ /* Zero writes leave the other MISC fields unchanged. */
+ TSUNAMI_cchip->misc.csr = TSUNAMI_MISC_NXM;
+ /* Complete the NXM acknowledgment before releasing the frame. */
+ mb();
+ TSUNAMI_cchip->misc.csr;
+ }
+}
+
+static void
+tsunami_report_live_errors(struct tsunami_error_state *state,
+ struct el_TSUNAMI_sysdata_mcheck *frame)
+{
+ int i;
+
+ /* PALcode's frame may predate these errors, or describe another chip. */
+ for (i = 0; i < 2; i++) {
+ if (!(state->perror[i] & TSUNAMI_PERROR_ERRMASK) ||
+ (frame && state->perror[i] == tsunami_pchip_error(frame, i)))
+ continue;
+ printk("%s Live Pchip status before acknowledgment:\n", err_print_prefix);
+ tsunami_parse_p_perror(i, state->perror[i], 1);
+ }
+ if ((state->misc & TSUNAMI_MISC_NXM) &&
+ (!frame || ((state->misc ^ frame->misc) & (0xfUL << 28))))
+ printk("%s Live MISC: %016llx, non-existent memory, NXS: %llu\n",
+ err_print_prefix, state->misc, (state->misc >> 29) & 7);
}
void
tsunami_machine_check(unsigned long vector, unsigned long la_ptr)
{
- /* Clear error before any reporting. */
+ struct el_common *header = (void *)la_ptr;
+ struct el_TSUNAMI_sysdata_mcheck *frame = NULL;
+ struct tsunami_error_state live;
+ char *saved_err_prefix = err_print_prefix;
+
+ /* Synchronize pending accesses before inspecting the chipset. */
mb();
- mb(); /* magic */
- draina();
- tsunami_pci_clr_err();
- wrmces(0x7);
mb();
+ draina();
+ tsunami_clear_errors(&live);
+ if (vector == SCB_Q_SYSMCHK || vector == SCB_Q_SYSERR)
+ frame = tsunami_system_frame(header);
+
+ err_print_prefix = KERN_CRIT;
+ if (vector == SCB_Q_SYSMCHK || vector == SCB_Q_SYSERR) {
+ printk("%sSystem %s error (vector %lx, code %x) on CPU %d:\n",
+ err_print_prefix, vector == SCB_Q_SYSERR ? "correctable" :
+ "uncorrectable", vector, header->code, smp_processor_id());
+ tsunami_process_logout_frame(header, 1);
+ dik_show_regs(get_irq_regs(), NULL);
+ } else if (vector == SCB_Q_SYSEVENT) {
+ printk("%sTsunami environmental event (code %x): layout unknown\n",
+ err_print_prefix, header->code);
+ mchk_dump_logout_frame_raw(header);
+ }
+ tsunami_report_live_errors(&live, frame);
+ err_print_prefix = saved_err_prefix;
+
+ if (vector != SCB_Q_SYSMCHK && vector != SCB_Q_SYSERR &&
+ vector != SCB_Q_SYSEVENT) {
+ /* EV6 decoding also releases the logout frame. */
+ ev6_machine_check(vector, la_ptr);
+ } else {
+ wrmces(0x7);
+ /* Complete acknowledgment before resuming. */
+ mb();
+ }
- process_mcheck_info(vector, la_ptr, "TSUNAMI",
- mcheck_expected(smp_processor_id()));
}
--
2.43.0
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v6 4/6] alpha: decode and acknowledge Tsunami system machine checks
2026-10-11 19:12 ` [PATCH v6 4/6] alpha: decode and acknowledge Tsunami system machine checks Magnus Lindholm
@ 2026-10-11 20:00 ` Matt Turner
0 siblings, 0 replies; 13+ messages in thread
From: Matt Turner @ 2026-10-11 20:00 UTC (permalink / raw)
To: Magnus Lindholm; +Cc: richard.henderson, linux-kernel, linux-alpha
> +#include <asm/irq_regs.h>
> #include <asm/core_tsunami.h>
Patch 1 already includes this a few lines down, so it is now included
twice.
> + /* INV invalidates SYN, CMD and ADDR; SERR has no command/address. */
> + if (perror & (TSUNAMI_PERROR_INV | perror_m_serr)) {
If SERR is set together with another error bit, this throws away the
transaction that the other error latched. Can it test for SERR being
the only error bit?
Similarly, with an ECC bit and a PCI bit both set, the fields are
decoded as ECC. We cannot tell which came first, but a comment saying
so would help.
> + tsunami_clear_errors(&live);
This runs for every vector, and tsunami_report_live_errors() then
prints whatever was latched. Does a PERROR bit still latch when its
PERRMASK bit is clear? If it does, NDS left over from config probing
will show up at KERN_CRIT on an unrelated CPU error.
> + tsunami_process_logout_frame(header, 1);
> + dik_show_regs(get_irq_regs(), NULL);
For the correctable vector this is a full register dump per CRE. Titan
only does it under alpha_verbose_mcheck. The old code dumped as well,
so it is not a regression, but would you want the same gate for 620?
> + mb();
> + }
>
> - process_mcheck_info(vector, la_ptr, "TSUNAMI",
> - mcheck_expected(smp_processor_id()));
> }
This leaves a blank line before the closing brace until patch 6.
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v6 5/6] alpha: decode Clipper environmental events and retain console logs
2026-10-11 19:12 [PATCH v6 0/6] alpha: improve Tsunami machine check reporting Magnus Lindholm
` (3 preceding siblings ...)
2026-10-11 19:12 ` [PATCH v6 4/6] alpha: decode and acknowledge Tsunami system machine checks Magnus Lindholm
@ 2026-10-11 19:12 ` Magnus Lindholm
2026-10-11 20:00 ` Matt Turner
2026-10-11 19:12 ` [PATCH v6 6/6] alpha: stop on fatal Tsunami system ECC and write parity errors Magnus Lindholm
2026-10-11 19:59 ` [PATCH v6 0/6] alpha: improve Tsunami machine check reporting Matt Turner
6 siblings, 1 reply; 13+ messages in thread
From: Magnus Lindholm @ 2026-10-11 19:12 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
Restrict ES40 live environmental decoding to Clipper. Honor print control,
validate bounds and masks, and separate fault bits from status context.
Report valid notifications even when no recognized fault bits are set,
so door-closed and supply-return notifications are not silently discarded.
Do not infer a recovery transition from a single status snapshot.
Keep inverted SMIR halt/reset bits undecoded and print their raw value.
Use plain door-status messages without the manual's "Set =" prefix.
Dump unknown or truncated environmental frames raw.
Register bounded console decoders from the error file, but keep the PCI
init hook and console-log invocation in sys_dp264.c, as Titan does.
Limit console-log scanning to Clipper pending older-board firmware tests.
The ES40 boot and QEMU Clipper test do not establish that nonempty console
logs are safe on DS10, DS20 or XP1000 firmware.
Print console environmental packets raw: ES40 Table D-18's sys_offset
conflicts with its field offsets. Actual SRM records are still needed.
Terminate annotation arrays and reject invalid packet bounds/revisions.
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/include/asm/err_common.h | 2 +
arch/alpha/kernel/err_tsunami.c | 329 ++++++++++++++++++++++++++++
arch/alpha/kernel/proto.h | 2 +
arch/alpha/kernel/sys_dp264.c | 5 +-
4 files changed, 337 insertions(+), 1 deletion(-)
diff --git a/arch/alpha/include/asm/err_common.h b/arch/alpha/include/asm/err_common.h
index 610e01fe73ab..63d4320581e2 100644
--- a/arch/alpha/include/asm/err_common.h
+++ b/arch/alpha/include/asm/err_common.h
@@ -47,6 +47,8 @@
# define EL_TYPE__REGATTA__PROCESSOR_ERROR_FRAME (1)
# define EL_TYPE__REGATTA__SYSTEM_ERROR_FRAME (2)
# define EL_TYPE__REGATTA__ENVIRONMENTAL_FRAME (3)
+# define EL_TYPE__REGATTA__TSUNAMI_PCHIP0_EXTENDED (6)
+# define EL_TYPE__REGATTA__TSUNAMI_PCHIP1_EXTENDED (7)
# define EL_TYPE__REGATTA__TITAN_PCHIP0_EXTENDED (8)
# define EL_TYPE__REGATTA__TITAN_PCHIP1_EXTENDED (9)
# define EL_TYPE__REGATTA__TITAN_MEMORY_EXTENDED (10)
diff --git a/arch/alpha/kernel/err_tsunami.c b/arch/alpha/kernel/err_tsunami.c
index 91d187cb2a0d..91937fd2d6e0 100644
--- a/arch/alpha/kernel/err_tsunami.c
+++ b/arch/alpha/kernel/err_tsunami.c
@@ -250,3 +250,332 @@ tsunami_machine_check(unsigned long vector, unsigned long la_ptr)
}
}
+
+static const char * const CLIPPER_EnvQW1SMIR[] = {
+ "System Power Supply failure detected",
+ "OCP or RMC halt detected",
+ "Sys_DC_Notok failure detected",
+ "",
+ "System temperature over 50 degrees C failure",
+ "PCI Bus #0 is in reset",
+ "PCI Bus #1 is in reset",
+ "System is being reset"
+};
+
+static const char * const CLIPPER_EnvQW2CPUIR[] = {
+ "CPU0 regulator is enabled",
+ "CPU1 regulator is enabled",
+ "CPU2 regulator is enabled",
+ "CPU3 regulator is enabled",
+ "CPU0 regulator or configuration sequence fail",
+ "CPU1 regulator or configuration sequence fail",
+ "CPU2 regulator or configuration sequence fail",
+ "CPU3 regulator or configuration sequence fail"
+};
+
+static const char * const CLIPPER_EnvQW3PSIR[] = {
+ "Power Supply 0 is enabled",
+ "Power Supply 1 is enabled",
+ "Power Supply 2 is enabled",
+ "",
+ "Power Supply 0 was enabled but failed",
+ "Power Supply 1 was enabled but failed",
+ "Power Supply 2 was enabled but failed"
+};
+
+static const char * const CLIPPER_EnvQW4LM78ISR[] = {
+ "PS +3.3V out of tolerance",
+ "PS +5V out of tolerance",
+ "PS +12V out of tolerance",
+ "VTERM out of tolerance",
+ "Temperature zone 0 (PCI Backplane slots 1-3 area) over limit failure",
+ "LM75 CPU0-3 Temperature over limit failure",
+ "System Fan 1 failure",
+ "System Fan 2 failure",
+ "CTERM out of tolerance",
+ "",
+ "-12V out of tolerance",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "CPU0_VCORE +2V out of tolerance",
+ "CPU0_VIO +1.5V out of tolerance",
+ "CPU1_VCORE +2V out of tolerance",
+ "CPU1_VIO +1.5V out of tolerance",
+ "Temperature zone 1 (PCI Backplane slots 7-10 area) over limit failure",
+ "",
+ "System Fan 4 failure",
+ "System Fan 5 failure",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "CPU2_VCORE +2V out of tolerance",
+ "CPU2_VIO +1.5V out of tolerance",
+ "CPU3_VCORE +2V out of tolerance",
+ "CPU3_VIO +1.5V out of tolerance",
+ "Temperature zone 2 (PCI Backplane slots 4-6 area) over limit failure",
+ "",
+ "System Fan 3 failure",
+ "System Fan 6 failure",
+ "",
+ "",
+ "Power supply 3.3V rail above high amperage warning",
+ "Power supply 5.0V rail above high amperage warning",
+ "Power supply 12V rail above high amperage warning",
+ "Power supply high temperature warning",
+ "Power supply AC input low limit warning",
+ "Power supply AC input high limit warning"
+};
+
+static const char * const CLIPPER_EnvQW5DOOR[] = {
+ "",
+ "System CPU door is open",
+ "System Fan door is open",
+ "System PCI door is open",
+ "",
+ "System CPU door is closed",
+ "System Fan door is closed",
+ "System PCI door is closed"
+};
+
+static const char * const CLIPPER_EnvQW6TEMP[] = {
+ "CPU0 temperature warning fault has occurred",
+ "CPU1 temperature warning fault has occurred",
+ "CPU2 temperature warning fault has occurred",
+ "CPU3 temperature warning fault has occurred",
+ "System temperature zone 0 warning fault has occurred",
+ "System temperature zone 1 warning fault has occurred",
+ "System temperature zone 2 warning fault has occurred"
+};
+
+static const char * const CLIPPER_EnvQW7FAN[] = {
+ "System Fan 1 is not responding to RMC Commands",
+ "System Fan 2 is not responding to RMC Commands",
+ "System Fan 3 is not responding to RMC Commands",
+ "System Fan 4 is not responding to RMC Commands",
+ "System Fan 5 is not responding to RMC Commands",
+ "System Fan 6 is not responding to RMC Commands",
+ "",
+ "",
+ "CPU fans 5/6 at maximum speed",
+ "CPU fans 5/6 reduced speed from maximum",
+ "PCI fans 1-4 at maximum speed",
+ "PCI fans 1-4 reduced speed from maximum"
+};
+
+#define CLIPPER_ENV_LM78ISR_MASK 0xfcdf00df05ffUL
+
+static char *el_tsunami_pchip0_extended_annotation[] = {
+"Subpacket Header", "P0_PCTL", "P0_PERRMASK",
+"P0_WSBA0", "P0_WSBA1", "P0_WSBA2", "P0_WSBA3",
+"P0_WSM0", "P0_WSM1", "P0_WSM2", "P0_WSM3",
+"P0_TBA0", "P0_TBA1", "P0_TBA2", "P0_TBA3", NULL
+};
+
+static char *el_tsunami_pchip1_extended_annotation[] = {
+"Subpacket Header", "P1_PCTL", "P1_PERRMASK",
+"P1_WSBA0", "P1_WSBA1", "P1_WSBA2", "P1_WSBA3",
+"P1_WSM0", "P1_WSM1", "P1_WSM2", "P1_WSM3",
+"P1_TBA0", "P1_TBA1", "P1_TBA2", "P1_TBA3", NULL
+};
+
+
+static struct el_subpacket_annotation el_tsunami_annotations[] = {
+ SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+ EL_TYPE__REGATTA__TSUNAMI_PCHIP0_EXTENDED,
+ 1,
+ "Tsunami PChip 0 Extended Frame",
+ el_tsunami_pchip0_extended_annotation),
+ SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+ EL_TYPE__REGATTA__TSUNAMI_PCHIP1_EXTENDED,
+ 1,
+ "Tsunami PChip 1 Extended Frame",
+ el_tsunami_pchip1_extended_annotation),
+ SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+ EL_TYPE__TERMINATION__TERMINATION,
+ 1,
+ "Termination Subpacket",
+ NULL)
+};
+
+/* ES40 Service Guide EK-ES240-SV A01, live frame: Tables D-20 and D-21. */
+struct el_clipper_envdata {
+ u64 summary;
+ u64 dir;
+ u64 smir;
+ u64 cpuir;
+ u64 psir;
+ u64 fault;
+ u64 doors;
+ u64 temp_warn;
+ u64 fan_ctrl;
+ u64 fatal_power_down;
+ u64 reserved;
+};
+
+static int
+clipper_print_bits(const char * const *messages, size_t count,
+ u64 value, u64 mask, int print)
+{
+ size_t i;
+
+ if (!(value & mask))
+ return MCHK_DISPOSITION_DISMISS;
+ if (print)
+ for (i = 0; i < count; i++)
+ if (value & mask & (1UL << i))
+ printk("%s %s\n", err_print_prefix, messages[i]);
+ return MCHK_DISPOSITION_REPORT;
+}
+
+#define CLIPPER_BITS(table, value, mask) \
+ clipper_print_bits(table, ARRAY_SIZE(table), value, mask, print)
+
+static int
+clipper_process_environment(struct el_common *header, int print)
+{
+ struct el_clipper_envdata *frame;
+ int status = 0;
+
+ if (!tsunami_frame_valid(header, sizeof(*frame))) {
+ if (print) {
+ printk("%s Truncated Clipper environmental frame\n", err_print_prefix);
+ mchk_dump_logout_frame_raw(header);
+ }
+ return MCHK_DISPOSITION_UNKNOWN_ERROR;
+ }
+ frame = (void *)header + header->sys_offset;
+ /* Only QW1 through QW7 carry error state in the live 680 frame. */
+ /* Inverted halt/reset signals remain raw context until verified. */
+ status |= CLIPPER_BITS(CLIPPER_EnvQW1SMIR, frame->smir, 0x15);
+ status |= CLIPPER_BITS(CLIPPER_EnvQW2CPUIR, frame->cpuir, 0xf0);
+ status |= CLIPPER_BITS(CLIPPER_EnvQW3PSIR, frame->psir, 0x70);
+ status |= CLIPPER_BITS(CLIPPER_EnvQW4LM78ISR,
+ frame->fault, CLIPPER_ENV_LM78ISR_MASK);
+ status |= CLIPPER_BITS(CLIPPER_EnvQW5DOOR, frame->doors, 0x0e);
+ status |= CLIPPER_BITS(CLIPPER_EnvQW6TEMP, frame->temp_warn, 0x7f);
+ status |= CLIPPER_BITS(CLIPPER_EnvQW7FAN, frame->fan_ctrl, 0x3f);
+ /* A notification with no recognized fault can describe recovery. */
+ if (print && !(status & MCHK_DISPOSITION_REPORT))
+ printk("%s No recognized environmental fault bits set\n",
+ err_print_prefix);
+ if (print) {
+ printk("%s Environmental summary: %016llx DIR: %016llx\n",
+ err_print_prefix, frame->summary, frame->dir);
+ printk("%s SMIR: %016llx (inverted halt/reset bits undecoded)\n",
+ err_print_prefix, frame->smir);
+ CLIPPER_BITS(CLIPPER_EnvQW2CPUIR, frame->cpuir, 0x0f);
+ CLIPPER_BITS(CLIPPER_EnvQW3PSIR, frame->psir, 0x07);
+ CLIPPER_BITS(CLIPPER_EnvQW5DOOR, frame->doors, 0xe0);
+ CLIPPER_BITS(CLIPPER_EnvQW7FAN, frame->fan_ctrl, 0xf00);
+ if (frame->fault & (0x3fUL << 42))
+ printk("%s Power supply warning source: %llu (3 = reserved)\n",
+ err_print_prefix, (frame->fault >> 40) & 3);
+ }
+ return MCHK_DISPOSITION_REPORT;
+}
+
+void
+clipper_machine_check(unsigned long vector, unsigned long la_ptr)
+{
+ struct el_common *header = (void *)la_ptr;
+ char *saved_err_prefix = err_print_prefix;
+
+ if (vector != SCB_Q_SYSEVENT) {
+ tsunami_machine_check(vector, la_ptr);
+ return;
+ }
+ /* Drain pending accesses before inspecting the environmental frame. */
+ mb();
+ draina();
+ if (header->code != 0x206 ||
+ clipper_process_environment(header, 0) != MCHK_DISPOSITION_DISMISS) {
+ err_print_prefix = KERN_CRIT;
+ printk("%sSystem correctable environmental event (code %x) on CPU %d:\n",
+ err_print_prefix, header->code, smp_processor_id());
+ if (header->code == 0x206)
+ clipper_process_environment(header, 1);
+ else {
+ printk("%s Unrecognized environmental event; raw frame follows\n",
+ err_print_prefix);
+ mchk_dump_logout_frame_raw(header);
+ }
+ err_print_prefix = saved_err_prefix;
+ }
+ wrmces(0x7);
+ /* Complete acknowledgment before returning from the event. */
+ mb();
+}
+
+static struct el_subpacket *
+tsunami_process_subpacket(struct el_subpacket *packet)
+{
+ struct el_common *frame;
+ size_t offset = offsetof(struct el_subpacket, by_type.regatta_frame.data_start);
+ int status;
+
+ /* Raw dumps consume whole quadwords, and the next packet must advance. */
+ if (packet->length < offsetof(struct el_subpacket, by_type) ||
+ (packet->length & 7))
+ return NULL;
+ if (packet->revision != 1) {
+ el_annotate_subpacket(packet);
+ return (void *)packet + packet->length;
+ }
+
+ switch (packet->type) {
+ case EL_TYPE__REGATTA__PROCESSOR_ERROR_FRAME:
+ case EL_TYPE__REGATTA__PROCESSOR_DBL_ERROR_HALT:
+ case EL_TYPE__REGATTA__SYSTEM_ERROR_FRAME:
+ case EL_TYPE__REGATTA__SYSTEM_DBL_ERROR_HALT:
+ if (packet->length < offset + sizeof(*frame))
+ return NULL;
+ frame = (void *)packet + offset;
+ if (frame->size > packet->length - offset || frame->size < sizeof(*frame))
+ return NULL;
+ if (packet->type == EL_TYPE__REGATTA__PROCESSOR_ERROR_FRAME ||
+ packet->type == EL_TYPE__REGATTA__PROCESSOR_DBL_ERROR_HALT) {
+ status = ev6_process_logout_frame(frame, 0);
+ if (status != MCHK_DISPOSITION_DISMISS)
+ ev6_process_logout_frame(frame, 1);
+ } else {
+ tsunami_process_logout_frame(frame, 1);
+ }
+ break;
+ case EL_TYPE__REGATTA__ENVIRONMENTAL_FRAME:
+ /*
+ * ES40 Table D-18 gives sys_offset=0x20, but places the
+ * summary at frame+0x18. Preserve the complete packet until
+ * the console layout is verified; do not apply the live layout.
+ */
+ printk("%s Console environmental layout unverified; raw packet follows\n",
+ err_print_prefix);
+ el_annotate_subpacket(packet);
+ break;
+ default:
+ el_annotate_subpacket(packet);
+ break;
+ }
+ return (void *)packet + packet->length;
+}
+
+static struct el_subpacket_handler tsunami_subpacket_handler =
+ SUBPACKET_HANDLER_INIT(EL_CLASS__REGATTA_FAMILY, tsunami_process_subpacket);
+
+void __init
+tsunami_register_error_handlers(void)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(el_tsunami_annotations); i++)
+ cdl_register_subpacket_annotation(&el_tsunami_annotations[i]);
+ cdl_register_subpacket_handler(&tsunami_subpacket_handler);
+ ev6_register_error_handlers();
+}
diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h
index f138bd494628..16dbc02954b7 100644
--- a/arch/alpha/kernel/proto.h
+++ b/arch/alpha/kernel/proto.h
@@ -78,6 +78,8 @@ extern struct _alpha_agp_info *titan_agp_info(void);
extern struct pci_ops tsunami_pci_ops;
extern void tsunami_init_arch(void);
extern void tsunami_kill_arch(int);
+extern void tsunami_register_error_handlers(void);
+extern void clipper_machine_check(unsigned long vector, unsigned long la_ptr);
extern void tsunami_machine_check(unsigned long vector, unsigned long la_ptr);
extern void tsunami_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c
index 0a2d319bb1c8..0ebee9aad98d 100644
--- a/arch/alpha/kernel/sys_dp264.c
+++ b/arch/alpha/kernel/sys_dp264.c
@@ -32,6 +32,7 @@
#include "proto.h"
#include "irq_impl.h"
+#include "err_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
@@ -533,6 +534,8 @@ monet_init_pci(void)
static void __init
clipper_init_pci(void)
{
+ tsunami_register_error_handlers();
+ cdl_check_console_data_log();
common_init_pci();
locate_and_init_vga(NULL);
}
@@ -627,7 +630,7 @@ struct alpha_machine_vector clipper_mv __initmv = {
DO_EV6_MMU,
DO_DEFAULT_RTC,
DO_TSUNAMI_IO,
- .machine_check = tsunami_machine_check,
+ .machine_check = clipper_machine_check,
.max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
.min_io_address = DEFAULT_IO_BASE,
.min_mem_address = DEFAULT_MEM_BASE,
--
2.43.0
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v6 5/6] alpha: decode Clipper environmental events and retain console logs
2026-10-11 19:12 ` [PATCH v6 5/6] alpha: decode Clipper environmental events and retain console logs Magnus Lindholm
@ 2026-10-11 20:00 ` Matt Turner
0 siblings, 0 replies; 13+ messages in thread
From: Matt Turner @ 2026-10-11 20:00 UTC (permalink / raw)
To: Magnus Lindholm; +Cc: richard.henderson, linux-kernel, linux-alpha
> + if (header->code != 0x206 ||
> + clipper_process_environment(header, 0) != MCHK_DISPOSITION_DISMISS) {
clipper_process_environment() returns MCHK_DISPOSITION_REPORT for any
valid frame and UNKNOWN_ERROR for a truncated one. It never returns
DISMISS, so this condition is always true. The silent first pass can
go, and the body can lose a level of indentation.
> + status |= CLIPPER_BITS(CLIPPER_EnvQW1SMIR, frame->smir, 0x15);
Your cover letter says SMIR bit 0 stayed set in all three reports,
including the one after the supply was reconnected and its own failure
bit had cleared. With this mask that last report prints "System Power
Supply failure detected" for a recovery. Bit 0 looks latched, or
inverted like the halt and reset bits. I would treat it as raw context
(mask 0x14) until we know. Could you post the dmesg from that test?
> + if (packet->type == EL_TYPE__REGATTA__PROCESSOR_ERROR_FRAME ||
Minor: Titan prints by_type.regatta_frame.cpuid for these. It would be
useful here as well.
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v6 6/6] alpha: stop on fatal Tsunami system ECC and write parity errors
2026-10-11 19:12 [PATCH v6 0/6] alpha: improve Tsunami machine check reporting Magnus Lindholm
` (4 preceding siblings ...)
2026-10-11 19:12 ` [PATCH v6 5/6] alpha: decode Clipper environmental events and retain console logs Magnus Lindholm
@ 2026-10-11 19:12 ` Magnus Lindholm
2026-10-11 20:01 ` Matt Turner
2026-10-11 19:59 ` [PATCH v6 0/6] alpha: improve Tsunami machine check reporting Matt Turner
6 siblings, 1 reply; 13+ messages in thread
From: Magnus Lindholm @ 2026-10-11 19:12 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
The 21272 HRM revision 4.0, section 8.8.1.1.2, describes uncorrectable
memory errors reported through PERROR<UECC>. Section 8.8.2.4 describes
PERROR<PERR>: incoming writes with bad parity can poison memory ECC and
have side effects on later writes; software is expected to crash.
PERR also covers parity errors reported by a PCI target on outgoing
writes. Treat either case conservatively as data integrity compromised.
After reporting and acknowledging a system error, panic for UECC or
PERR in either the saved frame or live Pchip snapshot. Saved errors must
not disappear merely because firmware already cleared the live register.
Limit this policy to system-error vectors: incidental PERROR state on a
CPU error or environmental vector must not trigger this new panic path.
This changes the old handler's policy and is kept separate so it can be
reviewed or reverted independently. Hardware UECC/PERR injection has not
been performed; validation of this policy uses synthetic handler tests.
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/kernel/err_tsunami.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/arch/alpha/kernel/err_tsunami.c b/arch/alpha/kernel/err_tsunami.c
index 91937fd2d6e0..386304776805 100644
--- a/arch/alpha/kernel/err_tsunami.c
+++ b/arch/alpha/kernel/err_tsunami.c
@@ -19,6 +19,7 @@
#include "pci_impl.h"
#define TSUNAMI_PERROR_ERRMASK 0xdffUL
+#define TSUNAMI_PERROR_FATAL (perror_m_uecc | perror_m_perr)
#define TSUNAMI_PERROR_ECCMASK (perror_m_uecc | perror_m_cre)
#define TSUNAMI_PERROR_INV (1UL << 51)
#define TSUNAMI_MISC_NXM (1UL << 28)
@@ -215,14 +216,22 @@ tsunami_machine_check(unsigned long vector, unsigned long la_ptr)
struct el_TSUNAMI_sysdata_mcheck *frame = NULL;
struct tsunami_error_state live;
char *saved_err_prefix = err_print_prefix;
+ u64 perror;
+ bool fatal = false;
/* Synchronize pending accesses before inspecting the chipset. */
mb();
mb();
draina();
tsunami_clear_errors(&live);
- if (vector == SCB_Q_SYSMCHK || vector == SCB_Q_SYSERR)
+ if (vector == SCB_Q_SYSMCHK || vector == SCB_Q_SYSERR) {
frame = tsunami_system_frame(header);
+ perror = live.perror[0] | live.perror[1];
+ if (frame)
+ perror |= tsunami_pchip_error(frame, 0) |
+ tsunami_pchip_error(frame, 1);
+ fatal = perror & TSUNAMI_PERROR_FATAL;
+ }
err_print_prefix = KERN_CRIT;
if (vector == SCB_Q_SYSMCHK || vector == SCB_Q_SYSERR) {
@@ -249,6 +258,8 @@ tsunami_machine_check(unsigned long vector, unsigned long la_ptr)
mb();
}
+ if (fatal)
+ panic("Tsunami: uncorrectable ECC or PCI write parity error");
}
static const char * const CLIPPER_EnvQW1SMIR[] = {
--
2.43.0
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v6 6/6] alpha: stop on fatal Tsunami system ECC and write parity errors
2026-10-11 19:12 ` [PATCH v6 6/6] alpha: stop on fatal Tsunami system ECC and write parity errors Magnus Lindholm
@ 2026-10-11 20:01 ` Matt Turner
2026-10-12 4:57 ` Magnus Lindholm
0 siblings, 1 reply; 13+ messages in thread
From: Matt Turner @ 2026-10-11 20:01 UTC (permalink / raw)
To: Magnus Lindholm; +Cc: richard.henderson, linux-kernel, linux-alpha
> +#define TSUNAMI_PERROR_FATAL (perror_m_uecc | perror_m_perr)
Why PERR and not RDPE? Bad parity on data read from PCI seems just as
bad for the consumer. If the HRM says the Pchip poisons that data and
the CPU takes a 670 for it, please say so in the changelog.
> + perror = live.perror[0] | live.perror[1];
The changelog says incidental PERROR state on a CPU or environmental
vector cannot trigger the panic. It still can on a system vector: UECC
or PERR latched before an unrelated NXM will panic here. That may be
what you want, since the error is real either way, but the changelog
should cover it. It also depends on the PERRMASK question I asked on
patch 4.
Two things that I think belong in the changelog:
A CPU-detected uncorrectable ECC error (670 through
ev6_machine_check()) still does not panic, so after this patch the
policy differs by who detected the error.
A PCI card with a marginal connection that asserts PERR# now takes the
machine down, where before it logged and carried on.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 6/6] alpha: stop on fatal Tsunami system ECC and write parity errors
2026-10-11 20:01 ` Matt Turner
@ 2026-10-12 4:57 ` Magnus Lindholm
0 siblings, 0 replies; 13+ messages in thread
From: Magnus Lindholm @ 2026-10-12 4:57 UTC (permalink / raw)
To: Matt Turner; +Cc: richard.henderson, linux-kernel, linux-alpha
Hi Matt,
On Sun, Oct 11, 2026 at 10:01 PM Matt Turner <mattst88@gmail.com> wrote:
>
> > +#define TSUNAMI_PERROR_FATAL (perror_m_uecc | perror_m_perr)
>
> Why PERR and not RDPE? Bad parity on data read from PCI seems just as
> bad for the consumer. If the HRM says the Pchip poisons that data and
> the CPU takes a 670 for it, please say so in the changelog.
>
> > + perror = live.perror[0] | live.perror[1];
>
> The changelog says incidental PERROR state on a CPU or environmental
> vector cannot trigger the panic. It still can on a system vector: UECC
> or PERR latched before an unrelated NXM will panic here. That may be
> what you want, since the error is real either way, but the changelog
> should cover it. It also depends on the PERRMASK question I asked on
> patch 4.
>
> Two things that I think belong in the changelog:
>
> A CPU-detected uncorrectable ECC error (670 through
> ev6_machine_check()) still does not panic, so after this patch the
> policy differs by who detected the error.
>
> A PCI card with a marginal connection that asserts PERR# now takes the
> machine down, where before it logged and carried on.
Thanks, these are good points. Would it make sense to drop patch 6
for now and address the panic policy in a follow-up? That would let
us consider RDPE, CPU-detected ECC and previously latched errors
alongside UECC/PERR, including the impact of a device asserting PERR#.
V7 could then focus on the reporting and acknowledgment improvements.
That would preserve the existing continuation behavior for now,
without implying that continuing after an uncorrectable error is safe.
Magnus
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 0/6] alpha: improve Tsunami machine check reporting
2026-10-11 19:12 [PATCH v6 0/6] alpha: improve Tsunami machine check reporting Magnus Lindholm
` (5 preceding siblings ...)
2026-10-11 19:12 ` [PATCH v6 6/6] alpha: stop on fatal Tsunami system ECC and write parity errors Magnus Lindholm
@ 2026-10-11 19:59 ` Matt Turner
6 siblings, 0 replies; 13+ messages in thread
From: Matt Turner @ 2026-10-11 19:59 UTC (permalink / raw)
To: Magnus Lindholm; +Cc: richard.henderson, linux-kernel, linux-alpha
On Sun, Oct 11, 2026 at 9:12 PM Magnus Lindholm <linmag7@gmail.com> wrote:
> This series adds Tsunami/Typhoon system-error diagnostics and Clipper
> ES40 environmental reporting.
I built each patch as vmlinux with W=1 for GENERIC, DP264, SHARK and
EIGER (gcc 16.2.0). All 24 builds pass with no warnings in the files
the series touches, so the err_ev6.o move to patch 4 bisects fine. The
tip boots GENERIC on QEMU Clipper as far as mounting root.
I have not exercised any of the machine check paths, and I did not
check the PERROR field layout, subpacket types 6/7 or the Clipper bit
tables against the manuals.
Comments on 4, 5 and 6 in reply to those patches.
^ permalink raw reply [flat|nested] 13+ messages in thread