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

Commit 34c5f893 authored by Ram Chandrasekar's avatar Ram Chandrasekar Committed by Matt Wagantall
Browse files

msm: thermal: Add support for partial goods CPU



Add support to thermal driver to handle partial
goods.

In this case, it is possible that some physical
CPUs may not be brought online and it can be
decided runtime. This behavior changes the physical
CPU to logical CPU numbering dynamic.

Thermal driver should be capable to map the
temperature sensor with the correct logical CPU number.
This is achieved by creating different mitigation
profiles and associating each physical CPU to one
profile using device tree phandle. Thus thermal driver
identifies the thermal profile associated with the
logical CPU and then determines the mitigation
information. The mitigation profile has a phandle to the
temperature sensor and devicetree properties to
enable or disable various type of mitigation.
A single device can have multiple sensors mapped in
array of phandles or even multiple sensors mapping
to a single sensor.

CRs-Fixed: 756322
Change-Id: If0196a9a3a03c117f67bae3591d1f5050d32b59b
Signed-off-by: default avatarRam Chandrasekar <rkumbako@codeaurora.org>
parent 95217710
Loading
Loading
Loading
Loading
+48 −24
Original line number Diff line number Diff line
@@ -24,16 +24,10 @@ Required properties

Optional properties

- qcom,freq-control-list: List of phandles to the cores that will be used to
			determine if a core can be frequency controlled for
			thermal condition.
- qcom,core-limit-temp: Threshold temperature to start shutting down cores
			in degC
- qcom,core-temp-hysteresis: Degrees C below which the cores will be brought
			online in sequence.
- qcom,core-control-list: List of phandles to the cores that will be used to
			determine if a core can be hotplugged for thermal condition.
			No handle indicates the feature is disabled.
- qcom,hotplug-temp: Threshold temperature to start shutting down cores
			in degC. This will be used when polling based
			core control is disabled. The difference between hotplug-temp
@@ -41,9 +35,6 @@ Optional properties
			early boot prior to thermal_sys being available for hotplug.
- qcom,hotplug-temp-hysteresis: Degrees C below which thermal will not force the
			cores to be offlined. Cores can be brought online if needed.
- qcpm,cpu-sensors:     List of type names in thermal zone device struct which maps
			to cpu0, cpu1, cpu2, cpu3 in sequence depending on how many
			cpus there are.
- qcom,freq-mitigation-temp: Threshold temperature to mitigate
			the CPU max frequency in degC. This will be
			used when polling based frequency control is disabled.
@@ -58,14 +49,6 @@ Optional properties
- qcom,freq-mitigation-value: The frequency value (in kHz) to which the thermal
			should mitigate the CPU, when the freq-mitigation-temp
			threshold is reached.
- qcom,freq-mitigation-control-list: List of phandles to the cores that will be
			used to determine if KTM should do emergency frequency
			mitigation for a core or not. No handle indicates the
			mitigation is disabled for all the cores.
			Note: For KTM's frequency mitigation to work, the data for all the
			above four properties (qcom,freq-mitigation-temp; qcom,
			freq-mitigation-temp-hysteresis; qcom,freq-mitigation-value and
			qcom,freq-mitigation-control-list) should be populated.
- qcom,vdd-restriction-temp: When temperature is below this threshold, will
			enable vdd restriction which will set higher voltage on
			key voltage rails, in degC.
