clocksource: exynos_mct: allow mct to read counter from coprocessor
Subsystems (2)
RFC PATCH 1/3 clocksource: exynos_mct: allow mct to read counter from coprocessor
It was discovered that 64-bit mmio MCT counter holds the same value as ARM arch timer 64-bit physical counter. Even more: arch timer and MCT are same underlying hardware timer.
Patch adds code to MCT to allow it to read 64-bit counter from coprocessor cp15 registers since it's way more faster than reading the same counter from MCT mmio region.
That functionality triggers only if special property use-cp15-phys-counter is present in device tree, only on 32-bit ARMv7 systems and only if HYP mode is available.
Idea of rewriting accessors is taken from arm_arch_timer.c.
By default MCT will read counter from mmio since it's guaranteed to work.
--- drivers/clocksource/exynos_mct.c | 77 ++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 10 deletions(-)
drivers/clocksource/exynos_mct.c +67 -10
@@ -26,6 +26,9 @@#include <linux/clocksource.h> #include <linux/sched_clock.h> +#include <asm/arch_timer.h> /* for cp15 physical arch timer counter */ +#include <asm/virt.h> /* for checking HYP mode */ +#define EXYNOS4_MCTREG (x) (x)#define EXYNOS4_MCT_G_CNT_L EXYNOS4_MCTREG(0x100)#define EXYNOS4_MCT_G_CNT_U EXYNOS4_MCTREG(0x104)
@@ -82,6 +85,17 @@ static unsigned long clk_rate;static unsigned int mct_int_type;static int mct_irqs[MCT_NR_IRQS ]; +static u32 notrace __exynos4_read_count_32(void); +static u64 __exynos4_read_count_64 (void ); + +/* +* Default to __exynos4_read_count_{32,64} functions that reads counter from +* MCT mmio region and this method is guaranteed +* to exist (if MCT was successfully initialized). +*/ +u32 (*exynos4_read_count_32)(void) = __exynos4_read_count_32; +u64 (*exynos4_read_count_64)(void) = __exynos4_read_count_64; +struct mct_clock_event_device {struct clock_event_device evt;unsigned long base;
@@ -163,16 +177,16 @@ static void exynos4_mct_frc_start(void) }/** -* exynos4_read_count_64 - Read all 64-bits of the global counter +* __exynos4_read_count_64 - Read all 64-bits of the global counter * -* This will read all 64-bits of the global counter taking care to make sure -* that the upper and lower half match. Note that reading the MCT can be quite -* slow (hundreds of nanoseconds) so you should use the 32-bit (lower half -* only) version when possible. +* This will read all 64-bits of the global counter from MCT mmio region +* taking care to make sure that the upper and lower half match. +* Note that reading the MCT can be quite slow (hundreds of nanoseconds) +* so you should use the 32-bit (lower half only) version when possible. * * Returns the number of cycles in the global counter. */ -static u64 exynos4_read_count_64 (void ) +static u64 __exynos4_read_count_64 (void ) {unsigned int lo, hi;u32 hi2 =readl_relaxed (reg_base +EXYNOS4_MCT_G_CNT_U );
@@ -187,18 +201,45 @@ static u64 exynos4_read_count_64(void) }/** -* exynos4_read_count_32 - Read the lower 32-bits of the global counter +* __exynos4_read_cp15_count_64 - Read all 64-bits of the global counter +* from coprocessor regisers. * -* This will read just the lower 32-bits of the global counter. This is marked -* as notrace so it can be used by the scheduler clock. +* Note that reading here is faster than reading from MCT mmio region. +* +* Returns the number of cycles in the global counter. +*/ +static u64 __exynos4_read_cp15_count_64 (void ) +{ +return arch_counter_get_cntpct (); +} + +/** +* __exynos4_read_count_32 - Read the lower 32-bits of the global counter +* +* This will read just the lower 32-bits of the global counter from +* MCT mmio region. +* This is marked as notrace so it can be used by the scheduler clock. * * Returns the number of cycles in the global counter (lower 32 bits). */ -static u32 notrace exynos4_read_count_32(void) +static u32 notrace __exynos4_read_count_32(void) {return readl_relaxed (reg_base +EXYNOS4_MCT_G_CNT_L ); } +/** +* __exynos4_read_cp15_count_32 - Read the lower 32-bits of the global counter +* +* This will read global counter from coprocessor regisers. +* This is marked as notrace so it can be used by the scheduler clock. +* +* Returns the number of cycles in the global counter (lower 32 bits). +*/ +static u32 notrace __exynos4_read_cp15_count_32(void) +{ +return arch_counter_get_cntpct (); +} +static cycle_t exynos4_frc_read (struct clocksource *cs) {return exynos4_read_count_32 ();
@@ -599,6 +640,22 @@ static void __init mct_init_dt(struct device_node *np, unsigned int int_type)for (i =MCT_L0_IRQ ; i < nr_irqs; i++) mct_irqs[i] =irq_of_parse_and_map (np, i); +/* +* If use-cp15-phys-counter property is present in device tree +* then use CP15 ARM arch timer 64-bit physical counter +* to speedup reading since it keeps the same value like +* 64-bit counter in MCT mmio region. +* If HYP mode is available we can rely on physical +* timer counter to be accessible from PL1. +*/ +if (IS_ENABLED (CONFIG_ARM ) &&is_hyp_mode_available () && +of_property_read_bool (np,"use-cp15-phys-counter" )) { + +/* point MCT functions to read counter from coprocessor */ + exynos4_read_count_32 = __exynos4_read_cp15_count_32; + exynos4_read_count_64 = __exynos4_read_cp15_count_64; + } +exynos4_timer_resources (np,of_iomap (np,0 ));exynos4_clocksource_init ();exynos4_clockevent_init ();
Signature · 1 line
2.1.4
RFC PATCH 1/3 clocksource: exynos_mct: allow mct to read counter from coprocessor
Quoted 5 lines · Alexey Klimov
It was discovered that 64-bit mmio MCT counter holds the same value as ARM arch timer 64-bit physical counter. Even more: arch timer and MCT are same underlying hardware timer.
Quoted 8 lines
Patch adds code to MCT to allow it to read 64-bit counter from coprocessor cp15 registers since it's way more faster than reading the same counter from MCT mmio region.
That functionality triggers only if special property use-cp15-phys-counter is present in device tree, only on 32-bit ARMv7 systems and only if HYP mode is available.
Hi,
It would be nice to put here also the measurements from cover letter. This would be the justification for the commit.
I guess same optimization could be done for ARMv8 Exynos SoCs?
Quoted 29 lines
Idea of rewriting accessors is taken from
arm_arch_timer.c.By default MCT will read counter from mmio since it's guaranteed to work.
Signed-off-by Alexey Klimov <[email protected]>--- drivers/clocksource/exynos_mct.c | 77 ++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 10 deletions(-)drivers/clocksource/exynos_mct.c +3
-0@@ -26,6 +26,9 @@#include <linux/clocksource.h> #include <linux/sched_clock.h> +#include <asm/arch_timer.h> /* for cp15 physical arch timer counter */ +#include <asm/virt.h> /* for checking HYP mode */ +#define EXYNOS4_MCTREG (x) (x)#define EXYNOS4_MCT_G_CNT_L EXYNOS4_MCTREG(0x100)#define EXYNOS4_MCT_G_CNT_U EXYNOS4_MCTREG(0x104)@@ -82,6 +85,17 @@ static unsigned long clk_rate;static unsigned int mct_int_type;static int mct_irqs[MCT_NR_IRQS ];
drivers/clocksource/exynos_mct.c static unsigned long clk_rate; · line 97
Quoted 10 lines
drivers/clocksource/exynos_mct.c +10
-0+static u32 notrace __exynos4_read_count_32(void); +static u64 __exynos4_read_count_64 (void ); + +/* +* Default to __exynos4_read_count_{32,64} functions that reads counter from +* MCT mmio region and this method is guaranteed +* to exist (if MCT was successfully initialized). +*/ +u32 (*exynos4_read_count_32)(void) = __exynos4_read_count_32; +u64 (*exynos4_read_count_64)(void) = __exynos4_read_count_64;
I think these could be static.
Quoted 55 lines
drivers/clocksource/exynos_mct.c +24
-9+struct mct_clock_event_device {struct clock_event_device evt;unsigned long base;@@ -163,16 +177,16 @@ static void exynos4_mct_frc_start(void) }/** -* exynos4_read_count_64 - Read all 64-bits of the global counter +* __exynos4_read_count_64 - Read all 64-bits of the global counter * -* This will read all 64-bits of the global counter taking care to make sure -* that the upper and lower half match. Note that reading the MCT can be quite -* slow (hundreds of nanoseconds) so you should use the 32-bit (lower half -* only) version when possible. +* This will read all 64-bits of the global counter from MCT mmio region +* taking care to make sure that the upper and lower half match. +* Note that reading the MCT can be quite slow (hundreds of nanoseconds) +* so you should use the 32-bit (lower half only) version when possible. * * Returns the number of cycles in the global counter. */ -static u64 exynos4_read_count_64 (void ) +static u64 __exynos4_read_count_64 (void ) {unsigned int lo, hi;u32 hi2 =readl_relaxed (reg_base +EXYNOS4_MCT_G_CNT_U );@@ -187,18 +201,45 @@ static u64 exynos4_read_count_64(void) }/** -* exynos4_read_count_32 - Read the lower 32-bits of the global counter +* __exynos4_read_cp15_count_64 - Read all 64-bits of the global counter +* from coprocessor regisers. * -* This will read just the lower 32-bits of the global counter. This is marked -* as notrace so it can be used by the scheduler clock. +* Note that reading here is faster than reading from MCT mmio region. +* +* Returns the number of cycles in the global counter. +*/ +static u64 __exynos4_read_cp15_count_64 (void ) +{ +return arch_counter_get_cntpct (); +} + +/** +* __exynos4_read_count_32 - Read the lower 32-bits of the global counter +* +* This will read just the lower 32-bits of the global counter from +* MCT mmio region. +* This is marked as notrace so it can be used by the scheduler clock. * * Returns the number of cycles in the global counter (lower 32 bits). */
drivers/clocksource/exynos_mct.c static u64 exynos4_read_count_64(void) · line 233
Quoted 10 lines
drivers/clocksource/exynos_mct.c +5
-1-static u32 notrace exynos4_read_count_32(void) +static u32 notrace __exynos4_read_count_32(void) {return readl_relaxed (reg_base +EXYNOS4_MCT_G_CNT_L ); } +/** +* __exynos4_read_cp15_count_32 - Read the lower 32-bits of the global counter +* +* This will read global counter from coprocessor regisers.
s/regisers/registers/
Quoted 16 lines
drivers/clocksource/exynos_mct.c +9
-0+* This is marked as notrace so it can be used by the scheduler clock. +* +* Returns the number of cycles in the global counter (lower 32 bits). +*/ +static u32 notrace __exynos4_read_cp15_count_32(void) +{ +return arch_counter_get_cntpct (); +} +static cycle_t exynos4_frc_read (struct clocksource *cs) {return exynos4_read_count_32 ();@@ -599,6 +640,22 @@ static void __init mct_init_dt(struct device_node *np, unsigned int int_type)for (i =MCT_L0_IRQ ; i < nr_irqs; i++) mct_irqs[i] =irq_of_parse_and_map (np, i);
drivers/clocksource/exynos_mct.c static void __init mct_init_dt(struct device_node *np, unsigned int int_type) · line 652
Quoted 10 lines
drivers/clocksource/exynos_mct.c +10
-0+/* +* If use-cp15-phys-counter property is present in device tree +* then use CP15 ARM arch timer 64-bit physical counter +* to speedup reading since it keeps the same value like +* 64-bit counter in MCT mmio region. +* If HYP mode is available we can rely on physical +* timer counter to be accessible from PL1. +*/ +if (IS_ENABLED (CONFIG_ARM ) &&is_hyp_mode_available () && +of_property_read_bool (np,"use-cp15-phys-counter" )) {
This looks like a property specific to Exynos. Add a "samsung," prefix.
Best regards,
Krzysztof
Quoted 10 lines
drivers/clocksource/exynos_mct.c +6
-0+ +/* point MCT functions to read counter from coprocessor */ + exynos4_read_count_32 = __exynos4_read_cp15_count_32; + exynos4_read_count_64 = __exynos4_read_cp15_count_64; + } +exynos4_timer_resources (np,of_iomap (np,0 ));exynos4_clocksource_init ();exynos4_clockevent_init ();
RFC PATCH 1/3 clocksource: exynos_mct: allow mct to read counter from coprocessor
Quoted 15 lines · Krzysztof Kozlowski
Quoted 5 lines · Alexey Klimov
It was discovered that 64-bit mmio MCT counter holds the same value as ARM arch timer 64-bit physical counter. Even more: arch timer and MCT are same underlying hardware timer.
Quoted 8 lines
Patch adds code to MCT to allow it to read 64-bit counter from coprocessor cp15 registers since it's way more faster than reading the same counter from MCT mmio region.
That functionality triggers only if special property use-cp15-phys-counter is present in device tree, only on 32-bit ARMv7 systems and only if HYP mode is available.
Quoted 4 lines
Hi,
It would be nice to put here also the measurements from cover letter. This would be the justification for the commit.
Ok, I will add them. I will try to find time to perform more precise measurements.
Quoted 1 line
I guess same optimization could be done for ARMv8 Exynos SoCs?
I honestly don't know, don't have access to ARMv8 Exynos SoCs. If i remember correctly there are no public-available 64-bit Exynos boards yet. Exynos7420 is on the way to be released.
The main concern is that MCT probably not enabled for arm64 and some cleanup/re-factoring is required for cycles_t variable. See message in exynos4_read_current_timer() in MCT.
Also ARMv8 requires arm generic timer to be available and fully operational. So for me it looks like current upstream kernel will work on top of arm arch timer.
Quoted 28 lines
Quoted 28 lines
Idea of rewriting accessors is taken from
arm_arch_timer.c.By default MCT will read counter from mmio since it's guaranteed to work.
Signed-off-by Alexey Klimov <[email protected]>--- drivers/clocksource/exynos_mct.c | 77 ++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 10 deletions(-)drivers/clocksource/exynos_mct.c +3
-0@@ -26,6 +26,9 @@#include <linux/clocksource.h> #include <linux/sched_clock.h> +#include <asm/arch_timer.h> /* for cp15 physical arch timer counter */ +#include <asm/virt.h> /* for checking HYP mode */ +#define EXYNOS4_MCTREG (x) (x)#define EXYNOS4_MCT_G_CNT_L EXYNOS4_MCTREG(0x100)#define EXYNOS4_MCT_G_CNT_U EXYNOS4_MCTREG(0x104)@@ -82,6 +85,17 @@ static unsigned long clk_rate;static unsigned int mct_int_type;static int mct_irqs[MCT_NR_IRQS ];
Quoted 12 lines
drivers/clocksource/exynos_mct.c static unsigned long clk_rate; · line 97
Quoted 10 lines
drivers/clocksource/exynos_mct.c +10
-0+static u32 notrace __exynos4_read_count_32(void); +static u64 __exynos4_read_count_64 (void ); + +/* +* Default to __exynos4_read_count_{32,64} functions that reads counter from +* MCT mmio region and this method is guaranteed +* to exist (if MCT was successfully initialized). +*/ +u32 (*exynos4_read_count_32)(void) = __exynos4_read_count_32; +u64 (*exynos4_read_count_64)(void) = __exynos4_read_count_64;I think these could be static.
Yeah. Will fix it right away.
Quoted 61 lines
Quoted 61 lines
drivers/clocksource/exynos_mct.c +25
-10+struct mct_clock_event_device {struct clock_event_device evt;unsigned long base;@@ -163,16 +177,16 @@ static void exynos4_mct_frc_start(void) }/** -* exynos4_read_count_64 - Read all 64-bits of the global counter +* __exynos4_read_count_64 - Read all 64-bits of the global counter * -* This will read all 64-bits of the global counter taking care to make sure -* that the upper and lower half match. Note that reading the MCT can be quite -* slow (hundreds of nanoseconds) so you should use the 32-bit (lower half -* only) version when possible. +* This will read all 64-bits of the global counter from MCT mmio region +* taking care to make sure that the upper and lower half match. +* Note that reading the MCT can be quite slow (hundreds of nanoseconds) +* so you should use the 32-bit (lower half only) version when possible. * * Returns the number of cycles in the global counter. */ -static u64 exynos4_read_count_64 (void ) +static u64 __exynos4_read_count_64 (void ) {unsigned int lo, hi;u32 hi2 =readl_relaxed (reg_base +EXYNOS4_MCT_G_CNT_U );@@ -187,18 +201,45 @@ static u64 exynos4_read_count_64(void) }/** -* exynos4_read_count_32 - Read the lower 32-bits of the global counter +* __exynos4_read_cp15_count_64 - Read all 64-bits of the global counter +* from coprocessor regisers. * -* This will read just the lower 32-bits of the global counter. This is marked -* as notrace so it can be used by the scheduler clock. +* Note that reading here is faster than reading from MCT mmio region. +* +* Returns the number of cycles in the global counter. +*/ +static u64 __exynos4_read_cp15_count_64 (void ) +{ +return arch_counter_get_cntpct (); +} + +/** +* __exynos4_read_count_32 - Read the lower 32-bits of the global counter +* +* This will read just the lower 32-bits of the global counter from +* MCT mmio region. +* This is marked as notrace so it can be used by the scheduler clock. * * Returns the number of cycles in the global counter (lower 32 bits). */ -static u32 notrace exynos4_read_count_32(void) +static u32 notrace __exynos4_read_count_32(void) {return readl_relaxed (reg_base +EXYNOS4_MCT_G_CNT_L ); }
Quoted 6 lines
drivers/clocksource/exynos_mct.c static u64 exynos4_read_count_64(void) · line 233
Quoted 4 lines
drivers/clocksource/exynos_mct.c +4
-0+/** +* __exynos4_read_cp15_count_32 - Read the lower 32-bits of the global counter +* +* This will read global counter from coprocessor regisers. s/regisers/registers/
Will fix it.
Quoted 29 lines
Quoted 16 lines
drivers/clocksource/exynos_mct.c +9
-0+* This is marked as notrace so it can be used by the scheduler clock. +* +* Returns the number of cycles in the global counter (lower 32 bits). +*/ +static u32 notrace __exynos4_read_cp15_count_32(void) +{ +return arch_counter_get_cntpct (); +} +static cycle_t exynos4_frc_read (struct clocksource *cs) {return exynos4_read_count_32 ();@@ -599,6 +640,22 @@ static void __init mct_init_dt(struct device_node *np, unsigned int int_type)for (i =MCT_L0_IRQ ; i < nr_irqs; i++) mct_irqs[i] =irq_of_parse_and_map (np, i);drivers/clocksource/exynos_mct.c static void __init mct_init_dt(struct device_node *np, unsigned int int_type) · line 652
Quoted 10 lines
drivers/clocksource/exynos_mct.c +10
-0+/* +* If use-cp15-phys-counter property is present in device tree +* then use CP15 ARM arch timer 64-bit physical counter +* to speedup reading since it keeps the same value like +* 64-bit counter in MCT mmio region. +* If HYP mode is available we can rely on physical +* timer counter to be accessible from PL1. +*/ +if (IS_ENABLED (CONFIG_ARM ) &&is_hyp_mode_available () && +of_property_read_bool (np,"use-cp15-phys-counter" )) {This looks like a property specific to Exynos. Add a "samsung," prefix.
Quoted 2 lines
Best regards,
Krzysztof
Agree.
Thanks for comments and review.
Best regards,
Alexey Klimov.
Quoted 11 lines
Quoted 10 lines
drivers/clocksource/exynos_mct.c +6
-0+ +/* point MCT functions to read counter from coprocessor */ + exynos4_read_count_32 = __exynos4_read_cp15_count_32; + exynos4_read_count_64 = __exynos4_read_cp15_count_64; + } +exynos4_timer_resources (np,of_iomap (np,0 ));exynos4_clocksource_init ();exynos4_clockevent_init ();
Signature · 1 line
Best regards, Klimov Alexey