forked from Minki/linux
rtc: sun6i: Fix time overflow handling
Using "unsigned long" for UNIX timestamps is never a good idea, and comparing the value of such a variable against U32_MAX does not do anything useful on 32-bit systems. Use the proper time64_t type when dealing with timestamps, and avoid cutting down the time range unnecessarily. This also fixes the flawed check for the alarm time being too far into the future. The check for this condition is actually somewhat theoretical, as the RTC counts till 2033 only anyways, and 2^32 seconds from now is not before the year 2157 - at which point I hope nobody will be using this hardware anymore. Signed-off-by: Andre Przywara <andre.przywara@arm.com> Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com> Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Link: https://lore.kernel.org/r/20220211122643.1343315-4-andre.przywara@arm.com
This commit is contained in:
parent
ea6af39f3d
commit
9f6cd82eca
@ -138,7 +138,7 @@ struct sun6i_rtc_dev {
|
|||||||
const struct sun6i_rtc_clk_data *data;
|
const struct sun6i_rtc_clk_data *data;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
int irq;
|
int irq;
|
||||||
unsigned long alarm;
|
time64_t alarm;
|
||||||
|
|
||||||
struct clk_hw hw;
|
struct clk_hw hw;
|
||||||
struct clk_hw *int_osc;
|
struct clk_hw *int_osc;
|
||||||
@ -510,10 +510,8 @@ static int sun6i_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
|||||||
struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
|
struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
|
||||||
struct rtc_time *alrm_tm = &wkalrm->time;
|
struct rtc_time *alrm_tm = &wkalrm->time;
|
||||||
struct rtc_time tm_now;
|
struct rtc_time tm_now;
|
||||||
unsigned long time_now = 0;
|
time64_t time_now, time_set;
|
||||||
unsigned long time_set = 0;
|
int ret;
|
||||||
unsigned long time_gap = 0;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
ret = sun6i_rtc_gettime(dev, &tm_now);
|
ret = sun6i_rtc_gettime(dev, &tm_now);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@ -528,9 +526,7 @@ static int sun6i_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
time_gap = time_set - time_now;
|
if ((time_set - time_now) > U32_MAX) {
|
||||||
|
|
||||||
if (time_gap > U32_MAX) {
|
|
||||||
dev_err(dev, "Date too far in the future\n");
|
dev_err(dev, "Date too far in the future\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -539,7 +535,7 @@ static int sun6i_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
|||||||
writel(0, chip->base + SUN6I_ALRM_COUNTER);
|
writel(0, chip->base + SUN6I_ALRM_COUNTER);
|
||||||
usleep_range(100, 300);
|
usleep_range(100, 300);
|
||||||
|
|
||||||
writel(time_gap, chip->base + SUN6I_ALRM_COUNTER);
|
writel(time_set - time_now, chip->base + SUN6I_ALRM_COUNTER);
|
||||||
chip->alarm = time_set;
|
chip->alarm = time_set;
|
||||||
|
|
||||||
sun6i_rtc_setaie(wkalrm->enabled, chip);
|
sun6i_rtc_setaie(wkalrm->enabled, chip);
|
||||||
|
Loading…
Reference in New Issue
Block a user