mca.c 55.8 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
/*
Linus Torvalds's avatar
Linus Torvalds committed
2 3
 * File:	mca.c
 * Purpose:	Generic MCA handling layer
Linus Torvalds's avatar
Linus Torvalds committed
4 5
 *
 * Updated for latest kernel
6 7 8
 * Copyright (C) 2002 Dell Computer Corporation
 * Copyright (C) Matt Domsch (Matt_Domsch@dell.com)
 *
David Mosberger's avatar
David Mosberger committed
9 10 11
 * Copyright (C) 2002 Intel
 * Copyright (C) Jenna Hall (jenna.s.hall@intel.com)
 *
Linus Torvalds's avatar
Linus Torvalds committed
12 13 14
 * Copyright (C) 2001 Intel
 * Copyright (C) Fred Lewis (frederick.v.lewis@intel.com)
 *
Linus Torvalds's avatar
Linus Torvalds committed
15 16
 * Copyright (C) 2000 Intel
 * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com)
Linus Torvalds's avatar
Linus Torvalds committed
17
 *
Linus Torvalds's avatar
Linus Torvalds committed
18 19 20
 * Copyright (C) 1999 Silicon Graphics, Inc.
 * Copyright (C) Vijay Chander(vijay@engr.sgi.com)
 *
21 22
 * 02/03/25 M. Domsch	GUID cleanups
 *
David Mosberger's avatar
David Mosberger committed
23 24 25 26 27
 * 02/01/04 J. Hall	Aligned MCA stack to 16 bytes, added platform vs. CPU
 *			error flag, set SAL default return values, changed
 *			error record structure to linked list, added init call
 *			to sal_get_state_info_size().
 *
Linus Torvalds's avatar
Linus Torvalds committed
28 29 30 31 32
 * 01/01/03 F. Lewis    Added setup of CMCI and CPEI IRQs, logging of corrected
 *                      platform errors, completed code for logging of
 *                      corrected & uncorrected machine check errors, and
 *                      updated for conformance with Nov. 2000 revision of the
 *                      SAL 3.0 spec.
Linus Torvalds's avatar
Linus Torvalds committed
33 34
 * 00/03/29 C. Fleckenstein  Fixed PAL/SAL update issues, began MCA bug fixes, logging issues,
 *                           added min save state dump, added INIT handler.
Linus Torvalds's avatar
Linus Torvalds committed
35 36 37 38 39
 */
#include <linux/config.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/sched.h>
Linus Torvalds's avatar
Linus Torvalds committed
40
#include <linux/interrupt.h>
Linus Torvalds's avatar
Linus Torvalds committed
41 42
#include <linux/irq.h>
#include <linux/smp_lock.h>
David Mosberger's avatar
David Mosberger committed
43
#include <linux/bootmem.h>
44
#include <linux/acpi.h>
Linus Torvalds's avatar
Linus Torvalds committed
45 46 47 48 49 50 51 52 53

#include <asm/machvec.h>
#include <asm/page.h>
#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/sal.h>
#include <asm/mca.h>

#include <asm/irq.h>
Linus Torvalds's avatar
Linus Torvalds committed
54
#include <asm/hw_irq.h>
Linus Torvalds's avatar
Linus Torvalds committed
55

Linus Torvalds's avatar
Linus Torvalds committed
56
#undef MCA_PRT_XTRA_DATA
Linus Torvalds's avatar
Linus Torvalds committed
57 58 59 60 61 62 63 64 65

typedef struct ia64_fptr {
	unsigned long fp;
	unsigned long gp;
} ia64_fptr_t;

ia64_mc_info_t			ia64_mc_info;
ia64_mca_sal_to_os_state_t	ia64_sal_to_os_handoff_state;
ia64_mca_os_to_sal_state_t	ia64_os_to_sal_handoff_state;
Linus Torvalds's avatar
Linus Torvalds committed
66
u64				ia64_mca_proc_state_dump[512];
David Mosberger's avatar
David Mosberger committed
67
u64				ia64_mca_stack[1024] __attribute__((aligned(16)));
Linus Torvalds's avatar
Linus Torvalds committed
68 69
u64				ia64_mca_stackframe[32];
u64				ia64_mca_bspstore[1024];
David Mosberger's avatar
David Mosberger committed
70 71 72 73 74
u64				ia64_init_stack[KERNEL_STACK_SIZE] __attribute__((aligned(16)));
u64				ia64_mca_sal_data_area[1356];
u64				ia64_mca_min_state_save_info;
u64				ia64_tlb_functional;
u64				ia64_os_mca_recovery_successful;
Linus Torvalds's avatar
Linus Torvalds committed
75 76 77 78

static void			ia64_mca_wakeup_ipi_wait(void);
static void			ia64_mca_wakeup(int cpu);
static void			ia64_mca_wakeup_all(void);
Linus Torvalds's avatar
Linus Torvalds committed
79
static void			ia64_log_init(int);
David Mosberger's avatar
David Mosberger committed
80 81 82
extern void			ia64_monarch_init_handler (void);
extern void			ia64_slave_init_handler (void);
extern struct hw_interrupt_type	irq_type_iosapic_level;
Linus Torvalds's avatar
Linus Torvalds committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115

static struct irqaction cmci_irqaction = {
	handler:    ia64_mca_cmc_int_handler,
	flags:      SA_INTERRUPT,
	name:       "cmc_hndlr"
};

static struct irqaction mca_rdzv_irqaction = {
	handler:    ia64_mca_rendez_int_handler,
	flags:      SA_INTERRUPT,
	name:       "mca_rdzv"
};

static struct irqaction mca_wkup_irqaction = {
	handler:    ia64_mca_wakeup_int_handler,
	flags:      SA_INTERRUPT,
	name:       "mca_wkup"
};

static struct irqaction mca_cpe_irqaction = {
	handler:    ia64_mca_cpe_int_handler,
	flags:      SA_INTERRUPT,
	name:       "cpe_hndlr"
};

/*
 *  ia64_mca_log_sal_error_record
 *
 *  This function retrieves a specified error record type from SAL, sends it to
 *  the system log, and notifies SALs to clear the record from its non-volatile
 *  memory.
 *
 *  Inputs  :   sal_info_type   (Type of error record MCA/CMC/CPE/INIT)
David Mosberger's avatar
David Mosberger committed
116
 *  Outputs :   platform error status
Linus Torvalds's avatar
Linus Torvalds committed
117
 */
David Mosberger's avatar
David Mosberger committed
118
int
Linus Torvalds's avatar
Linus Torvalds committed
119 120
ia64_mca_log_sal_error_record(int sal_info_type)
{
David Mosberger's avatar
David Mosberger committed
121 122
	int platform_err = 0;

Linus Torvalds's avatar
Linus Torvalds committed
123 124
	/* Get the MCA error record */
	if (!ia64_log_get(sal_info_type, (prfunc_t)printk))
David Mosberger's avatar
David Mosberger committed
125
		return platform_err;                 // no record retrieved
Linus Torvalds's avatar
Linus Torvalds committed
126

David Mosberger's avatar
David Mosberger committed
127 128 129 130 131
	/* TODO:
	 * 1. analyze error logs to determine recoverability
	 * 2. perform error recovery procedures, if applicable
	 * 3. set ia64_os_mca_recovery_successful flag, if applicable
	 */
Linus Torvalds's avatar
Linus Torvalds committed
132

David Mosberger's avatar
David Mosberger committed
133
	platform_err = ia64_log_print(sal_info_type, (prfunc_t)printk);
Linus Torvalds's avatar
Linus Torvalds committed
134
	ia64_sal_clear_state_info(sal_info_type);
David Mosberger's avatar
David Mosberger committed
135 136

	return platform_err;
Linus Torvalds's avatar
Linus Torvalds committed
137
}
Linus Torvalds's avatar
Linus Torvalds committed
138 139

/*
David Mosberger's avatar
David Mosberger committed
140
 * platform dependent error handling
Linus Torvalds's avatar
Linus Torvalds committed
141 142 143 144 145 146 147 148 149
 */
#ifndef PLATFORM_MCA_HANDLERS
void
mca_handler_platform (void)
{

}

void
Linus Torvalds's avatar
Linus Torvalds committed
150
ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs)
Linus Torvalds's avatar
Linus Torvalds committed
151
{
Linus Torvalds's avatar
Linus Torvalds committed
152
	IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. vector = %#x\n", cpe_irq);
Linus Torvalds's avatar
Linus Torvalds committed
153

Linus Torvalds's avatar
Linus Torvalds committed
154 155
	/* Get the CMC error record and log it */
	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE);
Linus Torvalds's avatar
Linus Torvalds committed
156
}
Linus Torvalds's avatar
Linus Torvalds committed
157

Linus Torvalds's avatar
Linus Torvalds committed
158 159 160 161 162 163 164
/*
 * This routine will be used to deal with platform specific handling
 * of the init, i.e. drop into the kernel debugger on server machine,
 * or if the processor is part of some parallel machine without a
 * console, then we would call the appropriate debug hooks here.
 */
void
Linus Torvalds's avatar
Linus Torvalds committed
165
init_handler_platform (struct pt_regs *regs)
Linus Torvalds's avatar
Linus Torvalds committed
166 167
{
	/* if a kernel debugger is available call it here else just dump the registers */
Linus Torvalds's avatar
Linus Torvalds committed
168

Linus Torvalds's avatar
Linus Torvalds committed
169
	show_regs(regs);		/* dump the state info */
Linus Torvalds's avatar
Linus Torvalds committed
170
	while (1);			/* hang city if no debugger */
Linus Torvalds's avatar
Linus Torvalds committed
171 172
}

Linus Torvalds's avatar
Linus Torvalds committed
173 174 175 176 177 178 179 180 181 182 183
/*
 * ia64_mca_init_platform
 *
 *  External entry for platform specific MCA initialization.
 *
 *  Inputs
 *      None
 *
 *  Outputs
 *      None
 */
Linus Torvalds's avatar
Linus Torvalds committed
184
void
Linus Torvalds's avatar
Linus Torvalds committed
185
ia64_mca_init_platform (void)
Linus Torvalds's avatar
Linus Torvalds committed
186
{
Linus Torvalds's avatar
Linus Torvalds committed
187

Linus Torvalds's avatar
Linus Torvalds committed
188
}
Linus Torvalds's avatar
Linus Torvalds committed
189

Linus Torvalds's avatar
Linus Torvalds committed
190 191 192 193 194 195 196 197 198 199 200 201
/*
 *  ia64_mca_check_errors
 *
 *  External entry to check for error records which may have been posted by SAL
 *  for a prior failure which resulted in a machine shutdown before an the
 *  error could be logged.  This function must be called after the filesystem
 *  is initialized.
 *
 *  Inputs  :   None
 *
 *  Outputs :   None
 */
Linus Torvalds's avatar
Linus Torvalds committed
202
void
Linus Torvalds's avatar
Linus Torvalds committed
203
ia64_mca_check_errors (void)
Linus Torvalds's avatar
Linus Torvalds committed
204
{
Linus Torvalds's avatar
Linus Torvalds committed
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
	/*
	 *  If there is an MCA error record pending, get it and log it.
	 */
	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
}

/*
 * ia64_mca_register_cpev
 *
 *  Register the corrected platform error vector with SAL.
 *
 *  Inputs
 *      cpev        Corrected Platform Error Vector number
 *
 *  Outputs
 *      None
 */
static void
ia64_mca_register_cpev (int cpev)
{
	/* Register the CPE interrupt vector with SAL */
	if (ia64_sal_mc_set_params(SAL_MC_PARAM_CPE_INT, SAL_MC_PARAM_MECHANISM_INT, cpev, 0, 0)) {
		printk("ia64_mca_platform_init: failed to register Corrected "
		       "Platform Error interrupt vector with SAL.\n");
		return;
	}

	IA64_MCA_DEBUG("ia64_mca_platform_init: corrected platform error "
		       "vector %#x setup and enabled\n", cpev);
Linus Torvalds's avatar
Linus Torvalds committed
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
}

#endif /* PLATFORM_MCA_HANDLERS */

static char *min_state_labels[] = {
	"nat",
	"r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8",
	"r9", "r10","r11", "r12","r13","r14", "r15",
	"b0r16","b0r17", "b0r18", "b0r19", "b0r20",
	"b0r21", "b0r22","b0r23", "b0r24", "b0r25",
	"b0r26", "b0r27", "b0r28","b0r29", "b0r30", "b0r31",
	"r16", "r17", "r18","r19", "r20", "r21","r22",
	"r23", "r24","r25", "r26", "r27","r28", "r29", "r30","r31",
	"preds", "br0", "rsc",
	"iip", "ipsr", "ifs",
	"xip", "xpsr", "xfs"
};