@@ -247,19 +230,14 @@ Example:
		qcom,limit-temp = <60>;
		qcom,temp-hysteresis = <10>;
		qcom,freq-step = <2>;
		qcom,freq-control-list = <&CPU0 &CPU1 &CPU2 &CPU3>;
		qcom,therm-reset-temp = <115>;
		qcom,core-limit-temp = <90>;
		qcom,core-temp-hysteresis = <10>;
		qcom,core-control-list = <&CPU1 &CPU2 &CPU3>;
		qcom,hotplug-temp = <110>;
		qcom,hotplug-temp-hysteresis = <20>;
		qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6",
				"tsens_tz_sensor7", "tsens_tz_sensor8";
		qcom,freq-mitigation-temp = <110>;
		qcom,freq-mitigation-temp-hysteresis = <20>;
		qcom,freq-mitigation-value = <960000>;
		qcom,freq-mitigation-control-list = <&CPU0>;
		qcom,rpm-phase-resource-type = "misc";
		qcom,rpm-phase-resource-id = <0>;
		qcom,cx-phase-resource-key = "tmpc";
@@ -340,9 +318,12 @@ Following are the required and optional properties of a child node.
1.1.b Optional properties:

- qcom,alias-name: Alias name for a sensor. The alias name corresponds
			to a device such as cpu/gpu/pop-mem whose temperature
			to a device such as gpu/pop-mem whose temperature
			is relative to the sensor temperature defined in the
			child node.
			child node. This node can not be used for providing
			alias name for cpu devices. Thermal driver assigns the
			cpu device alias, based on the sensor defined in the
			cpu mitigation profile.
- qcom,scaling-factor: The unit that needs to be multiplied to the
			sensor temperature to get temperature unit in
			degree centigrade. If this property is not
@@ -396,3 +377,46 @@ Example:
                };

	};

===============================================================================
Mitigation Profile:
===============================================================================
Thermal driver allows users to specify various mitigation profiles and
associate a profile to a device. The device should have a phandle, to associate
itself with a mitigation profile, using a "qcom,limits-info" property.
This profile can specify whether to mitigate the device during various
limiting conditions.

Required Node:
- qcom,limit_info-#: This is a mitigation profile node. A profile should
			normally have a sensor(s) to monitor and a list
			of properties enabling or disabling a mitigation.

Required properties:

- qcom,temperature-sensor: Array of phandle(s) to the temperature sensor(s) that
			need(s) to be used for monitoring the device associated
			with this mitigation profile. Right now the first
			sensor will be used for KTM CPU monitoring. Alias
			name of multiple sensors monitoring a same device will
			be differentiated by appending an index like, "cpu0_0"
			and "cpu0_1". A single sensor monitoring multiple
			devices will have an alias name like "cpu0-cpu1-cpu2".

Optional properties:

- qcom,boot-frequency-mitigate: Enable thermal frequency mitigation
			during boot.
- qcom,emergency-frequency-mitigate: Enable emergency frequency mitigation.
- qcom,hotplug-mitigation-enable: Enable hotplug mitigation. This enables
			hotplug mitigation both during boot and emergency
			condition.

Example:
	mitigation_profile7: qcom,limit_info-7 {
		qcom,temperature-sensor =
			<&sensor_information6 &sensor_information8>;
		qcom,boot-frequency-mitigate;
		qcom,emergency-frequency-mitigate;
		qcom,hotplug-mitigation-enable;
	};
+34 −9
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@
			compatible = "qcom,kryo";
			reg = <0x0 0x0>;
			enable-method = "qcom,msm8996-acc";
			qcom,limits-info = <&mitigation_profile0>;
			qcom,cpuss-pm = <&cpuss_pm>;
			qcom,cpuss-csr = <&cpuss_csr>;
			qcom,acc = <&acc0>;
@@ -68,6 +69,7 @@
			compatible = "qcom,kryo";
			reg = <0x0 0x1>;
			enable-method = "qcom,msm8996-acc";
			qcom,limits-info = <&mitigation_profile1>;
			qcom,acc = <&acc1>;
			qcom,sleep-status = <&cpu1_slp_sts>;
			qcom,ea = <&ea1>;
@@ -79,6 +81,7 @@
			compatible = "qcom,kryo";
			reg = <0x0 0x100>;
			enable-method = "qcom,msm8996-acc";
			qcom,limits-info = <&mitigation_profile2>;
			qcom,acc = <&acc2>;
			qcom,sleep-status = <&cpu2_slp_sts>;
			qcom,ea = <&ea2>;
