Skip to content

Commit b4a871c

Browse files
superm1roxanan1996
authored andcommitted
rtc: Add support for configuring the UIP timeout for RTC reads
BugLink: https://bugs.launchpad.net/bugs/2059068 commit 120931d upstream. 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: ec5895c ("rtc: mc146818-lib: extract mc146818_avoid_UIP") Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> Tested-by: Mateusz Jończyk <mat.jonczyk@o2.pl> Reviewed-by: Mateusz Jończyk <mat.jonczyk@o2.pl> Acked-by: Mateusz Jończyk <mat.jonczyk@o2.pl> Link: https://lore.kernel.org/r/20231128053653.101798-4-mario.limonciello@amd.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Portia Stephens <portia.stephens@canonical.com> Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
1 parent 4d4d5c4 commit b4a871c

7 files changed

Lines changed: 38 additions & 16 deletions

File tree

arch/alpha/kernel/rtc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ init_rtc_epoch(void)
8080
static int
8181
alpha_rtc_read_time(struct device *dev, struct rtc_time *tm)
8282
{
83-
int ret = mc146818_get_time(tm);
83+
int ret = mc146818_get_time(tm, 10);
8484

8585
if (ret < 0) {
8686
dev_err_ratelimited(dev, "unable to read current time\n");

arch/x86/kernel/hpet.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1438,7 +1438,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
14381438
memset(&curr_time, 0, sizeof(struct rtc_time));
14391439

14401440
if (hpet_rtc_flags & (RTC_UIE | RTC_AIE)) {
1441-
if (unlikely(mc146818_get_time(&curr_time) < 0)) {
1441+
if (unlikely(mc146818_get_time(&curr_time, 10) < 0)) {
14421442
pr_err_ratelimited("unable to read current time from RTC\n");
14431443
return IRQ_HANDLED;
14441444
}

arch/x86/kernel/rtc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ void mach_get_cmos_time(struct timespec64 *now)
6767
return;
6868
}
6969

70-
if (mc146818_get_time(&tm)) {
70+
if (mc146818_get_time(&tm, 10)) {
7171
pr_err("Unable to read current time from RTC\n");
7272
now->tv_sec = now->tv_nsec = 0;
7373
return;

drivers/base/power/trace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ static unsigned int read_magic_time(void)
120120
struct rtc_time time;
121121
unsigned int val;
122122

123-
if (mc146818_get_time(&time) < 0) {
123+
if (mc146818_get_time(&time, 10) < 0) {
124124
pr_err("Unable to read current time from RTC\n");
125125
return 0;
126126
}

drivers/rtc/rtc-cmos.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ static int cmos_read_time(struct device *dev, struct rtc_time *t)
231231
if (!pm_trace_rtc_valid())
232232
return -EIO;
233233

234-
ret = mc146818_get_time(t);
234+
ret = mc146818_get_time(t, 10);
235235
if (ret < 0) {
236236
dev_err_ratelimited(dev, "unable to read current time\n");
237237
return ret;
@@ -307,7 +307,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
307307
*
308308
* Use the mc146818_avoid_UIP() function to avoid this.
309309
*/
310-
if (!mc146818_avoid_UIP(cmos_read_alarm_callback, &p))
310+
if (!mc146818_avoid_UIP(cmos_read_alarm_callback, 10, &p))
311311
return -EIO;
312312

313313
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)
556556
*
557557
* Use mc146818_avoid_UIP() to avoid this.
558558
*/
559-
if (!mc146818_avoid_UIP(cmos_set_alarm_callback, &p))
559+
if (!mc146818_avoid_UIP(cmos_set_alarm_callback, 10, &p))
560560
return -ETIMEDOUT;
561561

562562
cmos->alarm_expires = rtc_tm_to_time64(&t->time);

drivers/rtc/rtc-mc146818-lib.c

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,31 @@
88
#include <linux/acpi.h>
99
#endif
1010

11+
#define UIP_RECHECK_DELAY 100 /* usec */
12+
#define UIP_RECHECK_DELAY_MS (USEC_PER_MSEC / UIP_RECHECK_DELAY)
13+
#define UIP_RECHECK_LOOPS_MS(x) (x / UIP_RECHECK_DELAY_MS)
14+
1115
/*
1216
* Execute a function while the UIP (Update-in-progress) bit of the RTC is
13-
* unset.
17+
* unset. The timeout is configurable by the caller in ms.
1418
*
1519
* Warning: callback may be executed more then once.
1620
*/
1721
bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
22+
int timeout,
1823
void *param)
1924
{
2025
int i;
2126
unsigned long flags;
2227
unsigned char seconds;
2328

24-
for (i = 0; i < 100; i++) {
29+
for (i = 0; UIP_RECHECK_LOOPS_MS(i) < timeout; i++) {
2530
spin_lock_irqsave(&rtc_lock, flags);
2631

2732
/*
2833
* Check whether there is an update in progress during which the
2934
* readout is unspecified. The maximum update time is ~2ms. Poll
30-
* every 100 usec for completion.
35+
* for completion.
3136
*
3237
* Store the second value before checking UIP so a long lasting
3338
* 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),
3742

3843
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
3944
spin_unlock_irqrestore(&rtc_lock, flags);
40-
udelay(100);
45+
udelay(UIP_RECHECK_DELAY);
4146
continue;
4247
}
4348

@@ -56,7 +61,7 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
5661
*/
5762
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
5863
spin_unlock_irqrestore(&rtc_lock, flags);
59-
udelay(100);
64+
udelay(UIP_RECHECK_DELAY);
6065
continue;
6166
}
6267

@@ -72,6 +77,10 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
7277
}
7378
spin_unlock_irqrestore(&rtc_lock, flags);
7479

80+
if (UIP_RECHECK_LOOPS_MS(i) >= 100)
81+
pr_warn("Reading current time from RTC took around %li ms\n",
82+
UIP_RECHECK_LOOPS_MS(i));
83+
7584
return true;
7685
}
7786
return false;
@@ -84,7 +93,7 @@ EXPORT_SYMBOL_GPL(mc146818_avoid_UIP);
8493
*/
8594
bool mc146818_does_rtc_work(void)
8695
{
87-
return mc146818_avoid_UIP(NULL, NULL);
96+
return mc146818_avoid_UIP(NULL, 10, NULL);
8897
}
8998
EXPORT_SYMBOL_GPL(mc146818_does_rtc_work);
9099

@@ -130,13 +139,25 @@ static void mc146818_get_time_callback(unsigned char seconds, void *param_in)
130139
p->ctrl = CMOS_READ(RTC_CONTROL);
131140
}
132141

133-
int mc146818_get_time(struct rtc_time *time)
142+
/**
143+
* mc146818_get_time - Get the current time from the RTC
144+
* @time: pointer to struct rtc_time to store the current time
145+
* @timeout: timeout value in ms
146+
*
147+
* This function reads the current time from the RTC and stores it in the
148+
* provided struct rtc_time. The timeout parameter specifies the maximum
149+
* time to wait for the RTC to become ready.
150+
*
151+
* Return: 0 on success, -ETIMEDOUT if the RTC did not become ready within
152+
* the specified timeout, or another error code if an error occurred.
153+
*/
154+
int mc146818_get_time(struct rtc_time *time, int timeout)
134155
{
135156
struct mc146818_get_time_callback_param p = {
136157
.time = time
137158
};
138159

139-
if (!mc146818_avoid_UIP(mc146818_get_time_callback, &p)) {
160+
if (!mc146818_avoid_UIP(mc146818_get_time_callback, timeout, &p)) {
140161
memset(time, 0, sizeof(*time));
141162
return -ETIMEDOUT;
142163
}

include/linux/mc146818rtc.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,11 @@ struct cmos_rtc_board_info {
126126
#endif /* ARCH_RTC_LOCATION */
127127

128128
bool mc146818_does_rtc_work(void);
129-
int mc146818_get_time(struct rtc_time *time);
129+
int mc146818_get_time(struct rtc_time *time, int timeout);
130130
int mc146818_set_time(struct rtc_time *time);
131131

132132
bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
133+
int timeout,
133134
void *param);
134135

135136
#endif /* _MC146818RTC_H */

0 commit comments

Comments
 (0)