int ia64_pmss_dump_bank0=0;  /* dump bank 0 ? */

/*
 * routine to process and prepare to dump min_state_save
 * information for debugging purposes.
 *
 */
void
ia64_process_min_state_save (pal_min_state_area_t *pmss, struct pt_regs *ptregs)
{
	int i, max=57;
	u64 *tpmss_ptr=(u64 *)pmss;

	/* dump out the min_state_area information */

	for (i=0;i<max;i++) {

		if(!ia64_pmss_dump_bank0) {
			if(strncmp("B0",min_state_labels[i],2)==0) {
				tpmss_ptr++;  /* skip to next entry */
				continue;
			}
Linus Torvalds's avatar
Linus Torvalds committed
274
		}
Linus Torvalds's avatar
Linus Torvalds committed
275 276 277 278 279 280 281 282

		printk("%5s=0x%16.16lx ",min_state_labels[i],*tpmss_ptr++);

		if (((i+1)%3)==0 || ((!strcmp("GR16",min_state_labels[i]))
				     && !ia64_pmss_dump_bank0))
			printk("\n");
	}
}
Linus Torvalds's avatar
Linus Torvalds committed
283

Linus Torvalds's avatar
Linus Torvalds committed
284 285
/*
 * ia64_mca_cmc_vector_setup
Linus Torvalds's avatar
Linus Torvalds committed
286 287 288 289
 *
 *  Setup the corrected machine check vector register in the processor and
 *  unmask interrupt.  This function is invoked on a per-processor basis.
 *
Linus Torvalds's avatar
Linus Torvalds committed
290
 * Inputs
Linus Torvalds's avatar
Linus Torvalds committed
291
 *      None
Linus Torvalds's avatar
Linus Torvalds committed
292 293 294 295
 *
 * Outputs
 *	None
 */
Linus Torvalds's avatar
Linus Torvalds committed
296 297
void
ia64_mca_cmc_vector_setup (void)
Linus Torvalds's avatar
Linus Torvalds committed
298 299 300
{
	cmcv_reg_t	cmcv;

Linus Torvalds's avatar
Linus Torvalds committed
301
	cmcv.cmcv_regval	= 0;
David Mosberger's avatar
David Mosberger committed
302 303
	cmcv.cmcv_mask		= 0;        /* Unmask/enable interrupt */
	cmcv.cmcv_vector	= IA64_CMC_VECTOR;
Linus Torvalds's avatar
Linus Torvalds committed
304
	ia64_set_cmcv(cmcv.cmcv_regval);
Linus Torvalds's avatar
Linus Torvalds committed
305 306 307 308 309 310 311

	IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d corrected "
		       "machine check vector %#x setup and enabled.\n",
		       smp_processor_id(), IA64_CMC_VECTOR);

	IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d CMCV = %#016lx\n",
		       smp_processor_id(), ia64_get_cmcv());
Linus Torvalds's avatar
Linus Torvalds committed
312 313 314 315 316 317 318 319 320 321
}


#if defined(MCA_TEST)

sal_log_processor_info_t	slpi_buf;

void
mca_test(void)
{
Linus Torvalds's avatar
Linus Torvalds committed
322 323 324 325 326 327 328 329 330 331
	slpi_buf.valid.psi_static_struct = 1;
	slpi_buf.valid.num_cache_check = 1;
	slpi_buf.valid.num_tlb_check = 1;
	slpi_buf.valid.num_bus_check = 1;
	slpi_buf.valid.processor_static_info.minstate = 1;
	slpi_buf.valid.processor_static_info.br = 1;
	slpi_buf.valid.processor_static_info.cr = 1;
	slpi_buf.valid.processor_static_info.ar = 1;
	slpi_buf.valid.processor_static_info.rr = 1;
	slpi_buf.valid.processor_static_info.fr = 1;
Linus Torvalds's avatar
Linus Torvalds committed
332 333 334 335 336 337

	ia64_os_mca_dispatch();
}

#endif /* #if defined(MCA_TEST) */

Linus Torvalds's avatar
Linus Torvalds committed
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355

/*
 *  verify_guid
 *
 *  Compares a test guid to a target guid and returns result.
 *
 *  Inputs
 *      test_guid *     (ptr to guid to be verified)
 *      target_guid *   (ptr to standard guid to be verified against)
 *
 *  Outputs
 *      0               (test verifies against target)
 *      non-zero        (test guid does not verify)
 */
static int
verify_guid (efi_guid_t *test, efi_guid_t *target)
{
	int     rc;
356
#ifdef IA64_MCA_DEBUG_INFO
357
	char out[40];
358
#endif
Linus Torvalds's avatar
Linus Torvalds committed
359

360 361 362 363
	if ((rc = efi_guidcmp(*test, *target))) {
		IA64_MCA_DEBUG(KERN_DEBUG
			       "verify_guid: invalid GUID = %s\n",
			       efi_guid_unparse(test, out));
Linus Torvalds's avatar
Linus Torvalds committed
364 365 366 367
	}
	return rc;
}

Linus Torvalds's avatar
Linus Torvalds committed
368 369
/*
 * ia64_mca_init
Linus Torvalds's avatar
Linus Torvalds committed
370 371
 *
 *  Do all the system level mca specific initialization.
Linus Torvalds's avatar
Linus Torvalds committed
372 373 374 375 376 377 378
 *
 *	1. Register spinloop and wakeup request interrupt vectors
 *
 *	2. Register OS_MCA handler entry point
 *
 *	3. Register OS_INIT handler entry point
 *
Linus Torvalds's avatar
Linus Torvalds committed
379
 *  4. Initialize MCA/CMC/INIT related log buffers maintained by the OS.
Linus Torvalds's avatar
Linus Torvalds committed
380
 *
Linus Torvalds's avatar
Linus Torvalds committed
381 382
 *  Note that this initialization is done very early before some kernel
 *  services are available.
Linus Torvalds's avatar
Linus Torvalds committed
383
 *
Linus Torvalds's avatar
Linus Torvalds committed
384 385 386
 *  Inputs  :   None
 *
 *  Outputs :   None
Linus Torvalds's avatar
Linus Torvalds committed
387 388 389 390 391 392
 */
void __init
ia64_mca_init(void)
{
	ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler;
	ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler;
Linus Torvalds's avatar
Linus Torvalds committed
393
	ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch;
Linus Torvalds's avatar
Linus Torvalds committed
394
	int i;
Linus Torvalds's avatar
Linus Torvalds committed
395
	s64 rc;
Linus Torvalds's avatar
Linus Torvalds committed
396

Linus Torvalds's avatar
Linus Torvalds committed
397
	IA64_MCA_DEBUG("ia64_mca_init: begin\n");
Linus Torvalds's avatar
Linus Torvalds committed
398

David Mosberger's avatar
David Mosberger committed
399 400 401
	/* initialize recovery success indicator */
	ia64_os_mca_recovery_successful = 0;

Linus Torvalds's avatar
Linus Torvalds committed
402
	/* Clear the Rendez checkin flag for all cpus */
Linus Torvalds's avatar
Linus Torvalds committed
403
	for(i = 0 ; i < NR_CPUS; i++)
Linus Torvalds's avatar
Linus Torvalds committed
404 405
		ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;

Linus Torvalds's avatar
Linus Torvalds committed
406
	/*
Linus Torvalds's avatar
Linus Torvalds committed
407 408 409 410
	 * Register the rendezvous spinloop and wakeup mechanism with SAL
	 */

	/* Register the rendezvous interrupt vector with SAL */
Linus Torvalds's avatar
Linus Torvalds committed
411 412 413 414 415 416 417 418
	if ((rc = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT,
					 SAL_MC_PARAM_MECHANISM_INT,
					 IA64_MCA_RENDEZ_VECTOR,
					 IA64_MCA_RENDEZ_TIMEOUT,
					 0)))
	{
		printk("ia64_mca_init: Failed to register rendezvous interrupt "
		       "with SAL.  rc = %ld\n", rc);
Linus Torvalds's avatar
Linus Torvalds committed
419
		return;
Linus Torvalds's avatar
Linus Torvalds committed
420
	}
Linus Torvalds's avatar
Linus Torvalds committed
421 422

	/* Register the wakeup interrupt vector with SAL */
Linus Torvalds's avatar
Linus Torvalds committed
423 424 425 426 427 428 429
	if ((rc = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP,
					 SAL_MC_PARAM_MECHANISM_INT,
					 IA64_MCA_WAKEUP_VECTOR,
					 0, 0)))
	{
		printk("ia64_mca_init: Failed to register wakeup interrupt with SAL.  rc = %ld\n",
		       rc);
Linus Torvalds's avatar
Linus Torvalds committed
430
		return;
Linus Torvalds's avatar
Linus Torvalds committed
431
	}
Linus Torvalds's avatar
Linus Torvalds committed
432

Linus Torvalds's avatar
Linus Torvalds committed
433
	IA64_MCA_DEBUG("ia64_mca_init: registered mca rendezvous spinloop and wakeup mech.\n");
Linus Torvalds's avatar
Linus Torvalds committed
434

Linus Torvalds's avatar
Linus Torvalds committed
435
	ia64_mc_info.imi_mca_handler        = __pa(mca_hldlr_ptr->fp);
Linus Torvalds's avatar
Linus Torvalds committed
436 437 438 439
	/*
	 * XXX - disable SAL checksum by setting size to 0; should be
	 *	__pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch);
	 */
Linus Torvalds's avatar
Linus Torvalds committed
440
	ia64_mc_info.imi_mca_handler_size	= 0;
Linus Torvalds's avatar
Linus Torvalds committed
441

Linus Torvalds's avatar
Linus Torvalds committed
442 443 444 445 446 447 448 449 450
	/* Register the os mca handler with SAL */
	if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA,
				       ia64_mc_info.imi_mca_handler,
				       mca_hldlr_ptr->gp,
				       ia64_mc_info.imi_mca_handler_size,
				       0, 0, 0)))
	{
		printk("ia64_mca_init: Failed to register os mca handler with SAL.  rc = %ld\n",
		       rc);
Linus Torvalds's avatar
Linus Torvalds committed
451
		return;
Linus Torvalds's avatar
Linus Torvalds committed
452
	}
Linus Torvalds's avatar
Linus Torvalds committed
453

Linus Torvalds's avatar
Linus Torvalds committed
454 455
	IA64_MCA_DEBUG("ia64_mca_init: registered os mca handler with SAL at 0x%lx, gp = 0x%lx\n",
		       ia64_mc_info.imi_mca_handler, mca_hldlr_ptr->gp);
Linus Torvalds's avatar
Linus Torvalds committed
456

Linus Torvalds's avatar
Linus Torvalds committed
457
	/*
Linus Torvalds's avatar
Linus Torvalds committed
458
	 * XXX - disable SAL checksum by setting size to 0, should be
Linus Torvalds's avatar
Linus Torvalds committed
459
	 * IA64_INIT_HANDLER_SIZE
Linus Torvalds's avatar
Linus Torvalds committed
460
	 */
Linus Torvalds's avatar
Linus Torvalds committed
461
	ia64_mc_info.imi_monarch_init_handler		= __pa(mon_init_ptr->fp);
Linus Torvalds's avatar
Linus Torvalds committed
462
	ia64_mc_info.imi_monarch_init_handler_size	= 0;
Linus Torvalds's avatar
Linus Torvalds committed
463
	ia64_mc_info.imi_slave_init_handler		= __pa(slave_init_ptr->fp);
Linus Torvalds's avatar
Linus Torvalds committed
464 465
	ia64_mc_info.imi_slave_init_handler_size	= 0;

Linus Torvalds's avatar
Linus Torvalds committed
466 467
	IA64_MCA_DEBUG("ia64_mca_init: os init handler at %lx\n",
		       ia64_mc_info.imi_monarch_init_handler);
Linus Torvalds's avatar
Linus Torvalds committed
468 469

	/* Register the os init handler with SAL */
Linus Torvalds's avatar
Linus Torvalds committed
470 471 472 473 474 475 476 477 478 479
	if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT,
				       ia64_mc_info.imi_monarch_init_handler,
				       __pa(ia64_get_gp()),
				       ia64_mc_info.imi_monarch_init_handler_size,
				       ia64_mc_info.imi_slave_init_handler,
				       __pa(ia64_get_gp()),
				       ia64_mc_info.imi_slave_init_handler_size)))
	{
		printk("ia64_mca_init: Failed to register m/s init handlers with SAL. rc = %ld\n",
		       rc);
Linus Torvalds's avatar
Linus Torvalds committed
480
		return;
Linus Torvalds's avatar
Linus Torvalds committed
481
	}
Linus Torvalds's avatar
Linus Torvalds committed
482