@@ -96,6 +99,7 @@
			reg = <0x0 0x101>;
			enable-method = "qcom,msm8996-acc";
			qcom,sleep-status = <&cpu3_slp_sts>;
			qcom,limits-info = <&mitigation_profile3>;
			qcom,acc = <&acc3>;
			qcom,ea = <&ea3>;
			next-level-cache = <&L2_1>;
@@ -2518,7 +2522,6 @@
		sensor_information4: qcom,sensor-information-4 {
			qcom,sensor-type = "tsens";
			qcom,sensor-name = "tsens_tz_sensor4";
			qcom,alias-name = "cpu0";
			qcom,scaling-factor = <10>;
		};

@@ -2531,7 +2534,6 @@
		sensor_information6: qcom,sensor-information-6 {
			qcom,sensor-type = "tsens";
			qcom,sensor-name = "tsens_tz_sensor6";
			qcom,alias-name = "cpu1";
			qcom,scaling-factor = <10>;
		};

@@ -2550,7 +2552,6 @@
		sensor_information9: qcom,sensor-information-9 {
			qcom,sensor-type = "tsens";
			qcom,sensor-name = "tsens_tz_sensor9";
			qcom,alias-name = "cpu2";
			qcom,scaling-factor = <10>;
		};

@@ -2563,7 +2564,6 @@
		sensor_information11: qcom,sensor-information-11 {
			qcom,sensor-type = "tsens";
			qcom,sensor-name = "tsens_tz_sensor11";
			qcom,alias-name = "cpu3";
			qcom,scaling-factor = <10>;
		};

