Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8fd39531 authored by Rama Aparna Mallavarapu's avatar Rama Aparna Mallavarapu
Browse files

PM / devfreq: bw_hwmon: Expose a throttle adjust tunable



Newer versions of bimc-bwmon counters have the capability to fake
higher byte count than what's actually transferred between a bus
master and DDR if the bus master is being throttled by QoS hardware
logic. Add support to set the throttle adjust field that comes with
this newer version of bimc-bwmon.

Change-Id: I33376c825fb11ab2e378f828b1d2ae46dd582836
Signed-off-by: default avatarRohit Gupta <rohgup@codeaurora.org>
[aparnam@codeaurora.org: Renamed throttle_adj functions]
Signed-off-by: default avatarRama Aparna Mallavarapu <aparnam@codeaurora.org>
parent 366b3c46
Loading
Loading
Loading
Loading
+36 −4
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
struct bwmon_spec {
	bool wrap_on_thres;
	bool overflow;
	bool throt_adj;
};

struct bwmon {
@@ -45,19 +46,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
@@ -139,6 +145,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));
@@ -318,13 +344,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 const struct of_device_id bimc_bwmon_match_table[] = {
	{ .compatible = "qcom,bimc-bwmon", .data = &spec[0] },
	{ .compatible = "qcom,bimc-bwmon2", .data = &spec[1] },
	{ .compatible = "qcom,bimc-bwmon3", .data = &spec[2] },
	{}
};

@@ -393,6 +421,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) {
+41 −0
Original line number Diff line number Diff line
@@ -651,6 +651,46 @@ static int devfreq_bw_hwmon_get_freq(struct devfreq *df,
	return 0;
}

static ssize_t throttle_adj_store(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 -EPERM;

	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 throttle_adj_show(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_RW(throttle_adj);

gov_attr(guard_band_mbps, 0U, 2000U);
gov_attr(decay_rate, 0U, 100U);
gov_attr(io_percent, 1U, 100U);
@@ -681,6 +721,7 @@ static struct attribute *dev_attr[] = {
	&dev_attr_hyst_length.attr,
	&dev_attr_idle_mbps.attr,
	&dev_attr_mbps_zones.attr,
	&dev_attr_throttle_adj.attr,
	NULL,
};

+4 −0
Original line number Diff line number Diff line
@@ -16,6 +16,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
@@ -39,6 +41,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;