Commit 423de5b5 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

thermal/of: Fix cdev lookup in thermal_of_should_bind()

Since thermal_of_should_bind() terminates the loop after processing
the first child found in cooling-maps, it will never match more than
one cdev to a given trip point which is incorrect, as there may be
cooling-maps associating one trip point with multiple cooling devices.

Address this by letting the loop continue until either all
children have been processed or a matching one has been found.

To avoid adding conditionals or goto statements, put the loop in
question into a separate function and make that function return
right away after finding a matching cooling-maps entry.

Fixes: 94c6110b ("thermal/of: Use the .should_bind() thermal zone callback")
Link: https://lore.kernel.org/linux-pm/20250219-fix-thermal-of-v1-1-de36e7a590c4@chromium.org/


Reported-by: default avatarYu-Che Cheng <giver@chromium.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: default avatarYu-Che Cheng <giver@chromium.org>
Tested-by: default avatarYu-Che Cheng <giver@chromium.org>
Reviewed-by: default avatarLukasz Luba <lukasz.luba@arm.com>
Tested-by: default avatarLukasz Luba <lukasz.luba@arm.com>
Link: https://patch.msgid.link/2788228.mvXUDI8C0e@rjwysocki.net
parent 4ecaa757
Loading
Loading
Loading
Loading
+29 −21
Original line number Diff line number Diff line
@@ -274,25 +274,11 @@ static bool thermal_of_get_cooling_spec(struct device_node *map_np, int index,
	return true;
}

static bool thermal_of_should_bind(struct thermal_zone_device *tz,
static bool thermal_of_cm_lookup(struct device_node *cm_np,
				 const struct thermal_trip *trip,
				 struct thermal_cooling_device *cdev,
				 struct cooling_spec *c)
{
	struct device_node *tz_np, *cm_np;
	bool result = false;

	tz_np = thermal_of_zone_get_by_name(tz);
	if (IS_ERR(tz_np)) {
		pr_err("Failed to get node tz by name\n");
		return false;
	}

	cm_np = of_get_child_by_name(tz_np, "cooling-maps");
	if (!cm_np)
		goto out;

	/* Look up the trip and the cdev in the cooling maps. */
	for_each_child_of_node_scoped(cm_np, child) {
		struct device_node *tr_np;
		int count, i;
@@ -302,19 +288,41 @@ static bool thermal_of_should_bind(struct thermal_zone_device *tz,
			continue;

		/* The trip has been found, look up the cdev. */
		count = of_count_phandle_with_args(child, "cooling-device", "#cooling-cells");
		count = of_count_phandle_with_args(child, "cooling-device",
						   "#cooling-cells");
		if (count <= 0)
			pr_err("Add a cooling_device property with at least one device\n");

		for (i = 0; i < count; i++) {
			result = thermal_of_get_cooling_spec(child, i, cdev, c);
			if (result)
				break;
			if (thermal_of_get_cooling_spec(child, i, cdev, c))
				return true;
		}
	}

	return false;
}

		break;
static bool thermal_of_should_bind(struct thermal_zone_device *tz,
				   const struct thermal_trip *trip,
				   struct thermal_cooling_device *cdev,
				   struct cooling_spec *c)
{
	struct device_node *tz_np, *cm_np;
	bool result = false;

	tz_np = thermal_of_zone_get_by_name(tz);
	if (IS_ERR(tz_np)) {
		pr_err("Failed to get node tz by name\n");
		return false;
	}

	cm_np = of_get_child_by_name(tz_np, "cooling-maps");
	if (!cm_np)
		goto out;

	/* Look up the trip and the cdev in the cooling maps. */
	result = thermal_of_cm_lookup(cm_np, trip, cdev, c);

	of_node_put(cm_np);
out:
	of_node_put(tz_np);