---------------------------------------
Required properties:
-- compatible: Should be either "marvell,armada-370-timer" or
- "marvell,armada-xp-timer" as appropriate.
+- compatible: Should be one of the following
+ "marvell,armada-370-timer",
+ "marvell,armada-375-timer",
+ "marvell,armada-xp-timer".
- interrupts: Should contain the list of Global Timer interrupts and
then local timer interrupts
- reg: Should contain location and length for timers register. First
Clocks required for compatible = "marvell,armada-370-timer":
- clocks : Must contain a single entry describing the clock input
-Clocks required for compatible = "marvell,armada-xp-timer":
+Clocks required for compatibles = "marvell,armada-xp-timer",
+ "marvell,armada-375-timer":
- clocks : Must contain an entry for each entry in clock-names.
- clock-names : Must include the following entries:
"nbclk" (L2/coherency fabric clock),
- reg : A third entry is mandatory and should contain the
shared mask/unmask RSTOUT address.
+Clocks required for compatibles = "marvell,orion-wdt",
+ "marvell,armada-370-wdt":
+- clocks : Must contain a single entry describing the clock input
+
+Clocks required for compatibles = "marvell,armada-xp-wdt"
+ "marvell,armada-375-wdt"
+ "marvell,armada-380-wdt":
+- clocks : Must contain an entry for each entry in clock-names.
+- clock-names : Must include the following entries:
+ "nbclk" (L2/coherency fabric clock),
+ "fixed" (Reference 25 MHz fixed-clock).
+
Optional properties:
- interrupts : Contains the IRQ for watchdog expiration
interrupts = <3>;
timeout-sec = <10>;
status = "okay";
+ clocks = <&gate_clk 7>;
};
/* The 25Mhz fixed clock is mandatory, and must always be available */
BUG_ON(IS_ERR(clk));
+ clk_prepare_enable(clk);
timer_clk = clk_get_rate(clk);
armada_370_xp_timer_common_init(np);
CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer",
armada_xp_timer_init);
+static void __init armada_375_timer_init(struct device_node *np)
+{
+ struct clk *clk;
+
+ clk = of_clk_get_by_name(np, "fixed");
+ if (!IS_ERR(clk)) {
+ clk_prepare_enable(clk);
+ timer_clk = clk_get_rate(clk);
+ } else {
+
+ /*
+ * This fallback is required in order to retain proper
+ * devicetree backwards compatibility.
+ */
+ clk = of_clk_get(np, 0);
+
+ /* Must have at least a clock */
+ BUG_ON(IS_ERR(clk));
+ clk_prepare_enable(clk);
+ timer_clk = clk_get_rate(clk) / TIMER_DIVIDER;
+ timer25Mhz = false;
+ }
+
+ armada_370_xp_timer_common_init(np);
+}
+CLOCKSOURCE_OF_DECLARE(armada_375, "marvell,armada-375-timer",
+ armada_375_timer_init);
+
static void __init armada_370_timer_init(struct device_node *np)
{
struct clk *clk = of_clk_get(np, 0);
BUG_ON(IS_ERR(clk));
+ clk_prepare_enable(clk);
timer_clk = clk_get_rate(clk) / TIMER_DIVIDER;
timer25Mhz = false;
#include <linux/of_address.h>
#include <linux/sched_clock.h>
-#define MARCO_CLOCK_FREQ 1000000
-
#define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000
#define SIRFSOC_TIMER_32COUNTER_1_CTRL 0x0004
#define SIRFSOC_TIMER_MATCH_0 0x0018
#define SIRFSOC_TIMER_REG_CNT 6
+static unsigned long marco_timer_rate;
+
static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
SIRFSOC_TIMER_WATCHDOG_EN,
SIRFSOC_TIMER_32COUNTER_0_CTRL,
ce->rating = 200;
ce->set_mode = sirfsoc_timer_set_mode;
ce->set_next_event = sirfsoc_timer_set_next_event;
- clockevents_calc_mult_shift(ce, MARCO_CLOCK_FREQ, 60);
+ clockevents_calc_mult_shift(ce, marco_timer_rate, 60);
ce->max_delta_ns = clockevent_delta2ns(-2, ce);
ce->min_delta_ns = clockevent_delta2ns(2, ce);
ce->cpumask = cpumask_of(cpu);
/* initialize the kernel jiffy timer source */
static void __init sirfsoc_marco_timer_init(struct device_node *np)
{
- unsigned long rate;
u32 timer_div;
struct clk *clk;
BUG_ON(clk_prepare_enable(clk));
- rate = clk_get_rate(clk);
-
- BUG_ON(rate < MARCO_CLOCK_FREQ);
- BUG_ON(rate % MARCO_CLOCK_FREQ);
+ marco_timer_rate = clk_get_rate(clk);
- /* Initialize the timer dividers */
- timer_div = rate / MARCO_CLOCK_FREQ - 1;
- writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
- writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL);
- writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL);
+ /* timer dividers: 0, not divided */
+ writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
+ writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL);
+ writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL);
/* Initialize timer counters to 0 */
writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
/* Clear all interrupts */
writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
- BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, MARCO_CLOCK_FREQ));
+ BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, marco_timer_rate));
sirfsoc_clockevent_init();
}
* system's wall clock; restore it on resume().
*/
-static struct timespec old_rtc, old_system, old_delta;
+static struct timespec64 old_rtc, old_system, old_delta;
static int rtc_suspend(struct device *dev)
{
struct rtc_device *rtc = to_rtc_device(dev);
struct rtc_time tm;
- struct timespec delta, delta_delta;
+ struct timespec64 delta, delta_delta;
int err;
if (has_persistent_clock())
return 0;
}
- getnstimeofday(&old_system);
- rtc_tm_to_time(&tm, &old_rtc.tv_sec);
+ getnstimeofday64(&old_system);
+ old_rtc.tv_sec = rtc_tm_to_time64(&tm);
/*
* try to compensate so the difference in system time
* and rtc time stays close to constant.
*/
- delta = timespec_sub(old_system, old_rtc);
- delta_delta = timespec_sub(delta, old_delta);
+ delta = timespec64_sub(old_system, old_rtc);
+ delta_delta = timespec64_sub(delta, old_delta);
if (delta_delta.tv_sec < -2 || delta_delta.tv_sec >= 2) {
/*
* if delta_delta is too large, assume time correction
old_delta = delta;
} else {
/* Otherwise try to adjust old_system to compensate */
- old_system = timespec_sub(old_system, delta_delta);
+ old_system = timespec64_sub(old_system, delta_delta);
}
return 0;
{
struct rtc_device *rtc = to_rtc_device(dev);
struct rtc_time tm;
- struct timespec new_system, new_rtc;
- struct timespec sleep_time;
+ struct timespec64 new_system, new_rtc;
+ struct timespec64 sleep_time;
int err;
if (has_persistent_clock())
return 0;
/* snapshot the current rtc and system time at resume */
- getnstimeofday(&new_system);
+ getnstimeofday64(&new_system);
err = rtc_read_time(rtc, &tm);
if (err < 0) {
pr_debug("%s: fail to read rtc time\n", dev_name(&rtc->dev));
pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev));
return 0;
}
- rtc_tm_to_time(&tm, &new_rtc.tv_sec);
+ new_rtc.tv_sec = rtc_tm_to_time64(&tm);
new_rtc.tv_nsec = 0;
if (new_rtc.tv_sec < old_rtc.tv_sec) {
}
/* calculate the RTC time delta (sleep time)*/
- sleep_time = timespec_sub(new_rtc, old_rtc);
+ sleep_time = timespec64_sub(new_rtc, old_rtc);
/*
* Since these RTC suspend/resume handlers are not called
* so subtract kernel run-time between rtc_suspend to rtc_resume
* to keep things accurate.
*/
- sleep_time = timespec_sub(sleep_time,
- timespec_sub(new_system, old_system));
+ sleep_time = timespec64_sub(sleep_time,
+ timespec64_sub(new_system, old_system));
if (sleep_time.tv_sec >= 0)
- timekeeping_inject_sleeptime(&sleep_time);
+ timekeeping_inject_sleeptime64(&sleep_time);
rtc_hctosys_ret = 0;
return 0;
}
}
EXPORT_SYMBOL(rtc_year_days);
+
/*
+ * rtc_time_to_tm64 - Converts time64_t to rtc_time.
* Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
*/
-void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
+void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
{
unsigned int month, year;
+ unsigned long secs;
int days;
- days = time / 86400;
- time -= (unsigned int) days * 86400;
+ /* time must be positive */
+ days = div_s64(time, 86400);
+ secs = time - (unsigned int) days * 86400;
/* day of the week, 1970-01-01 was a Thursday */
tm->tm_wday = (days + 4) % 7;
tm->tm_mon = month;
tm->tm_mday = days + 1;
- tm->tm_hour = time / 3600;
- time -= tm->tm_hour * 3600;
- tm->tm_min = time / 60;
- tm->tm_sec = time - tm->tm_min * 60;
+ tm->tm_hour = secs / 3600;
+ secs -= tm->tm_hour * 3600;
+ tm->tm_min = secs / 60;
+ tm->tm_sec = secs - tm->tm_min * 60;
tm->tm_isdst = 0;
}
-EXPORT_SYMBOL(rtc_time_to_tm);
+EXPORT_SYMBOL(rtc_time64_to_tm);
/*
* Does the rtc_time represent a valid date/time?
EXPORT_SYMBOL(rtc_valid_tm);
/*
+ * rtc_tm_to_time64 - Converts rtc_time to time64_t.
* Convert Gregorian date to seconds since 01-01-1970 00:00:00.
*/
-int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
+time64_t rtc_tm_to_time64(struct rtc_time *tm)
{
- *time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ return mktime64(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
- return 0;
}
-EXPORT_SYMBOL(rtc_tm_to_time);
+EXPORT_SYMBOL(rtc_tm_to_time64);
/*
* Convert rtc_time to ktime
*/
ktime_t rtc_tm_to_ktime(struct rtc_time tm)
{
- time_t time;
- rtc_tm_to_time(&tm, &time);
- return ktime_set(time, 0);
+ return ktime_set(rtc_tm_to_time64(&tm), 0);
}
EXPORT_SYMBOL_GPL(rtc_tm_to_ktime);
*/
struct rtc_time rtc_ktime_to_tm(ktime_t kt)
{
- struct timespec ts;
+ struct timespec64 ts;
struct rtc_time ret;
- ts = ktime_to_timespec(kt);
+ ts = ktime_to_timespec64(kt);
/* Round up any ns */
if (ts.tv_nsec)
ts.tv_sec++;
- rtc_time_to_tm(ts.tv_sec, &ret);
+ rtc_time64_to_tm(ts.tv_sec, &ret);
return ret;
}
EXPORT_SYMBOL_GPL(rtc_ktime_to_tm);
return 0;
}
+static int armada375_wdt_clock_init(struct platform_device *pdev,
+ struct orion_watchdog *dev)
+{
+ int ret;
+
+ dev->clk = of_clk_get_by_name(pdev->dev.of_node, "fixed");
+ if (!IS_ERR(dev->clk)) {
+ ret = clk_prepare_enable(dev->clk);
+ if (ret) {
+ clk_put(dev->clk);
+ return ret;
+ }
+
+ atomic_io_modify(dev->reg + TIMER_CTRL,
+ WDT_AXP_FIXED_ENABLE_BIT,
+ WDT_AXP_FIXED_ENABLE_BIT);
+ dev->clk_rate = clk_get_rate(dev->clk);
+
+ return 0;
+ }
+
+ /* Mandatory fallback for proper devicetree backward compatibility */
+ dev->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk))
+ return PTR_ERR(dev->clk);
+
+ ret = clk_prepare_enable(dev->clk);
+ if (ret) {
+ clk_put(dev->clk);
+ return ret;
+ }
+
+ atomic_io_modify(dev->reg + TIMER_CTRL,
+ WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT),
+ WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT));
+ dev->clk_rate = clk_get_rate(dev->clk) / WDT_A370_RATIO;
+
+ return 0;
+}
+
static int armadaxp_wdt_clock_init(struct platform_device *pdev,
struct orion_watchdog *dev)
{
.rstout_mask_bit = BIT(10),
.wdt_enable_bit = BIT(8),
.wdt_counter_offset = 0x34,
- .clock_init = armada370_wdt_clock_init,
+ .clock_init = armada375_wdt_clock_init,
.enabled = armada375_enabled,
.start = armada375_start,
.stop = armada375_stop,
extern int rtc_month_days(unsigned int month, unsigned int year);
extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year);
extern int rtc_valid_tm(struct rtc_time *tm);
-extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
-extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
+extern time64_t rtc_tm_to_time64(struct rtc_time *tm);
+extern void rtc_time64_to_tm(time64_t time, struct rtc_time *tm);
ktime_t rtc_tm_to_ktime(struct rtc_time tm);
struct rtc_time rtc_ktime_to_tm(ktime_t kt);
+/**
+ * Deprecated. Use rtc_time64_to_tm().
+ */
+static inline void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
+{
+ rtc_time64_to_tm(time, tm);
+}
+
+/**
+ * Deprecated. Use rtc_tm_to_time64().
+ */
+static inline int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
+{
+ *time = rtc_tm_to_time64(tm);
+
+ return 0;
+}
#include <linux/device.h>
#include <linux/seq_file.h>
return lhs->tv_usec - rhs->tv_usec;
}
-extern unsigned long mktime(const unsigned int year, const unsigned int mon,
- const unsigned int day, const unsigned int hour,
- const unsigned int min, const unsigned int sec);
+extern time64_t mktime64(const unsigned int year, const unsigned int mon,
+ const unsigned int day, const unsigned int hour,
+ const unsigned int min, const unsigned int sec);
+
+/**
+ * Deprecated. Use mktime64().
+ */
+static inline unsigned long mktime(const unsigned int year,
+ const unsigned int mon, const unsigned int day,
+ const unsigned int hour, const unsigned int min,
+ const unsigned int sec)
+{
+ return mktime64(year, mon, day, hour, min, sec);
+}
extern void set_normalized_timespec(struct timespec *ts, time_t sec, s64 nsec);
* Get and set timeofday
*/
extern void do_gettimeofday(struct timeval *tv);
-extern int do_settimeofday(const struct timespec *tv);
+extern int do_settimeofday64(const struct timespec64 *ts);
extern int do_sys_settimeofday(const struct timespec *tv,
const struct timezone *tz);
/*
* timespec based interfaces
*/
-struct timespec get_monotonic_coarse(void);
-extern void getrawmonotonic(struct timespec *ts);
+struct timespec64 get_monotonic_coarse64(void);
+extern void getrawmonotonic64(struct timespec64 *ts);
extern void ktime_get_ts64(struct timespec64 *ts);
extern int __getnstimeofday64(struct timespec64 *tv);
extern void getnstimeofday64(struct timespec64 *tv);
#if BITS_PER_LONG == 64
+/**
+ * Deprecated. Use do_settimeofday64().
+ */
+static inline int do_settimeofday(const struct timespec *ts)
+{
+ return do_settimeofday64(ts);
+}
+
static inline int __getnstimeofday(struct timespec *ts)
{
return __getnstimeofday64(ts);
getnstimeofday64(ts);
}
+static inline void getrawmonotonic(struct timespec *ts)
+{
+ getrawmonotonic64(ts);
+}
+
+static inline struct timespec get_monotonic_coarse(void)
+{
+ return get_monotonic_coarse64();
+}
#else
+/**
+ * Deprecated. Use do_settimeofday64().
+ */
+static inline int do_settimeofday(const struct timespec *ts)
+{
+ struct timespec64 ts64;
+
+ ts64 = timespec_to_timespec64(*ts);
+ return do_settimeofday64(&ts64);
+}
+
static inline int __getnstimeofday(struct timespec *ts)
{
struct timespec64 ts64;
getnstimeofday64(&ts64);
*ts = timespec64_to_timespec(ts64);
}
+
+static inline void getrawmonotonic(struct timespec *ts)
+{
+ struct timespec64 ts64;
+
+ getrawmonotonic64(&ts64);
+ *ts = timespec64_to_timespec(ts64);
+}
+
+static inline struct timespec get_monotonic_coarse(void)
+{
+ return timespec64_to_timespec(get_monotonic_coarse64());
+}
#endif
extern void getboottime(struct timespec *ts);
/*
* RTC specific
*/
-extern void timekeeping_inject_sleeptime(struct timespec *delta);
+extern void timekeeping_inject_sleeptime64(struct timespec64 *delta);
/*
* PPS accessor
obj-$(CONFIG_TICK_ONESHOT) += tick-sched.o
obj-$(CONFIG_TIMER_STATS) += timer_stats.o
obj-$(CONFIG_DEBUG_FS) += timekeeping_debug.o
-obj-$(CONFIG_TEST_UDELAY) += udelay_test.o
+obj-$(CONFIG_TEST_UDELAY) += test_udelay.o
$(obj)/time.o: $(obj)/timeconst.h
--- /dev/null
+/*
+ * udelay() test kernel module
+ *
+ * Test is executed by writing and reading to /sys/kernel/debug/udelay_test
+ * Tests are configured by writing: USECS ITERATIONS
+ * Tests are executed by reading from the same file.
+ * Specifying usecs of 0 or negative values will run multiples tests.
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/ktime.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+
+#define DEFAULT_ITERATIONS 100
+
+#define DEBUGFS_FILENAME "udelay_test"
+
+static DEFINE_MUTEX(udelay_test_lock);
+static struct dentry *udelay_test_debugfs_file;
+static int udelay_test_usecs;
+static int udelay_test_iterations = DEFAULT_ITERATIONS;
+
+static int udelay_test_single(struct seq_file *s, int usecs, uint32_t iters)
+{
+ int min = 0, max = 0, fail_count = 0;
+ uint64_t sum = 0;
+ uint64_t avg;
+ int i;
+ /* Allow udelay to be up to 0.5% fast */
+ int allowed_error_ns = usecs * 5;
+
+ for (i = 0; i < iters; ++i) {
+ struct timespec ts1, ts2;
+ int time_passed;
+
+ ktime_get_ts(&ts1);
+ udelay(usecs);
+ ktime_get_ts(&ts2);
+ time_passed = timespec_to_ns(&ts2) - timespec_to_ns(&ts1);
+
+ if (i == 0 || time_passed < min)
+ min = time_passed;
+ if (i == 0 || time_passed > max)
+ max = time_passed;
+ if ((time_passed + allowed_error_ns) / 1000 < usecs)
+ ++fail_count;
+ WARN_ON(time_passed < 0);
+ sum += time_passed;
+ }
+
+ avg = sum;
+ do_div(avg, iters);
+ seq_printf(s, "%d usecs x %d: exp=%d allowed=%d min=%d avg=%lld max=%d",
+ usecs, iters, usecs * 1000,
+ (usecs * 1000) - allowed_error_ns, min, avg, max);
+ if (fail_count)
+ seq_printf(s, " FAIL=%d", fail_count);
+ seq_puts(s, "\n");
+
+ return 0;
+}
+
+static int udelay_test_show(struct seq_file *s, void *v)
+{
+ int usecs;
+ int iters;
+ int ret = 0;
+
+ mutex_lock(&udelay_test_lock);
+ usecs = udelay_test_usecs;
+ iters = udelay_test_iterations;
+ mutex_unlock(&udelay_test_lock);
+
+ if (usecs > 0 && iters > 0) {
+ return udelay_test_single(s, usecs, iters);
+ } else if (usecs == 0) {
+ struct timespec ts;
+
+ ktime_get_ts(&ts);
+ seq_printf(s, "udelay() test (lpj=%ld kt=%ld.%09ld)\n",
+ loops_per_jiffy, ts.tv_sec, ts.tv_nsec);
+ seq_puts(s, "usage:\n");
+ seq_puts(s, "echo USECS [ITERS] > " DEBUGFS_FILENAME "\n");
+ seq_puts(s, "cat " DEBUGFS_FILENAME "\n");
+ }
+
+ return ret;
+}
+
+static int udelay_test_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, udelay_test_show, inode->i_private);
+}
+
+static ssize_t udelay_test_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ char lbuf[32];
+ int ret;
+ int usecs;
+ int iters;
+
+ if (count >= sizeof(lbuf))
+ return -EINVAL;
+
+ if (copy_from_user(lbuf, buf, count))
+ return -EFAULT;
+ lbuf[count] = '\0';
+
+ ret = sscanf(lbuf, "%d %d", &usecs, &iters);
+ if (ret < 1)
+ return -EINVAL;
+ else if (ret < 2)
+ iters = DEFAULT_ITERATIONS;
+
+ mutex_lock(&udelay_test_lock);
+ udelay_test_usecs = usecs;
+ udelay_test_iterations = iters;
+ mutex_unlock(&udelay_test_lock);
+
+ return count;
+}
+
+static const struct file_operations udelay_test_debugfs_ops = {
+ .owner = THIS_MODULE,
+ .open = udelay_test_open,
+ .read = seq_read,
+ .write = udelay_test_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init udelay_test_init(void)
+{
+ mutex_lock(&udelay_test_lock);
+ udelay_test_debugfs_file = debugfs_create_file(DEBUGFS_FILENAME,
+ S_IRUSR, NULL, NULL, &udelay_test_debugfs_ops);
+ mutex_unlock(&udelay_test_lock);
+
+ return 0;
+}
+
+module_init(udelay_test_init);
+
+static void __exit udelay_test_exit(void)
+{
+ mutex_lock(&udelay_test_lock);
+ debugfs_remove(udelay_test_debugfs_file);
+ mutex_unlock(&udelay_test_lock);
+}
+
+module_exit(udelay_test_exit);
+
+MODULE_AUTHOR("David Riley <davidriley@chromium.org>");
+MODULE_LICENSE("GPL");
}
EXPORT_SYMBOL(timespec_trunc);
-/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+/*
+ * mktime64 - Converts date to seconds.
+ * Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
* => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
*
* -year/100+year/400 terms, and add 10.]
*
* This algorithm was first published by Gauss (I think).
- *
- * WARNING: this function will overflow on 2106-02-07 06:28:16 on
- * machines where long is 32-bit! (However, as time_t is signed, we
- * will already get problems at other places on 2038-01-19 03:14:08)
*/
-unsigned long
-mktime(const unsigned int year0, const unsigned int mon0,
- const unsigned int day, const unsigned int hour,
- const unsigned int min, const unsigned int sec)
+time64_t mktime64(const unsigned int year0, const unsigned int mon0,
+ const unsigned int day, const unsigned int hour,
+ const unsigned int min, const unsigned int sec)
{
unsigned int mon = mon0, year = year0;
year -= 1;
}
- return ((((unsigned long)
+ return ((((time64_t)
(year/4 - year/100 + year/400 + 367*mon/12 + day) +
year*365 - 719499
)*24 + hour /* now have hours */
)*60 + min /* now have minutes */
)*60 + sec; /* finally seconds */
}
-
-EXPORT_SYMBOL(mktime);
+EXPORT_SYMBOL(mktime64);
/**
* set_normalized_timespec - set timespec sec and nsec parts and normalize
/**
* getnstimeofday64 - Returns the time of day in a timespec64.
- * @ts: pointer to the timespec to be set
+ * @ts: pointer to the timespec64 to be set
*
- * Returns the time of day in a timespec (WARN if suspended).
+ * Returns the time of day in a timespec64 (WARN if suspended).
*/
void getnstimeofday64(struct timespec64 *ts)
{
*
* The function calculates the monotonic clock from the realtime
* clock and the wall_to_monotonic offset and stores the result
- * in normalized timespec format in the variable pointed to by @ts.
+ * in normalized timespec64 format in the variable pointed to by @ts.
*/
void ktime_get_ts64(struct timespec64 *ts)
{
EXPORT_SYMBOL(do_gettimeofday);
/**
- * do_settimeofday - Sets the time of day
- * @tv: pointer to the timespec variable containing the new time
+ * do_settimeofday64 - Sets the time of day.
+ * @ts: pointer to the timespec64 variable containing the new time
*
* Sets the time of day to the new time and update NTP and notify hrtimers
*/
-int do_settimeofday(const struct timespec *tv)
+int do_settimeofday64(const struct timespec64 *ts)
{
struct timekeeper *tk = &tk_core.timekeeper;
- struct timespec64 ts_delta, xt, tmp;
+ struct timespec64 ts_delta, xt;
unsigned long flags;
- if (!timespec_valid_strict(tv))
+ if (!timespec64_valid_strict(ts))
return -EINVAL;
raw_spin_lock_irqsave(&timekeeper_lock, flags);
timekeeping_forward_now(tk);
xt = tk_xtime(tk);
- ts_delta.tv_sec = tv->tv_sec - xt.tv_sec;
- ts_delta.tv_nsec = tv->tv_nsec - xt.tv_nsec;
+ ts_delta.tv_sec = ts->tv_sec - xt.tv_sec;
+ ts_delta.tv_nsec = ts->tv_nsec - xt.tv_nsec;
tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts_delta));
- tmp = timespec_to_timespec64(*tv);
- tk_set_xtime(tk, &tmp);
+ tk_set_xtime(tk, ts);
timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
return 0;
}
-EXPORT_SYMBOL(do_settimeofday);
+EXPORT_SYMBOL(do_settimeofday64);
/**
* timekeeping_inject_offset - Adds or subtracts from the current time.
}
/**
- * getrawmonotonic - Returns the raw monotonic time in a timespec
- * @ts: pointer to the timespec to be set
+ * getrawmonotonic64 - Returns the raw monotonic time in a timespec
+ * @ts: pointer to the timespec64 to be set
*
* Returns the raw monotonic time (completely un-modified by ntp)
*/
-void getrawmonotonic(struct timespec *ts)
+void getrawmonotonic64(struct timespec64 *ts)
{
struct timekeeper *tk = &tk_core.timekeeper;
struct timespec64 ts64;
} while (read_seqcount_retry(&tk_core.seq, seq));
timespec64_add_ns(&ts64, nsecs);
- *ts = timespec64_to_timespec(ts64);
+ *ts = ts64;
}
-EXPORT_SYMBOL(getrawmonotonic);
+EXPORT_SYMBOL(getrawmonotonic64);
+
/**
* timekeeping_valid_for_hres - Check if timekeeping is suitable for hres
}
/**
- * timekeeping_inject_sleeptime - Adds suspend interval to timeekeeping values
- * @delta: pointer to a timespec delta value
+ * timekeeping_inject_sleeptime64 - Adds suspend interval to timeekeeping values
+ * @delta: pointer to a timespec64 delta value
*
* This hook is for architectures that cannot support read_persistent_clock
* because their RTC/persistent clock is only accessible when irqs are enabled.
* This function should only be called by rtc_resume(), and allows
* a suspend offset to be injected into the timekeeping values.
*/
-void timekeeping_inject_sleeptime(struct timespec *delta)
+void timekeeping_inject_sleeptime64(struct timespec64 *delta)
{
struct timekeeper *tk = &tk_core.timekeeper;
- struct timespec64 tmp;
unsigned long flags;
/*
timekeeping_forward_now(tk);
- tmp = timespec_to_timespec64(*delta);
- __timekeeping_inject_sleeptime(tk, &tmp);
+ __timekeeping_inject_sleeptime(tk, delta);
timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
*
* XXX - TODO: Doc ntp_error calculation.
*/
+ if ((mult_adj > 0) && (tk->tkr.mult + mult_adj < mult_adj)) {
+ /* NTP adjustment caused clocksource mult overflow */
+ WARN_ON_ONCE(1);
+ return;
+ }
+
tk->tkr.mult += mult_adj;
tk->xtime_interval += interval;
tk->tkr.xtime_nsec -= offset;
}
if (unlikely(tk->tkr.clock->maxadj &&
- (tk->tkr.mult > tk->tkr.clock->mult + tk->tkr.clock->maxadj))) {
+ (abs(tk->tkr.mult - tk->tkr.clock->mult)
+ > tk->tkr.clock->maxadj))) {
printk_once(KERN_WARNING
"Adjusting %s more than 11%% (%ld vs %ld)\n",
tk->tkr.clock->name, (long)tk->tkr.mult,
}
EXPORT_SYMBOL(current_kernel_time);
-struct timespec get_monotonic_coarse(void)
+struct timespec64 get_monotonic_coarse64(void)
{
struct timekeeper *tk = &tk_core.timekeeper;
struct timespec64 now, mono;
set_normalized_timespec64(&now, now.tv_sec + mono.tv_sec,
now.tv_nsec + mono.tv_nsec);
- return timespec64_to_timespec(now);
+ return now;
}
/*
+++ /dev/null
-/*
- * udelay() test kernel module
- *
- * Test is executed by writing and reading to /sys/kernel/debug/udelay_test
- * Tests are configured by writing: USECS ITERATIONS
- * Tests are executed by reading from the same file.
- * Specifying usecs of 0 or negative values will run multiples tests.
- *
- * Copyright (C) 2014 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/debugfs.h>
-#include <linux/delay.h>
-#include <linux/ktime.h>
-#include <linux/module.h>
-#include <linux/uaccess.h>
-
-#define DEFAULT_ITERATIONS 100
-
-#define DEBUGFS_FILENAME "udelay_test"
-
-static DEFINE_MUTEX(udelay_test_lock);
-static struct dentry *udelay_test_debugfs_file;
-static int udelay_test_usecs;
-static int udelay_test_iterations = DEFAULT_ITERATIONS;
-
-static int udelay_test_single(struct seq_file *s, int usecs, uint32_t iters)
-{
- int min = 0, max = 0, fail_count = 0;
- uint64_t sum = 0;
- uint64_t avg;
- int i;
- /* Allow udelay to be up to 0.5% fast */
- int allowed_error_ns = usecs * 5;
-
- for (i = 0; i < iters; ++i) {
- struct timespec ts1, ts2;
- int time_passed;
-
- ktime_get_ts(&ts1);
- udelay(usecs);
- ktime_get_ts(&ts2);
- time_passed = timespec_to_ns(&ts2) - timespec_to_ns(&ts1);
-
- if (i == 0 || time_passed < min)
- min = time_passed;
- if (i == 0 || time_passed > max)
- max = time_passed;
- if ((time_passed + allowed_error_ns) / 1000 < usecs)
- ++fail_count;
- WARN_ON(time_passed < 0);
- sum += time_passed;
- }
-
- avg = sum;
- do_div(avg, iters);
- seq_printf(s, "%d usecs x %d: exp=%d allowed=%d min=%d avg=%lld max=%d",
- usecs, iters, usecs * 1000,
- (usecs * 1000) - allowed_error_ns, min, avg, max);
- if (fail_count)
- seq_printf(s, " FAIL=%d", fail_count);
- seq_puts(s, "\n");
-
- return 0;
-}
-
-static int udelay_test_show(struct seq_file *s, void *v)
-{
- int usecs;
- int iters;
- int ret = 0;
-
- mutex_lock(&udelay_test_lock);
- usecs = udelay_test_usecs;
- iters = udelay_test_iterations;
- mutex_unlock(&udelay_test_lock);
-
- if (usecs > 0 && iters > 0) {
- return udelay_test_single(s, usecs, iters);
- } else if (usecs == 0) {
- struct timespec ts;
-
- ktime_get_ts(&ts);
- seq_printf(s, "udelay() test (lpj=%ld kt=%ld.%09ld)\n",
- loops_per_jiffy, ts.tv_sec, ts.tv_nsec);
- seq_puts(s, "usage:\n");
- seq_puts(s, "echo USECS [ITERS] > " DEBUGFS_FILENAME "\n");
- seq_puts(s, "cat " DEBUGFS_FILENAME "\n");
- }
-
- return ret;
-}
-
-static int udelay_test_open(struct inode *inode, struct file *file)
-{
- return single_open(file, udelay_test_show, inode->i_private);
-}
-
-static ssize_t udelay_test_write(struct file *file, const char __user *buf,
- size_t count, loff_t *pos)
-{
- char lbuf[32];
- int ret;
- int usecs;
- int iters;
-
- if (count >= sizeof(lbuf))
- return -EINVAL;
-
- if (copy_from_user(lbuf, buf, count))
- return -EFAULT;
- lbuf[count] = '\0';
-
- ret = sscanf(lbuf, "%d %d", &usecs, &iters);
- if (ret < 1)
- return -EINVAL;
- else if (ret < 2)
- iters = DEFAULT_ITERATIONS;
-
- mutex_lock(&udelay_test_lock);
- udelay_test_usecs = usecs;
- udelay_test_iterations = iters;
- mutex_unlock(&udelay_test_lock);
-
- return count;
-}
-
-static const struct file_operations udelay_test_debugfs_ops = {
- .owner = THIS_MODULE,
- .open = udelay_test_open,
- .read = seq_read,
- .write = udelay_test_write,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int __init udelay_test_init(void)
-{
- mutex_lock(&udelay_test_lock);
- udelay_test_debugfs_file = debugfs_create_file(DEBUGFS_FILENAME,
- S_IRUSR, NULL, NULL, &udelay_test_debugfs_ops);
- mutex_unlock(&udelay_test_lock);
-
- return 0;
-}
-
-module_init(udelay_test_init);
-
-static void __exit udelay_test_exit(void)
-{
- mutex_lock(&udelay_test_lock);
- debugfs_remove(udelay_test_debugfs_file);
- mutex_unlock(&udelay_test_lock);
-}
-
-module_exit(udelay_test_exit);
-
-MODULE_AUTHOR("David Riley <davidriley@chromium.org>");
-MODULE_LICENSE("GPL");