aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/intel_speed_select_if/isst_if_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/intel_speed_select_if/isst_if_common.c')
-rw-r--r--drivers/platform/x86/intel_speed_select_if/isst_if_common.c114
1 files changed, 113 insertions, 1 deletions
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 ab2bb4862dc8..0e16cbf685d0 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
@@ -7,14 +7,22 @@
* Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
*/
+#include <linux/cpufeature.h>
+#include <linux/cpuhotplug.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched/signal.h>
+#include <linux/slab.h>
#include <linux/uaccess.h>
#include <uapi/linux/isst_if.h>
#include "isst_if_common.h"
+#define MSR_THREAD_ID_INFO 0x53
+#define MSR_CPU_BUS_NUMBER 0x128
+
static struct isst_if_cmd_cb punit_callbacks[ISST_IF_DEV_MAX];
static int isst_if_get_platform_info(void __user *argp)
@@ -33,6 +41,99 @@ static int isst_if_get_platform_info(void __user *argp)
return 0;
}
+
+struct isst_if_cpu_info {
+ /* For BUS 0 and BUS 1 only, which we need for PUNIT interface */
+ int bus_info[2];
+ int punit_cpu_id;
+};
+
+static struct isst_if_cpu_info *isst_cpu_info;
+
+/**
+ * isst_if_get_pci_dev() - Get the PCI device instance for a CPU
+ * @cpu: Logical CPU number.
+ * @bus_number: The bus number assigned by the hardware.
+ * @dev: The device number assigned by the hardware.
+ * @fn: The function number assigned by the hardware.
+ *
+ * Using cached bus information, find out the PCI device for a bus number,
+ * device and function.
+ *
+ * Return: Return pci_dev pointer or NULL.
+ */
+struct pci_dev *isst_if_get_pci_dev(int cpu, int bus_no, int dev, int fn)
+{
+ int bus_number;
+
+ if (bus_no < 0 || bus_no > 1 || cpu < 0 || cpu >= nr_cpu_ids ||
+ cpu >= num_possible_cpus())
+ return NULL;
+
+ bus_number = isst_cpu_info[cpu].bus_info[bus_no];
+ if (bus_number < 0)
+ return NULL;
+
+ return pci_get_domain_bus_and_slot(0, bus_number, PCI_DEVFN(dev, fn));
+}
+EXPORT_SYMBOL_GPL(isst_if_get_pci_dev);
+
+static int isst_if_cpu_online(unsigned int cpu)
+{
+ u64 data;
+ int ret;
+
+ ret = rdmsrl_safe(MSR_CPU_BUS_NUMBER, &data);
+ if (ret) {
+ /* This is not a fatal error on MSR mailbox only I/F */
+ isst_cpu_info[cpu].bus_info[0] = -1;
+ isst_cpu_info[cpu].bus_info[1] = -1;
+ } else {
+ isst_cpu_info[cpu].bus_info[0] = data & 0xff;
+ isst_cpu_info[cpu].bus_info[1] = (data >> 8) & 0xff;
+ }
+
+ ret = rdmsrl_safe(MSR_THREAD_ID_INFO, &data);
+ if (ret) {
+ isst_cpu_info[cpu].punit_cpu_id = -1;
+ return ret;
+ }
+ isst_cpu_info[cpu].punit_cpu_id = data;
+
+ return 0;
+}
+
+static int isst_if_online_id;
+
+static int isst_if_cpu_info_init(void)
+{
+ int ret;
+
+ isst_cpu_info = kcalloc(num_possible_cpus(),
+ sizeof(*isst_cpu_info),
+ GFP_KERNEL);
+ if (!isst_cpu_info)
+ return -ENOMEM;
+
+ ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
+ "platform/x86/isst-if:online",
+ isst_if_cpu_online, NULL);
+ if (ret < 0) {
+ kfree(isst_cpu_info);
+ return ret;
+ }
+
+ isst_if_online_id = ret;
+
+ return 0;
+}
+
+static void isst_if_cpu_info_exit(void)
+{
+ cpuhp_remove_state(isst_if_online_id);
+ kfree(isst_cpu_info);
+};
+
static long isst_if_def_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
@@ -145,9 +246,18 @@ int isst_if_cdev_register(int device_type, struct isst_if_cmd_cb *cb)
return -EAGAIN;
}
if (!misc_usage_count) {
+ int ret;
+
misc_device_ret = misc_register(&isst_if_char_driver);
if (misc_device_ret)
goto unlock_exit;
+
+ ret = isst_if_cpu_info_init();
+ if (ret) {
+ misc_deregister(&isst_if_char_driver);
+ misc_device_ret = ret;
+ goto unlock_exit;
+ }
}
memcpy(&punit_callbacks[device_type], cb, sizeof(*cb));
punit_callbacks[device_type].registered = 1;
@@ -173,8 +283,10 @@ void isst_if_cdev_unregister(int device_type)
mutex_lock(&punit_misc_dev_lock);
misc_usage_count--;
punit_callbacks[device_type].registered = 0;
- if (!misc_usage_count && !misc_device_ret)
+ if (!misc_usage_count && !misc_device_ret) {
misc_deregister(&isst_if_char_driver);
+ isst_if_cpu_info_exit();
+ }
mutex_unlock(&punit_misc_dev_lock);
}
EXPORT_SYMBOL_GPL(isst_if_cdev_unregister);