Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7f613c7d authored by Keith Owens's avatar Keith Owens Committed by Tony Luck
Browse files

[PATCH] MCA/INIT: use per cpu stacks



The bulk of the change.  Use per cpu MCA/INIT stacks.  Change the SAL
to OS state (sos) to be per process.  Do all the assembler work on the
MCA/INIT stacks, leaving the original stack alone.  Pass per cpu state
data to the C handlers for MCA and INIT, which also means changing the
mca_drv interfaces slightly.  Lots of verification on whether the
original stack is usable before converting it to a sleeping process.

Signed-off-by: default avatarKeith Owens <kaos@sgi.com>
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
parent 289d773e
Loading
Loading
Loading
Loading
+32 −8
Original line number Diff line number Diff line
@@ -211,17 +211,41 @@ void foo(void)
#endif

	BLANK();
	DEFINE(IA64_MCA_CPU_PROC_STATE_DUMP_OFFSET,
	       offsetof (struct ia64_mca_cpu, proc_state_dump));
	DEFINE(IA64_MCA_CPU_STACK_OFFSET,
	       offsetof (struct ia64_mca_cpu, stack));
	DEFINE(IA64_MCA_CPU_STACKFRAME_OFFSET,
	       offsetof (struct ia64_mca_cpu, stackframe));
	DEFINE(IA64_MCA_CPU_RBSTORE_OFFSET,
	       offsetof (struct ia64_mca_cpu, rbstore));
	DEFINE(IA64_MCA_CPU_MCA_STACK_OFFSET,
	       offsetof (struct ia64_mca_cpu, mca_stack));
	DEFINE(IA64_MCA_CPU_INIT_STACK_OFFSET,
	       offsetof (struct ia64_mca_cpu, init_stack));
	BLANK();
	DEFINE(IA64_SAL_OS_STATE_COMMON_OFFSET,
	       offsetof (struct ia64_sal_os_state, sal_ra));
	DEFINE(IA64_SAL_OS_STATE_OS_GP_OFFSET,
	       offsetof (struct ia64_sal_os_state, os_gp));
	DEFINE(IA64_SAL_OS_STATE_PAL_MIN_STATE_OFFSET,
	       offsetof (struct ia64_sal_os_state, pal_min_state));
	DEFINE(IA64_SAL_OS_STATE_PROC_STATE_PARAM_OFFSET,
	       offsetof (struct ia64_sal_os_state, proc_state_param));
	DEFINE(IA64_SAL_OS_STATE_SIZE,
	       sizeof (struct ia64_sal_os_state));
	DEFINE(IA64_PMSA_GR_OFFSET,
	       offsetof (struct pal_min_state_area_s, pmsa_gr));
	DEFINE(IA64_PMSA_BANK1_GR_OFFSET,
	       offsetof (struct pal_min_state_area_s, pmsa_bank1_gr));
	DEFINE(IA64_PMSA_PR_OFFSET,
	       offsetof (struct pal_min_state_area_s, pmsa_pr));
	DEFINE(IA64_PMSA_BR0_OFFSET,
	       offsetof (struct pal_min_state_area_s, pmsa_br0));
	DEFINE(IA64_PMSA_RSC_OFFSET,
	       offsetof (struct pal_min_state_area_s, pmsa_rsc));
	DEFINE(IA64_PMSA_IIP_OFFSET,
	       offsetof (struct pal_min_state_area_s, pmsa_iip));
	DEFINE(IA64_PMSA_IPSR_OFFSET,
	       offsetof (struct pal_min_state_area_s, pmsa_ipsr));
	DEFINE(IA64_PMSA_IFS_OFFSET,
	       offsetof (struct pal_min_state_area_s, pmsa_ifs));
	DEFINE(IA64_PMSA_XIP_OFFSET,
	       offsetof (struct pal_min_state_area_s, pmsa_xip));
	BLANK();

	/* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */
	DEFINE(IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET, offsetof (struct time_interpolator, addr));
	DEFINE(IA64_TIME_INTERPOLATOR_SOURCE_OFFSET, offsetof (struct time_interpolator, source));
