From: Fu Wei fu.wei@linaro.org
This patchset: (1)Preparation for adding GTDT support in arm_arch_timer: 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 the header file 5. Add new enum for SPIs 6. Rework PPI determination; 7. Rework counter frequency detection; 8. Refactor arch_timer_needs_probing, move it into DT init call 9. 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: v20: https://lkml.org/lkml/2017/1/18/ Reorder the first 4 patches and split the 4th patches. Leave CNTHCTL_* as they originally were. Fix the bug in arch_timer_select_ppi. Split "Rework counter frequency detection" patch. Rework the arch_timer_detect_rate function. Improve the commit message of "Refactor MMIO timer probing". Rebase to 4.10.0-rc4
v19: https://lkml.org/lkml/2016/12/21/25 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@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 (17): clocksource/drivers/arm_arch_timer: Improve printk relevant code clocksource/drivers/arm_arch_timer: Rename the timer type macros. clocksource/drivers/arm_arch_timer: Rename the PPI enum and its values. 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: rework PPI determination clocksource/drivers/arm_arch_timer: Separate out device-tree code from arch_timer_detect_rate 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 MMIO timer probing. 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 | 497 +++++++++++++++++++++-------------- drivers/watchdog/Kconfig | 1 + include/clocksource/arm_arch_timer.h | 35 +++ include/linux/acpi.h | 7 + 8 files changed, 717 insertions(+), 202 deletions(-) create mode 100644 drivers/acpi/arm64/gtdt.c
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org Acked-by: Mark Rutland mark.rutland@arm.com Tested-by: Xiongfeng Wang wangxiongfeng2@huawei.com --- drivers/clocksource/arm_arch_timer.c | 49 ++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 24 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 4c8c3fb..923bd5c 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -32,6 +32,9 @@
#include <clocksource/arm_arch_timer.h>
+#undef pr_fmt +#define pr_fmt(fmt) "arch_timer: " fmt + #define CNTTIDR 0x08 #define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4))
@@ -516,22 +519,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"); }
static void arch_timer_banner(unsigned type) { - 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" : "", - (unsigned long)arch_timer_rate / 1000000, - (unsigned long)(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 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" : "", + (unsigned long)arch_timer_rate / 1000000, + (unsigned long)(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" : ""); } @@ -632,8 +635,7 @@ static void __init arch_counter_register(unsigned type)
static void arch_timer_stop(struct clock_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()) @@ -726,8 +728,7 @@ static int __init arch_timer_register(void) }
if (err) { - pr_err("arch_timer: can't register interrupt %d (%d)\n", - ppi, err); + pr_err("can't register interrupt %d (%d)\n", ppi, err); goto out_free; }
@@ -780,7 +781,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); }
@@ -858,7 +859,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; } } @@ -872,7 +873,7 @@ static int __init arch_timer_init(void) return ret;
arch_timer_kvm_info.virtual_irq = arch_timer_ppi[VIRT_PPI]; - + return 0; }
@@ -881,7 +882,7 @@ static int __init arch_timer_of_init(struct device_node *np) int i;
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"); return 0; }
@@ -929,7 +930,7 @@ static int __init arch_timer_mem_init(struct device_node *np) arch_timers_present |= ARCH_MEM_TIMER; cntctlbase = of_iomap(np, 0); if (!cntctlbase) { - pr_err("arch_timer: Can't find CNTCTLBase\n"); + pr_err("Can't find CNTCTLBase\n"); return -ENXIO; }
@@ -944,7 +945,7 @@ static int __init arch_timer_mem_init(struct device_node *np) u32 cntacr;
if (of_property_read_u32(frame, "frame-number", &n)) { - pr_err("arch_timer: Missing frame-number\n"); + pr_err("Missing frame-number\n"); of_node_put(frame); goto out; } @@ -974,7 +975,7 @@ static int __init arch_timer_mem_init(struct device_node *np) base = arch_counter_base = of_io_request_and_map(best_frame, 0, "arch_mem_timer"); if (IS_ERR(base)) { - pr_err("arch_timer: Can't map frame's registers\n"); + pr_err("Can't map frame's registers\n"); goto out; }
@@ -985,7 +986,7 @@ static int __init arch_timer_mem_init(struct device_node *np)
ret = -EINVAL; if (!irq) { - pr_err("arch_timer: Frame missing %s irq", + pr_err("Frame missing %s irq.\n", arch_timer_mem_use_virtual ? "virt" : "phys"); goto out; } @@ -1027,7 +1028,7 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table) struct acpi_table_gtdt *gtdt;
if (arch_timers_present & ARCH_CP15_TIMER) { - pr_warn("arch_timer: already initialized, skipping\n"); + pr_warn("already initialized, skipping\n"); return -EINVAL; }
From: Fu Wei fu.wei@linaro.org
Rename the timer type macros to unify the format of macros in arm_arch_timer.c, also update all the users of these macros.
No functional change.
Signed-off-by: Fu Wei fu.wei@linaro.org Tested-by: Xiongfeng Wang wangxiongfeng2@huawei.com --- drivers/clocksource/arm_arch_timer.c | 43 +++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 20 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 923bd5c..36998db 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -54,8 +54,8 @@ #define CNTV_TVAL 0x38 #define CNTV_CTL 0x3c
-#define ARCH_CP15_TIMER BIT(0) -#define ARCH_MEM_TIMER BIT(1) +#define ARCH_TIMER_TYPE_CP15 BIT(0) +#define ARCH_TIMER_TYPE_MEM BIT(1) static unsigned arch_timers_present __initdata;
static void __iomem *arch_counter_base; @@ -364,7 +364,7 @@ static void __arch_timer_setup(unsigned type, { clk->features = CLOCK_EVT_FEAT_ONESHOT;
- if (type == ARCH_CP15_TIMER) { + if (type == ARCH_TIMER_TYPE_CP15) { if (arch_timer_c3stop) clk->features |= CLOCK_EVT_FEAT_C3STOP; clk->name = "arch_sys_timer"; @@ -481,7 +481,7 @@ static int arch_timer_starting_cpu(unsigned int cpu) struct clock_event_device *clk = this_cpu_ptr(arch_timer_evt); u32 flags;
- __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); @@ -525,16 +525,17 @@ arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np) static void arch_timer_banner(unsigned type) { 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" : "", (unsigned long)arch_timer_rate / 1000000, (unsigned long)(arch_timer_rate / 10000) % 100, - type & ARCH_CP15_TIMER ? + type & ARCH_TIMER_TYPE_CP15 ? (arch_timer_uses_ppi == 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" : ""); } @@ -600,7 +601,7 @@ static void __init arch_counter_register(unsigned type) u64 start_count;
/* Register the CP15 based counter if we have one */ - if (type & ARCH_CP15_TIMER) { + if (type & ARCH_TIMER_TYPE_CP15) { if (IS_ENABLED(CONFIG_ARM64) || arch_timer_uses_ppi == VIRT_PPI) arch_timer_read_counter = arch_counter_get_cntvct; else @@ -772,7 +773,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; @@ -815,13 +816,15 @@ arch_timer_needs_probing(int type, const struct of_device_id *matches)
static int __init arch_timer_common_init(void) { - unsigned mask = ARCH_CP15_TIMER | ARCH_MEM_TIMER; + unsigned mask = 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)) return 0; - 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)) return 0; }
@@ -881,12 +884,12 @@ static int __init arch_timer_of_init(struct device_node *np) { int i;
- if (arch_timers_present & ARCH_CP15_TIMER) { + if (arch_timers_present & ARCH_TIMER_TYPE_CP15) { pr_warn("multiple nodes in dt, skipping\n"); return 0; }
- arch_timers_present |= ARCH_CP15_TIMER; + arch_timers_present |= ARCH_TIMER_TYPE_CP15; for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
@@ -927,7 +930,7 @@ static int __init arch_timer_mem_init(struct device_node *np) unsigned int irq, ret = -EINVAL; u32 cnttidr;
- arch_timers_present |= ARCH_MEM_TIMER; + arch_timers_present |= ARCH_TIMER_TYPE_MEM; cntctlbase = of_iomap(np, 0); if (!cntctlbase) { pr_err("Can't find CNTCTLBase\n"); @@ -1027,14 +1030,14 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table) { struct acpi_table_gtdt *gtdt;
- if (arch_timers_present & ARCH_CP15_TIMER) { + if (arch_timers_present & ARCH_TIMER_TYPE_CP15) { pr_warn("already initialized, skipping\n"); return -EINVAL; }
gtdt = container_of(table, struct acpi_table_gtdt, header);
- arch_timers_present |= ARCH_CP15_TIMER; + arch_timers_present |= ARCH_TIMER_TYPE_CP15;
arch_timer_ppi[PHYS_SECURE_PPI] = map_generic_timer_interrupt(gtdt->secure_el1_interrupt,
From: Fu Wei fu.wei@linaro.org
Rename the PPI enum and its values to unify the format of enum in arm_arch_timer.c, also update all the users of this enum.
No functional change.
Signed-off-by: Fu Wei fu.wei@linaro.org Tested-by: Xiongfeng Wang wangxiongfeng2@huawei.com --- drivers/clocksource/arm_arch_timer.c | 84 ++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 41 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 36998db..d5a1664 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -69,19 +69,19 @@ struct arch_timer {
static u32 arch_timer_rate;
-enum ppi_nr { - PHYS_SECURE_PPI, - PHYS_NONSECURE_PPI, - VIRT_PPI, - HYP_PPI, - MAX_TIMER_PPI +enum arch_timer_ppi_nr { + ARCH_TIMER_PHYS_SECURE_PPI, + ARCH_TIMER_PHYS_NONSECURE_PPI, + ARCH_TIMER_VIRT_PPI, + ARCH_TIMER_HYP_PPI, + ARCH_TIMER_MAX_TIMER_PPI };
-static int arch_timer_ppi[MAX_TIMER_PPI]; +static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI];
static struct clock_event_device __percpu *arch_timer_evt;
-static enum ppi_nr arch_timer_uses_ppi = VIRT_PPI; +static enum arch_timer_ppi_nr arch_timer_uses_ppi = ARCH_TIMER_VIRT_PPI; static bool arch_timer_c3stop; static bool arch_timer_mem_use_virtual; static bool arch_counter_suspend_stop; @@ -352,7 +352,7 @@ static void fsl_a008585_set_sne(struct clock_event_device *clk) if (!static_branch_unlikely(&arch_timer_read_ool_enabled)) return;
- if (arch_timer_uses_ppi == VIRT_PPI) + if (arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI) clk->set_next_event = fsl_a008585_set_next_event_virt; else clk->set_next_event = fsl_a008585_set_next_event_phys; @@ -372,14 +372,14 @@ static void __arch_timer_setup(unsigned type, clk->cpumask = cpumask_of(smp_processor_id()); clk->irq = arch_timer_ppi[arch_timer_uses_ppi]; switch (arch_timer_uses_ppi) { - case VIRT_PPI: + case ARCH_TIMER_VIRT_PPI: clk->set_state_shutdown = arch_timer_shutdown_virt; clk->set_state_oneshot_stopped = arch_timer_shutdown_virt; clk->set_next_event = arch_timer_set_next_event_virt; break; - case PHYS_SECURE_PPI: - case PHYS_NONSECURE_PPI: - case HYP_PPI: + case ARCH_TIMER_PHYS_SECURE_PPI: + case ARCH_TIMER_PHYS_NONSECURE_PPI: + case ARCH_TIMER_HYP_PPI: clk->set_state_shutdown = arch_timer_shutdown_phys; clk->set_state_oneshot_stopped = arch_timer_shutdown_phys; clk->set_next_event = arch_timer_set_next_event_phys; @@ -459,8 +459,8 @@ static void arch_counter_set_user_access(void)
static bool arch_timer_has_nonsecure_ppi(void) { - return (arch_timer_uses_ppi == PHYS_SECURE_PPI && - arch_timer_ppi[PHYS_NONSECURE_PPI]); + return (arch_timer_uses_ppi == ARCH_TIMER_PHYS_SECURE_PPI && + arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]); }
static u32 check_ppi_trigger(int irq) @@ -487,8 +487,9 @@ static int arch_timer_starting_cpu(unsigned int cpu) 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(); @@ -532,7 +533,7 @@ static void arch_timer_banner(unsigned type) (unsigned long)arch_timer_rate / 1000000, (unsigned long)(arch_timer_rate / 10000) % 100, type & ARCH_TIMER_TYPE_CP15 ? - (arch_timer_uses_ppi == VIRT_PPI) ? "virt" : "phys" : + (arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI) ? "virt" : "phys" : "", type == (ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM) ? "/" : "", type & ARCH_TIMER_TYPE_MEM ? @@ -602,7 +603,8 @@ static void __init arch_counter_register(unsigned type)
/* Register the CP15 based counter if we have one */ if (type & ARCH_TIMER_TYPE_CP15) { - if (IS_ENABLED(CONFIG_ARM64) || arch_timer_uses_ppi == VIRT_PPI) + if (IS_ENABLED(CONFIG_ARM64) || + arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI) arch_timer_read_counter = arch_counter_get_cntvct; else arch_timer_read_counter = arch_counter_get_cntpct; @@ -640,7 +642,7 @@ static void arch_timer_stop(struct clock_event_device *clk)
disable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi]); if (arch_timer_has_nonsecure_ppi()) - disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]); + disable_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);
clk->set_state_shutdown(clk); } @@ -703,24 +705,24 @@ static int __init arch_timer_register(void)
ppi = arch_timer_ppi[arch_timer_uses_ppi]; switch (arch_timer_uses_ppi) { - case VIRT_PPI: + case ARCH_TIMER_VIRT_PPI: err = request_percpu_irq(ppi, arch_timer_handler_virt, "arch_timer", arch_timer_evt); break; - case PHYS_SECURE_PPI: - case PHYS_NONSECURE_PPI: + case ARCH_TIMER_PHYS_SECURE_PPI: + case ARCH_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; - case HYP_PPI: + case ARCH_TIMER_HYP_PPI: err = request_percpu_irq(ppi, arch_timer_handler_phys, "arch_timer", arch_timer_evt); break; @@ -752,7 +754,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: @@ -849,16 +851,16 @@ static int __init arch_timer_init(void) * their CNTHP_*_EL2 counterparts, and use a different PPI * number. */ - if (is_hyp_mode_available() || !arch_timer_ppi[VIRT_PPI]) { + if (is_hyp_mode_available() || !arch_timer_ppi[ARCH_TIMER_VIRT_PPI]) { bool has_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) { @@ -875,7 +877,7 @@ static int __init arch_timer_init(void) if (ret) return ret;
- arch_timer_kvm_info.virtual_irq = arch_timer_ppi[VIRT_PPI]; + arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
return 0; } @@ -890,7 +892,7 @@ static int __init arch_timer_of_init(struct device_node *np) }
arch_timers_present |= ARCH_TIMER_TYPE_CP15; - for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) + 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); @@ -912,7 +914,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, @@ -1039,19 +1041,19 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
arch_timers_present |= ARCH_TIMER_TYPE_CP15;
- arch_timer_ppi[PHYS_SECURE_PPI] = + arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI] = map_generic_timer_interrupt(gtdt->secure_el1_interrupt, gtdt->secure_el1_flags);
- arch_timer_ppi[PHYS_NONSECURE_PPI] = + arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI] = map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt, gtdt->non_secure_el1_flags);
- arch_timer_ppi[VIRT_PPI] = + arch_timer_ppi[ARCH_TIMER_VIRT_PPI] = map_generic_timer_interrupt(gtdt->virtual_timer_interrupt, gtdt->virtual_timer_flags);
- arch_timer_ppi[HYP_PPI] = + arch_timer_ppi[ARCH_TIMER_HYP_PPI] = map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt, gtdt->non_secure_el2_flags);
From: Fu Wei fu.wei@linaro.org
To support the arm_arch_timer via ACPI we need to share defines and enums between the driver and the ACPI parser code. So we split out the relevant defines and enums into arm_arch_timer.h.
No functional change.
Signed-off-by: Fu Wei fu.wei@linaro.org Acked-by: Mark Rutland mark.rutland@arm.com Tested-by: Xiongfeng Wang wangxiongfeng2@huawei.com --- drivers/clocksource/arm_arch_timer.c | 11 ----------- include/clocksource/arm_arch_timer.h | 12 ++++++++++++ 2 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index d5a1664..90b6661 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -54,8 +54,6 @@ #define CNTV_TVAL 0x38 #define CNTV_CTL 0x3c
-#define ARCH_TIMER_TYPE_CP15 BIT(0) -#define ARCH_TIMER_TYPE_MEM BIT(1) static unsigned arch_timers_present __initdata;
static void __iomem *arch_counter_base; @@ -68,15 +66,6 @@ struct arch_timer { #define to_arch_timer(e) container_of(e, struct arch_timer, evt)
static u32 arch_timer_rate; - -enum arch_timer_ppi_nr { - ARCH_TIMER_PHYS_SECURE_PPI, - ARCH_TIMER_PHYS_NONSECURE_PPI, - ARCH_TIMER_VIRT_PPI, - ARCH_TIMER_HYP_PPI, - ARCH_TIMER_MAX_TIMER_PPI -}; - static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI];
static struct clock_event_device __percpu *arch_timer_evt; diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h index caedb74..b898637 100644 --- a/include/clocksource/arm_arch_timer.h +++ b/include/clocksource/arm_arch_timer.h @@ -16,9 +16,13 @@ #ifndef __CLKSOURCE_ARM_ARCH_TIMER_H #define __CLKSOURCE_ARM_ARCH_TIMER_H
+#include <linux/bitops.h> #include <linux/timecounter.h> #include <linux/types.h>
+#define ARCH_TIMER_TYPE_CP15 BIT(0) +#define ARCH_TIMER_TYPE_MEM BIT(1) + #define ARCH_TIMER_CTRL_ENABLE (1 << 0) #define ARCH_TIMER_CTRL_IT_MASK (1 << 1) #define ARCH_TIMER_CTRL_IT_STAT (1 << 2) @@ -34,6 +38,14 @@ enum arch_timer_reg { ARCH_TIMER_REG_TVAL, };
+enum arch_timer_ppi_nr { + ARCH_TIMER_PHYS_SECURE_PPI, + ARCH_TIMER_PHYS_NONSECURE_PPI, + ARCH_TIMER_VIRT_PPI, + ARCH_TIMER_HYP_PPI, + ARCH_TIMER_MAX_TIMER_PPI +}; + #define ARCH_TIMER_PHYS_ACCESS 0 #define ARCH_TIMER_VIRT_ACCESS 1 #define ARCH_TIMER_MEM_PHYS_ACCESS 2
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org 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(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 90b6661..ca73513 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -974,9 +974,9 @@ static int __init arch_timer_mem_init(struct device_node *np) }
if (arch_timer_mem_use_virtual) - irq = irq_of_parse_and_map(best_frame, 1); + irq = irq_of_parse_and_map(best_frame, ARCH_TIMER_VIRT_SPI); else - irq = irq_of_parse_and_map(best_frame, 0); + irq = irq_of_parse_and_map(best_frame, ARCH_TIMER_PHYS_SPI);
ret = -EINVAL; if (!irq) { diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h index b898637..4a98c06 100644 --- a/include/clocksource/arm_arch_timer.h +++ b/include/clocksource/arm_arch_timer.h @@ -46,6 +46,12 @@ enum arch_timer_ppi_nr { ARCH_TIMER_MAX_TIMER_PPI };
+enum arch_timer_spi_nr { + ARCH_TIMER_PHYS_SPI, + ARCH_TIMER_VIRT_SPI, + ARCH_TIMER_MAX_TIMER_SPI +}; + #define ARCH_TIMER_PHYS_ACCESS 0 #define ARCH_TIMER_VIRT_ACCESS 1 #define ARCH_TIMER_MEM_PHYS_ACCESS 2
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org Tested-by: Xiongfeng Wang wangxiongfeng2@huawei.com --- drivers/clocksource/arm_arch_timer.c | 77 +++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 31 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index ca73513..674d89f 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -702,7 +702,7 @@ static int __init arch_timer_register(void) case ARCH_TIMER_PHYS_NONSECURE_PPI: err = request_percpu_irq(ppi, arch_timer_handler_phys, "arch_timer", arch_timer_evt); - if (!err && arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]) { + if (!err && arch_timer_has_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); @@ -824,39 +824,41 @@ static int __init arch_timer_common_init(void) return arch_timer_arch_init(); }
-static int __init arch_timer_init(void) +/** + * arch_timer_select_ppi() - Select suitable PPI for the current system. + * + * If HYP mode is available, we know that the physical timer + * has been configured to be accessible from PL1. Use it, so + * that a guest can use the virtual timer instead. + * + * On ARMv8.1 with VH extensions, the kernel runs in HYP. VHE + * accesses to CNTP_*_EL1 registers are silently redirected to + * their CNTHP_*_EL2 counterparts, and use a different PPI + * number. + * + * If no interrupt provided for virtual timer, we'll have to + * stick to the physical timer. It'd better be accessible... + * For arm64 we never use the secure interrupt. + * + * Return: a suitable PPI type for the current system. + */ +static enum arch_timer_ppi_nr __init arch_timer_select_ppi(void) { - int ret; - /* - * If HYP mode is available, we know that the physical timer - * has been configured to be accessible from PL1. Use it, so - * that a guest can use the virtual timer instead. - * - * If no interrupt provided for virtual timer, we'll have to - * stick to the physical timer. It'd better be accessible... - * - * On ARMv8.1 with VH extensions, the kernel runs in HYP. VHE - * accesses to CNTP_*_EL1 registers are silently redirected to - * their CNTHP_*_EL2 counterparts, and use a different PPI - * number. - */ - if (is_hyp_mode_available() || !arch_timer_ppi[ARCH_TIMER_VIRT_PPI]) { - bool has_ppi; + if (is_kernel_in_hyp_mode()) + return ARCH_TIMER_HYP_PPI;
- if (is_kernel_in_hyp_mode()) { - arch_timer_uses_ppi = ARCH_TIMER_HYP_PPI; - has_ppi = !!arch_timer_ppi[ARCH_TIMER_HYP_PPI]; - } else { - 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 (!is_hyp_mode_available() && arch_timer_ppi[ARCH_TIMER_VIRT_PPI]) + return ARCH_TIMER_VIRT_PPI;
- if (!has_ppi) { - pr_warn("No interrupt available, giving up\n"); - return -EINVAL; - } - } + if (IS_ENABLED(CONFIG_ARM64)) + return ARCH_TIMER_PHYS_NONSECURE_PPI; + + return ARCH_TIMER_PHYS_SECURE_PPI; +} + +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; + } + /* Always-on capability */ arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
From: Fu Wei fu.wei@linaro.org
Currently, the counter frequency detection call(arch_timer_detect_rate) include getting the frequency from the device-tree property. But reading device-tree property will be needed only when system boot with device-tree.
This patch separate out device-tree code, keep them in device-tree init function.
Signed-off-by: Fu Wei fu.wei@linaro.org --- drivers/clocksource/arm_arch_timer.c | 38 ++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 15 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 674d89f..6484f84 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -488,24 +488,19 @@ 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 __iomem *cntbase) { /* Who has more than one independent system counter? */ if (arch_timer_rate) return;
/* - * 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 the MMIO timer or the sysreg. */ - 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 (cntbase) + arch_timer_rate = readl_relaxed(cntbase + CNTFRQ); + else + arch_timer_rate = arch_timer_get_cntfrq();
/* Check the timer frequency. */ if (arch_timer_rate == 0) @@ -886,7 +881,13 @@ 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); + /* + * Try to determine the frequency from the device tree, + * if fail, get the frequency from the sysreg CNTFRQ. + */ + if (!arch_timer_rate && + of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) + arch_timer_detect_rate(NULL);
arch_timer_c3stop = !of_property_read_bool(np, "always-on");
@@ -994,7 +995,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 the CNTFRQ reg of MMIO timer. + */ + if (!arch_timer_rate && + of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) + arch_timer_detect_rate(base); + ret = arch_timer_mem_register(base, irq); if (ret) goto out; @@ -1055,8 +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);
- /* Get the frequency from CNTFRQ */ - arch_timer_detect_rate(NULL, NULL); + /* Get the frequency from the sysreg CNTFRQ */ + arch_timer_detect_rate(NULL);
arch_timer_uses_ppi = arch_timer_select_ppi(); if (!arch_timer_ppi[arch_timer_uses_ppi]) {
From: Fu Wei fu.wei@linaro.org
The counter frequency detection call(arch_timer_detect_rate) combines two ways to get counter frequency: system coprocessor register and MMIO timer. But in a specific timer init code, we only need one way to try: getting frequency from MMIO timer register will be needed only when we init MMIO timer; getting frequency from system coprocessor register will be needed only when we init arch timer.
This patch separates paths to determine frequency: 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 --- drivers/clocksource/arm_arch_timer.c | 40 ++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 6484f84..9482481 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -488,23 +488,33 @@ static int arch_timer_starting_cpu(unsigned int cpu) return 0; }
-static void arch_timer_detect_rate(void __iomem *cntbase) +static void __arch_timer_determine_rate(u32 rate) { - /* Who has more than one independent system counter? */ - if (arch_timer_rate) - return; + /* Check the timer frequency. */ + if (!arch_timer_rate) { + if (rate) + arch_timer_rate = rate; + else + pr_warn("frequency not available\n"); + } else if (rate && arch_timer_rate != rate) { + pr_warn("got different frequency, keep original.\n"); + } +}
+static void arch_timer_detect_rate(void) +{ /* - * Try to determine the frequency from the MMIO timer or the sysreg. + * Try to get the timer frequency from the sysreg CNTFRQ. */ - if (cntbase) - arch_timer_rate = readl_relaxed(cntbase + CNTFRQ); - else - arch_timer_rate = arch_timer_get_cntfrq(); + __arch_timer_determine_rate(arch_timer_get_cntfrq()); +}
- /* Check the timer frequency. */ - if (arch_timer_rate == 0) - pr_warn("frequency not available\n"); +static void arch_timer_mem_detect_rate(void __iomem *cntbase) +{ + /* + * Try to get the timer frequency from the CNTFRQ reg of MMIO timer. + */ + __arch_timer_determine_rate(readl_relaxed(cntbase + CNTFRQ)); }
static void arch_timer_banner(unsigned type) @@ -887,7 +897,7 @@ static int __init arch_timer_of_init(struct device_node *np) */ if (!arch_timer_rate && of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) - arch_timer_detect_rate(NULL); + arch_timer_detect_rate();
arch_timer_c3stop = !of_property_read_bool(np, "always-on");
@@ -1001,7 +1011,7 @@ static int __init arch_timer_mem_init(struct device_node *np) */ if (!arch_timer_rate && of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) - arch_timer_detect_rate(base); + arch_timer_mem_detect_rate(base);
ret = arch_timer_mem_register(base, irq); if (ret) @@ -1064,7 +1074,7 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table) gtdt->non_secure_el2_flags);
/* Get the frequency from the sysreg CNTFRQ */ - arch_timer_detect_rate(NULL); + arch_timer_detect_rate();
arch_timer_uses_ppi = arch_timer_select_ppi(); if (!arch_timer_ppi[arch_timer_uses_ppi]) {
Hi Fuwei,
One comments below.
On 2017/1/18 21:25, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
The counter frequency detection call(arch_timer_detect_rate) combines two ways to get counter frequency: system coprocessor register and MMIO timer. But in a specific timer init code, we only need one way to try: getting frequency from MMIO timer register will be needed only when we init MMIO timer; getting frequency from system coprocessor register will be needed only when we init arch timer.
This patch separates paths to determine frequency: 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
drivers/clocksource/arm_arch_timer.c | 40 ++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 6484f84..9482481 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -488,23 +488,33 @@ static int arch_timer_starting_cpu(unsigned int cpu) return 0; }
-static void arch_timer_detect_rate(void __iomem *cntbase) +static void __arch_timer_determine_rate(u32 rate) {
- /* Who has more than one independent system counter? */
- if (arch_timer_rate)
return;
- /* Check the timer frequency. */
- if (!arch_timer_rate) {
if (rate)
arch_timer_rate = rate;
else
pr_warn("frequency not available\n");
- } else if (rate && arch_timer_rate != rate) {
^ Typo? I think it's "&" here.
Thanks Hanjun
Hi Hanjun,
On 19 January 2017 at 16:02, Hanjun Guo hanjun.guo@linaro.org wrote:
Hi Fuwei,
One comments below.
On 2017/1/18 21:25, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
The counter frequency detection call(arch_timer_detect_rate) combines two ways to get counter frequency: system coprocessor register and MMIO timer. But in a specific timer init code, we only need one way to try: getting frequency from MMIO timer register will be needed only when we init MMIO timer; getting frequency from system coprocessor register will be needed only when we init arch timer.
This patch separates paths to determine frequency: 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
drivers/clocksource/arm_arch_timer.c | 40 ++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 6484f84..9482481 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -488,23 +488,33 @@ static int arch_timer_starting_cpu(unsigned int cpu) return 0; }
-static void arch_timer_detect_rate(void __iomem *cntbase) +static void __arch_timer_determine_rate(u32 rate) {
/* Who has more than one independent system counter? */
if (arch_timer_rate)
return;
/* Check the timer frequency. */
if (!arch_timer_rate) {
if (rate)
arch_timer_rate = rate;
else
pr_warn("frequency not available\n");
} else if (rate && arch_timer_rate != rate) {
^
Typo? I think it's "&" here.
Not a typo, It's definitely a “&&” :-)
Here arch_timer_rate is not zero.
If rate is not zero(that means we got a valid rate), and arch_timer_rate != rate , we will print warning message.
Thanks Hanjun
On 2017/1/19 17:44, Fu Wei wrote:
Hi Hanjun,
On 19 January 2017 at 16:02, Hanjun Guo hanjun.guo@linaro.org wrote:
Hi Fuwei,
One comments below.
On 2017/1/18 21:25, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
The counter frequency detection call(arch_timer_detect_rate) combines two ways to get counter frequency: system coprocessor register and MMIO timer. But in a specific timer init code, we only need one way to try: getting frequency from MMIO timer register will be needed only when we init MMIO timer; getting frequency from system coprocessor register will be needed only when we init arch timer.
This patch separates paths to determine frequency: 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
drivers/clocksource/arm_arch_timer.c | 40 ++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 6484f84..9482481 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -488,23 +488,33 @@ static int arch_timer_starting_cpu(unsigned int cpu) return 0; }
-static void arch_timer_detect_rate(void __iomem *cntbase) +static void __arch_timer_determine_rate(u32 rate) {
/* Who has more than one independent system counter? */
if (arch_timer_rate)
return;
/* Check the timer frequency. */
if (!arch_timer_rate) {
if (rate)
arch_timer_rate = rate;
else
pr_warn("frequency not available\n");
} else if (rate && arch_timer_rate != rate) {
^
Typo? I think it's "&" here.
Not a typo, It's definitely a “&&” :-)
Here arch_timer_rate is not zero.
If rate is not zero(that means we got a valid rate), and arch_timer_rate != rate , we will print warning message.
Ah, misreading the code, thanks for clarify :)
Hanjun
On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
The counter frequency detection call(arch_timer_detect_rate) combines two ways to get counter frequency: system coprocessor register and MMIO timer. But in a specific timer init code, we only need one way to try: getting frequency from MMIO timer register will be needed only when we init MMIO timer; getting frequency from system coprocessor register will be needed only when we init arch timer.
When I mentioned this splitting before, I had mean that we'd completely separate the two, with separate mmio_rate and sysreg_rate variables.
The probing logic relying on this is complicated and fragile, and I think these patches are complicating that further (though I appreciate that's far from the intent).
I believe we need to split the MMIO and sysreg timer code apart entirely. I've had a look at that today, though it's been fairly painful so far. It appears some platforms may inadvertently be relying on the order and manner in which the rates are probed, which is a major headache.
I will try to attack that some more tomorrow.
This patch separates paths to determine frequency: 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
drivers/clocksource/arm_arch_timer.c | 40 ++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 6484f84..9482481 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -488,23 +488,33 @@ static int arch_timer_starting_cpu(unsigned int cpu) return 0; } -static void arch_timer_detect_rate(void __iomem *cntbase) +static void __arch_timer_determine_rate(u32 rate) {
- /* Who has more than one independent system counter? */
- if (arch_timer_rate)
return;
- /* Check the timer frequency. */
- if (!arch_timer_rate) {
if (rate)
arch_timer_rate = rate;
else
pr_warn("frequency not available\n");
- } else if (rate && arch_timer_rate != rate) {
pr_warn("got different frequency, keep original.\n");
- }
+}
This function should be killed off entirely. We need to be able to fail the probe if we cannot determine the rate, and that means we need error handling in the ACPI and DT cases anyway.
Thanks, Mark.
Hi Mark,
On 25 January 2017 at 01:24, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
The counter frequency detection call(arch_timer_detect_rate) combines two ways to get counter frequency: system coprocessor register and MMIO timer. But in a specific timer init code, we only need one way to try: getting frequency from MMIO timer register will be needed only when we init MMIO timer; getting frequency from system coprocessor register will be needed only when we init arch timer.
When I mentioned this splitting before, I had mean that we'd completely separate the two, with separate mmio_rate and sysreg_rate variables.
sorry for misunderstanding.
Are you saying :
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 663a57a..eec92f6 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -65,7 +65,8 @@ struct arch_timer {
#define to_arch_timer(e) container_of(e, struct arch_timer, evt)
-static u32 arch_timer_rate; +static u32 arch_timer_sysreg_rate ; +static u32 arch_timer_mmio_rate; static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI];
static struct clock_event_device __percpu *arch_timer_evt;
But what have I learned From ARMv8 ARM is AArch64 System register CNTFRQ_EL0 is provided so that software can discover the frequency of the system counter. CNTFRQ(in CNTCTLBase and CNTBaseN) is provided so that software can discover the frequency of the system counter. The bit assignments of the registers are identical in the System register interface and in the memory-mapped system level interface. So I think they both contain the same value : the frequency of the system counter, just in different view, and can be accessed in different ways.
So do we really need to separate mmio_rate and sysreg_rate variables?
And for CNTFRQ(in CNTCTLBase and CNTBaseN) , we can NOT access it in Linux kernel (EL1), Because ARMv8 ARM says: In a system that implements both Secure and Non-secure states, this register is only accessible by Secure accesses. That means we still need to get the frequency of the system counter from CNTFRQ_EL0 in MMIO timer code. This have been proved when I tested this driver on foundation model, I got "0" when I access CNTFRQ from Linux kernel (Non-secure EL1)
So I guess the logic of the original code is static u32 arch_timer_rate keeps the frequency of the system counter, no matter where the value comes from. Because they should be the same value. if we have got the frequency of the system counter(arch_timer_rate != 0), then we don't need to get it again, even in anther way.
But the above is just my thought, and I believe you're the expert of ARM. So please correct me if I misunderstand something. :-)
Thanks!
The probing logic relying on this is complicated and fragile, and I think these patches are complicating that further (though I appreciate that's far from the intent).
I believe we need to split the MMIO and sysreg timer code apart entirely. I've had a look at that today, though it's been fairly painful so far. It appears some platforms may inadvertently be relying on the order and manner in which the rates are probed, which is a major headache.
I will try to attack that some more tomorrow.
This patch separates paths to determine frequency: 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
drivers/clocksource/arm_arch_timer.c | 40 ++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 6484f84..9482481 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -488,23 +488,33 @@ static int arch_timer_starting_cpu(unsigned int cpu) return 0; }
-static void arch_timer_detect_rate(void __iomem *cntbase) +static void __arch_timer_determine_rate(u32 rate) {
/* Who has more than one independent system counter? */
if (arch_timer_rate)
return;
/* Check the timer frequency. */
if (!arch_timer_rate) {
if (rate)
arch_timer_rate = rate;
else
pr_warn("frequency not available\n");
} else if (rate && arch_timer_rate != rate) {
pr_warn("got different frequency, keep original.\n");
}
+}
This function should be killed off entirely. We need to be able to fail the probe if we cannot determine the rate, and that means we need error handling in the ACPI and DT cases anyway.
Thanks, Mark.
Hi Mark,
On 25 January 2017 at 14:46, Fu Wei fu.wei@linaro.org wrote:
Hi Mark,
On 25 January 2017 at 01:24, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
The counter frequency detection call(arch_timer_detect_rate) combines two ways to get counter frequency: system coprocessor register and MMIO timer. But in a specific timer init code, we only need one way to try: getting frequency from MMIO timer register will be needed only when we init MMIO timer; getting frequency from system coprocessor register will be needed only when we init arch timer.
When I mentioned this splitting before, I had mean that we'd completely separate the two, with separate mmio_rate and sysreg_rate variables.
sorry for misunderstanding.
Are you saying :
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 663a57a..eec92f6 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -65,7 +65,8 @@ struct arch_timer {
#define to_arch_timer(e) container_of(e, struct arch_timer, evt)
-static u32 arch_timer_rate; +static u32 arch_timer_sysreg_rate ; +static u32 arch_timer_mmio_rate; static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI];
static struct clock_event_device __percpu *arch_timer_evt;
But what have I learned From ARMv8 ARM is AArch64 System register CNTFRQ_EL0 is provided so that software can discover the frequency of the system counter. CNTFRQ(in CNTCTLBase and CNTBaseN) is provided so that software can discover the frequency of the system counter. The bit assignments of the registers are identical in the System register interface and in the memory-mapped system level interface. So I think they both contain the same value : the frequency of the system counter, just in different view, and can be accessed in different ways.
So do we really need to separate mmio_rate and sysreg_rate variables?
And for CNTFRQ(in CNTCTLBase and CNTBaseN) , we can NOT access it in Linux kernel (EL1), Because ARMv8 ARM says: In a system that implements both Secure and Non-secure states, this register is only accessible by Secure accesses. That means we still need to get the frequency of the system counter from CNTFRQ_EL0 in MMIO timer code. This have been proved when I tested this driver on foundation model, I got "0" when I access CNTFRQ from Linux kernel (Non-secure EL1)
So I guess the logic of the original code is static u32 arch_timer_rate keeps the frequency of the system counter, no matter where the value comes from. Because they should be the same value. if we have got the frequency of the system counter(arch_timer_rate != 0), then we don't need to get it again, even in anther way.
*IF* the above is right, For ARM32, boot with dtb, the original logic and this patch work well. For ARM64, boot with dtb, if MMIO timer is probed first, and there is not "clock-frequency" in the node. MMIO timer can't get the frequency. Because we will get "0" when we access CNTFRQ from Linux kernel (Non-secure EL1), that means the original logic and this patch won't work. To fix this issue, we need to get the frequency from sysreg CNTFRQ_EL0. For ARM64, boot with ACPI, the original logic and this patch work well, because we always probe arch_timer first.
So *IF* I understand it correctly, May I suggest that we only get the frequency from sysreg CNTFRQ_EL0 in this driver? I think that can simplify the code and avoid the issue when we boot ARM64 with dtb.
Again, please correct me if I misunderstand something. :-) Great thanks for your help!
But the above is just my thought, and I believe you're the expert of ARM. So please correct me if I misunderstand something. :-)
Thanks!
The probing logic relying on this is complicated and fragile, and I think these patches are complicating that further (though I appreciate that's far from the intent).
I believe we need to split the MMIO and sysreg timer code apart entirely. I've had a look at that today, though it's been fairly painful so far. It appears some platforms may inadvertently be relying on the order and manner in which the rates are probed, which is a major headache.
I will try to attack that some more tomorrow.
This patch separates paths to determine frequency: 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
drivers/clocksource/arm_arch_timer.c | 40 ++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 6484f84..9482481 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -488,23 +488,33 @@ static int arch_timer_starting_cpu(unsigned int cpu) return 0; }
-static void arch_timer_detect_rate(void __iomem *cntbase) +static void __arch_timer_determine_rate(u32 rate) {
/* Who has more than one independent system counter? */
if (arch_timer_rate)
return;
/* Check the timer frequency. */
if (!arch_timer_rate) {
if (rate)
arch_timer_rate = rate;
else
pr_warn("frequency not available\n");
} else if (rate && arch_timer_rate != rate) {
pr_warn("got different frequency, keep original.\n");
}
+}
This function should be killed off entirely. We need to be able to fail the probe if we cannot determine the rate, and that means we need error handling in the ACPI and DT cases anyway.
Thanks, Mark.
-- Best regards,
Fu Wei Software Engineer Red Hat
Hi Fu,
On 01/25/2017 01:46 AM, Fu Wei wrote:
Hi Mark,
On 25 January 2017 at 01:24, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
The counter frequency detection call(arch_timer_detect_rate) combines two ways to get counter frequency: system coprocessor register and MMIO timer. But in a specific timer init code, we only need one way to try: getting frequency from MMIO timer register will be needed only when we init MMIO timer; getting frequency from system coprocessor register will be needed only when we init arch timer.
When I mentioned this splitting before, I had mean that we'd completely separate the two, with separate mmio_rate and sysreg_rate variables.
sorry for misunderstanding.
Are you saying :
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 663a57a..eec92f6 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -65,7 +65,8 @@ struct arch_timer {
#define to_arch_timer(e) container_of(e, struct arch_timer, evt)
-static u32 arch_timer_rate; +static u32 arch_timer_sysreg_rate ; +static u32 arch_timer_mmio_rate; static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI];
static struct clock_event_device __percpu *arch_timer_evt;
But what have I learned From ARMv8 ARM is AArch64 System register CNTFRQ_EL0 is provided so that software can discover the frequency of the system counter. CNTFRQ(in CNTCTLBase and CNTBaseN) is provided so that software can discover the frequency of the system counter. The bit assignments of the registers are identical in the System register interface and in the memory-mapped system level interface. So I think they both contain the same value : the frequency of the system counter, just in different view, and can be accessed in different ways.
So do we really need to separate mmio_rate and sysreg_rate variables?
And for CNTFRQ(in CNTCTLBase and CNTBaseN) , we can NOT access it in Linux kernel (EL1), Because ARMv8 ARM says: In a system that implements both Secure and Non-secure states, this register is only accessible by Secure accesses. That means we still need to get the frequency of the system counter from CNTFRQ_EL0 in MMIO timer code. This have been proved when I tested this driver on foundation model, I got "0" when I access CNTFRQ from Linux kernel (Non-secure EL1)
That sounds like a firmware problem. Firmware in EL3 is supposed to write the value into CNTFRQ. If you're not currently using any firmware, I'd recommend the bootwrapper on models/simulators/emulators.
http://git.kernel.org/cgit/linux/kernel/git/mark/boot-wrapper-aarch64.git/tr...
Cheers, Cov
On Wed, Jan 25, 2017 at 10:38:01AM -0500, Christopher Covington wrote:
On 01/25/2017 01:46 AM, Fu Wei wrote:
On 25 January 2017 at 01:24, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
And for CNTFRQ(in CNTCTLBase and CNTBaseN) , we can NOT access it in Linux kernel (EL1), Because ARMv8 ARM says: In a system that implements both Secure and Non-secure states, this register is only accessible by Secure accesses. That means we still need to get the frequency of the system counter from CNTFRQ_EL0 in MMIO timer code. This have been proved when I tested this driver on foundation model, I got "0" when I access CNTFRQ from Linux kernel (Non-secure EL1)
That sounds like a firmware problem. Firmware in EL3 is supposed to write the value into CNTFRQ.
Definitely. FW *should* program the CNTFRQ_EL0 CPU registers and any MMIO CNTFRQ registers.
If you're not currently using any firmware, I'd recommend the bootwrapper on models/simulators/emulators.
http://git.kernel.org/cgit/linux/kernel/git/mark/boot-wrapper-aarch64.git/tr...
Unfortunately, the boot-wrapper only programs the CNTFRQ_EL0 CPU system registers, and does not program any MMIO CNTFRQ registers.
IIRC the models it was originally written for didn't have any (and we had no DT binding until far later...). Luckily the model DTs do not expose any MMIO timer addresses to the kernel currently.
Thanks, Mark.
Hi Mark, Christopher,
On 26 January 2017 at 01:36, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Jan 25, 2017 at 10:38:01AM -0500, Christopher Covington wrote:
On 01/25/2017 01:46 AM, Fu Wei wrote:
On 25 January 2017 at 01:24, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
And for CNTFRQ(in CNTCTLBase and CNTBaseN) , we can NOT access it in Linux kernel (EL1), Because ARMv8 ARM says: In a system that implements both Secure and Non-secure states, this register is only accessible by Secure accesses. That means we still need to get the frequency of the system counter from CNTFRQ_EL0 in MMIO timer code. This have been proved when I tested this driver on foundation model, I got "0" when I access CNTFRQ from Linux kernel (Non-secure EL1)
That sounds like a firmware problem. Firmware in EL3 is supposed to write the value into CNTFRQ.
Definitely. FW *should* program the CNTFRQ_EL0 CPU registers and any MMIO CNTFRQ registers.
Many thanks for the explanation. This might be the problem. Maybe we can check the UEFI :-)
If you're not currently using any firmware, I'd recommend the bootwrapper on models/simulators/emulators.
http://git.kernel.org/cgit/linux/kernel/git/mark/boot-wrapper-aarch64.git/tr...
Unfortunately, the boot-wrapper only programs the CNTFRQ_EL0 CPU system registers, and does not program any MMIO CNTFRQ registers.
IIRC the models it was originally written for didn't have any (and we had no DT binding until far later...). Luckily the model DTs do not expose any MMIO timer addresses to the kernel currently.
But according to another document(ARMv8-A Foundation Platform User Guide ARM DUI0677K), Table 3-2 ARMv8-A Foundation Platform memory map, we may have two frames in the Generic timer block, right?
Thanks, Mark.
On Wed, Jan 25, 2017 at 02:46:12PM +0800, Fu Wei wrote:
Hi Mark,
Hi,
On 25 January 2017 at 01:24, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
The counter frequency detection call(arch_timer_detect_rate) combines two ways to get counter frequency: system coprocessor register and MMIO timer. But in a specific timer init code, we only need one way to try: getting frequency from MMIO timer register will be needed only when we init MMIO timer; getting frequency from system coprocessor register will be needed only when we init arch timer.
When I mentioned this splitting before, I had mean that we'd completely separate the two, with separate mmio_rate and sysreg_rate variables.
sorry for misunderstanding.
Are you saying :
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 663a57a..eec92f6 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -65,7 +65,8 @@ struct arch_timer {
#define to_arch_timer(e) container_of(e, struct arch_timer, evt)
-static u32 arch_timer_rate; +static u32 arch_timer_sysreg_rate ; +static u32 arch_timer_mmio_rate; static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI];
static struct clock_event_device __percpu *arch_timer_evt;
But what have I learned From ARMv8 ARM is AArch64 System register CNTFRQ_EL0 is provided so that software can discover the frequency of the system counter. CNTFRQ(in CNTCTLBase and CNTBaseN) is provided so that software can discover the frequency of the system counter. The bit assignments of the registers are identical in the System register interface and in the memory-mapped system level interface.
This means that the bits in the registers have the same meaning.
However, they are separate registers, and must be written separately. A write to one does not propagate to the other, and they are not guaranteed to contain the same value.
So I think they both contain the same value : the frequency of the system counter, just in different view, and can be accessed in different ways.
Certainly, in theory, these *should* contain the same value.
Unfortunately, in practice, on several systems, they do not. It is very easy to forget to initialise one of these registers correctly, and it's possible for some software to work (masking the issue), while other software will fail very quickly. I very much suspect we will see the same class of issue on ACPI systems.
Consider a system where the sysreg CNTFRQ was correct, but the MMIO CNTFRQ contains an erroneous non-zero value.
If we get the frequency out of CNTFRQ_EL0 first, and assign this to arch_timer_rate, we won't bother to look at the MMIO registers (which could contain erroneous values). If we read an erroneous CNTBaseN.CNTFRQ value first, and assign this to arch_timer_rate, we won't look at CNTFRQ_EL0.
This is *very* fragile w.r.t. probe order. I don't like the fragility of setting a common arch_timer_rate depending on which gets probed first, as this masks a bug, which will adversely affect us later.
This is already a problem for DT systems, and I do not want this problem to spread to ACPI systems.
For ACPI, the approach I'd personally like to take is to keep the two rates separate. Probe the sysreg timer first and subsequently probe the MMIO timers. If the MMIO CNTFRQ (of all frames) does not match the sysreg CNTFRQ, we log a warning and give up probing the MMIO timers.
For legacy reasons, DT is going to be more complicated, but I believe we can apply that approach to ACPI.
So do we really need to separate mmio_rate and sysreg_rate variables?
And for CNTFRQ(in CNTCTLBase and CNTBaseN) , we can NOT access it in Linux kernel (EL1), Because ARMv8 ARM says: In a system that implements both Secure and Non-secure states, this register is only accessible by Secure accesses.
CNTCTLBase.CNTFRQ can only be accessed in secure states. That is clear from Table I1-3 in ARM DDI 0487A.k_iss10775). I agree that we cannot access this.
For CNT{,EL0}BaseN.CNTFRQ, I am very concerned by the wording in the current ARMv8 ARM ARM. This does not match my understanding, nor does it match the description in the ARMv7 ARM. I believe this may be a documentation error, and I'm chasing that up internally.
Either the currently logic in the driver which attempts to read CNT{,EL0}BaseN.CNTFRQ is flawed, or the description in the ARM ARM is erroneous.
That means we still need to get the frequency of the system counter from CNTFRQ_EL0 in MMIO timer code. This have been proved when I tested this driver on foundation model, I got "0" when I access CNTFRQ from Linux kernel (Non-secure EL1)
As mentioned in I3.5.7, the CNTBase{,EL0}N.CNTFRQ values are UNKNOWN out of reset, and require configuration by FW.
So I guess the logic of the original code is static u32 arch_timer_rate keeps the frequency of the system counter, no matter where the value comes from. Because they should be the same value. if we have got the frequency of the system counter(arch_timer_rate != 0), then we don't need to get it again, even in anther way.
Unfortunately, in practice this is not the case. :(
Thanks, Mark.
Hi Mark,
On 26 January 2017 at 01:25, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Jan 25, 2017 at 02:46:12PM +0800, Fu Wei wrote:
Hi Mark,
Hi,
On 25 January 2017 at 01:24, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
The counter frequency detection call(arch_timer_detect_rate) combines two ways to get counter frequency: system coprocessor register and MMIO timer. But in a specific timer init code, we only need one way to try: getting frequency from MMIO timer register will be needed only when we init MMIO timer; getting frequency from system coprocessor register will be needed only when we init arch timer.
When I mentioned this splitting before, I had mean that we'd completely separate the two, with separate mmio_rate and sysreg_rate variables.
sorry for misunderstanding.
Are you saying :
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 663a57a..eec92f6 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -65,7 +65,8 @@ struct arch_timer {
#define to_arch_timer(e) container_of(e, struct arch_timer, evt)
-static u32 arch_timer_rate; +static u32 arch_timer_sysreg_rate ; +static u32 arch_timer_mmio_rate; static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI];
static struct clock_event_device __percpu *arch_timer_evt;
But what have I learned From ARMv8 ARM is AArch64 System register CNTFRQ_EL0 is provided so that software can discover the frequency of the system counter. CNTFRQ(in CNTCTLBase and CNTBaseN) is provided so that software can discover the frequency of the system counter. The bit assignments of the registers are identical in the System register interface and in the memory-mapped system level interface.
This means that the bits in the registers have the same meaning.
However, they are separate registers, and must be written separately. A write to one does not propagate to the other, and they are not guaranteed to contain the same value.
Ah, Sorry for misunderstanding this, and thanks for correcting it, I thought they point to the same register.
So I think they both contain the same value : the frequency of the system counter, just in different view, and can be accessed in different ways.
Certainly, in theory, these *should* contain the same value.
Unfortunately, in practice, on several systems, they do not. It is very easy to forget to initialise one of these registers correctly, and it's possible for some software to work (masking the issue), while other software will fail very quickly. I very much suspect we will see the same class of issue on ACPI systems.
Ah, thanks , that makes sense to me :-)
So can I say: In normal case, CNTFRQ_EL0, CNTCTLBase.CNTFRQ and CNTBaseN.CNTFRQ should be set to the same value. But in some special case, some CNTFRQ maybe set to a different number for some reason(maybe on purpose).
Consider a system where the sysreg CNTFRQ was correct, but the MMIO CNTFRQ contains an erroneous non-zero value.
If we get the frequency out of CNTFRQ_EL0 first, and assign this to arch_timer_rate, we won't bother to look at the MMIO registers (which could contain erroneous values). If we read an erroneous CNTBaseN.CNTFRQ value first, and assign this to arch_timer_rate, we won't look at CNTFRQ_EL0.
This is *very* fragile w.r.t. probe order. I don't like the fragility of setting a common arch_timer_rate depending on which gets probed first, as this masks a bug, which will adversely affect us later.
This is already a problem for DT systems, and I do not want this problem to spread to ACPI systems.
For ACPI, the approach I'd personally like to take is to keep the two rates separate. Probe the sysreg timer first and subsequently probe the MMIO timers. If the MMIO CNTFRQ (of all frames) does not match the sysreg CNTFRQ, we log a warning and give up probing the MMIO timers.
OK, I think I got your point, will do this way. Thanks :-)
For legacy reasons, DT is going to be more complicated, but I believe we can apply that approach to ACPI.
So do we really need to separate mmio_rate and sysreg_rate variables?
And for CNTFRQ(in CNTCTLBase and CNTBaseN) , we can NOT access it in Linux kernel (EL1), Because ARMv8 ARM says: In a system that implements both Secure and Non-secure states, this register is only accessible by Secure accesses.
CNTCTLBase.CNTFRQ can only be accessed in secure states. That is clear from Table I1-3 in ARM DDI 0487A.k_iss10775). I agree that we cannot access this.
yes , got it. And we don't do it in the driver, we try to access CNTBaseN.CNTFRQ (in a frame) instead.
For CNT{,EL0}BaseN.CNTFRQ, I am very concerned by the wording in the current ARMv8 ARM ARM. This does not match my understanding, nor does it match the description in the ARMv7 ARM. I believe this may be a documentation error, and I'm chasing that up internally.
Either the currently logic in the driver which attempts to read CNT{,EL0}BaseN.CNTFRQ is flawed, or the description in the ARM ARM is erroneous.
Yes, those description did confuse me. :-(
But according to another document(ARMv8-A Foundation Platform User Guide ARM DUI0677K), Table 3-2 ARMv8-A Foundation Platform memory map (continued)
AP_REFCLK CNTBase0, Generic Timer 64KB S AP_REFCLK CNTBase1, Generic Timer 64KB S/NS
Dose it means the timer frame 0 can be accessed in SECURE status only, and the timer frame 1 can be accessed in both status?
And because Linux kernel is running on Non-secure EL1, so should we skip "SECURE" timer in Linux?
That means we still need to get the frequency of the system counter from CNTFRQ_EL0 in MMIO timer code. This have been proved when I tested this driver on foundation model, I got "0" when I access CNTFRQ from Linux kernel (Non-secure EL1)
As mentioned in I3.5.7, the CNTBase{,EL0}N.CNTFRQ values are UNKNOWN out of reset, and require configuration by FW.
So I guess the logic of the original code is static u32 arch_timer_rate keeps the frequency of the system counter, no matter where the value comes from. Because they should be the same value. if we have got the frequency of the system counter(arch_timer_rate != 0), then we don't need to get it again, even in anther way.
Unfortunately, in practice this is not the case. :(
Thanks, Mark.
On Thu, Jan 26, 2017 at 01:49:03PM +0800, Fu Wei wrote:
On 26 January 2017 at 01:25, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Jan 25, 2017 at 02:46:12PM +0800, Fu Wei wrote:
On 25 January 2017 at 01:24, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
For CNT{,EL0}BaseN.CNTFRQ, I am very concerned by the wording in the current ARMv8 ARM ARM. This does not match my understanding, nor does it match the description in the ARMv7 ARM. I believe this may be a documentation error, and I'm chasing that up internally.
Either the currently logic in the driver which attempts to read CNT{,EL0}BaseN.CNTFRQ is flawed, or the description in the ARM ARM is erroneous.
Yes, those description did confuse me. :-(
But according to another document(ARMv8-A Foundation Platform User Guide ARM DUI0677K), Table 3-2 ARMv8-A Foundation Platform memory map (continued)
AP_REFCLK CNTBase0, Generic Timer 64KB S AP_REFCLK CNTBase1, Generic Timer 64KB S/NS
Dose it means the timer frame 0 can be accessed in SECURE status only, and the timer frame 1 can be accessed in both status?
That does appear to be what it says.
I assume in this case CNTCTLBase.CNTSAR<0> is RES0.
And because Linux kernel is running on Non-secure EL1, so should we skip "SECURE" timer in Linux?
I guess you mean by checking the GTx Common flags, to see if the timer is secure? Yes, we must skip those.
Looking further at this, the ACPI spec is sorely lacking any statement as to the configuration of CNTCTLBase.{CNTSAR,CNTTIDR,CNTACR}, so it's not clear if we can access anything in a frame, even if it is listed as being a non-secure timer.
I think we need a stronger statement here. Otherwise, we will encounter problems. Linux currently assumes that CNTCTLBase.CNTACR<N> is writeable, given a non-secure frame N. This is only the case if CNTCTLBase.CNTSAR.NS<N> == 1.
Thanks, Mark.
On Mon, Jan 30, 2017 at 05:49:59PM +0000, Mark Rutland wrote:
On Thu, Jan 26, 2017 at 01:49:03PM +0800, Fu Wei wrote:
And because Linux kernel is running on Non-secure EL1, so should we skip "SECURE" timer in Linux?
I guess you mean by checking the GTx Common flags, to see if the timer is secure? Yes, we must skip those.
Looking further at this, the ACPI spec is sorely lacking any statement as to the configuration of CNTCTLBase.{CNTSAR,CNTTIDR,CNTACR}, so it's not clear if we can access anything in a frame, even if it is listed as being a non-secure timer.
Given CNTNSAR.NS<n> enables non-secure access to CNTACR<n>, I guess the obvious interpretation is that for frames listed as non-secure, this has been configured to permit non-secure access to the frame and associated CNTACR<n>.
I will work to that assumption while reviewing, though I still believe this needs to be clarified in the spec.
Thanks, Mark.
Hi Mark,
On 31 January 2017 at 01:49, Mark Rutland mark.rutland@arm.com wrote:
On Thu, Jan 26, 2017 at 01:49:03PM +0800, Fu Wei wrote:
On 26 January 2017 at 01:25, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Jan 25, 2017 at 02:46:12PM +0800, Fu Wei wrote:
On 25 January 2017 at 01:24, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
For CNT{,EL0}BaseN.CNTFRQ, I am very concerned by the wording in the current ARMv8 ARM ARM. This does not match my understanding, nor does it match the description in the ARMv7 ARM. I believe this may be a documentation error, and I'm chasing that up internally.
Either the currently logic in the driver which attempts to read CNT{,EL0}BaseN.CNTFRQ is flawed, or the description in the ARM ARM is erroneous.
Yes, those description did confuse me. :-(
But according to another document(ARMv8-A Foundation Platform User Guide ARM DUI0677K), Table 3-2 ARMv8-A Foundation Platform memory map (continued)
AP_REFCLK CNTBase0, Generic Timer 64KB S AP_REFCLK CNTBase1, Generic Timer 64KB S/NS
Dose it means the timer frame 0 can be accessed in SECURE status only, and the timer frame 1 can be accessed in both status?
That does appear to be what it says.
I assume in this case CNTCTLBase.CNTSAR<0> is RES0.
And because Linux kernel is running on Non-secure EL1, so should we skip "SECURE" timer in Linux?
I guess you mean by checking the GTx Common flags, to see if the timer is secure? Yes, we must skip those.
Yes, exactly.
I think we can check the GTx Common flags, if the timer is set as SECURE, this driver should just skip this timer.
Reason: 1, IF the timer is designed to be a secure timer which is only can be accessed in secure status, the ACPI table should label this as SECURE, then driver should skip it. 2, IF the timer is accessible from both status, but the firmware want to use this driver for secure OS, the ACPI table should also label this as SECURE(meanwhile firmware should configure CNTSAR too), then driver should skip it, too.
Actually I have added this into my next patchset v21. If you don't have other suggestion I can post it tomorrow.
Can I? any thought?
Looking further at this, the ACPI spec is sorely lacking any statement as to the configuration of CNTCTLBase.{CNTSAR,CNTTIDR,CNTACR}, so it's not clear if we can access anything in a frame, even if it is listed as being a non-secure timer.
I think we need a stronger statement here. Otherwise, we will encounter problems. Linux currently assumes that CNTCTLBase.CNTACR<N> is writeable, given a non-secure frame N. This is only the case if CNTCTLBase.CNTSAR.NS<N> == 1.
the original driver has checked these registers, but the problem is: What if the timer frame is designed to be a secure timer, all the register in this frame is only can be accessed in secure status, just like foundation model? Note: for foundation model, Please check Table 3-1 Access permissions of 3.1 ARMv8-A Foundation Platform memory map in ARMv8-A Foundation Platform User Guide
So I think we should check the GTDT first, if it's not a secure timer, then we can go on checking CNTSAR. :-)
Please correct me, If I miss something. :-)
Great thanks for your info :-)
Thanks, Mark.
On Wed, Feb 01, 2017 at 02:43:02AM +0800, Fu Wei wrote:
On 31 January 2017 at 01:49, Mark Rutland mark.rutland@arm.com wrote:
On Thu, Jan 26, 2017 at 01:49:03PM +0800, Fu Wei wrote:
On 26 January 2017 at 01:25, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Jan 25, 2017 at 02:46:12PM +0800, Fu Wei wrote:
On 25 January 2017 at 01:24, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote: > From: Fu Wei fu.wei@linaro.org
But according to another document(ARMv8-A Foundation Platform User Guide ARM DUI0677K), Table 3-2 ARMv8-A Foundation Platform memory map (continued)
AP_REFCLK CNTBase0, Generic Timer 64KB S AP_REFCLK CNTBase1, Generic Timer 64KB S/NS
Dose it means the timer frame 0 can be accessed in SECURE status only, and the timer frame 1 can be accessed in both status?
That does appear to be what it says.
I assume in this case CNTCTLBase.CNTSAR<0> is RES0.
And because Linux kernel is running on Non-secure EL1, so should we skip "SECURE" timer in Linux?
I guess you mean by checking the GTx Common flags, to see if the timer is secure? Yes, we must skip those.
Yes, exactly.
I think we can check the GTx Common flags, if the timer is set as SECURE, this driver should just skip this timer.
I completely agree that we must skip these.
Looking further at this, the ACPI spec is sorely lacking any statement as to the configuration of CNTCTLBase.{CNTSAR,CNTTIDR,CNTACR}, so it's not clear if we can access anything in a frame, even if it is listed as being a non-secure timer.
I think we need a stronger statement here. Otherwise, we will encounter problems. Linux currently assumes that CNTCTLBase.CNTACR<N> is writeable, given a non-secure frame N. This is only the case if CNTCTLBase.CNTSAR.NS<N> == 1.
the original driver has checked these registers, but the problem is: What if the timer frame is designed to be a secure timer, all the register in this frame is only can be accessed in secure status, just like foundation model? Note: for foundation model, Please check Table 3-1 Access permissions of 3.1 ARMv8-A Foundation Platform memory map in ARMv8-A Foundation Platform User Guide
So I think we should check the GTDT first, if it's not a secure timer, then we can go on checking CNTSAR. :-)
I've clearly confused matters here. I completely agree that we must skip timers the GTDT descrbies as secure.
My complaint here is that the spec does not explicitly state that CNTCTLBase.CNTSAR.NS<N> must be set for timers *not* marked as secure (though I believe that is the intent). That is a spec issue, not a code issue.
We unfortunately can't check CNTNSAR, as it is secure-only. :(
Thanks, Mark.
Hi Mark,
On 1 February 2017 at 02:49, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Feb 01, 2017 at 02:43:02AM +0800, Fu Wei wrote:
On 31 January 2017 at 01:49, Mark Rutland mark.rutland@arm.com wrote:
On Thu, Jan 26, 2017 at 01:49:03PM +0800, Fu Wei wrote:
On 26 January 2017 at 01:25, Mark Rutland mark.rutland@arm.com wrote:
On Wed, Jan 25, 2017 at 02:46:12PM +0800, Fu Wei wrote:
On 25 January 2017 at 01:24, Mark Rutland mark.rutland@arm.com wrote: > On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote: >> From: Fu Wei fu.wei@linaro.org
But according to another document(ARMv8-A Foundation Platform User Guide ARM DUI0677K), Table 3-2 ARMv8-A Foundation Platform memory map (continued)
AP_REFCLK CNTBase0, Generic Timer 64KB S AP_REFCLK CNTBase1, Generic Timer 64KB S/NS
Dose it means the timer frame 0 can be accessed in SECURE status only, and the timer frame 1 can be accessed in both status?
That does appear to be what it says.
I assume in this case CNTCTLBase.CNTSAR<0> is RES0.
And because Linux kernel is running on Non-secure EL1, so should we skip "SECURE" timer in Linux?
I guess you mean by checking the GTx Common flags, to see if the timer is secure? Yes, we must skip those.
Yes, exactly.
I think we can check the GTx Common flags, if the timer is set as SECURE, this driver should just skip this timer.
I completely agree that we must skip these.
Looking further at this, the ACPI spec is sorely lacking any statement as to the configuration of CNTCTLBase.{CNTSAR,CNTTIDR,CNTACR}, so it's not clear if we can access anything in a frame, even if it is listed as being a non-secure timer.
I think we need a stronger statement here. Otherwise, we will encounter problems. Linux currently assumes that CNTCTLBase.CNTACR<N> is writeable, given a non-secure frame N. This is only the case if CNTCTLBase.CNTSAR.NS<N> == 1.
the original driver has checked these registers, but the problem is: What if the timer frame is designed to be a secure timer, all the register in this frame is only can be accessed in secure status, just like foundation model? Note: for foundation model, Please check Table 3-1 Access permissions of 3.1 ARMv8-A Foundation Platform memory map in ARMv8-A Foundation Platform User Guide
So I think we should check the GTDT first, if it's not a secure timer, then we can go on checking CNTSAR. :-)
I've clearly confused matters here. I completely agree that we must skip timers the GTDT descrbies as secure.
Yes, got it :-)
My complaint here is that the spec does not explicitly state that CNTCTLBase.CNTSAR.NS<N> must be set for timers *not* marked as secure (though I believe that is the intent). That is a spec issue, not a code issue.
agree :-)
We unfortunately can't check CNTNSAR, as it is secure-only. :(
yes, the spec says: In a system that implements both Secure and Non-secure states, this register is only accessible by Secure accesses.
So I think the firmware(from vendor) can decide which timer frame should be marked as secure according to the GTDT, then kernel just get this info from GTDT instead of checking CNTNSAR.
Thanks, Mark.
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org --- drivers/clocksource/arm_arch_timer.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 9482481..d10c2f7 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -796,15 +796,28 @@ static const struct of_device_id arch_timer_mem_of_match[] __initconst = { {}, };
-static bool __init -arch_timer_needs_probing(int type, const struct of_device_id *matches) +static bool __init arch_timer_needs_of_probing(void) { struct device_node *dn; bool needs_probing = false; + unsigned int mask = 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) + return false; + + /* + * Only one type of timer is probed, + * check if we have another type of timer node in device-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);
return needs_probing; @@ -812,17 +825,8 @@ arch_timer_needs_probing(int type, const struct of_device_id *matches)
static int __init arch_timer_common_init(void) { - unsigned mask = 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)) - return 0; - if (arch_timer_needs_probing(ARCH_TIMER_TYPE_CP15, - arch_timer_of_match)) - return 0; - } + if (acpi_disabled && arch_timer_needs_of_probing()) + return 0;
arch_timer_banner(arch_timers_present); arch_counter_register(arch_timers_present);
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org --- drivers/clocksource/arm_arch_timer.c | 46 ++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 25 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index d10c2f7..9db5fb9 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -825,9 +825,6 @@ static bool __init arch_timer_needs_of_probing(void)
static int __init arch_timer_common_init(void) { - if (acpi_disabled && arch_timer_needs_of_probing()) - return 0; - arch_timer_banner(arch_timers_present); arch_counter_register(arch_timers_present); return arch_timer_arch_init(); @@ -865,26 +862,9 @@ static enum arch_timer_ppi_nr __init arch_timer_select_ppi(void) return ARCH_TIMER_PHYS_SECURE_PPI; }
-static int __init arch_timer_init(void) -{ - int ret; - - ret = arch_timer_register(); - if (ret) - return ret; - - ret = arch_timer_common_init(); - if (ret) - return ret; - - arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI]; - - return 0; -} - static int __init arch_timer_of_init(struct device_node *np) { - int i; + int i, ret;
if (arch_timers_present & ARCH_TIMER_TYPE_CP15) { pr_warn("multiple nodes in dt, skipping\n"); @@ -895,6 +875,8 @@ 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_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI]; + /* * Try to determine the frequency from the device tree, * if fail, get the frequency from the sysreg CNTFRQ. @@ -933,7 +915,14 @@ static int __init arch_timer_of_init(struct device_node *np) arch_counter_suspend_stop = of_property_read_bool(np, "arm,no-tick-in-suspend");
- return arch_timer_init(); + ret = arch_timer_register(); + if (ret) + return ret; + + if (arch_timer_needs_of_probing()) + return 0; + + return arch_timer_common_init(); } CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); @@ -1021,7 +1010,8 @@ static int __init arch_timer_mem_init(struct device_node *np) if (ret) goto out;
- return arch_timer_common_init(); + if (!arch_timer_needs_of_probing()) + ret = arch_timer_common_init(); out: iounmap(cntctlbase); of_node_put(best_frame); @@ -1050,6 +1040,7 @@ static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags) /* Initialize per-processor generic timer */ static int __init arch_timer_acpi_init(struct acpi_table_header *table) { + int ret; struct acpi_table_gtdt *gtdt;
if (arch_timers_present & ARCH_TIMER_TYPE_CP15) { @@ -1077,6 +1068,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 the sysreg CNTFRQ */ arch_timer_detect_rate();
@@ -1089,8 +1082,11 @@ 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_init(); - return 0; + ret = arch_timer_register(); + if (ret) + return ret; + + return arch_timer_common_init(); } CLOCKSOURCE_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init); #endif
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org --- include/clocksource/arm_arch_timer.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h index 4a98c06..b7dd185 100644 --- a/include/clocksource/arm_arch_timer.h +++ b/include/clocksource/arm_arch_timer.h @@ -57,6 +57,8 @@ enum arch_timer_spi_nr { #define ARCH_TIMER_MEM_PHYS_ACCESS 2 #define ARCH_TIMER_MEM_VIRT_ACCESS 3
+#define ARCH_TIMER_MEM_MAX_FRAMES 8 + #define ARCH_TIMER_USR_PCT_ACCESS_EN (1 << 0) /* physical counter */ #define ARCH_TIMER_USR_VCT_ACCESS_EN (1 << 1) /* virtual counter */ #define ARCH_TIMER_VIRT_EVT_EN (1 << 2) @@ -72,6 +74,21 @@ struct arch_timer_kvm_info { int virtual_irq; };
+struct arch_timer_mem_frame { + int frame_nr; + phys_addr_t cntbase; + size_t size; + int phys_irq; + int virt_irq; +}; + +struct arch_timer_mem { + phys_addr_t cntctlbase; + size_t size; + int num_frames; + struct arch_timer_mem_frame frame[ARCH_TIMER_MEM_MAX_FRAMES]; +}; + #ifdef CONFIG_ARM_ARCH_TIMER
extern u32 arch_timer_get_rate(void);
On 2017/1/18 21:25, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org
include/clocksource/arm_arch_timer.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h index 4a98c06..b7dd185 100644 --- a/include/clocksource/arm_arch_timer.h +++ b/include/clocksource/arm_arch_timer.h @@ -57,6 +57,8 @@ enum arch_timer_spi_nr { #define ARCH_TIMER_MEM_PHYS_ACCESS 2 #define ARCH_TIMER_MEM_VIRT_ACCESS 3
+#define ARCH_TIMER_MEM_MAX_FRAMES 8
#define ARCH_TIMER_USR_PCT_ACCESS_EN (1 << 0) /* physical counter */ #define ARCH_TIMER_USR_VCT_ACCESS_EN (1 << 1) /* virtual counter */ #define ARCH_TIMER_VIRT_EVT_EN (1 << 2) @@ -72,6 +74,21 @@ struct arch_timer_kvm_info { int virtual_irq; };
+struct arch_timer_mem_frame {
- int frame_nr;
- phys_addr_t cntbase;
- size_t size;
- int phys_irq;
- int virt_irq;
+};
+struct arch_timer_mem {
- phys_addr_t cntctlbase;
- size_t size;
- int num_frames;
- struct arch_timer_mem_frame frame[ARCH_TIMER_MEM_MAX_FRAMES];
+};
Since struct is introduced but not used in this patch, how about squash it with patch 12/17?
Thanks Hanjun
Hi Hanjun,
On 19 January 2017 at 16:28, Hanjun Guo hanjun.guo@linaro.org wrote:
On 2017/1/18 21:25, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org
include/clocksource/arm_arch_timer.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h index 4a98c06..b7dd185 100644 --- a/include/clocksource/arm_arch_timer.h +++ b/include/clocksource/arm_arch_timer.h @@ -57,6 +57,8 @@ enum arch_timer_spi_nr { #define ARCH_TIMER_MEM_PHYS_ACCESS 2 #define ARCH_TIMER_MEM_VIRT_ACCESS 3
+#define ARCH_TIMER_MEM_MAX_FRAMES 8
#define ARCH_TIMER_USR_PCT_ACCESS_EN (1 << 0) /* physical counter */ #define ARCH_TIMER_USR_VCT_ACCESS_EN (1 << 1) /* virtual counter */ #define ARCH_TIMER_VIRT_EVT_EN (1 << 2) @@ -72,6 +74,21 @@ struct arch_timer_kvm_info { int virtual_irq; };
+struct arch_timer_mem_frame {
int frame_nr;
phys_addr_t cntbase;
size_t size;
int phys_irq;
int virt_irq;
+};
+struct arch_timer_mem {
phys_addr_t cntctlbase;
size_t size;
int num_frames;
struct arch_timer_mem_frame frame[ARCH_TIMER_MEM_MAX_FRAMES];
+};
Since struct is introduced but not used in this patch, how about squash it with patch 12/17?
In the previous patchset, I have been suggested that I should split it out.
Thanks Hanjun
From: Fu Wei fu.wei@linaro.org
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.
Signed-off-by: Fu Wei fu.wei@linaro.org --- drivers/clocksource/arm_arch_timer.c | 142 ++++++++++++++++++++++++----------- 1 file changed, 99 insertions(+), 43 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 9db5fb9..6e8a20c 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -927,17 +927,17 @@ static int __init arch_timer_of_init(struct device_node *np) CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init);
-static int __init arch_timer_mem_init(struct device_node *np) +static int __init arch_timer_mem_init(struct arch_timer_mem *timer_mem) { - struct device_node *frame, *best_frame = NULL; void __iomem *cntctlbase, *base; - unsigned int irq, ret = -EINVAL; + struct arch_timer_mem_frame *best_frame = NULL; + unsigned int irq; u32 cnttidr; + int i, ret;
- arch_timers_present |= ARCH_TIMER_TYPE_MEM; - cntctlbase = of_iomap(np, 0); + cntctlbase = ioremap(timer_mem->cntctlbase, timer_mem->size); if (!cntctlbase) { - pr_err("Can't find CNTCTLBase\n"); + pr_err("Can't map CNTCTLBase.\n"); return -ENXIO; }
@@ -947,26 +947,18 @@ static int __init arch_timer_mem_init(struct device_node *np) * Try to find a virtual capable frame. Otherwise fall back to a * physical capable frame. */ - for_each_available_child_of_node(np, frame) { - int n; - u32 cntacr; - - if (of_property_read_u32(frame, "frame-number", &n)) { - pr_err("Missing frame-number\n"); - of_node_put(frame); - goto out; - } + for (i = 0; i < timer_mem->num_frames; i++) { + u32 cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT | + CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT; + int n = 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; } @@ -974,51 +966,115 @@ 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"); - goto out; + 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"); - goto out; + return -EINVAL; }
- /* - * Try to determine the frequency from the device tree, - * if fail, get the frequency from the CNTFRQ reg of MMIO timer. - */ - 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); + return ret; + } + + arch_counter_base = base; + arch_timers_present |= ARCH_TIMER_TYPE_MEM; + + return 0; +} + +static int __init arch_timer_mem_of_init(struct device_node *np) +{ + struct arch_timer_mem *timer_mem; + struct device_node *frame_node; + struct resource res; + int i, ret = -EINVAL; + + timer_mem = kzalloc(sizeof(*timer_mem), GFP_KERNEL); + if (!timer_mem) + return -ENOMEM; + + if (of_address_to_resource(np, 0, &res)) goto out; + timer_mem->cntctlbase = res.start; + timer_mem->size = resource_size(&res); + + i = 0; + for_each_available_child_of_node(np, frame_node) { + int n; + struct arch_timer_mem_frame *frame; + + if (i >= ARCH_TIMER_MEM_MAX_FRAMES) { + pr_err(FW_BUG "too many frames, only %u are permitted.\n", + ARCH_TIMER_MEM_MAX_FRAMES); + goto out; + } + + frame = &timer_mem->frame[i];
- if (!arch_timer_needs_of_probing()) + if (of_property_read_u32(frame_node, "frame-number", &n)) { + pr_err(FW_BUG "Missing frame-number\n"); + of_node_put(frame_node); + goto out; + } + frame->frame_nr = n; + + if (of_address_to_resource(frame_node, 0, &res)) { + of_node_put(frame_node); + goto out; + } + 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); + + i++; + } + 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); return ret; } CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", - arch_timer_mem_init); + arch_timer_mem_of_init);
#ifdef CONFIG_ACPI static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags)
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org Acked-by: Rafael J. Wysocki rafael.j.wysocki@intel.com Tested-by: Xiongfeng Wang wangxiongfeng2@huawei.com --- 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(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 1117421..ab1ee10 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -2,6 +2,7 @@ config ARM64 def_bool y select ACPI_CCA_REQUIRED if ACPI select ACPI_GENERIC_GSI if ACPI + select ACPI_GTDT if ACPI select ACPI_REDUCED_HARDWARE_ONLY if ACPI select ACPI_MCFG if ACPI select ACPI_SPCR_TABLE if ACPI diff --git a/drivers/acpi/arm64/Kconfig b/drivers/acpi/arm64/Kconfig index 4616da4..5a6f80f 100644 --- a/drivers/acpi/arm64/Kconfig +++ b/drivers/acpi/arm64/Kconfig @@ -4,3 +4,6 @@
config ACPI_IORT bool + +config ACPI_GTDT + bool diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile index 72331f2..1017def 100644 --- a/drivers/acpi/arm64/Makefile +++ b/drivers/acpi/arm64/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_ACPI_IORT) += iort.o +obj-$(CONFIG_ACPI_GTDT) += gtdt.o diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c new file mode 100644 index 0000000..d93a790 --- /dev/null +++ b/drivers/acpi/arm64/gtdt.c @@ -0,0 +1,157 @@ +/* + * ARM Specific GTDT table Support + * + * Copyright (C) 2016, Linaro Ltd. + * Author: Daniel Lezcano daniel.lezcano@linaro.org + * Fu Wei fu.wei@linaro.org + * Hanjun Guo hanjun.guo@linaro.org + * + * 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. + */ + +#include <linux/acpi.h> +#include <linux/init.h> +#include <linux/kernel.h> + +#include <clocksource/arm_arch_timer.h> + +#undef pr_fmt +#define pr_fmt(fmt) "ACPI GTDT: " fmt + +/** + * struct acpi_gtdt_descriptor - Store the key info of GTDT for all functions + * @gtdt: The pointer to the struct acpi_table_gtdt of GTDT table. + * @gtdt_end: The pointer to the end of GTDT table. + * @platform_timer: The pointer to the start of Platform Timer Structure + * + * The struct store the key info of GTDT table, it should be initialized by + * acpi_gtdt_init. + */ +struct acpi_gtdt_descriptor { + struct acpi_table_gtdt *gtdt; + void *gtdt_end; + void *platform_timer; +}; + +static struct acpi_gtdt_descriptor acpi_gtdt_desc __initdata; + +static int __init map_gt_gsi(u32 interrupt, u32 flags) +{ + int trigger, polarity; + + trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE + : ACPI_LEVEL_SENSITIVE; + + polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW + : ACPI_ACTIVE_HIGH; + + return acpi_register_gsi(NULL, interrupt, trigger, polarity); +} + +/** + * acpi_gtdt_map_ppi() - Map the PPIs of per-cpu arch_timer. + * @type: the type of PPI. + * + * Note: Linux on arm64 isn't supported on the secure side. + * So we only handle the non-secure timer PPIs, + * ARCH_TIMER_PHYS_SECURE_PPI is treated as invalid type. + * + * Return: the mapped PPI value, 0 if error. + */ +int __init acpi_gtdt_map_ppi(int type) +{ + struct acpi_table_gtdt *gtdt = acpi_gtdt_desc.gtdt; + + switch (type) { + case ARCH_TIMER_PHYS_NONSECURE_PPI: + return map_gt_gsi(gtdt->non_secure_el1_interrupt, + gtdt->non_secure_el1_flags); + case ARCH_TIMER_VIRT_PPI: + return map_gt_gsi(gtdt->virtual_timer_interrupt, + gtdt->virtual_timer_flags); + + case ARCH_TIMER_HYP_PPI: + return map_gt_gsi(gtdt->non_secure_el2_interrupt, + gtdt->non_secure_el2_flags); + default: + pr_err("Failed to map timer interrupt: invalid type.\n"); + } + + return 0; +} + +/** + * acpi_gtdt_c3stop() - Got c3stop info from GTDT according to the type of PPI. + * @type: the type of PPI. + * + * Return: 1 if the timer can be in deep idle state, 0 otherwise. + */ +bool __init acpi_gtdt_c3stop(int type) +{ + struct acpi_table_gtdt *gtdt = acpi_gtdt_desc.gtdt; + + switch (type) { + case ARCH_TIMER_PHYS_NONSECURE_PPI: + return !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON); + + case ARCH_TIMER_VIRT_PPI: + return !(gtdt->virtual_timer_flags & ACPI_GTDT_ALWAYS_ON); + + case ARCH_TIMER_HYP_PPI: + return !(gtdt->non_secure_el2_flags & ACPI_GTDT_ALWAYS_ON); + + default: + pr_err("Failed to get c3stop info: invalid type.\n"); + } + + return 0; +} + +/** + * acpi_gtdt_init() - Get the info of GTDT table to prepare for further init. + * @table: The pointer to GTDT table. + * @platform_timer_count: The pointer of int variate for returning the + * number of platform timers. It can be NULL, if + * driver don't need this info. + * + * Return: 0 if success, -EINVAL if error. + */ +int __init acpi_gtdt_init(struct acpi_table_header *table, + int *platform_timer_count) +{ + int ret = 0; + int timer_count = 0; + void *platform_timer = NULL; + struct acpi_table_gtdt *gtdt; + + gtdt = container_of(table, struct acpi_table_gtdt, header); + acpi_gtdt_desc.gtdt = gtdt; + acpi_gtdt_desc.gtdt_end = (void *)table + table->length; + + if (table->revision < 2) + pr_debug("Revision:%d doesn't support Platform Timers.\n", + table->revision); + else if (!gtdt->platform_timer_count) + pr_debug("No Platform Timer.\n"); + else + timer_count = gtdt->platform_timer_count; + + if (timer_count) { + platform_timer = (void *)gtdt + gtdt->platform_timer_offset; + if (platform_timer < (void *)table + + sizeof(struct acpi_table_gtdt)) { + pr_err(FW_BUG "invalid timer data.\n"); + timer_count = 0; + platform_timer = NULL; + ret = -EINVAL; + } + } + + acpi_gtdt_desc.platform_timer = platform_timer; + if (platform_timer_count) + *platform_timer_count = timer_count; + + return ret; +} diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 5b36974..d0b271e 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -597,6 +597,12 @@ enum acpi_reconfig_event { int acpi_reconfig_notifier_register(struct notifier_block *nb); int acpi_reconfig_notifier_unregister(struct notifier_block *nb);
+#ifdef CONFIG_ACPI_GTDT +int acpi_gtdt_init(struct acpi_table_header *table, int *platform_timer_count); +int acpi_gtdt_map_ppi(int type); +bool acpi_gtdt_c3stop(int type); +#endif + #else /* !CONFIG_ACPI */
#define acpi_disabled 1
On 2017/1/18 21:25, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org Acked-by: Rafael J. Wysocki rafael.j.wysocki@intel.com Tested-by: Xiongfeng Wang wangxiongfeng2@huawei.com
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(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 1117421..ab1ee10 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -2,6 +2,7 @@ config ARM64 def_bool y select ACPI_CCA_REQUIRED if ACPI select ACPI_GENERIC_GSI if ACPI
- select ACPI_GTDT if ACPI select ACPI_REDUCED_HARDWARE_ONLY if ACPI select ACPI_MCFG if ACPI select ACPI_SPCR_TABLE if ACPI
diff --git a/drivers/acpi/arm64/Kconfig b/drivers/acpi/arm64/Kconfig index 4616da4..5a6f80f 100644 --- a/drivers/acpi/arm64/Kconfig +++ b/drivers/acpi/arm64/Kconfig @@ -4,3 +4,6 @@
config ACPI_IORT bool
+config ACPI_GTDT
- bool
diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile index 72331f2..1017def 100644 --- a/drivers/acpi/arm64/Makefile +++ b/drivers/acpi/arm64/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_ACPI_IORT) += iort.o +obj-$(CONFIG_ACPI_GTDT) += gtdt.o diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c new file mode 100644 index 0000000..d93a790 --- /dev/null +++ b/drivers/acpi/arm64/gtdt.c @@ -0,0 +1,157 @@
[...]
+/**
- acpi_gtdt_init() - Get the info of GTDT table to prepare for further init.
- @table: The pointer to GTDT table.
- @platform_timer_count: The pointer of int variate for returning the
number of platform timers. It can be NULL, if
driver don't need this info.
- Return: 0 if success, -EINVAL if error.
- */
+int __init acpi_gtdt_init(struct acpi_table_header *table,
int *platform_timer_count)
+{
- int ret = 0;
- int timer_count = 0;
- void *platform_timer = NULL;
- struct acpi_table_gtdt *gtdt;
- gtdt = container_of(table, struct acpi_table_gtdt, header);
- acpi_gtdt_desc.gtdt = gtdt;
- acpi_gtdt_desc.gtdt_end = (void *)table + table->length;
- if (table->revision < 2)
pr_debug("Revision:%d doesn't support Platform Timers.\n",
table->revision);
GTDT table revision is updated to 2 in ACPI 5.1, we will not support ACPI version under 5.1 and disable ACPI in FADT parse before this code is called, so if we get revision <2 here, I think we need to print warning (we need to keep the firmware stick to the spec on ARM64).
- else if (!gtdt->platform_timer_count)
pr_debug("No Platform Timer.\n");
- else
timer_count = gtdt->platform_timer_count;
- if (timer_count) {
platform_timer = (void *)gtdt + gtdt->platform_timer_offset;
if (platform_timer < (void *)table +
sizeof(struct acpi_table_gtdt)) {
pr_err(FW_BUG "invalid timer data.\n");
It's ok but I didn't see other ACPI tables parsing did this check, maybe we can just remove it :)
timer_count = 0;
platform_timer = NULL;
ret = -EINVAL;
}
- }
- acpi_gtdt_desc.platform_timer = platform_timer;
- if (platform_timer_count)
*platform_timer_count = timer_count;
Then the code will much simple:
if (gtdt->platform_timer_count) { acpi_gtdt_desc.platform_timer = (void *)gtdt + gtdt->platform_timer_offset; if (platform_timer_count) *platform_timer_count = gtdt->platform_timer_count; }
return 0;
and remove ret, timer_count and platform_timer.
Thanks Hanjun
Hi Hanjun,
On 19 January 2017 at 17:11, Hanjun Guo hanjun.guo@linaro.org wrote:
On 2017/1/18 21:25, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org Acked-by: Rafael J. Wysocki rafael.j.wysocki@intel.com Tested-by: Xiongfeng Wang wangxiongfeng2@huawei.com
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(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 1117421..ab1ee10 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -2,6 +2,7 @@ config ARM64 def_bool y select ACPI_CCA_REQUIRED if ACPI select ACPI_GENERIC_GSI if ACPI
select ACPI_GTDT if ACPI select ACPI_REDUCED_HARDWARE_ONLY if ACPI select ACPI_MCFG if ACPI select ACPI_SPCR_TABLE if ACPI
diff --git a/drivers/acpi/arm64/Kconfig b/drivers/acpi/arm64/Kconfig index 4616da4..5a6f80f 100644 --- a/drivers/acpi/arm64/Kconfig +++ b/drivers/acpi/arm64/Kconfig @@ -4,3 +4,6 @@
config ACPI_IORT bool
+config ACPI_GTDT
bool
diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile index 72331f2..1017def 100644 --- a/drivers/acpi/arm64/Makefile +++ b/drivers/acpi/arm64/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_ACPI_IORT) += iort.o +obj-$(CONFIG_ACPI_GTDT) += gtdt.o diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c new file mode 100644 index 0000000..d93a790 --- /dev/null +++ b/drivers/acpi/arm64/gtdt.c @@ -0,0 +1,157 @@
[...]
+/**
- acpi_gtdt_init() - Get the info of GTDT table to prepare for further
init.
- @table: The pointer to GTDT table.
- @platform_timer_count: The pointer of int variate for returning
the
number of platform timers. It can be NULL,
if
driver don't need this info.
- Return: 0 if success, -EINVAL if error.
- */
+int __init acpi_gtdt_init(struct acpi_table_header *table,
int *platform_timer_count)
+{
int ret = 0;
int timer_count = 0;
void *platform_timer = NULL;
struct acpi_table_gtdt *gtdt;
gtdt = container_of(table, struct acpi_table_gtdt, header);
acpi_gtdt_desc.gtdt = gtdt;
acpi_gtdt_desc.gtdt_end = (void *)table + table->length;
if (table->revision < 2)
pr_debug("Revision:%d doesn't support Platform Timers.\n",
table->revision);
GTDT table revision is updated to 2 in ACPI 5.1, we will not support ACPI version under 5.1 and disable ACPI in FADT parse before this code is called, so if we get revision <2 here, I think we need to print warning (we need to keep the firmware stick to the spec on ARM64).
agree, will change pr_debug to pr_warn.
Thanks :-)
else if (!gtdt->platform_timer_count)
pr_debug("No Platform Timer.\n");
else
timer_count = gtdt->platform_timer_count;
if (timer_count) {
platform_timer = (void *)gtdt +
gtdt->platform_timer_offset;
if (platform_timer < (void *)table +
sizeof(struct acpi_table_gtdt)) {
pr_err(FW_BUG "invalid timer data.\n");
It's ok but I didn't see other ACPI tables parsing did this check, maybe we can just remove it :)
here, I want to make sure the FW is valid. Once there is a FW bug, we could just return with error. :-)
timer_count = 0;
platform_timer = NULL;
ret = -EINVAL;
}
}
acpi_gtdt_desc.platform_timer = platform_timer;
if (platform_timer_count)
*platform_timer_count = timer_count;
Then the code will much simple:
if (gtdt->platform_timer_count) { acpi_gtdt_desc.platform_timer = (void *)gtdt + gtdt->platform_timer_offset; if (platform_timer_count) *platform_timer_count = gtdt->platform_timer_count; }
return 0;
and remove ret, timer_count and platform_timer.
yes, this may can simplify the function, but this will be released at the end of init because of "__init" :-) So how about let's just keep this check to make sure the FW is OK. :-)
Thanks Hanjun
On Thu, Jan 19, 2017 at 06:32:55PM +0800, Fu Wei wrote:
On 19 January 2017 at 17:11, Hanjun Guo hanjun.guo@linaro.org wrote:
On 2017/1/18 21:25, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
else if (!gtdt->platform_timer_count)
pr_debug("No Platform Timer.\n");
else
timer_count = gtdt->platform_timer_count;
if (timer_count) {
platform_timer = (void *)gtdt +
gtdt->platform_timer_offset;
if (platform_timer < (void *)table +
sizeof(struct acpi_table_gtdt)) {
pr_err(FW_BUG "invalid timer data.\n");
It's ok but I didn't see other ACPI tables parsing did this check, maybe we can just remove it :)
here, I want to make sure the FW is valid. Once there is a FW bug, we could just return with error. :-)
Yes, please keep the check!
If anything, it would be nicer for the other ACPI code to verify things a little more stringently.
Thanks, Mark.
Hi Mark,
On 19 January 2017 at 19:16, Mark Rutland mark.rutland@arm.com wrote:
On Thu, Jan 19, 2017 at 06:32:55PM +0800, Fu Wei wrote:
On 19 January 2017 at 17:11, Hanjun Guo hanjun.guo@linaro.org wrote:
On 2017/1/18 21:25, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
else if (!gtdt->platform_timer_count)
pr_debug("No Platform Timer.\n");
else
timer_count = gtdt->platform_timer_count;
if (timer_count) {
platform_timer = (void *)gtdt +
gtdt->platform_timer_offset;
if (platform_timer < (void *)table +
sizeof(struct acpi_table_gtdt)) {
pr_err(FW_BUG "invalid timer data.\n");
It's ok but I didn't see other ACPI tables parsing did this check, maybe we can just remove it :)
here, I want to make sure the FW is valid. Once there is a FW bug, we could just return with error. :-)
Yes, please keep the check!
Yes, we will keep this check :-)
Thanks!
If anything, it would be nicer for the other ACPI code to verify things a little more stringently.
Thanks, Mark.
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org Tested-by: Xiongfeng Wang wangxiongfeng2@huawei.com --- drivers/clocksource/arm_arch_timer.c | 46 ++++++++++-------------------------- 1 file changed, 13 insertions(+), 33 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 6e8a20c..79dc004 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -1076,59 +1076,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 -static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags) -{ - int trigger, polarity; - - if (!interrupt) - return 0; - - trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE - : ACPI_LEVEL_SENSITIVE; - - polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW - : ACPI_ACTIVE_HIGH; - - return acpi_register_gsi(NULL, interrupt, trigger, polarity); -} - +#ifdef CONFIG_ACPI_GTDT /* Initialize per-processor generic timer */ static int __init arch_timer_acpi_init(struct acpi_table_header *table) { int ret; - struct acpi_table_gtdt *gtdt;
if (arch_timers_present & ARCH_TIMER_TYPE_CP15) { pr_warn("already initialized, skipping\n"); return -EINVAL; }
- gtdt = container_of(table, struct acpi_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"); + return ret; + }
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 the sysreg 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"); @@ -1136,7 +1113,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 the sysreg CNTFRQ */ + arch_timer_detect_rate();
ret = arch_timer_register(); if (ret)
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- drivers/acpi/arm64/gtdt.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/acpi.h | 1 + 2 files changed, 125 insertions(+)
diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c index d93a790..91ea6cb 100644 --- a/drivers/acpi/arm64/gtdt.c +++ b/drivers/acpi/arm64/gtdt.c @@ -37,6 +37,28 @@ struct acpi_gtdt_descriptor {
static struct acpi_gtdt_descriptor acpi_gtdt_desc __initdata;
+static inline void *next_platform_timer(void *platform_timer) +{ + struct acpi_gtdt_header *gh = platform_timer; + + platform_timer += gh->length; + if (platform_timer < acpi_gtdt_desc.gtdt_end) + return platform_timer; + + return NULL; +} + +#define for_each_platform_timer(_g) \ + for (_g = acpi_gtdt_desc.platform_timer; _g; \ + _g = next_platform_timer(_g)) + +static inline bool is_timer_block(void *platform_timer) +{ + struct acpi_gtdt_header *gh = platform_timer; + + return gh->type == ACPI_GTDT_TYPE_TIMER_BLOCK; +} + static int __init map_gt_gsi(u32 interrupt, u32 flags) { int trigger, polarity; @@ -155,3 +177,105 @@ int __init acpi_gtdt_init(struct acpi_table_header *table,
return ret; } + +static int __init gtdt_parse_timer_block(struct acpi_gtdt_timer_block *block, + struct arch_timer_mem *data) +{ + int i; + struct acpi_gtdt_timer_entry *frame; + + if (!block->timer_count) { + pr_err(FW_BUG "GT block present, but frame count is zero."); + return -ENODEV; + } + + if (block->timer_count > ARCH_TIMER_MEM_MAX_FRAMES) { + pr_err(FW_BUG "GT block lists %d frames, ACPI spec only allows 8\n", + block->timer_count); + return -EINVAL; + } + + data->cntctlbase = (phys_addr_t)block->block_address; + /* + * According to "Table * CNTCTLBase memory map" of + * <ARM Architecture Reference Manual> for ARMv8, + * The size of the CNTCTLBase frame is 4KB(Offset 0x000 – 0xFFC). + */ + data->size = SZ_4K; + data->num_frames = block->timer_count; + + frame = (void *)block + block->timer_offset; + if (frame + block->timer_count != (void *)block + block->header.length) + return -EINVAL; + + /* + * Get the GT timer Frame data for every GT Block Timer + */ + for (i = 0; i < block->timer_count; i++, frame++) { + if (!frame->base_address || !frame->timer_interrupt) + return -EINVAL; + + data->frame[i].phys_irq = map_gt_gsi(frame->timer_interrupt, + frame->timer_flags); + if (data->frame[i].phys_irq <= 0) { + pr_warn("failed to map physical timer irq in frame %d.\n", + i); + return -EINVAL; + } + + data->frame[i].virt_irq = + map_gt_gsi(frame->virtual_timer_interrupt, + frame->virtual_timer_flags); + if (data->frame[i].virt_irq <= 0) { + pr_warn("failed to map virtual timer irq in frame %d.\n", + i); + acpi_unregister_gsi(frame->timer_interrupt); + return -EINVAL; + } + + data->frame[i].frame_nr = frame->frame_number; + data->frame[i].cntbase = frame->base_address; + /* + * According to "Table * CNTBaseN memory map" of + * <ARM Architecture Reference Manual> for ARMv8, + * The size of the CNTBaseN frame is 4KB(Offset 0x000 – 0xFFC). + */ + data->frame[i].size = SZ_4K; + } + + return 0; +} + +/** + * acpi_arch_timer_mem_init() - Get the info of all GT blocks in GTDT table. + * @data: the pointer to the array of struct arch_timer_mem for returning + * the result of parsing. The element number of this array should + * be platform_timer_count(the total number of platform timers). + * @count: The pointer of int variate for returning the number of GT + * blocks we have parsed. + * + * Return: 0 if success, -EINVAL/-ENODEV if error. + */ +int __init acpi_arch_timer_mem_init(struct arch_timer_mem *data, + int *timer_count) +{ + int ret; + void *platform_timer; + + *timer_count = 0; + for_each_platform_timer(platform_timer) { + if (is_timer_block(platform_timer)) { + ret = gtdt_parse_timer_block(platform_timer, data); + if (ret) + return ret; + data++; + (*timer_count)++; + } + } + + if (*timer_count) + pr_info("found %d memory-mapped timer block(s).\n", + *timer_count); + + return 0; +} diff --git a/include/linux/acpi.h b/include/linux/acpi.h index d0b271e..51e85b9 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -601,6 +601,7 @@ int acpi_reconfig_notifier_unregister(struct notifier_block *nb); int acpi_gtdt_init(struct acpi_table_header *table, int *platform_timer_count); int acpi_gtdt_map_ppi(int type); bool acpi_gtdt_c3stop(int type); +int acpi_arch_timer_mem_init(struct arch_timer_mem *data, int *timer_count); #endif
#else /* !CONFIG_ACPI */
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org --- drivers/clocksource/arm_arch_timer.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 79dc004..7ca2da7 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -1077,10 +1077,36 @@ CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", arch_timer_mem_of_init);
#ifdef CONFIG_ACPI_GTDT -/* Initialize per-processor generic timer */ +static int __init arch_timer_mem_acpi_init(int platform_timer_count) +{ + struct arch_timer_mem *timer_mem; + int timer_count, i, ret; + + timer_mem = kcalloc(platform_timer_count, sizeof(*timer_mem), + GFP_KERNEL); + if (!timer_mem) + return -ENOMEM; + + ret = acpi_arch_timer_mem_init(timer_mem, &timer_count); + if (ret || !timer_count) + goto error; + + for (i = 0; i < timer_count; i++) { + ret = arch_timer_mem_init(timer_mem); + if (!ret) + break; + timer_mem++; + } + +error: + kfree(timer_mem); + return ret; +} + +/* Initialize per-processor generic timer and memory-mapped timer(if present) */ static int __init arch_timer_acpi_init(struct acpi_table_header *table) { - int ret; + int ret, platform_timer_count;
if (arch_timers_present & ARCH_TIMER_TYPE_CP15) { pr_warn("already initialized, skipping\n"); @@ -1089,7 +1115,7 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
arch_timers_present |= ARCH_TIMER_TYPE_CP15;
- ret = acpi_gtdt_init(table, NULL); + ret = acpi_gtdt_init(table, &platform_timer_count); if (ret) { pr_err("Failed to init GTDT table.\n"); return ret; @@ -1122,6 +1148,9 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table) if (ret) return ret;
+ if (arch_timer_mem_acpi_init(platform_timer_count)) + pr_err("Failed to initialize memory-mapped timer.\n"); + return arch_timer_common_init(); } CLOCKSOURCE_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init);
On 2017/1/18 21:25, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org
drivers/clocksource/arm_arch_timer.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 79dc004..7ca2da7 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -1077,10 +1077,36 @@ CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", arch_timer_mem_of_init);
#ifdef CONFIG_ACPI_GTDT -/* Initialize per-processor generic timer */ +static int __init arch_timer_mem_acpi_init(int platform_timer_count) +{
- struct arch_timer_mem *timer_mem;
- int timer_count, i, ret;
if (!platform_timer_count) return 0;
Did I miss something?
Thanks Hanjun
- timer_mem = kcalloc(platform_timer_count, sizeof(*timer_mem),
GFP_KERNEL);
- if (!timer_mem)
return -ENOMEM;
- ret = acpi_arch_timer_mem_init(timer_mem, &timer_count);
- if (ret || !timer_count)
goto error;
- for (i = 0; i < timer_count; i++) {
ret = arch_timer_mem_init(timer_mem);
if (!ret)
break;
timer_mem++;
- }
+error:
- kfree(timer_mem);
- return ret;
+}
+/* Initialize per-processor generic timer and memory-mapped timer(if present) */ static int __init arch_timer_acpi_init(struct acpi_table_header *table) {
- int ret;
int ret, platform_timer_count;
if (arch_timers_present & ARCH_TIMER_TYPE_CP15) { pr_warn("already initialized, skipping\n");
@@ -1089,7 +1115,7 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
arch_timers_present |= ARCH_TIMER_TYPE_CP15;
- ret = acpi_gtdt_init(table, NULL);
- ret = acpi_gtdt_init(table, &platform_timer_count); if (ret) { pr_err("Failed to init GTDT table.\n"); return ret;
@@ -1122,6 +1148,9 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table) if (ret) return ret;
- if (arch_timer_mem_acpi_init(platform_timer_count))
pr_err("Failed to initialize memory-mapped timer.\n");
- return arch_timer_common_init();
} CLOCKSOURCE_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init);
Hi Hanjun,
On 19 January 2017 at 17:16, Hanjun Guo hanjun.guo@linaro.org wrote:
On 2017/1/18 21:25, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org
drivers/clocksource/arm_arch_timer.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 79dc004..7ca2da7 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -1077,10 +1077,36 @@ CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", arch_timer_mem_of_init);
#ifdef CONFIG_ACPI_GTDT -/* Initialize per-processor generic timer */ +static int __init arch_timer_mem_acpi_init(int platform_timer_count) +{
struct arch_timer_mem *timer_mem;
int timer_count, i, ret;
if (!platform_timer_count) return 0;
Did I miss something?
Ah, thanks, I guess I miss this check below.
Thanks Hanjun
timer_mem = kcalloc(platform_timer_count, sizeof(*timer_mem),
GFP_KERNEL);
if (!timer_mem)
return -ENOMEM;
ret = acpi_arch_timer_mem_init(timer_mem, &timer_count);
if (ret || !timer_count)
goto error;
for (i = 0; i < timer_count; i++) {
ret = arch_timer_mem_init(timer_mem);
if (!ret)
break;
timer_mem++;
}
+error:
kfree(timer_mem);
return ret;
+}
+/* Initialize per-processor generic timer and memory-mapped timer(if present) */ static int __init arch_timer_acpi_init(struct acpi_table_header *table) {
int ret;
int ret, platform_timer_count; if (arch_timers_present & ARCH_TIMER_TYPE_CP15) { pr_warn("already initialized, skipping\n");
@@ -1089,7 +1115,7 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
arch_timers_present |= ARCH_TIMER_TYPE_CP15;
ret = acpi_gtdt_init(table, NULL);
ret = acpi_gtdt_init(table, &platform_timer_count); if (ret) { pr_err("Failed to init GTDT table.\n"); return ret;
@@ -1122,6 +1148,9 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table) if (ret) return ret;
if (arch_timer_mem_acpi_init(platform_timer_count))
+ if (platform_timer_count && + arch_timer_mem_acpi_init(platform_timer_count))
pr_err("Failed to initialize memory-mapped timer.\n");
return arch_timer_common_init();
} CLOCKSOURCE_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init);
On 2017/1/19 18:02, Fu Wei wrote:
Hi Hanjun,
On 19 January 2017 at 17:16, Hanjun Guo hanjun.guo@linaro.org wrote:
On 2017/1/18 21:25, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org
drivers/clocksource/arm_arch_timer.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 79dc004..7ca2da7 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -1077,10 +1077,36 @@ CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", arch_timer_mem_of_init);
#ifdef CONFIG_ACPI_GTDT -/* Initialize per-processor generic timer */ +static int __init arch_timer_mem_acpi_init(int platform_timer_count) +{
struct arch_timer_mem *timer_mem;
int timer_count, i, ret;
if (!platform_timer_count) return 0;
Did I miss something?
Ah, thanks, I guess I miss this check below.
Thanks Hanjun
timer_mem = kcalloc(platform_timer_count, sizeof(*timer_mem),
GFP_KERNEL);
if (!timer_mem)
return -ENOMEM;
ret = acpi_arch_timer_mem_init(timer_mem, &timer_count);
if (ret || !timer_count)
goto error;
for (i = 0; i < timer_count; i++) {
ret = arch_timer_mem_init(timer_mem);
if (!ret)
break;
timer_mem++;
}
+error:
kfree(timer_mem);
return ret;
+}
+/* Initialize per-processor generic timer and memory-mapped timer(if present) */ static int __init arch_timer_acpi_init(struct acpi_table_header *table) {
int ret;
int ret, platform_timer_count; if (arch_timers_present & ARCH_TIMER_TYPE_CP15) { pr_warn("already initialized, skipping\n");
@@ -1089,7 +1115,7 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
arch_timers_present |= ARCH_TIMER_TYPE_CP15;
ret = acpi_gtdt_init(table, NULL);
ret = acpi_gtdt_init(table, &platform_timer_count); if (ret) { pr_err("Failed to init GTDT table.\n"); return ret;
@@ -1122,6 +1148,9 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table) if (ret) return ret;
if (arch_timer_mem_acpi_init(platform_timer_count))
if (platform_timer_count &&
arch_timer_mem_acpi_init(platform_timer_count))
It's better.
Thanks Hanjun
From: Fu Wei fu.wei@linaro.org
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 fu.wei@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org Tested-by: Xiongfeng Wang wangxiongfeng2@huawei.com --- drivers/acpi/arm64/gtdt.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/watchdog/Kconfig | 1 + 2 files changed, 94 insertions(+)
diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c index 91ea6cb..22d3659 100644 --- a/drivers/acpi/arm64/gtdt.c +++ b/drivers/acpi/arm64/gtdt.c @@ -14,6 +14,7 @@ #include <linux/acpi.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/platform_device.h>
#include <clocksource/arm_arch_timer.h>
@@ -59,6 +60,13 @@ static inline bool is_timer_block(void *platform_timer) return gh->type == ACPI_GTDT_TYPE_TIMER_BLOCK; }
+static inline bool is_watchdog(void *platform_timer) +{ + struct acpi_gtdt_header *gh = platform_timer; + + return gh->type == ACPI_GTDT_TYPE_WATCHDOG; +} + static int __init map_gt_gsi(u32 interrupt, u32 flags) { int trigger, polarity; @@ -279,3 +287,88 @@ int __init acpi_arch_timer_mem_init(struct arch_timer_mem *data,
return 0; } + +/* + * Initialize a SBSA generic Watchdog platform device info from GTDT + */ +static int __init gtdt_import_sbsa_gwdt(struct acpi_gtdt_watchdog *wd, + int index) +{ + struct platform_device *pdev; + int irq = map_gt_gsi(wd->timer_interrupt, wd->timer_flags); + int no_irq = 1; + + /* + * According to SBSA specification the size of refresh and control + * frames of SBSA Generic Watchdog is SZ_4K(Offset 0x000 – 0xFFF). + */ + struct resource res[] = { + 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"); + else if (irq <= 0) + pr_warn("failed to map the Watchdog interrupt.\n"); + else + no_irq = 0; + + /* + * Add a platform device named "sbsa-gwdt" to match the platform driver. + * "sbsa-gwdt": SBSA(Server Base System Architecture) Generic Watchdog + * The platform driver (like drivers/watchdog/sbsa_gwdt.c)can get device + * info below by matching this name. + */ + pdev = platform_device_register_simple("sbsa-gwdt", index, res, + ARRAY_SIZE(res) - no_irq); + if (IS_ERR(pdev)) { + acpi_unregister_gsi(wd->timer_interrupt); + return PTR_ERR(pdev); + } + + return 0; +} + +static int __init gtdt_sbsa_gwdt_init(void) +{ + int ret, i = 0; + void *platform_timer; + struct acpi_table_header *table; + + if (acpi_disabled) + return 0; + + if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_GTDT, 0, &table))) + return -EINVAL; + + ret = acpi_gtdt_init(table, NULL); + if (ret) + return ret; + + 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); + + return ret; +} + +device_initcall(gtdt_sbsa_gwdt_init); diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index acb00b5..c899df1 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -219,6 +219,7 @@ config ARM_SBSA_WATCHDOG tristate "ARM SBSA Generic Watchdog" depends on ARM64 depends on ARM_ARCH_TIMER + depends on ACPI_GTDT || !ACPI select WATCHDOG_CORE help ARM SBSA Generic Watchdog has two stage timeouts:
Hi Fuwei,
On 2017/1/18 21:25, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
This patchset: (1)Preparation for adding GTDT support in arm_arch_timer: 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 the header file 5. Add new enum for SPIs 6. Rework PPI determination; 7. Rework counter frequency detection; 8. Refactor arch_timer_needs_probing, move it into DT init call 9. 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: v20: https://lkml.org/lkml/2017/1/18/ Reorder the first 4 patches and split the 4th patches. Leave CNTHCTL_* as they originally were. Fix the bug in arch_timer_select_ppi. Split "Rework counter frequency detection" patch. Rework the arch_timer_detect_rate function. Improve the commit message of "Refactor MMIO timer probing". Rebase to 4.10.0-rc4
Other than some minor comments I raised, the patch set looks fine to me, and I tested this patch set on D03, the percpu arch timer works fine as before.
With the comments fixed, Reviewed-by: Hanjun Guo hanjun.gu@linaro.org Tested-by: Hanjun Guo hanjun.gu@linaro.org
Thanks Hanjun
Hi Hanjun,
On 19 January 2017 at 17:20, Hanjun Guo hanjun.guo@linaro.org wrote:
Hi Fuwei,
On 2017/1/18 21:25, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
This patchset: (1)Preparation for adding GTDT support in arm_arch_timer: 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 the header file 5. Add new enum for SPIs 6. Rework PPI determination; 7. Rework counter frequency detection; 8. Refactor arch_timer_needs_probing, move it into DT init call 9. 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: v20: https://lkml.org/lkml/2017/1/18/ Reorder the first 4 patches and split the 4th patches. Leave CNTHCTL_* as they originally were. Fix the bug in arch_timer_select_ppi. Split "Rework counter frequency detection" patch. Rework the arch_timer_detect_rate function. Improve the commit message of "Refactor MMIO timer probing". Rebase to 4.10.0-rc4
Other than some minor comments I raised, the patch set looks fine to me, and I tested this patch set on D03, the percpu arch timer works fine as before.
With the comments fixed, Reviewed-by: Hanjun Guo hanjun.gu@linaro.org Tested-by: Hanjun Guo hanjun.gu@linaro.org
Great thanks for your testing. :-)
will apply Reviewed-by: Hanjun Guo hanjun.guo@linaro.org on all patches, and Tested-by: Hanjun Guo hanjun.guo@linaro.org on arch_timer patches.
Thanks Hanjun
Hi,
On Wed, Jan 18, 2017 at 09:25:24PM +0800, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
This patchset: (1)Preparation for adding GTDT support in arm_arch_timer: 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 the header file 5. Add new enum for SPIs 6. Rework PPI determination;
I've taken these few patches onto a preliminary/unstable branch [1].
I haven't had the time to take a look at the rest of the series yet. I intend to go over that tomorrow, picking what I can, and leaving feedback for anything that will need rework.
Thanks, Mark.
[1] git://git.kernel.org/pub/scm/linux/kernel/git/mark/linux.git arch-timer/updates
Hi Mark
On 24 January 2017 at 02:54, Mark Rutland mark.rutland@arm.com wrote:
Hi,
On Wed, Jan 18, 2017 at 09:25:24PM +0800, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
This patchset: (1)Preparation for adding GTDT support in arm_arch_timer: 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 the header file 5. Add new enum for SPIs 6. Rework PPI determination;
I've taken these few patches onto a preliminary/unstable branch [1].
Many thanks for the good news!
I haven't had the time to take a look at the rest of the series yet. I intend to go over that tomorrow, picking what I can, and leaving feedback for anything that will need rework.
Thanks, I will wait for your feedback, and improve this patchset ASAP.
Thanks, Mark.
[1] git://git.kernel.org/pub/scm/linux/kernel/git/mark/linux.git arch-timer/updates