Skip to content

Commit

Permalink
Merge tag 'devfreq-next-for-5.5' of git://git.kernel.org/pub/scm/linu…
Browse files Browse the repository at this point in the history
…x/kernel/git/chanwoo/linux

Pull devfreq updates for v5.5 from Chanwoo Choi:

"1. Update devfreq core

 - Check NULL governor in available_governors_show sysfs in order to prevent
   showing wrong governor information.

 - Fix race condition between devfreq_update_status() and trans_stat_show()

 - Add new 'interrupt-driven' flag for devfreq goveroris. Each devfreq driver can
   add their own interrupt-driven governor (NIVIDIA Tegra30 ACTMON governor). It
   needs to use the following sysfs interface to get the new polling interval in
   order to change the NVIDIA Tegra30 hardware's polling interval.

   : /sys/class/devfreq/devfreqX/polling_interval

   So, if 'interrupt-driven' flag of devfreq governor is 1, the devfreq governor
   is able to use the 'polling_interval' sysfs interface to get the new polling
   interval value. But, the devfreq core doesn't schedule out the polling work
   for this governor like NVIDIA Tegra30 ACTMON governor.

 2. Update devfreq drivers

 - For exynos-bus.c, remove unused property from dt-binding documentation

 - For tegra30-devfreq.c, update the internal behavior like fixing the overflow
   integer issue and clean-up code.

 3. Update devfreq-event driver

 - For exynos-ppmu.c, add exynos_ppmu.h dt-binding file for 'event-data-type' filed.
   and update dt-binging documentation. Also,  Fix minor coding style."

* tag 'devfreq-next-for-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux: (25 commits)
  PM / devfreq: tegra30: Tune up MCCPU boost-down coefficient
  PM / devfreq: tegra30: Support variable polling interval
  PM / devfreq: Add new interrupt_driven flag for governors
  PM / devfreq: tegra30: Use kHz units for dependency threshold
  PM / devfreq: tegra30: Disable consecutive interrupts when appropriate
  PM / devfreq: tegra30: Don't enable already enabled consecutive interrupts
  PM / devfreq: tegra30: Include appropriate header
  PM / devfreq: tegra30: Constify structs
  PM / devfreq: tegra30: Don't enable consecutive-down interrupt on startup
  PM / devfreq: tegra30: Reset boosting on startup
  PM / devfreq: tegra30: Move clk-notifier's registration to governor's start
  PM / devfreq: tegra30: Use CPUFreq notifier
  PM / devfreq: tegra30: Use kHz units uniformly in the code
  PM / devfreq: tegra30: Fix integer overflow on CPU's freq max out
  PM / devfreq: tegra30: Drop write-barrier
  PM / devfreq: tegra30: Handle possible round-rate error
  PM / devfreq: tegra30: Keep interrupt disabled while governor is stopped
  PM / devfreq: tegra30: Change irq type to unsigned int
  PM / devfreq: exynos-ppmu: remove useless assignment
  PM / devfreq: Lock devfreq in trans_stat_show
  ...
  • Loading branch information
Rafael J. Wysocki committed Nov 7, 2019
2 parents c389ec6 + fee2285 commit 2b32842
Show file tree
Hide file tree
Showing 8 changed files with 386 additions and 122 deletions.
26 changes: 24 additions & 2 deletions Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,23 @@ The Exynos PPMU driver uses the devfreq-event class to provide event data
to various devfreq devices. The devfreq devices would use the event data when
derterming the current state of each IP.

Required properties:
Required properties for PPMU device:
- compatible: Should be "samsung,exynos-ppmu" or "samsung,exynos-ppmu-v2.
- reg: physical base address of each PPMU and length of memory mapped region.

Optional properties:
Optional properties for PPMU device:
- clock-names : the name of clock used by the PPMU, "ppmu"
- clocks : phandles for clock specified in "clock-names" property

Required properties for 'events' child node of PPMU device:
- event-name : the unique event name among PPMU device
Optional properties for 'events' child node of PPMU device:
- event-data-type : Define the type of data which shell be counted
by the counter. You can check include/dt-bindings/pmu/exynos_ppmu.h for
all possible type, i.e. count read requests, count write data in bytes,
etc. This field is optional and when it is missing, the driver code
will use default data type.

Example1 : PPMUv1 nodes in exynos3250.dtsi are listed below.

ppmu_dmc0: ppmu_dmc0@106a0000 {
Expand Down Expand Up @@ -145,3 +154,16 @@ Example3 : PPMUv2 nodes in exynos5433.dtsi are listed below.
reg = <0x104d0000 0x2000>;
status = "disabled";
};

Example4 : 'event-data-type' in exynos4412-ppmu-common.dtsi are listed below.

&ppmu_dmc0 {
status = "okay";
events {
ppmu_dmc0_3: ppmu-event3-dmc0 {
event-name = "ppmu-event3-dmc0";
event-data-type = <(PPMU_RO_DATA_CNT |
PPMU_WO_DATA_CNT)>;
};
};
};
2 changes: 0 additions & 2 deletions Documentation/devicetree/bindings/devfreq/exynos-bus.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ Required properties only for passive bus device:
Optional properties only for parent bus device:
- exynos,saturation-ratio: the percentage value which is used to calibrate
the performance count against total cycle count.
- exynos,voltage-tolerance: the percentage value for bus voltage tolerance
which is used to calculate the max voltage.

Detailed correlation between sub-blocks and power line according to Exynos SoC:
- In case of Exynos3250, there are two power line as following:
Expand Down
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -4778,6 +4778,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
S: Supported
F: drivers/devfreq/event/
F: drivers/devfreq/devfreq-event.c
F: include/dt-bindings/pmu/exynos_ppmu.h
F: include/linux/devfreq-event.h
F: Documentation/devicetree/bindings/devfreq/event/

