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

Commit 304d0338 authored by Ram Chandrasekar's avatar Ram Chandrasekar
Browse files

power: bcl: Add hotplug mitigation support



Add Support for hotplugging the CPU's when BCL
thresholds are reached.

The default mask indicating the cores to hotplug
on BCL conditions is defined in device tree.
BCL module provides a sysfs node to input and
read the current hotplug mask.
/qcom,bcl.#/hotplug_mask
Here the bits 0-7 corresponds to cores 0-7
respectively. If the value of the bit is set to 1,
then the corresponding core will be hotplugged on
battery current limit condition.

BCL module also provides another sysfs node,
/qcom,bcl.#/hotplug_status
which shows the current cores hotplugged
because of BCL conditions.

Change-Id: I4cc8e1da6ed77fcf3e03c0b925e427d2fc94aeca
Signed-off-by: default avatarRam Chandrasekar <rkumbako@codeaurora.org>
parent 5b1408c2
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -42,6 +42,11 @@ Optional parameters:
		'vph-high-threshold-uv', 'vph-low-threshold-uv' and
		'thermal-handle' properties should be defined in the
		'qcom,ibat-monitor' node.
- qcom,bcl-hotplug-mask = <hotplug-mask>: Mask indicating the cores to hotplug,
		when battery current limit condition is reached. Here the bits
		0-7 corresponds to cores 0-7 respectively. If the value of the
		bit is set to 1, then the corresponding core will be
		hotplugged on battery current limit condition.

