lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <fe8f75e39938954be9f3f1f1e2179c4c398d6f55.1515486685.git.baolin.wang@linaro.org>
Date:   Tue,  9 Jan 2018 17:09:10 +0800
From:   Baolin Wang <baolin.wang@...aro.org>
To:     daniel.lezcano@...aro.org, tglx@...utronix.de
Cc:     broonie@...nel.org, arnd@...db.de, baolin.wang@...aro.org,
        linux-kernel@...r.kernel.org
Subject: [PATCH 1/2] clocksource: Add persistent timer support

On some platforms (such as Spreadtrum sc9860 platform), they need one
persistent timer to calculate the suspended time and compensate it
for the OS time.

But now there are no method to register one persistent timer on some
architectures (such as arm64), thus this patch adds one common framework
for timer drivers to register one persistent timer and implements the
read_persistent_clock64() to compensate the OS time.

Signed-off-by: Baolin Wang <baolin.wang@...aro.org>
---
 drivers/clocksource/Kconfig            |    3 +
 drivers/clocksource/Makefile           |    1 +
 drivers/clocksource/persistent-timer.c |  142 ++++++++++++++++++++++++++++++++
 drivers/clocksource/persistent-timer.h |   26 ++++++
 4 files changed, 172 insertions(+)
 create mode 100644 drivers/clocksource/persistent-timer.c
 create mode 100644 drivers/clocksource/persistent-timer.h

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 9a6b087..9cf3d41 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -27,6 +27,9 @@ config CLKBLD_I8253
 config CLKSRC_MMIO
 	bool
 
+config PERSISTENT_TIMER
+	bool
+
 config BCM2835_TIMER
 	bool "BCM2835 timer driver" if COMPILE_TEST
 	select CLKSRC_MMIO
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index d6dec44..42556f4 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -76,3 +76,4 @@ obj-$(CONFIG_H8300_TMR16)		+= h8300_timer16.o
 obj-$(CONFIG_H8300_TPU)			+= h8300_tpu.o
 obj-$(CONFIG_CLKSRC_ST_LPC)		+= clksrc_st_lpc.o
 obj-$(CONFIG_X86_NUMACHIP)		+= numachip.o
+obj-$(CONFIG_PERSISTENT_TIMER)		+= persistent-timer.o
diff --git a/drivers/clocksource/persistent-timer.c b/drivers/clocksource/persistent-timer.c
new file mode 100644
index 0000000..89a631d
--- /dev/null
+++ b/drivers/clocksource/persistent-timer.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Linaro, Inc.
+ *
+ * Author: Baolin Wang <baolin.wang@...aro.org>
+ */
+
+#include <linux/clk.h>
+#include <linux/clocksource.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include "persistent-timer.h"
+
+static struct persistent_timer *ptimer;
+
+void read_persistent_clock64(struct timespec64 *ts)
+{
+	u64 cycles, delta, nsecs;
+
+	if (!ptimer) {
+		ts->tv_sec = 0;
+		ts->tv_nsec = 0;
+		return;
+	}
+
+	cycles = ptimer->read(ptimer);
+	delta = (cycles - ptimer->last_cycles) & ptimer->mask;
+
+	nsecs = clocksource_cyc2ns(delta, ptimer->mult, ptimer->shift);
+	timespec64_add_ns(&ptimer->ts, nsecs);
+	*ts = ptimer->ts;
+
+	ptimer->last_cycles = cycles;
+}
+
+static __init void persistent_timer_freq_init(struct persistent_timer *p)
+{
+	u64 max_sec = p->mask;
+
+	do_div(max_sec, p->freq);
+
+	/*
+	 * Some counter's mask can be larger than 32bit, so we need to limit
+	 * the max suspend time to have a good conversion precision. 12 hours
+	 * can be enough usually.
+	 */
+	if (max_sec > 43200)
+		max_sec = 43200;
+
+	clocks_calc_mult_shift(&p->mult, &p->shift, p->freq,
+			       NSEC_PER_SEC, (u32)max_sec);
+}
+
+static __init int persistent_timer_clk_init(struct device_node *np,
+					    struct persistent_timer *p)
+{
+	int ret;
+
+	p->clk = of_clk_get(np, 0);
+	if (IS_ERR(p->clk)) {
+		pr_err("Can't get timer clock\n");
+		return PTR_ERR(p->clk);
+	}
+
+	ret = clk_prepare_enable(p->clk);
+	if (ret) {
+		pr_err("Failed to enable clock for %pOF\n", np);
+		clk_put(p->clk);
+		return ret;
+	}
+
+	p->freq = clk_get_rate(p->clk);
+	if (!p->freq) {
+		pr_err("Failed to get clock rate for %pOF\n", np);
+		clk_disable_unprepare(p->clk);
+		clk_put(p->clk);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static __init int persistent_timer_base_init(struct device_node *np,
+					     struct persistent_timer *p)
+{
+	p->base = of_io_request_and_map(np, 0, of_node_full_name(np));
+	if (IS_ERR(p->base)) {
+		pr_err("Can't map timer registers\n");
+		return PTR_ERR(p->base);
+	}
+
+	return 0;
+}
+
+int __init persistent_timer_init_and_register(struct device_node *np,
+					      struct persistent_timer *p)
+{
+	int ret;
+
+	if (!p->read || !p->mask)
+		return -EINVAL;
+
+	if (p->flags & PERSISTENT_TIMER_BASE) {
+		ret = persistent_timer_base_init(np, p);
+		if (ret)
+			return ret;
+	}
+
+	if (p->flags & PERSISTENT_TIMER_CLOCK) {
+		ret = persistent_timer_clk_init(np, p);
+		if (ret)
+			goto err_clk;
+	}
+
+	if (p->flags & PERSISTENT_TIMER_MULT_SHIFT)
+		persistent_timer_freq_init(p);
+
+	p->last_cycles = 0;
+	ptimer = p;
+	return 0;
+
+err_clk:
+	if (p->flags & PERSISTENT_TIMER_BASE)
+		iounmap(p->base);
+
+	return ret;
+}
+
+void __init persistent_timer_cleanup(struct persistent_timer *p)
+{
+	if (p->flags & PERSISTENT_TIMER_CLOCK) {
+		p->freq = 0;
+		clk_disable_unprepare(p->clk);
+		clk_put(p->clk);
+	}
+
+	if (p->flags & PERSISTENT_TIMER_BASE)
+		iounmap(p->base);
+
+	ptimer = NULL;
+}
diff --git a/drivers/clocksource/persistent-timer.h b/drivers/clocksource/persistent-timer.h
new file mode 100644
index 0000000..7705027
--- /dev/null
+++ b/drivers/clocksource/persistent-timer.h
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef __PERSISTENT_TIMER_H__
+#define __PERSISTENT_TIMER_H__
+
+#define PERSISTENT_TIMER_BASE		BIT(0)
+#define PERSISTENT_TIMER_CLOCK		BIT(1)
+#define PERSISTENT_TIMER_MULT_SHIFT	BIT(2)
+
+struct persistent_timer {
+	u64 (*read)(struct persistent_timer *p);
+	void __iomem *base;
+	u64 last_cycles;
+	u64 mask;
+	u32 mult;
+	u32 shift;
+	struct clk *clk;
+	unsigned long freq;
+	unsigned int flags;
+	struct timespec64 ts;
+};
+
+extern int __init persistent_timer_init_and_register(struct device_node *np,
+						     struct persistent_timer *p);
+extern void __init persistent_timer_cleanup(struct persistent_timer *p);
+
+#endif
-- 
1.7.9.5

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