+505 −316

File changed.

Preview size limit exceeded, changes collapsed.

+718 −640

File changed.

Preview size limit exceeded, changes collapsed.

+17 −20
Original line number Diff line number Diff line
@@ -4,6 +4,8 @@
 *
 * Copyright (C) 2004 FUJITSU LIMITED
 * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com)
 * Copyright (C) 2005 Silicon Graphics, Inc
 * Copyright (C) 2005 Keith Owens <kaos@sgi.com>
 */
#include <linux/config.h>
#include <linux/types.h>
@@ -38,10 +40,6 @@
/* max size of SAL error record (default) */
static int sal_rec_max = 10000;

/* from mca.c */
static ia64_mca_sal_to_os_state_t *sal_to_os_handoff_state;
static ia64_mca_os_to_sal_state_t *os_to_sal_handoff_state;

/* from mca_drv_asm.S */
extern void *mca_handler_bhhook(void);

@@ -316,7 +314,8 @@ init_record_index_pools(void)
 */

static mca_type_t
is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci)
is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci,
	      struct ia64_sal_os_state *sos)
{
	pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx);

@@ -327,7 +326,7 @@ is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci)
	 * Therefore it is local MCA when rendezvous has not been requested.
	 * Failed to rendezvous, the system must be down.
	 */
	switch (sal_to_os_handoff_state->imsto_rendez_state) {
	switch (sos->rv_rc) {
		case -1: /* SAL rendezvous unsuccessful */
			return MCA_IS_GLOBAL;
		case  0: /* SAL rendezvous not required */
@@ -388,7 +387,8 @@ is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci)
 */

static int
recover_from_read_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci)
recover_from_read_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci,
			struct ia64_sal_os_state *sos)
{
	sal_log_mod_error_info_t *smei;
	pal_min_state_area_t *pmsa;
@@ -426,7 +426,7 @@ recover_from_read_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_chec
			 *  setup for resume to bottom half of MCA,
			 * "mca_handler_bhhook"
			 */
			pmsa = (pal_min_state_area_t *)(sal_to_os_handoff_state->pal_min_state | (6ul<<61));
			pmsa = sos->pal_min_state;
			/* pass to bhhook as 1st argument (gr8) */
			pmsa->pmsa_gr[8-1] = smei->target_identifier;
			/* set interrupted return address (but no use) */
@@ -459,7 +459,8 @@ recover_from_read_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_chec
 */

static int
recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci)
recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci,
			    struct ia64_sal_os_state *sos)
{
	int status = 0;
	pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx);
@@ -469,7 +470,7 @@ recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_
		case 1: /* partial read */
		case 3: /* full line(cpu) read */
		case 9: /* I/O space read */
			status = recover_from_read_error(slidx, peidx, pbci);
			status = recover_from_read_error(slidx, peidx, pbci, sos);
			break;
		case 0: /* unknown */
		case 2: /* partial write */
@@ -508,7 +509,8 @@ recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_
 */

static int
recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci)
recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci,
			     struct ia64_sal_os_state *sos)
{
	pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx);

@@ -545,7 +547,7 @@ recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t *
	 * This means "there are some platform errors".
	 */
	if (platform) 
		return recover_from_platform_error(slidx, peidx, pbci);
		return recover_from_platform_error(slidx, peidx, pbci, sos);
	/* 
	 * On account of strange SAL error record, we cannot recover. 
	 */
@@ -562,8 +564,7 @@ recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t *

