From: Fu Wei <redacted>
This patchset:
(1)Preparation for adding GTDT support in arm_arch_timer:
1. Move some enums and marcos to header file;
2. Add a new enum for spi type;
3. Improve printk relevant code;
4. Rename some enums and defines;
5. Rework PPI determination;
6. Rework counter frequency detection;
7. Refactor arch_timer_needs_probing, move it into DT init call
8. Introduce some new structs and refactor the MMIO timer init code
for reusing some common code.
(2)Introduce ACPI GTDT parser: drivers/acpi/arm64/acpi_gtdt.c
Parse all kinds of timer in GTDT table of ACPI:arch timer,
memory-mapped timer and SBSA Generic Watchdog timer.
This driver can help to simplify all the relevant timer drivers,
and separate all the ACPI GTDT knowledge from them.
(3)Simplify ACPI code for arm_arch_timer
(4)Add GTDT support for ARM memory-mapped timer.
This patchset has been tested on the following platforms with ACPI enabled:
(1)ARM Foundation v8 model
Changelog:
v19: https://lkml.org/lkml/2016/12/21/
Fix a '\n' missing in a error message in arch_timer_mem_init.
Add "request_mem_region" for ioremapping cntbase, according to
f947ee1 clocksource/drivers/arm_arch_timer: Map frame with of_io_request_and_map()
Rebase to 4.9.0-gfb779ff
v18: https://lkml.org/lkml/2016/12/8/446
Fix 8/15 patch problem of "int ret;" in arch_timer_acpi_init.
Rebase to 4.9.0-rc8-g9269898
v17: https://lkml.org/lkml/2016/11/25/140
Take out some cleanups from 4/15.
Merge 5/15 and 6/15, improve PPI determination code,
improve commit message.
Rework counter frequency detection.
Move arch_timer_needs_of_probing into DT init call.
Move Platform Timer scan loop back to timer init call to avoid allocating
and free memory.
Improve all the exported functions' comment.
v16: https://lkml.org/lkml/2016/11/16/268
Fix patchset problem about static enum ppi_nr of 01/13 in v15.
Refactor arch_timer_detect_rate.
Refactor arch_timer_needs_probing.
v15: https://lkml.org/lkml/2016/11/15/366
Re-order patches
Add arm_arch_timer refactoring patches to prepare for GTDT:
1. rename some enums and defines, and some cleanups
2. separate out arch_timer_uses_ppi init code and fix a potential bug
3. Improve some new structs, refactor the timer init code.
Since the some structs have been changed, GTDT parser for memory-mapped
timer and SBSA Generic Watchdog timer have been update.
v14: https://lkml.org/lkml/2016/9/28/573
Separate memory-mapped timer GTDT support into two patches
1. Refactor the timer init code to prepare for GTDT
2. Add GTDT support for memory-mapped timer
v13: http://www.mail-archive.com/linux-kernel at vger.kernel.org/msg1231717.html
Improve arm_arch_timer code for memory-mapped
timer GTDT support, refactor original memory-mapped timer
dt support for reusing some common code.
v12: https://lkml.org/lkml/2016/9/13/250
Rebase to latest Linux 4.8-rc6
Delete the confusing "skipping" in the error message.
V11: https://lkml.org/lkml/2016/9/6/354
Rebase to latest Linux 4.8-rc5
Delete typedef (suggested by checkpatch.pl)
V10: https://lkml.org/lkml/2016/7/26/215
Drop the "readq" patch.
Rebase to latest Linux 4.7.
V9: https://lkml.org/lkml/2016/7/25/345
Improve pr_err message in acpi gtdt driver.
Update Commit message for 7/9
shorten the irq mapping function name
Improve GTDT driver for memory-mapped timer
v8: https://lkml.org/lkml/2016/7/19/660
Improve "pr_fmt(fmt)" definition: add "ACPI" in front of "GTDT",
and also improve printk message.
Simplify is_timer_block and is_watchdog.
Merge acpi_gtdt_desc_init and gtdt_arch_timer_init into acpi_gtdt_init();
Delete __init in include/linux/acpi.h for GTDT API
Make ARM64 select GTDT.
Delete "#include <linux/module.h>" from acpi_gtdt.c
Simplify GT block parse code.
v7: https://lkml.org/lkml/2016/7/13/769
Move the GTDT driver to drivers/acpi/arm64
Add add the ARM64-specific ACPI Support maintainers in MAINTAINERS
Merge 3 patches of GTDT parser driver.
Fix the for_each_platform_timer bug.
v6: https://lkml.org/lkml/2016/6/29/580
split the GTDT driver to 4 parts: basic, arch_timer, memory-mapped timer,
and SBSA Generic Watchdog timer
Improve driver by suggestions and example code from Daniel Lezcano
v5: https://lkml.org/lkml/2016/5/24/356
Sorting out all patches, simplify the API of GTDT driver:
GTDT driver just fills the data struct for arm_arch_timer driver.
v4: https://lists.linaro.org/pipermail/linaro-acpi/2016-March/006667.html
Delete the kvm relevant patches
Separate two patches for sorting out the code for arm_arch_timer.
Improve irq info export code to allow missing irq info in GTDT table.
v3: https://lkml.org/lkml/2016/2/1/658
Improve GTDT driver code:
(1)improve pr_* by defining pr_fmt(fmt)
(2)simplify gtdt_sbsa_gwdt_init
(3)improve gtdt_arch_timer_data_init, if table is NULL, it will try
to get GTDT table.
Move enum ppi_nr to arm_arch_timer.h, and add enum spi_nr.
Add arm_arch_timer get ppi from DT and GTDT support for kvm.
v2: https://lkml.org/lkml/2015/12/2/10
Rebase to latest kernel version(4.4-rc3).
Fix the bug about the config problem,
use CONFIG_ACPI_GTDT instead of CONFIG_ACPI in arm_arch_timer.c
v1: The first upstreaming version: https://lkml.org/lkml/2015/10/28/553
Fu Wei (15):
clocksource/drivers/arm_arch_timer: Move enums and defines to header
file
clocksource/drivers/arm_arch_timer: Add a new enum for spi type
clocksource/drivers/arm_arch_timer: Improve printk relevant code
clocksource/drivers/arm_arch_timer: rename some enums and defines.
clocksource/drivers/arm_arch_timer: rework PPI determination
clocksource/drivers/arm_arch_timer: Rework counter frequency
detection.
clocksource/drivers/arm_arch_timer: Refactor arch_timer_needs_probing
clocksource/drivers/arm_arch_timer: move arch_timer_needs_of_probing
into DT init call
clocksource/drivers/arm_arch_timer: Introduce some new structs to
prepare for GTDT
clocksource/drivers/arm_arch_timer: Refactor the timer init code to
prepare for GTDT
acpi/arm64: Add GTDT table parse driver
clocksource/drivers/arm_arch_timer: Simplify ACPI support code.
acpi/arm64: Add memory-mapped timer support in GTDT driver
clocksource/drivers/arm_arch_timer: Add GTDT support for memory-mapped
timer
acpi/arm64: Add SBSA Generic Watchdog support in GTDT driver
arch/arm64/Kconfig | 1 +
drivers/acpi/arm64/Kconfig | 3 +
drivers/acpi/arm64/Makefile | 1 +
drivers/acpi/arm64/gtdt.c | 374 +++++++++++++++++++++++++++
drivers/clocksource/arm_arch_timer.c | 483 ++++++++++++++++++++---------------
drivers/watchdog/Kconfig | 1 +
include/clocksource/arm_arch_timer.h | 45 +++-
include/linux/acpi.h | 7 +
virt/kvm/arm/hyp/timer-sr.c | 6 +-
9 files changed, 712 insertions(+), 209 deletions(-)
create mode 100644 drivers/acpi/arm64/gtdt.c
--
2.9.3
From: Fu Wei <redacted>
To support the arm_arch_timer via ACPI we need to share defines and enums
between the driver and the ACPI parser code.
Split out the relevant defines and enums into arm_arch_timer.h, and
change "enum ppi_nr" to "enum arch_timer_ppi_nr" to avoid the potential
name clashes.
Also switch "enum ppi_nr" to "enum arch_timer_ppi_nr" in
arm_arch_timer.c.
No functional change.
Signed-off-by: Fu Wei <redacted>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Xiongfeng Wang <redacted>
---
drivers/clocksource/arm_arch_timer.c | 13 +------------
include/clocksource/arm_arch_timer.h | 12 ++++++++++++
2 files changed, 13 insertions(+), 12 deletions(-)
From: Fu Wei <redacted>
This patch add a new enum "arch_timer_spi_nr" and use it in the driver.
Just for code's readability, no functional change.
Signed-off-by: Fu Wei <redacted>
Acked-by: Mark Rutland <mark.rutland@arm.com>
---
drivers/clocksource/arm_arch_timer.c | 4 ++--
include/clocksource/arm_arch_timer.h | 6 ++++++
2 files changed, 8 insertions(+), 2 deletions(-)
From: Fu Wei <redacted>
This patch defines pr_fmt(fmt) for all pr_* functions,
then the pr_* doesn't need to add "arch_timer:" everytime.
According to the suggestion from checkpatch.pl:
(1) delete some Blank Spaces in arch_timer_banner;
(2) delete a redundant Tab in a bland line of arch_timer_init(void)
No functional change.
Signed-off-by: Fu Wei <redacted>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Xiongfeng Wang <redacted>
---
drivers/clocksource/arm_arch_timer.c | 49 ++++++++++++++++++------------------
1 file changed, 25 insertions(+), 24 deletions(-)
@@ -505,22 +508,22 @@ arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)/* Check the timer frequency. */if(arch_timer_rate==0)-pr_warn("Architected timer frequency not available\n");+pr_warn("frequency not available\n");}staticvoidarch_timer_banner(unsignedtype){-pr_info("Architected %s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n",-type&ARCH_CP15_TIMER?"cp15":"",-type==(ARCH_CP15_TIMER|ARCH_MEM_TIMER)?" and ":"",-type&ARCH_MEM_TIMER?"mmio":"",-(unsignedlong)arch_timer_rate/1000000,-(unsignedlong)(arch_timer_rate/10000)%100,-type&ARCH_CP15_TIMER?-(arch_timer_uses_ppi==VIRT_PPI)?"virt":"phys":+pr_info("%s%s%s timer(s) running@%lu.%02luMHz (%s%s%s).\n",+type&ARCH_CP15_TIMER?"cp15":"",+type==(ARCH_CP15_TIMER|ARCH_MEM_TIMER)?" and ":"",+type&ARCH_MEM_TIMER?"mmio":"",+(unsignedlong)arch_timer_rate/1000000,+(unsignedlong)(arch_timer_rate/10000)%100,+type&ARCH_CP15_TIMER?+(arch_timer_uses_ppi==VIRT_PPI)?"virt":"phys":"",-type==(ARCH_CP15_TIMER|ARCH_MEM_TIMER)?"/":"",-type&ARCH_MEM_TIMER?+type==(ARCH_CP15_TIMER|ARCH_MEM_TIMER)?"/":"",+type&ARCH_MEM_TIMER?arch_timer_mem_use_virtual?"virt":"phys":"");}
@@ -621,8 +624,7 @@ static void __init arch_counter_register(unsigned type)staticvoidarch_timer_stop(structclock_event_device*clk){-pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",-clk->irq,smp_processor_id());+pr_debug("disable IRQ%d cpu #%d\n",clk->irq,smp_processor_id());disable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi]);if(arch_timer_has_nonsecure_ppi())
@@ -769,7 +770,7 @@ static int __init arch_timer_mem_register(void __iomem *base, unsigned int irq)ret=request_irq(irq,func,IRQF_TIMER,"arch_mem_timer",&t->evt);if(ret){-pr_err("arch_timer: Failed to request mem timer irq\n");+pr_err("Failed to request mem timer irq\n");kfree(t);}
@@ -847,7 +848,7 @@ static int __init arch_timer_init(void)}if(!has_ppi){-pr_warn("arch_timer: No interrupt available, giving up\n");+pr_warn("No interrupt available, giving up\n");return-EINVAL;}}
@@ -861,7 +862,7 @@ static int __init arch_timer_init(void)returnret;arch_timer_kvm_info.virtual_irq=arch_timer_ppi[VIRT_PPI];-+return0;}
@@ -870,7 +871,7 @@ static int __init arch_timer_of_init(struct device_node *np)inti;if(arch_timers_present&ARCH_CP15_TIMER){-pr_warn("arch_timer: multiple nodes in dt, skipping\n");+pr_warn("multiple nodes in dt, skipping\n");return0;}
From: Fu Wei <redacted>
Rename some enums and defines, to unify the format of enums and defines
in arm_arch_timer.h, also update all the users of these enums and defines:
drivers/clocksource/arm_arch_timer.c
virt/kvm/arm/hyp/timer-sr.c
No functional change.
Signed-off-by: Fu Wei <redacted>
Tested-by: Xiongfeng Wang <redacted>
---
drivers/clocksource/arm_arch_timer.c | 111 ++++++++++++++++++-----------------
include/clocksource/arm_arch_timer.h | 24 ++++----
virt/kvm/arm/hyp/timer-sr.c | 6 +-
3 files changed, 73 insertions(+), 68 deletions(-)
@@ -470,14 +470,15 @@ static int arch_timer_starting_cpu(unsigned int cpu)structclock_event_device*clk=this_cpu_ptr(arch_timer_evt);u32flags;-__arch_timer_setup(ARCH_CP15_TIMER,clk);+__arch_timer_setup(ARCH_TIMER_TYPE_CP15,clk);flags=check_ppi_trigger(arch_timer_ppi[arch_timer_uses_ppi]);enable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi],flags);if(arch_timer_has_nonsecure_ppi()){-flags=check_ppi_trigger(arch_timer_ppi[PHYS_NONSECURE_PPI]);-enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI],flags);+flags=check_ppi_trigger(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);+enable_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI],+flags);}arch_counter_set_user_access();
@@ -514,16 +515,17 @@ arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)staticvoidarch_timer_banner(unsignedtype){pr_info("%s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n",-type&ARCH_CP15_TIMER?"cp15":"",-type==(ARCH_CP15_TIMER|ARCH_MEM_TIMER)?" and ":"",-type&ARCH_MEM_TIMER?"mmio":"",+type&ARCH_TIMER_TYPE_CP15?"cp15":"",+type==(ARCH_TIMER_TYPE_CP15|ARCH_TIMER_TYPE_MEM)?+" and ":"",+type&ARCH_TIMER_TYPE_MEM?"mmio":"",(unsignedlong)arch_timer_rate/1000000,(unsignedlong)(arch_timer_rate/10000)%100,-type&ARCH_CP15_TIMER?-(arch_timer_uses_ppi==VIRT_PPI)?"virt":"phys":+type&ARCH_TIMER_TYPE_CP15?+(arch_timer_uses_ppi==ARCH_TIMER_VIRT_PPI)?"virt":"phys":"",-type==(ARCH_CP15_TIMER|ARCH_MEM_TIMER)?"/":"",-type&ARCH_MEM_TIMER?+type==(ARCH_TIMER_TYPE_CP15|ARCH_TIMER_TYPE_MEM)?"/":"",+type&ARCH_TIMER_TYPE_MEM?arch_timer_mem_use_virtual?"virt":"phys":"");}
@@ -589,8 +591,9 @@ static void __init arch_counter_register(unsigned type)u64start_count;/* Register the CP15 based counter if we have one */-if(type&ARCH_CP15_TIMER){-if(IS_ENABLED(CONFIG_ARM64)||arch_timer_uses_ppi==VIRT_PPI)+if(type&ARCH_TIMER_TYPE_CP15){+if(IS_ENABLED(CONFIG_ARM64)||+arch_timer_uses_ppi==ARCH_TIMER_VIRT_PPI)arch_timer_read_counter=arch_counter_get_cntvct;elsearch_timer_read_counter=arch_counter_get_cntpct;
@@ -691,24 +694,24 @@ static int __init arch_timer_register(void)ppi=arch_timer_ppi[arch_timer_uses_ppi];switch(arch_timer_uses_ppi){-caseVIRT_PPI:+caseARCH_TIMER_VIRT_PPI:err=request_percpu_irq(ppi,arch_timer_handler_virt,"arch_timer",arch_timer_evt);break;-casePHYS_SECURE_PPI:-casePHYS_NONSECURE_PPI:+caseARCH_TIMER_PHYS_SECURE_PPI:+caseARCH_TIMER_PHYS_NONSECURE_PPI:err=request_percpu_irq(ppi,arch_timer_handler_phys,"arch_timer",arch_timer_evt);-if(!err&&arch_timer_ppi[PHYS_NONSECURE_PPI]){-ppi=arch_timer_ppi[PHYS_NONSECURE_PPI];+if(!err&&arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]){+ppi=arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI];err=request_percpu_irq(ppi,arch_timer_handler_phys,"arch_timer",arch_timer_evt);if(err)-free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],+free_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI],arch_timer_evt);}break;-caseHYP_PPI:+caseARCH_TIMER_HYP_PPI:err=request_percpu_irq(ppi,arch_timer_handler_phys,"arch_timer",arch_timer_evt);break;
@@ -740,7 +743,7 @@ static int __init arch_timer_register(void)out_unreg_notify:free_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi],arch_timer_evt);if(arch_timer_has_nonsecure_ppi())-free_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI],+free_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI],arch_timer_evt);out_free:
@@ -761,7 +764,7 @@ static int __init arch_timer_mem_register(void __iomem *base, unsigned int irq)t->base=base;t->evt.irq=irq;-__arch_timer_setup(ARCH_MEM_TIMER,&t->evt);+__arch_timer_setup(ARCH_TIMER_TYPE_MEM,&t->evt);if(arch_timer_mem_use_virtual)func=arch_timer_handler_virt_mem;
@@ -804,13 +807,15 @@ arch_timer_needs_probing(int type, const struct of_device_id *matches)staticint__initarch_timer_common_init(void){-unsignedmask=ARCH_CP15_TIMER|ARCH_MEM_TIMER;+unsignedmask=ARCH_TIMER_TYPE_CP15|ARCH_TIMER_TYPE_MEM;/* Wait until both nodes are probed if we have two timers */if((arch_timers_present&mask)!=mask){-if(arch_timer_needs_probing(ARCH_MEM_TIMER,arch_timer_mem_of_match))+if(arch_timer_needs_probing(ARCH_TIMER_TYPE_MEM,+arch_timer_mem_of_match))return0;-if(arch_timer_needs_probing(ARCH_CP15_TIMER,arch_timer_of_match))+if(arch_timer_needs_probing(ARCH_TIMER_TYPE_CP15,+arch_timer_of_match))return0;}
@@ -835,16 +840,16 @@ static int __init arch_timer_init(void)*theirCNTHP_*_EL2counterparts,anduseadifferentPPI*number.*/-if(is_hyp_mode_available()||!arch_timer_ppi[VIRT_PPI]){+if(is_hyp_mode_available()||!arch_timer_ppi[ARCH_TIMER_VIRT_PPI]){boolhas_ppi;if(is_kernel_in_hyp_mode()){-arch_timer_uses_ppi=HYP_PPI;-has_ppi=!!arch_timer_ppi[HYP_PPI];+arch_timer_uses_ppi=ARCH_TIMER_HYP_PPI;+has_ppi=!!arch_timer_ppi[ARCH_TIMER_HYP_PPI];}else{-arch_timer_uses_ppi=PHYS_SECURE_PPI;-has_ppi=(!!arch_timer_ppi[PHYS_SECURE_PPI]||-!!arch_timer_ppi[PHYS_NONSECURE_PPI]);+arch_timer_uses_ppi=ARCH_TIMER_PHYS_SECURE_PPI;+has_ppi=(!!arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI]||+!!arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);}if(!has_ppi){
@@ -861,7 +866,7 @@ static int __init arch_timer_init(void)if(ret)returnret;-arch_timer_kvm_info.virtual_irq=arch_timer_ppi[VIRT_PPI];+arch_timer_kvm_info.virtual_irq=arch_timer_ppi[ARCH_TIMER_VIRT_PPI];return0;}
@@ -870,13 +875,13 @@ static int __init arch_timer_of_init(struct device_node *np){inti;-if(arch_timers_present&ARCH_CP15_TIMER){+if(arch_timers_present&ARCH_TIMER_TYPE_CP15){pr_warn("multiple nodes in dt, skipping\n");return0;}-arch_timers_present|=ARCH_CP15_TIMER;-for(i=PHYS_SECURE_PPI;i<MAX_TIMER_PPI;i++)+arch_timers_present|=ARCH_TIMER_TYPE_CP15;+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);
@@ -898,7 +903,7 @@ static int __init arch_timer_of_init(struct device_node *np)*/if(IS_ENABLED(CONFIG_ARM)&&of_property_read_bool(np,"arm,cpu-registers-not-fw-configured"))-arch_timer_uses_ppi=PHYS_SECURE_PPI;+arch_timer_uses_ppi=ARCH_TIMER_PHYS_SECURE_PPI;/* On some systems, the counter stops ticking when in suspend. */arch_counter_suspend_stop=of_property_read_bool(np,
From: Fu Wei <redacted>
Currently, the arch timer driver uses ARCH_TIMER_PHYS_SECURE_PPI to
mean the driver will use the secure PPI *and* potentialy also use the
non-secure PPI. This is somewhat confusing.
For arm64, where it never makes sense to use the secure PPI, this
means we must always request the useless secure PPI, adding to the
confusion. For ACPI, where we may not even have a valid secure PPI
number, this is additionally problematic. We need the driver to be
able to use *only* the non-secure PPI.
The logic to choose which PPI to use is intertwined with other logic
in arch_timer_init(). This patch factors the PPI determination out
into a new function named arch_timer_select_ppi, and then reworks it
so that we can handle having only a non-secure PPI.
This patch also moves arch_timer_ppi verification out to caller,
because we can verify the configuration from device-tree for ARM by this
way.
Meanwhile, because we will select ARCH_TIMER_PHYS_NONSECURE_PPI for ARM64,
the logic in arch_timer_register also need to be updated.
Signed-off-by: Fu Wei <redacted>
Tested-by: Xiongfeng Wang <redacted>
---
drivers/clocksource/arm_arch_timer.c | 77 +++++++++++++++++++++---------------
1 file changed, 46 insertions(+), 31 deletions(-)
@@ -904,6 +906,13 @@ static int __init arch_timer_of_init(struct device_node *np)if(IS_ENABLED(CONFIG_ARM)&&of_property_read_bool(np,"arm,cpu-registers-not-fw-configured"))arch_timer_uses_ppi=ARCH_TIMER_PHYS_SECURE_PPI;+else+arch_timer_uses_ppi=arch_timer_select_ppi();++if(!arch_timer_ppi[arch_timer_uses_ppi]){+pr_err("No interrupt available, giving up\n");+return-EINVAL;+}/* On some systems, the counter stops ticking when in suspend. */arch_counter_suspend_stop=of_property_read_bool(np,
@@ -1049,6 +1058,12 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)/* Get the frequency from CNTFRQ */arch_timer_detect_rate(NULL,NULL);+arch_timer_uses_ppi=arch_timer_select_ppi();+if(!arch_timer_ppi[arch_timer_uses_ppi]){+pr_err("No interrupt available, giving up\n");+return-EINVAL;+}+/* Always-on capability */arch_timer_c3stop=!(gtdt->non_secure_el1_flags&ACPI_GTDT_ALWAYS_ON);
From: Fu Wei <redacted>
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 <redacted>
Tested-by: Xiongfeng Wang <redacted>
---
drivers/clocksource/arm_arch_timer.c | 49 +++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 18 deletions(-)
@@ -488,27 +488,31 @@ static int arch_timer_starting_cpu(unsigned int cpu)return0;}-staticvoid-arch_timer_detect_rate(void__iomem*cntbase,structdevice_node*np)+staticvoidarch_timer_detect_rate(void){-/* Who has more than one independent system counter? */-if(arch_timer_rate)-return;+/*+*Trytogetthetimerfrequencyfrom+*cntfrq_el0(systemcoprocessorregister).+*/+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");+}+staticvoidarch_timer_mem_detect_rate(void__iomem*cntbase)+{/*-*TrytodeterminethefrequencyfromthedevicetreeorCNTFRQ,-*ifACPIisenabled,getthefrequencyfromCNTFRQONLY.+*Trytodeterminethefrequencyfrom+*CNTFRQinmemory-mappedtimer.*/-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)gotoout;}-arch_timer_detect_rate(base,np);+/*+*Trytodeterminethefrequencyfromthedevicetree,+*iffail,getthefrequencyfromCNTFRQ.+*/+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)gotoout;
@@ -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]){
From: Fu Wei <redacted>
When system init with device-tree, we don't know which node will be
initialized first. And the code in arch_timer_common_init should wait
until per-cpu timer and MMIO timer are both initialized. So we need
arch_timer_needs_probing to detect the init status of system.
But currently the code is dispersed in arch_timer_needs_probing and
arch_timer_common_init. And the function name doesn't specify that
it's only for device-tree. This is somewhat confusing.
This patch move all related code from arch_timer_common_init to
arch_timer_needs_probing, refactor it, and rename it to
arch_timer_needs_of_probing. And make sure that it will be called
only if acpi is disabled.
Signed-off-by: Fu Wei <redacted>
---
drivers/clocksource/arm_arch_timer.c | 34 +++++++++++++++++++---------------
1 file changed, 19 insertions(+), 15 deletions(-)
@@ -795,15 +795,28 @@ static const struct of_device_id arch_timer_mem_of_match[] __initconst = {{},};-staticbool__init-arch_timer_needs_probing(inttype,conststructof_device_id*matches)+staticbool__initarch_timer_needs_of_probing(void){structdevice_node*dn;boolneeds_probing=false;+unsignedintmask=ARCH_TIMER_TYPE_CP15|ARCH_TIMER_TYPE_MEM;-dn=of_find_matching_node(NULL,matches);-if(dn&&of_device_is_available(dn)&&!(arch_timers_present&type))+/* We have two timers, and both device-tree nodes are probed. */+if((arch_timers_present&mask)==mask)+returnfalse;++/*+*Onlyonetypeoftimerisprobed,+*checkifwehaveanothertypeoftimernodeindevice-tree.+*/+if(arch_timers_present&ARCH_TIMER_TYPE_CP15)+dn=of_find_matching_node(NULL,arch_timer_mem_of_match);+else+dn=of_find_matching_node(NULL,arch_timer_of_match);++if(dn&&of_device_is_available(dn))needs_probing=true;+of_node_put(dn);returnneeds_probing;
@@ -811,17 +824,8 @@ arch_timer_needs_probing(int type, const struct of_device_id *matches)staticint__initarch_timer_common_init(void){-unsignedmask=ARCH_TIMER_TYPE_CP15|ARCH_TIMER_TYPE_MEM;--/* Wait until both nodes are probed if we have two timers */-if((arch_timers_present&mask)!=mask){-if(arch_timer_needs_probing(ARCH_TIMER_TYPE_MEM,-arch_timer_mem_of_match))-return0;-if(arch_timer_needs_probing(ARCH_TIMER_TYPE_CP15,-arch_timer_of_match))-return0;-}+if(acpi_disabled&&arch_timer_needs_of_probing())+return0;arch_timer_banner(arch_timers_present);arch_counter_register(arch_timers_present);
From: Fu Wei <redacted>
Because arch_timer_needs_of_probing is only for booting with device-tree,
but arch_timer_common_init is a generic init call which shouldn't include
the FW-specific code. It's better to put arch_timer_needs_of_probing into
DT init function.
But for per-cpu timer, the arch_timer_common_init is called from
arch_timer_init. For reaching the goal above, this patch disassemble
arch_timer_init and use arch_timer_register and arch_timer_common_init
directly, just like arch_timer_mem init code is doing.
By this way, all the DT relevant code are only called from DT init call.
Signed-off-by: Fu Wei <redacted>
---
drivers/clocksource/arm_arch_timer.c | 46 ++++++++++++++++--------------------
1 file changed, 21 insertions(+), 25 deletions(-)
@@ -1072,6 +1063,8 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt,gtdt->non_secure_el2_flags);+arch_timer_kvm_info.virtual_irq=arch_timer_ppi[ARCH_TIMER_VIRT_PPI];+/* Get the frequency from CNTFRQ */arch_timer_detect_rate();
From: Fu Wei <redacted>
The patch introduce two new structs: arch_timer_mem, arch_timer_mem_frame.
And also introduce a new define: ARCH_TIMER_MEM_MAX_FRAMES
These will be used for refactoring the memory-mapped timer init code to
prepare for GTDT
Signed-off-by: Fu Wei <redacted>
---
include/clocksource/arm_arch_timer.h | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
From: Fu Wei <redacted>
The patch refactor original memory-mapped timer init code:
(1) Refactor "arch_timer_mem_init", make it become a common code for
memory-mapped timer init.
(2) Add a new function "arch_timer_mem_of_init" for DT init.
Signed-off-by: Fu Wei <redacted>
---
drivers/clocksource/arm_arch_timer.c | 135 ++++++++++++++++++++++++-----------
1 file changed, 92 insertions(+), 43 deletions(-)
@@ -942,26 +942,18 @@ static int __init arch_timer_mem_init(struct device_node *np)*Trytofindavirtualcapableframe.Otherwisefallbacktoa*physicalcapableframe.*/-for_each_available_child_of_node(np,frame){-intn;-u32cntacr;--if(of_property_read_u32(frame,"frame-number",&n)){-pr_err("Missing frame-number\n");-of_node_put(frame);-gotoout;-}+for(i=0;i<timer_mem->num_frames;i++){+u32cntacr=CNTACR_RFRQ|CNTACR_RWPT|CNTACR_RPCT|+CNTACR_RWVT|CNTACR_RVOFF|CNTACR_RVCT;+intn=timer_mem->frame[i].frame_nr;/* Try enabling everything, and see what sticks */-cntacr=CNTACR_RFRQ|CNTACR_RWPT|CNTACR_RPCT|-CNTACR_RWVT|CNTACR_RVOFF|CNTACR_RVCT;writel_relaxed(cntacr,cntctlbase+CNTACR(n));cntacr=readl_relaxed(cntctlbase+CNTACR(n));if((cnttidr&CNTTIDR_VIRT(n))&&!(~cntacr&(CNTACR_RWVT|CNTACR_RVCT))){-of_node_put(best_frame);-best_frame=frame;+best_frame=&timer_mem->frame[i];arch_timer_mem_use_virtual=true;break;}
@@ -969,51 +961,108 @@ static int __init arch_timer_mem_init(struct device_node *np)if(~cntacr&(CNTACR_RWPT|CNTACR_RPCT))continue;-of_node_put(best_frame);-best_frame=of_node_get(frame);+best_frame=&timer_mem->frame[i];}+iounmap(cntctlbase);-ret=-ENXIO;-base=arch_counter_base=of_io_request_and_map(best_frame,0,-"arch_mem_timer");-if(IS_ERR(base)){-pr_err("Can't map frame's registers\n");-gotoout;+if(!best_frame){+pr_err("Can't find frame for register\n");+return-EINVAL;}if(arch_timer_mem_use_virtual)-irq=irq_of_parse_and_map(best_frame,ARCH_TIMER_VIRT_SPI);+irq=best_frame->virt_irq;else-irq=irq_of_parse_and_map(best_frame,ARCH_TIMER_PHYS_SPI);+irq=best_frame->phys_irq;-ret=-EINVAL;if(!irq){pr_err("Frame missing %s irq.\n",arch_timer_mem_use_virtual?"virt":"phys");-gotoout;+return-EINVAL;}-/*-*Trytodeterminethefrequencyfromthedevicetree,-*iffail,getthefrequencyfromCNTFRQ.-*/-if(!arch_timer_rate&&-of_property_read_u32(np,"clock-frequency",&arch_timer_rate))-arch_timer_mem_detect_rate(base);+if(!request_mem_region(best_frame->cntbase,best_frame->size,+"arch_mem_timer"))+return-EBUSY;++base=ioremap(best_frame->cntbase,best_frame->size);+if(!base){+pr_err("Can't map frame's registers\n");+return-ENXIO;+}++arch_timer_mem_detect_rate(base);ret=arch_timer_mem_register(base,irq);-if(ret)+if(ret){+iounmap(base);+returnret;+}++arch_counter_base=base;+arch_timers_present|=ARCH_TIMER_TYPE_MEM;++return0;+}++staticint__initarch_timer_mem_of_init(structdevice_node*np)+{+structarch_timer_mem*timer_mem;+structdevice_node*frame_node;+structresourceres;+inti,ret=-EINVAL;++timer_mem=kzalloc(sizeof(*timer_mem),GFP_KERNEL);+if(!timer_mem)+return-ENOMEM;++if(of_address_to_resource(np,0,&res))gotoout;+timer_mem->cntctlbase=res.start;+timer_mem->size=resource_size(&res);++i=0;+for_each_available_child_of_node(np,frame_node){+intn;+structarch_timer_mem_frame*frame=&timer_mem->frame[i];++if(of_property_read_u32(frame_node,"frame-number",&n)){+pr_err("Missing frame-number\n");+of_node_put(frame_node);+gotoout;+}+frame->frame_nr=n;++if(of_address_to_resource(frame_node,0,&res)){+of_node_put(frame_node);+gotoout;+}+frame->cntbase=res.start;+frame->size=resource_size(&res);++frame->virt_irq=irq_of_parse_and_map(frame_node,+ARCH_TIMER_VIRT_SPI);+frame->phys_irq=irq_of_parse_and_map(frame_node,+ARCH_TIMER_PHYS_SPI);-if(!arch_timer_needs_of_probing())+if(++i>=ARCH_TIMER_MEM_MAX_FRAMES)+break;+}+timer_mem->num_frames=i;++/* Try to determine the frequency from the device tree */+if(!arch_timer_rate)+of_property_read_u32(np,"clock-frequency",&arch_timer_rate);++ret=arch_timer_mem_init(timer_mem);+if(!ret&&!arch_timer_needs_of_probing())ret=arch_timer_common_init();out:-iounmap(cntctlbase);-of_node_put(best_frame);+kfree(timer_mem);returnret;}CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem,"arm,armv7-timer-mem",-arch_timer_mem_init);+arch_timer_mem_of_init);#ifdef CONFIG_ACPIstaticint__initmap_generic_timer_interrupt(u32interrupt,u32flags)
From: Fu Wei <redacted>
This patch adds support for parsing arch timer info in GTDT,
provides some kernel APIs to parse all the PPIs and
always-on info in GTDT and export them.
By this driver, we can simplify arm_arch_timer drivers, and
separate the ACPI GTDT knowledge from it.
Signed-off-by: Fu Wei <redacted>
Signed-off-by: Hanjun Guo <redacted>
Acked-by: Rafael J. Wysocki <redacted>
Tested-by: Xiongfeng Wang <redacted>
---
arch/arm64/Kconfig | 1 +
drivers/acpi/arm64/Kconfig | 3 +
drivers/acpi/arm64/Makefile | 1 +
drivers/acpi/arm64/gtdt.c | 157 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 6 ++
5 files changed, 168 insertions(+)
From: Fu Wei <redacted>
The patch update arm_arch_timer driver to use the function
provided by the new GTDT driver of ACPI.
By this way, arm_arch_timer.c can be simplified, and separate
all the ACPI GTDT knowledge from this timer driver.
Signed-off-by: Fu Wei <redacted>
Signed-off-by: Hanjun Guo <redacted>
Tested-by: Xiongfeng Wang <redacted>
---
drivers/clocksource/arm_arch_timer.c | 46 ++++++++++--------------------------
1 file changed, 13 insertions(+), 33 deletions(-)
@@ -1064,59 +1064,36 @@ static int __init arch_timer_mem_of_init(struct device_node *np)CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem,"arm,armv7-timer-mem",arch_timer_mem_of_init);-#ifdef CONFIG_ACPI-staticint__initmap_generic_timer_interrupt(u32interrupt,u32flags)-{-inttrigger,polarity;--if(!interrupt)-return0;--trigger=(flags&ACPI_GTDT_INTERRUPT_MODE)?ACPI_EDGE_SENSITIVE-:ACPI_LEVEL_SENSITIVE;--polarity=(flags&ACPI_GTDT_INTERRUPT_POLARITY)?ACPI_ACTIVE_LOW-:ACPI_ACTIVE_HIGH;--returnacpi_register_gsi(NULL,interrupt,trigger,polarity);-}-+#ifdef CONFIG_ACPI_GTDT/* Initialize per-processor generic timer */staticint__initarch_timer_acpi_init(structacpi_table_header*table){intret;-structacpi_table_gtdt*gtdt;if(arch_timers_present&ARCH_TIMER_TYPE_CP15){pr_warn("already initialized, skipping\n");return-EINVAL;}-gtdt=container_of(table,structacpi_table_gtdt,header);-arch_timers_present|=ARCH_TIMER_TYPE_CP15;-arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI]=-map_generic_timer_interrupt(gtdt->secure_el1_interrupt,-gtdt->secure_el1_flags);+ret=acpi_gtdt_init(table,NULL);+if(ret){+pr_err("Failed to init GTDT table.\n");+returnret;+}arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]=-map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt,-gtdt->non_secure_el1_flags);+acpi_gtdt_map_ppi(ARCH_TIMER_PHYS_NONSECURE_PPI);arch_timer_ppi[ARCH_TIMER_VIRT_PPI]=-map_generic_timer_interrupt(gtdt->virtual_timer_interrupt,-gtdt->virtual_timer_flags);+acpi_gtdt_map_ppi(ARCH_TIMER_VIRT_PPI);arch_timer_ppi[ARCH_TIMER_HYP_PPI]=-map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt,-gtdt->non_secure_el2_flags);+acpi_gtdt_map_ppi(ARCH_TIMER_HYP_PPI);arch_timer_kvm_info.virtual_irq=arch_timer_ppi[ARCH_TIMER_VIRT_PPI];-/* Get the frequency from CNTFRQ */-arch_timer_detect_rate();-arch_timer_uses_ppi=arch_timer_select_ppi();if(!arch_timer_ppi[arch_timer_uses_ppi]){pr_err("No interrupt available, giving up\n");
@@ -1124,7 +1101,10 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)}/* Always-on capability */-arch_timer_c3stop=!(gtdt->non_secure_el1_flags&ACPI_GTDT_ALWAYS_ON);+arch_timer_c3stop=acpi_gtdt_c3stop(arch_timer_uses_ppi);++/* Get the frequency from CNTFRQ */+arch_timer_detect_rate();ret=arch_timer_register();if(ret)
From: Fu Wei <redacted>
On platforms booting with ACPI, architected memory-mapped timers'
configuration data is provided by firmware through the ACPI GTDT
static table.
The clocksource architected timer kernel driver requires a firmware
interface to collect timer configuration and configure its driver.
this infrastructure is present for device tree systems, but it is
missing on systems booting with ACPI.
Implement the kernel infrastructure required to parse the static
ACPI GTDT table so that the architected timer clocksource driver can
make use of it on systems booting with ACPI, therefore enabling
the corresponding timers configuration.
Signed-off-by: Fu Wei <redacted>
Signed-off-by: Hanjun Guo <redacted>
---
drivers/acpi/arm64/gtdt.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 1 +
2 files changed, 125 insertions(+)
From: Fu Wei <redacted>
The patch add memory-mapped timer register support by using the
information provided by the new GTDT driver of ACPI.
Signed-off-by: Fu Wei <redacted>
---
drivers/clocksource/arm_arch_timer.c | 35 ++++++++++++++++++++++++++++++++---
1 file changed, 32 insertions(+), 3 deletions(-)
From: Fu Wei <redacted>
This driver adds support for parsing SBSA Generic Watchdog timer
in GTDT, parse all info in SBSA Generic Watchdog Structure in GTDT,
and creating a platform device with that information.
This allows the operating system to obtain device data from the
resource of platform device. The platform device named "sbsa-gwdt"
can be used by the ARM SBSA Generic Watchdog driver.
Signed-off-by: Fu Wei <redacted>
Signed-off-by: Hanjun Guo <redacted>
Tested-by: Xiongfeng Wang <redacted>
---
drivers/acpi/arm64/gtdt.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/watchdog/Kconfig | 1 +
2 files changed, 94 insertions(+)
@@ -279,3 +287,88 @@ int __init acpi_arch_timer_mem_init(struct arch_timer_mem *data,return0;}++/*+*InitializeaSBSAgenericWatchdogplatformdeviceinfofromGTDT+*/+staticint__initgtdt_import_sbsa_gwdt(structacpi_gtdt_watchdog*wd,+intindex)+{+structplatform_device*pdev;+intirq=map_gt_gsi(wd->timer_interrupt,wd->timer_flags);+intno_irq=1;++/*+*AccordingtoSBSAspecificationthesizeofrefreshandcontrol+*framesofSBSAGenericWatchdogisSZ_4K(Offset0x000?0xFFF).+*/+structresourceres[]={+DEFINE_RES_MEM(wd->control_frame_address,SZ_4K),+DEFINE_RES_MEM(wd->refresh_frame_address,SZ_4K),+DEFINE_RES_IRQ(irq),+};++pr_debug("found a Watchdog (0x%llx/0x%llx gsi:%u flags:0x%x).\n",+wd->refresh_frame_address,wd->control_frame_address,+wd->timer_interrupt,wd->timer_flags);++if(!(wd->refresh_frame_address&&wd->control_frame_address)){+pr_err(FW_BUG"failed to get the Watchdog base address.\n");+return-EINVAL;+}++if(!wd->timer_interrupt)+pr_warn(FW_BUG"failed to get the Watchdog interrupt.\n");+elseif(irq<=0)+pr_warn("failed to map the Watchdog interrupt.\n");+else+no_irq=0;++/*+*Addaplatformdevicenamed"sbsa-gwdt"tomatchtheplatformdriver.+*"sbsa-gwdt":SBSA(ServerBaseSystemArchitecture)GenericWatchdog+*Theplatformdriver(likedrivers/watchdog/sbsa_gwdt.c)cangetdevice+*infobelowbymatchingthisname.+*/+pdev=platform_device_register_simple("sbsa-gwdt",index,res,+ARRAY_SIZE(res)-no_irq);+if(IS_ERR(pdev)){+acpi_unregister_gsi(wd->timer_interrupt);+returnPTR_ERR(pdev);+}++return0;+}++staticint__initgtdt_sbsa_gwdt_init(void)+{+intret,i=0;+void*platform_timer;+structacpi_table_header*table;++if(acpi_disabled)+return0;++if(ACPI_FAILURE(acpi_get_table(ACPI_SIG_GTDT,0,&table)))+return-EINVAL;++ret=acpi_gtdt_init(table,NULL);+if(ret)+returnret;++for_each_platform_timer(platform_timer){+if(is_watchdog(platform_timer)){+ret=gtdt_import_sbsa_gwdt(platform_timer,i);+if(ret)+break;+i++;+}+}++if(i)+pr_info("found %d SBSA generic Watchdog(s).\n",i);++returnret;+}++device_initcall(gtdt_sbsa_gwdt_init);
Hi Mark,
This v19 (I have mentioned it in my previous email) is the latest
patchset which can be applied on v4.10-rc4 directly.
please review this patchset, thanks! :-)
On 21 December 2016 at 14:45, [off-list ref] wrote:
From: Fu Wei <redacted>
This patchset:
(1)Preparation for adding GTDT support in arm_arch_timer:
1. Move some enums and marcos to header file;
2. Add a new enum for spi type;
3. Improve printk relevant code;
4. Rename some enums and defines;
5. Rework PPI determination;
6. Rework counter frequency detection;
7. Refactor arch_timer_needs_probing, move it into DT init call
8. Introduce some new structs and refactor the MMIO timer init code
for reusing some common code.
(2)Introduce ACPI GTDT parser: drivers/acpi/arm64/acpi_gtdt.c
Parse all kinds of timer in GTDT table of ACPI:arch timer,
memory-mapped timer and SBSA Generic Watchdog timer.
This driver can help to simplify all the relevant timer drivers,
and separate all the ACPI GTDT knowledge from them.
(3)Simplify ACPI code for arm_arch_timer
(4)Add GTDT support for ARM memory-mapped timer.
This patchset has been tested on the following platforms with ACPI enabled:
(1)ARM Foundation v8 model
Changelog:
v19: https://lkml.org/lkml/2016/12/21/
Fix a '\n' missing in a error message in arch_timer_mem_init.
Add "request_mem_region" for ioremapping cntbase, according to
f947ee1 clocksource/drivers/arm_arch_timer: Map frame with of_io_request_and_map()
Rebase to 4.9.0-gfb779ff
v18: https://lkml.org/lkml/2016/12/8/446
Fix 8/15 patch problem of "int ret;" in arch_timer_acpi_init.
Rebase to 4.9.0-rc8-g9269898
v17: https://lkml.org/lkml/2016/11/25/140
Take out some cleanups from 4/15.
Merge 5/15 and 6/15, improve PPI determination code,
improve commit message.
Rework counter frequency detection.
Move arch_timer_needs_of_probing into DT init call.
Move Platform Timer scan loop back to timer init call to avoid allocating
and free memory.
Improve all the exported functions' comment.
v16: https://lkml.org/lkml/2016/11/16/268
Fix patchset problem about static enum ppi_nr of 01/13 in v15.
Refactor arch_timer_detect_rate.
Refactor arch_timer_needs_probing.
v15: https://lkml.org/lkml/2016/11/15/366
Re-order patches
Add arm_arch_timer refactoring patches to prepare for GTDT:
1. rename some enums and defines, and some cleanups
2. separate out arch_timer_uses_ppi init code and fix a potential bug
3. Improve some new structs, refactor the timer init code.
Since the some structs have been changed, GTDT parser for memory-mapped
timer and SBSA Generic Watchdog timer have been update.
v14: https://lkml.org/lkml/2016/9/28/573
Separate memory-mapped timer GTDT support into two patches
1. Refactor the timer init code to prepare for GTDT
2. Add GTDT support for memory-mapped timer
v13: http://www.mail-archive.com/linux-kernel at vger.kernel.org/msg1231717.html
Improve arm_arch_timer code for memory-mapped
timer GTDT support, refactor original memory-mapped timer
dt support for reusing some common code.
v12: https://lkml.org/lkml/2016/9/13/250
Rebase to latest Linux 4.8-rc6
Delete the confusing "skipping" in the error message.
V11: https://lkml.org/lkml/2016/9/6/354
Rebase to latest Linux 4.8-rc5
Delete typedef (suggested by checkpatch.pl)
V10: https://lkml.org/lkml/2016/7/26/215
Drop the "readq" patch.
Rebase to latest Linux 4.7.
V9: https://lkml.org/lkml/2016/7/25/345
Improve pr_err message in acpi gtdt driver.
Update Commit message for 7/9
shorten the irq mapping function name
Improve GTDT driver for memory-mapped timer
v8: https://lkml.org/lkml/2016/7/19/660
Improve "pr_fmt(fmt)" definition: add "ACPI" in front of "GTDT",
and also improve printk message.
Simplify is_timer_block and is_watchdog.
Merge acpi_gtdt_desc_init and gtdt_arch_timer_init into acpi_gtdt_init();
Delete __init in include/linux/acpi.h for GTDT API
Make ARM64 select GTDT.
Delete "#include <linux/module.h>" from acpi_gtdt.c
Simplify GT block parse code.
v7: https://lkml.org/lkml/2016/7/13/769
Move the GTDT driver to drivers/acpi/arm64
Add add the ARM64-specific ACPI Support maintainers in MAINTAINERS
Merge 3 patches of GTDT parser driver.
Fix the for_each_platform_timer bug.
v6: https://lkml.org/lkml/2016/6/29/580
split the GTDT driver to 4 parts: basic, arch_timer, memory-mapped timer,
and SBSA Generic Watchdog timer
Improve driver by suggestions and example code from Daniel Lezcano
v5: https://lkml.org/lkml/2016/5/24/356
Sorting out all patches, simplify the API of GTDT driver:
GTDT driver just fills the data struct for arm_arch_timer driver.
v4: https://lists.linaro.org/pipermail/linaro-acpi/2016-March/006667.html
Delete the kvm relevant patches
Separate two patches for sorting out the code for arm_arch_timer.
Improve irq info export code to allow missing irq info in GTDT table.
v3: https://lkml.org/lkml/2016/2/1/658
Improve GTDT driver code:
(1)improve pr_* by defining pr_fmt(fmt)
(2)simplify gtdt_sbsa_gwdt_init
(3)improve gtdt_arch_timer_data_init, if table is NULL, it will try
to get GTDT table.
Move enum ppi_nr to arm_arch_timer.h, and add enum spi_nr.
Add arm_arch_timer get ppi from DT and GTDT support for kvm.
v2: https://lkml.org/lkml/2015/12/2/10
Rebase to latest kernel version(4.4-rc3).
Fix the bug about the config problem,
use CONFIG_ACPI_GTDT instead of CONFIG_ACPI in arm_arch_timer.c
v1: The first upstreaming version: https://lkml.org/lkml/2015/10/28/553
Fu Wei (15):
clocksource/drivers/arm_arch_timer: Move enums and defines to header
file
clocksource/drivers/arm_arch_timer: Add a new enum for spi type
clocksource/drivers/arm_arch_timer: Improve printk relevant code
clocksource/drivers/arm_arch_timer: rename some enums and defines.
clocksource/drivers/arm_arch_timer: rework PPI determination
clocksource/drivers/arm_arch_timer: Rework counter frequency
detection.
clocksource/drivers/arm_arch_timer: Refactor arch_timer_needs_probing
clocksource/drivers/arm_arch_timer: move arch_timer_needs_of_probing
into DT init call
clocksource/drivers/arm_arch_timer: Introduce some new structs to
prepare for GTDT
clocksource/drivers/arm_arch_timer: Refactor the timer init code to
prepare for GTDT
acpi/arm64: Add GTDT table parse driver
clocksource/drivers/arm_arch_timer: Simplify ACPI support code.
acpi/arm64: Add memory-mapped timer support in GTDT driver
clocksource/drivers/arm_arch_timer: Add GTDT support for memory-mapped
timer
acpi/arm64: Add SBSA Generic Watchdog support in GTDT driver
arch/arm64/Kconfig | 1 +
drivers/acpi/arm64/Kconfig | 3 +
drivers/acpi/arm64/Makefile | 1 +
drivers/acpi/arm64/gtdt.c | 374 +++++++++++++++++++++++++++
drivers/clocksource/arm_arch_timer.c | 483 ++++++++++++++++++++---------------
drivers/watchdog/Kconfig | 1 +
include/clocksource/arm_arch_timer.h | 45 +++-
include/linux/acpi.h | 7 +
virt/kvm/arm/hyp/timer-sr.c | 6 +-
9 files changed, 712 insertions(+), 209 deletions(-)
create mode 100644 drivers/acpi/arm64/gtdt.c
--
2.9.3
From: Mark Rutland <mark.rutland@arm.com> Date: 2017-01-16 12:02:29
On Mon, Jan 16, 2017 at 02:26:54PM +0800, Fu Wei wrote:
Hi Mark,
This v19 (I have mentioned it in my previous email) is the latest
patchset which can be applied on v4.10-rc4 directly.
please review this patchset, thanks! :-)
Thanks for the pointer; I will look at this shortly.
Mark.
Hi Mark,
On 16 January 2017 at 20:01, Mark Rutland [off-list ref] wrote:
On Mon, Jan 16, 2017 at 02:26:54PM +0800, Fu Wei wrote:
quoted
Hi Mark,
This v19 (I have mentioned it in my previous email) is the latest
patchset which can be applied on v4.10-rc4 directly.
please review this patchset, thanks! :-)
Thanks for the pointer; I will look at this shortly.
Great thanks, looking forward to your feedback! :-)
From: Mark Rutland <mark.rutland@arm.com> Date: 2017-01-16 17:01:22
Hi,
On Wed, Dec 21, 2016 at 02:45:48PM +0800, fu.wei at linaro.org wrote:
From: Fu Wei <redacted>
This patchset:
(1)Preparation for adding GTDT support in arm_arch_timer:
1. Move some enums and marcos to header file;
2. Add a new enum for spi type;
3. Improve printk relevant code;
4. Rename some enums and defines;
Can we please rework these first few patches into a series:
1. Clean up printk() usage
2. Rename the type macros
3. Rename the PPI enum & enum values
4. Move the type macro and PPI enum into a header
5. Add new enum for SPIs
Please leave CNTHCL_* as they originally were. It's not part of the
interface of the driver, and leaving them as they are will save us an
interdependency with KVM.
I'm happy to queue that immediately, as it's purely structural and
shouldn't have a functional impact anywhere. That will also shrink the
series a bit, and we can rebase the following patches atop of that.
5. Rework PPI determination;
6. Rework counter frequency detection;
7. Refactor arch_timer_needs_probing, move it into DT init call
8. Introduce some new structs and refactor the MMIO timer init code
for reusing some common code.
I'll review these in separate replies.
Thanks,
Mark.
For a 32-bit platform booted at hyp (with a virt PPI available), the new
logic will select ARCH_TIMER_VIRT_PPI. I beleive that will break KVM.
I think the logic should be:
if (is_kernel_in_hyp_mode())
return ARCH_TIMER_HYP_PPI;
if (!is_hyp_mode_available() &&
arch_timer_ppi[ARCH_TIMER_VIRT_PPI])
return ARCH_TIMER_VIRT_PPI;
if (IS_ENABLED(CONFIG_ARM64))
return ARCH_TIMER_PHYS_NONSECURE_PPI;
return ARCH_TIMER_PHYS_SECURE_PPI;
Please use that instead (keeping the comment you retained).
quoted hunk
+static int __init arch_timer_init(void)
+{
+ int ret;
ret = arch_timer_register();
if (ret)
@@ -904,6 +906,13 @@ static int __init arch_timer_of_init(struct device_node *np) if (IS_ENABLED(CONFIG_ARM) && of_property_read_bool(np, "arm,cpu-registers-not-fw-configured")) arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;+ else+ arch_timer_uses_ppi = arch_timer_select_ppi();++ if (!arch_timer_ppi[arch_timer_uses_ppi]) {+ pr_err("No interrupt available, giving up\n");+ return -EINVAL;+ } /* On some systems, the counter stops ticking when in suspend. */ arch_counter_suspend_stop = of_property_read_bool(np,
@@ -1049,6 +1058,12 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table) /* Get the frequency from CNTFRQ */ arch_timer_detect_rate(NULL, NULL);+ arch_timer_uses_ppi = arch_timer_select_ppi();+ if (!arch_timer_ppi[arch_timer_uses_ppi]) {+ pr_err("No interrupt available, giving up\n");+ return -EINVAL;+ }
I see that we have to duplicate this so we can special-case the
DT-specific behaviour, so that's fine by me.
If you can fix the arch_timer_select_ppi() logic as above, this should
be fine.
Thanks,
Mark.
From: Mark Rutland <mark.rutland@arm.com> Date: 2017-01-16 17:51:32
On Wed, Dec 21, 2016 at 02:45:54PM +0800, fu.wei at linaro.org wrote:
From: Fu Wei <redacted>
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.
quoted hunk
Signed-off-by: Fu Wei <redacted>
Tested-by: Xiongfeng Wang <redacted>
---
drivers/clocksource/arm_arch_timer.c | 49 +++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 18 deletions(-)
@@ -488,27 +488,31 @@ static int arch_timer_starting_cpu(unsigned int cpu)return0;}-staticvoid-arch_timer_detect_rate(void__iomem*cntbase,structdevice_node*np)+staticvoidarch_timer_detect_rate(void){-/* Who has more than one independent system counter? */-if(arch_timer_rate)-return;+/*+*Trytogetthetimerfrequencyfrom+*cntfrq_el0(systemcoprocessorregister).+*/+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");+}+staticvoidarch_timer_mem_detect_rate(void__iomem*cntbase)+{/*-*TrytodeterminethefrequencyfromthedevicetreeorCNTFRQ,-*ifACPIisenabled,getthefrequencyfromCNTFRQONLY.+*Trytodeterminethefrequencyfrom+*CNTFRQinmemory-mappedtimer.*/-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.
From: Mark Rutland <mark.rutland@arm.com> Date: 2017-01-16 18:31:50
On Wed, Dec 21, 2016 at 02:45:58PM +0800, fu.wei at linaro.org wrote:
From: Fu Wei <redacted>
The patch refactor original memory-mapped timer init code:
(1) Refactor "arch_timer_mem_init", make it become a common code for
memory-mapped timer init.
(2) Add a new function "arch_timer_mem_of_init" for DT init.
As a general note, please write proper commit messages, describing what
the problem is, and why we are making the changes. These bullet points
don't add anything to what can be derived from a glance at the code.
For this patch, you can use:
clocksource: arm_arch_timer: refactor MMIO timer probing
Currently the code to probe MMIO architected timers mixes DT parsing
with actual poking of hardware. This makes the code harder than
necessary to understand, and makes it difficult to add support for
probing via ACPI.
This patch factors all the DT-specific logic out of
arch_timer_mem_init(), into a new function, arch_timer_mem_of_init().
The former pokes the hardware and determines the suitablility of
frames based on a datastructure populated by the latter.
This cleanly separates the two and will make it possible to add
probing using the ACPI GTDT in subsequent patches.
[...]
Hi Mark,
On 17 January 2017 at 01:00, Mark Rutland [off-list ref] wrote:
Hi,
On Wed, Dec 21, 2016 at 02:45:48PM +0800, fu.wei at linaro.org wrote:
quoted
From: Fu Wei <redacted>
This patchset:
(1)Preparation for adding GTDT support in arm_arch_timer:
1. Move some enums and marcos to header file;
2. Add a new enum for spi type;
3. Improve printk relevant code;
4. Rename some enums and defines;
Can we please rework these first few patches into a series:
1. Clean up printk() usage
2. Rename the type macros
3. Rename the PPI enum & enum values
4. Move the type macro and PPI enum into a header
5. Add new enum for SPIs
Please leave CNTHCL_* as they originally were. It's not part of the
interface of the driver, and leaving them as they are will save us an
interdependency with KVM.
I'm happy to queue that immediately, as it's purely structural and
shouldn't have a functional impact anywhere. That will also shrink the
series a bit, and we can rebase the following patches atop of that.
5. Rework PPI determination;
6. Rework counter frequency detection;
7. Refactor arch_timer_needs_probing, move it into DT init call
8. Introduce some new structs and refactor the MMIO timer init code
for reusing some common code.
I'll review these in separate replies.
Thanks,
Mark.
Hi Mark,
On 17 January 2017 at 02:30, Mark Rutland [off-list ref] wrote:
On Wed, Dec 21, 2016 at 02:45:58PM +0800, fu.wei at linaro.org wrote:
quoted
From: Fu Wei <redacted>
The patch refactor original memory-mapped timer init code:
(1) Refactor "arch_timer_mem_init", make it become a common code for
memory-mapped timer init.
(2) Add a new function "arch_timer_mem_of_init" for DT init.
As a general note, please write proper commit messages, describing what
the problem is, and why we are making the changes. These bullet points
don't add anything to what can be derived from a glance at the code.
For this patch, you can use:
clocksource: arm_arch_timer: refactor MMIO timer probing
Currently the code to probe MMIO architected timers mixes DT parsing
with actual poking of hardware. This makes the code harder than
necessary to understand, and makes it difficult to add support for
probing via ACPI.
This patch factors all the DT-specific logic out of
arch_timer_mem_init(), into a new function, arch_timer_mem_of_init().
The former pokes the hardware and determines the suitablility of
frames based on a datastructure populated by the latter.
This cleanly separates the two and will make it possible to add
probing using the ACPI GTDT in subsequent patches.
Great thanks for this upstream tip.
I have used your example commit message instead.
It will be in v20.
It would be good if we could warn upon seeing more than
ARCH_TIMER_MEM_MAX_FRAMES children, since that's obviously an error.
OK, NP, will use
if (i >= ARCH_TIMER_MEM_MAX_FRAMES) {
pr_err(FW_BUG "too many frames, ARMv8 spec only allows 8.\n");
goto out;
}
at the beginning of this loop.
Here will be replaced by i++;
Great thanks for your suggestion!
Hi Mark,
On 17 January 2017 at 18:30, Fu Wei [off-list ref] wrote:
Hi Mark,
On 17 January 2017 at 02:30, Mark Rutland [off-list ref] wrote:
quoted
On Wed, Dec 21, 2016 at 02:45:58PM +0800, fu.wei at linaro.org wrote:
quoted
From: Fu Wei <redacted>
The patch refactor original memory-mapped timer init code:
(1) Refactor "arch_timer_mem_init", make it become a common code for
memory-mapped timer init.
(2) Add a new function "arch_timer_mem_of_init" for DT init.
As a general note, please write proper commit messages, describing what
the problem is, and why we are making the changes. These bullet points
don't add anything to what can be derived from a glance at the code.
For this patch, you can use:
clocksource: arm_arch_timer: refactor MMIO timer probing
Currently the code to probe MMIO architected timers mixes DT parsing
with actual poking of hardware. This makes the code harder than
necessary to understand, and makes it difficult to add support for
probing via ACPI.
This patch factors all the DT-specific logic out of
arch_timer_mem_init(), into a new function, arch_timer_mem_of_init().
The former pokes the hardware and determines the suitablility of
frames based on a datastructure populated by the latter.
This cleanly separates the two and will make it possible to add
probing using the ACPI GTDT in subsequent patches.
Great thanks for this upstream tip.
I have used your example commit message instead.
It will be in v20.
From: Timur Tabi <hidden> Date: 2017-01-17 12:18:25
Fu Wei wrote:
if (i >= ARCH_TIMER_MEM_MAX_FRAMES) {
pr_err(FW_BUG "too many frames, ARMv8 spec only allows 8.\n");
pr_err(FW_BUG "too many frames, ARMv8 spec only allows %u.\n",
ARCH_TIMER_MEM_MAX_FRAMES);
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the
Code Aurora Forum, hosted by The Linux Foundation.
From: Mark Rutland <mark.rutland@arm.com> Date: 2017-01-17 12:37:05
On Tue, Jan 17, 2017 at 06:18:12AM -0600, Timur Tabi wrote:
Fu Wei wrote:
quoted
if (i >= ARCH_TIMER_MEM_MAX_FRAMES) {
pr_err(FW_BUG "too many frames, ARMv8 spec only allows 8.\n");
pr_err(FW_BUG "too many frames, ARMv8 spec only allows %u.\n",
ARCH_TIMER_MEM_MAX_FRAMES);
While I don't see ARCH_TIMER_MEM_MAX_FRAMES changing, this would be
nicer to ensure the result obviously matches.
As for wording, I'd perfer:
pr_err(FW_BUG "too many frames, only %u are permitted.\n",
ARCH_TIMER_MEM_MAX_FRAMES);
... so as to avoid any confusion between spec versions and so on. We can
reconsider the message if/when that changes.
Thanks,
Mark.
Hi Mark,
On 17 January 2017 at 20:29, Mark Rutland [off-list ref] wrote:
On Tue, Jan 17, 2017 at 06:18:12AM -0600, Timur Tabi wrote:
quoted
Fu Wei wrote:
quoted
if (i >= ARCH_TIMER_MEM_MAX_FRAMES) {
pr_err(FW_BUG "too many frames, ARMv8 spec only allows 8.\n");
pr_err(FW_BUG "too many frames, ARMv8 spec only allows %u.\n",
ARCH_TIMER_MEM_MAX_FRAMES);
While I don't see ARCH_TIMER_MEM_MAX_FRAMES changing, this would be
nicer to ensure the result obviously matches.
As for wording, I'd perfer:
pr_err(FW_BUG "too many frames, only %u are permitted.\n",
ARCH_TIMER_MEM_MAX_FRAMES);
OK, will do so.
Thanks!
... so as to avoid any confusion between spec versions and so on. We can
reconsider the message if/when that changes.
Thanks,
Mark.
For a 32-bit platform booted at hyp (with a virt PPI available), the new
logic will select ARCH_TIMER_VIRT_PPI. I beleive that will break KVM.
I think the logic should be:
if (is_kernel_in_hyp_mode())
return ARCH_TIMER_HYP_PPI;
if (!is_hyp_mode_available() &&
arch_timer_ppi[ARCH_TIMER_VIRT_PPI])
return ARCH_TIMER_VIRT_PPI;
if (IS_ENABLED(CONFIG_ARM64))
return ARCH_TIMER_PHYS_NONSECURE_PPI;
return ARCH_TIMER_PHYS_SECURE_PPI;
Please use that instead (keeping the comment you retained).
Great thanks for pointing it out, that is bug.
also got this bug report from Huawei engineer.
I have fixed it using your example code, thanks!
quoted
+static int __init arch_timer_init(void)
+{
+ int ret;
ret = arch_timer_register();
if (ret)
@@ -904,6 +906,13 @@ static int __init arch_timer_of_init(struct device_node *np) if (IS_ENABLED(CONFIG_ARM) && of_property_read_bool(np, "arm,cpu-registers-not-fw-configured")) arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;+ else+ arch_timer_uses_ppi = arch_timer_select_ppi();++ if (!arch_timer_ppi[arch_timer_uses_ppi]) {+ pr_err("No interrupt available, giving up\n");+ return -EINVAL;+ } /* On some systems, the counter stops ticking when in suspend. */ arch_counter_suspend_stop = of_property_read_bool(np,
@@ -1049,6 +1058,12 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table) /* Get the frequency from CNTFRQ */ arch_timer_detect_rate(NULL, NULL);+ arch_timer_uses_ppi = arch_timer_select_ppi();+ if (!arch_timer_ppi[arch_timer_uses_ppi]) {+ pr_err("No interrupt available, giving up\n");+ return -EINVAL;+ }
I see that we have to duplicate this so we can special-case the
DT-specific behaviour, so that's fine by me.
Yes, that is the reason of the duplication :-)
If you can fix the arch_timer_select_ppi() logic as above, this should
be fine.
Hi Mark,
On 17 January 2017 at 01:50, Mark Rutland [off-list ref] wrote:
On Wed, Dec 21, 2016 at 02:45:54PM +0800, fu.wei at linaro.org wrote:
quoted
From: Fu Wei <redacted>
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.
OK , will do
quoted
Separate out the MMIO frequency and the sysreg frequency detection call,
and use the appropriate one for the counter.
quoted
Signed-off-by: Fu Wei <redacted>
Tested-by: Xiongfeng Wang <redacted>
---
drivers/clocksource/arm_arch_timer.c | 49 +++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 18 deletions(-)
@@ -488,27 +488,31 @@ static int arch_timer_starting_cpu(unsigned int cpu)return0;}-staticvoid-arch_timer_detect_rate(void__iomem*cntbase,structdevice_node*np)+staticvoidarch_timer_detect_rate(void){-/* Who has more than one independent system counter? */-if(arch_timer_rate)-return;+/*+*Trytogetthetimerfrequencyfrom+*cntfrq_el0(systemcoprocessorregister).+*/+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");+}+staticvoidarch_timer_mem_detect_rate(void__iomem*cntbase)+{/*-*TrytodeterminethefrequencyfromthedevicetreeorCNTFRQ,-*ifACPIisenabled,getthefrequencyfromCNTFRQONLY.+*Trytodeterminethefrequencyfrom+*CNTFRQinmemory-mappedtimer.*/-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)
I think you mean this one, this is for keeping consistency with
arch_timer_detect_rate.
quoted
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,
Yes, I am doing this way,
For sysreg rates,
static void arch_timer_detect_rate(void)
{
/*
* 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");
}
For MMIO timer,
static void arch_timer_mem_detect_rate(void __iomem *cntbase)
{
/*
* Try to determine the frequency from
* CNTFRQ in memory-mapped timer.
*/
if (!arch_timer_rate)
arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);
/* Check the timer frequency. */
if (!arch_timer_rate)
pr_warn("frequency not available\n");
}
in arch_time_*_init, only call arch_timer_detect_rate,
in arch_timer_mem_init, only call arch_timer_mem_detect_rate.
But you are right, this is fairly gnarly regardless.
and kill the implicit relationship between the two, or at least make one
canonical and warn if the two differ.
So I think maybe we can do this:
static void __arch_timer_determine_rate(u32 rate)
{
/* Check the timer frequency. */
if (!arch_timer_rate)
if (rate)
arch_timer_rate = rate;
else
pr_warn("frequency not available\n");
else if (arch_timer_rate != rate)
pr_warn("got different frequency, keep original.\n");
}
static void arch_timer_detect_rate(void)
{
/*
* Try to get the timer frequency from
* cntfrq_el0(system coprocessor register).
*/
__arch_timer_determine_rate(arch_timer_get_cntfrq());
}
static void arch_timer_mem_detect_rate(void __iomem *cntbase)
{
/*
* Try to get the timer frequency from
* CNTFRQ in the MMIO timer.
*/
__arch_timer_determine_rate(readl_relaxed(cntbase + CNTFRQ));
}
any thought?