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

Commit fb5fe0fd authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull some more powerpc fixes from Michael Ellerman:
 "The main item is the addition of the Power9 Machine Check handler.
  This was delayed to make sure some details were correct, and is as
  minimal as possible.

  The rest is small fixes, two for the Power9 PMU, two dealing with
  obscure toolchain problems, two for the PowerNV IOMMU code (used by
  VFIO), and one to fix a crash on 32-bit machines with macio devices
  due to missing dma_ops.

  Thanks to:
    Alexey Kardashevskiy, Cyril Bur, Larry Finger, Madhavan Srinivasan,
    Nicholas Piggin"

* tag 'powerpc-4.11-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
  powerpc/64s: POWER9 machine check handler
  powerpc/64s: allow machine check handler to set severity and initiator
  powerpc/64s: fix handling of non-synchronous machine checks
  powerpc/pmac: Fix crash in dma-mapping.h with NULL dma_ops
  powerpc/powernv/ioda2: Update iommu table base on ownership change
  powerpc/powernv/ioda2: Gracefully fail if too many TCE levels requested
  selftests/powerpc: Replace stxvx and lxvx with stxvd2x/lxvd2x
  powerpc/perf: Handle sdar_mode for marked event in power9
  powerpc/perf: Fix perf_get_data_addr() for power9 DD1
  powerpc/boot: Fix zImage TOC alignment
parents 065f3e49 7b9f71f9
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -68,6 +68,7 @@ SECTIONS
  }
  }


#ifdef CONFIG_PPC64_BOOT_WRAPPER
#ifdef CONFIG_PPC64_BOOT_WRAPPER
  . = ALIGN(256);
  .got :
  .got :
  {
  {
    __toc_start = .;
    __toc_start = .;
+4 −0
Original line number Original line Diff line number Diff line
@@ -51,6 +51,10 @@
#define PPC_BIT(bit)		(1UL << PPC_BITLSHIFT(bit))
#define PPC_BIT(bit)		(1UL << PPC_BITLSHIFT(bit))
#define PPC_BITMASK(bs, be)	((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
#define PPC_BITMASK(bs, be)	((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))


/* Put a PPC bit into a "normal" bit position */
#define PPC_BITEXTRACT(bits, ppc_bit, dst_bit)			\
	((((bits) >> PPC_BITLSHIFT(ppc_bit)) & 1) << (dst_bit))

#include <asm/barrier.h>
#include <asm/barrier.h>


/* Macro for generating the ***_bits() functions */
/* Macro for generating the ***_bits() functions */
+107 −1
Original line number Original line Diff line number Diff line
@@ -66,6 +66,55 @@


#define P8_DSISR_MC_SLB_ERRORS		(P7_DSISR_MC_SLB_ERRORS | \
#define P8_DSISR_MC_SLB_ERRORS		(P7_DSISR_MC_SLB_ERRORS | \
					 P8_DSISR_MC_ERAT_MULTIHIT_SEC)
					 P8_DSISR_MC_ERAT_MULTIHIT_SEC)

/*
 * Machine Check bits on power9
 */
#define P9_SRR1_MC_LOADSTORE(srr1)	(((srr1) >> PPC_BITLSHIFT(42)) & 1)

#define P9_SRR1_MC_IFETCH(srr1)	(	\
	PPC_BITEXTRACT(srr1, 45, 0) |	\
	PPC_BITEXTRACT(srr1, 44, 1) |	\
	PPC_BITEXTRACT(srr1, 43, 2) |	\
	PPC_BITEXTRACT(srr1, 36, 3) )

