Commit c102671a authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'pm-devfreq'

* pm-devfreq: (24 commits)
  PM / devfreq: Add debugfs support with devfreq_summary file
  PM / devfreq: exynos: Rename Exynos to lowercase
  PM / devfreq: imx8m-ddrc: Fix inconsistent IS_ERR and PTR_ERR
  PM / devfreq: exynos-bus: Add error log when fail to get devfreq-event
  PM / devfreq: exynos-bus: Disable devfreq-event device when fails
  PM / devfreq: rk3399_dmc: Disable devfreq-event device when fails
  PM / devfreq: imx8m-ddrc: Remove unused defines
  PM / devfreq: exynos-bus: Reduce goto statements and remove unused headers
  PM / devfreq: rk3399_dmc: Add COMPILE_TEST and HAVE_ARM_SMCCC dependency
  PM / devfreq: rockchip-dfi: Convert to devm_platform_ioremap_resource
  PM / devfreq: rk3399_dmc: Add missing of_node_put()
  PM / devfreq: rockchip-dfi: Add missing of_node_put()
  PM / devfreq: Fix multiple kernel-doc warnings
  PM / devfreq: exynos-bus: Extract exynos_bus_profile_init_passive()
  PM / devfreq: exynos-bus: Extract exynos_bus_profile_init()
  PM / devfreq: Move declaration of DEVICE_ATTR_RW(min_freq)
  PM / devfreq: Move statistics to separate struct devfreq_stats
  PM / devfreq: Add clearing transitions stats
  PM / devfreq: Change time stats to 64-bit
  PM / devfreq: Add new name attribute for sysfs
  ...