Linus Torvalds's avatar
Linus Torvalds committed
483 484 485 486
	IA64_MCA_DEBUG("ia64_mca_init: registered os init handler with SAL\n");

	/*
	 *  Configure the CMCI vector and handler. Interrupts for CMC are
David Mosberger's avatar
David Mosberger committed
487
	 *  per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c).
Linus Torvalds's avatar
Linus Torvalds committed
488 489 490 491 492 493 494 495 496 497 498 499 500 501
	 */
	register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction);
	ia64_mca_cmc_vector_setup();       /* Setup vector on BSP & enable */

	/* Setup the MCA rendezvous interrupt vector */
	register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction);

	/* Setup the MCA wakeup interrupt vector */
	register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction);

	/* Setup the CPE interrupt vector */
	{
		irq_desc_t *desc;
		unsigned int irq;
502
		int cpev = acpi_request_vector(ACPI_INTERRUPT_CPEI);
Linus Torvalds's avatar
Linus Torvalds committed
503 504 505 506 507 508 509 510 511 512 513 514 515

		if (cpev >= 0) {
			for (irq = 0; irq < NR_IRQS; ++irq)
				if (irq_to_vector(irq) == cpev) {
					desc = irq_desc(irq);
					desc->status |= IRQ_PER_CPU;
					desc->handler = &irq_type_iosapic_level;
					setup_irq(irq, &mca_cpe_irqaction);
				}
			ia64_mca_register_cpev(cpev);
		} else
			printk("ia64_mca_init: Failed to get routed CPEI vector from ACPI.\n");
	}
Linus Torvalds's avatar
Linus Torvalds committed
516

Linus Torvalds's avatar
Linus Torvalds committed
517
	/* Initialize the areas set aside by the OS to buffer the
Linus Torvalds's avatar
Linus Torvalds committed
518 519 520
	 * platform/processor error states for MCA/INIT/CMC
	 * handling.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
521 522 523 524
	ia64_log_init(SAL_INFO_TYPE_MCA);
	ia64_log_init(SAL_INFO_TYPE_INIT);
	ia64_log_init(SAL_INFO_TYPE_CMC);
	ia64_log_init(SAL_INFO_TYPE_CPE);
Linus Torvalds's avatar
Linus Torvalds committed
525

David Mosberger's avatar
David Mosberger committed
526 527 528
	/* Zero the min state save info */
	ia64_mca_min_state_save_info = 0;

Linus Torvalds's avatar
Linus Torvalds committed
529 530 531 532 533
#if defined(MCA_TEST)
	mca_test();
#endif /* #if defined(MCA_TEST) */

	printk("Mca related initialization done\n");
Linus Torvalds's avatar
Linus Torvalds committed
534 535 536 537 538

#if 0   // Too early in initialization -- error log is lost
	/* Do post-failure MCA error logging */
	ia64_mca_check_errors();
#endif  // Too early in initialization -- error log is lost
Linus Torvalds's avatar
Linus Torvalds committed
539 540 541 542
}

/*
 * ia64_mca_wakeup_ipi_wait
Linus Torvalds's avatar
Linus Torvalds committed
543
 *
Linus Torvalds's avatar
Linus Torvalds committed
544
 *	Wait for the inter-cpu interrupt to be sent by the
Linus Torvalds's avatar
Linus Torvalds committed
545
 *	monarch processor once it is done with handling the
Linus Torvalds's avatar
Linus Torvalds committed
546
 *	MCA.
Linus Torvalds's avatar
Linus Torvalds committed
547 548 549
 *
 *  Inputs  :   None
 *  Outputs :   None
Linus Torvalds's avatar
Linus Torvalds committed
550 551 552 553
 */
void
ia64_mca_wakeup_ipi_wait(void)
{
Linus Torvalds's avatar
Linus Torvalds committed
554 555
	int	irr_num = (IA64_MCA_WAKEUP_VECTOR >> 6);
	int	irr_bit = (IA64_MCA_WAKEUP_VECTOR & 0x3f);
Linus Torvalds's avatar
Linus Torvalds committed
556 557 558 559
	u64	irr = 0;

	do {
		switch(irr_num) {
Linus Torvalds's avatar
Linus Torvalds committed
560
		      case 0:
Linus Torvalds's avatar
Linus Torvalds committed
561 562
			irr = ia64_get_irr0();
			break;
Linus Torvalds's avatar
Linus Torvalds committed
563
		      case 1:
Linus Torvalds's avatar
Linus Torvalds committed
564 565
			irr = ia64_get_irr1();
			break;
Linus Torvalds's avatar
Linus Torvalds committed
566
		      case 2:
Linus Torvalds's avatar
Linus Torvalds committed
567 568
			irr = ia64_get_irr2();
			break;
Linus Torvalds's avatar
Linus Torvalds committed
569
		      case 3:
Linus Torvalds's avatar
Linus Torvalds committed
570 571 572 573 574 575 576 577
			irr = ia64_get_irr3();
			break;
		}
	} while (!(irr & (1 << irr_bit))) ;
}

/*
 * ia64_mca_wakeup
Linus Torvalds's avatar
Linus Torvalds committed
578
 *
Linus Torvalds's avatar
Linus Torvalds committed
579
 *	Send an inter-cpu interrupt to wake-up a particular cpu
Linus Torvalds's avatar
Linus Torvalds committed
580
 *	and mark that cpu to be out of rendez.
Linus Torvalds's avatar
Linus Torvalds committed
581 582 583
 *
 *  Inputs  :   cpuid
 *  Outputs :   None
Linus Torvalds's avatar
Linus Torvalds committed
584 585 586 587
 */
void
ia64_mca_wakeup(int cpu)
{
Linus Torvalds's avatar
Linus Torvalds committed
588
	platform_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0);
Linus Torvalds's avatar
Linus Torvalds committed
589
	ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
Linus Torvalds's avatar
Linus Torvalds committed
590

Linus Torvalds's avatar
Linus Torvalds committed
591
}
Linus Torvalds's avatar
Linus Torvalds committed
592

Linus Torvalds's avatar
Linus Torvalds committed
593 594
/*
 * ia64_mca_wakeup_all
Linus Torvalds's avatar
Linus Torvalds committed
595
 *
Linus Torvalds's avatar
Linus Torvalds committed
596
 *	Wakeup all the cpus which have rendez'ed previously.
Linus Torvalds's avatar
Linus Torvalds committed
597 598 599
 *
 *  Inputs  :   None
 *  Outputs :   None
Linus Torvalds's avatar
Linus Torvalds committed
600 601 602 603 604 605 606
 */
void
ia64_mca_wakeup_all(void)
{
	int cpu;

	/* Clear the Rendez checkin flag for all cpus */
David Mosberger's avatar
David Mosberger committed
607
	for(cpu = 0; cpu < smp_num_cpus; cpu++)
Linus Torvalds's avatar
Linus Torvalds committed
608 609 610 611
		if (ia64_mc_info.imi_rendez_checkin[cpu] == IA64_MCA_RENDEZ_CHECKIN_DONE)
			ia64_mca_wakeup(cpu);

}
Linus Torvalds's avatar
Linus Torvalds committed
612

Linus Torvalds's avatar
Linus Torvalds committed
613 614
/*
 * ia64_mca_rendez_interrupt_handler
Linus Torvalds's avatar
Linus Torvalds committed
615
 *
Linus Torvalds's avatar
Linus Torvalds committed
616
 *	This is handler used to put slave processors into spinloop
Linus Torvalds's avatar
Linus Torvalds committed
617 618
 *	while the monarch processor does the mca handling and later
 *	wake each slave up once the monarch is done.
Linus Torvalds's avatar
Linus Torvalds committed
619 620 621
 *
 *  Inputs  :   None
 *  Outputs :   None
Linus Torvalds's avatar
Linus Torvalds committed
622 623 624 625 626 627
 */
void
ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs)
{
	int flags, cpu = 0;
	/* Mask all interrupts */
Linus Torvalds's avatar
Linus Torvalds committed
628
	save_and_cli(flags);
Linus Torvalds's avatar
Linus Torvalds committed
629 630 631 632 633 634 635 636 637 638

#ifdef CONFIG_SMP
	cpu = cpu_logical_id(hard_smp_processor_id());
#endif
	ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_DONE;
	/* Register with the SAL monarch that the slave has
	 * reached SAL
	 */
	ia64_sal_mc_rendez();

Linus Torvalds's avatar
Linus Torvalds committed
639
	/* Wait for the wakeup IPI from the monarch
Linus Torvalds's avatar
Linus Torvalds committed
640 641 642 643 644 645 646 647 648 649 650 651
	 * This waiting is done by polling on the wakeup-interrupt
	 * vector bit in the processor's IRRs
	 */
	ia64_mca_wakeup_ipi_wait();

	/* Enable all interrupts */
	restore_flags(flags);
}


/*
 * ia64_mca_wakeup_int_handler
Linus Torvalds's avatar
Linus Torvalds committed
652
 *
Linus Torvalds's avatar
Linus Torvalds committed
653
 *	The interrupt handler for processing the inter-cpu interrupt to the
Linus Torvalds's avatar
Linus Torvalds committed
654
 *	slave cpu which was spinning in the rendez loop.
Linus Torvalds's avatar
Linus Torvalds committed
655
 *	Since this spinning is done by turning off the interrupts and
Linus Torvalds's avatar
Linus Torvalds committed
656
 *	polling on the wakeup-interrupt bit in the IRR, there is
Linus Torvalds's avatar
Linus Torvalds committed
657
 *	nothing useful to be done in the handler.
Linus Torvalds's avatar
Linus Torvalds committed
658 659
 *
 *  Inputs  :   wakeup_irq  (Wakeup-interrupt bit)
Linus Torvalds's avatar
Linus Torvalds committed
660 661
 *	arg		(Interrupt handler specific argument)
 *	ptregs		(Exception frame at the time of the interrupt)
Linus Torvalds's avatar
Linus Torvalds committed
662
 *  Outputs :   None
Linus Torvalds's avatar
Linus Torvalds committed
663
 *
Linus Torvalds's avatar
Linus Torvalds committed
664 665 666 667
 */
void
ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs)
{
Linus Torvalds's avatar
Linus Torvalds committed
668

Linus Torvalds's avatar
Linus Torvalds committed
669 670 671 672
}

/*
 * ia64_return_to_sal_check
Linus Torvalds's avatar
Linus Torvalds committed
673
 *
Linus Torvalds's avatar
Linus Torvalds committed
674
 *	This is function called before going back from the OS_MCA handler
Linus Torvalds's avatar
Linus Torvalds committed
675 676
 *	to the OS_MCA dispatch code which finally takes the control back
 *	to the SAL.
Linus Torvalds's avatar
Linus Torvalds committed
677
 *	The main purpose of this routine is to setup the OS_MCA to SAL
Linus Torvalds's avatar
Linus Torvalds committed
678
 *	return state which can be used by the OS_MCA dispatch code
Linus Torvalds's avatar
Linus Torvalds committed
679
 *	just before going back to SAL.
Linus Torvalds's avatar
Linus Torvalds committed
680 681 682
 *
 *  Inputs  :   None
 *  Outputs :   None
Linus Torvalds's avatar
Linus Torvalds committed
683 684 685 686 687 688 689 690
 */

void
ia64_return_to_sal_check(void)
{
	/* Copy over some relevant stuff from the sal_to_os_mca_handoff
	 * so that it can be used at the time of os_mca_to_sal_handoff
	 */
Linus Torvalds's avatar
Linus Torvalds committed
691
	ia64_os_to_sal_handoff_state.imots_sal_gp =
Linus Torvalds's avatar
Linus Torvalds committed
692 693
		ia64_sal_to_os_handoff_state.imsto_sal_gp;

Linus Torvalds's avatar
Linus Torvalds committed
694
	ia64_os_to_sal_handoff_state.imots_sal_check_ra =
Linus Torvalds's avatar
Linus Torvalds committed
695 696
		ia64_sal_to_os_handoff_state.imsto_sal_check_ra;

Linus Torvalds's avatar
Linus Torvalds committed
697 698
	/* Cold Boot for uncorrectable MCA */
	ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT;
David Mosberger's avatar
David Mosberger committed
699 700 701 702 703 704 705

	/* Default = tell SAL to return to same context */
	ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT;

	/* Register pointer to new min state values */
	/* NOTE: need to do something with this during recovery phase */
	ia64_os_to_sal_handoff_state.imots_new_min_state = &ia64_mca_min_state_save_info;
Linus Torvalds's avatar
Linus Torvalds committed
706
}
Linus Torvalds's avatar
Linus Torvalds committed
707

