From 939d572b127c7cd0c7102f05c3beecd575fa5236 Mon Sep 17 00:00:00 2001 From: Junjie Wu Date: Wed, 16 Jan 2019 18:30:32 -0800 Subject: [PATCH] PM / devfreq: cache_hwmon: Move IRQ handling to device drivers The cache monitoring devices might have more than one IRQ to handle or might have notifications from other drivers instead of using actual IRQs. So, refactor the governor to move the IRQ handling to the cache monitoring device specific drivers and just provide an API that can be used to request a re-evaluation. The device specific driver can call this API to request an immediate re-evaluation whenever the cache request has exceeded the previously set limit instead of waiting for the periodic update. Change-Id: Ib2e9f53f95749d659f440739a1b074b5a0d94fd8 Signed-off-by: Junjie Wu [avajid@codeaurora.org: made minor styling changes] Signed-off-by: Amir Vajid --- drivers/devfreq/governor_cache_hwmon.c | 47 +++++++++++--------------- drivers/devfreq/governor_cache_hwmon.h | 10 +++--- 2 files changed, 25 insertions(+), 32 deletions(-) diff --git a/drivers/devfreq/governor_cache_hwmon.c b/drivers/devfreq/governor_cache_hwmon.c index 53fe8f4a75bf..e670ee9e7548 100644 --- a/drivers/devfreq/governor_cache_hwmon.c +++ b/drivers/devfreq/governor_cache_hwmon.c @@ -34,6 +34,7 @@ struct cache_hwmon_node { unsigned int decay_rate; unsigned long prev_mhz; ktime_t prev_ts; + bool mon_started; struct list_head list; void *orig_data; struct cache_hwmon *hw; @@ -154,18 +155,26 @@ static void compute_cache_freq(struct cache_hwmon_node *node, } #define TOO_SOON_US (1 * USEC_PER_MSEC) -static irqreturn_t mon_intr_handler(int irq, void *dev) +int update_cache_hwmon(struct cache_hwmon *hwmon) { - struct cache_hwmon_node *node = dev; - struct devfreq *df = node->hw->df; + struct cache_hwmon_node *node; + struct devfreq *df; ktime_t ts; unsigned int us; int ret; - if (!node->hw->is_valid_irq(node->hw)) - return IRQ_NONE; + if (!hwmon) + return -EINVAL; + df = hwmon->df; + if (!df) + return -ENODEV; + node = df->data; + if (!node) + return -ENODEV; + if (!node->mon_started) + return -EBUSY; - dev_dbg(df->dev.parent, "Got interrupt\n"); + dev_dbg(df->dev.parent, "Got update request\n"); devfreq_monitor_stop(df); /* @@ -187,13 +196,13 @@ static irqreturn_t mon_intr_handler(int irq, void *dev) ret = update_devfreq(df); if (ret < 0) dev_err(df->dev.parent, - "Unable to update freq on IRQ! (%d)\n", ret); + "Unable to update freq on req! (%d)\n", ret); mutex_unlock(&df->lock); } devfreq_monitor_start(df); - return IRQ_HANDLED; + return 0; } static int devfreq_cache_hwmon_get_freq(struct devfreq *df, @@ -282,16 +291,7 @@ static int start_monitoring(struct devfreq *df) } devfreq_monitor_start(df); - - if (hw->irq) - ret = request_threaded_irq(hw->irq, NULL, mon_intr_handler, - IRQF_ONESHOT | IRQF_SHARED, - "cache_hwmon", node); - if (ret < 0) { - dev_err(dev, "Unable to register interrupt handler! (%d)\n", - ret); - goto req_irq_fail; - } + node->mon_started = true; ret = sysfs_create_group(&df->dev.kobj, &dev_attr_group); if (ret < 0) { @@ -302,11 +302,7 @@ static int start_monitoring(struct devfreq *df) return 0; sysfs_fail: - if (hw->irq) { - disable_irq(hw->irq); - free_irq(hw->irq, node); - } -req_irq_fail: + node->mon_started = false; devfreq_monitor_stop(df); hw->stop_hwmon(hw); err_start: @@ -322,10 +318,7 @@ static void stop_monitoring(struct devfreq *df) struct cache_hwmon *hw = node->hw; sysfs_remove_group(&df->dev.kobj, &dev_attr_group); - if (hw->irq) { - disable_irq(hw->irq); - free_irq(hw->irq, node); - } + node->mon_started = false; devfreq_monitor_stop(df); hw->stop_hwmon(hw); df->data = node->orig_data; diff --git a/drivers/devfreq/governor_cache_hwmon.h b/drivers/devfreq/governor_cache_hwmon.h index 8c492c58ee41..f78a1d7cd028 100644 --- a/drivers/devfreq/governor_cache_hwmon.h +++ b/drivers/devfreq/governor_cache_hwmon.h @@ -20,12 +20,9 @@ struct mrps_stats { * struct cache_hwmon - devfreq Cache HW monitor info * @start_hwmon: Start the HW monitoring * @stop_hwmon: Stop the HW monitoring - * @is_valid_irq: Check whether the IRQ was triggered by the counter - * used to monitor cache activity. * @meas_mrps_and_set_irq: Return the measured count and set up the * IRQ to fire if usage exceeds current * measurement by @tol percent. - * @irq: IRQ number that corresponds to this HW monitor. * @dev: device that this HW monitor can monitor. * @of_node: OF node of device that this HW monitor can monitor. * @df: Devfreq node that this HW montior is being used @@ -36,11 +33,9 @@ struct cache_hwmon { int (*start_hwmon)(struct cache_hwmon *hw, struct mrps_stats *mrps); void (*stop_hwmon)(struct cache_hwmon *hw); - bool (*is_valid_irq)(struct cache_hwmon *hw); unsigned long (*meas_mrps_and_set_irq)(struct cache_hwmon *hw, unsigned int tol, unsigned int us, struct mrps_stats *mrps); - int irq; struct device *dev; struct device_node *of_node; struct devfreq *df; @@ -48,12 +43,17 @@ struct cache_hwmon { #ifdef CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON int register_cache_hwmon(struct device *dev, struct cache_hwmon *hwmon); +int update_cache_hwmon(struct cache_hwmon *hwmon); #else static inline int register_cache_hwmon(struct device *dev, struct cache_hwmon *hwmon) { return 0; } +int update_cache_hwmon(struct cache_hwmon *hwmon) +{ + return 0; +} #endif #endif /* _GOVERNOR_CACHE_HWMON_H */