static int
mca_try_to_recover(void *rec, 
	ia64_mca_sal_to_os_state_t *sal_to_os_state,
	ia64_mca_os_to_sal_state_t *os_to_sal_state)
	struct ia64_sal_os_state *sos)
{
	int platform_err;
	int n_proc_err;
@@ -571,10 +572,6 @@ mca_try_to_recover(void *rec,
	peidx_table_t peidx;
	pal_bus_check_info_t pbci;

	/* handoff state from/to mca.c */
	sal_to_os_handoff_state = sal_to_os_state;
	os_to_sal_handoff_state = os_to_sal_state;

	/* Make index of SAL error record */
	platform_err = mca_make_slidx(rec, &slidx);

@@ -597,11 +594,11 @@ mca_try_to_recover(void *rec,
	*((u64*)&pbci) = peidx_check_info(&peidx, bus_check, 0);

	/* Check whether MCA is global or not */
	if (is_mca_global(&peidx, &pbci))
	if (is_mca_global(&peidx, &pbci, sos))
		return 0;
	
	/* Try to recover a processor error */
	return recover_from_processor_error(platform_err, &slidx, &peidx, &pbci);
	return recover_from_processor_error(platform_err, &slidx, &peidx, &pbci, sos);
}

/*
+64 −38
Original line number Diff line number Diff line
@@ -11,8 +11,6 @@
#ifndef _ASM_IA64_MCA_H
#define _ASM_IA64_MCA_H

#define IA64_MCA_STACK_SIZE	8192

#if !defined(__ASSEMBLY__)

#include <linux/interrupt.h>
@@ -48,7 +46,8 @@ typedef union cmcv_reg_u {

enum {
	IA64_MCA_RENDEZ_CHECKIN_NOTDONE	=	0x0,
	IA64_MCA_RENDEZ_CHECKIN_DONE	=	0x1
	IA64_MCA_RENDEZ_CHECKIN_DONE	=	0x1,
	IA64_MCA_RENDEZ_CHECKIN_INIT	=	0x2,
};

/* Information maintained by the MC infrastructure */
@@ -63,18 +62,42 @@ typedef struct ia64_mc_info_s {

} ia64_mc_info_t;

typedef struct ia64_mca_sal_to_os_state_s {
	u64		imsto_os_gp;		/* GP of the os registered with the SAL */
	u64		imsto_pal_proc;		/* PAL_PROC entry point - physical addr */
	u64		imsto_sal_proc;		/* SAL_PROC entry point - physical addr */
	u64		imsto_sal_gp;		/* GP of the SAL - physical */
	u64		imsto_rendez_state;	/* Rendez state information */
	u64		imsto_sal_check_ra;	/* Return address in SAL_CHECK while going
						 * back to SAL from OS after MCA handling.
/* Handover state from SAL to OS and vice versa, for both MCA and INIT events.
 * Besides the handover state, it also contains some saved registers from the
 * time of the event.
 * Note: mca_asm.S depends on the precise layout of this structure.
 */

struct ia64_sal_os_state {
	/* SAL to OS, must be at offset 0 */
	u64			os_gp;			/* GP of the os registered with the SAL, physical */
	u64			pal_proc;		/* PAL_PROC entry point, physical */
	u64			sal_proc;		/* SAL_PROC entry point, physical */
	u64			rv_rc;			/* MCA - Rendezvous state, INIT - reason code */
	u64			proc_state_param;	/* from R18 */
	u64			monarch;		/* 1 for a monarch event, 0 for a slave */
	/* common, must follow SAL to OS */
	u64			sal_ra;			/* Return address in SAL, physical */
	u64			sal_gp;			/* GP of the SAL - physical */
	pal_min_state_area_t	*pal_min_state;		/* from R17.  physical in asm, virtual in C */
	u64			prev_IA64_KR_CURRENT;	/* previous value of IA64_KR(CURRENT) */
	struct task_struct	*prev_task;		/* previous task, NULL if it is not useful */
	/* Some interrupt registers are not saved in minstate, pt_regs or
	 * switch_stack.  Because MCA/INIT can occur when interrupts are
	 * disabled, we need to save the additional interrupt registers over
	 * MCA/INIT and resume.
	 */
	u64		pal_min_state;		/* from PAL in r17 */
	u64		proc_state_param;	/* from PAL in r18. See SDV 2:268 11.3.2.1 */
} ia64_mca_sal_to_os_state_t;
	u64			isr;
	u64			ifa;
	u64			itir;
	u64			iipa;
	u64			iim;
	u64			iha;
	/* OS to SAL, must follow common */
	u64			os_status;		/* OS status to SAL, enum below */
	u64			context;		/* 0 if return to same context
							   1 if return to new context */
};

enum {
	IA64_MCA_CORRECTED	=	0x0,	/* Error has been corrected by OS_MCA */
@@ -83,36 +106,22 @@ enum {
	IA64_MCA_HALT		=	-3	/* System to be halted by SAL */
};

enum {
	IA64_INIT_RESUME	=	0x0,	/* Resume after return from INIT */
	IA64_INIT_WARM_BOOT	=	-1,	/* Warm boot of the system need from SAL */
};

enum {
	IA64_MCA_SAME_CONTEXT	=	0x0,	/* SAL to return to same context */
	IA64_MCA_NEW_CONTEXT	=	-1	/* SAL to return to new context */
};

typedef struct ia64_mca_os_to_sal_state_s {
	u64		imots_os_status;	/*   OS status to SAL as to what happened
						 *   with the MCA handling.
						 */
	u64		imots_sal_gp;		/* GP of the SAL - physical */
	u64		imots_context;		/* 0 if return to same context
						   1 if return to new context */
	u64		*imots_new_min_state;	/* Pointer to structure containing
						 * new values of registers in the min state
						 * save area.
						 */
	u64		imots_sal_check_ra;	/* Return address in SAL_CHECK while going
						 * back to SAL from OS after MCA handling.
						 */
} ia64_mca_os_to_sal_state_t;

/* Per-CPU MCA state that is too big for normal per-CPU variables.  */

struct ia64_mca_cpu {
	u64 stack[IA64_MCA_STACK_SIZE/8];	/* MCA memory-stack */
	u64 proc_state_dump[512];
	u64 stackframe[32];
	u64 rbstore[IA64_MCA_STACK_SIZE/8];	/* MCA reg.-backing store */
	u64 mca_stack[KERNEL_STACK_SIZE/8];
	u64 init_stack[KERNEL_STACK_SIZE/8];
} __attribute__ ((aligned(16)));
};

/* Array of physical addresses of each CPU's MCA area.  */
extern unsigned long __per_cpu_mca[NR_CPUS];
@@ -121,12 +130,29 @@ extern void ia64_mca_init(void);
extern void ia64_mca_cpu_init(void *);
extern void ia64_os_mca_dispatch(void);
extern void ia64_os_mca_dispatch_end(void);
extern void ia64_mca_ucmc_handler(void);
extern void ia64_mca_ucmc_handler(struct pt_regs *, struct ia64_sal_os_state *);
extern void ia64_init_handler(struct pt_regs *,
			      struct switch_stack *,
			      struct ia64_sal_os_state *);
extern void ia64_monarch_init_handler(void);
extern void ia64_slave_init_handler(void);
extern void ia64_mca_cmc_vector_setup(void);
extern int  ia64_reg_MCA_extension(void*);
extern int  ia64_reg_MCA_extension(int (*fn)(void *, struct ia64_sal_os_state *));
extern void ia64_unreg_MCA_extension(void);
extern u64 ia64_get_rnat(u64 *);

#else	/* __ASSEMBLY__ */

#define IA64_MCA_CORRECTED	0x0	/* Error has been corrected by OS_MCA */
#define IA64_MCA_WARM_BOOT	-1	/* Warm boot of the system need from SAL */
#define IA64_MCA_COLD_BOOT	-2	/* Cold boot of the system need from SAL */
#define IA64_MCA_HALT		-3	/* System to be halted by SAL */

#define IA64_INIT_RESUME	0x0	/* Resume after return from INIT */
#define IA64_INIT_WARM_BOOT	-1	/* Warm boot of the system need from SAL */

#define IA64_MCA_SAME_CONTEXT	0x0	/* SAL to return to same context */
#define IA64_MCA_NEW_CONTEXT	-1	/* SAL to return to new context */

#endif /* !__ASSEMBLY__ */
#endif /* _ASM_IA64_MCA_H */
Loading