Linus Torvalds's avatar
Linus Torvalds committed
708
/*
Linus Torvalds's avatar
Linus Torvalds committed
709
 * ia64_mca_ucmc_handler
Linus Torvalds's avatar
Linus Torvalds committed
710
 *
Linus Torvalds's avatar
Linus Torvalds committed
711 712 713 714 715
 *	This is uncorrectable machine check handler called from OS_MCA
 *	dispatch code which is in turn called from SAL_CHECK().
 *	This is the place where the core of OS MCA handling is done.
 *	Right now the logs are extracted and displayed in a well-defined
 *	format. This handler code is supposed to be run only on the
David Mosberger's avatar
David Mosberger committed
716
 *	monarch processor. Once the monarch is done with MCA handling
Linus Torvalds's avatar
Linus Torvalds committed
717 718
 *	further MCA logging is enabled by clearing logs.
 *	Monarch also has the duty of sending wakeup-IPIs to pull the
David Mosberger's avatar
David Mosberger committed
719
 *	slave processors out of rendezvous spinloop.
Linus Torvalds's avatar
Linus Torvalds committed
720 721 722
 *
 *  Inputs  :   None
 *  Outputs :   None
Linus Torvalds's avatar
Linus Torvalds committed
723 724 725 726
 */
void
ia64_mca_ucmc_handler(void)
{
David Mosberger's avatar
David Mosberger committed
727
	int platform_err = 0;
Linus Torvalds's avatar
Linus Torvalds committed
728

Linus Torvalds's avatar
Linus Torvalds committed
729
	/* Get the MCA error record and log it */
David Mosberger's avatar
David Mosberger committed
730
	platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
Linus Torvalds's avatar
Linus Torvalds committed
731

Linus Torvalds's avatar
Linus Torvalds committed
732
	/*
Linus Torvalds's avatar
Linus Torvalds committed
733
	 *  Do Platform-specific mca error handling if required.
Linus Torvalds's avatar
Linus Torvalds committed
734
	 */
David Mosberger's avatar
David Mosberger committed
735 736
	if (platform_err)
		mca_handler_platform();
Linus Torvalds's avatar
Linus Torvalds committed
737

Linus Torvalds's avatar
Linus Torvalds committed
738 739 740
	/*
	 *  Wakeup all the processors which are spinning in the rendezvous
	 *  loop.
Linus Torvalds's avatar
Linus Torvalds committed
741 742
	 */
	ia64_mca_wakeup_all();
Linus Torvalds's avatar
Linus Torvalds committed
743 744

	/* Return to SAL */
Linus Torvalds's avatar
Linus Torvalds committed
745 746 747
	ia64_return_to_sal_check();
}

Linus Torvalds's avatar
Linus Torvalds committed
748
/*
Linus Torvalds's avatar
Linus Torvalds committed
749
 * ia64_mca_cmc_int_handler
Linus Torvalds's avatar
Linus Torvalds committed
750 751
 *
 *  This is corrected machine check interrupt handler.
Linus Torvalds's avatar
Linus Torvalds committed
752
 *	Right now the logs are extracted and displayed in a well-defined
Linus Torvalds's avatar
Linus Torvalds committed
753
 *	format.
Linus Torvalds's avatar
Linus Torvalds committed
754
 *
Linus Torvalds's avatar
Linus Torvalds committed
755
 * Inputs
Linus Torvalds's avatar
Linus Torvalds committed
756 757 758 759
 *      interrupt number
 *      client data arg ptr
 *      saved registers ptr
 *
Linus Torvalds's avatar
Linus Torvalds committed
760 761 762 763 764
 * Outputs
 *	None
 */
void
ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs)
Linus Torvalds's avatar
Linus Torvalds committed
765
{
Linus Torvalds's avatar
Linus Torvalds committed
766 767
	IA64_MCA_DEBUG("ia64_mca_cmc_int_handler: received interrupt vector = %#x on CPU %d\n",
		       cmc_irq, smp_processor_id());
Linus Torvalds's avatar
Linus Torvalds committed
768

Linus Torvalds's avatar
Linus Torvalds committed
769 770
	/* Get the CMC error record and log it */
	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC);
Linus Torvalds's avatar
Linus Torvalds committed
771 772 773 774 775 776
}

/*
 * IA64_MCA log support
 */
#define IA64_MAX_LOGS		2	/* Double-buffering for nested MCAs */
Linus Torvalds's avatar
Linus Torvalds committed
777
#define IA64_MAX_LOG_TYPES      4   /* MCA, INIT, CMC, CPE */
Linus Torvalds's avatar
Linus Torvalds committed
778

Linus Torvalds's avatar
Linus Torvalds committed
779 780
typedef struct ia64_state_log_s
{
Linus Torvalds's avatar
Linus Torvalds committed
781 782
	spinlock_t	isl_lock;
	int		isl_index;
David Mosberger's avatar
David Mosberger committed
783
	ia64_err_rec_t  *isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */
Linus Torvalds's avatar
Linus Torvalds committed
784 785
} ia64_state_log_t;

Linus Torvalds's avatar
Linus Torvalds committed
786 787
static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES];

David Mosberger's avatar
David Mosberger committed
788 789 790 791 792
#define IA64_LOG_ALLOCATE(it, size) \
	{ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)] = \
		(ia64_err_rec_t *)alloc_bootmem(size); \
	ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)] = \
		(ia64_err_rec_t *)alloc_bootmem(size);}
Linus Torvalds's avatar
Linus Torvalds committed
793 794 795 796 797 798 799 800 801
#define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock)
#define IA64_LOG_LOCK(it)      spin_lock_irqsave(&ia64_state_log[it].isl_lock, s)
#define IA64_LOG_UNLOCK(it)    spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s)
#define IA64_LOG_NEXT_INDEX(it)    ia64_state_log[it].isl_index
#define IA64_LOG_CURR_INDEX(it)    1 - ia64_state_log[it].isl_index
#define IA64_LOG_INDEX_INC(it) \
    ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index
#define IA64_LOG_INDEX_DEC(it) \
    ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index
David Mosberger's avatar
David Mosberger committed
802 803
#define IA64_LOG_NEXT_BUFFER(it)   (void *)((ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)]))
#define IA64_LOG_CURR_BUFFER(it)   (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)]))
Linus Torvalds's avatar
Linus Torvalds committed
804 805 806 807

/*
 * C portion of the OS INIT handler
 *
David Mosberger's avatar
David Mosberger committed
808
 * Called from ia64_monarch_init_handler
Linus Torvalds's avatar
Linus Torvalds committed
809 810 811
 *
 * Inputs: pointer to pt_regs where processor info was saved.
 *
Linus Torvalds's avatar
Linus Torvalds committed
812
 * Returns:
Linus Torvalds's avatar
Linus Torvalds committed
813
 *   0 if SAL must warm boot the System
Linus Torvalds's avatar
Linus Torvalds committed
814
 *   1 if SAL must return to interrupted context using PAL_MC_RESUME
Linus Torvalds's avatar
Linus Torvalds committed
815 816 817 818 819 820
 *
 */
void
ia64_init_handler (struct pt_regs *regs)
{
	sal_log_processor_info_t *proc_ptr;
Linus Torvalds's avatar
Linus Torvalds committed
821
	ia64_err_rec_t *plog_ptr;
Linus Torvalds's avatar
Linus Torvalds committed
822 823 824 825

	printk("Entered OS INIT handler\n");

	/* Get the INIT processor log */
Linus Torvalds's avatar
Linus Torvalds committed
826 827
	if (!ia64_log_get(SAL_INFO_TYPE_INIT, (prfunc_t)printk))
		return;                 // no record retrieved
Linus Torvalds's avatar
Linus Torvalds committed
828

Linus Torvalds's avatar
Linus Torvalds committed
829
#ifdef IA64_DUMP_ALL_PROC_INFO
Linus Torvalds's avatar
Linus Torvalds committed
830
	ia64_log_print(SAL_INFO_TYPE_INIT, (prfunc_t)printk);
Linus Torvalds's avatar
Linus Torvalds committed
831
#endif
Linus Torvalds's avatar
Linus Torvalds committed
832

Linus Torvalds's avatar
Linus Torvalds committed
833
	/*
Linus Torvalds's avatar
Linus Torvalds committed
834 835 836
	 * get pointer to min state save area
	 *
	 */
Linus Torvalds's avatar
Linus Torvalds committed
837 838
	plog_ptr=(ia64_err_rec_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT);
	proc_ptr = &plog_ptr->proc_err;
Linus Torvalds's avatar
Linus Torvalds committed
839

Linus Torvalds's avatar
Linus Torvalds committed
840 841
	ia64_process_min_state_save(&proc_ptr->processor_static_info.min_state_area,
				    regs);
Linus Torvalds's avatar
Linus Torvalds committed
842 843

	/* Clear the INIT SAL logs now that they have been saved in the OS buffer */
Linus Torvalds's avatar
Linus Torvalds committed
844
	ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT);
Linus Torvalds's avatar
Linus Torvalds committed
845 846

	init_handler_platform(regs);              /* call platform specific routines */
Linus Torvalds's avatar
Linus Torvalds committed
847 848
}

Linus Torvalds's avatar
Linus Torvalds committed
849 850 851 852 853 854 855 856 857 858 859 860 861
/*
 *  ia64_log_prt_guid
 *
 *  Print a formatted GUID.
 *
 * Inputs   :   p_guid      (ptr to the GUID)
 *              prfunc      (print function)
 * Outputs  :   None
 *
 */
void
ia64_log_prt_guid (efi_guid_t *p_guid, prfunc_t prfunc)
{
862 863
	char out[40];
	printk(KERN_DEBUG "GUID = %s\n", efi_guid_unparse(p_guid, out));
Linus Torvalds's avatar
Linus Torvalds committed
864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
}

static void
ia64_log_hexdump(unsigned char *p, unsigned long n_ch, prfunc_t prfunc)
{
	int i, j;

	if (!p)
		return;

	for (i = 0; i < n_ch;) {
		prfunc("%p ", (void *)p);
		for (j = 0; (j < 16) && (i < n_ch); i++, j++, p++) {
			prfunc("%02x ", *p);
		}
		prfunc("\n");
	}
}

#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL

static void
ia64_log_prt_record_header (sal_log_record_header_t *rh, prfunc_t prfunc)
{
	prfunc("SAL RECORD HEADER:  Record buffer = %p,  header size = %ld\n",
	       (void *)rh, sizeof(sal_log_record_header_t));
	ia64_log_hexdump((unsigned char *)rh, sizeof(sal_log_record_header_t),
			 (prfunc_t)prfunc);
	prfunc("Total record length = %d\n", rh->len);
	ia64_log_prt_guid(&rh->platform_guid, prfunc);
	prfunc("End of SAL RECORD HEADER\n");
}

static void
ia64_log_prt_section_header (sal_log_section_hdr_t *sh, prfunc_t prfunc)
{
	prfunc("SAL SECTION HEADER:  Record buffer = %p,  header size = %ld\n",
	       (void *)sh, sizeof(sal_log_section_hdr_t));
	ia64_log_hexdump((unsigned char *)sh, sizeof(sal_log_section_hdr_t),
			 (prfunc_t)prfunc);
	prfunc("Length of section & header = %d\n", sh->len);
	ia64_log_prt_guid(&sh->guid, prfunc);
	prfunc("End of SAL SECTION HEADER\n");
}
#endif  // MCA_PRT_XTRA_DATA for test only @FVL

Linus Torvalds's avatar
Linus Torvalds committed
910 911
/*
 * ia64_log_init
Linus Torvalds's avatar
Linus Torvalds committed
912
 *	Reset the OS ia64 log buffer
Linus Torvalds's avatar
Linus Torvalds committed
913
 * Inputs   :   info_type   (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
Linus Torvalds's avatar
Linus Torvalds committed
914
 * Outputs	:	None
Linus Torvalds's avatar
Linus Torvalds committed
915 916
 */
void
Linus Torvalds's avatar
Linus Torvalds committed
917
ia64_log_init(int sal_info_type)
Linus Torvalds's avatar
Linus Torvalds committed
918
{
David Mosberger's avatar
David Mosberger committed
919 920
	u64	max_size = 0;

Linus Torvalds's avatar
Linus Torvalds committed
921
	IA64_LOG_NEXT_INDEX(sal_info_type) = 0;
David Mosberger's avatar
David Mosberger committed
922 923 924 925 926 927 928 929 930
	IA64_LOG_LOCK_INIT(sal_info_type);

	// SAL will tell us the maximum size of any error record of this type
	max_size = ia64_sal_get_state_info_size(sal_info_type);

	// set up OS data structures to hold error info
	IA64_LOG_ALLOCATE(sal_info_type, max_size);
	memset(IA64_LOG_CURR_BUFFER(sal_info_type), 0, max_size);
	memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, max_size);
