Loading Documentation/devicetree/bindings/devfreq/bimc-bwmon.txt +2 −1 Original line number Diff line number Diff line Loading @@ -5,7 +5,8 @@ can be used to measure the bandwidth of read/write traffic from the BIMC master ports. For example, the CPU subsystem sits on one BIMC master port. Required properties: - compatible: Must be "qcom,bimc-bwmon", "qcom,bimc-bwmon2" - compatible: Must be "qcom,bimc-bwmon", "qcom,bimc-bwmon2" or "qcom,bimc-bwmon3" - reg: Pairs of physical base addresses and region sizes of memory mapped registers. - reg-names: Names of the bases for the above registers. Expected Loading arch/arm/boot/dts/qcom/msm8996.dtsi +1 −1 Original line number Diff line number Diff line Loading @@ -456,7 +456,7 @@ }; qcom,cpu-bwmon { compatible = "qcom,bimc-bwmon2"; compatible = "qcom,bimc-bwmon3"; reg = <0x00408000 0x300>, <0x00401000 0x200>; reg-names = "base", "global_base"; interrupts = <0 183 4>; Loading drivers/devfreq/bimc-bwmon.c +36 −4 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ struct bwmon_spec { bool wrap_on_thres; bool overflow; bool throt_adj; }; struct bwmon { Loading @@ -53,19 +54,24 @@ struct bwmon { const struct bwmon_spec *spec; struct device *dev; struct bw_hwmon hw; u32 throttle_adj; }; #define to_bwmon(ptr) container_of(ptr, struct bwmon, hw) #define ENABLE_MASK BIT(0) #define THROTTLE_MASK 0x1F #define THROTTLE_SHIFT 16 static DEFINE_SPINLOCK(glb_lock); static void mon_enable(struct bwmon *m) { writel_relaxed(0x1, MON_EN(m)); writel_relaxed((ENABLE_MASK | m->throttle_adj), MON_EN(m)); } static void mon_disable(struct bwmon *m) { writel_relaxed(0x0, MON_EN(m)); writel_relaxed(m->throttle_adj, MON_EN(m)); /* * mon_disable() and mon_irq_clear(), * If latter goes first and count happen to trigger irq, we would Loading Loading @@ -145,6 +151,26 @@ static void mon_irq_clear(struct bwmon *m) mb(); } static int mon_set_throttle_adj(struct bw_hwmon *hw, uint adj) { struct bwmon *m = to_bwmon(hw); if (adj > THROTTLE_MASK) return -EINVAL; adj = (adj & THROTTLE_MASK) << THROTTLE_SHIFT; m->throttle_adj = adj; return 0; } static u32 mon_get_throttle_adj(struct bw_hwmon *hw) { struct bwmon *m = to_bwmon(hw); return m->throttle_adj >> THROTTLE_SHIFT; } static void mon_set_limit(struct bwmon *m, u32 count) { writel_relaxed(count, MON_THRES(m)); Loading Loading @@ -324,13 +350,15 @@ static int resume_bw_hwmon(struct bw_hwmon *hw) /*************************************************************************/ static const struct bwmon_spec spec[] = { { .wrap_on_thres = true, .overflow = false }, { .wrap_on_thres = false, .overflow = true }, { .wrap_on_thres = true, .overflow = false, .throt_adj = false}, { .wrap_on_thres = false, .overflow = true, .throt_adj = false}, { .wrap_on_thres = false, .overflow = true, .throt_adj = true}, }; static struct of_device_id match_table[] = { { .compatible = "qcom,bimc-bwmon", .data = &spec[0] }, { .compatible = "qcom,bimc-bwmon2", .data = &spec[1] }, { .compatible = "qcom,bimc-bwmon3", .data = &spec[2] }, {} }; Loading Loading @@ -399,6 +427,10 @@ static int bimc_bwmon_driver_probe(struct platform_device *pdev) m->hw.resume_hwmon = &resume_bw_hwmon; m->hw.get_bytes_and_clear = &get_bytes_and_clear; m->hw.set_thres = &set_thres; if (m->spec->throt_adj) { m->hw.set_throttle_adj = &mon_set_throttle_adj; m->hw.get_throttle_adj = &mon_get_throttle_adj; } ret = register_bw_hwmon(dev, &m->hw); if (ret) { Loading drivers/devfreq/governor_bw_hwmon.c +42 −0 Original line number Diff line number Diff line Loading @@ -673,6 +673,47 @@ static int devfreq_bw_hwmon_get_freq(struct devfreq *df, return 0; } static ssize_t store_throttle_adj(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct devfreq *df = to_devfreq(dev); struct hwmon_node *node = df->data; int ret; unsigned int val; if (!node->hw->set_throttle_adj) return -ENOSYS; ret = kstrtouint(buf, 10, &val); if (ret) return ret; ret = node->hw->set_throttle_adj(node->hw, val); if (!ret) return count; else return ret; } static ssize_t show_throttle_adj(struct device *dev, struct device_attribute *attr, char *buf) { struct devfreq *df = to_devfreq(dev); struct hwmon_node *node = df->data; unsigned int val; if (!node->hw->get_throttle_adj) val = 0; else val = node->hw->get_throttle_adj(node->hw); return snprintf(buf, PAGE_SIZE, "%u\n", val); } static DEVICE_ATTR(throttle_adj, 0644, show_throttle_adj, store_throttle_adj); gov_attr(guard_band_mbps, 0U, 2000U); gov_attr(decay_rate, 0U, 100U); gov_attr(io_percent, 1U, 100U); Loading Loading @@ -709,6 +750,7 @@ static struct attribute *dev_attr[] = { &dev_attr_low_power_io_percent.attr, &dev_attr_low_power_delay.attr, &dev_attr_mbps_zones.attr, &dev_attr_throttle_adj.attr, NULL, }; Loading drivers/devfreq/governor_bw_hwmon.h +4 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ * @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. * @set_throttle_adj: Set throttle adjust field to the given value * @get_throttle_adj: Get the value written to throttle adjust field * @dev: Pointer to device that this HW monitor can * monitor. * @of_node: OF node of device that this HW monitor can Loading @@ -47,6 +49,8 @@ struct bw_hwmon { int (*resume_hwmon)(struct bw_hwmon *hw); unsigned long (*set_thres)(struct bw_hwmon *hw, unsigned long bytes); unsigned long (*get_bytes_and_clear)(struct bw_hwmon *hw); int (*set_throttle_adj)(struct bw_hwmon *hw, uint adj); u32 (*get_throttle_adj)(struct bw_hwmon *hw); struct device *dev; struct device_node *of_node; struct devfreq_governor *gov; Loading Loading
Documentation/devicetree/bindings/devfreq/bimc-bwmon.txt +2 −1 Original line number Diff line number Diff line Loading @@ -5,7 +5,8 @@ can be used to measure the bandwidth of read/write traffic from the BIMC master ports. For example, the CPU subsystem sits on one BIMC master port. Required properties: - compatible: Must be "qcom,bimc-bwmon", "qcom,bimc-bwmon2" - compatible: Must be "qcom,bimc-bwmon", "qcom,bimc-bwmon2" or "qcom,bimc-bwmon3" - reg: Pairs of physical base addresses and region sizes of memory mapped registers. - reg-names: Names of the bases for the above registers. Expected Loading
arch/arm/boot/dts/qcom/msm8996.dtsi +1 −1 Original line number Diff line number Diff line Loading @@ -456,7 +456,7 @@ }; qcom,cpu-bwmon { compatible = "qcom,bimc-bwmon2"; compatible = "qcom,bimc-bwmon3"; reg = <0x00408000 0x300>, <0x00401000 0x200>; reg-names = "base", "global_base"; interrupts = <0 183 4>; Loading
drivers/devfreq/bimc-bwmon.c +36 −4 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ struct bwmon_spec { bool wrap_on_thres; bool overflow; bool throt_adj; }; struct bwmon { Loading @@ -53,19 +54,24 @@ struct bwmon { const struct bwmon_spec *spec; struct device *dev; struct bw_hwmon hw; u32 throttle_adj; }; #define to_bwmon(ptr) container_of(ptr, struct bwmon, hw) #define ENABLE_MASK BIT(0) #define THROTTLE_MASK 0x1F #define THROTTLE_SHIFT 16 static DEFINE_SPINLOCK(glb_lock); static void mon_enable(struct bwmon *m) { writel_relaxed(0x1, MON_EN(m)); writel_relaxed((ENABLE_MASK | m->throttle_adj), MON_EN(m)); } static void mon_disable(struct bwmon *m) { writel_relaxed(0x0, MON_EN(m)); writel_relaxed(m->throttle_adj, MON_EN(m)); /* * mon_disable() and mon_irq_clear(), * If latter goes first and count happen to trigger irq, we would Loading Loading @@ -145,6 +151,26 @@ static void mon_irq_clear(struct bwmon *m) mb(); } static int mon_set_throttle_adj(struct bw_hwmon *hw, uint adj) { struct bwmon *m = to_bwmon(hw); if (adj > THROTTLE_MASK) return -EINVAL; adj = (adj & THROTTLE_MASK) << THROTTLE_SHIFT; m->throttle_adj = adj; return 0; } static u32 mon_get_throttle_adj(struct bw_hwmon *hw) { struct bwmon *m = to_bwmon(hw); return m->throttle_adj >> THROTTLE_SHIFT; } static void mon_set_limit(struct bwmon *m, u32 count) { writel_relaxed(count, MON_THRES(m)); Loading Loading @@ -324,13 +350,15 @@ static int resume_bw_hwmon(struct bw_hwmon *hw) /*************************************************************************/ static const struct bwmon_spec spec[] = { { .wrap_on_thres = true, .overflow = false }, { .wrap_on_thres = false, .overflow = true }, { .wrap_on_thres = true, .overflow = false, .throt_adj = false}, { .wrap_on_thres = false, .overflow = true, .throt_adj = false}, { .wrap_on_thres = false, .overflow = true, .throt_adj = true}, }; static struct of_device_id match_table[] = { { .compatible = "qcom,bimc-bwmon", .data = &spec[0] }, { .compatible = "qcom,bimc-bwmon2", .data = &spec[1] }, { .compatible = "qcom,bimc-bwmon3", .data = &spec[2] }, {} }; Loading Loading @@ -399,6 +427,10 @@ static int bimc_bwmon_driver_probe(struct platform_device *pdev) m->hw.resume_hwmon = &resume_bw_hwmon; m->hw.get_bytes_and_clear = &get_bytes_and_clear; m->hw.set_thres = &set_thres; if (m->spec->throt_adj) { m->hw.set_throttle_adj = &mon_set_throttle_adj; m->hw.get_throttle_adj = &mon_get_throttle_adj; } ret = register_bw_hwmon(dev, &m->hw); if (ret) { Loading
drivers/devfreq/governor_bw_hwmon.c +42 −0 Original line number Diff line number Diff line Loading @@ -673,6 +673,47 @@ static int devfreq_bw_hwmon_get_freq(struct devfreq *df, return 0; } static ssize_t store_throttle_adj(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct devfreq *df = to_devfreq(dev); struct hwmon_node *node = df->data; int ret; unsigned int val; if (!node->hw->set_throttle_adj) return -ENOSYS; ret = kstrtouint(buf, 10, &val); if (ret) return ret; ret = node->hw->set_throttle_adj(node->hw, val); if (!ret) return count; else return ret; } static ssize_t show_throttle_adj(struct device *dev, struct device_attribute *attr, char *buf) { struct devfreq *df = to_devfreq(dev); struct hwmon_node *node = df->data; unsigned int val; if (!node->hw->get_throttle_adj) val = 0; else val = node->hw->get_throttle_adj(node->hw); return snprintf(buf, PAGE_SIZE, "%u\n", val); } static DEVICE_ATTR(throttle_adj, 0644, show_throttle_adj, store_throttle_adj); gov_attr(guard_band_mbps, 0U, 2000U); gov_attr(decay_rate, 0U, 100U); gov_attr(io_percent, 1U, 100U); Loading Loading @@ -709,6 +750,7 @@ static struct attribute *dev_attr[] = { &dev_attr_low_power_io_percent.attr, &dev_attr_low_power_delay.attr, &dev_attr_mbps_zones.attr, &dev_attr_throttle_adj.attr, NULL, }; Loading
drivers/devfreq/governor_bw_hwmon.h +4 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ * @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. * @set_throttle_adj: Set throttle adjust field to the given value * @get_throttle_adj: Get the value written to throttle adjust field * @dev: Pointer to device that this HW monitor can * monitor. * @of_node: OF node of device that this HW monitor can Loading @@ -47,6 +49,8 @@ struct bw_hwmon { int (*resume_hwmon)(struct bw_hwmon *hw); unsigned long (*set_thres)(struct bw_hwmon *hw, unsigned long bytes); unsigned long (*get_bytes_and_clear)(struct bw_hwmon *hw); int (*set_throttle_adj)(struct bw_hwmon *hw, uint adj); u32 (*get_throttle_adj)(struct bw_hwmon *hw); struct device *dev; struct device_node *of_node; struct devfreq_governor *gov; Loading