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(×tamp);
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