Linus Torvalds's avatar
Linus Torvalds committed
931 932
}

Linus Torvalds's avatar
Linus Torvalds committed
933
/*
Linus Torvalds's avatar
Linus Torvalds committed
934
 * ia64_log_get
Linus Torvalds's avatar
Linus Torvalds committed
935
 *
Linus Torvalds's avatar
Linus Torvalds committed
936
 *	Get the current MCA log from SAL and copy it into the OS log buffer.
Linus Torvalds's avatar
Linus Torvalds committed
937 938 939 940
 *
 *  Inputs  :   info_type   (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
 *              prfunc      (fn ptr of log output function)
 *  Outputs :   size        (total record length)
Linus Torvalds's avatar
Linus Torvalds committed
941 942
 *
 */
Linus Torvalds's avatar
Linus Torvalds committed
943 944
u64
ia64_log_get(int sal_info_type, prfunc_t prfunc)
Linus Torvalds's avatar
Linus Torvalds committed
945
{
Linus Torvalds's avatar
Linus Torvalds committed
946 947 948
	sal_log_record_header_t     *log_buffer;
	u64                         total_len = 0;
	int                         s;
Linus Torvalds's avatar
Linus Torvalds committed
949

Linus Torvalds's avatar
Linus Torvalds committed
950
	IA64_LOG_LOCK(sal_info_type);
Linus Torvalds's avatar
Linus Torvalds committed
951 952

	/* Get the process state information */
Linus Torvalds's avatar
Linus Torvalds committed
953 954 955 956 957 958 959 960 961 962 963 964
	log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type);

	total_len = ia64_sal_get_state_info(sal_info_type, (u64 *)log_buffer);

	if (total_len) {
		IA64_LOG_INDEX_INC(sal_info_type);
		IA64_LOG_UNLOCK(sal_info_type);
		IA64_MCA_DEBUG("ia64_log_get: SAL error record type %d retrieved. "
			       "Record length = %ld\n", sal_info_type, total_len);
		return total_len;
	} else {
		IA64_LOG_UNLOCK(sal_info_type);
David Mosberger's avatar
David Mosberger committed
965
		prfunc("ia64_log_get: No SAL error record available for type %d\n", sal_info_type);
Linus Torvalds's avatar
Linus Torvalds committed
966 967
		return 0;
	}
Linus Torvalds's avatar
Linus Torvalds committed
968 969
}

Linus Torvalds's avatar
Linus Torvalds committed
970
/*
Linus Torvalds's avatar
Linus Torvalds committed
971 972 973 974 975 976 977
 *  ia64_log_prt_oem_data
 *
 *  Print OEM specific data if included.
 *
 * Inputs   :   header_len  (length passed in section header)
 *              sect_len    (default length of section type)
 *              p_data      (ptr to data)
Linus Torvalds's avatar
Linus Torvalds committed
978
 *			prfunc		(print function)
Linus Torvalds's avatar
Linus Torvalds committed
979
 * Outputs	:	None
Linus Torvalds's avatar
Linus Torvalds committed
980 981 982
 *
 */
void
Linus Torvalds's avatar
Linus Torvalds committed
983
ia64_log_prt_oem_data (int header_len, int sect_len, u8 *p_data, prfunc_t prfunc)
Linus Torvalds's avatar
Linus Torvalds committed
984
{
Linus Torvalds's avatar
Linus Torvalds committed
985
	int oem_data_len, i;
Linus Torvalds's avatar
Linus Torvalds committed
986

Linus Torvalds's avatar
Linus Torvalds committed
987 988 989 990
	if ((oem_data_len = header_len - sect_len) > 0) {
		prfunc(" OEM Specific Data:");
		for (i = 0; i < oem_data_len; i++, p_data++)
			prfunc(" %02x", *p_data);
Linus Torvalds's avatar
Linus Torvalds committed
991
	}
Linus Torvalds's avatar
Linus Torvalds committed
992 993
	prfunc("\n");
}
Linus Torvalds's avatar
Linus Torvalds committed
994

Linus Torvalds's avatar
Linus Torvalds committed
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
/*
 *  ia64_log_rec_header_print
 *
 *  Log info from the SAL error record header.
 *
 *  Inputs  :   lh *    (ptr to SAL log error record header)
 *              prfunc  (fn ptr of log output function to use)
 *  Outputs :   None
 */
void
ia64_log_rec_header_print (sal_log_record_header_t *lh, prfunc_t prfunc)
{
	char str_buf[32];

	sprintf(str_buf, "%2d.%02d",
		(lh->revision.major >> 4) * 10 + (lh->revision.major & 0xf),
		(lh->revision.minor >> 4) * 10 + (lh->revision.minor & 0xf));
	prfunc("+Err Record ID: %d    SAL Rev: %s\n", lh->id, str_buf);
	sprintf(str_buf, "%02d/%02d/%04d/ %02d:%02d:%02d",
		(lh->timestamp.slh_month >> 4) * 10 +
		(lh->timestamp.slh_month & 0xf),
		(lh->timestamp.slh_day >> 4) * 10 +
		(lh->timestamp.slh_day & 0xf),
		(lh->timestamp.slh_century >> 4) * 1000 +
		(lh->timestamp.slh_century & 0xf) * 100 +
		(lh->timestamp.slh_year >> 4) * 10 +
		(lh->timestamp.slh_year & 0xf),
		(lh->timestamp.slh_hour >> 4) * 10 +
		(lh->timestamp.slh_hour & 0xf),
		(lh->timestamp.slh_minute >> 4) * 10 +
		(lh->timestamp.slh_minute & 0xf),
		(lh->timestamp.slh_second >> 4) * 10 +
		(lh->timestamp.slh_second & 0xf));
	prfunc("+Time: %s    Severity %d\n", str_buf, lh->severity);
Linus Torvalds's avatar
Linus Torvalds committed
1029 1030 1031 1032 1033 1034
}

/*
 * ia64_log_processor_regs_print
 *	Print the contents of the saved processor register(s) in the format
 *		<reg_prefix>[<index>] <value>
Linus Torvalds's avatar
Linus Torvalds committed
1035 1036 1037
 *
 * Inputs	:	regs		(Register save buffer)
 *			reg_num	(# of registers)
Linus Torvalds's avatar
Linus Torvalds committed
1038 1039
 *			reg_class	(application/banked/control/bank1_general)
 *			reg_prefix	(ar/br/cr/b1_gr)
Linus Torvalds's avatar
Linus Torvalds committed
1040
 * Outputs	:	None
Linus Torvalds's avatar
Linus Torvalds committed
1041 1042 1043
 *
 */
void
Linus Torvalds's avatar
Linus Torvalds committed
1044 1045 1046 1047
ia64_log_processor_regs_print(u64	*regs,
			      int	reg_num,
			      char	*reg_class,
			      char	*reg_prefix,
Linus Torvalds's avatar
Linus Torvalds committed
1048 1049 1050 1051 1052 1053 1054 1055 1056
			      prfunc_t	prfunc)
{
	int i;

	prfunc("+%s Registers\n", reg_class);
	for (i = 0; i < reg_num; i++)
		prfunc("+ %s[%d] 0x%lx\n", reg_prefix, i, regs[i]);
}

Linus Torvalds's avatar
Linus Torvalds committed
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
/*
 * ia64_log_processor_fp_regs_print
 *  Print the contents of the saved floating page register(s) in the format
 *      <reg_prefix>[<index>] <value>
 *
 * Inputs:  ia64_fpreg  (Register save buffer)
 *          reg_num     (# of registers)
 *          reg_class   (application/banked/control/bank1_general)
 *          reg_prefix  (ar/br/cr/b1_gr)
 * Outputs: None
 *
 */
void
ia64_log_processor_fp_regs_print (struct ia64_fpreg *regs,
                                  int               reg_num,
                                  char              *reg_class,
                                  char              *reg_prefix,
                                  prfunc_t          prfunc)
{
	int i;

	prfunc("+%s Registers\n", reg_class);
	for (i = 0; i < reg_num; i++)
		prfunc("+ %s[%d] 0x%lx%016lx\n", reg_prefix, i, regs[i].u.bits[1],
		       regs[i].u.bits[0]);
}

Linus Torvalds's avatar
Linus Torvalds committed
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
static char *pal_mesi_state[] = {
	"Invalid",
	"Shared",
	"Exclusive",
	"Modified",
	"Reserved1",
	"Reserved2",
	"Reserved3",
	"Reserved4"
};

static char *pal_cache_op[] = {
	"Unknown",
	"Move in",
	"Cast out",
	"Coherency check",
	"Internal",
	"Instruction fetch",
	"Implicit Writeback",
	"Reserved"
};

/*
 * ia64_log_cache_check_info_print
 *	Display the machine check information related to cache error(s).
Linus Torvalds's avatar
Linus Torvalds committed
1109 1110
 * Inputs:  i           (Multiple errors are logged, i - index of logged error)
 *          cc_info *   (Ptr to cache check info logged by the PAL and later
Linus Torvalds's avatar
Linus Torvalds committed
1111
 *					 captured by the SAL)
Linus Torvalds's avatar
Linus Torvalds committed
1112 1113
 *          prfunc      (fn ptr of print function to be used for output)
 * Outputs: None
Linus Torvalds's avatar
Linus Torvalds committed
1114
 */
Linus Torvalds's avatar
Linus Torvalds committed
1115
void
Linus Torvalds's avatar
Linus Torvalds committed
1116 1117 1118
ia64_log_cache_check_info_print (int                      i,
                                 sal_log_mod_error_info_t *cache_check_info,
				 prfunc_t		prfunc)
Linus Torvalds's avatar
Linus Torvalds committed
1119
{
Linus Torvalds's avatar
Linus Torvalds committed
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
	pal_cache_check_info_t  *info;
	u64                     target_addr;

	if (!cache_check_info->valid.check_info) {
		IA64_MCA_DEBUG("ia64_mca_log_print: invalid cache_check_info[%d]\n",i);
		return;                 /* If check info data not valid, skip it */
	}

	info        = (pal_cache_check_info_t *)&cache_check_info->check_info;
	target_addr = cache_check_info->target_identifier;

Linus Torvalds's avatar
Linus Torvalds committed
1131
	prfunc("+ Cache check info[%d]\n+", i);
Linus Torvalds's avatar
Linus Torvalds committed
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
	prfunc("  Level: L%d,",info->level);
	if (info->mv)
		prfunc(" Mesi: %s,",pal_mesi_state[info->mesi]);
	prfunc(" Index: %d,", info->index);
	if (info->ic)
		prfunc(" Cache: Instruction,");
	if (info->dc)
		prfunc(" Cache: Data,");
	if (info->tl)
		prfunc(" Line: Tag,");
	if (info->dl)
		prfunc(" Line: Data,");
	prfunc(" Operation: %s,", pal_cache_op[info->op]);
	if (info->wv)
		prfunc(" Way: %d,", info->way);
	if (cache_check_info->valid.target_identifier)
		/* Hope target address is saved in target_identifier */
		if (info->tv)
			prfunc(" Target Addr: 0x%lx,", target_addr);
	if (info->mc)
		prfunc(" MC: Corrected");
Linus Torvalds's avatar
Linus Torvalds committed
1153 1154 1155 1156 1157 1158
	prfunc("\n");
}

/*
 * ia64_log_tlb_check_info_print
 *	Display the machine check information related to tlb error(s).
Linus Torvalds's avatar
Linus Torvalds committed
1159 1160
 * Inputs:  i           (Multiple errors are logged, i - index of logged error)
 *          tlb_info *  (Ptr to machine check info logged by the PAL and later
Linus Torvalds's avatar
Linus Torvalds committed
1161
 *					 captured by the SAL)
Linus Torvalds's avatar
Linus Torvalds committed
1162 1163
 *          prfunc      (fn ptr of print function to be used for output)
 * Outputs: None
Linus Torvalds's avatar
Linus Torvalds committed
1164 1165
 */
void
Linus Torvalds's avatar
Linus Torvalds committed
1166 1167 1168 1169
ia64_log_tlb_check_info_print (int                      i,
                               sal_log_mod_error_info_t *tlb_check_info,
                               prfunc_t                 prfunc)

