xref: /linux/arch/alpha/kernel/err_tsunami.c (revision 742f62b63904cdc20a364a49d2861e32464a0af7)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Machine check handling for Tsunami/Typhoon systems.
4  * Author: Magnus Lindholm <linmag7@gmail.com>
5  * Based on Titan error handling by Jeff Wiedemeier (Compaq).
6  * Register definitions: 21272 Hardware Reference Manual, revision 4.0.
7  */
8 #include <linux/init.h>
9 #include <linux/printk.h>
10 #include <linux/pci.h>
11 #include <linux/sched.h>
12 #include <asm/io.h>
13 #include <asm/hwrpb.h>
14 #include <asm/core_tsunami.h>
15 #include <asm/smp.h>
16 #include <asm/err_common.h>
17 #include <asm/irq_regs.h>
18 #include "err_impl.h"
19 #include "proto.h"
20 #include "pci_impl.h"
21 
22 #define TSUNAMI_PERROR_ERRMASK	0xdffUL
23 #define TSUNAMI_PERROR_ECCMASK	(perror_m_uecc | perror_m_cre)
24 #define TSUNAMI_PERROR_INV	(1UL << 51)
25 #define TSUNAMI_MISC_NXM		(1UL << 28)
26 
27 static int
tsunami_frame_valid(struct el_common * header,size_t size)28 tsunami_frame_valid(struct el_common *header, size_t size)
29 {
30 	return !((header->sys_offset | header->size) & 7) &&
31 	       header->sys_offset >= sizeof(*header) &&
32 	       header->sys_offset <= header->size &&
33 	       size <= header->size - header->sys_offset;
34 }
35 
36 static int
tsunami_parse_p_perror(int which,u64 perror,int print)37 tsunami_parse_p_perror(int which, u64 perror, int print)
38 {
39 	static const char * const errors[] = {
40 		"Lost error", "SERR asserted", "PERR asserted",
41 		"Delayed-completion retry timeout", "Invalid scatter-gather PTE",
42 		"Address parity error", "Target abort", "Read data parity error",
43 		"No DEVSEL (master abort)", NULL,
44 		"Uncorrectable ECC error", "Correctable ECC error"
45 	};
46 	static const char * const pci_cmd[] = {
47 		"Interrupt acknowledge", "Special cycle", "I/O read", "I/O write",
48 		"Reserved", "Reserved", "Memory read", "Memory write",
49 		"Reserved", "Reserved", "Configuration read", "Configuration write",
50 		"Memory read multiple", "Dual address cycle",
51 		"Memory read line", "Memory write and invalidate"
52 	};
53 	unsigned long addr;
54 	unsigned int cmd;
55 	int i;
56 
57 	if (!(perror & TSUNAMI_PERROR_ERRMASK))
58 		return MCHK_DISPOSITION_UNKNOWN_ERROR;
59 	/* Do not import Titan's BIOS master-abort dismissal policy. */
60 	if (!print)
61 		return MCHK_DISPOSITION_REPORT;
62 
63 	printk("%s  Pchip %d PERROR: %016llx\n", err_print_prefix, which, perror);
64 	for (i = 0; i < ARRAY_SIZE(errors); i++)
65 		if ((perror & TSUNAMI_PERROR_ERRMASK & (1UL << i)) && errors[i])
66 			printk("%s    %s\n", err_print_prefix, errors[i]);
67 
68 	/*
69 	 * INV invalidates SYN, CMD and ADDR. HRM 8.8.2.6 leaves command/address
70 	 * undefined whenever SERR is set, including with other error bits.
71 	 */
72 	if (perror & (TSUNAMI_PERROR_INV | perror_m_serr)) {
73 		printk("%s    Transaction information unavailable\n", err_print_prefix);
74 		return MCHK_DISPOSITION_REPORT;
75 	}
76 	cmd = (perror & perror_m_cmd) >> 52;
77 	/*
78 	 * Table 10-42 selects the ECC fields whenever CRE or UECC is set.
79 	 * The first error freezes PERROR (10.2.5.6); mixed error bits were
80 	 * detected together. Only LOST can be set afterwards.
81 	 */
82 	if (perror & TSUNAMI_PERROR_ECCMASK) {
83 		const char *command = "Reserved";
84 
85 		if (cmd == 0)
86 			command = "DMA read";
87 		else if (cmd == 1)
88 			command = "DMA RMW";
89 		else if (cmd == 3)
90 			command = "SGTE read";
91 		addr = ((perror >> 19) & 0xffffffffUL) << 3;
92 		printk("%s    Command: %s (%x), syndrome: %02llx\n",
93 		       err_print_prefix, command, cmd, (perror & perror_m_syn) >> 56);
94 		printk("%s    System address: %lx\n", err_print_prefix, addr);
95 	} else {
96 		addr = ((perror >> 18) & 0x3fffffffUL) << 2;
97 		/* SGE captures only PCI address bits <31:13> (8KB page). */
98 		if (perror & perror_m_sge)
99 			addr &= ~0x1fffUL;
100 		printk("%s    Command: %s (%x), PCI address: %lx%s\n",
101 		       err_print_prefix, pci_cmd[cmd], cmd, addr,
102 		       (perror & perror_m_sge) ? " (8KB page)" : "");
103 		if (perror & (1UL << 17))
104 			printk("%s    Monster window\n", err_print_prefix);
105 		else if (perror & (1UL << 16))
106 			printk("%s    DAC scatter-gather window 3\n", err_print_prefix);
107 	}
108 	return MCHK_DISPOSITION_REPORT;
109 }
110 
111 /* SESF bits 0/1 identify PCI errors, bit 2 covers ECC on either Pchip/CPU. */
112 static u64
tsunami_pchip_error(struct el_TSUNAMI_sysdata_mcheck * frame,int which)113 tsunami_pchip_error(struct el_TSUNAMI_sysdata_mcheck *frame, int which)
114 {
115 	u64 perror = which ? frame->p1_perror : frame->p0_perror;
116 
117 	if (frame->sesf & (1UL << which))
118 		return perror;
119 	if ((frame->sesf & 4) && (perror & TSUNAMI_PERROR_ECCMASK))
120 		return perror;
121 	return 0;
122 }
123 
124 static struct el_TSUNAMI_sysdata_mcheck *
tsunami_system_frame(struct el_common * header)125 tsunami_system_frame(struct el_common *header)
126 {
127 	if (!tsunami_frame_valid(header, sizeof(struct el_TSUNAMI_sysdata_mcheck)))
128 		return NULL;
129 	return (void *)header + header->sys_offset;
130 }
131 
132 static int
tsunami_process_logout_frame(struct el_common * header,int print)133 tsunami_process_logout_frame(struct el_common *header, int print)
134 {
135 	struct el_TSUNAMI_sysdata_mcheck *frame = tsunami_system_frame(header);
136 	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
137 	int i;
138 
139 	if (!frame) {
140 		if (print) {
141 			printk("%s  Invalid Tsunami system frame; raw frame follows\n",
142 			       err_print_prefix);
143 			mchk_dump_logout_frame_raw(header);
144 		}
145 		return MCHK_DISPOSITION_UNKNOWN_ERROR;
146 	}
147 	if (print)
148 		printk("%s  SESF: %016llx DIR: %016llx MISC: %016llx\n",
149 		       err_print_prefix, frame->sesf, frame->dir, frame->misc);
150 	if (frame->misc & TSUNAMI_MISC_NXM) {
151 		status = MCHK_DISPOSITION_REPORT;
152 		if (print)
153 			printk("%s  Non-existent memory, NXS: %llu\n",
154 			       err_print_prefix, (frame->misc >> 29) & 7);
155 	}
156 	for (i = 0; i < 2; i++)
157 		status |= tsunami_parse_p_perror(i, tsunami_pchip_error(frame, i), print);
158 	return status;
159 }
160 
161 struct tsunami_error_state {
162 	u64 perror[2];
163 	u64 misc;
164 };
165 
166 static void
tsunami_ack_pchip(tsunami_pchip * pchip,u64 perror)167 tsunami_ack_pchip(tsunami_pchip *pchip, u64 perror)
168 {
169 	if (!(perror & TSUNAMI_PERROR_ERRMASK))
170 		return;
171 	pchip->perror.csr = perror & TSUNAMI_PERROR_ERRMASK;
172 	/* Complete the W1C write before releasing the logout frame. */
173 	mb();
174 	pchip->perror.csr;
175 }
176 
177 static void
tsunami_clear_errors(struct tsunami_error_state * state)178 tsunami_clear_errors(struct tsunami_error_state *state)
179 {
180 	bool pchip1 = TSUNAMI_cchip->csc.csr & (1UL << 14);
181 
182 	/* Preserve each chip's transaction and the NXM source before clearing. */
183 	state->perror[0] = TSUNAMI_pchip0->perror.csr;
184 	state->perror[1] = pchip1 ? TSUNAMI_pchip1->perror.csr : 0;
185 	state->misc = TSUNAMI_cchip->misc.csr;
186 
187 	/*
188 	 * Acknowledge both present Pchips: the saved frame may predate
189 	 * live errors. This can consume another chip's pending error
190 	 * with INV set before it reaches DRIR, losing its transaction
191 	 * details and subsequent system-error notification.
192 	 */
193 	tsunami_ack_pchip(TSUNAMI_pchip0, state->perror[0]);
194 	/* Do not access the second Pchip on single-Pchip systems. */
195 	if (pchip1)
196 		tsunami_ack_pchip(TSUNAMI_pchip1, state->perror[1]);
197 	if (state->misc & TSUNAMI_MISC_NXM) {
198 		/* Zero writes leave the other MISC fields unchanged. */
199 		TSUNAMI_cchip->misc.csr = TSUNAMI_MISC_NXM;
200 		/* Complete the NXM acknowledgment before releasing the frame. */
201 		mb();
202 		TSUNAMI_cchip->misc.csr;
203 	}
204 }
205 
206 static void
tsunami_report_live_errors(struct tsunami_error_state * state,struct el_TSUNAMI_sysdata_mcheck * frame)207 tsunami_report_live_errors(struct tsunami_error_state *state,
208 			  struct el_TSUNAMI_sysdata_mcheck *frame)
209 {
210 	int i;
211 
212 	/* PALcode's frame may predate these errors, or describe another chip. */
213 	for (i = 0; i < 2; i++) {
214 		if (!(state->perror[i] & TSUNAMI_PERROR_ERRMASK) ||
215 		    (frame && state->perror[i] == tsunami_pchip_error(frame, i)))
216 			continue;
217 		printk("%s  Live Pchip status before acknowledgment:\n", err_print_prefix);
218 		tsunami_parse_p_perror(i, state->perror[i], 1);
219 	}
220 	if ((state->misc & TSUNAMI_MISC_NXM) &&
221 	    (!frame || ((state->misc ^ frame->misc) & (0xfUL << 28))))
222 		printk("%s  Live MISC: %016llx, non-existent memory, NXS: %llu\n",
223 		       err_print_prefix, state->misc, (state->misc >> 29) & 7);
224 }
225 
226 void
tsunami_machine_check(unsigned long vector,unsigned long la_ptr)227 tsunami_machine_check(unsigned long vector, unsigned long la_ptr)
228 {
229 	struct el_common *header = (void *)la_ptr;
230 	struct el_TSUNAMI_sysdata_mcheck *frame = NULL;
231 	struct tsunami_error_state live = {};
232 	char *saved_err_prefix = err_print_prefix;
233 	bool show_regs = vector == SCB_Q_SYSMCHK;
234 
235 	/* Synchronize pending accesses before inspecting the chipset. */
236 	mb();
237 	mb();
238 	draina();
239 	/* CPU/event vectors must not consume a pending Pchip system error. */
240 	if (vector == SCB_Q_SYSMCHK || vector == SCB_Q_SYSERR) {
241 		tsunami_clear_errors(&live);
242 		frame = tsunami_system_frame(header);
243 	}
244 
245 #ifdef CONFIG_VERBOSE_MCHECK
246 	show_regs |= alpha_verbose_mcheck != 0;
247 #endif
248 	err_print_prefix = KERN_CRIT;
249 	if (vector == SCB_Q_SYSMCHK || vector == SCB_Q_SYSERR) {
250 		printk("%sSystem %s error (vector %lx, code %x) on CPU %d:\n",
251 		       err_print_prefix, vector == SCB_Q_SYSERR ? "correctable" :
252 		       "uncorrectable", vector, header->code, smp_processor_id());
253 		tsunami_process_logout_frame(header, 1);
254 		if (show_regs)
255 			dik_show_regs(get_irq_regs(), NULL);
256 		tsunami_report_live_errors(&live, frame);
257 	} else if (vector == SCB_Q_SYSEVENT) {
258 		printk("%sTsunami environmental event (code %x): layout unknown\n",
259 		       err_print_prefix, header->code);
260 		mchk_dump_logout_frame_raw(header);
261 	}
262 	err_print_prefix = saved_err_prefix;
263 
264 	if (vector != SCB_Q_SYSMCHK && vector != SCB_Q_SYSERR &&
265 	    vector != SCB_Q_SYSEVENT) {
266 		/* EV6 decoding also releases the logout frame. */
267 		ev6_machine_check(vector, la_ptr);
268 	} else {
269 		wrmces(0x7);
270 		/* Complete acknowledgment before resuming. */
271 		mb();
272 	}
273 }
274 
275 static const char * const CLIPPER_EnvQW1SMIR[] = {
276 	"", /* SMIR<0>: retain as raw context until its semantics are known. */
277 	"OCP or RMC halt detected",
278 	"Sys_DC_Notok failure detected",
279 	"",
280 	"System temperature over 50 degrees C failure",
281 	"PCI Bus #0 is in reset",
282 	"PCI Bus #1 is in reset",
283 	"System is being reset"
284 };
285 
286 static const char * const CLIPPER_EnvQW2CPUIR[] = {
287 	"CPU0 regulator is enabled",
288 	"CPU1 regulator is enabled",
289 	"CPU2 regulator is enabled",
290 	"CPU3 regulator is enabled",
291 	"CPU0 regulator or configuration sequence fail",
292 	"CPU1 regulator or configuration sequence fail",
293 	"CPU2 regulator or configuration sequence fail",
294 	"CPU3 regulator or configuration sequence fail"
295 };
296 
297 static const char * const CLIPPER_EnvQW3PSIR[] = {
298 	"Power Supply 0 is enabled",
299 	"Power Supply 1 is enabled",
300 	"Power Supply 2 is enabled",
301 	"",
302 	"Power Supply 0 was enabled but failed",
303 	"Power Supply 1 was enabled but failed",
304 	"Power Supply 2 was enabled but failed"
305 };
306 
307 static const char * const CLIPPER_EnvQW4LM78ISR[] = {
308 	"PS +3.3V out of tolerance",
309 	"PS +5V out of tolerance",
310 	"PS +12V out of tolerance",
311 	"VTERM out of tolerance",
312 	"Temperature zone 0 (PCI Backplane slots 1-3 area) over limit failure",
313 	"LM75 CPU0-3 Temperature over limit failure",
314 	"System Fan 1 failure",
315 	"System Fan 2 failure",
316 	"CTERM out of tolerance",
317 	"",
318 	"-12V out of tolerance",
319 	"",
320 	"",
321 	"",
322 	"",
323 	"",
324 	"CPU0_VCORE +2V out of tolerance",
325 	"CPU0_VIO +1.5V out of tolerance",
326 	"CPU1_VCORE +2V out of tolerance",
327 	"CPU1_VIO +1.5V out of tolerance",
328 	"Temperature zone 1 (PCI Backplane slots 7-10 area) over limit failure",
329 	"",
330 	"System Fan 4 failure",
331 	"System Fan 5 failure",
332 	"",
333 	"",
334 	"",
335 	"",
336 	"",
337 	"",
338 	"",
339 	"",
340 	"CPU2_VCORE +2V out of tolerance",
341 	"CPU2_VIO +1.5V out of tolerance",
342 	"CPU3_VCORE +2V out of tolerance",
343 	"CPU3_VIO +1.5V out of tolerance",
344 	"Temperature zone 2 (PCI Backplane slots 4-6 area) over limit failure",
345 	"",
346 	"System Fan 3 failure",
347 	"System Fan 6 failure",
348 	"",
349 	"",
350 	"Power supply 3.3V rail above high amperage warning",
351 	"Power supply 5.0V rail above high amperage warning",
352 	"Power supply 12V rail above high amperage warning",
353 	"Power supply high temperature warning",
354 	"Power supply AC input low limit warning",
355 	"Power supply AC input high limit warning"
356 };
357 
358 static const char * const CLIPPER_EnvQW5DOOR[] = {
359 	"",
360 	"System CPU door is open",
361 	"System Fan door is open",
362 	"System PCI door is open",
363 	"",
364 	"System CPU door is closed",
365 	"System Fan door is closed",
366 	"System PCI door is closed"
367 };
368 
369 static const char * const CLIPPER_EnvQW6TEMP[] = {
370 	"CPU0 temperature warning fault has occurred",
371 	"CPU1 temperature warning fault has occurred",
372 	"CPU2 temperature warning fault has occurred",
373 	"CPU3 temperature warning fault has occurred",
374 	"System temperature zone 0 warning fault has occurred",
375 	"System temperature zone 1 warning fault has occurred",
376 	"System temperature zone 2 warning fault has occurred"
377 };
378 
379 static const char * const CLIPPER_EnvQW7FAN[] = {
380 	"System Fan 1 is not responding to RMC Commands",
381 	"System Fan 2 is not responding to RMC Commands",
382 	"System Fan 3 is not responding to RMC Commands",
383 	"System Fan 4 is not responding to RMC Commands",
384 	"System Fan 5 is not responding to RMC Commands",
385 	"System Fan 6 is not responding to RMC Commands",
386 	"",
387 	"",
388 	"CPU fans 5/6 at maximum speed",
389 	"CPU fans 5/6 reduced speed from maximum",
390 	"PCI fans 1-4 at maximum speed",
391 	"PCI fans 1-4 reduced speed from maximum"
392 };
393 
394 #define CLIPPER_ENV_LM78ISR_MASK	0xfcdf00df05ffUL
395 
396 /* ES40 Service Guide EK-ES240-SV A01, live frame: Tables D-20 and D-21. */
397 struct el_clipper_envdata {
398 	u64 summary;
399 	u64 dir;
400 	u64 smir;
401 	u64 cpuir;
402 	u64 psir;
403 	u64 fault;
404 	u64 doors;
405 	u64 temp_warn;
406 	u64 fan_ctrl;
407 	u64 fatal_power_down;
408 	u64 reserved;
409 };
410 
411 static bool
clipper_print_bits(const char * const * messages,size_t count,u64 value,u64 mask)412 clipper_print_bits(const char * const *messages, size_t count,
413 		   u64 value, u64 mask)
414 {
415 	size_t i;
416 
417 	if (!(value & mask))
418 		return false;
419 	for (i = 0; i < count; i++)
420 		if (value & mask & (1UL << i))
421 			printk("%s    %s\n", err_print_prefix, messages[i]);
422 	return true;
423 }
424 
425 #define CLIPPER_BITS(table, value, mask) \
426 	clipper_print_bits(table, ARRAY_SIZE(table), value, mask)
427 
428 static void
clipper_process_environment(struct el_common * header)429 clipper_process_environment(struct el_common *header)
430 {
431 	struct el_clipper_envdata *frame;
432 	bool fault = false;
433 
434 	if (!tsunami_frame_valid(header, sizeof(*frame))) {
435 		printk("%s  Truncated Clipper environmental frame\n", err_print_prefix);
436 		mchk_dump_logout_frame_raw(header);
437 		return;
438 	}
439 	frame = (void *)header + header->sys_offset;
440 	/* Only QW1 through QW7 carry error state in the live 680 frame. */
441 	/* PSU summary and inverted halt/reset signals remain raw context. */
442 	fault |= CLIPPER_BITS(CLIPPER_EnvQW1SMIR, frame->smir, 0x14);
443 	fault |= CLIPPER_BITS(CLIPPER_EnvQW2CPUIR, frame->cpuir, 0xf0);
444 	fault |= CLIPPER_BITS(CLIPPER_EnvQW3PSIR, frame->psir, 0x70);
445 	fault |= CLIPPER_BITS(CLIPPER_EnvQW4LM78ISR,
446 			       frame->fault, CLIPPER_ENV_LM78ISR_MASK);
447 	fault |= CLIPPER_BITS(CLIPPER_EnvQW5DOOR, frame->doors, 0x0e);
448 	fault |= CLIPPER_BITS(CLIPPER_EnvQW6TEMP, frame->temp_warn, 0x7f);
449 	fault |= CLIPPER_BITS(CLIPPER_EnvQW7FAN, frame->fan_ctrl, 0x3f);
450 	/* A notification with no recognized fault can describe recovery. */
451 	if (!fault)
452 		printk("%s    No recognized environmental fault bits set\n",
453 		       err_print_prefix);
454 	printk("%s  Environmental summary: %016llx DIR: %016llx\n",
455 	       err_print_prefix, frame->summary, frame->dir);
456 	printk("%s  SMIR: %016llx (PSU summary/halt/reset bits undecoded)\n",
457 	       err_print_prefix, frame->smir);
458 	CLIPPER_BITS(CLIPPER_EnvQW2CPUIR, frame->cpuir, 0x0f);
459 	CLIPPER_BITS(CLIPPER_EnvQW3PSIR, frame->psir, 0x07);
460 	CLIPPER_BITS(CLIPPER_EnvQW5DOOR, frame->doors, 0xe0);
461 	CLIPPER_BITS(CLIPPER_EnvQW7FAN, frame->fan_ctrl, 0xf00);
462 	if (frame->fault & (0x3fUL << 42))
463 		printk("%s  Power supply warning source: %llu (3 = reserved)\n",
464 		       err_print_prefix, (frame->fault >> 40) & 3);
465 }
466 
467 void
clipper_machine_check(unsigned long vector,unsigned long la_ptr)468 clipper_machine_check(unsigned long vector, unsigned long la_ptr)
469 {
470 	struct el_common *header = (void *)la_ptr;
471 	char *saved_err_prefix = err_print_prefix;
472 
473 	if (vector != SCB_Q_SYSEVENT) {
474 		tsunami_machine_check(vector, la_ptr);
475 		return;
476 	}
477 	/* Drain pending accesses before inspecting the environmental frame. */
478 	mb();
479 	draina();
480 	err_print_prefix = KERN_CRIT;
481 	printk("%sSystem correctable environmental event (code %x) on CPU %d:\n",
482 	       err_print_prefix, header->code, smp_processor_id());
483 	if (header->code == 0x206)
484 		clipper_process_environment(header);
485 	else {
486 		printk("%s  Unrecognized environmental event; raw frame follows\n",
487 		       err_print_prefix);
488 		mchk_dump_logout_frame_raw(header);
489 	}
490 	err_print_prefix = saved_err_prefix;
491 	wrmces(0x7);
492 	/* Complete acknowledgment before returning from the event. */
493 	mb();
494 }
495 
496 static struct el_subpacket * __init
tsunami_process_subpacket(struct el_subpacket * packet)497 tsunami_process_subpacket(struct el_subpacket *packet)
498 {
499 	struct el_common *frame;
500 	size_t offset = offsetof(struct el_subpacket, by_type.regatta_frame.data_start);
501 	int status;
502 
503 	/* Raw dumps consume whole quadwords, and the next packet must advance. */
504 	if (packet->length < offsetof(struct el_subpacket, by_type) ||
505 	    (packet->length & 7))
506 		return NULL;
507 	if (packet->revision != 1) {
508 		el_annotate_subpacket(packet);
509 		return (void *)packet + packet->length;
510 	}
511 
512 	switch (packet->type) {
513 	case EL_TYPE__REGATTA__PROCESSOR_ERROR_FRAME:
514 	case EL_TYPE__REGATTA__PROCESSOR_DBL_ERROR_HALT:
515 	case EL_TYPE__REGATTA__SYSTEM_ERROR_FRAME:
516 	case EL_TYPE__REGATTA__SYSTEM_DBL_ERROR_HALT:
517 		if (packet->length < offset + sizeof(*frame))
518 			return NULL;
519 		frame = (void *)packet + offset;
520 		if (frame->size > packet->length - offset || frame->size < sizeof(*frame))
521 			return NULL;
522 		if (packet->type == EL_TYPE__REGATTA__PROCESSOR_ERROR_FRAME ||
523 		    packet->type == EL_TYPE__REGATTA__PROCESSOR_DBL_ERROR_HALT) {
524 			printk("%s  ** Occurred on CPU %d:\n", err_print_prefix,
525 			       (int)packet->by_type.regatta_frame.cpuid);
526 			status = ev6_process_logout_frame(frame, 0);
527 			if (status != MCHK_DISPOSITION_DISMISS)
528 				ev6_process_logout_frame(frame, 1);
529 		} else {
530 			tsunami_process_logout_frame(frame, 1);
531 		}
532 		break;
533 	case EL_TYPE__REGATTA__ENVIRONMENTAL_FRAME:
534 		/*
535 		 * ES40 Table D-18 gives sys_offset=0x20, but places the
536 		 * summary at frame+0x18. Preserve the complete packet until
537 		 * the console layout is verified; do not apply the live layout.
538 		 */
539 		printk("%s  Console environmental layout unverified; raw packet follows\n",
540 		       err_print_prefix);
541 		el_annotate_subpacket(packet);
542 		break;
543 	default:
544 		el_annotate_subpacket(packet);
545 		break;
546 	}
547 	return (void *)packet + packet->length;
548 }
549 
550 /*
551  * Clipper console logs have an HWRPB byte count. Do not use the generic
552  * unbounded dispatcher: a rejected record must not acknowledge the log.
553  */
554 static bool __init
tsunami_console_log(void * data,size_t remaining)555 tsunami_console_log(void *data, size_t remaining)
556 {
557 	struct el_subpacket *packet;
558 	unsigned char *pos = data;
559 	size_t size, length;
560 	u32 count;
561 	union el_timestamp timestamp;
562 	const char *name;
563 
564 	while (remaining >= offsetof(struct el_subpacket, by_type)) {
565 		packet = (void *)pos;
566 		size = packet->length;
567 		if (size < offsetof(struct el_subpacket, by_type) ||
568 		    size > remaining || (size & 7))
569 			return false;
570 		if (packet->class == EL_CLASS__TERMINATION)
571 			return packet->type == EL_TYPE__TERMINATION__TERMINATION;
572 		if (packet->class != EL_CLASS__HEADER || packet->revision != 1)
573 			return false;
574 
575 		timestamp.as_int = 0;
576 		/* Check each header's extent before accessing its union member. */
577 #define CONSOLE_HEADER_SIZE(member) \
578 	(offsetof(struct el_subpacket, by_type.member) + \
579 	 sizeof(packet->by_type.member))
580 		switch (packet->type) {
581 		case EL_TYPE__HEADER__SYSTEM_ERROR_FRAME:
582 			if (size < CONSOLE_HEADER_SIZE(sys_err))
583 				return false;
584 			name = "SYSTEM ERROR";
585 			length = packet->by_type.sys_err.frame_length;
586 			count = packet->by_type.sys_err.frame_packet_count;
587 			break;
588 		case EL_TYPE__HEADER__SYSTEM_EVENT_FRAME:
589 			if (size < CONSOLE_HEADER_SIZE(sys_event))
590 				return false;
591 			name = "SYSTEM EVENT";
592 			timestamp = packet->by_type.sys_event.timestamp;
593 			length = packet->by_type.sys_event.frame_length;
594 			count = packet->by_type.sys_event.frame_packet_count;
595 			break;
596 		case EL_TYPE__HEADER__HALT_FRAME:
597 			if (size < CONSOLE_HEADER_SIZE(err_halt))
598 				return false;
599 			name = "ERROR HALT";
600 			timestamp = packet->by_type.err_halt.timestamp;
601 			length = packet->by_type.err_halt.frame_length;
602 			count = packet->by_type.err_halt.frame_packet_count;
603 			break;
604 		case EL_TYPE__HEADER__LOGOUT_FRAME:
605 			if (size < CONSOLE_HEADER_SIZE(logout_header))
606 				return false;
607 			name = "LOGOUT FRAME";
608 			length = packet->by_type.logout_header.frame_length;
609 			count = 1;
610 			break;
611 		default:
612 			return false;
613 		}
614 #undef CONSOLE_HEADER_SIZE
615 		if (length > remaining - size || (length & 7) ||
616 		    count > length / offsetof(struct el_subpacket, by_type))
617 			return false;
618 		printk("%s*** %s: CLASS %u, TYPE %u\n", err_print_prefix,
619 		       name, packet->class, packet->type);
620 		el_print_timestamp(&timestamp);
621 		if (packet->type == EL_TYPE__HEADER__HALT_FRAME)
622 			printk("%s  HALT CODE: %04x\n", err_print_prefix,
623 			       packet->by_type.err_halt.halt_code);
624 		pos += size;
625 		remaining -= size + length;
626 		while (count--) {
627 			if (length < offsetof(struct el_subpacket, by_type))
628 				return false;
629 			packet = (void *)pos;
630 			size = packet->length;
631 			if (size < offsetof(struct el_subpacket, by_type) ||
632 			    size > length || (size & 7) ||
633 			    packet->class != EL_CLASS__REGATTA_FAMILY)
634 				return false;
635 			/* This handler checks embedded logout-frame bounds. */
636 			if (tsunami_process_subpacket(packet) != (void *)pos + size)
637 				return false;
638 			pos += size;
639 			length -= size;
640 		}
641 		if (length)
642 			return false;
643 	}
644 	/* Exhaustion without a complete termination packet is incomplete. */
645 	return false;
646 }
647 
648 static void __init
tsunami_console_data_log(int cpu,struct percpu_struct * pcpu)649 tsunami_console_data_log(int cpu, struct percpu_struct *pcpu)
650 {
651 	unsigned char *data = (void *)(IDENT_ADDR | pcpu->console_data_log_pa);
652 	size_t length = pcpu->console_data_log_length;
653 	size_t dump = length < 1024 ? length : 1024;
654 
655 	printk("%sConsole data log for CPU %d (%zu bytes):\n",
656 	       err_print_prefix, cpu, length);
657 	if (!(pcpu->console_data_log_pa & 7) &&
658 	    length <= ~0UL - (unsigned long)data &&
659 	    tsunami_console_log(data, length)) {
660 		/* Acknowledge only after reaching a valid termination packet. */
661 		pcpu->console_data_log_pa = 0;
662 		return;
663 	}
664 	printk("%s  Incomplete console log; retaining firmware pointer\n",
665 	       err_print_prefix);
666 	/* Byte reads preserve partial headers without rounding beyond length. */
667 	if (dump > ~0UL - (unsigned long)data)
668 		return;
669 	print_hex_dump(err_print_prefix, "  ", DUMP_PREFIX_OFFSET, 16, 1,
670 		       data, dump, false);
671 	if (dump < length)
672 		printk("%s  Raw console log truncated to %zu bytes\n",
673 		       err_print_prefix, dump);
674 }
675 
676 void __init
tsunami_check_console_data_log(void)677 tsunami_check_console_data_log(void)
678 {
679 	struct percpu_struct *pcpu;
680 	unsigned long cpu;
681 
682 	for (cpu = 0; cpu < hwrpb->nr_processors; cpu++) {
683 		pcpu = (void *)hwrpb + hwrpb->processor_offset +
684 			cpu * hwrpb->processor_size;
685 		if (pcpu->console_data_log_pa)
686 			tsunami_console_data_log(cpu, pcpu);
687 	}
688 }
689