Skip to contentSkip to conversation

Remove ARM local timer API

PATCH Superseded Stephen Boyd 4 participants 31 messages Mar 7, 2013 – Mar 12, 2013

Subsystems (7)

v2 of 7 Superseded Latest is v7 →

lore
Share & tools
lore
#0 lore raw

v2 cover Remove ARM local timer API

In light of Mark Rutland's recent work on divorcing the ARM architected timers from the ARM local timer API and introducing a generic arch hook for broadcast it seems that we should remove the local timer API entirely. Doing so will reduce the architecture dependencies of our timer drivers, reduce code in ARM core, and simplify timer drivers because they no longer go through an architecture layer that is essentially a hotplug notifier.

Previous attempts have been made[1] unsuccessfully. I'm hoping this can be accepted now so that we can clean up the timer drivers that are used in both UP and SMP situations. Right now these drivers have to ignore the timer setup callback on the boot CPU to avoid registering clockevents twice. This is not very symmetric and causes convuluted code that does the same thing in two places.

Patches based on v3.9-rc1. Mostly compile tested as I don't have access to the hardware.

[1] http://article.gmane.org/gmane.linux.ports.arm.kernel/145705

Note: A hotplug notifier is used by both x86 for the apb_timer (see apbt_cpuhp_notify) and by metag (see arch_timer_cpu_notify in metag_generic.c) so this is not new.

Changes since v1:
* Picked up Mark's generic dummy timer driver
* Split out omap changes into new patch

Mark Rutland (1):
clocksource: add generic dummy timer driver

Stephen Boyd (9):
ARM: smp: Remove duplicate dummy timer implementation
ARM: smp_twd: Divorce smp_twd from local timer API
ARM: OMAP2+: Divorce from local timer API
ARM: EXYNOS4: Divorce mct from local timer API
ARM: PRIMA2: Divorce timer-marco from local timer API
ARM: msm: Divorce msm_timer from local timer API
clocksource: time-armada-370-xp: Fix sparse warning
clocksource: time-armada-370-xp: Divorce from local timer API
ARM: smp: Remove local timer API

 arch/arm/Kconfig                         |  12 +--
 arch/arm/include/asm/localtimer.h        |  34 ---------
 arch/arm/kernel/smp.c                    |  87 ---------------------
 arch/arm/kernel/smp_twd.c                |  48 ++++++++----
 arch/arm/mach-exynos/mct.c               |  53 +++++++++----
 arch/arm/mach-msm/timer.c                | 125 +++++++++++++++++--------------
 arch/arm/mach-omap2/Kconfig              |   1 -
 arch/arm/mach-omap2/timer.c              |   7 --
 arch/arm/mach-prima2/timer-marco.c       |  98 ++++++++++++------------
 drivers/clocksource/Makefile             |   1 +
 drivers/clocksource/dummy_timer.c        |  67 +++++++++++++++++
 drivers/clocksource/time-armada-370-xp.c |  88 ++++++++++------------
 include/linux/time-armada-370-xp.h       |   4 +-
 13 files changed, 298 insertions(+), 327 deletions(-)
 delete mode 100644 arch/arm/include/asm/localtimer.h
 create mode 100644 drivers/clocksource/dummy_timer.c
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#1 lore raw

PATCH v2 1/10 clocksource: add generic dummy timer driver

From: Mark Rutland <[email protected]>

Several architectures have a dummy timer driver tightly coupled with their broadcast code to support machines without cpu-local timers (or where there is a lack of driver support).

Since 12ad100046: "clockevents: Add generic timer broadcast function" it's been possible to write broadcast-capable timer drivers decoupled from the broadcast mechanism. We can use this functionality to implement a generic dummy timer driver that can be shared by all architectures with generic tick broadcast (ARCH_HAS_TICK_BROADCAST).

This patch implements a generic dummy timer using this facility.

Cc John Stultz <[email protected]>
Cc Thomas Gleixner <[email protected]>
[sboyd: Make percpu data static, use __this_cpu_ptr(), s/dummy/dummy_timer/]
---
 drivers/clocksource/Makefile      |  1 +
 drivers/clocksource/dummy_timer.c | 67 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+)
 create mode 100644 drivers/clocksource/dummy_timer.c
drivers/clocksource/Makefile +1 -0
index 4d8283a..655d718 100644
@@ -22,3 +22,4 @@ obj-$(CONFIG_VT8500_TIMER)	+= vt8500_timer.o
 
 obj-$(CONFIG_ARM_ARCH_TIMER)		+= arm_arch_timer.o
 obj-$(CONFIG_CLKSRC_METAG_GENERIC)	+= metag_generic.o
+obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST)	+= dummy_timer.o
drivers/clocksource/dummy_timer.c new file +67 -0

67 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#2 lore raw

Re: [PATCH 01/10] clocksource: add generic dummy timer driver

drivers/clocksource/dummy_timer.c line 67

Quoted 12 lines · Stephen Boyd
drivers/clocksource/dummy_timer.c new file +12 -0
+static int __init dummy_timer_register(void)
+{
+	int err = register_cpu_notifier(&dummy_timer_cpu_nb);
+	if (err)
+		return err;
+
+	/* We won't get a call on the boot CPU, so register immediately */
+	dummy_timer_setup();
+
+	return 0;
+}
+device_initcall(dummy_timer_register);

Are you sure that you want that to be installed unconditionally? What about multi-platform kernels?

Thanks,

tglx

#3 lore raw

Re: [PATCH 01/10] clocksource: add generic dummy timer driver

Quoted 17 lines · Thomas Gleixner

drivers/clocksource/dummy_timer.c line 67

Quoted 12 lines · Stephen Boyd
drivers/clocksource/dummy_timer.c new file +12 -0
+static int __init dummy_timer_register(void)
+{
+	int err = register_cpu_notifier(&dummy_timer_cpu_nb);
+	if (err)
+		return err;
+
+	/* We won't get a call on the boot CPU, so register immediately */
+	dummy_timer_setup();
+
+	return 0;
+}
+device_initcall(dummy_timer_register);

Are you sure that you want that to be installed unconditionally? What about multi-platform kernels?

A dummy timer is already installed unconditionally on devices with an arm architected timer, so if this is breaking something then those devices have been broken in the 3.9 merge window. I suppose we may need to make the rating even lower if there is somebody using a clockevent with a rating below 100. My grep of the tree shows 125 as the lowest, but perhaps we want to set the rating to 1 to be safe?

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#4 lore raw

PATCH v2 2/10 ARM: smp: Remove duplicate dummy timer implementation

In reply to Stephen Boyd

Drop ARM's version of the dummy timer now that we have a generic implementation in drivers/clocksource.

---
 arch/arm/kernel/smp.c | 22 ++--------------------
 1 file changed, 2 insertions(+), 20 deletions(-)
arch/arm/kernel/smp.c +2 -20
index 1bdfd87..e4f3669 100644
@@ -468,24 +468,6 @@ void tick_broadcast(const struct cpumask *mask)
 }
 #endif
 
-static void broadcast_timer_set_mode(enum clock_event_mode mode,
-	struct clock_event_device *evt)
-{
-}
-
-static void __cpuinit broadcast_timer_setup(struct clock_event_device *evt)
-{
-	evt->name	= "dummy_timer";
-	evt->features	= CLOCK_EVT_FEAT_ONESHOT |
-			  CLOCK_EVT_FEAT_PERIODIC |
-			  CLOCK_EVT_FEAT_DUMMY;
-	evt->rating	= 400;
-	evt->mult	= 1;
-	evt->set_mode	= broadcast_timer_set_mode;
-
-	clockevents_register_device(evt);
-}
-
 static struct local_timer_ops *lt_ops;
 
 #ifdef CONFIG_LOCAL_TIMERS
@@ -509,8 +491,8 @@ static void __cpuinit percpu_timer_setup(void)
 
 	evt->cpumask = cpumask_of(cpu);
 
-	if (!lt_ops || lt_ops->setup(evt))
-		broadcast_timer_setup(evt);
+	if (lt_ops)
+		lt_ops->setup(evt);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#5 lore raw

PATCH v2 3/10 ARM: smp_twd: Divorce smp_twd from local timer API

In reply to Stephen Boyd

Separate the smp_twd timers from the local timer API. This will allow us to remove ARM local timer support in the near future and gets us closer to moving this driver to drivers/clocksource.

---
 arch/arm/Kconfig          |  2 +-
 arch/arm/kernel/smp_twd.c | 48 +++++++++++++++++++++++++++++++----------------
 2 files changed, 33 insertions(+), 17 deletions(-)
arch/arm/Kconfig +1 -1
index 5b71469..5ad2ccf 100644
@@ -1527,6 +1527,7 @@ config SMP
 	depends on HAVE_SMP
 	depends on MMU
 	select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP
+	select HAVE_ARM_TWD if (!ARCH_MSM_SCORPIONMP && !EXYNOS4_MCT)
 	select USE_GENERIC_SMP_HELPERS
 	help
 	  This enables support for systems with more than one CPU. If you have
@@ -1650,7 +1651,6 @@ config LOCAL_TIMERS
 	bool "Use local timer interrupts"
 	depends on SMP
 	default y
-	select HAVE_ARM_TWD if (!ARCH_MSM_SCORPIONMP && !EXYNOS4_MCT)
 	help
 	  Enable support for local timers on SMP platforms, rather then the
 	  legacy IPI broadcast method.  Local timers allows the system
arch/arm/kernel/smp_twd.c +32 -16

129 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
maintainer
#6 lore raw

Re: [PATCH 03/10] ARM: smp_twd: Divorce smp_twd from local timer API

Hi,

Quoted 3 lines · Stephen Boyd