Linus Torvalds's avatar
Linus Torvalds committed
1170
{
Linus Torvalds's avatar
Linus Torvalds committed
1171 1172 1173 1174 1175 1176 1177 1178 1179
	pal_tlb_check_info_t    *info;

	if (!tlb_check_info->valid.check_info) {
		IA64_MCA_DEBUG("ia64_mca_log_print: invalid tlb_check_info[%d]\n", i);
		return;                 /* If check info data not valid, skip it */
	}

	info = (pal_tlb_check_info_t *)&tlb_check_info->check_info;

Linus Torvalds's avatar
Linus Torvalds committed
1180
	prfunc("+ TLB Check Info [%d]\n+", i);
Linus Torvalds's avatar
Linus Torvalds committed
1181
	if (info->itc)
Linus Torvalds's avatar
Linus Torvalds committed
1182
		prfunc("  Failure: Instruction Translation Cache");
Linus Torvalds's avatar
Linus Torvalds committed
1183
	if (info->dtc)
Linus Torvalds's avatar
Linus Torvalds committed
1184
		prfunc("  Failure: Data Translation Cache");
Linus Torvalds's avatar
Linus Torvalds committed
1185
	if (info->itr) {
Linus Torvalds's avatar
Linus Torvalds committed
1186
		prfunc("  Failure: Instruction Translation Register");
Linus Torvalds's avatar
Linus Torvalds committed
1187
		prfunc(" ,Slot: %d", info->tr_slot);
Linus Torvalds's avatar
Linus Torvalds committed
1188
	}
Linus Torvalds's avatar
Linus Torvalds committed
1189
	if (info->dtr) {
Linus Torvalds's avatar
Linus Torvalds committed
1190
		prfunc("  Failure: Data Translation Register");
Linus Torvalds's avatar
Linus Torvalds committed
1191
		prfunc(" ,Slot: %d", info->tr_slot);
Linus Torvalds's avatar
Linus Torvalds committed
1192
	}
Linus Torvalds's avatar
Linus Torvalds committed
1193
	if (info->mc)
Linus Torvalds's avatar
Linus Torvalds committed
1194 1195 1196 1197 1198 1199 1200
		prfunc(" ,MC: Corrected");
	prfunc("\n");
}

/*
 * ia64_log_bus_check_info_print
 *	Display the machine check information related to bus error(s).
Linus Torvalds's avatar
Linus Torvalds committed
1201 1202
 * Inputs:  i           (Multiple errors are logged, i - index of logged error)
 *          bus_info *  (Ptr to machine check info logged by the PAL and later
Linus Torvalds's avatar
Linus Torvalds committed
1203
 *					 captured by the SAL)
Linus Torvalds's avatar
Linus Torvalds committed
1204 1205
 *          prfunc      (fn ptr of print function to be used for output)
 * Outputs: None
Linus Torvalds's avatar
Linus Torvalds committed
1206 1207
 */
void
Linus Torvalds's avatar
Linus Torvalds committed
1208 1209 1210
ia64_log_bus_check_info_print (int                      i,
                               sal_log_mod_error_info_t *bus_check_info,
                               prfunc_t                 prfunc)
Linus Torvalds's avatar
Linus Torvalds committed
1211
{
Linus Torvalds's avatar
Linus Torvalds committed
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227
	pal_bus_check_info_t *info;
	u64         req_addr;   /* Address of the requestor of the transaction */
	u64         resp_addr;  /* Address of the responder of the transaction */
	u64         targ_addr;  /* Address where the data was to be delivered to */
	/* or obtained from */

	if (!bus_check_info->valid.check_info) {
		IA64_MCA_DEBUG("ia64_mca_log_print: invalid bus_check_info[%d]\n", i);
		return;                 /* If check info data not valid, skip it */
	}

	info      = (pal_bus_check_info_t *)&bus_check_info->check_info;
	req_addr  = bus_check_info->requestor_identifier;
	resp_addr = bus_check_info->responder_identifier;
	targ_addr = bus_check_info->target_identifier;

Linus Torvalds's avatar
Linus Torvalds committed
1228
	prfunc("+ BUS Check Info [%d]\n+", i);
Linus Torvalds's avatar
Linus Torvalds committed
1229 1230 1231 1232 1233
	prfunc(" Status Info: %d", info->bsi);
	prfunc(" ,Severity: %d", info->sev);
	prfunc(" ,Transaction Type: %d", info->type);
	prfunc(" ,Transaction Size: %d", info->size);
	if (info->cc)
Linus Torvalds's avatar
Linus Torvalds committed
1234
		prfunc(" ,Cache-cache-transfer");
Linus Torvalds's avatar
Linus Torvalds committed
1235
	if (info->ib)
Linus Torvalds's avatar
Linus Torvalds committed
1236
		prfunc(" ,Error: Internal");
Linus Torvalds's avatar
Linus Torvalds committed
1237
	if (info->eb)
Linus Torvalds's avatar
Linus Torvalds committed
1238
		prfunc(" ,Error: External");
Linus Torvalds's avatar
Linus Torvalds committed
1239
	if (info->mc)
Linus Torvalds's avatar
Linus Torvalds committed
1240
		prfunc(" ,MC: Corrected");
Linus Torvalds's avatar
Linus Torvalds committed
1241
	if (info->tv)
Linus Torvalds's avatar
Linus Torvalds committed
1242
		prfunc(" ,Target Address: 0x%lx", targ_addr);
Linus Torvalds's avatar
Linus Torvalds committed
1243
	if (info->rq)
Linus Torvalds's avatar
Linus Torvalds committed
1244
		prfunc(" ,Requestor Address: 0x%lx", req_addr);
Linus Torvalds's avatar
Linus Torvalds committed
1245
	if (info->tv)
Linus Torvalds's avatar
Linus Torvalds committed
1246 1247 1248 1249
		prfunc(" ,Responder Address: 0x%lx", resp_addr);
	prfunc("\n");
}

Linus Torvalds's avatar
Linus Torvalds committed
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308
/*
 *  ia64_log_mem_dev_err_info_print
 *
 *  Format and log the platform memory device error record section data.
 *
 *  Inputs:  mem_dev_err_info * (Ptr to memory device error record section
 *                               returned by SAL)
 *           prfunc             (fn ptr of print function to be used for output)
 *  Outputs: None
 */
void
ia64_log_mem_dev_err_info_print (sal_log_mem_dev_err_info_t *mdei,
                                 prfunc_t                   prfunc)
{
	prfunc("+ Mem Error Detail: ");

	if (mdei->valid.error_status)
		prfunc(" Error Status: %#lx,", mdei->error_status);
	if (mdei->valid.physical_addr)
		prfunc(" Physical Address: %#lx,", mdei->physical_addr);
	if (mdei->valid.addr_mask)
		prfunc(" Address Mask: %#lx,", mdei->addr_mask);
	if (mdei->valid.node)
		prfunc(" Node: %d,", mdei->node);
	if (mdei->valid.card)
		prfunc(" Card: %d,", mdei->card);
	if (mdei->valid.module)
		prfunc(" Module: %d,", mdei->module);
	if (mdei->valid.bank)
		prfunc(" Bank: %d,", mdei->bank);
	if (mdei->valid.device)
		prfunc(" Device: %d,", mdei->device);
	if (mdei->valid.row)
		prfunc(" Row: %d,", mdei->row);
	if (mdei->valid.column)
		prfunc(" Column: %d,", mdei->column);
	if (mdei->valid.bit_position)
		prfunc(" Bit Position: %d,", mdei->bit_position);
	if (mdei->valid.target_id)
		prfunc(" ,Target Address: %#lx,", mdei->target_id);
	if (mdei->valid.requestor_id)
		prfunc(" ,Requestor Address: %#lx,", mdei->requestor_id);
	if (mdei->valid.responder_id)
		prfunc(" ,Responder Address: %#lx,", mdei->responder_id);
	if (mdei->valid.bus_spec_data)
		prfunc(" Bus Specific Data: %#lx,", mdei->bus_spec_data);
	prfunc("\n");

	if (mdei->valid.oem_id) {
		u8  *p_data = &(mdei->oem_id[0]);
		int i;

		prfunc(" OEM Memory Controller ID:");
		for (i = 0; i < 16; i++, p_data++)
			prfunc(" %02x", *p_data);
		prfunc("\n");
	}

	if (mdei->valid.oem_data) {
David Mosberger's avatar
David Mosberger committed
1309
		platform_mem_dev_err_print((int)mdei->header.len,
Linus Torvalds's avatar
Linus Torvalds committed
1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397
				      (int)sizeof(sal_log_mem_dev_err_info_t) - 1,
				      &(mdei->oem_data[0]), prfunc);
	}
}

/*
 *  ia64_log_sel_dev_err_info_print
 *
 *  Format and log the platform SEL device error record section data.
 *
 *  Inputs:  sel_dev_err_info * (Ptr to the SEL device error record section
 *                               returned by SAL)
 *           prfunc             (fn ptr of print function to be used for output)
 *  Outputs: None
 */
void
ia64_log_sel_dev_err_info_print (sal_log_sel_dev_err_info_t *sdei,
                                 prfunc_t                   prfunc)
{
	int     i;

	prfunc("+ SEL Device Error Detail: ");

	if (sdei->valid.record_id)
		prfunc(" Record ID: %#x", sdei->record_id);
	if (sdei->valid.record_type)
		prfunc(" Record Type: %#x", sdei->record_type);
	prfunc(" Time Stamp: ");
	for (i = 0; i < 4; i++)
		prfunc("%1d", sdei->timestamp[i]);
	if (sdei->valid.generator_id)
		prfunc(" Generator ID: %#x", sdei->generator_id);
	if (sdei->valid.evm_rev)
		prfunc(" Message Format Version: %#x", sdei->evm_rev);
	if (sdei->valid.sensor_type)
		prfunc(" Sensor Type: %#x", sdei->sensor_type);
	if (sdei->valid.sensor_num)
		prfunc(" Sensor Number: %#x", sdei->sensor_num);
	if (sdei->valid.event_dir)
		prfunc(" Event Direction Type: %#x", sdei->event_dir);
	if (sdei->valid.event_data1)
		prfunc(" Data1: %#x", sdei->event_data1);
	if (sdei->valid.event_data2)
		prfunc(" Data2: %#x", sdei->event_data2);
	if (sdei->valid.event_data3)
		prfunc(" Data3: %#x", sdei->event_data3);
	prfunc("\n");

}

/*
 *  ia64_log_pci_bus_err_info_print
 *
 *  Format and log the platform PCI bus error record section data.
 *
 *  Inputs:  pci_bus_err_info * (Ptr to the PCI bus error record section
 *                               returned by SAL)
 *           prfunc             (fn ptr of print function to be used for output)
 *  Outputs: None
 */
void
ia64_log_pci_bus_err_info_print (sal_log_pci_bus_err_info_t *pbei,
                                 prfunc_t                   prfunc)
{
	prfunc("+ PCI Bus Error Detail: ");

	if (pbei->valid.err_status)
		prfunc(" Error Status: %#lx", pbei->err_status);
	if (pbei->valid.err_type)
		prfunc(" Error Type: %#x", pbei->err_type);
	if (pbei->valid.bus_id)
		prfunc(" Bus ID: %#x", pbei->bus_id);
	if (pbei->valid.bus_address)
		prfunc(" Bus Address: %#lx", pbei->bus_address);
	if (pbei->valid.bus_data)
		prfunc(" Bus Data: %#lx", pbei->bus_data);
	if (pbei->valid.bus_cmd)
		prfunc(" Bus Command: %#lx", pbei->bus_cmd);
	if (pbei->valid.requestor_id)
		prfunc(" Requestor ID: %#lx", pbei->requestor_id);
	if (pbei->valid.responder_id)
		prfunc(" Responder ID: %#lx", pbei->responder_id);
	if (pbei->valid.target_id)
		prfunc(" Target ID: %#lx", pbei->target_id);
	if (pbei->valid.oem_data)
		prfunc("\n");

	if (pbei->valid.oem_data) {
David Mosberger's avatar
David Mosberger committed
1398
		platform_pci_bus_err_print((int)pbei->header.len,
Linus Torvalds's avatar
Linus Torvalds committed
1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496
				      (int)sizeof(sal_log_pci_bus_err_info_t) - 1,
				      &(pbei->oem_data[0]), prfunc);
	}
}

/*
 *  ia64_log_smbios_dev_err_info_print
 *
 *  Format and log the platform SMBIOS device error record section data.
 *
 *  Inputs:  smbios_dev_err_info * (Ptr to the SMBIOS device error record
 *                                  section returned by SAL)
 *           prfunc             (fn ptr of print function to be used for output)
 *  Outputs: None
 */
void
ia64_log_smbios_dev_err_info_print (sal_log_smbios_dev_err_info_t *sdei,
                                    prfunc_t                      prfunc)
{
	u8      i;

	prfunc("+ SMBIOS Device Error Detail: ");

	if (sdei->valid.event_type)
		prfunc(" Event Type: %#x", sdei->event_type);
	if (sdei->valid.time_stamp) {
		prfunc(" Time Stamp: ");
		for (i = 0; i < 6; i++)
			prfunc("%d", sdei->time_stamp[i]);
	}
	if ((sdei->valid.data) && (sdei->valid.length)) {
		prfunc(" Data: ");
		for (i = 0; i < sdei->length; i++)
			prfunc(" %02x", sdei->data[i]);
	}
	prfunc("\n");
}

