Loading drivers/rtc/rtc-cmos.c +51 −1 Original line number Diff line number Diff line Loading @@ -34,11 +34,11 @@ #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/platform_device.h> #include <linux/mod_devicetable.h> #include <linux/log2.h> #include <linux/pm.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/dmi.h> /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ #include <asm-generic/rtc.h> Loading Loading @@ -377,6 +377,51 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) return 0; } /* * Do not disable RTC alarm on shutdown - workaround for b0rked BIOSes. */ static bool alarm_disable_quirk; static int __init set_alarm_disable_quirk(const struct dmi_system_id *id) { alarm_disable_quirk = true; pr_info("rtc-cmos: BIOS has alarm-disable quirk. "); pr_info("RTC alarms disabled\n"); return 0; } static const struct dmi_system_id rtc_quirks[] __initconst = { /* https://bugzilla.novell.com/show_bug.cgi?id=805740 */ { .callback = set_alarm_disable_quirk, .ident = "IBM Truman", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "4852570"), }, }, /* https://bugzilla.novell.com/show_bug.cgi?id=812592 */ { .callback = set_alarm_disable_quirk, .ident = "Gigabyte GA-990XA-UD3", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Gigabyte Technology Co., Ltd."), DMI_MATCH(DMI_PRODUCT_NAME, "GA-990XA-UD3"), }, }, /* http://permalink.gmane.org/gmane.linux.kernel/1604474 */ { .callback = set_alarm_disable_quirk, .ident = "Toshiba Satellite L300", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L300"), }, }, {} }; static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct cmos_rtc *cmos = dev_get_drvdata(dev); Loading @@ -385,6 +430,9 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) if (!is_valid_irq(cmos->irq)) return -EINVAL; if (alarm_disable_quirk) return 0; spin_lock_irqsave(&rtc_lock, flags); if (enabled) Loading Loading @@ -1157,6 +1205,8 @@ static int __init cmos_init(void) platform_driver_registered = true; } dmi_check_system(rtc_quirks); if (retval == 0) return 0; Loading kernel/time/tick-common.c +1 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,7 @@ static void tick_periodic(int cpu) do_timer(1); write_sequnlock(&jiffies_lock); update_wall_time(); } update_process_times(user_mode(get_irq_regs())); Loading kernel/time/tick-internal.h +1 −0 Original line number Diff line number Diff line Loading @@ -155,3 +155,4 @@ static inline int tick_device_is_functional(struct clock_event_device *dev) #endif extern void do_timer(unsigned long ticks); extern void update_wall_time(void); kernel/time/tick-sched.c +1 −0 Original line number Diff line number Diff line Loading @@ -86,6 +86,7 @@ static void tick_do_update_jiffies64(ktime_t now) tick_next_period = ktime_add(last_jiffies_update, tick_period); } write_sequnlock(&jiffies_lock); update_wall_time(); } /* Loading kernel/time/timekeeping.c +26 −27 Original line number Diff line number Diff line Loading @@ -77,7 +77,7 @@ static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm) tk->wall_to_monotonic = wtm; set_normalized_timespec(&tmp, -wtm.tv_sec, -wtm.tv_nsec); tk->offs_real = timespec_to_ktime(tmp); tk->offs_tai = ktime_sub(tk->offs_real, ktime_set(tk->tai_offset, 0)); tk->offs_tai = ktime_add(tk->offs_real, ktime_set(tk->tai_offset, 0)); } static void tk_set_sleep_time(struct timekeeper *tk, struct timespec t) Loading @@ -90,8 +90,9 @@ static void tk_set_sleep_time(struct timekeeper *tk, struct timespec t) } /** * timekeeper_setup_internals - Set up internals to use clocksource clock. * tk_setup_internals - Set up internals to use clocksource clock. * * @tk: The target timekeeper to setup. * @clock: Pointer to clocksource. * * Calculates a fixed cycle/nsec interval for a given clocksource/adjustment Loading Loading @@ -595,7 +596,7 @@ s32 timekeeping_get_tai_offset(void) static void __timekeeping_set_tai_offset(struct timekeeper *tk, s32 tai_offset) { tk->tai_offset = tai_offset; tk->offs_tai = ktime_sub(tk->offs_real, ktime_set(tai_offset, 0)); tk->offs_tai = ktime_add(tk->offs_real, ktime_set(tai_offset, 0)); } /** Loading @@ -610,6 +611,7 @@ void timekeeping_set_tai_offset(s32 tai_offset) raw_spin_lock_irqsave(&timekeeper_lock, flags); write_seqcount_begin(&timekeeper_seq); __timekeeping_set_tai_offset(tk, tai_offset); timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); write_seqcount_end(&timekeeper_seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); clock_was_set(); Loading Loading @@ -1023,6 +1025,8 @@ static int timekeeping_suspend(void) timekeeping_suspend_time = timespec_add(timekeeping_suspend_time, delta_delta); } timekeeping_update(tk, TK_MIRROR); write_seqcount_end(&timekeeper_seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); Loading Loading @@ -1130,16 +1134,6 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset) * we can adjust by 1. */ error >>= 2; /* * XXX - In update_wall_time, we round up to the next * nanosecond, and store the amount rounded up into * the error. This causes the likely below to be unlikely. * * The proper fix is to avoid rounding up by using * the high precision tk->xtime_nsec instead of * xtime.tv_nsec everywhere. Fixing this will take some * time. */ if (likely(error <= interval)) adj = 1; else Loading Loading @@ -1255,7 +1249,7 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset) static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk) { u64 nsecps = (u64)NSEC_PER_SEC << tk->shift; unsigned int action = 0; unsigned int clock_set = 0; while (tk->xtime_nsec >= nsecps) { int leap; Loading @@ -1277,11 +1271,10 @@ static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk) __timekeeping_set_tai_offset(tk, tk->tai_offset - leap); clock_was_set_delayed(); action = TK_CLOCK_WAS_SET; clock_set = TK_CLOCK_WAS_SET; } } return action; return clock_set; } /** Loading @@ -1294,7 +1287,8 @@ static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk) * Returns the unconsumed cycles. */ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset, u32 shift) u32 shift, unsigned int *clock_set) { cycle_t interval = tk->cycle_interval << shift; u64 raw_nsecs; Loading @@ -1308,7 +1302,7 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset, tk->cycle_last += interval; tk->xtime_nsec += tk->xtime_interval << shift; accumulate_nsecs_to_secs(tk); *clock_set |= accumulate_nsecs_to_secs(tk); /* Accumulate raw time */ raw_nsecs = (u64)tk->raw_interval << shift; Loading Loading @@ -1359,14 +1353,14 @@ static inline void old_vsyscall_fixup(struct timekeeper *tk) * update_wall_time - Uses the current clocksource to increment the wall time * */ static void update_wall_time(void) void update_wall_time(void) { struct clocksource *clock; struct timekeeper *real_tk = &timekeeper; struct timekeeper *tk = &shadow_timekeeper; cycle_t offset; int shift = 0, maxshift; unsigned int action; unsigned int clock_set = 0; unsigned long flags; raw_spin_lock_irqsave(&timekeeper_lock, flags); Loading Loading @@ -1401,7 +1395,8 @@ static void update_wall_time(void) maxshift = (64 - (ilog2(ntp_tick_length())+1)) - 1; shift = min(shift, maxshift); while (offset >= tk->cycle_interval) { offset = logarithmic_accumulation(tk, offset, shift); offset = logarithmic_accumulation(tk, offset, shift, &clock_set); if (offset < tk->cycle_interval<<shift) shift--; } Loading @@ -1419,7 +1414,7 @@ static void update_wall_time(void) * Finally, make sure that after the rounding * xtime_nsec isn't larger than NSEC_PER_SEC */ action = accumulate_nsecs_to_secs(tk); clock_set |= accumulate_nsecs_to_secs(tk); write_seqcount_begin(&timekeeper_seq); /* Update clock->cycle_last with the new value */ Loading @@ -1435,10 +1430,12 @@ static void update_wall_time(void) * updating. */ memcpy(real_tk, tk, sizeof(*tk)); timekeeping_update(real_tk, action); timekeeping_update(real_tk, clock_set); write_seqcount_end(&timekeeper_seq); out: raw_spin_unlock_irqrestore(&timekeeper_lock, flags); if (clock_set) clock_was_set(); } /** Loading Loading @@ -1583,7 +1580,6 @@ struct timespec get_monotonic_coarse(void) void do_timer(unsigned long ticks) { jiffies_64 += ticks; update_wall_time(); calc_global_load(ticks); } Loading Loading @@ -1698,12 +1694,14 @@ int do_adjtimex(struct timex *txc) if (tai != orig_tai) { __timekeeping_set_tai_offset(tk, tai); update_pvclock_gtod(tk, true); clock_was_set_delayed(); timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); } write_seqcount_end(&timekeeper_seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); if (tai != orig_tai) clock_was_set(); ntp_notify_cmos_timer(); return ret; Loading Loading @@ -1739,4 +1737,5 @@ void xtime_update(unsigned long ticks) write_seqlock(&jiffies_lock); do_timer(ticks); write_sequnlock(&jiffies_lock); update_wall_time(); } Loading
drivers/rtc/rtc-cmos.c +51 −1 Original line number Diff line number Diff line Loading @@ -34,11 +34,11 @@ #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/platform_device.h> #include <linux/mod_devicetable.h> #include <linux/log2.h> #include <linux/pm.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/dmi.h> /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ #include <asm-generic/rtc.h> Loading Loading @@ -377,6 +377,51 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) return 0; } /* * Do not disable RTC alarm on shutdown - workaround for b0rked BIOSes. */ static bool alarm_disable_quirk; static int __init set_alarm_disable_quirk(const struct dmi_system_id *id) { alarm_disable_quirk = true; pr_info("rtc-cmos: BIOS has alarm-disable quirk. "); pr_info("RTC alarms disabled\n"); return 0; } static const struct dmi_system_id rtc_quirks[] __initconst = { /* https://bugzilla.novell.com/show_bug.cgi?id=805740 */ { .callback = set_alarm_disable_quirk, .ident = "IBM Truman", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "4852570"), }, }, /* https://bugzilla.novell.com/show_bug.cgi?id=812592 */ { .callback = set_alarm_disable_quirk, .ident = "Gigabyte GA-990XA-UD3", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Gigabyte Technology Co., Ltd."), DMI_MATCH(DMI_PRODUCT_NAME, "GA-990XA-UD3"), }, }, /* http://permalink.gmane.org/gmane.linux.kernel/1604474 */ { .callback = set_alarm_disable_quirk, .ident = "Toshiba Satellite L300", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L300"), }, }, {} }; static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct cmos_rtc *cmos = dev_get_drvdata(dev); Loading @@ -385,6 +430,9 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) if (!is_valid_irq(cmos->irq)) return -EINVAL; if (alarm_disable_quirk) return 0; spin_lock_irqsave(&rtc_lock, flags); if (enabled) Loading Loading @@ -1157,6 +1205,8 @@ static int __init cmos_init(void) platform_driver_registered = true; } dmi_check_system(rtc_quirks); if (retval == 0) return 0; Loading
kernel/time/tick-common.c +1 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,7 @@ static void tick_periodic(int cpu) do_timer(1); write_sequnlock(&jiffies_lock); update_wall_time(); } update_process_times(user_mode(get_irq_regs())); Loading
kernel/time/tick-internal.h +1 −0 Original line number Diff line number Diff line Loading @@ -155,3 +155,4 @@ static inline int tick_device_is_functional(struct clock_event_device *dev) #endif extern void do_timer(unsigned long ticks); extern void update_wall_time(void);
kernel/time/tick-sched.c +1 −0 Original line number Diff line number Diff line Loading @@ -86,6 +86,7 @@ static void tick_do_update_jiffies64(ktime_t now) tick_next_period = ktime_add(last_jiffies_update, tick_period); } write_sequnlock(&jiffies_lock); update_wall_time(); } /* Loading
kernel/time/timekeeping.c +26 −27 Original line number Diff line number Diff line Loading @@ -77,7 +77,7 @@ static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm) tk->wall_to_monotonic = wtm; set_normalized_timespec(&tmp, -wtm.tv_sec, -wtm.tv_nsec); tk->offs_real = timespec_to_ktime(tmp); tk->offs_tai = ktime_sub(tk->offs_real, ktime_set(tk->tai_offset, 0)); tk->offs_tai = ktime_add(tk->offs_real, ktime_set(tk->tai_offset, 0)); } static void tk_set_sleep_time(struct timekeeper *tk, struct timespec t) Loading @@ -90,8 +90,9 @@ static void tk_set_sleep_time(struct timekeeper *tk, struct timespec t) } /** * timekeeper_setup_internals - Set up internals to use clocksource clock. * tk_setup_internals - Set up internals to use clocksource clock. * * @tk: The target timekeeper to setup. * @clock: Pointer to clocksource. * * Calculates a fixed cycle/nsec interval for a given clocksource/adjustment Loading Loading @@ -595,7 +596,7 @@ s32 timekeeping_get_tai_offset(void) static void __timekeeping_set_tai_offset(struct timekeeper *tk, s32 tai_offset) { tk->tai_offset = tai_offset; tk->offs_tai = ktime_sub(tk->offs_real, ktime_set(tai_offset, 0)); tk->offs_tai = ktime_add(tk->offs_real, ktime_set(tai_offset, 0)); } /** Loading @@ -610,6 +611,7 @@ void timekeeping_set_tai_offset(s32 tai_offset) raw_spin_lock_irqsave(&timekeeper_lock, flags); write_seqcount_begin(&timekeeper_seq); __timekeeping_set_tai_offset(tk, tai_offset); timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); write_seqcount_end(&timekeeper_seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); clock_was_set(); Loading Loading @@ -1023,6 +1025,8 @@ static int timekeeping_suspend(void) timekeeping_suspend_time = timespec_add(timekeeping_suspend_time, delta_delta); } timekeeping_update(tk, TK_MIRROR); write_seqcount_end(&timekeeper_seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); Loading Loading @@ -1130,16 +1134,6 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset) * we can adjust by 1. */ error >>= 2; /* * XXX - In update_wall_time, we round up to the next * nanosecond, and store the amount rounded up into * the error. This causes the likely below to be unlikely. * * The proper fix is to avoid rounding up by using * the high precision tk->xtime_nsec instead of * xtime.tv_nsec everywhere. Fixing this will take some * time. */ if (likely(error <= interval)) adj = 1; else Loading Loading @@ -1255,7 +1249,7 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset) static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk) { u64 nsecps = (u64)NSEC_PER_SEC << tk->shift; unsigned int action = 0; unsigned int clock_set = 0; while (tk->xtime_nsec >= nsecps) { int leap; Loading @@ -1277,11 +1271,10 @@ static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk) __timekeeping_set_tai_offset(tk, tk->tai_offset - leap); clock_was_set_delayed(); action = TK_CLOCK_WAS_SET; clock_set = TK_CLOCK_WAS_SET; } } return action; return clock_set; } /** Loading @@ -1294,7 +1287,8 @@ static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk) * Returns the unconsumed cycles. */ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset, u32 shift) u32 shift, unsigned int *clock_set) { cycle_t interval = tk->cycle_interval << shift; u64 raw_nsecs; Loading @@ -1308,7 +1302,7 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset, tk->cycle_last += interval; tk->xtime_nsec += tk->xtime_interval << shift; accumulate_nsecs_to_secs(tk); *clock_set |= accumulate_nsecs_to_secs(tk); /* Accumulate raw time */ raw_nsecs = (u64)tk->raw_interval << shift; Loading Loading @@ -1359,14 +1353,14 @@ static inline void old_vsyscall_fixup(struct timekeeper *tk) * update_wall_time - Uses the current clocksource to increment the wall time * */ static void update_wall_time(void) void update_wall_time(void) { struct clocksource *clock; struct timekeeper *real_tk = &timekeeper; struct timekeeper *tk = &shadow_timekeeper; cycle_t offset; int shift = 0, maxshift; unsigned int action; unsigned int clock_set = 0; unsigned long flags; raw_spin_lock_irqsave(&timekeeper_lock, flags); Loading Loading @@ -1401,7 +1395,8 @@ static void update_wall_time(void) maxshift = (64 - (ilog2(ntp_tick_length())+1)) - 1; shift = min(shift, maxshift); while (offset >= tk->cycle_interval) { offset = logarithmic_accumulation(tk, offset, shift); offset = logarithmic_accumulation(tk, offset, shift, &clock_set); if (offset < tk->cycle_interval<<shift) shift--; } Loading @@ -1419,7 +1414,7 @@ static void update_wall_time(void) * Finally, make sure that after the rounding * xtime_nsec isn't larger than NSEC_PER_SEC */ action = accumulate_nsecs_to_secs(tk); clock_set |= accumulate_nsecs_to_secs(tk); write_seqcount_begin(&timekeeper_seq); /* Update clock->cycle_last with the new value */ Loading @@ -1435,10 +1430,12 @@ static void update_wall_time(void) * updating. */ memcpy(real_tk, tk, sizeof(*tk)); timekeeping_update(real_tk, action); timekeeping_update(real_tk, clock_set); write_seqcount_end(&timekeeper_seq); out: raw_spin_unlock_irqrestore(&timekeeper_lock, flags); if (clock_set) clock_was_set(); } /** Loading Loading @@ -1583,7 +1580,6 @@ struct timespec get_monotonic_coarse(void) void do_timer(unsigned long ticks) { jiffies_64 += ticks; update_wall_time(); calc_global_load(ticks); } Loading Loading @@ -1698,12 +1694,14 @@ int do_adjtimex(struct timex *txc) if (tai != orig_tai) { __timekeeping_set_tai_offset(tk, tai); update_pvclock_gtod(tk, true); clock_was_set_delayed(); timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); } write_seqcount_end(&timekeeper_seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); if (tai != orig_tai) clock_was_set(); ntp_notify_cmos_timer(); return ret; Loading Loading @@ -1739,4 +1737,5 @@ void xtime_update(unsigned long ticks) write_seqlock(&jiffies_lock); do_timer(ticks); write_sequnlock(&jiffies_lock); update_wall_time(); }