/* 0 is reserved */
#define P9_SRR1_MC_IFETCH_UE				1
#define P9_SRR1_MC_IFETCH_SLB_PARITY			2
#define P9_SRR1_MC_IFETCH_SLB_MULTIHIT			3
#define P9_SRR1_MC_IFETCH_ERAT_MULTIHIT			4
#define P9_SRR1_MC_IFETCH_TLB_MULTIHIT			5
#define P9_SRR1_MC_IFETCH_UE_TLB_RELOAD			6
/* 7 is reserved */
#define P9_SRR1_MC_IFETCH_LINK_TIMEOUT			8
#define P9_SRR1_MC_IFETCH_LINK_TABLEWALK_TIMEOUT	9
/* 10 ? */
#define P9_SRR1_MC_IFETCH_RA			11
#define P9_SRR1_MC_IFETCH_RA_TABLEWALK		12
#define P9_SRR1_MC_IFETCH_RA_ASYNC_STORE		13
#define P9_SRR1_MC_IFETCH_LINK_ASYNC_STORE_TIMEOUT	14
#define P9_SRR1_MC_IFETCH_RA_TABLEWALK_FOREIGN	15

/* DSISR bits for machine check (On Power9) */
#define P9_DSISR_MC_UE					(PPC_BIT(48))
#define P9_DSISR_MC_UE_TABLEWALK			(PPC_BIT(49))
#define P9_DSISR_MC_LINK_LOAD_TIMEOUT			(PPC_BIT(50))
#define P9_DSISR_MC_LINK_TABLEWALK_TIMEOUT		(PPC_BIT(51))
#define P9_DSISR_MC_ERAT_MULTIHIT			(PPC_BIT(52))
#define P9_DSISR_MC_TLB_MULTIHIT_MFTLB			(PPC_BIT(53))
#define P9_DSISR_MC_USER_TLBIE				(PPC_BIT(54))
#define P9_DSISR_MC_SLB_PARITY_MFSLB			(PPC_BIT(55))
#define P9_DSISR_MC_SLB_MULTIHIT_MFSLB			(PPC_BIT(56))
#define P9_DSISR_MC_RA_LOAD				(PPC_BIT(57))
#define P9_DSISR_MC_RA_TABLEWALK			(PPC_BIT(58))
#define P9_DSISR_MC_RA_TABLEWALK_FOREIGN		(PPC_BIT(59))
#define P9_DSISR_MC_RA_FOREIGN				(PPC_BIT(60))

/* SLB error bits */
#define P9_DSISR_MC_SLB_ERRORS		(P9_DSISR_MC_ERAT_MULTIHIT | \
					 P9_DSISR_MC_SLB_PARITY_MFSLB | \
					 P9_DSISR_MC_SLB_MULTIHIT_MFSLB)

enum MCE_Version {
enum MCE_Version {
	MCE_V1 = 1,
	MCE_V1 = 1,
};
};
@@ -93,6 +142,9 @@ enum MCE_ErrorType {
	MCE_ERROR_TYPE_SLB = 2,
	MCE_ERROR_TYPE_SLB = 2,
	MCE_ERROR_TYPE_ERAT = 3,
	MCE_ERROR_TYPE_ERAT = 3,
	MCE_ERROR_TYPE_TLB = 4,
	MCE_ERROR_TYPE_TLB = 4,
	MCE_ERROR_TYPE_USER = 5,
	MCE_ERROR_TYPE_RA = 6,
	MCE_ERROR_TYPE_LINK = 7,
};
};


enum MCE_UeErrorType {
enum MCE_UeErrorType {
@@ -121,6 +173,32 @@ enum MCE_TlbErrorType {
	MCE_TLB_ERROR_MULTIHIT = 2,
	MCE_TLB_ERROR_MULTIHIT = 2,
};
};


enum MCE_UserErrorType {
	MCE_USER_ERROR_INDETERMINATE = 0,
	MCE_USER_ERROR_TLBIE = 1,
};

enum MCE_RaErrorType {
	MCE_RA_ERROR_INDETERMINATE = 0,
	MCE_RA_ERROR_IFETCH = 1,
	MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH = 2,
	MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN = 3,
	MCE_RA_ERROR_LOAD = 4,
	MCE_RA_ERROR_STORE = 5,
	MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE = 6,
	MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN = 7,
	MCE_RA_ERROR_LOAD_STORE_FOREIGN = 8,
};

enum MCE_LinkErrorType {
	MCE_LINK_ERROR_INDETERMINATE = 0,
	MCE_LINK_ERROR_IFETCH_TIMEOUT = 1,
	MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT = 2,
	MCE_LINK_ERROR_LOAD_TIMEOUT = 3,
	MCE_LINK_ERROR_STORE_TIMEOUT = 4,
	MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT = 5,
};

struct machine_check_event {
struct machine_check_event {
	enum MCE_Version	version:8;	/* 0x00 */
	enum MCE_Version	version:8;	/* 0x00 */
	uint8_t			in_use;		/* 0x01 */
	uint8_t			in_use;		/* 0x01 */
@@ -166,6 +244,30 @@ struct machine_check_event {
			uint64_t	effective_address;
			uint64_t	effective_address;
			uint8_t		reserved_2[16];
			uint8_t		reserved_2[16];
		} tlb_error;
		} tlb_error;

