From patchwork Tue Nov 12 05:19:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 13871729 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2F6AAD41D57 for ; Tue, 12 Nov 2024 05:22:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=5bdj/n2LgxLKoSXpmbjX7w9HpSLYegxH5T6o6/+YLS4=; b=Q2DTYkZyBUGuvbgQ+xwaJvdgHH b4Pdo71sWbC5xlw6SnBaiy/PjcE6owugqCGN1OiTf6zrDs6pWe1NNaCa+ZwFau3ptQTKZIjMKi+rJ OWKv6HSCuqv0/DujPdHKZXi6wTbY9nZgXhkJvDoyWoDNb86ksNHJatUYUElApcyH/n/y/29dY3Ze3 DSo8EpvwPM1WbBg3B6W2R6YbVXphtd6R/N0RukfcTf3E08iUDjCILFbKMDVuXLiJd79DlYzHf1G30 SAbuBrxPFbguHPHbTs3IVB84y0u7IfQAb6b5d4bUty+6Tl2uNi0DmQkNxMKSMfJAPkg6QDCQdNRrm l0ThT2ig==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tAjM7-00000002F67-49c2; Tue, 12 Nov 2024 05:22:23 +0000 Received: from fout-a3-smtp.messagingengine.com ([103.168.172.146]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tAjM1-00000002F2i-2qH5 for linux-mediatek@lists.infradead.org; Tue, 12 Nov 2024 05:22:21 +0000 Received: from phl-compute-01.internal (phl-compute-01.phl.internal [10.202.2.41]) by mailfout.phl.internal (Postfix) with ESMTP id 3CB5E1380171; Tue, 12 Nov 2024 00:22:15 -0500 (EST) Received: from phl-frontend-01 ([10.202.2.160]) by phl-compute-01.internal (MEProxy); Tue, 12 Nov 2024 00:22:15 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fluxnic.net; h= cc:cc:content-transfer-encoding:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=2016-12.pbsmtp; t=1731388935; x=1731475335; bh=5bdj/n2LgxLKoSXpmbjX7w9HpSLYegxH5T6o6/+YLS4=; b= jYatm4tJFXRKm7NQ8XYg2KX0WHovLYH0dUK9B1MYh4UMuZc7QetfVrW1VMzX/c4L xK2+kCKgriOtR4B/LdRxzV46koiaEUk0oAudOcmLX+g1rhoTAwI2XsbUUEOmvR5V Ln8DpIn4c8FWmvyK5bmLxcak+WObR2zi1cFXKdxjDbs= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pobox.com; h=cc :cc:content-transfer-encoding:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm2; t=1731388935; x= 1731475335; bh=5bdj/n2LgxLKoSXpmbjX7w9HpSLYegxH5T6o6/+YLS4=; b=I hlurd1z1Sd2ci34BmfzTXcoQ/Is08G1unGuXoEmyREBNmgqiGPinELUWuqKsFpL4 4B3dXnkhDdrdAyvepACJVP1hMPbw39nno52z7+3reN0IcqeyM4XJSnE5CUG9fCD7 cFUlD8DkGk0CtDZmk8IkllwAPDFbCtjcaeIpnXzqm/x2U9bEt6Eh9OPwTSu6LG9M ISPiXpbn47r2momwV/TkJz+RC4bqyijlH9trQ7Y+iP7ZPITJ0uoEvai2+vCdzj6f 14XZIqHbUJrfuOgkSvMtp3iYcTAsyN3GyaW3/C7PWX/7Sq+YTFrSlb8kjRQpcPnL FOVeGdkCN3KKC44lMpMcw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1731388935; x=1731475335; bh=5 bdj/n2LgxLKoSXpmbjX7w9HpSLYegxH5T6o6/+YLS4=; b=ntcc2TkeDYUK6tgEf YYUrMidO7bng67ULq+kMCjMT7f5peMKz/HNy4QQF4jJlwYhz+kqi4jLin+M3n8jl 47vfMBjOwl9uwXB8FDKHi4BreoLeyt9wkkgLlDUO+dkN18QeMpOloyFSAGKvn1KD KUT7tioNiMTN7nHE+GqG8FGFxSFz7fmbtsixyyC0MFoV5r77FA/wXkAMrXTuVEpC z63Wu1zl+e/DhMszVclkEIeswHXVXRiiUF8pWfSkrWMizulwFkP5nlWrretiMm7R oM4sOOc+aFkpQfGx5nD+5OrH/u5R4uJ9AuIIHIY+vJJ5PwtiSeq9FL1PNr/Pk3OO 3RQ9w== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefuddrudefgdekvdcutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdpuffr tefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnth hsucdlqddutddtmdenucfjughrpefhvfevufffkffojghfggfgsedtkeertdertddtnecu hfhrohhmpefpihgtohhlrghsucfrihhtrhgvuceonhhitghosehflhhugihnihgtrdhnvg htqeenucggtffrrghtthgvrhhnpedtjeeuieeiheeiueffuddvffelheekleegkedukeef fffhudffudegvdetiefhteenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmh grihhlfhhrohhmpehnihgtohesfhhluhignhhitgdrnhgvthdpnhgspghrtghpthhtohep kedpmhhouggvpehsmhhtphhouhhtpdhrtghpthhtoheprggsrghilhhonhessggrhihlih gsrhgvrdgtohhmpdhrtghpthhtohepnhhpihhtrhgvsegsrgihlhhisghrvgdrtghomhdp rhgtphhtthhopehrrghfrggvlheskhgvrhhnvghlrdhorhhgpdhrtghpthhtohepuggrnh hivghlrdhlvgiitggrnhhosehlihhnrghrohdrohhrghdprhgtphhtthhopehlihhnuhig qdhmvgguihgrthgvkheslhhishhtshdrihhnfhhrrgguvggrugdrohhrghdprhgtphhtth hopeguvghvihgtvghtrhgvvgesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthho pehlihhnuhigqdhkvghrnhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtth hopehlihhnuhigqdhpmhesvhhgvghrrdhkvghrnhgvlhdrohhrgh X-ME-Proxy: Feedback-ID: i58514971:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 12 Nov 2024 00:22:14 -0500 (EST) Received: from xanadu.lan (OpenWrt.lan [192.168.1.1]) by yoda.fluxnic.net (Postfix) with ESMTPSA id 32494ECB802; Tue, 12 Nov 2024 00:22:14 -0500 (EST) From: Nicolas Pitre To: Daniel Lezcano , "Rafael J . Wysocki" , linux-pm@vger.kernel.org, linux-mediatek@lists.infradead.org, devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Nicolas Pitre , Alexandre Bailon Subject: [PATCH 4/5] thermal: automatic aggregation support Date: Tue, 12 Nov 2024 00:19:41 -0500 Message-ID: <20241112052211.3087348-5-nico@fluxnic.net> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20241112052211.3087348-1-nico@fluxnic.net> References: <20241112052211.3087348-1-nico@fluxnic.net> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241111_212218_239834_9074BE8B X-CRM114-Status: GOOD ( 23.23 ) X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org From: Nicolas Pitre Automatically apply thermal aggregation of multiple related thermal zones into a single one. Here "related" means such zones must have the same trip points and cooling devices bound to them. This is an alternative to the device tree's "thermal-sensors" list for testing purpose without actually modifying the DTB. Signed-off-by: Nicolas Pitre --- drivers/thermal/Kconfig | 12 ++ drivers/thermal/thermal_core.c | 227 +++++++++++++++++++++++++++++++++ 2 files changed, 239 insertions(+) diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 111f07b52a..1b2f319838 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -235,6 +235,18 @@ config THERMAL_AGGREGATION found in the device tree's "thermal-sensors" list when it contains more than one entry. +config THERMAL_AGGREGATION_AUTO + bool "Automatic Thermal Aggregation support" + depends on THERMAL_AGGREGATION + help + Automatically apply thermal aggregation of multiple related thermal + zones into a single one. Here "related" means such zones must have + the same trip points and cooling devices bound to them. This is an + alternative to the device tree's "thermal-sensors" list for testing + purpose without actually modifying the DTB. It is highly recommended + that the device tree method be used in preference to this for actual + system deployment. + config THERMAL_EMULATION bool "Thermal emulation mode support" help diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 73a1b30081..934d248aa9 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -755,6 +755,16 @@ static inline void thermal_remove_tz_from_aggregator(struct thermal_zone_device {} #endif /* CONFIG_THERMAL_AGGREGATION */ +#ifdef CONFIG_THERMAL_AGGREGATION_AUTO +static void thermal_check_zone_for_aggregation(struct thermal_zone_device *target_tz); +static void thermal_check_cdev_for_aggregation(struct thermal_cooling_device *new_cdev); +#else +static inline void thermal_check_zone_for_aggregation(struct thermal_zone_device *target_tz) +{} +static inline void thermal_check_cdev_for_aggregation(struct thermal_cooling_device *new_cdev) +{} +#endif /* CONFIG_THERMAL_AGGREGATION_AUTO */ + /** * thermal_bind_cdev_to_trip - bind a cooling device to a thermal zone * @tz: pointer to struct thermal_zone_device @@ -1073,6 +1083,8 @@ __thermal_cooling_device_register(struct device_node *np, mutex_unlock(&thermal_list_lock); + thermal_check_cdev_for_aggregation(cdev); + return cdev; out_cooling_dev: @@ -1515,6 +1527,8 @@ thermal_zone_device_register_with_trips(const char *type, if (atomic_cmpxchg(&tz->need_update, 1, 0)) thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + thermal_check_zone_for_aggregation(tz); + thermal_notify_tz_create(tz); thermal_debug_tz_add(tz); @@ -2068,6 +2082,219 @@ void thermal_zone_device_aggregate(struct thermal_zone_device *tz, mutex_unlock(&thermal_list_lock); } +#ifdef CONFIG_THERMAL_AGGREGATION_AUTO + +static bool is_aggregator(struct thermal_zone_device *tz) +{ + return !strcmp(tz->type, "aggregator"); +} + +/** + * thermal_trip_related - determine if two trips are equivalent + * + * @tt1, @tt2: thermal trip specs to compare + * + * Determine if given trips may be candidates for aggregation. + * + * Return: true if related for aggregation, false otherwise + */ +static bool thermal_trip_related(struct thermal_trip *tt1, + struct thermal_trip *tt2) +{ + return tt1->temperature == tt2->temperature && + tt1->hysteresis == tt2->hysteresis && + tt1->type == tt2->type && + tt1->flags == tt2->flags; +} + +static struct thermal_cooling_device * +trip_to_cdev(struct thermal_zone_device *tz, int trip_idx) +{ + struct thermal_instance *ti; + + list_for_each_entry(ti, &tz->thermal_instances, tz_node) + if (trip_to_trip_desc(ti->trip) == &tz->trips[trip_idx]) + return ti->cdev; + + return NULL; +} + +/** + * thermal_zone_related - determine if two tz's are candidates for aggregation + * + * @tz1, @tz2: thermal zones to compare + * + * Return: true if related for aggregation, false otherwise + */ +static bool thermal_zone_related(struct thermal_zone_device *tz1, + struct thermal_zone_device *tz2) +{ + /* a tz can't aggregate with itself */ + if (tz1 == tz2) + return false; + + /* no relation possible if ops.should_bind is unset */ + if (!tz1->ops.should_bind || !tz2->ops.should_bind) + return false; + + /* a tz always relates to its aggregator */ + if (tz1->aggregator == tz2 || tz2->aggregator == tz1) + return true; + + /* related tz's must have the same number of trip points */ + if (tz1->num_trips != tz2->num_trips) + return false; + + /* tz's with no cdev bindings are not (yet) considered */ + if (list_empty(&tz1->thermal_instances) || + list_empty(&tz2->thermal_instances)) + return false; + + for (int i = 0; i < tz1->num_trips; i++) { + /* all trips must be related */ + if (!thermal_trip_related(&tz1->trips[i].trip, &tz2->trips[i].trip)) + return false; + /* cdevs for given trips must be the same */ + if (trip_to_cdev(tz1, i) != trip_to_cdev(tz2, i)) + return false; + } + + return true; +} + +/** + * find_related_tz - look for a tz aggregation candidate + * + * @target_tz: tz to compare against + * + * Return: candidate tz for aggregation, or NULL if none + */ +static struct thermal_zone_device * +find_related_tz(struct thermal_zone_device *target_tz) +{ + struct thermal_zone_device *tz; + + list_for_each_entry(tz, &thermal_tz_list, node) { + if (is_aggregated(tz)) + continue; + if (is_aggregator(tz)) + continue; + if (!thermal_zone_related(tz, target_tz)) + continue; + return tz; + } + + return NULL; +} + +/** + * thermal_check_zone_for_aggregation - consider tz for aggregation + * + * @target_tz: tz to compare against + * + * Adds the provided tz to a compatible aggregator. If none found, look for + * the possibility to create a new aggregator if another compatible tz exists. + * This is called, notably, when a new tz is registered and potentially bound + * to existing cdevs. + */ +static void thermal_check_zone_for_aggregation(struct thermal_zone_device *target_tz) +{ + struct thermal_zone_aggregator *aggr; + struct thermal_zone_device *aggr_tz, *tz; + + if (is_aggregator(target_tz)) + return; + + mutex_lock(&thermal_list_lock); + if (!thermal_zone_is_present(target_tz)) { + mutex_unlock(&thermal_list_lock); + return; + } + + /* see if existing aggregators can appropriate this zone */ + list_for_each_entry(aggr, &thermal_aggregator_list, node) { + aggr_tz = aggr->tz; + if (!thermal_zone_related(aggr_tz, target_tz)) + continue; + pr_debug("aggr %s(%d) and zone %s(%d) are related\n", + aggr_tz->type, aggr_tz->id, target_tz->type, target_tz->id); + add_tz_to_aggregator(aggr_tz, target_tz); + mutex_unlock(&thermal_list_lock); + return; + } + + /* see if non-aggregated zones can be aggregated */ + tz = find_related_tz(target_tz); + if (!tz) { + mutex_unlock(&thermal_list_lock); + return; + } + + pr_debug("zones %s(%d) and %s(%d) are related\n", + tz->type, tz->id, target_tz->type, target_tz->id); + + mutex_unlock(&thermal_list_lock); + aggr_tz = create_thermal_aggregator(target_tz, "aggregator"); + if (IS_ERR(aggr_tz)) { + pr_err("unable to create thermal aggregator (%ld)\n", + PTR_ERR(aggr_tz)); + return; + } + + mutex_lock(&thermal_list_lock); + + /* the lock was momentarily dropped so need to revalide everything */ + if (thermal_zone_is_present(target_tz)) { + tz = find_related_tz(target_tz); + if (tz) { + add_tz_to_aggregator(aggr_tz, target_tz); + add_tz_to_aggregator(aggr_tz, tz); + mutex_unlock(&thermal_list_lock); + return; + } + } + + /* our match disappeared in the mean time */ + free_thermal_aggregator_unlock(aggr_tz); +} + +/** + * thermal_check_cdev_for_aggregation - consider aggregation after new cdev registration + * + * @new_cdev: cdev for which new thermal bindings might create aggregation candidates + * + * Consider tz's having thermal instance bindings with this new cdev as + * candidates for aggregation. This is called when a new cdev is registered + * and potentially bound to existing tz's. + */ +static void thermal_check_cdev_for_aggregation(struct thermal_cooling_device *new_cdev) +{ + struct thermal_zone_device *tz, *last_tz = NULL; + struct thermal_instance *ti; + +start_over: + mutex_lock(&thermal_list_lock); + + list_for_each_entry(tz, &thermal_tz_list, node) { + if (tz == last_tz) + continue; + if (is_aggregator(tz)) + continue; + list_for_each_entry(ti, &tz->thermal_instances, tz_node) { + if (ti->cdev == new_cdev) { + last_tz = tz; + mutex_unlock(&thermal_list_lock); + thermal_check_zone_for_aggregation(tz); + /* because the lock was dropped ... */ + goto start_over; + } + } + } + + mutex_unlock(&thermal_list_lock); +} + +#endif /* CONFIG_THERMAL_AGGREGATION_AUTO */ #endif /* CONFIG_THERMAL_AGGREGATION */ static void thermal_zone_device_resume(struct work_struct *work)