forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-11 297b60346df8beafee954a0fd7c2d64f33f3b9bc
kernel/arch/x86/xen/time.c
....@@ -28,7 +28,7 @@
2828
2929 #include "xen-ops.h"
3030
31
-/* Xen may fire a timer up to this many ns early */
31
+/* Minimum amount of time until next clock event fires */
3232 #define TIMER_SLOP 100000
3333
3434 static u64 xen_sched_clock_offset __read_mostly;
....@@ -39,6 +39,7 @@
3939 struct pvclock_vcpu_time_info *info =
4040 &HYPERVISOR_shared_info->vcpu_info[0].time;
4141
42
+ setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
4243 return pvclock_tsc_khz(info);
4344 }
4445
....@@ -145,12 +146,19 @@
145146 .notifier_call = xen_pvclock_gtod_notify,
146147 };
147148
149
+static int xen_cs_enable(struct clocksource *cs)
150
+{
151
+ vclocks_set_used(VDSO_CLOCKMODE_PVCLOCK);
152
+ return 0;
153
+}
154
+
148155 static struct clocksource xen_clocksource __read_mostly = {
149
- .name = "xen",
150
- .rating = 400,
151
- .read = xen_clocksource_get_cycles,
152
- .mask = ~0,
153
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
156
+ .name = "xen",
157
+ .rating = 400,
158
+ .read = xen_clocksource_get_cycles,
159
+ .mask = CLOCKSOURCE_MASK(64),
160
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
161
+ .enable = xen_cs_enable,
154162 };
155163
156164 /*
....@@ -212,7 +220,7 @@
212220 return 0;
213221 }
214222
215
-static const struct clock_event_device xen_timerop_clockevent = {
223
+static struct clock_event_device xen_timerop_clockevent __ro_after_init = {
216224 .name = "xen",
217225 .features = CLOCK_EVT_FEAT_ONESHOT,
218226
....@@ -273,7 +281,7 @@
273281 return ret;
274282 }
275283
276
-static const struct clock_event_device xen_vcpuop_clockevent = {
284
+static struct clock_event_device xen_vcpuop_clockevent __ro_after_init = {
277285 .name = "xen",
278286 .features = CLOCK_EVT_FEAT_ONESHOT,
279287
....@@ -412,12 +420,13 @@
412420 ret = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_time_memory_area, 0, &t);
413421
414422 /*
415
- * We don't disable VCLOCK_PVCLOCK entirely if it fails to register the
416
- * secondary time info with Xen or if we migrated to a host without the
417
- * necessary flags. On both of these cases what happens is either
418
- * process seeing a zeroed out pvti or seeing no PVCLOCK_TSC_STABLE_BIT
419
- * bit set. Userspace checks the latter and if 0, it discards the data
420
- * in pvti and fallbacks to a system call for a reliable timestamp.
423
+ * We don't disable VDSO_CLOCKMODE_PVCLOCK entirely if it fails to
424
+ * register the secondary time info with Xen or if we migrated to a
425
+ * host without the necessary flags. On both of these cases what
426
+ * happens is either process seeing a zeroed out pvti or seeing no
427
+ * PVCLOCK_TSC_STABLE_BIT bit set. Userspace checks the latter and
428
+ * if 0, it discards the data in pvti and fallbacks to a system
429
+ * call for a reliable timestamp.
421430 */
422431 if (ret != 0)
423432 pr_notice("Cannot restore secondary vcpu_time_info (err %d)",
....@@ -443,7 +452,7 @@
443452
444453 ret = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_time_memory_area, 0, &t);
445454 if (ret) {
446
- pr_notice("xen: VCLOCK_PVCLOCK not supported (err %d)\n", ret);
455
+ pr_notice("xen: VDSO_CLOCKMODE_PVCLOCK not supported (err %d)\n", ret);
447456 free_page((unsigned long)ti);
448457 return;
449458 }
....@@ -460,14 +469,14 @@
460469 if (!ret)
461470 free_page((unsigned long)ti);
462471
463
- pr_notice("xen: VCLOCK_PVCLOCK not supported (tsc unstable)\n");
472
+ pr_notice("xen: VDSO_CLOCKMODE_PVCLOCK not supported (tsc unstable)\n");
464473 return;
465474 }
466475
467476 xen_clock = ti;
468477 pvclock_set_pvti_cpu0_va(xen_clock);
469478
470
- xen_clocksource.archdata.vclock_mode = VCLOCK_PVCLOCK;
479
+ xen_clocksource.vdso_clock_mode = VDSO_CLOCKMODE_PVCLOCK;
471480 }
472481
473482 static void __init xen_time_init(void)
....@@ -519,7 +528,7 @@
519528 void __init xen_init_time_ops(void)
520529 {
521530 xen_sched_clock_offset = xen_clocksource_read();
522
- pv_time_ops = xen_time_ops;
531
+ pv_ops.time = xen_time_ops;
523532
524533 x86_init.timers.timer_init = xen_time_init;
525534 x86_init.timers.setup_percpu_clockev = x86_init_noop;
....@@ -547,6 +556,11 @@
547556
548557 void __init xen_hvm_init_time_ops(void)
549558 {
559
+ static bool hvm_time_initialized;
560
+
561
+ if (hvm_time_initialized)
562
+ return;
563
+
550564 /*
551565 * vector callback is needed otherwise we cannot receive interrupts
552566 * on cpu > 0 and at this point we don't know how many cpus are
....@@ -556,17 +570,48 @@
556570 return;
557571
558572 if (!xen_feature(XENFEAT_hvm_safe_pvclock)) {
559
- pr_info("Xen doesn't support pvclock on HVM, disable pv timer");
573
+ pr_info_once("Xen doesn't support pvclock on HVM, disable pv timer");
574
+ return;
575
+ }
576
+
577
+ /*
578
+ * Only MAX_VIRT_CPUS 'vcpu_info' are embedded inside 'shared_info'.
579
+ * The __this_cpu_read(xen_vcpu) is still NULL when Xen HVM guest
580
+ * boots on vcpu >= MAX_VIRT_CPUS (e.g., kexec), To access
581
+ * __this_cpu_read(xen_vcpu) via xen_clocksource_read() will panic.
582
+ *
583
+ * The xen_hvm_init_time_ops() should be called again later after
584
+ * __this_cpu_read(xen_vcpu) is available.
585
+ */
586
+ if (!__this_cpu_read(xen_vcpu)) {
587
+ pr_info("Delay xen_init_time_common() as kernel is running on vcpu=%d\n",
588
+ xen_vcpu_nr(0));
560589 return;
561590 }
562591
563592 xen_sched_clock_offset = xen_clocksource_read();
564
- pv_time_ops = xen_time_ops;
593
+ pv_ops.time = xen_time_ops;
565594 x86_init.timers.setup_percpu_clockev = xen_time_init;
566595 x86_cpuinit.setup_percpu_clockev = xen_hvm_setup_cpu_clockevents;
567596
568597 x86_platform.calibrate_tsc = xen_tsc_khz;
569598 x86_platform.get_wallclock = xen_get_wallclock;
570599 x86_platform.set_wallclock = xen_set_wallclock;
600
+
601
+ hvm_time_initialized = true;
571602 }
572603 #endif
604
+
605
+/* Kernel parameter to specify Xen timer slop */
606
+static int __init parse_xen_timer_slop(char *ptr)
607
+{
608
+ unsigned long slop = memparse(ptr, NULL);
609
+
610
+ xen_timerop_clockevent.min_delta_ns = slop;
611
+ xen_timerop_clockevent.min_delta_ticks = slop;
612
+ xen_vcpuop_clockevent.min_delta_ns = slop;
613
+ xen_vcpuop_clockevent.min_delta_ticks = slop;
614
+
615
+ return 0;
616
+}
617
+early_param("xen_timer_slop", parse_xen_timer_slop);