Separate the smp_twd timers from the local timer API. This will allow us to remove ARM local timer support in the near future and gets us closer to moving this driver to drivers/clocksource.

Looks like applying this patch makes omap4 to stop booting for some reason.

Regards,

Tony

#7 lore raw

Re: [PATCH 03/10] ARM: smp_twd: Divorce smp_twd from local timer API

Quoted 10 lines · Tony Lindgren

Hi,

Quoted 3 lines · Stephen Boyd

Separate the smp_twd timers from the local timer API. This will allow us to remove ARM local timer support in the near future and gets us closer to moving this driver to drivers/clocksource.

Looks like applying this patch makes omap4 to stop booting for some reason.

Hm... Perhaps you need the clock?

arch/arm/kernel/smp_twd.c +2 -2
index 2439843..081de6f 100644
@@ -345,11 +345,11 @@ static int __init twd_local_timer_common_register(struct device_node *np)
        if (err)
                goto out_irq;
 
+       twd_get_clock(np);
+
        /* Immediately configure the timer on the boot CPU */
        twd_timer_setup(this_cpu_ptr(twd_evt));
 
-       twd_get_clock(np);
-
        return 0;
 
 out_irq:
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
maintainer
#8 lore raw

Re: [PATCH 03/10] ARM: smp_twd: Divorce smp_twd from local timer API

Stephen Boyd <[email protected]> [130307 17:18]:

Quoted 7 lines · Tony Lindgren
Quoted 6 lines

Hi,

Stephen Boyd <[email protected]> [130306 17:53]:

Quoted 3 lines

Separate the smp_twd timers from the local timer APIThis will allow us to remove ARM local timer support in the near future and gets us closer to moving this driver to drivers/clocksource.

Quoted 6 lines
Quoted 4 lines

Looks like applying this patch makes omap4 to stop booting for some reason.

Hm..Perhaps you need the clock?

Something is missing as the interrupts don't happen and it hangs:

...
OMAP clockevent source: GPTIMER1 at 32768 Hz
sched_clock: 32 bits at 32kHz, resolution 30517ns, wraps every 131071999ms OMAP clocksource: 32k_counter at 32768 Hz
Calibrating local timer...

Quoted 6 lines
arch/arm/kernel/smp_twd.c +0 -0
@@ -345,11 +345,11 @@ static int __init twd_local_timer_common_register(struct device_node *np)
        if (err)
                goto out_irq;
 

arch/arm/kernel/smp_twd.c static int __init twd_local_timer_common_register(struct device_node *np) · line 355

Quoted 10 lines
arch/arm/kernel/smp_twd.c +2 -2
+       twd_get_clock(np);
+
        /Immediately configure the timer on the boot CPU */
        twd_timer_setup(this_cpu_ptr(twd_evt));
 
-       twd_get_clock(np);
-
        return 0;
 
 out_irq:

Adding that produces the following:

...
OMAP clockevent source: GPTIMER1 at 32768 Hz
sched_clock: 32 bits at 32kHz, resolution 30517ns, wraps every 131071999ms OMAP clocksource: 32k_counter at 32768 Hz
Console: colour dummy device 80x30
Lock dependency validator: Copyright (c) 2006 Red Hat, Inc., Ingo Molnar