		struct {
			enum MCE_UserErrorType user_error_type:8;
			uint8_t		effective_address_provided;
			uint8_t		reserved_1[6];
			uint64_t	effective_address;
			uint8_t		reserved_2[16];
		} user_error;

		struct {
			enum MCE_RaErrorType ra_error_type:8;
			uint8_t		effective_address_provided;
			uint8_t		reserved_1[6];
			uint64_t	effective_address;
			uint8_t		reserved_2[16];
		} ra_error;

		struct {
			enum MCE_LinkErrorType link_error_type:8;
			uint8_t		effective_address_provided;
			uint8_t		reserved_1[6];
			uint64_t	effective_address;
			uint8_t		reserved_2[16];
		} link_error;
	} u;
	} u;
};
};


@@ -176,8 +278,12 @@ struct mce_error_info {
		enum MCE_SlbErrorType slb_error_type:8;
		enum MCE_SlbErrorType slb_error_type:8;
		enum MCE_EratErrorType erat_error_type:8;
		enum MCE_EratErrorType erat_error_type:8;
		enum MCE_TlbErrorType tlb_error_type:8;
		enum MCE_TlbErrorType tlb_error_type:8;
		enum MCE_UserErrorType user_error_type:8;
		enum MCE_RaErrorType ra_error_type:8;
		enum MCE_LinkErrorType link_error_type:8;
	} u;
	} u;
	uint8_t		reserved[2];
	enum MCE_Severity	severity:8;
	enum MCE_Initiator	initiator:8;
};
};


