PM / devfreq: Add new interrupt_driven flag for governors
authorDmitry Osipenko <digetx@gmail.com>
Mon, 4 Nov 2019 21:56:14 +0000 (00:56 +0300)
committerChanwoo Choi <cw00.choi@samsung.com>
Wed, 6 Nov 2019 03:04:01 +0000 (12:04 +0900)
Currently interrupt-driven governors (like NVIDIA Tegra30 ACTMON governor)
are used to set polling_ms=0 in order to avoid periodic polling of device
status by devfreq core. This means that polling interval can't be changed
by userspace for such governors.

The new governor flag allows interrupt-driven governors to convey that
devfreq core shouldn't perform polling of device status and thus generic
devfreq polling interval could be supported by these governors now.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
drivers/devfreq/devfreq.c
drivers/devfreq/governor.h

index d6c3dce..f840e61 100644 (file)
@@ -410,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,
@@ -427,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);
@@ -454,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);
@@ -474,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;
 
@@ -510,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);
index bbe5ff9..dc7533c 100644 (file)
@@ -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
@@ -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);