Unable to handle kernel NULL pointer dereference at virtual address 0000001d
pgd = c0004000
[0000001d] *pgd=00000000
Internal error: Oops: 5 [#1] SMP ARM
Modules linked in:
CPU: 0    Not tainted  (3.9.0-rc1-12182-g90ac757-dirty #42)
PC is at 0xe7d7f0a0
LR is at twd_handler+0x34/0x40
pc : [<e7d7f0a0>]    lr : [<c001a650>]    psr: 200001d3

sp : c0791ea0 ip : c0790000 fp : 00000004
r10: ed806780 r9 : c0805840 r8 : 00e0c000
r7 : c07919c0 r6 : ed801900 r5 : 0000001d r4 : 00000001 r3 : fa240600 r2 : fa24060c r1 : c0090d28 r0 : c0090d28
Flags: nzCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment kernel
Control: 10c53c7d Table: 8000404a DAC: 00000017
Process swapper/0 (pid: 0, stack limit = 0xc0790240)

Stack: (0xc0791ea0 to 0xc0792000)

1ea0: c07997a8 c00ac80c 0000001d c078e248 c0790000 00000000 c07997a8 00000000 1ec0: c0790000 c00a9e2c 0000001d c00152a8 fa24010c c0791f00 c0799904 fa240110 1ee0: c082b260 c000868c 200001d3 c004901c 20000153 ffffffff c0791f34 c052db64 1f00: 00000001 00000001 c079bc90 00000000 00000000 00000000 00000048 00000048 1f20: c082b260 00000000 c0790000 00000004 00000000 c0791f48 60000153 c004901c 1f40: 20000153 ffffffff 00000000 00000000 00000000 00000000 c082b260 00000048 1f60: 00000000 00000000 00000000 60000153 c033e2ec c0791fac c08292bc c0829240 1f80: c076f678 ffffffff 411fc092 c07988c0 00000000 c0529c88 c068460c c0791fac 1fa0: c082924c c07515b4 c068460c c080bb1c 00000011 c0829258 bfffffff c0736884 1fc0: ffffffff ffffffff c0736474 00000000 00000000 c076f678 00000000 10c53c7d 1fe0: c0798934 c076fa7c c079d16c 8000406a 00000000 80008074 00000000 00000000 [<c001a650>] (twd_handler+0x34/0x40) from [<c00ac80c>] (handle_percpu_devid_irq+0xb8/0x128) [<c00ac80c>] (handle_percpu_devid_irq+0xb8/0x128) from [<c00a9e2c>] (generic_handle_irq+0x30/0x3c) [<c00a9e2c>] (generic_handle_irq+0x30/0x3c) from [<c00152a8>] (handle_IRQ+0x48/0xa8) [<c00152a8>] (handle_IRQ+0x48/0xa8) from [<c000868c>] (gic_handle_irq+0x30/0x6c) [<c000868c>] (gic_handle_irq+0x30/0x6c) from [<c052db64>] (__irq_svc+0x44/0x5c)

Exception stack(0xc0791f00 to 0xc0791f48)

1f00: 00000001 00000001 c079bc90 00000000 00000000 00000000 00000048 00000048 1f20: c082b260 00000000 c0790000 00000004 00000000 c0791f48 60000153 c004901c 1f40: 20000153 ffffffff
[<c052db64>] (__irq_svc+0x44/0x5c) from [<c004901c>] (vprintk_emit+0x1f8/0x544) [<c004901c>] (vprintk_emit+0x1f8/0x544) from [<c0529c88>] (printk+0x30/0x40) [<c0529c88>] (printk+0x30/0x40) from [<c07515b4>] (lockdep_info+0x10/0xb4) [<c07515b4>] (lockdep_info+0x10/0xb4) from [<c0736884>] (start_kernel+0x1dc/0x328) [<c0736884>] (start_kernel+0x1dc/0x328) from [<80008074>] (0x80008074)

Code: 57555555 55755154 557d5554 55d55655 (54555575) 

Regards,

Tony

#9 lore raw

Re: [PATCH 03/10] ARM: smp_twd: Divorce smp_twd from local timer API

Quoted 51 lines · Tony Lindgren

Adding that produces the following:

...
OMAP clockevent source: GPTIMER1 at 32768 Hz
sched_clock: 32 bits at 32kHz, resolution 30517ns, wraps every 131071999ms OMAP clocksource: 32k_counter at 32768 Hz
Console: colour dummy device 80x30
Lock dependency validator: Copyright (c) 2006 Red Hat, Inc., Ingo Molnar

Unable to handle kernel NULL pointer dereference at virtual address 0000001d
pgd = c0004000
[0000001d] *pgd=00000000
Internal error: Oops: 5 [#1] SMP ARM
Modules linked in:
CPU: 0    Not tainted  (3.9.0-rc1-12182-g90ac757-dirty #42)
PC is at 0xe7d7f0a0
LR is at twd_handler+0x34/0x40
pc : [<e7d7f0a0>]    lr : [<c001a650>]    psr: 200001d3

sp : c0791ea0 ip : c0790000 fp : 00000004
r10: ed806780 r9 : c0805840 r8 : 00e0c000
r7 : c07919c0 r6 : ed801900 r5 : 0000001d r4 : 00000001 r3 : fa240600 r2 : fa24060c r1 : c0090d28 r0 : c0090d28
Flags: nzCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment kernel
Control: 10c53c7d Table: 8000404a DAC: 00000017
Process swapper/0 (pid: 0, stack limit = 0xc0790240)

Stack: (0xc0791ea0 to 0xc0792000)

1ea0: c07997a8 c00ac80c 0000001d c078e248 c0790000 00000000 c07997a8 00000000 1ec0: c0790000 c00a9e2c 0000001d c00152a8 fa24010c c0791f00 c0799904 fa240110 1ee0: c082b260 c000868c 200001d3 c004901c 20000153 ffffffff c0791f34 c052db64 1f00: 00000001 00000001 c079bc90 00000000 00000000 00000000 00000048 00000048 1f20: c082b260 00000000 c0790000 00000004 00000000 c0791f48 60000153 c004901c 1f40: 20000153 ffffffff 00000000 00000000 00000000 00000000 c082b260 00000048 1f60: 00000000 00000000 00000000 60000153 c033e2ec c0791fac c08292bc c0829240 1f80: c076f678 ffffffff 411fc092 c07988c0 00000000 c0529c88 c068460c c0791fac 1fa0: c082924c c07515b4 c068460c c080bb1c 00000011 c0829258 bfffffff c0736884 1fc0: ffffffff ffffffff c0736474 00000000 00000000 c076f678 00000000 10c53c7d 1fe0: c0798934 c076fa7c c079d16c 8000406a 00000000 80008074 00000000 00000000 [<c001a650>] (twd_handler+0x34/0x40) from [<c00ac80c>] (handle_percpu_devid_irq+0xb8/0x128) [<c00ac80c>] (handle_percpu_devid_irq+0xb8/0x128) from [<c00a9e2c>] (generic_handle_irq+0x30/0x3c) [<c00a9e2c>] (generic_handle_irq+0x30/0x3c) from [<c00152a8>] (handle_IRQ+0x48/0xa8) [<c00152a8>] (handle_IRQ+0x48/0xa8) from [<c000868c>] (gic_handle_irq+0x30/0x6c) [<c000868c>] (gic_handle_irq+0x30/0x6c) from [<c052db64>] (__irq_svc+0x44/0x5c)

Exception stack(0xc0791f00 to 0xc0791f48)

1f00: 00000001 00000001 c079bc90 00000000 00000000 00000000 00000048 00000048 1f20: c082b260 00000000 c0790000 00000004 00000000 c0791f48 60000153 c004901c 1f40: 20000153 ffffffff
[<c052db64>] (__irq_svc+0x44/0x5c) from [<c004901c>] (vprintk_emit+0x1f8/0x544) [<c004901c>] (vprintk_emit+0x1f8/0x544) from [<c0529c88>] (printk+0x30/0x40) [<c0529c88>] (printk+0x30/0x40) from [<c07515b4>] (lockdep_info+0x10/0xb4) [<c07515b4>] (lockdep_info+0x10/0xb4) from [<c0736884>] (start_kernel+0x1dc/0x328) [<c0736884>] (start_kernel+0x1dc/0x328) from [<80008074>] (0x80008074)

Quoted 2 lines
Code: 57555555 55755154 557d5554 55d55655 (54555575) 

Ah. Two bugs :-(

----8<-----

arch/arm/kernel/smp_twd.c +1 -1
index 081de6f..4ea3e9d 100644
@@ -227,7 +227,7 @@ static void __cpuinit twd_calibrate_rate(void)
 
 static irqreturn_t twd_handler(int irq, void *dev_id)
 {
-       struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+       struct clock_event_device *evt = dev_id;
 
        if (twd_timer_ack()) {
                evt->event_handler(evt);
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
maintainer Acked-by
#10 lore raw

Re: [PATCH 03/10] ARM: smp_twd: Divorce smp_twd from local timer API

Quoted 65 lines · Stephen Boyd
Quoted 51 lines · Tony Lindgren

Adding that produces the following:

...
OMAP clockevent source: GPTIMER1 at 32768 Hz
sched_clock: 32 bits at 32kHz, resolution 30517ns, wraps every 131071999ms OMAP clocksource: 32k_counter at 32768 Hz
Console: colour dummy device 80x30
Lock dependency validator: Copyright (c) 2006 Red Hat, Inc., Ingo Molnar

Unable to handle kernel NULL pointer dereference at virtual address 0000001d
pgd = c0004000
[0000001d] *pgd=00000000
Internal error: Oops: 5 [#1] SMP ARM
Modules linked in:
CPU: 0    Not tainted  (3.9.0-rc1-12182-g90ac757-dirty #42)
PC is at 0xe7d7f0a0
LR is at twd_handler+0x34/0x40
pc : [<e7d7f0a0>]    lr : [<c001a650>]    psr: 200001d3

sp : c0791ea0 ip : c0790000 fp : 00000004
r10: ed806780 r9 : c0805840 r8 : 00e0c000
r7 : c07919c0 r6 : ed801900 r5 : 0000001d r4 : 00000001 r3 : fa240600 r2 : fa24060c r1 : c0090d28 r0 : c0090d28
Flags: nzCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment kernel
Control: 10c53c7d Table: 8000404a DAC: 00000017
Process swapper/0 (pid: 0, stack limit = 0xc0790240)

Stack: (0xc0791ea0 to 0xc0792000)

1ea0: c07997a8 c00ac80c 0000001d c078e248 c0790000 00000000 c07997a8 00000000 1ec0: c0790000 c00a9e2c 0000001d c00152a8 fa24010c c0791f00 c0799904 fa240110 1ee0: c082b260 c000868c 200001d3 c004901c 20000153 ffffffff c0791f34 c052db64 1f00: 00000001 00000001 c079bc90 00000000 00000000 00000000 00000048 00000048 1f20: c082b260 00000000 c0790000 00000004 00000000 c0791f48 60000153 c004901c 1f40: 20000153 ffffffff 00000000 00000000 00000000 00000000 c082b260 00000048 1f60: 00000000 00000000 00000000 60000153 c033e2ec c0791fac c08292bc c0829240 1f80: c076f678 ffffffff 411fc092 c07988c0 00000000 c0529c88 c068460c c0791fac 1fa0: c082924c c07515b4 c068460c c080bb1c 00000011 c0829258 bfffffff c0736884 1fc0: ffffffff ffffffff c0736474 00000000 00000000 c076f678 00000000 10c53c7d 1fe0: c0798934 c076fa7c c079d16c 8000406a 00000000 80008074 00000000 00000000 [<c001a650>] (twd_handler+0x34/0x40) from [<c00ac80c>] (handle_percpu_devid_irq+0xb8/0x128) [<c00ac80c>] (handle_percpu_devid_irq+0xb8/0x128) from [<c00a9e2c>] (generic_handle_irq+0x30/0x3c) [<c00a9e2c>] (generic_handle_irq+0x30/0x3c) from [<c00152a8>] (handle_IRQ+0x48/0xa8) [<c00152a8>] (handle_IRQ+0x48/0xa8) from [<c000868c>] (gic_handle_irq+0x30/0x6c) [<c000868c>] (gic_handle_irq+0x30/0x6c) from [<c052db64>] (__irq_svc+0x44/0x5c)

Exception stack(0xc0791f00 to 0xc0791f48)

1f00: 00000001 00000001 c079bc90 00000000 00000000 00000000 00000048 00000048 1f20: c082b260 00000000 c0790000 00000004 00000000 c0791f48 60000153 c004901c 1f40: 20000153 ffffffff
[<c052db64>] (__irq_svc+0x44/0x5c) from [<c004901c>] (vprintk_emit+0x1f8/0x544) [<c004901c>] (vprintk_emit+0x1f8/0x544) from [<c0529c88>] (printk+0x30/0x40) [<c0529c88>] (printk+0x30/0x40) from [<c07515b4>] (lockdep_info+0x10/0xb4) [<c07515b4>] (lockdep_info+0x10/0xb4) from [<c0736884>] (start_kernel+0x1dc/0x328) [<c0736884>] (start_kernel+0x1dc/0x328) from [<80008074>] (0x80008074)

Quoted 2 lines
Code: 57555555 55755154 557d5554 55d55655 (54555575) 

Ah. Two bugs :-(

----8<-----

arch/arm/kernel/smp_twd.c +0 -0
index 081de6f..4ea3e9d 100644

arch/arm/kernel/smp_twd.c static void __cpuinit twd_calibrate_rate(void) · line 233

Quoted 8 lines
arch/arm/kernel/smp_twd.c +1 -1
@@ -227,7 +227,7 @@ static void __cpuinit twd_calibrate_rate(void)
 
 static irqreturn_t twd_handler(int irq, void *dev_id)
 {
-       struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+       struct clock_event_device *evt = dev_id;
 
        if (twd_timer_ack()) {
                evt->event_handler(evt);

Yup thanks that fixes it, both fixes are needed. So for this patch + the two fixes please feel free to add:

#11 lore raw

Re: [PATCH 03/10] ARM: smp_twd: Divorce smp_twd from local timer API

Quoted 13 lines · Tony Lindgren
Quoted 12 lines · Stephen Boyd
arch/arm/kernel/smp_twd.c +1 -1
index 081de6f..4ea3e9d 100644
@@ -227,7 +227,7 @@ static void __cpuinit twd_calibrate_rate(void)
 
 static irqreturn_t twd_handler(int irq, void *dev_id)
 {
-       struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+       struct clock_event_device *evt = dev_id;
 
Quoted 7 lines

arch/arm/kernel/smp_twd.c static void __cpuinit twd_calibrate_rate(void) · line 233

Quoted 3 lines
arch/arm/kernel/smp_twd.c +0 -0
        if (twd_timer_ack()) {
                evt->event_handler(evt);

Yup thanks that fixes it, both fixes are needed. So for this patch + the two fixes please feel free to add:

Great. Thanks for testing.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
maintainer
#12 lore raw

Re: [PATCH 03/10] ARM: smp_twd: Divorce smp_twd from local timer API

Quoted 20 lines · Stephen Boyd
Quoted 19 lines · Tony Lindgren
Quoted 7 lines · Stephen Boyd
arch/arm/kernel/smp_twd.c +0 -0
index 081de6f..4ea3e9d 100644

arch/arm/kernel/smp_twd.c static void __cpuinit twd_calibrate_rate(void) · line 233

Quoted 8 lines
arch/arm/kernel/smp_twd.c +1 -1
@@ -227,7 +227,7 @@ static void __cpuinit twd_calibrate_rate(void)
 
 static irqreturn_t twd_handler(int irq, void *dev_id)
 {
-       struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+       struct clock_event_device *evt = dev_id;
 
        if (twd_timer_ack()) {
                evt->event_handler(evt);

Yup thanks that fixes it, both fixes are needed. So for this patch + the two fixes please feel free to add:

Quoted 3 lines
Quoted 1 line

Great. Thanks for testing.

Hmm noticed one more thing: vexpress no longer boots in qemu for me after applying this. Sorry did not get any debug_ll output, but maybe you can take a look at it. I tested with omap2plus_defconfig + linaro-qemu:

$ qemu-system-arm -machine vexpress-a9 -m 1024 -curses -net nic -net \
user -serial stdio -append console=ttyAMA0,115200n8 rw \
root=/dev/mmcblk0p2 rootwait physmap.enabled=0 -kernel zImage \
-initrd initrd.img -sd rootfs.img

Regards,

Tony

#13 lore raw

Re: [PATCH 03/10] ARM: smp_twd: Divorce smp_twd from local timer API

Quoted 27 lines · Tony Lindgren
Quoted 13 lines · Stephen Boyd
Quoted 12 lines · Tony Lindgren
Quoted 11 lines · Stephen Boyd
arch/arm/kernel/smp_twd.c +1 -1
index 081de6f..4ea3e9d 100644
@@ -227,7 +227,7 @@ static void __cpuinit twd_calibrate_rate(void)
 
 static irqreturn_t twd_handler(int irq, void *dev_id)
 {
-       struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+       struct clock_event_device *evt = dev_id;
 
Quoted 8 lines
Quoted 7 lines

arch/arm/kernel/smp_twd.c static void __cpuinit twd_calibrate_rate(void) · line 233

Quoted 3 lines
arch/arm/kernel/smp_twd.c +0 -0
        if (twd_timer_ack()) {
                evt->event_handler(evt);

Yup thanks that fixes it, both fixes are needed. So for this patch + the two fixes please feel free to add:

Great. Thanks for testing.

Hmm noticed one more thing: vexpress no longer boots in qemu for me after applying this. Sorry did not get any debug_ll output, but maybe you can take a look at it. I tested with omap2plus_defconfig + linaro-qemu:

Quoted 6 lines
$ qemu-system-arm -machine vexpress-a9 -m 1024 -curses -net nic -net \
user -serial stdio -append console=ttyAMA0,115200n8 rw \
root=/dev/mmcblk0p2 rootwait physmap.enabled=0 -kernel zImage \
-initrd initrd.img -sd rootfs.img

I wonder if you're hitting something similar to this issue on versatile boards [1]. Can you try that patch? Otherwise I will try to get qemu running (something I've never done, do you have instructions?).

[1] http://article.gmane.org/gmane.linux.ports.arm.kernel/221539

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
maintainer
#14 lore raw

Re: [PATCH 03/10] ARM: smp_twd: Divorce smp_twd from local timer API

Quoted 35 lines · Stephen Boyd
Quoted 27 lines · Tony Lindgren
Quoted 13 lines · Stephen Boyd
Quoted 12 lines · Tony Lindgren
Quoted 11 lines · Stephen Boyd
arch/arm/kernel/smp_twd.c +1 -1
index 081de6f..4ea3e9d 100644
@@ -227,7 +227,7 @@ static void __cpuinit twd_calibrate_rate(void)
 
 static irqreturn_t twd_handler(int irq, void *dev_id)
 {
-       struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+       struct clock_event_device *evt = dev_id;
 
Quoted 8 lines
Quoted 7 lines

arch/arm/kernel/smp_twd.c static void __cpuinit twd_calibrate_rate(void) · line 233

Quoted 3 lines
arch/arm/kernel/smp_twd.c +0 -0
        if (twd_timer_ack()) {
                evt->event_handler(evt);

Yup thanks that fixes it, both fixes are needed. So for this patch + the two fixes please feel free to add:

Great. Thanks for testing.

Hmm noticed one more thing: vexpress no longer boots in qemu for me after applying this. Sorry did not get any debug_ll output, but maybe you can take a look at it. I tested with omap2plus_defconfig + linaro-qemu:

Quoted 6 lines
$ qemu-system-arm -machine vexpress-a9 -m 1024 -curses -net nic -net \
user -serial stdio -append console=ttyAMA0,115200n8 rw \
root=/dev/mmcblk0p2 rootwait physmap.enabled=0 -kernel zImage \
-initrd initrd.img -sd rootfs.img
Quoted 3 lines

I wonder if you're hitting something similar to this issue on versatile boards [1]. Can you try that patch? Otherwise I will try to get qemu running (something I've never done, do you have instructions?).

Applying that does not seem to help, but you might want to get vexpress running anyways for some multiplatform sanity checks.

I just built and installed qemu-linaro from their git, then ran the command above. Looks like stock qemu does not work for vexpress for some reason. You can probably use a dummy initrd and rootfs to debug this though :)

More info on qemu-linaro at:

https://launchpad.net/qemu-linaro

Regards,

Tony

Quoted 1 line

[1] http://article.gmane.org/gmane.linux.ports.arm.kernel/221539

#15 lore raw

Re: [PATCH 03/10] ARM: smp_twd: Divorce smp_twd from local timer API

Quoted 7 lines · Tony Lindgren

Applying that does not seem to help, but you might want to get vexpress running anyways for some multiplatform sanity checks.

I just built and installed qemu-linaro from their git, then ran the command above. Looks like stock qemu does not work for vexpress for some reason. You can probably use a dummy initrd and rootfs to debug this though :)

So my patchset didn't break qemu?

Quoted 4 lines

More info on qemu-linaro at:

https://launchpad.net/qemu-linaro

Thanks for the link.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
maintainer
#16 lore raw

Re: [PATCH 03/10] ARM: smp_twd: Divorce smp_twd from local timer API

Quoted 10 lines · Stephen Boyd
Quoted 7 lines · Tony Lindgren

Applying that does not seem to help, but you might want to get vexpress running anyways for some multiplatform sanity checks.

I just built and installed qemu-linaro from their git, then ran the command above. Looks like stock qemu does not work for vexpress for some reason. You can probably use a dummy initrd and rootfs to debug this though :)

So my patchset didn't break qemu?

Sorry if that was unclear: Yes your patchset breaks booting vexpress in qemu.

What I meant earlier is that I've ever gotten the qemu-linaro to boot vexpress and the unpatches qemu did not seem to boot vexpress at all the last time I tried few months back.

Regards,

Tony

#17 lore raw

Re: [PATCH 03/10] ARM: smp_twd: Divorce smp_twd from local timer API

Quoted 5 lines · Tony Lindgren
Quoted 4 lines · Stephen Boyd
Quoted 3 lines · Tony Lindgren

Applying that does not seem to help, but you might want to get vexpress running anyways for some multiplatform sanity checks.

Quoted 9 lines
Quoted 5 lines
Quoted 4 lines

I just built and installed qemu-linaro from their git, then ran the command above. Looks like stock qemu does not work for vexpress for some reason. You can probably use a dummy initrd and rootfs to debug this though :)

So my patchset didn't break qemu?

Sorry if that was unclear: Yes your patchset breaks booting vexpress in qemu.

Ok. qemu works for me before applying my patches. I've added this into the series before this patch to fix the boot issue.

-----8<-----

Subject: [PATCH] ARM: vexpress: Move smp_twd setup to time_late_init hook

On devices without a clock describing the rate of the twd we detect the rate at runtime via twd_calibrate_rate(). Currently this happens when smp_prepare_cpus() calls the localtimer start callback, after the sp804 timer has been registered and when jiffies have started incrementing.

In the next patch we're going to make twd_local_timer_register() register the twd clockevent on the boot CPU. In the case of vexpress, this will hang the system at boot because jiffies haven't started incrementing when twd_calibrate_rate() is called. Register the smp_twd during time_late_init() on vexpress to avoid this problem.

Based on a patch by Marc Zyngier <[email protected]>.

---
 arch/arm/mach-vexpress/ct-ca9x4.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm/mach-vexpress/ct-ca9x4.c +1 -1
index 6f34497..a9f39bf 100644
@@ -62,7 +62,7 @@ static void __init ct_ca9x4_init_irq(void)
 {
 	gic_init(0, 29, ioremap(A9_MPCORE_GIC_DIST, SZ_4K),
 		 ioremap(A9_MPCORE_GIC_CPU, SZ_256));
-	ca9x4_twd_init();
+	late_time_init = ca9x4_twd_init;
 }
 
 static int ct_ca9x4_clcd_setup(struct clcd_fb *fb)
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
maintainer Acked-by
#18 lore raw

Re: [PATCH 03/10] ARM: smp_twd: Divorce smp_twd from local timer API

Quoted 10 lines · Stephen Boyd
Quoted 9 lines · Tony Lindgren
Quoted 8 lines · Stephen Boyd
Quoted 7 lines · Tony Lindgren

Applying that does not seem to help, but you might want to get vexpress running anyways for some multiplatform sanity checks.

I just built and installed qemu-linaro from their git, then ran the command above. Looks like stock qemu does not work for vexpress for some reason. You can probably use a dummy initrd and rootfs to debug this though :)

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

So my patchset didn't break qemu?

Sorry if that was unclear: Yes your patchset breaks booting vexpress in qemu.

Ok. qemu works for me before applying my patches. I've added this into the series before this patch to fix the boot issue.

OK thanks:

Quoted 44 lines

-----8<-----

Subject: [PATCH] ARM: vexpress: Move smp_twd setup to time_late_init hook

On devices without a clock describing the rate of the twd we detect the rate at runtime via twd_calibrate_rate(). Currently this happens when smp_prepare_cpus() calls the localtimer start callback, after the sp804 timer has been registered and when jiffies have started incrementing.

In the next patch we're going to make twd_local_timer_register() register the twd clockevent on the boot CPU. In the case of vexpress, this will hang the system at boot because jiffies haven't started incrementing when twd_calibrate_rate() is called. Register the smp_twd during time_late_init() on vexpress to avoid this problem.

Based on a patch by Marc Zyngier <[email protected]>.

---
 arch/arm/mach-vexpress/ct-ca9x4.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm/mach-vexpress/ct-ca9x4.c +1 -1
index 6f34497..a9f39bf 100644
@@ -62,7 +62,7 @@ static void __init ct_ca9x4_init_irq(void)
 {
 	gic_init(0, 29, ioremap(A9_MPCORE_GIC_DIST, SZ_4K),
 		 ioremap(A9_MPCORE_GIC_CPU, SZ_256));
-	ca9x4_twd_init();
+	late_time_init = ca9x4_twd_init;
 }
 
 static int ct_ca9x4_clcd_setup(struct clcd_fb *fb)
Signature · 3 lines
-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#19 lore raw

Re: [PATCH 03/10] ARM: smp_twd: Divorce smp_twd from local timer API

Quoted 6 lines · Tony Lindgren
Quoted 2 lines · Stephen Boyd

Ok. qemu works for me before applying my patches. I've added this into the series before this patch to fix the boot issue.

OK thanks:

Actually, it's worse. From reading the code it looks like quite a few other machines register a clockevent and get jiffies going so they can calibrate the twd. I also see that Rob Herring's pull request to move smp_twd to CLKSRC_OF_DECLARE is going to conflict with any changes I make in the board files. I think we need to make the twd use the late_time_init callback if there is no clock rate and ignore the other patch I sent out a few hours ago. Basically, squash this into this 3/10 patch.

----8<-----

arch/arm/kernel/smp_twd.c +19 -11
index a1185d3..c58918f 100644
@@ -90,8 +90,10 @@ static int twd_timer_ack(void)
 	return 0;
 }
 
-static void twd_timer_stop(struct clock_event_device *clk)
+static void twd_timer_stop(void)
 {
+	struct clock_event_device *clk = __this_cpu_ptr(twd_evt);
+
 	twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
 	disable_percpu_irq(clk->irq);
 }
@@ -265,8 +267,9 @@ static void twd_get_clock(struct device_node *np)
 /*
  * Setup the local clock events for a CPU.
  */
-static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
+static void __cpuinit twd_timer_setup(void)
 {
+	struct clock_event_device *clk = __this_cpu_ptr(twd_evt);
 	int cpu = smp_processor_id();
 
 	/*
@@ -275,9 +278,9 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 	 */
 	if (per_cpu(percpu_setup_called, cpu)) {
 		__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
-		clockevents_register_device(__this_cpu_ptr(twd_evt));
+		clockevents_register_device(clk);
 		enable_percpu_irq(clk->irq, 0);
-		return 0;
+		return;
 	}
 	per_cpu(percpu_setup_called, cpu) = true;
 
@@ -302,20 +305,18 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 					0xf, 0xffffffff);
 	enable_percpu_irq(clk->irq, 0);
 
-	return 0;
+	return;
 }
 
 static int __cpuinit twd_timer_cpu_notify(struct notifier_block *self,
 					   unsigned long action, void *hcpu)
 {
-	struct clock_event_device *evt = this_cpu_ptr(twd_evt);
-
 	switch (action & ~CPU_TASKS_FROZEN) {
 	case CPU_STARTING:
-		twd_timer_setup(evt);
+		twd_timer_setup();
 		break;
 	case CPU_DYING:
-		twd_timer_stop(evt);
+		twd_timer_stop();
 		break;
 	}
 
@@ -348,8 +349,15 @@ static int __init twd_local_timer_common_register(struct device_node *np)
 
 	twd_get_clock(np);
 
-	/* Immediately configure the timer on the boot CPU */
-	twd_timer_setup(this_cpu_ptr(twd_evt));
+	/*
+	 * Immediately configure the timer on the boot CPU, unless we need
+	 * jiffies to be incrementing to calibrate the rate in which case
+	 * setup the timer in late_time_init.
+	 */
+	if (twd_timer_rate)
+		twd_timer_setup();
+	else
+		late_time_init = twd_timer_setup;
 
 	return 0;
 
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
maintainer
#20 lore raw

Re: [PATCH 03/10] ARM: smp_twd: Divorce smp_twd from local timer API

Quoted 8 lines · Stephen Boyd
Quoted 6 lines · Tony Lindgren
Quoted 2 lines · Stephen Boyd

Ok. qemu works for me before applying my patches. I've added this into the series before this patch to fix the boot issue.

OK thanks:

Quoted 8 lines

Actually, it's worse. From reading the code it looks like quite a few other machines register a clockevent and get jiffies going so they can calibrate the twd. I also see that Rob Herring's pull request to move smp_twd to CLKSRC_OF_DECLARE is going to conflict with any changes I make in the board files. I think we need to make the twd use the late_time_init callback if there is no clock rate and ignore the other patch I sent out a few hours ago. Basically, squash this into this 3/10 patch.

Looks reasonable to me to keep things working.

Regards,

Tony

Quoted 93 lines

----8<-----

arch/arm/kernel/smp_twd.c +19 -11
index a1185d3..c58918f 100644
@@ -90,8 +90,10 @@ static int twd_timer_ack(void)
 	return 0;
 }
 
-static void twd_timer_stop(struct clock_event_device *clk)
+static void twd_timer_stop(void)
 {
+	struct clock_event_device *clk = __this_cpu_ptr(twd_evt);
+
 	twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
 	disable_percpu_irq(clk->irq);
 }
@@ -265,8 +267,9 @@ static void twd_get_clock(struct device_node *np)
 /*
  * Setup the local clock events for a CPU.
  */
-static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
+static void __cpuinit twd_timer_setup(void)
 {
+	struct clock_event_device *clk = __this_cpu_ptr(twd_evt);
 	int cpu = smp_processor_id();
 
 	/*
@@ -275,9 +278,9 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 	 */
 	if (per_cpu(percpu_setup_called, cpu)) {
 		__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
-		clockevents_register_device(__this_cpu_ptr(twd_evt));
+		clockevents_register_device(clk);
 		enable_percpu_irq(clk->irq, 0);
-		return 0;
+		return;
 	}
 	per_cpu(percpu_setup_called, cpu) = true;
 
@@ -302,20 +305,18 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 					0xf, 0xffffffff);
 	enable_percpu_irq(clk->irq, 0);
 
-	return 0;
+	return;
 }
 
 static int __cpuinit twd_timer_cpu_notify(struct notifier_block *self,
 					   unsigned long action, void *hcpu)
 {
-	struct clock_event_device *evt = this_cpu_ptr(twd_evt);
-
 	switch (action & ~CPU_TASKS_FROZEN) {
 	case CPU_STARTING:
-		twd_timer_setup(evt);
+		twd_timer_setup();
 		break;
 	case CPU_DYING:
-		twd_timer_stop(evt);
+		twd_timer_stop();
 		break;
 	}
 
@@ -348,8 +349,15 @@ static int __init twd_local_timer_common_register(struct device_node *np)
 
 	twd_get_clock(np);
 
-	/* Immediately configure the timer on the boot CPU */
-	twd_timer_setup(this_cpu_ptr(twd_evt));
+	/*
+	 * Immediately configure the timer on the boot CPU, unless we need
+	 * jiffies to be incrementing to calibrate the rate in which case
+	 * setup the timer in late_time_init.
+	 */
+	if (twd_timer_rate)
+		twd_timer_setup();
+	else
+		late_time_init = twd_timer_setup;
 
 	return 0;
 
Signature · 9 lines
-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
#21 lore raw

PATCH v2 4/10 ARM: OMAP2+: Divorce from local timer API

In reply to Stephen Boyd

Now that the TWD doesn't rely on the local timer API, OMAP can stop selecting it in Kconfig and relying on the config option to decide if it should call smp_twd functions.

Cc Santosh Shilimkar <[email protected]>
Cc Tony Lindgren <[email protected]>
---
 arch/arm/mach-omap2/Kconfig | 1 -
 arch/arm/mach-omap2/timer.c | 7 -------
 2 files changed, 8 deletions(-)
arch/arm/mach-omap2/Kconfig +0 -1
index 49ac3df..6e1f871 100644
@@ -88,7 +88,6 @@ config ARCH_OMAP4
 	select CACHE_L2X0
 	select CPU_V7
 	select HAVE_SMP
-	select LOCAL_TIMERS if SMP
 	select OMAP_INTERCONNECT
 	select PL310_ERRATA_588369
 	select PL310_ERRATA_727915
arch/arm/mach-omap2/timer.c +0 -7
index 2bdd4cf..c00a8f8 100644
@@ -587,7 +587,6 @@ OMAP_SYS_GP_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, "ti,timer-alwon",
 #ifdef CONFIG_ARCH_OMAP4
 OMAP_SYS_32K_TIMER_INIT(4, 1, OMAP4_32K_SOURCE, "ti,timer-alwon",
 			2, OMAP4_MPU_SOURCE);
-#ifdef CONFIG_LOCAL_TIMERS
 static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29);
 void __init omap4_local_timer_init(void)
 {
@@ -606,12 +605,6 @@ void __init omap4_local_timer_init(void)
 			pr_err("twd_local_timer_register failed %d\n", err);
 	}
 }
-#else /* CONFIG_LOCAL_TIMERS */
-void __init omap4_local_timer_init(void)
-{
-	omap4_sync32k_timer_init();
-}
-#endif /* CONFIG_LOCAL_TIMERS */
 #endif /* CONFIG_ARCH_OMAP4 */
 
 #ifdef CONFIG_SOC_OMAP5
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
maintainer Acked-by on v2 4/10
#22 lore raw

Re: [PATCH 04/10] ARM: OMAP2+: Divorce from local timer API

Quoted 5 lines · Stephen Boyd

Now that the TWD doesn't rely on the local timer API, OMAP can stop selecting it in Kconfig and relying on the config option to decide if it should call smp_twd functions.

Cc Santosh Shilimkar <[email protected]>
Quoted 52 lines
---
 arch/arm/mach-omap2/Kconfig | 1 -
 arch/arm/mach-omap2/timer.c | 7 -------
 2 files changed, 8 deletions(-)
arch/arm/mach-omap2/Kconfig +0 -1
index 49ac3df..6e1f871 100644
@@ -88,7 +88,6 @@ config ARCH_OMAP4
 	select CACHE_L2X0
 	select CPU_V7
 	select HAVE_SMP
-	select LOCAL_TIMERS if SMP
 	select OMAP_INTERCONNECT
 	select PL310_ERRATA_588369
 	select PL310_ERRATA_727915
arch/arm/mach-omap2/timer.c +0 -7
index 2bdd4cf..c00a8f8 100644
@@ -587,7 +587,6 @@ OMAP_SYS_GP_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, "ti,timer-alwon",
 #ifdef CONFIG_ARCH_OMAP4
 OMAP_SYS_32K_TIMER_INIT(4, 1, OMAP4_32K_SOURCE, "ti,timer-alwon",
 			2, OMAP4_MPU_SOURCE);
-#ifdef CONFIG_LOCAL_TIMERS
 static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29);
 void __init omap4_local_timer_init(void)
 {
@@ -606,12 +605,6 @@ void __init omap4_local_timer_init(void)
 			pr_err("twd_local_timer_register failed %d\n", err);
 	}
 }
-#else /* CONFIG_LOCAL_TIMERS */
-void __init omap4_local_timer_init(void)
-{
-	omap4_sync32k_timer_init();
-}
-#endif /* CONFIG_LOCAL_TIMERS */
 #endif /* CONFIG_ARCH_OMAP4 */
 
 #ifdef CONFIG_SOC_OMAP5
Signature · 8 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
#24 lore raw

PATCH v2 5/10 ARM: EXYNOS4: Divorce mct from local timer API

In reply to Stephen Boyd

Separate the mct local timers from the local timer API. This will allow us to remove ARM local timer support in the near future and gets us closer to moving this driver to drivers/clocksource.

---
 arch/arm/mach-exynos/mct.c | 53 ++++++++++++++++++++++++++++++++--------------
 1 file changed, 37 insertions(+), 16 deletions(-)
arch/arm/mach-exynos/mct.c +37 -16
index c9d6650..5a9a73f 100644
@@ -16,13 +16,13 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/clockchips.h>
+#include <linux/cpu.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/percpu.h>
 #include <linux/of.h>
 
 #include <asm/arch_timer.h>
-#include <asm/localtimer.h>
 
 #include <plat/cpu.h>
 
@@ -42,7 +42,7 @@ static unsigned long clk_rate;
 static unsigned int mct_int_type;
 
 struct mct_clock_event_device {
-	struct clock_event_device *evt;
+	struct clock_event_device evt;
 	void __iomem *base;
 	char name[10];
 };
@@ -264,8 +264,6 @@ static void exynos4_clockevent_init(void)
 		setup_irq(EXYNOS4_IRQ_MCT_G0, &mct_comp_event_irq);
 }
 
-#ifdef CONFIG_LOCAL_TIMERS
-
 static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick);
 
 /* Clock event handling */
@@ -338,7 +336,7 @@ static inline void exynos4_tick_set_mode(enum clock_event_mode mode,
 
 static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
 {
-	struct clock_event_device *evt = mevt->evt;
+	struct clock_event_device *evt = &mevt->evt;
 
 	/*
 	 * This is for supporting oneshot mode.
@@ -360,7 +358,7 @@ static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
 static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
 {
 	struct mct_clock_event_device *mevt = dev_id;
-	struct clock_event_device *evt = mevt->evt;
+	struct clock_event_device *evt = &mevt->evt;
 
 	exynos4_mct_tick_clear(mevt);
 
@@ -388,7 +386,6 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt)
 	int mct_lx_irq;
 
 	mevt = this_cpu_ptr(&percpu_mct_tick);
-	mevt->evt = evt;
 
 	mevt->base = EXYNOS4_MCT_L_BASE(cpu);
 	sprintf(mevt->name, "mct_tick%d", cpu);
@@ -426,7 +423,7 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt)
 	return 0;
 }
 
-static void exynos4_local_timer_stop(struct clock_event_device *evt)
+static void __cpuinit exynos4_local_timer_stop(struct clock_event_device *evt)
 {
 	unsigned int cpu = smp_processor_id();
 	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
@@ -439,22 +436,38 @@ static void exynos4_local_timer_stop(struct clock_event_device *evt)
 		disable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER);
 }
 
-static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = {
-	.setup	= exynos4_local_timer_setup,
-	.stop	= exynos4_local_timer_stop,
+static int __cpuinit exynos4_mct_cpu_notify(struct notifier_block *self,
+					   unsigned long action, void *hcpu)
+{
+	struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
+	struct clock_event_device *evt = &mevt->evt;
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_STARTING:
+		exynos4_local_timer_setup(evt);
+		break;
+	case CPU_DYING:
+		exynos4_local_timer_stop(evt);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block exynos4_mct_cpu_nb __cpuinitdata = {
+	.notifier_call = exynos4_mct_cpu_notify,
 };
-#endif /* CONFIG_LOCAL_TIMERS */
 
 static void __init exynos4_timer_resources(void)
 {
+	int err;
+	struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
 	struct clk *mct_clk;
 	mct_clk = clk_get(NULL, "xtal");
 
 	clk_rate = clk_get_rate(mct_clk);
 
-#ifdef CONFIG_LOCAL_TIMERS
 	if (mct_int_type == MCT_INT_PPI) {
-		int err;
 
 		err = request_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER,
 					 exynos4_mct_tick_isr, "MCT",
@@ -463,8 +476,16 @@ static void __init exynos4_timer_resources(void)
 		     EXYNOS_IRQ_MCT_LOCALTIMER, err);
 	}
 
-	local_timer_register(&exynos4_mct_tick_ops);
-#endif /* CONFIG_LOCAL_TIMERS */
+	err = register_cpu_notifier(&exynos4_mct_cpu_nb);
+	if (err)
+		goto out_irq;
+
+	/* Immediately configure the timer on the boot CPU */
+	exynos4_local_timer_setup(&mevt->evt);
+	return;
+
+out_irq:
+	free_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER, &percpu_mct_tick);
 }
 
 void __init exynos4_timer_init(void)
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#25 lore raw

PATCH v2 6/10 ARM: PRIMA2: Divorce timer-marco from local timer API

In reply to Stephen Boyd

Separate the marco local timers from the local timer API. This will allow us to remove ARM local timer support in the near future and gets us closer to moving this driver to drivers/clocksource.

---
 arch/arm/mach-prima2/timer-marco.c | 98 ++++++++++++++++++++------------------
 1 file changed, 52 insertions(+), 46 deletions(-)
arch/arm/mach-prima2/timer-marco.c +52 -46
index f4eea2e..d54aac2 100644
@@ -10,6 +10,7 @@
 #include <linux/interrupt.h>
 #include <linux/clockchips.h>
 #include <linux/clocksource.h>
+#include <linux/cpu.h>
 #include <linux/bitops.h>
 #include <linux/irq.h>
 #include <linux/clk.h>
@@ -18,7 +19,6 @@
 #include <linux/of_irq.h>
 #include <linux/of_address.h>
 #include <asm/sched_clock.h>
-#include <asm/localtimer.h>
 #include <asm/mach/time.h>
 
 #include "common.h"
@@ -154,13 +154,7 @@ static void sirfsoc_clocksource_resume(struct clocksource *cs)
 		BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
 }
 
-static struct clock_event_device sirfsoc_clockevent = {
-	.name = "sirfsoc_clockevent",
-	.rating = 200,
-	.features = CLOCK_EVT_FEAT_ONESHOT,
-	.set_mode = sirfsoc_timer_set_mode,
-	.set_next_event = sirfsoc_timer_set_next_event,
-};
+static struct clock_event_device __percpu *sirfsoc_clockevent;
 
 static struct clocksource sirfsoc_clocksource = {
 	.name = "sirfsoc_clocksource",
@@ -176,11 +170,8 @@ static struct irqaction sirfsoc_timer_irq = {
 	.name = "sirfsoc_timer0",
 	.flags = IRQF_TIMER | IRQF_NOBALANCING,
 	.handler = sirfsoc_timer_interrupt,
-	.dev_id = &sirfsoc_clockevent,
 };
 
-#ifdef CONFIG_LOCAL_TIMERS
-
 static struct irqaction sirfsoc_timer1_irq = {
 	.name = "sirfsoc_timer1",
 	.flags = IRQF_TIMER | IRQF_NOBALANCING,
@@ -189,56 +180,75 @@ static struct irqaction sirfsoc_timer1_irq = {
 
 static int __cpuinit sirfsoc_local_timer_setup(struct clock_event_device *ce)
 {
-	/* Use existing clock_event for cpu 0 */
-	if (!smp_processor_id())
-		return 0;
+	int cpu = smp_processor_id();
+	struct irqaction *action;
+
+	if (cpu == 0)
+		action = &sirfsoc_timer_irq;
+	else
+		action = &sirfsoc_timer1_irq;
 
-	ce->irq = sirfsoc_timer1_irq.irq;
+	ce->irq = action->irq;
 	ce->name = "local_timer";
-	ce->features = sirfsoc_clockevent.features;
-	ce->rating = sirfsoc_clockevent.rating;
+	ce->features = CLOCK_EVT_FEAT_ONESHOT;
+	ce->rating = 200;
 	ce->set_mode = sirfsoc_timer_set_mode;
 	ce->set_next_event = sirfsoc_timer_set_next_event;
-	ce->shift = sirfsoc_clockevent.shift;
-	ce->mult = sirfsoc_clockevent.mult;
-	ce->max_delta_ns = sirfsoc_clockevent.max_delta_ns;
-	ce->min_delta_ns = sirfsoc_clockevent.min_delta_ns;
+	clockevents_calc_mult_shift(ce, CLOCK_TICK_RATE, 60);
+	ce->max_delta_ns = clockevent_delta2ns(-2, ce);
+	ce->min_delta_ns = clockevent_delta2ns(2, ce);
+	ce->cpumask = cpumask_of(cpu);
 
-	sirfsoc_timer1_irq.dev_id = ce;
-	BUG_ON(setup_irq(ce->irq, &sirfsoc_timer1_irq));
-	irq_set_affinity(sirfsoc_timer1_irq.irq, cpumask_of(1));
+	action->dev_id = ce;
+	BUG_ON(setup_irq(ce->irq, action));
+	irq_set_affinity(action->irq, cpumask_of(cpu));
 
 	clockevents_register_device(ce);
 	return 0;
 }
 
-static void sirfsoc_local_timer_stop(struct clock_event_device *ce)
+static void __cpuinit sirfsoc_local_timer_stop(struct clock_event_device *ce)
 {
+	int cpu = smp_processor_id();
+
 	sirfsoc_timer_count_disable(1);
 
-	remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq);
+	if (cpu == 0)
+		remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq);
+	else
+		remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq);
+}
+
+static int __cpuinit sirfsoc_cpu_notify(struct notifier_block *self,
+					   unsigned long action, void *hcpu)
+{
+	struct clock_event_device *evt = this_cpu_ptr(sirfsoc_clockevent);
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_STARTING:
+		sirfsoc_local_timer_setup(evt);
+		break;
+	case CPU_DYING:
+		sirfsoc_local_timer_stop(evt);
+		break;
+	}
+
+	return NOTIFY_OK;
 }
 
-static struct local_timer_ops sirfsoc_local_timer_ops __cpuinitdata = {
-	.setup	= sirfsoc_local_timer_setup,
-	.stop	= sirfsoc_local_timer_stop,
+static struct notifier_block sirfsoc_cpu_nb __cpuinitdata = {
+	.notifier_call = sirfsoc_cpu_notify,
 };
-#endif /* CONFIG_LOCAL_TIMERS */
 
 static void __init sirfsoc_clockevent_init(void)
 {
-	clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60);
-
-	sirfsoc_clockevent.max_delta_ns =
-		clockevent_delta2ns(-2, &sirfsoc_clockevent);
-	sirfsoc_clockevent.min_delta_ns =
-		clockevent_delta2ns(2, &sirfsoc_clockevent);
-
-	sirfsoc_clockevent.cpumask = cpumask_of(0);
-	clockevents_register_device(&sirfsoc_clockevent);
-#ifdef CONFIG_LOCAL_TIMERS
-	local_timer_register(&sirfsoc_local_timer_ops);
-#endif
+	sirfsoc_clockevent = alloc_percpu(struct clock_event_device);
+	BUG_ON(!sirfsoc_clockevent);
+
+	BUG_ON(register_cpu_notifier(&sirfsoc_cpu_nb));
+
+	/* Immediately configure the timer on the boot CPU */
+	sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent));
 }
 
 /* initialize the kernel jiffy timer source */
@@ -281,8 +291,6 @@ void __init sirfsoc_marco_timer_init(void)
 
 	BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE));
 
