Skip to content

Commit 120931d

Browse files
superm1alexandrebelloni
authored andcommitted
rtc: Add support for configuring the UIP timeout for RTC reads
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>
1 parent 1311a8f commit 120931d

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)