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

Commit 78281d48 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "power: bcl: Add hotplug mitigation support"

parents 6695a73d 304d0338
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);