-	BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq));
-
 	sirfsoc_clockevent_init();
 }
 
@@ -306,11 +314,9 @@ static void __init sirfsoc_of_timer_map(void)
 	if (!sirfsoc_timer_irq.irq)
 		panic("No irq passed for timer0 via DT\n");
 
-#ifdef CONFIG_LOCAL_TIMERS
 	sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1);
 	if (!sirfsoc_timer1_irq.irq)
 		panic("No irq passed for timer1 via DT\n");
-#endif
 
 	of_node_put(np);
 }
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#26 lore raw

PATCH v2 7/10 ARM: msm: Divorce msm_timer from local timer API

In reply to Stephen Boyd

Separate the msm_timer from the local timer API. This will allow us to remove ARM local timer support in the near future and gets us closer to moving this driver to drivers/clocksource.

---
 arch/arm/mach-msm/timer.c | 125 +++++++++++++++++++++++++---------------------
 1 file changed, 67 insertions(+), 58 deletions(-)
arch/arm/mach-msm/timer.c +67 -58
index 2969027..4675c5e 100644
@@ -16,6 +16,7 @@
 
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
+#include <linux/cpu.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
@@ -25,7 +26,6 @@
 #include <linux/of_irq.h>
 
 #include <asm/mach/time.h>
-#include <asm/localtimer.h>
 #include <asm/sched_clock.h>
 
 #include "common.h"
