OSDN Git Service

scsi: ufs: Add support for clock scaling using devfreq framework
authorSahitya Tummala <stummala@codeaurora.org>
Thu, 2 Jan 2014 07:57:14 +0000 (13:27 +0530)
committerDavid Keitel <dkeitel@codeaurora.org>
Tue, 22 Mar 2016 17:56:31 +0000 (10:56 -0700)
The clocks for UFS device will be managed by generic DVFS (Dynamic
Voltage and Frequency Scaling) framework within kernel. This devfreq
framework works with different governors to scale the clocks. By default,
UFS devices uses simple_ondemand governor which scales the clocks up if
the load is more than upthreshold and scales down if the load is less than
downthreshold.

Change-Id: I1c3944a5b1771b967c1df3e441a75fd584d6e2a5
Signed-off-by: Sahitya Tummala <stummala@codeaurora.org>
[gbroner@codeaurora.org: fix usage of devfreq governor data]
Signed-off-by: Gilad Broner <gbroner@codeaurora.org>
[subhashj@codeaurora.org: resolved merge conflicts, dropped most of the
changes as they are already present on baseline]
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
drivers/scsi/ufs/ufshcd.c
include/trace/events/ufs.h

index 108976b..9507b1d 100644 (file)
@@ -6073,6 +6073,11 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
                                                clki->max_freq, ret);
                                        break;
                                }
+                               trace_ufshcd_clk_scaling(dev_name(hba->dev),
+                                               "scaled up", clki->name,
+                                               clki->curr_freq,
+                                               clki->max_freq);
+
                                clki->curr_freq = clki->max_freq;
 
                        } else if (!scale_up && clki->min_freq) {
@@ -6085,6 +6090,10 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
                                                clki->min_freq, ret);
                                        break;
                                }
+                               trace_ufshcd_clk_scaling(dev_name(hba->dev),
+                                               "scaled down", clki->name,
+                                               clki->curr_freq,
+                                               clki->min_freq);
                                clki->curr_freq = clki->min_freq;
                        }
                }
@@ -6153,6 +6162,18 @@ start_window:
        return 0;
 }
 
+#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)
+static struct devfreq_simple_ondemand_data ufshcd_ondemand_data = {
+       .upthreshold = 35,
+       .downdifferential = 5,
+       .simple_scaling = 1,
+};
+
+static void *gov_data = &ufshcd_ondemand_data;
+#else
+static void *gov_data;
+#endif
+
 static struct devfreq_dev_profile ufs_devfreq_profile = {
        .polling_ms     = 100,
        .target         = ufshcd_devfreq_target,
@@ -6267,7 +6288,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
 
        if (ufshcd_is_clkscaling_enabled(hba)) {
                hba->devfreq = devfreq_add_device(dev, &ufs_devfreq_profile,
-                                                  "simple_ondemand", NULL);
+                                                  "simple_ondemand", gov_data);
                if (IS_ERR(hba->devfreq)) {
                        dev_err(hba->dev, "Unable to register with devfreq %ld\n",
                                        PTR_ERR(hba->devfreq));
index 3042ba7..36cd5ac 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -39,6 +39,34 @@ TRACE_EVENT(ufshcd_clk_gating,
                __get_str(dev_name), __get_str(state))
 );
 
+TRACE_EVENT(ufshcd_clk_scaling,
+
+       TP_PROTO(const char *dev_name, const char *state, const char *clk,
+               u32 prev_state, u32 curr_state),
+
+       TP_ARGS(dev_name, state, clk, prev_state, curr_state),
+
+       TP_STRUCT__entry(
+               __string(dev_name, dev_name)
+               __string(state, state)
+               __string(clk, clk)
+               __field(u32, prev_state)
+               __field(u32, curr_state)
+       ),
+
+       TP_fast_assign(
+               __assign_str(dev_name, dev_name);
+               __assign_str(state, state);
+               __assign_str(clk, clk);
+               __entry->prev_state = prev_state;
+               __entry->curr_state = curr_state;
+       ),
+
+       TP_printk("%s: %s %s from %u to %u Hz",
+               __get_str(dev_name), __get_str(state), __get_str(clk),
+               __entry->prev_state, __entry->curr_state)
+);
+
 DECLARE_EVENT_CLASS(ufshcd_template,
        TP_PROTO(const char *dev_name, int err, s64 usecs),