1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/kernel.h> 3 #include <linux/time.h> 4 #include <linux/timer.h> 5 #include <linux/init.h> 6 #include <linux/rtc.h> 7 #include <linux/delay.h> 8 #include <linux/ratelimit.h> 9 #include <asm/rtas.h> 10 #include <asm/time.h> 11 12 13 #define MAX_RTC_WAIT 5000 /* 5 sec */ 14 15 time64_t __init rtas_get_boot_time(void) 16 { 17 int ret[8]; 18 int error; 19 unsigned int wait_time; 20 u64 max_wait_tb; 21 22 max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; 23 do { 24 error = rtas_call(rtas_function_token(RTAS_FN_GET_TIME_OF_DAY), 0, 8, ret); 25 26 wait_time = rtas_busy_delay_time(error); 27 if (wait_time) { 28 /* This is boot time so we spin. */ 29 udelay(wait_time*1000); 30 } 31 } while (wait_time && (get_tb() < max_wait_tb)); 32 33 if (error != 0) { 34 printk_ratelimited(KERN_WARNING 35 "error: reading the clock failed (%d)\n", 36 error); 37 return 0; 38 } 39 40 return mktime64(ret[0], ret[1], ret[2], ret[3], ret[4], ret[5]); 41 } 42 43 /* NOTE: get_rtc_time will get an error if executed in interrupt context 44 * and if a delay is needed to read the clock. In this case we just 45 * silently return without updating rtc_tm. 46 */ 47 void rtas_get_rtc_time(struct rtc_time *rtc_tm) 48 { 49 int ret[8]; 50 int error; 51 unsigned int wait_time; 52 u64 max_wait_tb; 53 54 max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; 55 do { 56 error = rtas_call(rtas_function_token(RTAS_FN_GET_TIME_OF_DAY), 0, 8, ret); 57 58 wait_time = rtas_busy_delay_time(error); 59 if (wait_time) { 60 if (in_interrupt()) { 61 memset(rtc_tm, 0, sizeof(struct rtc_time)); 62 printk_ratelimited(KERN_WARNING 63 "error: reading clock " 64 "would delay interrupt\n"); 65 return; /* delay not allowed */ 66 } 67 msleep(wait_time); 68 } 69 } while (wait_time && (get_tb() < max_wait_tb)); 70 71 if (error != 0) { 72 printk_ratelimited(KERN_WARNING 73 "error: reading the clock failed (%d)\n", 74 error); 75 return; 76 } 77 78 rtc_tm->tm_sec = ret[5]; 79 rtc_tm->tm_min = ret[4]; 80 rtc_tm->tm_hour = ret[3]; 81 rtc_tm->tm_mday = ret[2]; 82 rtc_tm->tm_mon = ret[1] - 1; 83 rtc_tm->tm_year = ret[0] - 1900; 84 } 85 86 int rtas_set_rtc_time(struct rtc_time *tm) 87 { 88 int error, wait_time; 89 u64 max_wait_tb; 90 91 max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; 92 do { 93 error = rtas_call(rtas_function_token(RTAS_FN_SET_TIME_OF_DAY), 7, 1, NULL, 94 tm->tm_year + 1900, tm->tm_mon + 1, 95 tm->tm_mday, tm->tm_hour, tm->tm_min, 96 tm->tm_sec, 0); 97 98 wait_time = rtas_busy_delay_time(error); 99 if (wait_time) { 100 if (in_interrupt()) 101 return 1; /* probably decrementer */ 102 msleep(wait_time); 103 } 104 } while (wait_time && (get_tb() < max_wait_tb)); 105 106 if (error != 0) 107 printk_ratelimited(KERN_WARNING 108 "error: setting the clock failed (%d)\n", 109 error); 110 111 return 0; 112 } 113
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.