@@ -46,7 +46,7 @@ static void __iomem *event_base;
 
 static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
 {
-	struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+	struct clock_event_device *evt = dev_id;
 	/* Stop the timer tick */
 	if (evt->mode == CLOCK_EVT_MODE_ONESHOT) {
 		u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE);
@@ -90,18 +90,7 @@ static void msm_timer_set_mode(enum clock_event_mode mode,
 	writel_relaxed(ctrl, event_base + TIMER_ENABLE);
 }
 
-static struct clock_event_device msm_clockevent = {
-	.name		= "gp_timer",
-	.features	= CLOCK_EVT_FEAT_ONESHOT,
-	.rating		= 200,
-	.set_next_event	= msm_timer_set_next_event,
-	.set_mode	= msm_timer_set_mode,
-};
-
-static union {
-	struct clock_event_device *evt;
-	struct clock_event_device * __percpu *percpu_evt;
-} msm_evt;
+static struct clock_event_device __percpu *msm_evt;
 
 static void __iomem *source_base;
 
@@ -127,40 +116,66 @@ static struct clocksource msm_clocksource = {
 	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-#ifdef CONFIG_LOCAL_TIMERS
+static int msm_timer_irq;
+static int msm_timer_has_ppi;
+
 static int __cpuinit msm_local_timer_setup(struct clock_event_device *evt)
 {
-	/* Use existing clock_event for cpu 0 */
-	if (!smp_processor_id())
-		return 0;
+	int cpu = smp_processor_id();
+	int err;
 
 	writel_relaxed(0, event_base + TIMER_ENABLE);
 	writel_relaxed(0, event_base + TIMER_CLEAR);
 	writel_relaxed(~0, event_base + TIMER_MATCH_VAL);
-	evt->irq = msm_clockevent.irq;
+	evt->irq = msm_timer_irq;
 	evt->name = "local_timer";
-	evt->features = msm_clockevent.features;
-	evt->rating = msm_clockevent.rating;
+	evt->features = CLOCK_EVT_FEAT_ONESHOT;
+	evt->rating = 200;
 	evt->set_mode = msm_timer_set_mode;
 	evt->set_next_event = msm_timer_set_next_event;
+	evt->cpumask = cpumask_of(cpu);
+
+	clockevents_config_and_register(evt, GPT_HZ, 4, 0xffffffff);
+
+	if (msm_timer_has_ppi) {
+		enable_percpu_irq(evt->irq, IRQ_TYPE_EDGE_RISING);
+	} else {
+		err = request_irq(evt->irq, msm_timer_interrupt,
+				IRQF_TIMER | IRQF_NOBALANCING |
+				IRQF_TRIGGER_RISING, "gp_timer", evt);
+		if (err)
+			pr_err("request_irq failed\n");
+	}
 
-	*__this_cpu_ptr(msm_evt.percpu_evt) = evt;
-	clockevents_config_and_register(evt, GPT_HZ, 4, 0xf0000000);
-	enable_percpu_irq(evt->irq, IRQ_TYPE_EDGE_RISING);
 	return 0;
 }
 
-static void msm_local_timer_stop(struct clock_event_device *evt)
+static void __cpuinit msm_local_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 msm_local_timer_ops __cpuinitdata = {
-	.setup	= msm_local_timer_setup,
-	.stop	= msm_local_timer_stop,
+static int __cpuinit msm_timer_cpu_notify(struct notifier_block *self,
+					   unsigned long action, void *hcpu)
+{
+	struct clock_event_device *evt = this_cpu_ptr(msm_evt);
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_STARTING:
+		msm_local_timer_setup(evt);
+		break;
+	case CPU_DYING:
+		msm_local_timer_stop(evt);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block msm_timer_cpu_nb __cpuinitdata = {
+	.notifier_call = msm_timer_cpu_notify,
 };
-#endif /* CONFIG_LOCAL_TIMERS */
 
 static notrace u32 msm_sched_clock_read(void)
 {
@@ -170,41 +185,35 @@ static notrace u32 msm_sched_clock_read(void)
 static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq,
 				  bool percpu)
 {
-	struct clock_event_device *ce = &msm_clockevent;
 	struct clocksource *cs = &msm_clocksource;
-	int res;
+	int res = 0;
 
-	writel_relaxed(0, event_base + TIMER_ENABLE);
-	writel_relaxed(0, event_base + TIMER_CLEAR);
-	writel_relaxed(~0, event_base + TIMER_MATCH_VAL);
-	ce->cpumask = cpumask_of(0);
-	ce->irq = irq;
-
-	clockevents_config_and_register(ce, GPT_HZ, 4, 0xffffffff);
-	if (percpu) {
-		msm_evt.percpu_evt = alloc_percpu(struct clock_event_device *);
-		if (!msm_evt.percpu_evt) {
-			pr_err("memory allocation failed for %s\n", ce->name);
+	msm_timer_irq = irq;
+	msm_timer_has_ppi = percpu;
+
+	msm_evt = alloc_percpu(struct clock_event_device);
+	if (!msm_evt) {
+		pr_err("memory allocation failed for clockevents\n");
+		goto err;
+	}
+
+	if (percpu)
+		res = request_percpu_irq(irq, msm_timer_interrupt,
+					 "gp_timer", msm_evt);
+
+	if (res) {
+		pr_err("request_percpu_irq failed\n");
+	} else {
+		res = register_cpu_notifier(&msm_timer_cpu_nb);
+		if (res) {
+			free_percpu_irq(irq, msm_evt);
 			goto err;
 		}
-		*__this_cpu_ptr(msm_evt.percpu_evt) = ce;
-		res = request_percpu_irq(ce->irq, msm_timer_interrupt,
-					 ce->name, msm_evt.percpu_evt);
-		if (!res) {
-			enable_percpu_irq(ce->irq, IRQ_TYPE_EDGE_RISING);
-#ifdef CONFIG_LOCAL_TIMERS
-			local_timer_register(&msm_local_timer_ops);
-#endif
-		}
-	} else {
-		msm_evt.evt = ce;
-		res = request_irq(ce->irq, msm_timer_interrupt,
-				  IRQF_TIMER | IRQF_NOBALANCING |
-				  IRQF_TRIGGER_RISING, ce->name, &msm_evt.evt);
+
+		/* Immediately configure the timer on the boot CPU */
+		msm_local_timer_setup(this_cpu_ptr(msm_evt));
 	}
 
-	if (res)
-		pr_err("request_irq failed for %s\n", ce->name);
 err:
 	writel_relaxed(TIMER_ENABLE_EN, source_base + TIMER_ENABLE);
 	res = clocksource_register_hz(cs, dgt_hz);
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#27 lore raw

PATCH v2 8/10 clocksource: time-armada-370-xp: Fix sparse warning

In reply to Stephen Boyd

drivers/clocksource/time-armada-370-xp.c:217:13: warning: symbol 'armada_370_xp_timer_init' was not declared. Should it be static?

Also remove the __init marking in the prototype as it's unnecessary and drop the init.h file.

Cc Gregory CLEMENT <[email protected]>
---
 drivers/clocksource/time-armada-370-xp.c | 3 ++-
 include/linux/time-armada-370-xp.h       | 4 +---
 2 files changed, 3 insertions(+), 4 deletions(-)
drivers/clocksource/time-armada-370-xp.c +2 -1
index 47a6730..efe4aef 100644
@@ -27,10 +27,11 @@
 #include <linux/of_address.h>
 #include <linux/irq.h>
 #include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/time-armada-370-xp.h>
 
 #include <asm/sched_clock.h>
 #include <asm/localtimer.h>
-#include <linux/percpu.h>
 /*
  * Timer block registers.
  */
include/linux/time-armada-370-xp.h +1 -3
index dfdfdc0..6fb0856 100644
@@ -11,8 +11,6 @@
 #ifndef __TIME_ARMADA_370_XPPRCMU_H
 #define __TIME_ARMADA_370_XPPRCMU_H
 
-#include <linux/init.h>
-
-void __init armada_370_xp_timer_init(void);
+void armada_370_xp_timer_init(void);
 
 #endif
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#28 lore raw

PATCH v2 9/10 clocksource: time-armada-370-xp: Divorce from local timer API

In reply to Stephen Boyd

Separate the armada 370xp local timers from the local timer API. This will allow us to remove ARM local timer support in the near future and makes this driver multi-architecture friendly.

Cc Gregory CLEMENT <[email protected]>
---
 drivers/clocksource/time-armada-370-xp.c | 85 ++++++++++++++------------------
 1 file changed, 38 insertions(+), 47 deletions(-)
drivers/clocksource/time-armada-370-xp.c +38 -47
index efe4aef..ee2e50c5 100644
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/clk.h>
+#include <linux/cpu.h>
 #include <linux/timer.h>
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
@@ -31,7 +32,6 @@
 #include <linux/time-armada-370-xp.h>
 
 #include <asm/sched_clock.h>
-#include <asm/localtimer.h>
 /*
  * Timer block registers.
  */
@@ -70,7 +70,7 @@ static bool timer25Mhz = true;
  */
 static u32 ticks_per_jiffy;
 
-static struct clock_event_device __percpu **percpu_armada_370_xp_evt;
+static struct clock_event_device __percpu *armada_370_xp_evt;
 
 static u32 notrace armada_370_xp_read_sched_clock(void)
 {
@@ -143,14 +143,7 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode,
 	}
 }
 
-static struct clock_event_device armada_370_xp_clkevt = {
-	.name		= "armada_370_xp_per_cpu_tick",
-	.features	= CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
-	.shift		= 32,
-	.rating		= 300,
-	.set_next_event	= armada_370_xp_clkevt_next_event,
-	.set_mode	= armada_370_xp_clkevt_mode,
-};
+static int armada_370_xp_clkevt_irq;
 
 static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id)
 {
@@ -173,42 +166,53 @@ 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->name		= "armada_370_xp_per_cpu_tick",
+	evt->features		= CLOCK_EVT_FEAT_ONESHOT |
+				  CLOCK_EVT_FEAT_PERIODIC;
+	evt->shift		= 32,
+	evt->rating		= 300,
 	evt->set_next_event	= armada_370_xp_clkevt_next_event,
 	evt->set_mode		= armada_370_xp_clkevt_mode,
+	evt->irq		= armada_370_xp_clkevt_irq;
 	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)
+static void __cpuinit 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,
+static int __cpuinit armada_370_xp_timer_cpu_notify(struct notifier_block *self,
+					   unsigned long action, void *hcpu)
+{
+	struct clock_event_device *evt = this_cpu_ptr(armada_370_xp_evt);
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_STARTING:
+		armada_370_xp_timer_setup(evt);
+		break;
+	case CPU_DYING:
+		armada_370_xp_timer_stop(evt);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block armada_370_xp_timer_cpu_nb __cpuinitdata = {
+	.notifier_call = armada_370_xp_timer_cpu_notify,
 };
 
 void __init armada_370_xp_timer_init(void)
@@ -224,9 +228,6 @@ void __init armada_370_xp_timer_init(void)
 
 	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,
 		       timer_base + TIMER_CTRL_OFF);
@@ -236,9 +237,6 @@ 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),
@@ -252,7 +250,7 @@ void __init armada_370_xp_timer_init(void)
 	 * 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);
+	armada_370_xp_clkevt_irq = irq_of_parse_and_map(np, 4);
 
 	ticks_per_jiffy = (timer_clk + HZ / 2) / HZ;
 
@@ -277,26 +275,19 @@ void __init armada_370_xp_timer_init(void)
 			      "armada_370_xp_clocksource",
 			      timer_clk, 300, 32, clocksource_mmio_readl_down);
 
-	/* 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);
+	register_cpu_notifier(&armada_370_xp_timer_cpu_nb);
 
-	percpu_armada_370_xp_evt = alloc_percpu(struct clock_event_device *);
+	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,
+	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
-	}
+				"armada_370_xp_per_cpu_tick",
+				armada_370_xp_evt);
+	/* Immediately configure the timer on the boot CPU */
+	if (!res)
+		armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
 }
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#29 lore raw

PATCH v2 10/10 ARM: smp: Remove local timer API

In reply to Stephen Boyd

There are no more users of this API, remove it.

---
 arch/arm/Kconfig                  | 10 ------
 arch/arm/include/asm/localtimer.h | 34 -------------------
 arch/arm/kernel/smp.c             | 69 ---------------------------------------
 3 files changed, 113 deletions(-)
 delete mode 100644 arch/arm/include/asm/localtimer.h
arch/arm/Kconfig +0 -10
index 5ad2ccf..f1a4c57 100644
@@ -1647,16 +1647,6 @@ config ARM_PSCI
 	  0022A ("Power State Coordination Interface System Software on
 	  ARM processors").
 
-config LOCAL_TIMERS
-	bool "Use local timer interrupts"
-	depends on SMP
-	default y
-	help
-	  Enable support for local timers on SMP platforms, rather then the
-	  legacy IPI broadcast method.  Local timers allows the system
-	  accounting to be spread across the timer interval, preventing a
-	  "thundering herd" at every timer tick.
-
 config ARCH_NR_GPIO
 	int
 	default 1024 if ARCH_SHMOBILE || ARCH_TEGRA
arch/arm/include/asm/localtimer.h deleted +0 -34
deleted file mode 100644
index f77ffc1..0000000
@@ -1,34 +0,0 @@
-/*
- *  arch/arm/include/asm/localtimer.h
- *
- *  Copyright (C) 2004-2005 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.
- */
-#ifndef __ASM_ARM_LOCALTIMER_H
-#define __ASM_ARM_LOCALTIMER_H
-
-#include <linux/errno.h>
-
-struct clock_event_device;
-
-struct local_timer_ops {
-	int  (*setup)(struct clock_event_device *);
-	void (*stop)(struct clock_event_device *);
-};
-
-#ifdef CONFIG_LOCAL_TIMERS
-/*
- * Register a local timer driver
- */
-int local_timer_register(struct local_timer_ops *);
-#else
-static inline int local_timer_register(struct local_timer_ops *ops)
-{
-	return -ENXIO;
-}
-#endif
-
-#endif
arch/arm/kernel/smp.c +0 -69

117 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation