* [PATCHv4 13/14] Documentation: Add ARMv8 to arch_timer devicetree
From: Mark Rutland @ 2013-01-15 17:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358271931-7761-1-git-send-email-mark.rutland@arm.com>
Currently the documentation for the arch_timer devicetree binding only
lists "arm,armv7-timer".
Add "arm,armv8-timer" to the list of compatible strings.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
.../devicetree/bindings/arm/arch_timer.txt | 7 ++++---
1 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt
index 52478c8..20746e5 100644
--- a/Documentation/devicetree/bindings/arm/arch_timer.txt
+++ b/Documentation/devicetree/bindings/arm/arch_timer.txt
@@ -1,13 +1,14 @@
* ARM architected timer
-ARM Cortex-A7 and Cortex-A15 have a per-core architected timer, which
-provides per-cpu timers.
+ARM cores may have a per-core architected timer, which provides per-cpu timers.
The timer is attached to a GIC to deliver its per-processor interrupts.
** Timer node properties:
-- compatible : Should at least contain "arm,armv7-timer".
+- compatible : Should at least contain one of
+ "arm,armv7-timer"
+ "arm,armv8-timer"
- interrupts : Interrupt list for secure, non-secure, virtual and
hypervisor timers, in that order.
--
1.7.0.4
^ permalink raw reply related
* [PATCHv4 12/14] arm64: move from arm_generic to arm_arch_timer
From: Mark Rutland @ 2013-01-15 17:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358271931-7761-1-git-send-email-mark.rutland@arm.com>
The arch_timer driver supports a superset of the functionality of the
arm_generic driver, and is not tied to a particular arch.
This patch moves arm64 to use the arch_timer driver, gaining additional
functionality in doing so, and removes the (now unused) arm_generic
driver. Timer-related hooks specific to arm64 are moved into
arch/arm64/kernel/time.c.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/arch_timer.h | 133 +++++++++++++++++++
arch/arm64/include/asm/arm_generic.h | 102 ---------------
arch/arm64/kernel/time.c | 29 ++++-
drivers/clocksource/Kconfig | 5 -
drivers/clocksource/Makefile | 1 -
drivers/clocksource/arm_arch_timer.c | 1 +
drivers/clocksource/arm_generic.c | 232 ----------------------------------
include/clocksource/arm_generic.h | 21 ---
9 files changed, 162 insertions(+), 363 deletions(-)
create mode 100644 arch/arm64/include/asm/arch_timer.h
delete mode 100644 arch/arm64/include/asm/arm_generic.h
delete mode 100644 drivers/clocksource/arm_generic.c
delete mode 100644 include/clocksource/arm_generic.h
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index f8f362a..2b6cef6 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -3,6 +3,7 @@ config ARM64
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
select ARM_AMBA
+ select ARM_ARCH_TIMER
select CLONE_BACKWARDS
select COMMON_CLK
select GENERIC_CLOCKEVENTS
diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h
new file mode 100644
index 0000000..91e2a6a
--- /dev/null
+++ b/arch/arm64/include/asm/arch_timer.h
@@ -0,0 +1,133 @@
+/*
+ * arch/arm64/include/asm/arch_timer.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_ARCH_TIMER_H
+#define __ASM_ARCH_TIMER_H
+
+#include <asm/barrier.h>
+
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <clocksource/arm_arch_timer.h>
+
+static inline void arch_timer_reg_write(int access, int reg, u32 val)
+{
+ if (access == ARCH_TIMER_PHYS_ACCESS) {
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("msr cntp_ctl_el0, %0" : : "r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("msr cntp_tval_el0, %0" : : "r" (val));
+ break;
+ default:
+ BUILD_BUG();
+ }
+ } else if (access == ARCH_TIMER_VIRT_ACCESS) {
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("msr cntv_ctl_el0, %0" : : "r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("msr cntv_tval_el0, %0" : : "r" (val));
+ break;
+ default:
+ BUILD_BUG();
+ }
+ } else {
+ BUILD_BUG();
+ }
+
+ isb();
+}
+
+static inline u32 arch_timer_reg_read(int access, int reg)
+{
+ u32 val;
+
+ if (access == ARCH_TIMER_PHYS_ACCESS) {
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("mrs %0, cntp_ctl_el0" : "=r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("mrs %0, cntp_tval_el0" : "=r" (val));
+ break;
+ default:
+ BUILD_BUG();
+ }
+ } else if (access == ARCH_TIMER_VIRT_ACCESS) {
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("mrs %0, cntv_ctl_el0" : "=r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("mrs %0, cntv_tval_el0" : "=r" (val));
+ break;
+ default:
+ BUILD_BUG();
+ }
+ } else {
+ BUILD_BUG();
+ }
+
+ return val;
+}
+
+static inline u32 arch_timer_get_cntfrq(void)
+{
+ u32 val;
+ asm volatile("mrs %0, cntfrq_el0" : "=r" (val));
+ return val;
+}
+
+static inline void __cpuinit arch_counter_set_user_access(void)
+{
+ u32 cntkctl;
+
+ /* Disable user access to the timers and the physical counter. */
+ asm volatile("mrs %0, cntkctl_el1" : "=r" (cntkctl));
+ cntkctl &= ~((3 << 8) | (1 << 0));
+
+ /* Enable user access to the virtual counter and frequency. */
+ cntkctl |= (1 << 1);
+ asm volatile("msr cntkctl_el1, %0" : : "r" (cntkctl));
+}
+
+static inline u64 arch_counter_get_cntpct(void)
+{
+ u64 cval;
+
+ isb();
+ asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
+
+ return cval;
+}
+
+static inline u64 arch_counter_get_cntvct(void)
+{
+ u64 cval;
+
+ isb();
+ asm volatile("mrs %0, cntvct_el0" : "=r" (cval));
+
+ return cval;
+}
+
+#endif
diff --git a/arch/arm64/include/asm/arm_generic.h b/arch/arm64/include/asm/arm_generic.h
deleted file mode 100644
index 6ece2f1..0000000
--- a/arch/arm64/include/asm/arm_generic.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * arch/arm64/include/asm/arm_generic.h
- *
- * Copyright (C) 2012 ARM Ltd.
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef __ASM_ARM_GENERIC_H
-#define __ASM_ARM_GENERIC_H
-
-#include <linux/clocksource.h>
-
-#define ARCH_TIMER_CTRL_ENABLE (1 << 0)
-#define ARCH_TIMER_CTRL_IMASK (1 << 1)
-#define ARCH_TIMER_CTRL_ISTATUS (1 << 2)
-
-#define ARCH_TIMER_REG_CTRL 0
-#define ARCH_TIMER_REG_FREQ 1
-#define ARCH_TIMER_REG_TVAL 2
-
-static inline void arch_timer_reg_write(int reg, u32 val)
-{
- switch (reg) {
- case ARCH_TIMER_REG_CTRL:
- asm volatile("msr cntp_ctl_el0, %0" : : "r" (val));
- break;
- case ARCH_TIMER_REG_TVAL:
- asm volatile("msr cntp_tval_el0, %0" : : "r" (val));
- break;
- default:
- BUILD_BUG();
- }
-
- isb();
-}
-
-static inline u32 arch_timer_reg_read(int reg)
-{
- u32 val;
-
- switch (reg) {
- case ARCH_TIMER_REG_CTRL:
- asm volatile("mrs %0, cntp_ctl_el0" : "=r" (val));
- break;
- case ARCH_TIMER_REG_FREQ:
- asm volatile("mrs %0, cntfrq_el0" : "=r" (val));
- break;
- case ARCH_TIMER_REG_TVAL:
- asm volatile("mrs %0, cntp_tval_el0" : "=r" (val));
- break;
- default:
- BUILD_BUG();
- }
-
- return val;
-}
-
-static inline void __cpuinit arch_counter_enable_user_access(void)
-{
- u32 cntkctl;
-
- /* Disable user access to the timers and the physical counter. */
- asm volatile("mrs %0, cntkctl_el1" : "=r" (cntkctl));
- cntkctl &= ~((3 << 8) | (1 << 0));
-
- /* Enable user access to the virtual counter and frequency. */
- cntkctl |= (1 << 1);
- asm volatile("msr cntkctl_el1, %0" : : "r" (cntkctl));
-}
-
-static inline cycle_t arch_counter_get_cntpct(void)
-{
- cycle_t cval;
-
- isb();
- asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
-
- return cval;
-}
-
-static inline cycle_t arch_counter_get_cntvct(void)
-{
- cycle_t cval;
-
- isb();
- asm volatile("mrs %0, cntvct_el0" : "=r" (cval));
-
- return cval;
-}
-
-#endif
diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c
index 3b4b725..b0ef18d 100644
--- a/arch/arm64/kernel/time.c
+++ b/arch/arm64/kernel/time.c
@@ -31,8 +31,9 @@
#include <linux/syscore_ops.h>
#include <linux/timer.h>
#include <linux/irq.h>
+#include <linux/delay.h>
-#include <clocksource/arm_generic.h>
+#include <clocksource/arm_arch_timer.h>
#include <asm/thread_info.h>
#include <asm/stacktrace.h>
@@ -59,7 +60,31 @@ unsigned long profile_pc(struct pt_regs *regs)
EXPORT_SYMBOL(profile_pc);
#endif
+static u64 sched_clock_mult __read_mostly;
+
+unsigned long long notrace sched_clock(void)
+{
+ return arch_timer_read_counter() * sched_clock_mult;
+}
+
+int read_current_timer(unsigned long *timer_value)
+{
+ *timer_value = arch_timer_read_counter();
+ return 0;
+}
+
void __init time_init(void)
{
- arm_generic_timer_init();
+ u32 arch_timer_rate;
+
+ if (arch_timer_init())
+ panic("Unable to initialise architected timer.\n");
+
+ arch_timer_rate = arch_timer_get_rate();
+
+ /* Cache the sched_clock multiplier to save a divide in the hot path. */
+ sched_clock_mult = NSEC_PER_SEC / arch_timer_rate;
+
+ /* Calibrate the delay loop directly */
+ lpj_fine = arch_timer_rate / HZ;
}
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index dbb085a..6479842 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -54,10 +54,5 @@ config CLKSRC_DBX500_PRCMU_SCHED_CLOCK
help
Use the always on PRCMU Timer as sched_clock
-config CLKSRC_ARM_GENERIC
- def_bool y if ARM64
- help
- This option enables support for the ARM generic timer.
-
config ARM_ARCH_TIMER
bool
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 32f858c..e69511c 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -17,5 +17,4 @@ obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o
-obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 3e4739d..ec30a73 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -338,6 +338,7 @@ out:
static const struct of_device_id arch_timer_of_match[] __initconst = {
{ .compatible = "arm,armv7-timer", },
+ { .compatible = "arm,armv8-timer", },
{},
};
diff --git a/drivers/clocksource/arm_generic.c b/drivers/clocksource/arm_generic.c
deleted file mode 100644
index 8ae1a61..0000000
--- a/drivers/clocksource/arm_generic.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Generic timers support
- *
- * Copyright (C) 2012 ARM Ltd.
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/smp.h>
-#include <linux/cpu.h>
-#include <linux/jiffies.h>
-#include <linux/interrupt.h>
-#include <linux/clockchips.h>
-#include <linux/of_irq.h>
-#include <linux/io.h>
-
-#include <clocksource/arm_generic.h>
-
-#include <asm/arm_generic.h>
-
-static u32 arch_timer_rate;
-static u64 sched_clock_mult __read_mostly;
-static DEFINE_PER_CPU(struct clock_event_device, arch_timer_evt);
-static int arch_timer_ppi;
-
-static irqreturn_t arch_timer_handle_irq(int irq, void *dev_id)
-{
- struct clock_event_device *evt = dev_id;
- unsigned long ctrl;
-
- ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
- if (ctrl & ARCH_TIMER_CTRL_ISTATUS) {
- ctrl |= ARCH_TIMER_CTRL_IMASK;
- arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
- evt->event_handler(evt);
- return IRQ_HANDLED;
- }
-
- return IRQ_NONE;
-}
-
-static void arch_timer_stop(void)
-{
- unsigned long ctrl;
-
- ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
- ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
- arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
-}
-
-static void arch_timer_set_mode(enum clock_event_mode mode,
- struct clock_event_device *clk)
-{
- switch (mode) {
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- arch_timer_stop();
- break;
- default:
- break;
- }
-}
-
-static int arch_timer_set_next_event(unsigned long evt,
- struct clock_event_device *unused)
-{
- unsigned long ctrl;
-
- ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
- ctrl |= ARCH_TIMER_CTRL_ENABLE;
- ctrl &= ~ARCH_TIMER_CTRL_IMASK;
-
- arch_timer_reg_write(ARCH_TIMER_REG_TVAL, evt);
- arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
-
- return 0;
-}
-
-static void __cpuinit arch_timer_setup(struct clock_event_device *clk)
-{
- /* Let's make sure the timer is off before doing anything else */
- arch_timer_stop();
-
- clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP;
- clk->name = "arch_sys_timer";
- clk->rating = 400;
- clk->set_mode = arch_timer_set_mode;
- clk->set_next_event = arch_timer_set_next_event;
- clk->irq = arch_timer_ppi;
- clk->cpumask = cpumask_of(smp_processor_id());
-
- clockevents_config_and_register(clk, arch_timer_rate,
- 0xf, 0x7fffffff);
-
- enable_percpu_irq(clk->irq, 0);
-
- /* Ensure the virtual counter is visible to userspace for the vDSO. */
- arch_counter_enable_user_access();
-}
-
-static void __init arch_timer_calibrate(void)
-{
- if (arch_timer_rate == 0) {
- arch_timer_reg_write(ARCH_TIMER_REG_CTRL, 0);
- arch_timer_rate = arch_timer_reg_read(ARCH_TIMER_REG_FREQ);
-
- /* Check the timer frequency. */
- if (arch_timer_rate == 0)
- panic("Architected timer frequency is set to zero.\n"
- "You must set this in your .dts file\n");
- }
-
- /* Cache the sched_clock multiplier to save a divide in the hot path. */
-
- sched_clock_mult = DIV_ROUND_CLOSEST(NSEC_PER_SEC, arch_timer_rate);
-
- pr_info("Architected local timer running at %u.%02uMHz.\n",
- arch_timer_rate / 1000000, (arch_timer_rate / 10000) % 100);
-}
-
-static cycle_t arch_counter_read(struct clocksource *cs)
-{
- return arch_counter_get_cntpct();
-}
-
-static struct clocksource clocksource_counter = {
- .name = "arch_sys_counter",
- .rating = 400,
- .read = arch_counter_read,
- .mask = CLOCKSOURCE_MASK(56),
- .flags = (CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_VALID_FOR_HRES),
-};
-
-int read_current_timer(unsigned long *timer_value)
-{
- *timer_value = arch_counter_get_cntpct();
- return 0;
-}
-
-unsigned long long notrace sched_clock(void)
-{
- return arch_counter_get_cntvct() * sched_clock_mult;
-}
-
-static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self,
- unsigned long action, void *hcpu)
-{
- int cpu = (long)hcpu;
- struct clock_event_device *clk = per_cpu_ptr(&arch_timer_evt, cpu);
-
- switch(action) {
- case CPU_STARTING:
- case CPU_STARTING_FROZEN:
- arch_timer_setup(clk);
- break;
-
- case CPU_DYING:
- case CPU_DYING_FROZEN:
- pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
- clk->irq, cpu);
- disable_percpu_irq(clk->irq);
- arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata arch_timer_cpu_nb = {
- .notifier_call = arch_timer_cpu_notify,
-};
-
-static const struct of_device_id arch_timer_of_match[] __initconst = {
- { .compatible = "arm,armv8-timer" },
- {},
-};
-
-int __init arm_generic_timer_init(void)
-{
- struct device_node *np;
- int err;
- u32 freq;
-
- np = of_find_matching_node(NULL, arch_timer_of_match);
- if (!np) {
- pr_err("arch_timer: can't find DT node\n");
- return -ENODEV;
- }
-
- /* Try to determine the frequency from the device tree or CNTFRQ */
- if (!of_property_read_u32(np, "clock-frequency", &freq))
- arch_timer_rate = freq;
- arch_timer_calibrate();
-
- arch_timer_ppi = irq_of_parse_and_map(np, 0);
- pr_info("arch_timer: found %s irq %d\n", np->name, arch_timer_ppi);
-
- err = request_percpu_irq(arch_timer_ppi, arch_timer_handle_irq,
- np->name, &arch_timer_evt);
- if (err) {
- pr_err("arch_timer: can't register interrupt %d (%d)\n",
- arch_timer_ppi, err);
- return err;
- }
-
- clocksource_register_hz(&clocksource_counter, arch_timer_rate);
-
- /* Calibrate the delay loop directly */
- lpj_fine = DIV_ROUND_CLOSEST(arch_timer_rate, HZ);
-
- /* Immediately configure the timer on the boot CPU */
- arch_timer_setup(this_cpu_ptr(&arch_timer_evt));
-
- register_cpu_notifier(&arch_timer_cpu_nb);
-
- return 0;
-}
diff --git a/include/clocksource/arm_generic.h b/include/clocksource/arm_generic.h
deleted file mode 100644
index 5b41b0d..0000000
--- a/include/clocksource/arm_generic.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2012 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef __CLKSOURCE_ARM_GENERIC_H
-#define __CLKSOURCE_ARM_GENERIC_H
-
-extern int arm_generic_timer_init(void);
-
-#endif
--
1.7.0.4
^ permalink raw reply related
* [PATCHv4 11/14] arm64: arm_generic: prevent reading stale time
From: Mark Rutland @ 2013-01-15 17:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358271931-7761-1-git-send-email-mark.rutland@arm.com>
Currently arch_counter_get_cnt{p,v}ct can be speculated, allowing for
stale time values to be read. This could be problematic for the delay
loop and other sensitive functions, as the time delta could jump around
unexpectedly.
This patch adds isbs to arch_counter_get_cnt{p,v}ct, preventing this
possibility.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
arch/arm64/include/asm/arm_generic.h | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/arch/arm64/include/asm/arm_generic.h b/arch/arm64/include/asm/arm_generic.h
index df2aeb8..6ece2f1 100644
--- a/arch/arm64/include/asm/arm_generic.h
+++ b/arch/arm64/include/asm/arm_generic.h
@@ -83,6 +83,7 @@ static inline cycle_t arch_counter_get_cntpct(void)
{
cycle_t cval;
+ isb();
asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
return cval;
@@ -92,6 +93,7 @@ static inline cycle_t arch_counter_get_cntvct(void)
{
cycle_t cval;
+ isb();
asm volatile("mrs %0, cntvct_el0" : "=r" (cval));
return cval;
--
1.7.0.4
^ permalink raw reply related
* [PATCHv4 10/14] arm: arch_timer: move core to drivers/clocksource
From: Mark Rutland @ 2013-01-15 17:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358271931-7761-1-git-send-email-mark.rutland@arm.com>
The core functionality of the arch_timer driver is not directly tied to
anything under arch/arm, and can be split out.
This patch factors out the core of the arch_timer driver, so it can be
shared with other architectures. A couple of functions are added so
that architecture-specific code can interact with the driver without
needing to touch its internals.
The ARM_ARCH_TIMER config variable is moved out to
drivers/clocksource/Kconfig, existing uses in arch/arm are replaced with
HAVE_ARM_ARCH_TIMER, which selects it.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm/Kconfig | 3 +-
arch/arm/include/asm/arch_timer.h | 19 +--
arch/arm/kernel/arch_timer.c | 386 ++--------------------------------
arch/arm/mach-omap2/Kconfig | 2 +-
drivers/clocksource/Kconfig | 3 +
drivers/clocksource/Makefile | 1 +
drivers/clocksource/arm_arch_timer.c | 385 +++++++++++++++++++++++++++++++++
include/clocksource/arm_arch_timer.h | 63 ++++++
8 files changed, 476 insertions(+), 386 deletions(-)
create mode 100644 drivers/clocksource/arm_arch_timer.c
create mode 100644 include/clocksource/arm_arch_timer.h
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 67874b8..e1162f5 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1572,9 +1572,10 @@ config HAVE_ARM_SCU
help
This option enables support for the ARM system coherency unit
-config ARM_ARCH_TIMER
+config HAVE_ARM_ARCH_TIMER
bool "Architected timer support"
depends on CPU_V7
+ select ARM_ARCH_TIMER
help
This option enables support for the ARM architected timer
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index 729f6d9..7ade91d 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -4,22 +4,14 @@
#include <asm/barrier.h>
#include <asm/errno.h>
#include <linux/clocksource.h>
+#include <linux/init.h>
#include <linux/types.h>
+#include <clocksource/arm_arch_timer.h>
+
#ifdef CONFIG_ARM_ARCH_TIMER
int arch_timer_of_register(void);
int arch_timer_sched_clock_init(void);
-struct timecounter *arch_timer_get_timecounter(void);
-
-#define ARCH_TIMER_CTRL_ENABLE (1 << 0)
-#define ARCH_TIMER_CTRL_IT_MASK (1 << 1)
-#define ARCH_TIMER_CTRL_IT_STAT (1 << 2)
-
-#define ARCH_TIMER_REG_CTRL 0
-#define ARCH_TIMER_REG_TVAL 1
-
-#define ARCH_TIMER_PHYS_ACCESS 0
-#define ARCH_TIMER_VIRT_ACCESS 1
/*
* These register accessors are marked inline so the compiler can
@@ -128,11 +120,6 @@ static inline int arch_timer_sched_clock_init(void)
{
return -ENXIO;
}
-
-static inline struct timecounter *arch_timer_get_timecounter(void)
-{
- return NULL;
-}
#endif
#endif
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 94f5033..36ebcf4 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -9,402 +9,52 @@
* published by the Free Software Foundation.
*/
#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/smp.h>
-#include <linux/cpu.h>
-#include <linux/jiffies.h>
-#include <linux/clockchips.h>
-#include <linux/interrupt.h>
-#include <linux/of_irq.h>
-#include <linux/io.h>
+#include <linux/types.h>
#include <asm/delay.h>
-#include <asm/arch_timer.h>
#include <asm/sched_clock.h>
-static u32 arch_timer_rate;
+#include <clocksource/arm_arch_timer.h>
-enum ppi_nr {
- PHYS_SECURE_PPI,
- PHYS_NONSECURE_PPI,
- VIRT_PPI,
- HYP_PPI,
- MAX_TIMER_PPI
-};
-
-static int arch_timer_ppi[MAX_TIMER_PPI];
-
-static struct clock_event_device __percpu *arch_timer_evt;
-static struct delay_timer arch_delay_timer;
-
-static bool arch_timer_use_virtual = true;
-
-/*
- * Architected system timer support.
- */
-
-static irqreturn_t inline timer_handler(const int access,
- struct clock_event_device *evt)
-{
- unsigned long ctrl;
- ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
- if (ctrl & ARCH_TIMER_CTRL_IT_STAT) {
- ctrl |= ARCH_TIMER_CTRL_IT_MASK;
- arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
- evt->event_handler(evt);
- return IRQ_HANDLED;
- }
-
- return IRQ_NONE;
-}
-
-static irqreturn_t arch_timer_handler_virt(int irq, void *dev_id)
-{
- struct clock_event_device *evt = dev_id;
-
- return timer_handler(ARCH_TIMER_VIRT_ACCESS, evt);
-}
-
-static irqreturn_t arch_timer_handler_phys(int irq, void *dev_id)
-{
- struct clock_event_device *evt = dev_id;
-
- return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt);
-}
-
-static inline void timer_set_mode(const int access, int mode)
-{
- unsigned long ctrl;
- switch (mode) {
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
- ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
- arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
- break;
- default:
- break;
- }
-}
-
-static void arch_timer_set_mode_virt(enum clock_event_mode mode,
- struct clock_event_device *clk)
-{
- timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode);
-}
-
-static void arch_timer_set_mode_phys(enum clock_event_mode mode,
- struct clock_event_device *clk)
-{
- timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode);
-}
-
-static inline void set_next_event(const int access, unsigned long evt)
-{
- unsigned long ctrl;
- ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
- ctrl |= ARCH_TIMER_CTRL_ENABLE;
- ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
- arch_timer_reg_write(access, ARCH_TIMER_REG_TVAL, evt);
- arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
-}
-
-static int arch_timer_set_next_event_virt(unsigned long evt,
- struct clock_event_device *unused)
-{
- set_next_event(ARCH_TIMER_VIRT_ACCESS, evt);
- return 0;
-}
-
-static int arch_timer_set_next_event_phys(unsigned long evt,
- struct clock_event_device *unused)
-{
- set_next_event(ARCH_TIMER_PHYS_ACCESS, evt);
- return 0;
-}
-
-static int __cpuinit arch_timer_setup(struct clock_event_device *clk)
-{
- clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP;
- clk->name = "arch_sys_timer";
- clk->rating = 450;
- if (arch_timer_use_virtual) {
- clk->irq = arch_timer_ppi[VIRT_PPI];
- clk->set_mode = arch_timer_set_mode_virt;
- clk->set_next_event = arch_timer_set_next_event_virt;
- } else {
- clk->irq = arch_timer_ppi[PHYS_SECURE_PPI];
- clk->set_mode = arch_timer_set_mode_phys;
- clk->set_next_event = arch_timer_set_next_event_phys;
- }
-
- clk->cpumask = cpumask_of(smp_processor_id());
-
- clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, NULL);
-
- clockevents_config_and_register(clk, arch_timer_rate,
- 0xf, 0x7fffffff);
-
- if (arch_timer_use_virtual)
- enable_percpu_irq(arch_timer_ppi[VIRT_PPI], 0);
- else {
- enable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI], 0);
- if (arch_timer_ppi[PHYS_NONSECURE_PPI])
- enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], 0);
- }
-
- arch_counter_set_user_access();
-
- return 0;
-}
-
-static int arch_timer_available(void)
-{
- u32 freq;
-
- if (arch_timer_rate == 0) {
- freq = arch_timer_get_cntfrq();
-
- /* Check the timer frequency. */
- if (freq == 0) {
- pr_warn("Architected timer frequency not available\n");
- return -EINVAL;
- }
-
- arch_timer_rate = freq;
- }
-
- pr_info_once("Architected local timer running at %lu.%02luMHz (%s).\n",
- (unsigned long)arch_timer_rate / 1000000,
- (unsigned long)(arch_timer_rate / 10000) % 100,
- arch_timer_use_virtual ? "virt" : "phys");
- return 0;
-}
-
-/*
- * Some external users of arch_timer_read_counter (e.g. sched_clock) may try to
- * call it before it has been initialised. Rather than incur a performance
- * penalty checking for initialisation, provide a default implementation that
- * won't lead to time appearing to jump backwards.
- */
-static u64 arch_timer_read_zero(void)
-{
- return 0;
-}
-
-u64 (*arch_timer_read_counter)(void) = arch_timer_read_zero;
-
-static u32 arch_timer_read_counter32(void)
-{
- return arch_timer_read_counter();
-}
-
-static cycle_t arch_counter_read(struct clocksource *cs)
+static unsigned long arch_timer_read_counter_long(void)
{
return arch_timer_read_counter();
}
-static unsigned long arch_timer_read_current_timer(void)
+static u32 arch_timer_read_counter_u32(void)
{
return arch_timer_read_counter();
}
-static cycle_t arch_counter_read_cc(const struct cyclecounter *cc)
-{
- return arch_timer_read_counter();
-}
-
-static struct clocksource clocksource_counter = {
- .name = "arch_sys_counter",
- .rating = 400,
- .read = arch_counter_read,
- .mask = CLOCKSOURCE_MASK(56),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static struct cyclecounter cyclecounter = {
- .read = arch_counter_read_cc,
- .mask = CLOCKSOURCE_MASK(56),
-};
-
-static struct timecounter timecounter;
-
-struct timecounter *arch_timer_get_timecounter(void)
-{
- return &timecounter;
-}
-
-static void __cpuinit arch_timer_stop(struct clock_event_device *clk)
-{
- pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
- clk->irq, smp_processor_id());
-
- if (arch_timer_use_virtual)
- disable_percpu_irq(arch_timer_ppi[VIRT_PPI]);
- else {
- disable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI]);
- if (arch_timer_ppi[PHYS_NONSECURE_PPI])
- disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]);
- }
-
- clk->set_mode(CLOCK_EVT_MODE_UNUSED, clk);
-}
-
-static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self,
- unsigned long action, void *hcpu)
-{
- struct clock_event_device *evt = this_cpu_ptr(arch_timer_evt);
-
- switch (action & ~CPU_TASKS_FROZEN) {
- case CPU_STARTING:
- arch_timer_setup(evt);
- break;
- case CPU_DYING:
- arch_timer_stop(evt);
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block arch_timer_cpu_nb __cpuinitdata = {
- .notifier_call = arch_timer_cpu_notify,
-};
+static struct delay_timer arch_delay_timer;
-static int __init arch_timer_register(void)
+static void __init arch_timer_delay_timer_register(void)
{
- int err;
- int ppi;
-
- err = arch_timer_available();
- if (err)
- goto out;
-
- arch_timer_evt = alloc_percpu(struct clock_event_device);
- if (!arch_timer_evt) {
- err = -ENOMEM;
- goto out;
- }
-
- clocksource_register_hz(&clocksource_counter, arch_timer_rate);
- cyclecounter.mult = clocksource_counter.mult;
- cyclecounter.shift = clocksource_counter.shift;
- timecounter_init(&timecounter, &cyclecounter,
- arch_counter_get_cntpct());
-
- if (arch_timer_use_virtual) {
- ppi = arch_timer_ppi[VIRT_PPI];
- err = request_percpu_irq(ppi, arch_timer_handler_virt,
- "arch_timer", arch_timer_evt);
- } else {
- ppi = arch_timer_ppi[PHYS_SECURE_PPI];
- err = request_percpu_irq(ppi, arch_timer_handler_phys,
- "arch_timer", arch_timer_evt);
- if (!err && arch_timer_ppi[PHYS_NONSECURE_PPI]) {
- ppi = arch_timer_ppi[PHYS_NONSECURE_PPI];
- err = request_percpu_irq(ppi, arch_timer_handler_phys,
- "arch_timer", arch_timer_evt);
- if (err)
- free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
- arch_timer_evt);
- }
- }
-
- if (err) {
- pr_err("arch_timer: can't register interrupt %d (%d)\n",
- ppi, err);
- goto out_free;
- }
-
- err = register_cpu_notifier(&arch_timer_cpu_nb);
- if (err)
- goto out_free_irq;
-
- /* Immediately configure the timer on the boot CPU */
- arch_timer_setup(this_cpu_ptr(arch_timer_evt));
-
/* Use the architected timer for the delay loop. */
- arch_delay_timer.read_current_timer = &arch_timer_read_current_timer;
- arch_delay_timer.freq = arch_timer_rate;
+ arch_delay_timer.read_current_timer = arch_timer_read_counter_long;
+ arch_delay_timer.freq = arch_timer_get_rate();
register_current_timer_delay(&arch_delay_timer);
- return 0;
-
-out_free_irq:
- if (arch_timer_use_virtual)
- free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt);
- else {
- free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
- arch_timer_evt);
- if (arch_timer_ppi[PHYS_NONSECURE_PPI])
- free_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI],
- arch_timer_evt);
- }
-
-out_free:
- free_percpu(arch_timer_evt);
-out:
- return err;
}
-static const struct of_device_id arch_timer_of_match[] __initconst = {
- { .compatible = "arm,armv7-timer", },
- {},
-};
-
int __init arch_timer_of_register(void)
{
- struct device_node *np;
- u32 freq;
- int i;
-
- np = of_find_matching_node(NULL, arch_timer_of_match);
- if (!np) {
- pr_err("arch_timer: can't find DT node\n");
- return -ENODEV;
- }
+ int ret;
- /* Try to determine the frequency from the device tree or CNTFRQ */
- if (!of_property_read_u32(np, "clock-frequency", &freq))
- arch_timer_rate = freq;
+ ret = arch_timer_init();
+ if (ret)
+ return ret;
- for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
- arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
+ arch_timer_delay_timer_register();
- of_node_put(np);
-
- /*
- * If no interrupt provided for virtual timer, we'll have to
- * stick to the physical timer. It'd better be accessible...
- */
- if (!arch_timer_ppi[VIRT_PPI]) {
- arch_timer_use_virtual = false;
-
- if (!arch_timer_ppi[PHYS_SECURE_PPI] ||
- !arch_timer_ppi[PHYS_NONSECURE_PPI]) {
- pr_warn("arch_timer: No interrupt available, giving up\n");
- return -EINVAL;
- }
- }
-
- if (arch_timer_use_virtual)
- arch_timer_read_counter = arch_counter_get_cntvct;
- else
- arch_timer_read_counter = arch_counter_get_cntpct;
-
- return arch_timer_register();
+ return 0;
}
int __init arch_timer_sched_clock_init(void)
{
- int err;
-
- err = arch_timer_available();
- if (err)
- return err;
+ if (arch_timer_get_rate() == 0)
+ return -ENXIO;
- setup_sched_clock(arch_timer_read_counter32,
- 32, arch_timer_rate);
+ setup_sched_clock(arch_timer_read_counter_u32,
+ 32, arch_timer_get_rate());
return 0;
}
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 41b581f..9d7909e 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -76,12 +76,12 @@ config ARCH_OMAP4
config SOC_OMAP5
bool "TI OMAP5"
- select ARM_ARCH_TIMER
select ARM_CPU_SUSPEND if PM
select ARM_GIC
select CPU_V7
select HAVE_SMP
select COMMON_CLK
+ select HAVE_ARM_ARCH_TIMER
comment "OMAP Core Type"
depends on ARCH_OMAP2
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 7fdcbd3..dbb085a 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -58,3 +58,6 @@ config CLKSRC_ARM_GENERIC
def_bool y if ARM64
help
This option enables support for the ARM generic timer.
+
+config ARM_ARCH_TIMER
+ bool
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index f93453d..32f858c 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o
obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o
+obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
new file mode 100644
index 0000000..3e4739d
--- /dev/null
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -0,0 +1,385 @@
+/*
+ * linux/drivers/clocksource/arm_arch_timer.c
+ *
+ * Copyright (C) 2011 ARM Ltd.
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/smp.h>
+#include <linux/cpu.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+
+#include <asm/arch_timer.h>
+
+#include <clocksource/arm_arch_timer.h>
+
+static u32 arch_timer_rate;
+
+enum ppi_nr {
+ PHYS_SECURE_PPI,
+ PHYS_NONSECURE_PPI,
+ VIRT_PPI,
+ HYP_PPI,
+ MAX_TIMER_PPI
+};
+
+static int arch_timer_ppi[MAX_TIMER_PPI];
+
+static struct clock_event_device __percpu *arch_timer_evt;
+
+static bool arch_timer_use_virtual = true;
+
+/*
+ * Architected system timer support.
+ */
+
+static inline irqreturn_t timer_handler(const int access,
+ struct clock_event_device *evt)
+{
+ unsigned long ctrl;
+ ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
+ if (ctrl & ARCH_TIMER_CTRL_IT_STAT) {
+ ctrl |= ARCH_TIMER_CTRL_IT_MASK;
+ arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static irqreturn_t arch_timer_handler_virt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ return timer_handler(ARCH_TIMER_VIRT_ACCESS, evt);
+}
+
+static irqreturn_t arch_timer_handler_phys(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt);
+}
+
+static inline void timer_set_mode(const int access, int mode)
+{
+ unsigned long ctrl;
+ switch (mode) {
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
+ ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
+ arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
+ break;
+ default:
+ break;
+ }
+}
+
+static void arch_timer_set_mode_virt(enum clock_event_mode mode,
+ struct clock_event_device *clk)
+{
+ timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode);
+}
+
+static void arch_timer_set_mode_phys(enum clock_event_mode mode,
+ struct clock_event_device *clk)
+{
+ timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode);
+}
+
+static inline void set_next_event(const int access, unsigned long evt)
+{
+ unsigned long ctrl;
+ ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
+ ctrl |= ARCH_TIMER_CTRL_ENABLE;
+ ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
+ arch_timer_reg_write(access, ARCH_TIMER_REG_TVAL, evt);
+ arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
+}
+
+static int arch_timer_set_next_event_virt(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ set_next_event(ARCH_TIMER_VIRT_ACCESS, evt);
+ return 0;
+}
+
+static int arch_timer_set_next_event_phys(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ set_next_event(ARCH_TIMER_PHYS_ACCESS, evt);
+ return 0;
+}
+
+static int __cpuinit arch_timer_setup(struct clock_event_device *clk)
+{
+ clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP;
+ clk->name = "arch_sys_timer";
+ clk->rating = 450;
+ if (arch_timer_use_virtual) {
+ clk->irq = arch_timer_ppi[VIRT_PPI];
+ clk->set_mode = arch_timer_set_mode_virt;
+ clk->set_next_event = arch_timer_set_next_event_virt;
+ } else {
+ clk->irq = arch_timer_ppi[PHYS_SECURE_PPI];
+ clk->set_mode = arch_timer_set_mode_phys;
+ clk->set_next_event = arch_timer_set_next_event_phys;
+ }
+
+ clk->cpumask = cpumask_of(smp_processor_id());
+
+ clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, NULL);
+
+ clockevents_config_and_register(clk, arch_timer_rate,
+ 0xf, 0x7fffffff);
+
+ if (arch_timer_use_virtual)
+ enable_percpu_irq(arch_timer_ppi[VIRT_PPI], 0);
+ else {
+ enable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI], 0);
+ if (arch_timer_ppi[PHYS_NONSECURE_PPI])
+ enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], 0);
+ }
+
+ arch_counter_set_user_access();
+
+ return 0;
+}
+
+static int arch_timer_available(void)
+{
+ u32 freq;
+
+ if (arch_timer_rate == 0) {
+ freq = arch_timer_get_cntfrq();
+
+ /* Check the timer frequency. */
+ if (freq == 0) {
+ pr_warn("Architected timer frequency not available\n");
+ return -EINVAL;
+ }
+
+ arch_timer_rate = freq;
+ }
+
+ pr_info_once("Architected local timer running at %lu.%02luMHz (%s).\n",
+ (unsigned long)arch_timer_rate / 1000000,
+ (unsigned long)(arch_timer_rate / 10000) % 100,
+ arch_timer_use_virtual ? "virt" : "phys");
+ return 0;
+}
+
+u32 arch_timer_get_rate(void)
+{
+ return arch_timer_rate;
+}
+
+/*
+ * Some external users of arch_timer_read_counter (e.g. sched_clock) may try to
+ * call it before it has been initialised. Rather than incur a performance
+ * penalty checking for initialisation, provide a default implementation that
+ * won't lead to time appearing to jump backwards.
+ */
+static u64 arch_timer_read_zero(void)
+{
+ return 0;
+}
+
+u64 (*arch_timer_read_counter)(void) = arch_timer_read_zero;
+
+static cycle_t arch_counter_read(struct clocksource *cs)
+{
+ return arch_timer_read_counter();
+}
+
+static cycle_t arch_counter_read_cc(const struct cyclecounter *cc)
+{
+ return arch_timer_read_counter();
+}
+
+static struct clocksource clocksource_counter = {
+ .name = "arch_sys_counter",
+ .rating = 400,
+ .read = arch_counter_read,
+ .mask = CLOCKSOURCE_MASK(56),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static struct cyclecounter cyclecounter = {
+ .read = arch_counter_read_cc,
+ .mask = CLOCKSOURCE_MASK(56),
+};
+
+static struct timecounter timecounter;
+
+struct timecounter *arch_timer_get_timecounter(void)
+{
+ return &timecounter;
+}
+
+static void __cpuinit arch_timer_stop(struct clock_event_device *clk)
+{
+ pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
+ clk->irq, smp_processor_id());
+
+ if (arch_timer_use_virtual)
+ disable_percpu_irq(arch_timer_ppi[VIRT_PPI]);
+ else {
+ disable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI]);
+ if (arch_timer_ppi[PHYS_NONSECURE_PPI])
+ disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]);
+ }
+
+ clk->set_mode(CLOCK_EVT_MODE_UNUSED, clk);
+}
+
+static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ struct clock_event_device *evt = this_cpu_ptr(arch_timer_evt);
+
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_STARTING:
+ arch_timer_setup(evt);
+ break;
+ case CPU_DYING:
+ arch_timer_stop(evt);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block arch_timer_cpu_nb __cpuinitdata = {
+ .notifier_call = arch_timer_cpu_notify,
+};
+
+static int __init arch_timer_register(void)
+{
+ int err;
+ int ppi;
+
+ err = arch_timer_available();
+ if (err)
+ goto out;
+
+ arch_timer_evt = alloc_percpu(struct clock_event_device);
+ if (!arch_timer_evt) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ clocksource_register_hz(&clocksource_counter, arch_timer_rate);
+ cyclecounter.mult = clocksource_counter.mult;
+ cyclecounter.shift = clocksource_counter.shift;
+ timecounter_init(&timecounter, &cyclecounter,
+ arch_counter_get_cntpct());
+
+ if (arch_timer_use_virtual) {
+ ppi = arch_timer_ppi[VIRT_PPI];
+ err = request_percpu_irq(ppi, arch_timer_handler_virt,
+ "arch_timer", arch_timer_evt);
+ } else {
+ ppi = arch_timer_ppi[PHYS_SECURE_PPI];
+ err = request_percpu_irq(ppi, arch_timer_handler_phys,
+ "arch_timer", arch_timer_evt);
+ if (!err && arch_timer_ppi[PHYS_NONSECURE_PPI]) {
+ ppi = arch_timer_ppi[PHYS_NONSECURE_PPI];
+ err = request_percpu_irq(ppi, arch_timer_handler_phys,
+ "arch_timer", arch_timer_evt);
+ if (err)
+ free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
+ arch_timer_evt);
+ }
+ }
+
+ if (err) {
+ pr_err("arch_timer: can't register interrupt %d (%d)\n",
+ ppi, err);
+ goto out_free;
+ }
+
+ err = register_cpu_notifier(&arch_timer_cpu_nb);
+ if (err)
+ goto out_free_irq;
+
+ /* Immediately configure the timer on the boot CPU */
+ arch_timer_setup(this_cpu_ptr(arch_timer_evt));
+
+ return 0;
+
+out_free_irq:
+ if (arch_timer_use_virtual)
+ free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt);
+ else {
+ free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
+ arch_timer_evt);
+ if (arch_timer_ppi[PHYS_NONSECURE_PPI])
+ free_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI],
+ arch_timer_evt);
+ }
+
+out_free:
+ free_percpu(arch_timer_evt);
+out:
+ return err;
+}
+
+static const struct of_device_id arch_timer_of_match[] __initconst = {
+ { .compatible = "arm,armv7-timer", },
+ {},
+};
+
+int __init arch_timer_init(void)
+{
+ struct device_node *np;
+ u32 freq;
+ int i;
+
+ np = of_find_matching_node(NULL, arch_timer_of_match);
+ if (!np) {
+ pr_err("arch_timer: can't find DT node\n");
+ return -ENODEV;
+ }
+
+ /* Try to determine the frequency from the device tree or CNTFRQ */
+ if (!of_property_read_u32(np, "clock-frequency", &freq))
+ arch_timer_rate = freq;
+
+ for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
+ arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
+
+ of_node_put(np);
+
+ /*
+ * If no interrupt provided for virtual timer, we'll have to
+ * stick to the physical timer. It'd better be accessible...
+ */
+ if (!arch_timer_ppi[VIRT_PPI]) {
+ arch_timer_use_virtual = false;
+
+ if (!arch_timer_ppi[PHYS_SECURE_PPI] ||
+ !arch_timer_ppi[PHYS_NONSECURE_PPI]) {
+ pr_warn("arch_timer: No interrupt available, giving up\n");
+ return -EINVAL;
+ }
+ }
+
+ if (arch_timer_use_virtual)
+ arch_timer_read_counter = arch_counter_get_cntvct;
+ else
+ arch_timer_read_counter = arch_counter_get_cntpct;
+
+ return arch_timer_register();
+}
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
new file mode 100644
index 0000000..b61f996
--- /dev/null
+++ b/include/clocksource/arm_arch_timer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __CLKSOURCE_ARM_ARCH_TIMER_H
+#define __CLKSOURCE_ARM_ARCH_TIMER_H
+
+#include <linux/clocksource.h>
+#include <linux/types.h>
+
+#define ARCH_TIMER_CTRL_ENABLE (1 << 0)
+#define ARCH_TIMER_CTRL_IT_MASK (1 << 1)
+#define ARCH_TIMER_CTRL_IT_STAT (1 << 2)
+
+#define ARCH_TIMER_REG_CTRL 0
+#define ARCH_TIMER_REG_TVAL 1
+
+#define ARCH_TIMER_PHYS_ACCESS 0
+#define ARCH_TIMER_VIRT_ACCESS 1
+
+#ifdef CONFIG_ARM_ARCH_TIMER
+
+extern int arch_timer_init(void);
+extern u32 arch_timer_get_rate(void);
+extern u64 (*arch_timer_read_counter)(void);
+extern struct timecounter *arch_timer_get_timecounter(void);
+
+#else
+
+static inline int arch_timer_init(void)
+{
+ return -ENXIO;
+}
+
+static inline u32 arch_timer_get_rate(void)
+{
+ return 0;
+}
+
+static inline u64 arch_timer_read_counter(void)
+{
+ return 0;
+}
+
+static struct timecounter *arch_timer_get_timecounter(void)
+{
+ return NULL;
+}
+
+#endif
+
+#endif
--
1.7.0.4
^ permalink raw reply related
* [PATCHv4 09/14] arm: arch_timer: add arch_counter_set_user_access
From: Mark Rutland @ 2013-01-15 17:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358271931-7761-1-git-send-email-mark.rutland@arm.com>
Several bits in CNTKCTL reset to 0, including PL0VTEN. For architectures
using the generic timer which wish to have a fast gettimeofday vDSO
implementation, these bits must be set to 1 by the kernel. For
architectures without a vDSO, it's best to leave the bits set to 0 for
now to ensure that if and when support is added, it's implemented sanely
architecture wide.
As the bootloader might set PL0VTEN to a value that doesn't correspond
to that which the kernel prefers, we must explicitly set it to the
architecture port's preferred value.
This patch adds arch_counter_set_user_access, which sets the PL0 access
permissions to that required by the architecture. For arch/arm, this
currently means disabling all userspace access.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
arch/arm/include/asm/arch_timer.h | 12 ++++++++++++
arch/arm/kernel/arch_timer.c | 2 ++
2 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index 75975d9..729f6d9 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -106,6 +106,18 @@ static inline u64 arch_counter_get_cntvct(void)
asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval));
return cval;
}
+
+static inline void __cpuinit arch_counter_set_user_access(void)
+{
+ u32 cntkctl;
+
+ asm volatile("mrc p15, 0, %0, c14, c1, 0" : "=r" (cntkctl));
+
+ /* disable user access to everything */
+ cntkctl &= ~((3 << 8) | (7 << 0));
+
+ asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl));
+}
#else
static inline int arch_timer_of_register(void)
{
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index c8dfec0..94f5033 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -155,6 +155,8 @@ static int __cpuinit arch_timer_setup(struct clock_event_device *clk)
enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], 0);
}
+ arch_counter_set_user_access();
+
return 0;
}
--
1.7.0.4
^ permalink raw reply related
* [PATCHv4 08/14] arm: arch_timer: divorce from local_timer api
From: Mark Rutland @ 2013-01-15 17:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358271931-7761-1-git-send-email-mark.rutland@arm.com>
Currently, the arch_timer driver is tied to the arm port, as it relies
on code in arch/arm/smp.c to setup and teardown timers as cores are
hotplugged on and off. The timer is registered through an arm-specific
registration mechanism, preventing sharing the driver with the arm64
port.
This patch moves the driver to using a cpu notifier instead, making it
easier to port.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
arch/arm/kernel/arch_timer.c | 52 +++++++++++++++++++++++------------------
1 files changed, 29 insertions(+), 23 deletions(-)
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index e973cc0..c8dfec0 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -21,7 +21,6 @@
#include <linux/io.h>
#include <asm/delay.h>
-#include <asm/localtimer.h>
#include <asm/arch_timer.h>
#include <asm/sched_clock.h>
@@ -37,7 +36,7 @@ enum ppi_nr {
static int arch_timer_ppi[MAX_TIMER_PPI];
-static struct clock_event_device __percpu **arch_timer_evt;
+static struct clock_event_device __percpu *arch_timer_evt;
static struct delay_timer arch_delay_timer;
static bool arch_timer_use_virtual = true;
@@ -63,14 +62,14 @@ static irqreturn_t inline timer_handler(const int access,
static irqreturn_t arch_timer_handler_virt(int irq, void *dev_id)
{
- struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+ struct clock_event_device *evt = dev_id;
return timer_handler(ARCH_TIMER_VIRT_ACCESS, evt);
}
static irqreturn_t arch_timer_handler_phys(int irq, void *dev_id)
{
- struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+ struct clock_event_device *evt = dev_id;
return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt);
}
@@ -141,13 +140,13 @@ static int __cpuinit arch_timer_setup(struct clock_event_device *clk)
clk->set_next_event = arch_timer_set_next_event_phys;
}
+ clk->cpumask = cpumask_of(smp_processor_id());
+
clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, NULL);
clockevents_config_and_register(clk, arch_timer_rate,
0xf, 0x7fffffff);
- *__this_cpu_ptr(arch_timer_evt) = clk;
-
if (arch_timer_use_virtual)
enable_percpu_irq(arch_timer_ppi[VIRT_PPI], 0);
else {
@@ -251,12 +250,26 @@ static void __cpuinit arch_timer_stop(struct clock_event_device *clk)
clk->set_mode(CLOCK_EVT_MODE_UNUSED, clk);
}
-static struct local_timer_ops arch_timer_ops __cpuinitdata = {
- .setup = arch_timer_setup,
- .stop = arch_timer_stop,
-};
+static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ struct clock_event_device *evt = this_cpu_ptr(arch_timer_evt);
+
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_STARTING:
+ arch_timer_setup(evt);
+ break;
+ case CPU_DYING:
+ arch_timer_stop(evt);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
-static struct clock_event_device arch_timer_global_evt;
+static struct notifier_block arch_timer_cpu_nb __cpuinitdata = {
+ .notifier_call = arch_timer_cpu_notify,
+};
static int __init arch_timer_register(void)
{
@@ -267,7 +280,7 @@ static int __init arch_timer_register(void)
if (err)
goto out;
- arch_timer_evt = alloc_percpu(struct clock_event_device *);
+ arch_timer_evt = alloc_percpu(struct clock_event_device);
if (!arch_timer_evt) {
err = -ENOMEM;
goto out;
@@ -303,20 +316,13 @@ static int __init arch_timer_register(void)
goto out_free;
}
- err = local_timer_register(&arch_timer_ops);
- if (err) {
- /*
- * We couldn't register as a local timer (could be
- * because we're on a UP platform, or because some
- * other local timer is already present...). Try as a
- * global timer instead.
- */
- arch_timer_global_evt.cpumask = cpumask_of(0);
- err = arch_timer_setup(&arch_timer_global_evt);
- }
+ err = register_cpu_notifier(&arch_timer_cpu_nb);
if (err)
goto out_free_irq;
+ /* Immediately configure the timer on the boot CPU */
+ arch_timer_setup(this_cpu_ptr(arch_timer_evt));
+
/* Use the architected timer for the delay loop. */
arch_delay_timer.read_current_timer = &arch_timer_read_current_timer;
arch_delay_timer.freq = arch_timer_rate;
--
1.7.0.4
^ permalink raw reply related
* [PATCHv4 07/14] arm: arch_timer: add isbs to register accessors
From: Mark Rutland @ 2013-01-15 17:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358271931-7761-1-git-send-email-mark.rutland@arm.com>
Without the isbs in arch_timer_get_cnt{p,v}ct the cpu may speculate
reads and return stale values. This could be bad for code sensitive to
changes in expected deltas between calls (e.g. the delay loop).
Without isbs in arch_timer_reg_write the processor may reorder
instructions around enabling/disabling of the timer or writing the
compare value, which we probably don't want.
This patch adds isbs to prevent those issues.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
arch/arm/include/asm/arch_timer.h | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index db0fdc4..75975d9 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -49,6 +49,8 @@ static inline void arch_timer_reg_write(const int access, const int reg, u32 val
break;
}
}
+
+ isb();
}
static inline u32 arch_timer_reg_read(const int access, const int reg)
@@ -91,6 +93,7 @@ static inline u64 arch_counter_get_cntpct(void)
{
u64 cval;
+ isb();
asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
return cval;
}
@@ -99,6 +102,7 @@ static inline u64 arch_counter_get_cntvct(void)
{
u64 cval;
+ isb();
asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval));
return cval;
}
--
1.7.0.4
^ permalink raw reply related
* [PATCHv4 06/14] arm: arch_timer: factor out register accessors
From: Mark Rutland @ 2013-01-15 17:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358271931-7761-1-git-send-email-mark.rutland@arm.com>
Currently the arch_timer register accessors are thrown together with
the main driver, preventing us from porting the driver to other
architectures.
This patch moves the register accessors into a header file, as with
the arm64 version. Constants required by the accessors are also moved.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
arch/arm/include/asm/arch_timer.h | 94 +++++++++++++++++++++++++++++++++++++
arch/arm/kernel/arch_timer.c | 92 ------------------------------------
2 files changed, 94 insertions(+), 92 deletions(-)
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index d40229d..db0fdc4 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -1,13 +1,107 @@
#ifndef __ASMARM_ARCH_TIMER_H
#define __ASMARM_ARCH_TIMER_H
+#include <asm/barrier.h>
#include <asm/errno.h>
#include <linux/clocksource.h>
+#include <linux/types.h>
#ifdef CONFIG_ARM_ARCH_TIMER
int arch_timer_of_register(void);
int arch_timer_sched_clock_init(void);
struct timecounter *arch_timer_get_timecounter(void);
+
+#define ARCH_TIMER_CTRL_ENABLE (1 << 0)
+#define ARCH_TIMER_CTRL_IT_MASK (1 << 1)
+#define ARCH_TIMER_CTRL_IT_STAT (1 << 2)
+
+#define ARCH_TIMER_REG_CTRL 0
+#define ARCH_TIMER_REG_TVAL 1
+
+#define ARCH_TIMER_PHYS_ACCESS 0
+#define ARCH_TIMER_VIRT_ACCESS 1
+
+/*
+ * These register accessors are marked inline so the compiler can
+ * nicely work out which register we want, and chuck away the rest of
+ * the code. At least it does so with a recent GCC (4.6.3).
+ */
+static inline void arch_timer_reg_write(const int access, const int reg, u32 val)
+{
+ if (access == ARCH_TIMER_PHYS_ACCESS) {
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("mcr p15, 0, %0, c14, c2, 1" : : "r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("mcr p15, 0, %0, c14, c2, 0" : : "r" (val));
+ break;
+ }
+ }
+
+ if (access == ARCH_TIMER_VIRT_ACCESS) {
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("mcr p15, 0, %0, c14, c3, 1" : : "r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("mcr p15, 0, %0, c14, c3, 0" : : "r" (val));
+ break;
+ }
+ }
+}
+
+static inline u32 arch_timer_reg_read(const int access, const int reg)
+{
+ u32 val = 0;
+
+ if (access == ARCH_TIMER_PHYS_ACCESS) {
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val));
+ break;
+ }
+ }
+
+ if (access == ARCH_TIMER_VIRT_ACCESS) {
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("mrc p15, 0, %0, c14, c3, 1" : "=r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("mrc p15, 0, %0, c14, c3, 0" : "=r" (val));
+ break;
+ }
+ }
+
+ return val;
+}
+
+static inline u32 arch_timer_get_cntfrq(void)
+{
+ u32 val;
+ asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val));
+ return val;
+}
+
+static inline u64 arch_counter_get_cntpct(void)
+{
+ u64 cval;
+
+ asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
+ return cval;
+}
+
+static inline u64 arch_counter_get_cntvct(void)
+{
+ u64 cval;
+
+ asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval));
+ return cval;
+}
#else
static inline int arch_timer_of_register(void)
{
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index f31c9ee..e973cc0 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -46,98 +46,6 @@ static bool arch_timer_use_virtual = true;
* Architected system timer support.
*/
-#define ARCH_TIMER_CTRL_ENABLE (1 << 0)
-#define ARCH_TIMER_CTRL_IT_MASK (1 << 1)
-#define ARCH_TIMER_CTRL_IT_STAT (1 << 2)
-
-#define ARCH_TIMER_REG_CTRL 0
-#define ARCH_TIMER_REG_TVAL 1
-
-#define ARCH_TIMER_PHYS_ACCESS 0
-#define ARCH_TIMER_VIRT_ACCESS 1
-
-/*
- * These register accessors are marked inline so the compiler can
- * nicely work out which register we want, and chuck away the rest of
- * the code. At least it does so with a recent GCC (4.6.3).
- */
-static inline void arch_timer_reg_write(const int access, const int reg, u32 val)
-{
- if (access == ARCH_TIMER_PHYS_ACCESS) {
- switch (reg) {
- case ARCH_TIMER_REG_CTRL:
- asm volatile("mcr p15, 0, %0, c14, c2, 1" : : "r" (val));
- break;
- case ARCH_TIMER_REG_TVAL:
- asm volatile("mcr p15, 0, %0, c14, c2, 0" : : "r" (val));
- break;
- }
- }
-
- if (access == ARCH_TIMER_VIRT_ACCESS) {
- switch (reg) {
- case ARCH_TIMER_REG_CTRL:
- asm volatile("mcr p15, 0, %0, c14, c3, 1" : : "r" (val));
- break;
- case ARCH_TIMER_REG_TVAL:
- asm volatile("mcr p15, 0, %0, c14, c3, 0" : : "r" (val));
- break;
- }
- }
-
- isb();
-}
-
-static inline u32 arch_timer_reg_read(const int access, const int reg)
-{
- u32 val = 0;
-
- if (access == ARCH_TIMER_PHYS_ACCESS) {
- switch (reg) {
- case ARCH_TIMER_REG_CTRL:
- asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
- break;
- case ARCH_TIMER_REG_TVAL:
- asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val));
- break;
- }
- }
-
- if (access == ARCH_TIMER_VIRT_ACCESS) {
- switch (reg) {
- case ARCH_TIMER_REG_CTRL:
- asm volatile("mrc p15, 0, %0, c14, c3, 1" : "=r" (val));
- break;
- case ARCH_TIMER_REG_TVAL:
- asm volatile("mrc p15, 0, %0, c14, c3, 0" : "=r" (val));
- break;
- }
- }
-
- return val;
-}
-
-static inline u32 arch_timer_get_cntfrq(void)
-{
- u32 val;
- asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val));
- return val;
-}
-
-static inline u64 arch_counter_get_cntpct(void)
-{
- u64 cval;
- asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
- return cval;
-}
-
-static inline u64 arch_counter_get_cntvct(void)
-{
- u64 cval;
- asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval));
- return cval;
-}
-
static irqreturn_t inline timer_handler(const int access,
struct clock_event_device *evt)
{
--
1.7.0.4
^ permalink raw reply related
* [PATCHv4 05/14] arm: arch_timer: split cntfrq accessor
From: Mark Rutland @ 2013-01-15 17:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358271931-7761-1-git-send-email-mark.rutland@arm.com>
The CNTFRQ register is not duplicated for physical and virtual timers,
and accessing it as if it were is confusing.
Instead, use a separate accessor which doesn't take the access type
as a parameter.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
arch/arm/kernel/arch_timer.c | 16 +++++++++-------
1 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index eb78f43..f31c9ee 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -51,8 +51,7 @@ static bool arch_timer_use_virtual = true;
#define ARCH_TIMER_CTRL_IT_STAT (1 << 2)
#define ARCH_TIMER_REG_CTRL 0
-#define ARCH_TIMER_REG_FREQ 1
-#define ARCH_TIMER_REG_TVAL 2
+#define ARCH_TIMER_REG_TVAL 1
#define ARCH_TIMER_PHYS_ACCESS 0
#define ARCH_TIMER_VIRT_ACCESS 1
@@ -101,9 +100,6 @@ static inline u32 arch_timer_reg_read(const int access, const int reg)
case ARCH_TIMER_REG_TVAL:
asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val));
break;
- case ARCH_TIMER_REG_FREQ:
- asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val));
- break;
}
}
@@ -121,6 +117,13 @@ static inline u32 arch_timer_reg_read(const int access, const int reg)
return val;
}
+static inline u32 arch_timer_get_cntfrq(void)
+{
+ u32 val;
+ asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val));
+ return val;
+}
+
static inline u64 arch_counter_get_cntpct(void)
{
u64 cval;
@@ -253,8 +256,7 @@ static int arch_timer_available(void)
u32 freq;
if (arch_timer_rate == 0) {
- freq = arch_timer_reg_read(ARCH_TIMER_PHYS_ACCESS,
- ARCH_TIMER_REG_FREQ);
+ freq = arch_timer_get_cntfrq();
/* Check the timer frequency. */
if (freq == 0) {
--
1.7.0.4
^ permalink raw reply related
* [PATCHv4 04/14] arm: arch_timer: standardise counter reading
From: Mark Rutland @ 2013-01-15 17:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358271931-7761-1-git-send-email-mark.rutland@arm.com>
We're currently inconsistent with respect to our accesses to the
physical and virtual counters, mixing and matching the two.
This patch introduces and uses a function pointer for accessing the
correct counter based on whether we're using physical or virtual
interrupts. All current accesses to the counter accessors are redirected
through it.
When the driver is moved out to drivers/clocksource, there's the
possibility that code called before the timer code is initialised will
attempt to call arch_timer_read_counter (e.g. sched_clock for AArch64).
To avoid having to have to check whether the timer has been initialised
either in arch_timer_read_counter or one of it's callers, a default
implementation is assigned that simply returns 0.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
arch/arm/kernel/arch_timer.c | 58 ++++++++++++++++--------------------------
1 files changed, 22 insertions(+), 36 deletions(-)
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 498c29f..eb78f43 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -272,51 +272,37 @@ static int arch_timer_available(void)
return 0;
}
-static u32 notrace arch_counter_get_cntpct32(void)
+/*
+ * Some external users of arch_timer_read_counter (e.g. sched_clock) may try to
+ * call it before it has been initialised. Rather than incur a performance
+ * penalty checking for initialisation, provide a default implementation that
+ * won't lead to time appearing to jump backwards.
+ */
+static u64 arch_timer_read_zero(void)
{
- cycle_t cnt = arch_counter_get_cntpct();
-
- /*
- * The sched_clock infrastructure only knows about counters
- * with at most 32bits. Forget about the upper 24 bits for the
- * time being...
- */
- return (u32)cnt;
+ return 0;
}
-static u32 notrace arch_counter_get_cntvct32(void)
-{
- cycle_t cnt = arch_counter_get_cntvct();
+u64 (*arch_timer_read_counter)(void) = arch_timer_read_zero;
- /*
- * The sched_clock infrastructure only knows about counters
- * with at most 32bits. Forget about the upper 24 bits for the
- * time being...
- */
- return (u32)cnt;
+static u32 arch_timer_read_counter32(void)
+{
+ return arch_timer_read_counter();
}
static cycle_t arch_counter_read(struct clocksource *cs)
{
- /*
- * Always use the physical counter for the clocksource.
- * CNTHCTL.PL1PCTEN must be set to 1.
- */
- return arch_counter_get_cntpct();
+ return arch_timer_read_counter();
}
static unsigned long arch_timer_read_current_timer(void)
{
- return arch_counter_get_cntpct();
+ return arch_timer_read_counter();
}
static cycle_t arch_counter_read_cc(const struct cyclecounter *cc)
{
- /*
- * Always use the physical counter for the clocksource.
- * CNTHCTL.PL1PCTEN must be set to 1.
- */
- return arch_counter_get_cntpct();
+ return arch_timer_read_counter();
}
static struct clocksource clocksource_counter = {
@@ -484,23 +470,23 @@ int __init arch_timer_of_register(void)
}
}
+ if (arch_timer_use_virtual)
+ arch_timer_read_counter = arch_counter_get_cntvct;
+ else
+ arch_timer_read_counter = arch_counter_get_cntpct;
+
return arch_timer_register();
}
int __init arch_timer_sched_clock_init(void)
{
- u32 (*cnt32)(void);
int err;
err = arch_timer_available();
if (err)
return err;
- if (arch_timer_use_virtual)
- cnt32 = arch_counter_get_cntvct32;
- else
- cnt32 = arch_counter_get_cntpct32;
-
- setup_sched_clock(cnt32, 32, arch_timer_rate);
+ setup_sched_clock(arch_timer_read_counter32,
+ 32, arch_timer_rate);
return 0;
}
--
1.7.0.4
^ permalink raw reply related
* [PATCHv4 03/14] arm: arch_timer: use u64/u32 for register data
From: Mark Rutland @ 2013-01-15 17:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358271931-7761-1-git-send-email-mark.rutland@arm.com>
To ensure the correct size of types, use u64 for the return value of
arch_timer_get_cnt{p,v}ct, and u32 for arch_timer_rate, matching the
size of the registers these values are taken from. While we're changing
them anyway, simplify the implementation of arch_timer_get_cnt{p,v}ct.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
arch/arm/kernel/arch_timer.c | 30 +++++++++++-------------------
1 files changed, 11 insertions(+), 19 deletions(-)
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 1bb3b58..498c29f 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -25,7 +25,7 @@
#include <asm/arch_timer.h>
#include <asm/sched_clock.h>
-static unsigned long arch_timer_rate;
+static u32 arch_timer_rate;
enum ppi_nr {
PHYS_SECURE_PPI,
@@ -121,27 +121,18 @@ static inline u32 arch_timer_reg_read(const int access, const int reg)
return val;
}
-static inline cycle_t arch_timer_counter_read(const int access)
+static inline u64 arch_counter_get_cntpct(void)
{
- cycle_t cval = 0;
-
- if (access == ARCH_TIMER_PHYS_ACCESS)
- asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
-
- if (access == ARCH_TIMER_VIRT_ACCESS)
- asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval));
-
+ u64 cval;
+ asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
return cval;
}
-static inline cycle_t arch_counter_get_cntpct(void)
-{
- return arch_timer_counter_read(ARCH_TIMER_PHYS_ACCESS);
-}
-
-static inline cycle_t arch_counter_get_cntvct(void)
+static inline u64 arch_counter_get_cntvct(void)
{
- return arch_timer_counter_read(ARCH_TIMER_VIRT_ACCESS);
+ u64 cval;
+ asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval));
+ return cval;
}
static irqreturn_t inline timer_handler(const int access,
@@ -259,7 +250,7 @@ static int __cpuinit arch_timer_setup(struct clock_event_device *clk)
static int arch_timer_available(void)
{
- unsigned long freq;
+ u32 freq;
if (arch_timer_rate == 0) {
freq = arch_timer_reg_read(ARCH_TIMER_PHYS_ACCESS,
@@ -275,7 +266,8 @@ static int arch_timer_available(void)
}
pr_info_once("Architected local timer running at %lu.%02luMHz (%s).\n",
- arch_timer_rate / 1000000, (arch_timer_rate / 10000) % 100,
+ (unsigned long)arch_timer_rate / 1000000,
+ (unsigned long)(arch_timer_rate / 10000) % 100,
arch_timer_use_virtual ? "virt" : "phys");
return 0;
}
--
1.7.0.4
^ permalink raw reply related
* [PATCHv4 02/14] arm: arch_timer: remove redundant available check
From: Mark Rutland @ 2013-01-15 17:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358271931-7761-1-git-send-email-mark.rutland@arm.com>
This check is a holdover from the pre-devicetree days. As the timer
is not probed except by platforms which register it via devicetree,
it's not strictly necessary.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm/kernel/arch_timer.c | 12 ------------
1 files changed, 0 insertions(+), 12 deletions(-)
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 6dd73c6..1bb3b58 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -20,11 +20,9 @@
#include <linux/of_irq.h>
#include <linux/io.h>
-#include <asm/cputype.h>
#include <asm/delay.h>
#include <asm/localtimer.h>
#include <asm/arch_timer.h>
-#include <asm/system_info.h>
#include <asm/sched_clock.h>
static unsigned long arch_timer_rate;
@@ -259,20 +257,10 @@ static int __cpuinit arch_timer_setup(struct clock_event_device *clk)
return 0;
}
-/* Is the optional system timer available? */
-static int local_timer_is_architected(void)
-{
- return (cpu_architecture() >= CPU_ARCH_ARMv7) &&
- ((read_cpuid_ext(CPUID_EXT_PFR1) >> 16) & 0xf) == 1;
-}
-
static int arch_timer_available(void)
{
unsigned long freq;
- if (!local_timer_is_architected())
- return -ENXIO;
-
if (arch_timer_rate == 0) {
freq = arch_timer_reg_read(ARCH_TIMER_PHYS_ACCESS,
ARCH_TIMER_REG_FREQ);
--
1.7.0.4
^ permalink raw reply related
* [PATCHv4 01/14] arm: arch_timer: balance device_node refcounting
From: Mark Rutland @ 2013-01-15 17:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358271931-7761-1-git-send-email-mark.rutland@arm.com>
When we get the device_node for the arch timer, it's refcount is
automatically incremented in of_find_matching_node, but it is
never decremented.
This patch decrements the refcount on the node after we're finished
using it.
Reported-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
arch/arm/kernel/arch_timer.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index c8ef207..6dd73c6 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -488,6 +488,8 @@ int __init arch_timer_of_register(void)
for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
+ of_node_put(np);
+
/*
* If no interrupt provided for virtual timer, we'll have to
* stick to the physical timer. It'd better be accessible...
--
1.7.0.4
^ permalink raw reply related
* [PATCHv4 00/14] Unify arm_generic and arch_timer drivers
From: Mark Rutland @ 2013-01-15 17:45 UTC (permalink / raw)
To: linux-arm-kernel
This is an update to v3 of the series I posted earlier this month [1].
Changes since v3:
* Rebase to v3.8-rc3 (fixing arm64 Kconfig conflict).
* Use physical timers if hyp mode is available.
* Separate the addition of isbs into separate patches.
* Change arch_timer_read_counter into a function pointer.
* Style fixups.
* Kconfig: s/USE_ARM_ARCH_TIMER/HAVE_ARM_ARCH_TIMER/
Changes since v2:
* Rebase to v3.8-rc2
Changes since v1:
* Rename arch_counter_{enable=>set}_user_access.
* Explicitly disable access to counters from userspace on arm.
* Add device_node refcounting fix.
* Fix conflict with Will Deacon's AArch64 vdso changes.
* Simplify the cpu notifier.
* Fix a couple of style issues.
Currently we have two drivers for the ARM generic / architected timer,
arch_timer in arch/arm, and arm_generic in drivers/clocksource. This is
an unnecessary duplication of code, and will only lead to maintenance
headaches later.
This patch series splits the generic portion of the arch_timer out to
drivers/clocksource, and ports the arm/arm64 code to use it. The now
unused arm_generic driver is removed in the process.
Separating the arch_timer driver from the arm-specific local_timer api
currently loses us broadcast timer support. I've posted another series
[2] which remedies this by decoupling the timer broadcast mechanism from
drivers.
The series applies to v3.8-rc3, and has been tested on a TC2 test chip.
It also applies to Catalin's soc-armv8-model branch [3], the result of
which has been tested on an AArch64 model (with additional interrupts
listed in the dt).
Christoffer, I've folded in a patch from Marc to use physical timers if
hyp mode is available. This should solve the conflict with your KVM/ARM
architected timers support patches.
Thanks,
Mark.
[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2013-January/140560.html
[2] http://lists.infradead.org/pipermail/linux-arm-kernel/2013-January/141706.html
[3] git://git.kernel.org/pub/scm/linux/kernel/git/cmarinas/linux-aarch64.git soc-armv8-model
Marc Zyngier (1):
ARM: arch_timers: switch to physical timers if HYP mode is available
Mark Rutland (13):
arm: arch_timer: balance device_node refcounting
arm: arch_timer: remove redundant available check
arm: arch_timer: use u64/u32 for register data
arm: arch_timer: standardise counter reading
arm: arch_timer: split cntfrq accessor
arm: arch_timer: factor out register accessors
arm: arch_timer: add isbs to register accessors
arm: arch_timer: divorce from local_timer api
arm: arch_timer: add arch_counter_set_user_access
arm: arch_timer: move core to drivers/clocksource
arm64: arm_generic: prevent reading stale time
arm64: move from arm_generic to arm_arch_timer
Documentation: Add ARMv8 to arch_timer devicetree
.../devicetree/bindings/arm/arch_timer.txt | 7 +-
arch/arm/Kconfig | 3 +-
arch/arm/include/asm/arch_timer.h | 109 ++++-
arch/arm/kernel/arch_timer.c | 504 +-------------------
arch/arm/mach-omap2/Kconfig | 2 +-
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/arch_timer.h | 133 +++++
arch/arm64/include/asm/arm_generic.h | 100 ----
arch/arm64/kernel/time.c | 29 +-
drivers/clocksource/Kconfig | 6 +-
drivers/clocksource/Makefile | 2 +-
drivers/clocksource/arm_arch_timer.c | 391 +++++++++++++++
drivers/clocksource/arm_generic.c | 232 ---------
include/clocksource/arm_arch_timer.h | 63 +++
include/clocksource/arm_generic.h | 21 -
15 files changed, 748 insertions(+), 855 deletions(-)
create mode 100644 arch/arm64/include/asm/arch_timer.h
delete mode 100644 arch/arm64/include/asm/arm_generic.h
create mode 100644 drivers/clocksource/arm_arch_timer.c
delete mode 100644 drivers/clocksource/arm_generic.c
create mode 100644 include/clocksource/arm_arch_timer.h
delete mode 100644 include/clocksource/arm_generic.h
^ permalink raw reply
* [PATCH v2] mtd: vt8500: Add support for Wondermedia Serial Flash Controller
From: Tony Prisk @ 2013-01-15 17:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358261750.2731.148.camel@sauron.fi.intel.com>
On Tue, 2013-01-15 at 16:55 +0200, Artem Bityutskiy wrote:
> On Mon, 2012-12-31 at 10:00 +1300, Tony Prisk wrote:
> > This patch adds support for the Wondermedia serial flash controller
> > found on WM8505, WM8650 and WM8850 SoCs.
> >
> > Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
> > ---
> > v2: Whitespace tidyup
>
> Hi, would you please take a look at these warings, identified by aiaiai:
>
> Successfully built configuration "x86_64_defconfig,x86_64,", results:
>
> --- before_patching.log
> +++ after_patching.log
> @@ @@
> +drivers/mtd/devices/wmt_sflash.c: In function ?sf_read?:
> +drivers/mtd/devices/wmt_sflash.c:425:9: warning: format ?%d? expects argument of type ?int?, but argument 4 has type ?size_t? [-Wformat]
> +drivers/mtd/devices/wmt_sflash.c: In function ?sf_sector_write?:
> +drivers/mtd/devices/wmt_sflash.c:442:16: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
> +drivers/mtd/devices/wmt_sflash.c:442:24: warning: cast removes address space of expression [sparse]
> +drivers/mtd/devices/wmt_sflash.c:458:16: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
> +drivers/mtd/devices/wmt_sflash.c:458:31: warning: incorrect type in argument 1 (different address spaces) [sparse]
> +drivers/mtd/devices/wmt_sflash.c:458:31: expected void volatile [noderef] <asn:2>*dst [sparse]
> +drivers/mtd/devices/wmt_sflash.c:458:31: got unsigned char [usertype] *<noident> [sparse]
> +drivers/mtd/devices/wmt_sflash.c:465:17: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
> +drivers/mtd/devices/wmt_sflash.c:465:39: warning: incorrect type in argument 1 (different address spaces) [sparse]
> +drivers/mtd/devices/wmt_sflash.c:465:39: expected void volatile [noderef] <asn:2>*dst [sparse]
> +drivers/mtd/devices/wmt_sflash.c:465:39: got unsigned char [usertype] *<noident> [sparse]
>
Apologies - This driver shouldn't be selectable for x86_64.
It is an ARM driver for an embedded device. Will fix.
Regards
Tony P
^ permalink raw reply
* [RFC PATCH 0/4] b.L: Memory barriers and miscellaneous tidyups
From: Dave Martin @ 2013-01-15 17:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.LFD.2.02.1301151228070.6300@xanadu.home>
On Tue, Jan 15, 2013 at 12:29:22PM -0500, Nicolas Pitre wrote:
> On Tue, 15 Jan 2013, Dave Martin wrote:
>
> > After much head-scratching and discussion, I have concluded that we
> > need comprehensive memory barriers in order to ensure that the
> > low-level synchronisation code executes robustly on all platforms.
> >
> > DSBs are excessive on most situations though, so many DSBs can be
> > replces with DMBs.
> >
> > As was observed in review, providing a C interface to the vlocks
> > makes little sense, so this series gets rid of it.
>
> Thanks. I have already removed the C stuff in my version but I'll merge
> the rest no problem.
OK, I wasn't sure whether you'd already done that, but figured the patch
would be trivial to throw away (it's not like I invested a lot of time
in that one!)
I've done my best with the barriers, but if you have any concerns about
correctness, let me know.
Cheers
---Dave
^ permalink raw reply
* [RFC PATCH 0/4] b.L: Memory barriers and miscellaneous tidyups
From: Nicolas Pitre @ 2013-01-15 17:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358268498-8086-1-git-send-email-dave.martin@linaro.org>
On Tue, 15 Jan 2013, Dave Martin wrote:
> After much head-scratching and discussion, I have concluded that we
> need comprehensive memory barriers in order to ensure that the
> low-level synchronisation code executes robustly on all platforms.
>
> DSBs are excessive on most situations though, so many DSBs can be
> replces with DMBs.
>
> As was observed in review, providing a C interface to the vlocks
> makes little sense, so this series gets rid of it.
Thanks. I have already removed the C stuff in my version but I'll merge
the rest no problem.
Nicolas
^ permalink raw reply
* [v3 6/9] ARM: dt: tegra114: Add new SoC base, Tegra 114 SoC
From: Peter De Schrijver @ 2013-01-15 17:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <50F58A13.10301@wwwdotorg.org>
On Tue, Jan 15, 2013 at 05:55:47PM +0100, Stephen Warren wrote:
> On 01/15/2013 01:13 AM, Hiroshi Doyu wrote:
> > Initial support for Tegra 114 SoC. This is expected to be included in
> > the board DTS files, Tegra 114 SoC based evaluation board family.
>
> This series looks fine to me. Assuming no other comments, I'll apply
> once CCF is applied and you've done the rebase you mentioned for patch 2.
>
> Note that I'll apply most patches to Tegra's for-3.9/soc branch (the
> code) but the 3 device tree patches to Tegra's for-3.9/dt branch, since
> it's fine for the DT files to appear later than the code supporting the
> SoC, since this is all new features.
>
> One question: The .dts files don't include any clocks properties. I
> assume Peter will add these when he posts the Tegra114 CCF code?
Yes. I will add those as part of the Tegra114 CCF series.
Cheers,
Peter.
^ permalink raw reply
* [PATCH v2] mm: dmapool: use provided gfp flags for all dma_alloc_coherent() calls
From: Jason Cooper @ 2013-01-15 16:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <50F3F289.3090402@web.de>
Greg,
I've added you to the this thread hoping for a little insight into USB
drivers and their use of coherent and GFP_ATOMIC. Am I barking up the
wrong tree by looking a the drivers?
On Mon, Jan 14, 2013 at 12:56:57PM +0100, Soeren Moch wrote:
> On 20.11.2012 15:31, Marek Szyprowski wrote:
> >dmapool always calls dma_alloc_coherent() with GFP_ATOMIC flag,
> >regardless the flags provided by the caller. This causes excessive
> >pruning of emergency memory pools without any good reason. Additionaly,
> >on ARM architecture any driver which is using dmapools will sooner or
> >later trigger the following error:
> >"ERROR: 256 KiB atomic DMA coherent pool is too small!
> >Please increase it with coherent_pool= kernel parameter!".
> >Increasing the coherent pool size usually doesn't help much and only
> >delays such error, because all GFP_ATOMIC DMA allocations are always
> >served from the special, very limited memory pool.
> >
> >This patch changes the dmapool code to correctly use gfp flags provided
> >by the dmapool caller.
> >
> >Reported-by: Soeren Moch <smoch@web.de>
> >Reported-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> >Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> >Tested-by: Andrew Lunn <andrew@lunn.ch>
> >Tested-by: Soeren Moch <smoch@web.de>
>
> Now I tested linux-3.7.1 (this patch is included there) on my Marvell
> Kirkwood system. I still see
>
> ERROR: 1024 KiB atomic DMA coherent pool is too small!
> Please increase it with coherent_pool= kernel parameter!
>
> after several hours of runtime under heavy load with SATA and
> DVB-Sticks (em28xx / drxk and dib0700).
Could you try running the system w/o the em28xx stick and see how it
goes with v3.7.1?
thx,
Jason.
> As already reported earlier this patch improved the behavior
> compared to linux-3.6.x and 3.7.0 (error after several ten minutes
> runtime), but
> I still see a regression compared to linux-3.5.x. With this kernel the
> same system with same workload runs flawlessly.
>
> Regards,
> Soeren
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [v3 6/9] ARM: dt: tegra114: Add new SoC base, Tegra 114 SoC
From: Stephen Warren @ 2013-01-15 16:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358237598-32413-7-git-send-email-hdoyu@nvidia.com>
On 01/15/2013 01:13 AM, Hiroshi Doyu wrote:
> Initial support for Tegra 114 SoC. This is expected to be included in
> the board DTS files, Tegra 114 SoC based evaluation board family.
This series looks fine to me. Assuming no other comments, I'll apply
once CCF is applied and you've done the rebase you mentioned for patch 2.
Note that I'll apply most patches to Tegra's for-3.9/soc branch (the
code) but the 3 device tree patches to Tegra's for-3.9/dt branch, since
it's fine for the DT files to appear later than the code supporting the
SoC, since this is all new features.
One question: The .dts files don't include any clocks properties. I
assume Peter will add these when he posts the Tegra114 CCF code?
^ permalink raw reply
* [RFC PATCH 4/4] ARM: vexpress/dcscb: power_up_setup memory barrier cleanup
From: Dave Martin @ 2013-01-15 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358268498-8086-1-git-send-email-dave.martin@linaro.org>
The bL_head framework has sufficient barriers to ensure correct
globally observed ordering of explicit memory accesses done by the
power_up_setup function.
This patch removes the unnecessary DSB from dcscb_setup.S.
Signed-off-by: Dave Martin <dave.martin@linaro.org>
---
arch/arm/mach-vexpress/dcscb_setup.S | 5 ++---
1 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-vexpress/dcscb_setup.S b/arch/arm/mach-vexpress/dcscb_setup.S
index c75ee8c..e338be7 100644
--- a/arch/arm/mach-vexpress/dcscb_setup.S
+++ b/arch/arm/mach-vexpress/dcscb_setup.S
@@ -64,14 +64,13 @@ ENTRY(dcscb_power_up_setup)
ldr r3, =RTSM_CCI_PHYS_BASE
- b 1f
-0: dsb
1: ldr r0, [r3, #CCI_STATUS_OFFSET]
tst r0, #STATUS_CHANGE_PENDING
- bne 0b
+ bne 1b
2: @ Implementation-specific local CPU setup operations should go here,
@ if any. In this case, there is nothing to do.
bx lr
+
ENDPROC(dcscb_power_up_setup)
--
1.7.4.1
^ permalink raw reply related
* [RFC PATCH 3/4] ARM: bL_entry: Match memory barriers to architectural requirements
From: Dave Martin @ 2013-01-15 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358268498-8086-1-git-send-email-dave.martin@linaro.org>
For architectural correctness even Strongly-Ordered memory accesses
require barriers in order to guarantee that multiple CPUs have a
coherent view of the ordering of memory accesses.
Virtually everything done by this early code is done via explicit
memory access only, so DSBs are seldom required. Existing barriers
are demoted to DMB, except where a DSB is needed to synchronise
non-memory signalling (i.e., before a SEV). If a particular
platform performs cache maintenance in its power_up_setup function,
it should force it to complete explicitly including a DSB, instead
of relying on the bL_head framework code to do it.
Some additional DMBs are added to ensure all the memory ordering
properties required by the race avoidance algorithm. DMBs are also
moved out of loops, and for clarity some are moved so that most
directly follow the memory operation which needs to be
synchronised.
The setting of a CPU's bL_entry_vectors[] entry is also required to
act as a synchronisation point, so a DMB is added after checking
that entry to ensure that other CPUs do not observe gated
operations leaking across the opening of the gate.
Signed-off-by: Dave Martin <dave.martin@linaro.org>
---
arch/arm/common/bL_head.S | 21 +++++++++++----------
1 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/arch/arm/common/bL_head.S b/arch/arm/common/bL_head.S
index fd71ff6..a4a20e5 100644
--- a/arch/arm/common/bL_head.S
+++ b/arch/arm/common/bL_head.S
@@ -87,8 +87,7 @@ ENTRY(bL_entry_point)
mov r5, #BL_SYNC_CPU_SIZE
mla r5, r9, r5, r8 @ r5 = bL_sync cpu address
strb r0, [r5]
-
- dsb
+ dmb
@ At this point, the cluster cannot unexpectedly enter the GOING_DOWN
@ state, because there is at least one active CPU (this CPU).
@@ -97,7 +96,7 @@ ENTRY(bL_entry_point)
mla r11, r0, r10, r11 @ r11 = cluster first man lock
mov r0, r11
mov r1, r9 @ cpu
- bl vlock_trylock
+ bl vlock_trylock @ implies DSB
cmp r0, #0 @ failed to get the lock?
bne cluster_setup_wait @ wait for cluster setup if so
@@ -115,11 +114,12 @@ cluster_setup:
@ Wait for any previously-pending cluster teardown operations to abort
@ or complete:
- dsb
- ldrb r0, [r8, #BL_SYNC_CLUSTER_CLUSTER]
+ dmb
+0: ldrb r0, [r8, #BL_SYNC_CLUSTER_CLUSTER]
cmp r0, #CLUSTER_GOING_DOWN
wfeeq
- beq cluster_setup
+ beq 0b
+ dmb
@ If the outbound gave up before teardown started, skip cluster setup:
@@ -131,8 +131,8 @@ cluster_setup:
cmp r7, #0
mov r0, #1 @ second (cluster) affinity level
blxne r7 @ Call power_up_setup if defined
+ dmb
- dsb
mov r0, #CLUSTER_UP
strb r0, [r8, #BL_SYNC_CLUSTER_CLUSTER]
dsb
@@ -146,11 +146,11 @@ cluster_setup_leave:
@ In the contended case, non-first men wait here for cluster setup
@ to complete:
cluster_setup_wait:
- dsb
ldrb r0, [r8, #BL_SYNC_CLUSTER_CLUSTER]
cmp r0, #CLUSTER_UP
wfene
bne cluster_setup_wait
+ dmb
cluster_setup_complete:
@ If a platform-specific CPU setup hook is needed, it is
@@ -162,13 +162,14 @@ cluster_setup_complete:
@ Mark the CPU as up:
- dsb
+ dmb
mov r0, #CPU_UP
strb r0, [r5]
+ dmb
bL_entry_gated:
- dsb
ldr r5, [r6, r4, lsl #2] @ r5 = CPU entry vector
+ dmb
cmp r5, #0
wfeeq
beq bL_entry_gated
--
1.7.4.1
^ permalink raw reply related
* [RFC PATCH 2/4] ARM: b.L: vlocks: Add architecturally required memory barriers
From: Dave Martin @ 2013-01-15 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358268498-8086-1-git-send-email-dave.martin@linaro.org>
For architectural correctness even Strongly-Ordered memory accesses
require barriers in order to guarantee that multiple CPUs have a
coherent view of the ordering of memory accesses.
Whether or not this matters depends on hardware implementation
details of the memory system.
Since the purpose of this code is to provide a clean, generic
locking mechanism with no platform-specific dependencies the
barriers should be present to avoid unpleasant surprises on future
platforms.
This patch adds the required barriers.
Note:
* When taking the lock, we don't care about implicit background
memory operations and other signalling which may be pending,
because those are not part of the critical section anyway.
A DMB is sufficient to ensure correctly observed ordering if
the explicit memory accesses in vlock_trylock.
* No barrier is required after checking the election result,
because the result is determined by the store st
VLOCK_OWNER_OFFSET and is already globally observed due to the
barriers in voting_end. This means that global agreement on
the winner is guaranteed, even before the winner is known
locally.
* The magic to guarantee correct barrierless access to the vlocks
by aligning them in memory now makes no sense and is removed.
However, we must still ensure that these don't share a
cacheline with anything else.
Signed-off-by: Dave Martin <dave.martin@linaro.org>
---
arch/arm/common/bL_head.S | 19 -------------------
arch/arm/common/vlock.S | 7 +++++--
2 files changed, 5 insertions(+), 21 deletions(-)
diff --git a/arch/arm/common/bL_head.S b/arch/arm/common/bL_head.S
index 314d4ae..fd71ff6 100644
--- a/arch/arm/common/bL_head.S
+++ b/arch/arm/common/bL_head.S
@@ -187,26 +187,7 @@ ENDPROC(bL_entry_point)
.bss
- @ Magic to size and align the first-man vlock structures
- @ so that each does not cross a 1KB boundary.
- @ We also must ensure that none of these shares a cacheline with
- @ any data which might be accessed through the cache.
-
- .equ .Log2, 0
- .rept 11
- .if (1 << .Log2) < VLOCK_SIZE
- .equ .Log2, .Log2 + 1
- .endif
- .endr
- .if .Log2 > 10
- .error "vlock struct is too large for guaranteed barrierless access ordering"
- .endif
- .equ .Lvlock_size, 1 << .Log2
-
- @ The presence of two .align directives here is deliberate: we must
- @ align to whichever of the two boundaries is larger:
.align __CACHE_WRITEBACK_ORDER
- .align .Log2
first_man_locks:
.rept BL_NR_CLUSTERS
.space .Lvlock_size
diff --git a/arch/arm/common/vlock.S b/arch/arm/common/vlock.S
index 0a1ee3a..f55744f 100644
--- a/arch/arm/common/vlock.S
+++ b/arch/arm/common/vlock.S
@@ -39,10 +39,11 @@
.macro voting_begin rbase:req, rcpu:req, rscratch:req
mov \rscratch, #1
strb \rscratch, [\rbase, \rcpu]
- dsb
+ dmb
.endm
.macro voting_end rbase:req, rcpu:req, rscratch:req
+ dmb
mov \rscratch, #0
strb \rscratch, [\rbase, \rcpu]
dsb
@@ -68,6 +69,7 @@ ENTRY(vlock_trylock)
cmp r2, #VLOCK_OWNER_NONE
bne trylock_fail @ fail if so
+ dmb
strb r1, [r0, #VLOCK_OWNER_OFFSET] @ submit my vote
voting_end r0, r1, r2
@@ -87,6 +89,7 @@ ENTRY(vlock_trylock)
@ Check who won:
+ dmb
ldrb r2, [r0, #VLOCK_OWNER_OFFSET]
eor r0, r1, r2 @ zero if I won, else nonzero
bx lr
@@ -99,8 +102,8 @@ ENDPROC(vlock_trylock)
@ r0: lock structure base
ENTRY(vlock_unlock)
+ dmb
mov r1, #VLOCK_OWNER_NONE
- dsb
strb r1, [r0, #VLOCK_OWNER_OFFSET]
dsb
sev
--
1.7.4.1
^ permalink raw reply related
* [RFC PATCH 1/4] ARM: b.L: Remove C declarations for vlocks
From: Dave Martin @ 2013-01-15 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358268498-8086-1-git-send-email-dave.martin@linaro.org>
Vlocks are only useful in very specialised situations, so the
precence of a C header file is more confusing than helpful. All
current use of vlocks, including allocation of space for the lock
structures themselves, is done in assembler.
This patch removes the C interface, so that people are not tempted
to use vlocks when they shouldn't.
Signed-off-by: Dave Martin <dave.martin@linaro.org>
---
arch/arm/common/vlock.h | 43 -------------------------------------------
1 files changed, 0 insertions(+), 43 deletions(-)
delete mode 100644 arch/arm/common/vlock.h
diff --git a/arch/arm/common/vlock.h b/arch/arm/common/vlock.h
deleted file mode 100644
index 94c29a6..0000000
--- a/arch/arm/common/vlock.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * vlock.h - simple voting lock implementation
- *
- * Created by: Dave Martin, 2012-08-16
- * Copyright: (C) 2012 Linaro Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef __VLOCK_H
-#define __VLOCK_H
-
-#include <asm/bL_entry.h>
-
-#define VLOCK_OWNER_OFFSET 0
-#define VLOCK_VOTING_OFFSET 4
-#define VLOCK_VOTING_SIZE ((BL_CPUS_PER_CLUSTER + 3) / 4 * 4)
-#define VLOCK_SIZE (VLOCK_VOTING_OFFSET + VLOCK_VOTING_SIZE)
-#define VLOCK_OWNER_NONE 0
-
-#ifndef __ASSEMBLY__
-
-struct vlock {
- char data[VLOCK_SIZE];
-};
-
-int vlock_trylock(struct vlock *lock, unsigned int owner);
-void vlock_unlock(struct vlock *lock);
-
-#endif /* __ASSEMBLY__ */
-#endif /* ! __VLOCK_H */
--
1.7.4.1
^ permalink raw reply related
* [RFC PATCH 0/4] b.L: Memory barriers and miscellaneous tidyups
From: Dave Martin @ 2013-01-15 16:48 UTC (permalink / raw)
To: linux-arm-kernel
After much head-scratching and discussion, I have concluded that we
need comprehensive memory barriers in order to ensure that the
low-level synchronisation code executes robustly on all platforms.
DSBs are excessive on most situations though, so many DSBs can be
replces with DMBs.
As was observed in review, providing a C interface to the vlocks
makes little sense, so this series gets rid of it.
Dave Martin (4):
ARM: b.L: Remove C declarations for vlocks
ARM: b.L: vlocks: Add architecturally required memory barriers
ARM: bL_entry: Match memory barriers to architectural requirements
ARM: vexpress/dcscb: power_up_setup memory barrier cleanup
arch/arm/common/bL_head.S | 40 ++++++++-----------------------
arch/arm/common/vlock.S | 7 ++++-
arch/arm/common/vlock.h | 43 ----------------------------------
arch/arm/mach-vexpress/dcscb_setup.S | 5 +--
4 files changed, 18 insertions(+), 77 deletions(-)
delete mode 100644 arch/arm/common/vlock.h
--
1.7.4.1
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox