KVM wishes to allow direct guest access to the ACPI pmtimer. In that
case QEMU/KVM has to read the current value for migration, so the proper
syncing can be done on the destination.

This patch will not register the device if the chipset has an unreliable
timer.

Signed-off-by: Marcelo Tosatti <[EMAIL PROTECTED]>

CC: john stultz <[EMAIL PROTECTED]>
CC: Thomas Gleixner <[EMAIL PROTECTED]>

Index: kvm/drivers/char/Kconfig
===================================================================
--- kvm.orig/drivers/char/Kconfig
+++ kvm/drivers/char/Kconfig
@@ -1057,6 +1057,13 @@ config HPET_MMAP
          exposed to the user.  If this applies to your hardware,
          say N here.
 
+config ACPI_PMTIMER_DEV
+       tristate "ACPI PM-Timer device"
+       default n
+       depends on ACPI && X86_PM_TIMER
+       help
+        Allow userspace to read the ACPI PM-Timer value.
+
 config HANGCHECK_TIMER
        tristate "Hangcheck timer"
        depends on X86 || IA64 || PPC64 || S390
Index: kvm/drivers/char/Makefile
===================================================================
--- kvm.orig/drivers/char/Makefile
+++ kvm/drivers/char/Makefile
@@ -112,6 +112,7 @@ obj-$(CONFIG_PS3_FLASH)             += ps3flash.o
 
 obj-$(CONFIG_JS_RTC)           += js-rtc.o
 js-rtc-y = rtc.o
+obj-$(CONFIG_ACPI_PMTIMER_DEV) += acpi_pmtimer.o
 
 # Files generated that shall be removed upon make clean
 clean-files := consolemap_deftbl.c defkeymap.c
Index: kvm/drivers/char/acpi_pmtimer.c
===================================================================
--- /dev/null
+++ kvm/drivers/char/acpi_pmtimer.c
@@ -0,0 +1,61 @@
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/acpi_pmtmr.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+static ssize_t pmtimer_read(struct file *file, char __user *buf, size_t count,
+                           loff_t *ppos)
+{
+       int ret;
+       __u32 value;
+
+       ret = -EINVAL;
+       if (count < sizeof(u32))
+               goto out;
+
+       value = inl(pmtmr_ioport) & ACPI_PM_MASK;
+
+       ret = -EFAULT;
+       if (put_user(value, (u32 __user *)buf))
+               goto out;
+
+       ret = sizeof(value);
+out:
+       return ret;
+}
+
+static const struct file_operations acpi_pmtimer_fops = {
+       .owner =        THIS_MODULE,
+       .read =         pmtimer_read,
+};
+
+static struct miscdevice pmtimer_miscdev = {
+       MISC_DYNAMIC_MINOR,
+       "pmtimer",
+       &acpi_pmtimer_fops,
+};
+
+static int __init pmtimer_init(void)
+{
+       if (!pmtmr_ioport || !pmtimer_is_reliable())
+               return -ENODEV;
+
+       return misc_register(&pmtimer_miscdev);
+}
+
+static void __exit pmtimer_exit(void)
+{
+       if (pmtmr_ioport && pmtimer_is_reliable())
+               misc_deregister(&pmtimer_miscdev);
+}
+
+module_init(pmtimer_init);
+module_exit(pmtimer_exit);
+MODULE_AUTHOR ("Marcelo Tosatti <[EMAIL PROTECTED]>");
+MODULE_DESCRIPTION("ACPI PM-Timer");
+MODULE_LICENSE ("GPL");
+
Index: kvm/drivers/clocksource/acpi_pm.c
===================================================================
--- kvm.orig/drivers/clocksource/acpi_pm.c
+++ kvm/drivers/clocksource/acpi_pm.c
@@ -30,6 +30,8 @@
  */
 u32 pmtmr_ioport __read_mostly;
 
+static int reliable_pmtimer;
+
 static inline u32 read_pmtmr(void)
 {
        /* mask the output to 24 bits */
@@ -208,10 +210,21 @@ pm_good:
        if (verify_pmtmr_rate() != 0)
                return -ENODEV;
 
+       if (clocksource_acpi_pm.read == acpi_pm_read)
+               reliable_pmtimer = 1;
+
        return clocksource_register(&clocksource_acpi_pm);
 }
 
+int pmtimer_is_reliable(void)
+{
+       return reliable_pmtimer;
+}
+
 /* We use fs_initcall because we want the PCI fixups to have run
  * but we still need to load before device_initcall
  */
 fs_initcall(init_acpi_pm_clocksource);
+
+EXPORT_SYMBOL(pmtmr_ioport);
+EXPORT_SYMBOL(pmtimer_is_reliable);
Index: kvm/include/linux/acpi_pmtmr.h
===================================================================
--- kvm.orig/include/linux/acpi_pmtmr.h
+++ kvm/include/linux/acpi_pmtmr.h
@@ -27,6 +27,8 @@ static inline u32 acpi_pm_read_early(voi
 
 extern void pmtimer_wait(unsigned);
 
+int pmtimer_is_reliable(void);
+
 #else
 
 static inline u32 acpi_pm_read_early(void)

-- 

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to