PM / devfreq: bw_hwmon: Add support for specifying count factor

Not all bandwidth monitors count in units of 1MB. Add a DT
property that indicates the number of bytes the monitor counts in
so we can properly scale the count we read from the hardware to
reflect the traffic. By default, we will assume 1MB units if the
property doesn't exist.

Change-Id: I1b581b2fffda04ba151df6e87221628368ff5b17
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
This commit is contained in:
Stephen Boyd 2017-04-06 17:49:16 -07:00 committed by Jonathan Avila
parent 40c5693a21
commit f6615037dc
2 changed files with 30 additions and 11 deletions

View File

@ -23,6 +23,7 @@ Required properties:
Optional properties:
- qcom,byte-mid-match: Byte count MID match value
- qcom,byte-mid-mask: Byte count MID mask value
- qcom,count-unit: Number of bytes monitor counts in
Example:
qcom,cpu-bwmon {
@ -35,4 +36,5 @@ Example:
qcom,hw-timer-hz = <19200000>;
qcom,byte-mid-match = <0x1e00>;
qcom,byte-mid-mask = <0x1e00>;
qcom,count-unit = <0x100000>;
};

View File

@ -26,6 +26,8 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/spinlock.h>
#include <linux/log2.h>
#include <linux/sizes.h>
#include "governor_bw_hwmon.h"
#define GLB_INT_STATUS(m) ((m)->global_base + 0x100)
@ -104,6 +106,8 @@ struct bwmon {
u32 throttle_adj;
u32 sample_size_ms;
u32 intr_status;
u8 count_shift;
u32 thres_lim;
u32 byte_mask;
u32 byte_match;
};
@ -418,11 +422,18 @@ static u32 calc_zone_counts(struct bw_hwmon *hw)
return zone_counts;
}
static unsigned int mbps_to_mb(unsigned long mbps, unsigned int ms)
#define MB_SHIFT 20
static u32 mbps_to_count(unsigned long mbps, unsigned int ms, u8 shift)
{
mbps *= ms;
mbps = DIV_ROUND_UP(mbps, MSEC_PER_SEC);
return mbps;
if (shift > MB_SHIFT)
mbps >>= shift - MB_SHIFT;
else
mbps <<= MB_SHIFT - shift;
return DIV_ROUND_UP(mbps, MSEC_PER_SEC);
}
/*
@ -430,9 +441,10 @@ static unsigned int mbps_to_mb(unsigned long mbps, unsigned int ms)
* Zone 0: byte count < THRES_LO
* Zone 1: THRES_LO < byte count < THRES_MED
* Zone 2: THRES_MED < byte count < THRES_HI
* Zone 3: byte count > THRES_HI
* Zone 3: THRES_LIM > byte count > THRES_HI
*/
#define THRES_LIM 0x7FFU
#define THRES_LIM(shift) (0xFFFFFFFF >> shift)
static __always_inline
void set_zone_thres(struct bwmon *m, unsigned int sample_ms,
enum mon_reg_type type)
@ -441,14 +453,14 @@ void set_zone_thres(struct bwmon *m, unsigned int sample_ms,
u32 hi, med, lo;
u32 zone_cnt_thres = calc_zone_counts(hw);
hi = mbps_to_mb(hw->up_wake_mbps, sample_ms);
med = mbps_to_mb(hw->down_wake_mbps, sample_ms);
hi = mbps_to_count(hw->up_wake_mbps, sample_ms, m->count_shift);
med = mbps_to_count(hw->down_wake_mbps, sample_ms, m->count_shift);
lo = 0;
if (unlikely((hi > THRES_LIM) || (med > hi) || (lo > med))) {
if (unlikely((hi > m->thres_lim) || (med > hi) || (lo > med))) {
pr_warn("Zone thres larger than hw limit: hi:%u med:%u lo:%u\n",
hi, med, lo);
hi = min(hi, THRES_LIM);
hi = min(hi, m->thres_lim);
med = min(med, hi - 1);
lo = min(lo, med-1);
}
@ -580,7 +592,7 @@ unsigned long mon_get_zone_stats(struct bwmon *m, enum mon_reg_type type)
zone = get_zone(m, type);
count = get_zone_count(m, zone, type);
count *= SZ_1M;
count <<= m->count_shift;
dev_dbg(m->dev, "Zone%d Max byte count: %08lx\n", zone, count);
@ -992,7 +1004,7 @@ static int bimc_bwmon_driver_probe(struct platform_device *pdev)
struct resource *res;
struct bwmon *m;
int ret;
u32 data;
u32 data, count_unit;
m = devm_kzalloc(dev, sizeof(*m), GFP_KERNEL);
if (!m)
@ -1057,6 +1069,11 @@ static int bimc_bwmon_driver_probe(struct platform_device *pdev)
}
}
if (of_property_read_u32(dev->of_node, "qcom,count-unit", &count_unit))
count_unit = SZ_1M;
m->count_shift = order_base_2(count_unit);
m->thres_lim = THRES_LIM(m->count_shift);
switch (m->spec->reg_type) {
case MON3:
m->hw.start_hwmon = start_bw_hwmon3;