[v19,06/15] clocksource/drivers/arm_arch_timer: Rework counter frequency detection.

Message ID 20161221064603.11830-7-fu.wei@linaro.org
State New
Headers show

Commit Message

Fu Wei Dec. 21, 2016, 6:45 a.m.
From: Fu Wei <fu.wei@linaro.org>


Currently, the counter frequency detection call(arch_timer_detect_rate)
combines all the ways to get counter frequency: device-tree property,
system coprocessor register, MMIO timer. But in the most of use cases,
we don't need all the ways to try:
For example, reading device-tree property will be needed only when
system boot with device-tree, getting frequency from MMIO timer register
will beneeded only when we init MMIO timer.

This patch separates paths to determine frequency:
Separate out device-tree code, keep them in device-tree init function.
Separate out the MMIO frequency and the sysreg frequency detection call,
and use the appropriate one for the counter.

Signed-off-by: Fu Wei <fu.wei@linaro.org>

Tested-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>

---
 drivers/clocksource/arm_arch_timer.c | 49 +++++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 18 deletions(-)

-- 
2.9.3

--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Mark Rutland Jan. 16, 2017, 5:50 p.m. | #1
On Wed, Dec 21, 2016 at 02:45:54PM +0800, fu.wei@linaro.org wrote:
> From: Fu Wei <fu.wei@linaro.org>

> 

> Currently, the counter frequency detection call(arch_timer_detect_rate)

> combines all the ways to get counter frequency: device-tree property,

> system coprocessor register, MMIO timer. But in the most of use cases,

> we don't need all the ways to try:

> For example, reading device-tree property will be needed only when

> system boot with device-tree, getting frequency from MMIO timer register

> will beneeded only when we init MMIO timer.

> 

> This patch separates paths to determine frequency:

> Separate out device-tree code, keep them in device-tree init function.


Splitting these out makes sense to me.

> Separate out the MMIO frequency and the sysreg frequency detection call,

> and use the appropriate one for the counter.


> Signed-off-by: Fu Wei <fu.wei@linaro.org>

> Tested-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>

> ---

>  drivers/clocksource/arm_arch_timer.c | 49 +++++++++++++++++++++++-------------

>  1 file changed, 31 insertions(+), 18 deletions(-)

> 

> diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c

> index c7b4482..9a1f138 100644

> --- a/drivers/clocksource/arm_arch_timer.c

> +++ b/drivers/clocksource/arm_arch_timer.c

> @@ -488,27 +488,31 @@ static int arch_timer_starting_cpu(unsigned int cpu)

>  	return 0;

>  }

>  

> -static void

> -arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)

> +static void arch_timer_detect_rate(void)

>  {

> -	/* Who has more than one independent system counter? */

> -	if (arch_timer_rate)

> -		return;

> +	/*

> +	 * Try to get the timer frequency from

> +	 * cntfrq_el0(system coprocessor register).

> +	 */

> +	if (!arch_timer_rate)

> +		arch_timer_rate = arch_timer_get_cntfrq();

> +

> +	/* Check the timer frequency. */

> +	if (!arch_timer_rate)

> +		pr_warn("frequency not available\n");

> +}

>  

> +static void arch_timer_mem_detect_rate(void __iomem *cntbase)

> +{

>  	/*

> -	 * Try to determine the frequency from the device tree or CNTFRQ,

> -	 * if ACPI is enabled, get the frequency from CNTFRQ ONLY.

> +	 * Try to determine the frequency from

> +	 * CNTFRQ in memory-mapped timer.

>  	 */

> -	if (!acpi_disabled ||

> -	    of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {

> -		if (cntbase)

> -			arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);

> -		else

> -			arch_timer_rate = arch_timer_get_cntfrq();

> -	}

> +	if (!arch_timer_rate)

> +		arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);

>  

>  	/* Check the timer frequency. */

> -	if (arch_timer_rate == 0)

> +	if (!arch_timer_rate)

>  		pr_warn("frequency not available\n");

>  }


There's a subtle change in behaviour here. Previously for ACPI we'd only
ever use the sysreg CNTFRQ value for arch_timer_rate, whereas now we
might use the MMIO timer rate. Maybe that's not a big deal, but I will
need to think.

Generally, the logic to determine the rate is fairly gnarly regardless.

It would be nice if we could split the MMIO and sysreg rates entirely,
and kill the implicit relationship between the two, or at least make one
canonical and warn if the two differ.

Thanks,
Mark.
--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index c7b4482..9a1f138 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -488,27 +488,31 @@  static int arch_timer_starting_cpu(unsigned int cpu)
 	return 0;
 }
 
-static void
-arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)
+static void arch_timer_detect_rate(void)
 {
-	/* Who has more than one independent system counter? */
-	if (arch_timer_rate)
-		return;
+	/*
+	 * Try to get the timer frequency from
+	 * cntfrq_el0(system coprocessor register).
+	 */
+	if (!arch_timer_rate)
+		arch_timer_rate = arch_timer_get_cntfrq();
+
+	/* Check the timer frequency. */
+	if (!arch_timer_rate)
+		pr_warn("frequency not available\n");
+}
 
+static void arch_timer_mem_detect_rate(void __iomem *cntbase)
+{
 	/*
-	 * Try to determine the frequency from the device tree or CNTFRQ,
-	 * if ACPI is enabled, get the frequency from CNTFRQ ONLY.
+	 * Try to determine the frequency from
+	 * CNTFRQ in memory-mapped timer.
 	 */
-	if (!acpi_disabled ||
-	    of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {
-		if (cntbase)
-			arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);
-		else
-			arch_timer_rate = arch_timer_get_cntfrq();
-	}
+	if (!arch_timer_rate)
+		arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);
 
 	/* Check the timer frequency. */
-	if (arch_timer_rate == 0)
+	if (!arch_timer_rate)
 		pr_warn("frequency not available\n");
 }
 
@@ -886,7 +890,9 @@  static int __init arch_timer_of_init(struct device_node *np)
 	for (i = ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++)
 		arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
 
-	arch_timer_detect_rate(NULL, np);
+	if (!arch_timer_rate &&
+	    of_property_read_u32(np, "clock-frequency", &arch_timer_rate))
+		arch_timer_detect_rate();
 
 	arch_timer_c3stop = !of_property_read_bool(np, "always-on");
 
@@ -994,7 +1000,14 @@  static int __init arch_timer_mem_init(struct device_node *np)
 		goto out;
 	}
 
-	arch_timer_detect_rate(base, np);
+	/*
+	 * Try to determine the frequency from the device tree,
+	 * if fail, get the frequency from CNTFRQ.
+	 */
+	if (!arch_timer_rate &&
+	    of_property_read_u32(np, "clock-frequency", &arch_timer_rate))
+		arch_timer_mem_detect_rate(base);
+
 	ret = arch_timer_mem_register(base, irq);
 	if (ret)
 		goto out;
@@ -1056,7 +1069,7 @@  static int __init arch_timer_acpi_init(struct acpi_table_header *table)
 		gtdt->non_secure_el2_flags);
 
 	/* Get the frequency from CNTFRQ */
-	arch_timer_detect_rate(NULL, NULL);
+	arch_timer_detect_rate();
 
 	arch_timer_uses_ppi = arch_timer_select_ppi();
 	if (!arch_timer_ppi[arch_timer_uses_ppi]) {