/*
 *  ia64_log_pci_comp_err_info_print
 *
 *  Format and log the platform PCI component error record section data.
 *
 *  Inputs:  pci_comp_err_info * (Ptr to the PCI component error record section
 *                                returned by SAL)
 *           prfunc             (fn ptr of print function to be used for output)
 *  Outputs: None
 */
void
ia64_log_pci_comp_err_info_print(sal_log_pci_comp_err_info_t *pcei,
				 prfunc_t                     prfunc)
{
	u32     n_mem_regs, n_io_regs;
	u64     i, n_pci_data;
	u64     *p_reg_data;
	u8      *p_oem_data;

	prfunc("+ PCI Component Error Detail: ");

	if (pcei->valid.err_status)
		prfunc(" Error Status: %#lx\n", pcei->err_status);
	if (pcei->valid.comp_info)
		prfunc(" Component Info: Vendor Id = %#x, Device Id = %#x,"
		       " Class Code = %#x, Seg/Bus/Dev/Func = %d/%d/%d/%d\n",
		       pcei->comp_info.vendor_id, pcei->comp_info.device_id,
		       pcei->comp_info.class_code, pcei->comp_info.seg_num,
		       pcei->comp_info.bus_num, pcei->comp_info.dev_num,
		       pcei->comp_info.func_num);

	n_mem_regs = (pcei->valid.num_mem_regs) ? pcei->num_mem_regs : 0;
	n_io_regs =  (pcei->valid.num_io_regs)  ? pcei->num_io_regs  : 0;
	p_reg_data = &(pcei->reg_data_pairs[0]);
	p_oem_data = (u8 *)p_reg_data +
		(n_mem_regs + n_io_regs) * 2 * sizeof(u64);
	n_pci_data = p_oem_data - (u8 *)pcei;

	if (n_pci_data > pcei->header.len) {
		prfunc(" Invalid PCI Component Error Record format: length = %ld, "
		       " Size PCI Data = %d, Num Mem-Map/IO-Map Regs = %ld/%ld\n",
		       pcei->header.len, n_pci_data, n_mem_regs, n_io_regs);
		return;
	}

	if (n_mem_regs) {
		prfunc(" Memory Mapped Registers\n Address \tValue\n");
		for (i = 0; i < pcei->num_mem_regs; i++) {
			prfunc(" %#lx %#lx\n", p_reg_data[0], p_reg_data[1]);
			p_reg_data += 2;
		}
	}
	if (n_io_regs) {
		prfunc(" I/O Mapped Registers\n Address \tValue\n");
		for (i = 0; i < pcei->num_io_regs; i++) {
			prfunc(" %#lx %#lx\n", p_reg_data[0], p_reg_data[1]);
			p_reg_data += 2;
		}
	}
	if (pcei->valid.oem_data) {
David Mosberger's avatar
David Mosberger committed
1497
		platform_pci_comp_err_print((int)pcei->header.len, n_pci_data,
Linus Torvalds's avatar
Linus Torvalds committed
1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525
				      p_oem_data, prfunc);
		prfunc("\n");
	}
}

/*
 *  ia64_log_plat_specific_err_info_print
 *
 *  Format and log the platform specifie error record section data.
 *
 *  Inputs:  sel_dev_err_info * (Ptr to the platform specific error record
 *                               section returned by SAL)
 *           prfunc             (fn ptr of print function to be used for output)
 *  Outputs: None
 */
void
ia64_log_plat_specific_err_info_print (sal_log_plat_specific_err_info_t *psei,
                                       prfunc_t                         prfunc)
{
	prfunc("+ Platform Specific Error Detail: ");

	if (psei->valid.err_status)
		prfunc(" Error Status: %#lx", psei->err_status);
	if (psei->valid.guid) {
		prfunc(" GUID: ");
		ia64_log_prt_guid(&psei->guid, prfunc);
	}
	if (psei->valid.oem_data) {
David Mosberger's avatar
David Mosberger committed
1526
		platform_plat_specific_err_print((int)psei->header.len,
Linus Torvalds's avatar
Linus Torvalds committed
1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
				      (int)sizeof(sal_log_plat_specific_err_info_t) - 1,
				      &(psei->oem_data[0]), prfunc);
	}
	prfunc("\n");
}

/*
 *  ia64_log_host_ctlr_err_info_print
 *
 *  Format and log the platform host controller error record section data.
 *
 *  Inputs:  host_ctlr_err_info * (Ptr to the host controller error record
 *                                 section returned by SAL)
 *           prfunc             (fn ptr of print function to be used for output)
 *  Outputs: None
 */
void
ia64_log_host_ctlr_err_info_print (sal_log_host_ctlr_err_info_t *hcei,
                                   prfunc_t                     prfunc)
{
	prfunc("+ Host Controller Error Detail: ");

	if (hcei->valid.err_status)
		prfunc(" Error Status: %#lx", hcei->err_status);
	if (hcei->valid.requestor_id)
		prfunc(" Requestor ID: %#lx", hcei->requestor_id);
	if (hcei->valid.responder_id)
		prfunc(" Responder ID: %#lx", hcei->responder_id);
	if (hcei->valid.target_id)
		prfunc(" Target ID: %#lx", hcei->target_id);
	if (hcei->valid.bus_spec_data)
		prfunc(" Bus Specific Data: %#lx", hcei->bus_spec_data);
	if (hcei->valid.oem_data) {
David Mosberger's avatar
David Mosberger committed
1560
		platform_host_ctlr_err_print((int)hcei->header.len,
Linus Torvalds's avatar
Linus Torvalds committed
1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593
				      (int)sizeof(sal_log_host_ctlr_err_info_t) - 1,
				      &(hcei->oem_data[0]), prfunc);
	}
	prfunc("\n");
}

/*
 *  ia64_log_plat_bus_err_info_print
 *
 *  Format and log the platform bus error record section data.
 *
 *  Inputs:  plat_bus_err_info * (Ptr to the platform bus error record section
 *                                returned by SAL)
 *           prfunc             (fn ptr of print function to be used for output)
 *  Outputs: None
 */
void
ia64_log_plat_bus_err_info_print (sal_log_plat_bus_err_info_t *pbei,
                                  prfunc_t                    prfunc)
{
	prfunc("+ Platform Bus Error Detail: ");

	if (pbei->valid.err_status)
		prfunc(" Error Status: %#lx", pbei->err_status);
	if (pbei->valid.requestor_id)
		prfunc(" Requestor ID: %#lx", pbei->requestor_id);
	if (pbei->valid.responder_id)
		prfunc(" Responder ID: %#lx", pbei->responder_id);
	if (pbei->valid.target_id)
		prfunc(" Target ID: %#lx", pbei->target_id);
	if (pbei->valid.bus_spec_data)
		prfunc(" Bus Specific Data: %#lx", pbei->bus_spec_data);
	if (pbei->valid.oem_data) {
David Mosberger's avatar
David Mosberger committed
1594
		platform_plat_bus_err_print((int)pbei->header.len,
Linus Torvalds's avatar
Linus Torvalds committed
1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713
				      (int)sizeof(sal_log_plat_bus_err_info_t) - 1,
				      &(pbei->oem_data[0]), prfunc);
	}
	prfunc("\n");
}

/*
 *  ia64_log_proc_dev_err_info_print
 *
 *  Display the processor device error record.
 *
 *  Inputs:  sal_log_processor_info_t * (Ptr to processor device error record
 *                                       section body).
 *           prfunc                     (fn ptr of print function to be used
 *                                       for output).
 *  Outputs: None
 */
void
ia64_log_proc_dev_err_info_print (sal_log_processor_info_t  *slpi,
                                  prfunc_t                  prfunc)
{
#ifdef MCA_PRT_XTRA_DATA
	size_t  d_len = slpi->header.len - sizeof(sal_log_section_hdr_t);
#endif
	sal_processor_static_info_t *spsi;
	int                         i;
	sal_log_mod_error_info_t    *p_data;

	prfunc("+Processor Device Error Info Section\n");

#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
	{
		char    *p_data = (char *)&slpi->valid;

		prfunc("SAL_PROC_DEV_ERR SECTION DATA:  Data buffer = %p, "
		       "Data size = %ld\n", (void *)p_data, d_len);
		ia64_log_hexdump(p_data, d_len, prfunc);
		prfunc("End of SAL_PROC_DEV_ERR SECTION DATA\n");
	}
#endif  // MCA_PRT_XTRA_DATA for test only @FVL

	if (slpi->valid.proc_error_map)
		prfunc(" Processor Error Map: %#lx\n", slpi->proc_error_map);

	if (slpi->valid.proc_state_param)
		prfunc(" Processor State Param: %#lx\n", slpi->proc_state_parameter);

	if (slpi->valid.proc_cr_lid)
		prfunc(" Processor LID: %#lx\n", slpi->proc_cr_lid);

	/*
	 *  Note: March 2001 SAL spec states that if the number of elements in any
	 *  of  the MOD_ERROR_INFO_STRUCT arrays is zero, the entire array is
	 *  absent. Also, current implementations only allocate space for number of
	 *  elements used.  So we walk the data pointer from here on.
	 */
	p_data = &slpi->cache_check_info[0];

	/* Print the cache check information if any*/
	for (i = 0 ; i < slpi->valid.num_cache_check; i++, p_data++)
		ia64_log_cache_check_info_print(i, p_data, prfunc);

	/* Print the tlb check information if any*/
	for (i = 0 ; i < slpi->valid.num_tlb_check; i++, p_data++)
		ia64_log_tlb_check_info_print(i, p_data, prfunc);

	/* Print the bus check information if any*/
	for (i = 0 ; i < slpi->valid.num_bus_check; i++, p_data++)
		ia64_log_bus_check_info_print(i, p_data, prfunc);

	/* Print the reg file check information if any*/
	for (i = 0 ; i < slpi->valid.num_reg_file_check; i++, p_data++)
		ia64_log_hexdump((u8 *)p_data, sizeof(sal_log_mod_error_info_t),
				 prfunc);    /* Just hex dump for now */

	/* Print the ms check information if any*/
	for (i = 0 ; i < slpi->valid.num_ms_check; i++, p_data++)
		ia64_log_hexdump((u8 *)p_data, sizeof(sal_log_mod_error_info_t),
				 prfunc);    /* Just hex dump for now */

	/* Print CPUID registers if any*/
	if (slpi->valid.cpuid_info) {
		u64     *p = (u64 *)p_data;

		prfunc(" CPUID Regs: %#lx %#lx %#lx %#lx\n", p[0], p[1], p[2], p[3]);
		p_data++;
	}

	/* Print processor static info if any */
	if (slpi->valid.psi_static_struct) {
		spsi = (sal_processor_static_info_t *)p_data;

		/* Print branch register contents if valid */
		if (spsi->valid.br)
			ia64_log_processor_regs_print(spsi->br, 8, "Branch", "br",
						      prfunc);

		/* Print control register contents if valid */
		if (spsi->valid.cr)
			ia64_log_processor_regs_print(spsi->cr, 128, "Control", "cr",
						      prfunc);

		/* Print application register contents if valid */
		if (spsi->valid.ar)
			ia64_log_processor_regs_print(spsi->ar, 128, "Application",
						      "ar", prfunc);

		/* Print region register contents if valid */
		if (spsi->valid.rr)
			ia64_log_processor_regs_print(spsi->rr, 8, "Region", "rr",
						      prfunc);

		/* Print floating-point register contents if valid */
		if (spsi->valid.fr)
			ia64_log_processor_fp_regs_print(spsi->fr, 128, "Floating-point", "fr",
							 prfunc);
	}
}

Linus Torvalds's avatar
Linus Torvalds committed
1714 1715
/*
 * ia64_log_processor_info_print
Linus Torvalds's avatar
Linus Torvalds committed
1716
 *
Linus Torvalds's avatar
Linus Torvalds committed
1717 1718
 *	Display the processor-specific information logged by PAL as a part
 *	of MCA or INIT or CMC.
Linus Torvalds's avatar
Linus Torvalds committed
1719 1720 1721 1722
 *
 *  Inputs   :  lh      (Pointer of the sal log header which specifies the
 *                       format of SAL state info as specified by the SAL spec).
 *              prfunc  (fn ptr of print function to be used for output).
Linus Torvalds's avatar
Linus Torvalds committed
1723
 * Outputs	:	None
Linus Torvalds's avatar
Linus Torvalds committed
1724 1725
 */