#define MAX_MC_EVT	100
#define MAX_MC_EVT	100
+3 −0
Original line number Original line Diff line number Diff line
@@ -77,6 +77,7 @@ extern void __flush_tlb_power8(unsigned int action);
extern void __flush_tlb_power9(unsigned int action);
extern void __flush_tlb_power9(unsigned int action);
extern long __machine_check_early_realmode_p7(struct pt_regs *regs);
extern long __machine_check_early_realmode_p7(struct pt_regs *regs);
extern long __machine_check_early_realmode_p8(struct pt_regs *regs);
extern long __machine_check_early_realmode_p8(struct pt_regs *regs);
extern long __machine_check_early_realmode_p9(struct pt_regs *regs);
#endif /* CONFIG_PPC64 */
#endif /* CONFIG_PPC64 */
#if defined(CONFIG_E500)
#if defined(CONFIG_E500)
extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec);
@@ -540,6 +541,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
		.cpu_setup		= __setup_cpu_power9,
		.cpu_setup		= __setup_cpu_power9,
		.cpu_restore		= __restore_cpu_power9,
		.cpu_restore		= __restore_cpu_power9,
		.flush_tlb		= __flush_tlb_power9,
		.flush_tlb		= __flush_tlb_power9,
		.machine_check_early	= __machine_check_early_realmode_p9,
		.platform		= "power9",
		.platform		= "power9",
	},
	},
	{	/* Power9 */
	{	/* Power9 */
@@ -559,6 +561,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
		.cpu_setup		= __setup_cpu_power9,
		.cpu_setup		= __setup_cpu_power9,
		.cpu_restore		= __restore_cpu_power9,
		.cpu_restore		= __restore_cpu_power9,
		.flush_tlb		= __flush_tlb_power9,
		.flush_tlb		= __flush_tlb_power9,
		.machine_check_early	= __machine_check_early_realmode_p9,
		.platform		= "power9",
		.platform		= "power9",
	},
	},
	{	/* Cell Broadband Engine */
	{	/* Cell Broadband Engine */
+86 −2
Original line number Original line Diff line number Diff line
@@ -58,6 +58,15 @@ static void mce_set_error_info(struct machine_check_event *mce,
	case MCE_ERROR_TYPE_TLB:
	case MCE_ERROR_TYPE_TLB:
		mce->u.tlb_error.tlb_error_type = mce_err->u.tlb_error_type;
		mce->u.tlb_error.tlb_error_type = mce_err->u.tlb_error_type;
		break;
		break;
	case MCE_ERROR_TYPE_USER:
		mce->u.user_error.user_error_type = mce_err->u.user_error_type;
		break;
	case MCE_ERROR_TYPE_RA:
		mce->u.ra_error.ra_error_type = mce_err->u.ra_error_type;
		break;
	case MCE_ERROR_TYPE_LINK:
		mce->u.link_error.link_error_type = mce_err->u.link_error_type;
		break;
	case MCE_ERROR_TYPE_UNKNOWN:
	case MCE_ERROR_TYPE_UNKNOWN:
	default:
	default:
		break;
		break;
@@ -90,13 +99,14 @@ void save_mce_event(struct pt_regs *regs, long handled,
	mce->gpr3 = regs->gpr[3];
	mce->gpr3 = regs->gpr[3];
	mce->in_use = 1;
	mce->in_use = 1;


	mce->initiator = MCE_INITIATOR_CPU;
	/* Mark it recovered if we have handled it and MSR(RI=1). */
	/* Mark it recovered if we have handled it and MSR(RI=1). */
	if (handled && (regs->msr & MSR_RI))
	if (handled && (regs->msr & MSR_RI))
		mce->disposition = MCE_DISPOSITION_RECOVERED;
		mce->disposition = MCE_DISPOSITION_RECOVERED;
	else
	else
		mce->disposition = MCE_DISPOSITION_NOT_RECOVERED;
		mce->disposition = MCE_DISPOSITION_NOT_RECOVERED;
	mce->severity = MCE_SEV_ERROR_SYNC;

	mce->initiator = mce_err->initiator;
	mce->severity = mce_err->severity;


	/*
	/*
	 * Populate the mce error_type and type-specific error_type.
	 * Populate the mce error_type and type-specific error_type.
@@ -115,6 +125,15 @@ void save_mce_event(struct pt_regs *regs, long handled,
	} else if (mce->error_type == MCE_ERROR_TYPE_ERAT) {
	} else if (mce->error_type == MCE_ERROR_TYPE_ERAT) {
		mce->u.erat_error.effective_address_provided = true;
		mce->u.erat_error.effective_address_provided = true;
		mce->u.erat_error.effective_address = addr;
		mce->u.erat_error.effective_address = addr;
	} else if (mce->error_type == MCE_ERROR_TYPE_USER) {
		mce->u.user_error.effective_address_provided = true;
		mce->u.user_error.effective_address = addr;
	} else if (mce->error_type == MCE_ERROR_TYPE_RA) {
		mce->u.ra_error.effective_address_provided = true;
		mce->u.ra_error.effective_address = addr;
	} else if (mce->error_type == MCE_ERROR_TYPE_LINK) {
		mce->u.link_error.effective_address_provided = true;
		mce->u.link_error.effective_address = addr;
	} else if (mce->error_type == MCE_ERROR_TYPE_UE) {
	} else if (mce->error_type == MCE_ERROR_TYPE_UE) {
		mce->u.ue_error.effective_address_provided = true;
		mce->u.ue_error.effective_address_provided = true;
		mce->u.ue_error.effective_address = addr;
		mce->u.ue_error.effective_address = addr;
@@ -239,6 +258,29 @@ void machine_check_print_event_info(struct machine_check_event *evt)
		"Parity",
		"Parity",
		"Multihit",
		"Multihit",
	};
	};
	static const char *mc_user_types[] = {
		"Indeterminate",
		"tlbie(l) invalid",
	};
	static const char *mc_ra_types[] = {
		"Indeterminate",
		"Instruction fetch (bad)",
		"Page table walk ifetch (bad)",
		"Page table walk ifetch (foreign)",
		"Load (bad)",
		"Store (bad)",
		"Page table walk Load/Store (bad)",
		"Page table walk Load/Store (foreign)",
		"Load/Store (foreign)",
	};
	static const char *mc_link_types[] = {
		"Indeterminate",
		"Instruction fetch (timeout)",
		"Page table walk ifetch (timeout)",
		"Load (timeout)",
		"Store (timeout)",
		"Page table walk Load/Store (timeout)",
	};


	/* Print things out */
	/* Print things out */
	if (evt->version != MCE_V1) {
	if (evt->version != MCE_V1) {
@@ -315,6 +357,36 @@ void machine_check_print_event_info(struct machine_check_event *evt)
			printk("%s    Effective address: %016llx\n",
			printk("%s    Effective address: %016llx\n",
			       level, evt->u.tlb_error.effective_address);
			       level, evt->u.tlb_error.effective_address);
		break;
		break;
	case MCE_ERROR_TYPE_USER:
		subtype = evt->u.user_error.user_error_type <
			ARRAY_SIZE(mc_user_types) ?
			mc_user_types[evt->u.user_error.user_error_type]
			: "Unknown";
		printk("%s  Error type: User [%s]\n", level, subtype);
		if (evt->u.user_error.effective_address_provided)
			printk("%s    Effective address: %016llx\n",
			       level, evt->u.user_error.effective_address);
		break;
	case MCE_ERROR_TYPE_RA:
		subtype = evt->u.ra_error.ra_error_type <
			ARRAY_SIZE(mc_ra_types) ?
			mc_ra_types[evt->u.ra_error.ra_error_type]
			: "Unknown";
		printk("%s  Error type: Real address [%s]\n", level, subtype);
		if (evt->u.ra_error.effective_address_provided)
			printk("%s    Effective address: %016llx\n",
			       level, evt->u.ra_error.effective_address);
		break;
	case MCE_ERROR_TYPE_LINK:
		subtype = evt->u.link_error.link_error_type <
			ARRAY_SIZE(mc_link_types) ?
			mc_link_types[evt->u.link_error.link_error_type]
			: "Unknown";
		printk("%s  Error type: Link [%s]\n", level, subtype);
		if (evt->u.link_error.effective_address_provided)
			printk("%s    Effective address: %016llx\n",
			       level, evt->u.link_error.effective_address);
		break;
	default:
	default:
	case MCE_ERROR_TYPE_UNKNOWN:
	case MCE_ERROR_TYPE_UNKNOWN:
		printk("%s  Error type: Unknown\n", level);
		printk("%s  Error type: Unknown\n", level);
@@ -341,6 +413,18 @@ uint64_t get_mce_fault_addr(struct machine_check_event *evt)
		if (evt->u.tlb_error.effective_address_provided)
		if (evt->u.tlb_error.effective_address_provided)
			return evt->u.tlb_error.effective_address;
			return evt->u.tlb_error.effective_address;
		break;
		break;
	case MCE_ERROR_TYPE_USER:
		if (evt->u.user_error.effective_address_provided)
			return evt->u.user_error.effective_address;
		break;
	case MCE_ERROR_TYPE_RA:
		if (evt->u.ra_error.effective_address_provided)
			return evt->u.ra_error.effective_address;
		break;
	case MCE_ERROR_TYPE_LINK:
		if (evt->u.link_error.effective_address_provided)
			return evt->u.link_error.effective_address;
		break;
	default:
	default:
	case MCE_ERROR_TYPE_UNKNOWN:
	case MCE_ERROR_TYPE_UNKNOWN:
		break;
		break;
Loading