From patchwork Sat May 17 04:51:21 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Viresh Kumar X-Patchwork-Id: 30351 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-oa0-f69.google.com (mail-oa0-f69.google.com [209.85.219.69]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 0BA0220C81 for ; Sat, 17 May 2014 04:52:10 +0000 (UTC) Received: by mail-oa0-f69.google.com with SMTP id i7sf17625513oag.0 for ; Fri, 16 May 2014 21:52:09 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:in-reply-to:references :sender:precedence:list-id:x-original-sender :x-original-authentication-results:mailing-list:list-post:list-help :list-archive:list-unsubscribe; bh=h2mamSXoF+ehajv8OMsuk06RFo6aR0plBg0MAXbRH1k=; b=FDgtdWcimKpD8O+mN2RmUIrpcX4sUdsjZh07d70pqQ9jCvX+opoj8irRqVnfFoVUeu azMyO6iQJU7y3sdSdNPSmqq6xK+d4N91qOYyY6ukf9VgIACsERuE0TYMaLcqn4ecobiz rzV2AdKoaLGJ5ze5MRIk5cGp6sTrB7SovyfUasS1g/txdSHcnDti59PboGAIQ31hl2Pk BFd0atTS+M8GABswIJTDyA52DcVX0dvQC7Apxx3Q8mxKtho8gqKtV3MMzM9F5KE2jx+C oYlRVQDAE2nbsakECq5Srx3ADVx2GX6EryoxRrwED+kWsYUTnqxCh3S8PvlNWKfKwVeH p7Gw== X-Gm-Message-State: ALoCoQkrGYfcwfKuOdFxsSkv8jlDfd2RpybH3OCOLVFQjZR9UpYeKl4Yu9NPHyHKRT579D1RWfPP X-Received: by 10.182.196.8 with SMTP id ii8mr10573515obc.5.1400302329663; Fri, 16 May 2014 21:52:09 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.31.195 with SMTP id f61ls855849qgf.59.gmail; Fri, 16 May 2014 21:52:09 -0700 (PDT) X-Received: by 10.221.74.200 with SMTP id yx8mr601231vcb.3.1400302329578; Fri, 16 May 2014 21:52:09 -0700 (PDT) Received: from mail-vc0-f169.google.com (mail-vc0-f169.google.com [209.85.220.169]) by mx.google.com with ESMTPS id bz6si1566559vdb.198.2014.05.16.21.52.09 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 16 May 2014 21:52:09 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.169 as permitted sender) client-ip=209.85.220.169; Received: by mail-vc0-f169.google.com with SMTP id ij19so7384438vcb.0 for ; Fri, 16 May 2014 21:52:09 -0700 (PDT) X-Received: by 10.52.110.195 with SMTP id ic3mr497243vdb.53.1400302329470; Fri, 16 May 2014 21:52:09 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.221.72 with SMTP id ib8csp103906vcb; Fri, 16 May 2014 21:52:08 -0700 (PDT) X-Received: by 10.66.66.225 with SMTP id i1mr26374141pat.0.1400302327807; Fri, 16 May 2014 21:52:07 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id wh4si5723181pbc.4.2014.05.16.21.52.07; Fri, 16 May 2014 21:52:07 -0700 (PDT) Received-SPF: none (google.com: linux-kernel-owner@vger.kernel.org does not designate permitted sender hosts) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756689AbaEQEvv (ORCPT + 27 others); Sat, 17 May 2014 00:51:51 -0400 Received: from mail-pb0-f46.google.com ([209.85.160.46]:53365 "EHLO mail-pb0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756544AbaEQEvr (ORCPT ); Sat, 17 May 2014 00:51:47 -0400 Received: by mail-pb0-f46.google.com with SMTP id rq2so3453817pbb.33 for ; Fri, 16 May 2014 21:51:46 -0700 (PDT) X-Received: by 10.68.200.133 with SMTP id js5mr26252295pbc.138.1400302306842; Fri, 16 May 2014 21:51:46 -0700 (PDT) Received: from localhost ([122.172.196.205]) by mx.google.com with ESMTPSA id pr4sm17526639pbb.53.2014.05.16.21.51.42 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 16 May 2014 21:51:46 -0700 (PDT) From: Viresh Kumar To: rjw@rjwysocki.net Cc: linaro-kernel@lists.linaro.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, arvind.chauhan@arm.com, swarren@nvidia.com, nicolas.pitre@linaro.org, swarren@wwwdotorg.org, dianders@chromium.org, linux@arm.linux.org.uk, thomas.abraham@linaro.org, pdeschrijver@nvidia.com, Viresh Kumar Subject: [PATCH V3 2/4] cpufreq: add support for intermediate (stable) frequencies Date: Sat, 17 May 2014 10:21:21 +0530 Message-Id: <046e3785229754332de62854439d2a4a17d637b7.1400302114.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.0.0.rc2 In-Reply-To: References: In-Reply-To: References: Sender: linux-kernel-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: viresh.kumar@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.169 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Douglas Anderson, recently pointed out an interesting problem due to which udelay() was expiring earlier than it should. While transitioning between frequencies few platforms may temporarily switch to a stable frequency, waiting for the main PLL to stabilize. For example: When we transition between very low frequencies on exynos, like between 200MHz and 300MHz, we may temporarily switch to a PLL running at 800MHz. No CPUFREQ notification is sent for that. That means there's a period of time when we're running at 800MHz but loops_per_jiffy is calibrated at between 200MHz and 300MHz. And so udelay behaves badly. To get this fixed in a generic way, lets introduce another set of callbacks get_intermediate() and target_intermediate(), only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION unset. get_intermediate should return a stable intermediate frequency platform wants to switch to, and target_intermediate() should set CPU to to that frequency, before jumping to the frequency corresponding to 'index'. Core will take care of sending notifications and driver doesn't have to handle them in target_intermediate() or target_index(). NOTE: Once set to intermediate frequency, driver isn't expected to fail for the following ->target_index() call, if it fails core will issue a WARN(). Tested-by: Stephen Warren Signed-off-by: Viresh Kumar --- Documentation/cpu-freq/cpu-drivers.txt | 19 ++++++++++++++-- drivers/cpufreq/cpufreq.c | 40 +++++++++++++++++++++++++++------- include/linux/cpufreq.h | 15 +++++++++++++ 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt index b045fe5..b1bdb8a 100644 --- a/Documentation/cpu-freq/cpu-drivers.txt +++ b/Documentation/cpu-freq/cpu-drivers.txt @@ -26,6 +26,7 @@ Contents: 1.4 target/target_index or setpolicy? 1.5 target/target_index 1.6 setpolicy +1.7 get_intermediate and target_intermediate 2. Frequency Table Helpers @@ -79,6 +80,10 @@ cpufreq_driver.attr - A pointer to a NULL-terminated list of "struct freq_attr" which allow to export values to sysfs. +cpufreq_driver.get_intermediate +and target_intermediate Used to switch to stable frequency while + changing CPU frequency. + 1.2 Per-CPU Initialization -------------------------- @@ -151,7 +156,7 @@ Some cpufreq-capable processors switch the frequency between certain limits on their own. These shall use the ->setpolicy call -1.4. target/target_index +1.5. target/target_index ------------- The target_index call has two arguments: struct cpufreq_policy *policy, @@ -179,7 +184,7 @@ Here again the frequency table helper might assist you - see section 2 for details. -1.5 setpolicy +1.6 setpolicy --------------- The setpolicy call only takes a struct cpufreq_policy *policy as @@ -190,6 +195,16 @@ setting when policy->policy is CPUFREQ_POLICY_PERFORMANCE, and a powersaving-oriented setting when CPUFREQ_POLICY_POWERSAVE. Also check the reference implementation in drivers/cpufreq/longrun.c +1.7 get_intermediate and target_intermediate +-------------------------------------------- + +Only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION unset. + +get_intermediate should return a stable intermediate frequency platform wants to +switch to, and target_intermediate() should set CPU to to that frequency, before +jumping to the frequency corresponding to 'index'. Core will take care of +sending notifications and driver doesn't have to handle them in +target_intermediate() or target_index(). 2. Frequency Table Helpers diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 9bf12a2..f38f2f2 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1819,27 +1819,50 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier); static int __target_index(struct cpufreq_policy *policy, struct cpufreq_frequency_table *freq_table, int index) { - struct cpufreq_freqs freqs; + struct cpufreq_freqs freqs = {.old = policy->cur, .flags = 0}; int retval = -EINVAL; bool notify; notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION); + if (!notify) + goto skip_notify; - if (notify) { - freqs.old = policy->cur; - freqs.new = freq_table[index].frequency; - freqs.flags = 0; + /* Handle switching to intermediate frequency */ + if (cpufreq_driver->get_intermediate) { + freqs.new = cpufreq_driver->get_intermediate(policy, index); - pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n", + pr_debug("%s: cpu: %d, switching to intermediate freq: oldfreq: %u, intermediate freq: %u\n", __func__, policy->cpu, freqs.old, freqs.new); cpufreq_freq_transition_begin(policy, &freqs); + retval = cpufreq_driver->target_intermediate(policy, freqs.new); + cpufreq_freq_transition_end(policy, &freqs, retval); + + if (retval) { + pr_err("%s: Failed to change to intermediate frequency: %d\n", + __func__, retval); + return retval; + } + + /* Set intermediate as old freq */ + freqs.old = freqs.new; } + freqs.new = freq_table[index].frequency; + + pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n", __func__, + policy->cpu, freqs.old, freqs.new); + + cpufreq_freq_transition_begin(policy, &freqs); + +skip_notify: retval = cpufreq_driver->target_index(policy, index); - if (retval) + if (retval) { + /* We shouldn't fail after setting intermediate freq */ + WARN_ON(cpufreq_driver->get_intermediate); pr_err("%s: Failed to change cpu frequency: %d\n", __func__, retval); + } if (notify) cpufreq_freq_transition_end(policy, &freqs, retval); @@ -2361,7 +2384,8 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) !(driver_data->setpolicy || driver_data->target_index || driver_data->target) || (driver_data->setpolicy && (driver_data->target_index || - driver_data->target))) + driver_data->target)) || + (!!driver_data->get_intermediate ^ !!driver_data->target_intermediate)) return -EINVAL; pr_debug("trying to register driver %s\n", driver_data->name); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 3f45889..bfcba11 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -226,6 +226,21 @@ struct cpufreq_driver { unsigned int relation); int (*target_index) (struct cpufreq_policy *policy, unsigned int index); + /* + * Only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION + * unset. + * + * get_intermediate should return a stable intermediate frequency + * platform wants to switch to and target_intermediate() should set CPU + * to to that frequency, before jumping to the frequency corresponding + * to 'index'. Core will take care of sending notifications and driver + * doesn't have to handle them in target_intermediate() or + * target_index(). + */ + unsigned int (*get_intermediate)(struct cpufreq_policy *policy, + unsigned int index); + int (*target_intermediate)(struct cpufreq_policy *policy, + unsigned int frequency); /* should be defined, if possible */ unsigned int (*get) (unsigned int cpu);