void
Linus Torvalds's avatar
Linus Torvalds committed
1726
ia64_log_processor_info_print(sal_log_record_header_t *lh, prfunc_t prfunc)
Linus Torvalds's avatar
Linus Torvalds committed
1727
{
Linus Torvalds's avatar
Linus Torvalds committed
1728 1729 1730
	sal_log_section_hdr_t       *slsh;
	int                         n_sects;
	int                         ercd_pos;
Linus Torvalds's avatar
Linus Torvalds committed
1731 1732 1733 1734

	if (!lh)
		return;

Linus Torvalds's avatar
Linus Torvalds committed
1735 1736 1737 1738 1739 1740 1741 1742
#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
	ia64_log_prt_record_header(lh, prfunc);
#endif  // MCA_PRT_XTRA_DATA for test only @FVL

	if ((ercd_pos = sizeof(sal_log_record_header_t)) >= lh->len) {
		IA64_MCA_DEBUG("ia64_mca_log_print: "
			       "truncated SAL CMC error record. len = %d\n",
			       lh->len);
Linus Torvalds's avatar
Linus Torvalds committed
1743
		return;
Linus Torvalds's avatar
Linus Torvalds committed
1744 1745 1746 1747
	}

	/* Print record header info */
	ia64_log_rec_header_print(lh, prfunc);
Linus Torvalds's avatar
Linus Torvalds committed
1748

Linus Torvalds's avatar
Linus Torvalds committed
1749 1750 1751 1752 1753 1754 1755 1756
	for (n_sects = 0; (ercd_pos < lh->len); n_sects++, ercd_pos += slsh->len) {
		/* point to next section header */
		slsh = (sal_log_section_hdr_t *)((char *)lh + ercd_pos);

#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
		ia64_log_prt_section_header(slsh, prfunc);
#endif  // MCA_PRT_XTRA_DATA for test only @FVL

1757
		if (verify_guid(&slsh->guid, &(SAL_PROC_DEV_ERR_SECT_GUID))) {
Linus Torvalds's avatar
Linus Torvalds committed
1758 1759 1760
			IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n");
			continue;
		}
Linus Torvalds's avatar
Linus Torvalds committed
1761

Linus Torvalds's avatar
Linus Torvalds committed
1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773
		/*
		 *  Now process processor device error record section
		 */
		ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh,
						 printk);
	}

	IA64_MCA_DEBUG("ia64_mca_log_print: "
		       "found %d sections in SAL CMC error record. len = %d\n",
		       n_sects, lh->len);
	if (!n_sects) {
		prfunc("No Processor Device Error Info Section found\n");
Linus Torvalds's avatar
Linus Torvalds committed
1774 1775
		return;
	}
Linus Torvalds's avatar
Linus Torvalds committed
1776
}
Linus Torvalds's avatar
Linus Torvalds committed
1777

Linus Torvalds's avatar
Linus Torvalds committed
1778 1779 1780 1781 1782 1783 1784 1785
/*
 *  ia64_log_platform_info_print
 *
 *  Format and Log the SAL Platform Error Record.
 *
 *  Inputs  :   lh      (Pointer to the sal error record header with format
 *                       specified by the SAL spec).
 *              prfunc  (fn ptr of log output function to use)
David Mosberger's avatar
David Mosberger committed
1786
 *  Outputs :	platform error status
Linus Torvalds's avatar
Linus Torvalds committed
1787
 */
David Mosberger's avatar
David Mosberger committed
1788
int
Linus Torvalds's avatar
Linus Torvalds committed
1789 1790
ia64_log_platform_info_print (sal_log_record_header_t *lh, prfunc_t prfunc)
{
David Mosberger's avatar
David Mosberger committed
1791 1792 1793 1794
	sal_log_section_hdr_t	*slsh;
	int			n_sects;
	int			ercd_pos;
	int			platform_err = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1795

Linus Torvalds's avatar
Linus Torvalds committed
1796
	if (!lh)
David Mosberger's avatar
David Mosberger committed
1797
		return platform_err;
Linus Torvalds's avatar
Linus Torvalds committed
1798

Linus Torvalds's avatar
Linus Torvalds committed
1799 1800 1801
#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
	ia64_log_prt_record_header(lh, prfunc);
#endif  // MCA_PRT_XTRA_DATA for test only @FVL
Linus Torvalds's avatar
Linus Torvalds committed
1802

Linus Torvalds's avatar
Linus Torvalds committed
1803 1804 1805 1806
	if ((ercd_pos = sizeof(sal_log_record_header_t)) >= lh->len) {
		IA64_MCA_DEBUG("ia64_mca_log_print: "
			       "truncated SAL error record. len = %d\n",
			       lh->len);
David Mosberger's avatar
David Mosberger committed
1807
		return platform_err;
Linus Torvalds's avatar
Linus Torvalds committed
1808
	}
Linus Torvalds's avatar
Linus Torvalds committed
1809

Linus Torvalds's avatar
Linus Torvalds committed
1810 1811
	/* Print record header info */
	ia64_log_rec_header_print(lh, prfunc);
Linus Torvalds's avatar
Linus Torvalds committed
1812

Linus Torvalds's avatar
Linus Torvalds committed
1813 1814 1815
	for (n_sects = 0; (ercd_pos < lh->len); n_sects++, ercd_pos += slsh->len) {
		/* point to next section header */
		slsh = (sal_log_section_hdr_t *)((char *)lh + ercd_pos);
Linus Torvalds's avatar
Linus Torvalds committed
1816

Linus Torvalds's avatar
Linus Torvalds committed
1817 1818
#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
		ia64_log_prt_section_header(slsh, prfunc);
Linus Torvalds's avatar
Linus Torvalds committed
1819

Linus Torvalds's avatar
Linus Torvalds committed
1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837
		if (efi_guidcmp(slsh->guid, SAL_PROC_DEV_ERR_SECT_GUID) != 0) {
			size_t  d_len = slsh->len - sizeof(sal_log_section_hdr_t);
			char    *p_data = (char *)&((sal_log_mem_dev_err_info_t *)slsh)->valid;

			prfunc("Start of Platform Err Data Section:  Data buffer = %p, "
			       "Data size = %ld\n", (void *)p_data, d_len);
			ia64_log_hexdump(p_data, d_len, prfunc);
			prfunc("End of Platform Err Data Section\n");
		}
#endif  // MCA_PRT_XTRA_DATA for test only @FVL

		/*
		 *  Now process CPE error record section
		 */
		if (efi_guidcmp(slsh->guid, SAL_PROC_DEV_ERR_SECT_GUID) == 0) {
			ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh,
							 prfunc);
		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID) == 0) {
David Mosberger's avatar
David Mosberger committed
1838
			platform_err = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1839 1840 1841 1842
			prfunc("+Platform Memory Device Error Info Section\n");
			ia64_log_mem_dev_err_info_print((sal_log_mem_dev_err_info_t *)slsh,
							prfunc);
		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_SEL_DEV_ERR_SECT_GUID) == 0) {
David Mosberger's avatar
David Mosberger committed
1843
			platform_err = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1844 1845 1846 1847
			prfunc("+Platform SEL Device Error Info Section\n");
			ia64_log_sel_dev_err_info_print((sal_log_sel_dev_err_info_t *)slsh,
							prfunc);
		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_BUS_ERR_SECT_GUID) == 0) {
David Mosberger's avatar
David Mosberger committed
1848
			platform_err = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1849 1850 1851 1852
			prfunc("+Platform PCI Bus Error Info Section\n");
			ia64_log_pci_bus_err_info_print((sal_log_pci_bus_err_info_t *)slsh,
							prfunc);
		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID) == 0) {
David Mosberger's avatar
David Mosberger committed
1853
			platform_err = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1854 1855 1856 1857
			prfunc("+Platform SMBIOS Device Error Info Section\n");
			ia64_log_smbios_dev_err_info_print((sal_log_smbios_dev_err_info_t *)slsh,
							   prfunc);
		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_COMP_ERR_SECT_GUID) == 0) {
David Mosberger's avatar
David Mosberger committed
1858
			platform_err = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1859 1860 1861 1862
			prfunc("+Platform PCI Component Error Info Section\n");
			ia64_log_pci_comp_err_info_print((sal_log_pci_comp_err_info_t *)slsh,
							 prfunc);
		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID) == 0) {
David Mosberger's avatar
David Mosberger committed
1863
			platform_err = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1864 1865 1866 1867 1868
			prfunc("+Platform Specific Error Info Section\n");
			ia64_log_plat_specific_err_info_print((sal_log_plat_specific_err_info_t *)
							      slsh,
							      prfunc);
		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_HOST_CTLR_ERR_SECT_GUID) == 0) {
David Mosberger's avatar
David Mosberger committed
1869
			platform_err = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1870 1871 1872 1873
			prfunc("+Platform Host Controller Error Info Section\n");
			ia64_log_host_ctlr_err_info_print((sal_log_host_ctlr_err_info_t *)slsh,
							  prfunc);
		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_BUS_ERR_SECT_GUID) == 0) {
David Mosberger's avatar
David Mosberger committed
1874
			platform_err = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887
			prfunc("+Platform Bus Error Info Section\n");
			ia64_log_plat_bus_err_info_print((sal_log_plat_bus_err_info_t *)slsh,
							 prfunc);
		} else {
			IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n");
			continue;
		}
	}

	IA64_MCA_DEBUG("ia64_mca_log_print: found %d sections in SAL error record. len = %d\n",
		       n_sects, lh->len);
	if (!n_sects) {
		prfunc("No Platform Error Info Sections found\n");
David Mosberger's avatar
David Mosberger committed
1888
		return platform_err;
Linus Torvalds's avatar
Linus Torvalds committed
1889
	}
David Mosberger's avatar
David Mosberger committed
1890
	return platform_err;
Linus Torvalds's avatar
Linus Torvalds committed
1891 1892 1893 1894
}

/*
 * ia64_log_print
Linus Torvalds's avatar
Linus Torvalds committed
1895 1896 1897 1898 1899
 *
 *  Displays the contents of the OS error log information
 *
 *  Inputs   :  info_type   (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
 *              prfunc      (fn ptr of log output function to use)
David Mosberger's avatar
David Mosberger committed
1900
 * Outputs	:	platform error status
Linus Torvalds's avatar
Linus Torvalds committed
1901
 */
David Mosberger's avatar
David Mosberger committed
1902
int
Linus Torvalds's avatar
Linus Torvalds committed
1903
ia64_log_print(int sal_info_type, prfunc_t prfunc)
Linus Torvalds's avatar
Linus Torvalds committed
1904
{
David Mosberger's avatar
David Mosberger committed
1905 1906
	int platform_err = 0;

Linus Torvalds's avatar
Linus Torvalds committed
1907
	switch(sal_info_type) {
Linus Torvalds's avatar
Linus Torvalds committed
1908 1909
	      case SAL_INFO_TYPE_MCA:
		prfunc("+BEGIN HARDWARE ERROR STATE AT MCA\n");
David Mosberger's avatar
David Mosberger committed
1910
		platform_err = ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc);
Linus Torvalds's avatar
Linus Torvalds committed
1911
		prfunc("+END HARDWARE ERROR STATE AT MCA\n");
Linus Torvalds's avatar
Linus Torvalds committed
1912
		break;
Linus Torvalds's avatar
Linus Torvalds committed
1913 1914
	      case SAL_INFO_TYPE_INIT:
		prfunc("+MCA INIT ERROR LOG (UNIMPLEMENTED)\n");
Linus Torvalds's avatar
Linus Torvalds committed
1915
		break;
Linus Torvalds's avatar
Linus Torvalds committed
1916 1917 1918 1919
	      case SAL_INFO_TYPE_CMC:
		prfunc("+BEGIN HARDWARE ERROR STATE AT CMC\n");
		ia64_log_processor_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc);
		prfunc("+END HARDWARE ERROR STATE AT CMC\n");
Linus Torvalds's avatar
Linus Torvalds committed
1920
		break;
Linus Torvalds's avatar
Linus Torvalds committed
1921 1922 1923 1924
	      case SAL_INFO_TYPE_CPE:
		prfunc("+BEGIN HARDWARE ERROR STATE AT CPE\n");
		ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc);
		prfunc("+END HARDWARE ERROR STATE AT CPE\n");
Linus Torvalds's avatar
Linus Torvalds committed
1925
		break;
Linus Torvalds's avatar
Linus Torvalds committed
1926 1927
	      default:
		prfunc("+MCA UNKNOWN ERROR LOG (UNIMPLEMENTED)\n");
Linus Torvalds's avatar
Linus Torvalds committed
1928 1929
		break;
	}
David Mosberger's avatar
David Mosberger committed
1930
	return platform_err;
Linus Torvalds's avatar
Linus Torvalds committed
1931
}