Expand Down
33 changes: 28 additions & 5 deletions drivers/devfreq/devfreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
int lev, prev_lev, ret = 0;
unsigned long cur_time;

lockdep_assert_held(&devfreq->lock);
cur_time = jiffies;

/* Immediately exit if previous_freq is not initialized yet. */
Expand Down Expand Up @@ -409,6 +410,9 @@ static void devfreq_monitor(struct work_struct *work)
*/
void devfreq_monitor_start(struct devfreq *devfreq)
{
if (devfreq->governor->interrupt_driven)
return;

INIT_DEFERRABLE_WORK(&devfreq->work, devfreq_monitor);
if (devfreq->profile->polling_ms)
queue_delayed_work(devfreq_wq, &devfreq->work,
Expand All @@ -426,6 +430,9 @@ EXPORT_SYMBOL(devfreq_monitor_start);
*/
void devfreq_monitor_stop(struct devfreq *devfreq)
{
if (devfreq->governor->interrupt_driven)
return;

cancel_delayed_work_sync(&devfreq->work);
}
EXPORT_SYMBOL(devfreq_monitor_stop);
Expand Down Expand Up @@ -453,6 +460,10 @@ void devfreq_monitor_suspend(struct devfreq *devfreq)
devfreq_update_status(devfreq, devfreq->previous_freq);
devfreq->stop_polling = true;
mutex_unlock(&devfreq->lock);

if (devfreq->governor->interrupt_driven)
return;

cancel_delayed_work_sync(&devfreq->work);
}
EXPORT_SYMBOL(devfreq_monitor_suspend);
Expand All @@ -473,11 +484,15 @@ void devfreq_monitor_resume(struct devfreq *devfreq)
if (!devfreq->stop_polling)
goto out;

if (devfreq->governor->interrupt_driven)
goto out_update;

if (!delayed_work_pending(&devfreq->work) &&
devfreq->profile->polling_ms)
queue_delayed_work(devfreq_wq, &devfreq->work,
msecs_to_jiffies(devfreq->profile->polling_ms));

out_update:
devfreq->last_stat_updated = jiffies;
devfreq->stop_polling = false;

Expand Down Expand Up @@ -509,6 +524,9 @@ void devfreq_interval_update(struct devfreq *devfreq, unsigned int *delay)
if (devfreq->stop_polling)
goto out;

if (devfreq->governor->interrupt_driven)
goto out;

/* if new delay is zero, stop polling */
if (!new_delay) {
mutex_unlock(&devfreq->lock);
Expand Down Expand Up @@ -625,7 +643,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
devfreq = find_device_devfreq(dev);
mutex_unlock(&devfreq_list_lock);
if (!IS_ERR(devfreq)) {
dev_err(dev, "%s: Unable to create devfreq for the device.\n",
dev_err(dev, "%s: devfreq device already exists!\n",
__func__);
err = -EINVAL;
goto err_out;
Expand Down Expand Up @@ -1195,7 +1213,7 @@ static ssize_t available_governors_show(struct device *d,
* The devfreq with immutable governor (e.g., passive) shows
* only own governor.
*/
if (df->governor->immutable) {
if (df->governor && df->governor->immutable) {
count = scnprintf(&buf[count], DEVFREQ_NAME_LEN,
"%s ", df->governor_name);
/*
Expand Down Expand Up @@ -1397,12 +1415,17 @@ static ssize_t trans_stat_show(struct device *dev,
int i, j;
unsigned int max_state = devfreq->profile->max_state;

if (!devfreq->stop_polling &&
devfreq_update_status(devfreq, devfreq->previous_freq))
return 0;
if (max_state == 0)
return sprintf(buf, "Not Supported.\n");

mutex_lock(&devfreq->lock);
if (!devfreq->stop_polling &&
devfreq_update_status(devfreq, devfreq->previous_freq)) {
mutex_unlock(&devfreq->lock);
return 0;
}
mutex_unlock(&devfreq->lock);

len = sprintf(buf, " From : To\n");
len += sprintf(buf + len, " :");
for (i = 0; i < max_state; i++)
Expand Down
1 change: 0 additions & 1 deletion drivers/devfreq/event/exynos-ppmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,6 @@ static int exynos_ppmu_probe(struct platform_device *pdev)
for (i = 0; i < info->num_events; i++) {
edev[i] = devm_devfreq_event_add_edev(&pdev->dev, &desc[i]);
if (IS_ERR(edev[i])) {
ret = PTR_ERR(edev[i]);
dev_err(&pdev->dev,
"failed to add devfreq-event device\n");
return PTR_ERR(edev[i]);
Expand Down
3 changes: 3 additions & 0 deletions drivers/devfreq/governor.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
* @name: Governor's name
* @immutable: Immutable flag for governor. If the value is 1,
* this govenror is never changeable to other governor.
* @interrupt_driven: Devfreq core won't schedule polling work for this
* governor if value is set to 1.
* @get_target_freq: Returns desired operating frequency for the device.
* Basically, get_target_freq will run
* devfreq_dev_profile.get_dev_status() to get the
Expand All @@ -49,6 +51,7 @@ struct devfreq_governor {

const char name[DEVFREQ_NAME_LEN];
const unsigned int immutable;
const unsigned int interrupt_driven;
int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
int (*event_handler)(struct devfreq *devfreq,
unsigned int event, void *data);
Expand Down
Loading

0 comments on commit 2b32842

Please sign in to comment.