static int mce_handle_err_virtmode()

in platforms/pseries/ras.c [556:713]


static int mce_handle_err_virtmode(struct pt_regs *regs,
				   struct rtas_error_log *errp,
				   struct pseries_mc_errorlog *mce_log,
				   int disposition)
{
	struct mce_error_info mce_err = { 0 };
	int initiator = rtas_error_initiator(errp);
	int severity = rtas_error_severity(errp);
	unsigned long eaddr = 0, paddr = 0;
	u8 error_type, err_sub_type;

	if (!mce_log)
		goto out;

	error_type = mce_log->error_type;
	err_sub_type = rtas_mc_error_sub_type(mce_log);

	if (initiator == RTAS_INITIATOR_UNKNOWN)
		mce_err.initiator = MCE_INITIATOR_UNKNOWN;
	else if (initiator == RTAS_INITIATOR_CPU)
		mce_err.initiator = MCE_INITIATOR_CPU;
	else if (initiator == RTAS_INITIATOR_PCI)
		mce_err.initiator = MCE_INITIATOR_PCI;
	else if (initiator == RTAS_INITIATOR_ISA)
		mce_err.initiator = MCE_INITIATOR_ISA;
	else if (initiator == RTAS_INITIATOR_MEMORY)
		mce_err.initiator = MCE_INITIATOR_MEMORY;
	else if (initiator == RTAS_INITIATOR_POWERMGM)
		mce_err.initiator = MCE_INITIATOR_POWERMGM;
	else
		mce_err.initiator = MCE_INITIATOR_UNKNOWN;

	if (severity == RTAS_SEVERITY_NO_ERROR)
		mce_err.severity = MCE_SEV_NO_ERROR;
	else if (severity == RTAS_SEVERITY_EVENT)
		mce_err.severity = MCE_SEV_WARNING;
	else if (severity == RTAS_SEVERITY_WARNING)
		mce_err.severity = MCE_SEV_WARNING;
	else if (severity == RTAS_SEVERITY_ERROR_SYNC)
		mce_err.severity = MCE_SEV_SEVERE;
	else if (severity == RTAS_SEVERITY_ERROR)
		mce_err.severity = MCE_SEV_SEVERE;
	else
		mce_err.severity = MCE_SEV_FATAL;

	if (severity <= RTAS_SEVERITY_ERROR_SYNC)
		mce_err.sync_error = true;
	else
		mce_err.sync_error = false;

	mce_err.error_type = MCE_ERROR_TYPE_UNKNOWN;
	mce_err.error_class = MCE_ECLASS_UNKNOWN;

	switch (error_type) {
	case MC_ERROR_TYPE_UE:
		mce_err.error_type = MCE_ERROR_TYPE_UE;
		mce_common_process_ue(regs, &mce_err);
		if (mce_err.ignore_event)
			disposition = RTAS_DISP_FULLY_RECOVERED;
		switch (err_sub_type) {
		case MC_ERROR_UE_IFETCH:
			mce_err.u.ue_error_type = MCE_UE_ERROR_IFETCH;
			break;
		case MC_ERROR_UE_PAGE_TABLE_WALK_IFETCH:
			mce_err.u.ue_error_type = MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH;
			break;
		case MC_ERROR_UE_LOAD_STORE:
			mce_err.u.ue_error_type = MCE_UE_ERROR_LOAD_STORE;
			break;
		case MC_ERROR_UE_PAGE_TABLE_WALK_LOAD_STORE:
			mce_err.u.ue_error_type = MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE;
			break;
		case MC_ERROR_UE_INDETERMINATE:
		default:
			mce_err.u.ue_error_type = MCE_UE_ERROR_INDETERMINATE;
			break;
		}
		if (mce_log->sub_err_type & UE_EFFECTIVE_ADDR_PROVIDED)
			eaddr = be64_to_cpu(mce_log->effective_address);

		if (mce_log->sub_err_type & UE_LOGICAL_ADDR_PROVIDED) {
			paddr = be64_to_cpu(mce_log->logical_address);
		} else if (mce_log->sub_err_type & UE_EFFECTIVE_ADDR_PROVIDED) {
			unsigned long pfn;

			pfn = addr_to_pfn(regs, eaddr);
			if (pfn != ULONG_MAX)
				paddr = pfn << PAGE_SHIFT;
		}

		break;
	case MC_ERROR_TYPE_SLB:
		mce_err.error_type = MCE_ERROR_TYPE_SLB;
		switch (err_sub_type) {
		case MC_ERROR_SLB_PARITY:
			mce_err.u.slb_error_type = MCE_SLB_ERROR_PARITY;
			break;
		case MC_ERROR_SLB_MULTIHIT:
			mce_err.u.slb_error_type = MCE_SLB_ERROR_MULTIHIT;
			break;
		case MC_ERROR_SLB_INDETERMINATE:
		default:
			mce_err.u.slb_error_type = MCE_SLB_ERROR_INDETERMINATE;
			break;
		}
		if (mce_log->sub_err_type & 0x80)
			eaddr = be64_to_cpu(mce_log->effective_address);
		break;
	case MC_ERROR_TYPE_ERAT:
		mce_err.error_type = MCE_ERROR_TYPE_ERAT;
		switch (err_sub_type) {
		case MC_ERROR_ERAT_PARITY:
			mce_err.u.erat_error_type = MCE_ERAT_ERROR_PARITY;
			break;
		case MC_ERROR_ERAT_MULTIHIT:
			mce_err.u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT;
			break;
		case MC_ERROR_ERAT_INDETERMINATE:
		default:
			mce_err.u.erat_error_type = MCE_ERAT_ERROR_INDETERMINATE;
			break;
		}
		if (mce_log->sub_err_type & 0x80)
			eaddr = be64_to_cpu(mce_log->effective_address);
		break;
	case MC_ERROR_TYPE_TLB:
		mce_err.error_type = MCE_ERROR_TYPE_TLB;
		switch (err_sub_type) {
		case MC_ERROR_TLB_PARITY:
			mce_err.u.tlb_error_type = MCE_TLB_ERROR_PARITY;
			break;
		case MC_ERROR_TLB_MULTIHIT:
			mce_err.u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT;
			break;
		case MC_ERROR_TLB_INDETERMINATE:
		default:
			mce_err.u.tlb_error_type = MCE_TLB_ERROR_INDETERMINATE;
			break;
		}
		if (mce_log->sub_err_type & 0x80)
			eaddr = be64_to_cpu(mce_log->effective_address);
		break;
	case MC_ERROR_TYPE_D_CACHE:
		mce_err.error_type = MCE_ERROR_TYPE_DCACHE;
		break;
	case MC_ERROR_TYPE_I_CACHE:
		mce_err.error_type = MCE_ERROR_TYPE_ICACHE;
		break;
	case MC_ERROR_TYPE_UNKNOWN:
	default:
		mce_err.error_type = MCE_ERROR_TYPE_UNKNOWN;
		break;
	}
out:
	save_mce_event(regs, disposition == RTAS_DISP_FULLY_RECOVERED,
		       &mce_err, regs->nip, eaddr, paddr);
	return disposition;
}