parents c95d9c14 854e3349
...@@ -7,6 +7,13 @@ Description: ...@@ -7,6 +7,13 @@ Description:
The name of devfreq object denoted as ... is same as the The name of devfreq object denoted as ... is same as the
name of device using devfreq. name of device using devfreq.
What: /sys/class/devfreq/.../name
Date: November 2019
Contact: Chanwoo Choi <cw00.choi@samsung.com>
Description:
The /sys/class/devfreq/.../name shows the name of device
of the corresponding devfreq object.
What: /sys/class/devfreq/.../governor What: /sys/class/devfreq/.../governor
Date: September 2011 Date: September 2011
Contact: MyungJoo Ham <myungjoo.ham@samsung.com> Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
...@@ -48,12 +55,15 @@ What: /sys/class/devfreq/.../trans_stat ...@@ -48,12 +55,15 @@ What: /sys/class/devfreq/.../trans_stat
Date: October 2012 Date: October 2012
Contact: MyungJoo Ham <myungjoo.ham@samsung.com> Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
Description: Description:
This ABI shows the statistics of devfreq behavior on a This ABI shows or clears the statistics of devfreq behavior
specific device. It shows the time spent in each state and on a specific device. It shows the time spent in each state
the number of transitions between states. and the number of transitions between states.
In order to activate this ABI, the devfreq target device In order to activate this ABI, the devfreq target device
driver should provide the list of available frequencies driver should provide the list of available frequencies
with its profile. with its profile. If need to reset the statistics of devfreq
behavior on a specific device, enter 0(zero) to 'trans_stat'
as following:
echo 0 > /sys/class/devfreq/.../trans_stat
What: /sys/class/devfreq/.../userspace/set_freq What: /sys/class/devfreq/.../userspace/set_freq
Date: September 2011 Date: September 2011
......
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/fsl/imx8m-ddrc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: i.MX8M DDR Controller
maintainers:
- Leonard Crestez <leonard.crestez@nxp.com>
description:
The DDRC block is integrated in i.MX8M for interfacing with DDR based
memories.
It supports switching between different frequencies at runtime but during
this process RAM itself becomes briefly inaccessible so actual frequency
switching is implemented by TF-A code which runs from a SRAM area.
The Linux driver for the DDRC doesn't even map registers (they're included
for the sake of "describing hardware"), it mostly just exposes firmware
capabilities through standard Linux mechanism like devfreq and OPP tables.
properties:
compatible:
items:
- enum:
- fsl,imx8mn-ddrc
- fsl,imx8mm-ddrc
- fsl,imx8mq-ddrc
- const: fsl,imx8m-ddrc
reg:
maxItems: 1
description:
Base address and size of DDRC CTL area.
This is not currently mapped by the imx8m-ddrc driver.
clocks:
maxItems: 4
clock-names:
items:
- const: core
- const: pll
- const: alt
- const: apb
operating-points-v2: true
opp-table: true
required:
- reg
- compatible
- clocks
- clock-names
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx8mm-clock.h>
ddrc: memory-controller@3d400000 {
compatible = "fsl,imx8mm-ddrc", "fsl,imx8m-ddrc";
reg = <0x3d400000 0x400000>;
clock-names = "core", "pll", "alt", "apb";
clocks = <&clk IMX8MM_CLK_DRAM_CORE>,
<&clk IMX8MM_DRAM_PLL>,
<&clk IMX8MM_CLK_DRAM_ALT>,
<&clk IMX8MM_CLK_DRAM_APB>;
operating-points-v2 = <&ddrc_opp_table>;
};
...@@ -77,7 +77,7 @@ config DEVFREQ_GOV_PASSIVE ...@@ -77,7 +77,7 @@ config DEVFREQ_GOV_PASSIVE
comment "DEVFREQ Drivers" comment "DEVFREQ Drivers"
config ARM_EXYNOS_BUS_DEVFREQ config ARM_EXYNOS_BUS_DEVFREQ
tristate "ARM EXYNOS Generic Memory Bus DEVFREQ Driver" tristate "ARM Exynos Generic Memory Bus DEVFREQ Driver"
depends on ARCH_EXYNOS || COMPILE_TEST depends on ARCH_EXYNOS || COMPILE_TEST
select DEVFREQ_GOV_SIMPLE_ONDEMAND select DEVFREQ_GOV_SIMPLE_ONDEMAND
select DEVFREQ_GOV_PASSIVE select DEVFREQ_GOV_PASSIVE
...@@ -91,6 +91,16 @@ config ARM_EXYNOS_BUS_DEVFREQ ...@@ -91,6 +91,16 @@ config ARM_EXYNOS_BUS_DEVFREQ
and adjusts the operating frequencies and voltages with OPP support. and adjusts the operating frequencies and voltages with OPP support.
This does not yet operate with optimal voltages. This does not yet operate with optimal voltages.
config ARM_IMX8M_DDRC_DEVFREQ
tristate "i.MX8M DDRC DEVFREQ Driver"
depends on (ARCH_MXC && HAVE_ARM_SMCCC) || \
(COMPILE_TEST && HAVE_ARM_SMCCC)
select DEVFREQ_GOV_SIMPLE_ONDEMAND
select DEVFREQ_GOV_USERSPACE
help
This adds the DEVFREQ driver for the i.MX8M DDR Controller. It allows
adjusting DRAM frequency.
config ARM_TEGRA_DEVFREQ config ARM_TEGRA_DEVFREQ
tristate "NVIDIA Tegra30/114/124/210 DEVFREQ Driver" tristate "NVIDIA Tegra30/114/124/210 DEVFREQ Driver"
depends on ARCH_TEGRA_3x_SOC || ARCH_TEGRA_114_SOC || \ depends on ARCH_TEGRA_3x_SOC || ARCH_TEGRA_114_SOC || \
...@@ -115,14 +125,15 @@ config ARM_TEGRA20_DEVFREQ ...@@ -115,14 +125,15 @@ config ARM_TEGRA20_DEVFREQ
config ARM_RK3399_DMC_DEVFREQ config ARM_RK3399_DMC_DEVFREQ
tristate "ARM RK3399 DMC DEVFREQ Driver" tristate "ARM RK3399 DMC DEVFREQ Driver"
depends on ARCH_ROCKCHIP depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \
(COMPILE_TEST && HAVE_ARM_SMCCC)
select DEVFREQ_EVENT_ROCKCHIP_DFI select DEVFREQ_EVENT_ROCKCHIP_DFI
select DEVFREQ_GOV_SIMPLE_ONDEMAND select DEVFREQ_GOV_SIMPLE_ONDEMAND
select PM_DEVFREQ_EVENT select PM_DEVFREQ_EVENT
help help
This adds the DEVFREQ driver for the RK3399 DMC(Dynamic Memory Controller). This adds the DEVFREQ driver for the RK3399 DMC(Dynamic Memory Controller).
It sets the frequency for the memory controller and reads the usage counts It sets the frequency for the memory controller and reads the usage counts
from hardware. from hardware.
source "drivers/devfreq/event/Kconfig" source "drivers/devfreq/event/Kconfig"
......
...@@ -9,6 +9,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o ...@@ -9,6 +9,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o
# DEVFREQ Drivers # DEVFREQ Drivers
obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o
obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ) += imx8m-ddrc.o
obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o
obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o
obj-$(CONFIG_ARM_TEGRA20_DEVFREQ) += tegra20-devfreq.o obj-$(CONFIG_ARM_TEGRA20_DEVFREQ) += tegra20-devfreq.o
......
...@@ -346,9 +346,9 @@ EXPORT_SYMBOL_GPL(devfreq_event_add_edev); ...@@ -346,9 +346,9 @@ EXPORT_SYMBOL_GPL(devfreq_event_add_edev);
/** /**
* devfreq_event_remove_edev() - Remove the devfreq-event device registered. * devfreq_event_remove_edev() - Remove the devfreq-event device registered.
* @dev : the devfreq-event device * @edev : the devfreq-event device
* *
* Note that this function remove the registered devfreq-event device. * Note that this function removes the registered devfreq-event device.
*/ */
int devfreq_event_remove_edev(struct devfreq_event_dev *edev) int devfreq_event_remove_edev(struct devfreq_event_dev *edev)
{ {
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/debugfs.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -33,6 +34,7 @@ ...@@ -33,6 +34,7 @@
#define HZ_PER_KHZ 1000 #define HZ_PER_KHZ 1000
static struct class *devfreq_class; static struct class *devfreq_class;
static struct dentry *devfreq_debugfs;
/* /*
* devfreq core provides delayed work based load monitoring helper * devfreq core provides delayed work based load monitoring helper
...@@ -209,10 +211,10 @@ static int set_freq_table(struct devfreq *devfreq) ...@@ -209,10 +211,10 @@ static int set_freq_table(struct devfreq *devfreq)
int devfreq_update_status(struct devfreq *devfreq, unsigned long freq) int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
{ {
int lev, prev_lev, ret = 0; int lev, prev_lev, ret = 0;
unsigned long cur_time; u64 cur_time;
lockdep_assert_held(&devfreq->lock); lockdep_assert_held(&devfreq->lock);
cur_time = jiffies; cur_time = get_jiffies_64();
/* Immediately exit if previous_freq is not initialized yet. */ /* Immediately exit if previous_freq is not initialized yet. */
if (!devfreq->previous_freq) if (!devfreq->previous_freq)
...@@ -224,8 +226,8 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq) ...@@ -224,8 +226,8 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
goto out; goto out;
} }
devfreq->time_in_state[prev_lev] += devfreq->stats.time_in_state[prev_lev] +=
cur_time - devfreq->last_stat_updated; cur_time - devfreq->stats.last_update;
lev = devfreq_get_freq_level(devfreq, freq); lev = devfreq_get_freq_level(devfreq, freq);
if (lev < 0) { if (lev < 0) {
...@@ -234,13 +236,13 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq) ...@@ -234,13 +236,13 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
} }
if (lev != prev_lev) { if (lev != prev_lev) {
devfreq->trans_table[(prev_lev * devfreq->stats.trans_table[
devfreq->profile->max_state) + lev]++; (prev_lev * devfreq->profile->max_state) + lev]++;
devfreq->total_trans++; devfreq->stats.total_trans++;
} }
out: out:
devfreq->last_stat_updated = cur_time; devfreq->stats.last_update = cur_time;
return ret; return ret;
} }
EXPORT_SYMBOL(devfreq_update_status); EXPORT_SYMBOL(devfreq_update_status);
...@@ -535,7 +537,7 @@ void devfreq_monitor_resume(struct devfreq *devfreq) ...@@ -535,7 +537,7 @@ void devfreq_monitor_resume(struct devfreq *devfreq)
msecs_to_jiffies(devfreq->profile->polling_ms)); msecs_to_jiffies(devfreq->profile->polling_ms));
out_update: out_update:
devfreq->last_stat_updated = jiffies; devfreq->stats.last_update = get_jiffies_64();
devfreq->stop_polling = false; devfreq->stop_polling = false;
if (devfreq->profile->get_cur_freq && if (devfreq->profile->get_cur_freq &&
...@@ -807,28 +809,29 @@ struct devfreq *devfreq_add_device(struct device *dev, ...@@ -807,28 +809,29 @@ struct devfreq *devfreq_add_device(struct device *dev,
goto err_out; goto err_out;
} }
devfreq->trans_table = devm_kzalloc(&devfreq->dev, devfreq->stats.trans_table = devm_kzalloc(&devfreq->dev,
array3_size(sizeof(unsigned int), array3_size(sizeof(unsigned int),
devfreq->profile->max_state, devfreq->profile->max_state,
devfreq->profile->max_state), devfreq->profile->max_state),
GFP_KERNEL); GFP_KERNEL);
if (!devfreq->trans_table) { if (!devfreq->stats.trans_table) {
mutex_unlock(&devfreq->lock); mutex_unlock(&devfreq->lock);
err = -ENOMEM; err = -ENOMEM;
goto err_devfreq; goto err_devfreq;
} }
devfreq->time_in_state = devm_kcalloc(&devfreq->dev, devfreq->stats.time_in_state = devm_kcalloc(&devfreq->dev,
devfreq->profile->max_state, devfreq->profile->max_state,
sizeof(unsigned long), sizeof(*devfreq->stats.time_in_state),
GFP_KERNEL); GFP_KERNEL);
if (!devfreq->time_in_state) { if (!devfreq->stats.time_in_state) {
mutex_unlock(&devfreq->lock); mutex_unlock(&devfreq->lock);
err = -ENOMEM; err = -ENOMEM;
goto err_devfreq; goto err_devfreq;
} }
devfreq->last_stat_updated = jiffies; devfreq->stats.total_trans = 0;
devfreq->stats.last_update = get_jiffies_64();
srcu_init_notifier_head(&devfreq->transition_notifier_list); srcu_init_notifier_head(&devfreq->transition_notifier_list);
...@@ -1259,6 +1262,14 @@ int devfreq_remove_governor(struct devfreq_governor *governor) ...@@ -1259,6 +1262,14 @@ int devfreq_remove_governor(struct devfreq_governor *governor)
} }
EXPORT_SYMBOL(devfreq_remove_governor); EXPORT_SYMBOL(devfreq_remove_governor);
static ssize_t name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct devfreq *devfreq = to_devfreq(dev);
return sprintf(buf, "%s\n", dev_name(devfreq->dev.parent));
}
static DEVICE_ATTR_RO(name);
static ssize_t governor_show(struct device *dev, static ssize_t governor_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
...@@ -1461,6 +1472,7 @@ static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr, ...@@ -1461,6 +1472,7 @@ static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%lu\n", min_freq); return sprintf(buf, "%lu\n", min_freq);
} }
static DEVICE_ATTR_RW(min_freq);
static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
...@@ -1501,7 +1513,6 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, ...@@ -1501,7 +1513,6 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
return count; return count;
} }
static DEVICE_ATTR_RW(min_freq);
static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr, static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
...@@ -1580,18 +1591,47 @@ static ssize_t trans_stat_show(struct device *dev, ...@@ -1580,18 +1591,47 @@ static ssize_t trans_stat_show(struct device *dev,
devfreq->profile->freq_table[i]); devfreq->profile->freq_table[i]);
for (j = 0; j < max_state; j++) for (j = 0; j < max_state; j++)
len += sprintf(buf + len, "%10u", len += sprintf(buf + len, "%10u",
devfreq->trans_table[(i * max_state) + j]); devfreq->stats.trans_table[(i * max_state) + j]);
len += sprintf(buf + len, "%10u\n",
jiffies_to_msecs(devfreq->time_in_state[i])); len += sprintf(buf + len, "%10llu\n", (u64)
jiffies64_to_msecs(devfreq->stats.time_in_state[i]));
} }
len += sprintf(buf + len, "Total transition : %u\n", len += sprintf(buf + len, "Total transition : %u\n",
devfreq->total_trans); devfreq->stats.total_trans);
return len; return len;
} }
static DEVICE_ATTR_RO(trans_stat);
static ssize_t trans_stat_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct devfreq *df = to_devfreq(dev);
int err, value;
if (df->profile->max_state == 0)
return count;
err = kstrtoint(buf, 10, &value);
if (err || value != 0)
return -EINVAL;
mutex_lock(&df->lock);
memset(df->stats.time_in_state, 0, (df->profile->max_state *
sizeof(*df->stats.time_in_state)));
memset(df->stats.trans_table, 0, array3_size(sizeof(unsigned int),
df->profile->max_state,
df->profile->max_state));
df->stats.total_trans = 0;
df->stats.last_update = get_jiffies_64();
mutex_unlock(&df->lock);
return count;
}
static DEVICE_ATTR_RW(trans_stat);
static struct attribute *devfreq_attrs[] = { static struct attribute *devfreq_attrs[] = {
&dev_attr_name.attr,
&dev_attr_governor.attr, &dev_attr_governor.attr,
&dev_attr_available_governors.attr, &dev_attr_available_governors.attr,
&dev_attr_cur_freq.attr, &dev_attr_cur_freq.attr,
...@@ -1605,6 +1645,81 @@ static struct attribute *devfreq_attrs[] = { ...@@ -1605,6 +1645,81 @@ static struct attribute *devfreq_attrs[] = {
}; };
ATTRIBUTE_GROUPS(devfreq); ATTRIBUTE_GROUPS(devfreq);
/**
* devfreq_summary_show() - Show the summary of the devfreq devices
* @s: seq_file instance to show the summary of devfreq devices
* @data: not used
*
* Show the summary of the devfreq devices via 'devfreq_summary' debugfs file.
* It helps that user can know the detailed information of the devfreq devices.
*
* Return 0 always because it shows the information without any data change.
*/
static int devfreq_summary_show(struct seq_file *s, void *data)
{
struct devfreq *devfreq;
struct devfreq *p_devfreq = NULL;
unsigned long cur_freq, min_freq, max_freq;
unsigned int polling_ms;
seq_printf(s, "%-30s %-10s %-10s %-15s %10s %12s %12s %12s\n",
"dev_name",
"dev",
"parent_dev",
"governor",
"polling_ms",
"cur_freq_Hz",
"min_freq_Hz",
"max_freq_Hz");
seq_printf(s, "%30s %10s %10s %15s %10s %12s %12s %12s\n",
"------------------------------",
"----------",
"----------",
"---------------",
"----------",
"------------",
"------------",
"------------");
mutex_lock(&devfreq_list_lock);
list_for_each_entry_reverse(devfreq, &devfreq_list, node) {
#if IS_ENABLED(CONFIG_DEVFREQ_GOV_PASSIVE)
if (!strncmp(devfreq->governor_name, DEVFREQ_GOV_PASSIVE,
DEVFREQ_NAME_LEN)) {
struct devfreq_passive_data *data = devfreq->data;
if (data)
p_devfreq = data->parent;
} else {
p_devfreq = NULL;
}
#endif
mutex_lock(&devfreq->lock);
cur_freq = devfreq->previous_freq,
get_freq_range(devfreq, &min_freq, &max_freq);
polling_ms = devfreq->profile->polling_ms,
mutex_unlock(&devfreq->lock);
seq_printf(s,
"%-30s %-10s %-10s %-15s %10d %12ld %12ld %12ld\n",
dev_name(devfreq->dev.parent),
dev_name(&devfreq->dev),
p_devfreq ? dev_name(&p_devfreq->dev) : "null",
devfreq->governor_name,
polling_ms,
cur_freq,
min_freq,
max_freq);
}
mutex_unlock(&devfreq_list_lock);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(devfreq_summary);
static int __init devfreq_init(void) static int __init devfreq_init(void)
{ {
devfreq_class = class_create(THIS_MODULE, "devfreq"); devfreq_class = class_create(THIS_MODULE, "devfreq");
...@@ -1621,6 +1736,11 @@ static int __init devfreq_init(void) ...@@ -1621,6 +1736,11 @@ static int __init devfreq_init(void)
} }
devfreq_class->dev_groups = devfreq_groups; devfreq_class->dev_groups = devfreq_groups;
devfreq_debugfs = debugfs_create_dir("devfreq", NULL);
debugfs_create_file("devfreq_summary", 0444,
devfreq_debugfs, NULL,
&devfreq_summary_fops);
return 0; return 0;
} }
subsys_initcall(devfreq_init); subsys_initcall(devfreq_init);
...@@ -1814,7 +1934,7 @@ static void devm_devfreq_notifier_release(struct device *dev, void *res) ...@@ -1814,7 +1934,7 @@ static void devm_devfreq_notifier_release(struct device *dev, void *res)
/** /**
* devm_devfreq_register_notifier() * devm_devfreq_register_notifier()
- Resource-managed devfreq_register_notifier() * - Resource-managed devfreq_register_notifier()
* @dev: The devfreq user device. (parent of devfreq) * @dev: The devfreq user device. (parent of devfreq)
* @devfreq: The devfreq object. * @devfreq: The devfreq object.
* @nb: The notifier block to be unregistered. * @nb: The notifier block to be unregistered.
...@@ -1850,7 +1970,7 @@ EXPORT_SYMBOL(devm_devfreq_register_notifier); ...@@ -1850,7 +1970,7 @@ EXPORT_SYMBOL(devm_devfreq_register_notifier);
/** /**
* devm_devfreq_unregister_notifier() * devm_devfreq_unregister_notifier()
- Resource-managed devfreq_unregister_notifier() * - Resource-managed devfreq_unregister_notifier()
* @dev: The devfreq user device. (parent of devfreq) * @dev: The devfreq user device. (parent of devfreq)
* @devfreq: The devfreq object. * @devfreq: The devfreq object.
* @nb: The notifier block to be unregistered. * @nb: The notifier block to be unregistered.
......
...@@ -15,7 +15,7 @@ menuconfig PM_DEVFREQ_EVENT ...@@ -15,7 +15,7 @@ menuconfig PM_DEVFREQ_EVENT
if PM_DEVFREQ_EVENT if PM_DEVFREQ_EVENT
config DEVFREQ_EVENT_EXYNOS_NOCP config DEVFREQ_EVENT_EXYNOS_NOCP
tristate "EXYNOS NoC (Network On Chip) Probe DEVFREQ event Driver" tristate "Exynos NoC (Network On Chip) Probe DEVFREQ event Driver"
depends on ARCH_EXYNOS || COMPILE_TEST depends on ARCH_EXYNOS || COMPILE_TEST
select PM_OPP select PM_OPP
select REGMAP_MMIO select REGMAP_MMIO
...@@ -24,7 +24,7 @@ config DEVFREQ_EVENT_EXYNOS_NOCP ...@@ -24,7 +24,7 @@ config DEVFREQ_EVENT_EXYNOS_NOCP
(Network on Chip) Probe counters to measure the bandwidth of AXI bus. (Network on Chip) Probe counters to measure the bandwidth of AXI bus.
config DEVFREQ_EVENT_EXYNOS_PPMU config DEVFREQ_EVENT_EXYNOS_PPMU
tristate "EXYNOS PPMU (Platform Performance Monitoring Unit) DEVFREQ event Driver" tristate "Exynos PPMU (Platform Performance Monitoring Unit) DEVFREQ event Driver"
depends on ARCH_EXYNOS || COMPILE_TEST depends on ARCH_EXYNOS || COMPILE_TEST
select PM_OPP select PM_OPP
help help
...@@ -34,7 +34,7 @@ config DEVFREQ_EVENT_EXYNOS_PPMU ...@@ -34,7 +34,7 @@ config DEVFREQ_EVENT_EXYNOS_PPMU
config DEVFREQ_EVENT_ROCKCHIP_DFI config DEVFREQ_EVENT_ROCKCHIP_DFI
tristate "ROCKCHIP DFI DEVFREQ event Driver" tristate "ROCKCHIP DFI DEVFREQ event Driver"
depends on ARCH_ROCKCHIP depends on ARCH_ROCKCHIP || COMPILE_TEST
help help
This add the devfreq-event driver for Rockchip SoC. It provides DFI This add the devfreq-event driver for Rockchip SoC. It provides DFI
(DDR Monitor Module) driver to count ddr load. (DDR Monitor Module) driver to count ddr load.
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* exynos-nocp.c - EXYNOS NoC (Network On Chip) Probe support * exynos-nocp.c - Exynos NoC (Network On Chip) Probe support
* *
* Copyright (c) 2016 Samsung Electronics Co., Ltd. * Copyright (c) 2016 Samsung Electronics Co., Ltd.
* Author : Chanwoo Choi <cw00.choi@samsung.com> * Author : Chanwoo Choi <cw00.choi@samsung.com>
......
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* exynos-nocp.h - EXYNOS NoC (Network on Chip) Probe header file * exynos-nocp.h - Exynos NoC (Network on Chip) Probe header file
* *
* Copyright (c) 2016 Samsung Electronics Co., Ltd. * Copyright (c) 2016 Samsung Electronics Co., Ltd.
* Author : Chanwoo Choi <cw00.choi@samsung.com> * Author : Chanwoo Choi <cw00.choi@samsung.com>
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* exynos_ppmu.c - EXYNOS PPMU (Platform Performance Monitoring Unit) support * exynos_ppmu.c - Exynos PPMU (Platform Performance Monitoring Unit) support
* *
* Copyright (c) 2014-2015 Samsung Electronics Co., Ltd. * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd.
* Author : Chanwoo Choi <cw00.choi@samsung.com> * Author : Chanwoo Choi <cw00.choi@samsung.com>
...@@ -101,17 +101,22 @@ static struct __exynos_ppmu_events { ...@@ -101,17 +101,22 @@ static struct __exynos_ppmu_events {
PPMU_EVENT(dmc1_1), PPMU_EVENT(dmc1_1),
}; };
static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev) static int __exynos_ppmu_find_ppmu_id(const char *edev_name)
{ {
int i; int i;
for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) for (i = 0; i < ARRAY_SIZE(ppmu_events); i++)
if (!strcmp(edev->desc->name, ppmu_events[i].name)) if (!strcmp(edev_name, ppmu_events[i].name))
return ppmu_events[i].id; return ppmu_events[i].id;
return -EINVAL; return -EINVAL;
} }
static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev)
{
return __exynos_ppmu_find_ppmu_id(edev->desc->name);
}
/* /*
* The devfreq-event ops structure for PPMU v1.1 * The devfreq-event ops structure for PPMU v1.1
*/ */
...@@ -556,13 +561,11 @@ static int of_get_devfreq_events(struct device_node *np, ...@@ -556,13 +561,11 @@ static int of_get_devfreq_events(struct device_node *np,
* use default if not. * use default if not.
*/ */
if (info->ppmu_type == EXYNOS_TYPE_PPMU_V2) { if (info->ppmu_type == EXYNOS_TYPE_PPMU_V2) {
struct devfreq_event_dev edev;
int id; int id;
/* Not all registers take the same value for /* Not all registers take the same value for
* read+write data count. * read+write data count.
*/ */
edev.desc = &desc[j]; id = __exynos_ppmu_find_ppmu_id(desc[j].name);
id = exynos_ppmu_find_ppmu_id(&edev);
switch (id) { switch (id) {
case PPMU_PMNCNT0: case PPMU_PMNCNT0:
......
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* exynos_ppmu.h - EXYNOS PPMU header file * exynos_ppmu.h - Exynos PPMU header file
* *
* Copyright (c) 2015 Samsung Electronics Co., Ltd. * Copyright (c) 2015 Samsung Electronics Co., Ltd.
* Author : Chanwoo Choi <cw00.choi@samsung.com> * Author : Chanwoo Choi <cw00.choi@samsung.com>
......
...@@ -177,7 +177,6 @@ static int rockchip_dfi_probe(struct platform_device *pdev) ...@@ -177,7 +177,6 @@ static int rockchip_dfi_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct rockchip_dfi *data; struct rockchip_dfi *data;
struct resource *res;
struct devfreq_event_desc *desc; struct devfreq_event_desc *desc;
struct device_node *np = pdev->dev.of_node, *node; struct device_node *np = pdev->dev.of_node, *node;
...@@ -185,8 +184,7 @@ static int rockchip_dfi_probe(struct platform_device *pdev) ...@@ -185,8 +184,7 @@ static int rockchip_dfi_probe(struct platform_device *pdev)
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); data->regs = devm_platform_ioremap_resource(pdev, 0);
data->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(data->regs)) if (IS_ERR(data->regs))
return PTR_ERR(data->regs); return PTR_ERR(data->regs);
...@@ -200,6 +198,7 @@ static int rockchip_dfi_probe(struct platform_device *pdev) ...@@ -200,6 +198,7 @@ static int rockchip_dfi_probe(struct platform_device *pdev)
node = of_parse_phandle(np, "rockchip,pmu", 0); node = of_parse_phandle(np, "rockchip,pmu", 0);
if (node) { if (node) {
data->regmap_pmu = syscon_node_to_regmap(node); data->regmap_pmu = syscon_node_to_regmap(node);
of_node_put(node);
if (IS_ERR(data->regmap_pmu)) if (IS_ERR(data->regmap_pmu))
return PTR_ERR(data->regmap_pmu); return PTR_ERR(data->regmap_pmu);
} }
......
...@@ -15,11 +15,10 @@ ...@@ -15,11 +15,10 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of.h>
#include <linux/pm_opp.h> #include <linux/pm_opp.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/slab.h>
#define DEFAULT_SATURATION_RATIO 40 #define DEFAULT_SATURATION_RATIO 40
...@@ -127,6 +126,7 @@ static int exynos_bus_get_dev_status(struct device *dev, ...@@ -127,6 +126,7 @@ static int exynos_bus_get_dev_status(struct device *dev,
ret = exynos_bus_get_event(bus, &edata); ret = exynos_bus_get_event(bus, &edata);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "failed to get event from devfreq-event devices\n");
stat->total_time = stat->busy_time = 0; stat->total_time = stat->busy_time = 0;
goto err; goto err;
} }
...@@ -287,52 +287,12 @@ static int exynos_bus_parse_of(struct device_node *np, ...@@ -287,52 +287,12 @@ static int exynos_bus_parse_of(struct device_node *np,
return ret; return ret;
} }
static int exynos_bus_probe(struct platform_device *pdev) static int exynos_bus_profile_init(struct exynos_bus *bus,
struct devfreq_dev_profile *profile)
{ {
struct device *dev = &pdev->dev; struct device *dev = bus->dev;
struct device_node *np = dev->of_node, *node;
struct devfreq_dev_profile *profile;
struct devfreq_simple_ondemand_data *ondemand_data; struct devfreq_simple_ondemand_data *ondemand_data;
struct devfreq_passive_data *passive_data; int ret;
struct devfreq *parent_devfreq;
struct exynos_bus *bus;
int ret, max_state;
unsigned long min_freq, max_freq;
bool passive = false;
if (!np) {
dev_err(dev, "failed to find devicetree node\n");
return -EINVAL;
}
bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
if (!bus)
return -ENOMEM;
mutex_init(&bus->lock);
bus->dev = &pdev->dev;
platform_set_drvdata(pdev, bus);
profile = devm_kzalloc(dev, sizeof(*profile), GFP_KERNEL);
if (!profile)
return -ENOMEM;
node = of_parse_phandle(dev->of_node, "devfreq", 0);
if (node) {
of_node_put(node);
passive = true;
} else {
ret = exynos_bus_parent_parse_of(np, bus);
if (ret < 0)
return ret;
}
/* Parse the device-tree to get the resource information */
ret = exynos_bus_parse_of(np, bus);
if (ret < 0)
goto err_reg;
if (passive)
goto passive;
/* Initialize the struct profile and governor data for parent device */ /* Initialize the struct profile and governor data for parent device */
profile->polling_ms = 50; profile->polling_ms = 50;
...@@ -341,10 +301,9 @@ static int exynos_bus_probe(struct platform_device *pdev) ...@@ -341,10 +301,9 @@ static int exynos_bus_probe(struct platform_device *pdev)
profile->exit = exynos_bus_exit; profile->exit = exynos_bus_exit;
ondemand_data = devm_kzalloc(dev, sizeof(*ondemand_data), GFP_KERNEL); ondemand_data = devm_kzalloc(dev, sizeof(*ondemand_data), GFP_KERNEL);
if (!ondemand_data) { if (!ondemand_data)
ret = -ENOMEM; return -ENOMEM;
goto err;
}
ondemand_data->upthreshold = 40; ondemand_data->upthreshold = 40;
ondemand_data->downdifferential = 5; ondemand_data->downdifferential = 5;
...@@ -354,15 +313,14 @@ static int exynos_bus_probe(struct platform_device *pdev) ...@@ -354,15 +313,14 @@ static int exynos_bus_probe(struct platform_device *pdev)
ondemand_data); ondemand_data);
if (IS_ERR(bus->devfreq)) { if (IS_ERR(bus->devfreq)) {
dev_err(dev, "failed to add devfreq device\n"); dev_err(dev, "failed to add devfreq device\n");
ret = PTR_ERR(bus->devfreq); return PTR_ERR(bus->devfreq);
goto err;
} }
/* Register opp_notifier to catch the change of OPP */ /* Register opp_notifier to catch the change of OPP */
ret = devm_devfreq_register_opp_notifier(dev, bus->devfreq); ret = devm_devfreq_register_opp_notifier(dev, bus->devfreq);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "failed to register opp notifier\n"); dev_err(dev, "failed to register opp notifier\n");
goto err; return ret;
} }
/* /*
...@@ -372,33 +330,44 @@ static int exynos_bus_probe(struct platform_device *pdev) ...@@ -372,33 +330,44 @@ static int exynos_bus_probe(struct platform_device *pdev)
ret = exynos_bus_enable_edev(bus); ret = exynos_bus_enable_edev(bus);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "failed to enable devfreq-event devices\n"); dev_err(dev, "failed to enable devfreq-event devices\n");
goto err; return ret;
} }
ret = exynos_bus_set_event(bus); ret = exynos_bus_set_event(bus);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "failed to set event to devfreq-event devices\n"); dev_err(dev, "failed to set event to devfreq-event devices\n");
goto err; goto err_edev;
} }
goto out; return 0;
passive:
err_edev:
if (exynos_bus_disable_edev(bus))
dev_warn(dev, "failed to disable the devfreq-event devices\n");
return ret;
}
static int exynos_bus_profile_init_passive(struct exynos_bus *bus,
struct devfreq_dev_profile *profile)
{
struct device *dev = bus->dev;
struct devfreq_passive_data *passive_data;
struct devfreq *parent_devfreq;
/* Initialize the struct profile and governor data for passive device */ /* Initialize the struct profile and governor data for passive device */
profile->target = exynos_bus_target; profile->target = exynos_bus_target;
profile->exit = exynos_bus_passive_exit; profile->exit = exynos_bus_passive_exit;
/* Get the instance of parent devfreq device */ /* Get the instance of parent devfreq device */
parent_devfreq = devfreq_get_devfreq_by_phandle(dev, 0); parent_devfreq = devfreq_get_devfreq_by_phandle(dev, 0);
if (IS_ERR(parent_devfreq)) { if (IS_ERR(parent_devfreq))
ret = -EPROBE_DEFER; return -EPROBE_DEFER;
goto err;
}
passive_data = devm_kzalloc(dev, sizeof(*passive_data), GFP_KERNEL); passive_data = devm_kzalloc(dev, sizeof(*passive_data), GFP_KERNEL);
if (!passive_data) { if (!passive_data)
ret = -ENOMEM; return -ENOMEM;
goto err;
}
passive_data->parent = parent_devfreq; passive_data->parent = parent_devfreq;
/* Add devfreq device for exynos bus with passive governor */ /* Add devfreq device for exynos bus with passive governor */
...@@ -407,11 +376,61 @@ static int exynos_bus_probe(struct platform_device *pdev) ...@@ -407,11 +376,61 @@ static int exynos_bus_probe(struct platform_device *pdev)
if (IS_ERR(bus->devfreq)) { if (IS_ERR(bus->devfreq)) {
dev_err(dev, dev_err(dev,
"failed to add devfreq dev with passive governor\n"); "failed to add devfreq dev with passive governor\n");
ret = PTR_ERR(bus->devfreq); return PTR_ERR(bus->devfreq);
goto err; }
return 0;
}
static int exynos_bus_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node, *node;
struct devfreq_dev_profile *profile;
struct exynos_bus *bus;
int ret, max_state;
unsigned long min_freq, max_freq;
bool passive = false;
if (!np) {
dev_err(dev, "failed to find devicetree node\n");
return -EINVAL;
} }
out: bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
if (!bus)
return -ENOMEM;
mutex_init(&bus->lock);
bus->dev = &pdev->dev;
platform_set_drvdata(pdev, bus);
profile = devm_kzalloc(dev, sizeof(*profile), GFP_KERNEL);
if (!profile)
return -ENOMEM;
node = of_parse_phandle(dev->of_node, "devfreq", 0);
if (node) {
of_node_put(node);
passive = true;
} else {
ret = exynos_bus_parent_parse_of(np, bus);
if (ret < 0)
return ret;
}
/* Parse the device-tree to get the resource information */
ret = exynos_bus_parse_of(np, bus);
if (ret < 0)
goto err_reg;
if (passive)
ret = exynos_bus_profile_init_passive(bus, profile);
else
ret = exynos_bus_profile_init(bus, profile);
if (ret < 0)
goto err;
max_state = bus->devfreq->profile->max_state; max_state = bus->devfreq->profile->max_state;
min_freq = (bus->devfreq->profile->freq_table[0] / 1000); min_freq = (bus->devfreq->profile->freq_table[0] / 1000);
max_freq = (bus->devfreq->profile->freq_table[max_state - 1] / 1000); max_freq = (bus->devfreq->profile->freq_table[max_state - 1] / 1000);
......
This diff is collapsed.
...@@ -364,7 +364,8 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev) ...@@ -364,7 +364,8 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
if (res.a0) { if (res.a0) {
dev_err(dev, "Failed to set dram param: %ld\n", dev_err(dev, "Failed to set dram param: %ld\n",
res.a0); res.a0);
return -EINVAL; ret = -EINVAL;
goto err_edev;
} }
} }
} }
...@@ -372,8 +373,11 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev) ...@@ -372,8 +373,11 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
node = of_parse_phandle(np, "rockchip,pmu", 0); node = of_parse_phandle(np, "rockchip,pmu", 0);
if (node) { if (node) {
data->regmap_pmu = syscon_node_to_regmap(node); data->regmap_pmu = syscon_node_to_regmap(node);
if (IS_ERR(data->regmap_pmu)) of_node_put(node);
return PTR_ERR(data->regmap_pmu); if (IS_ERR(data->regmap_pmu)) {
ret = PTR_ERR(data->regmap_pmu);
goto err_edev;
}
} }
regmap_read(data->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val); regmap_read(data->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val);
...@@ -391,7 +395,8 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev) ...@@ -391,7 +395,8 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
data->odt_dis_freq = data->timing.lpddr4_odt_dis_freq; data->odt_dis_freq = data->timing.lpddr4_odt_dis_freq;
break; break;
default: default:
return -EINVAL; ret = -EINVAL;
goto err_edev;
}; };
arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0, arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0,
...@@ -425,7 +430,8 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev) ...@@ -425,7 +430,8 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
*/ */
if (dev_pm_opp_of_add_table(dev)) { if (dev_pm_opp_of_add_table(dev)) {
dev_err(dev, "Invalid operating-points in device tree.\n"); dev_err(dev, "Invalid operating-points in device tree.\n");
return -EINVAL; ret = -EINVAL;
goto err_edev;
} }
of_property_read_u32(np, "upthreshold", of_property_read_u32(np, "upthreshold",
...@@ -465,6 +471,9 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev) ...@@ -465,6 +471,9 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
err_free_opp: err_free_opp:
dev_pm_opp_of_remove_table(&pdev->dev); dev_pm_opp_of_remove_table(&pdev->dev);
err_edev:
devfreq_event_disable_edev(data->edev);
return ret; return ret;
} }
......
...@@ -107,6 +107,20 @@ struct devfreq_dev_profile { ...@@ -107,6 +107,20 @@ struct devfreq_dev_profile {
unsigned int max_state; unsigned int max_state;
}; };
/**
* struct devfreq_stats - Statistics of devfreq device behavior
* @total_trans: Number of devfreq transitions.
* @trans_table: Statistics of devfreq transitions.
* @time_in_state: Statistics of devfreq states.
* @last_update: The last time stats were updated.
*/
struct devfreq_stats {
unsigned int total_trans;
unsigned int *trans_table;
u64 *time_in_state;
u64 last_update;
};
/** /**
* struct devfreq - Device devfreq structure * struct devfreq - Device devfreq structure
* @node: list node - contains the devices with devfreq that have been * @node: list node - contains the devices with devfreq that have been
...@@ -122,6 +136,7 @@ struct devfreq_dev_profile { ...@@ -122,6 +136,7 @@ struct devfreq_dev_profile {
* devfreq.nb to the corresponding register notifier call chain. * devfreq.nb to the corresponding register notifier call chain.
* @work: delayed work for load monitoring. * @work: delayed work for load monitoring.
* @previous_freq: previously configured frequency value. * @previous_freq: previously configured frequency value.
* @last_status: devfreq user device info, performance statistics
* @data: Private data of the governor. The devfreq framework does not * @data: Private data of the governor. The devfreq framework does not
* touch this. * touch this.
* @user_min_freq_req: PM QoS minimum frequency request from user (via sysfs) * @user_min_freq_req: PM QoS minimum frequency request from user (via sysfs)
...@@ -132,15 +147,12 @@ struct devfreq_dev_profile { ...@@ -132,15 +147,12 @@ struct devfreq_dev_profile {
* @suspend_freq: frequency of a device set during suspend phase. * @suspend_freq: frequency of a device set during suspend phase.
* @resume_freq: frequency of a device set in resume phase. * @resume_freq: frequency of a device set in resume phase.
* @suspend_count: suspend requests counter for a device. * @suspend_count: suspend requests counter for a device.
* @total_trans: Number of devfreq transitions * @stats: Statistics of devfreq device behavior
* @trans_table: Statistics of devfreq transitions
* @time_in_state: Statistics of devfreq states
* @last_stat_updated: The last time stat updated
* @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
* @nb_min: Notifier block for DEV_PM_QOS_MIN_FREQUENCY * @nb_min: Notifier block for DEV_PM_QOS_MIN_FREQUENCY
* @nb_max: Notifier block for DEV_PM_QOS_MAX_FREQUENCY * @nb_max: Notifier block for DEV_PM_QOS_MAX_FREQUENCY
* *
* This structure stores the devfreq information for a give device. * This structure stores the devfreq information for a given device.
* *
* Note that when a governor accesses entries in struct devfreq in its * Note that when a governor accesses entries in struct devfreq in its
* functions except for the context of callbacks defined in struct * functions except for the context of callbacks defined in struct
...@@ -174,11 +186,8 @@ struct devfreq { ...@@ -174,11 +186,8 @@ struct devfreq {
unsigned long resume_freq; unsigned long resume_freq;
atomic_t suspend_count; atomic_t suspend_count;
/* information for device frequency transition */ /* information for device frequency transitions */
unsigned int total_trans; struct devfreq_stats stats;
unsigned int *trans_table;
unsigned long *time_in_state;
unsigned long last_stat_updated;
struct srcu_notifier_head transition_notifier_list; struct srcu_notifier_head transition_notifier_list;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment