summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/devfreq/bimc-bwmon.c82
-rw-r--r--drivers/devfreq/governor_bw_hwmon.c419
-rw-r--r--drivers/devfreq/governor_bw_hwmon.h23
3 files changed, 414 insertions, 110 deletions
diff --git a/drivers/devfreq/bimc-bwmon.c b/drivers/devfreq/bimc-bwmon.c
index 3a85ae90b846..268aed2d9f10 100644
--- a/drivers/devfreq/bimc-bwmon.c
+++ b/drivers/devfreq/bimc-bwmon.c
@@ -40,13 +40,6 @@
#define MON_MASK(m) ((m)->base + 0x298)
#define MON_MATCH(m) ((m)->base + 0x29C)
-/*
- * Don't set the threshold lower than this value. This helps avoid
- * threshold IRQs when the traffic is close to zero and even small
- * changes can exceed the threshold percentage.
- */
-#define FLOOR_MBPS 100UL
-
struct bwmon_spec {
bool wrap_on_thres;
bool overflow;
@@ -171,14 +164,6 @@ static unsigned long mon_get_count(struct bwmon *m)
/* ********** CPUBW specific code ********** */
/* Returns MBps of read/writes for the sampling window. */
-static unsigned int bytes_to_mbps(long long bytes, unsigned int us)
-{
- bytes *= USEC_PER_SEC;
- do_div(bytes, us);
- bytes = DIV_ROUND_UP_ULL(bytes, SZ_1M);
- return bytes;
-}
-
static unsigned int mbps_to_bytes(unsigned long mbps, unsigned int ms,
unsigned int tolerance_percent)
{
@@ -189,48 +174,61 @@ static unsigned int mbps_to_bytes(unsigned long mbps, unsigned int ms,
return mbps;
}
-static unsigned long meas_bw_and_set_irq(struct bw_hwmon *hw,
- unsigned int tol, unsigned int us)
+static unsigned long get_bytes_and_clear(struct bw_hwmon *hw)
{
- unsigned long mbps;
- u32 limit;
- unsigned int sample_ms = hw->df->profile->polling_ms;
struct bwmon *m = to_bwmon(hw);
+ unsigned long count;
mon_disable(m);
+ count = mon_get_count(m);
+ mon_clear(m);
+ mon_irq_clear(m);
+ mon_enable(m);
- mbps = mon_get_count(m);
- mbps = bytes_to_mbps(mbps, us);
+ return count;
+}
+
+static unsigned long set_thres(struct bw_hwmon *hw, unsigned long bytes)
+{
+ unsigned long count;
+ u32 limit;
+ struct bwmon *m = to_bwmon(hw);
+
+ mon_disable(m);
+ count = mon_get_count(m);
+ mon_clear(m);
+ mon_irq_clear(m);
- /*
- * If the counter wraps on thres, don't set the thres too low.
- * Setting it too low runs the risk of the counter wrapping around
- * multiple times before the IRQ is processed.
- */
if (likely(!m->spec->wrap_on_thres))
- limit = mbps_to_bytes(max(mbps, FLOOR_MBPS), sample_ms, tol);
+ limit = bytes;
else
- limit = mbps_to_bytes(max(mbps, 400UL), sample_ms, tol);
+ limit = max(bytes, 500000UL);
mon_set_limit(m, limit);
-
- mon_clear(m);
- mon_irq_clear(m);
mon_enable(m);
- dev_dbg(m->dev, "MBps = %lu\n", mbps);
- return mbps;
+ return count;
}
static irqreturn_t bwmon_intr_handler(int irq, void *dev)
{
struct bwmon *m = dev;
- if (mon_irq_status(m)) {
- update_bw_hwmon(&m->hw);
- return IRQ_HANDLED;
- }
- return IRQ_NONE;
+ if (!mon_irq_status(m))
+ return IRQ_NONE;
+
+ if (bw_hwmon_sample_end(&m->hw) > 0)
+ return IRQ_WAKE_THREAD;
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bwmon_intr_thread(int irq, void *dev)
+{
+ struct bwmon *m = dev;
+
+ update_bw_hwmon(&m->hw);
+ return IRQ_HANDLED;
}
static int start_bw_hwmon(struct bw_hwmon *hw, unsigned long mbps)
@@ -239,7 +237,8 @@ static int start_bw_hwmon(struct bw_hwmon *hw, unsigned long mbps)
u32 limit;
int ret;
- ret = request_threaded_irq(m->irq, NULL, bwmon_intr_handler,
+ ret = request_threaded_irq(m->irq, bwmon_intr_handler,
+ bwmon_intr_thread,
IRQF_ONESHOT | IRQF_SHARED,
dev_name(m->dev), m);
if (ret) {
@@ -380,7 +379,8 @@ static int bimc_bwmon_driver_probe(struct platform_device *pdev)
m->hw.stop_hwmon = &stop_bw_hwmon;
m->hw.suspend_hwmon = &suspend_bw_hwmon;
m->hw.resume_hwmon = &resume_bw_hwmon;
- m->hw.meas_bw_and_set_irq = &meas_bw_and_set_irq;
+ m->hw.get_bytes_and_clear = &get_bytes_and_clear;
+ m->hw.set_thres = &set_thres;
ret = register_bw_hwmon(dev, &m->hw);
if (ret) {
diff --git a/drivers/devfreq/governor_bw_hwmon.c b/drivers/devfreq/governor_bw_hwmon.c
index 761defa151dd..d532edae7291 100644
--- a/drivers/devfreq/governor_bw_hwmon.c
+++ b/drivers/devfreq/governor_bw_hwmon.c
@@ -25,6 +25,7 @@
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/interrupt.h>
+#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/devfreq.h>
@@ -32,17 +33,47 @@
#include "governor.h"
#include "governor_bw_hwmon.h"
+#define NUM_MBPS_ZONES 10
struct hwmon_node {
unsigned int tolerance_percent;
unsigned int guard_band_mbps;
unsigned int decay_rate;
unsigned int io_percent;
unsigned int bw_step;
+ unsigned int sample_ms;
+ unsigned int up_scale;
+ unsigned int up_thres;
+ unsigned int down_thres;
+ unsigned int down_count;
+ unsigned int hist_memory;
+ unsigned int hyst_trigger_count;
+ unsigned int hyst_length;
+ unsigned int idle_mbps;
+ unsigned int low_power_ceil_mbps;
+ unsigned int low_power_io_percent;
+ unsigned int low_power_delay;
+ unsigned int mbps_zones[NUM_MBPS_ZONES];
+
unsigned long prev_ab;
unsigned long *dev_ab;
unsigned long resume_freq;
unsigned long resume_ab;
+ unsigned long bytes;
+ unsigned long max_mbps;
+ unsigned long hist_max_mbps;
+ unsigned long hist_mem;
+ unsigned long hyst_peak;
+ unsigned long hyst_mbps;
+ unsigned long hyst_trig_win;
+ unsigned long hyst_en;
+ unsigned long above_low_power;
+ unsigned long prev_req;
+ unsigned long up_wake_mbps;
+ unsigned long down_wake_mbps;
+ unsigned int wake;
+ unsigned int down_cnt;
ktime_t prev_ts;
+ ktime_t hist_max_ts;
bool mon_started;
struct list_head list;
void *orig_data;
@@ -51,6 +82,10 @@ struct hwmon_node {
struct attribute_group *attr_grp;
};
+#define UP_WAKE 1
+#define DOWN_WAKE 2
+static DEFINE_SPINLOCK(irq_lock);
+
static LIST_HEAD(hwmon_list);
static DEFINE_MUTEX(list_lock);
@@ -89,55 +124,301 @@ show_attr(__attr) \
store_attr(__attr, min, max) \
static DEVICE_ATTR(__attr, 0644, show_##__attr, store_##__attr)
+#define show_list_attr(name, n) \
+static ssize_t show_list_##name(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct devfreq *df = to_devfreq(dev); \
+ struct hwmon_node *hw = df->data; \
+ unsigned int i, cnt = 0; \
+ \
+ for (i = 0; i < n && hw->name[i]; i++) \
+ cnt += snprintf(buf + cnt, PAGE_SIZE, "%u ", hw->name[i]);\
+ cnt += snprintf(buf + cnt, PAGE_SIZE, "\n"); \
+ return cnt; \
+}
+
+#define store_list_attr(name, n, _min, _max) \
+static ssize_t store_list_##name(struct device *dev, \
+ struct device_attribute *attr, const char *buf, \
+ size_t count) \
+{ \
+ struct devfreq *df = to_devfreq(dev); \
+ struct hwmon_node *hw = df->data; \
+ int ret; \
+ unsigned int i = 0, val; \
+ \
+ do { \
+ ret = sscanf(buf, "%u", &val); \
+ if (ret != 1) \
+ break; \
+ buf = strnchr(buf, PAGE_SIZE, ' '); \
+ if (buf) \
+ buf++; \
+ val = max(val, _min); \
+ val = min(val, _max); \
+ hw->name[i] = val; \
+ i++; \
+ } while (buf && i < n - 1); \
+ if (i < 1) \
+ return -EINVAL; \
+ hw->name[i] = 0; \
+ return count; \
+}
+
+#define gov_list_attr(__attr, n, min, max) \
+show_list_attr(__attr, n) \
+store_list_attr(__attr, n, min, max) \
+static DEVICE_ATTR(__attr, 0644, show_list_##__attr, store_list_##__attr)
+
#define MIN_MS 10U
#define MAX_MS 500U
-static unsigned long measure_bw_and_set_irq(struct hwmon_node *node)
+/* Returns MBps of read/writes for the sampling window. */
+static unsigned int bytes_to_mbps(long long bytes, unsigned int us)
+{
+ bytes *= USEC_PER_SEC;
+ do_div(bytes, us);
+ bytes = DIV_ROUND_UP_ULL(bytes, SZ_1M);
+ return bytes;
+}
+
+static unsigned int mbps_to_bytes(unsigned long mbps, unsigned int ms,
+ unsigned int tolerance_percent)
{
+ mbps *= (100 + tolerance_percent) * ms;
+ mbps /= 100;
+ mbps = DIV_ROUND_UP(mbps, MSEC_PER_SEC);
+ mbps *= SZ_1M;
+ return mbps;
+}
+
+int bw_hwmon_sample_end(struct bw_hwmon *hwmon)
+{
+ struct devfreq *df;
+ struct hwmon_node *node;
ktime_t ts;
+ unsigned long bytes, mbps, flags;
unsigned int us;
- unsigned long mbps;
- struct bw_hwmon *hw = node->hw;
+ int wake = 0;
- /*
- * Since we are stopping the counters, we don't want this short work
- * to be interrupted by other tasks and cause the measurements to be
- * wrong. Not blocking interrupts to avoid affecting interrupt
- * latency and since they should be short anyway because they run in
- * atomic context.
- */
- preempt_disable();
+ df = hwmon->df;
+ node = df->data;
+ spin_lock_irqsave(&irq_lock, flags);
ts = ktime_get();
us = ktime_to_us(ktime_sub(ts, node->prev_ts));
- if (!us)
- us = 1;
- mbps = hw->meas_bw_and_set_irq(hw, node->tolerance_percent, us);
- node->prev_ts = ts;
+ bytes = hwmon->get_bytes_and_clear(hwmon);
+ bytes += node->bytes;
+ node->bytes = 0;
- preempt_enable();
+ mbps = bytes_to_mbps(bytes, us);
+ node->max_mbps = max(node->max_mbps, mbps);
- dev_dbg(hw->df->dev.parent, "BW MBps = %6lu, period = %u\n", mbps, us);
- trace_bw_hwmon_meas(dev_name(hw->df->dev.parent),
+ /*
+ * If the measured bandwidth in a micro sample is greater than the
+ * wake up threshold, it indicates an increase in load that's non
+ * trivial. So, have the governor ignore historical idle time or low
+ * bandwidth usage and do the bandwidth calculation based on just
+ * this micro sample.
+ */
+ if (mbps > node->up_wake_mbps)
+ wake = UP_WAKE;
+ else if (mbps < node->down_wake_mbps) {
+ node->down_cnt--;
+ if (node->down_cnt <= 0)
+ wake = DOWN_WAKE;
+ }
+
+ node->prev_ts = ts;
+ node->wake = wake;
+ spin_unlock_irqrestore(&irq_lock, flags);
+
+ trace_bw_hwmon_meas(dev_name(df->dev.parent),
mbps,
us,
- 0);
+ wake);
- return mbps;
+ dev_dbg(df->dev.parent, "MB/s: %5lu, us:%6d, wake: %d\n",
+ mbps, us, wake);
+
+ return wake;
+}
+
+unsigned long to_mbps_zone(struct hwmon_node *node, unsigned long mbps)
+{
+ int i;
+
+ for (i = 0; i < NUM_MBPS_ZONES && node->mbps_zones[i]; i++)
+ if (node->mbps_zones[i] >= mbps)
+ return node->mbps_zones[i];
+
+ return node->hw->df->max_freq;
}
-static void compute_bw(struct hwmon_node *node, int mbps,
- unsigned long *freq, unsigned long *ab)
+#define MIN_MBPS 500UL
+#define HIST_PEAK_TOL 60
+static unsigned long get_bw_and_set_irq(struct hwmon_node *node,
+ unsigned long *freq, unsigned long *ab)
{
- int new_bw;
+ unsigned long meas_mbps, thres, flags, req_mbps, adj_mbps;
+ unsigned long meas_mbps_zone;
+ unsigned long hist_lo_tol, hyst_lo_tol;
+ struct bw_hwmon *hw = node->hw;
+ unsigned int new_bw, io_percent;
+
+ spin_lock_irqsave(&irq_lock, flags);
+
+ req_mbps = meas_mbps = node->max_mbps;
+ node->max_mbps = 0;
+
+ hist_lo_tol = (node->hist_max_mbps * HIST_PEAK_TOL) / 100;
+ /* Remember historic peak in the past hist_mem decision windows. */
+ if (meas_mbps > node->hist_max_mbps || !node->hist_mem) {
+ /* If new max or no history */
+ node->hist_max_mbps = meas_mbps;
+ node->hist_mem = node->hist_memory;
+ } else if (meas_mbps >= hist_lo_tol) {
+ /*
+ * If subsequent peaks come close (within tolerance) to but
+ * less than the historic peak, then reset the history start,
+ * but not the peak value.
+ */
+ node->hist_mem = node->hist_memory;
+ } else {
+ /* Count down history expiration. */
+ if (node->hist_mem)
+ node->hist_mem--;
+ }
+
+ /* Keep track of whether we are in low power mode consistently. */
+ if (meas_mbps > node->low_power_ceil_mbps)
+ node->above_low_power = node->low_power_delay;
+ if (node->above_low_power)
+ node->above_low_power--;
+
+ if (node->above_low_power)
+ io_percent = node->io_percent;
+ else
+ io_percent = node->low_power_io_percent;
- mbps += node->guard_band_mbps;
+ /*
+ * The AB value that corresponds to the lowest mbps zone greater than
+ * or equal to the "frequency" the current measurement will pick.
+ * This upper limit is useful for balancing out any prediction
+ * mechanisms to be power friendly.
+ */
+ meas_mbps_zone = (meas_mbps * 100) / io_percent;
+ meas_mbps_zone = to_mbps_zone(node, meas_mbps_zone);
+ meas_mbps_zone = (meas_mbps_zone * io_percent) / 100;
- if (mbps > node->prev_ab) {
- new_bw = mbps;
+ /*
+ * If this is a wake up due to BW increase, vote much higher BW than
+ * what we measure to stay ahead of increasing traffic and then set
+ * it up to vote for measured BW if we see down_count short sample
+ * windows of low traffic.
+ */
+ if (node->wake == UP_WAKE) {
+ req_mbps += ((meas_mbps - node->prev_req)
+ * node->up_scale) / 100;
+ /*
+ * Don't drop below max_mbps which caused the UP_WAKE if
+ * down_thres is enabled. This is functionally equivalent of
+ * two adjacent decision windows overlapping by one short
+ * sample window when an UP_WAKE happens.
+ */
+ node->max_mbps = meas_mbps;
+ node->down_cnt = node->down_count;
+
+ /*
+ * However if the measured load is less than the historic
+ * peak, but the over request is higher than the historic
+ * peak, then we could limit the over requesting to the
+ * historic peak.
+ */
+ if (req_mbps > node->hist_max_mbps
+ && meas_mbps < node->hist_max_mbps)
+ req_mbps = node->hist_max_mbps;
+
+ req_mbps = min(req_mbps, meas_mbps_zone);
} else {
- new_bw = mbps * node->decay_rate
+ /*
+ * We want to quickly drop the vote only if we are
+ * over-voting (UP_WAKE). So, effectively disable it for all
+ * other cases by setting it to a very large value.
+ */
+ node->down_cnt = INT_MAX;
+ }
+
+ hyst_lo_tol = (node->hyst_mbps * HIST_PEAK_TOL) / 100;
+ if (meas_mbps > node->hyst_mbps && meas_mbps > MIN_MBPS) {
+ hyst_lo_tol = (meas_mbps * HIST_PEAK_TOL) / 100;
+ node->hyst_peak = 0;
+ node->hyst_trig_win = node->hyst_length;
+ node->hyst_mbps = meas_mbps;
+ }
+
+ /*
+ * Check node->max_mbps to avoid double counting peaks that cause
+ * early termination of a window.
+ */
+ if (meas_mbps >= hyst_lo_tol && meas_mbps > MIN_MBPS
+ && !node->max_mbps) {
+ node->hyst_peak++;
+ if (node->hyst_peak >= node->hyst_trigger_count
+ || node->hyst_en)
+ node->hyst_en = node->hyst_length;
+ }
+
+ if (node->hyst_trig_win)
+ node->hyst_trig_win--;
+ if (node->hyst_en)
+ node->hyst_en--;
+
+ if (!node->hyst_trig_win && !node->hyst_en) {
+ node->hyst_peak = 0;
+ node->hyst_mbps = 0;
+ }
+
+ if (node->hyst_en) {
+ if (meas_mbps > node->idle_mbps)
+ req_mbps = max(req_mbps, node->hyst_mbps);
+ }
+
+ /* Stretch the short sample window size, if the traffic is too low */
+ if (meas_mbps < MIN_MBPS) {
+ node->up_wake_mbps = (max(MIN_MBPS, req_mbps)
+ * (100 + node->up_thres)) / 100;
+ node->down_wake_mbps = 0;
+ thres = mbps_to_bytes(max(MIN_MBPS, req_mbps / 2),
+ node->sample_ms, 0);
+ } else {
+ /*
+ * Up wake vs down wake are intentionally a percentage of
+ * req_mbps vs meas_mbps to make sure the over requesting
+ * phase is handled properly. We only want to wake up and
+ * reduce the vote based on the measured mbps being less than
+ * the previous measurement that caused the "over request".
+ */
+ node->up_wake_mbps = (req_mbps * (100 + node->up_thres)) / 100;
+ node->down_wake_mbps = (meas_mbps * node->down_thres) / 100;
+ thres = mbps_to_bytes(meas_mbps, node->sample_ms, 0);
+ }
+
+ node->bytes = hw->set_thres(hw, thres);
+
+ node->wake = 0;
+ node->prev_req = req_mbps;
+
+ spin_unlock_irqrestore(&irq_lock, flags);
+
+ adj_mbps = req_mbps + node->guard_band_mbps;
+
+ if (adj_mbps > node->prev_ab) {
+ new_bw = adj_mbps;
+ } else {
+ new_bw = adj_mbps * node->decay_rate
+ node->prev_ab * (100 - node->decay_rate);
new_bw /= 100;
}
@@ -145,12 +426,14 @@ static void compute_bw(struct hwmon_node *node, int mbps,
node->prev_ab = new_bw;
if (ab)
*ab = roundup(new_bw, node->bw_step);
- *freq = (new_bw * 100) / node->io_percent;
+
+ *freq = (new_bw * 100) / io_percent;
trace_bw_hwmon_update(dev_name(node->hw->df->dev.parent),
new_bw,
*freq,
- 0,
- 0);
+ node->up_wake_mbps,
+ node->down_wake_mbps);
+ return req_mbps;
}
static struct hwmon_node *find_hwmon_node(struct devfreq *df)
@@ -171,13 +454,10 @@ static struct hwmon_node *find_hwmon_node(struct devfreq *df)
return found;
}
-#define TOO_SOON_US (1 * USEC_PER_MSEC)
int update_bw_hwmon(struct bw_hwmon *hwmon)
{
struct devfreq *df;
struct hwmon_node *node;
- ktime_t ts;
- unsigned int us;
int ret;
if (!hwmon)
@@ -185,7 +465,7 @@ int update_bw_hwmon(struct bw_hwmon *hwmon)
df = hwmon->df;
if (!df)
return -ENODEV;
- node = find_hwmon_node(df);
+ node = df->data;
if (!node)
return -ENODEV;
@@ -195,26 +475,12 @@ int update_bw_hwmon(struct bw_hwmon *hwmon)
dev_dbg(df->dev.parent, "Got update request\n");
devfreq_monitor_stop(df);
- /*
- * Don't recalc bandwidth if the interrupt comes right after a
- * previous bandwidth calculation. This is done for two reasons:
- *
- * 1. Sampling the BW during a very short duration can result in a
- * very inaccurate measurement due to very short bursts.
- * 2. This can only happen if the limit was hit very close to the end
- * of the previous sample period. Which means the current BW
- * estimate is not very off and doesn't need to be readjusted.
- */
- ts = ktime_get();
- us = ktime_to_us(ktime_sub(ts, node->prev_ts));
- if (us > TOO_SOON_US) {
- mutex_lock(&df->lock);
- ret = update_devfreq(df);
- if (ret)
- dev_err(df->dev.parent,
- "Unable to update freq on request!\n");
- mutex_unlock(&df->lock);
- }
+ mutex_lock(&df->lock);
+ ret = update_devfreq(df);
+ if (ret)
+ dev_err(df->dev.parent,
+ "Unable to update freq on request!\n");
+ mutex_unlock(&df->lock);
devfreq_monitor_start(df);
@@ -392,7 +658,6 @@ static int devfreq_bw_hwmon_get_freq(struct devfreq *df,
unsigned long *freq,
u32 *flag)
{
- unsigned long mbps;
struct hwmon_node *node = df->data;
/* Suspend/resume sequence */
@@ -402,8 +667,7 @@ static int devfreq_bw_hwmon_get_freq(struct devfreq *df,
return 0;
}
- mbps = measure_bw_and_set_irq(node);
- compute_bw(node, mbps, freq, node->dev_ab);
+ get_bw_and_set_irq(node, freq, node->dev_ab);
return 0;
}
@@ -413,6 +677,19 @@ gov_attr(guard_band_mbps, 0U, 2000U);
gov_attr(decay_rate, 0U, 100U);
gov_attr(io_percent, 1U, 100U);
gov_attr(bw_step, 50U, 1000U);
+gov_attr(sample_ms, 1U, 50U);
+gov_attr(up_scale, 100U, 500U);
+gov_attr(up_thres, 1U, 100U);
+gov_attr(down_thres, 0U, 90U);
+gov_attr(down_count, 0U, 90U);
+gov_attr(hist_memory, 0U, 90U);
+gov_attr(hyst_trigger_count, 0U, 90U);
+gov_attr(hyst_length, 0U, 90U);
+gov_attr(idle_mbps, 0U, 2000U);
+gov_attr(low_power_ceil_mbps, 0U, 2500U);
+gov_attr(low_power_io_percent, 1U, 100U);
+gov_attr(low_power_delay, 1U, 60U);
+gov_list_attr(mbps_zones, NUM_MBPS_ZONES, 0U, UINT_MAX);
static struct attribute *dev_attr[] = {
&dev_attr_tolerance_percent.attr,
@@ -420,6 +697,19 @@ static struct attribute *dev_attr[] = {
&dev_attr_decay_rate.attr,
&dev_attr_io_percent.attr,
&dev_attr_bw_step.attr,
+ &dev_attr_sample_ms.attr,
+ &dev_attr_up_scale.attr,
+ &dev_attr_up_thres.attr,
+ &dev_attr_down_thres.attr,
+ &dev_attr_down_count.attr,
+ &dev_attr_hist_memory.attr,
+ &dev_attr_hyst_trigger_count.attr,
+ &dev_attr_hyst_length.attr,
+ &dev_attr_idle_mbps.attr,
+ &dev_attr_low_power_ceil_mbps.attr,
+ &dev_attr_low_power_io_percent.attr,
+ &dev_attr_low_power_delay.attr,
+ &dev_attr_mbps_zones.attr,
NULL,
};
@@ -531,8 +821,21 @@ int register_bw_hwmon(struct device *dev, struct bw_hwmon *hwmon)
node->tolerance_percent = 10;
node->guard_band_mbps = 100;
node->decay_rate = 90;
- node->io_percent = 16;
+ node->io_percent = 34;
+ node->low_power_ceil_mbps = 0;
+ node->low_power_io_percent = 34;
+ node->low_power_delay = 20;
node->bw_step = 190;
+ node->sample_ms = 2;
+ node->up_scale = 250;
+ node->up_thres = 10;
+ node->down_thres = 0;
+ node->down_count = 3;
+ node->hist_memory = 20;
+ node->hyst_trigger_count = 3;
+ node->hyst_length = 10;
+ node->idle_mbps = 400;
+ node->mbps_zones[0] = 100000;
node->hw = hwmon;
mutex_lock(&list_lock);
diff --git a/drivers/devfreq/governor_bw_hwmon.h b/drivers/devfreq/governor_bw_hwmon.h
index 30de542444cb..8e60f9aeceb0 100644
--- a/drivers/devfreq/governor_bw_hwmon.h
+++ b/drivers/devfreq/governor_bw_hwmon.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015, 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
@@ -21,13 +21,9 @@
* struct bw_hwmon - dev BW HW monitor info
* @start_hwmon: Start the HW monitoring of the dev BW
* @stop_hwmon: Stop the HW monitoring of dev BW
- * @is_valid_irq: Check whether the IRQ was triggered by the
- * counters used to monitor dev BW.
- * @meas_bw_and_set_irq: Return the measured bandwidth and set up the
- * IRQ to fire if the usage exceeds current
- * measurement by @tol percent.
- * @irq: IRQ number that corresponds to this HW
- * monitor.
+ * @set_thres: Set the count threshold to generate an IRQ
+ * @get_bytes_and_clear: Get the bytes transferred since the last call
+ * and reset the counter to start over.
* @dev: Pointer to device that this HW monitor can
* monitor.
* @of_node: OF node of device that this HW monitor can
@@ -49,8 +45,8 @@ struct bw_hwmon {
void (*stop_hwmon)(struct bw_hwmon *hw);
int (*suspend_hwmon)(struct bw_hwmon *hw);
int (*resume_hwmon)(struct bw_hwmon *hw);
- unsigned long (*meas_bw_and_set_irq)(struct bw_hwmon *hw,
- unsigned int tol, unsigned int us);
+ unsigned long (*set_thres)(struct bw_hwmon *hw, unsigned long bytes);
+ unsigned long (*get_bytes_and_clear)(struct bw_hwmon *hw);
struct device *dev;
struct device_node *of_node;
struct devfreq_governor *gov;
@@ -61,13 +57,18 @@ struct bw_hwmon {
#ifdef CONFIG_DEVFREQ_GOV_MSM_BW_HWMON
int register_bw_hwmon(struct device *dev, struct bw_hwmon *hwmon);
int update_bw_hwmon(struct bw_hwmon *hwmon);
+int bw_hwmon_sample_end(struct bw_hwmon *hwmon);
#else
static inline int register_bw_hwmon(struct device *dev,
struct bw_hwmon *hwmon)
{
return 0;
}
-int update_bw_hwmon(struct bw_hwmon *hwmon)
+static inline int update_bw_hwmon(struct bw_hwmon *hwmon)
+{
+ return 0;
+}
+static inline int bw_hwmon_sample_end(struct bw_hwmon *hwmon)
{
return 0;
}