From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2F910C47E49 for ; Mon, 21 Oct 2019 14:36:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F0F2E20656 for ; Mon, 21 Oct 2019 14:36:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728920AbfJUOgw (ORCPT ); Mon, 21 Oct 2019 10:36:52 -0400 Received: from alexa-out-blr-02.qualcomm.com ([103.229.18.198]:30511 "EHLO alexa-out-blr-02.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726955AbfJUOgw (ORCPT ); Mon, 21 Oct 2019 10:36:52 -0400 Received: from ironmsg02-blr.qualcomm.com ([10.86.208.131]) by alexa-out-blr-02.qualcomm.com with ESMTP/TLS/AES256-SHA; 21 Oct 2019 20:00:43 +0530 IronPort-SDR: RM22F5kNPP3g5ZlDAHwZuId7j9Cc7qvf6swxUmy+W6o9o5aq7X9Ou0mTAMxxyATPuifh4xbLRr Jol8x2or1AZao+cRlqxDO4Epwgq/Z+c6Gyp4BljuAeUOKDnVbeucZqn/M3pTJ8dGir3Jcv1kYs d1jIvbGg+vdy0UCoDsL38fF4zyZreSnlbAgs+9cn7xvBedow0oq+IpBT3EQNh5tIue4tqrPLov NXVa3CyLsl8EBoITP/TzhjyPJhQaHYdcAtfz51jwhvRtKulfoKNpsT3wQXBDYGK45MMfX8sYnk vHpKL0VwWmP1//ob+DjW3OQs Received: from rampraka-linux.qualcomm.com ([10.206.25.221]) by ironmsg02-blr.qualcomm.com with ESMTP; 21 Oct 2019 20:00:42 +0530 Received: by rampraka-linux.qualcomm.com (Postfix, from userid 2305851) id 7BF69329D; Mon, 21 Oct 2019 20:00:41 +0530 (IST) From: Ram Prakash Gupta To: asutoshd@codeaurora.org, stummala@codeaurora.org, sayalil@codeaurora.org, rampraka@codeaurora.org, vbadigan@codeaurora.org, cang@codeaurora.org, ppvk@codeaurora.org, adrian.hunter@intel.com, ulf.hansson@linaro.org, robh+dt@kernel.org, linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Cc: Sujit Reddy Thumma , Talel Shenhar , Ritesh Harjani , "Bao D. Nguyen" Subject: [RFC 4/6] mmc: core: Add debugfs entries for scaling support Date: Mon, 21 Oct 2019 19:59:35 +0530 Message-Id: <1571668177-3766-5-git-send-email-rampraka@codeaurora.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1571668177-3766-1-git-send-email-rampraka@codeaurora.org> References: <1571668177-3766-1-git-send-email-rampraka@codeaurora.org> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add debugfs entries for scaling support. Signed-off-by: Sujit Reddy Thumma Signed-off-by: Talel Shenhar Signed-off-by: Sahitya Tummala Signed-off-by: Asutosh Das Signed-off-by: Ritesh Harjani Signed-off-by: Veerabhadrarao Badiganti Signed-off-by: Bao D. Nguyen Signed-off-by: Can Guo Signed-off-by: Sayali Lokhande Co-Developed-by: Ram Prakash Gupta Signed-off-by: Ram Prakash Gupta --- drivers/mmc/core/debugfs.c | 90 ++++++++++++++++++++++++++ drivers/mmc/core/host.c | 153 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 243 insertions(+) diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 09e0c76..a9f1e3f 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -222,6 +222,81 @@ static int mmc_clock_opt_set(void *data, u64 val) DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set, "%llu\n"); +static int mmc_scale_get(void *data, u64 *val) +{ + struct mmc_host *host = data; + + *val = host->clk_scaling.curr_freq; + + return 0; +} + +static int mmc_scale_set(void *data, u64 val) +{ + int err = 0; + struct mmc_host *host = data; + + mmc_claim_host(host); + + /* change frequency from sysfs manually */ + err = mmc_clk_update_freq(host, val, host->clk_scaling.state); + if (err == -EAGAIN) + err = 0; + else if (err) + pr_err("%s: clock scale to %llu failed with error %d\n", + mmc_hostname(host), val, err); + else + pr_debug("%s: clock change to %llu finished successfully (%s)\n", + mmc_hostname(host), val, current->comm); + + mmc_release_host(host); + + return err; +} + +DEFINE_SIMPLE_ATTRIBUTE(mmc_scale_fops, mmc_scale_get, mmc_scale_set, + "%llu\n"); + +static int mmc_max_clock_get(void *data, u64 *val) +{ + struct mmc_host *host = data; + + if (!host) + return -EINVAL; + + *val = host->f_max; + + return 0; +} + +static int mmc_max_clock_set(void *data, u64 val) +{ + struct mmc_host *host = data; + int err = -EINVAL; + unsigned long freq = val; + unsigned int old_freq; + + if (!host || (val < host->f_min)) + goto out; + + mmc_claim_host(host); + if (host->bus_ops && host->bus_ops->change_bus_speed) { + old_freq = host->f_max; + host->f_max = freq; + + err = host->bus_ops->change_bus_speed(host, &freq); + + if (err) + host->f_max = old_freq; + } + mmc_release_host(host); +out: + return err; +} + +DEFINE_SIMPLE_ATTRIBUTE(mmc_max_clock_fops, mmc_max_clock_get, + mmc_max_clock_set, "%llu\n"); + void mmc_add_host_debugfs(struct mmc_host *host) { struct dentry *root; @@ -235,6 +310,19 @@ void mmc_add_host_debugfs(struct mmc_host *host) debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host, &mmc_clock_fops); + if (!debugfs_create_file("max_clock", 0600, root, host, + &mmc_max_clock_fops)) + goto err_node; + + if (!debugfs_create_file("scale", 0600, root, host, + &mmc_scale_fops)) + goto err_node; + + if (!debugfs_create_bool("skip_clk_scale_freq_update", + 0600, root, + &host->clk_scaling.skip_clk_scale_freq_update)) + goto err_node; + #ifdef CONFIG_FAIL_MMC_REQUEST if (fail_request) setup_fault_attr(&fail_default_attr, fail_request); @@ -242,6 +330,8 @@ void mmc_add_host_debugfs(struct mmc_host *host) fault_create_debugfs_attr("fail_mmc_request", root, &host->fail_mmc_request); #endif +err_node: + return; } void mmc_remove_host_debugfs(struct mmc_host *host) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 9138041..c5b904b 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -522,6 +522,154 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) EXPORT_SYMBOL(mmc_alloc_host); +static ssize_t enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + + if (!host) + return -EINVAL; + + return snprintf(buf, PAGE_SIZE, "%d\n", mmc_can_scale_clk(host)); +} + +static ssize_t enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + unsigned long value; + + if (!host || !host->card || kstrtoul(buf, 0, &value)) + return -EINVAL; + + mmc_get_card(host->card, NULL); + + if (!value) { + /* Suspend the clock scaling and mask host capability */ + if (host->clk_scaling.enable) + mmc_suspend_clk_scaling(host); + host->clk_scaling.enable = false; + host->caps2 &= ~MMC_CAP2_CLK_SCALE; + host->clk_scaling.state = MMC_LOAD_HIGH; + /* Set to max. frequency when disabling */ + mmc_clk_update_freq(host, host->card->clk_scaling_highest, + host->clk_scaling.state); + } else if (value) { + /* Unmask host capability and resume scaling */ + host->caps2 |= MMC_CAP2_CLK_SCALE; + if (!host->clk_scaling.enable) { + host->clk_scaling.enable = true; + mmc_resume_clk_scaling(host); + } + } + + mmc_put_card(host->card, NULL); + + return count; +} + +static ssize_t up_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + + if (!host) + return -EINVAL; + + return snprintf(buf, PAGE_SIZE, "%d\n", host->clk_scaling.upthreshold); +} + +#define MAX_PERCENTAGE 100 +static ssize_t up_threshold_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + unsigned long value; + + if (!host || kstrtoul(buf, 0, &value) || (value > MAX_PERCENTAGE)) + return -EINVAL; + + host->clk_scaling.upthreshold = value; + + pr_debug("%s: clkscale_up_thresh set to %lu\n", + mmc_hostname(host), value); + return count; +} + +static ssize_t down_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + + if (!host) + return -EINVAL; + + return snprintf(buf, PAGE_SIZE, "%d\n", + host->clk_scaling.downthreshold); +} + +static ssize_t down_threshold_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + unsigned long value; + + if (!host || kstrtoul(buf, 0, &value) || (value > MAX_PERCENTAGE)) + return -EINVAL; + + host->clk_scaling.downthreshold = value; + + pr_debug("%s: clkscale_down_thresh set to %lu\n", + mmc_hostname(host), value); + return count; +} + +static ssize_t polling_interval_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + + if (!host) + return -EINVAL; + + return snprintf(buf, PAGE_SIZE, "%lu milliseconds\n", + host->clk_scaling.polling_delay_ms); +} + +static ssize_t polling_interval_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + unsigned long value; + + if (!host || kstrtoul(buf, 0, &value)) + return -EINVAL; + + host->clk_scaling.polling_delay_ms = value; + + pr_debug("%s: clkscale_polling_delay_ms set to %lu\n", + mmc_hostname(host), value); + return count; +} + +DEVICE_ATTR_RW(enable); +DEVICE_ATTR_RW(polling_interval); +DEVICE_ATTR_RW(up_threshold); +DEVICE_ATTR_RW(down_threshold); + +static struct attribute *clk_scaling_attrs[] = { + &dev_attr_enable.attr, + &dev_attr_up_threshold.attr, + &dev_attr_down_threshold.attr, + &dev_attr_polling_interval.attr, + NULL, +}; + +static struct attribute_group clk_scaling_attr_grp = { + .name = "clk_scaling", + .attrs = clk_scaling_attrs, +}; + /** * mmc_add_host - initialise host hardware * @host: mmc host @@ -551,6 +699,10 @@ int mmc_add_host(struct mmc_host *host) #ifdef CONFIG_DEBUG_FS mmc_add_host_debugfs(host); #endif + err = sysfs_create_group(&host->class_dev.kobj, &clk_scaling_attr_grp); + if (err) + pr_err("%s: failed to create clk scale sysfs group with err %d\n", + __func__, err); mmc_start_host(host); mmc_register_pm_notifier(host); @@ -577,6 +729,7 @@ void mmc_remove_host(struct mmc_host *host) mmc_remove_host_debugfs(host); #endif + sysfs_remove_group(&host->class_dev.kobj, &clk_scaling_attr_grp); device_del(&host->class_dev); led_trigger_unregister_simple(host->led); -- 1.9.1