@@ -2624,6 +2624,34 @@
		};
	};

	mitigation_profile0: qcom,limit_info-0 {
		qcom,temperature-sensor = <&sensor_information4>;
		qcom,boot-frequency-mitigate;
		qcom,hotplug-mitigation-enable;
		qcom,emergency-frequency-mitigate;
	};

	mitigation_profile1: qcom,limit_info-1 {
		qcom,temperature-sensor = <&sensor_information6>;
		qcom,boot-frequency-mitigate;
		qcom,hotplug-mitigation-enable;
		qcom,emergency-frequency-mitigate;
	};

	mitigation_profile2: qcom,limit_info-2 {
		qcom,temperature-sensor = <&sensor_information9>;
		qcom,boot-frequency-mitigate;
		qcom,hotplug-mitigation-enable;
		qcom,emergency-frequency-mitigate;
	};

	mitigation_profile3: qcom,limit_info-3 {
		qcom,temperature-sensor = <&sensor_information11>;
		qcom,boot-frequency-mitigate;
		qcom,hotplug-mitigation-enable;
		qcom,emergency-frequency-mitigate;
	};

	qcom,msm-thermal {
		compatible = "qcom,msm-thermal";
		qcom,sensor-id = <11>;
@@ -2632,20 +2660,17 @@
		qcom,temp-hysteresis = <10>;
		qcom,therm-reset-temp = <115>;
		qcom,freq-step = <4>;
		qcom,freq-control-list = <&CPU0 &CPU1 &CPU2 &CPU3>;
		qcom,core-limit-temp = <70>;
		qcom,core-temp-hysteresis = <10>;
		qcom,core-control-list = <&CPU0 &CPU1 &CPU2 &CPU3>;
		qcom,hotplug-temp = <100>;
		qcom,hotplug-temp-hysteresis = <40>;
		qcom,cpu-sensors = "tsens_tz_sensor4", "tsens_tz_sensor6",
				"tsens_tz_sensor9", "tsens_tz_sensor11";
		qcom,freq-mitigation-temp = <90>;
		qcom,freq-mitigation-temp-hysteresis = <40>;
		qcom,freq-mitigation-value = <576000>;
		qcom,freq-mitigation-control-list = <&CPU0 &CPU1 &CPU2 &CPU3>;
		qcom,online-hotplug-core;
		qcom,synchronous-cluster-id = <0 1>;
		qcom,synchronous-cluster-map = <0 2 &CPU0 &CPU1>,
			<1 2 &CPU2 &CPU3>;
		qcom,mx-restriction-temp = <5>;
		qcom,mx-restriction-temp-hysteresis = <5>;
		qcom,mx-retention-min = <3>;
+155 −76
Original line number Diff line number Diff line
@@ -65,6 +65,13 @@
#define CPU_DEVICE "cpu%d"
#define MAX_DEBUGFS_CONFIG_LEN   32
#define DEBUGFS_DISABLE_ALL_MIT "disable"
#define DEVM_NAME_MAX 30

#define VALIDATE_AND_SET_MASK(_node, _key, _mask, _cpu) \
	do { \
		if (of_property_read_bool(_node, _key)) \
			_mask |= BIT(_cpu); \
	} while (0)

#define THERM_CREATE_DEBUGFS_DIR(_node, _name, _parent, _ret) \
	do { \
@@ -391,36 +398,6 @@ static ssize_t thermal_config_debugfs_write(struct file *file,
	} while (0)


static uint32_t get_mask_from_core_handle(struct platform_device *pdev,
						const char *key)
{
	struct device_node *core_phandle = NULL;
	int i = 0, cpu = 0, cpu_cnt = 0;
	uint32_t mask = 0;

	if (!of_get_property(pdev->dev.of_node, key, &cpu_cnt)
		|| cpu_cnt <= 0) {
		pr_debug("Property %s not defined.\n", key);
		return -ENODEV;
	}
	cpu_cnt /= sizeof(__be32);

	core_phandle = of_parse_phandle(pdev->dev.of_node,
			key, i++);
	while (core_phandle && i <= cpu_cnt) {
		for_each_possible_cpu(cpu) {
			if (of_get_cpu_node(cpu, NULL) == core_phandle) {
				mask |= BIT(cpu);
				break;
			}
		}
		core_phandle = of_parse_phandle(pdev->dev.of_node,
			key, i++);
	}

	return mask;
}

static void get_cluster_mask(uint32_t cpu, cpumask_t *mask)
{
	int i;
@@ -5391,6 +5368,139 @@ read_node_fail:
	return ret;
}

static int create_alias_name(int _cpu, struct device_node *limits,
		struct platform_device *pdev)
{
	char device_name[DEVM_NAME_MAX] = "";
	int sensor_idx = 0, sensor_ct = 0, idx = 0, err = 0;
	struct device_node *tsens = NULL;
	const char *sensor_name = NULL;

	if (!sensors) {
		pr_debug("sensor info not defined\n");
		return -ENOSYS;
	}
	snprintf(device_name, DEVM_NAME_MAX, CPU_DEVICE, _cpu);

	if (!of_get_property(limits, "qcom,temperature-sensor", &sensor_ct)
		|| sensor_ct <= 0) {
		pr_err("Sensor not defined\n");
		return -ENODEV;
	}
	sensor_ct /= sizeof(__be32);
	do {
		tsens = of_parse_phandle(limits, "qcom,temperature-sensor",
				idx);
		if (!tsens) {
			pr_err("No temperature sensor defined for CPU%d\n",
				_cpu);
			return -ENODEV;
		}

		err = of_property_read_string(tsens, "qcom,sensor-name",
			&sensor_name);
		if (err) {
			pr_err("Sensor name not populated for CPU%d. err:%d\n",
					_cpu, err);
			return -ENODEV;
		}
		for (sensor_idx = 0; sensor_idx < sensor_cnt; sensor_idx++) {
			char cat_str[DEVM_NAME_MAX] = "";

			if (strcmp(sensors[sensor_idx].name, sensor_name))
				continue;
			if (!sensors[sensor_idx].alias) {
				sensors[sensor_idx].alias = devm_kzalloc(
					&pdev->dev, DEVM_NAME_MAX, GFP_KERNEL);
				if (!sensors[sensor_idx].alias) {
					pr_err("Memory alloc failed\n");
					return -ENOMEM;
				}
				strlcpy((char *)sensors[sensor_idx].alias,
					device_name, DEVM_NAME_MAX);
				if (sensor_ct > 1) {
					/* Multiple sensor monitoring
					 * single device */
					snprintf(cat_str, DEVM_NAME_MAX, "_%d",
						idx);
					strlcat((char *)
						sensors[sensor_idx].alias,
						cat_str, DEVM_NAME_MAX);
				}
			} else {
				/* Single sensor monitoring multiple devices */
				snprintf(cat_str, DEVM_NAME_MAX,
					"-"CPU_DEVICE, _cpu);
				strlcat((char *)sensors[sensor_idx].alias,
					cat_str, DEVM_NAME_MAX);
			}
			break;
		}
		idx++;
	} while (idx < sensor_ct);

	return 0;
}

static int fetch_cpu_mitigaiton_info(struct msm_thermal_data *data,
		struct platform_device *pdev)
{

	int _cpu = 0, err = 0;
	struct device_node *cpu_node = NULL, *limits = NULL, *tsens = NULL;

	for_each_possible_cpu(_cpu) {
		const char *sensor_name = NULL;

		cpu_node = of_get_cpu_node(_cpu, NULL);
		if (!cpu_node) {
			pr_err("No CPU phandle for CPU%d\n", _cpu);
			__WARN();
			continue;
		}
		limits = of_parse_phandle(cpu_node, "qcom,limits-info", 0);
		if (!limits) {
			pr_err("No mitigation info defined for CPU%d\n", _cpu);
			continue;
		}
		VALIDATE_AND_SET_MASK(limits, "qcom,boot-frequency-mitigate",
			data->bootup_freq_control_mask, _cpu);
		VALIDATE_AND_SET_MASK(limits,
			"qcom,emergency-frequency-mitigate",
			data->freq_mitig_control_mask, _cpu);
		VALIDATE_AND_SET_MASK(limits, "qcom,hotplug-mitigation-enable",
			data->core_control_mask, _cpu);

		tsens = of_parse_phandle(limits, "qcom,temperature-sensor", 0);
		if (!tsens) {
			pr_err("No temperature sensor defined for CPU%d\n",
				_cpu);
			continue;
		}

		err = of_property_read_string(tsens, "qcom,sensor-name",
			&sensor_name);
		if (err) {
			pr_err("Sensor name not populated for CPU%d. err:%d\n",
					_cpu, err);
			continue;
		}
		cpus[_cpu].sensor_type = devm_kzalloc(&pdev->dev,
					strlen(sensor_name) + 1, GFP_KERNEL);
		if (!cpus[_cpu].sensor_type) {
			pr_err("Memory alloc failed\n");
			err = -ENOMEM;
			goto fetch_mitig_exit;
		}
		strlcpy((char *) cpus[_cpu].sensor_type, sensor_name,
			strlen(sensor_name) + 1);
		create_alias_name(_cpu, limits, pdev);
	}

fetch_mitig_exit:
	return err;
}

static void probe_sensor_info(struct device_node *node,
		struct msm_thermal_data *data, struct platform_device *pdev)
{
@@ -5431,6 +5541,8 @@ static void probe_sensor_info(struct device_node *node,
	}

	for_each_child_of_node(np, child_node) {
		const char *alias_name = NULL;

		key = "qcom,sensor-type";
		err = of_property_read_string(child_node,
				key, &sensors[i].type);
@@ -5444,12 +5556,14 @@ static void probe_sensor_info(struct device_node *node,
			goto read_node_fail;

		key = "qcom,alias-name";
		of_property_read_string(child_node,
				key, &sensors[i].alias);
		of_property_read_string(child_node, key, &alias_name);
		if (alias_name && !strnstr(alias_name, "cpu",
			strlen(alias_name)))
			sensors[i].alias = alias_name;

		key = "qcom,scaling-factor";
		err = of_property_read_u32(child_node,
				key, &sensors[i].scaling_factor);
		err = of_property_read_u32(child_node, key,
				&sensors[i].scaling_factor);
		if (err || sensors[i].scaling_factor == 0) {
			sensors[i].scaling_factor = SENSOR_SCALING_FACTOR;
			err = 0;
@@ -5663,9 +5777,7 @@ static int probe_cc(struct device_node *node, struct msm_thermal_data *data,
		struct platform_device *pdev)
{
	char *key = NULL;
	uint32_t cpu_cnt = 0;
	int ret = 0;
	uint32_t cpu = 0;

	if (num_possible_cpus() > 1) {
		core_control_enabled = 1;
@@ -5682,14 +5794,6 @@ static int probe_cc(struct device_node *node, struct msm_thermal_data *data,
	if (ret)
		goto read_node_fail;

	key = "qcom,core-control-list";
	ret = get_mask_from_core_handle(pdev, key);
	if (ret <= 0)
		goto read_node_fail;

	data->core_control_mask = ret;
	ret = 0;

	key = "qcom,hotplug-temp";
	ret = of_property_read_u32(node, key, &data->hotplug_temp_degC);
	if (ret)
@@ -5701,21 +5805,6 @@ static int probe_cc(struct device_node *node, struct msm_thermal_data *data,
	if (ret)
		goto hotplug_node_fail;

	key = "qcom,cpu-sensors";
	cpu_cnt = of_property_count_strings(node, key);
	if (cpu_cnt < num_possible_cpus()) {
		pr_err("Wrong number of cpu sensors:%d\n", cpu_cnt);
		ret = -EINVAL;
		goto hotplug_node_fail;
	}

	for_each_possible_cpu(cpu) {
		ret = of_property_read_string_index(node, key, cpu,
				&cpus[cpu].sensor_type);
		if (ret)
			goto hotplug_node_fail;
	}

read_node_fail:
	if (ret) {
		dev_info(&pdev->dev,
@@ -5957,14 +6046,6 @@ static int probe_freq_mitigation(struct device_node *node,
	if (ret)
		goto PROBE_FREQ_EXIT;

	key = "qcom,freq-mitigation-control-list";
	ret = get_mask_from_core_handle(pdev, key);
	if (ret <= 0)
		goto PROBE_FREQ_EXIT;

	data->freq_mitig_control_mask = ret;
	ret = 0;

	freq_mitigation_enabled = 1;

PROBE_FREQ_EXIT:
@@ -6382,14 +6463,6 @@ static int msm_thermal_dev_probe(struct platform_device *pdev)
	else
		online_core = false;

	key = "qcom,freq-control-list";
	ret = get_mask_from_core_handle(pdev, key);
	if (ret <= 0)
		data.bootup_freq_control_mask = 0x0;
	else
		data.bootup_freq_control_mask = ret;
	ret = 0;

	probe_sensor_info(node, &data, pdev);
	ret = probe_cc(node, &data, pdev);

@@ -6418,6 +6491,12 @@ static int msm_thermal_dev_probe(struct platform_device *pdev)
	ret = probe_ocr(node, &data, pdev);

	update_cpu_topology(&pdev->dev);
	ret = fetch_cpu_mitigaiton_info(&data, pdev);
	if (ret) {
		pr_err("Error fetching CPU mitigation information. err:%d\n",
				ret);
		goto probe_exit;
	}

	/*
	 * In case sysfs add nodes get called before probe function.
@@ -6457,7 +6536,7 @@ fail:
	if (ret)
		pr_err("Failed reading node=%s, key=%s. err:%d\n",
			node->full_name, key, ret);

probe_exit:
	return ret;
}