WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] cpufreq/PowerNow! implementation - time keeps changing

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] cpufreq/PowerNow! implementation - time keeps changing
From: "Mark Langsdorf" <mark.langsdorf@xxxxxxx>
Date: Fri, 3 Aug 2007 15:11:12 -0500
Delivery-date: Fri, 03 Aug 2007 13:08:45 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: KMail/1.9.5
I'm working on getting cpufreq (specifically PowerNow!) support
for Xen.  My current approach is to have a platform hypervisor
call occur after the processor switches frequency.  The platform
call adjusts the CPU's time records to a scale of the new
frequency.

This usually seems to work, but sometimes Xen seems to alter
its record of the CPU frequency in a way that is very wrong.
The bad frequency causes subsequent cpufreq changes to scale
the new frequency wrong also, and sooner or later time briefly
goes wrong.  I had thought this was possibly happening in the
timer interrupt but I couldn't confirm it.  Does anyone have
any suggestions on what else I need to implement?

Thanks in advance for any advice.

-Mark Langsdorf
Operating System Research Center
AMD

diff -r a70de77dd8d3 arch/i386/kernel/time-xen.c
--- a/arch/i386/kernel/time-xen.c       Tue Jul 10 10:18:24 2007 +0100
+++ b/arch/i386/kernel/time-xen.c       Fri Aug 03 15:01:00 2007 -0500
@@ -50,6 +50,7 @@
 #include <linux/percpu.h>
 #include <linux/kernel_stat.h>
 #include <linux/posix-timers.h>
+#include <linux/cpufreq.h>
 
 #include <asm/io.h>
 #include <asm/smp.h>
@@ -1118,6 +1122,74 @@ void local_teardown_timer(unsigned int c
        BUG_ON(cpu == 0);
        unbind_from_irqhandler(per_cpu(timer_irq, cpu), NULL);
 }
