File-copy from v4.4.100

This is the result of 'cp' from a linux-stable tree with the 'v4.4.100'
tag checked out (commit 26d6298789e695c9f627ce49a7bbd2286405798a) on
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git

Please refer to that tree for all history prior to this point.

Change-Id: I8a9ee2aea93cd29c52c847d0ce33091a73ae6afe
diff --git a/arch/alpha/oprofile/op_model_ev67.c b/arch/alpha/oprofile/op_model_ev67.c
new file mode 100644
index 0000000..adb1744
--- /dev/null
+++ b/arch/alpha/oprofile/op_model_ev67.c
@@ -0,0 +1,261 @@
+/**
+ * @file arch/alpha/oprofile/op_model_ev67.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Richard Henderson <rth@twiddle.net>
+ * @author Falk Hueffner <falk@debian.org>
+ */
+
+#include <linux/oprofile.h>
+#include <linux/smp.h>
+#include <asm/ptrace.h>
+
+#include "op_impl.h"
+
+
+/* Compute all of the registers in preparation for enabling profiling.  */
+
+static void
+ev67_reg_setup(struct op_register_config *reg,
+	       struct op_counter_config *ctr,
+	       struct op_system_config *sys)
+{
+	unsigned long ctl, reset, need_reset, i;
+
+	/* Select desired events.  */
+	ctl = 1UL << 4;		/* Enable ProfileMe mode. */
+
+	/* The event numbers are chosen so we can use them directly if
+	   PCTR1 is enabled.  */
+	if (ctr[1].enabled) {
+		ctl |= (ctr[1].event & 3) << 2;
+	} else {
+		if (ctr[0].event == 0) /* cycles */
+			ctl |= 1UL << 2;
+	}
+	reg->mux_select = ctl;
+
+	/* Select logging options.  */
+	/* ??? Need to come up with some mechanism to trace only
+	   selected processes.  EV67 does not have a mechanism to
+	   select kernel or user mode only.  For now, enable always.  */
+	reg->proc_mode = 0;
+
+	/* EV67 cannot change the width of the counters as with the
+	   other implementations.  But fortunately, we can write to
+	   the counters and set the value such that it will overflow
+	   at the right time.  */
+	reset = need_reset = 0;
+	for (i = 0; i < 2; ++i) {
+		unsigned long count = ctr[i].count;
+		if (!ctr[i].enabled)
+			continue;
+
+		if (count > 0x100000)
+			count = 0x100000;
+		ctr[i].count = count;
+		reset |= (0x100000 - count) << (i ? 6 : 28);
+		if (count != 0x100000)
+			need_reset |= 1 << i;
+	}
+	reg->reset_values = reset;
+	reg->need_reset = need_reset;
+}
+
+/* Program all of the registers in preparation for enabling profiling.  */
+
+static void
+ev67_cpu_setup (void *x)
+{
+	struct op_register_config *reg = x;
+
+	wrperfmon(2, reg->mux_select);
+	wrperfmon(3, reg->proc_mode);
+	wrperfmon(6, reg->reset_values | 3);
+}
+
+/* CTR is a counter for which the user has requested an interrupt count
+   in between one of the widths selectable in hardware.  Reset the count
+   for CTR to the value stored in REG->RESET_VALUES.  */
+
+static void
+ev67_reset_ctr(struct op_register_config *reg, unsigned long ctr)
+{
+	wrperfmon(6, reg->reset_values | (1 << ctr));
+}
+
+/* ProfileMe conditions which will show up as counters. We can also
+   detect the following, but it seems unlikely that anybody is
+   interested in counting them:
+    * Reset
+    * MT_FPCR (write to floating point control register)
+    * Arithmetic trap
+    * Dstream Fault
+    * Machine Check (ECC fault, etc.)
+    * OPCDEC (illegal opcode)
+    * Floating point disabled
+    * Differentiate between DTB single/double misses and 3 or 4 level
+      page tables
+    * Istream access violation
+    * Interrupt
+    * Icache Parity Error.
+    * Instruction killed (nop, trapb)
+
+   Unfortunately, there seems to be no way to detect Dcache and Bcache
+   misses; the latter could be approximated by making the counter
+   count Bcache misses, but that is not precise.
+
+   We model this as 20 counters:
+    * PCTR0
+    * PCTR1
+    * 9 ProfileMe events, induced by PCTR0
+    * 9 ProfileMe events, induced by PCTR1
+*/
+
+enum profileme_counters {
+	PM_STALLED,		/* Stalled for at least one cycle
+				   between the fetch and map stages  */
+	PM_TAKEN,		/* Conditional branch taken */
+	PM_MISPREDICT,		/* Branch caused mispredict trap */
+	PM_ITB_MISS,		/* ITB miss */
+	PM_DTB_MISS,		/* DTB miss */
+	PM_REPLAY,		/* Replay trap */
+	PM_LOAD_STORE,		/* Load-store order trap */
+	PM_ICACHE_MISS,		/* Icache miss */
+	PM_UNALIGNED,		/* Unaligned Load/Store */
+	PM_NUM_COUNTERS
+};
+
+static inline void
+op_add_pm(unsigned long pc, int kern, unsigned long counter,
+	  struct op_counter_config *ctr, unsigned long event)
+{
+	unsigned long fake_counter = 2 + event;
+	if (counter == 1)
+		fake_counter += PM_NUM_COUNTERS;
+	if (ctr[fake_counter].enabled)
+		oprofile_add_pc(pc, kern, fake_counter);
+}
+
+static void
+ev67_handle_interrupt(unsigned long which, struct pt_regs *regs,
+		      struct op_counter_config *ctr)
+{
+	unsigned long pmpc, pctr_ctl;
+	int kern = !user_mode(regs);
+	int mispredict = 0;
+	union {
+		unsigned long v;
+		struct {
+			unsigned reserved:	30; /*  0-29 */
+			unsigned overcount:	 3; /* 30-32 */
+			unsigned icache_miss:	 1; /*    33 */
+			unsigned trap_type:	 4; /* 34-37 */
+			unsigned load_store:	 1; /*    38 */
+			unsigned trap:		 1; /*    39 */
+			unsigned mispredict:	 1; /*    40 */
+		} fields;
+	} i_stat;
+
+	enum trap_types {
+		TRAP_REPLAY,
+		TRAP_INVALID0,
+		TRAP_DTB_DOUBLE_MISS_3,
+		TRAP_DTB_DOUBLE_MISS_4,
+		TRAP_FP_DISABLED,
+		TRAP_UNALIGNED,
+		TRAP_DTB_SINGLE_MISS,
+		TRAP_DSTREAM_FAULT,
+		TRAP_OPCDEC,
+		TRAP_INVALID1,
+		TRAP_MACHINE_CHECK,
+		TRAP_INVALID2,
+		TRAP_ARITHMETIC,
+		TRAP_INVALID3,
+		TRAP_MT_FPCR,
+		TRAP_RESET
+	};
+
+	pmpc = wrperfmon(9, 0);
+	/* ??? Don't know how to handle physical-mode PALcode address.  */
+	if (pmpc & 1)
+		return;
+	pmpc &= ~2;		/* clear reserved bit */
+
+	i_stat.v = wrperfmon(8, 0);
+	if (i_stat.fields.trap) {
+		switch (i_stat.fields.trap_type) {
+		case TRAP_INVALID1:
+		case TRAP_INVALID2:
+		case TRAP_INVALID3:
+			/* Pipeline redirection occurred. PMPC points
+			   to PALcode. Recognize ITB miss by PALcode
+			   offset address, and get actual PC from
+			   EXC_ADDR.  */
+			oprofile_add_pc(regs->pc, kern, which);
+			if ((pmpc & ((1 << 15) - 1)) ==  581)
+				op_add_pm(regs->pc, kern, which,
+					  ctr, PM_ITB_MISS);
+			/* Most other bit and counter values will be
+			   those for the first instruction in the
+			   fault handler, so we're done.  */
+			return;
+		case TRAP_REPLAY:
+			op_add_pm(pmpc, kern, which, ctr,
+				  (i_stat.fields.load_store
+				   ? PM_LOAD_STORE : PM_REPLAY));
+			break;
+		case TRAP_DTB_DOUBLE_MISS_3:
+		case TRAP_DTB_DOUBLE_MISS_4:
+		case TRAP_DTB_SINGLE_MISS:
+			op_add_pm(pmpc, kern, which, ctr, PM_DTB_MISS);
+			break;
+		case TRAP_UNALIGNED:
+			op_add_pm(pmpc, kern, which, ctr, PM_UNALIGNED);
+			break;
+		case TRAP_INVALID0:
+		case TRAP_FP_DISABLED:
+		case TRAP_DSTREAM_FAULT:
+		case TRAP_OPCDEC:
+		case TRAP_MACHINE_CHECK:
+		case TRAP_ARITHMETIC:
+		case TRAP_MT_FPCR:
+		case TRAP_RESET:
+			break;
+		}
+
+		/* ??? JSR/JMP/RET/COR or HW_JSR/HW_JMP/HW_RET/HW_COR
+		   mispredicts do not set this bit but can be
+		   recognized by the presence of one of these
+		   instructions at the PMPC location with bit 39
+		   set.  */
+		if (i_stat.fields.mispredict) {
+			mispredict = 1;
+			op_add_pm(pmpc, kern, which, ctr, PM_MISPREDICT);
+		}
+	}
+
+	oprofile_add_pc(pmpc, kern, which);
+
+	pctr_ctl = wrperfmon(5, 0);
+	if (pctr_ctl & (1UL << 27))
+		op_add_pm(pmpc, kern, which, ctr, PM_STALLED);
+
+	/* Unfortunately, TAK is undefined on mispredicted branches.
+	   ??? It is also undefined for non-cbranch insns, should
+	   check that.  */
+	if (!mispredict && pctr_ctl & (1UL << 0))
+		op_add_pm(pmpc, kern, which, ctr, PM_TAKEN);
+}
+
+struct op_axp_model op_model_ev67 = {
+	.reg_setup		= ev67_reg_setup,
+	.cpu_setup		= ev67_cpu_setup,
+	.reset_ctr		= ev67_reset_ctr,
+	.handle_interrupt	= ev67_handle_interrupt,
+	.cpu_type		= "alpha/ev67",
+	.num_counters		= 20,
+	.can_set_proc_mode	= 0,
+};