From patchwork Thu Aug 8 14:11:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andr=C3=A9_Draszik?= X-Patchwork-Id: 13757555 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 B390BC3DA4A for ; Thu, 8 Aug 2024 14:12:09 +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:Cc:To:In-Reply-To:References :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=UaLjrFsw9Zi0L/EdvO9DIKyYpEUrx6lEBXaptLR+VmU=; b=GF5vFTgzSgbWkR1vKNKA31t1wM kn/2SESaQn5XOagFGcNb+GX0tO4BPyAjOLUV65388aMBbEajeaVIUAtw4D2HyVGYozxBpbSE8n0Bl 0LntsOaM6bbUAZAV/Q2QPT0IuW3+iabWYhfKe3WILYXgPCewuarHla7diSgfjMnnp0E1D0bMtRGj1 GxZ5oVec2XozjJJdqMJoRVozmPFEBY/r+gVOyA50hVeg8z/4TR4bse8ABLIiaxAsNDv1B5U7D7eoG HyIkByf9Vfnc3pfFFV74iXLn6UhSJxPR8O3VTR9ZePnZn6/D1uwdvpwwZkrjftK7IM266oub8jPd4 sRnBQWHg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.97.1 #2 (Red Hat Linux)) id 1sc3rx-00000008T5u-0SIa; Thu, 08 Aug 2024 14:11:57 +0000 Received: from mail-ed1-x533.google.com ([2a00:1450:4864:20::533]) by bombadil.infradead.org with esmtps (Exim 4.97.1 #2 (Red Hat Linux)) id 1sc3rL-00000008StV-2bmX for linux-arm-kernel@lists.infradead.org; Thu, 08 Aug 2024 14:11:21 +0000 Received: by mail-ed1-x533.google.com with SMTP id 4fb4d7f45d1cf-5b9d48d1456so1618679a12.1 for ; Thu, 08 Aug 2024 07:11:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1723126277; x=1723731077; darn=lists.infradead.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=UaLjrFsw9Zi0L/EdvO9DIKyYpEUrx6lEBXaptLR+VmU=; b=JHmusCVBCeXrmfX8kH/YXbhiC0jl5xD/ovfo3RQoZm+TmIdRGrACoY2gcfhwMTbSTa Wi9J1BOzQAAMPovvNLCWnEzYNtl4da7U6M0p9QBKcCOrKpqaGMTjXH2+T0BDNHALj3uP XfPjR7a8oRPZztRsVVi1rvwbz9iTFAIBYTibu5cAn38HpN5iZdjgm6GC2fgJANHFUmmW dMgfwt4sC7HHTk7Wijm3q4q8msO9ZVpHsmf4TekDOGy3XgfEnxVac9EVcCLpwlzWlWES got1es9n8PMd57+TecedQEMWW9KFN/XX0rIYhPASUA70bRwh5gCdv6YQf/aJGSnlJNi2 qRRg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1723126277; x=1723731077; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=UaLjrFsw9Zi0L/EdvO9DIKyYpEUrx6lEBXaptLR+VmU=; b=r7Ha7dGHjCGga9rDtrm7XcohDIkmMV4LTa4moP9L4ezmEveeuhCnJMvwfSKBGZjvo7 k/UMW+hvk3JG9BTr1ractBoh/Zc4dy26OXkwD42Ne0GsD0Xv2zMSQcm0/X4rFsO32TU6 BnYKP5vS8uL5nJq79IiA9F3T7SAZ8R4hMUvlIj2In+uWlfRDUk9422CMoce1mPZ83Qz9 42aN7yDfPUFYXjTKk4c+8rft8WEYtc9Cmp6fm4LbXxJWO9jxpvNjoehaHgoktJPeWQzI zhkOcwnzh5H+8MBklp4LJ5BomaKsc+yEZqcYq81A8HzB0SkKR4asWZJVvJ03ZxXG+Zv4 dEgw== X-Forwarded-Encrypted: i=1; AJvYcCW87e3y6GJxNucOMI+zCIp0Qcg6Raq5g64w+ZLPz45Med5NHS+RAwXBnGMX7W9u/5h+Lupjg08ads7Ij58jFFck@lists.infradead.org X-Gm-Message-State: AOJu0Yxu9PAS41nseLE2mF0wnluE1SZPxL5UDJ/QPXylDa7KE1Pb7i2j yudvEKYN2vPRPHj6wENEwVUfBPIFjUQzAOnmaHl9MQwFgxVLXdR/UJ01RM+qFeY= X-Google-Smtp-Source: AGHT+IF2Z+gOOpOJVUcuLSGq7/jhh5CJfmmh1hSytACnK5GYE20eb1XtkmCCnKm8aJbOYVVy6x+hag== X-Received: by 2002:a05:6402:3585:b0:5a2:bfd1:b892 with SMTP id 4fb4d7f45d1cf-5bbb3c41273mr1981407a12.11.1723126277143; Thu, 08 Aug 2024 07:11:17 -0700 (PDT) Received: from puffmais.c.googlers.com (64.227.90.34.bc.googleusercontent.com. [34.90.227.64]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-5bbb2c29f79sm671761a12.33.2024.08.08.07.11.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Aug 2024 07:11:16 -0700 (PDT) From: =?utf-8?q?Andr=C3=A9_Draszik?= Date: Thu, 08 Aug 2024 15:11:15 +0100 Subject: [PATCH v5 01/20] clk: bump stdout clock usage for earlycon MIME-Version: 1.0 Message-Id: <20240808-gs101-non-essential-clocks-2-v5-1-11cffef0634e@linaro.org> References: <20240808-gs101-non-essential-clocks-2-v5-0-11cffef0634e@linaro.org> In-Reply-To: <20240808-gs101-non-essential-clocks-2-v5-0-11cffef0634e@linaro.org> To: Michael Turquette , Stephen Boyd , Peter Griffin , Krzysztof Kozlowski , Sylwester Nawrocki , Chanwoo Choi , Alim Akhtar , Sam Protsenko , Tudor Ambarus , Abel Vesa , Peng Fan , Shawn Guo , Sascha Hauer , Pengutronix Kernel Team , Fabio Estevam Cc: Will McVicker , kernel-team@android.com, linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, imx@lists.linux.dev, =?utf-8?q?Andr=C3=A9_Draszik?= X-Mailer: b4 0.13.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20240808_071119_690472_F237A10A X-CRM114-Status: GOOD ( 27.67 ) X-BeenThere: linux-arm-kernel@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-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org On some platforms, earlycon depends on the bootloader setup stdout clocks being retained. In some cases stdout UART clocks (or their parents) can get disabled during loading of other drivers (e.g. i2c) causing earlycon to stop to work sometime into the boot, halting the whole system. Since there are at least two platforms where that is the case, i.MX and the Exynos-derivative gs101, this patch adds some logic to the clk core to detect these clocks if earlycon is enabled, to bump their usage count as part of of_clk_add_hw_provider() and of_clk_add_provider(), and to release them again at the end of init. This way code duplication in affected platforms can be avoided. The general idea is based on similar code in the i.MX clock driver, but this here is a bit more generic as in general (e.g. on gs101) clocks can come from various different clock units (driver instances) and therefore it can be necessary to run this code multiple times until all required stdout clocks have probed. Signed-off-by: André Draszik --- drivers/clk/clk.c | 129 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/samsung/clk-gs101.c | 1 + 2 files changed, 130 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 7264cf6165ce..03c5d80e833c 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -4923,6 +4923,131 @@ static void clk_core_reparent_orphans(void) clk_prepare_unlock(); } +/** + * struct of_clk_stdout_clks - holds data that is required for handling extra + * references to stdout clocks during early boot. + * + * On some platforms, earlycon depends on the bootloader setup stdout clocks + * being retained. In some cases stdout UART clocks (or their parents) can get + * disabled during loading of other drivers (e.g. i2c) causing earlycon to stop + * to work sometime into the boot, halting the system. + * + * Having logic to detect these clocks if earlycon is enabled helps with those + * cases by bumping their usage count during init. The extra usage count is + * later dropped at the end of init. + * + * @bump_refs: whether or not to add the extra stdout clock references + * @lock: mutex protecting access + * @have_all: whether or not we have acquired all clocks, to handle cases of + * clocks coming from different drivers / instances + * @clks: clocks associated with stdout + * @n_clks: number of clocks associated with stdout + */ +static struct of_clk_stdout_clks { + bool bump_refs; + + struct mutex lock; + bool have_all; + struct clk **clks; + size_t n_clks; +} of_clk_stdout_clks = { + .lock = __MUTEX_INITIALIZER(of_clk_stdout_clks.lock), +}; + +static int __init of_clk_bump_stdout_clocks_param(char *str) +{ + of_clk_stdout_clks.bump_refs = true; + return 0; +} +__setup("earlycon", of_clk_bump_stdout_clocks_param); +__setup_param("earlyprintk", of_clk_keep_stdout_clocks_earlyprintk, + of_clk_bump_stdout_clocks_param, 0); + +static void of_clk_bump_stdout_clocks(void) +{ + size_t n_clks; + + /* + * We only need to run this code if required to do so and only ever + * before late initcalls have run. Otherwise it'd be impossible to know + * when to drop the extra clock references again. + * + * This generally means that this only works if on affected platforms + * the clock drivers have been built-in (as opposed to being modules). + */ + if (!of_clk_stdout_clks.bump_refs) + return; + + n_clks = of_clk_get_parent_count(of_stdout); + if (!n_clks || !of_stdout) + return; + + mutex_lock(&of_clk_stdout_clks.lock); + + /* + * We only need to keep trying if we have not succeeded previously, + * i.e. if not all required clocks were ready during previous attempts. + */ + if (of_clk_stdout_clks.have_all) + goto out_unlock; + + if (!of_clk_stdout_clks.clks) { + of_clk_stdout_clks.n_clks = n_clks; + + of_clk_stdout_clks.clks = kcalloc(of_clk_stdout_clks.n_clks, + sizeof(*of_clk_stdout_clks.clks), + GFP_KERNEL); + if (!of_clk_stdout_clks.clks) + goto out_unlock; + } + + /* assume that this time we'll be able to grab all required clocks */ + of_clk_stdout_clks.have_all = true; + for (size_t i = 0; i < n_clks; ++i) { + struct clk *clk; + + /* we might have grabbed this clock in a previous attempt */ + if (of_clk_stdout_clks.clks[i]) + continue; + + clk = of_clk_get(of_stdout, i); + if (IS_ERR(clk)) { + /* retry next time if clock has not probed yet */ + of_clk_stdout_clks.have_all = false; + continue; + } + + if (clk_prepare_enable(clk)) { + clk_put(clk); + continue; + } + of_clk_stdout_clks.clks[i] = clk; + } + +out_unlock: + mutex_unlock(&of_clk_stdout_clks.lock); +} + +static int __init of_clk_drop_stdout_clocks(void) +{ + for (size_t i = 0; i < of_clk_stdout_clks.n_clks; ++i) { + clk_disable_unprepare(of_clk_stdout_clks.clks[i]); + clk_put(of_clk_stdout_clks.clks[i]); + } + + kfree(of_clk_stdout_clks.clks); + + /* + * Do not try to acquire stdout clocks after late initcalls, e.g. + * during further module loading, as we then wouldn't have a way to + * drop the references (and associated allocations) ever again. + */ + of_clk_stdout_clks.bump_refs = false; + + return 0; +} +late_initcall_sync(of_clk_drop_stdout_clocks); + /** * struct of_clk_provider - Clock provider registration structure * @link: Entry in global list of clock providers @@ -5031,6 +5156,8 @@ int of_clk_add_provider(struct device_node *np, fwnode_dev_initialized(&np->fwnode, true); + of_clk_bump_stdout_clocks(); + return ret; } EXPORT_SYMBOL_GPL(of_clk_add_provider); @@ -5073,6 +5200,8 @@ int of_clk_add_hw_provider(struct device_node *np, fwnode_dev_initialized(&np->fwnode, true); + of_clk_bump_stdout_clocks(); + return ret; } EXPORT_SYMBOL_GPL(of_clk_add_hw_provider); diff --git a/drivers/clk/samsung/clk-gs101.c b/drivers/clk/samsung/clk-gs101.c index 85098c61c15e..1759eb23263b 100644 --- a/drivers/clk/samsung/clk-gs101.c +++ b/drivers/clk/samsung/clk-gs101.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include