823 lines
22 KiB
Plaintext
823 lines
22 KiB
Plaintext
|
From: jbeulich@novell.com
|
||
|
Subject: introduce {rd,wr}msr_safe_on_pcpu() and add/enable users
|
||
|
Patch-mainline: n/a
|
||
|
|
||
|
--- head-2011-03-11.orig/arch/x86/Kconfig 2011-02-02 15:10:34.000000000 +0100
|
||
|
+++ head-2011-03-11/arch/x86/Kconfig 2011-02-03 14:42:26.000000000 +0100
|
||
|
@@ -1048,6 +1048,7 @@ config MICROCODE_OLD_INTERFACE
|
||
|
|
||
|
config X86_MSR
|
||
|
tristate "/dev/cpu/*/msr - Model-specific register support"
|
||
|
+ select XEN_DOMCTL if XEN_PRIVILEGED_GUEST
|
||
|
---help---
|
||
|
This device gives privileged processes access to the x86
|
||
|
Model-Specific Registers (MSRs). It is a character device with
|
||
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
|
+++ head-2011-03-11/arch/x86/kernel/msr-xen.c 2011-02-03 14:42:26.000000000 +0100
|
||
|
@@ -0,0 +1,339 @@
|
||
|
+#ifndef CONFIG_XEN_PRIVILEGED_GUEST
|
||
|
+#include "msr.c"
|
||
|
+#else
|
||
|
+/* ----------------------------------------------------------------------- *
|
||
|
+ *
|
||
|
+ * Copyright 2010 Novell, Inc.
|
||
|
+ *
|
||
|
+ * This program is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License as published by
|
||
|
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
|
||
|
+ * USA; either version 2 of the License, or (at your option) any later
|
||
|
+ * version; incorporated herein by reference.
|
||
|
+ *
|
||
|
+ * ----------------------------------------------------------------------- */
|
||
|
+
|
||
|
+/*
|
||
|
+ * x86 MSR access device
|
||
|
+ *
|
||
|
+ * This device is accessed by lseek() to the appropriate register number
|
||
|
+ * and then read/write in chunks of 8 bytes. A larger size means multiple
|
||
|
+ * reads or writes of the same register.
|
||
|
+ *
|
||
|
+ * This driver uses /dev/xen/cpu/%d/msr where %d correlates to the minor
|
||
|
+ * number, and on an SMP box will direct the access to pCPU %d.
|
||
|
+ */
|
||
|
+
|
||
|
+static int msr_init(void);
|
||
|
+static void msr_exit(void);
|
||
|
+
|
||
|
+#define msr_init(args...) _msr_init(args)
|
||
|
+#define msr_exit(args...) _msr_exit(args)
|
||
|
+#include "msr.c"
|
||
|
+#undef msr_exit
|
||
|
+#undef msr_init
|
||
|
+
|
||
|
+#include <linux/slab.h>
|
||
|
+#include <xen/pcpu.h>
|
||
|
+
|
||
|
+static struct class *pmsr_class;
|
||
|
+static unsigned int minor_bias = 10;
|
||
|
+static unsigned int nr_xen_cpu_ids;
|
||
|
+static unsigned long *xen_cpu_online_map;
|
||
|
+
|
||
|
+#define PMSR_DEV(cpu) MKDEV(MSR_MAJOR, (cpu) + minor_bias)
|
||
|
+
|
||
|
+static unsigned int pmsr_minor(struct inode *inode)
|
||
|
+{
|
||
|
+ return iminor(inode) - minor_bias;
|
||
|
+}
|
||
|
+
|
||
|
+static ssize_t pmsr_read(struct file *file, char __user *buf,
|
||
|
+ size_t count, loff_t *ppos)
|
||
|
+{
|
||
|
+ u32 __user *tmp = (u32 __user *) buf;
|
||
|
+ u32 data[2];
|
||
|
+ u32 reg = *ppos;
|
||
|
+ unsigned int cpu = pmsr_minor(file->f_path.dentry->d_inode);
|
||
|
+ int err = 0;
|
||
|
+ ssize_t bytes = 0;
|
||
|
+
|
||
|
+ if (count % 8)
|
||
|
+ return -EINVAL; /* Invalid chunk size */
|
||
|
+
|
||
|
+ for (; count; count -= 8) {
|
||
|
+ err = rdmsr_safe_on_pcpu(cpu, reg, &data[0], &data[1]);
|
||
|
+ if (err)
|
||
|
+ break;
|
||
|
+ if (copy_to_user(tmp, &data, 8)) {
|
||
|
+ err = -EFAULT;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ tmp += 2;
|
||
|
+ bytes += 8;
|
||
|
+ }
|
||
|
+
|
||
|
+ return bytes ? bytes : err;
|
||
|
+}
|
||
|
+
|
||
|
+static ssize_t pmsr_write(struct file *file, const char __user *buf,
|
||
|
+ size_t count, loff_t *ppos)
|
||
|
+{
|
||
|
+ const u32 __user *tmp = (const u32 __user *)buf;
|
||
|
+ u32 data[2];
|
||
|
+ u32 reg = *ppos;
|
||
|
+ unsigned int cpu = pmsr_minor(file->f_path.dentry->d_inode);
|
||
|
+ int err = 0;
|
||
|
+ ssize_t bytes = 0;
|
||
|
+
|
||
|
+ if (count % 8)
|
||
|
+ return -EINVAL; /* Invalid chunk size */
|
||
|
+
|
||
|
+ for (; count; count -= 8) {
|
||
|
+ if (copy_from_user(&data, tmp, 8)) {
|
||
|
+ err = -EFAULT;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ err = wrmsr_safe_on_pcpu(cpu, reg, data[0], data[1]);
|
||
|
+ if (err)
|
||
|
+ break;
|
||
|
+ tmp += 2;
|
||
|
+ bytes += 8;
|
||
|
+ }
|
||
|
+
|
||
|
+ return bytes ? bytes : err;
|
||
|
+}
|
||
|
+
|
||
|
+static long pmsr_ioctl(struct file *file, unsigned int ioc, unsigned long arg)
|
||
|
+{
|
||
|
+ u32 __user *uregs = (u32 __user *)arg;
|
||
|
+ u32 regs[8];
|
||
|
+ unsigned int cpu = pmsr_minor(file->f_path.dentry->d_inode);
|
||
|
+ int err;
|
||
|
+
|
||
|
+ switch (ioc) {
|
||
|
+ case X86_IOC_RDMSR_REGS:
|
||
|
+ if (!(file->f_mode & FMODE_READ)) {
|
||
|
+ err = -EBADF;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (copy_from_user(®s, uregs, sizeof regs)) {
|
||
|
+ err = -EFAULT;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ err = rdmsr_safe_regs_on_pcpu(cpu, regs);
|
||
|
+ if (err)
|
||
|
+ break;
|
||
|
+ if (copy_to_user(uregs, ®s, sizeof regs))
|
||
|
+ err = -EFAULT;
|
||
|
+ break;
|
||
|
+
|
||
|
+ case X86_IOC_WRMSR_REGS:
|
||
|
+ if (!(file->f_mode & FMODE_WRITE)) {
|
||
|
+ err = -EBADF;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (copy_from_user(®s, uregs, sizeof regs)) {
|
||
|
+ err = -EFAULT;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ err = wrmsr_safe_regs_on_pcpu(cpu, regs);
|
||
|
+ if (err)
|
||
|
+ break;
|
||
|
+ if (copy_to_user(uregs, ®s, sizeof regs))
|
||
|
+ err = -EFAULT;
|
||
|
+ break;
|
||
|
+
|
||
|
+ default:
|
||
|
+ err = -ENOTTY;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ return err;
|
||
|
+}
|
||
|
+
|
||
|
+static int pmsr_open(struct inode *inode, struct file *file)
|
||
|
+{
|
||
|
+ unsigned int cpu;
|
||
|
+
|
||
|
+ cpu = pmsr_minor(file->f_path.dentry->d_inode);
|
||
|
+ if (cpu >= nr_xen_cpu_ids || !test_bit(cpu, xen_cpu_online_map))
|
||
|
+ return -ENXIO; /* No such CPU */
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * File operations we support
|
||
|
+ */
|
||
|
+static const struct file_operations pmsr_fops = {
|
||
|
+ .owner = THIS_MODULE,
|
||
|
+ .llseek = msr_seek,
|
||
|
+ .read = pmsr_read,
|
||
|
+ .write = pmsr_write,
|
||
|
+ .open = pmsr_open,
|
||
|
+ .unlocked_ioctl = pmsr_ioctl,
|
||
|
+ .compat_ioctl = pmsr_ioctl,
|
||
|
+};
|
||
|
+
|
||
|
+static int pmsr_device_create(unsigned int cpu)
|
||
|
+{
|
||
|
+ struct device *dev;
|
||
|
+
|
||
|
+ if (cpu >= nr_xen_cpu_ids) {
|
||
|
+ static bool warned;
|
||
|
+ unsigned long *map;
|
||
|
+
|
||
|
+ if ((minor_bias + cpu) >> MINORBITS) {
|
||
|
+ if (!warned) {
|
||
|
+ warned = true;
|
||
|
+ pr_warning("Physical MSRs of CPUs beyond %u"
|
||
|
+ " will not be accessible\n",
|
||
|
+ MINORMASK - minor_bias);
|
||
|
+ }
|
||
|
+ return -EDOM;
|
||
|
+ }
|
||
|
+
|
||
|
+ map = kzalloc(BITS_TO_LONGS(cpu + 1) * sizeof(*map),
|
||
|
+ GFP_KERNEL);
|
||
|
+ if (!map) {
|
||
|
+ if (!warned) {
|
||
|
+ warned = true;
|
||
|
+ pr_warning("Physical MSRs of CPUs beyond %u"
|
||
|
+ " may not be accessible\n",
|
||
|
+ nr_xen_cpu_ids - 1);
|
||
|
+ }
|
||
|
+ return -ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ memcpy(map, xen_cpu_online_map,
|
||
|
+ BITS_TO_LONGS(nr_xen_cpu_ids)
|
||
|
+ * sizeof(*xen_cpu_online_map));
|
||
|
+ nr_xen_cpu_ids = min_t(unsigned int,
|
||
|
+ BITS_TO_LONGS(cpu + 1) * BITS_PER_LONG,
|
||
|
+ MINORMASK + 1 - minor_bias);
|
||
|
+ kfree(xchg(&xen_cpu_online_map, map));
|
||
|
+ }
|
||
|
+ set_bit(cpu, xen_cpu_online_map);
|
||
|
+ dev = device_create(pmsr_class, NULL, PMSR_DEV(cpu), NULL,
|
||
|
+ "pmsr%d", cpu);
|
||
|
+ return IS_ERR(dev) ? PTR_ERR(dev) : 0;
|
||
|
+}
|
||
|
+
|
||
|
+static void pmsr_device_destroy(unsigned int cpu)
|
||
|
+{
|
||
|
+ clear_bit(cpu, xen_cpu_online_map);
|
||
|
+ device_destroy(pmsr_class, PMSR_DEV(cpu));
|
||
|
+}
|
||
|
+
|
||
|
+static int pmsr_cpu_callback(struct notifier_block *nfb,
|
||
|
+ unsigned long action, void *hcpu)
|
||
|
+{
|
||
|
+ unsigned int cpu = (unsigned long)hcpu;
|
||
|
+
|
||
|
+ switch (action) {
|
||
|
+ case CPU_ONLINE:
|
||
|
+ pmsr_device_create(cpu);
|
||
|
+ break;
|
||
|
+ case CPU_DEAD:
|
||
|
+ pmsr_device_destroy(cpu);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ return NOTIFY_OK;
|
||
|
+}
|
||
|
+
|
||
|
+static struct notifier_block pmsr_cpu_notifier = {
|
||
|
+ .notifier_call = pmsr_cpu_callback,
|
||
|
+};
|
||
|
+
|
||
|
+static char *pmsr_devnode(struct device *dev, mode_t *mode)
|
||
|
+{
|
||
|
+ return kasprintf(GFP_KERNEL, "xen/cpu/%u/msr",
|
||
|
+ MINOR(dev->devt) - minor_bias);
|
||
|
+}
|
||
|
+
|
||
|
+static int __init msr_init(void)
|
||
|
+{
|
||
|
+ int err;
|
||
|
+ xen_platform_op_t op = {
|
||
|
+ .cmd = XENPF_get_cpuinfo,
|
||
|
+ .interface_version = XENPF_INTERFACE_VERSION,
|
||
|
+ .u.pcpu_info.xen_cpuid = 0
|
||
|
+ };
|
||
|
+
|
||
|
+ err = _msr_init();
|
||
|
+ if (err || !is_initial_xendomain())
|
||
|
+ return err;
|
||
|
+
|
||
|
+ do {
|
||
|
+ err = HYPERVISOR_platform_op(&op);
|
||
|
+ } while (err == -EBUSY);
|
||
|
+ if (err)
|
||
|
+ goto out;
|
||
|
+ nr_xen_cpu_ids = BITS_TO_LONGS(op.u.pcpu_info.max_present + 1)
|
||
|
+ * BITS_PER_LONG;
|
||
|
+
|
||
|
+ while (minor_bias < NR_CPUS)
|
||
|
+ minor_bias *= 10;
|
||
|
+ if ((minor_bias + nr_xen_cpu_ids - 1) >> MINORBITS)
|
||
|
+ minor_bias = NR_CPUS;
|
||
|
+ if ((minor_bias + nr_xen_cpu_ids - 1) >> MINORBITS)
|
||
|
+ nr_xen_cpu_ids = MINORMASK + 1 - NR_CPUS;
|
||
|
+
|
||
|
+ xen_cpu_online_map = kzalloc(BITS_TO_LONGS(nr_xen_cpu_ids)
|
||
|
+ * sizeof(*xen_cpu_online_map),
|
||
|
+ GFP_KERNEL);
|
||
|
+ if (!xen_cpu_online_map) {
|
||
|
+ err = -ENOMEM;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (__register_chrdev(MSR_MAJOR, minor_bias,
|
||
|
+ MINORMASK + 1 - minor_bias,
|
||
|
+ "pcpu/msr", &pmsr_fops)) {
|
||
|
+ pr_err("msr: unable to get minors for pmsr\n");
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ pmsr_class = class_create(THIS_MODULE, "pmsr");
|
||
|
+ if (IS_ERR(pmsr_class)) {
|
||
|
+ err = PTR_ERR(pmsr_class);
|
||
|
+ goto out_chrdev;
|
||
|
+ }
|
||
|
+ pmsr_class->devnode = pmsr_devnode;
|
||
|
+ err = register_pcpu_notifier(&pmsr_cpu_notifier);
|
||
|
+
|
||
|
+ if (!err && !nr_xen_cpu_ids)
|
||
|
+ err = -ENODEV;
|
||
|
+ if (!err)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ class_destroy(pmsr_class);
|
||
|
+
|
||
|
+out_chrdev:
|
||
|
+ __unregister_chrdev(MSR_MAJOR, minor_bias,
|
||
|
+ MINORMASK + 1 - minor_bias, "pcpu/msr");
|
||
|
+out:
|
||
|
+ if (err)
|
||
|
+ pr_warning("msr: can't initialize physical MSR access (%d)\n",
|
||
|
+ err);
|
||
|
+ nr_xen_cpu_ids = 0;
|
||
|
+ kfree(xen_cpu_online_map);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static void __exit msr_exit(void)
|
||
|
+{
|
||
|
+ if (nr_xen_cpu_ids) {
|
||
|
+ unsigned int cpu = 0;
|
||
|
+
|
||
|
+ unregister_pcpu_notifier(&pmsr_cpu_notifier);
|
||
|
+ for_each_set_bit(cpu, xen_cpu_online_map, nr_xen_cpu_ids)
|
||
|
+ msr_device_destroy(cpu);
|
||
|
+ class_destroy(pmsr_class);
|
||
|
+ __unregister_chrdev(MSR_MAJOR, minor_bias,
|
||
|
+ MINORMASK + 1 - minor_bias, "pcpu/msr");
|
||
|
+ kfree(xen_cpu_online_map);
|
||
|
+ }
|
||
|
+ _msr_exit();
|
||
|
+}
|
||
|
+#endif /* CONFIG_XEN_PRIVILEGED_GUEST */
|
||
|
--- head-2011-03-11.orig/drivers/hwmon/Kconfig 2011-02-01 15:04:27.000000000 +0100
|
||
|
+++ head-2011-03-11/drivers/hwmon/Kconfig 2011-03-11 11:17:24.000000000 +0100
|
||
|
@@ -392,7 +392,8 @@ config SENSORS_GPIO_FAN
|
||
|
|
||
|
config SENSORS_CORETEMP
|
||
|
tristate "Intel Core/Core2/Atom temperature sensor"
|
||
|
- depends on X86 && PCI && !XEN && EXPERIMENTAL
|
||
|
+ depends on X86 && PCI && !XEN_UNPRIVILEGED_GUEST && EXPERIMENTAL
|
||
|
+ select XEN_DOMCTL if XEN
|
||
|
help
|
||
|
If you say yes here you get support for the temperature
|
||
|
sensor inside your CPU. Most of the family 6 CPUs
|
||
|
@@ -400,7 +401,8 @@ config SENSORS_CORETEMP
|
||
|
|
||
|
config SENSORS_PKGTEMP
|
||
|
tristate "Intel processor package temperature sensor"
|
||
|
- depends on X86 && !XEN && EXPERIMENTAL
|
||
|
+ depends on X86 && !XEN_UNPRIVILEGED_GUEST && EXPERIMENTAL
|
||
|
+ select XEN_DOMCTL if XEN
|
||
|
help
|
||
|
If you say yes here you get support for the package level temperature
|
||
|
sensor inside your CPU. Check documentation/driver for details.
|
||
|
@@ -943,7 +945,8 @@ config SENSORS_TMP421
|
||
|
|
||
|
config SENSORS_VIA_CPUTEMP
|
||
|
tristate "VIA CPU temperature sensor"
|
||
|
- depends on X86 && !XEN
|
||
|
+ depends on X86 && !XEN_UNPRIVILEGED_GUEST
|
||
|
+ select XEN_DOMCTL if XEN
|
||
|
help
|
||
|
If you say yes here you get support for the temperature
|
||
|
sensor inside your CPU. Supported are all known variants of
|
||
|
--- head-2011-03-11.orig/drivers/xen/core/Makefile 2011-02-02 15:10:34.000000000 +0100
|
||
|
+++ head-2011-03-11/drivers/xen/core/Makefile 2011-02-03 14:42:26.000000000 +0100
|
||
|
@@ -5,8 +5,7 @@
|
||
|
obj-y := evtchn.o gnttab.o reboot.o machine_reboot.o
|
||
|
|
||
|
priv-$(CONFIG_PCI) += pci.o
|
||
|
-priv-$(CONFIG_ACPI_HOTPLUG_CPU) += pcpu.o
|
||
|
-obj-$(CONFIG_XEN_PRIVILEGED_GUEST) += firmware.o $(priv-y)
|
||
|
+obj-$(CONFIG_XEN_PRIVILEGED_GUEST) += firmware.o pcpu.o $(priv-y)
|
||
|
obj-$(CONFIG_PROC_FS) += xen_proc.o
|
||
|
obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor_sysfs.o
|
||
|
obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
|
||
|
@@ -17,4 +16,4 @@ obj-$(CONFIG_KEXEC) += machine_kexec.o
|
||
|
obj-$(CONFIG_GENERIC_CLOCKEVENTS) += clockevents.o
|
||
|
obj-$(CONFIG_XEN_DOMCTL) += domctl.o
|
||
|
CFLAGS_domctl.o := -D__XEN_PUBLIC_XEN_H__ -D__XEN_PUBLIC_GRANT_TABLE_H__
|
||
|
-CFLAGS_domctl.o += -D__XEN_TOOLS__ -imacros xen/interface/domctl.h
|
||
|
+CFLAGS_domctl.o += -D__XEN_TOOLS__ -imacros xen/interface/domctl.h -imacros xen/interface/sysctl.h
|
||
|
--- head-2011-03-11.orig/drivers/xen/core/domctl.c 2010-11-23 16:20:20.000000000 +0100
|
||
|
+++ head-2011-03-11/drivers/xen/core/domctl.c 2011-02-03 14:42:26.000000000 +0100
|
||
|
@@ -92,6 +92,110 @@ union xen_domctl {
|
||
|
} v5, v6, v7;
|
||
|
};
|
||
|
|
||
|
+struct xen_sysctl_physinfo_v6 {
|
||
|
+ uint32_t threads_per_core;
|
||
|
+ uint32_t cores_per_socket;
|
||
|
+ uint32_t nr_cpus;
|
||
|
+ uint32_t nr_nodes;
|
||
|
+ uint32_t cpu_khz;
|
||
|
+ uint64_aligned_t total_pages;
|
||
|
+ uint64_aligned_t free_pages;
|
||
|
+ uint64_aligned_t scrub_pages;
|
||
|
+ uint32_t hw_cap[8];
|
||
|
+ uint32_t max_cpu_id;
|
||
|
+ union {
|
||
|
+ XEN_GUEST_HANDLE(uint32) cpu_to_node;
|
||
|
+ uint64_aligned_t _ctn_align;
|
||
|
+ };
|
||
|
+ uint32_t capabilities;
|
||
|
+};
|
||
|
+
|
||
|
+struct xen_sysctl_physinfo_v7 {
|
||
|
+ uint32_t threads_per_core;
|
||
|
+ uint32_t cores_per_socket;
|
||
|
+ uint32_t nr_cpus;
|
||
|
+ uint32_t max_node_id;
|
||
|
+ uint32_t cpu_khz;
|
||
|
+ uint64_aligned_t total_pages;
|
||
|
+ uint64_aligned_t free_pages;
|
||
|
+ uint64_aligned_t scrub_pages;
|
||
|
+ uint32_t hw_cap[8];
|
||
|
+ uint32_t max_cpu_id;
|
||
|
+ union {
|
||
|
+ XEN_GUEST_HANDLE(uint32) cpu_to_node;
|
||
|
+ uint64_aligned_t _ctn_align;
|
||
|
+ };
|
||
|
+ uint32_t capabilities;
|
||
|
+};
|
||
|
+
|
||
|
+#define XEN_SYSCTL_pm_op_get_cputopo 0x20
|
||
|
+struct xen_get_cputopo_v6 {
|
||
|
+ uint32_t max_cpus;
|
||
|
+ union {
|
||
|
+ XEN_GUEST_HANDLE(uint32) cpu_to_core;
|
||
|
+ uint64_aligned_t _ctc_align;
|
||
|
+ };
|
||
|
+ union {
|
||
|
+ XEN_GUEST_HANDLE(uint32) cpu_to_socket;
|
||
|
+ uint64_aligned_t _cts_align;
|
||
|
+ };
|
||
|
+ uint32_t nr_cpus;
|
||
|
+};
|
||
|
+
|
||
|
+struct xen_sysctl_pm_op_v6 {
|
||
|
+ uint32_t cmd;
|
||
|
+ uint32_t cpuid;
|
||
|
+ union {
|
||
|
+ struct xen_get_cputopo_v6 get_topo;
|
||
|
+ };
|
||
|
+};
|
||
|
+#define xen_sysctl_pm_op_v7 xen_sysctl_pm_op_v6
|
||
|
+
|
||
|
+struct xen_sysctl_topologyinfo_v8 {
|
||
|
+ uint32_t max_cpu_index;
|
||
|
+ union {
|
||
|
+ XEN_GUEST_HANDLE(uint32) cpu_to_core;
|
||
|
+ uint64_aligned_t _ctc_align;
|
||
|
+ };
|
||
|
+ union {
|
||
|
+ XEN_GUEST_HANDLE(uint32) cpu_to_socket;
|
||
|
+ uint64_aligned_t _cts_align;
|
||
|
+ };
|
||
|
+ union {
|
||
|
+ XEN_GUEST_HANDLE(uint32) cpu_to_node;
|
||
|
+ uint64_aligned_t _ctn_align;
|
||
|
+ };
|
||
|
+};
|
||
|
+
|
||
|
+union xen_sysctl {
|
||
|
+ /* v6: Xen 3.4.x */
|
||
|
+ struct {
|
||
|
+ uint32_t cmd;
|
||
|
+ uint32_t interface_version;
|
||
|
+ union {
|
||
|
+ struct xen_sysctl_physinfo_v6 physinfo;
|
||
|
+ struct xen_sysctl_pm_op_v6 pm_op;
|
||
|
+ };
|
||
|
+ } v6;
|
||
|
+ /* v7: Xen 4.0.x */
|
||
|
+ struct {
|
||
|
+ uint32_t cmd;
|
||
|
+ uint32_t interface_version;
|
||
|
+ union {
|
||
|
+ struct xen_sysctl_physinfo_v7 physinfo;
|
||
|
+ struct xen_sysctl_pm_op_v7 pm_op;
|
||
|
+ };
|
||
|
+ } v7;
|
||
|
+ /* v8: Xen 4.1+ */
|
||
|
+ struct {
|
||
|
+ uint32_t cmd;
|
||
|
+ uint32_t interface_version;
|
||
|
+ union {
|
||
|
+ struct xen_sysctl_topologyinfo_v8 topologyinfo;
|
||
|
+ };
|
||
|
+ } v8;
|
||
|
+};
|
||
|
+
|
||
|
/* The actual code comes here */
|
||
|
|
||
|
static inline int hypervisor_domctl(void *domctl)
|
||
|
@@ -99,6 +203,11 @@ static inline int hypervisor_domctl(void
|
||
|
return _hypercall1(int, domctl, domctl);
|
||
|
}
|
||
|
|
||
|
+static inline int hypervisor_sysctl(void *sysctl)
|
||
|
+{
|
||
|
+ return _hypercall1(int, sysctl, sysctl);
|
||
|
+}
|
||
|
+
|
||
|
int xen_guest_address_size(int domid)
|
||
|
{
|
||
|
union xen_domctl domctl;
|
||
|
@@ -263,6 +372,172 @@ int xen_set_physical_cpu_affinity(int pc
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(xen_set_physical_cpu_affinity);
|
||
|
|
||
|
+int xen_get_topology_info(unsigned int cpu, u32 *core, u32 *sock, u32 *node)
|
||
|
+{
|
||
|
+ union xen_sysctl sysctl;
|
||
|
+ uint32_t *cores = NULL, *socks = NULL, *nodes = NULL;
|
||
|
+ unsigned int nr;
|
||
|
+ int rc;
|
||
|
+
|
||
|
+ if (core)
|
||
|
+ cores = kmalloc((cpu + 1) * sizeof(*cores), GFP_KERNEL);
|
||
|
+ if (sock)
|
||
|
+ socks = kmalloc((cpu + 1) * sizeof(*socks), GFP_KERNEL);
|
||
|
+ if (node)
|
||
|
+ nodes = kmalloc((cpu + 1) * sizeof(*nodes), GFP_KERNEL);
|
||
|
+ if ((core && !cores) || (sock && !socks) || (node && !nodes)) {
|
||
|
+ kfree(cores);
|
||
|
+ kfree(socks);
|
||
|
+ kfree(nodes);
|
||
|
+ return -ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+#define topologyinfo(ver) do { \
|
||
|
+ memset(&sysctl, 0, sizeof(sysctl)); \
|
||
|
+ sysctl.v##ver.cmd = XEN_SYSCTL_topologyinfo; \
|
||
|
+ sysctl.v##ver.interface_version = ver; \
|
||
|
+ sysctl.v##ver.topologyinfo.max_cpu_index = cpu; \
|
||
|
+ set_xen_guest_handle(sysctl.v##ver.topologyinfo.cpu_to_core, \
|
||
|
+ cores); \
|
||
|
+ set_xen_guest_handle(sysctl.v##ver.topologyinfo.cpu_to_socket, \
|
||
|
+ socks); \
|
||
|
+ set_xen_guest_handle(sysctl.v##ver.topologyinfo.cpu_to_node, \
|
||
|
+ nodes); \
|
||
|
+ rc = hypervisor_sysctl(&sysctl); \
|
||
|
+ nr = sysctl.v##ver.topologyinfo.max_cpu_index + 1; \
|
||
|
+} while (0)
|
||
|
+
|
||
|
+ BUILD_BUG_ON(XEN_SYSCTL_INTERFACE_VERSION > 8);
|
||
|
+ topologyinfo(8);
|
||
|
+
|
||
|
+#if CONFIG_XEN_COMPAT < 0x040100
|
||
|
+#define pm_op_cputopo(ver) do { \
|
||
|
+ memset(&sysctl, 0, sizeof(sysctl)); \
|
||
|
+ sysctl.v##ver.cmd = XEN_SYSCTL_pm_op; \
|
||
|
+ sysctl.v##ver.interface_version = ver; \
|
||
|
+ sysctl.v##ver.pm_op.cmd = XEN_SYSCTL_pm_op_get_cputopo; \
|
||
|
+ sysctl.v##ver.pm_op.cpuid = 0; \
|
||
|
+ sysctl.v##ver.pm_op.get_topo.max_cpus = cpu + 1; \
|
||
|
+ set_xen_guest_handle(sysctl.v##ver.pm_op.get_topo.cpu_to_core, \
|
||
|
+ cores); \
|
||
|
+ set_xen_guest_handle(sysctl.v##ver.pm_op.get_topo.cpu_to_socket,\
|
||
|
+ socks); \
|
||
|
+ rc = hypervisor_sysctl(&sysctl); \
|
||
|
+ memset(&sysctl, 0, sizeof(sysctl)); \
|
||
|
+ sysctl.v##ver.cmd = XEN_SYSCTL_physinfo; \
|
||
|
+ sysctl.v##ver.interface_version = ver; \
|
||
|
+ sysctl.v##ver.physinfo.max_cpu_id = cpu; \
|
||
|
+ set_xen_guest_handle(sysctl.v##ver.physinfo.cpu_to_node, nodes);\
|
||
|
+ rc = hypervisor_sysctl(&sysctl) ?: rc; \
|
||
|
+ nr = sysctl.v##ver.physinfo.max_cpu_id + 1; \
|
||
|
+} while (0)
|
||
|
+
|
||
|
+ if (rc)
|
||
|
+ pm_op_cputopo(7);
|
||
|
+#endif
|
||
|
+#if CONFIG_XEN_COMPAT < 0x040000
|
||
|
+ if (rc)
|
||
|
+ pm_op_cputopo(6);
|
||
|
+#endif
|
||
|
+
|
||
|
+ if (!rc && cpu >= nr)
|
||
|
+ rc = -EDOM;
|
||
|
+
|
||
|
+ if (!rc && core && (*core = cores[cpu]) == INVALID_TOPOLOGY_ID)
|
||
|
+ rc = -ENOENT;
|
||
|
+ kfree(cores);
|
||
|
+
|
||
|
+ if (!rc && sock && (*sock = socks[cpu]) == INVALID_TOPOLOGY_ID)
|
||
|
+ rc = -ENOENT;
|
||
|
+ kfree(socks);
|
||
|
+
|
||
|
+ if (!rc && node && (*node = nodes[cpu]) == INVALID_TOPOLOGY_ID)
|
||
|
+ rc = -ENOENT;
|
||
|
+ kfree(nodes);
|
||
|
+
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(xen_get_topology_info);
|
||
|
+
|
||
|
+#include <xen/pcpu.h>
|
||
|
+#include <asm/msr.h>
|
||
|
+
|
||
|
+int rdmsr_safe_on_pcpu(unsigned int pcpu, u32 msr_no, u32 *l, u32 *h)
|
||
|
+{
|
||
|
+ int err = xen_set_physical_cpu_affinity(pcpu);
|
||
|
+
|
||
|
+ switch (err) {
|
||
|
+ case 0:
|
||
|
+ err = rdmsr_safe(msr_no, l, h);
|
||
|
+ WARN_ON_ONCE(xen_set_physical_cpu_affinity(-1));
|
||
|
+ break;
|
||
|
+ case -EINVAL:
|
||
|
+ /* Fall back in case this is due to dom0_vcpus_pinned. */
|
||
|
+ err = rdmsr_safe_on_cpu(pcpu, msr_no, l, h) ?: 1;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ return err;
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(rdmsr_safe_on_pcpu);
|
||
|
+
|
||
|
+int wrmsr_safe_on_pcpu(unsigned int pcpu, u32 msr_no, u32 l, u32 h)
|
||
|
+{
|
||
|
+ int err = xen_set_physical_cpu_affinity(pcpu);
|
||
|
+
|
||
|
+ switch (err) {
|
||
|
+ case 0:
|
||
|
+ err = wrmsr_safe(msr_no, l, h);
|
||
|
+ WARN_ON_ONCE(xen_set_physical_cpu_affinity(-1));
|
||
|
+ break;
|
||
|
+ case -EINVAL:
|
||
|
+ /* Fall back in case this is due to dom0_vcpus_pinned. */
|
||
|
+ err = wrmsr_safe_on_cpu(pcpu, msr_no, l, h) ?: 1;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ return err;
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(wrmsr_safe_on_pcpu);
|
||
|
+
|
||
|
+int rdmsr_safe_regs_on_pcpu(unsigned int pcpu, u32 *regs)
|
||
|
+{
|
||
|
+ int err = xen_set_physical_cpu_affinity(pcpu);
|
||
|
+
|
||
|
+ switch (err) {
|
||
|
+ case 0:
|
||
|
+ err = rdmsr_safe_regs(regs);
|
||
|
+ WARN_ON_ONCE(xen_set_physical_cpu_affinity(-1));
|
||
|
+ break;
|
||
|
+ case -EINVAL:
|
||
|
+ /* Fall back in case this is due to dom0_vcpus_pinned. */
|
||
|
+ err = rdmsr_safe_regs_on_cpu(pcpu, regs) ?: 1;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ return err;
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(rdmsr_safe_regs_on_pcpu);
|
||
|
+
|
||
|
+int wrmsr_safe_regs_on_pcpu(unsigned int pcpu, u32 *regs)
|
||
|
+{
|
||
|
+ int err = xen_set_physical_cpu_affinity(pcpu);
|
||
|
+
|
||
|
+ switch (err) {
|
||
|
+ case 0:
|
||
|
+ err = wrmsr_safe_regs(regs);
|
||
|
+ WARN_ON_ONCE(xen_set_physical_cpu_affinity(-1));
|
||
|
+ break;
|
||
|
+ case -EINVAL:
|
||
|
+ /* Fall back in case this is due to dom0_vcpus_pinned. */
|
||
|
+ err = wrmsr_safe_regs_on_cpu(pcpu, regs) ?: 1;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ return err;
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(wrmsr_safe_regs_on_pcpu);
|
||
|
+
|
||
|
#endif /* CONFIG_X86 */
|
||
|
|
||
|
MODULE_LICENSE("GPL");
|
||
|
--- head-2011-03-11.orig/drivers/xen/core/domctl.h 2010-11-23 16:20:20.000000000 +0100
|
||
|
+++ head-2011-03-11/drivers/xen/core/domctl.h 2011-02-03 14:42:26.000000000 +0100
|
||
|
@@ -1,3 +1,4 @@
|
||
|
int xen_guest_address_size(int domid);
|
||
|
int xen_guest_blkif_protocol(int domid);
|
||
|
int xen_set_physical_cpu_affinity(int pcpu);
|
||
|
+int xen_get_topology_info(unsigned int cpu, u32 *core, u32 *socket, u32 *node);
|
||
|
--- head-2011-03-11.orig/drivers/xen/core/pcpu.c 2011-02-02 15:09:57.000000000 +0100
|
||
|
+++ head-2011-03-11/drivers/xen/core/pcpu.c 2011-02-03 14:42:26.000000000 +0100
|
||
|
@@ -11,6 +11,7 @@
|
||
|
#include <asm/hypervisor.h>
|
||
|
#include <xen/interface/platform.h>
|
||
|
#include <xen/evtchn.h>
|
||
|
+#include <xen/pcpu.h>
|
||
|
#include <acpi/processor.h>
|
||
|
|
||
|
struct pcpu {
|
||
|
@@ -35,6 +36,44 @@ static DEFINE_MUTEX(xen_pcpu_lock);
|
||
|
|
||
|
static LIST_HEAD(xen_pcpus);
|
||
|
|
||
|
+static BLOCKING_NOTIFIER_HEAD(pcpu_chain);
|
||
|
+
|
||
|
+static inline void *notifier_param(const struct pcpu *pcpu)
|
||
|
+{
|
||
|
+ return (void *)(unsigned long)pcpu->xen_id;
|
||
|
+}
|
||
|
+
|
||
|
+int register_pcpu_notifier(struct notifier_block *nb)
|
||
|
+{
|
||
|
+ int err;
|
||
|
+
|
||
|
+ get_pcpu_lock();
|
||
|
+
|
||
|
+ err = blocking_notifier_chain_register(&pcpu_chain, nb);
|
||
|
+
|
||
|
+ if (!err) {
|
||
|
+ struct pcpu *pcpu;
|
||
|
+
|
||
|
+ list_for_each_entry(pcpu, &xen_pcpus, pcpu_list)
|
||
|
+ if (xen_pcpu_online(pcpu->flags))
|
||
|
+ nb->notifier_call(nb, CPU_ONLINE,
|
||
|
+ notifier_param(pcpu));
|
||
|
+ }
|
||
|
+
|
||
|
+ put_pcpu_lock();
|
||
|
+
|
||
|
+ return err;
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(register_pcpu_notifier);
|
||
|
+
|
||
|
+void unregister_pcpu_notifier(struct notifier_block *nb)
|
||
|
+{
|
||
|
+ get_pcpu_lock();
|
||
|
+ blocking_notifier_chain_unregister(&pcpu_chain, nb);
|
||
|
+ put_pcpu_lock();
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(unregister_pcpu_notifier);
|
||
|
+
|
||
|
static int xen_pcpu_down(uint32_t xen_id)
|
||
|
{
|
||
|
xen_platform_op_t op = {
|
||
|
@@ -151,12 +190,16 @@ static int xen_pcpu_online_check(struct
|
||
|
if (xen_pcpu_online(info->flags) && !xen_pcpu_online(pcpu->flags)) {
|
||
|
/* the pcpu is onlined */
|
||
|
pcpu->flags |= XEN_PCPU_FLAGS_ONLINE;
|
||
|
+ blocking_notifier_call_chain(&pcpu_chain, CPU_ONLINE,
|
||
|
+ notifier_param(pcpu));
|
||
|
kobject_uevent(&pcpu->sysdev.kobj, KOBJ_ONLINE);
|
||
|
result = 1;
|
||
|
} else if (!xen_pcpu_online(info->flags) &&
|
||
|
xen_pcpu_online(pcpu->flags)) {
|
||
|
/* The pcpu is offlined now */
|
||
|
pcpu->flags &= ~XEN_PCPU_FLAGS_ONLINE;
|
||
|
+ blocking_notifier_call_chain(&pcpu_chain, CPU_DEAD,
|
||
|
+ notifier_param(pcpu));
|
||
|
kobject_uevent(&pcpu->sysdev.kobj, KOBJ_OFFLINE);
|
||
|
result = 1;
|
||
|
}
|
||
|
@@ -350,6 +393,8 @@ static irqreturn_t xen_pcpu_interrupt(in
|
||
|
return IRQ_HANDLED;
|
||
|
}
|
||
|
|
||
|
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
|
||
|
+
|
||
|
int xen_pcpu_hotplug(int type)
|
||
|
{
|
||
|
schedule_work(&xen_pcpu_work);
|
||
|
@@ -387,6 +432,8 @@ int xen_pcpu_index(uint32_t id, bool is_
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(xen_pcpu_index);
|
||
|
|
||
|
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
|
||
|
+
|
||
|
static int __init xen_pcpu_init(void)
|
||
|
{
|
||
|
int err;
|
||
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
|
+++ head-2011-03-11/include/xen/pcpu.h 2011-02-03 14:42:26.000000000 +0100
|
||
|
@@ -0,0 +1,18 @@
|
||
|
+#ifndef _XEN_SYSCTL_H
|
||
|
+#define _XEN_SYSCTL_H
|
||
|
+
|
||
|
+#include <linux/notifier.h>
|
||
|
+
|
||
|
+int register_pcpu_notifier(struct notifier_block *);
|
||
|
+void unregister_pcpu_notifier(struct notifier_block *);
|
||
|
+
|
||
|
+#ifdef CONFIG_X86
|
||
|
+int __must_check rdmsr_safe_on_pcpu(unsigned int pcpu, u32 msr_no,
|
||
|
+ u32 *l, u32 *h);
|
||
|
+int __must_check wrmsr_safe_on_pcpu(unsigned int pcpu, u32 msr_no,
|
||
|
+ u32 l, u32 h);
|
||
|
+int __must_check rdmsr_safe_regs_on_pcpu(unsigned int pcpu, u32 *regs);
|
||
|
+int __must_check wrmsr_safe_regs_on_pcpu(unsigned int pcpu, u32 *regs);
|
||
|
+#endif
|
||
|
+
|
||
|
+#endif /* _XEN_SYSCTL_H */
|