diff options
Diffstat (limited to 'drivers/clocksource/arm_arch_timer.c')
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 136 |
1 files changed, 91 insertions, 45 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index c64d543d6..5152b3898 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -32,6 +32,14 @@ #define CNTTIDR 0x08 #define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4)) +#define CNTACR(n) (0x40 + ((n) * 4)) +#define CNTACR_RPCT BIT(0) +#define CNTACR_RVCT BIT(1) +#define CNTACR_RFRQ BIT(2) +#define CNTACR_RVOFF BIT(3) +#define CNTACR_RWVT BIT(4) +#define CNTACR_RWPT BIT(5) + #define CNTVCT_LO 0x08 #define CNTVCT_HI 0x0c #define CNTFRQ 0x10 @@ -67,7 +75,7 @@ static int arch_timer_ppi[MAX_TIMER_PPI]; static struct clock_event_device __percpu *arch_timer_evt; -static bool arch_timer_use_virtual = true; +static enum ppi_nr arch_timer_uses_ppi = VIRT_PPI; static bool arch_timer_c3stop; static bool arch_timer_mem_use_virtual; @@ -263,14 +271,22 @@ static void __arch_timer_setup(unsigned type, clk->name = "arch_sys_timer"; clk->rating = 450; clk->cpumask = cpumask_of(smp_processor_id()); - if (arch_timer_use_virtual) { - clk->irq = arch_timer_ppi[VIRT_PPI]; + clk->irq = arch_timer_ppi[arch_timer_uses_ppi]; + switch (arch_timer_uses_ppi) { + case 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; - } else { - clk->irq = arch_timer_ppi[PHYS_SECURE_PPI]; + break; + case PHYS_SECURE_PPI: + case PHYS_NONSECURE_PPI: + case 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; + break; + default: + BUG(); } } else { clk->features |= CLOCK_EVT_FEAT_DYNIRQ; @@ -279,10 +295,12 @@ static void __arch_timer_setup(unsigned type, clk->cpumask = cpu_all_mask; if (arch_timer_mem_use_virtual) { clk->set_state_shutdown = arch_timer_shutdown_virt_mem; + clk->set_state_oneshot_stopped = arch_timer_shutdown_virt_mem; clk->set_next_event = arch_timer_set_next_event_virt_mem; } else { clk->set_state_shutdown = arch_timer_shutdown_phys_mem; + clk->set_state_oneshot_stopped = arch_timer_shutdown_phys_mem; clk->set_next_event = arch_timer_set_next_event_phys_mem; } @@ -338,17 +356,20 @@ static void arch_counter_set_user_access(void) arch_timer_set_cntkctl(cntkctl); } +static bool arch_timer_has_nonsecure_ppi(void) +{ + return (arch_timer_uses_ppi == PHYS_SECURE_PPI && + arch_timer_ppi[PHYS_NONSECURE_PPI]); +} + static int arch_timer_setup(struct clock_event_device *clk) { __arch_timer_setup(ARCH_CP15_TIMER, clk); - if (arch_timer_use_virtual) - enable_percpu_irq(arch_timer_ppi[VIRT_PPI], 0); - else { - enable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI], 0); - if (arch_timer_ppi[PHYS_NONSECURE_PPI]) - enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], 0); - } + enable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], 0); + + if (arch_timer_has_nonsecure_ppi()) + enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], 0); arch_counter_set_user_access(); if (IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM)) @@ -390,7 +411,7 @@ static void arch_timer_banner(unsigned type) (unsigned long)arch_timer_rate / 1000000, (unsigned long)(arch_timer_rate / 10000) % 100, type & ARCH_CP15_TIMER ? - arch_timer_use_virtual ? "virt" : "phys" : + (arch_timer_uses_ppi == VIRT_PPI) ? "virt" : "phys" : "", type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? "/" : "", type & ARCH_MEM_TIMER ? @@ -460,7 +481,7 @@ static void __init arch_counter_register(unsigned type) /* Register the CP15 based counter if we have one */ if (type & ARCH_CP15_TIMER) { - if (IS_ENABLED(CONFIG_ARM64) || arch_timer_use_virtual) + if (IS_ENABLED(CONFIG_ARM64) || arch_timer_uses_ppi == VIRT_PPI) arch_timer_read_counter = arch_counter_get_cntvct; else arch_timer_read_counter = arch_counter_get_cntpct; @@ -490,13 +511,9 @@ 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()); - if (arch_timer_use_virtual) - disable_percpu_irq(arch_timer_ppi[VIRT_PPI]); - else { - disable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI]); - if (arch_timer_ppi[PHYS_NONSECURE_PPI]) - disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]); - } + 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]); clk->set_state_shutdown(clk); } @@ -562,12 +579,14 @@ static int __init arch_timer_register(void) goto out; } - if (arch_timer_use_virtual) { - ppi = arch_timer_ppi[VIRT_PPI]; + ppi = arch_timer_ppi[arch_timer_uses_ppi]; + switch (arch_timer_uses_ppi) { + case VIRT_PPI: err = request_percpu_irq(ppi, arch_timer_handler_virt, "arch_timer", arch_timer_evt); - } else { - ppi = arch_timer_ppi[PHYS_SECURE_PPI]; + break; + case PHYS_SECURE_PPI: + case 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]) { @@ -578,6 +597,13 @@ static int __init arch_timer_register(void) free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI], arch_timer_evt); } + break; + case HYP_PPI: + err = request_percpu_irq(ppi, arch_timer_handler_phys, + "arch_timer", arch_timer_evt); + break; + default: + BUG(); } if (err) { @@ -602,15 +628,10 @@ static int __init arch_timer_register(void) out_unreg_notify: unregister_cpu_notifier(&arch_timer_cpu_nb); out_free_irq: - if (arch_timer_use_virtual) - free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt); - else { - free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI], + 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], arch_timer_evt); - if (arch_timer_ppi[PHYS_NONSECURE_PPI]) - free_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], - arch_timer_evt); - } out_free: free_percpu(arch_timer_evt); @@ -697,12 +718,25 @@ static void __init arch_timer_init(void) * * 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[VIRT_PPI]) { - arch_timer_use_virtual = false; + bool has_ppi; - if (!arch_timer_ppi[PHYS_SECURE_PPI] || - !arch_timer_ppi[PHYS_NONSECURE_PPI]) { + if (is_kernel_in_hyp_mode()) { + arch_timer_uses_ppi = HYP_PPI; + has_ppi = !!arch_timer_ppi[HYP_PPI]; + } else { + arch_timer_uses_ppi = PHYS_SECURE_PPI; + has_ppi = (!!arch_timer_ppi[PHYS_SECURE_PPI] || + !!arch_timer_ppi[PHYS_NONSECURE_PPI]); + } + + if (!has_ppi) { pr_warn("arch_timer: No interrupt available, giving up\n"); return; } @@ -735,7 +769,7 @@ static void __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_use_virtual = false; + arch_timer_uses_ppi = PHYS_SECURE_PPI; arch_timer_init(); } @@ -757,7 +791,6 @@ static void __init arch_timer_mem_init(struct device_node *np) } cnttidr = readl_relaxed(cntctlbase + CNTTIDR); - iounmap(cntctlbase); /* * Try to find a virtual capable frame. Otherwise fall back to a @@ -765,20 +798,31 @@ static void __init arch_timer_mem_init(struct device_node *np) */ for_each_available_child_of_node(np, frame) { int n; + u32 cntacr; if (of_property_read_u32(frame, "frame-number", &n)) { pr_err("arch_timer: Missing frame-number\n"); - of_node_put(best_frame); of_node_put(frame); - return; + goto out; } - if (cnttidr & CNTTIDR_VIRT(n)) { + /* 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; arch_timer_mem_use_virtual = true; break; } + + if (~cntacr & (CNTACR_RWPT | CNTACR_RPCT)) + continue; + of_node_put(best_frame); best_frame = of_node_get(frame); } @@ -786,24 +830,26 @@ static void __init arch_timer_mem_init(struct device_node *np) base = arch_counter_base = of_iomap(best_frame, 0); if (!base) { pr_err("arch_timer: Can't map frame's registers\n"); - of_node_put(best_frame); - return; + goto out; } if (arch_timer_mem_use_virtual) irq = irq_of_parse_and_map(best_frame, 1); else irq = irq_of_parse_and_map(best_frame, 0); - of_node_put(best_frame); + if (!irq) { pr_err("arch_timer: Frame missing %s irq", arch_timer_mem_use_virtual ? "virt" : "phys"); - return; + goto out; } arch_timer_detect_rate(base, np); arch_timer_mem_register(base, irq); arch_timer_common_init(); +out: + iounmap(cntctlbase); + of_node_put(best_frame); } CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", arch_timer_mem_init); |