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

Commit d8b46e28 authored by Saravana Kannan's avatar Saravana Kannan
Browse files

PM / devfreq: bw_hwmon: Move IRQ handling to device specific drivers



The bandwidth 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 bandwidth
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 bandwidth has exceeded the previously set limit
instead of waiting for the periodic update.

Change-Id: I8bfd85d0cb59a1fd0116000aac430680e483b422
Signed-off-by: default avatarSaravana Kannan <skannan@codeaurora.org>
parent dfc6b80d
Loading
Loading
Loading
Loading
+38 −43
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ struct hwmon_node {
	unsigned long prev_ab;
	unsigned long *dev_ab;
	ktime_t prev_ts;
	bool mon_started;
	struct list_head list;
	void *orig_data;
	struct bw_hwmon *hw;
@@ -140,19 +141,45 @@ static void compute_bw(struct hwmon_node *node, int mbps,
	*freq = (new_bw * 100) / node->io_percent;
}

static struct hwmon_node *find_hwmon_node(struct devfreq *df)
{
	struct hwmon_node *node, *found = NULL;

	mutex_lock(&list_lock);
	list_for_each_entry(node, &hwmon_list, list)
		if (node->hw->dev == df->dev.parent ||
		    node->hw->of_node == df->dev.parent->of_node ||
		    node->gov == df->governor) {
			found = node;
			break;
		}
	mutex_unlock(&list_lock);

	return found;
}

#define TOO_SOON_US	(1 * USEC_PER_MSEC)
static irqreturn_t mon_intr_handler(int irq, void *dev)
int update_bw_hwmon(struct bw_hwmon *hwmon)
{
	struct hwmon_node *node = dev;
	struct devfreq *df = node->hw->df;
	struct devfreq *df;
	struct hwmon_node *node;
	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 = find_hwmon_node(df);
	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);

	/*
@@ -172,30 +199,13 @@ static irqreturn_t mon_intr_handler(int irq, void *dev)
		ret = update_devfreq(df);
		if (ret)
			dev_err(df->dev.parent,
				"Unable to update freq on IRQ!\n");
				"Unable to update freq on request!\n");
		mutex_unlock(&df->lock);
	}

	devfreq_monitor_start(df);

	return IRQ_HANDLED;
}

static struct hwmon_node *find_hwmon_node(struct devfreq *df)
{
	struct hwmon_node *node, *found = NULL;

	mutex_lock(&list_lock);
	list_for_each_entry(node, &hwmon_list, list)
		if (node->hw->dev == df->dev.parent ||
		    node->hw->of_node == df->dev.parent->of_node ||
		    node->gov == df->governor) {
			found = node;
			break;
		}
	mutex_unlock(&list_lock);

	return found;
	return 0;
}

static int start_monitoring(struct devfreq *df)
@@ -236,15 +246,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,
				  "bw_hwmon", node);
	if (ret) {
		dev_err(dev, "Unable to register interrupt handler!\n");
		goto err_req_irq;
	}
	node->mon_started = true;

	ret = sysfs_create_group(&df->dev.kobj, node->attr_grp);
	if (ret)
@@ -253,11 +255,7 @@ static int start_monitoring(struct devfreq *df)
	return 0;

err_sysfs:
	if (hw->irq) {
		disable_irq(hw->irq);
		free_irq(hw->irq, node);
	}
err_req_irq:
	node->mon_started = false;
	devfreq_monitor_stop(df);
	hw->stop_hwmon(hw);
err_start:
@@ -274,10 +272,7 @@ static void stop_monitoring(struct devfreq *df)
	struct bw_hwmon *hw = node->hw;

	sysfs_remove_group(&df->dev.kobj, node->attr_grp);
	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;
+5 −2
Original line number Diff line number Diff line
@@ -47,10 +47,8 @@
struct bw_hwmon {
	int (*start_hwmon)(struct bw_hwmon *hw, unsigned long mbps);
	void (*stop_hwmon)(struct bw_hwmon *hw);
	bool (*is_valid_irq)(struct bw_hwmon *hw);
	unsigned long (*meas_bw_and_set_irq)(struct bw_hwmon *hw,
					unsigned int tol, unsigned int us);
	int irq;
	struct device *dev;
	struct device_node *of_node;
	struct devfreq_governor *gov;
@@ -60,12 +58,17 @@ 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);
#else
static inline int register_bw_hwmon(struct device *dev,
					struct bw_hwmon *hwmon)
{
	return 0;
}
int update_bw_hwmon(struct bw_hwmon *hwmon)
{
	return 0;
}
#endif

#endif /* _GOVERNOR_BW_HWMON_H */
+23 −7
Original line number Diff line number Diff line
@@ -135,6 +135,7 @@ static long mon_get_count(int n, u32 start_val)
static u32 bytes_per_beat;
static u32 prev_r_start_val;
static u32 prev_w_start_val;
static int bw_irq;

static void mon_bw_init(void)
{
@@ -200,14 +201,28 @@ static unsigned long meas_bw_and_set_irq(struct bw_hwmon *hw,
	return r_mbps + w_mbps;
}

static bool is_valid_bw_irq(struct bw_hwmon *hw)
static irqreturn_t bwmon_intr_handler(int irq, void *dev)
{
	return mon_overflow(RD_MON) || mon_overflow(WR_MON);
	if (mon_overflow(RD_MON) || mon_overflow(WR_MON)) {
		update_bw_hwmon(dev);
		return IRQ_HANDLED;
	}

	return IRQ_NONE;
}

static int start_bw_hwmon(struct bw_hwmon *hw, unsigned long mbps)
{
	u32 limit;
	int ret;

	ret = request_threaded_irq(bw_irq, NULL, bwmon_intr_handler,
				  IRQF_ONESHOT | IRQF_SHARED,
				  "bw_hwmon", hw);
	if (ret) {
		pr_err("Unable to register interrupt handler!\n");
		return ret;
	}

	mon_bw_init();
	mon_disable(RD_MON);
@@ -229,6 +244,8 @@ static int start_bw_hwmon(struct bw_hwmon *hw, unsigned long mbps)

static void stop_bw_hwmon(struct bw_hwmon *hw)
{
	disable_irq(bw_irq);
	free_irq(bw_irq, hw);
	global_mon_enable(false);
	mon_disable(RD_MON);
	mon_disable(WR_MON);
@@ -243,7 +260,6 @@ static struct devfreq_governor devfreq_gov_cpubw_hwmon = {
static struct bw_hwmon cpubw_hwmon = {
	.start_hwmon = &start_bw_hwmon,
	.stop_hwmon = &stop_bw_hwmon,
	.is_valid_irq = &is_valid_bw_irq,
	.meas_bw_and_set_irq = &meas_bw_and_set_irq,
	.gov = &devfreq_gov_cpubw_hwmon,
};
@@ -372,12 +388,12 @@ static int krait_l2pm_driver_probe(struct platform_device *pdev)
	struct device *dev = &pdev->dev;
	int ret, ret2;

	cpubw_hwmon.irq = platform_get_irq(pdev, 0);
	if (cpubw_hwmon.irq < 0) {
	bw_irq = platform_get_irq(pdev, 0);
	if (bw_irq < 0) {
		pr_err("Unable to get IRQ number\n");
		return cpubw_hwmon.irq;
		return bw_irq;
	}
	mrps_hwmon.irq = cpubw_hwmon.irq;
	mrps_hwmon.irq = bw_irq;

	ret = of_property_read_u32(dev->of_node, "qcom,bytes-per-beat",
					&bytes_per_beat);