* [PATCH v2 0/5] arm: mvebu: add support for local timer for Armada 370/XP
@ 2013-01-25 17:32 Gregory CLEMENT
2013-01-25 17:32 ` [PATCH v2 1/5] arm: mvebu: Add support for local interrupt Gregory CLEMENT
` (5 more replies)
0 siblings, 6 replies; 14+ messages in thread
From: Gregory CLEMENT @ 2013-01-25 17:32 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
The Armada XP SoCs comes with private timers. This allows us to use
local timers through CONFIG_LOCAL_TIMERS and as stated in the kconfig
help, it prevents a "thundering herd" at every timer tick.
Armada 370 also have these private timers, and even if it comes only
with a single CPU, the feature is also enabled for this SoC to keep
the code generic.
In order to be able to use the local timer, I also had to add the
support for the per-CPU interrupts.
There are not many changes since the first version (see the changelog
below), I hope it means that everybody is happy with this patch
set. If it is, so please could you give your acked-by. I especially
expect the acked-by from John Stultz then I will feel more comfortable
to ask Jason to pull it.
This patch set is based on 3.8-rc4 and is obviously 3.9 material. The
git branch called local_timer is available at:
https://github.com/MISL-EBU-System-SW/mainline-public.git.
Thanks,
Changelog:
V1->V2:
- Fixed unneeded empty line and wrong indentation.
- Made percpu_armada_370_xp_evt a static variable
- Removed the patch "arm: kconfig: don't select TWD with local timer
for Armada 370/XP" from the series. There is still some improvement
possible in this area, but this patch set not depends on it.
Gregory CLEMENT (5):
arm: mvebu: Add support for local interrupt
clocksource: time-armada-370-xp: add local timer support
arm: mvebu: update defconfig with local timer support
arm: mvebu: update DT to support local timers
clocksource: update and move armada-370-xp-timer documentation to
timer directory
.../bindings/arm/armada-370-xp-timer.txt | 12 --
.../bindings/timer/marvell,armada-370-xp-timer.txt | 15 ++
arch/arm/boot/dts/armada-370-xp.dtsi | 5 +-
arch/arm/configs/mvebu_defconfig | 1 -
arch/arm/mach-mvebu/irq-armada-370-xp.c | 15 +-
drivers/clocksource/time-armada-370-xp.c | 150 +++++++++++++++-----
6 files changed, 141 insertions(+), 57 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/arm/armada-370-xp-timer.txt
create mode 100644 Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
--
1.7.9.5
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 1/5] arm: mvebu: Add support for local interrupt
2013-01-25 17:32 [PATCH v2 0/5] arm: mvebu: add support for local timer for Armada 370/XP Gregory CLEMENT
@ 2013-01-25 17:32 ` Gregory CLEMENT
2013-01-25 17:32 ` [PATCH v2 2/5] clocksource: time-armada-370-xp: add local timer support Gregory CLEMENT
` (4 subsequent siblings)
5 siblings, 0 replies; 14+ messages in thread
From: Gregory CLEMENT @ 2013-01-25 17:32 UTC (permalink / raw)
To: linux-arm-kernel
MPIC allows the use of private interrupt for each CPUs. The 28th first
interrupts are per-cpu. This patch adds support to use them.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
arch/arm/mach-mvebu/irq-armada-370-xp.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-mvebu/irq-armada-370-xp.c b/arch/arm/mach-mvebu/irq-armada-370-xp.c
index f99a4a2..274ff58 100644
--- a/arch/arm/mach-mvebu/irq-armada-370-xp.c
+++ b/arch/arm/mach-mvebu/irq-armada-370-xp.c
@@ -145,10 +145,17 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
{
armada_370_xp_irq_mask(irq_get_irq_data(virq));
writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS);
-
- irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
- handle_level_irq);
irq_set_status_flags(virq, IRQ_LEVEL);
+
+ if (hw < ARMADA_370_XP_MAX_PER_CPU_IRQS) {
+ irq_set_percpu_devid(virq);
+ irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
+ handle_percpu_devid_irq);
+
+ } else {
+ irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
+ handle_level_irq);
+ }
set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
return 0;
@@ -245,7 +252,7 @@ asmlinkage void __exception_irq_entry armada_370_xp_handle_irq(struct pt_regs
if (irqnr > 1022)
break;
- if (irqnr >= 8) {
+ if (irqnr > 0) {
irqnr = irq_find_mapping(armada_370_xp_mpic_domain,
irqnr);
handle_IRQ(irqnr, regs);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 2/5] clocksource: time-armada-370-xp: add local timer support
2013-01-25 17:32 [PATCH v2 0/5] arm: mvebu: add support for local timer for Armada 370/XP Gregory CLEMENT
2013-01-25 17:32 ` [PATCH v2 1/5] arm: mvebu: Add support for local interrupt Gregory CLEMENT
@ 2013-01-25 17:32 ` Gregory CLEMENT
2013-02-15 21:21 ` Jason Cooper
2013-01-25 17:32 ` [PATCH v2 3/5] arm: mvebu: update defconfig with " Gregory CLEMENT
` (3 subsequent siblings)
5 siblings, 1 reply; 14+ messages in thread
From: Gregory CLEMENT @ 2013-01-25 17:32 UTC (permalink / raw)
To: linux-arm-kernel
On the SOCs Armada 370 and Armada XP, each CPU comes with two private
timers. This patch use the timer 0 of each CPU as local timer for the
clockevent if CONFIG_LOCAL_TIMER is selected. In the other case, use
only the private Timer 0 of CPU 0.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
drivers/clocksource/time-armada-370-xp.c | 150 ++++++++++++++++++++++--------
1 file changed, 112 insertions(+), 38 deletions(-)
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c
index a4605fd..47a6730 100644
--- a/drivers/clocksource/time-armada-370-xp.c
+++ b/drivers/clocksource/time-armada-370-xp.c
@@ -27,8 +27,10 @@
#include <linux/of_address.h>
#include <linux/irq.h>
#include <linux/module.h>
-#include <asm/sched_clock.h>
+#include <asm/sched_clock.h>
+#include <asm/localtimer.h>
+#include <linux/percpu.h>
/*
* Timer block registers.
*/
@@ -49,6 +51,7 @@
#define TIMER1_RELOAD_OFF 0x0018
#define TIMER1_VAL_OFF 0x001c
+#define LCL_TIMER_EVENTS_STATUS 0x0028
/* Global timers are connected to the coherency fabric clock, and the
below divider reduces their incrementing frequency. */
#define TIMER_DIVIDER_SHIFT 5
@@ -57,14 +60,17 @@
/*
* SoC-specific data.
*/
-static void __iomem *timer_base;
-static int timer_irq;
+static void __iomem *timer_base, *local_base;
+static unsigned int timer_clk;
+static bool timer25Mhz = true;
/*
* Number of timer ticks per jiffy.
*/
static u32 ticks_per_jiffy;
+static struct clock_event_device __percpu **percpu_armada_370_xp_evt;
+
static u32 notrace armada_370_xp_read_sched_clock(void)
{
return ~readl(timer_base + TIMER0_VAL_OFF);
@@ -78,24 +84,23 @@ armada_370_xp_clkevt_next_event(unsigned long delta,
struct clock_event_device *dev)
{
u32 u;
-
/*
* Clear clockevent timer interrupt.
*/
- writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS);
+ writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
/*
* Setup new clockevent timer value.
*/
- writel(delta, timer_base + TIMER1_VAL_OFF);
+ writel(delta, local_base + TIMER0_VAL_OFF);
/*
* Enable the timer.
*/
- u = readl(timer_base + TIMER_CTRL_OFF);
- u = ((u & ~TIMER1_RELOAD_EN) | TIMER1_EN |
- TIMER1_DIV(TIMER_DIVIDER_SHIFT));
- writel(u, timer_base + TIMER_CTRL_OFF);
+ u = readl(local_base + TIMER_CTRL_OFF);
+ u = ((u & ~TIMER0_RELOAD_EN) | TIMER0_EN |
+ TIMER0_DIV(TIMER_DIVIDER_SHIFT));
+ writel(u, local_base + TIMER_CTRL_OFF);
return 0;
}
@@ -107,37 +112,38 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode,
u32 u;
if (mode == CLOCK_EVT_MODE_PERIODIC) {
+
/*
* Setup timer to fire at 1/HZ intervals.
*/
- writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD_OFF);
- writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL_OFF);
+ writel(ticks_per_jiffy - 1, local_base + TIMER0_RELOAD_OFF);
+ writel(ticks_per_jiffy - 1, local_base + TIMER0_VAL_OFF);
/*
* Enable timer.
*/
- u = readl(timer_base + TIMER_CTRL_OFF);
- writel((u | TIMER1_EN | TIMER1_RELOAD_EN |
- TIMER1_DIV(TIMER_DIVIDER_SHIFT)),
- timer_base + TIMER_CTRL_OFF);
+ u = readl(local_base + TIMER_CTRL_OFF);
+
+ writel((u | TIMER0_EN | TIMER0_RELOAD_EN |
+ TIMER0_DIV(TIMER_DIVIDER_SHIFT)),
+ local_base + TIMER_CTRL_OFF);
} else {
/*
* Disable timer.
*/
- u = readl(timer_base + TIMER_CTRL_OFF);
- writel(u & ~TIMER1_EN, timer_base + TIMER_CTRL_OFF);
+ u = readl(local_base + TIMER_CTRL_OFF);
+ writel(u & ~TIMER0_EN, local_base + TIMER_CTRL_OFF);
/*
* ACK pending timer interrupt.
*/
- writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS);
-
+ writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
}
}
static struct clock_event_device armada_370_xp_clkevt = {
- .name = "armada_370_xp_tick",
+ .name = "armada_370_xp_per_cpu_tick",
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
.shift = 32,
.rating = 300,
@@ -150,32 +156,78 @@ static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id)
/*
* ACK timer interrupt and call event handler.
*/
+ struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
- writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS);
- armada_370_xp_clkevt.event_handler(&armada_370_xp_clkevt);
+ writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
-static struct irqaction armada_370_xp_timer_irq = {
- .name = "armada_370_xp_tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
- .handler = armada_370_xp_timer_interrupt
+/*
+ * Setup the local clock events for a CPU.
+ */
+static int __cpuinit armada_370_xp_timer_setup(struct clock_event_device *evt)
+{
+ u32 u;
+ int cpu = smp_processor_id();
+
+ /* Use existing clock_event for cpu 0 */
+ if (!smp_processor_id())
+ return 0;
+
+ u = readl(local_base + TIMER_CTRL_OFF);
+ if (timer25Mhz)
+ writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF);
+ else
+ writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF);
+
+ evt->name = armada_370_xp_clkevt.name;
+ evt->irq = armada_370_xp_clkevt.irq;
+ evt->features = armada_370_xp_clkevt.features;
+ evt->shift = armada_370_xp_clkevt.shift;
+ evt->rating = armada_370_xp_clkevt.rating,
+ evt->set_next_event = armada_370_xp_clkevt_next_event,
+ evt->set_mode = armada_370_xp_clkevt_mode,
+ evt->cpumask = cpumask_of(cpu);
+
+ *__this_cpu_ptr(percpu_armada_370_xp_evt) = evt;
+
+ clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe);
+ enable_percpu_irq(evt->irq, 0);
+
+ return 0;
+}
+
+static void armada_370_xp_timer_stop(struct clock_event_device *evt)
+{
+ evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
+ disable_percpu_irq(evt->irq);
+}
+
+static struct local_timer_ops armada_370_xp_local_timer_ops __cpuinitdata = {
+ .setup = armada_370_xp_timer_setup,
+ .stop = armada_370_xp_timer_stop,
};
void __init armada_370_xp_timer_init(void)
{
u32 u;
struct device_node *np;
- unsigned int timer_clk;
+ int res;
+
np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer");
timer_base = of_iomap(np, 0);
WARN_ON(!timer_base);
+ local_base = of_iomap(np, 1);
if (of_find_property(np, "marvell,timer-25Mhz", NULL)) {
/* The fixed 25MHz timer is available so let's use it */
+ u = readl(local_base + TIMER_CTRL_OFF);
+ writel(u | TIMER0_25MHZ,
+ local_base + TIMER_CTRL_OFF);
u = readl(timer_base + TIMER_CTRL_OFF);
- writel(u | TIMER0_25MHZ | TIMER1_25MHZ,
+ writel(u | TIMER0_25MHZ,
timer_base + TIMER_CTRL_OFF);
timer_clk = 25000000;
} else {
@@ -183,15 +235,23 @@ void __init armada_370_xp_timer_init(void)
struct clk *clk = of_clk_get(np, 0);
WARN_ON(IS_ERR(clk));
rate = clk_get_rate(clk);
+ u = readl(local_base + TIMER_CTRL_OFF);
+ writel(u & ~(TIMER0_25MHZ),
+ local_base + TIMER_CTRL_OFF);
+
u = readl(timer_base + TIMER_CTRL_OFF);
- writel(u & ~(TIMER0_25MHZ | TIMER1_25MHZ),
+ writel(u & ~(TIMER0_25MHZ),
timer_base + TIMER_CTRL_OFF);
+
timer_clk = rate / TIMER_DIVIDER;
+ timer25Mhz = false;
}
- /* We use timer 0 as clocksource, and timer 1 for
- clockevents */
- timer_irq = irq_of_parse_and_map(np, 1);
+ /*
+ * We use timer 0 as clocksource, and private(local) timer 0
+ * for clockevents
+ */
+ armada_370_xp_clkevt.irq = irq_of_parse_and_map(np, 4);
ticks_per_jiffy = (timer_clk + HZ / 2) / HZ;
@@ -216,12 +276,26 @@ void __init armada_370_xp_timer_init(void)
"armada_370_xp_clocksource",
timer_clk, 300, 32, clocksource_mmio_readl_down);
- /*
- * Setup clockevent timer (interrupt-driven).
- */
- setup_irq(timer_irq, &armada_370_xp_timer_irq);
+ /* Register the clockevent on the private timer of CPU 0 */
armada_370_xp_clkevt.cpumask = cpumask_of(0);
clockevents_config_and_register(&armada_370_xp_clkevt,
timer_clk, 1, 0xfffffffe);
-}
+ percpu_armada_370_xp_evt = alloc_percpu(struct clock_event_device *);
+
+
+ /*
+ * Setup clockevent timer (interrupt-driven).
+ */
+ *__this_cpu_ptr(percpu_armada_370_xp_evt) = &armada_370_xp_clkevt;
+ res = request_percpu_irq(armada_370_xp_clkevt.irq,
+ armada_370_xp_timer_interrupt,
+ armada_370_xp_clkevt.name,
+ percpu_armada_370_xp_evt);
+ if (!res) {
+ enable_percpu_irq(armada_370_xp_clkevt.irq, 0);
+#ifdef CONFIG_LOCAL_TIMERS
+ local_timer_register(&armada_370_xp_local_timer_ops);
+#endif
+ }
+}
--
1.7.9.5
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 3/5] arm: mvebu: update defconfig with local timer support
2013-01-25 17:32 [PATCH v2 0/5] arm: mvebu: add support for local timer for Armada 370/XP Gregory CLEMENT
2013-01-25 17:32 ` [PATCH v2 1/5] arm: mvebu: Add support for local interrupt Gregory CLEMENT
2013-01-25 17:32 ` [PATCH v2 2/5] clocksource: time-armada-370-xp: add local timer support Gregory CLEMENT
@ 2013-01-25 17:32 ` Gregory CLEMENT
2013-02-15 21:56 ` Jason Cooper
2013-01-25 17:32 ` [PATCH v2 4/5] arm: mvebu: update DT to support local timers Gregory CLEMENT
` (2 subsequent siblings)
5 siblings, 1 reply; 14+ messages in thread
From: Gregory CLEMENT @ 2013-01-25 17:32 UTC (permalink / raw)
To: linux-arm-kernel
Now that we have support for local timers, enable it by default
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
arch/arm/configs/mvebu_defconfig | 1 -
1 file changed, 1 deletion(-)
diff --git a/arch/arm/configs/mvebu_defconfig b/arch/arm/configs/mvebu_defconfig
index b5bc96c..28c1e38 100644
--- a/arch/arm/configs/mvebu_defconfig
+++ b/arch/arm/configs/mvebu_defconfig
@@ -14,7 +14,6 @@ CONFIG_MACH_ARMADA_XP=y
# CONFIG_CACHE_L2X0 is not set
# CONFIG_SWP_EMULATE is not set
CONFIG_SMP=y
-# CONFIG_LOCAL_TIMERS is not set
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
# CONFIG_COMPACTION is not set
--
1.7.9.5
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 4/5] arm: mvebu: update DT to support local timers
2013-01-25 17:32 [PATCH v2 0/5] arm: mvebu: add support for local timer for Armada 370/XP Gregory CLEMENT
` (2 preceding siblings ...)
2013-01-25 17:32 ` [PATCH v2 3/5] arm: mvebu: update defconfig with " Gregory CLEMENT
@ 2013-01-25 17:32 ` Gregory CLEMENT
2013-02-15 21:59 ` Jason Cooper
2013-01-25 17:32 ` [PATCH v2 5/5] clocksource: update and move armada-370-xp-timer documentation to timer directory Gregory CLEMENT
2013-01-30 19:52 ` [PATCH v2 0/5] arm: mvebu: add support for local timer for Armada 370/XP Jason Cooper
5 siblings, 1 reply; 14+ messages in thread
From: Gregory CLEMENT @ 2013-01-25 17:32 UTC (permalink / raw)
To: linux-arm-kernel
Now that the time-armada-370-xp support local timers, updated the
device tree to take it into account.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
arch/arm/boot/dts/armada-370-xp.dtsi | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi
index 4c0abe8..aa6a187 100644
--- a/arch/arm/boot/dts/armada-370-xp.dtsi
+++ b/arch/arm/boot/dts/armada-370-xp.dtsi
@@ -68,8 +68,9 @@
timer at d0020300 {
compatible = "marvell,armada-370-xp-timer";
- reg = <0xd0020300 0x30>;
- interrupts = <37>, <38>, <39>, <40>;
+ reg = <0xd0020300 0x30>,
+ <0xd0021040 0x30>;
+ interrupts = <37>, <38>, <39>, <40>, <5>, <6>;
clocks = <&coreclk 2>;
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 5/5] clocksource: update and move armada-370-xp-timer documentation to timer directory
2013-01-25 17:32 [PATCH v2 0/5] arm: mvebu: add support for local timer for Armada 370/XP Gregory CLEMENT
` (3 preceding siblings ...)
2013-01-25 17:32 ` [PATCH v2 4/5] arm: mvebu: update DT to support local timers Gregory CLEMENT
@ 2013-01-25 17:32 ` Gregory CLEMENT
2013-01-30 19:52 ` [PATCH v2 0/5] arm: mvebu: add support for local timer for Armada 370/XP Jason Cooper
5 siblings, 0 replies; 14+ messages in thread
From: Gregory CLEMENT @ 2013-01-25 17:32 UTC (permalink / raw)
To: linux-arm-kernel
Timer driver for Armada 370 and Armada XP have gained local timers
support. So it needs new resources information regarding the IRQs
and the registers.
Also move the documentation in the new and more accurate directory
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
.../bindings/arm/armada-370-xp-timer.txt | 12 ------------
.../bindings/timer/marvell,armada-370-xp-timer.txt | 15 +++++++++++++++
2 files changed, 15 insertions(+), 12 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/arm/armada-370-xp-timer.txt
create mode 100644 Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
diff --git a/Documentation/devicetree/bindings/arm/armada-370-xp-timer.txt b/Documentation/devicetree/bindings/arm/armada-370-xp-timer.txt
deleted file mode 100644
index 6483011..0000000
--- a/Documentation/devicetree/bindings/arm/armada-370-xp-timer.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-Marvell Armada 370 and Armada XP Global Timers
-----------------------------------------------
-
-Required properties:
-- compatible: Should be "marvell,armada-370-xp-timer"
-- interrupts: Should contain the list of Global Timer interrupts
-- reg: Should contain the base address of the Global Timer registers
-- clocks: clock driving the timer hardware
-
-Optional properties:
-- marvell,timer-25Mhz: Tells whether the Global timer supports the 25
- Mhz fixed mode (available on Armada XP and not on Armada 370)
diff --git a/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt b/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
new file mode 100644
index 0000000..3638112
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
@@ -0,0 +1,15 @@
+Marvell Armada 370 and Armada XP Timers
+---------------------------------------
+
+Required properties:
+- compatible: Should be "marvell,armada-370-xp-timer"
+- interrupts: Should contain the list of Global Timer interrupts and
+ then local timer interrupts
+- reg: Should contain location and length for timers register. First
+ pair for the Global Timer registers, second pair for the
+ local/private timers.
+- clocks: clock driving the timer hardware
+
+Optional properties:
+- marvell,timer-25Mhz: Tells whether the Global timer supports the 25
+ Mhz fixed mode (available on Armada XP and not on Armada 370)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 0/5] arm: mvebu: add support for local timer for Armada 370/XP
2013-01-25 17:32 [PATCH v2 0/5] arm: mvebu: add support for local timer for Armada 370/XP Gregory CLEMENT
` (4 preceding siblings ...)
2013-01-25 17:32 ` [PATCH v2 5/5] clocksource: update and move armada-370-xp-timer documentation to timer directory Gregory CLEMENT
@ 2013-01-30 19:52 ` Jason Cooper
5 siblings, 0 replies; 14+ messages in thread
From: Jason Cooper @ 2013-01-30 19:52 UTC (permalink / raw)
To: linux-arm-kernel
Thomas Gleixner, John Stultz,
I'm getting close to pulling this series in through arm-soc. Would you
prefer to take the clocksource patches through your tree, or provide an
Acked-by and I can take them through mvebu/arm-soc?
I'm comfortable with either, if you decide to take them, please let me
know which tree and branch you put them in so I can properly depend on
them.
thx,
Jason.
On Fri, Jan 25, 2013 at 06:32:40PM +0100, Gregory CLEMENT wrote:
> Hello,
>
> The Armada XP SoCs comes with private timers. This allows us to use
> local timers through CONFIG_LOCAL_TIMERS and as stated in the kconfig
> help, it prevents a "thundering herd" at every timer tick.
>
> Armada 370 also have these private timers, and even if it comes only
> with a single CPU, the feature is also enabled for this SoC to keep
> the code generic.
>
> In order to be able to use the local timer, I also had to add the
> support for the per-CPU interrupts.
>
> There are not many changes since the first version (see the changelog
> below), I hope it means that everybody is happy with this patch
> set. If it is, so please could you give your acked-by. I especially
> expect the acked-by from John Stultz then I will feel more comfortable
> to ask Jason to pull it.
>
> This patch set is based on 3.8-rc4 and is obviously 3.9 material. The
> git branch called local_timer is available at:
> https://github.com/MISL-EBU-System-SW/mainline-public.git.
>
> Thanks,
>
> Changelog:
> V1->V2:
> - Fixed unneeded empty line and wrong indentation.
> - Made percpu_armada_370_xp_evt a static variable
> - Removed the patch "arm: kconfig: don't select TWD with local timer
> for Armada 370/XP" from the series. There is still some improvement
> possible in this area, but this patch set not depends on it.
>
> Gregory CLEMENT (5):
> arm: mvebu: Add support for local interrupt
> clocksource: time-armada-370-xp: add local timer support
> arm: mvebu: update defconfig with local timer support
> arm: mvebu: update DT to support local timers
> clocksource: update and move armada-370-xp-timer documentation to
> timer directory
>
> .../bindings/arm/armada-370-xp-timer.txt | 12 --
> .../bindings/timer/marvell,armada-370-xp-timer.txt | 15 ++
> arch/arm/boot/dts/armada-370-xp.dtsi | 5 +-
> arch/arm/configs/mvebu_defconfig | 1 -
> arch/arm/mach-mvebu/irq-armada-370-xp.c | 15 +-
> drivers/clocksource/time-armada-370-xp.c | 150 +++++++++++++++-----
> 6 files changed, 141 insertions(+), 57 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/arm/armada-370-xp-timer.txt
> create mode 100644 Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
>
> --
> 1.7.9.5
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 2/5] clocksource: time-armada-370-xp: add local timer support
2013-01-25 17:32 ` [PATCH v2 2/5] clocksource: time-armada-370-xp: add local timer support Gregory CLEMENT
@ 2013-02-15 21:21 ` Jason Cooper
2013-02-15 21:41 ` Gregory CLEMENT
0 siblings, 1 reply; 14+ messages in thread
From: Jason Cooper @ 2013-02-15 21:21 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, Jan 25, 2013 at 06:32:42PM +0100, Gregory CLEMENT wrote:
> On the SOCs Armada 370 and Armada XP, each CPU comes with two private
> timers. This patch use the timer 0 of each CPU as local timer for the
> clockevent if CONFIG_LOCAL_TIMER is selected. In the other case, use
> only the private Timer 0 of CPU 0.
>
> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> ---
> drivers/clocksource/time-armada-370-xp.c | 150 ++++++++++++++++++++++--------
> 1 file changed, 112 insertions(+), 38 deletions(-)
After applying the first two patches in this series to mvebu/drivers I get:
CC arch/arm/mach-mvebu/irq-armada-370-xp.o
arch/arm/mach-mvebu/irq-armada-370-xp.c: In function 'armada_370_xp_mpic_irq_map':
arch/arm/mach-mvebu/irq-armada-370-xp.c:87:11: error: 'ARMADA_370_XP_MAX_PER_CPU_IRQS' undeclared (first use in this function)
arch/arm/mach-mvebu/irq-armada-370-xp.c:87:11: note: each undeclared identifier is reported only once for each function it appears in
make[1]: *** [arch/arm/mach-mvebu/irq-armada-370-xp.o] Error 1
make: *** [arch/arm/mach-mvebu] Error 2
with mvebu_defconfig.
Is there a dependency I missed? I'm not finding anything obvious. The
same occurs if I enable LOCAL_TIMER.
thx,
Jason.
>
> diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c
> index a4605fd..47a6730 100644
> --- a/drivers/clocksource/time-armada-370-xp.c
> +++ b/drivers/clocksource/time-armada-370-xp.c
> @@ -27,8 +27,10 @@
> #include <linux/of_address.h>
> #include <linux/irq.h>
> #include <linux/module.h>
> -#include <asm/sched_clock.h>
>
> +#include <asm/sched_clock.h>
> +#include <asm/localtimer.h>
> +#include <linux/percpu.h>
> /*
> * Timer block registers.
> */
> @@ -49,6 +51,7 @@
> #define TIMER1_RELOAD_OFF 0x0018
> #define TIMER1_VAL_OFF 0x001c
>
> +#define LCL_TIMER_EVENTS_STATUS 0x0028
> /* Global timers are connected to the coherency fabric clock, and the
> below divider reduces their incrementing frequency. */
> #define TIMER_DIVIDER_SHIFT 5
> @@ -57,14 +60,17 @@
> /*
> * SoC-specific data.
> */
> -static void __iomem *timer_base;
> -static int timer_irq;
> +static void __iomem *timer_base, *local_base;
> +static unsigned int timer_clk;
> +static bool timer25Mhz = true;
>
> /*
> * Number of timer ticks per jiffy.
> */
> static u32 ticks_per_jiffy;
>
> +static struct clock_event_device __percpu **percpu_armada_370_xp_evt;
> +
> static u32 notrace armada_370_xp_read_sched_clock(void)
> {
> return ~readl(timer_base + TIMER0_VAL_OFF);
> @@ -78,24 +84,23 @@ armada_370_xp_clkevt_next_event(unsigned long delta,
> struct clock_event_device *dev)
> {
> u32 u;
> -
> /*
> * Clear clockevent timer interrupt.
> */
> - writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS);
> + writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
>
> /*
> * Setup new clockevent timer value.
> */
> - writel(delta, timer_base + TIMER1_VAL_OFF);
> + writel(delta, local_base + TIMER0_VAL_OFF);
>
> /*
> * Enable the timer.
> */
> - u = readl(timer_base + TIMER_CTRL_OFF);
> - u = ((u & ~TIMER1_RELOAD_EN) | TIMER1_EN |
> - TIMER1_DIV(TIMER_DIVIDER_SHIFT));
> - writel(u, timer_base + TIMER_CTRL_OFF);
> + u = readl(local_base + TIMER_CTRL_OFF);
> + u = ((u & ~TIMER0_RELOAD_EN) | TIMER0_EN |
> + TIMER0_DIV(TIMER_DIVIDER_SHIFT));
> + writel(u, local_base + TIMER_CTRL_OFF);
>
> return 0;
> }
> @@ -107,37 +112,38 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode,
> u32 u;
>
> if (mode == CLOCK_EVT_MODE_PERIODIC) {
> +
> /*
> * Setup timer to fire at 1/HZ intervals.
> */
> - writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD_OFF);
> - writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL_OFF);
> + writel(ticks_per_jiffy - 1, local_base + TIMER0_RELOAD_OFF);
> + writel(ticks_per_jiffy - 1, local_base + TIMER0_VAL_OFF);
>
> /*
> * Enable timer.
> */
> - u = readl(timer_base + TIMER_CTRL_OFF);
>
> - writel((u | TIMER1_EN | TIMER1_RELOAD_EN |
> - TIMER1_DIV(TIMER_DIVIDER_SHIFT)),
> - timer_base + TIMER_CTRL_OFF);
> + u = readl(local_base + TIMER_CTRL_OFF);
> +
> + writel((u | TIMER0_EN | TIMER0_RELOAD_EN |
> + TIMER0_DIV(TIMER_DIVIDER_SHIFT)),
> + local_base + TIMER_CTRL_OFF);
> } else {
> /*
> * Disable timer.
> */
> - u = readl(timer_base + TIMER_CTRL_OFF);
> - writel(u & ~TIMER1_EN, timer_base + TIMER_CTRL_OFF);
> + u = readl(local_base + TIMER_CTRL_OFF);
> + writel(u & ~TIMER0_EN, local_base + TIMER_CTRL_OFF);
>
> /*
> * ACK pending timer interrupt.
> */
> - writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS);
> -
> + writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
> }
> }
>
> static struct clock_event_device armada_370_xp_clkevt = {
> - .name = "armada_370_xp_tick",
> + .name = "armada_370_xp_per_cpu_tick",
> .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
> .shift = 32,
> .rating = 300,
> @@ -150,32 +156,78 @@ static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id)
> /*
> * ACK timer interrupt and call event handler.
> */
> + struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
>
> - writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS);
> - armada_370_xp_clkevt.event_handler(&armada_370_xp_clkevt);
> + writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
> + evt->event_handler(evt);
>
> return IRQ_HANDLED;
> }
>
> -static struct irqaction armada_370_xp_timer_irq = {
> - .name = "armada_370_xp_tick",
> - .flags = IRQF_DISABLED | IRQF_TIMER,
> - .handler = armada_370_xp_timer_interrupt
> +/*
> + * Setup the local clock events for a CPU.
> + */
> +static int __cpuinit armada_370_xp_timer_setup(struct clock_event_device *evt)
> +{
> + u32 u;
> + int cpu = smp_processor_id();
> +
> + /* Use existing clock_event for cpu 0 */
> + if (!smp_processor_id())
> + return 0;
> +
> + u = readl(local_base + TIMER_CTRL_OFF);
> + if (timer25Mhz)
> + writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF);
> + else
> + writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF);
> +
> + evt->name = armada_370_xp_clkevt.name;
> + evt->irq = armada_370_xp_clkevt.irq;
> + evt->features = armada_370_xp_clkevt.features;
> + evt->shift = armada_370_xp_clkevt.shift;
> + evt->rating = armada_370_xp_clkevt.rating,
> + evt->set_next_event = armada_370_xp_clkevt_next_event,
> + evt->set_mode = armada_370_xp_clkevt_mode,
> + evt->cpumask = cpumask_of(cpu);
> +
> + *__this_cpu_ptr(percpu_armada_370_xp_evt) = evt;
> +
> + clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe);
> + enable_percpu_irq(evt->irq, 0);
> +
> + return 0;
> +}
> +
> +static void armada_370_xp_timer_stop(struct clock_event_device *evt)
> +{
> + evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
> + disable_percpu_irq(evt->irq);
> +}
> +
> +static struct local_timer_ops armada_370_xp_local_timer_ops __cpuinitdata = {
> + .setup = armada_370_xp_timer_setup,
> + .stop = armada_370_xp_timer_stop,
> };
>
> void __init armada_370_xp_timer_init(void)
> {
> u32 u;
> struct device_node *np;
> - unsigned int timer_clk;
> + int res;
> +
> np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer");
> timer_base = of_iomap(np, 0);
> WARN_ON(!timer_base);
> + local_base = of_iomap(np, 1);
>
> if (of_find_property(np, "marvell,timer-25Mhz", NULL)) {
> /* The fixed 25MHz timer is available so let's use it */
> + u = readl(local_base + TIMER_CTRL_OFF);
> + writel(u | TIMER0_25MHZ,
> + local_base + TIMER_CTRL_OFF);
> u = readl(timer_base + TIMER_CTRL_OFF);
> - writel(u | TIMER0_25MHZ | TIMER1_25MHZ,
> + writel(u | TIMER0_25MHZ,
> timer_base + TIMER_CTRL_OFF);
> timer_clk = 25000000;
> } else {
> @@ -183,15 +235,23 @@ void __init armada_370_xp_timer_init(void)
> struct clk *clk = of_clk_get(np, 0);
> WARN_ON(IS_ERR(clk));
> rate = clk_get_rate(clk);
> + u = readl(local_base + TIMER_CTRL_OFF);
> + writel(u & ~(TIMER0_25MHZ),
> + local_base + TIMER_CTRL_OFF);
> +
> u = readl(timer_base + TIMER_CTRL_OFF);
> - writel(u & ~(TIMER0_25MHZ | TIMER1_25MHZ),
> + writel(u & ~(TIMER0_25MHZ),
> timer_base + TIMER_CTRL_OFF);
> +
> timer_clk = rate / TIMER_DIVIDER;
> + timer25Mhz = false;
> }
>
> - /* We use timer 0 as clocksource, and timer 1 for
> - clockevents */
> - timer_irq = irq_of_parse_and_map(np, 1);
> + /*
> + * We use timer 0 as clocksource, and private(local) timer 0
> + * for clockevents
> + */
> + armada_370_xp_clkevt.irq = irq_of_parse_and_map(np, 4);
>
> ticks_per_jiffy = (timer_clk + HZ / 2) / HZ;
>
> @@ -216,12 +276,26 @@ void __init armada_370_xp_timer_init(void)
> "armada_370_xp_clocksource",
> timer_clk, 300, 32, clocksource_mmio_readl_down);
>
> - /*
> - * Setup clockevent timer (interrupt-driven).
> - */
> - setup_irq(timer_irq, &armada_370_xp_timer_irq);
> + /* Register the clockevent on the private timer of CPU 0 */
> armada_370_xp_clkevt.cpumask = cpumask_of(0);
> clockevents_config_and_register(&armada_370_xp_clkevt,
> timer_clk, 1, 0xfffffffe);
> -}
>
> + percpu_armada_370_xp_evt = alloc_percpu(struct clock_event_device *);
> +
> +
> + /*
> + * Setup clockevent timer (interrupt-driven).
> + */
> + *__this_cpu_ptr(percpu_armada_370_xp_evt) = &armada_370_xp_clkevt;
> + res = request_percpu_irq(armada_370_xp_clkevt.irq,
> + armada_370_xp_timer_interrupt,
> + armada_370_xp_clkevt.name,
> + percpu_armada_370_xp_evt);
> + if (!res) {
> + enable_percpu_irq(armada_370_xp_clkevt.irq, 0);
> +#ifdef CONFIG_LOCAL_TIMERS
> + local_timer_register(&armada_370_xp_local_timer_ops);
> +#endif
> + }
> +}
> --
> 1.7.9.5
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 2/5] clocksource: time-armada-370-xp: add local timer support
2013-02-15 21:21 ` Jason Cooper
@ 2013-02-15 21:41 ` Gregory CLEMENT
2013-02-15 21:48 ` Jason Cooper
0 siblings, 1 reply; 14+ messages in thread
From: Gregory CLEMENT @ 2013-02-15 21:41 UTC (permalink / raw)
To: linux-arm-kernel
On 02/15/2013 10:21 PM, Jason Cooper wrote:
> On Fri, Jan 25, 2013 at 06:32:42PM +0100, Gregory CLEMENT wrote:
>> On the SOCs Armada 370 and Armada XP, each CPU comes with two private
>> timers. This patch use the timer 0 of each CPU as local timer for the
>> clockevent if CONFIG_LOCAL_TIMER is selected. In the other case, use
>> only the private Timer 0 of CPU 0.
>>
>> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
>> ---
>> drivers/clocksource/time-armada-370-xp.c | 150 ++++++++++++++++++++++--------
>> 1 file changed, 112 insertions(+), 38 deletions(-)
>
> After applying the first two patches in this series to mvebu/drivers I get:
>
> CC arch/arm/mach-mvebu/irq-armada-370-xp.o
> arch/arm/mach-mvebu/irq-armada-370-xp.c: In function 'armada_370_xp_mpic_irq_map':
> arch/arm/mach-mvebu/irq-armada-370-xp.c:87:11: error: 'ARMADA_370_XP_MAX_PER_CPU_IRQS' undeclared (first use in this function)
> arch/arm/mach-mvebu/irq-armada-370-xp.c:87:11: note: each undeclared identifier is reported only once for each function it appears in
> make[1]: *** [arch/arm/mach-mvebu/irq-armada-370-xp.o] Error 1
> make: *** [arch/arm/mach-mvebu] Error 2
>
> with mvebu_defconfig.
>
> Is there a dependency I missed? I'm not finding anything obvious. The
> same occurs if I enable LOCAL_TIMER.
It depends on "arm: mvebu: Improve the SMP support of the interrupt controller"
As you have pulled this patch few weeks ago I forgot to this dependency, sorry.
Thanks,
Gregory
>
> thx,
>
> Jason.
>>
>> diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c
>> index a4605fd..47a6730 100644
>> --- a/drivers/clocksource/time-armada-370-xp.c
>> +++ b/drivers/clocksource/time-armada-370-xp.c
>> @@ -27,8 +27,10 @@
>> #include <linux/of_address.h>
>> #include <linux/irq.h>
>> #include <linux/module.h>
>> -#include <asm/sched_clock.h>
>>
>> +#include <asm/sched_clock.h>
>> +#include <asm/localtimer.h>
>> +#include <linux/percpu.h>
>> /*
>> * Timer block registers.
>> */
>> @@ -49,6 +51,7 @@
>> #define TIMER1_RELOAD_OFF 0x0018
>> #define TIMER1_VAL_OFF 0x001c
>>
>> +#define LCL_TIMER_EVENTS_STATUS 0x0028
>> /* Global timers are connected to the coherency fabric clock, and the
>> below divider reduces their incrementing frequency. */
>> #define TIMER_DIVIDER_SHIFT 5
>> @@ -57,14 +60,17 @@
>> /*
>> * SoC-specific data.
>> */
>> -static void __iomem *timer_base;
>> -static int timer_irq;
>> +static void __iomem *timer_base, *local_base;
>> +static unsigned int timer_clk;
>> +static bool timer25Mhz = true;
>>
>> /*
>> * Number of timer ticks per jiffy.
>> */
>> static u32 ticks_per_jiffy;
>>
>> +static struct clock_event_device __percpu **percpu_armada_370_xp_evt;
>> +
>> static u32 notrace armada_370_xp_read_sched_clock(void)
>> {
>> return ~readl(timer_base + TIMER0_VAL_OFF);
>> @@ -78,24 +84,23 @@ armada_370_xp_clkevt_next_event(unsigned long delta,
>> struct clock_event_device *dev)
>> {
>> u32 u;
>> -
>> /*
>> * Clear clockevent timer interrupt.
>> */
>> - writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS);
>> + writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
>>
>> /*
>> * Setup new clockevent timer value.
>> */
>> - writel(delta, timer_base + TIMER1_VAL_OFF);
>> + writel(delta, local_base + TIMER0_VAL_OFF);
>>
>> /*
>> * Enable the timer.
>> */
>> - u = readl(timer_base + TIMER_CTRL_OFF);
>> - u = ((u & ~TIMER1_RELOAD_EN) | TIMER1_EN |
>> - TIMER1_DIV(TIMER_DIVIDER_SHIFT));
>> - writel(u, timer_base + TIMER_CTRL_OFF);
>> + u = readl(local_base + TIMER_CTRL_OFF);
>> + u = ((u & ~TIMER0_RELOAD_EN) | TIMER0_EN |
>> + TIMER0_DIV(TIMER_DIVIDER_SHIFT));
>> + writel(u, local_base + TIMER_CTRL_OFF);
>>
>> return 0;
>> }
>> @@ -107,37 +112,38 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode,
>> u32 u;
>>
>> if (mode == CLOCK_EVT_MODE_PERIODIC) {
>> +
>> /*
>> * Setup timer to fire at 1/HZ intervals.
>> */
>> - writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD_OFF);
>> - writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL_OFF);
>> + writel(ticks_per_jiffy - 1, local_base + TIMER0_RELOAD_OFF);
>> + writel(ticks_per_jiffy - 1, local_base + TIMER0_VAL_OFF);
>>
>> /*
>> * Enable timer.
>> */
>> - u = readl(timer_base + TIMER_CTRL_OFF);
>>
>> - writel((u | TIMER1_EN | TIMER1_RELOAD_EN |
>> - TIMER1_DIV(TIMER_DIVIDER_SHIFT)),
>> - timer_base + TIMER_CTRL_OFF);
>> + u = readl(local_base + TIMER_CTRL_OFF);
>> +
>> + writel((u | TIMER0_EN | TIMER0_RELOAD_EN |
>> + TIMER0_DIV(TIMER_DIVIDER_SHIFT)),
>> + local_base + TIMER_CTRL_OFF);
>> } else {
>> /*
>> * Disable timer.
>> */
>> - u = readl(timer_base + TIMER_CTRL_OFF);
>> - writel(u & ~TIMER1_EN, timer_base + TIMER_CTRL_OFF);
>> + u = readl(local_base + TIMER_CTRL_OFF);
>> + writel(u & ~TIMER0_EN, local_base + TIMER_CTRL_OFF);
>>
>> /*
>> * ACK pending timer interrupt.
>> */
>> - writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS);
>> -
>> + writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
>> }
>> }
>>
>> static struct clock_event_device armada_370_xp_clkevt = {
>> - .name = "armada_370_xp_tick",
>> + .name = "armada_370_xp_per_cpu_tick",
>> .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
>> .shift = 32,
>> .rating = 300,
>> @@ -150,32 +156,78 @@ static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id)
>> /*
>> * ACK timer interrupt and call event handler.
>> */
>> + struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
>>
>> - writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS);
>> - armada_370_xp_clkevt.event_handler(&armada_370_xp_clkevt);
>> + writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
>> + evt->event_handler(evt);
>>
>> return IRQ_HANDLED;
>> }
>>
>> -static struct irqaction armada_370_xp_timer_irq = {
>> - .name = "armada_370_xp_tick",
>> - .flags = IRQF_DISABLED | IRQF_TIMER,
>> - .handler = armada_370_xp_timer_interrupt
>> +/*
>> + * Setup the local clock events for a CPU.
>> + */
>> +static int __cpuinit armada_370_xp_timer_setup(struct clock_event_device *evt)
>> +{
>> + u32 u;
>> + int cpu = smp_processor_id();
>> +
>> + /* Use existing clock_event for cpu 0 */
>> + if (!smp_processor_id())
>> + return 0;
>> +
>> + u = readl(local_base + TIMER_CTRL_OFF);
>> + if (timer25Mhz)
>> + writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF);
>> + else
>> + writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF);
>> +
>> + evt->name = armada_370_xp_clkevt.name;
>> + evt->irq = armada_370_xp_clkevt.irq;
>> + evt->features = armada_370_xp_clkevt.features;
>> + evt->shift = armada_370_xp_clkevt.shift;
>> + evt->rating = armada_370_xp_clkevt.rating,
>> + evt->set_next_event = armada_370_xp_clkevt_next_event,
>> + evt->set_mode = armada_370_xp_clkevt_mode,
>> + evt->cpumask = cpumask_of(cpu);
>> +
>> + *__this_cpu_ptr(percpu_armada_370_xp_evt) = evt;
>> +
>> + clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe);
>> + enable_percpu_irq(evt->irq, 0);
>> +
>> + return 0;
>> +}
>> +
>> +static void armada_370_xp_timer_stop(struct clock_event_device *evt)
>> +{
>> + evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
>> + disable_percpu_irq(evt->irq);
>> +}
>> +
>> +static struct local_timer_ops armada_370_xp_local_timer_ops __cpuinitdata = {
>> + .setup = armada_370_xp_timer_setup,
>> + .stop = armada_370_xp_timer_stop,
>> };
>>
>> void __init armada_370_xp_timer_init(void)
>> {
>> u32 u;
>> struct device_node *np;
>> - unsigned int timer_clk;
>> + int res;
>> +
>> np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer");
>> timer_base = of_iomap(np, 0);
>> WARN_ON(!timer_base);
>> + local_base = of_iomap(np, 1);
>>
>> if (of_find_property(np, "marvell,timer-25Mhz", NULL)) {
>> /* The fixed 25MHz timer is available so let's use it */
>> + u = readl(local_base + TIMER_CTRL_OFF);
>> + writel(u | TIMER0_25MHZ,
>> + local_base + TIMER_CTRL_OFF);
>> u = readl(timer_base + TIMER_CTRL_OFF);
>> - writel(u | TIMER0_25MHZ | TIMER1_25MHZ,
>> + writel(u | TIMER0_25MHZ,
>> timer_base + TIMER_CTRL_OFF);
>> timer_clk = 25000000;
>> } else {
>> @@ -183,15 +235,23 @@ void __init armada_370_xp_timer_init(void)
>> struct clk *clk = of_clk_get(np, 0);
>> WARN_ON(IS_ERR(clk));
>> rate = clk_get_rate(clk);
>> + u = readl(local_base + TIMER_CTRL_OFF);
>> + writel(u & ~(TIMER0_25MHZ),
>> + local_base + TIMER_CTRL_OFF);
>> +
>> u = readl(timer_base + TIMER_CTRL_OFF);
>> - writel(u & ~(TIMER0_25MHZ | TIMER1_25MHZ),
>> + writel(u & ~(TIMER0_25MHZ),
>> timer_base + TIMER_CTRL_OFF);
>> +
>> timer_clk = rate / TIMER_DIVIDER;
>> + timer25Mhz = false;
>> }
>>
>> - /* We use timer 0 as clocksource, and timer 1 for
>> - clockevents */
>> - timer_irq = irq_of_parse_and_map(np, 1);
>> + /*
>> + * We use timer 0 as clocksource, and private(local) timer 0
>> + * for clockevents
>> + */
>> + armada_370_xp_clkevt.irq = irq_of_parse_and_map(np, 4);
>>
>> ticks_per_jiffy = (timer_clk + HZ / 2) / HZ;
>>
>> @@ -216,12 +276,26 @@ void __init armada_370_xp_timer_init(void)
>> "armada_370_xp_clocksource",
>> timer_clk, 300, 32, clocksource_mmio_readl_down);
>>
>> - /*
>> - * Setup clockevent timer (interrupt-driven).
>> - */
>> - setup_irq(timer_irq, &armada_370_xp_timer_irq);
>> + /* Register the clockevent on the private timer of CPU 0 */
>> armada_370_xp_clkevt.cpumask = cpumask_of(0);
>> clockevents_config_and_register(&armada_370_xp_clkevt,
>> timer_clk, 1, 0xfffffffe);
>> -}
>>
>> + percpu_armada_370_xp_evt = alloc_percpu(struct clock_event_device *);
>> +
>> +
>> + /*
>> + * Setup clockevent timer (interrupt-driven).
>> + */
>> + *__this_cpu_ptr(percpu_armada_370_xp_evt) = &armada_370_xp_clkevt;
>> + res = request_percpu_irq(armada_370_xp_clkevt.irq,
>> + armada_370_xp_timer_interrupt,
>> + armada_370_xp_clkevt.name,
>> + percpu_armada_370_xp_evt);
>> + if (!res) {
>> + enable_percpu_irq(armada_370_xp_clkevt.irq, 0);
>> +#ifdef CONFIG_LOCAL_TIMERS
>> + local_timer_register(&armada_370_xp_local_timer_ops);
>> +#endif
>> + }
>> +}
>> --
>> 1.7.9.5
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 2/5] clocksource: time-armada-370-xp: add local timer support
2013-02-15 21:41 ` Gregory CLEMENT
@ 2013-02-15 21:48 ` Jason Cooper
0 siblings, 0 replies; 14+ messages in thread
From: Jason Cooper @ 2013-02-15 21:48 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, Feb 15, 2013 at 10:41:51PM +0100, Gregory CLEMENT wrote:
> On 02/15/2013 10:21 PM, Jason Cooper wrote:
> > On Fri, Jan 25, 2013 at 06:32:42PM +0100, Gregory CLEMENT wrote:
> >> On the SOCs Armada 370 and Armada XP, each CPU comes with two private
> >> timers. This patch use the timer 0 of each CPU as local timer for the
> >> clockevent if CONFIG_LOCAL_TIMER is selected. In the other case, use
> >> only the private Timer 0 of CPU 0.
> >>
> >> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> >> ---
> >> drivers/clocksource/time-armada-370-xp.c | 150 ++++++++++++++++++++++--------
> >> 1 file changed, 112 insertions(+), 38 deletions(-)
> >
> > After applying the first two patches in this series to mvebu/drivers I get:
> >
> > CC arch/arm/mach-mvebu/irq-armada-370-xp.o
> > arch/arm/mach-mvebu/irq-armada-370-xp.c: In function 'armada_370_xp_mpic_irq_map':
> > arch/arm/mach-mvebu/irq-armada-370-xp.c:87:11: error: 'ARMADA_370_XP_MAX_PER_CPU_IRQS' undeclared (first use in this function)
> > arch/arm/mach-mvebu/irq-armada-370-xp.c:87:11: note: each undeclared identifier is reported only once for each function it appears in
> > make[1]: *** [arch/arm/mach-mvebu/irq-armada-370-xp.o] Error 1
> > make: *** [arch/arm/mach-mvebu] Error 2
> >
> > with mvebu_defconfig.
> >
> > Is there a dependency I missed? I'm not finding anything obvious. The
> > same occurs if I enable LOCAL_TIMER.
>
> It depends on "arm: mvebu: Improve the SMP support of the interrupt controller"
>
> As you have pulled this patch few weeks ago I forgot to this dependency, sorry.
Cool, thanks!
Jason.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 3/5] arm: mvebu: update defconfig with local timer support
2013-01-25 17:32 ` [PATCH v2 3/5] arm: mvebu: update defconfig with " Gregory CLEMENT
@ 2013-02-15 21:56 ` Jason Cooper
2013-02-15 22:04 ` Gregory CLEMENT
0 siblings, 1 reply; 14+ messages in thread
From: Jason Cooper @ 2013-02-15 21:56 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, Jan 25, 2013 at 06:32:43PM +0100, Gregory CLEMENT wrote:
> Now that we have support for local timers, enable it by default
>
> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> ---
> arch/arm/configs/mvebu_defconfig | 1 -
> 1 file changed, 1 deletion(-)
Applied patches 1, 2, and 3 of this series to mvebu/boards. In the
future, please put driver changes first (patch #2) with few if any
dependencies.
In this case, since these patches depended on SMP support added to
mvebu/boards, I had to apply them to mvebu/boards to prevent a circular
dependency.
thx,
Jason.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 4/5] arm: mvebu: update DT to support local timers
2013-01-25 17:32 ` [PATCH v2 4/5] arm: mvebu: update DT to support local timers Gregory CLEMENT
@ 2013-02-15 21:59 ` Jason Cooper
0 siblings, 0 replies; 14+ messages in thread
From: Jason Cooper @ 2013-02-15 21:59 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, Jan 25, 2013 at 06:32:44PM +0100, Gregory CLEMENT wrote:
> Now that the time-armada-370-xp support local timers, updated the
> device tree to take it into account.
>
> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> ---
> arch/arm/boot/dts/armada-370-xp.dtsi | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
Patches 4 and 5 applied to mvebu/dt with a dependency on mvebu/boards
for patches 1-3 and the previous SMP support.
thx,
Jason.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 3/5] arm: mvebu: update defconfig with local timer support
2013-02-15 21:56 ` Jason Cooper
@ 2013-02-15 22:04 ` Gregory CLEMENT
2013-02-15 22:09 ` Jason Cooper
0 siblings, 1 reply; 14+ messages in thread
From: Gregory CLEMENT @ 2013-02-15 22:04 UTC (permalink / raw)
To: linux-arm-kernel
On 02/15/2013 10:56 PM, Jason Cooper wrote:
> On Fri, Jan 25, 2013 at 06:32:43PM +0100, Gregory CLEMENT wrote:
>> Now that we have support for local timers, enable it by default
>>
>> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
>> ---
>> arch/arm/configs/mvebu_defconfig | 1 -
>> 1 file changed, 1 deletion(-)
>
> Applied patches 1, 2, and 3 of this series to mvebu/boards. In the
> future, please put driver changes first (patch #2) with few if any
> dependencies.
>
> In this case, since these patches depended on SMP support added to
> mvebu/boards, I had to apply them to mvebu/boards to prevent a circular
> dependency.
Well the patch #2 can't work without the #1 (local interrupt support), so if
the order is changed then we loose the "bissecatiblity". That was the reason of
this order.
I hope Olof talk at ELC will help to understand better this workflow!
>
> thx,
>
> Jason.
>
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 3/5] arm: mvebu: update defconfig with local timer support
2013-02-15 22:04 ` Gregory CLEMENT
@ 2013-02-15 22:09 ` Jason Cooper
0 siblings, 0 replies; 14+ messages in thread
From: Jason Cooper @ 2013-02-15 22:09 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, Feb 15, 2013 at 11:04:14PM +0100, Gregory CLEMENT wrote:
> On 02/15/2013 10:56 PM, Jason Cooper wrote:
> > On Fri, Jan 25, 2013 at 06:32:43PM +0100, Gregory CLEMENT wrote:
> >> Now that we have support for local timers, enable it by default
> >>
> >> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> >> ---
> >> arch/arm/configs/mvebu_defconfig | 1 -
> >> 1 file changed, 1 deletion(-)
> >
> > Applied patches 1, 2, and 3 of this series to mvebu/boards. In the
> > future, please put driver changes first (patch #2) with few if any
> > dependencies.
> >
> > In this case, since these patches depended on SMP support added to
> > mvebu/boards, I had to apply them to mvebu/boards to prevent a circular
> > dependency.
>
> Well the patch #2 can't work without the #1 (local interrupt support), so if
> the order is changed then we loose the "bissecatiblity". That was the reason of
> this order.
Yes, that's why I kept them in order and didn't put them in
mvebu/drivers.
thx,
Jason.
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2013-02-15 22:09 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-01-25 17:32 [PATCH v2 0/5] arm: mvebu: add support for local timer for Armada 370/XP Gregory CLEMENT
2013-01-25 17:32 ` [PATCH v2 1/5] arm: mvebu: Add support for local interrupt Gregory CLEMENT
2013-01-25 17:32 ` [PATCH v2 2/5] clocksource: time-armada-370-xp: add local timer support Gregory CLEMENT
2013-02-15 21:21 ` Jason Cooper
2013-02-15 21:41 ` Gregory CLEMENT
2013-02-15 21:48 ` Jason Cooper
2013-01-25 17:32 ` [PATCH v2 3/5] arm: mvebu: update defconfig with " Gregory CLEMENT
2013-02-15 21:56 ` Jason Cooper
2013-02-15 22:04 ` Gregory CLEMENT
2013-02-15 22:09 ` Jason Cooper
2013-01-25 17:32 ` [PATCH v2 4/5] arm: mvebu: update DT to support local timers Gregory CLEMENT
2013-02-15 21:59 ` Jason Cooper
2013-01-25 17:32 ` [PATCH v2 5/5] clocksource: update and move armada-370-xp-timer documentation to timer directory Gregory CLEMENT
2013-01-30 19:52 ` [PATCH v2 0/5] arm: mvebu: add support for local timer for Armada 370/XP Jason Cooper
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox