From patchwork Tue Jan 9 16:49:28 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 123974 Delivered-To: patch@linaro.org Received: by 10.140.22.227 with SMTP id 90csp4236289qgn; Tue, 9 Jan 2018 08:49:44 -0800 (PST) X-Google-Smtp-Source: ACJfBotiK9FmOUFtEFYLCCiuvizx/6uiU2ozsbmxkOEWeCBqY5nDc1CsKcAoRTx+vZK+OZ2IbMGG X-Received: by 10.99.95.213 with SMTP id t204mr8407220pgb.294.1515516584032; Tue, 09 Jan 2018 08:49:44 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1515516584; cv=none; d=google.com; s=arc-20160816; b=YTydQTXKSddw/PdlRv4Jnvjk9VV0q8pnvtMeRZMf8EBNZN+TDfl0tU1n1HiEhJGaI7 VTuFF9HhM75VzzNHlAidfmQL7bjG7TdWEY/D1LT6KEZM3ORsKQzdNaBvUdnwlplz6AIV fp4ms+5WGKRxFZsesihX33xsavoHgYoJYd0TlI7EbOyqjjNNpwcjWAIvDLTDTXJT9p98 x0Nwf9372feXKg9Uf/DL2sY8MMHBLfm4wMwTEobLCDHp/XuexAMJxjpevpLfoSMVb68d zk8JLekdcyNcI9qVRk+y7Z8uNkHdj9x6vayBcaNMFBixNuXAHOXTHGg4kejBtxglc/vE T2vQ== 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:message-id:date :subject:cc:to:from:arc-authentication-results; bh=VSGeKN0awjqSopkRd8Cepfw7Xxe039rLiS/CxwfMpG4=; b=jkEOCW1Wa7t+xGGuesHT76PHU/WcD8T6VD7IN0ngVEvAZskmG8Rsub6XI47swiyK5w 8OLyWkR6Ybhm3N+rV2JVhVlI64vjQx4BrvI0S3z7Z/mFFKdSCBLvSuuPeMl+40KePjCi ebKfW5b3xziLvUxIrbxm3jg79IFM8sbU24yfjvg92U87AKxthRWEdDtgZrWQWPcB67yD qHVy1/oi8xCjnT6CL1FK3DFqhjnCzR/psuExC1M8qqWoz1RW8dOLnZw0tNRhw3QxUkOx bx/RMb+qZ56BnRsC5D+MsZ5DmSi8pxhWw4DZ6+fCFeCsguqpdODj4omAU8v+Acdi8nBu NH1g== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-pm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-pm-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f4si10445638plr.189.2018.01.09.08.49.43; Tue, 09 Jan 2018 08:49:44 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-pm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-pm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-pm-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759735AbeAIQtl (ORCPT + 11 others); Tue, 9 Jan 2018 11:49:41 -0500 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:58216 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1759714AbeAIQtk (ORCPT ); Tue, 9 Jan 2018 11:49:40 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id AEBFB15BF; Tue, 9 Jan 2018 08:49:39 -0800 (PST) Received: from e107155-lin.cambridge.arm.com (e107155-lin.cambridge.arm.com [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 360523F581; Tue, 9 Jan 2018 08:49:38 -0800 (PST) From: Sudeep Holla To: linux-arm-kernel@lists.infradead.org, linux-pm@vger.kernel.org Cc: Sudeep Holla , linux-kernel@vger.kernel.org, Viresh Kumar , Jeremy Linton , Lorenzo Pieralisi , "Rafael J. Wysocki" Subject: [PATCH 2/2] cpufreq: scpi: remove arm_big_little dependency Date: Tue, 9 Jan 2018 16:49:28 +0000 Message-Id: <1515516568-31359-3-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1515516568-31359-1-git-send-email-sudeep.holla@arm.com> References: <1515516568-31359-1-git-send-email-sudeep.holla@arm.com> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org The dependency on physical_package_id from the topology to get the cluster identifier is wrong. The concept of cluster used in ARM topology is unfortunately not well defined in the architecture, we should avoid using it. Further the frequency domain need not be mapped to so called "clusters" one to one. SCPI already provides means to obtain the frequency domain id from the device tree. In order to support some new topologies(e.g. DSU which contains 2 frequency domains within the physical cluster), pseudo clusters are created to make this driver work which is wrong again. In order to solve those issues and also remove dependency of topological physical id for frequency domain, this patch removes the arm_big_little dependency from scpi driver. Cc: "Rafael J. Wysocki" Cc: Viresh Kumar Signed-off-by: Sudeep Holla --- drivers/cpufreq/scpi-cpufreq.c | 193 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 178 insertions(+), 15 deletions(-) -- 2.7.4 diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c index 05d299052c5c..247fcbfa4cb5 100644 --- a/drivers/cpufreq/scpi-cpufreq.c +++ b/drivers/cpufreq/scpi-cpufreq.c @@ -18,27 +18,89 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include +#include +#include +#include #include -#include +#include #include #include +#include #include -#include "arm_big_little.h" +struct scpi_data { + struct clk *clk; + struct device *cpu_dev; + struct thermal_cooling_device *cdev; +}; static struct scpi_ops *scpi_ops; -static int scpi_get_transition_latency(struct device *cpu_dev) +static unsigned int scpi_cpufreq_get_rate(unsigned int cpu) +{ + struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); + struct scpi_data *priv = policy->driver_data; + unsigned long rate = clk_get_rate(priv->clk); + + return rate / 1000; +} + +static int +scpi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) +{ + struct scpi_data *priv = policy->driver_data; + u64 rate = policy->freq_table[index].frequency * 1000; + int ret; + + ret = clk_set_rate(priv->clk, rate); + if (!ret && (clk_get_rate(priv->clk) != rate)) + ret = -EIO; + + return ret; +} + +static int +scpi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) { - return scpi_ops->get_transition_latency(cpu_dev); + int cpu, domain, tdomain; + struct device *tcpu_dev; + + domain = scpi_ops->device_domain_id(cpu_dev); + if (domain < 0) + return domain; + + for_each_possible_cpu(cpu) { + if (cpu == cpu_dev->id) + continue; + + tcpu_dev = get_cpu_device(cpu); + if (!tcpu_dev) + continue; + + tdomain = scpi_ops->device_domain_id(tcpu_dev); + if (tdomain == domain) + cpumask_set_cpu(cpu, cpumask); + } + + return 0; } -static int scpi_init_opp_table(const struct cpumask *cpumask) +static int scpi_cpufreq_init(struct cpufreq_policy *policy) { int ret; - struct device *cpu_dev = get_cpu_device(cpumask_first(cpumask)); + unsigned int latency; + struct device *cpu_dev; + struct scpi_data *priv; + struct cpufreq_frequency_table *freq_table; + + cpu_dev = get_cpu_device(policy->cpu); + if (!cpu_dev) { + pr_err("failed to get cpu%d device\n", policy->cpu); + return -ENODEV; + } ret = scpi_ops->add_opps_to_device(cpu_dev); if (ret) { @@ -46,32 +108,133 @@ static int scpi_init_opp_table(const struct cpumask *cpumask) return ret; } - ret = dev_pm_opp_set_sharing_cpus(cpu_dev, cpumask); - if (ret) + ret = scpi_get_sharing_cpus(cpu_dev, policy->cpus); + if (ret) { + dev_warn(cpu_dev, "failed to get sharing cpumask\n"); + return ret; + } + + ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus); + if (ret) { dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", __func__, ret); + return ret; + } + + ret = dev_pm_opp_get_opp_count(cpu_dev); + if (ret <= 0) { + dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n"); + ret = -EPROBE_DEFER; + goto out_free_opp; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto out_free_opp; + } + + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); + if (ret) { + dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); + goto out_free_priv; + } + + priv->cpu_dev = cpu_dev; + priv->clk = clk_get(cpu_dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(cpu_dev, "%s: Failed to get clk for cpu: %d\n", + __func__, cpu_dev->id); + goto out_free_cpufreq_table; + } + + policy->driver_data = priv; + + ret = cpufreq_table_validate_and_show(policy, freq_table); + if (ret) { + dev_err(cpu_dev, "%s: invalid frequency table: %d\n", __func__, + ret); + goto out_put_clk; + } + + /* scpi allows DVFS request for any domain from any CPU */ + policy->dvfs_possible_from_any_cpu = true; + + latency = scpi_ops->get_transition_latency(cpu_dev); + if (!latency) + latency = CPUFREQ_ETERNAL; + + policy->cpuinfo.transition_latency = latency; + + policy->fast_switch_possible = false; + return 0; + +out_put_clk: + clk_put(priv->clk); +out_free_cpufreq_table: + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); +out_free_priv: + kfree(priv); +out_free_opp: + dev_pm_opp_cpumask_remove_table(policy->cpus); + return ret; } -static const struct cpufreq_arm_bL_ops scpi_cpufreq_ops = { - .name = "scpi", - .get_transition_latency = scpi_get_transition_latency, - .init_opp_table = scpi_init_opp_table, - .free_opp_table = dev_pm_opp_cpumask_remove_table, +static int scpi_cpufreq_exit(struct cpufreq_policy *policy) +{ + struct scpi_data *priv = policy->driver_data; + + cpufreq_cooling_unregister(priv->cdev); + clk_put(priv->clk); + dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); + kfree(priv); + dev_pm_opp_cpumask_remove_table(policy->related_cpus); + + return 0; +} + +static void scpi_cpufreq_ready(struct cpufreq_policy *policy) +{ + struct scpi_data *priv = policy->driver_data; + struct thermal_cooling_device *cdev; + + cdev = of_cpufreq_cooling_register(policy); + if (!IS_ERR(cdev)) + priv->cdev = cdev; +} + +static struct cpufreq_driver scpi_cpufreq_driver = { + .name = "scpi-cpufreq", + .flags = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY | + CPUFREQ_NEED_INITIAL_FREQ_CHECK, + .verify = cpufreq_generic_frequency_table_verify, + .attr = cpufreq_generic_attr, + .get = scpi_cpufreq_get_rate, + .init = scpi_cpufreq_init, + .exit = scpi_cpufreq_exit, + .ready = scpi_cpufreq_ready, + .target_index = scpi_cpufreq_set_target, }; static int scpi_cpufreq_probe(struct platform_device *pdev) { + int ret; + scpi_ops = get_scpi_ops(); if (!scpi_ops) return -EIO; - return bL_cpufreq_register(&scpi_cpufreq_ops); + ret = cpufreq_register_driver(&scpi_cpufreq_driver); + if (ret) + dev_err(&pdev->dev, "%s: registering cpufreq failed, err: %d\n", + __func__, ret); + return ret; } static int scpi_cpufreq_remove(struct platform_device *pdev) { - bL_cpufreq_unregister(&scpi_cpufreq_ops); + cpufreq_unregister_driver(&scpi_cpufreq_driver); scpi_ops = NULL; return 0; }