+#endif
+
+#ifdef CONFIG_CPU_FREQ
+/* 
+ * cpufreq scaling handling
+ */
+static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, 
+                               void *data)
+{
+       struct cpufreq_freqs *freq = data;
+        struct vcpu_time_info *info = &vcpu_info(freq->cpu)->time;
+       struct xen_platform_op op;
+
+       if (cpu_has(&cpu_data[freq->cpu], X86_FEATURE_CONSTANT_TSC))
+               return 0;
+
+       if (val == CPUFREQ_PRECHANGE)
+               return 0;
+
+       /* re order time per Ian's instructions */
+       op.cmd = XENPF_change_freq;
+       op.u.change_freq.info = info;
+       op.u.change_freq.old = freq->old;
+       op.u.change_freq.new = freq->new;
+       HYPERVISOR_platform_op(&op);
+       update_wallclock();
+
+       return 0;
+}
+
+static struct notifier_block time_cpufreq_notifier_block = {
+       .notifier_call = time_cpufreq_notifier
+};
+
+static int __init cpufreq_time_setup(void)
+{
+       if (!cpufreq_register_notifier(&time_cpufreq_notifier_block,
+                       CPUFREQ_TRANSITION_NOTIFIER)) {
+               printk(KERN_ERR "failed to set up cpufreq notifier\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+core_initcall(cpufreq_time_setup);
 #endif
 
 /*
diff -r 5682f899c7ae xen/arch/x86/platform_hypercall.c
--- a/xen/arch/x86/platform_hypercall.c Fri Jul 27 09:06:58 2007 +0100
+++ b/xen/arch/x86/platform_hypercall.c Fri Aug 03 14:51:11 2007 -0500
@@ -252,6 +252,13 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xe
         ret = acpi_enter_sleep(&op->u.enter_acpi_sleep);
         break;
 
+    case XENPF_change_freq:
+    {
+        do_change_freq((struct vcpu_time_info *) op->u.change_freq.info, 
op->u.change_freq.old, op->u.change_freq.new);
+        ret = 0;
+    }
+    break;
+
     default:
         ret = -ENOSYS;
         break;
diff -r 5682f899c7ae xen/arch/x86/time.c
--- a/xen/arch/x86/time.c       Fri Jul 27 09:06:58 2007 +0100
+++ b/xen/arch/x86/time.c       Fri Aug 03 14:51:11 2007 -0500
@@ -723,6 +723,35 @@ void update_domain_wallclock_time(struct
     spin_unlock(&wc_lock);
 }
 
+void do_change_freq(struct vcpu_time_info *info, unsigned int old, unsigned 
int new)
+{
+    u64 new_mult;
+    s8 new_shift;
+    struct cpu_time *t;
+
+    t = &this_cpu(cpu_time);
+    new_mult = info->tsc_to_system_mul;
+    do_div(new_mult, new / 1000);
+    new_mult *= (old / 1000);
+    new_shift = info->tsc_shift;
+    while (new_mult > (1LL <<32))  {
+        new_shift += 1;
+        new_mult = new_mult >> 1;
+    }
+    while (new_mult < (1LL << 31)) {
+        new_shift -= 1;
+        new_mult = new_mult << 1;
+    }
+    version_update_begin(&info->version);
+    info->tsc_timestamp = t->local_tsc_stamp;
+    info->system_time   = t->stime_local_stamp;
+    info->tsc_to_system_mul = new_mult; 
+    t->tsc_scale.mul_frac = new_mult;
+    t->tsc_scale.shift = new_shift;
+    info->tsc_shift     =  new_shift;
+    version_update_end(&info->version);
+}
+
 /* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */
 void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base)
 {
diff -r 5682f899c7ae xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c      Fri Jul 27 09:06:58 2007 +0100
+++ b/xen/arch/x86/traps.c      Fri Aug 03 14:51:11 2007 -0500
@@ -1724,6 +1724,15 @@ static int emulate_privileged_op(struct 
                 ((u64)regs->edx << 32) | regs->eax;
             break;
 #endif
+       case MSR_K8_FIDVID_STATUS:
+       case MSR_K8_FIDVID_CTL:
+           if ( IS_COMPAT(v->domain) )
+               goto fail;
+           if ( wrmsr_safe(regs->ecx, regs->eax, regs->edx) )
+               goto fail;
+            v->arch.guest_context.gs_base_user =
+               ((u64)regs->edx << 32) | regs->eax;
+           break;
         default:
             if ( wrmsr_hypervisor_regs(regs->ecx, regs->eax, regs->edx) )
                 break;
@@ -1760,6 +1769,13 @@ static int emulate_privileged_op(struct 
             regs->edx = v->arch.guest_context.gs_base_user >> 32;
             break;
 #endif
+       case MSR_K8_FIDVID_CTL:
+       case MSR_K8_FIDVID_STATUS:
+           if ( IS_COMPAT(v->domain) )
+               goto fail;
+            if ( rdmsr_safe(regs->ecx, regs->eax, regs->edx) )
+               goto fail;
+           break;
         case MSR_EFER:
             if ( rdmsr_safe(regs->ecx, regs->eax, regs->edx) )
                 goto fail;
diff -r 5682f899c7ae xen/include/asm-x86/msr.h
--- a/xen/include/asm-x86/msr.h Fri Jul 27 09:06:58 2007 +0100
+++ b/xen/include/asm-x86/msr.h Fri Aug 03 14:51:11 2007 -0500
@@ -352,6 +352,9 @@ static inline void write_efer(__u64 val)
 #define MSR_K8_VM_CR                   0xC0010114
 #define MSR_K8_VM_HSAVE_PA             0xC0010117
 
+#define MSR_K8_FIDVID_CTL              0xC0010041
+#define MSR_K8_FIDVID_STATUS           0xC0010042
+
 /* MSR_K8_VM_CR bits: */
 #define _K8_VMCR_SVME_DISABLE          4
 #define K8_VMCR_SVME_DISABLE           (1 << _K8_VMCR_SVME_DISABLE)
diff -r 5682f899c7ae xen/include/public/platform.h
--- a/xen/include/public/platform.h     Fri Jul 27 09:06:58 2007 +0100
+++ b/xen/include/public/platform.h     Fri Aug 03 14:51:11 2007 -0500
@@ -164,6 +164,16 @@ typedef struct xenpf_enter_acpi_sleep xe
 typedef struct xenpf_enter_acpi_sleep xenpf_enter_acpi_sleep_t;
 DEFINE_XEN_GUEST_HANDLE(xenpf_enter_acpi_sleep_t);
 
+#define XENPF_change_freq       52
+struct xenpf_change_freq {
+    /* IN variables */
+    struct vcpu_time_info *info; /* vcpu time info for changing vcpu */
+    uint32_t old;  /* original frequency */
+    uint32_t new;  /* new frequency */
+};
+typedef struct xenpf_change_freq xenpf_change_freq_t;
+DEFINE_XEN_GUEST_HANDLE(xenpf_change_freq_t);
+
 struct xen_platform_op {
     uint32_t cmd;
     uint32_t interface_version; /* XENPF_INTERFACE_VERSION */
@@ -176,6 +186,7 @@ struct xen_platform_op {
         struct xenpf_platform_quirk    platform_quirk;
         struct xenpf_firmware_info     firmware_info;
         struct xenpf_enter_acpi_sleep  enter_acpi_sleep;
+        struct xenpf_change_freq       change_freq;
         uint8_t                        pad[128];
     } u;
 };
diff -r 5682f899c7ae xen/include/xen/time.h
--- a/xen/include/xen/time.h    Fri Jul 27 09:06:58 2007 +0100
+++ b/xen/include/xen/time.h    Fri Aug 03 14:51:11 2007 -0500
@@ -74,6 +74,8 @@ extern void do_settime(
 extern void do_settime(
     unsigned long secs, unsigned long nsecs, u64 system_time_base);
 
+extern void do_change_freq(struct vcpu_time_info *info, unsigned int old, 
unsigned int new);
+
 extern void send_timer_event(struct vcpu *v);
 
 #endif /* __XEN_TIME_H__ */




_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] cpufreq/PowerNow! implementation - time keeps changing, Mark Langsdorf <=