Optional nodes:
- qcom,ibat-monitor: This optional node defines all the parameters for the
@@ -107,6 +112,7 @@ For Using BCL peripheral interface:
	qcom,bcl {
		compatible = "qcom,bcl";
		qcom,bcl-framework-interface;
		qcom,bcl-hotplug-mask = <0xFO>;
		qcom,ibat-monitor {
			high-threshold-uamp = <1500>;
			low-threshold-uamp = <500>;
+115 −0
Original line number Diff line number Diff line
@@ -185,6 +185,85 @@ static struct bcl_context *gbcl;
static enum bcl_threshold_state bcl_vph_state = BCL_THRESHOLD_DISABLED,
		bcl_ibat_state = BCL_THRESHOLD_DISABLED;
static DEFINE_MUTEX(bcl_notify_mutex);
static uint32_t bcl_hotplug_request, bcl_hotplug_mask;
static struct work_struct bcl_hotplug_work;
static DEFINE_MUTEX(bcl_hotplug_mutex);
static bool bcl_hotplug_enabled;

#ifdef CONFIG_SMP
static void __ref bcl_handle_hotplug(struct work_struct *work)
{
	int ret = 0, _cpu = 0;
	uint32_t prev_hotplug_request = 0;

	mutex_lock(&bcl_hotplug_mutex);
	prev_hotplug_request = bcl_hotplug_request;

	if (bcl_vph_state == BCL_LOW_THRESHOLD
		&& bcl_ibat_state == BCL_HIGH_THRESHOLD)
		bcl_hotplug_request = bcl_hotplug_mask;
	else
		bcl_hotplug_request = 0;

	if (bcl_hotplug_request == prev_hotplug_request)
		goto handle_hotplug_exit;

	for_each_possible_cpu(_cpu) {
		if (!(bcl_hotplug_mask & BIT(_cpu)))
			continue;

		if (bcl_hotplug_request & BIT(_cpu)) {
			if (!cpu_online(_cpu))
				continue;
			ret = cpu_down(_cpu);
			if (ret)
				pr_err("Error %d offlining core %d\n",
					ret, _cpu);
			else
				pr_info("Set Offline CPU:%d\n", _cpu);
		} else {
			if (cpu_online(_cpu))
				continue;
			ret = cpu_up(_cpu);
			if (ret)
				pr_err("Error %d onlining core %d\n",
					ret, _cpu);
			else
				pr_info("Allow Online CPU:%d\n", _cpu);
		}
	}

handle_hotplug_exit:
	mutex_unlock(&bcl_hotplug_mutex);
	return;
}
#else
static void __ref bcl_handle_hotplug(struct work_struct *work)
{
	return;
}
#endif

static int __ref bcl_cpu_ctrl_callback(struct notifier_block *nfb,
	unsigned long action, void *hcpu)
{
	uint32_t cpu = (uintptr_t)hcpu;

	if (action == CPU_UP_PREPARE || action == CPU_UP_PREPARE_FROZEN) {
		if ((bcl_hotplug_mask & BIT(cpu))
			&& (bcl_hotplug_request & BIT(cpu))) {
			pr_info("preventing CPU%d from coming online\n", cpu);
			return NOTIFY_BAD;
		}
	}

	pr_info("voting for CPU%d to be online\n", cpu);
	return NOTIFY_OK;
}

static struct notifier_block __refdata bcl_cpu_notifier = {
	.notifier_call = bcl_cpu_ctrl_callback,
};

static int bcl_cpufreq_callback(struct notifier_block *nfb,
		unsigned long event, void *data)
@@ -339,12 +418,16 @@ static void bcl_iavail_work(struct work_struct *work)

static void bcl_ibat_notify(enum bcl_threshold_state thresh_type)
{
	if (bcl_hotplug_enabled)
		schedule_work(&bcl_hotplug_work);
	bcl_ibat_state = thresh_type;
	update_cpu_freq();
}

static void bcl_vph_notify(enum bcl_threshold_state thresh_type)
{
	if (bcl_hotplug_enabled)
		schedule_work(&bcl_hotplug_work);
	bcl_vph_state = thresh_type;
	update_cpu_freq();
}
@@ -737,6 +820,8 @@ show_bcl(vph_low, (gbcl->bcl_monitor_type == BCL_IBAT_MONITOR_TYPE) ?
show_bcl(freq_limit, gbcl->thermal_freq_limit, "%u\n")
show_bcl(vph_state, bcl_vph_state, "%d\n")
show_bcl(ibat_state, bcl_ibat_state, "%d\n")
show_bcl(hotplug_mask, bcl_hotplug_mask, "%d\n")
show_bcl(hotplug_status, bcl_hotplug_request, "%d\n")

static ssize_t
mode_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -1047,6 +1132,21 @@ static ssize_t vph_high_store(struct device *dev,
	return count;
}

static ssize_t hotplug_mask_store(struct device *dev,
					struct device_attribute *attr,
					const char *buf, size_t count)
{
	int ret = 0, val = 0;

	ret = convert_to_int(buf, &val);
	if (ret)
		return ret;

	bcl_hotplug_mask = val;

	return count;
}

/*
 * BCL device attributes
 */
@@ -1085,6 +1185,8 @@ static struct device_attribute btm_dev_attr[] = {
	__ATTR(vph_high_thresh_uv, 0644, vph_high_show, vph_high_store),
	__ATTR(vph_low_thresh_uv, 0644, vph_low_show, vph_low_store),
	__ATTR(thermal_freq_limit, 0444, freq_limit_show, NULL),
	__ATTR(hotplug_status, 0444, hotplug_status_show, NULL),
	__ATTR(hotplug_mask, 0644, hotplug_mask_show, hotplug_mask_store),
};

static int create_bcl_sysfs(struct bcl_context *bcl)
@@ -1476,6 +1578,16 @@ static int bcl_probe(struct platform_device *pdev)
			bcl_type[BCL_IAVAIL_MONITOR_TYPE]);
	bcl->bcl_poll_interval_msec = BCL_POLL_INTERVAL;

	ret = of_property_read_u32(pdev->dev.of_node,
			"qcom,bcl-hotplug-mask",
			&bcl_hotplug_mask);
	if (ret) {
		bcl_hotplug_enabled = false;
		ret = 0;
	} else {
		bcl_hotplug_enabled = true;
	}

	if (of_property_read_bool(pdev->dev.of_node,
		"qcom,bcl-framework-interface"))
		ret = probe_bcl_periph_prop(bcl);
@@ -1494,6 +1606,9 @@ static int bcl_probe(struct platform_device *pdev)
	gbcl = bcl;
	platform_set_drvdata(pdev, bcl);
	INIT_DEFERRABLE_WORK(&bcl->bcl_iavail_work, bcl_iavail_work);
	INIT_WORK(&bcl_hotplug_work, bcl_handle_hotplug);
	if (bcl_hotplug_enabled)
		register_cpu_notifier(&bcl_cpu_notifier);
	if (bcl_mode == BCL_DEVICE_ENABLED)
		bcl_mode_set(bcl_mode);