17
17
#include <linux/nmi.h>
18
18
#include <linux/sched.h>
19
19
#include <linux/sched/loadavg.h>
20
+ #include <linux/sched/clock.h>
20
21
#include <linux/syscore_ops.h>
21
22
#include <linux/clocksource.h>
22
23
#include <linux/jiffies.h>
@@ -1496,18 +1497,20 @@ void __weak read_persistent_clock64(struct timespec64 *ts64)
1496
1497
}
1497
1498
1498
1499
/**
1499
- * read_boot_clock64 - Return time of the system start.
1500
+ * read_persistent_wall_and_boot_offset - Read persistent clock, and also offset
1501
+ * from the boot.
1500
1502
*
1501
1503
* Weak dummy function for arches that do not yet support it.
1502
- * Function to read the exact time the system has been started.
1503
- * Returns a timespec64 with tv_sec=0 and tv_nsec=0 if unsupported.
1504
- *
1505
- * XXX - Do be sure to remove it once all arches implement it.
1504
+ * wall_time - current time as returned by persistent clock
1505
+ * boot_offset - offset that is defined as wall_time - boot_time
1506
+ * default to 0.
1506
1507
*/
1507
- void __weak read_boot_clock64 (struct timespec64 * ts )
1508
+ void __weak __init
1509
+ read_persistent_wall_and_boot_offset (struct timespec64 * wall_time ,
1510
+ struct timespec64 * boot_offset )
1508
1511
{
1509
- ts -> tv_sec = 0 ;
1510
- ts -> tv_nsec = 0 ;
1512
+ read_persistent_clock64 ( wall_time ) ;
1513
+ * boot_offset = ( struct timespec64 ){ 0 } ;
1511
1514
}
1512
1515
1513
1516
/* Flag for if timekeeping_resume() has injected sleeptime */
@@ -1521,28 +1524,29 @@ static bool persistent_clock_exists;
1521
1524
*/
1522
1525
void __init timekeeping_init (void )
1523
1526
{
1527
+ struct timespec64 wall_time , boot_offset , wall_to_mono ;
1524
1528
struct timekeeper * tk = & tk_core .timekeeper ;
1525
1529
struct clocksource * clock ;
1526
1530
unsigned long flags ;
1527
- struct timespec64 now , boot , tmp ;
1528
-
1529
- read_persistent_clock64 (& now );
1530
- if (!timespec64_valid_strict (& now )) {
1531
- pr_warn ("WARNING: Persistent clock returned invalid value!\n"
1532
- " Check your CMOS/BIOS settings.\n" );
1533
- now .tv_sec = 0 ;
1534
- now .tv_nsec = 0 ;
1535
- } else if (now .tv_sec || now .tv_nsec )
1536
- persistent_clock_exists = true;
1537
1531
1538
- read_boot_clock64 (& boot );
1539
- if (!timespec64_valid_strict (& boot )) {
1540
- pr_warn ("WARNING: Boot clock returned invalid value!\n"
1541
- " Check your CMOS/BIOS settings.\n" );
1542
- boot .tv_sec = 0 ;
1543
- boot .tv_nsec = 0 ;
1532
+ read_persistent_wall_and_boot_offset (& wall_time , & boot_offset );
1533
+ if (timespec64_valid_strict (& wall_time ) &&
1534
+ timespec64_to_ns (& wall_time ) > 0 ) {
1535
+ persistent_clock_exists = true;
1536
+ } else {
1537
+ pr_warn ("Persistent clock returned invalid value" );
1538
+ wall_time = (struct timespec64 ){0 };
1544
1539
}
1545
1540
1541
+ if (timespec64_compare (& wall_time , & boot_offset ) < 0 )
1542
+ boot_offset = (struct timespec64 ){0 };
1543
+
1544
+ /*
1545
+ * We want set wall_to_mono, so the following is true:
1546
+ * wall time + wall_to_mono = boot time
1547
+ */
1548
+ wall_to_mono = timespec64_sub (boot_offset , wall_time );
1549
+
1546
1550
raw_spin_lock_irqsave (& timekeeper_lock , flags );
1547
1551
write_seqcount_begin (& tk_core .seq );
1548
1552
ntp_init ();
@@ -1552,13 +1556,10 @@ void __init timekeeping_init(void)
1552
1556
clock -> enable (clock );
1553
1557
tk_setup_internals (tk , clock );
1554
1558
1555
- tk_set_xtime (tk , & now );
1559
+ tk_set_xtime (tk , & wall_time );
1556
1560
tk -> raw_sec = 0 ;
1557
- if (boot .tv_sec == 0 && boot .tv_nsec == 0 )
1558
- boot = tk_xtime (tk );
1559
1561
1560
- set_normalized_timespec64 (& tmp , - boot .tv_sec , - boot .tv_nsec );
1561
- tk_set_wall_to_mono (tk , tmp );
1562
+ tk_set_wall_to_mono (tk , wall_to_mono );
1562
1563
1563
1564
timekeeping_update (tk , TK_MIRROR | TK_CLOCK_WAS_SET );
1564
1565
0 commit comments