Message ID | 20231127192553.9734-4-mario.limonciello@amd.com |
---|---|
State | Superseded |
Headers | show |
Series | Extend time to wait for UIP for some callers | expand |
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
diff --git a/arch/alpha/kernel/rtc.c b/arch/alpha/kernel/rtc.c index fb3025396ac9..cfdf90bc8b3f 100644 --- a/arch/alpha/kernel/rtc.c +++ b/arch/alpha/kernel/rtc.c @@ -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"); diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 41eecf180b7f..17adad4cbe78 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -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; } diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c index 1309b9b05338..961ebc7f1872 100644 --- a/arch/x86/kernel/rtc.c +++ b/arch/x86/kernel/rtc.c @@ -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; diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c index 72b7a92337b1..c2e925357474 100644 --- a/drivers/base/power/trace.c +++ b/drivers/base/power/trace.c @@ -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; } diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 391f91d3d144..d278b085821e 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -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); 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++) { 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; } diff --git a/include/linux/mc146818rtc.h b/include/linux/mc146818rtc.h index b0da04fe087b..34dfcc77f505 100644 --- a/include/linux/mc146818rtc.h +++ b/include/linux/mc146818rtc.h @@ -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 */
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(-)