[v3,3/4] rtc: Add support for configuring the UIP timeout for RTC reads
Commit Message
The UIP timeout is hardcoded to 10ms for all RTC reads, but in some
contexts this might not be enough time. Add a timeout parameter to
mc146818_get_time() and mc146818_get_time_callback().
If UIP timeout is configured by caller to be >=100 ms and a call
takes this long, log a warning.
Make all callers use 10ms to ensure no functional changes.
Cc: stable@vger.kernel.org # 6.1.y
Fixes: ec5895c0f2d8 ("rtc: mc146818-lib: extract mc146818_avoid_UIP")
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
v2->v3:
* Logic adjustments
* Clarify warning message
v1->v2:
* Add a warning if 100ms or more
* Add stable and fixes tags
---
arch/alpha/kernel/rtc.c | 2 +-
arch/x86/kernel/hpet.c | 2 +-
arch/x86/kernel/rtc.c | 2 +-
drivers/base/power/trace.c | 2 +-
drivers/rtc/rtc-cmos.c | 6 +++---
drivers/rtc/rtc-mc146818-lib.c | 37 ++++++++++++++++++++++++++--------
include/linux/mc146818rtc.h | 3 ++-
7 files changed, 38 insertions(+), 16 deletions(-)
Comments
W dniu 27.11.2023 o 20:25, Mario Limonciello pisze:
> The UIP timeout is hardcoded to 10ms for all RTC reads, but in some
> contexts this might not be enough time. Add a timeout parameter to
> mc146818_get_time() and mc146818_get_time_callback().
>
> If UIP timeout is configured by caller to be >=100 ms and a call
> takes this long, log a warning.
>
> Make all callers use 10ms to ensure no functional changes.
>
> Cc: stable@vger.kernel.org # 6.1.y
> Fixes: ec5895c0f2d8 ("rtc: mc146818-lib: extract mc146818_avoid_UIP")
> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
> ---
> v2->v3:
> * Logic adjustments
> * Clarify warning message
> v1->v2:
> * Add a warning if 100ms or more
> * Add stable and fixes tags
[snip]
> diff --git a/drivers/rtc/rtc-mc146818-lib.c b/drivers/rtc/rtc-mc146818-lib.c
> index 43a28e82674e..ab077dde397b 100644
> --- a/drivers/rtc/rtc-mc146818-lib.c
> +++ b/drivers/rtc/rtc-mc146818-lib.c
> @@ -8,26 +8,31 @@
> #include <linux/acpi.h>
> #endif
>
> +#define UIP_RECHECK_DELAY 100 /* usec */
> +#define UIP_RECHECK_DELAY_MS (USEC_PER_MSEC / UIP_RECHECK_DELAY)
> +#define UIP_RECHECK_TIMEOUT_MS(x) (x / UIP_RECHECK_DELAY_MS)
> +
> /*
> * Execute a function while the UIP (Update-in-progress) bit of the RTC is
> - * unset.
> + * unset. The timeout is configurable by the caller in ms.
> *
> * Warning: callback may be executed more then once.
> */
> bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
> + int timeout,
> void *param)
> {
> int i;
> unsigned long flags;
> unsigned char seconds;
>
> - for (i = 0; i < 100; i++) {
> + for (i = 0; i < UIP_RECHECK_TIMEOUT_MS(timeout); i++) {
Sorry, this will not work. UIP_RECHECK_DELAY_MS is 10, so
UIP_RECHECK_TIMEOUT_MS(timeout) will be 1 for timeout=10. Should be
for (i = 0; UIP_RECHECK_TIMEOUT_MS(i) < timeout; i++) {
With this, for i == 99, UIP_RECHECK_TIMEOUT_MS(i) = 9
for i == 100, UIP_RECHECK_TIMEOUT_MS(i) = 10 and the loop correctly terminates.
The macro should probably be renamed UIP_RECHECK_LOOPS_MS as it converts
loop count to ms.
> spin_lock_irqsave(&rtc_lock, flags);
>
> /*
> * Check whether there is an update in progress during which the
> * readout is unspecified. The maximum update time is ~2ms. Poll
> - * every 100 usec for completion.
> + * for completion.
> *
> * Store the second value before checking UIP so a long lasting
> * NMI which happens to hit after the UIP check cannot make
> @@ -37,7 +42,7 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
>
> if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
> spin_unlock_irqrestore(&rtc_lock, flags);
> - udelay(100);
> + udelay(UIP_RECHECK_DELAY);
> continue;
> }
>
> @@ -56,7 +61,7 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
> */
> if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
> spin_unlock_irqrestore(&rtc_lock, flags);
> - udelay(100);
> + udelay(UIP_RECHECK_DELAY);
> continue;
> }
>
> @@ -72,6 +77,10 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
> }
> spin_unlock_irqrestore(&rtc_lock, flags);
>
> + if (i >= UIP_RECHECK_TIMEOUT_MS(100))
Same, should be:
if (UIP_RECHECK_TIMEOUT_MS(i) >= 100)
> + pr_warn("Reading current time from RTC took around %d ms\n",
> + UIP_RECHECK_TIMEOUT_MS(i));
> +
> return true;
> }
> return false;
[snip]
Greetings,
Mateusz
On 11/27/2023 14:31, Mateusz Jończyk wrote:
> W dniu 27.11.2023 o 20:25, Mario Limonciello pisze:
>> The UIP timeout is hardcoded to 10ms for all RTC reads, but in some
>> contexts this might not be enough time. Add a timeout parameter to
>> mc146818_get_time() and mc146818_get_time_callback().
>>
>> If UIP timeout is configured by caller to be >=100 ms and a call
>> takes this long, log a warning.
>>
>> Make all callers use 10ms to ensure no functional changes.
>>
>> Cc: stable@vger.kernel.org # 6.1.y
>> Fixes: ec5895c0f2d8 ("rtc: mc146818-lib: extract mc146818_avoid_UIP")
>> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
>> ---
>> v2->v3:
>> * Logic adjustments
>> * Clarify warning message
>> v1->v2:
>> * Add a warning if 100ms or more
>> * Add stable and fixes tags
> [snip]
>> diff --git a/drivers/rtc/rtc-mc146818-lib.c b/drivers/rtc/rtc-mc146818-lib.c
>> index 43a28e82674e..ab077dde397b 100644
>> --- a/drivers/rtc/rtc-mc146818-lib.c
>> +++ b/drivers/rtc/rtc-mc146818-lib.c
>> @@ -8,26 +8,31 @@
>> #include <linux/acpi.h>
>> #endif
>>
>> +#define UIP_RECHECK_DELAY 100 /* usec */
>> +#define UIP_RECHECK_DELAY_MS (USEC_PER_MSEC / UIP_RECHECK_DELAY)
>> +#define UIP_RECHECK_TIMEOUT_MS(x) (x / UIP_RECHECK_DELAY_MS)
>> +
>> /*
>> * Execute a function while the UIP (Update-in-progress) bit of the RTC is
>> - * unset.
>> + * unset. The timeout is configurable by the caller in ms.
>> *
>> * Warning: callback may be executed more then once.
>> */
>> bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
>> + int timeout,
>> void *param)
>> {
>> int i;
>> unsigned long flags;
>> unsigned char seconds;
>>
>> - for (i = 0; i < 100; i++) {
>> + for (i = 0; i < UIP_RECHECK_TIMEOUT_MS(timeout); i++) {
>
> Sorry, this will not work. UIP_RECHECK_DELAY_MS is 10, so
> UIP_RECHECK_TIMEOUT_MS(timeout) will be 1 for timeout=10. Should be
>
> for (i = 0; UIP_RECHECK_TIMEOUT_MS(i) < timeout; i++) {
>
> With this, for i == 99, UIP_RECHECK_TIMEOUT_MS(i) = 9
> for i == 100, UIP_RECHECK_TIMEOUT_MS(i) = 10 and the loop correctly terminates.
>
> The macro should probably be renamed UIP_RECHECK_LOOPS_MS as it converts
> loop count to ms.
Got it; thanks for that.
>
>> spin_lock_irqsave(&rtc_lock, flags);
>>
>> /*
>> * Check whether there is an update in progress during which the
>> * readout is unspecified. The maximum update time is ~2ms. Poll
>> - * every 100 usec for completion.
>> + * for completion.
>> *
>> * Store the second value before checking UIP so a long lasting
>> * NMI which happens to hit after the UIP check cannot make
>> @@ -37,7 +42,7 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
>>
>> if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
>> spin_unlock_irqrestore(&rtc_lock, flags);
>> - udelay(100);
>> + udelay(UIP_RECHECK_DELAY);
>> continue;
>> }
>>
>> @@ -56,7 +61,7 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
>> */
>> if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
>> spin_unlock_irqrestore(&rtc_lock, flags);
>> - udelay(100);
>> + udelay(UIP_RECHECK_DELAY);
>> continue;
>> }
>>
>> @@ -72,6 +77,10 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
>> }
>> spin_unlock_irqrestore(&rtc_lock, flags);
>>
>> + if (i >= UIP_RECHECK_TIMEOUT_MS(100))
>
> Same, should be:
>
> if (UIP_RECHECK_TIMEOUT_MS(i) >= 100)
>
>> + pr_warn("Reading current time from RTC took around %d ms\n",
>> + UIP_RECHECK_TIMEOUT_MS(i));
>> +
>> return true;
>> }
>> return false;
>
> [snip]
>
> Greetings,
>
> Mateusz
>
>
Hi Mario,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 2cc14f52aeb78ce3f29677c2de1f06c0e91471ab]
url: https://github.com/intel-lab-lkp/linux/commits/Mario-Limonciello/rtc-mc146818-lib-Adjust-failure-return-code-for-mc146818_get_time/20231128-032825
base: 2cc14f52aeb78ce3f29677c2de1f06c0e91471ab
patch link: https://lore.kernel.org/r/20231127192553.9734-4-mario.limonciello%40amd.com
patch subject: [PATCH v3 3/4] rtc: Add support for configuring the UIP timeout for RTC reads
config: alpha-defconfig (https://download.01.org/0day-ci/archive/20231128/202311280605.EB8LQAVD-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231128/202311280605.EB8LQAVD-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202311280605.EB8LQAVD-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from include/asm-generic/bug.h:22,
from arch/alpha/include/asm/bug.h:23,
from include/linux/bug.h:5,
from include/linux/thread_info.h:13,
from include/asm-generic/current.h:6,
from ./arch/alpha/include/generated/asm/current.h:1,
from include/linux/sched.h:12,
from include/linux/delay.h:23,
from drivers/rtc/rtc-mc146818-lib.c:3:
drivers/rtc/rtc-mc146818-lib.c: In function 'mc146818_avoid_UIP':
>> include/linux/kern_levels.h:5:25: warning: format '%d' expects argument of type 'int', but argument 2 has type 'long int' [-Wformat=]
5 | #define KERN_SOH "\001" /* ASCII Start Of Header */
| ^~~~~~
include/linux/printk.h:427:25: note: in definition of macro 'printk_index_wrap'
427 | _p_func(_fmt, ##__VA_ARGS__); \
| ^~~~
include/linux/printk.h:508:9: note: in expansion of macro 'printk'
508 | printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
| ^~~~~~
include/linux/kern_levels.h:12:25: note: in expansion of macro 'KERN_SOH'
12 | #define KERN_WARNING KERN_SOH "4" /* warning conditions */
| ^~~~~~~~
include/linux/printk.h:508:16: note: in expansion of macro 'KERN_WARNING'
508 | printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
| ^~~~~~~~~~~~
drivers/rtc/rtc-mc146818-lib.c:81:25: note: in expansion of macro 'pr_warn'
81 | pr_warn("Reading current time from RTC took around %d ms\n",
| ^~~~~~~
vim +5 include/linux/kern_levels.h
314ba3520e513a Joe Perches 2012-07-30 4
04d2c8c83d0e3a Joe Perches 2012-07-30 @5 #define KERN_SOH "\001" /* ASCII Start Of Header */
04d2c8c83d0e3a Joe Perches 2012-07-30 6 #define KERN_SOH_ASCII '\001'
04d2c8c83d0e3a Joe Perches 2012-07-30 7
Hi Mario,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 2cc14f52aeb78ce3f29677c2de1f06c0e91471ab]
url: https://github.com/intel-lab-lkp/linux/commits/Mario-Limonciello/rtc-mc146818-lib-Adjust-failure-return-code-for-mc146818_get_time/20231128-032825
base: 2cc14f52aeb78ce3f29677c2de1f06c0e91471ab
patch link: https://lore.kernel.org/r/20231127192553.9734-4-mario.limonciello%40amd.com
patch subject: [PATCH v3 3/4] rtc: Add support for configuring the UIP timeout for RTC reads
config: i386-randconfig-141-20231128 (https://download.01.org/0day-ci/archive/20231128/202311280845.YrtuJ0eq-lkp@intel.com/config)
compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231128/202311280845.YrtuJ0eq-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202311280845.YrtuJ0eq-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/rtc/rtc-mc146818-lib.c:82:5: warning: format specifies type 'int' but the argument has type 'long' [-Wformat]
UIP_RECHECK_TIMEOUT_MS(i));
^~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/printk.h:508:37: note: expanded from macro 'pr_warn'
printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
~~~ ^~~~~~~~~~~
include/linux/printk.h:455:60: note: expanded from macro 'printk'
#define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
~~~ ^~~~~~~~~~~
include/linux/printk.h:427:19: note: expanded from macro 'printk_index_wrap'
_p_func(_fmt, ##__VA_ARGS__); \
~~~~ ^~~~~~~~~~~
drivers/rtc/rtc-mc146818-lib.c:13:35: note: expanded from macro 'UIP_RECHECK_TIMEOUT_MS'
#define UIP_RECHECK_TIMEOUT_MS(x) (x / UIP_RECHECK_DELAY_MS)
^~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
vim +82 drivers/rtc/rtc-mc146818-lib.c
14
15 /*
16 * Execute a function while the UIP (Update-in-progress) bit of the RTC is
17 * unset. The timeout is configurable by the caller in ms.
18 *
19 * Warning: callback may be executed more then once.
20 */
21 bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
22 int timeout,
23 void *param)
24 {
25 int i;
26 unsigned long flags;
27 unsigned char seconds;
28
29 for (i = 0; i < UIP_RECHECK_TIMEOUT_MS(timeout); i++) {
30 spin_lock_irqsave(&rtc_lock, flags);
31
32 /*
33 * Check whether there is an update in progress during which the
34 * readout is unspecified. The maximum update time is ~2ms. Poll
35 * for completion.
36 *
37 * Store the second value before checking UIP so a long lasting
38 * NMI which happens to hit after the UIP check cannot make
39 * an update cycle invisible.
40 */
41 seconds = CMOS_READ(RTC_SECONDS);
42
43 if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
44 spin_unlock_irqrestore(&rtc_lock, flags);
45 udelay(UIP_RECHECK_DELAY);
46 continue;
47 }
48
49 /* Revalidate the above readout */
50 if (seconds != CMOS_READ(RTC_SECONDS)) {
51 spin_unlock_irqrestore(&rtc_lock, flags);
52 continue;
53 }
54
55 if (callback)
56 callback(seconds, param);
57
58 /*
59 * Check for the UIP bit again. If it is set now then
60 * the above values may contain garbage.
61 */
62 if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
63 spin_unlock_irqrestore(&rtc_lock, flags);
64 udelay(UIP_RECHECK_DELAY);
65 continue;
66 }
67
68 /*
69 * A NMI might have interrupted the above sequence so check
70 * whether the seconds value has changed which indicates that
71 * the NMI took longer than the UIP bit was set. Unlikely, but
72 * possible and there is also virt...
73 */
74 if (seconds != CMOS_READ(RTC_SECONDS)) {
75 spin_unlock_irqrestore(&rtc_lock, flags);
76 continue;
77 }
78 spin_unlock_irqrestore(&rtc_lock, flags);
79
80 if (i >= UIP_RECHECK_TIMEOUT_MS(100))
81 pr_warn("Reading current time from RTC took around %d ms\n",
> 82 UIP_RECHECK_TIMEOUT_MS(i));
83
84 return true;
85 }
86 return false;
87 }
88 EXPORT_SYMBOL_GPL(mc146818_avoid_UIP);
89
@@ -80,7 +80,7 @@ init_rtc_epoch(void)
static int
alpha_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
- int ret = mc146818_get_time(tm);
+ int ret = mc146818_get_time(tm, 10);
if (ret < 0) {
dev_err_ratelimited(dev, "unable to read current time\n");
@@ -1438,7 +1438,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
memset(&curr_time, 0, sizeof(struct rtc_time));
if (hpet_rtc_flags & (RTC_UIE | RTC_AIE)) {
- if (unlikely(mc146818_get_time(&curr_time) < 0)) {
+ if (unlikely(mc146818_get_time(&curr_time, 10) < 0)) {
pr_err_ratelimited("unable to read current time from RTC\n");
return IRQ_HANDLED;
}
@@ -67,7 +67,7 @@ void mach_get_cmos_time(struct timespec64 *now)
return;
}
- if (mc146818_get_time(&tm)) {
+ if (mc146818_get_time(&tm, 10)) {
pr_err("Unable to read current time from RTC\n");
now->tv_sec = now->tv_nsec = 0;
return;
@@ -120,7 +120,7 @@ static unsigned int read_magic_time(void)
struct rtc_time time;
unsigned int val;
- if (mc146818_get_time(&time) < 0) {
+ if (mc146818_get_time(&time, 10) < 0) {
pr_err("Unable to read current time from RTC\n");
return 0;
}
@@ -231,7 +231,7 @@ static int cmos_read_time(struct device *dev, struct rtc_time *t)
if (!pm_trace_rtc_valid())
return -EIO;
- ret = mc146818_get_time(t);
+ ret = mc146818_get_time(t, 10);
if (ret < 0) {
dev_err_ratelimited(dev, "unable to read current time\n");
return ret;
@@ -307,7 +307,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
*
* Use the mc146818_avoid_UIP() function to avoid this.
*/
- if (!mc146818_avoid_UIP(cmos_read_alarm_callback, &p))
+ if (!mc146818_avoid_UIP(cmos_read_alarm_callback, 10, &p))
return -EIO;
if (!(p.rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
@@ -556,7 +556,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
*
* Use mc146818_avoid_UIP() to avoid this.
*/
- if (!mc146818_avoid_UIP(cmos_set_alarm_callback, &p))
+ if (!mc146818_avoid_UIP(cmos_set_alarm_callback, 10, &p))
return -ETIMEDOUT;
cmos->alarm_expires = rtc_tm_to_time64(&t->time);
@@ -8,26 +8,31 @@
#include <linux/acpi.h>
#endif
+#define UIP_RECHECK_DELAY 100 /* usec */
+#define UIP_RECHECK_DELAY_MS (USEC_PER_MSEC / UIP_RECHECK_DELAY)
+#define UIP_RECHECK_TIMEOUT_MS(x) (x / UIP_RECHECK_DELAY_MS)
+
/*
* Execute a function while the UIP (Update-in-progress) bit of the RTC is
- * unset.
+ * unset. The timeout is configurable by the caller in ms.
*
* Warning: callback may be executed more then once.
*/
bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
+ int timeout,
void *param)
{
int i;
unsigned long flags;
unsigned char seconds;
- for (i = 0; i < 100; i++) {
+ for (i = 0; i < UIP_RECHECK_TIMEOUT_MS(timeout); i++) {
spin_lock_irqsave(&rtc_lock, flags);
/*
* Check whether there is an update in progress during which the
* readout is unspecified. The maximum update time is ~2ms. Poll
- * every 100 usec for completion.
+ * for completion.
*
* Store the second value before checking UIP so a long lasting
* NMI which happens to hit after the UIP check cannot make
@@ -37,7 +42,7 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
spin_unlock_irqrestore(&rtc_lock, flags);
- udelay(100);
+ udelay(UIP_RECHECK_DELAY);
continue;
}
@@ -56,7 +61,7 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
*/
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
spin_unlock_irqrestore(&rtc_lock, flags);
- udelay(100);
+ udelay(UIP_RECHECK_DELAY);
continue;
}
@@ -72,6 +77,10 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
}
spin_unlock_irqrestore(&rtc_lock, flags);
+ if (i >= UIP_RECHECK_TIMEOUT_MS(100))
+ pr_warn("Reading current time from RTC took around %d ms\n",
+ UIP_RECHECK_TIMEOUT_MS(i));
+
return true;
}
return false;
@@ -84,7 +93,7 @@ EXPORT_SYMBOL_GPL(mc146818_avoid_UIP);
*/
bool mc146818_does_rtc_work(void)
{
- return mc146818_avoid_UIP(NULL, NULL);
+ return mc146818_avoid_UIP(NULL, 10, NULL);
}
EXPORT_SYMBOL_GPL(mc146818_does_rtc_work);
@@ -130,13 +139,25 @@ static void mc146818_get_time_callback(unsigned char seconds, void *param_in)
p->ctrl = CMOS_READ(RTC_CONTROL);
}
-int mc146818_get_time(struct rtc_time *time)
+/**
+ * mc146818_get_time - Get the current time from the RTC
+ * @time: pointer to struct rtc_time to store the current time
+ * @timeout: timeout value in ms
+ *
+ * This function reads the current time from the RTC and stores it in the
+ * provided struct rtc_time. The timeout parameter specifies the maximum
+ * time to wait for the RTC to become ready.
+ *
+ * Return: 0 on success, -ETIMEDOUT if the RTC did not become ready within
+ * the specified timeout, or another error code if an error occurred.
+ */
+int mc146818_get_time(struct rtc_time *time, int timeout)
{
struct mc146818_get_time_callback_param p = {
.time = time
};
- if (!mc146818_avoid_UIP(mc146818_get_time_callback, &p)) {
+ if (!mc146818_avoid_UIP(mc146818_get_time_callback, timeout, &p)) {
memset(time, 0, sizeof(*time));
return -ETIMEDOUT;
}
@@ -126,10 +126,11 @@ struct cmos_rtc_board_info {
#endif /* ARCH_RTC_LOCATION */
bool mc146818_does_rtc_work(void);
-int mc146818_get_time(struct rtc_time *time);
+int mc146818_get_time(struct rtc_time *time, int timeout);
int mc146818_set_time(struct rtc_time *time);
bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
+ int timeout,
void *param);
#endif /* _MC146818RTC_H */