From 30ac231ea740096c5095911fae081481abf7c219 Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Wed, 26 Jun 2019 15:38:49 -0700
Subject: [PATCH 0269/2944] ICX: platform/x86: ISST: Add Intel Speed Select
 PUNIT MSR interface

commit e765f37b9b8b4fa65682e9a78a2ca2b11d3d9096 upstream.

While using new non arhitectural features using PUNIT Mailbox and MMIO
read/write interface, still there is need to operate using MSRs to
control PUNIT. User space could have used user user-space MSR interface for
this, but when user space MSR access is disabled, then it can't. Here only
limited number of MSRs are allowed using this new interface.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Youquan Song <youquan.song@intel.com>
Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
Acked-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Acked-by: Caspar Zhang <caspar@linux.alibaba.com>
---
 .../x86/intel_speed_select_if/isst_if_common.c     | 59 ++++++++++++++++++++++
 include/uapi/linux/isst_if.h                       | 32 ++++++++++++
 2 files changed, 91 insertions(+)

diff --git a/drivers/platform/x86/intel_speed_select_if/isst_if_common.c b/drivers/platform/x86/intel_speed_select_if/isst_if_common.c
index 391fc3f..de2fb52 100644
--- a/drivers/platform/x86/intel_speed_select_if/isst_if_common.c
+++ b/drivers/platform/x86/intel_speed_select_if/isst_if_common.c
@@ -25,6 +25,11 @@
 
 static struct isst_if_cmd_cb punit_callbacks[ISST_IF_DEV_MAX];
 
+static int punit_msr_white_list[] = {
+	MSR_TURBO_RATIO_LIMIT,
+	MSR_CONFIG_TDP_CONTROL,
+};
+
 struct isst_valid_cmd_ranges {
 	u16 cmd;
 	u16 sub_cmd_beg;
@@ -229,6 +234,54 @@ static long isst_if_proc_phyid_req(u8 *cmd_ptr, int *write_only, int resume)
 	return 0;
 }
 
+static bool match_punit_msr_white_list(int msr)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(punit_msr_white_list); ++i) {
+		if (punit_msr_white_list[i] == msr)
+			return true;
+	}
+
+	return false;
+}
+
+static long isst_if_msr_cmd_req(u8 *cmd_ptr, int *write_only, int resume)
+{
+	struct isst_if_msr_cmd *msr_cmd;
+	int ret;
+
+	msr_cmd = (struct isst_if_msr_cmd *)cmd_ptr;
+
+	if (!match_punit_msr_white_list(msr_cmd->msr))
+		return -EINVAL;
+
+	if (msr_cmd->logical_cpu >= nr_cpu_ids)
+		return -EINVAL;
+
+	if (msr_cmd->read_write) {
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
+		ret = wrmsrl_safe_on_cpu(msr_cmd->logical_cpu,
+					 msr_cmd->msr,
+					 msr_cmd->data);
+		*write_only = 1;
+	} else {
+		u64 data;
+
+		ret = rdmsrl_safe_on_cpu(msr_cmd->logical_cpu,
+					 msr_cmd->msr, &data);
+		if (!ret) {
+			msr_cmd->data = data;
+			*write_only = 0;
+		}
+	}
+
+
+	return ret;
+}
+
 static long isst_if_exec_multi_cmd(void __user *argp, struct isst_if_cmd_cb *cb)
 {
 	unsigned char __user *ptr;
@@ -309,6 +362,12 @@ static long isst_if_def_ioctl(struct file *file, unsigned int cmd,
 		if (cb->registered)
 			ret = isst_if_exec_multi_cmd(argp, cb);
 		break;
+	case ISST_IF_MSR_COMMAND:
+		cmd_cb.cmd_size = sizeof(struct isst_if_msr_cmd);
+		cmd_cb.offset = offsetof(struct isst_if_msr_cmds, msr_cmd);
+		cmd_cb.cmd_callback = isst_if_msr_cmd_req;
+		ret = isst_if_exec_multi_cmd(argp, &cmd_cb);
+		break;
 	default:
 		break;
 	}
diff --git a/include/uapi/linux/isst_if.h b/include/uapi/linux/isst_if.h
index e4b1c2e..d10b832 100644
--- a/include/uapi/linux/isst_if.h
+++ b/include/uapi/linux/isst_if.h
@@ -132,9 +132,41 @@ struct isst_if_mbox_cmds {
 	struct isst_if_mbox_cmd mbox_cmd[1];
 };
 
+/**
+ * struct isst_if_msr_cmd - Structure to define msr command
+ * @read_write:		Value 0: Read, 1: Write
+ * @logical_cpu:	Logical CPU number
+ * @msr:		MSR number
+ * @data:		For write operation, data to write, for read
+ *			place holder
+ *
+ * Structure to specify MSR command related to PUNIT.
+ */
+struct isst_if_msr_cmd {
+	__u32 read_write; /* Read:0, Write:1 */
+	__u32 logical_cpu;
+	__u64 msr;
+	__u64 data;
+};
+
+/**
+ * struct isst_if_msr_cmds - structure for msr commands
+ * @cmd_count:	Number of mailbox commands in msr_cmd[]
+ * @msr_cmd[]:	Holds one or more msr commands
+ *
+ * This structure used with ioctl ISST_IF_MSR_COMMAND to send
+ * one or more MSR commands. IOCTL return value indicates number of
+ * commands sent or error number if no commands have been sent.
+ */
+struct isst_if_msr_cmds {
+	__u32 cmd_count;
+	struct isst_if_msr_cmd msr_cmd[1];
+};
+
 #define ISST_IF_MAGIC			0xFE
 #define ISST_IF_GET_PLATFORM_INFO	_IOR(ISST_IF_MAGIC, 0, struct isst_if_platform_info *)
 #define ISST_IF_GET_PHY_ID		_IOWR(ISST_IF_MAGIC, 1, struct isst_if_cpu_map *)
 #define ISST_IF_IO_CMD		_IOW(ISST_IF_MAGIC, 2, struct isst_if_io_regs *)
 #define ISST_IF_MBOX_COMMAND	_IOWR(ISST_IF_MAGIC, 3, struct isst_if_mbox_cmds *)
+#define ISST_IF_MSR_COMMAND	_IOWR(ISST_IF_MAGIC, 4, struct isst_if_msr_cmds *)
 #endif
-- 
1.8.3.1

