From patchwork Thu Jul 12 08:44:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "\(Exiting\) Baolin Wang" X-Patchwork-Id: 141809 Delivered-To: patch@linaro.org Received: by 2002:a2e:9754:0:0:0:0:0 with SMTP id f20-v6csp1245640ljj; Thu, 12 Jul 2018 01:45:04 -0700 (PDT) X-Google-Smtp-Source: AAOMgpc7yLIJ2PIXtq5yvQUuR3VejSEvNln5s9aQn2dqs6wb7IYdFX5nZEVJXapqzQv/hkvdvgwC X-Received: by 2002:a62:57dc:: with SMTP id i89-v6mr1413334pfj.65.1531385104117; Thu, 12 Jul 2018 01:45:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1531385104; cv=none; d=google.com; s=arc-20160816; b=yEucQbBZWpVHVJ+6s4C6+XXMfFFH4V5pAYdZEfEJrJT4aiRcIMX5Jt5oZ9IcfCgyQr Obt9DkL1x8ZkyX31B14v91BAqXbNbTjpv8e4W9kC3XYR1ZB9cECqrqAM6RD91VZy5FER UZfT4kiLcMl5EGC5zv1PrRXYiO0dT2LcMWyn1dXz9Ev7AeGvg3GgrgQ0pSJtdnuEqLLM 1sVeUPycHMSrd8ZYHhdoqchRJzItvbI5vte/so7dl8C64im17Dxmi8/BbKD8tisvUEb2 Jcl8BlfuYdzo884t/E7YPJb4mMjflBARvu9F15Am6EodD5GD2eFb4OVcOdsxnPPGf9LK hY9w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :dkim-signature:arc-authentication-results; bh=zFaCie2Frja+zTzIavMJRsXKeSi3+WJbCOfjDafXsco=; b=GF/OLI6Rs5tJC6ER2qqjjYc9t7Hr3nmBvmvyR9qRb8e9lxiEy+pV68O/N8CsjEz3D8 EvV1y4LmV3e4vSD1XcRypGAbRc/m4bYzkBhtYE0JP/u5NwcQnve1lRzaZHDVxFIpmiSu YKk8mgpqW4Qc5cazXQrqhbpDOB1TVisHbb9yYNIw9JFHZ1DNaQ7VprAhZ5A8rX13bIrX 29zlXbrVWQMAEbaFQ+AFlUL2qjOtb588WFX+aQkeGTyaL9IeGfwSb9iFxxxKOw++fv1r 0az22XTSHsGREAiO4De2vrj5BStM8Bf/6kV5NSd4C1pxwiAyF7cQjsJHVppYKVeWx0ky 9+kg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=LNKS5CV3; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id u7-v6si20596222pgn.194.2018.07.12.01.45.03; Thu, 12 Jul 2018 01:45:04 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=LNKS5CV3; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727478AbeGLIxh (ORCPT + 28 others); Thu, 12 Jul 2018 04:53:37 -0400 Received: from mail-pf0-f193.google.com ([209.85.192.193]:40558 "EHLO mail-pf0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726393AbeGLIxh (ORCPT ); Thu, 12 Jul 2018 04:53:37 -0400 Received: by mail-pf0-f193.google.com with SMTP id e13-v6so6817372pff.7 for ; Thu, 12 Jul 2018 01:45:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=zFaCie2Frja+zTzIavMJRsXKeSi3+WJbCOfjDafXsco=; b=LNKS5CV3qjZR2PpC9V5q7CuAC9XGSPUbbUqsYkl9sZfG9T58NGRuq75quj/+ZfowBY 7wYu0SuT6WiZd3pe/8fTpIGbB9AMHLTyFYg/q/+qQrGaWAE6/gDFxA0xB30XMT6AMKMb EajSjT6xtw77nImHtaGF9OlZcAAbNB20Gq6Hg= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=zFaCie2Frja+zTzIavMJRsXKeSi3+WJbCOfjDafXsco=; b=Vhk6pYSHxBJ5yvpq8BvIeZeL3ywPZgwfGqNdjN0O3D3KGTL4GpTpjphk7NvxbC978u O23m9tukE+d3xkZcnAEylqw4PKGfcCZqWIYnSYGVKOh+eqNC5pUZuS7qQSjqCNJag5Zp v897/o/Zv2FrqpVkqgFmw841C21aYsACmW5SnutjzgnMvg9wHz2B8H0nJ6gbkfigRTaJ oM58MFT00ZytowMtEo1NmaCSw38F2A1zI0hUQag1Z6Cr+EUFBn0BEZUlY+JjSu5qlWbM AzWh7Epw30FzkepuFWlvUfQbAM5BzN6x1bEds+zw9MPq/cjcZtN1CIvS0sAKJP7H6d5Z 1qiQ== X-Gm-Message-State: AOUpUlHgMEhxNg8V63aFSufmj0HuFT/IF0wMaO2IaTc9hRy/GO+yZbn+ 7oG85Tj4eR9Wl1QTbf/oSCTp2w== X-Received: by 2002:a65:6688:: with SMTP id b8-v6mr1306345pgw.24.1531385100539; Thu, 12 Jul 2018 01:45:00 -0700 (PDT) Received: from baolinwangubtpc.spreadtrum.com ([117.18.48.102]) by smtp.gmail.com with ESMTPSA id v17-v6sm27184314pfn.177.2018.07.12.01.44.57 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 12 Jul 2018 01:45:00 -0700 (PDT) From: Baolin Wang To: tglx@linutronix.de, john.stultz@linaro.org, sboyd@kernel.org, arnd@arndb.de, broonie@kernel.org, daniel.lezcano@linaro.org Cc: linux-kernel@vger.kernel.org, baolin.wang@linaro.org Subject: [RFC PATCH 1/2] time: Introduce one suspend clocksource to compensate the suspend time Date: Thu, 12 Jul 2018 16:44:12 +0800 Message-Id: <4aa9a65166f7e10984bfcff59e72d86e37c369a1.1531384486.git.baolin.wang@linaro.org> X-Mailer: git-send-email 1.7.9.5 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On some hardware with multiple clocksources, we have course grained clocksources that support the CLOCK_SOURCE_SUSPEND_NONSTOP flag, but which are less ideal for timekeeping then other clocksources which halt in suspend. Currently, the timekeeping core only supports timing suspend using CLOCK_SOURCE_SUSPEND_NONSTOP clocksources if that clocksource is the current clocksource for timekeeping. As a result, some architectures try to implement read_persisitent_clock64() using those non-stop clocksources, but isn't really ideal. Thus this patch provides logic to allow a registered SUSPEND_NONSTOP clocksource, which isn't the current clocksource, to be used to calculate the suspend time. Suggested-by: Thomas Gleixner Signed-off-by: Baolin Wang --- include/linux/clocksource.h | 3 + kernel/time/clocksource.c | 152 +++++++++++++++++++++++++++++++++++++++++++ kernel/time/timekeeping.c | 22 ++++--- 3 files changed, 169 insertions(+), 8 deletions(-) -- 1.7.9.5 diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 7dff196..3089189 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -194,6 +194,9 @@ static inline s64 clocksource_cyc2ns(u64 cycles, u32 mult, u32 shift) extern void clocksource_resume(void); extern struct clocksource * __init clocksource_default_clock(void); extern void clocksource_mark_unstable(struct clocksource *cs); +extern void +clocksource_start_suspend_timing(struct clocksource *cs, u64 start_cycles); +extern u64 clocksource_stop_suspend_timing(struct clocksource *cs, u64 now); extern u64 clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask, u64 *max_cycles); diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index f89a78e..7778eaa 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -94,6 +94,8 @@ /*[Clocksource internal variables]--------- * curr_clocksource: * currently selected clocksource. + * suspend_clocksource: + * used to calculate the suspend time. * clocksource_list: * linked list with the registered clocksources * clocksource_mutex: @@ -102,10 +104,12 @@ * Name of the user-specified clocksource. */ static struct clocksource *curr_clocksource; +static struct clocksource *suspend_clocksource; static LIST_HEAD(clocksource_list); static DEFINE_MUTEX(clocksource_mutex); static char override_name[CS_NAME_LEN]; static int finished_booting; +static u64 suspend_start; #ifdef CONFIG_CLOCKSOURCE_WATCHDOG static void clocksource_watchdog_work(struct work_struct *work); @@ -447,6 +451,133 @@ static inline void clocksource_watchdog_unlock(unsigned long *flags) { } #endif /* CONFIG_CLOCKSOURCE_WATCHDOG */ +static bool clocksource_is_suspend(struct clocksource *cs) +{ + return cs == suspend_clocksource; +} + +static void __clocksource_suspend_select(struct clocksource *cs) +{ + /* + * Skip the clocksource which will be stopped in suspend state. + */ + if (!(cs->flags & CLOCK_SOURCE_SUSPEND_NONSTOP)) + return; + + /* Pick the best rating. */ + if (!suspend_clocksource || cs->rating > suspend_clocksource->rating) + suspend_clocksource = cs; +} + +/** + * clocksource_suspend_select - Select the best clocksource for suspend timing + * @fallback: if select a fallback clocksource + */ +static void clocksource_suspend_select(bool fallback) +{ + struct clocksource *cs, *old_suspend; + + old_suspend = suspend_clocksource; + if (fallback) + suspend_clocksource = NULL; + + list_for_each_entry(cs, &clocksource_list, list) { + /* Skip current if we were requested for a fallback. */ + if (fallback && cs == old_suspend) + continue; + + __clocksource_suspend_select(cs); + } + + /* If we failed to find a fallback restore the old one. */ + if (!suspend_clocksource) + suspend_clocksource = old_suspend; +} + +/** + * clocksource_start_suspend_timing - Start measuring the suspend timing + * @cs: current clocksource from timekeeping + * @start_cycles: current cycles from timekeeping + * + * This function will save the start cycle values of suspend timer to calculate + * the suspend time when resuming system. + * + * This function is called late in the suspend process from timekeeping_suspend(), + * that means processes are freezed, non-boot cpus and interrupts are disabled + * now. It is therefore possible to start the suspend timer without taking the + * clocksource mutex. + */ +void clocksource_start_suspend_timing(struct clocksource *cs, u64 start_cycles) +{ + if (!suspend_clocksource) + return; + + /* + * If current clocksource is the suspend timer, we should use the + * tkr_mono.cycle_last value as suspend_start to avoid same reading + * from suspend timer. + */ + if (clocksource_is_suspend(cs)) { + suspend_start = start_cycles; + return; + } + + if (suspend_clocksource->enable && + WARN_ON_ONCE(suspend_clocksource->enable(suspend_clocksource))) { + pr_warn_once("Failed to enable the non-suspend-able clocksource.\n"); + return; + } + + suspend_start = suspend_clocksource->read(suspend_clocksource); +} + +/** + * clocksource_stop_suspend_timing - Stop measuring the suspend timing + * @cs: current clocksource from timekeeping + * @cycle_now: current cycles from timekeeping + * + * This function will calculate the suspend time from suspend timer, and return + * nanoseconds since suspend started or 0 if no usable clocksource. + * + * This function is called early in the resume process from timekeeping_resume(), + * that means there is only one cpu, no processes are running and the interrupts + * are disabled. It is therefore possible to stop the suspend timer without + * taking the clocksource mutex. + */ +u64 clocksource_stop_suspend_timing(struct clocksource *cs, u64 cycle_now) +{ + u64 now, delta, nsec = 0; + + if (!suspend_clocksource) + return 0; + + /* + * If current clocksource is the suspend timer, we should use the + * tkr_mono.cycle_last value from timekeeping as current cycle to + * avoid same reading from suspend timer. + */ + if (clocksource_is_suspend(cs)) + now = cycle_now; + else + now = suspend_clocksource->read(suspend_clocksource); + + if (now > suspend_start) { + delta = clocksource_delta(now, suspend_start, + suspend_clocksource->mask); + nsec = mul_u64_u32_shr(delta, suspend_clocksource->mult, + suspend_clocksource->shift); + } + + /* + * Disable the suspend timer to save power if current clocksource is + * not the suspend timer. + */ + if (!clocksource_is_suspend(cs) && suspend_clocksource->disable) + suspend_clocksource->disable(suspend_clocksource); + + return nsec; +} + /** * clocksource_suspend - suspend the clocksource(s) */ @@ -779,6 +910,16 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq) { unsigned long flags; + /* + * The nonstop clocksource can be selected as the suspend clocksource to + * calculate the suspend time, so it should not supply suspend/resume + * interfaces to suspend the nonstop clocksource when system suspends. + */ + if ((cs->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) && + (cs->suspend || cs->resume)) + pr_warn("Nonstop clocksource %s should not supply suspend/resume interfaces\n", + cs->name); + /* Initialize mult/shift and max_idle_ns */ __clocksource_update_freq_scale(cs, scale, freq); @@ -792,6 +933,7 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq) clocksource_select(); clocksource_select_watchdog(false); + __clocksource_suspend_select(cs); mutex_unlock(&clocksource_mutex); return 0; } @@ -820,6 +962,7 @@ void clocksource_change_rating(struct clocksource *cs, int rating) clocksource_select(); clocksource_select_watchdog(false); + clocksource_suspend_select(false); mutex_unlock(&clocksource_mutex); } EXPORT_SYMBOL(clocksource_change_rating); @@ -838,6 +981,15 @@ static int clocksource_unbind(struct clocksource *cs) return -EBUSY; } + if (clocksource_is_suspend(cs)) { + /* + * Select and try to install a replacement suspend clocksource. + */ + clocksource_suspend_select(true); + if (clocksource_is_suspend(cs)) + return -EBUSY; + } + if (cs == curr_clocksource) { /* Select and try to install a replacement clock source */ clocksource_select_fallback(); diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 4786df9..d80dba3 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1669,7 +1669,7 @@ void timekeeping_resume(void) struct clocksource *clock = tk->tkr_mono.clock; unsigned long flags; struct timespec64 ts_new, ts_delta; - u64 cycle_now; + u64 cycle_now, nsec; sleeptime_injected = false; read_persistent_clock64(&ts_new); @@ -1693,13 +1693,8 @@ void timekeeping_resume(void) * usable source. The rtc part is handled separately in rtc core code. */ cycle_now = tk_clock_read(&tk->tkr_mono); - if ((clock->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) && - cycle_now > tk->tkr_mono.cycle_last) { - u64 nsec, cyc_delta; - - cyc_delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last, - tk->tkr_mono.mask); - nsec = mul_u64_u32_shr(cyc_delta, clock->mult, clock->shift); + nsec = clocksource_stop_suspend_timing(clock, cycle_now); + if (nsec > 0) { ts_delta = ns_to_timespec64(nsec); sleeptime_injected = true; } else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) { @@ -1732,6 +1727,8 @@ int timekeeping_suspend(void) unsigned long flags; struct timespec64 delta, delta_delta; static struct timespec64 old_delta; + struct clocksource *curr_clock; + u64 cycle_now; read_persistent_clock64(&timekeeping_suspend_time); @@ -1748,6 +1745,15 @@ int timekeeping_suspend(void) timekeeping_forward_now(tk); timekeeping_suspended = 1; + /* + * Since we've called forward_now, cycle_last stores the value + * just read from the current clocksource. Save this to potentially + * use in suspend timing. + */ + curr_clock = tk->tkr_mono.clock; + cycle_now = tk->tkr_mono.cycle_last; + clocksource_start_suspend_timing(curr_clock, cycle_now); + if (persistent_clock_exists) { /* * To avoid drift caused by repeated suspend/resumes, From patchwork Thu Jul 12 08:44:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "\(Exiting\) Baolin Wang" X-Patchwork-Id: 141810 Delivered-To: patch@linaro.org Received: by 2002:a2e:9754:0:0:0:0:0 with SMTP id f20-v6csp1245693ljj; Thu, 12 Jul 2018 01:45:07 -0700 (PDT) X-Google-Smtp-Source: AAOMgpeLT/qAD147qGT7icMLlXJD2ExsntaGXP4wn90OjKfgKFDGyN+1Z3iaNk8z/fI0hkAq57ja X-Received: by 2002:a17:902:76c4:: with SMTP id j4-v6mr1284524plt.19.1531385107087; Thu, 12 Jul 2018 01:45:07 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1531385107; cv=none; d=google.com; s=arc-20160816; b=tAVxwf/B7E/k0fx/vOzYYmn3Jbpwhn3rEMaBHLt6sBlF4tUswEAFenRbGU+Kt3RN3f KVVyhSSK0OENw8EsYEp0xniE3xUtv7q/wwHiw3ETtlZ1aTzGBRaHuxHa9Y6Sg1nfzPcV NES6B/J0ncablqwMrD7gFMghh670a43UVLu1KLF5uReGtqNypw0TTIBXqlNXzWJO97pN jRCqUXHEIdQ1rs7YCHqTdE53bsuh+2mYirwTOjgn67o/ZKsgb/MhHlOifh0ccz5hgRfH CflDSGYlZLifoIxVpOvNzFoI69JO8YGpKc6pu1tdKiBDOKRC/+WRohzajLtFr56sQSI0 AFxw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:dkim-signature :arc-authentication-results; bh=7IO3qfA2g2fabXqH25n3LDrGVQAknfMl75vi9SRb11A=; b=Co6E3zJYubvO/MaSkRIV2xAGhBdSCeWyUjWk/B5Cjgik5zf7lIVHtUduqd+A+0da+R 0+x8sC0JzDEKfSbbJ2B/JQXw3DsUC+04FZk2LKkSeMyYOyUq6qjvms2U/mjgoHz4EkzE Q+Qx6TQAeXWRRnt2lwlFiX3rd5TTxpWHenEuvfMX0HjBoUiJkKjizTxuOWW9Xh8wuBRt laiTsaSFBq8q0gyN9IYIBB5AfD2p5z+plkrDMyIpaBpN6gy3uDFkAF8MBJYs0qGuL446 ByvoAI7KUPK5n/D6sbwa2VvIYmbTbHhc4Sy+ASK5oAha6if4BHzGr9BKx0CcdCnSr8HP kMvA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=KZfe0jvv; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r1-v6si21330722plb.172.2018.07.12.01.45.06; Thu, 12 Jul 2018 01:45:07 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=KZfe0jvv; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732341AbeGLIxk (ORCPT + 28 others); Thu, 12 Jul 2018 04:53:40 -0400 Received: from mail-pf0-f196.google.com ([209.85.192.196]:34923 "EHLO mail-pf0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726393AbeGLIxj (ORCPT ); Thu, 12 Jul 2018 04:53:39 -0400 Received: by mail-pf0-f196.google.com with SMTP id q7-v6so19089017pff.2 for ; Thu, 12 Jul 2018 01:45:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=7IO3qfA2g2fabXqH25n3LDrGVQAknfMl75vi9SRb11A=; b=KZfe0jvvXty2GG8LXIKc32hsXEFJFQwUFWQykXM7YHeuqU7Ad1bu3g6bV4YyivQJPJ T60QXemlq5tzKsEZ1F1aawwEdlArITP4t0V8AWNgK6ErIDfD8wKe1iorFdBSU9PzXkVI yvZS+vO2pGwW+/Ce162krUyK53dzzZuDroh+Q= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=7IO3qfA2g2fabXqH25n3LDrGVQAknfMl75vi9SRb11A=; b=Z/veEstKKETWAdD4/iU/E4Xp1MfHaCFOGRe/Dw1DL03wML8wZRALZKpP3W2Tf+3VGi IKGc6bsD9PygkDL3ZUyE8w/qq6eY1MBeqwZBlAG4Fqpie/wpfprHx52igfS9QxPjeYLu +ZPQJJFcSV6ng3rz2nib0lW34PqSNqj2QP0b3hW2g84aozHBiP/yN6d68akC7W6OSr9A 5WwVwajIbCyd1j+dhShJMNB6O1B7Hu7x1e8YtIBziM3dnRpsYWl+Auy/++zNPFfMVBKN mx3TxlfaXo3NXrvmx4Q4UgwedmLF+6BWP9Umx4TiEsRqlVVjR0Hy9KYEIUGdgdqA73zp onDQ== X-Gm-Message-State: AOUpUlG+bdD027dVTBkOokSCPISVqqyko3fof+WiDt7WPBVTYl161HtK 5vZkPk7cPkwuTfFFiyhZHlIVHkXSlQM= X-Received: by 2002:a62:e813:: with SMTP id c19-v6mr1418186pfi.124.1531385103205; Thu, 12 Jul 2018 01:45:03 -0700 (PDT) Received: from baolinwangubtpc.spreadtrum.com ([117.18.48.102]) by smtp.gmail.com with ESMTPSA id v17-v6sm27184314pfn.177.2018.07.12.01.45.00 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 12 Jul 2018 01:45:02 -0700 (PDT) From: Baolin Wang To: tglx@linutronix.de, john.stultz@linaro.org, sboyd@kernel.org, arnd@arndb.de, broonie@kernel.org, daniel.lezcano@linaro.org Cc: linux-kernel@vger.kernel.org, baolin.wang@linaro.org Subject: [RFC PATCH 2/2] clocksource: sprd: Register one always-on timer to compensate suspend time Date: Thu, 12 Jul 2018 16:44:13 +0800 Message-Id: <9f6309ba7e9c49d1f887f276471716d07a7f7bba.1531384486.git.baolin.wang@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <4aa9a65166f7e10984bfcff59e72d86e37c369a1.1531384486.git.baolin.wang@linaro.org> References: <4aa9a65166f7e10984bfcff59e72d86e37c369a1.1531384486.git.baolin.wang@linaro.org> In-Reply-To: <4aa9a65166f7e10984bfcff59e72d86e37c369a1.1531384486.git.baolin.wang@linaro.org> References: <4aa9a65166f7e10984bfcff59e72d86e37c369a1.1531384486.git.baolin.wang@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Since the clocksource framework has introduced one suspend clocksource to compensate the suspend time, this patch registers one always-on timer as the suspend clocksource. Signed-off-by: Baolin Wang --- drivers/clocksource/timer-sprd.c | 50 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) -- 1.7.9.5 diff --git a/drivers/clocksource/timer-sprd.c b/drivers/clocksource/timer-sprd.c index ef9ebea..430cb99 100644 --- a/drivers/clocksource/timer-sprd.c +++ b/drivers/clocksource/timer-sprd.c @@ -156,4 +156,54 @@ static int __init sprd_timer_init(struct device_node *np) return 0; } +static struct timer_of suspend_to = { + .flags = TIMER_OF_BASE | TIMER_OF_CLOCK, +}; + +static u64 sprd_suspend_timer_read(struct clocksource *cs) +{ + return ~(u64)readl_relaxed(timer_of_base(&suspend_to) + + TIMER_VALUE_SHDW_LO) & cs->mask; +} + +static int sprd_suspend_timer_enable(struct clocksource *cs) +{ + sprd_timer_update_counter(timer_of_base(&suspend_to), + TIMER_VALUE_LO_MASK); + sprd_timer_enable(timer_of_base(&suspend_to), TIMER_CTL_PERIOD_MODE); + + return 0; +} + +static void sprd_suspend_timer_disable(struct clocksource *cs) +{ + sprd_timer_disable(timer_of_base(&suspend_to)); +} + +static struct clocksource suspend_clocksource = { + .name = "sprd_suspend_timer", + .rating = 200, + .read = sprd_suspend_timer_read, + .enable = sprd_suspend_timer_enable, + .disable = sprd_suspend_timer_disable, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP, +}; + +static int __init sprd_suspend_timer_init(struct device_node *np) +{ + int ret; + + ret = timer_of_init(np, &suspend_to); + if (ret) + return ret; + + clocksource_register_hz(&suspend_clocksource, + timer_of_rate(&suspend_to)); + + return 0; +} + TIMER_OF_DECLARE(sc9860_timer, "sprd,sc9860-timer", sprd_timer_init); +TIMER_OF_DECLARE(sc9860_persistent_timer, "sprd,sc9860-suspend-timer", + sprd_suspend_timer_init);